From: Antonio Borneo Date: Sun, 24 Mar 2024 21:57:52 +0000 (+0100) Subject: jtag: linuxgpiod: drop extra parenthesis X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=commitdiff_plain;h=HEAD;hp=f2c83fade3ea7e51e5c9283aa3ff94632a41cc55 jtag: linuxgpiod: drop extra parenthesis Checkpatch complains for extra parenthesis not required. Drop them. Change-Id: I311409f5732acf10a4910de5dcf0fb05f43e21b5 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8187 Reviewed-by: Tomas Vanek Tested-by: jenkins --- 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/snapshot.yml b/.github/workflows/snapshot.yml index 2b73f9c8cd..f5cf56459c 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -8,52 +8,82 @@ name: OpenOCD Snapshot jobs: package: - runs-on: [ubuntu-18.04] + runs-on: [ubuntu-20.04] env: DL_DIR: ../downloads BUILD_DIR: ../build steps: - name: Install needed packages - run: sudo apt-get install autotools-dev autoconf automake libtool pkg-config cmake texinfo texlive g++-mingw-w64-i686 - - uses: actions/checkout@v1 + run: | + sudo apt-get update + sudo apt-get install autotools-dev autoconf automake libtool pkg-config cmake texinfo texlive g++-mingw-w64-i686 + - name: Checkout Code + uses: actions/checkout@v1 - run: ./bootstrap - name: Prepare libusb1 env: - LIBUSB1_VER: 1.0.23 + 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" tar -xjf libusb-${LIBUSB1_VER}.tar.bz2 - echo "::set-env name=LIBUSB1_SRC::$PWD/libusb-${LIBUSB1_VER}" + echo "LIBUSB1_SRC=$PWD/libusb-${LIBUSB1_VER}" >> $GITHUB_ENV - name: Prepare hidapi env: - HIDAPI_VER: 0.9.0 + 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" tar -xzf hidapi-${HIDAPI_VER}.tar.gz cd hidapi-hidapi-${HIDAPI_VER} ./bootstrap - echo "::set-env name=HIDAPI_SRC::$PWD" + echo "HIDAPI_SRC=$PWD" >> $GITHUB_ENV - name: Prepare libftdi env: - LIBFTDI_VER: 1.4 + 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 "::set-env name=LIBFTDI_SRC::$PWD/libftdi1-${LIBFTDI_VER}" + echo "LIBFTDI_SRC=$PWD/libftdi1-${LIBFTDI_VER}" >> $GITHUB_ENV + - name: Prepare capstone + env: + CAPSTONE_VER: 4.0.2 + run: | + mkdir -p $DL_DIR && cd $DL_DIR + CAPSTONE_NAME=${CAPSTONE_VER} + CAPSTONE_FOLDER=capstone-${CAPSTONE_VER} + 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 --enable-static + LIBUSB1_CONFIG: --enable-shared --disable-static HIDAPI_CONFIG: --enable-shared --disable-static --disable-testgui - LIBFTDI_CONFIG: "-DCMAKE_TOOLCHAIN_FILE='${{ env.LIBFTDI_SRC }}/cmake/Toolchain-i686-w64-mingw32.cmake' -DBUILD_TESTS:BOOL=off -DFTDIPP:BOOL=off -DPYTHON_BINDINGS:BOOL=off -DEXAMPLES:BOOL=off -DDOCUMENTATION:BOOL=off -DFTDI_EEPROM:BOOL=off" + LIBFTDI_CONFIG: -DSTATICLIBS=OFF -DEXAMPLES=OFF -DFTDI_EEPROM=OFF + CAPSTONE_CONFIG: "CAPSTONE_BUILD_CORE_ONLY=yes CAPSTONE_STATIC=yes CAPSTONE_SHARED=no" + LIBJAYLINK_CONFIG: --enable-shared --disable-static run: | - # set snapshot tag + # check if there is tag pointing at HEAD, otherwise take the HEAD SHA-1 as OPENOCD_TAG OPENOCD_TAG="`git tag --points-at HEAD`" [ -z $OPENOCD_TAG ] && OPENOCD_TAG="`git rev-parse --short HEAD`" + # check if there is tag pointing at HEAD, if so the release will have the same name as the tag, + # otherwise it will be named 'latest' + RELEASE_NAME="`git tag --points-at HEAD`" + [ -z $RELEASE_NAME ] && RELEASE_NAME="latest" + [[ $RELEASE_NAME = "latest" ]] && IS_PRE_RELEASE="true" || IS_PRE_RELEASE="false" # set env and call cross-build.sh export OPENOCD_TAG=$OPENOCD_TAG export OPENOCD_SRC=$PWD @@ -63,30 +93,31 @@ 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" tar -czf $ARTIFACT * - echo "::set-env name=ARTIFACT_NAME::$ARTIFACT" - echo "::set-env name=ARTIFACT_PATH::$PWD/$ARTIFACT" + 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@v1 + uses: actions/upload-artifact@v3 with: - name: ${{ env.ARTIFACT_NAME }} path: ${{ env.ARTIFACT_PATH }} - - name: Get the upload URL for a release - id: get_release - if: startsWith(github.ref, 'refs/tags/') - uses: bruceadams/get-release@v1.2.0 - env: - GITHUB_TOKEN: ${{ github.token }} - - name: Release OpenOCD packaged for windows - if: startsWith(github.ref, 'refs/tags/') - uses: actions/upload-release-asset@v1 + - 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: - upload_url: ${{ steps.get_release.outputs.upload_url }} - asset_path: ${{ env.ARTIFACT_PATH }} - asset_name: ${{ env.ARTIFACT_NAME }} - asset_content_type: application/gzip + 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/.gitignore b/.gitignore index f1021b2638..103dad2c75 100644 --- a/.gitignore +++ b/.gitignore @@ -53,27 +53,23 @@ doc/openocd.toc doc/openocd.tp doc/openocd.vr doc/version.texi -texinfo.tex src/openocd src/openocd.exe # configure/autotools output +/build-aux/ aclocal.m4 autom4te.cache -compile -config.* +config.h +config.log +config.status configure -depcomp doxygen doxygen.log Doxyfile -install-sh libtool -ltmain.sh Makefile !contrib/loaders/**/Makefile -mdate-sh -missing stamp-h1 stamp-vti INSTALL @@ -99,3 +95,19 @@ TAGS # ctags tag files tags + +# GNU Global tag files +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/.gitmodules b/.gitmodules index 958c5d901c..f2da17ed7a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ [submodule "tools/git2cl"] path = tools/git2cl - url = https://repo.or.cz/git2cl.git + url = https://git.savannah.nongnu.org/git/git2cl.git [submodule "jimtcl"] path = jimtcl - url = https://repo.or.cz/jimtcl.git + url = https://github.com/msteveb/jimtcl.git [submodule "src/jtag/drivers/libjaylink"] path = src/jtag/drivers/libjaylink - url = https://repo.or.cz/libjaylink.git + url = https://gitlab.zapb.de/libjaylink/libjaylink.git diff --git a/.travis.yml b/.travis.yml index da6b94c3f0..28d5502c5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0+ +# SPDX-License-Identifier: GPL-2.0-or-later # Copyright Marek Vasut # OpenOCD on Travis CI - https://travis-ci.org/ diff --git a/COPYING b/COPYING index d159169d10..0e8db929e6 100644 --- a/COPYING +++ b/COPYING @@ -1,339 +1,16 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 +OpenOCD is provided under: - Copyright (C) 1989, 1991 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. + SPDX-License-Identifier: GPL-2.0-or-later - Preamble +Being under the terms of the GNU General Public License version 2 or +later, according with: - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. + LICENSES/preferred/GPL-2.0 - When we speak of free software, we are referring to freedom, 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 or use pieces of it -in new free programs; and that you know you can do these things. +In addition, other licenses may also apply. Please see: - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. + LICENSES/license-rules.txt - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. +for more details. - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -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 give any other recipients of the Program a copy of this License -along with the Program. - -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 Program or any portion -of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -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 Program, 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 Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) 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; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, 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 executable. However, as a -special exception, the source code 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. - -If distribution of executable or 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 counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program 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. - - 5. 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 Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program 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 to -this License. - - 7. 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 Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program 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 Program. - -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. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program 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. - - 9. The Free Software Foundation may publish revised and/or new versions -of the 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 Program -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 Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, 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 - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), 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 Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. 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. - - - Copyright (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, 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. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. +All contributions to OpenOCD are subject to this COPYING file. diff --git a/Doxyfile.in b/Doxyfile.in index 6e68b4e373..9be53d0fc6 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -600,7 +600,7 @@ RECURSIVE = YES # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. -EXCLUDE = +EXCLUDE = @srcdir@/src/jtag/drivers/libjaylink # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded @@ -1234,7 +1234,7 @@ SEARCH_INCLUDES = YES # contain include files that are not input files but should be processed by # the preprocessor. -INCLUDE_PATH = +INCLUDE_PATH = @builddir@/src # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the diff --git a/HACKING b/HACKING index c1a6b0e8a1..74cbe02e74 100644 --- a/HACKING +++ b/HACKING @@ -77,6 +77,21 @@ patch: src/openocd -s ../tcl -f /path/to/openocd.cfg @endcode +- 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 @@ -91,7 +106,7 @@ Add yourself to the GPL copyright for non-trivial changes. @section stepbystep Step by step procedure --# Create a Gerrit account at: http://openocd.zylin.com +-# Create a Gerrit account at: https://review.openocd.org - On subsequent sign ins, use the full URL prefaced with 'http://' For example: http://user_identifier.open_id_provider.com -# Add a username to your profile. @@ -121,18 +136,18 @@ Add yourself to the GPL copyright for non-trivial changes. to instruct git locally how to send off the changes. -# Add a new remote to git using Gerrit username: @code -git remote add review ssh://USERNAME@openocd.zylin.com:29418/openocd.git +git remote add review ssh://USERNAME@review.openocd.org:29418/openocd.git git config remote.review.push HEAD:refs/for/master @endcode Or with http only: @code -git remote add review http://USERNAME@openocd.zylin.com/p/openocd.git +git remote add review https://USERNAME@review.openocd.org/p/openocd.git git config remote.review.push HEAD:refs/for/master @endcode - The http password is configured from your gerrit settings - http://openocd.zylin.com/#/settings/http-password. + The http password is configured from your gerrit settings - https://review.openocd.org/#/settings/http-password. \note If you want to simplify http access you can also add your http password to the url as follows: @code -git remote add review http://USERNAME:PASSWORD@openocd.zylin.com/p/openocd.git +git remote add review https://USERNAME:PASSWORD@review.openocd.org/p/openocd.git @endcode \note All contributions should be pushed to @c refs/for/master on the Gerrit server, even if you plan to use several local branches for different @@ -140,11 +155,7 @@ 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@openocd.zylin.com:hooks/commit-msg .git/hooks/ -@endcode - Or with http only: -@code -wget http://openocd.zylin.com/tools/hooks/commit-msg +wget https://review.openocd.org/tools/hooks/commit-msg mv commit-msg .git/hooks chmod +x .git/hooks/commit-msg @endcode @@ -171,18 +182,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: @@ -201,6 +242,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 @@ -228,10 +328,10 @@ not have to) be disregarded if all conditions listed below are met: - reviewer does not answer e-mails for another month. @section browsing Browsing Patches -All OpenOCD patches can be reviewed here. +All OpenOCD patches can be reviewed here. @section reviewing Reviewing Patches -From the main Review +From the main Review page select the patch you want to review and click on that patch. On the appearing page select the download method (top right). Apply the patch. After building and testing you can leave a note with the "Reply" 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 new file mode 100644 index 0000000000..ecc8e4db16 --- /dev/null +++ b/LICENSES/license-rules.txt @@ -0,0 +1,272 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +OpenOCD licensing rules +======================= + +The OpenOCD source code is provided under the terms of the GNU General +Public License version 2 or later (GPL-2.0-or-later), as provided in +LICENSES/preferred/GPL-2.0. + +The OpenOCD documentation is provided under the terms of the GNU Free +Documentation License version 1.2 or later without Invariant Sections +(GFDL-1.2-no-invariants-or-later). + +Few stand-alone applications coexist in the same code tree of OpenOCD +and are provided under the terms of the GNU General Public License +version 3 (GPL-3.0), as provided in LICENSES/stand-alone/GPL-3.0. + +This documentation file provides a description of how each source file +should be annotated to make its license clear and unambiguous. +It doesn't replace the OpenOCD's license. + +The license described in the COPYING file applies to the OpenOCD source +as a whole, though individual source files can have a different license +which is required to be compatible with the GPL-2.0: + + GPL-1.0-or-later : GNU General Public License v1.0 or later + GPL-2.0-or-later : GNU General Public License v2.0 or later + LGPL-2.0 : GNU Library General Public License v2 only + LGPL-2.0-or-later : GNU Library General Public License v2 or later + LGPL-2.1 : GNU Lesser General Public License v2.1 only + LGPL-2.1-or-later : GNU Lesser General Public License v2.1 or later + +Aside from that, individual files can be provided under a dual license, +e.g. one of the compatible GPL variants and alternatively under a +permissive license like BSD, MIT etc. + +The common way of expressing the license of a source file is to add the +matching boilerplate text into the top comment of the file. Due to +formatting, typos etc. these "boilerplates" are hard to validate for +tools which are used in the context of license compliance. + +An alternative to boilerplate text is the use of Software Package Data +Exchange (SPDX) license identifiers in each source file. SPDX license +identifiers are machine parsable and precise shorthands for the license +under which the content of the file is contributed. SPDX license +identifiers are managed by the SPDX Workgroup at the Linux Foundation and +have been agreed on by partners throughout the industry, tool vendors, and +legal teams. For further information see https://spdx.org/ + +OpenOCD requires the precise SPDX identifier in all source files. +The valid identifiers used in OpenOCD are explained in the section +`License identifiers` and have been retrieved from the official SPDX +license list at https://spdx.org/licenses/ along with the license texts. + +License identifier syntax +------------------------- + +1. Placement: + + The SPDX license identifier in OpenOCD files shall be added at the + first possible line in a file which can contain a comment. For the + majority of files this is the first line, except for scripts which + require the '#!PATH_TO_INTERPRETER' in the first line. For those + scripts the SPDX identifier goes into the second line. + +2. Style: + + The SPDX license identifier is added in form of a comment. The comment + style depends on the file type:: + + C source: // SPDX-License-Identifier: + C header: /* SPDX-License-Identifier: */ + ASM: /* SPDX-License-Identifier: */ + makefiles: # SPDX-License-Identifier: + scripts: # SPDX-License-Identifier: + texinfo: @c SPDX-License-Identifier: + text: # SPDX-License-Identifier: + + If a specific tool cannot handle the standard comment style, then the + appropriate comment mechanism which the tool accepts shall be used. This + is the reason for having the "/\* \*/" style comment in C header + files. There was build breakage observed with generated .lds files where + 'ld' failed to parse the C++ comment. This has been fixed by now, but + there are still older assembler tools which cannot handle C++ style + comments. + +3. Syntax: + + A is either an SPDX short form license + identifier found on the SPDX License List, or the combination of two + SPDX short form license identifiers separated by "WITH" when a license + exception applies. When multiple licenses apply, an expression consists + of keywords "AND", "OR" separating sub-expressions and surrounded by + "(", ")" . + + License identifiers for licenses like [L]GPL with the 'or later' option + are constructed by using a "-or-later": + + // SPDX-License-Identifier: GPL-2.0-or-later + // SPDX-License-Identifier: LGPL-2.1-or-later + + WITH should be used when there is a modifier to a license needed. + Exceptions can only be used with particular License identifiers. The + valid License identifiers are listed in the tags of the exception text + file. + + OR should be used if the file is dual licensed and only one license is + to be selected. For example, some source files are available under dual + licenses: + + // SPDX-License-Identifier: GPL-2.0-or-later OR BSD-1-Clause + // SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause + // SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause + + AND should be used if the file has multiple licenses whose terms all + apply to use the file. For example, if code is inherited from another + project and permission has been given to put it in OpenOCD, but the + original license terms need to remain in effect:: + + // SPDX-License-Identifier: GPL-2.0-or-later AND MIT + +License identifiers +------------------- + +The licenses currently used, as well as the licenses for code added to +OpenOCD, can be broken down into: + +1. `Preferred licenses`: + + Whenever possible these licenses should be used as they are known to be + fully compatible and widely used. These licenses are available from the + directory: + + LICENSES/preferred/ + + in the OpenOCD source tree. + + The files in this directory contain the full license text and + `Metatags`. The file names are identical to the SPDX license + identifier which shall be used for the license in source files. + + Examples: + + LICENSES/preferred/GPL-2.0 + + Contains the GPL version 2 license text and the required metatags. + + `Metatags`: + + The following meta tags must be available in a license file: + + - Valid-License-Identifier: + + One or more lines which declare which License Identifiers are valid + inside the project to reference this particular license text. Usually + this is a single valid identifier, but e.g. for licenses with the 'or + later' options two identifiers are valid. + + - SPDX-URL: + + The URL of the SPDX page which contains additional information related + to the license. + + - Usage-Guidance: + + Freeform text for usage advice. The text must include correct examples + for the SPDX license identifiers as they should be put into source + files according to the `License identifier syntax` guidelines. + + - License-Text: + + All text after this tag is treated as the original license text + + File format examples:: + + 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 + 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 General Public License (GPL) version 2 only' use: + 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. 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. + These licenses are available from the directory: + + LICENSES/stand-alone/ + + in the OpenOCD source tree. + + Examples: + + SPDX-License-Identifier: GPL-3.0 + +The format and requirements of the license files in the other sub-directories +of directory + + LICENSES + +have to follow the same format and requirements of the `Preferred licenses`. + +All SPDX license identifiers and exceptions must have a corresponding file +in the LICENSES subdirectories. This is required to allow tool +verification (e.g. checkpatch.pl) and to have the licenses ready to read +and extract right from the source, which is recommended by various FOSS +organizations, e.g. the `FSFE REUSE initiative `. diff --git a/LICENSES/preferred/BSD-1-Clause b/LICENSES/preferred/BSD-1-Clause new file mode 100644 index 0000000000..c63b05bf53 --- /dev/null +++ b/LICENSES/preferred/BSD-1-Clause @@ -0,0 +1,28 @@ +Valid-License-Identifier: BSD-1-Clause +SPDX-URL: https://spdx.org/licenses/BSD-1-Clause.html +Usage-Guide: + To use the BSD 1-clause 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-1-Clause +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. + +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/BSD-2-Clause b/LICENSES/preferred/BSD-2-Clause new file mode 100644 index 0000000000..da366e2ce5 --- /dev/null +++ b/LICENSES/preferred/BSD-2-Clause @@ -0,0 +1,32 @@ +Valid-License-Identifier: BSD-2-Clause +SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html +Usage-Guide: + To use the BSD 2-clause "Simplified" 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 +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. 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-3-Clause b/LICENSES/preferred/BSD-3-Clause new file mode 100644 index 0000000000..34c7f057c8 --- /dev/null +++ b/LICENSES/preferred/BSD-3-Clause @@ -0,0 +1,36 @@ +Valid-License-Identifier: BSD-3-Clause +SPDX-URL: https://spdx.org/licenses/BSD-3-Clause.html +Usage-Guide: + To use the BSD 3-clause "New" or "Revised" 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-3-Clause +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. + +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. 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/GFDL-1.2 b/LICENSES/preferred/GFDL-1.2 new file mode 100644 index 0000000000..9217d9c8ec --- /dev/null +++ b/LICENSES/preferred/GFDL-1.2 @@ -0,0 +1,412 @@ +Valid-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later +Valid-License-Identifier: GFDL-1.2-no-invariants-or-later +SPDX-URL: https://spdx.org/licenses/GFDL-1.2-no-invariants-or-later.html +Usage-Guide: + The GNU Free Documentation License should only be used without + Invariant Sections, Front-Cover Texts or Back-Cover Texts. + It should not be used for new documents. + To use the license in source code, put the following SPDX tag/value pair + into a comment according to the placement guidelines in the licensing + rules documentation: + SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + or + SPDX-License-Identifier: GFDL-1.2-no-invariants-or-later +License-Text: + + GNU Free Documentation License + Version 1.2, November 2002 + + + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 51 Franklin St, 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. + + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (Thus, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document 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. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation 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. See +https://www.gnu.org/licenses/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/LICENSES/preferred/GPL-2.0 b/LICENSES/preferred/GPL-2.0 new file mode 100644 index 0000000000..687bdddb11 --- /dev/null +++ b/LICENSES/preferred/GPL-2.0 @@ -0,0 +1,352 @@ +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 +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 General Public License (GPL) version 2 only' use: + 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: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 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. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, 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 or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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 to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), 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 Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. 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. + + + Copyright (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, 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. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. 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/preferred/MIT b/LICENSES/preferred/MIT new file mode 100644 index 0000000000..f33a68ceb3 --- /dev/null +++ b/LICENSES/preferred/MIT @@ -0,0 +1,30 @@ +Valid-License-Identifier: MIT +SPDX-URL: https://spdx.org/licenses/MIT.html +Usage-Guide: + To use the MIT License put the following SPDX tag/value pair into a + comment according to the placement guidelines in the licensing rules + documentation: + SPDX-License-Identifier: MIT +License-Text: + +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/LICENSES/preferred/gfdl-1.2.texi.readme b/LICENSES/preferred/gfdl-1.2.texi.readme new file mode 100644 index 0000000000..9375c7913b --- /dev/null +++ b/LICENSES/preferred/gfdl-1.2.texi.readme @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +The texinfo version of the license gfdl-1.2 is distributed in the +file doc/fdl.texi . 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/LICENSES/stand-alone/GPL-3.0 b/LICENSES/stand-alone/GPL-3.0 new file mode 100644 index 0000000000..97dde3ee85 --- /dev/null +++ b/LICENSES/stand-alone/GPL-3.0 @@ -0,0 +1,690 @@ +Valid-License-Identifier: GPL-3.0 +Valid-License-Identifier: GPL-3.0-only +Valid-License-Identifier: GPL-3.0-or-later +SPDX-URL: https://spdx.org/licenses/GPL-3.0.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 General Public License (GPL) version 3 only' use: + SPDX-License-Identifier: GPL-3.0 + or + SPDX-License-Identifier: GPL-3.0-only + For 'GNU General Public License (GPL) version 3 or any later version' use: + SPDX-License-Identifier: GPL-3.0-or-later +License-Text: + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, 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 +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (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 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Makefile.am b/Makefile.am index 930a307338..1313d151b5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,13 +1,16 @@ +# 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 +.DELETE_ON_ERROR: + # make sure we pass the correct jimtcl flags to distcheck DISTCHECK_CONFIGURE_FLAGS = --disable-install-jim # do not run Jim Tcl tests (esp. during distcheck) -check-recursive: - @true +check-recursive: SUBDIRS := nobase_dist_pkgdata_DATA = \ contrib/libdcc/dcc_stdio.c \ @@ -23,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 @@ -35,7 +42,6 @@ AM_CFLAGS = $(GCC_WARNINGS) AM_CPPFLAGS = $(HOST_CPPFLAGS)\ -I$(top_srcdir)/src \ -I$(top_builddir)/src \ - -I$(top_srcdir)/src/helper \ -DPKGDATADIR=\"$(pkgdatadir)\" \ -DBINDIR=\"$(bindir)\" @@ -48,9 +54,24 @@ EXTRA_DIST += \ HACKING \ NEWTAPS \ README.Windows \ - README.OSX \ - $(wildcard $(srcdir)/NEWS*) \ + README.macOS \ + $(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 \ tools/st7_dtc_as \ @@ -115,9 +136,9 @@ uninstall-hook: distclean-local: rm -rf Doxyfile doxygen - rm -f $(srcdir)/jimtcl/configure.gnu + -rm -f $(srcdir)/jimtcl/configure.gnu -DISTCLEANFILES = doxygen.log +DISTCLEANFILES += doxygen.log METASOURCES = AUTO diff --git a/NEWS b/NEWS index 9df165004a..9db6c5feee 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,8 @@ Board, Target, and Interface Configuration Scripts: Server Layer: +RTOS: + Documentation: Build and Release: diff --git a/NEWS-0.11.0 b/NEWS-0.11.0 new file mode 100644 index 0000000000..4542aa28f6 --- /dev/null +++ b/NEWS-0.11.0 @@ -0,0 +1,238 @@ +This file includes highlights of the changes made in the OpenOCD +source archive release. + +JTAG Layer: + * add debug level 4 for verbose I/O debug + * bitbang, add read buffer to improve performance + * Cadence SystemVerilog Direct Programming Interface (DPI) adapter driver + * CMSIS-DAP v2 (USB bulk based) adapter driver + * Cypress KitProg adapter driver + * FTDI FT232R sync bitbang adapter driver + * Linux GPIOD bitbang adapter driver through libgpiod + * Mellanox rshim USB or PCIe adapter driver + * Nuvoton Nu-Link and Nu-Link2 adapter drivers + * NXP IMX GPIO mmap based adapter driver + * ST-Link consolidate all versions in single config + * ST-Link read properly old USB serial numbers + * STLink/V3 support (for ST devices only !) + * STM8 SWIM transport + * TI XDS110 adapter driver + * Xilinx XVC/PCIe adapter driver + +Boundary Scan: + +Target Layer: + * 64 bit address support + * ARCv2 target support + * ARM Cortex-A hypervisor mode support + * ARM Cortex-M fast PC sampling support for profiling + * ARM generic CTI support + * ARM generic mem-ap target support + * ARMv7-A MMU tools + * ARMv7m traces add TCP stream server + * ARMv8 AARCH64 target support and semihosting support + * ARMv8 AARCH64 disassembler support through capstone library + * ARMv8-M target support + * EnSilica eSi-RISC target support, including instruction tracing + eSi-Trace support + * MIPS64 target support + * Motorola SREC S6 record image file support + * RISC-V target support + * SEGGER Real Time Transfer (RTT) initial support (for single target, + Cortex-M only) + * ST STM8 target support + * Various MIPS32 target improvements + +Flash Layer: + * Atheros (ath79) SPI interface support + * Atmel atmega128rfa1 support + * Atmel SAM D21, D51, DA1, E51, E53, E54, G55, R30 support + * Atmel SAMC2?N* support + * Cypress PSoC5LP, PSoC6 support + * EnSilica eSi-RISC support + * Foshan Synwit Tech SWM050 support + * Maxim Integrated MAX32XXX support + * Nordic Semiconductor nRF51822, nRF52810, nRF52832 support + * NXP Kinetis K27, K28, KE1x, KEAx, KL28, KL8x, KV5x, KWx support + * Renesas RPC HF support + * SH QSPI support + * SiFive Freedom E support + * Silicon Labs EFR-family, EZR32HG support + * ST BlueNRG support + * ST STM32 QUAD/OCTO-SPI interface support for Flash, FRAM and EEPROM + * ST STM32F72x, STM32F4x3, STM32H7xx support + * ST STM32G0xx, STM32G4xx, STM32L4x, STM32WB, STM32WL support + * ST STM32L5x support (non secure mode) + * TI CC13xx, CC26xx, CC32xx support + * TI MSP432 support + * Winner Micro w600 support + * Xilinx XCF platform support + * Various discrete SPI NOR flashes support + +Board, Target, and Interface Configuration Scripts: + * 8devices LIMA board config + * Achilles Instant-Development Kit Arria 10 board config + * Amazon Kindle 2 and DX board config + * Analog Devices ADSP-SC58x, ADSP-SC584-EZBRD board config + * Andes Technology ADP-XC7KFF676 board config + * Andes Technology Corvette-F1 board config + * ARM Musca A board config + * Arty Spartan 7 FPGA board config + * Atmel SAMD10 Xplained mini board config + * Atmel SAMD11 Xplained Pro board config + * Atmel SAM G55 Xplained Pro board config + * AVNET UltraZED EG StarterKit board config + * Blue Pill STM32F103C8 board config + * DP Busblaster v4.1a board config + * DPTechnics DPT-Board-v1 board config + * Emcraft imx8 SOM BSB board config + * Globalscale ESPRESSObin board config + * Kasli board config + * Kintex Ultrascale XCKU040 board config + * Knovative KC-100 board config + * LeMaker HiKey board config + * Microchip (Atmel) SAME54 Xplained Pro board config + * Microchip (Atmel) SAML11 Xplained Pro board config + * Nordic module NRF52 board config + * Numato Lab Mimas A7 board config + * NXP Freedom FRDM-LS1012A board config + * NXP IMX7SABRE board config + * NXP IMX8MP-EVK board config + * NXP MC-IMX8M-EVK board config + * QuickLogic QuickFeather board config + * Renesas R-Car E2, H2, M2 board config + * Renesas R-Car Salvator-X(S) board config + * Renesas RZ/A1H GR-Peach board config + * Rigado BMD-300 board config + * Sayma AMC board config + * Sifive e31arty, e51arty, hifive1 board config + * ST B-L475E-IOT01A board config + * ST BlueNRG idb007v1, idb008v1, idb011v1 board config + * ST STM32F412g discovery board config + * ST STM32F413h discovery board config + * ST STM32F469i discovery board config + * ST STM32F7 Nucleo board config + * ST STM32F723e discovery board config + * ST STM32F746g discovery board config + * ST STM32F769i discovery board config + * ST STM32H735g discovery board config + * ST STM32H743zi Nucleo board config + * ST STM32H745i discovery board config + * ST STM32H747i discovery board config + * ST STM32H750b discovery board config + * ST STM32H7b3i discovery board config + * ST STM32H7x_dual_qspi board config + * ST STM32H7x3i Eval boards config + * ST STM32L073 Nucleo board config + * ST STM32L476g discovery board config + * ST STM32L496g discovery board config + * ST STM32L4p5g discovery board config + * ST STM32L4r9i discovery board config + * ST STM32L5 Nucleo board config + * ST STM32MP15x DK2 board config + * ST STM32WB Nucleo board config + * ST STM8L152R8 Nucleo board config + * Synopsys DesignWare ARC EM board config + * Synopsys DesignWare ARC HSDK board config + * TI BeagleBone family boards config + * TI CC13xx, CC26xx, CC32xx LaunchPad board config + * TI MSP432 LaunchPad board config + * Tocoding Poplar board config + * TP-Link WDR4300 board config + * Allwinner V3s target config + * Andes Technology NDS V5 target config + * Atmel atmega128rfa1 target config + * ARM corelink SSE-200 target config + * Atheros_ar9344 target config + * Cypress PSoC5LP, PSoC6 target config + * EnSilica eSi-RISC target config + * Foshan Synwit Tech SWM050 target config + * GigaDevice GD32VF103 target config + * Hisilicon Hi3798 target config + * Hisilicon Hi6220 target config + * Infineon TLE987x target config + * Marvell Armada 3700 target config + * Maxim Integrated MAX32XXX target config + * Mellanox BlueField target config + * Microchip (Atmel) SAME5x, SAML1x target config + * NXP IMX6SX, IMX6UL, IMX7, IMX7ULP, IMX8 target config + * NXP Kinetis KE1xZ, KE1xF target config + * NXP LPC84x, LPC8Nxx, LS1012A, NHS31xx target config + * Qualcomm QCA4531 target config + * QuickLogic EOS S3 target config + * Renesas R-Car E2, H2, M2 target config + * Renesas R-Car Gen3 target config + * Renesas RZ/A1H target config + * Rockchip RK3308 target config + * ST BlueNRG target config + * ST STM32G0, STM32G4, STM32H7, STM32L0, STM32L5 target config + * ST STM32MP15x target config + * ST STM32WBx, STM32WLEx target config + * ST STM8L152, S003, S103, S105 target config + * Synopsys DesignWare ARC EM target config + * Synopsys DesignWare ARC HS Development Kit SoC target config + * TI CC13xx, CC26xx, CC32xx target config + * TI TNETC4401 target config + * Xilinx UltraScale+ target config + * Altera 5M570Z (MAXV family) CPLD config + * Xilinx Ultrascale, XCF CPLD config + * Intel (Altera) Arria10 FPGA config + * Cadence SystemVerilog Direct Programming Interface (DPI) interface config + * Cypress KitProg interface config + * Digilent SMT2 NC interface config + * DLN-2 example of Linux GPIOD interface config + * FTDI C232HM interface config + * HIE JTAG Debugger interface config + * In-Circuit's ICprog interface config + * isodebug isolated JTAG/SWD+UART interface config + * Mellanox rshim USB or PCIe interface config + * Nuvoton Nu-Link interface config + * NXP IMX GPIO mmap based interface config + * Steppenprobe open hardware interface config + * TI XDS110 interface config + +Server Layer: + * 64 bit address support + * default bind to IPv4 localhost + * gdb: allow multiple connections + * gdb: architecture element support + * gdb: vCont, vRun support + * telnet: handle Ctrl+A, Ctrl+E and Ctrl+K + +RTOS: + * Chromium-EC rtos support + * hwthread pseudo rtos support + * NuttX rtos support + * RIOT rtos support + +Documentation: + * Improve STM32 flash driver + * Various typo fix and improvements + +Build and Release: + * Add libutil to support jimtcl version 0.80 + * Clang warning fixes + * GitHub workflow for Win32 snapshot binaries + * Handle Tcl return values consistently + * Mitigation for CVE-2018-5704: Prevent some forms of Cross + Protocol Scripting attacks + * Support for libftdi 1.5 + * Travis-CI basic support + * Update libjaylink to version 0.2.0 + * Update jimtcl to version 0.79 + * Use external (optional) library capstone for ARM and AARCH64 disassembly + + +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.11.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/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 900324ab10..7d3f10def0 100644 --- a/README +++ b/README @@ -101,34 +101,43 @@ Supported hardware JTAG adapters ------------- -AICE, ARM-JTAG-EW, ARM-USB-OCD, ARM-USB-TINY, AT91RM9200, axm0432, -BCM2835, Bus Blaster, Buspirate, Chameleon, CMSIS-DAP, Cortino, DENX, -Digilent JTAG-SMT2, DLC 5, DLP-USB1232H, embedded projects, eStick, -FlashLINK, FlossJTAG, Flyswatter, Flyswatter2, Gateworks, Hoegl, ICDI, -ICEBear, J-Link, JTAG VPI, JTAGkey, JTAGkey2, JTAG-lock-pick, KT-Link, -Lisa/L, LPC1768-Stick, MiniModule, NGX, NXHX, OOCDLink, Opendous, -OpenJTAG, Openmoko, OpenRD, OSBDM, Presto, Redbee, RLink, SheevaPlug -devkit, Stellaris evkits, ST-LINK (SWO tracing supported), -STM32-PerformanceStick, STR9-comStick, sysfsgpio, TUMPA, Turtelizer, -ULINK, USB-A9260, USB-Blaster, USB-JTAG, USBprog, VPACLink, VSLLink, -Wiggler, XDS100v2, Xverve. +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, Tigard, TI XDS110, TUMPA, Turtelizer, ULINK, USB-A9260, USB-Blaster, +USB-JTAG, USBprog, VPACLink, VSLLink, Wiggler, XDS100v2, Xilinx XVC/PCIe, +Xverve. Debug targets ------------- -ARM11, ARM7, ARM9, AVR32, Cortex-A, Cortex-R, Cortex-M, LS102x-SAP, -Feroceon/Dragonite, DSP563xx, DSP5680xx, EnSilica eSi-RISC, FA526, MIPS -EJTAG, NDS32, XScale, Intel Quark. +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), +ESP32, ESP32-S2, ESP32-S3, Intel Quark, LS102x-SAP, RISC-V, ST STM8, +Xtensa. Flash drivers ------------- -ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, eSi-TSMC, FM3, -FM4, Freedom E SPI, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, -LPCSPIFI, Marvell QSPI, Milandr, NIIET, NuMicro, PIC32mx, PSoC4, PSoC5LP, -SiM3x, Stellaris, STM32, STMSMI, STR7x, STR9x, nRF51; NAND controllers of -AT91SAM9, LPC3180, LPC32xx, i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx, -S3C6400, XMC1xxx, XMC4xxx. +ADUC702x, AT91SAM, AT91SAM9 (NAND), ATH79, ATmega128RFA1, Atmel SAM, AVR, CFI, +DSP5680xx, EFM32, EM357, eSi-RISC, eSi-TSMC, EZR32HG, FM3, FM4, Freedom E SPI, +GD32, i.MX31, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPC3180, LPC32xx, +LPCSPIFI, Marvell QSPI, MAX32, Milandr, MXC, NIIET, nRF51, nRF52 , NuMicro, +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, +XMC1xxx, XMC4xxx. ================== @@ -210,23 +219,36 @@ 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: -- autoconf >= 2.64 +- autoconf >= 2.69 - automake >= 1.14 -- texinfo +- texinfo >= 5.0 -USB-based adapters depend on libusb-1.0 and some older drivers require -libusb-0.1 or libusb-compat-0.1. 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 6c616f38ac..64bf5c0c6f 100644 --- a/README.Windows +++ b/README.Windows @@ -40,10 +40,6 @@ WinUSB.sys to the composite parent instead of the specific interface. To do that one needs to activate an advanced option in the Zadig installer. -For the old drivers that use libusb-0.1 API you might need to link -against libusb-win32 headers and install the corresponding driver with -Zadig. - If you need to use the same adapter with other applications that may require another driver, a solution for Windows Vista and above is to activate the IgnoreHWSerNum registry setting for the USB device. @@ -56,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/README.OSX b/README.macOS similarity index 77% rename from README.OSX rename to README.macOS index 979c64ba60..91d5e9261b 100644 --- a/README.OSX +++ b/README.macOS @@ -1,10 +1,10 @@ -Building OpenOCD for OSX ------------------------- +Building OpenOCD for macOS +-------------------------- There are a few prerequisites you will need first: -- Xcode 5 (install from the AppStore) -- Command Line Tools (install from Xcode 5 -> Preferences -> Downloads) +- Xcode (install from the AppStore) +- Command Line Tools (install from Xcode -> Preferences -> Downloads) - Gentoo Prefix (http://www.gentoo.org/proj/en/gentoo-alt/prefix/bootstrap.xml) or - Homebrew (http://mxcl.github.io/homebrew/) @@ -12,6 +12,11 @@ There are a few prerequisites you will need first: - MacPorts (http://www.macports.org/install.php) +If you're building manually you need Texinfo version 5.0 or later. The +simplest way to get it is to use Homebrew (brew install texinfo) and +then ``export PATH=/usr/local/opt/texinfo/bin:$PATH``. + + With Gentoo Prefix you can build the release version or the latest devel version (-9999) the usual way described in the Gentoo documentation. Alternatively, install the prerequisites and build @@ -22,14 +27,14 @@ With Homebrew you can either run: brew install [--HEAD] openocd (where optional --HEAD asks brew to install the current git version) or - brew install libtool automake libusb [libusb-compat] [hidapi] [libftdi] + brew install libtool automake libusb [hidapi] [libftdi] (to install the needed dependencies and then proceed with the manual building procedure) For building with MacPorts you need to run: sudo port install libtool automake autoconf pkgconfig \ - libusb [libusb-compat] [libftdi1] + libusb [libftdi1] You should also specify LDFLAGS and CPPFLAGS to allow configure to use MacPorts' libraries, so run configure like this: 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/config_subdir.m4 b/config_subdir.m4 index 1c7909853d..2be590e44a 100644 --- a/config_subdir.m4 +++ b/config_subdir.m4 @@ -1,17 +1,3 @@ -dnl -dnl If needed, define the m4_ifblank and m4_ifnblank macros from autoconf 2.64 -dnl This allows us to run with earlier Autoconfs as well. -ifdef([m4_ifblank],[],[ -m4_define([m4_ifblank], -[m4_if(m4_translit([[$1]], [ ][ ][ -]), [], [$2], [$3])])]) -dnl -ifdef([m4_ifnblank],[],[ -m4_define([m4_ifnblank], -[m4_if(m4_translit([[$1]], [ ][ ][ -]), [], [$3], [$2])])]) -dnl - dnl AC_CONFIG_SUBDIRS does not allow configure options to be passed dnl to subdirs, this function allows that by creating a configure.gnu dnl script that prepends configure options and then calls the real @@ -21,6 +7,6 @@ AC_DEFUN([AX_CONFIG_SUBDIR_OPTION], AC_CONFIG_SUBDIRS([$1]) m4_ifblank([$2], [rm -f $srcdir/$1/configure.gnu], -[echo -e '#!/bin/sh\nexec "`dirname "'\$'0"`/configure" $2 "'\$'@"' > "$srcdir/$1/configure.gnu" +[echo -e '#!/bin/sh\nexec "`dirname "'\$'0"`/configure" '"$2"' "'\$'@"' > "$srcdir/$1/configure.gnu" ]) ]) diff --git a/configure.ac b/configure.ac index 90ac2a98c3..7613848371 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,10 @@ -AC_PREREQ(2.64) -AC_INIT([openocd], [0.10.0+dev], +# SPDX-License-Identifier: GPL-2.0-or-later + +AC_PREREQ([2.69]) +AC_INIT([openocd], [0.12.0+dev], [OpenOCD Mailing List ]) AC_CONFIG_SRCDIR([src/openocd.c]) +AC_CONFIG_AUX_DIR([build-aux]) m4_include([config_subdir.m4])dnl @@ -16,17 +19,19 @@ AC_SUBST([MAKEINFO]) AM_INIT_AUTOMAKE([-Wall -Wno-portability dist-bzip2 dist-zip subdir-objects]) AC_CONFIG_HEADERS([config.h]) -AH_BOTTOM([ -#include -#include -#include -]) AC_LANG([C]) AC_PROG_CC -AC_PROG_CC_C99 +# autoconf 2.70 obsoletes AC_PROG_CC_C99 and includes it in 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 @@ -43,15 +48,17 @@ AC_TYPE_LONG_LONG_INT AC_SEARCH_LIBS([ioperm], [ioperm]) AC_SEARCH_LIBS([dlopen], [dl]) +AC_SEARCH_LIBS([openpty], [util]) AC_CHECK_HEADERS([sys/socket.h]) AC_CHECK_HEADERS([elf.h]) -AC_CHECK_HEADERS([dirent.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([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]) @@ -61,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 @@ -78,7 +85,6 @@ AC_CHECK_HEADERS([arpa/inet.h ifaddrs.h netinet/in.h netinet/tcp.h net/if.h], [] AC_HEADER_ASSERT AC_HEADER_STDBOOL -AC_HEADER_TIME AC_C_BIGENDIAN @@ -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 @@ -113,21 +118,21 @@ 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]], [[xds110], [TI XDS110 Debug Probe], [XDS110]], + [[cmsis_dap_v2], [CMSIS-DAP v2 Compliant Debugger], [CMSIS_DAP_USB]], [[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]], [[opendous], [eStick/opendous JTAG Programmer], [OPENDOUS]], - [[aice], [Andes JTAG Programmer], [AICE]]]) - -m4_define([USB0_ADAPTERS], - [[[usbprog], [USBProg JTAG Programmer], [USBPROG]], + [[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]], [[rlink], [Raisonance RLink JTAG Programmer], [RLINK]], - [[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]]]) + [[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]], + [[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP_HID]], [[nulink], [Nu-Link Programmer], [HLADAPTER_NULINK]]]) m4_define([HIDAPI_USB1_ADAPTERS], @@ -135,8 +140,10 @@ m4_define([HIDAPI_USB1_ADAPTERS], m4_define([LIBFTDI_ADAPTERS], [[[usb_blaster], [Altera USB-Blaster Compatible], [USB_BLASTER]], - [[presto], [ASIX Presto Adapter], [PRESTO]], - [[openjtag], [OpenJTAG Adapter], [OPENJTAG]]]) + [[presto], [ASIX Presto Adapter], [PRESTO]]]) + +m4_define([LIBFTDI_USB1_ADAPTERS], + [[[openjtag], [OpenJTAG Adapter], [OPENJTAG]]]) m4_define([LIBGPIOD_ADAPTERS], [[[linuxgpiod], [Linux GPIO bitbang through libgpiod], [LINUXGPIOD]]]) @@ -147,6 +154,11 @@ m4_define([LIBJAYLINK_ADAPTERS], m4_define([PCIE_ADAPTERS], [[[xlnx_pcie_xvc], [Xilinx XVC/PCIe], [XLNX_PCIE_XVC]]]) +m4_define([SERIAL_PORT_ADAPTERS], + [[[buspirate], [Bus Pirate], [BUS_PIRATE]]]) + +m4_define([OPTIONAL_LIBRARIES], + [[[capstone], [Use Capstone disassembly framework], []]]) AC_ARG_ENABLE([doxygen-html], AS_HELP_STRING([--disable-doxygen-html], @@ -230,6 +242,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]), @@ -241,11 +257,12 @@ m4_define([AC_ARG_ADAPTERS], [ AC_ARG_ADAPTERS([ USB1_ADAPTERS, - USB0_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, + LIBFTDI_USB1_ADAPTERS LIBGPIOD_ADAPTERS, + SERIAL_PORT_ADAPTERS, LIBJAYLINK_ADAPTERS ],[auto]) @@ -267,22 +284,18 @@ AC_ARG_ENABLE([jtag_vpi], AS_HELP_STRING([--enable-jtag_vpi], [Enable building support for JTAG VPI]), [build_jtag_vpi=$enableval], [build_jtag_vpi=no]) +AC_ARG_ENABLE([vdebug], + AS_HELP_STRING([--enable-vdebug], [Enable building support for Cadence Virtual Debug Interface]), + [build_vdebug=$enableval], [build_vdebug=no]) + +AC_ARG_ENABLE([jtag_dpi], + AS_HELP_STRING([--enable-jtag_dpi], [Enable building support for JTAG DPI]), + [build_jtag_dpi=$enableval], [build_jtag_dpi=no]) + AC_ARG_ENABLE([amtjtagaccel], AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec JTAG-Accelerator driver]), [build_amtjtagaccel=$enableval], [build_amtjtagaccel=no]) -AC_ARG_ENABLE([zy1000_master], - AS_HELP_STRING([--enable-zy1000-master], [Use ZY1000 JTAG master registers]), - [build_zy1000_master=$enableval], [build_zy1000_master=no]) - -AC_ARG_ENABLE([zy1000], - AS_HELP_STRING([--enable-zy1000], [Enable ZY1000 interface]), - [build_zy1000=$enableval], [build_zy1000=no]) - -AC_ARG_ENABLE([ioutil], - AS_HELP_STRING([--enable-ioutil], [Enable ioutil functions - useful for standalone OpenOCD implementations]), - [build_ioutil=$enableval], [build_ioutil=no]) - AS_CASE(["${host_cpu}"], [arm*|aarch64], [ AC_ARG_ENABLE([bcm2835gpio], @@ -291,10 +304,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}"], @@ -316,15 +333,6 @@ AC_ARG_ENABLE([gw16012], AS_HELP_STRING([--enable-gw16012], [Enable building support for the Gateworks GW16012 JTAG Programmer]), [build_gw16012=$enableval], [build_gw16012=no]) -AC_ARG_ENABLE([oocd_trace], - AS_HELP_STRING([--enable-oocd_trace], - [Enable building support for some prototype OpenOCD+trace ETM capture hardware]), - [build_oocd_trace=$enableval], [build_oocd_trace=no]) - -AC_ARG_ENABLE([buspirate], - AS_HELP_STRING([--enable-buspirate], [Enable building support for the Buspirate]), - [build_buspirate=$enableval], [build_buspirate=no]) - AC_ARG_ENABLE([sysfsgpio], AS_HELP_STRING([--enable-sysfsgpio], [Enable building support for programming driven via sysfs gpios.]), [build_sysfsgpio=$enableval], [build_sysfsgpio=no]) @@ -354,58 +362,29 @@ AS_CASE([$host_os], AC_MSG_ERROR([build_rshim is only available on linux or freebsd]) ]) ]) -]) -AC_ARG_ENABLE([minidriver_dummy], - AS_HELP_STRING([--enable-minidriver-dummy], [Enable the dummy minidriver.]), - [build_minidriver_dummy=$enableval], [build_minidriver_dummy=no]) + AS_IF([test "x$build_dmem" = "xyes"], [ + AC_MSG_ERROR([dmem is only available on linux]) + ]) +]) AC_ARG_ENABLE([internal-jimtcl], AS_HELP_STRING([--disable-internal-jimtcl], [Disable building internal jimtcl]), [use_internal_jimtcl=$enableval], [use_internal_jimtcl=yes]) +AC_ARG_ENABLE([jimtcl-maintainer], + AS_HELP_STRING([--enable-jimtcl-maintainer], [Enable maintainer mode when building internal jimtcl]), + [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]) - -build_minidriver=no -AC_MSG_CHECKING([whether to enable ZY1000 minidriver]) -AS_IF([test "x$build_zy1000" = "xyes"], [ - AS_IF([test "x$build_minidriver" = "xyes"], [ - AC_MSG_ERROR([Multiple minidriver options have been enabled.]) - ]) - AC_DEFINE([HAVE_JTAG_MINIDRIVER_H], [1], - [Define to 1 if you have the header file.]) - build_minidriver=yes -]) -AC_MSG_RESULT([$build_zy1000]) + 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=no]) -AC_MSG_CHECKING([whether to enable dummy minidriver]) -AS_IF([test "x$build_minidriver_dummy" = "xyes"], [ - AS_IF([test "x$build_minidriver" = "xyes"], [ - AC_MSG_ERROR([Multiple minidriver options have been enabled.]) - ]) - build_minidriver=yes - AC_DEFINE([BUILD_MINIDRIVER_DUMMY], [1], [Use the dummy minidriver.]) - AC_DEFINE([HAVE_JTAG_MINIDRIVER_H], [1], - [Define to 1 if you have the header file.]) -]) -AC_MSG_RESULT([$build_minidriver_dummy]) - -AC_MSG_CHECKING([whether standard drivers can be built]) -AS_IF([test "x$build_minidriver" = "xyes"], [ - AC_MSG_RESULT([no]) - AC_MSG_WARN([Using the minidriver disables all other drivers.]) - sleep 2 -], [ - AC_MSG_RESULT([yes]) -]) - AS_CASE(["${host_cpu}"], [i?86|x86*], [], [ @@ -446,10 +425,13 @@ AS_CASE([$host], ]) parport_use_giveio=yes - AS_IF([test "x$build_buspirate" = "xyes"], [ + AS_IF([test "x$enable_buspirate" = "xyes"], [ AC_MSG_ERROR([buspirate currently not supported by MinGW32 hosts]) ]) + # In case enable_buspirate=auto, make sure it will not be built. + enable_buspirate=no + AC_SUBST([HOST_CPPFLAGS], [-D__USE_MINGW_ANSI_STDIO]) ], [*darwin*], [ @@ -504,6 +486,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.]) @@ -518,18 +506,6 @@ AS_IF([test "x$build_ep93xx" = "xyes"], [ AC_DEFINE([BUILD_EP93XX], [0], [0 if you don't want ep93xx.]) ]) -AS_IF([test "x$build_zy1000" = "xyes"], [ - AC_DEFINE([BUILD_ZY1000], [1], [1 if you want ZY1000.]) -], [ - AC_DEFINE([BUILD_ZY1000], [0], [0 if you don't want ZY1000.]) -]) - -AS_IF([test "x$build_zy1000_master" = "xyes"], [ - AC_DEFINE([BUILD_ZY1000_MASTER], [1], [1 if you want ZY1000 JTAG master registers.]) -], [ - AC_DEFINE([BUILD_ZY1000_MASTER], [0], [0 if you don't want ZY1000 JTAG master registers.]) -]) - AS_IF([test "x$build_at91rm9200" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_AT91RM9200], [1], [1 if you want at91rm9200.]) @@ -551,6 +527,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.]) ], [ @@ -569,6 +552,19 @@ AS_IF([test "x$build_jtag_vpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_VPI], [0], [0 if you don't want JTAG VPI.]) ]) +AS_IF([test "x$build_vdebug" = "xyes"], [ + AC_DEFINE([BUILD_VDEBUG], [1], [1 if you want Cadence vdebug interface.]) +], [ + AC_DEFINE([BUILD_VDEBUG], [0], [0 if you don't want Cadence vdebug interface.]) +]) + +AS_IF([test "x$build_jtag_dpi" = "xyes"], [ + AC_DEFINE([BUILD_JTAG_DPI], [1], [1 if you want JTAG DPI.]) +], [ + AC_DEFINE([BUILD_JTAG_DPI], [0], [0 if you don't want JTAG DPI.]) +]) + + AS_IF([test "x$build_amtjtagaccel" = "xyes"], [ AC_DEFINE([BUILD_AMTJTAGACCEL], [1], [1 if you want the Amontec JTAG-Accelerator driver.]) ], [ @@ -581,21 +577,20 @@ AS_IF([test "x$build_gw16012" = "xyes"], [ AC_DEFINE([BUILD_GW16012], [0], [0 if you don't want the Gateworks GW16012 driver.]) ]) -AS_IF([test "x$build_oocd_trace" = "xyes"], [ - AC_DEFINE([BUILD_OOCD_TRACE], [1], [1 if you want the OpenOCD+trace ETM capture driver.]) -], [ - AC_DEFINE([BUILD_OOCD_TRACE], [0], [0 if you don't want the OpenOCD+trace ETM capture driver.]) -]) - -AS_IF([test "x$build_buspirate" = "xyes"], [ +AS_IF([test "x$enable_buspirate" != "xno"], [ AC_DEFINE([BUILD_BUSPIRATE], [1], [1 if you want the Buspirate JTAG driver.]) ], [ AC_DEFINE([BUILD_BUSPIRATE], [0], [0 if you don't want the Buspirate JTAG driver.]) ]) AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ - AS_IF([test -f "$srcdir/jimtcl/configure.ac"], [ - AX_CONFIG_SUBDIR_OPTION([jimtcl], [--disable-install-jim]) + AS_IF([test -f "$srcdir/jimtcl/configure"], [ + AS_IF([test "x$use_internal_jimtcl_maintainer" = "xyes"], [ + jimtcl_config_options="--disable-install-jim --with-ext=json --minimal --disable-ssl --maintainer" + ], [ + jimtcl_config_options="--disable-install-jim --with-ext=json --minimal --disable-ssl" + ]) + AX_CONFIG_SUBDIR_OPTION([jimtcl], [$jimtcl_config_options]) ], [ AC_MSG_ERROR([jimtcl not found, run git submodule init and git submodule update.]) ]) @@ -603,9 +598,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"], [ @@ -625,9 +620,6 @@ AS_IF([test "x$build_xlnx_pcie_xvc" = "xyes"], [ PKG_CHECK_MODULES([LIBUSB1], [libusb-1.0], [ use_libusb1=yes AC_DEFINE([HAVE_LIBUSB1], [1], [Define if you have libusb-1.x]) - PKG_CHECK_EXISTS([libusb-1.0 >= 1.0.9], - [AC_DEFINE([HAVE_LIBUSB_ERROR_NAME], [1], [Define if your libusb has libusb_error_name()])], - [AC_MSG_WARN([libusb-1.x older than 1.0.9 detected, consider updating])]) LIBUSB1_CFLAGS=`echo $LIBUSB1_CFLAGS | sed 's/-I/-isystem /'` AC_MSG_NOTICE([libusb-1.0 header bug workaround: LIBUSB1_CFLAGS changed to "$LIBUSB1_CFLAGS"]) PKG_CHECK_EXISTS([libusb-1.0 >= 1.0.16], @@ -637,7 +629,28 @@ PKG_CHECK_MODULES([LIBUSB1], [libusb-1.0], [ AC_MSG_WARN([libusb-1.x not found, trying legacy libusb-0.1 as a fallback; consider installing libusb-1.x instead]) ]) -PKG_CHECK_MODULES([LIBUSB0], [libusb], [use_libusb0=yes], [use_libusb0=no]) +AC_ARG_WITH([capstone], + AS_HELP_STRING([--with-capstone], [Use Capstone disassembly library (default=auto)]) + , [ + enable_capstone=$withval + ], [ + enable_capstone=auto +]) + +AS_IF([test "x$enable_capstone" != xno], [ + PKG_CHECK_MODULES([CAPSTONE], [capstone], [ + AC_DEFINE([HAVE_CAPSTONE], [1], [1 if you have Capstone disassembly framework.]) + ], [ + if test "x$enable_capstone" != xauto; then + AC_MSG_ERROR([--with-capstone was given, but test for Capstone failed]) + fi + enable_capstone=no + ]) +]) + +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],[ @@ -648,20 +661,25 @@ for hidapi_lib in hidapi hidapi-hidraw hidapi-libusb; do ]) done -PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [use_libftdi=yes], [ +PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [ + use_libftdi=yes + PKG_CHECK_EXISTS([libftdi1 >= 1.5], + [AC_DEFINE([HAVE_LIBFTDI_TCIOFLUSH], [1], [Define if your libftdi has ftdi_tcioflush()])]) + ], [ PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no]) ]) -PKG_CHECK_MODULES([LIBGPIOD], [libgpiod], [use_libgpiod=yes], [use_libgpiod=no]) +PKG_CHECK_MODULES([LIBGPIOD], [libgpiod < 2.0], [ + use_libgpiod=yes + PKG_CHECK_EXISTS([libgpiod >= 1.5], + [AC_DEFINE([HAVE_LIBGPIOD1_FLAGS_BIAS], [1], [define if libgpiod v1 has line request flags bias])]) +], [use_libgpiod=no]) PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], [use_libjaylink=yes], [use_libjaylink=no]) m4_define([PROCESS_ADAPTERS], [ m4_foreach([adapter], [$1], [ - AS_IF([test "x$build_zy1000" = "xyes"], [ - ADAPTER_VAR([adapter])=no - ]) AS_IF([test $2], [ AS_IF([test "x$ADAPTER_VAR([adapter])" != "xno"], [ AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [1], [1 if you want the ]ADAPTER_DESC([adapter]).) @@ -673,26 +691,20 @@ m4_define([PROCESS_ADAPTERS], [ AC_MSG_ERROR([$3 is required for the ADAPTER_DESC([adapter])]) ]) ADAPTER_VAR([adapter])=no + AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [0], [0 if you do not want the ]ADAPTER_DESC([adapter]).) ]) AM_CONDITIONAL(ADAPTER_SYM([adapter]), [test "x$ADAPTER_VAR([adapter])" != "xno"]) ]) ]) PROCESS_ADAPTERS([USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x]) -PROCESS_ADAPTERS([USB0_ADAPTERS], ["x$use_libusb0" = "xyes"], [libusb-0.1]) 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]) +PROCESS_ADAPTERS([LIBFTDI_USB1_ADAPTERS], ["x$use_libftdi" = "xyes" -a "x$use_libusb1" = "xyes"], [libftdi and libusb-1.x]) PROCESS_ADAPTERS([LIBGPIOD_ADAPTERS], ["x$use_libgpiod" = "xyes"], [libgpiod]) PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.2]) -AS_IF([test "x$build_openjtag" = "xyes"], [ - AS_IF([test "x$use_libusb1" != "xyes" -a "x$use_libusb0" != "xyes"], [ - AC_MSG_ERROR([libusb-1.x or libusb-0.1 is required for the OpenJTAG Programmer]) - build_openjtag=no - ]) -]) - AS_IF([test "x$enable_linuxgpiod" != "xno"], [ build_bitbang=yes ]) @@ -714,7 +726,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'.]) ]) ]) ]) @@ -724,28 +736,31 @@ 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"]) AM_CONDITIONAL([GIVEIO], [test "x$parport_use_giveio" = "xyes"]) AM_CONDITIONAL([EP93XX], [test "x$build_ep93xx" = "xyes"]) -AM_CONDITIONAL([ZY1000], [test "x$build_zy1000" = "xyes"]) -AM_CONDITIONAL([ZY1000_MASTER], [test "x$build_zy1000_master" = "xyes"]) -AM_CONDITIONAL([IOUTIL], [test "x$build_ioutil" = "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" -o "x$build_jtag_vpi" = "xyes"]) +AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"]) +AM_CONDITIONAL([VDEBUG], [test "x$build_vdebug" = "xyes"]) +AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes"]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) AM_CONDITIONAL([AMTJTAGACCEL], [test "x$build_amtjtagaccel" = "xyes"]) AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"]) -AM_CONDITIONAL([OOCD_TRACE], [test "x$build_oocd_trace" = "xyes"]) AM_CONDITIONAL([REMOTE_BITBANG], [test "x$build_remote_bitbang" = "xyes"]) -AM_CONDITIONAL([BUSPIRATE], [test "x$build_buspirate" = "xyes"]) +AM_CONDITIONAL([BUSPIRATE], [test "x$enable_buspirate" != "xno"]) AM_CONDITIONAL([SYSFSGPIO], [test "x$build_sysfsgpio" = "xyes"]) AM_CONDITIONAL([XLNX_PCIE_XVC], [test "x$build_xlnx_pcie_xvc" = "xyes"]) -AM_CONDITIONAL([USE_LIBUSB0], [test "x$use_libusb0" = "xyes"]) AM_CONDITIONAL([USE_LIBUSB1], [test "x$use_libusb1" = "xyes"]) AM_CONDITIONAL([IS_CYGWIN], [test "x$is_cygwin" = "xyes"]) AM_CONDITIONAL([IS_MINGW], [test "x$is_mingw" = "xyes"]) @@ -757,9 +772,8 @@ 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([MINIDRIVER], [test "x$build_minidriver" = "xyes"]) -AM_CONDITIONAL([MINIDRIVER_DUMMY], [test "x$build_minidriver_dummy" = "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"]) AM_CONDITIONAL([INTERNAL_LIBJAYLINK], [test "x$use_internal_libjaylink" = "xyes"]) @@ -804,6 +818,8 @@ AS_IF([test "x${gcc_wextra}" = "xyes"], [ GCC_WARNINGS="${GCC_WARNINGS} -Wbad-function-cast" GCC_WARNINGS="${GCC_WARNINGS} -Wcast-align" GCC_WARNINGS="${GCC_WARNINGS} -Wredundant-decls" + GCC_WARNINGS="${GCC_WARNINGS} -Wpointer-arith" + GCC_WARNINGS="${GCC_WARNINGS} -Wundef" ]) AS_IF([test "x${gcc_werror}" = "xyes"], [ GCC_WARNINGS="${GCC_WARNINGS} -Werror" @@ -814,19 +830,29 @@ AS_IF([test "x$gcc_warnings" = "xyes"], [ AC_SUBST([GCC_WARNINGS], [$GCC_WARNINGS]) ]) +AC_SUBST(EXTRA_DIST_NEWS, ["$(echo $srcdir/NEWS-*)"]) + AC_CONFIG_FILES([ Makefile ]) 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, USB0_ADAPTERS, +m4_foreach([adapter], [USB1_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, + LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, - LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS], + LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS, + OPTIONAL_LIBRARIES], [s=m4_format(["%-40s"], ADAPTER_DESC([adapter])) AS_CASE([$ADAPTER_VAR([adapter])], [auto], [ @@ -840,26 +866,3 @@ m4_foreach([adapter], [USB1_ADAPTERS, USB0_ADAPTERS, ]) ]) echo - -AS_IF([test "x$build_oocd_trace" = "xyes"], [ - echo 'WARNING! Deprecated configure option (--enable-oocd_trace)' - echo 'The oocd_trace driver is deprecated and will be removed in the next release.' - echo 'If you regularly use this driver, please report to the OpenOCD Mailing List.' - echo -]) - -AS_IF([test "x$build_zy1000" = "xyes" -o "x$build_zy1000_master" = "xyes"], [ - echo 'WARNING! Deprecated configure option (--enable-zy1000, --enable-zy1000-master)' - echo 'Support for the ZY1000 platform is deprecated and will be removed in the next' - echo 'release. If you regularly use this platform, please report to the OpenOCD' - echo 'Mailing List.' - echo -]) - -AS_IF([test "x$build_ioutil" = "xyes"], [ - echo 'WARNING! Deprecated configure option (--enable-ioutil)' - echo 'Support for the ioutil functions is deprecated and will be removed in the next' - echo 'release. If you regularly depend on this functionality, please report to the' - echo 'OpenOCD Mailing List.' - echo -]) diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules index 53f97dd830..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" @@ -24,6 +26,8 @@ ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="660", GROUP="plugdev", # Original FT232H VID:PID ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Original FT231XQ VID:PID +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", MODE="660", GROUP="plugdev", TAG+="uaccess" # DISTORTEC JTAG-lock-pick Tiny 2 ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -32,8 +36,19 @@ ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="660", GROUP="plugdev", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Marvell OpenRD JTAGKey FT2232D B +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="9e90", MODE="660", GROUP="plugdev", TAG+="uaccess" + # XDS100v2 ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="660", GROUP="plugdev", TAG+="uaccess" +# XDS100v3 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d1", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# OOCDLink +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="baf8", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Kristech KT-Link +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bbe2", MODE="660", GROUP="plugdev", TAG+="uaccess" # Xverve Signalyzer Tool (DT-USB-ST), Signalyzer LITE (DT-USB-SLITE) ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -55,6 +70,9 @@ ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="660", GROUP="plugdev", # Amontec JTAGkey and JTAGkey-tiny ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="660", GROUP="plugdev", TAG+="uaccess" +# ASIX Presto programmer +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="f1a0", MODE="660", GROUP="plugdev", TAG+="uaccess" + # Nuvoton NuLink ATTRS{idVendor}=="0416", ATTRS{idProduct}=="511b", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0416", ATTRS{idProduct}=="511c", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -80,6 +98,12 @@ ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374d", MODE="660", GROUP="plugdev", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374e", MODE="660", GROUP="plugdev", TAG+="uaccess" 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" # Cypress KitProg in KitProg mode ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f139", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -87,6 +111,12 @@ ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f139", MODE="660", GROUP="plugdev", # Cypress KitProg in CMSIS-DAP mode ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f138", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Infineon DAP miniWiggler v3 +ATTRS{idVendor}=="058b", ATTRS{idProduct}=="0043", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Hitex LPC1768-Stick +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0026", MODE="660", GROUP="plugdev", TAG+="uaccess" + # Hilscher NXHX Boards ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -96,8 +126,17 @@ ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="660", GROUP="plugdev", # Hitex STM32-PerformanceStick ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Hitex Cortino +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0032", MODE="660", GROUP="plugdev", TAG+="uaccess" + # Altera USB Blaster ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Altera USB Blaster2 +ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6810", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Ashling Opella-LD +ATTRS{idVendor}=="0B6B", ATTRS{idProduct}=="0040", MODE="660", GROUP="plugdev", TAG+="uaccess" # Amontec JTAGkey-HiSpeed ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -119,7 +158,9 @@ ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", MODE="660", GROUP="plugdev", ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1016", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1018", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1020", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1051", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1055", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1061", MODE="660", GROUP="plugdev", TAG+="uaccess" # Raisonance RLink @@ -128,6 +169,11 @@ ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="660", GROUP="plugdev", # Debug Board for Neo1973 ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="660", GROUP="plugdev", TAG+="uaccess" +# OSBDM +ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="0042", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="0058", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="005e", MODE="660", GROUP="plugdev", TAG+="uaccess" + # Olimex ARM-USB-OCD ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -143,6 +189,9 @@ ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="660", GROUP="plugdev", # Olimex ARM-USB-OCD-H ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="660", GROUP="plugdev", TAG+="uaccess" +# ixo-usb-jtag - Emulation of a Altera Bus Blaster I on a Cypress FX2 IC +ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="06ad", MODE="660", GROUP="plugdev", TAG+="uaccess" + # USBprog with OpenOCD firmware ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -157,16 +206,37 @@ ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="02a5", MODE="660", GROUP="plugdev", # TI Tiva-based ICDI and XDS110 probes in DFU mode ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00ff", MODE="660", GROUP="plugdev", TAG+="uaccess" +# isodebug v1 +ATTRS{idVendor}=="22b7", ATTRS{idProduct}=="150d", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# PLS USB/JTAG Adapter for SPC5xxx +ATTRS{idVendor}=="263d", ATTRS{idProduct}=="4001", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Numato Mimas A7 - Artix 7 FPGA Board +ATTRS{idVendor}=="2a19", ATTRS{idProduct}=="1009", MODE="660", GROUP="plugdev", TAG+="uaccess" + # Ambiq Micro EVK and Debug boards. -ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6011", MODE="664", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="1106", MODE="664", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", TAG+="uaccess" +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" # Keil Software, Inc. ULink ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2750", MODE="660", GROUP="plugdev", TAG+="uaccess" # CMSIS-DAP compatible adapters ATTRS{product}=="*CMSIS-DAP*", 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 821d48ec77..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 @@ -14,8 +15,8 @@ # paths refer to the build file system. # # This script is probably more useful as a reference than as a complete build -# tool but for some configurations it may be usable as-is. It only cross- -# builds libusb-1.0, hidapi and libftdi from source, but the script can be +# tool but for some configurations it may be usable as-is. It only cross-builds +# libusb-1.0, hidapi, libftdi and capstone from source, but the script can be # extended to build other prerequisites in a similar manner. # # Usage: @@ -39,17 +40,23 @@ WORK_DIR=$PWD : ${LIBUSB1_SRC:=/path/to/libusb1} : ${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 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 @@ -118,17 +125,53 @@ 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 make install DESTDIR=$SYSROOT fi +# capstone build & install into sysroot +if [ -d $CAPSTONE_SRC ] ; then + mkdir -p $CAPSTONE_BUILD_DIR + cd $CAPSTONE_BUILD_DIR + cp -r $CAPSTONE_SRC/* . + make install DESTDIR=$SYSROOT PREFIX=$PREFIX \ + CROSS="${HOST_TRIPLET}-" \ + $CAPSTONE_CONFIG + # fix the generated capstone.pc + CAPSTONE_PC_FILE=${SYSROOT}${PREFIX}/lib/pkgconfig/capstone.pc + sed -i '/^libdir=/d' $CAPSTONE_PC_FILE + sed -i '/^includedir=/d' $CAPSTONE_PC_FILE + sed -i '/^archive=/d' $CAPSTONE_PC_FILE + sed -i '1s;^;prefix=/usr \ +exec_prefix=${prefix} \ +libdir=${exec_prefix}/lib \ +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 cd $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 24aa34f32b..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 @@ -39,8 +26,9 @@ #include #include -#include #include +#include +#include #include #include 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 new file mode 100644 index 0000000000..4fcfcdf348 --- /dev/null +++ b/contrib/list_example.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (C) 2021 by Andreas Fritiofson */ + +/* + * Simple example of using a circular doubly linked list through list.h + * + * gcc -I ../src/ list_example.c -o list_example + */ + +#include +#include +#include +#include + +static LIST_HEAD(threads); + +struct thread { + int id; + uint64_t tcb_address; + struct list_head lh; +}; + +void insert(struct thread *t) +{ + list_add_tail(&t->lh, &threads); +} + +void remove(struct thread *t) +{ + list_del(&t->lh); +} + +struct thread *lookup_id(int id) +{ + struct thread *t; + list_for_each_entry(t, &threads, lh) { + if (t->id == id) + return t; + } + return NULL; +} + +struct thread *lookup_tcb(uint64_t addr) +{ + struct thread *t; + list_for_each_entry(t, &threads, lh) { + if (t->tcb_address == addr) + return t; + } + return NULL; +} + +int main(void) +{ + struct thread t1 = { .id = 1, .tcb_address = 111111111 }; + struct thread t2 = { .id = 2, .tcb_address = 222222222 }; + struct thread t3 = { .id = 3, .tcb_address = 333333333 }; + + insert(&t1); + insert(&t2); + assert(lookup_id(1) == &t1); + assert(lookup_tcb(111111111) == &t1); + assert(lookup_id(2) == &t2); + assert(lookup_id(42) == NULL); + remove(&t1); + assert(lookup_id(1) == NULL); + insert(&t3); + remove(&t2); + assert(lookup_id(3) == &t3); + assert(lookup_tcb(333333333) == &t3); + assert(lookup_id(2) == NULL); + remove(&t3); + assert(list_empty(&threads)); +} 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 b9f59b8d85..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- @@ -6,25 +8,41 @@ ARM_OBJCOPY ?= $(ARM_CROSS_COMPILE)objcopy ARM_AFLAGS = -EL +RISCV_CROSS_COMPILE ?= riscv64-unknown-elf- +RISCV_CC ?= $(RISCV_CROSS_COMPILE)gcc +RISCV_OBJCOPY ?= $(RISCV_CROSS_COMPILE)objcopy +RISCV32_CFLAGS = -march=rv32e -mabi=ilp32e -nostdlib -nostartfiles -Os -fPIC +RISCV64_CFLAGS = -march=rv64i -mabi=lp64 -nostdlib -nostartfiles -Os -fPIC + +all: arm riscv + arm: armv4_5_crc.inc armv7m_crc.inc +riscv: riscv32_crc.inc riscv64_crc.inc + armv4_5_%.elf: armv4_5_%.s $(ARM_AS) $(ARM_AFLAGS) $< -o $@ armv4_5_%.bin: armv4_5_%.elf $(ARM_OBJCOPY) -Obinary $< $@ -armv4_5_%.inc: armv4_5_%.bin - $(BIN2C) < $< > $@ - armv7m_%.elf: armv7m_%.s $(ARM_AS) $(ARM_AFLAGS) $< -o $@ armv7m_%.bin: armv7m_%.elf $(ARM_OBJCOPY) -Obinary $< $@ -armv7m_%.inc: armv7m_%.bin +%.inc: %.bin $(BIN2C) < $< > $@ +riscv32_%.elf: riscv_%.c + $(RISCV_CC) $(RISCV32_CFLAGS) $< -o $@ + +riscv64_%.elf: riscv_%.c + $(RISCV_CC) $(RISCV64_CFLAGS) $< -o $@ + +riscv%.bin: riscv%.elf + $(RISCV_OBJCOPY) -Obinary $< $@ + clean: -rm -f *.elf *.bin *.inc 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/riscv32_crc.inc b/contrib/loaders/checksum/riscv32_crc.inc new file mode 100644 index 0000000000..d6566d2c2a --- /dev/null +++ b/contrib/loaders/checksum/riscv32_crc.inc @@ -0,0 +1,70 @@ +/* Autogenerated with ../../../src/helper/bin2char.sh */ +0xb3,0x05,0xb5,0x00,0x93,0x07,0xf0,0xff,0x17,0x07,0x00,0x00,0x13,0x07,0x47,0x04, +0x63,0x1a,0xb5,0x00,0x13,0x85,0x07,0x00,0x73,0x00,0x10,0x00,0x13,0x85,0x07,0x00, +0x67,0x80,0x00,0x00,0x03,0x46,0x05,0x00,0x93,0x96,0x87,0x00,0x93,0xd7,0x87,0x01, +0xb3,0xc7,0xc7,0x00,0x93,0x97,0x27,0x00,0xb3,0x07,0xf7,0x00,0x83,0xa7,0x07,0x00, +0x13,0x05,0x15,0x00,0xb3,0xc7,0xf6,0x00,0x6f,0xf0,0x9f,0xfc,0x00,0x00,0x00,0x00, +0xb7,0x1d,0xc1,0x04,0x6e,0x3b,0x82,0x09,0xd9,0x26,0x43,0x0d,0xdc,0x76,0x04,0x13, +0x6b,0x6b,0xc5,0x17,0xb2,0x4d,0x86,0x1a,0x05,0x50,0x47,0x1e,0xb8,0xed,0x08,0x26, +0x0f,0xf0,0xc9,0x22,0xd6,0xd6,0x8a,0x2f,0x61,0xcb,0x4b,0x2b,0x64,0x9b,0x0c,0x35, +0xd3,0x86,0xcd,0x31,0x0a,0xa0,0x8e,0x3c,0xbd,0xbd,0x4f,0x38,0x70,0xdb,0x11,0x4c, +0xc7,0xc6,0xd0,0x48,0x1e,0xe0,0x93,0x45,0xa9,0xfd,0x52,0x41,0xac,0xad,0x15,0x5f, +0x1b,0xb0,0xd4,0x5b,0xc2,0x96,0x97,0x56,0x75,0x8b,0x56,0x52,0xc8,0x36,0x19,0x6a, +0x7f,0x2b,0xd8,0x6e,0xa6,0x0d,0x9b,0x63,0x11,0x10,0x5a,0x67,0x14,0x40,0x1d,0x79, +0xa3,0x5d,0xdc,0x7d,0x7a,0x7b,0x9f,0x70,0xcd,0x66,0x5e,0x74,0xe0,0xb6,0x23,0x98, +0x57,0xab,0xe2,0x9c,0x8e,0x8d,0xa1,0x91,0x39,0x90,0x60,0x95,0x3c,0xc0,0x27,0x8b, +0x8b,0xdd,0xe6,0x8f,0x52,0xfb,0xa5,0x82,0xe5,0xe6,0x64,0x86,0x58,0x5b,0x2b,0xbe, +0xef,0x46,0xea,0xba,0x36,0x60,0xa9,0xb7,0x81,0x7d,0x68,0xb3,0x84,0x2d,0x2f,0xad, +0x33,0x30,0xee,0xa9,0xea,0x16,0xad,0xa4,0x5d,0x0b,0x6c,0xa0,0x90,0x6d,0x32,0xd4, +0x27,0x70,0xf3,0xd0,0xfe,0x56,0xb0,0xdd,0x49,0x4b,0x71,0xd9,0x4c,0x1b,0x36,0xc7, +0xfb,0x06,0xf7,0xc3,0x22,0x20,0xb4,0xce,0x95,0x3d,0x75,0xca,0x28,0x80,0x3a,0xf2, +0x9f,0x9d,0xfb,0xf6,0x46,0xbb,0xb8,0xfb,0xf1,0xa6,0x79,0xff,0xf4,0xf6,0x3e,0xe1, +0x43,0xeb,0xff,0xe5,0x9a,0xcd,0xbc,0xe8,0x2d,0xd0,0x7d,0xec,0x77,0x70,0x86,0x34, +0xc0,0x6d,0x47,0x30,0x19,0x4b,0x04,0x3d,0xae,0x56,0xc5,0x39,0xab,0x06,0x82,0x27, +0x1c,0x1b,0x43,0x23,0xc5,0x3d,0x00,0x2e,0x72,0x20,0xc1,0x2a,0xcf,0x9d,0x8e,0x12, +0x78,0x80,0x4f,0x16,0xa1,0xa6,0x0c,0x1b,0x16,0xbb,0xcd,0x1f,0x13,0xeb,0x8a,0x01, +0xa4,0xf6,0x4b,0x05,0x7d,0xd0,0x08,0x08,0xca,0xcd,0xc9,0x0c,0x07,0xab,0x97,0x78, +0xb0,0xb6,0x56,0x7c,0x69,0x90,0x15,0x71,0xde,0x8d,0xd4,0x75,0xdb,0xdd,0x93,0x6b, +0x6c,0xc0,0x52,0x6f,0xb5,0xe6,0x11,0x62,0x02,0xfb,0xd0,0x66,0xbf,0x46,0x9f,0x5e, +0x08,0x5b,0x5e,0x5a,0xd1,0x7d,0x1d,0x57,0x66,0x60,0xdc,0x53,0x63,0x30,0x9b,0x4d, +0xd4,0x2d,0x5a,0x49,0x0d,0x0b,0x19,0x44,0xba,0x16,0xd8,0x40,0x97,0xc6,0xa5,0xac, +0x20,0xdb,0x64,0xa8,0xf9,0xfd,0x27,0xa5,0x4e,0xe0,0xe6,0xa1,0x4b,0xb0,0xa1,0xbf, +0xfc,0xad,0x60,0xbb,0x25,0x8b,0x23,0xb6,0x92,0x96,0xe2,0xb2,0x2f,0x2b,0xad,0x8a, +0x98,0x36,0x6c,0x8e,0x41,0x10,0x2f,0x83,0xf6,0x0d,0xee,0x87,0xf3,0x5d,0xa9,0x99, +0x44,0x40,0x68,0x9d,0x9d,0x66,0x2b,0x90,0x2a,0x7b,0xea,0x94,0xe7,0x1d,0xb4,0xe0, +0x50,0x00,0x75,0xe4,0x89,0x26,0x36,0xe9,0x3e,0x3b,0xf7,0xed,0x3b,0x6b,0xb0,0xf3, +0x8c,0x76,0x71,0xf7,0x55,0x50,0x32,0xfa,0xe2,0x4d,0xf3,0xfe,0x5f,0xf0,0xbc,0xc6, +0xe8,0xed,0x7d,0xc2,0x31,0xcb,0x3e,0xcf,0x86,0xd6,0xff,0xcb,0x83,0x86,0xb8,0xd5, +0x34,0x9b,0x79,0xd1,0xed,0xbd,0x3a,0xdc,0x5a,0xa0,0xfb,0xd8,0xee,0xe0,0x0c,0x69, +0x59,0xfd,0xcd,0x6d,0x80,0xdb,0x8e,0x60,0x37,0xc6,0x4f,0x64,0x32,0x96,0x08,0x7a, +0x85,0x8b,0xc9,0x7e,0x5c,0xad,0x8a,0x73,0xeb,0xb0,0x4b,0x77,0x56,0x0d,0x04,0x4f, +0xe1,0x10,0xc5,0x4b,0x38,0x36,0x86,0x46,0x8f,0x2b,0x47,0x42,0x8a,0x7b,0x00,0x5c, +0x3d,0x66,0xc1,0x58,0xe4,0x40,0x82,0x55,0x53,0x5d,0x43,0x51,0x9e,0x3b,0x1d,0x25, +0x29,0x26,0xdc,0x21,0xf0,0x00,0x9f,0x2c,0x47,0x1d,0x5e,0x28,0x42,0x4d,0x19,0x36, +0xf5,0x50,0xd8,0x32,0x2c,0x76,0x9b,0x3f,0x9b,0x6b,0x5a,0x3b,0x26,0xd6,0x15,0x03, +0x91,0xcb,0xd4,0x07,0x48,0xed,0x97,0x0a,0xff,0xf0,0x56,0x0e,0xfa,0xa0,0x11,0x10, +0x4d,0xbd,0xd0,0x14,0x94,0x9b,0x93,0x19,0x23,0x86,0x52,0x1d,0x0e,0x56,0x2f,0xf1, +0xb9,0x4b,0xee,0xf5,0x60,0x6d,0xad,0xf8,0xd7,0x70,0x6c,0xfc,0xd2,0x20,0x2b,0xe2, +0x65,0x3d,0xea,0xe6,0xbc,0x1b,0xa9,0xeb,0x0b,0x06,0x68,0xef,0xb6,0xbb,0x27,0xd7, +0x01,0xa6,0xe6,0xd3,0xd8,0x80,0xa5,0xde,0x6f,0x9d,0x64,0xda,0x6a,0xcd,0x23,0xc4, +0xdd,0xd0,0xe2,0xc0,0x04,0xf6,0xa1,0xcd,0xb3,0xeb,0x60,0xc9,0x7e,0x8d,0x3e,0xbd, +0xc9,0x90,0xff,0xb9,0x10,0xb6,0xbc,0xb4,0xa7,0xab,0x7d,0xb0,0xa2,0xfb,0x3a,0xae, +0x15,0xe6,0xfb,0xaa,0xcc,0xc0,0xb8,0xa7,0x7b,0xdd,0x79,0xa3,0xc6,0x60,0x36,0x9b, +0x71,0x7d,0xf7,0x9f,0xa8,0x5b,0xb4,0x92,0x1f,0x46,0x75,0x96,0x1a,0x16,0x32,0x88, +0xad,0x0b,0xf3,0x8c,0x74,0x2d,0xb0,0x81,0xc3,0x30,0x71,0x85,0x99,0x90,0x8a,0x5d, +0x2e,0x8d,0x4b,0x59,0xf7,0xab,0x08,0x54,0x40,0xb6,0xc9,0x50,0x45,0xe6,0x8e,0x4e, +0xf2,0xfb,0x4f,0x4a,0x2b,0xdd,0x0c,0x47,0x9c,0xc0,0xcd,0x43,0x21,0x7d,0x82,0x7b, +0x96,0x60,0x43,0x7f,0x4f,0x46,0x00,0x72,0xf8,0x5b,0xc1,0x76,0xfd,0x0b,0x86,0x68, +0x4a,0x16,0x47,0x6c,0x93,0x30,0x04,0x61,0x24,0x2d,0xc5,0x65,0xe9,0x4b,0x9b,0x11, +0x5e,0x56,0x5a,0x15,0x87,0x70,0x19,0x18,0x30,0x6d,0xd8,0x1c,0x35,0x3d,0x9f,0x02, +0x82,0x20,0x5e,0x06,0x5b,0x06,0x1d,0x0b,0xec,0x1b,0xdc,0x0f,0x51,0xa6,0x93,0x37, +0xe6,0xbb,0x52,0x33,0x3f,0x9d,0x11,0x3e,0x88,0x80,0xd0,0x3a,0x8d,0xd0,0x97,0x24, +0x3a,0xcd,0x56,0x20,0xe3,0xeb,0x15,0x2d,0x54,0xf6,0xd4,0x29,0x79,0x26,0xa9,0xc5, +0xce,0x3b,0x68,0xc1,0x17,0x1d,0x2b,0xcc,0xa0,0x00,0xea,0xc8,0xa5,0x50,0xad,0xd6, +0x12,0x4d,0x6c,0xd2,0xcb,0x6b,0x2f,0xdf,0x7c,0x76,0xee,0xdb,0xc1,0xcb,0xa1,0xe3, +0x76,0xd6,0x60,0xe7,0xaf,0xf0,0x23,0xea,0x18,0xed,0xe2,0xee,0x1d,0xbd,0xa5,0xf0, +0xaa,0xa0,0x64,0xf4,0x73,0x86,0x27,0xf9,0xc4,0x9b,0xe6,0xfd,0x09,0xfd,0xb8,0x89, +0xbe,0xe0,0x79,0x8d,0x67,0xc6,0x3a,0x80,0xd0,0xdb,0xfb,0x84,0xd5,0x8b,0xbc,0x9a, +0x62,0x96,0x7d,0x9e,0xbb,0xb0,0x3e,0x93,0x0c,0xad,0xff,0x97,0xb1,0x10,0xb0,0xaf, +0x06,0x0d,0x71,0xab,0xdf,0x2b,0x32,0xa6,0x68,0x36,0xf3,0xa2,0x6d,0x66,0xb4,0xbc, +0xda,0x7b,0x75,0xb8,0x03,0x5d,0x36,0xb5,0xb4,0x40,0xf7,0xb1, diff --git a/contrib/loaders/checksum/riscv64_crc.inc b/contrib/loaders/checksum/riscv64_crc.inc new file mode 100644 index 0000000000..e131d77645 --- /dev/null +++ b/contrib/loaders/checksum/riscv64_crc.inc @@ -0,0 +1,71 @@ +/* Autogenerated with ../../../src/helper/bin2char.sh */ +0x93,0x07,0xf0,0xff,0x93,0x06,0xf0,0xff,0x17,0x06,0x00,0x00,0x13,0x06,0x06,0x05, +0x9b,0x85,0xf5,0xff,0x63,0x9a,0xd5,0x00,0x13,0x85,0x07,0x00,0x73,0x00,0x10,0x00, +0x13,0x85,0x07,0x00,0x67,0x80,0x00,0x00,0x83,0x48,0x05,0x00,0x1b,0xd7,0x87,0x01, +0x1b,0x98,0x87,0x00,0x33,0x47,0x17,0x01,0x13,0x17,0x27,0x00,0x33,0x07,0xe6,0x00, +0x83,0x27,0x07,0x00,0x13,0x05,0x15,0x00,0xb3,0xc7,0x07,0x01,0x9b,0x87,0x07,0x00, +0x6f,0xf0,0x1f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb7,0x1d,0xc1,0x04, +0x6e,0x3b,0x82,0x09,0xd9,0x26,0x43,0x0d,0xdc,0x76,0x04,0x13,0x6b,0x6b,0xc5,0x17, +0xb2,0x4d,0x86,0x1a,0x05,0x50,0x47,0x1e,0xb8,0xed,0x08,0x26,0x0f,0xf0,0xc9,0x22, +0xd6,0xd6,0x8a,0x2f,0x61,0xcb,0x4b,0x2b,0x64,0x9b,0x0c,0x35,0xd3,0x86,0xcd,0x31, +0x0a,0xa0,0x8e,0x3c,0xbd,0xbd,0x4f,0x38,0x70,0xdb,0x11,0x4c,0xc7,0xc6,0xd0,0x48, +0x1e,0xe0,0x93,0x45,0xa9,0xfd,0x52,0x41,0xac,0xad,0x15,0x5f,0x1b,0xb0,0xd4,0x5b, +0xc2,0x96,0x97,0x56,0x75,0x8b,0x56,0x52,0xc8,0x36,0x19,0x6a,0x7f,0x2b,0xd8,0x6e, +0xa6,0x0d,0x9b,0x63,0x11,0x10,0x5a,0x67,0x14,0x40,0x1d,0x79,0xa3,0x5d,0xdc,0x7d, +0x7a,0x7b,0x9f,0x70,0xcd,0x66,0x5e,0x74,0xe0,0xb6,0x23,0x98,0x57,0xab,0xe2,0x9c, +0x8e,0x8d,0xa1,0x91,0x39,0x90,0x60,0x95,0x3c,0xc0,0x27,0x8b,0x8b,0xdd,0xe6,0x8f, +0x52,0xfb,0xa5,0x82,0xe5,0xe6,0x64,0x86,0x58,0x5b,0x2b,0xbe,0xef,0x46,0xea,0xba, +0x36,0x60,0xa9,0xb7,0x81,0x7d,0x68,0xb3,0x84,0x2d,0x2f,0xad,0x33,0x30,0xee,0xa9, +0xea,0x16,0xad,0xa4,0x5d,0x0b,0x6c,0xa0,0x90,0x6d,0x32,0xd4,0x27,0x70,0xf3,0xd0, +0xfe,0x56,0xb0,0xdd,0x49,0x4b,0x71,0xd9,0x4c,0x1b,0x36,0xc7,0xfb,0x06,0xf7,0xc3, +0x22,0x20,0xb4,0xce,0x95,0x3d,0x75,0xca,0x28,0x80,0x3a,0xf2,0x9f,0x9d,0xfb,0xf6, +0x46,0xbb,0xb8,0xfb,0xf1,0xa6,0x79,0xff,0xf4,0xf6,0x3e,0xe1,0x43,0xeb,0xff,0xe5, +0x9a,0xcd,0xbc,0xe8,0x2d,0xd0,0x7d,0xec,0x77,0x70,0x86,0x34,0xc0,0x6d,0x47,0x30, +0x19,0x4b,0x04,0x3d,0xae,0x56,0xc5,0x39,0xab,0x06,0x82,0x27,0x1c,0x1b,0x43,0x23, +0xc5,0x3d,0x00,0x2e,0x72,0x20,0xc1,0x2a,0xcf,0x9d,0x8e,0x12,0x78,0x80,0x4f,0x16, +0xa1,0xa6,0x0c,0x1b,0x16,0xbb,0xcd,0x1f,0x13,0xeb,0x8a,0x01,0xa4,0xf6,0x4b,0x05, +0x7d,0xd0,0x08,0x08,0xca,0xcd,0xc9,0x0c,0x07,0xab,0x97,0x78,0xb0,0xb6,0x56,0x7c, +0x69,0x90,0x15,0x71,0xde,0x8d,0xd4,0x75,0xdb,0xdd,0x93,0x6b,0x6c,0xc0,0x52,0x6f, +0xb5,0xe6,0x11,0x62,0x02,0xfb,0xd0,0x66,0xbf,0x46,0x9f,0x5e,0x08,0x5b,0x5e,0x5a, +0xd1,0x7d,0x1d,0x57,0x66,0x60,0xdc,0x53,0x63,0x30,0x9b,0x4d,0xd4,0x2d,0x5a,0x49, +0x0d,0x0b,0x19,0x44,0xba,0x16,0xd8,0x40,0x97,0xc6,0xa5,0xac,0x20,0xdb,0x64,0xa8, +0xf9,0xfd,0x27,0xa5,0x4e,0xe0,0xe6,0xa1,0x4b,0xb0,0xa1,0xbf,0xfc,0xad,0x60,0xbb, +0x25,0x8b,0x23,0xb6,0x92,0x96,0xe2,0xb2,0x2f,0x2b,0xad,0x8a,0x98,0x36,0x6c,0x8e, +0x41,0x10,0x2f,0x83,0xf6,0x0d,0xee,0x87,0xf3,0x5d,0xa9,0x99,0x44,0x40,0x68,0x9d, +0x9d,0x66,0x2b,0x90,0x2a,0x7b,0xea,0x94,0xe7,0x1d,0xb4,0xe0,0x50,0x00,0x75,0xe4, +0x89,0x26,0x36,0xe9,0x3e,0x3b,0xf7,0xed,0x3b,0x6b,0xb0,0xf3,0x8c,0x76,0x71,0xf7, +0x55,0x50,0x32,0xfa,0xe2,0x4d,0xf3,0xfe,0x5f,0xf0,0xbc,0xc6,0xe8,0xed,0x7d,0xc2, +0x31,0xcb,0x3e,0xcf,0x86,0xd6,0xff,0xcb,0x83,0x86,0xb8,0xd5,0x34,0x9b,0x79,0xd1, +0xed,0xbd,0x3a,0xdc,0x5a,0xa0,0xfb,0xd8,0xee,0xe0,0x0c,0x69,0x59,0xfd,0xcd,0x6d, +0x80,0xdb,0x8e,0x60,0x37,0xc6,0x4f,0x64,0x32,0x96,0x08,0x7a,0x85,0x8b,0xc9,0x7e, +0x5c,0xad,0x8a,0x73,0xeb,0xb0,0x4b,0x77,0x56,0x0d,0x04,0x4f,0xe1,0x10,0xc5,0x4b, +0x38,0x36,0x86,0x46,0x8f,0x2b,0x47,0x42,0x8a,0x7b,0x00,0x5c,0x3d,0x66,0xc1,0x58, +0xe4,0x40,0x82,0x55,0x53,0x5d,0x43,0x51,0x9e,0x3b,0x1d,0x25,0x29,0x26,0xdc,0x21, +0xf0,0x00,0x9f,0x2c,0x47,0x1d,0x5e,0x28,0x42,0x4d,0x19,0x36,0xf5,0x50,0xd8,0x32, +0x2c,0x76,0x9b,0x3f,0x9b,0x6b,0x5a,0x3b,0x26,0xd6,0x15,0x03,0x91,0xcb,0xd4,0x07, +0x48,0xed,0x97,0x0a,0xff,0xf0,0x56,0x0e,0xfa,0xa0,0x11,0x10,0x4d,0xbd,0xd0,0x14, +0x94,0x9b,0x93,0x19,0x23,0x86,0x52,0x1d,0x0e,0x56,0x2f,0xf1,0xb9,0x4b,0xee,0xf5, +0x60,0x6d,0xad,0xf8,0xd7,0x70,0x6c,0xfc,0xd2,0x20,0x2b,0xe2,0x65,0x3d,0xea,0xe6, +0xbc,0x1b,0xa9,0xeb,0x0b,0x06,0x68,0xef,0xb6,0xbb,0x27,0xd7,0x01,0xa6,0xe6,0xd3, +0xd8,0x80,0xa5,0xde,0x6f,0x9d,0x64,0xda,0x6a,0xcd,0x23,0xc4,0xdd,0xd0,0xe2,0xc0, +0x04,0xf6,0xa1,0xcd,0xb3,0xeb,0x60,0xc9,0x7e,0x8d,0x3e,0xbd,0xc9,0x90,0xff,0xb9, +0x10,0xb6,0xbc,0xb4,0xa7,0xab,0x7d,0xb0,0xa2,0xfb,0x3a,0xae,0x15,0xe6,0xfb,0xaa, +0xcc,0xc0,0xb8,0xa7,0x7b,0xdd,0x79,0xa3,0xc6,0x60,0x36,0x9b,0x71,0x7d,0xf7,0x9f, +0xa8,0x5b,0xb4,0x92,0x1f,0x46,0x75,0x96,0x1a,0x16,0x32,0x88,0xad,0x0b,0xf3,0x8c, +0x74,0x2d,0xb0,0x81,0xc3,0x30,0x71,0x85,0x99,0x90,0x8a,0x5d,0x2e,0x8d,0x4b,0x59, +0xf7,0xab,0x08,0x54,0x40,0xb6,0xc9,0x50,0x45,0xe6,0x8e,0x4e,0xf2,0xfb,0x4f,0x4a, +0x2b,0xdd,0x0c,0x47,0x9c,0xc0,0xcd,0x43,0x21,0x7d,0x82,0x7b,0x96,0x60,0x43,0x7f, +0x4f,0x46,0x00,0x72,0xf8,0x5b,0xc1,0x76,0xfd,0x0b,0x86,0x68,0x4a,0x16,0x47,0x6c, +0x93,0x30,0x04,0x61,0x24,0x2d,0xc5,0x65,0xe9,0x4b,0x9b,0x11,0x5e,0x56,0x5a,0x15, +0x87,0x70,0x19,0x18,0x30,0x6d,0xd8,0x1c,0x35,0x3d,0x9f,0x02,0x82,0x20,0x5e,0x06, +0x5b,0x06,0x1d,0x0b,0xec,0x1b,0xdc,0x0f,0x51,0xa6,0x93,0x37,0xe6,0xbb,0x52,0x33, +0x3f,0x9d,0x11,0x3e,0x88,0x80,0xd0,0x3a,0x8d,0xd0,0x97,0x24,0x3a,0xcd,0x56,0x20, +0xe3,0xeb,0x15,0x2d,0x54,0xf6,0xd4,0x29,0x79,0x26,0xa9,0xc5,0xce,0x3b,0x68,0xc1, +0x17,0x1d,0x2b,0xcc,0xa0,0x00,0xea,0xc8,0xa5,0x50,0xad,0xd6,0x12,0x4d,0x6c,0xd2, +0xcb,0x6b,0x2f,0xdf,0x7c,0x76,0xee,0xdb,0xc1,0xcb,0xa1,0xe3,0x76,0xd6,0x60,0xe7, +0xaf,0xf0,0x23,0xea,0x18,0xed,0xe2,0xee,0x1d,0xbd,0xa5,0xf0,0xaa,0xa0,0x64,0xf4, +0x73,0x86,0x27,0xf9,0xc4,0x9b,0xe6,0xfd,0x09,0xfd,0xb8,0x89,0xbe,0xe0,0x79,0x8d, +0x67,0xc6,0x3a,0x80,0xd0,0xdb,0xfb,0x84,0xd5,0x8b,0xbc,0x9a,0x62,0x96,0x7d,0x9e, +0xbb,0xb0,0x3e,0x93,0x0c,0xad,0xff,0x97,0xb1,0x10,0xb0,0xaf,0x06,0x0d,0x71,0xab, +0xdf,0x2b,0x32,0xa6,0x68,0x36,0xf3,0xa2,0x6d,0x66,0xb4,0xbc,0xda,0x7b,0x75,0xb8, +0x03,0x5d,0x36,0xb5,0xb4,0x40,0xf7,0xb1, diff --git a/contrib/loaders/checksum/riscv_crc.c b/contrib/loaders/checksum/riscv_crc.c new file mode 100644 index 0000000000..9931af5ff6 --- /dev/null +++ b/contrib/loaders/checksum/riscv_crc.c @@ -0,0 +1,139 @@ +// 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. */ + +/* This table was generated by the following program. + #include + int + main () + { + unsigned int i, j; + unsigned int c; + int table[256]; + for (i = 0; i < 256; i++) + { + for (c = i << 24, j = 8; j > 0; --j) + c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); + table[i] = c; + } + printf ("static const unsigned int crc32_table[] =\n{\n"); + for (i = 0; i < 256; i += 4) + { + printf (" 0x%08x, 0x%08x, 0x%08x, 0x%08x", + table[i + 0], table[i + 1], table[i + 2], table[i + 3]); + if (i + 4 < 256) + putchar (','); + putchar ('\n'); + } + printf ("};\n"); + return 0; + } + For more information on CRC, see, e.g., + http://www.ross.net/crc/download/crc_v3.txt. */ + +static const unsigned int crc32_table[] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, + 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, + 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, + 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, + 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, + 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, + 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, + 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, + 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, + 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, + 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, + 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, + 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, + 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, + 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, + 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, + 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, + 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, + 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, + 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, + 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, + 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +/* +@deftypefn Extension {unsigned int} crc32 (const unsigned char *@var{buf}, @ + int @var{len}, unsigned int @var{init}) +Compute the 32-bit CRC of @var{buf} which has length @var{len}. The +starting value is 0xffffffff. +This is used by the @command{gdb} remote protocol for the @samp{qCRC} +command. +This CRC can be specified as: + Width : 32 + Poly : 0x04c11db7 + Init : 0xffffffff + RefIn : false + RefOut : false + XorOut : 0 +This differs from the "standard" CRC-32 algorithm in that the values +are not reflected, and there is no final XOR value. These differences +make it easy to compose the values of multiple blocks. +@end deftypefn +*/ + +#include + +unsigned int +xcrc32(const unsigned char *buf, int len) +{ + uint32_t crc = 0xffffffff; + while (len--) { + crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255]; + buf++; + } + asm("mv a0, %0;" + "ebreak;" + : + : "r"(crc)); + return crc; +} 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 4d2ab51d76..d63b819f62 100644 --- a/contrib/loaders/flash/fespi/Makefile +++ b/contrib/loaders/flash/fespi/Makefile @@ -1,28 +1,53 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= riscv64-unknown-elf- -CC=$(CROSS_COMPILE)gcc -OBJCOPY=$(CROSS_COMPILE)objcopy -OBJDUMP=$(CROSS_COMPILE)objdump +RISCV_CC=$(CROSS_COMPILE)gcc +RISCV_OBJCOPY=$(CROSS_COMPILE)objcopy +RISCV_OBJDUMP=$(CROSS_COMPILE)objdump -CFLAGS = -march=rv32i -mabi=ilp32 -x assembler-with-cpp -nostdlib -nostartfiles +CFLAGS = -nostdlib -nostartfiles -Wall -Werror -Os -fPIC -Wunused-result -g +RISCV32_CFLAGS = -march=rv32e -mabi=ilp32e $(CFLAGS) +RISCV64_CFLAGS = -march=rv64i -mabi=lp64 $(CFLAGS) -all: fespi.inc +all: riscv32_fespi.inc riscv64_fespi.inc .PHONY: clean -%.elf: %.S - $(CC) $(CFLAGS) $< -o $@ +# .c -> .o +riscv32_%.o: riscv_%.c + $(RISCV_CC) -c $(RISCV32_CFLAGS) $^ -o $@ -%.lst: %.elf - $(OBJDUMP) -S $< > $@ +riscv64_%.o: riscv_%.c + $(RISCV_CC) -c $(RISCV64_CFLAGS) $< -o $@ + +# .S -> .o +riscv32_%.o: riscv_%.S + $(RISCV_CC) -c $(RISCV32_CFLAGS) $^ -o $@ + +riscv64_%.o: riscv_%.S + $(RISCV_CC) -c $(RISCV64_CFLAGS) $^ -o $@ +# .o -> .elf +riscv32_%.elf: riscv32_%.o riscv32_wrapper.o + $(RISCV_CC) -T riscv.lds $(RISCV32_CFLAGS) $^ -o $@ + +riscv64_%.elf: riscv64_%.o riscv64_wrapper.o + $(RISCV_CC) -T riscv.lds $(RISCV64_CFLAGS) $^ -o $@ + +# .elf -> .bin %.bin: %.elf - $(OBJCOPY) -Obinary $< $@ + $(RISCV_OBJCOPY) -Obinary $< $@ +# .bin -> .inc %.inc: %.bin $(BIN2C) < $< > $@ +# utility +%.lst: %.elf + $(RISCV_OBJDUMP) -S $< > $@ + clean: - -rm -f *.elf *.lst *.bin *.inc + -rm -f *.elf *.o *.lst *.bin *.inc diff --git a/contrib/loaders/flash/fespi/fespi.S b/contrib/loaders/flash/fespi/fespi.S deleted file mode 100644 index d68e65ef81..0000000000 --- a/contrib/loaders/flash/fespi/fespi.S +++ /dev/null @@ -1,99 +0,0 @@ -#define SPIFLASH_READ_STATUS 0x05 // Read Status Register -#define SPIFLASH_BSY_BIT 0x00000001 // WIP Bit of SPI SR on SMI SR - -// Register offsets -#define FESPI_REG_FMT 0x40 -#define FESPI_REG_TXFIFO 0x48 -#define FESPI_REG_RXFIFO 0x4c -#define FESPI_REG_IP 0x74 - -// Fields -#define FESPI_IP_TXWM 0x1 -#define FESPI_FMT_DIR(x) (((x) & 0x1) << 3) - -// To enter, jump to the start of command_table (ie. offset 0). -// a0 - FESPI base address -// a1 - start address of buffer - -// The buffer contains a "program" in byte sequences. The first byte in a -// sequence determines the operation. Some operation will read more data from -// the program, while some will not. The operation byte is the offset into -// command_table, so eg. 4 means exit, 8 means transmit, and so on. - - .global _start -_start: -command_table: - j main // 0 - ebreak // 4 - j tx // 8 - j txwm_wait // 12 - j write_reg // 16 - j wip_wait // 20 - j set_dir // 24 - -// Execute the program. -main: - lbu t0, 0(a1) - addi a1, a1, 1 - la t1, command_table - add t0, t0, t1 - jr t0 - -// Read 1 byte the contains the number of bytes to transmit. Then read those -// bytes from the program and transmit them one by one. -tx: - lbu t1, 0(a1) // read number of bytes to transmit - addi a1, a1, 1 -1: lw t0, FESPI_REG_TXFIFO(a0) // wait for FIFO clear - bltz t0, 1b - lbu t0, 0(a1) // Load byte to write - sw t0, FESPI_REG_TXFIFO(a0) - addi a1, a1, 1 - addi t1, t1, -1 - bgtz t1, 1b - j main - -// Wait until TXWM is set. -txwm_wait: -1: lw t0, FESPI_REG_IP(a0) - andi t0, t0, FESPI_IP_TXWM - beqz t0, 1b - j main - -// Read 1 byte that contains the offset of the register to write, and 1 byte -// that contains the data to write. -write_reg: - lbu t0, 0(a1) // read register to write - add t0, t0, a0 - lbu t1, 1(a1) // read value to write - addi a1, a1, 2 - sw t1, 0(t0) - j main - -wip_wait: - li a2, SPIFLASH_READ_STATUS - jal txrx_byte - // discard first result -1: li a2, 0 - jal txrx_byte - andi t0, a2, SPIFLASH_BSY_BIT - bnez t0, 1b - j main - -txrx_byte: // transmit the byte in a2, receive a bit into a2 - lw t0, FESPI_REG_TXFIFO(a0) // wait for FIFO clear - bltz t0, txrx_byte - sw a2, FESPI_REG_TXFIFO(a0) -1: lw a2, FESPI_REG_RXFIFO(a0) - bltz a2, 1b - ret - -set_dir: - lw t0, FESPI_REG_FMT(a0) - li t1, ~(FESPI_FMT_DIR(0xFFFFFFFF)) - and t0, t0, t1 - lbu t1, 0(a1) // read value to OR in - addi a1, a1, 1 - or t0, t0, t1 - sw t0, FESPI_REG_FMT(a0) - j main diff --git a/contrib/loaders/flash/fespi/fespi.inc b/contrib/loaders/flash/fespi/fespi.inc deleted file mode 100644 index 768bdc5981..0000000000 --- a/contrib/loaders/flash/fespi/fespi.inc +++ /dev/null @@ -1,15 +0,0 @@ -/* Autogenerated with ../../../../src/helper/bin2char.sh */ -0x6f,0x00,0xc0,0x01,0x73,0x00,0x10,0x00,0x6f,0x00,0xc0,0x02,0x6f,0x00,0x00,0x05, -0x6f,0x00,0xc0,0x05,0x6f,0x00,0x00,0x07,0x6f,0x00,0x00,0x0a,0x83,0xc2,0x05,0x00, -0x93,0x85,0x15,0x00,0x17,0x03,0x00,0x00,0x13,0x03,0xc3,0xfd,0xb3,0x82,0x62,0x00, -0x67,0x80,0x02,0x00,0x03,0xc3,0x05,0x00,0x93,0x85,0x15,0x00,0x83,0x22,0x85,0x04, -0xe3,0xce,0x02,0xfe,0x83,0xc2,0x05,0x00,0x23,0x24,0x55,0x04,0x93,0x85,0x15,0x00, -0x13,0x03,0xf3,0xff,0xe3,0x44,0x60,0xfe,0x6f,0xf0,0x5f,0xfc,0x83,0x22,0x45,0x07, -0x93,0xf2,0x12,0x00,0xe3,0x8c,0x02,0xfe,0x6f,0xf0,0x5f,0xfb,0x83,0xc2,0x05,0x00, -0xb3,0x82,0xa2,0x00,0x03,0xc3,0x15,0x00,0x93,0x85,0x25,0x00,0x23,0xa0,0x62,0x00, -0x6f,0xf0,0xdf,0xf9,0x13,0x06,0x50,0x00,0xef,0x00,0x80,0x01,0x13,0x06,0x00,0x00, -0xef,0x00,0x00,0x01,0x93,0x72,0x16,0x00,0xe3,0x9a,0x02,0xfe,0x6f,0xf0,0x1f,0xf8, -0x83,0x22,0x85,0x04,0xe3,0xce,0x02,0xfe,0x23,0x24,0xc5,0x04,0x03,0x26,0xc5,0x04, -0xe3,0x4e,0x06,0xfe,0x67,0x80,0x00,0x00,0x83,0x22,0x05,0x04,0x13,0x03,0x70,0xff, -0xb3,0xf2,0x62,0x00,0x03,0xc3,0x05,0x00,0x93,0x85,0x15,0x00,0xb3,0xe2,0x62,0x00, -0x23,0x20,0x55,0x04,0x6f,0xf0,0x9f,0xf4, diff --git a/contrib/loaders/flash/fespi/riscv.lds b/contrib/loaders/flash/fespi/riscv.lds new file mode 100644 index 0000000000..7473128bf7 --- /dev/null +++ b/contrib/loaders/flash/fespi/riscv.lds @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +OUTPUT_ARCH( "riscv" ) + +SECTIONS +{ + . = 0x12340000; + .text : + { + *(.text.entry) + *(.text) + } + .data : { *(.data) } +} diff --git a/contrib/loaders/flash/fespi/riscv32_fespi.inc b/contrib/loaders/flash/fespi/riscv32_fespi.inc new file mode 100644 index 0000000000..44e04482fd --- /dev/null +++ b/contrib/loaders/flash/fespi/riscv32_fespi.inc @@ -0,0 +1,51 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x17,0x01,0x00,0x00,0x13,0x01,0xc1,0x31,0xef,0x00,0x80,0x10,0x73,0x00,0x10,0x00, +0x93,0x07,0x90,0x3e,0x93,0x87,0xf7,0xff,0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00, +0x67,0x80,0x00,0x00,0x03,0x27,0x45,0x07,0x13,0x77,0x17,0x00,0xe3,0x04,0x07,0xfe, +0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,0x93,0x07,0x90,0x3e,0x93,0x87,0xf7,0xff, +0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00,0x67,0x80,0x00,0x00,0x03,0x27,0x85,0x04, +0xe3,0x46,0x07,0xfe,0x23,0x24,0xb5,0x04,0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00, +0x83,0x27,0x05,0x04,0x13,0x01,0x41,0xff,0x23,0x22,0x81,0x00,0x23,0x24,0x11,0x00, +0x23,0x20,0x91,0x00,0x93,0xf7,0x77,0xff,0x23,0x20,0xf5,0x04,0x93,0x07,0x20,0x00, +0x23,0x2c,0xf5,0x00,0x93,0x05,0x50,0x00,0x13,0x04,0x05,0x00,0xef,0xf0,0xdf,0xfa, +0x93,0x07,0x90,0x3e,0x63,0x00,0x05,0x02,0x83,0x20,0x81,0x00,0x03,0x24,0x41,0x00, +0x83,0x24,0x01,0x00,0x13,0x01,0xc1,0x00,0x67,0x80,0x00,0x00,0x03,0x27,0xc4,0x04, +0x63,0x5a,0x07,0x00,0x93,0x87,0xf7,0xff,0xe3,0x9a,0x07,0xfe,0x13,0x05,0x10,0x00, +0x6f,0xf0,0x9f,0xfd,0x93,0x04,0x90,0x3e,0x93,0x84,0xf4,0xff,0xe3,0x88,0x04,0xfe, +0x93,0x05,0x00,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xf6,0xe3,0x1e,0x05,0xfa, +0x13,0x07,0x90,0x3e,0x13,0x07,0xf7,0xff,0xe3,0x0a,0x07,0xfc,0x83,0x27,0xc4,0x04, +0xe3,0xca,0x07,0xfe,0x93,0xf7,0x17,0x00,0xe3,0x98,0x07,0xfc,0x23,0x2c,0x04,0x00, +0x83,0x27,0x04,0x04,0x93,0xe7,0x87,0x00,0x23,0x20,0xf4,0x04,0x6f,0xf0,0xdf,0xf8, +0x13,0x01,0x41,0xfd,0x23,0x22,0x81,0x02,0x23,0x20,0x91,0x02,0x23,0x24,0x11,0x02, +0x13,0x04,0x05,0x00,0x23,0x26,0xb1,0x00,0x23,0x28,0xc1,0x00,0x23,0x20,0xd1,0x00, +0x23,0x22,0xe1,0x00,0x23,0x2a,0xf1,0x00,0xef,0xf0,0x9f,0xed,0x93,0x04,0x05,0x00, +0x63,0x16,0x05,0x04,0x83,0x27,0x04,0x06,0x13,0x05,0x04,0x00,0x93,0xf7,0xe7,0xff, +0x23,0x20,0xf4,0x06,0xef,0xf0,0xdf,0xf0,0x93,0x04,0x05,0x00,0x63,0x12,0x05,0x02, +0x83,0x27,0xc1,0x00,0x03,0x27,0x01,0x00,0x93,0x87,0xf7,0xff,0xb3,0xf7,0xe7,0x00, +0x03,0x47,0x41,0x01,0x23,0x2c,0xe1,0x00,0x03,0x27,0x41,0x00,0x63,0x14,0x07,0x02, +0x83,0x27,0x04,0x06,0x93,0xe7,0x17,0x00,0x23,0x20,0xf4,0x06,0x83,0x20,0x81,0x02, +0x03,0x24,0x41,0x02,0x13,0x85,0x04,0x00,0x83,0x24,0x01,0x02,0x13,0x01,0xc1,0x02, +0x67,0x80,0x00,0x00,0x83,0x26,0x41,0x00,0x03,0x27,0x41,0x00,0x23,0x24,0xd1,0x00, +0x83,0x26,0xc1,0x00,0x33,0x07,0xf7,0x00,0x63,0xf6,0xe6,0x00,0xb3,0x87,0xf6,0x40, +0x23,0x24,0xf1,0x00,0x93,0x05,0x60,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xe6, +0x63,0x1e,0x05,0x0c,0x13,0x05,0x04,0x00,0xef,0xf0,0x9f,0xe3,0x63,0x18,0x05,0x0c, +0x83,0x25,0x81,0x01,0x93,0x07,0x20,0x00,0x23,0x2c,0xf4,0x00,0x13,0x05,0x04,0x00, +0xef,0xf0,0x9f,0xe4,0x63,0x1c,0x05,0x0a,0x83,0x27,0x41,0x01,0x93,0xf7,0x07,0x10, +0x63,0x9c,0x07,0x08,0x83,0x27,0x01,0x00,0x13,0x05,0x04,0x00,0x93,0xd5,0x07,0x01, +0x93,0xf5,0xf5,0x0f,0xef,0xf0,0x5f,0xe2,0x63,0x1a,0x05,0x08,0x83,0x27,0x01,0x00, +0x13,0x05,0x04,0x00,0x93,0xd5,0x87,0x00,0x93,0xf5,0xf5,0x0f,0xef,0xf0,0xdf,0xe0, +0x63,0x1e,0x05,0x06,0x83,0x45,0x01,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xdf, +0x63,0x16,0x05,0x06,0x03,0x26,0x01,0x01,0x83,0x27,0x81,0x00,0xb3,0x07,0xf6,0x00, +0x63,0x12,0xf6,0x06,0x13,0x05,0x04,0x00,0x23,0x28,0xc1,0x00,0xef,0xf0,0x5f,0xdb, +0x63,0x16,0x05,0x04,0x23,0x2c,0x04,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xdf, +0x63,0x1e,0x05,0x02,0x83,0x27,0x01,0x00,0x03,0x27,0x81,0x00,0xb3,0x87,0xe7,0x00, +0x23,0x20,0xf1,0x00,0x83,0x27,0x41,0x00,0xb3,0x87,0xe7,0x40,0x23,0x22,0xf1,0x00, +0x93,0x07,0x00,0x00,0x6f,0xf0,0x5f,0xee,0x83,0x27,0x01,0x00,0x13,0x05,0x04,0x00, +0x93,0xd5,0x87,0x01,0xef,0xf0,0x5f,0xd9,0xe3,0x0e,0x05,0xf4,0x93,0x04,0x05,0x00, +0x6f,0xf0,0x1f,0xed,0x83,0x45,0x06,0x00,0x13,0x05,0x04,0x00,0x23,0x2e,0xf1,0x00, +0x23,0x28,0xc1,0x00,0xef,0xf0,0x5f,0xd7,0x03,0x26,0x01,0x01,0x83,0x27,0xc1,0x01, +0x13,0x06,0x16,0x00,0xe3,0x0e,0x05,0xf6,0x6f,0xf0,0x5f,0xfd,0x09,0x53,0x67,0x08, +0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08, +0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08, +0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08, +0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08, diff --git a/contrib/loaders/flash/fespi/riscv64_fespi.inc b/contrib/loaders/flash/fespi/riscv64_fespi.inc new file mode 100644 index 0000000000..97a860fe32 --- /dev/null +++ b/contrib/loaders/flash/fespi/riscv64_fespi.inc @@ -0,0 +1,58 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x17,0x01,0x00,0x00,0x13,0x01,0x81,0x38,0xef,0x00,0x40,0x12,0x73,0x00,0x10,0x00, +0x93,0x07,0x90,0x3e,0x9b,0x87,0xf7,0xff,0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00, +0x67,0x80,0x00,0x00,0x03,0x27,0x45,0x07,0x13,0x77,0x17,0x00,0xe3,0x04,0x07,0xfe, +0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,0x93,0x07,0x90,0x3e,0x9b,0x87,0xf7,0xff, +0x63,0x96,0x07,0x00,0x13,0x05,0x10,0x00,0x67,0x80,0x00,0x00,0x03,0x27,0x85,0x04, +0x93,0x16,0x07,0x02,0xe3,0xc4,0x06,0xfe,0x9b,0x85,0x05,0x00,0x23,0x24,0xb5,0x04, +0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,0x83,0x27,0x05,0x04,0x13,0x01,0x01,0xfe, +0x23,0x38,0x81,0x00,0x9b,0x87,0x07,0x00,0x23,0x3c,0x11,0x00,0x23,0x34,0x91,0x00, +0x93,0xf7,0x77,0xff,0x23,0x20,0xf5,0x04,0x93,0x07,0x20,0x00,0x23,0x2c,0xf5,0x00, +0x93,0x05,0x50,0x00,0x13,0x04,0x05,0x00,0xef,0xf0,0x1f,0xfa,0x93,0x07,0x90,0x3e, +0x63,0x02,0x05,0x02,0x83,0x30,0x81,0x01,0x03,0x34,0x01,0x01,0x83,0x34,0x81,0x00, +0x13,0x01,0x01,0x02,0x67,0x80,0x00,0x00,0x03,0x27,0xc4,0x04,0x93,0x16,0x07,0x02, +0x63,0xda,0x06,0x00,0x9b,0x87,0xf7,0xff,0xe3,0x98,0x07,0xfe,0x13,0x05,0x10,0x00, +0x6f,0xf0,0x5f,0xfd,0x93,0x04,0x90,0x3e,0x9b,0x84,0xf4,0xff,0xe3,0x88,0x04,0xfe, +0x93,0x05,0x00,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xf5,0xe3,0x1c,0x05,0xfa, +0x93,0x07,0x90,0x3e,0x9b,0x87,0xf7,0xff,0xe3,0x8a,0x07,0xfc,0x83,0x26,0xc4,0x04, +0x13,0x96,0x06,0x02,0x1b,0x87,0x06,0x00,0xe3,0x46,0x06,0xfe,0x93,0x77,0x17,0x00, +0xe3,0x94,0x07,0xfc,0x23,0x2c,0x04,0x00,0x83,0x27,0x04,0x04,0x9b,0x87,0x07,0x00, +0x93,0xe7,0x87,0x00,0x23,0x20,0xf4,0x04,0x6f,0xf0,0xdf,0xf7,0x13,0x01,0x01,0xfa, +0x23,0x38,0x81,0x04,0x23,0x34,0x91,0x04,0x23,0x30,0x21,0x05,0x23,0x3c,0x31,0x03, +0x23,0x38,0x41,0x03,0x23,0x34,0x51,0x03,0x23,0x30,0x61,0x03,0x23,0x3c,0x11,0x04, +0x23,0x3c,0x71,0x01,0x23,0x38,0x81,0x01,0x23,0x34,0x91,0x01,0x23,0x30,0xa1,0x01, +0x13,0x04,0x05,0x00,0x93,0x8a,0x05,0x00,0x13,0x0b,0x06,0x00,0x13,0x89,0x06,0x00, +0x13,0x0a,0x07,0x00,0x93,0x89,0x07,0x00,0xef,0xf0,0x9f,0xe9,0x93,0x04,0x05,0x00, +0x63,0x1a,0x05,0x04,0x83,0x27,0x04,0x06,0x13,0x05,0x04,0x00,0x9b,0x87,0x07,0x00, +0x93,0xf7,0xe7,0xff,0x23,0x20,0xf4,0x06,0xef,0xf0,0x1f,0xed,0x93,0x04,0x05,0x00, +0x63,0x12,0x05,0x02,0x9b,0x86,0xfa,0xff,0xb3,0x76,0xd9,0x00,0x93,0xfc,0xf9,0x0f, +0x93,0xf9,0x09,0x10,0x9b,0x86,0x06,0x00,0x13,0x0c,0x20,0x00,0x9b,0x89,0x09,0x00, +0x63,0x18,0x0a,0x04,0x83,0x27,0x04,0x06,0x9b,0x87,0x07,0x00,0x93,0xe7,0x17,0x00, +0x23,0x20,0xf4,0x06,0x83,0x30,0x81,0x05,0x03,0x34,0x01,0x05,0x03,0x39,0x01,0x04, +0x83,0x39,0x81,0x03,0x03,0x3a,0x01,0x03,0x83,0x3a,0x81,0x02,0x03,0x3b,0x01,0x02, +0x83,0x3b,0x81,0x01,0x03,0x3c,0x01,0x01,0x83,0x3c,0x81,0x00,0x03,0x3d,0x01,0x00, +0x13,0x85,0x04,0x00,0x83,0x34,0x81,0x04,0x13,0x01,0x01,0x06,0x67,0x80,0x00,0x00, +0xbb,0x07,0xda,0x00,0x93,0x0b,0x0a,0x00,0x63,0xf4,0xfa,0x00,0xbb,0x8b,0xda,0x40, +0x93,0x05,0x60,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xe1,0x63,0x1a,0x05,0x0a, +0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xdd,0x63,0x14,0x05,0x0a,0x23,0x2c,0x84,0x01, +0x93,0x85,0x0c,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xdf,0x63,0x1a,0x05,0x08, +0x63,0x90,0x09,0x08,0x9b,0x55,0x09,0x01,0x93,0xf5,0xf5,0x0f,0x13,0x05,0x04,0x00, +0xef,0xf0,0x9f,0xdd,0x63,0x1e,0x05,0x06,0x9b,0x55,0x89,0x00,0x93,0xf5,0xf5,0x0f, +0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xdc,0x63,0x14,0x05,0x06,0x93,0x75,0xf9,0x0f, +0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xdb,0x63,0x1c,0x05,0x04,0x13,0x0d,0x00,0x00, +0x9b,0x07,0x0d,0x00,0x63,0xea,0x77,0x05,0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xd7, +0x63,0x10,0x05,0x04,0x23,0x2c,0x04,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xdb, +0x63,0x18,0x05,0x02,0x93,0x97,0x0b,0x02,0x93,0xd7,0x07,0x02,0x33,0x0b,0xfb,0x00, +0x3b,0x09,0x79,0x01,0x3b,0x0a,0x7a,0x41,0x93,0x06,0x00,0x00,0x6f,0xf0,0x5f,0xef, +0x9b,0x55,0x89,0x01,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xd6,0xe3,0x0c,0x05,0xf6, +0x93,0x04,0x05,0x00,0x6f,0xf0,0x1f,0xee,0xb3,0x07,0xab,0x01,0x83,0xc5,0x07,0x00, +0x13,0x05,0x04,0x00,0x13,0x0d,0x1d,0x00,0xef,0xf0,0x1f,0xd4,0xe3,0x0a,0x05,0xf8, +0x6f,0xf0,0x1f,0xfe,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, +0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, +0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, +0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, +0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, +0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, +0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, +0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, +0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00, diff --git a/contrib/loaders/flash/fespi/riscv_fespi.c b/contrib/loaders/flash/fespi/riscv_fespi.c new file mode 100644 index 0000000000..17ae2fd22e --- /dev/null +++ b/contrib/loaders/flash/fespi/riscv_fespi.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include + +#include "../../../../src/flash/nor/spi.h" + +/* Register offsets */ + +#define FESPI_REG_SCKDIV 0x00 +#define FESPI_REG_SCKMODE 0x04 +#define FESPI_REG_CSID 0x10 +#define FESPI_REG_CSDEF 0x14 +#define FESPI_REG_CSMODE 0x18 + +#define FESPI_REG_DCSSCK 0x28 +#define FESPI_REG_DSCKCS 0x2a +#define FESPI_REG_DINTERCS 0x2c +#define FESPI_REG_DINTERXFR 0x2e + +#define FESPI_REG_FMT 0x40 +#define FESPI_REG_TXFIFO 0x48 +#define FESPI_REG_RXFIFO 0x4c +#define FESPI_REG_TXCTRL 0x50 +#define FESPI_REG_RXCTRL 0x54 + +#define FESPI_REG_FCTRL 0x60 +#define FESPI_REG_FFMT 0x64 + +#define FESPI_REG_IE 0x70 +#define FESPI_REG_IP 0x74 + +/* Fields */ + +#define FESPI_SCK_POL 0x1 +#define FESPI_SCK_PHA 0x2 + +#define FESPI_FMT_PROTO(x) ((x) & 0x3) +#define FESPI_FMT_ENDIAN(x) (((x) & 0x1) << 2) +#define FESPI_FMT_DIR(x) (((x) & 0x1) << 3) +#define FESPI_FMT_LEN(x) (((x) & 0xf) << 16) + +/* TXCTRL register */ +#define FESPI_TXWM(x) ((x) & 0xffff) +/* RXCTRL register */ +#define FESPI_RXWM(x) ((x) & 0xffff) + +#define FESPI_IP_TXWM 0x1 +#define FESPI_IP_RXWM 0x2 + +#define FESPI_FCTRL_EN 0x1 + +#define FESPI_INSN_CMD_EN 0x1 +#define FESPI_INSN_ADDR_LEN(x) (((x) & 0x7) << 1) +#define FESPI_INSN_PAD_CNT(x) (((x) & 0xf) << 4) +#define FESPI_INSN_CMD_PROTO(x) (((x) & 0x3) << 8) +#define FESPI_INSN_ADDR_PROTO(x) (((x) & 0x3) << 10) +#define FESPI_INSN_DATA_PROTO(x) (((x) & 0x3) << 12) +#define FESPI_INSN_CMD_CODE(x) (((x) & 0xff) << 16) +#define FESPI_INSN_PAD_CODE(x) (((x) & 0xff) << 24) + +/* Values */ + +#define FESPI_CSMODE_AUTO 0 +#define FESPI_CSMODE_HOLD 2 +#define FESPI_CSMODE_OFF 3 + +#define FESPI_DIR_RX 0 +#define FESPI_DIR_TX 1 + +#define FESPI_PROTO_S 0 +#define FESPI_PROTO_D 1 +#define FESPI_PROTO_Q 2 + +#define FESPI_ENDIAN_MSB 0 +#define FESPI_ENDIAN_LSB 1 + +/* Timeouts we use, in number of status checks. */ +#define TIMEOUT 1000 + +/* #define DEBUG to make the return error codes provide enough information to + * reconstruct the stack from where the error occurred. This is not enabled + * usually to reduce the program size. */ +#ifdef DEBUG +#define ERROR_STACK(x) (x) +#define ERROR_FESPI_TXWM_WAIT 0x10 +#define ERROR_FESPI_TX 0x100 +#define ERROR_FESPI_RX 0x1000 +#define ERROR_FESPI_WIP 0x50000 +#else +#define ERROR_STACK(x) 0 +#define ERROR_FESPI_TXWM_WAIT 1 +#define ERROR_FESPI_TX 1 +#define ERROR_FESPI_RX 1 +#define ERROR_FESPI_WIP 1 +#endif + +#define ERROR_OK 0 + +static int fespi_txwm_wait(volatile uint32_t *ctrl_base); +static void fespi_disable_hw_mode(volatile uint32_t *ctrl_base); +static void fespi_enable_hw_mode(volatile uint32_t *ctrl_base); +static int fespi_wip(volatile uint32_t *ctrl_base); +static int fespi_write_buffer(volatile uint32_t *ctrl_base, + const uint8_t *buffer, unsigned offset, unsigned len, + uint32_t flash_info); + +/* Can set bits 3:0 in result. */ +/* flash_info contains: + * bits 7:0 -- pprog_cmd + * bit 8 -- 0 means send 3 bytes after pprog_cmd, 1 means send 4 bytes + * after pprog_cmd + */ +int flash_fespi(volatile uint32_t *ctrl_base, uint32_t page_size, + const uint8_t *buffer, unsigned offset, uint32_t count, + uint32_t flash_info) +{ + int result; + + result = fespi_txwm_wait(ctrl_base); + if (result != ERROR_OK) + return result | ERROR_STACK(0x1); + + /* Disable Hardware accesses*/ + fespi_disable_hw_mode(ctrl_base); + + /* poll WIP */ + result = fespi_wip(ctrl_base); + if (result != ERROR_OK) { + result |= ERROR_STACK(0x2); + goto err; + } + + /* Assume page_size is a power of two so we don't need the modulus code. */ + uint32_t page_offset = offset & (page_size - 1); + + /* central part, aligned words */ + while (count > 0) { + uint32_t cur_count; + /* clip block at page boundary */ + if (page_offset + count > page_size) + cur_count = page_size - page_offset; + else + cur_count = count; + + result = fespi_write_buffer(ctrl_base, buffer, offset, cur_count, flash_info); + if (result != ERROR_OK) { + result |= ERROR_STACK(0x3); + goto err; + } + + page_offset = 0; + buffer += cur_count; + offset += cur_count; + count -= cur_count; + } + +err: + /* Switch to HW mode before return to prompt */ + fespi_enable_hw_mode(ctrl_base); + + return result; +} + +static uint32_t fespi_read_reg(volatile uint32_t *ctrl_base, unsigned address) +{ + return ctrl_base[address / 4]; +} + +static void fespi_write_reg(volatile uint32_t *ctrl_base, unsigned address, uint32_t value) +{ + ctrl_base[address / 4] = value; +} + +static void fespi_disable_hw_mode(volatile uint32_t *ctrl_base) +{ + uint32_t fctrl = fespi_read_reg(ctrl_base, FESPI_REG_FCTRL); + fespi_write_reg(ctrl_base, FESPI_REG_FCTRL, fctrl & ~FESPI_FCTRL_EN); +} + +static void fespi_enable_hw_mode(volatile uint32_t *ctrl_base) +{ + uint32_t fctrl = fespi_read_reg(ctrl_base, FESPI_REG_FCTRL); + fespi_write_reg(ctrl_base, FESPI_REG_FCTRL, fctrl | FESPI_FCTRL_EN); +} + +/* Can set bits 7:4 in result. */ +static int fespi_txwm_wait(volatile uint32_t *ctrl_base) +{ + unsigned timeout = TIMEOUT; + + while (timeout--) { + uint32_t ip = fespi_read_reg(ctrl_base, FESPI_REG_IP); + if (ip & FESPI_IP_TXWM) + return ERROR_OK; + } + + return ERROR_FESPI_TXWM_WAIT; +} + +static void fespi_set_dir(volatile uint32_t *ctrl_base, bool dir) +{ + uint32_t fmt = fespi_read_reg(ctrl_base, FESPI_REG_FMT); + fespi_write_reg(ctrl_base, FESPI_REG_FMT, + (fmt & ~(FESPI_FMT_DIR(0xFFFFFFFF))) | FESPI_FMT_DIR(dir)); +} + +/* Can set bits 11:8 in result. */ +static int fespi_tx(volatile uint32_t *ctrl_base, uint8_t in) +{ + unsigned timeout = TIMEOUT; + + while (timeout--) { + uint32_t txfifo = fespi_read_reg(ctrl_base, FESPI_REG_TXFIFO); + if (!(txfifo >> 31)) { + fespi_write_reg(ctrl_base, FESPI_REG_TXFIFO, in); + return ERROR_OK; + } + } + return ERROR_FESPI_TX; +} + +/* Can set bits 15:12 in result. */ +static int fespi_rx(volatile uint32_t *ctrl_base, uint8_t *out) +{ + unsigned timeout = TIMEOUT; + + while (timeout--) { + uint32_t value = fespi_read_reg(ctrl_base, FESPI_REG_RXFIFO); + if (!(value >> 31)) { + if (out) + *out = value & 0xff; + return ERROR_OK; + } + } + + return ERROR_FESPI_RX; +} + +/* Can set bits 19:16 in result. */ +static int fespi_wip(volatile uint32_t *ctrl_base) +{ + fespi_set_dir(ctrl_base, FESPI_DIR_RX); + + fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD); + + int result = fespi_tx(ctrl_base, SPIFLASH_READ_STATUS); + if (result != ERROR_OK) + return result | ERROR_STACK(0x10000); + result = fespi_rx(ctrl_base, NULL); + if (result != ERROR_OK) + return result | ERROR_STACK(0x20000); + + unsigned timeout = TIMEOUT; + while (timeout--) { + result = fespi_tx(ctrl_base, 0); + if (result != ERROR_OK) + return result | ERROR_STACK(0x30000); + uint8_t rx; + result = fespi_rx(ctrl_base, &rx); + if (result != ERROR_OK) + return result | ERROR_STACK(0x40000); + if ((rx & SPIFLASH_BSY_BIT) == 0) { + fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO); + fespi_set_dir(ctrl_base, FESPI_DIR_TX); + return ERROR_OK; + } + } + + return ERROR_FESPI_WIP; +} + +/* Can set bits 23:20 in result. */ +static int fespi_write_buffer(volatile uint32_t *ctrl_base, + const uint8_t *buffer, unsigned offset, unsigned len, + uint32_t flash_info) +{ + int result = fespi_tx(ctrl_base, SPIFLASH_WRITE_ENABLE); + if (result != ERROR_OK) + return result | ERROR_STACK(0x100000); + result = fespi_txwm_wait(ctrl_base); + if (result != ERROR_OK) + return result | ERROR_STACK(0x200000); + + fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD); + + result = fespi_tx(ctrl_base, flash_info & 0xff); + if (result != ERROR_OK) + return result | ERROR_STACK(0x300000); + + if (flash_info & 0x100) { + result = fespi_tx(ctrl_base, offset >> 24); + if (result != ERROR_OK) + return result | ERROR_STACK(0x400000); + } + result = fespi_tx(ctrl_base, offset >> 16); + if (result != ERROR_OK) + return result | ERROR_STACK(0x400000); + result = fespi_tx(ctrl_base, offset >> 8); + if (result != ERROR_OK) + return result | ERROR_STACK(0x500000); + result = fespi_tx(ctrl_base, offset); + if (result != ERROR_OK) + return result | ERROR_STACK(0x600000); + + for (unsigned i = 0; i < len; i++) { + result = fespi_tx(ctrl_base, buffer[i]); + if (result != ERROR_OK) + return result | ERROR_STACK(0x700000); + } + + result = fespi_txwm_wait(ctrl_base); + if (result != ERROR_OK) + return result | ERROR_STACK(0x800000); + + fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO); + + result = fespi_wip(ctrl_base); + if (result != ERROR_OK) + return result | ERROR_STACK(0x900000); + return ERROR_OK; +} diff --git a/contrib/loaders/flash/fespi/riscv_wrapper.S b/contrib/loaders/flash/fespi/riscv_wrapper.S new file mode 100644 index 0000000000..4bc4fe6dd9 --- /dev/null +++ b/contrib/loaders/flash/fespi/riscv_wrapper.S @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + + .section .text.entry + .global _start +_start: + lla sp, stack_end + jal flash_fespi + ebreak + + .section .data + .balign REGBYTES +stack: + .fill 16, REGBYTES, 0x8675309 +stack_end: 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/gd32vf103/Makefile b/contrib/loaders/flash/gd32vf103/Makefile new file mode 100644 index 0000000000..812fd8acaf --- /dev/null +++ b/contrib/loaders/flash/gd32vf103/Makefile @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +BIN2C = ../../../../src/helper/bin2char.sh + +CROSS_COMPILE ?= riscv-none-embed- + +CC=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump + +CFLAGS = -march=rv32i -mabi=ilp32 -static -nostartfiles -nostdlib -Os -g -fPIC + +all: gd32vf103.inc + +.PHONY: clean + +%.elf: %.c + $(CC) $(CFLAGS) $< -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/gd32vf103/gd32vf103.c b/contrib/loaders/flash/gd32vf103/gd32vf103.c new file mode 100644 index 0000000000..927014c740 --- /dev/null +++ b/contrib/loaders/flash/gd32vf103/gd32vf103.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#define FLASH_BSY (1 << 0) +#define FLASH_PGERR (1 << 2) +#define FLASH_WRPRTERR (1 << 4) + +void flash_write(volatile uint32_t *flash_sr, + uint32_t hwords_count, + uint16_t *buffer, + uint16_t *target_addr) __attribute__((naked)); + +void flash_write(volatile uint32_t *flash_sr, + uint32_t hwords_count, + uint16_t *buffer, + uint16_t *target_addr) +{ + do { + *target_addr = *buffer++; + + register uint32_t sr; + do { + sr = *flash_sr; + } while (sr & FLASH_BSY); + + if (sr & (FLASH_PGERR | FLASH_WRPRTERR)) + break; + + target_addr++; + } while (--hwords_count); + asm("ebreak"); +} diff --git a/contrib/loaders/flash/gd32vf103/gd32vf103.inc b/contrib/loaders/flash/gd32vf103/gd32vf103.inc new file mode 100644 index 0000000000..05eabff21a --- /dev/null +++ b/contrib/loaders/flash/gd32vf103/gd32vf103.inc @@ -0,0 +1,4 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x83,0x57,0x06,0x00,0x13,0x06,0x26,0x00,0x23,0x90,0xf6,0x00,0x83,0x27,0x05,0x00, +0x13,0xf7,0x17,0x00,0xe3,0x1c,0x07,0xfe,0x93,0xf7,0x47,0x01,0x63,0x98,0x07,0x00, +0x93,0x85,0xf5,0xff,0x93,0x86,0x26,0x00,0xe3,0x9c,0x05,0xfc,0x73,0x00,0x10,0x00, 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/Makefile b/contrib/loaders/flash/npcx/Makefile new file mode 100644 index 0000000000..293bd02dad --- /dev/null +++ b/contrib/loaders/flash/npcx/Makefile @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +BIN2C = ../../../../src/helper/bin2char.sh + +# Toolchain used in makefile +CROSS_COMPILE ?= arm-none-eabi- +CC = $(CROSS_COMPILE)gcc +CPLUS = $(CROSS_COMPILE)g++ +CPP = $(CROSS_COMPILE)cpp +LD = $(CROSS_COMPILE)gcc +AS = $(CROSS_COMPILE)as +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump +OBJSIZE = $(CROSS_COMPILE)size + +TARGET = npcx_algo +OBJS := npcx_flash.o +FLAGS = -mthumb -Os -ffunction-sections -fdata-sections -g -gdwarf-3 --specs=nano.specs +FLAGS += -gstrict-dwarf -Wall -fno-strict-aliasing --asm + +CFLAGS = -c -I. -mcpu=cortex-m4 -fpack-struct + +PRE_LD_FILE = npcx_flash.lds +LD_FILE = npcx_flash_generated.lds +LDFLAGS = -Wl,-Map,lfw.map -Wl,-T$(LD_FILE) -nostartfiles + +all: $(TARGET).inc + +# Implicit rules +%.o: %.c + -@ echo CC $@ from $< + @$(CC) $< $(FLAGS) $(CFLAGS) -o $@ + + $(LD_FILE): $(PRE_LD_FILE) + -@ echo Generate $@ from $< + -@$(CPP) $(PRE_LD_FILE) | grep -v '^#' >>$(LD_FILE) + +$(TARGET).elf: $(OBJS) $(LD_FILE) + -@ echo LD $@ from $< + @$(LD) -o $@ $< $(FLAGS) $(LDFLAGS) + +%.bin: %.elf + -@ echo OBJCOPY $@ from $< + -@ $(OBJCOPY) $< -O binary $@ + -@ $(OBJSIZE) $< --format=berkeley + +%.inc: %.bin + @echo 'Building target: $@' + @echo 'Invoking Bin2Char Script' + $(BIN2C) < $< > $@ + rm $< $*.elf + @echo 'Finished building target: $@' + @echo ' ' + +clean: + @echo 'Cleaning Targets and Build Artifacts' + rm -rf *.inc *.bin *.elf *.map + rm -rf *.o *.d + rm -rf $(LD_FILE) + @echo 'Finished clean' + @echo ' ' + +.PRECIOUS: %.bin + +.PHONY: all clean diff --git a/contrib/loaders/flash/npcx/npcx_algo.inc b/contrib/loaders/flash/npcx/npcx_algo.inc new file mode 100644 index 0000000000..46b79d8d9c --- /dev/null +++ b/contrib/loaders/flash/npcx/npcx_algo.inc @@ -0,0 +1,70 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +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, +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 new file mode 100644 index 0000000000..6df01b2d43 --- /dev/null +++ b/contrib/loaders/flash/npcx/npcx_flash.c @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2020 by Nuvoton Technology Corporation + * Mulin Chao + * Wealian Liao + */ + +#include +#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 */ + NPCX_UMA_CODE = code; + /* Execute UMA flash transaction by CTS setting */ + NPCX_UMA_CTS = cts; + /* Wait for transaction completed */ + while (NPCX_IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) + ; +} + +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, sw_cs); + else + NPCX_CLEAR_BIT(NPCX_UMA_ECTS, sw_cs); +} + +static void flash_set_address(uint32_t dest_addr) +{ + uint8_t *addr = (uint8_t *)&dest_addr; + + /* Set target flash address */ + NPCX_UMA_DB0 = addr[2]; + NPCX_UMA_DB1 = addr[1]; + NPCX_UMA_DB2 = addr[0]; +} + +static void delay(uint32_t i) +{ + while (i--) + __asm__ volatile ("nop"); +} + +static int flash_wait_ready(uint32_t timeout) +{ + /* Chip Select down. -- Burst mode */ + flash_cs_level(0); + + /* Command for Read status register */ + flash_execute_cmd(NPCX_CMD_READ_STATUS_REG, NPCX_MASK_CMD_ONLY); + while (timeout > 0) { + /* Read status register */ + NPCX_UMA_CTS = NPCX_MASK_RD_1BYTE; + while (NPCX_IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) + ; + + if (!(NPCX_UMA_DB0 & NPCX_SPI_FLASH_SR1_BUSY)) + break; + + if (--timeout > 0) + delay(100); + + }; /* Wait for Busy clear */ + + /* Chip Select high. */ + flash_cs_level(1); + + if (timeout == 0) + return NPCX_FLASH_STATUS_FAILED_TIMEOUT; + + return NPCX_FLASH_STATUS_OK; +} + +static int flash_write_enable(void) +{ + /* Write enable command */ + flash_execute_cmd(NPCX_CMD_WRITE_EN, NPCX_MASK_CMD_ONLY); + + /* Wait for flash is not busy */ + int status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); + if (status != NPCX_FLASH_STATUS_OK) + return status; + + if (NPCX_UMA_DB0 & NPCX_SPI_FLASH_SR1_WEL) + return NPCX_FLASH_STATUS_OK; + else + return NPCX_FLASH_STATUS_FAILED; +} + +static void flash_burst_write(uint32_t dest_addr, uint16_t bytes, + const uint8_t *data) +{ + /* Chip Select down -- Burst mode */ + flash_cs_level(0); + + /* Set write address */ + flash_set_address(dest_addr); + /* Start programming */ + 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++; + } + + /* Chip Select up */ + 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) +{ + int status = flash_write_enable(); + if (status != NPCX_FLASH_STATUS_OK) + return status; + + flash_burst_write(addr, size, data); + return flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); +} + +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; + + /* write head */ + 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) + return status; + data += write_len; + } + + dest_addr = trunk_start; + size -= write_len; + + /* write remaining data*/ + while (size > 0) { + write_len = (size > NPCX_FLASH_WRITE_SIZE) ? + NPCX_FLASH_WRITE_SIZE : size; + + status = flash_program_write(dest_addr, write_len, data); + if (status != NPCX_FLASH_STATUS_OK) + return status; + + data += write_len; + dest_addr += write_len; + size -= write_len; + } + + return NPCX_FLASH_STATUS_OK; +} + +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) { + /* Enable write */ + int status = flash_write_enable(); + if (status != NPCX_FLASH_STATUS_OK) + return status; + + /* Set erase address */ + flash_set_address(offset); + /* Start erase */ + 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) + return status; + } + + return NPCX_FLASH_STATUS_OK; +} + +static int flash_physical_erase_all(void) +{ + int status; + + /* Configure fiu and clear status register if needed */ + flash_init(); + status = flash_physical_clear_stsreg(); + if (status != NPCX_FLASH_STATUS_OK) + return status; + + /* Enable write */ + 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); + + /* Wait erase completed */ + status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); + if (status != NPCX_FLASH_STATUS_OK) + return status; + + return NPCX_FLASH_STATUS_OK; +} + +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; + + return NPCX_FLASH_STATUS_OK; +} + +/*---------------------------------------------------------------------------- + * flash loader function + *----------------------------------------------------------------------------*/ +static uint32_t flashloader_init(struct npcx_flash_params *params) +{ + /* Initialize params buffers */ + memset(params, 0, sizeof(struct npcx_flash_params)); + + return NPCX_FLASH_STATUS_OK; +} + +/*---------------------------------------------------------------------------- + * Functions + *----------------------------------------------------------------------------*/ +static int main(void) +{ + uint32_t id, status; + + /* set buffer */ + flashloader_init((struct npcx_flash_params *)&g_cfg); + + while (1) { + /* wait command*/ + while (g_cfg.sync == NPCX_FLASH_LOADER_WAIT) + ; + + /* command handler */ + switch (g_cfg.cmd) { + case NPCX_FLASH_CMD_GET_FLASH_ID: + status = flash_get_id(&id); + if (status == NPCX_FLASH_STATUS_OK) { + g_buf[0] = id & 0xff; + g_buf[1] = (id >> 8) & 0xff; + g_buf[2] = (id >> 16) & 0xff; + g_buf[3] = 0x00; + } + break; + case NPCX_FLASH_CMD_ERASE_SECTORS: + status = flash_physical_erase(g_cfg.addr, g_cfg.len); + break; + case NPCX_FLASH_CMD_ERASE_ALL: + status = flash_physical_erase_all(); + break; + case NPCX_FLASH_CMD_PROGRAM: + status = flash_physical_write(g_cfg.addr, + g_cfg.len, + g_buf); + break; + default: + status = NPCX_FLASH_STATUS_FAILED_UNKNOWN_COMMAND; + break; + } + + /* clear & set result for next command */ + if (status != NPCX_FLASH_STATUS_OK) { + g_cfg.sync = status; + while (1) + ; + } else { + g_cfg.sync = NPCX_FLASH_LOADER_WAIT; + } + } + + return 0; +} + +__attribute__ ((section(".stack"))) +__attribute__ ((used)) +static uint32_t stack[NPCX_FLASH_LOADER_STACK_SIZE / 4]; +extern uint32_t _estack; +extern uint32_t _bss; +extern uint32_t _ebss; + +__attribute__ ((section(".entry"))) +void entry(void) +{ + /* set sp from end of stack */ + __asm(" ldr sp, =_estack - 4"); + + main(); + + __asm(" bkpt #0x00"); +} diff --git a/contrib/loaders/flash/npcx/npcx_flash.h b/contrib/loaders/flash/npcx/npcx_flash.h new file mode 100644 index 0000000000..48e5d82fd3 --- /dev/null +++ b/contrib/loaders/flash/npcx/npcx_flash.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2020 by Nuvoton Technology Corporation + * Mulin Chao + * Wealian Liao + */ + +#ifndef OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_H +#define OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_H + +#include "npcx_flash_config.h" + +/* Bit functions */ +#define NPCX_SET_BIT(reg, bit) ((reg) |= (0x1 << (bit))) +#define NPCX_CLEAR_BIT(reg, bit) ((reg) &= (~(0x1 << (bit)))) +#define NPCX_IS_BIT_SET(reg, bit) (((reg) >> (bit)) & (0x1)) + +/* Field functions */ +#define NPCX_GET_POS_FIELD(pos, size) (pos) +#define NPCX_GET_SIZE_FIELD(pos, size) (size) +#define NPCX_FIELD_POS(field) NPCX_GET_POS_##field +#define NPCX_FIELD_SIZE(field) NPCX_GET_SIZE_##field +/* Read field functions */ +#define NPCX_GET_FIELD(reg, field) \ + _NPCX_GET_FIELD_((reg), NPCX_FIELD_POS(field), NPCX_FIELD_SIZE(field)) +#define _NPCX_GET_FIELD_(reg, f_pos, f_size) \ + (((reg) >> (f_pos)) & ((1 << (f_size)) - 1)) +/* Write field functions */ +#define NPCX_SET_FIELD(reg, field, value) \ + _NPCX_SET_FIELD_((reg), NPCX_FIELD_POS(field), NPCX_FIELD_SIZE(field), (value)) +#define _NPCX_SET_FIELD_(reg, f_pos, f_size, value) \ + ((reg) = ((reg) & (~(((1 << (f_size)) - 1) << (f_pos)))) | ((value) << (f_pos))) + +/* Register definitions */ +#define NPCX_REG32_ADDR(addr) ((volatile uint32_t *)(addr)) +#define NPCX_REG16_ADDR(addr) ((volatile uint16_t *)(addr)) +#define NPCX_REG8_ADDR(addr) ((volatile uint8_t *)(addr)) + +#define NPCX_HW_BYTE(addr) (*NPCX_REG8_ADDR(addr)) +#define NPCX_HW_WORD(addr) (*NPCX_REG16_ADDR(addr)) +#define NPCX_HW_DWORD(addr) (*NPCX_REG32_ADDR(addr)) + +/* Devalt */ +#define NPCX_SCFG_BASE_ADDR 0x400C3000 +#define NPCX_DEVCNT NPCX_HW_BYTE(NPCX_SCFG_BASE_ADDR + 0x000) +#define NPCX_DEVALT(n) NPCX_HW_BYTE(NPCX_SCFG_BASE_ADDR + 0x010 + (n)) + +#define NPCX_DEVCNT_HIF_TYP_SEL_FIELD FIELD(2, 2) +#define NPCX_DEVCNT_JEN0_HEN 4 +#define NPCX_DEVCNT_JEN1_HEN 5 +#define NPCX_DEVCNT_F_SPI_TRIS 6 + +/* Pin-mux for SPI/FIU */ +#define NPCX_DEVALT0_SPIP_SL 0 +#define NPCX_DEVALT0_GPIO_NO_SPIP 3 +#define NPCX_DEVALT0_F_SPI_CS1_2 4 +#define NPCX_DEVALT0_F_SPI_CS1_1 5 +#define NPCX_DEVALT0_F_SPI_QUAD 6 +#define NPCX_DEVALT0_NO_F_SPI 7 + +/* Flash Interface Unit (FIU) registers */ +#define NPCX_FIU_BASE_ADDR 0x40020000 +#define NPCX_FIU_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x000) +#define NPCX_BURST_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x001) +#define NPCX_RESP_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x002) +#define NPCX_SPI_FL_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x014) +#define NPCX_UMA_CODE NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x016) +#define NPCX_UMA_AB0 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x017) +#define NPCX_UMA_AB1 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x018) +#define NPCX_UMA_AB2 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x019) +#define NPCX_UMA_DB0 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01A) +#define NPCX_UMA_DB1 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01B) +#define NPCX_UMA_DB2 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01C) +#define NPCX_UMA_DB3 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01D) +#define NPCX_UMA_CTS NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01E) +#define NPCX_UMA_ECTS NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01F) +#define NPCX_UMA_DB0_3 NPCX_HW_DWORD(NPCX_FIU_BASE_ADDR + 0x020) +#define NPCX_FIU_RD_CMD NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x030) +#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 +#define NPCX_RESP_CFG_DEV_SIZE_EX 2 +#define NPCX_UMA_CTS_A_SIZE 3 +#define NPCX_UMA_CTS_C_SIZE 4 +#define NPCX_UMA_CTS_RD_WR 5 +#define NPCX_UMA_CTS_DEV_NUM 6 +#define NPCX_UMA_CTS_EXEC_DONE 7 +#define NPCX_UMA_ECTS_SW_CS0 0 +#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 +#define NPCX_CMD_READ_MAN_DEV_ID 0x90 +#define NPCX_CMD_WRITE_EN 0x06 +#define NPCX_CMD_WRITE_STATUS 0x50 +#define NPCX_CMD_READ_STATUS_REG 0x05 +#define NPCX_CMD_READ_STATUS_REG2 0x35 +#define NPCX_CMD_WRITE_STATUS_REG 0x01 +#define NPCX_CMD_FLASH_PROGRAM 0x02 +#define NPCX_CMD_SECTOR_ERASE 0x20 +#define NPCX_CMD_PROGRAM_UINT_SIZE 0x08 +#define NPCX_CMD_PAGE_SIZE 0x00 +#define NPCX_CMD_READ_ID_TYPE 0x47 +#define NPCX_CMD_FAST_READ 0x0B +#define NPCX_CMD_CHIP_ERASE 0xC7 + +/* + * Status registers for SPI flash + */ +#define NPCX_SPI_FLASH_SR2_SUS (1 << 7) +#define NPCX_SPI_FLASH_SR2_CMP (1 << 6) +#define NPCX_SPI_FLASH_SR2_LB3 (1 << 5) +#define NPCX_SPI_FLASH_SR2_LB2 (1 << 4) +#define NPCX_SPI_FLASH_SR2_LB1 (1 << 3) +#define NPCX_SPI_FLASH_SR2_QE (1 << 1) +#define NPCX_SPI_FLASH_SR2_SRP1 (1 << 0) +#define NPCX_SPI_FLASH_SR1_SRP0 (1 << 7) +#define NPCX_SPI_FLASH_SR1_SEC (1 << 6) +#define NPCX_SPI_FLASH_SR1_TB (1 << 5) +#define NPCX_SPI_FLASH_SR1_BP2 (1 << 4) +#define NPCX_SPI_FLASH_SR1_BP1 (1 << 3) +#define NPCX_SPI_FLASH_SR1_BP0 (1 << 2) +#define NPCX_SPI_FLASH_SR1_WEL (1 << 1) +#define NPCX_SPI_FLASH_SR1_BUSY (1 << 0) + +#define NPCX_MASK_CMD_ONLY (0xC0) +#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) +#define NPCX_MASK_RD_3BYTE (0xC0 | 0x10 | 0x03) +#define NPCX_MASK_RD_4BYTE (0xC0 | 0x10 | 0x04) +#define NPCX_MASK_CMD_RD_1BYTE (0xC0 | 0x01) +#define NPCX_MASK_CMD_RD_2BYTE (0xC0 | 0x02) +#define NPCX_MASK_CMD_RD_3BYTE (0xC0 | 0x03) +#define NPCX_MASK_CMD_RD_4BYTE (0xC0 | 0x04) +#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_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 */ + uint32_t sync; /* Handshake signal */ +}; + +/* Flash trigger signal */ +enum npcx_flash_handshake { + NPCX_FLASH_LOADER_WAIT = 0x0, /* Idle */ + NPCX_FLASH_LOADER_EXECUTE = 0xFFFFFFFF /* Execute Command */ +}; + +/* Flash loader command */ +enum npcx_flash_commands { + NPCX_FLASH_CMD_NO_ACTION = 0, /* No action, default value */ + NPCX_FLASH_CMD_GET_FLASH_ID, /* Get the internal flash ID */ + NPCX_FLASH_CMD_ERASE_SECTORS, /* Erase unprotected sectors */ + NPCX_FLASH_CMD_ERASE_ALL, /* Erase all */ + NPCX_FLASH_CMD_PROGRAM, /* Program data */ +}; + +/* Status */ +enum npcx_flash_status { + NPCX_FLASH_STATUS_OK = 0, + NPCX_FLASH_STATUS_FAILED_UNKNOWN_COMMAND, + NPCX_FLASH_STATUS_FAILED, + 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.lds b/contrib/loaders/flash/npcx/npcx_flash.lds new file mode 100644 index 0000000000..0d782523a4 --- /dev/null +++ b/contrib/loaders/flash/npcx/npcx_flash.lds @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "npcx_flash_config.h" + +/* Application memory map */ +MEMORY { + /* buffer + parameters */ + BUFFER (RWX) : ORIGIN = NPCX_FLASH_LOADER_PARAMS_ADDR, + LENGTH = NPCX_FLASH_LOADER_PARAMS_SIZE + NPCX_FLASH_LOADER_BUFFER_SIZE + + PROGRAM (RWX) : ORIGIN = NPCX_FLASH_LOADER_PROGRAM_ADDR, + LENGTH = NPCX_FLASH_LOADER_PROGRAM_SIZE +} + +/* Sections used for flashing */ +SECTIONS +{ + .buffers (NOLOAD) : + { + _buffers = .; + *(.buffers.g_cfg) + *(.buffers.g_buf) + *(.buffers*) + _ebuffers = .; + } > BUFFER + + .text : + { + _text = .; + *(.entry*) + *(.text*) + _etext = .; + } > PROGRAM + + .data : + { _data = .; + *(.rodata*) + *(.data*) + _edata = .; + } > PROGRAM + + .bss : + { + __bss_start__ = .; + _bss = .; + *(.bss*) + *(COMMON) + _ebss = .; + __bss_end__ = .; + } > PROGRAM + + .stack (NOLOAD) : + { + _stack = .; + *(.stack*) + _estack = .; + } > PROGRAM +} diff --git a/contrib/loaders/flash/npcx/npcx_flash_config.h b/contrib/loaders/flash/npcx/npcx_flash_config.h new file mode 100644 index 0000000000..4abd23e348 --- /dev/null +++ b/contrib/loaders/flash/npcx/npcx_flash_config.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2021 by Nuvoton Technology Corporation + * Mulin Chao + * Wealian Liao + */ + +#ifndef OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_CONFIG_H +#define OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_CONFIG_H + +#define NPCX_FLASH_ABORT_TIMEOUT 0xFFFFFF + +/* NPCX chip information */ +#define NPCX_FLASH_WRITE_SIZE 256L /* One page size for write */ +#define NPCX_FLASH_ERASE_SIZE 0x1000 + +/* 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 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) +#define NPCX_FLASH_LOADER_PROGRAM_SIZE 0x1000 + +/* Stack size in byte. 4 byte size alignment */ +#define NPCX_FLASH_LOADER_STACK_SIZE 400 + + +#endif /* OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_CONFIG_H */ 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 b58b412840..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- @@ -6,14 +8,19 @@ CC=$(CROSS_COMPILE)gcc OBJCOPY=$(CROSS_COMPILE)objcopy OBJDUMP=$(CROSS_COMPILE)objdump -CFLAGS = -static -nostartfiles -mlittle-endian -Wa,-EL + +AFLAGS = -static -nostartfiles -mlittle-endian -Wa,-EL +CFLAGS = -c -mthumb -nostdlib -nostartfiles -Os -g -fPIC all: stm32f1x.inc stm32f2x.inc stm32h7x.inc stm32l4x.inc stm32lx.inc .PHONY: clean %.elf: %.S - $(CC) $(CFLAGS) $< -o $@ + $(CC) $(AFLAGS) $< -o $@ + +stm32l4x.elf: stm32l4x.c + $(CC) $(CFLAGS) -mcpu=cortex-m0plus -fstack-usage -Wa,-adhln=$(<:.c=.lst) $< -o $@ %.lst: %.elf $(OBJDUMP) -S $< > $@ diff --git a/contrib/loaders/flash/stm32/stm32f1x.S b/contrib/loaders/flash/stm32/stm32f1x.S index 7b64c67aa3..fb214da31e 100644 --- a/contrib/loaders/flash/stm32/stm32f1x.S +++ b/contrib/loaders/flash/stm32/stm32f1x.S @@ -1,21 +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. * - * * - * 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/stm32f2x.S b/contrib/loaders/flash/stm32/stm32f2x.S index f6f5b30a49..95e5e384fb 100644 --- a/contrib/loaders/flash/stm32/stm32f2x.S +++ b/contrib/loaders/flash/stm32/stm32f2x.S @@ -1,24 +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. * - * * - * 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/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.S b/contrib/loaders/flash/stm32/stm32l4x.S deleted file mode 100644 index 9923ce7722..0000000000 --- a/contrib/loaders/flash/stm32/stm32l4x.S +++ /dev/null @@ -1,105 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Spencer Oliver * - * spen@spen-soft.co.uk * - * * - * Copyright (C) 2011 Øyvind Harboe * - * oyvind.harboe@zylin.com * - * * - * Copyright (C) 2015 Uwe Bonnes * - * bon@elektron.ikp.physik.tu-darmstadt.de * - * * - * Copyright (C) 2018 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, write to the * - * Free Software Foundation, Inc. * - ***************************************************************************/ - - .text - .syntax unified - .cpu cortex-m0 - .thumb - -/* - * Params : - * r0 = workarea start, status (out) - * r1 = workarea end + 1 - * r2 = target address - * r3 = count (64bit words) - * r4 = flash status register - * r5 = flash control register - * - * Clobbered: - * r6/7 - temp (64-bit) - */ - -#include "../../../../src/flash/nor/stm32l4x.h" - - .thumb_func - .global _start - -_start: - mov r8, r3 /* copy dword count */ -wait_fifo: - ldr r6, [r0, #0] /* read wp */ - cmp r6, #0 /* if wp == 0, */ - beq exit /* then abort */ - ldr r3, [r0, #4] /* read rp */ - subs r6, r6, r3 /* number of bytes available for read in r6 */ - bpl fifo_stat /* if not wrapped around, skip */ - adds r6, r6, r1 /* add end of buffer */ - subs r6, r6, r0 /* sub start of buffer */ -fifo_stat: - cmp r6, #8 /* wait until at least one dword available */ - bcc wait_fifo - - movs r6, #FLASH_PG /* flash program enable */ - str r6, [r5] /* write to FLASH_CR, start operation */ - ldmia r3!, {r6, r7} /* read one dword from src, increment ptr */ - stmia r2!, {r6, r7} /* write one dword to dst, increment ptr */ - dsb - ldr r7, =FLASH_BSY /* FLASH_BSY mask */ -busy: - ldr r6, [r4] /* get FLASH_SR register */ - tst r6, r7 /* BSY == 1 => operation in progress */ - bne busy /* if still set, wait more ... */ - movs r7, #FLASH_ERROR /* all error bits */ - tst r6, r7 /* check for any error bit */ - bne error /* fail ... */ - - cmp r3, r1 /* rp at end of buffer? */ - bcc upd_rp /* if no, then skip */ - subs r3, r3, r1 /* sub end of buffer */ - adds r3, r3, r0 /* add start of buffer */ - adds r3, r3, #8 /* skip wp and rp */ -upd_rp: - str r3, [r0, #4] /* store rp */ - mov r7, r8 /* get dword count */ - subs r7, r7, #1 /* decrement dword count */ - mov r8, r7 /* save dword count */ - beq exit /* exit if done */ - b wait_fifo - - .pool - -error: - movs r3, #0 - str r3, [r0, #4] /* set rp = 0 on error */ -exit: - mov r0, r6 /* return status in r0 */ - movs r6, #0 /* flash program disable */ - str r6, [r5] /* write to FLASH_CR */ - movs r6, #FLASH_ERROR /* all error bits */ - str r6, [r4] /* write to FLASH_CR to clear errors */ - bkpt #0x00 diff --git a/contrib/loaders/flash/stm32/stm32l4x.c b/contrib/loaders/flash/stm32/stm32l4x.c new file mode 100644 index 0000000000..b657ec9aea --- /dev/null +++ b/contrib/loaders/flash/stm32/stm32l4x.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/** + * Copyright (C) 2021 Tarek BOCHKATI + * tarek.bouchkati@st.com + */ + +#define OPENOCD_CONTRIB_LOADERS_FLASH_STM32_STM32L4X + +#include +#include "../../../../src/flash/nor/stm32l4x.h" + +static inline __attribute__((always_inline)) +void copy_buffer_u32(uint32_t *dst, uint32_t *src, int len) +{ + for (int i = 0; i < len; i++) + dst[i] = src[i]; +} + +/* this function is assumes that fifo_size is multiple of flash_word_size + * this condition is ensured by target_run_flash_async_algorithm + */ + +void write(volatile struct stm32l4_work_area *work_area, + uint8_t *fifo_end, + uint8_t *target_address, + uint32_t count) +{ + volatile uint32_t *flash_sr = (uint32_t *) work_area->params.flash_sr_addr; + volatile uint32_t *flash_cr = (uint32_t *) work_area->params.flash_cr_addr; + + /* optimization to avoid reading from memory each time */ + uint8_t *rp_cache = work_area->fifo.rp; + + /* fifo_start is used to wrap when we reach fifo_end */ + uint8_t *fifo_start = rp_cache; + + /* enable flash programming */ + *flash_cr = FLASH_PG; + + while (count) { + /* optimization to avoid reading from memory each time */ + uint8_t *wp_cache = work_area->fifo.wp; + if (wp_cache == 0) + break; /* aborted by target_run_flash_async_algorithm */ + + int32_t fifo_size = wp_cache - rp_cache; + if (fifo_size < 0) { + /* consider the linear fifo, we will wrap later */ + fifo_size = fifo_end - rp_cache; + } + + /* wait for at least a flash word */ + while (fifo_size >= work_area->params.flash_word_size) { + copy_buffer_u32((uint32_t *)target_address, + (uint32_t *)rp_cache, + work_area->params.flash_word_size / 4); + + /* update target_address and rp_cache */ + target_address += work_area->params.flash_word_size; + rp_cache += work_area->params.flash_word_size; + + /* wait for the busy flag */ + while (*flash_sr & work_area->params.flash_sr_bsy_mask) + ; + + if (*flash_sr & FLASH_ERROR) { + work_area->fifo.rp = 0; /* set rp to zero 0 on error */ + goto write_end; + } + + /* wrap if reach the fifo_end, and update rp in memory */ + if (rp_cache >= fifo_end) + rp_cache = fifo_start; + + /* flush the rp cache value, + * so target_run_flash_async_algorithm can fill the circular fifo */ + work_area->fifo.rp = rp_cache; + + /* update fifo_size and count */ + fifo_size -= work_area->params.flash_word_size; + count--; + } + } + +write_end: + /* disable flash programming */ + *flash_cr = 0; + + /* soft break the loader */ + __asm("bkpt 0"); +} + +/* by enabling this define 'DEBUG': + * the main() function can help help debugging the loader algo + * note: the application should be linked into RAM */ + +/* #define DEBUG */ + +#ifdef DEBUG +/* device selector: STM32L5 | STM32U5 | STM32WB | STM32WL | STM32WL_CPU2 | STM32G0Bx | ... */ +#define STM32U5 + +/* when using a secure device, and want to test the secure programming enable this define */ +/* #define SECURE */ + +#if defined(STM32U5) +# define FLASH_WORD_SIZE 16 +#else +# define FLASH_WORD_SIZE 8 +#endif + +#if defined(STM32WB) || defined(STM32WL) +# define FLASH_BASE 0x58004000 +#else +# define FLASH_BASE 0x40022000 +#endif + +#if defined(STM32G0Bx) +# define FLASH_BSY_MASK (FLASH_BSY | FLASH_BSY2) +#else +# define FLASH_BSY_MASK FLASH_BSY +#endif + +#if defined(STM32L5) || defined(STM32U5) +# ifdef SECURE +# define FLASH_KEYR_OFFSET 0x0c +# define FLASH_SR_OFFSET 0x24 +# define FLASH_CR_OFFSET 0x2c +# else +# define FLASH_KEYR_OFFSET 0x08 +# define FLASH_SR_OFFSET 0x20 +# define FLASH_CR_OFFSET 0x28 +# endif +#elif defined(STM32WL_CPU2) +# define FLASH_KEYR_OFFSET 0x08 +# define FLASH_SR_OFFSET 0x60 +# define FLASH_CR_OFFSET 0x64 +#else +# define FLASH_KEYR_OFFSET 0x08 +# define FLASH_SR_OFFSET 0x10 +# define FLASH_CR_OFFSET 0x14 +#endif + +#define FLASH_KEYR (uint32_t *)((FLASH_BASE) + (FLASH_KEYR_OFFSET)) +#define FLASH_SR (uint32_t *)((FLASH_BASE) + (FLASH_SR_OFFSET)) +#define FLASH_CR (uint32_t *)((FLASH_BASE) + (FLASH_CR_OFFSET)) + +int main() +{ + const uint32_t count = 2; + const uint32_t buf_size = count * FLASH_WORD_SIZE; + const uint32_t work_area_size = sizeof(struct stm32l4_work_area) + buf_size; + + uint8_t work_area_buf[work_area_size]; + struct stm32l4_work_area *workarea = (struct stm32l4_work_area *)work_area_buf; + + /* fill the workarea struct */ + workarea->params.flash_sr_addr = (uint32_t)(FLASH_SR); + workarea->params.flash_cr_addr = (uint32_t)(FLASH_CR); + workarea->params.flash_word_size = FLASH_WORD_SIZE; + workarea->params.flash_sr_bsy_mask = FLASH_BSY_MASK; + /* note: the workarea->stack is not used, in this configuration */ + + /* programming the existing memory raw content in workarea->fifo.buf */ + /* feel free to fill the memory with magical values ... */ + + workarea->fifo.wp = (uint8_t *)(&workarea->fifo.buf + buf_size); + workarea->fifo.rp = (uint8_t *)&workarea->fifo.buf; + + /* unlock the flash */ + *FLASH_KEYR = KEY1; + *FLASH_KEYR = KEY2; + + /* erase sector 0 */ + *FLASH_CR = FLASH_PER | FLASH_STRT; + while (*FLASH_SR & FLASH_BSY) + ; + + /* flash address, should be aligned to FLASH_WORD_SIZE */ + uint8_t *target_address = (uint8_t *) 0x8000000; + + write(workarea, + (uint8_t *)(workarea + work_area_size), + target_address, + count); + + while (1) + ; +} +#endif /* DEBUG */ diff --git a/contrib/loaders/flash/stm32/stm32l4x.inc b/contrib/loaders/flash/stm32/stm32l4x.inc index df5c7edd16..1ab400a0a5 100644 --- a/contrib/loaders/flash/stm32/stm32l4x.inc +++ b/contrib/loaders/flash/stm32/stm32l4x.inc @@ -1,7 +1,10 @@ /* Autogenerated with ../../../../src/helper/bin2char.sh */ -0x98,0x46,0x06,0x68,0x00,0x2e,0x23,0xd0,0x43,0x68,0xf6,0x1a,0x01,0xd5,0x76,0x18, -0x36,0x1a,0x08,0x2e,0xf5,0xd3,0x01,0x26,0x2e,0x60,0xc0,0xcb,0xc0,0xc2,0xbf,0xf3, -0x4f,0x8f,0x09,0x4f,0x26,0x68,0x3e,0x42,0xfc,0xd1,0xfa,0x27,0x3e,0x42,0x0d,0xd1, -0x8b,0x42,0x02,0xd3,0x5b,0x1a,0x1b,0x18,0x08,0x33,0x43,0x60,0x47,0x46,0x01,0x3f, -0xb8,0x46,0x05,0xd0,0xdd,0xe7,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x23,0x43,0x60, -0x30,0x46,0x00,0x26,0x2e,0x60,0xfa,0x26,0x26,0x60,0x00,0xbe, +0xf0,0xb5,0x87,0xb0,0x07,0x68,0x01,0x93,0x43,0x68,0x04,0x91,0x02,0x93,0x83,0x6f, +0x02,0x99,0x03,0x93,0x01,0x23,0x0b,0x60,0x03,0x9b,0x01,0x99,0x00,0x29,0x1f,0xd0, +0x41,0x6f,0x00,0x29,0x1c,0xd0,0xc9,0x1a,0x01,0xd5,0x04,0x99,0xc9,0x1a,0x84,0x68, +0x8c,0x42,0xf2,0xd8,0x85,0x68,0xac,0x08,0x05,0x94,0x00,0x24,0x05,0x9d,0xa5,0x42, +0x14,0xdc,0x84,0x68,0x12,0x19,0x84,0x68,0x1b,0x19,0x3c,0x68,0xc5,0x68,0x2e,0x00, +0x26,0x40,0x25,0x42,0xf9,0xd1,0xfa,0x25,0x3c,0x68,0x2c,0x42,0x0b,0xd0,0x86,0x67, +0x00,0x23,0x02,0x9a,0x13,0x60,0x00,0xbe,0x07,0xb0,0xf0,0xbd,0xa6,0x00,0x9d,0x59, +0x01,0x34,0x95,0x51,0xe2,0xe7,0x04,0x9c,0x9c,0x42,0x00,0xd8,0x03,0x9b,0x83,0x67, +0x84,0x68,0x09,0x1b,0x01,0x9c,0x01,0x3c,0x01,0x94,0xd0,0xe7, diff --git a/contrib/loaders/flash/stm32/stm32lx.S b/contrib/loaders/flash/stm32/stm32lx.S index bcae7a46cc..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,54 +12,61 @@ * * * 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. * - * * - * 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 .syntax unified .cpu cortex-m0 .thumb /* +Parameters r0 - destination address r1 - source address - r2 - count + r2 - half pages + r3 - bytes per half page + r4 - flash base +Variables + r0 - destination write pointer + r1 - source read pointer + r2 - source limit address + r3 - bytes per half page + r4 - flash base + r5 - pages left in current half page + r6 - temporary r/w */ +/* offsets of registers from flash reg base */ +#define STM32_FLASH_SR_OFFSET 0x18 + .thumb_func .global _start _start: - // r2 = source + count * 4 - lsls r2, r2, #2 - adds r2, r1, r2 + // r2 = source + half pages * bytes per half page + muls r2, r2, r3 + add r2, r1, r2 // Go to compare - b test_done + b test_done +write_half_page: + // initialize pages left in current half page + mov r5, r3 write_word: // load word from address in r1 and increase r1 by 4 - ldmia r1!, {r3} + ldmia r1!, {r6} // store word to address in r0 and increase r0 by 4 - stmia r0!, {r3} + stmia r0!, {r6} + // check for end of half page + subs r5, r5, #4 + bne write_word +wait_busy: + // read status register into r6, loop while bottom bit is set + ldr r6, [r4, #STM32_FLASH_SR_OFFSET] + lsls r6, r6, #31 + bne wait_busy test_done: - // compare r1 and r2 + // compare r1 and r2, loop if not equal cmp r1, r2 - // loop if not equal - bne write_word + bne write_half_page // Set breakpoint to exit - bkpt #0x00 - + bkpt #0x00 diff --git a/contrib/loaders/flash/stm32/stm32lx.inc b/contrib/loaders/flash/stm32/stm32lx.inc index eaaf1848aa..668de27787 100644 --- a/contrib/loaders/flash/stm32/stm32lx.inc +++ b/contrib/loaders/flash/stm32/stm32lx.inc @@ -1,2 +1,3 @@ /* Autogenerated with ../../../../src/helper/bin2char.sh */ -0x92,0x00,0x8a,0x18,0x01,0xe0,0x08,0xc9,0x08,0xc0,0x91,0x42,0xfb,0xd1,0x00,0xbe, +0x5a,0x43,0x0a,0x44,0x07,0xe0,0x1d,0x46,0x40,0xc9,0x40,0xc0,0x04,0x3d,0xfb,0xd1, +0xa6,0x69,0xf6,0x07,0xfc,0xd1,0x91,0x42,0xf5,0xd1,0x00,0xbe, diff --git a/contrib/loaders/flash/stmqspi/Makefile b/contrib/loaders/flash/stmqspi/Makefile new file mode 100644 index 0000000000..b07d452a82 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/Makefile @@ -0,0 +1,36 @@ +# 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 \ + stmoctospi_erase_check.S stmoctospi_crc32.S stmoctospi_read.S stmoctospi_write.S +OBJS=$(patsubst %.S,%.inc,$(SRCS)) + +CROSS_COMPILE ?= arm-none-eabi- + +CC=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump +LD=$(CROSS_COMPILE)ld + +all: $(OBJS) + +%.o: %.S Makefile + $(CC) -Wall -Werror -Wa,-adhlmn -o $@ -c $< > $(@:.o=.lst) + @enscript -Easm -T 4 -G -o - $(@:.o=.lst) | ps2pdf - $(@:.o=.pdf) || true + +%.elf: %.o + $(LD) -s -defsym=_start=0 -o $@ $< + +%.bin: %.elf + $(OBJCOPY) -S -O binary $< $@ + +%.inc: %.bin + $(BIN2C) < $< > $@ + +clean: + -rm -f *.o *.elf *.lst *.pdf *.bin *.inc + +.PHONY: all clean + +.INTERMEDIATE: $(patsubst %.S,%.o,$(SRCS)) $(patsubst %.S,%.elf,$(SRCS)) $(patsubst %.S,%.bin,$(SRCS)) diff --git a/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl b/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl new file mode 100755 index 0000000000..49b15c2022 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl @@ -0,0 +1,681 @@ +#!/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). +# +# Each pin is configured by "PortAndBit:Conf:Speed" +# 'PortAndBit' specifies Port and bit number +# 'Conf' is one of 'AFx' (alternate), 'P' (output), 'IN' (input), +# (each optionally by 'P' (push-pull) or 'O' (open-drain)), +# (all optionally followed by 'UP' (pull-up), or 'DO' (pull-down)) +# 'Speed' is one of 'L' (low), 'M' (medium), 'H' (high), 'V' (very high) +# +# Port configuration can be given on command line as a single string (pins separated by commas) +# or via CubeMX generated file. The latter must consist of the quadspi.c / octospi.c and the +# corresponding header. The precise spelling in these files doesn't seem to be consistent, though ... +# +# Pins have to be ordered this way: +# - I2C: SDA, SCL +# - SPI (1 line): NCS, CLK, IO1/MISO, IO0/MOSI +# - DPI (2 lines): NCS, CLK, IO1/MISO, IO0/MOSI +# - QPI (4 lines): NCS, CLK, IO3/NHOLD, IO2/NWP, IO1/MISO, IO0/MOSI +# For dual flash: BK_1 first, then BK_2. If single NCS for both, omit NCS in BK_2 +# For octal flash: NCS, CLK, DQS, IO7 down to IO0 + +use strict; +use Getopt::Std; + +my $GPIO_BASE; +my $Conf; +my $STM32F1 = 0; + +# "Blue-Pill stm32f103cbt6 board w/ cmspi +#$STM32F1 = 1; +#$GPIO_BASE = 0x40010800; +#$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB15:INUP:V"; +#$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB01:INUP:V"; + +#$STM32F1 = 1; +#$GPIO_BASE = 0x40010800; +#$Conf = "PB07:INUP:V, PB06:INUP:V"; + +# mini-stm32f030f4p6 board w/ cmspi +#$GPIO_BASE = 0x48000000; +#$Conf = "PB01:PP:V, PA05:PP:V, PA06:INUP:V, PA07:INUP:V"; + +# stm32f407vet6 board w/ cmspi +#$GPIO_BASE = 0x40020000; +#$Conf = "PB00:PP:M, PB03:PP:V, PB04:INUP:V, PB05:INUP:V"; + +# stm32f412g-disco quad +#$GPIO_BASE = 0x40020000; +#$Conf = "PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V"; + +# stm32f413h-disco +#$GPIO_BASE = 0x40020000; +#$Conf = "PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V"; + +# stm32f469i-disco quad +#$GPIO_BASE = 0x40020000; +#$Conf = "PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V"; +# w/ cmspi +#$Conf = "PB06:PP:M, PF10:PP:V, PF06:INUP:V, PF07:INUP:V, PF09:INUP:V, PF08:INUP:V"; + +# stm32f723e-disco quad +#$GPIO_BASE = 0x40020000; +#$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V"; + +# stm32f746g-disco quad +#$GPIO_BASE = 0x40020000; +#Conf = "PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V"; +# w/ cmspi +#$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PD12:INUP:V, PD11:INUP:V"; + +# stm32f769i-disco quad +#$GPIO_BASE = 0x40020000; +#$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V"; +# w/ cmspi +#$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PC10:INUP:V, PC09:INUP:V, "; + +# b-l475e-iot01a quad +#$GPIO_BASE = 0x48000000; +#$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V"; + +# stm32l476g-disco quad +#$GPIO_BASE = 0x48000000; +#$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V"; + +# stm32l496g-disco quad +#$GPIO_BASE = 0x48000000; +#$Conf = "PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V"; + +# stm32l4r9i-disco octal +#$GPIO_BASE = 0x48000000; +#$Conf = "PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V, " +# . "PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V"; + +# stm32l4p5g-disco octal/octal +#$GPIO_BASE = 0x48000000; +#$Conf = "PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V, " +# . "PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V"; +#$Conf = "PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V, " +# . "PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V"; + +# nucleo-f767zi dual quad +#$GPIO_BASE = 0x40020000; +#$Conf = "PB06:AF10:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, " +# . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V"; +# w/ cmspi +#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V"; +#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V"; + +# nucleo-h743zi dual quad +#$GPIO_BASE = 0x58020000; +#$Conf = "PB10:AF09:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, " +# . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V"; +# w/ cmspi +#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V"; +#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V"; + +# nucleo-h7a3zi dual quad +#$GPIO_BASE = 0x58020000; +#$Conf = "PB10:AF09:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V, " +# . "PC11:AF09:V, PE10:AF10:V, PD06:AF10:V, PE08:AF10:V, PE07:AF10:V"; +# w/ cmspi +#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V"; +#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PD06:INPUP:V, PE08:INPUP:V, PE07:INPUP:V"; + +# nucleo-l4r5zi one dual quad single NCS +#$GPIO_BASE = 0x48000000; +#$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, " +# . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V"; +# w/ cmspi +#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V"; +#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V"; + +# nucleo-l552ze-q dual quad with single NCS +#$GPIO_BASE = 0x42020000; +#$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, " +# . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V"; +# w/ cmspi +#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V"; +#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V"; + +# nucleo-g071rb dual quad +#$GPIO_BASE = 0x50000000; +#$Conf = "PA00:PPUP:H, PA04:PPUP:V, PB03:INPUP:V, PA10:INPUP:V, PB11:INPUP:H, PB01:INPUP:H"; +#$Conf = "PA01:PPUP:H, PA04:PPUP:V, PA08:INPUP:V, PB14:INPUP:V, PB04:INPUP:V, PB05:INPUP:V"; + +# nucleo-g474re dual quad with single NCS +#$GPIO_BASE = 0x48000000; +#$Conf = "PB11:AF10:H, PB10:AF10:V, PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V, " +# . "PC04:AF10:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V"; +# w/ cmspi +#$Conf = "PB11:PPUP:H, PB10:PPUP:V, PA06:INPUP:V, PA07:INPUP:V, PB00:INPUP:V, PB01:INPUP:V"; +#$Conf = "PB11:PPUP:H, PB10:PPUP:V, PC04:INPUP:V, PC03:INPUP:V, PC02:INPUP:V, PC01:INPUP:V"; + +# stm32h745i-disco dual quad with single NCS +#$GPIO_BASE = 0x58020000; +#$Conf = "PG06:AF10:H, PF10:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, " +# . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V"; + +# stm32h747i-disco dual quad with single NCS +#GPIO_BASE = 0x58020000; +#$Conf = "PG06:AF10:H, PB02:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, " +# . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V"; + +# stm32h7b3i-disco octal +#$GPIO_BASE = 0x58020000; +#$Conf = "PG06:AF10:V, PB02:AF09:V, PC05:AF10:V, PD07:AF10:V, PG09:AF09:V, PH03:AF09:V, PC01:AF10:V, " +# . "PF06:AF10:V, PF07:AF10:V, PF09:AF10:V, PD11:AF09:V"; + +# stm32h735g-disco octal +#$GPIO_BASE = 0x58020000; +#$Conf = "PG06:AF10:V, PF10:AF09:V, PB02:AF10:V, PD07:AF10:V, PG09:AF09:V, PD05:AF10:V, PD04:AF10:V, " +# . "PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V"; + +# stm32l562e-disco octal +#$GPIO_BASE = 0x42020000; +#$Conf = "PA02:AF10:V, PA03:AF10:V, PB02:AF10:V, PC00:AF03:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V, " +# . "PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V"; + +&getopts('b:c:f:t'); +if ($Getopt::Std::opt_b eq '') +{ + if ($GPIO_BASE eq '') + { + die("usage: $0 [ -1 ] -b io_base [ -c port_configuration ] [ -f conf_file ]"); + } +} +else +{ + $GPIO_BASE = eval $Getopt::Std::opt_b; +} + +if ($Getopt::Std::opt_c eq '') +{ + if (($Conf eq '') && ($Getopt::Std::opt_f eq '')) + { + die("usage: $0 [ -b io_base ] ( -c port_configuration | -f conf_file )"); + } +}# +else +{ + $Conf = $Getopt::Std::opt_c . ','; +} + +$STM32F1 = $Getopt::Std::opt_t; + +my $Sep = "\t"; +my $Form = "${Sep}mmw 0x%08X 0x%08X 0x%08X\t;# "; + +my $GPIO_OFFS; +my $GPIO_CRL; +my $GPIO_CRH; +my $GPIO_MODER; +my $GPIO_OTYPER; +my $GPIO_OSPEEDR; +my $GPIO_PUPDR; +my $GPIO_IDR; +my $GPIO_ODR; +my $GPIO_AFRL; +my $GPIO_AFRH; + +if ($STM32F1) +{ + # offsets for F1 devices + $GPIO_OFFS = 0x400; + $GPIO_CRL = 0x00; + $GPIO_CRH = 0x04; + $GPIO_IDR = 0x08; + $GPIO_ODR = 0x0C; +} +else +{ + # these offsets are identical on all F0, F4, F7, H7, L4, L4+ devices up to now + $GPIO_OFFS = 0x400; + $GPIO_MODER = 0x00; + $GPIO_OTYPER = 0x04; + $GPIO_OSPEEDR = 0x08; + $GPIO_PUPDR = 0x0C; + $GPIO_IDR = 0x10; + $GPIO_ODR = 0x14; + $GPIO_AFRL = 0x20; + $GPIO_AFRH = 0x24; +} + +my @Out = ( { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { } ); +my @Port = ( ); +my $Exor; +my %Conf; +my $Pins = "${Sep}#"; + +my $pins; +my $altn; +my %defs; + +if ($Getopt::Std::opt_f ne '') +{ + open(CONF_FILE, '<', $Getopt::Std::opt_f) || die("can't open $Getopt::Std::opt_f"); + while (my $line = ) + { + if ($line =~ /^\s*#define\s+.?(QSPI|QUAD_?SPI|OCTOSPI[^_]*)\w+_(Port|Pin)\s/) + { + if ($line =~ /#define\s+(\w+)\s+(\w+)/) + { + $defs{$1} = $2; + } + else + { + die($line); + } + } + elsif ($line =~ /^\s*(P[A-Z])([0-9]+)\s*-+>\s+.?(QSPI|QUAD_?SPI|OCTO_?SPI[^_]*)_(\w+)/) + { + $Conf{$4} = sprintf("%s%02d", $1, $2); + } + elsif ($line =~ /^\s*GPIO_InitStruct.Pin\s*=\s*([^;]+\w)/) + { + $pins = $1; + while ($line !~ /;/) + { + $line = ; + $line =~ /^\s*([^;]+\w)/; + $pins .= $1; + } + } + elsif ($line =~ /^\s*GPIO_InitStruct.Alternate\s*=\s*GPIO_AF([0-9]+)/) + { + $altn = $1; + } + elsif ($line =~ /^\s*HAL_GPIO_Init\s*\(\s*(\w+)\s*,/) + { + my $port = $1; + if ($port =~ /GPIO([A-Z])/) + { + $port = $1; + } + elsif (exists($defs{$port})) + { + $defs{$port} =~ /GPIO([A-Z])/; + $port = $1; + } + else + { + printf("\n"); + next; + } + my @pin = split(/\s*\|\s*/, $pins); + foreach my $pin (@pin) + { + my $bit; + if (exists($defs{$pin})) + { + $defs{$pin} =~ /GPIO_PIN_([0-9]+)/; + $bit = $1; + } + else + { + $pin =~ /GPIO_PIN_([0-9]+)/; + $bit = $1; + } + $Conf .= sprintf("P%s%02d:AF%02d:V, ", $port, $bit, $altn); + } + $pins = ''; + $altn = 0; + } + } + close(CONF_FILE); +} +else +{ + my @names = ( ); + my @conf = split(/\s*,\s*/, $Conf); + + if (@conf == 2) + { + push(@names, 'SDA', 'SCL'); + } else { + if (@conf == 3) + { + push(@names, 'NCS', 'CLK', 'IO0/DIO'); + } + elsif (@conf == 4) + { + push(@names, 'NCS', 'CLK','IO1/MISO', 'IO0/MOSI'); + } + elsif (@conf == 6) + { + push(@names, 'NCS', 'CLK', 'IO3/NHOLD', 'IO2/NWP', 'IO1/MISO', 'IO0/MOSI'); + } + elsif (@conf == 10) + { + push(@names, 'NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI'); + push(@names, 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI'); + } + elsif (@conf == 11) + { + push(@names, 'BK_1_NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI'); + push(@names, 'BK_2_NCS', 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI'); + } + else + { + die("invalid config"); + } + } + + for (my $index = 0; $index < @conf; $index++) + { + uc($conf[$index]) =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/; + $Pins .= sprintf(" %s: P%s%02d,", $names[$index], $1, $2); + } + chop($Pins); +} + +if (exists $Conf{'BK1_IO0'}) +{ + # QuadSPI on F4, F7, H7 + my $line; + for my $i ('NCS', 'BK1_NCS', 'CLK', 'BK1_IO3', 'BK1_IO2', 'BK1_IO1', 'BK1_IO0') + { + (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); + } +} + +if (exists $Conf{'BK2_IO0'}) +{ + # QuadSPI on F4, F7, H7 + my $line; + for my $i ('NCS', 'BK2_NCS', 'CLK', 'BK2_IO3', 'BK2_IO2', 'BK2_IO1', 'BK2_IO0') + { + (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); + } +} + +if (exists $Conf{'P1_IO0'}) +{ + # OctoSPI on L4+, L5, H7 + my $line; + for my $i ('P1_NCS', 'P1_CLK', 'P1_DQS', 'P1_IO7', 'P1_IO6', 'P1_IO5', 'P1_IO4', + 'P1_IO3', 'P1_IO2', 'P1_IO1', 'P1_IO0') + { + (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); + } +} + +if (exists $Conf{'P2_IO0'}) +{ + # OctoSPI on L4+, H7 + my $line; + for my $i ('P2_NCS', 'P2_CLK', 'P2_DQS', 'P2_IO7', 'P2_IO6', 'P2_IO5', 'P2_IO4', + 'P2_IO3', 'P2_IO2', 'P2_IO1', 'P2_IO0') + { + (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); + } +} + +my @Col = ( ); +my @conf = split(/\s*,\s*/, $Conf); + +if (@conf == 3) +{ + splice(@conf, 2, 0, 'NONE', 'NONE', 'NONE'); +} +elsif (@conf == 4) +{ + splice(@conf, 2, 0, 'NONE', 'NONE'); +} + +foreach my $line (@conf) +{ + $line = uc($line); + $line =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/; + my $port = $1; + my $pin = $2; + my $conf = $3; + my $speed = $4; + + my $MODER = 0x0; + my $OTYPER = 0x0; + my $OSPEEDR = 0x0; + my $PUPDR = 0x0; + my $AFR = 0x0; + my $num = ord(${port}) - ord('A'); + my $out = $Out[$num]; + + (exists $$out{'DEF'}) || ($$out{'DEF'} = 0); + + if ($conf eq '') + { + if ($line ne 'NONE') + { + printf(STDERR "invalid conf %s\n", $line); + } + next; + } + elsif ($conf =~ /^AF([0-9]+)(|P|O)(|UP|DO)$/) + { + if ($STM32F1) + { + printf(STDERR "no alternate %s for F1 family\n", $line); + next; + } + if (($1 < 0) || ($1 > 15)) + { + printf(STDERR "invalid alternate %s\n", $line); + next; + } + $MODER = 0x2; + $AFR = $1; + if ($pin <= 7) + { + $$out{'AFRL_H'} |= ($AFR << (${pin} << 2)); + $$out{'AFRL_L'} |= (($AFR ^ 0xF) << (${pin} << 2)); + } + else + { + $$out{'AFRH_H'} |= ($AFR << ((${pin} - 8) << 2)); + $$out{'AFRH_L'} |= (($AFR ^ 0xF) << ((${pin} - 8) << 2)); + } + if ($2 ne '') { + $OTYPER = ($1 eq 'O') ? 0x1 : 0x0; + $$out{'OTYPER_H'} |= ($OTYPER << $pin); + $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin); + } + $PUPDR = ($3 eq 'UP') ? 0x1 : (($3 eq 'DO') ? 0x2 : 0x0); + $$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1)); + $$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1)); + $conf = sprintf("AF%02d%s%s", $AFR, $2, $3); + } + elsif ($conf =~ /^IN(|P|O)(|UP|DO)$/) + { + if ($STM32F1) + { + $MODER = ($1 eq '') ? 0x4 : 0x8; + ($2 eq 'UP') && ($$out{'PUPDR_H'} |= (1 << ${pin})); + ($2 eq 'DO') && ($$out{'PUPDR_L'} |= (1 << ${pin})); + } + else + { + $MODER = 0x0; + if ($1 ne '') + { + $OTYPER = ($1 eq 'O') ? 0x1 : 0x0; + $$out{'OTYPER_H'} |= ($OTYPER << $pin); + $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin); + } + $PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0); + $$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1)); + $$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1)); + } + ($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin})); + ($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin})); + } + elsif ($conf =~ /^P(P|O)(|UP|DO)$/) + { + if ($STM32F1) + { + $MODER = ($1 eq 'O') ? 0x4 : 0x0; + $MODER |= (($speed eq 'V') ? 0x03 : (($speed eq 'L') ? 0x2 : 0x1)); + if ($2 ne '') + { + printf(STDERR "WARNING: no output w/ pull-up/pull-down for F1 family %s\n", $line); + } + } + else + { + $MODER = 0x1; + $OTYPER = ($1 eq 'O') ? 0x1 : 0x0; + $$out{'OTYPER_H'} |= ($OTYPER << $pin); + $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin); + $PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0); + $$out{'PUPDR_H'} |= ($PUPDR << ($pin << 1)); + $$out{'PUPDR_L'} |= (($PUPDR ^ 0x3) << ($pin << 1)); + } + ($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin})); + ($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin})); + } + else + { + printf(STDERR "invalid conf %s\n", $line); + next; + } + + if ($$out{'DEF'} & (1<< ${pin})) + { + printf(STDERR "redefinition: %s\n", $line); + } + + if ($STM32F1) + { + if ($pin >= 8) + { + $$out{'CRH_H'} |= ($MODER << (($pin & 0x7) << 2)); + $$out{'CRH_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2)); + } + else + { + $$out{'CRL_H'} |= ($MODER << (($pin & 0x7) << 2)); + $$out{'CRL_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2)); + } + + $Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port) - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin); + my $exor = 0xB << (($pin & 0x7) << 2); + (($MODER & 0x3) == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X", + ((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF, + ((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF, $exor)); + } + else + { + $$out{'DEF'} |= (1 << ${pin}); + $$out{'MODER_H'} |= ($MODER << (${pin} << 1)); + $$out{'MODER_L'} |= (($MODER ^ 0x3) << (${pin} << 1)); + + $OSPEEDR = (($speed eq 'V') ? 0x3 : (($speed eq 'H') ? 0x2 : (($speed eq 'M') ? 0x1 : 0x0))); + $$out{'OSPEEDR_H'} |= ($OSPEEDR << (${pin} << 1)); + $$out{'OSPEEDR_L'} |= (($OSPEEDR ^ 0x3) << (${pin} << 1)); + + $Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port) - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin); + my $exor = (0x1 << ($pin << 1)); + ($MODER == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X", (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF, + (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF, $exor)); + } + + push(@{$Port[$num]}, sprintf("P%s%02d:%s:%s", $port, $pin, $conf, $speed)); + push(@Col, $Exor); +} + +my $Col = sprintf("${Sep}0x%03X ", (${GPIO_IDR}-${GPIO_ODR}) & 0x3FF); +for (my $i = 0; $i < @Col; $i++) +{ + if (($i != 0) && (($i % 2) == 0)) + { + (($i + 1) < @Col) && ($Col .= "\\\n${Sep}"); + } + $Col .= sprintf("%s ", $Col[$i]); +} +printf("%s\n", $Col); + +my @Col = ( ); +my $Set; +for (my $i = 0; $i < @Out; $i++) +{ + my $out = $Out[$i]; + my $addr = ${GPIO_BASE} + $i * ${GPIO_OFFS}; + my $count = 0; + + if ($STM32F1) + { + if (($$out{'CRH_H'} | $$out{'CRH_L'} | $$out{'CRL_H'} | $$out{'CRL_L'} | + $$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0) + { + push(@Col, sort({ $b cmp $a } @{$Port[$i]})); + + $Set .= sprintf("\n%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')), + join(", ", sort({ $b cmp $a } @{$Port[$i]}))); + + (($$out{'CRL_H'} | $$out{'CRL_L'}) != 0) && + ($Set .= sprintf("${Form}CRL\n", $addr + ${GPIO_CRL}, $$out{'CRL_H'}, $$out{'CRL_L'})); + + (($$out{'CRH_H'} | $$out{'CRH_L'}) != 0) && + ($Set .= sprintf("${Form}CRH\n", $addr + ${GPIO_CRH}, $$out{'CRH_H'}, $$out{'CRH_L'})); + + (($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) && + ($Set .= sprintf("${Form}ODR/PUPDR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'})); + } + } + else + { + if (($$out{'MODER_H'} | $$out{'MODER_L'} | + $$out{'OTYPER_H'} | $$out{'OTYPER_L'} | + $$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'} | + $$out{'PUPDR_H'} | $$out{'PUPDR_L'} | + $$out{'ODR_H'} | $$out{'ODR_L'} | + $$out{'AFRL_H'} | $$out{'AFRL_L'} | + $$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0) + { + push(@Col, sort({ $b cmp $a } @{$Port[$i]})); + + $Set .= sprintf("%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')), + join(", ", sort({ $b cmp $a } @{$Port[$i]}))); + + (($$out{'MODER_H'} | $$out{'MODER_L'}) != 0) && + ($Set .= sprintf("${Form}MODER\n", $addr + ${GPIO_MODER}, $$out{'MODER_H'}, $$out{'MODER_L'})); + + (($$out{'OTYPER_H'} | $$out{'OTYPER_L'}) != 0) && + ($Set .= sprintf("${Form}OTYPER\n", $addr + ${GPIO_OTYPER}, $$out{'OTYPER_H'}, $$out{'OTYPER_L'})); + + (($$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'}) != 0) && + ($Set .= sprintf("${Form}OSPEEDR\n", $addr + ${GPIO_OSPEEDR}, $$out{'OSPEEDR_H'}, $$out{'OSPEEDR_L'})); + + (($$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0) && + ($Set .= sprintf("${Form}PUPDR\n", $addr + ${GPIO_PUPDR}, $$out{'PUPDR_H'}, $$out{'PUPDR_L'})); + + (($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) && + ($Set .= sprintf("${Form}ODR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'})); + + (($$out{'AFRL_H'} | $$out{'AFRL_L'}) != 0) && + ($Set .= sprintf("${Form}AFRL\n", $addr + ${GPIO_AFRL}, $$out{'AFRL_H'}, $$out{'AFRL_L'})); + + (($$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0) && + ($Set .= sprintf("${Form}AFRH\n", $addr + ${GPIO_AFRH}, $$out{'AFRH_H'}, $$out{'AFRH_L'})); + } + } +} + +my $Col = ''; +for (my $i = 0; $i < @Col; $i++) +{ + if (($i % 6) == 0) + { + chop($Col); + (($i + 1) < @Col) && ($Col .= "\n${Sep}#"); + } + $Col .= sprintf(" %s,", $Col[$i]); +} +chop($Col); +#printf("\n%s\n", $Pins); +printf("%s\n", $Col); +printf("%s\n", $Set); diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S new file mode 100644 index 0000000000..338fba370b --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch * + * andreas.bolsch@mni.thm.de * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + +/* Params: + * r0 - total count (bytes), crc32 (out) + * r1 - flash page size + * r2 - address offset into flash + * r3 - OCTOSPI io_base + + * Clobbered: + * r4 - tmp + * r5 - address of OCTOSPI_DR + * r6 - address of OCTOSPI_CCR + * r7 - tmp + */ + +#include "../../../../src/flash/nor/stmqspi.h" + +#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR) +#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR) +#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR) + + .macro octospi_abort + movs r5, #(1< CRC32XOR, pos. -> 0x0 */ + lsls r4, r4, #1 /* shift result */ + eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */ + .endr + adds r2, r2, #1 /* increment address */ + subs r0, r0, #1 /* decrement (count-1) */ + bmi exit /* stop if no data left */ + tst r2, r1 /* page end ? */ + bne read_loop /* if not, then next byte */ +page_end: + bal start_read /* then next page */ + .pool + +exit: + mvns r0, r4 /* invert to get final result */ + octospi_abort /* to idle state */ + .align 2 /* align to word, bkpt is 4 words */ + bkpt #0 /* before code end for exit_point */ + .align 2 /* align to word */ + +cr_page_read: + .space 4 /* OCTOSPI_CR value for read command */ +ccr_page_read: + .space 4 /* OCTOSPI_CCR value for read command */ +tcr_page_read: + .space 4 /* OCTOSPI_TCR value for read command */ +ir_page_read: + .space 4 /* OCTOSPI_IR value for read command */ diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc new file mode 100644 index 0000000000..afc6168834 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc @@ -0,0 +1,13 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60, +0x50,0x25,0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27, +0x5f,0x62,0x22,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9, +0x07,0x46,0x1f,0x64,0x1e,0x4f,0x37,0x60,0x1e,0x4f,0xb7,0x60,0x1e,0x4f,0x37,0x61, +0x9a,0x64,0x15,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, +0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, +0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, +0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, +0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38,0x05,0xd4, +0x0a,0x42,0xd7,0xd1,0xb8,0xe7,0x00,0x00,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25, +0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S b/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S new file mode 100644 index 0000000000..6593a8edea --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch * + * andreas.bolsch@mni.thm.de * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + +/* Params: + * r0 - sector count + * r1 - QSPI io_base + + * Clobbered: + * r2 - r7 tmp */ + +#include "../../../../src/flash/nor/stmqspi.h" + +#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR) +#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR) +#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR) + + .macro octospi_abort + movs r5, #(1< CRC32XOR, pos. -> 0x0 */ + lsls r4, r4, #1 /* shift result */ + eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */ + .endr + adds r2, r2, #1 /* increment address */ + subs r0, r0, #1 /* decrement (count-1) */ + bmi exit /* stop if no data left */ + tst r2, r1 /* page end ? */ + bne read_loop /* if not, then next byte */ +page_end: + bal start_read /* then next page */ + .pool + +exit: + mvns r0, r4 /* invert to get final result */ + qspi_abort /* to idle state */ + .align 2 /* align to word, bkpt is 4 words */ + bkpt #0 /* before code end for exit_point */ + .align 2 /* align to word */ + + .space 4 /* not used */ +ccr_page_read: + .space 4 /* QSPI_CCR value for read command */ + .space 4 /* not used */ + .space 4 /* not used */ diff --git a/contrib/loaders/flash/stmqspi/stmqspi_crc32.inc b/contrib/loaders/flash/stmqspi/stmqspi_crc32.inc new file mode 100644 index 0000000000..b532a48b95 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmqspi_crc32.inc @@ -0,0 +1,12 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60, +0x20,0x25,0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x17,0x46, +0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,0x1c,0x4f,0x5f,0x61, +0x9a,0x61,0x9f,0x68,0x14,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40, +0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40, +0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40, +0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40, +0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38, +0x04,0xd4,0x0a,0x42,0xd7,0xd1,0xbf,0xe7,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25, +0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, diff --git a/contrib/loaders/flash/stmqspi/stmqspi_erase_check.S b/contrib/loaders/flash/stmqspi/stmqspi_erase_check.S new file mode 100644 index 0000000000..5fddbcbb9c --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmqspi_erase_check.S @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch * + * andreas.bolsch@mni.thm.de * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + +/* Params: + * r0 - sector count + * r1 - QSPI io_base + + * Clobbered: + * r2 - r7 tmp */ + +#include "../../../../src/flash/nor/stmqspi.h" + + .macro qspi_abort + movs r4, #(1< $@" + $(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 5c717ce0ed..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 3470d848bf..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) @@ -95,24 +97,16 @@ class OpenOcd: return None if (len(raw) < 2) else strToHex(raw[1]) def readMemory(self, wordLen, address, n): - self.send("array unset output") # better to clear the array before - self.send("mem2array output %d 0x%x %d" % (wordLen, address, n)) - - output = [*map(int, self.send("return $output").split(" "))] - d = dict([tuple(output[i:i + 2]) for i in range(0, len(output), 2)]) - - return [d[k] for k in sorted(d.keys())] + output = self.send("read_memory 0x%x %d %d" % (address, wordLen, n)) + return [*map(lambda x: int(x, 16), output.split(" "))] def writeVariable(self, address, value): assert value is not None self.send("mww 0x%x 0x%x" % (address, value)) - def writeMemory(self, wordLen, address, n, data): - array = " ".join(["%d 0x%x" % (a, b) for a, b in enumerate(data)]) - - self.send("array unset 1986ве1т") # better to clear the array before - self.send("array set 1986ве1т { %s }" % array) - self.send("array2mem 1986ве1т 0x%x %s %d" % (wordLen, address, n)) + def writeMemory(self, wordLen, address, data): + data = "{" + ' '.join(['0x%x' % x for x in data]) + "}" + self.send("write_memory 0x%x %d %s" % (address, wordLen, data)) if __name__ == "__main__": diff --git a/contrib/rpc_examples/ocdrpc.hs b/contrib/rpc_examples/ocdrpc.hs index 9a80cdd849..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: @@ -16,13 +18,11 @@ module Main where import Prelude -import Control.Applicative import Network.Socket import System.IO.Streams.Core hiding (connect) import System.IO.Streams.Network import System.IO.Streams.Attoparsec import Data.Attoparsec.ByteString.Char8 -import Data.Attoparsec.Combinator import Data.ByteString.Char8 hiding (putStrLn, concat, map) import Text.Printf @@ -38,15 +38,14 @@ mdwParser = (manyTill anyChar (string ": ") *> `sepBy` string " \n" ocdMdw :: (InputStream ByteString, OutputStream ByteString) -> Integer -> Integer -> IO [Integer] -ocdMdw s start count = do - s <- ocdExec s $ "mdw " ++ show start ++ " " ++ show count - case parseOnly mdwParser (pack s) of +ocdMdw s start qnt = do + res <- ocdExec s $ "mdw " ++ show start ++ " " ++ show qnt + case parseOnly mdwParser (pack res) of Right r -> return $ concat r main = do osock <- socket AF_INET Stream defaultProtocol - haddr <- inet_addr "127.0.0.1" - connect osock (SockAddrInet 6666 haddr) + connect osock (SockAddrInet 6666 $ tupleToHostAddress (127,0,0,1)) ostreams <- socketToStreams osock putStrLn "Halting the target, full log output captured:" ocdExec ostreams "capture \"halt\"" >>= putStrLn 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/fdl.texi b/doc/fdl.texi index 33b2a16467..2189f80a66 100644 --- a/doc/fdl.texi +++ b/doc/fdl.texi @@ -1,6 +1,5 @@ @c -*-texinfo-*- -@node License -@appendix The GNU Free Documentation License. +@c The GNU Free Documentation License. @center Version 1.2, November 2002 @c This file is intended to be included within another document, @@ -396,7 +395,7 @@ The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See -@uref{http://www.gnu.org/copyleft/}. +@uref{https://www.gnu.org/licenses/}. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this @@ -408,7 +407,8 @@ number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. @end enumerate -@unnumberedsec ADDENDUM: How to use this License for your documents +@page +@heading ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and 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 1b01b2e6bb..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 @@ -89,7 +91,7 @@ mode(s) of execution, and strings that provide usage and help text. A single handler may be registered using multiple names, but any name may have only one handler associated with it. -The @c register_commands() and @c register_commands() functions provide +The @c register_command() and @c register_commands() functions provide registration, while the @c unregister_command() and @c unregister_all_commands() functions will remove existing commands. These may be called at any time, allowing the command set to change in diff --git a/doc/manual/jtag.txt b/doc/manual/jtag.txt index 8f0804ce93..2653fc78f5 100644 --- a/doc/manual/jtag.txt +++ b/doc/manual/jtag.txt @@ -36,7 +36,6 @@ asynchronous transactions. - declared in @c src/jtag/minidriver.h - used @a only by the core and minidriver implementations: - @c jtag_driver.c (in-tree OpenOCD drivers) - - @c zy1000/build/include/jtag_minidriver.h (ZY1000 minidriver) - future implementations (on other embedded hosts) - interface device drivers do @b not need this API. diff --git a/doc/manual/jtag/drivers/remote_bitbang.txt b/doc/manual/jtag/drivers/remote_bitbang.txt index f394d736af..8316cb0dd5 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,25 @@ 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: + + Z - Sleep for 1 millisecond + z - Sleep for 1 microsecond + +NOTE: Previously these were specified as 'D' and 'd', which conflicts with the +"SWD write 0 0" command defined above. Adapters that implement Dd for remote +sleep must be updated to work with Zz. -The read response is encoded in ASCII as either digit 0 or 1. */ diff --git a/doc/manual/main.txt b/doc/manual/main.txt index c14096b573..c28fbe2288 100644 --- a/doc/manual/main.txt +++ b/doc/manual/main.txt @@ -9,7 +9,7 @@ and processes that have been developed by and for the OpenOCD community. Developers that want to contribute to OpenOCD should read the following sections before starting work: -- The List of @subpage thelist enumerates opportunities for improving or +- @subpage thelist enumerates opportunities for improving or extending the OpenOCD platform. If your ideas are on The List, you might check the mailing list archives to find the status of your feature (or bug). - The @subpage styleguide provides rules that developers should @@ -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/primer/autotools.txt b/doc/manual/primer/autotools.txt index 3471eacd7e..f038f0b2f1 100644 --- a/doc/manual/primer/autotools.txt +++ b/doc/manual/primer/autotools.txt @@ -15,9 +15,6 @@ autotools in the correct sequence. When run after a fresh checkout, this script generates the build files required to compile the project, producing the project configure script. -After running @c configure, the @ref primermaintainermode settings will -handle most situations that require running these tools again. In some -cases, a fresh bootstrap may be still required. @subsection primerbootstrapcures Problems Solved By Bootstrap diff --git a/doc/manual/primer/jtag.txt b/doc/manual/primer/jtag.txt index 41eef723db..097e20d10d 100644 --- a/doc/manual/primer/jtag.txt +++ b/doc/manual/primer/jtag.txt @@ -104,7 +104,7 @@ target chips and work out what the various instruction registers/data registers do, so you can actually do something useful. That's where it gets interesting. But in and of itself, JTAG is actually very simple. -@section primerjtag More Reading +@section primerjtagmore More Reading A separate primer contains information about @subpage primerjtagbs for developers that want to extend OpenOCD for such purposes. diff --git a/doc/manual/primer/tcl.txt b/doc/manual/primer/tcl.txt index 868a75ba08..eba2f552d0 100644 --- a/doc/manual/primer/tcl.txt +++ b/doc/manual/primer/tcl.txt @@ -174,7 +174,7 @@ them. It is similar to this bash statement. EXPORT vn=`date` LINE 2 & 3 - set $vn [expr (1024 * $x)] + set $vn [expr {1024 * $x}] global $vn In line 1, we dynamically created a variable name. Here, we are diff --git a/doc/manual/style.txt b/doc/manual/style.txt index 7191a4b0e6..1d3ec6748d 100644 --- a/doc/manual/style.txt +++ b/doc/manual/style.txt @@ -48,9 +48,55 @@ OpenOCD project. - use Unix line endings ('\\n'); do NOT use DOS endings ('\\r\\n') - limit adjacent empty lines to at most two (2). - remove any trailing empty lines at the end of source files -- do not "comment out" code from the tree; instead, one should either: - -# remove it entirely (git can retrieve the old version), or - -# use an @c \#if/\#endif block. +- do not "comment out" code from the tree nor put it within a block + @code + #if 0 + ... + #endif + @endcode + otherwise it would never be checked at compile time and when new + patches get merged it could be not compilable anymore. + Code that is not fully working nor ready for submission should + instead be removed entirely (git can retrieve the old version). + For exceptional cases that require keeping some unused code, let + the compiler check it by putting it in a block + @code + if (false) { + /* explain why this code should be kept here */ + ... + } + @endcode +- in a @c switch statement align the @c switch with the @c case label + @code + switch (dev_id) { + case 0x0123: + size = 0x10000; + break; + case 0x0412: + size = 0x20000; + break; + default: + size = 0x40000; + break; + } + @endcode +- in an <tt> if / then / else </tt> statement, if only one of the conditions + require curly brackets due to multi-statement block, put the curly brackets + also to the other condition + @code + if (x > 0) + a = 12 + x; + else + a = 24; + @endcode + @code + if (x > 0) { + a = 12 + x; + } else { + a = 24; + x = 0; + } + @endcode Finally, try to avoid lines of code that are longer than 72-80 columns: @@ -60,12 +106,13 @@ Finally, try to avoid lines of code that are longer than 72-80 columns: - a few lines may be wider than this limit (typically format strings), but: - all C compilers will concatenate series of string constants. - all long string constants should be split across multiple lines. + - do never exceed 120 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. @@ -104,19 +151,23 @@ or variable length arrays on the stack. non-MMU hosts(uClinux) and pthreads require modest and predictable stack usage. @section styletypes Type Guidelines -- use native types (@c int or @c unsigned) if the type is not important +- use native types (@c int or <tt> unsigned int </tt>) if the type is not important - if size matters, use the types from \<stdint.h\> or \<inttypes.h\>: - @c int8_t, @c int16_t, @c int32_t, or @c int64_t: signed types of specified size - @c uint8_t, @c uint16_t, @c uint32_t, or @c uint64_t: unsigned types of specified size + - use the associated @c printf and @c scanf formatting strings for these types + (e.g. @c PRId8, PRIx16, SCNu8, ...) - do @b NOT redefine @c uN types from "types.h" + - use type @c target_addr_t for target's address values + - prefer type <tt> unsigned int </tt> to type @c unsigned @section stylefunc Functions - static inline functions should be preferred over macros: @code -/** do NOT define macro-like functions like this... */ +/* do NOT define macro-like functions like this... */ #define CUBE(x) ((x) * (x) * (x)) -/** instead, define the same expression using a C99 inline function */ +/* instead, define the same expression using a C99 inline function */ static inline int cube(int x) { return x * x * x; } @endcode - Functions should be declared static unless required by other modules @@ -135,14 +186,28 @@ should write statements like the following: @code // separate statements should be preferred result = foo(); -if (ERROR_OK != result) +if (result != ERROR_OK) ... @endcode More directly, do @b not combine these kinds of statements: @code // Combined statements should be avoided -if (ERROR_OK != (result = foo())) +if ((result = foo()) != ERROR_OK) return result; +@endcode +- Do not compare @c bool values with @c true or @c false but use the + value directly +@code +if (!is_enabled) + ... +@endcode +- Avoid comparing pointers with @c NULL +@code +buf = malloc(buf_size); +if (!buf) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; +} @endcode */ @@ -186,9 +251,9 @@ comments. "empty" lines should be removed from the block. -# Only single spaces should be used; do @b not add mid-line indentation. -# If the total line length will be less than 72-80 columns, then - - The @c /**< form can be used on the same line. + - The @c /\**< form can be used on the same line. - This style should be used sparingly; the best use is for fields: - @code int field; /**< field description */ @endcode + @verbatim int field; /**< field description */ @endverbatim @section styledoxyall Doxygen Style Guide @@ -341,7 +406,7 @@ For technical reference material: vice versa. - Alphabetize the \@defn declarations for all commands in each section. -- Keep the per-command documentation focussed on exactly what that +- Keep the per-command documentation focused on exactly what that command does, not motivation, advice, suggestions, or big examples. When commands deserve such expanded text, it belongs elsewhere. Solutions might be using a \@section explaining a cluster of related diff --git a/doc/openocd.texi b/doc/openocd.texi index 8c99228c3f..52a51c196f 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} @@ -30,9 +30,9 @@ of the Open On-Chip Debugger (OpenOCD). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no -Invariant Sections, with no Front-Cover Texts, and with no Back-Cover -Texts. A copy of the license is included in the section entitled ``GNU -Free Documentation License''. +Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A +copy of the license is included in the section entitled ``GNU Free +Documentation License''. @end quotation @end copying @@ -79,7 +79,6 @@ Free Documentation License''. * JTAG Commands:: JTAG Commands * Boundary Scan Commands:: Boundary Scan Commands * Utility Commands:: Utility Commands -* TFTP:: TFTP * GDB and OpenOCD:: Using GDB and OpenOCD * Tcl Scripting API:: Tcl Scripting API * FAQ:: Frequently Asked Questions @@ -203,7 +202,7 @@ communication between users: @section OpenOCD IRC Support can also be found on irc: -@uref{irc://irc.freenode.net/openocd} +@uref{irc://irc.libera.chat/openocd} @node Developers @chapter OpenOCD Developer Resources @@ -266,7 +265,7 @@ listed in the Doxyfile configuration at the top of the source tree. All changes in the OpenOCD Git repository go through the web-based Gerrit Code Review System: -@uref{http://openocd.zylin.com/} +@uref{https://review.openocd.org/} After a one-time registration and repository setup, anyone can push commits from their local Git repository directly into Gerrit. @@ -299,7 +298,6 @@ The OpenOCD Bug Tracker is hosted on SourceForge: @cindex dongles @cindex FTDI @cindex wiggler -@cindex zy1000 @cindex printer port @cindex USB Adapter @cindex RTCK @@ -308,12 +306,7 @@ Defined: @b{dongle}: A small device that plugs into a computer and serves as an adapter .... [snip] In the OpenOCD case, this generally refers to @b{a small adapter} that -attaches to your computer via USB or the parallel port. One -exception is the Ultimate Solutions ZY1000, packaged as a small box you -attach via an ethernet cable. The ZY1000 has the advantage that it does not -require any drivers to be installed on the developer PC. It also has -a built in web interface. It supports RTCK/RCLK or adaptive clocking -and has a built-in relay to power cycle targets remotely. +attaches to your computer via USB or the parallel port. @section Choosing a Dongle @@ -322,7 +315,7 @@ There are several things you should keep in mind when choosing a dongle. @enumerate @item @b{Transport} Does it support the kind of communication that you need? -OpenOCD focusses mostly on JTAG. Your version may also support +OpenOCD focuses mostly on JTAG. Your version may also support other ways to communicate with target devices. @item @b{Voltage} What voltage is your target - 1.8, 2.8, 3.3, or 5V? Does your dongle support it? You might need a level converter. @@ -335,26 +328,6 @@ Ethernet port needed? RTCK support (also known as ``adaptive clocking'')? @end enumerate -@section Stand-alone JTAG Probe - -The ZY1000 from Ultimate Solutions is technically not a dongle but a -stand-alone JTAG probe that, unlike most dongles, doesn't require any drivers -running on the developer's host computer. -Once installed on a network using DHCP or a static IP assignment, users can -access the ZY1000 probe locally or remotely from any host with access to the -IP address assigned to the probe. -The ZY1000 provides an intuitive web interface with direct access to the -OpenOCD debugger. -Users may also run a GDBSERVER directly on the ZY1000 to take full advantage -of GCC & GDB to debug any distribution of embedded Linux or NetBSD running on -the target. -The ZY1000 supports RTCK & RCLK or adaptive clocking and has a built-in relay -to power cycle the target remotely. - -For more information, visit: - -@b{ZY1000} See: @url{http://www.ultsol.com/index.php/component/content/article/8/210-zylin-zy1000-main} - @section USB FT2232 Based There are many USB JTAG dongles on the market, many of them based @@ -490,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, @@ -529,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/} @@ -611,13 +593,38 @@ 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} +@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 driver supports +JTAG and DAP-level transports. + +@item @b{jtag_dpi} +@* A JTAG driver acting as a client for the SystemVerilog Direct Programming +Interface (DPI) for JTAG devices. DPI allows OpenOCD to connect to the JTAG +interface of a hardware model written in SystemVerilog, for example, on an +emulation model of target hardware. + @item @b{xlnx_pcie_xvc} @* A JTAG driver exposing Xilinx Virtual Cable over PCI Express to OpenOCD as JTAG/SWD interface. +@item @b{linuxgpiod} +@* A bitbang JTAG driver using Linux GPIO through library libgpiod. + +@item @b{sysfsgpio} +@* 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 @@ -718,8 +725,11 @@ Configuration files and scripts are searched for in @item the current directory, @item any search dir specified on the command line using the @option{-s} option, @item any search dir specified using the @command{add_script_search_dir} command, -@item @file{$HOME/.openocd} (not on Windows), @item a directory in the @env{OPENOCD_SCRIPTS} environment variable (if set), +@item @file{%APPDATA%/OpenOCD} (only on Windows), +@item @file{$HOME/Library/Preferences/org.openocd} (only on Darwin), +@item @file{$XDG_CONFIG_HOME/openocd} (@env{$XDG_CONFIG_HOME} defaults to @file{$HOME/.config}), +@item @file{$HOME/.openocd}, @item the site wide script library @file{$pkgdatadir/site} and @item the OpenOCD-supplied script library @file{$pkgdatadir/scripts}. @end enumerate @@ -819,7 +829,7 @@ using Eclipse or some other GUI. Today's most common case is a dongle with a JTAG cable on one side (such as a ribbon cable with a 10-pin or 20-pin IDC connector) and a USB cable on the other. -Instead of USB, some cables use Ethernet; +Instead of USB, some dongles use Ethernet; older ones may use a PC parallel port, or even a serial port. @enumerate @@ -1370,6 +1380,16 @@ Read the OpenOCD source code (and Developer's Guide) if you have a new kind of hardware interface and need to provide a driver for it. +@deffn {Command} {find} 'filename' +Prints full path to @var{filename} according to OpenOCD search rules. +@end deffn + +@deffn {Command} {ocd_find} 'filename' +Prints full path to @var{filename} according to OpenOCD search rules. This +is a low level function used by the @command{find}. Usually you want +to use @command{find}, instead. +@end deffn + @section Board Config Files @cindex config file, board @cindex board config file @@ -1774,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. @@ -1928,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 @@ -2010,9 +2028,9 @@ proc setc15 @{regs value@} @{ echo [format "set p15 0x%04x, 0x%08x" $regs $value] - arm mcr 15 [expr ($regs>>12)&0x7] \ - [expr ($regs>>0)&0xf] [expr ($regs>>4)&0xf] \ - [expr ($regs>>8)&0x7] $value + arm mcr 15 [expr @{($regs >> 12) & 0x7@}] \ + [expr @{($regs >> 0) & 0xf@}] [expr @{($regs >> 4) & 0xf@}] \ + [expr @{($regs >> 8) & 0x7@}] $value @} @end example @@ -2051,6 +2069,19 @@ may access or activate TAPs. After it leaves this stage, configuration commands may no longer be issued. +@deffn {Command} {command mode} [command_name] +Returns the command modes allowed by a command: 'any', 'config', or +'exec'. If no command is specified, returns the current command +mode. Returns 'unknown' if an unknown command is given. Command can be +multiple tokens. (command valid any time) + +In this document, the modes are described as stages, 'config' and +'exec' mode correspond configuration stage and run stage. 'any' means +the command can be executed in either +stages. @xref{configurationstage,,Configuration Stage}, and +@xref{enteringtherunstage,,Entering the Run Stage}. +@end deffn + @anchor{enteringtherunstage} @section Entering the Run Stage @@ -2074,7 +2105,7 @@ a target has been successfully instantiated. If you want to use those commands, you may need to force entry to the run stage. -@deffn {Config Command} init +@deffn {Config Command} {init} This command terminates the configuration stage and enters the run stage. This helps when you need to have the startup scripts manage tasks such as resetting the target, @@ -2086,14 +2117,41 @@ If this command does not appear in any startup/configuration file OpenOCD executes the command for you after processing all configuration files and/or command line options. -@b{NOTE:} This command normally occurs at or near the end of your +@b{NOTE:} This command normally occurs near the end of your openocd.cfg file to force OpenOCD to ``initialize'' and make the targets ready. For example: If your openocd.cfg file needs to read/write memory on your target, @command{init} must occur before the memory read/write commands. This includes @command{nand probe}. + +@command{init} calls the following internal OpenOCD commands to initialize +corresponding subsystems: +@deffn {Config Command} {target init} +@deffnx {Command} {transport init} +@deffnx {Command} {dap init} +@deffnx {Config Command} {flash init} +@deffnx {Config Command} {nand init} +@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} +Prevent OpenOCD from implicit @command{init} call at the end of startup. +Allows issuing configuration commands over telnet or Tcl connection. +When you are done with configuration use @command{init} to enter +the run stage. @end deffn -@deffn {Overridable Procedure} jtag_init +@deffn {Overridable Procedure} {jtag_init} This is invoked at server startup to verify that it can talk to the scan chain (list of TAPs) which has been configured. @@ -2125,8 +2183,11 @@ 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 {Command} gdb_port [number] +@deffn {Config Command} {gdb_port} [number] @cindex GDB server Normally gdb listens to a TCP/IP port, but GDB can also communicate via pipes(stdin/out or named pipes). The name @@ -2140,9 +2201,6 @@ disables the gdb server. When using "pipe", also use log_output to redirect the log output to a file so as not to flood the stdin/out pipes. -The -p/--pipe option is deprecated and a warning is printed -as it is equivalent to passing in -c "gdb_port pipe; log_output openocd.log". - Any other string is interpreted as named pipe to listen to. Output pipe is the same name as input pipe, but with 'o' appended, e.g. /var/gdb, /var/gdbo. @@ -2162,7 +2220,7 @@ gdb (with 'set remotetimeout') is recommended. An insufficient timeout may cause initialization to fail with "Unknown remote qXfer reply: OK". @end deffn -@deffn {Command} tcl_port [number] +@deffn {Config Command} {tcl_port} [number] Specify or query the port used for a simplified RPC connection that can be used by clients to issue TCL commands and get the output from the Tcl engine. @@ -2172,7 +2230,7 @@ the port @var{number} defaults to 6666. When specified as "disabled", this service is not activated. @end deffn -@deffn {Command} telnet_port [number] +@deffn {Config Command} {telnet_port} [number] Specify or query the port on which to listen for incoming telnet connections. This port is intended for interaction with one human through TCL commands. @@ -2191,7 +2249,7 @@ The ones listed here are static and global. @xref{targetevents,,Target Events}, about configuring target-specific event handling. @anchor{gdbbreakpointoverride} -@deffn {Command} gdb_breakpoint_override [@option{hard}|@option{soft}|@option{disable}] +@deffn {Command} {gdb_breakpoint_override} [@option{hard}|@option{soft}|@option{disable}] Force breakpoint type for gdb @command{break} commands. This option supports GDB GUIs which don't distinguish hard versus soft breakpoints, if the default OpenOCD and @@ -2200,13 +2258,13 @@ breakpoints if the memory map has been set up for flash regions. @end deffn @anchor{gdbflashprogram} -@deffn {Config Command} gdb_flash_program (@option{enable}|@option{disable}) +@deffn {Config Command} {gdb_flash_program} (@option{enable}|@option{disable}) Set to @option{enable} to cause OpenOCD to program the flash memory when a vFlash packet is received. The default behaviour is @option{enable}. @end deffn -@deffn {Config Command} gdb_memory_map (@option{enable}|@option{disable}) +@deffn {Config Command} {gdb_memory_map} (@option{enable}|@option{disable}) Set to @option{enable} to cause OpenOCD to send the memory configuration to GDB when requested. GDB will then know when to set hardware breakpoints, and program flash using the GDB load command. @command{gdb_flash_program enable} must also be enabled @@ -2215,26 +2273,26 @@ Default behaviour is @option{enable}. @xref{gdbflashprogram,,gdb_flash_program}. @end deffn -@deffn {Config Command} gdb_report_data_abort (@option{enable}|@option{disable}) +@deffn {Config Command} {gdb_report_data_abort} (@option{enable}|@option{disable}) Specifies whether data aborts cause an error to be reported by GDB memory read packets. The default behaviour is @option{disable}; use @option{enable} see these errors reported. @end deffn -@deffn {Config Command} gdb_report_register_access_error (@option{enable}|@option{disable}) +@deffn {Config Command} {gdb_report_register_access_error} (@option{enable}|@option{disable}) Specifies whether register accesses requested by GDB register read/write packets report errors or not. The default behaviour is @option{disable}; use @option{enable} see these errors reported. @end deffn -@deffn {Config Command} gdb_target_description (@option{enable}|@option{disable}) +@deffn {Config Command} {gdb_target_description} (@option{enable}|@option{disable}) Set to @option{enable} to cause OpenOCD to send the target descriptions to gdb via qXfer:features:read packet. The default behaviour is @option{enable}. @end deffn -@deffn {Command} gdb_save_tdesc +@deffn {Command} {gdb_save_tdesc} Saves the target description file to the local file system. The file name is @i{target_name}.xml. @@ -2279,7 +2337,7 @@ to the various active targets. There is a command to manage and monitor that polling, which is normally done in the background. -@deffn Command poll [@option{on}|@option{off}] +@deffn {Command} {poll} [@option{on}|@option{off}] Poll the current target for its current state. (Also, @pxref{targetcurstate,,target curstate}.) If that target is in debug mode, architecture @@ -2353,25 +2411,74 @@ Use the adapter driver @var{name} to connect to the target. @end deffn -@deffn Command {adapter list} +@deffn {Command} {adapter list} List the debug adapter drivers that have been built into the running copy of OpenOCD. @end deffn -@deffn Command {adapter transports} transport_name+ +@deffn {Config Command} {adapter transports} transport_name+ Specifies the transports supported by this debug adapter. The adapter driver builds-in similar knowledge; use this only 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 -@deffn Command {adapter name} +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 Command {adapter usb location} [<bus>-<port>[.<port>]...] +@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 @var{port} option specifying a deeper level in the bus topology, the last @@ -2381,6 +2488,14 @@ The USB bus topology can be queried with the command @emph{lsusb -t} or @emph{dm This command is only available if your libusb1 is at least version 1.0.16. @end deffn +@deffn {Config Command} {adapter serial} serial_string +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: +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 + @section Interface Drivers Each of the interface drivers listed here must be explicitly @@ -2392,22 +2507,26 @@ Amontec Chameleon in its JTAG Accelerator configuration, connected to a PC's EPP mode parallel port. This defines some driver-specific commands: -@deffn {Config Command} {parport_port} number +@deffn {Config Command} {parport port} number Specifies either the address of the I/O port (default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. @end deffn -@deffn {Config Command} rtck [@option{enable}|@option{disable}] +@deffn {Config Command} {rtck} [@option{enable}|@option{disable}] Displays status of RTCK option. 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: -@deffn Command {armjtagew_info} +@deffn {Command} {armjtagew_info} Logs some status @end deffn @end deffn @@ -2421,25 +2540,60 @@ and a specific set of GPIOs is used. @end deffn @deffn {Interface Driver} {cmsis-dap} -ARM CMSIS-DAP compliant based adapter. +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_serial} [serial] -Specifies the @var{serial} of the CMSIS-DAP device to use. -If not specified, serial numbers are not considered. +@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. +@end itemize +@end deffn + +@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 + +@deffn {Command} {cmsis-dap cmd} number number ... +Execute an arbitrary CMSIS-DAP command. Use for adapter testing or for handling +of an adapter vendor specific command from a Tcl script. + +Take given numbers as bytes, assemble a CMSIS-DAP protocol command packet +from them and send it to the adapter. The first 4 bytes of the adapter response +are logged. +See @url{https://arm-software.github.io/CMSIS_5/DAP/html/group__DAP__Commands__gr.html} +@end deffn @end deffn @deffn {Interface Driver} {dummy} @@ -2455,17 +2609,17 @@ This driver is for adapters using the MPSSE (Multi-Protocol Synchronous Serial Engine) mode built into many FTDI chips, such as the FT2232, FT4232 and FT232H. The driver is using libusb-1.0 in asynchronous mode to talk to the FTDI device, -bypassing intermediate libraries like libftdi or D2XX. +bypassing intermediate libraries like libftdi. Support for new FTDI based adapters can be added completely through configuration files, without the need to patch and rebuild OpenOCD. The driver uses a signal abstraction to enable Tcl configuration files to define outputs for one or several FTDI GPIO. These outputs can then be -controlled using the @command{ftdi_set_signal} command. Special signal names +controlled using the @command{ftdi set_signal} command. Special signal names are reserved for nTRST, nSRST and LED (for blink) so that they, if defined, will be used for their customary purpose. Inputs can be read using the -@command{ftdi_get_signal} command. +@command{ftdi get_signal} command. To support SWD, a signal named SWD_EN must be defined. It is set to 1 when the SWD protocol is selected. When set, the adapter should route the SWDIO pin to @@ -2490,48 +2644,26 @@ signal. The following output buffer configurations are supported: These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -@deffn {Config Command} {ftdi_vid_pid} [vid pid]+ +@deffn {Config Command} {ftdi vid_pid} [vid pid]+ The vendor ID and product ID of the adapter. Up to eight [@var{vid}, @var{pid}] pairs may be given, e.g. @example -ftdi_vid_pid 0x0403 0xcff8 0x15ba 0x0003 +ftdi vid_pid 0x0403 0xcff8 0x15ba 0x0003 @end example @end deffn -@deffn {Config Command} {ftdi_device_desc} description +@deffn {Config Command} {ftdi device_desc} description Provides the USB device description (the @emph{iProduct string}) of the adapter. If not specified, the device description is ignored during device selection. @end deffn -@deffn {Config Command} {ftdi_serial} serial-number -Specifies the @var{serial-number} of the adapter to use, -in case the vendor provides unique IDs and more than one adapter -is connected to the host. -If not specified, serial numbers are not considered. -(Note that USB serial numbers can be arbitrary Unicode strings, -and are not restricted to containing only decimal digits.) -@end deffn - -@deffn {Config Command} {ftdi_location} <bus>-<port>[.<port>]... -@emph{DEPRECATED -- avoid using this. -Use the command @ref{adapter_usb_location,,adapter usb location} instead.} - -Specifies the physical USB port of the adapter to use. The path -roots at @var{bus} and walks down the physical ports, with each -@var{port} option specifying a deeper level in the bus topology, the last -@var{port} denoting where the target adapter is actually plugged. -The USB bus topology can be queried with the command @emph{lsusb -t}. - -This command is only available if your libusb1 is at least version 1.0.16. -@end deffn - -@deffn {Config Command} {ftdi_channel} channel +@deffn {Config Command} {ftdi channel} channel Selects the channel of the FTDI device to use for MPSSE operations. Most adapters use the default, channel 0, but there are exceptions. @end deffn -@deffn {Config Command} {ftdi_layout_init} data direction +@deffn {Config Command} {ftdi layout_init} data direction Specifies the initial values of the FTDI GPIO data and direction registers. Each value is a 16-bit number corresponding to the concatenation of the high and low FTDI GPIO registers. The values should be selected based on the @@ -2540,7 +2672,7 @@ minimal impact on the target system. Avoid floating inputs, conflicting outputs and initially asserted reset signals. @end deffn -@deffn {Config Command} {ftdi_layout_signal} name [@option{-data}|@option{-ndata} data_mask] [@option{-input}|@option{-ninput} input_mask] [@option{-oe}|@option{-noe} oe_mask] [@option{-alias}|@option{-nalias} name] +@deffn {Command} {ftdi layout_signal} name [@option{-data}|@option{-ndata} data_mask] [@option{-input}|@option{-ninput} input_mask] [@option{-oe}|@option{-noe} oe_mask] [@option{-alias}|@option{-nalias} name] Creates a signal with the specified @var{name}, controlled by one or more FTDI GPIO pins via a range of possible buffer connections. The masks are FTDI GPIO register bitmasks to tell the driver the connection and type of the output @@ -2550,7 +2682,7 @@ used with inverting data inputs and @option{-data} with non-inverting inputs. The @option{-oe} (or @option{-noe}) option tells where the output-enable (or not-output-enable) input to the output buffer is connected. The options @option{-input} and @option{-ninput} specify the bitmask for pins to be read -with the method @command{ftdi_get_signal}. +with the method @command{ftdi get_signal}. Both @var{data_mask} and @var{oe_mask} need not be specified. For example, a simple open-collector transistor driver would be specified with @option{-oe} @@ -2571,7 +2703,7 @@ identical (or with data inverted) to an already specified signal @var{name}. @end deffn -@deffn {Command} {ftdi_set_signal} name @option{0}|@option{1}|@option{z} +@deffn {Command} {ftdi set_signal} name @option{0}|@option{1}|@option{z} Set a previously defined signal to the specified level. @itemize @minus @item @option{0}, drive low @@ -2580,11 +2712,11 @@ Set a previously defined signal to the specified level. @end itemize @end deffn -@deffn {Command} {ftdi_get_signal} name +@deffn {Command} {ftdi get_signal} name Get the value of a previously defined signal. @end deffn -@deffn {Command} {ftdi_tdo_sample_edge} @option{rising}|@option{falling} +@deffn {Command} {ftdi tdo_sample_edge} @option{rising}|@option{falling} Configure TCK edge at which the adapter samples the value of the TDO signal Due to signal propagation delays, sampling TDO on rising TCK can become quite @@ -2641,47 +2773,41 @@ FT232R These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -@deffn {Config Command} {ft232r_vid_pid} @var{vid} @var{pid} +@deffn {Config Command} {ft232r vid_pid} @var{vid} @var{pid} The vendor ID and product ID of the adapter. If not specified, default 0x0403:0x6001 is used. @end deffn -@deffn {Config Command} {ft232r_serial_desc} @var{serial} -Specifies the @var{serial} of the adapter to use, in case the -vendor provides unique IDs and more than one adapter is connected to -the host. If not specified, serial numbers are not considered. -@end deffn - -@deffn {Config Command} {ft232r_jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo} +@deffn {Config Command} {ft232r jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo} Set four JTAG GPIO numbers at once. If not specified, default 0 3 1 2 or TXD CTS RXD RTS is used. @end deffn -@deffn {Config Command} {ft232r_tck_num} @var{tck} +@deffn {Config Command} {ft232r tck_num} @var{tck} Set TCK GPIO number. If not specified, default 0 or TXD is used. @end deffn -@deffn {Config Command} {ft232r_tms_num} @var{tms} +@deffn {Config Command} {ft232r tms_num} @var{tms} Set TMS GPIO number. If not specified, default 3 or CTS is used. @end deffn -@deffn {Config Command} {ft232r_tdi_num} @var{tdi} +@deffn {Config Command} {ft232r tdi_num} @var{tdi} Set TDI GPIO number. If not specified, default 1 or RXD is used. @end deffn -@deffn {Config Command} {ft232r_tdo_num} @var{tdo} +@deffn {Config Command} {ft232r tdo_num} @var{tdo} Set TDO GPIO number. If not specified, default 2 or RTS is used. @end deffn -@deffn {Config Command} {ft232r_trst_num} @var{trst} +@deffn {Config Command} {ft232r trst_num} @var{trst} Set TRST GPIO number. If not specified, default 4 or DTR is used. @end deffn -@deffn {Config Command} {ft232r_srst_num} @var{srst} +@deffn {Config Command} {ft232r srst_num} @var{srst} Set SRST GPIO number. If not specified, default 6 or DCD is used. @end deffn -@deffn {Config Command} {ft232r_restore_serial} @var{word} +@deffn {Config Command} {ft232r restore_serial} @var{word} Restore serial port after JTAG. This USB bitmode control word (16-bit) will be sent before quit. Lower byte should set GPIO direction register to a "sane" state: @@ -2696,21 +2822,30 @@ 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. -@deffn {Config Command} {remote_bitbang_port} number +@deffn {Config Command} {remote_bitbang port} number Specifies the TCP port of the remote process to connect to or 0 to use UNIX sockets instead of TCP. @end deffn -@deffn {Config Command} {remote_bitbang_host} hostname +@deffn {Config Command} {remote_bitbang host} hostname 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. +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 @@ -2718,8 +2853,17 @@ something like: @example adapter driver remote_bitbang -remote_bitbang_port 3335 -remote_bitbang_host foobar +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 @@ -2727,8 +2871,8 @@ named mysocket: @example adapter driver remote_bitbang -remote_bitbang_port 0 -remote_bitbang_host mysocket +remote_bitbang port 0 +remote_bitbang host mysocket @end example @end deffn @@ -2737,28 +2881,21 @@ USB JTAG/USB-Blaster compatibles over one of the userspace libraries for FTDI chips. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -@deffn {Config Command} {usb_blaster_device_desc} description -Provides the USB device description (the @emph{iProduct string}) -of the FTDI FT245 device. If not -specified, the FTDI default value is used. This setting is only valid -if compiled with FTD2XX support. -@end deffn - -@deffn {Config Command} {usb_blaster_vid_pid} vid pid +@deffn {Config Command} {usb_blaster vid_pid} vid pid The vendor ID and product ID of the FTDI FT245 device. If not specified, default values are used. Currently, only one @var{vid}, @var{pid} pair may be given, e.g. for Altera USB-Blaster (default): @example -usb_blaster_vid_pid 0x09FB 0x6001 +usb_blaster vid_pid 0x09FB 0x6001 @end example The following VID/PID is for Kolja Waschk's USB JTAG: @example -usb_blaster_vid_pid 0x16C0 0x06AD +usb_blaster vid_pid 0x16C0 0x06AD @end example @end deffn -@deffn {Command} {usb_blaster_pin} (@option{pin6}|@option{pin8}) (@option{0}|@option{1}|@option{s}|@option{t}) +@deffn {Command} {usb_blaster pin} (@option{pin6}|@option{pin8}) (@option{0}|@option{1}|@option{s}|@option{t}) Sets the state or function of the unused GPIO pins on USB-Blasters (pins 6 and 8 on the female JTAG header). These pins can be used as SRST and/or TRST provided the appropriate connections are made on the @@ -2766,18 +2903,18 @@ target board. For example, to use pin 6 as SRST: @example -usb_blaster_pin pin6 s +usb_blaster pin pin6 s reset_config srst_only @end example @end deffn -@deffn {Command} {usb_blaster_lowlevel_driver} (@option{ftdi}|@option{ublast2}) +@deffn {Config Command} {usb_blaster lowlevel_driver} (@option{ftdi}|@option{ublast2}) Chooses the low level access method for the adapter. If not specified, @option{ftdi} is selected unless it wasn't enabled during the configure stage. USB-Blaster II needs @option{ublast2}. @end deffn -@deffn {Command} {usb_blaster_firmware} @var{path} +@deffn {Config Command} {usb_blaster firmware} @var{path} This command specifies @var{path} to access USB-Blaster II firmware image. To be used with USB-Blaster II only. @end deffn @@ -2788,7 +2925,7 @@ image. To be used with USB-Blaster II only. Gateworks GW16012 JTAG programmer. This has one driver-specific command: -@deffn {Config Command} {parport_port} [port_number] +@deffn {Config Command} {parport port} [port_number] Display either the address of the I/O port (default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. If a parameter is provided, first switch to use that port. @@ -2849,7 +2986,7 @@ Reset the current configuration. @deffn {Command} {jlink config write} Write the current configuration to the internal persistent storage. @end deffn -@deffn {Command} {jlink emucom write <channel> <data>} +@deffn {Command} {jlink emucom write} <channel> <data> Write data to an EMUCOM channel. The data needs to be encoded as hexadecimal pairs. @@ -2859,7 +2996,7 @@ the EMUCOM channel 0x10: > jlink emucom write 0x10 aa0b23 @end example @end deffn -@deffn {Command} {jlink emucom read <channel> <length>} +@deffn {Command} {jlink emucom read} <channel> <length> Read data from an EMUCOM channel. The read data is encoded as hexadecimal pairs. @@ -2869,17 +3006,11 @@ The following example shows how to read 4 bytes from the EMUCOM channel 0x0: 77a90000 @end example @end deffn -@deffn {Config} {jlink usb} <@option{0} to @option{3}> +@deffn {Config Command} {jlink usb} <@option{0} to @option{3}> Set the USB address of the interface, in case more than one adapter is connected to the host. If not specified, USB addresses are not considered. Device -selection via USB address is deprecated and the serial number should be used -instead. - -As a configuration command, it can be used only before 'init'. -@end deffn -@deffn {Config} {jlink serial} <serial number> -Set the serial number of the interface, in case more than one adapter is -connected to the host. If not specified, serial numbers are not considered. +selection via USB address is not always unambiguous. It is recommended to use +the serial number instead, if possible. As a configuration command, it can be used only before 'init'. @end deffn @@ -2890,7 +3021,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 @@ -2911,23 +3042,18 @@ 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 -@deffn {Config Command} {kitprog_serial} serial -Select a KitProg device by its @var{serial}. If left unspecified, the first -device detected by OpenOCD will be used. -@end deffn - @deffn {Command} {kitprog acquire_psoc} Run a PSoC acquisition sequence immediately. Typically, this should not be used outside of the target-specific configuration scripts since it hard-resets the @@ -2947,7 +3073,7 @@ Wigglers, PLD download cable, and more. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -@deffn {Config Command} {parport_cable} name +@deffn {Config Command} {parport cable} name Set the layout of the parallel port cable used to connect to the target. This is a write-once setting. Currently valid cable @var{name} values include: @@ -2977,18 +3103,18 @@ several clones, such as the Olimex ARM-JTAG @end itemize @end deffn -@deffn {Config Command} {parport_port} [port_number] +@deffn {Config Command} {parport port} [port_number] Display either the address of the I/O port (default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. If a parameter is provided, first switch to use that port. This is a write-once setting. When using PPDEV to access the parallel port, use the number of the parallel port: -@option{parport_port 0} (the default). If @option{parport_port 0x378} is specified +@option{parport port 0} (the default). If @option{parport port 0x378} is specified you may encounter a problem. @end deffn -@deffn Command {parport_toggling_time} [nanoseconds] +@deffn {Config Command} {parport toggling_time} [nanoseconds] Displays how many nanoseconds the hardware needs to toggle TCK; the parport driver uses this value to obey the @command{adapter speed} configuration. @@ -3001,7 +3127,7 @@ However, you may want to calibrate for your specific hardware. To measure the toggling time with a logic analyzer or a digital storage oscilloscope, follow the procedure below: @example -> parport_toggling_time 1000 +> parport toggling_time 1000 > adapter speed 500 @end example This sets the maximum JTAG clock speed of the hardware, but @@ -3011,7 +3137,7 @@ You can use @command{runtest 1000} or something similar to generate a large set of samples. Update the setting to match your measurement: @example -> parport_toggling_time <measured nanoseconds> +> parport toggling_time <measured nanoseconds> @end example Now the clock speed will be a better match for @command{adapter speed} command given in OpenOCD scripts and event handlers. @@ -3025,7 +3151,7 @@ be conservative. @end quotation @end deffn -@deffn {Config Command} {parport_write_on_exit} (@option{on}|@option{off}) +@deffn {Config Command} {parport write_on_exit} (@option{on}|@option{off}) This will configure the parallel driver to write a known cable-specific value to the parallel interface on exiting OpenOCD. @end deffn @@ -3035,16 +3161,13 @@ classic ``Wiggler'' cable on LPT2 might look something like this: @example adapter driver parport -parport_port 0x278 -parport_cable wiggler +parport port 0x278 +parport cable wiggler @end example @end deffn @deffn {Interface Driver} {presto} ASIX PRESTO USB JTAG programmer. -@deffn {Config Command} {presto_serial} serial_string -Configures the USB serial number of the Presto device to use. -@end deffn @end deffn @deffn {Interface Driver} {rlink} @@ -3081,10 +3204,6 @@ version reported is V2.J21.S4. Currently Not Supported. @end deffn -@deffn {Config Command} {hla_serial} serial -Specifies the serial number of the adapter. -@end deffn - @deffn {Config Command} {hla_layout} (@option{stlink}|@option{icdi}|@option{nulink}) Specifies the adapter layout to use. @end deffn @@ -3093,6 +3212,15 @@ Specifies the adapter layout to use. Pairs of vendor IDs and product IDs of the device. @end deffn +@deffn {Config Command} {hla_stlink_backend} (usb | tcp [port]) +@emph{ST-Link only:} Choose between 'exclusive' USB communication (the default backend) or +'shared' mode using ST-Link TCP server (the default port is 7184). + +@emph{Note:} ST-Link TCP server is a binary application provided by ST +available from @url{https://www.st.com/en/development-tools/st-link-server.html, +ST-LINK server software module}. +@end deffn + @deffn {Command} {hla_command} command Execute a custom adapter-specific command. The @var{command} string is passed as is to the underlying adapter layout handler. @@ -3102,7 +3230,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 @@ -3113,13 +3241,42 @@ An error is returned for any AP number above the maximum allowed value. @emph{Note:} Either these same adapters and their older versions are also supported by @ref{hla_interface, the hla interface driver}. -@deffn {Config Command} {st-link serial} serial -Specifies the serial number of the adapter. +@deffn {Config Command} {st-link backend} (usb | tcp [port]) +Choose between 'exclusive' USB communication (the default backend) or +'shared' mode using ST-Link TCP server (the default port is 7184). + +@emph{Note:} ST-Link TCP server is a binary application provided by ST +available from @url{https://www.st.com/en/development-tools/st-link-server.html, +ST-LINK server software module}. + +@emph{Note:} ST-Link TCP server does not support the SWIM transport. @end deffn @deffn {Config Command} {st-link vid_pid} [vid pid]+ Pairs of vendor IDs and product IDs of the device. @end deffn + +@deffn {Command} {st-link cmd} rx_n (tx_byte)+ +Sends an arbitrary command composed by the sequence of bytes @var{tx_byte} +and receives @var{rx_n} bytes. + +For example, the command to read the target's supply voltage is one byte 0xf7 followed +by 15 bytes zero. It returns 8 bytes, where the first 4 bytes represent the ADC sampling +of the reference voltage 1.2V and the last 4 bytes represent the ADC sampling of half +the target's supply voltage. +@example +> st-link cmd 8 0xf7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0xf1 0x05 0x00 0x00 0x0b 0x08 0x00 0x00 +@end example +The result can be converted to Volts (ignoring the most significant bytes, always zero) +@example +> set a [st-link cmd 8 0xf7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +> set n [expr @{[lindex $a 4] + 256 * [lindex $a 5]@}] +> set d [expr @{[lindex $a 0] + 256 * [lindex $a 1]@}] +> echo [expr @{2 * 1.2 * $n / $d@}] +3.24891518738 +@end example +@end deffn @end deffn @deffn {Interface Driver} {opendous} @@ -3136,11 +3293,6 @@ LaunchPad evaluation boards. The XDS110 is also available as a stand-alone USB debug probe with the added capability to supply power to the target board. The following commands are supported by the XDS110 driver: -@deffn {Config Command} {xds110 serial} serial_string -Specifies the serial number of which XDS110 probe to use. Otherwise, the first -XDS110 found will be used. -@end deffn - @deffn {Config Command} {xds110 supply} voltage_in_millivolts Available only on the XDS110 stand-alone probe. Sets the voltage level of the XDS110 power supply. A value of 0 leaves the supply off. Otherwise, the supply @@ -3161,7 +3313,7 @@ exposed via extended capability registers in the PCI Express configuration space For more information see Xilinx PG245 (Section on From_PCIE_to_JTAG mode). -@deffn {Config Command} {xlnx_pcie_xvc_config} device +@deffn {Config Command} {xlnx_pcie_xvc config} device Specifies the PCI Express device via parameter @var{device} to use. The correct value for @var{device} can be obtained by looking at the output @@ -3172,20 +3324,6 @@ The string will be of the format "DDDD:BB:SS.F" such as "0000:65:00.1". @end deffn @end deffn -@deffn {Interface Driver} {ZY1000} -This is the Zylin ZY1000 JTAG debugger. -@end deffn - -@quotation Note -This defines some driver-specific commands, -which are not currently documented here. -@end quotation - -@deffn Command power [@option{on}|@option{off}] -Turn power switch to target on/off. -No arguments: print status. -@end deffn - @deffn {Interface Driver} {bcm2835gpio} This SoC is present in Raspberry Pi which is a cheap single-board computer exposing some GPIOs on its expansion header. @@ -3197,8 +3335,40 @@ 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 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. +@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. +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}. +@end deffn @end deffn @@ -3214,11 +3384,53 @@ 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 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 configuration file. +@end deffn + + +@deffn {Interface Driver} {sysfsgpio} +Linux legacy userspace access to GPIO through sysfs is deprecated from Linux kernel version v5.3. +Prefer using @b{linuxgpiod}, instead. + +See @file{interface/sysfsgpio-raspberrypi.cfg} for a sample config. +@end deffn + + @deffn {Interface Driver} {openjtag} OpenJTAG compatible USB adapter. This defines some driver-specific commands: -@deffn {Config Command} {openjtag_variant} variant +@deffn {Config Command} {openjtag variant} variant Specifies the variant of the OpenJTAG adapter (see @uref{http://www.openjtag.org/}). Currently valid @var{variant} values include: @@ -3229,10 +3441,243 @@ Currently valid @var{variant} values include: @end itemize @end deffn -@deffn {Config Command} {openjtag_device_desc} string +@deffn {Config Command} {openjtag device_desc} string 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 + + +@deffn {Interface Driver} {vdebug} +Cadence Virtual Debug Interface driver. + +@deffn {Config Command} {vdebug server} host:port +Specifies the host and TCP port number where the vdebug server runs. +@end deffn + +@deffn {Config Command} {vdebug batching} value +Specifies the batching method for the vdebug request. Possible values are +0 for no batching +1 or wr to batch write transactions together (default) +2 or rw to batch both read and write transactions +@end deffn + +@deffn {Config Command} {vdebug polling} min max +Takes two values, representing the polling interval in ms. Lower values mean faster +debugger responsiveness, but lower emulation performance. The minimum should be +around 10, maximum should not exceed 1000, which is the default gdb and keepalive +timeout value. +@end deffn + +@deffn {Config Command} {vdebug bfm_path} path clk_period +Specifies the hierarchical path and input clk period of the vdebug BFM in the design. +The hierarchical path uses Verilog notation top.inst.inst +The clock period must include the unit, for instance 40ns. +@end deffn + +@deffn {Config Command} {vdebug mem_path} path base size +Specifies the hierarchical path to the design memory instance for backdoor access. +Up to 4 memories can be specified. The hierarchical path uses Verilog notation. +The base specifies start address in the design address space, size its size in bytes. +Both values can use hexadecimal notation with prefix 0x. +@end deffn +@end deffn + +@deffn {Interface Driver} {jtag_dpi} +SystemVerilog Direct Programming Interface (DPI) compatible driver for +JTAG devices in emulation. The driver acts as a client for the SystemVerilog +DPI server interface. + +@deffn {Config Command} {jtag_dpi set_port} port +Specifies the TCP/IP port number of the SystemVerilog DPI server interface. +@end deffn + +@deffn {Config Command} {jtag_dpi set_address} address +Specifies the TCP/IP address of the SystemVerilog DPI server interface. +@end deffn +@end deffn + + +@deffn {Interface Driver} {buspirate} + +This driver is for the Bus Pirate (see @url{http://dangerousprototypes.com/docs/Bus_Pirate}) and compatible devices. +It uses a simple data protocol over a serial port connection. + +Most hardware development boards have a UART, a real serial port, or a virtual USB serial device, so this driver +allows you to start building your own JTAG adapter without the complexity of a custom USB connection. + +@deffn {Config Command} {buspirate port} serial_port +Specify the serial port's filename. For example: +@example +buspirate port /dev/ttyUSB0 +@end example +@end deffn + +@deffn {Config Command} {buspirate speed} (normal|fast) +Set the communication speed to 115k (normal) or 1M (fast). For example: +@example +buspirate speed normal +@end example +@end deffn + +@deffn {Config Command} {buspirate mode} (normal|open-drain) +Set the Bus Pirate output mode. +@itemize @minus +@item In normal mode (push/pull), do not enable the pull-ups, and do not connect I/O header pin VPU to JTAG VREF. +@item In open drain mode, you will then need to enable the pull-ups. +@end itemize +For example: +@example +buspirate mode normal +@end example +@end deffn + +@deffn {Config Command} {buspirate pullup} (0|1) +Whether to connect (1) or not (0) the I/O header pin VPU (JTAG VREF) +to the pull-up/pull-down resistors on MOSI (JTAG TDI), CLK (JTAG TCK), MISO (JTAG TDO) and CS (JTAG TMS). +For example: +@example +buspirate pullup 0 +@end example +@end deffn + +@deffn {Config Command} {buspirate vreg} (0|1) +Whether to enable (1) or disable (0) the built-in voltage regulator, +which can be used to supply power to a test circuit through +I/O header pins +3V3 and +5V. For example: +@example +buspirate vreg 0 +@end example +@end deffn + +@deffn {Command} {buspirate led} (0|1) +Turns the Bus Pirate's LED on (1) or off (0). For example: +@end deffn +@example +buspirate led 1 +@end example + +@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 @@ -3241,12 +3686,12 @@ As noted earlier, depending on the version of OpenOCD you use, and the debug adapter you are using, several transports may be available to communicate with debug targets (or perhaps to program flash memory). -@deffn Command {transport list} +@deffn {Command} {transport list} displays the names of the transports supported by this version of OpenOCD. @end deffn -@deffn Command {transport select} @option{transport_name} +@deffn {Command} {transport select} @option{transport_name} Select which of the supported transports to use in this OpenOCD session. When invoked with @option{transport_name}, attempts to select the named @@ -3293,16 +3738,22 @@ driver} (in which case the command is @command{transport select hla_swd}) or @ref{st_link_dap_interface,the st-link interface driver} (in which case the command is @command{transport select dapdirect_swd}). -@deffn Command {swd newdap} ... +@deffn {Config Command} {swd newdap} ... Declares a single DAP which uses SWD transport. Parameters are currently the same as "jtag newtap" but this is expected to change. @end deffn -@deffn Command {swd wcr trn prescale} -Updates TRN (turnaround delay) and prescaling.fields of the -Wire Control Register (WCR). -No parameters: displays current settings. -@end deffn + +@cindex SWD multi-drop +The newer SWD devices (SW-DP v2 or SWJ-DP v2) support the multi-drop extension +of SWD protocol: two or more devices can be connected to one SWD adapter. +SWD transport works in multi-drop mode if @ref{dap_create,DAP} is configured +with both @code{-dp-id} and @code{-instance-id} parameters regardless how many +DAPs are created. + +Not all adapters and adapter drivers support SWD multi-drop. Only the following +adapter drivers are SWD multi-drop capable: +cmsis_dap (use an adapter with CMSIS-DAP version 2.0), ftdi, all bitbang based. @subsection SPI Transport @cindex SPI @@ -3373,7 +3824,7 @@ may not be the fastest solution. instead of @command{adapter speed}, but only for (ARM) cores and boards which support adaptive clocking. -@deffn {Command} adapter speed max_speed_kHz +@deffn {Command} {adapter speed} max_speed_kHz A non-zero speed is in KHZ. Hence: 3000 is 3mhz. JTAG interfaces usually support a limited number of speeds. The speed actually used won't be faster @@ -3543,32 +3994,32 @@ needing to cope with both architecture and board specific constraints. @section Commands for Handling Resets -@deffn {Command} adapter srst pulse_width milliseconds +@deffn {Command} {adapter srst pulse_width} milliseconds Minimum amount of time (in milliseconds) OpenOCD should wait after asserting nSRST (active-low system reset) before allowing it to be deasserted. @end deffn -@deffn {Command} adapter srst delay milliseconds +@deffn {Command} {adapter srst delay} milliseconds How long (in milliseconds) OpenOCD should wait after deasserting nSRST (active-low system reset) before starting new JTAG operations. When a board has a reset button connected to SRST line it will probably have hardware debouncing, implying you should use this. @end deffn -@deffn {Command} jtag_ntrst_assert_width milliseconds +@deffn {Command} {jtag_ntrst_assert_width} milliseconds Minimum amount of time (in milliseconds) OpenOCD should wait after asserting nTRST (active-low JTAG TAP reset) before allowing it to be deasserted. @end deffn -@deffn {Command} jtag_ntrst_delay milliseconds +@deffn {Command} {jtag_ntrst_delay} milliseconds How long (in milliseconds) OpenOCD should wait after deasserting nTRST (active-low JTAG TAP reset) before starting new JTAG operations. @end deffn @anchor{reset_config} -@deffn {Command} reset_config mode_flag ... +@deffn {Command} {reset_config} mode_flag ... This command displays or modifies the reset configuration of your combination of JTAG board and target in target configuration scripts. @@ -3703,7 +4154,7 @@ schemes. For example, on a multi-target board the standard may need the ability to reset only one target at time and thus want to avoid using the board-wide SRST signal. -@deffn {Overridable Procedure} init_reset mode +@deffn {Overridable Procedure} {init_reset} mode This is invoked near the beginning of the @command{reset} command, usually to provide as much of a cold (power-up) reset as practical. By default it is also invoked from @command{jtag_init} if @@ -3726,7 +4177,7 @@ This is done by calling @command{jtag arp_init} (or @command{jtag arp_init-reset}). @end deffn -@deffn Command {jtag arp_init} +@deffn {Command} {jtag arp_init} This validates the scan chain using just the four standard JTAG signals (TMS, TCK, TDI, TDO). It starts by issuing a JTAG-only reset. @@ -3739,7 +4190,7 @@ If these tests all pass, TAP @code{setup} events are issued to all TAPs with handlers for that event. @end deffn -@deffn Command {jtag arp_init-reset} +@deffn {Command} {jtag arp_init-reset} This uses TRST and SRST to try resetting everything on the JTAG scan chain (and anything else connected to SRST). @@ -3847,7 +4298,7 @@ Actual config files typically use a variable such as @code{$_CHIPNAME} instead of literals like @option{str912}, to support more than one chip of each type. @xref{Config File Guidelines}. -@deffn Command {jtag names} +@deffn {Command} {jtag names} Returns the names of all current TAPs in the scan chain. Use @command{jtag cget} or @command{jtag tapisenabled} to examine attributes and state of each TAP. @@ -3858,7 +4309,7 @@ foreach t [jtag names] @{ @end example @end deffn -@deffn Command {scan_chain} +@deffn {Command} {scan_chain} Displays the TAPs in the scan chain configuration, and their status. The set of TAPs listed by this command is fixed by @@ -3891,8 +4342,7 @@ and underscores are OK; while others (including dots!) are not. @section TAP Declaration Commands -@c shouldn't this be(come) a {Config Command}? -@deffn Command {jtag newtap} chipname tapname configparams... +@deffn {Config Command} {jtag newtap} chipname tapname configparams... Declares a new TAP with the dotted name @var{chipname}.@var{tapname}, and configured according to the various @var{configparams}. @@ -3961,6 +4411,10 @@ option. When vendors put out multiple versions of a chip, or use the same JTAG-level ID for several largely-compatible chips, it may be more practical to ignore the version field than to update config files to handle all of the various chip IDs. The version field is defined as bit 28-31 of the IDCODE. +@item @code{-ignore-bypass} +@*Specify this to ignore the 'bypass' bit of the idcode. Some vendor put +an invalid idcode regarding this bit. Specify this to ignore this bit and +to not consider this tap in bypass mode. @item @code{-ircapture} @var{NUMBER} @*The bit pattern loaded by the TAP into the JTAG shift register on entry to the @sc{ircapture} state, such as 0x01. @@ -3979,17 +4433,21 @@ 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 @section Other TAP commands -@deffn Command {jtag cget} dotted.name @option{-idcode} +@deffn {Command} {jtag cget} dotted.name @option{-idcode} Get the value of the IDCODE found in hardware. @end deffn -@deffn Command {jtag cget} dotted.name @option{-event} event_name -@deffnx Command {jtag configure} dotted.name @option{-event} event_name handler +@deffn {Command} {jtag cget} dotted.name @option{-event} event_name +@deffnx {Command} {jtag configure} dotted.name @option{-event} event_name handler At this writing this TAP attribute mechanism is limited and used mostly for event handling. (It is not a direct analogue of the @code{cget}/@code{configure} @@ -4110,7 +4568,7 @@ uses quotes to evaluate @code{$CHIP} when the event is configured. Using brackets @{ @} would cause it to be evaluated later, at runtime, when it might have a different value. -@deffn Command {jtag tapdisable} dotted.name +@deffn {Command} {jtag tapdisable} dotted.name If necessary, disables the tap by sending it a @option{tap-disable} event. Returns the string "1" if the tap @@ -4118,7 +4576,7 @@ specified by @var{dotted.name} is enabled, and "0" if it is disabled. @end deffn -@deffn Command {jtag tapenable} dotted.name +@deffn {Command} {jtag tapenable} dotted.name If necessary, enables the tap by sending it a @option{tap-enable} event. Returns the string "1" if the tap @@ -4126,7 +4584,7 @@ specified by @var{dotted.name} is enabled, and "0" if it is disabled. @end deffn -@deffn Command {jtag tapisenabled} dotted.name +@deffn {Command} {jtag tapisenabled} dotted.name Returns the string "1" if the tap specified by @var{dotted.name} is enabled, and "0" if it is disabled. @@ -4218,7 +4676,8 @@ instead of "@option{-chain-position} @var{dotted.name}" when the target is creat The @command{dap} command group supports the following sub-commands: -@deffn Command {dap create} dap_name @option{-chain-position} dotted.name configparams... +@anchor{dap_create} +@deffn {Command} {dap create} dap_name @option{-chain-position} dotted.name configparams... Declare a DAP instance named @var{dap_name} linked to the JTAG tap @var{dotted.name}. This also creates a new command (@command{dap_name}) which is used for various purposes including additional configuration. @@ -4227,25 +4686,46 @@ 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. + +@item @code{-dp-id} @var{number} +@*Debug port identification number for SWD DPv2 multidrop. +The @var{number} is written to bits 0..27 of DP TARGETSEL during DP selection. +To find the id number of a single connected device read DP TARGETID: +@code{device.dap dpreg 0x24} +Use bits 0..27 of TARGETID. + +@item @code{-instance-id} @var{number} +@*Instance identification number for SWD DPv2 multidrop. +The @var{number} is written to bits 28..31 of DP TARGETSEL during DP selection. +To find the instance number of a single connected device read DP DLPIDR: +@code{device.dap dpreg 0x34} +The instance number is in bits 28..31 of DLPIDR value. @end itemize @end deffn -@deffn Command {dap names} +@deffn {Command} {dap names} 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} +@deffn {Command} {dap init} Initialize all registered DAPs. This command is used internally during initialization. It can be issued at any time after the initialization, too. @@ -4253,27 +4733,36 @@ 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] +@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] +@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] +@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] +@deffn {Command} {$dap_name dpreg} reg [value] Displays the content of DP register at address @var{reg}, or set it to a new value @var{value}. @@ -4285,18 +4774,20 @@ In case of JTAG it only assumes values 0, 4, 8 and 0xc. background activity by OpenOCD while you are operating at such low-level. @end deffn -@deffn Command {$dap_name baseaddr} [num] +@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] +@deffn {Command} {$dap_name memaccess} [value] Displays the number of extra tck cycles in the JTAG idle to use for MEM-AP memory bus access [0-255], giving additional time to respond to reads. If @var{value} is defined, first assigns that. @end deffn -@deffn Command {$dap_name apcsw} [value [mask]] +@deffn {Command} {$dap_name apcsw} [value [mask]] Displays or changes CSW bit pattern for MEM-AP transfers. At the begin of each memory access the CSW pattern is extended (bitwise or-ed) @@ -4318,13 +4809,13 @@ where the mask bit is 1. The following example sets HPROT3 (cacheable) and leaves the rest of the pattern intact. It configures memory access through DCache on Cortex-M7. @example -set CSW_HPROT3_CACHEABLE [expr 1 << 27] +set CSW_HPROT3_CACHEABLE [expr @{1 << 27@}] samv.dap apcsw $CSW_HPROT3_CACHEABLE $CSW_HPROT3_CACHEABLE @end example Another example clears SPROT bit and leaves the rest of pattern intact: @example -set CSW_SPROT [expr 1 << 30] +set CSW_SPROT [expr @{1 << 30@}] samv.dap apcsw 0 $CSW_SPROT @end example @@ -4339,11 +4830,15 @@ xxx.dap apcsw default @end example @end deffn -@deffn Command {$dap_name ti_be_32_quirks} [@option{enable}] +@deffn {Config Command} {$dap_name ti_be_32_quirks} [@option{enable}] 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 @@ -4388,11 +4883,11 @@ are examples; and there are many more. Several commands let you examine the list of targets: -@deffn Command {target current} +@deffn {Command} {target current} Returns the name of the current target. @end deffn -@deffn Command {target names} +@deffn {Command} {target names} Lists the names of all current targets in the list. @example foreach t [target names] @{ @@ -4404,7 +4899,7 @@ foreach t [target names] @{ @c yep, "target list" would have been better. @c plus maybe "target setdefault". -@deffn Command targets [name] +@deffn {Command} {targets} [name] @emph{Note: the name of this command is plural. Other target command names are singular.} @@ -4435,7 +4930,7 @@ It's easy to see what target types are supported, since there's a command to list them. @anchor{targettypes} -@deffn Command {target types} +@deffn {Command} {target types} Lists all supported target types. At this writing, the supported CPU types are: @@ -4462,17 +4957,23 @@ 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{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. @item @code{ls1_sap} -- this is the SAP on NXP LS102x CPUs, allowing access to physical memory addresses independently of CPU cores. -@item @code{mem_ap} -- this is an ARM debug infrastructure Access Port without a CPU, through which bus read and write cycles can be generated; it may be useful for working with non-CPU hardware behind an AP or during development of support for new CPUs. +@item @code{mem_ap} -- this is an ARM debug infrastructure Access Port without +a CPU, through which bus read and write cycles can be generated; it may be +useful for working with non-CPU hardware behind an AP or during development of +support for new CPUs. +It's possible to connect a GDB client to this target (the GDB port has to be +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. -@item @code{nds32_v3} -- this is an Andes NDS32 v3 core. -@item @code{nds32_v3m} -- this is an Andes NDS32 v3m core. @item @code{or1k} -- this is an OpenRISC 1000 core. The current implementation supports three JTAG TAP cores: @itemize @minus @@ -4482,8 +4983,10 @@ The current implementation supports three JTAG TAP cores: @end itemize And two debug interfaces cores: @itemize @minus -@item @code{Advanced debug interface} (See: @url{http://opencores.org/project@comma{}adv_debug_sys}) -@item @code{SoC Debug Interface} (See: @url{http://opencores.org/project@comma{}dbg_interface}) +@item @code{Advanced debug interface} +@*(See: @url{http://opencores.org/project@comma{}adv_debug_sys}) +@item @code{SoC Debug Interface} +@*(See: @url{http://opencores.org/project@comma{}dbg_interface}) @end itemize @item @code{quark_d20xx} -- an Intel Quark D20xx core. @item @code{quark_x10xx} -- an Intel Quark X10xx core. @@ -4492,6 +4995,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 @@ -4562,7 +5066,7 @@ That may be needed to let you write the boot loader into flash, in order to ``de-brick'' your board; or to load programs into external DDR memory without having run the boot loader. -@deffn Command {target create} target_name type configparams... +@deffn {Config Command} {target create} target_name type configparams... This command creates a GDB debug target that refers to a specific JTAG tap. It enters that target into a list, and creates a new command (@command{@var{target_name}}) which is used for various @@ -4587,7 +5091,7 @@ You @emph{must} set the @code{-chain-position @var{dotted.name}} or @end itemize @end deffn -@deffn Command {$target_name configure} configparams... +@deffn {Command} {$target_name configure} configparams... The options accepted by this command may also be specified as parameters to @command{target create}. Their values can later be queried one at a time by @@ -4642,18 +5146,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{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. @@ -4669,6 +5174,11 @@ possible values of the parameter @var{number}, which are not only numeric values Use this option to override, for this target only, the global parameter set with command @command{gdb_port}. @xref{gdb_port,,command gdb_port}. + +@item @code{-gdb-max-connections} @var{number} -- EXPERIMENTAL: set the maximum +number of GDB connections that are allowed for the target. Default is 1. +A negative value for @var{number} means unlimited connections. +See @xref{gdbmeminspect,,Using GDB as a non-intrusive memory inspector}. @end itemize @end deffn @@ -4705,51 +5215,100 @@ omap3530.cpu mww 0x5555 123 The commands supported by OpenOCD target objects are: -@deffn Command {$target_name arp_examine} @option{allow-defer} -@deffnx Command {$target_name arp_halt} -@deffnx Command {$target_name arp_poll} -@deffnx Command {$target_name arp_reset} -@deffnx Command {$target_name arp_waitstate} +@deffn {Command} {$target_name arp_examine} @option{allow-defer} +@deffnx {Command} {$target_name arp_halt} +@deffnx {Command} {$target_name arp_poll} +@deffnx {Command} {$target_name arp_reset} +@deffnx {Command} {$target_name arp_waitstate} Internal OpenOCD scripts (most notably @file{startup.tcl}) use these to deal with specific reset cases. They are not otherwise documented here. @end deffn -@deffn Command {$target_name array2mem} arrayname width address count -@deffnx Command {$target_name mem2array} arrayname width address count -These provide an efficient script-oriented interface to memory. -The @code{array2mem} primitive writes bytes, halfwords, or words; -while @code{mem2array} reads them. -In both cases, the TCL side uses an array, and -the target side uses raw memory. - -The efficiency comes from enabling the use of -bulk JTAG data transfer operations. -The script orientation comes from working with data -values that are packaged for use by TCL scripts; -@command{mdw} type primitives only print data they retrieve, -and neither store nor return those values. +@deffn {Command} {$target_name set_reg} dict +Set register values of the target. @itemize -@item @var{arrayname} ... is the name of an array variable -@item @var{width} ... is 8/16/32 - indicating the memory access size -@item @var{address} ... is the target memory address -@item @var{count} ... is the number of elements to process +@item @var{dict} ... Tcl dictionary with pairs of register names and values. @end itemize + +For example, the following command sets the value 0 to the program counter (pc) +register and 0x1000 to the stack pointer (sp) register: + +@example +set_reg @{pc 0 sp 0x1000@} +@end example @end deffn -@deffn Command {$target_name cget} queryparm -Each configuration parameter accepted by -@command{$target_name configure} -can be individually queried, to return its current value. -The @var{queryparm} is a parameter name -accepted by that command, such as @code{-work-area-phys}. -There are a few special cases: +@deffn {Command} {$target_name get_reg} [-force] list +Get register values from the target and return them as Tcl dictionary with pairs +of register names and values. +If option "-force" is set, the register values are read directly from the +target, bypassing any caching. -@itemize @bullet -@item @code{-event} @var{event_name} -- returns the handler for the -event named @var{event_name}. -This is a special case because setting a handler requires +@itemize +@item @var{list} ... List of register names +@end itemize + +For example, the following command retrieves the values from the program +counter (pc) and stack pointer (sp) register: + +@example +get_reg @{pc sp@} +@end example +@end deffn + +@deffn {Command} {$target_name write_memory} address width data ['phys'] +This function provides an efficient way to write to the target memory from a Tcl +script. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{data} ... Tcl list with the elements to write +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command writes two 32 bit words into the target +memory at address 0x20000000: + +@example +write_memory 0x20000000 32 @{0xdeadbeef 0x00230500@} +@end example +@end deffn + +@deffn {Command} {$target_name read_memory} address width count ['phys'] +This function provides an efficient way to read the target memory from a Tcl +script. +A Tcl list containing the requested memory elements is returned by this function. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{count} ... number of elements to read +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command reads two 32 bit words from the target +memory at address 0x20000000: + +@example +read_memory 0x20000000 32 2 +@end example +@end deffn + +@deffn {Command} {$target_name cget} queryparm +Each configuration parameter accepted by +@command{$target_name configure} +can be individually queried, to return its current value. +The @var{queryparm} is a parameter name +accepted by that command, such as @code{-work-area-phys}. +There are a few special cases: + +@itemize @bullet +@item @code{-event} @var{event_name} -- returns the handler for the +event named @var{event_name}. +This is a special case because setting a handler requires two parameters. @item @code{-type} -- returns the target type. This is a special case because this is set using @@ -4771,7 +5330,7 @@ foreach name [target names] @{ @end deffn @anchor{targetcurstate} -@deffn Command {$target_name curstate} +@deffn {Command} {$target_name curstate} Displays the current target state: @code{debug-running}, @code{halted}, @@ -4780,22 +5339,34 @@ Displays the current target state: (Also, @pxref{eventpolling,,Event Polling}.) @end deffn -@deffn Command {$target_name eventlist} +@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. @xref{targetevents,,Target Events}. @end deffn -@deffn Command {$target_name invoke-event} event_name +@deffn {Command} {$target_name invoke-event} event_name Invokes the handler for the event named @var{event_name}. (This is primarily intended for use by OpenOCD framework code, for example by the reset code in @file{startup.tcl}.) @end deffn -@deffn Command {$target_name mdd} [phys] addr [count] -@deffnx Command {$target_name mdw} [phys] addr [count] -@deffnx Command {$target_name mdh} [phys] addr [count] -@deffnx Command {$target_name mdb} [phys] addr [count] +@deffn {Command} {$target_name mdd} [phys] addr [count] +@deffnx {Command} {$target_name mdw} [phys] addr [count] +@deffnx {Command} {$target_name mdh} [phys] addr [count] +@deffnx {Command} {$target_name mdb} [phys] addr [count] Display contents of address @var{addr}, as 64-bit doublewords (@command{mdd}), 32-bit words (@command{mdw}), 16-bit halfwords (@command{mdh}), @@ -4805,14 +5376,14 @@ When the current target has an MMU which is present and active, Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. If @var{count} is specified, displays that many units. -(If you want to manipulate the data instead of displaying it, -see the @code{mem2array} primitives.) +(If you want to process the data instead of displaying it, +see the @code{read_memory} primitives.) @end deffn -@deffn Command {$target_name mwd} [phys] addr doubleword [count] -@deffnx Command {$target_name mww} [phys] addr word [count] -@deffnx Command {$target_name mwh} [phys] addr halfword [count] -@deffnx Command {$target_name mwb} [phys] addr byte [count] +@deffn {Command} {$target_name mwd} [phys] addr doubleword [count] +@deffnx {Command} {$target_name mww} [phys] addr word [count] +@deffnx {Command} {$target_name mwh} [phys] addr halfword [count] +@deffnx {Command} {$target_name mwb} [phys] addr byte [count] Writes the specified @var{doubleword} (64 bits), @var{word} (32 bits), @var{halfword} (16 bits), or @var{byte} (8-bit) value, at the specified address @var{addr}. @@ -4961,8 +5532,37 @@ when reset disables PLLs needed to use a fast clock. @* After single-step has completed @item @b{trace-config} @* After target hardware trace configuration was changed +@item @b{semihosting-user-cmd-0x100} +@* The target made a semihosting call with user-defined operation number 0x100 +@item @b{semihosting-user-cmd-0x101} +@* The target made a semihosting call with user-defined operation number 0x101 +@item @b{semihosting-user-cmd-0x102} +@* The target made a semihosting call with user-defined operation number 0x102 +@item @b{semihosting-user-cmd-0x103} +@* The target made a semihosting call with user-defined operation number 0x103 +@item @b{semihosting-user-cmd-0x104} +@* The target made a semihosting call with user-defined operation number 0x104 +@item @b{semihosting-user-cmd-0x105} +@* The target made a semihosting call with user-defined operation number 0x105 +@item @b{semihosting-user-cmd-0x106} +@* The target made a semihosting call with user-defined operation number 0x106 +@item @b{semihosting-user-cmd-0x107} +@* The target made a semihosting call with user-defined operation number 0x107 @end itemize +@quotation Note +OpenOCD events are not supposed to be preempt by another event, but this +is not enforced in current code. Only the target event @b{resumed} is +executed with polling disabled; this avoids polling to trigger the event +@b{halted}, reversing the logical order of execution of their handlers. +Future versions of OpenOCD will prevent the event preemption and will +disable the schedule of polling during the event execution. Do not rely +on polling in any event handler; this means, don't expect the status of +a core to change during the execution of the handler. The event handler +will have to enable polling or use @command{$target_name arp_poll} to +check if the core has changed status. +@end quotation + @node Flash Commands @chapter Flash Commands @@ -5037,20 +5637,20 @@ Use it in board specific configuration files, not interactively. @end deffn @comment less confusing would be: "flash list" (like "nand list") -@deffn Command {flash banks} +@deffn {Command} {flash banks} Prints a one-line summary of each device that was declared using @command{flash bank}, numbered from zero. Note that this is the @emph{plural} form; the @emph{singular} form is a very different command. @end deffn -@deffn Command {flash list} +@deffn {Command} {flash list} Retrieves a list of associative arrays for each device that was declared using @command{flash bank}, numbered from zero. This returned list can be manipulated easily from within scripts. @end deffn -@deffn Command {flash probe} num +@deffn {Command} {flash probe} num Identify the flash, or validate the parameters of the configured flash. Operation depends on the flash type. The @var{num} parameter is a value shown by @command{flash banks}. @@ -5112,7 +5712,7 @@ Examples include CFI flash such as ``Intel Advanced Bootblock flash'', and AT91SAM7 on-chip flash. @xref{flashprotect,,flash protect}. -@deffn Command {flash erase_sector} num first last +@deffn {Command} {flash erase_sector} num first last Erase sectors in bank @var{num}, starting at sector @var{first} up to and including @var{last}. Sector numbering starts at 0. @@ -5121,7 +5721,7 @@ specifies "to the end of the flash bank". The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {flash erase_address} [@option{pad}] [@option{unlock}] address length +@deffn {Command} {flash erase_address} [@option{pad}] [@option{unlock}] address length Erase sectors starting at @var{address} for @var{length} bytes. Unless @option{pad} is specified, @math{address} must begin a flash sector, and @math{address + length - 1} must end a sector. @@ -5135,10 +5735,10 @@ If @option{unlock} is specified, then the flash is unprotected before erase starts. @end deffn -@deffn Command {flash filld} address double-word length -@deffnx Command {flash fillw} address word length -@deffnx Command {flash fillh} address halfword length -@deffnx Command {flash fillb} address byte length +@deffn {Command} {flash filld} address double-word length +@deffnx {Command} {flash fillw} address word length +@deffnx {Command} {flash fillh} address halfword length +@deffnx {Command} {flash fillb} address byte length Fills flash memory with the specified @var{double-word} (64 bits), @var{word} (32 bits), @var{halfword} (16 bits), or @var{byte} (8-bit) pattern, starting at @var{address} and continuing @@ -5152,9 +5752,9 @@ each block, and the specified length must stay within that bank. @end deffn @comment no current checks for errors if fill blocks touch multiple banks! -@deffn Command {flash mdw} addr [count] -@deffnx Command {flash mdh} addr [count] -@deffnx Command {flash mdb} addr [count] +@deffn {Command} {flash mdw} addr [count] +@deffnx {Command} {flash mdh} addr [count] +@deffnx {Command} {flash mdb} addr [count] Display contents of address @var{addr}, as 32-bit words (@command{mdw}), 16-bit halfwords (@command{mdh}), or 8-bit bytes (@command{mdb}). @@ -5165,14 +5765,14 @@ The flash bank to use is inferred from the @var{address} of each block, and the specified length must stay within that bank. @end deffn -@deffn Command {flash write_bank} num filename [offset] +@deffn {Command} {flash write_bank} num filename [offset] Write the binary @file{filename} to flash bank @var{num}, starting at @var{offset} bytes from the beginning of the bank. If @var{offset} is omitted, start at the beginning of the flash bank. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {flash read_bank} num filename [offset [length]] +@deffn {Command} {flash read_bank} num filename [offset [length]] Read @var{length} bytes from the flash bank @var{num} starting at @var{offset} and write the contents to the binary @file{filename}. If @var{offset} is omitted, start at the beginning of the flash bank. If @var{length} is omitted, @@ -5180,14 +5780,14 @@ read the remaining bytes from the flash bank. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {flash verify_bank} num filename [offset] +@deffn {Command} {flash verify_bank} num filename [offset] Compare the contents of the binary file @var{filename} with the contents of the flash bank @var{num} starting at @var{offset}. If @var{offset} is omitted, start at the beginning of the flash bank. Fail if the contents do not match. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {flash write_image} [erase] [unlock] filename [offset] [type] +@deffn {Command} {flash write_image} [erase] [unlock] filename [offset] [type] Write the image @file{filename} to the current target's flash bank(s). Only loadable sections from the image are written. A relocation @var{offset} may be specified, in which case it is added @@ -5224,16 +5824,28 @@ it has been removed by the @option{unlock} flag. @end deffn +@deffn {Command} {flash verify_image} filename [offset] [type] +Verify the image @file{filename} to the current target's flash bank(s). +Parameters follow the description of 'flash write_image'. +In contrast to the 'verify_image' command, for banks with specific +verify method, that one is used instead of the usual target's read +memory methods. This is necessary for flash banks not readable by +ordinary memory reads. +This command gives only an overall good/bad result for each bank, not +addresses of individual failed bytes as it's intended only as quick +check for successful programming. +@end deffn + @section Other Flash commands @cindex flash protection -@deffn Command {flash erase_check} num +@deffn {Command} {flash erase_check} num Check erase state of sectors in flash bank @var{num}, and display that status. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {flash info} num [sectors] +@deffn {Command} {flash info} num [sectors] Print info about flash bank @var{num}, a list of protection blocks and their status. Use @option{sectors} to show a list of sectors instead. @@ -5243,7 +5855,7 @@ and possibly stale information. @end deffn @anchor{flashprotect} -@deffn Command {flash protect} num first last (@option{on}|@option{off}) +@deffn {Command} {flash protect} num first last (@option{on}|@option{off}) Enable (@option{on}) or disable (@option{off}) protection of flash blocks in flash bank @var{num}, starting at protection block @var{first} and continuing up to and including @var{last}. @@ -5255,14 +5867,14 @@ Some devices may utilize a protection block distinct from flash sector. See @command{flash info} for a list of protection blocks. @end deffn -@deffn Command {flash padded_value} num value +@deffn {Command} {flash padded_value} num value Sets the default value used for padding any image sections, This should normally match the flash bank erased value. If not specified by this command or the flash driver then it defaults to 0xff. @end deffn @anchor{program} -@deffn Command {program} filename [preverify] [verify] [reset] [exit] [offset] +@deffn {Command} {program} filename [preverify] [verify] [reset] [exit] [offset] This is a helper script that simplifies using OpenOCD as a standalone programmer. The only required parameter is @option{filename}, the others are optional. @xref{Flash Programming}. @@ -5274,7 +5886,7 @@ As noted above, the @command{flash bank} command requires a driver name, and allows driver-specific options and behaviors. Some drivers also activate driver-specific commands. -@deffn {Flash Driver} virtual +@deffn {Flash Driver} {virtual} This is a special driver that maps a previously defined bank to another address. All bank settings will be copied from the master physical bank. @@ -5298,7 +5910,7 @@ flash bank vbank1 virtual 0x9fc00000 0 0 0 \ @subsection External Flash -@deffn {Flash Driver} cfi +@deffn {Flash Driver} {cfi} @cindex Common Flash Interface @cindex CFI The ``Common Flash Interface'' (CFI) is the main standard for @@ -5343,24 +5955,42 @@ flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME @c "cfi part_id" disabled @end deffn -@deffn {Flash Driver} jtagspi +@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 @@ -5370,21 +6000,59 @@ will not work. These include all @command{*_image} and functionality is available through the @command{flash write_bank}, @command{flash read_bank}, and @command{flash verify_bank} commands. +According to device size, 1- to 4-byte addresses are sent. However, some +flash chips additionally have to be switched to 4-byte addresses by an extra +command, see below. + @itemize @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. +@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.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} +size in bytes, @var{page_size} is write page size. @var{read_cmd} and @var{pprg_cmd} +are commands for read and page program, respectively. @var{mass_erase_cmd}, +@var{sector_size} and @var{sector_erase_cmd} are optional. @example -target create $_TARGETNAME testee -chain-position $_CHIPNAME.fpga -set _XILINX_USER1 0x02 -flash bank $_FLASHNAME spi 0x0 0 0 0 \ - $_TARGETNAME $_XILINX_USER1 +jtagspi set 0 w25q128 0x1000000 0x100 0x03 0 0x02 0xC7 0x10000 0xD8 @end example @end deffn -@deffn {Flash Driver} xcf +@deffn Command {jtagspi cmd} bank_id resp_num cmd_byte ... +Sends command @var{cmd_byte} and at most 20 following bytes and reads +@var{resp_num} bytes afterwards. E.g. for 'Enter 4-byte address mode' +@example +jtagspi cmd 0 0 0xB7 +@end example +@end deffn + +@deffn Command {jtagspi always_4byte} bank_id [ on | off ] +Some devices use 4-byte addresses for all commands except the legacy 0x03 read +regardless of device size. This command controls the corresponding hack. +@end deffn +@end deffn + +@deffn {Flash Driver} {xcf} @cindex Xilinx Platform flash driver @cindex xcf Xilinx FPGAs can be configured from specialized flash ICs named Platform Flash. @@ -5393,7 +6061,7 @@ only difference is special registers controlling its FPGA specific behavior. They must be properly configured for successful FPGA loading using additional @var{xcf} driver command: -@deffn Command {xcf ccb} <bank_id> +@deffn {Command} {xcf ccb} <bank_id> command accepts additional parameters: @itemize @item @var{external|internal} ... selects clock source. @@ -5412,7 +6080,7 @@ every time you erase/program data sectors because it stores in dedicated sector. @end deffn -@deffn Command {xcf configure} <bank_id> +@deffn {Command} {xcf configure} <bank_id> Initiates FPGA loading procedure. Useful if your board has no "configure" button. @example @@ -5430,7 +6098,7 @@ only "bin" (raw binary, do not confuse it with "bit") and "mcs" @end itemize @end deffn -@deffn {Flash Driver} lpcspifi +@deffn {Flash Driver} {lpcspifi} @cindex NXP SPI Flash Interface @cindex SPIFI @cindex lpcspifi @@ -5454,7 +6122,7 @@ flash bank $_FLASHNAME lpcspifi 0x14000000 0 0 0 $_TARGETNAME @end deffn -@deffn {Flash Driver} stmsmi +@deffn {Flash Driver} {stmsmi} @cindex STMicroelectronics Serial Memory Interface @cindex SMI @cindex stmsmi @@ -5482,7 +6150,122 @@ flash bank $_FLASHNAME stmsmi 0xf8000000 0 0 0 $_TARGETNAME @end deffn -@deffn {Flash Driver} mrvlqspi +@deffn {Flash Driver} {stmqspi} +@cindex STMicroelectronics QuadSPI/OctoSPI Interface +@cindex QuadSPI +@cindex OctoSPI +@cindex stmqspi +Some devices from STMicroelectronics include a proprietary ``QuadSPI Interface'' +(e.g. STM32F4, STM32F7, STM32L4) or ``OctoSPI Interface'' (e.g. STM32L4+) +controller able to drive one or even two (dual mode) external SPI flash devices. +The OctoSPI is a superset of QuadSPI, its presence is detected automatically. +Currently only the regular command mode is supported, whereas the HyperFlash +mode is not. + +QuadSPI/OctoSPI makes the flash contents directly accessible in the CPU address +space; in case of dual mode both devices must be of the same type and are +mapped in the same memory bank (even and odd addresses interleaved). +CPU can directly read data, execute code (but not boot) from QuadSPI bank. + +The 'flash bank' command only requires the @var{base} parameter and the extra +parameter @var{io_base} in order to identify the memory bank. Both are fixed +by hardware, see datasheet or RM. All other parameters are ignored. + +The controller must be initialized after each reset and properly configured +for memory-mapped read operation for the particular flash chip(s), for the full +list of available register settings cf. the controller's RM. This setup is quite +board specific (that's why booting from this memory is not possible). The +flash driver infers all parameters from current controller register values when +'flash probe @var{bank_id}' is executed. + +Normal OpenOCD commands like @command{mdw} can be used to display the flash content, +but only after proper controller initialization as described above. However, +due to a silicon bug in some devices, attempting to access the very last word +should be avoided. + +It is possible to use two (even different) flash chips alternatingly, if individual +bank chip selects are available. For some package variants, this is not the case +due to limited pin count. To switch from one to another, adjust FSEL bit accordingly +and re-issue 'flash probe bank_id'. Note that the bank base address will @emph{not} +change, so the address spaces of both devices will overlap. In dual flash mode +both chips must be identical regarding size and most other properties. + +Block or sector protection internal to the flash chip is not handled by this +driver at all, but can be dealt with manually by the 'cmd' command, see below. +The sector protection via 'flash protect' command etc. is completely internal to +openocd, intended only to prevent accidental erase or overwrite and it does not +persist across openocd invocations. + +OpenOCD contains a hardcoded list of flash devices with their properties, +these are auto-detected. If a device is not included in this list, SFDP discovery +is attempted. If this fails or gives inappropriate results, manual setting is +required (see 'set' command). + +@example +flash bank $_FLASHNAME stmqspi 0x90000000 0 0 0 \ + $_TARGETNAME 0xA0001000 +flash bank $_FLASHNAME stmqspi 0x70000000 0 0 0 \ + $_TARGETNAME 0xA0001400 +@end example + +There are three specific commands +@deffn {Command} {stmqspi mass_erase} bank_id +Clears sector protections and performs a mass erase. Works only if there is no +chip specific write protection engaged. +@end deffn + +@deffn {Command} {stmqspi set} bank_id name total_size page_size read_cmd fread_cmd pprg_cmd mass_erase_cmd sector_size sector_erase_cmd +Set flash parameters: @var{name} human readable string, @var{total_size} size +in bytes, @var{page_size} is write page size. @var{read_cmd}, @var{fread_cmd} and @var{pprg_cmd} +are commands for reading and page programming. @var{fread_cmd} is used in DPI and QPI modes, +@var{read_cmd} in normal SPI (single line) mode. @var{mass_erase_cmd}, @var{sector_size} +and @var{sector_erase_cmd} are optional. + +This command is required if chip id is not hardcoded yet and e.g. for EEPROMs or FRAMs +which don't support an id command. + +In dual mode parameters of both chips are set identically. The parameters refer to +a single chip, so the whole bank gets twice the specified capacity etc. +@end deffn + +@deffn {Command} {stmqspi cmd} bank_id resp_num cmd_byte ... +If @var{resp_num} is zero, sends command @var{cmd_byte} and following data +bytes. In dual mode command byte is sent to @emph{both} chips but data bytes are +sent @emph{alternatingly} to chip 1 and 2, first to flash 1, second to flash 2, etc., +i.e. the total number of bytes (including cmd_byte) must be odd. + +If @var{resp_num} is not zero, cmd and at most four following data bytes are +sent, in dual mode @emph{simultaneously} to both chips. Then @var{resp_num} bytes +are read interleaved from both chips starting with chip 1. In this case +@var{resp_num} must be even. + +Note the hardware dictated subtle difference of those two cases in dual-flash mode. + +To check basic communication settings, issue +@example +stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 1 0x05 +stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 1 0x05 +@end example +for single flash mode or +@example +stmqspi cmd bank_id 0 0x04; stmqspi cmd bank_id 2 0x05 +stmqspi cmd bank_id 0 0x06; stmqspi cmd bank_id 2 0x05 +@end example +for dual flash mode. This should return the status register contents. + +In 8-line mode, @var{cmd_byte} is sent twice - first time as given, second time +complemented. Additionally, in 8-line mode only, some commands (e.g. Read Status) +need a dummy address, e.g. +@example +stmqspi cmd bank_id 1 0x05 0x00 0x00 0x00 0x00 +@end example +should return the status register contents. + +@end deffn + +@end deffn + +@deffn {Flash Driver} {mrvlqspi} This driver supports QSPI flash controller of Marvell's Wireless Microcontroller platform. @@ -5495,7 +6278,7 @@ flash bank $_FLASHNAME mrvlqspi 0x0 0 0 0 $_TARGETNAME 0x46010000 @end deffn -@deffn {Flash Driver} ath79 +@deffn {Flash Driver} {ath79} @cindex Atheros ath79 SPI driver @cindex ath79 Members of ATH79 SoC family from Atheros include a SPI interface with 3 @@ -5524,9 +6307,9 @@ CS1/CS2 is routed to on the given SoC. @example flash bank $_FLASHNAME ath79 0xbf000000 0 0 0 $_TARGETNAME -# When using multiple chipselects the base should be different for each, -# otherwise the write_image command is not able to distinguish the -# banks. +# When using multiple chipselects the base should be different +# for each, otherwise the write_image command is not able to +# distinguish the banks. flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0 flash bank flash1 ath79 0x10000000 0 0 0 $_TARGETNAME cs1 flash bank flash2 ath79 0x20000000 0 0 0 $_TARGETNAME cs2 @@ -5534,7 +6317,7 @@ flash bank flash2 ath79 0x20000000 0 0 0 $_TARGETNAME cs2 @end deffn -@deffn {Flash Driver} fespi +@deffn {Flash Driver} {fespi} @cindex Freedom E SPI @cindex fespi @@ -5547,7 +6330,7 @@ flash bank $_FLASHNAME fespi 0x20000000 0 0 0 $_TARGETNAME @subsection Internal Flash (Microcontrollers) -@deffn {Flash Driver} aduc702x +@deffn {Flash Driver} {aduc702x} The ADUC702x analog microcontrollers from Analog Devices include internal flash and use ARM7TDMI cores. The aduc702x flash driver works with models ADUC7019 through ADUC7028. @@ -5559,7 +6342,7 @@ flash bank $_FLASHNAME aduc702x 0 0 0 0 $_TARGETNAME @end example @end deffn -@deffn {Flash Driver} ambiqmicro +@deffn {Flash Driver} {ambiqmicro} @cindex ambiqmicro @cindex apollo All members of the Apollo microcontroller family from @@ -5592,13 +6375,13 @@ are available to the user. The @var{ambiqmicro} driver adds some additional commands: -@deffn Command {ambiqmicro mass_erase} <bank> +@deffn {Command} {ambiqmicro mass_erase} <bank> Erase entire bank. @end deffn -@deffn Command {ambiqmicro page_erase} <bank> <first> <last> +@deffn {Command} {ambiqmicro page_erase} <bank> <first> <last> Erase device pages. @end deffn -@deffn Command {ambiqmicro program_otp} <bank> <offset> <count> +@deffn {Command} {ambiqmicro program_otp} <bank> <offset> <count> Program OTP is a one time operation to create write protected flash. The user writes sectors to SRAM starting at 0x10000010. Program OTP will write these sectors from SRAM to flash, and write protect @@ -5606,8 +6389,7 @@ the flash. @end deffn @end deffn -@anchor{at91samd} -@deffn {Flash Driver} at91samd +@deffn {Flash Driver} {at91samd} @cindex at91samd All members of the ATSAM D2x, D1x, D0x, ATSAMR, ATSAML and ATSAMC microcontroller families from Atmel include internal flash and use ARM's Cortex-M0+ core. @@ -5620,13 +6402,13 @@ The devices have one flash bank: flash bank $_FLASHNAME at91samd 0x00000000 0 1 1 $_TARGETNAME @end example -@deffn Command {at91samd chip-erase} +@deffn {Command} {at91samd chip-erase} Issues a complete Flash erase via the Device Service Unit (DSU). This can be used to erase a chip back to its factory state and does not require the processor to be halted. @end deffn -@deffn Command {at91samd set-security} +@deffn {Command} {at91samd set-security} Secures the Flash via the Set Security Bit (SSB) command. This prevents access to the Flash and can only be undone by using the chip-erase command which erases the Flash contents and turns off the security bit. Warning: at this @@ -5638,7 +6420,7 @@ at91samd set-security enable @end example @end deffn -@deffn Command {at91samd eeprom} +@deffn {Command} {at91samd eeprom} Shows or sets the EEPROM emulation size configuration, stored in the User Row of the Flash. When setting, the EEPROM size must be specified in bytes and it must be one of the permitted sizes according to the datasheet. Settings are @@ -5653,7 +6435,7 @@ at91samd eeprom 1024 @end example @end deffn -@deffn Command {at91samd bootloader} +@deffn {Command} {at91samd bootloader} Shows or sets the bootloader size configuration, stored in the User Row of the Flash. This is called the BOOTPROT region. When setting, the bootloader size must be specified in bytes and it must be one of the permitted sizes according @@ -5666,13 +6448,13 @@ at91samd bootloader 16384 @end example @end deffn -@deffn Command {at91samd dsu_reset_deassert} +@deffn {Command} {at91samd dsu_reset_deassert} This command releases internal reset held by DSU and prepares reset vector catch in case of reset halt. Command is used internally in event reset-deassert-post. @end deffn -@deffn Command {at91samd nvmuserrow} +@deffn {Command} {at91samd nvmuserrow} Writes or reads the entire 64 bit wide NVM user row register which is located at 0x804000. This register includes various fuses lock-bits and factory calibration data. Reading the register is done by invoking this command without any @@ -5687,7 +6469,8 @@ reserved-bits are masked out and cannot be changed. NVMUSERROW: 0xFFFFFC5DD8E0C788 # Write 0xFFFFFC5DD8E0C788 to user row >at91samd nvmuserrow 0xFFFFFC5DD8E0C788 -# Write 0x12300 to user row but leave other bits and low byte unchanged +# Write 0x12300 to user row but leave other bits and low +# byte unchanged >at91samd nvmuserrow 0x12345 0xFFF00 @end example @end deffn @@ -5695,7 +6478,7 @@ NVMUSERROW: 0xFFFFFC5DD8E0C788 @end deffn @anchor{at91sam3} -@deffn {Flash Driver} at91sam3 +@deffn {Flash Driver} {at91sam3} @cindex at91sam3 All members of the AT91SAM3 microcontroller family from Atmel include internal flash and use ARM's Cortex-M3 core. The driver @@ -5731,10 +6514,10 @@ to the @command{flash bank} command: The AT91SAM3 driver adds some additional commands: -@deffn Command {at91sam3 gpnvm} -@deffnx Command {at91sam3 gpnvm clear} number -@deffnx Command {at91sam3 gpnvm set} number -@deffnx Command {at91sam3 gpnvm show} [@option{all}|number] +@deffn {Command} {at91sam3 gpnvm} +@deffnx {Command} {at91sam3 gpnvm clear} number +@deffnx {Command} {at91sam3 gpnvm set} number +@deffnx {Command} {at91sam3 gpnvm show} [@option{all}|number] With no parameters, @command{show} or @command{show all}, shows the status of all GPNVM bits. With @command{show} @var{number}, displays that bit. @@ -5743,7 +6526,7 @@ With @command{set} @var{number} or @command{clear} @var{number}, modifies that GPNVM bit. @end deffn -@deffn Command {at91sam3 info} +@deffn {Command} {at91sam3 info} This command attempts to display information about the AT91SAM3 chip. @emph{First} it read the @code{CHIPID_CIDR} [address 0x400e0740, see Section 28.2.1, page 505 of the AT91SAM3U 29/may/2009 datasheet, @@ -5753,27 +6536,27 @@ believes the chip is configured. By default, the SLOWCLK is assumed to be 32768 Hz, see the command @command{at91sam3 slowclk}. @end deffn -@deffn Command {at91sam3 slowclk} [value] +@deffn {Command} {at91sam3 slowclk} [value] This command shows/sets the slow clock frequency used in the @command{at91sam3 info} command calculations above. @end deffn @end deffn -@deffn {Flash Driver} at91sam4 +@deffn {Flash Driver} {at91sam4} @cindex at91sam4 All members of the AT91SAM4 microcontroller family from Atmel include internal flash and use ARM's Cortex-M4 core. This driver uses the same command names/syntax as @xref{at91sam3}. @end deffn -@deffn {Flash Driver} at91sam4l +@deffn {Flash Driver} {at91sam4l} @cindex at91sam4l All members of the AT91SAM4L microcontroller family from Atmel include internal flash and use ARM's Cortex-M4 core. This driver uses the same command names/syntax as @xref{at91sam3}. The AT91SAM4L driver adds some additional commands: -@deffn Command {at91sam4l smap_reset_deassert} +@deffn {Command} {at91sam4l smap_reset_deassert} This command releases internal reset held by SMAP and prepares reset vector catch in case of reset halt. Command is used internally in event reset-deassert-post. @@ -5781,7 +6564,7 @@ Command is used internally in event reset-deassert-post. @end deffn @anchor{atsame5} -@deffn {Flash Driver} atsame5 +@deffn {Flash Driver} {atsame5} @cindex atsame5 All members of the SAM E54, E53, E51 and D51 microcontroller families from Microchip (former Atmel) include internal flash @@ -5795,7 +6578,7 @@ Bank swapping is not supported yet. flash bank $_FLASHNAME atsame5 0x00000000 0 1 1 $_TARGETNAME @end example -@deffn Command {atsame5 bootloader} +@deffn {Command} {atsame5 bootloader} Shows or sets the bootloader size configuration, stored in the User Page of the Flash. This is called the BOOTPROT region. When setting, the bootloader size must be specified in bytes. The nearest bigger protection size is used. @@ -5808,19 +6591,19 @@ atsame5 bootloader 16384 @end example @end deffn -@deffn Command {atsame5 chip-erase} +@deffn {Command} {atsame5 chip-erase} Issues a complete Flash erase via the Device Service Unit (DSU). This can be used to erase a chip back to its factory state and does not require the processor to be halted. @end deffn -@deffn Command {atsame5 dsu_reset_deassert} +@deffn {Command} {atsame5 dsu_reset_deassert} This command releases internal reset held by DSU and prepares reset vector catch in case of reset halt. Command is used internally in event reset-deassert-post. @end deffn -@deffn Command {atsame5 userpage} +@deffn {Command} {atsame5 userpage} Writes or reads the first 64 bits of NVM User Page which is located at 0x804000. This field includes various fuses. Reading is done by invoking this command without any arguments. @@ -5835,22 +6618,38 @@ The reserved fields are always masked out and cannot be changed. USER PAGE: 0xAEECFF80FE9A9239 # Write >atsame5 userpage 0xAEECFF80FE9A9239 -# Write 2 to SEESBLK and 4 to SEEPSZ fields but leave other bits unchanged -# (setup SmartEEPROM of virtual size 8192 bytes) +# Write 2 to SEESBLK and 4 to SEEPSZ fields but leave other +# bits unchanged (setup SmartEEPROM of virtual size 8192 +# bytes) >atsame5 userpage 0x4200000000 0x7f00000000 @end example @end deffn @end deffn -@deffn {Flash Driver} atsamv +@deffn {Flash Driver} {atsamv} @cindex atsamv All members of the ATSAMV7x, ATSAMS70, and ATSAME70 families from Atmel include internal flash and use ARM's Cortex-M7 core. This driver uses the same command names/syntax as @xref{at91sam3}. + +@example +flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME +@end example + +@deffn {Command} {atsamv gpnvm} [@option{show} [@option{all}|number]] +@deffnx {Command} {atsamv gpnvm} (@option{clr}|@option{set}) number +With no parameters, @option{show} or @option{show all}, +shows the status of all GPNVM bits. +With @option{show} @var{number}, displays that bit. + +With @option{set} @var{number} or @option{clear} @var{number}, +modifies that GPNVM bit. +@end deffn + @end deffn -@deffn {Flash Driver} at91sam7 +@deffn {Flash Driver} {at91sam7} All members of the AT91SAM7 microcontroller family from Atmel include internal flash and use ARM7TDMI cores. The driver automatically recognizes a number of these chips using the chip identification @@ -5885,7 +6684,7 @@ However, there is an ``EraseAll`` command that can erase an entire flash plane (of up to 256KB), and it will be used automatically when you issue @command{flash erase_sector} or @command{flash erase_address} commands. -@deffn Command {at91sam7 gpnvm} bitnum (@option{set}|@option{clear}) +@deffn {Command} {at91sam7 gpnvm} bitnum (@option{set}|@option{clear}) Set or clear a ``General Purpose Non-Volatile Memory'' (GPNVM) bit for the processor. Each processor has a number of such bits, used for controlling features such as brownout detection (so they @@ -5897,14 +6696,14 @@ the appropriate at91sam7 target. @end deffn @end deffn -@deffn {Flash Driver} avr +@deffn {Flash Driver} {avr} The AVR 8-bit microcontrollers from Atmel integrate flash memory. @emph{The current implementation is incomplete.} @comment - defines mass_erase ... pointless given flash_erase_address @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. +@deffn {Flash Driver} {bluenrg-x} +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. @@ -5922,7 +6721,7 @@ flash erase_sector 0 0 last # It will perform a mass erase Triggering a mass erase is also useful when users want to disable readout protection. @end deffn -@deffn {Flash Driver} cc26xx +@deffn {Flash Driver} {cc26xx} All versions of the SimpleLink CC13xx and CC26xx microcontrollers from Texas Instruments include internal flash. The cc26xx flash driver supports both the CC13xx and CC26xx family of devices. The driver automatically recognizes the @@ -5934,7 +6733,7 @@ flash bank $_FLASHNAME cc26xx 0 0 0 0 $_TARGETNAME @end example @end deffn -@deffn {Flash Driver} cc3220sf +@deffn {Flash Driver} {cc3220sf} The CC3220SF version of the SimpleLink CC32xx microcontrollers from Texas Instruments includes 1MB of internal flash. The cc3220sf flash driver only supports the internal flash. The serial flash on SimpleLink boards is @@ -5948,14 +6747,23 @@ flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME @end example @end deffn -@deffn {Flash Driver} efm32 -All members of the EFM32 microcontroller family from Energy Micro include -internal flash and use ARM Cortex-M3 cores. The driver automatically recognizes -a number of these chips using the chip identification register, and +@deffn {Flash Driver} {efm32} +All members of the EFM32/EFR32 microcontroller family from Energy Micro (now Silicon Labs) +include internal flash and use Arm Cortex-M3 or Cortex-M4 cores. The driver automatically +recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME efm32 0 0 0 0 $_TARGETNAME @end example +It supports writing to the user data page, as well as the portion of the lockbits page +past 512 bytes on chips with larger page sizes. The latter is used by the SiLabs +bootloader/AppLoader system for encryption keys. Setting protection on these pages is +currently not supported. +@example +flash bank userdata.flash efm32 0x0FE00000 0 0 0 $_TARGETNAME +flash bank lockbits.flash efm32 0x0FE04000 0 0 0 $_TARGETNAME +@end example + A special feature of efm32 controllers is that it is possible to completely disable the debug interface by writing the correct values to the 'Debug Lock Word'. OpenOCD supports this via the following command: @@ -5968,7 +6776,25 @@ Note that in order for this command to take effect, the target needs to be reset supported.} @end deffn -@deffn {Flash Driver} esirisc +@deffn {Flash Driver} {eneispif} +All versions of the KB1200 microcontrollers from ENE include internal +flash. The eneispif flash driver supports the KB1200 family of devices. The driver +automatically recognizes the specific version's flash parameters and +autoconfigures itself. The flash bank starts at address 0x60000000. An optional additional +parameter sets the address of eneispif controller, with the default address is 0x50101000. + +@example + +flash bank $_FLASHNAME eneispif 0x60000000 0 0 0 $_TARGETNAME \ + 0x50101000 + +# Address defaults to 0x50101000 +flash bank $_FLASHNAME eneispif 0x60000000 0 0 0 $_TARGETNAME + +@end example +@end deffn + +@deffn {Flash Driver} {esirisc} Members of the eSi-RISC family may optionally include internal flash programmed via the eSi-TSMC Flash interface. Additional parameters are required to configure the driver: @option{cfg_address} is the base address of the @@ -5980,17 +6806,17 @@ flash bank $_FLASHNAME esirisc base_address size_bytes 0 0 \ $_TARGETNAME cfg_address clock_hz wait_states @end example -@deffn Command {esirisc flash mass_erase} bank_id +@deffn {Command} {esirisc flash mass_erase} bank_id Erase all pages in data memory for the bank identified by @option{bank_id}. @end deffn -@deffn Command {esirisc flash ref_erase} bank_id +@deffn {Command} {esirisc flash ref_erase} bank_id Erase the reference cell for the bank identified by @option{bank_id}. @emph{This is an uncommon operation.} @end deffn @end deffn -@deffn {Flash Driver} fm3 +@deffn {Flash Driver} {fm3} All members of the FM3 microcontroller family from Fujitsu include internal flash and use ARM Cortex-M3 cores. The @var{fm3} driver uses the @var{target} parameter to select the @@ -6003,7 +6829,7 @@ flash bank $_FLASHNAME fm3 0 0 0 0 $_TARGETNAME @end example @end deffn -@deffn {Flash Driver} fm4 +@deffn {Flash Driver} {fm4} All members of the FM4 microcontroller family from Spansion (formerly Fujitsu) include internal flash and use ARM Cortex-M4 cores. The @var{fm4} driver uses a @var{family} parameter to select the @@ -6023,31 +6849,38 @@ flash bank $@{_FLASHNAME@}1 fm4 0x00100000 0 0 0 \ nor is Chip Erase (only Sector Erase is implemented).} @end deffn -@deffn {Flash Driver} kinetis +@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 flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME @end example -@deffn Command {kinetis create_banks} +@deffn {Config Command} {kinetis create_banks} Configuration command enables automatic creation of additional flash banks based on real flash layout of device. Banks are created during device probe. Use 'flash probe 0' to force probe. @end deffn -@deffn Command {kinetis fcf_source} [protection|write] +@deffn {Command} {kinetis fcf_source} [protection|write] Select what source is used when writing to a Flash Configuration Field. @option{protection} mode builds FCF content from protection bits previously set by 'flash protect' command. @@ -6059,30 +6892,31 @@ with the rest of a flash image. @emph{BEWARE: Incorrect flash configuration may permanently lock the device!} @end deffn -@deffn Command {kinetis fopt} [num] +@deffn {Command} {kinetis fopt} [num] Set value to write to FOPT byte of Flash Configuration Field. Used in kinetis 'fcf_source protection' mode only. @end deffn -@deffn Command {kinetis mdm check_security} +@deffn {Command} {kinetis mdm check_security} Checks status of device security lock. Used internally in examine-end and examine-fail event. @end deffn -@deffn Command {kinetis mdm halt} +@deffn {Command} {kinetis mdm halt} Issues a halt via the MDM-AP. This command can be used to break a watchdog reset loop when connecting to an unsecured target. @end deffn -@deffn Command {kinetis mdm mass_erase} +@deffn {Command} {kinetis mdm mass_erase} Issues a complete flash erase via the MDM-AP. This can be used to erase a chip back to its factory state, removing security. It does not require the processor to be halted, however the target will remain in a halted state after this command completes. @end deffn -@deffn Command {kinetis nvm_partition} +@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. @@ -6111,18 +6945,18 @@ kinetis nvm_partition eebkp 16 1024 1024 off @end example @end deffn -@deffn Command {kinetis mdm reset} +@deffn {Command} {kinetis mdm reset} Issues a reset via the MDM-AP. This causes the MCU to output a low pulse on the RESET pin, which can be used to reset other hardware on board. @end deffn -@deffn Command {kinetis disable_wdog} +@deffn {Command} {kinetis disable_wdog} For Kx devices only (KLx has different COP watchdog, it is not supported). Command disables watchdog timer. @end deffn @end deffn -@deffn {Flash Driver} kinetis_ke +@deffn {Flash Driver} {kinetis_ke} @cindex kinetis_ke KE0x and KEAx members of the Kinetis microcontroller family from NXP include internal flash and use ARM Cortex-M0+. The driver automatically recognizes @@ -6134,23 +6968,23 @@ Use kinetis (not kinetis_ke) driver for KE1x devices. flash bank $_FLASHNAME kinetis_ke 0 0 0 0 $_TARGETNAME @end example -@deffn Command {kinetis_ke mdm check_security} +@deffn {Command} {kinetis_ke mdm check_security} Checks status of device security lock. Used internally in examine-end event. @end deffn -@deffn Command {kinetis_ke mdm mass_erase} +@deffn {Command} {kinetis_ke mdm mass_erase} Issues a complete Flash erase via the MDM-AP. This can be used to erase a chip back to its factory state. Command removes security lock from a device (use of SRST highly recommended). It does not require the processor to be halted. @end deffn -@deffn Command {kinetis_ke disable_wdog} +@deffn {Command} {kinetis_ke disable_wdog} Command disables watchdog timer. @end deffn @end deffn -@deffn {Flash Driver} lpc2000 +@deffn {Flash Driver} {lpc2000} This is the driver to support internal flash of all members of the LPC11(x)00 and LPC1300 microcontroller families and most members of the LPC800, LPC1500, LPC1700, LPC1800, LPC2000, LPC4000, LPC54100, @@ -6207,7 +7041,7 @@ the specified flash @var{bank}. @end deffn @end deffn -@deffn {Flash Driver} lpc288x +@deffn {Flash Driver} {lpc288x} The LPC2888 microcontroller from NXP needs slightly different flash support from its lpc2000 siblings. The @var{lpc288x} driver defines one mandatory parameter, @@ -6219,7 +7053,7 @@ flash bank $_FLASHNAME lpc288x 0 0 0 0 $_TARGETNAME 12000000 @end example @end deffn -@deffn {Flash Driver} lpc2900 +@deffn {Flash Driver} {lpc2900} This driver supports the LPC29xx ARM968E based microcontroller family from NXP. @@ -6255,7 +7089,7 @@ Some @code{lpc2900}-specific commands are defined. In the following command list the @var{bank} parameter is the bank number as obtained by the @code{flash banks} command. -@deffn Command {lpc2900 signature} bank +@deffn {Command} {lpc2900 signature} bank Calculates a 128-bit hash value, the @emph{signature}, from the whole flash content. This is a hardware feature of the flash block, hence the calculation is very fast. You may use this to verify the content of a programmed device against @@ -6267,7 +7101,7 @@ lpc2900 signature 0 @end example @end deffn -@deffn Command {lpc2900 read_custom} bank filename +@deffn {Command} {lpc2900 read_custom} bank filename Reads the 912 bytes of customer information from the flash index sector, and saves it to a file in binary format. Example: @@ -6281,7 +7115,7 @@ erased! In order to guard against unintentional write access, all following commands need to be preceded by a successful call to the @code{password} command: -@deffn Command {lpc2900 password} bank password +@deffn {Command} {lpc2900 password} bank password You need to use this command right before each of the following commands: @code{lpc2900 write_custom}, @code{lpc2900 secure_sector}, @code{lpc2900 secure_jtag}. @@ -6294,7 +7128,7 @@ lpc2900 password 0 I_know_what_I_am_doing @end example @end deffn -@deffn Command {lpc2900 write_custom} bank filename type +@deffn {Command} {lpc2900 write_custom} bank filename type Writes the content of the file into the customer info space of the flash index sector. The filetype can be specified with the @var{type} field. Possible values for @var{type} are: @var{bin} (binary), @var{ihex} (Intel hex format), @@ -6310,7 +7144,7 @@ lpc2900 write_custom 0 /path_to/customer_info.bin bin @end example @end deffn -@deffn Command {lpc2900 secure_sector} bank first last +@deffn {Command} {lpc2900 secure_sector} bank first last Secures the sector range from @var{first} to @var{last} (including) against further program and erase operations. The sector security will be effective after the next power cycle. @@ -6329,7 +7163,7 @@ flash info 0 @end example @end deffn -@deffn Command {lpc2900 secure_jtag} bank +@deffn {Command} {lpc2900 secure_jtag} bank Irreversibly disable the JTAG port. The new JTAG security setting will be effective after the next power cycle. @quotation Attention @@ -6342,7 +7176,7 @@ lpc2900 secure_jtag 0 @end deffn @end deffn -@deffn {Flash Driver} mdr +@deffn {Flash Driver} {mdr} This drivers handles the integrated NOR flash on Milandr Cortex-M based controllers. A known limitation is that the Info memory can't be read or verified as it's not memory mapped. @@ -6370,7 +7204,7 @@ if @{ [info exists IMEMORY] && [string equal $IMEMORY true] @} @{ @end example @end deffn -@deffn {Flash Driver} msp432 +@deffn {Flash Driver} {msp432} All versions of the SimpleLink MSP432 microcontrollers from Texas Instruments include internal flash. The msp432 flash driver automatically recognizes the specific version's flash parameters and autoconfigures itself. @@ -6381,7 +7215,7 @@ MSP432P4 versions starts at address 0x200000. flash bank $_FLASHNAME msp432 0 0 0 0 $_TARGETNAME @end example -@deffn Command {msp432 mass_erase} bank_id [main|all] +@deffn {Command} {msp432 mass_erase} bank_id [main|all] Performs a complete erase of flash. By default, @command{mass_erase} will erase only the main program flash. @@ -6390,7 +7224,7 @@ main program and information flash regions. To also erase the BSL in information flash, the user must first use the @command{bsl} command. @end deffn -@deffn Command {msp432 bsl} bank_id [unlock|lock] +@deffn {Command} {msp432 bsl} bank_id [unlock|lock] On MSP432P4 versions, @command{bsl} unlocks and locks the bootstrap loader (BSL) region in information flash so that flash commands can erase or write the BSL. Leave the BSL locked to prevent accidentally corrupting the bootstrap loader. @@ -6405,7 +7239,7 @@ msp432 bsl lock @end deffn @end deffn -@deffn {Flash Driver} niietcm4 +@deffn {Flash Driver} {niietcm4} This drivers handles the integrated NOR flash on NIIET Cortex-M4 based controllers. Flash size and sector layout are auto-configured by the driver. Main flash memory is called "Bootflash" and has main region and info region. @@ -6423,53 +7257,72 @@ flash bank $_FLASHNAME niietcm4 0 0 0 0 $_TARGETNAME Some niietcm4-specific commands are defined: -@deffn Command {niietcm4 uflash_read_byte} bank ('main'|'info') address +@deffn {Command} {niietcm4 uflash_read_byte} bank ('main'|'info') address Read byte from main or info userflash region. @end deffn -@deffn Command {niietcm4 uflash_write_byte} bank ('main'|'info') address value +@deffn {Command} {niietcm4 uflash_write_byte} bank ('main'|'info') address value Write byte to main or info userflash region. @end deffn -@deffn Command {niietcm4 uflash_full_erase} bank +@deffn {Command} {niietcm4 uflash_full_erase} bank Erase all userflash including info region. @end deffn -@deffn Command {niietcm4 uflash_erase} bank ('main'|'info') first_sector last_sector +@deffn {Command} {niietcm4 uflash_erase} bank ('main'|'info') first_sector last_sector Erase sectors of main or info userflash region, starting at sector first up to and including last. @end deffn -@deffn Command {niietcm4 uflash_protect_check} bank ('main'|'info') +@deffn {Command} {niietcm4 uflash_protect_check} bank ('main'|'info') Check sectors protect. @end deffn -@deffn Command {niietcm4 uflash_protect} bank ('main'|'info') first_sector last_sector ('on'|'off') +@deffn {Command} {niietcm4 uflash_protect} bank ('main'|'info') first_sector last_sector ('on'|'off') Protect sectors of main or info userflash region, starting at sector first up to and including last. @end deffn -@deffn Command {niietcm4 bflash_info_remap} bank ('on'|'off') +@deffn {Command} {niietcm4 bflash_info_remap} bank ('on'|'off') Enable remapping bootflash info region to 0x00000000 (or 0x40000000 if external memory boot used). @end deffn -@deffn Command {niietcm4 extmem_cfg} bank ('gpioa'|'gpiob'|'gpioc'|'gpiod'|'gpioe'|'gpiof'|'gpiog'|'gpioh') pin_num ('func1'|'func3') +@deffn {Command} {niietcm4 extmem_cfg} bank ('gpioa'|'gpiob'|'gpioc'|'gpiod'|'gpioe'|'gpiof'|'gpiog'|'gpioh') pin_num ('func1'|'func3') Configure external memory interface for boot. @end deffn -@deffn Command {niietcm4 service_mode_erase} bank +@deffn {Command} {niietcm4 service_mode_erase} bank Perform emergency erase of all flash (bootflash and userflash). @end deffn -@deffn Command {niietcm4 driver_info} bank +@deffn {Command} {niietcm4 driver_info} bank Show information about flash driver. @end deffn @end deffn -@deffn {Flash Driver} nrf5 +@deffn {Flash Driver} {npcx} +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. 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 + +@deffn {Flash Driver} {nrf5} All members of the nRF51 microcontroller families from Nordic Semiconductor -include internal flash and use ARM Cortex-M0 core. -Also, the nRF52832 microcontroller from Nordic Semiconductor, which include -internal flash and use an ARM Cortex-M4F core. +include internal flash and use ARM Cortex-M0 core. nRF52 family powered +by ARM Cortex-M4 or M4F core is supported too. nRF52832 is fully supported +including BPROT flash protection scheme. nRF52833 and nRF52840 devices are +supported with the exception of security extensions (flash access control list +- ACL). @example flash bank $_FLASHNAME nrf5 0 0x00000000 0 0 $_TARGETNAME @@ -6477,20 +7330,16 @@ flash bank $_FLASHNAME nrf5 0 0x00000000 0 0 $_TARGETNAME Some nrf5-specific commands are defined: -@deffn Command {nrf5 mass_erase} +@deffn {Command} {nrf5 mass_erase} Erases the contents of the code memory and user information configuration registers as well. It must be noted that this command works only for chips that do not have factory pre-programmed region 0 code. @end deffn -@deffn Command {nrf5 info} -Decodes and shows information from FICR and UICR registers. @end deffn -@end deffn - -@deffn {Flash Driver} ocl +@deffn {Flash Driver} {ocl} This driver is an implementation of the ``on chip flash loader'' protocol proposed by Pavel Chromy. @@ -6504,7 +7353,7 @@ flash bank $_FLASHNAME ocl 0 0 0 0 $_TARGETNAME @end example @end deffn -@deffn {Flash Driver} pic32mx +@deffn {Flash Driver} {pic32mx} The PIC32MX microcontrollers are based on the MIPS 4K cores, and integrate flash memory. @@ -6518,17 +7367,17 @@ flash bank $_FLASHNAME pix32mx 0x1d000000 0 0 0 $_TARGETNAME @comment - lock, unlock ... pointless given protect on/off (yes?) @comment - pgm_word ... shouldn't bank be deduced from address?? Some pic32mx-specific commands are defined: -@deffn Command {pic32mx pgm_word} address value bank +@deffn {Command} {pic32mx pgm_word} address value bank Programs the specified 32-bit @var{value} at the given @var{address} in the specified chip @var{bank}. @end deffn -@deffn Command {pic32mx unlock} bank +@deffn {Command} {pic32mx unlock} bank Unlock and erase specified chip @var{bank}. This will remove any Code Protection. @end deffn @end deffn -@deffn {Flash Driver} psoc4 +@deffn {Flash Driver} {psoc4} All members of the PSoC 41xx/42xx microcontroller family from Cypress include internal flash and use ARM Cortex-M0 cores. The driver automatically recognizes a number of these chips using @@ -6542,7 +7391,7 @@ flash bank $_FLASHNAME psoc4 0 0 0 0 $_TARGETNAME @end example psoc4-specific commands -@deffn Command {psoc4 flash_autoerase} num (on|off) +@deffn {Command} {psoc4 flash_autoerase} num (on|off) Enables or disables autoerase mode for a flash bank. If flash_autoerase is off, use mass_erase before flash programming. @@ -6555,14 +7404,14 @@ This mode is suitable for gdb load. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {psoc4 mass_erase} num +@deffn {Command} {psoc4 mass_erase} num Erases the contents of the flash memory, protection and security lock. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn -@deffn {Flash Driver} psoc5lp +@deffn {Flash Driver} {psoc5lp} All members of the PSoC 5LP microcontroller family from Cypress include internal program flash and use ARM Cortex-M3 cores. The driver probes for a number of these chips and autoconfigures itself, @@ -6582,24 +7431,25 @@ Writing to the ECC data bytes in ECC-disabled mode is not implemented. Commands defined in the @var{psoc5lp} driver: -@deffn Command {psoc5lp mass_erase} +@deffn {Command} {psoc5lp mass_erase} Erases all flash data and ECC/configuration bytes, all flash protection rows, and all row latches in all flash arrays on the device. @end deffn @end deffn -@deffn {Flash Driver} psoc5lp_eeprom +@deffn {Flash Driver} {psoc5lp_eeprom} All members of the PSoC 5LP microcontroller family from Cypress include internal EEPROM and use ARM Cortex-M3 cores. The driver probes for a number of these chips and autoconfigures itself, apart from the base address. @example -flash bank $_CHIPNAME.eeprom psoc5lp_eeprom 0x40008000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.eeprom psoc5lp_eeprom 0x40008000 0 0 0 \ + $_TARGETNAME @end example @end deffn -@deffn {Flash Driver} psoc5lp_nvl +@deffn {Flash Driver} {psoc5lp_nvl} All members of the PSoC 5LP microcontroller family from Cypress include internal Nonvolatile Latches and use ARM Cortex-M3 cores. The driver probes for a number of these chips and autoconfigures itself. @@ -6624,7 +7474,7 @@ after successful write. @end quotation @end deffn -@deffn {Flash Driver} psoc6 +@deffn {Flash Driver} {psoc6} Supports PSoC6 (CY8C6xxx) family of Cypress microcontrollers. PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share the same Flash/RAM/MMIO address space. @@ -6649,23 +7499,35 @@ automatically by parsing data in SPCIF_GEOMETRY register. PSoC6 is equipped with NOR Flash so erased Flash reads as 0x00. @example -flash bank main_flash_cm0 psoc6 0x10000000 0 0 0 $@{TARGET@}.cm0 -flash bank work_flash_cm0 psoc6 0x14000000 0 0 0 $@{TARGET@}.cm0 -flash bank super_flash_user_cm0 psoc6 0x16000800 0 0 0 $@{TARGET@}.cm0 -flash bank super_flash_nar_cm0 psoc6 0x16001A00 0 0 0 $@{TARGET@}.cm0 -flash bank super_flash_key_cm0 psoc6 0x16005A00 0 0 0 $@{TARGET@}.cm0 -flash bank super_flash_toc2_cm0 psoc6 0x16007C00 0 0 0 $@{TARGET@}.cm0 - -flash bank main_flash_cm4 psoc6 0x10000000 0 0 0 $@{TARGET@}.cm4 -flash bank work_flash_cm4 psoc6 0x14000000 0 0 0 $@{TARGET@}.cm4 -flash bank super_flash_user_cm4 psoc6 0x16000800 0 0 0 $@{TARGET@}.cm4 -flash bank super_flash_nar_cm4 psoc6 0x16001A00 0 0 0 $@{TARGET@}.cm4 -flash bank super_flash_key_cm4 psoc6 0x16005A00 0 0 0 $@{TARGET@}.cm4 -flash bank super_flash_toc2_cm4 psoc6 0x16007C00 0 0 0 $@{TARGET@}.cm4 +flash bank main_flash_cm0 psoc6 0x10000000 0 0 0 \ + $@{TARGET@}.cm0 +flash bank work_flash_cm0 psoc6 0x14000000 0 0 0 \ + $@{TARGET@}.cm0 +flash bank super_flash_user_cm0 psoc6 0x16000800 0 0 0 \ + $@{TARGET@}.cm0 +flash bank super_flash_nar_cm0 psoc6 0x16001A00 0 0 0 \ + $@{TARGET@}.cm0 +flash bank super_flash_key_cm0 psoc6 0x16005A00 0 0 0 \ + $@{TARGET@}.cm0 +flash bank super_flash_toc2_cm0 psoc6 0x16007C00 0 0 0 \ + $@{TARGET@}.cm0 + +flash bank main_flash_cm4 psoc6 0x10000000 0 0 0 \ + $@{TARGET@}.cm4 +flash bank work_flash_cm4 psoc6 0x14000000 0 0 0 \ + $@{TARGET@}.cm4 +flash bank super_flash_user_cm4 psoc6 0x16000800 0 0 0 \ + $@{TARGET@}.cm4 +flash bank super_flash_nar_cm4 psoc6 0x16001A00 0 0 0 \ + $@{TARGET@}.cm4 +flash bank super_flash_key_cm4 psoc6 0x16005A00 0 0 0 \ + $@{TARGET@}.cm4 +flash bank super_flash_toc2_cm4 psoc6 0x16007C00 0 0 0 \ + $@{TARGET@}.cm4 @end example psoc6-specific commands -@deffn Command {psoc6 reset_halt} +@deffn {Command} {psoc6 reset_halt} Command can be used to simulate broken Vector Catch from gdbinit or tcl scripts. When invoked for CM0+ target, it will set break point at application entry point and issue SYSRESETREQ. This will reset both cores and all peripherals. CM0+ will @@ -6673,14 +7535,160 @@ reset CM4 during boot anyway so this is safe. On CM4 target, VECTRESET is used instead of SYSRESETREQ to avoid unwanted reset of CM0+; @end deffn -@deffn Command {psoc6 mass_erase} num +@deffn {Command} {psoc6 mass_erase} num Erases the contents given flash bank. The @var{num} parameter is a value shown by @command{flash banks}. Note: only Main and Work flash regions support Erase operation. @end deffn @end deffn -@deffn {Flash Driver} sim3x +@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 +Flash/RAM/MMIO address space. Non-volatile storage is achieved with an +external QSPI flash; a Boot ROM provides helper functions. + +@example +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 and SWD interface. @@ -6693,17 +7701,17 @@ flash bank $_FLASHNAME sim3x 0 $_CPUROMSIZE 0 0 $_TARGETNAME There are 2 commands defined in the @var{sim3x} driver: -@deffn Command {sim3x mass_erase} +@deffn {Command} {sim3x mass_erase} Erases the complete flash. This is used to unlock the flash. And this command is only possible when using the SWD interface. @end deffn -@deffn Command {sim3x lock} +@deffn {Command} {sim3x lock} Lock the flash. To unlock use the @command{sim3x mass_erase} command. @end deffn @end deffn -@deffn {Flash Driver} stellaris +@deffn {Flash Driver} {stellaris} All members of the Stellaris LM3Sxxx, LM4x and Tiva C microcontroller families from Texas Instruments include internal flash. The driver automatically recognizes a number of these chips using the chip @@ -6713,7 +7721,7 @@ identification register, and autoconfigures itself. flash bank $_FLASHNAME stellaris 0 0 0 0 $_TARGETNAME @end example -@deffn Command {stellaris recover} +@deffn {Command} {stellaris recover} Performs the @emph{Recovering a "Locked" Device} procedure to restore the flash and its associated nonvolatile registers to their factory default values (erased). This is the only way to remove flash @@ -6729,11 +7737,11 @@ applied to all of them. @end deffn @end deffn -@deffn {Flash Driver} stm32f1x -All members of the STM32F0, STM32F1 and STM32F3 microcontroller families -from STMicroelectronics include internal flash and use ARM Cortex-M0/M3/M4 cores. -The driver automatically recognizes a number of these chips using -the chip identification register, and autoconfigures itself. +@deffn {Flash Driver} {stm32f1x} +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 @@ -6755,35 +7763,35 @@ flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME Some stm32f1x-specific commands are defined: -@deffn Command {stm32f1x lock} num +@deffn {Command} {stm32f1x lock} num Locks the entire stm32 device against reading. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32f1x unlock} num +@deffn {Command} {stm32f1x unlock} num Unlocks the entire stm32 device for reading. This command will cause a mass erase of the entire stm32 device if previously locked. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32f1x mass_erase} num +@deffn {Command} {stm32f1x mass_erase} num Mass erases the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32f1x options_read} num +@deffn {Command} {stm32f1x options_read} num Reads and displays active stm32 option bytes loaded during POR or upon executing the @command{stm32f1x options_load} command. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32f1x options_write} num (@option{SWWDG}|@option{HWWDG}) (@option{RSTSTNDBY}|@option{NORSTSTNDBY}) (@option{RSTSTOP}|@option{NORSTSTOP}) (@option{USEROPT} user_data) +@deffn {Command} {stm32f1x options_write} num (@option{SWWDG}|@option{HWWDG}) (@option{RSTSTNDBY}|@option{NORSTSTNDBY}) (@option{RSTSTOP}|@option{NORSTSTOP}) (@option{USEROPT} user_data) Writes the stm32 option byte with the specified values. The @var{num} parameter is a value shown by @command{flash banks}. The @var{user_data} parameter is content of higher 16 bits of the option byte register (Data0 and Data1 as one 16bit number). @end deffn -@deffn Command {stm32f1x options_load} num +@deffn {Command} {stm32f1x options_load} num Generates a special kind of reset to re-load the stm32 option bytes written by the @command{stm32f1x options_write} or @command{flash protect} commands without having to power cycle the target. Not applicable to stm32f1x devices. @@ -6791,9 +7799,10 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn -@deffn {Flash Driver} stm32f2x +@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. @@ -6807,7 +7816,7 @@ as per the following example. flash bank $_FLASHNAME stm32f2x 0x1FFF7800 0 0 0 $_TARGETNAME @end example -@deffn Command {stm32f2x otp } num (@option{enable}|@option{disable}|@option{show}) +@deffn {Command} {stm32f2x otp} num (@option{enable}|@option{disable}|@option{show}) Enables or disables OTP write commands for bank @var{num}. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @@ -6822,27 +7831,27 @@ flash bank $_FLASHNAME stm32f2x 0 0x20000 0 0 $_TARGETNAME Some stm32f2x-specific commands are defined: -@deffn Command {stm32f2x lock} num +@deffn {Command} {stm32f2x lock} num Locks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32f2x unlock} num +@deffn {Command} {stm32f2x unlock} num Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32f2x mass_erase} num +@deffn {Command} {stm32f2x mass_erase} num Mass erases the entire stm32f2x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32f2x options_read} num +@deffn {Command} {stm32f2x options_read} num Reads and displays user options and (where implemented) boot_addr0, boot_addr1, optcr2. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32f2x options_write} num user_options boot_addr0 boot_addr1 +@deffn {Command} {stm32f2x options_write} num user_options boot_addr0 boot_addr1 Writes user options and (where implemented) boot_addr0 and boot_addr1 in raw format. Warning: The meaning of the various bits depends on the device, always check datasheet! The @var{num} parameter is a value shown by @command{flash banks}, @var{user_options} a @@ -6850,13 +7859,13 @@ The @var{num} parameter is a value shown by @command{flash banks}, @var{user_opt @var{boot_addr1} two halfwords (of FLASH_OPTCR1). @end deffn -@deffn Command {stm32f2x optcr2_write} num optcr2 +@deffn {Command} {stm32f2x optcr2_write} num optcr2 Writes FLASH_OPTCR2 options. Warning: Clearing PCROPi bits requires a full mass erase! The @var{num} parameter is a value shown by @command{flash banks}, @var{optcr2} a 32-bit word. @end deffn @end deffn -@deffn {Flash Driver} stm32h7x +@deffn {Flash Driver} {stm32h7x} All members of the STM32H7 microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M7 core. The driver automatically recognizes a number of these chips using @@ -6876,22 +7885,22 @@ flash bank $_FLASHNAME stm32h7x 0 0x20000 0 0 $_TARGETNAME Some stm32h7x-specific commands are defined: -@deffn Command {stm32h7x lock} num +@deffn {Command} {stm32h7x lock} num Locks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32h7x unlock} num +@deffn {Command} {stm32h7x unlock} num Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32h7x mass_erase} num +@deffn {Command} {stm32h7x mass_erase} num Mass erases the entire stm32h7x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32h7x option_read} num reg_offset +@deffn {Command} {stm32h7x option_read} num reg_offset Reads an option byte register from the stm32h7x device. The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset} is the register offset of the option byte to read from the used bank registers' base. @@ -6908,7 +7917,7 @@ stm32h7x option_read 1 0x38 @end example @end deffn -@deffn Command {stm32h7x option_write} num reg_offset value [reg_mask] +@deffn {Command} {stm32h7x option_write} num reg_offset value [reg_mask] Writes an option byte register of the stm32h7x device. The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset} is the register offset of the option byte to write from the used bank register base, @@ -6917,13 +7926,14 @@ will be touched). Example usage: @example -# swap bank 1 and bank 2 in dual bank devices, by setting SWAP_BANK_OPT bit in OPTSR_PRG +# swap bank 1 and bank 2 in dual bank devices +# by setting SWAP_BANK_OPT bit in OPTSR_PRG stm32h7x option_write 0 0x20 0x8000000 0x8000000 @end example @end deffn @end deffn -@deffn {Flash Driver} stm32lx +@deffn {Flash Driver} {stm32lx} All members of the STM32L0 and STM32L1 microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M3 and Cortex-M0+ cores. The driver automatically recognizes a number of these chips using @@ -6945,17 +7955,17 @@ flash bank $_FLASHNAME stm32lx 0x08000000 0x20000 0 0 $_TARGETNAME Some stm32lx-specific commands are defined: -@deffn Command {stm32lx lock} num +@deffn {Command} {stm32lx lock} num Locks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32lx unlock} num +@deffn {Command} {stm32lx unlock} num Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32lx mass_erase} num +@deffn {Command} {stm32lx mass_erase} num Mass erases the entire stm32lx device (all flash banks and EEPROM data). This is the only way to unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). @@ -6963,11 +7973,10 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn -@deffn {Flash Driver} stm32l4x -All members of the STM32L4, STM32L4+, STM32WB, STM32WL and STM32G4 +@deffn {Flash Driver} {stm32l4x} +All members of the STM32 G0, G4, L4, L4+, L5, U5, WB and WL microcontroller families from STMicroelectronics include internal flash -and use ARM Cortex-M4 cores. -Additionally this driver supports STM32G0 family with ARM Cortex-M0+ core. +and use ARM Cortex-M0+, M4 and M33 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @@ -6975,6 +7984,17 @@ the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME @end example +If you use OTP (One-Time Programmable) memory define it as a second bank +as per the following example. +@example +flash bank $_FLASHNAME stm32l4x 0x1FFF7000 0 0 0 $_TARGETNAME +@end example + +@deffn {Command} {stm32l4x otp} num (@option{enable}|@option{disable}|@option{show}) +Enables or disables OTP write commands for bank @var{num}. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. However, specifying a wrong value might lead to a completely @@ -6986,22 +8006,26 @@ flash bank $_FLASHNAME stm32l4x 0x08000000 0x40000 0 0 $_TARGETNAME Some stm32l4x-specific commands are defined: -@deffn Command {stm32l4x lock} num +@deffn {Command} {stm32l4x lock} num Locks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. + +@emph{Note:} To apply the protection change immediately, use @command{stm32l4x option_load}. @end deffn -@deffn Command {stm32l4x unlock} num +@deffn {Command} {stm32l4x unlock} num Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. + +@emph{Note:} To apply the protection change immediately, use @command{stm32l4x option_load}. @end deffn -@deffn Command {stm32l4x mass_erase} num +@deffn {Command} {stm32l4x mass_erase} num Mass erases the entire stm32l4x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {stm32l4x option_read} num reg_offset +@deffn {Command} {stm32l4x option_read} num reg_offset Reads an option byte register from the stm32l4x device. The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset} is the register offset of the Option byte to read. @@ -7018,12 +8042,14 @@ The above example will read out the FLASH_OPTR register which contains the RDP option byte, Watchdog configuration, BOR level etc. @end deffn -@deffn Command {stm32l4x option_write} num reg_offset reg_mask +@deffn {Command} {stm32l4x option_write} num reg_offset reg_mask Write an option byte register of the stm32l4x device. The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset} is the register offset of the Option byte to write, and @var{reg_mask} is the mask to apply when writing the register (only bits with a '1' will be touched). +@emph{Note:} To apply the option bytes change immediately, use @command{stm32l4x option_load}. + For example to write the WRP1AR option bytes: @example stm32l4x option_write 0 0x28 0x00FF0000 0x00FF00FF @@ -7034,13 +8060,35 @@ Area A for bank 1. The above example set WRP1AR_END=255, WRP1AR_START=0. This will effectively write protect all sectors in flash bank 1. @end deffn -@deffn Command {stm32l4x option_load} num +@deffn {Command} {stm32l4x wrp_info} num [device_bank] +List the protected areas using WRP. +The @var{num} parameter is a value shown by @command{flash banks}. +@var{device_bank} parameter is optional, possible values 'bank1' or 'bank2', +if not specified, the command will display the whole flash protected areas. + +@b{Note:} @var{device_bank} is different from banks created using @code{flash bank}. +Devices supported in this flash driver, can have main flash memory organized +in single or dual-banks mode. +Thus the usage of @var{device_bank} is meaningful only in dual-bank mode, to get +write protected areas in a specific @var{device_bank} + +@end deffn + +@deffn {Command} {stm32l4x option_load} num Forces a re-load of the option byte registers. Will cause a system reset of the device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn + +@deffn Command {stm32l4x trustzone} num [@option{enable} | @option{disable}] +Enables or disables Global TrustZone Security, using the TZEN option bit. +If neither @option{enabled} nor @option{disable} are specified, the command will display +the TrustZone status. +@emph{Note:} This command works only with devices with TrustZone, eg. STM32L5. +@emph{Note:} This command will perform an OBL_Launch after modifying the TZEN. +@end deffn @end deffn -@deffn {Flash Driver} str7x +@deffn {Flash Driver} {str7x} All members of the STR7 microcontroller family from STMicroelectronics include internal flash and use ARM7TDMI cores. The @var{str7x} driver defines one mandatory parameter, @var{variant}, @@ -7051,13 +8099,13 @@ flash bank $_FLASHNAME str7x \ 0x40000000 0x00040000 0 0 $_TARGETNAME STR71x @end example -@deffn Command {str7x disable_jtag} bank +@deffn {Command} {str7x disable_jtag} bank Activate the Debug/Readout protection mechanism for the specified flash bank. @end deffn @end deffn -@deffn {Flash Driver} str9x +@deffn {Flash Driver} {str9x} Most members of the STR9 microcontroller family from STMicroelectronics include internal flash and use ARM966E cores. The str9 needs the flash controller to be configured using @@ -7068,7 +8116,7 @@ flash bank $_FLASHNAME str9x 0x40000000 0x00040000 0 0 $_TARGETNAME str9x flash_config 0 4 2 0 0x80000 @end example -@deffn Command {str9x flash_config} num bbsr nbbsr bbadr nbbadr +@deffn {Command} {str9x flash_config} num bbsr nbbsr bbadr nbbadr Configures the str9 flash controller. The @var{num} parameter is a value shown by @command{flash banks}. @@ -7082,7 +8130,7 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn {Flash Driver} str9xpec +@deffn {Flash Driver} {str9xpec} @cindex str9xpec Only use this driver for locking/unlocking the device or configuring the option bytes. @@ -7129,55 +8177,55 @@ as mentioned above, just issue the commands above manually or from a telnet prom Several str9xpec-specific commands are defined: -@deffn Command {str9xpec disable_turbo} num +@deffn {Command} {str9xpec disable_turbo} num Restore the str9 into JTAG chain. @end deffn -@deffn Command {str9xpec enable_turbo} num +@deffn {Command} {str9xpec enable_turbo} num Enable turbo mode, will simply remove the str9 from the chain and talk directly to the embedded flash controller. @end deffn -@deffn Command {str9xpec lock} num +@deffn {Command} {str9xpec lock} num Lock str9 device. The str9 will only respond to an unlock command that will erase the device. @end deffn -@deffn Command {str9xpec part_id} num +@deffn {Command} {str9xpec part_id} num Prints the part identifier for bank @var{num}. @end deffn -@deffn Command {str9xpec options_cmap} num (@option{bank0}|@option{bank1}) +@deffn {Command} {str9xpec options_cmap} num (@option{bank0}|@option{bank1}) Configure str9 boot bank. @end deffn -@deffn Command {str9xpec options_lvdsel} num (@option{vdd}|@option{vdd_vddq}) +@deffn {Command} {str9xpec options_lvdsel} num (@option{vdd}|@option{vdd_vddq}) Configure str9 lvd source. @end deffn -@deffn Command {str9xpec options_lvdthd} num (@option{2.4v}|@option{2.7v}) +@deffn {Command} {str9xpec options_lvdthd} num (@option{2.4v}|@option{2.7v}) Configure str9 lvd threshold. @end deffn -@deffn Command {str9xpec options_lvdwarn} bank (@option{vdd}|@option{vdd_vddq}) +@deffn {Command} {str9xpec options_lvdwarn} bank (@option{vdd}|@option{vdd_vddq}) Configure str9 lvd reset warning source. @end deffn -@deffn Command {str9xpec options_read} num +@deffn {Command} {str9xpec options_read} num Read str9 option bytes. @end deffn -@deffn Command {str9xpec options_write} num +@deffn {Command} {str9xpec options_write} num Write str9 option bytes. @end deffn -@deffn Command {str9xpec unlock} num +@deffn {Command} {str9xpec unlock} num unlock str9 device. @end deffn @end deffn -@deffn {Flash Driver} swm050 +@deffn {Flash Driver} {swm050} @cindex swm050 All members of the swm050 microcontroller family from Foshan Synwit Tech. @@ -7187,35 +8235,35 @@ flash bank $_FLASHNAME swm050 0x0 0x2000 0 0 $_TARGETNAME One swm050-specific command is defined: -@deffn Command {swm050 mass_erase} bank_id +@deffn {Command} {swm050 mass_erase} bank_id Erases the entire flash bank. @end deffn @end deffn -@deffn {Flash Driver} tms470 +@deffn {Flash Driver} {tms470} Most members of the TMS470 microcontroller family from Texas Instruments include internal flash and use ARM7TDMI cores. This driver doesn't require the chip and bus width to be specified. Some tms470-specific commands are defined: -@deffn Command {tms470 flash_keyset} key0 key1 key2 key3 +@deffn {Command} {tms470 flash_keyset} key0 key1 key2 key3 Saves programming keys in a register, to enable flash erase and write commands. @end deffn -@deffn Command {tms470 osc_mhz} clock_mhz +@deffn {Command} {tms470 osc_megahertz} clock_mhz Reports the clock speed, which is used to calculate timings. @end deffn -@deffn Command {tms470 plldis} (0|1) +@deffn {Command} {tms470 plldis} (0|1) Disables (@var{1}) or enables (@var{0}) use of the PLL to speed up the flash clock. @end deffn @end deffn -@deffn {Flash Driver} w600 +@deffn {Flash Driver} {w600} W60x series Wi-Fi SoC from WinnerMicro are designed with ARM Cortex-M3 and have 1M Byte QFLASH inside. The @var{w600} driver uses the @var{target} parameter to select the @@ -7226,22 +8274,22 @@ flash bank $_FLASHNAME w600 0x08000000 0 0 0 $_TARGETNAMEs @end example @end deffn -@deffn {Flash Driver} xmc1xxx +@deffn {Flash Driver} {xmc1xxx} All members of the XMC1xxx microcontroller family from Infineon. This driver does not require the chip and bus width to be specified. @end deffn -@deffn {Flash Driver} xmc4xxx +@deffn {Flash Driver} {xmc4xxx} All members of the XMC4xxx microcontroller family from Infineon. This driver does not require the chip and bus width to be specified. Some xmc4xxx-specific commands are defined: -@deffn Command {xmc4xxx flash_password} bank_id passwd1 passwd2 +@deffn {Command} {xmc4xxx flash_password} bank_id passwd1 passwd2 Saves flash protection passwords which are used to lock the user flash @end deffn -@deffn Command {xmc4xxx flash_unprotect} bank_id user_level[0-1] +@deffn {Command} {xmc4xxx flash_unprotect} bank_id user_level[0-1] Removes Flash write protection from the selected user bank @end deffn @@ -7346,7 +8394,7 @@ for more information. @end itemize @end deffn -@deffn Command {nand list} +@deffn {Command} {nand list} Prints a summary of each device declared using @command{nand device}, numbered from zero. Note that un-probed devices show no details. @@ -7360,7 +8408,7 @@ Note that un-probed devices show no details. @end example @end deffn -@deffn Command {nand probe} num +@deffn {Command} {nand probe} num Probes the specified device to determine key characteristics like its page and block sizes, and how many blocks it has. The @var{num} parameter is the value shown by @command{nand list}. @@ -7370,7 +8418,7 @@ it with most other NAND commands. @subsection Erasing, Reading, Writing to NAND Flash -@deffn Command {nand dump} num filename offset length [oob_option] +@deffn {Command} {nand dump} num filename offset length [oob_option] @cindex NAND reading Reads binary data from the NAND device and writes it to the file, starting at the specified offset. @@ -7407,7 +8455,7 @@ spare areas associated with each data page. @end itemize @end deffn -@deffn Command {nand erase} num [offset length] +@deffn {Command} {nand erase} num [offset length] @cindex NAND erasing @cindex NAND programming Erases blocks on the specified NAND device, starting at the @@ -7425,7 +8473,7 @@ For the remainder of the current server session, @command{nand info} will still report that the block ``is'' bad. @end deffn -@deffn Command {nand write} num filename offset [option...] +@deffn {Command} {nand write} num filename offset [option...] @cindex NAND writing @cindex NAND programming Writes binary data from the file into the specified NAND device, @@ -7484,7 +8532,7 @@ the underlying driver from applying hardware ECC. @end itemize @end deffn -@deffn Command {nand verify} num filename offset [option...] +@deffn {Command} {nand verify} num filename offset [option...] @cindex NAND verification @cindex NAND programming Verify the binary data in the file has been programmed to the @@ -7513,7 +8561,7 @@ be removed in a future release. @subsection Other NAND commands @cindex NAND other commands -@deffn Command {nand check_bad_blocks} num [offset length] +@deffn {Command} {nand check_bad_blocks} num [offset length] Checks for manufacturer bad block markers on the specified NAND device. If no parameters are provided, checks the whole device; otherwise, starts at the specified @var{offset} and @@ -7527,14 +8575,14 @@ with @command{nand raw_access enable} to ensure that the underlying driver will not try to apply hardware ECC. @end deffn -@deffn Command {nand info} num +@deffn {Command} {nand info} num The @var{num} parameter is the value shown by @command{nand list}. This prints the one-line summary from "nand list", plus for devices which have been probed this also prints any known status for each block. @end deffn -@deffn Command {nand raw_access} num (@option{enable}|@option{disable}) +@deffn {Command} {nand raw_access} num (@option{enable}|@option{disable}) Sets or clears an flag affecting how page I/O is done. The @var{num} parameter is the value shown by @command{nand list}. @@ -7559,7 +8607,7 @@ As noted above, the @command{nand device} command allows driver-specific options and behaviors. Some controllers also activate controller-specific commands. -@deffn {NAND Driver} at91sam9 +@deffn {NAND Driver} {at91sam9} This driver handles the NAND controllers found on AT91SAM9 family chips from Atmel. It takes two extra parameters: address of the NAND chip; address of the ECC controller. @@ -7571,30 +8619,30 @@ AT91SAM9 chips support single-bit ECC hardware. The @code{write_page} and disabled by using the @command{nand raw_access} command. There are four additional commands that are needed to fully configure the AT91SAM9 NAND controller. Two are optional; most boards use the same wiring for ALE/CLE: -@deffn Command {at91sam9 cle} num addr_line +@deffn {Config Command} {at91sam9 cle} num addr_line Configure the address line used for latching commands. The @var{num} parameter is the value shown by @command{nand list}. @end deffn -@deffn Command {at91sam9 ale} num addr_line +@deffn {Config Command} {at91sam9 ale} num addr_line Configure the address line used for latching addresses. The @var{num} parameter is the value shown by @command{nand list}. @end deffn For the next two commands, it is assumed that the pins have already been properly configured for input or output. -@deffn Command {at91sam9 rdy_busy} num pio_base_addr pin +@deffn {Config Command} {at91sam9 rdy_busy} num pio_base_addr pin Configure the RDY/nBUSY input from the NAND device. The @var{num} parameter is the value shown by @command{nand list}. @var{pio_base_addr} is the base address of the PIO controller and @var{pin} is the pin number. @end deffn -@deffn Command {at91sam9 ce} num pio_base_addr pin +@deffn {Config Command} {at91sam9 ce} num pio_base_addr pin Configure the chip enable input to the NAND device. The @var{num} parameter is the value shown by @command{nand list}. @var{pio_base_addr} is the base address of the PIO controller and @var{pin} is the pin number. @end deffn @end deffn -@deffn {NAND Driver} davinci +@deffn {NAND Driver} {davinci} This driver handles the NAND controllers found on DaVinci family chips from Texas Instruments. It takes three extra parameters: @@ -7612,10 +8660,10 @@ to implement those ECC modes, unless they are disabled using the @command{nand raw_access} command. @end deffn -@deffn {NAND Driver} lpc3180 +@deffn {NAND Driver} {lpc3180} These controllers require an extra @command{nand device} parameter: the clock rate used by the controller. -@deffn Command {lpc3180 select} num [mlc|slc] +@deffn {Command} {lpc3180 select} num [mlc|slc] Configures use of the MLC or SLC controller mode. MLC implies use of hardware ECC. The @var{num} parameter is the value shown by @command{nand list}. @@ -7628,12 +8676,12 @@ in the MLC controller mode, but won't change SLC behavior. @end deffn @comment current lpc3180 code won't issue 5-byte address cycles -@deffn {NAND Driver} mx3 +@deffn {NAND Driver} {mx3} This driver handles the NAND controller in i.MX31. The mxc driver should work for this chip as well. @end deffn -@deffn {NAND Driver} mxc +@deffn {NAND Driver} {mxc} This driver handles the NAND controller found in Freescale i.MX chips. It has support for v1 (i.MX27 and i.MX31) and v2 (i.MX35). The driver takes 3 extra arguments, chip (@option{mx27}, @@ -7643,13 +8691,13 @@ main area and spare area (@option{biswap}), defaults to off. @example nand device mx35.nand mxc imx35.cpu mx35 hwecc biswap @end example -@deffn Command {mxc biswap} bank_num [enable|disable] +@deffn {Command} {mxc biswap} bank_num [enable|disable] Turns on/off bad block information swapping from main area, without parameter query status. @end deffn @end deffn -@deffn {NAND Driver} orion +@deffn {NAND Driver} {orion} These controllers require an extra @command{nand device} parameter: the address of the controller. @example @@ -7661,11 +8709,11 @@ or @code{read_page} methods, so @command{nand raw_access} won't change any behavior. @end deffn -@deffn {NAND Driver} s3c2410 -@deffnx {NAND Driver} s3c2412 -@deffnx {NAND Driver} s3c2440 -@deffnx {NAND Driver} s3c2443 -@deffnx {NAND Driver} s3c6400 +@deffn {NAND Driver} {s3c2410} +@deffnx {NAND Driver} {s3c2412} +@deffnx {NAND Driver} {s3c2440} +@deffnx {NAND Driver} {s3c2443} +@deffnx {NAND Driver} {s3c6400} These S3C family controllers don't have any special @command{nand device} options, and don't define any specialized commands. @@ -7725,24 +8773,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 @@ -7752,20 +8803,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 @@ -7791,17 +8968,17 @@ 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 @section Server Commands -@deffn {Command} exit +@deffn {Command} {exit} Exits the current telnet session. @end deffn -@deffn {Command} help [string] +@deffn {Command} {help} [string] With no parameters, prints help text for all commands. Otherwise, prints each helptext containing @var{string}. Not every command provides helptext. @@ -7812,7 +8989,14 @@ In most cases, no such restriction is listed; this indicates commands which are only available after the configuration stage has completed. @end deffn -@deffn Command sleep msec [@option{busy}] +@deffn {Command} {usage} [string] +With no parameters, prints usage text for all commands. Otherwise, +prints all usage text of which command, help text, and usage text +containing @var{string}. +Not every command provides helptext. +@end deffn + +@deffn {Command} {sleep} msec [@option{busy}] Wait for at least @var{msec} milliseconds before resuming. If @option{busy} is passed, busy-wait instead of sleeping. (This option is strongly discouraged.) @@ -7820,27 +9004,28 @@ Useful in connection with script files (@command{script} command and @command{target_name} configuration). @end deffn -@deffn Command shutdown [@option{error}] +@deffn {Command} {shutdown} [@option{error}] 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} -@deffn Command debug_level [n] +@deffn {Command} {debug_level} [n] @cindex message level Display debug level. If @var{n} (from 0..4) is provided, then set it to that level. @@ -7856,25 +9041,25 @@ file (which is normally the server's standard output). @xref{Running}. @end deffn -@deffn Command echo [-n] message +@deffn {Command} {echo} [-n] message Logs a message at "user" priority. -Output @var{message} to stdout. Option "-n" suppresses trailing newline. @example 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] +@deffn {Command} {add_script_search_dir} [directory] Add @var{directory} to the file/script search path. @end deffn -@deffn Command bindto [@var{name}] +@deffn {Config Command} {bindto} [@var{name}] Specify hostname or IPv4 address on which to listen for incoming TCP/IP connections. By default, OpenOCD will listen on the loopback interface only. If your network environment is safe, @code{bindto @@ -7895,7 +9080,7 @@ various operations. The current target may be changed by using @command{targets} command with the name of the target which should become current. -@deffn Command reg [(number|name) [(value|'force')]] +@deffn {Command} {reg} [(number|name) [(value|'force')]] Access a single register by @var{number} or by its @var{name}. The target must generally be halted before access to CPU core registers is allowed. Depending on the hardware, some other @@ -7934,20 +9119,92 @@ Debug and trace infrastructure: @end example @end deffn -@deffn Command halt [ms] -@deffnx Command wait_halt [ms] -The @command{halt} command first sends a halt request to the target, -which @command{wait_halt} doesn't. -Otherwise these behave the same: wait up to @var{ms} milliseconds, -or 5 seconds if there is no parameter, for the target to halt -(and enter debug mode). -Using 0 as the @var{ms} parameter prevents OpenOCD from waiting. +@deffn {Command} {set_reg} dict +Set register values of the target. -@quotation Warning -On ARM cores, software using the @emph{wait for interrupt} operation -often blocks the JTAG access needed by a @command{halt} command. -This is because that operation also puts the core into a low -power mode by gating the core clock; +@itemize +@item @var{dict} ... Tcl dictionary with pairs of register names and values. +@end itemize + +For example, the following command sets the value 0 to the program counter (pc) +register and 0x1000 to the stack pointer (sp) register: + +@example +set_reg @{pc 0 sp 0x1000@} +@end example +@end deffn + +@deffn {Command} {get_reg} [-force] list +Get register values from the target and return them as Tcl dictionary with pairs +of register names and values. +If option "-force" is set, the register values are read directly from the +target, bypassing any caching. + +@itemize +@item @var{list} ... List of register names +@end itemize + +For example, the following command retrieves the values from the program +counter (pc) and stack pointer (sp) register: + +@example +get_reg @{pc sp@} +@end example +@end deffn + +@deffn {Command} {write_memory} address width data ['phys'] +This function provides an efficient way to write to the target memory from a Tcl +script. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{data} ... Tcl list with the elements to write +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command writes two 32 bit words into the target +memory at address 0x20000000: + +@example +write_memory 0x20000000 32 @{0xdeadbeef 0x00230500@} +@end example +@end deffn + +@deffn {Command} {read_memory} address width count ['phys'] +This function provides an efficient way to read the target memory from a Tcl +script. +A Tcl list containing the requested memory elements is returned by this function. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{count} ... number of elements to read +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command reads two 32 bit words from the target +memory at address 0x20000000: + +@example +read_memory 0x20000000 32 2 +@end example +@end deffn + +@deffn {Command} {halt} [ms] +@deffnx {Command} {wait_halt} [ms] +The @command{halt} command first sends a halt request to the target, +which @command{wait_halt} doesn't. +Otherwise these behave the same: wait up to @var{ms} milliseconds, +or 5 seconds if there is no parameter, for the target to halt +(and enter debug mode). +Using 0 as the @var{ms} parameter prevents OpenOCD from waiting. + +@quotation Warning +On ARM cores, software using the @emph{wait for interrupt} operation +often blocks the JTAG access needed by a @command{halt} command. +This is because that operation also puts the core into a low +power mode by gating the core clock; but the core clock is needed to detect JTAG clock transitions. One partial workaround uses adaptive clocking: when the core is @@ -7969,22 +9226,21 @@ power consumption (because the CPU is needlessly clocked). @end deffn -@deffn Command resume [address] +@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] +@deffn {Command} {step} [address] Single-step the target at its current code position, or the optional @var{address} if it is provided. @end deffn @anchor{resetcommand} -@deffn Command reset -@deffnx Command {reset run} -@deffnx Command {reset halt} -@deffnx Command {reset init} +@deffn {Command} {reset} +@deffnx {Command} {reset run} +@deffnx {Command} {reset halt} +@deffnx {Command} {reset init} Perform as hard a reset as possible, using SRST if possible. @emph{All defined targets will be reset, and target events will fire during the reset sequence.} @@ -8002,7 +9258,7 @@ The other options will not work on all systems. @end itemize @end deffn -@deffn Command soft_reset_halt +@deffn {Command} {soft_reset_halt} Requesting target halt and executing a soft reset. This is often used when a target cannot be reset and halted. The target, after reset is released begins to execute code. OpenOCD attempts to stop the CPU and @@ -8011,8 +9267,8 @@ the code that was executed may have left the hardware in an unknown state. @end deffn -@deffn Command {adapter assert} [signal [assert|deassert signal]] -@deffnx Command {adapter deassert} [signal [assert|deassert signal]] +@deffn {Command} {adapter assert} [signal [assert|deassert signal]] +@deffnx {Command} {adapter deassert} [signal [assert|deassert signal]] Set values of reset signals. Without parameters returns current status of the signals. The @var{signal} parameter values may be @@ -8041,66 +9297,6 @@ with handlers for that event. @end quotation @end deffn -@section I/O Utilities - -These commands are available when -OpenOCD is built with @option{--enable-ioutil}. -They are mainly useful on embedded targets, -notably the ZY1000. -Hosts with operating systems have complementary tools. - -@emph{Note:} there are several more such commands. - -@deffn Command append_file filename [string]* -Appends the @var{string} parameters to -the text file @file{filename}. -Each string except the last one is followed by one space. -The last string is followed by a newline. -@end deffn - -@deffn Command cat filename -Reads and displays the text file @file{filename}. -@end deffn - -@deffn Command cp src_filename dest_filename -Copies contents from the file @file{src_filename} -into @file{dest_filename}. -@end deffn - -@deffn Command ip -@emph{No description provided.} -@end deffn - -@deffn Command ls -@emph{No description provided.} -@end deffn - -@deffn Command mac -@emph{No description provided.} -@end deffn - -@deffn Command meminfo -Display available RAM memory on OpenOCD host. -Used in OpenOCD regression testing scripts. -@end deffn - -@deffn Command peek -@emph{No description provided.} -@end deffn - -@deffn Command poke -@emph{No description provided.} -@end deffn - -@deffn Command rm filename -@c "rm" has both normal and Jim-level versions?? -Unlinks the file @file{filename}. -@end deffn - -@deffn Command trunc filename -Removes all data in the file @file{filename}. -@end deffn - @anchor{memoryaccess} @section Memory access commands @cindex memory access @@ -8118,10 +9314,10 @@ Please use their TARGET object siblings to avoid making assumptions about what TAP is the current target, or about MMU configuration. @end enumerate -@deffn Command mdd [phys] addr [count] -@deffnx Command mdw [phys] addr [count] -@deffnx Command mdh [phys] addr [count] -@deffnx Command mdb [phys] addr [count] +@deffn {Command} {mdd} [phys] addr [count] +@deffnx {Command} {mdw} [phys] addr [count] +@deffnx {Command} {mdh} [phys] addr [count] +@deffnx {Command} {mdb} [phys] addr [count] Display contents of address @var{addr}, as 64-bit doublewords (@command{mdd}), 32-bit words (@command{mdw}), 16-bit halfwords (@command{mdh}), @@ -8131,14 +9327,14 @@ When the current target has an MMU which is present and active, Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. If @var{count} is specified, displays that many units. -(If you want to manipulate the data instead of displaying it, -see the @code{mem2array} primitives.) +(If you want to process the data instead of displaying it, +see the @code{read_memory} primitives.) @end deffn -@deffn Command mwd [phys] addr doubleword [count] -@deffnx Command mww [phys] addr word [count] -@deffnx Command mwh [phys] addr halfword [count] -@deffnx Command mwb [phys] addr byte [count] +@deffn {Command} {mwd} [phys] addr doubleword [count] +@deffnx {Command} {mww} [phys] addr word [count] +@deffnx {Command} {mwh} [phys] addr halfword [count] +@deffnx {Command} {mwb} [phys] addr byte [count] Writes the specified @var{doubleword} (64 bits), @var{word} (32 bits), @var{halfword} (16 bits), or @var{byte} (8-bit) value, at the specified address @var{addr}. @@ -8154,17 +9350,17 @@ If @var{count} is specified, fills that many units of consecutive address. @cindex image loading @cindex image dumping -@deffn Command {dump_image} filename address size +@deffn {Command} {dump_image} filename address size Dump @var{size} bytes of target memory starting at @var{address} to the binary file named @var{filename}. @end deffn -@deffn Command {fast_load} +@deffn {Command} {fast_load} 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 @@ -8175,8 +9371,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: @@ -8186,13 +9384,13 @@ In addition the following arguments may be specified: proc load_image_bin @{fname foffset address length @} @{ # Load data from fname filename at foffset offset to # target at address. Load at most length bytes. - load_image $fname [expr $address - $foffset] bin \ + load_image $fname [expr @{$address - $foffset@}] bin \ $address $length @} @end example @end deffn -@deffn Command {test_image} filename [address [@option{bin}|@option{ihex}|@option{elf}]] +@deffn {Command} {test_image} filename [address [@option{bin}|@option{ihex}|@option{elf}]] Displays image section sizes and addresses as if @var{filename} were loaded into target memory starting at @var{address} (defaults to zero). @@ -8200,15 +9398,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 @@ -8224,7 +9428,7 @@ hardware support for a handful of code breakpoints and data watchpoints. In addition, CPUs almost always support software breakpoints. -@deffn Command {bp} [address len [@option{hw}]] +@deffn {Command} {bp} [address len [@option{hw}]] With no parameters, lists all active breakpoints. Else sets a breakpoint on code execution starting at @var{address} for @var{length} bytes. @@ -8235,15 +9439,15 @@ in which case it will be a hardware breakpoint. for similar mechanisms that do not consume hardware breakpoints.) @end deffn -@deffn Command {rbp} @option{all} | address +@deffn {Command} {rbp} @option{all} | address 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 @@ -8254,26 +9458,125 @@ the watchpoint should trigger. The value may be first be masked using @var{mask} to mark ``don't care'' fields. @end deffn + +@section Real Time Transfer (RTT) + +Real Time Transfer (RTT) is an interface specified by SEGGER based on basic +memory reads and writes to transfer data bidirectionally between target and host. +The specification is independent of the target architecture. +Every target that supports so called "background memory access", which means +that the target memory can be accessed by the debugger while the target is +running, can be used. +This interface is especially of interest for targets without +Serial Wire Output (SWO), such as ARM Cortex-M0, or where semihosting is not +applicable because of real-time constraints. + +@quotation Note +The current implementation supports only single target devices. +@end quotation + +The data transfer between host and target device is organized through +unidirectional up/down-channels for target-to-host and host-to-target +communication, respectively. + +@quotation Note +The current implementation does not respect channel buffer flags. +They are used to determine what happens when writing to a full buffer, for +example. +@end quotation + +Channels are exposed via raw TCP/IP connections. One or more RTT servers can be +assigned to each channel to make them accessible to an unlimited number +of TCP/IP connections. + +@deffn {Command} {rtt setup} address size ID +Configure RTT for the currently selected target. +Once RTT is started, OpenOCD searches for a control block with the +identifier @var{ID} starting at the memory address @var{address} within the next +@var{size} bytes. +@end deffn + +@deffn {Command} {rtt start} +Start RTT. +If the control block location is not known, OpenOCD starts searching for it. +@end deffn + +@deffn {Command} {rtt stop} +Stop RTT. +@end deffn + +@deffn {Command} {rtt polling_interval} [interval] +Display the polling interval. +If @var{interval} is provided, set the polling interval. +The polling interval determines (in milliseconds) how often the up-channels are +checked for new data. +@end deffn + +@deffn {Command} {rtt channels} +Display a list of all channels and their properties. +@end deffn + +@deffn {Command} {rtt channellist} +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 [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 +Stop the TCP sever with port @var{port}. +@end deffn + +The following example shows how to setup RTT using the SEGGER RTT implementation +on the target device. + +@example +resume + +rtt setup 0x20000000 2048 "SEGGER RTT" +rtt start + +rtt server start 9090 0 +@end example + +In this example, OpenOCD searches the control block with the ID "SEGGER RTT" +starting at 0x20000000 for 2048 bytes. The RTT channel 0 is exposed through the +TCP/IP port 9090. + + @section Misc Commands @cindex profiling -@deffn Command {profile} seconds filename [start end] +@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 +@deffn {Command} {virt2phys} virtual_address Requests the current target to map the specified @var{virtual_address} to its corresponding physical address, and displays the result. @end deffn +@deffn {Command} {add_help_text} 'command_name' 'help-string' +Add or replace help text on the given @var{command_name}. +@end deffn + +@deffn {Command} {add_usage_text} 'command_name' 'help-string' +Add or replace usage text on the given @var{command_name}. +@end deffn + @node Architecture and Core Commands @chapter Architecture and Core Commands @cindex Architecture Specific Commands @@ -8378,21 +9681,21 @@ what CPU activities are traced. @end quotation @end deffn -@deffn Command {etm info} +@deffn {Command} {etm info} Displays information about the current target's ETM. This includes resource counts from the @code{ETM_CONFIG} register, as well as silicon capabilities (except on rather old modules). from the @code{ETM_SYS_CONFIG} register. @end deffn -@deffn Command {etm status} +@deffn {Command} {etm status} Displays status of the current target's ETM and trace port driver: is the ETM idle, or is it collecting data? Did trace data overflow? Was it triggered? @end deffn -@deffn Command {etm tracemode} [type context_id_bits cycle_accurate branch_output] +@deffn {Command} {etm tracemode} [type context_id_bits cycle_accurate branch_output] Displays what data that ETM will collect. If arguments are provided, first configures that data. When the configuration changes, tracing is stopped @@ -8416,7 +9719,7 @@ trace stream without an image of the code. @end itemize @end deffn -@deffn Command {etm trigger_debug} (@option{enable}|@option{disable}) +@deffn {Command} {etm trigger_debug} (@option{enable}|@option{disable}) Displays whether ETM triggering debug entry (like a breakpoint) is enabled or disabled, after optionally modifying that configuration. The default behaviour is @option{disable}. @@ -8463,28 +9766,28 @@ model with sequencer triggers which on entry and exit to the IRQ handler. At this writing, September 2009, there are no Tcl utility procedures to help set up any common tracing scenarios. -@deffn Command {etm analyze} +@deffn {Command} {etm analyze} Reads trace data into memory, if it wasn't already present. Decodes and prints the data that was collected. @end deffn -@deffn Command {etm dump} filename +@deffn {Command} {etm dump} filename Stores the captured trace data in @file{filename}. @end deffn -@deffn Command {etm image} filename [base_address] [type] +@deffn {Command} {etm image} filename [base_address] [type] Opens an image file. @end deffn -@deffn Command {etm load} filename +@deffn {Command} {etm load} filename Loads captured trace data from @file{filename}. @end deffn -@deffn Command {etm start} +@deffn {Command} {etm start} Starts trace data collection. @end deffn -@deffn Command {etm stop} +@deffn {Command} {etm stop} Stops trace data collection. @end deffn @@ -8493,7 +9796,7 @@ Stops trace data collection. To use an ETM trace port it must be associated with a driver. -@deffn {Trace Port Driver} dummy +@deffn {Trace Port Driver} {dummy} Use the @option{dummy} driver if you are configuring an ETM that's not connected to anything (on-chip ETB or off-chip trace connector). @emph{This driver lets OpenOCD talk to the ETM, but it does not expose @@ -8503,14 +9806,14 @@ Associates the ETM for @var{target} with a dummy driver. @end deffn @end deffn -@deffn {Trace Port Driver} etb +@deffn {Trace Port Driver} {etb} Use the @option{etb} driver if you are configuring an ETM to use on-chip ETB memory. @deffn {Config Command} {etb config} target etb_tap Associates the ETM for @var{target} with the ETB at @var{etb_tap}. You can see the ETB registers using the @command{reg} command. @end deffn -@deffn Command {etb trigger_percent} [percent] +@deffn {Command} {etb trigger_percent} [percent] This displays, or optionally changes, ETB behavior after the ETM's configured @emph{trigger} event fires. It controls how much more trace data is saved after the (single) @@ -8534,29 +9837,6 @@ how the event caused trouble. @end deffn -@deffn {Trace Port Driver} oocd_trace -This driver isn't available unless OpenOCD was explicitly configured -with the @option{--enable-oocd_trace} option. You probably don't want -to configure it unless you've built the appropriate prototype hardware; -it's @emph{proof-of-concept} software. - -Use the @option{oocd_trace} driver if you are configuring an ETM that's -connected to an off-chip trace connector. - -@deffn {Config Command} {oocd_trace config} target tty -Associates the ETM for @var{target} with a trace driver which -collects data through the serial port @var{tty}. -@end deffn - -@deffn Command {oocd_trace resync} -Re-synchronizes with the capture clock. -@end deffn - -@deffn Command {oocd_trace status} -Reports whether the capture clock is locked or not. -@end deffn -@end deffn - @anchor{armcrosstrigger} @section ARM Cross-Trigger Interface @cindex CTI @@ -8568,45 +9848,48 @@ CTI is mandatory for core run control and each core has an individual CTI instance attached to it. OpenOCD has limited support for CTI using the @emph{cti} group of commands. -@deffn Command {cti create} cti_name @option{-dap} dap_name @option{-ap-num} apn @option{-ctibase} base_address +@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. @end deffn -@deffn Command {$cti_name enable} @option{on|off} +@deffn {Command} {$cti_name enable} @option{on|off} Enable (@option{on}) or disable (@option{off}) the CTI. @end deffn -@deffn Command {$cti_name dump} +@deffn {Command} {$cti_name dump} Displays a register dump of the CTI. @end deffn -@deffn Command {$cti_name write } @var{reg_name} @var{value} +@deffn {Command} {$cti_name write} @var{reg_name} @var{value} Write @var{value} to the CTI register with the symbolic name @var{reg_name}. @end deffn -@deffn Command {$cti_name read} @var{reg_name} +@deffn {Command} {$cti_name read} @var{reg_name} Print the value read from the CTI register with the symbolic name @var{reg_name}. @end deffn -@deffn Command {$cti_name ack} @var{event} +@deffn {Command} {$cti_name ack} @var{event} Acknowledge a CTI @var{event}. @end deffn -@deffn Command {$cti_name channel} @var{channel_number} @var{operation} +@deffn {Command} {$cti_name channel} @var{channel_number} @var{operation} Perform a specific channel operation, the possible operations are: gate, ungate, set, clear and pulse @end deffn -@deffn Command {$cti_name testmode} @option{on|off} +@deffn {Command} {$cti_name testmode} @option{on|off} Enable (@option{on}) or disable (@option{off}) the integration test mode of the CTI. @end deffn -@deffn Command {cti names} +@deffn {Command} {cti names} Prints a list of names of all CTI objects created. This command is mainly useful in TCL scripting. @end deffn @@ -8618,7 +9901,7 @@ These commands should be available on all ARM processors. They are available in addition to other core-specific commands that may be available. -@deffn Command {arm core_state} [@option{arm}|@option{thumb}] +@deffn {Command} {arm core_state} [@option{arm}|@option{thumb}] Displays the core_state, optionally changing it to process either @option{arm} or @option{thumb} instructions. The target may later be resumed in the currently set core_state. @@ -8626,7 +9909,7 @@ The target may later be resumed in the currently set core_state. that is not currently supported in OpenOCD.) @end deffn -@deffn Command {arm disassemble} address [count [@option{thumb}]] +@deffn {Command} {arm disassemble} address [count [@option{thumb}]] @cindex disassemble Disassembles @var{count} instructions starting at @var{address}. If @var{count} is not specified, a single instruction is disassembled. @@ -8644,7 +9927,7 @@ with a handful of exceptions. ThumbEE disassembly currently has no explicit support. @end deffn -@deffn Command {arm mcr} pX op1 CRn CRm op2 value +@deffn {Command} {arm mcr} pX op1 CRn CRm op2 value Write @var{value} to a coprocessor @var{pX} register passing parameters @var{CRn}, @var{CRm}, opcodes @var{opc1} and @var{opc2}, @@ -8653,7 +9936,7 @@ and using the MCR instruction. an ARM register.) @end deffn -@deffn Command {arm mrc} pX coproc op1 CRn CRm op2 +@deffn {Command} {arm mrc} pX coproc op1 CRn CRm op2 Read a coprocessor @var{pX} register passing parameters @var{CRn}, @var{CRm}, opcodes @var{opc1} and @var{opc2}, and the MRC instruction. @@ -8662,12 +9945,12 @@ Returns the result so it can be manipulated by Jim scripts. an ARM register.) @end deffn -@deffn Command {arm reg} +@deffn {Command} {arm reg} Display a table of all banked core registers, fetching the current value from every core mode if necessary. @end deffn -@deffn Command {arm semihosting} [@option{enable}|@option{disable}] +@deffn {Command} {arm semihosting} [@option{enable}|@option{disable}] @cindex ARM semihosting Display status of semihosting, after optionally changing that status. @@ -8679,7 +9962,18 @@ requests by using a special SVC instruction that is trapped at the Supervisor Call vector by OpenOCD. @end deffn -@deffn Command {arm semihosting_cmdline} [@option{enable}|@option{disable}] +@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 + +@deffn {Command} {arm semihosting_cmdline} [@option{enable}|@option{disable}] @cindex ARM semihosting Set the command line to be passed to the debugger. @@ -8693,7 +9987,7 @@ standard C environment (argv[0]). Depending on the program (not much programs look at argv[0]), argv0 is ignored and can be any string. @end deffn -@deffn Command {arm semihosting_fileio} [@option{enable}|@option{disable}] +@deffn {Command} {arm semihosting_fileio} [@option{enable}|@option{disable}] @cindex ARM semihosting Display status of semihosting fileio, after optionally changing that status. @@ -8704,7 +9998,7 @@ interacting with remote files or displaying console messages in the debugger. @end deffn -@deffn Command {arm semihosting_resexit} [@option{enable}|@option{disable}] +@deffn {Command} {arm semihosting_resexit} [@option{enable}|@option{disable}] @cindex ARM semihosting Enable resumable SEMIHOSTING_SYS_EXIT. @@ -8728,6 +10022,23 @@ To make the SEMIHOSTING_SYS_EXIT call return normally, enable this option (default: disabled). @end deffn +@deffn {Command} {arm semihosting_read_user_param} +@cindex ARM semihosting +Read parameter of the semihosting call from the target. Usable in +semihosting-user-cmd-0x10* event handlers, returning a string. + +When the target makes semihosting call with operation number from range 0x100- +0x107, an optional string parameter can be passed to the server. This parameter +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 @@ -8746,7 +10057,7 @@ ARM9TDMI, ARM920T or ARM926EJ-S. They are available in addition to the ARM commands, and any other core-specific commands that may be available. -@deffn Command {arm7_9 dbgrq} [@option{enable}|@option{disable}] +@deffn {Command} {arm7_9 dbgrq} [@option{enable}|@option{disable}] Displays the value of the flag controlling use of the EmbeddedIce DBGRQ signal to force entry into debug mode, instead of breakpoints. @@ -8758,7 +10069,7 @@ This feature is enabled by default on most ARM9 cores, including ARM9TDMI, ARM920T, and ARM926EJ-S. @end deffn -@deffn Command {arm7_9 dcc_downloads} [@option{enable}|@option{disable}] +@deffn {Command} {arm7_9 dcc_downloads} [@option{enable}|@option{disable}] @cindex DCC Displays the value of the flag controlling use of the debug communications channel (DCC) to write larger (>128 byte) amounts of memory. @@ -8769,7 +10080,7 @@ unsafe, especially with targets running at very low speeds. This command was int with OpenOCD rev. 60, and requires a few bytes of working area. @end deffn -@deffn Command {arm7_9 fast_memory_access} [@option{enable}|@option{disable}] +@deffn {Command} {arm7_9 fast_memory_access} [@option{enable}|@option{disable}] Displays the value of the flag controlling use of memory writes and reads that don't check completion of the operation. If a boolean parameter is provided, first assigns that flag. @@ -8779,23 +10090,6 @@ cables (FT2232), but might be unsafe if used with targets running at very low speeds, like the 32kHz startup clock of an AT91RM9200. @end deffn -@subsection ARM720T specific commands -@cindex ARM720T - -These commands are available to ARM720T based CPUs, -which are implementations of the ARMv4T architecture -based on the ARM7TDMI-S integer core. -They are available in addition to the ARM and ARM7/ARM9 commands. - -@deffn Command {arm720t cp15} opcode [value] -@emph{DEPRECATED -- avoid using this. -Use the @command{arm mrc} or @command{arm mcr} commands instead.} - -Display cp15 register returned by the ARM instruction @var{opcode}; -else if a @var{value} is provided, that value is written to that register. -The @var{opcode} should be the value of either an MRC or MCR instruction. -@end deffn - @subsection ARM9 specific commands @cindex ARM9 @@ -8809,7 +10103,7 @@ Such cores include the ARM920T, ARM926EJ-S, and ARM966. @c versions have different rules about when they commit writes. @anchor{arm9vectorcatch} -@deffn Command {arm9 vector_catch} [@option{all}|@option{none}|list] +@deffn {Command} {arm9 vector_catch} [@option{all}|@option{none}|list] @cindex vector_catch Vector Catch hardware provides a sort of dedicated breakpoint for hardware events such as reset, interrupt, and abort. @@ -8836,12 +10130,12 @@ built using the ARM9TDMI integer core. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. -@deffn Command {arm920t cache_info} +@deffn {Command} {arm920t cache_info} Print information about the caches found. This allows to see whether your target is an ARM920T (2x16kByte cache) or ARM922T (2x8kByte cache). @end deffn -@deffn Command {arm920t cp15} regnum [value] +@deffn {Command} {arm920t cp15} regnum [value] Display cp15 register @var{regnum}; else if a @var{value} is provided, that value is written to that register. This uses "physical access" and the register number is as @@ -8849,23 +10143,11 @@ shown in bits 38..33 of table 9-9 in the ARM920T TRM. (Not all registers can be written.) @end deffn -@deffn Command {arm920t cp15i} opcode [value [address]] -@emph{DEPRECATED -- avoid using this. -Use the @command{arm mrc} or @command{arm mcr} commands instead.} - -Interpreted access using ARM instruction @var{opcode}, which should -be the value of either an MRC or MCR instruction -(as shown tables 9-11, 9-12, and 9-13 in the ARM920T TRM). -If no @var{value} is provided, the result is displayed. -Else if that value is written using the specified @var{address}, -or using zero if no other address is provided. -@end deffn - -@deffn Command {arm920t read_cache} filename +@deffn {Command} {arm920t read_cache} filename Dump the content of ICache and DCache to a file named @file{filename}. @end deffn -@deffn Command {arm920t read_mmu} filename +@deffn {Command} {arm920t read_mmu} filename Dump the content of the ITLB and DTLB to a file named @file{filename}. @end deffn @@ -8881,7 +10163,7 @@ and ARM9 commands. The Feroceon cores also support these commands, although they are not built from ARM926ej-s designs. -@deffn Command {arm926ejs cache_info} +@deffn {Command} {arm926ejs cache_info} Print information about the caches found. @end deffn @@ -8893,7 +10175,7 @@ which are implementations of the ARMv5TE architecture. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. -@deffn Command {arm966e cp15} regnum [value] +@deffn {Command} {arm966e cp15} regnum [value] Display cp15 register @var{regnum}; else if a @var{value} is provided, that value is written to that register. The six bit @var{regnum} values are bits 37..32 from table 7-2 of the @@ -8981,50 +10263,50 @@ length of four, or one watchpoint with a length greater than four. These commands are available to XScale based CPUs, which are implementations of the ARMv5TE architecture. -@deffn Command {xscale analyze_trace} +@deffn {Command} {xscale analyze_trace} Displays the contents of the trace buffer. @end deffn -@deffn Command {xscale cache_clean_address} address +@deffn {Command} {xscale cache_clean_address} address Changes the address used when cleaning the data cache. @end deffn -@deffn Command {xscale cache_info} +@deffn {Command} {xscale cache_info} Displays information about the CPU caches. @end deffn -@deffn Command {xscale cp15} regnum [value] +@deffn {Command} {xscale cp15} regnum [value] Display cp15 register @var{regnum}; else if a @var{value} is provided, that value is written to that register. @end deffn -@deffn Command {xscale debug_handler} target address +@deffn {Command} {xscale debug_handler} target address Changes the address used for the specified target's debug handler. @end deffn -@deffn Command {xscale dcache} [@option{enable}|@option{disable}] +@deffn {Command} {xscale dcache} [@option{enable}|@option{disable}] Enables or disable the CPU's data cache. @end deffn -@deffn Command {xscale dump_trace} filename +@deffn {Command} {xscale dump_trace} filename Dumps the raw contents of the trace buffer to @file{filename}. @end deffn -@deffn Command {xscale icache} [@option{enable}|@option{disable}] +@deffn {Command} {xscale icache} [@option{enable}|@option{disable}] Enables or disable the CPU's instruction cache. @end deffn -@deffn Command {xscale mmu} [@option{enable}|@option{disable}] +@deffn {Command} {xscale mmu} [@option{enable}|@option{disable}] Enables or disable the CPU's memory management unit. @end deffn -@deffn Command {xscale trace_buffer} [@option{enable}|@option{disable} [@option{fill} [n] | @option{wrap}]] +@deffn {Command} {xscale trace_buffer} [@option{enable}|@option{disable} [@option{fill} [n] | @option{wrap}]] Displays the trace buffer status, after optionally enabling or disabling the trace buffer and modifying how it is emptied. @end deffn -@deffn Command {xscale trace_image} filename [offset [type]] +@deffn {Command} {xscale trace_image} filename [offset [type]] Opens a trace image from @file{filename}, optionally rebasing its segment addresses by @var{offset}. The image @var{type} may be one of @@ -9034,7 +10316,7 @@ The image @var{type} may be one of @end deffn @anchor{xscalevectorcatch} -@deffn Command {xscale vector_catch} [mask] +@deffn {Command} {xscale vector_catch} [mask] @cindex vector_catch Display a bitmask showing the hardware vectors to catch. If the optional parameter is provided, first set the bitmask to that value. @@ -9052,7 +10334,7 @@ The mask bits correspond with bit 16..23 in the DCSR: @end example @end deffn -@deffn Command {xscale vector_table} [(@option{low}|@option{high}) index value] +@deffn {Command} {xscale vector_table} [(@option{low}|@option{high}) index value] @cindex vector_table Set an entry in the mini-IC vector table. There are two tables: one for @@ -9071,7 +10353,7 @@ Without arguments, the current settings are displayed. @subsection ARM11 specific commands @cindex ARM11 -@deffn Command {arm11 memwrite burst} [@option{enable}|@option{disable}] +@deffn {Command} {arm11 memwrite burst} [@option{enable}|@option{disable}] Displays the value of the memwrite burst-enable flag, which is enabled by default. If a boolean parameter is provided, first assigns that flag. @@ -9082,21 +10364,21 @@ instead of polling for a status flag to verify that completion. This is usually safe, because JTAG runs much slower than the CPU. @end deffn -@deffn Command {arm11 memwrite error_fatal} [@option{enable}|@option{disable}] +@deffn {Command} {arm11 memwrite error_fatal} [@option{enable}|@option{disable}] Displays the value of the memwrite error_fatal flag, which is enabled by default. If a boolean parameter is provided, first assigns that flag. When set, certain memory write errors cause earlier transfer termination. @end deffn -@deffn Command {arm11 step_irq_enable} [@option{enable}|@option{disable}] +@deffn {Command} {arm11 step_irq_enable} [@option{enable}|@option{disable}] Displays the value of the flag controlling whether IRQs are enabled during single stepping; they are disabled by default. If a boolean parameter is provided, first assigns that. @end deffn -@deffn Command {arm11 vcr} [value] +@deffn {Command} {arm11 vcr} [value] @cindex vector_catch Displays the value of the @emph{Vector Catch Register (VCR)}, coprocessor 14 register 7. @@ -9116,39 +10398,39 @@ cores @emph{except the ARM1176} use the same six bits. @subsection ARMv7-A specific commands @cindex Cortex-A -@deffn Command {cortex_a cache_info} +@deffn {Command} {cortex_a cache_info} display information about target caches @end deffn -@deffn Command {cortex_a dacrfixup [@option{on}|@option{off}]} +@deffn {Command} {cortex_a dacrfixup} [@option{on}|@option{off}] Work around issues with software breakpoints when the program text is mapped read-only by the operating system. This option sets the CP15 DACR to "all-manager" to bypass MMU permission checks on memory access. Defaults to 'off'. @end deffn -@deffn Command {cortex_a dbginit} +@deffn {Command} {cortex_a dbginit} Initialize core debug Enables debug by unlocking the Software Lock and clearing sticky powerdown indications @end deffn -@deffn Command {cortex_a smp} [on|off] +@deffn {Command} {cortex_a smp} [on|off] Display/set the current SMP mode @end deffn -@deffn Command {cortex_a smp_gdb} [core_id] +@deffn {Command} {cortex_a smp_gdb} [core_id] Display/set the current core displayed in GDB @end deffn -@deffn Command {cortex_a maskisr} [@option{on}|@option{off}] +@deffn {Command} {cortex_a maskisr} [@option{on}|@option{off}] Selects whether interrupts will be processed when single stepping @end deffn -@deffn Command {cache_config l2x} [base way] +@deffn {Command} {cache_config l2x} [base way] configure l2x cache @end deffn -@deffn Command {cortex_a mmu dump} [@option{0}|@option{1}|@option{addr} address [@option{num_entries}]] +@deffn {Command} {cortex_a mmu dump} [@option{0}|@option{1}|@option{addr} address [@option{num_entries}]] Dump the MMU translation table from TTB0 or TTB1 register, or from physical memory location @var{address}. When dumping the table from @var{address}, print at most @var{num_entries} page table entries. @var{num_entries} is optional, if omitted, the maximum @@ -9158,66 +10440,157 @@ possible (4096) entries are printed. @subsection ARMv7-R specific commands @cindex Cortex-R -@deffn Command {cortex_r dbginit} +@deffn {Command} {cortex_r4 dbginit} Initialize core debug Enables debug by unlocking the Software Lock and clearing sticky powerdown indications @end deffn -@deffn Command {cortex_r maskisr} [@option{on}|@option{off}] +@deffn {Command} {cortex_r4 maskisr} [@option{on}|@option{off}] Selects whether interrupts will be processed when single stepping @end deffn -@subsection ARMv7-M specific commands +@subsection ARM CoreSight TPIU and SWO specific commands @cindex tracing @cindex SWO @cindex SWV @cindex TPIU -@cindex ITM -@cindex ETM - -@deffn Command {tpiu config} (@option{disable} | ((@option{external} | @option{internal (@var{filename} | -)}) @ - (@option{sync @var{port_width}} | ((@option{manchester} | @option{uart}) @var{formatter_enable})) @ - @var{TRACECLKIN_freq} [@var{trace_freq}])) -ARMv7-M architecture provides several modules to generate debugging +ARM CoreSight provides several modules to generate debugging information internally (ITM, DWT and ETM). Their output is directed -through TPIU to be captured externally either on an SWO pin (this +through TPIU or SWO modules to be captured externally either on an SWO pin (this configuration is called SWV) or on a synchronous parallel trace port. -This command configures the TPIU module of the target and, if internal -capture mode is selected, starts to capture trace output by using the -debugger adapter features. +ARM CoreSight provides independent HW blocks named TPIU and SWO each with its +own functionality. Embedded in Cortex-M3 and M4, ARM provides an optional HW +block that includes both TPIU and SWO functionalities and is again named TPIU, +which causes quite some confusion. +The registers map of all the TPIU and SWO implementations allows using a single +driver that detects at runtime the features available. -Some targets require additional actions to be performed in the -@b{trace-config} handler for trace port to be activated. +The @command{tpiu} is used for either TPIU or SWO. +A convenient alias @command{swo} is available to help distinguish, in scripts, +the commands for SWO from the commands for TPIU. -Command options: +@deffn {Command} {swo} ... +Alias of @command{tpiu ...}. Can be used in scripts to distinguish the commands +for SWO from the commands for TPIU. +@end deffn + +@deffn {Command} {tpiu create} tpiu_name configparams... +Creates a TPIU or a SWO object. The two commands are equivalent. +Add the object in a list and add new commands (@command{@var{tpiu_name}}) +which are used for various purposes including additional configuration. + +@itemize @bullet +@item @var{tpiu_name} -- the name of the TPIU or SWO object. +This name is also used to create the object's command, referred to here +as @command{$tpiu_name}, and in other places where the TPIU or SWO needs to be identified. +@item @var{configparams} -- all parameters accepted by @command{$tpiu_name configure} are permitted. + +You @emph{must} set here the AP and MEM_AP base_address through @code{-dap @var{dap_name}}, +@code{-ap-num @var{ap_number}} and @code{-baseaddr @var{base_address}}. +@end itemize +@end deffn + +@deffn {Command} {tpiu names} +Lists all the TPIU or SWO objects created so far. The two commands are equivalent. +@end deffn + +@deffn {Command} {tpiu init} +Initialize all registered TPIU and SWO. The two commands are equivalent. +These commands are used internally during initialization. They can be issued +at any time after the initialization, too. +@end deffn + +@deffn {Command} {$tpiu_name cget} queryparm +Each configuration parameter accepted by @command{$tpiu_name configure} can be +individually queried, to return its current value. +The @var{queryparm} is a parameter name accepted by that command, such as @code{-dap}. +@end deffn + +@deffn {Command} {$tpiu_name configure} configparams... +The options accepted by this command may also be specified as parameters +to @command{tpiu create}. Their values can later be queried one at a time by +using the @command{$tpiu_name cget} command. + +@itemize @bullet +@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. +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. + +@item @code{-protocol} (@option{sync}|@option{uart}|@option{manchester}) -- sets the +protocol used for trace data: +@itemize @minus +@item @option{sync} -- synchronous parallel trace output mode, using @var{port_width} + data bits (default); +@item @option{uart} -- use asynchronous SWO mode with NRZ (same as regular UART 8N1) coding; +@item @option{manchester} -- use asynchronous SWO mode with Manchester coding. +@end itemize + +@item @code{-event} @var{event_name} @var{event_body} -- assigns an event handler, +a TCL string which is evaluated when the event is triggered. The events +@code{pre-enable}, @code{post-enable}, @code{pre-disable} and @code{post-disable} +are defined for TPIU/SWO. +A typical use case for the event @code{pre-enable} is to enable the trace clock +of the TPIU. + +@item @code{-output} (@option{external}|@option{:}@var{port}|@var{filename}|@option{-}) -- specifies +the destination of the trace data: @itemize @minus -@item @option{disable} disable TPIU handling; -@item @option{external} configure TPIU to let user capture trace -output externally (with an additional UART or logic analyzer hardware); -@item @option{internal @var{filename}} configure TPIU and debug adapter to -gather trace data and append it to @var{filename} (which can be -either a regular file or a named pipe); -@item @option{internal -} configure TPIU and debug adapter to -gather trace data, but not write to any file. Useful in conjunction with the @command{tcl_trace} command; -@item @option{sync @var{port_width}} use synchronous parallel trace output -mode, and set port width to @var{port_width}; -@item @option{manchester} use asynchronous SWO mode with Manchester -coding; -@item @option{uart} use asynchronous SWO mode with NRZ (same as -regular UART 8N1) coding; -@item @var{formatter_enable} is @option{on} or @option{off} to enable -or disable TPIU formatter which needs to be used when both ITM and ETM -data is to be output via SWO; -@item @var{TRACECLKIN_freq} this should be specified to match target's -current TRACECLKIN frequency (usually the same as HCLK); -@item @var{trace_freq} trace port frequency. Can be omitted in -internal mode to let the adapter driver select the maximum supported -rate automatically. +@item @option{external} -- configure TPIU/SWO to let user capture trace +output externally, either with an additional UART or with a logic analyzer (default); +@item @option{-} -- configure TPIU/SWO and debug adapter to gather trace data +and forward it to @command{tcl_trace} command; +@item @option{:}@var{port} -- configure TPIU/SWO and debug adapter to gather +trace data, open a TCP server at port @var{port} and send the trace data to +each connected client; +@item @var{filename} -- configure TPIU/SWO and debug adapter to +gather trace data and append it to @var{filename}, which can be +either a regular file or a named pipe. @end itemize +@item @code{-traceclk} @var{TRACECLKIN_freq} -- mandatory parameter. +Specifies the frequency in Hz of the trace clock. For the TPIU embedded in +Cortex-M3 or M4, this is usually the same frequency as HCLK. For protocol +@option{sync} this is twice the frequency of the pin data rate. + +@item @code{-pin-freq} @var{trace_freq} -- specifies the expected data rate +in Hz of the SWO pin. Parameter used only on protocols @option{uart} and +@option{manchester}. Can be omitted to let the adapter driver select the +maximum supported rate automatically. + +@item @code{-port-width} @var{port_width} -- sets to @var{port_width} the width +of the synchronous parallel port used for trace output. Parameter used only on +protocol @option{sync}. If not specified, default value is @var{1}. + +@item @code{-formatter} (@option{0}|@option{1}) -- specifies if the formatter +should be enabled. Parameter used only on protocol @option{sync}. If not specified, +default value is @var{0}. +@end itemize +@end deffn + +@deffn {Command} {$tpiu_name enable} +Uses the parameters specified by the previous @command{$tpiu_name configure} +to configure and enable the TPIU or the SWO. +If required, the adapter is also configured and enabled to receive the trace +data. +This command can be used before @command{init}, but it will take effect only +after the @command{init}. +@end deffn + +@deffn {Command} {$tpiu_name disable} +Disable the TPIU or the SWO, terminating the receiving of the trace data. +@end deffn + + + Example usage: @enumerate @item STM32L152 board is programmed with an application that configures @@ -9245,26 +10618,34 @@ baud with our custom divisor to get 12MHz) @item OpenOCD invocation line: @example openocd -f interface/stlink.cfg \ - -c "transport select hla_swd" \ - -f target/stm32l1.cfg \ - -c "tpiu config external uart off 24000000 12000000" +-c "transport select hla_swd" \ +-f target/stm32l1.cfg \ +-c "stm32l1.tpiu configure -protocol uart" \ +-c "stm32l1.tpiu configure -traceclk 24000000 -pin-freq 12000000" \ +-c "stm32l1.tpiu enable" @end example @end enumerate -@end deffn -@deffn Command {itm port} @var{port} (@option{0}|@option{1}|@option{on}|@option{off}) +@subsection ARMv7-M specific commands +@cindex tracing +@cindex SWO +@cindex SWV +@cindex ITM +@cindex ETM + +@deffn {Command} {itm port} @var{port} (@option{0}|@option{1}|@option{on}|@option{off}) Enable or disable trace output for ITM stimulus @var{port} (counting from 0). Port 0 is enabled on target creation automatically. @end deffn -@deffn Command {itm ports} (@option{0}|@option{1}|@option{on}|@option{off}) +@deffn {Command} {itm ports} (@option{0}|@option{1}|@option{on}|@option{off}) Enable or disable trace output for all ITM stimulus ports. @end deffn @subsection Cortex-M specific commands @cindex Cortex-M -@deffn Command {cortex_m maskisr} (@option{auto}|@option{on}|@option{off}|@option{steponly}) +@deffn {Command} {cortex_m maskisr} (@option{auto}|@option{on}|@option{off}|@option{steponly}) Control masking (disabling) interrupts during target step/resume. The @option{auto} option handles interrupts during stepping in a way that they @@ -9287,7 +10668,7 @@ does. Default is @option{auto}. @end deffn -@deffn Command {cortex_m vector_catch} [@option{all}|@option{none}|list] +@deffn {Command} {cortex_m vector_catch} [@option{all}|@option{none}|list] @cindex vector_catch Vector Catch hardware provides dedicated breakpoints for certain hardware events. @@ -9314,7 +10695,7 @@ must also be explicitly enabled. This finishes by listing the current vector catch configuration. @end deffn -@deffn Command {cortex_m reset_config} (@option{sysresetreq}|@option{vectreset}) +@deffn {Command} {cortex_m reset_config} (@option{sysresetreq}|@option{vectreset}) Control reset handling if hardware srst is not fitted @xref{reset_config,,reset_config}. @@ -9337,11 +10718,11 @@ instead. @cindex ARMv8-A @cindex aarch64 -@deffn Command {aarch64 cache_info} +@deffn {Command} {aarch64 cache_info} Display information about target caches @end deffn -@deffn Command {aarch64 dbginit} +@deffn {Command} {aarch64 dbginit} This command enables debugging by clearing the OS Lock and sticky power-down and reset indications. It also establishes the expected, basic cross-trigger configuration the aarch64 target code relies on. In a configuration file, the command would typically be called from a @@ -9349,19 +10730,25 @@ target code relies on. In a configuration file, the command would typically be c However, normally it is not necessary to use the command at all. @end deffn -@deffn Command {aarch64 smp} [on|off] +@deffn {Command} {aarch64 disassemble} address [count] +@cindex disassemble +Disassembles @var{count} instructions starting at @var{address}. +If @var{count} is not specified, a single instruction is disassembled. +@end deffn + +@deffn {Command} {aarch64 smp} [on|off] Display, enable or disable SMP handling mode. The state of SMP handling influences the way targets in an SMP group are handled by the run control. With SMP handling enabled, issuing halt or resume to one core will trigger halting or resuming of all cores in the group. The command @code{target smp} defines which targets are in the SMP group. With SMP handling disabled, all targets need to be treated individually. @end deffn -@deffn Command {aarch64 maskisr} [@option{on}|@option{off}] +@deffn {Command} {aarch64 maskisr} [@option{on}|@option{off}] Selects whether interrupts will be processed when single stepping. The default configuration is @option{on}. @end deffn -@deffn Command {$target_name catch_exc} [@option{off}|@option{sec_el1}|@option{sec_el3}|@option{nsec_el1}|@option{nsec_el2}]+ +@deffn {Command} {$target_name catch_exc} [@option{off}|@option{sec_el1}|@option{sec_el3}|@option{nsec_el1}|@option{nsec_el2}]+ Cause @command{$target_name} to halt when an exception is taken. Any combination of Secure (sec) EL1/EL3 or Non-Secure (nsec) EL1/EL2 is valid. The target @command{$target_name} will halt before taking the exception. In order to resume @@ -9369,6 +10756,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 @@ -9376,12 +10773,12 @@ provided by EnSilica. (See: @url{http://www.ensilica.com/risc-ip/}.) @subsection eSi-RISC Configuration -@deffn Command {esirisc cache_arch} (@option{harvard}|@option{von_neumann}) +@deffn {Command} {esirisc cache_arch} (@option{harvard}|@option{von_neumann}) Configure the caching architecture. Targets with the @code{UNIFIED_ADDRESS_SPACE} option disabled employ a Harvard architecture. By default, @option{von_neumann} is assumed. @end deffn -@deffn Command {esirisc hwdc} (@option{all}|@option{none}|mask ...) +@deffn {Command} {esirisc hwdc} (@option{all}|@option{none}|mask ...) Configure hardware debug control. The HWDC register controls which exceptions return control back to the debugger. Possible masks are @option{all}, @option{none}, @option{reset}, @option{interrupt}, @option{syscall}, @option{error}, and @option{debug}. @@ -9390,7 +10787,7 @@ By default, @option{reset}, @option{error}, and @option{debug} are enabled. @subsection eSi-RISC Operation -@deffn Command {esirisc flush_caches} +@deffn {Command} {esirisc flush_caches} Flush instruction and data caches. This command requires that the target is halted when the command is issued and configured with an instruction or data cache. @end deffn @@ -9421,22 +10818,22 @@ managed by enabling flow control, however this can impact timing-sensitive software operation on the CPU. @end quotation -@deffn Command {esirisc trace buffer} address size [@option{wrap}] +@deffn {Command} {esirisc trace buffer} address size [@option{wrap}] Configure trace buffer using the provided address and size. If the @option{wrap} option is specified, trace collection will continue once the end of the buffer is reached. By default, wrap is disabled. @end deffn -@deffn Command {esirisc trace fifo} address +@deffn {Command} {esirisc trace fifo} address Configure trace FIFO using the provided address. @end deffn -@deffn Command {esirisc trace flow_control} (@option{enable}|@option{disable}) +@deffn {Command} {esirisc trace flow_control} (@option{enable}|@option{disable}) Enable or disable stalling the CPU to collect trace data. By default, flow control is disabled. @end deffn -@deffn Command {esirisc trace format} (@option{full}|@option{branch}|@option{icache}) pc_bits +@deffn {Command} {esirisc trace format} (@option{full}|@option{branch}|@option{icache}) pc_bits Configure trace format and number of PC bits to be captured. @option{pc_bits} must be within 1 and 31 as the LSB is not collected. If external tooling is used to analyze collected trace data, these values must match. @@ -9451,7 +10848,7 @@ addresses. @end itemize @end deffn -@deffn Command {esirisc trace trigger start} (@option{condition}) [start_data start_mask] +@deffn {Command} {esirisc trace trigger start} (@option{condition}) [start_data start_mask] Configure trigger start condition using the provided start data and mask. A brief description of each condition is provided below; for more detail on how these values are used, see the eSi-RISC Architecture Manual. @@ -9474,7 +10871,7 @@ data and mask. @end itemize @end deffn -@deffn Command {esirisc trace trigger stop} (@option{condition}) [stop_data stop_mask] +@deffn {Command} {esirisc trace trigger stop} (@option{condition}) [stop_data stop_mask] Configure trigger stop condition using the provided stop data and mask. A brief description of each condition is provided below; for more detail on how these values are used, see the eSi-RISC Architecture Manual. @@ -9495,7 +10892,7 @@ data and mask. @end itemize @end deffn -@deffn Command {esirisc trace trigger delay} (@option{trigger}) [cycles] +@deffn {Command} {esirisc trace trigger delay} (@option{trigger}) [cycles] Configure trigger start/stop delay in clock cycles. Supported triggers: @@ -9510,36 +10907,36 @@ collection. @subsection eSi-Trace Operation -@deffn Command {esirisc trace init} +@deffn {Command} {esirisc trace init} Initialize trace collection. This command must be called any time the configuration changes. If a trace buffer has been configured, the contents will be overwritten when trace collection starts. @end deffn -@deffn Command {esirisc trace info} +@deffn {Command} {esirisc trace info} Display trace configuration. @end deffn -@deffn Command {esirisc trace status} +@deffn {Command} {esirisc trace status} Display trace collection status. @end deffn -@deffn Command {esirisc trace start} +@deffn {Command} {esirisc trace start} Start manual trace collection. @end deffn -@deffn Command {esirisc trace stop} +@deffn {Command} {esirisc trace stop} Stop manual trace collection. @end deffn -@deffn Command {esirisc trace analyze} [address size] +@deffn {Command} {esirisc trace analyze} [address size] Analyze collected trace data. This command may only be used if a trace buffer has been configured. If a trace FIFO has been configured, trace data must be copied to an in-memory buffer identified by the @option{address} and @option{size} options using DMA. @end deffn -@deffn Command {esirisc trace dump} [address size] @file{filename} +@deffn {Command} {esirisc trace dump} [address size] @file{filename} Dump collected trace data to file. This command may only be used if a trace buffer has been configured. If a trace FIFO has been configured, trace data must be copied to an in-memory buffer identified by the @option{address} and @@ -9563,27 +10960,27 @@ Useful docs are here: https://communities.intel.com/community/makers/documentati The three main address spaces for x86 are memory, I/O and configuration space. These commands allow a user to read and write to the 64Kbyte I/O address space. -@deffn Command {x86_32 idw} address +@deffn {Command} {x86_32 idw} address Display the contents of a 32-bit I/O port from address range 0x0000 - 0xffff. @end deffn -@deffn Command {x86_32 idh} address +@deffn {Command} {x86_32 idh} address Display the contents of a 16-bit I/O port from address range 0x0000 - 0xffff. @end deffn -@deffn Command {x86_32 idb} address +@deffn {Command} {x86_32 idb} address Display the contents of a 8-bit I/O port from address range 0x0000 - 0xffff. @end deffn -@deffn Command {x86_32 iww} address +@deffn {Command} {x86_32 iww} address Write the contents of a 32-bit I/O port to address range 0x0000 - 0xffff. @end deffn -@deffn Command {x86_32 iwh} address +@deffn {Command} {x86_32 iwh} address Write the contents of a 16-bit I/O port to address range 0x0000 - 0xffff. @end deffn -@deffn Command {x86_32 iwb} address +@deffn {Command} {x86_32 iwb} address Write the contents of a 8-bit I/O port to address range 0x0000 - 0xffff. @end deffn @@ -9593,10 +10990,10 @@ The OpenRISC CPU is a soft core. It is used in a programmable SoC which can be configured with any of the TAP / Debug Unit available. @subsection TAP and Debug Unit selection commands -@deffn Command {tap_select} (@option{vjtag}|@option{mohor}|@option{xilinx_bscan}) +@deffn {Command} {tap_select} (@option{vjtag}|@option{mohor}|@option{xilinx_bscan}) Select between the Altera Virtual JTAG , Xilinx Virtual JTAG and Mohor TAP. @end deffn -@deffn Command {du_select} (@option{adv}|@option{mohor}) [option] +@deffn {Command} {du_select} (@option{adv}|@option{mohor}) [option] Select between the Advanced Debug Interface and the classic one. An option can be passed as a second argument to the debug unit. @@ -9607,7 +11004,7 @@ between bytes while doing read or write bursts. @end deffn @subsection Registers commands -@deffn Command {addreg} [name] [address] [feature] [reg_group] +@deffn {Command} {addreg} [name] [address] [feature] [reg_group] Add a new register in the cpu register list. This register will be included in the generated target descriptor file. @@ -9622,14 +11019,78 @@ included in the generated target descriptor file. addreg rtest 0x1234 org.gnu.gdb.or1k.group0 system @end example +@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 -@deffn Command {readgroup} (@option{group}) -Display all registers in @emph{group}. -@emph{group} can be "system", - "dmmu", "immu", "dcache", "icache", "mac", "debug", "perf", "power", "pic", - "timer" or any new group created with addreg command. +@deffn {Command} {mips32 dsp} [[register_name] [value]] +Displays all DSP registers' contents or get/set value by register name. Will display +an error if current CPU does not support DSP. @end deffn @section RISC-V Architecture @@ -9647,47 +11108,155 @@ A @emph{hart} is a hardware thread. A hart may share resources (eg. FPU) with another hart, or may be a separate core. RISC-V treats those the same, and OpenOCD exposes each hart as a separate core. +@subsection Vector Registers + +For harts that implement the vector extension, OpenOCD provides access to the +relevant CSRs, as well as the vector registers (v0-v31). The size of each +vector register is dependent on the value of vlenb. RISC-V allows each vector +register to be divided into selected-width elements, and this division can be +changed at run-time. Because OpenOCD cannot update register definitions at +run-time, it exposes each vector register to gdb as a union of fields of +vectors so that users can easily access individual bytes, shorts, words, +longs, and quads inside each vector register. It is left to gdb or +higher-level debuggers to present this data in a more intuitive format. + +In the XML register description, the vector registers (when vlenb=16) look as +follows: + +@example +<feature name="org.gnu.gdb.riscv.vector"> +<vector id="bytes" type="uint8" count="16"/> +<vector id="shorts" type="uint16" count="8"/> +<vector id="words" type="uint32" count="4"/> +<vector id="longs" type="uint64" count="2"/> +<vector id="quads" type="uint128" count="1"/> +<union id="riscv_vector"> +<field name="b" type="bytes"/> +<field name="s" type="shorts"/> +<field name="w" type="words"/> +<field name="l" type="longs"/> +<field name="q" type="quads"/> +</union> +<reg name="v0" bitsize="128" regnum="4162" save-restore="no" + type="riscv_vector" group="vector"/> +... +<reg name="v31" bitsize="128" regnum="4193" save-restore="no" + type="riscv_vector" group="vector"/> +</feature> +@end example + @subsection RISC-V Debug Configuration Commands -@deffn Command {riscv expose_csrs} n0[-m0][,n1[-m1]]... -Configure a list of inclusive ranges for CSRs to expose in addition to the -standard ones. This must be executed before `init`. +@deffn {Config Command} {riscv expose_csrs} n[-m|=name] [...] +Configure which CSRs to expose in addition to the standard ones. The CSRs to expose +can be specified as individual register numbers or register ranges (inclusive). For the +individually listed CSRs, a human-readable name can optionally be set using the @code{n=name} +syntax, which will get @code{csr_} prepended to it. If no name is provided, the register will be +named @code{csr<n>}. By default OpenOCD attempts to expose only CSRs that are mentioned in a spec, and then only if the corresponding extension appears to be implemented. This -command can be used if OpenOCD gets this wrong, or a target implements custom +command can be used if OpenOCD gets this wrong, or if the target implements custom CSRs. + +@example +# Expose a single RISC-V CSR number 128 under the name "csr128": +$_TARGETNAME expose_csrs 128 + +# Expose multiple RISC-V CSRs 128..132 under names "csr128" through "csr132": +$_TARGETNAME expose_csrs 128-132 + +# Expose a single RISC-V CSR number 1996 under custom name "csr_myregister": +$_TARGETNAME expose_csrs 1996=myregister +@end example @end deffn -@deffn Command {riscv expose_custom} n0[-m0][,n1[-m1]]... +@deffn {Config Command} {riscv expose_custom} n[-m|=name] [...] The RISC-V Debug Specification allows targets to expose custom registers through abstract commands. (See Section 3.5.1.1 in that document.) This command -configures a list of inclusive ranges of those registers to expose. Number 0 -indicates the first custom register, whose abstract command number is 0xc000. -This command must be executed before `init`. +configures individual registers or register ranges (inclusive) that shall be exposed. +Number 0 indicates the first custom register, whose abstract command number is 0xc000. +For individually listed registers, a human-readable name can be optionally provided +using the @code{n=name} syntax, which will get @code{custom_} prepended to it. If no +name is provided, the register will be named @code{custom<n>}. + +@example +# Expose one RISC-V custom register with number 0xc010 (0xc000 + 16) +# under the name "custom16": +$_TARGETNAME expose_custom 16 + +# Expose a range of RISC-V custom registers with numbers 0xc010 .. 0xc018 +# (0xc000+16 .. 0xc000+24) under the names "custom16" through "custom24": +$_TARGETNAME expose_custom 16-24 + +# Expose one RISC-V custom register with number 0xc020 (0xc000 + 32) under +# user-defined name "custom_myregister": +$_TARGETNAME expose_custom 32=myregister +@end example +@end deffn + +@deffn {Command} {riscv info} +Displays some information OpenOCD detected about the target. @end deffn -@deffn Command {riscv set_command_timeout_sec} [seconds] +@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). @end deffn -@deffn Command {riscv set_reset_timeout_sec} [seconds] +@deffn {Command} {riscv set_reset_timeout_sec} [seconds] 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. +@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. + +Available methods are: +@itemize +@item @code{progbuf} - Use RISC-V Debug Program Buffer to access memory. +@item @code{sysbus} - Access memory via RISC-V Debug System Bus interface. +@item @code{abstract} - Access memory via RISC-V Debug abstract commands. +@end itemize + +By default, all memory access methods are enabled in the following order: +@code{progbuf sysbus abstract}. + +This command can be used to change the memory access methods if the default +behavior is not suitable for a particular target. +@end deffn + +@deffn {Command} {riscv set_enable_virtual} on|off +When on, memory accesses are performed on physical or virtual memory depending +on the current system configuration. When off (default), all memory accessses are performed +on physical memory. @end deffn -@deffn Command {riscv set_prefer_sba} on|off -When on, prefer to use System Bus Access to access memory. When off, prefer to -use the Program Buffer to access memory. +@deffn {Command} {riscv set_enable_virt2phys} on|off +When on (default), memory accesses are performed on physical or virtual memory +depending on the current satp configuration. When off, all memory accessses are +performed on physical memory. @end deffn -@deffn Command {riscv set_ir} (@option{idcode}|@option{dtmcs}|@option{dmi}) [value] +@deffn {Command} {riscv resume_order} normal|reversed +Some software assumes all harts are executing nearly continuously. Such +software may be sensitive to the order that harts are resumed in. On harts +that don't support hasel, this option allows the user to choose the order the +harts are resumed in. If you are using this option, it's probably masking a +race condition problem in your code. + +Normal order is from lowest hart index to highest. This is the default +behavior. Reversed order is from highest hart index to lowest. +@end deffn + +@deffn {Command} {riscv set_ir} (@option{idcode}|@option{dtmcs}|@option{dmi}) [value] Set the IR value for the specified JTAG register. This is useful, for example, when using the existing JTAG interface on a Xilinx FPGA by way of BSCANE2 primitives that only permit a limited selection of IR @@ -9698,6 +11267,26 @@ When utilizing version 0.11 of the RISC-V Debug Specification, and DBUS registers, respectively. @end deffn +@deffn {Command} {riscv use_bscan_tunnel} value +Enable or disable use of a BSCAN tunnel to reach DM. Supply the width of +the DM transport TAP's instruction register to enable. Supply a value of 0 to disable. +@end deffn + +@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 +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 +Control dcsr.ebreaku. When on (default), U-mode ebreak instructions trap to +OpenOCD. When off, they generate a breakpoint exception handled internally. +@end deffn + @subsection RISC-V Authentication Commands The following commands can be used to authenticate to a RISC-V system. Eg. a @@ -9705,14 +11294,14 @@ trivial challenge-response protocol could be implemented as follows in a configuration file, immediately following @command{init}: @example set challenge [riscv authdata_read] -riscv authdata_write [expr $challenge + 1] +riscv authdata_write [expr @{$challenge + 1@}] @end example -@deffn Command {riscv authdata_read} +@deffn {Command} {riscv authdata_read} Return the 32-bit value read from authdata. @end deffn -@deffn Command {riscv authdata_write} value +@deffn {Command} {riscv authdata_write} value Write the 32-bit value to authdata. @end deffn @@ -9721,11 +11310,11 @@ Write the 32-bit value to authdata. The following commands allow direct access to the Debug Module Interface, which can be used to interact with custom debug features. -@deffn Command {riscv dmi_read} +@deffn {Command} {riscv dmi_read} address Perform a 32-bit DMI read at address, returning the value. @end deffn -@deffn Command {riscv dmi_write} address value +@deffn {Command} {riscv dmi_write} address value Perform a 32-bit DMI write of value at address. @end deffn @@ -9735,7 +11324,7 @@ Perform a 32-bit DMI write of value at address. Synopsys DesignWare ARC Processors are a family of 32-bit CPUs that SoC designers can optimize for a wide range of uses, from deeply embedded to high-performance host applications in a variety of market segments. See more -at: http://www.synopsys.com/IP/ProcessorIP/ARCProcessors/Pages/default.aspx. +at: @url{http://www.synopsys.com/IP/ProcessorIP/ARCProcessors/Pages/default.aspx}. OpenOCD currently supports ARC EM processors. There is a set ARC-specific OpenOCD commands that allow low-level access to the core and provide necessary support for ARC extensibility and @@ -9823,7 +11412,7 @@ startbit endbit}. @deffn {Command} {arc get-reg-field} reg-name field-name Returns value of bit-field in a register. Register must be ``struct'' register -type, @xref{add-reg-type-struct} command definition. +type, @xref{add-reg-type-struct}. command definition. @end deffn @deffn {Command} {arc set-reg-exists} reg-names... @@ -9864,6 +11453,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 @@ -9917,7 +11808,7 @@ This is not the same format used by @file{libdcc}. Other software, such as the U-Boot boot loader, sometimes does the same thing. -@deffn Command {target_request debugmsgs} [@option{enable}|@option{disable}|@option{charmsg}] +@deffn {Command} {target_request debugmsgs} [@option{enable}|@option{disable}|@option{charmsg}] Displays current handling of target DCC message requests. These messages may be sent to the debugger while the target is running. The optional @option{enable} and @option{charmsg} parameters @@ -9928,7 +11819,7 @@ as used by Linux with CONFIG_DEBUG_ICEDCC; otherwise the libdcc format is used. @end deffn -@deffn Command {trace history} [@option{clear}|count] +@deffn {Command} {trace history} [@option{clear}|count] With no parameter, displays all the trace points that have triggered in the order they triggered. With the parameter @option{clear}, erases all current trace history records. @@ -9936,7 +11827,7 @@ With a @var{count} parameter, allocates space for that many history records. @end deffn -@deffn Command {trace point} [@option{clear}|identifier] +@deffn {Command} {trace point} [@option{clear}|identifier] With no parameter, displays all trace point identifiers and how many times they have been triggered. With the parameter @option{clear}, erases all current trace point counters. @@ -9990,7 +11881,7 @@ JTAG router), you probably won't need to use these commands. In a debug session that doesn't use JTAG for its transport protocol, these commands are not available. -@deffn Command {drscan} tap [numbits value]+ [@option{-endstate} tap_state] +@deffn {Command} {drscan} tap [numbits value]+ [@option{-endstate} tap_state] Loads the data register of @var{tap} with a series of bit fields that specify the entire register. Each field is @var{numbits} bits long with @@ -10025,7 +11916,7 @@ the register accessed by the INTEST instruction @end quotation @end deffn -@deffn Command {flush_count} +@deffn {Command} {flush_count} Returns the number of times the JTAG queue has been flushed. This may be used for performance tuning. @@ -10037,7 +11928,7 @@ tasks which waste bandwidth by flushing small transfers too often, instead of batching them into larger operations. @end deffn -@deffn Command {irscan} [tap instruction]+ [@option{-endstate} tap_state] +@deffn {Command} {irscan} [tap instruction]+ [@option{-endstate} tap_state] For each @var{tap} listed, loads the instruction register with its associated numeric @var{instruction}. (The number of bits in that instruction may be displayed @@ -10058,7 +11949,7 @@ portable scripts currently must issue only BYPASS instructions. @end quotation @end deffn -@deffn Command {pathmove} start_state [next_state ...] +@deffn {Command} {pathmove} start_state [next_state ...] Start by moving to @var{start_state}, which must be one of the @emph{stable} states. Unless it is the only state given, this will often be the @@ -10069,7 +11960,7 @@ each @var{next_state} in sequence, one per TCK cycle. The final state must also be stable. @end deffn -@deffn Command {runtest} @var{num_cycles} +@deffn {Command} {runtest} @var{num_cycles} Move to the @sc{run/idle} state, and execute at least @var{num_cycles} of the JTAG clock (TCK). Instructions often need some time @@ -10079,14 +11970,14 @@ to execute before they take effect. @c tms_sequence (short|long) @c ... temporary, debug-only, other than USBprog bug workaround... -@deffn Command {verify_ircapture} (@option{enable}|@option{disable}) +@deffn {Command} {verify_ircapture} (@option{enable}|@option{disable}) Verify values captured during @sc{ircapture} and returned during IR scans. Default is enabled, but this can be overridden by @command{verify_jtag}. This flag is ignored when validating JTAG chain configuration. @end deffn -@deffn Command {verify_jtag} (@option{enable}|@option{disable}) +@deffn {Command} {verify_jtag} (@option{enable}|@option{disable}) Enables verification of DR and IR scans, to help detect programming errors. For IR scans, @command{verify_ircapture} must also be enabled. @@ -10160,8 +12051,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}. @@ -10174,12 +12066,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 @@ -10197,7 +12093,7 @@ OpenOCD supports running such test files. Not all XSVF commands are supported. @end quotation -@deffn Command {xsvf} (tapname|@option{plain}) filename [@option{virt2}] [@option{quiet}] +@deffn {Command} {xsvf} (tapname|@option{plain}) filename [@option{virt2}] [@option{quiet}] This issues a JTAG reset (Test-Logic-Reset) and then runs the XSVF script from @file{filename}. When a @var{tapname} is specified, the commands are directed at @@ -10229,6 +12125,112 @@ If @emph{xsvfdump} shows a file is using those opcodes, it probably will not be usable with other XSVF tools. +@section IPDBG: JTAG-Host server +@cindex IPDBG JTAG-Host server +@cindex IPDBG + +IPDBG is a set of tools to debug IP-Cores. It comprises, among others, a logic analyzer and an arbitrary +waveform generator. These are synthesize-able hardware descriptions of +logic circuits in addition to software for control, visualization and further analysis. +In a session using JTAG for its transport protocol, OpenOCD supports the function +of a JTAG-Host. The JTAG-Host is needed to connect the circuit over JTAG to the +control-software. The JTAG-Hub is the circuit which transfers the data from JTAG to the +different tools connected to the Hub. Hub implementations for most major FPGA vendors/families +are provided. For more details see @url{http://ipdbg.org}. + +@deffn {Command} {ipdbg create-hub} @var{hub_name} @option{-tap @var{tapname}} @option{-ir @var{ir_value} [@var{dr_length}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] +@deffnx {Command} {ipdbg create-hub} @var{hub_name} @option{-pld @var{pld_name} [@var{user}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] +Creates a IPDBG JTAG Hub. The created hub is later used to start, stop and configure IPDBG JTAG Host servers. +The first argument @var{hub_name} is the name of the created hub. It can be used later as a reference. + +The pld drivers are able to provide the tap and ir_value for the IPDBG JTAG-Host server. This will be used with the second variant with option @option{-pld}. + +Command options: +@itemize @bullet +@item @var{hub_name} the name of the IPDBG hub. +This name is also used to create the object's command, referred to here +as @command{$hub_name}, and in other places where the Hub needs to be identified. + +@item @option{-tap @var{tapname}} targeting the TAP @var{tapname}. + +@item @option{-ir @var{ir_value}} states that the JTAG hub is +reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}. Also known as @verb{|USERx|} instructions. +The optional @var{dr_length} is the length of the dr. +Current JTAG-Hub implementation only supports dr_length=13, which is also the default value. + +@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} To support more Hubs than USER registers in a single FPGA it is possible to +use a mechanism known as virtual-ir where 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. + +@item @option{-pld @var{pld_name} [@var{user}]} The defined driver for the pld @var{pld_name} is used to get the tap and user instruction. +The pld devices names can be shown by the command @command{pld devices}. 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 @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 first variant. + +@end itemize + +@end deffn + +@deffn {Command} {$hub_name ipdbg start} @option{-tool @var{number}} @option{-port @var{number}} +Starts a IPDBG JTAG-Host server. The remaining arguments can be specified in any order. + +Command options: +@itemize @bullet +@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. +@end itemize +@end deffn + +@deffn {Command} {$hub_name ipdbg stop} @option{-tool @var{number}} +Stops a IPDBG JTAG-Host server. +Command options: +@itemize @bullet +@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. +@end itemize +@end deffn + +Examples: +@example +ipdbg create-hub xc6s.ipdbghub -tap xc6s.tap -hub 0x02 +xc6s.ipdbghub ipdbg start -port 4242 -tool 4 +@end example +Creates a IPDBG Hub and starts a server listening on tcp-port 4242 which connects to tool 4. +The connection is through the TAP of a Xilinx Spartan 6 on USER1 instruction (tested with a papillion pro board). + +@example +ipdbg create-hub max10m50.ipdbghub -tap max10m50.tap -hub 0x00C -vir +max10m50.ipdbghub ipdbg start -tool 1 -port 60000 +@end example +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 create-hub xc7.ipdbghub -pld xc7.pld +xc7.ipdbghub ipdbg start -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. + +@deffn {Command} {$hub_name queuing} @option{-size @var{size}} +Configure the queuing between IPDBG JTAG-Host and Hub. +The maximum possible queue size is 1024 which is also the default. + +@itemize @bullet +@item @option{-size @var{size}} max number of transfers in the queue. +@end itemize +@end deffn + +@example +bitbang.ibdbghub queuing -size 32 +@end example +Send a maximum of 32 transfers to the queue before executing them. + + @node Utility Commands @chapter Utility Commands @cindex Utility Commands @@ -10255,24 +12257,24 @@ source [find tools/memtest.tcl] to get access to the following facilities: -@deffn Command {memTestDataBus} address +@deffn {Command} {memTestDataBus} address Test the data bus wiring in a memory region by performing a walking 1's test at a fixed address within that region. @end deffn -@deffn Command {memTestAddressBus} baseaddress size +@deffn {Command} {memTestAddressBus} baseaddress size Perform a walking 1's test on the relevant bits of the address and check for aliasing. This test will find single-bit address failures such as stuck-high, stuck-low, and shorted pins. @end deffn -@deffn Command {memTestDevice} baseaddress size +@deffn {Command} {memTestDevice} baseaddress size Test the integrity of a physical memory device by performing an increment/decrement test over the entire region. In the process every storage bit in the device is tested as zero and as one. @end deffn -@deffn Command {runAllMemTests} baseaddress size +@deffn {Command} {runAllMemTests} baseaddress size Run all of the above tests over a specified memory region. @end deffn @@ -10287,28 +12289,6 @@ For quickstart instructions run: openocd -f tools/firmware-recovery.tcl -c firmware_help @end example -@node TFTP -@chapter TFTP -@cindex TFTP -If OpenOCD runs on an embedded host (as ZY1000 does), then TFTP can -be used to access files on PCs (either the developer's PC or some other PC). - -The way this works on the ZY1000 is to prefix a filename by -"/tftp/ip/" and append the TFTP path on the TFTP -server (tftpd). For example, - -@example -load_image /tftp/10.0.0.96/c:\temp\abc.elf -@end example - -will load c:\temp\abc.elf from the developer pc (10.0.0.96) into memory as -if the file was hosted on the embedded host. - -In order to achieve decent performance, you must choose a TFTP server -that supports a packet size bigger than the default packet size (512 bytes). There -are numerous TFTP servers out there (free and commercial) and you will have to do -a bit of googling to find something that fits your requirements. - @node GDB and OpenOCD @chapter GDB and OpenOCD @cindex GDB @@ -10369,7 +12349,8 @@ target remote localhost:3333 @item A pipe connection is typically started as follows: @example -target extended-remote | openocd -c "gdb_port pipe; log_output openocd.log" +target extended-remote | \ + openocd -c "gdb_port pipe; log_output openocd.log" @end example This would cause GDB to run OpenOCD and communicate using pipes (stdin/stdout). Using this method has the advantage of GDB starting/stopping OpenOCD for the debug @@ -10532,7 +12513,13 @@ of a running target. Do not use GDB commands @command{continue}, and GDB would require stopping the target to get the prompt back. Do not use this mode under an IDE like Eclipse as it caches values of -previously shown varibles. +previously shown variables. + +It's also possible to connect more than one GDB to the same target by the +target's configuration option @code{-gdb-max-connections}. This allows, for +example, one GDB to run a script that continuously polls a set of variables +while other GDB can be used interactively. Be extremely careful in this case, +because the two GDB can easily get out-of-sync. @section RTOS Support @cindex RTOS Support @@ -10566,8 +12553,15 @@ Currently supported rtos's include: @item @option{nuttx} @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. @@ -10577,17 +12571,11 @@ Cyg_Thread::thread_list, Cyg_Scheduler_Base::current_thread. @item ThreadX symbols _tx_thread_current_ptr, _tx_thread_created_ptr, _tx_thread_created_count. @item FreeRTOS symbols -@c The following is taken from recent texinfo to provide compatibility -@c with ancient versions that do not support @raggedright -@tex -\begingroup -\rightskip0pt plus2em \spaceskip.3333em \xspaceskip.5em\relax +@raggedright pxCurrentTCB, pxReadyTasksLists, xDelayedTaskList1, xDelayedTaskList2, pxDelayedTaskList, pxOverflowDelayedTaskList, xPendingReadyList, -uxCurrentNumberOfTasks, uxTopUsedPriority. -\par -\endgroup -@end tex +uxCurrentNumberOfTasks, uxTopUsedPriority, xSchedulerRunning. +@end raggedright @item linux symbols init_task. @item ChibiOS symbols @@ -10598,17 +12586,27 @@ Rtos::sListSuspended, Rtos::sMaxPriorities, Rtos::sCurrentTaskCount. @item mqx symbols _mqx_kernel_data, MQX_init_struct. @item uC/OS-III symbols -OSRunning, OSTCBCurPtr, OSTaskDbgListPtr, OSTaskQty +OSRunning, OSTCBCurPtr, OSTaskDbgListPtr, OSTaskQty. @item nuttx symbols -g_readytorun, g_tasklisttable +g_readytorun, g_tasklisttable. @item RIOT symbols -sched_threads, sched_num_threads, sched_active_pid, max_threads, _tcb_name_offset +@raggedright +sched_threads, sched_num_threads, sched_active_pid, max_threads, +_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 -some, eg. FreeRTOS and uC/OS-III, extra steps must be taken. +some, eg. FreeRTOS, uC/OS-III and Zephyr, extra steps must be taken. + +Zephyr must be compiled with the DEBUG_THREAD_INFO option. This will generate some symbols +with information needed in order to build the list of threads. -These RTOSes may require additional OpenOCD-specific file to be linked +FreeRTOS and uC/OS-III RTOSes may require additional OpenOCD-specific file to be linked along with the project: @table @code @@ -10633,57 +12631,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 @@ -10732,16 +12679,10 @@ should be passed in to the proc in question. @section Internal low-level Commands -By "low-level," we mean commands that a human would typically not +By "low-level", we mean commands that a human would typically not invoke directly. -@itemize @bullet -@item @b{mem2array} <@var{varname}> <@var{width}> <@var{addr}> <@var{nelems}> - -Read memory and return as a Tcl array for script processing -@item @b{array2mem} <@var{varname}> <@var{width}> <@var{addr}> <@var{nelems}> - -Convert a Tcl array to memory locations and write the values +@itemize @item @b{flash banks} <@var{driver}> <@var{base}> <@var{size}> <@var{chip_width}> <@var{bus_width}> <@var{target}> [@option{driver options} ...] Return information about the flash banks @@ -10749,7 +12690,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" @@ -10761,34 +12702,6 @@ OpenOCD commands can consist of two words, e.g. "flash banks". The @file{startup.tcl} "unknown" proc will translate this into a Tcl proc called "flash_banks". -@section OpenOCD specific Global Variables - -Real Tcl has ::tcl_platform(), and platform::identify, and many other -variables. JimTCL, as implemented in OpenOCD creates $ocd_HOSTOS which -holds one of the following values: - -@itemize @bullet -@item @b{cygwin} Running under Cygwin -@item @b{darwin} Darwin (Mac-OS) is the underlying operating system. -@item @b{freebsd} Running under FreeBSD -@item @b{openbsd} Running under OpenBSD -@item @b{netbsd} Running under NetBSD -@item @b{linux} Linux is the underlying operating system -@item @b{mingw32} Running under MingW32 -@item @b{winxx} Built using Microsoft Visual Studio -@item @b{ecos} Running under eCos -@item @b{other} Unknown, none of the above. -@end itemize - -Note: 'winxx' was chosen because today (March-2009) no distinction is made between Win32 and Win64. - -@quotation Note -We should add support for a variable like Tcl variable -@code{tcl_platform(platform)}, it should be called -@code{jim_platform} (because it -is jim, not real tcl). -@end quotation - @section Tcl RPC server @cindex RPC @@ -10822,7 +12735,7 @@ type target_state state [state-name] type target_reset mode [reset-mode] @end verbatim -@deffn {Command} tcl_notifications [on/off] +@deffn {Command} {tcl_notifications} [on/off] Toggle output of target notifications to the current Tcl RPC server. Only available from the Tcl RPC server. Defaults to off. @@ -10841,7 +12754,7 @@ Target trace data is emitted as a Tcl associative array in the following format. type target_trace data [trace-data-hex-encoded] @end verbatim -@deffn {Command} tcl_trace [on/off] +@deffn {Command} {tcl_trace} [on/off] Toggle output of target trace data to the current Tcl RPC server. Only available from the Tcl RPC server. Defaults to off. @@ -11033,7 +12946,7 @@ your C code, do the same - artificially push some zeros onto the stack, remember to pop them off when the ISR is done. @b{Also note:} If you have a multi-threaded operating system, they -often do not @b{in the intrest of saving memory} waste these few +often do not @b{in the interest of saving memory} waste these few bytes. Painful... @@ -11285,7 +13198,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()'' @@ -11411,7 +13324,7 @@ it reads a file and executes as a script. @example set x 6 set y 7 - puts [format "The answer: %d" [expr $x * $y]] + puts [format "The answer: %d" [expr @{$x * $y@}]] @end example @enumerate @item The SET command creates 2 variables, X and Y. @@ -11482,13 +13395,13 @@ proc myproc @{ @} @{ @b{Dynamic variable creation} @example # Dynamically create a bunch of variables. -for @{ set x 0 @} @{ $x < 32 @} @{ set x [expr $x + 1]@} @{ +for @{ set x 0 @} @{ $x < 32 @} @{ set x [expr @{$x + 1@}]@} @{ # Create var name set vn [format "BIT%d" $x] # Make it a global global $vn # Set it. - set $vn [expr (1 << $x)] + set $vn [expr @{1 << $x@}] @} @end example @b{Dynamic proc/command creation} @@ -11499,6 +13412,8 @@ foreach who @{A B C D E@} @} @end example +@node License +@appendix The GNU Free Documentation License. @include fdl.texi @node OpenOCD Concept Index 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 0aa0fb4e3a..1933e5457b 160000 --- a/jimtcl +++ b/jimtcl @@ -1 +1 @@ -Subproject commit 0aa0fb4e3a38d38a49de9eb585d93d63a370dcf6 +Subproject commit 1933e5457b9512d39ebbe11ed32578aada149f49 diff --git a/src/Makefile.am b/src/Makefile.am index 07981aa67e..6d79cd6311 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 @@ -53,7 +55,8 @@ endif %D%/target/libtarget.la \ %D%/server/libserver.la \ %D%/rtos/librtos.la \ - %D%/helper/libhelper.la + %D%/helper/libhelper.la \ + %D%/rtt/librtt.la BIN2C = $(srcdir)/%D%/helper/bin2char.sh @@ -64,6 +67,7 @@ BUILT_SOURCES += %D%/startup_tcl.inc # Convert .tcl to c-array %D%/startup_tcl.inc: $(STARTUP_TCL_SRCS) + mkdir -p %D% cat $^ | $(BIN2C) > $@ || { rm -f $@; false; } # add generated files to make clean list @@ -83,3 +87,4 @@ include %D%/rtos/Makefile.am include %D%/server/Makefile.am include %D%/flash/Makefile.am include %D%/pld/Makefile.am +include %D%/rtt/Makefile.am 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 3e2551192f..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 @@ -25,14 +14,14 @@ unsigned get_flash_name_index(const char *name) { const char *name_index = strrchr(name, '.'); - if (NULL == name_index) + if (!name_index) return 0; if (name_index[1] < '0' || name_index[1] > '9') return ~0U; unsigned requested; int retval = parse_uint(name_index + 1, &requested); /* detect parsing error by forcing past end of bank list */ - return (ERROR_OK == retval) ? requested : ~0U; + return (retval == ERROR_OK) ? requested : ~0U; } bool flash_driver_name_matches(const char *name, const char *expected) diff --git a/src/flash/common.h b/src/flash/common.h index 4244f13606..15aea5b810 100644 --- a/src/flash/common.h +++ b/src/flash/common.h @@ -1,24 +1,14 @@ +/* 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 #define OPENOCD_FLASH_COMMON_H #include <helper/log.h> +#include <helper/replacements.h> /** * Parses the optional '.index' portion of a flash bank identifier. 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 e319f95852..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 @@ -55,7 +44,7 @@ static int arm_code_to_working_area(struct target *target, */ /* make sure we have a working area */ - if (NULL == *area) { + if (!*area) { retval = target_alloc_working_area(target, size, area); if (retval != ERROR_OK) { LOG_DEBUG("%s: no %d byte buffer", __func__, (int) size); @@ -173,7 +162,7 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size) buf_set_u32(reg_params[2].value, 0, 32, size); /* armv4 must exit using a hardware breakpoint */ - if (arm->is_armv4) + if (arm->arch == ARM_ARCH_V4) exit_var = nand->copy_area->address + target_code_size - 4; /* use alg to write data from work area to NAND chip */ @@ -279,7 +268,7 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size) buf_set_u32(reg_params[2].value, 0, 32, size); /* armv4 must exit using a hardware breakpoint */ - if (arm->is_armv4) + if (arm->arch == ARM_ARCH_V4) exit_var = nand->copy_area->address + target_code_size - 4; /* use alg to write data from NAND chip to work area */ 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 47c0505630..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 @@ -25,13 +14,13 @@ #include "imp.h" #include "arm_io.h" -#define AT91C_PIOx_SODR (0x30) /**< Offset to PIO SODR. */ -#define AT91C_PIOx_CODR (0x34) /**< Offset to PIO CODR. */ -#define AT91C_PIOx_PDSR (0x3C) /**< Offset to PIO PDSR. */ -#define AT91C_ECCx_CR (0x00) /**< Offset to ECC CR. */ -#define AT91C_ECCx_SR (0x08) /**< Offset to ECC SR. */ -#define AT91C_ECCx_PR (0x0C) /**< Offset to ECC PR. */ -#define AT91C_ECCx_NPR (0x10) /**< Offset to ECC NPR. */ +#define AT91C_PIOX_SODR (0x30) /**< Offset to PIO SODR. */ +#define AT91C_PIOX_CODR (0x34) /**< Offset to PIO CODR. */ +#define AT91C_PIOX_PDSR (0x3C) /**< Offset to PIO PDSR. */ +#define AT91C_ECCX_CR (0x00) /**< Offset to ECC CR. */ +#define AT91C_ECCX_SR (0x08) /**< Offset to ECC SR. */ +#define AT91C_ECCX_PR (0x0C) /**< Offset to ECC PR. */ +#define AT91C_ECCX_NPR (0x10) /**< Offset to ECC NPR. */ /** * Representation of a pin on an AT91SAM9 chip. @@ -105,7 +94,7 @@ static int at91sam9_init(struct nand_device *nand) /** * Enable NAND device attached to a controller. * - * @param info NAND controller information for controlling NAND device. + * @param nand NAND controller information for controlling NAND device. * @return Success or failure of the enabling. */ static int at91sam9_enable(struct nand_device *nand) @@ -113,13 +102,13 @@ static int at91sam9_enable(struct nand_device *nand) struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; - return target_write_u32(target, info->ce.pioc + AT91C_PIOx_CODR, 1 << info->ce.num); + return target_write_u32(target, info->ce.pioc + AT91C_PIOX_CODR, 1 << info->ce.num); } /** * Disable NAND device attached to a controller. * - * @param info NAND controller information for controlling NAND device. + * @param nand NAND controller information for controlling NAND device. * @return Success or failure of the disabling. */ static int at91sam9_disable(struct nand_device *nand) @@ -127,7 +116,7 @@ static int at91sam9_disable(struct nand_device *nand) struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; - return target_write_u32(target, info->ce.pioc + AT91C_PIOx_SODR, 1 << info->ce.num); + return target_write_u32(target, info->ce.pioc + AT91C_PIOX_SODR, 1 << info->ce.num); } /** @@ -237,7 +226,7 @@ static int at91sam9_nand_ready(struct nand_device *nand, int timeout) return 0; do { - target_read_u32(target, info->busy.pioc + AT91C_PIOx_PDSR, &status); + target_read_u32(target, info->busy.pioc + AT91C_PIOX_PDSR, &status); if (status & (1 << info->busy.num)) return 1; @@ -311,7 +300,7 @@ static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info) } /* reset ECC parity registers */ - return target_write_u32(target, info->ecc + AT91C_ECCx_CR, 1); + return target_write_u32(target, info->ecc + AT91C_ECCX_CR, 1); } /** @@ -368,23 +357,23 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page, uint32_t status; retval = at91sam9_ecc_init(target, info); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = nand_page_command(nand, page, NAND_CMD_READ0, !data); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (data) { retval = nand_read_data_page(nand, data, data_size); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; } oob_data = at91sam9_oob_init(nand, oob, &oob_size); retval = nand_read_data_page(nand, oob_data, oob_size); - if (ERROR_OK == retval && data) { - target_read_u32(target, info->ecc + AT91C_ECCx_SR, &status); + if (retval == ERROR_OK && data) { + target_read_u32(target, info->ecc + AT91C_ECCX_SR, &status); if (status & 1) { LOG_ERROR("Error detected!"); if (status & 4) @@ -394,7 +383,7 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page, uint32_t parity; target_read_u32(target, - info->ecc + AT91C_ECCx_PR, + info->ecc + AT91C_ECCX_PR, &parity); uint32_t word = (parity & 0x0000FFF0) >> 4; uint32_t bit = parity & 0x0F; @@ -443,16 +432,16 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page, uint32_t parity, nparity; retval = at91sam9_ecc_init(target, info); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (data) { retval = nand_write_data_page(nand, data, data_size); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to NAND device"); return retval; } @@ -462,8 +451,8 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page, if (!oob) { /* no OOB given, so read in the ECC parity from the ECC controller */ - target_read_u32(target, info->ecc + AT91C_ECCx_PR, &parity); - target_read_u32(target, info->ecc + AT91C_ECCx_NPR, &nparity); + target_read_u32(target, info->ecc + AT91C_ECCX_PR, &parity); + target_read_u32(target, info->ecc + AT91C_ECCX_NPR, &nparity); oob_data[0] = (uint8_t) parity; oob_data[1] = (uint8_t) (parity >> 8); @@ -476,7 +465,7 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page, if (!oob) free(oob_data); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Unable to write OOB data to NAND"); return retval; } diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c index baef5d59cb..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 @@ -180,7 +169,7 @@ static struct nand_device *get_nand_device_by_name(const char *name) unsigned found = 0; struct nand_device *nand; - for (nand = nand_devices; NULL != nand; nand = nand->next) { + for (nand = nand_devices; nand; nand = nand->next) { if (strcmp(nand->name, name) == 0) return nand; if (!flash_driver_name_matches(nand->controller->name, name)) @@ -682,7 +671,7 @@ int nand_write_page(struct nand_device *nand, uint32_t page, if (nand->blocks[block].is_erased == 1) nand->blocks[block].is_erased = 0; - if (nand->use_raw || nand->controller->write_page == NULL) + if (nand->use_raw || !nand->controller->write_page) return nand_write_page_raw(nand, page, data, data_size, oob, oob_size); else return nand->controller->write_page(nand, page, data, data_size, oob, oob_size); @@ -695,7 +684,7 @@ int nand_read_page(struct nand_device *nand, uint32_t page, if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; - if (nand->use_raw || nand->controller->read_page == NULL) + if (nand->use_raw || !nand->controller->read_page) return nand_read_page_raw(nand, page, data, data_size, oob, oob_size); else return nand->controller->read_page(nand, page, data, data_size, oob, oob_size); @@ -750,7 +739,7 @@ int nand_page_command(struct nand_device *nand, uint32_t page, nand->controller->address(nand, (page >> 16) & 0xff); /* large page devices need a start command if reading */ - if (NAND_CMD_READ0 == cmd) + if (cmd == NAND_CMD_READ0) nand->controller->command(nand, NAND_CMD_READSTART); } @@ -769,10 +758,10 @@ int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size) { int retval = ERROR_NAND_NO_BUFFER; - if (nand->controller->read_block_data != NULL) + if (nand->controller->read_block_data) retval = (nand->controller->read_block_data)(nand, data, size); - if (ERROR_NAND_NO_BUFFER == retval) { + if (retval == ERROR_NAND_NO_BUFFER) { uint32_t i; int incr = (nand->device->options & NAND_BUSWIDTH_16) ? 2 : 1; @@ -793,7 +782,7 @@ int nand_read_page_raw(struct nand_device *nand, uint32_t page, int retval; retval = nand_page_command(nand, page, NAND_CMD_READ0, !data); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (data) @@ -809,10 +798,10 @@ int nand_write_data_page(struct nand_device *nand, uint8_t *data, uint32_t size) { int retval = ERROR_NAND_NO_BUFFER; - if (nand->controller->write_block_data != NULL) + if (nand->controller->write_block_data) retval = (nand->controller->write_block_data)(nand, data, size); - if (ERROR_NAND_NO_BUFFER == retval) { + if (retval == ERROR_NAND_NO_BUFFER) { bool is16bit = nand->device->options & NAND_BUSWIDTH_16; uint32_t incr = is16bit ? 2 : 1; uint16_t write_data; @@ -825,7 +814,7 @@ int nand_write_data_page(struct nand_device *nand, uint8_t *data, uint32_t size) write_data = *data; retval = nand->controller->write_data(nand, write_data); - if (ERROR_OK != retval) + if (retval != ERROR_OK) break; data += incr; @@ -849,7 +838,7 @@ int nand_write_finish(struct nand_device *nand) return ERROR_NAND_OPERATION_TIMEOUT; retval = nand_read_status(nand, &status); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("couldn't read status"); return ERROR_NAND_OPERATION_FAILED; } @@ -870,12 +859,12 @@ int nand_write_page_raw(struct nand_device *nand, uint32_t page, int retval; retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (data) { retval = nand_write_data_page(nand, data, data_size); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to NAND device"); return retval; } @@ -883,7 +872,7 @@ int nand_write_page_raw(struct nand_device *nand, uint32_t page, if (oob) { retval = nand_write_data_page(nand, oob, oob_size); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Unable to write OOB data to NAND device"); return retval; } diff --git a/src/flash/nand/core.h b/src/flash/nand/core.h index 5bf9fb3d19..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 @@ -100,7 +89,7 @@ struct nand_info { const char *name; }; -/* Option constants for bizarre disfunctionality and real features +/* Option constants for bizarre dysfunctionality and real features */ enum { /* Chip can not auto increment pages */ @@ -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 167b401504..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 */ @@ -731,7 +718,7 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command) } info = calloc(1, sizeof(*info)); - if (info == NULL) + if (!info) goto fail; info->eccmode = eccmode; diff --git a/src/flash/nand/driver.c b/src/flash/nand/driver.c index f7665603f0..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 }; @@ -75,7 +44,7 @@ int nand_driver_walk(nand_driver_walker_t f, void *x) { for (unsigned i = 0; nand_flash_controllers[i]; i++) { int retval = (*f)(nand_flash_controllers[i], x); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; } return ERROR_OK; 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 fee4012923..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 @@ -65,10 +54,10 @@ int nand_fileio_start(struct command_invocation *cmd, duration_start(&state->bench); - if (NULL != filename) { + if (filename) { int retval = fileio_open(&state->fileio, filename, filemode, FILEIO_BINARY); - if (ERROR_OK != retval) { - const char *msg = (FILEIO_READ == filemode) ? "read" : "write"; + if (retval != ERROR_OK) { + const char *msg = (filemode == FILEIO_READ) ? "read" : "write"; command_print(cmd, "failed to open '%s' for %s access", filename, msg); return retval; @@ -119,15 +108,15 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state, nand_fileio_init(state); unsigned minargs = need_size ? 4 : 3; - if (CMD_ARGC < minargs) + if (minargs > CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; struct nand_device *nand; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; - if (NULL == nand->device) { + if (!nand->device) { command_print(CMD, "#%s: not probed", CMD_ARGV[0]); return ERROR_NAND_DEVICE_NOT_PROBED; } @@ -141,7 +130,7 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state, } } - if (CMD_ARGC > minargs) { + if (minargs < CMD_ARGC) { for (unsigned i = minargs; i < CMD_ARGC; i++) { if (!strcmp(CMD_ARGV[i], "oob_raw")) state->oob_format |= NAND_OOB_RAW; @@ -159,7 +148,7 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state, } retval = nand_fileio_start(CMD, nand, CMD_ARGV[1], filemode, state); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (!need_size) { @@ -184,7 +173,7 @@ int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s) size_t total_read = 0; size_t one_read; - if (NULL != s->page) { + if (s->page) { fileio_read(s->fileio, s->page_size, s->page, &one_read); if (one_read < s->page_size) memset(s->page + one_read, 0xff, s->page_size - one_read); @@ -213,7 +202,7 @@ int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s) nand_calculate_ecc_kw(nand, s->page + i, ecc); ecc += 10; } - } else if (NULL != s->oob) { + } else if (s->oob) { fileio_read(s->fileio, s->oob_size, s->oob, &one_read); if (one_read < s->oob_size) memset(s->oob + one_read, 0xff, s->oob_size - one_read); 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 97bd7a351e..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 @@ -139,9 +128,9 @@ static int lpc3180_init(struct nand_device *nand) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; - int bus_width = nand->bus_width ? : 8; - int address_cycles = nand->address_cycles ? : 3; - int page_size = nand->page_size ? : 512; + int bus_width = nand->bus_width ? nand->bus_width : 8; + int address_cycles = nand->address_cycles ? nand->address_cycles : 3; + int page_size = nand->page_size ? nand->page_size : 512; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); @@ -589,7 +578,7 @@ static int lpc3180_write_page(struct nand_device *nand, oob_size); } retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* allocate a working area */ @@ -970,7 +959,7 @@ static int lpc3180_read_page(struct nand_device *nand, /* read always the data and also oob areas*/ retval = nand_page_command(nand, page, NAND_CMD_READ0, 0); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* allocate a working area */ 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 d516522f3d..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. @@ -60,14 +47,14 @@ static const int lp_ooblayout[] = { 58, 59, 60, 61, 62, 63 }; -typedef struct { +struct dmac_ll { volatile uint32_t dma_src; volatile uint32_t dma_dest; volatile uint32_t next_lli; volatile uint32_t next_ctrl; -} dmac_ll_t; +}; -static dmac_ll_t dmalist[(2048/256) * 2 + 1]; +static struct dmac_ll dmalist[(2048/256) * 2 + 1]; /* nand device lpc32xx <target#> <oscillator_frequency> */ @@ -90,7 +77,7 @@ NAND_DEVICE_COMMAND_HANDLER(lpc32xx_nand_device_command) "1000 and 20000 kHz, was %i", lpc32xx_info->osc_freq); - lpc32xx_info->selected_controller = LPC32xx_NO_CONTROLLER; + lpc32xx_info->selected_controller = LPC32XX_NO_CONTROLLER; lpc32xx_info->sw_write_protection = 0; lpc32xx_info->sw_wp_lower_bound = 0x0; lpc32xx_info->sw_wp_upper_bound = 0x0; @@ -141,7 +128,7 @@ static float lpc32xx_cycle_time(struct nand_device *nand) /* determine current SYSCLK (13'MHz or main oscillator) */ retval = target_read_u32(target, 0x40004050, &sysclk_ctrl); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not read SYSCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } @@ -153,7 +140,7 @@ static float lpc32xx_cycle_time(struct nand_device *nand) /* determine selected HCLK source */ retval = target_read_u32(target, 0x40004044, &pwr_ctrl); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not read HCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } @@ -162,14 +149,14 @@ static float lpc32xx_cycle_time(struct nand_device *nand) hclk = sysclk; else { retval = target_read_u32(target, 0x40004058, &hclkpll_ctrl); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not read HCLKPLL_CTRL"); return ERROR_NAND_OPERATION_FAILED; } hclk_pll = lpc32xx_pll(sysclk, hclkpll_ctrl); retval = target_read_u32(target, 0x40004040, &hclkdiv_ctrl); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not read CLKDIV_CTRL"); return ERROR_NAND_OPERATION_FAILED; } @@ -191,9 +178,9 @@ static int lpc32xx_init(struct nand_device *nand) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; - int bus_width = nand->bus_width ? : 8; - int address_cycles = nand->address_cycles ? : 3; - int page_size = nand->page_size ? : 512; + int bus_width = nand->bus_width ? nand->bus_width : 8; + int address_cycles = nand->address_cycles ? nand->address_cycles : 3; + int page_size = nand->page_size ? nand->page_size : 512; int retval; if (target->state != TARGET_HALTED) { @@ -222,34 +209,34 @@ static int lpc32xx_init(struct nand_device *nand) } /* select MLC controller if none is currently selected */ - if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { + if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_DEBUG("no LPC32xx NAND flash controller selected, " "using default 'slc'"); - lpc32xx_info->selected_controller = LPC32xx_SLC_CONTROLLER; + lpc32xx_info->selected_controller = LPC32XX_SLC_CONTROLLER; } - if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { + if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { uint32_t mlc_icr_value = 0x0; float cycle; int twp, twh, trp, treh, trhz, trbwb, tcea; /* FLASHCLK_CTRL = 0x22 (enable clk for MLC) */ retval = target_write_u32(target, 0x400040c8, 0x22); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set FLASHCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_CEH = 0x0 (Force nCE assert) */ retval = target_write_u32(target, 0x200b804c, 0x0); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CEH"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_LOCK = 0xa25e (unlock protected registers) */ retval = target_write_u32(target, 0x200b8044, 0xa25e); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_LOCK"); return ERROR_NAND_OPERATION_FAILED; } @@ -264,7 +251,7 @@ static int lpc32xx_init(struct nand_device *nand) if (bus_width == 16) mlc_icr_value |= 0x1; retval = target_write_u32(target, 0x200b8030, mlc_icr_value); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ICR"); return ERROR_NAND_OPERATION_FAILED; } @@ -282,7 +269,7 @@ static int lpc32xx_init(struct nand_device *nand) /* MLC_LOCK = 0xa25e (unlock protected registers) */ retval = target_write_u32(target, 0x200b8044, 0xa25e); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_LOCK"); return ERROR_NAND_OPERATION_FAILED; } @@ -296,22 +283,22 @@ static int lpc32xx_init(struct nand_device *nand) | ((trhz & 0x7) << 16) | ((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24)); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_TIME_REG"); return ERROR_NAND_OPERATION_FAILED; } retval = lpc32xx_reset(nand); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return ERROR_NAND_OPERATION_FAILED; - } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { float cycle; int r_setup, r_hold, r_width, r_rdy; int w_setup, w_hold, w_width, w_rdy; /* FLASHCLK_CTRL = 0x05 (enable clk for SLC) */ retval = target_write_u32(target, 0x400040c8, 0x05); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set FLASHCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } @@ -320,7 +307,7 @@ static int lpc32xx_init(struct nand_device *nand) * so reset calling is here at the beginning */ retval = lpc32xx_reset(nand); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return ERROR_NAND_OPERATION_FAILED; /* SLC_CFG = @@ -333,14 +320,14 @@ static int lpc32xx_init(struct nand_device *nand) */ retval = target_write_u32(target, 0x20020014, 0x3e | ((bus_width == 16) ? 1 : 0)); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_CFG"); return ERROR_NAND_OPERATION_FAILED; } /* SLC_IEN = 3 (INT_RDY_EN = 1) ,(INT_TC_STAT = 1) */ retval = target_write_u32(target, 0x20020020, 0x03); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_IEN"); return ERROR_NAND_OPERATION_FAILED; } @@ -349,14 +336,14 @@ static int lpc32xx_init(struct nand_device *nand) /* DMACLK_CTRL = 0x01 (enable clock for DMA controller) */ retval = target_write_u32(target, 0x400040e8, 0x01); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set DMACLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } /* DMACConfig = DMA enabled*/ retval = target_write_u32(target, 0x31000030, 0x01); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set DMACConfig"); return ERROR_NAND_OPERATION_FAILED; } @@ -380,7 +367,7 @@ static int lpc32xx_init(struct nand_device *nand) | ((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28)); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_TAC"); return ERROR_NAND_OPERATION_FAILED; } @@ -401,13 +388,13 @@ static int lpc32xx_reset(struct nand_device *nand) return ERROR_NAND_OPERATION_FAILED; } - if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { + if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; - } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { /* MLC_CMD = 0xff (reset controller and NAND device) */ retval = target_write_u32(target, 0x200b8000, 0xff); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } @@ -417,10 +404,10 @@ static int lpc32xx_reset(struct nand_device *nand) "after reset"); return ERROR_NAND_OPERATION_TIMEOUT; } - } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { /* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */ retval = target_write_u32(target, 0x20020010, 0x6); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_CTRL"); return ERROR_NAND_OPERATION_FAILED; } @@ -447,20 +434,20 @@ static int lpc32xx_command(struct nand_device *nand, uint8_t command) return ERROR_NAND_OPERATION_FAILED; } - if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { + if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; - } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { /* MLC_CMD = command */ retval = target_write_u32(target, 0x200b8000, command); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } - } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { /* SLC_CMD = command */ retval = target_write_u32(target, 0x20020008, command); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } @@ -481,20 +468,20 @@ static int lpc32xx_address(struct nand_device *nand, uint8_t address) return ERROR_NAND_OPERATION_FAILED; } - if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { + if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; - } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { /* MLC_ADDR = address */ retval = target_write_u32(target, 0x200b8004, address); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } - } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { /* SLC_ADDR = address */ retval = target_write_u32(target, 0x20020004, address); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } @@ -515,20 +502,20 @@ static int lpc32xx_write_data(struct nand_device *nand, uint16_t data) return ERROR_NAND_OPERATION_FAILED; } - if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { + if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; - } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { /* MLC_DATA = data */ retval = target_write_u32(target, 0x200b0000, data); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } - } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { /* SLC_DATA = data */ retval = target_write_u32(target, 0x20020000, data); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } @@ -549,10 +536,10 @@ static int lpc32xx_read_data(struct nand_device *nand, void *data) return ERROR_NAND_OPERATION_FAILED; } - if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { + if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; - } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { /* data = MLC_DATA, use sized access */ if (nand->bus_width == 8) { uint8_t *data8 = data; @@ -561,16 +548,16 @@ static int lpc32xx_read_data(struct nand_device *nand, void *data) LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); return ERROR_NAND_OPERATION_FAILED; } - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not read MLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } - } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { uint32_t data32; /* data = SLC_DATA, must use 32-bit access */ retval = target_read_u32(target, 0x20020000, &data32); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not read SLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } @@ -600,7 +587,7 @@ static int lpc32xx_write_page_mlc(struct nand_device *nand, uint32_t page, /* MLC_CMD = sequential input */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } @@ -608,20 +595,20 @@ static int lpc32xx_write_page_mlc(struct nand_device *nand, uint32_t page, if (nand->page_size == 512) { /* MLC_ADDR = 0x0 (one column cycle) */ retval = target_write_u32(target, 0x200b8004, 0x0); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } @@ -629,7 +616,7 @@ static int lpc32xx_write_page_mlc(struct nand_device *nand, uint32_t page, if (nand->address_cycles == 4) { retval = target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } @@ -637,25 +624,25 @@ static int lpc32xx_write_page_mlc(struct nand_device *nand, uint32_t page, } else { /* MLC_ADDR = 0x0 (two column cycles) */ retval = target_write_u32(target, 0x200b8004, 0x0); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, 0x0); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } @@ -687,27 +674,27 @@ static int lpc32xx_write_page_mlc(struct nand_device *nand, uint32_t page, /* write MLC_ECC_ENC_REG to start encode cycle */ retval = target_write_u32(target, 0x200b8008, 0x0); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ECC_ENC_REG"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_memory(target, 0x200a8000, 4, 128, page_buffer); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_BUF (data)"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_memory(target, 0x200a8000, 1, 6, oob_buffer); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_BUF (oob)"); return ERROR_NAND_OPERATION_FAILED; } /* write MLC_ECC_AUTO_ENC_REG to start auto encode */ retval = target_write_u32(target, 0x200b8010, 0x0); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ECC_AUTO_ENC_REG"); return ERROR_NAND_OPERATION_FAILED; } @@ -721,7 +708,7 @@ static int lpc32xx_write_page_mlc(struct nand_device *nand, uint32_t page, /* MLC_CMD = auto program command */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } @@ -867,14 +854,14 @@ static int lpc32xx_make_dma_list(uint32_t target_mem_base, uint32_t page_size, dmalist[i*2].dma_src = (do_read ? dmasrc : (dmasrc + i * 256)); dmalist[i*2].dma_dest = (do_read ? (dmadst + i * 256) : dmadst); dmalist[i*2].next_lli = - target_mem_base + (i*2 + 1) * sizeof(dmac_ll_t); + target_mem_base + (i*2 + 1) * sizeof(struct dmac_ll); dmalist[i*2].next_ctrl = ctrl; dmalist[(i*2) + 1].dma_src = 0x20020034;/* SLC_ECC */ dmalist[(i*2) + 1].dma_dest = target_mem_base + ECC_OFFS + i * 4; dmalist[(i*2) + 1].next_lli = - target_mem_base + (i*2 + 2) * sizeof(dmac_ll_t); + target_mem_base + (i*2 + 2) * sizeof(struct dmac_ll); dmalist[(i*2) + 1].next_ctrl = ecc_ctrl; } @@ -901,14 +888,14 @@ static int lpc32xx_start_slc_dma(struct nand_device *nand, uint32_t count, /* DMACIntTCClear = ch0 */ retval = target_write_u32(target, 0x31000008, 1); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not set DMACIntTCClear"); return retval; } /* DMACIntErrClear = ch0 */ retval = target_write_u32(target, 0x31000010, 1); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not set DMACIntErrClear"); return retval; } @@ -926,28 +913,28 @@ static int lpc32xx_start_slc_dma(struct nand_device *nand, uint32_t count, retval = target_write_u32(target, 0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not set DMACC0Config"); return retval; } /* SLC_CTRL = 3 (START DMA), ECC_CLEAR */ retval = target_write_u32(target, 0x20020010, 0x3); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not set SLC_CTRL"); return retval; } /* SLC_ICR = 2, INT_TC_CLR, clear pending TC*/ retval = target_write_u32(target, 0x20020028, 2); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not set SLC_ICR"); return retval; } /* SLC_TC */ retval = target_write_u32(target, 0x20020030, count); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("lpc32xx_start_slc_dma: Could not set SLC_TC"); return retval; } @@ -974,13 +961,13 @@ static int lpc32xx_dma_ready(struct nand_device *nand, int timeout) /* Read DMACRawIntTCStat */ retval = target_read_u32(target, 0x31000014, &tc_stat); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not read DMACRawIntTCStat"); return 0; } /* Read DMACRawIntErrStat */ retval = target_read_u32(target, 0x31000018, &err_stat); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not read DMACRawIntErrStat"); return 0; } @@ -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; /* @@ -1063,15 +1050,15 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, XXX: Assumes host and target have same byte sex. */ retval = target_write_memory(target, target_mem_base, 4, - nll * sizeof(dmac_ll_t) / 4, + nll * sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not write DMA descriptors to IRAM"); return retval; } retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("NAND_CMD_SEQIN failed"); return retval; } @@ -1085,7 +1072,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, WIDTH = bus_width */ retval = target_write_u32(target, 0x20020014, 0x3c); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not set SLC_CFG"); return retval; } @@ -1097,16 +1084,16 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, retval = target_write_memory(target, target_mem_base + DATA_OFFS, 4, nand->page_size/4, fdata); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not write data to IRAM"); return retval; } /* Write first descriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, - sizeof(dmac_ll_t) / 4, + sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not write DMA descriptor to DMAC"); return retval; } @@ -1115,7 +1102,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, int tot_size = nand->page_size; tot_size += tot_size == 2048 ? 64 : 16; retval = lpc32xx_start_slc_dma(nand, tot_size, 0); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("DMA failed"); return retval; } @@ -1139,7 +1126,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, static uint32_t hw_ecc[8]; retval = target_read_memory(target, target_mem_base + ECC_OFFS, 4, ecc_count, (uint8_t *)hw_ecc); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Reading hw generated ECC from IRAM failed"); return retval; } @@ -1154,16 +1141,16 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, } retval = target_write_memory(target, target_mem_base + SPARE_OFFS, 4, foob_size / 4, foob); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Writing OOB to IRAM failed"); return retval; } /* Write OOB descriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, - sizeof(dmac_ll_t) / 4, + sizeof(struct dmac_ll) / 4, (uint8_t *)(&dmalist[nll-1])); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not write OOB DMA descriptor to DMAC"); return retval; } @@ -1173,7 +1160,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, /* DMACIntTCClear = ch0 */ retval = target_write_u32(target, 0x31000008, 1); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not set DMACIntTCClear"); return retval; } @@ -1190,7 +1177,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, retval = target_write_u32(target, 0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not set DMACC0Config"); return retval; } @@ -1203,7 +1190,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, } else { /* Start xfer of data from iram to flash using DMA */ retval = lpc32xx_start_slc_dma(nand, foob_size, 1); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("DMA OOB failed"); return retval; } @@ -1211,7 +1198,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, /* Let NAND start actual writing */ retval = nand_write_finish(nand); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("nand_write_finish failed"); return retval; } @@ -1233,10 +1220,10 @@ static int lpc32xx_write_page(struct nand_device *nand, uint32_t page, return ERROR_NAND_OPERATION_FAILED; } - if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { + if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; - } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { if (!data && oob) { LOG_ERROR("LPC32xx MLC controller can't write " "OOB data only"); @@ -1256,7 +1243,7 @@ static int lpc32xx_write_page(struct nand_device *nand, uint32_t page, retval = lpc32xx_write_page_mlc(nand, page, data, data_size, oob, oob_size); - } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { struct working_area *pworking_area; if (!data && oob) { /* @@ -1307,7 +1294,7 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, /* MLC_CMD = Read0 */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_READ0); } - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } @@ -1315,20 +1302,20 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, /* small page device * MLC_ADDR = 0x0 (one column cycle) */ retval = target_write_u32(target, 0x200b8004, 0x0); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } @@ -1336,7 +1323,7 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, if (nand->address_cycles == 4) { retval = target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } @@ -1345,25 +1332,25 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, /* large page device * MLC_ADDR = 0x0 (two column cycles) */ retval = target_write_u32(target, 0x200b8004, 0x0); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, 0x0); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } @@ -1371,7 +1358,7 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, /* MLC_CMD = Read Start */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_READSTART); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } @@ -1380,7 +1367,7 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, while (page_bytes_done < (uint32_t)nand->page_size) { /* MLC_ECC_AUTO_DEC_REG = dummy */ retval = target_write_u32(target, 0x200b8014, 0xaa55aa55); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_ECC_AUTO_DEC_REG"); return ERROR_NAND_OPERATION_FAILED; } @@ -1392,7 +1379,7 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, } retval = target_read_u32(target, 0x200b8048, &mlc_isr); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not read MLC_ISR"); return ERROR_NAND_OPERATION_FAILED; } @@ -1411,7 +1398,7 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, if (data) { retval = target_read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not read MLC_BUF (data)"); return ERROR_NAND_OPERATION_FAILED; } @@ -1420,7 +1407,7 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, if (oob) { retval = target_read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not read MLC_BUF (oob)"); return ERROR_NAND_OPERATION_FAILED; } @@ -1460,15 +1447,15 @@ static int lpc32xx_read_page_slc(struct nand_device *nand, XXX: Assumes host and target have same byte sex. */ retval = target_write_memory(target, target_mem_base, 4, - nll * sizeof(dmac_ll_t) / 4, + nll * sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not write DMA descriptors to IRAM"); return retval; } retval = nand_page_command(nand, page, NAND_CMD_READ0, 0); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("lpc32xx_read_page_slc: NAND_CMD_READ0 failed"); return retval; } @@ -1482,15 +1469,15 @@ static int lpc32xx_read_page_slc(struct nand_device *nand, WIDTH = bus_width */ retval = target_write_u32(target, 0x20020014, 0x3e); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("lpc32xx_read_page_slc: Could not set SLC_CFG"); return retval; } /* Write first descriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, - sizeof(dmac_ll_t) / 4, (uint8_t *)dmalist); - if (ERROR_OK != retval) { + sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist); + if (retval != ERROR_OK) { LOG_ERROR("Could not write DMA descriptor to DMAC"); return retval; } @@ -1499,7 +1486,7 @@ static int lpc32xx_read_page_slc(struct nand_device *nand, int tot_size = nand->page_size; tot_size += nand->page_size == 2048 ? 64 : 16; retval = lpc32xx_start_slc_dma(nand, tot_size, 1); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("lpc32xx_read_page_slc: DMA read failed"); return retval; } @@ -1508,7 +1495,7 @@ static int lpc32xx_read_page_slc(struct nand_device *nand, if (data) { retval = target_read_memory(target, target_mem_base + DATA_OFFS, 4, data_size/4, data); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not read data from IRAM"); return retval; } @@ -1518,7 +1505,7 @@ static int lpc32xx_read_page_slc(struct nand_device *nand, retval = target_read_memory(target, target_mem_base + SPARE_OFFS, 4, oob_size/4, oob); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not read OOB from IRAM"); return retval; } @@ -1530,7 +1517,7 @@ static int lpc32xx_read_page_slc(struct nand_device *nand, retval = target_read_memory(target, target_mem_base + SPARE_OFFS, 4, nand->page_size == 2048 ? 16 : 4, foob); lpc32xx_dump_oob(foob, nand->page_size == 2048 ? 64 : 16); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not read OOB from IRAM"); return retval; } @@ -1539,7 +1526,7 @@ static int lpc32xx_read_page_slc(struct nand_device *nand, static uint32_t hw_ecc[8]; /* max size */ retval = target_read_memory(target, target_mem_base + ECC_OFFS, 4, ecc_count, (uint8_t *)hw_ecc); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not read hw generated ECC from IRAM"); return retval; } @@ -1584,17 +1571,17 @@ static int lpc32xx_read_page(struct nand_device *nand, uint32_t page, return ERROR_NAND_OPERATION_FAILED; } - if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { + if (lpc32xx_info->selected_controller == LPC32XX_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; - } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { if (data_size > (uint32_t)nand->page_size) { LOG_ERROR("data size exceeds page size"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } retval = lpc32xx_read_page_mlc(nand, page, data, data_size, oob, oob_size); - } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { struct working_area *pworking_area; retval = target_alloc_working_area(target, @@ -1628,12 +1615,12 @@ static int lpc32xx_controller_ready(struct nand_device *nand, int timeout) LOG_DEBUG("lpc32xx_controller_ready count start=%d", timeout); do { - if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { + if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { uint8_t status; /* Read MLC_ISR, wait for controller to become ready */ retval = target_read_u8(target, 0x200b8048, &status); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set MLC_STAT"); return ERROR_NAND_OPERATION_FAILED; } @@ -1643,12 +1630,12 @@ static int lpc32xx_controller_ready(struct nand_device *nand, int timeout) timeout); return 1; } - } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { uint32_t status; /* Read SLC_STAT and check READY bit */ retval = target_read_u32(target, 0x20020018, &status); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not set SLC_STAT"); return ERROR_NAND_OPERATION_FAILED; } @@ -1681,13 +1668,13 @@ static int lpc32xx_nand_ready(struct nand_device *nand, int timeout) LOG_DEBUG("lpc32xx_nand_ready count start=%d", timeout); do { - if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { + if (lpc32xx_info->selected_controller == LPC32XX_MLC_CONTROLLER) { uint8_t status = 0x0; /* Read MLC_ISR, wait for NAND flash device to * become ready */ retval = target_read_u8(target, 0x200b8048, &status); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not read MLC_ISR"); return ERROR_NAND_OPERATION_FAILED; } @@ -1697,12 +1684,12 @@ static int lpc32xx_nand_ready(struct nand_device *nand, int timeout) timeout); return 1; } - } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { + } else if (lpc32xx_info->selected_controller == LPC32XX_SLC_CONTROLLER) { uint32_t status = 0x0; /* Read SLC_STAT and check READY bit */ retval = target_read_u32(target, 0x20020018, &status); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("could not read SLC_STAT"); return ERROR_NAND_OPERATION_FAILED; } @@ -1731,7 +1718,7 @@ static int lpc32xx_tc_ready(struct nand_device *nand, int timeout) int retval; /* Read SLC_INT_STAT and check INT_TC_STAT bit */ retval = target_read_u32(target, 0x2002001c, &status); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Could not read SLC_INT_STAT"); return 0; } @@ -1770,10 +1757,10 @@ COMMAND_HANDLER(handle_lpc32xx_select_command) if (CMD_ARGC >= 2) { if (strcmp(CMD_ARGV[1], "mlc") == 0) { lpc32xx_info->selected_controller = - LPC32xx_MLC_CONTROLLER; + LPC32XX_MLC_CONTROLLER; } else if (strcmp(CMD_ARGV[1], "slc") == 0) { lpc32xx_info->selected_controller = - LPC32xx_SLC_CONTROLLER; + LPC32XX_SLC_CONTROLLER; } else return ERROR_COMMAND_SYNTAX_ERROR; } diff --git a/src/flash/nand/lpc32xx.h b/src/flash/nand/lpc32xx.h index 90b20b2472..f399142a9f 100644 --- a/src/flash/nand/lpc32xx.h +++ b/src/flash/nand/lpc32xx.h @@ -1,28 +1,17 @@ +/* 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 #define OPENOCD_FLASH_NAND_LPC32XX_H enum lpc32xx_selected_controller { - LPC32xx_NO_CONTROLLER, - LPC32xx_MLC_CONTROLLER, - LPC32xx_SLC_CONTROLLER, + LPC32XX_NO_CONTROLLER, + LPC32XX_MLC_CONTROLLER, + LPC32XX_SLC_CONTROLLER, }; struct lpc32xx_nand_controller { diff --git a/src/flash/nand/mx3.c b/src/flash/nand/mx3.c index b9f5ff1b9f..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/>. * ***************************************************************************/ /* @@ -64,7 +53,7 @@ NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command) { struct mx3_nf_controller *mx3_nf_info; mx3_nf_info = malloc(sizeof(struct mx3_nf_controller)); - if (mx3_nf_info == NULL) { + if (!mx3_nf_info) { LOG_ERROR("no memory for nand controller"); return ERROR_FAIL; } 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 2c5de0394e..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/>. * ***************************************************************************/ /* @@ -89,7 +78,7 @@ NAND_DEVICE_COMMAND_HANDLER(mxc_nand_device_command) int hwecc_needed; mxc_nf_info = malloc(sizeof(struct mxc_nf_controller)); - if (mxc_nf_info == NULL) { + if (!mxc_nf_info) { LOG_ERROR("no memory for nand controller"); return ERROR_FAIL; } @@ -207,9 +196,9 @@ static int mxc_init(struct nand_device *nand) int validate_target_result; uint16_t buffsize_register_content; uint32_t sreg_content; - uint32_t SREG = MX2_FMCR; - uint32_t SEL_16BIT = MX2_FMCR_NF_16BIT_SEL; - uint32_t SEL_FMS = MX2_FMCR_NF_FMS; + uint32_t sreg = MX2_FMCR; + uint32_t sel_16bit = MX2_FMCR_NF_16BIT_SEL; + uint32_t sel_fms = MX2_FMCR_NF_FMS; int retval; uint16_t nand_status_content; /* @@ -226,27 +215,27 @@ static int mxc_init(struct nand_device *nand) mxc_nf_info->flags.one_kb_sram = 0; if (mxc_nf_info->mxc_version == MXC_VERSION_MX31) { - SREG = MX3_PCSR; - SEL_16BIT = MX3_PCSR_NF_16BIT_SEL; - SEL_FMS = MX3_PCSR_NF_FMS; + sreg = MX3_PCSR; + sel_16bit = MX3_PCSR_NF_16BIT_SEL; + sel_fms = MX3_PCSR_NF_FMS; } else if (mxc_nf_info->mxc_version == MXC_VERSION_MX25) { - SREG = MX25_RCSR; - SEL_16BIT = MX25_RCSR_NF_16BIT_SEL; - SEL_FMS = MX25_RCSR_NF_FMS; + sreg = MX25_RCSR; + sel_16bit = MX25_RCSR_NF_16BIT_SEL; + sel_fms = MX25_RCSR_NF_FMS; } else if (mxc_nf_info->mxc_version == MXC_VERSION_MX35) { - SREG = MX35_RCSR; - SEL_16BIT = MX35_RCSR_NF_16BIT_SEL; - SEL_FMS = MX35_RCSR_NF_FMS; + sreg = MX35_RCSR; + sel_16bit = MX35_RCSR_NF_16BIT_SEL; + sel_fms = MX35_RCSR_NF_FMS; } - target_read_u32(target, SREG, &sreg_content); + target_read_u32(target, sreg, &sreg_content); if (!nand->bus_width) { /* bus_width not yet defined. Read it from MXC_FMCR */ - nand->bus_width = (sreg_content & SEL_16BIT) ? 16 : 8; + nand->bus_width = (sreg_content & sel_16bit) ? 16 : 8; } else { /* bus_width forced in soft. Sync it to MXC_FMCR */ - sreg_content |= ((nand->bus_width == 16) ? SEL_16BIT : 0x00000000); - target_write_u32(target, SREG, sreg_content); + sreg_content |= ((nand->bus_width == 16) ? sel_16bit : 0x00000000); + target_write_u32(target, sreg, sreg_content); } if (nand->bus_width == 16) LOG_DEBUG("MXC_NF : bus is 16-bit width"); @@ -254,10 +243,10 @@ static int mxc_init(struct nand_device *nand) LOG_DEBUG("MXC_NF : bus is 8-bit width"); if (!nand->page_size) - nand->page_size = (sreg_content & SEL_FMS) ? 2048 : 512; + nand->page_size = (sreg_content & sel_fms) ? 2048 : 512; else { - sreg_content |= ((nand->page_size == 2048) ? SEL_FMS : 0x00000000); - target_write_u32(target, SREG, sreg_content); + sreg_content |= ((nand->page_size == 2048) ? sel_fms : 0x00000000); + target_write_u32(target, sreg, sreg_content); } if (mxc_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) { LOG_ERROR("NAND controller have only 1 kb SRAM, so " @@ -649,18 +638,18 @@ static int mxc_read_page(struct nand_device *nand, uint32_t page, } if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) { - uint32_t SPARE_BUFFER3; + uint32_t spare_buffer3; /* BI-swap - work-around of mxc NFC for NAND device with page == 2k */ target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1); if (nfc_is_v1()) - SPARE_BUFFER3 = MXC_NF_V1_SPARE_BUFFER3 + 4; + spare_buffer3 = MXC_NF_V1_SPARE_BUFFER3 + 4; else - SPARE_BUFFER3 = MXC_NF_V2_SPARE_BUFFER3; - target_read_u16(target, SPARE_BUFFER3, &swap2); + spare_buffer3 = MXC_NF_V2_SPARE_BUFFER3; + target_read_u16(target, spare_buffer3, &swap2); new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8); swap2 = (swap1 << 8) | (swap2 & 0xFF); target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1); - target_write_u16(target, SPARE_BUFFER3, swap2); + target_write_u16(target, spare_buffer3, swap2); } if (data) @@ -860,7 +849,7 @@ static int validate_target_state(struct nand_device *nand) return ERROR_OK; } -int ecc_status_v1(struct nand_device *nand) +static int ecc_status_v1(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; @@ -886,7 +875,7 @@ int ecc_status_v1(struct nand_device *nand) return ERROR_OK; } -int ecc_status_v2(struct nand_device *nand) +static int ecc_status_v2(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; 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 1a2dd5968c..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/>. * ***************************************************************************/ /* @@ -183,7 +172,7 @@ static int nuc910_nand_init(struct nand_device *nand) { struct nuc910_nand_controller *nuc910_nand = nand->controller_priv; struct target *target = nand->target; - int bus_width = nand->bus_width ? : 8; + int bus_width = nand->bus_width ? nand->bus_width : 8; int result; result = validate_target_state(nand); 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 ae3f137371..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/>. * ***************************************************************************/ /* @@ -34,7 +23,7 @@ S3C24XX_DEVICE_COMMAND() struct s3c24xx_nand_controller *s3c24xx_info; s3c24xx_info = malloc(sizeof(struct s3c24xx_nand_controller)); - if (s3c24xx_info == NULL) { + if (!s3c24xx_info) { LOG_ERROR("no memory for nand controller"); return -ENOMEM; } diff --git a/src/flash/nand/s3c24xx.h b/src/flash/nand/s3c24xx.h index 5c7782dabc..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 @@ -51,7 +40,7 @@ S3C24XX_DEVICE_COMMAND(); #define CALL_S3C24XX_DEVICE_COMMAND(d, i) \ do { \ int retval = CALL_COMMAND_HANDLER(s3c24xx_nand_device_command, d, i); \ - if (ERROR_OK != retval) \ + if (retval != ERROR_OK) \ return retval; \ } while (0) diff --git a/src/flash/nand/s3c24xx_regs.h b/src/flash/nand/s3c24xx_regs.h index 88bc66567e..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/>. * ***************************************************************************/ /* @@ -61,7 +51,7 @@ #define S3C2410_NFCONF_512BYTE (1 << 14) #define S3C2410_NFCONF_4STEP (1 << 13) #define S3C2410_NFCONF_INITECC (1 << 12) -#define S3C2410_NFCONF_nFCE (1 << 11) +#define S3C2410_NFCONF_NFCE (1 << 11) #define S3C2410_NFCONF_TACLS(x) ((x) << 8) #define S3C2410_NFCONF_TWRPH0(x) ((x) << 4) #define S3C2410_NFCONF_TWRPH1(x) ((x) << 0) @@ -83,12 +73,12 @@ #define S3C2440_NFCONT_SPARE_ECCLOCK (1 << 6) #define S3C2440_NFCONT_MAIN_ECCLOCK (1 << 5) #define S3C2440_NFCONT_INITECC (1 << 4) -#define S3C2440_NFCONT_nFCE (1 << 1) +#define S3C2440_NFCONT_NFCE (1 << 1) #define S3C2440_NFCONT_ENABLE (1 << 0) #define S3C2440_NFSTAT_READY (1 << 0) -#define S3C2440_NFSTAT_nCE (1 << 1) -#define S3C2440_NFSTAT_RnB_CHANGE (1 << 2) +#define S3C2440_NFSTAT_NCE (1 << 1) +#define S3C2440_NFSTAT_RNB_CHANGE (1 << 2) #define S3C2440_NFSTAT_ILLEGAL_ACCESS (1 << 3) #define S3C2412_NFCONF_NANDBOOT (1 << 31) @@ -103,16 +93,16 @@ #define S3C2412_NFCONT_ECC4_DECINT (1 << 12) #define S3C2412_NFCONT_MAIN_ECC_LOCK (1 << 7) #define S3C2412_NFCONT_INIT_MAIN_ECC (1 << 5) -#define S3C2412_NFCONT_nFCE1 (1 << 2) -#define S3C2412_NFCONT_nFCE0 (1 << 1) +#define S3C2412_NFCONT_NFCE1 (1 << 2) +#define S3C2412_NFCONT_NFCE0 (1 << 1) #define S3C2412_NFSTAT_ECC_ENCDONE (1 << 7) #define S3C2412_NFSTAT_ECC_DECDONE (1 << 6) #define S3C2412_NFSTAT_ILLEGAL_ACCESS (1 << 5) -#define S3C2412_NFSTAT_RnB_CHANGE (1 << 4) -#define S3C2412_NFSTAT_nFCE1 (1 << 3) -#define S3C2412_NFSTAT_nFCE0 (1 << 2) -#define S3C2412_NFSTAT_Res1 (1 << 1) +#define S3C2412_NFSTAT_RNB_CHANGE (1 << 4) +#define S3C2412_NFSTAT_NFCE1 (1 << 3) +#define S3C2412_NFSTAT_NFCE0 (1 << 2) +#define S3C2412_NFSTAT_RES1 (1 << 1) #define S3C2412_NFSTAT_READY (1 << 0) #define S3C2412_NFECCERR_SERRDATA(x) (((x) >> 21) & 0xf) 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 ca8b9dad4d..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; @@ -83,10 +69,10 @@ COMMAND_HANDLER(handle_nand_info_command) struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; - if (NULL == p->device) { + if (!p->device) { command_print(CMD, "#%s: not probed", CMD_ARGV[0]); return ERROR_OK; } @@ -142,7 +128,7 @@ COMMAND_HANDLER(handle_nand_probe_command) struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = nand_probe(p); @@ -161,7 +147,7 @@ COMMAND_HANDLER(handle_nand_erase_command) struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; unsigned long offset; @@ -208,7 +194,7 @@ COMMAND_HANDLER(handle_nand_check_bad_blocks_command) struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (CMD_ARGC == 3) { @@ -246,7 +232,7 @@ COMMAND_HANDLER(handle_nand_write_command) struct nand_fileio_state s; int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args, &s, &nand, FILEIO_READ, false, true); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; uint32_t total_bytes = s.size; @@ -261,7 +247,7 @@ COMMAND_HANDLER(handle_nand_write_command) retval = nand_write_page(nand, s.address / nand->page_size, s.page, s.page_size, s.oob, s.oob_size); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { command_print(CMD, "failed writing file %s " "to NAND flash %s at offset 0x%8.8" PRIx32, CMD_ARGV[1], CMD_ARGV[0], s.address); @@ -286,7 +272,7 @@ COMMAND_HANDLER(handle_nand_verify_command) struct nand_fileio_state file; int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args, &file, &nand, FILEIO_READ, false, true); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; struct nand_fileio_state dev; @@ -295,13 +281,13 @@ COMMAND_HANDLER(handle_nand_verify_command) dev.size = file.size; dev.oob_format = file.oob_format; retval = nand_fileio_start(CMD, nand, NULL, FILEIO_NONE, &dev); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; while (file.size > 0) { retval = nand_read_page(nand, dev.address / dev.page_size, dev.page, dev.page_size, dev.oob, dev.oob_size); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { command_print(CMD, "reading NAND flash page failed"); nand_fileio_cleanup(&dev); nand_fileio_cleanup(&file); @@ -346,23 +332,23 @@ COMMAND_HANDLER(handle_nand_dump_command) struct nand_fileio_state s; int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args, &s, &nand, FILEIO_WRITE, true, false); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; while (s.size > 0) { size_t size_written; retval = nand_read_page(nand, s.address / nand->page_size, s.page, s.page_size, s.oob, s.oob_size); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { command_print(CMD, "reading NAND flash page failed"); nand_fileio_cleanup(&s); return retval; } - if (NULL != s.page) + if (s.page) fileio_write(s.fileio, s.page_size, s.page, &size_written); - if (NULL != s.oob) + if (s.oob) fileio_write(s.fileio, s.oob_size, s.oob, &size_written); s.size -= nand->page_size; @@ -388,10 +374,10 @@ COMMAND_HANDLER(handle_nand_raw_access_command) struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; - if (NULL == p->device) { + if (!p->device) { command_print(CMD, "#%s: not probed", CMD_ARGV[0]); return ERROR_OK; } @@ -479,8 +465,8 @@ static int nand_init(struct command_context *cmd_ctx) { if (!nand_devices) return ERROR_OK; - struct command *parent = command_find_in_context(cmd_ctx, "nand"); - return register_commands(cmd_ctx, parent, nand_exec_command_handlers); + + return register_commands(cmd_ctx, "nand", nand_exec_command_handlers); } COMMAND_HANDLER(handle_nand_init_command) @@ -527,14 +513,13 @@ static COMMAND_HELPER(create_nand_device, const char *bank_name, return ERROR_COMMAND_ARGUMENT_INVALID; } - if (NULL != controller->commands) { - retval = register_commands(CMD_CTX, NULL, - controller->commands); - if (ERROR_OK != retval) + if (controller->commands) { + retval = register_commands(CMD_CTX, NULL, controller->commands); + if (retval != ERROR_OK) return retval; } c = malloc(sizeof(struct nand_device)); - if (c == NULL) { + if (!c) { LOG_ERROR("End of memory"); return ERROR_FAIL; } @@ -552,7 +537,7 @@ static COMMAND_HELPER(create_nand_device, const char *bank_name, c->next = NULL; retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("'%s' driver rejected nand flash. Usage: %s", controller->name, controller->usage); @@ -560,7 +545,7 @@ static COMMAND_HELPER(create_nand_device, const char *bank_name, return retval; } - if (controller->usage == NULL) + if (!controller->usage) LOG_DEBUG("'%s' driver usage field missing", controller->name); nand_device_add(c); @@ -580,7 +565,7 @@ COMMAND_HANDLER(handle_nand_device_command) const char *driver_name = CMD_ARGV[0]; struct nand_flash_controller *controller; controller = nand_driver_find_by_name(CMD_ARGV[0]); - if (NULL == controller) { + if (!controller) { LOG_ERROR("No valid NAND flash driver found (%s)", driver_name); return CALL_COMMAND_HANDLER(handle_nand_list_drivers); } diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index b95b003dff..afa11e7d40 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 \ @@ -26,6 +28,7 @@ NOR_DRIVERS = \ %D%/dsp5680xx_flash.c \ %D%/efm32.c \ %D%/em357.c \ + %D%/eneispif.c \ %D%/esirisc_flash.c \ %D%/faux.c \ %D%/fespi.c \ @@ -44,6 +47,7 @@ NOR_DRIVERS = \ %D%/mrvlqspi.c \ %D%/niietcm4.c \ %D%/non_cfi.c \ + %D%/npcx.c \ %D%/nrf5.c \ %D%/numicro.c \ %D%/ocl.c \ @@ -51,11 +55,16 @@ 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 \ %D%/spi.c \ %D%/stmsmi.c \ + %D%/stmqspi.c \ %D%/stellaris.c \ %D%/stm32f1x.c \ %D%/stm32f2x.c \ @@ -83,6 +92,8 @@ NORHEADERS = \ %D%/imp.h \ %D%/non_cfi.h \ %D%/ocl.h \ + %D%/sfdp.h \ %D%/spi.h \ %D%/stm32l4x.h \ + %D%/stmqspi.h \ %D%/msp432.h diff --git a/src/flash/nor/aduc702x.c b/src/flash/nor/aduc702x.c index b7d2299f7d..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 @@ -31,15 +20,15 @@ static int aduc702x_build_sector_list(struct flash_bank *bank); static int aduc702x_check_flash_completion(struct target *target, unsigned int timeout_ms); static int aduc702x_set_write_enable(struct target *target, int enable); -#define ADUC702x_FLASH 0xfffff800 -#define ADUC702x_FLASH_FEESTA (0*4) -#define ADUC702x_FLASH_FEEMOD (1*4) -#define ADUC702x_FLASH_FEECON (2*4) -#define ADUC702x_FLASH_FEEDAT (3*4) -#define ADUC702x_FLASH_FEEADR (4*4) -#define ADUC702x_FLASH_FEESIGN (5*4) -#define ADUC702x_FLASH_FEEPRO (6*4) -#define ADUC702x_FLASH_FEEHIDE (7*4) +#define ADUC702X_FLASH 0xfffff800 +#define ADUC702X_FLASH_FEESTA (0*4) +#define ADUC702X_FLASH_FEEMOD (1*4) +#define ADUC702X_FLASH_FEECON (2*4) +#define ADUC702X_FLASH_FEEDAT (3*4) +#define ADUC702X_FLASH_FEEADR (4*4) +#define ADUC702X_FLASH_FEESIGN (5*4) +#define ADUC702X_FLASH_FEEPRO (6*4) +#define ADUC702X_FLASH_FEEHIDE (7*4) /* flash bank aduc702x 0 0 0 0 <target#> * The ADC7019-28 devices all have the same flash layout */ @@ -87,9 +76,9 @@ static int aduc702x_erase(struct flash_bank *bank, unsigned int first, /* mass erase */ if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) { LOG_DEBUG("performing mass erase."); - target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, 0x3cff); - target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, 0xffc3); - target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x06); + target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEDAT, 0x3cff); + target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEADR, 0xffc3); + target_write_u8(target, ADUC702X_FLASH + ADUC702X_FLASH_FEECON, 0x06); if (aduc702x_check_flash_completion(target, 3500) != ERROR_OK) { LOG_ERROR("mass erase failed"); @@ -106,8 +95,8 @@ static int aduc702x_erase(struct flash_bank *bank, unsigned int first, for (x = 0; x < count; ++x) { adr = bank->base + ((first + x) * 512); - target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, adr); - target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x05); + target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEADR, adr); + target_write_u8(target, ADUC702X_FLASH + ADUC702X_FLASH_FEECON, 0x05); if (aduc702x_check_flash_completion(target, 50) != ERROR_OK) { LOG_ERROR("failed to erase sector at address 0x%08lX", adr); @@ -283,7 +272,7 @@ static int aduc702x_write_single(struct flash_bank *bank, for (x = 0; x < count; x += 2) { /* FEEADR = address */ - target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, offset + x); + target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEADR, offset + x); /* set up data */ if ((x + 1) == count) { @@ -292,10 +281,10 @@ static int aduc702x_write_single(struct flash_bank *bank, } else b = buffer[x + 1]; - target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, buffer[x] | (b << 8)); + target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEDAT, buffer[x] | (b << 8)); /* do single-write command */ - target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x02); + target_write_u8(target, ADUC702X_FLASH + ADUC702X_FLASH_FEECON, 0x02); if (aduc702x_check_flash_completion(target, 1) != ERROR_OK) { LOG_ERROR("single write failed for address 0x%08lX", @@ -345,7 +334,7 @@ static int aduc702x_probe(struct flash_bank *bank) static int aduc702x_set_write_enable(struct target *target, int enable) { /* don't bother to preserve int enable bit here */ - target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEMOD, enable ? 8 : 0); + target_write_u16(target, ADUC702X_FLASH + ADUC702X_FLASH_FEEMOD, enable ? 8 : 0); return ERROR_OK; } @@ -361,7 +350,7 @@ static int aduc702x_check_flash_completion(struct target *target, unsigned int t int64_t endtime = timeval_ms() + timeout_ms; while (1) { - target_read_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEESTA, &v); + target_read_u8(target, ADUC702X_FLASH + ADUC702X_FLASH_FEESTA, &v); if ((v & 4) == 0) break; alive_sleep(1); 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 1c4dce87dc..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" @@ -123,7 +98,7 @@ static struct { uint8_t class; uint8_t partno; const char *partname; -} ambiqmicroParts[6] = { +} ambiqmicro_parts[6] = { {0xFF, 0x00, "Unknown"}, {0x01, 0x00, "Apollo"}, {0x02, 0x00, "Apollo2"}, @@ -132,7 +107,7 @@ static struct { {0x05, 0x00, "Apollo"}, }; -static char *ambiqmicroClassname[6] = { +static char *ambiqmicro_classname[6] = { "Unknown", "Apollo", "Apollo2", "Unknown", "Unknown", "Apollo" }; @@ -161,10 +136,9 @@ FLASH_BANK_COMMAND_HANDLER(ambiqmicro_flash_bank_command) return ERROR_OK; } -static int get_ambiqmicro_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_ambiqmicro_info(struct flash_bank *bank, struct command_invocation *cmd) { struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv; - int printed; char *classname; if (!ambiqmicro_info->probed) { @@ -173,21 +147,17 @@ static int get_ambiqmicro_info(struct flash_bank *bank, char *buf, int buf_size) } /* Check class name in range. */ - if (ambiqmicro_info->target_class < sizeof(ambiqmicroClassname)) - classname = ambiqmicroClassname[ambiqmicro_info->target_class]; + if (ambiqmicro_info->target_class < sizeof(ambiqmicro_classname)) + classname = ambiqmicro_classname[ambiqmicro_info->target_class]; else - classname = ambiqmicroClassname[0]; + classname = ambiqmicro_classname[0]; - printed = snprintf(buf, - buf_size, - "\nAmbiq Micro information: Chip is " + command_print_sameline(cmd, "\nAmbiq Micro information: Chip is " "class %d (%s) %s\n", ambiqmicro_info->target_class, classname, ambiqmicro_info->target_name); - if ((printed < 0)) - return ERROR_BUF_TOO_SMALL; return ERROR_OK; } @@ -200,24 +170,24 @@ static int ambiqmicro_read_part_info(struct flash_bank *bank) { struct ambiqmicro_flash_bank *ambiqmicro_info = bank->driver_priv; struct target *target = bank->target; - uint32_t PartNum = 0; + uint32_t part_num = 0; int retval; /* * Read Part Number. */ - retval = target_read_u32(target, 0x40020000, &PartNum); + retval = target_read_u32(target, 0x40020000, &part_num); if (retval != ERROR_OK) { - LOG_ERROR("status(0x%x):Could not read PartNum.\n", retval); - /* Set PartNum to default device */ - PartNum = 0; + LOG_ERROR("status(0x%x):Could not read part_num.\n", retval); + /* Set part_num to default device */ + part_num = 0; } - LOG_DEBUG("Part number: 0x%" PRIx32, PartNum); + LOG_DEBUG("Part number: 0x%" PRIx32, part_num); /* * Determine device class. */ - ambiqmicro_info->target_class = (PartNum & 0xFF000000) >> 24; + ambiqmicro_info->target_class = (part_num & 0xFF000000) >> 24; switch (ambiqmicro_info->target_class) { case 1: /* 1 - Apollo */ @@ -225,9 +195,9 @@ static int ambiqmicro_read_part_info(struct flash_bank *bank) bank->base = bank->bank_number * 0x40000; ambiqmicro_info->pagesize = 2048; ambiqmicro_info->flshsiz = - apollo_flash_size[(PartNum & 0x00F00000) >> 20]; + apollo_flash_size[(part_num & 0x00F00000) >> 20]; ambiqmicro_info->sramsiz = - apollo_sram_size[(PartNum & 0x000F0000) >> 16]; + apollo_sram_size[(part_num & 0x000F0000) >> 16]; ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz / ambiqmicro_info->pagesize; if (ambiqmicro_info->num_pages > 128) { @@ -253,12 +223,12 @@ static int ambiqmicro_read_part_info(struct flash_bank *bank) } - if (ambiqmicro_info->target_class < ARRAY_SIZE(ambiqmicroParts)) + if (ambiqmicro_info->target_class < ARRAY_SIZE(ambiqmicro_parts)) ambiqmicro_info->target_name = - ambiqmicroParts[ambiqmicro_info->target_class].partname; + ambiqmicro_parts[ambiqmicro_info->target_class].partname; else ambiqmicro_info->target_name = - ambiqmicroParts[0].partname; + ambiqmicro_parts[0].partname; LOG_DEBUG("num_pages: %" PRIu32 ", pagesize: %" PRIu32 ", flash: %" PRIu32 ", sram: %" PRIu32, ambiqmicro_info->num_pages, @@ -779,16 +749,12 @@ COMMAND_HANDLER(ambiqmicro_handle_mass_erase_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; - if (ambiqmicro_mass_erase(bank) == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - + if (ambiqmicro_mass_erase(bank) == ERROR_OK) command_print(CMD, "ambiqmicro mass erase complete"); - } else + else command_print(CMD, "ambiqmicro mass erase failed"); return ERROR_OK; @@ -807,7 +773,7 @@ COMMAND_HANDLER(ambiqmicro_handle_page_erase_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last); retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (ambiqmicro_erase(bank, first, last) == ERROR_OK) diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c index c9baffc708..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" @@ -104,12 +62,10 @@ #define AT91C_EFC_FCMD_STUI (0xE) /* (EFC) Start Read Unique ID */ #define AT91C_EFC_FCMD_SPUI (0xF) /* (EFC) Stop Read Unique ID */ -#define offset_EFC_FMR 0 -#define offset_EFC_FCR 4 -#define offset_EFC_FSR 8 -#define offset_EFC_FRR 12 - -extern const struct flash_driver at91sam3_flash; +#define OFFSET_EFC_FMR 0 +#define OFFSET_EFC_FCR 4 +#define OFFSET_EFC_FSR 8 +#define OFFSET_EFC_FRR 12 static float _tomhz(uint32_t freq_hz) { @@ -191,13 +147,13 @@ struct sam3_bank_private { /* DANGER: THERE ARE DRAGONS HERE.. */ /* NOTE: If you add more 'ghost' pointers */ /* be aware that you must *manually* update */ - /* these pointers in the function sam3_GetDetails() */ + /* these pointers in the function sam3_get_details() */ /* See the comment "Here there be dragons" */ /* so we can find the chip we belong to */ - struct sam3_chip *pChip; + struct sam3_chip *chip; /* so we can find the original bank pointer */ - struct flash_bank *pBank; + struct flash_bank *bank; unsigned bank_number; uint32_t controller_address; uint32_t base_address; @@ -214,7 +170,7 @@ struct sam3_chip_details { /* note: If you add pointers here */ /* be careful about them as they */ /* may need to be updated inside */ - /* the function: "sam3_GetDetails() */ + /* the function: "sam3_get_details() */ /* which copy/overwrites the */ /* 'runtime' copy of this structure */ uint32_t chipid_cidr; @@ -244,7 +200,7 @@ struct sam3_chip { struct sam3_reg_list { uint32_t address; size_t struct_offset; const char *name; - void (*explain_func)(struct sam3_chip *pInfo); + void (*explain_func)(struct sam3_chip *chip); }; static struct sam3_chip *all_sam3_chips; @@ -256,7 +212,7 @@ static struct sam3_chip *get_current_sam3(struct command_invocation *cmd) t = get_current_target(cmd->ctx); if (!t) { - command_print(cmd, "No current target?"); + command_print_sameline(cmd, "No current target?\n"); return NULL; } @@ -264,7 +220,7 @@ static struct sam3_chip *get_current_sam3(struct command_invocation *cmd) if (!p) { /* this should not happen */ /* the command is not registered until the chip is created? */ - command_print(cmd, "No SAM3 chips exist?"); + command_print_sameline(cmd, "No SAM3 chips exist?\n"); return NULL; } @@ -273,11 +229,11 @@ static struct sam3_chip *get_current_sam3(struct command_invocation *cmd) return p; p = p->next; } - command_print(cmd, "Cannot find SAM3 chip?"); + command_print_sameline(cmd, "Cannot find SAM3 chip?\n"); return NULL; } -/* these are used to *initialize* the "pChip->details" structure. */ +/* these are used to *initialize* the "chip->details" structure. */ static const struct sam3_chip_details all_sam3_details[] = { /* Start at91sam3u* series */ { @@ -307,8 +263,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, @@ -323,8 +279,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_U, .controller_address = 0x400e0a00, @@ -358,8 +314,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, @@ -400,8 +356,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, @@ -449,8 +405,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { /* .bank[0] = { */ .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, @@ -464,8 +420,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_U, .controller_address = 0x400e0a00, @@ -499,8 +455,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, @@ -541,8 +497,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, @@ -579,8 +535,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -612,8 +568,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -644,8 +600,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -676,8 +632,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -708,8 +664,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -740,8 +696,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, @@ -755,8 +711,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_SD, .controller_address = 0x400e0a00, @@ -780,8 +736,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, @@ -795,8 +751,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_SD, .controller_address = 0x400e0a00, @@ -820,8 +776,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, @@ -835,8 +791,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_SD, .controller_address = 0x400e0a00, @@ -860,8 +816,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -892,8 +848,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -924,8 +880,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -956,8 +912,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -988,8 +944,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -1020,8 +976,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -1052,8 +1008,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -1102,8 +1058,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1151,8 +1107,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1200,8 +1156,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1249,8 +1205,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1298,8 +1254,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1347,8 +1303,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1396,8 +1352,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1445,8 +1401,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1494,8 +1450,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1528,8 +1484,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1562,8 +1518,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1596,8 +1552,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1630,8 +1586,8 @@ static const struct sam3_chip_details all_sam3_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, @@ -1681,8 +1637,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, @@ -1696,8 +1652,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, @@ -1722,8 +1678,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, @@ -1737,8 +1693,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_256K_AX, .controller_address = 0x400e0c00, @@ -1781,8 +1737,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, @@ -1796,8 +1752,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, @@ -1823,8 +1779,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, @@ -1838,8 +1794,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, @@ -1864,8 +1820,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, @@ -1879,8 +1835,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, @@ -1905,8 +1861,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, @@ -1920,8 +1876,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, @@ -1946,8 +1902,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, @@ -1961,8 +1917,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_256K_AX, .controller_address = 0x400e0c00, @@ -1987,8 +1943,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[0] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, @@ -2002,8 +1958,8 @@ static const struct sam3_chip_details all_sam3_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_256K_AX, .controller_address = 0x400e0c00, @@ -2036,14 +1992,14 @@ static const struct sam3_chip_details all_sam3_details[] = { /** * Get the current status of the EEFC and * the value of some status bits (LOCKE, PROGE). - * @param pPrivate - info about the bank + * @param private - info about the bank * @param v - result goes here */ -static int EFC_GetStatus(struct sam3_bank_private *pPrivate, uint32_t *v) +static int efc_get_status(struct sam3_bank_private *private, uint32_t *v) { int r; - r = target_read_u32(pPrivate->pChip->target, - pPrivate->controller_address + offset_EFC_FSR, + r = target_read_u32(private->chip->target, + private->controller_address + OFFSET_EFC_FSR, v); LOG_DEBUG("Status: 0x%08x (lockerror: %d, cmderror: %d, ready: %d)", (unsigned int)(*v), @@ -2056,15 +2012,15 @@ static int EFC_GetStatus(struct sam3_bank_private *pPrivate, uint32_t *v) /** * Get the result of the last executed command. - * @param pPrivate - info about the bank + * @param private - info about the bank * @param v - result goes here */ -static int EFC_GetResult(struct sam3_bank_private *pPrivate, uint32_t *v) +static int efc_get_result(struct sam3_bank_private *private, uint32_t *v) { int r; uint32_t rv; - r = target_read_u32(pPrivate->pChip->target, - pPrivate->controller_address + offset_EFC_FRR, + r = target_read_u32(private->chip->target, + private->controller_address + OFFSET_EFC_FRR, &rv); if (v) *v = rv; @@ -2072,7 +2028,7 @@ static int EFC_GetResult(struct sam3_bank_private *pPrivate, uint32_t *v) return r; } -static int EFC_StartCommand(struct sam3_bank_private *pPrivate, +static int efc_start_command(struct sam3_bank_private *private, unsigned command, unsigned argument) { uint32_t n, v; @@ -2093,16 +2049,16 @@ do_retry: /* case AT91C_EFC_FCMD_EPA: */ case AT91C_EFC_FCMD_SLB: case AT91C_EFC_FCMD_CLB: - n = (pPrivate->size_bytes / pPrivate->page_size); + n = (private->size_bytes / private->page_size); if (argument >= n) LOG_ERROR("*BUG*: Embedded flash has only %u pages", (unsigned)(n)); break; case AT91C_EFC_FCMD_SFB: case AT91C_EFC_FCMD_CFB: - if (argument >= pPrivate->pChip->details.n_gpnvms) { + if (argument >= private->chip->details.n_gpnvms) { LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", - pPrivate->pChip->details.n_gpnvms); + private->chip->details.n_gpnvms); } break; @@ -2127,7 +2083,7 @@ do_retry: /* Situation (2) - normal, finished reading unique id */ } else { /* it should be "ready" */ - EFC_GetStatus(pPrivate, &v); + efc_get_status(private, &v); if (v & 1) { /* then it is ready */ /* we go on */ @@ -2136,14 +2092,14 @@ do_retry: /* we have done this before */ /* the controller is not responding. */ LOG_ERROR("flash controller(%d) is not ready! Error", - pPrivate->bank_number); + private->bank_number); return ERROR_FAIL; } else { retry++; LOG_ERROR("Flash controller(%d) is not ready, attempting reset", - pPrivate->bank_number); + private->bank_number); /* we do that by issuing the *STOP* command */ - EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0); + efc_start_command(private, AT91C_EFC_FCMD_SPUI, 0); /* above is recursive, and further recursion is blocked by */ /* if (command == AT91C_EFC_FCMD_SPUI) above */ goto do_retry; @@ -2153,8 +2109,8 @@ do_retry: v = (0x5A << 24) | (argument << 8) | command; LOG_DEBUG("Command: 0x%08x", ((unsigned int)(v))); - r = target_write_u32(pPrivate->pBank->target, - pPrivate->controller_address + offset_EFC_FCR, v); + r = target_write_u32(private->bank->target, + private->controller_address + OFFSET_EFC_FCR, v); if (r != ERROR_OK) LOG_DEBUG("Error Write failed"); return r; @@ -2162,12 +2118,12 @@ do_retry: /** * Performs the given command and wait until its completion (or an error). - * @param pPrivate - info about the bank + * @param private - info about the bank * @param command - Command to perform. * @param argument - Optional command argument. * @param status - put command status bits here */ -static int EFC_PerformCommand(struct sam3_bank_private *pPrivate, +static int efc_perform_command(struct sam3_bank_private *private, unsigned command, unsigned argument, uint32_t *status) @@ -2181,14 +2137,14 @@ static int EFC_PerformCommand(struct sam3_bank_private *pPrivate, if (status) *status = 0; - r = EFC_StartCommand(pPrivate, command, argument); + r = efc_start_command(private, command, argument); if (r != ERROR_OK) return r; ms_end = 500 + timeval_ms(); do { - r = EFC_GetStatus(pPrivate, &v); + r = efc_get_status(private, &v); if (r != ERROR_OK) return r; ms_now = timeval_ms(); @@ -2208,87 +2164,87 @@ static int EFC_PerformCommand(struct sam3_bank_private *pPrivate, /** * Read the unique ID. - * @param pPrivate - info about the bank - * The unique ID is stored in the 'pPrivate' structure. + * @param private - info about the bank + * The unique ID is stored in the 'private' structure. */ -static int FLASHD_ReadUniqueID(struct sam3_bank_private *pPrivate) +static int flashd_read_uid(struct sam3_bank_private *private) { int r; uint32_t v; int x; /* assume 0 */ - pPrivate->pChip->cfg.unique_id[0] = 0; - pPrivate->pChip->cfg.unique_id[1] = 0; - pPrivate->pChip->cfg.unique_id[2] = 0; - pPrivate->pChip->cfg.unique_id[3] = 0; + private->chip->cfg.unique_id[0] = 0; + private->chip->cfg.unique_id[1] = 0; + private->chip->cfg.unique_id[2] = 0; + private->chip->cfg.unique_id[3] = 0; LOG_DEBUG("Begin"); - r = EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_STUI, 0); + r = efc_start_command(private, AT91C_EFC_FCMD_STUI, 0); if (r < 0) return r; for (x = 0; x < 4; x++) { - r = target_read_u32(pPrivate->pChip->target, - pPrivate->pBank->base + (x * 4), + r = target_read_u32(private->chip->target, + private->bank->base + (x * 4), &v); if (r < 0) return r; - pPrivate->pChip->cfg.unique_id[x] = v; + private->chip->cfg.unique_id[x] = v; } - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0, NULL); + r = efc_perform_command(private, AT91C_EFC_FCMD_SPUI, 0, NULL); LOG_DEBUG("End: R=%d, id = 0x%08x, 0x%08x, 0x%08x, 0x%08x", r, - (unsigned int)(pPrivate->pChip->cfg.unique_id[0]), - (unsigned int)(pPrivate->pChip->cfg.unique_id[1]), - (unsigned int)(pPrivate->pChip->cfg.unique_id[2]), - (unsigned int)(pPrivate->pChip->cfg.unique_id[3])); + (unsigned int)(private->chip->cfg.unique_id[0]), + (unsigned int)(private->chip->cfg.unique_id[1]), + (unsigned int)(private->chip->cfg.unique_id[2]), + (unsigned int)(private->chip->cfg.unique_id[3])); return r; } /** * Erases the entire flash. - * @param pPrivate - the info about the bank. + * @param private - the info about the bank. */ -static int FLASHD_EraseEntireBank(struct sam3_bank_private *pPrivate) +static int flashd_erase_entire_bank(struct sam3_bank_private *private) { LOG_DEBUG("Here"); - return EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_EA, 0, NULL); + return efc_perform_command(private, AT91C_EFC_FCMD_EA, 0, NULL); } /** * Gets current GPNVM state. - * @param pPrivate - info about the bank. + * @param private - info about the bank. * @param gpnvm - GPNVM bit index. * @param puthere - result stored here. */ /* ------------------------------------------------------------------------------ */ -static int FLASHD_GetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm, unsigned *puthere) +static int flashd_get_gpnvm(struct sam3_bank_private *private, unsigned gpnvm, unsigned *puthere) { uint32_t v; int r; LOG_DEBUG("Here"); - if (pPrivate->bank_number != 0) { + if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } - if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { + if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", - gpnvm, pPrivate->pChip->details.n_gpnvms); + gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } /* Get GPNVMs status */ - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GFB, 0, NULL); + r = efc_perform_command(private, AT91C_EFC_FCMD_GFB, 0, NULL); if (r != ERROR_OK) { LOG_ERROR("Failed"); return r; } - r = EFC_GetResult(pPrivate, &v); + r = efc_get_result(private, &v); if (puthere) { /* Check if GPNVM is set */ @@ -2301,59 +2257,59 @@ static int FLASHD_GetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm, u /** * Clears the selected GPNVM bit. - * @param pPrivate info about the bank + * @param private info about the bank * @param gpnvm GPNVM index. * @returns 0 if successful; otherwise returns an error code. */ -static int FLASHD_ClrGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm) +static int flashd_clr_gpnvm(struct sam3_bank_private *private, unsigned gpnvm) { int r; unsigned v; LOG_DEBUG("Here"); - if (pPrivate->bank_number != 0) { + if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } - if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { + if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", - gpnvm, pPrivate->pChip->details.n_gpnvms); + gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } - r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v); + r = flashd_get_gpnvm(private, gpnvm, &v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CFB, gpnvm, NULL); + r = efc_perform_command(private, AT91C_EFC_FCMD_CFB, gpnvm, NULL); LOG_DEBUG("End: %d", r); return r; } /** * Sets the selected GPNVM bit. - * @param pPrivate info about the bank + * @param private info about the bank * @param gpnvm GPNVM index. */ -static int FLASHD_SetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm) +static int flashd_set_gpnvm(struct sam3_bank_private *private, unsigned gpnvm) { int r; unsigned v; - if (pPrivate->bank_number != 0) { + if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } - if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { + if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", - gpnvm, pPrivate->pChip->details.n_gpnvms); + gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } - r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v); + r = flashd_get_gpnvm(private, gpnvm, &v); if (r != ERROR_OK) return r; if (v) { @@ -2361,35 +2317,35 @@ static int FLASHD_SetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm) r = ERROR_OK; } else { /* set it */ - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SFB, gpnvm, NULL); + r = efc_perform_command(private, AT91C_EFC_FCMD_SFB, gpnvm, NULL); } return r; } /** * Returns a bit field (at most 64) of locked regions within a page. - * @param pPrivate info about the bank + * @param private info about the bank * @param v where to store locked bits */ -static int FLASHD_GetLockBits(struct sam3_bank_private *pPrivate, uint32_t *v) +static int flashd_get_lock_bits(struct sam3_bank_private *private, uint32_t *v) { int r; LOG_DEBUG("Here"); - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GLB, 0, NULL); + r = efc_perform_command(private, AT91C_EFC_FCMD_GLB, 0, NULL); if (r == ERROR_OK) - r = EFC_GetResult(pPrivate, v); + r = efc_get_result(private, v); LOG_DEBUG("End: %d", r); return r; } /** * Unlocks all the regions in the given address range. - * @param pPrivate info about the bank + * @param private info about the bank * @param start_sector first sector to unlock * @param end_sector last (inclusive) to unlock */ -static int FLASHD_Unlock(struct sam3_bank_private *pPrivate, +static int flashd_unlock(struct sam3_bank_private *private, unsigned start_sector, unsigned end_sector) { @@ -2398,13 +2354,13 @@ static int FLASHD_Unlock(struct sam3_bank_private *pPrivate, uint32_t pg; uint32_t pages_per_sector; - pages_per_sector = pPrivate->sector_size / pPrivate->page_size; + pages_per_sector = private->sector_size / private->page_size; /* Unlock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CLB, pg, &status); + r = efc_perform_command(private, AT91C_EFC_FCMD_CLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; @@ -2415,11 +2371,11 @@ static int FLASHD_Unlock(struct sam3_bank_private *pPrivate, /** * Locks regions - * @param pPrivate - info about the bank + * @param private - info about the bank * @param start_sector - first sector to lock * @param end_sector - last sector (inclusive) to lock */ -static int FLASHD_Lock(struct sam3_bank_private *pPrivate, +static int flashd_lock(struct sam3_bank_private *private, unsigned start_sector, unsigned end_sector) { @@ -2428,13 +2384,13 @@ static int FLASHD_Lock(struct sam3_bank_private *pPrivate, uint32_t pages_per_sector; int r; - pages_per_sector = pPrivate->sector_size / pPrivate->page_size; + pages_per_sector = private->sector_size / private->page_size; /* Lock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SLB, pg, &status); + r = efc_perform_command(private, AT91C_EFC_FCMD_SLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; @@ -2446,7 +2402,7 @@ static int FLASHD_Lock(struct sam3_bank_private *pPrivate, /* begin helpful debug code */ /* print the fieldname, the field value, in dec & hex, and return field value */ -static uint32_t sam3_reg_fieldname(struct sam3_chip *pChip, +static uint32_t sam3_reg_fieldname(struct sam3_chip *chip, const char *regname, uint32_t value, unsigned shift, @@ -2598,72 +2554,72 @@ static const char *const _rc_freq[] = { "4 MHz", "8 MHz", "12 MHz", "reserved" }; -static void sam3_explain_ckgr_mor(struct sam3_chip *pChip) +static void sam3_explain_ckgr_mor(struct sam3_chip *chip) { uint32_t v; uint32_t rcen; - v = sam3_reg_fieldname(pChip, "MOSCXTEN", pChip->cfg.CKGR_MOR, 0, 1); + v = sam3_reg_fieldname(chip, "MOSCXTEN", chip->cfg.CKGR_MOR, 0, 1); LOG_USER("(main xtal enabled: %s)", _yes_or_no(v)); - v = sam3_reg_fieldname(pChip, "MOSCXTBY", pChip->cfg.CKGR_MOR, 1, 1); + v = sam3_reg_fieldname(chip, "MOSCXTBY", chip->cfg.CKGR_MOR, 1, 1); LOG_USER("(main osc bypass: %s)", _yes_or_no(v)); - rcen = sam3_reg_fieldname(pChip, "MOSCRCEN", pChip->cfg.CKGR_MOR, 3, 1); + rcen = sam3_reg_fieldname(chip, "MOSCRCEN", chip->cfg.CKGR_MOR, 3, 1); LOG_USER("(onchip RC-OSC enabled: %s)", _yes_or_no(rcen)); - v = sam3_reg_fieldname(pChip, "MOSCRCF", pChip->cfg.CKGR_MOR, 4, 3); + v = sam3_reg_fieldname(chip, "MOSCRCF", chip->cfg.CKGR_MOR, 4, 3); LOG_USER("(onchip RC-OSC freq: %s)", _rc_freq[v]); - pChip->cfg.rc_freq = 0; + chip->cfg.rc_freq = 0; if (rcen) { switch (v) { default: - pChip->cfg.rc_freq = 0; + chip->cfg.rc_freq = 0; break; case 0: - pChip->cfg.rc_freq = 4 * 1000 * 1000; + chip->cfg.rc_freq = 4 * 1000 * 1000; break; case 1: - pChip->cfg.rc_freq = 8 * 1000 * 1000; + chip->cfg.rc_freq = 8 * 1000 * 1000; break; case 2: - pChip->cfg.rc_freq = 12 * 1000 * 1000; + chip->cfg.rc_freq = 12 * 1000 * 1000; break; } } - v = sam3_reg_fieldname(pChip, "MOSCXTST", pChip->cfg.CKGR_MOR, 8, 8); + v = sam3_reg_fieldname(chip, "MOSCXTST", chip->cfg.CKGR_MOR, 8, 8); LOG_USER("(startup clks, time= %f uSecs)", - ((float)(v * 1000000)) / ((float)(pChip->cfg.slow_freq))); - v = sam3_reg_fieldname(pChip, "MOSCSEL", pChip->cfg.CKGR_MOR, 24, 1); + ((float)(v * 1000000)) / ((float)(chip->cfg.slow_freq))); + v = sam3_reg_fieldname(chip, "MOSCSEL", chip->cfg.CKGR_MOR, 24, 1); LOG_USER("(mainosc source: %s)", v ? "external xtal" : "internal RC"); - v = sam3_reg_fieldname(pChip, "CFDEN", pChip->cfg.CKGR_MOR, 25, 1); + v = sam3_reg_fieldname(chip, "CFDEN", chip->cfg.CKGR_MOR, 25, 1); LOG_USER("(clock failure enabled: %s)", _yes_or_no(v)); } -static void sam3_explain_chipid_cidr(struct sam3_chip *pChip) +static void sam3_explain_chipid_cidr(struct sam3_chip *chip) { int x; uint32_t v; const char *cp; - sam3_reg_fieldname(pChip, "Version", pChip->cfg.CHIPID_CIDR, 0, 5); + sam3_reg_fieldname(chip, "Version", chip->cfg.CHIPID_CIDR, 0, 5); LOG_USER_N("\n"); - v = sam3_reg_fieldname(pChip, "EPROC", pChip->cfg.CHIPID_CIDR, 5, 3); + v = sam3_reg_fieldname(chip, "EPROC", chip->cfg.CHIPID_CIDR, 5, 3); LOG_USER("%s", eproc_names[v]); - v = sam3_reg_fieldname(pChip, "NVPSIZE", pChip->cfg.CHIPID_CIDR, 8, 4); + v = sam3_reg_fieldname(chip, "NVPSIZE", chip->cfg.CHIPID_CIDR, 8, 4); LOG_USER("%s", nvpsize[v]); - v = sam3_reg_fieldname(pChip, "NVPSIZE2", pChip->cfg.CHIPID_CIDR, 12, 4); + v = sam3_reg_fieldname(chip, "NVPSIZE2", chip->cfg.CHIPID_CIDR, 12, 4); LOG_USER("%s", nvpsize2[v]); - v = sam3_reg_fieldname(pChip, "SRAMSIZE", pChip->cfg.CHIPID_CIDR, 16, 4); + v = sam3_reg_fieldname(chip, "SRAMSIZE", chip->cfg.CHIPID_CIDR, 16, 4); LOG_USER("%s", sramsize[v]); - v = sam3_reg_fieldname(pChip, "ARCH", pChip->cfg.CHIPID_CIDR, 20, 8); + v = sam3_reg_fieldname(chip, "ARCH", chip->cfg.CHIPID_CIDR, 20, 8); cp = _unknown; for (x = 0; archnames[x].name; x++) { if (v == archnames[x].value) { @@ -2674,73 +2630,73 @@ static void sam3_explain_chipid_cidr(struct sam3_chip *pChip) LOG_USER("%s", cp); - v = sam3_reg_fieldname(pChip, "NVPTYP", pChip->cfg.CHIPID_CIDR, 28, 3); + v = sam3_reg_fieldname(chip, "NVPTYP", chip->cfg.CHIPID_CIDR, 28, 3); LOG_USER("%s", nvptype[v]); - v = sam3_reg_fieldname(pChip, "EXTID", pChip->cfg.CHIPID_CIDR, 31, 1); + v = sam3_reg_fieldname(chip, "EXTID", chip->cfg.CHIPID_CIDR, 31, 1); LOG_USER("(exists: %s)", _yes_or_no(v)); } -static void sam3_explain_ckgr_mcfr(struct sam3_chip *pChip) +static void sam3_explain_ckgr_mcfr(struct sam3_chip *chip) { uint32_t v; - v = sam3_reg_fieldname(pChip, "MAINFRDY", pChip->cfg.CKGR_MCFR, 16, 1); + v = sam3_reg_fieldname(chip, "MAINFRDY", chip->cfg.CKGR_MCFR, 16, 1); LOG_USER("(main ready: %s)", _yes_or_no(v)); - v = sam3_reg_fieldname(pChip, "MAINF", pChip->cfg.CKGR_MCFR, 0, 16); + v = sam3_reg_fieldname(chip, "MAINF", chip->cfg.CKGR_MCFR, 0, 16); - v = (v * pChip->cfg.slow_freq) / 16; - pChip->cfg.mainosc_freq = v; + v = (v * chip->cfg.slow_freq) / 16; + chip->cfg.mainosc_freq = v; LOG_USER("(%3.03f Mhz (%" PRIu32 ".%03" PRIu32 "khz slowclk)", _tomhz(v), - (uint32_t)(pChip->cfg.slow_freq / 1000), - (uint32_t)(pChip->cfg.slow_freq % 1000)); + (uint32_t)(chip->cfg.slow_freq / 1000), + (uint32_t)(chip->cfg.slow_freq % 1000)); } -static void sam3_explain_ckgr_plla(struct sam3_chip *pChip) +static void sam3_explain_ckgr_plla(struct sam3_chip *chip) { uint32_t mula, diva; - diva = sam3_reg_fieldname(pChip, "DIVA", pChip->cfg.CKGR_PLLAR, 0, 8); + diva = sam3_reg_fieldname(chip, "DIVA", chip->cfg.CKGR_PLLAR, 0, 8); LOG_USER_N("\n"); - mula = sam3_reg_fieldname(pChip, "MULA", pChip->cfg.CKGR_PLLAR, 16, 11); + mula = sam3_reg_fieldname(chip, "MULA", chip->cfg.CKGR_PLLAR, 16, 11); LOG_USER_N("\n"); - pChip->cfg.plla_freq = 0; + chip->cfg.plla_freq = 0; if (mula == 0) LOG_USER("\tPLLA Freq: (Disabled,mula = 0)"); else if (diva == 0) LOG_USER("\tPLLA Freq: (Disabled,diva = 0)"); else if (diva >= 1) { - pChip->cfg.plla_freq = (pChip->cfg.mainosc_freq * (mula + 1) / diva); + chip->cfg.plla_freq = (chip->cfg.mainosc_freq * (mula + 1) / diva); LOG_USER("\tPLLA Freq: %3.03f MHz", - _tomhz(pChip->cfg.plla_freq)); + _tomhz(chip->cfg.plla_freq)); } } -static void sam3_explain_mckr(struct sam3_chip *pChip) +static void sam3_explain_mckr(struct sam3_chip *chip) { uint32_t css, pres, fin = 0; int pdiv = 0; const char *cp = NULL; - css = sam3_reg_fieldname(pChip, "CSS", pChip->cfg.PMC_MCKR, 0, 2); + css = sam3_reg_fieldname(chip, "CSS", chip->cfg.PMC_MCKR, 0, 2); switch (css & 3) { case 0: - fin = pChip->cfg.slow_freq; + fin = chip->cfg.slow_freq; cp = "slowclk"; break; case 1: - fin = pChip->cfg.mainosc_freq; + fin = chip->cfg.mainosc_freq; cp = "mainosc"; break; case 2: - fin = pChip->cfg.plla_freq; + fin = chip->cfg.plla_freq; cp = "plla"; break; case 3: - if (pChip->cfg.CKGR_UCKR & (1 << 16)) { + if (chip->cfg.CKGR_UCKR & (1 << 16)) { fin = 480 * 1000 * 1000; cp = "upll"; } else { @@ -2756,7 +2712,7 @@ static void sam3_explain_mckr(struct sam3_chip *pChip) LOG_USER("%s (%3.03f Mhz)", cp, _tomhz(fin)); - pres = sam3_reg_fieldname(pChip, "PRES", pChip->cfg.PMC_MCKR, 4, 3); + pres = sam3_reg_fieldname(chip, "PRES", chip->cfg.PMC_MCKR, 4, 3); switch (pres & 0x07) { case 0: pdiv = 1; @@ -2798,33 +2754,33 @@ static void sam3_explain_mckr(struct sam3_chip *pChip) fin = fin / pdiv; /* sam3 has a *SINGLE* clock - */ /* other at91 series parts have divisors for these. */ - pChip->cfg.cpu_freq = fin; - pChip->cfg.mclk_freq = fin; - pChip->cfg.fclk_freq = fin; + chip->cfg.cpu_freq = fin; + chip->cfg.mclk_freq = fin; + chip->cfg.fclk_freq = fin; LOG_USER("\t\tResult CPU Freq: %3.03f", _tomhz(fin)); } #if 0 -static struct sam3_chip *target2sam3(struct target *pTarget) +static struct sam3_chip *target2sam3(struct target *target) { - struct sam3_chip *pChip; + struct sam3_chip *chip; - if (pTarget == NULL) + if (!target) return NULL; - pChip = all_sam3_chips; - while (pChip) { - if (pChip->target == pTarget) + chip = all_sam3_chips; + while (chip) { + if (chip->target == target) break; /* return below */ else - pChip = pChip->next; + chip = chip->next; } - return pChip; + return chip; } #endif -static uint32_t *sam3_get_reg_ptr(struct sam3_cfg *pCfg, const struct sam3_reg_list *pList) +static uint32_t *sam3_get_reg_ptr(struct sam3_cfg *cfg, const struct sam3_reg_list *list) { /* this function exists to help */ /* keep funky offsetof() errors */ @@ -2833,7 +2789,7 @@ static uint32_t *sam3_get_reg_ptr(struct sam3_cfg *pCfg, const struct sam3_reg_l /* By using prototypes - we can detect what would */ /* be casting errors. */ - return (uint32_t *)(void *)(((char *)(pCfg)) + pList->struct_offset); + return (uint32_t *)(void *)(((char *)(cfg)) + list->struct_offset); } @@ -2873,65 +2829,65 @@ static struct sam3_bank_private *get_sam3_bank_private(struct flash_bank *bank) * Given a pointer to where it goes in the structure, * determine the register name, address from the all registers table. */ -static const struct sam3_reg_list *sam3_GetReg(struct sam3_chip *pChip, uint32_t *goes_here) +static const struct sam3_reg_list *sam3_get_reg(struct sam3_chip *chip, uint32_t *goes_here) { - const struct sam3_reg_list *pReg; + const struct sam3_reg_list *reg; - pReg = &(sam3_all_regs[0]); - while (pReg->name) { - uint32_t *pPossible; + reg = &(sam3_all_regs[0]); + while (reg->name) { + uint32_t *possible; /* calculate where this one go.. */ /* it is "possibly" this register. */ - pPossible = ((uint32_t *)(void *)(((char *)(&(pChip->cfg))) + pReg->struct_offset)); + possible = ((uint32_t *)(void *)(((char *)(&(chip->cfg))) + reg->struct_offset)); /* well? Is it this register */ - if (pPossible == goes_here) { + if (possible == goes_here) { /* Jump for joy! */ - return pReg; + return reg; } /* next... */ - pReg++; + reg++; } /* This is *TOTAL*PANIC* - we are totally screwed. */ LOG_ERROR("INVALID SAM3 REGISTER"); return NULL; } -static int sam3_ReadThisReg(struct sam3_chip *pChip, uint32_t *goes_here) +static int sam3_read_this_reg(struct sam3_chip *chip, uint32_t *goes_here) { - const struct sam3_reg_list *pReg; + const struct sam3_reg_list *reg; int r; - pReg = sam3_GetReg(pChip, goes_here); - if (!pReg) + reg = sam3_get_reg(chip, goes_here); + if (!reg) return ERROR_FAIL; - r = target_read_u32(pChip->target, pReg->address, goes_here); + r = target_read_u32(chip->target, reg->address, goes_here); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Err: %d", - pReg->name, (unsigned)(pReg->address), r); + reg->name, (unsigned)(reg->address), r); } return r; } -static int sam3_ReadAllRegs(struct sam3_chip *pChip) +static int sam3_read_all_regs(struct sam3_chip *chip) { int r; - const struct sam3_reg_list *pReg; + const struct sam3_reg_list *reg; - pReg = &(sam3_all_regs[0]); - while (pReg->name) { - r = sam3_ReadThisReg(pChip, - sam3_get_reg_ptr(&(pChip->cfg), pReg)); + reg = &(sam3_all_regs[0]); + while (reg->name) { + r = sam3_read_this_reg(chip, + sam3_get_reg_ptr(&(chip->cfg), reg)); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Error: %d", - pReg->name, ((unsigned)(pReg->address)), r); + reg->name, ((unsigned)(reg->address)), r); return r; } - pReg++; + reg++; } /* Chip identification register @@ -2948,45 +2904,45 @@ static int sam3_ReadAllRegs(struct sam3_chip *pChip) * located in the memory map of the Power Management Controller * (PMC). Furthermore, the address is not used by the PMC. * So when read, the memory controller returns zero.*/ - if (pChip->cfg.CHIPID_CIDR == 0) { - /*Put the correct CIDR and EXID values in the pChip structure */ - pChip->cfg.CHIPID_CIDR = pChip->cfg.CHIPID_CIDR2; - pChip->cfg.CHIPID_EXID = pChip->cfg.CHIPID_EXID2; + if (chip->cfg.CHIPID_CIDR == 0) { + /*Put the correct CIDR and EXID values in the chip structure */ + chip->cfg.CHIPID_CIDR = chip->cfg.CHIPID_CIDR2; + chip->cfg.CHIPID_EXID = chip->cfg.CHIPID_EXID2; } return ERROR_OK; } -static int sam3_GetInfo(struct sam3_chip *pChip) +static int sam3_get_info(struct sam3_chip *chip) { - const struct sam3_reg_list *pReg; + const struct sam3_reg_list *reg; uint32_t regval; - pReg = &(sam3_all_regs[0]); - while (pReg->name) { + reg = &(sam3_all_regs[0]); + while (reg->name) { /* display all regs */ - LOG_DEBUG("Start: %s", pReg->name); - regval = *sam3_get_reg_ptr(&(pChip->cfg), pReg); + LOG_DEBUG("Start: %s", reg->name); + regval = *sam3_get_reg_ptr(&(chip->cfg), reg); LOG_USER("%*s: [0x%08" PRIx32 "] -> 0x%08" PRIx32, REG_NAME_WIDTH, - pReg->name, - pReg->address, + reg->name, + reg->address, regval); - if (pReg->explain_func) - (*(pReg->explain_func))(pChip); - LOG_DEBUG("End: %s", pReg->name); - pReg++; + if (reg->explain_func) + (*(reg->explain_func))(chip); + LOG_DEBUG("End: %s", reg->name); + reg++; } - LOG_USER(" rc-osc: %3.03f MHz", _tomhz(pChip->cfg.rc_freq)); - LOG_USER(" mainosc: %3.03f MHz", _tomhz(pChip->cfg.mainosc_freq)); - LOG_USER(" plla: %3.03f MHz", _tomhz(pChip->cfg.plla_freq)); - LOG_USER(" cpu-freq: %3.03f MHz", _tomhz(pChip->cfg.cpu_freq)); - LOG_USER("mclk-freq: %3.03f MHz", _tomhz(pChip->cfg.mclk_freq)); + LOG_USER(" rc-osc: %3.03f MHz", _tomhz(chip->cfg.rc_freq)); + LOG_USER(" mainosc: %3.03f MHz", _tomhz(chip->cfg.mainosc_freq)); + LOG_USER(" plla: %3.03f MHz", _tomhz(chip->cfg.plla_freq)); + LOG_USER(" cpu-freq: %3.03f MHz", _tomhz(chip->cfg.cpu_freq)); + LOG_USER("mclk-freq: %3.03f MHz", _tomhz(chip->cfg.mclk_freq)); LOG_USER(" UniqueId: 0x%08" PRIx32 " 0x%08" PRIx32 " 0x%08" PRIx32 " 0x%08" PRIx32, - pChip->cfg.unique_id[0], - pChip->cfg.unique_id[1], - pChip->cfg.unique_id[2], - pChip->cfg.unique_id[3]); + chip->cfg.unique_id[0], + chip->cfg.unique_id[1], + chip->cfg.unique_id[2], + chip->cfg.unique_id[3]); return ERROR_OK; } @@ -2996,7 +2952,7 @@ static int sam3_protect_check(struct flash_bank *bank) int r; uint32_t v = 0; unsigned x; - struct sam3_bank_private *pPrivate; + struct sam3_bank_private *private; LOG_DEBUG("Begin"); if (bank->target->state != TARGET_HALTED) { @@ -3004,21 +2960,21 @@ static int sam3_protect_check(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } - pPrivate = get_sam3_bank_private(bank); - if (!pPrivate) { + private = get_sam3_bank_private(bank); + if (!private) { LOG_ERROR("no private for this bank?"); return ERROR_FAIL; } - if (!(pPrivate->probed)) + if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; - r = FLASHD_GetLockBits(pPrivate, &v); + r = flashd_get_lock_bits(private, &v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } - for (x = 0; x < pPrivate->nsectors; x++) + for (x = 0; x < private->nsectors; x++) bank->sectors[x].is_protected = (!!(v & (1 << x))); LOG_DEBUG("Done"); return ERROR_OK; @@ -3026,32 +2982,32 @@ static int sam3_protect_check(struct flash_bank *bank) FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command) { - struct sam3_chip *pChip; + struct sam3_chip *chip; - pChip = all_sam3_chips; + chip = all_sam3_chips; /* is this an existing chip? */ - while (pChip) { - if (pChip->target == bank->target) + while (chip) { + if (chip->target == bank->target) break; - pChip = pChip->next; + chip = chip->next; } - if (!pChip) { + if (!chip) { /* this is a *NEW* chip */ - pChip = calloc(1, sizeof(struct sam3_chip)); - if (!pChip) { + chip = calloc(1, sizeof(struct sam3_chip)); + if (!chip) { LOG_ERROR("NO RAM!"); return ERROR_FAIL; } - pChip->target = bank->target; + chip->target = bank->target; /* insert at head */ - pChip->next = all_sam3_chips; - all_sam3_chips = pChip; - pChip->target = bank->target; + chip->next = all_sam3_chips; + all_sam3_chips = chip; + chip->target = bank->target; /* assumption is this runs at 32khz */ - pChip->cfg.slow_freq = 32768; - pChip->probed = false; + chip->cfg.slow_freq = 32768; + chip->probed = false; } switch (bank->base) { @@ -3073,20 +3029,20 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command) /* at91sam3u and at91sam3ax series has the same address for bank 0*/ case FLASH_BANK_BASE_S: case FLASH_BANK0_BASE_U: - bank->driver_priv = &(pChip->details.bank[0]); + bank->driver_priv = &(chip->details.bank[0]); bank->bank_number = 0; - pChip->details.bank[0].pChip = pChip; - pChip->details.bank[0].pBank = bank; + chip->details.bank[0].chip = chip; + chip->details.bank[0].bank = bank; break; /* Bank 1 of at91sam3u or at91sam3ax series */ case FLASH_BANK1_BASE_U: case FLASH_BANK1_BASE_256K_AX: case FLASH_BANK1_BASE_512K_AX: - bank->driver_priv = &(pChip->details.bank[1]); + bank->driver_priv = &(chip->details.bank[1]); bank->bank_number = 1; - pChip->details.bank[1].pChip = pChip; - pChip->details.bank[1].pBank = bank; + chip->details.bank[1].chip = chip; + chip->details.bank[1].bank = bank; break; } @@ -3099,7 +3055,7 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command) * is owned by this bank. This simplification works only for one shot * deallocation like current flash_free_all_banks() */ -void sam3_free_driver_priv(struct flash_bank *bank) +static void sam3_free_driver_priv(struct flash_bank *bank) { struct sam3_chip *chip = all_sam3_chips; while (chip) { @@ -3110,57 +3066,57 @@ void sam3_free_driver_priv(struct flash_bank *bank) all_sam3_chips = NULL; } -static int sam3_GetDetails(struct sam3_bank_private *pPrivate) +static int sam3_get_details(struct sam3_bank_private *private) { - const struct sam3_chip_details *pDetails; - struct sam3_chip *pChip; + const struct sam3_chip_details *details; + struct sam3_chip *chip; struct flash_bank *saved_banks[SAM3_MAX_FLASH_BANKS]; unsigned x; LOG_DEBUG("Begin"); - pDetails = all_sam3_details; - while (pDetails->name) { + details = all_sam3_details; + while (details->name) { /* Compare cidr without version bits */ - if (((pDetails->chipid_cidr ^ pPrivate->pChip->cfg.CHIPID_CIDR) & 0xFFFFFFE0) == 0) + if (((details->chipid_cidr ^ private->chip->cfg.CHIPID_CIDR) & 0xFFFFFFE0) == 0) break; else - pDetails++; + details++; } - if (pDetails->name == NULL) { + if (!details->name) { LOG_ERROR("SAM3 ChipID 0x%08x not found in table (perhaps you can ID this chip?)", - (unsigned int)(pPrivate->pChip->cfg.CHIPID_CIDR)); + (unsigned int)(private->chip->cfg.CHIPID_CIDR)); /* Help the victim, print details about the chip */ LOG_INFO("SAM3 CHIPID_CIDR: 0x%08" PRIx32 " decodes as follows", - pPrivate->pChip->cfg.CHIPID_CIDR); - sam3_explain_chipid_cidr(pPrivate->pChip); + private->chip->cfg.CHIPID_CIDR); + sam3_explain_chipid_cidr(private->chip); return ERROR_FAIL; } /* DANGER: THERE ARE DRAGONS HERE */ - /* get our pChip - it is going */ + /* get our chip - it is going */ /* to be over-written shortly */ - pChip = pPrivate->pChip; + chip = private->chip; /* Note that, in reality: */ /* */ - /* pPrivate = &(pChip->details.bank[0]) */ - /* or pPrivate = &(pChip->details.bank[1]) */ + /* private = &(chip->details.bank[0]) */ + /* or private = &(chip->details.bank[1]) */ /* */ /* save the "bank" pointers */ for (x = 0; x < SAM3_MAX_FLASH_BANKS; x++) - saved_banks[x] = pChip->details.bank[x].pBank; + saved_banks[x] = chip->details.bank[x].bank; /* Overwrite the "details" structure. */ - memcpy(&(pPrivate->pChip->details), - pDetails, - sizeof(pPrivate->pChip->details)); + memcpy(&(private->chip->details), + details, + sizeof(private->chip->details)); /* now fix the ghosted pointers */ for (x = 0; x < SAM3_MAX_FLASH_BANKS; x++) { - pChip->details.bank[x].pChip = pChip; - pChip->details.bank[x].pBank = saved_banks[x]; + chip->details.bank[x].chip = chip; + chip->details.bank[x].bank = saved_banks[x]; } /* update the *BANK*SIZE* */ @@ -3172,7 +3128,7 @@ static int sam3_GetDetails(struct sam3_bank_private *pPrivate) static int _sam3_probe(struct flash_bank *bank, int noise) { int r; - struct sam3_bank_private *pPrivate; + struct sam3_bank_private *private; LOG_DEBUG("Begin: Bank: %u, Noise: %d", bank->bank_number, noise); @@ -3181,61 +3137,61 @@ static int _sam3_probe(struct flash_bank *bank, int noise) return ERROR_TARGET_NOT_HALTED; } - pPrivate = get_sam3_bank_private(bank); - if (!pPrivate) { + private = get_sam3_bank_private(bank); + if (!private) { LOG_ERROR("Invalid/unknown bank number"); return ERROR_FAIL; } - r = sam3_ReadAllRegs(pPrivate->pChip); + r = sam3_read_all_regs(private->chip); if (r != ERROR_OK) return r; LOG_DEBUG("Here"); - if (pPrivate->pChip->probed) - r = sam3_GetInfo(pPrivate->pChip); + if (private->chip->probed) + r = sam3_get_info(private->chip); else - r = sam3_GetDetails(pPrivate); + r = sam3_get_details(private); if (r != ERROR_OK) return r; /* update the flash bank size */ for (unsigned int x = 0; x < SAM3_MAX_FLASH_BANKS; x++) { - if (bank->base == pPrivate->pChip->details.bank[x].base_address) { - bank->size = pPrivate->pChip->details.bank[x].size_bytes; + if (bank->base == private->chip->details.bank[x].base_address) { + bank->size = private->chip->details.bank[x].size_bytes; break; } } - if (bank->sectors == NULL) { - bank->sectors = calloc(pPrivate->nsectors, (sizeof((bank->sectors)[0]))); - if (bank->sectors == NULL) { + if (!bank->sectors) { + bank->sectors = calloc(private->nsectors, (sizeof((bank->sectors)[0]))); + if (!bank->sectors) { LOG_ERROR("No memory!"); return ERROR_FAIL; } - bank->num_sectors = pPrivate->nsectors; + bank->num_sectors = private->nsectors; for (unsigned int x = 0; x < bank->num_sectors; x++) { - bank->sectors[x].size = pPrivate->sector_size; - bank->sectors[x].offset = x * (pPrivate->sector_size); + bank->sectors[x].size = private->sector_size; + bank->sectors[x].offset = x * (private->sector_size); /* mark as unknown */ bank->sectors[x].is_erased = -1; bank->sectors[x].is_protected = -1; } } - pPrivate->probed = true; + private->probed = true; r = sam3_protect_check(bank); if (r != ERROR_OK) return r; LOG_DEBUG("Bank = %d, nbanks = %d", - pPrivate->bank_number, pPrivate->pChip->details.n_banks); - if ((pPrivate->bank_number + 1) == pPrivate->pChip->details.n_banks) { + private->bank_number, private->chip->details.n_banks); + if ((private->bank_number + 1) == private->chip->details.n_banks) { /* read unique id, */ /* it appears to be associated with the *last* flash bank. */ - FLASHD_ReadUniqueID(pPrivate); + flashd_read_uid(private); } return r; @@ -3254,7 +3210,7 @@ static int sam3_auto_probe(struct flash_bank *bank) static int sam3_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { - struct sam3_bank_private *pPrivate; + struct sam3_bank_private *private; int r; LOG_DEBUG("Here"); @@ -3269,14 +3225,14 @@ static int sam3_erase(struct flash_bank *bank, unsigned int first, return r; } - pPrivate = get_sam3_bank_private(bank); - if (!(pPrivate->probed)) + private = get_sam3_bank_private(bank); + if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; - if ((first == 0) && ((last + 1) == pPrivate->nsectors)) { + if ((first == 0) && ((last + 1) == private->nsectors)) { /* whole chip */ LOG_DEBUG("Here"); - return FLASHD_EraseEntireBank(pPrivate); + return flashd_erase_entire_bank(private); } LOG_INFO("sam3 auto-erases while programming (request ignored)"); return ERROR_OK; @@ -3285,7 +3241,7 @@ static int sam3_erase(struct flash_bank *bank, unsigned int first, static int sam3_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { - struct sam3_bank_private *pPrivate; + struct sam3_bank_private *private; int r; LOG_DEBUG("Here"); @@ -3294,32 +3250,32 @@ static int sam3_protect(struct flash_bank *bank, int set, unsigned int first, return ERROR_TARGET_NOT_HALTED; } - pPrivate = get_sam3_bank_private(bank); - if (!(pPrivate->probed)) + private = get_sam3_bank_private(bank); + if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; if (set) - r = FLASHD_Lock(pPrivate, first, last); + r = flashd_lock(private, first, last); else - r = FLASHD_Unlock(pPrivate, first, last); + r = flashd_unlock(private, first, last); LOG_DEBUG("End: r=%d", r); return r; } -static int sam3_page_read(struct sam3_bank_private *pPrivate, unsigned pagenum, uint8_t *buf) +static int sam3_page_read(struct sam3_bank_private *private, unsigned pagenum, uint8_t *buf) { uint32_t adr; int r; - adr = pagenum * pPrivate->page_size; - adr += pPrivate->base_address; + adr = pagenum * private->page_size; + adr += private->base_address; - r = target_read_memory(pPrivate->pChip->target, + r = target_read_memory(private->chip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ - pPrivate->page_size / 4, + private->page_size / 4, buf); if (r != ERROR_OK) LOG_ERROR("SAM3: Flash program failed to read page phys address: 0x%08x", @@ -3327,18 +3283,18 @@ static int sam3_page_read(struct sam3_bank_private *pPrivate, unsigned pagenum, return r; } -static int sam3_page_write(struct sam3_bank_private *pPrivate, unsigned pagenum, const uint8_t *buf) +static int sam3_page_write(struct sam3_bank_private *private, unsigned pagenum, const uint8_t *buf) { uint32_t adr; uint32_t status; uint32_t fmr; /* EEFC Flash Mode Register */ int r; - adr = pagenum * pPrivate->page_size; - adr += pPrivate->base_address; + adr = pagenum * private->page_size; + adr += private->base_address; /* Get flash mode register value */ - r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address, &fmr); + r = target_read_u32(private->chip->target, private->controller_address, &fmr); if (r != ERROR_OK) LOG_DEBUG("Error Read failed: read flash mode register"); @@ -3346,18 +3302,18 @@ static int sam3_page_write(struct sam3_bank_private *pPrivate, unsigned pagenum, fmr &= 0xfffff0ff; /* set FWS (flash wait states) field in the FMR (flash mode register) */ - fmr |= (pPrivate->flash_wait_states << 8); + fmr |= (private->flash_wait_states << 8); LOG_DEBUG("Flash Mode: 0x%08x", ((unsigned int)(fmr))); - r = target_write_u32(pPrivate->pBank->target, pPrivate->controller_address, fmr); + r = target_write_u32(private->bank->target, private->controller_address, fmr); if (r != ERROR_OK) LOG_DEBUG("Error Write failed: set flash mode register"); LOG_DEBUG("Wr Page %u @ phys address: 0x%08x", pagenum, (unsigned int)(adr)); - r = target_write_memory(pPrivate->pChip->target, + r = target_write_memory(private->chip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ - pPrivate->page_size / 4, + private->page_size / 4, buf); if (r != ERROR_OK) { LOG_ERROR("SAM3: Failed to write (buffer) page at phys address 0x%08x", @@ -3365,7 +3321,7 @@ static int sam3_page_write(struct sam3_bank_private *pPrivate, unsigned pagenum, return r; } - r = EFC_PerformCommand(pPrivate, + r = efc_perform_command(private, /* send Erase & Write Page */ AT91C_EFC_FCMD_EWP, pagenum, @@ -3395,7 +3351,7 @@ static int sam3_write(struct flash_bank *bank, unsigned page_end; int r; unsigned page_offset; - struct sam3_bank_private *pPrivate; + struct sam3_bank_private *private; uint8_t *pagebuffer; /* in case we bail further below, set this to null */ @@ -3413,32 +3369,32 @@ static int sam3_write(struct flash_bank *bank, goto done; } - pPrivate = get_sam3_bank_private(bank); - if (!(pPrivate->probed)) { + private = get_sam3_bank_private(bank); + if (!(private->probed)) { r = ERROR_FLASH_BANK_NOT_PROBED; goto done; } - if ((offset + count) > pPrivate->size_bytes) { + if ((offset + count) > private->size_bytes) { LOG_ERROR("Flash write error - past end of bank"); LOG_ERROR(" offset: 0x%08x, count 0x%08x, BankEnd: 0x%08x", (unsigned int)(offset), (unsigned int)(count), - (unsigned int)(pPrivate->size_bytes)); + (unsigned int)(private->size_bytes)); r = ERROR_FAIL; goto done; } - pagebuffer = malloc(pPrivate->page_size); + pagebuffer = malloc(private->page_size); if (!pagebuffer) { - LOG_ERROR("No memory for %d Byte page buffer", (int)(pPrivate->page_size)); + LOG_ERROR("No memory for %d Byte page buffer", (int)(private->page_size)); r = ERROR_FAIL; goto done; } /* what page do we start & end in? */ - page_cur = offset / pPrivate->page_size; - page_end = (offset + count - 1) / pPrivate->page_size; + page_cur = offset / private->page_size; + page_end = (offset + count - 1) / private->page_size; LOG_DEBUG("Offset: 0x%08x, Count: 0x%08x", (unsigned int)(offset), (unsigned int)(count)); LOG_DEBUG("Page start: %d, Page End: %d", (int)(page_cur), (int)(page_end)); @@ -3453,16 +3409,16 @@ static int sam3_write(struct flash_bank *bank, /* Handle special case - all one page. */ if (page_cur == page_end) { LOG_DEBUG("Special case, all in one page"); - r = sam3_page_read(pPrivate, page_cur, pagebuffer); + r = sam3_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; - page_offset = (offset & (pPrivate->page_size-1)); + page_offset = (offset & (private->page_size-1)); memcpy(pagebuffer + page_offset, buffer, count); - r = sam3_page_write(pPrivate, page_cur, pagebuffer); + r = sam3_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; r = ERROR_OK; @@ -3470,21 +3426,21 @@ static int sam3_write(struct flash_bank *bank, } /* non-aligned start */ - page_offset = offset & (pPrivate->page_size - 1); + page_offset = offset & (private->page_size - 1); if (page_offset) { LOG_DEBUG("Not-Aligned start"); /* read the partial */ - r = sam3_page_read(pPrivate, page_cur, pagebuffer); + r = sam3_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* over-write with new data */ - n = (pPrivate->page_size - page_offset); + n = (private->page_size - page_offset); memcpy(pagebuffer + page_offset, buffer, n); - r = sam3_page_write(pPrivate, page_cur, pagebuffer); + r = sam3_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; @@ -3496,7 +3452,7 @@ static int sam3_write(struct flash_bank *bank, /* By checking that offset is correct here, we also fix a clang warning */ - assert(offset % pPrivate->page_size == 0); + assert(offset % private->page_size == 0); /* intermediate large pages */ /* also - the final *terminal* */ @@ -3505,12 +3461,12 @@ static int sam3_write(struct flash_bank *bank, (int)page_cur, (int)page_end, (unsigned int)(count)); while ((page_cur < page_end) && - (count >= pPrivate->page_size)) { - r = sam3_page_write(pPrivate, page_cur, buffer); + (count >= private->page_size)) { + r = sam3_page_write(private, page_cur, buffer); if (r != ERROR_OK) goto done; - count -= pPrivate->page_size; - buffer += pPrivate->page_size; + count -= private->page_size; + buffer += private->page_size; page_cur += 1; } @@ -3518,12 +3474,12 @@ static int sam3_write(struct flash_bank *bank, if (count) { LOG_DEBUG("Terminal partial page, count = 0x%08x", (unsigned int)(count)); /* we have a partial page */ - r = sam3_page_read(pPrivate, page_cur, pagebuffer); + r = sam3_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* data goes at start */ memcpy(pagebuffer, buffer, count); - r = sam3_page_write(pPrivate, page_cur, pagebuffer); + r = sam3_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; } @@ -3536,16 +3492,16 @@ done: COMMAND_HANDLER(sam3_handle_info_command) { - struct sam3_chip *pChip; - pChip = get_current_sam3(CMD); - if (!pChip) + struct sam3_chip *chip; + chip = get_current_sam3(CMD); + if (!chip) return ERROR_OK; unsigned x; int r; /* bank0 must exist before we can do anything */ - if (pChip->details.bank[0].pBank == NULL) { + if (!chip->details.bank[0].bank) { x = 0; need_define: command_print(CMD, @@ -3556,8 +3512,8 @@ need_define: } /* if bank 0 is not probed, then probe it */ - if (!(pChip->details.bank[0].probed)) { - r = sam3_auto_probe(pChip->details.bank[0].pBank); + if (!(chip->details.bank[0].probed)) { + r = sam3_auto_probe(chip->details.bank[0].bank); if (r != ERROR_OK) return ERROR_FAIL; } @@ -3568,21 +3524,21 @@ need_define: /* auto-probe other banks, 0 done above */ for (x = 1; x < SAM3_MAX_FLASH_BANKS; x++) { /* skip banks not present */ - if (!(pChip->details.bank[x].present)) + if (!(chip->details.bank[x].present)) continue; - if (pChip->details.bank[x].pBank == NULL) + if (!chip->details.bank[x].bank) goto need_define; - if (pChip->details.bank[x].probed) + if (chip->details.bank[x].probed) continue; - r = sam3_auto_probe(pChip->details.bank[x].pBank); + r = sam3_auto_probe(chip->details.bank[x].bank); if (r != ERROR_OK) return r; } - r = sam3_GetInfo(pChip); + r = sam3_get_info(chip); if (r != ERROR_OK) { LOG_DEBUG("Sam3Info, Failed %d", r); return r; @@ -3595,24 +3551,24 @@ COMMAND_HANDLER(sam3_handle_gpnvm_command) { unsigned x, v; int r, who; - struct sam3_chip *pChip; + struct sam3_chip *chip; - pChip = get_current_sam3(CMD); - if (!pChip) + chip = get_current_sam3(CMD); + if (!chip) return ERROR_OK; - if (pChip->target->state != TARGET_HALTED) { + if (chip->target->state != TARGET_HALTED) { LOG_ERROR("sam3 - target not halted"); return ERROR_TARGET_NOT_HALTED; } - if (pChip->details.bank[0].pBank == NULL) { + if (!chip->details.bank[0].bank) { command_print(CMD, "Bank0 must be defined first via: flash bank %s ...", at91sam3_flash.name); return ERROR_FAIL; } - if (!pChip->details.bank[0].probed) { - r = sam3_auto_probe(pChip->details.bank[0].pBank); + if (!chip->details.bank[0].probed) { + r = sam3_auto_probe(chip->details.bank[0].bank); if (r != ERROR_OK) return r; } @@ -3626,7 +3582,7 @@ COMMAND_HANDLER(sam3_handle_gpnvm_command) who = -1; break; case 2: - if ((0 == strcmp(CMD_ARGV[0], "show")) && (0 == strcmp(CMD_ARGV[1], "all"))) + if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) who = -1; else { uint32_t v32; @@ -3636,20 +3592,20 @@ COMMAND_HANDLER(sam3_handle_gpnvm_command) break; } - if (0 == strcmp("show", CMD_ARGV[0])) { + if (strcmp("show", CMD_ARGV[0]) == 0) { if (who == -1) { showall: r = ERROR_OK; - for (x = 0; x < pChip->details.n_gpnvms; x++) { - r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), x, &v); + for (x = 0; x < chip->details.n_gpnvms; x++) { + r = flashd_get_gpnvm(&(chip->details.bank[0]), x, &v); if (r != ERROR_OK) break; command_print(CMD, "sam3-gpnvm%u: %u", x, v); } return r; } - if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) { - r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v); + if ((who >= 0) && (((unsigned)(who)) < chip->details.n_gpnvms)) { + r = flashd_get_gpnvm(&(chip->details.bank[0]), who, &v); if (r == ERROR_OK) command_print(CMD, "sam3-gpnvm%u: %u", who, v); return r; @@ -3664,11 +3620,11 @@ showall: return ERROR_COMMAND_SYNTAX_ERROR; } - if (0 == strcmp("set", CMD_ARGV[0])) - r = FLASHD_SetGPNVM(&(pChip->details.bank[0]), who); - else if ((0 == strcmp("clr", CMD_ARGV[0])) || - (0 == strcmp("clear", CMD_ARGV[0]))) /* quietly accept both */ - r = FLASHD_ClrGPNVM(&(pChip->details.bank[0]), who); + if (strcmp("set", CMD_ARGV[0]) == 0) + r = flashd_set_gpnvm(&(chip->details.bank[0]), who); + else if ((strcmp("clr", CMD_ARGV[0]) == 0) || + (strcmp("clear", CMD_ARGV[0]) == 0)) /* quietly accept both */ + r = flashd_clr_gpnvm(&(chip->details.bank[0]), who); else { command_print(CMD, "Unknown command: %s", CMD_ARGV[0]); r = ERROR_COMMAND_SYNTAX_ERROR; @@ -3678,10 +3634,10 @@ showall: COMMAND_HANDLER(sam3_handle_slowclk_command) { - struct sam3_chip *pChip; + struct sam3_chip *chip; - pChip = get_current_sam3(CMD); - if (!pChip) + chip = get_current_sam3(CMD); + if (!chip) return ERROR_OK; switch (CMD_ARGC) { @@ -3698,7 +3654,7 @@ COMMAND_HANDLER(sam3_handle_slowclk_command) command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); return ERROR_COMMAND_SYNTAX_ERROR; } - pChip->cfg.slow_freq = v; + chip->cfg.slow_freq = v; break; } default: @@ -3707,8 +3663,8 @@ COMMAND_HANDLER(sam3_handle_slowclk_command) return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "Slowclk freq: %d.%03dkhz", - (int)(pChip->cfg.slow_freq / 1000), - (int)(pChip->cfg.slow_freq % 1000)); + (int)(chip->cfg.slow_freq / 1000), + (int)(chip->cfg.slow_freq % 1000)); return ERROR_OK; } diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index 1c61064253..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" @@ -98,12 +57,10 @@ #define AT91C_EFC_FCMD_STUI (0xE) /* (EFC) Start Read Unique ID */ #define AT91C_EFC_FCMD_SPUI (0xF) /* (EFC) Stop Read Unique ID */ -#define offset_EFC_FMR 0 -#define offset_EFC_FCR 4 -#define offset_EFC_FSR 8 -#define offset_EFC_FRR 12 - -extern const struct flash_driver at91sam4_flash; +#define OFFSET_EFC_FMR 0 +#define OFFSET_EFC_FCR 4 +#define OFFSET_EFC_FSR 8 +#define OFFSET_EFC_FRR 12 static float _tomhz(uint32_t freq_hz) { @@ -170,13 +127,13 @@ struct sam4_bank_private { /* DANGER: THERE ARE DRAGONS HERE.. */ /* NOTE: If you add more 'ghost' pointers */ /* be aware that you must *manually* update */ - /* these pointers in the function sam4_GetDetails() */ + /* these pointers in the function sam4_get_details() */ /* See the comment "Here there be dragons" */ /* so we can find the chip we belong to */ - struct sam4_chip *pChip; + struct sam4_chip *chip; /* so we can find the original bank pointer */ - struct flash_bank *pBank; + struct flash_bank *bank; unsigned bank_number; uint32_t controller_address; uint32_t base_address; @@ -193,7 +150,7 @@ struct sam4_chip_details { /* note: If you add pointers here */ /* be careful about them as they */ /* may need to be updated inside */ - /* the function: "sam4_GetDetails() */ + /* the function: "sam4_get_details() */ /* which copy/overwrites the */ /* 'runtime' copy of this structure */ uint32_t chipid_cidr; @@ -223,7 +180,7 @@ struct sam4_chip { struct sam4_reg_list { uint32_t address; size_t struct_offset; const char *name; - void (*explain_func)(struct sam4_chip *pInfo); + void (*explain_func)(struct sam4_chip *chip); }; static struct sam4_chip *all_sam4_chips; @@ -235,7 +192,7 @@ static struct sam4_chip *get_current_sam4(struct command_invocation *cmd) t = get_current_target(cmd->ctx); if (!t) { - command_print(cmd, "No current target?"); + command_print_sameline(cmd, "No current target?\n"); return NULL; } @@ -243,7 +200,7 @@ static struct sam4_chip *get_current_sam4(struct command_invocation *cmd) if (!p) { /* this should not happen */ /* the command is not registered until the chip is created? */ - command_print(cmd, "No SAM4 chips exist?"); + command_print_sameline(cmd, "No SAM4 chips exist?\n"); return NULL; } @@ -252,7 +209,7 @@ static struct sam4_chip *get_current_sam4(struct command_invocation *cmd) return p; p = p->next; } - command_print(cmd, "Cannot find SAM4 chip?"); + command_print_sameline(cmd, "Cannot find SAM4 chip?\n"); return NULL; } @@ -261,7 +218,7 @@ static struct sam4_chip *get_current_sam4(struct command_invocation *cmd) /*For the best results, nsectors are thus set to the amount of lock regions, and the sector_size*/ /*set to the lock region size. Page erases are used to erase 8KB sections when programming*/ -/* these are used to *initialize* the "pChip->details" structure. */ +/* these are used to *initialize* the "chip->details" structure. */ static const struct sam4_chip_details all_sam4_details[] = { /* Start at91sam4c* series */ /* at91sam4c32e - LQFP144 */ @@ -276,8 +233,8 @@ static const struct sam4_chip_details all_sam4_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_C32, .controller_address = 0x400e0a00, @@ -291,8 +248,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_C32, .controller_address = 0x400e0c00, @@ -317,8 +274,8 @@ static const struct sam4_chip_details all_sam4_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_C32, .controller_address = 0x400e0a00, @@ -332,8 +289,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_C32, .controller_address = 0x400e0c00, @@ -358,8 +315,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_C, .controller_address = 0x400e0a00, @@ -391,8 +348,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_C, .controller_address = 0x400e0a00, @@ -424,8 +381,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_C, .controller_address = 0x400e0a00, @@ -459,8 +416,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -494,8 +451,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -527,8 +484,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -560,8 +517,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -593,8 +550,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -626,8 +583,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -661,8 +618,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -695,8 +652,8 @@ static const struct sam4_chip_details all_sam4_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -728,8 +685,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -761,8 +718,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -794,8 +751,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -827,8 +784,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -860,8 +817,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -893,8 +850,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -927,8 +884,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -961,8 +918,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -995,8 +952,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -1029,8 +986,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -1063,8 +1020,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -1097,8 +1054,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = {*/ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -1132,8 +1089,8 @@ static const struct sam4_chip_details all_sam4_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, @@ -1148,8 +1105,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_2048K_SD, .controller_address = 0x400e0c00, @@ -1176,8 +1133,8 @@ static const struct sam4_chip_details all_sam4_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, @@ -1192,8 +1149,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_2048K_SD, .controller_address = 0x400e0c00, @@ -1220,8 +1177,8 @@ static const struct sam4_chip_details all_sam4_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, @@ -1236,8 +1193,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_1024K_SD, .controller_address = 0x400e0c00, @@ -1264,8 +1221,8 @@ static const struct sam4_chip_details all_sam4_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, @@ -1280,8 +1237,8 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[1] = { */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_1024K_SD, .controller_address = 0x400e0c00, @@ -1308,8 +1265,8 @@ static const struct sam4_chip_details all_sam4_details[] = { { { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -1330,7 +1287,7 @@ static const struct sam4_chip_details all_sam4_details[] = { } }, - /* atsamg55g19 */ + /* atsamg55g19 Rev.A */ { .chipid_cidr = 0x24470ae0, .name = "atsamg55g19", @@ -1343,8 +1300,42 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, + .bank_number = 0, + .base_address = FLASH_BANK_BASE_S, + .controller_address = 0x400e0a00, + .flash_wait_states = 5, + .present = true, + .size_bytes = 512 * 1024, + .nsectors = 64, + .sector_size = 8192, + .page_size = 512, + }, +/* .bank[1] = */ + { + .present = false, + .probed = false, + .bank_number = 1, + }, + } + }, + + /* atsamg55g19 Rev.B */ + { + .chipid_cidr = 0x24470ae1, + .name = "atsamg55g19b", + .total_flash_size = 512 * 1024, + .total_sram_size = 160 * 1024, + .n_gpnvms = 2, + .n_banks = 1, + + { +/* .bank[0] = */ + { + .probed = false, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -1364,7 +1355,7 @@ static const struct sam4_chip_details all_sam4_details[] = { } }, - /* atsamg55j19 */ + /* atsamg55j19 Rev.A */ { .chipid_cidr = 0x24570ae0, .name = "atsamg55j19", @@ -1377,8 +1368,42 @@ static const struct sam4_chip_details all_sam4_details[] = { /* .bank[0] = */ { .probed = false, - .pChip = NULL, - .pBank = NULL, + .chip = NULL, + .bank = NULL, + .bank_number = 0, + .base_address = FLASH_BANK_BASE_S, + .controller_address = 0x400e0a00, + .flash_wait_states = 5, + .present = true, + .size_bytes = 512 * 1024, + .nsectors = 64, + .sector_size = 8192, + .page_size = 512, + }, +/* .bank[1] = */ + { + .present = false, + .probed = false, + .bank_number = 1, + }, + } + }, + + /* atsamg55j19 Rev.B */ + { + .chipid_cidr = 0x24570ae1, + .name = "atsamg55j19b", + .total_flash_size = 512 * 1024, + .total_sram_size = 160 * 1024, + .n_gpnvms = 2, + .n_banks = 1, + + { +/* .bank[0] = */ + { + .probed = false, + .chip = NULL, + .bank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, @@ -1417,14 +1442,14 @@ static const struct sam4_chip_details all_sam4_details[] = { /** * Get the current status of the EEFC and * the value of some status bits (LOCKE, PROGE). - * @param pPrivate - info about the bank + * @param private - info about the bank * @param v - result goes here */ -static int EFC_GetStatus(struct sam4_bank_private *pPrivate, uint32_t *v) +static int efc_get_status(struct sam4_bank_private *private, uint32_t *v) { int r; - r = target_read_u32(pPrivate->pChip->target, - pPrivate->controller_address + offset_EFC_FSR, + r = target_read_u32(private->chip->target, + private->controller_address + OFFSET_EFC_FSR, v); LOG_DEBUG("Status: 0x%08x (lockerror: %d, cmderror: %d, ready: %d)", (unsigned int)(*v), @@ -1437,15 +1462,15 @@ static int EFC_GetStatus(struct sam4_bank_private *pPrivate, uint32_t *v) /** * Get the result of the last executed command. - * @param pPrivate - info about the bank + * @param private - info about the bank * @param v - result goes here */ -static int EFC_GetResult(struct sam4_bank_private *pPrivate, uint32_t *v) +static int efc_get_result(struct sam4_bank_private *private, uint32_t *v) { int r; uint32_t rv; - r = target_read_u32(pPrivate->pChip->target, - pPrivate->controller_address + offset_EFC_FRR, + r = target_read_u32(private->chip->target, + private->controller_address + OFFSET_EFC_FRR, &rv); if (v) *v = rv; @@ -1453,7 +1478,7 @@ static int EFC_GetResult(struct sam4_bank_private *pPrivate, uint32_t *v) return r; } -static int EFC_StartCommand(struct sam4_bank_private *pPrivate, +static int efc_start_command(struct sam4_bank_private *private, unsigned command, unsigned argument) { uint32_t n, v; @@ -1474,16 +1499,16 @@ do_retry: case AT91C_EFC_FCMD_EPA: case AT91C_EFC_FCMD_SLB: case AT91C_EFC_FCMD_CLB: - n = (pPrivate->size_bytes / pPrivate->page_size); + n = (private->size_bytes / private->page_size); if (argument >= n) LOG_ERROR("*BUG*: Embedded flash has only %u pages", (unsigned)(n)); break; case AT91C_EFC_FCMD_SFB: case AT91C_EFC_FCMD_CFB: - if (argument >= pPrivate->pChip->details.n_gpnvms) { + if (argument >= private->chip->details.n_gpnvms) { LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", - pPrivate->pChip->details.n_gpnvms); + private->chip->details.n_gpnvms); } break; @@ -1508,7 +1533,7 @@ do_retry: /* Situation (2) - normal, finished reading unique id */ } else { /* it should be "ready" */ - EFC_GetStatus(pPrivate, &v); + efc_get_status(private, &v); if (v & 1) { /* then it is ready */ /* we go on */ @@ -1517,14 +1542,14 @@ do_retry: /* we have done this before */ /* the controller is not responding. */ LOG_ERROR("flash controller(%d) is not ready! Error", - pPrivate->bank_number); + private->bank_number); return ERROR_FAIL; } else { retry++; LOG_ERROR("Flash controller(%d) is not ready, attempting reset", - pPrivate->bank_number); + private->bank_number); /* we do that by issuing the *STOP* command */ - EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0); + efc_start_command(private, AT91C_EFC_FCMD_SPUI, 0); /* above is recursive, and further recursion is blocked by */ /* if (command == AT91C_EFC_FCMD_SPUI) above */ goto do_retry; @@ -1534,8 +1559,8 @@ do_retry: v = (0x5A << 24) | (argument << 8) | command; LOG_DEBUG("Command: 0x%08x", ((unsigned int)(v))); - r = target_write_u32(pPrivate->pBank->target, - pPrivate->controller_address + offset_EFC_FCR, v); + r = target_write_u32(private->bank->target, + private->controller_address + OFFSET_EFC_FCR, v); if (r != ERROR_OK) LOG_DEBUG("Error Write failed"); return r; @@ -1543,12 +1568,12 @@ do_retry: /** * Performs the given command and wait until its completion (or an error). - * @param pPrivate - info about the bank + * @param private - info about the bank * @param command - Command to perform. * @param argument - Optional command argument. * @param status - put command status bits here */ -static int EFC_PerformCommand(struct sam4_bank_private *pPrivate, +static int efc_perform_command(struct sam4_bank_private *private, unsigned command, unsigned argument, uint32_t *status) @@ -1562,14 +1587,14 @@ static int EFC_PerformCommand(struct sam4_bank_private *pPrivate, if (status) *status = 0; - r = EFC_StartCommand(pPrivate, command, argument); + r = efc_start_command(private, command, argument); if (r != ERROR_OK) return r; ms_end = 10000 + timeval_ms(); do { - r = EFC_GetStatus(pPrivate, &v); + r = efc_get_status(private, &v); if (r != ERROR_OK) return r; ms_now = timeval_ms(); @@ -1589,81 +1614,84 @@ static int EFC_PerformCommand(struct sam4_bank_private *pPrivate, /** * Read the unique ID. - * @param pPrivate - info about the bank - * The unique ID is stored in the 'pPrivate' structure. + * @param private - info about the bank + * The unique ID is stored in the 'private' structure. */ -static int FLASHD_ReadUniqueID(struct sam4_bank_private *pPrivate) +static int flashd_read_uid(struct sam4_bank_private *private) { int r; uint32_t v; int x; /* assume 0 */ - pPrivate->pChip->cfg.unique_id[0] = 0; - pPrivate->pChip->cfg.unique_id[1] = 0; - pPrivate->pChip->cfg.unique_id[2] = 0; - pPrivate->pChip->cfg.unique_id[3] = 0; + private->chip->cfg.unique_id[0] = 0; + private->chip->cfg.unique_id[1] = 0; + private->chip->cfg.unique_id[2] = 0; + private->chip->cfg.unique_id[3] = 0; LOG_DEBUG("Begin"); - r = EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_STUI, 0); + r = efc_start_command(private, AT91C_EFC_FCMD_STUI, 0); if (r < 0) return r; for (x = 0; x < 4; x++) { - r = target_read_u32(pPrivate->pChip->target, - pPrivate->pBank->base + (x * 4), + r = target_read_u32(private->chip->target, + private->bank->base + (x * 4), &v); if (r < 0) return r; - pPrivate->pChip->cfg.unique_id[x] = v; + private->chip->cfg.unique_id[x] = v; } - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0, NULL); + r = efc_perform_command(private, AT91C_EFC_FCMD_SPUI, 0, NULL); LOG_DEBUG("End: R=%d, id = 0x%08x, 0x%08x, 0x%08x, 0x%08x", r, - (unsigned int)(pPrivate->pChip->cfg.unique_id[0]), - (unsigned int)(pPrivate->pChip->cfg.unique_id[1]), - (unsigned int)(pPrivate->pChip->cfg.unique_id[2]), - (unsigned int)(pPrivate->pChip->cfg.unique_id[3])); + (unsigned int)(private->chip->cfg.unique_id[0]), + (unsigned int)(private->chip->cfg.unique_id[1]), + (unsigned int)(private->chip->cfg.unique_id[2]), + (unsigned int)(private->chip->cfg.unique_id[3])); return r; } /** * Erases the entire flash. - * @param pPrivate - the info about the bank. + * @param private - the info about the bank. */ -static int FLASHD_EraseEntireBank(struct sam4_bank_private *pPrivate) +static int flashd_erase_entire_bank(struct sam4_bank_private *private) { LOG_DEBUG("Here"); - return EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_EA, 0, NULL); + return efc_perform_command(private, AT91C_EFC_FCMD_EA, 0, NULL); } /** * Erases the entire flash. - * @param pPrivate - the info about the bank. + * @param private - the info about the bank. + * @param first_page + * @param num_pages + * @param status */ -static int FLASHD_ErasePages(struct sam4_bank_private *pPrivate, - int firstPage, - int numPages, +static int flashd_erase_pages(struct sam4_bank_private *private, + int first_page, + int num_pages, uint32_t *status) { LOG_DEBUG("Here"); - uint8_t erasePages; - switch (numPages) { + uint8_t erase_pages; + switch (num_pages) { case 4: - erasePages = 0x00; + erase_pages = 0x00; break; case 8: - erasePages = 0x01; + erase_pages = 0x01; break; case 16: - erasePages = 0x02; + erase_pages = 0x02; break; case 32: - erasePages = 0x03; + erase_pages = 0x03; break; default: - erasePages = 0x00; + erase_pages = 0x00; break; } @@ -1674,45 +1702,45 @@ static int FLASHD_ErasePages(struct sam4_bank_private *pPrivate, * number of pages to be erased. Previously (firstpage << 2) was used * to conform to this, seems it should not be shifted... */ - return EFC_PerformCommand(pPrivate, + return efc_perform_command(private, /* send Erase Page */ AT91C_EFC_FCMD_EPA, - (firstPage) | erasePages, + (first_page) | erase_pages, status); } /** * Gets current GPNVM state. - * @param pPrivate - info about the bank. + * @param private - info about the bank. * @param gpnvm - GPNVM bit index. * @param puthere - result stored here. */ /* ------------------------------------------------------------------------------ */ -static int FLASHD_GetGPNVM(struct sam4_bank_private *pPrivate, unsigned gpnvm, unsigned *puthere) +static int flashd_get_gpnvm(struct sam4_bank_private *private, unsigned gpnvm, unsigned *puthere) { uint32_t v; int r; LOG_DEBUG("Here"); - if (pPrivate->bank_number != 0) { + if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } - if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { + if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", - gpnvm, pPrivate->pChip->details.n_gpnvms); + gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } /* Get GPNVMs status */ - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GFB, 0, NULL); + r = efc_perform_command(private, AT91C_EFC_FCMD_GFB, 0, NULL); if (r != ERROR_OK) { LOG_ERROR("Failed"); return r; } - r = EFC_GetResult(pPrivate, &v); + r = efc_get_result(private, &v); if (puthere) { /* Check if GPNVM is set */ @@ -1725,59 +1753,59 @@ static int FLASHD_GetGPNVM(struct sam4_bank_private *pPrivate, unsigned gpnvm, u /** * Clears the selected GPNVM bit. - * @param pPrivate info about the bank + * @param private info about the bank * @param gpnvm GPNVM index. * @returns 0 if successful; otherwise returns an error code. */ -static int FLASHD_ClrGPNVM(struct sam4_bank_private *pPrivate, unsigned gpnvm) +static int flashd_clr_gpnvm(struct sam4_bank_private *private, unsigned gpnvm) { int r; unsigned v; LOG_DEBUG("Here"); - if (pPrivate->bank_number != 0) { + if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } - if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { + if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", - gpnvm, pPrivate->pChip->details.n_gpnvms); + gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } - r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v); + r = flashd_get_gpnvm(private, gpnvm, &v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CFB, gpnvm, NULL); + r = efc_perform_command(private, AT91C_EFC_FCMD_CFB, gpnvm, NULL); LOG_DEBUG("End: %d", r); return r; } /** * Sets the selected GPNVM bit. - * @param pPrivate info about the bank + * @param private info about the bank * @param gpnvm GPNVM index. */ -static int FLASHD_SetGPNVM(struct sam4_bank_private *pPrivate, unsigned gpnvm) +static int flashd_set_gpnvm(struct sam4_bank_private *private, unsigned gpnvm) { int r; unsigned v; - if (pPrivate->bank_number != 0) { + if (private->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } - if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { + if (gpnvm >= private->chip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", - gpnvm, pPrivate->pChip->details.n_gpnvms); + gpnvm, private->chip->details.n_gpnvms); return ERROR_FAIL; } - r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v); + r = flashd_get_gpnvm(private, gpnvm, &v); if (r != ERROR_OK) return r; if (v) { @@ -1785,26 +1813,26 @@ static int FLASHD_SetGPNVM(struct sam4_bank_private *pPrivate, unsigned gpnvm) r = ERROR_OK; } else { /* set it */ - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SFB, gpnvm, NULL); + r = efc_perform_command(private, AT91C_EFC_FCMD_SFB, gpnvm, NULL); } return r; } /** * Returns a bit field (at most 64) of locked regions within a page. - * @param pPrivate info about the bank + * @param private info about the bank * @param v where to store locked bits */ -static int FLASHD_GetLockBits(struct sam4_bank_private *pPrivate, uint32_t *v) +static int flashd_get_lock_bits(struct sam4_bank_private *private, uint32_t *v) { int r; LOG_DEBUG("Here"); - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GLB, 0, NULL); + r = efc_perform_command(private, AT91C_EFC_FCMD_GLB, 0, NULL); if (r == ERROR_OK) { - EFC_GetResult(pPrivate, v); - EFC_GetResult(pPrivate, v); - EFC_GetResult(pPrivate, v); - r = EFC_GetResult(pPrivate, v); + efc_get_result(private, v); + efc_get_result(private, v); + efc_get_result(private, v); + r = efc_get_result(private, v); } LOG_DEBUG("End: %d", r); return r; @@ -1812,12 +1840,12 @@ static int FLASHD_GetLockBits(struct sam4_bank_private *pPrivate, uint32_t *v) /** * Unlocks all the regions in the given address range. - * @param pPrivate info about the bank + * @param private info about the bank * @param start_sector first sector to unlock * @param end_sector last (inclusive) to unlock */ -static int FLASHD_Unlock(struct sam4_bank_private *pPrivate, +static int flashd_unlock(struct sam4_bank_private *private, unsigned start_sector, unsigned end_sector) { @@ -1826,13 +1854,13 @@ static int FLASHD_Unlock(struct sam4_bank_private *pPrivate, uint32_t pg; uint32_t pages_per_sector; - pages_per_sector = pPrivate->sector_size / pPrivate->page_size; + pages_per_sector = private->sector_size / private->page_size; /* Unlock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CLB, pg, &status); + r = efc_perform_command(private, AT91C_EFC_FCMD_CLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; @@ -1843,11 +1871,11 @@ static int FLASHD_Unlock(struct sam4_bank_private *pPrivate, /** * Locks regions - * @param pPrivate - info about the bank + * @param private - info about the bank * @param start_sector - first sector to lock * @param end_sector - last sector (inclusive) to lock */ -static int FLASHD_Lock(struct sam4_bank_private *pPrivate, +static int flashd_lock(struct sam4_bank_private *private, unsigned start_sector, unsigned end_sector) { @@ -1856,13 +1884,13 @@ static int FLASHD_Lock(struct sam4_bank_private *pPrivate, uint32_t pages_per_sector; int r; - pages_per_sector = pPrivate->sector_size / pPrivate->page_size; + pages_per_sector = private->sector_size / private->page_size; /* Lock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; - r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SLB, pg, &status); + r = efc_perform_command(private, AT91C_EFC_FCMD_SLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; @@ -1874,7 +1902,7 @@ static int FLASHD_Lock(struct sam4_bank_private *pPrivate, /* begin helpful debug code */ /* print the fieldname, the field value, in dec & hex, and return field value */ -static uint32_t sam4_reg_fieldname(struct sam4_chip *pChip, +static uint32_t sam4_reg_fieldname(struct sam4_chip *chip, const char *regname, uint32_t value, unsigned shift, @@ -2035,72 +2063,72 @@ static const char *const _rc_freq[] = { "4 MHz", "8 MHz", "12 MHz", "reserved" }; -static void sam4_explain_ckgr_mor(struct sam4_chip *pChip) +static void sam4_explain_ckgr_mor(struct sam4_chip *chip) { uint32_t v; uint32_t rcen; - v = sam4_reg_fieldname(pChip, "MOSCXTEN", pChip->cfg.CKGR_MOR, 0, 1); + v = sam4_reg_fieldname(chip, "MOSCXTEN", chip->cfg.CKGR_MOR, 0, 1); LOG_USER("(main xtal enabled: %s)", _yes_or_no(v)); - v = sam4_reg_fieldname(pChip, "MOSCXTBY", pChip->cfg.CKGR_MOR, 1, 1); + v = sam4_reg_fieldname(chip, "MOSCXTBY", chip->cfg.CKGR_MOR, 1, 1); LOG_USER("(main osc bypass: %s)", _yes_or_no(v)); - rcen = sam4_reg_fieldname(pChip, "MOSCRCEN", pChip->cfg.CKGR_MOR, 3, 1); + rcen = sam4_reg_fieldname(chip, "MOSCRCEN", chip->cfg.CKGR_MOR, 3, 1); LOG_USER("(onchip RC-OSC enabled: %s)", _yes_or_no(rcen)); - v = sam4_reg_fieldname(pChip, "MOSCRCF", pChip->cfg.CKGR_MOR, 4, 3); + v = sam4_reg_fieldname(chip, "MOSCRCF", chip->cfg.CKGR_MOR, 4, 3); LOG_USER("(onchip RC-OSC freq: %s)", _rc_freq[v]); - pChip->cfg.rc_freq = 0; + chip->cfg.rc_freq = 0; if (rcen) { switch (v) { default: - pChip->cfg.rc_freq = 0; + chip->cfg.rc_freq = 0; break; case 0: - pChip->cfg.rc_freq = 4 * 1000 * 1000; + chip->cfg.rc_freq = 4 * 1000 * 1000; break; case 1: - pChip->cfg.rc_freq = 8 * 1000 * 1000; + chip->cfg.rc_freq = 8 * 1000 * 1000; break; case 2: - pChip->cfg.rc_freq = 12 * 1000 * 1000; + chip->cfg.rc_freq = 12 * 1000 * 1000; break; } } - v = sam4_reg_fieldname(pChip, "MOSCXTST", pChip->cfg.CKGR_MOR, 8, 8); + v = sam4_reg_fieldname(chip, "MOSCXTST", chip->cfg.CKGR_MOR, 8, 8); LOG_USER("(startup clks, time= %f uSecs)", - ((float)(v * 1000000)) / ((float)(pChip->cfg.slow_freq))); - v = sam4_reg_fieldname(pChip, "MOSCSEL", pChip->cfg.CKGR_MOR, 24, 1); + ((float)(v * 1000000)) / ((float)(chip->cfg.slow_freq))); + v = sam4_reg_fieldname(chip, "MOSCSEL", chip->cfg.CKGR_MOR, 24, 1); LOG_USER("(mainosc source: %s)", v ? "external xtal" : "internal RC"); - v = sam4_reg_fieldname(pChip, "CFDEN", pChip->cfg.CKGR_MOR, 25, 1); + v = sam4_reg_fieldname(chip, "CFDEN", chip->cfg.CKGR_MOR, 25, 1); LOG_USER("(clock failure enabled: %s)", _yes_or_no(v)); } -static void sam4_explain_chipid_cidr(struct sam4_chip *pChip) +static void sam4_explain_chipid_cidr(struct sam4_chip *chip) { int x; uint32_t v; const char *cp; - sam4_reg_fieldname(pChip, "Version", pChip->cfg.CHIPID_CIDR, 0, 5); + sam4_reg_fieldname(chip, "Version", chip->cfg.CHIPID_CIDR, 0, 5); LOG_USER_N("\n"); - v = sam4_reg_fieldname(pChip, "EPROC", pChip->cfg.CHIPID_CIDR, 5, 3); + v = sam4_reg_fieldname(chip, "EPROC", chip->cfg.CHIPID_CIDR, 5, 3); LOG_USER("%s", eproc_names[v]); - v = sam4_reg_fieldname(pChip, "NVPSIZE", pChip->cfg.CHIPID_CIDR, 8, 4); + v = sam4_reg_fieldname(chip, "NVPSIZE", chip->cfg.CHIPID_CIDR, 8, 4); LOG_USER("%s", nvpsize[v]); - v = sam4_reg_fieldname(pChip, "NVPSIZE2", pChip->cfg.CHIPID_CIDR, 12, 4); + v = sam4_reg_fieldname(chip, "NVPSIZE2", chip->cfg.CHIPID_CIDR, 12, 4); LOG_USER("%s", nvpsize2[v]); - v = sam4_reg_fieldname(pChip, "SRAMSIZE", pChip->cfg.CHIPID_CIDR, 16, 4); + v = sam4_reg_fieldname(chip, "SRAMSIZE", chip->cfg.CHIPID_CIDR, 16, 4); LOG_USER("%s", sramsize[v]); - v = sam4_reg_fieldname(pChip, "ARCH", pChip->cfg.CHIPID_CIDR, 20, 8); + v = sam4_reg_fieldname(chip, "ARCH", chip->cfg.CHIPID_CIDR, 20, 8); cp = _unknown; for (x = 0; archnames[x].name; x++) { if (v == archnames[x].value) { @@ -2111,73 +2139,73 @@ static void sam4_explain_chipid_cidr(struct sam4_chip *pChip) LOG_USER("%s", cp); - v = sam4_reg_fieldname(pChip, "NVPTYP", pChip->cfg.CHIPID_CIDR, 28, 3); + v = sam4_reg_fieldname(chip, "NVPTYP", chip->cfg.CHIPID_CIDR, 28, 3); LOG_USER("%s", nvptype[v]); - v = sam4_reg_fieldname(pChip, "EXTID", pChip->cfg.CHIPID_CIDR, 31, 1); + v = sam4_reg_fieldname(chip, "EXTID", chip->cfg.CHIPID_CIDR, 31, 1); LOG_USER("(exists: %s)", _yes_or_no(v)); } -static void sam4_explain_ckgr_mcfr(struct sam4_chip *pChip) +static void sam4_explain_ckgr_mcfr(struct sam4_chip *chip) { uint32_t v; - v = sam4_reg_fieldname(pChip, "MAINFRDY", pChip->cfg.CKGR_MCFR, 16, 1); + v = sam4_reg_fieldname(chip, "MAINFRDY", chip->cfg.CKGR_MCFR, 16, 1); LOG_USER("(main ready: %s)", _yes_or_no(v)); - v = sam4_reg_fieldname(pChip, "MAINF", pChip->cfg.CKGR_MCFR, 0, 16); + v = sam4_reg_fieldname(chip, "MAINF", chip->cfg.CKGR_MCFR, 0, 16); - v = (v * pChip->cfg.slow_freq) / 16; - pChip->cfg.mainosc_freq = v; + v = (v * chip->cfg.slow_freq) / 16; + chip->cfg.mainosc_freq = v; LOG_USER("(%3.03f Mhz (%" PRIu32 ".%03" PRIu32 "khz slowclk)", _tomhz(v), - (uint32_t)(pChip->cfg.slow_freq / 1000), - (uint32_t)(pChip->cfg.slow_freq % 1000)); + (uint32_t)(chip->cfg.slow_freq / 1000), + (uint32_t)(chip->cfg.slow_freq % 1000)); } -static void sam4_explain_ckgr_plla(struct sam4_chip *pChip) +static void sam4_explain_ckgr_plla(struct sam4_chip *chip) { uint32_t mula, diva; - diva = sam4_reg_fieldname(pChip, "DIVA", pChip->cfg.CKGR_PLLAR, 0, 8); + diva = sam4_reg_fieldname(chip, "DIVA", chip->cfg.CKGR_PLLAR, 0, 8); LOG_USER_N("\n"); - mula = sam4_reg_fieldname(pChip, "MULA", pChip->cfg.CKGR_PLLAR, 16, 11); + mula = sam4_reg_fieldname(chip, "MULA", chip->cfg.CKGR_PLLAR, 16, 11); LOG_USER_N("\n"); - pChip->cfg.plla_freq = 0; + chip->cfg.plla_freq = 0; if (mula == 0) LOG_USER("\tPLLA Freq: (Disabled,mula = 0)"); else if (diva == 0) LOG_USER("\tPLLA Freq: (Disabled,diva = 0)"); else if (diva >= 1) { - pChip->cfg.plla_freq = (pChip->cfg.mainosc_freq * (mula + 1) / diva); + chip->cfg.plla_freq = (chip->cfg.mainosc_freq * (mula + 1) / diva); LOG_USER("\tPLLA Freq: %3.03f MHz", - _tomhz(pChip->cfg.plla_freq)); + _tomhz(chip->cfg.plla_freq)); } } -static void sam4_explain_mckr(struct sam4_chip *pChip) +static void sam4_explain_mckr(struct sam4_chip *chip) { uint32_t css, pres, fin = 0; int pdiv = 0; const char *cp = NULL; - css = sam4_reg_fieldname(pChip, "CSS", pChip->cfg.PMC_MCKR, 0, 2); + css = sam4_reg_fieldname(chip, "CSS", chip->cfg.PMC_MCKR, 0, 2); switch (css & 3) { case 0: - fin = pChip->cfg.slow_freq; + fin = chip->cfg.slow_freq; cp = "slowclk"; break; case 1: - fin = pChip->cfg.mainosc_freq; + fin = chip->cfg.mainosc_freq; cp = "mainosc"; break; case 2: - fin = pChip->cfg.plla_freq; + fin = chip->cfg.plla_freq; cp = "plla"; break; case 3: - if (pChip->cfg.CKGR_UCKR & (1 << 16)) { + if (chip->cfg.CKGR_UCKR & (1 << 16)) { fin = 480 * 1000 * 1000; cp = "upll"; } else { @@ -2193,7 +2221,7 @@ static void sam4_explain_mckr(struct sam4_chip *pChip) LOG_USER("%s (%3.03f Mhz)", cp, _tomhz(fin)); - pres = sam4_reg_fieldname(pChip, "PRES", pChip->cfg.PMC_MCKR, 4, 3); + pres = sam4_reg_fieldname(chip, "PRES", chip->cfg.PMC_MCKR, 4, 3); switch (pres & 0x07) { case 0: pdiv = 1; @@ -2235,33 +2263,33 @@ static void sam4_explain_mckr(struct sam4_chip *pChip) fin = fin / pdiv; /* sam4 has a *SINGLE* clock - */ /* other at91 series parts have divisors for these. */ - pChip->cfg.cpu_freq = fin; - pChip->cfg.mclk_freq = fin; - pChip->cfg.fclk_freq = fin; + chip->cfg.cpu_freq = fin; + chip->cfg.mclk_freq = fin; + chip->cfg.fclk_freq = fin; LOG_USER("\t\tResult CPU Freq: %3.03f", _tomhz(fin)); } #if 0 -static struct sam4_chip *target2sam4(struct target *pTarget) +static struct sam4_chip *target2sam4(struct target *target) { - struct sam4_chip *pChip; + struct sam4_chip *chip; - if (pTarget == NULL) + if (!target) return NULL; - pChip = all_sam4_chips; - while (pChip) { - if (pChip->target == pTarget) + chip = all_sam4_chips; + while (chip) { + if (chip->target == target) break; /* return below */ else - pChip = pChip->next; + chip = chip->next; } - return pChip; + return chip; } #endif -static uint32_t *sam4_get_reg_ptr(struct sam4_cfg *pCfg, const struct sam4_reg_list *pList) +static uint32_t *sam4_get_reg_ptr(struct sam4_cfg *cfg, const struct sam4_reg_list *list) { /* this function exists to help */ /* keep funky offsetof() errors */ @@ -2270,7 +2298,7 @@ static uint32_t *sam4_get_reg_ptr(struct sam4_cfg *pCfg, const struct sam4_reg_l /* By using prototypes - we can detect what would */ /* be casting errors. */ - return (uint32_t *)(void *)(((char *)(pCfg)) + pList->struct_offset); + return (uint32_t *)(void *)(((char *)(cfg)) + list->struct_offset); } @@ -2308,106 +2336,106 @@ static struct sam4_bank_private *get_sam4_bank_private(struct flash_bank *bank) * Given a pointer to where it goes in the structure, * determine the register name, address from the all registers table. */ -static const struct sam4_reg_list *sam4_GetReg(struct sam4_chip *pChip, uint32_t *goes_here) +static const struct sam4_reg_list *sam4_get_reg(struct sam4_chip *chip, uint32_t *goes_here) { - const struct sam4_reg_list *pReg; + const struct sam4_reg_list *reg; - pReg = &(sam4_all_regs[0]); - while (pReg->name) { - uint32_t *pPossible; + reg = &(sam4_all_regs[0]); + while (reg->name) { + uint32_t *possible; /* calculate where this one go.. */ /* it is "possibly" this register. */ - pPossible = ((uint32_t *)(void *)(((char *)(&(pChip->cfg))) + pReg->struct_offset)); + possible = ((uint32_t *)(void *)(((char *)(&(chip->cfg))) + reg->struct_offset)); /* well? Is it this register */ - if (pPossible == goes_here) { + if (possible == goes_here) { /* Jump for joy! */ - return pReg; + return reg; } /* next... */ - pReg++; + reg++; } /* This is *TOTAL*PANIC* - we are totally screwed. */ LOG_ERROR("INVALID SAM4 REGISTER"); return NULL; } -static int sam4_ReadThisReg(struct sam4_chip *pChip, uint32_t *goes_here) +static int sam4_read_this_reg(struct sam4_chip *chip, uint32_t *goes_here) { - const struct sam4_reg_list *pReg; + const struct sam4_reg_list *reg; int r; - pReg = sam4_GetReg(pChip, goes_here); - if (!pReg) + reg = sam4_get_reg(chip, goes_here); + if (!reg) return ERROR_FAIL; - r = target_read_u32(pChip->target, pReg->address, goes_here); + r = target_read_u32(chip->target, reg->address, goes_here); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM4 register: %s @ 0x%08x, Err: %d", - pReg->name, (unsigned)(pReg->address), r); + reg->name, (unsigned)(reg->address), r); } return r; } -static int sam4_ReadAllRegs(struct sam4_chip *pChip) +static int sam4_read_all_regs(struct sam4_chip *chip) { int r; - const struct sam4_reg_list *pReg; + const struct sam4_reg_list *reg; - pReg = &(sam4_all_regs[0]); - while (pReg->name) { - r = sam4_ReadThisReg(pChip, - sam4_get_reg_ptr(&(pChip->cfg), pReg)); + reg = &(sam4_all_regs[0]); + while (reg->name) { + r = sam4_read_this_reg(chip, + sam4_get_reg_ptr(&(chip->cfg), reg)); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM4 register: %s @ 0x%08x, Error: %d", - pReg->name, ((unsigned)(pReg->address)), r); + reg->name, ((unsigned)(reg->address)), r); return r; } - pReg++; + reg++; } return ERROR_OK; } -static int sam4_GetInfo(struct sam4_chip *pChip) +static int sam4_get_info(struct sam4_chip *chip) { - const struct sam4_reg_list *pReg; + const struct sam4_reg_list *reg; uint32_t regval; int r; - r = sam4_ReadAllRegs(pChip); + r = sam4_read_all_regs(chip); if (r != ERROR_OK) return r; - pReg = &(sam4_all_regs[0]); - while (pReg->name) { + reg = &(sam4_all_regs[0]); + while (reg->name) { /* display all regs */ - LOG_DEBUG("Start: %s", pReg->name); - regval = *sam4_get_reg_ptr(&(pChip->cfg), pReg); + LOG_DEBUG("Start: %s", reg->name); + regval = *sam4_get_reg_ptr(&(chip->cfg), reg); LOG_USER("%*s: [0x%08" PRIx32 "] -> 0x%08" PRIx32, REG_NAME_WIDTH, - pReg->name, - pReg->address, + reg->name, + reg->address, regval); - if (pReg->explain_func) - (*(pReg->explain_func))(pChip); - LOG_DEBUG("End: %s", pReg->name); - pReg++; + if (reg->explain_func) + (*(reg->explain_func))(chip); + LOG_DEBUG("End: %s", reg->name); + reg++; } - LOG_USER(" rc-osc: %3.03f MHz", _tomhz(pChip->cfg.rc_freq)); - LOG_USER(" mainosc: %3.03f MHz", _tomhz(pChip->cfg.mainosc_freq)); - LOG_USER(" plla: %3.03f MHz", _tomhz(pChip->cfg.plla_freq)); - LOG_USER(" cpu-freq: %3.03f MHz", _tomhz(pChip->cfg.cpu_freq)); - LOG_USER("mclk-freq: %3.03f MHz", _tomhz(pChip->cfg.mclk_freq)); + LOG_USER(" rc-osc: %3.03f MHz", _tomhz(chip->cfg.rc_freq)); + LOG_USER(" mainosc: %3.03f MHz", _tomhz(chip->cfg.mainosc_freq)); + LOG_USER(" plla: %3.03f MHz", _tomhz(chip->cfg.plla_freq)); + LOG_USER(" cpu-freq: %3.03f MHz", _tomhz(chip->cfg.cpu_freq)); + LOG_USER("mclk-freq: %3.03f MHz", _tomhz(chip->cfg.mclk_freq)); LOG_USER(" UniqueId: 0x%08" PRIx32 " 0x%08" PRIx32 " 0x%08" PRIx32 " 0x%08"PRIx32, - pChip->cfg.unique_id[0], - pChip->cfg.unique_id[1], - pChip->cfg.unique_id[2], - pChip->cfg.unique_id[3]); + chip->cfg.unique_id[0], + chip->cfg.unique_id[1], + chip->cfg.unique_id[2], + chip->cfg.unique_id[3]); return ERROR_OK; } @@ -2417,7 +2445,7 @@ static int sam4_protect_check(struct flash_bank *bank) int r; uint32_t v[4] = {0}; unsigned x; - struct sam4_bank_private *pPrivate; + struct sam4_bank_private *private; LOG_DEBUG("Begin"); if (bank->target->state != TARGET_HALTED) { @@ -2425,21 +2453,21 @@ static int sam4_protect_check(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } - pPrivate = get_sam4_bank_private(bank); - if (!pPrivate) { + private = get_sam4_bank_private(bank); + if (!private) { LOG_ERROR("no private for this bank?"); return ERROR_FAIL; } - if (!(pPrivate->probed)) + if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; - r = FLASHD_GetLockBits(pPrivate, v); + r = flashd_get_lock_bits(private, v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } - for (x = 0; x < pPrivate->nsectors; x++) + for (x = 0; x < private->nsectors; x++) bank->sectors[x].is_protected = (!!(v[x >> 5] & (1 << (x % 32)))); LOG_DEBUG("Done"); return ERROR_OK; @@ -2447,32 +2475,32 @@ static int sam4_protect_check(struct flash_bank *bank) FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command) { - struct sam4_chip *pChip; + struct sam4_chip *chip; - pChip = all_sam4_chips; + chip = all_sam4_chips; /* is this an existing chip? */ - while (pChip) { - if (pChip->target == bank->target) + while (chip) { + if (chip->target == bank->target) break; - pChip = pChip->next; + chip = chip->next; } - if (!pChip) { + if (!chip) { /* this is a *NEW* chip */ - pChip = calloc(1, sizeof(struct sam4_chip)); - if (!pChip) { + chip = calloc(1, sizeof(struct sam4_chip)); + if (!chip) { LOG_ERROR("NO RAM!"); return ERROR_FAIL; } - pChip->target = bank->target; + chip->target = bank->target; /* insert at head */ - pChip->next = all_sam4_chips; - all_sam4_chips = pChip; - pChip->target = bank->target; + chip->next = all_sam4_chips; + all_sam4_chips = chip; + chip->target = bank->target; /* assumption is this runs at 32khz */ - pChip->cfg.slow_freq = 32768; - pChip->probed = false; + chip->cfg.slow_freq = 32768; + chip->probed = false; } switch (bank->base) { @@ -2487,20 +2515,20 @@ FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command) /* at91sam4sd series has the same address for bank 0 (FLASH_BANK0_BASE_SD)*/ case FLASH_BANK_BASE_S: case FLASH_BANK_BASE_C: - bank->driver_priv = &(pChip->details.bank[0]); + bank->driver_priv = &(chip->details.bank[0]); bank->bank_number = 0; - pChip->details.bank[0].pChip = pChip; - pChip->details.bank[0].pBank = bank; + chip->details.bank[0].chip = chip; + chip->details.bank[0].bank = bank; break; /* Bank 1 of at91sam4sd/at91sam4c32 series */ case FLASH_BANK1_BASE_1024K_SD: case FLASH_BANK1_BASE_2048K_SD: case FLASH_BANK1_BASE_C32: - bank->driver_priv = &(pChip->details.bank[1]); + bank->driver_priv = &(chip->details.bank[1]); bank->bank_number = 1; - pChip->details.bank[1].pChip = pChip; - pChip->details.bank[1].pBank = bank; + chip->details.bank[1].chip = chip; + chip->details.bank[1].bank = bank; break; } @@ -2524,59 +2552,59 @@ static void sam4_free_driver_priv(struct flash_bank *bank) all_sam4_chips = NULL; } -static int sam4_GetDetails(struct sam4_bank_private *pPrivate) +static int sam4_get_details(struct sam4_bank_private *private) { - const struct sam4_chip_details *pDetails; - struct sam4_chip *pChip; + const struct sam4_chip_details *details; + struct sam4_chip *chip; struct flash_bank *saved_banks[SAM4_MAX_FLASH_BANKS]; unsigned x; LOG_DEBUG("Begin"); - pDetails = all_sam4_details; - while (pDetails->name) { + details = all_sam4_details; + while (details->name) { /* Compare cidr without version bits */ - if (pDetails->chipid_cidr == (pPrivate->pChip->cfg.CHIPID_CIDR & 0xFFFFFFE0)) + if (details->chipid_cidr == (private->chip->cfg.CHIPID_CIDR & 0xFFFFFFE0)) break; else - pDetails++; + details++; } - if (pDetails->name == NULL) { + if (!details->name) { LOG_ERROR("SAM4 ChipID 0x%08x not found in table (perhaps you can ID this chip?)", - (unsigned int)(pPrivate->pChip->cfg.CHIPID_CIDR)); + (unsigned int)(private->chip->cfg.CHIPID_CIDR)); /* Help the victim, print details about the chip */ LOG_INFO("SAM4 CHIPID_CIDR: 0x%08" PRIx32 " decodes as follows", - pPrivate->pChip->cfg.CHIPID_CIDR); - sam4_explain_chipid_cidr(pPrivate->pChip); + private->chip->cfg.CHIPID_CIDR); + sam4_explain_chipid_cidr(private->chip); return ERROR_FAIL; } else { - LOG_DEBUG("SAM4 Found chip %s, CIDR 0x%08" PRIx32, pDetails->name, pDetails->chipid_cidr); + LOG_DEBUG("SAM4 Found chip %s, CIDR 0x%08" PRIx32, details->name, details->chipid_cidr); } /* DANGER: THERE ARE DRAGONS HERE */ - /* get our pChip - it is going */ + /* get our chip - it is going */ /* to be over-written shortly */ - pChip = pPrivate->pChip; + chip = private->chip; /* Note that, in reality: */ /* */ - /* pPrivate = &(pChip->details.bank[0]) */ - /* or pPrivate = &(pChip->details.bank[1]) */ + /* private = &(chip->details.bank[0]) */ + /* or private = &(chip->details.bank[1]) */ /* */ /* save the "bank" pointers */ for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) - saved_banks[x] = pChip->details.bank[x].pBank; + saved_banks[x] = chip->details.bank[x].bank; /* Overwrite the "details" structure. */ - memcpy(&(pPrivate->pChip->details), - pDetails, - sizeof(pPrivate->pChip->details)); + memcpy(&(private->chip->details), + details, + sizeof(private->chip->details)); /* now fix the ghosted pointers */ for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) { - pChip->details.bank[x].pChip = pChip; - pChip->details.bank[x].pBank = saved_banks[x]; + chip->details.bank[x].chip = chip; + chip->details.bank[x].bank = saved_banks[x]; } /* update the *BANK*SIZE* */ @@ -2585,21 +2613,18 @@ static int sam4_GetDetails(struct sam4_bank_private *pPrivate) return ERROR_OK; } -static int sam4_info(struct flash_bank *bank, char *buf, int buf_size) +static int sam4_info(struct flash_bank *bank, struct command_invocation *cmd) { - struct sam4_bank_private *pPrivate; + struct sam4_bank_private *private; int k = bank->size / 1024; - pPrivate = get_sam4_bank_private(bank); - if (pPrivate == NULL) { - buf[0] = '\0'; + private = get_sam4_bank_private(bank); + if (!private) return ERROR_FAIL; - } - snprintf(buf, buf_size, - "%s bank %d: %d kB at " TARGET_ADDR_FMT, - pPrivate->pChip->details.name, - pPrivate->bank_number, + command_print_sameline(cmd, "%s bank %d: %d kB at " TARGET_ADDR_FMT, + private->chip->details.name, + private->bank_number, k, bank->base); @@ -2609,7 +2634,7 @@ static int sam4_info(struct flash_bank *bank, char *buf, int buf_size) static int sam4_probe(struct flash_bank *bank) { int r; - struct sam4_bank_private *pPrivate; + struct sam4_bank_private *private; LOG_DEBUG("Begin: Bank: %u", bank->bank_number); @@ -2618,28 +2643,28 @@ static int sam4_probe(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } - pPrivate = get_sam4_bank_private(bank); - if (!pPrivate) { + private = get_sam4_bank_private(bank); + if (!private) { LOG_ERROR("Invalid/unknown bank number"); return ERROR_FAIL; } - r = sam4_ReadAllRegs(pPrivate->pChip); + r = sam4_read_all_regs(private->chip); if (r != ERROR_OK) return r; LOG_DEBUG("Here"); - if (pPrivate->pChip->probed) - r = sam4_GetInfo(pPrivate->pChip); + if (private->chip->probed) + r = sam4_get_info(private->chip); else - r = sam4_GetDetails(pPrivate); + r = sam4_get_details(private); if (r != ERROR_OK) return r; /* update the flash bank size */ for (unsigned int x = 0; x < SAM4_MAX_FLASH_BANKS; x++) { - if (bank->base == pPrivate->pChip->details.bank[x].base_address) { - bank->size = pPrivate->pChip->details.bank[x].size_bytes; + if (bank->base == private->chip->details.bank[x].base_address) { + bank->size = private->chip->details.bank[x].size_bytes; LOG_DEBUG("SAM4 Set flash bank to " TARGET_ADDR_FMT " - " TARGET_ADDR_FMT ", idx %d", bank->base, bank->base + bank->size, x); @@ -2647,35 +2672,35 @@ static int sam4_probe(struct flash_bank *bank) } } - if (bank->sectors == NULL) { - bank->sectors = calloc(pPrivate->nsectors, (sizeof((bank->sectors)[0]))); - if (bank->sectors == NULL) { + if (!bank->sectors) { + bank->sectors = calloc(private->nsectors, (sizeof((bank->sectors)[0]))); + if (!bank->sectors) { LOG_ERROR("No memory!"); return ERROR_FAIL; } - bank->num_sectors = pPrivate->nsectors; + bank->num_sectors = private->nsectors; for (unsigned int x = 0; x < bank->num_sectors; x++) { - bank->sectors[x].size = pPrivate->sector_size; - bank->sectors[x].offset = x * (pPrivate->sector_size); + bank->sectors[x].size = private->sector_size; + bank->sectors[x].offset = x * (private->sector_size); /* mark as unknown */ bank->sectors[x].is_erased = -1; bank->sectors[x].is_protected = -1; } } - pPrivate->probed = true; + private->probed = true; r = sam4_protect_check(bank); if (r != ERROR_OK) return r; LOG_DEBUG("Bank = %d, nbanks = %d", - pPrivate->bank_number, pPrivate->pChip->details.n_banks); - if ((pPrivate->bank_number + 1) == pPrivate->pChip->details.n_banks) { + private->bank_number, private->chip->details.n_banks); + if ((private->bank_number + 1) == private->chip->details.n_banks) { /* read unique id, */ /* it appears to be associated with the *last* flash bank. */ - FLASHD_ReadUniqueID(pPrivate); + flashd_read_uid(private); } return r; @@ -2683,10 +2708,10 @@ static int sam4_probe(struct flash_bank *bank) static int sam4_auto_probe(struct flash_bank *bank) { - struct sam4_bank_private *pPrivate; + struct sam4_bank_private *private; - pPrivate = get_sam4_bank_private(bank); - if (pPrivate && pPrivate->probed) + private = get_sam4_bank_private(bank); + if (private && private->probed) return ERROR_OK; return sam4_probe(bank); @@ -2695,11 +2720,11 @@ static int sam4_auto_probe(struct flash_bank *bank) static int sam4_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { - struct sam4_bank_private *pPrivate; + struct sam4_bank_private *private; int r; - int pageCount; + int page_count; /*16 pages equals 8KB - Same size as a lock region*/ - pageCount = 16; + page_count = 16; uint32_t status; LOG_DEBUG("Here"); @@ -2714,20 +2739,20 @@ static int sam4_erase(struct flash_bank *bank, unsigned int first, return r; } - pPrivate = get_sam4_bank_private(bank); - if (!(pPrivate->probed)) + private = get_sam4_bank_private(bank); + if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; - if ((first == 0) && ((last + 1) == pPrivate->nsectors)) { + if ((first == 0) && ((last + 1) == private->nsectors)) { /* whole chip */ LOG_DEBUG("Here"); - return FLASHD_EraseEntireBank(pPrivate); + return flashd_erase_entire_bank(private); } LOG_INFO("sam4 does not auto-erase while programming (Erasing relevant sectors)"); LOG_INFO("sam4 First: 0x%08x Last: 0x%08x", first, last); for (unsigned int i = first; i <= last; i++) { /*16 pages equals 8KB - Same size as a lock region*/ - r = FLASHD_ErasePages(pPrivate, (i * pageCount), pageCount, &status); + r = flashd_erase_pages(private, (i * page_count), page_count, &status); LOG_INFO("Erasing sector: 0x%08x", i); if (r != ERROR_OK) LOG_ERROR("SAM4: Error performing Erase page @ lock region number %u", @@ -2748,7 +2773,7 @@ static int sam4_erase(struct flash_bank *bank, unsigned int first, static int sam4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { - struct sam4_bank_private *pPrivate; + struct sam4_bank_private *private; int r; LOG_DEBUG("Here"); @@ -2757,32 +2782,32 @@ static int sam4_protect(struct flash_bank *bank, int set, unsigned int first, return ERROR_TARGET_NOT_HALTED; } - pPrivate = get_sam4_bank_private(bank); - if (!(pPrivate->probed)) + private = get_sam4_bank_private(bank); + if (!(private->probed)) return ERROR_FLASH_BANK_NOT_PROBED; if (set) - r = FLASHD_Lock(pPrivate, first, last); + r = flashd_lock(private, first, last); else - r = FLASHD_Unlock(pPrivate, first, last); + r = flashd_unlock(private, first, last); LOG_DEBUG("End: r=%d", r); return r; } -static int sam4_page_read(struct sam4_bank_private *pPrivate, unsigned pagenum, uint8_t *buf) +static int sam4_page_read(struct sam4_bank_private *private, unsigned pagenum, uint8_t *buf) { uint32_t adr; int r; - adr = pagenum * pPrivate->page_size; - adr = adr + pPrivate->base_address; + adr = pagenum * private->page_size; + adr = adr + private->base_address; - r = target_read_memory(pPrivate->pChip->target, + r = target_read_memory(private->chip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ - pPrivate->page_size / 4, + private->page_size / 4, buf); if (r != ERROR_OK) LOG_ERROR("SAM4: Flash program failed to read page phys address: 0x%08x", @@ -2790,13 +2815,13 @@ static int sam4_page_read(struct sam4_bank_private *pPrivate, unsigned pagenum, return r; } -static int sam4_set_wait(struct sam4_bank_private *pPrivate) +static int sam4_set_wait(struct sam4_bank_private *private) { uint32_t fmr; /* EEFC Flash Mode Register */ int r; /* Get flash mode register value */ - r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address, &fmr); + r = target_read_u32(private->chip->target, private->controller_address, &fmr); if (r != ERROR_OK) { LOG_ERROR("Error Read failed: read flash mode register"); return r; @@ -2806,33 +2831,33 @@ static int sam4_set_wait(struct sam4_bank_private *pPrivate) fmr &= 0xfffff0ff; /* set FWS (flash wait states) field in the FMR (flash mode register) */ - fmr |= (pPrivate->flash_wait_states << 8); + fmr |= (private->flash_wait_states << 8); LOG_DEBUG("Flash Mode: 0x%08x", ((unsigned int)(fmr))); - r = target_write_u32(pPrivate->pBank->target, pPrivate->controller_address, fmr); + r = target_write_u32(private->bank->target, private->controller_address, fmr); if (r != ERROR_OK) LOG_ERROR("Error Write failed: set flash mode register"); return r; } -static int sam4_page_write(struct sam4_bank_private *pPrivate, unsigned pagenum, const uint8_t *buf) +static int sam4_page_write(struct sam4_bank_private *private, unsigned pagenum, const uint8_t *buf) { uint32_t adr; uint32_t status; int r; - adr = pagenum * pPrivate->page_size; - adr = (adr + pPrivate->base_address); + adr = pagenum * private->page_size; + adr = (adr + private->base_address); /* 1st sector 8kBytes - page 0 - 15*/ /* 2nd sector 8kBytes - page 16 - 30*/ /* 3rd sector 48kBytes - page 31 - 127*/ LOG_DEBUG("Wr Page %u @ phys address: 0x%08x", pagenum, (unsigned int)(adr)); - r = target_write_memory(pPrivate->pChip->target, + r = target_write_memory(private->chip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ - pPrivate->page_size / 4, + private->page_size / 4, buf); if (r != ERROR_OK) { LOG_ERROR("SAM4: Failed to write (buffer) page at phys address 0x%08x", @@ -2840,7 +2865,7 @@ static int sam4_page_write(struct sam4_bank_private *pPrivate, unsigned pagenum, return r; } - r = EFC_PerformCommand(pPrivate, + r = efc_perform_command(private, /* send Erase & Write Page */ AT91C_EFC_FCMD_WP, /*AT91C_EFC_FCMD_EWP only works on first two 8kb sectors*/ pagenum, @@ -2870,7 +2895,7 @@ static int sam4_write(struct flash_bank *bank, unsigned page_end; int r; unsigned page_offset; - struct sam4_bank_private *pPrivate; + struct sam4_bank_private *private; uint8_t *pagebuffer; /* in case we bail further below, set this to null */ @@ -2888,36 +2913,36 @@ static int sam4_write(struct flash_bank *bank, goto done; } - pPrivate = get_sam4_bank_private(bank); - if (!(pPrivate->probed)) { + private = get_sam4_bank_private(bank); + if (!(private->probed)) { r = ERROR_FLASH_BANK_NOT_PROBED; goto done; } - if ((offset + count) > pPrivate->size_bytes) { + if ((offset + count) > private->size_bytes) { LOG_ERROR("Flash write error - past end of bank"); LOG_ERROR(" offset: 0x%08x, count 0x%08x, BankEnd: 0x%08x", (unsigned int)(offset), (unsigned int)(count), - (unsigned int)(pPrivate->size_bytes)); + (unsigned int)(private->size_bytes)); r = ERROR_FAIL; goto done; } - pagebuffer = malloc(pPrivate->page_size); + pagebuffer = malloc(private->page_size); if (!pagebuffer) { - LOG_ERROR("No memory for %d Byte page buffer", (int)(pPrivate->page_size)); + LOG_ERROR("No memory for %d Byte page buffer", (int)(private->page_size)); r = ERROR_FAIL; goto done; } - r = sam4_set_wait(pPrivate); + r = sam4_set_wait(private); if (r != ERROR_OK) goto done; /* what page do we start & end in? */ - page_cur = offset / pPrivate->page_size; - page_end = (offset + count - 1) / pPrivate->page_size; + page_cur = offset / private->page_size; + page_end = (offset + count - 1) / private->page_size; LOG_DEBUG("Offset: 0x%08x, Count: 0x%08x", (unsigned int)(offset), (unsigned int)(count)); LOG_DEBUG("Page start: %d, Page End: %d", (int)(page_cur), (int)(page_end)); @@ -2932,16 +2957,16 @@ static int sam4_write(struct flash_bank *bank, /* Handle special case - all one page. */ if (page_cur == page_end) { LOG_DEBUG("Special case, all in one page"); - r = sam4_page_read(pPrivate, page_cur, pagebuffer); + r = sam4_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; - page_offset = (offset & (pPrivate->page_size-1)); + page_offset = (offset & (private->page_size-1)); memcpy(pagebuffer + page_offset, buffer, count); - r = sam4_page_write(pPrivate, page_cur, pagebuffer); + r = sam4_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; r = ERROR_OK; @@ -2949,21 +2974,21 @@ static int sam4_write(struct flash_bank *bank, } /* non-aligned start */ - page_offset = offset & (pPrivate->page_size - 1); + page_offset = offset & (private->page_size - 1); if (page_offset) { LOG_DEBUG("Not-Aligned start"); /* read the partial */ - r = sam4_page_read(pPrivate, page_cur, pagebuffer); + r = sam4_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* over-write with new data */ - n = (pPrivate->page_size - page_offset); + n = (private->page_size - page_offset); memcpy(pagebuffer + page_offset, buffer, n); - r = sam4_page_write(pPrivate, page_cur, pagebuffer); + r = sam4_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; @@ -2975,7 +3000,7 @@ static int sam4_write(struct flash_bank *bank, /* By checking that offset is correct here, we also fix a clang warning */ - assert(offset % pPrivate->page_size == 0); + assert(offset % private->page_size == 0); /* intermediate large pages */ /* also - the final *terminal* */ @@ -2984,12 +3009,12 @@ static int sam4_write(struct flash_bank *bank, (int)page_cur, (int)page_end, (unsigned int)(count)); while ((page_cur < page_end) && - (count >= pPrivate->page_size)) { - r = sam4_page_write(pPrivate, page_cur, buffer); + (count >= private->page_size)) { + r = sam4_page_write(private, page_cur, buffer); if (r != ERROR_OK) goto done; - count -= pPrivate->page_size; - buffer += pPrivate->page_size; + count -= private->page_size; + buffer += private->page_size; page_cur += 1; } @@ -2997,12 +3022,12 @@ static int sam4_write(struct flash_bank *bank, if (count) { LOG_DEBUG("Terminal partial page, count = 0x%08x", (unsigned int)(count)); /* we have a partial page */ - r = sam4_page_read(pPrivate, page_cur, pagebuffer); + r = sam4_page_read(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* data goes at start */ memcpy(pagebuffer, buffer, count); - r = sam4_page_write(pPrivate, page_cur, pagebuffer); + r = sam4_page_write(private, page_cur, pagebuffer); if (r != ERROR_OK) goto done; } @@ -3015,16 +3040,16 @@ done: COMMAND_HANDLER(sam4_handle_info_command) { - struct sam4_chip *pChip; - pChip = get_current_sam4(CMD); - if (!pChip) + struct sam4_chip *chip; + chip = get_current_sam4(CMD); + if (!chip) return ERROR_OK; unsigned x; int r; /* bank0 must exist before we can do anything */ - if (pChip->details.bank[0].pBank == NULL) { + if (!chip->details.bank[0].bank) { x = 0; need_define: command_print(CMD, @@ -3035,8 +3060,8 @@ need_define: } /* if bank 0 is not probed, then probe it */ - if (!(pChip->details.bank[0].probed)) { - r = sam4_auto_probe(pChip->details.bank[0].pBank); + if (!(chip->details.bank[0].probed)) { + r = sam4_auto_probe(chip->details.bank[0].bank); if (r != ERROR_OK) return ERROR_FAIL; } @@ -3047,21 +3072,21 @@ need_define: /* auto-probe other banks, 0 done above */ for (x = 1; x < SAM4_MAX_FLASH_BANKS; x++) { /* skip banks not present */ - if (!(pChip->details.bank[x].present)) + if (!(chip->details.bank[x].present)) continue; - if (pChip->details.bank[x].pBank == NULL) + if (!chip->details.bank[x].bank) goto need_define; - if (pChip->details.bank[x].probed) + if (chip->details.bank[x].probed) continue; - r = sam4_auto_probe(pChip->details.bank[x].pBank); + r = sam4_auto_probe(chip->details.bank[x].bank); if (r != ERROR_OK) return r; } - r = sam4_GetInfo(pChip); + r = sam4_get_info(chip); if (r != ERROR_OK) { LOG_DEBUG("Sam4Info, Failed %d", r); return r; @@ -3074,24 +3099,24 @@ COMMAND_HANDLER(sam4_handle_gpnvm_command) { unsigned x, v; int r, who; - struct sam4_chip *pChip; + struct sam4_chip *chip; - pChip = get_current_sam4(CMD); - if (!pChip) + chip = get_current_sam4(CMD); + if (!chip) return ERROR_OK; - if (pChip->target->state != TARGET_HALTED) { + if (chip->target->state != TARGET_HALTED) { LOG_ERROR("sam4 - target not halted"); return ERROR_TARGET_NOT_HALTED; } - if (pChip->details.bank[0].pBank == NULL) { + if (!chip->details.bank[0].bank) { command_print(CMD, "Bank0 must be defined first via: flash bank %s ...", at91sam4_flash.name); return ERROR_FAIL; } - if (!pChip->details.bank[0].probed) { - r = sam4_auto_probe(pChip->details.bank[0].pBank); + if (!chip->details.bank[0].probed) { + r = sam4_auto_probe(chip->details.bank[0].bank); if (r != ERROR_OK) return r; } @@ -3105,7 +3130,7 @@ COMMAND_HANDLER(sam4_handle_gpnvm_command) who = -1; break; case 2: - if ((0 == strcmp(CMD_ARGV[0], "show")) && (0 == strcmp(CMD_ARGV[1], "all"))) + if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) who = -1; else { uint32_t v32; @@ -3115,20 +3140,20 @@ COMMAND_HANDLER(sam4_handle_gpnvm_command) break; } - if (0 == strcmp("show", CMD_ARGV[0])) { + if (strcmp("show", CMD_ARGV[0]) == 0) { if (who == -1) { showall: r = ERROR_OK; - for (x = 0; x < pChip->details.n_gpnvms; x++) { - r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), x, &v); + for (x = 0; x < chip->details.n_gpnvms; x++) { + r = flashd_get_gpnvm(&(chip->details.bank[0]), x, &v); if (r != ERROR_OK) break; command_print(CMD, "sam4-gpnvm%u: %u", x, v); } return r; } - if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) { - r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v); + if ((who >= 0) && (((unsigned)(who)) < chip->details.n_gpnvms)) { + r = flashd_get_gpnvm(&(chip->details.bank[0]), who, &v); if (r == ERROR_OK) command_print(CMD, "sam4-gpnvm%u: %u", who, v); return r; @@ -3143,11 +3168,11 @@ showall: return ERROR_COMMAND_SYNTAX_ERROR; } - if (0 == strcmp("set", CMD_ARGV[0])) - r = FLASHD_SetGPNVM(&(pChip->details.bank[0]), who); - else if ((0 == strcmp("clr", CMD_ARGV[0])) || - (0 == strcmp("clear", CMD_ARGV[0]))) /* quietly accept both */ - r = FLASHD_ClrGPNVM(&(pChip->details.bank[0]), who); + if (strcmp("set", CMD_ARGV[0]) == 0) + r = flashd_set_gpnvm(&(chip->details.bank[0]), who); + else if ((strcmp("clr", CMD_ARGV[0]) == 0) || + (strcmp("clear", CMD_ARGV[0]) == 0)) /* quietly accept both */ + r = flashd_clr_gpnvm(&(chip->details.bank[0]), who); else { command_print(CMD, "Unknown command: %s", CMD_ARGV[0]); r = ERROR_COMMAND_SYNTAX_ERROR; @@ -3157,10 +3182,10 @@ showall: COMMAND_HANDLER(sam4_handle_slowclk_command) { - struct sam4_chip *pChip; + struct sam4_chip *chip; - pChip = get_current_sam4(CMD); - if (!pChip) + chip = get_current_sam4(CMD); + if (!chip) return ERROR_OK; switch (CMD_ARGC) { @@ -3177,7 +3202,7 @@ COMMAND_HANDLER(sam4_handle_slowclk_command) command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); return ERROR_COMMAND_SYNTAX_ERROR; } - pChip->cfg.slow_freq = v; + chip->cfg.slow_freq = v; break; } default: @@ -3186,8 +3211,8 @@ COMMAND_HANDLER(sam4_handle_slowclk_command) return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "Slowclk freq: %d.%03dkhz", - (int)(pChip->cfg.slow_freq / 1000), - (int)(pChip->cfg.slow_freq % 1000)); + (int)(chip->cfg.slow_freq / 1000), + (int)(chip->cfg.slow_freq % 1000)); return ERROR_OK; } diff --git a/src/flash/nor/at91sam4l.c b/src/flash/nor/at91sam4l.c index d09414cbe7..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 @@ -22,6 +11,7 @@ #include "imp.h" +#include <jtag/jtag.h> #include <target/cortex_m.h> /* At this time, the SAM4L Flash is available in these capacities: @@ -480,9 +470,6 @@ static int sam4l_erase(struct flash_bank *bank, unsigned int first, return ERROR_FAIL; } } - - /* This sector is definitely erased. */ - bank->sectors[i].is_erased = 1; } } diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c index 3d8fee1afe..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/>. * ****************************************************************************/ /*************************************************************************** @@ -104,11 +93,11 @@ static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode); static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout); static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen); -static const uint32_t MC_FMR[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 }; -static const uint32_t MC_FCR[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 }; -static const uint32_t MC_FSR[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 }; +static const uint32_t mc_fmr[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 }; +static const uint32_t mc_fcr[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 }; +static const uint32_t mc_fsr[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 }; -static const char *EPROC[8] = { +static const char *eproc[8] = { "Unknown", "ARM946-E", "ARM7TDMI", "Unknown", "ARM920T", "ARM926EJ-S", "Unknown", "Unknown" }; @@ -179,7 +168,7 @@ static long SRAMSIZ[16] = { static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number) { uint32_t fsr; - target_read_u32(target, MC_FSR[bank_number], &fsr); + target_read_u32(target, mc_fsr[bank_number], &fsr); return fsr; } @@ -290,7 +279,7 @@ static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode) LOG_DEBUG("fmcn[%i]: %i", bank->bank_number, (int)(fmcn)); fmr = fmcn << 16 | fws << 8; - target_write_u32(target, MC_FMR[bank->bank_number], fmr); + target_write_u32(target, mc_fmr[bank->bank_number], fmr); } at91sam7_info->flashmode = mode; @@ -329,7 +318,7 @@ static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t struct target *target = bank->target; fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd; - target_write_u32(target, MC_FCR[bank->bank_number], fcr); + target_write_u32(target, mc_fcr[bank->bank_number], fcr); LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %i, page number: %u", fcr, bank->bank_number + 1, @@ -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 */ @@ -978,56 +978,39 @@ static int at91sam7_probe(struct flash_bank *bank) return ERROR_OK; } -static int get_at91sam7_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_at91sam7_info(struct flash_bank *bank, struct command_invocation *cmd) { - int printed; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; if (at91sam7_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; - printed = snprintf(buf, buf_size, - "\n at91sam7 driver information: Chip is %s\n", + command_print_sameline(cmd, "\n at91sam7 driver information: Chip is %s\n", at91sam7_info->target_name); - buf += printed; - buf_size -= printed; - - printed = snprintf(buf, - buf_size, + command_print_sameline(cmd, " Cidr: 0x%8.8" PRIx32 " | Arch: 0x%4.4x | Eproc: %s | Version: 0x%3.3x | " "Flashsize: 0x%8.8" PRIx32 "\n", at91sam7_info->cidr, at91sam7_info->cidr_arch, - EPROC[at91sam7_info->cidr_eproc], + eproc[at91sam7_info->cidr_eproc], at91sam7_info->cidr_version, bank->size); - buf += printed; - buf_size -= printed; - - printed = snprintf(buf, buf_size, - " Master clock (estimated): %u KHz | External clock: %u KHz\n", + command_print_sameline(cmd, + " Master clock (estimated): %u kHz | External clock: %u kHz\n", (unsigned)(at91sam7_info->mck_freq / 1000), (unsigned)(at91sam7_info->ext_freq / 1000)); - buf += printed; - buf_size -= printed; - - printed = snprintf(buf, - buf_size, + command_print_sameline(cmd, " Pagesize: %i bytes | Lockbits(%u): %i 0x%4.4x | Pages in lock region: %i\n", at91sam7_info->pagesize, bank->num_sectors, at91sam7_info->num_lockbits_on, at91sam7_info->lockbits, - at91sam7_info->pages_per_sector*at91sam7_info->num_lockbits_on); - - buf += printed; - buf_size -= printed; + at91sam7_info->pages_per_sector * at91sam7_info->num_lockbits_on); - snprintf(buf, buf_size, - " Securitybit: %i | Nvmbits(%i): %i 0x%1.1x\n", + command_print_sameline(cmd, " Securitybit: %i | Nvmbits(%i): %i 0x%1.1x\n", at91sam7_info->securitybit, at91sam7_info->num_nvmbits, at91sam7_info->num_nvmbits_on, at91sam7_info->nvmbits); @@ -1057,7 +1040,7 @@ COMMAND_HANDLER(at91sam7_handle_gpnvm_command) return ERROR_COMMAND_SYNTAX_ERROR; bank = get_flash_bank_by_num_noprobe(0); - if (bank == NULL) + if (!bank) return ERROR_FLASH_BANK_INVALID; if (strcmp(bank->driver->name, "at91sam7")) { command_print(CMD, "not an at91sam7 flash bank '%s'", CMD_ARGV[0]); diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 5fbf8bcaa8..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,8 @@ #include "imp.h" #include "helper/binarybuffer.h" +#include <helper/time_support.h> +#include <jtag/jtag.h> #include <target/cortex_m.h> #define SAMD_NUM_PROT_BLOCKS 16 @@ -41,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 */ @@ -65,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 @@ -84,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; @@ -249,7 +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 }, + { 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. */ @@ -317,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 { @@ -385,7 +384,7 @@ static const struct samd_part *samd_find_part(uint32_t id) { uint8_t devsel = SAMD_GET_DEVSEL(id); const struct samd_family *family = samd_find_family(id); - if (family == NULL) + if (!family) return NULL; for (unsigned i = 0; i < family->num_parts; i++) { @@ -452,7 +451,7 @@ static int samd_probe(struct flash_bank *bank) } part = samd_find_part(id); - if (part == NULL) { + if (!part) { LOG_ERROR("Couldn't find part corresponding to DID %08" PRIx32, id); return ERROR_FAIL; } @@ -506,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); @@ -552,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; @@ -606,7 +626,7 @@ static int samd_get_reservedmask(struct target *target, uint64_t *mask) } const struct samd_family *family; family = samd_find_family(id); - if (family == NULL) { + if (!family) { LOG_ERROR("Couldn't determine device family"); return ERROR_FAIL; } @@ -944,11 +964,6 @@ FLASH_BANK_COMMAND_HANDLER(samd_flash_bank_command) return ERROR_OK; } -COMMAND_HANDLER(samd_handle_info_command) -{ - return ERROR_OK; -} - COMMAND_HANDLER(samd_handle_chip_erase_command) { struct target *target = get_current_target(CMD_CTX); @@ -1051,31 +1066,6 @@ COMMAND_HANDLER(samd_handle_eeprom_command) return res; } -static COMMAND_HELPER(get_u64_from_hexarg, unsigned int num, uint64_t *value) -{ - if (num >= CMD_ARGC) { - command_print(CMD, "Too few Arguments."); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - if (strlen(CMD_ARGV[num]) >= 3 && - CMD_ARGV[num][0] == '0' && - CMD_ARGV[num][1] == 'x') { - char *check = NULL; - *value = strtoull(&(CMD_ARGV[num][2]), &check, 16); - if ((value == 0 && errno == ERANGE) || - check == NULL || *check != 0) { - command_print(CMD, "Invalid 64-bit hex value in argument %d.", - num + 1); - return ERROR_COMMAND_SYNTAX_ERROR; - } - } else { - command_print(CMD, "Argument %d needs to be a hex value.", num + 1); - return ERROR_COMMAND_SYNTAX_ERROR; - } - return ERROR_OK; -} - COMMAND_HANDLER(samd_handle_nvmuserrow_command) { int res = ERROR_OK; @@ -1102,14 +1092,12 @@ COMMAND_HANDLER(samd_handle_nvmuserrow_command) mask &= NVMUSERROW_LOCKBIT_MASK; uint64_t value; - res = CALL_COMMAND_HANDLER(get_u64_from_hexarg, 0, &value); - if (res != ERROR_OK) - return res; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], value); + if (CMD_ARGC == 2) { uint64_t mask_temp; - res = CALL_COMMAND_HANDLER(get_u64_from_hexarg, 1, &mask_temp); - if (res != ERROR_OK) - return res; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], mask_temp); + mask &= mask_temp; } res = samd_modify_user_row_masked(target, value, mask); @@ -1236,14 +1224,6 @@ static const struct command_registration at91samd_exec_command_handlers[] = { .help = "Deassert internal reset held by DSU.", .usage = "", }, - { - .name = "info", - .handler = samd_handle_info_command, - .mode = COMMAND_EXEC, - .help = "Print information about the current at91samd chip " - "and its flash configuration.", - .usage = "", - }, { .name = "chip-erase", .handler = samd_handle_chip_erase_command, diff --git a/src/flash/nor/ath79.c b/src/flash/nor/ath79.c index 9a4595f6d1..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. @@ -875,17 +863,16 @@ static int ath79_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int get_ath79_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_ath79_info(struct flash_bank *bank, struct command_invocation *cmd) { struct ath79_flash_bank *ath79_info = bank->driver_priv; if (!ath79_info->probed) { - snprintf(buf, buf_size, - "\nATH79 flash bank not probed yet\n"); + command_print_sameline(cmd, "\nATH79 flash bank not probed yet\n"); return ERROR_OK; } - snprintf(buf, buf_size, "\nATH79 flash information:\n" + command_print_sameline(cmd, "\nATH79 flash information:\n" " Device \'%s\' (ID 0x%08" PRIx32 ")\n", ath79_info->dev->name, ath79_info->dev->device_id); diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c index ed0bef463b..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 @@ -28,6 +17,7 @@ #include "helper/binarybuffer.h" #include <helper/time_support.h> +#include <jtag/jtag.h> #include <target/cortex_m.h> /* A note to prefixing. @@ -103,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; @@ -113,7 +103,7 @@ struct samd_part { }; /* See SAM D5x/E5x Family Silicon Errata and Data Sheet Clarification - * DS80000748B */ + * DS80000748K */ /* Known SAMD51 parts. */ static const struct samd_part samd51_parts[] = { { 0x00, "SAMD51P20A", 1024, 256 }, @@ -134,6 +124,8 @@ static const struct samd_part same51_parts[] = { { 0x02, "SAME51J19A", 512, 192 }, { 0x03, "SAME51J18A", 256, 128 }, { 0x04, "SAME51J20A", 1024, 256 }, + { 0x05, "SAME51G19A", 512, 192 }, /* New in rev D */ + { 0x06, "SAME51G18A", 256, 128 }, /* New in rev D */ }; /* Known SAME53 parts. */ @@ -143,6 +135,9 @@ static const struct samd_part same53_parts[] = { { 0x04, "SAME53J20A", 1024, 256 }, { 0x05, "SAME53J19A", 512, 192 }, { 0x06, "SAME53J18A", 256, 128 }, + { 0x55, "LAN9255/ZMX020", 1024, 256 }, + { 0x56, "LAN9255/ZMX019", 512, 192 }, + { 0x57, "LAN9255/ZMX018", 256, 128 }, }; /* Known SAME54 parts. */ @@ -218,7 +213,7 @@ static const struct samd_part *samd_find_part(uint32_t id) { uint8_t devsel = SAMD_GET_DEVSEL(id); const struct samd_family *family = samd_find_family(id); - if (family == NULL) + if (!family) return NULL; for (unsigned i = 0; i < family->num_parts; i++) { @@ -285,7 +280,7 @@ static int same5_probe(struct flash_bank *bank) } part = samd_find_part(id); - if (part == NULL) { + if (!part) { LOG_ERROR("Couldn't find part corresponding to DID %08" PRIx32, id); return ERROR_FAIL; } @@ -795,11 +790,12 @@ COMMAND_HANDLER(same5_handle_userpage_command) } if (CMD_ARGC >= 1) { - uint64_t mask = NVMUSERROW_SAM_E5_D5_MASK; - uint64_t value = strtoull(CMD_ARGV[0], NULL, 0); + uint64_t value, mask = NVMUSERROW_SAM_E5_D5_MASK; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], value); if (CMD_ARGC == 2) { - uint64_t mask_temp = strtoull(CMD_ARGV[1], NULL, 0); + uint64_t mask_temp; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], mask_temp); mask &= mask_temp; } @@ -835,7 +831,9 @@ COMMAND_HANDLER(same5_handle_bootloader_command) return ERROR_FAIL; if (CMD_ARGC >= 1) { - unsigned long size = strtoul(CMD_ARGV[0], NULL, 0); + unsigned long size; + + COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[0], size); uint32_t code = (size + 8191) / 8192; if (code > 15) { command_print(CMD, "Invalid bootloader size. Please " diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index af48398e09..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; @@ -607,15 +564,15 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_OK; } -static int samv_get_info(struct flash_bank *bank, char *buf, int buf_size) +static int samv_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct samv_flash_bank *samv_info = bank->driver_priv; if (!samv_info->probed) { int r = samv_probe(bank); - if (ERROR_OK != r) + if (r != ERROR_OK) return r; } - snprintf(buf, buf_size, "Cortex-M7 detected with %" PRIu32 " kB flash", + command_print_sameline(cmd, "Cortex-M7 detected with %" PRIu32 " kB flash\n", bank->size / 1024); return ERROR_OK; } @@ -661,7 +618,7 @@ COMMAND_HANDLER(samv_handle_gpnvm_command) return ERROR_COMMAND_SYNTAX_ERROR; } - unsigned v; + unsigned v = 0; if (!strcmp("show", CMD_ARGV[0])) { if (who == -1) { showall: @@ -676,6 +633,9 @@ showall: } if ((who >= 0) && (((unsigned)who) < SAMV_NUM_GPNVM_BITS)) { r = samv_get_gpnvm(target, who, &v); + if (r != ERROR_OK) + return r; + command_print(CMD, "samv-gpnvm%u: %u", who, v); return r; } else { diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c index dd3d077a09..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 @@ -38,14 +27,14 @@ #define AVR_JTAG_INS_PROG_PAGEREAD 0x07 /* Data Registers: */ -#define AVR_JTAG_REG_Bypass_Len 1 -#define AVR_JTAG_REG_DeviceID_Len 32 +#define AVR_JTAG_REG_BYPASS_LEN 1 +#define AVR_JTAG_REG_DEVICEID_LEN 32 -#define AVR_JTAG_REG_Reset_Len 1 -#define AVR_JTAG_REG_JTAGID_Len 32 -#define AVR_JTAG_REG_ProgrammingEnable_Len 16 -#define AVR_JTAG_REG_ProgrammingCommand_Len 15 -#define AVR_JTAG_REG_FlashDataByte_Len 16 +#define AVR_JTAG_REG_RESET_LEN 1 +#define AVR_JTAG_REG_JTAGID_LEN 32 +#define AVR_JTAG_REG_PROGRAMMING_ENABLE_LEN 16 +#define AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN 15 +#define AVR_JTAG_REG_FLASH_DATA_BYTE_LEN 16 struct avrf_type { char name[15]; @@ -75,13 +64,14 @@ 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 */ static int avr_jtag_reset(struct avr_common *avr, uint32_t reset) { avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_AVR_RESET); - avr_jtag_senddat(avr->jtag_info.tap, NULL, reset, AVR_JTAG_REG_Reset_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, reset, AVR_JTAG_REG_RESET_LEN); return ERROR_OK; } @@ -89,7 +79,7 @@ static int avr_jtag_reset(struct avr_common *avr, uint32_t reset) static int avr_jtag_read_jtagid(struct avr_common *avr, uint32_t *id) { avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_IDCODE); - avr_jtag_senddat(avr->jtag_info.tap, id, 0, AVR_JTAG_REG_JTAGID_Len); + avr_jtag_senddat(avr->jtag_info.tap, id, 0, AVR_JTAG_REG_JTAGID_LEN); return ERROR_OK; } @@ -99,7 +89,7 @@ static int avr_jtagprg_enterprogmode(struct avr_common *avr) avr_jtag_reset(avr, 1); avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xA370, AVR_JTAG_REG_ProgrammingEnable_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xA370, AVR_JTAG_REG_PROGRAMMING_ENABLE_LEN); return ERROR_OK; } @@ -107,11 +97,11 @@ static int avr_jtagprg_enterprogmode(struct avr_common *avr) static int avr_jtagprg_leaveprogmode(struct avr_common *avr) { avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2300, AVR_JTAG_REG_ProgrammingCommand_Len); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3300, AVR_JTAG_REG_ProgrammingCommand_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2300, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3300, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0, AVR_JTAG_REG_ProgrammingEnable_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0, AVR_JTAG_REG_PROGRAMMING_ENABLE_LEN); avr_jtag_reset(avr, 0); @@ -123,18 +113,18 @@ static int avr_jtagprg_chiperase(struct avr_common *avr) uint32_t poll_value; avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2380, AVR_JTAG_REG_ProgrammingCommand_Len); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3180, AVR_JTAG_REG_ProgrammingCommand_Len); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2380, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3180, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); do { poll_value = 0; avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3380, - AVR_JTAG_REG_ProgrammingCommand_Len); - if (ERROR_OK != mcu_execute_queue()) + AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); + if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value); } while (!(poll_value & 0x0200)); @@ -152,26 +142,26 @@ static int avr_jtagprg_writeflashpage(struct avr_common *avr, uint32_t poll_value; avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); /* load extended high byte */ if (ext_addressing) avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0b00 | ((addr >> 17) & 0xFF), - AVR_JTAG_REG_ProgrammingCommand_Len); + AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); /* load addr high byte */ avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0700 | ((addr >> 9) & 0xFF), - AVR_JTAG_REG_ProgrammingCommand_Len); + AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); /* load addr low byte */ avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0300 | ((addr >> 1) & 0xFF), - AVR_JTAG_REG_ProgrammingCommand_Len); + AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD); @@ -184,18 +174,18 @@ static int avr_jtagprg_writeflashpage(struct avr_common *avr, avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3500, AVR_JTAG_REG_ProgrammingCommand_Len); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len); - avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3500, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); do { poll_value = 0; avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3700, - AVR_JTAG_REG_ProgrammingCommand_Len); - if (ERROR_OK != mcu_execute_queue()) + AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); + if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value); } while (!(poll_value & 0x0200)); @@ -266,7 +256,7 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o LOG_DEBUG("offset is 0x%08" PRIx32 "", offset); LOG_DEBUG("count is %" PRIu32 "", count); - if (ERROR_OK != avr_jtagprg_enterprogmode(avr)) + if (avr_jtagprg_enterprogmode(avr) != ERROR_OK) return ERROR_FAIL; if (bank->size > 0x20000) @@ -315,7 +305,7 @@ static int avrf_probe(struct flash_bank *bank) avrf_info->probed = false; avr_jtag_read_jtagid(avr, &device_id); - if (ERROR_OK != mcu_execute_queue()) + if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; LOG_INFO("device id = 0x%08" PRIx32 "", device_id); @@ -332,7 +322,7 @@ static int avrf_probe(struct flash_bank *bank) } } - if (avr_info != NULL) { + if (avr_info) { free(bank->sectors); /* chip found */ @@ -367,7 +357,7 @@ static int avrf_auto_probe(struct flash_bank *bank) return avrf_probe(bank); } -static int avrf_info(struct flash_bank *bank, char *buf, int buf_size) +static int avrf_info(struct flash_bank *bank, struct command_invocation *cmd) { struct target *target = bank->target; struct avr_common *avr = target->arch_info; @@ -380,7 +370,7 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size) } avr_jtag_read_jtagid(avr, &device_id); - if (ERROR_OK != mcu_execute_queue()) + if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; LOG_INFO("device id = 0x%08" PRIx32 "", device_id); @@ -398,14 +388,14 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size) } } - if (avr_info != NULL) { + if (avr_info) { /* chip found */ - snprintf(buf, buf_size, "%s - Rev: 0x%" PRIx32 "", avr_info->name, + command_print_sameline(cmd, "%s - Rev: 0x%" PRIx32 "", avr_info->name, EXTRACT_VER(device_id)); return ERROR_OK; } else { /* chip not supported */ - snprintf(buf, buf_size, "Cannot identify target as a avr\n"); + command_print_sameline(cmd, "Cannot identify target as a avr\n"); return ERROR_FLASH_OPERATION_FAILED; } } @@ -420,9 +410,9 @@ static int avrf_mass_erase(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } - if ((ERROR_OK != avr_jtagprg_enterprogmode(avr)) - || (ERROR_OK != avr_jtagprg_chiperase(avr)) - || (ERROR_OK != avr_jtagprg_leaveprogmode(avr))) + if ((avr_jtagprg_enterprogmode(avr) != ERROR_OK) + || (avr_jtagprg_chiperase(avr) != ERROR_OK) + || (avr_jtagprg_leaveprogmode(avr) != ERROR_OK)) return ERROR_FAIL; return ERROR_OK; @@ -435,16 +425,12 @@ COMMAND_HANDLER(avrf_handle_mass_erase_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; - if (avrf_mass_erase(bank) == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - + if (avrf_mass_erase(bank) == ERROR_OK) command_print(CMD, "avr mass erase complete"); - } else + else command_print(CMD, "avr mass erase failed"); LOG_DEBUG("%s", __func__); diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index 57ea7396f0..9ced2e9718 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -1,25 +1,16 @@ +// 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 #include "config.h" #endif +#include <helper/binarybuffer.h> +#include "helper/types.h" #include <target/algorithm.h> #include <target/armv7m.h> #include <target/cortex_m.h> @@ -33,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; @@ -43,7 +36,7 @@ struct flash_ctrl_priv_data { char *part_name; }; -const struct flash_ctrl_priv_data flash_priv_data_1 = { +static const struct flash_ctrl_priv_data flash_priv_data_1 = { .die_id_reg = 0x4090001C, .jtag_idcode_reg = 0x40900028, .flash_base = 0x10040000, @@ -53,7 +46,7 @@ const struct flash_ctrl_priv_data flash_priv_data_1 = { .part_name = "BLUENRG-1", }; -const struct flash_ctrl_priv_data flash_priv_data_2 = { +static const struct flash_ctrl_priv_data flash_priv_data_2 = { .die_id_reg = 0x4090001C, .jtag_idcode_reg = 0x40900028, .flash_base = 0x10040000, @@ -63,7 +56,7 @@ const struct flash_ctrl_priv_data flash_priv_data_2 = { .part_name = "BLUENRG-2", }; -const struct flash_ctrl_priv_data flash_priv_data_lp = { +static const struct flash_ctrl_priv_data flash_priv_data_lp = { .die_id_reg = 0x40000000, .jtag_idcode_reg = 0x40000004, .flash_base = 0x10040000, @@ -73,13 +66,27 @@ 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; const struct flash_ctrl_priv_data *flash_ptr; }; -const struct flash_ctrl_priv_data *flash_ctrl[] = {&flash_priv_data_1, &flash_priv_data_2, &flash_priv_data_lp}; +static const struct flash_ctrl_priv_data *flash_ctrl[] = { + &flash_priv_data_1, + &flash_priv_data_2, + &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) @@ -89,7 +96,7 @@ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) bluenrgx_info = calloc(1, sizeof(*bluenrgx_info)); /* Check allocation */ - if (bluenrgx_info == NULL) { + if (!bluenrgx_info) { LOG_ERROR("failed to allocate bank structure"); return ERROR_FAIL; } @@ -229,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]; @@ -278,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; } @@ -293,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); @@ -304,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); @@ -350,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]); @@ -371,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; @@ -389,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; @@ -424,7 +441,7 @@ static int bluenrgx_auto_probe(struct flash_bank *bank) } /* This method must return a string displaying information about the bank */ -static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size) +static int bluenrgx_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; int mask_number, cut_number; @@ -432,8 +449,7 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size) if (!bluenrgx_info->probed) { int retval = bluenrgx_probe(bank); if (retval != ERROR_OK) { - snprintf(buf, buf_size, - "Unable to find bank information."); + command_print_sameline(cmd, "Unable to find bank information."); return retval; } } @@ -441,8 +457,8 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size) mask_number = (bluenrgx_info->die_id >> 4) & 0xF; cut_number = bluenrgx_info->die_id & 0xF; - snprintf(buf, buf_size, - "%s - Rev: %d.%d", bluenrgx_info->flash_ptr->part_name, mask_number, cut_number); + command_print_sameline(cmd, "%s - Rev: %d.%d", + bluenrgx_info->flash_ptr->part_name, mask_number, cut_number); return ERROR_OK; } 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 5565aeb41f..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) @@ -107,9 +106,9 @@ static int cc26xx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) int retval = ERROR_OK; start_ms = timeval_ms(); - while (CC26XX_BUFFER_FULL == status) { + while (status == CC26XX_BUFFER_FULL) { retval = target_read_u32(target, status_addr, &status); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; elapsed_ms = timeval_ms() - start_ms; @@ -119,7 +118,7 @@ static int cc26xx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) break; }; - if (CC26XX_BUFFER_EMPTY != status) { + if (status != CC26XX_BUFFER_EMPTY) { LOG_ERROR("%s: Flash operation failed", cc26xx_bank->family_name); return ERROR_FAIL; } @@ -136,28 +135,30 @@ static int cc26xx_init(struct flash_bank *bank) /* Make sure we've probed the flash to get the device and size */ retval = cc26xx_auto_probe(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Check for working area to use for flash helper algorithm */ - if (NULL != cc26xx_bank->working_area) - target_free_working_area(target, cc26xx_bank->working_area); + target_free_working_area(target, cc26xx_bank->working_area); + cc26xx_bank->working_area = NULL; + retval = target_alloc_working_area(target, cc26xx_bank->algo_working_size, &cc26xx_bank->working_area); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Confirm the defined working address is the area we need to use */ - if (CC26XX_ALGO_BASE_ADDRESS != cc26xx_bank->working_area->address) + if (cc26xx_bank->working_area->address != CC26XX_ALGO_BASE_ADDRESS) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* Write flash helper algorithm into target memory */ retval = target_write_buffer(target, CC26XX_ALGO_BASE_ADDRESS, cc26xx_bank->algo_size, cc26xx_bank->algo_code); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("%s: Failed to load flash helper algorithm", cc26xx_bank->family_name); target_free_working_area(target, cc26xx_bank->working_area); + cc26xx_bank->working_area = NULL; return retval; } @@ -168,10 +169,11 @@ static int cc26xx_init(struct flash_bank *bank) /* Begin executing the flash helper algorithm */ retval = target_start_algorithm(target, 0, NULL, 0, NULL, CC26XX_ALGO_BASE_ADDRESS, 0, &cc26xx_bank->armv7m_info); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("%s: Failed to start flash helper algorithm", cc26xx_bank->family_name); target_free_working_area(target, cc26xx_bank->working_area); + cc26xx_bank->working_area = NULL; return retval; } @@ -211,13 +213,13 @@ static int cc26xx_mass_erase(struct flash_bank *bank) int retval; - if (TARGET_HALTED != target->state) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = cc26xx_init(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Initialize algorithm parameters */ @@ -231,7 +233,7 @@ static int cc26xx_mass_erase(struct flash_bank *bank) sizeof(algo_params), (uint8_t *)&algo_params); /* Wait for command to complete */ - if (ERROR_OK == retval) + if (retval == ERROR_OK) retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]); /* Regardless of errors, try to close down algo */ @@ -248,7 +250,7 @@ FLASH_BANK_COMMAND_HANDLER(cc26xx_flash_bank_command) return ERROR_COMMAND_SYNTAX_ERROR; cc26xx_bank = malloc(sizeof(struct cc26xx_bank)); - if (NULL == cc26xx_bank) + if (!cc26xx_bank) return ERROR_FAIL; /* Initialize private flash information */ @@ -259,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; } @@ -275,7 +276,7 @@ static int cc26xx_erase(struct flash_bank *bank, unsigned int first, uint32_t length; int retval; - if (TARGET_HALTED != target->state) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -290,7 +291,7 @@ static int cc26xx_erase(struct flash_bank *bank, unsigned int first, length = (last - first + 1) * cc26xx_bank->sector_length; retval = cc26xx_init(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Set up algorithm parameters for erase command */ @@ -304,7 +305,7 @@ static int cc26xx_erase(struct flash_bank *bank, unsigned int first, sizeof(algo_params), (uint8_t *)&algo_params); /* If no error, wait for erase to finish */ - if (ERROR_OK == retval) + if (retval == ERROR_OK) retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]); /* Regardless of errors, try to close down algo */ @@ -327,13 +328,13 @@ static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t index; int retval; - if (TARGET_HALTED != target->state) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = cc26xx_init(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Initialize algorithm parameters to default values */ @@ -354,7 +355,7 @@ static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, /* Put next block of data to flash into buffer */ retval = target_write_buffer(target, cc26xx_bank->buffer_addr[index], size, buffer); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to target memory"); break; } @@ -367,13 +368,13 @@ static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, /* Issue flash helper algorithm parameters for block write */ retval = target_write_buffer(target, cc26xx_bank->params_addr[index], sizeof(algo_params[index]), (uint8_t *)&algo_params[index]); - if (ERROR_OK != retval) + if (retval != ERROR_OK) break; /* Wait for next ping pong buffer to be ready */ index ^= 1; retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]); - if (ERROR_OK != retval) + if (retval != ERROR_OK) break; count -= size; @@ -386,7 +387,7 @@ static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, } /* If no error yet, wait for last buffer to finish */ - if (ERROR_OK == retval) { + if (retval == ERROR_OK) { index ^= 1; retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]); } @@ -410,12 +411,12 @@ static int cc26xx_probe(struct flash_bank *bank) int retval; retval = target_read_u32(target, FCFG1_ICEPICK_ID, &value); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; cc26xx_bank->icepick_id = value; retval = target_read_u32(target, FCFG1_USER_ID, &value); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; cc26xx_bank->user_id = value; @@ -454,14 +455,14 @@ static int cc26xx_probe(struct flash_bank *bank) } retval = target_read_u32(target, CC26XX_FLASH_SIZE_INFO, &value); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; num_sectors = value & 0xff; if (num_sectors > max_sectors) num_sectors = max_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); - if (NULL == bank->sectors) + if (!bank->sectors) return ERROR_FAIL; bank->base = CC26XX_FLASH_BASE_ADDR; @@ -498,10 +499,9 @@ static int cc26xx_auto_probe(struct flash_bank *bank) return retval; } -static int cc26xx_info(struct flash_bank *bank, char *buf, int buf_size) +static int cc26xx_info(struct flash_bank *bank, struct command_invocation *cmd) { struct cc26xx_bank *cc26xx_bank = bank->driver_priv; - int printed = 0; const char *device; switch (cc26xx_bank->device_type) { @@ -526,13 +526,10 @@ static int cc26xx_info(struct flash_bank *bank, char *buf, int buf_size) break; } - printed = snprintf(buf, buf_size, + command_print_sameline(cmd, "%s device: ICEPick ID 0x%08" PRIx32 ", USER ID 0x%08" PRIx32 "\n", device, cc26xx_bank->icepick_id, cc26xx_bank->user_id); - if (printed >= buf_size) - return ERROR_BUF_TOO_SMALL; - 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 5427bd3a9b..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 @@ -21,6 +10,7 @@ #include "imp.h" #include "cc3220sf.h" +#include <helper/binarybuffer.h> #include <helper/time_support.h> #include <target/algorithm.h> #include <target/armv7m.h> @@ -32,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; @@ -42,19 +37,19 @@ static int cc3220sf_mass_erase(struct flash_bank *bank) int retval = ERROR_OK; - if (TARGET_HALTED != target->state) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Set starting address to erase to zero */ retval = target_write_u32(target, FMA_REGISTER_ADDR, 0); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Write the MERASE bit of the FMC register */ retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_MERASE_VALUE); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Poll the MERASE bit until the mass erase is complete */ @@ -62,7 +57,7 @@ static int cc3220sf_mass_erase(struct flash_bank *bank) start_ms = timeval_ms(); while (!done) { retval = target_read_u32(target, FMC_REGISTER_ADDR, &value); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if ((value & FMC_MERASE_BIT) == 0) { @@ -93,7 +88,7 @@ FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command) return ERROR_COMMAND_SYNTAX_ERROR; cc3220sf_bank = malloc(sizeof(struct cc3220sf_bank)); - if (NULL == cc3220sf_bank) + if (!cc3220sf_bank) return ERROR_FAIL; /* Initialize private flash information */ @@ -101,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; } @@ -118,7 +112,7 @@ static int cc3220sf_erase(struct flash_bank *bank, unsigned int first, int retval = ERROR_OK; - if (TARGET_HALTED != target->state) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -137,12 +131,12 @@ static int cc3220sf_erase(struct flash_bank *bank, unsigned int first, /* Set starting address to erase */ retval = target_write_u32(target, FMA_REGISTER_ADDR, address); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Write the ERASE bit of the FMC register */ retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_ERASE_VALUE); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Poll the ERASE bit until the erase is complete */ @@ -150,7 +144,7 @@ static int cc3220sf_erase(struct flash_bank *bank, unsigned int first, start_ms = timeval_ms(); while (!done) { retval = target_read_u32(target, FMC_REGISTER_ADDR, &value); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if ((value & FMC_ERASE_BIT) == 0) { @@ -192,7 +186,7 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, int retval = ERROR_OK; - if (TARGET_HALTED != target->state) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -200,13 +194,13 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, /* Obtain working area to use for flash helper algorithm */ retval = target_alloc_working_area(target, sizeof(cc3220sf_algo), &algo_working_area); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Obtain working area to use for flash buffer */ retval = target_alloc_working_area(target, target_get_working_area_avail(target), &buffer_working_area); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { target_free_working_area(target, algo_working_area); return retval; } @@ -223,7 +217,7 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, /* Write flash helper algorithm into target memory */ retval = target_write_buffer(target, algo_base_address, sizeof(cc3220sf_algo), cc3220sf_algo); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { target_free_working_area(target, algo_working_area); target_free_working_area(target, buffer_working_area); return retval; @@ -262,7 +256,7 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, /* Retrieve what is already in flash at the head address */ retval = target_read_buffer(target, head_address, sizeof(head), head); - if (ERROR_OK == retval) { + if (retval == ERROR_OK) { /* Substitute in the new data to write */ while ((remaining > 0) && (head_offset < 4)) { head[head_offset] = *buffer; @@ -273,7 +267,7 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, } } - if (ERROR_OK == retval) { + if (retval == ERROR_OK) { /* Helper parameters are passed in registers R0-R2 */ /* Set start of data buffer, address to write to, and word count */ buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address); @@ -285,17 +279,17 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, sizeof(head), head); } - if (ERROR_OK == retval) { + if (retval == ERROR_OK) { /* Execute the flash helper algorithm */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, algo_base_address, 0, FLASH_TIMEOUT, &cc3220sf_bank->armv7m_info); - if (ERROR_OK != retval) + if (retval != ERROR_OK) LOG_ERROR("cc3220sf: Flash algorithm failed to run"); /* Check that the head value was written to flash */ result = buf_get_u32(reg_params[2].value, 0, 32); - if (0 != result) { + if (result != 0) { retval = ERROR_FAIL; LOG_ERROR("cc3220sf: Flash operation failed"); } @@ -307,7 +301,7 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, /* Adjust remaining so it is a multiple of whole words */ remaining -= tail_count; - while ((ERROR_OK == retval) && (remaining > 0)) { + while ((retval == ERROR_OK) && (remaining > 0)) { /* Set start of data buffer and address to write to */ buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address); buf_set_u32(reg_params[1].value, 0, 32, address); @@ -317,7 +311,7 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, /* Fill up buffer with data to flash */ retval = target_write_buffer(target, algo_buffer_address, algo_buffer_size, buffer); - if (ERROR_OK != retval) + if (retval != ERROR_OK) break; /* Count to write is in 32-bit words */ @@ -331,7 +325,7 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, /* Fill buffer with what's left of the data */ retval = target_write_buffer(target, algo_buffer_address, remaining, buffer); - if (ERROR_OK != retval) + if (retval != ERROR_OK) break; /* Calculate the final word count to write */ @@ -352,14 +346,14 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, retval = target_run_algorithm(target, 0, NULL, 3, reg_params, algo_base_address, 0, FLASH_TIMEOUT, &cc3220sf_bank->armv7m_info); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("cc3220sf: Flash algorithm failed to run"); break; } /* Check that all words were written to flash */ result = buf_get_u32(reg_params[2].value, 0, 32); - if (0 != result) { + if (result != 0) { retval = ERROR_FAIL; LOG_ERROR("cc3220sf: Flash operation failed"); break; @@ -369,7 +363,7 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, } /* Do one word write for any final bytes less than a full word */ - if ((ERROR_OK == retval) && (0 != tail_count)) { + if ((retval == ERROR_OK) && (tail_count != 0)) { uint8_t tail[4]; /* Set starting byte offset for data to write */ @@ -378,7 +372,7 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, /* Retrieve what is already in flash at the tail address */ retval = target_read_buffer(target, address, sizeof(tail), tail); - if (ERROR_OK == retval) { + if (retval == ERROR_OK) { /* Substitute in the new data to write */ while (tail_count > 0) { tail[tail_offset] = *buffer; @@ -388,7 +382,7 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, } } - if (ERROR_OK == retval) { + if (retval == ERROR_OK) { /* Set start of data buffer, address to write to, and word count */ buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address); buf_set_u32(reg_params[1].value, 0, 32, address); @@ -399,17 +393,17 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, sizeof(tail), tail); } - if (ERROR_OK == retval) { + if (retval == ERROR_OK) { /* Execute the flash helper algorithm */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, algo_base_address, 0, FLASH_TIMEOUT, &cc3220sf_bank->armv7m_info); - if (ERROR_OK != retval) + if (retval != ERROR_OK) LOG_ERROR("cc3220sf: Flash algorithm failed to run"); /* Check that the tail was written to flash */ result = buf_get_u32(reg_params[2].value, 0, 32); - if (0 != result) { + if (result != 0) { retval = ERROR_FAIL; LOG_ERROR("cc3220sf: Flash operation failed"); } @@ -441,7 +435,7 @@ static int cc3220sf_probe(struct flash_bank *bank) free(bank->sectors); bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); - if (NULL == bank->sectors) + if (!bank->sectors) return ERROR_FAIL; bank->base = base; @@ -477,15 +471,9 @@ static int cc3220sf_auto_probe(struct flash_bank *bank) return retval; } -static int cc3220sf_info(struct flash_bank *bank, char *buf, int buf_size) +static int cc3220sf_info(struct flash_bank *bank, struct command_invocation *cmd) { - int printed; - - printed = snprintf(buf, buf_size, "CC3220SF with 1MB internal flash\n"); - - if (printed >= buf_size) - return ERROR_BUF_TOO_SMALL; - + command_print_sameline(cmd, "CC3220SF with 1MB internal flash\n"); 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 5f5071e696..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 @@ -426,7 +415,7 @@ static int cfi_read_intel_pri_ext(struct flash_bank *bank) free(cfi_info->pri_ext); pri_ext = malloc(sizeof(struct cfi_intel_pri_ext)); - if (pri_ext == NULL) { + if (!pri_ext) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -522,7 +511,7 @@ static int cfi_read_spansion_pri_ext(struct flash_bank *bank) free(cfi_info->pri_ext); pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext)); - if (pri_ext == NULL) { + if (!pri_ext) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -561,55 +550,55 @@ static int cfi_read_spansion_pri_ext(struct flash_bank *bank) LOG_DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); - retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5, &pri_ext->SiliconRevision); + retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5, &pri_ext->silicon_revision); if (retval != ERROR_OK) return retval; - retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6, &pri_ext->EraseSuspend); + retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6, &pri_ext->erase_suspend); if (retval != ERROR_OK) return retval; - retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7, &pri_ext->BlkProt); + retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7, &pri_ext->blk_prot); if (retval != ERROR_OK) return retval; - retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8, &pri_ext->TmpBlkUnprotect); + retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8, &pri_ext->tmp_blk_unprotected); if (retval != ERROR_OK) return retval; - retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9, &pri_ext->BlkProtUnprot); + retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9, &pri_ext->blk_prot_unprot); if (retval != ERROR_OK) return retval; - retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 10, &pri_ext->SimultaneousOps); + retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 10, &pri_ext->simultaneous_ops); if (retval != ERROR_OK) return retval; - retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 11, &pri_ext->BurstMode); + retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 11, &pri_ext->burst_mode); if (retval != ERROR_OK) return retval; - retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 12, &pri_ext->PageMode); + retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 12, &pri_ext->page_mode); if (retval != ERROR_OK) return retval; - retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 13, &pri_ext->VppMin); + retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 13, &pri_ext->vpp_min); if (retval != ERROR_OK) return retval; - retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 14, &pri_ext->VppMax); + retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 14, &pri_ext->vpp_max); if (retval != ERROR_OK) return retval; - retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 15, &pri_ext->TopBottom); + retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 15, &pri_ext->top_bottom); if (retval != ERROR_OK) return retval; LOG_DEBUG("Silicon Revision: 0x%x, Erase Suspend: 0x%x, Block protect: 0x%x", - pri_ext->SiliconRevision, pri_ext->EraseSuspend, pri_ext->BlkProt); + pri_ext->silicon_revision, pri_ext->erase_suspend, pri_ext->blk_prot); LOG_DEBUG("Temporary Unprotect: 0x%x, Block Protect Scheme: 0x%x, " - "Simultaneous Ops: 0x%x", pri_ext->TmpBlkUnprotect, - pri_ext->BlkProtUnprot, pri_ext->SimultaneousOps); + "Simultaneous Ops: 0x%x", pri_ext->tmp_blk_unprotected, + pri_ext->blk_prot_unprot, pri_ext->simultaneous_ops); - LOG_DEBUG("Burst Mode: 0x%x, Page Mode: 0x%x, ", pri_ext->BurstMode, pri_ext->PageMode); + LOG_DEBUG("Burst Mode: 0x%x, Page Mode: 0x%x, ", pri_ext->burst_mode, pri_ext->page_mode); LOG_DEBUG("Vpp min: %u.%x, Vpp max: %u.%x", - (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f, - (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f); + (pri_ext->vpp_min & 0xf0) >> 4, pri_ext->vpp_min & 0x0f, + (pri_ext->vpp_max & 0xf0) >> 4, pri_ext->vpp_max & 0x0f); - LOG_DEBUG("WP# protection 0x%x", pri_ext->TopBottom); + LOG_DEBUG("WP# protection 0x%x", pri_ext->top_bottom); return ERROR_OK; } @@ -624,7 +613,7 @@ static int cfi_read_atmel_pri_ext(struct flash_bank *bank) free(cfi_info->pri_ext); pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext)); - if (pri_ext == NULL) { + if (!pri_ext) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -696,20 +685,20 @@ static int cfi_read_atmel_pri_ext(struct flash_bank *bank) atmel_pri_ext.page_mode); if (atmel_pri_ext.features & 0x02) - pri_ext->EraseSuspend = 2; + pri_ext->erase_suspend = 2; /* some chips got it backwards... */ if (cfi_info->device_id == AT49BV6416 || cfi_info->device_id == AT49BV6416T) { if (atmel_pri_ext.bottom_boot) - pri_ext->TopBottom = 3; + pri_ext->top_bottom = 3; else - pri_ext->TopBottom = 2; + pri_ext->top_bottom = 2; } else { if (atmel_pri_ext.bottom_boot) - pri_ext->TopBottom = 2; + pri_ext->top_bottom = 2; else - pri_ext->TopBottom = 3; + pri_ext->top_bottom = 3; } pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1; @@ -728,79 +717,57 @@ static int cfi_read_0002_pri_ext(struct flash_bank *bank) return cfi_read_spansion_pri_ext(bank); } -static int cfi_spansion_info(struct flash_bank *bank, char *buf, int buf_size) +static int cfi_spansion_info(struct flash_bank *bank, struct command_invocation *cmd) { - int printed; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; - printed = snprintf(buf, buf_size, "\nSpansion primary algorithm extend information:\n"); - buf += printed; - buf_size -= printed; + command_print_sameline(cmd, "\nSpansion primary algorithm extend information:\n"); - printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], - pri_ext->pri[1], pri_ext->pri[2], + command_print_sameline(cmd, "pri: '%c%c%c', version: %c.%c\n", + pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); - buf += printed; - buf_size -= printed; - printed = snprintf(buf, buf_size, "Silicon Rev.: 0x%x, Address Sensitive unlock: 0x%x\n", - (pri_ext->SiliconRevision) >> 2, - (pri_ext->SiliconRevision) & 0x03); - buf += printed; - buf_size -= printed; + command_print_sameline(cmd, "Silicon Rev.: 0x%x, Address Sensitive unlock: 0x%x\n", + (pri_ext->silicon_revision) >> 2, + (pri_ext->silicon_revision) & 0x03); - printed = snprintf(buf, buf_size, "Erase Suspend: 0x%x, Sector Protect: 0x%x\n", - pri_ext->EraseSuspend, - pri_ext->BlkProt); - buf += printed; - buf_size -= printed; + command_print_sameline(cmd, "Erase Suspend: 0x%x, Sector Protect: 0x%x\n", + pri_ext->erase_suspend, + pri_ext->blk_prot); - snprintf(buf, buf_size, "VppMin: %u.%x, VppMax: %u.%x\n", - (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f, - (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f); + command_print_sameline(cmd, "VppMin: %u.%x, VppMax: %u.%x\n", + (pri_ext->vpp_min & 0xf0) >> 4, pri_ext->vpp_min & 0x0f, + (pri_ext->vpp_max & 0xf0) >> 4, pri_ext->vpp_max & 0x0f); return ERROR_OK; } -static int cfi_intel_info(struct flash_bank *bank, char *buf, int buf_size) +static int cfi_intel_info(struct flash_bank *bank, struct command_invocation *cmd) { - int printed; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext; - printed = snprintf(buf, buf_size, "\nintel primary algorithm extend information:\n"); - buf += printed; - buf_size -= printed; + command_print_sameline(cmd, "\nintel primary algorithm extend information:\n"); - printed = snprintf(buf, - buf_size, - "pri: '%c%c%c', version: %c.%c\n", + command_print_sameline(cmd, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); - buf += printed; - buf_size -= printed; - printed = snprintf(buf, - buf_size, - "feature_support: 0x%" PRIx32 ", " + command_print_sameline(cmd, "feature_support: 0x%" PRIx32 ", " "suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x\n", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask); - buf += printed; - buf_size -= printed; - printed = snprintf(buf, buf_size, "Vcc opt: %x.%x, Vpp opt: %u.%x\n", + command_print_sameline(cmd, "Vcc opt: %x.%x, Vpp opt: %u.%x\n", (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f, (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f); - buf += printed; - buf_size -= printed; - snprintf(buf, buf_size, "protection_fields: %i, prot_reg_addr: 0x%x, " + command_print_sameline(cmd, "protection_fields: %i, prot_reg_addr: 0x%x, " "factory pre-programmed: %i, user programmable: %i\n", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size); @@ -832,17 +799,13 @@ int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char ** return ERROR_FLASH_BANK_INVALID; } - cfi_info = malloc(sizeof(struct cfi_flash_bank)); - cfi_info->probed = false; - cfi_info->erase_region_info = NULL; - cfi_info->pri_ext = NULL; + cfi_info = calloc(1, sizeof(struct cfi_flash_bank)); + if (!cfi_info) { + LOG_ERROR("No memory for flash bank info"); + return ERROR_FAIL; + } bank->driver_priv = cfi_info; - cfi_info->x16_as_x8 = false; - cfi_info->jedec_probe = false; - cfi_info->not_cfi = false; - cfi_info->data_swap = false; - for (unsigned i = 6; i < argc; i++) { if (strcmp(argv[i], "x16_as_x8") == 0) cfi_info->x16_as_x8 = true; @@ -896,9 +859,7 @@ static int cfi_intel_erase(struct flash_bank *bank, unsigned int first, if (retval != ERROR_OK) return retval; - if (status == 0x80) - bank->sectors[i].is_erased = 1; - else { + if (status != 0x80) { retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -953,9 +914,7 @@ static int cfi_spansion_erase(struct flash_bank *bank, unsigned int first, if (retval != ERROR_OK) return retval; - if (cfi_spansion_wait_status_busy(bank, cfi_info->block_erase_timeout) == ERROR_OK) - bank->sectors[i].is_erased = 1; - else { + if (cfi_spansion_wait_status_busy(bank, cfi_info->block_erase_timeout) != ERROR_OK) { retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -1389,9 +1348,7 @@ static int cfi_intel_write_block(struct flash_bank *bank, const uint8_t *buffer, /* free up resources */ cleanup: - if (source) - target_free_working_area(target, source); - + target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); @@ -1514,7 +1471,7 @@ static int cfi_spansion_write_block_mips(struct flash_bank *bank, const uint8_t /* convert bus-width dependent algorithm code to correct endianness */ target_code = malloc(target_code_size); - if (target_code == NULL) { + if (!target_code) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -1893,7 +1850,7 @@ static int cfi_spansion_write_block(struct flash_bank *bank, const uint8_t *buff /* convert bus-width dependent algorithm code to correct endianness */ target_code = malloc(target_code_size); - if (target_code == NULL) { + if (!target_code) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -2506,7 +2463,7 @@ static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *pa struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; (void) param; - if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3)) { + if ((pri_ext->_reversed_geometry) || (pri_ext->top_bottom == 3)) { LOG_DEBUG("swapping reversed erase region information on cmdset 0002 device"); for (unsigned int i = 0; i < cfi_info->num_erase_regions / 2; i++) { @@ -2996,45 +2953,36 @@ int cfi_protect_check(struct flash_bank *bank) return ERROR_OK; } -int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size) +int cfi_get_info(struct flash_bank *bank, struct command_invocation *cmd) { - int printed; struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->qry[0] == 0xff) { - snprintf(buf, buf_size, "\ncfi flash bank not probed yet\n"); + command_print_sameline(cmd, "\ncfi flash bank not probed yet\n"); return ERROR_OK; } if (!cfi_info->not_cfi) - printed = snprintf(buf, buf_size, "\nCFI flash: "); + command_print_sameline(cmd, "\nCFI flash: "); else - printed = snprintf(buf, buf_size, "\nnon-CFI flash: "); - buf += printed; - buf_size -= printed; + command_print_sameline(cmd, "\nnon-CFI flash: "); - printed = snprintf(buf, buf_size, "mfr: 0x%4.4x, id:0x%4.4x\n\n", + command_print_sameline(cmd, "mfr: 0x%4.4x, id:0x%4.4x\n", cfi_info->manufacturer, cfi_info->device_id); - buf += printed; - buf_size -= printed; - printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: " + command_print_sameline(cmd, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: " "0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr); - buf += printed; - buf_size -= printed; - printed = snprintf(buf, buf_size, "Vcc min: %x.%x, Vcc max: %x.%x, " + command_print_sameline(cmd, "Vcc min: %x.%x, Vcc max: %x.%x, " "Vpp min: %u.%x, Vpp max: %u.%x\n", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f, (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f, (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f, (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f); - buf += printed; - buf_size -= printed; - printed = snprintf(buf, buf_size, "typ. word write timeout: %u us, " + command_print_sameline(cmd, "typ. word write timeout: %u us, " "typ. buf write timeout: %u us, " "typ. block erase timeout: %u ms, " "typ. chip erase timeout: %u ms\n", @@ -3042,12 +2990,8 @@ int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size) 1 << cfi_info->buf_write_timeout_typ, 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ); - buf += printed; - buf_size -= printed; - printed = snprintf(buf, - buf_size, - "max. word write timeout: %u us, " + command_print_sameline(cmd, "max. word write timeout: %u us, " "max. buf write timeout: %u us, max. " "block erase timeout: %u ms, max. chip erase timeout: %u ms\n", (1 << @@ -3060,24 +3004,20 @@ int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size) (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ)); - buf += printed; - buf_size -= printed; - printed = snprintf(buf, buf_size, "size: 0x%" PRIx32 ", interface desc: %i, " + command_print_sameline(cmd, "size: 0x%" PRIx32 ", interface desc: %i, " "max buffer write size: 0x%x\n", cfi_info->dev_size, cfi_info->interface_desc, 1 << cfi_info->max_buf_write_size); - buf += printed; - buf_size -= printed; switch (cfi_info->pri_id) { case 1: case 3: - cfi_intel_info(bank, buf, buf_size); + cfi_intel_info(bank, cmd); break; case 2: - cfi_spansion_info(bank, buf, buf_size); + cfi_spansion_info(bank, cmd); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); diff --git a/src/flash/nor/cfi.h b/src/flash/nor/cfi.h index eceb9a4b3c..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 @@ -108,17 +97,17 @@ struct cfi_spansion_pri_ext { uint8_t pri[3]; uint8_t major_version; uint8_t minor_version; - uint8_t SiliconRevision; /* bits 1-0: Address Sensitive Unlock */ - uint8_t EraseSuspend; - uint8_t BlkProt; - uint8_t TmpBlkUnprotect; - uint8_t BlkProtUnprot; - uint8_t SimultaneousOps; - uint8_t BurstMode; - uint8_t PageMode; - uint8_t VppMin; - uint8_t VppMax; - uint8_t TopBottom; + uint8_t silicon_revision; /* bits 1-0: Address Sensitive Unlock */ + uint8_t erase_suspend; + uint8_t blk_prot; + uint8_t tmp_blk_unprotected; + uint8_t blk_prot_unprot; + uint8_t simultaneous_ops; + uint8_t burst_mode; + uint8_t page_mode; + uint8_t vpp_min; + uint8_t vpp_max; + uint8_t top_bottom; int _reversed_geometry; uint32_t _unlock1; uint32_t _unlock2; @@ -160,7 +149,7 @@ int cfi_protect(struct flash_bank *bank, int set, unsigned int first, int cfi_probe(struct flash_bank *bank); int cfi_auto_probe(struct flash_bank *bank); int cfi_protect_check(struct flash_bank *bank); -int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size); +int cfi_get_info(struct flash_bank *bank, struct command_invocation *cmd); int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv); uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset); diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index d56301351b..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 @@ -70,7 +59,7 @@ int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first, /* force "set" to 0/1 */ set = !!set; - if (bank->driver->protect == NULL) { + if (!bank->driver->protect) { LOG_ERROR("Flash protection is not supported."); return ERROR_FLASH_OPER_UNSUPPORTED; } @@ -94,7 +83,7 @@ int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first, } int flash_driver_write(struct flash_bank *bank, - uint8_t *buffer, uint32_t offset, uint32_t count) + const uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; @@ -135,6 +124,43 @@ int default_flash_read(struct flash_bank *bank, return target_read_buffer(bank->target, offset + bank->base, count, buffer); } +int flash_driver_verify(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + int retval; + + retval = bank->driver->verify ? bank->driver->verify(bank, buffer, offset, count) : + default_flash_verify(bank, buffer, offset, count); + if (retval != ERROR_OK) { + LOG_ERROR("verify failed in bank at " TARGET_ADDR_FMT " starting at 0x%8.8" PRIx32, + bank->base, offset); + } + + return retval; +} + +int default_flash_verify(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + uint32_t target_crc, image_crc; + int retval; + + retval = image_calculate_checksum(buffer, count, &image_crc); + if (retval != ERROR_OK) + return retval; + + retval = target_checksum_memory(bank->target, offset + bank->base, count, &target_crc); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("addr " TARGET_ADDR_FMT ", len 0x%08" PRIx32 ", crc 0x%08" PRIx32 " 0x%08" PRIx32, + offset + bank->base, count, ~image_crc, ~target_crc); + if (target_crc == image_crc) + return ERROR_OK; + else + return ERROR_FAIL; +} + void flash_bank_add(struct flash_bank *bank) { /* put flash bank in linked list */ @@ -142,7 +168,7 @@ void flash_bank_add(struct flash_bank *bank) if (flash_banks) { /* find last flash bank */ struct flash_bank *p = flash_banks; - while (NULL != p->next) { + while (p->next) { bank_num += 1; p = p->next; } @@ -220,7 +246,7 @@ struct flash_bank *get_flash_bank_by_name_noprobe(const char *name) unsigned found = 0; struct flash_bank *bank; - for (bank = flash_banks; NULL != bank; bank = bank->next) { + for (bank = flash_banks; bank; bank = bank->next) { if (strcmp(bank->name, name) == 0) return bank; if (!flash_driver_name_matches(bank->driver->name, name)) @@ -238,7 +264,7 @@ int get_flash_bank_by_name(const char *name, struct flash_bank **bank_result) int retval; bank = get_flash_bank_by_name_noprobe(name); - if (bank != NULL) { + if (bank) { retval = bank->driver->auto_probe(bank); if (retval != ERROR_OK) { @@ -256,7 +282,7 @@ int get_flash_bank_by_num(unsigned int num, struct flash_bank **bank) struct flash_bank *p = get_flash_bank_by_num_noprobe(num); int retval; - if (p == NULL) + if (!p) return ERROR_FAIL; retval = p->driver->auto_probe(p); @@ -308,7 +334,7 @@ static int default_flash_mem_blank_check(struct flash_bank *bank) { struct target *target = bank->target; const int buffer_size = 1024; - uint32_t nBytes; + uint32_t n_bytes; int retval = ERROR_OK; if (bank->target->state != TARGET_HALTED) { @@ -336,8 +362,8 @@ static int default_flash_mem_blank_check(struct flash_bank *bank) if (retval != ERROR_OK) goto done; - for (nBytes = 0; nBytes < chunk; nBytes++) { - if (buffer[nBytes] != bank->erased_value) { + for (n_bytes = 0; n_bytes < chunk; n_bytes++) { + if (buffer[n_bytes] != bank->erased_value) { bank->sectors[i].is_erased = 0; break; } @@ -363,7 +389,7 @@ int default_flash_blank_check(struct flash_bank *bank) struct target_memory_check_block *block_array; block_array = malloc(bank->num_sectors * sizeof(struct target_memory_check_block)); - if (block_array == NULL) + if (!block_array) return default_flash_mem_blank_check(bank); for (unsigned int i = 0; i < bank->num_sectors; i++) { @@ -392,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); @@ -454,7 +484,7 @@ static int flash_iterate_address_range_inner(struct target *target, return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } - if (c->prot_blocks == NULL || c->num_prot_blocks == 0) { + if (!c->prot_blocks || c->num_prot_blocks == 0) { /* flash driver does not define protect blocks, use sectors instead */ iterate_protect_blocks = false; } @@ -697,12 +727,12 @@ static bool flash_write_check_gap(struct flash_bank *bank, } -int flash_write_unlock(struct target *target, struct image *image, - uint32_t *written, bool erase, bool unlock) +int flash_write_unlock_verify(struct target *target, struct image *image, + uint32_t *written, bool erase, bool unlock, bool write, bool verify) { int retval = ERROR_OK; - int section; + unsigned int section; uint32_t section_offset; struct flash_bank *c; int *padding; @@ -727,8 +757,8 @@ int flash_write_unlock(struct target *target, struct image *image, * whereas an image can have sections out of order. */ struct imagesection **sections = malloc(sizeof(struct imagesection *) * image->num_sections); - int i; - for (i = 0; i < image->num_sections; i++) + + for (unsigned int i = 0; i < image->num_sections; i++) sections[i] = &image->sections[i]; qsort(sections, image->num_sections, sizeof(struct imagesection *), @@ -738,7 +768,7 @@ int flash_write_unlock(struct target *target, struct image *image, while (section < image->num_sections) { uint32_t buffer_idx; uint8_t *buffer; - int section_last; + unsigned int section_last; target_addr_t run_address = sections[section]->base_address + section_offset; uint32_t run_size = sections[section]->size - section_offset; int pad_bytes = 0; @@ -754,7 +784,7 @@ int flash_write_unlock(struct target *target, struct image *image, retval = get_flash_bank_by_addr(target, run_address, false, &c); if (retval != ERROR_OK) goto done; - if (c == NULL) { + if (!c) { LOG_WARNING("no flash bank found for address " TARGET_ADDR_FMT, run_address); section++; /* and skip it */ section_offset = 0; @@ -866,7 +896,7 @@ int flash_write_unlock(struct target *target, struct image *image, /* allocate buffer */ buffer = malloc(run_size); - if (buffer == NULL) { + if (!buffer) { LOG_ERROR("Out of memory for flash bank buffer"); retval = ERROR_FAIL; goto done; @@ -932,8 +962,17 @@ int flash_write_unlock(struct target *target, struct image *image, } if (retval == ERROR_OK) { - /* write flash sectors */ - retval = flash_driver_write(c, buffer, run_address - c->base, run_size); + if (write) { + /* write flash sectors */ + retval = flash_driver_write(c, buffer, run_address - c->base, run_size); + } + } + + if (retval == ERROR_OK) { + if (verify) { + /* verify flash sectors */ + retval = flash_driver_verify(c, buffer, run_address - c->base, run_size); + } } free(buffer); @@ -943,7 +982,7 @@ int flash_write_unlock(struct target *target, struct image *image, goto done; } - if (written != NULL) + if (written) *written += run_size; /* add run size to total written counter */ } @@ -957,14 +996,14 @@ done: int flash_write(struct target *target, struct image *image, uint32_t *written, bool erase) { - return flash_write_unlock(target, image, written, erase, false); + return flash_write_unlock_verify(target, image, written, erase, false, true, false); } struct flash_sector *alloc_block_array(uint32_t offset, uint32_t size, unsigned int num_blocks) { struct flash_sector *array = calloc(num_blocks, sizeof(struct flash_sector)); - if (array == NULL) + if (!array) return NULL; for (unsigned int i = 0; i < num_blocks; i++) { diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index 163e57878e..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 @@ -200,6 +187,7 @@ void default_flash_free_driver_priv(struct flash_bank *bank); /** Deallocates all flash banks */ void flash_free_all_banks(void); + /** * Provides default read implementation for flash memory. * @param bank The bank to read. @@ -210,6 +198,18 @@ void flash_free_all_banks(void); */ int default_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); + +/** + * Provides default verify implementation for flash memory. + * @param bank The bank to verify. + * @param buffer The data bytes to verify. + * @param offset The offset into the chip to verify. + * @param count The number of bytes to verify. + * @returns ERROR_OK if successful; otherwise, an error code. + */ +int default_flash_verify(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count); + /** * Provides default erased-bank check handling. Checks to see if * the flash driver knows they are erased; if things look uncertain, @@ -217,7 +217,6 @@ int default_flash_read(struct flash_bank *bank, * @returns ERROR_OK if successful; otherwise, an error code. */ int default_flash_blank_check(struct flash_bank *bank); - /** * Returns the flash bank specified by @a name, which matches the * driver name and a suffix (option) specify the driver-specific @@ -253,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. @@ -264,7 +276,8 @@ struct flash_bank *get_flash_bank_by_num_noprobe(unsigned int num); * @param target The target, presumed to contain one or more banks. * @param addr An address that is within the range of the bank. * @param check return ERROR_OK and result_bank NULL if the bank does not exist - * @returns The struct flash_bank located at @a addr, or NULL. + * @param result_bank The struct flash_bank located at @a addr, or NULL. + * @returns ERROR_OK on success, or an error indicating the problem. */ int get_flash_bank_by_addr(struct target *target, target_addr_t addr, bool check, struct flash_bank **result_bank); diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 7f66047fef..7d6f8c5cc4 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 @@ -155,6 +144,20 @@ struct flash_driver { int (*read)(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); + /** + * Verify data in flash. Note CPU address will be + * "bank->base + offset", while the physical address is + * dependent upon current target MMU mappings. + * + * @param bank The bank to verify + * @param buffer The data bytes to verify against. + * @param offset The offset into the chip to verify. + * @param count The number of bytes to verify. + * @returns ERROR_OK if successful; otherwise, an error code. + */ + int (*verify)(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count); + /** * Probe to determine what kind of flash is present. * This is invoked by the "probe" script command. @@ -191,15 +194,14 @@ struct flash_driver { /** * Display human-readable information about the flash - * bank into the given buffer. Drivers must be careful to avoid - * overflowing the buffer. + * bank. * * @param bank - the bank to get info about - * @param char - where to put the text for the human to read - * @param buf_size - the size of the human buffer. + * @param cmd - command invocation instance for which to generate + * the textual output * @returns ERROR_OK if successful; otherwise, an error code. */ - int (*info)(struct flash_bank *bank, char *buf, int buf_size); + int (*info)(struct flash_bank *bank, struct command_invocation *cmd); /** * A more gentle flavor of flash_driver_s::probe, performing @@ -235,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 eneispif_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 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 d52e072ee5..34359889a6 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,73 +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 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 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 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 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 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. @@ -111,6 +33,7 @@ static const struct flash_driver * const flash_drivers[] = { &dsp5680xx_flash, &efm32_flash, &em357_flash, + &eneispif_flash, &esirisc_flash, &faux_flash, &fm3_flash, @@ -128,6 +51,7 @@ static const struct flash_driver * const flash_drivers[] = { &mrvlqspi_flash, &msp432_flash, &niietcm4_flash, + &npcx_flash, &nrf5_flash, &nrf51_flash, &numicro_flash, @@ -138,7 +62,9 @@ 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, &sim3x_flash, &stellaris_flash, @@ -148,6 +74,7 @@ static const struct flash_driver * const flash_drivers[] = { &stm32l4x_flash, &stm32h7x_flash, &stmsmi_flash, + &stmqspi_flash, &str7x_flash, &str9x_flash, &str9xpec_flash, @@ -158,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 6f1eccfeb9..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; } @@ -130,15 +116,9 @@ static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, if (set) retval = dsp5680xx_f_lock(bank->target); - else { + else retval = dsp5680xx_f_unlock(bank->target); - if (retval == ERROR_OK) { - /* mark all as erased */ - for (int i = 0; i <= (HFM_SECTOR_COUNT - 1); i++) - /* FM does not recognize it as erased if erased via JTAG. */ - bank->sectors[i].is_erased = 1; - } - } + return retval; } @@ -156,8 +136,6 @@ static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { - int retval; - if ((offset + count / 2) > bank->size) { LOG_ERROR("%s: Flash bank cannot fit data.", __func__); return ERROR_FAIL; @@ -171,17 +149,7 @@ static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t *buffer, LOG_ERROR("%s: Writing to odd addresses not supported for this target", __func__); return ERROR_FAIL; } - retval = dsp5680xx_f_wr(bank->target, buffer, bank->base + offset / 2, count, 0); - uint32_t addr_word; - - for (addr_word = bank->base + offset / 2; addr_word < count / 2; - addr_word += (HFM_SECTOR_SIZE / 2)) { - if (retval == ERROR_OK) - bank->sectors[addr_word / (HFM_SECTOR_SIZE / 2)].is_erased = 0; - else - bank->sectors[addr_word / (HFM_SECTOR_SIZE / 2)].is_erased = -1; - } - return retval; + return dsp5680xx_f_wr(bank->target, buffer, bank->base + offset / 2, count, 0); } static int dsp5680xx_probe(struct flash_bank *bank) @@ -193,8 +161,8 @@ static int dsp5680xx_probe(struct flash_bank *bank) /** * The flash module (FM) on the dsp5680xx supports both individual sector * and mass erase of the flash memory. - * If this function is called with @first == @last == 0 or if @first is the - * first sector (#0) and @last is the last sector then the mass erase command + * If this function is called with @a first == @a last == 0 or if @a first is the + * first sector (#0) and @a last is the last sector then the mass erase command * is executed (much faster than erasing each sector individually). * * @param bank @@ -206,22 +174,7 @@ static int dsp5680xx_probe(struct flash_bank *bank) static int dsp5680xx_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { - int retval; - - retval = dsp5680xx_f_erase(bank->target, (uint32_t) first, (uint32_t) last); - if ((!(first | last)) || ((first == 0) && (last == (HFM_SECTOR_COUNT - 1)))) - last = HFM_SECTOR_COUNT - 1; - if (retval == ERROR_OK) - for (unsigned int i = first; i <= last; i++) - bank->sectors[i].is_erased = 1; - else - /** - * If an error occurred unknown status - *is set even though some sector could have been correctly erased. - */ - for (unsigned int i = first; i <= last; i++) - bank->sectors[i].is_erased = -1; - return retval; + return dsp5680xx_f_erase(bank->target, (uint32_t) first, (uint32_t) last); } /** @@ -241,16 +194,14 @@ static int dsp5680xx_flash_erase_check(struct flash_bank *bank) uint32_t i; for (i = 0; i < HFM_SECTOR_COUNT; i++) { - if (bank->sectors[i].is_erased == -1) { - retval = dsp5680xx_f_erase_check(bank->target, &erased, i); - if (retval != ERROR_OK) { - bank->sectors[i].is_erased = -1; - } else { - if (erased) - bank->sectors[i].is_erased = 1; - else - bank->sectors[i].is_erased = 0; - } + retval = dsp5680xx_f_erase_check(bank->target, &erased, i); + if (retval != ERROR_OK) { + bank->sectors[i].is_erased = -1; + } else { + if (erased) + bank->sectors[i].is_erased = 1; + else + bank->sectors[i].is_erased = 0; } } return retval; diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 6f29007624..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 * @@ -14,18 +16,8 @@ * Copyright (C) 2014 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/>. * + * Copyright (C) 2021 Doug Brunner * + * doug.a.brunner@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -45,13 +37,16 @@ #define EFM32_FLASH_WDATAREADY_TMO 100 #define EFM32_FLASH_WRITE_TMO 100 +#define EFM32_FLASH_BASE 0 + /* size in bytes, not words; must fit all Gecko devices */ -#define LOCKBITS_PAGE_SZ 512 +#define LOCKWORDS_SZ 512 #define EFM32_MSC_INFO_BASE 0x0fe00000 #define EFM32_MSC_USER_DATA EFM32_MSC_INFO_BASE #define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE+0x4000) +#define EFM32_MSC_LOCK_BITS_EXTRA (EFM32_MSC_LOCK_BITS+LOCKWORDS_SZ) #define EFM32_MSC_DEV_INFO (EFM32_MSC_INFO_BASE+0x8000) /* PAGE_SIZE is not present in Zero, Happy and the original Gecko MCU */ @@ -83,6 +78,27 @@ #define EFM32_MSC_REG_LOCK_SERIES1 0x040 #define EFM32_MSC_LOCK_LOCKKEY 0x1b71 +enum efm32_bank_index { + EFM32_BANK_INDEX_MAIN, + EFM32_BANK_INDEX_USER_DATA, + EFM32_BANK_INDEX_LOCK_BITS, + EFM32_N_BANKS +}; + +static int efm32x_get_bank_index(target_addr_t base) +{ + switch (base) { + case EFM32_FLASH_BASE: + return EFM32_BANK_INDEX_MAIN; + case EFM32_MSC_USER_DATA: + return EFM32_BANK_INDEX_USER_DATA; + case EFM32_MSC_LOCK_BITS: + return EFM32_BANK_INDEX_LOCK_BITS; + default: + return ERROR_FAIL; + } +} + struct efm32_family_data { int family_id; const char *name; @@ -98,13 +114,6 @@ struct efm32_family_data { uint32_t msc_regbase; }; -struct efm32x_flash_bank { - bool probed; - uint32_t lb_page[LOCKBITS_PAGE_SZ/4]; - uint32_t reg_base; - uint32_t reg_lock; -}; - struct efm32_info { const struct efm32_family_data *family_data; uint16_t flash_sz_kib; @@ -115,13 +124,22 @@ struct efm32_info { uint16_t page_size; }; +struct efm32x_flash_chip { + struct efm32_info info; + bool probed[EFM32_N_BANKS]; + uint32_t lb_page[LOCKWORDS_SZ/4]; + uint32_t reg_base; + uint32_t reg_lock; + uint32_t refcount; +}; + static const struct efm32_family_data efm32_families[] = { { 16, "EFR32MG1P Mighty", .series = 1 }, { 17, "EFR32MG1B Mighty", .series = 1 }, { 18, "EFR32MG1V Mighty", .series = 1 }, - { 19, "EFR32MG1P Blue", .series = 1 }, - { 20, "EFR32MG1B Blue", .series = 1 }, - { 21, "EFR32MG1V Blue", .series = 1 }, + { 19, "EFR32BG1P Blue", .series = 1 }, + { 20, "EFR32BG1B Blue", .series = 1 }, + { 21, "EFR32BG1V Blue", .series = 1 }, { 25, "EFR32FG1P Flex", .series = 1 }, { 26, "EFR32FG1B Flex", .series = 1 }, { 27, "EFR32FG1V Flex", .series = 1 }, @@ -175,9 +193,12 @@ static const struct efm32_family_data efm32_families[] = { { 122, "EZR32HG Happy", .series = 0, .page_size = 1024 }, }; +const struct flash_driver efm32_flash; -static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count); +static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t addr, uint32_t count); + +static int efm32x_write_only_lockbits(struct flash_bank *bank); static int efm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_sz) { @@ -207,7 +228,7 @@ static int efm32x_get_prod_rev(struct flash_bank *bank, uint8_t *prev) static int efm32x_read_reg_u32(struct flash_bank *bank, target_addr_t offset, uint32_t *value) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; uint32_t base = efm32x_info->reg_base; return target_read_u32(bank->target, base + offset, value); @@ -216,54 +237,38 @@ static int efm32x_read_reg_u32(struct flash_bank *bank, target_addr_t offset, static int efm32x_write_reg_u32(struct flash_bank *bank, target_addr_t offset, uint32_t value) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; uint32_t base = efm32x_info->reg_base; return target_write_u32(bank->target, base + offset, value); } -static int efm32x_read_info(struct flash_bank *bank, - struct efm32_info *efm32_info) +static int efm32x_read_info(struct flash_bank *bank) { int ret; - uint32_t cpuid = 0; - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + struct efm32_info *efm32_info = &(efm32x_info->info); memset(efm32_info, 0, sizeof(struct efm32_info)); - ret = target_read_u32(bank->target, CPUID, &cpuid); - if (ERROR_OK != ret) - return ret; - - if (((cpuid >> 4) & 0xfff) == 0xc23) { - /* Cortex-M3 device */ - } else if (((cpuid >> 4) & 0xfff) == 0xc24) { - /* Cortex-M4 device (WONDER GECKO) */ - } else if (((cpuid >> 4) & 0xfff) == 0xc60) { - /* Cortex-M0+ device */ - } else { - LOG_ERROR("Target is not Cortex-Mx Device"); - return ERROR_FAIL; - } - ret = efm32x_get_flash_size(bank, &(efm32_info->flash_sz_kib)); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; ret = efm32x_get_ram_size(bank, &(efm32_info->ram_sz_kib)); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; ret = efm32x_get_part_num(bank, &(efm32_info->part_num)); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; ret = efm32x_get_part_family(bank, &(efm32_info->part_family)); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; ret = efm32x_get_prod_rev(bank, &(efm32_info->prod_rev)); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; for (size_t i = 0; i < ARRAY_SIZE(efm32_families); i++) { @@ -271,7 +276,7 @@ static int efm32x_read_info(struct flash_bank *bank, efm32_info->family_data = &efm32_families[i]; } - if (efm32_info->family_data == NULL) { + if (!efm32_info->family_data) { LOG_ERROR("Unknown MCU family %d", efm32_info->part_family); return ERROR_FAIL; } @@ -296,7 +301,7 @@ static int efm32x_read_info(struct flash_bank *bank, uint8_t pg_size = 0; ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE, &pg_size); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; efm32_info->page_size = (1 << ((pg_size+10) & 0xff)); @@ -324,39 +329,64 @@ static int efm32x_read_info(struct flash_bank *bank, return ERROR_OK; } -/* - * Helper to create a human friendly string describing a part - */ -static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size) -{ - int printed = 0; - printed = snprintf(buf, buf_size, "%s Gecko, rev %d", - info->family_data->name, info->prod_rev); - - if (printed >= buf_size) - return ERROR_BUF_TOO_SMALL; - - return ERROR_OK; -} - -/* flash bank efm32 <base> <size> 0 0 <target#> - */ +/* flash bank efm32 <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command) { - struct efm32x_flash_bank *efm32x_info; + struct efm32x_flash_chip *efm32x_info = NULL; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; - efm32x_info = malloc(sizeof(struct efm32x_flash_bank)); + int bank_index = efm32x_get_bank_index(bank->base); + if (bank_index < 0) { + LOG_ERROR("Flash bank with base address %" PRIx32 " is not supported", + (uint32_t) bank->base); + return ERROR_FAIL; + } + + /* look for an existing flash structure matching target */ + for (struct flash_bank *bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) { + if (bank_iter->driver == &efm32_flash + && bank_iter->target == bank->target + && bank->driver_priv) { + efm32x_info = bank->driver_priv; + break; + } + } + + if (!efm32x_info) { + /* target not matched, make a new one */ + efm32x_info = calloc(1, sizeof(struct efm32x_flash_chip)); + + memset(efm32x_info->lb_page, 0xff, LOCKWORDS_SZ); + } + ++efm32x_info->refcount; bank->driver_priv = efm32x_info; - efm32x_info->probed = false; - memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ); return ERROR_OK; } +/** + * Remove flash structure corresponding to this bank, + * if and only if it's not used by any others + */ +static void efm32x_free_driver_priv(struct flash_bank *bank) +{ + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + + if (efm32x_info) { + /* Use ref count to determine if it can be freed; scanning bank list doesn't work, + * because this function can be called after some banks in the list have been + * already destroyed */ + --efm32x_info->refcount; + if (efm32x_info->refcount == 0) { + free(efm32x_info); + bank->driver_priv = NULL; + } + } +} + /* set or reset given bits in a register */ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, uint32_t bitmask, int set) @@ -365,7 +395,7 @@ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, uint32_t reg_val = 0; ret = efm32x_read_reg_u32(bank, reg, ®_val); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; if (set) @@ -384,7 +414,7 @@ static int efm32x_set_wren(struct flash_bank *bank, int write_enable) static int efm32x_msc_lock(struct flash_bank *bank, int lock) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; return efm32x_write_reg_u32(bank, efm32x_info->reg_lock, (lock ? 0 : EFM32_MSC_LOCK_LOCKKEY)); } @@ -397,12 +427,12 @@ static int efm32x_wait_status(struct flash_bank *bank, int timeout, while (1) { ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); - if (ERROR_OK != ret) + if (ret != ERROR_OK) break; LOG_DEBUG("status: 0x%" PRIx32 "", status); - if (((status & wait_mask) == 0) && (0 == wait_for_set)) + if (((status & wait_mask) == 0) && (wait_for_set == 0)) break; else if (((status & wait_mask) != 0) && wait_for_set) break; @@ -432,20 +462,19 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) */ int ret = 0; uint32_t status = 0; - addr += bank->base; LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr); ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; LOG_DEBUG("status 0x%" PRIx32, status); @@ -460,7 +489,7 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; return efm32x_wait_status(bank, EFM32_FLASH_ERASE_TMO, @@ -473,33 +502,41 @@ static int efm32x_erase(struct flash_bank *bank, unsigned int first, struct target *target = bank->target; int ret = 0; - if (TARGET_HALTED != target->state) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } efm32x_msc_lock(bank, 0); ret = efm32x_set_wren(bank, 1); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to enable MSC write"); return ret; } for (unsigned int i = first; i <= last; i++) { - ret = efm32x_erase_page(bank, bank->sectors[i].offset); - if (ERROR_OK != ret) + ret = efm32x_erase_page(bank, bank->base + bank->sectors[i].offset); + if (ret != ERROR_OK) LOG_ERROR("Failed to erase page %d", i); } ret = efm32x_set_wren(bank, 0); efm32x_msc_lock(bank, 1); + if (ret != ERROR_OK) + return ret; + + if (bank->base == EFM32_MSC_LOCK_BITS) { + ret = efm32x_write_only_lockbits(bank); + if (ret != ERROR_OK) + LOG_ERROR("Failed to restore lockbits after erase"); + } return ret; } static int efm32x_read_lock_data(struct flash_bank *bank) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; struct target *target = bank->target; int data_size = 0; uint32_t *ptr = NULL; @@ -514,7 +551,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) for (int i = 0; i < data_size; i++, ptr++) { ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+i*4, ptr); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to read PLW %d", i); return ret; } @@ -525,7 +562,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) /* ULW, word 126 */ ptr = efm32x_info->lb_page + 126; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+126*4, ptr); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to read ULW"); return ret; } @@ -533,7 +570,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) /* DLW, word 127 */ ptr = efm32x_info->lb_page + 127; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+127*4, ptr); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to read DLW"); return ret; } @@ -541,7 +578,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) /* MLW, word 125, present in GG, LG, PG, JG, EFR32 */ ptr = efm32x_info->lb_page + 125; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+125*4, ptr); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to read MLW"); return ret; } @@ -549,7 +586,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) /* ALW, word 124, present in GG, LG, PG, JG, EFR32 */ ptr = efm32x_info->lb_page + 124; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+124*4, ptr); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to read ALW"); return ret; } @@ -557,7 +594,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) /* CLW1, word 123, present in EFR32 */ ptr = efm32x_info->lb_page + 123; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+123*4, ptr); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to read CLW1"); return ret; } @@ -565,7 +602,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) /* CLW0, word 122, present in GG, LG, PG, JG, EFR32 */ ptr = efm32x_info->lb_page + 122; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+122*4, ptr); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to read CLW0"); return ret; } @@ -573,35 +610,84 @@ static int efm32x_read_lock_data(struct flash_bank *bank) return ERROR_OK; } +static int efm32x_write_only_lockbits(struct flash_bank *bank) +{ + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + return efm32x_priv_write(bank, (uint8_t *)efm32x_info->lb_page, EFM32_MSC_LOCK_BITS, LOCKWORDS_SZ); +} + static int efm32x_write_lock_data(struct flash_bank *bank) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; int ret = 0; + /* Preserve any data written to the high portion of the lockbits page */ + assert(efm32x_info->info.page_size >= LOCKWORDS_SZ); + uint32_t extra_bytes = efm32x_info->info.page_size - LOCKWORDS_SZ; + uint8_t *extra_data = NULL; + if (extra_bytes) { + extra_data = malloc(extra_bytes); + ret = target_read_buffer(bank->target, EFM32_MSC_LOCK_BITS_EXTRA, extra_bytes, extra_data); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read extra contents of LB page"); + free(extra_data); + return ret; + } + } + ret = efm32x_erase_page(bank, EFM32_MSC_LOCK_BITS); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to erase LB page"); + if (extra_data) + free(extra_data); return ret; } - return efm32x_write(bank, (uint8_t *)efm32x_info->lb_page, EFM32_MSC_LOCK_BITS, - LOCKBITS_PAGE_SZ); + if (extra_data) { + ret = efm32x_priv_write(bank, extra_data, EFM32_MSC_LOCK_BITS_EXTRA, extra_bytes); + free(extra_data); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to restore extra contents of LB page"); + return ret; + } + } + + return efm32x_write_only_lockbits(bank); } static int efm32x_get_page_lock(struct flash_bank *bank, size_t page) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; - uint32_t dw = efm32x_info->lb_page[page >> 5]; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + uint32_t dw = 0; uint32_t mask = 0; - mask = 1 << (page & 0x1f); + switch (bank->base) { + case EFM32_FLASH_BASE: + dw = efm32x_info->lb_page[page >> 5]; + mask = 1 << (page & 0x1f); + break; + case EFM32_MSC_USER_DATA: + dw = efm32x_info->lb_page[126]; + mask = 0x1; + break; + case EFM32_MSC_LOCK_BITS: + dw = efm32x_info->lb_page[126]; + mask = 0x2; + break; + } return (dw & mask) ? 0 : 1; } static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + + if (bank->base != EFM32_FLASH_BASE) { + LOG_ERROR("Locking user and lockbits pages is not supported yet"); + return ERROR_FAIL; + } + uint32_t *dw = &efm32x_info->lb_page[page >> 5]; uint32_t mask = 0; @@ -621,11 +707,6 @@ static int efm32x_protect(struct flash_bank *bank, int set, unsigned int first, struct target *target = bank->target; int ret = 0; - if (!set) { - LOG_ERROR("Erase device data to reset page locks"); - return ERROR_FAIL; - } - if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; @@ -633,14 +714,14 @@ static int efm32x_protect(struct flash_bank *bank, int set, unsigned int first, for (unsigned int i = first; i <= last; i++) { ret = efm32x_set_page_lock(bank, i, set); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to set lock on page %d", i); return ret; } } ret = efm32x_write_lock_data(bank); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to write LB page"); return ret; } @@ -649,16 +730,15 @@ static int efm32x_protect(struct flash_bank *bank, int set, unsigned int first, } static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, - uint32_t offset, uint32_t count) + uint32_t address, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; - uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; int ret = ERROR_OK; /* see contrib/loaders/flash/efm32.S for src */ @@ -828,16 +908,16 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, keep_alive(); ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; LOG_DEBUG("status 0x%" PRIx32, status); @@ -852,27 +932,27 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, ret = efm32x_wait_status(bank, EFM32_FLASH_WDATAREADY_TMO, EFM32_MSC_STATUS_WDATAREADY_MASK, 1); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Wait for WDATAREADY failed"); return ret; } ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WDATA, val); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("WDATA write failed"); return ret; } ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_WRITEONCE_MASK); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("WRITECMD write failed"); return ret; } ret = efm32x_wait_status(bank, EFM32_FLASH_WRITE_TMO, EFM32_MSC_STATUS_BUSY_MASK, 0); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Wait for BUSY failed"); return ret; } @@ -880,8 +960,8 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, return ERROR_OK; } -static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) +static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t addr, uint32_t count) { struct target *target = bank->target; uint8_t *new_buffer = NULL; @@ -891,9 +971,9 @@ static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_TARGET_NOT_HALTED; } - if (offset & 0x3) { - LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-byte " - "alignment", offset); + if (addr & 0x3) { + LOG_ERROR("addr 0x%" PRIx32 " breaks required 4-byte " + "alignment", addr); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } @@ -901,7 +981,7 @@ static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t old_count = count; count = (old_count | 3) + 1; new_buffer = malloc(count); - if (new_buffer == NULL) { + if (!new_buffer) { LOG_ERROR("odd number of bytes to write and no memory " "for padding buffer"); return ERROR_FAIL; @@ -922,7 +1002,7 @@ static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, goto cleanup; /* try using a block write */ - retval = efm32x_write_block(bank, buffer, offset, words_remaining); + retval = efm32x_write_block(bank, buffer, addr, words_remaining); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), @@ -934,13 +1014,13 @@ static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t value; memcpy(&value, buffer, sizeof(uint32_t)); - retval = efm32x_write_word(bank, offset, value); + retval = efm32x_write_word(bank, addr, value); if (retval != ERROR_OK) goto reset_pg_and_lock; words_remaining--; buffer += 4; - offset += 4; + addr += 4; } } @@ -955,67 +1035,77 @@ cleanup: return retval; } +static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + if (bank->base == EFM32_MSC_LOCK_BITS && offset < LOCKWORDS_SZ) { + LOG_ERROR("Cannot write to lock words"); + return ERROR_FAIL; + } + return efm32x_priv_write(bank, buffer, bank->base + offset, count); +} + static int efm32x_probe(struct flash_bank *bank) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; - struct efm32_info efm32_mcu_info; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + struct efm32_info *efm32_mcu_info = &(efm32x_info->info); int ret; - uint32_t base_address = 0x00000000; - char buf[256]; - efm32x_info->probed = false; - memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ); + int bank_index = efm32x_get_bank_index(bank->base); + assert(bank_index >= 0); - ret = efm32x_read_info(bank, &efm32_mcu_info); - if (ERROR_OK != ret) - return ret; + efm32x_info->probed[bank_index] = false; + memset(efm32x_info->lb_page, 0xff, LOCKWORDS_SZ); - ret = efm32x_decode_info(&efm32_mcu_info, buf, sizeof(buf)); - if (ERROR_OK != ret) + ret = efm32x_read_info(bank); + if (ret != ERROR_OK) return ret; - LOG_INFO("detected part: %s", buf); - LOG_INFO("flash size = %dkbytes", efm32_mcu_info.flash_sz_kib); - LOG_INFO("flash page size = %dbytes", efm32_mcu_info.page_size); - - assert(0 != efm32_mcu_info.page_size); - - int num_pages = efm32_mcu_info.flash_sz_kib * 1024 / - efm32_mcu_info.page_size; + LOG_INFO("detected part: %s Gecko, rev %d", + efm32_mcu_info->family_data->name, efm32_mcu_info->prod_rev); + 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(num_pages > 0); + assert(efm32_mcu_info->page_size != 0); free(bank->sectors); bank->sectors = NULL; - bank->base = base_address; - bank->size = (num_pages * efm32_mcu_info.page_size); - bank->num_sectors = num_pages; + if (bank->base == EFM32_FLASH_BASE) { + bank->num_sectors = efm32_mcu_info->flash_sz_kib * 1024 / + efm32_mcu_info->page_size; + assert(bank->num_sectors > 0); - ret = efm32x_read_lock_data(bank); - if (ERROR_OK != ret) { - LOG_ERROR("Failed to read LB data"); - return ret; - } - - bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); - - for (int i = 0; i < num_pages; i++) { - bank->sectors[i].offset = i * efm32_mcu_info.page_size; - bank->sectors[i].size = efm32_mcu_info.page_size; + ret = efm32x_read_lock_data(bank); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read LB data"); + return ret; + } + } else + bank->num_sectors = 1; + bank->size = bank->num_sectors * efm32_mcu_info->page_size; + bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + + for (uint32_t i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * efm32_mcu_info->page_size; + bank->sectors[i].size = efm32_mcu_info->page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } - efm32x_info->probed = true; + efm32x_info->probed[bank_index] = true; return ERROR_OK; } static int efm32x_auto_probe(struct flash_bank *bank) { - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; - if (efm32x_info->probed) + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + + int bank_index = efm32x_get_bank_index(bank->base); + assert(bank_index >= 0); + + if (efm32x_info->probed[bank_index]) return ERROR_OK; return efm32x_probe(bank); } @@ -1031,12 +1121,12 @@ static int efm32x_protect_check(struct flash_bank *bank) } ret = efm32x_read_lock_data(bank); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { LOG_ERROR("Failed to read LB data"); return ret; } - assert(NULL != bank->sectors); + assert(bank->sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = efm32x_get_page_lock(bank, i); @@ -1044,18 +1134,20 @@ static int efm32x_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int get_efm32x_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_efm32x_info(struct flash_bank *bank, struct command_invocation *cmd) { - struct efm32_info info; - int ret = 0; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + int ret; - ret = efm32x_read_info(bank, &info); - if (ERROR_OK != ret) { + ret = efm32x_read_info(bank); + if (ret != ERROR_OK) { LOG_ERROR("Failed to read EFM32 info"); return ret; } - return efm32x_decode_info(&info, buf, buf_size); + command_print_sameline(cmd, "%s Gecko, rev %d", efm32x_info->info.family_data->name, + efm32x_info->info.prod_rev); + return ERROR_OK; } COMMAND_HANDLER(efm32x_handle_debuglock_command) @@ -1067,10 +1159,10 @@ COMMAND_HANDLER(efm32x_handle_debuglock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; - struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + struct efm32x_flash_chip *efm32x_info = bank->driver_priv; target = bank->target; @@ -1084,7 +1176,7 @@ COMMAND_HANDLER(efm32x_handle_debuglock_command) *ptr = 0; retval = efm32x_write_lock_data(bank); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Failed to write LB page"); return retval; } @@ -1129,5 +1221,5 @@ const struct flash_driver efm32_flash = { .erase_check = default_flash_blank_check, .protect_check = efm32x_protect_check, .info = get_efm32x_info, - .free_driver_priv = default_flash_free_driver_priv, + .free_driver_priv = efm32x_free_driver_priv, }; diff --git a/src/flash/nor/em357.c b/src/flash/nor/em357.c index 4e2a169c66..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 @@ -382,8 +371,6 @@ static int em357_erase(struct flash_bank *bank, unsigned int first, retval = em357_wait_status_busy(bank, 100); if (retval != ERROR_OK) return retval; - - bank->sectors[i].is_erased = 1; } retval = target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK); @@ -722,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); @@ -761,7 +748,7 @@ COMMAND_HANDLER(em357_handle_lock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; em357_info = bank->driver_priv; @@ -800,7 +787,7 @@ COMMAND_HANDLER(em357_handle_unlock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; target = bank->target; @@ -873,17 +860,13 @@ COMMAND_HANDLER(em357_handle_mass_erase_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = em357_mass_erase(bank); - if (retval == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - + if (retval == ERROR_OK) command_print(CMD, "em357 mass erase complete"); - } else + else command_print(CMD, "em357 mass erase failed"); return retval; diff --git a/src/flash/nor/eneispif.c b/src/flash/nor/eneispif.c new file mode 100644 index 0000000000..6572b8c25b --- /dev/null +++ b/src/flash/nor/eneispif.c @@ -0,0 +1,433 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (c) 2024 ENE Technology Inc. + * steven@ene.com.tw +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/time_support.h> +#include <helper/bits.h> +#include <target/target.h> +#include <flash/nor/core.h> +#include <flash/nor/driver.h> +#include <flash/nor/spi.h> + +#define ISPICFG 0x0000 +#define ISPISTS 0x0004 +#define ISPIADDR 0x0008 +#define ISPICMD 0x000C +#define ISPIDAT 0x0100 + +#define ISPISTS_BUSY BIT(0) +#define STATUS1_QE BIT(1) + +#define CFG_READ 0x372 +#define CFG_WRITE 0x371 + +#define ISPI_CTRL_BASE 0x50101000 + +/* name read qread page erase chip device_id page erase flash + * _cmd _cmd _prog _cmd* _erase size size* size + * _cmd _cmd + */ +struct flash_device ene_flash_device = + FLASH_ID("ISPI flash", 0x03, 0x00, 0x02, 0x20, 0x60, 0x00132085, 0x100, 0x1000, 0x80000); + +struct eneispif_flash_bank { + bool probed; + target_addr_t ctrl_base; + uint32_t dev_id; + const struct flash_device *dev; +}; + +FLASH_BANK_COMMAND_HANDLER(eneispif_flash_bank_command) +{ + struct eneispif_flash_bank *eneispif_info; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + eneispif_info = malloc(sizeof(struct eneispif_flash_bank)); + if (!eneispif_info) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + bank->driver_priv = eneispif_info; + eneispif_info->probed = false; + eneispif_info->ctrl_base = ISPI_CTRL_BASE; + if (CMD_ARGC >= 7) { + COMMAND_PARSE_ADDRESS(CMD_ARGV[6], eneispif_info->ctrl_base); + LOG_INFO("ASSUMING ISPI device at ctrl_base = " TARGET_ADDR_FMT, + eneispif_info->ctrl_base); + } + + return ERROR_OK; +} + +static int eneispif_read_reg(struct flash_bank *bank, uint32_t *value, target_addr_t address) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + + int result = target_read_u32(target, eneispif_info->ctrl_base + address, value); + if (result != ERROR_OK) { + LOG_ERROR("%s error at " TARGET_ADDR_FMT, __func__, + eneispif_info->ctrl_base + address); + return result; + } + LOG_DEBUG("Read address " TARGET_ADDR_FMT " = 0x%" PRIx32, + eneispif_info->ctrl_base + address, *value); + return ERROR_OK; +} + +static int eneispif_write_reg(struct flash_bank *bank, target_addr_t address, uint32_t value) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + + LOG_DEBUG("Write address " TARGET_ADDR_FMT " = 0x%" PRIx32, + eneispif_info->ctrl_base + address, value); + int result = target_write_u32(target, eneispif_info->ctrl_base + address, value); + if (result != ERROR_OK) { + LOG_ERROR("%s error writing 0x%" PRIx32 " to " TARGET_ADDR_FMT, __func__, + value, eneispif_info->ctrl_base + address); + return result; + } + return ERROR_OK; +} + +static int eneispif_wait(struct flash_bank *bank) +{ + int64_t start = timeval_ms(); + + while (1) { + uint32_t status; + + if (eneispif_read_reg(bank, &status, ISPISTS) != ERROR_OK) + return ERROR_FAIL; + + if (!(status & ISPISTS_BUSY)) + break; + + int64_t now = timeval_ms(); + if (now - start > 1000) { + LOG_ERROR("Busy more than 1000ms."); + return ERROR_TARGET_TIMEOUT; + } + } + + return ERROR_OK; +} + +static int eneispi_erase_sector(struct flash_bank *bank, int sector) +{ + int retval = ERROR_OK; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + uint32_t offset; + uint32_t conf; + + retval = eneispif_read_reg(bank, &conf, ISPICFG); + if (retval != ERROR_OK) + return retval; + + offset = bank->sectors[sector].offset; + retval = eneispif_write_reg(bank, ISPIADDR, offset); /* Address */ + if (retval != ERROR_OK) + goto done; + + eneispif_write_reg(bank, ISPICFG, CFG_WRITE); /* Cmmmand enable */ + eneispif_write_reg(bank, ISPICMD, SPIFLASH_WRITE_ENABLE); /* Write enable */ + retval = eneispif_write_reg(bank, ISPICMD, eneispif_info->dev->erase_cmd); /* Erase page */ + if (retval != ERROR_OK) + goto done; + + retval = eneispif_wait(bank); + if (retval != ERROR_OK) + goto done; + +done: + eneispif_write_reg(bank, ISPICFG, conf); /* restore */ + return retval; +} + +static int eneispif_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + int retval = ERROR_OK; + + LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (last < first || last >= bank->num_sectors) { + LOG_ERROR("Flash sector invalid"); + return ERROR_FLASH_SECTOR_INVALID; + } + + if (!(eneispif_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + for (unsigned int sector = first; sector <= last; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FAIL; + } + } + + if (eneispif_info->dev->erase_cmd == 0x00) + return ERROR_FLASH_OPER_UNSUPPORTED; + + for (unsigned int sector = first; sector <= last; sector++) { + retval = eneispi_erase_sector(bank, sector); + if (retval != ERROR_OK) + break; + } + + return retval; +} + +static int eneispif_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) +{ + for (unsigned int sector = first; sector <= last; sector++) + bank->sectors[sector].is_protected = set; + + return ERROR_OK; +} + +static int eneispif_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, + uint32_t count) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + uint32_t page_size; + uint32_t conf; + int retval = ERROR_OK; + + LOG_DEBUG("bank->size=0x%x offset=0x%08" PRIx32 " count=0x%08" PRIx32, bank->size, offset, + count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > eneispif_info->dev->size_in_bytes) { + LOG_WARNING("Write past end of flash. Extra data discarded."); + count = eneispif_info->dev->size_in_bytes - offset; + } + + /* Check sector protection */ + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + /* Start offset in or before this sector? */ + /* End offset in or behind this sector? */ + if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && + ((offset + count - 1) >= bank->sectors[sector].offset) && + bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FAIL; + } + } + + retval = eneispif_read_reg(bank, &conf, ISPICFG); + if (retval != ERROR_OK) + return retval; + + eneispif_write_reg(bank, ISPICFG, CFG_WRITE); // Cmmmand enable + + /* If no valid page_size, use reasonable default. */ + page_size = + eneispif_info->dev->pagesize ? eneispif_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; + uint32_t page_offset = offset % page_size; + + while (count > 0) { + uint32_t cur_count; + + /* clip block at page boundary */ + if (page_offset + count > page_size) + cur_count = page_size - page_offset; + else + cur_count = count; + + eneispif_write_reg(bank, ISPICMD, SPIFLASH_WRITE_ENABLE); /* Write enable */ + target_write_buffer(target, eneispif_info->ctrl_base + ISPIDAT, cur_count, buffer); + eneispif_write_reg(bank, ISPIADDR, offset); + retval = eneispif_write_reg(bank, ISPICMD, + (cur_count << 16) | eneispif_info->dev->pprog_cmd); + if (retval != ERROR_OK) + goto err; + + page_offset = 0; + buffer += cur_count; + offset += cur_count; + count -= cur_count; + retval = eneispif_wait(bank); + if (retval != ERROR_OK) + goto err; + } + +err: + eneispif_write_reg(bank, ISPICFG, conf); /* restore */ + return retval; +} + +/* Return ID of flash device */ +/* On exit, SW mode is kept */ +static int eneispif_read_flash_id(struct flash_bank *bank, uint32_t *id) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + struct target *target = bank->target; + int retval; + uint32_t conf, value; + uint8_t buffer[4]; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = eneispif_read_reg(bank, &conf, ISPICFG); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("ISPCFG = (0x%08" PRIx32 ")", conf); + + /* read ID from Receive Register */ + eneispif_write_reg(bank, ISPICFG, CFG_WRITE); /* Cmmmand enable */ + retval = eneispif_write_reg(bank, ISPICMD, (3 << 16) | SPIFLASH_READ_ID); + if (retval != ERROR_OK) + goto done; + + retval = eneispif_wait(bank); + if (retval != ERROR_OK) + goto done; + + retval = target_read_buffer(target, eneispif_info->ctrl_base + ISPIDAT, 3, buffer); + if (retval != ERROR_OK) + goto done; + value = (buffer[2] << 16) | (buffer[1] << 8) | buffer[0]; + LOG_DEBUG("ISPDAT = (0x%08" PRIx32 ")", value); + + *id = value; +done: + eneispif_write_reg(bank, ISPICFG, conf); // restore + return retval; +} + +static int eneispif_probe(struct flash_bank *bank) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + struct flash_sector *sectors; + uint32_t id; + int retval; + uint32_t sectorsize; + + if (eneispif_info->probed) + free(bank->sectors); + + eneispif_info->probed = false; + + LOG_INFO("Assuming ISPI flash at address " TARGET_ADDR_FMT + " with controller at " TARGET_ADDR_FMT, + bank->base, eneispif_info->ctrl_base); + + eneispif_write_reg(bank, ISPICFG, CFG_READ); /* RAM map enable */ + + retval = eneispif_read_flash_id(bank, &id); + if (retval != ERROR_OK) + return retval; + + eneispif_info->dev_id = id; + eneispif_info->dev = &ene_flash_device; + + LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", eneispif_info->dev->name, + eneispif_info->dev_id); + + /* Set correct size value */ + bank->size = eneispif_info->dev->size_in_bytes; + + if (bank->size <= (1UL << 16)) + LOG_WARNING("device needs 2-byte addresses - not implemented"); + + /* if no sectors, treat whole bank as single sector */ + sectorsize = eneispif_info->dev->sectorsize ? eneispif_info->dev->sectorsize + : eneispif_info->dev->size_in_bytes; + + /* create and fill sectors array */ + bank->num_sectors = eneispif_info->dev->size_in_bytes / sectorsize; + sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (!sectors) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * sectorsize; + sectors[sector].size = sectorsize; + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + eneispif_info->probed = true; + return ERROR_OK; +} + +static int eneispif_auto_probe(struct flash_bank *bank) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + if (eneispif_info->probed) + return ERROR_OK; + return eneispif_probe(bank); +} + +static int eneispif_protect_check(struct flash_bank *bank) +{ + /* Nothing to do. Protection is only handled in SW. */ + return ERROR_OK; +} + +static int get_eneispif_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + + if (!(eneispif_info->probed)) { + command_print(cmd, "ENE ISPI flash bank not probed yet."); + return ERROR_OK; + } + + command_print(cmd, + "ENE ISPI flash information:\n" + " Device \'%s\' (ID 0x%08" PRIx32 ")", + eneispif_info->dev->name, eneispif_info->dev_id); + + return ERROR_OK; +} + +const struct flash_driver eneispif_flash = { + .name = "eneispif", + .usage = "flash bank <name> 'eneispif' <base_address> <size> 0 0 <target> <ctrl_base>", + .flash_bank_command = eneispif_flash_bank_command, + .erase = eneispif_erase, + .protect = eneispif_protect, + .write = eneispif_write, + .read = default_flash_read, + .probe = eneispif_probe, + .auto_probe = eneispif_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = eneispif_protect_check, + .info = get_eneispif_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/esirisc_flash.c b/src/flash/nor/esirisc_flash.c index 88f00bccaa..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 @@ -109,7 +98,6 @@ static const struct command_registration esirisc_flash_command_handlers[]; FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command) { struct esirisc_flash_bank *esirisc_info; - struct command *esirisc_cmd; if (CMD_ARGC < 9) return ERROR_COMMAND_SYNTAX_ERROR; @@ -123,8 +111,7 @@ FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command) bank->driver_priv = esirisc_info; /* register commands using existing esirisc context */ - esirisc_cmd = command_find_in_context(CMD_CTX, "esirisc"); - register_commands(CMD_CTX, esirisc_cmd, esirisc_flash_command_handlers); + register_commands(CMD_CTX, "esirisc", esirisc_flash_command_handlers); return ERROR_OK; } @@ -489,11 +476,11 @@ static int esirisc_flash_auto_probe(struct flash_bank *bank) return esirisc_flash_probe(bank); } -static int esirisc_flash_info(struct flash_bank *bank, char *buf, int buf_size) +static int esirisc_flash_info(struct flash_bank *bank, struct command_invocation *cmd) { struct esirisc_flash_bank *esirisc_info = bank->driver_priv; - snprintf(buf, buf_size, + command_print_sameline(cmd, "%4s cfg at 0x%" PRIx32 ", clock %" PRIu32 ", wait_states %" PRIu32, "", /* align with first line */ esirisc_info->cfg, diff --git a/src/flash/nor/faux.c b/src/flash/nor/faux.c index d6c6b2dae0..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 @@ -30,7 +19,7 @@ struct faux_flash_bank { uint32_t start_address; }; -static const int sectorSize = 0x10000; +static const int sector_size = 0x10000; /* flash bank faux <base> <size> <chip_width> <bus_width> <target#> <driverPath> @@ -43,12 +32,12 @@ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command) return ERROR_COMMAND_SYNTAX_ERROR; info = malloc(sizeof(struct faux_flash_bank)); - if (info == NULL) { + if (!info) { LOG_ERROR("no memory for flash bank info"); return ERROR_FAIL; } info->memory = malloc(bank->size); - if (info->memory == NULL) { + if (!info->memory) { free(info); LOG_ERROR("no memory for flash bank info"); return ERROR_FAIL; @@ -57,18 +46,18 @@ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command) /* Use 0x10000 as a fixed sector size. */ uint32_t offset = 0; - bank->num_sectors = bank->size/sectorSize; + bank->num_sectors = bank->size/sector_size; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; - bank->sectors[i].size = sectorSize; + bank->sectors[i].size = sector_size; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } info->target = get_target(CMD_ARGV[5]); - if (info->target == NULL) { + if (!info->target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[5]); free(info->memory); free(info); @@ -81,7 +70,7 @@ static int faux_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct faux_flash_bank *info = bank->driver_priv; - memset(info->memory + first*sectorSize, 0xff, sectorSize*(last-first + 1)); + memset(info->memory + first*sector_size, 0xff, sector_size*(last-first + 1)); return ERROR_OK; } @@ -92,9 +81,9 @@ static int faux_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o return ERROR_OK; } -static int faux_info(struct flash_bank *bank, char *buf, int buf_size) +static int faux_info(struct flash_bank *bank, struct command_invocation *cmd) { - snprintf(buf, buf_size, "faux flash driver"); + command_print_sameline(cmd, "faux flash driver"); return ERROR_OK; } diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c index 02630ac24f..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 @@ -151,7 +140,7 @@ FLASH_BANK_COMMAND_HANDLER(fespi_flash_bank_command) return ERROR_COMMAND_SYNTAX_ERROR; fespi_info = malloc(sizeof(struct fespi_flash_bank)); - if (fespi_info == NULL) { + if (!fespi_info) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } @@ -337,6 +326,11 @@ static int fespi_erase_sector(struct flash_bank *bank, int sector) if (retval != ERROR_OK) return retval; sector = bank->sectors[sector].offset; + if (bank->size > 0x1000000) { + retval = fespi_tx(bank, sector >> 24); + if (retval != ERROR_OK) + return retval; + } retval = fespi_tx(bank, sector >> 16); if (retval != ERROR_OK) return retval; @@ -435,32 +429,38 @@ static int fespi_protect(struct flash_bank *bank, int set, static int slow_fespi_write_buffer(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t len) { + struct fespi_flash_bank *fespi_info = bank->driver_priv; uint32_t ii; - if (offset & 0xFF000000) { - LOG_ERROR("FESPI interface does not support greater than 3B addressing, can't write to offset 0x%" PRIx32, - offset); - return ERROR_FAIL; - } - /* TODO!!! assert that len < page size */ - fespi_tx(bank, SPIFLASH_WRITE_ENABLE); - fespi_txwm_wait(bank); + if (fespi_tx(bank, SPIFLASH_WRITE_ENABLE) != ERROR_OK) + return ERROR_FAIL; + if (fespi_txwm_wait(bank) != ERROR_OK) + return ERROR_FAIL; if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD) != ERROR_OK) return ERROR_FAIL; - fespi_tx(bank, SPIFLASH_PAGE_PROGRAM); + if (fespi_tx(bank, fespi_info->dev->pprog_cmd) != ERROR_OK) + return ERROR_FAIL; - fespi_tx(bank, offset >> 16); - fespi_tx(bank, offset >> 8); - fespi_tx(bank, offset); + if (bank->size > 0x1000000 && fespi_tx(bank, offset >> 24) != ERROR_OK) + return ERROR_FAIL; + if (fespi_tx(bank, offset >> 16) != ERROR_OK) + return ERROR_FAIL; + if (fespi_tx(bank, offset >> 8) != ERROR_OK) + return ERROR_FAIL; + if (fespi_tx(bank, offset) != ERROR_OK) + return ERROR_FAIL; - for (ii = 0; ii < len; ii++) - fespi_tx(bank, buffer[ii]); + for (ii = 0; ii < len; ii++) { + if (fespi_tx(bank, buffer[ii]) != ERROR_OK) + return ERROR_FAIL; + } - fespi_txwm_wait(bank); + if (fespi_txwm_wait(bank) != ERROR_OK) + return ERROR_FAIL; if (fespi_write_reg(bank, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO) != ERROR_OK) return ERROR_FAIL; @@ -470,273 +470,24 @@ static int slow_fespi_write_buffer(struct flash_bank *bank, return ERROR_OK; } -static const uint8_t algorithm_bin[] = { -#include "../../../contrib/loaders/flash/fespi/fespi.inc" -}; -#define STEP_EXIT 4 -#define STEP_TX 8 -#define STEP_TXWM_WAIT 12 -#define STEP_WRITE_REG 16 -#define STEP_WIP_WAIT 20 -#define STEP_SET_DIR 24 -#define STEP_NOP 0xff - -struct algorithm_steps { - unsigned size; - unsigned used; - uint8_t **steps; +static const uint8_t riscv32_bin[] = { +#include "../../../contrib/loaders/flash/fespi/riscv32_fespi.inc" }; -static struct algorithm_steps *as_new(void) -{ - struct algorithm_steps *as = calloc(1, sizeof(struct algorithm_steps)); - as->size = 8; - as->steps = malloc(as->size * sizeof(as->steps[0])); - return as; -} - -static struct algorithm_steps *as_delete(struct algorithm_steps *as) -{ - for (unsigned step = 0; step < as->used; step++) { - free(as->steps[step]); - as->steps[step] = NULL; - } - free(as->steps); - free(as); - return NULL; -} - -static int as_empty(struct algorithm_steps *as) -{ - for (unsigned s = 0; s < as->used; s++) { - if (as->steps[s][0] != STEP_NOP) - return 0; - } - return 1; -} - -/* Return size of compiled program. */ -static unsigned as_compile(struct algorithm_steps *as, uint8_t *target, - unsigned target_size) -{ - unsigned offset = 0; - bool finish_early = false; - for (unsigned s = 0; s < as->used && !finish_early; s++) { - unsigned bytes_left = target_size - offset; - switch (as->steps[s][0]) { - case STEP_NOP: - break; - case STEP_TX: - { - unsigned size = as->steps[s][1]; - if (size + 3 > bytes_left) { - finish_early = true; - break; - } - memcpy(target + offset, as->steps[s], size + 2); - offset += size + 2; - break; - } - case STEP_WRITE_REG: - if (4 > bytes_left) { - finish_early = true; - break; - } - memcpy(target + offset, as->steps[s], 3); - offset += 3; - break; - case STEP_SET_DIR: - if (3 > bytes_left) { - finish_early = true; - break; - } - memcpy(target + offset, as->steps[s], 2); - offset += 2; - break; - case STEP_TXWM_WAIT: - case STEP_WIP_WAIT: - if (2 > bytes_left) { - finish_early = true; - break; - } - memcpy(target + offset, as->steps[s], 1); - offset += 1; - break; - default: - assert(0); - } - if (!finish_early) - as->steps[s][0] = STEP_NOP; - } - assert(offset + 1 <= target_size); - target[offset++] = STEP_EXIT; - - LOG_DEBUG("%d-byte program:", offset); - for (unsigned i = 0; i < offset;) { - char buf[80]; - for (unsigned x = 0; i < offset && x < 16; x++, i++) - sprintf(buf + x*3, "%02x ", target[i]); - LOG_DEBUG("%s", buf); - } - - return offset; -} - -static void as_add_step(struct algorithm_steps *as, uint8_t *step) -{ - if (as->used == as->size) { - as->size *= 2; - as->steps = realloc(as->steps, sizeof(as->steps[0]) * as->size); - LOG_DEBUG("Increased size to 0x%x", as->size); - } - as->steps[as->used] = step; - as->used++; -} - -static void as_add_tx(struct algorithm_steps *as, unsigned count, const uint8_t *data) -{ - LOG_DEBUG("count=%d", count); - while (count > 0) { - unsigned step_count = MIN(count, 255); - uint8_t *step = malloc(step_count + 2); - step[0] = STEP_TX; - step[1] = step_count; - memcpy(step + 2, data, step_count); - as_add_step(as, step); - data += step_count; - count -= step_count; - } -} - -static void as_add_tx1(struct algorithm_steps *as, uint8_t byte) -{ - uint8_t data[1]; - data[0] = byte; - as_add_tx(as, 1, data); -} - -static void as_add_write_reg(struct algorithm_steps *as, uint8_t offset, uint8_t data) -{ - uint8_t *step = malloc(3); - step[0] = STEP_WRITE_REG; - step[1] = offset; - step[2] = data; - as_add_step(as, step); -} - -static void as_add_txwm_wait(struct algorithm_steps *as) -{ - uint8_t *step = malloc(1); - step[0] = STEP_TXWM_WAIT; - as_add_step(as, step); -} - -static void as_add_wip_wait(struct algorithm_steps *as) -{ - uint8_t *step = malloc(1); - step[0] = STEP_WIP_WAIT; - as_add_step(as, step); -} - -static void as_add_set_dir(struct algorithm_steps *as, bool dir) -{ - uint8_t *step = malloc(2); - step[0] = STEP_SET_DIR; - step[1] = FESPI_FMT_DIR(dir); - as_add_step(as, step); -} - -/* This should write something less than or equal to a page.*/ -static int steps_add_buffer_write(struct algorithm_steps *as, - const uint8_t *buffer, uint32_t chip_offset, uint32_t len) -{ - if (chip_offset & 0xFF000000) { - LOG_ERROR("FESPI interface does not support greater than 3B addressing, can't write to offset 0x%" PRIx32, - chip_offset); - return ERROR_FAIL; - } - - as_add_tx1(as, SPIFLASH_WRITE_ENABLE); - as_add_txwm_wait(as); - as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD); - - uint8_t setup[] = { - SPIFLASH_PAGE_PROGRAM, - chip_offset >> 16, - chip_offset >> 8, - chip_offset, - }; - as_add_tx(as, sizeof(setup), setup); - - as_add_tx(as, len, buffer); - as_add_txwm_wait(as); - as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO); - - /* fespi_wip() */ - as_add_set_dir(as, FESPI_DIR_RX); - as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD); - as_add_wip_wait(as); - as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO); - as_add_set_dir(as, FESPI_DIR_TX); - - return ERROR_OK; -} - -static int steps_execute(struct algorithm_steps *as, - struct flash_bank *bank, struct working_area *algorithm_wa, - struct working_area *data_wa) -{ - struct target *target = bank->target; - struct fespi_flash_bank *fespi_info = bank->driver_priv; - uint32_t ctrl_base = fespi_info->ctrl_base; - int xlen = riscv_xlen(target); - - struct reg_param reg_params[2]; - init_reg_param(®_params[0], "a0", xlen, PARAM_OUT); - init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); - buf_set_u64(reg_params[0].value, 0, xlen, ctrl_base); - buf_set_u64(reg_params[1].value, 0, xlen, data_wa->address); - - int retval = ERROR_OK; - while (!as_empty(as)) { - keep_alive(); - uint8_t *data_buf = malloc(data_wa->size); - unsigned bytes = as_compile(as, data_buf, data_wa->size); - retval = target_write_buffer(target, data_wa->address, bytes, - data_buf); - free(data_buf); - if (retval != ERROR_OK) { - LOG_ERROR("Failed to write data to " TARGET_ADDR_FMT ": %d", - data_wa->address, retval); - goto exit; - } - - retval = target_run_algorithm(target, 0, NULL, 2, reg_params, - algorithm_wa->address, algorithm_wa->address + 4, - 10000, NULL); - if (retval != ERROR_OK) { - LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d", - algorithm_wa->address, retval); - goto exit; - } - } - -exit: - destroy_reg_param(®_params[1]); - destroy_reg_param(®_params[0]); - return retval; -} +static const uint8_t riscv64_bin[] = { +#include "../../../contrib/loaders/flash/fespi/riscv64_fespi.inc" +}; static int fespi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; - uint32_t cur_count, page_size, page_offset; + uint32_t cur_count, page_size; int retval = ERROR_OK; - LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, - __func__, offset, count); + LOG_DEBUG("bank->size=0x%x offset=0x%08" PRIx32 " count=0x%08" PRIx32, + bank->size, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -761,92 +512,157 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer, } } - struct working_area *algorithm_wa; - if (target_alloc_working_area(target, sizeof(algorithm_bin), - &algorithm_wa) != ERROR_OK) { - LOG_WARNING("Couldn't allocate %zd-byte working area.", - sizeof(algorithm_bin)); - algorithm_wa = NULL; + 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; + const uint8_t *bin; + size_t bin_size; + if (xlen == 32) { + bin = riscv32_bin; + bin_size = sizeof(riscv32_bin); } else { + bin = riscv64_bin; + bin_size = sizeof(riscv64_bin); + } + + unsigned data_wa_size = 0; + if (target_alloc_working_area(target, bin_size, &algorithm_wa) == ERROR_OK) { retval = target_write_buffer(target, algorithm_wa->address, - sizeof(algorithm_bin), algorithm_bin); + bin_size, bin); if (retval != ERROR_OK) { LOG_ERROR("Failed to write code to " TARGET_ADDR_FMT ": %d", algorithm_wa->address, retval); target_free_working_area(target, algorithm_wa); algorithm_wa = NULL; - } - } - struct working_area *data_wa = NULL; - unsigned data_wa_size = 2 * count; - while (1) { - if (data_wa_size < 128) { - LOG_WARNING("Couldn't allocate data working area."); - target_free_working_area(target, algorithm_wa); - algorithm_wa = NULL; - } - if (target_alloc_working_area_try(target, data_wa_size, &data_wa) == - ERROR_OK) { - break; + } else { + data_wa_size = MIN(target_get_working_area_avail(target), count); + if (data_wa_size < 128) { + LOG_WARNING("Couldn't allocate data working area."); + target_free_working_area(target, algorithm_wa); + algorithm_wa = NULL; + } else if (target_alloc_working_area(target, data_wa_size, &data_wa) != ERROR_OK) { + target_free_working_area(target, algorithm_wa); + algorithm_wa = NULL; + } } - - data_wa_size /= 2; + } else { + LOG_WARNING("Couldn't allocate %zd-byte working area.", bin_size); + algorithm_wa = NULL; } /* If no valid page_size, use reasonable default. */ page_size = fespi_info->dev->pagesize ? fespi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; - fespi_txwm_wait(bank); + if (algorithm_wa) { + struct reg_param reg_params[6]; + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + init_reg_param(®_params[2], "a2", xlen, PARAM_OUT); + init_reg_param(®_params[3], "a3", xlen, PARAM_OUT); + init_reg_param(®_params[4], "a4", xlen, PARAM_OUT); + init_reg_param(®_params[5], "a5", xlen, PARAM_OUT); + + while (count > 0) { + cur_count = MIN(count, data_wa_size); + buf_set_u64(reg_params[0].value, 0, xlen, fespi_info->ctrl_base); + buf_set_u64(reg_params[1].value, 0, xlen, page_size); + buf_set_u64(reg_params[2].value, 0, xlen, data_wa->address); + buf_set_u64(reg_params[3].value, 0, xlen, offset); + buf_set_u64(reg_params[4].value, 0, xlen, cur_count); + buf_set_u64(reg_params[5].value, 0, xlen, + fespi_info->dev->pprog_cmd | (bank->size > 0x1000000 ? 0x100 : 0)); + + retval = target_write_buffer(target, data_wa->address, cur_count, + buffer); + if (retval != ERROR_OK) { + LOG_DEBUG("Failed to write %d bytes to " TARGET_ADDR_FMT ": %d", + cur_count, data_wa->address, retval); + goto err; + } + + LOG_DEBUG("write(ctrl_base=0x%" TARGET_PRIxADDR ", page_size=0x%x, " + "address=0x%" TARGET_PRIxADDR ", offset=0x%" PRIx32 + ", count=0x%" PRIx32 "), buffer=%02x %02x %02x %02x %02x %02x ..." PRIx32, + fespi_info->ctrl_base, page_size, data_wa->address, offset, cur_count, + buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + retval = target_run_algorithm(target, 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm_wa->address, 0, cur_count * 2, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d", + algorithm_wa->address, retval); + goto err; + } + + uint64_t algorithm_result = buf_get_u64(reg_params[0].value, 0, xlen); + if (algorithm_result != 0) { + LOG_ERROR("Algorithm returned error %" PRId64, algorithm_result); + retval = ERROR_FAIL; + goto err; + } + + buffer += cur_count; + offset += cur_count; + count -= cur_count; + } - /* Disable Hardware accesses*/ - if (fespi_disable_hw_mode(bank) != ERROR_OK) - return ERROR_FAIL; + target_free_working_area(target, data_wa); + target_free_working_area(target, algorithm_wa); - struct algorithm_steps *as = as_new(); + } else { + fespi_txwm_wait(bank); - /* poll WIP */ - retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT); - if (retval != ERROR_OK) - goto err; - - page_offset = offset % page_size; - /* central part, aligned words */ - while (count > 0) { - /* clip block at page boundary */ - if (page_offset + count > page_size) - cur_count = page_size - page_offset; - else - cur_count = count; - - if (algorithm_wa) - retval = steps_add_buffer_write(as, buffer, offset, cur_count); - else - retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count); + /* Disable Hardware accesses*/ + if (fespi_disable_hw_mode(bank) != ERROR_OK) + return ERROR_FAIL; + + /* poll WIP */ + retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT); if (retval != ERROR_OK) goto err; - page_offset = 0; - buffer += cur_count; - offset += cur_count; - count -= cur_count; - } + uint32_t page_offset = offset % page_size; + /* central part, aligned words */ + while (count > 0) { + /* clip block at page boundary */ + if (page_offset + count > page_size) + cur_count = page_size - page_offset; + else + cur_count = count; - if (algorithm_wa) - retval = steps_execute(as, bank, algorithm_wa, data_wa); + retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count); + if (retval != ERROR_OK) + goto err; -err: - if (algorithm_wa) { - target_free_working_area(target, data_wa); - target_free_working_area(target, algorithm_wa); + page_offset = 0; + buffer += cur_count; + offset += cur_count; + count -= cur_count; + } + + /* Switch to HW mode before return to prompt */ + if (fespi_enable_hw_mode(bank) != ERROR_OK) + return ERROR_FAIL; } - as_delete(as); + return ERROR_OK; + +err: + target_free_working_area(target, data_wa); + target_free_working_area(target, algorithm_wa); /* Switch to HW mode before return to prompt */ if (fespi_enable_hw_mode(bank) != ERROR_OK) return ERROR_FAIL; + return retval; } @@ -976,8 +792,6 @@ static int fespi_probe(struct flash_bank *bank) if (bank->size <= (1UL << 16)) LOG_WARNING("device needs 2-byte addresses - not implemented"); - if (bank->size > (1UL << 24)) - LOG_WARNING("device needs paging or 4-byte addresses - not implemented"); /* if no sectors, treat whole bank as single sector */ sectorsize = fespi_info->dev->sectorsize ? @@ -986,7 +800,7 @@ static int fespi_probe(struct flash_bank *bank) /* create and fill sectors array */ bank->num_sectors = fespi_info->dev->size_in_bytes / sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); - if (sectors == NULL) { + if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } @@ -1017,17 +831,16 @@ static int fespi_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int get_fespi_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_fespi_info(struct flash_bank *bank, struct command_invocation *cmd) { struct fespi_flash_bank *fespi_info = bank->driver_priv; if (!(fespi_info->probed)) { - snprintf(buf, buf_size, - "\nFESPI flash bank not probed yet\n"); + command_print_sameline(cmd, "\nFESPI flash bank not probed yet\n"); return ERROR_OK; } - snprintf(buf, buf_size, "\nFESPI flash information:\n" + command_print_sameline(cmd, "\nFESPI flash information:\n" " Device \'%s\' (ID 0x%08" PRIx32 ")\n", fespi_info->dev->name, fespi_info->dev->device_id); diff --git a/src/flash/nor/fm3.c b/src/flash/nor/fm3.c index fef1797069..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 @@ -33,29 +22,29 @@ #define FLASH_DQ5 0x20 /* Time limit exceeding flag bit (TLOV) position */ enum fm3_variant { - mb9bfxx1, /* Flash Type '1' */ - mb9bfxx2, - mb9bfxx3, - mb9bfxx4, - mb9bfxx5, - mb9bfxx6, - mb9bfxx7, - mb9bfxx8, - - mb9afxx1, /* Flash Type '2' */ - mb9afxx2, - mb9afxx3, - mb9afxx4, - mb9afxx5, - mb9afxx6, - mb9afxx7, - mb9afxx8, + MB9BFXX1, /* Flash Type '1' */ + MB9BFXX2, + MB9BFXX3, + MB9BFXX4, + MB9BFXX5, + MB9BFXX6, + MB9BFXX7, + MB9BFXX8, + + MB9AFXX1, /* Flash Type '2' */ + MB9AFXX2, + MB9AFXX3, + MB9AFXX4, + MB9AFXX5, + MB9AFXX6, + MB9AFXX7, + MB9AFXX8, }; enum fm3_flash_type { - fm3_no_flash_type = 0, - fm3_flash_type1 = 1, - fm3_flash_type2 = 2 + FM3_NO_FLASH_TYPE = 0, + FM3_FLASH_TYPE1 = 1, + FM3_FLASH_TYPE2 = 2 }; struct fm3_flash_bank { @@ -76,53 +65,53 @@ FLASH_BANK_COMMAND_HANDLER(fm3_flash_bank_command) /* Flash type '1' */ if (strcmp(CMD_ARGV[5], "mb9bfxx1.cpu") == 0) { - fm3_info->variant = mb9bfxx1; - fm3_info->flashtype = fm3_flash_type1; + fm3_info->variant = MB9BFXX1; + fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx2.cpu") == 0) { - fm3_info->variant = mb9bfxx2; - fm3_info->flashtype = fm3_flash_type1; + fm3_info->variant = MB9BFXX2; + fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx3.cpu") == 0) { - fm3_info->variant = mb9bfxx3; - fm3_info->flashtype = fm3_flash_type1; + fm3_info->variant = MB9BFXX3; + fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx4.cpu") == 0) { - fm3_info->variant = mb9bfxx4; - fm3_info->flashtype = fm3_flash_type1; + fm3_info->variant = MB9BFXX4; + fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx5.cpu") == 0) { - fm3_info->variant = mb9bfxx5; - fm3_info->flashtype = fm3_flash_type1; + fm3_info->variant = MB9BFXX5; + fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx6.cpu") == 0) { - fm3_info->variant = mb9bfxx6; - fm3_info->flashtype = fm3_flash_type1; + fm3_info->variant = MB9BFXX6; + fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx7.cpu") == 0) { - fm3_info->variant = mb9bfxx7; - fm3_info->flashtype = fm3_flash_type1; + fm3_info->variant = MB9BFXX7; + fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx8.cpu") == 0) { - fm3_info->variant = mb9bfxx8; - fm3_info->flashtype = fm3_flash_type1; + fm3_info->variant = MB9BFXX8; + fm3_info->flashtype = FM3_FLASH_TYPE1; } else if (strcmp(CMD_ARGV[5], "mb9afxx1.cpu") == 0) { /* Flash type '2' */ - fm3_info->variant = mb9afxx1; - fm3_info->flashtype = fm3_flash_type2; + fm3_info->variant = MB9AFXX1; + fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx2.cpu") == 0) { - fm3_info->variant = mb9afxx2; - fm3_info->flashtype = fm3_flash_type2; + fm3_info->variant = MB9AFXX2; + fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx3.cpu") == 0) { - fm3_info->variant = mb9afxx3; - fm3_info->flashtype = fm3_flash_type2; + fm3_info->variant = MB9AFXX3; + fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx4.cpu") == 0) { - fm3_info->variant = mb9afxx4; - fm3_info->flashtype = fm3_flash_type2; + fm3_info->variant = MB9AFXX4; + fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx5.cpu") == 0) { - fm3_info->variant = mb9afxx5; - fm3_info->flashtype = fm3_flash_type2; + fm3_info->variant = MB9AFXX5; + fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx6.cpu") == 0) { - fm3_info->variant = mb9afxx6; - fm3_info->flashtype = fm3_flash_type2; + fm3_info->variant = MB9AFXX6; + fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx7.cpu") == 0) { - fm3_info->variant = mb9afxx7; - fm3_info->flashtype = fm3_flash_type2; + fm3_info->variant = MB9AFXX7; + fm3_info->flashtype = FM3_FLASH_TYPE2; } else if (strcmp(CMD_ARGV[5], "mb9afxx8.cpu") == 0) { - fm3_info->variant = mb9afxx8; - fm3_info->flashtype = fm3_flash_type2; + fm3_info->variant = MB9AFXX8; + fm3_info->flashtype = FM3_FLASH_TYPE2; } /* unknown Flash type */ @@ -207,24 +196,24 @@ static int fm3_erase(struct flash_bank *bank, unsigned int first, struct fm3_flash_bank *fm3_info = bank->driver_priv; struct target *target = bank->target; int retval = ERROR_OK; - uint32_t u32DummyRead; + uint32_t u32_dummy_read; int odd; - uint32_t u32FlashType; - uint32_t u32FlashSeqAddress1; - uint32_t u32FlashSeqAddress2; + uint32_t u32_flash_type; + uint32_t u32_flash_seq_address1; + uint32_t u32_flash_seq_address2; struct working_area *write_algorithm; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; - u32FlashType = (uint32_t) fm3_info->flashtype; + u32_flash_type = (uint32_t) fm3_info->flashtype; - if (u32FlashType == fm3_flash_type1) { - u32FlashSeqAddress1 = 0x00001550; - u32FlashSeqAddress2 = 0x00000AA8; - } else if (u32FlashType == fm3_flash_type2) { - u32FlashSeqAddress1 = 0x00000AA8; - u32FlashSeqAddress2 = 0x00000554; + if (u32_flash_type == FM3_FLASH_TYPE1) { + u32_flash_seq_address1 = 0x00001550; + u32_flash_seq_address2 = 0x00000AA8; + } else if (u32_flash_type == FM3_FLASH_TYPE2) { + u32_flash_seq_address1 = 0x00000AA8; + u32_flash_seq_address2 = 0x00000554; } else { LOG_ERROR("Flash/Device type unknown!"); return ERROR_FLASH_OPERATION_FAILED; @@ -282,7 +271,7 @@ static int fm3_erase(struct flash_bank *bank, unsigned int first, return retval; /* dummy read of FASZR */ - retval = target_read_u32(target, 0x40000000, &u32DummyRead); + retval = target_read_u32(target, 0x40000000, &u32_dummy_read); if (retval != ERROR_OK) return retval; @@ -300,8 +289,8 @@ static int fm3_erase(struct flash_bank *bank, unsigned int first, armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; - init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* u32FlashSeqAddress1 */ - init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* u32FlashSeqAddress2 */ + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* u32_flash_seq_address1 */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* u32_flash_seq_address2 */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* offset */ /* write code buffer and use Flash sector erase code within fm3 */ @@ -312,8 +301,8 @@ static int fm3_erase(struct flash_bank *bank, unsigned int first, if (odd) offset += 4; - buf_set_u32(reg_params[0].value, 0, 32, u32FlashSeqAddress1); - buf_set_u32(reg_params[1].value, 0, 32, u32FlashSeqAddress2); + buf_set_u32(reg_params[0].value, 0, 32, u32_flash_seq_address1); + buf_set_u32(reg_params[1].value, 0, 32, u32_flash_seq_address2); buf_set_u32(reg_params[2].value, 0, 32, offset); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, @@ -328,7 +317,6 @@ static int fm3_erase(struct flash_bank *bank, unsigned int first, if (retval != ERROR_OK) return retval; } - bank->sectors[sector].is_erased = 1; } target_free_working_area(target, write_algorithm); @@ -341,7 +329,7 @@ static int fm3_erase(struct flash_bank *bank, unsigned int first, if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, 0x40000000, &u32DummyRead); /* dummy read of FASZR */ + retval = target_read_u32(target, 0x40000000, &u32_dummy_read); /* dummy read of FASZR */ return retval; } @@ -358,22 +346,22 @@ static int fm3_write_block(struct flash_bank *bank, const uint8_t *buffer, struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - uint32_t u32FlashType; - uint32_t u32FlashSeqAddress1; - uint32_t u32FlashSeqAddress2; + uint32_t u32_flash_type; + uint32_t u32_flash_seq_address1; + uint32_t u32_flash_seq_address2; /* Increase buffer_size if needed */ if (buffer_size < (target->working_area_size / 2)) buffer_size = (target->working_area_size / 2); - u32FlashType = (uint32_t) fm3_info->flashtype; + u32_flash_type = (uint32_t) fm3_info->flashtype; - if (u32FlashType == fm3_flash_type1) { - u32FlashSeqAddress1 = 0x00001550; - u32FlashSeqAddress2 = 0x00000AA8; - } else if (u32FlashType == fm3_flash_type2) { - u32FlashSeqAddress1 = 0x00000AA8; - u32FlashSeqAddress2 = 0x00000554; + if (u32_flash_type == FM3_FLASH_TYPE1) { + u32_flash_seq_address1 = 0x00001550; + u32_flash_seq_address2 = 0x00000AA8; + } else if (u32_flash_type == FM3_FLASH_TYPE2) { + u32_flash_seq_address1 = 0x00000AA8; + u32_flash_seq_address2 = 0x00000554; } else { LOG_ERROR("Flash/Device type unknown!"); return ERROR_FLASH_OPERATION_FAILED; @@ -401,8 +389,8 @@ static int fm3_write_block(struct flash_bank *bank, const uint8_t *buffer, 0x55, 0xF0, 0x01, 0x05, /* ORRS.W R5, R5, #1 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ - /* u32DummyRead = fm3_FLASH_IF->FASZ; */ - 0x28, 0x4D, /* LDR.N R5, ??u32DummyRead */ + /* u32_dummy_read = fm3_FLASH_IF->FASZ; */ + 0x28, 0x4D, /* LDR.N R5, ??u32_dummy_read */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x36, 0x68, /* LDR R6, [R6] */ 0x2E, 0x60, /* STR R6, [R5] */ @@ -492,8 +480,8 @@ static int fm3_write_block(struct flash_bank *bank, const uint8_t *buffer, 0x55, 0xF0, 0x02, 0x05, /* ORRS.W R5, R5, #2 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ - /* u32DummyRead = fm3_FLASH_IF->FASZ; */ - 0x04, 0x4D, /* LDR.N R5, ??u32DummyRead */ + /* u32_dummy_read = fm3_FLASH_IF->FASZ; */ + 0x04, 0x4D, /* LDR.N R5, ??u32_dummy_read */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x36, 0x68, /* LDR R6, [R6] */ 0x2E, 0x60, /* STR R6, [R5] */ @@ -508,7 +496,7 @@ static int fm3_write_block(struct flash_bank *bank, const uint8_t *buffer, /* SRAM basic-address + 8.These address pointers will be patched, if a */ /* different start address in RAM is used (e.g. for Flash type 2)! */ /* Default SRAM basic-address is 0x20000000. */ - 0x00, 0x00, 0x00, 0x20, /* u32DummyRead address in RAM (0x20000000) */ + 0x00, 0x00, 0x00, 0x20, /* u32_dummy_read address in RAM (0x20000000) */ 0x04, 0x00, 0x00, 0x20 /* u32FlashResult address in RAM (0x20000004) */ }; @@ -548,7 +536,7 @@ static int fm3_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; /* Patching 'local variable address' */ - /* Algorithm: u32DummyRead: */ + /* Algorithm: u32_dummy_read: */ retval = target_write_u32(target, (write_algorithm->address + 8) + sizeof(fm3_flash_write_code) - 8, (write_algorithm->address)); if (retval != ERROR_OK) @@ -595,8 +583,8 @@ static int fm3_write_block(struct flash_bank *bank, const uint8_t *buffer, buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); - buf_set_u32(reg_params[3].value, 0, 32, u32FlashSeqAddress1); - buf_set_u32(reg_params[4].value, 0, 32, u32FlashSeqAddress2); + buf_set_u32(reg_params[3].value, 0, 32, u32_flash_seq_address1); + buf_set_u32(reg_params[4].value, 0, 32, u32_flash_seq_address2); retval = target_run_algorithm(target, 0, NULL, 6, reg_params, (write_algorithm->address + 8), 0, 1000, &armv7m_info); @@ -673,8 +661,8 @@ static int fm3_probe(struct flash_bank *bank) bank->sectors[1].is_erased = -1; bank->sectors[1].is_protected = -1; - if ((fm3_info->variant == mb9bfxx1) - || (fm3_info->variant == mb9afxx1)) { + if ((fm3_info->variant == MB9BFXX1) + || (fm3_info->variant == MB9AFXX1)) { num_pages = 3; bank->size = 64 * 1024; /* bytes */ bank->num_sectors = num_pages; @@ -685,18 +673,18 @@ static int fm3_probe(struct flash_bank *bank) bank->sectors[2].is_protected = -1; } - if ((fm3_info->variant == mb9bfxx2) - || (fm3_info->variant == mb9bfxx4) - || (fm3_info->variant == mb9bfxx5) - || (fm3_info->variant == mb9bfxx6) - || (fm3_info->variant == mb9bfxx7) - || (fm3_info->variant == mb9bfxx8) - || (fm3_info->variant == mb9afxx2) - || (fm3_info->variant == mb9afxx4) - || (fm3_info->variant == mb9afxx5) - || (fm3_info->variant == mb9afxx6) - || (fm3_info->variant == mb9afxx7) - || (fm3_info->variant == mb9afxx8)) { + if ((fm3_info->variant == MB9BFXX2) + || (fm3_info->variant == MB9BFXX4) + || (fm3_info->variant == MB9BFXX5) + || (fm3_info->variant == MB9BFXX6) + || (fm3_info->variant == MB9BFXX7) + || (fm3_info->variant == MB9BFXX8) + || (fm3_info->variant == MB9AFXX2) + || (fm3_info->variant == MB9AFXX4) + || (fm3_info->variant == MB9AFXX5) + || (fm3_info->variant == MB9AFXX6) + || (fm3_info->variant == MB9AFXX7) + || (fm3_info->variant == MB9AFXX8)) { num_pages = 3; bank->size = 128 * 1024; /* bytes */ bank->num_sectors = num_pages; @@ -707,16 +695,16 @@ static int fm3_probe(struct flash_bank *bank) bank->sectors[2].is_protected = -1; } - if ((fm3_info->variant == mb9bfxx4) - || (fm3_info->variant == mb9bfxx5) - || (fm3_info->variant == mb9bfxx6) - || (fm3_info->variant == mb9bfxx7) - || (fm3_info->variant == mb9bfxx8) - || (fm3_info->variant == mb9afxx4) - || (fm3_info->variant == mb9afxx5) - || (fm3_info->variant == mb9afxx6) - || (fm3_info->variant == mb9afxx7) - || (fm3_info->variant == mb9afxx8)) { + if ((fm3_info->variant == MB9BFXX4) + || (fm3_info->variant == MB9BFXX5) + || (fm3_info->variant == MB9BFXX6) + || (fm3_info->variant == MB9BFXX7) + || (fm3_info->variant == MB9BFXX8) + || (fm3_info->variant == MB9AFXX4) + || (fm3_info->variant == MB9AFXX5) + || (fm3_info->variant == MB9AFXX6) + || (fm3_info->variant == MB9AFXX7) + || (fm3_info->variant == MB9AFXX8)) { num_pages = 4; bank->size = 256 * 1024; /* bytes */ bank->num_sectors = num_pages; @@ -727,14 +715,14 @@ static int fm3_probe(struct flash_bank *bank) bank->sectors[3].is_protected = -1; } - if ((fm3_info->variant == mb9bfxx5) - || (fm3_info->variant == mb9bfxx6) - || (fm3_info->variant == mb9bfxx7) - || (fm3_info->variant == mb9bfxx8) - || (fm3_info->variant == mb9afxx5) - || (fm3_info->variant == mb9afxx6) - || (fm3_info->variant == mb9afxx7) - || (fm3_info->variant == mb9afxx8)) { + if ((fm3_info->variant == MB9BFXX5) + || (fm3_info->variant == MB9BFXX6) + || (fm3_info->variant == MB9BFXX7) + || (fm3_info->variant == MB9BFXX8) + || (fm3_info->variant == MB9AFXX5) + || (fm3_info->variant == MB9AFXX6) + || (fm3_info->variant == MB9AFXX7) + || (fm3_info->variant == MB9AFXX8)) { num_pages = 5; bank->size = 384 * 1024; /* bytes */ bank->num_sectors = num_pages; @@ -745,12 +733,12 @@ static int fm3_probe(struct flash_bank *bank) bank->sectors[4].is_protected = -1; } - if ((fm3_info->variant == mb9bfxx6) - || (fm3_info->variant == mb9bfxx7) - || (fm3_info->variant == mb9bfxx8) - || (fm3_info->variant == mb9afxx6) - || (fm3_info->variant == mb9afxx7) - || (fm3_info->variant == mb9afxx8)) { + if ((fm3_info->variant == MB9BFXX6) + || (fm3_info->variant == MB9BFXX7) + || (fm3_info->variant == MB9BFXX8) + || (fm3_info->variant == MB9AFXX6) + || (fm3_info->variant == MB9AFXX7) + || (fm3_info->variant == MB9AFXX8)) { num_pages = 6; bank->size = 512 * 1024; /* bytes */ bank->num_sectors = num_pages; @@ -761,10 +749,10 @@ static int fm3_probe(struct flash_bank *bank) bank->sectors[5].is_protected = -1; } - if ((fm3_info->variant == mb9bfxx7) - || (fm3_info->variant == mb9bfxx8) - || (fm3_info->variant == mb9afxx7) - || (fm3_info->variant == mb9afxx8)) { + if ((fm3_info->variant == MB9BFXX7) + || (fm3_info->variant == MB9BFXX8) + || (fm3_info->variant == MB9AFXX7) + || (fm3_info->variant == MB9AFXX8)) { num_pages = 8; bank->size = 768 * 1024; /* bytes */ bank->num_sectors = num_pages; @@ -780,8 +768,8 @@ static int fm3_probe(struct flash_bank *bank) bank->sectors[7].is_protected = -1; } - if ((fm3_info->variant == mb9bfxx8) - || (fm3_info->variant == mb9afxx8)) { + if ((fm3_info->variant == MB9BFXX8) + || (fm3_info->variant == MB9AFXX8)) { num_pages = 10; bank->size = 1024 * 1024; /* bytes */ bank->num_sectors = num_pages; @@ -816,25 +804,25 @@ static int fm3_chip_erase(struct flash_bank *bank) struct target *target = bank->target; struct fm3_flash_bank *fm3_info2 = bank->driver_priv; int retval = ERROR_OK; - uint32_t u32DummyRead; - uint32_t u32FlashType; - uint32_t u32FlashSeqAddress1; - uint32_t u32FlashSeqAddress2; + uint32_t u32_dummy_read; + uint32_t u32_flash_type; + uint32_t u32_flash_seq_address1; + uint32_t u32_flash_seq_address2; struct working_area *write_algorithm; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; - u32FlashType = (uint32_t) fm3_info2->flashtype; + u32_flash_type = (uint32_t) fm3_info2->flashtype; - if (u32FlashType == fm3_flash_type1) { + if (u32_flash_type == FM3_FLASH_TYPE1) { LOG_INFO("*** Erasing mb9bfxxx type"); - u32FlashSeqAddress1 = 0x00001550; - u32FlashSeqAddress2 = 0x00000AA8; - } else if (u32FlashType == fm3_flash_type2) { + u32_flash_seq_address1 = 0x00001550; + u32_flash_seq_address2 = 0x00000AA8; + } else if (u32_flash_type == FM3_FLASH_TYPE2) { LOG_INFO("*** Erasing mb9afxxx type"); - u32FlashSeqAddress1 = 0x00000AA8; - u32FlashSeqAddress2 = 0x00000554; + u32_flash_seq_address1 = 0x00000AA8; + u32_flash_seq_address2 = 0x00000554; } else { LOG_ERROR("Flash/Device type unknown!"); return ERROR_FLASH_OPERATION_FAILED; @@ -891,7 +879,7 @@ static int fm3_chip_erase(struct flash_bank *bank) return retval; /* dummy read of FASZR */ - retval = target_read_u32(target, 0x40000000, &u32DummyRead); + retval = target_read_u32(target, 0x40000000, &u32_dummy_read); if (retval != ERROR_OK) return retval; @@ -909,11 +897,11 @@ static int fm3_chip_erase(struct flash_bank *bank) armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; - init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* u32FlashSeqAddress1 */ - init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* u32FlashSeqAddress2 */ + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* u32_flash_seq_address1 */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* u32_flash_seq_address2 */ - buf_set_u32(reg_params[0].value, 0, 32, u32FlashSeqAddress1); - buf_set_u32(reg_params[1].value, 0, 32, u32FlashSeqAddress2); + buf_set_u32(reg_params[0].value, 0, 32, u32_flash_seq_address1); + buf_set_u32(reg_params[1].value, 0, 32, u32_flash_seq_address2); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, write_algorithm->address, 0, 100000, &armv7m_info); @@ -928,7 +916,7 @@ static int fm3_chip_erase(struct flash_bank *bank) destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); - retval = fm3_busy_wait(target, u32FlashSeqAddress2, 20000); /* 20s timeout */ + retval = fm3_busy_wait(target, u32_flash_seq_address2, 20000); /* 20s timeout */ if (retval != ERROR_OK) return retval; @@ -937,7 +925,7 @@ static int fm3_chip_erase(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, 0x40000000, &u32DummyRead); /* dummy read of FASZR */ + retval = target_read_u32(target, 0x40000000, &u32_dummy_read); /* dummy read of FASZR */ return retval; } @@ -949,14 +937,10 @@ COMMAND_HANDLER(fm3_handle_chip_erase_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (fm3_chip_erase(bank) == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - command_print(CMD, "fm3 chip erase complete"); } else { command_print(CMD, "fm3 chip erase failed"); diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c index 211a008637..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 * @@ -28,17 +30,17 @@ #define WDG_LCK (WDG_BASE + 0xC00) enum fm4_variant { - mb9bfx64, - mb9bfx65, - mb9bfx66, - mb9bfx67, - mb9bfx68, + MB9BFX64, + MB9BFX65, + MB9BFX66, + MB9BFX67, + MB9BFX68, - s6e2cx8, - s6e2cx9, - s6e2cxa, + S6E2CX8, + S6E2CX9, + S6E2CXA, - s6e2dx, + S6E2DX, }; struct fm4_flash_bank { @@ -177,8 +179,6 @@ static int fm4_flash_erase(struct flash_bank *bank, unsigned int first, goto err_run_ret; } else retval = ERROR_OK; - - bank->sectors[sector].is_erased = 1; } err_run_ret: @@ -350,19 +350,19 @@ static int mb9bf_probe(struct flash_bank *bank) uint32_t flash_addr = bank->base; switch (fm4_bank->variant) { - case mb9bfx64: + case MB9BFX64: bank->num_sectors = 8; break; - case mb9bfx65: + case MB9BFX65: bank->num_sectors = 10; break; - case mb9bfx66: + case MB9BFX66: bank->num_sectors = 12; break; - case mb9bfx67: + case MB9BFX67: bank->num_sectors = 16; break; - case mb9bfx68: + case MB9BFX68: bank->num_sectors = 20; break; default: @@ -421,13 +421,13 @@ static int s6e2cc_probe(struct flash_bank *bank) } switch (fm4_bank->variant) { - case s6e2cx8: + case S6E2CX8: num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 0; break; - case s6e2cx9: + case S6E2CX9: num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 12; break; - case s6e2cxa: + case S6E2CXA: num_sectors = 20; break; default: @@ -503,19 +503,19 @@ static int fm4_probe(struct flash_bank *bank) } switch (fm4_bank->variant) { - case mb9bfx64: - case mb9bfx65: - case mb9bfx66: - case mb9bfx67: - case mb9bfx68: + case MB9BFX64: + case MB9BFX65: + case MB9BFX66: + case MB9BFX67: + case MB9BFX68: retval = mb9bf_probe(bank); break; - case s6e2cx8: - case s6e2cx9: - case s6e2cxa: + case S6E2CX8: + case S6E2CX9: + case S6E2CXA: retval = s6e2cc_probe(bank); break; - case s6e2dx: + case S6E2DX: retval = s6e2dh_probe(bank); break; default: @@ -539,7 +539,7 @@ static int fm4_auto_probe(struct flash_bank *bank) return fm4_probe(bank); } -static int fm4_get_info_command(struct flash_bank *bank, char *buf, int buf_size) +static int fm4_get_info_command(struct flash_bank *bank, struct command_invocation *cmd) { struct fm4_flash_bank *fm4_bank = bank->driver_priv; const char *name; @@ -550,31 +550,31 @@ static int fm4_get_info_command(struct flash_bank *bank, char *buf, int buf_size } switch (fm4_bank->variant) { - case mb9bfx64: + case MB9BFX64: name = "MB9BFx64"; break; - case mb9bfx65: + case MB9BFX65: name = "MB9BFx65"; break; - case mb9bfx66: + case MB9BFX66: name = "MB9BFx66"; break; - case mb9bfx67: + case MB9BFX67: name = "MB9BFx67"; break; - case mb9bfx68: + case MB9BFX68: name = "MB9BFx68"; break; - case s6e2cx8: + case S6E2CX8: name = "S6E2Cx8"; break; - case s6e2cx9: + case S6E2CX9: name = "S6E2Cx9"; break; - case s6e2cxa: + case S6E2CXA: name = "S6E2CxA"; break; - case s6e2dx: + case S6E2DX: name = "S6E2Dx"; break; default: @@ -583,14 +583,13 @@ static int fm4_get_info_command(struct flash_bank *bank, char *buf, int buf_size } switch (fm4_bank->variant) { - case s6e2cx8: - case s6e2cx9: - case s6e2cxa: - snprintf(buf, buf_size, "%s MainFlash Macro #%i", - name, fm4_bank->macro_nr); + case S6E2CX8: + case S6E2CX9: + case S6E2CXA: + command_print_sameline(cmd, "%s MainFlash Macro #%i", name, fm4_bank->macro_nr); break; default: - snprintf(buf, buf_size, "%s MainFlash", name); + command_print_sameline(cmd, "%s MainFlash", name); break; } @@ -618,15 +617,15 @@ static int mb9bf_bank_setup(struct flash_bank *bank, const char *variant) struct fm4_flash_bank *fm4_bank = bank->driver_priv; if (fm4_name_match(variant, "MB9BFx64")) { - fm4_bank->variant = mb9bfx64; + fm4_bank->variant = MB9BFX64; } else if (fm4_name_match(variant, "MB9BFx65")) { - fm4_bank->variant = mb9bfx65; + fm4_bank->variant = MB9BFX65; } else if (fm4_name_match(variant, "MB9BFx66")) { - fm4_bank->variant = mb9bfx66; + fm4_bank->variant = MB9BFX66; } else if (fm4_name_match(variant, "MB9BFx67")) { - fm4_bank->variant = mb9bfx67; + fm4_bank->variant = MB9BFX67; } else if (fm4_name_match(variant, "MB9BFx68")) { - fm4_bank->variant = mb9bfx68; + fm4_bank->variant = MB9BFX68; } else { LOG_WARNING("MB9BF variant %s not recognized.", variant); return ERROR_FLASH_OPER_UNSUPPORTED; @@ -640,11 +639,11 @@ static int s6e2cc_bank_setup(struct flash_bank *bank, const char *variant) struct fm4_flash_bank *fm4_bank = bank->driver_priv; if (fm4_name_match(variant, "S6E2Cx8")) { - fm4_bank->variant = s6e2cx8; + fm4_bank->variant = S6E2CX8; } else if (fm4_name_match(variant, "S6E2Cx9")) { - fm4_bank->variant = s6e2cx9; + fm4_bank->variant = S6E2CX9; } else if (fm4_name_match(variant, "S6E2CxA")) { - fm4_bank->variant = s6e2cxa; + fm4_bank->variant = S6E2CXA; } else { LOG_WARNING("S6E2CC variant %s not recognized.", variant); return ERROR_FLASH_OPER_UNSUPPORTED; @@ -678,7 +677,7 @@ FLASH_BANK_COMMAND_HANDLER(fm4_flash_bank_command) else if (fm4_name_match(variant, "S6E2Cx")) ret = s6e2cc_bank_setup(bank, variant); else if (fm4_name_match(variant, "S6E2Dx")) { - fm4_bank->variant = s6e2dx; + fm4_bank->variant = S6E2DX; ret = ERROR_OK; } else { LOG_WARNING("Family %s not recognized.", variant); @@ -689,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 06fb2a2b6a..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 @@ -42,12 +31,14 @@ int flash_driver_erase(struct flash_bank *bank, unsigned int first, int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last); int flash_driver_write(struct flash_bank *bank, - uint8_t *buffer, uint32_t offset, uint32_t count); + const uint8_t *buffer, uint32_t offset, uint32_t count); int flash_driver_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); +int flash_driver_verify(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count); /* write (optional verify) an image to flash memory of the given target */ -int flash_write_unlock(struct target *target, struct image *image, - uint32_t *written, bool erase, bool unlock); +int flash_write_unlock_verify(struct target *target, struct image *image, + uint32_t *written, bool erase, bool unlock, bool write, bool verify); #endif /* OPENOCD_FLASH_NOR_IMP_H */ diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c index 20362f3842..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,45 +12,80 @@ #include <jtag/jtag.h> #include <flash/nor/spi.h> #include <helper/time_support.h> +#include <pld/pld.h> #define JTAGSPI_MAX_TIMEOUT 3000 struct jtagspi_flash_bank { struct jtag_tap *tap; - const struct flash_device *dev; + struct flash_device dev; + char devname[32]; bool probed; - uint32_t ir; + 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)); - if (info == NULL) { + 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; } + 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; @@ -69,149 +93,402 @@ static void jtagspi_set_ir(struct flash_bank *bank) jtag_add_ir_scan(info->tap, &field, TAP_IDLE); } -static void flip_u8(uint8_t *in, uint8_t *out, int len) +static void flip_u8(const uint8_t *in, uint8_t *out, unsigned int len) { - for (int i = 0; i < len; i++) + for (unsigned int i = 0; i < len; i++) out[i] = flip_u32(in[i], 8); } static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd, - uint32_t *addr, uint8_t *data, int len) + uint8_t *write_buffer, unsigned int write_len, uint8_t *data_buffer, int data_len) { - struct jtagspi_flash_bank *info = bank->driver_priv; + assert(write_buffer || write_len == 0); + assert(data_buffer || data_len == 0); + struct scan_field fields[6]; - uint8_t marker = 1; - uint8_t xfer_bits_buf[4]; - uint8_t addr_buf[3]; - uint8_t *data_buf; - uint32_t xfer_bits; - int is_read, lenb, n; + struct jtagspi_flash_bank *info = bank->driver_priv; - /* LOG_DEBUG("cmd=0x%02x len=%i", cmd, len); */ + LOG_DEBUG("cmd=0x%02x write_len=%d data_len=%d", cmd, write_len, data_len); - is_read = (len < 0); + /* negative data_len == read operation */ + const bool is_read = (data_len < 0); if (is_read) - len = -len; + data_len = -data_len; - n = 0; + unsigned int facing_read_bits = 0; + unsigned int trailing_write_bits = 0; - fields[n].num_bits = 1; - fields[n].out_value = ▮ - fields[n].in_value = NULL; - n++; + 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; + } - xfer_bits = 8 + len - 1; - /* cmd + read/write - 1 due to the counter implementation */ - if (addr) - xfer_bits += 24; - h_u32_to_be(xfer_bits_buf, xfer_bits); - flip_u8(xfer_bits_buf, xfer_bits_buf, 4); - fields[n].num_bits = 32; - fields[n].out_value = xfer_bits_buf; - fields[n].in_value = NULL; - n++; + int n = 0; + const uint8_t marker = 1; + uint8_t xfer_bits[4]; + 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++; + } - cmd = flip_u32(cmd, 8); - fields[n].num_bits = 8; + flip_u8(&cmd, &cmd, sizeof(cmd)); + fields[n].num_bits = sizeof(cmd) * CHAR_BIT; fields[n].out_value = &cmd; fields[n].in_value = NULL; n++; - if (addr) { - h_u24_to_be(addr_buf, *addr); - flip_u8(addr_buf, addr_buf, 3); - fields[n].num_bits = 24; - fields[n].out_value = addr_buf; + if (write_len) { + flip_u8(write_buffer, write_buffer, write_len); + fields[n].num_bits = write_len * CHAR_BIT; + fields[n].out_value = write_buffer; fields[n].in_value = NULL; n++; } - lenb = DIV_ROUND_UP(len, 8); - data_buf = malloc(lenb); - if (lenb > 0) { - if (data_buf == NULL) { - LOG_ERROR("no memory for spi buffer"); - return ERROR_FAIL; - } + 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_buf; + fields[n].in_value = data_buffer; } else { - flip_u8(data, data_buf, lenb); - fields[n].out_value = data_buf; + flip_u8(data_buffer, data_buffer, data_len); + fields[n].out_value = data_buffer; fields[n].in_value = NULL; } - fields[n].num_bits = len; + 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++; } - jtagspi_set_ir(bank); + 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); + } + /* passing from an IR scan to SHIFT-DR clears BYPASS registers */ 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_buf, data, lenb); - free(data_buf); - return retval; + flip_u8(data_buffer, data_buffer, data_len); + + if (info->pld_device) + return pld_disconnect_spi_from_jtag(info->pld_device); + return ERROR_OK; +} + +COMMAND_HANDLER(jtagspi_handle_set) +{ + struct flash_bank *bank = NULL; + struct jtagspi_flash_bank *info = NULL; + struct flash_sector *sectors = NULL; + uint32_t temp; + unsigned int index = 1; + int retval; + + LOG_DEBUG("%s", __func__); + + /* there are 6 mandatory arguments: + * devname, size_in_bytes, pagesize, read_cmd, unused, pprog_cmd */ + if (index + 6 > CMD_ARGC) { + command_print(CMD, "jtagspi: not enough arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + /* 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; + + /* invalidate all old info */ + if (info->probed) { + bank->size = 0; + bank->num_sectors = 0; + if (bank->sectors) + free(bank->sectors); + bank->sectors = NULL; + info->always_4byte = false; + info->probed = false; + } + memset(&info->dev, 0, sizeof(info->dev)); + + strncpy(info->devname, CMD_ARGV[index++], sizeof(info->devname) - 1); + info->devname[sizeof(info->devname) - 1] = '\0'; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], temp); + info->dev.size_in_bytes = temp; + if ((temp & (temp - 1)) || (temp < (1UL << 8))) { + command_print(CMD, "jtagspi: device size must be 2^n with n >= 8"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], temp); + info->dev.pagesize = temp; + if (info->dev.pagesize == 0) + info->dev.pagesize = SPIFLASH_DEF_PAGESIZE; + if ((temp & (temp - 1)) || (temp > info->dev.size_in_bytes)) { + command_print(CMD, "jtagspi: page size must be 2^n and <= device size"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.read_cmd); + if ((info->dev.read_cmd != 0x03) && + (info->dev.read_cmd != 0x13)) { + command_print(CMD, "jtagspi: only 0x03/0x13 READ allowed"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.qread_cmd); + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.pprog_cmd); + if ((info->dev.pprog_cmd != 0x02) && + (info->dev.pprog_cmd != 0x12)) { + command_print(CMD, "jtagspi: only 0x02/0x12 PPRG allowed"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + /* remaining params are optional */ + if (index < CMD_ARGC) + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.chip_erase_cmd); + else + info->dev.chip_erase_cmd = 0x00; + + if (index < CMD_ARGC) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], temp); + info->dev.sectorsize = temp; + if ((info->dev.sectorsize > info->dev.size_in_bytes) || + (info->dev.sectorsize < info->dev.pagesize) || (temp & (temp - 1))) { + command_print(CMD, "jtagspi: sector size must be 2^n and <= device size"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (index < CMD_ARGC) + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.erase_cmd); + else { + command_print(CMD, "jtagspi: erase command missing"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else { + /* no sector size / sector erase cmd given, treat whole bank as a single sector */ + info->dev.erase_cmd = 0x00; + info->dev.sectorsize = info->dev.size_in_bytes; + } + + if (index < CMD_ARGC) { + command_print(CMD, "jtagspi: extra arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + /* set correct size value */ + bank->size = info->dev.size_in_bytes; + + /* calculate address length in bytes */ + if (bank->size <= (1UL << 8)) + info->addr_len = 1; + else if (bank->size <= (1UL << 16)) + info->addr_len = 2; + else if (bank->size <= (1UL << 24)) + info->addr_len = 3; + else { + info->addr_len = 4; + LOG_WARNING("4-byte addresses needed, might need extra command to enable"); + } + + /* create and fill sectors array */ + bank->num_sectors = + info->dev.size_in_bytes / info->dev.sectorsize; + sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (!sectors) { + LOG_ERROR("Not enough memory"); + return ERROR_FAIL; + } + + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * (info->dev.sectorsize); + sectors[sector].size = info->dev.sectorsize; + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + info->dev.name = info->devname; + if (info->dev.size_in_bytes / 4096) + LOG_INFO("flash \'%s\' id = unknown\nflash size = %" PRIu32 " kbytes", + info->dev.name, info->dev.size_in_bytes / 1024); + else + LOG_INFO("flash \'%s\' id = unknown\nflash size = %" PRIu32 " bytes", + info->dev.name, info->dev.size_in_bytes); + info->probed = true; + + return ERROR_OK; +} + +COMMAND_HANDLER(jtagspi_handle_cmd) +{ + struct flash_bank *bank; + 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) + return ERROR_COMMAND_SYNTAX_ERROR; + + uint8_t num_write = CMD_ARGC - 3; + if (num_write > max) { + command_print(CMD, "at most %d bytes may be send", max); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + /* 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[1], num_read); + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[2], cmd_byte); + + for (unsigned int i = 0; i < num_write; i++) + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[i + 3], write_buffer[i]); + + /* process command */ + retval = jtagspi_cmd(bank, cmd_byte, write_buffer, num_write, read_buffer, -num_read); + if (retval != ERROR_OK) + return retval; + + 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; +} + +COMMAND_HANDLER(jtagspi_handle_always_4byte) +{ + struct flash_bank *bank; + struct jtagspi_flash_bank *jtagspi_info; + int retval; + + LOG_DEBUG("%s", __func__); + + if ((CMD_ARGC != 1) && (CMD_ARGC != 2)) + return ERROR_COMMAND_SYNTAX_ERROR; + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + jtagspi_info = bank->driver_priv; + + if (CMD_ARGC == 1) + command_print(CMD, jtagspi_info->always_4byte ? "on" : "off"); + else + COMMAND_PARSE_BOOL(CMD_ARGV[1], jtagspi_info->always_4byte, "on", "off"); + + return ERROR_OK; } static int jtagspi_probe(struct flash_bank *bank) { struct jtagspi_flash_bank *info = bank->driver_priv; struct flash_sector *sectors; + const struct flash_device *p; uint8_t in_buf[3]; uint32_t id, sectorsize; - if (info->probed) + if (bank->sectors) { free(bank->sectors); - info->probed = false; - - if (bank->target->tap == NULL) { - LOG_ERROR("Target has no JTAG tap"); - return ERROR_FAIL; + bank->sectors = NULL; } - info->tap = bank->target->tap; + info->probed = false; - jtagspi_cmd(bank, SPIFLASH_READ_ID, NULL, in_buf, -24); + 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); - info->dev = NULL; - for (const struct flash_device *p = flash_devices; p->name ; p++) + memset(&info->dev, 0, sizeof(info->dev)); + for (p = flash_devices; p->name ; p++) if (p->device_id == id) { - info->dev = p; + memcpy(&info->dev, p, sizeof(info->dev)); break; } - if (!(info->dev)) { - LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id); + if (!(p->name)) { + LOG_ERROR("Unknown flash device (ID 0x%06" PRIx32 ")", id & 0xFFFFFF); return ERROR_FAIL; } - LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", - info->dev->name, info->dev->device_id); + LOG_INFO("Found flash device \'%s\' (ID 0x%06" PRIx32 ")", + info->dev.name, info->dev.device_id & 0xFFFFFF); /* Set correct size value */ - bank->size = info->dev->size_in_bytes; - if (bank->size <= (1UL << 16)) - LOG_WARNING("device needs 2-byte addresses - not implemented"); - if (bank->size > (1UL << 24)) - LOG_WARNING("device needs paging or 4-byte addresses - not implemented"); + bank->size = info->dev.size_in_bytes; + + /* calculate address length in bytes */ + if (bank->size <= (1UL << 8)) + info->addr_len = 1; + else if (bank->size <= (1UL << 16)) + info->addr_len = 2; + else if (bank->size <= (1UL << 24)) + info->addr_len = 3; + else { + info->addr_len = 4; + LOG_WARNING("4-byte addresses needed, might need extra command to enable"); + } /* if no sectors, treat whole bank as single sector */ - sectorsize = info->dev->sectorsize ? - info->dev->sectorsize : info->dev->size_in_bytes; + sectorsize = info->dev.sectorsize ? + info->dev.sectorsize : info->dev.size_in_bytes; /* create and fill sectors array */ - bank->num_sectors = info->dev->size_in_bytes / sectorsize; + bank->num_sectors = info->dev.size_in_bytes / sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); - if (sectors == NULL) { + if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } @@ -228,27 +505,35 @@ static int jtagspi_probe(struct flash_bank *bank) return ERROR_OK; } +static int jtagspi_auto_probe(struct flash_bank *bank) +{ + struct jtagspi_flash_bank *info = bank->driver_priv; + + if (info->probed) + return ERROR_OK; + return jtagspi_probe(bank); +} + static int jtagspi_read_status(struct flash_bank *bank, uint32_t *status) { uint8_t buf; - int err = jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8); + int err = jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, 0, &buf, -1); if (err == ERROR_OK) { *status = buf; - /* LOG_DEBUG("status=0x%08" PRIx32, *status); */ + LOG_DEBUG("status=0x%02" PRIx32, *status); } - return err; } static int jtagspi_wait(struct flash_bank *bank, int timeout_ms) { - uint32_t status; int64_t t0 = timeval_ms(); int64_t dt; do { dt = timeval_ms() - t0; + uint32_t status = (uint32_t)-1; int retval = jtagspi_read_status(bank, &status); if (retval != ERROR_OK) return retval; @@ -266,16 +551,15 @@ static int jtagspi_wait(struct flash_bank *bank, int timeout_ms) static int jtagspi_write_enable(struct flash_bank *bank) { - uint32_t status; - - jtagspi_cmd(bank, SPIFLASH_WRITE_ENABLE, NULL, NULL, 0); + jtagspi_cmd(bank, SPIFLASH_WRITE_ENABLE, NULL, 0, NULL, 0); + uint32_t status = (uint32_t)-1; int retval = jtagspi_read_status(bank, &status); if (retval != ERROR_OK) return retval; if ((status & SPIFLASH_WE_BIT) == 0) { - LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status); + LOG_ERROR("Cannot enable write to flash. Status=0x%02" PRIx32, status); return ERROR_FAIL; } return ERROR_OK; @@ -287,28 +571,51 @@ static int jtagspi_bulk_erase(struct flash_bank *bank) int retval; int64_t t0 = timeval_ms(); - if (info->dev->chip_erase_cmd == 0x00) + if (info->dev.chip_erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; retval = jtagspi_write_enable(bank); if (retval != ERROR_OK) return retval; - jtagspi_cmd(bank, info->dev->chip_erase_cmd, NULL, NULL, 0); - retval = jtagspi_wait(bank, bank->num_sectors*JTAGSPI_MAX_TIMEOUT); + + retval = jtagspi_cmd(bank, info->dev.chip_erase_cmd, NULL, 0, NULL, 0); + if (retval != ERROR_OK) + return retval; + + retval = jtagspi_wait(bank, bank->num_sectors * JTAGSPI_MAX_TIMEOUT); LOG_INFO("took %" PRId64 " ms", timeval_ms() - t0); return retval; } +static uint8_t *fill_addr(uint32_t addr, unsigned int addr_len, uint8_t *buffer) +{ + for (buffer += addr_len; addr_len > 0; --addr_len) { + *--buffer = addr; + addr >>= 8; + } + + return buffer; +} + static int jtagspi_sector_erase(struct flash_bank *bank, unsigned int sector) { struct jtagspi_flash_bank *info = bank->driver_priv; int retval; + uint8_t addr[sizeof(uint32_t)]; int64_t t0 = timeval_ms(); retval = jtagspi_write_enable(bank); if (retval != ERROR_OK) return retval; - jtagspi_cmd(bank, info->dev->erase_cmd, &bank->sectors[sector].offset, NULL, 0); + + /* ATXP032/064/128 use always 4-byte addresses except for 0x03 read */ + unsigned int addr_len = info->always_4byte ? 4 : info->addr_len; + + retval = jtagspi_cmd(bank, info->dev.erase_cmd, fill_addr(bank->sectors[sector].offset, addr_len, addr), + addr_len, NULL, 0); + if (retval != ERROR_OK) + return retval; + retval = jtagspi_wait(bank, JTAGSPI_MAX_TIMEOUT); LOG_INFO("sector %u took %" PRId64 " ms", sector, timeval_ms() - t0); return retval; @@ -339,8 +646,9 @@ static int jtagspi_erase(struct flash_bank *bank, unsigned int first, } } - if (first == 0 && last == (bank->num_sectors - 1) - && info->dev->chip_erase_cmd != info->dev->erase_cmd) { + if (first == 0 && last == (bank->num_sectors - 1) && + info->dev.chip_erase_cmd != 0x00 && + info->dev.chip_erase_cmd != info->dev.erase_cmd) { LOG_DEBUG("Trying bulk erase."); retval = jtagspi_bulk_erase(bank); if (retval == ERROR_OK) @@ -349,7 +657,7 @@ static int jtagspi_erase(struct flash_bank *bank, unsigned int first, LOG_WARNING("Bulk flash erase failed. Falling back to sector erase."); } - if (info->dev->erase_cmd == 0x00) + if (info->dev.erase_cmd == 0x00) return ERROR_FLASH_OPER_UNSUPPORTED; for (unsigned int sector = first; sector <= last; sector++) { @@ -374,78 +682,172 @@ static int jtagspi_protect(struct flash_bank *bank, int set, unsigned int first, static int jtagspi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct jtagspi_flash_bank *info = bank->driver_priv; + uint32_t pagesize, currsize; + uint8_t addr[sizeof(uint32_t)]; + int retval; if (!(info->probed)) { - LOG_ERROR("Flash bank not yet probed."); + LOG_ERROR("Flash bank not probed."); return ERROR_FLASH_BANK_NOT_PROBED; } - jtagspi_cmd(bank, SPIFLASH_READ, &offset, buffer, -count*8); + /* if no sectorsize, use reasonable default */ + pagesize = info->dev.sectorsize ? info->dev.sectorsize : info->dev.pagesize; + if (pagesize == 0) + pagesize = (info->dev.size_in_bytes <= SPIFLASH_DEF_PAGESIZE) ? + info->dev.size_in_bytes : SPIFLASH_DEF_PAGESIZE; + + /* ATXP032/064/128 use always 4-byte addresses except for 0x03 read */ + unsigned int addr_len = ((info->dev.read_cmd != 0x03) && info->always_4byte) ? 4 : info->addr_len; + + while (count > 0) { + /* length up to end of current page */ + currsize = ((offset + pagesize) & ~(pagesize - 1)) - offset; + /* but no more than remaining size */ + currsize = (count < currsize) ? count : currsize; + + retval = jtagspi_cmd(bank, info->dev.read_cmd, fill_addr(offset, addr_len, addr), + addr_len, buffer, -currsize); + if (retval != ERROR_OK) { + LOG_ERROR("page read error"); + return retval; + } + LOG_DEBUG("read page at 0x%08" PRIx32, offset); + offset += currsize; + buffer += currsize; + count -= currsize; + } return ERROR_OK; } static int jtagspi_page_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { + struct jtagspi_flash_bank *info = bank->driver_priv; + uint8_t addr[sizeof(uint32_t)]; int retval; retval = jtagspi_write_enable(bank); if (retval != ERROR_OK) return retval; - jtagspi_cmd(bank, SPIFLASH_PAGE_PROGRAM, &offset, (uint8_t *) buffer, count*8); + + /* ATXP032/064/128 use always 4-byte addresses except for 0x03 read */ + unsigned int addr_len = ((info->dev.read_cmd != 0x03) && info->always_4byte) ? 4 : info->addr_len; + + retval = jtagspi_cmd(bank, info->dev.pprog_cmd, fill_addr(offset, addr_len, addr), + addr_len, (uint8_t *) buffer, count); + if (retval != ERROR_OK) + return retval; return jtagspi_wait(bank, JTAGSPI_MAX_TIMEOUT); } static int jtagspi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct jtagspi_flash_bank *info = bank->driver_priv; + uint32_t pagesize, currsize; int retval; - uint32_t n, pagesize; if (!(info->probed)) { - LOG_ERROR("Flash bank not yet probed."); + LOG_ERROR("Flash bank not probed."); return ERROR_FLASH_BANK_NOT_PROBED; } /* if no write pagesize, use reasonable default */ - pagesize = info->dev->pagesize ? info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; + pagesize = info->dev.pagesize ? info->dev.pagesize : SPIFLASH_DEF_PAGESIZE; - for (n = 0; n < count; n += pagesize) { - retval = jtagspi_page_write(bank, buffer + n, offset + n, - MIN(count - n, pagesize)); + while (count > 0) { + /* length up to end of current page */ + currsize = ((offset + pagesize) & ~(pagesize - 1)) - offset; + /* but no more than remaining size */ + currsize = (count < currsize) ? count : currsize; + + retval = jtagspi_page_write(bank, buffer, offset, currsize); if (retval != ERROR_OK) { LOG_ERROR("page write error"); return retval; } - LOG_DEBUG("wrote page at 0x%08" PRIx32, offset + n); + LOG_DEBUG("wrote page at 0x%08" PRIx32, offset); + offset += currsize; + buffer += currsize; + count -= currsize; } return ERROR_OK; } -static int jtagspi_info(struct flash_bank *bank, char *buf, int buf_size) +static int jtagspi_info(struct flash_bank *bank, struct command_invocation *cmd) { struct jtagspi_flash_bank *info = bank->driver_priv; if (!(info->probed)) { - snprintf(buf, buf_size, "\nJTAGSPI flash bank not probed yet\n"); + command_print_sameline(cmd, "\nJTAGSPI flash bank not probed yet\n"); return ERROR_OK; } - snprintf(buf, buf_size, "\nSPIFI flash information:\n" - " Device \'%s\' (ID 0x%08" PRIx32 ")\n", - info->dev->name, info->dev->device_id); + command_print_sameline(cmd, "flash \'%s\', device id = 0x%06" PRIx32 + ", flash size = %" PRIu32 " %sbytes\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 ")", + info->dev.name, info->dev.device_id & 0xFFFFFF, + bank->size / 4096 ? bank->size / 1024 : bank->size, + bank->size / 4096 ? "k" : "", info->dev.pagesize, + info->dev.read_cmd, info->dev.qread_cmd, + info->dev.pprog_cmd, info->dev.chip_erase_cmd, + info->dev.sectorsize / 4096 ? + info->dev.sectorsize / 1024 : info->dev.sectorsize, + info->dev.sectorsize / 4096 ? "k" : "", + info->dev.erase_cmd); return ERROR_OK; } +static const struct command_registration jtagspi_exec_command_handlers[] = { + { + .name = "set", + .handler = jtagspi_handle_set, + .mode = COMMAND_EXEC, + .usage = "bank_id name chip_size page_size read_cmd unused pprg_cmd " + "[ mass_erase_cmd ] [ sector_size sector_erase_cmd ]", + .help = "Set device parameters if not autodetected.", + }, + { + .name = "cmd", + .handler = jtagspi_handle_cmd, + .mode = COMMAND_EXEC, + .usage = "bank_id num_resp cmd_byte ...", + .help = "Send low-level command cmd_byte and following bytes, read num_bytes.", + }, + { + .name = "always_4byte", + .handler = jtagspi_handle_always_4byte, + .mode = COMMAND_EXEC, + .usage = "bank_id [ on | off ]", + .help = "Use always 4-byte address except for basic 0x03.", + }, + + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration jtagspi_command_handlers[] = { + { + .name = "jtagspi", + .mode = COMMAND_ANY, + .help = "jtagspi command group", + .usage = "", + .chain = jtagspi_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + const struct flash_driver jtagspi_flash = { .name = "jtagspi", + .commands = jtagspi_command_handlers, .flash_bank_command = jtagspi_flash_bank_command, .erase = jtagspi_erase, .protect = jtagspi_protect, .write = jtagspi_write, .read = jtagspi_read, .probe = jtagspi_probe, - .auto_probe = jtagspi_probe, + .auto_probe = jtagspi_auto_probe, .erase_check = default_flash_blank_check, .info = jtagspi_info, .free_driver_priv = default_flash_free_driver_priv, diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index e6b452e057..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 @@ -38,6 +27,7 @@ #include <helper/time_support.h> #include <target/target_type.h> #include <target/algorithm.h> +#include <target/arm_adi_v5.h> #include <target/armv7m.h> #include <target/cortex_m.h> @@ -90,12 +80,13 @@ #define FLEXRAM 0x14000000 #define MSCM_OCMDR0 0x40001400 +#define MSCM_OCMDR1 0x40001404 #define FMC_PFB01CR 0x4001f004 -#define FTFx_FSTAT 0x40020000 -#define FTFx_FCNFG 0x40020001 -#define FTFx_FCCOB3 0x40020004 -#define FTFx_FPROT3 0x40020010 -#define FTFx_FDPROT 0x40020017 +#define FTFX_FSTAT 0x40020000 +#define FTFX_FCNFG 0x40020001 +#define FTFX_FCCOB3 0x40020004 +#define FTFX_FPROT3 0x40020010 +#define FTFX_FDPROT 0x40020017 #define SIM_BASE 0x40047000 #define SIM_BASE_KL28 0x40074000 #define SIM_COPC 0x40048100 @@ -107,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 */ @@ -124,14 +117,14 @@ #define PM_CTRL_RUNM_RUN 0x00 /* Commands */ -#define FTFx_CMD_BLOCKSTAT 0x00 -#define FTFx_CMD_SECTSTAT 0x01 -#define FTFx_CMD_LWORDPROG 0x06 -#define FTFx_CMD_SECTERASE 0x09 -#define FTFx_CMD_SECTWRITE 0x0b -#define FTFx_CMD_MASSERASE 0x44 -#define FTFx_CMD_PGMPART 0x80 -#define FTFx_CMD_SETFLEXRAM 0x81 +#define FTFX_CMD_BLOCKSTAT 0x00 +#define FTFX_CMD_SECTSTAT 0x01 +#define FTFX_CMD_LWORDPROG 0x06 +#define FTFX_CMD_SECTERASE 0x09 +#define FTFX_CMD_SECTWRITE 0x0b +#define FTFX_CMD_MASSERASE 0x44 +#define FTFX_CMD_PGMPART 0x80 +#define FTFX_CMD_SETFLEXRAM 0x81 /* The older Kinetis K series uses the following SDID layout : * Bit 31-16 : 0 @@ -198,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 @@ -232,8 +228,30 @@ /* The field originally named DIEID has new name/meaning on KE1x */ #define KINETIS_SDID_PROJECTID_MASK KINETIS_SDID_DIEID_MASK -#define KINETIS_SDID_PROJECTID_KE1xF 0x00000080 -#define KINETIS_SDID_PROJECTID_KE1xZ 0x00000100 +#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; @@ -280,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, @@ -295,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 { @@ -308,6 +332,7 @@ struct kinetis_chip { enum { KINETIS_SMC, KINETIS_SMC32, + KINETIS_MC, } sysmodectrlr_type; char name[40]; @@ -396,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; @@ -422,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; @@ -786,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; @@ -862,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]); } @@ -882,9 +929,9 @@ FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command) k_chip = kinetis_get_chip(target); - if (k_chip == NULL) { + if (!k_chip) { k_chip = calloc(sizeof(struct kinetis_chip), 1); - if (k_chip == NULL) { + if (!k_chip) { LOG_ERROR("No memory"); return ERROR_FAIL; } @@ -915,11 +962,11 @@ FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command) static void kinetis_free_driver_priv(struct flash_bank *bank) { struct kinetis_flash_bank *k_bank = bank->driver_priv; - if (k_bank == NULL) + if (!k_bank) return; struct kinetis_chip *k_chip = k_bank->k_chip; - if (k_chip == NULL) + if (!k_chip) return; k_chip->num_banks--; @@ -933,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; @@ -985,7 +1032,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) } bank = calloc(sizeof(struct flash_bank), 1); - if (bank == NULL) + if (!bank) return ERROR_FAIL; bank->target = k_chip->target; @@ -1125,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; } @@ -1174,7 +1227,7 @@ COMMAND_HANDLER(kinetis_disable_wdog_handler) struct target *target = get_current_target(CMD_CTX); struct kinetis_chip *k_chip = kinetis_get_chip(target); - if (k_chip == NULL) + if (!k_chip) return ERROR_FAIL; if (CMD_ARGC > 0) @@ -1209,7 +1262,7 @@ static int kinetis_ftfx_decode_error(uint8_t fstat) static int kinetis_ftfx_clear_error(struct target *target) { /* reset error flags */ - return target_write_u8(target, FTFx_FSTAT, 0x70); + return target_write_u8(target, FTFX_FSTAT, 0x70); } @@ -1220,7 +1273,7 @@ static int kinetis_ftfx_prepare(struct target *target) /* wait until busy */ for (unsigned int i = 0; i < 50; i++) { - result = target_read_u8(target, FTFx_FSTAT, &fstat); + result = target_read_u8(target, FTFX_FSTAT, &fstat); if (result != ERROR_OK) return result; @@ -1300,7 +1353,7 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, buf_set_u32(reg_params[1].value, 0, 32, wcount); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); - buf_set_u32(reg_params[4].value, 0, 32, FTFx_FSTAT); + buf_set_u32(reg_params[4].value, 0, 32, FTFX_FSTAT); retval = target_run_flash_async_algorithm(target, buffer, wcount, 4, 0, NULL, @@ -1314,12 +1367,12 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, LOG_ERROR("Error writing flash at %08" PRIx32, end_address); - retval = target_read_u8(target, FTFx_FSTAT, &fstat); + retval = target_read_u8(target, FTFX_FSTAT, &fstat); if (retval == ERROR_OK) { retval = kinetis_ftfx_decode_error(fstat); /* reset error flags */ - target_write_u8(target, FTFx_FSTAT, 0x70); + target_write_u8(target, FTFX_FSTAT, 0x70); } } else if (retval != ERROR_OK) LOG_ERROR("Error executing kinetis Flash programming algorithm"); @@ -1369,7 +1422,7 @@ static int kinetis_protect_check(struct flash_bank *bank) if (k_bank->flash_class == FC_PFLASH) { /* read protection register */ - result = target_read_u32(bank->target, FTFx_FPROT3, &fprot); + result = target_read_u32(bank->target, FTFX_FPROT3, &fprot); if (result != ERROR_OK) return result; @@ -1379,7 +1432,7 @@ static int kinetis_protect_check(struct flash_bank *bank) uint8_t fdprot; /* read protection register */ - result = target_read_u8(bank->target, FTFx_FDPROT, &fdprot); + result = target_read_u8(bank->target, FTFX_FDPROT, &fdprot); if (result != ERROR_OK) return result; @@ -1428,7 +1481,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) k_bank = &(k_chip->banks[bank_idx]); bank_iter = k_bank->bank; - if (bank_iter == NULL) { + if (!bank_iter) { LOG_WARNING("Missing bank %u configuration, FCF protection flags may be incomplete", bank_idx); continue; } @@ -1475,18 +1528,18 @@ static int kinetis_ftfx_command(struct target *target, uint8_t fcmd, uint32_t fa uint8_t fstat; int64_t ms_timeout = timeval_ms() + 250; - result = target_write_memory(target, FTFx_FCCOB3, 4, 3, command); + result = target_write_memory(target, FTFX_FCCOB3, 4, 3, command); if (result != ERROR_OK) return result; /* start command */ - result = target_write_u8(target, FTFx_FSTAT, 0x80); + result = target_write_u8(target, FTFX_FSTAT, 0x80); if (result != ERROR_OK) return result; /* wait for done */ do { - result = target_read_u8(target, FTFx_FSTAT, &fstat); + result = target_read_u8(target, FTFX_FSTAT, &fstat); if (result != ERROR_OK) return result; @@ -1528,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; } @@ -1538,7 +1602,7 @@ static int kinetis_check_run_mode(struct kinetis_chip *k_chip) uint8_t pmstat; struct target *target; - if (k_chip == NULL) { + if (!k_chip) { LOG_ERROR("Chip not probed."); return ERROR_FAIL; } @@ -1568,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; @@ -1609,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; } @@ -1641,7 +1715,7 @@ static int kinetis_erase(struct flash_bank *bank, unsigned int first, */ for (unsigned int i = first; i <= last; i++) { /* set command and sector address */ - result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTERASE, k_bank->prog_base + bank->sectors[i].offset, + result = kinetis_ftfx_command(bank->target, FTFX_CMD_SECTERASE, k_bank->prog_base + bank->sectors[i].offset, 0, 0, 0, 0, 0, 0, 0, 0, NULL); if (result != ERROR_OK) { @@ -1679,7 +1753,7 @@ static int kinetis_make_ram_ready(struct target *target) uint8_t ftfx_fcnfg; /* check if ram ready */ - result = target_read_u8(target, FTFx_FCNFG, &ftfx_fcnfg); + result = target_read_u8(target, FTFX_FCNFG, &ftfx_fcnfg); if (result != ERROR_OK) return result; @@ -1687,13 +1761,13 @@ static int kinetis_make_ram_ready(struct target *target) return ERROR_OK; /* ram ready */ /* make flex ram available */ - result = kinetis_ftfx_command(target, FTFx_CMD_SETFLEXRAM, 0x00ff0000, + result = kinetis_ftfx_command(target, FTFX_CMD_SETFLEXRAM, 0x00ff0000, 0, 0, 0, 0, 0, 0, 0, 0, NULL); if (result != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* check again */ - result = target_read_u8(target, FTFx_FCNFG, &ftfx_fcnfg); + result = target_read_u8(target, FTFX_FCNFG, &ftfx_fcnfg); if (result != ERROR_OK) return result; @@ -1766,7 +1840,7 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer } /* execute section-write command */ - result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTWRITE, + result = kinetis_ftfx_command(bank->target, FTFX_CMD_SECTWRITE, k_bank->prog_base + offset - align_begin, chunk_count>>8, chunk_count, 0, 0, 0, 0, 0, 0, &ftfx_fstat); @@ -1840,7 +1914,7 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, uint32_t old_count = count; count = (old_count | 3) + 1; new_buffer = malloc(count); - if (new_buffer == NULL) { + if (!new_buffer) { LOG_ERROR("odd number of bytes to write and no memory " "for padding buffer"); return ERROR_FAIL; @@ -1869,7 +1943,7 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, LOG_DEBUG("write longword @ %08" PRIx32, (uint32_t)(bank->base + offset)); - result = kinetis_ftfx_command(bank->target, FTFx_CMD_LWORDPROG, k_bank->prog_base + offset, + result = kinetis_ftfx_command(bank->target, FTFX_CMD_LWORDPROG, k_bank->prog_base + offset, buffer[3], buffer[2], buffer[1], buffer[0], 0, 0, 0, 0, &ftfx_fstat); @@ -2018,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; @@ -2134,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; @@ -2405,8 +2665,8 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) k_chip->watchdog_type = KINETIS_WDOG32_KE1X; switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK | KINETIS_SDID_PROJECTID_MASK)) { - case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX4 | KINETIS_SDID_PROJECTID_KE1xZ: - case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX5 | KINETIS_SDID_PROJECTID_KE1xZ: + case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX4 | KINETIS_SDID_PROJECTID_KE1XZ: + case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX5 | KINETIS_SDID_PROJECTID_KE1XZ: /* KE1xZ: FTFE, 2kB sectors */ k_chip->pflash_sector_size = 2<<10; k_chip->nvm_sector_size = 2<<10; @@ -2420,9 +2680,9 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) familyid, subfamid, cpu_mhz / 10); break; - case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX4 | KINETIS_SDID_PROJECTID_KE1xF: - case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX6 | KINETIS_SDID_PROJECTID_KE1xF: - case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX8 | KINETIS_SDID_PROJECTID_KE1xF: + case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX4 | KINETIS_SDID_PROJECTID_KE1XF: + case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX6 | KINETIS_SDID_PROJECTID_KE1XF: + case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX8 | KINETIS_SDID_PROJECTID_KE1XF: /* KE1xF: FTFE, 4kB sectors */ k_chip->pflash_sector_size = 4<<10; k_chip->nvm_sector_size = 2<<10; @@ -2614,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; @@ -2645,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; } @@ -2717,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); @@ -2778,7 +3047,7 @@ static int kinetis_auto_probe(struct flash_bank *bank) return kinetis_probe(bank); } -static int kinetis_info(struct flash_bank *bank, char *buf, int buf_size) +static int kinetis_info(struct flash_bank *bank, struct command_invocation *cmd) { const char *bank_class_names[] = { "(ANY)", "PFlash", "FlexNVM", "FlexRAM" @@ -2788,7 +3057,7 @@ static int kinetis_info(struct flash_bank *bank, char *buf, int buf_size) struct kinetis_chip *k_chip = k_bank->k_chip; uint32_t size_k = bank->size / 1024; - snprintf(buf, buf_size, + command_print_sameline(cmd, "%s %s: %" PRIu32 "k %s bank %s at " TARGET_ADDR_FMT, bank->driver->name, k_chip->name, size_k, bank_class_names[k_bank->flash_class], @@ -2803,7 +3072,7 @@ static int kinetis_blank_check(struct flash_bank *bank) struct kinetis_chip *k_chip = k_bank->k_chip; int result; - /* suprisingly blank check does not work in VLPR and HSRUN modes */ + /* surprisingly blank check does not work in VLPR and HSRUN modes */ result = kinetis_check_run_mode(k_chip); if (result != ERROR_OK) return result; @@ -2827,7 +3096,7 @@ static int kinetis_blank_check(struct flash_bank *bank) if (use_block_cmd) { /* check if whole bank is blank */ - result = kinetis_ftfx_command(bank->target, FTFx_CMD_BLOCKSTAT, k_bank->prog_base, + result = kinetis_ftfx_command(bank->target, FTFX_CMD_BLOCKSTAT, k_bank->prog_base, 0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); if (result != ERROR_OK) @@ -2840,7 +3109,7 @@ static int kinetis_blank_check(struct flash_bank *bank) /* the whole bank is not erased, check sector-by-sector */ for (unsigned int i = 0; i < bank->num_sectors; i++) { /* normal margin */ - result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTSTAT, + result = kinetis_ftfx_command(bank->target, FTFX_CMD_SECTSTAT, k_bank->prog_base + bank->sectors[i].offset, 1, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); @@ -2884,19 +3153,24 @@ 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; else if (strcmp(CMD_ARGV[0], "eebkp") == 0) sz_type = EEBKP_SIZE; - par = strtoul(CMD_ARGV[1], NULL, 10); + COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], par); while (par >> (log2 + 3)) log2++; } switch (sz_type) { case SHOW_INFO: - if (k_chip == NULL) { + if (!k_chip) { LOG_ERROR("Chip not probed."); return ERROR_FAIL; } @@ -2945,11 +3219,13 @@ COMMAND_HANDLER(kinetis_nvm_partition) break; } - if (CMD_ARGC == 3) - ee1 = ee2 = strtoul(CMD_ARGV[2], NULL, 10) / 2; - else if (CMD_ARGC >= 4) { - ee1 = strtoul(CMD_ARGV[2], NULL, 10); - ee2 = strtoul(CMD_ARGV[3], NULL, 10); + if (CMD_ARGC == 3) { + unsigned long eex; + COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], eex); + ee1 = ee2 = eex / 2; + } else if (CMD_ARGC >= 4) { + COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], ee1); + COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[3], ee2); } enable = ee1 + ee2 > 0; @@ -2992,7 +3268,7 @@ COMMAND_HANDLER(kinetis_nvm_partition) if (result != ERROR_OK) return result; - result = kinetis_ftfx_command(target, FTFx_CMD_PGMPART, load_flex_ram, + result = kinetis_ftfx_command(target, FTFX_CMD_PGMPART, load_flex_ram, ee_size_code, flex_nvm_partition_code, 0, 0, 0, 0, 0, 0, NULL); if (result != ERROR_OK) @@ -3044,7 +3320,7 @@ COMMAND_HANDLER(kinetis_fopt_handler) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { - fcf_fopt = (uint8_t)strtoul(CMD_ARGV[0], NULL, 0); + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], fcf_fopt); } else { command_print(CMD, "FCF_FOPT 0x%02" PRIx8, fcf_fopt); } diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c index 349b2564d3..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 @@ -41,6 +30,7 @@ #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> +#include <target/arm_adi_v5.h> #include <target/armv7m.h> #include <target/cortex_m.h> @@ -146,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; @@ -166,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; @@ -434,7 +438,7 @@ static int kinetis_ke_prepare_flash(struct flash_bank *bank) return ERROR_OK; } -int kinetis_ke_stop_watchdog(struct target *target) +static int kinetis_ke_stop_watchdog(struct target *target) { struct working_area *watchdog_algorithm; struct armv7m_algorithm armv7m_info; @@ -932,39 +936,6 @@ static int kinetis_ke_ftmrx_command(struct flash_bank *bank, uint8_t count, return ERROR_OK; } -COMMAND_HANDLER(kinetis_ke_securing_test) -{ - int result; - struct target *target = get_current_target(CMD_CTX); - struct flash_bank *bank = NULL; - uint32_t address; - - uint8_t FCCOBIX[2], FCCOBHI[2], FCCOBLO[2], fstat; - - result = get_flash_bank_by_addr(target, 0x00000000, true, &bank); - if (result != ERROR_OK) - return result; - - assert(bank != NULL); - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - address = bank->base + 0x00000400; - - FCCOBIX[0] = 0; - FCCOBHI[0] = FTMRX_CMD_ERASESECTOR; - FCCOBLO[0] = address >> 16; - - FCCOBIX[1] = 1; - FCCOBHI[1] = address >> 8; - FCCOBLO[1] = address; - - return kinetis_ke_ftmrx_command(bank, 2, FCCOBIX, FCCOBHI, FCCOBLO, &fstat); -} - static int kinetis_ke_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { @@ -1000,8 +971,6 @@ static int kinetis_ke_erase(struct flash_bank *bank, unsigned int first, return ERROR_FLASH_OPERATION_FAILED; } - bank->sectors[i].is_erased = 1; - if (i == 2) fcf_erased = true; } @@ -1046,7 +1015,7 @@ static int kinetis_ke_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t old_count = count; count = (old_count | 3) + 1; new_buffer = malloc(count); - if (new_buffer == NULL) { + if (!new_buffer) { LOG_ERROR("odd number of bytes to write and no memory " "for padding buffer"); return ERROR_FAIL; @@ -1171,10 +1140,9 @@ static int kinetis_ke_auto_probe(struct flash_bank *bank) return kinetis_ke_probe(bank); } -static int kinetis_ke_info(struct flash_bank *bank, char *buf, int buf_size) +static int kinetis_ke_info(struct flash_bank *bank, struct command_invocation *cmd) { - (void) snprintf(buf, buf_size, - "%s driver for flash bank %s at " TARGET_ADDR_FMT, + command_print_sameline(cmd, "%s driver for flash bank %s at " TARGET_ADDR_FMT, bank->driver->name, bank->name, bank->base); return ERROR_OK; @@ -1243,24 +1211,17 @@ static const struct command_registration kinetis_ke_security_command_handlers[] { .name = "check_security", .mode = COMMAND_EXEC, - .help = "", + .help = "Check status of device security lock", .usage = "", .handler = kinetis_ke_check_flash_security_status, }, { .name = "mass_erase", .mode = COMMAND_EXEC, - .help = "", + .help = "Issue a complete flash erase via the MDM-AP", .usage = "", .handler = kinetis_ke_mdm_mass_erase, }, - { - .name = "test_securing", - .mode = COMMAND_EXEC, - .help = "", - .usage = "", - .handler = kinetis_ke_securing_test, - }, COMMAND_REGISTRATION_DONE }; @@ -1268,7 +1229,7 @@ static const struct command_registration kinetis_ke_exec_command_handlers[] = { { .name = "mdm", .mode = COMMAND_ANY, - .help = "", + .help = "MDM-AP command group", .usage = "", .chain = kinetis_ke_security_command_handlers, }, @@ -1286,7 +1247,7 @@ static const struct command_registration kinetis_ke_command_handler[] = { { .name = "kinetis_ke", .mode = COMMAND_ANY, - .help = "Kinetis KE NAND flash controller commands", + .help = "Kinetis KE flash controller commands", .usage = "", .chain = kinetis_ke_exec_command_handlers, }, diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c index 942ef555c9..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 @@ -281,18 +270,18 @@ #define IAP_CODE_LEN 0x34 -#define LPC11xx_REG_SECTORS 24 +#define LPC11XX_REG_SECTORS 24 typedef enum { - lpc2000_v1, - lpc2000_v2, - lpc1700, - lpc4300, - lpc800, - lpc1100, - lpc1500, - lpc54100, - lpc_auto, + LPC2000_V1, + LPC2000_V2, + LPC1700, + LPC4300, + LPC800, + LPC1100, + LPC1500, + LPC54100, + LPC_AUTO, } lpc2000_variant; struct lpc2000_flash_bank { @@ -342,7 +331,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) /* default to a 4096 write buffer */ lpc2000_info->cmd51_max_buffer = 4096; - if (lpc2000_info->variant == lpc2000_v1) { + if (lpc2000_info->variant == LPC2000_V1) { lpc2000_info->cmd51_dst_boundary = 512; lpc2000_info->checksum_vector = 5; lpc2000_info->iap_max_stack = 128; @@ -387,7 +376,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } - } else if (lpc2000_info->variant == lpc2000_v2) { + } else if (lpc2000_info->variant == LPC2000_V2) { lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->checksum_vector = 5; lpc2000_info->iap_max_stack = 128; @@ -453,7 +442,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) bank->sectors[i].is_protected = 1; } } - } else if (lpc2000_info->variant == lpc1700) { + } else if (lpc2000_info->variant == LPC1700) { lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 128; @@ -502,7 +491,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } - } else if (lpc2000_info->variant == lpc4300) { + } else if (lpc2000_info->variant == LPC4300) { lpc2000_info->cmd51_dst_boundary = 512; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 208; @@ -533,7 +522,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) bank->sectors[i].is_protected = 1; } - } else if (lpc2000_info->variant == lpc800) { + } else if (lpc2000_info->variant == LPC800) { lpc2000_info->cmd51_dst_boundary = 64; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 208; /* 148byte for LPC81x,208byte for LPC82x. */ @@ -577,7 +566,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) bank->sectors[i].is_protected = 1; } - } else if (lpc2000_info->variant == lpc1100) { + } else if (lpc2000_info->variant == LPC1100) { lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 128; @@ -590,9 +579,9 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) unsigned int large_sectors = 0; unsigned int normal_sectors = bank->size / 4096; - if (normal_sectors > LPC11xx_REG_SECTORS) { - large_sectors = (normal_sectors - LPC11xx_REG_SECTORS) / 8; - normal_sectors = LPC11xx_REG_SECTORS; + if (normal_sectors > LPC11XX_REG_SECTORS) { + large_sectors = (normal_sectors - LPC11XX_REG_SECTORS) / 8; + normal_sectors = LPC11XX_REG_SECTORS; } bank->num_sectors = normal_sectors + large_sectors; @@ -601,13 +590,13 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) for (unsigned int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; - bank->sectors[i].size = (i < LPC11xx_REG_SECTORS ? 4 : 32) * 1024; + bank->sectors[i].size = (i < LPC11XX_REG_SECTORS ? 4 : 32) * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } - } else if (lpc2000_info->variant == lpc1500) { + } else if (lpc2000_info->variant == LPC1500) { lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 128; @@ -638,7 +627,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) bank->sectors[i].is_protected = 1; } - } else if (lpc2000_info->variant == lpc54100) { + } else if (lpc2000_info->variant == LPC54100) { lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 128; @@ -697,18 +686,18 @@ static int lpc2000_iap_working_area_init(struct flash_bank *bank, struct working /* write IAP code to working area */ switch (lpc2000_info->variant) { - case lpc800: - case lpc1100: - case lpc1500: - case lpc1700: - case lpc4300: - case lpc54100: - case lpc_auto: + case LPC800: + case LPC1100: + case LPC1500: + case LPC1700: + case LPC4300: + case LPC54100: + case LPC_AUTO: target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0)); break; - case lpc2000_v1: - case lpc2000_v2: + case LPC2000_V1: + case LPC2000_V2: target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0)); break; @@ -740,28 +729,28 @@ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_wo uint32_t iap_entry_point = 0; /* to make compiler happier */ switch (lpc2000_info->variant) { - case lpc800: - case lpc1100: - case lpc1700: - case lpc_auto: + case LPC800: + case LPC1100: + case LPC1700: + case LPC_AUTO: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; iap_entry_point = 0x1fff1ff1; break; - case lpc1500: - case lpc54100: + case LPC1500: + case LPC54100: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; iap_entry_point = 0x03000205; break; - case lpc2000_v1: - case lpc2000_v2: + case LPC2000_V1: + case LPC2000_V2: arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; iap_entry_point = 0x7ffffff1; break; - case lpc4300: + case LPC4300: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; /* read out IAP entry point from ROM driver table at 0x10400100 */ @@ -802,13 +791,13 @@ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_wo buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point); switch (lpc2000_info->variant) { - case lpc800: - case lpc1100: - case lpc1500: - case lpc1700: - case lpc4300: - case lpc54100: - case lpc_auto: + case LPC800: + case LPC1100: + case LPC1500: + case LPC1700: + case LPC4300: + case LPC54100: + case LPC_AUTO: /* IAP stack */ init_reg_param(®_params[3], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, @@ -822,8 +811,8 @@ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_wo target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, 0, 10000, &armv7m_info); break; - case lpc2000_v1: - case lpc2000_v2: + case LPC2000_V1: + case LPC2000_V2: /* IAP stack */ init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, @@ -879,7 +868,7 @@ static int lpc2000_iap_blank_check(struct flash_bank *bank, unsigned int first, return retval; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; - if (lpc2000_info->variant == lpc4300) + if (lpc2000_info->variant == LPC4300) param_table[2] = lpc2000_info->lpc4300_bank; for (unsigned int i = first; i <= last && retval == ERROR_OK; i++) { @@ -929,23 +918,23 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command) bank->driver_priv = lpc2000_info; if (strcmp(CMD_ARGV[6], "lpc2000_v1") == 0) { - lpc2000_info->variant = lpc2000_v1; + lpc2000_info->variant = LPC2000_V1; } else if (strcmp(CMD_ARGV[6], "lpc2000_v2") == 0) { - lpc2000_info->variant = lpc2000_v2; + lpc2000_info->variant = LPC2000_V2; } else if (strcmp(CMD_ARGV[6], "lpc1700") == 0 || strcmp(CMD_ARGV[6], "lpc4000") == 0) { - lpc2000_info->variant = lpc1700; + lpc2000_info->variant = LPC1700; } else if (strcmp(CMD_ARGV[6], "lpc1800") == 0 || strcmp(CMD_ARGV[6], "lpc4300") == 0) { - lpc2000_info->variant = lpc4300; + lpc2000_info->variant = LPC4300; } else if (strcmp(CMD_ARGV[6], "lpc800") == 0) { - lpc2000_info->variant = lpc800; + lpc2000_info->variant = LPC800; } else if (strcmp(CMD_ARGV[6], "lpc1100") == 0) { - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; } else if (strcmp(CMD_ARGV[6], "lpc1500") == 0) { - lpc2000_info->variant = lpc1500; + lpc2000_info->variant = LPC1500; } else if (strcmp(CMD_ARGV[6], "lpc54100") == 0) { - lpc2000_info->variant = lpc54100; + lpc2000_info->variant = LPC54100; } else if (strcmp(CMD_ARGV[6], "auto") == 0) { - lpc2000_info->variant = lpc_auto; + lpc2000_info->variant = LPC_AUTO; } else { LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV[6]); free(lpc2000_info); @@ -993,7 +982,7 @@ static int lpc2000_erase(struct flash_bank *bank, unsigned int first, param_table[0] = first; param_table[1] = last; - if (lpc2000_info->variant == lpc4300) + if (lpc2000_info->variant == LPC4300) param_table[2] = lpc2000_info->lpc4300_bank; else param_table[2] = lpc2000_info->cclk; @@ -1006,7 +995,7 @@ static int lpc2000_erase(struct flash_bank *bank, unsigned int first, if (retval != ERROR_OK) return retval; - if (lpc2000_info->variant == lpc4300) + if (lpc2000_info->variant == LPC4300) /* Init IAP Anyway */ lpc2000_iap_call(bank, iap_working_area, 49, param_table, result_table); @@ -1030,7 +1019,7 @@ static int lpc2000_erase(struct flash_bank *bank, unsigned int first, if (retval == ERROR_OK) { /* Erase sectors */ param_table[2] = lpc2000_info->cclk; - if (lpc2000_info->variant == lpc4300) + if (lpc2000_info->variant == LPC4300) param_table[3] = lpc2000_info->lpc4300_bank; status_code = lpc2000_iap_call(bank, iap_working_area, 52, param_table, result_table); @@ -1103,9 +1092,9 @@ static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32); if (original_value != checksum) { - LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") to be written to flash is " + LOG_WARNING("Boot verification checksum in image (0x%8.8" PRIx32 ") to be written to flash is " "different from calculated vector checksum (0x%8.8" PRIx32 ").", original_value, checksum); - LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector " + LOG_WARNING("OpenOCD will write the correct checksum. To remove this warning modify build tools on developer PC to inject correct LPC vector " "checksum."); } @@ -1134,7 +1123,7 @@ static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ uint32_t param_table[5] = {0}; uint32_t result_table[4]; - if (lpc2000_info->variant == lpc4300) + if (lpc2000_info->variant == LPC4300) /* Init IAP Anyway */ lpc2000_iap_call(bank, iap_working_area, 49, param_table, result_table); @@ -1149,7 +1138,7 @@ static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ param_table[0] = first_sector; param_table[1] = last_sector; - if (lpc2000_info->variant == lpc4300) + if (lpc2000_info->variant == LPC4300) param_table[2] = lpc2000_info->lpc4300_bank; else param_table[2] = lpc2000_info->cclk; @@ -1280,7 +1269,7 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) switch (part_id) { case LPC1110_1: case LPC1110_2: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 4 * 1024; break; @@ -1296,7 +1285,7 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC11E11_101: case LPC1311: case LPC1311_1: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 8 * 1024; break; @@ -1316,7 +1305,7 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC11U12_201_1: case LPC11U12_201_2: case LPC1342: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 16 * 1024; break; @@ -1331,7 +1320,7 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC11U13_201_1: case LPC11U13_201_2: case LPC11U23_301: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 24 * 1024; break; @@ -1359,18 +1348,18 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC1343: case LPC1343_1: case LPC1345: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 32 * 1024; break; case LPC1751_1: case LPC1751_2: - lpc2000_info->variant = lpc1700; + lpc2000_info->variant = LPC1700; bank->size = 32 * 1024; break; case LPC11U34_311: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 40 * 1024; break; @@ -1378,12 +1367,12 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC11U34_421: case LPC1316: case LPC1346: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 48 * 1024; break; case LPC1114_333_1: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 56 * 1024; break; @@ -1394,19 +1383,19 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC11U66: case LPC1317: case LPC1347: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 64 * 1024; break; case LPC1752: case LPC4072: - lpc2000_info->variant = lpc1700; + lpc2000_info->variant = LPC1700; bank->size = 64 * 1024; break; case LPC11E36_501: case LPC11U36_401: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 96 * 1024; break; @@ -1419,7 +1408,7 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC11E68: case LPC11U67_1: case LPC11U67_2: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 128 * 1024; break; @@ -1427,13 +1416,13 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC1764: case LPC1774: case LPC4074: - lpc2000_info->variant = lpc1700; + lpc2000_info->variant = LPC1700; bank->size = 128 * 1024; break; case LPC11U68_1: case LPC11U68_2: - lpc2000_info->variant = lpc1100; + lpc2000_info->variant = LPC1100; bank->size = 256 * 1024; break; @@ -1445,7 +1434,7 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC1785: case LPC1786: case LPC4076: - lpc2000_info->variant = lpc1700; + lpc2000_info->variant = LPC1700; bank->size = 256 * 1024; break; @@ -1460,17 +1449,17 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC1788: case LPC4078: case LPC4088: - lpc2000_info->variant = lpc1700; + lpc2000_info->variant = LPC1700; bank->size = 512 * 1024; break; case LPC810_021: - lpc2000_info->variant = lpc800; + lpc2000_info->variant = LPC800; bank->size = 4 * 1024; break; case LPC811_001: - lpc2000_info->variant = lpc800; + lpc2000_info->variant = LPC800; bank->size = 8 * 1024; break; @@ -1480,13 +1469,13 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC812_101_3: case LPC822_101: case LPC822_101_1: - lpc2000_info->variant = lpc800; + lpc2000_info->variant = LPC800; bank->size = 16 * 1024; break; case LPC824_201: case LPC824_201_1: - lpc2000_info->variant = lpc800; + lpc2000_info->variant = LPC800; bank->size = 32 * 1024; break; @@ -1494,7 +1483,7 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case NHS3100: case NHS3152: case NHS3153: - lpc2000_info->variant = lpc800; + lpc2000_info->variant = LPC800; bank->size = 30 * 1024; break; @@ -1505,7 +1494,7 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) case LPC845_301_1: case LPC845_301_2: case LPC845_301_3: - lpc2000_info->variant = lpc800; + lpc2000_info->variant = LPC800; bank->size = 64 * 1024; break; @@ -1524,11 +1513,11 @@ static int lpc2000_probe(struct flash_bank *bank) struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; if (!lpc2000_info->probed) { - if (lpc2000_info->variant == lpc_auto) { + if (lpc2000_info->variant == LPC_AUTO) { status = lpc2000_auto_probe_flash(bank); if (status != ERROR_OK) return status; - } else if (lpc2000_info->variant == lpc1100 || lpc2000_info->variant == lpc1700) { + } else if (lpc2000_info->variant == LPC1100 || lpc2000_info->variant == LPC1700) { status = get_lpc2000_part_id(bank, &part_id); if (status == LPC2000_CMD_SUCCESS) LOG_INFO("If auto-detection fails for this part, please email " @@ -1552,12 +1541,12 @@ static int lpc2000_erase_check(struct flash_bank *bank) return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1); } -static int get_lpc2000_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_lpc2000_info(struct flash_bank *bank, struct command_invocation *cmd) { struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; - snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %" PRIu32 "kHz", lpc2000_info->variant, - lpc2000_info->cclk); + command_print_sameline(cmd, "lpc2000 flash driver variant: %i, clk: %" PRIu32 "kHz", + lpc2000_info->variant, lpc2000_info->cclk); return ERROR_OK; } @@ -1569,7 +1558,7 @@ COMMAND_HANDLER(lpc2000_handle_part_id_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (bank->target->state != TARGET_HALTED) { 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 c8e885aba1..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 @@ -453,8 +442,8 @@ static int lpc2900_write_index_page(struct flash_bank *bank, /** * Calculate FPTR.TR register value for desired program/erase time. * - * @param clock System clock in Hz - * @param time Program/erase time in µs + * @param clock_var System clock in Hz + * @param time_var Program/erase time in µs */ static uint32_t lpc2900_calc_tr(uint32_t clock_var, uint32_t time_var) { @@ -487,7 +476,7 @@ COMMAND_HANDLER(lpc2900_handle_signature_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (bank->target->state != TARGET_HALTED) { @@ -522,7 +511,7 @@ COMMAND_HANDLER(lpc2900_handle_read_custom_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; @@ -584,7 +573,7 @@ COMMAND_HANDLER(lpc2900_handle_password_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; @@ -614,7 +603,7 @@ COMMAND_HANDLER(lpc2900_handle_write_custom_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; @@ -635,9 +624,9 @@ COMMAND_HANDLER(lpc2900_handle_write_custom_command) /* The image will always start at offset 0 */ struct image image; - image.base_address_set = 1; + image.base_address_set = true; image.base_address = 0; - image.start_address_set = 0; + image.start_address_set = false; const char *filename = CMD_ARGV[1]; const char *type = (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL; @@ -713,7 +702,7 @@ COMMAND_HANDLER(lpc2900_handle_secure_sector_command) /* Get the bank descriptor */ struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; @@ -794,7 +783,7 @@ COMMAND_HANDLER(lpc2900_handle_secure_jtag_command) /* Get the bank descriptor */ struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; @@ -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 dd1c63d747..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 @@ -66,7 +55,7 @@ FLASH_BANK_COMMAND_HANDLER(lpcspifi_flash_bank_command) return ERROR_COMMAND_SYNTAX_ERROR; lpcspifi_info = malloc(sizeof(struct lpcspifi_flash_bank)); - if (lpcspifi_info == NULL) { + if (!lpcspifi_info) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } @@ -894,7 +883,7 @@ static int lpcspifi_probe(struct flash_bank *bank) /* create and fill sectors array */ bank->num_sectors = lpcspifi_info->dev->size_in_bytes / sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); - if (sectors == NULL) { + if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } @@ -926,17 +915,16 @@ static int lpcspifi_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int get_lpcspifi_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_lpcspifi_info(struct flash_bank *bank, struct command_invocation *cmd) { struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; if (!(lpcspifi_info->probed)) { - snprintf(buf, buf_size, - "\nSPIFI flash bank not probed yet\n"); + command_print_sameline(cmd, "\nSPIFI flash bank not probed yet\n"); return ERROR_OK; } - snprintf(buf, buf_size, "\nSPIFI flash information:\n" + command_print_sameline(cmd, "\nSPIFI flash information:\n" " Device \'%s\' (ID 0x%08" PRIx32 ")\n", lpcspifi_info->dev->name, lpcspifi_info->dev->device_id); diff --git a/src/flash/nor/max32xxx.c b/src/flash/nor/max32xxx.c index 9a5e83fa05..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 @@ -21,6 +10,7 @@ #endif #include "imp.h" +#include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> @@ -82,7 +72,7 @@ struct max32xxx_flash_bank { /* see contrib/loaders/flash/max32xxx/max32xxx.s for src */ static const uint8_t write_code[] = { -#include "../../contrib/loaders/flash/max32xxx/max32xxx.inc" +#include "../../../contrib/loaders/flash/max32xxx/max32xxx.inc" }; /* Config Command: flash bank name driver base size chip_width bus_width target [driver_option] @@ -113,17 +103,14 @@ FLASH_BANK_COMMAND_HANDLER(max32xxx_flash_bank_command) return ERROR_OK; } -static int get_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_info(struct flash_bank *bank, struct command_invocation *cmd) { - int printed; struct max32xxx_flash_bank *info = bank->driver_priv; if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; - printed = snprintf(buf, buf_size, "\nMaxim Integrated max32xxx flash driver\n"); - buf += printed; - buf_size -= printed; + command_print_sameline(cmd, "\nMaxim Integrated max32xxx flash driver\n"); return ERROR_OK; } @@ -305,8 +292,6 @@ static int max32xxx_erase(struct flash_bank *bank, unsigned int first, max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } - - bank->sectors[banknr].is_erased = 1; } if (!erased) { @@ -771,16 +756,12 @@ COMMAND_HANDLER(max32xxx_handle_mass_erase_command) return ERROR_OK; } - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; - if (max32xxx_mass_erase(bank) == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - + if (max32xxx_mass_erase(bank) == ERROR_OK) command_print(CMD, "max32xxx mass erase complete"); - } else + else command_print(CMD, "max32xxx mass erase failed"); return ERROR_OK; @@ -799,12 +780,12 @@ COMMAND_HANDLER(max32xxx_handle_protection_set_command) } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; info = bank->driver_priv; /* Convert the range to the page numbers */ - if (1 != sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr)) { + if (sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr) != 1) { LOG_WARNING("Error parsing address"); command_print(CMD, "max32xxx protection_set <bank> <addr> <size>"); return ERROR_FAIL; @@ -812,7 +793,7 @@ COMMAND_HANDLER(max32xxx_handle_protection_set_command) /* Mask off the top portion on the address */ addr = (addr & 0x0FFFFFFF); - if (1 != sscanf(CMD_ARGV[2], "0x%"SCNx32, &len)) { + if (sscanf(CMD_ARGV[2], "0x%"SCNx32, &len) != 1) { LOG_WARNING("Error parsing length"); command_print(CMD, "max32xxx protection_set <bank> <addr> <size>"); return ERROR_FAIL; @@ -855,12 +836,12 @@ COMMAND_HANDLER(max32xxx_handle_protection_clr_command) } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; info = bank->driver_priv; /* Convert the range to the page numbers */ - if (1 != sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr)) { + if (sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr) != 1) { LOG_WARNING("Error parsing address"); command_print(CMD, "max32xxx protection_clr <bank> <addr> <size>"); return ERROR_FAIL; @@ -868,7 +849,7 @@ COMMAND_HANDLER(max32xxx_handle_protection_clr_command) /* Mask off the top portion on the address */ addr = (addr & 0x0FFFFFFF); - if (1 != sscanf(CMD_ARGV[2], "0x%"SCNx32, &len)) { + if (sscanf(CMD_ARGV[2], "0x%"SCNx32, &len) != 1) { LOG_WARNING("Error parsing length"); command_print(CMD, "max32xxx protection_clr <bank> <addr> <size>"); return ERROR_FAIL; @@ -910,13 +891,13 @@ COMMAND_HANDLER(max32xxx_handle_protection_check_command) } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; info = bank->driver_priv; /* Update the protection array */ retval = max32xxx_protect_check(bank); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_WARNING("Error updating the protection array"); return retval; } diff --git a/src/flash/nor/mdr.c b/src/flash/nor/mdr.c index 2518c229b2..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 @@ -197,7 +186,6 @@ static int mdr_erase(struct flash_bank *bank, unsigned int first, if (retval != ERROR_OK) goto reset_pg_and_lock; } - bank->sectors[i].is_erased = 1; } reset_pg_and_lock: @@ -328,7 +316,7 @@ static int mdr_write(struct flash_bank *bank, const uint8_t *buffer, int rem = count % 4; if (rem) { new_buffer = malloc(count + rem); - if (new_buffer == NULL) { + if (!new_buffer) { LOG_ERROR("odd number of bytes to write and no memory for padding buffer"); return ERROR_FAIL; } @@ -597,11 +585,11 @@ static int mdr_auto_probe(struct flash_bank *bank) return mdr_probe(bank); } -static int get_mdr_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_mdr_info(struct flash_bank *bank, struct command_invocation *cmd) { struct mdr_flash_bank *mdr_info = bank->driver_priv; - snprintf(buf, buf_size, "MDR32Fx - %s", - mdr_info->mem_type ? "info memory" : "main memory"); + command_print_sameline(cmd, "MDR32Fx - %s", + mdr_info->mem_type ? "info memory" : "main memory"); return ERROR_OK; } diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c index 3293e61290..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/>. * ***************************************************************************/ /* @@ -37,7 +26,7 @@ #define QSPI_W_EN (0x1) #define QSPI_SS_DISABLE (0x0) #define QSPI_SS_ENABLE (0x1) -#define WRITE_DISBALE (0x0) +#define WRITE_DISABLE (0x0) #define WRITE_ENABLE (0x1) #define QSPI_TIMEOUT (1000) @@ -761,7 +750,7 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer, return retval; } -int mrvlqspi_flash_read(struct flash_bank *bank, uint8_t *buffer, +static int mrvlqspi_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; @@ -882,7 +871,7 @@ static int mrvlqspi_probe(struct flash_bank *bank) /* create and fill sectors array */ bank->num_sectors = mrvlqspi_info->dev->size_in_bytes / sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); - if (sectors == NULL) { + if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } @@ -914,17 +903,16 @@ static int mrvlqspi_flash_erase_check(struct flash_bank *bank) return ERROR_OK; } -int mrvlqspi_get_info(struct flash_bank *bank, char *buf, int buf_size) +static int mrvlqspi_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; if (!(mrvlqspi_info->probed)) { - snprintf(buf, buf_size, - "\nQSPI flash bank not probed yet\n"); + command_print_sameline(cmd, "\nQSPI flash bank not probed yet\n"); return ERROR_OK; } - snprintf(buf, buf_size, "\nQSPI flash information:\n" + command_print_sameline(cmd, "\nQSPI flash information:\n" " Device \'%s\' ID 0x%08" PRIx32 "\n", mrvlqspi_info->dev->name, mrvlqspi_info->dev->device_id); @@ -939,7 +927,7 @@ FLASH_BANK_COMMAND_HANDLER(mrvlqspi_flash_bank_command) return ERROR_COMMAND_SYNTAX_ERROR; mrvlqspi_info = malloc(sizeof(struct mrvlqspi_flash_bank)); - if (mrvlqspi_info == NULL) { + if (!mrvlqspi_info) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c index b6933e1e9b..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, @@ -63,7 +67,7 @@ static int msp432_device_type(uint32_t family_type, uint32_t device_id, { int device_type = MSP432_NO_TYPE; - if (MSP432E4 == family_type) { + if (family_type == MSP432E4) { /* MSP432E4 device family */ if (device_id == 0x180C0002) { @@ -191,7 +195,7 @@ static int msp432_exec_cmd(struct target *target, struct msp432_algo_params /* Write out parameters to target memory */ retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR, sizeof(struct msp432_algo_params), (uint8_t *)algo_params); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Write out command to target memory */ @@ -209,9 +213,9 @@ static int msp432_wait_return_code(struct target *target) int retval = ERROR_OK; start_ms = timeval_ms(); - while ((0 == return_code) || (FLASH_BUSY == return_code)) { + while ((return_code == 0) || (return_code == FLASH_BUSY)) { retval = target_read_u32(target, ALGO_RETURN_CODE_ADDR, &return_code); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; elapsed_ms = timeval_ms() - start_ms; @@ -221,7 +225,7 @@ static int msp432_wait_return_code(struct target *target) break; }; - if (FLASH_SUCCESS != return_code) { + if (return_code != FLASH_SUCCESS) { LOG_ERROR("msp432: Flash operation failed: %s", msp432_return_text(return_code)); return ERROR_FAIL; @@ -251,9 +255,9 @@ static int msp432_wait_inactive(struct target *target, uint32_t buffer) } start_ms = timeval_ms(); - while (BUFFER_INACTIVE != status_code) { + while (status_code != BUFFER_INACTIVE) { retval = target_read_u32(target, status_addr, &status_code); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; elapsed_ms = timeval_ms() - start_ms; @@ -263,7 +267,7 @@ static int msp432_wait_inactive(struct target *target, uint32_t buffer) break; }; - if (BUFFER_INACTIVE != status_code) { + if (status_code != BUFFER_INACTIVE) { LOG_ERROR( "msp432: Flash operation failed: buffer not written to flash"); return ERROR_FAIL; @@ -286,7 +290,7 @@ static int msp432_init(struct flash_bank *bank) /* Make sure we've probed the flash to get the device and size */ retval = msp432_auto_probe(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Choose appropriate flash helper algorithm */ @@ -315,18 +319,18 @@ static int msp432_init(struct flash_bank *bank) } /* Issue warnings if this is a device we may not be able to flash */ - if (MSP432P401X_GUESS == msp432_bank->device_type || - MSP432P411X_GUESS == msp432_bank->device_type) { + if (msp432_bank->device_type == MSP432P401X_GUESS || + msp432_bank->device_type == MSP432P411X_GUESS) { /* Explicit device type check failed. Report this. */ LOG_WARNING( "msp432: Unrecognized MSP432P4 Device ID and Hardware " "Rev (%04" PRIX32 ", %02" PRIX32 ")", msp432_bank->device_id, msp432_bank->hardware_rev); - } else if (MSP432P401X_DEPR == msp432_bank->device_type) { + } else if (msp432_bank->device_type == MSP432P401X_DEPR) { LOG_WARNING( "msp432: MSP432P401x pre-production device (deprecated " "silicon)\n" SUPPORT_MESSAGE); - } else if (MSP432E4X_GUESS == msp432_bank->device_type) { + } else if (msp432_bank->device_type == MSP432E4X_GUESS) { /* Explicit device type check failed. Report this. */ LOG_WARNING( "msp432: Unrecognized MSP432E4 DID0 and DID1 values " @@ -335,21 +339,22 @@ static int msp432_init(struct flash_bank *bank) } /* Check for working area to use for flash helper algorithm */ - if (NULL != msp432_bank->working_area) - target_free_working_area(target, msp432_bank->working_area); + target_free_working_area(target, msp432_bank->working_area); + msp432_bank->working_area = NULL; + retval = target_alloc_working_area(target, ALGO_WORKING_SIZE, &msp432_bank->working_area); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Confirm the defined working address is the area we need to use */ - if (ALGO_BASE_ADDR != msp432_bank->working_area->address) + if (msp432_bank->working_area->address != ALGO_BASE_ADDR) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* Write flash helper algorithm into target memory */ retval = target_write_buffer(target, ALGO_BASE_ADDR, loader_size, loader_code); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Initialize the ARMv7 specific info to run the algorithm */ @@ -362,7 +367,7 @@ static int msp432_init(struct flash_bank *bank) /* Write out parameters to target memory */ retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR, sizeof(algo_params), (uint8_t *)&algo_params); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Initialize stack pointer for flash helper algorithm */ @@ -370,10 +375,10 @@ 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 (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("msp432: Failed to start flash helper algorithm"); return retval; } @@ -385,7 +390,7 @@ static int msp432_init(struct flash_bank *bank) /* Issue the init command to the flash helper algorithm */ retval = msp432_exec_cmd(target, &algo_params, FLASH_INIT); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = msp432_wait_return_code(target); @@ -406,7 +411,7 @@ static int msp432_quit(struct flash_bank *bank) /* Issue the exit command to the flash helper algorithm */ retval = msp432_exec_cmd(target, &algo_params, FLASH_EXIT); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; (void)msp432_wait_return_code(target); @@ -432,13 +437,13 @@ static int msp432_mass_erase(struct flash_bank *bank, bool all) int retval; - if (TARGET_HALTED != target->state) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = msp432_init(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Initialize algorithm parameters to default values */ @@ -452,19 +457,19 @@ static int msp432_mass_erase(struct flash_bank *bank, bool all) /* Issue the mass erase command to the flash helper algorithm */ retval = msp432_exec_cmd(target, &algo_params, FLASH_MASS_ERASE); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } retval = msp432_wait_return_code(target); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } retval = msp432_quit(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; return retval; @@ -489,9 +494,9 @@ COMMAND_HANDLER(msp432_mass_erase_command) all = false; } else if (2 == CMD_ARGC) { /* Check argument for how much to erase */ - if (0 == strcmp(CMD_ARGV[1], "main")) + if (strcmp(CMD_ARGV[1], "main") == 0) all = false; - else if (0 == strcmp(CMD_ARGV[1], "all")) + else if (strcmp(CMD_ARGV[1], "all") == 0) all = true; else return ERROR_COMMAND_SYNTAX_ERROR; @@ -501,16 +506,16 @@ COMMAND_HANDLER(msp432_mass_erase_command) msp432_bank = bank->driver_priv; - if (MSP432E4 == msp432_bank->family_type) { + if (msp432_bank->family_type == MSP432E4) { /* MSP432E4 does not have main vs info regions, ignore "all" */ all = false; } retval = msp432_mass_erase(bank, all); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; - if (MSP432E4 == msp432_bank->family_type) { + if (msp432_bank->family_type == MSP432E4) { /* MSP432E4 does not have main vs info regions */ LOG_INFO("msp432: Mass erase of flash is complete"); } else { @@ -537,15 +542,15 @@ COMMAND_HANDLER(msp432_bsl_command) msp432_bank = bank->driver_priv; - if (MSP432E4 == msp432_bank->family_type) { + if (msp432_bank->family_type == MSP432E4) { LOG_WARNING("msp432: MSP432E4 does not have a BSL region"); return ERROR_OK; } if (2 == CMD_ARGC) { - if (0 == strcmp(CMD_ARGV[1], "lock")) + if (strcmp(CMD_ARGV[1], "lock") == 0) msp432_bank->unlock_bsl = false; - else if (0 == strcmp(CMD_ARGV[1], "unlock")) + else if (strcmp(CMD_ARGV[1], "unlock") == 0) msp432_bank->unlock_bsl = true; else return ERROR_COMMAND_SYNTAX_ERROR; @@ -569,7 +574,7 @@ FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command) /* Create shared private struct for flash banks */ msp432_bank = malloc(sizeof(struct msp432_bank)); - if (NULL == msp432_bank) + if (!msp432_bank) return ERROR_FAIL; /* Initialize private flash information */ @@ -597,12 +602,12 @@ static int msp432_erase(struct flash_bank *bank, unsigned int first, struct msp432_bank *msp432_bank = bank->driver_priv; struct msp432_algo_params algo_params; - bool is_main = FLASH_BASE == bank->base; - bool is_info = P4_FLASH_INFO_BASE == bank->base; + bool is_main = bank->base == FLASH_BASE; + bool is_info = bank->base == P4_FLASH_INFO_BASE; int retval; - if (TARGET_HALTED != target->state) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -614,7 +619,7 @@ static int msp432_erase(struct flash_bank *bank, unsigned int first, } retval = msp432_init(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Initialize algorithm parameters to default values */ @@ -646,20 +651,20 @@ static int msp432_erase(struct flash_bank *bank, unsigned int first, /* Issue the sector erase command to the flash helper algorithm */ retval = msp432_exec_cmd(target, &algo_params, FLASH_SECTOR_ERASE); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } retval = msp432_wait_return_code(target); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } } retval = msp432_quit(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; return retval; @@ -676,11 +681,11 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, long long start_ms; long long elapsed_ms; - bool is_info = P4_FLASH_INFO_BASE == bank->base; + bool is_info = bank->base == P4_FLASH_INFO_BASE; int retval; - if (TARGET_HALTED != target->state) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -705,7 +710,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, if (offset < start) { uint32_t start_count = MIN(start - offset, count); retval = msp432_write(bank, buffer, offset, start_count); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; } /* Send a request for anything after read-only sectors */ @@ -723,7 +728,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, } retval = msp432_init(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* Initialize algorithm parameters to default values */ @@ -742,7 +747,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, /* Set up flash helper algorithm to continuous flash mode */ retval = msp432_exec_cmd(target, &algo_params, FLASH_CONTINUOUS); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } @@ -758,7 +763,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, /* Put next block of data to flash into buffer */ retval = target_write_buffer(target, ALGO_BUFFER1_ADDR, size, buffer); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to target memory"); (void)msp432_quit(bank); return ERROR_FLASH_OPERATION_FAILED; @@ -767,13 +772,13 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, /* Signal the flash helper algorithm that data is ready to flash */ retval = target_write_u32(target, ALGO_BUFFER1_STATUS_ADDR, data_ready); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { (void)msp432_quit(bank); return ERROR_FLASH_OPERATION_FAILED; } retval = msp432_wait_inactive(target, 1); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } @@ -788,13 +793,13 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, /* Confirm that the flash helper algorithm is finished */ retval = msp432_wait_return_code(target); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { (void)msp432_quit(bank); return retval; } retval = msp432_quit(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; return retval; @@ -812,8 +817,8 @@ static int msp432_probe(struct flash_bank *bank) uint32_t size; unsigned int num_sectors; - bool is_main = FLASH_BASE == bank->base; - bool is_info = P4_FLASH_INFO_BASE == bank->base; + bool is_main = bank->base == FLASH_BASE; + bool is_info = bank->base == P4_FLASH_INFO_BASE; int retval; @@ -826,21 +831,21 @@ static int msp432_probe(struct flash_bank *bank) /* Read the flash size register to determine this is a P4 or not */ /* MSP432P4s will return the size of flash. MSP432E4s will return zero */ retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; - if (0 == size) { + if (size == 0) { /* This is likely an MSP432E4 */ msp432_bank->family_type = MSP432E4; retval = target_read_u32(target, E4_DID0_REG, &device_id); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; msp432_bank->device_id = device_id; retval = target_read_u32(target, E4_DID1_REG, &hardware_rev); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; msp432_bank->hardware_rev = hardware_rev; @@ -849,13 +854,13 @@ static int msp432_probe(struct flash_bank *bank) msp432_bank->family_type = MSP432P4; retval = target_read_u32(target, P4_DEVICE_ID_REG, &device_id); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; msp432_bank->device_id = device_id & 0xFFFF; retval = target_read_u32(target, P4_HARDWARE_REV_REG, &hardware_rev); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; msp432_bank->hardware_rev = hardware_rev & 0xFF; @@ -864,11 +869,11 @@ static int msp432_probe(struct flash_bank *bank) msp432_bank->device_type = msp432_device_type(msp432_bank->family_type, msp432_bank->device_id, msp432_bank->hardware_rev); - if (MSP432P4 == msp432_bank->family_type) { + if (msp432_bank->family_type == MSP432P4) { /* Set up MSP432P4 specific flash parameters */ if (is_main) { retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; sector_length = P4_SECTOR_LENGTH; @@ -878,7 +883,7 @@ static int msp432_probe(struct flash_bank *bank) msp432_bank->device_type == MSP432P411X_GUESS) { /* MSP432P411x has an info size register, use that for size */ retval = target_read_u32(target, P4_FLASH_INFO_SIZE_REG, &size); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; } else { /* All other MSP432P401x devices have fixed info region size */ @@ -907,7 +912,7 @@ static int msp432_probe(struct flash_bank *bank) if (num_sectors > 0) { bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); - if (NULL == bank->sectors) + if (!bank->sectors) return ERROR_FAIL; } @@ -933,7 +938,7 @@ static int msp432_probe(struct flash_bank *bank) if (is_main && MSP432P4 == msp432_bank->family_type) { /* Create the info flash bank needed by MSP432P4 variants */ struct flash_bank *info = calloc(sizeof(struct flash_bank), 1); - if (NULL == info) + if (!info) return ERROR_FAIL; /* Create a name for the info bank, append "_1" to main name */ @@ -960,8 +965,8 @@ static int msp432_auto_probe(struct flash_bank *bank) { struct msp432_bank *msp432_bank = bank->driver_priv; - bool is_main = FLASH_BASE == bank->base; - bool is_info = P4_FLASH_INFO_BASE == bank->base; + bool is_main = bank->base == FLASH_BASE; + bool is_info = bank->base == P4_FLASH_INFO_BASE; int retval = ERROR_OK; @@ -975,60 +980,50 @@ static int msp432_auto_probe(struct flash_bank *bank) return retval; } -static int msp432_info(struct flash_bank *bank, char *buf, int buf_size) +static int msp432_info(struct flash_bank *bank, struct command_invocation *cmd) { struct msp432_bank *msp432_bank = bank->driver_priv; - int printed = 0; switch (msp432_bank->device_type) { case MSP432P401X_DEPR: - if (0xFFFF == msp432_bank->device_id) { + if (msp432_bank->device_id == 0xFFFF) { /* Very early pre-production silicon currently deprecated */ - printed = snprintf(buf, buf_size, - "MSP432P401x pre-production device (deprecated silicon)\n" + command_print_sameline(cmd, "MSP432P401x pre-production device (deprecated silicon)\n" SUPPORT_MESSAGE); } else { /* Revision A or B silicon, also deprecated */ - printed = snprintf(buf, buf_size, - "MSP432P401x Device Rev %c (deprecated silicon)\n" + command_print_sameline(cmd, "MSP432P401x Device Rev %c (deprecated silicon)\n" SUPPORT_MESSAGE, (char)msp432_bank->hardware_rev); } break; case MSP432P401X: - printed = snprintf(buf, buf_size, - "MSP432P401x Device Rev %c\n", + command_print_sameline(cmd, "MSP432P401x Device Rev %c\n", (char)msp432_bank->hardware_rev); break; case MSP432P411X: - printed = snprintf(buf, buf_size, - "MSP432P411x Device Rev %c\n", + command_print_sameline(cmd, "MSP432P411x Device Rev %c\n", (char)msp432_bank->hardware_rev); break; case MSP432E401Y: - printed = snprintf(buf, buf_size, "MSP432E401Y Device\n"); + command_print_sameline(cmd, "MSP432E401Y Device\n"); break; case MSP432E411Y: - printed = snprintf(buf, buf_size, "MSP432E411Y Device\n"); + command_print_sameline(cmd, "MSP432E411Y Device\n"); break; case MSP432E4X_GUESS: - printed = snprintf(buf, buf_size, + command_print_sameline(cmd, "Unrecognized MSP432E4 DID0 and DID1 IDs (%08" PRIX32 ", %08" PRIX32 ")", msp432_bank->device_id, msp432_bank->hardware_rev); break; case MSP432P401X_GUESS: case MSP432P411X_GUESS: default: - printed = snprintf(buf, buf_size, + command_print_sameline(cmd, "Unrecognized MSP432P4 Device ID and Hardware Rev (%04" PRIX32 ", %02" PRIX32 ")", msp432_bank->device_id, msp432_bank->hardware_rev); break; } - buf_size -= printed; - - if (0 > buf_size) - return ERROR_BUF_TOO_SMALL; - return ERROR_OK; } @@ -1040,7 +1035,7 @@ static int msp432_protect_check(struct flash_bank *bank) static void msp432_flash_free_driver_priv(struct flash_bank *bank) { - bool is_main = FLASH_BASE == bank->base; + bool is_main = bank->base == FLASH_BASE; /* A single private struct is shared between main and info banks */ /* Only free it on the call for main bank */ diff --git a/src/flash/nor/msp432.h b/src/flash/nor/msp432.h index 663393b79d..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 @@ -43,7 +32,7 @@ #define P4_SECTOR_LENGTH 0x1000 #define P4_ALGO_ENTRY_ADDR 0x01000110 -/* MSP432E4 flash paramters */ +/* MSP432E4 flash parameters */ #define E4_FLASH_BASE FLASH_BASE #define E4_FLASH_SIZE 0x100000 #define E4_SECTOR_LENGTH 0x4000 @@ -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 1831314ddd..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 @@ -1206,8 +1195,6 @@ static int niietcm4_erase(struct flash_bank *bank, unsigned int first, retval = niietcm4_opstatus_check(bank); if (retval != ERROR_OK) return retval; - - bank->sectors[i].is_erased = 1; } return retval; @@ -1394,7 +1381,7 @@ static int niietcm4_write(struct flash_bank *bank, const uint8_t *buffer, int rem = count % 16; if (rem) { new_buffer = malloc(count + 16 - rem); - if (new_buffer == NULL) { + if (!new_buffer) { LOG_ERROR("Odd number of words to write and no memory for padding buffer"); return ERROR_FAIL; } @@ -1719,12 +1706,11 @@ static int niietcm4_auto_probe(struct flash_bank *bank) return niietcm4_probe(bank); } -static int get_niietcm4_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_niietcm4_info(struct flash_bank *bank, struct command_invocation *cmd) { struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv; - LOG_INFO("\nNIIET Cortex-M4F %s\n%s", niietcm4_info->chip_name, niietcm4_info->chip_brief); - snprintf(buf, buf_size, " "); - + command_print_sameline(cmd, "\nNIIET Cortex-M4F %s\n%s", + niietcm4_info->chip_name, niietcm4_info->chip_brief); return ERROR_OK; } diff --git a/src/flash/nor/non_cfi.c b/src/flash/nor/non_cfi.c index a817966c61..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 @@ -536,17 +525,17 @@ void cfi_fixup_non_cfi(struct flash_bank *bank) pri_ext->major_version = '1'; pri_ext->minor_version = '0'; - pri_ext->SiliconRevision = 0x0; - pri_ext->EraseSuspend = 0x0; - pri_ext->BlkProt = 0x0; - pri_ext->TmpBlkUnprotect = 0x0; - pri_ext->BlkProtUnprot = 0x0; - pri_ext->SimultaneousOps = 0x0; - pri_ext->BurstMode = 0x0; - pri_ext->PageMode = 0x0; - pri_ext->VppMin = 0x0; - pri_ext->VppMax = 0x0; - pri_ext->TopBottom = 0x0; + pri_ext->silicon_revision = 0x0; + pri_ext->erase_suspend = 0x0; + pri_ext->blk_prot = 0x0; + pri_ext->tmp_blk_unprotected = 0x0; + pri_ext->blk_prot_unprot = 0x0; + pri_ext->simultaneous_ops = 0x0; + pri_ext->burst_mode = 0x0; + pri_ext->page_mode = 0x0; + pri_ext->vpp_min = 0x0; + pri_ext->vpp_max = 0x0; + pri_ext->top_bottom = 0x0; pri_ext->_unlock1 = 0x5555; pri_ext->_unlock2 = 0x2AAA; 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 new file mode 100644 index 0000000000..8309630d7c --- /dev/null +++ b/src/flash/nor/npcx.c @@ -0,0 +1,540 @@ +// 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 +#include "config.h" +#endif + +#include "imp.h" +#include <helper/binarybuffer.h> +#include <helper/time_support.h> +#include <target/armv7m.h> +#include "../../../contrib/loaders/flash/npcx/npcx_flash.h" + +/* NPCX flash loader */ +static const uint8_t npcx_algo[] = { +#include "../../../contrib/loaders/flash/npcx/npcx_algo.inc" +}; + +#define NPCX_FLASH_TIMEOUT_MS 8000 + +/* flash list */ +enum npcx_flash_device_index { + NPCX_FLASH_256KB = 0, + NPCX_FLASH_512KB = 1, + NPCX_FLASH_1MB = 2, + NPCX_FLASH_UNKNOWN, +}; + +struct npcx_flash_bank { + uint32_t sector_length; + bool probed; + enum npcx_flash_device_index flash; + struct working_area *working_area; + struct armv7m_algorithm armv7m_info; + const uint8_t *algo_code; + uint32_t algo_size; + uint32_t algo_working_size; + uint32_t buffer_addr; + uint32_t params_addr; + uint32_t fiu_ver; +}; + +struct npcx_flash_info { + char *name; + uint32_t id; + uint32_t size; +}; + +static const struct npcx_flash_info flash_info[] = { + [NPCX_FLASH_256KB] = { + .name = "256KB Flash", + .id = 0xEF4012, + .size = 256 * 1024, + }, + [NPCX_FLASH_512KB] = { + .name = "512KB Flash", + .id = 0xEF4013, + .size = 512 * 1024, + }, + [NPCX_FLASH_1MB] = { + .name = "1MB Flash", + .id = 0xEF4014, + .size = 1024 * 1024, + }, + [NPCX_FLASH_UNKNOWN] = { + .name = "Unknown Flash", + .size = 0xFFFFFFFF, + }, +}; + +static int npcx_init(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct npcx_flash_bank *npcx_bank = bank->driver_priv; + + /* Check for working area to use for flash helper algorithm */ + target_free_working_area(target, npcx_bank->working_area); + npcx_bank->working_area = NULL; + + int retval = target_alloc_working_area(target, npcx_bank->algo_working_size, + &npcx_bank->working_area); + if (retval != ERROR_OK) + return retval; + + /* Confirm the defined working address is the area we need to use */ + if (npcx_bank->working_area->address != NPCX_FLASH_LOADER_WORKING_ADDR) { + 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); + npcx_bank->working_area = NULL; + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* Write flash helper algorithm into target memory */ + retval = target_write_buffer(target, NPCX_FLASH_LOADER_PROGRAM_ADDR, + npcx_bank->algo_size, npcx_bank->algo_code); + if (retval != ERROR_OK) { + 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; + } + + /* Initialize the ARMv7 specific info to run the algorithm */ + npcx_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + npcx_bank->armv7m_info.core_mode = ARM_MODE_THREAD; + + /* Begin executing the flash helper algorithm */ + retval = target_start_algorithm(target, 0, NULL, 0, NULL, + NPCX_FLASH_LOADER_PROGRAM_ADDR, 0, + &npcx_bank->armv7m_info); + if (retval != ERROR_OK) { + 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; + } + + /* + * At this point, the algorithm is running on the target and + * ready to receive commands and data to flash the target + */ + + return retval; +} + +static int npcx_quit(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct npcx_flash_bank *npcx_bank = bank->driver_priv; + + /* Regardless of the algo's status, attempt to halt the target */ + (void)target_halt(target); + + /* Now confirm target halted and clean up from flash helper algorithm */ + int retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, + NPCX_FLASH_TIMEOUT_MS, &npcx_bank->armv7m_info); + + target_free_working_area(target, npcx_bank->working_area); + npcx_bank->working_area = NULL; + + return retval; +} + +static int npcx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) +{ + struct target *target = bank->target; + uint32_t status_addr = params_addr + offsetof(struct npcx_flash_params, sync); + uint32_t status; + int64_t start_ms = timeval_ms(); + + do { + int retval = target_read_u32(target, status_addr, &status); + if (retval != ERROR_OK) + return retval; + + keep_alive(); + + int64_t elapsed_ms = timeval_ms() - start_ms; + if (elapsed_ms > NPCX_FLASH_TIMEOUT_MS) + break; + } while (status == NPCX_FLASH_LOADER_EXECUTE); + + if (status != NPCX_FLASH_LOADER_WAIT) { + LOG_TARGET_ERROR(target, "Flash operation failed, status (%0x" PRIX32 ") ", status); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static enum npcx_flash_device_index npcx_get_flash_id(struct flash_bank *bank, uint32_t *flash_id) +{ + struct target *target = bank->target; + struct npcx_flash_bank *npcx_bank = bank->driver_priv; + struct npcx_flash_params algo_params; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = npcx_init(bank); + if (retval != ERROR_OK) + 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); + + /* Issue flash helper algorithm parameters for get flash ID */ + retval = target_write_buffer(target, npcx_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + if (retval != ERROR_OK) { + (void)npcx_quit(bank); + return retval; + } + + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); + retval = target_write_buffer(target, npcx_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + + /* If no error, wait for finishing */ + if (retval == ERROR_OK) { + retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); + if (retval == ERROR_OK) + target_read_u32(target, NPCX_FLASH_LOADER_BUFFER_ADDR, flash_id); + } + + /* Regardless of errors, try to close down algo */ + (void)npcx_quit(bank); + + return retval; +} + +static int npcx_get_flash(uint32_t flash_id) +{ + for (uint32_t i = 0; i < ARRAY_SIZE(flash_info) - 1; i++) { + if (flash_info[i].id == flash_id) + return i; + } + + return NPCX_FLASH_UNKNOWN; +} + +static int npcx_probe(struct flash_bank *bank) +{ + struct npcx_flash_bank *npcx_bank = bank->driver_priv; + uint32_t sector_length = NPCX_FLASH_ERASE_SIZE; + uint32_t flash_id; + + /* Set up appropriate flash helper algorithm */ + npcx_bank->algo_code = npcx_algo; + npcx_bank->algo_size = sizeof(npcx_algo); + npcx_bank->algo_working_size = NPCX_FLASH_LOADER_PARAMS_SIZE + + NPCX_FLASH_LOADER_BUFFER_SIZE + + NPCX_FLASH_LOADER_PROGRAM_SIZE; + 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; + + npcx_bank->flash = npcx_get_flash(flash_id); + + unsigned int num_sectors = flash_info[npcx_bank->flash].size / sector_length; + + bank->sectors = calloc(num_sectors, sizeof(struct flash_sector)); + if (!bank->sectors) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + bank->num_sectors = num_sectors; + bank->size = num_sectors * sector_length; + bank->write_start_alignment = 0; + bank->write_end_alignment = 0; + npcx_bank->sector_length = sector_length; + + for (unsigned int i = 0; i < num_sectors; i++) { + bank->sectors[i].offset = i * sector_length; + bank->sectors[i].size = sector_length; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + /* We've successfully determined the stats on the flash bank */ + npcx_bank->probed = true; + + /* If we fall through to here, then all went well */ + return ERROR_OK; +} + +static int npcx_auto_probe(struct flash_bank *bank) +{ + struct npcx_flash_bank *npcx_bank = bank->driver_priv; + int retval = ERROR_OK; + + if (!npcx_bank->probed) + retval = npcx_probe(bank); + + return retval; +} + +FLASH_BANK_COMMAND_HANDLER(npcx_flash_bank_command) +{ + struct npcx_flash_bank *npcx_bank; + + if (CMD_ARGC < 6 || CMD_ARGC > 7) + return ERROR_COMMAND_SYNTAX_ERROR; + + npcx_bank = calloc(1, sizeof(struct npcx_flash_bank)); + if (!npcx_bank) { + LOG_ERROR("Out of memory"); + 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->sector_length = NPCX_FLASH_ERASE_SIZE; + + /* Finish initialization of bank */ + bank->driver_priv = npcx_bank; + + return ERROR_OK; +} + +static int npcx_chip_erase(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct npcx_flash_bank *npcx_bank = bank->driver_priv; + struct npcx_flash_params algo_params; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Make sure we've probed the flash to get the device and size */ + int retval = npcx_auto_probe(bank); + if (retval != ERROR_OK) + return retval; + + retval = npcx_init(bank); + if (retval != ERROR_OK) + 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); + + /* Set algorithm parameters */ + retval = target_write_buffer(target, npcx_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + if (retval != ERROR_OK) { + (void)npcx_quit(bank); + return retval; + } + + /* Issue flash helper algorithm parameters for chip erase */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); + retval = target_write_buffer(target, npcx_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + + /* If no error, wait for chip erase finish */ + if (retval == ERROR_OK) + retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); + + /* Regardless of errors, try to close down algo */ + (void)npcx_quit(bank); + + return retval; +} + +static int npcx_erase(struct flash_bank *bank, unsigned int first, + unsigned int last) +{ + struct target *target = bank->target; + struct npcx_flash_bank *npcx_bank = bank->driver_priv; + struct npcx_flash_params algo_params; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if ((first == 0) && (last == (bank->num_sectors - 1))) { + /* Request chip erase */ + return npcx_chip_erase(bank); + } + + uint32_t address = first * npcx_bank->sector_length; + uint32_t length = (last - first + 1) * npcx_bank->sector_length; + + /* Make sure we've probed the flash to get the device and size */ + int retval = npcx_auto_probe(bank); + if (retval != ERROR_OK) + return retval; + + retval = npcx_init(bank); + if (retval != ERROR_OK) + 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); + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); + + /* Set algorithm parameters */ + retval = target_write_buffer(target, npcx_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + if (retval != ERROR_OK) { + (void)npcx_quit(bank); + return retval; + } + + /* Issue flash helper algorithm parameters for erase */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); + retval = target_write_buffer(target, npcx_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + + /* If no error, wait for erase to finish */ + if (retval == ERROR_OK) + retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); + + /* Regardless of errors, try to close down algo */ + (void)npcx_quit(bank); + + return retval; +} + +static int npcx_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct npcx_flash_bank *npcx_bank = bank->driver_priv; + struct npcx_flash_params algo_params; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Make sure we've probed the flash to get the device and size */ + int retval = npcx_auto_probe(bank); + if (retval != ERROR_OK) + return retval; + + retval = npcx_init(bank); + if (retval != ERROR_OK) + return retval; + + /* Initialize algorithm parameters to default values */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_PROGRAM); + + uint32_t address = offset; + + while (count > 0) { + uint32_t size = (count > NPCX_FLASH_LOADER_BUFFER_SIZE) ? + NPCX_FLASH_LOADER_BUFFER_SIZE : count; + + /* Put the data into buffer */ + retval = target_write_buffer(target, npcx_bank->buffer_addr, + size, buffer); + if (retval != ERROR_OK) { + LOG_ERROR("Unable to write data to target memory"); + break; + } + + /* 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); + + /* Set algorithm parameters */ + retval = target_write_buffer(target, npcx_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + if (retval != ERROR_OK) + break; + + /* Issue flash helper algorithm parameters for flash write */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); + retval = target_write_buffer(target, npcx_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + if (retval != ERROR_OK) + break; + + /* Wait for flash write finish */ + retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); + if (retval != ERROR_OK) + break; + + count -= size; + buffer += size; + address += size; + } + + /* Regardless of errors, try to close down algo */ + (void)npcx_quit(bank); + + return retval; +} + +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", + target_name(bank->target), + flash_info[npcx_bank->flash].name); + + return ERROR_OK; +} + +const struct flash_driver npcx_flash = { + .name = "npcx", + .flash_bank_command = npcx_flash_bank_command, + .erase = npcx_erase, + .write = npcx_write, + .read = default_flash_read, + .probe = npcx_probe, + .auto_probe = npcx_auto_probe, + .erase_check = default_flash_blank_check, + .info = npcx_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 0ceb8d7544..bf8c9da5fe 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 @@ -23,10 +12,12 @@ #endif #include "imp.h" +#include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> #include <helper/types.h> #include <helper/time_support.h> +#include <helper/bits.h> /* Both those values are constant across the current spectrum ofr nRF5 devices */ #define WATCHDOG_REFRESH_REGISTER 0x40010600 @@ -52,32 +43,9 @@ enum nrf5_ficr_registers { NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040), NRF51_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044), + /* CONFIGID is documented on nRF51 series only. + * On nRF52 is present but not documented */ NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C), - NRF5_FICR_DEVICEID0 = NRF5_FICR_REG(0x060), - NRF5_FICR_DEVICEID1 = NRF5_FICR_REG(0x064), - NRF5_FICR_ER0 = NRF5_FICR_REG(0x080), - NRF5_FICR_ER1 = NRF5_FICR_REG(0x084), - NRF5_FICR_ER2 = NRF5_FICR_REG(0x088), - NRF5_FICR_ER3 = NRF5_FICR_REG(0x08C), - NRF5_FICR_IR0 = NRF5_FICR_REG(0x090), - NRF5_FICR_IR1 = NRF5_FICR_REG(0x094), - NRF5_FICR_IR2 = NRF5_FICR_REG(0x098), - NRF5_FICR_IR3 = NRF5_FICR_REG(0x09C), - NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG(0x0A0), - NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG(0x0A4), - NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG(0x0A8), - - NRF51_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC), - NRF51_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0), - NRF51_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4), - NRF51_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8), - NRF51_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC), - NRF51_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0), - NRF51_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC), - NRF51_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0), - NRF51_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4), - NRF51_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8), - NRF51_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC), /* Following registers are available on nRF52 and on nRF51 since rev 3 */ NRF5_FICR_INFO_PART = NRF5_FICR_REG(0x100), @@ -94,9 +62,6 @@ enum nrf5_uicr_registers { #define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset) NRF51_UICR_CLENR0 = NRF5_UICR_REG(0x000), - NRF51_UICR_RBPCONF = NRF5_UICR_REG(0x004), - NRF51_UICR_XTALFREQ = NRF5_UICR_REG(0x008), - NRF51_UICR_FWID = NRF5_UICR_REG(0x010), }; enum nrf5_nvmc_registers { @@ -130,10 +95,10 @@ struct nrf52_ficr_info { }; enum nrf5_features { - NRF5_FEATURE_SERIES_51 = 1 << 0, - NRF5_FEATURE_SERIES_52 = 1 << 1, - NRF5_FEATURE_BPROT = 1 << 2, - NRF5_FEATURE_ACL_PROT = 1 << 3, + NRF5_FEATURE_SERIES_51 = BIT(0), + NRF5_FEATURE_SERIES_52 = BIT(1), + NRF5_FEATURE_BPROT = BIT(2), + NRF5_FEATURE_ACL_PROT = BIT(3), }; struct nrf5_device_spec { @@ -146,7 +111,7 @@ struct nrf5_device_spec { }; struct nrf5_info { - uint32_t refcount; + unsigned int refcount; struct nrf5_bank { struct nrf5_info *chip; @@ -158,7 +123,7 @@ struct nrf5_info { bool ficr_info_valid; struct nrf52_ficr_info ficr_info; const struct nrf5_device_spec *spec; - uint32_t hwid; + uint16_t hwid; enum nrf5_features features; unsigned int flash_size_kb; unsigned int ram_size_kb; @@ -174,26 +139,20 @@ struct nrf5_info { .features = NRF5_FEATURE_SERIES_51, \ } -#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize, features) \ -{ \ -.hwid = (id), \ -.part = pt, \ -.variant = var, \ -.build_code = bcode, \ -.flash_size_kb = (fsize), \ -.features = features, \ -} - -/* The known devices table below is derived from the "nRF5x series - * compatibility matrix" documents, which can be found in the "DocLib" of - * nordic: +/* + * The table maps known HWIDs to the part numbers, variant + * build code and some other info. For nRF51 rev 1 and 2 devices + * this is the only way how to get the part number and variant. + * + * All tested nRF51 rev 3 devices have FICR INFO fields + * but the fields are not documented in RM so we keep HWIDs in + * this table. * - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51422_ic_revision_overview - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51822_ic_revision_overview - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51824_ic_revision_overview - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52810/latest/COMP/nrf52810/nRF52810_ic_revision_overview - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52832/latest/COMP/nrf52832/ic_revision_overview - * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52840/latest/COMP/nrf52840/nRF52840_ic_revision_overview + * nRF52 and newer devices have FICR INFO documented, the autodetection + * can rely on it and HWIDs table is not used. + * + * The known devices table below is derived from the "nRF5x series + * compatibility matrix" documents. * * Up to date with Matrix v2.0, plus some additional HWIDs. * @@ -258,19 +217,6 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { /* The driver fully autodetects nRF52 series devices by FICR INFO, * no need for nRF52xxx HWIDs in this table */ -#if 0 - /* nRF52810 Devices */ - NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), - NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), - - /* nRF52832 Devices */ - NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), - NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), - NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), - - /* nRF52840 Devices */ - NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_ACL_PROT), -#endif }; struct nrf5_device_package { @@ -280,43 +226,27 @@ struct nrf5_device_package { /* Newer devices have FICR INFO.PACKAGE. * This table converts its value to two character code */ -static const struct nrf5_device_package nrf5_packages_table[] = { +static const struct nrf5_device_package nrf52_packages_table[] = { { 0x2000, "QF" }, { 0x2001, "CH" }, { 0x2002, "CI" }, + { 0x2003, "QC" }, + { 0x2004, "QI/CA" }, /* differs nRF52805, 810, 811: CA, nRF52833, 840: QI */ { 0x2005, "CK" }, + { 0x2007, "QD" }, + { 0x2008, "CJ" }, + { 0x2009, "CF" }, }; const struct flash_driver nrf5_flash, nrf51_flash; -static int nrf5_bank_is_probed(struct flash_bank *bank) +static bool nrf5_bank_is_probed(const struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; - - assert(nbank != NULL); + assert(nbank); return nbank->probed; } -static int nrf5_probe(struct flash_bank *bank); - -static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_info **chip) -{ - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - struct nrf5_bank *nbank = bank->driver_priv; - *chip = nbank->chip; - - int probed = nrf5_bank_is_probed(bank); - if (probed < 0) - return probed; - else if (!probed) - return nrf5_probe(bank); - else - return ERROR_OK; -} static int nrf5_wait_for_nvmc(struct nrf5_info *chip) { @@ -328,7 +258,7 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip) do { res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready); if (res != ERROR_OK) { - LOG_ERROR("Couldn't read NVMC_READY register"); + LOG_ERROR("Error waiting NVMC_READY: generic flash write/erase error (check protection etc...)"); return res; } @@ -440,12 +370,45 @@ error: return ERROR_FAIL; } -static int nrf5_protect_check_bprot(struct flash_bank *bank) +static int nrf5_protect_check_clenr0(struct flash_bank *bank) { + int res; + uint32_t clenr0; + struct nrf5_bank *nbank = bank->driver_priv; + assert(nbank); struct nrf5_info *chip = nbank->chip; + assert(chip); - assert(chip != NULL); + res = target_read_u32(chip->target, NRF51_FICR_CLENR0, + &clenr0); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read code region 0 size[FICR]"); + return res; + } + + if (clenr0 == 0xFFFFFFFF) { + res = target_read_u32(chip->target, NRF51_UICR_CLENR0, + &clenr0); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read code region 0 size[UICR]"); + return res; + } + } + + for (unsigned int i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_protected = + clenr0 != 0xFFFFFFFF && bank->sectors[i].offset < clenr0; + + return ERROR_OK; +} + +static int nrf5_protect_check_bprot(struct flash_bank *bank) +{ + struct nrf5_bank *nbank = bank->driver_priv; + assert(nbank); + struct nrf5_info *chip = nbank->chip; + assert(chip); static uint32_t nrf5_bprot_offsets[4] = { 0x600, 0x604, 0x610, 0x614 }; uint32_t bprot_reg = 0; @@ -469,68 +432,35 @@ static int nrf5_protect_check_bprot(struct flash_bank *bank) static int nrf5_protect_check(struct flash_bank *bank) { - int res; - uint32_t clenr0; - /* UICR cannot be write protected so just return early */ if (bank->base == NRF5_UICR_BASE) return ERROR_OK; struct nrf5_bank *nbank = bank->driver_priv; + assert(nbank); struct nrf5_info *chip = nbank->chip; - - assert(chip != NULL); + assert(chip); if (chip->features & NRF5_FEATURE_BPROT) return nrf5_protect_check_bprot(bank); - if (!(chip->features & NRF5_FEATURE_SERIES_51)) { - LOG_WARNING("Flash protection of this nRF device is not supported"); - return ERROR_FLASH_OPER_UNSUPPORTED; - } + if (chip->features & NRF5_FEATURE_SERIES_51) + return nrf5_protect_check_clenr0(bank); - res = target_read_u32(chip->target, NRF51_FICR_CLENR0, - &clenr0); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code region 0 size[FICR]"); - return res; - } - - if (clenr0 == 0xFFFFFFFF) { - res = target_read_u32(chip->target, NRF51_UICR_CLENR0, - &clenr0); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code region 0 size[UICR]"); - return res; - } - } - - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_protected = - clenr0 != 0xFFFFFFFF && bank->sectors[i].offset < clenr0; - - return ERROR_OK; + LOG_WARNING("Flash protection of this nRF device is not supported"); + return ERROR_FLASH_OPER_UNSUPPORTED; } -static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, +static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int res; uint32_t clenr0, ppfc; - struct nrf5_info *chip; - - /* UICR cannot be write protected so just bail out early */ - if (bank->base == NRF5_UICR_BASE) - return ERROR_FAIL; - - res = nrf5_get_probed_chip_if_halted(bank, &chip); - if (res != ERROR_OK) - return res; - if (!(chip->features & NRF5_FEATURE_SERIES_51)) { - LOG_ERROR("Flash protection setting of this nRF device is not supported"); - return ERROR_FLASH_OPER_UNSUPPORTED; - } + struct nrf5_bank *nbank = bank->driver_priv; + assert(nbank); + struct nrf5_info *chip = nbank->chip; + assert(chip); if (first != 0) { LOG_ERROR("Code region 0 must start at the beginning of the bank"); @@ -552,25 +482,62 @@ static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, res = target_read_u32(chip->target, NRF51_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code region 0 size[UICR]"); + LOG_ERROR("Couldn't read code region 0 size from UICR"); return res; } - if (clenr0 == 0xFFFFFFFF) { - res = target_write_u32(chip->target, NRF51_UICR_CLENR0, - clenr0); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't write code region 0 size[UICR]"); - return res; - } - - } else { + if (!set || clenr0 != 0xFFFFFFFF) { LOG_ERROR("You need to perform chip erase before changing the protection settings"); + return ERROR_FAIL; } - nrf5_protect_check(bank); + res = nrf5_nvmc_write_enable(chip); + if (res != ERROR_OK) + goto error; + + clenr0 = bank->sectors[last].offset + bank->sectors[last].size; + res = target_write_u32(chip->target, NRF51_UICR_CLENR0, clenr0); - return ERROR_OK; + int res2 = nrf5_wait_for_nvmc(chip); + + if (res == ERROR_OK) + res = res2; + + if (res == ERROR_OK) + LOG_INFO("A reset or power cycle is required for the new protection settings to take effect."); + else + LOG_ERROR("Couldn't write code region 0 size to UICR"); + +error: + nrf5_nvmc_read_only(chip); + + return res; +} + +static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, + unsigned int last) +{ + /* UICR cannot be write protected so just bail out early */ + if (bank->base == NRF5_UICR_BASE) { + LOG_ERROR("UICR page does not support protection"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + struct nrf5_bank *nbank = bank->driver_priv; + assert(nbank); + struct nrf5_info *chip = nbank->chip; + assert(chip); + + if (chip->features & NRF5_FEATURE_SERIES_51) + return nrf5_protect_clenr0(bank, set, first, last); + + LOG_ERROR("Flash protection setting is not supported on this nRF5 device"); + return ERROR_FLASH_OPER_UNSUPPORTED; } static bool nrf5_info_variant_to_str(uint32_t variant, char *bf) @@ -590,42 +557,51 @@ static bool nrf5_info_variant_to_str(uint32_t variant, char *bf) static const char *nrf5_decode_info_package(uint32_t package) { - for (size_t i = 0; i < ARRAY_SIZE(nrf5_packages_table); i++) { - if (nrf5_packages_table[i].package == package) - return nrf5_packages_table[i].code; + for (size_t i = 0; i < ARRAY_SIZE(nrf52_packages_table); i++) { + if (nrf52_packages_table[i].package == package) + return nrf52_packages_table[i].code; } return "xx"; } -static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_nrf5_chip_type_str(const struct nrf5_info *chip, char *buf, unsigned int buf_size) { - struct nrf5_bank *nbank = bank->driver_priv; - struct nrf5_info *chip = nbank->chip; int res; - if (chip->spec) { - res = snprintf(buf, buf_size, - "nRF%s-%s(build code: %s)", + res = snprintf(buf, buf_size, "nRF%s-%s(build code: %s)", chip->spec->part, chip->spec->variant, chip->spec->build_code); - } else if (chip->ficr_info_valid) { char variant[5]; nrf5_info_variant_to_str(chip->ficr_info.variant, variant); - res = snprintf(buf, buf_size, - "nRF%" PRIx32 "-%s%.2s(build code: %s)", + res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s%.2s(build code: %s)", chip->ficr_info.part, nrf5_decode_info_package(chip->ficr_info.package), variant, &variant[2]); - } else { - res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%08" PRIx32 ")", - chip->hwid); + res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ")", chip->hwid); } - if (res <= 0) + + /* safety: */ + if (res <= 0 || (unsigned int)res >= buf_size) { + LOG_ERROR("BUG: buffer problem in %s", __func__); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + struct nrf5_bank *nbank = bank->driver_priv; + assert(nbank); + struct nrf5_info *chip = nbank->chip; + assert(chip); + + char chip_type_str[256]; + if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) return ERROR_FAIL; - snprintf(buf + res, buf_size - res, " %ukB Flash, %ukB RAM", - chip->flash_size_kb, chip->ram_size_kb); + command_print_sameline(cmd, "%s %ukB Flash, %ukB RAM", + chip_type_str, chip->flash_size_kb, chip->ram_size_kb); return ERROR_OK; } @@ -652,11 +628,15 @@ static int nrf5_read_ficr_info(struct nrf5_info *chip) chip->features = NRF5_FEATURE_SERIES_52; switch (chip->ficr_info.part) { + case 0x52805: case 0x52810: + case 0x52811: case 0x52832: chip->features |= NRF5_FEATURE_BPROT; break; + case 0x52820: + case 0x52833: case 0x52840: chip->features |= NRF5_FEATURE_ACL_PROT; break; @@ -731,18 +711,22 @@ static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size) static int nrf5_probe(struct flash_bank *bank) { int res; + struct nrf5_bank *nbank = bank->driver_priv; + assert(nbank); struct nrf5_info *chip = nbank->chip; + assert(chip); struct target *target = chip->target; - res = target_read_u32(target, NRF5_FICR_CONFIGID, &chip->hwid); + uint32_t configid; + res = target_read_u32(target, NRF5_FICR_CONFIGID, &configid); if (res != ERROR_OK) { LOG_ERROR("Couldn't read CONFIGID register"); return res; } - chip->hwid &= 0xFFFF; /* HWID is stored in the lower two - * bytes of the CONFIGID register */ + /* HWID is stored in the lower two bytes of the CONFIGID register */ + chip->hwid = configid & 0xFFFF; /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */ chip->features = NRF5_FEATURE_SERIES_51; @@ -796,13 +780,15 @@ static int nrf5_probe(struct flash_bank *bank) chip->flash_size_kb = num_sectors * flash_page_size / 1024; if (!chip->bank[0].probed && !chip->bank[1].probed) { - char buf[80]; - nrf5_info(bank, buf, sizeof(buf)); - if (!chip->spec && !chip->ficr_info_valid) { - LOG_INFO("Unknown device: %s", buf); - } else { - LOG_INFO("%s", buf); - } + char chip_type_str[256]; + if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) + return ERROR_FAIL; + const bool device_is_unknown = (!chip->spec && !chip->ficr_info_valid); + LOG_INFO("%s%s %ukB Flash, %ukB RAM", + device_is_unknown ? "Unknown device: " : "", + chip_type_str, + chip->flash_size_kb, + chip->ram_size_kb); } free(bank->sectors); @@ -821,8 +807,6 @@ static int nrf5_probe(struct flash_bank *bank) if (!bank->sectors) return ERROR_FAIL; - nrf5_protect_check(bank); - chip->bank[0].probed = true; } else { @@ -843,14 +827,10 @@ static int nrf5_probe(struct flash_bank *bank) static int nrf5_auto_probe(struct flash_bank *bank) { - int probed = nrf5_bank_is_probed(bank); - - if (probed < 0) - return probed; - else if (probed) + if (nrf5_bank_is_probed(bank)) return ERROR_OK; - else - return nrf5_probe(bank); + + return nrf5_probe(bank); } static int nrf5_erase_all(struct nrf5_info *chip) @@ -984,7 +964,7 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u 0, NULL, ARRAY_SIZE(reg_params), reg_params, source->address, source->size, - write_algorithm->address, 0, + write_algorithm->address, write_algorithm->address + sizeof(nrf5_flash_write_code) - 2, &armv7m_info); target_free_working_area(target, source); @@ -1003,15 +983,49 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { - struct nrf5_info *chip; + int res; - int res = nrf5_get_probed_chip_if_halted(bank, &chip); - if (res != ERROR_OK) - return res; + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + struct nrf5_bank *nbank = bank->driver_priv; + assert(nbank); + struct nrf5_info *chip = nbank->chip; + assert(chip); assert(offset % 4 == 0); assert(count % 4 == 0); + /* UICR CLENR0 based protection used on nRF51 is somewhat clumsy: + * RM reads: Code running from code region 1 will not be able to write + * to code region 0. + * Unfortunately the flash loader running from RAM can write to both + * code regions without any hint the protection is violated. + * + * Update protection state and check if any flash sector to be written + * is protected. */ + if (chip->features & NRF5_FEATURE_SERIES_51) { + + res = nrf5_protect_check_clenr0(bank); + if (res != ERROR_OK) + return res; + + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + struct flash_sector *bs = &bank->sectors[sector]; + + /* Start offset in or before this sector? */ + /* End offset in or behind this sector? */ + if ((offset < (bs->offset + bs->size)) + && ((offset + count - 1) >= bs->offset) + && bs->is_protected == 1) { + LOG_ERROR("Write refused, sector %d is protected", sector); + return ERROR_FLASH_PROTECTED; + } + } + } + res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) goto error; @@ -1032,24 +1046,55 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int res; - struct nrf5_info *chip; - res = nrf5_get_probed_chip_if_halted(bank, &chip); - if (res != ERROR_OK) - return res; + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + struct nrf5_bank *nbank = bank->driver_priv; + assert(nbank); + struct nrf5_info *chip = nbank->chip; + assert(chip); + + /* UICR CLENR0 based protection used on nRF51 prevents erase + * absolutely silently. NVMC has no flag to indicate the protection + * was violated. + * + * Update protection state and check if any flash sector to be erased + * is protected. */ + if (chip->features & NRF5_FEATURE_SERIES_51) { + + res = nrf5_protect_check_clenr0(bank); + if (res != ERROR_OK) + return res; + } /* For each sector to be erased */ - for (unsigned int s = first; s <= last && res == ERROR_OK; s++) + for (unsigned int s = first; s <= last; s++) { + + if (chip->features & NRF5_FEATURE_SERIES_51 + && bank->sectors[s].is_protected == 1) { + LOG_ERROR("Flash sector %d is protected", s); + return ERROR_FLASH_PROTECTED; + } + res = nrf5_erase_page(bank, chip, &bank->sectors[s]); + if (res != ERROR_OK) { + LOG_ERROR("Error erasing sector %d", s); + return res; + } + } - return res; + return ERROR_OK; } static void nrf5_free_driver_priv(struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; + assert(nbank); struct nrf5_info *chip = nbank->chip; - if (chip == NULL) + if (!chip) return; chip->refcount--; @@ -1086,6 +1131,9 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) struct nrf5_info *chip; struct nrf5_bank *nbank = NULL; + if (bank->driver == &nrf51_flash) + LOG_WARNING("Flash driver 'nrf51' is deprecated! Use 'nrf5' instead."); + switch (bank->base) { case NRF5_FLASH_BASE: case NRF5_UICR_BASE: @@ -1113,7 +1161,7 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) nbank = &chip->bank[1]; break; } - assert(nbank != NULL); + assert(nbank); chip->refcount++; nbank->chip = chip; @@ -1134,13 +1182,17 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) if (res != ERROR_OK) return res; - assert(bank != NULL); + assert(bank); - struct nrf5_info *chip; + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } - res = nrf5_get_probed_chip_if_halted(bank, &chip); - if (res != ERROR_OK) - return res; + struct nrf5_bank *nbank = bank->driver_priv; + assert(nbank); + struct nrf5_info *chip = nbank->chip; + assert(chip); if (chip->features & NRF5_FEATURE_SERIES_51) { uint32_t ppfc; @@ -1159,156 +1211,18 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) } res = nrf5_erase_all(chip); - if (res != ERROR_OK) { - LOG_ERROR("Failed to erase the chip"); - nrf5_protect_check(bank); - return res; - } + if (res == ERROR_OK) { + LOG_INFO("Mass erase completed."); + if (chip->features & NRF5_FEATURE_SERIES_51) + LOG_INFO("A reset or power cycle is required if the flash was protected before."); - res = nrf5_protect_check(bank); - if (res != ERROR_OK) { - LOG_ERROR("Failed to check chip's write protection"); - return res; + } else { + LOG_ERROR("Failed to erase the chip"); } - res = get_flash_bank_by_addr(target, NRF5_UICR_BASE, true, &bank); - if (res != ERROR_OK) - return res; - - return ERROR_OK; + return res; } -COMMAND_HANDLER(nrf5_handle_info_command) -{ - int res; - struct flash_bank *bank = NULL; - struct target *target = get_current_target(CMD_CTX); - - res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank); - if (res != ERROR_OK) - return res; - - assert(bank != NULL); - - struct nrf5_info *chip; - - res = nrf5_get_probed_chip_if_halted(bank, &chip); - if (res != ERROR_OK) - return res; - - static struct { - const uint32_t address; - uint32_t value; - } ficr[] = { - { .address = NRF5_FICR_CODEPAGESIZE }, - { .address = NRF5_FICR_CODESIZE }, - { .address = NRF51_FICR_CLENR0 }, - { .address = NRF51_FICR_PPFC }, - { .address = NRF51_FICR_NUMRAMBLOCK }, - { .address = NRF51_FICR_SIZERAMBLOCK0 }, - { .address = NRF51_FICR_SIZERAMBLOCK1 }, - { .address = NRF51_FICR_SIZERAMBLOCK2 }, - { .address = NRF51_FICR_SIZERAMBLOCK3 }, - { .address = NRF5_FICR_CONFIGID }, - { .address = NRF5_FICR_DEVICEID0 }, - { .address = NRF5_FICR_DEVICEID1 }, - { .address = NRF5_FICR_ER0 }, - { .address = NRF5_FICR_ER1 }, - { .address = NRF5_FICR_ER2 }, - { .address = NRF5_FICR_ER3 }, - { .address = NRF5_FICR_IR0 }, - { .address = NRF5_FICR_IR1 }, - { .address = NRF5_FICR_IR2 }, - { .address = NRF5_FICR_IR3 }, - { .address = NRF5_FICR_DEVICEADDRTYPE }, - { .address = NRF5_FICR_DEVICEADDR0 }, - { .address = NRF5_FICR_DEVICEADDR1 }, - { .address = NRF51_FICR_OVERRIDEN }, - { .address = NRF51_FICR_NRF_1MBIT0 }, - { .address = NRF51_FICR_NRF_1MBIT1 }, - { .address = NRF51_FICR_NRF_1MBIT2 }, - { .address = NRF51_FICR_NRF_1MBIT3 }, - { .address = NRF51_FICR_NRF_1MBIT4 }, - { .address = NRF51_FICR_BLE_1MBIT0 }, - { .address = NRF51_FICR_BLE_1MBIT1 }, - { .address = NRF51_FICR_BLE_1MBIT2 }, - { .address = NRF51_FICR_BLE_1MBIT3 }, - { .address = NRF51_FICR_BLE_1MBIT4 }, - }, uicr[] = { - { .address = NRF51_UICR_CLENR0, }, - { .address = NRF51_UICR_RBPCONF }, - { .address = NRF51_UICR_XTALFREQ }, - { .address = NRF51_UICR_FWID }, - }; - - for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) { - res = target_read_u32(chip->target, ficr[i].address, - &ficr[i].value); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read %" PRIx32, ficr[i].address); - return res; - } - } - - for (size_t i = 0; i < ARRAY_SIZE(uicr); i++) { - res = target_read_u32(chip->target, uicr[i].address, - &uicr[i].value); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read %" PRIx32, uicr[i].address); - return res; - } - } - - command_print(CMD, - "\n[factory information control block]\n\n" - "code page size: %"PRIu32"B\n" - "code memory size: %"PRIu32"kB\n" - "code region 0 size: %"PRIu32"kB\n" - "pre-programmed code: %s\n" - "number of ram blocks: %"PRIu32"\n" - "ram block 0 size: %"PRIu32"B\n" - "ram block 1 size: %"PRIu32"B\n" - "ram block 2 size: %"PRIu32"B\n" - "ram block 3 size: %"PRIu32 "B\n" - "config id: %" PRIx32 "\n" - "device id: 0x%"PRIx32"%08"PRIx32"\n" - "encryption root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n" - "identity root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n" - "device address type: 0x%"PRIx32"\n" - "device address: 0x%"PRIx32"%08"PRIx32"\n" - "override enable: %"PRIx32"\n" - "NRF_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n" - "BLE_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n" - "\n[user information control block]\n\n" - "code region 0 size: %"PRIu32"kB\n" - "read back protection configuration: %"PRIx32"\n" - "reset value for XTALFREQ: %"PRIx32"\n" - "firmware id: 0x%04"PRIx32, - ficr[0].value, - (ficr[1].value * ficr[0].value) / 1024, - (ficr[2].value == 0xFFFFFFFF) ? 0 : ficr[2].value / 1024, - ((ficr[3].value & 0xFF) == 0x00) ? "present" : "not present", - ficr[4].value, - ficr[5].value, - (ficr[6].value == 0xFFFFFFFF) ? 0 : ficr[6].value, - (ficr[7].value == 0xFFFFFFFF) ? 0 : ficr[7].value, - (ficr[8].value == 0xFFFFFFFF) ? 0 : ficr[8].value, - ficr[9].value, - ficr[10].value, ficr[11].value, - ficr[12].value, ficr[13].value, ficr[14].value, ficr[15].value, - ficr[16].value, ficr[17].value, ficr[18].value, ficr[19].value, - ficr[20].value, - ficr[21].value, ficr[22].value, - ficr[23].value, - ficr[24].value, ficr[25].value, ficr[26].value, ficr[27].value, ficr[28].value, - ficr[29].value, ficr[30].value, ficr[31].value, ficr[32].value, ficr[33].value, - (uicr[0].value == 0xFFFFFFFF) ? 0 : uicr[0].value / 1024, - uicr[1].value & 0xFFFF, - uicr[2].value & 0xFF, - uicr[3].value & 0xFFFF); - - return ERROR_OK; -} static const struct command_registration nrf5_exec_command_handlers[] = { { @@ -1318,13 +1232,6 @@ static const struct command_registration nrf5_exec_command_handlers[] = { .help = "Erase all flash contents of the chip.", .usage = "", }, - { - .name = "info", - .handler = nrf5_handle_info_command, - .mode = COMMAND_EXEC, - .help = "Show FICR and UICR info.", - .usage = "", - }, COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c index 7609fa81c0..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,1043 +120,468 @@ 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} } + {{NUMICRO_APROM_BASE, (aprom_size)}, \ + {NUMICRO_DATA_BASE, (data_size)}, \ + {NUMICRO_LDROM_BASE, (ldrom_size)}, \ + {NUMICRO_CONFIG_BASE, (config_size)}} -#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} } - - -static const struct numicro_cpu_type NuMicroParts[] = { +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. */ struct numicro_flash_bank { struct working_area *write_algorithm; - int probed; + bool probed; 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 == NULL) { - /* 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,17 +904,15 @@ 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; - } else { - bank->sectors[i].is_erased = 1; } } @@ -1558,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; @@ -1582,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) { @@ -1615,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 { @@ -1639,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; @@ -1648,9 +1039,9 @@ static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_ LOG_INFO("Device ID: 0x%08" PRIx32 "", part_id); /* search part numbers */ - for (size_t i = 0; i < ARRAY_SIZE(NuMicroParts); i++) { - if (part_id == NuMicroParts[i].partid) { - *cpu = &NuMicroParts[i]; + for (size_t i = 0; i < ARRAY_SIZE(numicro_parts); i++) { + if (part_id == numicro_parts[i].partid) { + *cpu = &numicro_parts[i]; LOG_INFO("Device Name: %s", (*cpu)->partname); return ERROR_OK; } @@ -1692,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); @@ -1700,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; @@ -1742,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) @@ -1758,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; @@ -1785,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; @@ -1807,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 c42cfb2bbe..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 @@ -46,11 +35,11 @@ * Note: These macros only work for KSEG0/KSEG1 addresses. */ -#define Virt2Phys(v) ((v) & 0x1FFFFFFF) +#define virt2phys(v) ((v) & 0x1FFFFFFF) /* pic32mx configuration register locations */ -#define PIC32MX_DEVCFG0_1xx_2xx 0xBFC00BFC +#define PIC32MX_DEVCFG0_1XX_2XX 0xBFC00BFC #define PIC32MX_DEVCFG0 0xBFC02FFC #define PIC32MX_DEVCFG1 0xBFC02FF8 #define PIC32MX_DEVCFG2 0xBFC02FF4 @@ -91,8 +80,8 @@ #define NVMKEY1 0xAA996655 #define NVMKEY2 0x556699AA -#define MX_1xx_2xx 1 /* PIC32mx1xx/2xx */ -#define MX_17x_27x 2 /* PIC32mx17x/27x */ +#define MX_1XX_2XX 1 /* PIC32mx1xx/2xx */ +#define MX_17X_27X 2 /* PIC32mx17x/27x */ struct pic32mx_flash_bank { bool probed; @@ -279,9 +268,9 @@ static int pic32mx_protect_check(struct flash_bank *bank) } switch (pic32mx_info->dev_type) { - case MX_1xx_2xx: - case MX_17x_27x: - config0_address = PIC32MX_DEVCFG0_1xx_2xx; + case MX_1XX_2XX: + case MX_17X_27X: + config0_address = PIC32MX_DEVCFG0_1XX_2XX; break; default: config0_address = PIC32MX_DEVCFG0; @@ -292,7 +281,7 @@ static int pic32mx_protect_check(struct flash_bank *bank) if ((devcfg0 & (1 << 28)) == 0) /* code protect bit */ num_pages = 0xffff; /* All pages protected */ - else if (Virt2Phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) { + else if (virt2phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) { if (devcfg0 & (1 << 24)) num_pages = 0; /* All pages unprotected */ else @@ -300,10 +289,10 @@ static int pic32mx_protect_check(struct flash_bank *bank) } else { /* pgm flash */ switch (pic32mx_info->dev_type) { - case MX_1xx_2xx: + case MX_1XX_2XX: num_pages = (~devcfg0 >> 10) & 0x7f; break; - case MX_17x_27x: + case MX_17X_27X: num_pages = (~devcfg0 >> 10) & 0x1ff; break; default: @@ -332,7 +321,7 @@ static int pic32mx_erase(struct flash_bank *bank, unsigned int first, } if ((first == 0) && (last == (bank->num_sectors - 1)) - && (Virt2Phys(bank->base) == PIC32MX_PHYS_PGM_FLASH)) { + && (virt2phys(bank->base) == PIC32MX_PHYS_PGM_FLASH)) { /* this will only erase the Program Flash (PFM), not the Boot Flash (BFM) * we need to use the MTAP to perform a full erase */ LOG_DEBUG("Erasing entire program flash"); @@ -345,7 +334,7 @@ static int pic32mx_erase(struct flash_bank *bank, unsigned int first, } for (unsigned int i = first; i <= last; i++) { - target_write_u32(target, PIC32MX_NVMADDR, Virt2Phys(bank->base + bank->sectors[i].offset)); + target_write_u32(target, PIC32MX_NVMADDR, virt2phys(bank->base + bank->sectors[i].offset)); status = pic32mx_nvm_exec(bank, NVMCON_OP_PAGE_ERASE, 10); @@ -353,7 +342,6 @@ static int pic32mx_erase(struct flash_bank *bank, unsigned int first, return ERROR_FLASH_OPERATION_FAILED; if (status & NVMCON_LVDERR) return ERROR_FLASH_OPERATION_FAILED; - bank->sectors[i].is_erased = 1; } return ERROR_OK; @@ -465,8 +453,8 @@ static int pic32mx_write_block(struct flash_bank *bank, const uint8_t *buffer, /* Change values for counters and row size, depending on variant */ switch (pic32mx_info->dev_type) { - case MX_1xx_2xx: - case MX_17x_27x: + case MX_1XX_2XX: + case MX_17X_27X: /* 128 byte row */ pic32mx_flash_write_code[8] = 0x2CD30020; pic32mx_flash_write_code[14] = 0x24840080; @@ -515,7 +503,7 @@ static int pic32mx_write_block(struct flash_bank *bank, const uint8_t *buffer, uint8_t *new_buffer = NULL; if (row_offset && (count >= (row_size / 4))) { new_buffer = malloc(buffer_size); - if (new_buffer == NULL) { + if (!new_buffer) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -548,8 +536,8 @@ static int pic32mx_write_block(struct flash_bank *bank, const uint8_t *buffer, break; } - buf_set_u32(reg_params[0].value, 0, 32, Virt2Phys(source->address)); - buf_set_u32(reg_params[1].value, 0, 32, Virt2Phys(address)); + buf_set_u32(reg_params[0].value, 0, 32, virt2phys(source->address)); + buf_set_u32(reg_params[1].value, 0, 32, virt2phys(address)); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count + row_offset / 4); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, @@ -599,7 +587,7 @@ static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_ { struct target *target = bank->target; - target_write_u32(target, PIC32MX_NVMADDR, Virt2Phys(address)); + target_write_u32(target, PIC32MX_NVMADDR, virt2phys(address)); target_write_u32(target, PIC32MX_NVMDATA, word); return pic32mx_nvm_exec(bank, NVMCON_OP_WORD_PROG, 5); @@ -714,17 +702,17 @@ static int pic32mx_probe(struct flash_bank *bank) } /* Check for PIC32mx1xx/2xx */ - for (i = 0; pic32mx_devs[i].name != NULL; i++) { + for (i = 0; pic32mx_devs[i].name; i++) { if (pic32mx_devs[i].devid == (device_id & 0x0fffffff)) { if ((pic32mx_devs[i].name[0] == '1') || (pic32mx_devs[i].name[0] == '2')) - pic32mx_info->dev_type = (pic32mx_devs[i].name[1] == '7') ? MX_17x_27x : MX_1xx_2xx; + pic32mx_info->dev_type = (pic32mx_devs[i].name[1] == '7') ? MX_17X_27X : MX_1XX_2XX; break; } } switch (pic32mx_info->dev_type) { - case MX_1xx_2xx: - case MX_17x_27x: + case MX_1XX_2XX: + case MX_17X_27X: page_size = 1024; break; default: @@ -732,7 +720,7 @@ static int pic32mx_probe(struct flash_bank *bank) break; } - if (Virt2Phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) { + if (virt2phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) { /* 0x1FC00000: Boot flash size */ #if 0 /* for some reason this register returns 8k for the boot bank size @@ -745,8 +733,8 @@ static int pic32mx_probe(struct flash_bank *bank) #else /* fixed 12k boot bank - see comments above */ switch (pic32mx_info->dev_type) { - case MX_1xx_2xx: - case MX_17x_27x: + case MX_1XX_2XX: + case MX_17X_27X: num_pages = (3 * 1024); break; default: @@ -758,8 +746,8 @@ static int pic32mx_probe(struct flash_bank *bank) /* read the flash size from the device */ if (target_read_u32(target, PIC32MX_BMXPFMSZ, &num_pages) != ERROR_OK) { switch (pic32mx_info->dev_type) { - case MX_1xx_2xx: - case MX_17x_27x: + case MX_1XX_2XX: + case MX_17X_27X: LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 32k flash"); num_pages = (32 * 1024); break; @@ -771,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); @@ -801,37 +789,35 @@ static int pic32mx_auto_probe(struct flash_bank *bank) return pic32mx_probe(bank); } -static int pic32mx_info(struct flash_bank *bank, char *buf, int buf_size) +static int pic32mx_info(struct flash_bank *bank, struct command_invocation *cmd) { struct target *target = bank->target; struct mips32_common *mips32 = target->arch_info; struct mips_ejtag *ejtag_info = &mips32->ejtag_info; uint32_t device_id; - int printed = 0, i; device_id = ejtag_info->idcode; if (((device_id >> 1) & 0x7ff) != PIC32MX_MANUF_ID) { - snprintf(buf, buf_size, - "Cannot identify target as a PIC32MX family (manufacturer 0x%03x != 0x%03x)\n", - (unsigned)((device_id >> 1) & 0x7ff), - PIC32MX_MANUF_ID); + command_print_sameline(cmd, + "Cannot identify target as a PIC32MX family (manufacturer 0x%03x != 0x%03x)\n", + (unsigned)((device_id >> 1) & 0x7ff), + PIC32MX_MANUF_ID); return ERROR_FLASH_OPERATION_FAILED; } - for (i = 0; pic32mx_devs[i].name != NULL; i++) { + int i; + for (i = 0; pic32mx_devs[i].name; i++) { if (pic32mx_devs[i].devid == (device_id & 0x0fffffff)) { - printed = snprintf(buf, buf_size, "PIC32MX%s", pic32mx_devs[i].name); + command_print_sameline(cmd, "PIC32MX%s", pic32mx_devs[i].name); break; } } - if (pic32mx_devs[i].name == NULL) - printed = snprintf(buf, buf_size, "Unknown"); + if (!pic32mx_devs[i].name) + command_print_sameline(cmd, "Unknown"); - buf += printed; - buf_size -= printed; - snprintf(buf, buf_size, " Ver: 0x%02x", + command_print_sameline(cmd, " Ver: 0x%02x", (unsigned)((device_id >> 28) & 0xf)); return ERROR_OK; @@ -850,7 +836,7 @@ COMMAND_HANDLER(pic32mx_handle_pgm_word_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 2, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (address < bank->base || address >= (bank->base + bank->size)) { @@ -880,14 +866,12 @@ 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); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; target = bank->target; @@ -946,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 9c2fdf7754..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 @@ -139,7 +128,7 @@ struct psoc4_chip_family { uint32_t flags; }; -const struct psoc4_chip_family psoc4_families[] = { +static const struct psoc4_chip_family psoc4_families[] = { { 0x93, "PSoC4100/4200", .flags = PSOC4_FAMILY_FLAG_LEGACY }, { 0x9A, "PSoC4000", .flags = 0 }, { 0x9E, "PSoC/PRoC BLE (119E)", .flags = 0 }, @@ -320,7 +309,7 @@ static int psoc4_sysreq(struct flash_bank *bank, uint8_t cmd, sysreq_wait_algorithm->address + sysreq_wait_algorithm->size); struct armv7m_common *armv7m = target_to_armv7m(target); - if (armv7m == NULL) { + if (!armv7m) { /* something is very wrong if armv7m is NULL */ LOG_ERROR("unable to get armv7m target"); retval = ERROR_FAIL; @@ -335,7 +324,7 @@ static int psoc4_sysreq(struct flash_bank *bank, uint8_t cmd, /* Execute wait code */ retval = target_run_algorithm(target, 0, NULL, - sizeof(reg_params) / sizeof(*reg_params), reg_params, + ARRAY_SIZE(reg_params), reg_params, sysreq_wait_algorithm->address, 0, 1000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("sysreq wait code execution failed"); @@ -520,16 +509,9 @@ static int psoc4_mass_erase(struct flash_bank *bank) /* Call "Erase All" system ROM API */ uint32_t param = 0; - retval = psoc4_sysreq(bank, PSOC4_CMD_ERASE_ALL, + return psoc4_sysreq(bank, PSOC4_CMD_ERASE_ALL, 0, ¶m, sizeof(param), NULL); - - if (retval == ERROR_OK) - /* set all sectors as erased */ - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - - return retval; } @@ -576,7 +558,7 @@ static int psoc4_protect(struct flash_bank *bank, int set, unsigned int first, int prot_sz = num_bits / 8; sysrq_buffer = malloc(param_sz + prot_sz); - if (sysrq_buffer == NULL) { + if (!sysrq_buffer) { LOG_ERROR("no memory for row buffer"); return ERROR_FAIL; } @@ -624,7 +606,7 @@ COMMAND_HANDLER(psoc4_handle_flash_autoerase_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; @@ -658,7 +640,7 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, return retval; sysrq_buffer = malloc(param_sz + psoc4_info->row_size); - if (sysrq_buffer == NULL) { + if (!sysrq_buffer) { LOG_ERROR("no memory for row buffer"); return ERROR_FAIL; } @@ -669,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) { @@ -711,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; } @@ -792,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 @@ -802,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; @@ -833,7 +810,7 @@ static int psoc4_probe(struct flash_bank *bank) bank->size = num_rows * row_size; bank->num_sectors = num_rows; bank->sectors = alloc_block_array(0, row_size, num_rows); - if (bank->sectors == NULL) + if (!bank->sectors) return ERROR_FAIL; LOG_DEBUG("flash bank set %" PRIu32 " rows", num_rows); @@ -851,7 +828,7 @@ static int psoc4_auto_probe(struct flash_bank *bank) } -static int get_psoc4_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_psoc4_info(struct flash_bank *bank, struct command_invocation *cmd) { struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; @@ -863,35 +840,30 @@ static int get_psoc4_info(struct flash_bank *bank, char *buf, int buf_size) uint32_t size_in_kb = bank->size / 1024; if (target->state != TARGET_HALTED) { - snprintf(buf, buf_size, "%s, flash %" PRIu32 " kb" + command_print_sameline(cmd, "%s, flash %" PRIu32 " kb" " (halt target to see details)", family->name, size_in_kb); return ERROR_OK; } - int retval; - int printed = 0; uint32_t silicon_id; uint16_t family_id; uint8_t protection; - retval = psoc4_get_silicon_id(bank, &silicon_id, &family_id, &protection); + int retval = psoc4_get_silicon_id(bank, &silicon_id, &family_id, &protection); if (retval != ERROR_OK) return retval; if (family_id != psoc4_info->family_id) - printed = snprintf(buf, buf_size, "Family id mismatch 0x%02" PRIx16 + command_print_sameline(cmd, "Family id mismatch 0x%02" PRIx16 "/0x%02" PRIx16 ", silicon id 0x%08" PRIx32, psoc4_info->family_id, family_id, silicon_id); else { - printed = snprintf(buf, buf_size, "%s silicon id 0x%08" PRIx32 "", + command_print_sameline(cmd, "%s silicon id 0x%08" PRIx32 "", family->name, silicon_id); } - buf += printed; - buf_size -= printed; - const char *prot_txt = psoc4_decode_chip_protection(protection); - snprintf(buf, buf_size, ", flash %" PRIu32 " kb %s", size_in_kb, prot_txt); + command_print_sameline(cmd, ", flash %" PRIu32 " kb %s", size_in_kb, prot_txt); return ERROR_OK; } @@ -903,7 +875,7 @@ COMMAND_HANDLER(psoc4_handle_mass_erase_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = psoc4_mass_erase(bank); diff --git a/src/flash/nor/psoc5lp.c b/src/flash/nor/psoc5lp.c index c651dea7a6..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 @@ -86,15 +75,15 @@ #define PM_ACT_CFG0_EN_CLK_SPC (1 << 3) -#define PHUB_CHx_BASIC_CFG_EN (1 << 0) -#define PHUB_CHx_BASIC_CFG_WORK_SEP (1 << 5) +#define PHUB_CHX_BASIC_CFG_EN (1 << 0) +#define PHUB_CHX_BASIC_CFG_WORK_SEP (1 << 5) -#define PHUB_CHx_ACTION_CPU_REQ (1 << 0) +#define PHUB_CHX_ACTION_CPU_REQ (1 << 0) -#define PHUB_CFGMEMx_CFG0 (1 << 7) +#define PHUB_CFGMEMX_CFG0 (1 << 7) -#define PHUB_TDMEMx_ORIG_TD0_NEXT_TD_PTR_LAST (0xff << 16) -#define PHUB_TDMEMx_ORIG_TD0_INC_SRC_ADDR (1 << 24) +#define PHUB_TDMEMX_ORIG_TD0_NEXT_TD_PTR_LAST (0xff << 16) +#define PHUB_TDMEMX_ORIG_TD0_INC_SRC_ADDR (1 << 24) #define NVL_3_ECCEN (1 << 3) @@ -753,14 +742,14 @@ static int psoc5lp_nvl_write(struct flash_bank *bank, } static int psoc5lp_nvl_get_info_command(struct flash_bank *bank, - char *buf, int buf_size) + struct command_invocation *cmd) { struct psoc5lp_nvl_flash_bank *psoc_nvl_bank = bank->driver_priv; char part_number[PART_NUMBER_LEN]; psoc5lp_get_part_number(psoc_nvl_bank->device, part_number); - snprintf(buf, buf_size, "%s", part_number); + command_print_sameline(cmd, "%s", part_number); return ERROR_OK; } @@ -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, @@ -934,14 +907,14 @@ static int psoc5lp_eeprom_write(struct flash_bank *bank, return ERROR_OK; } -static int psoc5lp_eeprom_get_info_command(struct flash_bank *bank, char *buf, int buf_size) +static int psoc5lp_eeprom_get_info_command(struct flash_bank *bank, struct command_invocation *cmd) { struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank = bank->driver_priv; char part_number[PART_NUMBER_LEN]; psoc5lp_get_part_number(psoc_eeprom_bank->device, part_number); - snprintf(buf, buf_size, "%s", part_number); + command_print_sameline(cmd, "%s", part_number); return ERROR_OK; } @@ -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, @@ -1113,7 +1070,7 @@ static int psoc5lp_erase_check(struct flash_bank *bank) struct target_memory_check_block *block_array; block_array = malloc(num_sectors * sizeof(struct target_memory_check_block)); - if (block_array == NULL) + if (!block_array) return ERROR_FAIL; for (unsigned int i = 0; i < num_sectors; i++) { @@ -1289,13 +1246,13 @@ static int psoc5lp_write(struct flash_bank *bank, const uint8_t *buffer, retval = target_write_u32(target, even_row ? PHUB_CH0_BASIC_CFG : PHUB_CH1_BASIC_CFG, - PHUB_CHx_BASIC_CFG_WORK_SEP | PHUB_CHx_BASIC_CFG_EN); + PHUB_CHX_BASIC_CFG_WORK_SEP | PHUB_CHX_BASIC_CFG_EN); if (retval != ERROR_OK) goto err_dma; retval = target_write_u32(target, even_row ? PHUB_CFGMEM0_CFG0 : PHUB_CFGMEM1_CFG0, - PHUB_CFGMEMx_CFG0); + PHUB_CFGMEMX_CFG0); if (retval != ERROR_OK) goto err_dma; @@ -1307,8 +1264,8 @@ static int psoc5lp_write(struct flash_bank *bank, const uint8_t *buffer, retval = target_write_u32(target, even_row ? PHUB_TDMEM0_ORIG_TD0 : PHUB_TDMEM1_ORIG_TD0, - PHUB_TDMEMx_ORIG_TD0_INC_SRC_ADDR | - PHUB_TDMEMx_ORIG_TD0_NEXT_TD_PTR_LAST | + PHUB_TDMEMX_ORIG_TD0_INC_SRC_ADDR | + PHUB_TDMEMX_ORIG_TD0_NEXT_TD_PTR_LAST | ((SPC_OPCODE_LEN + 1 + row_size + 3 + SPC_OPCODE_LEN + 5) & 0xfff)); if (retval != ERROR_OK) goto err_dma; @@ -1325,7 +1282,7 @@ static int psoc5lp_write(struct flash_bank *bank, const uint8_t *buffer, retval = target_write_u32(target, even_row ? PHUB_CH0_ACTION : PHUB_CH1_ACTION, - PHUB_CHx_ACTION_CPU_REQ); + PHUB_CHX_ACTION_CPU_REQ); if (retval != ERROR_OK) goto err_dma_action; } @@ -1397,7 +1354,7 @@ static int psoc5lp_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int psoc5lp_get_info_command(struct flash_bank *bank, char *buf, int buf_size) +static int psoc5lp_get_info_command(struct flash_bank *bank, struct command_invocation *cmd) { struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv; char part_number[PART_NUMBER_LEN]; @@ -1406,7 +1363,7 @@ static int psoc5lp_get_info_command(struct flash_bank *bank, char *buf, int buf_ psoc5lp_get_part_number(psoc_bank->device, part_number); ecc = psoc_bank->ecc_enabled ? "ECC enabled" : "ECC disabled"; - snprintf(buf, buf_size, "%s %s", part_number, ecc); + command_print_sameline(cmd, "%s %s", part_number, ecc); return ERROR_OK; } diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index df151c1b5e..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 @@ -24,11 +13,12 @@ #include <time.h> #include "imp.h" +#include "helper/time_support.h" +#include "target/arm_adi_v5.h" #include "target/target.h" #include "target/cortex_m.h" #include "target/breakpoints.h" #include "target/target_type.h" -#include "time_support.h" #include "target/algorithm.h" /************************************************************************************************** @@ -151,12 +141,6 @@ static int sromalgo_prepare(struct target *target) if (hr != ERROR_OK) return hr; - /* Restore THUMB bit in xPSR register */ - const struct armv7m_common *cm = target_to_armv7m(target); - hr = cm->store_core_reg_u32(target, ARMV7M_xPSR, 0x01000000); - if (hr != ERROR_OK) - return hr; - /* Allocate Working Area for Stack and Flash algorithm */ hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area); if (hr != ERROR_OK) @@ -187,10 +171,8 @@ destroy_rp_free_wa: /* Something went wrong, do some cleanup */ destroy_reg_param(®_params); - if (g_stack_area) { - target_free_working_area(target, g_stack_area); - g_stack_area = NULL; - } + target_free_working_area(target, g_stack_area); + g_stack_area = NULL; return hr; } @@ -497,11 +479,10 @@ static const char *protection_to_str(uint8_t protection) /** *********************************************************************************************** * @brief psoc6_get_info Displays human-readable information about acquired device * @param bank current flash bank - * @param buf pointer to buffer for human-readable text - * @param buf_size size of the buffer + * @param cmd pointer to command invocation instance * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ -static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size) +static int psoc6_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct psoc6_target_info *psoc6_info = bank->driver_priv; @@ -512,7 +493,7 @@ static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size) if (hr != ERROR_OK) return hr; - snprintf(buf, buf_size, + command_print_sameline(cmd, "PSoC6 Silicon ID: 0x%08" PRIX32 "\n" "Protection: %s\n" "Main Flash size: %" PRIu32 " kB\n" @@ -610,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; @@ -750,9 +730,6 @@ static int psoc6_erase(struct flash_bank *bank, unsigned int first, if (hr != ERROR_OK) goto exit_free_wa; - for (unsigned int i = first; i < first + rows_in_sector; i++) - bank->sectors[i].is_erased = 1; - first += rows_in_sector; } else { /* Perform Row Erase otherwise */ @@ -760,7 +737,6 @@ static int psoc6_erase(struct flash_bank *bank, unsigned int first, if (hr != ERROR_OK) goto exit_free_wa; - bank->sectors[first].is_erased = 1; first += 1; } } @@ -879,7 +855,6 @@ exit: /** *********************************************************************************************** * @brief Performs Mass Erase operation - * @param bank flash bank index to erase * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ COMMAND_HANDLER(psoc6_handle_mass_erase_command) @@ -908,7 +883,7 @@ COMMAND_HANDLER(psoc6_handle_mass_erase_command) * @param target current target * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ -int handle_reset_halt(struct target *target) +static int handle_reset_halt(struct target *target) { int hr; uint32_t reset_addr; @@ -1026,7 +1001,7 @@ static const struct command_registration psoc6_exec_command_handlers[] = { .name = "reset_halt", .handler = psoc6_handle_reset_halt, .mode = COMMAND_EXEC, - .usage = NULL, + .usage = "", .help = "Tries to simulate broken Vector Catch", }, COMMAND_REGISTRATION_DONE 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 new file mode 100644 index 0000000000..b2ebd9c49e --- /dev/null +++ b/src/flash/nor/rp2040.c @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include <helper/binarybuffer.h> +#include <target/algorithm.h> +#include <target/armv7m.h> +#include "spi.h" + +/* NOTE THAT THIS CODE REQUIRES FLASH ROUTINES in BOOTROM WITH FUNCTION TABLE PTR AT 0x00000010 + Your gdbinit should load the bootrom.elf if appropriate */ + +/* this is 'M' 'u', 1 (version) */ +#define BOOTROM_MAGIC 0x01754d +#define BOOTROM_MAGIC_ADDR 0x00000010 + +/* Call a ROM function via the debug trampoline + Up to four arguments passed in r0...r3 as per ABI + Function address is passed in r7 + the trampoline is needed because OpenOCD "algorithm" code insists on sw breakpoints. */ + +#define MAKE_TAG(a, b) (((b)<<8) | a) +#define FUNC_DEBUG_TRAMPOLINE MAKE_TAG('D', 'T') +#define FUNC_DEBUG_TRAMPOLINE_END MAKE_TAG('D', 'E') +#define FUNC_FLASH_EXIT_XIP MAKE_TAG('E', 'X') +#define FUNC_CONNECT_INTERNAL_FLASH MAKE_TAG('I', 'F') +#define FUNC_FLASH_RANGE_ERASE MAKE_TAG('R', 'E') +#define FUNC_FLASH_RANGE_PROGRAM MAKE_TAG('R', 'P') +#define FUNC_FLASH_FLUSH_CACHE MAKE_TAG('F', 'C') +#define FUNC_FLASH_ENTER_CMD_XIP MAKE_TAG('C', 'X') + +struct rp2040_flash_bank { + /* flag indicating successful flash probe */ + bool probed; + /* stack used by Boot ROM calls */ + struct working_area *stack; + /* function jump table populated by rp2040_flash_probe() */ + uint16_t jump_debug_trampoline; + uint16_t jump_debug_trampoline_end; + uint16_t jump_flash_exit_xip; + uint16_t jump_connect_internal_flash; + uint16_t jump_flash_range_erase; + uint16_t jump_flash_range_program; + uint16_t jump_flush_cache; + uint16_t jump_enter_cmd_xip; + /* detected model of SPI flash */ + 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; + int err = target_read_u32(target, BOOTROM_MAGIC_ADDR, &magic); + if (err != ERROR_OK) + return err; + + magic &= 0xffffff; /* ignore bootrom version */ + if (magic != BOOTROM_MAGIC) { + if (!((magic ^ BOOTROM_MAGIC)&0xffff)) + LOG_ERROR("Incorrect RP2040 BOOT ROM version"); + else + LOG_ERROR("RP2040 BOOT ROM not found"); + return ERROR_FAIL; + } + + /* dereference the table pointer */ + uint16_t table_entry; + err = target_read_u16(target, BOOTROM_MAGIC_ADDR + 4, &table_entry); + if (err != ERROR_OK) + return err; + + uint16_t entry_tag; + do { + err = target_read_u16(target, table_entry, &entry_tag); + if (err != ERROR_OK) + return err; + if (entry_tag == tag) { + /* 16 bit symbol is next */ + return target_read_u16(target, table_entry + 2, symbol); + } + table_entry += 4; + } while (entry_tag); + return ERROR_FAIL; +} + +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, unsigned int timeout_ms) +{ + char *regnames[4] = { "r0", "r1", "r2", "r3" }; + + assert(n_args <= ARRAY_SIZE(regnames)); /* only allow register arguments */ + + if (!priv->stack) { + LOG_ERROR("no stack for flash programming code"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + target_addr_t stacktop = priv->stack->address + priv->stack->size; + + 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; + + for (unsigned int i = 0; i < n_args; ++i) { + init_reg_param(&args[i], regnames[i], 32, PARAM_OUT); + buf_set_u32(args[i].value, 0, 32, argdata[i]); + } + /* 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_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 */ + alg_info.common_magic = ARMV7M_COMMON_MAGIC; + alg_info.core_mode = ARM_MODE_THREAD; + int err = target_run_algorithm( + target, + 0, NULL, /* No memory arguments */ + n_reg_params, args, /* User arguments + r7 + sp */ + priv->jump_debug_trampoline, priv->jump_debug_trampoline_end, + timeout_ms, + &alg_info + ); + + 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, 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; +} + +/* 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(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(target, priv, priv->jump_connect_internal_flash, NULL, 0, 1000); + if (err != ERROR_OK) { + LOG_ERROR("Failed to connect internal flash"); + return err; + } + + LOG_DEBUG("Kicking flash out of XIP mode"); + err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0, 1000); + if (err != ERROR_OK) { + LOG_ERROR("Failed to exit flash XIP mode"); + return err; + } + + return ERROR_OK; +} + +static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32, count, offset); + + 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; + } + + struct working_area *bounce = NULL; + + 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"); + goto cleanup; + } + + LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address); + + while (count > 0) { + uint32_t write_size = count > chunk_size ? chunk_size : count; + LOG_DEBUG("Writing %d bytes to offset 0x%" PRIx32, write_size, offset); + err = target_write_buffer(target, bounce->address, write_size, buffer); + if (err != ERROR_OK) { + LOG_ERROR("Could not load data into target bounce buffer"); + break; + } + uint32_t args[3] = { + offset, /* addr */ + bounce->address, /* data */ + write_size /* count */ + }; + 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; + } + + buffer += write_size; + offset += write_size; + count -= write_size; + } + +cleanup: + target_free_working_area(target, bounce); + + rp2040_finalize_stack_free(bank); + + 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 = rp2040_stack_grab_and_prep(bank); + if (err != ERROR_OK) + goto cleanup; + + LOG_DEBUG("Remote call flash_range_erase"); + + uint32_t args[4] = { + bank->sectors[first].offset, /* addr */ + bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset, /* count */ + priv->dev->sectorsize, /* block_size */ + priv->dev->erase_cmd /* block_cmd */ + }; + + /* + The RP2040 Boot ROM provides a _flash_range_erase() API call documented in Section 2.8.3.1.3: + https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf + and the particular source code for said Boot ROM function can be found here: + 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). + */ + + 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; +} + +/* ----------------------------------------------------------------------------- + Driver probing etc */ + +static int rp2040_ssel_active(struct target *target, bool active) +{ + const target_addr_t qspi_ctrl_addr = 0x4001800c; + const uint32_t qspi_ctrl_outover_low = 2UL << 8; + const uint32_t qspi_ctrl_outover_high = 3UL << 8; + uint32_t state = (active) ? qspi_ctrl_outover_low : qspi_ctrl_outover_high; + uint32_t val; + + int err = target_read_u32(target, qspi_ctrl_addr, &val); + if (err != ERROR_OK) + return err; + + val = (val & ~qspi_ctrl_outover_high) | state; + + err = target_write_u32(target, qspi_ctrl_addr, val); + if (err != ERROR_OK) + return err; + + 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."); + return err; + } + priv->jump_debug_trampoline &= ~1u; /* mask off thumb bit */ + + err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE_END, &priv->jump_debug_trampoline_end); + if (err != ERROR_OK) { + LOG_ERROR("Debug trampoline end not found in RP2040 ROM."); + return err; + } + priv->jump_debug_trampoline_end &= ~1u; /* mask off thumb bit */ + + err = rp2040_lookup_symbol(target, FUNC_FLASH_EXIT_XIP, &priv->jump_flash_exit_xip); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2040 ROM."); + return err; + } + + err = rp2040_lookup_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, &priv->jump_connect_internal_flash); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2040 ROM."); + return err; + } + + err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_ERASE, &priv->jump_flash_range_erase); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2040 ROM."); + return err; + } + + err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_PROGRAM, &priv->jump_flash_range_program); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2040 ROM."); + return err; + } + + err = rp2040_lookup_symbol(target, FUNC_FLASH_FLUSH_CACHE, &priv->jump_flush_cache); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2040 ROM."); + return err; + } + + err = rp2040_lookup_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, &priv->jump_enter_cmd_xip); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2040 ROM."); + 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"); + + } else { + /* zero bank size in cfg, read SPI flash ID and autodetect */ + err = rp2040_stack_grab_and_prep(bank); + + uint32_t device_id = 0; + if (err == ERROR_OK) + err = rp2040_spi_read_flash_id(target, &device_id); + + rp2040_finalize_stack_free(bank); + + 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; + } + + 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); + + bank->size = priv->dev->size_in_bytes; + } + + /* 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->num_sectors = bank->size / priv->dev->sectorsize; + 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) + return ERROR_FAIL; + + if (err == ERROR_OK) + priv->probed = true; + + return err; +} + +static int rp2040_flash_auto_probe(struct flash_bank *bank) +{ + struct rp2040_flash_bank *priv = bank->driver_priv; + + if (priv->probed) + return ERROR_OK; + + return rp2040_flash_probe(bank); +} + +static void rp2040_flash_free_driver_priv(struct flash_bank *bank) +{ + free(bank->driver_priv); + bank->driver_priv = NULL; +} + +/* ----------------------------------------------------------------------------- + Driver boilerplate */ + +FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command) +{ + struct rp2040_flash_bank *priv; + priv = malloc(sizeof(struct rp2040_flash_bank)); + priv->probed = false; + + /* Set up driver_priv */ + bank->driver_priv = priv; + + return ERROR_OK; +} + +const struct flash_driver rp2040_flash = { + .name = "rp2040_flash", + .flash_bank_command = rp2040_flash_bank_command, + .erase = rp2040_flash_erase, + .write = rp2040_flash_write, + .read = default_flash_read, + .probe = rp2040_flash_probe, + .auto_probe = rp2040_flash_auto_probe, + .erase_check = default_flash_blank_check, + .free_driver_priv = rp2040_flash_free_driver_priv +}; 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 new file mode 100644 index 0000000000..5bfb541946 --- /dev/null +++ b/src/flash/nor/sfdp.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch <andreas.bolsch@mni.thm.de * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include "spi.h" +#include "sfdp.h" + +#define SFDP_MAGIC 0x50444653 +#define SFDP_ACCESS_PROT 0xFF +#define SFDP_BASIC_FLASH 0xFF00 +#define SFDP_4BYTE_ADDR 0xFF84 + +static const char *sfdp_name = "sfdp"; + +struct sfdp_hdr { + uint32_t signature; + uint32_t revision; +}; + +struct sfdp_phdr { + uint32_t revision; + uint32_t ptr; +}; + +struct sfdp_basic_flash_param { + uint32_t fast_addr; /* 01: fast read and 3/4 address bytes */ + uint32_t density; /* 02: memory density */ + uint32_t fast_1x4; /* 03: 1-1-4 and 1-4-4 fast read */ + uint32_t fast_1x2; /* 04: 1-2-2 and 1-1-2 fast read */ + uint32_t fast_444; /* 05: 4-4-4 and 2-2-2 fast read */ + uint32_t read_222; /* 06: 2-2-2 fast read instr and dummy */ + uint32_t read_444; /* 07: 4-4-4 fast read instr and dummy */ + uint32_t erase_t12; /* 08: erase types 1, 2 */ + uint32_t erase_t34; /* 09: erase types 3, 4 */ + uint32_t erase_time; /* 10: erase times for types 1 - 4 */ + uint32_t chip_byte; /* 11: chip erase time, byte prog time, page prog */ + uint32_t susp_time; /* 12: suspend and resume times */ + uint32_t susp_instr; /* 13: suspend and resume instr */ + uint32_t pwrd_instr; /* 14: powerdown instr */ + uint32_t quad_req; /* 15: quad enable requirements */ + uint32_t addr_reset; /* 16: 3-/4-byte addressing and reset */ + uint32_t read_1x8; /* 17: 1-1-8 and 1-8-8 fast read instr and dummy */ + uint32_t dtr_drive; /* 18: dtr modes and drive strength */ + uint32_t octal_req; /* 19: octal enable requirements */ + uint32_t speed_888; /* 20: speed in 8-8-8 modes */ +}; + +struct sfdp_4byte_addr_param { + uint32_t flags; /* 01: various flags */ + uint32_t erase_t1234; /* 02: erase commands */ +}; + +/* Try to get parameters from flash via SFDP */ +int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, + read_sfdp_block_t read_sfdp_block) +{ + struct sfdp_hdr header; + struct sfdp_phdr *pheaders = NULL; + uint32_t *ptable = NULL; + unsigned int j, k, nph; + int retval, erase_type = 0; + + memset(dev, 0, sizeof(struct flash_device)); + + /* retrieve SFDP header */ + memset(&header, 0, sizeof(header)); + retval = read_sfdp_block(bank, 0x0, sizeof(header) >> 2, (uint32_t *)&header); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("header 0x%08" PRIx32 " 0x%08" PRIx32, header.signature, header.revision); + if (header.signature != SFDP_MAGIC) { + LOG_INFO("no SDFP found"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + if (((header.revision >> 24) & 0xFF) != SFDP_ACCESS_PROT) { + LOG_ERROR("access protocol 0x%02x not implemented", + (header.revision >> 24) & 0xFFU); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + /* retrieve table of parameter headers */ + nph = ((header.revision >> 16) & 0xFF) + 1; + LOG_DEBUG("parameter headers: %d", nph); + pheaders = malloc(sizeof(struct sfdp_phdr) * nph); + if (!pheaders) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + memset(pheaders, 0, sizeof(struct sfdp_phdr) * nph); + retval = read_sfdp_block(bank, sizeof(header), + (sizeof(struct sfdp_phdr) >> 2) * nph, (uint32_t *)pheaders); + if (retval != ERROR_OK) + goto err; + + for (k = 0; k < nph; k++) { + uint8_t words = (pheaders[k].revision >> 24) & 0xFF; + uint16_t id = (((pheaders[k].ptr) >> 16) & 0xFF00) | (pheaders[k].revision & 0xFF); + uint32_t ptr = pheaders[k].ptr & 0xFFFFFF; + + LOG_DEBUG("pheader %d len=0x%02" PRIx8 " id=0x%04" PRIx16 + " ptr=0x%06" PRIx32, k, words, id, ptr); + + /* retrieve parameter table */ + ptable = malloc(words << 2); + if (!ptable) { + LOG_ERROR("not enough memory"); + retval = ERROR_FAIL; + goto err; + } + retval = read_sfdp_block(bank, ptr, words, ptable); + if (retval != ERROR_OK) + goto err; + + for (j = 0; j < words; j++) + LOG_DEBUG("word %02d 0x%08X", j + 1, ptable[j]); + + if (id == SFDP_BASIC_FLASH) { + struct sfdp_basic_flash_param *table = (struct sfdp_basic_flash_param *)ptable; + uint16_t erase; + + if (words < 9) { + LOG_ERROR("id=0x%04" PRIx16 " invalid length %d", id, words); + retval = ERROR_FLASH_BANK_NOT_PROBED; + goto err; + } + + LOG_DEBUG("basic flash parameter table"); + /* dummy device name */ + dev->name = sfdp_name; + + /* default instructions */ + dev->read_cmd = SPIFLASH_READ; + dev->pprog_cmd = SPIFLASH_PAGE_PROGRAM; + dev->chip_erase_cmd = SPIFLASH_MASS_ERASE; + + /* get device size */ + if (table->density & (1UL << 31)) + dev->size_in_bytes = 1UL << ((table->density & ~(1UL << 31)) - 3); + else + dev->size_in_bytes = (table->density + 1) >> 3; + + /* 2-2-2 read instruction, not used */ + if (table->fast_444 & (1UL << 0)) + dev->qread_cmd = (table->read_222 >> 24) & 0xFF; + + /* 4-4-4 read instruction */ + if (table->fast_444 & (1UL << 4)) + dev->qread_cmd = (table->read_444 >> 24) & 0xFF; + + /* find the largest erase block size and instruction */ + erase = (table->erase_t12 >> 0) & 0xFFFF; + erase_type = 1; + if (((table->erase_t12 >> 16) & 0xFF) > (erase & 0xFF)) { + erase = (table->erase_t12 >> 16) & 0xFFFF; + erase_type = 2; + } + if (((table->erase_t34 >> 0) & 0xFF) > (erase & 0xFF)) { + erase = (table->erase_t34 >> 0) & 0xFFFF; + erase_type = 3; + } + if (((table->erase_t34 >> 16) & 0xFF) > (erase & 0xFF)) { + erase = (table->erase_t34 >> 16) & 0xFFFF; + erase_type = 4; + } + dev->erase_cmd = (erase >> 8) & 0xFF; + dev->sectorsize = 1UL << (erase & 0xFF); + + if ((offsetof(struct sfdp_basic_flash_param, chip_byte) >> 2) < words) { + /* get Program Page Size, if chip_byte present, that's optional */ + dev->pagesize = 1UL << ((table->chip_byte >> 4) & 0x0F); + } else { + /* no explicit page size specified ... */ + if (table->fast_addr & (1UL << 2)) { + /* Write Granularity = 1, use 64 bytes */ + dev->pagesize = 1UL << 6; + } else { + /* Write Granularity = 0, use 16 bytes */ + dev->pagesize = 1UL << 4; + } + } + + if (dev->size_in_bytes > (1UL << 24)) { + if (((table->fast_addr >> 17) & 0x3) == 0x0) + LOG_ERROR("device needs paging - not implemented"); + + /* 4-byte addresses needed if more than 16 MBytes */ + if (((offsetof(struct sfdp_basic_flash_param, addr_reset) >> 2) < words) && + (table->addr_reset & (1UL << 29))) { + /* dedicated 4-byte-address instructions, hopefully these ... + * this entry is unfortunately optional as well + * a subsequent 4-byte address table may overwrite this */ + dev->read_cmd = 0x13; + dev->pprog_cmd = 0x12; + dev->erase_cmd = 0xDC; + if (dev->qread_cmd != 0) + dev->qread_cmd = 0xEC; + } else if (((table->fast_addr >> 17) & 0x3) == 0x1) + LOG_INFO("device has to be switched to 4-byte addresses"); + } + } else if (id == SFDP_4BYTE_ADDR) { + struct sfdp_4byte_addr_param *table = (struct sfdp_4byte_addr_param *)ptable; + + if (words >= (offsetof(struct sfdp_4byte_addr_param, erase_t1234) + + sizeof(table->erase_t1234)) >> 2) { + LOG_INFO("4-byte address parameter table"); + + /* read and page program instructions */ + if (table->flags & (1UL << 0)) + dev->read_cmd = 0x13; + if (table->flags & (1UL << 5)) + dev->qread_cmd = 0xEC; + if (table->flags & (1UL << 6)) + dev->pprog_cmd = 0x12; + + /* erase instructions */ + if ((erase_type == 1) && (table->flags & (1UL << 9))) + dev->erase_cmd = (table->erase_t1234 >> 0) & 0xFF; + else if ((erase_type == 2) && (table->flags & (1UL << 10))) + dev->erase_cmd = (table->erase_t1234 >> 8) & 0xFF; + else if ((erase_type == 3) && (table->flags & (1UL << 11))) + dev->erase_cmd = (table->erase_t1234 >> 16) & 0xFF; + else if ((erase_type == 4) && (table->flags & (1UL << 12))) + dev->erase_cmd = (table->erase_t1234 >> 24) & 0xFF; + } else + LOG_ERROR("parameter table id=0x%04" PRIx16 " invalid length %d", id, words); + } else + LOG_DEBUG("unimplemented parameter table id=0x%04" PRIx16, id); + + free(ptable); + ptable = NULL; + } + + if (erase_type != 0) { + LOG_INFO("valid SFDP detected"); + retval = ERROR_OK; + } else { + LOG_ERROR("incomplete/invalid SFDP"); + retval = ERROR_FLASH_BANK_NOT_PROBED; + } + +err: + free(pheaders); + free(ptable); + + return retval; +} diff --git a/src/flash/nor/sfdp.h b/src/flash/nor/sfdp.h new file mode 100644 index 0000000000..1c9af326b3 --- /dev/null +++ b/src/flash/nor/sfdp.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch <andreas.bolsch@mni.thm.de * + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_SFDP_H +#define OPENOCD_FLASH_NOR_SFDP_H + +/* per JESD216D 'addr' is *byte* based but must be word aligned, + * 'buffer' is word based, word aligned and always little-endian encoded, + * in the flash, 'addr_len' is 3 or 4, 'dummy' ***usually*** 8 + * + * the actual number of dummy clocks should be worked out by this function + * dynamically, i.e. by scanning the first few bytes for the SFDP signature + * + * buffer contents is supposed to be returned in ***host*** endianness */ +typedef int (*read_sfdp_block_t)(struct flash_bank *bank, uint32_t addr, + uint32_t words, uint32_t *buffer); + +extern int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, + read_sfdp_block_t read_sfdp_block); + +#endif /* OPENOCD_FLASH_NOR_SFDP_H */ diff --git a/src/flash/nor/sh_qspi.c b/src/flash/nor/sh_qspi.c index 4ec7ebe658..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> @@ -703,11 +704,14 @@ static int sh_qspi_upload_helper(struct flash_bank *bank) }; int ret; - if (info->source) - target_free_working_area(target, info->source); - if (info->io_algorithm) - target_free_working_area(target, info->io_algorithm); + target_free_working_area(target, info->source); + target_free_working_area(target, info->io_algorithm); + /* FIXME: Working areas are allocated during flash probe + * and eventual target_free_all_working_areas() called in case + * of target reset or run is not handled at all. + * Not a big problem if area backp is off. + */ /* flash write code */ if (target_alloc_working_area(target, sizeof(sh_qspi_io_code), &info->io_algorithm) != ERROR_OK) { @@ -851,17 +855,16 @@ static int sh_qspi_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int sh_qspi_get_info(struct flash_bank *bank, char *buf, int buf_size) +static int sh_qspi_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct sh_qspi_flash_bank *info = bank->driver_priv; if (!info->probed) { - snprintf(buf, buf_size, - "\nSH QSPI flash bank not probed yet\n"); + command_print_sameline(cmd, "\nSH QSPI flash bank not probed yet\n"); return ERROR_OK; } - snprintf(buf, buf_size, "\nSH QSPI flash information:\n" + command_print_sameline(cmd, "\nSH QSPI flash information:\n" " Device \'%s\' (ID 0x%08" PRIx32 ")\n", info->dev->name, info->dev->device_id); diff --git a/src/flash/nor/sim3x.c b/src/flash/nor/sim3x.c index 76280f1abc..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 @@ -27,6 +16,7 @@ #include <helper/binarybuffer.h> #include <helper/time_support.h> #include <target/algorithm.h> +#include <target/arm_adi_v5.h> #include <target/cortex_m.h> /* SI32_DEVICEID0 */ @@ -511,7 +501,7 @@ static int sim3x_flash_write(struct flash_bank *bank, const uint8_t *buffer, uin count++; new_buffer = malloc(count); - if (new_buffer == NULL) { + if (!new_buffer) { LOG_ERROR("odd number of bytes to write and no memory " "for padding buffer"); return ERROR_FAIL; @@ -834,53 +824,32 @@ static int sim3x_auto_probe(struct flash_bank *bank) } } -static int sim3x_flash_info(struct flash_bank *bank, char *buf, int buf_size) +static int sim3x_flash_info(struct flash_bank *bank, struct command_invocation *cmd) { - int ret; - int printed = 0; struct sim3x_info *sim3x_info; sim3x_info = bank->driver_priv; /* Read info about chip */ - ret = sim3x_read_info(bank); + int ret = sim3x_read_info(bank); if (ret != ERROR_OK) return ret; /* Part */ if (sim3x_info->part_family && sim3x_info->part_number) { - printed = snprintf(buf, buf_size, "SiM3%c%d", sim3x_info->part_family, sim3x_info->part_number); - buf += printed; - buf_size -= printed; - - if (buf_size <= 0) - return ERROR_BUF_TOO_SMALL; + command_print_sameline(cmd, "SiM3%c%d", sim3x_info->part_family, sim3x_info->part_number); /* Revision */ if (sim3x_info->device_revision && sim3x_info->device_revision <= 'Z' - 'A') { - printed = snprintf(buf, buf_size, "-%c", sim3x_info->device_revision + 'A'); - buf += printed; - buf_size -= printed; - - if (buf_size <= 0) - return ERROR_BUF_TOO_SMALL; + command_print_sameline(cmd, "-%c", sim3x_info->device_revision + 'A'); /* Package */ - printed = snprintf(buf, buf_size, "-G%s", sim3x_info->device_package); - buf += printed; - buf_size -= printed; - - if (buf_size <= 0) - return ERROR_BUF_TOO_SMALL; + command_print_sameline(cmd, "-G%s", sim3x_info->device_package); } } /* Print flash size */ - printed = snprintf(buf, buf_size, " flash_size = %dKB", sim3x_info->flash_size_kb); - buf_size -= printed; - - if (buf_size <= 0) - return ERROR_BUF_TOO_SMALL; + command_print_sameline(cmd, " flash_size = %dKB", sim3x_info->flash_size_kb); return ERROR_OK; } @@ -892,16 +861,23 @@ static int sim3x_flash_info(struct flash_bank *bank, char *buf, int buf_size) */ 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; @@ -912,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; @@ -956,7 +938,7 @@ COMMAND_HANDLER(sim3x_mass_erase) struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; - if (dap == NULL) { + if (!dap) { /* Used debug interface doesn't support direct DAP access */ LOG_ERROR("mass_erase can't be used by this debug interface"); return ERROR_FAIL; @@ -1001,9 +983,9 @@ COMMAND_HANDLER(sim3x_lock) struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; - if (dap == NULL) { + if (!dap) { /* Used debug interface doesn't support direct DAP access */ - LOG_INFO("Target can't by unlocked by this debug interface"); + LOG_INFO("Target can't be unlocked by this debug interface"); /* Core check */ ret = target_read_u32(target, CPUID, &val); @@ -1060,7 +1042,7 @@ COMMAND_HANDLER(sim3x_lock) return retval; ret = sim3x_flash_write(bank, lock_word, LOCK_WORD_ADDRESS, 4); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ret; LOG_INFO("Target is successfully locked"); @@ -1073,7 +1055,7 @@ COMMAND_HANDLER(sim3x_lock) LOG_ERROR("Unexpected lock word value"); /* SIM3X_AP_ID_VALUE is not checked */ - if (dap == NULL) + if (!dap) LOG_INFO("Maybe this isn't a SiM3x MCU"); return ERROR_FAIL; diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index 937c194e6c..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), @@ -96,6 +123,7 @@ const struct flash_device flash_devices[] = { FLASH_ID("micron n25q256 1.8v", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019bb20, 0x100, 0x10000, 0x2000000), FLASH_ID("micron mt25ql512", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0020ba20, 0x100, 0x10000, 0x4000000), 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("win w25q80bv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540ef, 0x100, 0x10000, 0x200000), @@ -112,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), @@ -119,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), @@ -130,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), @@ -140,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 11c381fbd2..807af12e78 100644 --- a/src/flash/nor/spi.h +++ b/src/flash/nor/spi.h @@ -1,5 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** - * Copyright (C) 2018 by Andreas Bolsch * + * Copyright (C) 2018-2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * * * * Copyright (C) 2012 by George Harris * @@ -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 @@ -29,7 +18,7 @@ /* data structure to maintain flash ids from different vendors */ struct flash_device { - char *name; + const char *name; uint8_t read_cmd; uint8_t qread_cmd; uint8_t pprog_cmd; @@ -87,6 +76,8 @@ extern const struct flash_device flash_devices[]; #define SPIFLASH_PAGE_PROGRAM 0x02 /* Page Program */ #define SPIFLASH_FAST_READ 0x0B /* Fast Read */ #define SPIFLASH_READ 0x03 /* Normal Read */ +#define SPIFLASH_MASS_ERASE 0xC7 /* Mass Erase */ +#define SPIFLASH_READ_SFDP 0x5A /* Read Serial Flash Discoverable Parameters */ #define SPIFLASH_DEF_PAGESIZE 256 /* default for non-page-oriented devices (FRAMs) */ diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index 55b99de3fc..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/>. * ***************************************************************************/ /*************************************************************************** @@ -30,6 +19,7 @@ #include "jtag/interface.h" #include "imp.h" #include <target/algorithm.h> +#include <target/arm_adi_v5.h> #include <target/armv7m.h> #define DID0_VER(did0) ((did0 >> 28)&0x07) @@ -126,7 +116,7 @@ static const struct { uint8_t class; uint8_t partno; const char *partname; -} StellarisParts[] = { +} stellaris_parts[] = { {0x00, 0x01, "LM3S101"}, {0x00, 0x02, "LM3S102"}, {0x01, 0xBF, "LM3S1110"}, @@ -436,7 +426,7 @@ static const struct { {0xFF, 0x00, "Unknown Part"} }; -static const char * const StellarisClassname[] = { +static const char * const stellaris_classname[] = { "Sandstorm", "Fury", "Unknown", @@ -479,9 +469,8 @@ FLASH_BANK_COMMAND_HANDLER(stellaris_flash_bank_command) return ERROR_OK; } -static int get_stellaris_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_stellaris_info(struct flash_bank *bank, struct command_invocation *cmd) { - int printed; struct stellaris_flash_bank *stellaris_info = bank->driver_priv; if (stellaris_info->did1 == 0) @@ -490,41 +479,34 @@ static int get_stellaris_info(struct flash_bank *bank, char *buf, int buf_size) /* Read main and master clock frequency register */ stellaris_read_clock_info(bank); - printed = snprintf(buf, - buf_size, - "\nTI/LMI Stellaris information: Chip is " - "class %i (%s) %s rev %c%i\n", - stellaris_info->target_class, - StellarisClassname[stellaris_info->target_class], - stellaris_info->target_name, - (int)('A' + ((stellaris_info->did0 >> 8) & 0xFF)), - (int)((stellaris_info->did0) & 0xFF)); - buf += printed; - buf_size -= printed; - - printed = snprintf(buf, - buf_size, - "did1: 0x%8.8" PRIx32 ", arch: 0x%4.4" PRIx32 - ", eproc: %s, ramsize: %" PRIu32 "k, flashsize: %" PRIu32 "k\n", - stellaris_info->did1, - stellaris_info->did1, - "ARMv7M", - stellaris_info->sramsiz, - (uint32_t)(stellaris_info->num_pages * stellaris_info->pagesize / 1024)); - buf += printed; - buf_size -= printed; - - snprintf(buf, - buf_size, - "master clock: %ikHz%s, " - "rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 ", " - "pagesize: %" PRIu32 ", pages: %" PRIu32, - (int)(stellaris_info->mck_freq / 1000), - stellaris_info->mck_desc, - stellaris_info->rcc, - stellaris_info->rcc2, - stellaris_info->pagesize, - stellaris_info->num_pages); + command_print_sameline(cmd, + "\nTI/LMI Stellaris information: Chip is " + "class %i (%s) %s rev %c%i\n", + stellaris_info->target_class, + stellaris_classname[stellaris_info->target_class], + stellaris_info->target_name, + (int)('A' + ((stellaris_info->did0 >> 8) & 0xFF)), + (int)((stellaris_info->did0) & 0xFF)); + + command_print_sameline(cmd, + "did1: 0x%8.8" PRIx32 ", arch: 0x%4.4" PRIx32 + ", eproc: %s, ramsize: %" PRIu32 "k, flashsize: %" PRIu32 "k\n", + stellaris_info->did1, + stellaris_info->did1, + "ARMv7M", + stellaris_info->sramsiz, + (uint32_t)(stellaris_info->num_pages * stellaris_info->pagesize / 1024)); + + command_print_sameline(cmd, + "master clock: %ikHz%s, " + "rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 ", " + "pagesize: %" PRIu32 ", pages: %" PRIu32, + (int)(stellaris_info->mck_freq / 1000), + stellaris_info->mck_desc, + stellaris_info->rcc, + stellaris_info->rcc2, + stellaris_info->pagesize, + stellaris_info->num_pages); return ERROR_OK; } @@ -751,13 +733,13 @@ static int stellaris_read_part_info(struct flash_bank *bank) LOG_WARNING("Unknown did0 class"); } - for (i = 0; StellarisParts[i].partno; i++) { - if ((StellarisParts[i].partno == ((did1 >> 16) & 0xFF)) && - (StellarisParts[i].class == stellaris_info->target_class)) + for (i = 0; stellaris_parts[i].partno; i++) { + if ((stellaris_parts[i].partno == ((did1 >> 16) & 0xFF)) && + (stellaris_parts[i].class == stellaris_info->target_class)) break; } - stellaris_info->target_name = StellarisParts[i].partname; + stellaris_info->target_name = stellaris_parts[i].partname; stellaris_info->did0 = did0; stellaris_info->did1 = did1; @@ -894,8 +876,6 @@ static int stellaris_erase(struct flash_bank *bank, unsigned int first, target_write_u32(target, FLASH_CRIS, 0); return ERROR_FLASH_OPERATION_FAILED; } - - bank->sectors[banknr].is_erased = 1; } return ERROR_OK; @@ -1323,16 +1303,12 @@ COMMAND_HANDLER(stellaris_handle_mass_erase_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; - if (stellaris_mass_erase(bank) == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - + if (stellaris_mass_erase(bank) == ERROR_OK) command_print(CMD, "stellaris mass erase complete"); - } else + else command_print(CMD, "stellaris mass erase failed"); return ERROR_OK; @@ -1366,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 78efc8b479..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,29 +9,18 @@ * * * 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 #include "config.h" #endif +#include <string.h> + #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> -#include <target/armv7m.h> +#include <target/cortex_m.h> /* stm32x register locations */ @@ -129,9 +120,8 @@ struct stm32x_flash_bank { }; static int stm32x_mass_erase(struct flash_bank *bank); -static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id); static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t address, uint32_t count); + uint32_t address, uint32_t hwords_count); /* flash bank stm32x <base> <size> 0 0 <target#> */ @@ -151,6 +141,9 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) 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; } @@ -182,19 +175,19 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); - return ERROR_FAIL; + return ERROR_FLASH_BUSY; } alive_sleep(1); } if (status & FLASH_WRPRTERR) { LOG_ERROR("stm32x device protected"); - retval = ERROR_FAIL; + retval = ERROR_FLASH_PROTECTED; } if (status & FLASH_PGERR) { - LOG_ERROR("stm32x device programming failed"); - retval = ERROR_FAIL; + LOG_ERROR("stm32x device programming failed / flash not erased"); + retval = ERROR_FLASH_OPERATION_FAILED; } /* Clear but report errors */ @@ -215,7 +208,7 @@ static int stm32x_check_operation_supported(struct flash_bank *bank) /* if we have a dual flash bank device then * we need to perform option byte stuff on bank0 only */ if (stm32x_info->register_base != FLASH_REG_BASE_B0) { - LOG_ERROR("Option Byte Operation's must use bank0"); + LOG_ERROR("Option byte operations must use bank 0"); return ERROR_FLASH_OPERATION_FAILED; } @@ -258,36 +251,39 @@ static int stm32x_erase_options(struct flash_bank *bank) int retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* unlock option flash registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* erase option bytes */ retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_OPTWRE); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* clear read protection option byte * this will also force a device unlock if set */ stm32x_info->option_bytes.rdp = stm32x_info->default_rdp; return ERROR_OK; + +flash_lock: + target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); + return retval; } static int stm32x_write_options(struct flash_bank *bank) @@ -303,20 +299,20 @@ static int stm32x_write_options(struct flash_bank *bank) return retval; retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* unlock option flash registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* program option bytes */ retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTPG | FLASH_OPTWRE); if (retval != ERROR_OK) - return retval; + goto flash_lock; uint8_t opt_bytes[16]; @@ -329,18 +325,20 @@ static int stm32x_write_options(struct flash_bank *bank) target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff); target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff); + /* Block write is preferred in favour of operation with ancient ST-Link + * firmwares without 16-bit memory access. See + * 480: flash: stm32f1x: write option bytes using the loader + * https://review.openocd.org/c/openocd/+/480 + */ retval = stm32x_write_block(bank, opt_bytes, STM32_OB_RDP, sizeof(opt_bytes) / 2); - if (retval != ERROR_OK) { - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - LOG_ERROR("working area required to erase options bytes"); - return retval; - } - - retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); - if (retval != ERROR_OK) - return retval; - return ERROR_OK; +flash_lock: + { + int retval2 = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); + if (retval == ERROR_OK) + retval = retval2; + } + return retval; } static int stm32x_protect_check(struct flash_bank *bank) @@ -349,7 +347,7 @@ static int stm32x_protect_check(struct flash_bank *bank) uint32_t protection; int retval = stm32x_check_operation_supported(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* medium density - each bit refers to a 4 sector protection block @@ -384,33 +382,33 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; for (unsigned int i = first; i <= last; i++) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_AR), bank->base + bank->sectors[i].offset); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER | FLASH_STRT); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) - return retval; - - bank->sectors[i].is_erased = 1; + goto flash_lock; } - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; +flash_lock: + { + int retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); + if (retval == ERROR_OK) + retval = retval2; + } + return retval; } static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, @@ -444,17 +442,16 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, return stm32x_write_options(bank); } -static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t address, uint32_t count) +static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buffer, + uint32_t address, uint32_t hwords_count) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; - uint32_t buffer_size = 16384; + uint32_t buffer_size; struct working_area *write_algorithm; struct working_area *source; - struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; - int retval = ERROR_OK; + int retval; static const uint8_t stm32x_flash_write_code[] = { #include "../../../contrib/loaders/flash/stm32/stm32f1x.inc" @@ -475,19 +472,28 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, } /* memory buffer */ - while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { - buffer_size /= 2; - buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ - if (buffer_size <= 256) { - /* we already allocated the writing code, but failed to get a - * buffer, free the algorithm */ - target_free_working_area(target, write_algorithm); - - LOG_WARNING("no large enough working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + buffer_size = target_get_working_area_avail(target); + 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 + * than 256, the following allocation fails with + * ERROR_TARGET_RESOURCE_NOT_AVAILABLE and slow flashing takes place. + */ + + retval = target_alloc_working_area(target, buffer_size, &source); + /* Allocated size is always 32-bit word aligned */ + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + LOG_WARNING("no large enough working area available, can't do block memory writes"); + /* target_alloc_working_area() may return ERROR_FAIL if area backup fails: + * convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE + */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } + struct reg_param reg_params[5]; + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ @@ -495,7 +501,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ buf_set_u32(reg_params[0].value, 0, 32, stm32x_info->register_base); - buf_set_u32(reg_params[1].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, hwords_count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[4].value, 0, 32, address); @@ -503,188 +509,298 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; - retval = target_run_flash_async_algorithm(target, buffer, count, 2, + retval = target_run_flash_async_algorithm(target, buffer, hwords_count, 2, 0, NULL, - 5, reg_params, + ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { - LOG_ERROR("flash write failed at address 0x%"PRIx32, - buf_get_u32(reg_params[4].value, 0, 32)); - - if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_PGERR) { - LOG_ERROR("flash memory not erased before writing"); - /* Clear but report errors */ - target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_PGERR); - } + /* Actually we just need to check for programming errors + * stm32x_wait_status_busy also reports error and clears status bits. + * + * Target algo returns flash status in r0 only if properly finished. + * It is safer to re-read status register. + */ + int retval2 = stm32x_wait_status_busy(bank, 5); + if (retval2 != ERROR_OK) + retval = retval2; - if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_WRPRTERR) { - LOG_ERROR("flash memory write protected"); - /* Clear but report errors */ - target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_WRPRTERR); - } + LOG_ERROR("flash write failed just before address 0x%"PRIx32, + buf_get_u32(reg_params[4].value, 0, 32)); } + for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) + destroy_reg_param(®_params[i]); + target_free_working_area(target, source); target_free_working_area(target, write_algorithm); - destroy_reg_param(®_params[0]); - destroy_reg_param(®_params[1]); - destroy_reg_param(®_params[2]); - destroy_reg_param(®_params[3]); - destroy_reg_param(®_params[4]); - return retval; } -static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) +static int stm32x_write_block_riscv(struct flash_bank *bank, const uint8_t *buffer, + uint32_t address, uint32_t hwords_count) { struct target *target = bank->target; - uint8_t *new_buffer = NULL; + uint32_t buffer_size; + struct working_area *write_algorithm; + struct working_area *source; + static const uint8_t gd32vf103_flash_write_code[] = { +#include "../../../contrib/loaders/flash/gd32vf103/gd32vf103.inc" + }; - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; + /* flash write code */ + if (target_alloc_working_area(target, sizeof(gd32vf103_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; } - if (offset & 0x1) { - LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + int retval = target_write_buffer(target, write_algorithm->address, + sizeof(gd32vf103_flash_write_code), gd32vf103_flash_write_code); + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + return retval; + } + + /* memory buffer */ + buffer_size = target_get_working_area_avail(target); + buffer_size = MIN(hwords_count * 2, MAX(buffer_size, 256)); + + retval = target_alloc_working_area(target, buffer_size, &source); + /* Allocated size is always word aligned */ + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + LOG_WARNING("no large enough working area available, can't do block memory writes"); + /* target_alloc_working_area() may return ERROR_FAIL if area backup fails: + * convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE + */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - /* If there's an odd number of bytes, the data has to be padded. Duplicate - * the buffer and use the normal code path with a single block write since - * it's probably cheaper than to special case the last odd write using - * discrete accesses. */ - if (count & 1) { - new_buffer = malloc(count + 1); - if (new_buffer == NULL) { - LOG_ERROR("odd number of bytes to write and no memory for padding buffer"); - return ERROR_FAIL; + struct reg_param reg_params[4]; + + init_reg_param(®_params[0], "a0", 32, PARAM_OUT); /* poiner to FLASH_SR */ + init_reg_param(®_params[1], "a1", 32, PARAM_OUT); /* count (halfword-16bit) */ + init_reg_param(®_params[2], "a2", 32, PARAM_OUT); /* buffer start */ + init_reg_param(®_params[3], "a3", 32, PARAM_IN_OUT); /* target address */ + + while (hwords_count > 0) { + uint32_t thisrun_hwords = source->size / 2; + + /* Limit to the amount of data we actually want to write */ + if (thisrun_hwords > hwords_count) + thisrun_hwords = hwords_count; + + /* Write data to buffer */ + retval = target_write_buffer(target, source->address, + thisrun_hwords * 2, buffer); + if (retval != ERROR_OK) + break; + + buf_set_u32(reg_params[0].value, 0, 32, stm32x_get_flash_reg(bank, STM32_FLASH_SR)); + buf_set_u32(reg_params[1].value, 0, 32, thisrun_hwords); + buf_set_u32(reg_params[2].value, 0, 32, source->address); + buf_set_u32(reg_params[3].value, 0, 32, address); + + retval = target_run_algorithm(target, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + write_algorithm->address, + write_algorithm->address + sizeof(gd32vf103_flash_write_code) - 4, + 10000, NULL); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", + write_algorithm->address, retval); + break; + } + + /* Actually we just need to check for programming errors + * stm32x_wait_status_busy also reports error and clears status bits + */ + retval = stm32x_wait_status_busy(bank, 5); + if (retval != ERROR_OK) { + LOG_ERROR("flash write failed at address 0x%"PRIx32, + buf_get_u32(reg_params[3].value, 0, 32)); + break; } - LOG_INFO("odd number of bytes to write, padding with 0xff"); - buffer = memcpy(new_buffer, buffer, count); - new_buffer[count++] = 0xff; + + /* Update counters */ + buffer += thisrun_hwords * 2; + address += thisrun_hwords * 2; + hwords_count -= thisrun_hwords; } - uint32_t words_remaining = count / 2; - int retval, retval2; + for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) + destroy_reg_param(®_params[i]); - /* unlock flash registers */ - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); - if (retval != ERROR_OK) - goto cleanup; - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); - if (retval != ERROR_OK) - goto cleanup; + target_free_working_area(target, source); + target_free_working_area(target, write_algorithm); - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG); - if (retval != ERROR_OK) - goto cleanup; + return retval; +} - /* try using a block write */ - retval = stm32x_write_block(bank, buffer, bank->base + offset, words_remaining); +/** Writes a block to flash either using target algorithm + * or use fallback, host controlled halfword-by-halfword access. + * Flash controller must be unlocked before this call. + */ +static int stm32x_write_block(struct flash_bank *bank, + const uint8_t *buffer, uint32_t address, uint32_t hwords_count) +{ + struct target *target = bank->target; + + /* The flash write must be aligned to a halfword boundary. + * The flash infrastructure ensures it, do just a security check + */ + assert(address % 2 == 0); + + int retval; + struct arm *arm = target_to_arm(target); + if (is_arm(arm)) { + /* try using a block write - on ARM architecture or... */ + retval = stm32x_write_block_async(bank, buffer, address, hwords_count); + } else { + /* ... RISC-V architecture */ + retval = stm32x_write_block_riscv(bank, buffer, address, hwords_count); + } if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single halfword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); - while (words_remaining > 0) { - uint16_t value; - memcpy(&value, buffer, sizeof(uint16_t)); - - retval = target_write_u16(target, bank->base + offset, value); + while (hwords_count > 0) { + retval = target_write_memory(target, address, 2, 1, buffer); if (retval != ERROR_OK) - goto reset_pg_and_lock; + return retval; retval = stm32x_wait_status_busy(bank, 5); if (retval != ERROR_OK) - goto reset_pg_and_lock; + return retval; - words_remaining--; + hwords_count--; buffer += 2; - offset += 2; + address += 2; } } + return retval; +} + +static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* The flash write must be aligned to a halfword boundary. + * The flash infrastructure ensures it, do just a security check + */ + assert(offset % 2 == 0); + assert(count % 2 == 0); + + int retval, retval2; + + /* unlock flash registers */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); + if (retval != ERROR_OK) + goto reset_pg_and_lock; + + /* enable flash programming */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG); + if (retval != ERROR_OK) + goto reset_pg_and_lock; + + /* write to flash */ + retval = stm32x_write_block(bank, buffer, bank->base + offset, count / 2); reset_pg_and_lock: retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval == ERROR_OK) retval = retval2; -cleanup: - free(new_buffer); return retval; } -static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) -{ - /* This check the device CPUID core register to detect - * the M0 from the M3 devices. */ - - struct target *target = bank->target; - uint32_t cpuid, device_id_register = 0; +struct stm32x_property_addr { + uint32_t device_id; + uint32_t flash_size; +}; - /* Get the CPUID from the ARM Core - * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/DDI0432C_cortex_m0_r0p0_trm.pdf 4.2.1 */ - int retval = target_read_u32(target, 0xE000ED00, &cpuid); - if (retval != ERROR_OK) - return retval; +static int stm32x_get_property_addr(struct target *target, struct stm32x_property_addr *addr) +{ + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } - if (((cpuid >> 4) & 0xFFF) == 0xC20) { - /* 0xC20 is M0 devices */ - device_id_register = 0x40015800; - } else if (((cpuid >> 4) & 0xFFF) == 0xC23) { - /* 0xC23 is M3 devices */ - device_id_register = 0xE0042000; - } else if (((cpuid >> 4) & 0xFFF) == 0xC24) { - /* 0xC24 is M4 devices */ - device_id_register = 0xE0042000; - } else { + 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; + case CORTEX_M3_PARTNO: /* STM32F1x devices */ + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; + case CORTEX_M4_PARTNO: /* STM32F3x devices */ + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7CC; + return ERROR_OK; + case CORTEX_M23_PARTNO: /* GD32E23x devices */ + addr->device_id = 0x40015800; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; + case CORTEX_M_PARTNO_INVALID: + /* Check for GD32VF103 with RISC-V CPU */ + if (strcmp(target_type_name(target), "riscv") == 0 + && target_address_bits(target) == 32) { + /* There is nothing like arm common_magic in riscv_info_t + * check text name of target and if target is 32-bit + */ + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; + } + /* fallthrough */ + default: LOG_ERROR("Cannot identify target as a stm32x"); return ERROR_FAIL; } +} - /* read stm32 device id register */ - retval = target_read_u32(target, device_id_register, device_id); +static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) +{ + struct target *target = bank->target; + struct stm32x_property_addr addr; + + int retval = stm32x_get_property_addr(target, &addr); if (retval != ERROR_OK) return retval; - return retval; + return target_read_u32(target, addr.device_id, device_id); } static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) { struct target *target = bank->target; - uint32_t cpuid, flash_size_reg; - - int retval = target_read_u32(target, 0xE000ED00, &cpuid); - if (retval != ERROR_OK) - return retval; - - if (((cpuid >> 4) & 0xFFF) == 0xC20) { - /* 0xC20 is M0 devices */ - flash_size_reg = 0x1FFFF7CC; - } else if (((cpuid >> 4) & 0xFFF) == 0xC23) { - /* 0xC23 is M3 devices */ - flash_size_reg = 0x1FFFF7E0; - } else if (((cpuid >> 4) & 0xFFF) == 0xC24) { - /* 0xC24 is M4 devices */ - flash_size_reg = 0x1FFFF7CC; - } else { - LOG_ERROR("Cannot identify target as a stm32x"); - return ERROR_FAIL; - } + struct stm32x_property_addr addr; - retval = target_read_u16(target, flash_size_reg, flash_size_in_kb); + int retval = stm32x_get_property_addr(target, &addr); if (retval != ERROR_OK) return retval; - return retval; + return target_read_u16(target, addr.flash_size, flash_size_in_kb); } static int stm32x_probe(struct flash_bank *bank) @@ -692,7 +808,7 @@ static int stm32x_probe(struct flash_bank *bank) struct stm32x_flash_bank *stm32x_info = bank->driver_priv; uint16_t flash_size_in_kb; uint16_t max_flash_size_in_kb; - uint32_t device_id; + uint32_t dbgmcu_idcode; int page_size; uint32_t base_address = 0x08000000; @@ -705,14 +821,17 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->default_rdp = 0xA5; /* read stm32 device id register */ - int retval = stm32x_get_device_id(bank, &device_id); + int retval = stm32x_get_device_id(bank, &dbgmcu_idcode); if (retval != ERROR_OK) return retval; - LOG_INFO("device id = 0x%08" PRIx32 "", device_id); + LOG_INFO("device id = 0x%08" PRIx32 "", dbgmcu_idcode); + + uint16_t device_id = dbgmcu_idcode & 0xfff; + uint16_t rev_id = dbgmcu_idcode >> 16; /* set page size, protection granularity and max flash size depending on family */ - switch (device_id & 0xfff) { + switch (device_id) { case 0x440: /* stm32f05x */ page_size = 1024; stm32x_info->ppage_size = 4; @@ -754,6 +873,35 @@ static int stm32x_probe(struct flash_bank *bank) page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 128; + /* GigaDevice GD32F1x0 & GD32F3x0 & GD32E23x series devices + share DEV_ID with STM32F101/2/3 medium-density line, + however they use a REV_ID different from any STM32 device. + The main difference is another offset of user option bits + (like WDG_SW, nRST_STOP, nRST_STDBY) in option byte register + (FLASH_OBR/FMC_OBSTAT 0x4002201C). + This caused problems e.g. during flash block programming + because of unexpected active hardware watchog. */ + switch (rev_id) { + case 0x1303: /* gd32f1x0 */ + stm32x_info->user_data_offset = 16; + stm32x_info->option_offset = 6; + max_flash_size_in_kb = 64; + stm32x_info->can_load_options = true; + break; + case 0x1704: /* gd32f3x0 */ + stm32x_info->user_data_offset = 16; + stm32x_info->option_offset = 6; + stm32x_info->can_load_options = true; + break; + case 0x1906: /* gd32vf103 */ + break; + case 0x1909: /* gd32e23x */ + stm32x_info->user_data_offset = 16; + stm32x_info->option_offset = 6; + max_flash_size_in_kb = 64; + stm32x_info->can_load_options = true; + break; + } break; case 0x412: /* stm32f1x low-density */ page_size = 1024; @@ -859,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); @@ -932,11 +1080,11 @@ static const char *get_stm32f0_revision(uint16_t rev_id) return rev_str; } -static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_stm32x_info(struct flash_bank *bank, struct command_invocation *cmd) { uint32_t dbgmcu_idcode; - /* read stm32 device id register */ + /* read stm32 device id register */ int retval = stm32x_get_device_id(bank, &dbgmcu_idcode); if (retval != ERROR_OK) return retval; @@ -955,6 +1103,22 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) rev_str = "A"; break; + case 0x1303: /* gd32f1x0 */ + device_str = "GD32F1x0"; + break; + + case 0x1704: /* gd32f3x0 */ + device_str = "GD32F3x0"; + break; + + case 0x1906: + device_str = "GD32VF103"; + break; + + case 0x1909: /* gd32e23x */ + device_str = "GD32E23x"; + break; + case 0x2000: rev_str = "B"; break; @@ -1144,14 +1308,14 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) break; default: - snprintf(buf, buf_size, "Cannot identify target as a STM32F0/1/3\n"); + command_print_sameline(cmd, "Cannot identify target as a STM32F0/1/3\n"); return ERROR_FAIL; } - if (rev_str != NULL) - snprintf(buf, buf_size, "%s - Rev: %s", device_str, rev_str); + if (rev_str) + command_print_sameline(cmd, "%s - Rev: %s", device_str, rev_str); else - snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)", device_str, rev_id); + command_print_sameline(cmd, "%s - Rev: unknown (0x%04x)", device_str, rev_id); return ERROR_OK; } @@ -1166,7 +1330,7 @@ COMMAND_HANDLER(stm32x_handle_lock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; @@ -1179,7 +1343,7 @@ COMMAND_HANDLER(stm32x_handle_lock_command) } retval = stm32x_check_operation_supported(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (stm32x_erase_options(bank) != ERROR_OK) { @@ -1209,7 +1373,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; target = bank->target; @@ -1220,7 +1384,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) } retval = stm32x_check_operation_supported(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (stm32x_erase_options(bank) != ERROR_OK) { @@ -1251,7 +1415,7 @@ COMMAND_HANDLER(stm32x_handle_options_read_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; @@ -1264,7 +1428,7 @@ COMMAND_HANDLER(stm32x_handle_options_read_command) } retval = stm32x_check_operation_supported(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = target_read_u32(target, STM32_FLASH_OBR_B0, &optionbyte); @@ -1318,7 +1482,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; @@ -1331,11 +1495,11 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) } retval = stm32x_check_operation_supported(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32x_read_options(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* start with current options */ @@ -1407,7 +1571,7 @@ COMMAND_HANDLER(stm32x_handle_options_load_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; struct stm32x_flash_bank *stm32x_info = bank->driver_priv; @@ -1426,7 +1590,7 @@ COMMAND_HANDLER(stm32x_handle_options_load_command) } retval = stm32x_check_operation_supported(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* unlock option flash registers */ @@ -1434,8 +1598,10 @@ COMMAND_HANDLER(stm32x_handle_options_load_command) if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + (void)target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); return retval; + } /* force re-load of option bytes - generates software reset */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBL_LAUNCH); @@ -1460,26 +1626,26 @@ static int stm32x_mass_erase(struct flash_bank *bank) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* mass erase flash memory */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER | FLASH_STRT); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; +flash_lock: + { + int retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); + if (retval == ERROR_OK) + retval = retval2; + } + return retval; } COMMAND_HANDLER(stm32x_handle_mass_erase_command) @@ -1489,23 +1655,19 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32x_mass_erase(bank); - if (retval == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - + if (retval == ERROR_OK) command_print(CMD, "stm32x mass erase complete"); - } else + else command_print(CMD, "stm32x mass erase failed"); return retval; } -static const struct command_registration stm32x_exec_command_handlers[] = { +static const struct command_registration stm32f1x_exec_command_handlers[] = { { .name = "lock", .handler = stm32x_handle_lock_command, @@ -1553,20 +1715,20 @@ static const struct command_registration stm32x_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const struct command_registration stm32x_command_handlers[] = { +static const struct command_registration stm32f1x_command_handlers[] = { { .name = "stm32f1x", .mode = COMMAND_ANY, .help = "stm32f1x flash command group", .usage = "", - .chain = stm32x_exec_command_handlers, + .chain = stm32f1x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver stm32f1x_flash = { .name = "stm32f1x", - .commands = stm32x_command_handlers, + .commands = stm32f1x_command_handlers, .flash_bank_command = stm32x_flash_bank_command, .erase = stm32x_erase, .protect = stm32x_protect, diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index e3625f3226..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 @@ -29,7 +18,7 @@ #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> -#include <target/armv7m.h> +#include <target/cortex_m.h> /* Regarding performance: * @@ -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; @@ -636,8 +625,8 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, for (unsigned int i = first; i <= last; i++) { unsigned int snb; - if (stm32x_info->has_large_mem && i >= 12) - snb = (i - 12) | 0x10; + if (stm32x_info->has_large_mem && i >= (bank->num_sectors / 2)) + snb = (i - (bank->num_sectors / 2)) | 0x10; else snb = i; @@ -649,8 +638,6 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; - - bank->sectors[i].is_erased = 1; } retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); @@ -672,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); } @@ -858,15 +847,12 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, Wait for the BSY bit to be cleared */ while (words_remaining > 0) { - uint16_t value; - memcpy(&value, buffer + bytes_written, sizeof(uint16_t)); - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG | FLASH_PSIZE_16); if (retval != ERROR_OK) return retval; - retval = target_write_u16(target, address, value); + retval = target_write_memory(target, address, 2, 1, buffer + bytes_written); if (retval != ERROR_OK) return retval; @@ -968,25 +954,17 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) * Only effects Rev A silicon */ struct target *target = bank->target; - uint32_t cpuid; /* read stm32 device id register */ int retval = target_read_u32(target, 0xE0042000, device_id); if (retval != ERROR_OK) return retval; - if ((*device_id & 0xfff) == 0x411) { - /* read CPUID reg to check core type */ - retval = target_read_u32(target, 0xE000ED00, &cpuid); - if (retval != ERROR_OK) - return retval; - - /* check for cortex_m4 */ - if (((cpuid >> 4) & 0xFFF) == 0xC24) { - *device_id &= ~((0xFFFF << 16) | 0xfff); - *device_id |= (0x1000 << 16) | 0x413; - LOG_INFO("stm32f4x errata detected - fixing incorrect MCU_IDCODE"); - } + if ((*device_id & 0xfff) == 0x411 + && 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"); } return retval; } @@ -1021,6 +999,11 @@ static int stm32x_probe(struct flash_bank *bank) bank->num_prot_blocks = 0; bank->prot_blocks = NULL; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + /* if explicitly called out as OTP bank, short circuit probe */ if (stm32x_is_otp(bank)) { if (stm32x_otp_is_f7(bank)) { @@ -1144,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); @@ -1251,7 +1234,7 @@ static int stm32x_auto_probe(struct flash_bank *bank) return stm32x_probe(bank); } -static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_stm32x_info(struct flash_bank *bank, struct command_invocation *cmd) { uint32_t dbgmcu_idcode; @@ -1416,14 +1399,14 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) break; default: - snprintf(buf, buf_size, "Cannot identify target as a STM32F2/4/7\n"); + command_print_sameline(cmd, "Cannot identify target as a STM32F2/4/7\n"); return ERROR_FAIL; } - if (rev_str != NULL) - snprintf(buf, buf_size, "%s - Rev: %s", device_str, rev_str); + if (rev_str) + command_print_sameline(cmd, "%s - Rev: %s", device_str, rev_str); else - snprintf(buf, buf_size, "%s - Rev: unknown (0x%04" PRIx16 ")", device_str, rev_id); + command_print_sameline(cmd, "%s - Rev: unknown (0x%04" PRIx16 ")", device_str, rev_id); return ERROR_OK; } @@ -1438,7 +1421,7 @@ COMMAND_HANDLER(stm32x_handle_lock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; @@ -1477,7 +1460,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; @@ -1557,22 +1540,16 @@ 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); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32x_mass_erase(bank); if (retval == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - command_print(CMD, "stm32x mass erase complete"); } else { command_print(CMD, "stm32x mass erase failed"); @@ -1587,17 +1564,15 @@ 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 (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32x_read_options(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; @@ -1633,34 +1608,27 @@ 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 (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32x_read_options(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; 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); @@ -1695,13 +1663,11 @@ 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 (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; stm32x_info = bank->driver_priv; @@ -1715,7 +1681,7 @@ COMMAND_HANDLER(stm32f2x_handle_optcr2_write_command) " finally unlock it. Clears PCROP and mass erases flash."); retval = stm32x_read_options(bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], optcr2_pcrop); @@ -1732,14 +1698,12 @@ 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); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (stm32x_is_otp(bank)) { if (strcmp(CMD_ARGV[1], "enable") == 0) { @@ -1761,7 +1725,7 @@ COMMAND_HANDLER(stm32x_handle_otp_command) return retval; } -static const struct command_registration stm32x_exec_command_handlers[] = { +static const struct command_registration stm32f2x_exec_command_handlers[] = { { .name = "lock", .handler = stm32x_handle_lock_command, @@ -1808,26 +1772,26 @@ static const struct command_registration stm32x_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 }; -static const struct command_registration stm32x_command_handlers[] = { +static const struct command_registration stm32f2x_command_handlers[] = { { .name = "stm32f2x", .mode = COMMAND_ANY, .help = "stm32f2x flash command group", .usage = "", - .chain = stm32x_exec_command_handlers, + .chain = stm32f2x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver stm32f2x_flash = { .name = "stm32f2x", - .commands = stm32x_command_handlers, + .commands = stm32f2x_command_handlers, .flash_bank_command = stm32x_flash_bank_command, .erase = stm32x_erase, .protect = stm32x_protect, diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index ac7d759481..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" @@ -21,7 +10,7 @@ #include "imp.h" #include <helper/binarybuffer.h> #include <target/algorithm.h> -#include <target/armv7m.h> +#include <target/cortex_m.h> /* Erase time can be as high as 1000ms, 10x this and it's toast... */ @@ -100,6 +89,11 @@ #define FLASH_REG_BASE_B0 0x52002000 #define FLASH_REG_BASE_B1 0x52002100 +/* Supported device IDs */ +#define DEVID_STM32H74_H75XX 0x450 +#define DEVID_STM32H7A_H7BXX 0x480 +#define DEVID_STM32H72_H73XX 0x483 + struct stm32h7x_rev { uint16_t rev; const char *str; @@ -139,20 +133,24 @@ enum stm32h7x_opt_rdp { OPT_RDP_L2 = 0xcc }; -static const struct stm32h7x_rev stm32_450_revs[] = { +static const struct stm32h7x_rev stm32h74_h75xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, { 0x2003, "V" }, }; -static const struct stm32h7x_rev stm32_480_revs[] = { +static const struct stm32h7x_rev stm32h7a_h7bxx_revs[] = { { 0x1000, "A"}, }; -static uint32_t stm32x_compute_flash_cr_450(uint32_t cmd, int snb) +static const struct stm32h7x_rev stm32h72_h73xx_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, +}; + +static uint32_t stm32h74_h75xx_compute_flash_cr(uint32_t cmd, int snb) { return cmd | (snb << 8); } -static uint32_t stm32x_compute_flash_cr_480(uint32_t cmd, int snb) +static uint32_t stm32h7a_h7bxx_compute_flash_cr(uint32_t cmd, int snb) { /* save FW and START bits, to be right shifted by 2 bits later */ const uint32_t tmp = cmd & (FLASH_FW | FLASH_START); @@ -165,9 +163,9 @@ static uint32_t stm32x_compute_flash_cr_480(uint32_t cmd, int snb) static const struct stm32h7x_part_info stm32h7x_parts[] = { { - .id = 0x450, - .revs = stm32_450_revs, - .num_revs = ARRAY_SIZE(stm32_450_revs), + .id = DEVID_STM32H74_H75XX, + .revs = stm32h74_h75xx_revs, + .num_revs = ARRAY_SIZE(stm32h74_h75xx_revs), .device_str = "STM32H74x/75x", .page_size_kb = 128, .block_size = 32, @@ -177,12 +175,12 @@ static const struct stm32h7x_part_info stm32h7x_parts[] = { .fsize_addr = 0x1FF1E880, .wps_group_size = 1, .wps_mask = 0xFF, - .compute_flash_cr = stm32x_compute_flash_cr_450, + .compute_flash_cr = stm32h74_h75xx_compute_flash_cr, }, { - .id = 0x480, - .revs = stm32_480_revs, - .num_revs = ARRAY_SIZE(stm32_480_revs), + .id = DEVID_STM32H7A_H7BXX, + .revs = stm32h7a_h7bxx_revs, + .num_revs = ARRAY_SIZE(stm32h7a_h7bxx_revs), .device_str = "STM32H7Ax/7Bx", .page_size_kb = 8, .block_size = 16, @@ -192,7 +190,22 @@ static const struct stm32h7x_part_info stm32h7x_parts[] = { .fsize_addr = 0x08FFF80C, .wps_group_size = 4, .wps_mask = 0xFFFFFFFF, - .compute_flash_cr = stm32x_compute_flash_cr_480, + .compute_flash_cr = stm32h7a_h7bxx_compute_flash_cr, + }, + { + .id = DEVID_STM32H72_H73XX, + .revs = stm32h72_h73xx_revs, + .num_revs = ARRAY_SIZE(stm32h72_h73xx_revs), + .device_str = "STM32H72x/73x", + .page_size_kb = 128, + .block_size = 32, + .max_flash_size_kb = 1024, + .max_bank_size_kb = 1024, + .has_dual_bank = false, + .fsize_addr = 0x1FF1E880, + .wps_group_size = 1, + .wps_mask = 0xFF, + .compute_flash_cr = stm32h74_h75xx_compute_flash_cr, }, }; @@ -493,7 +506,6 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, LOG_ERROR("erase time-out or operation error sector %u", i); goto flash_lock; } - bank->sectors[i].is_erased = 1; } flash_lock: @@ -508,6 +520,7 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint32_t protection; if (target->state != TARGET_HALTED) { @@ -530,7 +543,7 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, } /* apply WRPSN mask */ - protection &= 0xff; + protection &= stm32x_info->part_info->wps_mask; LOG_DEBUG("stm32x_protect, option_bytes written WPSN 0x%" PRIx32, protection); @@ -743,6 +756,11 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->probed = false; stm32x_info->part_info = NULL; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + int retval = stm32x_read_id_code(bank, &stm32x_info->idcode); if (retval != ERROR_OK) return retval; @@ -774,15 +792,20 @@ static int stm32x_probe(struct flash_bank *bank) LOG_DEBUG("flash_regs_base: 0x%" PRIx32, stm32x_info->flash_regs_base); /* get flash size from target */ - retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &flash_size_in_kb); + /* STM32H74x/H75x, the second core (Cortex-M4) cannot read the flash size */ + retval = ERROR_FAIL; + if (device_id == DEVID_STM32H74_H75XX + && 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); + if (retval != ERROR_OK) { /* read error when device has invalid value, set max flash size */ flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb; + LOG_INFO("assuming %" PRIu16 "k flash", flash_size_in_kb); } else - LOG_INFO("flash size probed value %" PRIu16, flash_size_in_kb); - - - + LOG_INFO("flash size probed value %" PRIu16 "k", flash_size_in_kb); /* setup bank size */ const uint32_t bank1_base = FLASH_BANK0_ADDRESS; @@ -790,8 +813,8 @@ static int stm32x_probe(struct flash_bank *bank) bool has_dual_bank = stm32x_info->part_info->has_dual_bank; switch (device_id) { - case 0x450: - case 0x480: + case DEVID_STM32H74_H75XX: + case DEVID_STM32H7A_H7BXX: /* For STM32H74x/75x and STM32H7Ax/Bx * - STM32H7xxxI devices contains dual bank, 1 Mbyte each * - STM32H7xxxG devices contains dual bank, 512 Kbyte each @@ -804,6 +827,8 @@ static int stm32x_probe(struct flash_bank *bank) /* flash size is 2M or 1M */ flash_size_in_kb /= 2; break; + case DEVID_STM32H72_H73XX: + break; default: LOG_ERROR("unsupported device"); return ERROR_FAIL; @@ -858,7 +883,7 @@ static int stm32x_probe(struct flash_bank *bank) bank->sectors = alloc_block_array(0, stm32x_info->part_info->page_size_kb * 1024, bank->num_sectors); - if (bank->sectors == NULL) { + if (!bank->sectors) { LOG_ERROR("failed to allocate bank sectors"); return ERROR_FAIL; } @@ -875,7 +900,7 @@ static int stm32x_probe(struct flash_bank *bank) bank->prot_blocks = alloc_block_array(0, stm32x_info->part_info->page_size_kb * wpsn * 1024, bank->num_prot_blocks); - if (bank->prot_blocks == NULL) { + if (!bank->prot_blocks) { LOG_ERROR("failed to allocate bank prot_block"); return ERROR_FAIL; } @@ -895,7 +920,7 @@ static int stm32x_auto_probe(struct flash_bank *bank) } /* This method must return a string displaying information about the bank */ -static int stm32x_get_info(struct flash_bank *bank, char *buf, int buf_size) +static int stm32x_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; const struct stm32h7x_part_info *info = stm32x_info->part_info; @@ -903,7 +928,7 @@ static int stm32x_get_info(struct flash_bank *bank, char *buf, int buf_size) if (!stm32x_info->probed) { int retval = stm32x_probe(bank); if (retval != ERROR_OK) { - snprintf(buf, buf_size, "Unable to find bank information."); + command_print_sameline(cmd, "Unable to find bank information."); return retval; } } @@ -916,17 +941,17 @@ static int stm32x_get_info(struct flash_bank *bank, char *buf, int buf_size) if (rev_id == info->revs[i].rev) rev_str = info->revs[i].str; - if (rev_str != NULL) { - snprintf(buf, buf_size, "%s - Rev: %s", + if (rev_str) { + command_print_sameline(cmd, "%s - Rev: %s", stm32x_info->part_info->device_str, rev_str); } else { - snprintf(buf, buf_size, + command_print_sameline(cmd, "%s - Rev: unknown (0x%04" PRIx16 ")", stm32x_info->part_info->device_str, rev_id); } } else { - snprintf(buf, buf_size, "Cannot identify target as a STM32H7x"); - return ERROR_FAIL; + command_print_sameline(cmd, "Cannot identify target as a STM32H7x"); + return ERROR_FAIL; } return ERROR_OK; } @@ -982,7 +1007,7 @@ COMMAND_HANDLER(stm32x_handle_lock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32x_set_rdp(bank, OPT_RDP_L1); @@ -1002,7 +1027,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32x_set_rdp(bank, OPT_RDP_L0); @@ -1055,47 +1080,38 @@ flash_lock: 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); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32x_mass_erase(bank); - if (retval == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - + if (retval == ERROR_OK) command_print(CMD, "stm32h7x mass erase complete"); - } else { + else command_print(CMD, "stm32h7x mass erase failed"); - } return retval; } 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); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; uint32_t reg_offset, value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); retval = stm32x_read_flash_reg(bank, reg_offset, &value); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32, @@ -1106,14 +1122,12 @@ 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); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; uint32_t reg_offset, value, mask = 0xffffffff; @@ -1126,7 +1140,7 @@ COMMAND_HANDLER(stm32x_handle_option_write_command) return stm32x_modify_option(bank, reg_offset, value, mask); } -static const struct command_registration stm32x_exec_command_handlers[] = { +static const struct command_registration stm32h7x_exec_command_handlers[] = { { .name = "lock", .handler = stm32x_handle_lock_command, @@ -1165,20 +1179,20 @@ static const struct command_registration stm32x_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const struct command_registration stm32x_command_handlers[] = { +static const struct command_registration stm32h7x_command_handlers[] = { { .name = "stm32h7x", .mode = COMMAND_ANY, .help = "stm32h7x flash command group", .usage = "", - .chain = stm32x_exec_command_handlers, + .chain = stm32h7x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver stm32h7x_flash = { .name = "stm32h7x", - .commands = stm32x_command_handlers, + .commands = stm32h7x_command_handlers, .flash_bank_command = stm32x_flash_bank_command, .erase = stm32x_erase, .protect = stm32x_protect, diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 379f1b4b38..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 @@ -24,10 +13,12 @@ #endif #include "imp.h" +#include <helper/align.h> #include <helper/binarybuffer.h> +#include <helper/bits.h> #include <target/algorithm.h> -#include <target/armv7m.h> -#include "bits.h" +#include <target/arm_adi_v5.h> +#include <target/cortex_m.h> #include "stm32l4x.h" /* STM32L4xxx series for reference. @@ -63,26 +54,42 @@ * - for STM32L4P5/Q5x * In 1M FLASH devices bit 22 (DBANK) controls Dual Bank mode. * In 512K FLASH devices bit 21 (DB512K) controls Dual Bank mode. - * */ /* STM32WBxxx series for reference. * - * RM0434 (STM32WB55) + * 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 * - * RM0471 (STM32WB50) + * RM0471 (STM32WB50/WB30x) * http://www.st.com/resource/en/reference_manual/dm00622834.pdf + * + * RM0473 (STM32WB15x) + * http://www.st.com/resource/en/reference_manual/dm00649196.pdf + * + * RM0478 (STM32WB10x) + * http://www.st.com/resource/en/reference_manual/dm00689203.pdf */ /* STM32WLxxx series for reference. * * RM0461 (STM32WLEx) * http://www.st.com/resource/en/reference_manual/dm00530369.pdf + * + * RM0453 (STM32WL5x) + * 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. +/* STM32G0xxx series for reference. * * RM0444 (STM32G0x1) * http://www.st.com/resource/en/reference_manual/dm00371828.pdf @@ -91,10 +98,9 @@ * http://www.st.com/resource/en/reference_manual/dm00463896.pdf */ -/* - * STM32G4xxx series for reference. +/* STM32G4xxx series for reference. * - * RM0440 (STM32G43x/44x/47x/48x) + * RM0440 (STM32G43x/44x/47x/48x/49x/4Ax) * http://www.st.com/resource/en/reference_manual/dm00355726.pdf * * Cat. 2 devices have single bank only, page size is 2kByte. @@ -104,11 +110,113 @@ * * Bank mode is controlled by bit 22 (DBANK) in option bytes register. * Both banks are treated as a single OpenOCD bank. + * + * Cat. 4 devices have single bank only, page size is 2kByte. + */ + +/* STM32L5xxx series for reference. + * + * RM0428 (STM32L552xx/STM32L562xx) + * http://www.st.com/resource/en/reference_manual/dm00346336.pdf */ /* Erase time can be as high as 25ms, 10x this and assume it's toast... */ #define FLASH_ERASE_TIMEOUT 250 +#define FLASH_WRITE_TIMEOUT 50 + + +/* relevant STM32L4 flags ****************************************************/ +#define F_NONE 0 +/* this flag indicates if the device flash is with dual bank architecture */ +#define F_HAS_DUAL_BANK BIT(0) +/* this flags is used for dual bank devices only, it indicates if the + * 4 WRPxx are usable if the device is configured in single-bank mode */ +#define F_USE_ALL_WRPXX BIT(1) +/* this flag indicates if the device embeds a TrustZone security feature */ +#define F_HAS_TZ BIT(2) +/* this flag indicates if the device has the same flash registers as STM32L5 */ +#define F_HAS_L5_FLASH_REGS BIT(3) +/* this flag indicates that programming should be done in quad-word + * the default programming word size is double-word */ +#define F_QUAD_WORD_PROG BIT(4) +/* end of STM32L4 flags ******************************************************/ + + +enum stm32l4_flash_reg_index { + STM32_FLASH_ACR_INDEX, + STM32_FLASH_KEYR_INDEX, + STM32_FLASH_OPTKEYR_INDEX, + STM32_FLASH_SR_INDEX, + STM32_FLASH_CR_INDEX, + /* for some devices like STM32WL5x, the CPU2 have a dedicated C2CR register w/o LOCKs, + * so it uses the C2CR for flash operations and CR for checking locks and locking */ + STM32_FLASH_CR_WLK_INDEX, /* FLASH_CR_WITH_LOCK */ + STM32_FLASH_OPTR_INDEX, + STM32_FLASH_WRP1AR_INDEX, + STM32_FLASH_WRP1BR_INDEX, + STM32_FLASH_WRP2AR_INDEX, + STM32_FLASH_WRP2BR_INDEX, + STM32_FLASH_REG_INDEX_NUM, +}; + +enum stm32l4_rdp { + RDP_LEVEL_0 = 0xAA, + RDP_LEVEL_0_5 = 0x55, /* for devices with TrustZone enabled */ + RDP_LEVEL_1 = 0x00, + RDP_LEVEL_2 = 0xCC +}; + +static const uint32_t stm32l4_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { + [STM32_FLASH_ACR_INDEX] = 0x000, + [STM32_FLASH_KEYR_INDEX] = 0x008, + [STM32_FLASH_OPTKEYR_INDEX] = 0x00C, + [STM32_FLASH_SR_INDEX] = 0x010, + [STM32_FLASH_CR_INDEX] = 0x014, + [STM32_FLASH_OPTR_INDEX] = 0x020, + [STM32_FLASH_WRP1AR_INDEX] = 0x02C, + [STM32_FLASH_WRP1BR_INDEX] = 0x030, + [STM32_FLASH_WRP2AR_INDEX] = 0x04C, + [STM32_FLASH_WRP2BR_INDEX] = 0x050, +}; + +static const uint32_t stm32wl_cpu2_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { + [STM32_FLASH_ACR_INDEX] = 0x000, + [STM32_FLASH_KEYR_INDEX] = 0x008, + [STM32_FLASH_OPTKEYR_INDEX] = 0x010, + [STM32_FLASH_SR_INDEX] = 0x060, + [STM32_FLASH_CR_INDEX] = 0x064, + [STM32_FLASH_CR_WLK_INDEX] = 0x014, + [STM32_FLASH_OPTR_INDEX] = 0x020, + [STM32_FLASH_WRP1AR_INDEX] = 0x02C, + [STM32_FLASH_WRP1BR_INDEX] = 0x030, +}; + +static const uint32_t stm32l5_ns_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { + [STM32_FLASH_ACR_INDEX] = 0x000, + [STM32_FLASH_KEYR_INDEX] = 0x008, /* NSKEYR */ + [STM32_FLASH_OPTKEYR_INDEX] = 0x010, + [STM32_FLASH_SR_INDEX] = 0x020, /* NSSR */ + [STM32_FLASH_CR_INDEX] = 0x028, /* NSCR */ + [STM32_FLASH_OPTR_INDEX] = 0x040, + [STM32_FLASH_WRP1AR_INDEX] = 0x058, + [STM32_FLASH_WRP1BR_INDEX] = 0x05C, + [STM32_FLASH_WRP2AR_INDEX] = 0x068, + [STM32_FLASH_WRP2BR_INDEX] = 0x06C, +}; + +static const uint32_t stm32l5_s_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { + [STM32_FLASH_ACR_INDEX] = 0x000, + [STM32_FLASH_KEYR_INDEX] = 0x00C, /* SECKEYR */ + [STM32_FLASH_OPTKEYR_INDEX] = 0x010, + [STM32_FLASH_SR_INDEX] = 0x024, /* SECSR */ + [STM32_FLASH_CR_INDEX] = 0x02C, /* SECCR */ + [STM32_FLASH_OPTR_INDEX] = 0x040, + [STM32_FLASH_WRP1AR_INDEX] = 0x058, + [STM32_FLASH_WRP1BR_INDEX] = 0x05C, + [STM32_FLASH_WRP2AR_INDEX] = 0x068, + [STM32_FLASH_WRP2BR_INDEX] = 0x06C, +}; struct stm32l4_rev { const uint16_t rev; @@ -121,9 +229,11 @@ struct stm32l4_part_info { const struct stm32l4_rev *revs; const size_t num_revs; const uint16_t max_flash_size_kb; - const bool has_dual_bank; + const uint32_t flags; /* one bit per feature, see STM32L4 flags: macros F_XXX */ const uint32_t flash_regs_base; const uint32_t fsize_addr; + const uint32_t otp_base; + const uint32_t otp_size; }; struct stm32l4_flash_bank { @@ -133,209 +243,408 @@ struct stm32l4_flash_bank { bool dual_bank_mode; int hole_sectors; uint32_t user_bank_size; + uint32_t data_width; + uint32_t cr_bker_mask; + uint32_t sr_bsy_mask; uint32_t wrpxxr_mask; const struct stm32l4_part_info *part_info; + uint32_t flash_regs_base; + const uint32_t *flash_regs; + bool otp_enabled; + enum stm32l4_rdp rdp; + bool tzen; + uint32_t optr; }; -/* human readable list of families this drivers supports */ -static const char *device_families = "STM32L4/L4+/WB/WL/G4/G0"; +enum stm32_bank_id { + STM32_BANK1, + STM32_BANK2, + STM32_ALL_BANKS +}; -static const struct stm32l4_rev stm32_415_revs[] = { +struct stm32l4_wrp { + enum stm32l4_flash_reg_index reg_idx; + uint32_t value; + bool used; + int first; + int last; + int offset; +}; + +/* human readable list of families this drivers supports (sorted alphabetically) */ +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" } }; -static const struct stm32l4_rev stm32_435_revs[] = { +static const struct stm32l4_rev stm32l43_l44xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; -static const struct stm32l4_rev stm32_460_revs[] = { + +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" }, +}; + +static const struct stm32l4_rev stm32_g07_g08xx_revs[] = { { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" }, }; -static const struct stm32l4_rev stm32_461_revs[] = { +static const struct stm32l4_rev stm32l49_l4axx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, }; -static const struct stm32l4_rev stm32_462_revs[] = { +static const struct stm32l4_rev stm32l45_l46xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; -static const struct stm32l4_rev stm32_464_revs[] = { +static const struct stm32l4_rev stm32l41_l42xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; -static const struct stm32l4_rev stm32_466_revs[] = { +static const struct stm32l4_rev stm32g03_g04xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2000, "B" }, }; -static const struct stm32l4_rev stm32_468_revs[] = { +static const struct stm32l4_rev stm32g0b_g0cxx_revs[] = { + { 0x1000, "A" }, +}; + +static const struct stm32l4_rev stm32g43_g44xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; -static const struct stm32l4_rev stm32_469_revs[] = { +static const struct stm32l4_rev stm32g47_g48xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; -static const struct stm32l4_rev stm32_470_revs[] = { +static const struct stm32l4_rev stm32l4r_l4sxx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" }, + { 0x101F, "V" }, }; -static const struct stm32l4_rev stm32_471_revs[] = { +static const struct stm32l4_rev stm32l4p_l4qxx_revs[] = { { 0x1001, "Z" }, }; -static const struct stm32l4_rev stm32_495_revs[] = { +static const struct stm32l4_rev stm32l55_l56xx_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, +}; + +static const struct stm32l4_rev stm32g49_g4axx_revs[] = { + { 0x1000, "A" }, +}; + +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[] = { + { 0x1000, "A" }, { 0x2000, "B" }, +}; + +static const struct stm32l4_rev stm32wb5xx_revs[] = { { 0x2001, "2.1" }, }; -static const struct stm32l4_rev stm32_496_revs[] = { +static const struct stm32l4_rev stm32wb3xx_revs[] = { { 0x1000, "A" }, }; -static const struct stm32l4_rev stm32_497_revs[] = { +static const struct stm32l4_rev stm32wle_wl5xx_revs[] = { { 0x1000, "1.0" }, }; static const struct stm32l4_part_info stm32l4_parts[] = { { - .id = 0x415, - .revs = stm32_415_revs, - .num_revs = ARRAY_SIZE(stm32_415_revs), + .id = DEVID_STM32L47_L48XX, + .revs = stm32l47_l48xx_revs, + .num_revs = ARRAY_SIZE(stm32l47_l48xx_revs), .device_str = "STM32L47/L48xx", .max_flash_size_kb = 1024, - .has_dual_bank = true, + .flags = F_HAS_DUAL_BANK, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { - .id = 0x435, - .revs = stm32_435_revs, - .num_revs = ARRAY_SIZE(stm32_435_revs), + .id = DEVID_STM32L43_L44XX, + .revs = stm32l43_l44xx_revs, + .num_revs = ARRAY_SIZE(stm32l43_l44xx_revs), .device_str = "STM32L43/L44xx", .max_flash_size_kb = 256, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, + .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 = 0x460, - .revs = stm32_460_revs, - .num_revs = ARRAY_SIZE(stm32_460_revs), + .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, + .num_revs = ARRAY_SIZE(stm32g05_g06xx_revs), + .device_str = "STM32G05/G06xx", + .max_flash_size_kb = 64, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, + { + .id = DEVID_STM32G07_G08XX, + .revs = stm32_g07_g08xx_revs, + .num_revs = ARRAY_SIZE(stm32_g07_g08xx_revs), .device_str = "STM32G07/G08xx", .max_flash_size_kb = 128, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { - .id = 0x461, - .revs = stm32_461_revs, - .num_revs = ARRAY_SIZE(stm32_461_revs), + .id = DEVID_STM32L49_L4AXX, + .revs = stm32l49_l4axx_revs, + .num_revs = ARRAY_SIZE(stm32l49_l4axx_revs), .device_str = "STM32L49/L4Axx", .max_flash_size_kb = 1024, - .has_dual_bank = true, + .flags = F_HAS_DUAL_BANK, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { - .id = 0x462, - .revs = stm32_462_revs, - .num_revs = ARRAY_SIZE(stm32_462_revs), + .id = DEVID_STM32L45_L46XX, + .revs = stm32l45_l46xx_revs, + .num_revs = ARRAY_SIZE(stm32l45_l46xx_revs), .device_str = "STM32L45/L46xx", .max_flash_size_kb = 512, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { - .id = 0x464, - .revs = stm32_464_revs, - .num_revs = ARRAY_SIZE(stm32_464_revs), + .id = DEVID_STM32L41_L42XX, + .revs = stm32l41_l42xx_revs, + .num_revs = ARRAY_SIZE(stm32l41_l42xx_revs), .device_str = "STM32L41/L42xx", .max_flash_size_kb = 128, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { - .id = 0x466, - .revs = stm32_466_revs, - .num_revs = ARRAY_SIZE(stm32_466_revs), - .device_str = "STM32G03/G04xx", + .id = DEVID_STM32G03_G04XX, + .revs = stm32g03_g04xx_revs, + .num_revs = ARRAY_SIZE(stm32g03_g04xx_revs), + .device_str = "STM32G03x/G04xx", .max_flash_size_kb = 64, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { - .id = 0x468, - .revs = stm32_468_revs, - .num_revs = ARRAY_SIZE(stm32_468_revs), + .id = DEVID_STM32G0B_G0CXX, + .revs = stm32g0b_g0cxx_revs, + .num_revs = ARRAY_SIZE(stm32g0b_g0cxx_revs), + .device_str = "STM32G0B/G0Cx", + .max_flash_size_kb = 512, + .flags = F_HAS_DUAL_BANK, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, + { + .id = DEVID_STM32G43_G44XX, + .revs = stm32g43_g44xx_revs, + .num_revs = ARRAY_SIZE(stm32g43_g44xx_revs), .device_str = "STM32G43/G44xx", .max_flash_size_kb = 128, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { - .id = 0x469, - .revs = stm32_469_revs, - .num_revs = ARRAY_SIZE(stm32_469_revs), + .id = DEVID_STM32G47_G48XX, + .revs = stm32g47_g48xx_revs, + .num_revs = ARRAY_SIZE(stm32g47_g48xx_revs), .device_str = "STM32G47/G48xx", .max_flash_size_kb = 512, - .has_dual_bank = true, + .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { - .id = 0x470, - .revs = stm32_470_revs, - .num_revs = ARRAY_SIZE(stm32_470_revs), + .id = DEVID_STM32L4R_L4SXX, + .revs = stm32l4r_l4sxx_revs, + .num_revs = ARRAY_SIZE(stm32l4r_l4sxx_revs), .device_str = "STM32L4R/L4Sxx", .max_flash_size_kb = 2048, - .has_dual_bank = true, + .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { - .id = 0x471, - .revs = stm32_471_revs, - .num_revs = ARRAY_SIZE(stm32_471_revs), - .device_str = "STM32L4P5/L4Q5x", + .id = DEVID_STM32L4P_L4QXX, + .revs = stm32l4p_l4qxx_revs, + .num_revs = ARRAY_SIZE(stm32l4p_l4qxx_revs), + .device_str = "STM32L4P/L4Qxx", .max_flash_size_kb = 1024, - .has_dual_bank = true, + .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, + { + .id = DEVID_STM32L55_L56XX, + .revs = stm32l55_l56xx_revs, + .num_revs = ARRAY_SIZE(stm32l55_l56xx_revs), + .device_str = "STM32L55/L56xx", + .max_flash_size_kb = 512, + .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BFA05E0, + .otp_base = 0x0BFA0000, + .otp_size = 512, }, { - .id = 0x495, - .revs = stm32_495_revs, - .num_revs = ARRAY_SIZE(stm32_495_revs), + .id = DEVID_STM32G49_G4AXX, + .revs = stm32g49_g4axx_revs, + .num_revs = ARRAY_SIZE(stm32g49_g4axx_revs), + .device_str = "STM32G49/G4Axx", + .max_flash_size_kb = 512, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, + { + .id = DEVID_STM32U57_U58XX, + .revs = stm32u57_u58xx_revs, + .num_revs = ARRAY_SIZE(stm32u57_u58xx_revs), + .device_str = "STM32U57/U58xx", + .max_flash_size_kb = 2048, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BFA07A0, + .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, + .num_revs = ARRAY_SIZE(stm32wb1xx_revs), + .device_str = "STM32WB1x", + .max_flash_size_kb = 320, + .flags = F_NONE, + .flash_regs_base = 0x58004000, + .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, + { + .id = DEVID_STM32WB5XX, + .revs = stm32wb5xx_revs, + .num_revs = ARRAY_SIZE(stm32wb5xx_revs), .device_str = "STM32WB5x", .max_flash_size_kb = 1024, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x58004000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { - .id = 0x496, - .revs = stm32_496_revs, - .num_revs = ARRAY_SIZE(stm32_496_revs), + .id = DEVID_STM32WB3XX, + .revs = stm32wb3xx_revs, + .num_revs = ARRAY_SIZE(stm32wb3xx_revs), .device_str = "STM32WB3x", .max_flash_size_kb = 512, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x58004000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, { - .id = 0x497, - .revs = stm32_497_revs, - .num_revs = ARRAY_SIZE(stm32_497_revs), - .device_str = "STM32WLEx", + .id = DEVID_STM32WLE_WL5XX, + .revs = stm32wle_wl5xx_revs, + .num_revs = ARRAY_SIZE(stm32wle_wl5xx_revs), + .device_str = "STM32WLE/WL5x", .max_flash_size_kb = 256, - .has_dual_bank = false, + .flags = F_NONE, .flash_regs_base = 0x58004000, .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, }, }; @@ -347,25 +656,150 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command) if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; - stm32l4_info = malloc(sizeof(struct stm32l4_flash_bank)); + /* fix-up bank base address: 0 is used for normal flash memory */ + if (bank->base == 0) + bank->base = STM32_FLASH_BANK_BASE; + + stm32l4_info = calloc(1, sizeof(struct stm32l4_flash_bank)); if (!stm32l4_info) return ERROR_FAIL; /* Checkme: What better error to use?*/ bank->driver_priv = stm32l4_info; - /* The flash write must be aligned to a double word (8-bytes) boundary. - * Ask the flash infrastructure to ensure required alignment */ - bank->write_start_alignment = bank->write_end_alignment = 8; - stm32l4_info->probed = false; + stm32l4_info->otp_enabled = false; stm32l4_info->user_bank_size = bank->size; return ERROR_OK; } +/* bitmap helper extension */ +struct range { + unsigned int start; + unsigned int end; +}; + +static void bitmap_to_ranges(unsigned long *bitmap, unsigned int nbits, + struct range *ranges, unsigned int *ranges_count) { + *ranges_count = 0; + bool last_bit = 0, cur_bit; + for (unsigned int i = 0; i < nbits; i++) { + cur_bit = test_bit(i, bitmap); + + if (cur_bit && !last_bit) { + (*ranges_count)++; + ranges[*ranges_count - 1].start = i; + ranges[*ranges_count - 1].end = i; + } else if (cur_bit && last_bit) { + /* update (increment) the end this range */ + ranges[*ranges_count - 1].end = i; + } + + last_bit = cur_bit; + } +} + +static inline int range_print_one(struct range *range, char *str) +{ + if (range->start == range->end) + return sprintf(str, "[%d]", range->start); + + return sprintf(str, "[%d,%d]", range->start, range->end); +} + +static char *range_print_alloc(struct range *ranges, unsigned int ranges_count) +{ + /* each range will be printed like the following: [start,end] + * start and end, both are unsigned int, an unsigned int takes 10 characters max + * plus 3 characters for '[', ',' and ']' + * thus means each range can take maximum 23 character + * after each range we add a ' ' as separator and finally we need the '\0' + * if the ranges_count is zero we reserve one char for '\0' to return an empty string */ + char *str = calloc(1, ranges_count * (24 * sizeof(char)) + 1); + char *ptr = str; + + for (unsigned int i = 0; i < ranges_count; i++) { + ptr += range_print_one(&(ranges[i]), ptr); + + if (i < ranges_count - 1) + *(ptr++) = ' '; + } + + return str; +} + +/* end of bitmap helper extension */ + +static inline bool stm32l4_is_otp(struct flash_bank *bank) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return bank->base == stm32l4_info->part_info->otp_base; +} + +static int stm32l4_otp_enable(struct flash_bank *bank, bool enable) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + + if (!stm32l4_is_otp(bank)) + return ERROR_FAIL; + + char *op_str = enable ? "enabled" : "disabled"; + + LOG_INFO("OTP memory (bank #%d) is %s%s for write commands", + bank->bank_number, + stm32l4_info->otp_enabled == enable ? "already " : "", + op_str); + + stm32l4_info->otp_enabled = enable; + + return ERROR_OK; +} + +static inline bool stm32l4_otp_is_enabled(struct flash_bank *bank) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return stm32l4_info->otp_enabled; +} + +static void stm32l4_sync_rdp_tzen(struct flash_bank *bank) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + + bool tzen = false; + + if (stm32l4_info->part_info->flags & F_HAS_TZ) + tzen = (stm32l4_info->optr & FLASH_TZEN) != 0; + + uint32_t rdp = stm32l4_info->optr & FLASH_RDP_MASK; + + /* for devices without TrustZone: + * RDP level 0 and 2 values are to 0xAA and 0xCC + * Any other value corresponds to RDP level 1 + * for devices with TrusZone: + * RDP level 0 and 2 values are 0xAA and 0xCC + * RDP level 0.5 value is 0x55 only if TZEN = 1 + * Any other value corresponds to RDP level 1, including 0x55 if TZEN = 0 + */ + + if (rdp != RDP_LEVEL_0 && rdp != RDP_LEVEL_2) { + if (!tzen || (tzen && rdp != RDP_LEVEL_0_5)) + rdp = RDP_LEVEL_1; + } + + stm32l4_info->tzen = tzen; + stm32l4_info->rdp = rdp; +} + static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; - return stm32l4_info->part_info->flash_regs_base + reg_offset; + return stm32l4_info->flash_regs_base + reg_offset; +} + +static inline uint32_t stm32l4_get_flash_reg_by_index(struct flash_bank *bank, + enum stm32l4_flash_reg_index reg_index) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return stm32l4_get_flash_reg(bank, stm32l4_info->flash_regs[reg_index]); } static inline int stm32l4_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) @@ -373,23 +807,38 @@ static inline int stm32l4_read_flash_reg(struct flash_bank *bank, uint32_t reg_o return target_read_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value); } +static inline int stm32l4_read_flash_reg_by_index(struct flash_bank *bank, + enum stm32l4_flash_reg_index reg_index, uint32_t *value) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return stm32l4_read_flash_reg(bank, stm32l4_info->flash_regs[reg_index], value); +} + static inline int stm32l4_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) { return target_write_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value); } +static inline int stm32l4_write_flash_reg_by_index(struct flash_bank *bank, + enum stm32l4_flash_reg_index reg_index, uint32_t value) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return stm32l4_write_flash_reg(bank, stm32l4_info->flash_regs[reg_index], value); +} + static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) { + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; uint32_t status; int retval = ERROR_OK; /* wait for busy to clear */ for (;;) { - retval = stm32l4_read_flash_reg(bank, STM32_FLASH_SR, &status); + retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); - if ((status & FLASH_BSY) == 0) + if ((status & stm32l4_info->sr_bsy_mask) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); @@ -398,7 +847,6 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) alive_sleep(1); } - if (status & FLASH_WRPERR) { LOG_ERROR("stm32x device protected"); retval = ERROR_FAIL; @@ -411,20 +859,71 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) /* If this operation fails, we ignore it and report the original * retval */ - stm32l4_write_flash_reg(bank, STM32_FLASH_SR, status & FLASH_ERROR); + stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, status & FLASH_ERROR); } return retval; } +/** set all FLASH_SECBB registers to the same value */ +static int stm32l4_set_secbb(struct flash_bank *bank, uint32_t value) +{ + /* This function should be used only with device with TrustZone, do just a security check */ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + assert(stm32l4_info->part_info->flags & F_HAS_TZ); + + /* based on RM0438 Rev6 for STM32L5x devices: + * to modify a page block-based security attribution, it is recommended to + * 1- check that no flash operation is ongoing on the related page + * 2- add ISB instruction after modifying the page security attribute in SECBBxRy + * this step is not need in case of JTAG direct access + */ + int retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + /* write SECBBxRy registers */ + LOG_DEBUG("setting secure block-based areas registers (SECBBxRy) to 0x%08x", value); + + const uint8_t secbb_regs[] = { + FLASH_SECBB1(1), FLASH_SECBB1(2), FLASH_SECBB1(3), FLASH_SECBB1(4), /* bank 1 SECBB register offsets */ + FLASH_SECBB2(1), FLASH_SECBB2(2), FLASH_SECBB2(3), FLASH_SECBB2(4) /* bank 2 SECBB register offsets */ + }; + + + unsigned int num_secbb_regs = ARRAY_SIZE(secbb_regs); + + /* in single bank mode, it's useless to modify FLASH_SECBB2Rx registers + * then consider only the first half of secbb_regs + */ + if (!stm32l4_info->dual_bank_mode) + num_secbb_regs /= 2; + + for (unsigned int i = 0; i < num_secbb_regs; i++) { + retval = stm32l4_write_flash_reg(bank, secbb_regs[i], value); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +static inline int stm32l4_get_flash_cr_with_lock_index(struct flash_bank *bank) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return (stm32l4_info->flash_regs[STM32_FLASH_CR_WLK_INDEX]) ? + STM32_FLASH_CR_WLK_INDEX : STM32_FLASH_CR_INDEX; +} + static int stm32l4_unlock_reg(struct flash_bank *bank) { + const uint32_t flash_cr_index = stm32l4_get_flash_cr_with_lock_index(bank); uint32_t ctrl; /* first check if not already unlocked * otherwise writing on STM32_FLASH_KEYR will fail */ - int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); + int retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl); if (retval != ERROR_OK) return retval; @@ -432,15 +931,15 @@ static int stm32l4_unlock_reg(struct flash_bank *bank) return ERROR_OK; /* unlock flash registers */ - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY1); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY1); if (retval != ERROR_OK) return retval; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY2); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY2); if (retval != ERROR_OK) return retval; - retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); + retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl); if (retval != ERROR_OK) return retval; @@ -454,9 +953,10 @@ static int stm32l4_unlock_reg(struct flash_bank *bank) static int stm32l4_unlock_option_reg(struct flash_bank *bank) { + const uint32_t flash_cr_index = stm32l4_get_flash_cr_with_lock_index(bank); uint32_t ctrl; - int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); + int retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl); if (retval != ERROR_OK) return retval; @@ -464,15 +964,15 @@ static int stm32l4_unlock_option_reg(struct flash_bank *bank) return ERROR_OK; /* unlock option registers */ - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY1); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY1); if (retval != ERROR_OK) return retval; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY2); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY2); if (retval != ERROR_OK) return retval; - retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); + retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl); if (retval != ERROR_OK) return retval; @@ -484,9 +984,47 @@ static int stm32l4_unlock_option_reg(struct flash_bank *bank) return ERROR_OK; } +static int stm32l4_perform_obl_launch(struct flash_bank *bank) +{ + int retval, retval2; + + retval = stm32l4_unlock_reg(bank); + if (retval != ERROR_OK) + goto err_lock; + + retval = stm32l4_unlock_option_reg(bank); + if (retval != ERROR_OK) + goto err_lock; + + /* Set OBL_LAUNCH bit in CR -> system reset and option bytes reload, + * but the RMs explicitly do *NOT* list this as power-on reset cause, and: + * "Note: If the read protection is set while the debugger is still + * connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset." + */ + + /* "Setting OBL_LAUNCH generates a reset so the option byte loading is performed under system reset" */ + /* Due to this reset ST-Link reports an SWD_DP_ERROR, despite the write was successful, + * then just ignore the returned value */ + stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_OBL_LAUNCH); + + /* Need to re-probe after change */ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + stm32l4_info->probed = false; + +err_lock: + retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), + FLASH_LOCK | FLASH_OPTLOCK); + + if (retval != ERROR_OK) + return retval; + + return retval2; +} + static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask) { + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; uint32_t optiondata; int retval, retval2; @@ -494,6 +1032,12 @@ static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset, if (retval != ERROR_OK) return retval; + /* for STM32L5 and similar devices, use always non-secure + * registers for option bytes programming */ + const uint32_t *saved_flash_regs = stm32l4_info->flash_regs; + if (stm32l4_info->part_info->flags & F_HAS_L5_FLASH_REGS) + stm32l4_info->flash_regs = stm32l5_ns_flash_regs; + retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) goto err_lock; @@ -508,14 +1052,16 @@ static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset, if (retval != ERROR_OK) goto err_lock; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OPTSTRT); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_OPTSTRT); if (retval != ERROR_OK) goto err_lock; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); err_lock: - retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK | FLASH_OPTLOCK); + retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), + FLASH_LOCK | FLASH_OPTLOCK); + stm32l4_info->flash_regs = saved_flash_regs; if (retval != ERROR_OK) return retval; @@ -523,53 +1069,125 @@ err_lock: return retval2; } -static int stm32l4_protect_check(struct flash_bank *bank) +static int stm32l4_get_one_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy, + enum stm32l4_flash_reg_index reg_idx, int offset) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + int ret; - uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br; - stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1AR, &wrp1ar); - stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1BR, &wrp1br); - if (stm32l4_info->part_info->has_dual_bank) { - stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2AR, &wrp2ar); - stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2BR, &wrp2br); - } else { - /* prevent uninitialized errors */ - wrp2ar = 0; - wrp2br = 0; + wrpxy->reg_idx = reg_idx; + wrpxy->offset = offset; + + ret = stm32l4_read_flash_reg_by_index(bank, wrpxy->reg_idx , &wrpxy->value); + if (ret != ERROR_OK) + return ret; + + wrpxy->first = (wrpxy->value & stm32l4_info->wrpxxr_mask) + wrpxy->offset; + wrpxy->last = ((wrpxy->value >> 16) & stm32l4_info->wrpxxr_mask) + wrpxy->offset; + wrpxy->used = wrpxy->first <= wrpxy->last; + + return ERROR_OK; +} + +static int stm32l4_get_all_wrpxy(struct flash_bank *bank, enum stm32_bank_id dev_bank_id, + struct stm32l4_wrp *wrpxy, unsigned int *n_wrp) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + int ret; + + *n_wrp = 0; + + /* for single bank devices there is 2 WRP regions. + * for dual bank devices there is 2 WRP regions per bank, + * if configured as single bank only 2 WRP are usable + * except for STM32L4R/S/P/Q, G4 cat3, L5 ... all 4 WRP are usable + * note: this should be revised, if a device will have the SWAP banks option + */ + + int wrp2y_sectors_offset = -1; /* -1 : unused */ + + /* if bank_id is BANK1 or ALL_BANKS */ + if (dev_bank_id != STM32_BANK2) { + /* get FLASH_WRP1AR */ + ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP1AR_INDEX, 0); + if (ret != ERROR_OK) + return ret; + + /* get WRP1BR */ + ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP1BR_INDEX, 0); + if (ret != ERROR_OK) + return ret; + + /* for some devices (like STM32L4R/S) in single-bank mode, the 4 WRPxx are usable */ + if ((stm32l4_info->part_info->flags & F_USE_ALL_WRPXX) && !stm32l4_info->dual_bank_mode) + wrp2y_sectors_offset = 0; } - const uint8_t wrp1a_start = wrp1ar & stm32l4_info->wrpxxr_mask; - const uint8_t wrp1a_end = (wrp1ar >> 16) & stm32l4_info->wrpxxr_mask; - const uint8_t wrp1b_start = wrp1br & stm32l4_info->wrpxxr_mask; - const uint8_t wrp1b_end = (wrp1br >> 16) & stm32l4_info->wrpxxr_mask; - const uint8_t wrp2a_start = wrp2ar & stm32l4_info->wrpxxr_mask; - const uint8_t wrp2a_end = (wrp2ar >> 16) & stm32l4_info->wrpxxr_mask; - const uint8_t wrp2b_start = wrp2br & stm32l4_info->wrpxxr_mask; - const uint8_t wrp2b_end = (wrp2br >> 16) & stm32l4_info->wrpxxr_mask; + /* if bank_id is BANK2 or ALL_BANKS */ + if (dev_bank_id != STM32_BANK1 && stm32l4_info->dual_bank_mode) + wrp2y_sectors_offset = stm32l4_info->bank1_sectors; - for (unsigned int i = 0; i < bank->num_sectors; i++) { - if (i < stm32l4_info->bank1_sectors) { - if (((i >= wrp1a_start) && - (i <= wrp1a_end)) || - ((i >= wrp1b_start) && - (i <= wrp1b_end))) - bank->sectors[i].is_protected = 1; - else - bank->sectors[i].is_protected = 0; - } else { - assert(stm32l4_info->part_info->has_dual_bank == true); - uint8_t snb; - snb = i - stm32l4_info->bank1_sectors; - if (((snb >= wrp2a_start) && - (snb <= wrp2a_end)) || - ((snb >= wrp2b_start) && - (snb <= wrp2b_end))) - bank->sectors[i].is_protected = 1; - else - bank->sectors[i].is_protected = 0; + 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) + return ret; + + /* get WRP2BR */ + ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP2BR_INDEX, wrp2y_sectors_offset); + if (ret != ERROR_OK) + return ret; + } + + return ERROR_OK; +} + +static int stm32l4_write_one_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + + int wrp_start = wrpxy->first - wrpxy->offset; + int wrp_end = wrpxy->last - wrpxy->offset; + + uint32_t wrp_value = (wrp_start & stm32l4_info->wrpxxr_mask) | ((wrp_end & stm32l4_info->wrpxxr_mask) << 16); + + return stm32l4_write_option(bank, stm32l4_info->flash_regs[wrpxy->reg_idx], wrp_value, 0xffffffff); +} + +static int stm32l4_write_all_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy, unsigned int n_wrp) +{ + int ret; + + for (unsigned int i = 0; i < n_wrp; i++) { + ret = stm32l4_write_one_wrpxy(bank, &wrpxy[i]); + if (ret != ERROR_OK) + return ret; + } + + return ERROR_OK; +} + +static int stm32l4_protect_check(struct flash_bank *bank) +{ + unsigned int n_wrp; + struct stm32l4_wrp wrpxy[4]; + + int ret = stm32l4_get_all_wrpxy(bank, STM32_ALL_BANKS, wrpxy, &n_wrp); + if (ret != ERROR_OK) + return ret; + + /* initialize all sectors as unprotected */ + for (unsigned int i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_protected = 0; + + /* now check WRPxy and mark the protected sectors */ + for (unsigned int i = 0; i < n_wrp; i++) { + if (wrpxy[i].used) { + for (int s = wrpxy[i].first; s <= wrpxy[i].last; s++) + bank->sectors[s].is_protected = 1; } } + return ERROR_OK; } @@ -581,11 +1199,26 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first, assert((first <= last) && (last < bank->num_sectors)); + if (stm32l4_is_otp(bank)) { + LOG_ERROR("cannot erase OTP memory"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } + if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { + /* set all FLASH pages as secure */ + retval = stm32l4_set_secbb(bank, FLASH_SECBB_SECURE); + if (retval != ERROR_OK) { + /* restore all FLASH pages as non-secure */ + stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); /* ignore the return value */ + return retval; + } + } + retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) goto err_lock; @@ -608,22 +1241,27 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first, if (i >= stm32l4_info->bank1_sectors) { uint8_t snb; snb = i - stm32l4_info->bank1_sectors; - erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER; + erase_flags |= snb << FLASH_PAGE_SHIFT | stm32l4_info->cr_bker_mask; } else erase_flags |= i << FLASH_PAGE_SHIFT; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, erase_flags); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, erase_flags); if (retval != ERROR_OK) break; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) break; - - bank->sectors[i].is_erased = 1; } err_lock: - retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); + retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK); + + if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { + /* restore all FLASH pages as non-secure */ + int retval3 = stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); + if (retval3 != ERROR_OK) + return retval3; + } if (retval != ERROR_OK) return retval; @@ -631,52 +1269,141 @@ err_lock: 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) +{ + unsigned int i; + + /* check if the desired protection is already configured */ + for (i = first; i <= last; i++) { + if (bank->sectors[i].is_protected != set) + break; + else if (i == last) { + LOG_INFO("The specified sectors are already %s", set ? "protected" : "unprotected"); + return ERROR_OK; + } + } + + /* all sectors from first to last (or part of them) could have different + * protection other than the requested */ + unsigned int n_wrp; + struct stm32l4_wrp wrpxy[4]; + + int ret = stm32l4_get_all_wrpxy(bank, bank_id, wrpxy, &n_wrp); + if (ret != ERROR_OK) + return ret; + + /* use bitmap and range helpers to optimize the WRP usage */ + DECLARE_BITMAP(pages, bank->num_sectors); + bitmap_zero(pages, bank->num_sectors); + + for (i = 0; i < n_wrp; i++) { + if (wrpxy[i].used) { + for (int p = wrpxy[i].first; p <= wrpxy[i].last; p++) + set_bit(p, pages); + } + } + + /* we have at most 'n_wrp' WRP areas + * add one range if the user is trying to protect a fifth range */ + struct range ranges[n_wrp + 1]; + unsigned int ranges_count = 0; + + bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count); + + /* pretty-print the currently protected ranges */ + if (ranges_count > 0) { + char *ranges_str = range_print_alloc(ranges, ranges_count); + LOG_DEBUG("current protected areas: %s", ranges_str); + free(ranges_str); + } else + LOG_DEBUG("current protected areas: none"); + + if (set) { /* flash protect */ + for (i = first; i <= last; i++) + set_bit(i, pages); + } else { /* flash unprotect */ + for (i = first; i <= last; i++) + clear_bit(i, pages); + } + + /* check the ranges_count after the user request */ + bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count); + + /* pretty-print the requested areas for protection */ + if (ranges_count > 0) { + char *ranges_str = range_print_alloc(ranges, ranges_count); + LOG_DEBUG("requested areas for protection: %s", ranges_str); + free(ranges_str); + } else + LOG_DEBUG("requested areas for protection: none"); + + if (ranges_count > n_wrp) { + LOG_ERROR("cannot set the requested protection " + "(only %u write protection areas are available)" , n_wrp); + return ERROR_FAIL; + } + + /* re-init all WRPxy as disabled (first > last)*/ + for (i = 0; i < n_wrp; i++) { + wrpxy[i].first = wrpxy[i].offset + 1; + wrpxy[i].last = wrpxy[i].offset; + } + + /* then configure WRPxy areas */ + for (i = 0; i < ranges_count; i++) { + wrpxy[i].first = ranges[i].start; + wrpxy[i].last = ranges[i].end; + } + + /* finally write WRPxy registers */ + 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; } - int ret = ERROR_OK; - /* Bank 2 */ - uint32_t reg_value = 0xFF; /* Default to bank un-protected */ - if (last >= stm32l4_info->bank1_sectors) { - if (set == 1) { - uint8_t begin = first > stm32l4_info->bank1_sectors ? first : 0x00; - reg_value = ((last & 0xFF) << 16) | begin; - } + /* refresh the sectors' protection */ + int ret = stm32l4_protect_check(bank); + if (ret != ERROR_OK) + return ret; - ret = stm32l4_write_option(bank, STM32_FLASH_WRP2AR, reg_value, 0xffffffff); - } - /* Bank 1 */ - reg_value = 0xFF; /* Default to bank un-protected */ - if (first < stm32l4_info->bank1_sectors) { - if (set == 1) { - uint8_t end = last >= stm32l4_info->bank1_sectors ? 0xFF : last; - reg_value = (end << 16) | (first & 0xFF); - } + /* 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; - ret = stm32l4_write_option(bank, STM32_FLASH_WRP1AR, reg_value, 0xffffffff); + return stm32l4_protect_same_bank(bank, STM32_BANK2, set, stm32l4_info->bank1_sectors, last); } - - return ret; } -/* Count is in double-words */ +/* 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) { struct target *target = bank->target; - uint32_t buffer_size; + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; - struct reg_param reg_params[6]; + struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -698,17 +1425,23 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } - /* memory buffer, size *must* be multiple of dword plus one dword for rp and one for wp */ - buffer_size = target_get_working_area_avail(target) & ~(2 * sizeof(uint32_t) - 1); + /* data_width should be multiple of double-word */ + assert(stm32l4_info->data_width % 8 == 0); + const size_t extra_size = sizeof(struct stm32l4_work_area); + uint32_t buffer_size = target_get_working_area_avail(target) - extra_size; + /* buffer_size should be multiple of stm32l4_info->data_width */ + buffer_size &= ~(stm32l4_info->data_width - 1); + if (buffer_size < 256) { LOG_WARNING("large enough working area not available, can't do block memory writes"); + target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (buffer_size > 16384) { /* probably won't benefit from more than 16k ... */ buffer_size = 16384; } - if (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { + if (target_alloc_working_area_try(target, buffer_size + extra_size, &source) != ERROR_OK) { LOG_ERROR("allocating working area failed"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -716,31 +1449,52 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; - init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ + /* contrib/loaders/flash/stm32/stm32l4x.c:write() arguments */ + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* stm32l4_work_area ptr , status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ - init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (double word-64bit) */ - init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash status register */ - init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* flash control register */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (of stm32l4_info->data_width) */ buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, count); - buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_SR)); - buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_CR)); - retval = target_run_flash_async_algorithm(target, buffer, count, 8, + /* write algo stack pointer */ + init_reg_param(®_params[4], "sp", 32, PARAM_OUT); + buf_set_u32(reg_params[4].value, 0, 32, source->address + + offsetof(struct stm32l4_work_area, stack) + LDR_STACK_SIZE); + + struct stm32l4_loader_params loader_extra_params; + + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_addr, + stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX)); + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_cr_addr, + stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX)); + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_word_size, + stm32l4_info->data_width); + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_bsy_mask, + stm32l4_info->sr_bsy_mask); + + retval = target_write_buffer(target, source->address, sizeof(loader_extra_params), + (uint8_t *) &loader_extra_params); + if (retval != ERROR_OK) + return retval; + + retval = target_run_flash_async_algorithm(target, buffer, count, stm32l4_info->data_width, 0, NULL, ARRAY_SIZE(reg_params), reg_params, - source->address, source->size, + source->address + offsetof(struct stm32l4_work_area, fifo), + source->size - offsetof(struct stm32l4_work_area, fifo), write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("error executing stm32l4 flash write algorithm"); - uint32_t error = buf_get_u32(reg_params[0].value, 0, 32) & FLASH_ERROR; + uint32_t error; + stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, &error); + error &= FLASH_ERROR; if (error & FLASH_WRPERR) LOG_ERROR("flash memory write protected"); @@ -748,7 +1502,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, if (error != 0) { LOG_ERROR("flash write failed = %08" PRIx32, error); /* Clear but report errors */ - stm32l4_write_flash_reg(bank, STM32_FLASH_SR, error); + stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, error); retval = ERROR_FAIL; } } @@ -761,7 +1515,51 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); - destroy_reg_param(®_params[5]); + + return retval; +} + +/* count is the size divided by stm32l4_info->data_width */ +static int stm32l4_write_block_without_loader(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + struct target *target = bank->target; + uint32_t address = bank->base + offset; + int retval = ERROR_OK; + + /* wait for BSY bit */ + retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + /* set PG in FLASH_CR */ + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_PG); + if (retval != ERROR_OK) + return retval; + + + /* write directly to flash memory */ + const uint8_t *src = buffer; + const uint32_t data_width_in_words = stm32l4_info->data_width / 4; + while (count--) { + retval = target_write_memory(target, address, 4, data_width_in_words, src); + if (retval != ERROR_OK) + return retval; + + /* wait for BSY bit */ + retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + src += stm32l4_info->data_width; + address += stm32l4_info->data_width; + } + + /* reset PG in FLASH_CR */ + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, 0); + if (retval != ERROR_OK) + return retval; return retval; } @@ -769,17 +1567,26 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; int retval = ERROR_OK, retval2; + if (stm32l4_is_otp(bank) && !stm32l4_otp_is_enabled(bank)) { + LOG_ERROR("OTP memory is disabled for write commands"); + return ERROR_FAIL; + } + if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - /* The flash write must be aligned to a double word (8-bytes) boundary. + /* ensure that stm32l4_info->data_width is 'at least' a multiple of dword */ + assert(stm32l4_info->data_width % 8 == 0); + + /* The flash write must be aligned to the 'stm32l4_info->data_width' boundary. * The flash infrastructure ensures it, do just a security check */ - assert(offset % 8 == 0); - assert(count % 8 == 0); + assert(offset % stm32l4_info->data_width == 0); + assert(count % stm32l4_info->data_width == 0); /* STM32G4xxx Cat. 3 devices may have gaps between banks, check whether * data to be written does not go into a gap: @@ -818,14 +1625,48 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) return retval; + if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { + /* set all FLASH pages as secure */ + retval = stm32l4_set_secbb(bank, FLASH_SECBB_SECURE); + if (retval != ERROR_OK) { + /* restore all FLASH pages as non-secure */ + stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); /* ignore the return value */ + return retval; + } + } + retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) goto err_lock; - retval = stm32l4_write_block(bank, buffer, offset, count / 8); + + /* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5, + * the debug is possible only in non-secure state. + * Thus means the flashloader will run in non-secure mode, + * and the workarea need to be in non-secure RAM */ + if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0_5)) + LOG_WARNING("RDP = 0x55, the work-area should be in non-secure RAM (check SAU partitioning)"); + + /* first try to write using the loader, for better performance */ + retval = stm32l4_write_block(bank, buffer, offset, + count / stm32l4_info->data_width); + + /* if resources are not available write without a loader */ + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + LOG_WARNING("falling back to programming without a flash loader (slower)"); + retval = stm32l4_write_block_without_loader(bank, buffer, offset, + count / stm32l4_info->data_width); + } err_lock: - retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); + retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK); + + if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { + /* restore all FLASH pages as non-secure */ + int retval3 = stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); + if (retval3 != ERROR_OK) + return retval3; + } if (retval != ERROR_OK) { LOG_ERROR("block write failed"); @@ -836,19 +1677,74 @@ err_lock: static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) { - int retval; - - /* try stm32l4/l4+/wb/g4 id register first, then stm32g0 id register */ - retval = target_read_u32(bank->target, DBGMCU_IDCODE_L4_G4, id); - if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) { - retval = target_read_u32(bank->target, DBGMCU_IDCODE_G0, id); - if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) { - LOG_ERROR("can't get device id"); - return (retval == ERROR_OK) ? ERROR_FAIL : retval; + int retval = ERROR_OK; + struct target *target = bank->target; + + /* try reading possible IDCODE registers, in the following order */ + uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5}; + + for (unsigned int i = 0; i < ARRAY_SIZE(dbgmcu_idcode); i++) { + retval = target_read_u32(target, dbgmcu_idcode[i], id); + if ((retval == ERROR_OK) && ((*id & 0xfff) != 0) && ((*id & 0xfff) != 0xfff)) + return ERROR_OK; + } + + /* Workaround for STM32WL5x devices: + * DBGMCU_IDCODE cannot be read using CPU1 (Cortex-M0+) at AP1, + * to solve this read the UID64 (IEEE 64-bit unique device ID register) */ + + struct armv7m_common *armv7m = target_to_armv7m_safe(target); + if (!armv7m) { + LOG_ERROR("Flash requires Cortex-M target"); + return ERROR_TARGET_INVALID; + } + + /* 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_impl_part(target) == CORTEX_M0P_PARTNO && + armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) { + uint32_t uid64_ids; + + /* UID64 is contains + * - Bits 63:32 : DEVNUM (unique device number, different for each individual device) + * - Bits 31:08 : STID (company ID) = 0x0080E1 + * - Bits 07:00 : DEVID (device ID) = 0x15 + * + * read only the fixed values {STID,DEVID} from UID64_IDS to identify the device as STM32WLx + */ + retval = target_read_u32(target, UID64_IDS, &uid64_ids); + if (retval == ERROR_OK && uid64_ids == UID64_IDS_STM32WL) { + /* force the DEV_ID to DEVID_STM32WLE_WL5XX and the REV_ID to unknown */ + *id = DEVID_STM32WLE_WL5XX; + return ERROR_OK; } } - return retval; + LOG_ERROR("can't get the device id"); + return (retval == ERROR_OK) ? ERROR_FAIL : retval; +} + +static const char *get_stm32l4_rev_str(struct flash_bank *bank) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + const struct stm32l4_part_info *part_info = stm32l4_info->part_info; + assert(part_info); + + const uint16_t rev_id = stm32l4_info->idcode >> 16; + for (unsigned int i = 0; i < part_info->num_revs; i++) { + if (rev_id == part_info->revs[i].rev) + return part_info->revs[i].str; + } + return "'unknown'"; +} + +static const char *get_stm32l4_bank_type_str(struct flash_bank *bank) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + assert(stm32l4_info->part_info); + return stm32l4_is_otp(bank) ? "OTP" : + stm32l4_info->dual_bank_mode ? "Flash dual" : + "Flash single"; } static int stm32l4_probe(struct flash_bank *bank) @@ -857,8 +1753,17 @@ static int stm32l4_probe(struct flash_bank *bank) struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; const struct stm32l4_part_info *part_info; uint16_t flash_size_kb = 0xffff; - uint32_t device_id; - uint32_t options; + + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + + struct armv7m_common *armv7m = target_to_armv7m_safe(target); + if (!armv7m) { + LOG_ERROR("Flash requires Cortex-M target"); + return ERROR_TARGET_INVALID; + } stm32l4_info->probed = false; @@ -867,11 +1772,13 @@ static int stm32l4_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - device_id = stm32l4_info->idcode & 0xFFF; + const uint32_t device_id = stm32l4_info->idcode & 0xFFF; for (unsigned int n = 0; n < ARRAY_SIZE(stm32l4_parts); n++) { - if (device_id == stm32l4_parts[n].id) + if (device_id == stm32l4_parts[n].id) { stm32l4_info->part_info = &stm32l4_parts[n]; + break; + } } if (!stm32l4_info->part_info) { @@ -880,13 +1787,76 @@ static int stm32l4_probe(struct flash_bank *bank) } part_info = stm32l4_info->part_info; + const char *rev_str = get_stm32l4_rev_str(bank); + const uint16_t rev_id = stm32l4_info->idcode >> 16; + + LOG_INFO("device idcode = 0x%08" PRIx32 " (%s - Rev %s : 0x%04x)", + stm32l4_info->idcode, part_info->device_str, rev_str, rev_id); - char device_info[1024]; - retval = bank->driver->info(bank, device_info, sizeof(device_info)); + stm32l4_info->flash_regs_base = stm32l4_info->part_info->flash_regs_base; + stm32l4_info->data_width = (part_info->flags & F_QUAD_WORD_PROG) ? 16 : 8; + stm32l4_info->cr_bker_mask = FLASH_BKER; + stm32l4_info->sr_bsy_mask = FLASH_BSY; + + /* Set flash write alignment boundaries. + * Ask the flash infrastructure to ensure required alignment */ + 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) + stm32l4_info->flash_regs = stm32l5_ns_flash_regs; + else + stm32l4_info->flash_regs = stm32l4_flash_regs; + + /* read flash option register */ + retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &stm32l4_info->optr); if (retval != ERROR_OK) return retval; - LOG_INFO("device idcode = 0x%08" PRIx32 " (%s)", stm32l4_info->idcode, device_info); + stm32l4_sync_rdp_tzen(bank); + + /* for devices with TrustZone, use flash secure registers when TZEN=1 and RDP is LEVEL_0 */ + if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { + if (part_info->flags & F_HAS_L5_FLASH_REGS) { + stm32l4_info->flash_regs_base |= STM32L5_REGS_SEC_OFFSET; + stm32l4_info->flash_regs = stm32l5_s_flash_regs; + } else { + LOG_ERROR("BUG: device supported incomplete"); + return ERROR_NOT_IMPLEMENTED; + } + } + + if (part_info->flags & F_HAS_TZ) + LOG_INFO("TZEN = %d : TrustZone %s by option bytes", + stm32l4_info->tzen, + stm32l4_info->tzen ? "enabled" : "disabled"); + + LOG_INFO("RDP level %s (0x%02X)", + stm32l4_info->rdp == RDP_LEVEL_0 ? "0" : stm32l4_info->rdp == RDP_LEVEL_0_5 ? "0.5" : "1", + stm32l4_info->rdp); + + if (stm32l4_is_otp(bank)) { + bank->size = part_info->otp_size; + + LOG_INFO("OTP size is %d bytes, base address is " TARGET_ADDR_FMT, bank->size, bank->base); + + /* OTP memory is considered as one sector */ + free(bank->sectors); + bank->num_sectors = 1; + bank->sectors = alloc_block_array(0, part_info->otp_size, 1); + + if (!bank->sectors) { + LOG_ERROR("failed to allocate bank sectors"); + return ERROR_FAIL; + } + + stm32l4_info->probed = true; + return ERROR_OK; + } else if (bank->base != STM32_FLASH_BANK_BASE && bank->base != STM32_FLASH_S_BANK_BASE) { + LOG_ERROR("invalid bank base address"); + return ERROR_FAIL; + } /* get flash size from target. */ retval = target_read_u16(target, part_info->fsize_addr, &flash_size_kb); @@ -907,15 +1877,12 @@ 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); - /* read flash option register */ - retval = stm32l4_read_flash_reg(bank, STM32_FLASH_OPTR, &options); - if (retval != ERROR_OK) - return retval; + const bool is_max_flash_size = flash_size_kb == stm32l4_info->part_info->max_flash_size_kb; stm32l4_info->bank1_sectors = 0; stm32l4_info->hole_sectors = 0; @@ -926,11 +1893,11 @@ static int stm32l4_probe(struct flash_bank *bank) stm32l4_info->dual_bank_mode = false; switch (device_id) { - case 0x415: /* STM32L47/L48xx */ - case 0x461: /* STM32L49/L4Axx */ + case DEVID_STM32L47_L48XX: + case DEVID_STM32L49_L4AXX: /* if flash size is max (1M) the device is always dual bank - * 0x415: has variants with 512K - * 0x461: has variants with 512 and 256 + * STM32L47/L48xx: has variants with 512K + * STM32L49/L4Axx: has variants with 512 and 256 * for these variants: * if DUAL_BANK = 0 -> single bank * else -> dual bank without gap @@ -940,25 +1907,43 @@ static int stm32l4_probe(struct flash_bank *bank) num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; - /* check DUAL_BANK bit[21] if the flash is less than 1M */ - if (flash_size_kb == 1024 || (options & BIT(21))) { + /* check DUAL_BANK option bit if the flash is less than 1M */ + if (is_max_flash_size || (stm32l4_info->optr & FLASH_L4_DUAL_BANK)) { stm32l4_info->dual_bank_mode = true; stm32l4_info->bank1_sectors = num_pages / 2; } break; - case 0x435: /* STM32L43/L44xx */ - case 0x460: /* STM32G07/G08xx */ - case 0x462: /* STM32L45/L46xx */ - case 0x464: /* STM32L41/L42xx */ - case 0x466: /* STM32G03/G04xx */ - case 0x468: /* STM32G43/G44xx */ - case 0x497: /* STM32WLEx */ + case DEVID_STM32L43_L44XX: + case DEVID_STM32C01XX: + case DEVID_STM32C03XX: + case DEVID_STM32G05_G06XX: + case DEVID_STM32G07_G08XX: + case DEVID_STM32L45_L46XX: + case DEVID_STM32L41_L42XX: + case DEVID_STM32G03_G04XX: + case DEVID_STM32G43_G44XX: + case DEVID_STM32G49_G4AXX: + case DEVID_STM32WB1XX: /* single bank flash */ page_size_kb = 2; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; break; - case 0x469: /* STM32G47/G48xx */ + case DEVID_STM32G0B_G0CXX: + /* single/dual bank depending on DUAL_BANK option bit */ + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + stm32l4_info->cr_bker_mask = FLASH_BKER_G0; + + /* check DUAL_BANK bit */ + if (stm32l4_info->optr & FLASH_G0_DUAL_BANK) { + stm32l4_info->sr_bsy_mask = FLASH_BSY | FLASH_BSY2; + stm32l4_info->dual_bank_mode = true; + stm32l4_info->bank1_sectors = num_pages / 2; + } + break; + case DEVID_STM32G47_G48XX: /* STM32G47/8 can be single/dual bank: * if DUAL_BANK = 0 -> single bank * else -> dual bank WITH gap @@ -966,7 +1951,7 @@ static int stm32l4_probe(struct flash_bank *bank) page_size_kb = 4; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; - if (options & BIT(22)) { + if (stm32l4_info->optr & FLASH_G4_DUAL_BANK) { stm32l4_info->dual_bank_mode = true; page_size_kb = 2; num_pages = flash_size_kb / page_size_kb; @@ -977,39 +1962,94 @@ static int stm32l4_probe(struct flash_bank *bank) (part_info->max_flash_size_kb - flash_size_kb) / (2 * page_size_kb); } break; - case 0x470: /* STM32L4R/L4Sxx */ - case 0x471: /* STM32L4P5/L4Q5x */ + case DEVID_STM32L4R_L4SXX: + case DEVID_STM32L4P_L4QXX: /* STM32L4R/S can be single/dual bank: - * if size = 2M check DBANK bit(22) - * if size = 1M check DB1M bit(21) + * if size = 2M check DBANK bit + * if size = 1M check DB1M bit * STM32L4P/Q can be single/dual bank - * if size = 1M check DBANK bit(22) - * if size = 512K check DB512K bit(21) + * if size = 1M check DBANK bit + * if size = 512K check DB512K bit (same as DB1M bit) */ page_size_kb = 8; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; - const bool use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb; - if ((use_dbank_bit && (options & BIT(22))) || - (!use_dbank_bit && (options & BIT(21)))) { + if ((is_max_flash_size && (stm32l4_info->optr & FLASH_L4R_DBANK)) || + (!is_max_flash_size && (stm32l4_info->optr & FLASH_LRR_DB1M))) { stm32l4_info->dual_bank_mode = true; page_size_kb = 4; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages / 2; } break; - case 0x495: /* STM32WB5x */ - case 0x496: /* STM32WB3x */ + case DEVID_STM32L55_L56XX: + /* STM32L55/L56xx can be single/dual bank: + * if size = 512K check DBANK bit + * if size = 256K check DB256K bit + * + * default page size is 4kb, if DBANK = 1, the page size is 2kb. + */ + + page_size_kb = (stm32l4_info->optr & FLASH_L5_DBANK) ? 2 : 4; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + + if ((is_max_flash_size && (stm32l4_info->optr & FLASH_L5_DBANK)) || + (!is_max_flash_size && (stm32l4_info->optr & FLASH_L5_DB256))) { + stm32l4_info->dual_bank_mode = true; + stm32l4_info->bank1_sectors = num_pages / 2; + } + break; + case DEVID_STM32U57_U58XX: + /* if flash size is max (2M) the device is always dual bank + * otherwise check DUALBANK + */ + page_size_kb = 8; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + if (is_max_flash_size || (stm32l4_info->optr & FLASH_U5_DUALBANK)) { + stm32l4_info->dual_bank_mode = true; + 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 */ page_size_kb = 4; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; break; + case DEVID_STM32WLE_WL5XX: + /* single bank flash */ + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + + /* 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 (armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) + stm32l4_info->flash_regs = stm32wl_cpu2_flash_regs; + break; default: LOG_ERROR("unsupported device"); 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; @@ -1030,10 +2070,8 @@ static int stm32l4_probe(struct flash_bank *bank) /* use *max_flash_size* instead of actual size as the trimmed versions * certainly use the same number of bits - * max_flash_size is always power of two, so max_pages too */ uint32_t max_pages = stm32l4_info->part_info->max_flash_size_kb / page_size_kb; - assert((max_pages & (max_pages - 1)) == 0); /* in dual bank mode number of pages is doubled, but extra bit is bank selection */ stm32l4_info->wrpxxr_mask = ((max_pages >> (stm32l4_info->dual_bank_mode ? 1 : 0)) - 1); @@ -1043,10 +2081,9 @@ static int stm32l4_probe(struct flash_bank *bank) free(bank->sectors); bank->size = (flash_size_kb + gap_size_kb) * 1024; - bank->base = STM32_FLASH_BANK_BASE; bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); - if (bank->sectors == NULL) { + if (!bank->sectors) { LOG_ERROR("failed to allocate bank sectors"); return ERROR_FAIL; } @@ -1069,40 +2106,45 @@ static int stm32l4_probe(struct flash_bank *bank) static int stm32l4_auto_probe(struct flash_bank *bank) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; - if (stm32l4_info->probed) - return ERROR_OK; + if (stm32l4_info->probed) { + uint32_t optr_cur; + + /* save flash_regs_base */ + uint32_t saved_flash_regs_base = stm32l4_info->flash_regs_base; + + /* for devices with TrustZone, use NS flash registers to read OPTR */ + if (stm32l4_info->part_info->flags & F_HAS_L5_FLASH_REGS) + stm32l4_info->flash_regs_base &= ~STM32L5_REGS_SEC_OFFSET; + + /* read flash option register and re-probe if optr value is changed */ + int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &optr_cur); + + /* restore saved flash_regs_base */ + stm32l4_info->flash_regs_base = saved_flash_regs_base; + + if (retval != ERROR_OK) + return retval; + + if (stm32l4_info->optr == optr_cur) + return ERROR_OK; + } return stm32l4_probe(bank); } -static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_stm32l4_info(struct flash_bank *bank, struct command_invocation *cmd) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; const struct stm32l4_part_info *part_info = stm32l4_info->part_info; if (part_info) { - const char *rev_str = NULL; - uint16_t rev_id = stm32l4_info->idcode >> 16; - for (unsigned int i = 0; i < part_info->num_revs; i++) { - if (rev_id == part_info->revs[i].rev) { - rev_str = part_info->revs[i].str; - - if (rev_str != NULL) { - snprintf(buf, buf_size, "%s - Rev: %s%s", - part_info->device_str, rev_str, stm32l4_info->probed ? - (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : ""); - return ERROR_OK; - } - } - } - - snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)%s", - part_info->device_str, rev_id, stm32l4_info->probed ? - (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : ""); - return ERROR_OK; + const uint16_t rev_id = stm32l4_info->idcode >> 16; + command_print_sameline(cmd, "%s - Rev %s : 0x%04x", part_info->device_str, + get_stm32l4_rev_str(bank), rev_id); + if (stm32l4_info->probed) + command_print_sameline(cmd, " - %s-bank", get_stm32l4_bank_type_str(bank)); } else { - snprintf(buf, buf_size, "Cannot identify target as an %s device", device_families); - return ERROR_FAIL; + command_print_sameline(cmd, "Cannot identify target as an %s device", device_families); } return ERROR_OK; @@ -1114,9 +2156,14 @@ static int stm32l4_mass_erase(struct flash_bank *bank) struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + if (stm32l4_is_otp(bank)) { + LOG_ERROR("cannot erase OTP memory"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + uint32_t action = FLASH_MER1; - if (stm32l4_info->part_info->has_dual_bank) + if (stm32l4_info->part_info->flags & F_HAS_DUAL_BANK) action |= FLASH_MER2; if (target->state != TARGET_HALTED) { @@ -1124,6 +2171,16 @@ static int stm32l4_mass_erase(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } + if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { + /* set all FLASH pages as secure */ + retval = stm32l4_set_secbb(bank, FLASH_SECBB_SECURE); + if (retval != ERROR_OK) { + /* restore all FLASH pages as non-secure */ + stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); /* ignore the return value */ + return retval; + } + } + retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) goto err_lock; @@ -1133,18 +2190,25 @@ static int stm32l4_mass_erase(struct flash_bank *bank) if (retval != ERROR_OK) goto err_lock; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, action); if (retval != ERROR_OK) goto err_lock; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action | FLASH_STRT); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, action | FLASH_STRT); if (retval != ERROR_OK) goto err_lock; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); err_lock: - retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); + retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK); + + if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { + /* restore all FLASH pages as non-secure */ + int retval3 = stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); + if (retval3 != ERROR_OK) + return retval3; + } if (retval != ERROR_OK) return retval; @@ -1154,50 +2218,41 @@ err_lock: 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); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32l4_mass_erase(bank); - if (retval == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - + if (retval == ERROR_OK) command_print(CMD, "stm32l4x mass erase complete"); - } else { + else command_print(CMD, "stm32l4x mass erase failed"); - } return retval; } 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); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; uint32_t reg_offset, reg_addr; uint32_t value = 0; - reg_offset = strtoul(CMD_ARGV[1], NULL, 16); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); reg_addr = stm32l4_get_flash_reg(bank, reg_offset); retval = stm32l4_read_flash_reg(bank, reg_offset, &value); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "", reg_addr, value); @@ -1207,24 +2262,23 @@ 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); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; uint32_t reg_offset; uint32_t value = 0; uint32_t mask = 0xFFFFFFFF; - reg_offset = strtoul(CMD_ARGV[1], NULL, 16); - value = strtoul(CMD_ARGV[2], NULL, 16); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); + if (CMD_ARGC > 3) - mask = strtoul(CMD_ARGV[3], NULL, 16); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], mask); command_print(CMD, "%s Option written.\n" "INFO: a reset or power cycle is required " @@ -1234,52 +2288,106 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command) return retval; } -COMMAND_HANDLER(stm32l4_handle_option_load_command) +COMMAND_HANDLER(stm32l4_handle_trustzone_command) { - if (CMD_ARGC != 1) + if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; - retval = stm32l4_unlock_reg(bank); - if (ERROR_OK != retval) + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + if (!(stm32l4_info->part_info->flags & F_HAS_TZ)) { + LOG_ERROR("This device does not have a TrustZone"); + return ERROR_FAIL; + } + + retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &stm32l4_info->optr); + if (retval != ERROR_OK) return retval; - retval = stm32l4_unlock_option_reg(bank); - if (ERROR_OK != retval) + stm32l4_sync_rdp_tzen(bank); + + if (CMD_ARGC == 1) { + /* only display the TZEN value */ + LOG_INFO("Global TrustZone Security is %s", stm32l4_info->tzen ? "enabled" : "disabled"); + return ERROR_OK; + } + + bool new_tzen; + COMMAND_PARSE_ENABLE(CMD_ARGV[1], new_tzen); + + if (new_tzen == stm32l4_info->tzen) { + LOG_INFO("The requested TZEN is already programmed"); + return ERROR_OK; + } + + if (new_tzen) { + if (stm32l4_info->rdp != RDP_LEVEL_0) { + LOG_ERROR("TZEN can be set only when RDP level is 0"); + return ERROR_FAIL; + } + retval = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], + FLASH_TZEN, FLASH_TZEN); + } else { + /* Deactivation of TZEN (from 1 to 0) is only possible when the RDP is + * changing to level 0 (from level 1 to level 0 or from level 0.5 to level 0). */ + if (stm32l4_info->rdp != RDP_LEVEL_1 && stm32l4_info->rdp != RDP_LEVEL_0_5) { + LOG_ERROR("Deactivation of TZEN is only possible when the RDP is changing to level 0"); + return ERROR_FAIL; + } + + retval = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], + RDP_LEVEL_0, FLASH_RDP_MASK | FLASH_TZEN); + } + + if (retval != ERROR_OK) return retval; - /* Set OBL_LAUNCH bit in CR -> system reset and option bytes reload, - * but the RMs explicitly do *NOT* list this as power-on reset cause, and: - * "Note: If the read protection is set while the debugger is still - * connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset." - */ - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OBL_LAUNCH); + return stm32l4_perform_obl_launch(bank); +} - command_print(CMD, "stm32l4x option load completed. Power-on reset might be required"); +COMMAND_HANDLER(stm32l4_handle_option_load_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - /* Need to re-probe after change */ - struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; - stm32l4_info->probed = false; + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; - return retval; + retval = stm32l4_perform_obl_launch(bank); + if (retval != ERROR_OK) { + command_print(CMD, "stm32l4x option load failed"); + return retval; + } + + + command_print(CMD, "stm32l4x option load completed. Power-on reset might be required"); + + return ERROR_OK; } 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; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; + if (stm32l4_is_otp(bank)) { + LOG_ERROR("cannot lock/unlock OTP memory"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + target = bank->target; if (target->state != TARGET_HALTED) { @@ -1288,7 +2396,9 @@ COMMAND_HANDLER(stm32l4_handle_lock_command) } /* set readout protection level 1 by erasing the RDP option byte */ - if (stm32l4_write_option(bank, STM32_FLASH_OPTR, 0, 0x000000FF) != ERROR_OK) { + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], + RDP_LEVEL_1, FLASH_RDP_MASK) != ERROR_OK) { command_print(CMD, "%s failed to lock device", bank->driver->name); return ERROR_OK; } @@ -1300,14 +2410,19 @@ 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; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; + if (stm32l4_is_otp(bank)) { + LOG_ERROR("cannot lock/unlock OTP memory"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + target = bank->target; if (target->state != TARGET_HALTED) { @@ -1315,7 +2430,9 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command) return ERROR_TARGET_NOT_HALTED; } - if (stm32l4_write_option(bank, STM32_FLASH_OPTR, RDP_LEVEL_0, 0x000000FF) != ERROR_OK) { + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], + RDP_LEVEL_0, FLASH_RDP_MASK) != ERROR_OK) { command_print(CMD, "%s failed to unlock device", bank->driver->name); return ERROR_OK; } @@ -1323,6 +2440,105 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command) return ERROR_OK; } +COMMAND_HANDLER(stm32l4_handle_wrp_info_command) +{ + if (CMD_ARGC < 1 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; + + if (stm32l4_is_otp(bank)) { + LOG_ERROR("OTP memory does not have write protection areas"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + enum stm32_bank_id dev_bank_id = STM32_ALL_BANKS; + if (CMD_ARGC == 2) { + if (strcmp(CMD_ARGV[1], "bank1") == 0) + dev_bank_id = STM32_BANK1; + else if (strcmp(CMD_ARGV[1], "bank2") == 0) + dev_bank_id = STM32_BANK2; + else + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (dev_bank_id == STM32_BANK2) { + if (!(stm32l4_info->part_info->flags & F_HAS_DUAL_BANK)) { + LOG_ERROR("this device has no second bank"); + return ERROR_FAIL; + } else if (!stm32l4_info->dual_bank_mode) { + LOG_ERROR("this device is configured in single bank mode"); + return ERROR_FAIL; + } + } + + int ret; + unsigned int n_wrp, i; + struct stm32l4_wrp wrpxy[4]; + + ret = stm32l4_get_all_wrpxy(bank, dev_bank_id, wrpxy, &n_wrp); + if (ret != ERROR_OK) + return ret; + + /* use bitmap and range helpers to better describe protected areas */ + DECLARE_BITMAP(pages, bank->num_sectors); + bitmap_zero(pages, bank->num_sectors); + + for (i = 0; i < n_wrp; i++) { + if (wrpxy[i].used) { + for (int p = wrpxy[i].first; p <= wrpxy[i].last; p++) + set_bit(p, pages); + } + } + + /* we have at most 'n_wrp' WRP areas */ + struct range ranges[n_wrp]; + unsigned int ranges_count = 0; + + bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count); + + if (ranges_count > 0) { + /* pretty-print the protected ranges */ + char *ranges_str = range_print_alloc(ranges, ranges_count); + command_print(CMD, "protected areas: %s", ranges_str); + free(ranges_str); + } else + command_print(CMD, "no protected areas"); + + return ERROR_OK; +} + +COMMAND_HANDLER(stm32l4_handle_otp_command) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; + + if (!stm32l4_is_otp(bank)) { + command_print(CMD, "the specified bank is not an OTP memory"); + return ERROR_FAIL; + } + if (strcmp(CMD_ARGV[1], "enable") == 0) + stm32l4_otp_enable(bank, true); + else if (strcmp(CMD_ARGV[1], "disable") == 0) + stm32l4_otp_enable(bank, false); + else if (strcmp(CMD_ARGV[1], "show") == 0) + command_print(CMD, "OTP memory bank #%d is %s for write commands.", + bank->bank_number, stm32l4_otp_is_enabled(bank) ? "enabled" : "disabled"); + else + return ERROR_COMMAND_SYNTAX_ERROR; + + return ERROR_OK; +} + static const struct command_registration stm32l4_exec_command_handlers[] = { { .name = "lock", @@ -1359,6 +2575,20 @@ static const struct command_registration stm32l4_exec_command_handlers[] = { .usage = "bank_id reg_offset value mask", .help = "Write device option bit fields with provided value.", }, + { + .name = "trustzone", + .handler = stm32l4_handle_trustzone_command, + .mode = COMMAND_EXEC, + .usage = "<bank_id> [enable|disable]", + .help = "Configure TrustZone security", + }, + { + .name = "wrp_info", + .handler = stm32l4_handle_wrp_info_command, + .mode = COMMAND_EXEC, + .usage = "bank_id [bank1|bank2]", + .help = "list the protected areas using WRP", + }, { .name = "option_load", .handler = stm32l4_handle_option_load_command, @@ -1366,6 +2596,13 @@ static const struct command_registration stm32l4_exec_command_handlers[] = { .usage = "bank_id", .help = "Force re-load of device options (will cause device reset).", }, + { + .name = "otp", + .handler = stm32l4_handle_otp_command, + .mode = COMMAND_EXEC, + .usage = "<bank_id> <enable|disable|show>", + .help = "OTP (One Time Programmable) memory write enable/disable", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h index abd8010fc7..3dc0909554 100644 --- a/src/flash/nor/stm32l4x.h +++ b/src/flash/nor/stm32l4x.h @@ -1,62 +1,51 @@ +/* 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 #define OPENOCD_FLASH_NOR_STM32L4X -/* Flash registers offsets */ -#define STM32_FLASH_ACR 0x00 -#define STM32_FLASH_KEYR 0x08 -#define STM32_FLASH_OPTKEYR 0x0c -#define STM32_FLASH_SR 0x10 -#define STM32_FLASH_CR 0x14 -#define STM32_FLASH_OPTR 0x20 -#define STM32_FLASH_WRP1AR 0x2c -#define STM32_FLASH_WRP1BR 0x30 -#define STM32_FLASH_WRP2AR 0x4c -#define STM32_FLASH_WRP2BR 0x50 +/* IMPORTANT: this file is included by stm32l4x driver and flashloader, + * so please when changing this file, do not forget to check the flashloader */ + +/* FIXME: #include "helper/bits.h" cause build errors when compiling + * the flashloader, for now just redefine the needed 'BIT 'macro */ + +#ifndef BIT +#define BIT(nr) (1UL << (nr)) +#endif /* FLASH_CR register bits */ -#define FLASH_PG (1 << 0) -#define FLASH_PER (1 << 1) -#define FLASH_MER1 (1 << 2) +#define FLASH_PG BIT(0) +#define FLASH_PER BIT(1) +#define FLASH_MER1 BIT(2) #define FLASH_PAGE_SHIFT 3 -#define FLASH_CR_BKER (1 << 11) -#define FLASH_MER2 (1 << 15) -#define FLASH_STRT (1 << 16) -#define FLASH_OPTSTRT (1 << 17) -#define FLASH_EOPIE (1 << 24) -#define FLASH_ERRIE (1 << 25) -#define FLASH_OBL_LAUNCH (1 << 27) -#define FLASH_OPTLOCK (1 << 30) -#define FLASH_LOCK (1 << 31) +#define FLASH_BKER BIT(11) +#define FLASH_BKER_G0 BIT(13) +#define FLASH_MER2 BIT(15) +#define FLASH_STRT BIT(16) +#define FLASH_OPTSTRT BIT(17) +#define FLASH_EOPIE BIT(24) +#define FLASH_ERRIE BIT(25) +#define FLASH_OBL_LAUNCH BIT(27) +#define FLASH_OPTLOCK BIT(30) +#define FLASH_LOCK BIT(31) /* FLASH_SR register bits */ -#define FLASH_BSY (1 << 16) +#define FLASH_BSY BIT(16) +#define FLASH_BSY2 BIT(17) /* Fast programming not used => related errors not used*/ -#define FLASH_PGSERR (1 << 7) /* Programming sequence error */ -#define FLASH_SIZERR (1 << 6) /* Size error */ -#define FLASH_PGAERR (1 << 5) /* Programming alignment error */ -#define FLASH_WRPERR (1 << 4) /* Write protection error */ -#define FLASH_PROGERR (1 << 3) /* Programming error */ -#define FLASH_OPERR (1 << 1) /* Operation error */ -#define FLASH_EOP (1 << 0) /* End of operation */ +#define FLASH_PGSERR BIT(7) /* Programming sequence error */ +#define FLASH_SIZERR BIT(6) /* Size error */ +#define FLASH_PGAERR BIT(5) /* Programming alignment error */ +#define FLASH_WRPERR BIT(4) /* Write protection error */ +#define FLASH_PROGERR BIT(3) /* Programming error */ +#define FLASH_OPERR BIT(1) /* Operation error */ +#define FLASH_EOP BIT(0) /* End of operation */ #define FLASH_ERROR (FLASH_PGSERR | FLASH_SIZERR | FLASH_PGAERR | \ FLASH_WRPERR | FLASH_PROGERR | FLASH_OPERR) @@ -68,15 +57,96 @@ #define OPTKEY1 0x08192A3B #define OPTKEY2 0x4C5D6E7F -#define RDP_LEVEL_0 0xAA -#define RDP_LEVEL_1 0xBB -#define RDP_LEVEL_2 0xCC +/* FLASH_OPTR register bits */ +#define FLASH_RDP_MASK 0xFF +#define FLASH_G0_DUAL_BANK BIT(21) +#define FLASH_G4_DUAL_BANK BIT(22) +#define FLASH_L4_DUAL_BANK BIT(21) +#define FLASH_L4R_DBANK BIT(22) +#define FLASH_LRR_DB1M BIT(21) +#define FLASH_L5_DBANK BIT(22) +#define FLASH_L5_DB256 BIT(21) +#define FLASH_U5_DUALBANK BIT(21) +#define FLASH_TZEN BIT(31) + +/* FLASH secure block based bank 1/2 register offsets */ +#define FLASH_SECBB1(X) (0x80 + 4 * (X - 1)) +#define FLASH_SECBB2(X) (0xA0 + 4 * (X - 1)) -/* other registers */ +#define FLASH_SECBB_SECURE 0xFFFFFFFF +#define FLASH_SECBB_NON_SECURE 0 + +/* IDCODE register possible addresses */ #define DBGMCU_IDCODE_G0 0x40015800 #define DBGMCU_IDCODE_L4_G4 0xE0042000 #define DBGMCU_IDCODE_L5 0xE0044000 +#define UID64_DEVNUM 0x1FFF7580 +#define UID64_IDS 0x1FFF7584 +#define UID64_IDS_STM32WL 0x0080E115 + +/* 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 +#define DEVID_STM32L45_L46XX 0x462 +#define DEVID_STM32L41_L42XX 0x464 +#define DEVID_STM32G03_G04XX 0x466 +#define DEVID_STM32G0B_G0CXX 0x467 +#define DEVID_STM32G43_G44XX 0x468 +#define DEVID_STM32G47_G48XX 0x469 +#define DEVID_STM32L4R_L4SXX 0x470 +#define DEVID_STM32L4P_L4QXX 0x471 +#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 +#define DEVID_STM32WLE_WL5XX 0x497 +/* known Flash base addresses */ #define STM32_FLASH_BANK_BASE 0x08000000 +#define STM32_FLASH_S_BANK_BASE 0x0C000000 + +/* offset between non-secure and secure flash registers */ +#define STM32L5_REGS_SEC_OFFSET 0x10000000 + +/* 100 bytes as loader stack should be large enough for the loader to operate */ +#define LDR_STACK_SIZE 100 + +struct stm32l4_work_area { + struct stm32l4_loader_params { + uint32_t flash_sr_addr; + uint32_t flash_cr_addr; + uint32_t flash_word_size; + uint32_t flash_sr_bsy_mask; + } params; + uint8_t stack[LDR_STACK_SIZE]; + struct flash_async_algorithm_circbuf { + /* note: stm32l4_work_area struct is shared between the loader + * and stm32l4x flash driver. + * + * '*wp' and '*rp' pointers' size is 4 bytes each since stm32l4x + * devices have 32-bit processors. + * however when used in openocd code, their size depends on the host + * if the host is 32-bit, then the size is 4 bytes each. + * if the host is 64-bit, then the size is 8 bytes each. + * to avoid this size difference, change their types depending on the + * usage (pointers for the loader, and 32-bit integers in openocd code). + */ +#ifdef OPENOCD_CONTRIB_LOADERS_FLASH_STM32_STM32L4X + uint8_t *wp; + uint8_t *rp; +#else + uint32_t wp; + uint32_t rp; +#endif /* OPENOCD_CONTRIB_LOADERS_FLASH_STM32_STM32L4X */ + } fifo; +}; #endif diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index 3cb1a49982..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" }, @@ -290,7 +279,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command) stm32lx_info = calloc(1, sizeof(*stm32lx_info)); /* Check allocation */ - if (stm32lx_info == NULL) { + if (!stm32lx_info) { LOG_ERROR("failed to allocate bank structure"); return ERROR_FAIL; } @@ -313,19 +302,14 @@ COMMAND_HANDLER(stm32lx_handle_mass_erase_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32lx_mass_erase(bank); - if (retval == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - + if (retval == ERROR_OK) command_print(CMD, "stm32lx mass erase complete"); - } else { + else command_print(CMD, "stm32lx mass erase failed"); - } return retval; } @@ -337,7 +321,7 @@ COMMAND_HANDLER(stm32lx_handle_lock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32lx_lock(bank); @@ -357,7 +341,7 @@ COMMAND_HANDLER(stm32lx_handle_unlock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = stm32lx_unlock(bank); @@ -430,12 +414,12 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; uint32_t hp_nb = stm32lx_info->part_info.page_size / 2; - uint32_t buffer_size = 16384; + uint32_t buffer_size = (16384 / hp_nb) * hp_nb; /* must be multiple of hp_nb */ struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; - struct reg_param reg_params[3]; + struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -445,6 +429,10 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff }; /* Make sure we're performing a half-page aligned write. */ + if (offset % hp_nb) { + LOG_ERROR("The offset must be %" PRIu32 "B-aligned but it is %" PRIi32 "B)", hp_nb, offset); + return ERROR_FAIL; + } if (count % hp_nb) { LOG_ERROR("The byte count must be %" PRIu32 "B-aligned but count is %" PRIu32 "B)", hp_nb, count); return ERROR_FAIL; @@ -481,6 +469,9 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } else { + /* Make sure we're still asking for an integral number of half-pages */ + buffer_size -= buffer_size % hp_nb; } } @@ -489,6 +480,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* Enable half-page write */ retval = stm32lx_enable_write_half_page(bank); @@ -499,11 +492,13 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); return retval; } struct armv7m_common *armv7m = target_to_armv7m(target); - if (armv7m == NULL) { + if (!armv7m) { /* something is very wrong if armv7m is NULL */ LOG_ERROR("unable to get armv7m target"); @@ -529,12 +524,16 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff buf_set_u32(reg_params[0].value, 0, 32, address); /* The source address of the copy (R1) */ buf_set_u32(reg_params[1].value, 0, 32, source->address); - /* The length of the copy (R2) */ - buf_set_u32(reg_params[2].value, 0, 32, this_count / 4); + /* The number of half pages to copy (R2) */ + buf_set_u32(reg_params[2].value, 0, 32, this_count / hp_nb); + /* The size in byes of a half page (R3) */ + buf_set_u32(reg_params[3].value, 0, 32, hp_nb); + /* The flash base address (R4) */ + buf_set_u32(reg_params[4].value, 0, 32, stm32lx_info->flash_base); /* 5: Execute the bunch of code */ - retval = target_run_algorithm(target, 0, NULL, sizeof(reg_params) - / sizeof(*reg_params), reg_params, + retval = target_run_algorithm(target, 0, NULL, + ARRAY_SIZE(reg_params), reg_params, write_algorithm->address, 0, 10000, &armv7m_info); if (retval != ERROR_OK) break; @@ -598,6 +597,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); return retval; } @@ -718,7 +719,7 @@ static int stm32lx_read_id_code(struct target *target, uint32_t *id) { struct armv7m_common *armv7m = target_to_armv7m(target); int retval; - if (armv7m->arm.is_armv6m == true) + if (armv7m->arm.arch == ARM_ARCH_V6M) retval = target_read_u32(target, DBGMCU_IDCODE_L0, id); else /* read stm32 device id register */ @@ -842,7 +843,7 @@ static int stm32lx_probe(struct flash_bank *bank) bank->base = base_address; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); - if (bank->sectors == NULL) { + if (!bank->sectors) { LOG_ERROR("failed to allocate bank sectors"); return ERROR_FAIL; } @@ -870,7 +871,7 @@ static int stm32lx_auto_probe(struct flash_bank *bank) } /* This method must return a string displaying information about the bank */ -static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size) +static int stm32lx_get_info(struct flash_bank *bank, struct command_invocation *cmd) { struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; const struct stm32lx_part_info *info = &stm32lx_info->part_info; @@ -880,8 +881,7 @@ static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size) if (!stm32lx_info->probed) { int retval = stm32lx_probe(bank); if (retval != ERROR_OK) { - snprintf(buf, buf_size, - "Unable to find bank information."); + command_print_sameline(cmd, "Unable to find bank information."); return retval; } } @@ -890,14 +890,10 @@ static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size) if (rev_id == info->revs[i].rev) rev_str = info->revs[i].str; - if (rev_str != NULL) { - snprintf(buf, buf_size, - "%s - Rev: %s", - info->device_str, rev_str); + if (rev_str) { + command_print_sameline(cmd, "%s - Rev: %s", info->device_str, rev_str); } else { - snprintf(buf, buf_size, - "%s - Rev: unknown (0x%04x)", - info->device_str, rev_id); + 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 new file mode 100644 index 0000000000..a1e1d34116 --- /dev/null +++ b/src/flash/nor/stmqspi.c @@ -0,0 +1,2465 @@ +// 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 * + ***************************************************************************/ + +/* STM QuadSPI (QSPI) and OctoSPI (OCTOSPI) controller are SPI bus controllers + * specifically designed for SPI memories. + * Two working modes are available: + * - indirect mode: the SPI is controlled by SW. Any custom commands can be sent + * on the bus. + * - memory mapped mode: the SPI is under QSPI/OCTOSPI control. Memory content + * is directly accessible in CPU memory space. CPU can read and execute from + * memory (but not write to) */ + +/* ATTENTION: + * To have flash mapped in CPU memory space, the QSPI/OCTOSPI controller + * has to be in "memory mapped mode". This requires following constraints: + * 1) The command "reset init" has to initialize QSPI/OCTOSPI controller and put + * it in memory mapped mode; + * 2) every command in this file has to return to prompt in memory mapped mode. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include <helper/binarybuffer.h> +#include <helper/bits.h> +#include <helper/time_support.h> +#include <target/algorithm.h> +#include <target/armv7m.h> +#include <target/image.h> +#include "stmqspi.h" +#include "sfdp.h" + +/* deprecated */ +#undef SPIFLASH_READ +#undef SPIFLASH_PAGE_PROGRAM + +/* saved mode settings */ +#define QSPI_MODE (stmqspi_info->saved_ccr & \ + (0xF0000000U | QSPI_DCYC_MASK | QSPI_4LINE_MODE | QSPI_ALTB_MODE | QSPI_ADDR4)) + +/* saved read mode settings but indirect read instead of memory mapped + * in particular, use the dummy cycle setting from this saved setting */ +#define QSPI_CCR_READ (QSPI_READ_MODE | (stmqspi_info->saved_ccr & \ + (0xF0000000U | QSPI_DCYC_MASK | QSPI_4LINE_MODE | QSPI_ALTB_MODE | QSPI_ADDR4 | 0xFF))) + +/* QSPI_CCR for various other commands, these never use dummy cycles nor alternate bytes */ +#define QSPI_CCR_READ_STATUS \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB) | \ + (QSPI_READ_MODE | SPIFLASH_READ_STATUS)) + +#define QSPI_CCR_READ_ID \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB) | \ + (QSPI_READ_MODE | SPIFLASH_READ_ID)) + +#define QSPI_CCR_READ_MID \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB) | \ + (QSPI_READ_MODE | SPIFLASH_READ_MID)) + +/* always use 3-byte addresses for read SFDP */ +#define QSPI_CCR_READ_SFDP \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & ~QSPI_ADDR4 & QSPI_NO_ALTB) | \ + (QSPI_READ_MODE | QSPI_ADDR3 | SPIFLASH_READ_SFDP)) + +#define QSPI_CCR_WRITE_ENABLE \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB & QSPI_NO_DATA) | \ + (QSPI_WRITE_MODE | SPIFLASH_WRITE_ENABLE)) + +#define QSPI_CCR_SECTOR_ERASE \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ALTB & QSPI_NO_DATA) | \ + (QSPI_WRITE_MODE | stmqspi_info->dev.erase_cmd)) + +#define QSPI_CCR_MASS_ERASE \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB & QSPI_NO_DATA) | \ + (QSPI_WRITE_MODE | stmqspi_info->dev.chip_erase_cmd)) + +#define QSPI_CCR_PAGE_PROG \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ALTB) | \ + (QSPI_WRITE_MODE | stmqspi_info->dev.pprog_cmd)) + +/* saved mode settings */ +#define OCTOSPI_MODE (stmqspi_info->saved_cr & 0xCFFFFFFF) + +#define OPI_MODE ((stmqspi_info->saved_ccr & OCTOSPI_ISIZE_MASK) != 0) + +#define OCTOSPI_MODE_CCR (stmqspi_info->saved_ccr & \ + (0xF0000000U | OCTOSPI_8LINE_MODE | OCTOSPI_ALTB_MODE | OCTOSPI_ADDR4)) + +/* use saved ccr for read */ +#define OCTOSPI_CCR_READ OCTOSPI_MODE_CCR + +/* OCTOSPI_CCR for various other commands, these never use alternate bytes * + * for READ_STATUS and READ_ID, 4-byte address 0 * + * 4 dummy cycles must sent in OPI mode when DQS is disabled. However, when * + * DQS is enabled, some STM32 devices need at least 6 dummy cycles for * + * proper operation, but otherwise the actual number has no effect! * + * E.g. RM0432 Rev. 7 is incorrect regarding this: L4R9 works well with 4 * + * dummy clocks whereas L4P5 not at all. * + */ +#define OPI_DUMMY \ + ((stmqspi_info->saved_ccr & OCTOSPI_DQSEN) ? 6U : 4U) + +#define OCTOSPI_CCR_READ_STATUS \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & \ + (OPI_MODE ? ~0U : OCTOSPI_NO_ADDR) & OCTOSPI_NO_ALTB)) + +#define OCTOSPI_CCR_READ_ID \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & \ + (OPI_MODE ? ~0U : OCTOSPI_NO_ADDR) & OCTOSPI_NO_ALTB)) + +#define OCTOSPI_CCR_READ_MID OCTOSPI_CCR_READ_ID + +/* 4-byte address in octo mode, else 3-byte address for read SFDP */ +#define OCTOSPI_CCR_READ_SFDP(len) \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & ~OCTOSPI_ADDR4 & OCTOSPI_NO_ALTB) | \ + (((len) < 4) ? OCTOSPI_ADDR3 : OCTOSPI_ADDR4)) + +#define OCTOSPI_CCR_WRITE_ENABLE \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_ADDR & OCTOSPI_NO_ALTB & OCTOSPI_NO_DATA)) + +#define OCTOSPI_CCR_SECTOR_ERASE \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_ALTB & OCTOSPI_NO_DATA)) + +#define OCTOSPI_CCR_MASS_ERASE \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_ADDR & OCTOSPI_NO_ALTB & OCTOSPI_NO_DATA)) + +#define OCTOSPI_CCR_PAGE_PROG \ + ((OCTOSPI_MODE_CCR & QSPI_NO_ALTB)) + +#define SPI_ADSIZE (((stmqspi_info->saved_ccr >> SPI_ADSIZE_POS) & 0x3) + 1) + +#define OPI_CMD(cmd) ((OPI_MODE ? ((((uint16_t)(cmd)) << 8) | (~(cmd) & 0xFFU)) : (cmd))) + +/* convert uint32_t into 4 uint8_t in little endian byte order */ +static inline uint32_t h_to_le_32(uint32_t val) +{ + uint32_t result; + + h_u32_to_le((uint8_t *)&result, val); + return result; +} + +/* Timeout in ms */ +#define SPI_CMD_TIMEOUT (100) +#define SPI_PROBE_TIMEOUT (100) +#define SPI_MAX_TIMEOUT (2000) +#define SPI_MASS_ERASE_TIMEOUT (400000) + +struct sector_info { + uint32_t offset; + uint32_t size; + uint32_t result; +}; + +struct stmqspi_flash_bank { + bool probed; + char devname[32]; + bool octo; + struct flash_device dev; + uint32_t io_base; + uint32_t saved_cr; /* in particular FSEL, DFM bit mask in QUADSPI_CR *AND* OCTOSPI_CR */ + uint32_t saved_ccr; /* different meaning for QUADSPI and OCTOSPI */ + uint32_t saved_tcr; /* only for OCTOSPI */ + uint32_t saved_ir; /* only for OCTOSPI */ + unsigned int sfdp_dummy1; /* number of dummy bytes for SFDP read for flash1 and octo */ + unsigned int sfdp_dummy2; /* number of dummy bytes for SFDP read for flash2 */ +}; + +static inline int octospi_cmd(struct flash_bank *bank, uint32_t mode, + uint32_t ccr, uint32_t ir) +{ + struct target *target = bank->target; + const struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + const uint32_t io_base = stmqspi_info->io_base; + + int retval = target_write_u32(target, io_base + OCTOSPI_CR, + OCTOSPI_MODE | mode); + + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, io_base + OCTOSPI_TCR, + (stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) | + ((OPI_MODE && (mode == OCTOSPI_READ_MODE)) ? + (OPI_DUMMY << OCTOSPI_DCYC_POS) : 0)); + + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, io_base + OCTOSPI_CCR, ccr); + + if (retval != ERROR_OK) + return retval; + + return target_write_u32(target, io_base + OCTOSPI_IR, OPI_CMD(ir)); +} + +FLASH_BANK_COMMAND_HANDLER(stmqspi_flash_bank_command) +{ + struct stmqspi_flash_bank *stmqspi_info; + uint32_t io_base; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC < 7) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], io_base); + + stmqspi_info = malloc(sizeof(struct stmqspi_flash_bank)); + if (!stmqspi_info) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + bank->driver_priv = stmqspi_info; + stmqspi_info->sfdp_dummy1 = 0; + stmqspi_info->sfdp_dummy2 = 0; + stmqspi_info->probed = false; + stmqspi_info->io_base = io_base; + + return ERROR_OK; +} + +/* Poll busy flag */ +/* timeout in ms */ +static int poll_busy(struct flash_bank *bank, int timeout) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + long long endtime; + + endtime = timeval_ms() + timeout; + do { + uint32_t spi_sr; + int retval = target_read_u32(target, io_base + SPI_SR, &spi_sr); + + if (retval != ERROR_OK) + return retval; + + if ((spi_sr & BIT(SPI_BUSY)) == 0) { + /* Clear transmit finished flag */ + return target_write_u32(target, io_base + SPI_FCR, BIT(SPI_TCF)); + } else + LOG_DEBUG("busy: 0x%08X", spi_sr); + alive_sleep(1); + } while (timeval_ms() < endtime); + + LOG_ERROR("Timeout while polling BUSY"); + return ERROR_FLASH_OPERATION_FAILED; +} + +static int stmqspi_abort(struct flash_bank *bank) +{ + struct target *target = bank->target; + const struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + const uint32_t io_base = stmqspi_info->io_base; + uint32_t cr; + + int retval = target_read_u32(target, io_base + SPI_CR, &cr); + + if (retval != ERROR_OK) + cr = 0; + + return target_write_u32(target, io_base + SPI_CR, cr | BIT(SPI_ABORT)); +} + +/* Set to memory-mapped mode, e.g. after an error */ +static int set_mm_mode(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + int retval; + + /* Reset Address register bits 0 and 1, see various errata sheets */ + retval = target_write_u32(target, io_base + SPI_AR, 0x0); + if (retval != ERROR_OK) + return retval; + + /* Abort any previous operation */ + retval = stmqspi_abort(bank); + if (retval != ERROR_OK) + return retval; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + /* Finally switch to memory mapped mode */ + if (IS_OCTOSPI) { + retval = target_write_u32(target, io_base + OCTOSPI_CR, + OCTOSPI_MODE | OCTOSPI_MM_MODE); + if (retval == ERROR_OK) + retval = target_write_u32(target, io_base + OCTOSPI_CCR, + stmqspi_info->saved_ccr); + if (retval == ERROR_OK) + retval = target_write_u32(target, io_base + OCTOSPI_TCR, + stmqspi_info->saved_tcr); + if (retval == ERROR_OK) + retval = target_write_u32(target, io_base + OCTOSPI_IR, + stmqspi_info->saved_ir); + } else { + retval = target_write_u32(target, io_base + QSPI_CR, + stmqspi_info->saved_cr); + if (retval == ERROR_OK) + retval = target_write_u32(target, io_base + QSPI_CCR, + stmqspi_info->saved_ccr); + } + return retval; +} + +/* Read the status register of the external SPI flash chip(s). */ +static int read_status_reg(struct flash_bank *bank, uint16_t *status) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + uint8_t data; + int count, retval; + + /* Abort any previous operation */ + retval = stmqspi_abort(bank); + if (retval != ERROR_OK) + return retval; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + goto err; + + /* Read always two (for DTR mode) bytes per chip */ + count = 2; + retval = target_write_u32(target, io_base + SPI_DLR, + ((stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 2 * count : count) - 1); + if (retval != ERROR_OK) + goto err; + + /* Read status */ + if (IS_OCTOSPI) { + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_STATUS, + SPIFLASH_READ_STATUS); + if (OPI_MODE) { + /* Dummy address 0, only required for 8-line mode */ + retval = target_write_u32(target, io_base + SPI_AR, 0); + if (retval != ERROR_OK) + goto err; + } + } else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_STATUS); + if (retval != ERROR_OK) + goto err; + + *status = 0; + + /* for debugging only */ + uint32_t dummy; + (void)target_read_u32(target, io_base + SPI_SR, &dummy); + + for ( ; count > 0; --count) { + if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) + != BIT(SPI_FSEL_FLASH)) { + /* get status of flash 1 in dual mode or flash 1 only mode */ + retval = target_read_u8(target, io_base + SPI_DR, &data); + if (retval != ERROR_OK) + goto err; + *status |= data; + } + + if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) { + /* get status of flash 2 in dual mode or flash 2 only mode */ + retval = target_read_u8(target, io_base + SPI_DR, &data); + if (retval != ERROR_OK) + goto err; + *status |= ((uint16_t)data) << 8; + } + } + + LOG_DEBUG("flash status regs: 0x%04" PRIx16, *status); + +err: + return retval; +} + +/* check for WIP (write in progress) bit(s) in status register(s) */ +/* timeout in ms */ +static int wait_till_ready(struct flash_bank *bank, int timeout) +{ + uint16_t status; + int retval; + long long endtime; + + endtime = timeval_ms() + timeout; + do { + /* Read flash status register(s) */ + retval = read_status_reg(bank, &status); + if (retval != ERROR_OK) + return retval; + + if ((status & ((SPIFLASH_BSY_BIT << 8) | SPIFLASH_BSY_BIT)) == 0) + return retval; + alive_sleep(25); + } while (timeval_ms() < endtime); + + LOG_ERROR("timeout"); + return ERROR_FLASH_OPERATION_FAILED; +} + +/* Send "write enable" command to SPI flash chip(s). */ +static int qspi_write_enable(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + uint16_t status; + int retval; + + /* Abort any previous operation */ + retval = stmqspi_abort(bank); + if (retval != ERROR_OK) + return retval; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + goto err; + + /* Send write enable command */ + if (IS_OCTOSPI) { + retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_WRITE_ENABLE, + SPIFLASH_WRITE_ENABLE); + if (OPI_MODE) { + /* Dummy address 0, only required for 8-line mode */ + retval = target_write_u32(target, io_base + SPI_AR, 0); + if (retval != ERROR_OK) + goto err; + } + } else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_WRITE_ENABLE); + if (retval != ERROR_OK) + goto err; + + + /* Wait for transmit of command completed */ + poll_busy(bank, SPI_CMD_TIMEOUT); + if (retval != ERROR_OK) + goto err; + + /* Read flash status register */ + retval = read_status_reg(bank, &status); + if (retval != ERROR_OK) + goto err; + + /* Check write enabled for flash 1 */ + if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) + != BIT(SPI_FSEL_FLASH)) + if ((status & (SPIFLASH_WE_BIT | SPIFLASH_BSY_BIT)) != SPIFLASH_WE_BIT) { + LOG_ERROR("Cannot write enable flash1. Status=0x%02x", + status & 0xFFU); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Check write enabled for flash 2 */ + status >>= 8; + if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) + if ((status & (SPIFLASH_WE_BIT | SPIFLASH_BSY_BIT)) != SPIFLASH_WE_BIT) { + LOG_ERROR("Cannot write enable flash2. Status=0x%02x", + status & 0xFFU); + return ERROR_FLASH_OPERATION_FAILED; + } + +err: + return retval; +} + +COMMAND_HANDLER(stmqspi_handle_mass_erase_command) +{ + struct target *target = NULL; + struct flash_bank *bank; + struct stmqspi_flash_bank *stmqspi_info; + struct duration bench; + uint32_t io_base; + uint16_t status; + unsigned int sector; + int retval; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; + + stmqspi_info = bank->driver_priv; + target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (stmqspi_info->dev.chip_erase_cmd == 0x00) { + LOG_ERROR("Mass erase not available for this device"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + for (sector = 0; sector < bank->num_sectors; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FLASH_PROTECTED; + } + } + + io_base = stmqspi_info->io_base; + duration_start(&bench); + + retval = qspi_write_enable(bank); + if (retval != ERROR_OK) + goto err; + + /* Send Mass Erase command */ + if (IS_OCTOSPI) + retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_MASS_ERASE, + stmqspi_info->dev.chip_erase_cmd); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_MASS_ERASE); + if (retval != ERROR_OK) + goto err; + + /* Wait for transmit of command completed */ + poll_busy(bank, SPI_CMD_TIMEOUT); + if (retval != ERROR_OK) + goto err; + + /* Read flash status register(s) */ + retval = read_status_reg(bank, &status); + if (retval != ERROR_OK) + goto err; + + /* Check for command in progress for flash 1 */ + if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) + != BIT(SPI_FSEL_FLASH)) && ((status & SPIFLASH_BSY_BIT) == 0) && + ((status & SPIFLASH_WE_BIT) != 0)) { + LOG_ERROR("Mass erase command not accepted by flash1. Status=0x%02x", + status & 0xFFU); + retval = ERROR_FLASH_OPERATION_FAILED; + goto err; + } + + /* Check for command in progress for flash 2 */ + status >>= 8; + if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) && + ((status & SPIFLASH_BSY_BIT) == 0) && + ((status & SPIFLASH_WE_BIT) != 0)) { + LOG_ERROR("Mass erase command not accepted by flash2. Status=0x%02x", + status & 0xFFU); + retval = ERROR_FLASH_OPERATION_FAILED; + goto err; + } + + /* Poll WIP for end of self timed Sector Erase cycle */ + retval = wait_till_ready(bank, SPI_MASS_ERASE_TIMEOUT); + + duration_measure(&bench); + if (retval == ERROR_OK) + command_print(CMD, "stmqspi mass erase completed in %fs (%0.3f KiB/s)", + duration_elapsed(&bench), + duration_kbps(&bench, bank->size)); + else + command_print(CMD, "stmqspi mass erase not completed even after %fs", + duration_elapsed(&bench)); + +err: + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int log2u(uint32_t word) +{ + int result; + + for (result = 0; (unsigned int) result < sizeof(uint32_t) * CHAR_BIT; result++) + if (word == BIT(result)) + return result; + + return -1; +} + +COMMAND_HANDLER(stmqspi_handle_set) +{ + struct flash_bank *bank = NULL; + struct target *target = NULL; + struct stmqspi_flash_bank *stmqspi_info = NULL; + struct flash_sector *sectors = NULL; + uint32_t io_base; + unsigned int index = 0, dual, fsize; + int retval; + + LOG_DEBUG("%s", __func__); + + /* chip_erase_cmd, sectorsize and erase_cmd are optional */ + if ((CMD_ARGC < 7) || (CMD_ARGC > 10)) + return ERROR_COMMAND_SYNTAX_ERROR; + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, index++, &bank); + if (retval != ERROR_OK) + return retval; + + target = bank->target; + stmqspi_info = bank->driver_priv; + dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; + + /* invalidate all flash device info */ + if (stmqspi_info->probed) + free(bank->sectors); + 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"; + + strncpy(stmqspi_info->devname, CMD_ARGV[index++], sizeof(stmqspi_info->devname) - 1); + stmqspi_info->devname[sizeof(stmqspi_info->devname) - 1] = '\0'; + + 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_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_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_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.qread_cmd); + if ((stmqspi_info->dev.qread_cmd != 0x00) && + (stmqspi_info->dev.qread_cmd != 0x0B) && + (stmqspi_info->dev.qread_cmd != 0x0C) && + (stmqspi_info->dev.qread_cmd != 0x3B) && + (stmqspi_info->dev.qread_cmd != 0x3C) && + (stmqspi_info->dev.qread_cmd != 0x6B) && + (stmqspi_info->dev.qread_cmd != 0x6C) && + (stmqspi_info->dev.qread_cmd != 0xBB) && + (stmqspi_info->dev.qread_cmd != 0xBC) && + (stmqspi_info->dev.qread_cmd != 0xEB) && + (stmqspi_info->dev.qread_cmd != 0xEC) && + (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_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.pprog_cmd); + if ((stmqspi_info->dev.pprog_cmd != 0x02) && + (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_ARGUMENT_INVALID; + } + + if (index < CMD_ARGC) + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.chip_erase_cmd); + else + stmqspi_info->dev.chip_erase_cmd = 0x00; + + if (index < CMD_ARGC) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], stmqspi_info->dev.sectorsize); + if ((stmqspi_info->dev.sectorsize > stmqspi_info->dev.size_in_bytes) || + (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_ARGUMENT_INVALID; + } + + if (index < CMD_ARGC) + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.erase_cmd); + else + return ERROR_COMMAND_SYNTAX_ERROR; + } else { + /* no sector size / sector erase cmd given, treat whole bank as a single sector */ + stmqspi_info->dev.erase_cmd = 0x00; + stmqspi_info->dev.sectorsize = stmqspi_info->dev.size_in_bytes; + } + + /* set correct size value */ + bank->size = stmqspi_info->dev.size_in_bytes << dual; + + io_base = stmqspi_info->io_base; + + 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); + if (bank->size == BIT(fsize + 1)) + LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1."); + else if (bank->size == BIT(fsize + 0)) + LOG_DEBUG("FSIZE in DCR(1) is off by one regarding actual capacity. Fix for silicon bug?"); + else + LOG_ERROR("FSIZE in DCR(1) doesn't match actual capacity."); + + /* create and fill sectors array */ + bank->num_sectors = + stmqspi_info->dev.size_in_bytes / stmqspi_info->dev.sectorsize; + sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (!sectors) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * (stmqspi_info->dev.sectorsize << dual); + sectors[sector].size = (stmqspi_info->dev.sectorsize << dual); + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + 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 " 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 " B," + " bank size = %" PRIu32 " B", stmqspi_info->dev.name, + stmqspi_info->dev.size_in_bytes, + stmqspi_info->dev.size_in_bytes << dual); + + stmqspi_info->probed = true; + + return ERROR_OK; +} + +COMMAND_HANDLER(stmqspi_handle_cmd) +{ + struct target *target = NULL; + struct flash_bank *bank; + struct stmqspi_flash_bank *stmqspi_info = NULL; + uint32_t io_base, addr; + uint8_t num_write, num_read, cmd_byte, data; + unsigned int count; + const int max = 21; + char temp[4], output[(2 + max + 256) * 3 + 8]; + int retval; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC < 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + num_write = CMD_ARGC - 2; + if (num_write > max) { + LOG_ERROR("at most %d bytes may be sent", max); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; + + target = bank->target; + stmqspi_info = bank->driver_priv; + io_base = stmqspi_info->io_base; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], num_read); + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[2], cmd_byte); + + if (num_read == 0) { + /* nothing to read, then one command byte and for dual flash + * an *even* number of data bytes to follow */ + 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_ARGUMENT_INVALID; + } + } + } else { + /* read mode, one command byte and up to four following address bytes */ + 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_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_ARGUMENT_INVALID; + } + } + + /* Abort any previous operation */ + retval = stmqspi_abort(bank); + if (retval != ERROR_OK) + return retval; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + /* send command byte */ + snprintf(output, sizeof(output), "spi: %02x ", cmd_byte); + if (num_read == 0) { + /* write, send cmd byte */ + retval = target_write_u32(target, io_base + SPI_DLR, ((uint32_t)num_write) - 2); + if (retval != ERROR_OK) + goto err; + + if (IS_OCTOSPI) + retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, + (OCTOSPI_MODE_CCR & OCTOSPI_NO_ALTB & OCTOSPI_NO_ADDR & + ((num_write == 1) ? OCTOSPI_NO_DATA : ~0U)), cmd_byte); + else + retval = target_write_u32(target, io_base + QSPI_CCR, + (QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ALTB & QSPI_NO_ADDR & + ((num_write == 1) ? QSPI_NO_DATA : ~0U)) | + (QSPI_WRITE_MODE | cmd_byte)); + if (retval != ERROR_OK) + goto err; + + /* send additional data bytes */ + for (count = 3; count < CMD_ARGC; count++) { + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[count], data); + snprintf(temp, sizeof(temp), "%02" PRIx8 " ", data); + retval = target_write_u8(target, io_base + SPI_DR, data); + if (retval != ERROR_OK) + goto err; + strncat(output, temp, sizeof(output) - strlen(output) - 1); + } + strncat(output, "-> ", sizeof(output) - strlen(output) - 1); + } else { + /* read, pack additional bytes into address */ + addr = 0; + for (count = 3; count < CMD_ARGC; count++) { + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[count], data); + snprintf(temp, sizeof(temp), "%02" PRIx8 " ", data); + addr = (addr << 8) | data; + strncat(output, temp, sizeof(output) - strlen(output) - 1); + } + strncat(output, "-> ", sizeof(output) - strlen(output) - 1); + + /* send cmd byte, if ADMODE indicates no address, this already triggers command */ + retval = target_write_u32(target, io_base + SPI_DLR, ((uint32_t)num_read) - 1); + if (retval != ERROR_OK) + goto err; + if (IS_OCTOSPI) + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, + (OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & OCTOSPI_NO_ALTB & ~OCTOSPI_ADDR4 & + ((num_write == 1) ? OCTOSPI_NO_ADDR : ~0U)) | + (((num_write - 2) & 0x3U) << SPI_ADSIZE_POS), cmd_byte); + else + retval = target_write_u32(target, io_base + QSPI_CCR, + (QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ALTB & ~QSPI_ADDR4 & + ((num_write == 1) ? QSPI_NO_ADDR : ~0U)) | + ((QSPI_READ_MODE | (((num_write - 2) & 0x3U) << SPI_ADSIZE_POS) | cmd_byte))); + if (retval != ERROR_OK) + goto err; + + if (num_write > 1) { + /* if ADMODE indicates address required, only the write to AR triggers command */ + retval = target_write_u32(target, io_base + SPI_AR, addr); + if (retval != ERROR_OK) + goto err; + } + + /* read response bytes */ + for ( ; num_read > 0; num_read--) { + retval = target_read_u8(target, io_base + SPI_DR, &data); + if (retval != ERROR_OK) + goto err; + snprintf(temp, sizeof(temp), "%02" PRIx8 " ", data); + strncat(output, temp, sizeof(output) - strlen(output) - 1); + } + } + command_print(CMD, "%s", output); + +err: + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int qspi_erase_sector(struct flash_bank *bank, unsigned int sector) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + uint16_t status; + int retval; + + retval = qspi_write_enable(bank); + if (retval != ERROR_OK) + goto err; + + /* Send Sector Erase command */ + if (IS_OCTOSPI) + retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_SECTOR_ERASE, + stmqspi_info->dev.erase_cmd); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_SECTOR_ERASE); + if (retval != ERROR_OK) + goto err; + + /* Address is sector offset, this write initiates command transmission */ + retval = target_write_u32(target, io_base + SPI_AR, bank->sectors[sector].offset); + if (retval != ERROR_OK) + goto err; + + /* Wait for transmit of command completed */ + poll_busy(bank, SPI_CMD_TIMEOUT); + if (retval != ERROR_OK) + goto err; + + /* Read flash status register(s) */ + retval = read_status_reg(bank, &status); + if (retval != ERROR_OK) + goto err; + + LOG_DEBUG("erase status regs: 0x%04" PRIx16, status); + + /* Check for command in progress for flash 1 */ + /* If BSY and WE are already cleared the erase did probably complete already */ + if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) + != BIT(SPI_FSEL_FLASH)) && ((status & SPIFLASH_BSY_BIT) == 0) && + ((status & SPIFLASH_WE_BIT) != 0)) { + LOG_ERROR("Sector erase command not accepted by flash1. Status=0x%02x", + status & 0xFFU); + retval = ERROR_FLASH_OPERATION_FAILED; + goto err; + } + + /* Check for command in progress for flash 2 */ + /* If BSY and WE are already cleared the erase did probably complete already */ + status >>= 8; + if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) && + ((status & SPIFLASH_BSY_BIT) == 0) && + ((status & SPIFLASH_WE_BIT) != 0)) { + LOG_ERROR("Sector erase command not accepted by flash2. Status=0x%02x", + status & 0xFFU); + retval = ERROR_FLASH_OPERATION_FAILED; + goto err; + } + + /* Erase takes a long time, so some sort of progress message is a good idea */ + LOG_DEBUG("erasing sector %4u", sector); + + /* Poll WIP for end of self timed Sector Erase cycle */ + retval = wait_till_ready(bank, SPI_MAX_TIMEOUT); + +err: + return retval; +} + +static int stmqspi_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + unsigned int sector; + int retval = ERROR_OK; + + LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (stmqspi_info->dev.erase_cmd == 0x00) { + LOG_ERROR("Sector erase not available for this device"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + if ((last < first) || (last >= bank->num_sectors)) { + LOG_ERROR("Flash sector invalid"); + return ERROR_FLASH_SECTOR_INVALID; + } + + for (sector = first; sector <= last; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FLASH_PROTECTED; + } + } + + for (sector = first; sector <= last; sector++) { + retval = qspi_erase_sector(bank, sector); + if (retval != ERROR_OK) + break; + alive_sleep(10); + keep_alive(); + } + + if (retval != ERROR_OK) + LOG_ERROR("Flash sector_erase failed on sector %u", sector); + + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int stmqspi_protect(struct flash_bank *bank, int set, + unsigned int first, unsigned int last) +{ + unsigned int sector; + + for (sector = first; sector <= last; sector++) + bank->sectors[sector].is_protected = set; + + if (set) + LOG_WARNING("setting soft protection only, not related to flash's hardware write protection"); + + return ERROR_OK; +} + +/* Check whether flash is blank */ +static int stmqspi_blank_check(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + struct duration bench; + struct reg_param reg_params[2]; + struct armv7m_algorithm armv7m_info; + struct working_area *algorithm; + const uint8_t *code; + struct sector_info erase_check_info; + uint32_t codesize, maxsize, result, exit_point; + unsigned int count, index, num_sectors, sector; + int retval; + const uint32_t erased = 0x00FF; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + /* Abort any previous operation */ + retval = stmqspi_abort(bank); + if (retval != ERROR_OK) + return retval; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + /* see contrib/loaders/flash/stmqspi/stmqspi_erase_check.S for src */ + static const uint8_t stmqspi_erase_check_code[] = { + #include "../../../contrib/loaders/flash/stmqspi/stmqspi_erase_check.inc" + }; + + /* see contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S for src */ + static const uint8_t stmoctospi_erase_check_code[] = { + #include "../../../contrib/loaders/flash/stmqspi/stmoctospi_erase_check.inc" + }; + + if (IS_OCTOSPI) { + code = stmoctospi_erase_check_code; + codesize = sizeof(stmoctospi_erase_check_code); + } else { + code = stmqspi_erase_check_code; + codesize = sizeof(stmqspi_erase_check_code); + } + + /* This will overlay the last 4 words of stmqspi/stmoctospi_erase_check_code in target */ + /* for read use the saved settings (memory mapped mode) but indirect read mode */ + uint32_t ccr_buffer[][4] = { + /* cr (not used for QSPI) * + * ccr (for both QSPI and OCTOSPI) * + * tcr (not used for QSPI) * + * ir (not used for QSPI) */ + { + h_to_le_32(OCTOSPI_MODE | OCTOSPI_READ_MODE), + h_to_le_32(IS_OCTOSPI ? OCTOSPI_CCR_READ : QSPI_CCR_READ), + h_to_le_32(stmqspi_info->saved_tcr), + h_to_le_32(stmqspi_info->saved_ir), + }, + }; + + maxsize = target_get_working_area_avail(target); + if (maxsize < codesize + sizeof(erase_check_info)) { + LOG_ERROR("Not enough working area, can't do QSPI blank check"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + num_sectors = (maxsize - codesize) / sizeof(erase_check_info); + num_sectors = (bank->num_sectors < num_sectors) ? bank->num_sectors : num_sectors; + + if (target_alloc_working_area_try(target, + codesize + num_sectors * sizeof(erase_check_info), &algorithm) != ERROR_OK) { + LOG_ERROR("allocating working area failed"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + }; + + /* prepare blank check code, excluding ccr_buffer */ + retval = target_write_buffer(target, algorithm->address, + codesize - sizeof(ccr_buffer), code); + if (retval != ERROR_OK) + goto err; + + /* prepare QSPI/OCTOSPI_CCR register values */ + retval = target_write_buffer(target, algorithm->address + + codesize - sizeof(ccr_buffer), + sizeof(ccr_buffer), (uint8_t *)ccr_buffer); + if (retval != ERROR_OK) + goto err; + + duration_start(&bench); + + /* after breakpoint instruction (halfword), one nop (halfword) and + * port_buffer till end of code */ + exit_point = algorithm->address + codesize - sizeof(uint32_t) - sizeof(ccr_buffer); + + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* sector count */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* QSPI/OCTOSPI io_base */ + + sector = 0; + while (sector < bank->num_sectors) { + /* at most num_sectors sectors to handle in one run */ + count = bank->num_sectors - sector; + if (count > num_sectors) + count = num_sectors; + + for (index = 0; index < count; index++) { + erase_check_info.offset = h_to_le_32(bank->sectors[sector + index].offset); + erase_check_info.size = h_to_le_32(bank->sectors[sector + index].size); + erase_check_info.result = h_to_le_32(erased); + + retval = target_write_buffer(target, algorithm->address + + codesize + index * sizeof(erase_check_info), + sizeof(erase_check_info), (uint8_t *)&erase_check_info); + if (retval != ERROR_OK) + goto err; + } + + buf_set_u32(reg_params[0].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, stmqspi_info->io_base); + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + LOG_DEBUG("checking sectors %u to %u", sector, sector + count - 1); + /* check a block of sectors */ + retval = target_run_algorithm(target, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm->address, exit_point, + count * ((bank->sectors[sector].size >> 6) + 1) + 1000, + &armv7m_info); + if (retval != ERROR_OK) + break; + + for (index = 0; index < count; index++) { + retval = target_read_buffer(target, algorithm->address + + codesize + index * sizeof(erase_check_info), + sizeof(erase_check_info), (uint8_t *)&erase_check_info); + if (retval != ERROR_OK) + goto err; + + if ((erase_check_info.offset != h_to_le_32(bank->sectors[sector + index].offset)) || + (erase_check_info.size != 0)) { + LOG_ERROR("corrupted blank check info"); + goto err; + } + + /* we need le_32_to_h, but that's the same as h_to_le_32 */ + result = h_to_le_32(erase_check_info.result); + bank->sectors[sector + index].is_erased = ((result & 0xFF) == 0xFF); + LOG_DEBUG("Flash sector %u checked: 0x%04x", sector + index, result & 0xFFFFU); + } + keep_alive(); + sector += count; + } + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + + duration_measure(&bench); + LOG_INFO("stmqspi blank checked in %fs (%0.3f KiB/s)", duration_elapsed(&bench), + duration_kbps(&bench, bank->size)); + +err: + target_free_working_area(target, algorithm); + + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +/* Verify checksum */ +static int qspi_verify(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + struct reg_param reg_params[4]; + struct armv7m_algorithm armv7m_info; + struct working_area *algorithm; + const uint8_t *code; + uint32_t pagesize, codesize, crc32, result, exit_point; + int retval; + + /* see contrib/loaders/flash/stmqspi/stmqspi_crc32.S for src */ + static const uint8_t stmqspi_crc32_code[] = { + #include "../../../contrib/loaders/flash/stmqspi/stmqspi_crc32.inc" + }; + + /* see contrib/loaders/flash/stmqspi/stmoctospi_crc32.S for src */ + static const uint8_t stmoctospi_crc32_code[] = { + #include "../../../contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc" + }; + + if (IS_OCTOSPI) { + code = stmoctospi_crc32_code; + codesize = sizeof(stmoctospi_crc32_code); + } else { + code = stmqspi_crc32_code; + codesize = sizeof(stmqspi_crc32_code); + } + + /* block size doesn't matter that much here */ + pagesize = stmqspi_info->dev.sectorsize; + if (pagesize == 0) + pagesize = stmqspi_info->dev.pagesize; + if (pagesize == 0) + pagesize = SPIFLASH_DEF_PAGESIZE; + + /* adjust size according to dual flash mode */ + pagesize = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? pagesize << 1 : pagesize; + + /* This will overlay the last 4 words of stmqspi/stmoctospi_crc32_code in target */ + /* for read use the saved settings (memory mapped mode) but indirect read mode */ + uint32_t ccr_buffer[][4] = { + /* cr (not used for QSPI) * + * ccr (for both QSPI and OCTOSPI) * + * tcr (not used for QSPI) * + * ir (not used for QSPI) */ + { + h_to_le_32(OCTOSPI_MODE | OCTOSPI_READ_MODE), + h_to_le_32(IS_OCTOSPI ? OCTOSPI_CCR_READ : QSPI_CCR_READ), + h_to_le_32(stmqspi_info->saved_tcr), + h_to_le_32(stmqspi_info->saved_ir), + }, + }; + + if (target_alloc_working_area_try(target, codesize, &algorithm) != ERROR_OK) { + LOG_ERROR("Not enough working area, can't do QSPI verify"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + }; + + /* prepare verify code, excluding ccr_buffer */ + retval = target_write_buffer(target, algorithm->address, + codesize - sizeof(ccr_buffer), code); + if (retval != ERROR_OK) + goto err; + + /* prepare QSPI/OCTOSPI_CCR register values */ + retval = target_write_buffer(target, algorithm->address + + codesize - sizeof(ccr_buffer), + sizeof(ccr_buffer), (uint8_t *)ccr_buffer); + if (retval != ERROR_OK) + goto err; + + /* after breakpoint instruction (halfword), one nop (halfword) and + * port_buffer till end of code */ + exit_point = algorithm->address + codesize - sizeof(uint32_t) - sizeof(ccr_buffer); + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* count (in), crc32 (out) */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* pagesize */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* offset into flash address */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* QSPI/OCTOSPI io_base */ + + buf_set_u32(reg_params[0].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, pagesize); + buf_set_u32(reg_params[2].value, 0, 32, offset); + buf_set_u32(reg_params[3].value, 0, 32, stmqspi_info->io_base); + + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + retval = target_run_algorithm(target, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm->address, exit_point, + (count >> 5) + 1000, + &armv7m_info); + keep_alive(); + + image_calculate_checksum(buffer, count, &crc32); + + if (retval == ERROR_OK) { + result = buf_get_u32(reg_params[0].value, 0, 32); + LOG_DEBUG("addr " TARGET_ADDR_FMT ", len 0x%08" PRIx32 ", crc 0x%08" PRIx32 " 0x%08" PRIx32, + offset + bank->base, count, ~crc32, result); + if (~crc32 != result) + retval = ERROR_FAIL; + } + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + +err: + target_free_working_area(target, algorithm); + + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int qspi_read_write_block(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count, bool write) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + struct reg_param reg_params[6]; + struct armv7m_algorithm armv7m_info; + struct working_area *algorithm; + uint32_t pagesize, fifo_start, fifosize, remaining; + uint32_t maxsize, codesize, exit_point; + const uint8_t *code = NULL; + unsigned int dual; + int retval; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " len=0x%08" PRIx32, + __func__, offset, count); + + dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; + + /* see contrib/loaders/flash/stmqspi/stmqspi_read.S for src */ + static const uint8_t stmqspi_read_code[] = { +#include "../../../contrib/loaders/flash/stmqspi/stmqspi_read.inc" + }; + + /* see contrib/loaders/flash/stmqspi/stmoctospi_read.S for src */ + static const uint8_t stmoctospi_read_code[] = { +#include "../../../contrib/loaders/flash/stmqspi/stmoctospi_read.inc" + }; + + /* see contrib/loaders/flash/stmqspi/stmqspi_write.S for src */ + static const uint8_t stmqspi_write_code[] = { +#include "../../../contrib/loaders/flash/stmqspi/stmqspi_write.inc" + }; + + /* see contrib/loaders/flash/stmqspi/stmoctospi_write.S for src */ + static const uint8_t stmoctospi_write_code[] = { +#include "../../../contrib/loaders/flash/stmqspi/stmoctospi_write.inc" + }; + + /* This will overlay the last 12 words of stmqspi/stmoctospi_read/write_code in target */ + /* for read use the saved settings (memory mapped mode) but indirect read mode */ + uint32_t ccr_buffer[][4] = { + /* cr (not used for QSPI) * + * ccr (for both QSPI and OCTOSPI) * + * tcr (not used for QSPI) * + * ir (not used for QSPI) */ + { + h_to_le_32(OCTOSPI_MODE | OCTOSPI_READ_MODE), + h_to_le_32(IS_OCTOSPI ? OCTOSPI_CCR_READ_STATUS : QSPI_CCR_READ_STATUS), + h_to_le_32((stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) | + (OPI_MODE ? (OPI_DUMMY << OCTOSPI_DCYC_POS) : 0)), + h_to_le_32(OPI_CMD(SPIFLASH_READ_STATUS)), + }, + { + h_to_le_32(OCTOSPI_MODE | OCTOSPI_WRITE_MODE), + h_to_le_32(IS_OCTOSPI ? OCTOSPI_CCR_WRITE_ENABLE : QSPI_CCR_WRITE_ENABLE), + h_to_le_32(stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK), + h_to_le_32(OPI_CMD(SPIFLASH_WRITE_ENABLE)), + }, + { + h_to_le_32(OCTOSPI_MODE | (write ? OCTOSPI_WRITE_MODE : OCTOSPI_READ_MODE)), + h_to_le_32(write ? (IS_OCTOSPI ? OCTOSPI_CCR_PAGE_PROG : QSPI_CCR_PAGE_PROG) : + (IS_OCTOSPI ? OCTOSPI_CCR_READ : QSPI_CCR_READ)), + h_to_le_32(write ? (stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) : + stmqspi_info->saved_tcr), + h_to_le_32(write ? OPI_CMD(stmqspi_info->dev.pprog_cmd) : stmqspi_info->saved_ir), + }, + }; + + /* force reasonable defaults */ + fifosize = stmqspi_info->dev.sectorsize ? + stmqspi_info->dev.sectorsize : stmqspi_info->dev.size_in_bytes; + + if (write) { + if (IS_OCTOSPI) { + code = stmoctospi_write_code; + codesize = sizeof(stmoctospi_write_code); + } else { + code = stmqspi_write_code; + codesize = sizeof(stmqspi_write_code); + } + } else { + if (IS_OCTOSPI) { + code = stmoctospi_read_code; + codesize = sizeof(stmoctospi_read_code); + } else { + code = stmqspi_read_code; + codesize = sizeof(stmqspi_read_code); + } + } + + /* for write, pagesize must be taken into account */ + /* for read, the page size doesn't matter that much */ + pagesize = stmqspi_info->dev.pagesize; + if (pagesize == 0) + pagesize = (fifosize <= SPIFLASH_DEF_PAGESIZE) ? + fifosize : SPIFLASH_DEF_PAGESIZE; + + /* adjust sizes according to dual flash mode */ + pagesize <<= dual; + fifosize <<= dual; + + /* memory buffer, we assume sectorsize to be a power of 2 times pagesize */ + maxsize = target_get_working_area_avail(target); + if (maxsize < codesize + 2 * sizeof(uint32_t) + pagesize) { + LOG_ERROR("not enough working area, can't do QSPI page reads/writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* fifo size at most sector size, and multiple of page size */ + maxsize -= (codesize + 2 * sizeof(uint32_t)); + fifosize = ((maxsize < fifosize) ? maxsize : fifosize) & ~(pagesize - 1); + + if (target_alloc_working_area_try(target, + codesize + 2 * sizeof(uint32_t) + fifosize, &algorithm) != ERROR_OK) { + LOG_ERROR("allocating working area failed"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + }; + + /* prepare flash write code, excluding ccr_buffer */ + retval = target_write_buffer(target, algorithm->address, + codesize - sizeof(ccr_buffer), code); + if (retval != ERROR_OK) + goto err; + + /* prepare QSPI/OCTOSPI_CCR register values */ + retval = target_write_buffer(target, algorithm->address + + codesize - sizeof(ccr_buffer), + sizeof(ccr_buffer), (uint8_t *)ccr_buffer); + if (retval != ERROR_OK) + goto err; + + /* target buffer starts right after flash_write_code, i.e. + * wp and rp are implicitly included in buffer!!! */ + fifo_start = algorithm->address + codesize + 2 * sizeof(uint32_t); + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* count (in), status (out) */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* pagesize */ + init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); /* offset into flash address */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* QSPI/OCTOSPI io_base */ + init_reg_param(®_params[4], "r8", 32, PARAM_OUT); /* fifo start */ + init_reg_param(®_params[5], "r9", 32, PARAM_OUT); /* fifo end + 1 */ + + buf_set_u32(reg_params[0].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, pagesize); + buf_set_u32(reg_params[2].value, 0, 32, offset); + buf_set_u32(reg_params[3].value, 0, 32, io_base); + buf_set_u32(reg_params[4].value, 0, 32, fifo_start); + buf_set_u32(reg_params[5].value, 0, 32, fifo_start + fifosize); + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + /* after breakpoint instruction (halfword), one nop (halfword) and + * ccr_buffer follow till end of code */ + exit_point = algorithm->address + codesize + - (sizeof(ccr_buffer) + sizeof(uint32_t)); + + if (write) { + retval = target_run_flash_async_algorithm(target, buffer, count, 1, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm->address + codesize, + fifosize + 2 * sizeof(uint32_t), + algorithm->address, exit_point, + &armv7m_info); + } else { + retval = target_run_read_async_algorithm(target, buffer, count, 1, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm->address + codesize, + fifosize + 2 * sizeof(uint32_t), + algorithm->address, exit_point, + &armv7m_info); + } + + remaining = buf_get_u32(reg_params[0].value, 0, 32); + if ((retval == ERROR_OK) && remaining) + retval = ERROR_FLASH_OPERATION_FAILED; + + if (retval != ERROR_OK) { + offset = buf_get_u32(reg_params[2].value, 0, 32); + LOG_ERROR("flash %s failed at address 0x%" PRIx32 ", remaining 0x%" PRIx32, + write ? "write" : "read", offset, remaining); + } + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); + +err: + target_free_working_area(target, algorithm); + + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int stmqspi_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + int retval; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Read beyond end of flash. Extra data to be ignored."); + count = bank->size - offset; + } + + /* Abort any previous operation */ + retval = stmqspi_abort(bank); + if (retval != ERROR_OK) + return retval; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + return qspi_read_write_block(bank, buffer, offset, count, false); +} + +static int stmqspi_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + unsigned int dual, sector; + bool octal_dtr; + int retval; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; + octal_dtr = IS_OCTOSPI && (stmqspi_info->saved_ccr & BIT(OCTOSPI_DDTR)); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Write beyond end of flash. Extra data discarded."); + count = bank->size - offset; + } + + /* Check sector protection */ + for (sector = 0; sector < bank->num_sectors; sector++) { + /* Start offset in or before this sector? */ + /* End offset in or behind this sector? */ + if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && + ((offset + count - 1) >= bank->sectors[sector].offset) && + bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FLASH_PROTECTED; + } + } + + if ((dual || octal_dtr) && ((offset & 1) != 0 || (count & 1) != 0)) { + LOG_ERROR("In dual-QSPI and octal-DTR modes writes must be two byte aligned: " + "%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, offset, count); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + /* Abort any previous operation */ + retval = stmqspi_abort(bank); + if (retval != ERROR_OK) + return retval; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + return qspi_read_write_block(bank, (uint8_t *)buffer, offset, count, true); +} + +static int stmqspi_verify(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + unsigned int dual; + bool octal_dtr; + int retval; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; + octal_dtr = IS_OCTOSPI && (stmqspi_info->saved_ccr & BIT(OCTOSPI_DDTR)); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Verify beyond end of flash. Extra data ignored."); + count = bank->size - offset; + } + + if ((dual || octal_dtr) && ((offset & 1) != 0 || (count & 1) != 0)) { + LOG_ERROR("In dual-QSPI and octal-DTR modes reads must be two byte aligned: " + "%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, offset, count); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + /* Abort any previous operation */ + retval = stmqspi_abort(bank); + if (retval != ERROR_OK) + return retval; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + return qspi_verify(bank, (uint8_t *)buffer, offset, count); +} + +/* Find appropriate dummy setting, in particular octo mode */ +static int find_sfdp_dummy(struct flash_bank *bank, int len) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + uint8_t data; + unsigned int dual, count; + bool flash1 = !(stmqspi_info->saved_cr & BIT(SPI_FSEL_FLASH)); + int retval; + const unsigned int max_bytes = 64; + + dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; + + LOG_DEBUG("%s: len=%d, dual=%u, flash1=%d", + __func__, len, dual, flash1); + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + stmqspi_info->saved_cr | BIT(SPI_ABORT)); + if (retval != ERROR_OK) + goto err; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + goto err; + + /* Switch to saved_cr (had to be set accordingly before this call) */ + retval = target_write_u32(target, io_base + SPI_CR, stmqspi_info->saved_cr); + if (retval != ERROR_OK) + goto err; + + /* Read at most that many bytes */ + retval = target_write_u32(target, io_base + SPI_DLR, (max_bytes << dual) - 1); + if (retval != ERROR_OK) + return retval; + + /* Read SFDP block */ + if (IS_OCTOSPI) + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, + OCTOSPI_CCR_READ_SFDP(len), SPIFLASH_READ_SFDP); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_SFDP); + if (retval != ERROR_OK) + goto err; + + /* Read from start of sfdp block */ + retval = target_write_u32(target, io_base + SPI_AR, 0); + if (retval != ERROR_OK) + goto err; + + for (count = 0 ; count < max_bytes; count++) { + if ((dual != 0) && !flash1) { + /* discard even byte in dual flash-mode if flash2 */ + retval = target_read_u8(target, io_base + SPI_DR, &data); + if (retval != ERROR_OK) + goto err; + } + + retval = target_read_u8(target, io_base + SPI_DR, &data); + if (retval != ERROR_OK) + goto err; + + if (data == 0x53) { + LOG_DEBUG("start of SFDP header for flash%c after %u dummy bytes", + flash1 ? '1' : '2', count); + if (flash1) + stmqspi_info->sfdp_dummy1 = count; + else + stmqspi_info->sfdp_dummy2 = count; + return ERROR_OK; + } + + if ((dual != 0) && flash1) { + /* discard odd byte in dual flash-mode if flash1 */ + retval = target_read_u8(target, io_base + SPI_DR, &data); + if (retval != ERROR_OK) + goto err; + } + } + + LOG_DEBUG("no start of SFDP header even after %u dummy bytes", count); + +err: + /* Abort operation */ + retval = stmqspi_abort(bank); + + return retval; +} + +/* Read SFDP parameter block */ +static int read_sfdp_block(struct flash_bank *bank, uint32_t addr, + uint32_t words, uint32_t *buffer) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + bool flash1 = !(stmqspi_info->saved_cr & BIT(SPI_FSEL_FLASH)); + unsigned int dual, count, len, *dummy; + int retval; + + dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; + + if (IS_OCTOSPI && (((stmqspi_info->saved_ccr >> SPI_DMODE_POS) & 0x7) > 3)) { + /* in OCTO mode 4-byte address and (yet) unknown number of dummy clocks */ + len = 4; + + /* in octo mode, use sfdp_dummy1 only */ + dummy = &stmqspi_info->sfdp_dummy1; + if (*dummy == 0) { + retval = find_sfdp_dummy(bank, len); + if (retval != ERROR_OK) + return retval; + } + } else { + /* in all other modes 3-byte-address and 8(?) dummy clocks */ + len = 3; + + /* use sfdp_dummy1/2 according to currently selected flash */ + dummy = (stmqspi_info->saved_cr & BIT(SPI_FSEL_FLASH)) ? + &stmqspi_info->sfdp_dummy2 : &stmqspi_info->sfdp_dummy1; + + /* according to SFDP standard, there should always be 8 dummy *CLOCKS* + * giving 1, 2 or 4 dummy *BYTES*, however, this is apparently not + * always implemented correctly, so determine the number of dummy bytes + * dynamically */ + if (*dummy == 0) { + retval = find_sfdp_dummy(bank, len); + if (retval != ERROR_OK) + return retval; + } + } + + LOG_DEBUG("%s: addr=0x%08" PRIx32 " words=0x%08" PRIx32 " dummy=%u", + __func__, addr, words, *dummy); + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + stmqspi_info->saved_cr | BIT(SPI_ABORT)); + if (retval != ERROR_OK) + goto err; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + goto err; + + /* Switch to one flash only */ + retval = target_write_u32(target, io_base + SPI_CR, stmqspi_info->saved_cr); + if (retval != ERROR_OK) + goto err; + + /* Read that many words plus dummy bytes */ + retval = target_write_u32(target, io_base + SPI_DLR, + ((*dummy + words * sizeof(uint32_t)) << dual) - 1); + if (retval != ERROR_OK) + goto err; + + /* Read SFDP block */ + if (IS_OCTOSPI) + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, + OCTOSPI_CCR_READ_SFDP(len), SPIFLASH_READ_SFDP); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_SFDP); + if (retval != ERROR_OK) + goto err; + + retval = target_write_u32(target, io_base + SPI_AR, addr << dual); + if (retval != ERROR_OK) + goto err; + + /* dummy clocks */ + for (count = *dummy << dual; count > 0; --count) { + retval = target_read_u8(target, io_base + SPI_DR, (uint8_t *)buffer); + if (retval != ERROR_OK) + goto err; + } + + for ( ; words > 0; words--) { + if (dual != 0) { + uint32_t word1, word2; + + retval = target_read_u32(target, io_base + SPI_DR, &word1); + if (retval != ERROR_OK) + goto err; + retval = target_read_u32(target, io_base + SPI_DR, &word2); + if (retval != ERROR_OK) + goto err; + + if (!flash1) { + /* shift odd numbered bytes into even numbered ones */ + word1 >>= 8; + word2 >>= 8; + } + + /* pack even numbered bytes into one word */ + *buffer = (word1 & 0xFFU) | ((word1 & 0xFF0000U) >> 8) | + ((word2 & 0xFFU) << 16) | ((word2 & 0xFF0000U) << 8); + + + } else { + retval = target_read_u32(target, io_base + SPI_DR, buffer); + if (retval != ERROR_OK) + goto err; + } + LOG_DEBUG("raw SFDP data 0x%08" PRIx32, *buffer); + + /* endian correction, sfdp data is always le uint32_t based */ + *buffer = le_to_h_u32((uint8_t *)buffer); + buffer++; + } + +err: + return retval; +} + +/* Return ID of flash device(s) */ +/* On exit, indirect mode is kept */ +static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + uint8_t byte; + unsigned int type, count, len1, len2; + int retval = ERROR_OK; + + /* invalidate both ids */ + *id1 = 0; + *id2 = 0; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* SPIFLASH_READ_MID causes device in octal mode to go berserk, so don't use in this case */ + for (type = (IS_OCTOSPI && OPI_MODE) ? 1 : 0; type < 2 ; type++) { + /* Abort any previous operation */ + retval = stmqspi_abort(bank); + if (retval != ERROR_OK) + goto err; + + /* Poll WIP */ + retval = wait_till_ready(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + goto err; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + goto err; + + /* Read at most 16 bytes per chip */ + count = 16; + retval = target_write_u32(target, io_base + SPI_DLR, + (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH) ? count * 2 : count) - 1); + if (retval != ERROR_OK) + goto err; + + /* Read id: one particular flash chip (N25Q128) switches back to SPI mode when receiving + * SPI_FLASH_READ_ID in QPI mode, hence try SPIFLASH_READ_MID first */ + switch (type) { + case 0: + if (IS_OCTOSPI) + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, + OCTOSPI_CCR_READ_MID, SPIFLASH_READ_MID); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_MID); + break; + + case 1: + if (IS_OCTOSPI) + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, + OCTOSPI_CCR_READ_ID, SPIFLASH_READ_ID); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_ID); + break; + + default: + return ERROR_FAIL; + } + + if (retval != ERROR_OK) + goto err; + + /* Dummy address 0, only required for 8-line mode */ + if (IS_OCTOSPI && OPI_MODE) { + retval = target_write_u32(target, io_base + SPI_AR, 0); + if (retval != ERROR_OK) + goto err; + } + + /* for debugging only */ + uint32_t dummy; + (void)target_read_u32(target, io_base + SPI_SR, &dummy); + + /* Read ID from Data Register */ + for (len1 = 0, len2 = 0; count > 0; --count) { + if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | + BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) { + retval = target_read_u8(target, io_base + SPI_DR, &byte); + if (retval != ERROR_OK) + goto err; + /* collect 3 bytes without continuation codes */ + if ((byte != 0x7F) && (len1 < 3)) { + *id1 = (*id1 >> 8) | ((uint32_t)byte) << 16; + len1++; + } + } + if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | + BIT(SPI_FSEL_FLASH))) != 0) { + retval = target_read_u8(target, io_base + SPI_DR, &byte); + if (retval != ERROR_OK) + goto err; + /* collect 3 bytes without continuation codes */ + if ((byte != 0x7F) && (len2 < 3)) { + *id2 = (*id2 >> 8) | ((uint32_t)byte) << 16; + len2++; + } + } + } + + if (((*id1 != 0x000000) && (*id1 != 0xFFFFFF)) || + ((*id2 != 0x000000) && (*id2 != 0xFFFFFF))) + break; + } + + if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | + BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) { + if ((*id1 == 0x000000) || (*id1 == 0xFFFFFF)) { + /* no id retrieved, so id must be set manually */ + LOG_INFO("No id from flash1"); + retval = ERROR_FLASH_BANK_NOT_PROBED; + } + } + + if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) { + if ((*id2 == 0x000000) || (*id2 == 0xFFFFFF)) { + /* no id retrieved, so id must be set manually */ + LOG_INFO("No id from flash2"); + retval = ERROR_FLASH_BANK_NOT_PROBED; + } + } + +err: + return retval; +} + +static int stmqspi_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + struct flash_sector *sectors = NULL; + uint32_t io_base = stmqspi_info->io_base; + uint32_t id1 = 0, id2 = 0, data = 0; + const struct flash_device *p; + const uint32_t magic = 0xAEF1510E; + unsigned int dual, fsize; + bool octal_dtr; + int retval; + + /* invalidate all flash device info */ + if (stmqspi_info->probed) + free(bank->sectors); + 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); + if (retval != ERROR_OK) + return retval; + + /* Wait for busy to be cleared */ + retval = poll_busy(bank, SPI_PROBE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + /* 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) { + (void)target_read_u32(target, io_base + QSPI_ABR, &data); + (void)target_write_u32(target, io_base + QSPI_ABR, 0); + } + + if (data == magic) { + LOG_DEBUG("QSPI_ABR register present"); + stmqspi_info->octo = false; + } else { + uint32_t magic_id; + + retval = target_read_u32(target, io_base + OCTOSPI_MAGIC, &magic_id); + + if (retval == ERROR_OK && magic_id == OCTO_MAGIC_ID) { + LOG_DEBUG("OCTOSPI_MAGIC present"); + stmqspi_info->octo = true; + } else { + LOG_ERROR("No QSPI, no OCTOSPI at 0x%08" PRIx32, io_base); + stmqspi_info->probed = false; + stmqspi_info->dev.name = "none"; + return ERROR_FAIL; + } + } + + /* save current FSEL and DFM bits in QSPI/OCTOSPI_CR, current QSPI/OCTOSPI_CCR value */ + retval = target_read_u32(target, io_base + SPI_CR, &stmqspi_info->saved_cr); + if (retval == ERROR_OK) + retval = target_read_u32(target, io_base + SPI_CCR, &stmqspi_info->saved_ccr); + + if (IS_OCTOSPI) { + uint32_t dcr1; + + retval = target_read_u32(target, io_base + OCTOSPI_DCR1, &dcr1); + + if (retval == ERROR_OK) + retval = target_read_u32(target, io_base + OCTOSPI_TCR, + &stmqspi_info->saved_tcr); + + if (retval == ERROR_OK) + retval = target_read_u32(target, io_base + OCTOSPI_IR, + &stmqspi_info->saved_ir); + + if (retval != ERROR_OK) { + LOG_ERROR("No OCTOSPI at io_base 0x%08" PRIx32, io_base); + stmqspi_info->probed = false; + stmqspi_info->dev.name = "none"; + return ERROR_FAIL; + } + + const uint32_t mtyp = (dcr1 & OCTOSPI_MTYP_MASK) >> OCTOSPI_MTYP_POS; + + if ((mtyp != 0x0) && (mtyp != 0x1)) { + LOG_ERROR("Only regular SPI protocol supported in OCTOSPI"); + stmqspi_info->probed = false; + stmqspi_info->dev.name = "none"; + return ERROR_FAIL; + } + + LOG_DEBUG("OCTOSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", OCTOSPI_CR 0x%08" + PRIx32 ", OCTOSPI_CCR 0x%08" PRIx32 ", %d-byte addr", bank->base, io_base, + stmqspi_info->saved_cr, stmqspi_info->saved_ccr, SPI_ADSIZE); + } else { + if (retval == ERROR_OK) { + LOG_DEBUG("QSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", QSPI_CR 0x%08" + PRIx32 ", QSPI_CCR 0x%08" PRIx32 ", %d-byte addr", bank->base, io_base, + stmqspi_info->saved_cr, stmqspi_info->saved_ccr, SPI_ADSIZE); + if (stmqspi_info->saved_ccr & (1U << QSPI_DDRM)) + LOG_WARNING("DDR mode is untested and suffers from some silicon bugs"); + } else { + LOG_ERROR("No QSPI at io_base 0x%08" PRIx32, io_base); + stmqspi_info->probed = false; + stmqspi_info->dev.name = "none"; + return ERROR_FAIL; + } + } + + dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; + octal_dtr = IS_OCTOSPI && (stmqspi_info->saved_ccr & BIT(OCTOSPI_DDTR)); + if (dual || octal_dtr) + bank->write_start_alignment = bank->write_end_alignment = 2; + else + bank->write_start_alignment = bank->write_end_alignment = 1; + + /* read and decode flash ID; returns in indirect mode */ + retval = read_flash_id(bank, &id1, &id2); + LOG_DEBUG("id1 0x%06" PRIx32 ", id2 0x%06" PRIx32, id1, id2); + if (retval == ERROR_FLASH_BANK_NOT_PROBED) { + /* no id retrieved, so id must be set manually */ + LOG_INFO("No id - set flash parameters manually"); + retval = ERROR_OK; + goto err; + } + + if (retval != ERROR_OK) + goto err; + + /* identify flash1 */ + for (p = flash_devices; id1 && p->name ; p++) { + if (p->device_id == id1) { + 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 + " KiB", p->name, id1, p->size_in_bytes / 1024); + else + LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 + " B", p->name, id1, p->size_in_bytes); + break; + } + } + + if (id1 && !p->name) { + /* chip not been identified by id, then try SFDP */ + struct flash_device temp; + uint32_t saved_cr = stmqspi_info->saved_cr; + + /* select flash1 */ + stmqspi_info->saved_cr = stmqspi_info->saved_cr & ~BIT(SPI_FSEL_FLASH); + retval = spi_sfdp(bank, &temp, &read_sfdp_block); + + /* restore saved_cr */ + stmqspi_info->saved_cr = saved_cr; + + if (retval == ERROR_OK) { + LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 + " 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; + } else { + /* even not identified by SFDP, then give up */ + LOG_WARNING("Unknown flash1 device id = 0x%06" PRIx32 + " - set flash parameters manually", id1); + retval = ERROR_OK; + goto err; + } + } + + /* identify flash2 */ + for (p = flash_devices; id2 && p->name ; p++) { + if (p->device_id == id2) { + if (p->size_in_bytes / 4096) + LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 + " KiB", p->name, id2, p->size_in_bytes / 1024); + else + LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 + " B", p->name, id2, p->size_in_bytes); + + if (!id1) + memcpy(&stmqspi_info->dev, p, sizeof(stmqspi_info->dev)); + else { + if ((stmqspi_info->dev.read_cmd != p->read_cmd) || + (stmqspi_info->dev.qread_cmd != p->qread_cmd) || + (stmqspi_info->dev.pprog_cmd != p->pprog_cmd) || + (stmqspi_info->dev.erase_cmd != p->erase_cmd) || + (stmqspi_info->dev.chip_erase_cmd != p->chip_erase_cmd) || + (stmqspi_info->dev.sectorsize != p->sectorsize) || + (stmqspi_info->dev.size_in_bytes != p->size_in_bytes)) { + LOG_ERROR("Incompatible flash1/flash2 devices"); + goto err; + } + /* page size is optional in SFDP, so accept smallest value */ + if (p->pagesize < stmqspi_info->dev.pagesize) + stmqspi_info->dev.pagesize = p->pagesize; + } + break; + } + } + + if (id2 && !p->name) { + /* chip not been identified by id, then try SFDP */ + struct flash_device temp; + uint32_t saved_cr = stmqspi_info->saved_cr; + + /* select flash2 */ + stmqspi_info->saved_cr = stmqspi_info->saved_cr | BIT(SPI_FSEL_FLASH); + retval = spi_sfdp(bank, &temp, &read_sfdp_block); + + /* restore saved_cr */ + stmqspi_info->saved_cr = saved_cr; + + if (retval == ERROR_OK) + LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 + " 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 + " - set flash parameters manually", id2); + retval = ERROR_OK; + goto err; + } + + if (!id1) + memcpy(&stmqspi_info->dev, &temp, sizeof(stmqspi_info->dev)); + else { + if ((stmqspi_info->dev.read_cmd != temp.read_cmd) || + (stmqspi_info->dev.qread_cmd != temp.qread_cmd) || + (stmqspi_info->dev.pprog_cmd != temp.pprog_cmd) || + (stmqspi_info->dev.erase_cmd != temp.erase_cmd) || + (stmqspi_info->dev.chip_erase_cmd != temp.chip_erase_cmd) || + (stmqspi_info->dev.sectorsize != temp.sectorsize) || + (stmqspi_info->dev.size_in_bytes != temp.size_in_bytes)) { + LOG_ERROR("Incompatible flash1/flash2 devices"); + goto err; + } + /* page size is optional in SFDP, so accept smallest value */ + if (temp.pagesize < stmqspi_info->dev.pagesize) + stmqspi_info->dev.pagesize = temp.pagesize; + } + } + + /* Set correct size value */ + bank->size = stmqspi_info->dev.size_in_bytes << dual; + + uint32_t dcr; + retval = target_read_u32(target, io_base + SPI_DCR, &dcr); + + if (retval != ERROR_OK) + goto err; + + fsize = (dcr >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1); + + LOG_DEBUG("FSIZE = 0x%04x", fsize); + if (bank->size == BIT((fsize + 1))) + LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1."); + else if (bank->size == BIT((fsize + 0))) + LOG_DEBUG("FSIZE in DCR(1) is off by one regarding actual capacity. Fix for silicon bug?"); + else + LOG_ERROR("FSIZE in DCR(1) doesn't match actual capacity."); + + /* if no sectors, then treat whole flash as single sector */ + if (stmqspi_info->dev.sectorsize == 0) + stmqspi_info->dev.sectorsize = stmqspi_info->dev.size_in_bytes; + /* if no page_size, then use sectorsize as page_size */ + if (stmqspi_info->dev.pagesize == 0) + stmqspi_info->dev.pagesize = stmqspi_info->dev.sectorsize; + + /* create and fill sectors array */ + bank->num_sectors = stmqspi_info->dev.size_in_bytes / stmqspi_info->dev.sectorsize; + sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (!sectors) { + LOG_ERROR("not enough memory"); + retval = ERROR_FAIL; + goto err; + } + + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * (stmqspi_info->dev.sectorsize << dual); + sectors[sector].size = (stmqspi_info->dev.sectorsize << dual); + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + stmqspi_info->probed = true; + +err: + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int stmqspi_auto_probe(struct flash_bank *bank) +{ + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + + if (stmqspi_info->probed) + return ERROR_OK; + stmqspi_probe(bank); + return ERROR_OK; +} + +static int stmqspi_protect_check(struct flash_bank *bank) +{ + /* Nothing to do. Protection is only handled in SW. */ + return ERROR_OK; +} + +static int get_stmqspi_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + + if (!(stmqspi_info->probed)) { + command_print_sameline(cmd, "\nQSPI flash bank not probed yet\n"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + command_print_sameline(cmd, "flash%s%s \'%s\', device id = 0x%06" PRIx32 + ", 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 " %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 ? "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 ? "Ki" : "", + stmqspi_info->dev.erase_cmd); + + return ERROR_OK; +} + +static const struct command_registration stmqspi_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = stmqspi_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Mass erase entire flash device.", + }, + { + .name = "set", + .handler = stmqspi_handle_set, + .mode = COMMAND_EXEC, + .usage = "bank_id name chip_size page_size read_cmd qread_cmd pprg_cmd " + "[ mass_erase_cmd ] [ sector_size sector_erase_cmd ]", + .help = "Set params of single flash chip", + }, + { + .name = "cmd", + .handler = stmqspi_handle_cmd, + .mode = COMMAND_EXEC, + .usage = "bank_id num_resp cmd_byte ...", + .help = "Send low-level command cmd_byte and following bytes or read num_resp.", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration stmqspi_command_handlers[] = { + { + .name = "stmqspi", + .mode = COMMAND_ANY, + .help = "stmqspi flash command group", + .usage = "", + .chain = stmqspi_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +const struct flash_driver stmqspi_flash = { + .name = "stmqspi", + .commands = stmqspi_command_handlers, + .flash_bank_command = stmqspi_flash_bank_command, + .erase = stmqspi_erase, + .protect = stmqspi_protect, + .write = stmqspi_write, + .read = stmqspi_read, + .verify = stmqspi_verify, + .probe = stmqspi_probe, + .auto_probe = stmqspi_auto_probe, + .erase_check = stmqspi_blank_check, + .protect_check = stmqspi_protect_check, + .info = get_stmqspi_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/stmqspi.h b/src/flash/nor/stmqspi.h new file mode 100644 index 0000000000..245df40b38 --- /dev/null +++ b/src/flash/nor/stmqspi.h @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2016 - 2018 by Andreas Bolsch * + * andreas.bolsch@mni.thm.de * + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_STMQSPI_H +#define OPENOCD_FLASH_NOR_STMQSPI_H + +#include "spi.h" + +/* QSPI register offsets */ +#define QSPI_CR (0x00) /* Control register */ +#define QSPI_DCR (0x04) /* Device configuration register */ +#define QSPI_SR (0x08) /* Status register */ +#define QSPI_FCR (0x0C) /* Flag clear register */ +#define QSPI_DLR (0x10) /* Data length register */ +#define QSPI_CCR (0x14) /* Communication configuration register */ +#define QSPI_AR (0x18) /* Address register */ +#define QSPI_ABR (0x1C) /* Alternate bytes register */ +#define QSPI_DR (0x20) /* Data register */ + +/* common bits in QSPI_CR and OCTOSPI_CR */ +#define SPI_FSEL_FLASH 7 /* Select flash 2 */ +#define SPI_DUAL_FLASH 6 /* Dual flash mode */ +#define SPI_ABORT 1 /* Abort bit */ + +/* common bits in QSPI_DCR and OCTOSPI_DCR1 */ +#define SPI_FSIZE_POS 16 /* bit position of FSIZE */ +#define SPI_FSIZE_LEN 5 /* width of FSIZE field */ + +/* common bits in QSPI_SR/FCR and OCTOSPI_SR/FCR */ +#define SPI_BUSY 5 /* Busy flag */ +#define SPI_FTF 2 /* FIFO threshold flag */ +#define SPI_TCF 1 /* Transfer complete flag */ + +/* fields in QSPI_CCR */ +#define QSPI_DDRM 31 /* position of DDRM bit */ +#define SPI_DMODE_POS 24 /* bit position of DMODE */ +#define QSPI_DCYC_POS 18 /* bit position of DCYC */ +#define QSPI_DCYC_LEN 5 /* width of DCYC field */ +#define QSPI_DCYC_MASK ((BIT(QSPI_DCYC_LEN) - 1) << QSPI_DCYC_POS) +#define SPI_ADSIZE_POS 12 /* bit position of ADSIZE */ + +#define QSPI_WRITE_MODE 0x00000000U /* indirect write mode */ +#define QSPI_READ_MODE 0x04000000U /* indirect read mode */ +#define QSPI_MM_MODE 0x0C000000U /* memory mapped mode */ +#define QSPI_ALTB_MODE 0x0003C000U /* alternate byte mode */ +#define QSPI_4LINE_MODE 0x03000F00U /* 4 lines for data, addr, instr */ +#define QSPI_NO_DATA (~0x03000000U) /* no data */ +#define QSPI_NO_ALTB (~QSPI_ALTB_MODE) /* no alternate */ +#define QSPI_NO_ADDR (~0x00000C00U) /* no address */ +#define QSPI_ADDR3 (0x2U << SPI_ADSIZE_POS) /* 3 byte address */ +#define QSPI_ADDR4 (0x3U << SPI_ADSIZE_POS) /* 4 byte address */ + +/* OCTOSPI register offsets */ +#define OCTOSPI_CR (0x000) /* Control register */ +#define OCTOSPI_DCR1 (0x008) /* Device configuration register 1 */ +#define OCTOSPI_DCR2 (0x00C) /* Device configuration register 2 */ +#define OCTOSPI_DCR3 (0x010) /* Device configuration register 3 */ +#define OCTOSPI_SR (0x020) /* Status register */ +#define OCTOSPI_FCR (0x024) /* Flag clear register */ +#define OCTOSPI_DLR (0x040) /* Data length register */ +#define OCTOSPI_AR (0x048) /* Address register */ +#define OCTOSPI_DR (0x050) /* Data register */ +#define OCTOSPI_CCR (0x100) /* Communication configuration register */ +#define OCTOSPI_TCR (0x108) /* Timing configuration register */ +#define OCTOSPI_IR (0x110) /* Instruction register */ +#define OCTOSPI_WCCR (0x180) /* Write communication configuration register */ +#define OCTOSPI_WIR (0x190) /* Write instruction register */ +#define OCTOSPI_MAGIC (0x3FC) /* Magic ID register, deleted from RM, why? */ + +#define OCTO_MAGIC_ID 0xA3C5DD01 /* Magic ID, deleted from RM, why? */ + +/* additional bits in OCTOSPI_CR */ +#define OCTOSPI_WRITE_MODE 0x00000000U /* indirect write mode */ +#define OCTOSPI_READ_MODE 0x10000000U /* indirect read mode */ +#define OCTOSPI_MM_MODE 0x30000000U /* memory mapped mode */ + +/* additional fields in OCTOSPI_DCR1 */ +#define OCTOSPI_MTYP_POS (24) /* bit position of MTYP */ +#define OCTOSPI_MTYP_LEN (3) /* width of MTYP field */ +#define OCTOSPI_MTYP_MASK ((BIT(OCTOSPI_MTYP_LEN) - 1) << OCTOSPI_MTYP_POS) + +/* fields in OCTOSPI_CCR */ +#define OCTOSPI_ALTB_MODE 0x001F0000U /* alternate byte mode */ +#define OCTOSPI_8LINE_MODE 0x0F003F3FU /* 8 lines DTR for data, addr, instr */ +#define OCTOSPI_NO_DATA (~0x0F000000U) /* no data */ +#define OCTOSPI_NO_ALTB (~OCTOSPI_ALTB_MODE) /* no alternate */ +#define OCTOSPI_NO_ADDR (~0x00000F00U) /* no address */ +#define OCTOSPI_ADDR3 (0x2U << SPI_ADSIZE_POS) /* 3 byte address */ +#define OCTOSPI_ADDR4 (0x3U << SPI_ADSIZE_POS) /* 4 byte address */ +#define OCTOSPI_DQSEN 29 /* DQS enable */ +#define OCTOSPI_DDTR 27 /* DTR for data */ +#define OCTOSPI_NO_DDTR (~BIT(OCTOSPI_DDTR)) /* no DTR for data, but maybe still DQS */ +#define OCTOSPI_ISIZE_MASK (0x30) /* ISIZE field */ + +/* fields in OCTOSPI_TCR */ +#define OCTOSPI_DCYC_POS 0 /* bit position of DCYC */ +#define OCTOSPI_DCYC_LEN 5 /* width of DCYC field */ +#define OCTOSPI_DCYC_MASK ((BIT(OCTOSPI_DCYC_LEN) - 1) << OCTOSPI_DCYC_POS) + +#define IS_OCTOSPI (stmqspi_info->octo) +#define SPI_CR (IS_OCTOSPI ? OCTOSPI_CR : QSPI_CR) +#define SPI_DCR (IS_OCTOSPI ? OCTOSPI_DCR1 : QSPI_DCR) +#define SPI_SR (IS_OCTOSPI ? OCTOSPI_SR : QSPI_SR) +#define SPI_FCR (IS_OCTOSPI ? OCTOSPI_FCR : QSPI_FCR) +#define SPI_DLR (IS_OCTOSPI ? OCTOSPI_DLR : QSPI_DLR) +#define SPI_AR (IS_OCTOSPI ? OCTOSPI_AR : QSPI_AR) +#define SPI_DR (IS_OCTOSPI ? OCTOSPI_DR : QSPI_DR) +#define SPI_CCR (IS_OCTOSPI ? OCTOSPI_CCR : QSPI_CCR) + +#endif /* OPENOCD_FLASH_NOR_STMQSPI_H */ diff --git a/src/flash/nor/stmsmi.c b/src/flash/nor/stmsmi.c index 278c73e7fa..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 @@ -41,34 +30,33 @@ #include <jtag/jtag.h> #include <helper/time_support.h> -#define SMI_READ_REG(a) (_SMI_READ_REG(a)) -#define _SMI_READ_REG(a) \ -{ \ - int __a; \ - uint32_t __v; \ +#define SMI_READ_REG(a) \ +({ \ + int _ret; \ + uint32_t _value; \ \ - __a = target_read_u32(target, io_base + (a), &__v); \ - if (__a != ERROR_OK) \ - return __a; \ - __v; \ -} + _ret = target_read_u32(target, io_base + (a), &_value); \ + if (_ret != ERROR_OK) \ + return _ret; \ + _value; \ +}) #define SMI_WRITE_REG(a, v) \ { \ - int __r; \ + int _retval; \ \ - __r = target_write_u32(target, io_base + (a), (v)); \ - if (__r != ERROR_OK) \ - return __r; \ + _retval = target_write_u32(target, io_base + (a), (v)); \ + if (_retval != ERROR_OK) \ + return _retval; \ } #define SMI_POLL_TFF(timeout) \ { \ - int __r; \ + int _retval; \ \ - __r = poll_tff(target, io_base, timeout); \ - if (__r != ERROR_OK) \ - return __r; \ + _retval = poll_tff(target, io_base, timeout); \ + if (_retval != ERROR_OK) \ + return _retval; \ } #define SMI_SET_SW_MODE() SMI_WRITE_REG(SMI_CR1, \ @@ -145,7 +133,7 @@ FLASH_BANK_COMMAND_HANDLER(stmsmi_flash_bank_command) return ERROR_COMMAND_SYNTAX_ERROR; stmsmi_info = malloc(sizeof(struct stmsmi_flash_bank)); - if (stmsmi_info == NULL) { + if (!stmsmi_info) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } @@ -601,7 +589,7 @@ static int stmsmi_probe(struct flash_bank *bank) bank->num_sectors = stmsmi_info->dev->size_in_bytes / sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); - if (sectors == NULL) { + if (!sectors) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } @@ -632,17 +620,16 @@ static int stmsmi_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int get_stmsmi_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_stmsmi_info(struct flash_bank *bank, struct command_invocation *cmd) { struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; if (!(stmsmi_info->probed)) { - snprintf(buf, buf_size, - "\nSMI flash bank not probed yet\n"); + command_print_sameline(cmd, "\nSMI flash bank not probed yet\n"); return ERROR_OK; } - snprintf(buf, buf_size, "\nSMI flash information:\n" + command_print_sameline(cmd, "\nSMI flash information:\n" " Device \'%s\' (ID 0x%08" PRIx32 ")\n", stmsmi_info->dev->name, stmsmi_info->dev->device_id); diff --git a/src/flash/nor/str7x.c b/src/flash/nor/str7x.c index e028c1ffd1..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 @@ -376,9 +365,6 @@ static int str7x_erase(struct flash_bank *bank, unsigned int first, if (err != ERROR_OK) return err; - for (unsigned int i = first; i <= last; i++) - bank->sectors[i].is_erased = 1; - return ERROR_OK; } @@ -702,13 +688,13 @@ COMMAND_HANDLER(str7x_handle_part_id_command) } #endif -static int get_str7x_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_str7x_info(struct flash_bank *bank, struct command_invocation *cmd) { /* Setting the write protection on a sector is a permanent change but it * can be disabled temporarily. FLASH_NVWPAR reflects the permanent * protection state of the sectors, not the temporary. */ - snprintf(buf, buf_size, "STR7x flash protection info is only valid after a power cycle, " + command_print_sameline(cmd, "STR7x flash protection info is only valid after a power cycle, " "clearing the protection is only temporary and may not be reflected in the current " "info returned."); return ERROR_OK; @@ -720,15 +706,15 @@ COMMAND_HANDLER(str7x_handle_disable_jtag_command) struct str7x_flash_bank *str7x_info = NULL; uint32_t flash_cmd; - uint16_t ProtectionLevel = 0; - uint16_t ProtectionRegs; + uint16_t protection_level = 0; + uint16_t protection_regs; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; str7x_info = bank->driver_priv; @@ -745,17 +731,17 @@ COMMAND_HANDLER(str7x_handle_disable_jtag_command) target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), ®); if (!(reg & str7x_info->disable_bit)) - ProtectionLevel = 1; + protection_level = 1; target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), ®); - ProtectionRegs = ~(reg >> 16); + protection_regs = ~(reg >> 16); - while (((ProtectionRegs) != 0) && (ProtectionLevel < 16)) { - ProtectionRegs >>= 1; - ProtectionLevel++; + while (((protection_regs) != 0) && (protection_level < 16)) { + protection_regs >>= 1; + protection_level++; } - if (ProtectionLevel == 0) { + if (protection_level == 0) { flash_cmd = FLASH_SPR; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd); target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFB8); @@ -767,7 +753,7 @@ COMMAND_HANDLER(str7x_handle_disable_jtag_command) target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd); target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC); target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), - ~(1 << (15 + ProtectionLevel))); + ~(1 << (15 + protection_level))); flash_cmd = FLASH_SPR | FLASH_WMS; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd); } diff --git a/src/flash/nor/str9x.c b/src/flash/nor/str9x.c index 87ffec8777..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 @@ -300,9 +289,6 @@ static int str9x_erase(struct flash_bank *bank, unsigned int first, break; } - for (unsigned int i = first; i <= last; i++) - bank->sectors[i].is_erased = 1; - return ERROR_OK; } @@ -611,7 +597,7 @@ COMMAND_HANDLER(str9x_handle_flash_config_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; uint32_t bbsr, nbbsr, bbadr, nbbadr; diff --git a/src/flash/nor/str9xpec.c b/src/flash/nor/str9xpec.c index 9946b06fb2..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 @@ -81,7 +70,7 @@ static int str9xpec_write_options(struct flash_bank *bank); static int str9xpec_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_state_t end_state) { - if (tap == NULL) + if (!tap) return ERROR_TARGET_INVALID; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { @@ -727,7 +716,7 @@ COMMAND_HANDLER(str9xpec_handle_part_id_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; @@ -768,7 +757,7 @@ COMMAND_HANDLER(str9xpec_handle_flash_options_read_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; @@ -877,7 +866,7 @@ COMMAND_HANDLER(str9xpec_handle_flash_options_write_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; status = str9xpec_write_options(bank); @@ -901,7 +890,7 @@ COMMAND_HANDLER(str9xpec_handle_flash_options_cmap_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; @@ -923,7 +912,7 @@ COMMAND_HANDLER(str9xpec_handle_flash_options_lvdthd_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; @@ -945,7 +934,7 @@ COMMAND_HANDLER(str9xpec_handle_flash_options_lvdsel_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; @@ -967,7 +956,7 @@ COMMAND_HANDLER(str9xpec_handle_flash_options_lvdwarn_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; @@ -989,7 +978,7 @@ COMMAND_HANDLER(str9xpec_handle_flash_lock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; status = str9xpec_lock_device(bank); @@ -1009,7 +998,7 @@ COMMAND_HANDLER(str9xpec_handle_flash_unlock_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; status = str9xpec_unlock_device(bank); @@ -1036,26 +1025,26 @@ COMMAND_HANDLER(str9xpec_handle_flash_enable_turbo_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; /* remove arm core from chain - enter turbo mode */ tap0 = str9xpec_info->tap; - if (tap0 == NULL) { + if (!tap0) { /* things are *WRONG* */ command_print(CMD, "**STR9FLASH** (tap0) invalid chain?"); return ERROR_FAIL; } tap1 = tap0->next_tap; - if (tap1 == NULL) { + if (!tap1) { /* things are *WRONG* */ command_print(CMD, "**STR9FLASH** (tap1) invalid chain?"); return ERROR_FAIL; } tap2 = tap1->next_tap; - if (tap2 == NULL) { + if (!tap2) { /* things are *WRONG* */ command_print(CMD, "**STR9FLASH** (tap2) invalid chain?"); return ERROR_FAIL; @@ -1083,13 +1072,13 @@ COMMAND_HANDLER(str9xpec_handle_flash_disable_turbo_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; - if (tap == NULL) + if (!tap) return ERROR_FAIL; /* exit turbo mode via RESET */ diff --git a/src/flash/nor/swm050.c b/src/flash/nor/swm050.c index 98361eb91d..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 @@ -142,7 +131,7 @@ COMMAND_HANDLER(swm050_handle_mass_erase_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = swm050_mass_erase(bank); @@ -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 e935b3b4af..720fb60a1b 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. */ -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 @@ 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); } @@ -88,8 +77,7 @@ COMMAND_HANDLER(handle_flash_info_command) if (retval != ERROR_OK) return retval; - if (p != NULL) { - char buf[1024]; + if (p) { int num_blocks; struct flash_sector *block_array; @@ -100,7 +88,7 @@ COMMAND_HANDLER(handle_flash_info_command) /* If the driver does not implement protection, we show the default * state of is_protected array - usually protection state unknown */ - if (p->driver->protect_check == NULL) { + if (!p->driver->protect_check) { retval = ERROR_FLASH_OPER_UNSUPPORTED; } else { /* We must query the hardware to avoid printing stale information! */ @@ -149,11 +137,11 @@ COMMAND_HANDLER(handle_flash_info_command) protect_state); } - if (p->driver->info != NULL) { - retval = p->driver->info(p, buf, sizeof(buf)); - if (retval == ERROR_OK) - command_print(CMD, "%s", buf); - else + if (p->driver->info) { + /* Let the flash driver print extra custom info */ + retval = p->driver->info(p, CMD); + command_print_sameline(CMD, "\n"); + if (retval != ERROR_OK) LOG_ERROR("error retrieving flash info"); } } @@ -169,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; @@ -196,7 +184,7 @@ COMMAND_HANDLER(handle_flash_erase_check_command) struct flash_bank *p; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = p->driver->erase_check(p); @@ -287,7 +275,7 @@ COMMAND_HANDLER(handle_flash_erase_address_command) if (retval == ERROR_OK) retval = flash_erase_address_range(target, do_pad, address, length); - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { + if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "erased address " TARGET_ADDR_FMT " (length %" PRIu32 ")" " in %fs (%0.3f KiB/s)", address, length, duration_elapsed(&bench), duration_kbps(&bench, length)); @@ -335,7 +323,7 @@ COMMAND_HANDLER(handle_flash_erase_command) retval = flash_driver_erase(p, first, last); - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { + if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "erased sectors %" PRIu32 " " "through %" PRIu32 " on flash bank %u " "in %fs", first, last, p->bank_number, duration_elapsed(&bench)); @@ -441,26 +429,27 @@ COMMAND_HANDLER(handle_flash_write_image_command) duration_start(&bench); if (CMD_ARGC >= 2) { - image.base_address_set = 1; + image.base_address_set = true; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address); } else { - image.base_address_set = 0; + image.base_address_set = false; image.base_address = 0x0; } - image.start_address_set = 0; + image.start_address_set = false; retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) return retval; - retval = flash_write_unlock(target, &image, &written, auto_erase, auto_unlock); + retval = flash_write_unlock_verify(target, &image, &written, auto_erase, + auto_unlock, true, false); if (retval != ERROR_OK) { image_close(&image); return retval; } - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { + if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "wrote %" PRIu32 " bytes from file %s " "in %fs (%0.3f KiB/s)", written, CMD_ARGV[0], duration_elapsed(&bench), duration_kbps(&bench, written)); @@ -471,6 +460,58 @@ COMMAND_HANDLER(handle_flash_write_image_command) return retval; } +COMMAND_HANDLER(handle_flash_verify_image_command) +{ + struct target *target = get_current_target(CMD_CTX); + + struct image image; + uint32_t verified; + + int retval; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!target) { + LOG_ERROR("no target selected"); + return ERROR_FAIL; + } + + struct duration bench; + duration_start(&bench); + + if (CMD_ARGC >= 2) { + image.base_address_set = 1; + COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address); + } else { + image.base_address_set = 0; + image.base_address = 0x0; + } + + image.start_address_set = 0; + + retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); + if (retval != ERROR_OK) + return retval; + + retval = flash_write_unlock_verify(target, &image, &verified, false, + false, false, true); + if (retval != ERROR_OK) { + image_close(&image); + return retval; + } + + if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { + command_print(CMD, "verified %" PRIu32 " bytes from file %s " + "in %fs (%0.3f KiB/s)", verified, CMD_ARGV[0], + duration_elapsed(&bench), duration_kbps(&bench, verified)); + } + + image_close(&image); + + return retval; +} + COMMAND_HANDLER(handle_flash_fill_command) { target_addr_t address; @@ -532,7 +573,7 @@ COMMAND_HANDLER(handle_flash_fill_command) uint32_t padding_at_end = aligned_end - end_addr; uint8_t *buffer = malloc(aligned_size); - if (buffer == NULL) + if (!buffer) return ERROR_FAIL; if (padding_at_start) { @@ -672,7 +713,7 @@ COMMAND_HANDLER(handle_flash_md_command) } uint8_t *buffer = calloc(count, wordsize); - if (buffer == NULL) { + if (!buffer) { command_print(CMD, "No memory for flash read buffer"); return ERROR_FAIL; } @@ -702,7 +743,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command) struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; offset = 0; @@ -747,7 +788,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command) uint32_t padding_at_end = aligned_end - end_addr; buffer = malloc(aligned_size); - if (buffer == NULL) { + if (!buffer) { fileio_close(fileio); LOG_ERROR("Out of memory"); return ERROR_FAIL; @@ -773,6 +814,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command) if (buf_cnt != length) { LOG_ERROR("Short read"); free(buffer); + fileio_close(fileio); return ERROR_FAIL; } @@ -789,7 +831,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command) free(buffer); - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { + if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "wrote %zu bytes from file %s to flash bank %u" " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", length, CMD_ARGV[1], bank->bank_number, offset, @@ -818,7 +860,7 @@ COMMAND_HANDLER(handle_flash_read_bank_command) struct flash_bank *p; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; offset = 0; @@ -844,7 +886,7 @@ COMMAND_HANDLER(handle_flash_read_bank_command) } buffer = malloc(length); - if (buffer == NULL) { + if (!buffer) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -899,7 +941,7 @@ COMMAND_HANDLER(handle_flash_verify_bank_command) struct flash_bank *p; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; offset = 0; @@ -938,7 +980,7 @@ COMMAND_HANDLER(handle_flash_verify_bank_command) "first %zu bytes of the file", length); buffer_file = malloc(length); - if (buffer_file == NULL) { + if (!buffer_file) { LOG_ERROR("Out of memory"); fileio_close(fileio); return ERROR_FAIL; @@ -959,7 +1001,7 @@ COMMAND_HANDLER(handle_flash_verify_bank_command) } buffer_flash = malloc(length); - if (buffer_flash == NULL) { + if (!buffer_flash) { LOG_ERROR("Out of memory"); free(buffer_file); return ERROR_FAIL; @@ -1020,7 +1062,7 @@ COMMAND_HANDLER(handle_flash_padded_value_command) struct flash_bank *p; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], p->default_padded_value); @@ -1142,7 +1184,15 @@ static const struct command_registration flash_exec_command_handlers[] = { .mode = COMMAND_EXEC, .usage = "[erase] [unlock] filename [offset [file_type]]", .help = "Write an image to flash. Optionally first unprotect " - "and/or erase the region to be used. Allow optional " + "and/or erase the region to be used. Allow optional " + "offset from beginning of bank (defaults to zero)", + }, + { + .name = "verify_image", + .handler = handle_flash_verify_image_command, + .mode = COMMAND_EXEC, + .usage = "filename [offset [file_type]]", + .help = "Verify an image against flash. Allow optional " "offset from beginning of bank (defaults to zero)", }, { @@ -1187,8 +1237,7 @@ static int flash_init_drivers(struct command_context *cmd_ctx) if (!flash_bank_list()) return ERROR_OK; - struct command *parent = command_find_in_context(cmd_ctx, "flash"); - return register_commands(cmd_ctx, parent, flash_exec_command_handlers); + return register_commands(cmd_ctx, "flash", flash_exec_command_handlers); } COMMAND_HANDLER(handle_flash_bank_command) @@ -1203,31 +1252,30 @@ COMMAND_HANDLER(handle_flash_bank_command) CMD_ARGC--; struct target *target = get_target(CMD_ARGV[5]); - if (target == NULL) { + if (!target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[5]); return ERROR_FAIL; } const char *driver_name = CMD_ARGV[0]; const struct flash_driver *driver = flash_driver_find_by_name(driver_name); - if (NULL == driver) { + if (!driver) { /* no matching flash driver found */ LOG_ERROR("flash driver '%s' not found", driver_name); return ERROR_FAIL; } /* check the flash bank name is unique */ - if (get_flash_bank_by_name_noprobe(bank_name) != NULL) { + if (get_flash_bank_by_name_noprobe(bank_name)) { /* flash bank name already exists */ LOG_ERROR("flash bank name '%s' already exists", bank_name); return ERROR_FAIL; } /* register flash specific commands */ - if (NULL != driver->commands) { - int retval = register_commands(CMD_CTX, NULL, - driver->commands); - if (ERROR_OK != retval) { + if (driver->commands) { + int retval = register_commands(CMD_CTX, NULL, driver->commands); + if (retval != ERROR_OK) { LOG_ERROR("couldn't register '%s' commands", driver_name); return ERROR_FAIL; @@ -1247,14 +1295,14 @@ COMMAND_HANDLER(handle_flash_bank_command) int retval; retval = CALL_COMMAND_HANDLER(driver->flash_bank_command, c); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("'%s' driver rejected flash bank at " TARGET_ADDR_FMT "; usage: %s", driver_name, c->base, driver->usage); free(c); return retval; } - if (driver->usage == NULL) + if (!driver->usage) LOG_DEBUG("'%s' driver usage field missing", driver_name); flash_bank_add(c); @@ -1277,36 +1325,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->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, 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) @@ -1353,8 +1392,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 3004682b8e..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 @@ -39,7 +28,7 @@ struct tms470_flash_bank { }; -static const struct flash_sector TMS470R1A256_SECTORS[] = { +static const struct flash_sector tms470r1a256_sectors[] = { {0x00000000, 0x00002000, -1, -1}, {0x00002000, 0x00002000, -1, -1}, {0x00004000, 0x00002000, -1, -1}, @@ -57,9 +46,9 @@ static const struct flash_sector TMS470R1A256_SECTORS[] = { }; #define TMS470R1A256_NUM_SECTORS \ - ARRAY_SIZE(TMS470R1A256_SECTORS) + ARRAY_SIZE(tms470r1a256_sectors) -static const struct flash_sector TMS470R1A288_BANK0_SECTORS[] = { +static const struct flash_sector tms470r1a288_bank0_sectors[] = { {0x00000000, 0x00002000, -1, -1}, {0x00002000, 0x00002000, -1, -1}, {0x00004000, 0x00002000, -1, -1}, @@ -67,9 +56,9 @@ static const struct flash_sector TMS470R1A288_BANK0_SECTORS[] = { }; #define TMS470R1A288_BANK0_NUM_SECTORS \ - ARRAY_SIZE(TMS470R1A288_BANK0_SECTORS) + ARRAY_SIZE(tms470r1a288_bank0_sectors) -static const struct flash_sector TMS470R1A288_BANK1_SECTORS[] = { +static const struct flash_sector tms470r1a288_bank1_sectors[] = { {0x00040000, 0x00010000, -1, -1}, {0x00050000, 0x00010000, -1, -1}, {0x00060000, 0x00010000, -1, -1}, @@ -77,9 +66,9 @@ static const struct flash_sector TMS470R1A288_BANK1_SECTORS[] = { }; #define TMS470R1A288_BANK1_NUM_SECTORS \ - ARRAY_SIZE(TMS470R1A288_BANK1_SECTORS) + ARRAY_SIZE(tms470r1a288_bank1_sectors) -static const struct flash_sector TMS470R1A384_BANK0_SECTORS[] = { +static const struct flash_sector tms470r1a384_bank0_sectors[] = { {0x00000000, 0x00002000, -1, -1}, {0x00002000, 0x00002000, -1, -1}, {0x00004000, 0x00004000, -1, -1}, @@ -93,9 +82,9 @@ static const struct flash_sector TMS470R1A384_BANK0_SECTORS[] = { }; #define TMS470R1A384_BANK0_NUM_SECTORS \ - ARRAY_SIZE(TMS470R1A384_BANK0_SECTORS) + ARRAY_SIZE(tms470r1a384_bank0_sectors) -static const struct flash_sector TMS470R1A384_BANK1_SECTORS[] = { +static const struct flash_sector tms470r1a384_bank1_sectors[] = { {0x00020000, 0x00008000, -1, -1}, {0x00028000, 0x00008000, -1, -1}, {0x00030000, 0x00008000, -1, -1}, @@ -103,9 +92,9 @@ static const struct flash_sector TMS470R1A384_BANK1_SECTORS[] = { }; #define TMS470R1A384_BANK1_NUM_SECTORS \ - ARRAY_SIZE(TMS470R1A384_BANK1_SECTORS) + ARRAY_SIZE(tms470r1a384_bank1_sectors) -static const struct flash_sector TMS470R1A384_BANK2_SECTORS[] = { +static const struct flash_sector tms470r1a384_bank2_sectors[] = { {0x00040000, 0x00008000, -1, -1}, {0x00048000, 0x00008000, -1, -1}, {0x00050000, 0x00008000, -1, -1}, @@ -113,7 +102,7 @@ static const struct flash_sector TMS470R1A384_BANK2_SECTORS[] = { }; #define TMS470R1A384_BANK2_NUM_SECTORS \ - ARRAY_SIZE(TMS470R1A384_BANK2_SECTORS) + ARRAY_SIZE(tms470r1a384_bank2_sectors) /* ---------------------------------------------------------------------- */ @@ -173,10 +162,10 @@ static int tms470_read_part_info(struct flash_bank *bank) bank->base = 0x00000000; bank->size = 256 * 1024; bank->num_sectors = TMS470R1A256_NUM_SECTORS; - bank->sectors = malloc(sizeof(TMS470R1A256_SECTORS)); + bank->sectors = malloc(sizeof(tms470r1a256_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, TMS470R1A256_SECTORS, sizeof(TMS470R1A256_SECTORS)); + (void)memcpy(bank->sectors, tms470r1a256_sectors, sizeof(tms470r1a256_sectors)); break; case 0x2b: @@ -187,21 +176,21 @@ static int tms470_read_part_info(struct flash_bank *bank) bank->base = 0x00000000; bank->size = 32 * 1024; bank->num_sectors = TMS470R1A288_BANK0_NUM_SECTORS; - bank->sectors = malloc(sizeof(TMS470R1A288_BANK0_SECTORS)); + bank->sectors = malloc(sizeof(tms470r1a288_bank0_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, TMS470R1A288_BANK0_SECTORS, - sizeof(TMS470R1A288_BANK0_SECTORS)); + (void)memcpy(bank->sectors, tms470r1a288_bank0_sectors, + sizeof(tms470r1a288_bank0_sectors)); } else if ((bank->base >= 0x00040000) && (bank->base < 0x00080000)) { tms470_info->ordinal = 1; bank->base = 0x00040000; bank->size = 256 * 1024; bank->num_sectors = TMS470R1A288_BANK1_NUM_SECTORS; - bank->sectors = malloc(sizeof(TMS470R1A288_BANK1_SECTORS)); + bank->sectors = malloc(sizeof(tms470r1a288_bank1_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, TMS470R1A288_BANK1_SECTORS, - sizeof(TMS470R1A288_BANK1_SECTORS)); + (void)memcpy(bank->sectors, tms470r1a288_bank1_sectors, + sizeof(tms470r1a288_bank1_sectors)); } else { LOG_ERROR("No %s flash bank contains base address " TARGET_ADDR_FMT ".", part_name, bank->base); @@ -217,31 +206,31 @@ static int tms470_read_part_info(struct flash_bank *bank) bank->base = 0x00000000; bank->size = 128 * 1024; bank->num_sectors = TMS470R1A384_BANK0_NUM_SECTORS; - bank->sectors = malloc(sizeof(TMS470R1A384_BANK0_SECTORS)); + bank->sectors = malloc(sizeof(tms470r1a384_bank0_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, TMS470R1A384_BANK0_SECTORS, - sizeof(TMS470R1A384_BANK0_SECTORS)); + (void)memcpy(bank->sectors, tms470r1a384_bank0_sectors, + sizeof(tms470r1a384_bank0_sectors)); } else if ((bank->base >= 0x00020000) && (bank->base < 0x00040000)) { tms470_info->ordinal = 1; bank->base = 0x00020000; bank->size = 128 * 1024; bank->num_sectors = TMS470R1A384_BANK1_NUM_SECTORS; - bank->sectors = malloc(sizeof(TMS470R1A384_BANK1_SECTORS)); + bank->sectors = malloc(sizeof(tms470r1a384_bank1_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, TMS470R1A384_BANK1_SECTORS, - sizeof(TMS470R1A384_BANK1_SECTORS)); + (void)memcpy(bank->sectors, tms470r1a384_bank1_sectors, + sizeof(tms470r1a384_bank1_sectors)); } else if ((bank->base >= 0x00040000) && (bank->base < 0x00060000)) { tms470_info->ordinal = 2; bank->base = 0x00040000; bank->size = 128 * 1024; bank->num_sectors = TMS470R1A384_BANK2_NUM_SECTORS; - bank->sectors = malloc(sizeof(TMS470R1A384_BANK2_SECTORS)); + bank->sectors = malloc(sizeof(tms470r1a384_bank2_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, TMS470R1A384_BANK2_SECTORS, - sizeof(TMS470R1A384_BANK2_SECTORS)); + (void)memcpy(bank->sectors, tms470r1a384_bank2_sectors, + sizeof(tms470r1a384_bank2_sectors)); } else { LOG_ERROR("No %s flash bank contains base address " TARGET_ADDR_FMT ".", part_name, bank->base); @@ -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), @@ -285,8 +271,8 @@ static int tms470_read_part_info(struct flash_bank *bank) /* ---------------------------------------------------------------------- */ -static uint32_t keysSet; -static uint32_t flashKeys[4]; +static uint32_t keys_set; +static uint32_t flash_keys[4]; COMMAND_HANDLER(tms470_handle_flash_keyset_command) { @@ -296,9 +282,9 @@ COMMAND_HANDLER(tms470_handle_flash_keyset_command) int i; for (i = 0; i < 4; i++) { - int start = (0 == strncmp(CMD_ARGV[i], "0x", 2)) ? 2 : 0; + int start = (strncmp(CMD_ARGV[i], "0x", 2) == 0) ? 2 : 0; - if (1 != sscanf(&CMD_ARGV[i][start], "%" SCNx32 "", &flashKeys[i])) { + if (sscanf(&CMD_ARGV[i][start], "%" SCNx32 "", &flash_keys[i]) != 1) { command_print(CMD, "could not process flash key %s", CMD_ARGV[i]); LOG_ERROR("could not process flash key %s", CMD_ARGV[i]); @@ -306,56 +292,56 @@ COMMAND_HANDLER(tms470_handle_flash_keyset_command) } } - keysSet = 1; + keys_set = 1; } else if (CMD_ARGC != 0) { command_print(CMD, "tms470 flash_keyset <key0> <key1> <key2> <key3>"); return ERROR_COMMAND_SYNTAX_ERROR; } - if (keysSet) { + if (keys_set) { command_print(CMD, "using flash keys 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 "", - flashKeys[0], - flashKeys[1], - flashKeys[2], - flashKeys[3]); + flash_keys[0], + flash_keys[1], + flash_keys[2], + flash_keys[3]); } else command_print(CMD, "flash keys not set"); return ERROR_OK; } -static const uint32_t FLASH_KEYS_ALL_ONES[] = { 0xFFFFFFFF, 0xFFFFFFFF, +static const uint32_t flash_keys_all_ones[] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,}; -static const uint32_t FLASH_KEYS_ALL_ZEROS[] = { 0x00000000, 0x00000000, +static const uint32_t flash_keys_all_zeros[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,}; -static const uint32_t FLASH_KEYS_MIX1[] = { 0xf0fff0ff, 0xf0fff0ff, +static const uint32_t flash_keys_mix1[] = { 0xf0fff0ff, 0xf0fff0ff, 0xf0fff0ff, 0xf0fff0ff}; -static const uint32_t FLASH_KEYS_MIX2[] = { 0x0000ffff, 0x0000ffff, +static const uint32_t flash_keys_mix2[] = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}; /* ---------------------------------------------------------------------- */ -static int oscMHz = 12; +static int osc_mhz = 12; COMMAND_HANDLER(tms470_handle_osc_megahertz_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; else if (CMD_ARGC == 1) - sscanf(CMD_ARGV[0], "%d", &oscMHz); + sscanf(CMD_ARGV[0], "%d", &osc_mhz); - if (oscMHz <= 0) { + if (osc_mhz <= 0) { LOG_ERROR("osc_megahertz must be positive and non-zero!"); command_print(CMD, "osc_megahertz must be positive and non-zero!"); - oscMHz = 12; + osc_mhz = 12; return ERROR_COMMAND_SYNTAX_ERROR; } - command_print(CMD, "osc_megahertz=%d", oscMHz); + command_print(CMD, "osc_megahertz=%d", osc_mhz); return ERROR_OK; } @@ -437,7 +423,7 @@ static int tms470_try_flash_keys(struct target *target, const uint32_t *key_set) target_write_u32(target, 0xFFE89C0C, key_set[i]); } - if (ERROR_OK == tms470_check_flash_unlocked(target)) { + if (tms470_check_flash_unlocked(target) == ERROR_OK) { /* * There seems to be a side-effect of reading the FMPKEY * register in that it re-enables the protection. So we @@ -471,19 +457,19 @@ static int tms470_unlock_flash(struct flash_bank *bank) const uint32_t *p_key_sets[5]; unsigned i, key_set_count; - if (keysSet) { + if (keys_set) { key_set_count = 5; - p_key_sets[0] = flashKeys; - p_key_sets[1] = FLASH_KEYS_ALL_ONES; - p_key_sets[2] = FLASH_KEYS_ALL_ZEROS; - p_key_sets[3] = FLASH_KEYS_MIX1; - p_key_sets[4] = FLASH_KEYS_MIX2; + p_key_sets[0] = flash_keys; + p_key_sets[1] = flash_keys_all_ones; + p_key_sets[2] = flash_keys_all_zeros; + p_key_sets[3] = flash_keys_mix1; + p_key_sets[4] = flash_keys_mix2; } else { key_set_count = 4; - p_key_sets[0] = FLASH_KEYS_ALL_ONES; - p_key_sets[1] = FLASH_KEYS_ALL_ZEROS; - p_key_sets[2] = FLASH_KEYS_MIX1; - p_key_sets[3] = FLASH_KEYS_MIX2; + p_key_sets[0] = flash_keys_all_ones; + p_key_sets[1] = flash_keys_all_zeros; + p_key_sets[2] = flash_keys_mix1; + p_key_sets[3] = flash_keys_mix2; } for (i = 0; i < key_set_count; i++) { @@ -573,7 +559,7 @@ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *ban * the plldis global. */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); - sysclk = (plldis ? 1 : (glbctrl & 0x08) ? 4 : 8) * oscMHz / (1 + (glbctrl & 7)); + sysclk = (plldis ? 1 : (glbctrl & 0x08) ? 4 : 8) * osc_mhz / (1 + (glbctrl & 7)); delay = (sysclk > 10) ? (sysclk + 1) / 2 : 5; target_write_u32(target, 0xFFE8A018, (delay << 4) | (delay << 8)); LOG_DEBUG("set fmpsetup = 0x%04" PRIx32 "", (delay << 4) | (delay << 8)); @@ -685,7 +671,7 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector) { uint32_t glbctrl, orig_fmregopt, fmbsea, fmbseb, fmmstat; struct target *target = bank->target; - uint32_t flashAddr = bank->base + bank->sectors[sector].offset; + uint32_t flash_addr = bank->base + bank->sectors[sector].offset; int result = ERROR_OK; /* @@ -722,12 +708,12 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector) /* * clear status register, sent erase command, kickoff erase */ - target_write_u16(target, flashAddr, 0x0040); - LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0040", flashAddr); - target_write_u16(target, flashAddr, 0x0020); - LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0020", flashAddr); - target_write_u16(target, flashAddr, 0xffff); - LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0xffff", flashAddr); + target_write_u16(target, flash_addr, 0x0040); + LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0040", flash_addr); + target_write_u16(target, flash_addr, 0x0020); + LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0020", flash_addr); + target_write_u16(target, flash_addr, 0xffff); + LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0xffff", flash_addr); /* * Monitor FMMSTAT, busy until clear, then check and other flags for @@ -1118,26 +1104,20 @@ static int tms470_protect_check(struct flash_bank *bank) /* ---------------------------------------------------------------------- */ -static int get_tms470_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_tms470_info(struct flash_bank *bank, struct command_invocation *cmd) { - int used = 0; struct tms470_flash_bank *tms470_info = bank->driver_priv; if (!tms470_info->device_ident_reg) tms470_read_part_info(bank); if (!tms470_info->device_ident_reg) { - (void)snprintf(buf, buf_size, "Cannot identify target as a TMS470\n"); + command_print_sameline(cmd, "Cannot identify target as a TMS470\n"); return ERROR_FLASH_OPERATION_FAILED; } - used = - snprintf(buf, buf_size, "\ntms470 information: Chip is %s\n", - tms470_info->part_name); - buf += used; - buf_size -= used; - - snprintf(buf, buf_size, "Flash protection level 2 is %s\n", + command_print_sameline(cmd, "\ntms470 information: Chip is %s\n", tms470_info->part_name); + command_print_sameline(cmd, "Flash protection level 2 is %s\n", tms470_check_flash_unlocked(bank->target) == ERROR_OK ? "disabled" : "enabled"); return ERROR_OK; diff --git a/src/flash/nor/virtual.c b/src/flash/nor/virtual.c index 1aa12fecdd..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 @@ -27,7 +16,7 @@ static struct flash_bank *virtual_get_master_bank(struct flash_bank *bank) struct flash_bank *master_bank; master_bank = get_flash_bank_by_name_noprobe(bank->driver_priv); - if (master_bank == NULL) + if (!master_bank) LOG_ERROR("master flash bank '%s' does not exist", (char *)bank->driver_priv); return master_bank; @@ -37,7 +26,7 @@ static void virtual_update_bank_info(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); - if (master_bank == NULL) + if (!master_bank) return; /* update the info we do not have */ @@ -64,7 +53,7 @@ FLASH_BANK_COMMAND_HANDLER(virtual_flash_bank_command) const char *bank_name = CMD_ARGV[6]; struct flash_bank *master_bank = get_flash_bank_by_name_noprobe(bank_name); - if (master_bank == NULL) { + if (!master_bank) { LOG_ERROR("master flash bank '%s' does not exist", bank_name); return ERROR_FLASH_OPERATION_FAILED; } @@ -80,7 +69,7 @@ static int virtual_protect(struct flash_bank *bank, int set, unsigned int first, { struct flash_bank *master_bank = virtual_get_master_bank(bank); - if (master_bank == NULL) + if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; return flash_driver_protect(master_bank, set, first, last); @@ -90,10 +79,10 @@ static int virtual_protect_check(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); - if (master_bank == NULL) + if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; - if (master_bank->driver->protect_check == NULL) + if (!master_bank->driver->protect_check) return ERROR_FLASH_OPER_UNSUPPORTED; /* call master handler */ @@ -106,7 +95,7 @@ static int virtual_erase(struct flash_bank *bank, unsigned int first, struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; - if (master_bank == NULL) + if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ @@ -123,7 +112,7 @@ static int virtual_write(struct flash_bank *bank, const uint8_t *buffer, struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; - if (master_bank == NULL) + if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ @@ -139,7 +128,7 @@ static int virtual_probe(struct flash_bank *bank) struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; - if (master_bank == NULL) + if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ @@ -158,7 +147,7 @@ static int virtual_auto_probe(struct flash_bank *bank) struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; - if (master_bank == NULL) + if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ @@ -172,14 +161,14 @@ static int virtual_auto_probe(struct flash_bank *bank) return ERROR_OK; } -static int virtual_info(struct flash_bank *bank, char *buf, int buf_size) +static int virtual_info(struct flash_bank *bank, struct command_invocation *cmd) { struct flash_bank *master_bank = virtual_get_master_bank(bank); - if (master_bank == NULL) + if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; - snprintf(buf, buf_size, "%s driver for flash bank %s at " TARGET_ADDR_FMT, + command_print_sameline(cmd, "%s driver for flash bank %s at " TARGET_ADDR_FMT, bank->driver->name, master_bank->name, master_bank->base); return ERROR_OK; @@ -190,7 +179,7 @@ static int virtual_blank_check(struct flash_bank *bank) struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; - if (master_bank == NULL) + if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ @@ -207,7 +196,7 @@ static int virtual_flash_read(struct flash_bank *bank, struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; - if (master_bank == NULL) + if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ diff --git a/src/flash/nor/w600.c b/src/flash/nor/w600.c index 2506f2b550..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; @@ -362,7 +351,7 @@ static int w600_auto_probe(struct flash_bank *bank) return w600_probe(bank); } -static int get_w600_info(struct flash_bank *bank, char *buf, int buf_size) +static int get_w600_info(struct flash_bank *bank, struct command_invocation *cmd) { uint32_t flash_id; @@ -371,7 +360,7 @@ static int get_w600_info(struct flash_bank *bank, char *buf, int buf_size) if (retval != ERROR_OK) return retval; - snprintf(buf, buf_size, "w600 : 0x%08" PRIx32 "", flash_id); + command_print_sameline(cmd, "w600 : 0x%08" PRIx32 "", flash_id); return ERROR_OK; } diff --git a/src/flash/nor/xcf.c b/src/flash/nor/xcf.c index 29eef2dc33..1d67b09430 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 @@ -45,7 +34,7 @@ #define ID_XCF32P 0x05059093 #define ID_MEANINGFUL_MASK 0x0FFFFFFF -const char *xcf_name_list[] = { +static const char * const xcf_name_list[] = { "XCF08P", "XCF16P", "XCF32P", @@ -68,25 +57,25 @@ struct xcf_status { * GLOBAL VARIABLES ****************************************************************************** */ -static const uint8_t CMD_BYPASS[2] = {0xFF, 0xFF}; - -static const uint8_t CMD_ISC_ADDRESS_SHIFT[2] = {0xEB, 0x00}; -static const uint8_t CMD_ISC_DATA_SHIFT[2] = {0xED, 0x00}; -static const uint8_t CMD_ISC_DISABLE[2] = {0xF0, 0x00}; -static const uint8_t CMD_ISC_ENABLE[2] = {0xE8, 0x00}; -static const uint8_t CMD_ISC_ERASE[2] = {0xEC, 0x00}; -static const uint8_t CMD_ISC_PROGRAM[2] = {0xEA, 0x00}; - -static const uint8_t CMD_XSC_BLANK_CHECK[2] = {0x0D, 0x00}; -static const uint8_t CMD_XSC_CONFIG[2] = {0xEE, 0x00}; -static const uint8_t CMD_XSC_DATA_BTC[2] = {0xF2, 0x00}; -static const uint8_t CMD_XSC_DATA_CCB[2] = {0x0C, 0x00}; -static const uint8_t CMD_XSC_DATA_DONE[2] = {0x09, 0x00}; -static const uint8_t CMD_XSC_DATA_SUCR[2] = {0x0E, 0x00}; -static const uint8_t CMD_XSC_DATA_WRPT[2] = {0xF7, 0x00}; -static const uint8_t CMD_XSC_OP_STATUS[2] = {0xE3, 0x00}; -static const uint8_t CMD_XSC_READ[2] = {0xEF, 0x00}; -static const uint8_t CMD_XSC_UNLOCK[2] = {0x55, 0xAA}; +static const uint8_t cmd_bypass[2] = {0xFF, 0xFF}; + +static const uint8_t cmd_isc_address_shift[2] = {0xEB, 0x00}; +static const uint8_t cmd_isc_data_shift[2] = {0xED, 0x00}; +static const uint8_t cmd_isc_disable[2] = {0xF0, 0x00}; +static const uint8_t cmd_isc_enable[2] = {0xE8, 0x00}; +static const uint8_t cmd_isc_erase[2] = {0xEC, 0x00}; +static const uint8_t cmd_isc_program[2] = {0xEA, 0x00}; + +static const uint8_t cmd_xsc_blank_check[2] = {0x0D, 0x00}; +static const uint8_t cmd_xsc_config[2] = {0xEE, 0x00}; +static const uint8_t cmd_xsc_data_btc[2] = {0xF2, 0x00}; +static const uint8_t cmd_xsc_data_ccb[2] = {0x0C, 0x00}; +static const uint8_t cmd_xsc_data_done[2] = {0x09, 0x00}; +static const uint8_t cmd_xsc_data_sucr[2] = {0x0E, 0x00}; +static const uint8_t cmd_xsc_data_wrpt[2] = {0xF7, 0x00}; +static const uint8_t cmd_xsc_op_status[2] = {0xE3, 0x00}; +static const uint8_t cmd_xsc_read[2] = {0xEF, 0x00}; +static const uint8_t cmd_xsc_unlock[2] = {0x55, 0xAA}; /* ****************************************************************************** @@ -135,14 +124,14 @@ static struct xcf_status read_status(struct flash_bank *bank) scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; - scan.out_value = CMD_BYPASS; + scan.out_value = cmd_bypass; scan.in_value = irdata; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); jtag_execute_queue(); - ret.isc_error = ((irdata[0] >> 7) & 3) == 0b01; - ret.prog_error = ((irdata[0] >> 5) & 3) == 0b01; + ret.isc_error = ((irdata[0] >> 7) & 3) == 1; + ret.prog_error = ((irdata[0] >> 5) & 3) == 1; ret.prog_busy = ((irdata[0] >> 4) & 1) == 0; ret.isc_mode = ((irdata[0] >> 3) & 1) == 1; @@ -162,14 +151,14 @@ static int isc_enter(struct flash_bank *bank) scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; - scan.out_value = CMD_ISC_ENABLE; + scan.out_value = cmd_isc_enable; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); jtag_execute_queue(); status = read_status(bank); - if (false == status.isc_mode) { + if (!status.isc_mode) { LOG_ERROR("*** XCF: FAILED to enter ISC mode"); return ERROR_FLASH_OPERATION_FAILED; } @@ -183,7 +172,7 @@ static int isc_leave(struct flash_bank *bank) struct xcf_status status = read_status(bank); - if (false == status.isc_mode) + if (!status.isc_mode) return ERROR_OK; else { struct scan_field scan; @@ -191,7 +180,7 @@ static int isc_leave(struct flash_bank *bank) scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; - scan.out_value = CMD_ISC_DISABLE; + scan.out_value = cmd_isc_disable; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); @@ -199,7 +188,7 @@ static int isc_leave(struct flash_bank *bank) alive_sleep(1); /* device needs 50 uS to leave ISC mode */ status = read_status(bank); - if (true == status.isc_mode) { + if (status.isc_mode) { LOG_ERROR("*** XCF: FAILED to leave ISC mode"); return ERROR_FLASH_OPERATION_FAILED; } @@ -252,7 +241,7 @@ static int isc_wait_erase_program(struct flash_bank *bank, int64_t timeout_ms) int64_t dt; do { - isc_read_register(bank, CMD_XSC_OP_STATUS, &isc_default, 8); + isc_read_register(bank, cmd_xsc_op_status, &isc_default, 8); if (((isc_default >> 2) & 1) == 1) return ERROR_OK; dt = timeval_ms() - t0; @@ -280,7 +269,7 @@ static int isc_set_register(struct flash_bank *bank, const uint8_t *cmd, scan.in_value = NULL; jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE); - if (0 == timeout_ms) + if (timeout_ms == 0) return jtag_execute_queue(); else return isc_wait_erase_program(bank, timeout_ms); @@ -307,11 +296,11 @@ static int isc_program_register(struct flash_bank *bank, const uint8_t *cmd, jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IRSHIFT); scan.num_bits = 16; - scan.out_value = CMD_ISC_PROGRAM; + scan.out_value = cmd_isc_program; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); - if (0 == timeout_ms) + if (timeout_ms == 0) return jtag_execute_queue(); else return isc_wait_erase_program(bank, timeout_ms); @@ -322,7 +311,7 @@ static int isc_clear_protect(struct flash_bank *bank, unsigned int first, { uint8_t select_block[3] = {0x0, 0x0, 0x0}; select_block[0] = fill_select_block(first, last); - return isc_set_register(bank, CMD_XSC_UNLOCK, select_block, 24, 0); + return isc_set_register(bank, cmd_xsc_unlock, select_block, 24, 0); } static int isc_set_protect(struct flash_bank *bank, unsigned int first, @@ -332,7 +321,7 @@ static int isc_set_protect(struct flash_bank *bank, unsigned int first, for (unsigned int i = first; i <= last; i++) wrpt[0] &= ~(1 << i); - return isc_program_register(bank, CMD_XSC_DATA_WRPT, wrpt, 16, 0); + return isc_program_register(bank, cmd_xsc_data_wrpt, wrpt, 16, 0); } static int isc_erase_sectors(struct flash_bank *bank, unsigned int first, @@ -341,19 +330,19 @@ static int isc_erase_sectors(struct flash_bank *bank, unsigned int first, uint8_t select_block[3] = {0, 0, 0}; select_block[0] = fill_select_block(first, last); int64_t timeout = SECTOR_ERASE_TIMEOUT_MS * (last - first + 1); - return isc_set_register(bank, CMD_ISC_ERASE, select_block, 24, timeout); + return isc_set_register(bank, cmd_isc_erase, select_block, 24, timeout); } static int isc_adr_shift(struct flash_bank *bank, int adr) { uint8_t adr_buf[3]; h_u24_to_le(adr_buf, adr); - return isc_set_register(bank, CMD_ISC_ADDRESS_SHIFT, adr_buf, 24, 0); + return isc_set_register(bank, cmd_isc_address_shift, adr_buf, 24, 0); } static int isc_program_data_page(struct flash_bank *bank, const uint8_t *page_buf) { - return isc_program_register(bank, CMD_ISC_DATA_SHIFT, page_buf, 8 * XCF_PAGE_SIZE, 100); + return isc_program_register(bank, cmd_isc_data_shift, page_buf, 8 * XCF_PAGE_SIZE, 100); } static void isc_data_read_out(struct flash_bank *bank, uint8_t *buffer, uint32_t count) @@ -366,7 +355,7 @@ static void isc_data_read_out(struct flash_bank *bank, uint8_t *buffer, uint32_t scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; - scan.out_value = CMD_XSC_READ; + scan.out_value = cmd_xsc_read; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); @@ -382,7 +371,7 @@ static int isc_set_data_done(struct flash_bank *bank, int sector) { uint8_t done = 0xFF; done &= ~(1 << sector); - return isc_program_register(bank, CMD_XSC_DATA_DONE, &done, 8, 100); + return isc_program_register(bank, cmd_xsc_data_done, &done, 8, 100); } static void flip_u8(uint8_t *out, const uint8_t *in, int len) @@ -399,7 +388,7 @@ static void flip_u8(uint8_t *out, const uint8_t *in, int len) * Function presumes need of bit reversing if it can not exactly detects * the opposite. */ -bool need_bit_reverse(const uint8_t *buffer) +static bool need_bit_reverse(const uint8_t *buffer) { const size_t L = 20; uint8_t reference[L]; @@ -409,7 +398,7 @@ bool need_bit_reverse(const uint8_t *buffer) reference[18] = 0xAA; reference[19] = 0x66; - if (0 == memcmp(reference, buffer, L)) + if (memcmp(reference, buffer, L) == 0) return false; else return true; @@ -444,7 +433,7 @@ static int read_write_data(struct flash_bank *bank, const uint8_t *w_buffer, goto EXIT; } - if ((write_flag) && (0 == offset) && (count >= XCF_PAGE_SIZE)) + if ((write_flag) && (offset == 0) && (count >= XCF_PAGE_SIZE)) revbit = need_bit_reverse(w_buffer); while (count > 0) { @@ -475,7 +464,7 @@ static int read_write_data(struct flash_bank *bank, const uint8_t *w_buffer, w_buffer += len; sector_bytes -= len; ret = isc_program_data_page(bank, page_buf); - if (ERROR_OK != ret) + if (ret != ERROR_OK) goto EXIT; else { LOG_DEBUG("written %d bytes from %d", dbg_written, dbg_count); @@ -494,7 +483,7 @@ static int read_write_data(struct flash_bank *bank, const uint8_t *w_buffer, if (write_flag) { for (unsigned int i = 0; i < bank->num_sectors; i++) { ret = isc_set_data_done(bank, i); - if (ERROR_OK != ret) + if (ret != ERROR_OK) goto EXIT; } } @@ -508,7 +497,7 @@ EXIT: static uint16_t isc_read_ccb(struct flash_bank *bank) { uint8_t ccb[2]; - isc_read_register(bank, CMD_XSC_DATA_CCB, ccb, 16); + isc_read_register(bank, cmd_xsc_data_ccb, ccb, 16); return le_to_h_u16(ccb); } @@ -526,24 +515,24 @@ static int isc_program_ccb(struct flash_bank *bank, uint16_t ccb) { uint8_t buf[2]; h_u16_to_le(buf, ccb); - return isc_program_register(bank, CMD_XSC_DATA_CCB, buf, 16, 100); + return isc_program_register(bank, cmd_xsc_data_ccb, buf, 16, 100); } static int isc_program_singe_revision_sucr(struct flash_bank *bank) { uint8_t sucr[2] = {0xFC, 0xFF}; - return isc_program_register(bank, CMD_XSC_DATA_SUCR, sucr, 16, 100); + return isc_program_register(bank, cmd_xsc_data_sucr, sucr, 16, 100); } static int isc_program_single_revision_btc(struct flash_bank *bank) { uint8_t buf[4]; uint32_t btc = 0xFFFFFFFF; - btc &= ~0b1111; + btc &= ~0xF; btc |= ((bank->num_sectors - 1) << 2); btc &= ~(1 << 4); h_u32_to_le(buf, btc); - return isc_program_register(bank, CMD_XSC_DATA_BTC, buf, 32, 100); + return isc_program_register(bank, cmd_xsc_data_btc, buf, 32, 100); } static int fpga_configure(struct flash_bank *bank) @@ -553,7 +542,7 @@ static int fpga_configure(struct flash_bank *bank) scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; - scan.out_value = CMD_XSC_CONFIG; + scan.out_value = cmd_xsc_config; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); jtag_execute_queue(); @@ -572,7 +561,7 @@ FLASH_BANK_COMMAND_HANDLER(xcf_flash_bank_command) struct xcf_priv *priv; priv = malloc(sizeof(struct xcf_priv)); - if (priv == NULL) { + if (!priv) { LOG_ERROR("no memory for flash bank info"); return ERROR_FAIL; } @@ -581,15 +570,15 @@ FLASH_BANK_COMMAND_HANDLER(xcf_flash_bank_command) return ERROR_OK; } -static int xcf_info(struct flash_bank *bank, char *buf, int buf_size) +static int xcf_info(struct flash_bank *bank, struct command_invocation *cmd) { const struct xcf_priv *priv = bank->driver_priv; - if (false == priv->probed) { - snprintf(buf, buf_size, "\nXCF flash bank not probed yet\n"); + if (!priv->probed) { + command_print_sameline(cmd, "\nXCF flash bank not probed yet\n"); return ERROR_OK; } - snprintf(buf, buf_size, "%s", product_name(bank)); + command_print_sameline(cmd, "%s", product_name(bank)); return ERROR_OK; } @@ -598,17 +587,17 @@ static int xcf_probe(struct flash_bank *bank) struct xcf_priv *priv = bank->driver_priv; uint32_t id; - if (true == priv->probed) + if (priv->probed) free(bank->sectors); priv->probed = false; - if (bank->target->tap == NULL) { + if (!bank->target->tap) { LOG_ERROR("Target has no JTAG tap"); return ERROR_FAIL; } /* 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 */ @@ -629,7 +618,7 @@ static int xcf_probe(struct flash_bank *bank) } bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector)); - if (NULL == bank->sectors) { + if (!bank->sectors) { LOG_ERROR("No memory for sector table"); return ERROR_FAIL; } @@ -652,7 +641,7 @@ static int xcf_auto_probe(struct flash_bank *bank) { struct xcf_priv *priv = bank->driver_priv; - if (true == priv->probed) + if (priv->probed) return ERROR_OK; else return xcf_probe(bank); @@ -663,7 +652,7 @@ static int xcf_protect_check(struct flash_bank *bank) uint8_t wrpt[2]; isc_enter(bank); - isc_read_register(bank, CMD_XSC_DATA_WRPT, wrpt, 16); + isc_read_register(bank, cmd_xsc_data_wrpt, wrpt, 16); isc_leave(bank); for (unsigned int i = 0; i < bank->num_sectors; i++) @@ -684,7 +673,7 @@ static int xcf_erase_check(struct flash_bank *bank) scan.check_mask = NULL; scan.check_value = NULL; scan.num_bits = 16; - scan.out_value = CMD_XSC_BLANK_CHECK; + scan.out_value = cmd_xsc_blank_check; scan.in_value = NULL; jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE); jtag_execute_queue(); @@ -755,7 +744,7 @@ COMMAND_HANDLER(xcf_handle_ccb_command) { struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; uint16_t ccb = 0xFFFF; @@ -800,29 +789,29 @@ COMMAND_HANDLER(xcf_handle_ccb_command) { sector = gucr_num(bank); isc_clear_protect(bank, sector, sector); int ret = isc_erase_sectors(bank, sector, sector); - if (ERROR_OK != ret) + if (ret != ERROR_OK) goto EXIT; ret = isc_program_ccb(bank, ccb); - if (ERROR_OK != ret) + if (ret != ERROR_OK) goto EXIT; ret = isc_program_single_revision_btc(bank); - if (ERROR_OK != ret) + if (ret != ERROR_OK) goto EXIT; ret = isc_set_data_done(bank, sector); - if (ERROR_OK != ret) + if (ret != ERROR_OK) goto EXIT; /* SUCR sector */ sector = sucr_num(bank); isc_clear_protect(bank, sector, sector); ret = isc_erase_sectors(bank, sector, sector); - if (ERROR_OK != ret) + if (ret != ERROR_OK) goto EXIT; ret = isc_program_singe_revision_sucr(bank); - if (ERROR_OK != ret) + if (ret != ERROR_OK) goto EXIT; ret = isc_set_data_done(bank, sector); - if (ERROR_OK != ret) + if (ret != ERROR_OK) goto EXIT; EXIT: @@ -838,7 +827,7 @@ COMMAND_HANDLER(xcf_handle_configure_command) { struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; return fpga_configure(bank); diff --git a/src/flash/nor/xmc1xxx.c b/src/flash/nor/xmc1xxx.c index 757dd952f5..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 @@ -11,6 +11,7 @@ #endif #include "imp.h" +#include <helper/align.h> #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> @@ -140,9 +141,6 @@ static int xmc1xxx_erase(struct flash_bank *bank, unsigned int first, goto err_run; } - for (unsigned int sector = first; sector <= last; sector++) - bank->sectors[sector].is_erased = 1; - err_run: for (i = 0; i < ARRAY_SIZE(reg_params); i++) destroy_reg_param(®_params[i]); @@ -256,12 +254,12 @@ static int xmc1xxx_write(struct flash_bank *bank, const uint8_t *buffer, LOG_DEBUG("Infineon XMC1000 write at 0x%08" PRIx32 " (%" PRIu32 " bytes)", offset, byte_count); - if (offset & (NVM_BLOCK_SIZE - 1)) { + if (!IS_ALIGNED(offset, NVM_BLOCK_SIZE)) { LOG_ERROR("offset 0x%" PRIx32 " breaks required block alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } - if (byte_count & (NVM_BLOCK_SIZE - 1)) { + if (!IS_ALIGNED(byte_count, NVM_BLOCK_SIZE)) { LOG_WARNING("length %" PRIu32 " is not block aligned, rounding up", byte_count); } @@ -403,7 +401,7 @@ static int xmc1xxx_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int xmc1xxx_get_info_command(struct flash_bank *bank, char *buf, int buf_size) +static int xmc1xxx_get_info_command(struct flash_bank *bank, struct command_invocation *cmd) { uint32_t chipid[8]; int i, retval; @@ -429,7 +427,8 @@ static int xmc1xxx_get_info_command(struct flash_bank *bank, char *buf, int buf_ } LOG_DEBUG("ID[7] = %08" PRIX32, chipid[7]); - snprintf(buf, buf_size, "XMC%" PRIx32 "00 %" PRIX32 " flash %" PRIu32 "KB ROM %" PRIu32 "KB SRAM %" PRIu32 "KB", + command_print_sameline(cmd, + "XMC%" PRIx32 "00 %" PRIX32 " flash %" PRIu32 "KB ROM %" PRIu32 "KB SRAM %" PRIu32 "KB", (chipid[0] >> 12) & 0xff, 0xAA + (chipid[7] >> 28) - 1, (((chipid[6] >> 12) & 0x3f) - 1) * 4, @@ -521,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 a032e4d46f..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 @@ -577,8 +566,6 @@ static int xmc4xxx_erase(struct flash_bank *bank, unsigned int first, if (res != ERROR_OK) goto clear_status_and_exit; - - bank->sectors[i].is_erased = 1; } clear_status_and_exit: @@ -805,7 +792,7 @@ abort_write_and_exit: } -static int xmc4xxx_get_info_command(struct flash_bank *bank, char *buf, int buf_size) +static int xmc4xxx_get_info_command(struct flash_bank *bank, struct command_invocation *cmd) { struct xmc4xxx_flash_bank *fb = bank->driver_priv; uint32_t scu_idcode; @@ -914,9 +901,7 @@ static int xmc4xxx_get_info_command(struct flash_bank *bank, char *buf, int buf_ break; default: - snprintf(buf, buf_size, - "Cannot identify target as an XMC4xxx. SCU_ID: %"PRIx32"\n", - scu_idcode); + command_print_sameline(cmd, "Cannot identify target as an XMC4xxx. SCU_ID: %"PRIx32 "\n", scu_idcode); return ERROR_OK; } @@ -943,12 +928,10 @@ static int xmc4xxx_get_info_command(struct flash_bank *bank, char *buf, int buf_ } } - if (rev_str != NULL) - snprintf(buf, buf_size, "%s - Rev: %s%s", - dev_str, rev_str, prot_str); + if (rev_str) + command_print_sameline(cmd, "%s - Rev: %s%s", dev_str, rev_str, prot_str); else - snprintf(buf, buf_size, "%s - Rev: unknown (0x%01x)%s", - dev_str, rev_id, prot_str); + command_print_sameline(cmd, "%s - Rev: unknown (0x%01x)%s", dev_str, rev_id, prot_str); return ERROR_OK; } @@ -1274,12 +1257,12 @@ COMMAND_HANDLER(xmc4xxx_handle_flash_password_command) errno = 0; /* We skip over the flash bank */ - fb->pw1 = strtol(CMD_ARGV[1], NULL, 16); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], fb->pw1); if (errno) return ERROR_COMMAND_SYNTAX_ERROR; - fb->pw2 = strtol(CMD_ARGV[2], NULL, 16); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], fb->pw2); if (errno) return ERROR_COMMAND_SYNTAX_ERROR; diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl index aafb939cd6..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 # @@ -6,6 +8,7 @@ # optional args: verify, reset, exit and address # +lappend _telnet_autocomplete_skip program_error proc program_error {description exit} { if {$exit == 1} { echo $description @@ -113,19 +116,13 @@ proc stm32f7x args { eval stm32f2x $args } proc stm32l0x args { eval stm32lx $args } proc stm32l1x args { eval stm32lx $args } -# stm32[g0|g4|wb|wl] uses the same flash driver as the stm32l4x +# stm32[g0|g4|l5|u5|wb|wl] uses the same flash driver as the stm32l4x proc stm32g0x args { eval stm32l4x $args } proc stm32g4x args { eval stm32l4x $args } +proc stm32l5x args { eval stm32l4x $args } +proc stm32u5x args { eval stm32l4x $args } proc stm32wbx args { eval stm32l4x $args } proc stm32wlx args { eval stm32l4x $args } -# ease migration to updated flash driver -proc stm32x args { - echo "DEPRECATED! use 'stm32f1x $args' not 'stm32x $args'" - eval stm32f1x $args -} - -proc stm32f2xxx args { - echo "DEPRECATED! use 'stm32f2x $args' not 'stm32f2xxx $args'" - eval stm32f2x $args -} +# gd32e23x uses the same flash driver as the stm32f1x +proc gd32e23x args { eval stm32f1x $args } diff --git a/src/hello.c b/src/hello.c index a1c00c0ddf..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) { @@ -88,7 +78,7 @@ COMMAND_HANDLER(handle_hello_command) { const char *sep, *name; int retval = CALL_COMMAND_HANDLER(handle_hello_args, &sep, &name); - if (ERROR_OK == retval) + if (retval == ERROR_OK) command_print(CMD, "Greetings%s%s!", sep, name); return retval; } 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 2b3523f7ac..e0fa331ea2 100644 --- a/src/helper/Makefile.am +++ b/src/helper/Makefile.am @@ -1,6 +1,6 @@ -noinst_LTLIBRARIES += %D%/libhelper.la +# SPDX-License-Identifier: GPL-2.0-or-later -%C%_libhelper_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS) +noinst_LTLIBRARIES += %D%/libhelper.la %C%_libhelper_la_SOURCES = \ %D%/binarybuffer.c \ @@ -9,40 +9,33 @@ 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 \ %D%/configuration.h \ - %D%/ioutil.h \ %D%/list.h \ %D%/util.h \ %D%/types.h \ %D%/log.h \ %D%/command.h \ + %D%/crc32.h \ %D%/time_support.h \ %D%/replacements.h \ %D%/fileio.h \ %D%/system.h \ %D%/jep106.h \ %D%/jep106.inc \ - %D%/jim-nvp.h - -if IOUTIL -%C%_libhelper_la_SOURCES += %D%/ioutil.c -else -%C%_libhelper_la_SOURCES += %D%/ioutil_stubs.c -endif - -%C%_libhelper_la_CFLAGS = $(AM_CFLAGS) -if IS_MINGW -# FD_* macros are sloppy with their signs on MinGW32 platform -%C%_libhelper_la_CFLAGS += -Wno-sign-compare -endif + %D%/jim-nvp.h \ + %D%/nvp.h \ + %D%/compiler.h STARTUP_TCL_SRCS += %D%/startup.tcl EXTRA_DIST += \ diff --git a/src/helper/align.h b/src/helper/align.h new file mode 100644 index 0000000000..935a6a3b26 --- /dev/null +++ b/src/helper/align.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * The content of this file is mainly copied/inspired from Linux kernel + * code in include/linux/align.h and include/uapi/linux/const.h + * + * Macro name 'ALIGN' conflicts with macOS/BSD file param.h + */ + +#ifndef OPENOCD_HELPER_ALIGN_H +#define OPENOCD_HELPER_ALIGN_H + +#define ALIGN_MASK(x, mask) \ +({ \ + typeof(mask) _mask = (mask); \ + ((x) + _mask) & ~_mask; \ +}) + +/* @a is a power of 2 value */ +#define ALIGN_UP(x, a) ALIGN_MASK(x, (typeof(x))(a) - 1) +#define ALIGN_DOWN(x, a) ((x) & ~((typeof(x))(a) - 1)) +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) + +#define IS_PWR_OF_2(x) \ +({ \ + typeof(x) _x = (x); \ + _x == 0 || (_x & (_x - 1)) == 0; \ +}) + +#endif /* OPENOCD_HELPER_ALIGN_H */ 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 44d139f58d..5f38b43ae1 100644 --- a/src/helper/binarybuffer.c +++ b/src/helper/binarybuffer.c @@ -1,28 +1,18 @@ +// 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 #include "config.h" #endif +#include "helper/replacements.h" #include "log.h" #include "binarybuffer.h" @@ -52,7 +42,7 @@ static const char hex_digits[] = { void *buf_cpy(const void *from, void *_to, unsigned size) { - if (NULL == from || NULL == _to) + if (!from || !_to) return NULL; /* copy entire buffer */ @@ -221,7 +211,7 @@ static void str_radix_guess(const char **_str, unsigned *_str_len, unsigned *_radix) { unsigned radix = *_radix; - if (0 != radix) + if (radix != 0) return; const char *str = *_str; unsigned str_len = *_str_len; diff --git a/src/helper/binarybuffer.h b/src/helper/binarybuffer.h index 36d6adc6f2..3446296817 100644 --- a/src/helper/binarybuffer.h +++ b/src/helper/binarybuffer.h @@ -1,28 +1,18 @@ +/* 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 #define OPENOCD_HELPER_BINARYBUFFER_H -#include "list.h" +#include <helper/list.h> +#include <helper/types.h> /** @file * Support functions to access arbitrary bits in a byte array diff --git a/src/helper/bits.h b/src/helper/bits.h index 464584db8c..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/>. */ /* @@ -24,11 +13,16 @@ #ifndef OPENOCD_HELPER_BITS_H #define OPENOCD_HELPER_BITS_H +#include <helper/replacements.h> #include <helper/types.h> #define BIT(nr) (1UL << (nr)) +#define BIT_ULL(nr) (1ULL << (nr)) #define BITS_PER_BYTE 8 #define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) +#define BITS_PER_LONG_LONG (BITS_PER_BYTE * sizeof(long long)) +#define GENMASK(h, l) (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#define GENMASK_ULL(h, l) (((~0ULL) - (1ULL << (l)) + 1) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) @@ -36,8 +30,8 @@ /** * bitmap_zero - Clears all the bits in memory - * @dst: the address of the bitmap - * @nbits: the number of bits to clear + * @param dst the address of the bitmap + * @param nbits the number of bits to clear */ static inline void bitmap_zero(unsigned long *dst, unsigned int nbits) { @@ -47,8 +41,8 @@ static inline void bitmap_zero(unsigned long *dst, unsigned int nbits) /** * clear_bit - Clear a bit in memory - * @nr: the bit to set - * @addr: the address to start counting from + * @param nr the bit to set + * @param addr the address to start counting from */ static inline void clear_bit(unsigned int nr, volatile unsigned long *addr) { @@ -60,8 +54,8 @@ static inline void clear_bit(unsigned int nr, volatile unsigned long *addr) /** * set_bit - Set a bit in memory - * @nr: the bit to set - * @addr: the address to start counting from + * @param nr the bit to set + * @param addr the address to start counting from */ static inline void set_bit(unsigned int nr, volatile unsigned long *addr) { @@ -73,8 +67,8 @@ static inline void set_bit(unsigned int nr, volatile unsigned long *addr) /** * test_bit - Determine whether a bit is set - * @nr: bit number to test - * @addr: Address to start counting from + * @param nr bit number to test + * @param addr Address to start counting from */ static inline int test_bit(unsigned int nr, const volatile unsigned long *addr) { diff --git a/src/helper/command.c b/src/helper/command.c index 271e7b993f..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> @@ -44,17 +30,33 @@ /* nice short description of source file */ #define __THIS__FILE__ "command.c" -static int run_command(struct command_context *context, - struct command *c, const char *words[], unsigned num_words); - struct log_capture_state { Jim_Interp *interp; Jim_Obj *output; }; static int unregister_command(struct command_context *context, - struct command *parent, const char *name); -static char *command_name(struct command *c, char delim); + const char *cmd_prefix, const char *name); +static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *argv); +static int help_add_command(struct command_context *cmd_ctx, + const char *cmd_name, const char *help_text, const char *usage_text); +static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name); + +/* set of functions to wrap jimtcl internal data */ +static inline bool jimcmd_is_proc(Jim_Cmd *cmd) +{ + return cmd->isproc; +} + +bool jimcmd_is_oocd_command(Jim_Cmd *cmd) +{ + return !cmd->isproc && cmd->u.native.cmdProc == jim_command_dispatch; +} + +void *jimcmd_privdata(Jim_Cmd *cmd) +{ + return cmd->isproc ? NULL : cmd->u.native.privData; +} static void tcl_output(void *privData, const char *file, unsigned line, const char *function, const char *string) @@ -67,17 +69,21 @@ static struct log_capture_state *command_log_capture_start(Jim_Interp *interp) { /* capture log output and return it. A garbage collect can * happen, so we need a reference count to this object */ - Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0); - if (NULL == tclOutput) + Jim_Obj *jim_output = Jim_NewStringObj(interp, "", 0); + if (!jim_output) return NULL; + Jim_IncrRefCount(jim_output); + struct log_capture_state *state = malloc(sizeof(*state)); - if (NULL == state) + if (!state) { + LOG_ERROR("Out of memory"); + Jim_DecrRefCount(interp, jim_output); return NULL; + } state->interp = interp; - Jim_IncrRefCount(tclOutput); - state->output = tclOutput; + state->output = jim_output; log_add_callback(tcl_output, state); @@ -93,25 +99,27 @@ 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) { - if (NULL == state) + if (!state) return; 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); @@ -120,7 +128,7 @@ static void command_log_capture_finish(struct log_capture_state *state) static int command_retval_set(Jim_Interp *interp, int retval) { int *return_retval = Jim_GetAssocData(interp, "retval"); - if (return_retval != NULL) + if (return_retval) *return_retval = retval; return (retval == ERROR_OK) ? JIM_OK : retval; @@ -130,15 +138,14 @@ extern struct command_context *global_cmd_ctx; /* dump a single line to the log for the command. * Do nothing in case we are not at debug level 3 */ -void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv) +static void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv) { if (debug_level < LOG_LVL_DEBUG) return; 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; @@ -147,39 +154,11 @@ void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv) 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 (NULL == 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] == NULL) { - 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 */ struct command_context *cmd_ctx = Jim_GetAssocData(interp, "context"); - if (NULL == cmd_ctx) { + if (!cmd_ctx) { /* Tcl can invoke commands directly instead of via command_run_line(). This would * happen when the Jim Tcl interpreter is provided by eCos or if we are running * commands in a startup script. @@ -192,111 +171,28 @@ struct command_context *current_command_context(Jim_Interp *interp) return cmd_ctx; } -static int script_command_run(Jim_Interp *interp, - int argc, Jim_Obj * const *argv, struct command *c) -{ - target_call_timer_callbacks_now(); - LOG_USER_N("%s", ""); /* Keep GDB connection alive*/ - - unsigned nwords; - char **words = script_command_args_alloc(argc, argv, &nwords); - if (NULL == words) - return JIM_ERR; - - struct command_context *cmd_ctx = current_command_context(interp); - 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 script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - /* the private data is stashed in the interp structure */ - - struct command *c = interp->cmdPrivData; - assert(c); - script_debug(interp, argc, argv); - return script_command_run(interp, argc, argv, c); -} - -static struct command *command_root(struct command *c) -{ - while (NULL != c->parent) - c = c->parent; - return c; -} - /** - * Find a command by name from a list of commands. - * @returns Returns the named command if it exists in the list. + * Find a openocd command from fullname. + * @returns Returns the named command if it is registred in interp. * Returns NULL otherwise. */ -static struct command *command_find(struct command *head, const char *name) -{ - for (struct command *cc = head; cc; cc = cc->next) { - if (strcmp(cc->name, name) == 0) - return cc; - } - return NULL; -} - -struct command *command_find_in_context(struct command_context *cmd_ctx, - const char *name) +static struct command *command_find_from_name(Jim_Interp *interp, const char *name) { - return command_find(cmd_ctx->commands, name); -} - -/** - * Add the command into the linked list, sorted by name. - * @param head Address to head of command list pointer, which may be - * updated if @c c gets inserted at the beginning of the list. - * @param c The command to add to the list pointed to by @c head. - */ -static void command_add_child(struct command **head, struct command *c) -{ - assert(head); - if (NULL == *head) { - *head = c; - return; - } - - while ((*head)->next && (strcmp(c->name, (*head)->name) > 0)) - head = &(*head)->next; - - if (strcmp(c->name, (*head)->name) > 0) { - c->next = (*head)->next; - (*head)->next = c; - } else { - c->next = *head; - *head = c; - } -} - -static struct command **command_list_for_parent( - struct command_context *cmd_ctx, struct command *parent) -{ - return parent ? &parent->children : &cmd_ctx->commands; -} - -static void command_free(struct command *c) -{ - /** @todo if command has a handler, unregister its jim command! */ + if (!name) + return NULL; - while (NULL != c->children) { - struct command *tmp = c->children; - c->children = tmp->next; - command_free(tmp); - } + Jim_Obj *jim_name = Jim_NewStringObj(interp, name, -1); + Jim_IncrRefCount(jim_name); + Jim_Cmd *cmd = Jim_GetCommand(interp, jim_name, JIM_NONE); + Jim_DecrRefCount(interp, jim_name); + if (!cmd || jimcmd_is_proc(cmd) || !jimcmd_is_oocd_command(cmd)) + return NULL; - free(c->name); - free(c->help); - free(c->usage); - free(c); + return jimcmd_privdata(cmd); } static struct command *command_new(struct command_context *cmd_ctx, - struct command *parent, const struct command_registration *cr) + const char *full_name, const struct command_registration *cr) { assert(cr->name); @@ -307,94 +203,89 @@ static struct command *command_new(struct command_context *cmd_ctx, * strlen(.usage) == 0 means that the command takes no * arguments. */ - if ((cr->jim_handler == NULL) && (cr->usage == NULL)) { - LOG_ERROR("BUG: command '%s%s%s' does not have the " + if (!cr->jim_handler && !cr->usage) + LOG_ERROR("BUG: command '%s' does not have the " "'.usage' field filled out", - parent && parent->name ? parent->name : "", - parent && parent->name ? " " : "", - cr->name); - } + full_name); struct command *c = calloc(1, sizeof(struct command)); - if (NULL == c) + if (!c) return NULL; c->name = strdup(cr->name); - if (cr->help) - c->help = strdup(cr->help); - if (cr->usage) - c->usage = strdup(cr->usage); - - if (!c->name || (cr->help && !c->help) || (cr->usage && !c->usage)) - goto command_new_error; + if (!c->name) { + free(c); + return NULL; + } - c->parent = parent; c->handler = cr->handler; c->jim_handler = cr->jim_handler; c->mode = cr->mode; - command_add_child(command_list_for_parent(cmd_ctx, parent), c); + if (cr->help || cr->usage) + help_add_command(cmd_ctx, full_name, cr->help, cr->usage); return c; - -command_new_error: - command_free(c); - return NULL; } -static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv); - -static int register_command_handler(struct command_context *cmd_ctx, - struct command *c) +static void command_free(struct Jim_Interp *interp, void *priv) { - Jim_Interp *interp = cmd_ctx->interp; - - LOG_DEBUG("registering '%s'...", c->name); + struct command *c = priv; - Jim_CmdProc *func = c->handler ? &script_command : &command_unknown; - int retval = Jim_CreateCommand(interp, c->name, func, c, NULL); - - return retval; + free(c->name); + free(c); } static struct command *register_command(struct command_context *context, - struct command *parent, const struct command_registration *cr) + const char *cmd_prefix, const struct command_registration *cr) { + char *full_name; + if (!context || !cr->name) return NULL; - const char *name = cr->name; - struct command **head = command_list_for_parent(context, parent); - struct command *c = command_find(*head, name); - if (NULL != c) { + if (cmd_prefix) + full_name = alloc_printf("%s %s", cmd_prefix, cr->name); + else + full_name = strdup(cr->name); + if (!full_name) + return NULL; + + struct command *c = command_find_from_name(context->interp, full_name); + if (c) { /* TODO: originally we treated attempting to register a cmd twice as an error * Sometimes we need this behaviour, such as with flash banks. * http://www.mail-archive.com/openocd-development@lists.berlios.de/msg11152.html */ - LOG_DEBUG("command '%s' is already registered in '%s' context", - name, parent ? parent->name : "<global>"); + LOG_DEBUG("command '%s' is already registered", full_name); + free(full_name); return c; } - c = command_new(context, parent, cr); - if (NULL == c) + c = command_new(context, full_name, cr); + if (!c) { + free(full_name); return NULL; + } - int retval = JIM_OK; - if (NULL != cr->jim_handler && NULL == parent) { - retval = Jim_CreateCommand(context->interp, cr->name, - cr->jim_handler, NULL, NULL); - } else if (NULL != cr->handler || NULL != parent) - retval = register_command_handler(context, command_root(c)); - + if (false) /* too noisy with debug_level 3 */ + LOG_DEBUG("registering '%s'...", full_name); + int retval = Jim_CreateCommand(context->interp, full_name, + jim_command_dispatch, c, command_free); if (retval != JIM_OK) { - unregister_command(context, parent, name); - c = NULL; + command_run_linef(context, "del_help_text {%s}", full_name); + command_run_linef(context, "del_usage_text {%s}", full_name); + free(c); + free(full_name); + return NULL; } + + free(full_name); return c; } -int register_commands(struct command_context *cmd_ctx, struct command *parent, - const struct command_registration *cmds) +int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, + const struct command_registration *cmds, void *data, + struct target *override_target) { int retval = ERROR_OK; unsigned i; @@ -402,73 +293,122 @@ int register_commands(struct command_context *cmd_ctx, struct command *parent, const struct command_registration *cr = cmds + i; struct command *c = NULL; - if (NULL != cr->name) { - c = register_command(cmd_ctx, parent, cr); - if (NULL == c) { + if (cr->name) { + c = register_command(cmd_ctx, cmd_prefix, cr); + if (!c) { retval = ERROR_FAIL; break; } + c->jim_handler_data = data; + c->jim_override_target = override_target; } - if (NULL != cr->chain) { - struct command *p = c ? : parent; - retval = register_commands(cmd_ctx, p, cr->chain); - if (ERROR_OK != retval) + if (cr->chain) { + if (cr->name) { + if (cmd_prefix) { + char *new_prefix = alloc_printf("%s %s", cmd_prefix, cr->name); + if (!new_prefix) { + retval = ERROR_FAIL; + break; + } + retval = __register_commands(cmd_ctx, new_prefix, cr->chain, data, override_target); + free(new_prefix); + } else { + retval = __register_commands(cmd_ctx, cr->name, cr->chain, data, override_target); + } + } else { + retval = __register_commands(cmd_ctx, cmd_prefix, cr->chain, data, override_target); + } + if (retval != ERROR_OK) break; } } - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { for (unsigned j = 0; j < i; j++) - unregister_command(cmd_ctx, parent, cmds[j].name); + unregister_command(cmd_ctx, cmd_prefix, cmds[j].name); } return retval; } -int unregister_all_commands(struct command_context *context, - struct command *parent) +static __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))) +int unregister_commands_match(struct command_context *cmd_ctx, const char *format, ...) { - if (context == NULL) - return ERROR_OK; + Jim_Interp *interp = cmd_ctx->interp; + va_list ap; - struct command **head = command_list_for_parent(context, parent); - while (NULL != *head) { - struct command *tmp = *head; - *head = tmp->next; - command_free(tmp); - } + va_start(ap, format); + char *query = alloc_vprintf(format, ap); + va_end(ap); + if (!query) + return ERROR_FAIL; - return ERROR_OK; -} + char *query_cmd = alloc_printf("info commands {%s}", query); + free(query); + if (!query_cmd) + return ERROR_FAIL; -static int unregister_command(struct command_context *context, - struct command *parent, const char *name) -{ - if ((!context) || (!name)) - return ERROR_COMMAND_SYNTAX_ERROR; + int retval = Jim_EvalSource(interp, __THIS__FILE__, __LINE__, query_cmd); + free(query_cmd); + if (retval != JIM_OK) + return ERROR_FAIL; + + Jim_Obj *list = Jim_GetResult(interp); + Jim_IncrRefCount(list); + + int len = Jim_ListLength(interp, list); + for (int i = 0; i < len; i++) { + Jim_Obj *elem = Jim_ListGetIndex(interp, list, i); + Jim_IncrRefCount(elem); - struct command *p = NULL; - struct command **head = command_list_for_parent(context, parent); - for (struct command *c = *head; NULL != c; p = c, c = c->next) { - if (strcmp(name, c->name) != 0) + const char *name = Jim_GetString(elem, NULL); + struct command *c = command_find_from_name(interp, name); + if (!c) { + /* not openocd command */ + Jim_DecrRefCount(interp, elem); continue; + } + if (false) /* too noisy with debug_level 3 */ + LOG_DEBUG("delete command \"%s\"", name); +#if JIM_VERSION >= 80 + Jim_DeleteCommand(interp, elem); +#else + Jim_DeleteCommand(interp, name); +#endif - if (p) - p->next = c->next; - else - *head = c->next; + help_del_command(cmd_ctx, name); - command_free(c); - return ERROR_OK; + Jim_DecrRefCount(interp, elem); } + Jim_DecrRefCount(interp, list); return ERROR_OK; } -void command_set_handler_data(struct command *c, void *p) +int unregister_all_commands(struct command_context *context, + const char *cmd_prefix) { - if (NULL != c->handler || NULL != c->jim_handler) - c->jim_handler_data = p; - for (struct command *cc = c->children; NULL != cc; cc = cc->next) - command_set_handler_data(cc, p); + if (!context) + return ERROR_OK; + + if (!cmd_prefix || !*cmd_prefix) + return unregister_commands_match(context, "*"); + + int retval = unregister_commands_match(context, "%s *", cmd_prefix); + if (retval != ERROR_OK) + return retval; + + return unregister_commands_match(context, "%s", cmd_prefix); +} + +static int unregister_command(struct command_context *context, + const char *cmd_prefix, const char *name) +{ + if (!context || !name) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!cmd_prefix || !*cmd_prefix) + return unregister_commands_match(context, "%s", name); + + return unregister_commands_match(context, "%s %s", cmd_prefix, name); } void command_output_text(struct command_context *context, const char *data) @@ -485,7 +425,7 @@ void command_print_sameline(struct command_invocation *cmd, const char *format, va_start(ap, format); string = alloc_vprintf(format, ap); - if (string != NULL && cmd) { + if (string && cmd) { /* we want this collected in the log + we also want to pick it up as a tcl return * value. * @@ -508,7 +448,7 @@ void command_print(struct command_invocation *cmd, const char *format, ...) va_start(ap, format); string = alloc_vprintf(format, ap); - if (string != NULL && cmd) { + if (string && cmd) { strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one *char longer */ /* we want this collected in the log + we also want to pick it up as a tcl return @@ -525,34 +465,7 @@ void command_print(struct command_invocation *cmd, const char *format, ...) va_end(ap); } -static char *__command_name(struct command *c, char delim, unsigned extra) -{ - char *name; - unsigned len = strlen(c->name); - if (NULL == c->parent) { - /* allocate enough for the name, child names, and '\0' */ - name = malloc(len + extra + 1); - if (!name) { - LOG_ERROR("Out of memory"); - return NULL; - } - strcpy(name, c->name); - } else { - /* parent's extra must include both the space and name */ - name = __command_name(c->parent, delim, 1 + len + extra); - char dstr[2] = { delim, 0 }; - strcat(name, dstr); - strcat(name, c->name); - } - return name; -} - -static char *command_name(struct command *c, char delim) -{ - return __command_name(c, delim, 0); -} - -static bool command_can_run(struct command_context *cmd_ctx, struct command *c) +static bool command_can_run(struct command_context *cmd_ctx, struct command *c, const char *full_name) { if (c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode) return true; @@ -571,68 +484,64 @@ static bool command_can_run(struct command_context *cmd_ctx, struct command *c) when = "if Cthulhu is summoned by"; break; } - char *full_name = command_name(c, ' '); LOG_ERROR("The '%s' command must be used %s 'init'.", full_name ? full_name : c->name, when); - free(full_name); 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 (!command_can_run(context, c)) - return ERROR_FAIL; + 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, }; - /* Black magic of overridden current target: - * If the command we are going to handle has a target prefix, - * override the current target temporarily for the time - * of processing the command. - * current_target_override is used also for event handlers - * therefore we prevent touching it if command has no prefix. - * Previous override is saved and restored back to ensure - * correct work when run_command() is re-entered. */ - struct target *saved_target_override = context->current_target_override; - if (c->jim_handler_data) - context->current_target_override = c->jim_handler_data; cmd.output = Jim_NewEmptyStringObj(context->interp); Jim_IncrRefCount(cmd.output); int retval = c->handler(&cmd); - - if (c->jim_handler_data) - context->current_target_override = saved_target_override; - if (retval == ERROR_COMMAND_SYNTAX_ERROR) { /* Print help for command */ - char *full_name = command_name(c, ' '); - if (NULL != full_name) { - command_run_linef(context, "usage %s", full_name); - free(full_name); - } + command_run_linef(context, "usage %s", words[0]); } else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) { /* just fall through for a shutdown request */ } else { - if (retval != ERROR_OK) { - char *full_name = command_name(c, ' '); + if (retval != ERROR_OK) LOG_DEBUG("Command '%s' failed with error code %d", - full_name ? full_name : c->name, retval); - free(full_name); - } - /* Use the command output as the Tcl result */ - Jim_SetResult(context->interp, cmd.output); + words[0], retval); + /* + * 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) @@ -661,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"); } @@ -708,7 +617,7 @@ int command_run_linef(struct command_context *context, const char *format, ...) va_list ap; va_start(ap, format); string = alloc_vprintf(format, ap); - if (string != NULL) { + if (string) { retval = command_run_line(context, string); free(string); } @@ -734,42 +643,44 @@ struct command_context *copy_command_context(struct command_context *context) void command_done(struct command_context *cmd_ctx) { - if (NULL == cmd_ctx) + if (!cmd_ctx) return; free(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 (full_path == NULL) - return JIM_ERR; - Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path)); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + char *full_path = find_file(CMD_ARGV[0]); + if (!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(jim_echo) +COMMAND_HANDLER(handle_echo) { if (CMD_ARGC == 2 && !strcmp(CMD_ARGV[0], "-n")) { LOG_USER_N("%s", CMD_ARGV[1]); - return JIM_OK; + return ERROR_OK; } + if (CMD_ARGC != 1) - return JIM_ERR; + return ERROR_FAIL; + LOG_USER("%s", CMD_ARGV[0]); - return JIM_OK; + 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) { @@ -784,42 +695,34 @@ 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); return retcode; } -static COMMAND_HELPER(command_help_find, struct command *head, - struct command **out) -{ - if (0 == CMD_ARGC) - return ERROR_COMMAND_SYNTAX_ERROR; - *out = command_find(head, CMD_ARGV[0]); - if (NULL == *out) - return ERROR_COMMAND_SYNTAX_ERROR; - if (--CMD_ARGC == 0) - return ERROR_OK; - CMD_ARGV++; - return CALL_COMMAND_HANDLER(command_help_find, (*out)->children, out); -} +struct help_entry { + struct list_head lh; + char *cmd_name; + char *help; + char *usage; +}; -static COMMAND_HELPER(command_help_show, struct command *c, unsigned n, +static COMMAND_HELPER(command_help_show, struct help_entry *c, bool show_help, const char *cmd_match); -static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n, - bool show_help, const char *cmd_match) +static COMMAND_HELPER(command_help_show_list, bool show_help, const char *cmd_match) { - for (struct command *c = head; NULL != c; c = c->next) - CALL_COMMAND_HANDLER(command_help_show, c, n, show_help, cmd_match); + struct help_entry *entry; + + list_for_each_entry(entry, CMD_CTX->help_list, lh) + CALL_COMMAND_HANDLER(command_help_show, entry, show_help, cmd_match); return ERROR_OK; } @@ -850,41 +753,56 @@ static void command_help_show_wrap(const char *str, unsigned n, unsigned n2) } } -static COMMAND_HELPER(command_help_show, struct command *c, unsigned n, +static COMMAND_HELPER(command_help_show, struct help_entry *c, bool show_help, const char *cmd_match) { - char *cmd_name = command_name(c, ' '); - if (NULL == cmd_name) - return ERROR_FAIL; + unsigned int n = 0; + for (const char *s = strchr(c->cmd_name, ' '); s; s = strchr(s + 1, ' ')) + n++; /* If the match string occurs anywhere, we print out * stuff for this command. */ - bool is_match = (strstr(cmd_name, cmd_match) != NULL) || - ((c->usage != NULL) && (strstr(c->usage, cmd_match) != NULL)) || - ((c->help != NULL) && (strstr(c->help, cmd_match) != NULL)); - - if (is_match) { - command_help_show_indent(n); - LOG_USER_N("%s", cmd_name); - } - free(cmd_name); + bool is_match = strstr(c->cmd_name, cmd_match) || + (c->usage && strstr(c->usage, cmd_match)) || + (c->help && strstr(c->help, cmd_match)); if (is_match) { if (c->usage && strlen(c->usage) > 0) { - LOG_USER_N(" "); - command_help_show_wrap(c->usage, 0, n + 5); - } else - LOG_USER_N("\n"); + char *msg = alloc_printf("%s %s", c->cmd_name, c->usage); + command_help_show_wrap(msg, n, n + 5); + free(msg); + } else { + command_help_show_wrap(c->cmd_name, n, n + 5); + } } if (is_match && show_help) { char *msg; + /* TODO: factorize jim_command_mode() to avoid running jim command here */ + char *request = alloc_printf("command mode %s", c->cmd_name); + if (!request) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + int retval = Jim_Eval(CMD_CTX->interp, request); + free(request); + enum command_mode mode = COMMAND_UNKNOWN; + if (retval != JIM_ERR) { + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL); + if (!strcmp(result, "any")) + mode = COMMAND_ANY; + else if (!strcmp(result, "config")) + mode = COMMAND_CONFIG; + else if (!strcmp(result, "exec")) + mode = COMMAND_EXEC; + } + /* Normal commands are runtime-only; highlight exceptions */ - if (c->mode != COMMAND_EXEC) { + if (mode != COMMAND_EXEC) { const char *stage_msg = ""; - switch (c->mode) { + switch (mode) { case COMMAND_CONFIG: stage_msg = " (configuration command)"; break; @@ -895,80 +813,49 @@ static COMMAND_HELPER(command_help_show, struct command *c, unsigned n, stage_msg = " (?mode error?)"; break; } - msg = alloc_printf("%s%s", c->help ? : "", stage_msg); + msg = alloc_printf("%s%s", c->help ? c->help : "", stage_msg); } else - msg = alloc_printf("%s", c->help ? : ""); + msg = alloc_printf("%s", c->help ? c->help : ""); - if (NULL != msg) { + if (msg) { command_help_show_wrap(msg, n + 3, n + 3); free(msg); } else return -ENOMEM; } - if (++n > 5) { - LOG_ERROR("command recursion exceeded"); - return ERROR_FAIL; - } - - return CALL_COMMAND_HANDLER(command_help_show_list, - c->children, n, show_help, cmd_match); + return ERROR_OK; } COMMAND_HANDLER(handle_help_command) { bool full = strcmp(CMD_NAME, "help") == 0; int retval; - struct command *c = CMD_CTX->commands; - char *cmd_match = NULL; - - if (CMD_ARGC == 0) - cmd_match = ""; - else if (CMD_ARGC >= 1) { - unsigned i; - - for (i = 0; i < CMD_ARGC; ++i) { - if (NULL != cmd_match) { - char *prev = cmd_match; - - cmd_match = alloc_printf("%s %s", cmd_match, CMD_ARGV[i]); - free(prev); - if (NULL == cmd_match) { - LOG_ERROR("unable to build search string"); - return -ENOMEM; - } - } else { - cmd_match = alloc_printf("%s", CMD_ARGV[i]); - if (NULL == cmd_match) { - LOG_ERROR("unable to build search string"); - return -ENOMEM; - } - } + char *cmd_match; + + if (CMD_ARGC <= 0) + cmd_match = strdup(""); + + else { + cmd_match = strdup(CMD_ARGV[0]); + + for (unsigned int i = 1; i < CMD_ARGC && cmd_match; ++i) { + char *prev = cmd_match; + cmd_match = alloc_printf("%s %s", prev, CMD_ARGV[i]); + free(prev); } - } else - return ERROR_COMMAND_SYNTAX_ERROR; + } - retval = CALL_COMMAND_HANDLER(command_help_show_list, - c, 0, full, cmd_match); + if (!cmd_match) { + LOG_ERROR("unable to build search string"); + return -ENOMEM; + } + retval = CALL_COMMAND_HANDLER(command_help_show_list, full, cmd_match); - if (CMD_ARGC >= 1) - free(cmd_match); + free(cmd_match); return retval; } -static int command_unknown_find(unsigned argc, Jim_Obj *const *argv, - struct command *head, struct command **out) -{ - if (0 == argc) - return argc; - const char *cmd_name = Jim_GetString(argv[0], NULL); - struct command *c = command_find(head, cmd_name); - if (NULL == c) - return argc; - *out = c; - return command_unknown_find(--argc, ++argv, (*out)->children, out); -} - static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv) { char *prev, *all; @@ -995,75 +882,58 @@ static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv) return all; } -static int run_usage(Jim_Interp *interp, int argc_valid, int argc, Jim_Obj * const *argv) +static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { - struct command_context *cmd_ctx = current_command_context(interp); - char *command; - int retval; - - assert(argc_valid >= 1); - assert(argc >= argc_valid); + /* check subcommands */ + if (argc > 1) { + char *s = alloc_printf("%s %s", Jim_GetString(argv[0], NULL), Jim_GetString(argv[1], NULL)); + Jim_Obj *js = Jim_NewStringObj(interp, s, -1); + Jim_IncrRefCount(js); + free(s); + Jim_Cmd *cmd = Jim_GetCommand(interp, js, JIM_NONE); + if (cmd) { + int retval = Jim_EvalObjPrefix(interp, js, argc - 2, argv + 2); + Jim_DecrRefCount(interp, js); + return retval; + } + Jim_DecrRefCount(interp, js); + } - command = alloc_concatenate_strings(argc_valid, argv); - if (!command) - return JIM_ERR; + script_debug(interp, argc, argv); - retval = command_run_linef(cmd_ctx, "usage %s", command); - if (retval != ERROR_OK) { - LOG_ERROR("unable to execute command \"usage %s\"", command); + struct command *c = jim_to_command(interp); + if (!c->jim_handler && !c->handler) { + Jim_EvalObjPrefix(interp, Jim_NewStringObj(interp, "usage", -1), 1, argv); return JIM_ERR; } - if (argc_valid == argc) - LOG_ERROR("%s: command requires more arguments", command); - else { - free(command); - command = alloc_concatenate_strings(argc - argc_valid, argv + argc_valid); - if (!command) - return JIM_ERR; - LOG_ERROR("invalid subcommand \"%s\"", command); - } + struct command_context *cmd_ctx = current_command_context(interp); - free(command); - return retval; -} + if (!command_can_run(cmd_ctx, c, Jim_GetString(argv[0], NULL))) + return JIM_ERR; -static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - script_debug(interp, argc, argv); + target_call_timer_callbacks(); - struct command_context *cmd_ctx = current_command_context(interp); - struct command *c = cmd_ctx->commands; - int remaining = command_unknown_find(argc, argv, c, &c); - /* if nothing could be consumed, then it's really an unknown command */ - if (remaining == argc) { - const char *cmd = Jim_GetString(argv[0], NULL); - LOG_ERROR("Unknown command:\n %s", cmd); - return JIM_OK; - } + /* + * Black magic of overridden current target: + * If the command we are going to handle has a target prefix, + * override the current target temporarily for the time + * of processing the command. + * current_target_override is used also for event handlers + * therefore we prevent touching it if command has no prefix. + * Previous override is saved and restored back to ensure + * correct work when jim_command_dispatch() is re-entered. + */ + struct target *saved_target_override = cmd_ctx->current_target_override; + if (c->jim_override_target) + cmd_ctx->current_target_override = c->jim_override_target; - Jim_Obj *const *start; - unsigned count; - if (c->handler || c->jim_handler) { - /* include the command name in the list */ - count = remaining + 1; - start = argv + (argc - remaining - 1); - } else { - count = argc - remaining; - start = argv; - run_usage(interp, count, argc, start); - return JIM_ERR; - } - /* pass the command through to the intended handler */ - if (c->jim_handler) { - if (!command_can_run(cmd_ctx, c)) - return JIM_ERR; + int retval = exec_command(interp, cmd_ctx, c, argc, argv); - interp->cmdPrivData = c->jim_handler_data; - return (*c->jim_handler)(interp, count, start); - } + if (c->jim_override_target) + cmd_ctx->current_target_override = saved_target_override; - return script_command_run(interp, count, start, c); + return retval; } static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) @@ -1072,14 +942,27 @@ static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) enum command_mode mode; if (argc > 1) { - struct command *c = cmd_ctx->commands; - int remaining = command_unknown_find(argc - 1, argv + 1, c, &c); - /* if nothing could be consumed, then it's an unknown command */ - if (remaining == argc - 1) { + char *full_name = alloc_concatenate_strings(argc - 1, argv + 1); + if (!full_name) + return JIM_ERR; + Jim_Obj *s = Jim_NewStringObj(interp, full_name, -1); + Jim_IncrRefCount(s); + Jim_Cmd *cmd = Jim_GetCommand(interp, s, JIM_NONE); + Jim_DecrRefCount(interp, s); + free(full_name); + if (!cmd || !(jimcmd_is_proc(cmd) || jimcmd_is_oocd_command(cmd))) { Jim_SetResultString(interp, "unknown", -1); return JIM_OK; } - mode = c->mode; + + if (jimcmd_is_proc(cmd)) { + /* tcl proc */ + mode = COMMAND_ANY; + } else { + struct command *c = jimcmd_privdata(cmd); + + mode = c->mode; + } } else mode = cmd_ctx->mode; @@ -1102,81 +985,104 @@ static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_OK; } -int help_add_command(struct command_context *cmd_ctx, struct command *parent, - const char *cmd_name, const char *help_text, const char *usage) +int help_del_all_commands(struct command_context *cmd_ctx) { - struct command **head = command_list_for_parent(cmd_ctx, parent); - struct command *nc = command_find(*head, cmd_name); - if (NULL == nc) { - /* add a new command with help text */ - struct command_registration cr = { - .name = cmd_name, - .mode = COMMAND_ANY, - .help = help_text, - .usage = usage ? : "", - }; - nc = register_command(cmd_ctx, parent, &cr); - if (NULL == nc) { - LOG_ERROR("failed to add '%s' help text", cmd_name); + struct help_entry *curr, *n; + + list_for_each_entry_safe(curr, n, cmd_ctx->help_list, lh) { + list_del(&curr->lh); + free(curr->cmd_name); + free(curr->help); + free(curr->usage); + free(curr); + } + return ERROR_OK; +} + +static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name) +{ + struct help_entry *curr; + + list_for_each_entry(curr, cmd_ctx->help_list, lh) { + if (!strcmp(cmd_name, curr->cmd_name)) { + list_del(&curr->lh); + free(curr->cmd_name); + free(curr->help); + free(curr->usage); + free(curr); + break; + } + } + + return ERROR_OK; +} + +static int help_add_command(struct command_context *cmd_ctx, + const char *cmd_name, const char *help_text, const char *usage_text) +{ + int cmp = -1; /* add after curr */ + struct help_entry *curr; + + list_for_each_entry_reverse(curr, cmd_ctx->help_list, lh) { + cmp = strcmp(cmd_name, curr->cmd_name); + if (cmp >= 0) + break; + } + + struct help_entry *entry; + if (cmp) { + entry = calloc(1, sizeof(*entry)); + if (!entry) { + LOG_ERROR("Out of memory"); return ERROR_FAIL; } - LOG_DEBUG("added '%s' help text", cmd_name); - return ERROR_OK; + entry->cmd_name = strdup(cmd_name); + if (!entry->cmd_name) { + LOG_ERROR("Out of memory"); + free(entry); + return ERROR_FAIL; + } + list_add(&entry->lh, &curr->lh); + } else { + entry = curr; } + if (help_text) { - bool replaced = false; - if (nc->help) { - free(nc->help); - replaced = true; + char *text = strdup(help_text); + if (!text) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } - nc->help = strdup(help_text); - if (replaced) - LOG_INFO("replaced existing '%s' help", cmd_name); - else - LOG_DEBUG("added '%s' help text", cmd_name); + free(entry->help); + entry->help = text; } - if (usage) { - bool replaced = false; - if (nc->usage) { - if (*nc->usage) - replaced = true; - free(nc->usage); + + if (usage_text) { + char *text = strdup(usage_text); + if (!text) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } - nc->usage = strdup(usage); - if (replaced) - LOG_INFO("replaced existing '%s' usage", cmd_name); - else - LOG_DEBUG("added '%s' usage text", cmd_name); + free(entry->usage); + entry->usage = text; } + return ERROR_OK; } COMMAND_HANDLER(handle_help_add_command) { - if (CMD_ARGC < 2) { - LOG_ERROR("%s: insufficient arguments", CMD_NAME); + if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - } - /* save help text and remove it from argument list */ - const char *str = CMD_ARGV[--CMD_ARGC]; - const char *help = !strcmp(CMD_NAME, "add_help_text") ? str : NULL; - const char *usage = !strcmp(CMD_NAME, "add_usage_text") ? str : NULL; + const char *help = !strcmp(CMD_NAME, "add_help_text") ? CMD_ARGV[1] : NULL; + const char *usage = !strcmp(CMD_NAME, "add_usage_text") ? CMD_ARGV[1] : NULL; if (!help && !usage) { LOG_ERROR("command name '%s' is unknown", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } - /* likewise for the leaf command name */ - const char *cmd_name = CMD_ARGV[--CMD_ARGC]; - - struct command *c = NULL; - if (CMD_ARGC > 0) { - c = CMD_CTX->commands; - int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c); - if (ERROR_OK != retval) - return retval; - } - return help_add_command(CMD_CTX, c, cmd_name, help, usage); + const char *cmd_name = CMD_ARGV[0]; + return help_add_command(CMD_CTX, cmd_name, help, usage); } /* sleep command sleeps for <n> milliseconds @@ -1195,13 +1101,14 @@ COMMAND_HANDLER(handle_sleep_command) unsigned long duration = 0; int retval = parse_ulong(CMD_ARGV[0], &duration); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (!busy) { int64_t then = timeval_ms(); while (timeval_ms() - then < (int64_t)duration) { target_call_timer_callbacks_now(); + keep_alive(); usleep(1000); } } else @@ -1229,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", }, @@ -1243,10 +1150,9 @@ static const struct command_registration command_builtin_handlers[] = { }, { .name = "echo", - .handler = jim_echo, + .handler = handle_echo, .mode = COMMAND_ANY, .help = "Logs a message at \"user\" priority. " - "Output message to stdout. " "Option \"-n\" suppresses trailing newline", .usage = "[-n] string", }, @@ -1303,12 +1209,15 @@ static const struct command_registration command_builtin_handlers[] = { struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp) { struct command_context *context = calloc(1, sizeof(struct command_context)); - const char *HostOs; context->mode = COMMAND_EXEC; + /* context can be duplicated. Put list head on separate mem-chunk to keep list consistent */ + context->help_list = malloc(sizeof(*context->help_list)); + INIT_LIST_HEAD(context->help_list); + /* Create a jim interpreter if we were not handed one */ - if (interp == NULL) { + if (!interp) { /* Create an interpreter */ interp = Jim_CreateInterp(); /* Add all the Jim core commands */ @@ -1318,39 +1227,6 @@ struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp context->interp = interp; - /* Stick to lowercase for HostOS strings. */ -#if defined(_MSC_VER) - /* WinXX - is generic, the forward - * looking problem is this: - * - * "win32" or "win64" - * - * "winxx" is generic. - */ - HostOs = "winxx"; -#elif defined(__linux__) - HostOs = "linux"; -#elif defined(__APPLE__) || defined(__DARWIN__) - HostOs = "darwin"; -#elif defined(__CYGWIN__) - HostOs = "cygwin"; -#elif defined(__MINGW32__) - HostOs = "mingw32"; -#elif defined(__ECOS) - HostOs = "ecos"; -#elif defined(__FreeBSD__) - HostOs = "freebsd"; -#elif defined(__NetBSD__) - HostOs = "netbsd"; -#elif defined(__OpenBSD__) - HostOs = "openbsd"; -#else -#warning "Unrecognized host OS..." - HostOs = "other"; -#endif - Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS", - Jim_NewStringObj(interp, HostOs, strlen(HostOs))); - register_commands(context, NULL, command_builtin_handlers); Jim_SetAssocData(interp, "context", NULL, context); @@ -1371,6 +1247,7 @@ void command_exit(struct command_context *context) return; Jim_FreeInterp(context->interp); + free(context->help_list); command_done(context); } @@ -1408,11 +1285,11 @@ void process_jim_events(struct command_context *cmd_ctx) LOG_ERROR("Invalid command argument"); \ return ERROR_COMMAND_ARGUMENT_INVALID; \ } \ - if ((max == *ul) && (ERANGE == errno)) { \ + if ((max == *ul) && (errno == ERANGE)) { \ LOG_ERROR("Argument overflow"); \ return ERROR_COMMAND_ARGUMENT_OVERFLOW; \ } \ - if (min && (min == *ul) && (ERANGE == errno)) { \ + if (min && (min == *ul) && (errno == ERANGE)) { \ LOG_ERROR("Argument underflow"); \ return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \ } \ @@ -1428,7 +1305,7 @@ DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX) { \ functype n; \ int retval = parse ## funcname(str, &n); \ - if (ERROR_OK != retval) \ + if (retval != ERROR_OK) \ return retval; \ if (n > max) \ return ERROR_COMMAND_ARGUMENT_OVERFLOW; \ diff --git a/src/helper/command.h b/src/helper/command.h index b0c84bb43d..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 @@ -24,8 +13,9 @@ #include <stdint.h> #include <stdbool.h> -#include <jim-nvp.h> +#include <helper/jim-nvp.h> +#include <helper/list.h> #include <helper/types.h> /* To achieve C99 printf compatibility in MinGW, gnu_printf should be @@ -37,10 +27,20 @@ #define PRINTF_ATTRIBUTE_FORMAT printf #endif +/** + * OpenOCD command mode is COMMAND_CONFIG at start, then switches to COMMAND_EXEC + * during the execution of command 'init'. + * The field 'mode' in struct command_registration specifies in which command mode + * the command can be executed: + * - during COMMAND_CONFIG only, + * - during COMMAND_EXEC only, + * - in both modes (COMMAND_ANY). + */ enum command_mode { COMMAND_EXEC, COMMAND_CONFIG, COMMAND_ANY, + COMMAND_UNKNOWN = -1, /* error condition */ }; struct command_context; @@ -52,7 +52,6 @@ typedef int (*command_output_handler_t)(struct command_context *context, struct command_context { Jim_Interp *interp; enum command_mode mode; - struct command *commands; struct target *current_target; /* The target set by 'targets xx' command or the latest created */ struct target *current_target_override; @@ -64,6 +63,7 @@ struct command_context { */ command_output_handler_t output_handler; void *output_handler_priv; + struct list_head *help_list; }; struct command; @@ -79,9 +79,21 @@ struct command_invocation { const char *name; unsigned argc; const char **argv; + Jim_Obj * const *jimtcl_argv; Jim_Obj *output; }; +/** + * Return true if the command @c cmd is registered by OpenOCD. + */ +bool jimcmd_is_oocd_command(Jim_Cmd *cmd); + +/** + * Return the pointer to the command's private data specified during the + * registration of command @a cmd . + */ +void *jimcmd_privdata(Jim_Cmd *cmd); + /** * Command handlers may be defined with more parameters than the base * set provided by command.c. This macro uses C99 magic to allow @@ -142,6 +154,11 @@ struct command_invocation { * 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. @@ -179,22 +196,24 @@ typedef __COMMAND_HANDLER((*command_handler_t)); struct command { char *name; - char *help; - char *usage; - struct command *parent; - struct command *children; command_handler_t handler; Jim_CmdProc *jim_handler; void *jim_handler_data; - /* Currently used only for target of target-prefixed cmd. - * Native OpenOCD commands use jim_handler_data exclusively - * as a target override. - * Jim handlers outside of target cmd tree can use - * jim_handler_data for any handler specific data */ + /* Command handlers can use it for any handler specific data */ + struct target *jim_override_target; + /* Used only for target of target-prefixed cmd */ enum command_mode mode; - struct command *next; }; +/* + * Return the struct command pointer kept in private data + * Used to enforce check on data type + */ +static inline struct command *jim_to_command(Jim_Interp *interp) +{ + return Jim_CmdPrivData(interp); +} + /* * Commands should be registered by filling in one or more of these * structures and passing them to [un]register_commands(). @@ -233,6 +252,10 @@ struct command_registration { /** Use this as the last entry in an array of command_registration records. */ #define COMMAND_REGISTRATION_DONE { .name = NULL, .chain = NULL } +int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, + const struct command_registration *cmds, void *data, + struct target *override_target); + /** * Register one or more commands in the specified context, as children * of @c parent (or top-level commends, if NULL). In a registration's @@ -241,37 +264,77 @@ struct command_registration { * Otherwise, the chained commands are added as children of the command. * * @param cmd_ctx The command_context in which to register the command. - * @param parent Register this command as a child of this, or NULL to + * @param cmd_prefix Register this command as a child of this, or NULL to * register a top-level command. * @param cmds Pointer to an array of command_registration records that * contains the desired command parameters. The last record must have * NULL for all fields. * @returns ERROR_OK on success; ERROR_FAIL if any registration fails. */ -int register_commands(struct command_context *cmd_ctx, struct command *parent, - const struct command_registration *cmds); +static inline int register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, + const struct command_registration *cmds) +{ + return __register_commands(cmd_ctx, cmd_prefix, cmds, NULL, NULL); +} + +/** + * Register one or more commands, as register_commands(), plus specify + * that command should override the current target + * + * @param cmd_ctx The command_context in which to register the command. + * @param cmd_prefix Register this command as a child of this, or NULL to + * register a top-level command. + * @param cmds Pointer to an array of command_registration records that + * contains the desired command parameters. The last record must have + * NULL for all fields. + * @param target The target that has to override current target. + * @returns ERROR_OK on success; ERROR_FAIL if any registration fails. + */ +static inline int register_commands_override_target(struct command_context *cmd_ctx, + const char *cmd_prefix, const struct command_registration *cmds, + struct target *target) +{ + return __register_commands(cmd_ctx, cmd_prefix, cmds, NULL, target); +} + +/** + * Register one or more commands, as register_commands(), plus specify + * a pointer to command private data that would be accessible through + * the macro CMD_DATA. The private data will not be freed when command + * is unregistered. + * + * @param cmd_ctx The command_context in which to register the command. + * @param cmd_prefix Register this command as a child of this, or NULL to + * register a top-level command. + * @param cmds Pointer to an array of command_registration records that + * contains the desired command parameters. The last record must have + * NULL for all fields. + * @param data The command private data. + * @returns ERROR_OK on success; ERROR_FAIL if any registration fails. + */ +static inline int register_commands_with_data(struct command_context *cmd_ctx, + const char *cmd_prefix, const struct command_registration *cmds, + void *data) +{ + return __register_commands(cmd_ctx, cmd_prefix, cmds, data, NULL); +} /** * Unregisters all commands from the specified context. * @param cmd_ctx The context that will be cleared of registered commands. - * @param parent If given, only clear commands from under this one command. + * @param cmd_prefix If given, only clear commands from under this one command. * @returns ERROR_OK on success, or an error code. */ int unregister_all_commands(struct command_context *cmd_ctx, - struct command *parent); - -struct command *command_find_in_context(struct command_context *cmd_ctx, - const char *name); + const char *cmd_prefix); /** - * Update the private command data field for a command and all descendents. - * This is used when creating a new hierarchy of commands that depends - * on obtaining a dynamically created context. The value will be available - * in command handlers by using the CMD_DATA macro. - * @param c The command (group) whose data pointer(s) will be updated. - * @param p The new data pointer to use for the command or its descendents. + * Unregisters the help for all commands. Used at exit to remove the help + * added through the commands 'add_help_text' and 'add_usage_text'. + * @param cmd_ctx The context that will be cleared of registered helps. + * @returns ERROR_OK on success, or an error code. */ -void command_set_handler_data(struct command *c, void *p); +int help_del_all_commands(struct command_context *cmd_ctx); void command_set_output_handler(struct command_context *context, command_output_handler_t output_handler, void *priv); @@ -313,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))); @@ -368,7 +442,7 @@ DECLARE_PARSE_WRAPPER(_target_addr, target_addr_t); #define COMMAND_PARSE_NUMBER(type, in, out) \ do { \ int retval_macro_tmp = parse_ ## type(in, &(out)); \ - if (ERROR_OK != retval_macro_tmp) { \ + if (retval_macro_tmp != ERROR_OK) { \ command_print(CMD, stringify(out) \ " option value ('%s') is not valid", in); \ return retval_macro_tmp; \ @@ -378,6 +452,48 @@ DECLARE_PARSE_WRAPPER(_target_addr, target_addr_t); #define COMMAND_PARSE_ADDRESS(in, out) \ COMMAND_PARSE_NUMBER(target_addr, in, out) +/** + * @brief parses the command argument at position @a argn into @a out + * as a @a type, or prints a command error referring to @a name_str + * and passes the error code to the caller. @a argn will be incremented + * if no error occurred. Otherwise the calling function will return + * the error code produced by the parsing function. + * + * This function may cause the calling function to return immediately, + * so it should be used carefully to avoid leaking resources. In most + * situations, parsing should be completed in full before proceeding + * to allocate resources, and this strategy will most prevents leaks. + */ +#define COMMAND_PARSE_ADDITIONAL_NUMBER(type, argn, out, name_str) \ + do { \ + if (argn+1 >= CMD_ARGC || CMD_ARGV[argn+1][0] == '-') { \ + command_print(CMD, "no " name_str " given"); \ + return ERROR_FAIL; \ + } \ + ++argn; \ + COMMAND_PARSE_NUMBER(type, CMD_ARGV[argn], out); \ + } while (0) + +/** + * @brief parses the command argument at position @a argn into @a out + * as a @a type if the argument @a argn does not start with '-'. + * and passes the error code to the caller. @a argn will be incremented + * if no error occurred. Otherwise the calling function will return + * the error code produced by the parsing function. + * + * This function may cause the calling function to return immediately, + * so it should be used carefully to avoid leaking resources. In most + * situations, parsing should be completed in full before proceeding + * to allocate resources, and this strategy will most prevents leaks. + */ +#define COMMAND_PARSE_OPTIONAL_NUMBER(type, argn, out) \ + do { \ + if (argn+1 < CMD_ARGC && CMD_ARGV[argn+1][0] != '-') { \ + ++argn; \ + COMMAND_PARSE_NUMBER(type, CMD_ARGV[argn], out); \ + } \ + } while (0) + /** * Parse the string @c as a binary parameter, storing the boolean value * in @c out. The strings @c on and @c off are used to match different @@ -388,7 +504,7 @@ DECLARE_PARSE_WRAPPER(_target_addr, target_addr_t); do { \ bool value; \ int retval_macro_tmp = command_parse_bool_arg(in, &value); \ - if (ERROR_OK != retval_macro_tmp) { \ + if (retval_macro_tmp != ERROR_OK) { \ command_print(CMD, stringify(out) \ " option value ('%s') is not valid", in); \ command_print(CMD, " choices are '%s' or '%s'", \ @@ -408,6 +524,4 @@ COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label); #define COMMAND_PARSE_ENABLE(in, out) \ COMMAND_PARSE_BOOL(in, out, "enable", "disable") -void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv); - #endif /* OPENOCD_HELPER_COMMAND_H */ 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 114ad2c6c9..16732eb3dd 100644 --- a/src/helper/configuration.c +++ b/src/helper/configuration.c @@ -1,29 +1,20 @@ +// 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 #include "config.h" #endif #include "configuration.h" #include "log.h" +#include "replacements.h" static size_t num_config_files; static char **config_file_names; @@ -109,7 +100,7 @@ FILE *open_file_from_path(const char *file, const char *mode) return fopen(file, mode); else { char *full_path = find_file(file); - if (full_path == NULL) + if (!full_path) return NULL; FILE *fp = NULL; fp = fopen(full_path, mode); @@ -146,16 +137,18 @@ 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 == NULL) { + if (!home) { #ifdef _WIN32 home = getenv("USERPROFILE"); - if (home == NULL) { - - char homepath[MAX_PATH]; + if (!home) { char *drive = getenv("HOMEDRIVE"); char *path = getenv("HOMEPATH"); if (drive && path) { @@ -171,7 +164,7 @@ char *get_home_dir(const char *append_path) #endif } - if (home == NULL) + if (!home) return home; char *home_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 9dd57e72a1..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 @@ -29,6 +18,7 @@ #include "log.h" #include "configuration.h" #include "fileio.h" +#include "replacements.h" struct fileio { char *url; @@ -197,9 +187,9 @@ int fileio_read_u32(struct fileio *fileio, uint32_t *data) retval = fileio_local_read(fileio, sizeof(uint32_t), buf, &size_read); - if (ERROR_OK == retval && sizeof(uint32_t) != size_read) + if (retval == ERROR_OK && sizeof(uint32_t) != size_read) retval = -EIO; - if (ERROR_OK == retval) + if (retval == ERROR_OK) *data = be_to_h_u32(buf); return retval; @@ -207,7 +197,7 @@ int fileio_read_u32(struct fileio *fileio, uint32_t *data) static int fileio_local_fgets(struct fileio *fileio, size_t size, void *buffer) { - if (fgets(buffer, size, fileio->file) == NULL) + if (!fgets(buffer, size, fileio->file)) return ERROR_FILEIO_OPERATION_FAILED; return ERROR_OK; @@ -251,7 +241,7 @@ int fileio_write_u32(struct fileio *fileio, uint32_t data) retval = fileio_write(fileio, 4, buf, &size_written); - if (ERROR_OK == retval && size_written != sizeof(uint32_t)) + if (retval == ERROR_OK && size_written != sizeof(uint32_t)) retval = -EIO; return retval; diff --git a/src/helper/fileio.h b/src/helper/fileio.h index 02592e28d0..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,24 +9,13 @@ * * * 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 #define OPENOCD_HELPER_FILEIO_H +#include "types.h" + #define FILEIO_MAX_ERROR_STRING (128) enum fileio_type { diff --git a/src/helper/ioutil.c b/src/helper/ioutil.c deleted file mode 100644 index ffdeca898f..0000000000 --- a/src/helper/ioutil.c +++ /dev/null @@ -1,534 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-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 */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "log.h" -#include "time_support.h" - -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef HAVE_DIRENT_H -#include <dirent.h> -#endif -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif -#ifdef HAVE_NET_IF_H -#include <net/if.h> -#endif -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_IFADDRS_H -#include <ifaddrs.h> -#endif -#ifdef HAVE_MALLOC_H -#include <malloc.h> -#endif - -/* loads a file and returns a pointer to it in memory. The file contains - * a 0 byte(sentinel) after len bytes - the length of the file. */ -static int load_file(const char *fileName, char **data, size_t *len) -{ - /* ensure returned length is always sane */ - *len = 0; - - FILE *pFile; - pFile = fopen(fileName, "rb"); - if (pFile == NULL) { - LOG_ERROR("Can't open %s", fileName); - return ERROR_FAIL; - } - if (fseek(pFile, 0, SEEK_END) != 0) { - LOG_ERROR("Can't open %s", fileName); - fclose(pFile); - return ERROR_FAIL; - } - long fsize = ftell(pFile); - if (fsize == -1) { - LOG_ERROR("Can't open %s", fileName); - fclose(pFile); - return ERROR_FAIL; - } - *len = fsize; - - if (fseek(pFile, 0, SEEK_SET) != 0) { - LOG_ERROR("Can't open %s", fileName); - fclose(pFile); - return ERROR_FAIL; - } - *data = malloc(*len + 1); - if (*data == NULL) { - LOG_ERROR("Can't open %s", fileName); - fclose(pFile); - return ERROR_FAIL; - } - - if (fread(*data, 1, *len, pFile) != *len) { - fclose(pFile); - free(*data); - LOG_ERROR("Can't open %s", fileName); - return ERROR_FAIL; - } - fclose(pFile); - - /* 0-byte after buffer (not included in *len) serves as a sentinel */ - (*data)[*len] = 0; - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_cat_command) -{ - if (CMD_ARGC != 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - /* NOTE!!! we only have line printing capability so we print the entire file as a single - * line. */ - char *data; - size_t len; - - int retval = load_file(CMD_ARGV[0], &data, &len); - if (retval == ERROR_OK) { - command_print(CMD, "%s", data); - free(data); - } else - command_print(CMD, "%s not found", CMD_ARGV[0]); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_trunc_command) -{ - if (CMD_ARGC != 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - FILE *config_file = NULL; - config_file = fopen(CMD_ARGV[0], "w"); - if (config_file != NULL) - fclose(config_file); - - return ERROR_OK; -} - -#ifdef HAVE_MALLOC_H -COMMAND_HANDLER(handle_meminfo_command) -{ - static int prev; - struct mallinfo info; - - if (CMD_ARGC != 0) - return ERROR_COMMAND_SYNTAX_ERROR; - - info = mallinfo(); - - if (prev > 0) - command_print(CMD, "Diff: %d", prev - info.fordblks); - prev = info.fordblks; - - command_print(CMD, "Available ram: %d", info.fordblks); - - return ERROR_OK; -} -#endif - -COMMAND_HANDLER(handle_append_command) -{ - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - int retval = ERROR_FAIL; - FILE *config_file = NULL; - - config_file = fopen(CMD_ARGV[0], "a"); - if (config_file != NULL) { - fseek(config_file, 0, SEEK_END); - - unsigned i; - for (i = 1; i < CMD_ARGC; i++) { - if (fwrite(CMD_ARGV[i], 1, strlen(CMD_ARGV[i]), - config_file) != strlen(CMD_ARGV[i])) - break; - if (i != CMD_ARGC - 1) { - if (fwrite(" ", 1, 1, config_file) != 1) - break; - } - } - if ((i == CMD_ARGC) && (fwrite("\n", 1, 1, config_file) == 1)) - retval = ERROR_OK; - - fclose(config_file); - } - - return retval; -} - -COMMAND_HANDLER(handle_cp_command) -{ - if (CMD_ARGC != 2) - return ERROR_COMMAND_SYNTAX_ERROR; - - /* NOTE!!! we only have line printing capability so we print the entire file as a single - * line. */ - char *data; - size_t len; - - int retval = load_file(CMD_ARGV[0], &data, &len); - if (retval != ERROR_OK) - return retval; - - FILE *f = fopen(CMD_ARGV[1], "wb"); - if (f == NULL) - retval = ERROR_COMMAND_SYNTAX_ERROR; - - size_t pos = 0; - for (;; ) { - size_t chunk = len - pos; - static const size_t maxChunk = 512 * 1024; /* ~1/sec */ - if (chunk > maxChunk) - chunk = maxChunk; - - if ((retval == ERROR_OK) && (fwrite(data + pos, 1, chunk, f) != chunk)) - retval = ERROR_COMMAND_SYNTAX_ERROR; - - if (retval != ERROR_OK) - break; - - command_print(CMD, "%zu", len - pos); - - pos += chunk; - - if (pos == len) - break; - } - - if (retval == ERROR_OK) - command_print(CMD, "Copied %s to %s", CMD_ARGV[0], CMD_ARGV[1]); - else - command_print(CMD, "copy failed"); - - free(data); - if (f != NULL) - fclose(f); - - if (retval != ERROR_OK) - unlink(CMD_ARGV[1]); - - return retval; -} - -COMMAND_HANDLER(handle_rm_command) -{ - if (CMD_ARGC != 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - bool del = false; - if (rmdir(CMD_ARGV[0]) == 0) - del = true; - else if (unlink(CMD_ARGV[0]) == 0) - del = true; - - return del ? ERROR_OK : ERROR_FAIL; -} - -static int ioutil_Jim_Command_ls(Jim_Interp *interp, - int argc, - Jim_Obj * const *argv) -{ - if (argc != 2) { - Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?"); - return JIM_ERR; - } - - const char *name = Jim_GetString(argv[1], NULL); - - DIR *dirp = NULL; - dirp = opendir(name); - if (dirp == NULL) - return JIM_ERR; - Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); - - for (;; ) { - struct dirent *entry = NULL; - entry = readdir(dirp); - if (entry == NULL) - break; - - if ((strcmp(".", entry->d_name) == 0) || (strcmp("..", entry->d_name) == 0)) - continue; - - Jim_ListAppendElement(interp, objPtr, - Jim_NewStringObj(interp, entry->d_name, strlen(entry->d_name))); - } - closedir(dirp); - - Jim_SetResult(interp, objPtr); - - return JIM_OK; -} - -static int ioutil_Jim_Command_peek(Jim_Interp *interp, - int argc, - Jim_Obj *const *argv) -{ - if (argc != 2) { - Jim_WrongNumArgs(interp, 1, argv, "peek ?address?"); - return JIM_ERR; - } - - long address; - if (Jim_GetLong(interp, argv[1], &address) != JIM_OK) - return JIM_ERR; - - int value = *((volatile int *) address); - - Jim_SetResult(interp, Jim_NewIntObj(interp, value)); - - return JIM_OK; -} - -static int ioutil_Jim_Command_poke(Jim_Interp *interp, - int argc, - Jim_Obj *const *argv) -{ - if (argc != 3) { - Jim_WrongNumArgs(interp, 1, argv, "poke ?address? ?value?"); - return JIM_ERR; - } - - long address; - if (Jim_GetLong(interp, argv[1], &address) != JIM_OK) - return JIM_ERR; - long value; - if (Jim_GetLong(interp, argv[2], &value) != JIM_OK) - return JIM_ERR; - - *((volatile int *) address) = value; - - return JIM_OK; -} - -/* not so pretty code to fish out ip number*/ -static int ioutil_Jim_Command_ip(Jim_Interp *interp, int argc, - Jim_Obj *const *argv) -{ -#if !defined(__CYGWIN__) - Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0); - - struct ifaddrs *ifa = NULL, *ifp = NULL; - - if (getifaddrs(&ifp) < 0) - return JIM_ERR; - - for (ifa = ifp; ifa; ifa = ifa->ifa_next) { - char ip[200]; - socklen_t salen; - - if (ifa->ifa_addr->sa_family == AF_INET) - salen = sizeof(struct sockaddr_in); - else if (ifa->ifa_addr->sa_family == AF_INET6) - salen = sizeof(struct sockaddr_in6); - else - continue; - - if (getnameinfo(ifa->ifa_addr, salen, ip, sizeof(ip), NULL, 0, - NI_NUMERICHOST) < 0) - continue; - - Jim_AppendString(interp, tclOutput, ip, strlen(ip)); - break; - - } - - freeifaddrs(ifp); -#else - Jim_Obj *tclOutput = Jim_NewStringObj(interp, "fixme!!!", 0); - LOG_ERROR("NOT IMPLEMENTED!!!"); -#endif - Jim_SetResult(interp, tclOutput); - - return JIM_OK; -} - -#ifdef HAVE_SYS_IOCTL_H -#ifdef SIOCGIFHWADDR -/* not so pretty code to fish out eth0 mac address */ -static int ioutil_Jim_Command_mac(Jim_Interp *interp, int argc, - Jim_Obj *const *argv) -{ - struct ifreq *ifr, *ifend; - struct ifreq ifreq; - struct ifconf ifc; - struct ifreq ifs[5]; - int SockFD; - - SockFD = socket(AF_INET, SOCK_DGRAM, 0); - if (SockFD < 0) - return JIM_ERR; - - ifc.ifc_len = sizeof(ifs); - ifc.ifc_req = ifs; - if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0) { - close(SockFD); - return JIM_ERR; - } - - ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq)); - for (ifr = ifc.ifc_req; ifr < ifend; ifr++) { - /* if (ifr->ifr_addr.sa_family == AF_INET) */ - { - if (strcmp("eth0", ifr->ifr_name) != 0) - continue; - strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name) - 1); - if (ioctl(SockFD, SIOCGIFHWADDR, &ifreq) < 0) { - close(SockFD); - return JIM_ERR; - } - - close(SockFD); - - Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0); - - char buffer[256]; - sprintf(buffer, "%02x-%02x-%02x-%02x-%02x-%02x", - ifreq.ifr_hwaddr.sa_data[0]&0xff, - ifreq.ifr_hwaddr.sa_data[1]&0xff, - ifreq.ifr_hwaddr.sa_data[2]&0xff, - ifreq.ifr_hwaddr.sa_data[3]&0xff, - ifreq.ifr_hwaddr.sa_data[4]&0xff, - ifreq.ifr_hwaddr.sa_data[5]&0xff); - - Jim_AppendString(interp, tclOutput, buffer, strlen(buffer)); - - Jim_SetResult(interp, tclOutput); - - return JIM_OK; - } - } - close(SockFD); - - return JIM_ERR; - -} -#endif -#endif - -static const struct command_registration ioutil_command_handlers[] = { - { - .name = "cat", - .handler = handle_cat_command, - .mode = COMMAND_ANY, - .help = "display text file content", - .usage = "file_name", - }, - { - .name = "trunc", - .handler = handle_trunc_command, - .mode = COMMAND_ANY, - .help = "truncate a file to zero length", - .usage = "file_name", - }, - { - .name = "cp", - .handler = handle_cp_command, - .mode = COMMAND_ANY, - .help = "copy a file", - .usage = "src_file_name dst_file_name", - }, - { - .name = "append_file", - .handler = handle_append_command, - .mode = COMMAND_ANY, - .help = "append a variable number of strings to a file", - .usage = "file_name [<string1>, [<string2>, ...]]", - }, -#ifdef HAVE_MALLOC_H - { - .name = "meminfo", - .handler = handle_meminfo_command, - .mode = COMMAND_ANY, - .help = "display free heap space", - .usage = "", - }, -#endif - { - .name = "rm", - .mode = COMMAND_ANY, - .handler = handle_rm_command, - .help = "remove a directory or file", - .usage = "file_name", - }, - - /* - * Peek and poke are security holes -- they manipulate - * server-internal addresses. - */ - - /* jim handlers */ - { - .name = "peek", - .mode = COMMAND_ANY, - .jim_handler = ioutil_Jim_Command_peek, - .help = "peek at a memory address", - .usage = "address", - }, - { - .name = "poke", - .mode = COMMAND_ANY, - .jim_handler = ioutil_Jim_Command_poke, - .help = "poke at a memory address", - .usage = "address value", - }, - { - .name = "ls", - .mode = COMMAND_ANY, - .jim_handler = ioutil_Jim_Command_ls, - .help = "show a listing of files", - .usage = "dirname", - }, -#ifdef HAVE_SYS_IOCTL_H -#ifdef SIOCGIFHWADDR - { - .name = "mac", - .mode = COMMAND_ANY, - .jim_handler = ioutil_Jim_Command_mac, - .help = "show MAC address", - }, -#endif -#endif - { - .name = "ip", - .jim_handler = ioutil_Jim_Command_ip, - .mode = COMMAND_ANY, - .help = "show IP address", - }, - COMMAND_REGISTRATION_DONE -}; - -int ioutil_init(struct command_context *cmd_ctx) -{ - return register_commands(cmd_ctx, NULL, ioutil_command_handlers); -} diff --git a/src/helper/ioutil.h b/src/helper/ioutil.h deleted file mode 100644 index f060aab090..0000000000 --- a/src/helper/ioutil.h +++ /dev/null @@ -1,25 +0,0 @@ -/*************************************************************************** - * 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_HELPER_IOUTIL_H -#define OPENOCD_HELPER_IOUTIL_H - -struct command_context; - -int ioutil_init(struct command_context *cmd_ctx); - -#endif /* OPENOCD_HELPER_IOUTIL_H */ diff --git a/src/helper/ioutil_stubs.c b/src/helper/ioutil_stubs.c deleted file mode 100644 index 0d81fe665e..0000000000 --- a/src/helper/ioutil_stubs.c +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - * 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 "ioutil.h" -#include "log.h" - -int ioutil_init(struct command_context *cmd_ctx) -{ - LOG_DEBUG("libocdhelper was built without I/O utility support"); - return ERROR_OK; -} diff --git a/src/helper/jep106.c b/src/helper/jep106.c index 33dc61c91b..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 @@ -27,7 +16,7 @@ static const char * const jep106[][126] = { #include "jep106.inc" }; -const char *jep106_manufacturer(unsigned bank, unsigned id) +const char *jep106_table_manufacturer(unsigned int bank, unsigned int id) { if (id < 1 || id > 126) { LOG_DEBUG("BUG: Caller passed out-of-range JEP106 ID!"); @@ -37,7 +26,7 @@ const char *jep106_manufacturer(unsigned bank, unsigned 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 08445803e7..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 @@ -27,6 +16,11 @@ * manufacturer associated with bank and id, or one of the strings * "<invalid>" and "<unknown>". */ -const char *jep106_manufacturer(unsigned bank, unsigned id); +const char *jep106_table_manufacturer(unsigned int bank, unsigned int id); + +static inline const char *jep106_manufacturer(unsigned int manufacturer) +{ + return jep106_table_manufacturer(manufacturer >> 7, manufacturer & 0x7f); +} #endif /* OPENOCD_HELPER_JEP106_H */ diff --git a/src/helper/jep106.inc b/src/helper/jep106.inc index c0295a603d..958dc4ea4d 100644 --- a/src/helper/jep106.inc +++ b/src/helper/jep106.inc @@ -1,4 +1,17 @@ -/* Autogenerated with update_jep106.pl*/ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * 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", @@ -22,7 +35,7 @@ [0][0x15 - 1] = "NXP (Philips)", [0][0x16 - 1] = "Synertek", [0][0x17 - 1] = "Texas Instruments", -[0][0x18 - 1] = "Toshiba", +[0][0x18 - 1] = "Kioxia Corporation", [0][0x19 - 1] = "Xicor", [0][0x1a - 1] = "Zilog", [0][0x1b - 1] = "Eurotechnique", @@ -39,8 +52,8 @@ [0][0x26 - 1] = "Visic", [0][0x27 - 1] = "Intl. CMOS Technology", [0][0x28 - 1] = "SSSI", -[0][0x29 - 1] = "MicrochipTechnology", -[0][0x2a - 1] = "Ricoh Ltd.", +[0][0x29 - 1] = "Microchip Technology", +[0][0x2a - 1] = "Ricoh Ltd", [0][0x2b - 1] = "VLSI", [0][0x2c - 1] = "Micron Technology", [0][0x2d - 1] = "SK Hynix", @@ -67,7 +80,7 @@ [0][0x42 - 1] = "Macronix", [0][0x43 - 1] = "Xerox", [0][0x44 - 1] = "Plus Logic", -[0][0x45 - 1] = "SanDisk Corporation", +[0][0x45 - 1] = "Western Digital Technologies Inc", [0][0x46 - 1] = "Elan Circuit Tech.", [0][0x47 - 1] = "European Silicon Str.", [0][0x48 - 1] = "Apple Computer", @@ -75,12 +88,12 @@ [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", [0][0x51 - 1] = "Crosspoint Solutions", -[0][0x52 - 1] = "Alliance Semiconductor", +[0][0x52 - 1] = "Alliance Memory Inc", [0][0x53 - 1] = "Tandem", [0][0x54 - 1] = "Hewlett-Packard", [0][0x55 - 1] = "Integrated Silicon Solutions", @@ -138,11 +151,11 @@ [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", -[1][0x12 - 1] = "United Microelectronics Corp.", +[1][0x12 - 1] = "United Microelectronics Corp", [1][0x13 - 1] = "TCSI", [1][0x14 - 1] = "Smart Modular", [1][0x15 - 1] = "Hughes Aircraft", @@ -156,7 +169,7 @@ [1][0x1d - 1] = "Integrated Silicon Solution (ISSI)", [1][0x1e - 1] = "DoD", [1][0x1f - 1] = "Integ. Memories Tech.", -[1][0x20 - 1] = "Corollary Inc.", +[1][0x20 - 1] = "Corollary Inc", [1][0x21 - 1] = "Dallas Semiconductor", [1][0x22 - 1] = "Omnivision", [1][0x23 - 1] = "EIV(Switzerland)", @@ -171,18 +184,18 @@ [1][0x2c - 1] = "Celestica", [1][0x2d - 1] = "Century", [1][0x2e - 1] = "Hal Computers", -[1][0x2f - 1] = "Rohm Company Ltd.", +[1][0x2f - 1] = "Rohm Company Ltd", [1][0x30 - 1] = "Juniper Networks", [1][0x31 - 1] = "Libit Signal Processing", [1][0x32 - 1] = "Mushkin Enhanced Memory", [1][0x33 - 1] = "Tundra Semiconductor", -[1][0x34 - 1] = "Adaptec Inc.", +[1][0x34 - 1] = "Adaptec Inc", [1][0x35 - 1] = "LightSpeed Semi.", -[1][0x36 - 1] = "ZSP Corp.", +[1][0x36 - 1] = "ZSP Corp", [1][0x37 - 1] = "AMIC Technology", [1][0x38 - 1] = "Adobe Systems", [1][0x39 - 1] = "Dynachip", -[1][0x3a - 1] = "PNY Technologies, Inc.", +[1][0x3a - 1] = "PNY Technologies Inc", [1][0x3b - 1] = "Newport Digital", [1][0x3c - 1] = "MMC Networks", [1][0x3d - 1] = "T Square", @@ -194,8 +207,8 @@ [1][0x43 - 1] = "Suwa Electronics", [1][0x44 - 1] = "Transmeta", [1][0x45 - 1] = "Micron CMS", -[1][0x46 - 1] = "American Computer & Digital", -[1][0x47 - 1] = "Enhance 3000 Inc.", +[1][0x46 - 1] = "American Computer & Digital Components Inc", +[1][0x47 - 1] = "Enhance 3000 Inc", [1][0x48 - 1] = "Tower Semiconductor", [1][0x49 - 1] = "CPU Design", [1][0x4a - 1] = "Price Point", @@ -205,19 +218,19 @@ [1][0x4e - 1] = "Unigen Corporation", [1][0x4f - 1] = "Transcend Information", [1][0x50 - 1] = "Memory Card Technology", -[1][0x51 - 1] = "CKD Corporation Ltd.", -[1][0x52 - 1] = "Capital Instruments, Inc.", -[1][0x53 - 1] = "Aica Kogyo, Ltd.", +[1][0x51 - 1] = "CKD Corporation Ltd", +[1][0x52 - 1] = "Capital Instruments Inc", +[1][0x53 - 1] = "Aica Kogyo Ltd", [1][0x54 - 1] = "Linvex Technology", [1][0x55 - 1] = "MSC Vertriebs GmbH", -[1][0x56 - 1] = "AKM Company, Ltd.", -[1][0x57 - 1] = "Dynamem, Inc.", +[1][0x56 - 1] = "AKM Company Ltd", +[1][0x57 - 1] = "Dynamem Inc", [1][0x58 - 1] = "NERA ASA", [1][0x59 - 1] = "GSI Technology", [1][0x5a - 1] = "Dane-Elec (C Memory)", [1][0x5b - 1] = "Acorn Computers", [1][0x5c - 1] = "Lara Technology", -[1][0x5d - 1] = "Oak Technology, Inc.", +[1][0x5d - 1] = "Oak Technology Inc", [1][0x5e - 1] = "Itec Memory", [1][0x5f - 1] = "Tanisys Technology", [1][0x60 - 1] = "Truevision", @@ -234,7 +247,7 @@ [1][0x6b - 1] = "Goldenram", [1][0x6c - 1] = "Clear Logic", [1][0x6d - 1] = "Cimaron Communications", -[1][0x6e - 1] = "Nippon Steel Semi. Corp.", +[1][0x6e - 1] = "Nippon Steel Semi. Corp", [1][0x6f - 1] = "Advantage Memory", [1][0x70 - 1] = "AMCC", [1][0x71 - 1] = "LeCroy", @@ -245,7 +258,7 @@ [1][0x76 - 1] = "Advanced Fibre", [1][0x77 - 1] = "BF Goodrich Data.", [1][0x78 - 1] = "Epigram", -[1][0x79 - 1] = "Acbel Polytech Inc.", +[1][0x79 - 1] = "Acbel Polytech Inc", [1][0x7a - 1] = "Apacer Technology", [1][0x7b - 1] = "Admor Memory", [1][0x7c - 1] = "FOXCONN", @@ -260,7 +273,7 @@ [2][0x07 - 1] = "MOSAID Technologies", [2][0x08 - 1] = "Ardent Technologies", [2][0x09 - 1] = "Switchcore", -[2][0x0a - 1] = "Cisco Systems, Inc.", +[2][0x0a - 1] = "Cisco Systems Inc", [2][0x0b - 1] = "Allayer Technologies", [2][0x0c - 1] = "WorkX AG (Wichman)", [2][0x0d - 1] = "Oasis Semiconductor", @@ -281,9 +294,9 @@ [2][0x1c - 1] = "Sanmina Corporation", [2][0x1d - 1] = "HADCO Corporation", [2][0x1e - 1] = "Corsair", -[2][0x1f - 1] = "Actrans System Inc.", +[2][0x1f - 1] = "Actrans System Inc", [2][0x20 - 1] = "ALPHA Technologies", -[2][0x21 - 1] = "Silicon Laboratories, Inc. (Cygnal)", +[2][0x21 - 1] = "Silicon Laboratories Inc (Cygnal)", [2][0x22 - 1] = "Artesyn Technologies", [2][0x23 - 1] = "Align Manufacturing", [2][0x24 - 1] = "Peregrine Semiconductor", @@ -300,7 +313,7 @@ [2][0x2f - 1] = "Siemens AG", [2][0x30 - 1] = "Sarnoff Corporation", [2][0x31 - 1] = "Itautec SA", -[2][0x32 - 1] = "Radiata Inc.", +[2][0x32 - 1] = "Radiata Inc", [2][0x33 - 1] = "Benchmark Elect. (AVEX)", [2][0x34 - 1] = "Legend", [2][0x35 - 1] = "SpecTek Incorporated", @@ -330,7 +343,7 @@ [2][0x4d - 1] = "Element 14", [2][0x4e - 1] = "Pycon", [2][0x4f - 1] = "Saifun Semiconductors", -[2][0x50 - 1] = "Sibyte, Incorporated", +[2][0x50 - 1] = "Sibyte Incorporated", [2][0x51 - 1] = "MetaLink Technologies", [2][0x52 - 1] = "Feiya Technology", [2][0x53 - 1] = "I & C Technology", @@ -438,7 +451,7 @@ [3][0x3b - 1] = "Concept Computer", [3][0x3c - 1] = "SILCOM", [3][0x3d - 1] = "3Dlabs", -[3][0x3e - 1] = "c’t Magazine", +[3][0x3e - 1] = "c't Magazine", [3][0x3f - 1] = "Sanera Systems", [3][0x40 - 1] = "Silicon Packets", [3][0x41 - 1] = "Viasystems Group", @@ -470,7 +483,7 @@ [3][0x5b - 1] = "Nazomi Communications", [3][0x5c - 1] = "eWave System", [3][0x5d - 1] = "Rockwell Collins", -[3][0x5e - 1] = "Picocel Co. Ltd. (Paion)", +[3][0x5e - 1] = "Picocel Co Ltd (Paion)", [3][0x5f - 1] = "Alphamosaic Ltd", [3][0x60 - 1] = "Sandburst", [3][0x61 - 1] = "SiCon Video", @@ -521,20 +534,20 @@ [4][0x10 - 1] = "Scaleo Chip", [4][0x11 - 1] = "Potentia Power Systems", [4][0x12 - 1] = "C-guys Incorporated", -[4][0x13 - 1] = "Digital Communications Technology", +[4][0x13 - 1] = "Digital Communications Technology Inc", [4][0x14 - 1] = "Silicon-Based Technology", [4][0x15 - 1] = "Fulcrum Microsystems", [4][0x16 - 1] = "Positivo Informatica Ltd", [4][0x17 - 1] = "XIOtech Corporation", [4][0x18 - 1] = "PortalPlayer", [4][0x19 - 1] = "Zhiying Software", -[4][0x1a - 1] = "ParkerVision, Inc.", +[4][0x1a - 1] = "ParkerVision Inc", [4][0x1b - 1] = "Phonex Broadband", [4][0x1c - 1] = "Skyworks Solutions", [4][0x1d - 1] = "Entropic Communications", -[4][0x1e - 1] = "I’M Intelligent Memory Ltd.", +[4][0x1e - 1] = "I'M Intelligent Memory Ltd", [4][0x1f - 1] = "Zensys A/S", -[4][0x20 - 1] = "Legend Silicon Corp.", +[4][0x20 - 1] = "Legend Silicon Corp", [4][0x21 - 1] = "Sci-worx GmbH", [4][0x22 - 1] = "SMSC (Standard Microsystems)", [4][0x23 - 1] = "Renesas Electronics", @@ -543,7 +556,7 @@ [4][0x26 - 1] = "MediaTek", [4][0x27 - 1] = "Non-cents Productions", [4][0x28 - 1] = "US Modular", -[4][0x29 - 1] = "Wintegra Ltd.", +[4][0x29 - 1] = "Wintegra Ltd", [4][0x2a - 1] = "Mathstar", [4][0x2b - 1] = "StarCore", [4][0x2c - 1] = "Oplus Technologies", @@ -559,9 +572,9 @@ [4][0x36 - 1] = "SolusTek", [4][0x37 - 1] = "Kongsberg Maritime", [4][0x38 - 1] = "Faraday Technology", -[4][0x39 - 1] = "Altium Ltd.", +[4][0x39 - 1] = "Altium Ltd", [4][0x3a - 1] = "Insyte", -[4][0x3b - 1] = "ARM Ltd.", +[4][0x3b - 1] = "ARM Ltd", [4][0x3c - 1] = "DigiVision", [4][0x3d - 1] = "Vativ Technologies", [4][0x3e - 1] = "Endicott Interconnect Technologies", @@ -583,7 +596,7 @@ [4][0x4e - 1] = "Quanta Computer", [4][0x4f - 1] = "Yield Microelectronics", [4][0x50 - 1] = "Afa Technologies", -[4][0x51 - 1] = "KINGBOX Technology Co. Ltd.", +[4][0x51 - 1] = "KINGBOX Technology Co Ltd", [4][0x52 - 1] = "Ceva", [4][0x53 - 1] = "iStor Networks", [4][0x54 - 1] = "Advance Modules", @@ -598,149 +611,149 @@ [4][0x5d - 1] = "Adimos", [4][0x5e - 1] = "SiGe Semiconductor", [4][0x5f - 1] = "Fodus Communications", -[4][0x60 - 1] = "Credence Systems Corp.", -[4][0x61 - 1] = "Genesis Microchip Inc.", -[4][0x62 - 1] = "Vihana, Inc.", +[4][0x60 - 1] = "Credence Systems Corp", +[4][0x61 - 1] = "Genesis Microchip Inc", +[4][0x62 - 1] = "Vihana Inc", [4][0x63 - 1] = "WIS Technologies", [4][0x64 - 1] = "GateChange Technologies", [4][0x65 - 1] = "High Density Devices AS", [4][0x66 - 1] = "Synopsys", [4][0x67 - 1] = "Gigaram", -[4][0x68 - 1] = "Enigma Semiconductor Inc.", -[4][0x69 - 1] = "Century Micro Inc.", +[4][0x68 - 1] = "Enigma Semiconductor Inc", +[4][0x69 - 1] = "Century Micro Inc", [4][0x6a - 1] = "Icera Semiconductor", [4][0x6b - 1] = "Mediaworks Integrated Systems", -[4][0x6c - 1] = "O’Neil Product Development", -[4][0x6d - 1] = "Supreme Top Technology Ltd.", +[4][0x6c - 1] = "O'Neil Product Development", +[4][0x6d - 1] = "Supreme Top Technology Ltd", [4][0x6e - 1] = "MicroDisplay Corporation", -[4][0x6f - 1] = "Team Group Inc.", +[4][0x6f - 1] = "Team Group Inc", [4][0x70 - 1] = "Sinett Corporation", [4][0x71 - 1] = "Toshiba Corporation", [4][0x72 - 1] = "Tensilica", [4][0x73 - 1] = "SiRF Technology", -[4][0x74 - 1] = "Bacoc Inc.", +[4][0x74 - 1] = "Bacoc Inc", [4][0x75 - 1] = "SMaL Camera Technologies", [4][0x76 - 1] = "Thomson SC", [4][0x77 - 1] = "Airgo Networks", -[4][0x78 - 1] = "Wisair Ltd.", +[4][0x78 - 1] = "Wisair Ltd", [4][0x79 - 1] = "SigmaTel", [4][0x7a - 1] = "Arkados", -[4][0x7b - 1] = "Compete IT gmbH Co. KG", -[4][0x7c - 1] = "Eudar Technology Inc.", +[4][0x7b - 1] = "Compete IT gmbH Co KG", +[4][0x7c - 1] = "Eudar Technology Inc", [4][0x7d - 1] = "Focus Enhancements", [4][0x7e - 1] = "Xyratex", [5][0x01 - 1] = "Specular Networks", [5][0x02 - 1] = "Patriot Memory (PDP Systems)", -[5][0x03 - 1] = "U-Chip Technology Corp.", +[5][0x03 - 1] = "U-Chip Technology Corp", [5][0x04 - 1] = "Silicon Optix", [5][0x05 - 1] = "Greenfield Networks", [5][0x06 - 1] = "CompuRAM GmbH", -[5][0x07 - 1] = "Stargen, Inc.", +[5][0x07 - 1] = "Stargen Inc", [5][0x08 - 1] = "NetCell Corporation", [5][0x09 - 1] = "Excalibrus Technologies Ltd", [5][0x0a - 1] = "SCM Microsystems", -[5][0x0b - 1] = "Xsigo Systems, Inc.", +[5][0x0b - 1] = "Xsigo Systems Inc", [5][0x0c - 1] = "CHIPS & Systems Inc", [5][0x0d - 1] = "Tier 1 Multichip Solutions", [5][0x0e - 1] = "CWRL Labs", [5][0x0f - 1] = "Teradici", -[5][0x10 - 1] = "Gigaram, Inc.", +[5][0x10 - 1] = "Gigaram Inc", [5][0x11 - 1] = "g2 Microsystems", [5][0x12 - 1] = "PowerFlash Semiconductor", -[5][0x13 - 1] = "P.A. Semi, Inc.", -[5][0x14 - 1] = "NovaTech Solutions, S.A.", -[5][0x15 - 1] = "c2 Microsystems, Inc.", +[5][0x13 - 1] = "P.A. Semi Inc", +[5][0x14 - 1] = "NovaTech Solutions S.A.", +[5][0x15 - 1] = "c2 Microsystems Inc", [5][0x16 - 1] = "Level5 Networks", [5][0x17 - 1] = "COS Memory AG", [5][0x18 - 1] = "Innovasic Semiconductor", -[5][0x19 - 1] = "02IC Co. Ltd", -[5][0x1a - 1] = "Tabula, Inc.", +[5][0x19 - 1] = "02IC Co Ltd", +[5][0x1a - 1] = "Tabula Inc", [5][0x1b - 1] = "Crucial Technology", [5][0x1c - 1] = "Chelsio Communications", [5][0x1d - 1] = "Solarflare Communications", -[5][0x1e - 1] = "Xambala Inc.", +[5][0x1e - 1] = "Xambala Inc", [5][0x1f - 1] = "EADS Astrium", -[5][0x20 - 1] = "Terra Semiconductor, Inc.", -[5][0x21 - 1] = "Imaging Works, Inc.", -[5][0x22 - 1] = "Astute Networks, Inc.", +[5][0x20 - 1] = "Terra Semiconductor Inc", +[5][0x21 - 1] = "Imaging Works Inc", +[5][0x22 - 1] = "Astute Networks Inc", [5][0x23 - 1] = "Tzero", [5][0x24 - 1] = "Emulex", [5][0x25 - 1] = "Power-One", -[5][0x26 - 1] = "Pulse~LINK Inc.", +[5][0x26 - 1] = "Pulse~LINK Inc", [5][0x27 - 1] = "Hon Hai Precision Industry", -[5][0x28 - 1] = "White Rock Networks Inc.", -[5][0x29 - 1] = "Telegent Systems USA, Inc.", -[5][0x2a - 1] = "Atrua Technologies, Inc.", -[5][0x2b - 1] = "Acbel Polytech Inc.", -[5][0x2c - 1] = "eRide Inc.", -[5][0x2d - 1] = "ULi Electronics Inc.", -[5][0x2e - 1] = "Magnum Semiconductor Inc.", -[5][0x2f - 1] = "neoOne Technology, Inc.", -[5][0x30 - 1] = "Connex Technology, Inc.", -[5][0x31 - 1] = "Stream Processors, Inc.", +[5][0x28 - 1] = "White Rock Networks Inc", +[5][0x29 - 1] = "Telegent Systems USA Inc", +[5][0x2a - 1] = "Atrua Technologies Inc", +[5][0x2b - 1] = "Acbel Polytech Inc", +[5][0x2c - 1] = "eRide Inc", +[5][0x2d - 1] = "ULi Electronics Inc", +[5][0x2e - 1] = "Magnum Semiconductor Inc", +[5][0x2f - 1] = "neoOne Technology Inc", +[5][0x30 - 1] = "Connex Technology Inc", +[5][0x31 - 1] = "Stream Processors Inc", [5][0x32 - 1] = "Focus Enhancements", -[5][0x33 - 1] = "Telecis Wireless, Inc.", +[5][0x33 - 1] = "Telecis Wireless Inc", [5][0x34 - 1] = "uNav Microelectronics", -[5][0x35 - 1] = "Tarari, Inc.", -[5][0x36 - 1] = "Ambric, Inc.", -[5][0x37 - 1] = "Newport Media, Inc.", +[5][0x35 - 1] = "Tarari Inc", +[5][0x36 - 1] = "Ambric Inc", +[5][0x37 - 1] = "Newport Media Inc", [5][0x38 - 1] = "VMTS", -[5][0x39 - 1] = "Enuclia Semiconductor, Inc.", -[5][0x3a - 1] = "Virtium Technology Inc.", -[5][0x3b - 1] = "Solid State System Co., Ltd.", +[5][0x39 - 1] = "Enuclia Semiconductor Inc", +[5][0x3a - 1] = "Virtium Technology Inc", +[5][0x3b - 1] = "Solid State System Co Ltd", [5][0x3c - 1] = "Kian Tech LLC", [5][0x3d - 1] = "Artimi", [5][0x3e - 1] = "Power Quotient International", [5][0x3f - 1] = "Avago Technologies", [5][0x40 - 1] = "ADTechnology", [5][0x41 - 1] = "Sigma Designs", -[5][0x42 - 1] = "SiCortex, Inc.", +[5][0x42 - 1] = "SiCortex Inc", [5][0x43 - 1] = "Ventura Technology Group", [5][0x44 - 1] = "eASIC", [5][0x45 - 1] = "M.H.S. SAS", [5][0x46 - 1] = "Micro Star International", -[5][0x47 - 1] = "Rapport Inc.", +[5][0x47 - 1] = "Rapport Inc", [5][0x48 - 1] = "Makway International", -[5][0x49 - 1] = "Broad Reach Engineering Co.", +[5][0x49 - 1] = "Broad Reach Engineering Co", [5][0x4a - 1] = "Semiconductor Mfg Intl Corp", [5][0x4b - 1] = "SiConnect", -[5][0x4c - 1] = "FCI USA Inc.", +[5][0x4c - 1] = "FCI USA Inc", [5][0x4d - 1] = "Validity Sensors", -[5][0x4e - 1] = "Coney Technology Co. Ltd.", +[5][0x4e - 1] = "Coney Technology Co Ltd", [5][0x4f - 1] = "Spans Logic", -[5][0x50 - 1] = "Neterion Inc.", +[5][0x50 - 1] = "Neterion Inc", [5][0x51 - 1] = "Qimonda", -[5][0x52 - 1] = "New Japan Radio Co. Ltd.", +[5][0x52 - 1] = "New Japan Radio Co Ltd", [5][0x53 - 1] = "Velogix", [5][0x54 - 1] = "Montalvo Systems", -[5][0x55 - 1] = "iVivity Inc.", +[5][0x55 - 1] = "iVivity Inc", [5][0x56 - 1] = "Walton Chaintech", [5][0x57 - 1] = "AENEON", -[5][0x58 - 1] = "Lorom Industrial Co. Ltd.", +[5][0x58 - 1] = "Lorom Industrial Co Ltd", [5][0x59 - 1] = "Radiospire Networks", -[5][0x5a - 1] = "Sensio Technologies, Inc.", +[5][0x5a - 1] = "Sensio Technologies Inc", [5][0x5b - 1] = "Nethra Imaging", [5][0x5c - 1] = "Hexon Technology Pte Ltd", [5][0x5d - 1] = "CompuStocx (CSX)", -[5][0x5e - 1] = "Methode Electronics, Inc.", -[5][0x5f - 1] = "Connect One Ltd.", +[5][0x5e - 1] = "Methode Electronics Inc", +[5][0x5f - 1] = "Connect One Ltd", [5][0x60 - 1] = "Opulan Technologies", [5][0x61 - 1] = "Septentrio NV", -[5][0x62 - 1] = "Goldenmars Technology Inc.", +[5][0x62 - 1] = "Goldenmars Technology Inc", [5][0x63 - 1] = "Kreton Corporation", -[5][0x64 - 1] = "Cochlear Ltd.", +[5][0x64 - 1] = "Cochlear Ltd", [5][0x65 - 1] = "Altair Semiconductor", -[5][0x66 - 1] = "NetEffect, Inc.", -[5][0x67 - 1] = "Spansion, Inc.", +[5][0x66 - 1] = "NetEffect Inc", +[5][0x67 - 1] = "Spansion Inc", [5][0x68 - 1] = "Taiwan Semiconductor Mfg", -[5][0x69 - 1] = "Emphany Systems Inc.", +[5][0x69 - 1] = "Emphany Systems Inc", [5][0x6a - 1] = "ApaceWave Technologies", [5][0x6b - 1] = "Mobilygen Corporation", [5][0x6c - 1] = "Tego", [5][0x6d - 1] = "Cswitch Corporation", -[5][0x6e - 1] = "Haier (Beijing) IC Design Co.", +[5][0x6e - 1] = "Haier (Beijing) IC Design Co", [5][0x6f - 1] = "MetaRAM", -[5][0x70 - 1] = "Axel Electronics Co. Ltd.", +[5][0x70 - 1] = "Axel Electronics Co Ltd", [5][0x71 - 1] = "Tilera Corporation", [5][0x72 - 1] = "Aquantia", [5][0x73 - 1] = "Vivace Semiconductor", @@ -748,197 +761,197 @@ [5][0x75 - 1] = "Octalica", [5][0x76 - 1] = "InterDigital Communications", [5][0x77 - 1] = "Avant Technology", -[5][0x78 - 1] = "Asrock, Inc.", +[5][0x78 - 1] = "Asrock Inc", [5][0x79 - 1] = "Availink", -[5][0x7a - 1] = "Quartics, Inc.", +[5][0x7a - 1] = "Quartics Inc", [5][0x7b - 1] = "Element CXI", [5][0x7c - 1] = "Innovaciones Microelectronicas", [5][0x7d - 1] = "VeriSilicon Microelectronics", [5][0x7e - 1] = "W5 Networks", [6][0x01 - 1] = "MOVEKING", -[6][0x02 - 1] = "Mavrix Technology, Inc.", -[6][0x03 - 1] = "CellGuide Ltd.", +[6][0x02 - 1] = "Mavrix Technology Inc", +[6][0x03 - 1] = "CellGuide Ltd", [6][0x04 - 1] = "Faraday Technology", -[6][0x05 - 1] = "Diablo Technologies, Inc.", +[6][0x05 - 1] = "Diablo Technologies Inc", [6][0x06 - 1] = "Jennic", [6][0x07 - 1] = "Octasic", [6][0x08 - 1] = "Molex Incorporated", [6][0x09 - 1] = "3Leaf Networks", [6][0x0a - 1] = "Bright Micron Technology", [6][0x0b - 1] = "Netxen", -[6][0x0c - 1] = "NextWave Broadband Inc.", +[6][0x0c - 1] = "NextWave Broadband Inc", [6][0x0d - 1] = "DisplayLink", [6][0x0e - 1] = "ZMOS Technology", [6][0x0f - 1] = "Tec-Hill", -[6][0x10 - 1] = "Multigig, Inc.", +[6][0x10 - 1] = "Multigig Inc", [6][0x11 - 1] = "Amimon", -[6][0x12 - 1] = "Euphonic Technologies, Inc.", +[6][0x12 - 1] = "Euphonic Technologies Inc", [6][0x13 - 1] = "BRN Phoenix", [6][0x14 - 1] = "InSilica", [6][0x15 - 1] = "Ember Corporation", [6][0x16 - 1] = "Avexir Technologies Corporation", [6][0x17 - 1] = "Echelon Corporation", [6][0x18 - 1] = "Edgewater Computer Systems", -[6][0x19 - 1] = "XMOS Semiconductor Ltd.", -[6][0x1a - 1] = "GENUSION, Inc.", +[6][0x19 - 1] = "XMOS Semiconductor Ltd", +[6][0x1a - 1] = "GENUSION Inc", [6][0x1b - 1] = "Memory Corp NV", [6][0x1c - 1] = "SiliconBlue Technologies", -[6][0x1d - 1] = "Rambus Inc.", +[6][0x1d - 1] = "Rambus Inc", [6][0x1e - 1] = "Andes Technology Corporation", [6][0x1f - 1] = "Coronis Systems", [6][0x20 - 1] = "Achronix Semiconductor", -[6][0x21 - 1] = "Siano Mobile Silicon Ltd.", +[6][0x21 - 1] = "Siano Mobile Silicon Ltd", [6][0x22 - 1] = "Semtech Corporation", -[6][0x23 - 1] = "Pixelworks Inc.", +[6][0x23 - 1] = "Pixelworks Inc", [6][0x24 - 1] = "Gaisler Research AB", [6][0x25 - 1] = "Teranetics", -[6][0x26 - 1] = "Toppan Printing Co. Ltd.", +[6][0x26 - 1] = "Toppan Printing Co Ltd", [6][0x27 - 1] = "Kingxcon", [6][0x28 - 1] = "Silicon Integrated Systems", -[6][0x29 - 1] = "I-O Data Device, Inc.", -[6][0x2a - 1] = "NDS Americas Inc.", +[6][0x29 - 1] = "I-O Data Device Inc", +[6][0x2a - 1] = "NDS Americas Inc", [6][0x2b - 1] = "Solomon Systech Limited", [6][0x2c - 1] = "On Demand Microelectronics", -[6][0x2d - 1] = "Amicus Wireless Inc.", +[6][0x2d - 1] = "Amicus Wireless Inc", [6][0x2e - 1] = "SMARDTV SNC", -[6][0x2f - 1] = "Comsys Communication Ltd.", -[6][0x30 - 1] = "Movidia Ltd.", -[6][0x31 - 1] = "Javad GNSS, Inc.", +[6][0x2f - 1] = "Comsys Communication Ltd", +[6][0x30 - 1] = "Movidia Ltd", +[6][0x31 - 1] = "Javad GNSS Inc", [6][0x32 - 1] = "Montage Technology Group", [6][0x33 - 1] = "Trident Microsystems", [6][0x34 - 1] = "Super Talent", -[6][0x35 - 1] = "Optichron, Inc.", -[6][0x36 - 1] = "Future Waves UK Ltd.", -[6][0x37 - 1] = "SiBEAM, Inc.", -[6][0x38 - 1] = "Inicore,Inc.", +[6][0x35 - 1] = "Optichron Inc", +[6][0x36 - 1] = "Future Waves UK Ltd", +[6][0x37 - 1] = "SiBEAM Inc", +[6][0x38 - 1] = "InicoreInc", [6][0x39 - 1] = "Virident Systems", -[6][0x3a - 1] = "M2000, Inc.", -[6][0x3b - 1] = "ZeroG Wireless, Inc.", -[6][0x3c - 1] = "Gingle Technology Co. Ltd.", -[6][0x3d - 1] = "Space Micro Inc.", +[6][0x3a - 1] = "M2000 Inc", +[6][0x3b - 1] = "ZeroG Wireless Inc", +[6][0x3c - 1] = "Gingle Technology Co Ltd", +[6][0x3d - 1] = "Space Micro Inc", [6][0x3e - 1] = "Wilocity", -[6][0x3f - 1] = "Novafora, Inc.", +[6][0x3f - 1] = "Novafora Inc", [6][0x40 - 1] = "iKoa Corporation", [6][0x41 - 1] = "ASint Technology", [6][0x42 - 1] = "Ramtron", -[6][0x43 - 1] = "Plato Networks Inc.", +[6][0x43 - 1] = "Plato Networks Inc", [6][0x44 - 1] = "IPtronics AS", [6][0x45 - 1] = "Infinite-Memories", -[6][0x46 - 1] = "Parade Technologies Inc.", +[6][0x46 - 1] = "Parade Technologies Inc", [6][0x47 - 1] = "Dune Networks", [6][0x48 - 1] = "GigaDevice Semiconductor", -[6][0x49 - 1] = "Modu Ltd.", +[6][0x49 - 1] = "Modu Ltd", [6][0x4a - 1] = "CEITEC", [6][0x4b - 1] = "Northrop Grumman", [6][0x4c - 1] = "XRONET Corporation", [6][0x4d - 1] = "Sicon Semiconductor AB", -[6][0x4e - 1] = "Atla Electronics Co. Ltd.", +[6][0x4e - 1] = "Atla Electronics Co Ltd", [6][0x4f - 1] = "TOPRAM Technology", -[6][0x50 - 1] = "Silego Technology Inc.", +[6][0x50 - 1] = "Silego Technology Inc", [6][0x51 - 1] = "Kinglife", -[6][0x52 - 1] = "Ability Industries Ltd.", -[6][0x53 - 1] = "Silicon Power Computer &", -[6][0x54 - 1] = "Augusta Technology, Inc.", +[6][0x52 - 1] = "Ability Industries Ltd", +[6][0x53 - 1] = "Silicon Power Computer & Communications", +[6][0x54 - 1] = "Augusta Technology Inc", [6][0x55 - 1] = "Nantronics Semiconductors", [6][0x56 - 1] = "Hilscher Gesellschaft", -[6][0x57 - 1] = "Quixant Ltd.", -[6][0x58 - 1] = "Percello Ltd.", -[6][0x59 - 1] = "NextIO Inc.", -[6][0x5a - 1] = "Scanimetrics Inc.", -[6][0x5b - 1] = "FS-Semi Company Ltd.", +[6][0x57 - 1] = "Quixant Ltd", +[6][0x58 - 1] = "Percello Ltd", +[6][0x59 - 1] = "NextIO Inc", +[6][0x5a - 1] = "Scanimetrics Inc", +[6][0x5b - 1] = "FS-Semi Company Ltd", [6][0x5c - 1] = "Infinera Corporation", -[6][0x5d - 1] = "SandForce Inc.", +[6][0x5d - 1] = "SandForce Inc", [6][0x5e - 1] = "Lexar Media", -[6][0x5f - 1] = "Teradyne Inc.", -[6][0x60 - 1] = "Memory Exchange Corp.", +[6][0x5f - 1] = "Teradyne Inc", +[6][0x60 - 1] = "Memory Exchange Corp", [6][0x61 - 1] = "Suzhou Smartek Electronics", [6][0x62 - 1] = "Avantium Corporation", -[6][0x63 - 1] = "ATP Electronics Inc.", +[6][0x63 - 1] = "ATP Electronics Inc", [6][0x64 - 1] = "Valens Semiconductor Ltd", -[6][0x65 - 1] = "Agate Logic, Inc.", +[6][0x65 - 1] = "Agate Logic Inc", [6][0x66 - 1] = "Netronome", -[6][0x67 - 1] = "Zenverge, Inc.", +[6][0x67 - 1] = "Zenverge Inc", [6][0x68 - 1] = "N-trig Ltd", -[6][0x69 - 1] = "SanMax Technologies Inc.", -[6][0x6a - 1] = "Contour Semiconductor Inc.", +[6][0x69 - 1] = "SanMax Technologies Inc", +[6][0x6a - 1] = "Contour Semiconductor Inc", [6][0x6b - 1] = "TwinMOS", -[6][0x6c - 1] = "Silicon Systems, Inc.", -[6][0x6d - 1] = "V-Color Technology Inc.", +[6][0x6c - 1] = "Silicon Systems Inc", +[6][0x6d - 1] = "V-Color Technology Inc", [6][0x6e - 1] = "Certicom Corporation", [6][0x6f - 1] = "JSC ICC Milandr", -[6][0x70 - 1] = "PhotoFast Global Inc.", +[6][0x70 - 1] = "PhotoFast Global Inc", [6][0x71 - 1] = "InnoDisk Corporation", [6][0x72 - 1] = "Muscle Power", [6][0x73 - 1] = "Energy Micro", [6][0x74 - 1] = "Innofidei", [6][0x75 - 1] = "CopperGate Communications", -[6][0x76 - 1] = "Holtek Semiconductor Inc.", -[6][0x77 - 1] = "Myson Century, Inc.", +[6][0x76 - 1] = "Holtek Semiconductor Inc", +[6][0x77 - 1] = "Myson Century Inc", [6][0x78 - 1] = "FIDELIX", [6][0x79 - 1] = "Red Digital Cinema", [6][0x7a - 1] = "Densbits Technology", [6][0x7b - 1] = "Zempro", [6][0x7c - 1] = "MoSys", [6][0x7d - 1] = "Provigent", -[6][0x7e - 1] = "Triad Semiconductor, Inc.", -[7][0x01 - 1] = "Siklu Communication Ltd.", -[7][0x02 - 1] = "A Force Manufacturing Ltd.", +[6][0x7e - 1] = "Triad Semiconductor Inc", +[7][0x01 - 1] = "Siklu Communication Ltd", +[7][0x02 - 1] = "A Force Manufacturing Ltd", [7][0x03 - 1] = "Strontium", [7][0x04 - 1] = "ALi Corp (Abilis Systems)", -[7][0x05 - 1] = "Siglead, Inc.", -[7][0x06 - 1] = "Ubicom, Inc.", +[7][0x05 - 1] = "Siglead Inc", +[7][0x06 - 1] = "Ubicom Inc", [7][0x07 - 1] = "Unifosa Corporation", -[7][0x08 - 1] = "Stretch, Inc.", +[7][0x08 - 1] = "Stretch Inc", [7][0x09 - 1] = "Lantiq Deutschland GmbH", [7][0x0a - 1] = "Visipro.", [7][0x0b - 1] = "EKMemory", [7][0x0c - 1] = "Microelectronics Institute ZTE", [7][0x0d - 1] = "u-blox AG", -[7][0x0e - 1] = "Carry Technology Co. Ltd.", +[7][0x0e - 1] = "Carry Technology Co Ltd", [7][0x0f - 1] = "Nokia", [7][0x10 - 1] = "King Tiger Technology", [7][0x11 - 1] = "Sierra Wireless", [7][0x12 - 1] = "HT Micron", -[7][0x13 - 1] = "Albatron Technology Co. Ltd.", +[7][0x13 - 1] = "Albatron Technology Co Ltd", [7][0x14 - 1] = "Leica Geosystems AG", [7][0x15 - 1] = "BroadLight", [7][0x16 - 1] = "AEXEA", -[7][0x17 - 1] = "ClariPhy Communications, Inc.", +[7][0x17 - 1] = "ClariPhy Communications Inc", [7][0x18 - 1] = "Green Plug", [7][0x19 - 1] = "Design Art Networks", -[7][0x1a - 1] = "Mach Xtreme Technology Ltd.", -[7][0x1b - 1] = "ATO Solutions Co. Ltd.", +[7][0x1a - 1] = "Mach Xtreme Technology Ltd", +[7][0x1b - 1] = "ATO Solutions Co Ltd", [7][0x1c - 1] = "Ramsta", -[7][0x1d - 1] = "Greenliant Systems, Ltd.", +[7][0x1d - 1] = "Greenliant Systems Ltd", [7][0x1e - 1] = "Teikon", [7][0x1f - 1] = "Antec Hadron", -[7][0x20 - 1] = "NavCom Technology, Inc.", +[7][0x20 - 1] = "NavCom Technology Inc", [7][0x21 - 1] = "Shanghai Fudan Microelectronics", -[7][0x22 - 1] = "Calxeda, Inc.", +[7][0x22 - 1] = "Calxeda Inc", [7][0x23 - 1] = "JSC EDC Electronics", -[7][0x24 - 1] = "Kandit Technology Co. Ltd.", +[7][0x24 - 1] = "Kandit Technology Co Ltd", [7][0x25 - 1] = "Ramos Technology", [7][0x26 - 1] = "Goldenmars Technology", -[7][0x27 - 1] = "XeL Technology Inc.", +[7][0x27 - 1] = "XeL Technology Inc", [7][0x28 - 1] = "Newzone Corporation", [7][0x29 - 1] = "ShenZhen MercyPower Tech", [7][0x2a - 1] = "Nanjing Yihuo Technology", -[7][0x2b - 1] = "Nethra Imaging Inc.", +[7][0x2b - 1] = "Nethra Imaging Inc", [7][0x2c - 1] = "SiTel Semiconductor BV", [7][0x2d - 1] = "SolidGear Corporation", -[7][0x2e - 1] = "Topower Computer Ind Co Ltd.", +[7][0x2e - 1] = "Topower Computer Ind Co Ltd", [7][0x2f - 1] = "Wilocity", [7][0x30 - 1] = "Profichip GmbH", [7][0x31 - 1] = "Gerad Technologies", [7][0x32 - 1] = "Ritek Corporation", [7][0x33 - 1] = "Gomos Technology Limited", [7][0x34 - 1] = "Memoright Corporation", -[7][0x35 - 1] = "D-Broad, Inc.", +[7][0x35 - 1] = "D-Broad Inc", [7][0x36 - 1] = "HiSilicon Technologies", -[7][0x37 - 1] = "Syndiant Inc..", -[7][0x38 - 1] = "Enverv Inc.", +[7][0x37 - 1] = "Syndiant Inc.", +[7][0x38 - 1] = "Enverv Inc", [7][0x39 - 1] = "Cognex", -[7][0x3a - 1] = "Xinnova Technology Inc.", +[7][0x3a - 1] = "Xinnova Technology Inc", [7][0x3b - 1] = "Ultron AG", [7][0x3c - 1] = "Concord Idea Corporation", [7][0x3d - 1] = "AIM Corporation", @@ -948,15 +961,15 @@ [7][0x41 - 1] = "Haotian Jinshibo Science Tech", [7][0x42 - 1] = "Being Advanced Memory", [7][0x43 - 1] = "Adesto Technologies", -[7][0x44 - 1] = "Giantec Semiconductor, Inc.", +[7][0x44 - 1] = "Giantec Semiconductor Inc", [7][0x45 - 1] = "HMD Electronics AG", [7][0x46 - 1] = "Gloway International (HK)", [7][0x47 - 1] = "Kingcore", [7][0x48 - 1] = "Anucell Technology Holding", -[7][0x49 - 1] = "Accord Software & Systems Pvt. Ltd.", -[7][0x4a - 1] = "Active-Semi Inc.", +[7][0x49 - 1] = "Accord Software & Systems Pvt. Ltd", +[7][0x4a - 1] = "Active-Semi Inc", [7][0x4b - 1] = "Denso Corporation", -[7][0x4c - 1] = "TLSI Inc.", +[7][0x4c - 1] = "TLSI Inc", [7][0x4d - 1] = "Qidan", [7][0x4e - 1] = "Mustang", [7][0x4f - 1] = "Orca Systems", @@ -970,23 +983,23 @@ [7][0x57 - 1] = "Eorex Corporation", [7][0x58 - 1] = "Xingtera", [7][0x59 - 1] = "Netsol", -[7][0x5a - 1] = "Bestdon Technology Co. Ltd.", -[7][0x5b - 1] = "Baysand Inc.", -[7][0x5c - 1] = "Uroad Technology Co. Ltd.", +[7][0x5a - 1] = "Bestdon Technology Co Ltd", +[7][0x5b - 1] = "Baysand Inc", +[7][0x5c - 1] = "Uroad Technology Co Ltd", [7][0x5d - 1] = "Wilk Elektronik S.A.", [7][0x5e - 1] = "AAI", [7][0x5f - 1] = "Harman", -[7][0x60 - 1] = "Berg Microelectronics Inc.", -[7][0x61 - 1] = "ASSIA, Inc.", +[7][0x60 - 1] = "Berg Microelectronics Inc", +[7][0x61 - 1] = "ASSIA Inc", [7][0x62 - 1] = "Visiontek Products LLC", [7][0x63 - 1] = "OCMEMORY", -[7][0x64 - 1] = "Welink Solution Inc.", +[7][0x64 - 1] = "Welink Solution Inc", [7][0x65 - 1] = "Shark Gaming", [7][0x66 - 1] = "Avalanche Technology", [7][0x67 - 1] = "R&D Center ELVEES OJSC", -[7][0x68 - 1] = "KingboMars Technology Co. Ltd.", -[7][0x69 - 1] = "High Bridge Solutions Industria", -[7][0x6a - 1] = "Transcend Technology Co. Ltd.", +[7][0x68 - 1] = "KingboMars Technology Co Ltd", +[7][0x69 - 1] = "High Bridge Solutions Industria Eletronica", +[7][0x6a - 1] = "Transcend Technology Co Ltd", [7][0x6b - 1] = "Everspin Technologies", [7][0x6c - 1] = "Hon-Hai Precision", [7][0x6d - 1] = "Smart Storage Systems", @@ -997,54 +1010,54 @@ [7][0x72 - 1] = "LITE-ON IT Corporation", [7][0x73 - 1] = "Inuitive", [7][0x74 - 1] = "HMicro", -[7][0x75 - 1] = "BittWare, Inc.", +[7][0x75 - 1] = "BittWare Inc", [7][0x76 - 1] = "GLOBALFOUNDRIES", -[7][0x77 - 1] = "ACPI Digital Co. Ltd.", +[7][0x77 - 1] = "ACPI Digital Co Ltd", [7][0x78 - 1] = "Annapurna Labs", [7][0x79 - 1] = "AcSiP Technology Corporation", [7][0x7a - 1] = "Idea! Electronic Systems", -[7][0x7b - 1] = "Gowe Technology Co. Ltd.", -[7][0x7c - 1] = "Hermes Testing Solutions, Inc.", +[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", [8][0x04 - 1] = "Mercury Systems", -[8][0x05 - 1] = "Sonics, Inc.", -[8][0x06 - 1] = "GE Intelligent Platforms GmbH & Co.", -[8][0x07 - 1] = "Shenzhen Jinge Information Co. Ltd.", +[8][0x05 - 1] = "Sonics Inc", +[8][0x06 - 1] = "Emerson Automation Solutions", +[8][0x07 - 1] = "Shenzhen Jinge Information Co Ltd", [8][0x08 - 1] = "SCWW", -[8][0x09 - 1] = "Silicon Motion Inc.", +[8][0x09 - 1] = "Silicon Motion Inc", [8][0x0a - 1] = "Anurag", [8][0x0b - 1] = "King Kong", -[8][0x0c - 1] = "FROM30 Co. Ltd.", +[8][0x0c - 1] = "FROM30 Co Ltd", [8][0x0d - 1] = "Gowin Semiconductor Corp", -[8][0x0e - 1] = "Fremont Micro Devices Ltd.", +[8][0x0e - 1] = "Fremont Micro Devices Ltd", [8][0x0f - 1] = "Ericsson Modems", [8][0x10 - 1] = "Exelis", -[8][0x11 - 1] = "Satixfy Ltd.", -[8][0x12 - 1] = "Galaxy Microsystems Ltd.", -[8][0x13 - 1] = "Gloway International Co. Ltd.", +[8][0x11 - 1] = "Satixfy Ltd", +[8][0x12 - 1] = "Galaxy Microsystems Ltd", +[8][0x13 - 1] = "Gloway International Co Ltd", [8][0x14 - 1] = "Lab", [8][0x15 - 1] = "Smart Energy Instruments", [8][0x16 - 1] = "Approved Memory Corporation", [8][0x17 - 1] = "Axell Corporation", [8][0x18 - 1] = "Essencore Limited", [8][0x19 - 1] = "Phytium", -[8][0x1a - 1] = "Xi’an SinoChip Semiconductor", +[8][0x1a - 1] = "Xi'an UniIC Semiconductors Co Ltd", [8][0x1b - 1] = "Ambiq Micro", -[8][0x1c - 1] = "eveRAM Technology, Inc.", +[8][0x1c - 1] = "eveRAM Technology Inc", [8][0x1d - 1] = "Infomax", -[8][0x1e - 1] = "Butterfly Network, Inc.", +[8][0x1e - 1] = "Butterfly Network Inc", [8][0x1f - 1] = "Shenzhen City Gcai Electronics", [8][0x20 - 1] = "Stack Devices Corporation", [8][0x21 - 1] = "ADK Media Group", -[8][0x22 - 1] = "TSP Global Co., Ltd.", +[8][0x22 - 1] = "TSP Global Co Ltd", [8][0x23 - 1] = "HighX", [8][0x24 - 1] = "Shenzhen Elicks Technology", -[8][0x25 - 1] = "ISSI/Chingis", -[8][0x26 - 1] = "Google, Inc.", +[8][0x25 - 1] = "XinKai/Silicon Kaiser", +[8][0x26 - 1] = "Google Inc", [8][0x27 - 1] = "Dasima International Development", [8][0x28 - 1] = "Leahkinn Technology Limited", [8][0x29 - 1] = "HIMA Paul Hildebrandt GmbH Co KG", @@ -1052,98 +1065,98 @@ [8][0x2b - 1] = "Techcomp International (Fastable)", [8][0x2c - 1] = "Ancore Technology Corporation", [8][0x2d - 1] = "Nuvoton", -[8][0x2e - 1] = "Korea Uhbele International Group Ltd.", -[8][0x2f - 1] = "Ikegami Tsushinki Co Ltd.", -[8][0x30 - 1] = "RelChip, Inc.", +[8][0x2e - 1] = "Korea Uhbele International Group Ltd", +[8][0x2f - 1] = "Ikegami Tsushinki Co Ltd", +[8][0x30 - 1] = "RelChip Inc", [8][0x31 - 1] = "Baikal Electronics", -[8][0x32 - 1] = "Nemostech Inc.", +[8][0x32 - 1] = "Nemostech Inc", [8][0x33 - 1] = "Memorysolution GmbH", [8][0x34 - 1] = "Silicon Integrated Systems Corporation", [8][0x35 - 1] = "Xiede", -[8][0x36 - 1] = "Multilaser Components", +[8][0x36 - 1] = "BRC", [8][0x37 - 1] = "Flash Chi", [8][0x38 - 1] = "Jone", -[8][0x39 - 1] = "GCT Semiconductor Inc.", +[8][0x39 - 1] = "GCT Semiconductor Inc", [8][0x3a - 1] = "Hong Kong Zetta Device Technology", -[8][0x3b - 1] = "Unimemory Technology(s) Pte Ltd.", +[8][0x3b - 1] = "Unimemory Technology(s) Pte Ltd", [8][0x3c - 1] = "Cuso", [8][0x3d - 1] = "Kuso", -[8][0x3e - 1] = "Uniquify Inc.", +[8][0x3e - 1] = "Uniquify Inc", [8][0x3f - 1] = "Skymedi Corporation", -[8][0x40 - 1] = "Core Chance Co. Ltd.", -[8][0x41 - 1] = "Tekism Co. Ltd.", +[8][0x40 - 1] = "Core Chance Co Ltd", +[8][0x41 - 1] = "Tekism Co Ltd", [8][0x42 - 1] = "Seagate Technology PLC", -[8][0x43 - 1] = "Hong Kong Gaia Group Co. Limited", +[8][0x43 - 1] = "Hong Kong Gaia Group Co Limited", [8][0x44 - 1] = "Gigacom Semiconductor LLC", [8][0x45 - 1] = "V2 Technologies", [8][0x46 - 1] = "TLi", [8][0x47 - 1] = "Neotion", [8][0x48 - 1] = "Lenovo", -[8][0x49 - 1] = "Shenzhen Zhongteng Electronic Corp. Ltd.", +[8][0x49 - 1] = "Shenzhen Zhongteng Electronic Corp Ltd", [8][0x4a - 1] = "Compound Photonics", [8][0x4b - 1] = "in2H2 inc", -[8][0x4c - 1] = "Shenzhen Pango Microsystems Co. Ltd", +[8][0x4c - 1] = "Shenzhen Pango Microsystems Co Ltd", [8][0x4d - 1] = "Vasekey", [8][0x4e - 1] = "Cal-Comp Industria de Semicondutores", -[8][0x4f - 1] = "Eyenix Co., Ltd.", +[8][0x4f - 1] = "Eyenix Co Ltd", [8][0x50 - 1] = "Heoriady", -[8][0x51 - 1] = "Accelerated Memory Production Inc.", -[8][0x52 - 1] = "INVECAS, Inc.", +[8][0x51 - 1] = "Accelerated Memory Production Inc", +[8][0x52 - 1] = "INVECAS Inc", [8][0x53 - 1] = "AP Memory", [8][0x54 - 1] = "Douqi Technology", -[8][0x55 - 1] = "Etron Technology, Inc.", +[8][0x55 - 1] = "Etron Technology Inc", [8][0x56 - 1] = "Indie Semiconductor", -[8][0x57 - 1] = "Socionext Inc.", +[8][0x57 - 1] = "Socionext Inc", [8][0x58 - 1] = "HGST", [8][0x59 - 1] = "EVGA", -[8][0x5a - 1] = "Audience Inc.", +[8][0x5a - 1] = "Audience Inc", [8][0x5b - 1] = "EpicGear", -[8][0x5c - 1] = "Vitesse Enterprise Co.", +[8][0x5c - 1] = "Vitesse Enterprise Co", [8][0x5d - 1] = "Foxtronn International Corporation", -[8][0x5e - 1] = "Bretelon Inc.", +[8][0x5e - 1] = "Bretelon Inc", [8][0x5f - 1] = "Graphcore", [8][0x60 - 1] = "Eoplex Inc", -[8][0x61 - 1] = "MaxLinear, Inc.", +[8][0x61 - 1] = "MaxLinear Inc", [8][0x62 - 1] = "ETA Devices", [8][0x63 - 1] = "LOKI", -[8][0x64 - 1] = "IMS Electronics Co., Ltd.", -[8][0x65 - 1] = "Dosilicon Co., Ltd.", +[8][0x64 - 1] = "IMS Electronics Co Ltd", +[8][0x65 - 1] = "Dosilicon Co Ltd", [8][0x66 - 1] = "Dolphin Integration", -[8][0x67 - 1] = "Shenzhen Mic Electronics Technology", -[8][0x68 - 1] = "Boya Microelectronics Inc.", +[8][0x67 - 1] = "Shenzhen Mic Electronics Technolog", +[8][0x68 - 1] = "Boya Microelectronics Inc", [8][0x69 - 1] = "Geniachip (Roche)", [8][0x6a - 1] = "Axign", -[8][0x6b - 1] = "Kingred Electronic Technology Ltd.", +[8][0x6b - 1] = "Kingred Electronic Technology Ltd", [8][0x6c - 1] = "Chao Yue Zhuo Computer Business Dept.", [8][0x6d - 1] = "Guangzhou Si Nuo Electronic Technology.", -[8][0x6e - 1] = "Crocus Technology Inc.", +[8][0x6e - 1] = "Crocus Technology Inc", [8][0x6f - 1] = "Creative Chips GmbH", [8][0x70 - 1] = "GE Aviation Systems LLC.", [8][0x71 - 1] = "Asgard", -[8][0x72 - 1] = "Good Wealth Technology Ltd.", +[8][0x72 - 1] = "Good Wealth Technology Ltd", [8][0x73 - 1] = "TriCor Technologies", [8][0x74 - 1] = "Nova-Systems GmbH", [8][0x75 - 1] = "JUHOR", -[8][0x76 - 1] = "Zhuhai Douke Commerce Co. Ltd.", +[8][0x76 - 1] = "Zhuhai Douke Commerce Co Ltd", [8][0x77 - 1] = "DSL Memory", [8][0x78 - 1] = "Anvo-Systems Dresden GmbH", [8][0x79 - 1] = "Realtek", [8][0x7a - 1] = "AltoBeam", [8][0x7b - 1] = "Wave Computing", -[8][0x7c - 1] = "Beijing TrustNet Technology Co. Ltd.", -[8][0x7d - 1] = "Innovium, Inc.", +[8][0x7c - 1] = "Beijing TrustNet Technology Co Ltd", +[8][0x7d - 1] = "Innovium Inc", [8][0x7e - 1] = "Starsway Technology Limited", -[9][0x01 - 1] = "Weltronics Co. LTD", -[9][0x02 - 1] = "VMware, Inc.", +[9][0x01 - 1] = "Weltronics Co LTD", +[9][0x02 - 1] = "VMware Inc", [9][0x03 - 1] = "Hewlett Packard Enterprise", [9][0x04 - 1] = "INTENSO", [9][0x05 - 1] = "Puya Semiconductor", [9][0x06 - 1] = "MEMORFI", [9][0x07 - 1] = "MSC Technologies GmbH", [9][0x08 - 1] = "Txrui", -[9][0x09 - 1] = "SiFive, Inc.", +[9][0x09 - 1] = "SiFive Inc", [9][0x0a - 1] = "Spreadtrum Communications", -[9][0x0b - 1] = "Paragon Technology (Shenzhen) Ltd.", +[9][0x0b - 1] = "XTX Technology Limited", [9][0x0c - 1] = "UMAX Technology", [9][0x0d - 1] = "Shenzhen Yong Sheng Technology", [9][0x0e - 1] = "SNOAMOO (Shenzhen Kai Zhuo Yue)", @@ -1151,6 +1164,778 @@ [9][0x10 - 1] = "Shenzhen XinRuiYan Electronics", [9][0x11 - 1] = "Eta Compute", [9][0x12 - 1] = "Energous", -[9][0x13 - 1] = "Raspberry Pi Trading Ltd.", -[9][0x14 - 1] = "Shenzhen Chixingzhe Tech Co. Ltd.", +[9][0x13 - 1] = "Raspberry Pi Trading Ltd", +[9][0x14 - 1] = "Shenzhen Chixingzhe Tech Co Ltd", +[9][0x15 - 1] = "Silicon Mobility", +[9][0x16 - 1] = "IQ-Analog Corporation", +[9][0x17 - 1] = "Uhnder Inc", +[9][0x18 - 1] = "Impinj", +[9][0x19 - 1] = "DEPO Computers", +[9][0x1a - 1] = "Nespeed Sysems", +[9][0x1b - 1] = "Yangtze Memory Technologies Co Ltd", +[9][0x1c - 1] = "MemxPro Inc", +[9][0x1d - 1] = "Tammuz Co Ltd", +[9][0x1e - 1] = "Allwinner Technology", +[9][0x1f - 1] = "Shenzhen City Futian District Qing Xuan Tong Computer Trading Firm", +[9][0x20 - 1] = "XMC", +[9][0x21 - 1] = "Teclast", +[9][0x22 - 1] = "Maxsun", +[9][0x23 - 1] = "Haiguang Integrated Circuit Design", +[9][0x24 - 1] = "RamCENTER Technology", +[9][0x25 - 1] = "Phison Electronics Corporation", +[9][0x26 - 1] = "Guizhou Huaxintong Semi-Conductor", +[9][0x27 - 1] = "Network Intelligence", +[9][0x28 - 1] = "Continental Technology (Holdings)", +[9][0x29 - 1] = "Guangzhou Huayan Suning Electronic", +[9][0x2a - 1] = "Guangzhou Zhouji Electronic Co Ltd", +[9][0x2b - 1] = "Shenzhen Giant Hui Kang Tech Co Ltd", +[9][0x2c - 1] = "Shenzhen Yilong Innovative Co Ltd", +[9][0x2d - 1] = "Neo Forza", +[9][0x2e - 1] = "Lyontek Inc", +[9][0x2f - 1] = "Shanghai Kuxin Microelectronics Ltd", +[9][0x30 - 1] = "Shenzhen Larix Technology Co Ltd", +[9][0x31 - 1] = "Qbit Semiconductor Ltd", +[9][0x32 - 1] = "Insignis Technology Corporation", +[9][0x33 - 1] = "Lanson Memory Co Ltd", +[9][0x34 - 1] = "Shenzhen Superway Electronics Co Ltd", +[9][0x35 - 1] = "Canaan-Creative Co Ltd", +[9][0x36 - 1] = "Black Diamond Memory", +[9][0x37 - 1] = "Shenzhen City Parker Baking Electronics", +[9][0x38 - 1] = "Shenzhen Baihong Technology Co Ltd", +[9][0x39 - 1] = "GEO Semiconductors", +[9][0x3a - 1] = "OCPC", +[9][0x3b - 1] = "Artery Technology Co Ltd", +[9][0x3c - 1] = "Jinyu", +[9][0x3d - 1] = "ShenzhenYing Chi Technology Development", +[9][0x3e - 1] = "Shenzhen Pengcheng Xin Technology", +[9][0x3f - 1] = "Pegasus Semiconductor (Shanghai) Co", +[9][0x40 - 1] = "Mythic Inc", +[9][0x41 - 1] = "Elmos Semiconductor AG", +[9][0x42 - 1] = "Kllisre", +[9][0x43 - 1] = "Shenzhen Winconway Technology", +[9][0x44 - 1] = "Shenzhen Xingmem Technology Corp", +[9][0x45 - 1] = "Gold Key Technology Co Ltd", +[9][0x46 - 1] = "Habana Labs Ltd", +[9][0x47 - 1] = "Hoodisk Electronics Co Ltd", +[9][0x48 - 1] = "SemsoTai (SZ) Technology Co Ltd", +[9][0x49 - 1] = "OM Nanotech Pvt. Ltd", +[9][0x4a - 1] = "Shenzhen Zhifeng Weiye Technology", +[9][0x4b - 1] = "Xinshirui (Shenzhen) Electronics Co", +[9][0x4c - 1] = "Guangzhou Zhong Hao Tian Electronic", +[9][0x4d - 1] = "Shenzhen Longsys Electronics Co Ltd", +[9][0x4e - 1] = "Deciso B.V.", +[9][0x4f - 1] = "Puya Semiconductor (Shenzhen)", +[9][0x50 - 1] = "Shenzhen Veineda Technology Co Ltd", +[9][0x51 - 1] = "Antec Memory", +[9][0x52 - 1] = "Cortus SAS", +[9][0x53 - 1] = "Dust Leopard", +[9][0x54 - 1] = "MyWo AS", +[9][0x55 - 1] = "J&A Information Inc", +[9][0x56 - 1] = "Shenzhen JIEPEI Technology Co Ltd", +[9][0x57 - 1] = "Heidelberg University", +[9][0x58 - 1] = "Flexxon PTE Ltd", +[9][0x59 - 1] = "Wiliot", +[9][0x5a - 1] = "Raysun Electronics International Ltd", +[9][0x5b - 1] = "Aquarius Production Company LLC", +[9][0x5c - 1] = "MACNICA DHW LTDA", +[9][0x5d - 1] = "Intelimem", +[9][0x5e - 1] = "Zbit Semiconductor Inc", +[9][0x5f - 1] = "Shenzhen Technology Co Ltd", +[9][0x60 - 1] = "Signalchip", +[9][0x61 - 1] = "Shenzen Recadata Storage Technology", +[9][0x62 - 1] = "Hyundai Technology", +[9][0x63 - 1] = "Shanghai Fudi Investment Development", +[9][0x64 - 1] = "Aixi Technology", +[9][0x65 - 1] = "Tecon MT", +[9][0x66 - 1] = "Onda Electric Co Ltd", +[9][0x67 - 1] = "Jinshen", +[9][0x68 - 1] = "Kimtigo Semiconductor (HK) Limited", +[9][0x69 - 1] = "IIT Madras", +[9][0x6a - 1] = "Shenshan (Shenzhen) Electronic", +[9][0x6b - 1] = "Hefei Core Storage Electronic Limited", +[9][0x6c - 1] = "Colorful Technology Ltd", +[9][0x6d - 1] = "Visenta (Xiamen) Technology Co Ltd", +[9][0x6e - 1] = "Roa Logic BV", +[9][0x6f - 1] = "NSITEXE Inc", +[9][0x70 - 1] = "Hong Kong Hyunion Electronics", +[9][0x71 - 1] = "ASK Technology Group Limited", +[9][0x72 - 1] = "GIGA-BYTE Technology Co Ltd", +[9][0x73 - 1] = "Terabyte Co Ltd", +[9][0x74 - 1] = "Hyundai Inc", +[9][0x75 - 1] = "EXCELERAM", +[9][0x76 - 1] = "PsiKick", +[9][0x77 - 1] = "Netac Technology Co Ltd", +[9][0x78 - 1] = "PCCOOLER", +[9][0x79 - 1] = "Jiangsu Huacun Electronic Technology", +[9][0x7a - 1] = "Shenzhen Micro Innovation Industry", +[9][0x7b - 1] = "Beijing Tongfang Microelectronics Co", +[9][0x7c - 1] = "XZN Storage Technology", +[9][0x7d - 1] = "ChipCraft Sp. z.o.o.", +[9][0x7e - 1] = "ALLFLASH Technology Limited", +[10][0x01 - 1] = "Foerd Technology Co Ltd", +[10][0x02 - 1] = "KingSpec", +[10][0x03 - 1] = "Codasip GmbH", +[10][0x04 - 1] = "SL Link Co Ltd", +[10][0x05 - 1] = "Shenzhen Kefu Technology Co Limited", +[10][0x06 - 1] = "Shenzhen ZST Electronics Technology", +[10][0x07 - 1] = "Kyokuto Electronic Inc", +[10][0x08 - 1] = "Warrior Technology", +[10][0x09 - 1] = "TRINAMIC Motion Control GmbH & Co", +[10][0x0a - 1] = "PixelDisplay Inc", +[10][0x0b - 1] = "Shenzhen Futian District Bo Yueda Elec", +[10][0x0c - 1] = "Richtek Power", +[10][0x0d - 1] = "Shenzhen LianTeng Electronics Co Ltd", +[10][0x0e - 1] = "AITC Memory", +[10][0x0f - 1] = "UNIC Memory Technology Co Ltd", +[10][0x10 - 1] = "Shenzhen Huafeng Science Technology", +[10][0x11 - 1] = "CXMT", +[10][0x12 - 1] = "Guangzhou Xinyi Heng Computer Trading Firm", +[10][0x13 - 1] = "SambaNova Systems", +[10][0x14 - 1] = "V-GEN", +[10][0x15 - 1] = "Jump Trading", +[10][0x16 - 1] = "Ampere Computing", +[10][0x17 - 1] = "Shenzhen Zhongshi Technology Co Ltd", +[10][0x18 - 1] = "Shenzhen Zhongtian Bozhong Technology", +[10][0x19 - 1] = "Tri-Tech International", +[10][0x1a - 1] = "Silicon Intergrated Systems Corporation", +[10][0x1b - 1] = "Shenzhen HongDingChen Information", +[10][0x1c - 1] = "Plexton Holdings Limited", +[10][0x1d - 1] = "AMS (Jiangsu Advanced Memory Semi)", +[10][0x1e - 1] = "Wuhan Jing Tian Interconnected Tech Co", +[10][0x1f - 1] = "Axia Memory Technology", +[10][0x20 - 1] = "Chipset Technology Holding Limited", +[10][0x21 - 1] = "Shenzhen Xinshida Technology Co Ltd", +[10][0x22 - 1] = "Shenzhen Chuangshifeida Technology", +[10][0x23 - 1] = "Guangzhou MiaoYuanJi Technology", +[10][0x24 - 1] = "ADVAN Inc", +[10][0x25 - 1] = "Shenzhen Qianhai Weishengda Electronic Commerce Company Ltd", +[10][0x26 - 1] = "Guangzhou Guang Xie Cheng Trading", +[10][0x27 - 1] = "StarRam International Co Ltd", +[10][0x28 - 1] = "Shen Zhen XinShenHua Tech Co Ltd", +[10][0x29 - 1] = "UltraMemory Inc", +[10][0x2a - 1] = "New Coastline Global Tech Industry Co", +[10][0x2b - 1] = "Sinker", +[10][0x2c - 1] = "Diamond", +[10][0x2d - 1] = "PUSKILL", +[10][0x2e - 1] = "Guangzhou Hao Jia Ye Technology Co", +[10][0x2f - 1] = "Ming Xin Limited", +[10][0x30 - 1] = "Barefoot Networks", +[10][0x31 - 1] = "Biwin Semiconductor (HK) Co Ltd", +[10][0x32 - 1] = "UD INFO Corporation", +[10][0x33 - 1] = "Trek Technology (S) PTE Ltd", +[10][0x34 - 1] = "Xiamen Kingblaze Technology Co Ltd", +[10][0x35 - 1] = "Shenzhen Lomica Technology Co Ltd", +[10][0x36 - 1] = "Nuclei System Technology Co Ltd", +[10][0x37 - 1] = "Wuhan Xun Zhan Electronic Technology", +[10][0x38 - 1] = "Shenzhen Ingacom Semiconductor Ltd", +[10][0x39 - 1] = "Zotac Technology Ltd", +[10][0x3a - 1] = "Foxline", +[10][0x3b - 1] = "Shenzhen Farasia Science Technology", +[10][0x3c - 1] = "Efinix Inc", +[10][0x3d - 1] = "Hua Nan San Xian Technology Co Ltd", +[10][0x3e - 1] = "Goldtech Electronics Co Ltd", +[10][0x3f - 1] = "Shanghai Han Rong Microelectronics Co", +[10][0x40 - 1] = "Shenzhen Zhongguang Yunhe Trading", +[10][0x41 - 1] = "Smart Shine(QingDao) Microelectronics", +[10][0x42 - 1] = "Thermaltake Technology Co Ltd", +[10][0x43 - 1] = "Shenzhen O'Yang Maile Technology Ltd", +[10][0x44 - 1] = "UPMEM", +[10][0x45 - 1] = "Chun Well Technology Holding Limited", +[10][0x46 - 1] = "Astera Labs Inc", +[10][0x47 - 1] = "Winconway", +[10][0x48 - 1] = "Advantech Co Ltd", +[10][0x49 - 1] = "Chengdu Fengcai Electronic Technology", +[10][0x4a - 1] = "The Boeing Company", +[10][0x4b - 1] = "Blaize Inc", +[10][0x4c - 1] = "Ramonster Technology Co Ltd", +[10][0x4d - 1] = "Wuhan Naonongmai Technology Co Ltd", +[10][0x4e - 1] = "Shenzhen Hui ShingTong Technology", +[10][0x4f - 1] = "Yourlyon", +[10][0x50 - 1] = "Fabu Technology", +[10][0x51 - 1] = "Shenzhen Yikesheng Technology Co Ltd", +[10][0x52 - 1] = "NOR-MEM", +[10][0x53 - 1] = "Cervoz Co Ltd", +[10][0x54 - 1] = "Bitmain Technologies Inc.", +[10][0x55 - 1] = "Facebook Inc", +[10][0x56 - 1] = "Shenzhen Longsys Electronics Co Ltd", +[10][0x57 - 1] = "Guangzhou Siye Electronic Technology", +[10][0x58 - 1] = "Silergy", +[10][0x59 - 1] = "Adamway", +[10][0x5a - 1] = "PZG", +[10][0x5b - 1] = "Shenzhen King Power Electronics", +[10][0x5c - 1] = "Guangzhou ZiaoFu Tranding Co Ltd", +[10][0x5d - 1] = "Shenzhen SKIHOTAR Semiconductor", +[10][0x5e - 1] = "PulseRain Technology", +[10][0x5f - 1] = "Seeker Technology Limited", +[10][0x60 - 1] = "Shenzhen OSCOO Tech Co Ltd", +[10][0x61 - 1] = "Shenzhen Yze Technology Co Ltd", +[10][0x62 - 1] = "Shenzhen Jieshuo Electronic Commerce", +[10][0x63 - 1] = "Gazda", +[10][0x64 - 1] = "Hua Wei Technology Co Ltd", +[10][0x65 - 1] = "Esperanto Technologies", +[10][0x66 - 1] = "JinSheng Electronic (Shenzhen) Co Ltd", +[10][0x67 - 1] = "Shenzhen Shi Bolunshuai Technology", +[10][0x68 - 1] = "Shanghai Rui Zuan Information Tech", +[10][0x69 - 1] = "Fraunhofer IIS", +[10][0x6a - 1] = "Kandou Bus SA", +[10][0x6b - 1] = "Acer", +[10][0x6c - 1] = "Artmem Technology Co Ltd", +[10][0x6d - 1] = "Gstar Semiconductor Co Ltd", +[10][0x6e - 1] = "ShineDisk", +[10][0x6f - 1] = "Shenzhen CHN Technology Co Ltd", +[10][0x70 - 1] = "UnionChip Semiconductor Co Ltd", +[10][0x71 - 1] = "Tanbassh", +[10][0x72 - 1] = "Shenzhen Tianyu Jieyun Intl Logistics", +[10][0x73 - 1] = "MCLogic Inc", +[10][0x74 - 1] = "Eorex Corporation", +[10][0x75 - 1] = "Arm Technology (China) Co Ltd", +[10][0x76 - 1] = "Lexar Co Limited", +[10][0x77 - 1] = "QinetiQ Group plc", +[10][0x78 - 1] = "Exascend", +[10][0x79 - 1] = "Hong Kong Hyunion Electronics Co Ltd", +[10][0x7a - 1] = "Shenzhen Banghong Electronics Co Ltd", +[10][0x7b - 1] = "MBit Wireless Inc", +[10][0x7c - 1] = "Hex Five Security Inc", +[10][0x7d - 1] = "ShenZhen Juhor Precision Tech Co Ltd", +[10][0x7e - 1] = "Shenzhen Reeinno Technology Co Ltd", +[11][0x01 - 1] = "ABIT Electronics (Shenzhen) Co Ltd", +[11][0x02 - 1] = "Semidrive", +[11][0x03 - 1] = "MyTek Electronics Corp", +[11][0x04 - 1] = "Wxilicon Technology Co Ltd", +[11][0x05 - 1] = "Shenzhen Meixin Electronics Ltd", +[11][0x06 - 1] = "Ghost Wolf", +[11][0x07 - 1] = "LiSion Technologies Inc", +[11][0x08 - 1] = "Power Active Co Ltd", +[11][0x09 - 1] = "Pioneer High Fidelity Taiwan Co. Ltd", +[11][0x0a - 1] = "LuoSilk", +[11][0x0b - 1] = "Shenzhen Chuangshifeida Technology", +[11][0x0c - 1] = "Black Sesame Technologies Inc", +[11][0x0d - 1] = "Jiangsu Xinsheng Intelligent Technology", +[11][0x0e - 1] = "MLOONG", +[11][0x0f - 1] = "Quadratica LLC", +[11][0x10 - 1] = "Anpec Electronics", +[11][0x11 - 1] = "Xi'an Morebeck Semiconductor Tech Co", +[11][0x12 - 1] = "Kingbank Technology Co Ltd", +[11][0x13 - 1] = "ITRenew Inc", +[11][0x14 - 1] = "Shenzhen Eaget Innovation Tech Ltd", +[11][0x15 - 1] = "Jazer", +[11][0x16 - 1] = "Xiamen Semiconductor Investment Group", +[11][0x17 - 1] = "Guangzhou Longdao Network Tech Co", +[11][0x18 - 1] = "Shenzhen Futian SEC Electronic Market", +[11][0x19 - 1] = "Allegro Microsystems LLC", +[11][0x1a - 1] = "Hunan RunCore Innovation Technology", +[11][0x1b - 1] = "C-Corsa Technology", +[11][0x1c - 1] = "Zhuhai Chuangfeixin Technology Co Ltd", +[11][0x1d - 1] = "Beijing InnoMem Technologies Co Ltd", +[11][0x1e - 1] = "YooTin", +[11][0x1f - 1] = "Shenzhen Pengxiong Technology Co Ltd", +[11][0x20 - 1] = "Dongguan Yingbang Commercial Trading Co", +[11][0x21 - 1] = "Shenzhen Ronisys Electronics Co Ltd", +[11][0x22 - 1] = "Hongkong Xinlan Guangke Co Ltd", +[11][0x23 - 1] = "Apex Microelectronics Co Ltd", +[11][0x24 - 1] = "Beijing Hongda Jinming Technology Co Ltd", +[11][0x25 - 1] = "Ling Rui Technology (Shenzhen) Co Ltd", +[11][0x26 - 1] = "Hongkong Hyunion Electronics Co Ltd", +[11][0x27 - 1] = "Starsystems Inc", +[11][0x28 - 1] = "Shenzhen Yingjiaxun Industrial Co Ltd", +[11][0x29 - 1] = "Dongguan Crown Code Electronic Commerce", +[11][0x2a - 1] = "Monolithic Power Systems Inc", +[11][0x2b - 1] = "WuHan SenNaiBo E-Commerce Co Ltd", +[11][0x2c - 1] = "Hangzhou Hikstorage Technology Co", +[11][0x2d - 1] = "Shenzhen Goodix Technology Co Ltd", +[11][0x2e - 1] = "Aigo Electronic Technology Co Ltd", +[11][0x2f - 1] = "Hefei Konsemi Storage Technology Co Ltd", +[11][0x30 - 1] = "Cactus Technologies Limited", +[11][0x31 - 1] = "DSIN", +[11][0x32 - 1] = "Blu Wireless Technology", +[11][0x33 - 1] = "Nanjing UCUN Technology Inc", +[11][0x34 - 1] = "Acacia Communications", +[11][0x35 - 1] = "Beijinjinshengyihe Technology Co Ltd", +[11][0x36 - 1] = "Zyzyx", +[11][0x37 - 1] = "T-HEAD Semiconductor Co Ltd", +[11][0x38 - 1] = "Shenzhen Hystou Technology Co Ltd", +[11][0x39 - 1] = "Syzexion", +[11][0x3a - 1] = "Kembona", +[11][0x3b - 1] = "Qingdao Thunderobot Technology Co Ltd", +[11][0x3c - 1] = "Morse Micro", +[11][0x3d - 1] = "Shenzhen Envida Technology Co Ltd", +[11][0x3e - 1] = "UDStore Solution Limited", +[11][0x3f - 1] = "Shunlie", +[11][0x40 - 1] = "Shenzhen Xin Hong Rui Tech Ltd", +[11][0x41 - 1] = "Shenzhen Yze Technology Co Ltd", +[11][0x42 - 1] = "Shenzhen Huang Pu He Xin Technology", +[11][0x43 - 1] = "Xiamen Pengpai Microelectronics Co Ltd", +[11][0x44 - 1] = "JISHUN", +[11][0x45 - 1] = "Shenzhen WODPOSIT Technology Co", +[11][0x46 - 1] = "Unistar", +[11][0x47 - 1] = "UNICORE Electronic (Suzhou) Co Ltd", +[11][0x48 - 1] = "Axonne Inc", +[11][0x49 - 1] = "Shenzhen SOVERECA Technology Co", +[11][0x4a - 1] = "Dire Wolf", +[11][0x4b - 1] = "Whampoa Core Technology Co Ltd", +[11][0x4c - 1] = "CSI Halbleiter GmbH", +[11][0x4d - 1] = "ONE Semiconductor", +[11][0x4e - 1] = "SimpleMachines Inc", +[11][0x4f - 1] = "Shenzhen Chengyi Qingdian Electronic", +[11][0x50 - 1] = "Shenzhen Xinlianxin Network Technology", +[11][0x51 - 1] = "Vayyar Imaging Ltd", +[11][0x52 - 1] = "Paisen Network Technology Co Ltd", +[11][0x53 - 1] = "Shenzhen Fengwensi Technology Co Ltd", +[11][0x54 - 1] = "Caplink Technology Limited", +[11][0x55 - 1] = "JJT Solution Co Ltd", +[11][0x56 - 1] = "HOSIN Global Electronics Co Ltd", +[11][0x57 - 1] = "Shenzhen KingDisk Century Technology", +[11][0x58 - 1] = "SOYO", +[11][0x59 - 1] = "DIT Technology Co Ltd", +[11][0x5a - 1] = "iFound", +[11][0x5b - 1] = "Aril Computer Company", +[11][0x5c - 1] = "ASUS", +[11][0x5d - 1] = "Shenzhen Ruiyingtong Technology Co", +[11][0x5e - 1] = "HANA Micron", +[11][0x5f - 1] = "RANSOR", +[11][0x60 - 1] = "Axiado Corporation", +[11][0x61 - 1] = "Tesla Corporation", +[11][0x62 - 1] = "Pingtouge (Shanghai) Semiconductor Co", +[11][0x63 - 1] = "S3Plus Technologies SA", +[11][0x64 - 1] = "Integrated Silicon Solution Israel Ltd", +[11][0x65 - 1] = "GreenWaves Technologies", +[11][0x66 - 1] = "NUVIA Inc", +[11][0x67 - 1] = "Guangzhou Shuvrwine Technology Co", +[11][0x68 - 1] = "Shenzhen Hangshun Chip Technology", +[11][0x69 - 1] = "Chengboliwei Electronic Business", +[11][0x6a - 1] = "Kowin Technology HK Limited", +[11][0x6b - 1] = "Euronet Technology Inc", +[11][0x6c - 1] = "SCY", +[11][0x6d - 1] = "Shenzhen Xinhongyusheng Electrical", +[11][0x6e - 1] = "PICOCOM", +[11][0x6f - 1] = "Shenzhen Toooogo Memory Technology", +[11][0x70 - 1] = "VLSI Solution", +[11][0x71 - 1] = "Costar Electronics Inc", +[11][0x72 - 1] = "Shenzhen Huatop Technology Co Ltd", +[11][0x73 - 1] = "Inspur Electronic Information Industry", +[11][0x74 - 1] = "Shenzhen Boyuan Computer Technology", +[11][0x75 - 1] = "Beijing Welldisk Electronics Co Ltd", +[11][0x76 - 1] = "Suzhou EP Semicon Co Ltd", +[11][0x77 - 1] = "Zhejiang Dahua Memory Technology", +[11][0x78 - 1] = "Virtu Financial", +[11][0x79 - 1] = "Datotek International Co Ltd", +[11][0x7a - 1] = "Telecom and Microelectronics Industries", +[11][0x7b - 1] = "Echow Technology Ltd", +[11][0x7c - 1] = "APEX-INFO", +[11][0x7d - 1] = "Yingpark", +[11][0x7e - 1] = "Shenzhen Bigway Tech Co Ltd", +[12][0x01 - 1] = "Beijing Haawking Technology Co Ltd", +[12][0x02 - 1] = "Open HW Group", +[12][0x03 - 1] = "JHICC", +[12][0x04 - 1] = "ncoder AG", +[12][0x05 - 1] = "ThinkTech Information Technology Co", +[12][0x06 - 1] = "Shenzhen Chixingzhe Technology Co Ltd", +[12][0x07 - 1] = "Biao Ram Technology Co Ltd", +[12][0x08 - 1] = "Shenzhen Kaizhuoyue Electronics Co Ltd", +[12][0x09 - 1] = "Shenzhen YC Storage Technology Co Ltd", +[12][0x0a - 1] = "Shenzhen Chixingzhe Technology Co", +[12][0x0b - 1] = "Wink Semiconductor (Shenzhen) Co Ltd", +[12][0x0c - 1] = "AISTOR", +[12][0x0d - 1] = "Palma Ceia SemiDesign", +[12][0x0e - 1] = "EM Microelectronic-Marin SA", +[12][0x0f - 1] = "Shenzhen Monarch Memory Technology", +[12][0x10 - 1] = "Reliance Memory Inc", +[12][0x11 - 1] = "Jesis", +[12][0x12 - 1] = "Espressif Systems (Shanghai) Co Ltd", +[12][0x13 - 1] = "Shenzhen Sati Smart Technology Co Ltd", +[12][0x14 - 1] = "NeuMem Co Ltd", +[12][0x15 - 1] = "Lifelong", +[12][0x16 - 1] = "Beijing Oitech Technology Co Ltd", +[12][0x17 - 1] = "Groupe LDLC", +[12][0x18 - 1] = "Semidynamics Technology Services SLU", +[12][0x19 - 1] = "swordbill", +[12][0x1a - 1] = "YIREN", +[12][0x1b - 1] = "Shenzhen Yinxiang Technology Co Ltd", +[12][0x1c - 1] = "PoweV Electronic Technology Co Ltd", +[12][0x1d - 1] = "LEORICE", +[12][0x1e - 1] = "Waymo LLC", +[12][0x1f - 1] = "Ventana Micro Systems", +[12][0x20 - 1] = "Hefei Guangxin Microelectronics Co Ltd", +[12][0x21 - 1] = "Shenzhen Sooner Industrial Co Ltd", +[12][0x22 - 1] = "Horizon Robotics", +[12][0x23 - 1] = "Tangem AG", +[12][0x24 - 1] = "FuturePath Technology (Shenzhen) Co", +[12][0x25 - 1] = "RC Module", +[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", +[12][0x2a - 1] = "Ceremorphic Inc", +[12][0x2b - 1] = "Biwin Storage Technology Co Ltd", +[12][0x2c - 1] = "Beijing ESWIN Computing Technology", +[12][0x2d - 1] = "WeForce Co Ltd", +[12][0x2e - 1] = "Shenzhen Fanxiang Information Technology", +[12][0x2f - 1] = "Unisoc", +[12][0x30 - 1] = "YingChu", +[12][0x31 - 1] = "GUANCUN", +[12][0x32 - 1] = "IPASON", +[12][0x33 - 1] = "Ayar Labs", +[12][0x34 - 1] = "Amazon", +[12][0x35 - 1] = "Shenzhen Xinxinshun Technology Co", +[12][0x36 - 1] = "Galois Inc", +[12][0x37 - 1] = "Ubilite Inc", +[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", +[12][0x3c - 1] = "Group Star Technology Co Ltd", +[12][0x3d - 1] = "RWA (Hong Kong) Ltd", +[12][0x3e - 1] = "Genesys Logic Inc", +[12][0x3f - 1] = "T3 Robotics Inc.", +[12][0x40 - 1] = "Biostar Microtech International Corp", +[12][0x41 - 1] = "Shenzhen SXmicro Technology Co Ltd", +[12][0x42 - 1] = "Shanghai Yili Computer Technology Co", +[12][0x43 - 1] = "Zhixin Semicoducotor Co Ltd", +[12][0x44 - 1] = "uFound", +[12][0x45 - 1] = "Aigo Data Security Technology Co. Ltd", +[12][0x46 - 1] = ".GXore Technologies", +[12][0x47 - 1] = "Shenzhen Pradeon Intelligent Technology", +[12][0x48 - 1] = "Power LSI", +[12][0x49 - 1] = "PRIME", +[12][0x4a - 1] = "Shenzhen Juyang Innovative Technology", +[12][0x4b - 1] = "CERVO", +[12][0x4c - 1] = "SiEngine Technology Co., Ltd.", +[12][0x4d - 1] = "Beijing Unigroup Tsingteng MicroSystem", +[12][0x4e - 1] = "Brainsao GmbH", +[12][0x4f - 1] = "Credo Technology Group Ltd", +[12][0x50 - 1] = "Shanghai Biren Technology Co Ltd", +[12][0x51 - 1] = "Nucleu Semiconductor", +[12][0x52 - 1] = "Shenzhen Guangshuo Electronics Co Ltd", +[12][0x53 - 1] = "ZhongsihangTechnology Co Ltd", +[12][0x54 - 1] = "Suzhou Mainshine Electronic Co Ltd.", +[12][0x55 - 1] = "Guangzhou Riss Electronic Technology", +[12][0x56 - 1] = "Shenzhen Cloud Security Storage Co", +[12][0x57 - 1] = "ROG", +[12][0x58 - 1] = "Perceive", +[12][0x59 - 1] = "e-peas", +[12][0x5a - 1] = "Fraunhofer IPMS", +[12][0x5b - 1] = "Shenzhen Daxinlang Electronic Tech Co", +[12][0x5c - 1] = "Abacus Peripherals Private Limited", +[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 d13bdfba4c..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,92 +13,69 @@ * 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 +#include "config.h" +#endif + +#include "jim-nvp.h" #include <string.h> -#include <jim-nvp.h> -int Jim_GetNvp(Jim_Interp *interp, - Jim_Obj *objPtr, const Jim_Nvp *nvp_table, const Jim_Nvp **result) +int jim_get_nvp(Jim_Interp *interp, + Jim_Obj *objptr, const struct jim_nvp *nvp_table, const struct jim_nvp **result) { - Jim_Nvp *n; + struct jim_nvp *n; int e; - e = Jim_Nvp_name2value_obj(interp, nvp_table, objPtr, &n); + e = jim_nvp_name2value_obj(interp, nvp_table, objptr, &n); if (e == JIM_ERR) return e; /* Success? found? */ if (n->name) { /* remove const */ - *result = (Jim_Nvp *) n; + *result = (struct jim_nvp *)n; return JIM_OK; } else return JIM_ERR; } -Jim_Nvp *Jim_Nvp_name2value_simple(const Jim_Nvp *p, const char *name) +struct jim_nvp *jim_nvp_name2value_simple(const struct jim_nvp *p, const char *name) { while (p->name) { - if (0 == strcmp(name, p->name)) + if (strcmp(name, p->name) == 0) break; p++; } - return (Jim_Nvp *) (p); + return (struct jim_nvp *)p; } -Jim_Nvp *Jim_Nvp_name2value_nocase_simple(const Jim_Nvp *p, const char *name) +struct jim_nvp *jim_nvp_name2value_nocase_simple(const struct jim_nvp *p, const char *name) { while (p->name) { - if (0 == strcasecmp(name, p->name)) + if (strcasecmp(name, p->name) == 0) break; p++; } - return (Jim_Nvp *) (p); + return (struct jim_nvp *)p; } -int Jim_Nvp_name2value_obj(Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim_Nvp **result) +int jim_nvp_name2value_obj(Jim_Interp *interp, const struct jim_nvp *p, Jim_Obj *o, struct jim_nvp **result) { - return Jim_Nvp_name2value(interp, p, Jim_String(o), result); + return jim_nvp_name2value(interp, p, Jim_String(o), result); } -int Jim_Nvp_name2value(Jim_Interp *interp, const Jim_Nvp *_p, const char *name, Jim_Nvp **result) +int jim_nvp_name2value(Jim_Interp *interp, const struct jim_nvp *_p, const char *name, struct jim_nvp **result) { - const Jim_Nvp *p; + const struct jim_nvp *p; - p = Jim_Nvp_name2value_simple(_p, name); + p = jim_nvp_name2value_simple(_p, name); /* result */ if (result) - *result = (Jim_Nvp *) (p); + *result = (struct jim_nvp *)p; /* found? */ if (p->name) @@ -105,23 +84,23 @@ int Jim_Nvp_name2value(Jim_Interp *interp, const Jim_Nvp *_p, const char *name, return JIM_ERR; } -int Jim_Nvp_name2value_obj_nocase(Jim_Interp *interp, - const Jim_Nvp *p, +int jim_nvp_name2value_obj_nocase(Jim_Interp *interp, + const struct jim_nvp *p, Jim_Obj *o, - Jim_Nvp **puthere) + struct jim_nvp **puthere) { - return Jim_Nvp_name2value_nocase(interp, p, Jim_String(o), puthere); + return jim_nvp_name2value_nocase(interp, p, Jim_String(o), puthere); } -int Jim_Nvp_name2value_nocase(Jim_Interp *interp, const Jim_Nvp *_p, const char *name, - Jim_Nvp **puthere) +int jim_nvp_name2value_nocase(Jim_Interp *interp, const struct jim_nvp *_p, const char *name, + struct jim_nvp **puthere) { - const Jim_Nvp *p; + const struct jim_nvp *p; - p = Jim_Nvp_name2value_nocase_simple(_p, name); + p = jim_nvp_name2value_nocase_simple(_p, name); if (puthere) - *puthere = (Jim_Nvp *) (p); + *puthere = (struct jim_nvp *)p; /* found */ if (p->name) return JIM_OK; @@ -129,7 +108,7 @@ int Jim_Nvp_name2value_nocase(Jim_Interp *interp, const Jim_Nvp *_p, const char return JIM_ERR; } -int Jim_Nvp_value2name_obj(Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim_Nvp **result) +int jim_nvp_value2name_obj(Jim_Interp *interp, const struct jim_nvp *p, Jim_Obj *o, struct jim_nvp **result) { int e; jim_wide w; @@ -138,27 +117,27 @@ int Jim_Nvp_value2name_obj(Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim if (e != JIM_OK) return e; - return Jim_Nvp_value2name(interp, p, w, result); + return jim_nvp_value2name(interp, p, w, result); } -Jim_Nvp *Jim_Nvp_value2name_simple(const Jim_Nvp *p, int value) +struct jim_nvp *jim_nvp_value2name_simple(const struct jim_nvp *p, int value) { while (p->name) { if (value == p->value) break; p++; } - return (Jim_Nvp *) (p); + return (struct jim_nvp *)p; } -int Jim_Nvp_value2name(Jim_Interp *interp, const Jim_Nvp *_p, int value, Jim_Nvp **result) +int jim_nvp_value2name(Jim_Interp *interp, const struct jim_nvp *_p, int value, struct jim_nvp **result) { - const Jim_Nvp *p; + const struct jim_nvp *p; - p = Jim_Nvp_value2name_simple(_p, value); + p = jim_nvp_value2name_simple(_p, value); if (result) - *result = (Jim_Nvp *) (p); + *result = (struct jim_nvp *)p; if (p->name) return JIM_OK; @@ -166,7 +145,7 @@ int Jim_Nvp_value2name(Jim_Interp *interp, const Jim_Nvp *_p, int value, Jim_Nvp return JIM_ERR; } -int Jim_GetOpt_Setup(Jim_GetOptInfo *p, Jim_Interp *interp, int argc, Jim_Obj *const *argv) +int jim_getopt_setup(struct jim_getopt_info *p, Jim_Interp *interp, int argc, Jim_Obj *const *argv) { memset(p, 0, sizeof(*p)); p->interp = interp; @@ -176,7 +155,7 @@ int Jim_GetOpt_Setup(Jim_GetOptInfo *p, Jim_Interp *interp, int argc, Jim_Obj *c return JIM_OK; } -void Jim_GetOpt_Debug(Jim_GetOptInfo *p) +void jim_getopt_debug(struct jim_getopt_info *p) { int x; @@ -186,7 +165,7 @@ void Jim_GetOpt_Debug(Jim_GetOptInfo *p) fprintf(stderr, "-------\n"); } -int Jim_GetOpt_Obj(Jim_GetOptInfo *goi, Jim_Obj **puthere) +int jim_getopt_obj(struct jim_getopt_info *goi, Jim_Obj **puthere) { Jim_Obj *o; @@ -199,19 +178,19 @@ int Jim_GetOpt_Obj(Jim_GetOptInfo *goi, Jim_Obj **puthere) } if (puthere) *puthere = o; - if (o != NULL) + if (o) return JIM_OK; else return JIM_ERR; } -int Jim_GetOpt_String(Jim_GetOptInfo *goi, const char **puthere, int *len) +int jim_getopt_string(struct jim_getopt_info *goi, const char **puthere, int *len) { int r; Jim_Obj *o; const char *cp; - r = Jim_GetOpt_Obj(goi, &o); + r = jim_getopt_obj(goi, &o); if (r == JIM_OK) { cp = Jim_GetString(o, len); if (puthere) { @@ -221,16 +200,16 @@ int Jim_GetOpt_String(Jim_GetOptInfo *goi, const char **puthere, int *len) return r; } -int Jim_GetOpt_Double(Jim_GetOptInfo *goi, double *puthere) +int jim_getopt_double(struct jim_getopt_info *goi, double *puthere) { int r; Jim_Obj *o; double _safe; - if (puthere == NULL) + if (!puthere) puthere = &_safe; - r = Jim_GetOpt_Obj(goi, &o); + r = jim_getopt_obj(goi, &o); if (r == JIM_OK) { r = Jim_GetDouble(goi->interp, o, puthere); if (r != JIM_OK) @@ -239,61 +218,61 @@ int Jim_GetOpt_Double(Jim_GetOptInfo *goi, double *puthere) return r; } -int Jim_GetOpt_Wide(Jim_GetOptInfo *goi, jim_wide *puthere) +int jim_getopt_wide(struct jim_getopt_info *goi, jim_wide *puthere) { int r; Jim_Obj *o; jim_wide _safe; - if (puthere == NULL) + if (!puthere) puthere = &_safe; - r = Jim_GetOpt_Obj(goi, &o); + r = jim_getopt_obj(goi, &o); if (r == JIM_OK) r = Jim_GetWide(goi->interp, o, puthere); return r; } -int Jim_GetOpt_Nvp(Jim_GetOptInfo *goi, const Jim_Nvp *nvp, Jim_Nvp **puthere) +int jim_getopt_nvp(struct jim_getopt_info *goi, const struct jim_nvp *nvp, struct jim_nvp **puthere) { - Jim_Nvp *_safe; + struct jim_nvp *_safe; Jim_Obj *o; int e; - if (puthere == NULL) + if (!puthere) puthere = &_safe; - e = Jim_GetOpt_Obj(goi, &o); + e = jim_getopt_obj(goi, &o); if (e == JIM_OK) - e = Jim_Nvp_name2value_obj(goi->interp, nvp, o, puthere); + e = jim_nvp_name2value_obj(goi->interp, nvp, o, puthere); return e; } -void Jim_GetOpt_NvpUnknown(Jim_GetOptInfo *goi, const Jim_Nvp *nvptable, int hadprefix) +void jim_getopt_nvp_unknown(struct jim_getopt_info *goi, const struct jim_nvp *nvptable, int hadprefix) { if (hadprefix) - Jim_SetResult_NvpUnknown(goi->interp, goi->argv[-2], goi->argv[-1], nvptable); + jim_set_result_nvp_unknown(goi->interp, goi->argv[-2], goi->argv[-1], nvptable); else - Jim_SetResult_NvpUnknown(goi->interp, NULL, goi->argv[-1], nvptable); + jim_set_result_nvp_unknown(goi->interp, NULL, goi->argv[-1], nvptable); } -int Jim_GetOpt_Enum(Jim_GetOptInfo *goi, const char *const *lookup, int *puthere) +int jim_getopt_enum(struct jim_getopt_info *goi, const char *const *lookup, int *puthere) { int _safe; Jim_Obj *o; int e; - if (puthere == NULL) + if (!puthere) puthere = &_safe; - e = Jim_GetOpt_Obj(goi, &o); + e = jim_getopt_obj(goi, &o); if (e == JIM_OK) e = Jim_GetEnum(goi->interp, o, lookup, puthere, "option", JIM_ERRMSG); return e; } -void Jim_SetResult_NvpUnknown(Jim_Interp *interp, - Jim_Obj *param_name, Jim_Obj *param_value, const Jim_Nvp *nvp) +void jim_set_result_nvp_unknown(Jim_Interp *interp, + Jim_Obj *param_name, Jim_Obj *param_value, const struct jim_nvp *nvp) { if (param_name) Jim_SetResultFormatted(interp, @@ -318,7 +297,7 @@ void Jim_SetResult_NvpUnknown(Jim_Interp *interp, } } -const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +const char *jim_debug_argv_string(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { static Jim_Obj *debug_string_obj; @@ -333,9 +312,3 @@ const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *a return Jim_String(debug_string_obj); } - -int Jim_nvpInit(Jim_Interp *interp) -{ - /* This is really a helper library, not an extension, but this is the easy way */ - return JIM_OK; -} diff --git a/src/helper/jim-nvp.h b/src/helper/jim-nvp.h index 4c4dc8ff4f..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 @@ -62,7 +37,7 @@ * * Example: * \code - * const Jim_Nvp yn[] = { + * const struct jim_nvp yn[] = { * { "yes", 1 }, * { "no" , 0 }, * { "yep", 1 }, @@ -70,60 +45,60 @@ * { NULL, -1 }, * }; * - * Jim_Nvp *result - * e = Jim_Nvp_name2value(interp, yn, "y", &result); + * struct jim_nvp *result + * e = jim_nvp_name2value(interp, yn, "y", &result); * returns &yn[0]; - * e = Jim_Nvp_name2value(interp, yn, "n", &result); + * e = jim_nvp_name2value(interp, yn, "n", &result); * returns &yn[1]; - * e = Jim_Nvp_name2value(interp, yn, "Blah", &result); + * e = jim_nvp_name2value(interp, yn, "Blah", &result); * returns &yn[4]; * \endcode * * During the number2name operation, the first matching value is returned. */ -typedef struct { +struct jim_nvp { const char *name; int value; -} Jim_Nvp; +}; -int Jim_GetNvp(Jim_Interp *interp, - Jim_Obj *objPtr, - const Jim_Nvp *nvp_table, - const Jim_Nvp **result); +int jim_get_nvp(Jim_Interp *interp, + Jim_Obj *objptr, + const struct jim_nvp *nvp_table, + const struct jim_nvp **result); /* Name Value Pairs Operations */ -Jim_Nvp *Jim_Nvp_name2value_simple(const Jim_Nvp *nvp_table, const char *name); -Jim_Nvp *Jim_Nvp_name2value_nocase_simple(const Jim_Nvp *nvp_table, const char *name); -Jim_Nvp *Jim_Nvp_value2name_simple(const Jim_Nvp *nvp_table, int v); +struct jim_nvp *jim_nvp_name2value_simple(const struct jim_nvp *nvp_table, const char *name); +struct jim_nvp *jim_nvp_name2value_nocase_simple(const struct jim_nvp *nvp_table, const char *name); +struct jim_nvp *jim_nvp_value2name_simple(const struct jim_nvp *nvp_table, int v); -int Jim_Nvp_name2value(Jim_Interp *interp, - const Jim_Nvp *nvp_table, +int jim_nvp_name2value(Jim_Interp *interp, + const struct jim_nvp *nvp_table, const char *name, - Jim_Nvp **result); -int Jim_Nvp_name2value_nocase(Jim_Interp *interp, - const Jim_Nvp *nvp_table, + struct jim_nvp **result); +int jim_nvp_name2value_nocase(Jim_Interp *interp, + const struct jim_nvp *nvp_table, const char *name, - Jim_Nvp **result); -int Jim_Nvp_value2name(Jim_Interp *interp, const Jim_Nvp *nvp_table, int value, Jim_Nvp **result); + struct jim_nvp **result); +int jim_nvp_value2name(Jim_Interp *interp, const struct jim_nvp *nvp_table, int value, struct jim_nvp **result); -int Jim_Nvp_name2value_obj(Jim_Interp *interp, - const Jim_Nvp *nvp_table, +int jim_nvp_name2value_obj(Jim_Interp *interp, + const struct jim_nvp *nvp_table, Jim_Obj *name_obj, - Jim_Nvp **result); -int Jim_Nvp_name2value_obj_nocase(Jim_Interp *interp, - const Jim_Nvp *nvp_table, + struct jim_nvp **result); +int jim_nvp_name2value_obj_nocase(Jim_Interp *interp, + const struct jim_nvp *nvp_table, Jim_Obj *name_obj, - Jim_Nvp **result); -int Jim_Nvp_value2name_obj(Jim_Interp *interp, - const Jim_Nvp *nvp_table, + struct jim_nvp **result); +int jim_nvp_value2name_obj(Jim_Interp *interp, + const struct jim_nvp *nvp_table, Jim_Obj *value_obj, - Jim_Nvp **result); + struct jim_nvp **result); /** prints a nice 'unknown' parameter error message to the 'result' */ -void Jim_SetResult_NvpUnknown(Jim_Interp *interp, +void jim_set_result_nvp_unknown(Jim_Interp *interp, Jim_Obj *param_name, Jim_Obj *param_value, - const Jim_Nvp *nvp_table); + const struct jim_nvp *nvp_table); /** Debug: convert argc/argv into a printable string for printf() debug * @@ -142,7 +117,7 @@ void Jim_SetResult_NvpUnknown(Jim_Interp *interp, * fclose(fp); * \endcode */ -const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *argv); +const char *jim_debug_argv_string(Jim_Interp *interp, int argc, Jim_Obj *const *argv); /** A TCL -ish GetOpt like code. @@ -157,25 +132,25 @@ const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *a * Only supports tcl type options, like "-foo 123" */ -typedef struct jim_getopt { +struct jim_getopt_info { Jim_Interp *interp; int argc; Jim_Obj *const *argv; int isconfigure; /* non-zero if configure */ -} Jim_GetOptInfo; +}; /** GetOpt - how to. * * Example (short and incomplete): * \code - * Jim_GetOptInfo goi; + * struct jim_getopt_info goi; * - * Jim_GetOpt_Setup(&goi, interp, argc, argv); + * jim_getopt_setup(&goi, interp, argc, argv); * * while (goi.argc) { - * e = Jim_GetOpt_Nvp(&goi, nvp_options, &n); + * e = jim_getopt_nvp(&goi, nvp_options, &n); * if (e != JIM_OK) { - * Jim_GetOpt_NvpUnknown(&goi, nvp_options, 0); + * jim_getopt_nvp_unknown(&goi, nvp_options, 0); * return e; * } * @@ -187,16 +162,16 @@ typedef struct jim_getopt { * if (goi.argc < 1) { * .. not enough args error .. * } - * Jim_GetOpt_String(&goi, &cp, NULL); + * jim_getopt_string(&goi, &cp, NULL); * printf("FIRSTNAME: %s\n", cp); * case AGE: - * Jim_GetOpt_Wide(&goi, &w); + * jim_getopt_wide(&goi, &w); * printf("AGE: %d\n", (int)(w)); * break; * case POLITICS: - * e = Jim_GetOpt_Nvp(&goi, nvp_politics, &n); + * e = jim_getopt_nvp(&goi, nvp_politics, &n); * if (e != JIM_OK) { - * Jim_GetOpt_NvpUnknown(&goi, nvp_politics, 1); + * jim_getopt_nvp_unknown(&goi, nvp_politics, 1); * return e; * } * } @@ -214,13 +189,13 @@ typedef struct jim_getopt { * \param argv - argv (will be copied) * * \code - * Jim_GetOptInfo goi; + * struct jim_getopt_info goi; * * Jim_GetOptSetup(&goi, interp, argc, argv); * \endcode */ -int Jim_GetOpt_Setup(Jim_GetOptInfo *goi, +int jim_getopt_setup(struct jim_getopt_info *goi, Jim_Interp *interp, int argc, Jim_Obj *const *argv); @@ -229,7 +204,7 @@ int Jim_GetOpt_Setup(Jim_GetOptInfo *goi, /** Debug - Dump parameters to stderr * \param goi - current parameters */ -void Jim_GetOpt_Debug(Jim_GetOptInfo *goi); +void jim_getopt_debug(struct jim_getopt_info *goi); /** Remove argv[0] from the list. * @@ -237,7 +212,7 @@ void Jim_GetOpt_Debug(Jim_GetOptInfo *goi); * \param puthere - where param is put * */ -int Jim_GetOpt_Obj(Jim_GetOptInfo *goi, Jim_Obj **puthere); +int jim_getopt_obj(struct jim_getopt_info *goi, Jim_Obj **puthere); /** Remove argv[0] as string. * @@ -245,7 +220,7 @@ int Jim_GetOpt_Obj(Jim_GetOptInfo *goi, Jim_Obj **puthere); * \param puthere - where param is put * \param len - return its length */ -int Jim_GetOpt_String(Jim_GetOptInfo *goi, const char **puthere, int *len); +int jim_getopt_string(struct jim_getopt_info *goi, const char **puthere, int *len); /** Remove argv[0] as double. * @@ -253,14 +228,14 @@ int Jim_GetOpt_String(Jim_GetOptInfo *goi, const char **puthere, int *len); * \param puthere - where param is put. * */ -int Jim_GetOpt_Double(Jim_GetOptInfo *goi, double *puthere); +int jim_getopt_double(struct jim_getopt_info *goi, double *puthere); /** Remove argv[0] as wide. * * \param goi - get opt info * \param puthere - where param is put. */ -int Jim_GetOpt_Wide(Jim_GetOptInfo *goi, jim_wide *puthere); +int jim_getopt_wide(struct jim_getopt_info *goi, jim_wide *puthere); /** Remove argv[0] as NVP. * @@ -269,7 +244,7 @@ int Jim_GetOpt_Wide(Jim_GetOptInfo *goi, jim_wide *puthere); * \param puthere - where param is put. * */ -int Jim_GetOpt_Nvp(Jim_GetOptInfo *goi, const Jim_Nvp *lookup, Jim_Nvp **puthere); +int jim_getopt_nvp(struct jim_getopt_info *goi, const struct jim_nvp *lookup, struct jim_nvp **puthere); /** Create an appropriate error message for an NVP. * @@ -289,20 +264,20 @@ int Jim_GetOpt_Nvp(Jim_GetOptInfo *goi, const Jim_Nvp *lookup, Jim_Nvp **puthere * * while (goi.argc) { * // Get the next option - * e = Jim_GetOpt_Nvp(&goi, cmd_options, &n); + * e = jim_getopt_nvp(&goi, cmd_options, &n); * if (e != JIM_OK) { * // option was not recognized * // pass 'hadprefix = 0' because there is no prefix - * Jim_GetOpt_NvpUnknown(&goi, cmd_options, 0); + * jim_getopt_nvp_unknown(&goi, cmd_options, 0); * return e; * } * * switch (n->value) { * case OPT_SEX: * // handle: --sex male | female | lots | needmore - * e = Jim_GetOpt_Nvp(&goi, &nvp_sex, &n); + * e = jim_getopt_nvp(&goi, &nvp_sex, &n); * if (e != JIM_OK) { - * Jim_GetOpt_NvpUnknown(&ogi, nvp_sex, 1); + * jim_getopt_nvp_unknown(&ogi, nvp_sex, 1); * return e; * } * printf("Code: (%d) is %s\n", n->value, n->name); @@ -314,7 +289,7 @@ int Jim_GetOpt_Nvp(Jim_GetOptInfo *goi, const Jim_Nvp *lookup, Jim_Nvp **puthere * \endcode * */ -void Jim_GetOpt_NvpUnknown(Jim_GetOptInfo *goi, const Jim_Nvp *lookup, int hadprefix); +void jim_getopt_nvp_unknown(struct jim_getopt_info *goi, const struct jim_nvp *lookup, int hadprefix); /** Remove argv[0] as Enum @@ -324,6 +299,6 @@ void Jim_GetOpt_NvpUnknown(Jim_GetOptInfo *goi, const Jim_Nvp *lookup, int hadpr * \param puthere - where param is put. * */ -int Jim_GetOpt_Enum(Jim_GetOptInfo *goi, const char *const *lookup, int *puthere); +int jim_getopt_enum(struct jim_getopt_info *goi, const char *const *lookup, int *puthere); #endif /* OPENOCD_HELPER_JIM_NVP_H */ diff --git a/src/helper/list.h b/src/helper/list.h index 6fd0e7ca71..47290c2602 100644 --- a/src/helper/list.h +++ b/src/helper/list.h @@ -1,139 +1,96 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * Copyright (c) 2013-2016 Mellanox Technologies, Ltd. + * Copyright (c) 2021-2024 by Antonio Borneo <borneo.antonio@gmail.com> + * All rights reserved. + */ + +/* + * Circular doubly linked list implementation. + * + * The content of this file is mainly copied/inspired from FreeBSD code in: + * https://cgit.freebsd.org/src/tree/ + * files: + * sys/compat/linuxkpi/common/include/linux/list.h + * sys/compat/linuxkpi/common/include/linux/types.h + * + * Last aligned with release/13.3.0: + * + * - Skip 'hlist_*' double linked lists with a single pointer list head. + * - Expand WRITE_ONCE(). + * - Use TAB for indentation. + * - Put macro arguments within parenthesis. + * - Remove blank lines after an open brace '{'. + * - Remove multiple assignment. + * + * There is an example of using this file in contrib/list_example.c. + */ + #ifndef OPENOCD_HELPER_LIST_H #define OPENOCD_HELPER_LIST_H -/* begin local changes */ -#include <helper/types.h> +/* begin OpenOCD changes */ -#define prefetch(x) ((void)x) -#define LIST_POISON1 NULL -#define LIST_POISON2 NULL +#include <stddef.h> struct list_head { - struct list_head *next, *prev; -}; -struct hlist_head { - struct hlist_node *first; + struct list_head *next; + struct list_head *prev; }; -struct hlist_node { - struct hlist_node *next, **pprev; -}; -/* end local changes */ -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ +/* end OpenOCD changes */ #define LIST_HEAD_INIT(name) { &(name), &(name) } -#define LIST_HEAD(name) \ +#define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) -static inline void INIT_LIST_HEAD(struct list_head *list) +static inline void +INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -#ifndef CONFIG_DEBUG_LIST -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) +static inline int +list_empty(const struct list_head *head) { - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + return (head->next == head); } -#else -extern void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next); -#endif -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) +static inline int +list_empty_careful(const struct list_head *head) { - __list_add(new, head, head->next); -} - + struct list_head *next = head->next; -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); + return ((next == head) && (next == head->prev)); } -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head *prev, struct list_head *next) +static inline void +__list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -#ifndef CONFIG_DEBUG_LIST -static inline void __list_del_entry(struct list_head *entry) +static inline void +__list_del_entry(struct list_head *entry) { __list_del(entry->prev, entry->next); } -static inline void list_del(struct list_head *entry) +static inline void +list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; } -#else -extern void __list_del_entry(struct list_head *entry); -extern void list_del(struct list_head *entry); -#endif -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) +static inline void +list_replace(struct list_head *old, struct list_head *new) { new->next = old->next; new->next->prev = new; @@ -141,597 +98,279 @@ static inline void list_replace(struct list_head *old, new->prev->next = new; } -static inline void list_replace_init(struct list_head *old, - struct list_head *new) +static inline void +list_replace_init(struct list_head *old, struct list_head *new) { list_replace(old, new); INIT_LIST_HEAD(old); } -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) +static inline void +linux_list_add(struct list_head *new, struct list_head *prev, + struct list_head *next) { - __list_del_entry(entry); - INIT_LIST_HEAD(entry); + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; } -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) +static inline void +list_del_init(struct list_head *entry) { - __list_del_entry(list); - list_add(list, head); + list_del(entry); + INIT_LIST_HEAD(entry); } -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del_entry(list); - list_add_tail(list, head); -} +#define list_entry(ptr, type, field) container_of(ptr, type, field) -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +#define list_first_entry_or_null(ptr, type, member) \ + (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) + +#define list_next_entry(ptr, member) \ + list_entry(((ptr)->member.next), typeof(*(ptr)), member) + +#define list_safe_reset_next(ptr, n, member) \ + (n) = list_next_entry(ptr, member) + +#define list_prev_entry(ptr, member) \ + list_entry(((ptr)->member.prev), typeof(*(ptr)), member) + +#define list_for_each(p, head) \ + for (p = (head)->next; p != (head); p = (p)->next) + +#define list_for_each_safe(p, n, head) \ + for (p = (head)->next, n = (p)->next; p != (head); p = n, n = (p)->next) + +#define list_for_each_entry(p, h, field) \ + for (p = list_entry((h)->next, typeof(*p), field); &(p)->field != (h); \ + p = list_entry((p)->field.next, typeof(*p), field)) + +#define list_for_each_entry_safe(p, n, h, field) \ + for (p = list_entry((h)->next, typeof(*p), field), \ + n = list_entry((p)->field.next, typeof(*p), field); &(p)->field != (h);\ + p = n, n = list_entry(n->field.next, typeof(*n), field)) + +#define list_for_each_entry_from(p, h, field) \ + for ( ; &(p)->field != (h); \ + p = list_entry((p)->field.next, typeof(*p), field)) + +#define list_for_each_entry_continue(p, h, field) \ + for (p = list_next_entry((p), field); &(p)->field != (h); \ + p = list_next_entry((p), field)) + +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry((pos)->member.next, typeof(*pos), member); \ + &(pos)->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#define list_for_each_entry_reverse(p, h, field) \ + for (p = list_entry((h)->prev, typeof(*p), field); &(p)->field != (h); \ + p = list_entry((p)->field.prev, typeof(*p), field)) + +#define list_for_each_entry_safe_reverse(p, n, h, field) \ + for (p = list_entry((h)->prev, typeof(*p), field), \ + n = list_entry((p)->field.prev, typeof(*p), field); &(p)->field != (h); \ + p = n, n = list_entry(n->field.prev, typeof(*n), field)) + +#define list_for_each_entry_continue_reverse(p, h, field) \ + for (p = list_entry((p)->field.prev, typeof(*p), field); &(p)->field != (h); \ + p = list_entry((p)->field.prev, typeof(*p), field)) + +#define list_for_each_prev(p, h) for (p = (h)->prev; p != (h); p = (p)->prev) + +#define list_for_each_entry_from_reverse(p, h, field) \ + for (; &p->field != (h); \ + p = list_prev_entry(p, field)) + +static inline void +list_add(struct list_head *new, struct list_head *head) { - return head->next == head; + linux_list_add(new, head, head->next); } -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) +static inline void +list_add_tail(struct list_head *new, struct list_head *head) { - struct list_head *next = head->next; - return (next == head) && (next == head->prev); + linux_list_add(new, head->prev, head); } -/** - * list_rotate_left - rotate the list to the left - * @head: the head of the list - */ -static inline void list_rotate_left(struct list_head *head) +static inline void +list_move(struct list_head *list, struct list_head *head) { - struct list_head *first; - - if (!list_empty(head)) { - first = head->next; - list_move_tail(first, head); - } + list_del(list); + list_add(list, head); } -/** - * list_is_singular - tests whether a list has just one entry. - * @head: the list to test. - */ -static inline int list_is_singular(const struct list_head *head) +static inline void +list_move_tail(struct list_head *entry, struct list_head *head) { - return !list_empty(head) && (head->next == head->prev); + list_del(entry); + list_add_tail(entry, head); } -static inline void __list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) +static inline void +list_rotate_to_front(struct list_head *entry, struct list_head *head) { - struct list_head *new_first = entry->next; - list->next = head->next; - list->next->prev = list; - list->prev = entry; - entry->next = list; - head->next = new_first; - new_first->prev = head; + list_move_tail(entry, head); } -/** - * list_cut_position - cut a list into two - * @list: a new list to add all removed entries - * @head: a list with entries - * @entry: an entry within head, could be the head itself - * and if so we won't cut the list - * - * This helper moves the initial part of @head, up to and - * including @entry, from @head to @list. You should - * pass on @entry an element you know is on @head. @list - * should be an empty list or a list you do not care about - * losing its data. - * - */ -static inline void list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) +static inline void +list_bulk_move_tail(struct list_head *head, struct list_head *first, + struct list_head *last) { - if (list_empty(head)) - return; - if (list_is_singular(head) && - (head->next != entry && head != entry)) - return; - if (entry == head) - INIT_LIST_HEAD(list); - else - __list_cut_position(list, head, entry); + first->prev->next = last->next; + last->next->prev = first->prev; + head->prev->next = first; + first->prev = head->prev; + last->next = head; + head->prev = last; } -static inline void __list_splice(const struct list_head *list, - struct list_head *prev, +static inline void +linux_list_splice(const struct list_head *list, struct list_head *prev, struct list_head *next) { - struct list_head *first = list->next; - struct list_head *last = list->prev; + struct list_head *first; + struct list_head *last; + if (list_empty(list)) + return; + first = list->next; + last = list->prev; first->prev = prev; prev->next = first; - last->next = next; next->prev = last; } -/** - * list_splice - join two lists, this is designed for stacks - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(const struct list_head *list, - struct list_head *head) +static inline void +list_splice(const struct list_head *list, struct list_head *head) { - if (!list_empty(list)) - __list_splice(list, head, head->next); + linux_list_splice(list, head, head->next); } -/** - * list_splice_tail - join two lists, each list being a queue - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice_tail(struct list_head *list, - struct list_head *head) +static inline void +list_splice_tail(struct list_head *list, struct list_head *head) { - if (!list_empty(list)) - __list_splice(list, head->prev, head); + linux_list_splice(list, head->prev, head); } -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) +static inline void +list_splice_init(struct list_head *list, struct list_head *head) { - if (!list_empty(list)) { - __list_splice(list, head, head->next); - INIT_LIST_HEAD(list); - } + linux_list_splice(list, head, head->next); + INIT_LIST_HEAD(list); } -/** - * list_splice_tail_init - join two lists and reinitialise the emptied list - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * Each of the lists is a queue. - * The list at @list is reinitialised - */ -static inline void list_splice_tail_init(struct list_head *list, - struct list_head *head) +static inline void +list_splice_tail_init(struct list_head *list, struct list_head *head) { - if (!list_empty(list)) { - __list_splice(list, head->prev, head); - INIT_LIST_HEAD(list); - } + linux_list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); } -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; prefetch(pos->next), pos != (head); \ - pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - prefetch(pos->prev), pos != (head); \ - pos = n, n = pos->prev) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - continue list iteration safe against removal - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - iterate over list from current point safe against removal - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -/** - * list_safe_reset_next - reset a stale list_for_each_entry_safe loop - * @pos: the loop cursor used in the list_for_each_entry_safe loop - * @n: temporary storage used in list_for_each_entry_safe - * @member: the name of the list_struct within the struct. - * - * list_safe_reset_next is not safe to use in general if the list may be - * modified concurrently (eg. the lock is dropped in the loop body). An - * exception to this is if the cursor element (pos) is pinned in the list, - * and list_safe_reset_next is called after re-taking the lock and before - * completing the current iteration of the loop body. - */ -#define list_safe_reset_next(pos, n, member) \ - n = list_entry(pos->member.next, typeof(*pos), member) - /* * 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). + * IGNORED */ -#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; -} - -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline void __hlist_del(struct hlist_node *n) +static inline int list_is_singular(const struct list_head *head) { - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; + return !list_empty(head) && (head->next == head->prev); } -static inline void hlist_del(struct hlist_node *n) +static inline void __list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) { - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; + struct list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; } -static inline void hlist_del_init(struct hlist_node *n) +static inline void list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) { - if (!hlist_unhashed(n)) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } + if (list_empty(head)) + return; + if (list_is_singular(head) && + (head->next != entry && head != entry)) + return; + if (entry == head) + INIT_LIST_HEAD(list); + else + __list_cut_position(list, head, entry); } -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +static inline int list_is_first(const struct list_head *list, + const struct list_head *head) { - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; + return (list->prev == head); } -/* next must be != NULL */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) { - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; + return list->next == head; } -static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) +static inline size_t +list_count_nodes(const struct list_head *list) { - next->next = n->next; - n->next = next; - next->pprev = &n->next; + const struct list_head *lh; + size_t count; - if (next->next) - next->next->pprev = &next->next; -} + count = 0; + list_for_each(lh, list) { + count++; + } -/* after that we'll appear to be on some hlist and hlist_del will work */ -static inline void hlist_add_fake(struct hlist_node *n) -{ - n->pprev = &n->next; + return (count); } /* - * Move a list from one list head to another. Fixup the pprev - * reference of the first entry if it exists. + * Double linked lists with a single pointer list head. + * IGNORED */ -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 && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) +/* begin OpenOCD extensions */ /** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. + * list_for_each_entry_direction - iterate forward/backward over list of given type + * @param is_fwd the iterate direction, true for forward, false for backward. + * @param p the type * to use as a loop cursor. + * @param h the head of the list. + * @param field the name of the list_head within the struct. */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ - pos = pos->next) +#define list_for_each_entry_direction(is_fwd, p, h, field) \ + for (p = list_entry(is_fwd ? (h)->next : (h)->prev, typeof(*p), field); \ + &(p)->field != (h); \ + p = list_entry(is_fwd ? (p)->field.next : (p)->field.prev, typeof(*p), field)) /** - * hlist_for_each_entry_continue - iterate over a hlist continuing after current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. + * list_rotate_left - rotate the list to the left + * @param h the head of the list */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ - pos = pos->next) +static inline void list_rotate_left(struct list_head *h) +{ + struct list_head *first; -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ - pos = pos->next) + if (!list_empty(h)) { + first = h->next; + list_move_tail(first, h); + } +} -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ - pos = n) +/* end OpenOCD extensions */ #endif /* OPENOCD_HELPER_LIST_H */ diff --git a/src/helper/log.c b/src/helper/log.c index 7440b70f62..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 @@ -28,7 +17,10 @@ #include "log.h" #include "command.h" +#include "replacements.h" #include "time_support.h" +#include <server/gdb_server.h> +#include <server/server.h> #include <stdarg.h> @@ -46,7 +38,6 @@ static FILE *log_output; static struct log_callback *log_callbacks; static int64_t last_time; -static int64_t current_time; static int64_t start; @@ -107,35 +98,30 @@ static void log_puts(enum log_levels level, } f = strrchr(file, '/'); - if (f != NULL) + if (f) file = f + 1; - if (strlen(string) > 0) { - if (debug_level >= LOG_LVL_DEBUG) { - /* print with count and time information */ - int64_t t = timeval_ms() - start; + if (debug_level >= LOG_LVL_DEBUG) { + /* print with count and time information */ + int64_t t = timeval_ms() - start; #ifdef _DEBUG_FREE_SPACE_ - struct mallinfo info; - info = mallinfo(); + struct mallinfo info; + info = mallinfo(); #endif - fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()" + fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()" #ifdef _DEBUG_FREE_SPACE_ - " %d" + " %d" #endif - ": %s", log_strings[level + 1], count, t, file, line, function, + ": %s", log_strings[level + 1], count, t, file, line, function, #ifdef _DEBUG_FREE_SPACE_ - info.fordblks, + info.fordblks, #endif - string); - } else { - /* if we are using gdb through pipes then we do not want any output - * to the pipe otherwise we get repeated strings */ - fprintf(log_output, "%s%s", - (level > LOG_LVL_USER) ? log_strings[level + 1] : "", string); - } + string); } else { - /* Empty strings are sent to log callbacks to keep e.g. gdbserver alive, here we do - *nothing. */ + /* if we are using gdb through pipes then we do not want any output + * to the pipe otherwise we get repeated strings */ + fprintf(log_output, "%s%s", + (level > LOG_LVL_USER) ? log_strings[level + 1] : "", string); } fflush(log_output); @@ -162,7 +148,7 @@ void log_printf(enum log_levels level, va_start(ap, format); string = alloc_vprintf(format, ap); - if (string != NULL) { + if (string) { log_puts(level, file, line, function, string); free(string); } @@ -228,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 != NULL) { - /* 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 (file == NULL) { - LOG_ERROR("failed to open output log '%s'", CMD_ARGV[0]); + 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) { + command_print(CMD, "failed to open output log \"%s\"", CMD_ARGV[0]); return ERROR_FAIL; } - if (log_output != stderr && log_output != NULL) { - /* 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[] = { @@ -261,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", @@ -286,25 +269,28 @@ void log_init(void) /* set defaults for daemon configuration, * if not set by cmdline or cfgfile */ char *debug_env = getenv("OPENOCD_DEBUG_LEVEL"); - if (NULL != debug_env) { + if (debug_env) { int value; int retval = parse_int(debug_env, &value); - if (ERROR_OK == retval && + if (retval == ERROR_OK && debug_level >= LOG_LVL_SILENT && debug_level <= LOG_LVL_DEBUG_IO) debug_level = value; } - if (log_output == NULL) + if (!log_output) log_output = stderr; start = last_time = timeval_ms(); } -int set_log_output(struct command_context *cmd_ctx, FILE *output) +void log_exit(void) { - log_output = output; - return ERROR_OK; + if (log_output && log_output != stderr) { + /* Close log file, if it was open and wasn't stderr. */ + fclose(log_output); + } + log_output = NULL; } /* add/remove log callback handler */ @@ -321,7 +307,7 @@ int log_add_callback(log_callback_fn fn, void *priv) /* alloc memory, it is safe just to return in case of an error, no need for the caller to *check this */ cb = malloc(sizeof(struct log_callback)); - if (cb == NULL) + if (!cb) return ERROR_BUF_TOO_SMALL; /* add item to the beginning of the linked list */ @@ -366,7 +352,7 @@ char *alloc_vprintf(const char *fmt, va_list ap) * other code depend on that. They should be probably be fixed, but for * now reserve the extra byte. */ string = malloc(len + 2); - if (string == NULL) + if (!string) return NULL; /* do the real work */ @@ -411,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 " @@ -430,8 +414,7 @@ static void gdb_timeout_warning(int64_t delta_time) void keep_alive(void) { - current_time = timeval_ms(); - + int64_t current_time = timeval_ms(); int64_t delta_time = current_time - last_time; if (delta_time > KEEP_ALIVE_TIMEOUT_MS) { @@ -444,7 +427,7 @@ void keep_alive(void) last_time = current_time; /* this will keep the GDB connection alive */ - LOG_USER_N("%s", ""); + server_keep_clients_alive(); /* DANGER!!!! do not add code to invoke e.g. target event processing, * jim timer processing, etc. it can cause infinite recursion + @@ -459,7 +442,7 @@ void keep_alive(void) /* reset keep alive timer without sending message */ void kept_alive(void) { - current_time = timeval_ms(); + int64_t current_time = timeval_ms(); int64_t delta_time = current_time - last_time; @@ -472,11 +455,11 @@ void kept_alive(void) /* if we sleep for extended periods of time, we must invoke keep_alive() intermittently */ void alive_sleep(uint64_t ms) { - uint64_t napTime = 10; - for (uint64_t i = 0; i < ms; i += napTime) { + uint64_t nap_time = 10; + for (uint64_t i = 0; i < ms; i += nap_time) { uint64_t sleep_a_bit = ms - i; - if (sleep_a_bit > napTime) - sleep_a_bit = napTime; + if (sleep_a_bit > nap_time) + sleep_a_bit = nap_time; usleep(sleep_a_bit * 1000); keep_alive(); @@ -517,3 +500,16 @@ void log_socket_error(const char *socket_desc) LOG_ERROR("Error on socket '%s': errno==%d, message: %s.", socket_desc, error_code, strerror(error_code)); #endif } + +/** + * Find the first non-printable character in the char buffer, return a pointer to it. + * If no such character exists, return NULL. + */ +char *find_nonprint_char(char *buf, unsigned buf_len) +{ + for (unsigned int i = 0; i < buf_len; i++) { + if (!isprint(buf[i])) + return buf + i; + } + return NULL; +} diff --git a/src/helper/log.h b/src/helper/log.h index 0c6623f01e..818716a9df 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 @@ -72,7 +61,7 @@ __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))); * Initialize logging module. Call during program startup. */ void log_init(void); -int set_log_output(struct command_context *cmd_ctx, FILE *output); +void log_exit(void); int log_register_commands(struct command_context *cmd_ctx); @@ -100,6 +89,8 @@ char *alloc_vprintf(const char *fmt, va_list ap); char *alloc_printf(const char *fmt, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 2))); +char *find_nonprint_char(char *buf, unsigned buf_len); + extern int debug_level; /* Avoid fn call and building parameter list if we're not outputting the information. @@ -123,6 +114,15 @@ extern int debug_level; expr); \ } while (0) +#define LOG_CUSTOM_LEVEL(level, expr ...) \ + do { \ + enum log_levels _level = level; \ + if (debug_level >= _level) \ + log_printf_lf(_level, \ + __FILE__, __LINE__, __func__, \ + expr); \ + } while (0) + #define LOG_INFO(expr ...) \ log_printf_lf(LOG_LVL_INFO, __FILE__, __LINE__, __func__, expr) @@ -141,6 +141,23 @@ extern int debug_level; #define LOG_OUTPUT(expr ...) \ log_printf(LOG_LVL_OUTPUT, __FILE__, __LINE__, __func__, expr) +/* Output a log entry that is related to a given target */ + +#define LOG_TARGET_DEBUG_IO(target, fmt_str, ...) \ + LOG_DEBUG_IO("[%s] " fmt_str, target_name(target), ##__VA_ARGS__) + +#define LOG_TARGET_DEBUG(target, fmt_str, ...) \ + LOG_DEBUG("[%s] " fmt_str, target_name(target), ##__VA_ARGS__) + +#define LOG_TARGET_INFO(target, fmt_str, ...) \ + LOG_INFO("[%s] " fmt_str, target_name(target), ##__VA_ARGS__) + +#define LOG_TARGET_WARNING(target, fmt_str, ...) \ + LOG_WARNING("[%s] " fmt_str, target_name(target), ##__VA_ARGS__) + +#define LOG_TARGET_ERROR(target, fmt_str, ...) \ + LOG_ERROR("[%s] " fmt_str, target_name(target), ##__VA_ARGS__) + /* general failures * error codes < 100 */ @@ -154,6 +171,7 @@ extern int debug_level; #define ERROR_WAIT (-5) /* ERROR_TIMEOUT is already taken by winerror.h. */ #define ERROR_TIMEOUT_REACHED (-6) +#define ERROR_NOT_IMPLEMENTED (-7) #endif /* OPENOCD_HELPER_LOG_H */ 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 6622ece6ca..61a1014697 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 @@ -31,6 +20,7 @@ #include <limits.h> #include <stdlib.h> +#include <string.h> #if IS_DARWIN #include <libproc.h> #endif @@ -49,13 +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'}, - {"pipe", no_argument, 0, 'p'}, - {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) @@ -75,7 +64,7 @@ static char *find_exe_path(void) do { #if IS_WIN32 && !IS_CYGWIN exepath = malloc(MAX_PATH); - if (exepath == NULL) + if (!exepath) break; GetModuleFileName(NULL, exepath, MAX_PATH); @@ -87,7 +76,7 @@ static char *find_exe_path(void) #elif IS_DARWIN exepath = malloc(PROC_PIDPATHINFO_MAXSIZE); - if (exepath == NULL) + if (!exepath) break; if (proc_pidpath(getpid(), exepath, PROC_PIDPATHINFO_MAXSIZE) <= 0) { free(exepath); @@ -99,7 +88,7 @@ static char *find_exe_path(void) #define PATH_MAX 1024 #endif char *path = malloc(PATH_MAX); - if (path == NULL) + if (!path) break; int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; size_t size = PATH_MAX; @@ -117,14 +106,14 @@ static char *find_exe_path(void) #elif defined(HAVE_REALPATH) /* Assume POSIX.1-2008 */ /* Try Unices in order of likelihood. */ exepath = realpath("/proc/self/exe", NULL); /* Linux/Cygwin */ - if (exepath == NULL) + if (!exepath) exepath = realpath("/proc/self/path/a.out", NULL); /* Solaris */ - if (exepath == NULL) + if (!exepath) exepath = realpath("/proc/curproc/file", NULL); /* FreeBSD (Should be covered above) */ #endif } while (0); - if (exepath != NULL) { + if (exepath) { /* Strip executable file name, leaving path */ *strrchr(exepath, '/') = '\0'; } else { @@ -163,7 +152,7 @@ static char *find_relative_path(const char *from, const char *to) if (from[0] != '/') i++; char *next = strchr(from, '/'); - if (next == NULL) + if (!next) break; from = next + 1; } @@ -178,6 +167,63 @@ static char *find_relative_path(const char *from, const char *to) return relpath; } +static void add_user_dirs(void) +{ + char *path; + +#if IS_WIN32 + const char *appdata = getenv("APPDATA"); + + if (appdata) { + path = alloc_printf("%s/OpenOCD", appdata); + if (path) { + /* Convert path separators to UNIX style, should work on Windows also. */ + for (char *p = path; *p; p++) { + if (*p == '\\') + *p = '/'; + } + add_script_search_dir(path); + free(path); + } + } + /* WIN32 may also have HOME defined, particularly under Cygwin, so add those paths below too */ +#endif + + const char *home = getenv("HOME"); +#if IS_DARWIN + if (home) { + path = alloc_printf("%s/Library/Preferences/org.openocd", home); + if (path) { + add_script_search_dir(path); + free(path); + } + } +#endif + const char *xdg_config = getenv("XDG_CONFIG_HOME"); + + if (xdg_config) { + path = alloc_printf("%s/openocd", xdg_config); + if (path) { + add_script_search_dir(path); + free(path); + } + } else if (home) { + path = alloc_printf("%s/.config/openocd", home); + if (path) { + add_script_search_dir(path); + free(path); + } + } + + if (home) { + path = alloc_printf("%s/.openocd", home); + if (path) { + add_script_search_dir(path); + free(path); + } + } +} + static void add_default_dirs(void) { char *path; @@ -194,32 +240,11 @@ static void add_default_dirs(void) * listed last in the built-in search order, so the user can * override these scripts with site-specific customizations. */ - const char *home = getenv("HOME"); - - if (home) { - path = alloc_printf("%s/.openocd", home); - if (path) { - add_script_search_dir(path); - free(path); - } - } - path = getenv("OPENOCD_SCRIPTS"); - if (path) add_script_search_dir(path); -#ifdef _WIN32 - const char *appdata = getenv("APPDATA"); - - if (appdata) { - path = alloc_printf("%s/OpenOCD", appdata); - if (path) { - add_script_search_dir(path); - free(path); - } - } -#endif + add_user_dirs(); path = alloc_printf("%s/%s/%s", exepath, bin2data, "site"); if (path) { @@ -245,7 +270,7 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) /* getopt_long stores the option index here. */ int option_index = 0; - c = getopt_long(argc, argv, "hvd::l:f:s:c:p", long_options, &option_index); + c = getopt_long(argc, argv, "hvd::l:f:s:c:", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) @@ -285,13 +310,6 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) if (optarg) add_config_command(optarg); break; - case 'p': - /* to replicate the old syntax this needs to be synchronous - * otherwise the gdb stdin will overflow with the warning message */ - command_run_line(cmd_ctx, "gdb_port pipe; log_output openocd.log"); - LOG_WARNING("deprecated option: -p/--pipe. Use '-c \"gdb_port pipe; " - "log_output openocd.log\"' instead."); - break; default: /* '?' */ /* getopt will emit an error message, all we have to do is bail. */ return ERROR_FAIL; @@ -323,6 +341,10 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) exit(0); } + /* dump full command line */ + for (int i = 0; i < argc; i++) + LOG_DEBUG("ARGV[%d] = \"%s\"", i, argv[i]); + /* paths specified on the command line take precedence over these * built-in paths */ diff --git a/src/helper/replacements.c b/src/helper/replacements.c index b4bb94f06e..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 * @@ -33,7 +30,7 @@ void *clear_malloc(size_t size) { void *t = malloc(size); - if (t != NULL) + if (t) memset(t, 0x00, size); return t; } @@ -41,7 +38,7 @@ void *clear_malloc(size_t size) void *fill_malloc(size_t size) { void *t = malloc(size); - if (t != NULL) { + if (t) { /* We want to initialize memory to some known bad state. * 0 and 0xff yields 0 and -1 as integers, which often * have meaningful values. 0x5555... is not often a valid @@ -52,16 +49,13 @@ 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 #ifdef _WIN32 #include <io.h> +#include <winsock2.h> #endif /* replacements for gettimeofday */ @@ -123,7 +117,7 @@ char *strndup(const char *s, size_t n) size_t len = strnlen(s, n); char *new = malloc(len + 1); - if (new == NULL) + if (!new) return NULL; new[len] = '\0'; @@ -144,10 +138,10 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time struct timeval tvslice; int retcode; -#define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set)) +#define SAFE_FD_ISSET(fd, set) (set && FD_ISSET(fd, set)) /* calculate how long we need to wait in milliseconds */ - if (tv == NULL) + if (!tv) ms_total = INFINITE; else { ms_total = tv->tv_sec * 1000; @@ -232,16 +226,16 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time if (retcode < 0) retcode = 0; for (i = 0; i < n_handles; i++) { - if (WAIT_OBJECT_0 == WaitForSingleObject(handles[i], 0)) { + if (WaitForSingleObject(handles[i], 0) == WAIT_OBJECT_0) { if (SAFE_FD_ISSET(handle_slot_to_fd[i], rfds)) { - DWORD dwBytes; + DWORD bytes; intptr_t handle = (intptr_t) _get_osfhandle( handle_slot_to_fd[i]); if (PeekNamedPipe((HANDLE)handle, NULL, 0, - NULL, &dwBytes, NULL)) { + NULL, &bytes, NULL)) { /* check to see if gdb pipe has data available */ - if (dwBytes) { + if (bytes) { FD_SET(handle_slot_to_fd[i], &aread); retcode++; } @@ -274,45 +268,3 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time return retcode; } #endif - -#if defined HAVE_LIBUSB1 && !defined HAVE_LIBUSB_ERROR_NAME -#include <libusb.h> -/* Verbatim from git://git.libusb.org/libusb.git tag 1.0.9 - * The libusb_error enum is compatible down to v0.9.1 - */ -const char *libusb_error_name(int error_code) -{ - enum libusb_error error = error_code; - switch (error) { - case LIBUSB_SUCCESS: - return "LIBUSB_SUCCESS"; - case LIBUSB_ERROR_IO: - return "LIBUSB_ERROR_IO"; - case LIBUSB_ERROR_INVALID_PARAM: - return "LIBUSB_ERROR_INVALID_PARAM"; - case LIBUSB_ERROR_ACCESS: - return "LIBUSB_ERROR_ACCESS"; - case LIBUSB_ERROR_NO_DEVICE: - return "LIBUSB_ERROR_NO_DEVICE"; - case LIBUSB_ERROR_NOT_FOUND: - return "LIBUSB_ERROR_NOT_FOUND"; - case LIBUSB_ERROR_BUSY: - return "LIBUSB_ERROR_BUSY"; - case LIBUSB_ERROR_TIMEOUT: - return "LIBUSB_ERROR_TIMEOUT"; - case LIBUSB_ERROR_OVERFLOW: - return "LIBUSB_ERROR_OVERFLOW"; - case LIBUSB_ERROR_PIPE: - return "LIBUSB_ERROR_PIPE"; - case LIBUSB_ERROR_INTERRUPTED: - return "LIBUSB_ERROR_INTERRUPTED"; - case LIBUSB_ERROR_NO_MEM: - return "LIBUSB_ERROR_NO_MEM"; - case LIBUSB_ERROR_NOT_SUPPORTED: - return "LIBUSB_ERROR_NOT_SUPPORTED"; - case LIBUSB_ERROR_OTHER: - return "LIBUSB_ERROR_OTHER"; - } - return "**UNKNOWN**"; -} -#endif diff --git a/src/helper/replacements.h b/src/helper/replacements.h index ac5009549a..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,25 +9,13 @@ * * * 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 #define OPENOCD_HELPER_REPLACEMENTS_H #include <stdint.h> +#include <helper/system.h> /* MIN,MAX macros */ #ifndef MIN @@ -76,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: * @@ -110,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 @@ -241,13 +230,13 @@ static inline int socket_select(int max_fd, typedef uint32_t Elf32_Addr; typedef uint16_t Elf32_Half; typedef uint32_t Elf32_Off; -typedef int32_t Elf32_Sword; typedef uint32_t Elf32_Word; typedef uint32_t Elf32_Size; -typedef Elf32_Off Elf32_Hashelt; + +#define EI_NIDENT 16 typedef struct { - unsigned char e_ident[16]; /* Magic number and other info */ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf32_Half e_type; /* Object file type */ Elf32_Half e_machine; /* Architecture */ Elf32_Word e_version; /* Object file version */ @@ -289,8 +278,42 @@ typedef struct { #endif /* HAVE_ELF_H */ -#if defined HAVE_LIBUSB1 && !defined HAVE_LIBUSB_ERROR_NAME -const char *libusb_error_name(int error_code); -#endif /* defined HAVE_LIBUSB1 && !defined HAVE_LIBUSB_ERROR_NAME */ +#ifndef HAVE_ELF64 + +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +typedef struct { + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +#endif /* HAVE_ELF64 */ #endif /* OPENOCD_HELPER_REPLACEMENTS_H */ 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 97b3443bed..bd96d626ab 100644 --- a/src/helper/system.h +++ b/src/helper/system.h @@ -1,26 +1,24 @@ +/* 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 #define OPENOCD_HELPER_SYSTEM_H +/* +++ platform specific headers +++ */ +#ifdef _WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#include <sys/types.h> +#include <sys/stat.h> +#endif +/* --- platform specific headers --- */ + /* standard C library header files */ #include <stdio.h> #include <stdlib.h> @@ -28,28 +26,11 @@ #include <assert.h> #include <ctype.h> #include <errno.h> +#include <time.h> -/* +++ AC_HEADER_TIME +++ */ -#ifdef TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> #endif -/* --- AC_HEADER_TIME --- */ - -/* +++ platform specific headers +++ */ -#ifdef _WIN32 -#include <winsock2.h> -#include <ws2tcpip.h> -#include <sys/types.h> -#include <sys/stat.h> -#endif -/* --- platform specific headers --- */ #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> diff --git a/src/helper/time_support.c b/src/helper/time_support.c index 05eaf0a9d0..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 @@ -86,7 +75,7 @@ int duration_measure(struct duration *duration) { struct timeval end; int retval = gettimeofday(&end, NULL); - if (0 == retval) + if (retval == 0) timeval_subtract(&duration->elapsed, &end, &duration->start); return retval; } diff --git a/src/helper/time_support.h b/src/helper/time_support.h index 7abbdb24d2..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,33 +9,16 @@ * * * 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 #define OPENOCD_HELPER_TIME_SUPPORT_H -#ifdef TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif +#include <time.h> +#include "types.h" + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> #endif int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y); @@ -50,7 +35,7 @@ struct duration { /** Update the duration->start field to start the @a duration measurement. */ int duration_start(struct duration *duration); -/** Update the duration->elapsed field to finish the @a duration measurment. */ +/** Update the duration->elapsed field to finish the @a duration measurement. */ int duration_measure(struct duration *duration); /** @returns Elapsed time in seconds. */ 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 f3d5e04a35..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 @@ -47,16 +36,10 @@ #ifndef __cplusplus #define false 0 -#define true 1 +#define true 1 -typedef int _Bool; -#else -typedef bool _Bool; #endif /* __cplusplus */ #endif /* HAVE__BOOL */ - -#define bool _Bool - #endif /* HAVE_STDBOOL_H */ /// turns a macro argument into a string constant @@ -168,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); @@ -180,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); @@ -192,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 dcd59e6eac..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 util_Jim_Command_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 = util_Jim_Command_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 b82914bcbf..7ce4adc295 100644 --- a/src/jtag/Makefile.am +++ b/src/jtag/Makefile.am @@ -1,73 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libjtag.la -JTAG_SRCS = %D%/commands.c %C%_libjtag_la_LIBADD = -BUILT_SOURCES += %D%/minidriver_imp.h -CLEANFILES += %D%/minidriver_imp.h - -if MINIDRIVER - -if ZY1000 -JTAG_SRCS += %D%/zy1000/zy1000.c -JTAG_MINIDRIVER_DIR = %D%/zy1000 -endif -if MINIDRIVER_DUMMY -JTAG_SRCS += %D%/minidummy/minidummy.c -JTAG_MINIDRIVER_DIR = %D%/minidummy -endif - -MINIDRIVER_IMP_DIR = %D%/minidriver - -%D%/jtag_minidriver.h: $(JTAG_MINIDRIVER_DIR)/jtag_minidriver.h - cp $< $@ - -BUILT_SOURCES += %D%/jtag_minidriver.h - -CLEANFILES += %D%/jtag_minidriver.h - -else - -MINIDRIVER_IMP_DIR = %D%/drivers - if HLADAPTER 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 -endif -# endif // MINIDRIVER - -%D%/minidriver_imp.h: $(MINIDRIVER_IMP_DIR)/minidriver_imp.h - cp $< $@ - - %C%_libjtag_la_SOURCES = \ %D%/adapter.c \ + %D%/adapter.h \ + %D%/commands.c \ %D%/core.c \ %D%/interface.c \ %D%/interfaces.c \ %D%/tcl.c \ %D%/swim.c \ %D%/commands.h \ - %D%/driver.h \ %D%/interface.h \ %D%/interfaces.h \ %D%/minidriver.h \ %D%/jtag.h \ - %D%/minidriver/minidriver_imp.h \ - %D%/minidummy/jtag_minidriver.h \ %D%/swd.h \ %D%/swim.h \ - %D%/tcl.h \ - $(JTAG_SRCS) + %D%/tcl.h STARTUP_TCL_SRCS += %D%/startup.tcl diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index af75917a32..bbf1cb3d2e 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -1,45 +1,22 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * Copyright (C) 2007-2010 Øyvind Harboe * - * oyvind.harboe@zylin.com * - * * - * Copyright (C) 2009 SoftPLC Corporation * - * http://softplc.com * - * dick@softplc.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/>. * - ***************************************************************************/ +// 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> + * Copyright (C) 2009 SoftPLC Corporation, http://softplc.com, Dick Hollenbeck <dick@softplc.com> + * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> + * Copyright (C) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> + */ #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include "adapter.h" #include "jtag.h" #include "minidriver.h" #include "interface.h" #include "interfaces.h" #include <transport/transport.h> -#include <jtag/drivers/jtag_usb_common.h> - -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif /** * @file @@ -49,21 +26,367 @@ struct adapter_driver *adapter_driver; const char * const jtag_only[] = { "jtag", NULL }; -static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +enum adapter_clk_mode { + CLOCK_MODE_UNSELECTED = 0, + CLOCK_MODE_KHZ, + CLOCK_MODE_RCLK +}; + +#define DEFAULT_CLOCK_SPEED_KHZ 100U + +/** + * Adapter configuration + */ +static struct { + bool adapter_initialized; + char *usb_location; + char *serial; + 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. + */ +int adapter_init(struct command_context *cmd_ctx) +{ + if (is_adapter_initialized()) + return ERROR_OK; + + if (!adapter_driver) { + /* nothing was previously specified by "adapter driver" command */ + LOG_ERROR("Debug Adapter has to be specified, " + "see \"adapter driver\" command"); + 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("Note: The adapter \"%s\" doesn't support configurable speed", adapter_driver->name); + return ERROR_OK; + } + + int requested_khz = adapter_get_speed_khz(); + int actual_khz = requested_khz; + int speed_var = 0; + retval = adapter_get_speed(&speed_var); + if (retval != ERROR_OK) + return retval; + retval = adapter_driver->speed(speed_var); + if (retval != ERROR_OK) + return retval; + retval = adapter_get_speed_readable(&actual_khz); + if (retval != ERROR_OK) + LOG_INFO("adapter-specific clock speed value %d", speed_var); + else if (actual_khz) { + /* Adaptive clocking -- JTAG-specific */ + if ((adapter_config.clock_mode == CLOCK_MODE_RCLK) + || ((adapter_config.clock_mode == CLOCK_MODE_KHZ) && !requested_khz)) { + LOG_INFO("RCLK (adaptive clock speed) not supported - fallback to %d kHz" + , actual_khz); + } else + LOG_INFO("clock speed %d kHz", actual_khz); + } else + LOG_INFO("RCLK (adaptive clock speed)"); + + return ERROR_OK; +} + +int adapter_quit(void) +{ + if (is_adapter_initialized() && adapter_driver->quit) { + /* close the JTAG interface */ + int result = adapter_driver->quit(); + if (result != ERROR_OK) + LOG_ERROR("failed: %d", result); + } + + free(adapter_config.serial); + free(adapter_config.usb_location); + + struct jtag_tap *t = jtag_all_taps(); + while (t) { + struct jtag_tap *n = t->next_tap; + jtag_tap_free(t); + t = n; + } + + return ERROR_OK; +} + +unsigned int adapter_get_speed_khz(void) +{ + return adapter_config.speed_khz; +} + +static int adapter_khz_to_speed(unsigned int khz, int *speed) +{ + LOG_DEBUG("convert khz to adapter specific speed value"); + adapter_config.speed_khz = khz; + if (!is_adapter_initialized()) + return ERROR_OK; + LOG_DEBUG("have adapter set up"); + if (!adapter_driver->khz) { + LOG_ERROR("Translation from khz to adapter speed not implemented"); + return ERROR_FAIL; + } + int speed_div1; + int retval = adapter_driver->khz(adapter_get_speed_khz(), &speed_div1); + if (retval != ERROR_OK) + return retval; + *speed = speed_div1; + return ERROR_OK; +} + +static int adapter_rclk_to_speed(unsigned int fallback_speed_khz, int *speed) +{ + int retval = adapter_khz_to_speed(0, speed); + if ((retval != ERROR_OK) && fallback_speed_khz) { + LOG_DEBUG("trying fallback speed..."); + retval = adapter_khz_to_speed(fallback_speed_khz, speed); + } + return retval; +} + +static int adapter_set_speed(int speed) +{ + /* this command can be called during CONFIG, + * in which case adapter isn't initialized */ + return is_adapter_initialized() ? adapter_driver->speed(speed) : ERROR_OK; +} + +int adapter_config_khz(unsigned int khz) +{ + LOG_DEBUG("handle adapter khz"); + adapter_config.clock_mode = CLOCK_MODE_KHZ; + int speed = 0; + int retval = adapter_khz_to_speed(khz, &speed); + return (retval != ERROR_OK) ? retval : adapter_set_speed(speed); +} + +int adapter_config_rclk(unsigned int fallback_speed_khz) +{ + LOG_DEBUG("handle adapter rclk"); + adapter_config.clock_mode = CLOCK_MODE_RCLK; + adapter_config.rclk_fallback_speed_khz = fallback_speed_khz; + int speed = 0; + int retval = adapter_rclk_to_speed(fallback_speed_khz, &speed); + return (retval != ERROR_OK) ? retval : adapter_set_speed(speed); +} + +int adapter_get_speed(int *speed) +{ + switch (adapter_config.clock_mode) { + case CLOCK_MODE_KHZ: + adapter_khz_to_speed(adapter_get_speed_khz(), speed); + break; + case CLOCK_MODE_RCLK: + adapter_rclk_to_speed(adapter_config.rclk_fallback_speed_khz, speed); + break; + default: + LOG_ERROR("BUG: unknown adapter clock mode"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +int adapter_get_speed_readable(int *khz) +{ + int speed_var = 0; + int retval = adapter_get_speed(&speed_var); + if (retval != ERROR_OK) + return retval; + if (!is_adapter_initialized()) + return ERROR_OK; + if (!adapter_driver->speed_div) { + LOG_ERROR("Translation from adapter speed to khz not implemented"); + return ERROR_FAIL; + } + return adapter_driver->speed_div(speed_var, khz); +} + +const char *adapter_get_required_serial(void) +{ + return adapter_config.serial; +} + +/* + * 1 char: bus + * 2 * 7 chars: max 7 ports + * 1 char: test for overflow + * ------ + * 16 chars + */ +#define USB_MAX_LOCATION_LENGTH 16 + +#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS +static void adapter_usb_set_location(const char *location) +{ + if (strnlen(location, USB_MAX_LOCATION_LENGTH) == USB_MAX_LOCATION_LENGTH) + LOG_WARNING("usb location string is too long!!"); + + free(adapter_config.usb_location); + + adapter_config.usb_location = strndup(location, USB_MAX_LOCATION_LENGTH); +} +#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ + +const char *adapter_usb_get_location(void) +{ + return adapter_config.usb_location; +} + +bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len) { - Jim_GetOptInfo goi; - Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1); + size_t path_step, string_length; + char *ptr, *loc; + bool equal = false; + if (!adapter_usb_get_location()) + return equal; + + /* strtok need non const char */ + loc = strndup(adapter_usb_get_location(), USB_MAX_LOCATION_LENGTH); + string_length = strnlen(loc, USB_MAX_LOCATION_LENGTH); + + ptr = strtok(loc, "-"); + if (!ptr) { + LOG_WARNING("no '-' in usb path\n"); + goto done; + } + + string_length -= strnlen(ptr, string_length); + /* check bus mismatch */ + if (atoi(ptr) != dev_bus) + goto done; + + path_step = 0; + while (path_step < path_len) { + ptr = strtok(NULL, "."); + + /* no more tokens in path */ + if (!ptr) + break; + + /* path mismatch at some step */ + if (path_step < path_len && atoi(ptr) != port_path[path_step]) + break; + + path_step++; + string_length -= strnlen(ptr, string_length) + 1; + }; + + /* walked the full path, all elements match */ + if (path_step == path_len && !string_length) + equal = true; + +done: + free(loc); + return equal; +} + +COMMAND_HANDLER(handle_adapter_name) +{ /* 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 ? : "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) @@ -91,7 +414,7 @@ COMMAND_HANDLER(handle_adapter_list_command) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "The following debug adapters are available:"); - for (unsigned i = 0; NULL != adapter_drivers[i]; i++) { + for (unsigned i = 0; adapter_drivers[i]; i++) { const char *name = adapter_drivers[i]->name; command_print(CMD, "%u: %s", i + 1, name); } @@ -113,14 +436,13 @@ COMMAND_HANDLER(handle_adapter_driver_command) if (CMD_ARGC != 1 || CMD_ARGV[0][0] == '\0') return ERROR_COMMAND_SYNTAX_ERROR; - for (unsigned i = 0; NULL != adapter_drivers[i]; i++) { + for (unsigned i = 0; adapter_drivers[i]; i++) { if (strcmp(CMD_ARGV[0], adapter_drivers[i]->name) != 0) continue; - if (NULL != adapter_drivers[i]->commands) { - retval = register_commands(CMD_CTX, NULL, - adapter_drivers[i]->commands); - if (ERROR_OK != retval) + if (adapter_drivers[i]->commands) { + retval = register_commands(CMD_CTX, NULL, adapter_drivers[i]->commands); + if (retval != ERROR_OK) return retval; } @@ -277,6 +599,8 @@ next: 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(); @@ -393,14 +717,14 @@ COMMAND_HANDLER(handle_adapter_speed_command) unsigned khz = 0; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], khz); - retval = jtag_config_khz(khz); - if (ERROR_OK != retval) + retval = adapter_config_khz(khz); + if (retval != ERROR_OK) return retval; } - int cur_speed = jtag_get_speed_khz(); - retval = jtag_get_speed_readable(&cur_speed); - if (ERROR_OK != retval) + int cur_speed = adapter_get_speed_khz(); + retval = adapter_get_speed_readable(&cur_speed); + if (retval != ERROR_OK) return retval; if (cur_speed) @@ -411,6 +735,16 @@ COMMAND_HANDLER(handle_adapter_speed_command) return retval; } +COMMAND_HANDLER(handle_adapter_serial_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(adapter_config.serial); + adapter_config.serial = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + COMMAND_HANDLER(handle_adapter_reset_de_assert) { enum values { @@ -497,14 +831,226 @@ COMMAND_HANDLER(handle_adapter_reset_de_assert) (srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT); } -#ifndef HAVE_JTAG_MINIDRIVER_H +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) { if (CMD_ARGC == 1) - jtag_usb_set_location(CMD_ARGV[0]); + adapter_usb_set_location(CMD_ARGV[0]); - command_print(CMD, "adapter usb location: %s", jtag_usb_get_location()); + command_print(CMD, "adapter usb location: %s", adapter_usb_get_location()); return ERROR_OK; } @@ -522,7 +1068,6 @@ static const struct command_registration adapter_usb_command_handlers[] = { #endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ COMMAND_REGISTRATION_DONE }; -#endif /* MINIDRIVER */ static const struct command_registration adapter_srst_command_handlers[] = { { @@ -560,6 +1105,13 @@ static const struct command_registration adapter_command_handlers[] = { "With or without argument, display current setting.", .usage = "[khz]", }, + { + .name = "serial", + .handler = handle_adapter_serial_command, + .mode = COMMAND_CONFIG, + .help = "Set the serial number of the adapter", + .usage = "serial_string", + }, { .name = "list", .handler = handle_adapter_list_command, @@ -570,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", @@ -586,9 +1139,8 @@ static const struct command_registration adapter_command_handlers[] = { .handler = adapter_transports_command, .mode = COMMAND_CONFIG, .help = "Declare transports the adapter supports.", - .usage = "transport ... ", + .usage = "transport ...", }, -#ifndef HAVE_JTAG_MINIDRIVER_H { .name = "usb", .mode = COMMAND_ANY, @@ -596,7 +1148,6 @@ static const struct command_registration adapter_command_handlers[] = { .usage = "", .chain = adapter_usb_command_handlers, }, -#endif /* MINIDRIVER */ { .name = "assert", .handler = handle_adapter_reset_de_assert, @@ -611,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 }; @@ -643,7 +1207,18 @@ static const struct command_registration interface_command_handlers[] = { * @todo Remove internal assumptions that all debug adapters use JTAG for * transport. Various types and data structures are not named generically. */ -int interface_register_commands(struct command_context *ctx) +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 new file mode 100644 index 0000000000..23ffe2cc51 --- /dev/null +++ b/src/jtag/adapter.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> + * Copyright (c) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> + */ + +#ifndef OPENOCD_JTAG_ADAPTER_H +#define OPENOCD_JTAG_ADAPTER_H + +#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; + +/** Register the adapter's commands */ +int adapter_register_commands(struct command_context *ctx); + +/** Initialize debug adapter upon startup. */ +int adapter_init(struct command_context *cmd_ctx); + +/** Shutdown the debug adapter upon program exit. */ +int adapter_quit(void); + +/** @returns true if adapter has been initialized */ +bool is_adapter_initialized(void); + +/** @returns USB location string set with command 'adapter usb location' */ +const char *adapter_usb_get_location(void); + +/** @returns true if USB location string is "<dev_bus>-<port_path[0]>[.<port_path[1]>[...]]" */ +bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len); + +/** @returns The current adapter speed setting. */ +int adapter_get_speed(int *speed); + +/** + * Given a @a speed setting, use the interface @c speed_div callback to + * adjust the setting. + * @param speed The speed setting to convert back to readable kHz. + * @returns ERROR_OK if the interface has not been initialized or on success; + * otherwise, the error code produced by the @c speed_div callback. + */ +int adapter_get_speed_readable(int *speed); + +/** Attempt to configure the adapter for the specified kHz. */ +int adapter_config_khz(unsigned int khz); + +/** + * Attempt to enable RTCK/RCLK. If that fails, fallback to the + * specified frequency. + */ +int adapter_config_rclk(unsigned int fallback_speed_khz); + +/** Retrieves the clock speed of the adapter in kHz. */ +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 97e38258a1..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) $(LIBUSB0_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 160eb1105a..0000000000 --- a/src/jtag/aice/aice_interface.c +++ /dev/null @@ -1,536 +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/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 (ERROR_OK != aice_port->api->open(¶m)) { - 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 (8 <= i) - *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", param.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_serial_command) -{ - LOG_DEBUG("aice_handle_aice_serial_command"); - - if (CMD_ARGC == 1) - param.serial = strdup(CMD_ARGV[0]); - else - LOG_ERROR("expected exactly one argument to aice serial <serial-number>"); - - 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 = "[desciption string]", - }, - { - .name = "serial", - .handler = &aice_handle_aice_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the serial number of the AICE device", - .usage = "[serial 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 220b0b04d4..0000000000 --- a/src/jtag/aice/aice_interface.h +++ /dev/null @@ -1,36 +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 - -struct aice_interface_param_s { - /** */ - const char *device_desc; - /** */ - const char *serial; - /** */ - uint16_t vid; - /** */ - uint16_t pid; -}; - -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 bdc8c090a5..0000000000 --- a/src/jtag/aice/aice_pipe.c +++ /dev/null @@ -1,893 +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 - -#ifdef _WIN32 -#include <windows.h> -#else -#include <signal.h> -#endif - -#include <helper/log.h> -#include <helper/time_support.h> -#include "aice_port.h" -#include "aice_pipe.h" - -#define AICE_PIPE_MAXLINE 8192 - -#ifdef _WIN32 -PROCESS_INFORMATION proc_info; - -HANDLE aice_pipe_output[2]; -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 - -int aice_pipe_output[2]; -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 d3d6a1a2c9..0000000000 --- a/src/jtag/aice/aice_port.h +++ /dev/null @@ -1,237 +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; - /** */ - const char *serial; - /** */ - 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 ea710ad25d..0000000000 --- a/src/jtag/aice/aice_transport.c +++ /dev/null @@ -1,445 +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> - -/* */ -static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi, - struct jtag_tap *pTap) -{ - 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) * pTap->expected_ids_cnt; - uint32_t *new_expected_ids = malloc(expected_len + sizeof(uint32_t)); - if (new_expected_ids == NULL) { - Jim_SetResultFormatted(goi->interp, "no memory"); - return JIM_ERR; - } - - assert(pTap->expected_ids); - memcpy(new_expected_ids, pTap->expected_ids, expected_len); - - new_expected_ids[pTap->expected_ids_cnt] = w; - - free(pTap->expected_ids); - pTap->expected_ids = new_expected_ids; - pTap->expected_ids_cnt++; - - return JIM_OK; -} - -#define NTAP_OPT_EXPECTED_ID 0 - -/* */ -static int jim_aice_newtap_cmd(Jim_GetOptInfo *goi) -{ - struct jtag_tap *pTap; - int x; - int e; - Jim_Nvp *n; - char *cp; - const Jim_Nvp opts[] = { - {.name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID}, - {.name = NULL, .value = -1}, - }; - - pTap = calloc(1, sizeof(struct jtag_tap)); - if (!pTap) { - 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(pTap); - return JIM_ERR; - } - - const char *tmp; - Jim_GetOpt_String(goi, &tmp, NULL); - pTap->chip = strdup(tmp); - - Jim_GetOpt_String(goi, &tmp, NULL); - pTap->tapname = strdup(tmp); - - /* name + dot + name + null */ - x = strlen(pTap->chip) + 1 + strlen(pTap->tapname) + 1; - cp = malloc(x); - sprintf(cp, "%s.%s", pTap->chip, pTap->tapname); - pTap->dotted_name = cp; - - LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params", - pTap->chip, pTap->tapname, pTap->dotted_name, goi->argc); - - while (goi->argc) { - e = Jim_GetOpt_Nvp(goi, opts, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(goi, opts, 0); - free(cp); - free(pTap); - return e; - } - LOG_DEBUG("Processing option: %s", n->name); - switch (n->value) { - case NTAP_OPT_EXPECTED_ID: - e = jim_newtap_expected_id(n, goi, pTap); - if (JIM_OK != e) { - free(cp); - free(pTap); - return e; - } - break; - } /* switch (n->value) */ - } /* while (goi->argc) */ - - /* default is enabled-after-reset */ - pTap->enabled = !pTap->disabled_after_reset; - - jtag_tap_init(pTap); - return JIM_OK; -} - -/* */ -static int jim_aice_newtap(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - Jim_GetOptInfo 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; - Jim_GetOptInfo 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 *eObj = Jim_NewIntObj(goi.interp, e); - Jim_SetResultFormatted(goi.interp, "error: %#s", eObj); - Jim_FreeNewObj(goi.interp, eObj); - return JIM_ERR; - } - return JIM_OK; -} - -static int jim_aice_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - Jim_GetOptInfo 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 7144632df9..0000000000 --- a/src/jtag/aice/aice_usb.c +++ /dev/null @@ -1,4110 +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/drivers/libusb_helper.h> -#include <helper/log.h> -#include <helper/time_support.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 */ -static const uint8_t AICE_CMD_SCAN_CHAIN = 0x00; -static const uint8_t AICE_CMD_T_READ_MISC = 0x20; -static const uint8_t AICE_CMD_T_READ_EDMSR = 0x21; -static const uint8_t AICE_CMD_T_READ_DTR = 0x22; -static const uint8_t AICE_CMD_T_READ_MEM_B = 0x24; -static const uint8_t AICE_CMD_T_READ_MEM_H = 0x25; -static const uint8_t AICE_CMD_T_READ_MEM = 0x26; -static const uint8_t AICE_CMD_T_FASTREAD_MEM = 0x27; -static const uint8_t AICE_CMD_T_WRITE_MISC = 0x28; -static const uint8_t AICE_CMD_T_WRITE_EDMSR = 0x29; -static const uint8_t AICE_CMD_T_WRITE_DTR = 0x2A; -static const uint8_t AICE_CMD_T_WRITE_DIM = 0x2B; -static const uint8_t AICE_CMD_T_WRITE_MEM_B = 0x2C; -static const uint8_t AICE_CMD_T_WRITE_MEM_H = 0x2D; -static const uint8_t AICE_CMD_T_WRITE_MEM = 0x2E; -static const uint8_t AICE_CMD_T_FASTWRITE_MEM = 0x2F; -static const uint8_t AICE_CMD_T_EXECUTE = 0x3E; -static const uint8_t AICE_CMD_READ_CTRL = 0x50; -static const uint8_t AICE_CMD_WRITE_CTRL = 0x51; -static const uint8_t AICE_CMD_BATCH_BUFFER_READ = 0x60; -static const uint8_t AICE_CMD_READ_DTR_TO_BUFFER = 0x61; -static const uint8_t AICE_CMD_BATCH_BUFFER_WRITE = 0x68; -static const uint8_t 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)(libusb_device_handle *, int, char *, int, int, int *), - 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 (ERROR_OK == ret) - count += result; - else if ((ERROR_TIMEOUT_REACHED != ret) || !--tries) - return ret; - } - - *transferred = count; - return ERROR_OK; -} - -static int wrap_usb_bulk_write(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(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_PACK == aice_command_mode) { - 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_BATCH == aice_command_mode) { - 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_PACK == aice_command_mode) { - max_packet_size = AICE_OUT_PACK_COMMAND_SIZE; - } else if (AICE_COMMAND_MODE_BATCH == aice_command_mode) { - 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_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) - 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 (AICE_FORMAT_DTHA != result) { - 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%" PRIx8 ", 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_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) - 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 (AICE_FORMAT_DTHA != result) { - 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%" PRIx32 ", response=0x%" PRIx8 ")", - (uint32_t)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_PACK == aice_command_mode) { - aice_usb_packet_flush(); - } else if (AICE_COMMAND_MODE_BATCH == aice_command_mode) { - 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 (AICE_FORMAT_DTHB != result) { - 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%" PRIx8 ", response=0x%" PRIx8 ")", - AICE_CMD_WRITE_CTRL, cmd_ack_code); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -int aice_read_dtr(uint8_t target_id, uint32_t *data) -{ - int retry_times = 0; - - if ((AICE_COMMAND_MODE_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) - 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 (AICE_FORMAT_DTHMA != result) { - 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%" PRIx8 ", 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; -} - -int aice_read_dtr_to_buffer(uint8_t target_id, uint32_t buffer_idx) -{ - int retry_times = 0; - - if (AICE_COMMAND_MODE_PACK == aice_command_mode) { - aice_usb_packet_flush(); - } else if (AICE_COMMAND_MODE_BATCH == aice_command_mode) { - 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 ", 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; -} - -int aice_write_dtr(uint8_t target_id, uint32_t data) -{ - int retry_times = 0; - - if (AICE_COMMAND_MODE_PACK == aice_command_mode) { - aice_usb_packet_flush(); - } else if (AICE_COMMAND_MODE_BATCH == aice_command_mode) { - 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 ", 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; -} - -int aice_write_dtr_from_buffer(uint8_t target_id, uint32_t buffer_idx) -{ - int retry_times = 0; - - if (AICE_COMMAND_MODE_PACK == aice_command_mode) { - aice_usb_packet_flush(); - } else if (AICE_COMMAND_MODE_BATCH == aice_command_mode) { - 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 ", 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; -} - -int aice_read_misc(uint8_t target_id, uint32_t address, uint32_t *data) -{ - int retry_times = 0; - - if ((AICE_COMMAND_MODE_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) - 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 (AICE_FORMAT_DTHMA != result) { - 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%" PRIx8 ", 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; -} - -int aice_write_misc(uint8_t target_id, uint32_t address, uint32_t data) -{ - int retry_times = 0; - - if (AICE_COMMAND_MODE_PACK == aice_command_mode) { - aice_usb_packet_flush(); - } else if (AICE_COMMAND_MODE_BATCH == aice_command_mode) { - 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 ", 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; -} - -int aice_read_edmsr(uint8_t target_id, uint32_t address, uint32_t *data) -{ - int retry_times = 0; - - if ((AICE_COMMAND_MODE_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) - 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 (AICE_FORMAT_DTHMA != result) { - 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%" PRIx8 ", 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; -} - -int aice_write_edmsr(uint8_t target_id, uint32_t address, uint32_t data) -{ - int retry_times = 0; - - if (AICE_COMMAND_MODE_PACK == aice_command_mode) { - aice_usb_packet_flush(); - } else if (AICE_COMMAND_MODE_BATCH == aice_command_mode) { - 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 ", 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_PACK == aice_command_mode) { - aice_usb_packet_flush(); - } else if (AICE_COMMAND_MODE_BATCH == aice_command_mode) { - 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 - ", 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_PACK == aice_command_mode) { - aice_usb_packet_flush(); - } else if (AICE_COMMAND_MODE_BATCH == aice_command_mode) { - 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 ", 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; -} - -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_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) { - 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 ", 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; -} - -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_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) { - 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 ", 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; -} - -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_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) { - 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 ", 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; -} - -int aice_fastread_mem(uint8_t target_id, uint8_t *word, uint32_t num_of_words) -{ - int retry_times = 0; - - if ((AICE_COMMAND_MODE_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) - 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%" PRIx8 ", 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; -} - -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_PACK == aice_command_mode) { - aice_usb_packet_flush(); - } else if (AICE_COMMAND_MODE_BATCH == aice_command_mode) { - 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 ", 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; -} - -int aice_read_mem_b(uint8_t target_id, uint32_t address, uint32_t *data) -{ - int retry_times = 0; - - if ((AICE_COMMAND_MODE_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) - 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 (AICE_FORMAT_DTHMA != result) { - 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%" PRIx8 ", 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; -} - -int aice_read_mem_h(uint8_t target_id, uint32_t address, uint32_t *data) -{ - int retry_times = 0; - - if ((AICE_COMMAND_MODE_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) - 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 (AICE_FORMAT_DTHMA != result) { - 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%" PRIx8 ", 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; -} - -int aice_read_mem(uint8_t target_id, uint32_t address, uint32_t *data) -{ - int retry_times = 0; - - if ((AICE_COMMAND_MODE_PACK == aice_command_mode) || - (AICE_COMMAND_MODE_BATCH == aice_command_mode)) - 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 (AICE_FORMAT_DTHMA != result) { - 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%" PRIx8 ", 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; -} - -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%" PRIx8 ", 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 (AICE_FORMAT_DTHMB != result) { - 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%" PRIx8 ", 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); - -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 (ERROR_OK != check_suppressed_exception(coreid, value_dbger)) - return ERROR_FAIL; - if (ERROR_OK != check_privilege(coreid, value_dbger)) - 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_GPR == nds32_reg_type(num)) { /* general registers */ - instructions[0] = MTSR_DTR(num); - instructions[1] = DSB; - instructions[2] = NOP; - instructions[3] = BEQ_MINUS_12; - } else if (NDS32_REG_TYPE_SPR == nds32_reg_type(num)) { /* 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_AUMR == nds32_reg_type(num)) { /* audio registers */ - if ((CB_CTL <= num) && (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_FPU == nds32_reg_type(num)) { /* fpu registers */ - if (FPCSR == num) { - instructions[0] = FMFCSR; - instructions[1] = MTSR_DTR(0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else if (FPCFG == num) { - instructions[0] = FMFCFG; - instructions[1] = MTSR_DTR(0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else { - if (FS0 <= num && 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 (FD0 <= num && 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 (ERROR_OK != aice_read_reg(coreid, num, val)) - *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_GPR == nds32_reg_type(num)) { /* general registers */ - instructions[0] = MFSR_DTR(num); - instructions[1] = DSB; - instructions[2] = NOP; - instructions[3] = BEQ_MINUS_12; - } else if (NDS32_REG_TYPE_SPR == nds32_reg_type(num)) { /* 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_AUMR == nds32_reg_type(num)) { /* audio registers */ - if ((CB_CTL <= num) && (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_FPU == nds32_reg_type(num)) { /* fpu registers */ - if (FPCSR == num) { - instructions[0] = MFSR_DTR(0); - instructions[1] = FMTCSR; - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else if (FPCFG == num) { - /* FPCFG is readonly */ - } else { - if (FS0 <= num && 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 (FD0 <= num && 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, NULL, &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, NULL, &devh, NULL)) != ERROR_OK) { - usleep(1000); - timeout--; - if (!timeout) - break; - } - if (ERROR_OK != retval) - 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 (ERROR_OK != aice_read_reg(coreid, num, &value)) - 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 == NULL) { - return ERROR_FAIL; - } else { - while (fgets(line_buffer, LINE_BUFFER_SIZE, script_fd) != NULL) { - /* execute operations */ - set_op = false; - op_str = strstr(line_buffer, "set"); - if (op_str != NULL) { - set_op = true; - goto get_reset_type; - } - - op_str = strstr(line_buffer, "clear"); - if (op_str == NULL) - continue; -get_reset_type: - reset_str = strstr(op_str, "srst"); - if (reset_str != NULL) { - 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 != NULL) { - 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 != NULL) { - 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 (ERROR_OK != aice_usb_open(param)) - return ERROR_FAIL; - - if (ERROR_FAIL == aice_get_version_info()) { - LOG_ERROR("Cannot get AICE version!"); - return ERROR_FAIL; - } - - LOG_INFO("AICE initialization started"); - - /* attempt to reset Andes EDM */ - if (ERROR_FAIL == aice_reset_box()) { - 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 (ERROR_OK != aice_usb_set_clock(a_clock)) { - 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 (ERROR_OK == retval) { - 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' bahavior */ - /* !!!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 (ERROR_AICE_TIMEOUT == result) { - 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 (ERROR_AICE_DISCONNECT == result) { - 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 (AICE_TARGET_RUNNING == core_info[coreid].core_state) { - /* 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 (AICE_TARGET_UNKNOWN == core_info[coreid].core_state) { - /* 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 ((AICE_SRST != srst) && (AICE_RESET_HOLD != srst)) - 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 (AICE_SRST == srst) - result = aice_issue_srst(coreid); - else { - if (1 == total_num_of_core) - 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 (ERROR_FAIL == aice_usb_run(coreid)) - 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 (AICE_TARGET_HALTED == state) - 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 (NDS_MEMORY_ACC_CPU == core_info[coreid].access_channel) - 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 (NDS_MEMORY_ACC_BUS == core_info[coreid].access_channel) - 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 (NDS_MEMORY_ACC_BUS == core_info[coreid].access_channel) - 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 (NDS_MEMORY_ACC_BUS == core_info[coreid].access_channel) - 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 (NDS_MEMORY_ACC_CPU == core_info[coreid].access_channel) - aice_usb_set_address_dim(coreid, addr); - - size_t i; - write_mem_func_t write_mem_func; - - switch (size) { - case 1: - if (NDS_MEMORY_ACC_BUS == core_info[coreid].access_channel) - 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 (NDS_MEMORY_ACC_BUS == core_info[coreid].access_channel) - 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 (NDS_MEMORY_ACC_BUS == core_info[coreid].access_channel) - 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 (NDS_MEMORY_ACC_CPU == core_info[coreid].access_channel) - aice_usb_set_address_dim(coreid, addr); - - if (NDS_MEMORY_ACC_CPU == core_info[coreid].access_channel) - 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 (NDS_MEMORY_ACC_CPU == core_info[coreid].access_channel) - aice_usb_set_address_dim(coreid, addr); - - if (NDS_MEMORY_ACC_CPU == core_info[coreid].access_channel) - 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 (AICE_TARGET_HALTED == core_info[coreid].core_state) { - if (NDS_EDM_SR_EDMSW == addr) { - *val = core_info[coreid].edmsw_backup; - } else if (NDS_EDM_SR_EDM_DTR == addr) { - 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 (AICE_TARGET_HALTED == core_info[coreid].core_state) { - if (NDS_EDM_SR_EDM_DTR == addr) { - 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 (NDS_MEMORY_SELECT_AUTO != core_info[coreid].memory_select) - 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 (0 == access_page_size) { /* 4K page */ - virtual_offset = virtual_address & 0x00000FFF; - physical_page_number = value_mr3 & 0xFFFFF000; - } else if (1 == access_page_size) { /* 8K page */ - virtual_offset = virtual_address & 0x00001FFF; - physical_page_number = value_mr3 & 0xFFFFE000; - } else if (5 == access_page_size) { /* 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 (ERROR_OK != aice_write_dtr(coreid, cache_index)) - return ERROR_FAIL; - - if (ERROR_OK != aice_execute_dim(coreid, instructions, 4)) - 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 (ERROR_OK != aice_write_dtr(coreid, cache_index)) - return ERROR_FAIL; - - if (ERROR_OK != aice_execute_dim(coreid, instructions, 4)) - 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 (ERROR_OK != aice_write_dtr(coreid, cache_index)) - return ERROR_FAIL; - - if (ERROR_OK != aice_execute_dim(coreid, instructions, 4)) - 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 == NULL) - 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 != NULL) { - 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 != NULL) { - 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 != NULL); - - 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 (AICE_COMMAND_MODE_BATCH == command_mode) { - /* 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_GPR == nds32_reg_type(reg_no)) { - /* 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_SPR == nds32_reg_type(reg_no)) { - /* 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 cafb05b5be..a60684c880 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) @@ -66,8 +55,8 @@ void jtag_queue_command(struct jtag_command *cmd) cmd->next = NULL; struct jtag_command **last_cmd = next_command_pointer; - assert(NULL != last_cmd); - assert(NULL == *last_cmd); + assert(last_cmd); + assert(!*last_cmd); *last_cmd = cmd; /* store location where the next command pointer will be stored */ @@ -114,7 +103,7 @@ void *cmd_queue_alloc(size_t size) if (*p_page) { p_page = &cmd_queue_pages_tail; - if (CMD_QUEUE_PAGE_SIZE - (*p_page)->used < size) + if (CMD_QUEUE_PAGE_SIZE < (*p_page)->used + size) p_page = &((*p_page)->next); } @@ -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 03a26bec21..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,30 +13,19 @@ * * * 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" #endif +#include "adapter.h" #include "jtag.h" #include "swd.h" #include "interface.h" #include <transport/transport.h> #include <helper/jep106.h> +#include "helper/system.h" #ifdef HAVE_STRINGS_H #include <strings.h> @@ -44,6 +35,9 @@ #include "svf/svf.h" #include "xsvf/xsvf.h" +/* ipdbg are utilities to debug IP-cores. It uses JTAG for transport. */ +#include "server/ipdbg.h" + /** The number of JTAG queue flushes (for profiling and debugging purposes). */ static int jtag_flush_queue_count; @@ -119,16 +113,6 @@ struct jtag_event_callback { /* callbacks to inform high-level handlers about JTAG state changes */ static struct jtag_event_callback *jtag_event_callbacks; -/* speed in kHz*/ -static int speed_khz; -/* speed to fallback to when RCLK is requested but not supported */ -static int rclk_fallback_speed_khz; -static enum {CLOCK_MODE_UNSELECTED, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK} clock_mode; -static int jtag_speed; - -/* FIXME: change name to this variable, it is not anymore JTAG only */ -static struct adapter_driver *jtag; - extern struct adapter_driver *adapter_driver; void jtag_set_flush_queue_sleep(int ms) @@ -152,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; @@ -178,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) @@ -209,12 +210,12 @@ unsigned jtag_tap_count_enabled(void) } /** Append a new TAP to the chain of all taps. */ -void jtag_tap_add(struct jtag_tap *t) +static void jtag_tap_add(struct jtag_tap *t) { unsigned jtag_num_taps = 0; struct jtag_tap **tap = &__jtag_all_taps; - while (*tap != NULL) { + while (*tap) { jtag_num_taps++; tap = &(*tap)->next_tap; } @@ -239,7 +240,7 @@ struct jtag_tap *jtag_tap_by_string(const char *s) struct jtag_tap *t = jtag_all_taps(); while (t) { - if (0 == strcmp(t->dotted_name, s)) + if (strcmp(t->dotted_name, s) == 0) return t; t = t->next_tap; } @@ -274,7 +275,7 @@ struct jtag_tap *jtag_tap_next_enabled(struct jtag_tap *p) const char *jtag_tap_name(const struct jtag_tap *tap) { - return (tap == NULL) ? "(unknown)" : tap->dotted_name; + return (!tap) ? "(unknown)" : tap->dotted_name; } @@ -282,7 +283,7 @@ int jtag_register_event_callback(jtag_event_handler_t callback, void *priv) { struct jtag_event_callback **callbacks_p = &jtag_event_callbacks; - if (callback == NULL) + if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; if (*callbacks_p) { @@ -303,7 +304,7 @@ int jtag_unregister_event_callback(jtag_event_handler_t callback, void *priv) { struct jtag_event_callback **p = &jtag_event_callbacks, *temp; - if (callback == NULL) + if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; while (*p) { @@ -391,7 +392,7 @@ void jtag_add_ir_scan(struct jtag_tap *active, struct scan_field *in_fields, tap void jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { - assert(out_bits != NULL); + assert(out_bits); assert(state != TAP_RESET); jtag_prelude(state); @@ -425,8 +426,7 @@ static void jtag_add_scan_check(struct jtag_tap *active, void (*jtag_add_scan)( jtag_add_scan(active, in_num_fields, in_fields, state); for (int i = 0; i < in_num_fields; i++) { - if ((in_fields[i].check_value != NULL) && (in_fields[i].in_value != NULL)) { - /* this is synchronous for a minidriver */ + if ((in_fields[i].check_value) && (in_fields[i].in_value)) { jtag_add_callback4(jtag_check_value_mask_callback, (jtag_callback_data_t)in_fields[i].in_value, (jtag_callback_data_t)in_fields[i].check_value, @@ -465,7 +465,7 @@ void jtag_add_dr_scan(struct jtag_tap *active, void jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { - assert(out_bits != NULL); + assert(out_bits); assert(state != TAP_RESET); jtag_prelude(state); @@ -487,7 +487,7 @@ void jtag_add_tlr(void) /** * If supported by the underlying adapter, this clocks a raw bit sequence - * onto TMS for switching betwen JTAG and SWD modes. + * onto TMS for switching between JTAG and SWD modes. * * DO NOT use this to bypass the integrity checks and logging provided * by the jtag_add_pathmove() and jtag_add_statemove() calls. @@ -503,7 +503,7 @@ int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state) { int retval; - if (!(jtag->jtag_ops->supported & DEBUG_CAP_TMS_SEQ)) + if (!(adapter_driver->jtag_ops->supported & DEBUG_CAP_TMS_SEQ)) return ERROR_JTAG_NOT_IMPLEMENTED; jtag_checks(); @@ -625,7 +625,7 @@ static int adapter_system_reset(int req_srst) /* Maybe change SRST signal state */ if (jtag_srst != req_srst) { - retval = jtag->reset(0, req_srst); + retval = adapter_driver->reset(0, req_srst); if (retval != ERROR_OK) { LOG_ERROR("SRST error"); return ERROR_FAIL; @@ -762,7 +762,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst) int new_srst = 0; int new_trst = 0; - if (!jtag->reset) { + if (!adapter_driver->reset) { legacy_jtag_add_reset(req_tlr_or_trst, req_srst); return; } @@ -811,7 +811,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst) /* guarantee jtag queue empty before changing reset status */ jtag_execute_queue(); - retval = jtag->reset(new_trst, new_srst); + retval = adapter_driver->reset(new_trst, new_srst); if (retval != ERROR_OK) { jtag_set_error(retval); LOG_ERROR("TRST/SRST error"); @@ -916,9 +916,9 @@ static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask) { - assert(field->in_value != NULL); + assert(field->in_value); - if (value == NULL) { + if (!value) { /* no checking to do */ return; } @@ -931,7 +931,7 @@ void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *ma int default_interface_jtag_execute_queue(void) { - if (NULL == jtag) { + if (!is_adapter_initialized()) { LOG_ERROR("No JTAG interface configured yet. " "Issue 'init' command in startup scripts " "before communicating with targets."); @@ -947,19 +947,13 @@ int default_interface_jtag_execute_queue(void) * The fix can be applied immediately after next release (v0.11.0 ?) */ LOG_ERROR("JTAG API jtag_execute_queue() called on non JTAG interface"); - if (!jtag->jtag_ops || !jtag->jtag_ops->execute_queue) + if (!adapter_driver->jtag_ops || !adapter_driver->jtag_ops->execute_queue) return ERROR_OK; } - int result = jtag->jtag_ops->execute_queue(); + struct jtag_command *cmd = jtag_command_queue_get(); + int result = adapter_driver->jtag_ops->execute_queue(cmd); -#if !BUILD_ZY1000 - /* Only build this if we use a regular driver with a command queue. - * Otherwise jtag_command_queue won't be found at compile/link time. Its - * definition is in jtag/commands.c, which is only built/linked by - * jtag/Makefile.am if MINIDRIVER_DUMMY || !MINIDRIVER, but those variables - * aren't accessible here. */ - struct jtag_command *cmd = jtag_command_queue; while (debug_level >= LOG_LVL_DEBUG_IO && cmd) { switch (cmd->type) { case JTAG_SCAN: @@ -1017,7 +1011,6 @@ int default_interface_jtag_execute_queue(void) } cmd = cmd->next; } -#endif return result; } @@ -1056,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; @@ -1076,8 +1069,6 @@ void jtag_sleep(uint32_t us) #define JTAG_MAX_AUTO_TAPS 20 -#define EXTRACT_JEP106_BANK(X) (((X) & 0xf00) >> 8) -#define EXTRACT_JEP106_ID(X) (((X) & 0xfe) >> 1) #define EXTRACT_MFG(X) (((X) & 0xffe) >> 1) #define EXTRACT_PART(X) (((X) & 0xffff000) >> 12) #define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28) @@ -1145,7 +1136,7 @@ static void jtag_examine_chain_display(enum log_levels level, const char *msg, name, msg, (unsigned int)idcode, (unsigned int)EXTRACT_MFG(idcode), - jep106_manufacturer(EXTRACT_JEP106_BANK(idcode), EXTRACT_JEP106_ID(idcode)), + jep106_manufacturer(EXTRACT_MFG(idcode)), (unsigned int)EXTRACT_PART(idcode), (unsigned int)EXTRACT_VER(idcode)); } @@ -1186,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 */ @@ -1201,7 +1192,7 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap) return true; /* treat "-expected-id 0" as a "don't-warn" wildcard */ - if (0 == tap->expected_ids[ii]) + if (tap->expected_ids[ii] == 0) return true; } @@ -1234,7 +1225,7 @@ static int jtag_examine_chain(void) max_taps++; uint8_t *idcode_buffer = calloc(4, max_taps); - if (idcode_buffer == NULL) + if (!idcode_buffer) return ERROR_JTAG_INIT_FAILED; /* DR scan to collect BYPASS or IDCODE register contents. @@ -1259,7 +1250,7 @@ static int jtag_examine_chain(void) uint32_t idcode = buf_get_u32(idcode_buffer, bit_count, 32); /* No predefined TAP? Auto-probe. */ - if (tap == NULL) { + if (!tap) { /* Is there another TAP? */ if (jtag_idcode_is_final(idcode)) break; @@ -1288,17 +1279,17 @@ static int jtag_examine_chain(void) jtag_tap_init(tap); } - if ((idcode & 1) == 0) { + if ((idcode & 1) == 0 && !tap->ignore_bypass) { /* 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); @@ -1340,26 +1331,25 @@ out: static int jtag_validate_ircapture(void) { struct jtag_tap *tap; - int total_ir_length = 0; uint8_t *ir_test = NULL; struct scan_field field; - uint64_t val; int chain_pos = 0; int retval; - /* when autoprobing, accomodate huge IR lengths */ - for (tap = NULL, total_ir_length = 0; - (tap = jtag_tap_next_enabled(tap)) != NULL; - total_ir_length += tap->ir_length) { + /* when autoprobing, accommodate huge IR lengths */ + int total_ir_length = 0; + for (tap = jtag_tap_next_enabled(NULL); tap; tap = jtag_tap_next_enabled(tap)) { if (tap->ir_length == 0) total_ir_length += JTAG_IRLEN_MAX; + else + total_ir_length += tap->ir_length; } /* increase length to add 2 bit sentinel after scan */ total_ir_length += 2; ir_test = malloc(DIV_ROUND_UP(total_ir_length, 8)); - if (ir_test == NULL) + if (!ir_test) return ERROR_FAIL; /* after this scan, all TAPs will capture BYPASS instructions */ @@ -1381,7 +1371,7 @@ static int jtag_validate_ircapture(void) for (;; ) { tap = jtag_tap_next_enabled(tap); - if (tap == NULL) + if (!tap) break; /* If we're autoprobing, guess IR lengths. They must be at @@ -1402,7 +1392,7 @@ static int jtag_validate_ircapture(void) */ if (tap->ir_length == 0) { tap->ir_length = 2; - while ((val = buf_get_u64(ir_test, chain_pos, tap->ir_length + 1)) == 1 + while (buf_get_u64(ir_test, chain_pos, tap->ir_length + 1) == 1 && tap->ir_length < JTAG_IRLEN_MAX) { tap->ir_length++; } @@ -1418,7 +1408,7 @@ static int jtag_validate_ircapture(void) * this part of the JTAG spec, so their capture mask/value * attributes might disable this test. */ - val = buf_get_u64(ir_test, chain_pos, tap->ir_length); + uint64_t val = buf_get_u64(ir_test, chain_pos, tap->ir_length); if ((val & tap->ir_capture_mask) != tap->ir_capture_value) { LOG_ERROR("%s: IR capture error; saw 0x%0*" PRIx64 " not 0x%0*" PRIx32, jtag_tap_name(tap), @@ -1434,7 +1424,7 @@ static int jtag_validate_ircapture(void) } /* verify the '11' sentinel we wrote is returned at the end */ - val = buf_get_u64(ir_test, chain_pos, 2); + uint64_t val = buf_get_u64(ir_test, chain_pos, 2); if (val != 0x3) { char *cbuf = buf_to_hex_str(ir_test, total_ir_length); @@ -1459,7 +1449,7 @@ void jtag_tap_init(struct jtag_tap *tap) unsigned ir_len_bytes; /* if we're autoprobing, cope with potentially huge ir_length */ - ir_len_bits = tap->ir_length ? : JTAG_IRLEN_MAX; + ir_len_bits = tap->ir_length ? tap->ir_length : JTAG_IRLEN_MAX; ir_len_bytes = DIV_ROUND_UP(ir_len_bits, 8); tap->expected = calloc(1, ir_len_bytes); @@ -1474,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 */ @@ -1510,65 +1500,6 @@ void jtag_tap_free(struct jtag_tap *tap) free(tap); } -/** - * Do low-level setup like initializing registers, output signals, - * and clocking. - */ -int adapter_init(struct command_context *cmd_ctx) -{ - if (jtag) - return ERROR_OK; - - if (!adapter_driver) { - /* nothing was previously specified by "adapter driver" command */ - LOG_ERROR("Debug Adapter has to be specified, " - "see \"adapter driver\" command"); - return ERROR_JTAG_INVALID_INTERFACE; - } - - int retval; - retval = adapter_driver->init(); - if (retval != ERROR_OK) - return retval; - jtag = adapter_driver; - - if (jtag->speed == NULL) { - LOG_INFO("This adapter doesn't support configurable speed"); - return ERROR_OK; - } - - if (CLOCK_MODE_UNSELECTED == clock_mode) { - 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 = jtag_get_speed_khz(); - int actual_khz = requested_khz; - int jtag_speed_var = 0; - retval = jtag_get_speed(&jtag_speed_var); - if (retval != ERROR_OK) - return retval; - retval = jtag->speed(jtag_speed_var); - if (retval != ERROR_OK) - return retval; - retval = jtag_get_speed_readable(&actual_khz); - if (ERROR_OK != retval) - LOG_INFO("adapter-specific clock speed value %d", jtag_speed_var); - else if (actual_khz) { - /* Adaptive clocking -- JTAG-specific */ - if ((CLOCK_MODE_RCLK == clock_mode) - || ((CLOCK_MODE_KHZ == clock_mode) && !requested_khz)) { - LOG_INFO("RCLK (adaptive clock speed) not supported - fallback to %d kHz" - , actual_khz); - } else - LOG_INFO("clock speed %d kHz", actual_khz); - } else - LOG_INFO("RCLK (adaptive clock speed)"); - - return ERROR_OK; -} - int jtag_init_inner(struct command_context *cmd_ctx) { struct jtag_tap *tap; @@ -1578,7 +1509,7 @@ int jtag_init_inner(struct command_context *cmd_ctx) LOG_DEBUG("Init JTAG chain"); tap = jtag_tap_next_enabled(NULL); - if (tap == NULL) { + if (!tap) { /* Once JTAG itself is properly set up, and the scan chain * isn't absurdly large, IDCODE autoprobe should work fine. * @@ -1649,25 +1580,6 @@ int jtag_init_inner(struct command_context *cmd_ctx) return ERROR_OK; } -int adapter_quit(void) -{ - if (jtag && jtag->quit) { - /* close the JTAG interface */ - int result = jtag->quit(); - if (ERROR_OK != result) - LOG_ERROR("failed: %d", result); - } - - struct jtag_tap *t = jtag_all_taps(); - while (t) { - struct jtag_tap *n = t->next_tap; - jtag_tap_free(t); - t = n; - } - - return ERROR_OK; -} - int swd_init_reset(struct command_context *cmd_ctx) { int retval, retval1; @@ -1775,98 +1687,6 @@ int jtag_init(struct command_context *cmd_ctx) return ERROR_OK; } -unsigned jtag_get_speed_khz(void) -{ - return speed_khz; -} - -static int adapter_khz_to_speed(unsigned khz, int *speed) -{ - LOG_DEBUG("convert khz to interface specific speed value"); - speed_khz = khz; - if (!jtag) - return ERROR_OK; - LOG_DEBUG("have interface set up"); - if (!jtag->khz) { - LOG_ERROR("Translation from khz to jtag_speed not implemented"); - return ERROR_FAIL; - } - int speed_div1; - int retval = jtag->khz(jtag_get_speed_khz(), &speed_div1); - if (ERROR_OK != retval) - return retval; - *speed = speed_div1; - return ERROR_OK; -} - -static int jtag_rclk_to_speed(unsigned fallback_speed_khz, int *speed) -{ - int retval = adapter_khz_to_speed(0, speed); - if ((ERROR_OK != retval) && fallback_speed_khz) { - LOG_DEBUG("trying fallback speed..."); - retval = adapter_khz_to_speed(fallback_speed_khz, speed); - } - return retval; -} - -static int jtag_set_speed(int speed) -{ - jtag_speed = speed; - /* this command can be called during CONFIG, - * in which case jtag isn't initialized */ - return jtag ? jtag->speed(speed) : ERROR_OK; -} - -int jtag_config_khz(unsigned khz) -{ - LOG_DEBUG("handle jtag khz"); - clock_mode = CLOCK_MODE_KHZ; - int speed = 0; - int retval = adapter_khz_to_speed(khz, &speed); - return (ERROR_OK != retval) ? retval : jtag_set_speed(speed); -} - -int jtag_config_rclk(unsigned fallback_speed_khz) -{ - LOG_DEBUG("handle jtag rclk"); - clock_mode = CLOCK_MODE_RCLK; - rclk_fallback_speed_khz = fallback_speed_khz; - int speed = 0; - int retval = jtag_rclk_to_speed(fallback_speed_khz, &speed); - return (ERROR_OK != retval) ? retval : jtag_set_speed(speed); -} - -int jtag_get_speed(int *speed) -{ - switch (clock_mode) { - case CLOCK_MODE_KHZ: - adapter_khz_to_speed(jtag_get_speed_khz(), speed); - break; - case CLOCK_MODE_RCLK: - jtag_rclk_to_speed(rclk_fallback_speed_khz, speed); - break; - default: - LOG_ERROR("BUG: unknown jtag clock mode"); - return ERROR_FAIL; - } - return ERROR_OK; -} - -int jtag_get_speed_readable(int *khz) -{ - int jtag_speed_var = 0; - int retval = jtag_get_speed(&jtag_speed_var); - if (retval != ERROR_OK) - return retval; - if (!jtag) - return ERROR_OK; - if (!jtag->speed_div) { - LOG_ERROR("Translation from jtag_speed to khz not implemented"); - return ERROR_FAIL; - } - return jtag->speed_div(jtag_speed_var, khz); -} - void jtag_set_verify(bool enable) { jtag_verify = enable; @@ -1889,14 +1709,14 @@ bool jtag_will_verify_capture_ir(void) int jtag_power_dropout(int *dropout) { - if (jtag == NULL) { + if (!is_adapter_initialized()) { /* TODO: as the jtag interface is not valid all * we can do at the moment is exit OpenOCD */ LOG_ERROR("No Valid JTAG Interface Configured."); exit(-1); } - if (jtag->power_dropout) - return jtag->power_dropout(dropout); + if (adapter_driver->power_dropout) + return adapter_driver->power_dropout(dropout); *dropout = 0; /* by default we can't detect power dropout */ return ERROR_OK; @@ -1904,8 +1724,8 @@ int jtag_power_dropout(int *dropout) int jtag_srst_asserted(int *srst_asserted) { - if (jtag->srst_asserted) - return jtag->srst_asserted(srst_asserted); + if (adapter_driver->srst_asserted) + return adapter_driver->srst_asserted(srst_asserted); *srst_asserted = 0; /* by default we can't detect srst asserted */ return ERROR_OK; @@ -1982,7 +1802,12 @@ static int jtag_select(struct command_context *ctx) if (retval != ERROR_OK) return retval; - return xsvf_register_commands(ctx); + retval = xsvf_register_commands(ctx); + + if (retval != ERROR_OK) + return retval; + + return ipdbg_register_commands(ctx); } static struct transport jtag_transport = { @@ -2007,7 +1832,7 @@ bool transport_is_jtag(void) int adapter_resets(int trst, int srst) { - if (get_current_transport() == NULL) { + if (!get_current_transport()) { LOG_ERROR("transport is not selected"); return ERROR_FAIL; } @@ -2064,7 +1889,7 @@ int adapter_assert_reset(void) transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() || transport_is_swim()) return adapter_system_reset(1); - else if (get_current_transport() != NULL) + else if (get_current_transport()) LOG_ERROR("reset is not supported on %s", get_current_transport()->name); else @@ -2081,7 +1906,7 @@ int adapter_deassert_reset(void) transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() || transport_is_swim()) return adapter_system_reset(0); - else if (get_current_transport() != NULL) + else if (get_current_transport()) LOG_ERROR("reset is not supported on %s", get_current_transport()->name); else @@ -2093,8 +1918,8 @@ int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler) { - if (jtag->config_trace) { - return jtag->config_trace(enabled, pin_protocol, port_size, trace_freq, + if (adapter_driver->config_trace) { + return adapter_driver->config_trace(enabled, pin_protocol, port_size, trace_freq, traceclkin_freq, prescaler); } else if (enabled) { LOG_ERROR("The selected interface does not support tracing"); @@ -2106,8 +1931,8 @@ int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, int adapter_poll_trace(uint8_t *buf, size_t *size) { - if (jtag->poll_trace) - return jtag->poll_trace(buf, size); + if (adapter_driver->poll_trace) + return adapter_driver->poll_trace(buf, size); return ERROR_FAIL; } diff --git a/src/jtag/driver.h b/src/jtag/driver.h deleted file mode 100644 index ae00414c4b..0000000000 --- a/src/jtag/driver.h +++ /dev/null @@ -1,26 +0,0 @@ -/*************************************************************************** - * 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_JTAG_DRIVER_H -#define OPENOCD_JTAG_DRIVER_H - -struct command_context; - -int interface_register_commands(struct command_context *ctx); - -#endif /* OPENOCD_JTAG_DRIVER_H */ diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index c860833b31..e404afe9f0 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 \ @@ -19,7 +23,6 @@ DRIVERFILES = # Standard Driver: common files DRIVERFILES += %D%/driver.c -DRIVERFILES += %D%/jtag_usb_common.c if USE_LIBUSB1 DRIVERFILES += %D%/libusb_helper.c @@ -27,12 +30,6 @@ DRIVERFILES += %D%/libusb_helper.c %C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB1_LIBS) endif -if USE_LIBUSB0 -DRIVERFILES += %D%/usb_common.c -%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB0_CFLAGS) -%C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB0_LIBS) -endif - if USE_LIBFTDI %C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBFTDI_CFLAGS) %C%_libocdjtagdrivers_la_LIBADD += $(LIBFTDI_LIBS) @@ -82,6 +79,12 @@ endif if JTAG_VPI DRIVERFILES += %D%/jtag_vpi.c endif +if VDEBUG +DRIVERFILES += %D%/vdebug.c +endif +if JTAG_DPI +DRIVERFILES += %D%/jtag_dpi.c +endif if USB_BLASTER_DRIVER %C%_libocdjtagdrivers_la_LIBADD += %D%/usb_blaster/libocdusbblaster.la include %D%/usb_blaster/Makefile.am @@ -107,6 +110,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 +125,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 +161,9 @@ endif if RSHIM DRIVERFILES += %D%/rshim.c endif +if DMEM +DRIVERFILES += %D%/dmem.c +endif if OSBDM DRIVERFILES += %D%/osbdm.c endif @@ -167,8 +182,15 @@ endif if OPENJTAG DRIVERFILES += %D%/openjtag.c endif -if CMSIS_DAP -DRIVERFILES += %D%/cmsis_dap_usb.c +if CMSIS_DAP_HID +DRIVERFILES += %D%/cmsis_dap_usb_hid.c +DRIVERFILES += %D%/cmsis_dap.c +endif +if CMSIS_DAP_USB +DRIVERFILES += %D%/cmsis_dap_usb_bulk.c +if !CMSIS_DAP_HID +DRIVERFILES += %D%/cmsis_dap.c +endif endif if IMX_GPIO DRIVERFILES += %D%/imx_gpio.c @@ -179,19 +201,22 @@ endif if XDS110 DRIVERFILES += %D%/xds110.c endif +if AM335XGPIO +DRIVERFILES += %D%/am335xgpio.c +endif DRIVERHEADERS = \ %D%/bitbang.h \ %D%/bitq.h \ - %D%/jtag_usb_common.h \ + %D%/libftdi_helper.h \ %D%/libusb_helper.h \ + %D%/cmsis_dap.h \ %D%/minidriver_imp.h \ %D%/mpsse.h \ %D%/rlink.h \ %D%/rlink_dtc_cmd.h \ %D%/rlink_ep1_cmd.h \ %D%/rlink_st7.h \ - %D%/usb_common.h \ %D%/versaloon/usbtoxxx/usbtoxxx.h \ %D%/versaloon/usbtoxxx/usbtoxxx_internal.h \ %D%/versaloon/versaloon.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 ecf98a08c3..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" @@ -48,6 +37,7 @@ uint8_t delay_tms; * Maximum achievable TCK frequency is 182 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts + * @param in_offset */ void jtag_scan_in(uint8_t out_offset, uint8_t in_offset) { @@ -125,6 +115,7 @@ void jtag_scan_in(uint8_t out_offset, uint8_t in_offset) * Maximum achievable TCK frequency is 113 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts + * @param in_offset */ void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset) { @@ -373,6 +364,7 @@ void jtag_slow_scan_out(uint8_t out_offset) * Maximum achievable TCK frequency is 100 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts + * @param in_offset */ void jtag_scan_io(uint8_t out_offset, uint8_t in_offset) { @@ -465,6 +457,7 @@ void jtag_scan_io(uint8_t out_offset, uint8_t in_offset) * Maximum achievable TCK frequency is 78 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts + * @param in_offset */ void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset) { 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 e9ff8dfa1d..b28ce62ffb 100644 --- a/src/jtag/drivers/amt_jtagaccel.c +++ b/src/jtag/drivers/amt_jtagaccel.c @@ -1,25 +1,15 @@ +// 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" #endif +#include <jtag/adapter.h> #include <jtag/interface.h> #if PARPORT_USE_PPDEV == 1 @@ -198,7 +188,7 @@ static void amt_jtagaccel_state_move(void) aw_scan_tms_5 = 0x40 | (tms_scan[0] & 0x1f); AMT_AW(aw_scan_tms_5); int jtag_speed = 0; - int retval = jtag_get_speed(&jtag_speed); + int retval = adapter_get_speed(&jtag_speed); assert(retval == ERROR_OK); if (jtag_speed > 3 || rtck_enabled) amt_wait_scan_busy(); @@ -254,7 +244,7 @@ static void amt_jtagaccel_scan(bool ir_scan, enum scan_type type, uint8_t *buffe uint8_t aw_tms_scan; uint8_t tms_scan[2]; int jtag_speed_var; - int retval = jtag_get_speed(&jtag_speed_var); + int retval = adapter_get_speed(&jtag_speed_var); assert(retval == ERROR_OK); if (ir_scan) @@ -327,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 40d52acb9c..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 @@ -22,8 +11,8 @@ #include <jtag/interface.h> #include <jtag/commands.h> -#include <usb.h> -#include "usb_common.h" +#include "helper/system.h" +#include "libusb_helper.h" #define USB_VID 0x15ba #define USB_PID 0x001e @@ -75,7 +64,7 @@ static void armjtagew_tap_append_scan(int length, uint8_t *buffer, struct scan_c /* ARM-JTAG-EW lowlevel functions */ struct armjtagew { - struct usb_dev_handle *usb_handle; + struct libusb_device_handle *usb_handle; }; static struct armjtagew *armjtagew_usb_open(void); @@ -96,14 +85,14 @@ 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; - while (cmd != NULL) { + while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %i", @@ -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; @@ -684,35 +673,37 @@ static int armjtagew_tap_execute(void) static struct armjtagew *armjtagew_usb_open(void) { - usb_init(); - const uint16_t vids[] = { USB_VID, 0 }; const uint16_t pids[] = { USB_PID, 0 }; - struct usb_dev_handle *dev; - if (jtag_usb_open(vids, pids, &dev) != ERROR_OK) + struct libusb_device_handle *dev; + + if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK) return NULL; struct armjtagew *result = malloc(sizeof(struct armjtagew)); result->usb_handle = dev; #if 0 - /* usb_set_configuration required under win32 */ - usb_set_configuration(dev, dev->config[0].bConfigurationValue); + /* libusb_set_configuration required under win32 */ + struct libusb_config_descriptor *config; + struct libusb_device *usb_dev = libusb_get_device(dev); + libusb_get_config_descriptor(usb_dev, 0, &config); + libusb_set_configuration(dev, config->bConfigurationValue); #endif - usb_claim_interface(dev, 0); + libusb_claim_interface(dev, 0); #if 0 /* * This makes problems under Mac OS X. And is not needed * under Windows. Hopefully this will not break a linux build */ - usb_set_altinterface(dev, 0); + libusb_set_interface_alt_setting(dev, 0, 0); #endif return result; } static void armjtagew_usb_close(struct armjtagew *armjtagew) { - usb_close(armjtagew->usb_handle); + libusb_close(armjtagew->usb_handle); free(armjtagew); } @@ -725,13 +716,13 @@ static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, in if (result == out_length) { result = armjtagew_usb_read(armjtagew, in_length); if (result != in_length) { - LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", + LOG_ERROR("jtag_libusb_bulk_read failed (requested=%d, result=%d)", in_length, result); return -1; } } else { - LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length, result); + LOG_ERROR("jtag_libusb_bulk_write failed (requested=%d, result=%d)", out_length, result); return -1; } return 0; @@ -741,6 +732,7 @@ static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, in static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length) { int result; + int transferred; if (out_length > ARMJTAGEW_OUT_BUFFER_SIZE) { LOG_ERROR("armjtagew_write illegal out_length=%d (max=%d)", @@ -749,29 +741,34 @@ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length) return -1; } - result = usb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT, - (char *)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT); + result = jtag_libusb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT, + (char *)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT, &transferred); LOG_DEBUG_IO("armjtagew_usb_write, out_length = %d, result = %d", out_length, result); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(usb_out_buffer, out_length); #endif - return result; + if (result != ERROR_OK) + return -1; + return transferred; } /* Read data from USB into in_buffer. */ static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length) { - int result = usb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN, - (char *)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT); + int transferred; + int result = jtag_libusb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN, + (char *)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT, &transferred); LOG_DEBUG_IO("armjtagew_usb_read, result = %d", result); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(usb_in_buffer, result); #endif - return result; + if (result != ERROR_OK) + return -1; + return transferred; } #ifdef _DEBUG_USB_COMMS_ @@ -779,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 bccb9bb234..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]); } @@ -209,7 +202,7 @@ static int at91rm9200_init(void) cur_device = devices; - if (at91rm9200_device == NULL || at91rm9200_device[0] == 0) { + if (!at91rm9200_device || at91rm9200_device[0] == 0) { at91rm9200_device = "rea_ecr"; LOG_WARNING("No at91rm9200 device specified, using default 'rea_ecr'"); } diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index 40cb5aa0b6..ff10b0a78c 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -1,297 +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 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; - - GPIO_SET = set; - GPIO_CLR = clear; + if (bcm2835_peri_mem_dev) + return bcm2835_peri_mem_dev; - 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 (is_output) - OUT_GPIO(swdio_gpio); - else - INP_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 { + GPIO_CLR = 1 << gpio_config->gpio_num; + OUT_GPIO(gpio_config->gpio_num); + } + 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); + 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; + } + } + bcm2835_gpio_synchronize(); } -static int bcm2835gpio_khz(int khz, int *jtag_speed) +static void initialize_gpio(enum adapter_gpio_config_index idx) { - if (!khz) { - LOG_DEBUG("RCLK not supported"); - return ERROR_FAIL; + 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)); } - *jtag_speed = speed_coeff/khz - speed_offset; - if (*jtag_speed < 0) - *jtag_speed = 0; - return ERROR_OK; -} -static int bcm2835gpio_speed_div(int speed, int *khz) -{ - *khz = speed_coeff/(speed + speed_offset); - 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 bcm2835gpio_speed(int speed) -{ - jtag_delay = speed; - return ERROR_OK; + /* 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(); } -static int is_gpio_valid(int gpio) +static bb_value_t bcm2835gpio_read(void) { - return gpio >= 0 && gpio <= 53; + 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_HANDLER(bcm2835gpio_handle_jtag_gpionums) +static int bcm2835gpio_write(int tck, int tms, int tdi) { - 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; - } + 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; + + GPIO_SET = set; + GPIO_CLR = clear; + bcm2835_gpio_synchronize(); - command_print(CMD, - "BCM2835 GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d", - tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); + bcm2835_delay(); return ERROR_OK; } -COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tck) +/* 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], tck_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: tck = %d", tck_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_tms) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio); + GPIO_SET = set; + GPIO_CLR = clear; + bcm2835_gpio_synchronize(); + + bcm2835_delay(); - command_print(CMD, "BCM2835 GPIO config: tms = %d", tms_gpio); return ERROR_OK; } -COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdo) +/* 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], tdo_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: tdo = %d", tdo_gpio); return ERROR_OK; } -COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdi) +/* (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], tdi_gpio); - - command_print(CMD, "BCM2835 GPIO config: tdi = %d", tdi_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_jtag_gpionum_srst) +static void bcm2835_swdio_drive(bool is_output) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio); - - command_print(CMD, "BCM2835 GPIO config: srst = %d", srst_gpio); - return ERROR_OK; + 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); + } + bcm2835_gpio_synchronize(); } -COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_trst) +static int bcm2835_swdio_read(void) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio); - - command_print(CMD, "BCM2835 GPIO config: trst = %d", trst_gpio); - return ERROR_OK; + 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_HANDLER(bcm2835gpio_handle_swd_gpionums) +static int bcm2835gpio_khz(int khz, int *jtag_speed) { - 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 (!khz) { + LOG_DEBUG("BCM2835 GPIO: RCLK not supported"); + return ERROR_FAIL; } - - command_print(CMD, - "BCM2835 GPIO nums: swclk = %d, swdio = %d", - swclk_gpio, swdio_gpio); - + *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_swclk) +static int bcm2835gpio_speed_div(int speed, int *khz) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); - - command_print(CMD, "BCM2835 num: swclk = %d", swclk_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_gpionum_swdio) +static int bcm2835gpio_speed(int speed) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio); - - command_print(CMD, "BCM2835 num: swdio = %d", swdio_gpio); + jtag_delay = speed; return ERROR_OK; } @@ -307,156 +310,128 @@ 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_command_handlers[] = { - { - .name = "bcm2835gpio_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 = "bcm2835gpio_tck_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_tck, - .mode = COMMAND_CONFIG, - .help = "gpio number for tck.", - .usage = "[tck]", - }, - { - .name = "bcm2835gpio_tms_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_tms, - .mode = COMMAND_CONFIG, - .help = "gpio number for tms.", - .usage = "[tms]", - }, - { - .name = "bcm2835gpio_tdo_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_tdo, - .mode = COMMAND_CONFIG, - .help = "gpio number for tdo.", - .usage = "[tdo]", - }, - { - .name = "bcm2835gpio_tdi_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_tdi, - .mode = COMMAND_CONFIG, - .help = "gpio number for tdi.", - .usage = "[tdi]", - }, - { - .name = "bcm2835gpio_swd_nums", - .handler = &bcm2835gpio_handle_swd_gpionums, - .mode = COMMAND_CONFIG, - .help = "gpio numbers for swclk, swdio. (in that order)", - .usage = "[swclk swdio]", - }, - { - .name = "bcm2835gpio_swclk_num", - .handler = &bcm2835gpio_handle_swd_gpionum_swclk, - .mode = COMMAND_CONFIG, - .help = "gpio number for swclk.", - .usage = "[swclk]", - }, - { - .name = "bcm2835gpio_swdio_num", - .handler = &bcm2835gpio_handle_swd_gpionum_swdio, - .mode = COMMAND_CONFIG, - .help = "gpio number for swdio.", - .usage = "[swdio]", - }, - { - .name = "bcm2835gpio_srst_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_srst, - .mode = COMMAND_CONFIG, - .help = "gpio number for srst.", - .usage = "[srst]", - }, +static const struct command_registration bcm2835gpio_subcommand_handlers[] = { { - .name = "bcm2835gpio_trst_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_trst, - .mode = COMMAND_CONFIG, - .help = "gpio number for trst.", - .usage = "[trst]", - }, - { - .name = "bcm2835gpio_speed_coeffs", + .name = "speed_coeffs", .handler = &bcm2835gpio_handle_speed_coeffs, .mode = COMMAND_CONFIG, .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.", .usage = "[SPEED_COEFF SPEED_OFFSET]", }, { - .name = "bcm2835gpio_peripheral_base", + .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]", }, 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 const struct command_registration bcm2835gpio_command_handlers[] = { + { + .name = "bcm2835gpio", + .mode = COMMAND_ANY, + .help = "perform bcm2835gpio management", + .chain = bcm2835gpio_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE }; 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; @@ -467,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; } @@ -486,64 +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); - /* - * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST - * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. + 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 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()) { - swclk_gpio_mode = MODE_GPIO(swclk_gpio); - swdio_gpio_mode = MODE_GPIO(swdio_gpio); - - GPIO_CLR = 1<<swdio_gpio | 1<<swclk_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); + } - 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; } @@ -551,21 +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 (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 df1d601b8e..3d839e65de 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,10 +15,16 @@ #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> +#include <helper/time_support.h> + +/* Timeout for retrying on SWD WAIT in msec */ +#define SWD_WAIT_TIMEOUT 500 + /** * Function bitbang_stableclocks * issues a number of clock cycles while staying in a stable state. @@ -289,9 +284,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) +{ + 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 = 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; @@ -362,7 +366,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 +397,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,21 +427,35 @@ 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: LOG_DEBUG("JTAG-to-SWD"); bitbang_swd_exchange(false, (uint8_t *)swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len); break; + case JTAG_TO_DORMANT: + LOG_DEBUG("JTAG-to-DORMANT"); + bitbang_swd_exchange(false, (uint8_t *)swd_seq_jtag_to_dormant, 0, swd_seq_jtag_to_dormant_len); + break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); bitbang_swd_exchange(false, (uint8_t *)swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len); break; + case SWD_TO_DORMANT: + LOG_DEBUG("SWD-to-DORMANT"); + bitbang_swd_exchange(false, (uint8_t *)swd_seq_swd_to_dormant, 0, swd_seq_swd_to_dormant_len); + break; + case DORMANT_TO_SWD: + LOG_DEBUG("DORMANT-to-SWD"); + bitbang_swd_exchange(false, (uint8_t *)swd_seq_dormant_to_swd, 0, swd_seq_dormant_to_swd_len); + break; + case DORMANT_TO_JTAG: + LOG_DEBUG("DORMANT-to-JTAG"); + bitbang_swd_exchange(false, (uint8_t *)swd_seq_dormant_to_jtag, 0, swd_seq_dormant_to_jtag_len); + break; default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; @@ -454,18 +472,18 @@ 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); + assert(cmd & SWD_CMD_RNW); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skip bitbang_swd_read_reg because queued_retval=%d", queued_retval); return; } - for (;;) { + int64_t timeout = timeval_ms() + SWD_WAIT_TIMEOUT; + for (unsigned int retry = 0;; retry++) { uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)]; - cmd |= SWD_CMD_START | (1 << 7); + cmd |= SWD_CMD_START | SWD_CMD_PARK; bitbang_swd_exchange(false, &cmd, 0, 8); bitbang_interface->swdio_drive(false); @@ -476,103 +494,123 @@ 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 %s 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_RnW ? "read" : "write", - (cmd & SWD_CMD_A32) >> 1, - data); - - switch (ack) { - case SWD_ACK_OK: - if (parity != parity_u32(data)) { - LOG_DEBUG("Wrong parity detected"); - queued_retval = ERROR_FAIL; - return; - } - if (value) - *value = data; - if (cmd & SWD_CMD_APnDP) - bitbang_swd_exchange(true, NULL, 0, ap_delay_clk); - return; - case SWD_ACK_WAIT: - LOG_DEBUG("SWD_ACK_WAIT"); + LOG_CUSTOM_LEVEL((ack != SWD_ACK_OK && (retry == 0 || ack != SWD_ACK_WAIT)) + ? LOG_LVL_DEBUG : LOG_LVL_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, + data); + + if (ack == SWD_ACK_WAIT && timeval_ms() <= timeout) { swd_clear_sticky_errors(); - break; - case SWD_ACK_FAULT: - LOG_DEBUG("SWD_ACK_FAULT"); - queued_retval = ack; + if (retry > 20) + alive_sleep(1); + + continue; + } + if (retry > 1) + LOG_DEBUG("SWD WAIT: retried %u times", retry); + + if (ack != SWD_ACK_OK) { + queued_retval = swd_ack_to_error_code(ack); return; - default: - LOG_DEBUG("No valid acknowledge: ack=%d", ack); - queued_retval = ack; + } + + if (parity != parity_u32(data)) { + LOG_ERROR("Wrong parity detected"); + queued_retval = ERROR_FAIL; return; } + if (value) + *value = data; + if (cmd & SWD_CMD_APNDP) + bitbang_swd_exchange(true, NULL, 0, ap_delay_clk); + return; } } 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)); + assert(!(cmd & SWD_CMD_RNW)); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skip bitbang_swd_write_reg because queued_retval=%d", queued_retval); return; } - for (;;) { - uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)]; + int64_t timeout = timeval_ms() + SWD_WAIT_TIMEOUT; + + /* 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 (unsigned int retry = 0;; retry++) { 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)); - cmd |= SWD_CMD_START | (1 << 7); + cmd |= SWD_CMD_START | SWD_CMD_PARK; 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 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_RnW ? "read" : "write", - (cmd & SWD_CMD_A32) >> 1, - buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32)); - - switch (ack) { - case SWD_ACK_OK: - if (cmd & SWD_CMD_APnDP) - bitbang_swd_exchange(true, NULL, 0, ap_delay_clk); - return; - case SWD_ACK_WAIT: - LOG_DEBUG("SWD_ACK_WAIT"); + LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK && (retry == 0 || ack != SWD_ACK_WAIT)) + ? LOG_LVL_DEBUG : LOG_LVL_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", + (cmd & SWD_CMD_A32) >> 1, + buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32)); + + if (check_ack && ack == SWD_ACK_WAIT && timeval_ms() <= timeout) { swd_clear_sticky_errors(); - break; - case SWD_ACK_FAULT: - LOG_DEBUG("SWD_ACK_FAULT"); - queued_retval = ack; - return; - default: - LOG_DEBUG("No valid acknowledge: ack=%d", ack); - queued_retval = ack; + if (retry > 20) + alive_sleep(1); + + continue; + } + + if (retry > 1) + LOG_DEBUG("SWD WAIT: retried %u times", retry); + + if (check_ack && ack != SWD_ACK_OK) { + queued_retval = swd_ack_to_error_code(ack); return; } + + if (cmd & SWD_CMD_APNDP) + bitbang_swd_exchange(true, NULL, 0, ap_delay_clk); + return; } } 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 97734a92e5..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 @@ -168,7 +157,7 @@ static void bitq_scan_field(struct scan_field *field, int do_pause) else tdo_req = 0; - if (field->out_value == NULL) { + if (!field->out_value) { /* just send zeros and request data from TDO */ for (bit_cnt = field->num_bits; bit_cnt > 1; bit_cnt--) bitq_io(0, 0, tdo_req); @@ -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 12bb81e393..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); @@ -58,6 +47,8 @@ static void buspirate_stableclocks(int num_cycles); #define CMD_RAW_SPEED 0x60 #define CMD_RAW_MODE 0x80 +#define CMD_TAP_SHIFT_HEADER_LEN 3 + /* raw-wire mode configuration */ #define CMD_RAW_CONFIG_HIZ 0x00 #define CMD_RAW_CONFIG_3V3 0x08 @@ -71,6 +62,9 @@ static void buspirate_stableclocks(int num_cycles); #define B1000000 0010010 #endif +#define SHORT_TIMEOUT 1 /* Must be at least 1. */ +#define NORMAL_TIMEOUT 10 + enum { MODE_HIZ = 0, MODE_JTAG = 1, /* push-pull outputs */ @@ -107,9 +101,6 @@ static bool swd_mode; static int queued_retval; static char swd_features; -static const cc_t SHORT_TIMEOUT = 1; /* Must be at least 1. */ -static const cc_t NORMAL_TIMEOUT = 10; - static int buspirate_fd = -1; static int buspirate_pinmode = MODE_JTAG_OD; static int buspirate_baudrate = SERIAL_NORMAL; @@ -160,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; @@ -283,7 +274,7 @@ static bool read_and_discard_all_data(const int fd) static int buspirate_init(void) { - if (buspirate_port == NULL) { + if (!buspirate_port) { LOG_ERROR("You need to specify the serial port!"); return ERROR_JTAG_INIT_FAILED; } @@ -464,58 +455,58 @@ COMMAND_HANDLER(buspirate_handle_port_command) if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; - if (buspirate_port == NULL) + if (!buspirate_port) buspirate_port = strdup(CMD_ARGV[0]); return ERROR_OK; } -static const struct command_registration buspirate_command_handlers[] = { +static const struct command_registration buspirate_subcommand_handlers[] = { { - .name = "buspirate_adc", + .name = "adc", .handler = &buspirate_handle_adc_command, .mode = COMMAND_EXEC, .help = "reads voltages on adc pins", .usage = "", }, { - .name = "buspirate_vreg", + .name = "vreg", .usage = "<1|0>", .handler = &buspirate_handle_vreg_command, .mode = COMMAND_CONFIG, .help = "changes the state of voltage regulators", }, { - .name = "buspirate_pullup", + .name = "pullup", .usage = "<1|0>", .handler = &buspirate_handle_pullup_command, .mode = COMMAND_CONFIG, .help = "changes the state of pullup", }, { - .name = "buspirate_led", + .name = "led", .usage = "<1|0>", .handler = &buspirate_handle_led_command, .mode = COMMAND_EXEC, .help = "changes the state of led", }, { - .name = "buspirate_speed", + .name = "speed", .usage = "<normal|fast>", .handler = &buspirate_handle_speed_command, .mode = COMMAND_CONFIG, .help = "speed of the interface", }, { - .name = "buspirate_mode", + .name = "mode", .usage = "<normal|open-drain>", .handler = &buspirate_handle_mode_command, .mode = COMMAND_CONFIG, .help = "pin mode of the interface", }, { - .name = "buspirate_port", + .name = "port", .usage = "/dev/ttyUSB0", .handler = &buspirate_handle_port_command, .mode = COMMAND_CONFIG, @@ -524,6 +515,17 @@ static const struct command_registration buspirate_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration buspirate_command_handlers[] = { + { + .name = "buspirate", + .mode = COMMAND_ANY, + .help = "perform buspirate management", + .chain = buspirate_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static const struct swd_driver buspirate_swd = { .init = buspirate_swd_init, .switch_seq = buspirate_swd_switch_seq, @@ -708,8 +710,6 @@ static void buspirate_tap_init(void) static int buspirate_tap_execute(void) { - static const int CMD_TAP_SHIFT_HEADER_LEN = 3; - uint8_t tmp[4096]; uint8_t *in_buf; int i; @@ -800,7 +800,7 @@ static void buspirate_tap_append(int tms, int tdi) int bit_index = tap_chain_index % 8; uint8_t bit = 1 << bit_index; - if (0 == bit_index) { + if (bit_index == 0) { /* Let's say that the TAP shift operation wants to shift 9 bits, so we will be sending to the Bus Pirate a bit count of 9 but still full 16 bits (2 bytes) of shift data. @@ -1178,13 +1178,13 @@ static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout) /* set the serial port parameters */ fcntl(fd, F_SETFL, 0); - if (0 != tcgetattr(fd, &t_opt)) + if (tcgetattr(fd, &t_opt) != 0) return -1; - if (0 != cfsetispeed(&t_opt, baud)) + if (cfsetispeed(&t_opt, baud) != 0) return -1; - if (0 != cfsetospeed(&t_opt, baud)) + if (cfsetospeed(&t_opt, baud) != 0) return -1; t_opt.c_cflag |= (CLOCAL | CREAD); @@ -1206,7 +1206,7 @@ static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout) /* Note that, in the past, TCSANOW was used below instead of TCSADRAIN, and CMD_UART_SPEED did not work properly then, at least with the Bus Pirate v3.5 (USB). */ - if (0 != tcsetattr(fd, TCSADRAIN, &t_opt)) { + if (tcsetattr(fd, TCSADRAIN, &t_opt) != 0) { /* According to the Linux documentation, this is actually not enough to detect errors, you need to call tcgetattr() and check that all changes have been performed successfully. */ @@ -1365,7 +1365,7 @@ static uint8_t buspirate_swd_write_header(uint8_t cmd) tmp[5] = 0x07; /* write mode trn_1 */ tmp[6] = 0x07; /* write mode trn_2 */ - to_send = ((cmd & SWD_CMD_RnW) == 0) ? 7 : 5; + to_send = ((cmd & SWD_CMD_RNW) == 0) ? 7 : 5; buspirate_serial_write(buspirate_fd, tmp, to_send); /* read ack */ @@ -1411,7 +1411,7 @@ static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_del uint8_t tmp[16]; LOG_DEBUG("buspirate_swd_read_reg"); - assert(cmd & SWD_CMD_RnW); + assert(cmd & SWD_CMD_RNW); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skip buspirate_swd_read_reg because queued_retval=%d", queued_retval); @@ -1441,8 +1441,8 @@ static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_del LOG_DEBUG("%s %s %s 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_RnW ? "read" : "write", + cmd & SWD_CMD_APNDP ? "AP" : "DP", + cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, data); @@ -1455,7 +1455,7 @@ static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_del } if (value) *value = data; - if (cmd & SWD_CMD_APnDP) + if (cmd & SWD_CMD_APNDP) buspirate_swd_idle_clocks(ap_delay_clk); return; case SWD_ACK_WAIT: @@ -1478,7 +1478,7 @@ static void buspirate_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_del uint8_t tmp[16]; LOG_DEBUG("buspirate_swd_write_reg"); - assert(!(cmd & SWD_CMD_RnW)); + assert(!(cmd & SWD_CMD_RNW)); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skip buspirate_swd_write_reg because queued_retval=%d", queued_retval); @@ -1499,14 +1499,14 @@ static void buspirate_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_del LOG_DEBUG("%s %s %s 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_RnW ? "read" : "write", + cmd & SWD_CMD_APNDP ? "AP" : "DP", + cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, value); switch (ack) { case SWD_ACK_OK: - if (cmd & SWD_CMD_APnDP) + if (cmd & SWD_CMD_APNDP) buspirate_swd_idle_clocks(ap_delay_clk); return; case SWD_ACK_WAIT: diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c new file mode 100644 index 0000000000..d7367d8137 --- /dev/null +++ b/src/jtag/drivers/cmsis_dap.c @@ -0,0 +1,2330 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2021 by Adrian Negreanu * + * groleo@gmail.com * + * * + * Copyright (C) 2018 by Mickaël Thomas * + * mickael9@gmail.com * + * * + * Copyright (C) 2016 by Maksym Hilliaka * + * oter@frozen-team.com * + * * + * Copyright (C) 2016 by Phillip Pearson * + * pp@myelin.co.nz * + * * + * Copyright (C) 2014 by Paul Fertser * + * fercerpav@gmail.com * + * * + * Copyright (C) 2013 by mike brown * + * mike@theshedworks.org.uk * + * * + * Copyright (C) 2013 by Spencer Oliver * + * spen@spen-soft.co.uk * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <transport/transport.h> +#include "helper/replacements.h" +#include <jtag/adapter.h> +#include <jtag/swd.h> +#include <jtag/interface.h> +#include <jtag/commands.h> +#include <jtag/tcl.h> +#include <target/cortex_m.h> + +#include "cmsis_dap.h" +#include "libusb_helper.h" + +static const struct cmsis_dap_backend *const cmsis_dap_backends[] = { +#if BUILD_CMSIS_DAP_USB == 1 + &cmsis_dap_usb_backend, +#endif + +#if BUILD_CMSIS_DAP_HID == 1 + &cmsis_dap_hid_backend, +#endif +}; + +/* USB Config */ + +/* Known vid/pid pairs: + * VID 0xc251: Keil Software + * PID 0xf001: LPC-Link-II CMSIS_DAP + * PID 0xf002: OPEN-SDA CMSIS_DAP (Freedom Board) + * PID 0x2722: Keil ULINK2 CMSIS-DAP + * PID 0x2750: Keil ULINKplus CMSIS-DAP + * + * VID 0x0d28: mbed Software + * PID 0x0204: MBED CMSIS-DAP + */ + +#define MAX_USB_IDS 8 +/* vid = pid = 0 marks the end of the list */ +static uint16_t cmsis_dap_vid[MAX_USB_IDS + 1] = { 0 }; +static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 }; +static int cmsis_dap_backend = -1; +static bool swd_mode; + +/* CMSIS-DAP General Commands */ +#define CMD_DAP_INFO 0x00 +#define CMD_DAP_LED 0x01 +#define CMD_DAP_CONNECT 0x02 +#define CMD_DAP_DISCONNECT 0x03 +#define CMD_DAP_WRITE_ABORT 0x08 +#define CMD_DAP_DELAY 0x09 +#define CMD_DAP_RESET_TARGET 0x0A + +/* CMD_INFO */ +#define INFO_ID_VENDOR 0x01 /* string */ +#define INFO_ID_PRODUCT 0x02 /* string */ +#define INFO_ID_SERNUM 0x03 /* string */ +#define INFO_ID_FW_VER 0x04 /* string */ +#define INFO_ID_TD_VEND 0x05 /* string */ +#define INFO_ID_TD_NAME 0x06 /* string */ +#define INFO_ID_CAPS 0xf0 /* byte */ +#define INFO_ID_PKT_CNT 0xfe /* byte */ +#define INFO_ID_PKT_SZ 0xff /* short */ +#define INFO_ID_SWO_BUF_SZ 0xfd /* word */ + +#define INFO_CAPS_SWD BIT(0) +#define INFO_CAPS_JTAG BIT(1) +#define INFO_CAPS_SWO_UART BIT(2) +#define INFO_CAPS_SWO_MANCHESTER BIT(3) +#define INFO_CAPS_ATOMIC_CMDS BIT(4) +#define INFO_CAPS_TEST_DOMAIN_TIMER BIT(5) +#define INFO_CAPS_SWO_STREAMING_TRACE BIT(6) +#define INFO_CAPS_UART_PORT BIT(7) +#define INFO_CAPS_USB_COM_PORT BIT(8) +#define INFO_CAPS__NUM_CAPS 9 + +/* CMD_LED */ +#define LED_ID_CONNECT 0x00 +#define LED_ID_RUN 0x01 + +#define LED_OFF 0x00 +#define LED_ON 0x01 + +/* CMD_CONNECT */ +#define CONNECT_DEFAULT 0x00 +#define CONNECT_SWD 0x01 +#define CONNECT_JTAG 0x02 + +/* CMSIS-DAP Common SWD/JTAG Commands */ +#define CMD_DAP_DELAY 0x09 +#define CMD_DAP_SWJ_PINS 0x10 +#define CMD_DAP_SWJ_CLOCK 0x11 +#define CMD_DAP_SWJ_SEQ 0x12 + +/* + * PINS + * Bit 0: SWCLK/TCK + * Bit 1: SWDIO/TMS + * Bit 2: TDI + * Bit 3: TDO + * Bit 5: nTRST + * Bit 7: nRESET + */ + +#define SWJ_PIN_TCK (1<<0) +#define SWJ_PIN_TMS (1<<1) +#define SWJ_PIN_TDI (1<<2) +#define SWJ_PIN_TDO (1<<3) +#define SWJ_PIN_TRST (1<<5) +#define SWJ_PIN_SRST (1<<7) + +/* CMSIS-DAP SWD Commands */ +#define CMD_DAP_SWD_CONFIGURE 0x13 +#define CMD_DAP_SWD_SEQUENCE 0x1D + +/* CMSIS-DAP JTAG Commands */ +#define CMD_DAP_JTAG_SEQ 0x14 +#define CMD_DAP_JTAG_CONFIGURE 0x15 +#define CMD_DAP_JTAG_IDCODE 0x16 + +/* CMSIS-DAP JTAG sequence info masks */ +/* Number of bits to clock through (0 means 64) */ +#define DAP_JTAG_SEQ_TCK 0x3F +/* TMS will be set during the sequence if this bit is set */ +#define DAP_JTAG_SEQ_TMS 0x40 +/* TDO output will be captured if this bit is set */ +#define DAP_JTAG_SEQ_TDO 0x80 + + +/* CMSIS-DAP Transfer Commands */ +#define CMD_DAP_TFER_CONFIGURE 0x04 +#define CMD_DAP_TFER 0x05 +#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 + +/* CMSIS-DAP SWO Commands */ +#define CMD_DAP_SWO_TRANSPORT 0x17 +#define CMD_DAP_SWO_MODE 0x18 +#define CMD_DAP_SWO_BAUDRATE 0x19 +#define CMD_DAP_SWO_CONTROL 0x1A +#define CMD_DAP_SWO_STATUS 0x1B +#define CMD_DAP_SWO_DATA 0x1C +#define CMD_DAP_SWO_EX_STATUS 0x1E + +/* SWO transport mode for reading trace data */ +#define DAP_SWO_TRANSPORT_NONE 0 +#define DAP_SWO_TRANSPORT_DATA 1 +#define DAP_SWO_TRANSPORT_WINUSB 2 + +/* SWO trace capture mode */ +#define DAP_SWO_MODE_OFF 0 +#define DAP_SWO_MODE_UART 1 +#define DAP_SWO_MODE_MANCHESTER 2 + +/* SWO trace data capture */ +#define DAP_SWO_CONTROL_STOP 0 +#define DAP_SWO_CONTROL_START 1 + +/* SWO trace status */ +#define DAP_SWO_STATUS_CAPTURE_INACTIVE 0 +#define DAP_SWO_STATUS_CAPTURE_ACTIVE 1 +#define DAP_SWO_STATUS_CAPTURE_MASK BIT(0) +#define DAP_SWO_STATUS_STREAM_ERROR_MASK BIT(6) +#define DAP_SWO_STATUS_BUFFER_OVERRUN_MASK BIT(7) + +/* CMSIS-DAP Vendor Commands + * None as yet... */ + +static const char * const info_caps_str[INFO_CAPS__NUM_CAPS] = { + "SWD supported", + "JTAG supported", + "SWO-UART supported", + "SWO-MANCHESTER supported", + "Atomic commands supported", + "Test domain timer supported", + "SWO streaming trace supported", + "UART communication port supported", + "UART via USB COM port supported", +}; + +struct pending_scan_result { + /** Offset in bytes in the CMD_DAP_JTAG_SEQ response buffer. */ + unsigned int first; + /** Number of bits to read. */ + unsigned int length; + /** Location to store the result */ + uint8_t *buffer; + /** Offset in the destination buffer */ + unsigned int buffer_offset; +}; + +/* Read mode */ +enum cmsis_dap_blocking { + CMSIS_DAP_NON_BLOCKING, + CMSIS_DAP_BLOCKING +}; + +/* Each block in FIFO can contain up to pending_queue_len transfers */ +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 +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_usable_size - 3) +static int queued_seq_count; +static int queued_seq_buf_end; +static int queued_seq_tdo_ptr; +static uint8_t queued_seq_buf[1024]; /* TODO: make dynamic / move into cmsis object */ + +static int queued_retval; + +static uint8_t output_pins = SWJ_PIN_SRST | SWJ_PIN_TRST; + +static struct cmsis_dap *cmsis_dap_handle; + + +static int cmsis_dap_quit(void); + +static int cmsis_dap_open(void) +{ + const struct cmsis_dap_backend *backend = NULL; + + struct cmsis_dap *dap = calloc(1, sizeof(struct cmsis_dap)); + if (!dap) { + LOG_ERROR("unable to allocate memory"); + return ERROR_FAIL; + } + + if (cmsis_dap_backend >= 0) { + /* Use forced backend */ + backend = cmsis_dap_backends[cmsis_dap_backend]; + if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, adapter_get_required_serial()) != ERROR_OK) + backend = NULL; + } else { + /* Try all backends */ + for (unsigned int i = 0; i < ARRAY_SIZE(cmsis_dap_backends); i++) { + backend = cmsis_dap_backends[i]; + if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, adapter_get_required_serial()) == ERROR_OK) + break; + else + backend = NULL; + } + } + + if (!backend) { + LOG_ERROR("unable to find a matching CMSIS-DAP device"); + free(dap); + return ERROR_FAIL; + } + + dap->backend = backend; + + cmsis_dap_handle = dap; + + return ERROR_OK; +} + +static void cmsis_dap_close(struct cmsis_dap *dap) +{ + if (dap->backend) { + dap->backend->close(dap); + dap->backend = NULL; + } + + free(dap->packet_buffer); + + 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) +{ + unsigned int i; + /* Some CMSIS-DAP adapters keep buffered packets over + * 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, NULL); + if (retval == ERROR_TIMEOUT_REACHED) + break; + } + if (i) + LOG_DEBUG("Flushed %u packets", i); +} + +/* Send a message and receive the reply */ +static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen) +{ + 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--; + } + dap->pending_fifo_put_idx = 0; + dap->pending_fifo_get_idx = 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, NULL); + if (retval < 0) + return retval; + + 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; + } + + if (resp[0] != current_cmd) { + 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; + } + + return ERROR_OK; +} + +static int cmsis_dap_cmd_dap_swj_pins(uint8_t pins, uint8_t mask, uint32_t delay, uint8_t *input) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_SWJ_PINS; + command[1] = pins; + command[2] = mask; + h_u32_to_le(&command[3], delay); + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 7); + if (retval != ERROR_OK) { + LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_PINS failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + if (input) + *input = cmsis_dap_handle->response[1]; + + return ERROR_OK; +} + +static int cmsis_dap_cmd_dap_swj_clock(uint32_t swj_clock) +{ + uint8_t *command = cmsis_dap_handle->command; + + /* set clock in Hz */ + swj_clock *= 1000; + + command[0] = CMD_DAP_SWJ_CLOCK; + h_u32_to_le(&command[1], swj_clock); + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 5); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { + LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_CLOCK failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +/* clock a sequence of bits out on TMS, to change JTAG states */ +static int cmsis_dap_cmd_dap_swj_sequence(uint8_t s_len, const uint8_t *sequence) +{ + uint8_t *command = cmsis_dap_handle->command; + +#ifdef CMSIS_DAP_JTAG_DEBUG + LOG_DEBUG("cmsis-dap TMS sequence: len=%d", s_len); + for (unsigned int i = 0; i < DIV_ROUND_UP(s_len, 8); ++i) + printf("%02X ", sequence[i]); + + printf("\n"); +#endif + + command[0] = CMD_DAP_SWJ_SEQ; + command[1] = s_len; + bit_copy(&command[2], 0, sequence, 0, s_len); + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 2 + DIV_ROUND_UP(s_len, 8)); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static int cmsis_dap_cmd_dap_info(uint8_t info, uint8_t **data) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_INFO; + command[1] = info; + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); + if (retval != ERROR_OK) { + LOG_ERROR("CMSIS-DAP command CMD_INFO failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + *data = &cmsis_dap_handle->response[1]; + + return ERROR_OK; +} + +static int cmsis_dap_cmd_dap_led(uint8_t led, uint8_t state) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_LED; + command[1] = led; + command[2] = state; + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 3); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { + LOG_ERROR("CMSIS-DAP command CMD_LED failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +static int cmsis_dap_cmd_dap_connect(uint8_t mode) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_CONNECT; + command[1] = mode; + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); + if (retval != ERROR_OK) { + LOG_ERROR("CMSIS-DAP command CMD_CONNECT failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + if (cmsis_dap_handle->response[1] != mode) { + LOG_ERROR("CMSIS-DAP failed to connect in mode (%d)", mode); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +static int cmsis_dap_cmd_dap_disconnect(void) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_DISCONNECT; + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 1); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { + LOG_ERROR("CMSIS-DAP command CMD_DISCONNECT failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +static int cmsis_dap_cmd_dap_tfer_configure(uint8_t idle, uint16_t retry_count, uint16_t match_retry) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_TFER_CONFIGURE; + command[1] = idle; + h_u16_to_le(&command[2], retry_count); + h_u16_to_le(&command[4], match_retry); + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 6); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { + LOG_ERROR("CMSIS-DAP command CMD_TFER_Configure failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +static int cmsis_dap_cmd_dap_swd_configure(uint8_t cfg) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_SWD_CONFIGURE; + command[1] = cfg; + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { + LOG_ERROR("CMSIS-DAP command CMD_SWD_Configure failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +#if 0 +static int cmsis_dap_cmd_dap_delay(uint16_t delay_us) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_DELAY; + h_u16_to_le(&command[1], delay_us); + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 3); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { + LOG_ERROR("CMSIS-DAP command CMD_Delay failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} +#endif + +static int cmsis_dap_metacmd_targetsel(uint32_t instance_id) +{ + uint8_t *command = cmsis_dap_handle->command; + const uint32_t SEQ_RD = 0x80, SEQ_WR = 0x00; + + /* SWD multi-drop requires a transfer ala CMD_DAP_TFER, + but with no expectation of an SWD ACK response. In + CMSIS-DAP v1.20 and v2.00, CMD_DAP_SWD_SEQUENCE was + added to allow this special sequence to be generated. + 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 */ + + /* sequence 0: packet request for TARGETSEL */ + command[idx++] = SEQ_WR | 8; + command[idx++] = SWD_CMD_START | swd_cmd(false, false, DP_TARGETSEL) | SWD_CMD_STOP | SWD_CMD_PARK; + + /* sequence 1: read Trn ACK Trn, no expectation for target to ACK */ + command[idx++] = SEQ_RD | 5; + + /* sequence 2: WDATA plus parity */ + command[idx++] = SEQ_WR | (32 + 1); + h_u32_to_le(command + idx, instance_id); + idx += 4; + command[idx++] = parity_u32(instance_id); + + int retval = cmsis_dap_xfer(cmsis_dap_handle, idx); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { + LOG_ERROR("CMSIS-DAP command SWD_Sequence failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +/** + * Sets the SWO transport mode. + * @param[in] transport The transport mode. Can be None, SWO_Data or + * WinUSB (requires CMSIS-DAP v2). + */ +static int cmsis_dap_cmd_dap_swo_transport(uint8_t transport) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_SWO_TRANSPORT; + command[1] = transport; + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { + LOG_ERROR("CMSIS-DAP: command CMD_SWO_Transport(%d) failed.", transport); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +/** + * Sets the SWO trace capture mode. + * @param[in] mode Trace capture mode. Can be UART or MANCHESTER. + */ +static int cmsis_dap_cmd_dap_swo_mode(uint8_t mode) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_SWO_MODE; + command[1] = mode; + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { + LOG_ERROR("CMSIS-DAP: command CMD_SWO_Mode(%d) failed.", mode); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +/** + * Sets the baudrate for capturing SWO trace data. + * Can be called iteratively to determine supported baudrates. + * @param[in] in_baudrate Requested baudrate. + * @param[out] dev_baudrate Actual baudrate or 0 (baudrate not configured). + * When requested baudrate is not achievable the + * closest configured baudrate can be returned or + * 0 which indicates that baudrate was not configured. + */ +static int cmsis_dap_cmd_dap_swo_baudrate( + uint32_t in_baudrate, + uint32_t *dev_baudrate) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_SWO_BAUDRATE; + h_u32_to_le(&command[1], in_baudrate); + + 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); + if (dev_baudrate) + *dev_baudrate = 0; + return ERROR_JTAG_DEVICE_ERROR; + } + + if (dev_baudrate) + *dev_baudrate = rvbr; + + return ERROR_OK; +} + +/** + * Controls the SWO trace data capture. + * @param[in] control Start or stop a trace. Starting capture automatically + * flushes any existing trace data in buffers which has + * not yet been read. + */ +static int cmsis_dap_cmd_dap_swo_control(uint8_t control) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_SWO_CONTROL; + command[1] = control; + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 2); + if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) { + LOG_ERROR("CMSIS-DAP: command CMD_SWO_Control(%d) failed.", control); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +/** + * Reads the SWO trace status. + * @param[out] trace_status The trace's status. + * Bit0: Trace Capture (1 - active, 0 - inactive). + * Bit6: Trace Stream Error. + * Bit7: Trace Buffer Overrun. + * @param[out] trace_count Number of bytes in Trace Buffer (not yet read). + */ +static int cmsis_dap_cmd_dap_swo_status( + uint8_t *trace_status, + size_t *trace_count) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_SWO_STATUS; + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 1); + if (retval != ERROR_OK) { + LOG_ERROR("CMSIS-DAP: command CMD_SWO_Status failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + if (trace_status) + *trace_status = cmsis_dap_handle->response[1]; + if (trace_count) + *trace_count = le_to_h_u32(&cmsis_dap_handle->response[2]); + + return ERROR_OK; +} + +/** + * Reads the captured SWO trace data from Trace Buffer. + * @param[in] max_trace_count Maximum number of Trace Data bytes to read. + * @param[out] trace_status The trace's status. + * @param[out] trace_count Number of Trace Data bytes read. + * @param[out] data Trace Data bytes read. + */ +static int cmsis_dap_cmd_dap_swo_data( + size_t max_trace_count, + uint8_t *trace_status, + size_t *trace_count, + uint8_t *data) +{ + uint8_t *command = cmsis_dap_handle->command; + + command[0] = CMD_DAP_SWO_DATA; + h_u16_to_le(&command[1], max_trace_count); + + int retval = cmsis_dap_xfer(cmsis_dap_handle, 3); + if (retval != ERROR_OK) { + LOG_ERROR("CMSIS-DAP: command CMD_SWO_Data failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + *trace_status = cmsis_dap_handle->response[1]; + *trace_count = le_to_h_u16(&cmsis_dap_handle->response[2]); + + if (*trace_count > 0) + memcpy(data, &cmsis_dap_handle->response[4], *trace_count); + + 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 = 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 %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) { + 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] = block->command; + command[1] = 0x00; /* DAP Index */ + + 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, + cmd & SWD_CMD_APNDP ? "AP" : "DP", + cmd & SWD_CMD_RNW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, data); + + /* When proper WAIT handling is implemented in the + * common SWD framework, this kludge can be + * removed. However, this might lead to minor + * performance degradation as the adapter wouldn't be + * able to automatically retry anything (because ARM + * has forgotten to implement sticky error flags + * clearing). See also comments regarding + * cmsis_dap_cmd_dap_tfer_configure() and + * cmsis_dap_cmd_dap_swd_configure() in + * cmsis_dap_init(). + */ + if (!(cmd & SWD_CMD_RNW) && + !(cmd & SWD_CMD_APNDP) && + (cmd & SWD_CMD_A32) >> 1 == DP_CTRL_STAT && + (data & CORUNDETECT)) { + LOG_DEBUG("refusing to enable sticky overrun detection"); + data &= ~CORUNDETECT; + } + + if (!block_cmd || i == 0) + command[idx++] = (cmd >> 1) & 0x0f; + + if (!(cmd & SWD_CMD_RNW)) { + h_u32_to_le(&command[idx], data); + idx += 4; + } + } + + int retval = dap->backend->write(dap, idx, LIBUSB_TIMEOUT_MS); + if (retval < 0) { + queued_retval = retval; + goto skip; + } + + 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; + +skip: + block->transfer_count = 0; +} + +static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, enum cmsis_dap_blocking blocking) +{ + int retval; + struct pending_request_block *block = &dap->pending_fifo[dap->pending_fifo_get_idx]; + + 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 */ + 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 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] != block->command) { + LOG_ERROR("CMSIS-DAP command mismatch. Expected 0x%x received 0x%" PRIx8, + block->command, resp[0]); + cmsis_dap_swd_cancel_transfers(dap); + queued_retval = ERROR_FAIL; + return; + } + + 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"); + queued_retval = swd_ack_to_error_code(ack); + /* TODO: use results of transfers completed before the error occurred? */ + goto skip; + } + + 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 %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; + uint32_t data = le_to_h_u32(&resp[idx]); + uint32_t tmp = data; + idx += 4; + + LOG_DEBUG_IO("Read result: %" PRIx32, data); + + /* Imitate posted AP reads */ + if ((transfer->cmd & SWD_CMD_APNDP) || + ((transfer->cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) { + tmp = last_read; + last_read = data; + } + + if (transfer->buffer) + *(uint32_t *)(transfer->buffer) = tmp; + } + } + +skip: + block->transfer_count = 0; + 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 (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); + } + + while (cmsis_dap_handle->pending_fifo_block_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, CMSIS_DAP_BLOCKING); + + cmsis_dap_handle->pending_fifo_put_idx = 0; + cmsis_dap_handle->pending_fifo_get_idx = 0; + + int retval = queued_retval; + queued_retval = ERROR_OK; + + 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) +{ + /* 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; + + /* 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); + + 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); + } + + assert(cmsis_dap_handle->pending_fifo[cmsis_dap_handle->pending_fifo_put_idx].transfer_count < pending_queue_len); + + if (queued_retval != ERROR_OK) + return; + + 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++; +} + +static void cmsis_dap_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) +{ + assert(!(cmd & SWD_CMD_RNW)); + cmsis_dap_swd_queue_cmd(cmd, NULL, value); +} + +static void cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) +{ + assert(cmd & SWD_CMD_RNW); + cmsis_dap_swd_queue_cmd(cmd, value, 0); +} + +static int cmsis_dap_get_serial_info(void) +{ + uint8_t *data; + + int retval = cmsis_dap_cmd_dap_info(INFO_ID_SERNUM, &data); + if (retval != ERROR_OK) + return retval; + + if (data[0]) /* strlen */ + LOG_INFO("CMSIS-DAP: Serial# = %s", &data[1]); + + return ERROR_OK; +} + +static int cmsis_dap_get_version_info(void) +{ + uint8_t *data; + + /* INFO_ID_FW_VER - string */ + int retval = cmsis_dap_cmd_dap_info(INFO_ID_FW_VER, &data); + if (retval != ERROR_OK) + return retval; + + if (data[0]) /* strlen */ + LOG_INFO("CMSIS-DAP: FW Version = %s", &data[1]); + + return ERROR_OK; +} + +static int cmsis_dap_get_caps_info(void) +{ + uint8_t *data; + + /* INFO_ID_CAPS - byte */ + int retval = cmsis_dap_cmd_dap_info(INFO_ID_CAPS, &data); + if (retval != ERROR_OK) + return retval; + + if (data[0] == 1 || data[0] == 2) { + uint16_t caps = data[1]; + if (data[0] == 2) + caps |= (uint16_t)data[2] << 8; + + cmsis_dap_handle->caps = caps; + + for (unsigned int i = 0; i < INFO_CAPS__NUM_CAPS; ++i) { + if (caps & BIT(i)) + LOG_INFO("CMSIS-DAP: %s", info_caps_str[i]); + } + } + + return ERROR_OK; +} + +static int cmsis_dap_get_swo_buf_sz(uint32_t *swo_buf_sz) +{ + uint8_t *data; + + /* INFO_ID_SWO_BUF_SZ - word */ + int retval = cmsis_dap_cmd_dap_info(INFO_ID_SWO_BUF_SZ, &data); + if (retval != ERROR_OK) + return retval; + + if (data[0] != 4) + return ERROR_FAIL; + + *swo_buf_sz = le_to_h_u32(&data[1]); + + LOG_INFO("CMSIS-DAP: SWO Trace Buffer Size = %u bytes", *swo_buf_sz); + + return ERROR_OK; +} + +static int cmsis_dap_get_status(void) +{ + uint8_t d; + + int retval = cmsis_dap_cmd_dap_swj_pins(0, 0, 0, &d); + + if (retval == ERROR_OK) { + LOG_INFO("SWCLK/TCK = %d SWDIO/TMS = %d TDI = %d TDO = %d nTRST = %d nRESET = %d", + (d & SWJ_PIN_TCK) ? 1 : 0, + (d & SWJ_PIN_TMS) ? 1 : 0, + (d & SWJ_PIN_TDI) ? 1 : 0, + (d & SWJ_PIN_TDO) ? 1 : 0, + (d & SWJ_PIN_TRST) ? 1 : 0, + (d & SWJ_PIN_SRST) ? 1 : 0); + } + + return retval; +} + +static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq) +{ + const uint8_t *s; + unsigned int s_len; + int retval; + + 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. */ + + /* First disconnect before connecting, Atmel EDBG needs it for SAMD/R/L/C */ + cmsis_dap_cmd_dap_disconnect(); + + /* When we are reconnecting, DAP_Connect needs to be rerun, at + * least on Keil ULINK-ME */ + retval = cmsis_dap_cmd_dap_connect(CONNECT_SWD); + if (retval != ERROR_OK) + return retval; + } + + switch (seq) { + case LINE_RESET: + LOG_DEBUG_IO("SWD line reset"); + s = swd_seq_line_reset; + s_len = swd_seq_line_reset_len; + break; + case JTAG_TO_SWD: + LOG_DEBUG("JTAG-to-SWD"); + s = swd_seq_jtag_to_swd; + s_len = swd_seq_jtag_to_swd_len; + break; + case JTAG_TO_DORMANT: + LOG_DEBUG("JTAG-to-DORMANT"); + s = swd_seq_jtag_to_dormant; + s_len = swd_seq_jtag_to_dormant_len; + break; + case SWD_TO_JTAG: + LOG_DEBUG("SWD-to-JTAG"); + s = swd_seq_swd_to_jtag; + s_len = swd_seq_swd_to_jtag_len; + break; + case SWD_TO_DORMANT: + LOG_DEBUG("SWD-to-DORMANT"); + s = swd_seq_swd_to_dormant; + s_len = swd_seq_swd_to_dormant_len; + break; + case DORMANT_TO_SWD: + LOG_DEBUG("DORMANT-to-SWD"); + s = swd_seq_dormant_to_swd; + s_len = swd_seq_dormant_to_swd_len; + break; + case DORMANT_TO_JTAG: + LOG_DEBUG("DORMANT-to-JTAG"); + s = swd_seq_dormant_to_jtag; + s_len = swd_seq_dormant_to_jtag_len; + break; + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; + } + + retval = cmsis_dap_cmd_dap_swj_sequence(s_len, s); + if (retval != ERROR_OK) + return retval; + + /* Atmel EDBG needs renew clock setting after SWJ_Sequence + * otherwise default frequency is used */ + return cmsis_dap_cmd_dap_swj_clock(adapter_get_speed_khz()); +} + +static int cmsis_dap_swd_open(void) +{ + if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) { + LOG_ERROR("CMSIS-DAP: SWD not supported"); + return ERROR_JTAG_DEVICE_ERROR; + } + + int retval = cmsis_dap_cmd_dap_connect(CONNECT_SWD); + if (retval != ERROR_OK) + return retval; + + /* Add more setup here.??... */ + + LOG_INFO("CMSIS-DAP: Interface Initialised (SWD)"); + return ERROR_OK; +} + +static int cmsis_dap_init(void) +{ + uint8_t *data; + + int retval = cmsis_dap_open(); + if (retval != ERROR_OK) + return retval; + + cmsis_dap_flush_read(cmsis_dap_handle); + + retval = cmsis_dap_get_caps_info(); + if (retval != ERROR_OK) + return retval; + + retval = cmsis_dap_get_version_info(); + if (retval != ERROR_OK) + return retval; + + retval = cmsis_dap_get_serial_info(); + if (retval != ERROR_OK) + return retval; + + if (swd_mode) { + retval = cmsis_dap_swd_open(); + if (retval != ERROR_OK) + return retval; + } else { + /* Connect in JTAG mode */ + if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) { + LOG_ERROR("CMSIS-DAP: JTAG not supported"); + return ERROR_JTAG_DEVICE_ERROR; + } + + retval = cmsis_dap_cmd_dap_connect(CONNECT_JTAG); + if (retval != ERROR_OK) + return retval; + + LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)"); + } + + /* Be conservative and suppress submitting multiple HID requests + * until we get packet count info from the adaptor */ + cmsis_dap_handle->packet_count = 1; + + /* INFO_ID_PKT_SZ - short */ + retval = cmsis_dap_cmd_dap_info(INFO_ID_PKT_SZ, &data); + if (retval != ERROR_OK) + goto init_err; + + if (data[0] == 2) { /* short */ + uint16_t pkt_sz = data[1] + (data[2] << 8); + if (pkt_sz != cmsis_dap_handle->packet_size) { + 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; + + LOG_DEBUG("CMSIS-DAP: Packet Size = %" PRIu16, pkt_sz); + } + } + + /* 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 */ + 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 = %u", pkt_cnt); + } + + 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; + } + } + + /* Intentionally not checked for error, just logs an info message + * not vital for further debugging */ + (void)cmsis_dap_get_status(); + + /* Now try to connect to the target + * TODO: This is all SWD only @ present */ + retval = cmsis_dap_cmd_dap_swj_clock(adapter_get_speed_khz()); + if (retval != ERROR_OK) + goto init_err; + + /* Ask CMSIS-DAP to automatically retry on receiving WAIT for + * up to 64 times. This must be changed to 0 if sticky + * overrun detection is enabled. */ + retval = cmsis_dap_cmd_dap_tfer_configure(0, 64, 0); + if (retval != ERROR_OK) + goto init_err; + + if (swd_mode) { + /* Data Phase (bit 2) must be set to 1 if sticky overrun + * detection is enabled */ + retval = cmsis_dap_cmd_dap_swd_configure(0); /* 1 TRN, no Data Phase */ + if (retval != ERROR_OK) + goto init_err; + } + /* Both LEDs on */ + /* Intentionally not checked for error, debugging will work + * without LEDs */ + (void)cmsis_dap_cmd_dap_led(LED_ID_CONNECT, LED_ON); + (void)cmsis_dap_cmd_dap_led(LED_ID_RUN, LED_ON); + + /* support connecting with srst asserted */ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) { + retval = cmsis_dap_cmd_dap_swj_pins(0, SWJ_PIN_SRST, 0, NULL); + if (retval != ERROR_OK) + goto init_err; + LOG_INFO("Connecting under reset"); + } + } + LOG_INFO("CMSIS-DAP: Interface ready"); + return ERROR_OK; + +init_err: + cmsis_dap_quit(); + return retval; +} + +static int cmsis_dap_swd_init(void) +{ + swd_mode = true; + return ERROR_OK; +} + +static int cmsis_dap_quit(void) +{ + cmsis_dap_cmd_dap_disconnect(); + + /* Both LEDs off */ + cmsis_dap_cmd_dap_led(LED_ID_RUN, LED_OFF); + cmsis_dap_cmd_dap_led(LED_ID_CONNECT, LED_OFF); + + cmsis_dap_close(cmsis_dap_handle); + + return ERROR_OK; +} + +static int cmsis_dap_reset(int trst, int srst) +{ + /* Set both TRST and SRST even if they're not enabled as + * there's no way to tristate them */ + + output_pins = 0; + if (!srst) + output_pins |= SWJ_PIN_SRST; + if (!trst) + output_pins |= SWJ_PIN_TRST; + + int retval = cmsis_dap_cmd_dap_swj_pins(output_pins, + SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL); + if (retval != ERROR_OK) + LOG_ERROR("CMSIS-DAP: Interface reset failed"); + return retval; +} + +static void cmsis_dap_execute_sleep(struct jtag_command *cmd) +{ +#if 0 + int retval = cmsis_dap_cmd_dap_delay(cmd->cmd.sleep->us); + if (retval != ERROR_OK) +#endif + jtag_sleep(cmd->cmd.sleep->us); +} + +/* Set TMS high for five TCK clocks, to move the TAP to the Test-Logic-Reset state */ +static int cmsis_dap_execute_tlr_reset(struct jtag_command *cmd) +{ + LOG_INFO("cmsis-dap JTAG TLR_RESET"); + uint8_t seq = 0xff; + + int retval = cmsis_dap_cmd_dap_swj_sequence(8, &seq); + if (retval == ERROR_OK) + tap_set_state(TAP_RESET); + return retval; +} + +/* Set new end state */ +static void cmsis_dap_end_state(tap_state_t state) +{ + if (tap_is_state_stable(state)) + tap_set_end_state(state); + else { + LOG_ERROR("BUG: %i is not a valid end state", state); + exit(-1); + } +} + +#ifdef SPRINT_BINARY +static void sprint_binary(char *s, const uint8_t *buf, unsigned int offset, unsigned int len) +{ + if (!len) + return; + + /* + buf = { 0x18 } len=5 should result in: 11000 + buf = { 0xff 0x18 } len=13 should result in: 11111111 11000 + buf = { 0xc0 0x18 } offset=3 len=10 should result in: 11000 11000 + i=3 there means i/8 = 0 so c = 0xFF, and + */ + 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(' '); + *s++ = (c & mask) ? '1' : '0'; + } + *s = 0; +} +#endif + +#ifdef CMSIS_DAP_JTAG_DEBUG +static void debug_parse_cmsis_buf(const uint8_t *cmd, int cmdlen) +{ + /* cmd is a usb packet to go to the cmsis-dap interface */ + printf("cmsis-dap buffer (%d b): ", cmdlen); + for (int i = 0; i < cmdlen; ++i) + printf(" %02x", cmd[i]); + printf("\n"); + switch (cmd[0]) { + case CMD_DAP_JTAG_SEQ: { + printf("cmsis-dap jtag sequence command %02x (n=%d)\n", cmd[0], cmd[1]); + /* + * #1 = number of sequences + * #2 = sequence info 1 + * #3...4+n_bytes-1 = sequence 1 + * #4+n_bytes = sequence info 2 + * #5+n_bytes = sequence 2 (single bit) + */ + int pos = 2; + for (int seq = 0; seq < cmd[1]; ++seq) { + uint8_t info = cmd[pos++]; + int len = info & DAP_JTAG_SEQ_TCK; + if (len == 0) + len = 64; + printf(" sequence %d starting %d: info %02x (len=%d tms=%d read_tdo=%d): ", + seq, pos, info, len, info & DAP_JTAG_SEQ_TMS, info & DAP_JTAG_SEQ_TDO); + for (int i = 0; i < DIV_ROUND_UP(len, 8); ++i) + printf(" %02x", cmd[pos+i]); + pos += DIV_ROUND_UP(len, 8); + printf("\n"); + } + if (pos != cmdlen) { + printf("BUFFER LENGTH MISMATCH looks like %d but %d specified", pos, cmdlen); + exit(-1); + } + + break; + } + default: + LOG_DEBUG("unknown cmsis-dap command %02x", cmd[1]); + break; + } +} +#endif + +static void cmsis_dap_flush(void) +{ + if (!queued_seq_count) + return; + + LOG_DEBUG_IO("Flushing %d queued sequences (%d bytes) with %d pending scan results to capture", + queued_seq_count, queued_seq_buf_end, pending_scan_result_count); + + /* prepare CMSIS-DAP packet */ + uint8_t *command = cmsis_dap_handle->command; + command[0] = CMD_DAP_JTAG_SEQ; + command[1] = queued_seq_count; + memcpy(&command[2], queued_seq_buf, queued_seq_buf_end); + +#ifdef CMSIS_DAP_JTAG_DEBUG + debug_parse_cmsis_buf(command, queued_seq_buf_end + 2); +#endif + + /* send command to USB device */ + int retval = cmsis_dap_xfer(cmsis_dap_handle, queued_seq_buf_end + 2); + + uint8_t *resp = cmsis_dap_handle->response; + if (retval != ERROR_OK || resp[1] != DAP_OK) { + LOG_ERROR("CMSIS-DAP command CMD_DAP_JTAG_SEQ failed."); + exit(-1); + } + +#ifdef CMSIS_DAP_JTAG_DEBUG + LOG_DEBUG_IO("USB response buf:"); + for (int c = 0; c < queued_seq_buf_end + 3; ++c) + printf("%02X ", resp[c]); + printf("\n"); +#endif + + /* copy scan results into client buffers */ + for (int i = 0; i < pending_scan_result_count; ++i) { + struct pending_scan_result *scan = &pending_scan_results[i]; + LOG_DEBUG_IO("Copying pending_scan_result %d/%d: %d bits from byte %d -> buffer + %d bits", + i, pending_scan_result_count, scan->length, scan->first + 2, scan->buffer_offset); +#ifdef CMSIS_DAP_JTAG_DEBUG + for (uint32_t b = 0; b < DIV_ROUND_UP(scan->length, 8); ++b) + printf("%02X ", resp[2+scan->first+b]); + printf("\n"); +#endif + bit_copy(scan->buffer, scan->buffer_offset, &resp[2 + scan->first], 0, scan->length); + } + + /* reset */ + queued_seq_count = 0; + queued_seq_buf_end = 0; + queued_seq_tdo_ptr = 0; + pending_scan_result_count = 0; +} + +/* queue a sequence of bits to clock out TDI / in TDO, executing if the buffer is full. + * + * sequence=NULL means clock out zeros on TDI + * tdo_buffer=NULL means don't capture TDO + */ +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] %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); + + if (s_len == 0) + return; + + if (s_len > 64) { + LOG_DEBUG_IO("START JTAG SEQ SPLIT"); + 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: %u-bit chunk starting at offset %u", len, offset); + cmsis_dap_add_jtag_sequence( + len, + sequence, + s_offset + offset, + tms, + tdo_buffer, + !tdo_buffer ? 0 : (tdo_buffer_offset + offset) + ); + } + LOG_DEBUG_IO("END JTAG SEQ SPLIT"); + return; + } + + 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(); + + ++queued_seq_count; + + /* control byte */ + queued_seq_buf[queued_seq_buf_end] = + (tms ? DAP_JTAG_SEQ_TMS : 0) | + (tdo_buffer ? DAP_JTAG_SEQ_TDO : 0) | + (s_len == 64 ? 0 : s_len); + + if (sequence) + bit_copy(&queued_seq_buf[queued_seq_buf_end + 1], 0, sequence, s_offset, s_len); + else + memset(&queued_seq_buf[queued_seq_buf_end + 1], 0, DIV_ROUND_UP(s_len, 8)); + + queued_seq_buf_end += cmd_len; + + if (tdo_buffer) { + struct pending_scan_result *scan = &pending_scan_results[pending_scan_result_count++]; + scan->first = queued_seq_tdo_ptr; + queued_seq_tdo_ptr += DIV_ROUND_UP(s_len, 8); + scan->length = s_len; + scan->buffer = tdo_buffer; + scan->buffer_offset = tdo_buffer_offset; + } +} + +/* queue a sequence of bits to clock out TMS, executing if the buffer is full */ +static void cmsis_dap_add_tms_sequence(const uint8_t *sequence, int s_len) +{ + LOG_DEBUG_IO("%d bits: %02X", s_len, *sequence); + /* we use a series of CMD_DAP_JTAG_SEQ commands to toggle TMS, + because even though it seems ridiculously inefficient, it + allows us to combine TMS and scan sequences into the same + USB packet. */ + /* TODO: combine runs of the same tms value */ + for (int i = 0; i < s_len; ++i) { + bool bit = (sequence[i / 8] & (1 << (i % 8))) != 0; + cmsis_dap_add_jtag_sequence(1, NULL, 0, bit, NULL, 0); + } +} + +/* Move to the end state by queuing a sequence to clock into TMS */ +static void cmsis_dap_state_move(void) +{ + uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + uint8_t tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + LOG_DEBUG_IO("state move from %s to %s: %d clocks, %02X on tms", + tap_state_name(tap_get_state()), tap_state_name(tap_get_end_state()), + tms_scan_bits, tms_scan); + cmsis_dap_add_tms_sequence(&tms_scan, tms_scan_bits); + + tap_set_state(tap_get_end_state()); +} + + +/* Execute a JTAG scan operation by queueing TMS and TDI/TDO sequences */ +static void cmsis_dap_execute_scan(struct jtag_command *cmd) +{ + LOG_DEBUG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", + jtag_scan_type(cmd->cmd.scan)); + + /* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */ + while (cmd->cmd.scan->num_fields > 0 + && cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) { + cmd->cmd.scan->num_fields--; + LOG_DEBUG("discarding trailing empty field"); + } + + if (cmd->cmd.scan->num_fields == 0) { + LOG_DEBUG("empty scan, doing nothing"); + return; + } + + if (cmd->cmd.scan->ir_scan) { + if (tap_get_state() != TAP_IRSHIFT) { + cmsis_dap_end_state(TAP_IRSHIFT); + cmsis_dap_state_move(); + } + } else { + if (tap_get_state() != TAP_DRSHIFT) { + cmsis_dap_end_state(TAP_DRSHIFT); + cmsis_dap_state_move(); + } + } + + cmsis_dap_end_state(cmd->cmd.scan->end_state); + + struct scan_field *field = cmd->cmd.scan->fields; + unsigned scan_size = 0; + + for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { + scan_size += field->num_bits; + LOG_DEBUG_IO("%s%s field %d/%d %d bits", + field->in_value ? "in" : "", + field->out_value ? "out" : "", + i, + cmd->cmd.scan->num_fields, + field->num_bits); + + if (i == cmd->cmd.scan->num_fields - 1 && tap_get_state() != tap_get_end_state()) { + LOG_DEBUG_IO("Last field and have to move out of SHIFT state"); + /* Last field, and we're leaving IRSHIFT/DRSHIFT. Clock last bit during tap + * movement. This last field can't have length zero, it was checked above. */ + cmsis_dap_add_jtag_sequence( + field->num_bits - 1, /* number of bits to clock */ + field->out_value, /* output sequence */ + 0, /* output offset */ + false, /* TMS low */ + field->in_value, + 0); + + /* Clock the last bit out, with TMS high */ + uint8_t last_bit = 0; + if (field->out_value) + bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1); + cmsis_dap_add_jtag_sequence( + 1, + &last_bit, + 0, + true, + field->in_value, + field->num_bits - 1); + tap_set_state(tap_state_transition(tap_get_state(), 1)); + + /* Now clock one more cycle, with TMS low, to get us into a PAUSE state */ + cmsis_dap_add_jtag_sequence( + 1, + &last_bit, + 0, + false, + NULL, + 0); + tap_set_state(tap_state_transition(tap_get_state(), 0)); + } else { + LOG_DEBUG_IO("Internal field, staying in SHIFT state afterwards"); + /* Clocking part of a sequence into DR or IR with TMS=0, + leaving TMS=0 at the end so we can continue later */ + cmsis_dap_add_jtag_sequence( + field->num_bits, + field->out_value, + 0, + false, + field->in_value, + 0); + } + } + + if (tap_get_state() != tap_get_end_state()) { + cmsis_dap_end_state(tap_get_end_state()); + cmsis_dap_state_move(); + } + + LOG_DEBUG_IO("%s scan, %i bits, end in %s", + (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, + tap_state_name(tap_get_end_state())); +} + +static void cmsis_dap_pathmove(int num_states, tap_state_t *path) +{ + uint8_t tms0 = 0x00; + uint8_t tms1 = 0xff; + + for (int i = 0; i < num_states; i++) { + if (path[i] == tap_state_transition(tap_get_state(), false)) + cmsis_dap_add_tms_sequence(&tms0, 1); + else if (path[i] == tap_state_transition(tap_get_state(), true)) + cmsis_dap_add_tms_sequence(&tms1, 1); + else { + LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.", + tap_state_name(tap_get_state()), tap_state_name(path[i])); + exit(-1); + } + + tap_set_state(path[i]); + } + + cmsis_dap_end_state(tap_get_state()); +} + +static void cmsis_dap_execute_pathmove(struct jtag_command *cmd) +{ + LOG_DEBUG_IO("pathmove: %i states, end in %i", + cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + + cmsis_dap_pathmove(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); +} + +static void cmsis_dap_stableclocks(int num_cycles) +{ + uint8_t tms = tap_get_state() == TAP_RESET; + /* TODO: Perform optimizations? */ + /* Execute num_cycles. */ + for (int i = 0; i < num_cycles; i++) + cmsis_dap_add_tms_sequence(&tms, 1); +} + +static void cmsis_dap_runtest(int num_cycles) +{ + tap_state_t saved_end_state = tap_get_end_state(); + + /* Only do a state_move when we're not already in IDLE. */ + if (tap_get_state() != TAP_IDLE) { + cmsis_dap_end_state(TAP_IDLE); + cmsis_dap_state_move(); + } + cmsis_dap_stableclocks(num_cycles); + + /* Finish in end_state. */ + cmsis_dap_end_state(saved_end_state); + + if (tap_get_state() != tap_get_end_state()) + cmsis_dap_state_move(); +} + +static void cmsis_dap_execute_runtest(struct jtag_command *cmd) +{ + LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + + cmsis_dap_end_state(cmd->cmd.runtest->end_state); + cmsis_dap_runtest(cmd->cmd.runtest->num_cycles); +} + +static void cmsis_dap_execute_stableclocks(struct jtag_command *cmd) +{ + LOG_DEBUG_IO("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); + cmsis_dap_stableclocks(cmd->cmd.runtest->num_cycles); +} + +static void cmsis_dap_execute_tms(struct jtag_command *cmd) +{ + LOG_DEBUG_IO("TMS: %d bits", cmd->cmd.tms->num_bits); + cmsis_dap_cmd_dap_swj_sequence(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits); +} + +/* TODO: Is there need to call cmsis_dap_flush() for the JTAG_PATHMOVE, + * JTAG_RUNTEST, JTAG_STABLECLOCKS? */ +static void cmsis_dap_execute_command(struct jtag_command *cmd) +{ + switch (cmd->type) { + case JTAG_SLEEP: + cmsis_dap_flush(); + cmsis_dap_execute_sleep(cmd); + break; + case JTAG_TLR_RESET: + cmsis_dap_flush(); + cmsis_dap_execute_tlr_reset(cmd); + break; + case JTAG_SCAN: + cmsis_dap_execute_scan(cmd); + break; + case JTAG_PATHMOVE: + cmsis_dap_execute_pathmove(cmd); + break; + case JTAG_RUNTEST: + cmsis_dap_execute_runtest(cmd); + break; + case JTAG_STABLECLOCKS: + cmsis_dap_execute_stableclocks(cmd); + break; + case JTAG_TMS: + cmsis_dap_execute_tms(cmd); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type); + exit(-1); + } +} + +static int cmsis_dap_execute_queue(struct jtag_command *cmd_queue) +{ + struct jtag_command *cmd = cmd_queue; + + while (cmd) { + cmsis_dap_execute_command(cmd); + cmd = cmd->next; + } + + cmsis_dap_flush(); + + return ERROR_OK; +} + +static int cmsis_dap_speed(int speed) +{ + if (speed == 0) { + LOG_ERROR("RTCK not supported. Set nonzero \"adapter speed\"."); + return ERROR_JTAG_NOT_IMPLEMENTED; + } + + return cmsis_dap_cmd_dap_swj_clock(speed); +} + +static int cmsis_dap_speed_div(int speed, int *khz) +{ + *khz = speed; + return ERROR_OK; +} + +static int cmsis_dap_khz(int khz, int *jtag_speed) +{ + *jtag_speed = khz; + return ERROR_OK; +} + +static bool calculate_swo_prescaler(unsigned int traceclkin_freq, + uint32_t trace_freq, uint16_t *prescaler) +{ + unsigned int presc = (traceclkin_freq + trace_freq / 2) / trace_freq; + if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) + return false; + + /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */ + unsigned int max_deviation = (traceclkin_freq * 3) / 100; + if (presc * trace_freq < traceclkin_freq - max_deviation || + presc * trace_freq > traceclkin_freq + max_deviation) + return false; + + *prescaler = presc; + + return true; +} + +/** + * @see adapter_driver::config_trace + */ +static int cmsis_dap_config_trace( + bool trace_enabled, + enum tpiu_pin_protocol pin_protocol, + uint32_t port_size, + unsigned int *swo_freq, + unsigned int traceclkin_hz, + uint16_t *swo_prescaler) +{ + int retval; + + if (!trace_enabled) { + if (cmsis_dap_handle->trace_enabled) { + retval = cmsis_dap_cmd_dap_swo_control(DAP_SWO_CONTROL_STOP); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to disable the SWO-trace."); + return retval; + } + } + cmsis_dap_handle->trace_enabled = false; + LOG_INFO("SWO-trace disabled."); + return ERROR_OK; + } + + if (!(cmsis_dap_handle->caps & INFO_CAPS_SWO_UART) && + !(cmsis_dap_handle->caps & INFO_CAPS_SWO_MANCHESTER)) { + LOG_ERROR("SWO-trace is not supported by the device."); + return ERROR_FAIL; + } + + uint8_t swo_mode; + if (pin_protocol == TPIU_PIN_PROTOCOL_ASYNC_UART && + (cmsis_dap_handle->caps & INFO_CAPS_SWO_UART)) { + swo_mode = DAP_SWO_MODE_UART; + } else if (pin_protocol == TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER && + (cmsis_dap_handle->caps & INFO_CAPS_SWO_MANCHESTER)) { + swo_mode = DAP_SWO_MODE_MANCHESTER; + } else { + LOG_ERROR("Selected pin protocol is not supported."); + return ERROR_FAIL; + } + + if (*swo_freq == 0) { + LOG_INFO("SWO-trace frequency autodetection not implemented."); + return ERROR_FAIL; + } + + retval = cmsis_dap_cmd_dap_swo_control(DAP_SWO_CONTROL_STOP); + if (retval != ERROR_OK) + return retval; + + cmsis_dap_handle->trace_enabled = false; + + retval = cmsis_dap_get_swo_buf_sz(&cmsis_dap_handle->swo_buf_sz); + if (retval != ERROR_OK) + return retval; + + retval = cmsis_dap_cmd_dap_swo_transport(DAP_SWO_TRANSPORT_DATA); + if (retval != ERROR_OK) + return retval; + + retval = cmsis_dap_cmd_dap_swo_mode(swo_mode); + if (retval != ERROR_OK) + return retval; + + retval = cmsis_dap_cmd_dap_swo_baudrate(*swo_freq, swo_freq); + if (retval != ERROR_OK) + return retval; + + if (!calculate_swo_prescaler(traceclkin_hz, *swo_freq, + swo_prescaler)) { + LOG_ERROR("SWO frequency is not suitable. Please choose a " + "different frequency or use auto-detection."); + return ERROR_FAIL; + } + + LOG_INFO("SWO frequency: %u Hz.", *swo_freq); + LOG_INFO("SWO prescaler: %u.", *swo_prescaler); + + retval = cmsis_dap_cmd_dap_swo_control(DAP_SWO_CONTROL_START); + if (retval != ERROR_OK) + return retval; + + cmsis_dap_handle->trace_enabled = true; + + return ERROR_OK; +} + +/** + * @see adapter_driver::poll_trace + */ +static int cmsis_dap_poll_trace(uint8_t *buf, size_t *size) +{ + uint8_t trace_status; + size_t trace_count; + + if (!cmsis_dap_handle->trace_enabled) { + *size = 0; + return ERROR_OK; + } + + int retval = cmsis_dap_cmd_dap_swo_status(&trace_status, &trace_count); + if (retval != ERROR_OK) + return retval; + if ((trace_status & DAP_SWO_STATUS_CAPTURE_MASK) != DAP_SWO_STATUS_CAPTURE_ACTIVE) + return ERROR_FAIL; + + *size = trace_count < *size ? trace_count : *size; + size_t read_so_far = 0; + do { + size_t rb = 0; + uint32_t packet_size = cmsis_dap_handle->packet_size - 4 /*data-reply*/; + uint32_t remaining = *size - read_so_far; + if (remaining < packet_size) + packet_size = remaining; + retval = cmsis_dap_cmd_dap_swo_data( + packet_size, + &trace_status, + &rb, + &buf[read_so_far]); + if (retval != ERROR_OK) + return retval; + if ((trace_status & DAP_SWO_STATUS_CAPTURE_MASK) != DAP_SWO_STATUS_CAPTURE_ACTIVE) + return ERROR_FAIL; + + read_so_far += rb; + } while (read_so_far < *size); + + return ERROR_OK; +} + +COMMAND_HANDLER(cmsis_dap_handle_info_command) +{ + if (cmsis_dap_get_version_info() == ERROR_OK) + cmsis_dap_get_status(); + + return ERROR_OK; +} + +COMMAND_HANDLER(cmsis_dap_handle_cmd_command) +{ + uint8_t *command = cmsis_dap_handle->command; + + for (unsigned i = 0; i < CMD_ARGC; i++) + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[i], command[i]); + + int retval = cmsis_dap_xfer(cmsis_dap_handle, CMD_ARGC); + + if (retval != ERROR_OK) { + LOG_ERROR("CMSIS-DAP command failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + uint8_t *resp = cmsis_dap_handle->response; + LOG_INFO("Returned data %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8, + resp[1], resp[2], resp[3], resp[4]); + + return ERROR_OK; +} + +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 " + "(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"); + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + /* remove the incomplete trailing id */ + CMD_ARGC -= 1; + } + + unsigned i; + for (i = 0; i < CMD_ARGC; i += 2) { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], cmsis_dap_vid[i >> 1]); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], cmsis_dap_pid[i >> 1]); + } + + /* + * Explicitly terminate, in case there are multiples instances of + * cmsis_dap_vid_pid. + */ + cmsis_dap_vid[i >> 1] = cmsis_dap_pid[i >> 1] = 0; + + return ERROR_OK; +} + +COMMAND_HANDLER(cmsis_dap_handle_backend_command) +{ + if (CMD_ARGC == 1) { + if (strcmp(CMD_ARGV[0], "auto") == 0) { + cmsis_dap_backend = -1; /* autoselect */ + } else { + for (unsigned int i = 0; i < ARRAY_SIZE(cmsis_dap_backends); i++) { + if (strcasecmp(cmsis_dap_backends[i]->name, CMD_ARGV[0]) == 0) { + cmsis_dap_backend = i; + return ERROR_OK; + } + } + + command_print(CMD, "invalid backend argument to cmsis-dap backend <backend>"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } else { + 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", + .handler = &cmsis_dap_handle_info_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "show cmsis-dap info", + }, + { + .name = "cmd", + .handler = &cmsis_dap_handle_cmd_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "issue cmsis-dap command", + }, + { + .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 = "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 = "usb", + .chain = cmsis_dap_usb_subcommand_handlers, + .mode = COMMAND_ANY, + .help = "USB bulk backend-specific commands", + .usage = "<cmd>", + }, +#endif + 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, + .read_reg = cmsis_dap_swd_read_reg, + .write_reg = cmsis_dap_swd_write_reg, + .run = cmsis_dap_swd_run_queue, +}; + +static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL }; + +static struct jtag_interface cmsis_dap_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = cmsis_dap_execute_queue, +}; + +struct adapter_driver cmsis_dap_adapter_driver = { + .name = "cmsis-dap", + .transports = cmsis_dap_transport, + .commands = cmsis_dap_command_handlers, + + .init = cmsis_dap_init, + .quit = cmsis_dap_quit, + .reset = cmsis_dap_reset, + .speed = cmsis_dap_speed, + .khz = cmsis_dap_khz, + .speed_div = cmsis_dap_speed_div, + .config_trace = cmsis_dap_config_trace, + .poll_trace = cmsis_dap_poll_trace, + + .jtag_ops = &cmsis_dap_interface, + .swd_ops = &cmsis_dap_swd_driver, +}; diff --git a/src/jtag/drivers/cmsis_dap.h b/src/jtag/drivers/cmsis_dap.h new file mode 100644 index 0000000000..e47697d1f9 --- /dev/null +++ b/src/jtag/drivers/cmsis_dap.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_JTAG_DRIVERS_CMSIS_DAP_H +#define OPENOCD_JTAG_DRIVERS_CMSIS_DAP_H + +#include <stdint.h> + +struct cmsis_dap_backend; +struct cmsis_dap_backend_data; + +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; + unsigned int packet_size; + unsigned int packet_usable_size; + unsigned int packet_buffer_size; + uint8_t *packet_buffer; + 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; + bool quirk_mode; /* enable expensive workarounds */ + + uint32_t swo_buf_sz; + bool trace_enabled; +}; + +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 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; +extern const struct cmsis_dap_backend cmsis_dap_usb_backend; +extern const struct command_registration cmsis_dap_usb_subcommand_handlers[]; + +#define REPORT_ID_SIZE 1 + +#endif diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c deleted file mode 100644 index 6d55392d5a..0000000000 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ /dev/null @@ -1,1807 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Maksym Hilliaka * - * oter@frozen-team.com * - * * - * Copyright (C) 2016 by Phillip Pearson * - * pp@myelin.co.nz * - * * - * Copyright (C) 2014 by Paul Fertser * - * fercerpav@gmail.com * - * * - * Copyright (C) 2013 by mike brown * - * mike@theshedworks.org.uk * - * * - * 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 -#include "config.h" -#endif - -#include <transport/transport.h> -#include <jtag/swd.h> -#include <jtag/interface.h> -#include <jtag/commands.h> -#include <jtag/tcl.h> - -#include <hidapi.h> - -/* - * See CMSIS-DAP documentation: - * Version 0.01 - Beta. - */ - -/* USB Config */ - -/* Known vid/pid pairs: - * VID 0xc251: Keil Software - * PID 0xf001: LPC-Link-II CMSIS_DAP - * PID 0xf002: OPEN-SDA CMSIS_DAP (Freedom Board) - * PID 0x2722: Keil ULINK2 CMSIS-DAP - * - * VID 0x0d28: mbed Software - * PID 0x0204: MBED CMSIS-DAP - */ - -#define MAX_USB_IDS 8 -/* vid = pid = 0 marks the end of the list */ -static uint16_t cmsis_dap_vid[MAX_USB_IDS + 1] = { 0 }; -static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 }; -static wchar_t *cmsis_dap_serial; -static bool swd_mode; - -#define PACKET_SIZE (64 + 1) /* 64 bytes plus report id */ -#define USB_TIMEOUT 1000 - -/* CMSIS-DAP General Commands */ -#define CMD_DAP_INFO 0x00 -#define CMD_DAP_LED 0x01 -#define CMD_DAP_CONNECT 0x02 -#define CMD_DAP_DISCONNECT 0x03 -#define CMD_DAP_WRITE_ABORT 0x08 -#define CMD_DAP_DELAY 0x09 -#define CMD_DAP_RESET_TARGET 0x0A - -/* CMD_INFO */ -#define INFO_ID_VENDOR 0x01 /* string */ -#define INFO_ID_PRODUCT 0x02 /* string */ -#define INFO_ID_SERNUM 0x03 /* string */ -#define INFO_ID_FW_VER 0x04 /* string */ -#define INFO_ID_TD_VEND 0x05 /* string */ -#define INFO_ID_TD_NAME 0x06 /* string */ -#define INFO_ID_CAPS 0xf0 /* byte */ -#define INFO_ID_PKT_CNT 0xfe /* byte */ -#define INFO_ID_PKT_SZ 0xff /* short */ - -#define INFO_CAPS_SWD 0x01 -#define INFO_CAPS_JTAG 0x02 - -/* CMD_LED */ -#define LED_ID_CONNECT 0x00 -#define LED_ID_RUN 0x01 - -#define LED_OFF 0x00 -#define LED_ON 0x01 - -/* CMD_CONNECT */ -#define CONNECT_DEFAULT 0x00 -#define CONNECT_SWD 0x01 -#define CONNECT_JTAG 0x02 - -/* CMSIS-DAP Common SWD/JTAG Commands */ -#define CMD_DAP_DELAY 0x09 -#define CMD_DAP_SWJ_PINS 0x10 -#define CMD_DAP_SWJ_CLOCK 0x11 -#define CMD_DAP_SWJ_SEQ 0x12 - -/* - * PINS - * Bit 0: SWCLK/TCK - * Bit 1: SWDIO/TMS - * Bit 2: TDI - * Bit 3: TDO - * Bit 5: nTRST - * Bit 7: nRESET - */ - -#define SWJ_PIN_TCK (1<<0) -#define SWJ_PIN_TMS (1<<1) -#define SWJ_PIN_TDI (1<<2) -#define SWJ_PIN_TDO (1<<3) -#define SWJ_PIN_TRST (1<<5) -#define SWJ_PIN_SRST (1<<7) - -/* CMSIS-DAP SWD Commands */ -#define CMD_DAP_SWD_CONFIGURE 0x13 - -/* CMSIS-DAP JTAG Commands */ -#define CMD_DAP_JTAG_SEQ 0x14 -#define CMD_DAP_JTAG_CONFIGURE 0x15 -#define CMD_DAP_JTAG_IDCODE 0x16 - -/* CMSIS-DAP JTAG sequence info masks */ -/* Number of bits to clock through (0 means 64) */ -#define DAP_JTAG_SEQ_TCK 0x3F -/* TMS will be set during the sequence if this bit is set */ -#define DAP_JTAG_SEQ_TMS 0x40 -/* TDO output will be captured if this bit is set */ -#define DAP_JTAG_SEQ_TDO 0x80 - - -/* CMSIS-DAP Transfer Commands */ -#define CMD_DAP_TFER_CONFIGURE 0x04 -#define CMD_DAP_TFER 0x05 -#define CMD_DAP_TFER_BLOCK 0x06 -#define CMD_DAP_TFER_ABORT 0x07 - -/* DAP Status Code */ -#define DAP_OK 0 -#define DAP_ERROR 0xFF - -/* CMSIS-DAP Vendor Commands - * None as yet... */ - -static const char * const info_caps_str[] = { - "SWD Supported", - "JTAG Supported" -}; - -/* max clock speed (kHz) */ -#define DAP_MAX_CLOCK 5000 - -struct cmsis_dap { - hid_device *dev_handle; - uint16_t packet_size; - int packet_count; - uint8_t *packet_buffer; - uint8_t caps; - uint8_t mode; -}; - -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; - /** Number of bits to read. */ - unsigned length; - /** Location to store the result */ - uint8_t *buffer; - /** Offset in the destination buffer */ - unsigned buffer_offset; -}; - -/* Up to MIN(packet_count, MAX_PENDING_REQUESTS) requests may be issued - * until the first response arrives */ -#define MAX_PENDING_REQUESTS 3 - -/* 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; - -/* pointers to buffers that will receive jtag scan results on the next flush */ -#define MAX_PENDING_SCAN_RESULTS 256 -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) -static int queued_seq_count; -static int queued_seq_buf_end; -static int queued_seq_tdo_ptr; -static uint8_t queued_seq_buf[1024]; /* TODO: make dynamic / move into cmsis object */ - -static int queued_retval; - -static uint8_t output_pins = SWJ_PIN_SRST | SWJ_PIN_TRST; - -static struct cmsis_dap *cmsis_dap_handle; - -static int cmsis_dap_usb_open(void) -{ - hid_device *dev = NULL; - int i; - struct hid_device_info *devs, *cur_dev; - unsigned short target_vid, target_pid; - bool found = false; - - target_vid = 0; - target_pid = 0; - - if (hid_init() != 0) { - LOG_ERROR("unable to open HIDAPI"); - return ERROR_FAIL; - } - - /* - * The CMSIS-DAP specification stipulates: - * "The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the - * debuggers to identify a CMSIS-DAP compliant Debug Unit that is connected to a host computer." - */ - devs = hid_enumerate(0x0, 0x0); - cur_dev = devs; - while (NULL != cur_dev) { - if (0 == cmsis_dap_vid[0]) { - if (NULL == cur_dev->product_string) { - LOG_DEBUG("Cannot read product string of device 0x%x:0x%x", - cur_dev->vendor_id, cur_dev->product_id); - } else { - if (wcsstr(cur_dev->product_string, L"CMSIS-DAP")) { - /* if the user hasn't specified VID:PID *and* - * product string contains "CMSIS-DAP", pick it - */ - found = true; - } - } - } else { - /* otherwise, exhaustively compare against all VID:PID in list */ - for (i = 0; cmsis_dap_vid[i] || cmsis_dap_pid[i]; i++) { - if ((cmsis_dap_vid[i] == cur_dev->vendor_id) && (cmsis_dap_pid[i] == cur_dev->product_id)) - found = true; - } - - if (cmsis_dap_vid[i] || cmsis_dap_pid[i]) - found = true; - } - - /* LPC-LINK2 has cmsis-dap on interface 0 and other HID functions on other interfaces */ - if (cur_dev->vendor_id == 0x1fc9 && cur_dev->product_id == 0x0090 && cur_dev->interface_number != 0) - found = false; - - if (found) { - /* we have found an adapter, so exit further checks */ - /* check serial number matches if given */ - if (cmsis_dap_serial != NULL) { - if ((cur_dev->serial_number != NULL) && wcscmp(cmsis_dap_serial, cur_dev->serial_number) == 0) { - break; - } - } else - break; - - found = false; - } - - cur_dev = cur_dev->next; - } - - if (NULL != cur_dev) { - target_vid = cur_dev->vendor_id; - target_pid = cur_dev->product_id; - } - - if (target_vid == 0 && target_pid == 0) { - LOG_ERROR("unable to find CMSIS-DAP device"); - hid_free_enumeration(devs); - return ERROR_FAIL; - } - - dev = hid_open_path(cur_dev->path); - hid_free_enumeration(devs); - - if (dev == NULL) { - LOG_ERROR("unable to open CMSIS-DAP device 0x%x:0x%x", target_vid, target_pid); - return ERROR_FAIL; - } - - struct cmsis_dap *dap = malloc(sizeof(struct cmsis_dap)); - if (dap == NULL) { - LOG_ERROR("unable to allocate memory"); - return ERROR_FAIL; - } - - dap->dev_handle = dev; - dap->caps = 0; - dap->mode = 0; - - cmsis_dap_handle = dap; - - /* allocate default packet buffer, may be changed later. - * currently with HIDAPI we have no way of getting the output report length - * without this info we cannot communicate with the adapter. - * For the moment we ahve to hard code the packet size */ - - int packet_size = PACKET_SIZE; - - /* atmel cmsis-dap uses 512 byte reports */ - /* except when it doesn't e.g. with mEDBG on SAMD10 Xplained - * board */ - /* 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 + 1; - - cmsis_dap_handle->packet_buffer = malloc(packet_size); - cmsis_dap_handle->packet_size = packet_size; - - if (cmsis_dap_handle->packet_buffer == NULL) { - LOG_ERROR("unable to allocate memory"); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static void cmsis_dap_usb_close(struct cmsis_dap *dap) -{ - hid_close(dap->dev_handle); - hid_exit(); - - free(cmsis_dap_handle->packet_buffer); - free(cmsis_dap_handle); - cmsis_dap_handle = NULL; - free(cmsis_dap_serial); - cmsis_dap_serial = NULL; - - for (int i = 0; i < MAX_PENDING_REQUESTS; i++) { - free(pending_fifo[i].transfers); - pending_fifo[i].transfers = NULL; - } -} - -static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen) -{ -#ifdef CMSIS_DAP_JTAG_DEBUG - LOG_DEBUG("cmsis-dap usb xfer cmd=%02X", dap->packet_buffer[1]); -#endif - /* Pad the rest of the TX buffer with 0's */ - memset(dap->packet_buffer + txlen, 0, dap->packet_size - txlen); - - /* write data to device */ - int retval = hid_write(dap->dev_handle, dap->packet_buffer, dap->packet_size); - if (retval == -1) { - LOG_ERROR("error writing data: %ls", hid_error(dap->dev_handle)); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -/* Send a message and receive the reply */ -static int cmsis_dap_usb_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) { - hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, 10); - pending_fifo_block_count--; - } - pending_fifo_put_idx = 0; - pending_fifo_get_idx = 0; - } - - int retval = cmsis_dap_usb_write(dap, txlen); - if (retval != ERROR_OK) - return retval; - - /* get reply */ - retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, USB_TIMEOUT); - if (retval == -1 || retval == 0) { - LOG_DEBUG("error reading data: %ls", hid_error(dap->dev_handle)); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_SWJ_Pins(uint8_t pins, uint8_t mask, uint32_t delay, uint8_t *input) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWJ_PINS; - buffer[2] = pins; - buffer[3] = mask; - buffer[4] = delay & 0xff; - buffer[5] = (delay >> 8) & 0xff; - buffer[6] = (delay >> 16) & 0xff; - buffer[7] = (delay >> 24) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 8); - - if (retval != ERROR_OK) { - LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_PINS failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - if (input) - *input = buffer[1]; - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_SWJ_Clock(uint32_t swj_clock) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - /* set clock in Hz */ - swj_clock *= 1000; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWJ_CLOCK; - buffer[2] = swj_clock & 0xff; - buffer[3] = (swj_clock >> 8) & 0xff; - buffer[4] = (swj_clock >> 16) & 0xff; - buffer[5] = (swj_clock >> 24) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 6); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) { - LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_CLOCK failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -/* clock a sequence of bits out on TMS, to change JTAG states */ -static int cmsis_dap_cmd_DAP_SWJ_Sequence(uint8_t s_len, const uint8_t *sequence) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - -#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) - printf("%02X ", sequence[i]); - - printf("\n"); -#endif - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWJ_SEQ; - buffer[2] = s_len; - bit_copy(&buffer[3], 0, sequence, 0, s_len); - - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, DIV_ROUND_UP(s_len, 8) + 3); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) - return ERROR_FAIL; - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_INFO; - buffer[2] = info; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3); - - if (retval != ERROR_OK) { - LOG_ERROR("CMSIS-DAP command CMD_INFO failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - *data = &(buffer[1]); - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_LED(uint8_t led, uint8_t state) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_LED; - buffer[2] = led; - buffer[3] = state; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4); - - if (retval != ERROR_OK || buffer[1] != 0x00) { - LOG_ERROR("CMSIS-DAP command CMD_LED failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_Connect(uint8_t mode) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_CONNECT; - buffer[2] = mode; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3); - - if (retval != ERROR_OK) { - LOG_ERROR("CMSIS-DAP command CMD_CONNECT failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - if (buffer[1] != mode) { - LOG_ERROR("CMSIS-DAP failed to connect in mode (%d)", mode); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_Disconnect(void) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_DISCONNECT; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 2); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) { - LOG_ERROR("CMSIS-DAP command CMD_DISCONNECT failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_TFER_Configure(uint8_t idle, uint16_t retry_count, uint16_t match_retry) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_TFER_CONFIGURE; - buffer[2] = idle; - buffer[3] = retry_count & 0xff; - buffer[4] = (retry_count >> 8) & 0xff; - buffer[5] = match_retry & 0xff; - buffer[6] = (match_retry >> 8) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 7); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) { - LOG_ERROR("CMSIS-DAP command CMD_TFER_Configure failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_SWD_Configure(uint8_t cfg) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWD_CONFIGURE; - buffer[2] = cfg; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) { - LOG_ERROR("CMSIS-DAP command CMD_SWD_Configure failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -#if 0 -static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_DELAY; - buffer[2] = delay_us & 0xff; - buffer[3] = (delay_us >> 8) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) { - LOG_ERROR("CMSIS-DAP command CMD_Delay failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} -#endif - -static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) -{ - uint8_t *buffer = dap->packet_buffer; - struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx]; - - LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %d", block->transfer_count, pending_fifo_put_idx); - - if (queued_retval != ERROR_OK) { - LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); - goto skip; - } - - if (block->transfer_count == 0) - goto skip; - - size_t idx = 0; - buffer[idx++] = 0; /* report number */ - buffer[idx++] = CMD_DAP_TFER; - buffer[idx++] = 0x00; /* DAP Index */ - buffer[idx++] = block->transfer_count; - - for (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, - cmd & SWD_CMD_APnDP ? "AP" : "DP", - cmd & SWD_CMD_RnW ? "read" : "write", - (cmd & SWD_CMD_A32) >> 1, data); - - /* When proper WAIT handling is implemented in the - * common SWD framework, this kludge can be - * removed. However, this might lead to minor - * performance degradation as the adapter wouldn't be - * able to automatically retry anything (because ARM - * has forgotten to implement sticky error flags - * clearing). See also comments regarding - * cmsis_dap_cmd_DAP_TFER_Configure() and - * cmsis_dap_cmd_DAP_SWD_Configure() in - * cmsis_dap_init(). - */ - if (!(cmd & SWD_CMD_RnW) && - !(cmd & SWD_CMD_APnDP) && - (cmd & SWD_CMD_A32) >> 1 == DP_CTRL_STAT && - (data & CORUNDETECT)) { - LOG_DEBUG("refusing to enable sticky overrun detection"); - data &= ~CORUNDETECT; - } - - buffer[idx++] = (cmd >> 1) & 0x0f; - if (!(cmd & SWD_CMD_RnW)) { - buffer[idx++] = (data) & 0xff; - buffer[idx++] = (data >> 8) & 0xff; - buffer[idx++] = (data >> 16) & 0xff; - buffer[idx++] = (data >> 24) & 0xff; - } - } - - queued_retval = cmsis_dap_usb_write(dap, idx); - if (queued_retval != ERROR_OK) - goto skip; - - 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); - - return; - -skip: - block->transfer_count = 0; -} - -static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) -{ - uint8_t *buffer = dap->packet_buffer; - struct pending_request_block *block = &pending_fifo[pending_fifo_get_idx]; - - if (pending_fifo_block_count == 0) - LOG_ERROR("no pending write"); - - /* get reply */ - int retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, timeout_ms); - if (retval == 0 && timeout_ms < USB_TIMEOUT) - return; - - if (retval == -1 || retval == 0) { - LOG_DEBUG("error reading data: %ls", hid_error(dap->dev_handle)); - queued_retval = ERROR_FAIL; - goto skip; - } - - if (buffer[2] & 0x08) { - LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", buffer[1]); - queued_retval = ERROR_FAIL; - goto skip; - } - uint8_t ack = buffer[2] & 0x07; - if (ack != SWD_ACK_OK) { - LOG_DEBUG("SWD ack not OK @ %d %s", buffer[1], - ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); - queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; - goto skip; - } - - if (block->transfer_count != buffer[1]) - LOG_ERROR("CMSIS-DAP transfer count mismatch: expected %d, got %d", - block->transfer_count, buffer[1]); - - LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %d", buffer[1], pending_fifo_get_idx); - size_t idx = 3; - for (int i = 0; i < buffer[1]; i++) { - struct pending_transfer_result *transfer = &(block->transfers[i]); - if (transfer->cmd & SWD_CMD_RnW) { - static uint32_t last_read; - uint32_t data = le_to_h_u32(&buffer[idx]); - uint32_t tmp = data; - idx += 4; - - LOG_DEBUG_IO("Read result: %"PRIx32, data); - - /* Imitate posted AP reads */ - if ((transfer->cmd & SWD_CMD_APnDP) || - ((transfer->cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) { - tmp = last_read; - last_read = data; - } - - if (transfer->buffer) - *(uint32_t *)(transfer->buffer) = tmp; - } - } - -skip: - block->transfer_count = 0; - pending_fifo_get_idx = (pending_fifo_get_idx + 1) % dap->packet_count; - 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); - - cmsis_dap_swd_write_from_queue(cmsis_dap_handle); - - while (pending_fifo_block_count) - cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT); - - pending_fifo_put_idx = 0; - pending_fifo_get_idx = 0; - - int retval = queued_retval; - queued_retval = ERROR_OK; - - return retval; -} - -static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) -{ - if (pending_fifo[pending_fifo_put_idx].transfer_count == pending_queue_len) { - if (pending_fifo_block_count) - cmsis_dap_swd_read_process(cmsis_dap_handle, 0); - - /* 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, USB_TIMEOUT); - } - - if (queued_retval != ERROR_OK) - return; - - struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx]; - struct pending_transfer_result *transfer = &(block->transfers[block->transfer_count]); - transfer->data = data; - transfer->cmd = cmd; - if (cmd & SWD_CMD_RnW) { - /* Queue a read transaction */ - transfer->buffer = dst; - } - block->transfer_count++; -} - -static void cmsis_dap_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) -{ - assert(!(cmd & SWD_CMD_RnW)); - cmsis_dap_swd_queue_cmd(cmd, NULL, value); -} - -static void cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) -{ - assert(cmd & SWD_CMD_RnW); - cmsis_dap_swd_queue_cmd(cmd, value, 0); -} - -static int cmsis_dap_get_serial_info(void) -{ - uint8_t *data; - - int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_SERNUM, &data); - if (retval != ERROR_OK) - return retval; - - if (data[0]) /* strlen */ - LOG_INFO("CMSIS-DAP: Serial# = %s", &data[1]); - - return ERROR_OK; -} - -static int cmsis_dap_get_version_info(void) -{ - uint8_t *data; - - /* INFO_ID_FW_VER - string */ - int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_FW_VER, &data); - if (retval != ERROR_OK) - return retval; - - if (data[0]) /* strlen */ - LOG_INFO("CMSIS-DAP: FW Version = %s", &data[1]); - - return ERROR_OK; -} - -static int cmsis_dap_get_caps_info(void) -{ - uint8_t *data; - - /* INFO_ID_CAPS - byte */ - int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_CAPS, &data); - if (retval != ERROR_OK) - return retval; - - if (data[0] == 1) { - uint8_t caps = data[1]; - - cmsis_dap_handle->caps = caps; - - if (caps & INFO_CAPS_SWD) - LOG_INFO("CMSIS-DAP: %s", info_caps_str[0]); - if (caps & INFO_CAPS_JTAG) - LOG_INFO("CMSIS-DAP: %s", info_caps_str[1]); - } - - return ERROR_OK; -} - -static int cmsis_dap_get_status(void) -{ - uint8_t d; - - int retval = cmsis_dap_cmd_DAP_SWJ_Pins(0, 0, 0, &d); - - if (retval == ERROR_OK) { - LOG_INFO("SWCLK/TCK = %d SWDIO/TMS = %d TDI = %d TDO = %d nTRST = %d nRESET = %d", - (d & SWJ_PIN_TCK) ? 1 : 0, - (d & SWJ_PIN_TMS) ? 1 : 0, - (d & SWJ_PIN_TDI) ? 1 : 0, - (d & SWJ_PIN_TDO) ? 1 : 0, - (d & SWJ_PIN_TRST) ? 1 : 0, - (d & SWJ_PIN_SRST) ? 1 : 0); - } - - return retval; -} - -static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq) -{ - const uint8_t *s; - unsigned int s_len; - int retval; - - if ((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. */ - - /* First disconnect before connecting, Atmel EDBG needs it for SAMD/R/L/C */ - cmsis_dap_cmd_DAP_Disconnect(); - - /* When we are reconnecting, DAP_Connect needs to be rerun, at - * least on Keil ULINK-ME */ - retval = cmsis_dap_cmd_DAP_Connect(CONNECT_SWD); - if (retval != ERROR_OK) - return retval; - } - - switch (seq) { - case LINE_RESET: - LOG_DEBUG("SWD line reset"); - s = swd_seq_line_reset; - s_len = swd_seq_line_reset_len; - break; - case JTAG_TO_SWD: - LOG_DEBUG("JTAG-to-SWD"); - s = swd_seq_jtag_to_swd; - s_len = swd_seq_jtag_to_swd_len; - break; - case SWD_TO_JTAG: - LOG_DEBUG("SWD-to-JTAG"); - s = swd_seq_swd_to_jtag; - s_len = swd_seq_swd_to_jtag_len; - break; - default: - LOG_ERROR("Sequence %d not supported", seq); - return ERROR_FAIL; - } - - retval = cmsis_dap_cmd_DAP_SWJ_Sequence(s_len, s); - if (retval != ERROR_OK) - return retval; - - /* Atmel EDBG needs renew clock setting after SWJ_Sequence - * otherwise default frequency is used */ - return cmsis_dap_cmd_DAP_SWJ_Clock(jtag_get_speed_khz()); -} - -static int cmsis_dap_swd_open(void) -{ - int retval; - - if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) { - LOG_ERROR("CMSIS-DAP: SWD not supported"); - return ERROR_JTAG_DEVICE_ERROR; - } - - retval = cmsis_dap_cmd_DAP_Connect(CONNECT_SWD); - if (retval != ERROR_OK) - return retval; - - /* Add more setup here.??... */ - - LOG_INFO("CMSIS-DAP: Interface Initialised (SWD)"); - return ERROR_OK; -} - -static int cmsis_dap_init(void) -{ - int retval; - uint8_t *data; - - retval = cmsis_dap_usb_open(); - if (retval != ERROR_OK) - return retval; - - retval = cmsis_dap_get_caps_info(); - if (retval != ERROR_OK) - return retval; - - retval = cmsis_dap_get_version_info(); - if (retval != ERROR_OK) - return retval; - - retval = cmsis_dap_get_serial_info(); - if (retval != ERROR_OK) - return retval; - - if (swd_mode) { - retval = cmsis_dap_swd_open(); - if (retval != ERROR_OK) - return retval; - } else { - /* Connect in JTAG mode */ - if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) { - LOG_ERROR("CMSIS-DAP: JTAG not supported"); - return ERROR_JTAG_DEVICE_ERROR; - } - - retval = cmsis_dap_cmd_DAP_Connect(CONNECT_JTAG); - if (retval != ERROR_OK) - return retval; - - LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)"); - } - - /* 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); - if (retval != ERROR_OK) - return retval; - - if (data[0] == 2) { /* short */ - uint16_t pkt_sz = data[1] + (data[2] << 8); - - /* 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; - - if (cmsis_dap_handle->packet_size != pkt_sz + 1) { - /* reallocate buffer */ - cmsis_dap_handle->packet_size = pkt_sz + 1; - cmsis_dap_handle->packet_buffer = realloc(cmsis_dap_handle->packet_buffer, - cmsis_dap_handle->packet_size); - if (cmsis_dap_handle->packet_buffer == NULL) { - LOG_ERROR("unable to reallocate memory"); - return ERROR_FAIL; - } - } - - LOG_DEBUG("CMSIS-DAP: Packet Size = %" PRId16, pkt_sz); - } - - /* INFO_ID_PKT_CNT - byte */ - retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_CNT, &data); - if (retval != ERROR_OK) - return retval; - - if (data[0] == 1) { /* byte */ - 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("Allocating FIFO for %d pending HID requests", 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_ERROR("Unable to allocate memory for CMSIS-DAP queue"); - return ERROR_FAIL; - } - } - - - retval = cmsis_dap_get_status(); - if (retval != ERROR_OK) - return ERROR_FAIL; - - /* Now try to connect to the target - * TODO: This is all SWD only @ present */ - retval = cmsis_dap_cmd_DAP_SWJ_Clock(jtag_get_speed_khz()); - if (retval != ERROR_OK) - return ERROR_FAIL; - - /* Ask CMSIS-DAP to automatically retry on receiving WAIT for - * up to 64 times. This must be changed to 0 if sticky - * overrun detection is enabled. */ - retval = cmsis_dap_cmd_DAP_TFER_Configure(0, 64, 0); - if (retval != ERROR_OK) - return ERROR_FAIL; - - if (swd_mode) { - /* Data Phase (bit 2) must be set to 1 if sticky overrun - * detection is enabled */ - retval = cmsis_dap_cmd_DAP_SWD_Configure(0); /* 1 TRN, no Data Phase */ - if (retval != ERROR_OK) - return ERROR_FAIL; - } - /* Both LEDs on */ - retval = cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_ON); - if (retval != ERROR_OK) - return ERROR_FAIL; - - retval = cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_ON); - if (retval != ERROR_OK) - return ERROR_FAIL; - - /* support connecting with srst asserted */ - enum reset_types jtag_reset_config = jtag_get_reset_config(); - - if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { - if (jtag_reset_config & RESET_SRST_NO_GATING) { - retval = cmsis_dap_cmd_DAP_SWJ_Pins(0, SWJ_PIN_SRST, 0, NULL); - if (retval != ERROR_OK) - return ERROR_FAIL; - LOG_INFO("Connecting under reset"); - } - } - LOG_INFO("CMSIS-DAP: Interface ready"); - - return ERROR_OK; -} - -static int cmsis_dap_swd_init(void) -{ - swd_mode = true; - return ERROR_OK; -} - -static int cmsis_dap_quit(void) -{ - cmsis_dap_cmd_DAP_Disconnect(); - /* Both LEDs off */ - cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_OFF); - cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_OFF); - - cmsis_dap_usb_close(cmsis_dap_handle); - - return ERROR_OK; -} - -static int cmsis_dap_reset(int trst, int srst) -{ - /* Set both TRST and SRST even if they're not enabled as - * there's no way to tristate them */ - - output_pins = 0; - if (!srst) - output_pins |= SWJ_PIN_SRST; - if (!trst) - output_pins |= SWJ_PIN_TRST; - - int retval = cmsis_dap_cmd_DAP_SWJ_Pins(output_pins, - SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL); - if (retval != ERROR_OK) - LOG_ERROR("CMSIS-DAP: Interface reset failed"); - return retval; -} - -static void cmsis_dap_execute_sleep(struct jtag_command *cmd) -{ -#if 0 - int retval = cmsis_dap_cmd_DAP_Delay(cmd->cmd.sleep->us); - if (retval != ERROR_OK) -#endif - jtag_sleep(cmd->cmd.sleep->us); -} - -/* Set TMS high for five TCK clocks, to move the TAP to the Test-Logic-Reset state */ -static int cmsis_dap_execute_tlr_reset(struct jtag_command *cmd) -{ - LOG_INFO("cmsis-dap JTAG TLR_RESET"); - uint8_t seq = 0xff; - int ret = cmsis_dap_cmd_DAP_SWJ_Sequence(8, &seq); - if (ret == ERROR_OK) - tap_set_state(TAP_RESET); - return ret; -} - -/* Set new end state */ -static void cmsis_dap_end_state(tap_state_t state) -{ - if (tap_is_state_stable(state)) - tap_set_end_state(state); - else { - LOG_ERROR("BUG: %i is not a valid end state", state); - exit(-1); - } -} - -#ifdef SPRINT_BINARY -static void sprint_binary(char *s, const uint8_t *buf, int offset, int len) -{ - if (!len) - return; - - /* - buf = { 0x18 } len=5 should result in: 11000 - buf = { 0xff 0x18 } len=13 should result in: 11111111 11000 - 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) { - uint8_t c = buf[i / 8], mask = 1 << (i % 8); - if ((i != offset) && !(i % 8)) - putchar(' '); - *s++ = (c & mask) ? '1' : '0'; - } - *s = 0; -} -#endif - -#ifdef CMSIS_DAP_JTAG_DEBUG -static void debug_parse_cmsis_buf(const uint8_t *cmd, int cmdlen) -{ - /* cmd is a usb packet to go to the cmsis-dap interface */ - printf("cmsis-dap buffer (%d b): ", cmdlen); - for (int i = 0; i < cmdlen; ++i) - printf(" %02x", cmd[i]); - printf("\n"); - switch (cmd[1]) { - case CMD_DAP_JTAG_SEQ: { - printf("cmsis-dap jtag sequence command %02x (n=%d)\n", cmd[1], cmd[2]); - /* - * #2 = number of sequences - * #3 = sequence info 1 - * #4...4+n_bytes-1 = sequence 1 - * #4+n_bytes = sequence info 2 - * #5+n_bytes = sequence 2 (single bit) - */ - int pos = 3; - for (int seq = 0; seq < cmd[2]; ++seq) { - uint8_t info = cmd[pos++]; - int len = info & DAP_JTAG_SEQ_TCK; - if (len == 0) - len = 64; - printf(" sequence %d starting %d: info %02x (len=%d tms=%d read_tdo=%d): ", - seq, pos, info, len, info & DAP_JTAG_SEQ_TMS, info & DAP_JTAG_SEQ_TDO); - for (int i = 0; i < DIV_ROUND_UP(len, 8); ++i) - printf(" %02x", cmd[pos+i]); - pos += DIV_ROUND_UP(len, 8); - printf("\n"); - } - if (pos != cmdlen) { - printf("BUFFER LENGTH MISMATCH looks like %d but %d specified", pos, cmdlen); - exit(-1); - } - - break; - } - default: - LOG_DEBUG("unknown cmsis-dap command %02x", cmd[1]); - break; - } -} -#endif - -static void cmsis_dap_flush(void) -{ - if (!queued_seq_count) - return; - - LOG_DEBUG_IO("Flushing %d queued sequences (%d bytes) with %d pending scan results to capture", - queued_seq_count, queued_seq_buf_end, pending_scan_result_count); - - /* prep CMSIS-DAP packet */ - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_JTAG_SEQ; - buffer[2] = queued_seq_count; - memcpy(buffer + 3, queued_seq_buf, queued_seq_buf_end); - -#ifdef CMSIS_DAP_JTAG_DEBUG - debug_parse_cmsis_buf(buffer, queued_seq_buf_end + 3); -#endif - - /* send command to USB device */ - int retval = cmsis_dap_usb_xfer(cmsis_dap_handle, queued_seq_buf_end + 3); - if (retval != ERROR_OK || buffer[1] != DAP_OK) { - LOG_ERROR("CMSIS-DAP command CMD_DAP_JTAG_SEQ failed."); - exit(-1); - } - -#ifdef CMSIS_DAP_JTAG_DEBUG - LOG_DEBUG_IO("USB response buf:"); - for (int c = 0; c < queued_seq_buf_end + 3; ++c) - printf("%02X ", buffer[c]); - printf("\n"); -#endif - - /* copy scan results into client buffers */ - for (int i = 0; i < pending_scan_result_count; ++i) { - struct pending_scan_result *scan = &pending_scan_results[i]; - LOG_DEBUG_IO("Copying pending_scan_result %d/%d: %d bits from byte %d -> buffer + %d bits", - i, pending_scan_result_count, scan->length, scan->first + 2, scan->buffer_offset); -#ifdef CMSIS_DAP_JTAG_DEBUG - for (uint32_t b = 0; b < DIV_ROUND_UP(scan->length, 8); ++b) - printf("%02X ", buffer[2+scan->first+b]); - printf("\n"); -#endif - bit_copy(scan->buffer, scan->buffer_offset, buffer + 2 + scan->first, 0, scan->length); - } - - /* reset */ - queued_seq_count = 0; - queued_seq_buf_end = 0; - queued_seq_tdo_ptr = 0; - pending_scan_result_count = 0; -} - -/* queue a sequence of bits to clock out TDI / in TDO, executing if the buffer is full. - * - * 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) -{ - LOG_DEBUG_IO("[at %d] %d bits, tms %s, seq offset %d, tdo buf %p, tdo offset %d", - queued_seq_buf_end, - s_len, tms ? "HIGH" : "LOW", s_offset, tdo_buffer, tdo_buffer_offset); - - if (s_len == 0) - return; - - 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; - if (len > 64) - len = 64; - LOG_DEBUG_IO("Splitting long jtag sequence: %d-bit chunk starting at offset %d", len, offset); - cmsis_dap_add_jtag_sequence( - len, - sequence, - s_offset + offset, - tms, - tdo_buffer, - tdo_buffer == NULL ? 0 : (tdo_buffer_offset + offset) - ); - } - LOG_DEBUG_IO("END JTAG SEQ SPLIT"); - return; - } - - 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(); - - ++queued_seq_count; - - /* control byte */ - queued_seq_buf[queued_seq_buf_end] = - (tms ? DAP_JTAG_SEQ_TMS : 0) | - (tdo_buffer != NULL ? DAP_JTAG_SEQ_TDO : 0) | - (s_len == 64 ? 0 : s_len); - - if (sequence != NULL) - bit_copy(&queued_seq_buf[queued_seq_buf_end + 1], 0, sequence, s_offset, s_len); - else - memset(&queued_seq_buf[queued_seq_buf_end + 1], 0, DIV_ROUND_UP(s_len, 8)); - - queued_seq_buf_end += cmd_len; - - if (tdo_buffer != NULL) { - struct pending_scan_result *scan = &pending_scan_results[pending_scan_result_count++]; - scan->first = queued_seq_tdo_ptr; - queued_seq_tdo_ptr += DIV_ROUND_UP(s_len, 8); - scan->length = s_len; - scan->buffer = tdo_buffer; - scan->buffer_offset = tdo_buffer_offset; - } -} - -/* queue a sequence of bits to clock out TMS, executing if the buffer is full */ -static void cmsis_dap_add_tms_sequence(const uint8_t *sequence, int s_len) -{ - LOG_DEBUG_IO("%d bits: %02X", s_len, *sequence); - /* we use a series of CMD_DAP_JTAG_SEQ commands to toggle TMS, - because even though it seems ridiculously inefficient, it - allows us to combine TMS and scan sequences into the same - USB packet. */ - /* TODO: combine runs of the same tms value */ - for (int i = 0; i < s_len; ++i) { - bool bit = (sequence[i / 8] & (1 << (i % 8))) != 0; - cmsis_dap_add_jtag_sequence(1, NULL, 0, bit, NULL, 0); - } -} - -/* Move to the end state by queuing a sequence to clock into TMS */ -static void cmsis_dap_state_move(void) -{ - uint8_t tms_scan; - uint8_t tms_scan_bits; - - tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); - tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); - - LOG_DEBUG_IO("state move from %s to %s: %d clocks, %02X on tms", - tap_state_name(tap_get_state()), tap_state_name(tap_get_end_state()), - tms_scan_bits, tms_scan); - cmsis_dap_add_tms_sequence(&tms_scan, tms_scan_bits); - - tap_set_state(tap_get_end_state()); -} - - -/* Execute a JTAG scan operation by queueing TMS and TDI/TDO sequences */ -static void cmsis_dap_execute_scan(struct jtag_command *cmd) -{ - LOG_DEBUG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", - jtag_scan_type(cmd->cmd.scan)); - - /* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */ - while (cmd->cmd.scan->num_fields > 0 - && cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) { - cmd->cmd.scan->num_fields--; - LOG_DEBUG("discarding trailing empty field"); - } - - if (cmd->cmd.scan->num_fields == 0) { - LOG_DEBUG("empty scan, doing nothing"); - return; - } - - if (cmd->cmd.scan->ir_scan) { - if (tap_get_state() != TAP_IRSHIFT) { - cmsis_dap_end_state(TAP_IRSHIFT); - cmsis_dap_state_move(); - } - } else { - if (tap_get_state() != TAP_DRSHIFT) { - cmsis_dap_end_state(TAP_DRSHIFT); - cmsis_dap_state_move(); - } - } - - cmsis_dap_end_state(cmd->cmd.scan->end_state); - - struct scan_field *field = cmd->cmd.scan->fields; - unsigned scan_size = 0; - - for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { - scan_size += field->num_bits; - LOG_DEBUG_IO("%s%s field %d/%d %d bits", - field->in_value ? "in" : "", - field->out_value ? "out" : "", - i, - cmd->cmd.scan->num_fields, - field->num_bits); - - if (i == cmd->cmd.scan->num_fields - 1 && tap_get_state() != tap_get_end_state()) { - LOG_DEBUG_IO("Last field and have to move out of SHIFT state"); - /* Last field, and we're leaving IRSHIFT/DRSHIFT. Clock last bit during tap - * movement. This last field can't have length zero, it was checked above. */ - cmsis_dap_add_jtag_sequence( - field->num_bits - 1, /* number of bits to clock */ - field->out_value, /* output sequence */ - 0, /* output offset */ - false, /* TMS low */ - field->in_value, - 0); - - /* Clock the last bit out, with TMS high */ - uint8_t last_bit = 0; - if (field->out_value) - bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1); - cmsis_dap_add_jtag_sequence( - 1, - &last_bit, - 0, - true, - field->in_value, - field->num_bits - 1); - tap_set_state(tap_state_transition(tap_get_state(), 1)); - - /* Now clock one more cycle, with TMS low, to get us into a PAUSE state */ - cmsis_dap_add_jtag_sequence( - 1, - &last_bit, - 0, - false, - NULL, - 0); - tap_set_state(tap_state_transition(tap_get_state(), 0)); - } else { - LOG_DEBUG_IO("Internal field, staying in SHIFT state afterwards"); - /* Clocking part of a sequence into DR or IR with TMS=0, - leaving TMS=0 at the end so we can continue later */ - cmsis_dap_add_jtag_sequence( - field->num_bits, - field->out_value, - 0, - false, - field->in_value, - 0); - } - } - - if (tap_get_state() != tap_get_end_state()) { - cmsis_dap_end_state(tap_get_end_state()); - cmsis_dap_state_move(); - } - - LOG_DEBUG_IO("%s scan, %i bits, end in %s", - (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, - tap_state_name(tap_get_end_state())); -} - -static void cmsis_dap_pathmove(int num_states, tap_state_t *path) -{ - int i; - uint8_t tms0 = 0x00; - uint8_t tms1 = 0xff; - - for (i = 0; i < num_states; i++) { - if (path[i] == tap_state_transition(tap_get_state(), false)) - cmsis_dap_add_tms_sequence(&tms0, 1); - else if (path[i] == tap_state_transition(tap_get_state(), true)) - cmsis_dap_add_tms_sequence(&tms1, 1); - else { - LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.", - tap_state_name(tap_get_state()), tap_state_name(path[i])); - exit(-1); - } - - tap_set_state(path[i]); - } - - cmsis_dap_end_state(tap_get_state()); -} - -static void cmsis_dap_execute_pathmove(struct jtag_command *cmd) -{ - LOG_DEBUG_IO("pathmove: %i states, end in %i", - cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - - cmsis_dap_pathmove(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); -} - -static void cmsis_dap_stableclocks(int num_cycles) -{ - int i; - - uint8_t tms = tap_get_state() == TAP_RESET; - /* TODO: Perform optimizations? */ - /* Execute num_cycles. */ - for (i = 0; i < num_cycles; i++) - cmsis_dap_add_tms_sequence(&tms, 1); -} - -static void cmsis_dap_runtest(int num_cycles) -{ - tap_state_t saved_end_state = tap_get_end_state(); - - /* Only do a state_move when we're not already in IDLE. */ - if (tap_get_state() != TAP_IDLE) { - cmsis_dap_end_state(TAP_IDLE); - cmsis_dap_state_move(); - } - cmsis_dap_stableclocks(num_cycles); - - /* Finish in end_state. */ - cmsis_dap_end_state(saved_end_state); - - if (tap_get_state() != tap_get_end_state()) - cmsis_dap_state_move(); -} - -static void cmsis_dap_execute_runtest(struct jtag_command *cmd) -{ - LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); - - cmsis_dap_end_state(cmd->cmd.runtest->end_state); - cmsis_dap_runtest(cmd->cmd.runtest->num_cycles); -} - -static void cmsis_dap_execute_stableclocks(struct jtag_command *cmd) -{ - LOG_DEBUG_IO("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); - cmsis_dap_stableclocks(cmd->cmd.runtest->num_cycles); -} - -static void cmsis_dap_execute_tms(struct jtag_command *cmd) -{ - LOG_DEBUG_IO("TMS: %d bits", cmd->cmd.tms->num_bits); - cmsis_dap_cmd_DAP_SWJ_Sequence(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits); -} - -/* TODO: Is there need to call cmsis_dap_flush() for the JTAG_PATHMOVE, - * JTAG_RUNTEST, JTAG_STABLECLOCKS? */ -static void cmsis_dap_execute_command(struct jtag_command *cmd) -{ - switch (cmd->type) { - case JTAG_SLEEP: - cmsis_dap_flush(); - cmsis_dap_execute_sleep(cmd); - break; - case JTAG_TLR_RESET: - cmsis_dap_flush(); - cmsis_dap_execute_tlr_reset(cmd); - break; - case JTAG_SCAN: - cmsis_dap_execute_scan(cmd); - break; - case JTAG_PATHMOVE: - cmsis_dap_execute_pathmove(cmd); - break; - case JTAG_RUNTEST: - cmsis_dap_execute_runtest(cmd); - break; - case JTAG_STABLECLOCKS: - cmsis_dap_execute_stableclocks(cmd); - break; - case JTAG_TMS: - cmsis_dap_execute_tms(cmd); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type); - exit(-1); - } -} - -static int cmsis_dap_execute_queue(void) -{ - struct jtag_command *cmd = jtag_command_queue; - - while (cmd != NULL) { - cmsis_dap_execute_command(cmd); - cmd = cmd->next; - } - - cmsis_dap_flush(); - - return ERROR_OK; -} - -static int cmsis_dap_speed(int speed) -{ - if (speed > DAP_MAX_CLOCK) - LOG_INFO("High speed (adapter speed %d) may be limited by adapter firmware.", speed); - - if (speed == 0) { - LOG_ERROR("RTCK not supported. Set nonzero \"adapter speed\"."); - return ERROR_JTAG_NOT_IMPLEMENTED; - } - - return cmsis_dap_cmd_DAP_SWJ_Clock(speed); -} - -static int cmsis_dap_speed_div(int speed, int *khz) -{ - *khz = speed; - return ERROR_OK; -} - -static int cmsis_dap_khz(int khz, int *jtag_speed) -{ - *jtag_speed = khz; - return ERROR_OK; -} - -COMMAND_HANDLER(cmsis_dap_handle_info_command) -{ - if (cmsis_dap_get_version_info() == ERROR_OK) - cmsis_dap_get_status(); - - return ERROR_OK; -} - -COMMAND_HANDLER(cmsis_dap_handle_cmd_command) -{ - int retval; - unsigned i; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - - for (i = 0; i < CMD_ARGC; i++) - buffer[i + 1] = strtoul(CMD_ARGV[i], NULL, 16); - - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, CMD_ARGC + 1); - - if (retval != ERROR_OK) { - LOG_ERROR("CMSIS-DAP command failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - LOG_INFO("Returned data %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8, - buffer[1], buffer[2], buffer[3], buffer[4]); - - return ERROR_OK; -} - -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 " - "(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"); - if (CMD_ARGC < 2) - return ERROR_COMMAND_SYNTAX_ERROR; - /* remove the incomplete trailing id */ - CMD_ARGC -= 1; - } - - unsigned i; - for (i = 0; i < CMD_ARGC; i += 2) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], cmsis_dap_vid[i >> 1]); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], cmsis_dap_pid[i >> 1]); - } - - /* - * Explicitly terminate, in case there are multiples instances of - * cmsis_dap_vid_pid. - */ - cmsis_dap_vid[i >> 1] = cmsis_dap_pid[i >> 1] = 0; - - return ERROR_OK; -} - -COMMAND_HANDLER(cmsis_dap_handle_serial_command) -{ - if (CMD_ARGC == 1) { - size_t len = mbstowcs(NULL, CMD_ARGV[0], 0); - cmsis_dap_serial = calloc(len + 1, sizeof(wchar_t)); - if (cmsis_dap_serial == NULL) { - LOG_ERROR("unable to allocate memory"); - return ERROR_OK; - } - if (mbstowcs(cmsis_dap_serial, CMD_ARGV[0], len + 1) == (size_t)-1) { - free(cmsis_dap_serial); - cmsis_dap_serial = NULL; - LOG_ERROR("unable to convert serial"); - } - } else { - LOG_ERROR("expected exactly one argument to cmsis_dap_serial <serial-number>"); - } - - return ERROR_OK; -} - -static const struct command_registration cmsis_dap_subcommand_handlers[] = { - { - .name = "info", - .handler = &cmsis_dap_handle_info_command, - .mode = COMMAND_EXEC, - .usage = "", - .help = "show cmsis-dap info", - }, - { - .name = "cmd", - .handler = &cmsis_dap_handle_cmd_command, - .mode = COMMAND_EXEC, - .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", - .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_serial", - .handler = &cmsis_dap_handle_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the serial number of the adapter", - .usage = "serial_string", - }, - COMMAND_REGISTRATION_DONE -}; - -static const struct swd_driver cmsis_dap_swd_driver = { - .init = cmsis_dap_swd_init, - .switch_seq = cmsis_dap_swd_switch_seq, - .read_reg = cmsis_dap_swd_read_reg, - .write_reg = cmsis_dap_swd_write_reg, - .run = cmsis_dap_swd_run_queue, -}; - -static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL }; - -static struct jtag_interface cmsis_dap_interface = { - .supported = DEBUG_CAP_TMS_SEQ, - .execute_queue = cmsis_dap_execute_queue, -}; - -struct adapter_driver cmsis_dap_adapter_driver = { - .name = "cmsis-dap", - .transports = cmsis_dap_transport, - .commands = cmsis_dap_command_handlers, - - .init = cmsis_dap_init, - .quit = cmsis_dap_quit, - .reset = cmsis_dap_reset, - .speed = cmsis_dap_speed, - .khz = cmsis_dap_khz, - .speed_div = cmsis_dap_speed_div, - - .jtag_ops = &cmsis_dap_interface, - .swd_ops = &cmsis_dap_swd_driver, -}; diff --git a/src/jtag/drivers/cmsis_dap_usb_bulk.c b/src/jtag/drivers/cmsis_dap_usb_bulk.c new file mode 100644 index 0000000000..8d0cb544d7 --- /dev/null +++ b/src/jtag/drivers/cmsis_dap_usb_bulk.c @@ -0,0 +1,675 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2018 by Mickaël Thomas * + * mickael9@gmail.com * + * * + * Copyright (C) 2016 by Maksym Hilliaka * + * oter@frozen-team.com * + * * + * Copyright (C) 2016 by Phillip Pearson * + * pp@myelin.co.nz * + * * + * Copyright (C) 2014 by Paul Fertser * + * fercerpav@gmail.com * + * * + * Copyright (C) 2013 by mike brown * + * mike@theshedworks.org.uk * + * * + * Copyright (C) 2013 by Spencer Oliver * + * spen@spen-soft.co.uk * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/system.h> +#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; + struct libusb_device_handle *dev_handle; + 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) +{ + int err; + struct libusb_context *ctx; + struct libusb_device **device_list; + + err = libusb_init(&ctx); + if (err) { + LOG_ERROR("libusb initialization failed: %s", libusb_strerror(err)); + return ERROR_FAIL; + } + + int num_devices = libusb_get_device_list(ctx, &device_list); + if (num_devices < 0) { + LOG_ERROR("could not enumerate USB devices: %s", libusb_strerror(num_devices)); + libusb_exit(ctx); + return ERROR_FAIL; + } + + for (int i = 0; i < num_devices; i++) { + struct libusb_device *dev = device_list[i]; + struct libusb_device_descriptor dev_desc; + + err = libusb_get_device_descriptor(dev, &dev_desc); + if (err) { + LOG_ERROR("could not get device descriptor for device %d: %s", i, libusb_strerror(err)); + continue; + } + + /* Match VID/PID */ + + bool id_match = false; + bool id_filter = vids[0] || pids[0]; + for (int id = 0; vids[id] || pids[id]; id++) { + id_match = !vids[id] || dev_desc.idVendor == vids[id]; + id_match &= !pids[id] || dev_desc.idProduct == pids[id]; + + if (id_match) + break; + } + + if (id_filter && !id_match) + continue; + + /* Don't continue if we asked for a serial number and the device doesn't have one */ + if (dev_desc.iSerialNumber == 0 && serial && serial[0]) + continue; + + struct libusb_device_handle *dev_handle = NULL; + err = libusb_open(dev, &dev_handle); + if (err) { + /* It's to be expected that most USB devices can't be opened + * so only report an error if it was explicitly selected + */ + if (id_filter) { + LOG_ERROR("could not open device 0x%04x:0x%04x: %s", + dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); + } else { + LOG_DEBUG("could not open device 0x%04x:0x%04x: %s", + dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); + } + continue; + } + + /* Match serial number */ + + bool serial_match = false; + char dev_serial[256] = {0}; + if (dev_desc.iSerialNumber > 0) { + err = libusb_get_string_descriptor_ascii( + dev_handle, dev_desc.iSerialNumber, + (uint8_t *)dev_serial, sizeof(dev_serial)); + + if (err < 0) { + const char *msg = "could not read serial number for device 0x%04x:0x%04x: %s"; + if (serial) + LOG_WARNING(msg, dev_desc.idVendor, dev_desc.idProduct, + libusb_strerror(err)); + else + LOG_DEBUG(msg, dev_desc.idVendor, dev_desc.idProduct, + libusb_strerror(err)); + } else if (serial && strncmp(dev_serial, serial, sizeof(dev_serial)) == 0) { + serial_match = true; + } + } + + if (serial && !serial_match) { + libusb_close(dev_handle); + continue; + } + + /* Find the CMSIS-DAP string in product string */ + + bool cmsis_dap_in_product_str = false; + char product_string[256] = {0}; + if (dev_desc.iProduct > 0) { + err = libusb_get_string_descriptor_ascii( + dev_handle, dev_desc.iProduct, + (uint8_t *)product_string, sizeof(product_string)); + if (err < 0) { + LOG_WARNING("could not read product string for device 0x%04x:0x%04x: %s", + dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); + } else if (strstr(product_string, "CMSIS-DAP")) { + LOG_DEBUG("found product string of 0x%04x:0x%04x '%s'", + dev_desc.idVendor, dev_desc.idProduct, product_string); + cmsis_dap_in_product_str = true; + } + } + + bool device_identified_reliably = cmsis_dap_in_product_str + || serial_match || id_match; + + /* Find the CMSIS-DAP interface */ + + for (int config = 0; config < dev_desc.bNumConfigurations; config++) { + struct libusb_config_descriptor *config_desc; + err = libusb_get_config_descriptor(dev, config, &config_desc); + if (err) { + LOG_ERROR("could not get configuration descriptor %d for device 0x%04x:0x%04x: %s", + config, dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); + continue; + } + + LOG_DEBUG("enumerating interfaces of 0x%04x:0x%04x", + dev_desc.idVendor, dev_desc.idProduct); + int config_num = config_desc->bConfigurationValue; + const struct libusb_interface_descriptor *intf_desc_candidate = NULL; + const struct libusb_interface_descriptor *intf_desc_found = NULL; + + for (int interface = 0; interface < config_desc->bNumInterfaces; interface++) { + const struct libusb_interface_descriptor *intf_desc = &config_desc->interface[interface].altsetting[0]; + int interface_num = intf_desc->bInterfaceNumber; + + /* Skip this interface if another one was requested explicitly */ + if (cmsis_dap_usb_interface != -1 && cmsis_dap_usb_interface != interface_num) + continue; + + /* CMSIS-DAP v2 spec says: + * + * CMSIS-DAP with default V2 configuration uses WinUSB and is therefore faster. + * Optionally support for streaming SWO trace is provided via an additional USB endpoint. + * + * The WinUSB configuration requires custom class support with the interface setting + * Class Code: 0xFF (Vendor specific) + * Subclass: 0x00 + * Protocol code: 0x00 + * + * Depending on the configuration it uses the following USB endpoints which should be configured + * in the interface descriptor in this order: + * - Endpoint 1: Bulk Out – used for commands received from host PC. + * - Endpoint 2: Bulk In – used for responses send to host PC. + * - Endpoint 3: Bulk In (optional) – used for streaming SWO trace (if enabled with SWO_STREAM). + */ + + /* Search for "CMSIS-DAP" in the interface string */ + bool cmsis_dap_in_interface_str = false; + if (intf_desc->iInterface != 0) { + + char interface_str[256] = {0}; + + err = libusb_get_string_descriptor_ascii( + dev_handle, intf_desc->iInterface, + (uint8_t *)interface_str, sizeof(interface_str)); + if (err < 0) { + LOG_DEBUG("could not read interface string %d for device 0x%04x:0x%04x: %s", + intf_desc->iInterface, + dev_desc.idVendor, dev_desc.idProduct, + libusb_strerror(err)); + } else if (strstr(interface_str, "CMSIS-DAP")) { + cmsis_dap_in_interface_str = true; + LOG_DEBUG("found interface %d string '%s'", + interface_num, interface_str); + } + } + + /* Bypass the following check if this interface was explicitly requested. */ + if (cmsis_dap_usb_interface == -1) { + if (!cmsis_dap_in_product_str && !cmsis_dap_in_interface_str) + continue; + } + + /* check endpoints */ + if (intf_desc->bNumEndpoints < 2) { + LOG_DEBUG("skipping interface %d, has only %d endpoints", + interface_num, intf_desc->bNumEndpoints); + continue; + } + + if ((intf_desc->endpoint[0].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || + (intf_desc->endpoint[0].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_OUT) { + LOG_DEBUG("skipping interface %d, endpoint[0] is not bulk out", + interface_num); + continue; + } + + if ((intf_desc->endpoint[1].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || + (intf_desc->endpoint[1].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_IN) { + LOG_DEBUG("skipping interface %d, endpoint[1] is not bulk in", + interface_num); + continue; + } + + /* We can rely on the interface is really CMSIS-DAP if + * - we've seen CMSIS-DAP in the interface string + * - config asked explicitly for an interface number + * - the device has only one interface + * The later two cases should be honored only if we know + * we are on the right device */ + bool intf_identified_reliably = cmsis_dap_in_interface_str + || (device_identified_reliably && + (cmsis_dap_usb_interface != -1 + || config_desc->bNumInterfaces == 1)); + + if (intf_desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC || + intf_desc->bInterfaceSubClass != 0 || intf_desc->bInterfaceProtocol != 0) { + /* 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 && + (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, + intf_desc->bInterfaceClass, + intf_desc->bInterfaceSubClass, + intf_desc->bInterfaceProtocol); + } else { + LOG_DEBUG("skipping interface %d, class %" PRId8 + " subclass %" PRId8 " protocol %" PRId8, + interface_num, + intf_desc->bInterfaceClass, + intf_desc->bInterfaceSubClass, + intf_desc->bInterfaceProtocol); + continue; + + } + } + + if (intf_identified_reliably) { + /* That's the one! */ + intf_desc_found = intf_desc; + break; + } + + if (!intf_desc_candidate && device_identified_reliably) { + /* This interface looks suitable for CMSIS-DAP. Store the pointer to it + * and keep searching for another one with CMSIS-DAP in interface string */ + intf_desc_candidate = intf_desc; + } + } + + if (!intf_desc_found) { + /* We were not able to identify reliably which interface is CMSIS-DAP. + * Let's use the first suitable if we found one */ + intf_desc_found = intf_desc_candidate; + } + + if (!intf_desc_found) { + libusb_free_config_descriptor(config_desc); + continue; + } + + /* We've chosen an interface, connect to it */ + int interface_num = intf_desc_found->bInterfaceNumber; + int packet_size = intf_desc_found->endpoint[0].wMaxPacketSize; + int ep_out = intf_desc_found->endpoint[0].bEndpointAddress; + int ep_in = intf_desc_found->endpoint[1].bEndpointAddress; + + libusb_free_config_descriptor(config_desc); + libusb_free_device_list(device_list, true); + + LOG_INFO("Using CMSIS-DAPv2 interface with VID:PID=0x%04x:0x%04x, serial=%s", + dev_desc.idVendor, dev_desc.idProduct, dev_serial); + + int current_config; + err = libusb_get_configuration(dev_handle, ¤t_config); + if (err) { + LOG_ERROR("could not find current configuration: %s", libusb_strerror(err)); + libusb_close(dev_handle); + libusb_exit(ctx); + return ERROR_FAIL; + } + + if (config_num != current_config) { + err = libusb_set_configuration(dev_handle, config_num); + if (err) { + LOG_ERROR("could not set configuration: %s", libusb_strerror(err)); + libusb_close(dev_handle); + libusb_exit(ctx); + return ERROR_FAIL; + } + } + + err = libusb_claim_interface(dev_handle, interface_num); + if (err) + LOG_WARNING("could not claim interface: %s", libusb_strerror(err)); + + 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); + libusb_close(dev_handle); + libusb_exit(ctx); + return ERROR_FAIL; + } + + 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; + + 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; + } + } + + err = cmsis_dap_usb_alloc(dap, packet_size); + if (err != ERROR_OK) + cmsis_dap_usb_close(dap); + + return err; + } + + libusb_close(dev_handle); + } + + libusb_free_device_list(device_list, true); + + libusb_exit(ctx); + return ERROR_FAIL; +} + +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; +} + +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; + } + } + + 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; + } + + 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 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); + + 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_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 ERROR_OK; +} + +static int cmsis_dap_usb_alloc(struct cmsis_dap *dap, unsigned int pkt_sz) +{ + dap->packet_buffer = malloc(pkt_sz); + if (!dap->packet_buffer) { + LOG_ERROR("unable to allocate CMSIS-DAP packet buffer"); + return ERROR_FAIL; + } + + 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) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cmsis_dap_usb_interface); + else + LOG_ERROR("expected exactly one argument to cmsis_dap_usb_interface <interface_number>"); + + return ERROR_OK; +} + +const struct command_registration cmsis_dap_usb_subcommand_handlers[] = { + { + .name = "interface", + .handler = &cmsis_dap_handle_usb_interface_command, + .mode = COMMAND_CONFIG, + .help = "set the USB interface number to use (for USB bulk backend only)", + .usage = "<interface_number>", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct cmsis_dap_backend cmsis_dap_usb_backend = { + .name = "usb_bulk", + .open = cmsis_dap_usb_open, + .close = cmsis_dap_usb_close, + .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 new file mode 100644 index 0000000000..98ccc3e381 --- /dev/null +++ b/src/jtag/drivers/cmsis_dap_usb_hid.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2018 by Mickaël Thomas * + * mickael9@gmail.com * + * * + * Copyright (C) 2016 by Maksym Hilliaka * + * oter@frozen-team.com * + * * + * Copyright (C) 2016 by Phillip Pearson * + * pp@myelin.co.nz * + * * + * Copyright (C) 2014 by Paul Fertser * + * fercerpav@gmail.com * + * * + * Copyright (C) 2013 by mike brown * + * mike@theshedworks.org.uk * + * * + * Copyright (C) 2013 by Spencer Oliver * + * spen@spen-soft.co.uk * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <hidapi.h> +#include <helper/log.h> + +#include "cmsis_dap.h" + +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) +{ + hid_device *dev = NULL; + int i; + struct hid_device_info *devs, *cur_dev; + unsigned short target_vid, target_pid; + + target_vid = 0; + target_pid = 0; + + if (hid_init() != 0) { + LOG_ERROR("unable to open HIDAPI"); + return ERROR_FAIL; + } + + /* + * The CMSIS-DAP specification stipulates: + * "The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the + * debuggers to identify a CMSIS-DAP compliant Debug Unit that is connected to a host computer." + */ + devs = hid_enumerate(0x0, 0x0); + cur_dev = devs; + while (cur_dev) { + bool found = false; + + if (vids[0] == 0) { + if (!cur_dev->product_string) { + LOG_DEBUG("Cannot read product string of device 0x%x:0x%x", + cur_dev->vendor_id, cur_dev->product_id); + } else if (wcsstr(cur_dev->product_string, L"CMSIS-DAP")) { + /* if the user hasn't specified VID:PID *and* + * product string contains "CMSIS-DAP", pick it + */ + found = true; + } + } else { + /* otherwise, exhaustively compare against all VID:PID in list */ + for (i = 0; vids[i] || pids[i]; i++) { + if ((vids[i] == cur_dev->vendor_id) && (pids[i] == cur_dev->product_id)) + found = true; + } + } + + /* LPC-LINK2 has cmsis-dap on interface 0 and other HID functions on other interfaces */ + if (cur_dev->vendor_id == 0x1fc9 && cur_dev->product_id == 0x0090 && cur_dev->interface_number != 0) + found = false; + + if (found) { + /* check serial number matches if given */ + if (!serial) + break; + + if (cur_dev->serial_number) { + size_t len = (strlen(serial) + 1) * sizeof(wchar_t); + wchar_t *wserial = malloc(len); + mbstowcs(wserial, serial, len); + + if (wcscmp(wserial, cur_dev->serial_number) == 0) { + free(wserial); + break; + } else { + free(wserial); + wserial = NULL; + } + } + } + + cur_dev = cur_dev->next; + } + + if (cur_dev) { + target_vid = cur_dev->vendor_id; + target_pid = cur_dev->product_id; + } + + if (target_vid == 0 && target_pid == 0) { + hid_free_enumeration(devs); + return ERROR_FAIL; + } + + dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data)); + if (!dap->bdata) { + LOG_ERROR("unable to allocate memory"); + return ERROR_FAIL; + } + + dev = hid_open_path(cur_dev->path); + hid_free_enumeration(devs); + + if (!dev) { + LOG_ERROR("unable to open CMSIS-DAP device 0x%x:0x%x", target_vid, target_pid); + return ERROR_FAIL; + } + + /* allocate default packet buffer, may be changed later. + * currently with HIDAPI we have no way of getting the output report length + * without this info we cannot communicate with the adapter. + * For the moment we have to hard code the packet size */ + + unsigned int packet_size = 64; + + /* 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/PID */ + + dap->bdata->dev_handle = dev; + + int retval = cmsis_dap_hid_alloc(dap, packet_size); + if (retval != ERROR_OK) { + cmsis_dap_hid_close(dap); + return ERROR_FAIL; + } + + dap->command = dap->packet_buffer + REPORT_ID_SIZE; + dap->response = dap->packet_buffer; + return ERROR_OK; +} + +static void cmsis_dap_hid_close(struct cmsis_dap *dap) +{ + hid_close(dap->bdata->dev_handle); + hid_exit(); + free(dap->bdata); + dap->bdata = NULL; + cmsis_dap_hid_free(dap); +} + +static int cmsis_dap_hid_read(struct cmsis_dap *dap, int transfer_timeout_ms, + struct timeval *wait_timeout) +{ + 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) { + LOG_ERROR("error reading data: %ls", hid_error(dap->bdata->dev_handle)); + return ERROR_FAIL; + } + + return retval; +} + +static int cmsis_dap_hid_write(struct cmsis_dap *dap, int txlen, int timeout_ms) +{ + (void) timeout_ms; + + dap->packet_buffer[0] = 0; /* HID report number */ + + /* Pad the rest of the TX buffer with 0's */ + memset(dap->command + txlen, 0, dap->packet_size - txlen); + + /* write data to device */ + int retval = hid_write(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_buffer_size); + if (retval == -1) { + LOG_ERROR("error writing data: %ls", hid_error(dap->bdata->dev_handle)); + return ERROR_FAIL; + } + + return retval; +} + +static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz) +{ + unsigned int packet_buffer_size = pkt_sz + REPORT_ID_SIZE; + uint8_t *buf = malloc(packet_buffer_size); + if (!buf) { + LOG_ERROR("unable to allocate CMSIS-DAP packet buffer"); + return ERROR_FAIL; + } + + 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; + dap->response = dap->packet_buffer; + + 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, + .close = cmsis_dap_hid_close, + .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 4923f96eb8..e52816d3ab 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 @@ -82,21 +71,27 @@ int interface_jtag_add_ir_scan(struct jtag_tap *active, /* loop over all enabled TAPs */ - for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) { + for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap; tap = jtag_tap_next_enabled(tap)) { /* search the input field list for fields for the current TAP */ 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 */ } @@ -121,12 +116,21 @@ int interface_jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields, /* count devices in bypass */ size_t bypass_devices = 0; + size_t all_devices = 0; + + for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap; tap = jtag_tap_next_enabled(tap)) { + all_devices++; - for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) { if (tap->bypass) bypass_devices++; } + if (all_devices == bypass_devices) { + LOG_ERROR("At least one TAP shouldn't be in BYPASS mode"); + + return ERROR_FAIL; + } + struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command)); struct scan_field *out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(struct scan_field)); @@ -145,7 +149,7 @@ int interface_jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields, /* loop over all enabled TAPs */ - for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) { + for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap; tap = jtag_tap_next_enabled(tap)) { /* if TAP is not bypassed insert matching input fields */ if (!tap->bypass) { @@ -235,7 +239,7 @@ int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state struct jtag_command *cmd; cmd = cmd_queue_alloc(sizeof(struct jtag_command)); - if (cmd == NULL) + if (!cmd) return ERROR_FAIL; cmd->type = JTAG_TMS; @@ -350,7 +354,7 @@ void interface_jtag_add_callback4(jtag_callback_t callback, entry->data2 = data2; entry->data3 = data3; - if (jtag_callback_queue_head == NULL) { + if (!jtag_callback_queue_head) { jtag_callback_queue_head = entry; jtag_callback_queue_tail = entry; } else { @@ -369,7 +373,7 @@ int interface_jtag_execute_queue(void) int retval = default_interface_jtag_execute_queue(); if (retval == ERROR_OK) { struct jtag_callback_entry *entry; - for (entry = jtag_callback_queue_head; entry != NULL; entry = entry->next) { + for (entry = jtag_callback_queue_head; entry; entry = entry->next) { retval = entry->callback(entry->data0, entry->data1, entry->data2, entry->data3); if (retval != ERROR_OK) break; diff --git a/src/jtag/drivers/dummy.c b/src/jtag/drivers/dummy.c index e66cb6bd50..1b1e57392f 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 d97db56a64..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 @@ -26,6 +15,7 @@ #endif /* project specific includes */ +#include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/commands.h> #include <helper/time_support.h> @@ -68,7 +58,6 @@ #define FT232R_BUF_SIZE_EXTRA 4096 -static char *ft232r_serial_desc; static uint16_t ft232r_vid = 0x0403; /* FTDI */ static uint16_t ft232r_pid = 0x6001; /* FT232R */ static struct libusb_device_handle *adapter; @@ -170,13 +159,13 @@ static int ft232r_send_recv(void) return ERROR_OK; } -void ft232r_increase_buf_size(size_t new_buf_size) +static void ft232r_increase_buf_size(size_t new_buf_size) { uint8_t *new_buf_ptr; if (new_buf_size >= ft232r_buf_size) { new_buf_size += FT232R_BUF_SIZE_EXTRA; new_buf_ptr = realloc(ft232r_output, new_buf_size); - if (new_buf_ptr != NULL) { + if (new_buf_ptr) { ft232r_output = new_buf_ptr; ft232r_buf_size = new_buf_size; } @@ -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,9 +246,10 @@ static int ft232r_init(void) { uint16_t avids[] = {ft232r_vid, 0}; uint16_t apids[] = {ft232r_pid, 0}; - if (jtag_libusb_open(avids, apids, ft232r_serial_desc, &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 == NULL) ? "[any]" : ft232r_serial_desc); + ft232r_vid, ft232r_pid, (!ft232r_serial_desc) ? "[any]" : ft232r_serial_desc); return ERROR_JTAG_INIT_FAILED; } @@ -276,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; } @@ -285,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; } @@ -298,19 +288,19 @@ 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; } ft232r_output = malloc(ft232r_buf_size); - if (ft232r_output == NULL) { + if (!ft232r_output) { LOG_ERROR("Unable to allocate memory for the buffer"); return ERROR_JTAG_INIT_FAILED; } @@ -325,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"); } } @@ -395,16 +385,6 @@ static int ft232r_bit_name_to_number(const char *name) return -1; } -COMMAND_HANDLER(ft232r_handle_serial_desc_command) -{ - if (CMD_ARGC == 1) - ft232r_serial_desc = strdup(CMD_ARGV[0]); - else - LOG_ERROR("require exactly one argument to " - "ft232r_serial_desc <serial>"); - return ERROR_OK; -} - COMMAND_HANDLER(ft232r_handle_vid_pid_command) { if (CMD_ARGC > 2) { @@ -560,72 +540,65 @@ COMMAND_HANDLER(ft232r_handle_restore_serial_command) return ERROR_OK; } -static const struct command_registration ft232r_command_handlers[] = { +static const struct command_registration ft232r_subcommand_handlers[] = { { - .name = "ft232r_serial_desc", - .handler = ft232r_handle_serial_desc_command, - .mode = COMMAND_CONFIG, - .help = "USB serial descriptor of the adapter", - .usage = "serial string", - }, - { - .name = "ft232r_vid_pid", + .name = "vid_pid", .handler = ft232r_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "USB VID and PID of the adapter", .usage = "vid pid", }, { - .name = "ft232r_jtag_nums", + .name = "jtag_nums", .handler = ft232r_handle_jtag_nums_command, .mode = COMMAND_CONFIG, .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", .usage = "<0-7|TXD-RI> <0-7|TXD-RI> <0-7|TXD-RI> <0-7|TXD-RI>", }, { - .name = "ft232r_tck_num", + .name = "tck_num", .handler = ft232r_handle_tck_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for tck.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { - .name = "ft232r_tms_num", + .name = "tms_num", .handler = ft232r_handle_tms_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for tms.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { - .name = "ft232r_tdo_num", + .name = "tdo_num", .handler = ft232r_handle_tdo_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for tdo.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { - .name = "ft232r_tdi_num", + .name = "tdi_num", .handler = ft232r_handle_tdi_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for tdi.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { - .name = "ft232r_srst_num", + .name = "srst_num", .handler = ft232r_handle_srst_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for srst.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { - .name = "ft232r_trst_num", + .name = "trst_num", .handler = ft232r_handle_trst_num_command, .mode = COMMAND_CONFIG, .help = "gpio number for trst.", .usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>", }, { - .name = "ft232r_restore_serial", + .name = "restore_serial", .handler = ft232r_handle_restore_serial_command, .mode = COMMAND_CONFIG, .help = "bitmode control word that restores serial port.", @@ -634,6 +607,17 @@ static const struct command_registration ft232r_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration ft232r_command_handlers[] = { + { + .name = "ft232r", + .mode = COMMAND_ANY, + .help = "perform ft232r management", + .chain = ft232r_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + /* * Synchronous bitbang protocol implementation. */ @@ -819,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 4fa83ae560..58f83af592 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/>. * ***************************************************************************/ /** @@ -69,11 +58,13 @@ #endif /* project specific includes */ -#include <jtag/drivers/jtag_usb_common.h> +#include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/swd.h> #include <transport/transport.h> #include <helper/time_support.h> +#include <helper/log.h> +#include <helper/nvp.h> #if IS_CYGWIN == 1 #include <windows.h> @@ -89,7 +80,6 @@ #define SWD_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT) static char *ftdi_device_desc; -static char *ftdi_serial; static uint8_t ftdi_channel; static uint8_t ftdi_jtag_mode = JTAG_MODE; @@ -149,11 +139,11 @@ static struct signal *create_signal(const char *name) psig = &(*psig)->next; *psig = calloc(1, sizeof(**psig)); - if (*psig == NULL) + if (!*psig) return NULL; (*psig)->name = strdup(name); - if ((*psig)->name == NULL) { + if (!(*psig)->name) { free(*psig); *psig = NULL; } @@ -192,7 +182,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; } @@ -288,7 +278,7 @@ static int ftdi_speed(int speed) if (!swd_mode && speed >= 10000000 && ftdi_jtag_mode != JTAG_MODE_ALT) LOG_INFO("ftdi: if you experience problems at higher adapter clocks, try " - "the command \"ftdi_tdo_sample_edge falling\""); + "the command \"ftdi tdo_sample_edge falling\""); return ERROR_OK; } @@ -482,7 +472,11 @@ static void ftdi_execute_scan(struct jtag_command *cmd) uint8_t last_bit = 0; if (field->out_value) bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1); - uint8_t tms_bits = 0x01; + + /* If endstate is TAP_IDLE, clock out 1-1-0 (->EXIT1 ->UPDATE ->IDLE) + * Otherwise, clock out 1-0 (->EXIT1 ->PAUSE) + */ + uint8_t tms_bits = 0x03; mpsse_clock_tms_cs(mpsse_ctx, &tms_bits, 0, @@ -492,13 +486,24 @@ static void ftdi_execute_scan(struct jtag_command *cmd) last_bit, ftdi_jtag_mode); tap_set_state(tap_state_transition(tap_get_state(), 1)); - mpsse_clock_tms_cs_out(mpsse_ctx, - &tms_bits, - 1, - 1, - last_bit, - ftdi_jtag_mode); - tap_set_state(tap_state_transition(tap_get_state(), 0)); + if (tap_get_end_state() == TAP_IDLE) { + mpsse_clock_tms_cs_out(mpsse_ctx, + &tms_bits, + 1, + 2, + last_bit, + ftdi_jtag_mode); + tap_set_state(tap_state_transition(tap_get_state(), 1)); + tap_set_state(tap_state_transition(tap_get_state(), 0)); + } else { + mpsse_clock_tms_cs_out(mpsse_ctx, + &tms_bits, + 2, + 1, + last_bit, + ftdi_jtag_mode); + tap_set_state(tap_state_transition(tap_get_state(), 0)); + } } else mpsse_clock_data(mpsse_ctx, field->out_value, @@ -524,17 +529,19 @@ static int ftdi_reset(int trst, int srst) LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst); - if (trst == 1) { - if (sig_ntrst) - ftdi_set_signal(sig_ntrst, '0'); - else - LOG_ERROR("Can't assert TRST: nTRST signal is not defined"); - } else if (sig_ntrst && jtag_get_reset_config() & RESET_HAS_TRST && - trst == 0) { - if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN) - ftdi_set_signal(sig_ntrst, 'z'); - else - ftdi_set_signal(sig_ntrst, '1'); + if (!swd_mode) { + if (trst == 1) { + if (sig_ntrst) + ftdi_set_signal(sig_ntrst, '0'); + else + LOG_ERROR("Can't assert TRST: nTRST signal is not defined"); + } else if (sig_ntrst && jtag_get_reset_config() & RESET_HAS_TRST && + trst == 0) { + if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN) + ftdi_set_signal(sig_ntrst, 'z'); + else + ftdi_set_signal(sig_ntrst, '1'); + } } if (srst == 1) { @@ -618,14 +625,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); } @@ -648,17 +655,12 @@ static int ftdi_initialize(void) LOG_DEBUG("ftdi interface using shortest path jtag state transitions"); if (!ftdi_vid[0] && !ftdi_pid[0]) { - LOG_ERROR("Please specify ftdi_vid_pid"); + LOG_ERROR("Please specify ftdi vid_pid"); 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, - ftdi_serial, jtag_usb_get_location(), ftdi_channel); - if (mpsse_ctx) - break; - } - + mpsse_ctx = mpsse_open(ftdi_vid, ftdi_pid, ftdi_device_desc, + adapter_get_required_serial(), adapter_usb_get_location(), ftdi_channel); if (!mpsse_ctx) return ERROR_JTAG_INIT_FAILED; @@ -681,7 +683,7 @@ static int ftdi_initialize(void) mpsse_loopback_config(mpsse_ctx, false); - freq = mpsse_set_frequency(mpsse_ctx, jtag_get_speed_khz() * 1000); + freq = mpsse_set_frequency(mpsse_ctx, adapter_get_speed_khz() * 1000); return mpsse_flush(mpsse_ctx); } @@ -699,7 +701,6 @@ static int ftdi_quit(void) } free(ftdi_device_desc); - free(ftdi_serial); free(swd_cmd_queue); @@ -712,19 +713,7 @@ COMMAND_HANDLER(ftdi_handle_device_desc_command) free(ftdi_device_desc); ftdi_device_desc = strdup(CMD_ARGV[0]); } else { - LOG_ERROR("expected exactly one argument to ftdi_device_desc <description>"); - } - - return ERROR_OK; -} - -COMMAND_HANDLER(ftdi_handle_serial_command) -{ - if (CMD_ARGC == 1) { - free(ftdi_serial); - ftdi_serial = strdup(CMD_ARGV[0]); - } else { - return ERROR_COMMAND_SYNTAX_ERROR; + LOG_ERROR("expected exactly one argument to ftdi device_desc <description>"); } return ERROR_OK; @@ -848,7 +837,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); @@ -879,12 +868,12 @@ COMMAND_HANDLER(ftdi_handle_get_signal_command) COMMAND_HANDLER(ftdi_handle_vid_pid_command) { if (CMD_ARGC > MAX_USB_IDS * 2) { - LOG_WARNING("ignoring extra IDs in ftdi_vid_pid " + LOG_WARNING("ignoring extra IDs in ftdi 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 ftdi_vid_pid configuration directive"); + LOG_WARNING("incomplete ftdi vid_pid configuration directive"); if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* remove the incomplete trailing id */ @@ -899,7 +888,7 @@ COMMAND_HANDLER(ftdi_handle_vid_pid_command) /* * Explicitly terminate, in case there are multiples instances of - * ftdi_vid_pid. + * ftdi vid_pid. */ ftdi_vid[i >> 1] = ftdi_pid[i >> 1] = 0; @@ -908,51 +897,44 @@ COMMAND_HANDLER(ftdi_handle_vid_pid_command) COMMAND_HANDLER(ftdi_handle_tdo_sample_edge_command) { - Jim_Nvp *n; - static const 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]); - if (n->name == NULL) + 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; } -static const struct command_registration ftdi_command_handlers[] = { +static const struct command_registration ftdi_subcommand_handlers[] = { { - .name = "ftdi_device_desc", + .name = "device_desc", .handler = &ftdi_handle_device_desc_command, .mode = COMMAND_CONFIG, .help = "set the USB device description of the FTDI device", .usage = "description_string", }, { - .name = "ftdi_serial", - .handler = &ftdi_handle_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the serial number of the FTDI device", - .usage = "serial_string", - }, - { - .name = "ftdi_channel", + .name = "channel", .handler = &ftdi_handle_channel_command, .mode = COMMAND_CONFIG, .help = "set the channel of the FTDI device that is used as JTAG", .usage = "(0-3)", }, { - .name = "ftdi_layout_init", + .name = "layout_init", .handler = &ftdi_handle_layout_init_command, .mode = COMMAND_CONFIG, .help = "initialize the FTDI GPIO signals used " @@ -960,7 +942,7 @@ static const struct command_registration ftdi_command_handlers[] = { .usage = "data direction", }, { - .name = "ftdi_layout_signal", + .name = "layout_signal", .handler = &ftdi_handle_layout_signal_command, .mode = COMMAND_ANY, .help = "define a signal controlled by one or more FTDI GPIO as data " @@ -968,28 +950,28 @@ static const struct command_registration ftdi_command_handlers[] = { .usage = "name [-data mask|-ndata mask] [-oe mask|-noe mask] [-alias|-nalias name]", }, { - .name = "ftdi_set_signal", + .name = "set_signal", .handler = &ftdi_handle_set_signal_command, .mode = COMMAND_EXEC, .help = "control a layout-specific signal", .usage = "name (1|0|z)", }, { - .name = "ftdi_get_signal", + .name = "get_signal", .handler = &ftdi_handle_get_signal_command, .mode = COMMAND_EXEC, .help = "read the value of a layout-specific signal", .usage = "name", }, { - .name = "ftdi_vid_pid", + .name = "vid_pid", .handler = &ftdi_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor ID and product ID of the FTDI device", - .usage = "(vid pid)* ", + .usage = "(vid pid)*", }, { - .name = "ftdi_tdo_sample_edge", + .name = "tdo_sample_edge", .handler = &ftdi_handle_tdo_sample_edge_command, .mode = COMMAND_ANY, .help = "set which TCK clock edge is used for sampling TDO " @@ -1000,6 +982,17 @@ static const struct command_registration ftdi_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration ftdi_command_handlers[] = { + { + .name = "ftdi", + .mode = COMMAND_ANY, + .help = "perform ftdi management", + .chain = ftdi_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static int create_default_signal(const char *name, uint16_t data_mask) { struct signal *sig = create_signal(name); @@ -1039,7 +1032,7 @@ static int ftdi_swd_init(void) swd_cmd_queue_alloced = 10; swd_cmd_queue = malloc(swd_cmd_queue_alloced * sizeof(*swd_cmd_queue)); - return swd_cmd_queue != NULL ? ERROR_OK : ERROR_FAIL; + return swd_cmd_queue ? ERROR_OK : ERROR_FAIL; } static void ftdi_swd_swdio_en(bool enable) @@ -1062,7 +1055,6 @@ static void ftdi_swd_swdio_en(bool enable) /** * Flush the MPSSE queue and process the SWD transaction queue - * @param dap * @return */ static int ftdi_swd_run_queue(void) @@ -1093,19 +1085,24 @@ static int ftdi_swd_run_queue(void) for (size_t i = 0; i < swd_cmd_queue_length; i++) { int ack = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1, 3); - LOG_DEBUG_IO("%s %s %s reg %X = %08"PRIx32, + /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */ + bool check_ack = swd_cmd_returns_ack(swd_cmd_queue[i].cmd); + + LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK) ? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO, + "%s%s %s %s reg %X = %08" PRIx32, + check_ack ? "" : "ack ignored ", ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", - swd_cmd_queue[i].cmd & SWD_CMD_APnDP ? "AP" : "DP", - swd_cmd_queue[i].cmd & SWD_CMD_RnW ? "read" : "write", + swd_cmd_queue[i].cmd & SWD_CMD_APNDP ? "AP" : "DP", + swd_cmd_queue[i].cmd & SWD_CMD_RNW ? "read" : "write", (swd_cmd_queue[i].cmd & SWD_CMD_A32) >> 1, buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, - 1 + 3 + (swd_cmd_queue[i].cmd & SWD_CMD_RnW ? 0 : 1), 32)); + 1 + 3 + (swd_cmd_queue[i].cmd & SWD_CMD_RNW ? 0 : 1), 32)); - if (ack != SWD_ACK_OK) { - queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; + if (ack != SWD_ACK_OK && check_ack) { + queued_retval = swd_ack_to_error_code(ack); goto skip; - } else if (swd_cmd_queue[i].cmd & SWD_CMD_RnW) { + } else if (swd_cmd_queue[i].cmd & SWD_CMD_RNW) { uint32_t data = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3, 32); int parity = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3 + 32, 1); @@ -1115,7 +1112,7 @@ static int ftdi_swd_run_queue(void) goto skip; } - if (swd_cmd_queue[i].dst != NULL) + if (swd_cmd_queue[i].dst) *swd_cmd_queue[i].dst = data; } } @@ -1140,7 +1137,7 @@ static void ftdi_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32 * pointers into the queue which may be invalid after the realloc. */ queued_retval = ftdi_swd_run_queue(); struct swd_cmd_queue_entry *q = realloc(swd_cmd_queue, swd_cmd_queue_alloced * 2 * sizeof(*swd_cmd_queue)); - if (q != NULL) { + if (q) { swd_cmd_queue = q; swd_cmd_queue_alloced *= 2; LOG_DEBUG("Increased SWD command queue to %zu elements", swd_cmd_queue_alloced); @@ -1155,7 +1152,7 @@ static void ftdi_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32 mpsse_clock_data_out(mpsse_ctx, &swd_cmd_queue[i].cmd, 0, 8, SWD_MODE); - if (swd_cmd_queue[i].cmd & SWD_CMD_RnW) { + if (swd_cmd_queue[i].cmd & SWD_CMD_RNW) { /* Queue a read transaction */ swd_cmd_queue[i].dst = dst; @@ -1180,20 +1177,20 @@ static void ftdi_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32 } /* Insert idle cycles after AP accesses to avoid WAIT */ - if (cmd & SWD_CMD_APnDP) + if (cmd & SWD_CMD_APNDP) mpsse_clock_data_out(mpsse_ctx, NULL, 0, ap_delay_clk, SWD_MODE); } static void ftdi_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { - assert(cmd & SWD_CMD_RnW); + assert(cmd & SWD_CMD_RNW); ftdi_swd_queue_cmd(cmd, value, 0, ap_delay_clk); } static void ftdi_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { - assert(!(cmd & SWD_CMD_RnW)); + assert(!(cmd & SWD_CMD_RNW)); ftdi_swd_queue_cmd(cmd, NULL, value, ap_delay_clk); } @@ -1210,11 +1207,31 @@ static int ftdi_swd_switch_seq(enum swd_special_seq seq) ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len, SWD_MODE); break; + case JTAG_TO_DORMANT: + LOG_DEBUG("JTAG-to-DORMANT"); + ftdi_swd_swdio_en(true); + mpsse_clock_data_out(mpsse_ctx, swd_seq_jtag_to_dormant, 0, swd_seq_jtag_to_dormant_len, SWD_MODE); + break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len, SWD_MODE); break; + case SWD_TO_DORMANT: + LOG_DEBUG("SWD-to-DORMANT"); + ftdi_swd_swdio_en(true); + mpsse_clock_data_out(mpsse_ctx, swd_seq_swd_to_dormant, 0, swd_seq_swd_to_dormant_len, SWD_MODE); + break; + case DORMANT_TO_SWD: + LOG_DEBUG("DORMANT-to-SWD"); + ftdi_swd_swdio_en(true); + mpsse_clock_data_out(mpsse_ctx, swd_seq_dormant_to_swd, 0, swd_seq_dormant_to_swd_len, SWD_MODE); + break; + case DORMANT_TO_JTAG: + LOG_DEBUG("DORMANT-to-JTAG"); + ftdi_swd_swdio_en(true); + mpsse_clock_data_out(mpsse_ctx, swd_seq_dormant_to_jtag, 0, swd_seq_dormant_to_jtag_len, SWD_MODE); + break; default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c index ef4b5d929e..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 @@ -63,7 +52,7 @@ #endif /* configuration */ -uint16_t gw16012_port; +static uint16_t gw16012_port; /* interface variables */ @@ -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 57e357b79b..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 @@ -38,7 +27,8 @@ #include <jtag/interface.h> #include <jtag/swd.h> #include <jtag/commands.h> -#include <jtag/drivers/jtag_usb_common.h> +#include <jtag/adapter.h> +#include <helper/replacements.h> #include <target/cortex_m.h> #include <libjaylink/libjaylink.h> @@ -113,8 +103,6 @@ static int jlink_flush(void); * @param in A pointer to store TDO data to, if NULL the data will be discarded. * @param in_offset A bit offset for TDO data. * @param length Amount of bits to transfer out and in. - * - * @retval This function doesn't return any value. */ static void jlink_clock_data(const uint8_t *out, unsigned out_offset, const uint8_t *tms_out, unsigned tms_offset, @@ -281,19 +269,19 @@ static int jlink_execute_command(struct jtag_command *cmd) jlink_execute_sleep(cmd); break; default: - LOG_ERROR("BUG: Unknown JTAG command type encountered."); + LOG_ERROR("BUG: Unknown JTAG command type encountered"); return ERROR_JTAG_QUEUE_FAILED; } 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 != NULL) { + while (cmd) { ret = jlink_execute_command(cmd); if (ret != ERROR_OK) @@ -315,7 +303,7 @@ static int jlink_speed(int speed) ret = jaylink_get_speeds(devh, &tmp); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_speeds() failed: %s.", + LOG_ERROR("jaylink_get_speeds() failed: %s", jaylink_strerror(ret)); return ERROR_JTAG_DEVICE_ERROR; } @@ -328,13 +316,13 @@ static int jlink_speed(int speed) if (!speed) { if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING)) { - LOG_ERROR("Adaptive clocking is not supported by the device."); + LOG_ERROR("Adaptive clocking is not supported by the device"); return ERROR_JTAG_NOT_IMPLEMENTED; } speed = JAYLINK_SPEED_ADAPTIVE_CLOCKING; } else if (speed > max_speed) { - LOG_INFO("Reduced speed from %d kHz to %d kHz (maximum).", speed, + LOG_INFO("Reduced speed from %d kHz to %d kHz (maximum)", speed, max_speed); speed = max_speed; } @@ -342,7 +330,7 @@ static int jlink_speed(int speed) ret = jaylink_set_speed(devh, speed); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_set_speed() failed: %s.", + LOG_ERROR("jaylink_set_speed() failed: %s", jaylink_strerror(ret)); return ERROR_JTAG_DEVICE_ERROR; } @@ -371,7 +359,7 @@ static bool read_device_config(struct device_config *cfg) ret = jaylink_read_raw_config(devh, (uint8_t *)cfg); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_read_raw_config() failed: %s.", + LOG_ERROR("jaylink_read_raw_config() failed: %s", jaylink_strerror(ret)); return false; } @@ -392,7 +380,7 @@ static int select_interface(void) if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SELECT_TIF)) { if (iface != JAYLINK_TIF_JTAG) { - LOG_ERROR("Device supports JTAG transport only."); + LOG_ERROR("Device supports JTAG transport only"); return ERROR_JTAG_INIT_FAILED; } @@ -402,20 +390,20 @@ static int select_interface(void) ret = jaylink_get_available_interfaces(devh, &interfaces); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_available_interfaces() failed: %s.", + LOG_ERROR("jaylink_get_available_interfaces() failed: %s", jaylink_strerror(ret)); return ERROR_JTAG_INIT_FAILED; } if (!(interfaces & (1 << iface))) { - LOG_ERROR("Selected transport is not supported by the device."); + LOG_ERROR("Selected transport is not supported by the device"); return ERROR_JTAG_INIT_FAILED; } ret = jaylink_select_interface(devh, iface, NULL); if (ret < 0) { - LOG_ERROR("jaylink_select_interface() failed: %s.", + LOG_ERROR("jaylink_select_interface() failed: %s", jaylink_strerror(ret)); return ERROR_JTAG_INIT_FAILED; } @@ -436,7 +424,7 @@ static int jlink_register(void) ret = jaylink_register(devh, &conn, connlist, &count); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_register() failed: %s.", jaylink_strerror(ret)); + LOG_ERROR("jaylink_register() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -451,7 +439,7 @@ static int jlink_register(void) if (!handle_found) { LOG_ERROR("Registration failed: maximum number of connections on the " - "device reached."); + "device reached"); return ERROR_FAIL; } @@ -474,13 +462,13 @@ static bool adjust_swd_buffer_size(void) ret = jaylink_get_free_memory(devh, &tmp); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_free_memory() failed: %s.", + LOG_ERROR("jaylink_get_free_memory() failed: %s", jaylink_strerror(ret)); return false; } if (tmp < 143) { - LOG_ERROR("Not enough free device internal memory: %" PRIu32 " bytes.", tmp); + LOG_ERROR("Not enough free device internal memory: %" PRIu32 " bytes", tmp); return false; } @@ -488,7 +476,7 @@ static bool adjust_swd_buffer_size(void) if (tmp != swd_buffer_size) { swd_buffer_size = tmp; - LOG_DEBUG("Adjusted SWD transaction buffer size to %u bytes.", + LOG_DEBUG("Adjusted SWD transaction buffer size to %u bytes", swd_buffer_size); } @@ -541,100 +529,59 @@ static bool jlink_usb_location_equal(struct jaylink_device *dev) if (retval == JAYLINK_ERR_NOT_SUPPORTED) { return false; } else if (retval != JAYLINK_OK) { - LOG_WARNING("jaylink_device_get_usb_bus_ports() failed: %s.", + LOG_WARNING("jaylink_device_get_usb_bus_ports() failed: %s", jaylink_strerror(retval)); return false; } - equal = jtag_usb_location_equal(bus, ports, num_ports); + equal = adapter_usb_location_equal(bus, ports, num_ports); free(ports); return equal; } -static int jlink_init(void) +static int jlink_open_device(uint32_t ifaces, bool *found_device) { - int ret; - struct jaylink_device **devs; - unsigned int i; - bool found_device; - uint32_t tmp; - char *firmware_version; - struct jaylink_hardware_version hwver; - struct jaylink_hardware_status hwstatus; - enum jaylink_usb_address address; - size_t length; - size_t num_devices; - uint32_t host_interfaces; - - LOG_DEBUG("Using libjaylink %s (compiled with %s).", - jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING); - - if (!jaylink_library_has_cap(JAYLINK_CAP_HIF_USB) && use_usb_address) { - LOG_ERROR("J-Link driver does not support USB devices."); - return ERROR_JTAG_INIT_FAILED; - } - - ret = jaylink_init(&jayctx); - - if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_init() failed: %s.", jaylink_strerror(ret)); - return ERROR_JTAG_INIT_FAILED; - } - - ret = jaylink_log_set_callback(jayctx, &jaylink_log_handler, NULL); - - if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_log_set_callback() failed: %s.", - jaylink_strerror(ret)); - jaylink_exit(jayctx); - return ERROR_JTAG_INIT_FAILED; - } - - host_interfaces = JAYLINK_HIF_USB; - - if (use_serial_number) - host_interfaces |= JAYLINK_HIF_TCP; - - ret = jaylink_discovery_scan(jayctx, host_interfaces); - + int ret = jaylink_discovery_scan(jayctx, ifaces); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_discovery_scan() failed: %s.", - jaylink_strerror(ret)); + LOG_ERROR("jaylink_discovery_scan() failed: %s", jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } + size_t num_devices; + struct jaylink_device **devs; ret = jaylink_get_devices(jayctx, &devs, &num_devices); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_devices() failed: %s.", jaylink_strerror(ret)); + LOG_ERROR("jaylink_get_devices() failed: %s", jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } - use_usb_location = (jtag_usb_get_location() != NULL); + use_usb_location = !!adapter_usb_get_location(); if (!use_serial_number && !use_usb_address && !use_usb_location && num_devices > 1) { - LOG_ERROR("Multiple devices found, specify the desired device."); + LOG_ERROR("Multiple devices found, specify the desired device"); jaylink_free_devices(devs, true); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } - found_device = false; + *found_device = false; - for (i = 0; devs[i]; i++) { + for (size_t i = 0; devs[i]; i++) { struct jaylink_device *dev = devs[i]; if (use_serial_number) { + uint32_t tmp; ret = jaylink_device_get_serial_number(dev, &tmp); if (ret == JAYLINK_ERR_NOT_AVAILABLE) { continue; } else if (ret != JAYLINK_OK) { - LOG_WARNING("jaylink_device_get_serial_number() failed: %s.", + LOG_WARNING("jaylink_device_get_serial_number() failed: %s", jaylink_strerror(ret)); continue; } @@ -644,12 +591,13 @@ static int jlink_init(void) } if (use_usb_address) { + enum jaylink_usb_address address; ret = jaylink_device_get_usb_address(dev, &address); if (ret == JAYLINK_ERR_NOT_SUPPORTED) { continue; } else if (ret != JAYLINK_OK) { - LOG_WARNING("jaylink_device_get_usb_address() failed: %s.", + LOG_WARNING("jaylink_device_get_usb_address() failed: %s", jaylink_strerror(ret)); continue; } @@ -664,17 +612,80 @@ static int jlink_init(void) ret = jaylink_open(dev, &devh); if (ret == JAYLINK_OK) { - found_device = true; + *found_device = true; break; } - LOG_ERROR("Failed to open device: %s.", jaylink_strerror(ret)); + LOG_ERROR("Failed to open device: %s", jaylink_strerror(ret)); } jaylink_free_devices(devs, true); + return ERROR_OK; +} + + +static int jlink_init(void) +{ + int ret; + char *firmware_version; + struct jaylink_hardware_version hwver; + struct jaylink_hardware_status hwstatus; + size_t length; + + LOG_DEBUG("Using libjaylink %s (compiled with %s)", + jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING); + + if (!jaylink_library_has_cap(JAYLINK_CAP_HIF_USB) && use_usb_address) { + LOG_ERROR("J-Link driver does not support USB devices"); + return ERROR_JTAG_INIT_FAILED; + } + + ret = jaylink_init(&jayctx); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_init() failed: %s", jaylink_strerror(ret)); + return ERROR_JTAG_INIT_FAILED; + } + + ret = jaylink_log_set_callback(jayctx, &jaylink_log_handler, NULL); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_log_set_callback() failed: %s", + jaylink_strerror(ret)); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + + const char *serial = adapter_get_required_serial(); + if (serial) { + ret = jaylink_parse_serial_number(serial, &serial_number); + if (ret == JAYLINK_ERR) { + LOG_ERROR("Invalid serial number: %s", serial); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_parse_serial_number() failed: %s", jaylink_strerror(ret)); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + use_serial_number = true; + use_usb_address = false; + } + + bool found_device; + ret = jlink_open_device(JAYLINK_HIF_USB, &found_device); + if (ret != ERROR_OK) + return ret; + + if (!found_device && use_serial_number) { + ret = jlink_open_device(JAYLINK_HIF_TCP, &found_device); + if (ret != ERROR_OK) + return ret; + } if (!found_device) { - LOG_ERROR("No J-Link device found."); + LOG_ERROR("No J-Link device found"); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } @@ -687,7 +698,7 @@ static int jlink_init(void) ret = jaylink_get_firmware_version(devh, &firmware_version, &length); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_firmware_version() failed: %s.", + LOG_ERROR("jaylink_get_firmware_version() failed: %s", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); @@ -696,14 +707,14 @@ static int jlink_init(void) LOG_INFO("%s", firmware_version); free(firmware_version); } else { - LOG_WARNING("Device responds empty firmware version string."); + LOG_WARNING("Device responds empty firmware version string"); } memset(caps, 0, JAYLINK_DEV_EXT_CAPS_SIZE); ret = jaylink_get_caps(devh, caps); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_caps() failed: %s.", jaylink_strerror(ret)); + LOG_ERROR("jaylink_get_caps() failed: %s", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -713,7 +724,7 @@ static int jlink_init(void) ret = jaylink_get_extended_caps(devh, caps); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_extended_caps() failed: %s.", + LOG_ERROR("jaylink_get_extended_caps() failed: %s", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); @@ -727,7 +738,7 @@ static int jlink_init(void) ret = jaylink_get_hardware_version(devh, &hwver); if (ret != JAYLINK_OK) { - LOG_ERROR("Failed to retrieve hardware version: %s.", + LOG_ERROR("Failed to retrieve hardware version: %s", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); @@ -756,7 +767,7 @@ static int jlink_init(void) if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { if (!read_device_config(&config)) { - LOG_ERROR("Failed to read device configuration data."); + LOG_ERROR("Failed to read device configuration data"); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -768,7 +779,7 @@ static int jlink_init(void) ret = jaylink_get_hardware_status(devh, &hwstatus); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_hardware_status() failed: %s.", + LOG_ERROR("jaylink_get_hardware_status() failed: %s", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); @@ -804,7 +815,7 @@ static int jlink_init(void) jtag_sleep(3000); jlink_tap_init(); - jlink_speed(jtag_get_speed_khz()); + jlink_speed(adapter_get_speed_khz()); if (iface == JAYLINK_TIF_JTAG) { /* @@ -830,14 +841,14 @@ static int jlink_quit(void) ret = jaylink_swo_stop(devh); if (ret != JAYLINK_OK) - LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror(ret)); + LOG_ERROR("jaylink_swo_stop() failed: %s", jaylink_strerror(ret)); } if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) { ret = jaylink_unregister(devh, &conn, connlist, &count); if (ret != JAYLINK_OK) - LOG_ERROR("jaylink_unregister() failed: %s.", + LOG_ERROR("jaylink_unregister() failed: %s", jaylink_strerror(ret)); } @@ -885,7 +896,7 @@ static void jlink_path_move(int num_states, tap_state_t *path) else if (path[i] == tap_state_transition(tap_get_state(), true)) jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 1); else { - LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.", + LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } @@ -928,7 +939,7 @@ static void jlink_runtest(int num_cycles) static void jlink_reset(int trst, int srst) { - LOG_DEBUG("TRST: %i, SRST: %i.", trst, srst); + LOG_DEBUG("TRST: %i, SRST: %i", trst, srst); /* Signals are active low. */ if (srst == 0) @@ -955,55 +966,26 @@ 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; + command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); + 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; + command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } usb_address = tmp; - use_serial_number = false; use_usb_address = true; return ERROR_OK; } -COMMAND_HANDLER(jlink_serial_command) -{ - int ret; - - if (CMD_ARGC != 1) { - command_print(CMD, "Need exactly one argument for jlink serial."); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - ret = jaylink_parse_serial_number(CMD_ARGV[0], &serial_number); - - if (ret == JAYLINK_ERR) { - command_print(CMD, "Invalid serial number: %s.", CMD_ARGV[0]); - return ERROR_FAIL; - } else if (ret != JAYLINK_OK) { - command_print(CMD, "jaylink_parse_serial_number() failed: %s.", - jaylink_strerror(ret)); - return ERROR_FAIL; - } - - use_serial_number = true; - use_usb_address = false; - - return ERROR_OK; -} - COMMAND_HANDLER(jlink_handle_hwstatus_command) { int ret; @@ -1012,7 +994,7 @@ COMMAND_HANDLER(jlink_handle_hwstatus_command) ret = jaylink_get_hardware_status(devh, &status); if (ret != JAYLINK_OK) { - command_print(CMD, "jaylink_get_hardware_status() failed: %s.", + command_print(CMD, "jaylink_get_hardware_status() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1025,7 +1007,7 @@ COMMAND_HANDLER(jlink_handle_hwstatus_command) status.tres, status.trst); if (status.target_voltage < 1500) - command_print(CMD, "Target voltage too low. Check target power."); + command_print(CMD, "Target voltage too low. Check target power"); return ERROR_OK; } @@ -1037,19 +1019,19 @@ COMMAND_HANDLER(jlink_handle_free_memory_command) if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_FREE_MEMORY)) { command_print(CMD, "Retrieval of free memory is not supported by " - "the device."); + "the device"); return ERROR_OK; } ret = jaylink_get_free_memory(devh, &tmp); if (ret != JAYLINK_OK) { - command_print(CMD, "jaylink_get_free_memory() failed: %s.", + command_print(CMD, "jaylink_get_free_memory() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } - command_print(CMD, "Device has %" PRIu32 " bytes of free memory.", tmp); + command_print(CMD, "Device has %" PRIu32 " bytes of free memory", tmp); return ERROR_OK; } @@ -1074,8 +1056,8 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command) command_print(CMD, "JTAG command version: %i", version); } 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; + command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } switch (tmp) { @@ -1086,11 +1068,10 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command) jtag_command_version = JAYLINK_JTAG_VERSION_3; break; default: - command_print(CMD, "Invalid argument: %s.", CMD_ARGV[0]); - return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } } else { - command_print(CMD, "Need exactly one argument for jlink jtag."); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1102,15 +1083,12 @@ 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 " - "device."); + "device"); return ERROR_OK; } @@ -1119,14 +1097,14 @@ COMMAND_HANDLER(jlink_handle_target_power_command) } else if (!strcmp(CMD_ARGV[0], "off")) { enable = false; } else { - command_print(CMD, "Invalid argument: %s.", CMD_ARGV[0]); + command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); return ERROR_FAIL; } ret = jaylink_set_target_power(devh, enable); if (ret != JAYLINK_OK) { - command_print(CMD, "jaylink_set_target_power() failed: %s.", + command_print(CMD, "jaylink_set_target_power() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1233,7 +1211,7 @@ static int poll_trace(uint8_t *buf, size_t *size) ret = jaylink_swo_read(devh, buf, &length); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_swo_read() failed: %s.", jaylink_strerror(ret)); + LOG_ERROR("jaylink_swo_read() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1253,7 +1231,7 @@ static uint32_t calculate_trace_buffer_size(void) ret = jaylink_get_free_memory(devh, &tmp); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_free_memory() failed: %s.", + LOG_ERROR("jaylink_get_free_memory() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1269,17 +1247,14 @@ static uint32_t calculate_trace_buffer_size(void) static bool calculate_swo_prescaler(unsigned int traceclkin_freq, uint32_t trace_freq, uint16_t *prescaler) { - unsigned int presc; - double deviation; - - presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / trace_freq + 1; - - if (presc > TPIU_ACPR_MAX_SWOSCALER) + unsigned int presc = (traceclkin_freq + trace_freq / 2) / trace_freq; + if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) return false; - deviation = fabs(1.0 - ((double)trace_freq * presc / traceclkin_freq)); - - if (deviation > SWO_MAX_FREQ_DEV) + /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */ + unsigned int max_deviation = (traceclkin_freq * 3) / 100; + if (presc * trace_freq < traceclkin_freq - max_deviation || + presc * trace_freq > traceclkin_freq + max_deviation) return false; *prescaler = presc; @@ -1299,7 +1274,7 @@ static bool detect_swo_freq_and_prescaler(struct jaylink_swo_speed speed, *trace_freq = speed.freq / divider; presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / *trace_freq + 1; - if (presc > TPIU_ACPR_MAX_SWOSCALER) + if (presc > TPIU_ACPR_MAX_SWOSCALER + 1) break; deviation = fabs(1.0 - ((double)*trace_freq * presc / traceclkin_freq)); @@ -1330,14 +1305,14 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, if (!enabled) return ERROR_OK; - LOG_ERROR("Trace capturing is not supported by the device."); + LOG_ERROR("Trace capturing is not supported by the device"); return ERROR_FAIL; } ret = jaylink_swo_stop(devh); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror(ret)); + LOG_ERROR("jaylink_swo_stop() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1353,21 +1328,21 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, } if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) { - LOG_ERROR("Selected pin protocol is not supported."); + LOG_ERROR("Selected pin protocol is not supported"); return ERROR_FAIL; } buffer_size = calculate_trace_buffer_size(); if (!buffer_size) { - LOG_ERROR("Not enough free device memory to start trace capturing."); + LOG_ERROR("Not enough free device memory to start trace capturing"); return ERROR_FAIL; } ret = jaylink_swo_get_speeds(devh, JAYLINK_SWO_MODE_UART, &speed); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_swo_get_speeds() failed: %s.", + LOG_ERROR("jaylink_swo_get_speeds() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1378,49 +1353,49 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, max_freq = speed.freq / speed.min_div; if (*trace_freq > max_freq) { - LOG_INFO("Given SWO frequency too high, using %" PRIu32 " Hz instead.", + LOG_INFO("Given SWO frequency too high, using %" PRIu32 " Hz instead", max_freq); *trace_freq = max_freq; } else if (*trace_freq < min_freq) { - LOG_INFO("Given SWO frequency too low, using %" PRIu32 " Hz instead.", + LOG_INFO("Given SWO frequency too low, using %" PRIu32 " Hz instead", min_freq); *trace_freq = min_freq; } else if (*trace_freq != speed.freq / divider) { *trace_freq = speed.freq / divider; LOG_INFO("Given SWO frequency is not supported by the device, " - "using %u Hz instead.", *trace_freq); + "using %u Hz instead", *trace_freq); } if (!calculate_swo_prescaler(traceclkin_freq, *trace_freq, prescaler)) { LOG_ERROR("SWO frequency is not suitable. Please choose a " - "different frequency or use auto-detection."); + "different frequency or use auto-detection"); return ERROR_FAIL; } } else { - LOG_INFO("Trying to auto-detect SWO frequency."); + LOG_INFO("Trying to auto-detect SWO frequency"); if (!detect_swo_freq_and_prescaler(speed, traceclkin_freq, trace_freq, prescaler)) { LOG_ERROR("Maximum permitted frequency deviation of %.02f %% " - "could not be achieved.", SWO_MAX_FREQ_DEV); - LOG_ERROR("Auto-detection of SWO frequency failed."); + "could not be achieved", SWO_MAX_FREQ_DEV); + LOG_ERROR("Auto-detection of SWO frequency failed"); return ERROR_FAIL; } - LOG_INFO("Using SWO frequency of %u Hz.", *trace_freq); + LOG_INFO("Using SWO frequency of %u Hz", *trace_freq); } ret = jaylink_swo_start(devh, JAYLINK_SWO_MODE_UART, *trace_freq, buffer_size); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_start_swo() failed: %s.", jaylink_strerror(ret)); + LOG_ERROR("jaylink_start_swo() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } - LOG_DEBUG("Using %" PRIu32 " bytes device memory for trace capturing.", + LOG_DEBUG("Using %" PRIu32 " bytes device memory for trace capturing", buffer_size); /* @@ -1439,7 +1414,7 @@ COMMAND_HANDLER(jlink_handle_config_usb_address_command) if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Reading configuration is not supported by the " - "device."); + "device"); return ERROR_OK; } @@ -1447,19 +1422,17 @@ COMMAND_HANDLER(jlink_handle_config_usb_address_command) show_config_usb_address(CMD); } 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; + command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } if (tmp > JAYLINK_USB_ADDRESS_3) { - command_print(CMD, "Invalid USB address: %u.", tmp); - return ERROR_FAIL; + command_print(CMD, "Invalid USB address: %u", tmp); + 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; } @@ -1472,13 +1445,13 @@ COMMAND_HANDLER(jlink_handle_config_target_power_command) if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Reading configuration is not supported by the " - "device."); + "device"); return ERROR_OK; } if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) { command_print(CMD, "Target power supply is not supported by the " - "device."); + "device"); return ERROR_OK; } @@ -1490,14 +1463,12 @@ COMMAND_HANDLER(jlink_handle_config_target_power_command) } else if (!strcmp(CMD_ARGV[0], "off")) { enable = false; } else { - command_print(CMD, "Invalid argument: %s.", CMD_ARGV[0]); - return ERROR_FAIL; + command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); + 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; } @@ -1513,13 +1484,13 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command) if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Reading configuration is not supported by the " - "device."); + "device"); return ERROR_OK; } if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) { command_print(CMD, "Ethernet connectivity is not supported by the " - "device."); + "device"); return ERROR_OK; } @@ -1530,8 +1501,8 @@ 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; + command_print(CMD, "Invalid MAC address format"); + return ERROR_COMMAND_ARGUMENT_INVALID; } for (i = 5; i >= 0; i--) { @@ -1540,19 +1511,17 @@ 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; + command_print(CMD, "Invalid MAC address: zero address"); + return ERROR_COMMAND_ARGUMENT_INVALID; } if (!(0x01 & addr[0])) { - command_print(CMD, "Invalid MAC address: multicast address."); - return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "Invalid MAC address: multicast address"); + 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; } @@ -1601,33 +1570,39 @@ COMMAND_HANDLER(jlink_handle_config_ip_address_command) if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Reading configuration is not supported by the " - "device."); + "device"); return ERROR_OK; } if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) { command_print(CMD, "Ethernet connectivity is not supported by the " - "device."); + "device"); return ERROR_OK; } 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) @@ -1658,44 +1633,44 @@ COMMAND_HANDLER(jlink_handle_config_write_command) if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Reading configuration is not supported by the " - "device."); + "device"); return ERROR_OK; } if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_WRITE_CONFIG)) { command_print(CMD, "Writing configuration is not supported by the " - "device."); + "device"); return ERROR_OK; } if (!memcmp(&config, &tmp_config, sizeof(struct device_config))) { command_print(CMD, "Operation not performed due to no changes in " - "the configuration."); + "the configuration"); return ERROR_OK; } ret = jaylink_write_raw_config(devh, (const uint8_t *)&tmp_config); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_write_raw_config() failed: %s.", + LOG_ERROR("jaylink_write_raw_config() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } if (!read_device_config(&config)) { - LOG_ERROR("Failed to read device configuration for verification."); + LOG_ERROR("Failed to read device configuration for verification"); return ERROR_FAIL; } if (memcmp(&config, &tmp_config, sizeof(struct device_config))) { LOG_ERROR("Verification of device configuration failed. Please check " - "your device."); + "your device"); return ERROR_FAIL; } memcpy(&tmp_config, &config, sizeof(struct device_config)); command_print(CMD, "The new device configuration applies after power " - "cycling the J-Link device."); + "cycling the J-Link device"); return ERROR_OK; } @@ -1703,7 +1678,7 @@ COMMAND_HANDLER(jlink_handle_config_write_command) COMMAND_HANDLER(jlink_handle_config_command) { if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { - command_print(CMD, "Device doesn't support reading configuration."); + command_print(CMD, "Device doesn't support reading configuration"); return ERROR_OK; } @@ -1726,7 +1701,7 @@ COMMAND_HANDLER(jlink_handle_emucom_write_command) return ERROR_COMMAND_SYNTAX_ERROR; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) { - LOG_ERROR("Device does not support EMUCOM."); + LOG_ERROR("Device does not support EMUCOM"); return ERROR_FAIL; } @@ -1735,21 +1710,21 @@ COMMAND_HANDLER(jlink_handle_emucom_write_command) tmp = strlen(CMD_ARGV[1]); if (tmp % 2 != 0) { - LOG_ERROR("Data must be encoded as hexadecimal pairs."); + LOG_ERROR("Data must be encoded as hexadecimal pairs"); return ERROR_COMMAND_ARGUMENT_INVALID; } buf = malloc(tmp / 2); if (!buf) { - LOG_ERROR("Failed to allocate buffer."); + LOG_ERROR("Failed to allocate buffer"); return ERROR_FAIL; } dummy = unhexify(buf, CMD_ARGV[1], tmp / 2); if (dummy != (tmp / 2)) { - LOG_ERROR("Data must be encoded as hexadecimal pairs."); + LOG_ERROR("Data must be encoded as hexadecimal pairs"); free(buf); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -1760,15 +1735,15 @@ COMMAND_HANDLER(jlink_handle_emucom_write_command) free(buf); if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) { - LOG_ERROR("Channel not supported by the device."); + LOG_ERROR("Channel not supported by the device"); return ERROR_FAIL; } else if (ret != JAYLINK_OK) { - LOG_ERROR("Failed to write to channel: %s.", jaylink_strerror(ret)); + LOG_ERROR("Failed to write to channel: %s", jaylink_strerror(ret)); return ERROR_FAIL; } if (length != (tmp / 2)) - LOG_WARNING("Only %" PRIu32 " bytes written to the channel.", length); + LOG_WARNING("Only %" PRIu32 " bytes written to the channel", length); return ERROR_OK; } @@ -1785,7 +1760,7 @@ COMMAND_HANDLER(jlink_handle_emucom_read_command) return ERROR_COMMAND_SYNTAX_ERROR; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) { - LOG_ERROR("Device does not support EMUCOM."); + LOG_ERROR("Device does not support EMUCOM"); return ERROR_FAIL; } @@ -1795,23 +1770,23 @@ COMMAND_HANDLER(jlink_handle_emucom_read_command) buf = malloc(length * 3 + 1); if (!buf) { - LOG_ERROR("Failed to allocate buffer."); + LOG_ERROR("Failed to allocate buffer"); return ERROR_FAIL; } ret = jaylink_emucom_read(devh, channel, buf, &length); if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) { - LOG_ERROR("Channel is not supported by the device."); + LOG_ERROR("Channel is not supported by the device"); free(buf); return ERROR_FAIL; } else if (ret == JAYLINK_ERR_DEV_NOT_AVAILABLE) { LOG_ERROR("Channel is not available for the requested amount of data. " - "%" PRIu32 " bytes are available.", length); + "%" PRIu32 " bytes are available", length); free(buf); return ERROR_FAIL; } else if (ret != JAYLINK_OK) { - LOG_ERROR("Failed to read from channel: %s.", jaylink_strerror(ret)); + LOG_ERROR("Failed to read from channel: %s", jaylink_strerror(ret)); free(buf); return ERROR_FAIL; } @@ -1819,7 +1794,7 @@ COMMAND_HANDLER(jlink_handle_emucom_read_command) tmp = hexify((char *)buf + length, buf, length, 2 * length + 1); if (tmp != 2 * length) { - LOG_ERROR("Failed to convert data into hexadecimal string."); + LOG_ERROR("Failed to convert data into hexadecimal string"); free(buf); return ERROR_FAIL; } @@ -1931,13 +1906,6 @@ static const struct command_registration jlink_subcommand_handlers[] = { .help = "set the USB address of the device that should be used", .usage = "<0-3>" }, - { - .name = "serial", - .handler = &jlink_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the serial number of the device that should be used", - .usage = "<serial number>" - }, { .name = "config", .handler = &jlink_handle_config_command, @@ -1977,13 +1945,13 @@ static int jlink_swd_init(void) static void jlink_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { - assert(!(cmd & SWD_CMD_RnW)); + assert(!(cmd & SWD_CMD_RNW)); jlink_swd_queue_cmd(cmd, NULL, value, ap_delay_clk); } static void jlink_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { - assert(cmd & SWD_CMD_RnW); + assert(cmd & SWD_CMD_RNW); jlink_swd_queue_cmd(cmd, value, 0, ap_delay_clk); } @@ -2005,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 @@ -2077,7 +2047,7 @@ static int jlink_flush(void) tap_length, jtag_command_version); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_jtag_io() failed: %s.", jaylink_strerror(ret)); + LOG_ERROR("jaylink_jtag_io() failed: %s", jaylink_strerror(ret)); jlink_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } @@ -2088,7 +2058,7 @@ static int jlink_flush(void) buf_set_buf(tdo_buffer, p->first, p->buffer, p->buffer_offset, p->length); - LOG_DEBUG_IO("Pending scan result, length = %d.", p->length); + LOG_DEBUG_IO("Pending scan result, length = %d", p->length); } jlink_tap_init(); @@ -2138,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; @@ -2147,13 +2117,33 @@ static int jlink_swd_switch_seq(enum swd_special_seq seq) s = swd_seq_jtag_to_swd; s_len = swd_seq_jtag_to_swd_len; break; + case JTAG_TO_DORMANT: + LOG_DEBUG("JTAG-to-DORMANT"); + s = swd_seq_jtag_to_dormant; + s_len = swd_seq_jtag_to_dormant_len; + break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); s = swd_seq_swd_to_jtag; s_len = swd_seq_swd_to_jtag_len; break; + case SWD_TO_DORMANT: + LOG_DEBUG("SWD-to-DORMANT"); + s = swd_seq_swd_to_dormant; + s_len = swd_seq_swd_to_dormant_len; + break; + case DORMANT_TO_SWD: + LOG_DEBUG("DORMANT-to-SWD"); + s = swd_seq_dormant_to_swd; + s_len = swd_seq_dormant_to_swd_len; + break; + case DORMANT_TO_JTAG: + LOG_DEBUG("DORMANT-to-JTAG"); + s = swd_seq_dormant_to_jtag; + s_len = swd_seq_dormant_to_jtag_len; + break; default: - LOG_ERROR("Sequence %d not supported.", seq); + LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; } @@ -2167,10 +2157,10 @@ 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); + LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); goto skip; } @@ -2183,24 +2173,25 @@ static int jlink_swd_run_queue(void) ret = jaylink_swd_io(devh, tms_buffer, tdi_buffer, tdo_buffer, tap_length); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_swd_io() failed: %s.", jaylink_strerror(ret)); + LOG_ERROR("jaylink_swd_io() failed: %s", jaylink_strerror(ret)); goto skip; } 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); int parity = buf_get_u32(tdo_buffer, 3 + 32 + pending_scan_results_buffer[i].first, 1); if (parity != parity_u32(data)) { - LOG_ERROR("SWD: Read data parity mismatch."); + LOG_ERROR("SWD: Read data parity mismatch"); queued_retval = ERROR_FAIL; goto skip; } @@ -2230,13 +2221,14 @@ 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); pending_scan_results_buffer[pending_scan_results_length].first = tap_length; - if (cmd & SWD_CMD_RnW) { + if (cmd & SWD_CMD_RNW) { /* Queue a read transaction. */ pending_scan_results_buffer[pending_scan_results_length].length = 32; pending_scan_results_buffer[pending_scan_results_length].buffer = dst; @@ -2256,7 +2248,7 @@ static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint3 pending_scan_results_length++; /* Insert idle cycles after AP accesses to avoid WAIT. */ - if (cmd & SWD_CMD_APnDP) + if (cmd & SWD_CMD_APNDP) jlink_queue_data_out(NULL, ap_delay_clk); } diff --git a/src/jtag/drivers/jtag_dpi.c b/src/jtag/drivers/jtag_dpi.c new file mode 100644 index 0000000000..285f96e4bf --- /dev/null +++ b/src/jtag/drivers/jtag_dpi.c @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * JTAG to DPI driver + * + * Copyright (C) 2013 Franck Jullien, <elec4fun@gmail.com> + * + * Copyright (C) 2019-2020, Ampere Computing LLC + * + * See file CREDITS for list of people who contributed to this + * project. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <jtag/interface.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#ifndef _WIN32 +#include <netinet/tcp.h> +#endif + +#define SERVER_ADDRESS "127.0.0.1" +#define SERVER_PORT 5555 + +static uint16_t server_port = SERVER_PORT; +static char *server_address; + +static int sockfd; +static struct sockaddr_in serv_addr; + +static uint8_t *last_ir_buf; +static int last_ir_num_bits; + +static int write_sock(char *buf, size_t len) +{ + if (!buf) { + LOG_ERROR("%s: NULL 'buf' argument, file %s, line %d", + __func__, __FILE__, __LINE__); + return ERROR_FAIL; + } + if (write(sockfd, buf, len) != (ssize_t)len) { + LOG_ERROR("%s: %s, file %s, line %d", __func__, + strerror(errno), __FILE__, __LINE__); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int read_sock(char *buf, size_t len) +{ + if (!buf) { + LOG_ERROR("%s: NULL 'buf' argument, file %s, line %d", + __func__, __FILE__, __LINE__); + return ERROR_FAIL; + } + if (read(sockfd, buf, len) != (ssize_t)len) { + LOG_ERROR("%s: %s, file %s, line %d", __func__, + strerror(errno), __FILE__, __LINE__); + return ERROR_FAIL; + } + return ERROR_OK; +} + +/** + * jtag_dpi_reset - ask to reset the JTAG device + * @param trst 1 if TRST is to be asserted + * @param srst 1 if SRST is to be asserted + */ +static int jtag_dpi_reset(int trst, int srst) +{ + char *buf = "reset\n"; + int ret = ERROR_OK; + + LOG_DEBUG_IO("JTAG DRIVER DEBUG: reset trst: %i srst %i", trst, srst); + + if (trst == 1) { + /* reset the JTAG TAP controller */ + ret = write_sock(buf, strlen(buf)); + if (ret != ERROR_OK) { + LOG_ERROR("write_sock() fail, file %s, line %d", + __FILE__, __LINE__); + } + } + + if (srst == 1) { + /* System target reset not supported */ + LOG_ERROR("DPI SRST not supported"); + ret = ERROR_FAIL; + } + + return ret; +} + +/** + * jtag_dpi_scan - launches a DR-scan or IR-scan + * @param cmd the command to launch + * + * Launch a JTAG IR-scan or DR-scan + * + * Returns ERROR_OK if OK, ERROR_xxx if a read/write error occurred. + */ +static int jtag_dpi_scan(struct scan_command *cmd) +{ + char buf[20]; + uint8_t *data_buf; + int num_bits, bytes; + int ret = ERROR_OK; + + num_bits = jtag_build_buffer(cmd, &data_buf); + if (!data_buf) { + LOG_ERROR("jtag_build_buffer call failed, data_buf == NULL, " + "file %s, line %d", __FILE__, __LINE__); + return ERROR_FAIL; + } + + bytes = DIV_ROUND_UP(num_bits, 8); + if (cmd->ir_scan) { + free(last_ir_buf); + last_ir_buf = (uint8_t *)malloc(bytes * sizeof(uint8_t)); + if (!last_ir_buf) { + LOG_ERROR("%s: malloc fail, file %s, line %d", + __func__, __FILE__, __LINE__); + ret = ERROR_FAIL; + goto out; + } + memcpy(last_ir_buf, data_buf, bytes); + last_ir_num_bits = num_bits; + } + snprintf(buf, sizeof(buf), "%s %d\n", cmd->ir_scan ? "ib" : "db", num_bits); + ret = write_sock(buf, strlen(buf)); + if (ret != ERROR_OK) { + LOG_ERROR("write_sock() fail, file %s, line %d", + __FILE__, __LINE__); + goto out; + } + ret = write_sock((char *)data_buf, bytes); + if (ret != ERROR_OK) { + LOG_ERROR("write_sock() fail, file %s, line %d", + __FILE__, __LINE__); + goto out; + } + ret = read_sock((char *)data_buf, bytes); + if (ret != ERROR_OK) { + LOG_ERROR("read_sock() fail, file %s, line %d", + __FILE__, __LINE__); + goto out; + } + + ret = jtag_read_buffer(data_buf, cmd); + if (ret != ERROR_OK) { + LOG_ERROR("jtag_read_buffer() fail, file %s, line %d", + __FILE__, __LINE__); + goto out; + } + +out: + free(data_buf); + return ret; +} + +static int jtag_dpi_runtest(int cycles) +{ + char buf[20]; + uint8_t *data_buf = last_ir_buf, *read_scan; + int num_bits = last_ir_num_bits, bytes; + int ret = ERROR_OK; + + if (!data_buf) { + LOG_ERROR("%s: NULL 'data_buf' argument, file %s, line %d", + __func__, __FILE__, __LINE__); + return ERROR_FAIL; + } + if (num_bits <= 0) { + LOG_ERROR("%s: 'num_bits' invalid value, file %s, line %d", + __func__, __FILE__, __LINE__); + return ERROR_FAIL; + } + + bytes = DIV_ROUND_UP(num_bits, 8); + read_scan = (uint8_t *)malloc(bytes * sizeof(uint8_t)); + if (!read_scan) { + LOG_ERROR("%s: malloc fail, file %s, line %d", + __func__, __FILE__, __LINE__); + return ERROR_FAIL; + } + snprintf(buf, sizeof(buf), "ib %d\n", num_bits); + while (cycles > 0) { + ret = write_sock(buf, strlen(buf)); + if (ret != ERROR_OK) { + LOG_ERROR("write_sock() fail, file %s, line %d", + __FILE__, __LINE__); + goto out; + } + ret = write_sock((char *)data_buf, bytes); + if (ret != ERROR_OK) { + LOG_ERROR("write_sock() fail, file %s, line %d", + __FILE__, __LINE__); + goto out; + } + ret = read_sock((char *)read_scan, bytes); + if (ret != ERROR_OK) { + LOG_ERROR("read_sock() fail, file %s, line %d", + __FILE__, __LINE__); + goto out; + } + + cycles -= num_bits + 6; + } + +out: + free(read_scan); + return ret; +} + +static int jtag_dpi_stableclocks(int cycles) +{ + return jtag_dpi_runtest(cycles); +} + +static int jtag_dpi_execute_queue(struct jtag_command *cmd_queue) +{ + struct jtag_command *cmd; + int ret = ERROR_OK; + + for (cmd = cmd_queue; ret == ERROR_OK && cmd; + cmd = cmd->next) { + switch (cmd->type) { + case JTAG_RUNTEST: + ret = jtag_dpi_runtest(cmd->cmd.runtest->num_cycles); + break; + case JTAG_STABLECLOCKS: + ret = jtag_dpi_stableclocks(cmd->cmd.stableclocks->num_cycles); + break; + case JTAG_TLR_RESET: + /* Enter Test-Logic-Reset state by asserting TRST */ + if (cmd->cmd.statemove->end_state == TAP_RESET) + jtag_dpi_reset(1, 0); + break; + case JTAG_PATHMOVE: + /* unsupported */ + break; + case JTAG_TMS: + /* unsupported */ + break; + case JTAG_SLEEP: + jtag_sleep(cmd->cmd.sleep->us); + break; + case JTAG_SCAN: + ret = jtag_dpi_scan(cmd->cmd.scan); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%X", + cmd->type); + ret = ERROR_FAIL; + break; + } + } + + return ret; +} + +static int jtag_dpi_init(void) +{ + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + LOG_ERROR("socket: %s, function %s, file %s, line %d", + strerror(errno), __func__, __FILE__, __LINE__); + return ERROR_FAIL; + } + + memset(&serv_addr, 0, sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(server_port); + + if (!server_address) { + server_address = strdup(SERVER_ADDRESS); + if (!server_address) { + LOG_ERROR("%s: strdup fail, file %s, line %d", + __func__, __FILE__, __LINE__); + return ERROR_FAIL; + } + } + + serv_addr.sin_addr.s_addr = inet_addr(server_address); + + if (serv_addr.sin_addr.s_addr == INADDR_NONE) { + LOG_ERROR("inet_addr error occurred"); + return ERROR_FAIL; + } + + if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + close(sockfd); + LOG_ERROR("Can't connect to %s : %" PRIu16, server_address, server_port); + return ERROR_FAIL; + } + if (serv_addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { + /* This increases performance dramatically for local + * connections, which is the most likely arrangement + * for a DPI connection. */ + int flag = 1; + setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)); + } + + LOG_INFO("Connection to %s : %" PRIu16 " succeed", server_address, server_port); + + return ERROR_OK; +} + +static int jtag_dpi_quit(void) +{ + free(server_address); + server_address = NULL; + + return close(sockfd); +} + +COMMAND_HANDLER(jtag_dpi_set_port) +{ + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + else if (CMD_ARGC == 0) + LOG_INFO("Using server port %" PRIu16, server_port); + else { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], server_port); + LOG_INFO("Set server port to %" PRIu16, server_port); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(jtag_dpi_set_address) +{ + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + else if (CMD_ARGC == 0) { + if (!server_address) { + server_address = strdup(SERVER_ADDRESS); + if (!server_address) { + LOG_ERROR("%s: strdup fail, file %s, line %d", + __func__, __FILE__, __LINE__); + return ERROR_FAIL; + } + } + LOG_INFO("Using server address %s", server_address); + } else { + free(server_address); + server_address = strdup(CMD_ARGV[0]); + if (!server_address) { + LOG_ERROR("%s: strdup fail, file %s, line %d", + __func__, __FILE__, __LINE__); + return ERROR_FAIL; + } + LOG_INFO("Set server address to %s", server_address); + } + + return ERROR_OK; +} + +static const struct command_registration jtag_dpi_subcommand_handlers[] = { + { + .name = "set_port", + .handler = &jtag_dpi_set_port, + .mode = COMMAND_CONFIG, + .help = "set the port of the DPI server", + .usage = "[port]", + }, + { + .name = "set_address", + .handler = &jtag_dpi_set_address, + .mode = COMMAND_CONFIG, + .help = "set the address of the DPI server", + .usage = "[address]", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration jtag_dpi_command_handlers[] = { + { + .name = "jtag_dpi", + .mode = COMMAND_ANY, + .help = "perform jtag_dpi management", + .chain = jtag_dpi_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static struct jtag_interface jtag_dpi_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = jtag_dpi_execute_queue, +}; + +struct adapter_driver jtag_dpi_adapter_driver = { + .name = "jtag_dpi", + .transports = jtag_only, + .commands = jtag_dpi_command_handlers, + .init = jtag_dpi_init, + .quit = jtag_dpi_quit, + .reset = jtag_dpi_reset, + .jtag_ops = &jtag_dpi_interface, +}; diff --git a/src/jtag/drivers/jtag_usb_common.c b/src/jtag/drivers/jtag_usb_common.c deleted file mode 100644 index 969ea84062..0000000000 --- a/src/jtag/drivers/jtag_usb_common.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-2.0+ - * Copyright (c) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> - */ - -#include <helper/log.h> - -#include "jtag_usb_common.h" - -static char *jtag_usb_location; -/* - * 1 char: bus - * 2 * 7 chars: max 7 ports - * 1 char: test for overflow - * ------ - * 16 chars - */ -#define JTAG_USB_MAX_LOCATION_LENGTH 16 - -void jtag_usb_set_location(const char *location) -{ - if (strnlen(location, JTAG_USB_MAX_LOCATION_LENGTH) == - JTAG_USB_MAX_LOCATION_LENGTH) - LOG_WARNING("usb location string is too long!!\n"); - - free(jtag_usb_location); - - jtag_usb_location = strndup(location, JTAG_USB_MAX_LOCATION_LENGTH); -} - -const char *jtag_usb_get_location(void) -{ - return jtag_usb_location; -} - -bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, - size_t path_len) -{ - size_t path_step, string_length; - char *ptr, *loc; - bool equal = false; - - /* strtok need non const char */ - loc = strndup(jtag_usb_get_location(), JTAG_USB_MAX_LOCATION_LENGTH); - string_length = strnlen(loc, JTAG_USB_MAX_LOCATION_LENGTH); - - ptr = strtok(loc, "-"); - if (ptr == NULL) { - LOG_WARNING("no '-' in usb path\n"); - goto done; - } - - string_length -= 1; - /* check bus mismatch */ - if (atoi(ptr) != dev_bus) - goto done; - - path_step = 0; - while (path_step < path_len) { - ptr = strtok(NULL, "."); - - /* no more tokens in path */ - if (ptr == NULL) - break; - - /* path mismatch at some step */ - if (path_step < path_len && atoi(ptr) != port_path[path_step]) - break; - - path_step++; - string_length -= 2; - }; - - /* walked the full path, all elements match */ - if (path_step == path_len && !string_length) - equal = true; - -done: - free(loc); - return equal; -} diff --git a/src/jtag/drivers/jtag_usb_common.h b/src/jtag/drivers/jtag_usb_common.h deleted file mode 100644 index 8c03742e92..0000000000 --- a/src/jtag/drivers/jtag_usb_common.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-2.0+ - * Copyright (c) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> - */ - -#ifndef OPENOCD_JTAG_USB_COMMON_H -#define OPENOCD_JTAG_USB_COMMON_H - -void jtag_usb_set_location(const char *location); -const char *jtag_usb_get_location(void); -bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, - size_t path_len); - -#endif /* OPENOCD_JTAG_USB_COMMON_H */ diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c index 32a43f8bfc..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 @@ -33,13 +22,13 @@ #include <netinet/tcp.h> #endif -#include <string.h> +#include "helper/replacements.h" #define NO_TAP_SHIFT 0 #define TAP_SHIFT 1 -#define SERVER_ADDRESS "127.0.0.1" -#define SERVER_PORT 5555 +#define DEFAULT_SERVER_ADDRESS "127.0.0.1" +#define DEFAULT_SERVER_PORT 5555 #define XFERT_MAX_SIZE 512 @@ -50,7 +39,7 @@ #define CMD_STOP_SIMU 4 /* jtag_vpi server port and address to connect to */ -static int server_port = SERVER_PORT; +static int server_port = DEFAULT_SERVER_PORT; static char *server_address; /* Send CMD_STOP_SIMU to server when OpenOCD exits? */ @@ -159,7 +148,7 @@ retry_write: /* This means we could not send all data, which is most likely fatal for the jtag_vpi connection (the underlying TCP connection likely not usable anymore) */ - LOG_ERROR("Could not send all data through jtag_vpi connection."); + LOG_ERROR("jtag_vpi: Could not send all data through jtag_vpi connection."); exit(-1); } @@ -208,8 +197,8 @@ static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi) /** * jtag_vpi_reset - ask to reset the JTAG device - * @trst: 1 if TRST is to be asserted - * @srst: 1 if SRST is to be asserted + * @param trst 1 if TRST is to be asserted + * @param srst 1 if SRST is to be asserted */ static int jtag_vpi_reset(int trst, int srst) { @@ -223,12 +212,12 @@ static int jtag_vpi_reset(int trst, int srst) /** * jtag_vpi_tms_seq - ask a TMS sequence transition to JTAG - * @bits: TMS bits to be written (bit0, bit1 .. bitN) - * @nb_bits: number of TMS bits (between 1 and 8) + * @param bits TMS bits to be written (bit0, bit1 .. bitN) + * @param nb_bits number of TMS bits (between 1 and 8) * * Write a series of TMS transitions, where each transition consists in : - * - writing out TCK=0, TMS=<new_state>, TDI=<???> - * - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition + * - writing out TCK=0, TMS=\<new_state>, TDI=\<???> + * - writing out TCK=1, TMS=\<new_state>, TDI=\<???> which triggers the transition * The function ensures that at the end of the sequence, the clock (TCK) is put * low. */ @@ -250,11 +239,11 @@ static int jtag_vpi_tms_seq(const uint8_t *bits, int nb_bits) /** * jtag_vpi_path_move - ask a TMS sequence transition to JTAG - * @cmd: path transition + * @param cmd path transition * * Write a series of TMS transitions, where each transition consists in : - * - writing out TCK=0, TMS=<new_state>, TDI=<???> - * - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition + * - writing out TCK=0, TMS=\<new_state>, TDI=\<???> + * - writing out TCK=1, TMS=\<new_state>, TDI=\<???> which triggers the transition * The function ensures that at the end of the sequence, the clock (TCK) is put * low. */ @@ -276,7 +265,7 @@ static int jtag_vpi_path_move(struct pathmove_command *cmd) /** * jtag_vpi_tms - ask a tms command - * @cmd: tms command + * @param cmd tms command */ static int jtag_vpi_tms(struct tms_command *cmd) { @@ -342,8 +331,9 @@ static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift) /** * jtag_vpi_queue_tdi - short description - * @bits: bits to be queued on TDI (or NULL if 0 are to be queued) - * @nb_bits: number of bits + * @param bits bits to be queued on TDI (or NULL if 0 are to be queued) + * @param nb_bits number of bits + * @param tap_shift */ static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift) { @@ -372,7 +362,7 @@ static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift) /** * jtag_vpi_clock_tms - clock a TMS transition - * @tms: the TMS to be sent + * @param tms the TMS to be sent * * Triggers a TMS transition (ie. one JTAG TAP state move). */ @@ -386,7 +376,7 @@ static int jtag_vpi_clock_tms(int tms) /** * jtag_vpi_scan - launches a DR-scan or IR-scan - * @cmd: the command to launch + * @param cmd the command to launch * * Launch a JTAG IR-scan or DR-scan * @@ -490,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 != NULL; + for (cmd = cmd_queue; retval == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { case JTAG_RESET: @@ -540,7 +530,7 @@ static int jtag_vpi_init(void) sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { - LOG_ERROR("Could not create socket"); + LOG_ERROR("jtag_vpi: Could not create client socket"); return ERROR_FAIL; } @@ -550,18 +540,18 @@ static int jtag_vpi_init(void) serv_addr.sin_port = htons(server_port); if (!server_address) - server_address = strdup(SERVER_ADDRESS); + server_address = strdup(DEFAULT_SERVER_ADDRESS); serv_addr.sin_addr.s_addr = inet_addr(server_address); if (serv_addr.sin_addr.s_addr == INADDR_NONE) { - LOG_ERROR("inet_addr error occurred"); + LOG_ERROR("jtag_vpi: inet_addr error occurred"); return ERROR_FAIL; } if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { close(sockfd); - LOG_ERROR("Can't connect to %s : %u", server_address, server_port); + LOG_ERROR("jtag_vpi: Can't connect to %s : %u", server_address, server_port); return ERROR_COMMAND_CLOSE_CONNECTION; } @@ -572,7 +562,7 @@ static int jtag_vpi_init(void) setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)); } - LOG_INFO("Connection to %s : %u succeed", server_address, server_port); + LOG_INFO("jtag_vpi: Connection to %s : %u successful", server_address, server_port); return ERROR_OK; } @@ -604,58 +594,53 @@ static int jtag_vpi_quit(void) COMMAND_HANDLER(jtag_vpi_set_port) { if (CMD_ARGC == 0) - LOG_WARNING("You need to set a port number"); - else - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port); + return ERROR_COMMAND_SYNTAX_ERROR; - LOG_INFO("Set server port to %u", server_port); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port); + LOG_INFO("jtag_vpi: server port set to %u", server_port); return ERROR_OK; } COMMAND_HANDLER(jtag_vpi_set_address) { - free(server_address); - if (CMD_ARGC == 0) { - LOG_WARNING("You need to set an address"); - server_address = strdup(SERVER_ADDRESS); - } else - server_address = strdup(CMD_ARGV[0]); + if (CMD_ARGC == 0) + return ERROR_COMMAND_SYNTAX_ERROR; - LOG_INFO("Set server address to %s", server_address); + free(server_address); + server_address = strdup(CMD_ARGV[0]); + LOG_INFO("jtag_vpi: server address set to %s", server_address); return ERROR_OK; } COMMAND_HANDLER(jtag_vpi_stop_sim_on_exit_handler) { - if (CMD_ARGC != 1) { - LOG_ERROR("jtag_vpi_stop_sim_on_exit expects 1 argument (on|off)"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } else { - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], stop_sim_on_exit); - } + + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], stop_sim_on_exit); return ERROR_OK; } -static const struct command_registration jtag_vpi_command_handlers[] = { +static const struct command_registration jtag_vpi_subcommand_handlers[] = { { - .name = "jtag_vpi_set_port", + .name = "set_port", .handler = &jtag_vpi_set_port, .mode = COMMAND_CONFIG, - .help = "set the port of the VPI server", + .help = "set the TCP port number of the jtag_vpi server (default: 5555)", .usage = "tcp_port_num", }, { - .name = "jtag_vpi_set_address", + .name = "set_address", .handler = &jtag_vpi_set_address, .mode = COMMAND_CONFIG, - .help = "set the address of the VPI server", + .help = "set the IP address of the jtag_vpi server (default: 127.0.0.1)", .usage = "ipv4_addr", }, { - .name = "jtag_vpi_stop_sim_on_exit", + .name = "stop_sim_on_exit", .handler = &jtag_vpi_stop_sim_on_exit_handler, .mode = COMMAND_CONFIG, .help = "Configure if simulation stop command shall be sent " @@ -665,6 +650,17 @@ static const struct command_registration jtag_vpi_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration jtag_vpi_command_handlers[] = { + { + .name = "jtag_vpi", + .mode = COMMAND_ANY, + .help = "perform jtag_vpi management", + .chain = jtag_vpi_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static struct jtag_interface jtag_vpi_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = jtag_vpi_execute_queue, diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index 5538bcd739..98b0d16681 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; @@ -114,7 +119,6 @@ struct pending_transfer_result { void *buffer; }; -static char *kitprog_serial; static bool kitprog_init_acquire_psoc; static int pending_transfer_count, pending_queue_len; @@ -158,7 +162,7 @@ static int kitprog_init(void) int retval; kitprog_handle = malloc(sizeof(struct kitprog)); - if (kitprog_handle == NULL) { + if (!kitprog_handle) { LOG_ERROR("Failed to allocate memory"); return ERROR_FAIL; } @@ -208,14 +212,14 @@ static int kitprog_init(void) /* Allocate packet buffers and queues */ kitprog_handle->packet_size = SWD_MAX_BUFFER_LENGTH; kitprog_handle->packet_buffer = malloc(SWD_MAX_BUFFER_LENGTH); - if (kitprog_handle->packet_buffer == NULL) { + if (!kitprog_handle->packet_buffer) { LOG_ERROR("Failed to allocate memory for the packet buffer"); return ERROR_FAIL; } pending_queue_len = SWD_MAX_BUFFER_LENGTH / 5; pending_transfers = malloc(pending_queue_len * sizeof(*pending_transfers)); - if (pending_transfers == NULL) { + if (!pending_transfers) { LOG_ERROR("Failed to allocate memory for the SWD transfer queue"); return ERROR_FAIL; } @@ -230,7 +234,6 @@ static int kitprog_quit(void) free(kitprog_handle->packet_buffer); free(kitprog_handle->serial); free(kitprog_handle); - free(kitprog_serial); free(pending_transfers); return ERROR_OK; @@ -256,7 +259,7 @@ static int kitprog_get_usb_serial(void) /* Allocate memory for the serial number */ kitprog_handle->serial = calloc(retval + 1, sizeof(char)); - if (kitprog_handle->serial == NULL) { + if (!kitprog_handle->serial) { LOG_ERROR("Failed to allocate memory for the serial number"); return ERROR_FAIL; } @@ -272,8 +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_serial, - &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; } @@ -285,7 +287,7 @@ static int kitprog_usb_open(void) /* Convert the ASCII serial number into a (wchar_t *) */ size_t len = strlen(kitprog_handle->serial); wchar_t *hid_serial = calloc(len + 1, sizeof(wchar_t)); - if (hid_serial == NULL) { + if (!hid_serial) { LOG_ERROR("Failed to allocate memory for the serial number"); return ERROR_FAIL; } @@ -298,7 +300,7 @@ static int kitprog_usb_open(void) /* Use HID for the KitBridge interface */ kitprog_handle->hid_handle = hid_open(VID, PID, hid_serial); free(hid_serial); - if (kitprog_handle->hid_handle == NULL) { + if (!kitprog_handle->hid_handle) { LOG_ERROR("Failed to open KitBridge (HID) interface"); return ERROR_FAIL; } @@ -314,7 +316,7 @@ static int kitprog_usb_open(void) static void kitprog_usb_close(void) { - if (kitprog_handle->hid_handle != NULL) { + if (kitprog_handle->hid_handle) { hid_close(kitprog_handle->hid_handle); hid_exit(); } @@ -335,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; } @@ -408,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; } @@ -434,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); } @@ -460,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; } @@ -485,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; } @@ -509,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; } @@ -533,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; } @@ -557,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; } @@ -625,13 +631,13 @@ static int kitprog_swd_init(void) static void kitprog_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { - assert(!(cmd & SWD_CMD_RnW)); + assert(!(cmd & SWD_CMD_RNW)); kitprog_swd_queue_cmd(cmd, NULL, value); } static void kitprog_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { - assert(cmd & SWD_CMD_RnW); + assert(cmd & SWD_CMD_RNW); kitprog_swd_queue_cmd(cmd, value, 0); } @@ -699,8 +705,8 @@ static int kitprog_swd_run_queue(void) * cmsis_dap_cmd_DAP_SWD_Configure() in * cmsis_dap_init(). */ - if (!(cmd & SWD_CMD_RnW) && - !(cmd & SWD_CMD_APnDP) && + if (!(cmd & SWD_CMD_RNW) && + !(cmd & SWD_CMD_APNDP) && (cmd & SWD_CMD_A32) >> 1 == DP_CTRL_STAT && (data & CORUNDETECT)) { LOG_DEBUG("refusing to enable sticky overrun detection"); @@ -708,13 +714,13 @@ static int kitprog_swd_run_queue(void) } LOG_DEBUG_IO("%s %s reg %x %"PRIx32, - cmd & SWD_CMD_APnDP ? "AP" : "DP", - cmd & SWD_CMD_RnW ? "read" : "write", + cmd & SWD_CMD_APNDP ? "AP" : "DP", + cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, data); buffer[write_count++] = (cmd | SWD_CMD_START | SWD_CMD_PARK) & ~SWD_CMD_STOP; read_count++; - if (!(cmd & SWD_CMD_RnW)) { + if (!(cmd & SWD_CMD_RNW)) { buffer[write_count++] = (data) & 0xff; buffer[write_count++] = (data >> 8) & 0xff; buffer[write_count++] = (data >> 16) & 0xff; @@ -761,7 +767,7 @@ static int kitprog_swd_run_queue(void) } for (int i = 0; i < pending_transfer_count; i++) { - if (pending_transfers[i].cmd & SWD_CMD_RnW) { + if (pending_transfers[i].cmd & SWD_CMD_RNW) { uint32_t data = le_to_h_u32(&buffer[read_index]); LOG_DEBUG_IO("Read result: %"PRIx32, data); @@ -776,7 +782,7 @@ static int kitprog_swd_run_queue(void) if (ack != SWD_ACK_OK || (buffer[read_index] & 0x08)) { LOG_DEBUG("SWD ack not OK: %d %s", i, 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); break; } read_index++; @@ -802,7 +808,7 @@ static void kitprog_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) pending_transfers[pending_transfer_count].data = data; pending_transfers[pending_transfer_count].cmd = cmd; - if (cmd & SWD_CMD_RnW) { + if (cmd & SWD_CMD_RNW) { /* Queue a read transaction */ pending_transfers[pending_transfer_count].buffer = dst; } @@ -851,22 +857,6 @@ COMMAND_HANDLER(kitprog_handle_acquire_psoc_command) return retval; } -COMMAND_HANDLER(kitprog_handle_serial_command) -{ - if (CMD_ARGC == 1) { - kitprog_serial = strdup(CMD_ARGV[0]); - if (kitprog_serial == NULL) { - LOG_ERROR("Failed to allocate memory for the serial number"); - return ERROR_FAIL; - } - } else { - LOG_ERROR("expected exactly one argument to kitprog_serial <serial-number>"); - return ERROR_FAIL; - } - - return ERROR_OK; -} - COMMAND_HANDLER(kitprog_handle_init_acquire_psoc_command) { kitprog_init_acquire_psoc = true; @@ -889,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 }; @@ -900,20 +897,6 @@ static const struct command_registration kitprog_command_handlers[] = { .usage = "<cmd>", .chain = kitprog_subcommand_handlers, }, - { - .name = "kitprog_serial", - .handler = &kitprog_handle_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the serial number of the adapter", - .usage = "serial_string", - }, - { - .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/libftdi_helper.h b/src/jtag/drivers/libftdi_helper.h new file mode 100644 index 0000000000..e187b57270 --- /dev/null +++ b/src/jtag/drivers/libftdi_helper.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H +#define OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H + +#include <ftdi.h> + +#ifndef HAVE_LIBFTDI_TCIOFLUSH +/* Backward compatibility with libftdi pre 1.5 */ + +static inline int ftdi_tciflush(struct ftdi_context *ftdi) +{ + return ftdi_usb_purge_rx_buffer(ftdi); +} + +static inline int ftdi_tcoflush(struct ftdi_context *ftdi) +{ + return ftdi_usb_purge_tx_buffer(ftdi); +} + +static inline int ftdi_tcioflush(struct ftdi_context *ftdi) +{ + return ftdi_usb_purge_buffers(ftdi); +} +#endif + +#endif /* OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H */ 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 184882abcc..57ea8cd3fa 100644 --- a/src/jtag/drivers/libusb_helper.c +++ b/src/jtag/drivers/libusb_helper.c @@ -1,28 +1,20 @@ +// 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 #include "config.h" #endif -#include <jtag/drivers/jtag_usb_common.h> + +#include <string.h> + +#include <helper/log.h> +#include <jtag/adapter.h> #include "libusb_helper.h" -#include "log.h" /* * comment from libusb: @@ -31,7 +23,7 @@ #define MAX_USB_PORTS 7 static struct libusb_context *jtag_libusb_context; /**< Libusb context **/ -static libusb_device **devs; /**< The usb device list **/ +static struct libusb_device **devs; /**< The usb device list **/ static int jtag_libusb_error(int err) { @@ -58,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++) { @@ -71,7 +63,7 @@ static bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, } #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS -static bool jtag_libusb_location_equal(libusb_device *device) +static bool jtag_libusb_location_equal(struct libusb_device *device) { uint8_t port_path[MAX_USB_PORTS]; uint8_t dev_bus; @@ -85,10 +77,10 @@ static bool jtag_libusb_location_equal(libusb_device *device) } dev_bus = libusb_get_bus_number(device); - return jtag_usb_location_equal(dev_bus, port_path, path_len); + return adapter_usb_location_equal(dev_bus, port_path, path_len); } #else /* HAVE_LIBUSB_GET_PORT_NUMBERS */ -static bool jtag_libusb_location_equal(libusb_device *device) +static bool jtag_libusb_location_equal(struct libusb_device *device) { return true; } @@ -96,7 +88,7 @@ static bool jtag_libusb_location_equal(libusb_device *device) /* Returns true if the string descriptor indexed by str_index in device matches string */ -static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_index, +static bool string_descriptor_equal(struct libusb_device_handle *device, uint8_t str_index, const char *string) { int retval; @@ -123,7 +115,7 @@ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_in return matched; } -static bool jtag_libusb_match_serial(libusb_device_handle *device, +static bool jtag_libusb_match_serial(struct libusb_device_handle *device, struct libusb_device_descriptor *dev_desc, const char *serial, adapter_get_alternate_serial_fn adapter_get_alternate_serial) { @@ -138,7 +130,7 @@ static bool jtag_libusb_match_serial(libusb_device_handle *device, char *alternate_serial = adapter_get_alternate_serial(device, dev_desc); /* check possible failures */ - if (alternate_serial == NULL) + if (!alternate_serial) return false; /* then compare and free the alternate serial */ @@ -154,14 +146,15 @@ static bool jtag_libusb_match_serial(libusb_device_handle *device, } int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], - const char *serial, - 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, errCode; + 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(); if (libusb_init(&jtag_libusb_context) < 0) return ERROR_FAIL; @@ -177,29 +170,37 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], if (!jtag_libusb_match_ids(&dev_desc, vids, pids)) continue; - if (jtag_usb_get_location() && !jtag_libusb_location_equal(devs[idx])) + if (adapter_usb_get_location() && !jtag_libusb_location_equal(devs[idx])) continue; - errCode = libusb_open(devs[idx], &libusb_handle); + err_code = libusb_open(devs[idx], &libusb_handle); - if (errCode) { + if (err_code) { LOG_ERROR("libusb_open() failed with %s", - libusb_error_name(errCode)); + libusb_error_name(err_code)); continue; } /* Device must be open to use libusb_get_string_descriptor_ascii. */ - if (serial != NULL && + if (serial && !jtag_libusb_match_serial(libusb_handle, &dev_desc, serial, adapter_get_alternate_serial)) { serial_mismatch = true; libusb_close(libusb_handle); 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) @@ -208,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); @@ -222,19 +226,24 @@ void jtag_libusb_close(struct libusb_device_handle *dev) libusb_exit(jtag_libusb_context); } -int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t requestType, - uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes, - uint16_t size, unsigned int timeout) +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, int *transferred) { - int transferred = 0; - - transferred = libusb_control_transfer(dev, requestType, request, wValue, wIndex, + 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, @@ -275,28 +284,28 @@ int jtag_libusb_set_configuration(struct libusb_device_handle *devh, int configuration) { struct libusb_device *udev = libusb_get_device(devh); - int retCode = -99; + int retval = -99; struct libusb_config_descriptor *config = NULL; int current_config = -1; - retCode = libusb_get_configuration(devh, ¤t_config); - if (retCode != 0) - return retCode; + retval = libusb_get_configuration(devh, ¤t_config); + if (retval != 0) + return retval; - retCode = libusb_get_config_descriptor(udev, configuration, &config); - if (retCode != 0 || config == NULL) - return retCode; + retval = libusb_get_config_descriptor(udev, configuration, &config); + if (retval != 0 || !config) + return retval; /* Only change the configuration if it is not already set to the same one. Otherwise this issues a lightweight reset and hangs LPC-Link2 with JLink firmware. */ if (current_config != config->bConfigurationValue) - retCode = libusb_set_configuration(devh, config->bConfigurationValue); + retval = libusb_set_configuration(devh, config->bConfigurationValue); libusb_free_config_descriptor(config); - return retCode; + return retval; } int jtag_libusb_choose_interface(struct libusb_device_handle *devh, @@ -363,3 +372,64 @@ int jtag_libusb_get_pid(struct libusb_device *dev, uint16_t *pid) return ERROR_FAIL; } + +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 74bb23c52e..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 @@ -22,19 +11,35 @@ #include <libusb.h> +/* When we debug a target that works as a USB device, halting the target causes the + * USB communication with the USB host to become unresponsive. The host will try + * to reconnect/reset/setup the unresponsive device during which communication + * with other devices on the same USB bus can get stalled for several seconds. + * If the JTAG adapter is on the same bus, we need to make sure openOCD will wait + * for packets at least as long as the host USB stack. Otherwise the USB stack + * might deliver a valid packet, but openOCD would ignore it due to the timeout. + * The xHCI spec uses 5 sec timeouts, so let's use that in openOCD with some margin. + * + * Use this value in all libusb calls. HID API might have a libusb backend and + * would probably be victim to the same bug, so it should use this timeout, too. + */ +#define LIBUSB_TIMEOUT_MS (6000) + /* this callback should return a non NULL value only when the serial could not * be retrieved by the standard 'libusb_get_string_descriptor_ascii' */ -typedef char * (*adapter_get_alternate_serial_fn)(libusb_device_handle *device, +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[], - const char *serial, - 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 requestType, uint8_t request, uint16_t wValue, - uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout); + uint8_t request_type, uint8_t request, uint16_t value, + 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, @@ -60,5 +65,29 @@ int jtag_libusb_choose_interface(struct libusb_device_handle *devh, unsigned int *usb_write_ep, int bclass, int subclass, int protocol, int trans_type); 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 99422a1168..2f3d644542 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,44 +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 led_gpio = -1; -static int gpiochip = -1; - -static struct gpiod_chip *gpiod_chip; -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_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 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; @@ -84,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"); } @@ -113,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; @@ -131,16 +126,26 @@ 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) { - retval = gpiod_line_request_output(gpiod_swdio, "OpenOCD", 1); + 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_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_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"); + } } last_stored = false; @@ -152,16 +157,16 @@ static int linuxgpiod_swd_write(int swclk, int swdio) int retval; if (!swdio_input) { - if (!last_stored || (swdio != last_swdio)) { - retval = gpiod_line_set_value(gpiod_swdio, swdio); + if (!last_stored || swdio != last_swdio) { + retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], swdio); if (retval < 0) LOG_WARNING("Fail set swdio"); } } /* write swclk last */ - if (!last_stored || (swclk != last_swclk)) { - retval = gpiod_line_set_value(gpiod_swclk, swclk); + if (!last_stored || swclk != last_swclk) { + retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWCLK], swclk); if (retval < 0) LOG_WARNING("Fail set swclk"); } @@ -177,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; @@ -206,16 +211,18 @@ static int linuxgpiod_reset(int trst, int srst) LOG_DEBUG("linuxgpiod_reset"); - /* assume active low */ - if (gpiod_srst != NULL) { - 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 != NULL) { - 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"); } @@ -223,99 +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); - - gpiod_chip_close(gpiod_chip); + 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_input_line(const char *label, unsigned int offset) +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; - line = gpiod_chip_get_line(gpiod_chip, offset); - if (line == NULL) { - LOG_ERROR("Error get line %s", label); - return NULL; + 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; } - retval = gpiod_line_request_input(line, "OpenOCD"); - if (retval < 0) { - LOG_ERROR("Error request_input line %s", label); - return NULL; + 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; } - return line; -} + 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; + } -static struct gpiod_line *helper_get_output_line(const char *label, unsigned int offset, int val) -{ - struct gpiod_line *line; - int retval; + 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 == NULL) { - LOG_ERROR("Error get line %s", label); - return NULL; + switch (adapter_gpio_config[idx].pull) { + case ADAPTER_GPIO_PULL_NONE: +#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS + flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE; +#endif + break; + case ADAPTER_GPIO_PULL_UP: +#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS + 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 HAVE_LIBGPIOD1_FLAGS_BIAS + 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; } - retval = gpiod_line_request_output(line, "OpenOCD", val); + 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(gpiod_line[idx], &config, val); if (retval < 0) { - LOG_ERROR("Error request_output line %s", label); - return NULL; + LOG_ERROR("Error requesting gpio line %s", adapter_gpio_get_name(idx)); + return ERROR_JTAG_INIT_FAILED; } - return line; + return ERROR_OK; } static int linuxgpiod_init(void) @@ -323,17 +365,11 @@ static int linuxgpiod_init(void) LOG_INFO("Linux GPIOD JTAG/SWD bitbang driver"); bitbang_interface = &linuxgpiod_bitbang; - - gpiod_chip = gpiod_chip_open_by_number(gpiochip); - if (gpiod_chip == NULL) { - LOG_ERROR("Cannot open LinuxGPIOD gpiochip %d", gpiochip); - return ERROR_JTAG_INIT_FAILED; - } + 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()) { @@ -342,55 +378,44 @@ static int linuxgpiod_init(void) goto out_error; } - gpiod_tdo = helper_get_input_line("tdo", tdo_gpio); - if (gpiod_tdo == NULL) - goto out_error; - - gpiod_tdi = helper_get_output_line("tdi", tdi_gpio, 0); - if (gpiod_tdi == NULL) - goto out_error; - - gpiod_tck = helper_get_output_line("tck", tck_gpio, 0); - if (gpiod_tck == NULL) - goto out_error; - - gpiod_tms = helper_get_output_line("tms", tms_gpio, 1); - if (gpiod_tms == NULL) - goto out_error; - - if (is_gpio_valid(trst_gpio)) { - gpiod_trst = helper_get_output_line("trst", trst_gpio, 1); - if (gpiod_trst == NULL) + 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 (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_swclk = helper_get_output_line("swclk", swclk_gpio, 1); - if (gpiod_swclk == NULL) + /* + * 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); + } + if (retval1 != ERROR_OK || retval2 != ERROR_OK) goto out_error; - gpiod_swdio = helper_get_output_line("swdio", swdio_gpio, 1); - if (gpiod_swdio == NULL) + if (helper_get_line(ADAPTER_GPIO_IDX_SWCLK) != ERROR_OK) goto out_error; } - if (is_gpio_valid(srst_gpio)) { - gpiod_srst = helper_get_output_line("srst", srst_gpio, 1); - if (gpiod_srst == NULL) + if (helper_get_line(ADAPTER_GPIO_IDX_SRST) != ERROR_OK || + helper_get_line(ADAPTER_GPIO_IDX_LED) != ERROR_OK) goto out_error; - } - - if (is_gpio_valid(led_gpio)) { - gpiod_led = helper_get_output_line("led", led_gpio, 0); - if (gpiod_led == NULL) - goto out_error; - } return ERROR_OK; @@ -400,218 +425,6 @@ out_error: return ERROR_JTAG_INIT_FAILED; } -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) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); - - command_print(CMD, "LinuxGPIOD num: tck = %d", tck_gpio); - return ERROR_OK; -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tms) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio); - - command_print(CMD, "LinuxGPIOD num: tms = %d", tms_gpio); - return ERROR_OK; -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tdo) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio); - - command_print(CMD, "LinuxGPIOD num: tdo = %d", tdo_gpio); - return ERROR_OK; -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tdi) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio); - - command_print(CMD, "LinuxGPIOD num: tdi = %d", tdi_gpio); - return ERROR_OK; -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_srst) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio); - - command_print(CMD, "LinuxGPIOD num: srst = %d", srst_gpio); - return ERROR_OK; -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_trst) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio); - - command_print(CMD, "LinuxGPIOD num: trst = %d", trst_gpio); - return ERROR_OK; -} - -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) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); - - command_print(CMD, "LinuxGPIOD num: swclk = %d", swclk_gpio); - return ERROR_OK; -} - -COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio); - - command_print(CMD, "LinuxGPIOD num: swdio = %d", swdio_gpio); - return ERROR_OK; -} - -COMMAND_HANDLER(linuxgpiod_handle_gpionum_led) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], led_gpio); - - command_print(CMD, "LinuxGPIOD num: led = %d", led_gpio); - return ERROR_OK; -} - -COMMAND_HANDLER(linuxgpiod_handle_gpiochip) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], gpiochip); - - command_print(CMD, "LinuxGPIOD gpiochip = %d", gpiochip); - return ERROR_OK; -} - -static const struct command_registration linuxgpiod_command_handlers[] = { - { - .name = "linuxgpiod_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 = "linuxgpiod_tck_num", - .handler = linuxgpiod_handle_jtag_gpionum_tck, - .mode = COMMAND_CONFIG, - .help = "gpio number for tck.", - .usage = "tck", - }, - { - .name = "linuxgpiod_tms_num", - .handler = linuxgpiod_handle_jtag_gpionum_tms, - .mode = COMMAND_CONFIG, - .help = "gpio number for tms.", - .usage = "tms", - }, - { - .name = "linuxgpiod_tdo_num", - .handler = linuxgpiod_handle_jtag_gpionum_tdo, - .mode = COMMAND_CONFIG, - .help = "gpio number for tdo.", - .usage = "tdo", - }, - { - .name = "linuxgpiod_tdi_num", - .handler = linuxgpiod_handle_jtag_gpionum_tdi, - .mode = COMMAND_CONFIG, - .help = "gpio number for tdi.", - .usage = "tdi", - }, - { - .name = "linuxgpiod_srst_num", - .handler = linuxgpiod_handle_jtag_gpionum_srst, - .mode = COMMAND_CONFIG, - .help = "gpio number for srst.", - .usage = "srst", - }, - { - .name = "linuxgpiod_trst_num", - .handler = linuxgpiod_handle_jtag_gpionum_trst, - .mode = COMMAND_CONFIG, - .help = "gpio number for trst.", - .usage = "trst", - }, - { - .name = "linuxgpiod_swd_nums", - .handler = linuxgpiod_handle_swd_gpionums, - .mode = COMMAND_CONFIG, - .help = "gpio numbers for swclk, swdio. (in that order)", - .usage = "swclk swdio", - }, - { - .name = "linuxgpiod_swclk_num", - .handler = linuxgpiod_handle_swd_gpionum_swclk, - .mode = COMMAND_CONFIG, - .help = "gpio number for swclk.", - .usage = "swclk", - }, - { - .name = "linuxgpiod_swdio_num", - .handler = linuxgpiod_handle_swd_gpionum_swdio, - .mode = COMMAND_CONFIG, - .help = "gpio number for swdio.", - .usage = "swdio", - }, - { - .name = "linuxgpiod_led_num", - .handler = linuxgpiod_handle_gpionum_led, - .mode = COMMAND_CONFIG, - .help = "gpio number for LED.", - .usage = "led", - }, - { - .name = "linuxgpiod_gpiochip", - .handler = linuxgpiod_handle_gpiochip, - .mode = COMMAND_CONFIG, - .help = "number of the gpiochip.", - .usage = "gpiochip", - }, - COMMAND_REGISTRATION_DONE -}; - static const char *const linuxgpiod_transport[] = { "swd", "jtag", NULL }; static struct jtag_interface linuxgpiod_interface = { @@ -622,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 fe8b6b82c1..f3499e3864 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 @@ -22,7 +11,9 @@ #include "mpsse.h" #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 */ @@ -62,8 +53,8 @@ #define SIO_RESET_PURGE_TX 2 struct mpsse_ctx { - libusb_context *usb_ctx; - libusb_device_handle *usb_dev; + struct libusb_context *usb_ctx; + struct libusb_device_handle *usb_dev; unsigned int usb_write_timeout; unsigned int usb_read_timeout; uint8_t in_ep; @@ -85,7 +76,7 @@ struct mpsse_ctx { }; /* Returns true if the string descriptor indexed by str_index in device matches string */ -static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_index, +static bool string_descriptor_equal(struct libusb_device_handle *device, uint8_t str_index, const char *string) { int retval; @@ -99,7 +90,7 @@ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_in return strncmp(string, desc_string, sizeof(desc_string)) == 0; } -static bool device_location_equal(libusb_device *device, const char *location) +static bool device_location_equal(struct libusb_device *device, const char *location) { bool result = false; #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS @@ -118,7 +109,7 @@ static bool device_location_equal(libusb_device *device, const char *location) LOG_DEBUG("device path has %i steps", path_len); ptr = strtok(loc, "-:"); - if (ptr == NULL) { + if (!ptr) { LOG_DEBUG("no ':' in path"); goto done; } @@ -130,7 +121,7 @@ static bool device_location_equal(libusb_device *device, const char *location) path_step = 0; while (path_step < 7) { ptr = strtok(NULL, ".,"); - if (ptr == NULL) { + if (!ptr) { LOG_DEBUG("no more tokens in path at step %i", path_step); break; } @@ -158,10 +149,10 @@ static bool device_location_equal(libusb_device *device, const char *location) * 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) { - libusb_device **list; + struct libusb_device **list; struct libusb_device_descriptor desc; struct libusb_config_descriptor *config0; int err; @@ -171,7 +162,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con LOG_ERROR("libusb_get_device_list() failed with %s", libusb_error_name(cnt)); for (ssize_t i = 0; i < cnt; i++) { - libusb_device *device = list[i]; + struct libusb_device *device = list[i]; err = libusb_get_device_descriptor(device, &desc); if (err != LIBUSB_SUCCESS) { @@ -179,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); @@ -213,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; } @@ -276,6 +265,24 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con case 0x900: ctx->type = TYPE_FT232H; break; + case 0x2800: + ctx->type = TYPE_FT2233HP; + break; + case 0x2900: + ctx->type = TYPE_FT4233HP; + break; + case 0x3000: + ctx->type = TYPE_FT2232HP; + break; + case 0x3100: + ctx->type = TYPE_FT4232HP; + break; + case 0x3200: + ctx->type = TYPE_FT233HP; + break; + case 0x3300: + ctx->type = TYPE_FT232HP; + break; default: LOG_ERROR("unsupported FTDI chip type: 0x%04x", desc.bcdDevice); goto error; @@ -317,14 +324,14 @@ error: 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; @@ -353,18 +360,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; } @@ -394,7 +396,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) @@ -481,13 +483,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, @@ -564,7 +566,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, @@ -858,7 +860,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 */ @@ -896,20 +898,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) { @@ -917,6 +905,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: @@ -944,12 +941,12 @@ error_check: retval = ERROR_OK; } + if (retval != ERROR_OK) + mpsse_purge(ctx); + libusb_free_transfer(write_transfer); if (read_transfer) libusb_free_transfer(read_transfer); - if (retval != ERROR_OK) - mpsse_purge(ctx); - return retval; } diff --git a/src/jtag/drivers/mpsse.h b/src/jtag/drivers/mpsse.h index 651eef9406..e92a9bb56f 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 @@ -35,6 +24,12 @@ enum ftdi_chip_type { TYPE_FT2232H, TYPE_FT4232H, TYPE_FT232H, + TYPE_FT2233HP, + TYPE_FT4233HP, + TYPE_FT2232HP, + TYPE_FT4232HP, + TYPE_FT233HP, + TYPE_FT232HP, }; struct mpsse_ctx; diff --git a/src/jtag/drivers/nulink_usb.c b/src/jtag/drivers/nulink_usb.c index 5fdbed3fc4..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 @@ -22,6 +11,7 @@ /* project specific includes */ #include <helper/binarybuffer.h> +#include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/hla/hla_layout.h> #include <jtag/hla/hla_transport.h> @@ -32,7 +22,9 @@ #include <hidapi.h> -#define NULINK_READ_TIMEOUT 1000 +#include "libusb_helper.h" + +#define NULINK_READ_TIMEOUT LIBUSB_TIMEOUT_MS #define NULINK_HID_MAX_SIZE (64) #define NULINK2_HID_MAX_SIZE (1024) @@ -253,7 +245,7 @@ static int nulink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) { struct nulink_usb_handle_s *h = handle; - LOG_DEBUG("nulink_usb_write_debug_reg 0x%08" PRIX32 "0x%08" PRIX32, addr, val); + LOG_DEBUG("nulink_usb_write_debug_reg 0x%08" PRIX32 " 0x%08" PRIX32, addr, val); nulink_usb_init_buffer(handle, 8 + 12 * 1); /* set command ID */ @@ -411,7 +403,7 @@ static int nulink_usb_step(void *handle) return res; } -static int nulink_usb_read_reg(void *handle, int num, uint32_t *val) +static int nulink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { struct nulink_usb_handle_s *h = handle; @@ -434,7 +426,7 @@ static int nulink_usb_read_reg(void *handle, int num, uint32_t *val) h->cmdbuf[h->cmdidx] = 0; h->cmdidx += 1; /* u32Addr */ - h_u32_to_le(h->cmdbuf + h->cmdidx, num); + h_u32_to_le(h->cmdbuf + h->cmdidx, regsel); h->cmdidx += 4; /* u32Data */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0); @@ -450,7 +442,7 @@ static int nulink_usb_read_reg(void *handle, int num, uint32_t *val) return res; } -static int nulink_usb_write_reg(void *handle, int num, uint32_t val) +static int nulink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) { struct nulink_usb_handle_s *h = handle; @@ -473,7 +465,7 @@ static int nulink_usb_write_reg(void *handle, int num, uint32_t val) h->cmdbuf[h->cmdidx] = 0; h->cmdidx += 1; /* u32Addr */ - h_u32_to_le(h->cmdbuf + h->cmdidx, num); + h_u32_to_le(h->cmdbuf + h->cmdidx, regsel); h->cmdidx += 4; /* u32Data */ h_u32_to_le(h->cmdbuf + h->cmdidx, val); @@ -503,7 +495,7 @@ static int nulink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len, aligned_addr = aligned_addr * 4; offset = addr - aligned_addr; LOG_DEBUG("nulink_usb_read_mem8: unaligned address addr 0x%08" PRIx32 - "/aligned addr 0x%08" PRIx32 "offset %" PRIu32, + "/aligned addr 0x%08" PRIx32 " offset %" PRIu32, addr, aligned_addr, offset); addr = aligned_addr; @@ -844,11 +836,11 @@ static int nulink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, /* the nulink only supports 8/32bit memory read/writes * honour 32bit, all others will be handled as 8bit access */ if (size == 4) { - /* When in jtag mode the nulink uses the auto-increment functinality. + /* When in jtag mode the nulink uses the auto-increment functionality. * However it expects us to pass the data correctly, this includes * alignment and any page boundaries. We already do this as part of the * adi_v5 implementation, but the nulink is a hla adapter and so this - * needs implementiong manually. + * needs implementing manually. * currently this only affects jtag mode, they do single * access in SWD mode - but this may change and so we do it for both modes */ @@ -909,11 +901,11 @@ static int nulink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, /* the nulink only supports 8/32bit memory read/writes * honour 32bit, all others will be handled as 8bit access */ if (size == 4) { - /* When in jtag mode the nulink uses the auto-increment functinality. + /* When in jtag mode the nulink uses the auto-increment functionality. * However it expects us to pass the data correctly, this includes * alignment and any page boundaries. We already do this as part of the * adi_v5 implementation, but the nulink is a hla adapter and so this - * needs implementiong manually. + * needs implementing manually. * currently this only affects jtag mode, do single * access in SWD mode - but this may change and so we do it for both modes */ @@ -1054,8 +1046,9 @@ static int nulink_usb_open(struct hl_interface_param_s *param, void **fd) goto error_open; } - if (param->serial) { - size_t len = mbstowcs(NULL, param->serial, 0); + const char *serial = adapter_get_required_serial(); + if (serial) { + size_t len = mbstowcs(NULL, serial, 0); target_serial = calloc(len + 1, sizeof(wchar_t)); if (!target_serial) { @@ -1063,7 +1056,7 @@ static int nulink_usb_open(struct hl_interface_param_s *param, void **fd) goto error_open; } - if (mbstowcs(target_serial, param->serial, len + 1) == (size_t)(-1)) { + if (mbstowcs(target_serial, serial, len + 1) == (size_t)(-1)) { LOG_WARNING("unable to convert serial"); free(target_serial); target_serial = NULL; diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index f0e4f566d2..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); @@ -144,7 +133,7 @@ static int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_lengt static int opendous_usb_read(struct opendous_jtag *opendous_jtag); /* helper functions */ -int opendous_get_version_info(void); +static int opendous_get_version_info(void); #ifdef _DEBUG_USB_COMMS_ static void opendous_debug_buffer(uint8_t *buffer, int length); @@ -161,7 +150,7 @@ COMMAND_HANDLER(opendous_handle_opendous_type_command) return ERROR_OK; /* only if the cable name wasn't overwritten by cmdline */ - if (opendous_type == NULL) { + if (!opendous_type) { /* REVISIT first verify that it's listed in cables[] ... */ opendous_type = strdup(CMD_ARGV[0]); } @@ -249,14 +238,14 @@ 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; - while (cmd != NULL) { + while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, @@ -331,7 +320,7 @@ static int opendous_init(void) cur_opendous_probe = opendous_probes; - if (opendous_type == NULL) { + if (!opendous_type) { opendous_type = strdup("opendous"); LOG_WARNING("No opendous_type specified, using default 'opendous'"); } @@ -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; } @@ -544,7 +533,7 @@ int opendous_get_status(void) return ERROR_OK; } -int opendous_get_version_info(void) +static int opendous_get_version_info(void) { return ERROR_OK; } @@ -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 2cf5751d6b..ea78ca8fd6 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -1,6 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /******************************************************************************* * Driver for OpenJTAG Project (www.openjtag.org) * - * Compatible with libftdi and ftd2xx drivers. * + * Compatible with libftdi drivers. * * * * Cypress CY7C65215 support * * Copyright (C) 2015 Vianney le Clément de Saint-Marcq, Essensium NV * @@ -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/>. * ***************************************************************************/ /*************************************************************************** @@ -82,7 +71,7 @@ typedef enum openjtag_tap_state { } openjtag_tap_state_t; /* OPENJTAG access library includes */ -#include <ftdi.h> +#include "libftdi_helper.h" /* OpenJTAG vid/pid */ static uint16_t openjtag_vid = 0x0403; @@ -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, @@ -397,7 +386,7 @@ static int openjtag_init_standard(void) uint8_t latency_timer; /* Open by device description */ - if (openjtag_device_desc == NULL) { + if (!openjtag_device_desc) { LOG_WARNING("no openjtag device description specified, " "using default 'Open JTAG Project'"); openjtag_device_desc = "Open JTAG Project"; @@ -436,8 +425,8 @@ static int openjtag_init_standard(void) return ERROR_JTAG_DEVICE_ERROR; } - if (ftdi_usb_purge_buffers(&ftdic) < 0) { - LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str); + if (ftdi_tcioflush(&ftdic) < 0) { + LOG_ERROR("ftdi flush: %s", ftdic.error_str); return ERROR_JTAG_INIT_FAILED; } @@ -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; } @@ -475,9 +464,9 @@ static int openjtag_init_cy7c65215(void) return ERROR_OK; err: - if (usbh != NULL) + 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,11 +805,11 @@ 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 != NULL) { + while (cmd) { openjtag_execute_command(cmd); cmd = cmd->next; } @@ -870,21 +876,50 @@ COMMAND_HANDLER(openjtag_handle_variant_command) return ERROR_OK; } -static const struct command_registration openjtag_command_handlers[] = { +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 = "openjtag_device_desc", + .name = "device_desc", .handler = openjtag_handle_device_desc_command, .mode = COMMAND_CONFIG, .help = "set the USB device description of the OpenJTAG", .usage = "description-string", }, { - .name = "openjtag_variant", + .name = "variant", .handler = openjtag_handle_variant_command, .mode = COMMAND_CONFIG, .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 +}; + +static const struct command_registration openjtag_command_handlers[] = { + { + .name = "openjtag", + .mode = COMMAND_ANY, + .help = "perform openjtag management", + .chain = openjtag_subcommand_handlers, + .usage = "", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/osbdm.c b/src/jtag/drivers/osbdm.c index 5c43d32445..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" @@ -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 b203c828ba..d26a51048f 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -1,28 +1,18 @@ +// 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 #include "config.h" #endif +#include <jtag/adapter.h> #include <jtag/interface.h> #include "bitbang.h" @@ -272,7 +262,7 @@ static int parport_init(void) cur_cable = cables; - if (parport_cable == NULL) { + if (!parport_cable) { parport_cable = strdup("wiggler"); LOG_WARNING("No parport cable specified, using default 'wiggler'"); } @@ -421,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]); } @@ -448,7 +442,7 @@ COMMAND_HANDLER(parport_handle_parport_toggling_time_command) uint32_t ns; int retval = parse_u32(CMD_ARGV[0], &ns); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (ns == 0) { @@ -457,9 +451,9 @@ COMMAND_HANDLER(parport_handle_parport_toggling_time_command) } parport_toggling_time_ns = ns; - retval = jtag_get_speed(&wait_states); + retval = adapter_get_speed(&wait_states); if (retval != ERROR_OK) { - /* if jtag_get_speed fails then the clock_mode + /* if adapter_get_speed fails then the clock_mode * has not been configured, this happens if parport_toggling_time is * called before the adapter speed is set */ LOG_INFO("no parport speed set - defaulting to zero wait states"); @@ -473,9 +467,9 @@ COMMAND_HANDLER(parport_handle_parport_toggling_time_command) return ERROR_OK; } -static const struct command_registration parport_command_handlers[] = { +static const struct command_registration parport_subcommand_handlers[] = { { - .name = "parport_port", + .name = "port", .handler = parport_handle_parport_port_command, .mode = COMMAND_CONFIG, .help = "Display the address of the I/O port (e.g. 0x378) " @@ -484,7 +478,7 @@ static const struct command_registration parport_command_handlers[] = { .usage = "[port_number]", }, { - .name = "parport_cable", + .name = "cable", .handler = parport_handle_parport_cable_command, .mode = COMMAND_CONFIG, .help = "Set the layout of the parallel port cable " @@ -493,7 +487,7 @@ static const struct command_registration parport_command_handlers[] = { .usage = "[layout]", }, { - .name = "parport_write_on_exit", + .name = "write_on_exit", .handler = parport_handle_write_on_exit_command, .mode = COMMAND_CONFIG, .help = "Configure the parallel driver to write " @@ -501,7 +495,7 @@ static const struct command_registration parport_command_handlers[] = { .usage = "('on'|'off')", }, { - .name = "parport_toggling_time", + .name = "toggling_time", .handler = parport_handle_parport_toggling_time_command, .mode = COMMAND_CONFIG, .help = "Displays or assigns how many nanoseconds it " @@ -511,6 +505,17 @@ static const struct command_registration parport_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration parport_command_handlers[] = { + { + .name = "parport", + .mode = COMMAND_ANY, + .help = "perform parport management", + .chain = parport_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static struct jtag_interface parport_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, diff --git a/src/jtag/drivers/presto.c b/src/jtag/drivers/presto.c index 6c3a187dbc..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/>. * ***************************************************************************/ /** @@ -29,12 +18,13 @@ #include "windows.h" #endif +#include <jtag/adapter.h> #include <jtag/interface.h> #include <helper/time_support.h> #include "bitq.h" /* PRESTO access library includes */ -#include <ftdi.h> +#include "libftdi_helper.h" /* -------------------------------------------------------------------------- */ @@ -132,7 +122,7 @@ static int presto_read(uint8_t *buf, uint32_t size) return ERROR_OK; } -static int presto_open_libftdi(char *req_serial) +static int presto_open_libftdi(const char *req_serial) { uint8_t presto_data; @@ -160,8 +150,8 @@ static int presto_open_libftdi(char *req_serial) return ERROR_JTAG_DEVICE_ERROR; } - if (ftdi_usb_purge_buffers(&presto->ftdic) < 0) { - LOG_ERROR("unable to purge PRESTO buffers"); + if (ftdi_tcioflush(&presto->ftdic) < 0) { + LOG_ERROR("unable to flush PRESTO buffers"); return ERROR_JTAG_DEVICE_ERROR; } @@ -174,7 +164,7 @@ static int presto_open_libftdi(char *req_serial) if (presto_read(&presto_data, 1) != ERROR_OK) { LOG_DEBUG("no response from PRESTO, retrying"); - if (ftdi_usb_purge_buffers(&presto->ftdic) < 0) + if (ftdi_tcioflush(&presto->ftdic) < 0) return ERROR_JTAG_DEVICE_ERROR; presto_data = 0xD0; @@ -195,7 +185,7 @@ static int presto_open_libftdi(char *req_serial) return ERROR_OK; } -static int presto_open(char *req_serial) +static int presto_open(const char *req_serial) { presto->buff_out_pos = 0; presto->buff_in_pos = 0; @@ -506,35 +496,13 @@ static int presto_jtag_speed(int speed) return 0; } -static char *presto_serial; - -COMMAND_HANDLER(presto_handle_serial_command) -{ - if (CMD_ARGC == 1) { - free(presto_serial); - presto_serial = strdup(CMD_ARGV[0]); - } else - return ERROR_COMMAND_SYNTAX_ERROR; - - return ERROR_OK; -} - -static const struct command_registration presto_command_handlers[] = { - { - .name = "presto_serial", - .handler = presto_handle_serial_command, - .mode = COMMAND_CONFIG, - .help = "Configure USB serial number of Presto device.", - .usage = "serial_string", - }, - COMMAND_REGISTRATION_DONE -}; - static int presto_jtag_init(void) { + const char *presto_serial = adapter_get_required_serial(); + if (presto_open(presto_serial) != ERROR_OK) { presto_close(); - if (presto_serial != NULL) + if (presto_serial) LOG_ERROR("Cannot open PRESTO, serial number '%s'", presto_serial); else LOG_ERROR("Cannot open PRESTO"); @@ -551,10 +519,6 @@ static int presto_jtag_quit(void) bitq_cleanup(); presto_close(); LOG_INFO("PRESTO closed"); - - free(presto_serial); - presto_serial = NULL; - return ERROR_OK; } @@ -565,7 +529,6 @@ static struct jtag_interface presto_interface = { struct adapter_driver presto_adapter_driver = { .name = "presto", .transports = jtag_only, - .commands = presto_command_handlers, .init = presto_jtag_init, .quit = presto_jtag_quit, diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index 663795296f..53d2151fdc 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 @@ -23,7 +14,10 @@ #ifndef _WIN32 #include <sys/un.h> #include <netdb.h> +#include <netinet/tcp.h> #endif +#include "helper/system.h" +#include "helper/replacements.h" #include <jtag/interface.h> #include "bitbang.h" @@ -33,51 +27,109 @@ static char *remote_bitbang_host; static char *remote_bitbang_port; -static FILE *remote_bitbang_file; 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_buf[64]; -static unsigned remote_bitbang_start; -static unsigned remote_bitbang_end; +static char remote_bitbang_recv_buf[256]; +static unsigned int remote_bitbang_recv_buf_start; +static unsigned int remote_bitbang_recv_buf_end; -static int remote_bitbang_buf_full(void) +static bool remote_bitbang_recv_buf_full(void) { - return remote_bitbang_end == - ((remote_bitbang_start + sizeof(remote_bitbang_buf) - 1) % - sizeof(remote_bitbang_buf)); + return remote_bitbang_recv_buf_end == + ((remote_bitbang_recv_buf_start + sizeof(remote_bitbang_recv_buf) - 1) % + sizeof(remote_bitbang_recv_buf)); } -/* Read any incoming data, placing it into the buffer. */ -static int remote_bitbang_fill_buf(void) +static bool remote_bitbang_recv_buf_empty(void) { - socket_nonblock(remote_bitbang_fd); - while (!remote_bitbang_buf_full()) { - unsigned contiguous_available_space; - if (remote_bitbang_end >= remote_bitbang_start) { - contiguous_available_space = sizeof(remote_bitbang_buf) - - remote_bitbang_end; - if (remote_bitbang_start == 0) - contiguous_available_space -= 1; - } else { - contiguous_available_space = remote_bitbang_start - - remote_bitbang_end - 1; + return remote_bitbang_recv_buf_start == remote_bitbang_recv_buf_end; +} + +static unsigned int remote_bitbang_recv_buf_contiguous_available_space(void) +{ + if (remote_bitbang_recv_buf_end >= remote_bitbang_recv_buf_start) { + unsigned int space = sizeof(remote_bitbang_recv_buf) - + remote_bitbang_recv_buf_end; + if (remote_bitbang_recv_buf_start == 0) + space -= 1; + return space; + } else { + return remote_bitbang_recv_buf_start - + remote_bitbang_recv_buf_end - 1; + } +} + +static int remote_bitbang_flush(void) +{ + if (remote_bitbang_send_buf_used <= 0) + return ERROR_OK; + + unsigned int offset = 0; + while (offset < remote_bitbang_send_buf_used) { + ssize_t written = write_socket(remote_bitbang_fd, remote_bitbang_send_buf + offset, + remote_bitbang_send_buf_used - offset); + if (written < 0) { + log_socket_error("remote_bitbang_putc"); + remote_bitbang_send_buf_used = 0; + return ERROR_FAIL; } - ssize_t count = read(remote_bitbang_fd, - remote_bitbang_buf + remote_bitbang_end, + offset += written; + } + remote_bitbang_send_buf_used = 0; + return ERROR_OK; +} + +enum block_bool { + NO_BLOCK, + BLOCK +}; + +/* Read any incoming data, placing it into the buffer. */ +static int remote_bitbang_fill_buf(enum block_bool block) +{ + if (remote_bitbang_recv_buf_empty()) { + /* If the buffer is empty, reset it to 0 so we get more + * contiguous space. */ + remote_bitbang_recv_buf_start = 0; + remote_bitbang_recv_buf_end = 0; + } + + if (block == BLOCK) { + if (remote_bitbang_flush() != ERROR_OK) + return ERROR_FAIL; + socket_block(remote_bitbang_fd); + } + + bool first = true; + while (!remote_bitbang_recv_buf_full()) { + unsigned int contiguous_available_space = + remote_bitbang_recv_buf_contiguous_available_space(); + ssize_t count = read_socket(remote_bitbang_fd, + remote_bitbang_recv_buf + remote_bitbang_recv_buf_end, contiguous_available_space); + if (first && block == BLOCK) + socket_nonblock(remote_bitbang_fd); + first = false; if (count > 0) { - remote_bitbang_end += count; - if (remote_bitbang_end == sizeof(remote_bitbang_buf)) - remote_bitbang_end = 0; + remote_bitbang_recv_buf_end += count; + if (remote_bitbang_recv_buf_end == sizeof(remote_bitbang_recv_buf)) + remote_bitbang_recv_buf_end = 0; } else if (count == 0) { return ERROR_OK; } else if (count < 0) { +#ifdef _WIN32 + if (WSAGetLastError() == WSAEWOULDBLOCK) { +#else if (errno == EAGAIN) { +#endif return ERROR_OK; } else { - LOG_ERROR("remote_bitbang_fill_buf: %s (%d)", - strerror(errno), errno); + log_socket_error("remote_bitbang_fill_buf"); return ERROR_FAIL; } } @@ -86,31 +138,27 @@ static int remote_bitbang_fill_buf(void) return ERROR_OK; } -static int remote_bitbang_putc(int c) +typedef enum { + NO_FLUSH, + FLUSH_SEND_BUF +} flush_bool_t; + +static int remote_bitbang_queue(int c, flush_bool_t flush) { - if (EOF == fputc(c, remote_bitbang_file)) { - LOG_ERROR("remote_bitbang_putc: %s", strerror(errno)); - return ERROR_FAIL; - } + remote_bitbang_send_buf[remote_bitbang_send_buf_used++] = c; + if (flush == FLUSH_SEND_BUF || + remote_bitbang_send_buf_used >= ARRAY_SIZE(remote_bitbang_send_buf)) + return remote_bitbang_flush(); return ERROR_OK; } static int remote_bitbang_quit(void) { - if (EOF == fputc('Q', remote_bitbang_file)) { - LOG_ERROR("fputs: %s", strerror(errno)); - return ERROR_FAIL; - } - - if (EOF == fflush(remote_bitbang_file)) { - LOG_ERROR("fflush: %s", strerror(errno)); + if (remote_bitbang_queue('Q', FLUSH_SEND_BUF) == ERROR_FAIL) return ERROR_FAIL; - } - /* We only need to close one of the FILE*s, because they both use the same */ - /* underlying file descriptor. */ - if (EOF == fclose(remote_bitbang_file)) { - LOG_ERROR("fclose: %s", strerror(errno)); + if (close_socket(remote_bitbang_fd) != 0) { + log_socket_error("close_socket"); return ERROR_FAIL; } @@ -135,71 +183,105 @@ static bb_value_t char_to_int(int c) } } -/* Get the next read response. */ -static bb_value_t remote_bitbang_rread(void) -{ - if (EOF == fflush(remote_bitbang_file)) { - remote_bitbang_quit(); - LOG_ERROR("fflush: %s", strerror(errno)); - return BB_ERROR; - } - - /* Enable blocking access. */ - socket_block(remote_bitbang_fd); - char c; - ssize_t count = read(remote_bitbang_fd, &c, 1); - if (count == 1) { - return char_to_int(c); - } else { - remote_bitbang_quit(); - LOG_ERROR("read: count=%d, error=%s", (int) count, strerror(errno)); - return BB_ERROR; - } -} - static int remote_bitbang_sample(void) { - if (remote_bitbang_fill_buf() != ERROR_OK) + if (remote_bitbang_fill_buf(NO_BLOCK) != ERROR_OK) return ERROR_FAIL; - assert(!remote_bitbang_buf_full()); - return remote_bitbang_putc('R'); + assert(!remote_bitbang_recv_buf_full()); + return remote_bitbang_queue('R', NO_FLUSH); } static bb_value_t remote_bitbang_read_sample(void) { - if (remote_bitbang_start != remote_bitbang_end) { - int c = remote_bitbang_buf[remote_bitbang_start]; - remote_bitbang_start = - (remote_bitbang_start + 1) % sizeof(remote_bitbang_buf); - return char_to_int(c); + if (remote_bitbang_recv_buf_empty()) { + if (remote_bitbang_fill_buf(BLOCK) != ERROR_OK) + return BB_ERROR; } - return remote_bitbang_rread(); + assert(!remote_bitbang_recv_buf_empty()); + int c = remote_bitbang_recv_buf[remote_bitbang_recv_buf_start]; + remote_bitbang_recv_buf_start = + (remote_bitbang_recv_buf_start + 1) % sizeof(remote_bitbang_recv_buf); + return char_to_int(c); } static int remote_bitbang_write(int tck, int tms, int tdi) { char c = '0' + ((tck ? 0x4 : 0x0) | (tms ? 0x2 : 0x0) | (tdi ? 0x1 : 0x0)); - return remote_bitbang_putc(c); + return remote_bitbang_queue(c, NO_FLUSH); } static int remote_bitbang_reset(int trst, int srst) { char c = 'r' + ((trst ? 0x2 : 0x0) | (srst ? 0x1 : 0x0)); - return remote_bitbang_putc(c); + /* Always flush the send buffer on reset, because the reset call need not be + * followed by jtag_execute_queue(). */ + 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('Z', NO_FLUSH); + if (tmp != ERROR_OK) + return tmp; + } + + for (unsigned int i = 0; i < us; i++) { + tmp = remote_bitbang_queue('z', 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_putc(c); + 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_buf) - 1, + .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) @@ -224,7 +306,7 @@ static int remote_bitbang_init_tcp(void) If socket(2) (or connect(2)) fails, we (close the socket and) try the next address. */ - for (rp = result; rp != NULL ; rp = rp->ai_next) { + for (rp = result; rp ; rp = rp->ai_next) { fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (fd == -1) continue; @@ -235,10 +317,17 @@ static int remote_bitbang_init_tcp(void) close(fd); } + /* We work hard to collapse the writes into the minimum number, so when + * we write something we want to get it to the other end of the + * connection as fast as possible. */ + int one = 1; + /* On Windows optval has to be a const char *. */ + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one)); + freeaddrinfo(result); /* No longer needed */ - if (rp == NULL) { /* No address succeeded */ - LOG_ERROR("Failed to connect: %s", strerror(errno)); + if (!rp) { /* No address succeeded */ + log_socket_error("Failed to connect"); return ERROR_FAIL; } @@ -247,7 +336,7 @@ static int remote_bitbang_init_tcp(void) static int remote_bitbang_init_unix(void) { - if (remote_bitbang_host == NULL) { + if (!remote_bitbang_host) { LOG_ERROR("host/socket not specified"); return ERROR_FAIL; } @@ -255,7 +344,7 @@ static int remote_bitbang_init_unix(void) LOG_INFO("Connecting to unix socket %s", remote_bitbang_host); int fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { - LOG_ERROR("socket: %s", strerror(errno)); + log_socket_error("socket"); return ERROR_FAIL; } @@ -265,7 +354,7 @@ static int remote_bitbang_init_unix(void) addr.sun_path[sizeof(addr.sun_path)-1] = '\0'; if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { - LOG_ERROR("connect: %s", strerror(errno)); + log_socket_error("connect"); return ERROR_FAIL; } @@ -276,11 +365,11 @@ static int remote_bitbang_init(void) { bitbang_interface = &remote_bitbang_bitbang; - remote_bitbang_start = 0; - remote_bitbang_end = 0; + remote_bitbang_recv_buf_start = 0; + remote_bitbang_recv_buf_end = 0; LOG_INFO("Initializing remote_bitbang driver"); - if (remote_bitbang_port == NULL) + if (!remote_bitbang_port) remote_bitbang_fd = remote_bitbang_init_unix(); else remote_bitbang_fd = remote_bitbang_init_tcp(); @@ -288,12 +377,7 @@ static int remote_bitbang_init(void) if (remote_bitbang_fd < 0) return remote_bitbang_fd; - remote_bitbang_file = fdopen(remote_bitbang_fd, "w+"); - if (remote_bitbang_file == NULL) { - LOG_ERROR("fdopen: failed to open write stream"); - close(remote_bitbang_fd); - return ERROR_FAIL; - } + socket_nonblock(remote_bitbang_fd); LOG_INFO("remote_bitbang driver initialized"); return ERROR_OK; @@ -321,9 +405,21 @@ COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_host_command) return ERROR_COMMAND_SYNTAX_ERROR; } -static const struct command_registration remote_bitbang_command_handlers[] = { +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 = "remote_bitbang_port", + .name = "port", .handler = remote_bitbang_handle_remote_bitbang_port_command, .mode = COMMAND_CONFIG, .help = "Set the port to use to connect to the remote jtag.\n" @@ -331,23 +427,57 @@ static const struct command_registration remote_bitbang_command_handlers[] = { .usage = "port_number", }, { - .name = "remote_bitbang_host", + .name = "host", .handler = remote_bitbang_handle_remote_bitbang_host_command, .mode = COMMAND_CONFIG, .help = "Set the host to use to connect to the remote jtag.\n" " 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[] = { + { + .name = "remote_bitbang", + .mode = COMMAND_ANY, + .help = "perform remote_bitbang management", + .chain = remote_bitbang_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE }; +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(cmd_queue); + if (ret != ERROR_OK) + return ret; + + /* flush not-yet-sent characters, if any */ + return remote_bitbang_flush(); +} + static struct jtag_interface remote_bitbang_interface = { - .execute_queue = &bitbang_execute_queue, + .execute_queue = &remote_bitbang_execute_queue, }; 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, @@ -355,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 be4ad08bf2..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 @@ -29,11 +18,12 @@ /* project specific includes */ #include <jtag/interface.h> #include <jtag/commands.h> +#include "helper/replacements.h" #include "rlink.h" #include "rlink_st7.h" #include "rlink_ep1_cmd.h" #include "rlink_dtc_cmd.h" -#include "usb_common.h" +#include "libusb_helper.h" /* This feature is made useless by running the DTC all the time. When automatic, the LED is on *whenever the DTC is running. Otherwise, USB messages are sent to turn it on and off. */ @@ -58,8 +48,6 @@ #define USB_EP2IN_SIZE (USB_EP2OUT_SIZE) #define USB_EP2BANK_SIZE (512) -#define USB_TIMEOUT_MS (3 * 1000) - #define DTC_STATUS_POLL_BYTE (ST7_USB_BUF_EP0OUT + 0xff) #define ST7_PD_NBUSY_LED ST7_PD0 @@ -96,19 +84,20 @@ #define ST7_PC_TDO ST7_PC_IO9 #define ST7_PA_DBGACK ST7_PA_IO10 -static usb_dev_handle *pHDev; +static struct libusb_device_handle *hdev; /* * ep1 commands are up to USB_EP1OUT_SIZE bytes in length. * This function takes care of zeroing the unused bytes before sending the packet. * Any reply packet is not handled by this function. */ -static int ep1_generic_commandl(usb_dev_handle *pHDev_param, size_t length, ...) +static int ep1_generic_commandl(struct libusb_device_handle *hdev_param, size_t length, ...) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; uint8_t *usb_buffer_p; va_list ap; int usb_ret; + int transferred; if (length > sizeof(usb_buffer)) length = sizeof(usb_buffer); @@ -127,25 +116,29 @@ static int ep1_generic_commandl(usb_dev_handle *pHDev_param, size_t length, ...) sizeof(usb_buffer) - (usb_buffer_p - usb_buffer) ); - usb_ret = usb_bulk_write( - pHDev_param, + usb_ret = jtag_libusb_bulk_write( + hdev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); - return usb_ret; + if (usb_ret != ERROR_OK) + return usb_ret; + return transferred; } #if 0 static ssize_t ep1_memory_read( - usb_dev_handle *pHDev, uint16_t addr, + struct libusb_device_handle *hdev_param, uint16_t addr, size_t length, uint8_t *buffer) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; int usb_ret; size_t remain; ssize_t count; + int transferred; usb_buffer[0] = EP1_CMD_MEMORY_READ; memset( @@ -167,22 +160,24 @@ static ssize_t ep1_memory_read( usb_buffer[2] = addr; usb_buffer[3] = length; - usb_ret = usb_bulk_write( - pHDev, USB_EP1OUT_ADDR, - usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS + usb_ret = jtag_libusb_bulk_write( + hdev_param, USB_EP1OUT_ADDR, + (char *)usb_buffer, sizeof(usb_buffer), + LIBUSB_TIMEOUT_MS, + &transferred ); - if (usb_ret < sizeof(usb_buffer)) + if (usb_ret != ERROR_OK || transferred < (int)sizeof(usb_buffer)) break; - usb_ret = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, - buffer, length, - USB_TIMEOUT_MS + usb_ret = jtag_libusb_bulk_read( + hdev_param, USB_EP1IN_ADDR, + (char *)buffer, length, + LIBUSB_TIMEOUT_MS, + &transferred ); - if (usb_ret < length) + if (usb_ret != ERROR_OK || transferred < (int)length) break; addr += length; @@ -195,7 +190,7 @@ static ssize_t ep1_memory_read( } #endif -static ssize_t ep1_memory_write(usb_dev_handle *pHDev_param, uint16_t addr, +static ssize_t ep1_memory_write(struct libusb_device_handle *hdev_param, uint16_t addr, size_t length, uint8_t const *buffer) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; @@ -228,13 +223,16 @@ static ssize_t ep1_memory_write(usb_dev_handle *pHDev_param, uint16_t addr, sizeof(usb_buffer) - 4 - length ); - usb_ret = usb_bulk_write( - pHDev_param, USB_EP1OUT_ADDR, + int transferred; + + usb_ret = jtag_libusb_bulk_write( + hdev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); - if ((size_t)usb_ret < sizeof(usb_buffer)) + if (usb_ret != ERROR_OK || transferred < (int)sizeof(usb_buffer)) break; addr += length; @@ -248,7 +246,7 @@ static ssize_t ep1_memory_write(usb_dev_handle *pHDev_param, uint16_t addr, #if 0 -static ssize_t ep1_memory_writel(usb_dev_handle *pHDev, uint16_t addr, +static ssize_t ep1_memory_writel(struct libusb_device_handle *hdev_param, uint16_t addr, size_t length, ...) { uint8_t buffer[USB_EP1OUT_SIZE - 4]; @@ -268,7 +266,7 @@ static ssize_t ep1_memory_writel(usb_dev_handle *pHDev, uint16_t addr, remain--; } - return ep1_memory_write(pHDev, addr, length, buffer); + return ep1_memory_write(hdev_param, addr, length, buffer); } #endif @@ -285,7 +283,7 @@ static ssize_t ep1_memory_writel(usb_dev_handle *pHDev, uint16_t addr, static uint8_t dtc_entry_download; /* The buffer is specially formatted to represent a valid image to load into the DTC. */ -static int dtc_load_from_buffer(usb_dev_handle *pHDev_param, const uint8_t *buffer, +static int dtc_load_from_buffer(struct libusb_device_handle *hdev_param, const uint8_t *buffer, size_t length) { struct header_s { @@ -301,7 +299,7 @@ static int dtc_load_from_buffer(usb_dev_handle *pHDev_param, const uint8_t *buff /* Stop the DTC before loading anything. */ usb_err = ep1_generic_commandl( - pHDev_param, 1, + hdev_param, 1, EP1_CMD_DTC_STOP ); if (usb_err < 0) @@ -335,7 +333,7 @@ static int dtc_load_from_buffer(usb_dev_handle *pHDev_param, const uint8_t *buff case DTCLOAD_LOAD: /* Send the DTC program to ST7 RAM. */ usb_err = ep1_memory_write( - pHDev_param, + hdev_param, DTC_LOAD_BUFFER, header->length + 1, buffer ); @@ -344,7 +342,7 @@ static int dtc_load_from_buffer(usb_dev_handle *pHDev_param, const uint8_t *buff /* Load it into the DTC. */ usb_err = ep1_generic_commandl( - pHDev_param, 3, + hdev_param, 3, EP1_CMD_DTC_LOAD, (DTC_LOAD_BUFFER >> 8), DTC_LOAD_BUFFER @@ -356,7 +354,7 @@ static int dtc_load_from_buffer(usb_dev_handle *pHDev_param, const uint8_t *buff case DTCLOAD_RUN: usb_err = ep1_generic_commandl( - pHDev_param, 3, + hdev_param, 3, EP1_CMD_DTC_CALL, buffer[0], EP1_CMD_DTC_WAIT @@ -372,7 +370,7 @@ static int dtc_load_from_buffer(usb_dev_handle *pHDev_param, const uint8_t *buff case DTCLOAD_LUT: usb_err = ep1_memory_write( - pHDev_param, + hdev_param, ST7_USB_BUF_EP0OUT + lut_start, header->length + 1, buffer ); @@ -400,10 +398,11 @@ static int dtc_start_download(void) { int usb_err; uint8_t ep2txr; + int transferred; /* set up for download mode and make sure EP2 is set up to transmit */ usb_err = ep1_generic_commandl( - pHDev, 7, + hdev, 7, EP1_CMD_DTC_STOP, EP1_CMD_SET_UPLOAD, @@ -417,16 +416,17 @@ static int dtc_start_download(void) return usb_err; /* read back ep2txr */ - usb_err = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, + usb_err = jtag_libusb_bulk_read( + hdev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); - if (usb_err < 0) + if (usb_err != ERROR_OK) return usb_err; usb_err = ep1_generic_commandl( - pHDev, 13, + hdev, 13, EP1_CMD_MEMORY_WRITE, /* preinitialize poll byte */ DTC_STATUS_POLL_BYTE >> 8, @@ -446,17 +446,18 @@ static int dtc_start_download(void) return usb_err; /* wait for completion */ - usb_err = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, + usb_err = jtag_libusb_bulk_read( + hdev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); return usb_err; } static int dtc_run_download( - usb_dev_handle *pHDev_param, + struct libusb_device_handle *hdev_param, uint8_t *command_buffer, int command_buffer_size, uint8_t *reply_buffer, @@ -466,14 +467,16 @@ static int dtc_run_download( char dtc_status; int usb_err; int i; + int transferred; LOG_DEBUG("%d/%d", command_buffer_size, reply_buffer_size); - usb_err = usb_bulk_write( - pHDev_param, + usb_err = jtag_libusb_bulk_write( + hdev_param, USB_EP2OUT_ADDR, (char *)command_buffer, USB_EP2BANK_SIZE, - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); if (usb_err < 0) return usb_err; @@ -482,7 +485,7 @@ static int dtc_run_download( /* Wait for DTC to finish running command buffer */ for (i = 50;; ) { usb_err = ep1_generic_commandl( - pHDev_param, 4, + hdev_param, 4, EP1_CMD_MEMORY_READ, DTC_STATUS_POLL_BYTE >> 8, @@ -492,11 +495,12 @@ static int dtc_run_download( if (usb_err < 0) return usb_err; - usb_err = usb_bulk_read( - pHDev_param, + usb_err = jtag_libusb_bulk_read( + hdev_param, USB_EP1IN_ADDR, &dtc_status, 1, - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); if (usb_err < 0) return usb_err; @@ -506,20 +510,21 @@ static int dtc_run_download( if (!--i) { LOG_ERROR("too many retries waiting for DTC status"); - return -ETIMEDOUT; + return LIBUSB_ERROR_TIMEOUT; } } if (reply_buffer && reply_buffer_size) { - usb_err = usb_bulk_read( - pHDev_param, + usb_err = jtag_libusb_bulk_read( + hdev_param, USB_EP2IN_ADDR, (char *)reply_buffer, reply_buffer_size, - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); - if (usb_err < reply_buffer_size) { + if (usb_err != ERROR_OK || transferred < reply_buffer_size) { LOG_ERROR("Read of endpoint 2 returned %d, expected %d", usb_err, reply_buffer_size ); @@ -590,7 +595,7 @@ static inline struct dtc_reply_queue_entry *dtc_queue_enqueue_reply( struct dtc_reply_queue_entry *rq_entry; rq_entry = malloc(sizeof(struct dtc_reply_queue_entry)); - if (rq_entry != NULL) { + if (rq_entry) { rq_entry->scan.type = type; rq_entry->scan.buffer = buffer; rq_entry->scan.size = size; @@ -599,7 +604,7 @@ static inline struct dtc_reply_queue_entry *dtc_queue_enqueue_reply( rq_entry->cmd = cmd; rq_entry->next = NULL; - if (dtc_queue.rq_head == NULL) + if (!dtc_queue.rq_head) dtc_queue.rq_head = rq_entry; else dtc_queue.rq_tail->next = rq_entry; @@ -627,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); @@ -638,16 +643,16 @@ static int dtc_queue_run(void) dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_STOP; - usb_err = dtc_run_download(pHDev, + usb_err = dtc_run_download(hdev, dtc_queue.cmd_buffer, dtc_queue.cmd_index, reply_buffer, sizeof(reply_buffer) ); if (usb_err < 0) { - LOG_ERROR("dtc_run_download: %s", usb_strerror()); + LOG_ERROR("dtc_run_download: %s", libusb_error_name(usb_err)); exit(1); } - if (dtc_queue.rq_head != NULL) { + if (dtc_queue.rq_head) { /* process the reply, which empties the reply queue and frees its entries */ dtc_p = reply_buffer; @@ -659,7 +664,7 @@ static int dtc_queue_run(void) for ( rq_p = dtc_queue.rq_head; - rq_p != NULL; + rq_p; rq_p = rq_next ) { tdo_p = rq_p->scan.buffer + (rq_p->scan.offset / 8); @@ -918,27 +923,29 @@ static void rlink_reset(int trst, int srst) { uint8_t bitmap; int usb_err; + int transferred; /* Read port A for bit op */ usb_err = ep1_generic_commandl( - pHDev, 4, + hdev, 4, EP1_CMD_MEMORY_READ, ST7_PADR >> 8, ST7_PADR, 1 ); if (usb_err < 0) { - LOG_ERROR("%s", usb_strerror()); + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } - usb_err = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, + usb_err = jtag_libusb_bulk_read( + hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); - if (usb_err < 1) { - LOG_ERROR("%s", usb_strerror()); + if (usb_err != ERROR_OK || transferred < 1) { + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } @@ -951,7 +958,7 @@ static void rlink_reset(int trst, int srst) * port B has no OR, and we want to emulate open drain on NSRST, so we initialize DR to 0 *and assert NSRST by setting DDR to 1. */ usb_err = ep1_generic_commandl( - pHDev, 9, + hdev, 9, EP1_CMD_MEMORY_WRITE, ST7_PADR >> 8, ST7_PADR, @@ -963,17 +970,18 @@ static void rlink_reset(int trst, int srst) 1 ); if (usb_err < 0) { - LOG_ERROR("%s", usb_strerror()); + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } - usb_err = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, + usb_err = jtag_libusb_bulk_read( + hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); - if (usb_err < 1) { - LOG_ERROR("%s", usb_strerror()); + if (usb_err != ERROR_OK || transferred < 1) { + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } @@ -984,7 +992,7 @@ static void rlink_reset(int trst, int srst) /* write port B and read dummy to ensure completion before returning */ usb_err = ep1_generic_commandl( - pHDev, 6, + hdev, 6, EP1_CMD_MEMORY_WRITE, ST7_PBDDR >> 8, ST7_PBDDR, @@ -993,17 +1001,18 @@ static void rlink_reset(int trst, int srst) EP1_CMD_DTC_GET_CACHED_STATUS ); if (usb_err < 0) { - LOG_ERROR("%s", usb_strerror()); + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } - usb_err = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, + usb_err = jtag_libusb_bulk_read( + hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); - if (usb_err < 1) { - LOG_ERROR("%s", usb_strerror()); + if (usb_err != ERROR_OK || transferred < 1) { + LOG_ERROR("%s", libusb_error_name(usb_err)); exit(1); } } @@ -1126,11 +1135,8 @@ static int rlink_scan(struct jtag_command *cmd, enum scan_type type, byte_bits -= chunk_bits; if (type != SCAN_OUT) { - if (dtc_queue_enqueue_reply( - type, buffer, scan_size, tdi_bit_offset, - chunk_bits, - cmd - ) == NULL) { + if (!dtc_queue_enqueue_reply(type, buffer, scan_size, tdi_bit_offset, + chunk_bits, cmd)) { LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno)); exit(1); } @@ -1186,11 +1192,8 @@ static int rlink_scan(struct jtag_command *cmd, enum scan_type type, * and one reply byte */ dtc_queue_run_if_full(type == SCAN_IN ? 1 : 2, 1); - if (dtc_queue_enqueue_reply( - type, buffer, scan_size, tdi_bit_offset, - extra_bits, - cmd - ) == NULL) { + if (!dtc_queue_enqueue_reply(type, buffer, scan_size, tdi_bit_offset, + extra_bits, cmd)) { LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno)); exit(1); } @@ -1238,11 +1241,8 @@ static int rlink_scan(struct jtag_command *cmd, enum scan_type type, DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 0); } else { - if (dtc_queue_enqueue_reply( - type, buffer, scan_size, tdi_bit_offset, - 1, - cmd - ) == NULL) { + if (!dtc_queue_enqueue_reply(type, buffer, scan_size, tdi_bit_offset, + 1, cmd)) { LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno)); exit(1); } @@ -1262,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; @@ -1275,7 +1275,7 @@ static int rlink_execute_queue(void) #ifndef AUTOMATIC_BUSY_LED /* turn LED on */ - ep1_generic_commandl(pHDev, 2, + ep1_generic_commandl(hdev, 2, EP1_CMD_SET_PORTD_LEDS, ~(ST7_PD_NBUSY_LED) ); @@ -1359,7 +1359,7 @@ static int rlink_execute_queue(void) #ifndef AUTOMATIC_BUSY_LED /* turn LED off */ - ep1_generic_commandl(pHDev, 2, + ep1_generic_commandl(hdev, 2, EP1_CMD_SET_PORTD_LEDS, ~0 ); @@ -1382,7 +1382,7 @@ static int rlink_speed(int speed) for (i = rlink_speed_table_size; i--; ) { if (rlink_speed_table[i].prescaler == speed) { - if (dtc_load_from_buffer(pHDev, rlink_speed_table[i].dtc, + if (dtc_load_from_buffer(hdev, rlink_speed_table[i].dtc, rlink_speed_table[i].dtc_size) != 0) { LOG_ERROR( "An error occurred while trying to load DTC code for speed \"%d\".", @@ -1390,8 +1390,9 @@ static int rlink_speed(int speed) exit(1); } - if (dtc_start_download() < 0) { - LOG_ERROR("starting DTC: %s", usb_strerror()); + int ret = dtc_start_download(); + if (ret < 0) { + LOG_ERROR("starting DTC: %s", libusb_error_name(ret)); exit(1); } @@ -1443,49 +1444,56 @@ static int rlink_init(void) { int i, j, retries; uint8_t reply_buffer[USB_EP1IN_SIZE]; + int transferred; - usb_init(); const uint16_t vids[] = { USB_IDVENDOR, 0 }; const uint16_t pids[] = { USB_IDPRODUCT, 0 }; - if (jtag_usb_open(vids, pids, &pHDev) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &hdev, NULL) != ERROR_OK) + return ERROR_FAIL; + + struct libusb_device_descriptor descriptor; + struct libusb_device *usb_dev = libusb_get_device(hdev); + int r = libusb_get_device_descriptor(usb_dev, &descriptor); + if (r < 0) { + LOG_ERROR("error %d getting device descriptor", r); return ERROR_FAIL; + } - struct usb_device *dev = usb_device(pHDev); - if (dev->descriptor.bNumConfigurations > 1) { + if (descriptor.bNumConfigurations > 1) { LOG_ERROR("Whoops! NumConfigurations is not 1, don't know what to do..."); return ERROR_FAIL; } - if (dev->config->bNumInterfaces > 1) { + struct libusb_config_descriptor *config; + libusb_get_config_descriptor(usb_dev, 0, &config); + if (config->bNumInterfaces > 1) { LOG_ERROR("Whoops! NumInterfaces is not 1, don't know what to do..."); return ERROR_FAIL; } - LOG_DEBUG("Opened device, pHDev = %p", pHDev); + LOG_DEBUG("Opened device, hdev = %p", hdev); /* usb_set_configuration required under win32 */ - usb_set_configuration(pHDev, dev->config[0].bConfigurationValue); + libusb_set_configuration(hdev, config->bConfigurationValue); retries = 3; do { - i = usb_claim_interface(pHDev, 0); - if (i) { - LOG_ERROR("usb_claim_interface: %s", usb_strerror()); -#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP - j = usb_detach_kernel_driver_np(pHDev, 0); - if (j) - LOG_ERROR("detach kernel driver: %s", usb_strerror()); -#endif + i = libusb_claim_interface(hdev, 0); + if (i != LIBUSB_SUCCESS) { + LOG_ERROR("usb_claim_interface: %s", libusb_error_name(i)); + j = libusb_detach_kernel_driver(hdev, 0); + if (j != LIBUSB_SUCCESS) + LOG_ERROR("detach kernel driver: %s", libusb_error_name(j)); } else { LOG_DEBUG("interface claimed!"); break; } } while (--retries); - if (i) { + if (i != LIBUSB_SUCCESS) { LOG_ERROR("Initialisation failed."); return ERROR_FAIL; } - if (usb_set_altinterface(pHDev, 0) != 0) { + if (libusb_set_interface_alt_setting(hdev, 0, 0) != LIBUSB_SUCCESS) { LOG_ERROR("Failed to set interface."); return ERROR_FAIL; } @@ -1501,24 +1509,25 @@ static int rlink_init(void) */ for (i = 0; i < 5; i++) { j = ep1_generic_commandl( - pHDev, 1, + hdev, 1, EP1_CMD_GET_FWREV ); if (j < USB_EP1OUT_SIZE) { - LOG_ERROR("USB write error: %s", usb_strerror()); + LOG_ERROR("USB write error: %s", libusb_error_name(j)); return ERROR_FAIL; } - j = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, + j = jtag_libusb_bulk_read( + hdev, USB_EP1IN_ADDR, (char *)reply_buffer, sizeof(reply_buffer), - 200 + 200, + &transferred ); - if (j != -ETIMEDOUT) + if (j != LIBUSB_ERROR_TIMEOUT) break; } - if (j < (int)sizeof(reply_buffer)) { - LOG_ERROR("USB read error: %s", usb_strerror()); + if (j != ERROR_OK || transferred != (int)sizeof(reply_buffer)) { + LOG_ERROR("USB read error: %s", libusb_error_name(j)); return ERROR_FAIL; } LOG_DEBUG(INTERFACE_NAME " firmware version: %d.%d.%d", @@ -1532,7 +1541,7 @@ static int rlink_init(void) /* Probe port E for adapter presence */ ep1_generic_commandl( - pHDev, 16, + hdev, 16, EP1_CMD_MEMORY_WRITE, /* Drive sense pin with 0 */ ST7_PEDR >> 8, ST7_PEDR, @@ -1551,17 +1560,18 @@ static int rlink_init(void) ST7_PE_ADAPTER_SENSE_OUT ); - usb_bulk_read( - pHDev, USB_EP1IN_ADDR, + jtag_libusb_bulk_read( + hdev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); if ((reply_buffer[0] & ST7_PE_ADAPTER_SENSE_IN) != 0) LOG_WARNING("target detection problem"); ep1_generic_commandl( - pHDev, 11, + hdev, 11, EP1_CMD_MEMORY_READ, /* Read back */ ST7_PEDR >> 8, ST7_PEDR, @@ -1575,10 +1585,11 @@ static int rlink_init(void) 0x00 /* OR */ ); - usb_bulk_read( - pHDev, USB_EP1IN_ADDR, + jtag_libusb_bulk_read( + hdev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, - USB_TIMEOUT_MS + LIBUSB_TIMEOUT_MS, + &transferred ); @@ -1587,7 +1598,7 @@ static int rlink_init(void) /* float ports A and B */ ep1_generic_commandl( - pHDev, 11, + hdev, 11, EP1_CMD_MEMORY_WRITE, ST7_PADDR >> 8, ST7_PADDR, @@ -1603,7 +1614,7 @@ static int rlink_init(void) /* make sure DTC is stopped, set VPP control, set up ports A and B */ ep1_generic_commandl( - pHDev, 14, + hdev, 14, EP1_CMD_DTC_STOP, EP1_CMD_SET_PORTD_VPP, ~(ST7_PD_VPP_SHDN), @@ -1624,7 +1635,7 @@ static int rlink_init(void) /* set LED updating mode and make sure they're unlit */ ep1_generic_commandl( - pHDev, 3, + hdev, 3, #ifdef AUTOMATIC_BUSY_LED EP1_CMD_LEDUE_BUSY, #else @@ -1645,7 +1656,7 @@ static int rlink_quit(void) { /* stop DTC and make sure LEDs are off */ ep1_generic_commandl( - pHDev, 6, + hdev, 6, EP1_CMD_DTC_STOP, EP1_CMD_LEDUE_NONE, EP1_CMD_SET_PORTD_LEDS, @@ -1654,8 +1665,8 @@ static int rlink_quit(void) ~0 ); - usb_release_interface(pHDev, 0); - usb_close(pHDev); + libusb_release_interface(hdev, 0); + libusb_close(hdev); return ERROR_OK; } diff --git a/src/jtag/drivers/rlink.h b/src/jtag/drivers/rlink.h index 74b62580c2..38f8429b06 100644 --- a/src/jtag/drivers/rlink.h +++ b/src/jtag/drivers/rlink.h @@ -1,24 +1,14 @@ +/* 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 #define OPENOCD_JTAG_DRIVERS_RLINK_H +#include "helper/types.h" struct rlink_speed_table { uint8_t const *dtc; uint16_t dtc_size; 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 ce55b94a55..b14fbf1f38 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -1,4 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** + * Copyright (C) 2020 by Tarek Bochkati * + * Tarek Bochkati <tarek.bouchkati@gmail.com> * + * * * SWIM contributions by Ake Rehnman * * Copyright (C) 2017 Ake Rehnman * * ake.rehnman(at)gmail.com * @@ -10,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 @@ -30,18 +22,33 @@ #endif /* project specific includes */ +#include <helper/align.h> #include <helper/binarybuffer.h> #include <helper/bits.h> +#include <helper/system.h> +#include <helper/time_support.h> +#include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/hla/hla_layout.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> #include <jtag/swim.h> +#include <target/arm_adi_v5.h> #include <target/target.h> #include <transport/transport.h> #include <target/cortex_m.h> +#include <helper/system.h> + +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif + #include "libusb_helper.h" #ifdef HAVE_LIBUSB1 @@ -53,8 +60,8 @@ #define ENDPOINT_IN 0x80 #define ENDPOINT_OUT 0x00 -#define STLINK_WRITE_TIMEOUT 1000 -#define STLINK_READ_TIMEOUT 1000 +#define STLINK_WRITE_TIMEOUT (LIBUSB_TIMEOUT_MS) +#define STLINK_READ_TIMEOUT (LIBUSB_TIMEOUT_MS) #define STLINK_RX_EP (1|ENDPOINT_IN) #define STLINK_TX_EP (2|ENDPOINT_OUT) @@ -64,7 +71,7 @@ #define STLINK_V2_1_TRACE_EP (2|ENDPOINT_IN) #define STLINK_SG_SIZE (31) -#define STLINK_DATA_SIZE (4096) +#define STLINK_DATA_SIZE (6144) #define STLINK_CMD_SIZE_V2 (16) #define STLINK_CMD_SIZE_V1 (10) @@ -76,20 +83,34 @@ #define STLINK_V3E_PID (0x374E) #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 * this limits the bulk packet size and the 8bit read/writes to max 64 bytes. * STLINK-V3 is a high speed USB 2.0 and the limit is 512 bytes from FW V3J6. + * + * For 16 and 32bit read/writes stlink handles USB packet split and the limit + * is the internal buffer size of 6144 bytes. + * TODO: override ADIv5 layer's tar_autoincr_block that limits the transfer + * to 1024 or 4096 bytes */ -#define STLINK_MAX_RW8 (64) -#define STLINKV3_MAX_RW8 (512) +#define STLINK_MAX_RW8 (64) +#define STLINKV3_MAX_RW8 (512) +#define STLINK_MAX_RW16_32 STLINK_DATA_SIZE +#define STLINK_SWIM_DATA_SIZE STLINK_DATA_SIZE /* "WAIT" responses will be retried (with exponential backoff) at * most this many times before failing to caller. */ #define MAX_WAIT_RETRIES 8 +/* HLA is currently limited at AP#0 and no control on CSW */ +#define STLINK_HLA_AP_NUM 0 +#define STLINK_HLA_CSW 0 + enum stlink_jtag_api_version { STLINK_JTAG_API_V1 = 1, STLINK_JTAG_API_V2, @@ -119,12 +140,119 @@ struct stlink_usb_version { uint32_t flags; }; -/** */ -struct stlink_usb_handle_s { +struct stlink_usb_priv_s { /** */ struct libusb_device_handle *fd; /** */ struct libusb_transfer *trans; +}; + +struct stlink_tcp_version { + uint32_t api; + uint32_t major; + uint32_t minor; + uint32_t build; +}; + +struct stlink_tcp_priv_s { + /** */ + int fd; + /** */ + bool connected; + /** */ + uint32_t device_id; + /** */ + uint32_t connect_id; + /** */ + uint8_t *send_buf; + /** */ + uint8_t *recv_buf; + /** */ + struct stlink_tcp_version version; +}; + +struct stlink_backend_s { + /** */ + int (*open)(void *handle, struct hl_interface_param_s *param); + /** */ + int (*close)(void *handle); + /** */ + int (*xfer_noerrcheck)(void *handle, const uint8_t *buf, int size); + /** */ + int (*read_trace)(void *handle, const uint8_t *buf, int size); +}; + +/* TODO: make queue size dynamic */ +/* TODO: don't allocate queue for HLA */ +#define MAX_QUEUE_DEPTH (4096) + +enum queue_cmd { + CMD_DP_READ = 1, + CMD_DP_WRITE, + + CMD_AP_READ, + CMD_AP_WRITE, + + /* + * encode the bytes size in the enum's value. This makes easy to extract it + * with a simple logic AND, by using the macro CMD_MEM_AP_2_SIZE() below + */ + CMD_MEM_AP_READ8 = 0x10 + 1, + CMD_MEM_AP_READ16 = 0x10 + 2, + CMD_MEM_AP_READ32 = 0x10 + 4, + + CMD_MEM_AP_WRITE8 = 0x20 + 1, + CMD_MEM_AP_WRITE16 = 0x20 + 2, + CMD_MEM_AP_WRITE32 = 0x20 + 4, +}; + +#define CMD_MEM_AP_2_SIZE(cmd) ((cmd) & 7) + +struct dap_queue { + enum queue_cmd cmd; + union { + struct dp_r { + unsigned int reg; + struct adiv5_dap *dap; + uint32_t *p_data; + } dp_r; + struct dp_w { + unsigned int reg; + struct adiv5_dap *dap; + uint32_t data; + } dp_w; + struct ap_r { + unsigned int reg; + struct adiv5_ap *ap; + uint32_t *p_data; + } ap_r; + struct ap_w { + unsigned int reg; + struct adiv5_ap *ap; + uint32_t data; + bool changes_csw_default; + } ap_w; + struct mem_ap { + uint32_t addr; + struct adiv5_ap *ap; + union { + uint32_t *p_data; + uint32_t data; + }; + uint32_t csw; + } mem_ap; + }; +}; + +/** */ +struct stlink_usb_handle_s { + /** */ + struct stlink_backend_s *backend; + /** */ + union { + struct stlink_usb_priv_s usb_backend_priv; + struct stlink_tcp_priv_s tcp_backend_priv; + }; /** */ uint8_t rx_ep; /** */ @@ -132,13 +260,13 @@ struct stlink_usb_handle_s { /** */ uint8_t trace_ep; /** */ - uint8_t cmdbuf[STLINK_SG_SIZE]; + uint8_t *cmdbuf; /** */ uint8_t cmdidx; /** */ uint8_t direction; /** */ - uint8_t databuf[STLINK_DATA_SIZE]; + uint8_t *databuf; /** */ uint32_t max_mem_packet; /** */ @@ -159,8 +287,32 @@ struct stlink_usb_handle_s { /** reconnect is needed next time we try to query the * status */ bool reconnect_pending; + /** queue of dap_direct operations */ + struct dap_queue queue[MAX_QUEUE_DEPTH]; + /** first element available in the queue */ + unsigned int queue_index; }; +/** */ +static inline int stlink_usb_open(void *handle, struct hl_interface_param_s *param) +{ + struct stlink_usb_handle_s *h = handle; + return h->backend->open(handle, param); +} + +/** */ +static inline int stlink_usb_close(void *handle) +{ + struct stlink_usb_handle_s *h = handle; + return h->backend->close(handle); +} +/** */ +static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) +{ + struct stlink_usb_handle_s *h = handle; + return h->backend->xfer_noerrcheck(handle, buf, size); +} + #define STLINK_SWIM_ERR_OK 0x00 #define STLINK_SWIM_BUSY 0x01 #define STLINK_DEBUG_ERR_OK 0x80 @@ -286,6 +438,12 @@ struct stlink_usb_handle_s { #define STLINK_DEBUG_APIV2_INIT_AP 0x4B #define STLINK_DEBUG_APIV2_CLOSE_AP_DBG 0x4C +#define STLINK_DEBUG_WRITEMEM_32BIT_NO_ADDR_INC 0x50 +#define STLINK_DEBUG_APIV2_RW_MISC_OUT 0x51 +#define STLINK_DEBUG_APIV2_RW_MISC_IN 0x52 + +#define STLINK_DEBUG_READMEM_32BIT_NO_ADDR_INC 0x54 + #define STLINK_APIV3_SET_COM_FREQ 0x61 #define STLINK_APIV3_GET_COM_FREQ 0x62 @@ -298,31 +456,74 @@ struct stlink_usb_handle_s { #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 #define REQUEST_SENSE 0x03 #define REQUEST_SENSE_LENGTH 18 +/* STLINK TCP commands */ +#define STLINK_TCP_CMD_REFRESH_DEVICE_LIST 0x00 +#define STLINK_TCP_CMD_GET_NB_DEV 0x01 +#define STLINK_TCP_CMD_GET_DEV_INFO 0x02 +#define STLINK_TCP_CMD_OPEN_DEV 0x03 +#define STLINK_TCP_CMD_CLOSE_DEV 0x04 +#define STLINK_TCP_CMD_SEND_USB_CMD 0x05 +#define STLINK_TCP_CMD_GET_SERVER_VERSION 0x06 +#define STLINK_TCP_CMD_GET_NB_OF_DEV_CLIENTS 0x07 + +/* STLINK TCP constants */ +#define OPENOCD_STLINK_TCP_API_VERSION 1 +#define STLINK_TCP_REQUEST_WRITE 0 +#define STLINK_TCP_REQUEST_READ 1 +#define STLINK_TCP_REQUEST_READ_SWO 3 +#define STLINK_TCP_SS_SIZE 4 +#define STLINK_TCP_USB_CMD_SIZE 32 +#define STLINK_TCP_SERIAL_SIZE 32 +#define STLINK_TCP_SEND_BUFFER_SIZE 10240 +#define STLINK_TCP_RECV_BUFFER_SIZE 10240 + +/* STLINK TCP command status */ +#define STLINK_TCP_SS_OK 0x00000001 +#define STLINK_TCP_SS_MEMORY_PROBLEM 0x00001000 +#define STLINK_TCP_SS_TIMEOUT 0x00001001 +#define STLINK_TCP_SS_BAD_PARAMETER 0x00001002 +#define STLINK_TCP_SS_OPEN_ERR 0x00001003 +#define STLINK_TCP_SS_TRUNCATED_DATA 0x00001052 +#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 + /* * Map the relevant features, quirks and workaround for specific firmware * version of stlink */ -#define STLINK_F_HAS_TRACE BIT(0) -#define STLINK_F_HAS_SWD_SET_FREQ BIT(1) -#define STLINK_F_HAS_JTAG_SET_FREQ BIT(2) -#define STLINK_F_HAS_MEM_16BIT BIT(3) -#define STLINK_F_HAS_GETLASTRWSTATUS2 BIT(4) -#define STLINK_F_HAS_DAP_REG BIT(5) -#define STLINK_F_QUIRK_JTAG_DP_READ BIT(6) -#define STLINK_F_HAS_AP_INIT BIT(7) -#define STLINK_F_HAS_DPBANKSEL BIT(8) -#define STLINK_F_HAS_RW8_512BYTES BIT(9) -#define STLINK_F_FIX_CLOSE_AP BIT(10) +#define STLINK_F_HAS_TRACE BIT(0) /* v2>=j13 || v3 */ +#define STLINK_F_HAS_GETLASTRWSTATUS2 BIT(1) /* v2>=j15 || v3 */ +#define STLINK_F_HAS_SWD_SET_FREQ BIT(2) /* v2>=j22 */ +#define STLINK_F_HAS_JTAG_SET_FREQ BIT(3) /* v2>=j24 */ +#define STLINK_F_QUIRK_JTAG_DP_READ BIT(4) /* v2>=j24 && v2<j32 */ +#define STLINK_F_HAS_DAP_REG BIT(5) /* v2>=j24 || v3 */ +#define STLINK_F_HAS_MEM_16BIT BIT(6) /* v2>=j26 || v3 */ +#define STLINK_F_HAS_AP_INIT BIT(7) /* v2>=j28 || v3 */ +#define STLINK_F_FIX_CLOSE_AP BIT(8) /* v2>=j29 || v3 */ +#define STLINK_F_HAS_DPBANKSEL BIT(9) /* v2>=j32 || v3>=j2 */ +#define STLINK_F_HAS_RW8_512BYTES BIT(10) /* v3>=j6 */ /* aliases */ #define STLINK_F_HAS_TARGET_VOLT STLINK_F_HAS_TRACE +#define STLINK_F_HAS_FPU_REG STLINK_F_HAS_GETLASTRWSTATUS2 +#define STLINK_F_HAS_MEM_WR_NO_INC STLINK_F_HAS_MEM_16BIT +#define STLINK_F_HAS_MEM_RD_NO_INC STLINK_F_HAS_DPBANKSEL +#define STLINK_F_HAS_RW_MISC STLINK_F_HAS_DPBANKSEL +#define STLINK_F_HAS_CSW STLINK_F_HAS_DPBANKSEL + +#define STLINK_REGSEL_IS_FPU(x) ((x) > 0x1F) struct speed_map { int speed; @@ -358,7 +559,7 @@ static const struct speed_map stlink_khz_to_speed_map_jtag[] = { static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size); static int stlink_swim_status(void *handle); -void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size); +static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size); static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map); static int stlink_speed(void *handle, int khz, bool query); static int stlink_usb_open_ap(void *handle, unsigned short apsel); @@ -368,7 +569,7 @@ static unsigned int stlink_usb_block(void *handle) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (h->version.flags & STLINK_F_HAS_RW8_512BYTES) return STLINKV3_MAX_RW8; @@ -376,8 +577,6 @@ static unsigned int stlink_usb_block(void *handle) return STLINK_MAX_RW8; } - - #ifdef USE_LIBUSB_ASYNCIO static LIBUSB_CALL void sync_transfer_cb(struct libusb_transfer *transfer) @@ -392,13 +591,8 @@ static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer) { int r, *completed = transfer->user_data; - /* Assuming a single libusb context exists. There no existing interface into this - * module to pass a libusb context. - */ - struct libusb_context *ctx = NULL; - while (!*completed) { - r = libusb_handle_events_completed(ctx, completed); + r = jtag_libusb_handle_events_completed(completed); if (r < 0) { if (r == LIBUSB_ERROR_INTERRUPTED) continue; @@ -468,7 +662,7 @@ static int jtag_libusb_bulk_transfer_n( transfers[i].transfer_size = 0; transfers[i].transfer = libusb_alloc_transfer(0); - if (transfers[i].transfer == NULL) { + if (!transfers[i].transfer) { for (size_t j = 0; j < i; ++j) libusb_free_transfer(transfers[j].transfer); @@ -536,12 +730,12 @@ static int stlink_usb_xfer_v1_get_status(void *handle) struct stlink_usb_handle_s *h = handle; int tr, ret; - assert(handle != NULL); + assert(handle); /* read status */ memset(h->cmdbuf, 0, STLINK_SG_SIZE); - ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf, 13, + ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)h->cmdbuf, 13, STLINK_READ_TIMEOUT, &tr); if (ret || tr != 13) return ERROR_FAIL; @@ -570,7 +764,7 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); size_t n_transfers = 0; struct jtag_xfer transfers[2]; @@ -598,7 +792,7 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int } return jtag_libusb_bulk_transfer_n( - h->fd, + h->usb_backend_priv.fd, transfers, n_transfers, STLINK_WRITE_TIMEOUT); @@ -609,22 +803,22 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int struct stlink_usb_handle_s *h = handle; int tr, ret; - assert(handle != NULL); + assert(handle); - ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf, + ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)h->cmdbuf, cmdsize, STLINK_WRITE_TIMEOUT, &tr); if (ret || tr != cmdsize) return ERROR_FAIL; if (h->direction == h->tx_ep && size) { - ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf, + ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)buf, size, STLINK_WRITE_TIMEOUT, &tr); if (ret || tr != size) { LOG_DEBUG("bulk write failed"); return ERROR_FAIL; } } else if (h->direction == h->rx_ep && size) { - ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf, + ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)buf, size, STLINK_READ_TIMEOUT, &tr); if (ret || tr != size) { LOG_DEBUG("bulk read failed"); @@ -642,7 +836,7 @@ static int stlink_usb_xfer_v1_get_sense(void *handle) int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 16); @@ -663,18 +857,34 @@ static int stlink_usb_xfer_v1_get_sense(void *handle) return ERROR_OK; } +/** */ +static int stlink_usb_usb_read_trace(void *handle, const uint8_t *buf, int size) +{ + struct stlink_usb_handle_s *h = handle; + int tr, ret; + + ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->trace_ep, (char *)buf, size, + STLINK_READ_TIMEOUT, &tr); + if (ret || tr != size) { + LOG_ERROR("bulk trace read failed"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + /* transfers block in cmdbuf <size> indicates number of bytes in the following data phase. Ignore the (eventual) error code in the received packet. */ -static int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) +static int stlink_usb_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) { int err, cmdsize = STLINK_CMD_SIZE_V2; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (h->version.stlink == 1) { cmdsize = STLINK_SG_SIZE; @@ -702,6 +912,140 @@ static int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size return ERROR_OK; } + +static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool check_tcp_status) +{ + struct stlink_usb_handle_s *h = handle; + + assert(handle); + + /* send the TCP command */ + int sent_size = send(h->tcp_backend_priv.fd, (void *)h->tcp_backend_priv.send_buf, send_size, 0); + if (sent_size != send_size) { + LOG_ERROR("failed to send USB CMD"); + if (sent_size == -1) + LOG_DEBUG("socket send error: %s (errno %d)", strerror(errno), errno); + else + LOG_DEBUG("sent size %d (expected %d)", sent_size, send_size); + return ERROR_FAIL; + } + + /* read the TCP response */ + int retval = ERROR_OK; + int remaining_bytes = recv_size; + uint8_t *recv_buf = h->tcp_backend_priv.recv_buf; + const int64_t timeout = timeval_ms() + 1000; /* 1 second */ + + while (remaining_bytes > 0) { + if (timeval_ms() > timeout) { + LOG_DEBUG("received size %d (expected %d)", recv_size - remaining_bytes, recv_size); + retval = ERROR_TIMEOUT_REACHED; + break; + } + + keep_alive(); + int received = recv(h->tcp_backend_priv.fd, (void *)recv_buf, remaining_bytes, 0); + + if (received == -1) { + LOG_DEBUG("socket recv error: %s (errno %d)", strerror(errno), errno); + retval = ERROR_FAIL; + break; + } + + recv_buf += received; + remaining_bytes -= received; + } + + if (retval != ERROR_OK) { + LOG_ERROR("failed to receive USB CMD response"); + return retval; + } + + 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; + } + } + + return ERROR_OK; +} + +/** */ +static int stlink_tcp_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) +{ + struct stlink_usb_handle_s *h = handle; + + int send_size = STLINK_TCP_USB_CMD_SIZE; + int recv_size = STLINK_TCP_SS_SIZE; + + assert(handle); + + /* prepare the TCP command */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_SEND_USB_CMD; + memset(&h->tcp_backend_priv.send_buf[1], 0, 3); /* reserved for alignment and future use, must be zero */ + h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.connect_id); + /* tcp_backend_priv.send_buf[8..23] already contains the constructed stlink command */ + h->tcp_backend_priv.send_buf[24] = h->direction; + memset(&h->tcp_backend_priv.send_buf[25], 0, 3); /* reserved for alignment and future use, must be zero */ + + h_u32_to_le(&h->tcp_backend_priv.send_buf[28], size); + + /* + * if the xfer is a write request (tx_ep) + * > then buf content will be copied + * into &cmdbuf[32]. + * else : the xfer is a read or trace read request (rx_ep or trace_ep) + * > the buf content will be filled from &databuf[4]. + * + * note : if h->direction is trace_ep, h->cmdbuf is zeros. + */ + + if (h->direction == h->tx_ep) { /* STLINK_TCP_REQUEST_WRITE */ + send_size += size; + if (send_size > STLINK_TCP_SEND_BUFFER_SIZE) { + LOG_ERROR("STLINK_TCP command buffer overflow"); + return ERROR_FAIL; + } + memcpy(&h->tcp_backend_priv.send_buf[32], buf, size); + } else { /* STLINK_TCP_REQUEST_READ or STLINK_TCP_REQUEST_READ_SWO */ + recv_size += size; + if (recv_size > STLINK_TCP_RECV_BUFFER_SIZE) { + LOG_ERROR("STLINK_TCP data buffer overflow"); + return ERROR_FAIL; + } + } + + int ret = stlink_tcp_send_cmd(h, send_size, recv_size, true); + if (ret != ERROR_OK) + return ret; + + if (h->direction != h->tx_ep) { + /* the read data is located in tcp_backend_priv.recv_buf[4] */ + /* most of the case it will be copying the data from tcp_backend_priv.recv_buf[4] + * to handle->cmd_buff which are the same, so let's avoid unnecessary copying */ + if (buf != &h->tcp_backend_priv.recv_buf[4]) + memcpy((uint8_t *)buf, &h->tcp_backend_priv.recv_buf[4], size); + } + + return ERROR_OK; +} + +/** */ +static int stlink_tcp_read_trace(void *handle, const uint8_t *buf, int size) +{ + struct stlink_usb_handle_s *h = handle; + + stlink_usb_init_buffer(h, h->trace_ep, 0); + return stlink_tcp_xfer_noerrcheck(handle, buf, size); +} + /** Converts an STLINK status code held in the first byte of a response to an openocd error, logs any error/wait status as debug output. @@ -710,7 +1054,7 @@ static int stlink_usb_error_check(void *handle) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { switch (h->databuf[0]) { @@ -848,20 +1192,12 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size) static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; - int tr, ret; - assert(handle != NULL); + assert(handle); assert(h->version.flags & STLINK_F_HAS_TRACE); - ret = jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf, size, - STLINK_READ_TIMEOUT, &tr); - if (ret || tr != size) { - LOG_ERROR("bulk trace read failed"); - return ERROR_FAIL; - } - - return ERROR_OK; + return h->backend->read_trace(handle, buf, size); } /* @@ -922,7 +1258,7 @@ static int stlink_usb_version(void *handle) char *p; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 6); @@ -963,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; @@ -1025,6 +1361,7 @@ static int stlink_usb_version(void *handle) flags |= STLINK_F_QUIRK_JTAG_DP_READ; /* API to read/write memory at 16 bit from J26 */ + /* API to write memory without address increment from J26 */ if (h->version.jtag >= 26) flags |= STLINK_F_HAS_MEM_16BIT; @@ -1037,6 +1374,8 @@ static int stlink_usb_version(void *handle) flags |= STLINK_F_FIX_CLOSE_AP; /* Banked regs (DPv1 & DPv2) support from V2J32 */ + /* API to read memory without address increment from V2J32 */ + /* Memory R/W supports CSW from V2J32 */ if (h->version.jtag >= 32) flags |= STLINK_F_HAS_DPBANKSEL; @@ -1058,6 +1397,7 @@ static int stlink_usb_version(void *handle) 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 */ @@ -1067,6 +1407,8 @@ static int stlink_usb_version(void *handle) flags |= STLINK_F_FIX_CLOSE_AP; /* Banked regs (DPv1 & DPv2) support from V3J2 */ + /* API to read memory without address increment from V3J2 */ + /* Memory R/W supports CSW from V3J2 */ if (h->version.jtag >= 2) flags |= STLINK_F_HAS_DPBANKSEL; @@ -1074,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; @@ -1136,7 +1513,7 @@ static int stlink_usb_set_swdclk(void *handle, uint16_t clk_divisor) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (!(h->version.flags & STLINK_F_HAS_SWD_SET_FREQ)) return ERROR_COMMAND_NOTFOUND; @@ -1160,7 +1537,7 @@ static int stlink_usb_set_jtagclk(void *handle, uint16_t clk_divisor) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (!(h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ)) return ERROR_COMMAND_NOTFOUND; @@ -1186,7 +1563,7 @@ static int stlink_usb_current_mode(void *handle, uint8_t *mode) int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 2); @@ -1208,7 +1585,7 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type) int rx_size = 0; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); /* on api V2 we are able the read the latest command * status @@ -1256,7 +1633,7 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type) int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); /* command with no reply, use a valid endpoint but zero size */ stlink_usb_init_buffer(handle, h->rx_ep, 0); @@ -1309,7 +1686,7 @@ static int stlink_usb_exit_mode(void *handle) uint8_t mode; enum stlink_mode emode; - assert(handle != NULL); + assert(handle); res = stlink_usb_current_mode(handle, &mode); @@ -1350,7 +1727,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init enum stlink_mode emode; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); res = stlink_usb_exit_mode(handle); if (res != ERROR_OK) @@ -1407,7 +1784,8 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init } } - if (h->version.jtag_api == STLINK_JTAG_API_V3) { + if (h->version.jtag_api == STLINK_JTAG_API_V3 && + (emode == STLINK_MODE_DEBUG_JTAG || emode == STLINK_MODE_DEBUG_SWD)) { struct speed_map map[STLINK_V3_MAX_FREQ_NB]; stlink_get_com_freq(h, (emode == STLINK_MODE_DEBUG_JTAG), map); @@ -1585,7 +1963,7 @@ static int stlink_swim_writebytes(void *handle, uint32_t addr, uint32_t len, con unsigned int datalen = 0; int cmdsize = STLINK_CMD_SIZE_V2; - if (len > STLINK_DATA_SIZE) + if (len > STLINK_SWIM_DATA_SIZE) return ERROR_FAIL; if (h->version.stlink == 1) @@ -1618,7 +1996,7 @@ static int stlink_swim_readbytes(void *handle, uint32_t addr, uint32_t len, uint struct stlink_usb_handle_s *h = handle; int res; - if (len > STLINK_DATA_SIZE) + if (len > STLINK_SWIM_DATA_SIZE) return ERROR_FAIL; stlink_usb_init_buffer(handle, h->rx_ep, 0); @@ -1648,7 +2026,7 @@ static int stlink_usb_idcode(void *handle, uint32_t *idcode) int res, offset; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); /* there is no swim read core id cmd */ if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { @@ -1686,7 +2064,7 @@ static int stlink_usb_v2_read_debug_reg(void *handle, uint32_t addr, uint32_t *v struct stlink_usb_handle_s *h = handle; int res; - assert(handle != NULL); + assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 8); @@ -1707,7 +2085,7 @@ static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 2); @@ -1729,7 +2107,7 @@ static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (h->trace.enabled && (h->version.flags & STLINK_F_HAS_TRACE)) { int res; @@ -1744,7 +2122,7 @@ static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size) return res; size_t bytes_avail = le_to_h_u16(h->databuf); - *size = bytes_avail < *size ? bytes_avail : *size - 1; + *size = bytes_avail < *size ? bytes_avail : *size; if (*size > 0) { res = stlink_usb_read_trace(handle, buf, *size); @@ -1780,7 +2158,7 @@ static enum target_state stlink_usb_state(void *handle) int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (h->reconnect_pending) { LOG_INFO("Previous state query failed, trying to reconnect"); @@ -1822,7 +2200,7 @@ static int stlink_usb_assert_srst(void *handle, int srst) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (h->st_mode == STLINK_MODE_DEBUG_SWIM) return stlink_swim_assert_reset(handle, srst); @@ -1845,7 +2223,7 @@ static void stlink_usb_trace_disable(void *handle) int res = ERROR_OK; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); assert(h->version.flags & STLINK_F_HAS_TRACE); @@ -1867,7 +2245,7 @@ static int stlink_usb_trace_enable(void *handle) int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (h->version.flags & STLINK_F_HAS_TRACE) { stlink_usb_init_buffer(handle, h->rx_ep, 10); @@ -1899,7 +2277,7 @@ static int stlink_usb_reset(void *handle) struct stlink_usb_handle_s *h = handle; int retval; - assert(handle != NULL); + assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 2); @@ -1928,7 +2306,7 @@ static int stlink_usb_run(void *handle) int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (h->version.jtag_api != STLINK_JTAG_API_V1) { res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN); @@ -1950,7 +2328,7 @@ static int stlink_usb_halt(void *handle) int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (h->version.jtag_api != STLINK_JTAG_API_V1) { res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN); @@ -1971,7 +2349,7 @@ static int stlink_usb_step(void *handle) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (h->version.jtag_api != STLINK_JTAG_API_V1) { /* TODO: this emulates the v1 api, it should really use a similar auto mask isr @@ -1995,7 +2373,7 @@ static int stlink_usb_read_regs(void *handle) int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); stlink_usb_init_buffer(handle, h->rx_ep, 88); @@ -2015,12 +2393,21 @@ static int stlink_usb_read_regs(void *handle) } /** */ -static int stlink_usb_read_reg(void *handle, int num, uint32_t *val) +static int stlink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); + + if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) { + res = stlink_usb_write_debug_reg(h, DCB_DCRSR, regsel & 0x7f); + if (res != ERROR_OK) + return res; + + /* FIXME: poll DHCSR.S_REGRDY before read DCRDR */ + return stlink_usb_v2_read_debug_reg(h, DCB_DCRDR, val); + } stlink_usb_init_buffer(handle, h->rx_ep, h->version.jtag_api == STLINK_JTAG_API_V1 ? 4 : 8); @@ -2029,7 +2416,7 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READREG; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READREG; - h->cmdbuf[h->cmdidx++] = num; + h->cmdbuf[h->cmdidx++] = regsel; if (h->version.jtag_api == STLINK_JTAG_API_V1) { res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 4); @@ -2047,11 +2434,20 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val) } /** */ -static int stlink_usb_write_reg(void *handle, int num, uint32_t val) +static int stlink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); + + if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) { + int res = stlink_usb_write_debug_reg(h, DCB_DCRDR, val); + if (res != ERROR_OK) + return res; + + return stlink_usb_write_debug_reg(h, DCB_DCRSR, DCRSR_WNR | (regsel & 0x7f)); + /* FIXME: poll DHCSR.S_REGRDY after write DCRSR */ + } stlink_usb_init_buffer(handle, h->rx_ep, 2); @@ -2060,7 +2456,7 @@ static int stlink_usb_write_reg(void *handle, int num, uint32_t val) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEREG; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEREG; - h->cmdbuf[h->cmdidx++] = num; + h->cmdbuf[h->cmdidx++] = regsel; h_u32_to_le(h->cmdbuf+h->cmdidx, val); h->cmdidx += 4; @@ -2071,7 +2467,7 @@ static int stlink_usb_get_rw_status(void *handle) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (h->version.jtag_api == STLINK_JTAG_API_V1) return ERROR_OK; @@ -2089,14 +2485,17 @@ static int stlink_usb_get_rw_status(void *handle) } /** */ -static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len, - uint8_t *buffer) +static int stlink_usb_read_mem8(void *handle, uint8_t ap_num, uint32_t csw, + uint32_t addr, uint16_t len, uint8_t *buffer) { int res; uint16_t read_len = len; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); + + if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) + return ERROR_COMMAND_NOTFOUND; /* max 8 bit read/write is 64 bytes or 512 bytes for v3 */ if (len > stlink_usb_block(h)) { @@ -2112,6 +2511,9 @@ static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len, h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; + h->cmdbuf[h->cmdidx++] = ap_num; + h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); + h->cmdidx += 3; /* we need to fix read length for single bytes */ if (read_len == 1) @@ -2128,13 +2530,16 @@ static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len, } /** */ -static int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len, - const uint8_t *buffer) +static int stlink_usb_write_mem8(void *handle, uint8_t ap_num, uint32_t csw, + uint32_t addr, uint16_t len, const uint8_t *buffer) { int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); + + if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) + return ERROR_COMMAND_NOTFOUND; /* max 8 bit read/write is 64 bytes or 512 bytes for v3 */ if (len > stlink_usb_block(h)) { @@ -2150,6 +2555,9 @@ static int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len, h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; + h->cmdbuf[h->cmdidx++] = ap_num; + h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); + h->cmdidx += 3; res = stlink_usb_xfer_noerrcheck(handle, buffer, len); @@ -2160,17 +2568,25 @@ static int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len, } /** */ -static int stlink_usb_read_mem16(void *handle, uint32_t addr, uint16_t len, - uint8_t *buffer) +static int stlink_usb_read_mem16(void *handle, uint8_t ap_num, uint32_t csw, + uint32_t addr, uint16_t len, uint8_t *buffer) { int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (!(h->version.flags & STLINK_F_HAS_MEM_16BIT)) return ERROR_COMMAND_NOTFOUND; + if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) + return ERROR_COMMAND_NOTFOUND; + + if (len > STLINK_MAX_RW16_32) { + LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); + return ERROR_FAIL; + } + /* data must be a multiple of 2 and half-word aligned */ if (len % 2 || addr % 2) { LOG_DEBUG("Invalid data alignment"); @@ -2185,6 +2601,9 @@ static int stlink_usb_read_mem16(void *handle, uint32_t addr, uint16_t len, h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; + h->cmdbuf[h->cmdidx++] = ap_num; + h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); + h->cmdidx += 3; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, len); @@ -2197,17 +2616,25 @@ static int stlink_usb_read_mem16(void *handle, uint32_t addr, uint16_t len, } /** */ -static int stlink_usb_write_mem16(void *handle, uint32_t addr, uint16_t len, - const uint8_t *buffer) +static int stlink_usb_write_mem16(void *handle, uint8_t ap_num, uint32_t csw, + uint32_t addr, uint16_t len, const uint8_t *buffer) { int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (!(h->version.flags & STLINK_F_HAS_MEM_16BIT)) return ERROR_COMMAND_NOTFOUND; + if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) + return ERROR_COMMAND_NOTFOUND; + + if (len > STLINK_MAX_RW16_32) { + LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); + return ERROR_FAIL; + } + /* data must be a multiple of 2 and half-word aligned */ if (len % 2 || addr % 2) { LOG_DEBUG("Invalid data alignment"); @@ -2222,6 +2649,9 @@ static int stlink_usb_write_mem16(void *handle, uint32_t addr, uint16_t len, h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; + h->cmdbuf[h->cmdidx++] = ap_num; + h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); + h->cmdidx += 3; res = stlink_usb_xfer_noerrcheck(handle, buffer, len); @@ -2232,13 +2662,21 @@ static int stlink_usb_write_mem16(void *handle, uint32_t addr, uint16_t len, } /** */ -static int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len, - uint8_t *buffer) +static int stlink_usb_read_mem32(void *handle, uint8_t ap_num, uint32_t csw, + uint32_t addr, uint16_t len, uint8_t *buffer) { int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); + + if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) + return ERROR_COMMAND_NOTFOUND; + + if (len > STLINK_MAX_RW16_32) { + LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); + return ERROR_FAIL; + } /* data must be a multiple of 4 and word aligned */ if (len % 4 || addr % 4) { @@ -2254,6 +2692,9 @@ static int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len, h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; + h->cmdbuf[h->cmdidx++] = ap_num; + h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); + h->cmdidx += 3; res = stlink_usb_xfer_noerrcheck(handle, h->databuf, len); @@ -2266,13 +2707,21 @@ static int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len, } /** */ -static int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len, - const uint8_t *buffer) +static int stlink_usb_write_mem32(void *handle, uint8_t ap_num, uint32_t csw, + uint32_t addr, uint16_t len, const uint8_t *buffer) { int res; struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); + + if ((ap_num != 0 || csw != 0) && !(h->version.flags & STLINK_F_HAS_CSW)) + return ERROR_COMMAND_NOTFOUND; + + if (len > STLINK_MAX_RW16_32) { + LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); + return ERROR_FAIL; + } /* data must be a multiple of 4 and word aligned */ if (len % 4 || addr % 4) { @@ -2288,6 +2737,9 @@ static int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len, h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; + h->cmdbuf[h->cmdidx++] = ap_num; + h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); + h->cmdidx += 3; res = stlink_usb_xfer_noerrcheck(handle, buffer, len); @@ -2297,7 +2749,89 @@ static int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len, return stlink_usb_get_rw_status(handle); } -static uint32_t stlink_max_block_size(uint32_t tar_autoincr_block, uint32_t address) +static int stlink_usb_read_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_t csw, + uint32_t addr, uint16_t len, uint8_t *buffer) +{ + struct stlink_usb_handle_s *h = handle; + + assert(handle != NULL); + + if (!(h->version.flags & STLINK_F_HAS_MEM_RD_NO_INC)) + return ERROR_COMMAND_NOTFOUND; + + if (len > STLINK_MAX_RW16_32) { + LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); + return ERROR_FAIL; + } + + /* data must be a multiple of 4 and word aligned */ + if (len % 4 || addr % 4) { + LOG_DEBUG("Invalid data alignment"); + return ERROR_TARGET_UNALIGNED_ACCESS; + } + + stlink_usb_init_buffer(handle, h->rx_ep, len); + + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READMEM_32BIT_NO_ADDR_INC; + h_u32_to_le(h->cmdbuf + h->cmdidx, addr); + h->cmdidx += 4; + h_u16_to_le(h->cmdbuf + h->cmdidx, len); + h->cmdidx += 2; + h->cmdbuf[h->cmdidx++] = ap_num; + h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); + h->cmdidx += 3; + + int retval = stlink_usb_xfer_noerrcheck(handle, h->databuf, len); + if (retval != ERROR_OK) + return retval; + + memcpy(buffer, h->databuf, len); + + return stlink_usb_get_rw_status(handle); +} + +static int stlink_usb_write_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_t csw, + uint32_t addr, uint16_t len, const uint8_t *buffer) +{ + struct stlink_usb_handle_s *h = handle; + + assert(handle != NULL); + + if (!(h->version.flags & STLINK_F_HAS_MEM_WR_NO_INC)) + return ERROR_COMMAND_NOTFOUND; + + if (len > STLINK_MAX_RW16_32) { + LOG_DEBUG("max buffer (%d) length exceeded", STLINK_MAX_RW16_32); + return ERROR_FAIL; + } + + /* data must be a multiple of 4 and word aligned */ + if (len % 4 || addr % 4) { + LOG_DEBUG("Invalid data alignment"); + return ERROR_TARGET_UNALIGNED_ACCESS; + } + + stlink_usb_init_buffer(handle, h->tx_ep, len); + + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_WRITEMEM_32BIT_NO_ADDR_INC; + h_u32_to_le(h->cmdbuf + h->cmdidx, addr); + h->cmdidx += 4; + h_u16_to_le(h->cmdbuf + h->cmdidx, len); + h->cmdidx += 2; + h->cmdbuf[h->cmdidx++] = ap_num; + h_u24_to_le(h->cmdbuf + h->cmdidx, csw >> 8); + h->cmdidx += 3; + + int retval = stlink_usb_xfer_noerrcheck(handle, buffer, len); + if (retval != ERROR_OK) + return retval; + + return stlink_usb_get_rw_status(handle); +} + +static uint32_t stlink_max_block_size(uint32_t tar_autoincr_block, uint32_t address) { uint32_t max_tar_block = (tar_autoincr_block - ((tar_autoincr_block - 1) & address)); if (max_tar_block == 0) @@ -2305,8 +2839,8 @@ static uint32_t stlink_max_block_size(uint32_t tar_autoincr_block, uint32_t addr return max_tar_block; } -static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, - uint32_t count, uint8_t *buffer) +static int stlink_usb_read_ap_mem(void *handle, uint8_t ap_num, uint32_t csw, + uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer) { int retval = ERROR_OK; uint32_t bytes_remaining; @@ -2321,7 +2855,6 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, size = 1; while (count) { - bytes_remaining = (size != 1) ? stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h); @@ -2335,7 +2868,6 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, * as 8bit access. */ if (size != 1) { - /* When in jtag mode the stlink uses the auto-increment functionality. * However it expects us to pass the data correctly, this includes * alignment and any page boundaries. We already do this as part of the @@ -2346,11 +2878,10 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, /* we first need to check for any unaligned bytes */ if (addr & (size - 1)) { - uint32_t head_bytes = size - (addr & (size - 1)); - retval = stlink_usb_read_mem8(handle, addr, head_bytes, buffer); + retval = stlink_usb_read_mem8(handle, ap_num, csw, addr, head_bytes, buffer); if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { - usleep((1<<retries++) * 1000); + usleep((1 << retries++) * 1000); continue; } if (retval != ERROR_OK) @@ -2362,16 +2893,17 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, } if (bytes_remaining & (size - 1)) - retval = stlink_usb_read_mem(handle, addr, 1, bytes_remaining, buffer); + retval = stlink_usb_read_ap_mem(handle, ap_num, csw, addr, 1, bytes_remaining, buffer); else if (size == 2) - retval = stlink_usb_read_mem16(handle, addr, bytes_remaining, buffer); + retval = stlink_usb_read_mem16(handle, ap_num, csw, addr, bytes_remaining, buffer); else - retval = stlink_usb_read_mem32(handle, addr, bytes_remaining, buffer); - } else - retval = stlink_usb_read_mem8(handle, addr, bytes_remaining, buffer); + retval = stlink_usb_read_mem32(handle, ap_num, csw, addr, bytes_remaining, buffer); + } else { + retval = stlink_usb_read_mem8(handle, ap_num, csw, addr, bytes_remaining, buffer); + } if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { - usleep((1<<retries++) * 1000); + usleep((1 << retries++) * 1000); continue; } if (retval != ERROR_OK) @@ -2385,8 +2917,15 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, return retval; } -static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, - uint32_t count, const uint8_t *buffer) +static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, + uint32_t count, uint8_t *buffer) +{ + return stlink_usb_read_ap_mem(handle, STLINK_HLA_AP_NUM, STLINK_HLA_CSW, + addr, size, count, buffer); +} + +static int stlink_usb_write_ap_mem(void *handle, uint8_t ap_num, uint32_t csw, + uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval = ERROR_OK; uint32_t bytes_remaining; @@ -2428,7 +2967,7 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, if (addr & (size - 1)) { uint32_t head_bytes = size - (addr & (size - 1)); - retval = stlink_usb_write_mem8(handle, addr, head_bytes, buffer); + retval = stlink_usb_write_mem8(handle, ap_num, csw, addr, head_bytes, buffer); if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { usleep((1<<retries++) * 1000); continue; @@ -2442,14 +2981,14 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, } if (bytes_remaining & (size - 1)) - retval = stlink_usb_write_mem(handle, addr, 1, bytes_remaining, buffer); + retval = stlink_usb_write_ap_mem(handle, ap_num, csw, addr, 1, bytes_remaining, buffer); else if (size == 2) - retval = stlink_usb_write_mem16(handle, addr, bytes_remaining, buffer); + retval = stlink_usb_write_mem16(handle, ap_num, csw, addr, bytes_remaining, buffer); else - retval = stlink_usb_write_mem32(handle, addr, bytes_remaining, buffer); + retval = stlink_usb_write_mem32(handle, ap_num, csw, addr, bytes_remaining, buffer); } else - retval = stlink_usb_write_mem8(handle, addr, bytes_remaining, buffer); + retval = stlink_usb_write_mem8(handle, ap_num, csw, addr, bytes_remaining, buffer); if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { usleep((1<<retries++) * 1000); continue; @@ -2465,6 +3004,13 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, return retval; } +static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, + uint32_t count, const uint8_t *buffer) +{ + return stlink_usb_write_ap_mem(handle, STLINK_HLA_AP_NUM, STLINK_HLA_CSW, + addr, size, count, buffer); +} + /** */ static int stlink_usb_override_target(const char *targetname) { @@ -2577,7 +3123,7 @@ static int stlink_speed_jtag(void *handle, int khz, bool query) return stlink_khz_to_speed_map_jtag[speed_index].speed; } -void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size) +static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size) { unsigned int i; @@ -2693,18 +3239,68 @@ static int stlink_speed(void *handle, int khz, bool query) } /** */ -static int stlink_usb_close(void *handle) +static int stlink_usb_usb_close(void *handle) { struct stlink_usb_handle_s *h = handle; - if (h && h->fd) { + if (!h) + return ERROR_OK; + + if (h->usb_backend_priv.fd) { stlink_usb_exit_mode(h); /* do not check return code, it prevent us from closing jtag_libusb */ - jtag_libusb_close(h->fd); + jtag_libusb_close(h->usb_backend_priv.fd); + } + + free(h->cmdbuf); + free(h->databuf); + + return ERROR_OK; +} + +/** */ +static int stlink_tcp_close(void *handle) +{ + struct stlink_usb_handle_s *h = handle; + + if (!h) + return ERROR_OK; + + int ret = ERROR_OK; + if (h->tcp_backend_priv.connected) { + if (h->tcp_backend_priv.connect_id) { + stlink_usb_exit_mode(h); + + /* close the stlink */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_CLOSE_DEV; + memset(&h->tcp_backend_priv.send_buf[1], 0, 4); /* reserved */ + h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.connect_id); + ret = stlink_tcp_send_cmd(h, 8, 4, true); + if (ret != ERROR_OK) + LOG_ERROR("cannot close the STLINK"); + } + + if (close_socket(h->tcp_backend_priv.fd) != 0) + LOG_ERROR("error closing the socket, errno: %s", strerror(errno)); } - free(h); + free(h->tcp_backend_priv.send_buf); + free(h->tcp_backend_priv.recv_buf); + + return ret; +} + +/** */ +static int stlink_close(void *handle) +{ + if (handle) { + struct stlink_usb_handle_s *h = handle; + + stlink_usb_close(handle); + + free(h); + } return ERROR_OK; } @@ -2725,7 +3321,7 @@ static int stlink_usb_close(void *handle) * based on the length (0x1a = 26) we could easily decide if we have to fixup the serial * and then we have just to convert the raw data into printable characters using sprintf */ -char *stlink_usb_get_alternate_serial(libusb_device_handle *device, +static char *stlink_usb_get_alternate_serial(struct libusb_device_handle *device, struct libusb_device_descriptor *dev_desc) { int usb_retval; @@ -2777,7 +3373,7 @@ char *stlink_usb_get_alternate_serial(libusb_device_handle *device, /* else (len == 26) => buggy ST-Link */ char *alternate_serial = malloc((STLINK_SERIAL_LEN + 1) * sizeof(char)); - if (alternate_serial == NULL) + if (!alternate_serial) return NULL; for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2) @@ -2789,27 +3385,16 @@ char *stlink_usb_get_alternate_serial(libusb_device_handle *device, } /** */ -static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd) +static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param) { + struct stlink_usb_handle_s *h = handle; int err, retry_count = 1; - struct stlink_usb_handle_s *h; - - LOG_DEBUG("stlink_usb_open"); - h = calloc(1, sizeof(struct stlink_usb_handle_s)); + h->cmdbuf = malloc(STLINK_SG_SIZE); + h->databuf = malloc(STLINK_DATA_SIZE); - if (h == 0) { - LOG_DEBUG("malloc failed"); + if (!h->cmdbuf || !h->databuf) return ERROR_FAIL; - } - - h->st_mode = mode; - - for (unsigned i = 0; param->vid[i]; i++) { - LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", - h->st_mode, param->vid[i], param->pid[i], - param->serial ? param->serial : ""); - } /* On certain host USB configurations(e.g. MacBook Air) @@ -2821,26 +3406,26 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode in order to become operational. */ do { - if (jtag_libusb_open(param->vid, param->pid, param->serial, - &h->fd, stlink_usb_get_alternate_serial) != ERROR_OK) { + 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"); - goto error_open; + return ERROR_FAIL; } - jtag_libusb_set_configuration(h->fd, 0); + jtag_libusb_set_configuration(h->usb_backend_priv.fd, 0); - if (libusb_claim_interface(h->fd, 0) != ERROR_OK) { + if (libusb_claim_interface(h->usb_backend_priv.fd, 0) != ERROR_OK) { LOG_DEBUG("claim interface failed"); - goto error_open; + return ERROR_FAIL; } /* RX EP is common for all versions */ h->rx_ep = STLINK_RX_EP; uint16_t pid; - if (jtag_libusb_get_pid(libusb_get_device(h->fd), &pid) != ERROR_OK) { + if (jtag_libusb_get_pid(libusb_get_device(h->usb_backend_priv.fd), &pid) != ERROR_OK) { LOG_DEBUG("libusb_get_pid failed"); - goto error_open; + return ERROR_FAIL; } /* wrap version for first read */ @@ -2853,6 +3438,9 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode case STLINK_V3E_PID: 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; @@ -2880,21 +3468,21 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode } else if (h->version.stlink == 1 || retry_count == 0) { LOG_ERROR("read version failed"); - goto error_open; + return ERROR_FAIL; } else { - err = libusb_release_interface(h->fd, 0); + err = libusb_release_interface(h->usb_backend_priv.fd, 0); if (err != ERROR_OK) { LOG_ERROR("release interface failed"); - goto error_open; + return ERROR_FAIL; } - err = libusb_reset_device(h->fd); + err = libusb_reset_device(h->usb_backend_priv.fd); if (err != ERROR_OK) { LOG_ERROR("reset device failed"); - goto error_open; + return ERROR_FAIL; } - jtag_libusb_close(h->fd); + jtag_libusb_close(h->usb_backend_priv.fd); /* Give the device one second to settle down and reenumerate. @@ -2904,8 +3492,270 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode } } while (1); + return ERROR_OK; +} + +/** */ +static int stlink_tcp_open(void *handle, struct hl_interface_param_s *param) +{ + struct stlink_usb_handle_s *h = handle; + int ret; + + /* SWIM is not supported using stlink-server */ + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { + LOG_ERROR("stlink-server does not support SWIM mode"); + return ERROR_FAIL; + } + + h->tcp_backend_priv.send_buf = malloc(STLINK_TCP_SEND_BUFFER_SIZE); + h->tcp_backend_priv.recv_buf = malloc(STLINK_TCP_RECV_BUFFER_SIZE); + + if (!h->tcp_backend_priv.send_buf || !h->tcp_backend_priv.recv_buf) + return ERROR_FAIL; + + h->cmdbuf = &h->tcp_backend_priv.send_buf[8]; + h->databuf = &h->tcp_backend_priv.recv_buf[4]; + + /* configure directions */ + h->rx_ep = STLINK_TCP_REQUEST_READ; + h->tx_ep = STLINK_TCP_REQUEST_WRITE; + h->trace_ep = STLINK_TCP_REQUEST_READ_SWO; + + h->tcp_backend_priv.fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + h->tcp_backend_priv.connected = false; + h->tcp_backend_priv.device_id = 0; + h->tcp_backend_priv.connect_id = 0; + + if (h->tcp_backend_priv.fd == -1) { + LOG_ERROR("error creating the socket, errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + struct sockaddr_in serv; + memset(&serv, 0, sizeof(struct sockaddr_in)); + serv.sin_family = AF_INET; + serv.sin_port = htons(param->stlink_tcp_port); + serv.sin_addr.s_addr = inet_addr("127.0.0.1"); + + LOG_DEBUG("socket : %x", h->tcp_backend_priv.fd); + + int optval = 1; + if (setsockopt(h->tcp_backend_priv.fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, sizeof(int)) == -1) { + LOG_ERROR("cannot set sock option 'TCP_NODELAY', errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + optval = STLINK_TCP_RECV_BUFFER_SIZE; + if (setsockopt(h->tcp_backend_priv.fd, SOL_SOCKET, SO_RCVBUF, (const void *)&optval, sizeof(int)) == -1) { + LOG_ERROR("cannot set sock option 'SO_RCVBUF', errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + optval = STLINK_TCP_SEND_BUFFER_SIZE; + if (setsockopt(h->tcp_backend_priv.fd, SOL_SOCKET, SO_SNDBUF, (const void *)&optval, sizeof(int)) == -1) { + LOG_ERROR("cannot set sock option 'SO_SNDBUF', errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + if (connect(h->tcp_backend_priv.fd, (const struct sockaddr *)&serv, sizeof(serv)) == -1) { + LOG_ERROR("cannot connect to stlink server, errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + h->tcp_backend_priv.connected = true; + + LOG_INFO("connected to stlink-server"); + + /* print stlink-server version */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_SERVER_VERSION; + h->tcp_backend_priv.send_buf[1] = OPENOCD_STLINK_TCP_API_VERSION; + memset(&h->tcp_backend_priv.send_buf[2], 0, 2); /* reserved */ + ret = stlink_tcp_send_cmd(h, 4, 16, false); + if (ret != ERROR_OK) { + LOG_ERROR("cannot get the stlink-server version"); + return ERROR_FAIL; + } + + h->tcp_backend_priv.version.api = le_to_h_u32(&h->tcp_backend_priv.recv_buf[0]); + h->tcp_backend_priv.version.major = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); + h->tcp_backend_priv.version.minor = le_to_h_u32(&h->tcp_backend_priv.recv_buf[8]); + h->tcp_backend_priv.version.build = le_to_h_u32(&h->tcp_backend_priv.recv_buf[12]); + LOG_INFO("stlink-server API v%d, version %d.%d.%d", + h->tcp_backend_priv.version.api, + h->tcp_backend_priv.version.major, + h->tcp_backend_priv.version.minor, + h->tcp_backend_priv.version.build); + + /* in stlink-server API v1 sending more than 1428 bytes will cause stlink-server + * to crash in windows: select a safe default value (1K) */ + if (h->tcp_backend_priv.version.api < 2) + h->max_mem_packet = (1 << 10); + + /* refresh stlink list (re-enumerate) */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_REFRESH_DEVICE_LIST; + h->tcp_backend_priv.send_buf[1] = 0; /* don't clear the list, just refresh it */ + ret = stlink_tcp_send_cmd(h, 2, 4, true); + if (ret != ERROR_OK) + return ret; + + /* get the number of connected stlinks */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_NB_DEV; + ret = stlink_tcp_send_cmd(h, 1, 4, false); + if (ret != ERROR_OK) + return ret; + + uint32_t connected_stlinks = le_to_h_u32(h->tcp_backend_priv.recv_buf); + + if (connected_stlinks == 0) { + LOG_ERROR("no ST-LINK detected"); + return ERROR_FAIL; + } + + LOG_DEBUG("%d ST-LINK detected", connected_stlinks); + + if (connected_stlinks > 255) { + LOG_WARNING("STLink server cannot handle more than 255 ST-LINK connected"); + connected_stlinks = 255; + } + + /* list all connected ST-Link and seek for the requested vid:pid and serial */ + char serial[STLINK_TCP_SERIAL_SIZE + 1] = {0}; + uint8_t stlink_used; + bool stlink_id_matched = false; + const char *adapter_serial = adapter_get_required_serial(); + bool stlink_serial_matched = !adapter_serial; + + for (uint32_t stlink_id = 0; stlink_id < connected_stlinks; stlink_id++) { + /* get the stlink info */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_DEV_INFO; + h->tcp_backend_priv.send_buf[1] = (uint8_t)stlink_id; + memset(&h->tcp_backend_priv.send_buf[2], 0, 2); /* reserved */ + h_u32_to_le(&h->tcp_backend_priv.send_buf[4], 41); /* size of TDeviceInfo2 */ + ret = stlink_tcp_send_cmd(h, 8, 45, true); + if (ret != ERROR_OK) + return ret; + + h->tcp_backend_priv.device_id = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); + memcpy(serial, &h->tcp_backend_priv.recv_buf[8], STLINK_TCP_SERIAL_SIZE); + h->vid = le_to_h_u16(&h->tcp_backend_priv.recv_buf[40]); + h->pid = le_to_h_u16(&h->tcp_backend_priv.recv_buf[42]); + stlink_used = h->tcp_backend_priv.recv_buf[44]; + + /* check the vid:pid */ + for (int i = 0; param->vid[i]; i++) { + if (param->vid[i] == h->vid && param->pid[i] == h->pid) { + stlink_id_matched = true; + break; + } + } + + if (!stlink_id_matched) + continue; + + /* check the serial if specified */ + if (adapter_serial) { + /* ST-Link server fixes the buggy serial returned by old ST-Link DFU + * for further details refer to stlink_usb_get_alternate_serial + * so if the user passes the buggy serial, we need to fix it before + * comparing with the serial returned by ST-Link server */ + if (strlen(adapter_serial) == STLINK_SERIAL_LEN / 2) { + char fixed_serial[STLINK_SERIAL_LEN + 1]; + + for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2) + sprintf(fixed_serial + i, "%02X", adapter_serial[i / 2]); + + fixed_serial[STLINK_SERIAL_LEN] = '\0'; + + stlink_serial_matched = strcmp(fixed_serial, serial) == 0; + } else { + stlink_serial_matched = strcmp(adapter_serial, serial) == 0; + } + } + + if (!stlink_serial_matched) + LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'", + serial, adapter_serial); + else /* exit the search loop if there is match */ + break; + } + + if (!stlink_id_matched) { + LOG_ERROR("ST-LINK open failed (vid/pid mismatch)"); + return ERROR_FAIL; + } + + if (!stlink_serial_matched) { + LOG_ERROR("ST-LINK open failed (serial mismatch)"); + return ERROR_FAIL; + } + + /* check if device is 'exclusively' used by another application */ + if (stlink_used) { + LOG_ERROR("the selected device is already used"); + return ERROR_FAIL; + } + + LOG_DEBUG("transport: vid: 0x%04x pid: 0x%04x serial: %s", h->vid, h->pid, serial); + + /* now let's open the stlink */ + h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_OPEN_DEV; + memset(&h->tcp_backend_priv.send_buf[1], 0, 4); /* reserved */ + h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.device_id); + ret = stlink_tcp_send_cmd(h, 8, 8, true); + if (ret != ERROR_OK) + return ret; + + h->tcp_backend_priv.connect_id = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); + + /* get stlink version */ + return stlink_usb_version(h); +} + +static struct stlink_backend_s stlink_usb_backend = { + .open = stlink_usb_usb_open, + .close = stlink_usb_usb_close, + .xfer_noerrcheck = stlink_usb_usb_xfer_noerrcheck, + .read_trace = stlink_usb_usb_read_trace, +}; + +static struct stlink_backend_s stlink_tcp_backend = { + .open = stlink_tcp_open, + .close = stlink_tcp_close, + .xfer_noerrcheck = stlink_tcp_xfer_noerrcheck, + .read_trace = stlink_tcp_read_trace, +}; + +static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd) +{ + struct stlink_usb_handle_s *h; + + LOG_DEBUG("stlink_open"); + + h = calloc(1, sizeof(struct stlink_usb_handle_s)); + + if (!h) { + LOG_DEBUG("malloc failed"); + return ERROR_FAIL; + } + + h->st_mode = mode; + + for (unsigned i = 0; param->vid[i]; i++) { + LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", + h->st_mode, param->vid[i], param->pid[i], + adapter_get_required_serial() ? adapter_get_required_serial() : ""); + } + + if (param->use_stlink_tcp) + h->backend = &stlink_tcp_backend; + else + h->backend = &stlink_usb_backend; + + if (stlink_usb_open(h, param) != ERROR_OK) + goto error_open; + /* check if mode is supported */ - err = ERROR_OK; + int err = ERROR_OK; switch (h->st_mode) { case STLINK_MODE_DEBUG_SWD: @@ -2945,54 +3795,54 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode goto error_open; } *fd = h; - h->max_mem_packet = STLINK_DATA_SIZE; + h->max_mem_packet = STLINK_SWIM_DATA_SIZE; return ERROR_OK; } - /* get cpuid, so we can determine the max page size - * start with a safe default */ - h->max_mem_packet = (1 << 10); + /* set max_mem_packet if it was not set by the low-level interface */ + if (h->max_mem_packet == 0) { + /* get cpuid, so we can determine the max page size + * start with a safe default */ + h->max_mem_packet = (1 << 10); - uint8_t buffer[4]; - stlink_usb_open_ap(h, 0); - err = stlink_usb_read_mem32(h, CPUID, 4, buffer); - if (err == ERROR_OK) { - uint32_t cpuid = le_to_h_u32(buffer); - int i = (cpuid >> 4) & 0xf; - if (i == 4 || i == 3) { - /* Cortex-M3/M4 has 4096 bytes autoincrement range */ - h->max_mem_packet = (1 << 12); + uint8_t buffer[4]; + stlink_usb_open_ap(h, STLINK_HLA_AP_NUM); + err = stlink_usb_read_mem32(h, STLINK_HLA_AP_NUM, STLINK_HLA_CSW, CPUID, 4, buffer); + if (err == ERROR_OK) { + uint32_t cpuid = le_to_h_u32(buffer); + int i = (cpuid >> 4) & 0xf; + if (i == 4 || i == 3) { + /* Cortex-M3/M4 has 4096 bytes autoincrement range */ + h->max_mem_packet = (1 << 12); + } } - } - LOG_DEBUG("Using TAR autoincrement: %" PRIu32, h->max_mem_packet); + LOG_DEBUG("Using TAR autoincrement: %" PRIu32, h->max_mem_packet); + } *fd = h; return ERROR_OK; error_open: - stlink_usb_close(h); - + stlink_close(h); return ERROR_FAIL; } static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd) { - return stlink_usb_open(param, stlink_get_mode(param->transport), fd); + return stlink_open(param, stlink_get_mode(param->transport), fd); } -int stlink_config_trace(void *handle, bool enabled, +static int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler) { struct stlink_usb_handle_s *h = handle; - uint16_t presc; - if (enabled && (!(h->version.flags & STLINK_F_HAS_TRACE) || - pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) { - LOG_ERROR("The attached ST-LINK version doesn't support this trace mode"); + if (!(h->version.flags & STLINK_F_HAS_TRACE)) { + LOG_ERROR("The attached ST-LINK version doesn't support trace"); return ERROR_FAIL; } @@ -3001,29 +3851,47 @@ int stlink_config_trace(void *handle, bool enabled, return ERROR_OK; } - if (*trace_freq > STLINK_TRACE_MAX_HZ) { - LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u", - STLINK_TRACE_MAX_HZ); + assert(trace_freq); + assert(prescaler); + + if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) { + LOG_ERROR("The attached ST-LINK version doesn't support this trace mode"); return ERROR_FAIL; } - stlink_usb_trace_disable(h); + unsigned int max_trace_freq = (h->version.stlink >= 3) ? + STLINK_V3_TRACE_MAX_HZ : STLINK_TRACE_MAX_HZ; - if (!*trace_freq) - *trace_freq = STLINK_TRACE_MAX_HZ; + /* Only concern ourselves with the frequency if the STlink is processing it. */ + if (*trace_freq > max_trace_freq) { + LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u", + max_trace_freq); + return ERROR_FAIL; + } - presc = traceclkin_freq / *trace_freq; + if (!*trace_freq) + *trace_freq = max_trace_freq; - if (traceclkin_freq % *trace_freq > 0) - presc++; + unsigned int presc = (traceclkin_freq + *trace_freq / 2) / *trace_freq; + if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) { + LOG_ERROR("SWO frequency is not suitable. Please choose a different " + "frequency."); + return ERROR_FAIL; + } - if (presc > TPIU_ACPR_MAX_SWOSCALER) { + /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */ + unsigned int max_deviation = (traceclkin_freq * 3) / 100; + if (presc * *trace_freq < traceclkin_freq - max_deviation || + presc * *trace_freq > traceclkin_freq + max_deviation) { LOG_ERROR("SWO frequency is not suitable. Please choose a different " "frequency."); return ERROR_FAIL; } *prescaler = presc; + + stlink_usb_trace_disable(h); + h->trace.source_hz = *trace_freq; return stlink_usb_trace_enable(h); @@ -3034,7 +3902,7 @@ static int stlink_usb_init_access_port(void *handle, unsigned char ap_num) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (!(h->version.flags & STLINK_F_HAS_AP_INIT)) return ERROR_COMMAND_NOTFOUND; @@ -3053,7 +3921,7 @@ static int stlink_usb_close_access_port(void *handle, unsigned char ap_num) { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (!(h->version.flags & STLINK_F_HAS_AP_INIT)) return ERROR_COMMAND_NOTFOUND; @@ -3072,15 +3940,62 @@ static int stlink_usb_close_access_port(void *handle, unsigned char ap_num) } -/** */ -static int stlink_read_dap_register(void *handle, unsigned short dap_port, - unsigned short addr, uint32_t *val) +static int stlink_usb_rw_misc_out(void *handle, uint32_t items, const uint8_t *buffer) { struct stlink_usb_handle_s *h = handle; - int retval; + unsigned int buflen = ALIGN_UP(items, 4) + 4 * items; + + LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items); + + assert(handle != NULL); + + if (!(h->version.flags & STLINK_F_HAS_RW_MISC)) + return ERROR_COMMAND_NOTFOUND; + + stlink_usb_init_buffer(handle, h->tx_ep, buflen); + + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RW_MISC_OUT; + h_u32_to_le(&h->cmdbuf[2], items); + + return stlink_usb_xfer_noerrcheck(handle, buffer, buflen); +} + +static int stlink_usb_rw_misc_in(void *handle, uint32_t items, uint8_t *buffer) +{ + struct stlink_usb_handle_s *h = handle; + unsigned int buflen = 2 * 4 * items; + + LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items); assert(handle != NULL); + if (!(h->version.flags & STLINK_F_HAS_RW_MISC)) + return ERROR_COMMAND_NOTFOUND; + + stlink_usb_init_buffer(handle, h->rx_ep, buflen); + + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RW_MISC_IN; + + int res = stlink_usb_xfer_noerrcheck(handle, h->databuf, buflen); + if (res != ERROR_OK) + return res; + + memcpy(buffer, h->databuf, buflen); + + return ERROR_OK; +} + +/** */ +static int stlink_read_dap_register(void *handle, unsigned short dap_port, + unsigned short addr, uint32_t *val) +{ + struct stlink_usb_handle_s *h = handle; + int retval; + + assert(handle); + if (!(h->version.flags & STLINK_F_HAS_DAP_REG)) return ERROR_COMMAND_NOTFOUND; @@ -3102,7 +4017,7 @@ static int stlink_write_dap_register(void *handle, unsigned short dap_port, { struct stlink_usb_handle_s *h = handle; - assert(handle != NULL); + assert(handle); if (!(h->version.flags & STLINK_F_HAS_DAP_REG)) return ERROR_COMMAND_NOTFOUND; @@ -3122,7 +4037,7 @@ struct hl_layout_api_s stlink_usb_layout_api = { /** */ .open = stlink_usb_hl_open, /** */ - .close = stlink_usb_close, + .close = stlink_close, /** */ .idcode = stlink_usb_idcode, /** */ @@ -3166,11 +4081,9 @@ struct hl_layout_api_s stlink_usb_layout_api = { static struct stlink_usb_handle_s *stlink_dap_handle; static struct hl_interface_param_s stlink_dap_param; static DECLARE_BITMAP(opened_ap, DP_APSEL_MAX + 1); +static uint32_t last_csw_default[DP_APSEL_MAX + 1]; static int stlink_dap_error = ERROR_OK; -static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg, - uint32_t *data); - /** */ static int stlink_dap_record_error(int error) { @@ -3187,6 +4100,11 @@ static int stlink_dap_get_and_clear_error(void) return retval; } +static int stlink_dap_get_error(void) +{ + return stlink_dap_error; +} + static int stlink_usb_open_ap(void *handle, unsigned short apsel) { struct stlink_usb_handle_s *h = handle; @@ -3208,6 +4126,7 @@ static int stlink_usb_open_ap(void *handle, unsigned short apsel) LOG_DEBUG("AP %d enabled", apsel); set_bit(apsel, opened_ap); + last_csw_default[apsel] = 0; return ERROR_OK; } @@ -3261,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); @@ -3291,6 +4210,8 @@ static int stlink_dap_op_connect(struct adiv5_dap *dap) dap->do_reconnect = false; dap_invalidate_cache(dap); + for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) + last_csw_default[i] = 0; retval = dap_dp_init(dap); if (retval != ERROR_OK) { @@ -3332,8 +4253,7 @@ static int stlink_dap_op_send_sequence(struct adiv5_dap *dap, enum swd_special_s } /** */ -static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg, - uint32_t *data) +static int stlink_dap_dp_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data) { uint32_t dummy; int retval; @@ -3344,11 +4264,7 @@ static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg, return ERROR_COMMAND_NOTFOUND; } - retval = stlink_dap_check_reconnect(dap); - if (retval != ERROR_OK) - return retval; - - data = data ? : &dummy; + data = data ? data : &dummy; if (stlink_dap_handle->version.flags & STLINK_F_QUIRK_JTAG_DP_READ && stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) { /* Quirk required in JTAG. Read RDBUFF to get the data */ @@ -3362,12 +4278,11 @@ static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg, STLINK_DEBUG_PORT_ACCESS, reg, data); } - return stlink_dap_record_error(retval); + return retval; } /** */ -static int stlink_dap_op_queue_dp_write(struct adiv5_dap *dap, unsigned reg, - uint32_t data) +static int stlink_dap_dp_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data) { int retval; @@ -3383,53 +4298,55 @@ static int stlink_dap_op_queue_dp_write(struct adiv5_dap *dap, unsigned reg, data &= ~DP_SELECT_DPBANK; } - retval = stlink_dap_check_reconnect(dap); - if (retval != ERROR_OK) - return retval; - /* ST-Link does not like that we set CORUNDETECT */ if (reg == DP_CTRL_STAT) data &= ~CORUNDETECT; retval = stlink_write_dap_register(stlink_dap_handle, STLINK_DEBUG_PORT_ACCESS, reg, data); - return stlink_dap_record_error(retval); + return retval; } /** */ -static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned reg, - uint32_t *data) +static int stlink_dap_ap_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) { struct adiv5_dap *dap = ap->dap; uint32_t dummy; int retval; - retval = stlink_dap_check_reconnect(dap); - if (retval != ERROR_OK) - return 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; + } - if (reg != AP_REG_IDR) { + if (reg != ADIV5_AP_REG_IDR) { retval = stlink_dap_open_ap(ap->ap_num); if (retval != ERROR_OK) return retval; } - data = data ? : &dummy; + data = data ? data : &dummy; retval = stlink_read_dap_register(stlink_dap_handle, ap->ap_num, reg, data); dap->stlink_flush_ap_write = false; - return stlink_dap_record_error(retval); + return retval; } /** */ -static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned reg, - uint32_t data) +static int stlink_dap_ap_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) { struct adiv5_dap *dap = ap->dap; int retval; - retval = stlink_dap_check_reconnect(dap); - if (retval != ERROR_OK) - return 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) @@ -3438,7 +4355,7 @@ static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned reg, retval = stlink_write_dap_register(stlink_dap_handle, ap->ap_num, reg, data); dap->stlink_flush_ap_write = true; - return stlink_dap_record_error(retval); + return retval; } /** */ @@ -3448,8 +4365,305 @@ static int stlink_dap_op_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) return ERROR_OK; } +#define RW_MISC_CMD_ADDRESS 1 +#define RW_MISC_CMD_WRITE 2 +#define RW_MISC_CMD_READ 3 +#define RW_MISC_CMD_APNUM 5 + +static int stlink_usb_misc_rw_segment(void *handle, const struct dap_queue *q, unsigned int len, unsigned int items) +{ + uint8_t buf[2 * 4 * items]; + + LOG_DEBUG("Queue: %u commands in %u items", len, items); + + 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++) { + if (ap_num != q[i].mem_ap.ap->ap_num) { + ap_num = q[i].mem_ap.ap->ap_num; + buf[cmd_index++] = RW_MISC_CMD_APNUM; + h_u32_to_le(&buf[val_index], ap_num); + val_index += 4; + } + + switch (q[i].cmd) { + case CMD_MEM_AP_READ32: + buf[cmd_index++] = RW_MISC_CMD_READ; + h_u32_to_le(&buf[val_index], q[i].mem_ap.addr); + val_index += 4; + break; + case CMD_MEM_AP_WRITE32: + buf[cmd_index++] = RW_MISC_CMD_ADDRESS; + h_u32_to_le(&buf[val_index], q[i].mem_ap.addr); + val_index += 4; + buf[cmd_index++] = RW_MISC_CMD_WRITE; + h_u32_to_le(&buf[val_index], q[i].mem_ap.data); + val_index += 4; + break; + default: + /* Not supposed to happen */ + return ERROR_FAIL; + } + } + /* pad after last command */ + while (!IS_ALIGNED(cmd_index, 4)) + buf[cmd_index++] = 0; + + int retval = stlink_usb_rw_misc_out(handle, items, buf); + if (retval != ERROR_OK) + return retval; + + retval = stlink_usb_rw_misc_in(handle, items, buf); + if (retval != ERROR_OK) + return retval; + + ap_num = DP_APSEL_INVALID; + val_index = 0; + unsigned int err_index = 4 * items; + for (unsigned int i = 0; i < len; i++) { + uint32_t errcode = le_to_h_u32(&buf[err_index]); + if (errcode != STLINK_DEBUG_ERR_OK) { + LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode); + return ERROR_FAIL; + } + if (ap_num != q[i].mem_ap.ap->ap_num) { + ap_num = q[i].mem_ap.ap->ap_num; + err_index += 4; + val_index += 4; + errcode = le_to_h_u32(&buf[err_index]); + if (errcode != STLINK_DEBUG_ERR_OK) { + LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode); + return ERROR_FAIL; + } + } + + if (q[i].cmd == CMD_MEM_AP_READ32) { + *q[i].mem_ap.p_data = le_to_h_u32(&buf[val_index]); + } else { /* q[i]->cmd == CMD_MEM_AP_WRITE32 */ + err_index += 4; + val_index += 4; + errcode = le_to_h_u32(&buf[err_index]); + if (errcode != STLINK_DEBUG_ERR_OK) { + LOG_ERROR("unknown/unexpected STLINK status code 0x%x", errcode); + return ERROR_FAIL; + } + } + err_index += 4; + val_index += 4; + } + + return ERROR_OK; +} + +static int stlink_usb_buf_rw_segment(void *handle, const struct dap_queue *q, unsigned int count) +{ + uint32_t bufsize = count * CMD_MEM_AP_2_SIZE(q[0].cmd); + uint8_t buf[bufsize]; + uint8_t ap_num = q[0].mem_ap.ap->ap_num; + uint32_t addr = q[0].mem_ap.addr; + uint32_t csw = q[0].mem_ap.csw; + + int retval = stlink_dap_open_ap(ap_num); + if (retval != ERROR_OK) + return retval; + + switch (q[0].cmd) { + case CMD_MEM_AP_WRITE8: + for (unsigned int i = 0; i < count; i++) + buf[i] = q[i].mem_ap.data >> 8 * (q[i].mem_ap.addr & 3); + return stlink_usb_write_mem8(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); + + case CMD_MEM_AP_WRITE16: + for (unsigned int i = 0; i < count; i++) + h_u16_to_le(&buf[2 * i], q[i].mem_ap.data >> 8 * (q[i].mem_ap.addr & 2)); + return stlink_usb_write_mem16(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); + + case CMD_MEM_AP_WRITE32: + for (unsigned int i = 0; i < count; i++) + h_u32_to_le(&buf[4 * i], q[i].mem_ap.data); + if (count > 1 && q[0].mem_ap.addr == q[1].mem_ap.addr) + return stlink_usb_write_mem32_noaddrinc(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); + else + return stlink_usb_write_mem32(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); + + case CMD_MEM_AP_READ8: + retval = stlink_usb_read_mem8(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); + if (retval == ERROR_OK) + for (unsigned int i = 0; i < count; i++) + *q[i].mem_ap.p_data = buf[i] << 8 * (q[i].mem_ap.addr & 3); + return retval; + + case CMD_MEM_AP_READ16: + retval = stlink_usb_read_mem16(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); + if (retval == ERROR_OK) + for (unsigned int i = 0; i < count; i++) + *q[i].mem_ap.p_data = le_to_h_u16(&buf[2 * i]) << 8 * (q[i].mem_ap.addr & 2); + return retval; + + case CMD_MEM_AP_READ32: + if (count > 1 && q[0].mem_ap.addr == q[1].mem_ap.addr) + retval = stlink_usb_read_mem32_noaddrinc(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); + else + retval = stlink_usb_read_mem32(stlink_dap_handle, ap_num, csw, addr, bufsize, buf); + if (retval == ERROR_OK) + for (unsigned int i = 0; i < count; i++) + *q[i].mem_ap.p_data = le_to_h_u32(&buf[4 * i]); + return retval; + + default: + return ERROR_FAIL; + }; +} + +/* TODO: recover these values with cmd STLINK_DEBUG_APIV2_RW_MISC_GET_MAX (0x53) */ +#define STLINK_V2_RW_MISC_SIZE (64) +#define STLINK_V3_RW_MISC_SIZE (1227) + +static int stlink_usb_count_misc_rw_queue(void *handle, const struct dap_queue *q, unsigned int len, + unsigned int *pkt_items) +{ + struct stlink_usb_handle_s *h = handle; + unsigned int i, items = 0; + 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)) + return 0; + /* + * Before stlink-server API v3, RW_MISC sequence doesn't lock the st-link, + * so are not safe in shared mode. + * Don't use it with TCP backend to prevent any issue in case of sharing. + * This further degrades the performance, on top of TCP server overhead. + */ + if (h->backend == &stlink_tcp_backend && h->tcp_backend_priv.version.api < 3) + return 0; + + for (i = 0; i < len; i++) { + if (q[i].cmd != CMD_MEM_AP_READ32 && q[i].cmd != CMD_MEM_AP_WRITE32) + break; + unsigned int count = 1; + if (ap_num != q[i].mem_ap.ap->ap_num) { + count++; + ap_num = q[i].mem_ap.ap->ap_num; + } + if (q[i].cmd == CMD_MEM_AP_WRITE32) + count++; + if (items + count > misc_max_items) + break; + items += count; + } + + *pkt_items = items; + + return i; +} + +static int stlink_usb_count_buf_rw_queue(const struct dap_queue *q, unsigned int len) +{ + uint32_t incr = CMD_MEM_AP_2_SIZE(q[0].cmd); + unsigned int len_max; + + if (incr == 1) + len_max = stlink_usb_block(stlink_dap_handle); + else + len_max = STLINK_MAX_RW16_32 / incr; + + /* check for no address increment, 32 bits only */ + if (len > 1 && incr == 4 && q[0].mem_ap.addr == q[1].mem_ap.addr) + incr = 0; + + if (len > len_max) + len = len_max; + + for (unsigned int i = 1; i < len; i++) + if (q[i].cmd != q[0].cmd || + q[i].mem_ap.ap != q[0].mem_ap.ap || + q[i].mem_ap.csw != q[0].mem_ap.csw || + q[i].mem_ap.addr != q[i - 1].mem_ap.addr + incr) + return i; + + return len; +} + +static int stlink_usb_mem_rw_queue(void *handle, const struct dap_queue *q, unsigned int len, unsigned int *skip) +{ + unsigned int count, misc_items = 0; + int retval; + + unsigned int count_misc = stlink_usb_count_misc_rw_queue(handle, q, len, &misc_items); + unsigned int count_buf = stlink_usb_count_buf_rw_queue(q, len); + + if (count_misc > count_buf) { + count = count_misc; + retval = stlink_usb_misc_rw_segment(handle, q, count, misc_items); + } else { + count = count_buf; + retval = stlink_usb_buf_rw_segment(handle, q, count_buf); + } + if (retval != ERROR_OK) + return retval; + + *skip = count; + return ERROR_OK; +} + +static void stlink_dap_run_internal(struct adiv5_dap *dap) +{ + int retval = stlink_dap_check_reconnect(dap); + if (retval != ERROR_OK) { + stlink_dap_handle->queue_index = 0; + stlink_dap_record_error(retval); + return; + } + + unsigned int i = stlink_dap_handle->queue_index; + struct dap_queue *q = &stlink_dap_handle->queue[0]; + + while (i && stlink_dap_get_error() == ERROR_OK) { + unsigned int skip = 1; + + switch (q->cmd) { + case CMD_DP_READ: + retval = stlink_dap_dp_read(q->dp_r.dap, q->dp_r.reg, q->dp_r.p_data); + break; + case CMD_DP_WRITE: + retval = stlink_dap_dp_write(q->dp_w.dap, q->dp_w.reg, q->dp_w.data); + break; + case CMD_AP_READ: + retval = stlink_dap_ap_read(q->ap_r.ap, q->ap_r.reg, q->ap_r.p_data); + break; + case CMD_AP_WRITE: + /* ignore increment packed, not supported */ + 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; + + case CMD_MEM_AP_READ8: + case CMD_MEM_AP_READ16: + case CMD_MEM_AP_READ32: + case CMD_MEM_AP_WRITE8: + case CMD_MEM_AP_WRITE16: + case CMD_MEM_AP_WRITE32: + retval = stlink_usb_mem_rw_queue(stlink_dap_handle, q, i, &skip); + break; + + default: + LOG_ERROR("ST-Link: Unknown queue command %d", q->cmd); + retval = ERROR_FAIL; + break; + } + stlink_dap_record_error(retval); + q += skip; + i -= skip; + } + + stlink_dap_handle->queue_index = 0; +} + /** */ -static int stlink_dap_op_run(struct adiv5_dap *dap) +static int stlink_dap_run_finalize(struct adiv5_dap *dap) { uint32_t ctrlstat, pwrmask; int retval, saved_retval; @@ -3464,7 +4678,7 @@ static int stlink_dap_op_run(struct adiv5_dap *dap) */ if (dap->stlink_flush_ap_write) { dap->stlink_flush_ap_write = false; - retval = stlink_dap_op_queue_dp_read(dap, DP_RDBUFF, NULL); + retval = stlink_dap_dp_read(dap, DP_RDBUFF, NULL); if (retval != ERROR_OK) { dap->do_reconnect = true; return retval; @@ -3473,12 +4687,7 @@ static int stlink_dap_op_run(struct adiv5_dap *dap) saved_retval = stlink_dap_get_and_clear_error(); - retval = stlink_dap_op_queue_dp_read(dap, DP_CTRL_STAT, &ctrlstat); - if (retval != ERROR_OK) { - dap->do_reconnect = true; - return retval; - } - retval = stlink_dap_get_and_clear_error(); + retval = stlink_dap_dp_read(dap, DP_CTRL_STAT, &ctrlstat); if (retval != ERROR_OK) { LOG_ERROR("Fail reading CTRL/STAT register. Force reconnect"); dap->do_reconnect = true; @@ -3487,15 +4696,10 @@ static int stlink_dap_op_run(struct adiv5_dap *dap) if (ctrlstat & SSTICKYERR) { if (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) - retval = stlink_dap_op_queue_dp_write(dap, DP_CTRL_STAT, + retval = stlink_dap_dp_write(dap, DP_CTRL_STAT, ctrlstat & (dap->dp_ctrl_stat | SSTICKYERR)); else - retval = stlink_dap_op_queue_dp_write(dap, DP_ABORT, STKERRCLR); - if (retval != ERROR_OK) { - dap->do_reconnect = true; - return retval; - } - retval = stlink_dap_get_and_clear_error(); + retval = stlink_dap_dp_write(dap, DP_ABORT, STKERRCLR); if (retval != ERROR_OK) { dap->do_reconnect = true; return retval; @@ -3510,6 +4714,12 @@ static int stlink_dap_op_run(struct adiv5_dap *dap) return saved_retval; } +static int stlink_dap_op_queue_run(struct adiv5_dap *dap) +{ + stlink_dap_run_internal(dap); + return stlink_dap_run_finalize(dap); +} + /** */ static void stlink_dap_op_quit(struct adiv5_dap *dap) { @@ -3520,6 +4730,183 @@ static void stlink_dap_op_quit(struct adiv5_dap *dap) LOG_ERROR("Error closing APs"); } +static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned int reg, + uint32_t *data) +{ + if (stlink_dap_get_error() != ERROR_OK) + return ERROR_OK; + + unsigned int i = stlink_dap_handle->queue_index++; + struct dap_queue *q = &stlink_dap_handle->queue[i]; + q->cmd = CMD_DP_READ; + q->dp_r.reg = reg; + q->dp_r.dap = dap; + q->dp_r.p_data = data; + + if (i == MAX_QUEUE_DEPTH - 1) + stlink_dap_run_internal(dap); + + return ERROR_OK; +} + +static int stlink_dap_op_queue_dp_write(struct adiv5_dap *dap, unsigned int reg, + uint32_t data) +{ + if (stlink_dap_get_error() != ERROR_OK) + return ERROR_OK; + + unsigned int i = stlink_dap_handle->queue_index++; + struct dap_queue *q = &stlink_dap_handle->queue[i]; + q->cmd = CMD_DP_WRITE; + q->dp_w.reg = reg; + q->dp_w.dap = dap; + q->dp_w.data = data; + + if (i == MAX_QUEUE_DEPTH - 1) + stlink_dap_run_internal(dap); + + return ERROR_OK; +} + +static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned int reg, + uint32_t *data) +{ + if (stlink_dap_get_error() != ERROR_OK) + return ERROR_OK; + + unsigned int i = stlink_dap_handle->queue_index++; + struct dap_queue *q = &stlink_dap_handle->queue[i]; + + /* 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 == 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 == 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 == ADIV5_MEM_AP_REG_CSW && + !prev_q->ap_w.changes_csw_default) { + stlink_dap_handle->queue_index = i; + q = prev_q; + } + + switch (ap->csw_value & CSW_SIZE_MASK) { + case CSW_8BIT: + q->cmd = CMD_MEM_AP_READ8; + break; + case CSW_16BIT: + q->cmd = CMD_MEM_AP_READ16; + break; + case CSW_32BIT: + q->cmd = CMD_MEM_AP_READ32; + break; + default: + LOG_ERROR("ST-Link: Unsupported CSW size %d", ap->csw_value & CSW_SIZE_MASK); + stlink_dap_record_error(ERROR_FAIL); + return ERROR_FAIL; + } + + 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; + + /* force TAR and CSW update */ + ap->tar_valid = false; + ap->csw_value = 0; + } else { + q->cmd = CMD_AP_READ; + q->ap_r.reg = reg; + q->ap_r.ap = ap; + q->ap_r.p_data = data; + } + + if (i == MAX_QUEUE_DEPTH - 1) + stlink_dap_run_internal(ap->dap); + + return ERROR_OK; +} + +static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned int reg, + uint32_t data) +{ + if (stlink_dap_get_error() != ERROR_OK) + return ERROR_OK; + + unsigned int i = stlink_dap_handle->queue_index++; + struct dap_queue *q = &stlink_dap_handle->queue[i]; + + /* 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 == 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 == 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 == ADIV5_MEM_AP_REG_CSW && + !prev_q->ap_w.changes_csw_default) { + stlink_dap_handle->queue_index = i; + q = prev_q; + } + + switch (ap->csw_value & CSW_SIZE_MASK) { + case CSW_8BIT: + q->cmd = CMD_MEM_AP_WRITE8; + break; + case CSW_16BIT: + q->cmd = CMD_MEM_AP_WRITE16; + break; + case CSW_32BIT: + q->cmd = CMD_MEM_AP_WRITE32; + break; + default: + LOG_ERROR("ST-Link: Unsupported CSW size %d", ap->csw_value & CSW_SIZE_MASK); + stlink_dap_record_error(ERROR_FAIL); + return ERROR_FAIL; + } + + 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; + + /* force TAR and CSW update */ + ap->tar_valid = false; + ap->csw_value = 0; + } else { + q->cmd = CMD_AP_WRITE; + q->ap_w.reg = reg; + q->ap_w.ap = ap; + q->ap_w.data = data; + 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_num] = ap->csw_default; + } else { + q->ap_w.changes_csw_default = false; + } + } + + if (i == MAX_QUEUE_DEPTH - 1) + stlink_dap_run_internal(ap->dap); + + return ERROR_OK; +} + static int stlink_swim_op_srst(void) { return stlink_swim_generate_rst(stlink_dap_handle); @@ -3535,7 +4922,7 @@ static int stlink_swim_op_read_mem(uint32_t addr, uint32_t size, count *= size; while (count) { - bytes_remaining = (count > STLINK_DATA_SIZE) ? STLINK_DATA_SIZE : count; + bytes_remaining = (count > STLINK_SWIM_DATA_SIZE) ? STLINK_SWIM_DATA_SIZE : count; retval = stlink_swim_readbytes(stlink_dap_handle, addr, bytes_remaining, buffer); if (retval != ERROR_OK) return retval; @@ -3558,7 +4945,7 @@ static int stlink_swim_op_write_mem(uint32_t addr, uint32_t size, count *= size; while (count) { - bytes_remaining = (count > STLINK_DATA_SIZE) ? STLINK_DATA_SIZE : count; + bytes_remaining = (count > STLINK_SWIM_DATA_SIZE) ? STLINK_SWIM_DATA_SIZE : count; retval = stlink_swim_writebytes(stlink_dap_handle, addr, bytes_remaining, buffer); if (retval != ERROR_OK) return retval; @@ -3597,25 +4984,6 @@ static int stlink_dap_trace_read(uint8_t *buf, size_t *size) return stlink_usb_trace_read(stlink_dap_handle, buf, size); } -/** */ -COMMAND_HANDLER(stlink_dap_serial_command) -{ - LOG_DEBUG("stlink_dap_serial_command"); - - if (CMD_ARGC != 1) { - LOG_ERROR("Expected exactly one argument for \"st-link serial <serial-number>\"."); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - if (stlink_dap_param.serial) { - LOG_WARNING("Command \"st-link serial\" already used. Replacing previous value"); - free((void *)stlink_dap_param.serial); - } - - stlink_dap_param.serial = strdup(CMD_ARGV[0]); - return ERROR_OK; -} - /** */ COMMAND_HANDLER(stlink_dap_vid_pid) { @@ -3641,15 +5009,71 @@ COMMAND_HANDLER(stlink_dap_vid_pid) return ERROR_OK; } +/** */ +COMMAND_HANDLER(stlink_dap_backend_command) +{ + /* default values */ + bool use_stlink_tcp = false; + uint16_t stlink_tcp_port = 7184; + + if (CMD_ARGC == 0 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; + else if (strcmp(CMD_ARGV[0], "usb") == 0) { + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + /* else use_stlink_tcp = false (already the case ) */ + } else if (strcmp(CMD_ARGV[0], "tcp") == 0) { + use_stlink_tcp = true; + if (CMD_ARGC == 2) + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], stlink_tcp_port); + } else + return ERROR_COMMAND_SYNTAX_ERROR; + + stlink_dap_param.use_stlink_tcp = use_stlink_tcp; + stlink_dap_param.stlink_tcp_port = stlink_tcp_port; + + return ERROR_OK; +} + +#define BYTES_PER_LINE 16 +COMMAND_HANDLER(stlink_dap_cmd_command) +{ + unsigned int rx_n, tx_n; + struct stlink_usb_handle_s *h = stlink_dap_handle; + + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], rx_n); + tx_n = CMD_ARGC - 1; + if (tx_n > STLINK_SG_SIZE || rx_n > STLINK_DATA_SIZE) { + LOG_ERROR("max %x byte sent and %d received", STLINK_SG_SIZE, STLINK_DATA_SIZE); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + stlink_usb_init_buffer(h, h->rx_ep, rx_n); + + for (unsigned int i = 0; i < tx_n; i++) { + uint8_t byte; + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[i + 1], byte); + h->cmdbuf[h->cmdidx++] = byte; + } + + int retval = stlink_usb_xfer_noerrcheck(h, h->databuf, rx_n); + if (retval != ERROR_OK) { + LOG_ERROR("Error %d", retval); + return retval; + } + + for (unsigned int i = 0; i < rx_n; i++) + command_print_sameline(CMD, "0x%02x%c", h->databuf[i], + ((i == (rx_n - 1)) || ((i % BYTES_PER_LINE) == (BYTES_PER_LINE - 1))) ? '\n' : ' '); + + return ERROR_OK; +} + /** */ static const struct command_registration stlink_dap_subcommand_handlers[] = { - { - .name = "serial", - .handler = stlink_dap_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the serial number of the adapter", - .usage = "<serial_number>", - }, { .name = "vid_pid", .handler = stlink_dap_vid_pid, @@ -3657,6 +5081,20 @@ static const struct command_registration stlink_dap_subcommand_handlers[] = { .help = "USB VID and PID of the adapter", .usage = "(vid pid)+", }, + { + .name = "backend", + .handler = &stlink_dap_backend_command, + .mode = COMMAND_CONFIG, + .help = "select which ST-Link backend to use", + .usage = "usb | tcp [port]", + }, + { + .name = "cmd", + .handler = stlink_dap_cmd_command, + .mode = COMMAND_EXEC, + .help = "send arbitrary command", + .usage = "rx_n (tx_byte)+", + }, COMMAND_REGISTRATION_DONE }; @@ -3699,7 +5137,7 @@ static int stlink_dap_init(void) return ERROR_FAIL; } - retval = stlink_usb_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle); + retval = stlink_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle); if (retval != ERROR_OK) return retval; @@ -3716,10 +5154,7 @@ static int stlink_dap_quit(void) { LOG_DEBUG("stlink_dap_quit()"); - free((void *)stlink_dap_param.serial); - stlink_dap_param.serial = NULL; - - return stlink_usb_close(stlink_dap_handle); + return stlink_close(stlink_dap_handle); } /** */ @@ -3771,7 +5206,7 @@ static const struct dap_ops stlink_dap_ops = { .queue_ap_read = stlink_dap_op_queue_ap_read, .queue_ap_write = stlink_dap_op_queue_ap_write, .queue_ap_abort = stlink_dap_op_queue_ap_abort, - .run = stlink_dap_op_run, + .run = stlink_dap_op_queue_run, .sync = NULL, /* optional */ .quit = stlink_dap_op_quit, /* optional */ }; diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c index 78a4c5b77e..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 @@ -468,72 +457,72 @@ COMMAND_HANDLER(sysfsgpio_handle_swd_gpionum_swdio) return ERROR_OK; } -static const struct command_registration sysfsgpio_command_handlers[] = { +static const struct command_registration sysfsgpio_subcommand_handlers[] = { { - .name = "sysfsgpio_jtag_nums", + .name = "jtag_nums", .handler = &sysfsgpio_handle_jtag_gpionums, .mode = COMMAND_CONFIG, .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", .usage = "[tck tms tdi tdo]", }, { - .name = "sysfsgpio_tck_num", + .name = "tck_num", .handler = &sysfsgpio_handle_jtag_gpionum_tck, .mode = COMMAND_CONFIG, .help = "gpio number for tck.", .usage = "[tck]", }, { - .name = "sysfsgpio_tms_num", + .name = "tms_num", .handler = &sysfsgpio_handle_jtag_gpionum_tms, .mode = COMMAND_CONFIG, .help = "gpio number for tms.", .usage = "[tms]", }, { - .name = "sysfsgpio_tdo_num", + .name = "tdo_num", .handler = &sysfsgpio_handle_jtag_gpionum_tdo, .mode = COMMAND_CONFIG, .help = "gpio number for tdo.", .usage = "[tdo]", }, { - .name = "sysfsgpio_tdi_num", + .name = "tdi_num", .handler = &sysfsgpio_handle_jtag_gpionum_tdi, .mode = COMMAND_CONFIG, .help = "gpio number for tdi.", .usage = "[tdi]", }, { - .name = "sysfsgpio_srst_num", + .name = "srst_num", .handler = &sysfsgpio_handle_jtag_gpionum_srst, .mode = COMMAND_CONFIG, .help = "gpio number for srst.", .usage = "[srst]", }, { - .name = "sysfsgpio_trst_num", + .name = "trst_num", .handler = &sysfsgpio_handle_jtag_gpionum_trst, .mode = COMMAND_CONFIG, .help = "gpio number for trst.", .usage = "[trst]", }, { - .name = "sysfsgpio_swd_nums", + .name = "swd_nums", .handler = &sysfsgpio_handle_swd_gpionums, .mode = COMMAND_CONFIG, .help = "gpio numbers for swclk, swdio. (in that order)", .usage = "[swclk swdio]", }, { - .name = "sysfsgpio_swclk_num", + .name = "swclk_num", .handler = &sysfsgpio_handle_swd_gpionum_swclk, .mode = COMMAND_CONFIG, .help = "gpio number for swclk.", .usage = "[swclk]", }, { - .name = "sysfsgpio_swdio_num", + .name = "swdio_num", .handler = &sysfsgpio_handle_swd_gpionum_swdio, .mode = COMMAND_CONFIG, .help = "gpio number for swdio.", @@ -542,6 +531,17 @@ static const struct command_registration sysfsgpio_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration sysfsgpio_command_handlers[] = { + { + .name = "sysfsgpio", + .mode = COMMAND_ANY, + .help = "perform sysfsgpio management", + .chain = sysfsgpio_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static int sysfsgpio_init(void); static int sysfsgpio_quit(void); @@ -571,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 d276e588f5..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 @@ -23,6 +12,7 @@ /* project specific includes */ #include <helper/binarybuffer.h> +#include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/hla/hla_layout.h> #include <jtag/hla/hla_transport.h> @@ -31,21 +21,20 @@ #include <target/cortex_m.h> -#include <libusb.h> +#include "libusb_helper.h" #define ICDI_WRITE_ENDPOINT 0x02 #define ICDI_READ_ENDPOINT 0x83 -#define ICDI_WRITE_TIMEOUT 1000 -#define ICDI_READ_TIMEOUT 1000 +#define ICDI_WRITE_TIMEOUT (LIBUSB_TIMEOUT_MS) +#define ICDI_READ_TIMEOUT (LIBUSB_TIMEOUT_MS) #define ICDI_PACKET_SIZE 2048 #define PACKET_START "$" #define PACKET_END "#" struct icdi_usb_handle_s { - libusb_context *usb_ctx; - libusb_device_handle *usb_dev; + struct libusb_device_handle *usb_dev; char *read_buffer; char *write_buffer; @@ -123,7 +112,7 @@ static int icdi_send_packet(void *handle, int len) int result, retry = 0; int transferred = 0; - assert(handle != NULL); + assert(handle); /* check we have a large enough buffer for checksum "#00" */ if (len + 3 > h->max_packet) { @@ -254,7 +243,7 @@ static int icdi_get_cmd_result(void *handle) int offset = 0; char ch; - assert(handle != NULL); + assert(handle); do { ch = h->read_buffer[offset++]; @@ -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; } @@ -476,13 +465,13 @@ static int icdi_usb_read_regs(void *handle) return ERROR_OK; } -static int icdi_usb_read_reg(void *handle, int num, uint32_t *val) +static int icdi_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { int result; struct icdi_usb_handle_s *h = handle; char cmd[10]; - snprintf(cmd, sizeof(cmd), "p%x", num); + snprintf(cmd, sizeof(cmd), "p%x", regsel); result = icdi_send_cmd(handle, cmd); if (result != ERROR_OK) return result; @@ -505,14 +494,14 @@ static int icdi_usb_read_reg(void *handle, int num, uint32_t *val) return result; } -static int icdi_usb_write_reg(void *handle, int num, uint32_t val) +static int icdi_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) { int result; char cmd[20]; uint8_t buf[4]; h_u32_to_le(buf, val); - int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", num); + int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", regsel); hexify(cmd + cmd_len, buf, 4, sizeof(cmd)); result = icdi_send_cmd(handle, cmd); @@ -657,10 +646,7 @@ static int icdi_usb_close(void *handle) return ERROR_OK; if (h->usb_dev) - libusb_close(h->usb_dev); - - if (h->usb_ctx) - libusb_exit(h->usb_ctx); + jtag_libusb_close(h->usb_dev); free(h->read_buffer); free(h->write_buffer); @@ -670,6 +656,7 @@ static int icdi_usb_close(void *handle) static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) { + /* TODO: Convert remaining libusb_ calls to jtag_libusb_ */ int retval; struct icdi_usb_handle_s *h; @@ -677,24 +664,19 @@ 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; } - LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport, - param->vid[0], param->pid[0]); - - /* TODO: convert libusb_ calls to jtag_libusb_ */ - if (param->vid[1]) - LOG_WARNING("Bad configuration: 'hla_vid_pid' command does not accept more than one VID PID pair on ti-icdi!"); + for (uint8_t i = 0; param->vid[i] && param->pid[i]; ++i) + LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", param->transport, + param->vid[i], param->pid[i], adapter_get_required_serial() ? adapter_get_required_serial() : ""); - if (libusb_init(&h->usb_ctx) != 0) { - LOG_ERROR("libusb init failed"); - goto error_open; - } + /* 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, NULL, &h->usb_dev, NULL); - h->usb_dev = libusb_open_device_with_vid_pid(h->usb_ctx, param->vid[0], param->pid[0]); if (!h->usb_dev) { LOG_ERROR("open failed"); goto error_open; @@ -730,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 68249dcfe6..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 @@ -21,10 +10,12 @@ #endif #include <math.h> +#include "helper/system.h" #include <jtag/interface.h> #include <jtag/commands.h> #include <target/image.h> #include <libusb.h> +#include "libusb_helper.h" #include "OpenULINK/include/msgtypes.h" /** USB Vendor ID of ULINK device in unconfigured state (no firmware loaded @@ -54,9 +45,6 @@ /** USB interface number */ #define USB_INTERFACE 0 -/** libusb timeout in ms */ -#define USB_TIMEOUT 5000 - /** Delay (in microseconds) to wait while EZ-USB performs ReNumeration. */ #define ULINK_RENUMERATION_DELAY 1500000 @@ -148,6 +136,9 @@ struct ulink { struct libusb_device_handle *usb_device_handle; enum ulink_type type; + unsigned int ep_in; /**< IN endpoint number */ + unsigned int ep_out; /**< OUT endpoint number */ + 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 */ @@ -162,34 +153,34 @@ struct ulink { /**************************** Function Prototypes *****************************/ /* USB helper functions */ -int ulink_usb_open(struct ulink **device); -int ulink_usb_close(struct ulink **device); +static int ulink_usb_open(struct ulink **device); +static int ulink_usb_close(struct ulink **device); /* ULINK MCU (Cypress EZ-USB) specific functions */ -int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit); -int ulink_load_firmware_and_renumerate(struct ulink **device, const char *filename, +static int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit); +static int ulink_load_firmware_and_renumerate(struct ulink **device, const char *filename, uint32_t delay); -int ulink_load_firmware(struct ulink *device, const char *filename); -int ulink_write_firmware_section(struct ulink *device, +static int ulink_load_firmware(struct ulink *device, const char *filename); +static int ulink_write_firmware_section(struct ulink *device, struct image *firmware_image, int section_index); /* Generic helper functions */ -void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals); +static void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals); /* OpenULINK command generation helper functions */ -int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, +static int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, enum ulink_payload_direction direction); /* OpenULINK command queue helper functions */ -int ulink_get_queue_size(struct ulink *device, +static int ulink_get_queue_size(struct ulink *device, enum ulink_payload_direction direction); -void ulink_clear_queue(struct ulink *device); -int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd); -int ulink_execute_queued_commands(struct ulink *device, int timeout); +static void ulink_clear_queue(struct ulink *device); +static int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd); +static int ulink_execute_queued_commands(struct ulink *device, int timeout); static void ulink_print_queue(struct ulink *device); -int ulink_append_scan_cmd(struct ulink *device, +static int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, int scan_size_bits, uint8_t *tdi, @@ -201,42 +192,42 @@ int ulink_append_scan_cmd(struct ulink *device, uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess); -int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, +static int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, uint8_t sequence); -int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count); -int ulink_append_get_signals_cmd(struct ulink *device); -int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, +static int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count); +static int ulink_append_get_signals_cmd(struct ulink *device); +static int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, uint8_t high); -int ulink_append_sleep_cmd(struct ulink *device, uint32_t us); -int ulink_append_configure_tck_cmd(struct ulink *device, +static int ulink_append_sleep_cmd(struct ulink *device, uint32_t us); +static int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms); -int ulink_append_led_cmd(struct ulink *device, uint8_t led_state); -int ulink_append_test_cmd(struct ulink *device); +static int __attribute__((unused)) ulink_append_led_cmd(struct ulink *device, uint8_t led_state); +static int ulink_append_test_cmd(struct ulink *device); /* OpenULINK TCK frequency helper functions */ -int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay); +static int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay); /* Interface between OpenULINK and OpenOCD */ static void ulink_set_end_state(tap_state_t endstate); -int ulink_queue_statemove(struct ulink *device); +static int ulink_queue_statemove(struct ulink *device); -int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd); -int ulink_post_process_scan(struct ulink_cmd *ulink_cmd); -int ulink_post_process_queue(struct ulink *device); +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); @@ -245,12 +236,12 @@ static int ulink_quit(void); /****************************** Global Variables ******************************/ -struct ulink *ulink_handle; +static struct ulink *ulink_handle; /**************************** USB helper functions ****************************/ /** - * Opens the ULINK device and claims its USB interface. + * Opens the ULINK device * * Currently, only the original ULINK is supported * @@ -258,11 +249,11 @@ struct ulink *ulink_handle; * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_usb_open(struct ulink **device) +static int ulink_usb_open(struct ulink **device) { ssize_t num_devices, i; bool found; - libusb_device **usb_devices; + struct libusb_device **usb_devices; struct libusb_device_descriptor usb_desc; struct libusb_device_handle *usb_device_handle; @@ -288,9 +279,6 @@ int ulink_usb_open(struct ulink **device) return ERROR_FAIL; libusb_free_device_list(usb_devices, 1); - if (libusb_claim_interface(usb_device_handle, 0) != 0) - return ERROR_FAIL; - (*device)->usb_device_handle = usb_device_handle; (*device)->type = ULINK_1; @@ -304,7 +292,7 @@ int ulink_usb_open(struct ulink **device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_usb_close(struct ulink **device) +static int ulink_usb_close(struct ulink **device) { if (libusb_release_interface((*device)->usb_device_handle, 0) != 0) return ERROR_FAIL; @@ -327,13 +315,13 @@ int ulink_usb_close(struct ulink **device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit) +static int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit) { int ret; ret = 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, USB_TIMEOUT); + REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, LIBUSB_TIMEOUT_MS); /* usb_control_msg() returns the number of bytes transferred during the * DATA stage of the control transfer - must be exactly 1 in this case! */ @@ -354,7 +342,7 @@ int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_load_firmware_and_renumerate(struct ulink **device, +static int ulink_load_firmware_and_renumerate(struct ulink **device, const char *filename, uint32_t delay) { int ret; @@ -390,10 +378,10 @@ int ulink_load_firmware_and_renumerate(struct ulink **device, * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_load_firmware(struct ulink *device, const char *filename) +static int ulink_load_firmware(struct ulink *device, const char *filename) { struct image ulink_firmware_image; - int ret, i; + int ret; ret = ulink_cpu_reset(device, CPU_RESET); if (ret != ERROR_OK) { @@ -402,7 +390,7 @@ int ulink_load_firmware(struct ulink *device, const char *filename) } ulink_firmware_image.base_address = 0; - ulink_firmware_image.base_address_set = 0; + ulink_firmware_image.base_address_set = false; ret = image_open(&ulink_firmware_image, filename, "ihex"); if (ret != ERROR_OK) { @@ -411,7 +399,7 @@ int ulink_load_firmware(struct ulink *device, const char *filename) } /* Download all sections in the image to ULINK */ - for (i = 0; i < ulink_firmware_image.num_sections; i++) { + for (unsigned int i = 0; i < ulink_firmware_image.num_sections; i++) { ret = ulink_write_firmware_section(device, &ulink_firmware_image, i); if (ret != ERROR_OK) return ret; @@ -439,7 +427,7 @@ int ulink_load_firmware(struct ulink *device, const char *filename) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_write_firmware_section(struct ulink *device, +static int ulink_write_firmware_section(struct ulink *device, struct image *firmware_image, int section_index) { uint16_t addr, size, bytes_remaining, chunk_size; @@ -476,7 +464,7 @@ int ulink_write_firmware_section(struct ulink *device, ret = libusb_control_transfer(device->usb_device_handle, (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), REQUEST_FIRMWARE_LOAD, addr, FIRMWARE_ADDR, (unsigned char *)data_ptr, - chunk_size, USB_TIMEOUT); + chunk_size, LIBUSB_TIMEOUT_MS); if (ret != (int)chunk_size) { /* Abort if libusb sent less data than requested */ @@ -499,7 +487,7 @@ int ulink_write_firmware_section(struct ulink *device, * @param input_signals input signal states as returned by CMD_GET_SIGNALS * @param output_signals output signal states as returned by CMD_GET_SIGNALS */ -void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals) +static void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals) { LOG_INFO("ULINK signal states: TDI: %i, TDO: %i, TMS: %i, TCK: %i, TRST: %i," " SRST: %i", @@ -522,21 +510,21 @@ void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, +static int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, enum ulink_payload_direction direction) { uint8_t *payload; payload = calloc(size, sizeof(uint8_t)); - if (payload == NULL) { + if (!payload) { LOG_ERROR("Could not allocate OpenULINK command payload: out of memory"); return ERROR_FAIL; } switch (direction) { case PAYLOAD_DIRECTION_OUT: - if (ulink_cmd->payload_out != NULL) { + if (ulink_cmd->payload_out) { LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); free(payload); return ERROR_FAIL; @@ -546,7 +534,7 @@ int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, } break; case PAYLOAD_DIRECTION_IN: - if (ulink_cmd->payload_in_start != NULL) { + if (ulink_cmd->payload_in_start) { LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); free(payload); return ERROR_FAIL; @@ -576,13 +564,13 @@ int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, * @return the number of bytes currently stored in the queue for the specified * direction. */ -int ulink_get_queue_size(struct ulink *device, +static int ulink_get_queue_size(struct ulink *device, enum ulink_payload_direction direction) { struct ulink_cmd *current = device->queue_start; int sum = 0; - while (current != NULL) { + while (current) { switch (direction) { case PAYLOAD_DIRECTION_OUT: sum += current->payload_out_size + 1; /* + 1 byte for Command ID */ @@ -602,15 +590,13 @@ int ulink_get_queue_size(struct ulink *device, * Clear the OpenULINK command queue. * * @param device pointer to struct ulink identifying ULINK driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL */ -void ulink_clear_queue(struct ulink *device) +static void ulink_clear_queue(struct ulink *device) { struct ulink_cmd *current = device->queue_start; struct ulink_cmd *next = NULL; - while (current != NULL) { + while (current) { /* Save pointer to next element */ next = current->next; @@ -647,7 +633,7 @@ void ulink_clear_queue(struct ulink *device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) +static int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) { int newsize_out, newsize_in; int ret = ERROR_OK; @@ -662,7 +648,7 @@ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) 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 = ulink_execute_queued_commands(device, USB_TIMEOUT); + ret = ulink_execute_queued_commands(device, LIBUSB_TIMEOUT_MS); if (ret == ERROR_OK) ret = ulink_post_process_queue(device); @@ -671,7 +657,7 @@ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) ulink_clear_queue(device); } - if (device->queue_start == NULL) { + if (!device->queue_start) { /* Queue was empty */ device->commands_in_queue = 1; @@ -695,10 +681,11 @@ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) * Sends all queued OpenULINK commands to the ULINK for execution. * * @param device pointer to struct ulink identifying ULINK driver instance. + * @param timeout * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_execute_queued_commands(struct ulink *device, int timeout) +static int ulink_execute_queued_commands(struct ulink *device, int timeout) { struct ulink_cmd *current; int ret, i, index_out, index_in, count_out, count_in, transferred; @@ -725,7 +712,7 @@ int ulink_execute_queued_commands(struct ulink *device, int timeout) } /* Send packet to ULINK */ - ret = libusb_bulk_transfer(device->usb_device_handle, (2 | LIBUSB_ENDPOINT_OUT), + ret = libusb_bulk_transfer(device->usb_device_handle, device->ep_out, (unsigned char *)buffer, count_out, &transferred, timeout); if (ret != 0) return ERROR_FAIL; @@ -734,7 +721,7 @@ int ulink_execute_queued_commands(struct ulink *device, int timeout) /* Wait for response if commands contain IN payload data */ if (count_in > 0) { - ret = libusb_bulk_transfer(device->usb_device_handle, (2 | LIBUSB_ENDPOINT_IN), + ret = libusb_bulk_transfer(device->usb_device_handle, device->ep_in, (unsigned char *)buffer, 64, &transferred, timeout); if (ret != 0) return ERROR_FAIL; @@ -865,7 +852,7 @@ static void ulink_print_queue(struct ulink *device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, +static int ulink_append_scan_cmd(struct ulink *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) @@ -874,7 +861,7 @@ int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, int ret, i, scan_size_bytes; uint8_t bits_last_byte; - if (cmd == NULL) + if (!cmd) return ERROR_FAIL; /* Check size of command. USB buffer can hold 64 bytes, 1 byte is command ID, @@ -966,13 +953,13 @@ int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, +static int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, uint8_t sequence) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; - if (cmd == NULL) + if (!cmd) return ERROR_FAIL; if (device->delay_clock_tms < 0) @@ -1003,12 +990,12 @@ int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count) +static int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; - if (cmd == NULL) + if (!cmd) return ERROR_FAIL; if (device->delay_clock_tck < 0) @@ -1036,12 +1023,12 @@ int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_get_signals_cmd(struct ulink *device) +static int ulink_append_get_signals_cmd(struct ulink *device) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; - if (cmd == NULL) + if (!cmd) return ERROR_FAIL; cmd->id = CMD_GET_SIGNALS; @@ -1075,13 +1062,13 @@ int ulink_append_get_signals_cmd(struct ulink *device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, +static int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, uint8_t high) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; - if (cmd == NULL) + if (!cmd) return ERROR_FAIL; cmd->id = CMD_SET_SIGNALS; @@ -1108,12 +1095,12 @@ int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_sleep_cmd(struct ulink *device, uint32_t us) +static int ulink_append_sleep_cmd(struct ulink *device, uint32_t us) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; - if (cmd == NULL) + if (!cmd) return ERROR_FAIL; cmd->id = CMD_SLEEP_US; @@ -1144,13 +1131,13 @@ int ulink_append_sleep_cmd(struct ulink *device, uint32_t us) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, +static int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; - if (cmd == NULL) + if (!cmd) return ERROR_FAIL; cmd->id = CMD_CONFIGURE_TCK_FREQ; @@ -1206,12 +1193,12 @@ int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_led_cmd(struct ulink *device, uint8_t led_state) +static int ulink_append_led_cmd(struct ulink *device, uint8_t led_state) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; - if (cmd == NULL) + if (!cmd) return ERROR_FAIL; cmd->id = CMD_SET_LEDS; @@ -1236,12 +1223,12 @@ int ulink_append_led_cmd(struct ulink *device, uint8_t led_state) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_test_cmd(struct ulink *device) +static int ulink_append_test_cmd(struct ulink *device) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; - if (cmd == NULL) + if (!cmd) return ERROR_FAIL; cmd->id = CMD_TEST; @@ -1292,7 +1279,7 @@ int ulink_append_test_cmd(struct ulink *device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay) +static int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay) { float t, x, x_ceil; @@ -1423,7 +1410,7 @@ static void ulink_set_end_state(tap_state_t endstate) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_statemove(struct ulink *device) +static int ulink_queue_statemove(struct ulink *device) { uint8_t tms_sequence, tms_count; int ret; @@ -1452,7 +1439,7 @@ int ulink_queue_statemove(struct ulink *device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) { uint32_t scan_size_bits, scan_size_bytes, bits_last_scan; uint32_t scans_max_payload, bytecount; @@ -1488,7 +1475,7 @@ int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) if ((type == SCAN_IN) || (type == SCAN_IO)) { tdo_buffer_start = calloc(sizeof(uint8_t), scan_size_bytes); - if (tdo_buffer_start == NULL) + if (!tdo_buffer_start) return ERROR_FAIL; tdo_buffer = tdo_buffer_start; @@ -1566,9 +1553,9 @@ int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) bytecount -= 58; /* Update TDI and TDO buffer pointers */ - if (tdi_buffer_start != NULL) + if (tdi_buffer_start) tdi_buffer += 58; - if (tdo_buffer_start != NULL) + if (tdo_buffer_start) tdo_buffer += 58; } else if (bytecount == 58) { /* Full scan, no further scans */ tms_count_end = last_tms_count; @@ -1631,7 +1618,7 @@ int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd) { int ret; @@ -1654,7 +1641,7 @@ int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd) { int ret; @@ -1681,11 +1668,12 @@ int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd) /** * Execute a JTAG_RESET command * + * @param device * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd) { uint8_t low = 0, high = 0; @@ -1711,7 +1699,7 @@ int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd) { int ret, i, num_states, batch_size, state_count; tap_state_t *path; @@ -1770,7 +1758,7 @@ int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_sleep(struct ulink *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 ULINK device */ @@ -1783,7 +1771,7 @@ int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd) * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. */ -int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd) { int ret; unsigned num_cycles; @@ -1828,7 +1816,7 @@ int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_post_process_scan(struct ulink_cmd *ulink_cmd) +static int ulink_post_process_scan(struct ulink_cmd *ulink_cmd) { struct jtag_command *cmd = ulink_cmd->cmd_origin; int ret; @@ -1859,7 +1847,7 @@ int ulink_post_process_scan(struct ulink_cmd *ulink_cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_post_process_queue(struct ulink *device) +static int ulink_post_process_queue(struct ulink *device) { struct ulink_cmd *current; struct jtag_command *openocd_cmd; @@ -1867,12 +1855,12 @@ int ulink_post_process_queue(struct ulink *device) current = device->queue_start; - while (current != NULL) { + while (current) { openocd_cmd = current->cmd_origin; /* Check if a corresponding OpenOCD command is stored for this * OpenULINK command */ - if ((current->needs_postprocessing == true) && (openocd_cmd != NULL)) { + if ((current->needs_postprocessing == true) && (openocd_cmd)) { switch (openocd_cmd->type) { case JTAG_SCAN: ret = ulink_post_process_scan(current); @@ -1917,9 +1905,9 @@ 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) { @@ -1958,7 +1946,7 @@ static int ulink_execute_queue(void) } if (ulink_handle->commands_in_queue > 0) { - ret = ulink_execute_queued_commands(ulink_handle, USB_TIMEOUT); + ret = ulink_execute_queued_commands(ulink_handle, LIBUSB_TIMEOUT_MS); if (ret != ERROR_OK) return ret; @@ -2118,7 +2106,7 @@ static int ulink_init(void) uint8_t input_signals, output_signals; ulink_handle = calloc(1, sizeof(struct ulink)); - if (ulink_handle == NULL) + if (!ulink_handle) return ERROR_FAIL; libusb_init(&ulink_handle->libusb_ctx); @@ -2156,6 +2144,12 @@ static int ulink_init(void) } else LOG_INFO("ULINK device is already running OpenULINK firmware"); + /* Get OpenULINK USB IN/OUT endpoints and claim the interface */ + ret = jtag_libusb_choose_interface(ulink_handle->usb_device_handle, + &ulink_handle->ep_in, &ulink_handle->ep_out, -1, -1, -1, -1); + if (ret != ERROR_OK) + return ret; + /* Initialize OpenULINK command queue */ ulink_clear_queue(ulink_handle); @@ -2171,7 +2165,7 @@ static int ulink_init(void) * shut down by the user via Ctrl-C. Try to retrieve this Bulk IN packet. */ dummy = calloc(64, sizeof(uint8_t)); - ret = libusb_bulk_transfer(ulink_handle->usb_device_handle, (2 | LIBUSB_ENDPOINT_IN), + ret = libusb_bulk_transfer(ulink_handle->usb_device_handle, ulink_handle->ep_in, dummy, 64, &transferred, 200); free(dummy); @@ -2248,9 +2242,9 @@ COMMAND_HANDLER(ulink_download_firmware_handler) /*************************** Command Registration **************************/ -static const struct command_registration ulink_command_handlers[] = { +static const struct command_registration ulink_subcommand_handlers[] = { { - .name = "ulink_download_firmware", + .name = "download_firmware", .handler = &ulink_download_firmware_handler, .mode = COMMAND_EXEC, .help = "download firmware image to ULINK device", @@ -2259,6 +2253,17 @@ static const struct command_registration ulink_command_handlers[] = { COMMAND_REGISTRATION_DONE, }; +static const struct command_registration ulink_command_handlers[] = { + { + .name = "ulink", + .mode = COMMAND_ANY, + .help = "perform ulink management", + .chain = ulink_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static struct jtag_interface ulink_interface = { .execute_queue = ulink_execute_queue, }; 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 f8ff66e2fb..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 @@ -23,6 +12,7 @@ #endif #include <jtag/interface.h> #include <jtag/commands.h> +#include "helper/system.h" #include <libusb_helper.h> #include <target/image.h> @@ -113,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; @@ -133,13 +124,18 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, return ERROR_FAIL; } + if (libusb_claim_interface(libusb_dev, 0)) { + LOG_ERROR("unable to claim interface"); + return ERROR_JTAG_INIT_FAILED; + } + ublast2_firmware_image.base_address = 0; - ublast2_firmware_image.base_address_set = 0; + ublast2_firmware_image.base_address_set = false; int ret = image_open(&ublast2_firmware_image, low->firmware_path, "ihex"); if (ret != ERROR_OK) { LOG_ERROR("Could not load firmware image"); - return ret; + goto error_release_usb; } /** A host loader program must write 0x01 to the CPUCS register @@ -159,15 +155,16 @@ 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 (int i = 0; i < ublast2_firmware_image.num_sections; i++) { + for (unsigned int i = 0; i < ublast2_firmware_image.num_sections; i++) { ret = ublast2_write_firmware_section(libusb_dev, &ublast2_firmware_image, i); if (ret != ERROR_OK) { LOG_ERROR("Error while downloading the firmware"); - return ret; + goto error_close_firmware; } } @@ -180,11 +177,21 @@ 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); - return ERROR_OK; +error_release_usb: + /* + * Release claimed interface. Most probably it is already disconnected + * and re-enumerated as new devices after firmware upload, so we do + * not need to care about errors. + */ + libusb_release_interface(libusb_dev, 0); + + return ret; } static int ublast2_libusb_init(struct ublast_lowlevel *low) @@ -209,15 +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, NULL, - &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, NULL, - &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..."); } @@ -228,6 +233,12 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) } } + if (libusb_claim_interface(low->libusb_dev, 0)) { + LOG_ERROR("unable to claim interface"); + jtag_libusb_close(low->libusb_dev); + return ERROR_JTAG_INIT_FAILED; + } + char buffer[5]; jtag_libusb_control_transfer(low->libusb_dev, LIBUSB_REQUEST_TYPE_VENDOR | @@ -237,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); @@ -246,6 +258,9 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) static int ublast2_libusb_quit(struct ublast_lowlevel *low) { + if (libusb_release_interface(low->libusb_dev, 0)) + LOG_ERROR("usb release interface failed"); + jtag_libusb_close(low->libusb_dev); return ERROR_OK; }; diff --git a/src/jtag/drivers/usb_blaster/ublast_access.h b/src/jtag/drivers/usb_blaster/ublast_access.h index ad20d65d4f..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 @@ -36,7 +25,6 @@ struct ublast_lowlevel { uint16_t ublast_pid; uint16_t ublast_vid_uninit; uint16_t ublast_pid_uninit; - char *ublast_device_desc; struct libusb_device_handle *libusb_dev; char *firmware_path; 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 9648ba2e23..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/>. - * */ /* @@ -77,6 +66,7 @@ #include <jtag/interface.h> #include <jtag/commands.h> #include <helper/time_support.h> +#include <helper/replacements.h> #include "ublast_access.h" /* system includes */ @@ -118,7 +108,6 @@ struct ublast_info { char *lowlevel_name; struct ublast_lowlevel *drv; - char *ublast_device_desc; uint16_t ublast_vid, ublast_pid; uint16_t ublast_vid_uninit, ublast_pid_uninit; int flags; @@ -139,7 +128,7 @@ static struct ublast_info info = { }; /* - * Available lowlevel drivers (FTDI, FTD2xx, ...) + * Available lowlevel drivers (FTDI, libusb, ...) */ struct drvs_map { char *name; @@ -253,7 +242,7 @@ static void ublast_flush_buffer(void) /** * ublast_queue_byte - queue one 'bitbang mode' byte for USB Blaster - * @abyte: the byte to queue + * @param abyte the byte to queue * * Queues one byte in 'bitbang mode' to the USB Blaster. The byte is not * actually sent, but stored in a buffer. The write is performed once @@ -271,11 +260,11 @@ static void ublast_queue_byte(uint8_t abyte) /** * ublast_compute_pin - compute if gpio should be asserted - * @steer: control (ie. TRST driven, SRST driven, of fixed) + * @param steer control (ie. TRST driven, SRST driven, of fixed) * * Returns pin value (1 means driven high, 0 mean driven low) */ -bool ublast_compute_pin(enum gpio_steer steer) +static bool ublast_compute_pin(enum gpio_steer steer) { switch (steer) { case FIXED_0: @@ -293,7 +282,7 @@ bool ublast_compute_pin(enum gpio_steer steer) /** * ublast_build_out - build bitbang mode output byte - * @type: says if reading back TDO is required + * @param type says if reading back TDO is required * * Returns the compute bitbang mode byte */ @@ -313,8 +302,8 @@ static uint8_t ublast_build_out(enum scan_type type) /** * ublast_reset - reset the JTAG device is possible - * @trst: 1 if TRST is to be asserted - * @srst: 1 if SRST is to be asserted + * @param trst 1 if TRST is to be asserted + * @param srst 1 if SRST is to be asserted */ static void ublast_reset(int trst, int srst) { @@ -329,7 +318,7 @@ static void ublast_reset(int trst, int srst) /** * ublast_clock_tms - clock a TMS transition - * @tms: the TMS to be sent + * @param tms the TMS to be sent * * Triggers a TMS transition (ie. one JTAG TAP state move). */ @@ -360,12 +349,12 @@ static void ublast_idle_clock(void) /** * ublast_clock_tdi - Output a TDI with bitbang mode - * @tdi: the TDI bit to be shifted out - * @type: scan type (ie. does a readback of TDO is required) + * @param tdi the TDI bit to be shifted out + * @param type scan type (ie. does a readback of TDO is required) * * Output a TDI bit and assert clock to push it into the JTAG device : - * - writing out TCK=0, TMS=<old_state>=0, TDI=<tdi> - * - writing out TCK=1, TMS=<new_state>, TDI=<tdi> which triggers the JTAG + * - writing out TCK=0, TMS=\<old_state>=0, TDI=\<tdi> + * - writing out TCK=1, TMS=\<new_state>, TDI=\<tdi> which triggers the JTAG * device acquiring the data. * * If a TDO is to be read back, the required read is requested (bitbang mode), @@ -387,8 +376,8 @@ static void ublast_clock_tdi(int tdi, enum scan_type type) /** * ublast_clock_tdi_flip_tms - Output a TDI with bitbang mode, change JTAG state - * @tdi: the TDI bit to be shifted out - * @type: scan type (ie. does a readback of TDO is required) + * @param tdi the TDI bit to be shifted out + * @param type scan type (ie. does a readback of TDO is required) * * This function is the same as ublast_clock_tdi(), but it changes also the TMS * while output the TDI. This should be the last TDI output of a TDI @@ -416,8 +405,8 @@ static void ublast_clock_tdi_flip_tms(int tdi, enum scan_type type) /** * ublast_queue_bytes - queue bytes for the USB Blaster - * @bytes: byte array - * @nb_bytes: number of bytes + * @param bytes byte array + * @param nb_bytes number of bytes * * Queues bytes to be sent to the USB Blaster. The bytes are not * actually sent, but stored in a buffer. The write is performed once @@ -443,13 +432,13 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes) /** * ublast_tms_seq - write a TMS sequence transition to JTAG - * @bits: TMS bits to be written (bit0, bit1 .. bitN) - * @nb_bits: number of TMS bits (between 1 and 8) - * @skip: number of TMS bits to skip at the beginning of the series + * @param bits TMS bits to be written (bit0, bit1 .. bitN) + * @param nb_bits number of TMS bits (between 1 and 8) + * @param skip number of TMS bits to skip at the beginning of the series * * Write a series of TMS transitions, where each transition consists in : - * - writing out TCK=0, TMS=<new_state>, TDI=<???> - * - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition + * - writing out TCK=0, TMS=\<new_state>, TDI=\<???> + * - writing out TCK=1, TMS=\<new_state>, TDI=\<???> which triggers the transition * The function ensures that at the end of the sequence, the clock (TCK) is put * low. */ @@ -465,7 +454,7 @@ static void ublast_tms_seq(const uint8_t *bits, int nb_bits, int skip) /** * ublast_tms - write a tms command - * @cmd: tms command + * @param cmd tms command */ static void ublast_tms(struct tms_command *cmd) { @@ -475,11 +464,11 @@ static void ublast_tms(struct tms_command *cmd) /** * ublast_path_move - write a TMS sequence transition to JTAG - * @cmd: path transition + * @param cmd path transition * * Write a series of TMS transitions, where each transition consists in : - * - writing out TCK=0, TMS=<new_state>, TDI=<???> - * - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition + * - writing out TCK=0, TMS=\<new_state>, TDI=\<???> + * - writing out TCK=1, TMS=\<new_state>, TDI=\<???> which triggers the transition * The function ensures that at the end of the sequence, the clock (TCK) is put * low. */ @@ -501,8 +490,8 @@ static void ublast_path_move(struct pathmove_command *cmd) /** * ublast_state_move - move JTAG state to the target state - * @state: the target state - * @skip: number of bits to skip at the beginning of the path + * @param state the target state + * @param skip number of bits to skip at the beginning of the path * * Input the correct TMS sequence to the JTAG TAP so that we end up in the * target state. This assumes the current state (tap_get_state()) is correct. @@ -524,8 +513,8 @@ static void ublast_state_move(tap_state_t state, int skip) /** * ublast_read_byteshifted_tdos - read TDO of byteshift writes - * @buf: the buffer to store the bits - * @nb_bits: the number of bits + * @param buf the buffer to store the bits + * @param nb_bytes the number of bytes * * Reads back from USB Blaster TDO bits, triggered by a 'byteshift write', ie. eight * bits per received byte from USB interface, and store them in buffer. @@ -552,16 +541,16 @@ static int ublast_read_byteshifted_tdos(uint8_t *buf, int nb_bytes) /** * ublast_read_bitbang_tdos - read TDO of bitbang writes - * @buf: the buffer to store the bits - * @nb_bits: the number of bits + * @param buf the buffer to store the bits + * @param nb_bits the number of bits * * Reads back from USB Blaster TDO bits, triggered by a 'bitbang write', ie. one * bit per received byte from USB interface, and store them in buffer, where : * - first bit is stored in byte0, bit0 (LSB) * - second bit is stored in byte0, bit 1 * ... - * - eight bit is sotred in byte0, bit 7 - * - ninth bit is sotred in byte1, bit 0 + * - eight bit is stored in byte0, bit 7 + * - ninth bit is stored in byte1, bit 0 * - etc ... * * Returns ERROR_OK if OK, ERROR_xxx if a read error occurred @@ -592,9 +581,9 @@ static int ublast_read_bitbang_tdos(uint8_t *buf, int nb_bits) /** * ublast_queue_tdi - short description - * @bits: bits to be queued on TDI (or NULL if 0 are to be queued) - * @nb_bits: number of bits - * @scan: scan type (ie. if TDO read back is required or not) + * @param bits bits to be queued on TDI (or NULL if 0 are to be queued) + * @param nb_bits number of bits + * @param scan scan type (ie. if TDO read back is required or not) * * Outputs a series of TDI bits on TDI. * As a side effect, the last TDI bit is sent along a TMS=1, and triggers a JTAG @@ -703,7 +692,7 @@ static void ublast_stableclocks(int cycles) /** * ublast_scan - launches a DR-scan or IR-scan - * @cmd: the command to launch + * @param cmd the command to launch * * Launch a JTAG IR-scan or DR-scan * @@ -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 != NULL; + for (cmd = cmd_queue; ret == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { case JTAG_RESET: @@ -873,7 +862,6 @@ static int ublast_init(void) info.drv->ublast_pid = info.ublast_pid; info.drv->ublast_vid_uninit = info.ublast_vid_uninit; info.drv->ublast_pid_uninit = info.ublast_pid_uninit; - info.drv->ublast_device_desc = info.ublast_device_desc; info.drv->firmware_path = info.firmware_path; info.flags |= info.drv->flags; @@ -907,16 +895,6 @@ static int ublast_quit(void) return info.drv->close(info.drv); } -COMMAND_HANDLER(ublast_handle_device_desc_command) -{ - if (CMD_ARGC != 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - info.ublast_device_desc = strdup(CMD_ARGV[0]); - - return ERROR_OK; -} - COMMAND_HANDLER(ublast_handle_vid_pid_command) { if (CMD_ARGC > 4) { @@ -1029,16 +1007,9 @@ COMMAND_HANDLER(ublast_firmware_command) } -static const struct command_registration ublast_command_handlers[] = { - { - .name = "usb_blaster_device_desc", - .handler = ublast_handle_device_desc_command, - .mode = COMMAND_CONFIG, - .help = "set the USB device description of the USB-Blaster", - .usage = "description-string", - }, +static const struct command_registration ublast_subcommand_handlers[] = { { - .name = "usb_blaster_vid_pid", + .name = "vid_pid", .handler = ublast_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor ID and product ID of the USB-Blaster and " @@ -1047,21 +1018,21 @@ static const struct command_registration ublast_command_handlers[] = { .usage = "vid pid vid_uninit pid_uninit", }, { - .name = "usb_blaster_lowlevel_driver", + .name = "lowlevel_driver", .handler = ublast_handle_lowlevel_drv_command, .mode = COMMAND_CONFIG, .help = "set the lowlevel access for the USB Blaster (ftdi, ublast2)", .usage = "(ftdi|ublast2)", }, { - .name = "usb_blaster_pin", + .name = "pin", .handler = ublast_handle_pin_command, .mode = COMMAND_ANY, .help = "show or set pin state for the unused GPIO pins", .usage = "(pin6|pin8) (0|1|s|t)", }, { - .name = "usb_blaster_firmware", + .name = "firmware", .handler = &ublast_firmware_command, .mode = COMMAND_CONFIG, .help = "configure the USB-Blaster II firmware location", @@ -1070,6 +1041,17 @@ static const struct command_registration ublast_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration ublast_command_handlers[] = { + { + .name = "usb_blaster", + .mode = COMMAND_ANY, + .help = "perform usb_blaster management", + .chain = ublast_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static struct jtag_interface usb_blaster_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = ublast_execute_queue, diff --git a/src/jtag/drivers/usb_common.c b/src/jtag/drivers/usb_common.c deleted file mode 100644 index 1b7602d198..0000000000 --- a/src/jtag/drivers/usb_common.c +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************** - * 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 -#include "config.h" -#endif -#include "usb_common.h" -#include "log.h" - - -static bool jtag_usb_match(struct usb_device *dev, - const uint16_t vids[], const uint16_t pids[]) -{ - for (unsigned i = 0; vids[i] && pids[i]; i++) { - if (dev->descriptor.idVendor == vids[i] && - dev->descriptor.idProduct == pids[i]) - return true; - } - return false; -} - -int jtag_usb_open(const uint16_t vids[], const uint16_t pids[], - struct usb_dev_handle **out) -{ - usb_find_busses(); - usb_find_devices(); - - struct usb_bus *busses = usb_get_busses(); - for (struct usb_bus *bus = busses; bus; bus = bus->next) { - for (struct usb_device *dev = bus->devices; dev; dev = dev->next) { - if (!jtag_usb_match(dev, vids, pids)) - continue; - - *out = usb_open(dev); - if (NULL == *out) { - LOG_ERROR("usb_open() failed with %s", usb_strerror()); - return ERROR_FAIL; - } - return ERROR_OK; - } - } - return ERROR_FAIL; -} diff --git a/src/jtag/drivers/usb_common.h b/src/jtag/drivers/usb_common.h deleted file mode 100644 index 4d2bd2686d..0000000000 --- a/src/jtag/drivers/usb_common.h +++ /dev/null @@ -1,26 +0,0 @@ -/*************************************************************************** - * 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_JTAG_DRIVERS_USB_COMMON_H -#define OPENOCD_JTAG_DRIVERS_USB_COMMON_H - -#include <usb.h> - -int jtag_usb_open(const uint16_t vids[], const uint16_t pids[], - struct usb_dev_handle **out); - -#endif /* OPENOCD_JTAG_DRIVERS_USB_COMMON_H */ diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 627e4653dd..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/>. * ***************************************************************************/ /* @@ -34,7 +23,7 @@ #include <jtag/interface.h> #include <jtag/commands.h> -#include "usb_common.h" +#include "libusb_helper.h" #define VID 0x1781 #define PID 0x0c63 @@ -64,7 +53,7 @@ static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int #define WRITE_TMS_CHAIN 0x0A struct usbprog_jtag { - struct usb_dev_handle *usb_handle; + struct libusb_device_handle *usb_handle; }; static struct usbprog_jtag *usbprog_jtag_handle; @@ -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,25 +335,21 @@ static void usbprog_reset(int trst, int srst) /*************** jtag lowlevel functions ********************/ -struct usb_bus *busses; - struct usbprog_jtag *usbprog_jtag_open(void) { - usb_set_debug(10); - usb_init(); - const uint16_t vids[] = { VID, 0 }; const uint16_t pids[] = { PID, 0 }; - struct usb_dev_handle *dev; - if (jtag_usb_open(vids, pids, &dev) != ERROR_OK) + struct libusb_device_handle *dev; + + if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK) return NULL; struct usbprog_jtag *tmp = malloc(sizeof(struct usbprog_jtag)); tmp->usb_handle = dev; - usb_set_configuration(dev, 1); - usb_claim_interface(dev, 0); - usb_set_altinterface(dev, 0); + libusb_set_configuration(dev, 1); + libusb_claim_interface(dev, 0); + libusb_set_interface_alt_setting(dev, 0, 0); return tmp; } @@ -372,21 +357,23 @@ struct usbprog_jtag *usbprog_jtag_open(void) #if 0 static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag) { - usb_close(usbprog_jtag->usb_handle); + libusb_close(usbprog_jtag->usb_handle); free(usbprog_jtag); } #endif static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen) { - int res = usb_bulk_write(usbprog_jtag->usb_handle, 3, msg, msglen, 100); + int transferred; + + int res = jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, msg, msglen, 100, &transferred); if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || (msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9)) return 1; - if (res == msglen) { + if (res == ERROR_OK && transferred == msglen) { /* LOG_INFO("HALLLLOOO %i",(int)msg[0]); */ - res = usb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100); - if (res > 0) + res = jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100, &transferred); + if (res == ERROR_OK && transferred > 0) return (unsigned char)msg[1]; else return -1; @@ -428,11 +415,13 @@ static void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char bufindex++; } - if (usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000) == 64) { + int transferred; + int res = jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000, &transferred); + if (res == ERROR_OK && transferred == 64) { /* LOG_INFO("HALLLLOOO2 %i",(int)tmp[0]); */ usleep(1); int timeout = 0; - while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000) < 1) { + while (jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000, &transferred) != ERROR_OK) { timeout++; if (timeout > 10) break; @@ -469,12 +458,13 @@ static void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char *buffe tmp[1] = (char)(send_bits >> 8); /* high */ tmp[2] = (char)(send_bits); /* low */ - usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000); + int transferred; + jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000, &transferred); /* LOG_INFO("HALLLLOOO3 %i",(int)tmp[0]); */ int timeout = 0; usleep(1); - while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10) < 1) { + while (jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10, &transferred) != ERROR_OK) { timeout++; if (timeout > 10) break; @@ -513,7 +503,8 @@ static void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char *buff tmp[3 + i] = buffer[bufindex]; bufindex++; } - usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000); + int transferred; + jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000, &transferred); } } @@ -582,15 +573,15 @@ static void usbprog_jtag_tms_collect(char tms_scan) static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag) { - int i; /* LOG_INFO("TMS SEND"); */ if (tms_chain_index > 0) { char tmp[tms_chain_index + 2]; tmp[0] = WRITE_TMS_CHAIN; tmp[1] = (char)(tms_chain_index); - for (i = 0; i < tms_chain_index + 1; i++) + for (int i = 0; i < tms_chain_index + 1; i++) tmp[2 + i] = tms_chain[i]; - usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000); + int transferred; + jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000, &transferred); tms_chain_index = 0; } } diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c new file mode 100644 index 0000000000..f1fc4535f3 --- /dev/null +++ b/src/jtag/drivers/vdebug.c @@ -0,0 +1,1359 @@ +// 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. 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 + * +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#else +#ifdef HAVE_UNISTD_H +#include <unistd.h> /* close */ +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#endif +#include <stdio.h> +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <stdarg.h> +#include <string.h> +#include <errno.h> + +#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 48 +#define VD_BUFFER_LEN 4024 +#define VD_CHEADER_LEN 24 +#define VD_SHEADER_LEN 16 + +#define VD_MAX_MEMORIES 20 +#define VD_POLL_INTERVAL 500 +#define VD_SCALE_PSTOMS 1000000000 + +/** + * @brief List of transactor types + */ +enum { + 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 */ + VD_BFM_AXI = 0x0005, /* transactor AMBA AXI */ + VD_BFM_JTAG = 0x0006, /* transactor serial JTAG */ + VD_BFM_SWD = 0x0007, /* transactor serial SWD */ +}; + +/** + * @brief List of signals that can be read or written by the debugger + */ +enum { + VD_SIG_TCK = 0x0001, /* JTAG clock; tclk */ + VD_SIG_TDI = 0x0002, /* JTAG TDI; tdi */ + VD_SIG_TMS = 0x0004, /* JTAG TMS; tms */ + VD_SIG_RESET = 0x0008, /* DUT reset; rst */ + VD_SIG_TRST = 0x0010, /* JTAG Reset; trstn */ + VD_SIG_TDO = 0x0020, /* JTAG TDO; tdo */ + VD_SIG_POWER = 0x0100, /* BFM power; bfm_up */ + VD_SIG_TCKDIV = 0x0200, /* JTAG clock divider; tclkdiv */ + VD_SIG_BUF = 0x1000, /* memory buffer; mem */ +}; + +/** + * @brief List of errors + */ +enum { + VD_ERR_NONE = 0x0000, /* no error */ + VD_ERR_NOT_IMPL = 0x0100, /* feature not implemented */ + VD_ERR_USAGE = 0x0101, /* incorrect usage */ + VD_ERR_PARAM = 0x0102, /* incorrect parameter */ + VD_ERR_CONFIG = 0x0107, /* incorrect configuration */ + VD_ERR_NO_MEMORY = 0x0104, /* out of memory */ + VD_ERR_SHM_OPEN = 0x010a, /* cannot open shared memory */ + VD_ERR_SHM_MAP = 0x010b, /* cannot map shared memory */ + VD_ERR_SOC_OPEN = 0x011a, /* cannot open socket */ + VD_ERR_SOC_OPT = 0x011b, /* cannot set socket option */ + VD_ERR_SOC_ADDR = 0x011c, /* cannot resolve host address */ + VD_ERR_SOC_CONN = 0x011d, /* cannot connect to host */ + VD_ERR_SOC_SEND = 0x011e, /* error sending data on socket */ + VD_ERR_SOC_RECV = 0x011f, /* error receiving data from socket */ + VD_ERR_LOCKED = 0x0202, /* device locked */ + VD_ERR_NOT_RUN = 0x0204, /* transactor not running */ + VD_ERR_NOT_OPEN = 0x0205, /* transactor not open/connected */ + VD_ERR_LICENSE = 0x0206, /* cannot check out the license */ + VD_ERR_VERSION = 0x0207, /* transactor version mismatch */ + VD_ERR_TIME_OUT = 0x0301, /* time out, waiting */ + VD_ERR_NO_POWER = 0x0302, /* power out error */ + VD_ERR_BUS_ERROR = 0x0304, /* bus protocol error, like pslverr */ + VD_ERR_NO_ACCESS = 0x0306, /* no access to an object */ + VD_ERR_INV_HANDLE = 0x0307, /* invalid object handle */ + VD_ERR_INV_SCOPE = 0x0308, /* invalid scope */ +}; + +enum { + VD_CMD_OPEN = 0x01, + VD_CMD_CLOSE = 0x02, + VD_CMD_CONNECT = 0x04, + VD_CMD_DISCONNECT = 0x05, + VD_CMD_WAIT = 0x09, + 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, + VD_BATCH_WR = 2, +}; + +struct vd_shm { + struct { /* VD_CHEADER_LEN written by client */ + uint8_t cmd; /* 000; command */ + uint8_t type; /* 001; interface type */ + 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 */ + 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; */ + }; + 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 { + uint8_t trans_batch; + bool trans_first; + bool trans_last; + uint8_t mem_ndx; + uint8_t buf_width; + uint8_t addr_bits; + uint8_t bfm_type; + uint16_t sig_read; + uint16_t sig_write; + uint32_t bfm_period; + uint32_t mem_base[VD_MAX_MEMORIES]; + uint32_t mem_size[VD_MAX_MEMORIES]; + uint32_t mem_width[VD_MAX_MEMORIES]; + uint32_t mem_depth[VD_MAX_MEMORIES]; + uint16_t server_port; + uint32_t poll_cycles; + uint32_t poll_min; + uint32_t poll_max; + uint32_t targ_time; + int hsocket; + char server_name[32]; + char bfm_path[128]; + char mem_path[VD_MAX_MEMORIES][128]; + struct vd_rdata rdataq; +}; + +struct vd_jtag_hdr { + uint64_t tlen:24; + uint64_t post:3; + uint64_t pre:3; + uint64_t cmd:2; + uint64_t wlen:16; + 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; + +static int vdebug_socket_error(void) +{ +#ifdef _WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + +static int vdebug_socket_open(char *server_addr, uint32_t port) +{ + int hsock; + int rc = 0; + uint32_t buflen = sizeof(struct vd_shm); /* size of the send and rcv buffer */ + struct addrinfo *ainfo = NULL; + struct addrinfo ahint = { 0, AF_INET, SOCK_STREAM, 0, 0, NULL, NULL, NULL }; + +#ifdef _WIN32 + 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); + if (hsock < 0) + rc = errno; + else if (setsockopt(hsock, SOL_SOCKET, SO_RCVLOWAT, &rcvwat, sizeof(rcvwat)) < 0) + rc = errno; +#endif + else if (setsockopt(hsock, SOL_SOCKET, SO_SNDBUF, (const char *)&buflen, sizeof(buflen)) < 0) + rc = vdebug_socket_error(); + else if (setsockopt(hsock, SOL_SOCKET, SO_RCVBUF, (const char *)&buflen, sizeof(buflen)) < 0) + rc = vdebug_socket_error(); + + if (rc) { + LOG_ERROR("socket_open: cannot set socket option, error %d", rc); + } else if (getaddrinfo(server_addr, NULL, &ahint, &ainfo) != 0) { + LOG_ERROR("socket_open: cannot resolve address %s, error %d", server_addr, vdebug_socket_error()); + rc = VD_ERR_SOC_ADDR; + } else { + 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; + } + } + + if (rc) { + close_socket(hsock); + hsock = 0; + } + + if (ainfo) + freeaddrinfo(ainfo); + + return hsock; +} + +static int vdebug_socket_receive(int hsock, struct vd_shm *pmem) +{ + int rc; + int dreceived = 0; + int offset = &pmem->rid[0] - &pmem->cmd; + int to_receive = VD_SHEADER_LEN + le_to_h_u16(pmem->rbytes); + char *pb = (char *)pmem; + + do { + rc = recv(hsock, pb + offset, to_receive, 0); + if (rc <= 0) { + LOG_WARNING("socket_receive: recv failed, error %d", rc < 0 ? vdebug_socket_error() : 0); + return rc; + } + to_receive -= rc; + offset += rc; + LOG_DEBUG_IO("socket_receive: received %d, to receive %d", rc, to_receive); + dreceived += rc; + } while (to_receive); + + return dreceived; +} + +static int vdebug_socket_send(int hsock, struct vd_shm *pmem) +{ + 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 + LOG_DEBUG_IO("socket_send: sent %d, to send 0", rc); + + return rc; +} + +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; + + int rd = vdebug_socket_receive(hsock, pmem); + if (rd <= 0) + return VD_ERR_SOC_RECV; + + 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); + + return rc; +} + +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; + unsigned int req, waddr, rwords; + int64_t ts, te; + uint8_t *tdo; + int rc; + uint64_t jhdr; + 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 */ + 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 + num = anum - num_pre; + bytes = (num + 7) / 8; + vdc.trans_last = (req + 1) < count ? 0 : 1; + vdc.trans_first = waddr ? 0 : 1; + 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", le_to_h_u16(pm->wid) - count + req, j, tdo[j]); + } + rwords += words; /* read data offset */ + } else { + tdo = NULL; + } + 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_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; + } + + 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; +} + +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; +} + +static int vdebug_open(int hsock, struct vd_shm *pm, const char *path, + uint8_t type, uint32_t period_ps, uint32_t sig_mask) +{ + int rc = VD_ERR_NOT_OPEN; + + pm->cmd = VD_CMD_OPEN; + 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 (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 */ + 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 = 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 = 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) { + LOG_ERROR("0x%x connecting to BFM %s", rc, 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); + + return ERROR_OK; +} + +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 */ + 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; + 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); + + return ERROR_OK; +} + +static int vdebug_wait(int hsock, struct vd_shm *pm, uint32_t cycles) +{ + if (cycles) { + pm->cmd = VD_CMD_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); + return ERROR_FAIL; + } + LOG_DEBUG("%d cycles", cycles); + } + + return ERROR_OK; +} + +static int vdebug_sig_set(int hsock, struct vd_shm *pm, uint32_t write_mask, uint32_t value) +{ + pm->cmd = VD_CMD_SIGSET; + 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); + return ERROR_FAIL; + } + + LOG_DEBUG("setting signals %04" PRIx32 " to %04" PRIx32, write_mask, value); + + return ERROR_OK; +} + +static int vdebug_jtag_clock(int hsock, struct vd_shm *pm, uint32_t value) +{ + pm->cmd = VD_CMD_JTAGCLOCK; + 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); + return ERROR_FAIL; + } + + LOG_DEBUG("setting jtag clock divider to %" PRIx32, value); + + return ERROR_OK; +} + +static int vdebug_jtag_shift_tap(int hsock, struct vd_shm *pm, uint8_t num_pre, + const uint8_t tms_pre, uint32_t num, const uint8_t *tdi, + uint8_t num_post, const uint8_t tms_post, uint8_t *tdo, + uint8_t f_last) +{ + const uint32_t tobits = 8; + uint16_t bytes, hwords, anum, words, waddr; + int rc = 0; + + pm->cmd = VD_CMD_JTAGSHTAP; + 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_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 + anum = num + num_pre; + hwords = (anum + 4 * vdc.buf_width - 1) / (4 * vdc.buf_width); /* in 4B TDI/TMS words */ + 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(uint64_t) + 8 * hwords + 64 > VD_BUFFER_LEN) { + vdc.trans_last = 1; /* force flush within 64B of buffer end */ + } 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", + 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; /* 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); + pm->wd8[4 * waddr + 4] = tms_pre; /* init with tms_pre */ + if (num + num_pre <= 8) /* and tms_post for num <=4 */ + pm->wd8[4 * waddr + 4] |= (tms_post << (num + num_pre - 1)); + for (i = 1, j = 4 * waddr; i < bytes; i++) { + if (i == bytes - 1 && num + num_pre <= bytes * tobits) + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8); + else + pm->wd8[j + i + 4] = 0x0;/* placing 4 bytes of TMS bits into high word */ + if (!tdi) /* placing 4 bytes of TDI bits into low word */ + pm->wd8[j + i] = 0x0; + else + pm->wd8[j + i] = (tdi[i] << num_pre) | (tdi[i - 1] >> (8 - num_pre)); + if (i % 4 == 3) + j += 4; + } + + if (tdi) + if (num + num_pre > bytes * tobits) /* in case 1 additional byte needed for TDI */ + pm->wd8[j + i] = (tdi[i - 1] >> (8 - num_pre)); /* put last TDI bits there */ + + if (num + num_pre <= bytes * tobits) { /* in case no or 1 additional byte needed */ + pm->wd8[j + i + 4] = tms_post >> (8 - (num + num_pre - 1) % 8); /* may need to add higher part */ + /* in case exactly 1 additional byte needed */ + } else if (num + num_pre > bytes * tobits && anum <= (bytes + 1) * tobits) { + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8); /* add whole tms_post */ + } else { /* in case 2 additional bytes, tms_post split */ + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8);/* add lower part of tms_post */ + if (i % 4 == 3) /* next byte is in the next 32b word */ + pm->wd8[j + i + 4 + 5] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */ + else /* next byte is in the same 32b word */ + pm->wd8[j + i + 4 + 1] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */ + } + + if (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 */ + } + 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 */ + 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, 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; +} + +static int vdebug_mem_open(int hsock, struct vd_shm *pm, const char *path, uint8_t ndx) +{ + int rc; + + if (!path) + return ERROR_OK; + + pm->cmd = VD_CMD_MEMOPEN; + 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->rd8[2]) { + LOG_WARNING("Invalid memory index %" PRIu16 " returned. Direct memory access disabled", pm->rd8[2]); + } else { + 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]); + } + + return ERROR_OK; +} + +static void vdebug_mem_close(int hsock, struct vd_shm *pm, uint8_t ndx) +{ + pm->cmd = VD_CMD_MEMCLOSE; + 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); + pbuf = calloc(1, sizeof(struct vd_shm)); + if (!pbuf) { + close_socket(vdc.hsocket); + vdc.hsocket = 0; + LOG_ERROR("cannot allocate %zu bytes", sizeof(struct vd_shm)); + return ERROR_FAIL; + } + if (vdc.hsocket <= 0) { + free(pbuf); + pbuf = NULL; + LOG_ERROR("cannot connect to vdebug server %s:%" PRIu16, + vdc.server_name, vdc.server_port); + return ERROR_FAIL; + } + vdc.trans_first = 1; + vdc.poll_cycles = vdc.poll_max; + 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("0x%x cannot connect to %s", rc, vdc.bfm_path); + close_socket(vdc.hsocket); + vdc.hsocket = 0; + free(pbuf); + pbuf = NULL; + } else { + 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("0x%x cannot connect to %s", rc, vdc.mem_path[i]); + } + + LOG_INFO("vdebug %d connected to %s through %s:%" PRIu16, + VD_VERSION, vdc.bfm_path, vdc.server_name, vdc.server_port); + } + + return rc; +} + +static int vdebug_quit(void) +{ + for (uint8_t i = 0; i < vdc.mem_ndx; i++) + if (vdc.mem_width[i]) + vdebug_mem_close(vdc.hsocket, pbuf, i); + int rc = vdebug_close(vdc.hsocket, pbuf, vdc.bfm_type); + LOG_INFO("vdebug %d disconnected from %s through %s:%" PRIu16 " rc:%d", VD_VERSION, + vdc.bfm_path, vdc.server_name, vdc.server_port, rc); + if (vdc.hsocket) + close_socket(vdc.hsocket); + free(pbuf); + pbuf = NULL; + + return ERROR_OK; +} + +static int vdebug_reset(int trst, int srst) +{ + uint16_t sig_val = 0xffff; + uint16_t sig_mask = 0; + + sig_mask |= VD_SIG_RESET; + if (srst) + sig_val &= ~VD_SIG_RESET;/* active low */ + if (transport_is_jtag()) { + sig_mask |= VD_SIG_TRST; + if (trst) + sig_val &= ~VD_SIG_TRST; /* active low */ + } + + LOG_INFO("rst trst:%d srst:%d mask:%" PRIx16 " val:%" PRIx16, trst, srst, sig_mask, sig_val); + int rc = vdebug_sig_set(vdc.hsocket, pbuf, sig_mask, sig_val); + if (rc == 0) + rc = vdebug_wait(vdc.hsocket, pbuf, 20); /* 20 clock cycles pulse */ + + return rc; +} + +static int vdebug_jtag_tms_seq(const uint8_t *tms, int num, uint8_t f_flush) +{ + 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); +} + +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_DEBUG_IO("path num states %d", cmd->num_states); + + memset(tms, 0, DIV_ROUND_UP(cmd->num_states, 8)); + + for (uint8_t i = 0; i < cmd->num_states; i++) { + if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) + buf_set_u32(tms, i, 1, 1); + tap_set_state(cmd->path[i]); + } + + return vdebug_jtag_tms_seq(tms, cmd->num_states, f_flush); +} + +static int vdebug_jtag_tlr(tap_state_t state, uint8_t f_flush) +{ + int rc = ERROR_OK; + + 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_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); + } + + return rc; +} + +static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush) +{ + int rc = ERROR_OK; + + 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_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; + uint8_t cur_tms_pre = i == 0 ? tms_pre : 0; + uint8_t cur_num_post = i == cmd->num_fields - 1 ? num_post : 0; + 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); + if (rc) + break; + } + + if (cur != cmd->end_state) + tap_set_state(cmd->end_state); + + return rc; +} + +static int vdebug_jtag_runtest(int cycles, tap_state_t state, uint8_t f_flush) +{ + 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_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); + + return rc; +} + +static int vdebug_jtag_stableclocks(int num, uint8_t f_flush) +{ + 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); +} + +static int vdebug_sleep(int us) +{ + LOG_INFO("sleep %d us", us); + + return vdebug_wait(vdc.hsocket, pbuf, us / 1000); +} + +static int vdebug_jtag_speed(int speed) +{ + unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */ + unsigned int divval = clkmax / speed; + LOG_INFO("jclk speed:%d kHz set, BFM divider %u", speed, divval); + + return vdebug_jtag_clock(vdc.hsocket, pbuf, divval); +} + +static int vdebug_jtag_khz(int khz, int *jtag_speed) +{ + unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */ + unsigned int divval = khz ? clkmax / khz : 1; + *jtag_speed = clkmax / divval; + LOG_DEBUG("khz speed:%d from khz:%d", *jtag_speed, khz); + + return ERROR_OK; +} + +static int vdebug_jtag_div(int speed, int *khz) +{ + *khz = speed; + LOG_DEBUG("div khz:%d from speed:%d", *khz, speed); + + return ERROR_OK; +} + +static int vdebug_jtag_execute_queue(struct jtag_command *cmd_queue) +{ + int rc = ERROR_OK; + + 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); + break; + case JTAG_STABLECLOCKS: + rc = vdebug_jtag_stableclocks(cmd->cmd.stableclocks->num_cycles, !cmd->next); + break; + case JTAG_TLR_RESET: + rc = vdebug_jtag_tlr(cmd->cmd.statemove->end_state, !cmd->next); + break; + case JTAG_PATHMOVE: + rc = vdebug_jtag_path_move(cmd->cmd.pathmove, !cmd->next); + break; + case JTAG_TMS: + rc = vdebug_jtag_tms_seq(cmd->cmd.tms->bits, cmd->cmd.tms->num_bits, !cmd->next); + break; + case JTAG_SLEEP: + rc = vdebug_sleep(cmd->cmd.sleep->us); + break; + case JTAG_SCAN: + rc = vdebug_jtag_scan(cmd->cmd.scan, !cmd->next); + break; + default: + LOG_ERROR("Unknown JTAG command type 0x%x encountered", cmd->type); + rc = ERROR_FAIL; + } + } + + 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], ':')) + return ERROR_COMMAND_SYNTAX_ERROR; + + char *pchar = strchr(CMD_ARGV[0], ':'); + *pchar = '\0'; + strncpy(vdc.server_name, CMD_ARGV[0], sizeof(vdc.server_name) - 1); + int port = atoi(++pchar); + if (port < 0 || port > UINT16_MAX) { + LOG_ERROR("invalid port number %d specified", port); + return ERROR_COMMAND_SYNTAX_ERROR; + } + vdc.server_port = port; + LOG_DEBUG("server: %s port %u", vdc.server_name, vdc.server_port); + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_bfm) +{ + char prefix; + + if ((CMD_ARGC != 2) || (sscanf(CMD_ARGV[1], "%u%c", &vdc.bfm_period, &prefix) != 2)) + return ERROR_COMMAND_SYNTAX_ERROR; + + strncpy(vdc.bfm_path, CMD_ARGV[0], sizeof(vdc.bfm_path) - 1); + switch (prefix) { + case 'u': + vdc.bfm_period *= 1000000; + break; + case 'n': + vdc.bfm_period *= 1000; + break; + case 'p': + default: + break; + } + 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; +} + +COMMAND_HANDLER(vdebug_set_mem) +{ + if (CMD_ARGC != 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (vdc.mem_ndx >= VD_MAX_MEMORIES) { + LOG_ERROR("mem_path declared more than %d allowed times", VD_MAX_MEMORIES); + return ERROR_FAIL; + } + + strncpy(vdc.mem_path[vdc.mem_ndx], CMD_ARGV[0], sizeof(vdc.mem_path[vdc.mem_ndx]) - 1); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], vdc.mem_base[vdc.mem_ndx]); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], vdc.mem_size[vdc.mem_ndx]); + LOG_DEBUG("mem_path: set %s @ 0x%08x+0x%08x", vdc.mem_path[vdc.mem_ndx], + vdc.mem_base[vdc.mem_ndx], vdc.mem_size[vdc.mem_ndx]); + vdc.mem_ndx++; + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_batching) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (isdigit((unsigned char)CMD_ARGV[0][0])) + vdc.trans_batch = (CMD_ARGV[0][0] == '0' ? 0 : (CMD_ARGV[0][0] == '1' ? 1 : 2)); + else if (CMD_ARGV[0][0] == 'r') + vdc.trans_batch = VD_BATCH_WR; + else if (CMD_ARGV[0][0] == 'w') + vdc.trans_batch = VD_BATCH_WO; + else + vdc.trans_batch = VD_BATCH_NO; + LOG_DEBUG("batching: set to %u", vdc.trans_batch); + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_polling) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + vdc.poll_min = atoi(CMD_ARGV[0]); + vdc.poll_max = atoi(CMD_ARGV[1]); + LOG_DEBUG("polling: set min %u max %u", vdc.poll_min, vdc.poll_max); + + return ERROR_OK; +} + +static const struct command_registration vdebug_command_handlers[] = { + { + .name = "server", + .handler = &vdebug_set_server, + .mode = COMMAND_CONFIG, + .help = "set the vdebug server name or address", + .usage = "<host:port>", + }, + { + .name = "bfm_path", + .handler = &vdebug_set_bfm, + .mode = COMMAND_CONFIG, + .help = "set the vdebug BFM hierarchical path", + .usage = "<path> <clk_period[p|n|u]s>", + }, + { + .name = "mem_path", + .handler = &vdebug_set_mem, + .mode = COMMAND_CONFIG, + .help = "set the design memory for the code load", + .usage = "<path> <base_address> <size>", + }, + { + .name = "batching", + .handler = &vdebug_set_batching, + .mode = COMMAND_CONFIG, + .help = "set the transaction batching no|wr|rd [0|1|2]", + .usage = "<level>", + }, + { + .name = "polling", + .handler = &vdebug_set_polling, + .mode = COMMAND_CONFIG, + .help = "set the polling pause, executing hardware cycles between min and max", + .usage = "<min cycles> <max cycles>", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration vdebug_command[] = { + { + .name = "vdebug", + .chain = vdebug_command_handlers, + .mode = COMMAND_ANY, + .help = "vdebug command group", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static struct jtag_interface vdebug_jtag_ops = { + .supported = DEBUG_CAP_TMS_SEQ, + .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 = vdebug_transports, + .speed = vdebug_jtag_speed, + .khz = vdebug_jtag_khz, + .speed_div = vdebug_jtag_div, + .commands = vdebug_command, + .init = vdebug_init, + .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 f2ea175ad6..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 @@ -37,7 +26,7 @@ RESULT usbtojtagraw_fini(uint8_t interface_index) return usbtoxxx_fini_command(USB_TO_JTAG_RAW, interface_index); } -RESULT usbtojtagraw_config(uint8_t interface_index, uint32_t kHz) +RESULT usbtojtagraw_config(uint8_t interface_index, uint32_t khz) { uint8_t cfg_buf[4]; @@ -48,7 +37,7 @@ RESULT usbtojtagraw_config(uint8_t interface_index, uint32_t kHz) } #endif - SET_LE_U32(&cfg_buf[0], kHz); + SET_LE_U32(&cfg_buf[0], khz); return usbtoxxx_conf_command(USB_TO_JTAG_RAW, interface_index, cfg_buf, 4); } diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtopwr.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtopwr.c index 16433aff5c..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 @@ -49,7 +38,7 @@ RESULT usbtopwr_config(uint8_t interface_index) return usbtoxxx_conf_command(USB_TO_POWER, interface_index, NULL, 0); } -RESULT usbtopwr_output(uint8_t interface_index, uint16_t mV) +RESULT usbtopwr_output(uint8_t interface_index, uint16_t millivolt) { #if PARAM_CHECK if (interface_index > 7) { @@ -58,6 +47,6 @@ RESULT usbtopwr_output(uint8_t interface_index, uint16_t mV) } #endif - return usbtoxxx_out_command(USB_TO_POWER, interface_index, (uint8_t *)&mV, + return usbtoxxx_out_command(USB_TO_POWER, interface_index, (uint8_t *)&millivolt, 2, 0); } diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c index ef1b675f79..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 @@ -28,21 +17,21 @@ #include "usbtoxxx.h" #include "usbtoxxx_internal.h" -RESULT usbtoswd_read_callback(void *p, uint8_t *src, uint8_t *processed) +static RESULT usbtoswd_read_callback(void *p, uint8_t *src, uint8_t *processed) { struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p; - if (pending->extra_data != NULL) + if (pending->extra_data) *((uint8_t *)pending->extra_data) = src[0]; return ERROR_OK; } -RESULT usbtoswd_write_callback(void *p, uint8_t *src, uint8_t *processed) +static RESULT usbtoswd_write_callback(void *p, uint8_t *src, uint8_t *processed) { struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p; - if (pending->extra_data != NULL) + if (pending->extra_data) *((uint8_t *)pending->extra_data) = src[0]; /* mark it processed to ignore other input data */ @@ -135,7 +124,7 @@ RESULT usbtoswd_transact(uint8_t interface_index, uint8_t request, parity += (request >> 4) & 1; parity &= 1; buff[0] = (request | 0x81 | (parity << 5)) & ~0x40; - if (data != NULL) + if (data) SET_LE_U32(&buff[1], *data); else memset(buff + 1, 0, 4); diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c index 678b097c94..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 @@ -29,7 +18,7 @@ #define N_A "n/a" -const char *types_name[96] = { +static const char *types_name[96] = { "usbtousart", "usbtospi", "usbtoi2c", "usbtogpio", "usbtocan", "usbtopwm", "usbtoadc", "usbtodac", "usbtomicrowire", "usbtoswim", "usbtodusi", N_A, N_A, N_A, "usbtopower", "usbtodelay", @@ -55,8 +44,8 @@ static uint16_t usbtoxxx_buffer_index; static uint16_t usbtoxxx_current_cmd_index; static uint8_t *usbtoxxx_buffer; -uint16_t collect_index; -uint8_t collect_cmd; +static uint16_t collect_index; +static uint8_t collect_cmd; static uint8_t poll_nesting; struct usbtoxxx_context_t { @@ -86,11 +75,11 @@ static void usbtoxxx_pop_context(struct usbtoxxx_context_t *c) versaloon_pending_idx = c->versaloon_pending_idx; } -RESULT usbtoxxx_validate_current_command_type(void) +static RESULT usbtoxxx_validate_current_command_type(void) { if (type_pre > 0) { /* not the first command */ - if (NULL == usbtoxxx_buffer) { + if (!usbtoxxx_buffer) { LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(usbtoxxx_buffer)); return ERRCODE_INVALID_BUFFER; } @@ -126,12 +115,12 @@ RESULT usbtoxxx_execute_command(void) return ERROR_FAIL; } - if (ERROR_OK != usbtoxxx_validate_current_command_type()) { + if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); versaloon_free_want_pos(); return ERRCODE_FAILURE_OPERATION; } - if (3 == usbtoxxx_buffer_index) { + if (usbtoxxx_buffer_index == 3) { versaloon_free_want_pos(); return ERROR_OK; } @@ -139,7 +128,7 @@ RESULT usbtoxxx_execute_command(void) versaloon_buf[0] = USB_TO_ALL; SET_LE_U16(&versaloon_buf[1], usbtoxxx_buffer_index); - if (ERROR_OK != versaloon_send_command(usbtoxxx_buffer_index, &inlen)) { + if (versaloon_send_command(usbtoxxx_buffer_index, &inlen) != ERROR_OK) { versaloon_free_want_pos(); return ERROR_FAIL; } @@ -148,7 +137,7 @@ RESULT usbtoxxx_execute_command(void) usbtoxxx_buffer_index = 0; for (i = 0; i < versaloon_pending_idx; i++) { /* check result */ - if ((0 == i) || !((versaloon_pending[i].collect) + if ((i == 0) || !((versaloon_pending[i].collect) && (versaloon_pending[i - 1].collect) && (versaloon_pending[i].cmd == versaloon_pending[i - 1].cmd))) { @@ -159,7 +148,7 @@ RESULT usbtoxxx_execute_command(void) "current dongle"); result = ERROR_FAIL; break; - } else if (USB_TO_XXX_OK != versaloon_buf[usbtoxxx_buffer_index]) { + } else if (versaloon_buf[usbtoxxx_buffer_index] != USB_TO_XXX_OK) { LOG_ERROR("%s command 0x%02x failed with 0x%02x", usbtoxxx_get_type_name(versaloon_pending[i].type), versaloon_pending[i].cmd, @@ -171,10 +160,10 @@ RESULT usbtoxxx_execute_command(void) } /* get result data */ - if (versaloon_pending[i].pos != NULL) { + if (versaloon_pending[i].pos) { uint8_t processed = 0; - if (versaloon_pending[i].callback != NULL) { + if (versaloon_pending[i].callback) { versaloon_pending[i].callback(&versaloon_pending[i], versaloon_buf + usbtoxxx_buffer_index, &processed); } @@ -182,8 +171,8 @@ RESULT usbtoxxx_execute_command(void) struct versaloon_want_pos_t *tmp; tmp = versaloon_pending[i].pos; - while (tmp != NULL) { - if ((tmp->buff != NULL) && (tmp->size > 0)) { + while (tmp) { + if ((tmp->buff) && (tmp->size > 0)) { memcpy(tmp->buff, versaloon_buf + usbtoxxx_buffer_index + tmp->offset, @@ -197,10 +186,10 @@ RESULT usbtoxxx_execute_command(void) versaloon_pending[i].pos = NULL; } } else if ((versaloon_pending[i].want_data_size > 0) - && (versaloon_pending[i].data_buffer != NULL)) { + && (versaloon_pending[i].data_buffer)) { uint8_t processed = 0; - if (versaloon_pending[i].callback != NULL) { + if (versaloon_pending[i].callback) { versaloon_pending[i].callback(&versaloon_pending[i], versaloon_buf + usbtoxxx_buffer_index, &processed); } @@ -245,8 +234,8 @@ RESULT usbtoxxx_init(void) { versaloon_pending_idx = 0; - if ((ERROR_OK != usbtoinfo_get_abilities(usbtoxxx_abilities)) || - (ERROR_OK != usbtoxxx_execute_command())) + if ((usbtoinfo_get_abilities(usbtoxxx_abilities) != ERROR_OK) || + (usbtoxxx_execute_command() != ERROR_OK)) return ERROR_FAIL; LOG_INFO("USB_TO_XXX abilities: 0x%08X:0x%08X:0x%08X", GET_LE_U32(&usbtoxxx_abilities[0]), @@ -272,7 +261,7 @@ bool usbtoxxx_interface_supported(uint8_t cmd) return (usbtoxxx_abilities[cmd / 8] & (1 << (cmd % 8))) > 0; } -RESULT usbtoxxx_ensure_buffer_size(uint16_t cmdlen) +static RESULT usbtoxxx_ensure_buffer_size(uint16_t cmdlen) { /* check free space, commit if not enough */ if (((usbtoxxx_buffer_index + usbtoxxx_current_cmd_index + cmdlen) @@ -283,7 +272,7 @@ RESULT usbtoxxx_ensure_buffer_size(uint16_t cmdlen) memset(&context_tmp, 0, sizeof(context_tmp)); if (poll_nesting) { - if (0 == poll_context.type_pre) { + if (poll_context.type_pre == 0) { LOG_BUG("USB_TO_POLL toooooo long"); return ERROR_OK; } @@ -329,18 +318,18 @@ RESULT usbtoxxx_add_command(uint8_t type, uint8_t cmd, uint8_t *cmdbuf, /* 3 more bytes by usbtoxxx_validate_current_command_type */ /* 3 more bytes when ((0 == collect_index) || (collect_cmd != cmd)) */ - if (ERROR_OK != usbtoxxx_ensure_buffer_size(cmdlen + 6)) + if (usbtoxxx_ensure_buffer_size(cmdlen + 6) != ERROR_OK) return ERROR_FAIL; - if ((type_pre != type) || (NULL == usbtoxxx_buffer)) { - if (ERROR_OK != usbtoxxx_validate_current_command_type()) { + if ((type_pre != type) || (!usbtoxxx_buffer)) { + if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = type; } - if ((0 == collect_index) || (collect_cmd != cmd)) { + if ((collect_index == 0) || (collect_cmd != cmd)) { usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = cmd; if (collect) { @@ -357,7 +346,7 @@ RESULT usbtoxxx_add_command(uint8_t type, uint8_t cmd, uint8_t *cmdbuf, SET_LE_U16(&usbtoxxx_buffer[collect_index], len_tmp); } - if (cmdbuf != NULL) { + if (cmdbuf) { memcpy(usbtoxxx_buffer + usbtoxxx_current_cmd_index, cmdbuf, cmdlen); usbtoxxx_current_cmd_index += cmdlen; } @@ -368,10 +357,10 @@ RESULT usbtoxxx_add_command(uint8_t type, uint8_t cmd, uint8_t *cmdbuf, RESULT usbtoinfo_get_abilities(uint8_t abilities[USB_TO_XXX_ABILITIES_LEN]) { - if (ERROR_OK != usbtoxxx_ensure_buffer_size(3)) + if (usbtoxxx_ensure_buffer_size(3) != ERROR_OK) return ERROR_FAIL; - if (ERROR_OK != usbtoxxx_validate_current_command_type()) { + if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } @@ -383,12 +372,12 @@ RESULT usbtoinfo_get_abilities(uint8_t abilities[USB_TO_XXX_ABILITIES_LEN]) RESULT usbtopoll_start(uint16_t retry_cnt, uint16_t interval_us) { - if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 5)) + if (usbtoxxx_ensure_buffer_size(3 + 5) != ERROR_OK) return ERROR_FAIL; if (!poll_nesting) usbtoxxx_save_context(&poll_context); - if (ERROR_OK != usbtoxxx_validate_current_command_type()) { + if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } @@ -410,10 +399,10 @@ RESULT usbtopoll_end(void) LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } - if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 1)) + if (usbtoxxx_ensure_buffer_size(3 + 1) != ERROR_OK) return ERROR_FAIL; - if (ERROR_OK != usbtoxxx_validate_current_command_type()) { + if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } @@ -439,10 +428,10 @@ RESULT usbtopoll_checkok(uint8_t equ, uint16_t offset, uint8_t size, LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } - if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size)) + if (usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size) != ERROR_OK) return ERROR_FAIL; - if (ERROR_OK != usbtoxxx_validate_current_command_type()) { + if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } @@ -475,10 +464,10 @@ RESULT usbtopoll_checkfail(uint8_t equ, uint16_t offset, uint8_t size, LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } - if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size)) + if (usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size) != ERROR_OK) return ERROR_FAIL; - if (ERROR_OK != usbtoxxx_validate_current_command_type()) { + if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } @@ -504,10 +493,10 @@ RESULT usbtopoll_verifybuff(uint16_t offset, uint16_t size, uint8_t *buff) LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } - if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 5 + size)) + if (usbtoxxx_ensure_buffer_size(3 + 5 + size) != ERROR_OK) return ERROR_FAIL; - if (ERROR_OK != usbtoxxx_validate_current_command_type()) { + if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } @@ -527,10 +516,10 @@ RESULT usbtopoll_verifybuff(uint16_t offset, uint16_t size, uint8_t *buff) RESULT usbtodelay_delay(uint16_t dly) { - if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 2)) + if (usbtoxxx_ensure_buffer_size(3 + 2) != ERROR_OK) return ERROR_FAIL; - if (ERROR_OK != usbtoxxx_validate_current_command_type()) { + if (usbtoxxx_validate_current_command_type() != ERROR_OK) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.h b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.h index 98a056a8b8..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 @@ -47,7 +36,7 @@ RESULT usbtousart_status(uint8_t interface_index, /* USB_TO_SPI */ RESULT usbtospi_init(uint8_t interface_index); RESULT usbtospi_fini(uint8_t interface_index); -RESULT usbtospi_config(uint8_t interface_index, uint32_t kHz, uint8_t mode); +RESULT usbtospi_config(uint8_t interface_index, uint32_t khz, uint8_t mode); RESULT usbtospi_io(uint8_t interface_index, uint8_t *out, uint8_t *in, uint16_t bytelen); @@ -82,7 +71,7 @@ RESULT usbtolpcicp_poll_ready(uint8_t interface_index, uint8_t data, /* USB_TO_JTAG_LL */ RESULT usbtojtagll_init(uint8_t interface_index); RESULT usbtojtagll_fini(uint8_t interface_index); -RESULT usbtojtagll_config(uint8_t interface_index, uint32_t kHz); +RESULT usbtojtagll_config(uint8_t interface_index, uint32_t khz); RESULT usbtojtagll_tms(uint8_t interface_index, uint8_t *tms, uint8_t bytelen); RESULT usbtojtagll_tms_clocks(uint8_t interface_index, uint32_t bytelen, uint8_t tms); @@ -94,7 +83,7 @@ RESULT usbtojtagll_scan(uint8_t interface_index, uint8_t *data, /* USB_TO_JTAG_HL */ RESULT usbtojtaghl_init(uint8_t interface_index); RESULT usbtojtaghl_fini(uint8_t interface_index); -RESULT usbtojtaghl_config(uint8_t interface_index, uint32_t kHz, uint8_t ub, +RESULT usbtojtaghl_config(uint8_t interface_index, uint32_t khz, uint8_t ub, uint8_t ua, uint16_t bb, uint16_t ba); RESULT usbtojtaghl_ir(uint8_t interface_index, uint8_t *ir, uint16_t bitlen, uint8_t idle, uint8_t want_ret); @@ -108,7 +97,7 @@ RESULT usbtojtaghl_register_callback(uint8_t index, jtag_callback_t send_callbac /* USB_TO_JTAG_RAW */ RESULT usbtojtagraw_init(uint8_t interface_index); RESULT usbtojtagraw_fini(uint8_t interface_index); -RESULT usbtojtagraw_config(uint8_t interface_index, uint32_t kHz); +RESULT usbtojtagraw_config(uint8_t interface_index, uint32_t khz); RESULT usbtojtagraw_execute(uint8_t interface_index, uint8_t *tdi, uint8_t *tms, uint8_t *tdo, uint32_t bitlen); @@ -123,7 +112,7 @@ RESULT usbtoc2_readdata(uint8_t interface_index, uint8_t *buf, uint8_t len); /* USB_TO_I2C */ RESULT usbtoi2c_init(uint8_t interface_index); RESULT usbtoi2c_fini(uint8_t interface_index); -RESULT usbtoi2c_config(uint8_t interface_index, uint16_t kHz, +RESULT usbtoi2c_config(uint8_t interface_index, uint16_t khz, uint16_t byte_interval, uint16_t max_dly); RESULT usbtoi2c_read(uint8_t interface_index, uint16_t chip_addr, uint8_t *data, uint16_t data_len, uint8_t stop, @@ -165,7 +154,7 @@ RESULT usbtomsp430sbw_poll(uint8_t interface_index, uint32_t dr, uint32_t mask, RESULT usbtopwr_init(uint8_t interface_index); RESULT usbtopwr_fini(uint8_t interface_index); RESULT usbtopwr_config(uint8_t interface_index); -RESULT usbtopwr_output(uint8_t interface_index, uint16_t mV); +RESULT usbtopwr_output(uint8_t interface_index, uint16_t millivolt); /* USB_TO_POLL */ RESULT usbtopoll_start(uint16_t retry_cnt, uint16_t interval_us); @@ -190,14 +179,14 @@ RESULT usbtoswd_transact(uint8_t interface_index, uint8_t request, /* USB_TO_SWIM */ RESULT usbtoswim_init(uint8_t interface_index); RESULT usbtoswim_fini(uint8_t interface_index); -RESULT usbtoswim_config(uint8_t interface_index, uint8_t mHz, uint8_t cnt0, +RESULT usbtoswim_config(uint8_t interface_index, uint8_t mhz, uint8_t cnt0, uint8_t cnt1); RESULT usbtoswim_srst(uint8_t interface_index); RESULT usbtoswim_wotf(uint8_t interface_index, uint8_t *data, uint16_t bytelen, uint32_t addr); RESULT usbtoswim_rotf(uint8_t interface_index, uint8_t *data, uint16_t bytelen, uint32_t addr); -RESULT usbtoswim_sync(uint8_t interface_index, uint8_t mHz); +RESULT usbtoswim_sync(uint8_t interface_index, uint8_t mhz); RESULT usbtoswim_enable(uint8_t interface_index); /* USB_TO_BDM */ @@ -210,14 +199,14 @@ RESULT usbtobdm_transact(uint8_t interface_index, uint8_t *out, /* USB_TO_DUSI */ RESULT usbtodusi_init(uint8_t interface_index); RESULT usbtodusi_fini(uint8_t interface_index); -RESULT usbtodusi_config(uint8_t interface_index, uint32_t kHz, uint8_t mode); +RESULT usbtodusi_config(uint8_t interface_index, uint32_t khz, uint8_t mode); RESULT usbtodusi_io(uint8_t interface_index, uint8_t *mo, uint8_t *mi, uint8_t *so, uint8_t *si, uint32_t bitlen); /* USB_TO_MICROWIRE */ RESULT usbtomicrowire_init(uint8_t interface_index); RESULT usbtomicrowire_fini(uint8_t interface_index); -RESULT usbtomicrowire_config(uint8_t interface_index, uint16_t kHz, +RESULT usbtomicrowire_config(uint8_t interface_index, uint16_t khz, uint8_t sel_polarity); RESULT usbtomicrowire_transport(uint8_t interface_index, uint32_t opcode, uint8_t opcode_bitlen, @@ -230,7 +219,7 @@ RESULT usbtomicrowire_poll(uint8_t interface_index, uint16_t interval_us, /* USB_TO_PWM */ RESULT usbtopwm_init(uint8_t interface_index); RESULT usbtopwm_fini(uint8_t interface_index); -RESULT usbtopwm_config(uint8_t interface_index, uint16_t kHz, uint8_t mode); +RESULT usbtopwm_config(uint8_t interface_index, uint16_t khz, uint8_t mode); RESULT usbtopwm_out(uint8_t interface_index, uint16_t count, uint16_t *rate); RESULT usbtopwm_in(uint8_t interface_index, uint16_t count, uint16_t *rate); 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 8efe44353f..48d317436b 100644 --- a/src/jtag/drivers/versaloon/versaloon.c +++ b/src/jtag/drivers/versaloon/versaloon.c @@ -1,29 +1,19 @@ +// 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 #include "config.h" #endif +#include "versaloon_include.h" + #include <stdio.h> #include <string.h> #include <libusb.h> -#include "versaloon_include.h" #include "versaloon.h" #include "versaloon_internal.h" #include "usbtoxxx/usbtoxxx.h" @@ -35,15 +25,15 @@ uint16_t versaloon_buf_size; struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER]; uint16_t versaloon_pending_idx; -libusb_device_handle *versaloon_usb_device_handle; +struct libusb_device_handle *versaloon_usb_device_handle; static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT; -RESULT versaloon_init(void); -RESULT versaloon_fini(void); -RESULT versaloon_get_target_voltage(uint16_t *voltage); -RESULT versaloon_set_target_voltage(uint16_t voltage); -RESULT versaloon_delay_ms(uint16_t ms); -RESULT versaloon_delay_us(uint16_t us); +static RESULT versaloon_init(void); +static RESULT versaloon_fini(void); +static RESULT versaloon_get_target_voltage(uint16_t *voltage); +static RESULT versaloon_set_target_voltage(uint16_t voltage); +static RESULT versaloon_delay_ms(uint16_t ms); +static RESULT versaloon_delay_us(uint16_t us); struct versaloon_interface_t versaloon_interface = { .init = versaloon_init, @@ -86,7 +76,6 @@ struct versaloon_interface_t versaloon_interface = { .ep_out = VERSALOON_OUTP, .ep_in = VERSALOON_INP, .interface = VERSALOON_IFACE, - .serialstring = NULL, .buf_size = 256, } }; @@ -116,16 +105,16 @@ void versaloon_free_want_pos(void) struct versaloon_want_pos_t *tmp, *free_tmp; tmp = versaloon_want_pos; - while (tmp != NULL) { + while (tmp) { free_tmp = tmp; tmp = tmp->next; free(free_tmp); } versaloon_want_pos = NULL; - for (i = 0; i < dimof(versaloon_pending); i++) { + for (i = 0; i < ARRAY_SIZE(versaloon_pending); i++) { tmp = versaloon_pending[i].pos; - while (tmp != NULL) { + while (tmp) { free_tmp = tmp; tmp = tmp->next; free(free_tmp); @@ -139,7 +128,7 @@ RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff) struct versaloon_want_pos_t *new_pos = NULL; new_pos = malloc(sizeof(*new_pos)); - if (NULL == new_pos) { + if (!new_pos) { LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } @@ -148,12 +137,12 @@ RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff) new_pos->buff = buff; new_pos->next = NULL; - if (NULL == versaloon_want_pos) + if (!versaloon_want_pos) versaloon_want_pos = new_pos; else { struct versaloon_want_pos_t *tmp = versaloon_want_pos; - while (tmp->next != NULL) + while (tmp->next) tmp = tmp->next; tmp->next = new_pos; } @@ -198,11 +187,11 @@ RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen) int transferred; #if PARAM_CHECK - if (NULL == versaloon_buf) { + if (!versaloon_buf) { LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf)); return ERRCODE_INVALID_BUFFER; } - if ((0 == out_len) || (out_len > versaloon_interface.usb_setting.buf_size)) { + if ((out_len == 0) || (out_len > versaloon_interface.usb_setting.buf_size)) { LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__); return ERRCODE_INVALID_PARAMETER; } @@ -211,17 +200,17 @@ RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen) ret = libusb_bulk_transfer(versaloon_usb_device_handle, versaloon_interface.usb_setting.ep_out, versaloon_buf, out_len, &transferred, versaloon_usb_to); - if (0 != ret || transferred != out_len) { + if (ret != 0 || transferred != out_len) { LOG_ERROR(ERRMSG_FAILURE_OPERATION, "send usb data"); return ERRCODE_FAILURE_OPERATION; } - if (inlen != NULL) { + if (inlen) { ret = libusb_bulk_transfer(versaloon_usb_device_handle, versaloon_interface.usb_setting.ep_in, versaloon_buf, versaloon_interface.usb_setting.buf_size, &transferred, versaloon_usb_to); - if (0 == ret) { + if (ret == 0) { *inlen = (uint16_t)transferred; return ERROR_OK; } else { @@ -233,7 +222,7 @@ RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen) } #define VERSALOON_RETRY_CNT 10 -RESULT versaloon_init(void) +static RESULT versaloon_init(void) { uint16_t ret = 0; uint8_t retry; @@ -241,7 +230,7 @@ RESULT versaloon_init(void) /* malloc temporary buffer */ versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size); - if (NULL == versaloon_buf) { + if (!versaloon_buf) { LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } @@ -253,11 +242,11 @@ RESULT versaloon_init(void) versaloon_usb_to = 100; for (retry = 0; retry < VERSALOON_RETRY_CNT; retry++) { versaloon_buf[0] = VERSALOON_GET_INFO; - if ((ERROR_OK == versaloon_send_command(1, &ret)) && (ret >= 3)) + if ((versaloon_send_command(1, &ret) == ERROR_OK) && (ret >= 3)) break; } versaloon_usb_to = timeout_tmp; - if (VERSALOON_RETRY_CNT == retry) { + if (retry == VERSALOON_RETRY_CNT) { versaloon_fini(); LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon"); return ERRCODE_FAILURE_OPERATION; @@ -273,27 +262,27 @@ RESULT versaloon_init(void) versaloon_buf = NULL; versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size); - if (NULL == versaloon_buf) { + if (!versaloon_buf) { versaloon_fini(); LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } versaloon_cmd_buf = malloc(versaloon_interface.usb_setting.buf_size - 3); - if (NULL == versaloon_cmd_buf) { + if (!versaloon_cmd_buf) { versaloon_fini(); LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } - if (ERROR_OK != usbtoxxx_init()) { + if (usbtoxxx_init() != ERROR_OK) { LOG_ERROR(ERRMSG_FAILURE_OPERATION, "initialize usbtoxxx"); return ERROR_FAIL; } return versaloon_get_target_voltage(&ret); } -RESULT versaloon_fini(void) +static RESULT versaloon_fini(void) { - if (versaloon_usb_device_handle != NULL) { + if (versaloon_usb_device_handle) { usbtoxxx_fini(); versaloon_free_want_pos(); @@ -309,7 +298,7 @@ RESULT versaloon_fini(void) return ERROR_OK; } -RESULT versaloon_set_target_voltage(uint16_t voltage) +static RESULT versaloon_set_target_voltage(uint16_t voltage) { usbtopwr_init(0); usbtopwr_config(0); @@ -319,16 +308,16 @@ RESULT versaloon_set_target_voltage(uint16_t voltage) return usbtoxxx_execute_command(); } -RESULT versaloon_get_target_voltage(uint16_t *voltage) +static RESULT versaloon_get_target_voltage(uint16_t *voltage) { uint16_t inlen; #if PARAM_CHECK - if (NULL == versaloon_buf) { + if (!versaloon_buf) { LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf)); return ERRCODE_INVALID_BUFFER; } - if (NULL == voltage) { + if (!voltage) { LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__); return ERRCODE_INVALID_PARAMETER; } @@ -336,7 +325,7 @@ RESULT versaloon_get_target_voltage(uint16_t *voltage) versaloon_buf[0] = VERSALOON_GET_TVCC; - if ((ERROR_OK != versaloon_send_command(1, &inlen)) || (inlen != 2)) { + if ((versaloon_send_command(1, &inlen) != ERROR_OK) || (inlen != 2)) { LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon"); return ERRCODE_FAILURE_OPERATION; } else { @@ -345,12 +334,12 @@ RESULT versaloon_get_target_voltage(uint16_t *voltage) } } -RESULT versaloon_delay_ms(uint16_t ms) +static RESULT versaloon_delay_ms(uint16_t ms) { return usbtodelay_delay(ms | 0x8000); } -RESULT versaloon_delay_us(uint16_t us) +static RESULT versaloon_delay_us(uint16_t us) { return usbtodelay_delay(us & 0x7FFF); } diff --git a/src/jtag/drivers/versaloon/versaloon.h b/src/jtag/drivers/versaloon/versaloon.h index 9d92bcaa19..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 @@ -69,7 +58,7 @@ struct interface_swd_t { struct interface_jtag_raw_t { RESULT(*init)(uint8_t interface_index); RESULT(*fini)(uint8_t interface_index); - RESULT(*config)(uint8_t interface_index, uint32_t kHz); + RESULT(*config)(uint8_t interface_index, uint32_t khz); RESULT(*execute)(uint8_t interface_index, uint8_t *tdi, uint8_t *tms, uint8_t *tdo, uint32_t bitlen); }; @@ -94,8 +83,6 @@ struct versaloon_usb_setting_t { uint8_t ep_out; uint8_t ep_in; uint8_t interface; - char *serialstring; - uint16_t buf_size; }; @@ -107,6 +94,6 @@ struct versaloon_interface_t { }; extern struct versaloon_interface_t versaloon_interface; -extern libusb_device_handle *versaloon_usb_device_handle; +extern struct libusb_device_handle *versaloon_usb_device_handle; #endif /* 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 901402520f..5804ad5210 100644 --- a/src/jtag/drivers/versaloon/versaloon_include.h +++ b/src/jtag/drivers/versaloon/versaloon_include.h @@ -1,23 +1,13 @@ +/* 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 #define OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INCLUDE_H +#include "helper/system.h" /* This file is used to include different header and macros */ /* according to different platform */ #include <jtag/interface.h> @@ -26,7 +16,6 @@ #define PARAM_CHECK 1 #define sleep_ms(ms) jtag_sleep((ms) * 1000) -#define dimof(arr) (sizeof(arr) / sizeof((arr)[0])) #define TO_STR(name) #name #define RESULT int 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 9aaed36b77..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. @@ -24,6 +13,7 @@ #include "config.h" #endif +#include <jtag/adapter.h> #include <jtag/interface.h> #include <jtag/commands.h> #include <jtag/swd.h> @@ -94,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; @@ -105,7 +95,7 @@ static int vsllink_execute_queue(void) " vsllink " "-------------------------------------"); - while (cmd != NULL) { + while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %s", @@ -272,6 +262,7 @@ static int vsllink_quit(void) vsllink_free_buffer(); vsllink_usb_close(vsllink_handle); + libusb_exit(vsllink_handle->libusb_ctx); free(vsllink_handle); return ERROR_OK; @@ -280,14 +271,14 @@ static int vsllink_quit(void) static int vsllink_interface_init(void) { vsllink_handle = malloc(sizeof(struct vsllink)); - if (NULL == vsllink_handle) { + if (!vsllink_handle) { LOG_ERROR("unable to allocate memory"); return ERROR_FAIL; } libusb_init(&vsllink_handle->libusb_ctx); - if (ERROR_OK != vsllink_usb_open(vsllink_handle)) { + if (vsllink_usb_open(vsllink_handle) != ERROR_OK) { LOG_ERROR("Can't find USB JTAG Interface!" "Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; @@ -297,7 +288,7 @@ static int vsllink_interface_init(void) versaloon_interface.usb_setting.pid); versaloon_usb_device_handle = vsllink_handle->usb_device_handle; - if (ERROR_OK != versaloon_interface.init()) + if (versaloon_interface.init() != ERROR_OK) return ERROR_FAIL; if (versaloon_interface.usb_setting.buf_size < 32) { versaloon_interface.fini(); @@ -310,7 +301,7 @@ static int vsllink_interface_init(void) static int vsllink_init(void) { int retval = vsllink_interface_init(); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; versaloon_interface.adaptors.gpio.init(0); @@ -323,7 +314,7 @@ static int vsllink_init(void) versaloon_interface.adaptors.gpio.config(0, GPIO_TRST, 0, GPIO_TRST, GPIO_TRST); versaloon_interface.adaptors.swd.init(0); - vsllink_swd_frequency(jtag_get_speed_khz() * 1000); + vsllink_swd_frequency(adapter_get_speed_khz() * 1000); vsllink_swd_switch_seq(JTAG_TO_SWD); } else { @@ -333,18 +324,18 @@ static int vsllink_init(void) tdi_buffer = malloc(tap_buffer_size); tdo_buffer = malloc(tap_buffer_size); tms_buffer = malloc(tap_buffer_size); - if ((NULL == tdi_buffer) || (NULL == tdo_buffer) || (NULL == tms_buffer)) { + if ((!tdi_buffer) || (!tdo_buffer) || (!tms_buffer)) { vsllink_quit(); return ERROR_FAIL; } versaloon_interface.adaptors.jtag_raw.init(0); - versaloon_interface.adaptors.jtag_raw.config(0, jtag_get_speed_khz()); + versaloon_interface.adaptors.jtag_raw.config(0, adapter_get_speed_khz()); versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST, GPIO_TRST, GPIO_SRST, GPIO_SRST); } - if (ERROR_OK != versaloon_interface.adaptors.peripheral_commit()) + if (versaloon_interface.adaptors.peripheral_commit() != ERROR_OK) return ERROR_FAIL; vsllink_reset(0, 0); @@ -498,21 +489,6 @@ COMMAND_HANDLER(vsllink_handle_usb_pid_command) return ERROR_OK; } -COMMAND_HANDLER(vsllink_handle_usb_serial_command) -{ - if (CMD_ARGC > 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - free(versaloon_interface.usb_setting.serialstring); - - if (CMD_ARGC == 1) - versaloon_interface.usb_setting.serialstring = strdup(CMD_ARGV[0]); - else - versaloon_interface.usb_setting.serialstring = NULL; - - return ERROR_OK; -} - COMMAND_HANDLER(vsllink_handle_usb_bulkin_command) { if (CMD_ARGC != 1) @@ -785,14 +761,14 @@ static int vsllink_check_usb_strings( char desc_string[256]; int retval; - if (NULL != versaloon_interface.usb_setting.serialstring) { + if (adapter_get_required_serial()) { retval = libusb_get_string_descriptor_ascii(usb_device_handle, usb_desc->iSerialNumber, (unsigned char *)desc_string, sizeof(desc_string)); if (retval < 0) return ERROR_FAIL; - if (strncmp(desc_string, versaloon_interface.usb_setting.serialstring, + if (strncmp(desc_string, adapter_get_required_serial(), sizeof(desc_string))) return ERROR_FAIL; } @@ -803,7 +779,7 @@ static int vsllink_check_usb_strings( if (retval < 0) return ERROR_FAIL; - if (strstr(desc_string, "Versaloon") == NULL) + if (!strstr(desc_string, "Versaloon")) return ERROR_FAIL; return ERROR_OK; @@ -812,7 +788,7 @@ static int vsllink_check_usb_strings( static int vsllink_usb_open(struct vsllink *vsllink) { ssize_t num_devices, i; - libusb_device **usb_devices; + struct libusb_device **usb_devices; struct libusb_device_descriptor usb_desc; struct libusb_device_handle *usb_device_handle; int retval; @@ -823,7 +799,7 @@ static int vsllink_usb_open(struct vsllink *vsllink) return ERROR_FAIL; for (i = 0; i < num_devices; i++) { - libusb_device *device = usb_devices[i]; + struct libusb_device *device = usb_devices[i]; retval = libusb_get_device_descriptor(device, &usb_desc); if (retval != 0) @@ -838,7 +814,7 @@ static int vsllink_usb_open(struct vsllink *vsllink) continue; retval = vsllink_check_usb_strings(usb_device_handle, &usb_desc); - if (ERROR_OK == retval) + if (retval == ERROR_OK) break; libusb_close(usb_device_handle); @@ -887,44 +863,37 @@ static void vsllink_debug_buffer(uint8_t *buffer, int length) } } -static const struct command_registration vsllink_command_handlers[] = { +static const struct command_registration vsllink_subcommand_handlers[] = { { - .name = "vsllink_usb_vid", + .name = "usb_vid", .handler = &vsllink_handle_usb_vid_command, .mode = COMMAND_CONFIG, .help = "Set USB VID", .usage = "<vid>", }, { - .name = "vsllink_usb_pid", + .name = "usb_pid", .handler = &vsllink_handle_usb_pid_command, .mode = COMMAND_CONFIG, .help = "Set USB PID", .usage = "<pid>", }, { - .name = "vsllink_usb_serial", - .handler = &vsllink_handle_usb_serial_command, - .mode = COMMAND_CONFIG, - .help = "Set or disable check for USB serial", - .usage = "[<serial>]", - }, - { - .name = "vsllink_usb_bulkin", + .name = "usb_bulkin", .handler = &vsllink_handle_usb_bulkin_command, .mode = COMMAND_CONFIG, .help = "Set USB input endpoint", .usage = "<ep_in>", }, { - .name = "vsllink_usb_bulkout", + .name = "usb_bulkout", .handler = &vsllink_handle_usb_bulkout_command, .mode = COMMAND_CONFIG, .help = "Set USB output endpoint", .usage = "<ep_out>", }, { - .name = "vsllink_usb_interface", + .name = "usb_interface", .handler = &vsllink_handle_usb_interface_command, .mode = COMMAND_CONFIG, .help = "Set USB output interface", @@ -933,6 +902,17 @@ static const struct command_registration vsllink_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration vsllink_command_handlers[] = { + { + .name = "vsllink", + .mode = COMMAND_ANY, + .help = "perform vsllink management", + .chain = vsllink_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static const char * const vsllink_transports[] = {"jtag", "swd", NULL}; static const struct swd_driver vsllink_swd_driver = { diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index fb04d51a45..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 @@ -20,15 +9,13 @@ #endif #include <transport/transport.h> +#include <jtag/adapter.h> #include <jtag/swd.h> #include <jtag/interface.h> #include <jtag/commands.h> #include <jtag/tcl.h> #include <libusb.h> -/* XDS110 USB serial number length */ -#define XDS110_SERIAL_LEN 8 - /* XDS110 stand-alone probe voltage supply limits */ #define XDS110_MIN_VOLTAGE 1800 #define XDS110_MAX_VOLTAGE 3600 @@ -186,7 +173,7 @@ #define CMD_STABLECLOCKS 4 /* Array to convert from OpenOCD tap_state_t to XDS JTAG state */ -const uint32_t xds_jtag_state[] = { +static const uint32_t xds_jtag_state[] = { XDS_JTAG_STATE_EXIT2_DR, /* TAP_DREXIT2 = 0x0 */ XDS_JTAG_STATE_EXIT1_DR, /* TAP_DREXIT1 = 0x1 */ XDS_JTAG_STATE_SHIFT_DR, /* TAP_DRSHIFT = 0x2 */ @@ -213,8 +200,8 @@ struct scan_result { struct xds110_info { /* USB connection handles and data buffers */ - libusb_context *ctx; - libusb_device_handle *dev; + struct libusb_context *ctx; + struct libusb_device_handle *dev; unsigned char read_payload[USB_PAYLOAD_SIZE]; unsigned char write_packet[3]; unsigned char write_payload[USB_PAYLOAD_SIZE]; @@ -238,8 +225,6 @@ struct xds110_info { /* TCK speed and delay count*/ uint32_t speed; uint32_t delay_count; - /* XDS110 serial number */ - char serial[XDS110_SERIAL_LEN + 1]; /* XDS110 voltage supply setting */ uint32_t voltage; /* XDS110 firmware and hardware version */ @@ -269,7 +254,6 @@ static struct xds110_info xds110 = { .is_ap_dirty = false, .speed = XDS110_DEFAULT_TCK_SPEED, .delay_count = 0, - .serial = {0}, .voltage = 0, .firmware = 0, .hardware = 0, @@ -317,9 +301,9 @@ static inline uint16_t xds110_get_u16(uint8_t *buffer) static bool usb_connect(void) { - libusb_context *ctx = NULL; - libusb_device **list = NULL; - libusb_device_handle *dev = NULL; + struct libusb_context *ctx = NULL; + struct libusb_device **list = NULL; + struct libusb_device_handle *dev = NULL; struct libusb_device_descriptor desc; @@ -341,7 +325,7 @@ static bool usb_connect(void) /* Initialize libusb context */ result = libusb_init(&ctx); - if (0 == result) { + if (result == 0) { /* Get list of USB devices attached to system */ count = libusb_get_device_list(ctx, &list); if (count <= 0) { @@ -350,13 +334,13 @@ static bool usb_connect(void) } } - if (0 == result) { + if (result == 0) { /* Scan through list of devices for any XDS110s */ for (i = 0; i < count; i++) { /* Check for device vid/pid match */ libusb_get_device_descriptor(list[i], &desc); match = false; - for (device = 0; device < sizeof(vids)/sizeof(vids[0]); device++) { + for (device = 0; device < ARRAY_SIZE(vids); device++) { if (desc.idVendor == vids[device] && desc.idProduct == pids[device]) { match = true; @@ -365,13 +349,13 @@ static bool usb_connect(void) } if (match) { result = libusb_open(list[i], &dev); - if (0 == result) { + if (result == 0) { const int max_data = 256; unsigned char data[max_data + 1]; *data = '\0'; /* May be the requested device if serial number matches */ - if (0 == xds110.serial[0]) { + if (!adapter_get_required_serial()) { /* No serial number given; match first XDS110 found */ found = true; break; @@ -379,8 +363,8 @@ static bool usb_connect(void) /* Get the device's serial number string */ result = libusb_get_string_descriptor_ascii(dev, desc.iSerialNumber, data, max_data); - if (0 < result && - 0 == strcmp((char *)data, (char *)xds110.serial)) { + if (result > 0 && + strcmp((char *)data, adapter_get_required_serial()) == 0) { found = true; break; } @@ -400,7 +384,7 @@ static bool usb_connect(void) * 2) didn't find the XDS110, and no devices are currently open */ - if (NULL != list) { + if (list) { /* Free the device list, we're done with it */ libusb_free_device_list(list, 1); } @@ -430,36 +414,36 @@ static bool usb_connect(void) } /* On an error, clean up what we can */ - if (0 != result) { - if (NULL != dev) { + if (result != 0) { + if (dev) { /* Release the debug and data interface on the XDS110 */ (void)libusb_release_interface(dev, xds110.interface); libusb_close(dev); } - if (NULL != ctx) + if (ctx) libusb_exit(ctx); xds110.ctx = NULL; xds110.dev = NULL; } /* Log the results */ - if (0 == result) + if (result == 0) LOG_INFO("XDS110: connected"); else LOG_ERROR("XDS110: failed to connect"); - return (0 == result) ? true : false; + return (result == 0) ? true : false; } static void usb_disconnect(void) { - if (NULL != xds110.dev) { + if (xds110.dev) { /* Release the debug and data interface on the XDS110 */ (void)libusb_release_interface(xds110.dev, xds110.interface); libusb_close(xds110.dev); xds110.dev = NULL; } - if (NULL != xds110.ctx) { + if (xds110.ctx) { libusb_exit(xds110.ctx); xds110.ctx = NULL; } @@ -472,17 +456,17 @@ static bool usb_read(unsigned char *buffer, int size, int *bytes_read, { int result; - if (NULL == xds110.dev || NULL == buffer || NULL == bytes_read) + if (!xds110.dev || !buffer || !bytes_read) return false; /* Force a non-zero timeout to prevent blocking */ - if (0 == timeout) + if (timeout == 0) timeout = DEFAULT_TIMEOUT; result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_in, buffer, size, bytes_read, timeout); - return (0 == result) ? true : false; + return (result == 0) ? true : false; } static bool usb_write(unsigned char *buffer, int size, int *written) @@ -491,13 +475,13 @@ static bool usb_write(unsigned char *buffer, int size, int *written) int result = LIBUSB_SUCCESS; int retries = 0; - if (NULL == xds110.dev || NULL == buffer) + if (!xds110.dev || !buffer) return false; result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_out, buffer, size, &bytes_written, 0); - while (LIBUSB_ERROR_PIPE == result && retries < 3) { + while (result == LIBUSB_ERROR_PIPE && retries < 3) { /* Try clearing the pipe stall and retry transfer */ libusb_clear_halt(xds110.dev, xds110.endpoint_out); result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_out, buffer, @@ -505,10 +489,10 @@ static bool usb_write(unsigned char *buffer, int size, int *written) retries++; } - if (NULL != written) + if (written) *written = bytes_written; - return (0 == result && size == bytes_written) ? true : false; + return (result == 0 && size == bytes_written) ? true : false; } static bool usb_get_response(uint32_t *total_bytes_read, uint32_t timeout) @@ -550,7 +534,7 @@ static bool usb_get_response(uint32_t *total_bytes_read, uint32_t timeout) /* Abort now if we didn't receive a valid response */ if (!success) { - if (NULL != total_bytes_read) + if (total_bytes_read) *total_bytes_read = 0; return false; } @@ -587,7 +571,7 @@ static bool usb_get_response(uint32_t *total_bytes_read, uint32_t timeout) if (!success) count = 0; - if (NULL != total_bytes_read) + if (total_bytes_read) *total_bytes_read = count; return success; @@ -595,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; @@ -612,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); } /*************************************************************************** @@ -636,7 +611,7 @@ static bool xds_execute(uint32_t out_length, uint32_t in_length, int error = 0; uint32_t bytes_read = 0; - if (NULL == xds110.dev) + if (!xds110.dev) return false; while (!done && attempts > 0) { @@ -661,7 +636,7 @@ static bool xds_execute(uint32_t out_length, uint32_t in_length, /* Extract error code from return packet */ error = (int)xds110_get_u32(&xds110.read_payload[0]); done = true; - if (SC_ERR_NONE != error) + if (error != SC_ERR_NONE) LOG_DEBUG("XDS110: command 0x%02x returned error %d", xds110.write_payload[0], error); } @@ -671,7 +646,7 @@ static bool xds_execute(uint32_t out_length, uint32_t in_length, if (!success) error = SC_ERR_XDS110_FAIL; - if (0 != error) + if (error != 0) success = false; return success; @@ -714,9 +689,9 @@ static bool xds_version(uint32_t *firmware_id, uint16_t *hardware_id) DEFAULT_TIMEOUT); if (success) { - if (NULL != firmware_id) + if (firmware_id) *firmware_id = xds110_get_u32(fw_id_pntr); - if (NULL != hardware_id) + if (hardware_id) *hardware_id = xds110_get_u16(hw_id_pntr); } @@ -863,7 +838,7 @@ static bool cmapi_connect(uint32_t *idcode) DEFAULT_TIMEOUT); if (success) { - if (NULL != idcode) + if (idcode) *idcode = xds110_get_u32(idcode_pntr); } @@ -926,7 +901,7 @@ static bool cmapi_read_dap_reg(uint32_t type, uint32_t ap_num, DEFAULT_TIMEOUT); if (success) { - if (NULL != value) + if (value) *value = xds110_get_u32(value_pntr); } @@ -943,7 +918,7 @@ static bool cmapi_write_dap_reg(uint32_t type, uint32_t ap_num, bool success; - if (NULL == value) + if (!value) return false; xds110.write_payload[0] = CMAPI_REG_WRITE; @@ -1021,7 +996,7 @@ static bool xds_set_supply(uint32_t voltage) xds110.write_payload[0] = XDS_SET_SUPPLY; xds110_set_u32(volts_pntr, voltage); - *source_pntr = (uint8_t)(0 != voltage ? 1 : 0); + *source_pntr = (uint8_t)(voltage != 0 ? 1 : 0); success = xds_execute(XDS_OUT_LEN + 5, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); @@ -1037,7 +1012,7 @@ static bool ocd_dap_request(uint8_t *dap_requests, uint32_t request_size, bool success; - if (NULL == dap_requests || NULL == dap_results) + if (!dap_requests || !dap_results) return false; xds110.write_payload[0] = OCD_DAP_REQUEST; @@ -1062,7 +1037,7 @@ static bool ocd_scan_request(uint8_t *scan_requests, uint32_t request_size, bool success; - if (NULL == scan_requests || NULL == scan_results) + if (!scan_requests || !scan_results) return false; xds110.write_payload[0] = OCD_SCAN_REQUEST; @@ -1086,7 +1061,7 @@ static bool ocd_pathmove(uint32_t num_states, uint8_t *path) bool success; - if (NULL == path) + if (!path) return false; xds110.write_payload[0] = OCD_PATHMOVE; @@ -1165,9 +1140,9 @@ static int xds110_swd_switch_seq(enum swd_special_seq seq) static bool xds110_legacy_read_reg(uint8_t cmd, uint32_t *value) { /* Make sure this is a read request */ - bool is_read_request = (0 != (SWD_CMD_RnW & cmd)); + bool is_read_request = (0 != (SWD_CMD_RNW & cmd)); /* Determine whether this is a DP or AP register access */ - uint32_t type = (0 != (SWD_CMD_APnDP & cmd)) ? DAP_AP : DAP_DP; + uint32_t type = (0 != (SWD_CMD_APNDP & cmd)) ? DAP_AP : DAP_DP; /* Determine the AP number from cached SELECT value */ uint32_t ap_num = (xds110.select & 0xff000000) >> 24; /* Extract register address from command */ @@ -1183,7 +1158,7 @@ static bool xds110_legacy_read_reg(uint8_t cmd, uint32_t *value) if (!is_read_request) return false; - if (DAP_AP == type) { + if (type == DAP_AP) { /* Add bank address to register address for CMAPI call */ address |= bank; } @@ -1209,7 +1184,7 @@ static bool xds110_legacy_read_reg(uint8_t cmd, uint32_t *value) /* Handle result of read attempt */ if (!success) LOG_ERROR("XDS110: failed to read DAP register"); - else if (NULL != value) + else if (value) *value = reg_value; if (success && DAP_AP == type) { @@ -1227,9 +1202,9 @@ static bool xds110_legacy_read_reg(uint8_t cmd, uint32_t *value) static bool xds110_legacy_write_reg(uint8_t cmd, uint32_t value) { /* Make sure this isn't a read request */ - bool is_read_request = (0 != (SWD_CMD_RnW & cmd)); + bool is_read_request = (0 != (SWD_CMD_RNW & cmd)); /* Determine whether this is a DP or AP register access */ - uint32_t type = (0 != (SWD_CMD_APnDP & cmd)) ? DAP_AP : DAP_DP; + uint32_t type = (0 != (SWD_CMD_APNDP & cmd)) ? DAP_AP : DAP_DP; /* Determine the AP number from cached SELECT value */ uint32_t ap_num = (xds110.select & 0xff000000) >> 24; /* Extract register address from command */ @@ -1245,12 +1220,12 @@ static bool xds110_legacy_write_reg(uint8_t cmd, uint32_t value) /* Invalidate the RDBUFF cache */ xds110.use_rdbuff = false; - if (DAP_AP == type) { + if (type == DAP_AP) { /* Add bank address to register address for CMAPI call */ address |= bank; /* Any write to an AP register invalidates the firmware's cache */ xds110.is_ap_dirty = true; - } else if (DAP_DP_SELECT == address) { + } else if (address == DAP_DP_SELECT) { /* Any write to the SELECT register invalidates the firmware's cache */ xds110.is_ap_dirty = true; } @@ -1264,7 +1239,7 @@ static bool xds110_legacy_write_reg(uint8_t cmd, uint32_t value) * If the debugger wrote to SELECT, cache the value * to use to build the apNum and address values above */ - if ((DAP_DP == type) && (DAP_DP_SELECT == address)) + if ((type == DAP_DP) && (address == DAP_DP_SELECT)) xds110.select = value; } @@ -1280,7 +1255,7 @@ static int xds110_swd_run_queue(void) uint32_t value; bool success = true; - if (0 == xds110.txn_request_size) + if (xds110.txn_request_size == 0) return ERROR_OK; /* Terminate request queue */ @@ -1296,7 +1271,7 @@ static int xds110_swd_run_queue(void) result = 0; while (xds110.txn_requests[request] != 0) { cmd = xds110.txn_requests[request++]; - if (0 == (SWD_CMD_RnW & cmd)) { + if (0 == (SWD_CMD_RNW & cmd)) { /* DAP register write command */ value = (uint32_t)(xds110.txn_requests[request++]) << 0; value |= (uint32_t)(xds110.txn_requests[request++]) << 8; @@ -1316,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 (0 != xds110.txn_dap_results[result]) + if (xds110.txn_dap_results[result]) *xds110.txn_dap_results[result] = dap_results[result]; xds110.txn_request_size = 0; @@ -1329,9 +1304,9 @@ static int xds110_swd_run_queue(void) static void xds110_swd_queue_cmd(uint8_t cmd, uint32_t *value) { /* Check if this is a read or write request */ - bool is_read_request = (0 != (SWD_CMD_RnW & cmd)); + bool is_read_request = (0 != (SWD_CMD_RNW & cmd)); /* Determine whether this is a DP or AP register access */ - uint32_t type = (0 != (SWD_CMD_APnDP & cmd)) ? DAP_AP : DAP_DP; + uint32_t type = (0 != (SWD_CMD_APNDP & cmd)) ? DAP_AP : DAP_DP; /* Extract register address from command */ uint32_t address = ((cmd & SWD_CMD_A32) >> 1); uint32_t request_size = (is_read_request) ? 1 : 5; @@ -1370,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); } @@ -1395,8 +1372,8 @@ static void xds110_show_info(void) (((firmware >> 12) & 0xf) * 10) + ((firmware >> 8) & 0xf), (((firmware >> 4) & 0xf) * 10) + ((firmware >> 0) & 0xf)); LOG_INFO("XDS110: hardware version = 0x%04x", xds110.hardware); - if (0 != xds110.serial[0]) - LOG_INFO("XDS110: serial number = %s", xds110.serial); + if (adapter_get_required_serial()) + LOG_INFO("XDS110: serial number = %s", adapter_get_required_serial()); if (xds110.is_swd_mode) { LOG_INFO("XDS110: connected to target via SWD"); LOG_INFO("XDS110: SWCLK set to %" PRIu32 " kHz", xds110.speed); @@ -1470,12 +1447,12 @@ static int xds110_init(void) if (success) { /* Set supply voltage for stand-alone probes */ - if (XDS110_STAND_ALONE_ID == xds110.hardware) { + if (xds110.hardware == XDS110_STAND_ALONE_ID) { success = xds_set_supply(xds110.voltage); /* Allow time for target device to power up */ /* (CC32xx takes up to 1300 ms before debug is enabled) */ alive_sleep(1500); - } else if (0 != xds110.voltage) { + } else if (xds110.voltage != 0) { /* Voltage supply not a feature of embedded probes */ LOG_WARNING( "XDS110: ignoring supply voltage, not supported on this probe"); @@ -1557,7 +1534,7 @@ static void xds110_flush(void) uint8_t data_in[MAX_DATA_BLOCK]; uint8_t *data_pntr; - if (0 == xds110.txn_request_size) + if (xds110.txn_request_size == 0) return; /* Terminate request queue */ @@ -1625,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; @@ -1701,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; } @@ -1780,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); @@ -1863,11 +1840,11 @@ 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 != NULL) { + while (cmd) { xds110_execute_command(cmd); cmd = cmd->next; } @@ -2024,34 +2001,6 @@ COMMAND_HANDLER(xds110_handle_info_command) return ERROR_OK; } -COMMAND_HANDLER(xds110_handle_serial_command) -{ - wchar_t serial[XDS110_SERIAL_LEN + 1]; - - xds110.serial[0] = 0; - - if (CMD_ARGC == 1) { - size_t len = mbstowcs(0, CMD_ARGV[0], 0); - if (len > XDS110_SERIAL_LEN) { - LOG_ERROR("XDS110: serial number is limited to %d characters", - XDS110_SERIAL_LEN); - return ERROR_FAIL; - } - if ((size_t)-1 == mbstowcs(serial, CMD_ARGV[0], len + 1)) { - LOG_ERROR("XDS110: unable to convert serial number"); - return ERROR_FAIL; - } - - for (uint32_t i = 0; i < len; i++) - xds110.serial[i] = (char)serial[i]; - - xds110.serial[len] = 0; - } else - return ERROR_COMMAND_SYNTAX_ERROR; - - return ERROR_OK; -} - COMMAND_HANDLER(xds110_handle_supply_voltage_command) { uint32_t voltage = 0; @@ -2082,13 +2031,6 @@ static const struct command_registration xds110_subcommand_handlers[] = { .help = "show XDS110 info", .usage = "", }, - { - .name = "serial", - .handler = &xds110_handle_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the XDS110 probe serial number", - .usage = "serial_string", - }, { .name = "supply", .handler = &xds110_handle_supply_voltage_command, diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-pcie-xvc.c index 2423a9f05b..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> */ @@ -31,7 +32,7 @@ #define XLNX_XVC_VSEC_HDR 0x04 #define XLNX_XVC_LEN_REG 0x0C #define XLNX_XVC_TMS_REG 0x10 -#define XLNX_XVC_TDx_REG 0x14 +#define XLNX_XVC_TDX_REG 0x14 #define XLNX_XVC_CAP_SIZE 0x20 #define XLNX_XVC_VSEC_ID 0x8 @@ -103,11 +104,11 @@ static int xlnx_pcie_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, if (err != ERROR_OK) return err; - err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TDx_REG, tdi); + err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TDX_REG, tdi); if (err != ERROR_OK) return err; - err = xlnx_pcie_xvc_read_reg(XLNX_XVC_TDx_REG, tdo); + err = xlnx_pcie_xvc_read_reg(XLNX_XVC_TDX_REG, tdo); if (err != ERROR_OK) return err; @@ -120,7 +121,7 @@ static int xlnx_pcie_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, return ERROR_OK; } -int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) +static int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) { int tms = tap_get_state() == TAP_RESET ? 1 : 0; size_t left = cmd->cmd.stableclocks->num_cycles; @@ -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) { @@ -460,9 +461,9 @@ COMMAND_HANDLER(xlnx_pcie_xvc_handle_config_command) return ERROR_OK; } -static const struct command_registration xlnx_pcie_xvc_command_handlers[] = { +static const struct command_registration xlnx_pcie_xvc_subcommand_handlers[] = { { - .name = "xlnx_pcie_xvc_config", + .name = "config", .handler = xlnx_pcie_xvc_handle_config_command, .mode = COMMAND_CONFIG, .help = "Configure XVC/PCIe JTAG adapter", @@ -471,6 +472,17 @@ static const struct command_registration xlnx_pcie_xvc_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration xlnx_pcie_xvc_command_handlers[] = { + { + .name = "xlnx_pcie_xvc", + .mode = COMMAND_ANY, + .help = "perform xlnx_pcie_xvc management", + .chain = xlnx_pcie_xvc_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static struct jtag_interface xlnx_pcie_xvc_jtag_ops = { .execute_queue = &xlnx_pcie_xvc_execute_queue, }; @@ -535,7 +547,7 @@ static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t res, ack, rpar; int err; - assert(cmd & SWD_CMD_RnW); + assert(cmd & SWD_CMD_RNW); cmd |= SWD_CMD_START | SWD_CMD_PARK; /* cmd + ack */ @@ -558,8 +570,8 @@ static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, LOG_DEBUG("%s %s %s 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_RnW ? "read" : "write", + cmd & SWD_CMD_APNDP ? "AP" : "DP", + cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, res); switch (ack) { @@ -571,7 +583,7 @@ static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, } if (value) *value = res; - if (cmd & SWD_CMD_APnDP) + if (cmd & SWD_CMD_APNDP) err = xlnx_pcie_xvc_transact(ap_delay_clk, 0, 0, NULL); queued_retval = err; return; @@ -598,7 +610,7 @@ static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t res, ack; int err; - assert(!(cmd & SWD_CMD_RnW)); + assert(!(cmd & SWD_CMD_RNW)); cmd |= SWD_CMD_START | SWD_CMD_PARK; /* cmd + trn + ack */ @@ -621,14 +633,14 @@ static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, LOG_DEBUG("%s %s %s 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_RnW ? "read" : "write", + cmd & SWD_CMD_APNDP ? "AP" : "DP", + cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, value); switch (ack) { case SWD_ACK_OK: - if (cmd & SWD_CMD_APnDP) + if (cmd & SWD_CMD_APNDP) err = xlnx_pcie_xvc_transact(ap_delay_clk, 0, 0, NULL); queued_retval = err; return; 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 490eb9f4dc..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,14 +17,26 @@ #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> #include <target/target.h> -static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 }; +static struct hl_interface_s hl_if = { + .param = { + .device_desc = NULL, + .vid = { 0 }, + .pid = { 0 }, + .transport = HL_TRANSPORT_UNKNOWN, + .connect_under_reset = false, + .initial_interface_speed = -1, + .use_stlink_tcp = false, + .stlink_tcp_port = 7184, + }, + .layout = NULL, + .handle = NULL, +}; int hl_interface_open(enum hl_transports tr) { @@ -99,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; } @@ -122,7 +123,6 @@ static int hl_interface_quit(void) jtag_command_queue_reset(); free((void *)hl_if.param.device_desc); - free((void *)hl_if.param.serial); return ERROR_OK; } @@ -147,7 +147,7 @@ int hl_interface_init_reset(void) static int hl_interface_khz(int khz, int *jtag_speed) { - if (hl_if.layout->api->speed == NULL) + if (!hl_if.layout->api->speed) return ERROR_OK; *jtag_speed = hl_if.layout->api->speed(hl_if.handle, khz, true); @@ -162,10 +162,10 @@ static int hl_interface_speed_div(int speed, int *khz) static int hl_interface_speed(int speed) { - if (hl_if.layout->api->speed == NULL) + if (!hl_if.layout->api->speed) return ERROR_OK; - if (hl_if.handle == NULL) { + if (!hl_if.handle) { /* pass speed as initial param as interface not open yet */ hl_if.param.initial_interface_speed = speed; return ERROR_OK; @@ -188,7 +188,7 @@ int hl_interface_override_target(const char **targetname) return ERROR_FAIL; } -int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, +static int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler) { @@ -203,7 +203,7 @@ int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, return ERROR_OK; } -int hl_interface_poll_trace(uint8_t *buf, size_t *size) +static int hl_interface_poll_trace(uint8_t *buf, size_t *size) { if (hl_if.layout->api->poll_trace) return hl_if.layout->api->poll_trace(hl_if.handle, buf, size); @@ -224,19 +224,6 @@ COMMAND_HANDLER(hl_interface_handle_device_desc_command) return ERROR_OK; } -COMMAND_HANDLER(hl_interface_handle_serial_command) -{ - LOG_DEBUG("hl_interface_handle_serial_command"); - - if (CMD_ARGC == 1) { - hl_if.param.serial = strdup(CMD_ARGV[0]); - } else { - LOG_ERROR("expected exactly one argument to hl_serial <serial-number>"); - } - - return ERROR_OK; -} - COMMAND_HANDLER(hl_interface_handle_layout_command) { LOG_DEBUG("hl_interface_handle_layout_command"); @@ -292,6 +279,31 @@ COMMAND_HANDLER(hl_interface_handle_vid_pid_command) return ERROR_OK; } +COMMAND_HANDLER(hl_interface_handle_stlink_backend_command) +{ + /* default values */ + bool use_stlink_tcp = false; + uint16_t stlink_tcp_port = 7184; + + if (CMD_ARGC == 0 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; + else if (strcmp(CMD_ARGV[0], "usb") == 0) { + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + /* else use_stlink_tcp = false (already the case ) */ + } else if (strcmp(CMD_ARGV[0], "tcp") == 0) { + use_stlink_tcp = true; + if (CMD_ARGC == 2) + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], stlink_tcp_port); + } else + return ERROR_COMMAND_SYNTAX_ERROR; + + hl_if.param.use_stlink_tcp = use_stlink_tcp; + hl_if.param.stlink_tcp_port = stlink_tcp_port; + + return ERROR_OK; +} + COMMAND_HANDLER(interface_handle_hla_command) { if (CMD_ARGC != 1) @@ -315,13 +327,6 @@ static const struct command_registration hl_interface_command_handlers[] = { .help = "set the device description of the adapter", .usage = "description_string", }, - { - .name = "hla_serial", - .handler = &hl_interface_handle_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the serial number of the adapter", - .usage = "serial_string", - }, { .name = "hla_layout", .handler = &hl_interface_handle_layout_command, @@ -334,8 +339,15 @@ static const struct command_registration hl_interface_command_handlers[] = { .handler = &hl_interface_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor and product ID of the adapter", - .usage = "(vid pid)* ", + .usage = "(vid pid)*", }, + { + .name = "hla_stlink_backend", + .handler = &hl_interface_handle_stlink_backend_command, + .mode = COMMAND_CONFIG, + .help = "select which ST-Link backend to use", + .usage = "usb | tcp [port]", + }, { .name = "hla_command", .handler = &interface_handle_hla_command, diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index b6e4a8b92b..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 @@ -29,13 +18,11 @@ enum e_hl_transports; /** */ extern const char *hl_transports[]; -#define HLA_MAX_USB_IDS 8 +#define HLA_MAX_USB_IDS 16 struct hl_interface_param_s { /** */ const char *device_desc; - /** */ - const char *serial; /** List of recognised VIDs */ uint16_t vid[HLA_MAX_USB_IDS + 1]; /** List of recognised PIDs */ @@ -46,6 +33,10 @@ struct hl_interface_param_s { bool connect_under_reset; /** Initial interface clock clock speed */ int initial_interface_speed; + /** */ + bool use_stlink_tcp; + /** */ + uint16_t stlink_tcp_port; }; struct hl_interface_s { diff --git a/src/jtag/hla/hla_layout.c b/src/jtag/hla/hla_layout.c index cf51a67133..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> @@ -94,7 +82,7 @@ int hl_layout_init(struct hl_interface_s *adapter) { LOG_DEBUG("hl_layout_init"); - if (adapter->layout == NULL) { + if (!adapter->layout) { LOG_ERROR("no layout specified"); return ERROR_FAIL; } diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h index e0bbd0fed6..e13da6531c 100644 --- a/src/jtag/hla/hla_layout.h +++ b/src/jtag/hla/hla_layout.h @@ -1,28 +1,18 @@ +/* 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 #define OPENOCD_JTAG_HLA_HLA_LAYOUT_H #include <target/armv7m_trace.h> +#include <target/arm_tpiu_swo.h> /** */ struct hl_interface_s; @@ -51,10 +41,25 @@ struct hl_layout_api_s { int (*step)(void *handle); /** */ int (*read_regs)(void *handle); - /** */ - int (*read_reg)(void *handle, int num, uint32_t *val); - /** */ - int (*write_reg)(void *handle, int num, uint32_t val); + /** + * Read one register from the target + * + * @param handle A pointer to the device-specific handle + * @param regsel Register selection index compatible with all the + * values allowed by armv7m DCRSR.REGSEL + * @param val A pointer to retrieve the register value + * @returns ERROR_OK on success, or an error code on failure. + */ + int (*read_reg)(void *handle, unsigned int regsel, uint32_t *val); + /** + * Write one register to the target + * @param handle A pointer to the device-specific handle + * @param regsel Register selection index compatible with all the + * values allowed by armv7m DCRSR.REGSEL + * @param val The value to be written in the register + * @returns ERROR_OK on success, or an error code on failure. + */ + int (*write_reg)(void *handle, unsigned int regsel, uint32_t val); /** */ int (*read_mem)(void *handle, uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer); diff --git a/src/jtag/hla/hla_tcl.c b/src/jtag/hla/hla_tcl.c deleted file mode 100644 index 73f78fc8a5..0000000000 --- a/src/jtag/hla/hla_tcl.c +++ /dev/null @@ -1,152 +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(Jim_Nvp *n, Jim_GetOptInfo *goi, - struct jtag_tap *pTap) -{ - 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(pTap->expected_ids, - (pTap->expected_ids_cnt + 1) * sizeof(uint32_t)); - if (!p) { - Jim_SetResultFormatted(goi->interp, "no memory"); - return JIM_ERR; - } - - pTap->expected_ids = p; - pTap->expected_ids[pTap->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 - -static int jim_hl_newtap_cmd(Jim_GetOptInfo *goi) -{ - struct jtag_tap *pTap; - int x; - int e; - Jim_Nvp *n; - char *cp; - const 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 = NULL, .value = -1}, - }; - - pTap = calloc(1, sizeof(struct jtag_tap)); - if (!pTap) { - 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(pTap); - return JIM_ERR; - } - - const char *tmp; - Jim_GetOpt_String(goi, &tmp, NULL); - pTap->chip = strdup(tmp); - - Jim_GetOpt_String(goi, &tmp, NULL); - pTap->tapname = strdup(tmp); - - /* name + dot + name + null */ - x = strlen(pTap->chip) + 1 + strlen(pTap->tapname) + 1; - cp = malloc(x); - sprintf(cp, "%s.%s", pTap->chip, pTap->tapname); - pTap->dotted_name = cp; - - LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params", - pTap->chip, pTap->tapname, pTap->dotted_name, goi->argc); - - while (goi->argc) { - e = Jim_GetOpt_Nvp(goi, opts, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(goi, opts, 0); - free(cp); - free(pTap); - return e; - } - LOG_DEBUG("Processing option: %s", n->name); - switch (n->value) { - case NTAP_OPT_EXPECTED_ID: - e = jim_newtap_expected_id(n, goi, pTap); - if (JIM_OK != e) { - free(cp); - free(pTap); - 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 */ - pTap->enabled = !pTap->disabled_after_reset; - - jtag_tap_init(pTap); - return JIM_OK; -} - -int jim_hl_newtap(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - Jim_GetOptInfo 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 10028260d9..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> @@ -45,13 +33,20 @@ COMMAND_HANDLER(hl_transport_reset_command) return hl_interface_init_reset(); } -static const struct command_registration -hl_swd_transport_subcommand_handlers[] = { +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 }; @@ -67,16 +62,21 @@ static const struct command_registration hl_swd_transport_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const struct command_registration -hl_transport_jtag_subcommand_handlers[] = { +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", @@ -99,12 +99,18 @@ 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", @@ -121,7 +127,8 @@ hl_transport_jtag_subcommand_handlers[] = { { .name = "cget", .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_configure, + .handler = handle_jtag_configure, + .usage = "", }, { .name = "names", @@ -196,15 +203,13 @@ static int hl_jtag_transport_select(struct command_context *cmd_ctx) * That works with only C code ... no Tcl glue required. */ - return register_commands(cmd_ctx, NULL, - hl_jtag_transport_command_handlers); + return register_commands(cmd_ctx, NULL, hl_jtag_transport_command_handlers); } static int hl_swd_transport_select(struct command_context *cmd_ctx) { LOG_DEBUG("hl_swd_transport_select"); - return register_commands(cmd_ctx, NULL, - hl_swd_transport_command_handlers); + return register_commands(cmd_ctx, NULL, hl_swd_transport_command_handlers); } static struct transport hl_swd_transport = { 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 0884868a80..28c1458cb0 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 @@ -27,7 +16,7 @@ #include <jtag/jtag.h> #include <jtag/swim.h> -#include <target/armv7m_trace.h> +#include <target/arm_tpiu_swo.h> /* @file * The "Cable Helper API" is what the cable drivers can use to help @@ -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,44 @@ 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_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 45e30c9b04..c24ead8cd9 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 * @@ -12,18 +14,7 @@ * 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/>. * + * Copyright (C) 2020, Ampere Computing LLC * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -33,135 +24,18 @@ #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_ZY1000 == 1 -extern struct adapter_driver zy1000_adapter_driver; -#elif defined(BUILD_MINIDRIVER_DUMMY) -extern struct adapter_driver minidummy_adapter_driver; -#else /* standard drivers */ -#if BUILD_PARPORT == 1 -extern struct adapter_driver parport_adapter_driver; -#endif -#if BUILD_DUMMY == 1 -extern struct adapter_driver dummy_adapter_driver; -#endif -#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_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 == 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 -#endif /* standard drivers */ - /** * The list of built-in JTAG interfaces, containing entries for those * drivers that were enabled by the @c configure script. - * - * The list should be defined to contain either one minidriver interface - * or some number of standard driver interfaces, never both. */ struct adapter_driver *adapter_drivers[] = { -#if BUILD_ZY1000 == 1 - &zy1000_adapter_driver, -#elif defined(BUILD_MINIDRIVER_DUMMY) - &minidummy_adapter_driver, -#else /* standard drivers */ #if BUILD_PARPORT == 1 &parport_adapter_driver, #endif @@ -174,9 +48,18 @@ 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 +#if BUILD_VDEBUG == 1 + &vdebug_adapter_driver, +#endif +#if BUILD_JTAG_DPI == 1 + &jtag_dpi_adapter_driver, +#endif #if BUILD_FT232R == 1 &ft232r_adapter_driver, #endif @@ -213,6 +96,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 @@ -240,13 +126,10 @@ 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 -#if BUILD_CMSIS_DAP == 1 +#if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1 &cmsis_dap_adapter_driver, #endif #if BUILD_KITPROG == 1 @@ -264,6 +147,11 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_RSHIM == 1 &rshim_dap_adapter_driver, #endif -#endif /* standard drivers */ +#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 2fa580223a..470ae18334 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -1,29 +1,20 @@ +/* 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> #ifndef DEBUG_JTAG_IOZ #define DEBUG_JTAG_IOZ 64 @@ -46,15 +37,6 @@ typedef enum tap_state { TAP_INVALID = -1, -#if BUILD_ZY1000 - /* These are the old numbers. Leave as-is for now... */ - TAP_RESET = 0, TAP_IDLE = 8, - TAP_DRSELECT = 1, TAP_DRCAPTURE = 2, TAP_DRSHIFT = 3, TAP_DREXIT1 = 4, - TAP_DRPAUSE = 5, TAP_DREXIT2 = 6, TAP_DRUPDATE = 7, - TAP_IRSELECT = 9, TAP_IRCAPTURE = 10, TAP_IRSHIFT = 11, TAP_IREXIT1 = 12, - TAP_IRPAUSE = 13, TAP_IREXIT2 = 14, TAP_IRUPDATE = 15, - -#else /* Proper ARM recommended numbers */ TAP_DREXIT2 = 0x0, TAP_DREXIT1 = 0x1, @@ -72,8 +54,6 @@ typedef enum tap_state { TAP_IRUPDATE = 0xd, TAP_IRCAPTURE = 0xe, TAP_RESET = 0x0f, - -#endif } tap_state_t; /** @@ -135,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; @@ -145,10 +125,16 @@ struct jtag_tap { /** Flag saying whether to ignore version field in expected_ids[] */ bool ignore_version; + /** Flag saying whether to ignore the bypass bit in the code */ + bool ignore_bypass; + /** 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; @@ -227,31 +213,6 @@ int jtag_unregister_event_callback(jtag_event_handler_t f, void *x); int jtag_call_event_callbacks(enum jtag_event event); - -/** @returns The current JTAG speed setting. */ -int jtag_get_speed(int *speed); - -/** - * Given a @a speed setting, use the interface @c speed_div callback to - * adjust the setting. - * @param speed The speed setting to convert back to readable KHz. - * @returns ERROR_OK if the interface has not been initialized or on success; - * otherwise, the error code produced by the @c speed_div callback. - */ -int jtag_get_speed_readable(int *speed); - -/** Attempt to configure the interface for the specified KHz. */ -int jtag_config_khz(unsigned khz); - -/** - * Attempt to enable RTCK/RCLK. If that fails, fallback to the - * specified frequency. - */ -int jtag_config_rclk(unsigned fallback_speed_khz); - -/** Retrieves the clock speed of the JTAG interface in KHz. */ -unsigned jtag_get_speed_khz(void); - enum reset_types { RESET_NONE = 0x0, RESET_HAS_TRST = 0x1, @@ -295,12 +256,6 @@ void jtag_set_verify_capture_ir(bool enable); /** @returns True if IR scan verification will be performed. */ bool jtag_will_verify_capture_ir(void); -/** Initialize debug adapter upon startup. */ -int adapter_init(struct command_context *cmd_ctx); - -/** Shutdown the debug adapter upon program exit. */ -int adapter_quit(void); - /** Set ms to sleep after jtag_execute_queue() flushes queue. Debug purposes. */ void jtag_set_flush_queue_sleep(int ms); @@ -584,7 +539,8 @@ int jtag_srst_asserted(int *srst_asserted); * @param field Pointer to scan field. * @param value Pointer to scan value. * @param mask Pointer to scan mask; may be NULL. - * @returns Nothing, but calls jtag_set_error() on any error. + * + * returns Nothing, but calls jtag_set_error() on any error. */ void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask); @@ -635,11 +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); -/* The minidriver may have inline versions of some of the low - * level APIs that are used in inner loops. */ #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 ad830cc135..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 @@ -32,7 +21,7 @@ * interface functions, instead of the built-in asynchronous driver * module that is used by the standard JTAG interface drivers. * - * In addtion to the functions defined in the @c minidriver.h file, the + * In addition to the functions defined in the @c minidriver.h file, the * @c jtag_minidriver.h file must declare the following functions (or * define static inline versions of them): * - jtag_add_callback @@ -45,7 +34,7 @@ /* this header will be provided by the minidriver implementation, */ /* and it may provide additional declarations that must be defined. */ -#include <jtag/minidriver_imp.h> +#include <jtag/drivers/minidriver_imp.h> int interface_jtag_add_ir_scan(struct jtag_tap *active, const struct scan_field *fields, diff --git a/src/jtag/minidriver/minidriver_imp.h b/src/jtag/minidriver/minidriver_imp.h deleted file mode 100644 index 11d0fae722..0000000000 --- a/src/jtag/minidriver/minidriver_imp.h +++ /dev/null @@ -1,30 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * - * Copyright (C) 2007,2008 Ø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_MINIDRIVER_MINIDRIVER_IMP_H -#define OPENOCD_JTAG_MINIDRIVER_MINIDRIVER_IMP_H - -#include <jtag/jtag_minidriver.h> - -#define jtag_add_callback(callback, in) interface_jtag_add_callback(callback, in) - -#define jtag_add_callback4(callback, in, data1, data2, data3) \ - interface_jtag_add_callback4(callback, in, data1, data2, data3) - -#endif /* OPENOCD_JTAG_MINIDRIVER_MINIDRIVER_IMP_H */ diff --git a/src/jtag/minidummy/jtag_minidriver.h b/src/jtag/minidummy/jtag_minidriver.h deleted file mode 100644 index 1708356a53..0000000000 --- a/src/jtag/minidummy/jtag_minidriver.h +++ /dev/null @@ -1,21 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2008 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/>. * - ***************************************************************************/ - -#define interface_jtag_add_callback(callback, in) callback(in) - -#define interface_jtag_add_callback4(callback, in, data1, data2, data3) \ - jtag_set_error(callback(in, data1, data2, data3)) diff --git a/src/jtag/minidummy/minidummy.c b/src/jtag/minidummy/minidummy.c deleted file mode 100644 index 7ee206732b..0000000000 --- a/src/jtag/minidummy/minidummy.c +++ /dev/null @@ -1,176 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2008 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/>. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <jtag/jtag.h> -#include <target/embeddedice.h> -#include <jtag/minidriver.h> -#include <jtag/interface.h> - -static struct jtag_interface minidummy_interface = { - .execute_queue = NULL, -}; - -struct adapter_driver minidummy_adapter_driver = { - .name = "minidummy", - .transports = jtag_only, - .commands = NULL, - - .init = NULL, - .quit = NULL, - .speed = NULL, - .khz = NULL, - .speed_div = NULL, - .power_dropout = NULL, - .srst_asserted = NULL, - - .jtag_ops = &minidummy_interface, -}; - -int interface_jtag_execute_queue(void) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_ir_scan(struct jtag_tap *active, const struct scan_field *fields, - tap_state_t state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, - uint8_t *in_bits, tap_state_t state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_dr_scan(struct jtag_tap *active, int num_fields, - const struct scan_field *fields, tap_state_t state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, - uint8_t *in_bits, tap_state_t state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_tlr(void) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_reset(int req_trst, int req_srst) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_runtest(int num_cycles, tap_state_t state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_clocks(int num_cycles) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_jtag_add_sleep(uint32_t us) -{ - jtag_sleep(us); - return ERROR_OK; -} - -int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) -{ - int state_count; - int tms = 0; - - state_count = 0; - - tap_state_t cur_state = cmd_queue_cur_state; - - while (num_states) { - if (tap_state_transition(cur_state, false) == path[state_count]) - tms = 0; - else if (tap_state_transition(cur_state, true) == path[state_count]) - tms = 1; - else { - LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", - tap_state_name(cur_state), tap_state_name(path[state_count])); - exit(-1); - } - - /* synchronously do the operation here */ - - cur_state = path[state_count]; - state_count++; - num_states--; - } - - - /* synchronously do the operation here */ - - return ERROR_OK; -} - -int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state) -{ - /* synchronously do the operation here */ - - return ERROR_OK; -} - -void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *buffer, - int little, int count) -{ - int i; - for (i = 0; i < count; i++) { - embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little)); - buffer += 4; - } -} - -int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode, - uint32_t *data, size_t count) -{ - int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, - uint32_t opcode, uint32_t *data, size_t count); - return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count); -} diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index 82327a39b6..41db38e4ac 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 @@ -29,7 +31,7 @@ proc init_reset { mode } { ######### # TODO: power_restore and power_dropout are currently neither -# documented nor supported except on ZY1000. +# documented nor supported. proc power_restore {} { echo "Sensed power restore, running reset init and halting GDB." @@ -55,7 +57,7 @@ proc power_dropout {} { ######### # TODO: srst_deasserted and srst_asserted are currently neither -# documented nor supported except on ZY1000. +# documented nor supported. proc srst_deasserted {} { echo "Sensed nSRST deasserted, running reset init and halting GDB." @@ -81,9 +83,10 @@ proc srst_asserted {} { # measure actual JTAG clock proc measure_clk {} { set start_time [ms]; - set iterations 10000000; + set iterations 10000000; runtest $iterations; - echo "Running at more than [expr $iterations.0 / ([ms]-$start_time)] kHz"; + set speed [expr "$iterations.0 / ([ms] - $start_time)"] + echo "Running at more than $speed kHz"; } add_help_text measure_clk "Runs a test to measure the JTAG clk. Useful with RCLK / RTCK." @@ -117,23 +120,69 @@ proc jtag_ntrst_assert_width args { # JTAG-specific names despite the fact that the operations were not # specific to JTAG, or otherwise had troublesome/misleading names. # -# FIXME phase these aids out after about April 2011 +# FIXME phase these aids out after some releases # -proc jtag_khz args { - echo "DEPRECATED! use 'adapter speed' not 'jtag_khz'" - eval adapter speed $args +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 } -proc jtag_nsrst_delay args { - echo "DEPRECATED! use 'adapter srst delay' not 'jtag_nsrst_delay'" - eval adapter srst delay $args +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 } -proc jtag_nsrst_assert_width args { - echo "DEPRECATED! use 'adapter srst pulse_width' not 'jtag_nsrst_assert_width'" - eval adapter srst pulse_width $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'" switch $args { @@ -150,77 +199,61 @@ proc jtag_reset args { } } -# stlink migration helpers -proc stlink_device_desc args { - echo "DEPRECATED! use 'hla_device_desc' not 'stlink_device_desc'" - eval hla_device_desc $args -} - -proc stlink_serial args { - echo "DEPRECATED! use 'hla_serial' not 'stlink_serial'" - eval hla_serial $args -} - -proc stlink_layout args { - echo "DEPRECATED! use 'hla_layout' not 'stlink_layout'" - eval hla_layout $args -} - -proc stlink_vid_pid args { - echo "DEPRECATED! use 'hla_vid_pid' not 'stlink_vid_pid'" - eval hla_vid_pid $args -} - -proc stlink args { - echo "DEPRECATED! use 'hla' not 'stlink'" - eval hla $args -} - +lappend _telnet_autocomplete_skip adapter_khz proc adapter_khz args { echo "DEPRECATED! use 'adapter speed' not 'adapter_khz'" eval adapter speed $args } +lappend _telnet_autocomplete_skip adapter_name proc adapter_name args { echo "DEPRECATED! use 'adapter name' not 'adapter_name'" eval adapter name $args } +lappend _telnet_autocomplete_skip adapter_nsrst_delay proc adapter_nsrst_delay args { echo "DEPRECATED! use 'adapter srst delay' not 'adapter_nsrst_delay'" eval adapter srst delay $args } +lappend _telnet_autocomplete_skip adapter_nsrst_assert_width proc adapter_nsrst_assert_width args { echo "DEPRECATED! use 'adapter srst pulse_width' not 'adapter_nsrst_assert_width'" eval adapter srst pulse_width $args } +lappend _telnet_autocomplete_skip interface proc interface args { echo "DEPRECATED! use 'adapter driver' not 'interface'" eval adapter driver $args } +lappend _telnet_autocomplete_skip interface_transports proc interface_transports args { echo "DEPRECATED! use 'adapter transports' not 'interface_transports'" eval adapter transports $args } +lappend _telnet_autocomplete_skip interface_list proc interface_list args { echo "DEPRECATED! use 'adapter list' not 'interface_list'" eval adapter list $args } +lappend _telnet_autocomplete_skip ftdi_location proc ftdi_location args { echo "DEPRECATED! use 'adapter usb location' not 'ftdi_location'" eval adapter usb location $args } +lappend _telnet_autocomplete_skip xds110_serial proc xds110_serial args { - echo "DEPRECATED! use 'xds110 serial' not 'xds110_serial'" - eval xds110 serial $args + echo "DEPRECATED! use 'adapter serial' not 'xds110_serial'" + eval adapter serial $args } +lappend _telnet_autocomplete_skip xds110_supply_voltage proc xds110_supply_voltage args { echo "DEPRECATED! use 'xds110 supply' not 'xds110_supply_voltage'" eval xds110 supply $args @@ -230,9 +263,1015 @@ proc hla {cmd args} { tailcall "hla $cmd" {*}$args } +lappend _telnet_autocomplete_skip "hla newtap" proc "hla newtap" {args} { echo "DEPRECATED! use 'swj_newdap' not 'hla newtap'" eval swj_newdap $args } +lappend _telnet_autocomplete_skip ftdi_device_desc +proc ftdi_device_desc args { + echo "DEPRECATED! use 'ftdi device_desc' not 'ftdi_device_desc'" + eval ftdi device_desc $args +} + +lappend _telnet_autocomplete_skip ftdi_serial +proc ftdi_serial args { + echo "DEPRECATED! use 'adapter serial' not 'ftdi_serial'" + eval adapter serial $args +} + +lappend _telnet_autocomplete_skip ftdi_channel +proc ftdi_channel args { + echo "DEPRECATED! use 'ftdi channel' not 'ftdi_channel'" + eval ftdi channel $args +} + +lappend _telnet_autocomplete_skip ftdi_layout_init +proc ftdi_layout_init args { + echo "DEPRECATED! use 'ftdi layout_init' not 'ftdi_layout_init'" + eval ftdi layout_init $args +} + +lappend _telnet_autocomplete_skip ftdi_layout_signal +proc ftdi_layout_signal args { + echo "DEPRECATED! use 'ftdi layout_signal' not 'ftdi_layout_signal'" + eval ftdi layout_signal $args +} + +lappend _telnet_autocomplete_skip ftdi_set_signal +proc ftdi_set_signal args { + echo "DEPRECATED! use 'ftdi set_signal' not 'ftdi_set_signal'" + eval ftdi set_signal $args +} + +lappend _telnet_autocomplete_skip ftdi_get_signal +proc ftdi_get_signal args { + echo "DEPRECATED! use 'ftdi get_signal' not 'ftdi_get_signal'" + eval ftdi get_signal $args +} + +lappend _telnet_autocomplete_skip ftdi_vid_pid +proc ftdi_vid_pid args { + echo "DEPRECATED! use 'ftdi vid_pid' not 'ftdi_vid_pid'" + eval ftdi vid_pid $args +} + +lappend _telnet_autocomplete_skip ftdi_tdo_sample_edge +proc ftdi_tdo_sample_edge args { + echo "DEPRECATED! use 'ftdi tdo_sample_edge' not 'ftdi_tdo_sample_edge'" + eval ftdi tdo_sample_edge $args +} + +lappend _telnet_autocomplete_skip remote_bitbang_host +proc remote_bitbang_host args { + echo "DEPRECATED! use 'remote_bitbang host' not 'remote_bitbang_host'" + eval remote_bitbang host $args +} + +lappend _telnet_autocomplete_skip remote_bitbang_port +proc remote_bitbang_port args { + echo "DEPRECATED! use 'remote_bitbang port' not 'remote_bitbang_port'" + eval remote_bitbang port $args +} + +lappend _telnet_autocomplete_skip openjtag_device_desc +proc openjtag_device_desc args { + echo "DEPRECATED! use 'openjtag device_desc' not 'openjtag_device_desc'" + eval openjtag device_desc $args +} + +lappend _telnet_autocomplete_skip openjtag_variant +proc openjtag_variant args { + echo "DEPRECATED! use 'openjtag variant' not 'openjtag_variant'" + eval openjtag variant $args +} + +lappend _telnet_autocomplete_skip parport_port +proc parport_port args { + echo "DEPRECATED! use 'parport port' not 'parport_port'" + eval parport port $args +} + +lappend _telnet_autocomplete_skip parport_cable +proc parport_cable args { + echo "DEPRECATED! use 'parport cable' not 'parport_cable'" + eval parport cable $args +} + +lappend _telnet_autocomplete_skip parport_write_on_exit +proc parport_write_on_exit args { + echo "DEPRECATED! use 'parport write_on_exit' not 'parport_write_on_exit'" + eval parport write_on_exit $args +} + +lappend _telnet_autocomplete_skip parport_toggling_time +proc parport_toggling_time args { + echo "DEPRECATED! use 'parport toggling_time' not 'parport_toggling_time'" + eval parport toggling_time $args +} + +lappend _telnet_autocomplete_skip jtag_dpi_set_port +proc jtag_dpi_set_port args { + echo "DEPRECATED! use 'jtag_dpi set_port' not 'jtag_dpi_set_port'" + eval jtag_dpi set_port $args +} + +lappend _telnet_autocomplete_skip jtag_dpi_set_address +proc jtag_dpi_set_address args { + echo "DEPRECATED! use 'jtag_dpi set_address' not 'jtag_dpi_set_address'" + eval jtag_dpi set_address $args +} + +lappend _telnet_autocomplete_skip jtag_vpi_set_port +proc jtag_vpi_set_port args { + echo "DEPRECATED! use 'jtag_vpi set_port' not 'jtag_vpi_set_port'" + eval jtag_vpi set_port $args +} + +lappend _telnet_autocomplete_skip jtag_vpi_set_address +proc jtag_vpi_set_address args { + echo "DEPRECATED! use 'jtag_vpi set_address' not 'jtag_vpi_set_address'" + eval jtag_vpi set_address $args +} + +lappend _telnet_autocomplete_skip jtag_vpi_stop_sim_on_exit +proc jtag_vpi_stop_sim_on_exit args { + echo "DEPRECATED! use 'jtag_vpi stop_sim_on_exit' not 'jtag_vpi_stop_sim_on_exit'" + eval jtag_vpi stop_sim_on_exit $args +} + +lappend _telnet_autocomplete_skip presto_serial +proc presto_serial args { + echo "DEPRECATED! use 'presto serial' not 'presto_serial'" + eval presto serial $args +} + +lappend _telnet_autocomplete_skip xlnx_pcie_xvc_config +proc xlnx_pcie_xvc_config args { + echo "DEPRECATED! use 'xlnx_pcie_xvc config' not 'xlnx_pcie_xvc_config'" + eval xlnx_pcie_xvc config $args +} + +lappend _telnet_autocomplete_skip ulink_download_firmware +proc ulink_download_firmware args { + echo "DEPRECATED! use 'ulink download_firmware' not 'ulink_download_firmware'" + eval ulink download_firmware $args +} + +lappend _telnet_autocomplete_skip vsllink_usb_vid +proc vsllink_usb_vid args { + echo "DEPRECATED! use 'vsllink usb_vid' not 'vsllink_usb_vid'" + eval vsllink usb_vid $args +} + +lappend _telnet_autocomplete_skip vsllink_usb_pid +proc vsllink_usb_pid args { + echo "DEPRECATED! use 'vsllink usb_pid' not 'vsllink_usb_pid'" + eval vsllink usb_pid $args +} + +lappend _telnet_autocomplete_skip vsllink_usb_serial +proc vsllink_usb_serial args { + echo "DEPRECATED! use 'adapter serial' not 'vsllink_usb_serial'" + eval adapter serial $args +} + +lappend _telnet_autocomplete_skip vsllink_usb_bulkin +proc vsllink_usb_bulkin args { + echo "DEPRECATED! use 'vsllink usb_bulkin' not 'vsllink_usb_bulkin'" + eval vsllink usb_bulkin $args +} + +lappend _telnet_autocomplete_skip vsllink_usb_bulkout +proc vsllink_usb_bulkout args { + echo "DEPRECATED! use 'vsllink usb_bulkout' not 'vsllink_usb_bulkout'" + eval vsllink usb_bulkout $args +} + +lappend _telnet_autocomplete_skip vsllink_usb_interface +proc vsllink_usb_interface args { + echo "DEPRECATED! use 'vsllink usb_interface' not 'vsllink_usb_interface'" + 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 {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 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 +proc bcm2835gpio_speed_coeffs args { + echo "DEPRECATED! use 'bcm2835gpio speed_coeffs' not 'bcm2835gpio_speed_coeffs'" + eval bcm2835gpio speed_coeffs $args +} + +lappend _telnet_autocomplete_skip bcm2835gpio_peripheral_base +proc bcm2835gpio_peripheral_base args { + echo "DEPRECATED! use 'bcm2835gpio peripheral_base' not 'bcm2835gpio_peripheral_base'" + eval bcm2835gpio peripheral_base $args +} + +lappend _telnet_autocomplete_skip linuxgpiod_jtag_nums +proc linuxgpiod_jtag_nums args { + eval adapter_gpio_jtag_nums $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_tdo_num +proc linuxgpiod_tdo_num args { + eval adapter_gpio_helper tdo $args +} + +lappend _telnet_autocomplete_skip linuxgpiod_tdi_num +proc linuxgpiod_tdi_num args { + eval adapter_gpio_helper tdi $args +} + +lappend _telnet_autocomplete_skip linuxgpiod_srst_num +proc linuxgpiod_srst_num args { + eval adapter_gpio_helper srst $args +} + +lappend _telnet_autocomplete_skip linuxgpiod_trst_num +proc linuxgpiod_trst_num args { + eval adapter_gpio_helper trst $args +} + +lappend _telnet_autocomplete_skip linuxgpiod_swd_nums +proc linuxgpiod_swd_nums args { + eval adapter_gpio_swd_nums $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_led_num +proc linuxgpiod_led_num args { + eval adapter_gpio_helper led $args +} + +lappend _telnet_autocomplete_skip linuxgpiod_gpiochip +proc 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 +proc sysfsgpio_jtag_nums args { + echo "DEPRECATED! use 'sysfsgpio jtag_nums' not 'sysfsgpio_jtag_nums'" + eval sysfsgpio jtag_nums $args +} + +lappend _telnet_autocomplete_skip sysfsgpio_tck_num +proc sysfsgpio_tck_num args { + echo "DEPRECATED! use 'sysfsgpio tck_num' not 'sysfsgpio_tck_num'" + eval sysfsgpio tck_num $args +} + +lappend _telnet_autocomplete_skip sysfsgpio_tms_num +proc sysfsgpio_tms_num args { + echo "DEPRECATED! use 'sysfsgpio tms_num' not 'sysfsgpio_tms_num'" + eval sysfsgpio tms_num $args +} + +lappend _telnet_autocomplete_skip sysfsgpio_tdo_num +proc sysfsgpio_tdo_num args { + echo "DEPRECATED! use 'sysfsgpio tdo_num' not 'sysfsgpio_tdo_num'" + eval sysfsgpio tdo_num $args +} + +lappend _telnet_autocomplete_skip sysfsgpio_tdi_num +proc sysfsgpio_tdi_num args { + echo "DEPRECATED! use 'sysfsgpio tdi_num' not 'sysfsgpio_tdi_num'" + eval sysfsgpio tdi_num $args +} + +lappend _telnet_autocomplete_skip sysfsgpio_srst_num +proc sysfsgpio_srst_num args { + echo "DEPRECATED! use 'sysfsgpio srst_num' not 'sysfsgpio_srst_num'" + eval sysfsgpio srst_num $args +} + +lappend _telnet_autocomplete_skip sysfsgpio_trst_num +proc sysfsgpio_trst_num args { + echo "DEPRECATED! use 'sysfsgpio trst_num' not 'sysfsgpio_trst_num'" + eval sysfsgpio trst_num $args +} + +lappend _telnet_autocomplete_skip sysfsgpio_swd_nums +proc sysfsgpio_swd_nums args { + echo "DEPRECATED! use 'sysfsgpio swd_nums' not 'sysfsgpio_swd_nums'" + eval sysfsgpio swd_nums $args +} + +lappend _telnet_autocomplete_skip sysfsgpio_swclk_num +proc sysfsgpio_swclk_num args { + echo "DEPRECATED! use 'sysfsgpio swclk_num' not 'sysfsgpio_swclk_num'" + eval sysfsgpio swclk_num $args +} + +lappend _telnet_autocomplete_skip sysfsgpio_swdio_num +proc sysfsgpio_swdio_num args { + echo "DEPRECATED! use 'sysfsgpio swdio_num' not 'sysfsgpio_swdio_num'" + eval sysfsgpio swdio_num $args +} + +lappend _telnet_autocomplete_skip buspirate_adc +proc buspirate_adc args { + echo "DEPRECATED! use 'buspirate adc' not 'buspirate_adc'" + eval buspirate adc $args +} + +lappend _telnet_autocomplete_skip buspirate_vreg +proc buspirate_vreg args { + echo "DEPRECATED! use 'buspirate vreg' not 'buspirate_vreg'" + eval buspirate vreg $args +} + +lappend _telnet_autocomplete_skip buspirate_pullup +proc buspirate_pullup args { + echo "DEPRECATED! use 'buspirate pullup' not 'buspirate_pullup'" + eval buspirate pullup $args +} + +lappend _telnet_autocomplete_skip buspirate_led +proc buspirate_led args { + echo "DEPRECATED! use 'buspirate led' not 'buspirate_led'" + eval buspirate led $args +} + +lappend _telnet_autocomplete_skip buspirate_speed +proc buspirate_speed args { + echo "DEPRECATED! use 'buspirate speed' not 'buspirate_speed'" + eval buspirate speed $args +} + +lappend _telnet_autocomplete_skip buspirate_mode +proc buspirate_mode args { + echo "DEPRECATED! use 'buspirate mode' not 'buspirate_mode'" + eval buspirate mode $args +} + +lappend _telnet_autocomplete_skip buspirate_port +proc buspirate_port args { + echo "DEPRECATED! use 'buspirate port' not 'buspirate_port'" + eval buspirate port $args +} + +lappend _telnet_autocomplete_skip usb_blaster_device_desc +proc usb_blaster_device_desc args { + echo "DEPRECATED! use 'usb_blaster device_desc' not 'usb_blaster_device_desc'" + eval usb_blaster device_desc $args +} + +lappend _telnet_autocomplete_skip usb_blaster_vid_pid +proc usb_blaster_vid_pid args { + echo "DEPRECATED! use 'usb_blaster vid_pid' not 'usb_blaster_vid_pid'" + eval usb_blaster vid_pid $args +} + +lappend _telnet_autocomplete_skip usb_blaster_lowlevel_driver +proc usb_blaster_lowlevel_driver args { + echo "DEPRECATED! use 'usb_blaster lowlevel_driver' not 'usb_blaster_lowlevel_driver'" + eval usb_blaster lowlevel_driver $args +} + +lappend _telnet_autocomplete_skip usb_blaster_pin +proc usb_blaster_pin args { + echo "DEPRECATED! use 'usb_blaster pin' not 'usb_blaster_pin'" + eval usb_blaster pin $args +} + +lappend _telnet_autocomplete_skip usb_blaster_firmware +proc usb_blaster_firmware args { + echo "DEPRECATED! use 'usb_blaster firmware' not 'usb_blaster_firmware'" + eval usb_blaster firmware $args +} + +lappend _telnet_autocomplete_skip ft232r_serial_desc +proc ft232r_serial_desc args { + echo "DEPRECATED! use 'adapter serial_desc' not 'ft232r_serial_desc'" + eval adapter serial_desc $args +} + +lappend _telnet_autocomplete_skip ft232r_vid_pid +proc ft232r_vid_pid args { + echo "DEPRECATED! use 'ft232r vid_pid' not 'ft232r_vid_pid'" + eval ft232r vid_pid $args +} + +lappend _telnet_autocomplete_skip ft232r_jtag_nums +proc ft232r_jtag_nums args { + echo "DEPRECATED! use 'ft232r jtag_nums' not 'ft232r_jtag_nums'" + eval ft232r jtag_nums $args +} + +lappend _telnet_autocomplete_skip ft232r_tck_num +proc ft232r_tck_num args { + echo "DEPRECATED! use 'ft232r tck_num' not 'ft232r_tck_num'" + eval ft232r tck_num $args +} + +lappend _telnet_autocomplete_skip ft232r_tms_num +proc ft232r_tms_num args { + echo "DEPRECATED! use 'ft232r tms_num' not 'ft232r_tms_num'" + eval ft232r tms_num $args +} + +lappend _telnet_autocomplete_skip ft232r_tdo_num +proc ft232r_tdo_num args { + echo "DEPRECATED! use 'ft232r tdo_num' not 'ft232r_tdo_num'" + eval ft232r tdo_num $args +} + +lappend _telnet_autocomplete_skip ft232r_tdi_num +proc ft232r_tdi_num args { + echo "DEPRECATED! use 'ft232r tdi_num' not 'ft232r_tdi_num'" + eval ft232r tdi_num $args +} + +lappend _telnet_autocomplete_skip ft232r_srst_num +proc ft232r_srst_num args { + echo "DEPRECATED! use 'ft232r srst_num' not 'ft232r_srst_num'" + eval ft232r srst_num $args +} + +lappend _telnet_autocomplete_skip ft232r_trst_num +proc ft232r_trst_num args { + echo "DEPRECATED! use 'ft232r trst_num' not 'ft232r_trst_num'" + eval ft232r trst_num $args +} + +lappend _telnet_autocomplete_skip ft232r_restore_serial +proc ft232r_restore_serial args { + echo "DEPRECATED! use 'ft232r restore_serial' not 'ft232r_restore_serial'" + eval ft232r restore_serial $args +} + +lappend _telnet_autocomplete_skip cmsis_dap_serial +proc cmsis_dap_serial args { + echo "DEPRECATED! use 'adapter serial' not 'cmsis_dap_serial'" + eval adapter serial $args +} + +lappend _telnet_autocomplete_skip "ft232r serial_desc" +proc "ft232r serial_desc" {args} { + echo "DEPRECATED! use 'adapter serial' not 'ft232r serial_desc'" + eval adapter serial $args +} + +lappend _telnet_autocomplete_skip "ftdi serial" +proc "ftdi serial" {args} { + echo "DEPRECATED! use 'adapter serial' not 'ftdi serial'" + eval adapter serial $args +} + +lappend _telnet_autocomplete_skip hla_serial +proc hla_serial args { + echo "DEPRECATED! use 'adapter serial' not 'hla_serial'" + eval adapter serial $args +} + +lappend _telnet_autocomplete_skip "jlink serial" +proc "jlink serial" {args} { + echo "DEPRECATED! use 'adapter serial' not 'jlink serial'" + eval adapter serial $args +} + +lappend _telnet_autocomplete_skip kitprog_serial +proc kitprog_serial args { + echo "DEPRECATED! use 'adapter serial' not 'kitprog_serial'" + eval adapter serial $args +} + +lappend _telnet_autocomplete_skip "presto serial" +proc "presto serial" {args} { + echo "DEPRECATED! use 'adapter serial' not 'presto serial'" + eval adapter serial $args +} + +lappend _telnet_autocomplete_skip "st-link serial" +proc "st-link serial" {args} { + echo "DEPRECATED! use 'adapter serial' not 'st-link serial'" + eval adapter serial $args +} + +lappend _telnet_autocomplete_skip "vsllink usb_serial" +proc "vsllink usb_serial" {args} { + echo "DEPRECATED! use 'adapter serial' not 'vsllink usb_serial'" + eval adapter serial $args +} + +lappend _telnet_autocomplete_skip "xds110 serial" +proc "xds110 serial" {args} { + echo "DEPRECATED! use 'adapter serial' not 'xds110 serial'" + 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 + } +} + +lappend _telnet_autocomplete_skip "ipdbg -start" +proc "ipdbg -start" {args} { + echo "DEPRECATED! use 'ipdbg create-hub' and 'chip.ipdbghub ipdbg start ...', not 'ipdbg -start ...'" + set tap_name "" + set pld_name "" + set tool_num "1" + set port_num "4242" + set idx 0 + set num_args [llength $args] + while {$idx < $num_args} { + set arg [lindex $args $idx] + switch -- $arg { + "-tap" { + incr idx + if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} { + echo "no TAP name given" + return + } + set tap_name [lindex $args $idx] + } + "-pld" { + incr idx + if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} { + echo "no PLD name given" + return + } + set pld_name [lindex $args $idx] + } + "-tool" { + if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} { + set tool_num [lindex $args [expr {$idx + 1}]] + set args [lreplace $args [expr {$idx + 1}] [expr {$idx + 1}]] + incr num_args -1 + } + set args [lreplace $args $idx $idx] + incr num_args -1 + incr idx -1 + } + "-port" { + if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} { + set port_num [lindex $args [expr {$idx + 1}]] + set args [lreplace $args [expr {$idx + 1}] [expr {$idx + 1}]] + incr num_args -1 + } + set args [lreplace $args $idx $idx] + incr num_args -1 + incr idx -1 + } + "-hub" { + set args [lreplace $args $idx $idx "-ir" ] + } + default { +# don't touch remaining arguments + } + } + incr idx + } + + set hub_name "" + if {$tap_name != ""} { + set hub_name [lindex [split $tap_name .] 0].ipdbghub + } elseif {$pld_name != ""} { + set hub_name [lindex [split $pld_name .] 0].ipdbghub + } else { + echo "parsing arguments failed: no tap and no pld given." + return + } + + echo "name: $hub_name" + echo "ipdbg create-hub $hub_name $args" + + catch {eval ipdbg create-hub $hub_name $args} + + eval $hub_name ipdbg start -tool $tool_num -port $port_num +} + +lappend _telnet_autocomplete_skip "ipdbg -stop" +proc "ipdbg -stop" {args} { + echo "DEPRECATED! use 'chip.ipdbghub ipdbg stop ...', not 'ipdbg -stop ...'" + set tap_name "" + set pld_name "" + set tool_num "1" + set idx 0 + set num_args [llength $args] + while {$idx < $num_args} { + set arg [lindex $args $idx] + switch -- $arg { + "-tap" { + incr idx + if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} { + echo "no TAP name given" + return + } + set tap_name [lindex $args $idx] + } + "-pld" { + incr idx + if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} { + echo "no PLD name given" + return + } + set pld_name [lindex $args $idx] + } + "-tool" { + if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} { + set tool_num [lindex $args [expr {$idx + 1}]] + } + } + default { +# don't touch remaining arguments + } + } + incr idx + } + + set hub_name "" + if {$tap_name != ""} { + set hub_name [lindex [split $tap_name .] 0].ipdbghub + } elseif {$pld_name != ""} { + set hub_name [lindex [split $pld_name .] 0].ipdbghub + } else { + echo "parsing arguments failed: no tap and no pld given." + return + } + + eval $hub_name ipdbg stop -tool $tool_num +} + # END MIGRATION AIDS diff --git a/src/jtag/swd.h b/src/jtag/swd.h index 487cb85bf0..5f626c1bf8 100644 --- a/src/jtag/swd.h +++ b/src/jtag/swd.h @@ -1,45 +1,41 @@ +/* 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 #define OPENOCD_JTAG_SWD_H +#include <helper/log.h> #include <target/arm_adi_v5.h> /* Bits in SWD command packets, written from host to target * first bit on the wire is START */ #define SWD_CMD_START (1 << 0) /* always set */ -#define SWD_CMD_APnDP (1 << 1) /* set only for AP access */ -#define SWD_CMD_RnW (1 << 2) /* set only for read access */ +#define SWD_CMD_APNDP (1 << 1) /* set only for AP access */ +#define SWD_CMD_RNW (1 << 2) /* set only for read access */ #define SWD_CMD_A32 (3 << 3) /* bits A[3:2] of register addr */ #define SWD_CMD_PARITY (1 << 5) /* parity of APnDP|RnW|A32 */ #define SWD_CMD_STOP (0 << 6) /* always clear for synch SWD */ #define SWD_CMD_PARK (1 << 7) /* driven high by host */ /* followed by TRN, 3-bits of ACK, TRN */ +/* + * The SWD subsystem error codes + */ +#define ERROR_SWD_FAIL (-400) /** protocol or parity error */ +#define ERROR_SWD_FAULT (-401) /** device returned FAULT in ACK field */ + /** * Construct a "cmd" byte, in lSB bit order, which swd_driver.read_reg() * and swd_driver.write_reg() methods will use directly. */ static inline uint8_t swd_cmd(bool is_read, bool is_ap, uint8_t regnum) { - uint8_t cmd = (is_ap ? SWD_CMD_APnDP : 0) - | (is_read ? SWD_CMD_RnW : 0) + uint8_t cmd = (is_ap ? SWD_CMD_APNDP : 0) + | (is_read ? SWD_CMD_RNW : 0) | ((regnum & 0xc) << 1); /* 8 cmd bits 4:1 may be set */ @@ -53,6 +49,40 @@ static inline uint8_t swd_cmd(bool is_read, bool is_ap, uint8_t regnum) /* SWD_ACK_* bits are defined in <target/arm_adi_v5.h> */ +/** + * Test if we can rely on ACK returned by SWD command + * + * @param cmd Byte constructed by swd_cmd(), START, STOP and TRN are filtered off + * @returns true if ACK should be checked, false if should be ignored + */ +static inline bool swd_cmd_returns_ack(uint8_t cmd) +{ + uint8_t base_cmd = cmd & (SWD_CMD_APNDP | SWD_CMD_RNW | SWD_CMD_A32); + + /* DPv2 does not reply to DP_TARGETSEL write cmd */ + return base_cmd != swd_cmd(false, false, DP_TARGETSEL); +} + +/** + * Convert SWD ACK value returned from DP to OpenOCD error code + * + * @param ack + * @returns error code + */ +static inline int swd_ack_to_error_code(uint8_t ack) +{ + switch (ack) { + case SWD_ACK_OK: + return ERROR_OK; + case SWD_ACK_WAIT: + return ERROR_WAIT; + case SWD_ACK_FAULT: + return ERROR_SWD_FAULT; + default: + return ERROR_SWD_FAIL; + } +} + /* * The following sequences are updated to * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031E 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 153a98e1b6..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,25 +13,13 @@ * * * 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 "adapter.h" #include "jtag.h" #include "swd.h" #include "minidriver.h" @@ -41,6 +31,8 @@ #include <strings.h> #endif +#include <helper/command.h> +#include <helper/nvp.h> #include <helper/time_support.h> #include "transport/transport.h" @@ -49,7 +41,7 @@ * Holds support for accessing JTAG-specific mechanisms from TCl scripts. */ -static const 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" }, @@ -62,9 +54,9 @@ struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) { const char *cp = Jim_GetString(o, NULL); struct jtag_tap *t = cp ? jtag_tap_by_string(cp) : NULL; - if (NULL == cp) + if (!cp) cp = "(unknown)"; - if (NULL == t) + if (!t) Jim_SetResultFormatted(interp, "Tap '%s' could not be found", cp); return t; } @@ -82,190 +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; - - script_debug(interp, argc, args); + 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 (0 == strcmp("-endstate", cp)) { - /* 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 */ - - assert(e == JIM_OK); + if (!scan_is_safe(endstate)) + LOG_WARNING("drscan with unsafe endstate \"%s\"", state_name); - tap = jtag_tap_by_jim_obj(interp, args[1]); - if (tap == NULL) - 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); - 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; - } - - script_debug(interp, argc, args); + 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) { - script_debug(interp, argc, args); + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - Jim_SetResult(interp, Jim_NewIntObj(interp, jtag_get_flush_queue_count())); + int count = jtag_get_flush_queue_count(); + command_print_sameline(CMD, "%d", count); - return JIM_OK; + 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 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(Jim_GetOptInfo *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; - } - - Jim_Nvp *n; - int e = Jim_GetOpt_Nvp(goi, nvp_jtag_tap_event, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(goi, nvp_jtag_tap_event, 1); - return e; - } + struct jtag_tap_event_action *jteap = tap->event_action; - 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; - /* 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 (NULL != 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(Jim_GetOptInfo *goi, struct jtag_tap *tap) +__COMMAND_HANDLER(handle_jtag_configure) { - /* parse config or cget options */ - while (goi->argc > 0) { - Jim_SetEmptyResult(goi->interp); - - Jim_Nvp *n; - int e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(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(Jim_Nvp *n, Jim_GetOptInfo *goi, - struct jtag_tap *pTap) -{ - 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(pTap->expected_ids, - (pTap->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; + } } - - pTap->expected_ids = p; - pTap->expected_ids[pTap->expected_ids_cnt++] = w; - - return JIM_OK; + return ERROR_OK; } #define NTAP_OPT_IRLEN 0 @@ -470,170 +366,168 @@ static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi, #define NTAP_OPT_DISABLED 4 #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(Jim_Nvp *n, Jim_GetOptInfo *goi, - struct jtag_tap *pTap) +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(pTap->ir_capture_value))) { - LOG_WARNING("%s: huge IR length %d", - pTap->dotted_name, (int) w); - } - pTap->ir_length = w; - break; - case NTAP_OPT_IRMASK: - if (is_bad_irval(pTap->ir_length, w)) { - LOG_ERROR("%s: IR mask %x too big", - pTap->dotted_name, - (int) w); - return JIM_ERR; - } - if ((w & 3) != 3) - LOG_WARNING("%s: nonstandard IR mask", pTap->dotted_name); - pTap->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(pTap->ir_length, w)) { - LOG_ERROR("%s: IR capture %x too big", - pTap->dotted_name, (int) w); - return JIM_ERR; - } - if ((w & 3) != 1) - LOG_WARNING("%s: nonstandard IR value", - pTap->dotted_name); - pTap->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(Jim_GetOptInfo *goi) -{ - struct jtag_tap *pTap; - int x; - int e; - Jim_Nvp *n; - char *cp; - const 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 = NULL, .value = -1 }, - }; - - pTap = calloc(1, sizeof(struct jtag_tap)); - if (!pTap) { - 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(pTap); - 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); - pTap->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); - pTap->tapname = strdup(tmp); + break; - /* name + dot + name + null */ - x = strlen(pTap->chip) + 1 + strlen(pTap->tapname) + 1; - cp = malloc(x); - sprintf(cp, "%s.%s", pTap->chip, pTap->tapname); - pTap->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", - pTap->chip, pTap->tapname, pTap->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 */ - pTap->enabled = true; - jtag_tap_init(pTap); - 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. - */ - pTap->ir_capture_mask = 0x03; - pTap->ir_capture_value = 0x01; - - while (goi->argc) { - e = Jim_GetOpt_Nvp(goi, opts, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(goi, opts, 0); - free(cp); - free(pTap); - return e; + 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; + + 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: - pTap->disabled_after_reset = false; - break; - case NTAP_OPT_DISABLED: - pTap->disabled_after_reset = true; - break; - case NTAP_OPT_EXPECTED_ID: - e = jim_newtap_expected_id(n, goi, pTap); - if (JIM_OK != e) { - free(cp); - free(pTap); - return e; - } - break; - case NTAP_OPT_IRLEN: - case NTAP_OPT_IRMASK: - case NTAP_OPT_IRCAPTURE: - e = jim_newtap_ir_param(n, goi, pTap); - if (JIM_OK != e) { - free(cp); - free(pTap); - return e; - } - break; - case NTAP_OPT_VERSION: - pTap->ignore_version = true; - break; - } /* switch (n->value) */ - } /* while (goi->argc) */ + } /* default is enabled-after-reset */ - pTap->enabled = !pTap->disabled_after_reset; + tap->enabled = !tap->disabled_after_reset; + + if (transport_is_jtag() && tap->ir_length == 0) { + command_print(CMD, "newtap: %s missing IR length", tap->dotted_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + 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; + } - /* Did all the required option bits get cleared? */ - if (pTap->ir_length != 0) { - jtag_tap_init(pTap); - return JIM_OK; + 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; } - Jim_SetResultFormatted(goi->interp, - "newtap: %s missing IR length", - pTap->dotted_name); - jtag_tap_free(pTap); - return JIM_ERR; + jtag_tap_init(tap); + return ERROR_OK; } static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e) @@ -641,11 +535,11 @@ static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e) struct jtag_tap_event_action *jteap; int retval; - for (jteap = tap->event_action; jteap != NULL; jteap = jteap->next) { + for (jteap = tap->event_action; jteap; jteap = jteap->next) { if (jteap->event != e) continue; - 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)); @@ -677,62 +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) { - Jim_GetOptInfo 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 *eObj = Jim_NewIntObj(goi.interp, e); - Jim_IncrRefCount(eObj); - Jim_SetResultFormatted(goi.interp, "error: %#s", eObj); - Jim_DecrRefCount(goi.interp, eObj); - 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; - Jim_GetOptInfo 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 *eObj = Jim_NewIntObj(goi.interp, e); - Jim_IncrRefCount(eObj); - Jim_SetResultFormatted(goi.interp, "error: %#s", eObj); - Jim_DecrRefCount(goi.interp, eObj); - 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) -{ - Jim_GetOptInfo 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; @@ -747,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; @@ -760,84 +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) { - const char *cmd_name = Jim_GetString(argv[0], NULL); - Jim_GetOptInfo 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 == NULL) - 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) -{ - const char *cmd_name = Jim_GetString(argv[0], NULL); - Jim_GetOptInfo 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 == NULL) - 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) { - Jim_GetOptInfo 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) @@ -867,35 +694,39 @@ 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 " "['-enable'|'-disable'] " "['-expected_id' number] " "['-ignore-version'] " + "['-ignore-bypass'] " "['-ircapture' number] " - "['-mask' 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", @@ -903,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", @@ -911,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", @@ -919,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", @@ -927,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", @@ -935,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, @@ -1043,14 +875,14 @@ COMMAND_HANDLER(handle_jtag_rclk_command) unsigned khz = 0; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], khz); - retval = jtag_config_rclk(khz); - if (ERROR_OK != retval) + retval = adapter_config_rclk(khz); + if (retval != ERROR_OK) return retval; } - int cur_khz = jtag_get_speed_khz(); - retval = jtag_get_speed_readable(&cur_khz); - if (ERROR_OK != retval) + int cur_khz = adapter_get_speed_khz(); + retval = adapter_get_speed_readable(&cur_khz); + if (retval != ERROR_OK) return retval; if (cur_khz) @@ -1125,7 +957,7 @@ COMMAND_HANDLER(handle_irscan_command) int retval; for (i = 0; i < num_fields; i++) { tap = jtag_tap_by_string(CMD_ARGV[i*2]); - if (tap == NULL) { + if (!tap) { free(fields); command_print(CMD, "Tap: %s unknown", CMD_ARGV[i*2]); @@ -1133,7 +965,7 @@ COMMAND_HANDLER(handle_irscan_command) } uint64_t value; retval = parse_u64(CMD_ARGV[i * 2 + 1], &value); - if (ERROR_OK != retval) + if (retval != ERROR_OK) goto error_return; int field_size = tap->ir_length; @@ -1356,7 +1188,7 @@ static const struct command_registration jtag_command_handlers[] = { .mode = COMMAND_ANY, .help = "Wait for an SRST deassert. " "Useful for cases where you need something to happen within ms " - "of an srst deassert. Timeout in ms ", + "of an srst deassert. Timeout in ms", .usage = "ms", }, { 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/jtag/zy1000/jtag_minidriver.h b/src/jtag/zy1000/jtag_minidriver.h deleted file mode 100644 index 7d1ede5d48..0000000000 --- a/src/jtag/zy1000/jtag_minidriver.h +++ /dev/null @@ -1,182 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-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/>. * - ***************************************************************************/ - -/* used to test manual mode */ -#define TEST_MANUAL() 0 -#define VERBOSE(a) - -#if BUILD_ZY1000_MASTER - -#define ZY1000_PEEK(a, b) do {b = *((volatile uint32_t *)(a)); } while (0) -#define ZY1000_POKE(a, b) do {*((volatile uint32_t *)(a)) = b; } while (0) -extern volatile void *zy1000_jtag_master; -#define ZY1000_JTAG_BASE ((unsigned long)zy1000_jtag_master) - -#else - -/* redirect this to TCP/IP */ -#define ZY1000_JTAG_BASE 0 -extern void zy1000_tcpout(uint32_t address, uint32_t data); -extern uint32_t zy1000_tcpin(uint32_t address); -#define ZY1000_PEEK(a, b) b = zy1000_tcpin(a) -#define ZY1000_POKE(a, b) zy1000_tcpout(a, b) - -#endif - -#if BUILD_ZY1000_MASTER -/* FIFO empty? */ -static inline void waitIdle(void) -{ - uint32_t empty; - do { - ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, empty); - } while ((empty & 0x100) == 0); -} - -static inline void zy1000_flush_readqueue(void) -{ - /* Not used w/hardware fifo */ -} -static inline void zy1000_flush_callbackqueue(void) -{ - /* Not used w/hardware fifo */ -} -#else -extern void waitIdle(void); -void zy1000_flush_readqueue(void); -void zy1000_flush_callbackqueue(void); -void zy1000_jtag_add_callback4(jtag_callback_t callback, - jtag_callback_data_t data0, - jtag_callback_data_t data1, - jtag_callback_data_t data2, - jtag_callback_data_t data3); -void zy1000_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0); -#endif - -static inline void waitQueue(void) -{ -/* waitIdle(); */ -} - -static inline void sampleShiftRegister(void) -{ -#if 0 - uint32_t dummy; - waitIdle(); - ZY1000_PEEK(ZY1000_JTAG_BASE + 0xc, dummy); -#endif -} - -static inline void setCurrentState(enum tap_state state) -{ - uint32_t a; - a = state; - int repeat = 0; - if (state == TAP_RESET) { - /* The FPGA nor we know the current state of the CPU TAP */ - /* controller. This will move it to TAP for sure. */ - /* */ - /* 5 should be enough here, 7 is what OpenOCD uses */ - repeat = 7; - } - waitQueue(); - sampleShiftRegister(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | a); - -} - -/* - * Enter state and cause repeat transitions *out* of that state. So if the endState != state, then - * the transition from state to endState counts as a transition out of state. - */ -static inline void shiftValueInner(const enum tap_state state, - const enum tap_state endState, - int repeat, - uint32_t value) -{ - uint32_t a, b; - a = state; - b = endState; - waitQueue(); - sampleShiftRegister(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0xc, value); -#if 1 -#if TEST_MANUAL() - if ((state == TAP_DRSHIFT) && (endState != TAP_DRSHIFT)) { - int i; - setCurrentState(state); - for (i = 0; i < repeat; i++) { - int tms; - tms = 0; - if ((i == repeat-1) && (state != endState)) - tms = 1; - /* shift out value */ - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, (((value >> i)&1) << 1) | tms); - } - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - waitIdle(); - /* ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_DRSHIFT); // set this state and things - * break => expected */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_DRPAUSE); /* set this and things will - * work => expected. Not - * setting this is not - * sufficient to make things - * break. */ - setCurrentState(endState); - } else - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | b); - -#else - /* fast version */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | b); -#endif -#else - /* maximum debug version */ - if ((repeat > 0) && ((state == TAP_DRSHIFT) || (state == TAP_SI))) { - int i; - /* sample shift register for every bit. */ - for (i = 0; i < repeat-1; i++) { - sampleShiftRegister(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0xc, value >> i); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (1 << 8) | (a << 4) | a); - } - sampleShiftRegister(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0xc, value >> (repeat-1)); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (1 << 8) | (a << 4) | b); - } else { - sampleShiftRegister(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | b); - } - sampleShiftRegister(); -#endif -} - -#if BUILD_ZY1000_MASTER -#define interface_jtag_add_callback(callback, in) callback(in) -#define interface_jtag_add_callback4(callback, in, data1, data2, \ - data3) jtag_set_error(callback(in, data1, data2, data3)) -#else -#define interface_jtag_add_callback(callback, in) zy1000_jtag_add_callback(callback, in) -#define interface_jtag_add_callback4(callback, in, data1, data2, data3) zy1000_jtag_add_callback4( \ - callback, \ - in, \ - data1, \ - data2, \ - data3) -#endif diff --git a/src/jtag/zy1000/zy1000.c b/src/jtag/zy1000/zy1000.c deleted file mode 100644 index 669e6f45c4..0000000000 --- a/src/jtag/zy1000/zy1000.c +++ /dev/null @@ -1,1259 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-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 supports the zy1000 debugger: - * - * http://www.ultsol.com/index.php/component/content/article/8/33-zylin-zy1000-jtag-probe - * - * The zy1000 is a standalone debugger that has a web interface and - * requires no drivers on the developer host as all communication - * is via TCP/IP. The zy1000 gets it performance(~400-700kBytes/s - * DCC downloads @ 16MHz target) as it has an FPGA to hardware - * accelerate the JTAG commands, while offering *very* low latency - * between OpenOCD and the FPGA registers. - * - * The disadvantage of the zy1000 is that it has a feeble CPU compared to - * a PC(ca. 50-500 DMIPS depending on how one counts it), whereas a PC - * is on the order of 10000 DMIPS(i.e. at a factor of 20-200). - * - * The zy1000 revc hardware is using an Altera Nios CPU, whereas the - * revb is using ARM7 + Xilinx. - * - * See Zylin web pages or contact Zylin for more information. - * - * The reason this code is in OpenOCD rather than OpenOCD linked with the - * ZY1000 code is that OpenOCD is the long road towards getting - * libopenocd into place. libopenocd will support both low performance, - * low latency systems(embedded) and high performance high latency - * systems(PCs). - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <pthread.h> - -#include <target/embeddedice.h> -#include <jtag/minidriver.h> -#include <jtag/interface.h> -#include <time.h> -#include <helper/time_support.h> - -#include <netinet/tcp.h> - -/* Assume we're connecting to a revc w/60MHz clock. */ -#define ZYLIN_KHZ 60000 - -/* The software needs to check if it's in RCLK mode or not */ -static bool zy1000_rclk; - -static int zy1000_khz(int khz, int *jtag_speed) -{ - if (khz == 0) - *jtag_speed = 0; - else { - int speed; - /* Round speed up to nearest divisor. - * - * E.g. 16000kHz - * (64000 + 15999) / 16000 = 4 - * (4 + 1) / 2 = 2 - * 2 * 2 = 4 - * - * 64000 / 4 = 16000 - * - * E.g. 15999 - * (64000 + 15998) / 15999 = 5 - * (5 + 1) / 2 = 3 - * 3 * 2 = 6 - * - * 64000 / 6 = 10666 - * - */ - speed = (ZYLIN_KHZ + (khz - 1)) / khz; - speed = (speed + 1) / 2; - speed *= 2; - if (speed > 8190) { - /* maximum dividend */ - speed = 8190; - } - *jtag_speed = speed; - } - return ERROR_OK; -} - -static int zy1000_speed_div(int speed, int *khz) -{ - if (speed == 0) - *khz = 0; - else - *khz = ZYLIN_KHZ / speed; - - return ERROR_OK; -} - -static bool readPowerDropout(void) -{ - uint32_t state; - /* sample and clear power dropout */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x80); - ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, state); - bool powerDropout; - powerDropout = (state & 0x80) != 0; - return powerDropout; -} - - -static bool readSRST(void) -{ - uint32_t state; - /* sample and clear SRST sensing */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000040); - ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, state); - bool srstAsserted; - srstAsserted = (state & 0x40) != 0; - return srstAsserted; -} - -static int zy1000_srst_asserted(int *srst_asserted) -{ - *srst_asserted = readSRST(); - return ERROR_OK; -} - -static int zy1000_power_dropout(int *dropout) -{ - *dropout = readPowerDropout(); - return ERROR_OK; -} - -/* Wait for SRST to assert or deassert */ -static void waitSRST(bool asserted) -{ - bool first = true; - int64_t start = 0; - int64_t total = 0; - const char *mode = asserted ? "assert" : "deassert"; - - for (;; ) { - bool srstAsserted = readSRST(); - if ((asserted && srstAsserted) || (!asserted && !srstAsserted)) { - if (total > 1) - LOG_USER("SRST took %dms to %s", (int)total, mode); - break; - } - - if (first) { - first = false; - start = timeval_ms(); - } - - total = timeval_ms() - start; - - keep_alive(); - - if (total > 5000) { - LOG_ERROR("SRST took too long to %s: %" PRId64 "ms", mode, total); - break; - } - } -} - -void zy1000_reset(int trst, int srst) -{ - LOG_DEBUG("zy1000 trst=%d, srst=%d", trst, srst); - - /* flush the JTAG FIFO. Not flushing the queue before messing with - * reset has such interesting bugs as causing hard to reproduce - * RCLK bugs as RCLK will stop responding when TRST is asserted - */ - waitIdle(); - - if (!srst) - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x00000001); - else { - /* Danger!!! if clk != 0 when in - * idle in TAP_IDLE, reset halt on str912 will fail. - */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000001); - - waitSRST(true); - } - - if (!trst) - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x00000002); - else { - /* assert reset */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000002); - } - - if (trst || (srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) { - /* we're now in the RESET state until trst is deasserted */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_RESET); - } else { - /* We'll get RCLK failure when we assert TRST, so clear any false positives here */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x400); - } - - /* wait for srst to float back up */ - if ((!srst && ((jtag_get_reset_config() & RESET_TRST_PULLS_SRST) == 0)) || - (!srst && !trst && (jtag_get_reset_config() & RESET_TRST_PULLS_SRST))) - waitSRST(false); -} - -int zy1000_speed(int speed) -{ - /* flush JTAG master FIFO before setting speed */ - waitIdle(); - - zy1000_rclk = false; - - if (speed == 0) { - /*0 means RCLK*/ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x100); - zy1000_rclk = true; - LOG_DEBUG("jtag_speed using RCLK"); - } else { - if (speed > 8190 || speed < 2) { - LOG_USER( - "valid ZY1000 jtag_speed=[8190,2]. With divisor is %dkHz / even values between 8190-2, i.e. min %dHz, max %dMHz", - ZYLIN_KHZ, - (ZYLIN_KHZ * 1000) / 8190, - ZYLIN_KHZ / (2 * 1000)); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - int khz; - speed &= ~1; - zy1000_speed_div(speed, &khz); - LOG_USER("jtag_speed %d => JTAG clk=%d kHz", speed, khz); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x100); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x1c, speed); - } - return ERROR_OK; -} - -static bool savePower; - -static void setPower(bool power) -{ - savePower = power; - if (power) - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x8); - else - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x8); -} - -COMMAND_HANDLER(handle_power_command) -{ - switch (CMD_ARGC) { - case 1: { - bool enable; - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable); - setPower(enable); - } - /* fall through */ - case 0: - LOG_INFO("Target power %s", savePower ? "on" : "off"); - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; -} - -#if !BUILD_ZY1000_MASTER -static char *tcp_server = "notspecified"; -static int jim_zy1000_server(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - if (argc != 2) - return JIM_ERR; - - tcp_server = strdup(Jim_GetString(argv[1], NULL)); - - return JIM_OK; -} -#endif - -static int zylinjtag_Jim_Command_powerstatus(Jim_Interp *interp, - int argc, - Jim_Obj * const *argv) -{ - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "powerstatus"); - return JIM_ERR; - } - - bool dropout = readPowerDropout(); - - Jim_SetResult(interp, Jim_NewIntObj(interp, dropout)); - - return JIM_OK; -} - -int zy1000_quit(void) -{ - - return ERROR_OK; -} - -int interface_jtag_execute_queue(void) -{ - uint32_t empty; - - waitIdle(); - - /* We must make sure to write data read back to memory location before we return - * from this fn - */ - zy1000_flush_readqueue(); - - /* and handle any callbacks... */ - zy1000_flush_callbackqueue(); - - if (zy1000_rclk) { - /* Only check for errors when using RCLK to speed up - * jtag over TCP/IP - */ - ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, empty); - /* clear JTAG error register */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x400); - - if ((empty&0x400) != 0) { - LOG_WARNING("RCLK timeout"); - /* the error is informative only as we don't want to break the firmware if there - * is a false positive. - */ - /* return ERROR_FAIL; */ - } - } - return ERROR_OK; -} - -static void writeShiftValue(uint8_t *data, int bits); - -/* here we shuffle N bits out/in */ -static inline void scanBits(const uint8_t *out_value, - uint8_t *in_value, - int num_bits, - bool pause_now, - tap_state_t shiftState, - tap_state_t end_state) -{ - tap_state_t pause_state = shiftState; - for (int j = 0; j < num_bits; j += 32) { - int k = num_bits - j; - if (k > 32) { - k = 32; - /* we have more to shift out */ - } else if (pause_now) { - /* this was the last to shift out this time */ - pause_state = end_state; - } - - /* we have (num_bits + 7)/8 bytes of bits to toggle out. */ - /* bits are pushed out LSB to MSB */ - uint32_t value; - value = 0; - if (out_value != NULL) { - for (int l = 0; l < k; l += 8) - value |= out_value[(j + l)/8]<<l; - } - /* mask away unused bits for easier debugging */ - if (k < 32) - value &= ~(((uint32_t)0xffffffff) << k); - else { - /* Shifting by >= 32 is not defined by the C standard - * and will in fact shift by &0x1f bits on nios */ - } - - shiftValueInner(shiftState, pause_state, k, value); - - if (in_value != NULL) - writeShiftValue(in_value + (j/8), k); - } -} - -static inline void scanFields(int num_fields, - const struct scan_field *fields, - tap_state_t shiftState, - tap_state_t end_state) -{ - for (int i = 0; i < num_fields; i++) { - scanBits(fields[i].out_value, - fields[i].in_value, - fields[i].num_bits, - (i == num_fields-1), - shiftState, - end_state); - } -} - -int interface_jtag_add_ir_scan(struct jtag_tap *active, - const struct scan_field *fields, - tap_state_t state) -{ - int scan_size = 0; - struct jtag_tap *tap, *nextTap; - tap_state_t pause_state = TAP_IRSHIFT; - - for (tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = nextTap) { - nextTap = jtag_tap_next_enabled(tap); - if (nextTap == NULL) - pause_state = state; - scan_size = tap->ir_length; - - /* search the list */ - if (tap == active) { - scanFields(1, fields, TAP_IRSHIFT, pause_state); - /* update device information */ - buf_cpy(fields[0].out_value, tap->cur_instr, scan_size); - - tap->bypass = 0; - } else { - /* if a device isn't listed, set it to BYPASS */ - assert(scan_size <= 32); - shiftValueInner(TAP_IRSHIFT, pause_state, scan_size, 0xffffffff); - - /* Optimization code will check what the cur_instr is set to, so - * we must set it to bypass value. - */ - buf_set_ones(tap->cur_instr, tap->ir_length); - - tap->bypass = 1; - } - } - - return ERROR_OK; -} - -int interface_jtag_add_plain_ir_scan(int num_bits, - const uint8_t *out_bits, - uint8_t *in_bits, - tap_state_t state) -{ - scanBits(out_bits, in_bits, num_bits, true, TAP_IRSHIFT, state); - return ERROR_OK; -} - -int interface_jtag_add_dr_scan(struct jtag_tap *active, - int num_fields, - const struct scan_field *fields, - tap_state_t state) -{ - struct jtag_tap *tap, *nextTap; - tap_state_t pause_state = TAP_DRSHIFT; - for (tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = nextTap) { - nextTap = jtag_tap_next_enabled(tap); - if (nextTap == NULL) - pause_state = state; - - /* Find a range of fields to write to this tap */ - if (tap == active) { - assert(!tap->bypass); - - scanFields(num_fields, fields, TAP_DRSHIFT, pause_state); - } else { - /* Shift out a 0 for disabled tap's */ - assert(tap->bypass); - shiftValueInner(TAP_DRSHIFT, pause_state, 1, 0); - } - } - return ERROR_OK; -} - -int interface_jtag_add_plain_dr_scan(int num_bits, - const uint8_t *out_bits, - uint8_t *in_bits, - tap_state_t state) -{ - scanBits(out_bits, in_bits, num_bits, true, TAP_DRSHIFT, state); - return ERROR_OK; -} - -int interface_jtag_add_tlr(void) -{ - setCurrentState(TAP_RESET); - return ERROR_OK; -} - -int interface_jtag_add_reset(int req_trst, int req_srst) -{ - zy1000_reset(req_trst, req_srst); - return ERROR_OK; -} - -static int zy1000_jtag_add_clocks(int num_cycles, tap_state_t state, tap_state_t clockstate) -{ - /* num_cycles can be 0 */ - setCurrentState(clockstate); - - /* execute num_cycles, 32 at the time. */ - int i; - for (i = 0; i < num_cycles; i += 32) { - int num; - num = 32; - if (num_cycles-i < num) - num = num_cycles-i; - shiftValueInner(clockstate, clockstate, num, 0); - } - -#if !TEST_MANUAL() - /* finish in end_state */ - setCurrentState(state); -#else - tap_state_t t = TAP_IDLE; - /* test manual drive code on any target */ - int tms; - uint8_t tms_scan = tap_get_tms_path(t, state); - int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); - - for (i = 0; i < tms_count; i++) { - tms = (tms_scan >> i) & 1; - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, tms); - } - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, state); -#endif - - return ERROR_OK; -} - -int interface_jtag_add_runtest(int num_cycles, tap_state_t state) -{ - return zy1000_jtag_add_clocks(num_cycles, state, TAP_IDLE); -} - -int interface_jtag_add_clocks(int num_cycles) -{ - return zy1000_jtag_add_clocks(num_cycles, cmd_queue_cur_state, cmd_queue_cur_state); -} - -int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state) -{ - /*wait for the fifo to be empty*/ - waitIdle(); - - for (unsigned i = 0; i < num_bits; i++) { - int tms; - - if (((seq[i/8] >> (i % 8)) & 1) == 0) - tms = 0; - else - tms = 1; - - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, tms); - } - - waitIdle(); - if (state != TAP_INVALID) - ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, state); - else { - /* this would be normal if - * we are switching to SWD mode */ - } - return ERROR_OK; -} - -int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) -{ - int state_count; - int tms = 0; - - state_count = 0; - - tap_state_t cur_state = cmd_queue_cur_state; - - uint8_t seq[16]; - memset(seq, 0, sizeof(seq)); - assert(num_states < (int)((sizeof(seq) * 8))); - - while (num_states) { - if (tap_state_transition(cur_state, false) == path[state_count]) - tms = 0; - else if (tap_state_transition(cur_state, true) == path[state_count]) - tms = 1; - else { - LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", - tap_state_name(cur_state), tap_state_name(path[state_count])); - exit(-1); - } - - seq[state_count/8] = seq[state_count/8] | (tms << (state_count % 8)); - - cur_state = path[state_count]; - state_count++; - num_states--; - } - - return interface_add_tms_seq(state_count, seq, cur_state); -} - -static void jtag_pre_post_bits(struct jtag_tap *tap, int *pre, int *post) -{ - /* bypass bits before and after */ - int pre_bits = 0; - int post_bits = 0; - - bool found = false; - struct jtag_tap *cur_tap, *nextTap; - for (cur_tap = jtag_tap_next_enabled(NULL); cur_tap != NULL; cur_tap = nextTap) { - nextTap = jtag_tap_next_enabled(cur_tap); - if (cur_tap == tap) - found = true; - else { - if (found) - post_bits++; - else - pre_bits++; - } - } - *pre = pre_bits; - *post = post_bits; -} - -void embeddedice_write_dcc(struct jtag_tap *tap, - int reg_addr, - const uint8_t *buffer, - int little, - int count) -{ -#if 0 - int i; - for (i = 0; i < count; i++) { - embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, - little)); - buffer += 4; - } -#else - int pre_bits; - int post_bits; - jtag_pre_post_bits(tap, &pre_bits, &post_bits); - - if ((pre_bits > 32) || (post_bits + 6 > 32)) { - int i; - for (i = 0; i < count; i++) { - embeddedice_write_reg_inner(tap, reg_addr, - fast_target_buffer_get_u32(buffer, little)); - buffer += 4; - } - } else { - int i; - for (i = 0; i < count; i++) { - /* Fewer pokes means we get to use the FIFO more efficiently */ - shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, pre_bits, 0); - shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, - fast_target_buffer_get_u32(buffer, little)); - /* Danger! here we need to exit into the TAP_IDLE state to make - * DCC pick up this value. - */ - shiftValueInner(TAP_DRSHIFT, TAP_IDLE, 6 + post_bits, - (reg_addr | (1 << 5))); - buffer += 4; - } - } -#endif -} - -int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, - uint32_t opcode, - uint32_t *data, - size_t count) -{ - /* bypass bits before and after */ - int pre_bits; - int post_bits; - jtag_pre_post_bits(tap, &pre_bits, &post_bits); - post_bits += 2; - - if ((pre_bits > 32) || (post_bits > 32)) { - int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, - uint32_t opcode, uint32_t *data, size_t count); - return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count); - } else { - static const uint8_t zero; - - /* FIX!!!!!! the target_write_memory() API started this nasty problem - * with unaligned uint32_t * pointers... */ - const uint8_t *t = (const uint8_t *)data; - - while (--count > 0) { -#if 1 - /* Danger! This code doesn't update cmd_queue_cur_state, so - * invoking jtag_add_pathmove() before jtag_add_dr_scan() after - * this loop would fail! - */ - shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, pre_bits, 0); - - uint32_t value; - value = *t++; - value |= (*t++<<8); - value |= (*t++<<16); - value |= (*t++<<24); - - shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, value); - /* minimum 2 bits */ - shiftValueInner(TAP_DRSHIFT, TAP_DRPAUSE, post_bits, 0); - - /* copy & paste from arm11_dbgtap.c */ - /* TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_DRSELECT, - * TAP_DRCAPTURE, TAP_DRSHIFT */ - /* KLUDGE! we have to flush the fifo or the Nios CPU locks up. - * This is probably a bug in the Avalon bus(cross clocking bridge?) - * or in the jtag registers module. - */ - waitIdle(); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); - /* we don't have to wait for the queue to empty here */ - ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_DRSHIFT); - waitIdle(); -#else - static const tap_state_t arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay[] = { - TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE, - TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT - }; - - struct scan_field fields[2] = { - { .num_bits = 32, .out_value = t }, - { .num_bits = 2, .out_value = &zero }, - }; - t += 4; - - jtag_add_dr_scan(tap, - 2, - fields, - TAP_IDLE); - - jtag_add_pathmove(ARRAY_SIZE(arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay), - arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay); -#endif - } - - struct scan_field fields[2] = { - { .num_bits = 32, .out_value = t }, - { .num_bits = 2, .out_value = &zero }, - }; - - /* This will happen on the last iteration updating cmd_queue_cur_state - * so we don't have to track it during the common code path - */ - jtag_add_dr_scan(tap, - 2, - fields, - TAP_IDLE); - - return jtag_execute_queue(); - } -} - -static const struct command_registration zy1000_commands[] = { - { - .name = "power", - .handler = handle_power_command, - .mode = COMMAND_ANY, - .help = "Turn power switch to target on/off. " - "With no arguments, prints status.", - .usage = "('on'|'off)", - }, -#if !BUILD_ZY1000_MASTER - { - .name = "zy1000_server", - .mode = COMMAND_ANY, - .jim_handler = jim_zy1000_server, - .help = "Tcpip address for ZY1000 server.", - .usage = "address", - }, -#endif - { - .name = "powerstatus", - .mode = COMMAND_ANY, - .jim_handler = zylinjtag_Jim_Command_powerstatus, - .help = "Returns power status of target", - }, - COMMAND_REGISTRATION_DONE -}; - -#if !BUILD_ZY1000_MASTER - -static int tcp_ip = -1; - -/* Write large packets if we can */ -static size_t out_pos; -static uint8_t out_buffer[16384]; -static size_t in_pos; -static size_t in_write; -static uint8_t in_buffer[16384]; - -static bool flush_writes(void) -{ - bool ok = (write(tcp_ip, out_buffer, out_pos) == (int)out_pos); - out_pos = 0; - return ok; -} - -static bool writeLong(uint32_t l) -{ - int i; - for (i = 0; i < 4; i++) { - uint8_t c = (l >> (i*8))&0xff; - out_buffer[out_pos++] = c; - if (out_pos >= sizeof(out_buffer)) { - if (!flush_writes()) - return false; - } - } - return true; -} - -static bool readLong(uint32_t *out_data) -{ - uint32_t data = 0; - int i; - for (i = 0; i < 4; i++) { - uint8_t c; - if (in_pos == in_write) { - /* If we have some data that we can send, send them before - * we wait for more data - */ - if (out_pos > 0) { - if (!flush_writes()) - return false; - } - - /* read more */ - int t; - t = read(tcp_ip, in_buffer, sizeof(in_buffer)); - if (t < 1) - return false; - in_write = (size_t) t; - in_pos = 0; - } - c = in_buffer[in_pos++]; - - data |= (c << (i*8)); - } - *out_data = data; - return true; -} - -enum ZY1000_CMD { - ZY1000_CMD_POKE = 0x0, - ZY1000_CMD_PEEK = 0x8, - ZY1000_CMD_SLEEP = 0x1, - ZY1000_CMD_WAITIDLE = 2 -}; - -#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */ -#include <arpa/inet.h> /* for sockaddr_in and inet_addr() */ - -/* We initialize this late since we need to know the server address - * first. - */ -static void tcpip_open(void) -{ - if (tcp_ip >= 0) - return; - - struct sockaddr_in echoServAddr;/* Echo server address */ - - /* Create a reliable, stream socket using TCP */ - tcp_ip = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (tcp_ip < 0) { - fprintf(stderr, "Failed to connect to zy1000 server\n"); - exit(-1); - } - - /* Construct the server address structure */ - memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */ - echoServAddr.sin_family = AF_INET; /* Internet address family */ - echoServAddr.sin_addr.s_addr = inet_addr(tcp_server); /* Server IP address */ - echoServAddr.sin_port = htons(7777); /* Server port */ - - /* Establish the connection to the echo server */ - if (connect(tcp_ip, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) { - fprintf(stderr, "Failed to connect to zy1000 server\n"); - exit(-1); - } - - int flag = 1; - setsockopt(tcp_ip, /* socket affected */ - IPPROTO_TCP, /* set option at TCP level */ - TCP_NODELAY, /* name of option */ - (char *)&flag, /* the cast is historical cruft */ - sizeof(int)); /* length of option value */ - -} - -/* send a poke */ -void zy1000_tcpout(uint32_t address, uint32_t data) -{ - tcpip_open(); - if (!writeLong((ZY1000_CMD_POKE << 24) | address) || !writeLong(data)) { - fprintf(stderr, "Could not write to zy1000 server\n"); - exit(-1); - } -} - -/* By sending the wait to the server, we avoid a readback - * of status. Radically improves performance for this operation - * with long ping times. - */ -void waitIdle(void) -{ - tcpip_open(); - if (!writeLong((ZY1000_CMD_WAITIDLE << 24))) { - fprintf(stderr, "Could not write to zy1000 server\n"); - exit(-1); - } -} - -uint32_t zy1000_tcpin(uint32_t address) -{ - tcpip_open(); - - zy1000_flush_readqueue(); - - uint32_t data; - if (!writeLong((ZY1000_CMD_PEEK << 24) | address) || !readLong(&data)) { - fprintf(stderr, "Could not read from zy1000 server\n"); - exit(-1); - } - return data; -} - -int interface_jtag_add_sleep(uint32_t us) -{ - tcpip_open(); - if (!writeLong((ZY1000_CMD_SLEEP << 24)) || !writeLong(us)) { - fprintf(stderr, "Could not read from zy1000 server\n"); - exit(-1); - } - return ERROR_OK; -} - -/* queue a readback */ -#define readqueue_size 16384 -static struct { - uint8_t *dest; - int bits; -} readqueue[readqueue_size]; - -static int readqueue_pos; - -/* flush the readqueue, this means reading any data that - * we're expecting and store them into the final position - */ -void zy1000_flush_readqueue(void) -{ - if (readqueue_pos == 0) { - /* simply debugging by allowing easy breakpoints when there - * is something to do. */ - return; - } - int i; - tcpip_open(); - for (i = 0; i < readqueue_pos; i++) { - uint32_t value; - if (!readLong(&value)) { - fprintf(stderr, "Could not read from zy1000 server\n"); - exit(-1); - } - - uint8_t *in_value = readqueue[i].dest; - int k = readqueue[i].bits; - - /* we're shifting in data to MSB, shift data to be aligned for returning the value */ - value >>= 32-k; - - for (int l = 0; l < k; l += 8) - in_value[l/8] = (value >> l)&0xff; - } - readqueue_pos = 0; -} - -/* By queuing the callback's we avoid flushing the - * read queue until jtag_execute_queue(). This can - * reduce latency dramatically for cases where - * callbacks are used extensively. -*/ -#define callbackqueue_size 128 -static struct callbackentry { - jtag_callback_t callback; - jtag_callback_data_t data0; - jtag_callback_data_t data1; - jtag_callback_data_t data2; - jtag_callback_data_t data3; -} callbackqueue[callbackqueue_size]; - -static int callbackqueue_pos; - -void zy1000_jtag_add_callback4(jtag_callback_t callback, - jtag_callback_data_t data0, - jtag_callback_data_t data1, - jtag_callback_data_t data2, - jtag_callback_data_t data3) -{ - if (callbackqueue_pos >= callbackqueue_size) - zy1000_flush_callbackqueue(); - - callbackqueue[callbackqueue_pos].callback = callback; - callbackqueue[callbackqueue_pos].data0 = data0; - callbackqueue[callbackqueue_pos].data1 = data1; - callbackqueue[callbackqueue_pos].data2 = data2; - callbackqueue[callbackqueue_pos].data3 = data3; - callbackqueue_pos++; - - /* KLUDGE! - * make callbacks synchronous for now as minidriver requires callback - * to be synchronous. - * - * We can get away with making read and writes asynchronous so we - * don't completely kill performance. - */ - zy1000_flush_callbackqueue(); -} - -static int zy1000_jtag_convert_to_callback4(jtag_callback_data_t data0, - jtag_callback_data_t data1, - jtag_callback_data_t data2, - jtag_callback_data_t data3) -{ - ((jtag_callback1_t)data1)(data0); - return ERROR_OK; -} - -void zy1000_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0) -{ - zy1000_jtag_add_callback4(zy1000_jtag_convert_to_callback4, - data0, - (jtag_callback_data_t)callback, - 0, - 0); -} - -void zy1000_flush_callbackqueue(void) -{ - /* we have to flush the read queue so we have access to - the data the callbacks will use - */ - zy1000_flush_readqueue(); - int i; - for (i = 0; i < callbackqueue_pos; i++) { - struct callbackentry *entry = &callbackqueue[i]; - jtag_set_error(entry->callback(entry->data0, entry->data1, entry->data2, - entry->data3)); - } - callbackqueue_pos = 0; -} - -static void writeShiftValue(uint8_t *data, int bits) -{ - waitIdle(); - - if (!writeLong((ZY1000_CMD_PEEK << 24) | (ZY1000_JTAG_BASE + 0xc))) { - fprintf(stderr, "Could not read from zy1000 server\n"); - exit(-1); - } - - if (readqueue_pos >= readqueue_size) - zy1000_flush_readqueue(); - - readqueue[readqueue_pos].dest = data; - readqueue[readqueue_pos].bits = bits; - readqueue_pos++; - - /* KLUDGE!!! minidriver requires readqueue to be synchronous */ - zy1000_flush_readqueue(); -} - -#else - -static void writeShiftValue(uint8_t *data, int bits) -{ - uint32_t value; - waitIdle(); - ZY1000_PEEK(ZY1000_JTAG_BASE + 0xc, value); - VERBOSE(LOG_INFO("getShiftValue %08x", value)); - - /* data in, LSB to MSB */ - /* we're shifting in data to MSB, shift data to be aligned for returning the value */ - value >>= 32 - bits; - - for (int l = 0; l < bits; l += 8) - data[l/8] = (value >> l)&0xff; -} - -#endif - -#if BUILD_ZY1000_MASTER - -#ifdef WATCHDOG_BASE -/* If we connect to port 8888 we must send a char every 10s or the board resets itself */ -static void watchdog_server(cyg_addrword_t data) -{ - int so_reuseaddr_option = 1; - - int fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) { - LOG_ERROR("error creating socket: %s", strerror(errno)); - exit(-1); - } - - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &so_reuseaddr_option, - sizeof(int)); - - struct sockaddr_in sin; - unsigned int address_size; - address_size = sizeof(sin); - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = htons(8888); - - if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) == -1) { - LOG_ERROR("couldn't bind to socket: %s", strerror(errno)); - exit(-1); - } - - if (listen(fd, 1) == -1) { - LOG_ERROR("couldn't listen on socket: %s", strerror(errno)); - exit(-1); - } - - - for (;; ) { - int watchdog_ip = accept(fd, (struct sockaddr *) &sin, &address_size); - - /* Start watchdog, must be reset every 10 seconds. */ - HAL_WRITE_UINT32(WATCHDOG_BASE + 4, 4); - - if (watchdog_ip < 0) { - LOG_ERROR("couldn't open watchdog socket: %s", strerror(errno)); - exit(-1); - } - - int flag = 1; - setsockopt(watchdog_ip, /* socket affected */ - IPPROTO_TCP, /* set option at TCP level */ - TCP_NODELAY, /* name of option */ - (char *)&flag, /* the cast is historical cruft */ - sizeof(int)); /* length of option value */ - - - char buf; - for (;; ) { - if (read(watchdog_ip, &buf, 1) == 1) { - /* Reset timer */ - HAL_WRITE_UINT32(WATCHDOG_BASE + 8, 0x1234); - /* Echo so we can telnet in and see that resetting works */ - write(watchdog_ip, &buf, 1); - } else { - /* Stop tickling the watchdog, the CPU will reset in < 10 seconds - * now. - */ - return; - } - - } - - /* Never reached */ - } -} -#endif - -#endif - -#if BUILD_ZY1000_MASTER -int interface_jtag_add_sleep(uint32_t us) -{ - jtag_sleep(us); - return ERROR_OK; -} -#endif - -#if BUILD_ZY1000_MASTER -volatile void *zy1000_jtag_master; -#include <sys/mman.h> -#endif - -int zy1000_init(void) -{ -#if BUILD_ZY1000_MASTER - int fd = open("/dev/mem", O_RDWR | O_SYNC); - if (fd == -1) { - LOG_ERROR("No access to /dev/mem"); - return ERROR_FAIL; - } -#ifndef REGISTERS_BASE -#define REGISTERS_BASE 0x9002000 -#define REGISTERS_SPAN 128 -#endif - - zy1000_jtag_master = mmap(0, - REGISTERS_SPAN, - PROT_READ | PROT_WRITE, - MAP_SHARED, - fd, - REGISTERS_BASE); - - if (zy1000_jtag_master == (void *) -1) { - close(fd); - LOG_ERROR("No access to /dev/mem"); - return ERROR_FAIL; - } -#endif - - ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x30); /* Turn on LED1 & LED2 */ - - setPower(true); /* on by default */ - - /* deassert resets. Important to avoid infinite loop waiting for SRST to deassert */ - zy1000_reset(0, 0); - - return ERROR_OK; -} - -static struct jtag_interface zy1000_interface = { - .supported = DEBUG_CAP_TMS_SEQ, - .execute_queue = NULL, -}; - -struct adapter_driver zy1000_adapter_driver = { - .name = "ZY1000", - .transports = jtag_only, - .commands = zy1000_commands, - - .init = zy1000_init, - .quit = zy1000_quit, - .speed = zy1000_speed, - .khz = zy1000_khz, - .speed_div = zy1000_speed_div, - .power_dropout = zy1000_power_dropout, - .srst_asserted = zy1000_srst_asserted, - - .jtag_ops = &zy1000_interface, -}; diff --git a/src/main.c b/src/main.c index 83e60d8e0e..a36e6b55fa 100644 --- a/src/main.c +++ b/src/main.c @@ -1,25 +1,15 @@ +// 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" #endif #include "openocd.h" +#include "helper/system.h" /* This is the main entry for developer PC hosted OpenOCD. * diff --git a/src/openocd.c b/src/openocd.c index 886228425d..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 @@ -27,10 +16,9 @@ #endif #include "openocd.h" -#include <jtag/driver.h> +#include <jtag/adapter.h> #include <jtag/jtag.h> #include <transport/transport.h> -#include <helper/ioutil.h> #include <helper/util.h> #include <helper/configuration.h> #include <flash/nor/core.h> @@ -38,9 +26,12 @@ #include <pld/pld.h> #include <target/arm_cti.h> #include <target/arm_adi_v5.h> +#include <target/arm_tpiu_swo.h> +#include <rtt/rtt.h> #include <server/server.h> #include <server/gdb_server.h> +#include <server/rtt_server.h> #ifdef HAVE_STRINGS_H #include <strings.h> @@ -60,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 (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; - if (argc == 2) - str = Jim_GetString(argv[1], NULL); + 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, @@ -128,8 +118,10 @@ COMMAND_HANDLER(handle_init_command) initialized = 1; + bool save_poll_mask = jtag_poll_mask(); + retval = command_run_line(CMD_CTX, "target init"); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return ERROR_FAIL; retval = adapter_init(CMD_CTX); @@ -148,11 +140,11 @@ COMMAND_HANDLER(handle_init_command) command_context_mode(CMD_CTX, COMMAND_EXEC); retval = command_run_line(CMD_CTX, "transport init"); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return ERROR_FAIL; retval = command_run_line(CMD_CTX, "dap init"); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("Examining targets..."); @@ -171,11 +163,20 @@ COMMAND_HANDLER(handle_init_command) return ERROR_FAIL; command_context_mode(CMD_CTX, COMMAND_EXEC); + /* in COMMAND_EXEC, after target_examine(), only tpiu or only swo */ + 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; } @@ -192,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", @@ -230,10 +232,7 @@ static int openocd_register_commands(struct command_context *cmd_ctx) struct command_context *global_cmd_ctx; -/* NB! this fn can be invoked outside this file for non PC hosted builds - * NB! do not change to 'static'!!!! - */ -struct command_context *setup_command_handler(Jim_Interp *interp) +static struct command_context *setup_command_handler(Jim_Interp *interp) { log_init(); LOG_DEBUG("log_init: complete"); @@ -247,19 +246,21 @@ struct command_context *setup_command_handler(Jim_Interp *interp) &server_register_commands, &gdb_register_commands, &log_register_commands, + &rtt_server_register_commands, &transport_register_commands, - &interface_register_commands, + &adapter_register_commands, &target_register_commands, &flash_register_commands, &nand_register_commands, &pld_register_commands, &cti_register_commands, &dap_register_commands, + &arm_tpiu_swo_register_commands, NULL }; - for (unsigned i = 0; NULL != command_registrants[i]; i++) { + for (unsigned i = 0; command_registrants[i]; i++) { int retval = (*command_registrants[i])(cmd_ctx); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { command_done(cmd_ctx); return NULL; } @@ -298,12 +299,12 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct } ret = server_init(cmd_ctx); - if (ERROR_OK != ret) + if (ret != ERROR_OK) return ERROR_FAIL; if (init_at_startup) { ret = command_run_line(cmd_ctx, "init"); - if (ERROR_OK != ret) { + if (ret != ERROR_OK) { server_quit(); return ERROR_FAIL; } @@ -335,7 +336,7 @@ int openocd_main(int argc, char *argv[]) if (util_init(cmd_ctx) != ERROR_OK) return EXIT_FAILURE; - if (ioutil_init(cmd_ctx) != ERROR_OK) + if (rtt_init() != ERROR_OK) return EXIT_FAILURE; LOG_OUTPUT("For bug reports, read\n\t" @@ -352,13 +353,15 @@ int openocd_main(int argc, char *argv[]) flash_free_all_banks(); gdb_service_free(); + arm_tpiu_swo_cleanup_all(); server_free(); unregister_all_commands(cmd_ctx, NULL); + help_del_all_commands(cmd_ctx); /* free all DAP and CTI objects */ - dap_cleanup_all(); arm_cti_cleanup_all(); + dap_cleanup_all(); adapter_quit(); @@ -367,11 +370,14 @@ int openocd_main(int argc, char *argv[]) /* Shutdown commandline interface */ command_exit(cmd_ctx); + rtt_exit(); free_config(); - if (ERROR_FAIL == ret) + log_exit(); + + if (ret == ERROR_FAIL) return EXIT_FAILURE; - else if (ERROR_OK != ret) + else if (ret != ERROR_OK) exit_on_signal(ret); return ret; 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 ef7993c5d4..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,15 +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, }; @@ -42,69 +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 (ERROR_OK != retval) { - 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 (ERROR_OK != retval) { - 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 }; @@ -187,8 +319,7 @@ static int pld_init(struct command_context *cmd_ctx) if (!pld_devices) return ERROR_OK; - struct command *parent = command_find_in_context(cmd_ctx, "pld"); - return register_commands(cmd_ctx, parent, pld_exec_command_handlers); + return register_commands(cmd_ctx, "pld", pld_exec_command_handlers); } COMMAND_HANDLER(handle_pld_init_command) @@ -209,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 934a6807c3..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 == NULL) + 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]); - if (tap == NULL) { - command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); - return ERROR_OK; + 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; } - virtex2_info = malloc(sizeof(struct virtex2_pld_device)); + 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[3]); + return ERROR_FAIL; + } + + 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 f83d8942d3..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,8 +13,7 @@ #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, uint32_t *buffer_length, uint8_t **buffer) @@ -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 == NULL) { + 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 1a35c3be22..f443bf70eb 100644 --- a/src/pld/xilinx_bit.h +++ b/src/pld/xilinx_bit.h @@ -1,24 +1,15 @@ +/* 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 #define OPENOCD_PLD_XILINX_BIT_H +#include "helper/types.h" + struct xilinx_bit_file { uint8_t unknown_header[13]; uint8_t *source_file; @@ -31,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 9a51974c51..e8df030aad 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 @@ -31,13 +20,14 @@ #include "target/armv7m.h" #include "target/cortex_m.h" - - #define FREERTOS_MAX_PRIORITIES 63 -#define FreeRTOS_STRUCT(int_type, ptr_type, list_prev_offset) +/* FIXME: none of the _width parameters are actually observed properly! + * you WILL need to edit more if you actually attempt to target a 8/16/64 + * bit target! + */ -struct FreeRTOS_params { +struct freertos_params { const char *target_name; const unsigned char thread_count_width; const unsigned char pointer_width; @@ -52,7 +42,7 @@ struct FreeRTOS_params { const struct rtos_register_stacking *stacking_info_cm4f_fpu; }; -static const struct FreeRTOS_params FreeRTOS_params_list[] = { +static const struct freertos_params freertos_params_list[] = { { "cortex_m", /* target_name */ 4, /* thread_count_width; */ @@ -63,9 +53,9 @@ static const struct FreeRTOS_params FreeRTOS_params_list[] = { 12, /* list_elem_content_offset */ 0, /* thread_stack_offset; */ 52, /* thread_name_offset; */ - &rtos_standard_Cortex_M3_stacking, /* stacking_info */ - &rtos_standard_Cortex_M4F_stacking, - &rtos_standard_Cortex_M4F_FPU_stacking, + &rtos_standard_cortex_m3_stacking, /* stacking_info */ + &rtos_standard_cortex_m4f_stacking, + &rtos_standard_cortex_m4f_fpu_stacking, }, { "hla_target", /* target_name */ @@ -77,57 +67,42 @@ static const struct FreeRTOS_params FreeRTOS_params_list[] = { 12, /* list_elem_content_offset */ 0, /* thread_stack_offset; */ 52, /* thread_name_offset; */ - &rtos_standard_Cortex_M3_stacking, /* stacking_info */ - &rtos_standard_Cortex_M4F_stacking, - &rtos_standard_Cortex_M4F_FPU_stacking, - }, - { - "nds32_v3", /* target_name */ - 4, /* thread_count_width; */ - 4, /* pointer_width; */ - 16, /* list_next_offset; */ - 20, /* list_width; */ - 8, /* list_elem_next_offset; */ - 12, /* list_elem_content_offset */ - 0, /* thread_stack_offset; */ - 52, /* thread_name_offset; */ - &rtos_standard_NDS32_N1068_stacking, /* stacking_info */ - &rtos_standard_Cortex_M4F_stacking, - &rtos_standard_Cortex_M4F_FPU_stacking, + &rtos_standard_cortex_m3_stacking, /* stacking_info */ + &rtos_standard_cortex_m4f_stacking, + &rtos_standard_cortex_m4f_fpu_stacking, }, }; -#define FREERTOS_NUM_PARAMS ((int)(sizeof(FreeRTOS_params_list)/sizeof(struct FreeRTOS_params))) - -static bool FreeRTOS_detect_rtos(struct target *target); -static int FreeRTOS_create(struct target *target); -static int FreeRTOS_update_threads(struct rtos *rtos); -static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, +static bool freertos_detect_rtos(struct target *target); +static int freertos_create(struct target *target); +static int freertos_update_threads(struct rtos *rtos); +static int freertos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); -static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +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, - .create = FreeRTOS_create, - .update_threads = FreeRTOS_update_threads, - .get_thread_reg_list = FreeRTOS_get_thread_reg_list, - .get_symbol_list_to_lookup = FreeRTOS_get_symbol_list_to_lookup, + .detect_rtos = freertos_detect_rtos, + .create = freertos_create, + .update_threads = freertos_update_threads, + .get_thread_reg_list = freertos_get_thread_reg_list, + .get_symbol_list_to_lookup = freertos_get_symbol_list_to_lookup, }; -enum FreeRTOS_symbol_values { - FreeRTOS_VAL_pxCurrentTCB = 0, - FreeRTOS_VAL_pxReadyTasksLists = 1, - FreeRTOS_VAL_xDelayedTaskList1 = 2, - FreeRTOS_VAL_xDelayedTaskList2 = 3, - FreeRTOS_VAL_pxDelayedTaskList = 4, - FreeRTOS_VAL_pxOverflowDelayedTaskList = 5, - FreeRTOS_VAL_xPendingReadyList = 6, - FreeRTOS_VAL_xTasksWaitingTermination = 7, - FreeRTOS_VAL_xSuspendedTaskList = 8, - FreeRTOS_VAL_uxCurrentNumberOfTasks = 9, - FreeRTOS_VAL_uxTopUsedPriority = 10, +enum freertos_symbol_values { + FREERTOS_VAL_PX_CURRENT_TCB = 0, + FREERTOS_VAL_PX_READY_TASKS_LISTS = 1, + FREERTOS_VAL_X_DELAYED_TASK_LIST1 = 2, + FREERTOS_VAL_X_DELAYED_TASK_LIST2 = 3, + FREERTOS_VAL_PX_DELAYED_TASK_LIST = 4, + FREERTOS_VAL_PX_OVERFLOW_DELAYED_TASK_LIST = 5, + FREERTOS_VAL_X_PENDING_READY_LIST = 6, + FREERTOS_VAL_X_TASKS_WAITING_TERMINATION = 7, + 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 { @@ -135,7 +110,7 @@ struct symbols { bool optional; }; -static const struct symbols FreeRTOS_symbol_list[] = { +static const struct symbols freertos_symbol_list[] = { { "pxCurrentTCB", false }, { "pxReadyTasksLists", false }, { "xDelayedTaskList1", false }, @@ -147,6 +122,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 } }; @@ -155,34 +131,33 @@ static const struct symbols FreeRTOS_symbol_list[] = { /* may be problems reading if sizes are not 32 bit long integers. */ /* test mallocs for failure */ -static int FreeRTOS_update_threads(struct rtos *rtos) +static int freertos_update_threads(struct rtos *rtos) { int retval; - int tasks_found = 0; - const struct FreeRTOS_params *param; + unsigned int tasks_found = 0; + const struct freertos_params *param; - if (rtos->rtos_specific_params == NULL) + if (!rtos->rtos_specific_params) return -1; - param = (const struct FreeRTOS_params *) rtos->rtos_specific_params; + param = (const struct freertos_params *) rtos->rtos_specific_params; - if (rtos->symbols == NULL) { + if (!rtos->symbols) { LOG_ERROR("No symbols for FreeRTOS"); return -3; } - if (rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address == 0) { + if (rtos->symbols[FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS].address == 0) { LOG_ERROR("Don't have the number of threads in FreeRTOS"); return -2; } - int thread_list_size = 0; - retval = target_read_buffer(rtos->target, - rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address, - param->thread_count_width, - (uint8_t *)&thread_list_size); - LOG_DEBUG("FreeRTOS: Read uxCurrentNumberOfTasks at 0x%" PRIx64 ", value %d\r\n", - rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address, + uint32_t thread_list_size = 0; + retval = target_read_u32(rtos->target, + rtos->symbols[FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS].address, + &thread_list_size); + LOG_DEBUG("FreeRTOS: Read uxCurrentNumberOfTasks at 0x%" PRIx64 ", value %" PRIu32, + rtos->symbols[FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS].address, thread_list_size); if (retval != ERROR_OK) { @@ -194,19 +169,33 @@ static int FreeRTOS_update_threads(struct rtos *rtos) rtos_free_threadlist(rtos); /* read the current thread */ - retval = target_read_buffer(rtos->target, - rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address, - param->pointer_width, - (uint8_t *)&rtos->current_thread); + uint32_t pointer_casts_are_bad; + retval = target_read_u32(rtos->target, + rtos->symbols[FREERTOS_VAL_PX_CURRENT_TCB].address, + &pointer_casts_are_bad); 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 "\r\n", - rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address, + rtos->current_thread = pointer_casts_are_bad; + LOG_DEBUG("FreeRTOS: Read pxCurrentTCB at 0x%" PRIx64 ", value 0x%" PRIx64, + rtos->symbols[FREERTOS_VAL_PX_CURRENT_TCB].address, rtos->current_thread); - if ((thread_list_size == 0) || (rtos->current_thread == 0)) { + /* read scheduler running */ + uint32_t scheduler_running; + retval = target_read_u32(rtos->target, + rtos->symbols[FREERTOS_VAL_X_SCHEDULER_RUNNING].address, + &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%" PRIx32, + rtos->symbols[FREERTOS_VAL_X_SCHEDULER_RUNNING].address, + scheduler_running); + + if ((thread_list_size == 0) || (rtos->current_thread == 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 */ @@ -219,7 +208,8 @@ static int FreeRTOS_update_threads(struct rtos *rtos) LOG_ERROR("Error allocating memory for %d threads", thread_list_size); return ERROR_FAIL; } - rtos->thread_details->threadid = 1; + rtos->current_thread = 1; + 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)); @@ -240,24 +230,21 @@ static int FreeRTOS_update_threads(struct rtos *rtos) } /* Find out how many lists are needed to be read from pxReadyTasksLists, */ - if (rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address == 0) { + if (rtos->symbols[FREERTOS_VAL_UX_TOP_USED_PRIORITY].address == 0) { LOG_ERROR("FreeRTOS: uxTopUsedPriority is not defined, consult the OpenOCD manual for a work-around"); return ERROR_FAIL; } - uint64_t top_used_priority = 0; - /* FIXME: endianness error on almost all target_read_buffer(), see also - * other rtoses */ - retval = target_read_buffer(rtos->target, - rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address, - param->pointer_width, - (uint8_t *)&top_used_priority); + uint32_t top_used_priority = 0; + retval = target_read_u32(rtos->target, + rtos->symbols[FREERTOS_VAL_UX_TOP_USED_PRIORITY].address, + &top_used_priority); if (retval != ERROR_OK) return retval; - LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRIu64 "\r\n", - rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address, + LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRIu32, + rtos->symbols[FREERTOS_VAL_UX_TOP_USED_PRIORITY].address, top_used_priority); if (top_used_priority > FREERTOS_MAX_PRIORITIES) { - LOG_ERROR("FreeRTOS top used priority is unreasonably big, not proceeding: %" PRIu64, + LOG_ERROR("FreeRTOS top used priority is unreasonably big, not proceeding: %" PRIu32, top_used_priority); return ERROR_FAIL; } @@ -278,66 +265,63 @@ static int FreeRTOS_update_threads(struct rtos *rtos) unsigned int num_lists; for (num_lists = 0; num_lists < config_max_priorities; num_lists++) - list_of_lists[num_lists] = rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address + + list_of_lists[num_lists] = rtos->symbols[FREERTOS_VAL_PX_READY_TASKS_LISTS].address + num_lists * param->list_width; - list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList1].address; - list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList2].address; - list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xPendingReadyList].address; - list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xSuspendedTaskList].address; - list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xTasksWaitingTermination].address; + list_of_lists[num_lists++] = rtos->symbols[FREERTOS_VAL_X_DELAYED_TASK_LIST1].address; + list_of_lists[num_lists++] = rtos->symbols[FREERTOS_VAL_X_DELAYED_TASK_LIST2].address; + list_of_lists[num_lists++] = rtos->symbols[FREERTOS_VAL_X_PENDING_READY_LIST].address; + 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; for (unsigned int i = 0; i < num_lists; i++) { if (list_of_lists[i] == 0) continue; /* Read the number of threads in this list */ - int64_t list_thread_count = 0; - retval = target_read_buffer(rtos->target, + uint32_t list_thread_count = 0; + retval = target_read_u32(rtos->target, list_of_lists[i], - param->thread_count_width, - (uint8_t *)&list_thread_count); + &list_thread_count); if (retval != ERROR_OK) { LOG_ERROR("Error reading number of threads in FreeRTOS thread list"); free(list_of_lists); return retval; } - LOG_DEBUG("FreeRTOS: Read thread count for list %u at 0x%" PRIx64 ", value %" PRId64 "\r\n", + LOG_DEBUG("FreeRTOS: Read thread count for list %u at 0x%" PRIx64 ", value %" PRIu32, i, list_of_lists[i], list_thread_count); if (list_thread_count == 0) continue; /* Read the location of first list item */ - uint64_t prev_list_elem_ptr = -1; - uint64_t list_elem_ptr = 0; - retval = target_read_buffer(rtos->target, + uint32_t prev_list_elem_ptr = -1; + uint32_t list_elem_ptr = 0; + retval = target_read_u32(rtos->target, list_of_lists[i] + param->list_next_offset, - param->pointer_width, - (uint8_t *)&list_elem_ptr); + &list_elem_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading first thread item location in FreeRTOS thread list"); free(list_of_lists); return retval; } - LOG_DEBUG("FreeRTOS: Read first item for list %u at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n", + LOG_DEBUG("FreeRTOS: Read first item for list %u at 0x%" PRIx64 ", value 0x%" PRIx32, i, list_of_lists[i] + param->list_next_offset, list_elem_ptr); while ((list_thread_count > 0) && (list_elem_ptr != 0) && (list_elem_ptr != prev_list_elem_ptr) && (tasks_found < thread_list_size)) { /* Get the location of the thread structure. */ - rtos->thread_details[tasks_found].threadid = 0; - retval = target_read_buffer(rtos->target, + retval = target_read_u32(rtos->target, list_elem_ptr + param->list_elem_content_offset, - param->pointer_width, - (uint8_t *)&(rtos->thread_details[tasks_found].threadid)); + &pointer_casts_are_bad); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread list item object in FreeRTOS thread list"); free(list_of_lists); return retval; } - LOG_DEBUG("FreeRTOS: Read Thread ID at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n", + rtos->thread_details[tasks_found].threadid = pointer_casts_are_bad; + LOG_DEBUG("FreeRTOS: Read Thread ID at 0x%" PRIx32 ", value 0x%" PRIx64, list_elem_ptr + param->list_elem_content_offset, rtos->thread_details[tasks_found].threadid); @@ -357,7 +341,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos) return retval; } tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00'; - LOG_DEBUG("FreeRTOS: Read Thread Name at 0x%" PRIx64 ", value \"%s\"\r\n", + LOG_DEBUG("FreeRTOS: Read Thread Name at 0x%" PRIx64 ", value '%s'", rtos->thread_details[tasks_found].threadid + param->thread_name_offset, tmp_str); @@ -380,57 +364,57 @@ 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; - retval = target_read_buffer(rtos->target, + retval = target_read_u32(rtos->target, prev_list_elem_ptr + param->list_elem_next_offset, - param->pointer_width, - (uint8_t *)&list_elem_ptr); + &list_elem_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading next thread item location in FreeRTOS thread list"); free(list_of_lists); return retval; } - LOG_DEBUG("FreeRTOS: Read next thread location at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n", + LOG_DEBUG("FreeRTOS: Read next thread location at 0x%" PRIx32 ", value 0x%" PRIx32, prev_list_elem_ptr + param->list_elem_next_offset, list_elem_ptr); } } free(list_of_lists); - rtos->thread_count = tasks_found; return 0; } -static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, +static int freertos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { int retval; - const struct FreeRTOS_params *param; + const struct freertos_params *param; int64_t stack_ptr = 0; - if (rtos == NULL) + if (!rtos) return -1; if (thread_id == 0) return -2; - if (rtos->rtos_specific_params == NULL) + if (!rtos->rtos_specific_params) return -1; - param = (const struct FreeRTOS_params *) rtos->rtos_specific_params; + param = (const struct freertos_params *) rtos->rtos_specific_params; /* Read the stack pointer */ - retval = target_read_buffer(rtos->target, + uint32_t pointer_casts_are_bad; + retval = target_read_u32(rtos->target, thread_id + param->thread_stack_offset, - param->pointer_width, - (uint8_t *)&stack_ptr); + &pointer_casts_are_bad); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack frame from FreeRTOS thread"); return retval; } - LOG_DEBUG("FreeRTOS: Read stack pointer at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n", + stack_ptr = pointer_casts_are_bad; + LOG_DEBUG("FreeRTOS: Read stack pointer at 0x%" PRIx64 ", value 0x%" PRIx64, thread_id + param->thread_stack_offset, stack_ptr); @@ -438,7 +422,8 @@ static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, 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; @@ -458,16 +443,15 @@ static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, if (cm4_fpu_enabled == 1) { /* Read the LR to decide between stacking with or without FPU */ - uint32_t LR_svc = 0; - retval = target_read_buffer(rtos->target, + uint32_t lr_svc = 0; + retval = target_read_u32(rtos->target, stack_ptr + 0x20, - param->pointer_width, - (uint8_t *)&LR_svc); + &lr_svc); if (retval != ERROR_OK) { - LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n"); + LOG_OUTPUT("Error reading stack frame from FreeRTOS thread"); return retval; } - if ((LR_svc & 0x10) == 0) + if ((lr_svc & 0x10) == 0) return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs); else return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, reg_list, num_regs); @@ -475,15 +459,15 @@ static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, reg_list, num_regs); } -static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int freertos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; *symbol_list = calloc( - ARRAY_SIZE(FreeRTOS_symbol_list), sizeof(symbol_table_elem_t)); + ARRAY_SIZE(freertos_symbol_list), sizeof(struct symbol_table_elem)); - for (i = 0; i < ARRAY_SIZE(FreeRTOS_symbol_list); i++) { - (*symbol_list)[i].symbol_name = FreeRTOS_symbol_list[i].name; - (*symbol_list)[i].optional = FreeRTOS_symbol_list[i].optional; + for (i = 0; i < ARRAY_SIZE(freertos_symbol_list); i++) { + (*symbol_list)[i].symbol_name = freertos_symbol_list[i].name; + (*symbol_list)[i].optional = freertos_symbol_list[i].optional; } return 0; @@ -491,26 +475,26 @@ static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[] #if 0 -static int FreeRTOS_set_current_thread(struct rtos *rtos, threadid_t thread_id) +static int freertos_set_current_thread(struct rtos *rtos, threadid_t thread_id) { return 0; } -static int FreeRTOS_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_id, char **info) +static int freertos_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_id, char **info) { int retval; - const struct FreeRTOS_params *param; + const struct freertos_params *param; - if (rtos == NULL) + if (!rtos) return -1; if (thread_id == 0) return -2; - if (rtos->rtos_specific_params == NULL) + if (!rtos->rtos_specific_params) return -3; - param = (const struct FreeRTOS_params *) rtos->rtos_specific_params; + param = (const struct freertos_params *) rtos->rtos_specific_params; #define FREERTOS_THREAD_NAME_STR_SIZE (200) char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE]; @@ -536,28 +520,24 @@ static int FreeRTOS_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_i #endif -static bool FreeRTOS_detect_rtos(struct target *target) +static bool freertos_detect_rtos(struct target *target) { - if ((target->rtos->symbols != NULL) && - (target->rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address != 0)) { + if ((target->rtos->symbols) && + (target->rtos->symbols[FREERTOS_VAL_PX_READY_TASKS_LISTS].address != 0)) { /* looks like FreeRTOS */ return true; } return false; } -static int FreeRTOS_create(struct target *target) +static int freertos_create(struct target *target) { - int i = 0; - while ((i < FREERTOS_NUM_PARAMS) && - (0 != strcmp(FreeRTOS_params_list[i].target_name, target->type->name))) { - i++; - } - if (i >= FREERTOS_NUM_PARAMS) { - LOG_ERROR("Could not find target in FreeRTOS compatibility list"); - return -1; - } + for (unsigned int i = 0; i < ARRAY_SIZE(freertos_params_list); i++) + if (strcmp(freertos_params_list[i].target_name, target->type->name) == 0) { + target->rtos->rtos_specific_params = (void *)&freertos_params_list[i]; + return 0; + } - target->rtos->rtos_specific_params = (void *) &FreeRTOS_params_list[i]; - return 0; + LOG_ERROR("Could not find target in FreeRTOS compatibility list"); + return -1; } diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am index de54596cd4..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,7 +21,9 @@ 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 \ %D%/rtos.h \ %D%/rtos_standard_stackings.h \ @@ -29,11 +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 - -%C%_librtos_la_CFLAGS = $(AM_CFLAGS) - -if IS_MINGW -# FD_* macros are sloppy with their signs on MinGW32 platform -%C%_librtos_la_CFLAGS += -Wno-sign-compare -endif + %D%/rtos_nuttx_stackings.h diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c index 302641bae4..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 @@ -35,20 +24,20 @@ static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const st static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id); static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id); -static bool ThreadX_detect_rtos(struct target *target); -static int ThreadX_create(struct target *target); -static int ThreadX_update_threads(struct rtos *rtos); -static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); -static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +static bool threadx_detect_rtos(struct target *target); +static int threadx_create(struct target *target); +static int threadx_update_threads(struct rtos *rtos); +static int threadx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); +static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); -struct ThreadX_thread_state { +struct threadx_thread_state { int value; const char *desc; }; -static const struct ThreadX_thread_state ThreadX_thread_states[] = { +static const struct threadx_thread_state threadx_thread_states[] = { { 0, "Ready" }, { 1, "Completed" }, { 2, "Terminated" }, @@ -65,7 +54,7 @@ static const struct ThreadX_thread_state ThreadX_thread_states[] = { { 13, "Waiting - Mutex" }, }; -#define THREADX_NUM_STATES (sizeof(ThreadX_thread_states)/sizeof(struct ThreadX_thread_state)) +#define THREADX_NUM_STATES ARRAY_SIZE(threadx_thread_states) #define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4) static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited[] = { @@ -110,24 +99,22 @@ static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_i { 16, 0x04, 32 }, /* xPSR */ }; -const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = { +static const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = { { - ARM926EJS_REGISTERS_SIZE_SOLICITED, /* stack_registers_size */ - -1, /* stack_growth_direction */ - 17, /* num_output_registers */ - NULL, /* stack_alignment */ - rtos_threadx_arm926ejs_stack_offsets_solicited /* register_offsets */ + .stack_registers_size = ARM926EJS_REGISTERS_SIZE_SOLICITED, + .stack_growth_direction = -1, + .num_output_registers = 17, + .register_offsets = rtos_threadx_arm926ejs_stack_offsets_solicited }, { - ARM926EJS_REGISTERS_SIZE_INTERRUPT, /* stack_registers_size */ - -1, /* stack_growth_direction */ - 17, /* num_output_registers */ - NULL, /* stack_alignment */ - rtos_threadx_arm926ejs_stack_offsets_interrupt /* register_offsets */ + .stack_registers_size = ARM926EJS_REGISTERS_SIZE_INTERRUPT, + .stack_growth_direction = -1, + .num_output_registers = 17, + .register_offsets = rtos_threadx_arm926ejs_stack_offsets_interrupt }, }; -struct ThreadX_params { +struct threadx_params { const char *target_name; unsigned char pointer_width; unsigned char thread_stack_offset; @@ -140,7 +127,7 @@ struct ThreadX_params { int (*fn_is_thread_id_valid)(const struct rtos *rtos, int64_t thread_id); }; -static const struct ThreadX_params ThreadX_params_list[] = { +static const struct threadx_params threadx_params_list[] = { { "cortex_m", /* target_name */ 4, /* pointer_width; */ @@ -148,7 +135,7 @@ static const struct ThreadX_params ThreadX_params_list[] = { 40, /* thread_name_offset; */ 48, /* thread_state_offset; */ 136, /* thread_next_offset */ - &rtos_standard_Cortex_M3_stacking, /* stacking_info */ + &rtos_standard_cortex_m3_stacking, /* stacking_info */ 1, /* stacking_info_nb */ NULL, /* fn_get_stacking_info */ NULL, /* fn_is_thread_id_valid */ @@ -160,7 +147,7 @@ static const struct ThreadX_params ThreadX_params_list[] = { 40, /* thread_name_offset; */ 48, /* thread_state_offset; */ 136, /* thread_next_offset */ - &rtos_standard_Cortex_R4_stacking, /* stacking_info */ + &rtos_standard_cortex_r4_stacking, /* stacking_info */ 1, /* stacking_info_nb */ NULL, /* fn_get_stacking_info */ NULL, /* fn_is_thread_id_valid */ @@ -177,38 +164,48 @@ static const struct ThreadX_params ThreadX_params_list[] = { get_stacking_info_arm926ejs, /* fn_get_stacking_info */ is_thread_id_valid_arm926ejs, /* fn_is_thread_id_valid */ }, + { + "hla_target", /* target_name */ + 4, /* pointer_width; */ + 8, /* thread_stack_offset; */ + 40, /* thread_name_offset; */ + 48, /* thread_state_offset; */ + 136, /* thread_next_offset */ + &rtos_standard_cortex_m3_stacking, /* stacking_info */ + 1, /* stacking_info_nb */ + NULL, /* fn_get_stacking_info */ + NULL, /* fn_is_thread_id_valid */ + }, }; -#define THREADX_NUM_PARAMS ((int)(sizeof(ThreadX_params_list)/sizeof(struct ThreadX_params))) - -enum ThreadX_symbol_values { - ThreadX_VAL_tx_thread_current_ptr = 0, - ThreadX_VAL_tx_thread_created_ptr = 1, - ThreadX_VAL_tx_thread_created_count = 2, +enum threadx_symbol_values { + THREADX_VAL_TX_THREAD_CURRENT_PTR = 0, + THREADX_VAL_TX_THREAD_CREATED_PTR = 1, + THREADX_VAL_TX_THREAD_CREATED_COUNT = 2, }; -static const char * const ThreadX_symbol_list[] = { +static const char * const threadx_symbol_list[] = { "_tx_thread_current_ptr", "_tx_thread_created_ptr", "_tx_thread_created_count", NULL }; -const struct rtos_type ThreadX_rtos = { +const struct rtos_type threadx_rtos = { .name = "ThreadX", - .detect_rtos = ThreadX_detect_rtos, - .create = ThreadX_create, - .update_threads = ThreadX_update_threads, - .get_thread_reg_list = ThreadX_get_thread_reg_list, - .get_symbol_list_to_lookup = ThreadX_get_symbol_list_to_lookup, + .detect_rtos = threadx_detect_rtos, + .create = threadx_create, + .update_threads = threadx_update_threads, + .get_thread_reg_list = threadx_get_thread_reg_list, + .get_symbol_list_to_lookup = threadx_get_symbol_list_to_lookup, }; static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr) { - const struct ThreadX_params *param = (const struct ThreadX_params *) rtos->rtos_specific_params; + const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params; - if (param->fn_get_stacking_info != NULL) + if (param->fn_get_stacking_info) return param->fn_get_stacking_info(rtos, stack_ptr); return param->stacking_info + 0; @@ -216,14 +213,14 @@ static const struct rtos_register_stacking *get_stacking_info(const struct rtos static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id) { - const struct ThreadX_params *param; + const struct threadx_params *param; - if (rtos->rtos_specific_params == NULL) + if (!rtos->rtos_specific_params) return 0; /* invalid */ - param = (const struct ThreadX_params *) rtos->rtos_specific_params; + param = (const struct threadx_params *) rtos->rtos_specific_params; - if (param->fn_is_thread_id_valid != NULL) + if (param->fn_is_thread_id_valid) return param->fn_is_thread_id_valid(rtos, thread_id); return (thread_id != 0); @@ -231,7 +228,7 @@ static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id) static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr) { - const struct ThreadX_params *param = (const struct ThreadX_params *) rtos->rtos_specific_params; + const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params; int retval; uint32_t flag; @@ -258,34 +255,34 @@ static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_ return (thread_id != 0 && thread_id != 1); } -static int ThreadX_update_threads(struct rtos *rtos) +static int threadx_update_threads(struct rtos *rtos) { int retval; int tasks_found = 0; int thread_list_size = 0; - const struct ThreadX_params *param; + const struct threadx_params *param; - if (rtos == NULL) + if (!rtos) return -1; - if (rtos->rtos_specific_params == NULL) + if (!rtos->rtos_specific_params) return -3; - param = (const struct ThreadX_params *) rtos->rtos_specific_params; + param = (const struct threadx_params *) rtos->rtos_specific_params; - if (rtos->symbols == NULL) { + if (!rtos->symbols) { LOG_ERROR("No symbols for ThreadX"); return -4; } - if (rtos->symbols[ThreadX_VAL_tx_thread_created_count].address == 0) { + if (rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address == 0) { LOG_ERROR("Don't have the number of threads in ThreadX"); return -2; } /* read the number of threads */ retval = target_read_buffer(rtos->target, - rtos->symbols[ThreadX_VAL_tx_thread_created_count].address, + rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address, 4, (uint8_t *)&thread_list_size); @@ -299,7 +296,7 @@ static int ThreadX_update_threads(struct rtos *rtos) /* read the current thread id */ retval = target_read_buffer(rtos->target, - rtos->symbols[ThreadX_VAL_tx_thread_current_ptr].address, + rtos->symbols[THREADX_VAL_TX_THREAD_CURRENT_PTR].address, 4, (uint8_t *)&rtos->current_thread); @@ -323,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; @@ -336,7 +339,7 @@ static int ThreadX_update_threads(struct rtos *rtos) /* Read the pointer to the first thread */ int64_t thread_ptr = 0; retval = target_read_buffer(rtos->target, - rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address, + rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address, param->pointer_width, (uint8_t *)&thread_ptr); if (retval != ERROR_OK) { @@ -367,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"); @@ -397,13 +405,13 @@ static int ThreadX_update_threads(struct rtos *rtos) } for (i = 0; (i < THREADX_NUM_STATES) && - (ThreadX_thread_states[i].value != thread_status); i++) { + (threadx_thread_states[i].value != thread_status); i++) { /* empty */ } const char *state_desc; if (i < THREADX_NUM_STATES) - state_desc = ThreadX_thread_states[i].desc; + state_desc = threadx_thread_states[i].desc; else state_desc = "Unknown state"; @@ -433,22 +441,22 @@ static int ThreadX_update_threads(struct rtos *rtos) return 0; } -static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, +static int threadx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { int retval; - const struct ThreadX_params *param; + const struct threadx_params *param; - if (rtos == NULL) + if (!rtos) return -1; if (!is_thread_id_valid(rtos, thread_id)) return -2; - if (rtos->rtos_specific_params == NULL) + if (!rtos->rtos_specific_params) return -3; - param = (const struct ThreadX_params *) rtos->rtos_specific_params; + param = (const struct threadx_params *) rtos->rtos_specific_params; /* Read the stack pointer */ int64_t stack_ptr = 0; @@ -471,7 +479,7 @@ static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, const struct rtos_register_stacking *stacking_info = get_stacking_info(rtos, stack_ptr); - if (stacking_info == NULL) { + if (!stacking_info) { LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64, (uint64_t)thread_id); return -6; } @@ -479,22 +487,22 @@ static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs); } -static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; *symbol_list = calloc( - ARRAY_SIZE(ThreadX_symbol_list), sizeof(symbol_table_elem_t)); + ARRAY_SIZE(threadx_symbol_list), sizeof(struct symbol_table_elem)); - for (i = 0; i < ARRAY_SIZE(ThreadX_symbol_list); i++) - (*symbol_list)[i].symbol_name = ThreadX_symbol_list[i]; + for (i = 0; i < ARRAY_SIZE(threadx_symbol_list); i++) + (*symbol_list)[i].symbol_name = threadx_symbol_list[i]; return 0; } -static bool ThreadX_detect_rtos(struct target *target) +static bool threadx_detect_rtos(struct target *target) { - if ((target->rtos->symbols != NULL) && - (target->rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address != 0)) { + if ((target->rtos->symbols) && + (target->rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address != 0)) { /* looks like ThreadX */ return true; } @@ -503,12 +511,12 @@ static bool ThreadX_detect_rtos(struct target *target) #if 0 -static int ThreadX_set_current_thread(struct rtos *rtos, threadid_t thread_id) +static int threadx_set_current_thread(struct rtos *rtos, threadid_t thread_id) { return 0; } -static int ThreadX_get_thread_detail(struct rtos *rtos, +static int threadx_get_thread_detail(struct rtos *rtos, threadid_t thread_id, struct thread_detail *detail) { @@ -518,20 +526,20 @@ static int ThreadX_get_thread_detail(struct rtos *rtos, #define THREADX_THREAD_NAME_STR_SIZE (200) char tmp_str[THREADX_THREAD_NAME_STR_SIZE]; - const struct ThreadX_params *param; + const struct threadx_params *param; - if (rtos == NULL) + if (!rtos) return -1; if (thread_id == 0) return -2; - if (rtos->rtos_specific_params == NULL) + if (!rtos->rtos_specific_params) return -3; - param = (const struct ThreadX_params *) rtos->rtos_specific_params; + param = (const struct threadx_params *) rtos->rtos_specific_params; - if (rtos->symbols == NULL) { + if (!rtos->symbols) { LOG_ERROR("No symbols for ThreadX"); return -3; } @@ -578,13 +586,13 @@ static int ThreadX_get_thread_detail(struct rtos *rtos, } for (i = 0; (i < THREADX_NUM_STATES) && - (ThreadX_thread_states[i].value != thread_status); i++) { + (threadx_thread_states[i].value != thread_status); i++) { /* empty */ } char *state_desc; if (i < THREADX_NUM_STATES) - state_desc = ThreadX_thread_states[i].desc; + state_desc = threadx_thread_states[i].desc; else state_desc = "Unknown state"; @@ -597,20 +605,16 @@ static int ThreadX_get_thread_detail(struct rtos *rtos, #endif -static int ThreadX_create(struct target *target) +static int threadx_create(struct target *target) { - int i = 0; - while ((i < THREADX_NUM_PARAMS) && - (0 != strcmp(ThreadX_params_list[i].target_name, target->type->name))) { - i++; - } - if (i >= THREADX_NUM_PARAMS) { - LOG_ERROR("Could not find target in ThreadX compatibility list"); - return -1; - } + for (unsigned int i = 0; i < ARRAY_SIZE(threadx_params_list); i++) + if (strcmp(threadx_params_list[i].target_name, target->type->name) == 0) { + target->rtos->rtos_specific_params = (void *)&threadx_params_list[i]; + target->rtos->current_thread = 0; + target->rtos->thread_details = NULL; + return 0; + } - target->rtos->rtos_specific_params = (void *) &ThreadX_params_list[i]; - target->rtos->current_thread = 0; - target->rtos->thread_details = NULL; - return 0; + LOG_ERROR("Could not find target in ThreadX compatibility list"); + return -1; } diff --git a/src/rtos/chibios.c b/src/rtos/chibios.c index a56d3ce058..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 @@ -62,9 +51,9 @@ struct chibios_chdebug { uint8_t cf_off_time; /**< @brief Offset of @p p_time field. */ }; -#define GET_CH_KERNEL_MAJOR(codedVersion) ((codedVersion >> 11) & 0x1f) -#define GET_CH_KERNEL_MINOR(codedVersion) ((codedVersion >> 6) & 0x1f) -#define GET_CH_KERNEL_PATCH(codedVersion) ((codedVersion >> 0) & 0x3f) +#define GET_CH_KERNEL_MAJOR(coded_version) ((coded_version >> 11) & 0x1f) +#define GET_CH_KERNEL_MINOR(coded_version) ((coded_version >> 6) & 0x1f) +#define GET_CH_KERNEL_PATCH(coded_version) ((coded_version >> 0) & 0x3f) /** * @brief ChibiOS thread states. @@ -74,7 +63,7 @@ static const char * const chibios_thread_states[] = { "READY", "CURRENT", "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "FINAL" }; -#define CHIBIOS_NUM_STATES (sizeof(chibios_thread_states)/sizeof(char *)) +#define CHIBIOS_NUM_STATES ARRAY_SIZE(chibios_thread_states) /* Maximum ChibiOS thread name. There is no real limit set by ChibiOS but 64 * chars ought to be enough. @@ -91,25 +80,24 @@ 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 */ } }; -#define CHIBIOS_NUM_PARAMS ((int)(sizeof(chibios_params_list)/sizeof(struct chibios_params))) static bool chibios_detect_rtos(struct target *target); static int chibios_create(struct target *target); static int chibios_update_threads(struct rtos *rtos); 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(symbol_table_elem_t *symbol_list[]); +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, @@ -131,7 +119,7 @@ enum chibios_symbol_values { CHIBIOS_VAL_CH_DEBUG = 2 }; -static symbol_table_elem_t chibios_symbol_list[] = { +static struct symbol_table_elem chibios_symbol_list[] = { { "rlist", 0, true}, /* Thread ready list */ { "ch", 0, true}, /* System data structure */ { "ch_debug", 0, false}, /* Memory Signature containing offsets of fields in rlist */ @@ -185,10 +173,10 @@ static int chibios_update_memory_signature(struct rtos *rtos) } /* Convert endianness of version field */ - const uint8_t *versionTarget = (const uint8_t *) + const uint8_t *versiontarget = (const uint8_t *) &signature->ch_version; signature->ch_version = rtos->target->endianness == TARGET_LITTLE_ENDIAN ? - le_to_h_u32(versionTarget) : be_to_h_u32(versionTarget); + le_to_h_u32(versiontarget) : be_to_h_u32(versiontarget); const uint16_t ch_version = signature->ch_version; LOG_INFO("Successfully loaded memory map of ChibiOS/RT target " @@ -210,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; } @@ -470,8 +458,8 @@ static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, const struct chibios_params *param; uint32_t stack_ptr = 0; - if ((rtos == NULL) || (thread_id == 0) || - (rtos->rtos_specific_params == NULL)) + if ((!rtos) || (thread_id == 0) || + (!rtos->rtos_specific_params)) return -1; param = (const struct chibios_params *) rtos->rtos_specific_params; @@ -480,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; @@ -497,11 +485,11 @@ static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs); } -static int chibios_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { *symbol_list = malloc(sizeof(chibios_symbol_list)); - if (*symbol_list == NULL) + if (!*symbol_list) return ERROR_FAIL; memcpy(*symbol_list, chibios_symbol_list, sizeof(chibios_symbol_list)); @@ -510,7 +498,7 @@ static int chibios_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) static bool chibios_detect_rtos(struct target *target) { - if ((target->rtos->symbols != NULL) && + if ((target->rtos->symbols) && ((target->rtos->symbols[CHIBIOS_VAL_RLIST].address != 0) || (target->rtos->symbols[CHIBIOS_VAL_CH].address != 0))) { @@ -529,17 +517,13 @@ static bool chibios_detect_rtos(struct target *target) static int chibios_create(struct target *target) { - int i = 0; - while ((i < CHIBIOS_NUM_PARAMS) && - (0 != strcmp(chibios_params_list[i].target_name, target->type->name))) { - i++; - } - if (i >= CHIBIOS_NUM_PARAMS) { - LOG_WARNING("Could not find target \"%s\" in ChibiOS compatibility " - "list", target->type->name); - return -1; - } + for (unsigned int i = 0; i < ARRAY_SIZE(chibios_params_list); i++) + if (strcmp(chibios_params_list[i].target_name, target->type->name) == 0) { + target->rtos->rtos_specific_params = (void *)&chibios_params_list[i]; + return 0; + } - target->rtos->rtos_specific_params = (void *) &chibios_params_list[i]; - return 0; + LOG_WARNING("Could not find target \"%s\" in ChibiOS compatibility " + "list", target->type->name); + return -1; } diff --git a/src/rtos/chromium-ec.c b/src/rtos/chromium-ec.c index ae12a3bf54..a95969e345 100644 --- a/src/rtos/chromium-ec.c +++ b/src/rtos/chromium-ec.c @@ -1,12 +1,17 @@ +// 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> * * Chromium-EC RTOS Task Awareness */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/bits.h> #include <rtos/rtos.h> #include <target/target.h> #include <target/target_type.h> @@ -16,7 +21,6 @@ #define CROS_EC_MAX_TASKS 32 #define CROS_EC_MAX_NAME 200 #define CROS_EC_IDLE_STRING "<< idle >>" -#define BIT(x) (1 << (x)) struct chromium_ec_params { const char *target_name; @@ -36,7 +40,7 @@ static const struct chromium_ec_params chromium_ec_params_list[] = { .task_offset_sp = 0, .task_offset_events = 4, .task_offset_runtime = 8, - .stacking = &rtos_standard_Cortex_M3_stacking, + .stacking = &rtos_standard_cortex_m3_stacking, }, { @@ -46,7 +50,7 @@ static const struct chromium_ec_params chromium_ec_params_list[] = { .task_offset_sp = 0, .task_offset_events = 4, .task_offset_runtime = 8, - .stacking = &rtos_standard_Cortex_M3_stacking, + .stacking = &rtos_standard_cortex_m3_stacking, }, }; @@ -62,13 +66,13 @@ static const char * const chromium_ec_symbol_list[] = { }; enum chromium_ec_symbol_values { - CHROMIUM_EC_VAL_start_called = 0, - CHROMIUM_EC_VAL_current_task, - CHROMIUM_EC_VAL_tasks, - CHROMIUM_EC_VAL_tasks_enabled, - CHROMIUM_EC_VAL_tasks_ready, - CHROMIUM_EC_VAL_task_names, - CHROMIUM_EC_VAL_build_info, + CHROMIUM_EC_VAL_START_CALLED = 0, + CHROMIUM_EC_VAL_CURRENT_TASK, + CHROMIUM_EC_VAL_TASKS, + CHROMIUM_EC_VAL_TASKS_ENABLED, + CHROMIUM_EC_VAL_TASKS_READY, + CHROMIUM_EC_VAL_TASK_NAMES, + CHROMIUM_EC_VAL_BUILD_INFO, CHROMIUM_EC_VAL_COUNT, }; @@ -84,7 +88,7 @@ static bool chromium_ec_detect_rtos(struct target *target) if (!target || !target->rtos || !target->rtos->symbols) return false; - for (sym = CHROMIUM_EC_VAL_start_called; + for (sym = CHROMIUM_EC_VAL_START_CALLED; sym < CHROMIUM_EC_VAL_COUNT; sym++) { if (target->rtos->symbols[sym].address) { LOG_DEBUG("Chromium-EC: Symbol \"%s\" found", @@ -97,7 +101,7 @@ static bool chromium_ec_detect_rtos(struct target *target) } ret = target_read_buffer(target, - target->rtos->symbols[CHROMIUM_EC_VAL_build_info].address, + target->rtos->symbols[CHROMIUM_EC_VAL_BUILD_INFO].address, sizeof(build_info_buf), (uint8_t *)build_info_buf); @@ -107,7 +111,7 @@ static bool chromium_ec_detect_rtos(struct target *target) LOG_INFO("Chromium-EC: Buildinfo: %s", build_info_buf); return target->rtos->symbols && - target->rtos->symbols[CHROMIUM_EC_VAL_start_called].address; + target->rtos->symbols[CHROMIUM_EC_VAL_START_CALLED].address; } static int chromium_ec_create(struct target *target) @@ -143,7 +147,7 @@ static int chromium_ec_get_current_task_ptr(struct rtos *rtos, uint32_t *current return ERROR_FAIL; return target_read_u32(rtos->target, - rtos->symbols[CHROMIUM_EC_VAL_current_task].address, + rtos->symbols[CHROMIUM_EC_VAL_CURRENT_TASK].address, current_task); } @@ -153,7 +157,7 @@ static int chromium_ec_get_num_tasks(struct rtos *rtos, int *num_tasks) int ret, t, found; ret = target_read_u32(rtos->target, - rtos->symbols[CHROMIUM_EC_VAL_tasks_enabled].address, + rtos->symbols[CHROMIUM_EC_VAL_TASKS_ENABLED].address, &tasks_enabled); if (ret != ERROR_OK) { LOG_ERROR("Failed to determine #of tasks"); @@ -213,7 +217,7 @@ static int chromium_ec_update_threads(struct rtos *rtos) /* One check if task switching has started ... */ start_called = 0; - ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_start_called].address, + ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_START_CALLED].address, &start_called); if (ret != ERROR_OK) { LOG_ERROR("Failed to load start_called"); @@ -241,7 +245,7 @@ static int chromium_ec_update_threads(struct rtos *rtos) } tasks_enabled = 0; - ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_tasks_enabled].address, + ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_TASKS_ENABLED].address, &tasks_enabled); if (ret != ERROR_OK) { LOG_ERROR("Failed to load tasks_enabled"); @@ -249,14 +253,14 @@ static int chromium_ec_update_threads(struct rtos *rtos) } tasks_ready = 0; - ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_tasks_ready].address, + ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_TASKS_READY].address, &tasks_ready); if (ret != ERROR_OK) { LOG_ERROR("Failed to load tasks_ready"); return ret; } - thread_ptr = rtos->symbols[CHROMIUM_EC_VAL_tasks].address; + thread_ptr = rtos->symbols[CHROMIUM_EC_VAL_TASKS].address; tasks_found = 0; for (t = 0; t < CROS_EC_MAX_TASKS; t++) { @@ -268,7 +272,7 @@ static int chromium_ec_update_threads(struct rtos *rtos) rtos->thread_details[tasks_found].threadid = thread_ptr; ret = target_read_u32(rtos->target, - rtos->symbols[CHROMIUM_EC_VAL_task_names].address + + rtos->symbols[CHROMIUM_EC_VAL_TASK_NAMES].address + params->ptr_size * t, &name_ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read name_ptr"); @@ -348,7 +352,7 @@ static int chromium_ec_get_thread_reg_list(struct rtos *rtos, return ERROR_FAIL; ret = target_read_u32(rtos->target, - rtos->symbols[CHROMIUM_EC_VAL_tasks].address + + rtos->symbols[CHROMIUM_EC_VAL_TASKS].address + params->task_offset_next * t, &stack_ptr); if (ret != ERROR_OK) { @@ -360,12 +364,12 @@ static int chromium_ec_get_thread_reg_list(struct rtos *rtos, stack_ptr, reg_list, num_regs); } -static int chromium_ec_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int chromium_ec_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { size_t s; *symbol_list = calloc(ARRAY_SIZE(chromium_ec_symbol_list), - sizeof(symbol_table_elem_t)); + sizeof(struct symbol_table_elem)); if (!(*symbol_list)) { LOG_ERROR("Chromium-EC: out of memory"); return ERROR_FAIL; diff --git a/src/rtos/eCos.c b/src/rtos/eCos.c index e6b70730b5..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,161 +11,817 @@ #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(symbol_table_elem_t *symbol_list[]); +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); -struct eCos_thread_state { +/* 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 (sizeof(eCos_thread_states)/sizeof(struct eCos_thread_state)) +/* 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; +struct ecos_params { + 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 ((int)(sizeof(eCos_params_list)/sizeof(struct eCos_params))) +#define ECOS_NUM_PARAMS ARRAY_SIZE(ecos_params_list) -enum eCos_symbol_values { - eCos_VAL_thread_list = 0, - eCos_VAL_current_thread_ptr = 1 +/* 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 }; -static const char * const eCos_symbol_list[] = { - "Cyg_Thread::thread_list", - "Cyg_Scheduler_Base::current_thread", - NULL +#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 }; -const struct rtos_type eCos_rtos = { +/* 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, + 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 +}; + +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 = { .name = "eCos", - .detect_rtos = eCos_detect_rtos, - .create = eCos_create, - .update_threads = eCos_update_threads, - .get_thread_reg_list = eCos_get_thread_reg_list, - .get_symbol_list_to_lookup = eCos_get_symbol_list_to_lookup, + .detect_rtos = ecos_detect_rtos, + .create = ecos_create, + .update_threads = ecos_update_threads, + .get_thread_reg_list = ecos_get_thread_reg_list, + .get_symbol_list_to_lookup = ecos_get_symbol_list_to_lookup, + +}; + +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('"', """) }; -static int eCos_update_threads(struct rtos *rtos) +/** 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 == NULL) + if (!rtos) return -1; - if (rtos->rtos_specific_params == NULL) + /* 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 == NULL) { + 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; } - if (rtos->symbols[eCos_VAL_thread_list].address == 0) { + 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_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address; uint32_t thread_index; target_read_buffer(rtos->target, thread_list_head, 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, + rtos->symbols[ECOS_VAL_CURRENT_THREAD_PTR].address, + 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; } @@ -189,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"); @@ -208,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, @@ -230,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); @@ -241,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; - 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); + /* 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; + } + + 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; @@ -270,7 +1014,7 @@ static int eCos_update_threads(struct rtos *rtos) prev_thread_ptr = thread_index; /* Get the location of the next thread structure. */ - thread_index = rtos->symbols[eCos_VAL_thread_list].address; + thread_index = rtos->symbols[ECOS_VAL_THREAD_LIST].address; retval = target_read_buffer(rtos->target, prev_thread_ptr + param->thread_next_offset, param->pointer_width, @@ -282,29 +1026,44 @@ 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, +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 == NULL) + if (!rtos) return -1; if (thread_id == 0) return -2; - if (rtos->rtos_specific_params == NULL) + 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; - uint32_t thread_list_head = rtos->symbols[eCos_VAL_thread_list].address; + uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address; uint32_t thread_index; target_read_buffer(rtos->target, thread_list_head, param->pointer_width, (uint8_t *)&thread_index); @@ -312,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; } @@ -341,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); @@ -351,42 +1126,100 @@ static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return -1; } -static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +/* 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(symbol_table_elem_t)); + 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; } -static bool eCos_detect_rtos(struct target *target) +/* 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 != NULL) && - (target->rtos->symbols[eCos_VAL_thread_list].address != 0)) { + if ((target->rtos->symbols) && + (target->rtos->symbols[ECOS_VAL_THREAD_LIST].address != 0)) { /* looks like eCos */ return true; } return false; } -static int eCos_create(struct target *target) +/* 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) { - int i = 0; - while ((i < ECOS_NUM_PARAMS) && - (0 != strcmp(eCos_params_list[i].target_name, target->type->name))) { - i++; + 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; + } + } } - if (i >= ECOS_NUM_PARAMS) { - LOG_ERROR("Could not find target in eCos compatibility list"); - return -1; + + 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++) { + 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++; + } } - target->rtos->rtos_specific_params = (void *) &eCos_params_list[i]; - target->rtos->current_thread = 0; - target->rtos->thread_details = NULL; - return 0; + 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 2f04963b42..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 @@ -31,33 +20,33 @@ #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64) -static bool embKernel_detect_rtos(struct target *target); -static int embKernel_create(struct target *target); -static int embKernel_update_threads(struct rtos *rtos); -static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, +static bool embkernel_detect_rtos(struct target *target); +static int embkernel_create(struct target *target); +static int embkernel_update_threads(struct rtos *rtos); +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(symbol_table_elem_t *symbol_list[]); +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, - .update_threads = embKernel_update_threads, + .detect_rtos = embkernel_detect_rtos, + .create = embkernel_create, + .update_threads = embkernel_update_threads, .get_thread_reg_list = - embKernel_get_thread_reg_list, - .get_symbol_list_to_lookup = embKernel_get_symbol_list_to_lookup, + embkernel_get_thread_reg_list, + .get_symbol_list_to_lookup = embkernel_get_symbol_list_to_lookup, }; enum { - SYMBOL_ID_sCurrentTask = 0, - SYMBOL_ID_sListReady = 1, - SYMBOL_ID_sListSleep = 2, - SYMBOL_ID_sListSuspended = 3, - SYMBOL_ID_sMaxPriorities = 4, - SYMBOL_ID_sCurrentTaskCount = 5, + SYMBOL_ID_S_CURRENT_TASK = 0, + SYMBOL_ID_S_LIST_READY = 1, + SYMBOL_ID_S_LIST_SLEEP = 2, + SYMBOL_ID_S_LIST_SUSPENDED = 3, + SYMBOL_ID_S_MAX_PRIORITIES = 4, + SYMBOL_ID_S_CURRENT_TASK_COUNT = 5, }; -static const char * const embKernel_symbol_list[] = { +static const char * const embkernel_symbol_list[] = { "Rtos::sCurrentTask", "Rtos::sListReady", "Rtos::sListSleep", @@ -66,7 +55,7 @@ static const char * const embKernel_symbol_list[] = { "Rtos::sCurrentTaskCount", NULL }; -struct embKernel_params { +struct embkernel_params { const char *target_name; const unsigned char pointer_width; const unsigned char thread_count_width; @@ -80,7 +69,7 @@ struct embKernel_params { const struct rtos_register_stacking *stacking_info; }; -static const struct embKernel_params embKernel_params_list[] = { +static const struct embkernel_params embkernel_params_list[] = { { "cortex_m", /* target_name */ 4, /* pointer_width */ @@ -92,7 +81,7 @@ static const struct embKernel_params embKernel_params_list[] = { 4, /*thread_priority_width */ 4, /*iterable_next_offset */ 12, /*iterable_task_owner_offset */ - &rtos_embkernel_Cortex_M_stacking, /* stacking_info*/ + &rtos_embkernel_cortex_m_stacking, /* stacking_info*/ }, { "hla_target", /* target_name */ 4, /* pointer_width */ @@ -104,37 +93,37 @@ static const struct embKernel_params embKernel_params_list[] = { 4, /*thread_priority_width */ 4, /*iterable_next_offset */ 12, /*iterable_task_owner_offset */ - &rtos_embkernel_Cortex_M_stacking, /* stacking_info */ + &rtos_embkernel_cortex_m_stacking, /* stacking_info */ } }; -static bool embKernel_detect_rtos(struct target *target) +static bool embkernel_detect_rtos(struct target *target) { - if (target->rtos->symbols != NULL) { - if (target->rtos->symbols[SYMBOL_ID_sCurrentTask].address != 0) + if (target->rtos->symbols) { + if (target->rtos->symbols[SYMBOL_ID_S_CURRENT_TASK].address != 0) return true; } return false; } -static int embKernel_create(struct target *target) +static int embkernel_create(struct target *target) { size_t i = 0; - while ((i < ARRAY_SIZE(embKernel_params_list)) && - (0 != strcmp(embKernel_params_list[i].target_name, target->type->name))) + while ((i < ARRAY_SIZE(embkernel_params_list)) && + (strcmp(embkernel_params_list[i].target_name, target->type->name) != 0)) i++; - if (i >= ARRAY_SIZE(embKernel_params_list)) { + if (i >= ARRAY_SIZE(embkernel_params_list)) { LOG_WARNING("Could not find target \"%s\" in embKernel compatibility " "list", target->type->name); return -1; } - target->rtos->rtos_specific_params = (void *) &embKernel_params_list[i]; + target->rtos->rtos_specific_params = (void *) &embkernel_params_list[i]; return 0; } -static int embKernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embKernel_params *param, +static int embkernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embkernel_params *param, struct thread_detail *details, const char *state_str) { int64_t task = 0; @@ -181,24 +170,24 @@ static int embKernel_get_tasks_details(struct rtos *rtos, int64_t iterable, cons return 0; } -static int embKernel_update_threads(struct rtos *rtos) +static int embkernel_update_threads(struct rtos *rtos) { /* int i = 0; */ int retval; - const struct embKernel_params *param; + const struct embkernel_params *param; - if (rtos == NULL) + if (!rtos) return -1; - if (rtos->rtos_specific_params == NULL) + if (!rtos->rtos_specific_params) return -3; - if (rtos->symbols == NULL) { + if (!rtos->symbols) { LOG_ERROR("No symbols for embKernel"); return -4; } - if (rtos->symbols[SYMBOL_ID_sCurrentTask].address == 0) { + if (rtos->symbols[SYMBOL_ID_S_CURRENT_TASK].address == 0) { LOG_ERROR("Don't have the thread list head"); return -2; } @@ -206,9 +195,9 @@ static int embKernel_update_threads(struct rtos *rtos) /* wipe out previous thread details if any */ rtos_free_threadlist(rtos); - param = (const struct embKernel_params *) rtos->rtos_specific_params; + param = (const struct embkernel_params *) rtos->rtos_specific_params; - retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTask].address, param->pointer_width, + retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_CURRENT_TASK].address, param->pointer_width, (uint8_t *) &rtos->current_thread); if (retval != ERROR_OK) { LOG_ERROR("Error reading current thread in embKernel thread list"); @@ -216,13 +205,13 @@ static int embKernel_update_threads(struct rtos *rtos) } int64_t max_used_priority = 0; - retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sMaxPriorities].address, param->pointer_width, + retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_MAX_PRIORITIES].address, param->pointer_width, (uint8_t *) &max_used_priority); if (retval != ERROR_OK) return retval; int thread_list_size = 0; - retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTaskCount].address, + retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_CURRENT_TASK_COUNT].address, param->thread_count_width, (uint8_t *) &thread_list_size); if (retval != ERROR_OK) { @@ -237,19 +226,19 @@ static int embKernel_update_threads(struct rtos *rtos) return ERROR_FAIL; } - int threadIdx = 0; + int thread_idx = 0; /* Look for ready tasks */ for (int pri = 0; pri < max_used_priority; pri++) { /* Get first item in queue */ int64_t iterable = 0; retval = target_read_buffer(rtos->target, - rtos->symbols[SYMBOL_ID_sListReady].address + (pri * param->rtos_list_size), param->pointer_width, + rtos->symbols[SYMBOL_ID_S_LIST_READY].address + (pri * param->rtos_list_size), param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; - for (; iterable && threadIdx < thread_list_size; threadIdx++) { + for (; iterable && thread_idx < thread_list_size; thread_idx++) { /* Get info from this iterable item */ - retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Ready"); + retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Ready"); if (retval != ERROR_OK) return retval; /* Get next iterable item */ @@ -261,13 +250,13 @@ static int embKernel_update_threads(struct rtos *rtos) } /* Look for sleeping tasks */ int64_t iterable = 0; - retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSleep].address, param->pointer_width, + retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_LIST_SLEEP].address, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; - for (; iterable && threadIdx < thread_list_size; threadIdx++) { + for (; iterable && thread_idx < thread_list_size; thread_idx++) { /*Get info from this iterable item */ - retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Sleeping"); + retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Sleeping"); if (retval != ERROR_OK) return retval; /*Get next iterable item */ @@ -279,13 +268,13 @@ static int embKernel_update_threads(struct rtos *rtos) /* Look for suspended tasks */ iterable = 0; - retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSuspended].address, param->pointer_width, + retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_LIST_SUSPENDED].address, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; - for (; iterable && threadIdx < thread_list_size; threadIdx++) { + for (; iterable && thread_idx < thread_list_size; thread_idx++) { /* Get info from this iterable item */ - retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Suspended"); + retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Suspended"); if (retval != ERROR_OK) return retval; /*Get next iterable item */ @@ -296,28 +285,28 @@ static int embKernel_update_threads(struct rtos *rtos) } rtos->thread_count = 0; - rtos->thread_count = threadIdx; - LOG_OUTPUT("Found %u tasks\n", (unsigned int)threadIdx); + rtos->thread_count = thread_idx; + LOG_OUTPUT("Found %u tasks\n", (unsigned int)thread_idx); return 0; } -static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, +static int embkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { int retval; - const struct embKernel_params *param; + const struct embkernel_params *param; int64_t stack_ptr = 0; - if (rtos == NULL) + if (!rtos) return -1; if (thread_id == 0) return -2; - if (rtos->rtos_specific_params == NULL) + if (!rtos->rtos_specific_params) return -1; - param = (const struct embKernel_params *) rtos->rtos_specific_params; + param = (const struct embkernel_params *) rtos->rtos_specific_params; /* Read the stack pointer */ retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width, @@ -330,13 +319,13 @@ static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs); } -static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int embkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; - *symbol_list = calloc(ARRAY_SIZE(embKernel_symbol_list), sizeof(symbol_table_elem_t)); + *symbol_list = calloc(ARRAY_SIZE(embkernel_symbol_list), sizeof(struct symbol_table_elem)); - for (i = 0; i < ARRAY_SIZE(embKernel_symbol_list); i++) - (*symbol_list)[i].symbol_name = embKernel_symbol_list[i]; + for (i = 0; i < ARRAY_SIZE(embkernel_symbol_list); i++) + (*symbol_list)[i].symbol_name = embkernel_symbol_list[i]; return 0; } diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index e0789aa63a..895f11cfc9 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" @@ -23,6 +9,7 @@ #include "target/target.h" #include "target/target_type.h" #include "target/register.h" +#include <target/smp.h> #include "rtos.h" #include "helper/log.h" #include "helper/types.h" @@ -35,14 +22,16 @@ static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id, uint32_t reg_num, struct rtos_reg *rtos_reg); static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); -static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); static int hwthread_smp_init(struct target *target); -int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); +static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); +static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, + uint32_t size, uint8_t *buffer); +static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, + uint32_t size, const uint8_t *buffer); #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; @@ -58,6 +47,8 @@ const struct rtos_type hwthread_rtos = { .get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup, .smp_init = hwthread_smp_init, .set_reg = hwthread_set_reg, + .read_buffer = hwthread_read_buffer, + .write_buffer = hwthread_write_buffer, }; struct hwthread_params { @@ -89,9 +80,10 @@ 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 == NULL) + if (!rtos) return -1; target = rtos->target; @@ -101,7 +93,7 @@ static int hwthread_update_threads(struct rtos *rtos) /* determine the number of "threads" */ if (target->smp) { - for (head = target->head; head != NULL; head = head->next) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) @@ -112,12 +104,21 @@ static int hwthread_update_threads(struct rtos *rtos) } else thread_list_size = 1; + /* 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); if (target->smp) { /* loop over all threads */ - for (head = target->head; head != NULL; head = head->next) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) @@ -209,10 +210,11 @@ static int hwthread_smp_init(struct target *target) static struct target *hwthread_find_thread(struct target *target, int64_t thread_id) { /* Find the thread with that thread_id */ - if (target == NULL) + if (!target) return NULL; if (target->smp) { - for (struct target_list *head = target->head; head != NULL; head = head->next) { + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { if (thread_id == threadid_from_target(head->target)) return head->target; } @@ -225,35 +227,56 @@ static struct target *hwthread_find_thread(struct target *target, int64_t thread static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **rtos_reg_list, int *rtos_reg_list_size) { - if (rtos == NULL) + if (!rtos) return ERROR_FAIL; struct target *target = rtos->target; struct target *curr = hwthread_find_thread(target, thread_id); - if (curr == NULL) + if (!curr) return ERROR_FAIL; if (!target_was_examined(curr)) return ERROR_FAIL; + int reg_list_size; struct reg **reg_list; - int retval = target_get_gdb_reg_list(curr, ®_list, rtos_reg_list_size, + int retval = target_get_gdb_reg_list(curr, ®_list, ®_list_size, REG_CLASS_GENERAL); if (retval != ERROR_OK) return retval; + int j = 0; + for (int i = 0; i < reg_list_size; i++) { + if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden) + continue; + j++; + } + *rtos_reg_list_size = j; *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg)); - if (*rtos_reg_list == NULL) { + if (!*rtos_reg_list) { free(reg_list); return ERROR_FAIL; } - for (int i = 0; i < *rtos_reg_list_size; i++) { - (*rtos_reg_list)[i].number = (*reg_list)[i].number; - (*rtos_reg_list)[i].size = (*reg_list)[i].size; - memcpy((*rtos_reg_list)[i].value, (*reg_list)[i].value, - ((*reg_list)[i].size + 7) / 8); + j = 0; + for (int 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) { + 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); @@ -263,13 +286,13 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id, uint32_t reg_num, struct rtos_reg *rtos_reg) { - if (rtos == NULL) + if (!rtos) return ERROR_FAIL; struct target *target = rtos->target; struct target *curr = hwthread_find_thread(target, thread_id); - if (curr == NULL) { + if (!curr) { LOG_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id); return ERROR_FAIL; } @@ -298,15 +321,15 @@ static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id, return ERROR_OK; } -int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value) +static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value) { - if (rtos == NULL) + if (!rtos) return ERROR_FAIL; struct target *target = rtos->target; struct target *curr = hwthread_find_thread(target, rtos->current_thread); - if (curr == NULL) + if (!curr) return ERROR_FAIL; struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true); @@ -316,10 +339,10 @@ int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value) return reg->type->set(reg, reg_value); } -static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { /* return an empty list, we don't have any symbols to look up */ - *symbol_list = calloc(1, sizeof(symbol_table_elem_t)); + *symbol_list = calloc(1, sizeof(struct symbol_table_elem)); (*symbol_list)[0].symbol_name = NULL; return 0; } @@ -329,7 +352,7 @@ static int hwthread_target_for_threadid(struct connection *connection, int64_t t struct target *target = get_target_from_connection(connection); struct target *curr = hwthread_find_thread(target, thread_id); - if (curr == NULL) + if (!curr) return ERROR_FAIL; *p_target = curr; @@ -384,3 +407,33 @@ static int hwthread_create(struct target *target) target->rtos->gdb_thread_packet = hwthread_thread_packet; return 0; } + +static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, + uint32_t size, uint8_t *buffer) +{ + if (!rtos) + return ERROR_FAIL; + + struct target *target = rtos->target; + + struct target *curr = hwthread_find_thread(target, rtos->current_thread); + if (!curr) + return ERROR_FAIL; + + return target_read_buffer(curr, address, size, buffer); +} + +static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, + uint32_t size, const uint8_t *buffer) +{ + if (!rtos) + return ERROR_FAIL; + + struct target *target = rtos->target; + + struct target *curr = hwthread_find_thread(target, rtos->current_thread); + if (!curr) + return ERROR_FAIL; + + return target_write_buffer(curr, address, size, buffer); +} diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 44e132d36e..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 @@ -30,6 +19,7 @@ #include "rtos.h" #include "rtos_standard_stackings.h" #include <target/register.h> +#include <target/smp.h> #include "server/gdb_server.h" #define LINUX_USER_KERNEL_BORDER 0xc0000000 @@ -92,7 +82,7 @@ struct cpu_context { uint32_t PC; uint32_t preempt_count; }; -struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, +static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, uint32_t *info_addr); static int insert_into_threadlist(struct target *target, struct threads *t); @@ -133,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; } @@ -144,7 +134,7 @@ static int linux_read_memory(struct target *target, return ERROR_OK; } -int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer) +static int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer) { if ((addr & 0xfffffffc) != addr) @@ -155,7 +145,7 @@ int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer) } -uint32_t get_buffer(struct target *target, const uint8_t *buffer) +static uint32_t get_buffer(struct target *target, const uint8_t *buffer) { uint32_t value = 0; const uint8_t *value_ptr = buffer; @@ -181,7 +171,7 @@ static int linux_os_thread_reg_list(struct rtos *rtos, found = 1; else next = next->next; - } while ((found == 0) && (next != tmp) && (next != NULL)); + } while ((found == 0) && (next != tmp) && (next)); if (found == 0) { LOG_ERROR("could not find thread: %" PRIx64, thread_id); @@ -191,17 +181,14 @@ static int linux_os_thread_reg_list(struct rtos *rtos, /* search target to perform the access */ struct reg **gdb_reg_list; struct target_list *head; - head = target->head; found = 0; - do { + foreach_smp_target(head, target->smp_targets) { if (head->target->coreid == next->core_id) { - target = head->target; found = 1; - } else - head = head->next; - - } while ((head != (struct target_list *)NULL) && (found == 0)); + break; + } + } if (found == 0) { LOG_ERROR @@ -246,11 +233,11 @@ static const char * const linux_symbol_list[] = { NULL }; -static int linux_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int linux_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; - *symbol_list = (symbol_table_elem_t *) - calloc(ARRAY_SIZE(linux_symbol_list), sizeof(symbol_table_elem_t)); + *symbol_list = (struct symbol_table_elem *) + calloc(ARRAY_SIZE(linux_symbol_list), sizeof(struct symbol_table_elem)); for (i = 0; i < ARRAY_SIZE(linux_symbol_list); i++) (*symbol_list)[i].symbol_name = linux_symbol_list[i]; @@ -260,7 +247,7 @@ static int linux_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) static char *linux_ps_command(struct target *target); -const struct rtos_type Linux_os = { +const struct rtos_type linux_rtos = { .name = "linux", .detect_rtos = linux_os_detect, .create = linux_os_create, @@ -293,7 +280,7 @@ int fill_task_pid(struct target *target, struct threads *t) } #endif -int fill_task(struct target *target, struct threads *t) +static int fill_task(struct target *target, struct threads *t) { int retval; uint32_t pid_addr = t->base_addr + PID; @@ -349,7 +336,7 @@ int fill_task(struct target *target, struct threads *t) return retval; } -int get_name(struct target *target, struct threads *t) +static int get_name(struct target *target, struct threads *t) { int retval; uint32_t full_name[4]; @@ -395,10 +382,9 @@ int get_name(struct target *target, struct threads *t) } -int get_current(struct target *target, int create) +static int get_current(struct target *target, int create) { struct target_list *head; - head = target->head; uint8_t *buf; uint32_t val; uint32_t ti_addr; @@ -408,13 +394,13 @@ int get_current(struct target *target, int create) struct current_thread *ctt = linux_os->current_threads; /* invalid current threads content */ - while (ctt != NULL) { + while (ctt) { ctt->threadid = -1; ctt->TS = 0xdeadbeef; ctt = ctt->next; } - while (head != (struct target_list *)NULL) { + foreach_smp_target(head, target->smp_targets) { struct reg **reg_list; int reg_list_size; int retval; @@ -431,8 +417,8 @@ int get_current(struct target *target, int create) buf = reg_list[13]->value; val = get_buffer(target, buf); ti_addr = (val & 0xffffe000); - uint32_t TS_addr = ti_addr + 0xc; - retval = fill_buffer(target, TS_addr, buffer); + uint32_t ts_addr = ti_addr + 0xc; + retval = fill_buffer(target, ts_addr, buffer); if (retval == ERROR_OK) { uint32_t TS = get_buffer(target, buffer); @@ -445,10 +431,10 @@ int get_current(struct target *target, int create) linux_os->current_threads; cpu = head->target->coreid; - while ((ct != NULL) && (ct->core_id != (int32_t) cpu)) + while ((ct) && (ct->core_id != (int32_t) cpu)) ct = ct->next; - if ((ct != NULL) && (ct->TS == 0xdeadbeef)) + if ((ct) && (ct->TS == 0xdeadbeef)) ct->TS = TS; else LOG_ERROR @@ -475,7 +461,6 @@ int get_current(struct target *target, int create) } free(reg_list); - head = head->next; } free(buffer); @@ -483,7 +468,7 @@ int get_current(struct target *target, int create) return ERROR_OK; } -struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, +static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, uint32_t *thread_info_addr_old) { struct cpu_context *context = calloc(1, sizeof(struct cpu_context)); @@ -579,7 +564,7 @@ retry: return context; } -uint32_t next_task(struct target *target, struct threads *t) +static uint32_t next_task(struct target *target, struct threads *t) { uint8_t *buffer = calloc(1, 4); uint32_t next_addr = t->base_addr + NEXT; @@ -598,18 +583,18 @@ uint32_t next_task(struct target *target, struct threads *t) return 0; } -struct current_thread *add_current_thread(struct current_thread *currents, +static struct current_thread *add_current_thread(struct current_thread *currents, struct current_thread *ct) { ct->next = NULL; - if (currents == NULL) { + if (!currents) { currents = ct; return currents; } else { struct current_thread *temp = currents; - while (temp->next != NULL) + while (temp->next) temp = temp->next; temp->next = ct; @@ -617,7 +602,7 @@ struct current_thread *add_current_thread(struct current_thread *currents, } } -struct threads *liste_del_task(struct threads *task_list, struct threads **t, +static struct threads *liste_del_task(struct threads *task_list, struct threads **t, struct threads *prev) { LOG_INFO("del task %" PRId64, (*t)->threadid); @@ -634,19 +619,19 @@ struct threads *liste_del_task(struct threads *task_list, struct threads **t, return task_list; } -struct threads *liste_add_task(struct threads *task_list, struct threads *t, +static struct threads *liste_add_task(struct threads *task_list, struct threads *t, struct threads **last) { t->next = NULL; - if (*last == NULL) - if (task_list == NULL) { + if (!*last) + if (!task_list) { task_list = t; return task_list; } else { struct threads *temp = task_list; - while (temp->next != NULL) + while (temp->next) temp = temp->next; temp->next = t; @@ -668,22 +653,22 @@ static int current_base_addr(struct linux_os *linux_os, uint32_t base_addr) struct current_thread *ct = linux_os->current_threads; #ifdef PID_CHECK - while ((ct != NULL) && (ct->pid != pid)) + while ((ct) && (ct->pid != pid)) #else - while ((ct != NULL) && (ct->TS != base_addr)) + while ((ct) && (ct->TS != base_addr)) #endif ct = ct->next; #ifdef PID_CHECK - if ((ct != NULL) && (ct->pid == pid)) + if ((ct) && (ct->pid == pid)) #else - if ((ct != NULL) && (ct->TS == base_addr)) + if ((ct) && (ct->TS == base_addr)) #endif return 1; return 0; } -int linux_get_tasks(struct target *target, int context) +static int linux_get_tasks(struct target *target, int context) { int loop = 0; int retval = 0; @@ -777,7 +762,7 @@ static int clean_threadlist(struct target *target) target->rtos->rtos_specific_params; struct threads *old, *temp = linux_os->thread_list; - while (temp != NULL) { + while (temp) { old = temp; free(temp->context); @@ -815,10 +800,10 @@ static int insert_into_threadlist(struct target *target, struct threads *t) t->status = 1; t->next = NULL; - if (temp == NULL) + if (!temp) linux_os->thread_list = t; else { - while (temp->next != NULL) + while (temp->next) temp = temp->next; t->next = NULL; @@ -836,7 +821,7 @@ static void linux_identify_current_threads(struct target *target) struct current_thread *ct = linux_os->current_threads; struct threads *t = NULL; - while ((ct != NULL)) { + while ((ct)) { if (ct->threadid == -1) { /* un-identified thread */ @@ -856,7 +841,7 @@ error_handling: /* search in the list of threads if pid already present */ - while ((thread_list != NULL) && (found == 0)) { + while ((thread_list) && (found == 0)) { #ifdef PID_CHECK if (thread_list->pid == t->pid) { #else @@ -926,7 +911,7 @@ static int linux_task_update(struct target *target, int context) linux_os->thread_count = 0; /*thread_list = thread_list->next; skip init_task*/ - while (thread_list != NULL) { + while (thread_list) { thread_list->status = 0; /*setting all tasks to dead state*/ free(thread_list->context); @@ -967,7 +952,7 @@ static int linux_task_update(struct target *target, int context) thread_list = linux_os->thread_list; - while (thread_list != NULL) { + while (thread_list) { #ifdef PID_CHECK if (t->pid == thread_list->pid) { #else @@ -1033,7 +1018,7 @@ static int linux_task_update(struct target *target, int context) return ERROR_OK; } -int linux_gdb_thread_packet(struct target *target, +static int linux_gdb_thread_packet(struct target *target, struct connection *connection, char const *packet, int packet_size) { @@ -1058,7 +1043,7 @@ int linux_gdb_thread_packet(struct target *target, tmp_str += sprintf(tmp_str, "m"); struct threads *temp = linux_os->thread_list; - while (temp != NULL) { + while (temp) { tmp_str += sprintf(tmp_str, "%016" PRIx64, temp->threadid); temp = temp->next; if (temp) @@ -1070,7 +1055,7 @@ int linux_gdb_thread_packet(struct target *target, return ERROR_OK; } -int linux_gdb_thread_update(struct target *target, +static int linux_gdb_thread_update(struct target *target, struct connection *connection, char const *packet, int packet_size) { @@ -1079,7 +1064,7 @@ int linux_gdb_thread_update(struct target *target, target->rtos->rtos_specific_params; struct threads *temp = linux_os->thread_list; - while (temp != NULL) { + while (temp) { if (temp->threadid == linux_os->preupdtate_threadid_count + 1) { /*LOG_INFO("FOUND");*/ found = 1; @@ -1098,7 +1083,7 @@ int linux_gdb_thread_update(struct target *target, temp = temp->next; - while (temp != NULL) { + while (temp) { /*LOG_INFO("INTO GDB THREAD UPDATE WHILE");*/ tmp_strr += sprintf(tmp_strr, ","); tmp_strr += @@ -1117,7 +1102,7 @@ int linux_gdb_thread_update(struct target *target, return ERROR_OK; } -int linux_thread_extra_info(struct target *target, +static int linux_thread_extra_info(struct target *target, struct connection *connection, char const *packet, int packet_size) { @@ -1128,7 +1113,7 @@ int linux_thread_extra_info(struct target *target, /*LOG_INFO("lookup extra info for thread %" SCNx64, threadid);*/ struct threads *temp = linux_os->thread_list; - while (temp != NULL) { + while (temp) { if (temp->threadid == threadid) { char *pid = " PID: "; char *pid_current = "*PID: "; @@ -1163,7 +1148,7 @@ int linux_thread_extra_info(struct target *target, return ERROR_OK; } -int linux_gdb_T_packet(struct connection *connection, +static int linux_gdb_t_packet(struct connection *connection, struct target *target, char const *packet, int packet_size) { int64_t threadid; @@ -1176,7 +1161,7 @@ int linux_gdb_T_packet(struct connection *connection, struct threads *temp = linux_os->thread_list; struct threads *prev = NULL; - while (temp != NULL) { + while (temp) { if (temp->threadid == threadid) { if (temp->status != 0) { gdb_put_packet(connection, "OK", 2); @@ -1205,7 +1190,7 @@ int linux_gdb_T_packet(struct connection *connection, retval = linux_task_update(target, 1); struct threads *temp = linux_os->thread_list; - while (temp != NULL) { + while (temp) { if (temp->threadid == threadid) { if (temp->status == 1) { gdb_put_packet(connection, "OK", 2); @@ -1223,7 +1208,7 @@ int linux_gdb_T_packet(struct connection *connection, return retval; } -int linux_gdb_h_packet(struct connection *connection, +static int linux_gdb_h_packet(struct connection *connection, struct target *target, char const *packet, int packet_size) { struct linux_os *linux_os = (struct linux_os *) @@ -1231,20 +1216,20 @@ int linux_gdb_h_packet(struct connection *connection, struct current_thread *ct = linux_os->current_threads; /* select to display the current thread of the selected target */ - while ((ct != NULL) && (ct->core_id != target->coreid)) + while ((ct) && (ct->core_id != target->coreid)) ct = ct->next; int64_t current_gdb_thread_rq; if (linux_os->threads_lookup == 1) { - if ((ct != NULL) && (ct->threadid == -1)) { + if ((ct) && (ct->threadid == -1)) { ct = linux_os->current_threads; - while ((ct != NULL) && (ct->threadid == -1)) + while ((ct) && (ct->threadid == -1)) ct = ct->next; } - if (ct == NULL) { + if (!ct) { /* no current thread can be identified * any way with smp */ LOG_INFO("no current thread identified"); @@ -1253,7 +1238,7 @@ int linux_gdb_h_packet(struct connection *connection, struct threads t; ct = linux_os->current_threads; - while ((ct != NULL) && (ct->threadid == -1)) { + while ((ct) && (ct->threadid == -1)) { t.base_addr = ct->TS; get_name(target, &t); LOG_INFO("name of unidentified thread %s", @@ -1304,7 +1289,7 @@ static int linux_thread_packet(struct connection *connection, char const *packet switch (packet[0]) { case 'T': /* Is thread alive?*/ - linux_gdb_T_packet(connection, target, packet, packet_size); + linux_gdb_t_packet(connection, target, packet, packet_size); break; case 'H': /* Set current thread */ /* ( 'c' for step and continue, 'g' for all other operations )*/ @@ -1321,7 +1306,7 @@ static int linux_thread_packet(struct connection *connection, char const *packet break; } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { - if (linux_os->thread_list == NULL) { + if (!linux_os->thread_list) { retval = linux_gdb_thread_packet(target, connection, packet, @@ -1356,17 +1341,17 @@ static int linux_thread_packet(struct connection *connection, char const *packet if (linux_os->threads_lookup == 1) { ct = linux_os->current_threads; - while ((ct != NULL) && (ct->core_id) != target->coreid) + while ((ct) && (ct->core_id) != target->coreid) ct = ct->next; - if ((ct != NULL) && (ct->threadid == -1)) { + if ((ct) && (ct->threadid == -1)) { ct = linux_os->current_threads; - while ((ct != NULL) && (ct->threadid == -1)) + while ((ct) && (ct->threadid == -1)) ct = ct->next; } - if ((ct != NULL) && (ct->threadid != + if ((ct) && (ct->threadid != target->rtos->current_threadid) && (target->rtos->current_threadid != -1)) LOG_WARNING("WARNING! current GDB thread do not match " @@ -1395,9 +1380,8 @@ static int linux_os_smp_init(struct target *target) struct linux_os *os_linux = (struct linux_os *)rtos->rtos_specific_params; struct current_thread *ct; - head = target->head; - while (head != (struct target_list *)NULL) { + foreach_smp_target(head, target->smp_targets) { if (head->target->rtos != rtos) { struct linux_os *smp_os_linux = (struct linux_os *)head->target->rtos->rtos_specific_params; @@ -1414,8 +1398,6 @@ static int linux_os_smp_init(struct target *target) os_linux->nr_cpus++; free(smp_os_linux); } - - head = head->next; } return ERROR_OK; @@ -1478,7 +1460,7 @@ static char *linux_ps_command(struct target *target) tmp += sprintf(tmp, "PID\t\tCPU\t\tASID\t\tNAME\n"); tmp += sprintf(tmp, "---\t\t---\t\t----\t\t----\n"); - while (temp != NULL) { + while (temp) { if (temp->status) { if (temp->context) tmp += 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 f45c15d23e..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 @@ -49,8 +38,8 @@ /* types */ enum mqx_symbols { - mqx_VAL_mqx_kernel_data, - mqx_VAL_MQX_init_struct, + MQX_VAL_MQX_KERNEL_DATA, + MQX_VAL_MQX_INIT_STRUCT, }; enum mqx_arch { @@ -199,41 +188,33 @@ static int mqx_is_scheduler_running( uint32_t capability_value = 0; /* get '_mqx_kernel_data' symbol */ - if (ERROR_OK != mqx_get_symbol( - rtos, mqx_VAL_mqx_kernel_data, &kernel_data_symbol - )) { + if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_symbol) != ERROR_OK) return ERROR_FAIL; - } + /* get '_mqx_kernel_data' */ - if (ERROR_OK != mqx_get_member( - rtos, kernel_data_symbol, 0, 4, - "_mqx_kernel_data", &kernel_data_addr - )) { + if (mqx_get_member(rtos, kernel_data_symbol, 0, 4, + "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK) return ERROR_FAIL; - } + /* return if '_mqx_kernel_data' is NULL or default 0xFFFFFFFF */ - if (0 == kernel_data_addr || (uint32_t)(-1) == kernel_data_addr) + if (kernel_data_addr == 0 || kernel_data_addr == (uint32_t)(-1)) return ERROR_FAIL; /* get kernel_data->ADDRESSING_CAPABILITY */ - if (ERROR_OK != mqx_get_member( - rtos, kernel_data_addr, MQX_KERNEL_OFFSET_CAPABILITY, 4, - "kernel_data->ADDRESSING_CAPABILITY", (void *)&capability_value - )) { + if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_CAPABILITY, 4, + "kernel_data->ADDRESSING_CAPABILITY", (void *)&capability_value) != ERROR_OK) return ERROR_FAIL; - } + /* check first member, the '_mqx_kernel_data->ADDRESSING_CAPABILITY'. - it supose to be set to value 8 */ + it suppose to be set to value 8 */ if (capability_value != 8) { LOG_WARNING("MQX RTOS - value of '_mqx_kernel_data->ADDRESSING_CAPABILITY' contains invalid value"); return ERROR_FAIL; } /* get active ptr */ - if (ERROR_OK != mqx_get_member( - rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4, - "kernel_data->ACTIVE_PTR", (void *)&active_td_addr - )) { + if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4, + "kernel_data->ACTIVE_PTR", (void *)&active_td_addr) != ERROR_OK) return ERROR_FAIL; - } + /* active task is system task, scheduler has not not run yet */ system_td_addr = kernel_data_addr + MQX_KERNEL_OFFSET_SYSTEM_TASK; if (active_td_addr == system_td_addr) { @@ -251,8 +232,8 @@ static bool mqx_detect_rtos( ) { if ( - (target->rtos->symbols != NULL) && - (target->rtos->symbols[mqx_VAL_mqx_kernel_data].address != 0) + (target->rtos->symbols) && + (target->rtos->symbols[MQX_VAL_MQX_KERNEL_DATA].address != 0) ) { return true; } @@ -267,9 +248,8 @@ static int mqx_create( ) { /* check target name against supported architectures */ - int mqx_params_list_num = (sizeof(mqx_params_list)/sizeof(struct mqx_params)); - for (int i = 0; i < mqx_params_list_num; i++) { - if (0 == strcmp(mqx_params_list[i].target_name, target->type->name)) { + for (unsigned int i = 0; i < ARRAY_SIZE(mqx_params_list); i++) { + if (strcmp(mqx_params_list[i].target_name, target->type->name) == 0) { target->rtos->rtos_specific_params = (void *)&mqx_params_list[i]; /* LOG_DEBUG("MQX RTOS - valid architecture: %s", target->type->name); */ return 0; @@ -300,42 +280,34 @@ static int mqx_update_threads( /* clear old data */ rtos_free_threadlist(rtos); /* check scheduler */ - if (ERROR_OK != mqx_is_scheduler_running(rtos)) + if (mqx_is_scheduler_running(rtos) != ERROR_OK) return ERROR_FAIL; /* get kernel_data symbol */ - if (ERROR_OK != mqx_get_symbol( - rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr - )) { + if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_addr) != ERROR_OK) return ERROR_FAIL; - } + /* read kernel_data */ - if (ERROR_OK != mqx_get_member( - rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr - )) { + if (mqx_get_member(rtos, kernel_data_addr, 0, 4, + "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK) return ERROR_FAIL; - } + /* get task queue address */ task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST; /* get task queue size */ - if (ERROR_OK != mqx_get_member( - rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2, - "kernel_data->TD_LIST.SIZE", &task_queue_size - )) { + if (mqx_get_member(rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2, + "kernel_data->TD_LIST.SIZE", &task_queue_size) != ERROR_OK) return ERROR_FAIL; - } + /* get active ptr */ - if (ERROR_OK != mqx_get_member( - rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4, - "kernel_data->ACTIVE_PTR", (void *)&active_td_addr - )) { + if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4, + "kernel_data->ACTIVE_PTR", (void *)&active_td_addr) != ERROR_OK) return ERROR_FAIL; - } /* setup threads info */ rtos->thread_count = task_queue_size; rtos->current_thread = 0; rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail)); - if (NULL == rtos->thread_details) + if (!rtos->thread_details) return ERROR_FAIL; /* loop over each task and setup thread details, @@ -351,69 +323,54 @@ static int mqx_update_threads( uint8_t task_name[MQX_THREAD_NAME_LENGTH + 1]; uint32_t task_addr = 0, task_template = 0, task_state = 0; uint32_t task_name_addr = 0, task_id = 0, task_errno = 0; - uint32_t state_index = 0, state_max = 0; + uint32_t state_index = 0; uint32_t extra_info_length = 0; char *state_name = "Unknown"; /* set current taskpool address */ - if (ERROR_OK != mqx_get_member( - rtos, taskpool_addr, MQX_TASK_OFFSET_NEXT, 4, - "td_struct_ptr->NEXT", &taskpool_addr - )) { + if (mqx_get_member(rtos, taskpool_addr, MQX_TASK_OFFSET_NEXT, 4, + "td_struct_ptr->NEXT", &taskpool_addr) != ERROR_OK) return ERROR_FAIL; - } + /* get task address from taskpool */ task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST; /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */ - if (ERROR_OK != mqx_get_member( - rtos, task_addr, MQX_TASK_OFFSET_TEMPLATE, 4, - "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template - )) { + if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_TEMPLATE, 4, + "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template) != ERROR_OK) return ERROR_FAIL; - } + /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */ - if (ERROR_OK != mqx_get_member( - rtos, task_template, MQX_TASK_TEMPLATE_OFFSET_NAME, 4, - "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr - )) { + if (mqx_get_member(rtos, task_template, MQX_TASK_TEMPLATE_OFFSET_NAME, 4, + "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr) != ERROR_OK) return ERROR_FAIL; - } + /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */ - if (ERROR_OK != mqx_get_member( - rtos, task_name_addr, 0, MQX_THREAD_NAME_LENGTH, - "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name - )) { + if (mqx_get_member(rtos, task_name_addr, 0, MQX_THREAD_NAME_LENGTH, + "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name) != ERROR_OK) return ERROR_FAIL; - } + /* always terminate last character by force, otherwise openocd might fail if task_name has corrupted data */ task_name[MQX_THREAD_NAME_LENGTH] = '\0'; /* get value of 'td_struct_ptr->TASK_ID' */ - if (ERROR_OK != mqx_get_member( - rtos, task_addr, MQX_TASK_OFFSET_ID, 4, - "td_struct_ptr->TASK_ID", &task_id - )) { + if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ID, 4, + "td_struct_ptr->TASK_ID", &task_id) != ERROR_OK) return ERROR_FAIL; - } + /* get task errno */ - if (ERROR_OK != mqx_get_member( - rtos, task_addr, MQX_TASK_OFFSET_ERROR_CODE, 4, - "td_struct_ptr->TASK_ERROR_CODE", &task_errno - )) { + if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ERROR_CODE, 4, + "td_struct_ptr->TASK_ERROR_CODE", &task_errno) != ERROR_OK) return ERROR_FAIL; - } + /* get value of 'td_struct_ptr->STATE' */ - if (ERROR_OK != mqx_get_member( - rtos, task_addr, MQX_TASK_OFFSET_STATE, 4, - "td_struct_ptr->STATE", &task_state - )) { + if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_STATE, 4, + "td_struct_ptr->STATE", &task_state) != ERROR_OK) return ERROR_FAIL; - } + task_state &= MQX_TASK_STATE_MASK; /* and search for defined state */ - state_max = (sizeof(mqx_states)/sizeof(struct mqx_state)); - for (state_index = 0; (state_index < state_max); state_index++) { + for (state_index = 0; state_index < ARRAY_SIZE(mqx_states); state_index++) { if (mqx_states[state_index].state == task_state) { state_name = mqx_states[state_index].name; break; @@ -425,7 +382,7 @@ static int mqx_update_threads( rtos->thread_details[i].exists = true; /* set thread name */ rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1); - if (NULL == rtos->thread_details[i].thread_name_str) + if (!rtos->thread_details[i].thread_name_str) return ERROR_FAIL; strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name); /* set thread extra info @@ -437,7 +394,7 @@ static int mqx_update_threads( */ extra_info_length += strlen((void *)state_name) + 7 + 13 + 8 + 15 + 8; rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1); - if (NULL == rtos->thread_details[i].extra_info_str) + if (!rtos->thread_details[i].extra_info_str) return ERROR_FAIL; snprintf(rtos->thread_details[i].extra_info_str, extra_info_length, "State: %s, Address: 0x%" PRIx32 ", Error Code: %" PRIu32, @@ -470,29 +427,24 @@ static int mqx_get_thread_reg_list( LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id); return ERROR_FAIL; } - if (ERROR_OK != mqx_is_scheduler_running(rtos)) + if (mqx_is_scheduler_running(rtos) != ERROR_OK) return ERROR_FAIL; /* get kernel_data symbol */ - if (ERROR_OK != mqx_get_symbol( - rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr - )) { + if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_addr) != ERROR_OK) return ERROR_FAIL; - } + /* read kernel_data */ - if (ERROR_OK != mqx_get_member( - rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr - )) { + if (mqx_get_member(rtos, kernel_data_addr, 0, 4, + "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK) return ERROR_FAIL; - } + /* get task queue address */ task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST; /* get task queue size */ - if (ERROR_OK != mqx_get_member( - rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2, - "kernel_data->TD_LIST.SIZE", &task_queue_size - )) { + if (mqx_get_member(rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2, + "kernel_data->TD_LIST.SIZE", &task_queue_size) != ERROR_OK) return ERROR_FAIL; - } + /* search for taskid */ for ( uint32_t i = 0, taskpool_addr = task_queue_addr; @@ -503,21 +455,17 @@ static int mqx_get_thread_reg_list( uint32_t task_id = 0; /* set current taskpool address */ tmp_address = taskpool_addr; - if (ERROR_OK != mqx_get_member( - rtos, tmp_address, MQX_TASK_OFFSET_NEXT, 4, - "td_struct_ptr->NEXT", &taskpool_addr - )) { + if (mqx_get_member(rtos, tmp_address, MQX_TASK_OFFSET_NEXT, 4, + "td_struct_ptr->NEXT", &taskpool_addr) != ERROR_OK) return ERROR_FAIL; - } + /* get task address from taskpool */ task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST; /* get value of td_struct->TASK_ID */ - if (ERROR_OK != mqx_get_member( - rtos, task_addr, MQX_TASK_OFFSET_ID, 4, - "td_struct_ptr->TASK_ID", &task_id - )) { + if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ID, 4, + "td_struct_ptr->TASK_ID", &task_id) != ERROR_OK) return ERROR_FAIL; - } + /* found taskid, break */ if (task_id == thread_id) { my_task_addr = task_addr; @@ -529,21 +477,20 @@ static int mqx_get_thread_reg_list( return ERROR_FAIL; } /* get task stack head address */ - if (ERROR_OK != mqx_get_member( - rtos, my_task_addr, MQX_TASK_OFFSET_STACK, 4, "task->STACK_PTR", &stack_ptr - )) { + if (mqx_get_member(rtos, my_task_addr, MQX_TASK_OFFSET_STACK, 4, + "task->STACK_PTR", &stack_ptr) != ERROR_OK) return ERROR_FAIL; - } + return rtos_generic_stack_read( rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, reg_list, num_regs ); } /* API function, export list of required symbols */ -static int mqx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { - *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(symbol_table_elem_t)); - if (NULL == *symbol_list) + *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(struct symbol_table_elem)); + if (!*symbol_list) return ERROR_FAIL; /* export required symbols */ for (int i = 0; i < (int)(ARRAY_SIZE(mqx_symbol_list)); i++) @@ -551,7 +498,7 @@ static int mqx_get_symbol_list_to_lookup(symbol_table_elem_t *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 3c90625164..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, }; -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,319 +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 = { - 0x48, /* stack_registers_size */ - -1, /* stack_growth_direction */ - 17, /* num_output_registers */ - 0, /* stack_alignment */ - nuttx_stack_offsets_cortex_m /* register_offsets */ -}; - -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 = { - 0x8c, /* stack_registers_size */ - -1, /* stack_growth_direction */ - 17, /* num_output_registers */ - 0, /* stack_alignment */ - nuttx_stack_offsets_cortex_m_fpu /* register_offsets */ -}; + 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 != NULL) && - (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 == NULL) { - LOG_ERROR("No symbols for NuttX"); - return -3; + if (!rtos->symbols) { + 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; + } + + 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; } - /* readytorun head is current thread */ - if (g_tasklist[i].addr == rtos->symbols[0].address) - rtos->current_thread = head; + struct thread_detail *thread = &new_thread_details[thread_count]; + thread->threadid = tcbaddr; + thread->exists = true; + thread->extra_info_str = NULL; + rtos->thread_details = new_thread_details; + thread_count++; - 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 < sizeof(task_state_str)/sizeof(char *)) { - 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]); + 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]); + } - 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 (tcbinfo.name_off) { + thread->thread_name_str = calloc(NAME_SIZE + 1, sizeof(char)); + if (!thread->thread_name_str) { + ret = ERROR_FAIL; + goto errout; } - - tcb_addr = tcb.flink; + 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; + } - return rtos_generic_stack_read(rtos->target, stacking, - (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs); + 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, regsaddr, reg_list, num_regs); } -static int nuttx_get_symbol_list_to_lookup(symbol_table_elem_t *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 = (symbol_table_elem_t *) calloc(1, - sizeof(symbol_table_elem_t) * 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 15cbb0f856..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 @@ -35,7 +24,7 @@ static int riot_create(struct target *target); static int riot_update_threads(struct rtos *rtos); static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); -static int riot_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); struct riot_thread_state { int value; @@ -91,19 +80,19 @@ enum riot_symbol_values { RIOT_NAME_OFFSET, }; -/* refer RIOT core/sched.c */ -static const char *const riot_symbol_list[] = { - "sched_threads", - "sched_num_threads", - "sched_active_pid", - "max_threads", - "_tcb_name_offset", - NULL +struct riot_symbol { + const char *const name; + bool optional; }; -/* Define which symbols are not mandatory */ -static const enum riot_symbol_values riot_optional_symbols[] = { - RIOT_NAME_OFFSET, +/* refer RIOT core/sched.c */ +static struct riot_symbol const riot_symbol_list[] = { + {"sched_threads", false}, + {"sched_num_threads", false}, + {"sched_active_pid", false}, + {"max_threads", false}, + {"_tcb_name_offset", true}, + {NULL, false} }; const struct rtos_type riot_rtos = { @@ -118,25 +107,25 @@ const struct rtos_type riot_rtos = { static int riot_update_threads(struct rtos *rtos) { int retval; - unsigned int tasks_found = 0; + int tasks_found = 0; const struct riot_params *param; - if (rtos == NULL) + if (!rtos) return ERROR_FAIL; - if (rtos->rtos_specific_params == NULL) + if (!rtos->rtos_specific_params) return ERROR_FAIL; param = (const struct riot_params *)rtos->rtos_specific_params; - if (rtos->symbols == NULL) { + if (!rtos->symbols) { LOG_ERROR("No symbols for RIOT"); return ERROR_FAIL; } if (rtos->symbols[RIOT_THREADS_BASE].address == 0) { LOG_ERROR("Can't find symbol `%s`", - riot_symbol_list[RIOT_THREADS_BASE]); + riot_symbol_list[RIOT_THREADS_BASE].name); return ERROR_FAIL; } @@ -154,7 +143,7 @@ static int riot_update_threads(struct rtos *rtos) (uint16_t *)&active_pid); if (retval != ERROR_OK) { LOG_ERROR("Can't read symbol `%s`", - riot_symbol_list[RIOT_ACTIVE_PID]); + riot_symbol_list[RIOT_ACTIVE_PID].name); return retval; } rtos->current_thread = active_pid; @@ -167,10 +156,9 @@ static int riot_update_threads(struct rtos *rtos) (uint16_t *)&thread_count); if (retval != ERROR_OK) { LOG_ERROR("Can't read symbol `%s`", - riot_symbol_list[RIOT_NUM_THREADS]); + riot_symbol_list[RIOT_NUM_THREADS].name); return retval; } - rtos->thread_count = thread_count; /* read the maximum number of threads */ uint8_t max_threads = 0; @@ -179,9 +167,14 @@ static int riot_update_threads(struct rtos *rtos) &max_threads); if (retval != ERROR_OK) { LOG_ERROR("Can't read symbol `%s`", - riot_symbol_list[RIOT_MAX_THREADS]); + riot_symbol_list[RIOT_MAX_THREADS].name); return retval; } + if (thread_count > max_threads) { + LOG_ERROR("Thread count is invalid"); + return ERROR_FAIL; + } + rtos->thread_count = thread_count; /* Base address of thread array */ uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address; @@ -195,14 +188,14 @@ static int riot_update_threads(struct rtos *rtos) &name_offset); if (retval != ERROR_OK) { LOG_ERROR("Can't read symbol `%s`", - riot_symbol_list[RIOT_NAME_OFFSET]); + riot_symbol_list[RIOT_NAME_OFFSET].name); return retval; } } /* Allocate memory for thread description */ rtos->thread_details = calloc(thread_count, sizeof(struct thread_detail)); - if (rtos->thread_details == NULL) { + if (!rtos->thread_details) { LOG_ERROR("RIOT: out of memory"); return ERROR_FAIL; } @@ -211,13 +204,17 @@ static int riot_update_threads(struct rtos *rtos) char buffer[32]; for (unsigned int i = 0; i < max_threads; i++) { + if (tasks_found == rtos->thread_count) + break; + /* get pointer to tcb_t */ uint32_t tcb_pointer = 0; retval = target_read_u32(rtos->target, threads_base + (i * 4), &tcb_pointer); if (retval != ERROR_OK) { - LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]); + LOG_ERROR("Can't parse `%s`", + riot_symbol_list[RIOT_THREADS_BASE].name); goto error; } @@ -235,7 +232,8 @@ static int riot_update_threads(struct rtos *rtos) tcb_pointer + param->thread_status_offset, &status); if (retval != ERROR_OK) { - LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]); + LOG_ERROR("Can't parse `%s`", + riot_symbol_list[RIOT_THREADS_BASE].name); goto error; } @@ -255,7 +253,7 @@ static int riot_update_threads(struct rtos *rtos) strdup(riot_thread_states[k].desc); } - if (rtos->thread_details[tasks_found].extra_info_str == NULL) { + if (!rtos->thread_details[tasks_found].extra_info_str) { LOG_ERROR("RIOT: out of memory"); retval = ERROR_FAIL; goto error; @@ -269,7 +267,7 @@ static int riot_update_threads(struct rtos *rtos) &name_pointer); if (retval != ERROR_OK) { LOG_ERROR("Can't parse `%s`", - riot_symbol_list[RIOT_THREADS_BASE]); + riot_symbol_list[RIOT_THREADS_BASE].name); goto error; } @@ -280,7 +278,7 @@ static int riot_update_threads(struct rtos *rtos) (uint8_t *)&buffer); if (retval != ERROR_OK) { LOG_ERROR("Can't parse `%s`", - riot_symbol_list[RIOT_THREADS_BASE]); + riot_symbol_list[RIOT_THREADS_BASE].name); goto error; } @@ -297,7 +295,7 @@ static int riot_update_threads(struct rtos *rtos) strdup("Enable DEVELHELP to see task names"); } - if (rtos->thread_details[tasks_found].thread_name_str == NULL) { + if (!rtos->thread_details[tasks_found].thread_name_str) { LOG_ERROR("RIOT: out of memory"); retval = ERROR_FAIL; goto error; @@ -321,13 +319,13 @@ static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, int retval; const struct riot_params *param; - if (rtos == NULL) + if (!rtos) return ERROR_FAIL; if (thread_id == 0) return ERROR_FAIL; - if (rtos->rtos_specific_params == NULL) + if (!rtos->rtos_specific_params) return ERROR_FAIL; param = (const struct riot_params *)rtos->rtos_specific_params; @@ -339,7 +337,7 @@ static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, threads_base + (thread_id * 4), &tcb_pointer); if (retval != ERROR_OK) { - LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]); + LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name); return retval; } @@ -349,7 +347,7 @@ static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, tcb_pointer + param->thread_sp_offset, &stackptr); if (retval != ERROR_OK) { - LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]); + LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name); return retval; } @@ -360,26 +358,18 @@ static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, num_regs); } -static int riot_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { - *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(symbol_table_elem_t)); + *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(struct symbol_table_elem)); - if (*symbol_list == NULL) { + if (!*symbol_list) { LOG_ERROR("RIOT: out of memory"); return ERROR_FAIL; } for (unsigned int i = 0; i < ARRAY_SIZE(riot_symbol_list); i++) { - (*symbol_list)[i].symbol_name = riot_symbol_list[i]; - (*symbol_list)[i].optional = false; - - /* Lookup if symbol is optional */ - for (unsigned int k = 0; k < sizeof(riot_optional_symbols); k++) { - if (i == riot_optional_symbols[k]) { - (*symbol_list)[i].optional = true; - break; - } - } + (*symbol_list)[i].symbol_name = riot_symbol_list[i].name; + (*symbol_list)[i].optional = riot_symbol_list[i].optional; } return ERROR_OK; @@ -387,7 +377,7 @@ static int riot_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) static bool riot_detect_rtos(struct target *target) { - if ((target->rtos->symbols != NULL) && + if ((target->rtos->symbols) && (target->rtos->symbols[RIOT_THREADS_BASE].address != 0)) { /* looks like RIOT */ return true; @@ -401,7 +391,7 @@ static int riot_create(struct target *target) /* lookup if target is supported by RIOT */ while ((i < RIOT_NUM_PARAMS) && - (0 != strcmp(riot_params_list[i].target_name, target->type->name))) { + (strcmp(riot_params_list[i].target_name, target->type->name) != 0)) { i++; } if (i >= RIOT_NUM_PARAMS) { @@ -416,7 +406,7 @@ static int riot_create(struct target *target) /* Stacking is different depending on architecture */ struct armv7m_common *armv7m_target = target_to_armv7m(target); - if (armv7m_target->arm.is_armv6m) + if (armv7m_target->arm.arch == ARM_ARCH_V6M) stacking_info = &rtos_riot_cortex_m0_stacking; else if (is_armv7m(armv7m_target)) stacking_info = &rtos_riot_cortex_m34_stacking; 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 62b65aae12..0df1182c0a 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 @@ -26,38 +15,26 @@ #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_os; -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; - -static struct rtos_type *rtos_types[] = { - &ThreadX_rtos, - &FreeRTOS_rtos, - &eCos_rtos, - &Linux_os, +static const struct rtos_type *rtos_types[] = { + &threadx_rtos, + &freertos_rtos, + &ecos_rtos, + &linux_rtos, &chibios_rtos, &chromium_ec_rtos, - &embKernel_rtos, + &embkernel_rtos, &mqx_rtos, - &uCOS_III_rtos, + &ucos_iii_rtos, &nuttx_rtos, &riot_rtos, + &zephyr_rtos, + &rtkernel_rtos, /* keep this as last, as it always matches with rtos auto */ &hwthread_rtos, NULL }; -int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size); +static int rtos_try_next(struct target *target); int rtos_smp_init(struct target *target) { @@ -75,7 +52,7 @@ static int rtos_target_for_threadid(struct connection *connection, int64_t threa 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 rtos *os = target->rtos = calloc(1, sizeof(struct rtos)); @@ -101,15 +78,16 @@ 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) { int ret = os_alloc(target, ostype); - if (JIM_OK == ret) { + if (ret == JIM_OK) { ret = target->rtos->type->create(target); if (ret != JIM_OK) os_free(target); @@ -118,7 +96,7 @@ static int os_alloc_create(struct target *target, struct rtos_type *ostype) return ret; } -int rtos_create(Jim_GetOptInfo *goi, struct target *target) +int rtos_create(struct jim_getopt_info *goi, struct target *target) { int x; const char *cp; @@ -132,11 +110,14 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target) os_free(target); - e = Jim_GetOpt_String(goi, &cp, NULL); + e = jim_getopt_string(goi, &cp, NULL); if (e != JIM_OK) return e; - if (0 == strcmp(cp, "auto")) { + 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 * finds all symbols for any RTOS. See rtos_qsymbol(). */ @@ -148,14 +129,14 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target) } for (x = 0; rtos_types[x]; x++) - if (0 == strcmp(cp, rtos_types[x]->name)) + if (strcmp(cp, rtos_types[x]->name) == 0) return os_alloc_create(target, rtos_types[x]); Jim_SetResultFormatted(goi->interp, "Unknown RTOS type %s, try one of: ", cp); 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; } @@ -168,41 +149,38 @@ void rtos_destroy(struct target *target) int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); - if (target->rtos == NULL) + if (!target->rtos) return rtos_thread_packet(connection, packet, packet_size); /* thread not *found*/ return target->rtos->gdb_thread_packet(connection, packet, packet_size); } -static symbol_table_elem_t *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) { - symbol_table_elem_t *s; - - 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; 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 (symbol_table_elem_t *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. @@ -222,6 +200,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) @@ -230,7 +214,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 */ - symbol_table_elem_t *next_sym = NULL; + struct symbol_table_elem *next_sym = NULL; struct target *target = get_target_from_connection(connection); struct rtos *os = target->rtos; @@ -243,26 +227,62 @@ 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'; + } } } - next_sym = next_symbol(os, cur_sym, addr); + + LOG_DEBUG("RTOS: Address of symbol '%s%s' is 0x%" PRIx64, cur_sym, cur_suffix, 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%s' that we did not ask for", cur_sym, cur_suffix); + goto done; + } if (!next_sym->symbol_name) { /* No more symbols need looking up */ @@ -282,15 +302,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%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); @@ -302,13 +333,13 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa struct target *target = get_target_from_connection(connection); if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) { - if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) && + if ((target->rtos) && (target->rtos->thread_details) && (target->rtos->thread_count != 0)) { threadid_t threadid = 0; int found = -1; sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid); - if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) { + if ((target->rtos) && (target->rtos->thread_details)) { int thread_num; for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) { if (target->rtos->thread_details[thread_num].threadid == threadid) { @@ -325,17 +356,17 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa struct thread_detail *detail = &target->rtos->thread_details[found]; int str_size = 0; - if (detail->thread_name_str != NULL) + if (detail->thread_name_str) str_size += strlen(detail->thread_name_str); - if (detail->extra_info_str != NULL) + if (detail->extra_info_str) str_size += strlen(detail->extra_info_str); char *tmp_str = calloc(str_size + 9, sizeof(char)); char *tmp_str_ptr = tmp_str; - if (detail->thread_name_str != NULL) + if (detail->thread_name_str) tmp_str_ptr += sprintf(tmp_str_ptr, "Name: %s", detail->thread_name_str); - if (detail->extra_info_str != NULL) { + if (detail->extra_info_str) { if (tmp_str_ptr != tmp_str) tmp_str_ptr += sprintf(tmp_str_ptr, ", "); tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->extra_info_str); @@ -367,7 +398,7 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa return ERROR_OK; } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { int i; - if (target->rtos != NULL) { + if (target->rtos) { if (target->rtos->thread_count == 0) { gdb_put_packet(connection, "l", 1); } else { @@ -400,7 +431,7 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa * otherwise it gets incorrectly handled */ return GDB_THREAD_PACKET_NOT_CONSUMED; } else if (strncmp(packet, "qC", 2) == 0) { - if (target->rtos != NULL) { + if (target->rtos) { char buffer[19]; int size; size = snprintf(buffer, 19, "QC%016" PRIx64, target->rtos->current_thread); @@ -412,7 +443,7 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa threadid_t threadid; int found = -1; sscanf(packet, "T%" SCNx64, &threadid); - if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) { + if ((target->rtos) && (target->rtos->thread_details)) { int thread_num; for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) { if (target->rtos->thread_details[thread_num].threadid == threadid) { @@ -428,7 +459,7 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa return ERROR_OK; } else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for * all other operations ) */ - if ((packet[1] == 'g') && (target->rtos != NULL)) { + if ((packet[1] == 'g') && (target->rtos)) { threadid_t threadid; sscanf(packet, "Hg%16" SCNx64, &threadid); LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64, threadid); @@ -473,7 +504,7 @@ int rtos_get_gdb_reg(struct connection *connection, int reg_num) { struct target *target = get_target_from_connection(connection); int64_t current_threadid = target->rtos->current_threadid; - if ((target->rtos != NULL) && (current_threadid != -1) && + if ((target->rtos) && (current_threadid != -1) && (current_threadid != 0) && ((current_threadid != target->rtos->current_thread) || (target->smp))) { /* in smp several current thread are possible */ @@ -525,7 +556,7 @@ int rtos_get_gdb_reg_list(struct connection *connection) { struct target *target = get_target_from_connection(connection); int64_t current_threadid = target->rtos->current_threadid; - if ((target->rtos != NULL) && (current_threadid != -1) && + if ((target->rtos) && (current_threadid != -1) && (current_threadid != 0) && ((current_threadid != target->rtos->current_thread) || (target->smp))) { /* in smp several current thread are possible */ @@ -559,8 +590,8 @@ int rtos_set_reg(struct connection *connection, int reg_num, { struct target *target = get_target_from_connection(connection); int64_t current_threadid = target->rtos->current_threadid; - if ((target->rtos != NULL) && - (target->rtos->type->set_reg != NULL) && + if ((target->rtos) && + (target->rtos->type->set_reg) && (current_threadid != -1) && (current_threadid != 0)) { return target->rtos->type->set_reg(target->rtos, reg_num, reg_value); @@ -586,7 +617,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"); @@ -601,8 +635,8 @@ int rtos_generic_stack_read(struct target *target, LOG_OUTPUT("\r\n"); #endif - int64_t new_stack_ptr; - if (stacking->calculate_process_stack != NULL) { + target_addr_t new_stack_ptr; + if (stacking->calculate_process_stack) { new_stack_ptr = stacking->calculate_process_stack(target, stack_data, stacking, stack_ptr); } else { @@ -629,10 +663,10 @@ int rtos_generic_stack_read(struct target *target, return ERROR_OK; } -int rtos_try_next(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; @@ -653,7 +687,7 @@ int rtos_try_next(struct target *target) int rtos_update_threads(struct target *target) { - if ((target->rtos != NULL) && (target->rtos->type != NULL)) + if ((target->rtos) && (target->rtos->type)) target->rtos->type->update_threads(target->rtos); return ERROR_OK; } @@ -675,3 +709,19 @@ void rtos_free_threadlist(struct rtos *rtos) rtos->current_thread = 0; } } + +int rtos_read_buffer(struct target *target, target_addr_t address, + uint32_t size, uint8_t *buffer) +{ + if (target->rtos->type->read_buffer) + return target->rtos->type->read_buffer(target->rtos, address, size, buffer); + return ERROR_NOT_IMPLEMENTED; +} + +int rtos_write_buffer(struct target *target, target_addr_t address, + uint32_t size, const uint8_t *buffer) +{ + if (target->rtos->type->write_buffer) + return target->rtos->type->write_buffer(target->rtos, address, size, buffer); + return ERROR_NOT_IMPLEMENTED; +} diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index c755eec291..5ba8b26945 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 @@ -21,7 +10,7 @@ #include "server/server.h" #include "target/target.h" -#include <jim-nvp.h> +#include <helper/jim-nvp.h> typedef int64_t threadid_t; typedef int64_t symbol_address_t; @@ -31,11 +20,11 @@ struct reg; /** * Table should be terminated by an element with NULL in symbol_name */ -typedef struct symbol_table_elem_struct { +struct symbol_table_elem { const char *symbol_name; symbol_address_t address; bool optional; -} symbol_table_elem_t; +}; struct thread_detail { threadid_t threadid; @@ -47,7 +36,7 @@ struct thread_detail { struct rtos { const struct rtos_type *type; - symbol_table_elem_t *symbols; + struct symbol_table_elem *symbols; struct target *target; /* add a context variable instead of global variable */ /* The thread currently selected by gdb. */ @@ -78,10 +67,17 @@ struct rtos_type { struct rtos_reg **reg_list, int *num_regs); int (*get_thread_reg)(struct rtos *rtos, int64_t thread_id, uint32_t reg_num, struct rtos_reg *reg); - int (*get_symbol_list_to_lookup)(symbol_table_elem_t *symbol_list[]); + int (*get_symbol_list_to_lookup)(struct symbol_table_elem *symbol_list[]); int (*clean)(struct target *target); char * (*ps_command)(struct target *target); int (*set_reg)(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); + /* Implement these if different threads in the RTOS can see memory + * differently (for instance because address translation might be different + * for each thread). */ + int (*read_buffer)(struct rtos *rtos, target_addr_t address, uint32_t size, + uint8_t *buffer); + int (*write_buffer)(struct rtos *rtos, target_addr_t address, uint32_t size, + const uint8_t *buffer); }; struct stack_register_offset { @@ -101,16 +97,23 @@ struct rtos_register_stacking { * just use stacking->stack_registers_size * stack_growth_direction * to calculate adjustment. */ - int64_t (*calculate_process_stack)(struct target *target, + target_addr_t (*calculate_process_stack)(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, - int64_t stack_ptr); + target_addr_t stack_ptr); const struct stack_register_offset *register_offsets; + /* 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) -int rtos_create(Jim_GetOptInfo *goi, struct target *target); +int rtos_create(struct jim_getopt_info *goi, struct target *target); void rtos_destroy(struct target *target); int rtos_set_reg(struct connection *connection, int reg_num, uint8_t *reg_value); @@ -119,8 +122,8 @@ int rtos_generic_stack_read(struct target *target, int64_t stack_ptr, struct rtos_reg **reg_list, int *num_regs); -int rtos_try_next(struct target *target); 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); @@ -128,5 +131,24 @@ void rtos_free_threadlist(struct rtos *rtos); int rtos_smp_init(struct target *target); /* function for handling symbol access */ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_size); +int rtos_read_buffer(struct target *target, target_addr_t address, + uint32_t size, uint8_t *buffer); +int rtos_write_buffer(struct target *target, target_addr_t address, + uint32_t size, const uint8_t *buffer); + +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 2887930bdc..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,15 +33,14 @@ 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 = { - 0x24, /* stack_registers_size */ - -1, /* stack_growth_direction */ - ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - NULL, /* stack_alignment */ - rtos_chibios_arm_v7m_stack_offsets /* register_offsets */ + .stack_registers_size = 0x24, + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .register_offsets = rtos_chibios_arm_v7m_stack_offsets }; static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets_w_fpu[ARMV7M_NUM_CORE_REGS] = { @@ -71,13 +60,12 @@ 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 = { - 0x64, /* stack_registers_size */ - -1, /* stack_growth_direction */ - ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - NULL, /* stack_alignment */ - rtos_chibios_arm_v7m_stack_offsets_w_fpu /* register_offsets */ + .stack_registers_size = 0x64, + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .register_offsets = rtos_chibios_arm_v7m_stack_offsets_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 ca98d94179..cae271270a 100644 --- a/src/rtos/rtos_ecos_stackings.c +++ b/src/rtos/rtos_ecos_stackings.c @@ -1,28 +1,22 @@ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * 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. */ -static const struct stack_register_offset rtos_eCos_Cortex_M3_stack_offsets[ARMV7M_NUM_CORE_REGS] = { +/* 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 */ { ARMV7M_R2, 0x14, 32 }, /* r2 */ @@ -39,13 +33,13 @@ 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 = { - 0x44, /* stack_registers_size */ - -1, /* stack_growth_direction */ - ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - rtos_generic_stack_align8, /* stack_alignment */ - rtos_eCos_Cortex_M3_stack_offsets /* register_offsets */ +const struct rtos_register_stacking rtos_ecos_cortex_m3_stacking = { + .stack_registers_size = 0x44, + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .calculate_process_stack = rtos_generic_stack_align8, + .register_offsets = rtos_ecos_cortex_m3_stack_offsets }; diff --git a/src/rtos/rtos_ecos_stackings.h b/src/rtos/rtos_ecos_stackings.h index 951f7de506..a6bcf1acbb 100644 --- a/src/rtos/rtos_ecos_stackings.h +++ b/src/rtos/rtos_ecos_stackings.h @@ -1,28 +1,10 @@ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * 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; +extern const struct rtos_register_stacking rtos_ecos_cortex_m3_stacking; #endif /* OPENOCD_RTOS_RTOS_ECOS_STACKINGS_H */ diff --git a/src/rtos/rtos_embkernel_stackings.c b/src/rtos/rtos_embkernel_stackings.c index 543a8cd2ac..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,8 +12,9 @@ #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] = { +static const struct stack_register_offset rtos_embkernel_cortex_m_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x24, 32 }, /* r0 */ { ARMV7M_R1, 0x28, 32 }, /* r1 */ { ARMV7M_R2, 0x2c, 32 }, /* r2 */ @@ -41,13 +31,13 @@ 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 = { - 0x40, /* stack_registers_size */ - -1, /* stack_growth_direction */ - ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - rtos_generic_stack_align8, /* stack_alignment */ - rtos_embkernel_Cortex_M_stack_offsets /* register_offsets */ +const struct rtos_register_stacking rtos_embkernel_cortex_m_stacking = { + .stack_registers_size = 0x40, + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .calculate_process_stack = rtos_generic_stack_align8, + .register_offsets = rtos_embkernel_cortex_m_stack_offsets }; diff --git a/src/rtos/rtos_embkernel_stackings.h b/src/rtos/rtos_embkernel_stackings.h index 89a0c2f125..87bd0e73b8 100644 --- a/src/rtos/rtos_embkernel_stackings.h +++ b/src/rtos/rtos_embkernel_stackings.h @@ -1,30 +1,15 @@ +/* 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; +extern const struct rtos_register_stacking rtos_embkernel_cortex_m_stacking; #endif /* OPENOCD_RTOS_RTOS_EMBKERNEL_STACKINGS_H */ diff --git a/src/rtos/rtos_mqx_stackings.c b/src/rtos/rtos_mqx_stackings.c index f2d3b22270..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,13 +56,12 @@ 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 = { - 0x4C, /* stack_registers_size, calculate offset base address */ - -1, /* stack_growth_direction */ - ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - NULL, /* stack_alignment */ - rtos_mqx_arm_v7m_stack_offsets /* register_offsets */ + .stack_registers_size = 0x4C, /* calculate offset base address */ + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .register_offsets = rtos_mqx_arm_v7m_stack_offsets }; 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 23f4d1786e..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,16 +12,17 @@ #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 */ -static int64_t rtos_riot_cortex_m_stack_align(struct target *target, +static target_addr_t rtos_riot_cortex_m_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, - int64_t stack_ptr) + target_addr_t stack_ptr) { const int XPSR_OFFSET = 0x40; - return rtos_Cortex_M_stack_align(target, stack_data, stacking, + return rtos_cortex_m_stack_align(target, stack_data, stacking, stack_ptr, XPSR_OFFSET); } @@ -54,15 +44,15 @@ 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 = { - 0x44, /* stack_registers_size */ - -1, /* stack_growth_direction */ - ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - rtos_riot_cortex_m_stack_align, /* stack_alignment */ - rtos_riot_cortex_m0_stack_offsets /* register_offsets */ + .stack_registers_size = 0x44, + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .calculate_process_stack = rtos_riot_cortex_m_stack_align, + .register_offsets = rtos_riot_cortex_m0_stack_offsets }; /* see thread_arch.c */ @@ -83,13 +73,13 @@ 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 = { - 0x44, /* stack_registers_size */ - -1, /* stack_growth_direction */ - ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - rtos_riot_cortex_m_stack_align, /* stack_alignment */ - rtos_riot_cortex_m34_stack_offsets /* register_offsets */ + .stack_registers_size = 0x44, + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .calculate_process_stack = rtos_riot_cortex_m_stack_align, + .register_offsets = rtos_riot_cortex_m34_stack_offsets }; 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 7b054cbbcb..5478080cf7 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 @@ -22,8 +11,9 @@ #include "rtos.h" #include "target/armv7m.h" +#include "rtos_standard_stackings.h" -static const struct stack_register_offset rtos_standard_Cortex_M3_stack_offsets[ARMV7M_NUM_CORE_REGS] = { +static const struct stack_register_offset rtos_standard_cortex_m3_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x20, 32 }, /* r0 */ { ARMV7M_R1, 0x24, 32 }, /* r1 */ { ARMV7M_R2, 0x28, 32 }, /* r2 */ @@ -40,10 +30,10 @@ 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[] = { +static const struct stack_register_offset rtos_standard_cortex_m4f_stack_offsets[] = { { ARMV7M_R0, 0x24, 32 }, /* r0 */ { ARMV7M_R1, 0x28, 32 }, /* r1 */ { ARMV7M_R2, 0x2c, 32 }, /* r2 */ @@ -60,10 +50,10 @@ 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[] = { +static const struct stack_register_offset rtos_standard_cortex_m4f_fpu_stack_offsets[] = { { ARMV7M_R0, 0x64, 32 }, /* r0 */ { ARMV7M_R1, 0x68, 32 }, /* r1 */ { ARMV7M_R2, 0x6c, 32 }, /* r2 */ @@ -80,11 +70,11 @@ 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 */ }; -static const struct stack_register_offset rtos_standard_Cortex_R4_stack_offsets[] = { +static const struct stack_register_offset rtos_standard_cortex_r4_stack_offsets[] = { { 0, 0x08, 32 }, /* r0 (a1) */ { 1, 0x0c, 32 }, /* r1 (a2) */ { 2, 0x10, 32 }, /* r2 (a3) */ @@ -113,68 +103,29 @@ 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 int64_t rtos_generic_stack_align(struct target *target, +static target_addr_t rtos_generic_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, - int64_t stack_ptr, int align) + target_addr_t stack_ptr, int align) { - int64_t new_stack_ptr; - int64_t aligned_stack_ptr; + target_addr_t new_stack_ptr; + target_addr_t aligned_stack_ptr; new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size; - aligned_stack_ptr = new_stack_ptr & ~((int64_t)align - 1); + aligned_stack_ptr = new_stack_ptr & ~((target_addr_t)align - 1); if (aligned_stack_ptr != new_stack_ptr && stacking->stack_growth_direction == -1) { /* If we have a downward growing stack, the simple alignment code * above results in a wrong result (since it rounds down to nearest * alignment). We want to round up so add an extra align. */ - aligned_stack_ptr += (int64_t)align; + aligned_stack_ptr += (target_addr_t)align; } return aligned_stack_ptr; } -int64_t rtos_generic_stack_align8(struct target *target, +target_addr_t rtos_generic_stack_align8(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, - int64_t stack_ptr) + target_addr_t stack_ptr) { return rtos_generic_stack_align(target, stack_data, stacking, stack_ptr, 8); @@ -199,13 +150,13 @@ int64_t rtos_generic_stack_align8(struct target *target, * This is just a helper function for use in the calculate_process_stack * function for a given architecture/rtos. */ -int64_t rtos_Cortex_M_stack_align(struct target *target, +target_addr_t rtos_cortex_m_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, - int64_t stack_ptr, size_t xpsr_offset) + target_addr_t stack_ptr, size_t xpsr_offset) { const uint32_t ALIGN_NEEDED = (1 << 9); uint32_t xpsr; - int64_t new_stack_ptr; + target_addr_t new_stack_ptr; new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size; @@ -220,70 +171,62 @@ int64_t rtos_Cortex_M_stack_align(struct target *target, return new_stack_ptr; } -static int64_t rtos_standard_Cortex_M3_stack_align(struct target *target, +static target_addr_t rtos_standard_cortex_m3_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, - int64_t stack_ptr) + target_addr_t stack_ptr) { const int XPSR_OFFSET = 0x3c; - return rtos_Cortex_M_stack_align(target, stack_data, stacking, + return rtos_cortex_m_stack_align(target, stack_data, stacking, stack_ptr, XPSR_OFFSET); } -static int64_t rtos_standard_Cortex_M4F_stack_align(struct target *target, +static target_addr_t rtos_standard_cortex_m4f_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, - int64_t stack_ptr) + target_addr_t stack_ptr) { const int XPSR_OFFSET = 0x40; - return rtos_Cortex_M_stack_align(target, stack_data, stacking, + return rtos_cortex_m_stack_align(target, stack_data, stacking, stack_ptr, XPSR_OFFSET); } -static int64_t rtos_standard_Cortex_M4F_FPU_stack_align(struct target *target, +static target_addr_t rtos_standard_cortex_m4f_fpu_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, - int64_t stack_ptr) + target_addr_t stack_ptr) { const int XPSR_OFFSET = 0x80; - return rtos_Cortex_M_stack_align(target, stack_data, stacking, + return rtos_cortex_m_stack_align(target, stack_data, stacking, stack_ptr, XPSR_OFFSET); } -const struct rtos_register_stacking rtos_standard_Cortex_M3_stacking = { - 0x40, /* stack_registers_size */ - -1, /* stack_growth_direction */ - ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - rtos_standard_Cortex_M3_stack_align, /* stack_alignment */ - rtos_standard_Cortex_M3_stack_offsets /* register_offsets */ -}; - -const struct rtos_register_stacking rtos_standard_Cortex_M4F_stacking = { - 0x44, /* stack_registers_size 4 more for LR*/ - -1, /* stack_growth_direction */ - ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - rtos_standard_Cortex_M4F_stack_align, /* stack_alignment */ - rtos_standard_Cortex_M4F_stack_offsets /* register_offsets */ +const struct rtos_register_stacking rtos_standard_cortex_m3_stacking = { + .stack_registers_size = 0x40, + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .calculate_process_stack = rtos_standard_cortex_m3_stack_align, + .register_offsets = rtos_standard_cortex_m3_stack_offsets }; -const struct rtos_register_stacking rtos_standard_Cortex_M4F_FPU_stacking = { - 0xcc, /* stack_registers_size 4 more for LR + 48 more for FPU S0-S15 register*/ - -1, /* stack_growth_direction */ - ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - rtos_standard_Cortex_M4F_FPU_stack_align, /* stack_alignment */ - rtos_standard_Cortex_M4F_FPU_stack_offsets /* register_offsets */ +const struct rtos_register_stacking rtos_standard_cortex_m4f_stacking = { + .stack_registers_size = 0x44, + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .calculate_process_stack = rtos_standard_cortex_m4f_stack_align, + .register_offsets = rtos_standard_cortex_m4f_stack_offsets }; -const struct rtos_register_stacking rtos_standard_Cortex_R4_stacking = { - 0x48, /* stack_registers_size */ - -1, /* stack_growth_direction */ - 26, /* num_output_registers */ - rtos_generic_stack_align8, /* stack_alignment */ - rtos_standard_Cortex_R4_stack_offsets /* register_offsets */ +const struct rtos_register_stacking rtos_standard_cortex_m4f_fpu_stacking = { + .stack_registers_size = 0xcc, + .stack_growth_direction = -1, + .num_output_registers = ARMV7M_NUM_CORE_REGS, + .calculate_process_stack = rtos_standard_cortex_m4f_fpu_stack_align, + .register_offsets = rtos_standard_cortex_m4f_fpu_stack_offsets }; -const struct rtos_register_stacking rtos_standard_NDS32_N1068_stacking = { - 0x90, /* stack_registers_size */ - -1, /* stack_growth_direction */ - 32, /* num_output_registers */ - rtos_generic_stack_align8, /* stack_alignment */ - rtos_standard_NDS32_N1068_stack_offsets /* register_offsets */ +const struct rtos_register_stacking rtos_standard_cortex_r4_stacking = { + .stack_registers_size = 0x48, + .stack_growth_direction = -1, + .num_output_registers = 26, + .calculate_process_stack = rtos_generic_stack_align8, + .register_offsets = rtos_standard_cortex_r4_stack_offsets }; diff --git a/src/rtos/rtos_standard_stackings.h b/src/rtos/rtos_standard_stackings.h index 6971efd1ec..99fbe07e48 100644 --- a/src/rtos/rtos_standard_stackings.h +++ b/src/rtos/rtos_standard_stackings.h @@ -1,40 +1,24 @@ +/* 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; -int64_t rtos_generic_stack_align8(struct target *target, +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; +target_addr_t rtos_generic_stack_align8(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, - int64_t stack_ptr); -int64_t rtos_Cortex_M_stack_align(struct target *target, + target_addr_t stack_ptr); +target_addr_t rtos_cortex_m_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, - int64_t stack_ptr, size_t xpsr_offset); + target_addr_t stack_ptr, size_t xpsr_offset); #endif /* OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H */ diff --git a/src/rtos/rtos_ucos_iii_stackings.c b/src/rtos/rtos_ucos_iii_stackings.c index d093563bae..f1e248231e 100644 --- a/src/rtos/rtos_ucos_iii_stackings.c +++ b/src/rtos/rtos_ucos_iii_stackings.c @@ -1,32 +1,21 @@ +// 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[] = { +static const struct stack_register_offset rtos_ucos_iii_cortex_m_stack_offsets[] = { { ARMV7M_R0, 0x20, 32 }, /* r0 */ { ARMV7M_R1, 0x24, 32 }, /* r1 */ { ARMV7M_R2, 0x28, 32 }, /* r2 */ @@ -43,10 +32,10 @@ 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[] = { +static const struct stack_register_offset rtos_ucos_iii_esi_risc_stack_offsets[] = { { ESIRISC_SP, -2, 32 }, /* sp */ { ESIRISC_RA, 0x48, 32 }, /* ra */ { ESIRISC_R2, 0x44, 32 }, /* r2 */ @@ -67,18 +56,17 @@ static const struct stack_register_offset rtos_uCOS_III_eSi_RISC_stack_offsets[] { ESIRISC_CAS, 0x08, 32 }, /* CAS */ }; -const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = { - 0x40, /* stack_registers_size */ - -1, /* stack_growth_direction */ - ARRAY_SIZE(rtos_uCOS_III_Cortex_M_stack_offsets), /* num_output_registers */ - rtos_generic_stack_align8, /* stack_alignment */ - rtos_uCOS_III_Cortex_M_stack_offsets /* register_offsets */ +const struct rtos_register_stacking rtos_ucos_iii_cortex_m_stacking = { + .stack_registers_size = 0x40, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(rtos_ucos_iii_cortex_m_stack_offsets), + .calculate_process_stack = rtos_generic_stack_align8, + .register_offsets = rtos_ucos_iii_cortex_m_stack_offsets }; -const struct rtos_register_stacking rtos_uCOS_III_eSi_RISC_stacking = { - 0x4c, /* stack_registers_size */ - -1, /* stack_growth_direction */ - ARRAY_SIZE(rtos_uCOS_III_eSi_RISC_stack_offsets), /* num_output_registers */ - NULL, /* stack_alignment */ - rtos_uCOS_III_eSi_RISC_stack_offsets /* register_offsets */ +const struct rtos_register_stacking rtos_ucos_iii_esi_risc_stacking = { + .stack_registers_size = 0x4c, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(rtos_ucos_iii_esi_risc_stack_offsets), + .register_offsets = 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 a9398138b5..dfe60b27b4 100644 --- a/src/rtos/rtos_ucos_iii_stackings.h +++ b/src/rtos/rtos_ucos_iii_stackings.h @@ -1,31 +1,16 @@ +/* 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; +extern const struct rtos_register_stacking rtos_ucos_iii_cortex_m_stacking; +extern const struct rtos_register_stacking rtos_ucos_iii_esi_risc_stacking; #endif /* OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H */ diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c index 304d07c591..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 @@ -37,9 +26,15 @@ #define UCOS_III_MAX_THREADS 256 #endif -struct uCOS_III_params { +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,44 +42,26 @@ 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[] = { +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, }, }; -static const char * const uCOS_III_symbol_list[] = { +static const char * const ucos_iii_symbol_list[] = { "OSRunning", "OSTCBCurPtr", "OSTaskDbgListPtr", @@ -100,22 +77,22 @@ static const char * const uCOS_III_symbol_list[] = { NULL }; -enum uCOS_III_symbol_values { - uCOS_III_VAL_OSRunning, - uCOS_III_VAL_OSTCBCurPtr, - uCOS_III_VAL_OSTaskDbgListPtr, - uCOS_III_VAL_OSTaskQty, +enum ucos_iii_symbol_values { + UCOS_III_VAL_OS_RUNNING, + UCOS_III_VAL_OS_TCB_CUR_PTR, + UCOS_III_VAL_OS_TASK_DBG_LIST_PTR, + UCOS_III_VAL_OS_TASK_QTY, /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */ - uCOS_III_VAL_OS_TCB_StkPtr_offset, - uCOS_III_VAL_OS_TCB_NamePtr_offset, - uCOS_III_VAL_OS_TCB_TaskState_offset, - uCOS_III_VAL_OS_TCB_Prio_offset, - uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset, - uCOS_III_VAL_OS_TCB_DbgNextPtr_offset, + UCOS_III_VAL_OS_TCB_STK_PTR_OFFSET, + UCOS_III_VAL_OS_TCB_NAME_PTR_OFFSET, + UCOS_III_VAL_OS_TCB_TASK_STATE_OFFSET, + UCOS_III_VAL_OS_TCB_PRIO_OFFSET, + UCOS_III_VAL_OS_TCB_DBG_PREV_PTR_OFFSET, + UCOS_III_VAL_OS_TCB_DBG_NEXT_PTR_OFFSET, }; -static const char * const uCOS_III_thread_state_list[] = { +static const char * const ucos_iii_thread_state_list[] = { "Ready", "Delay", "Pend", @@ -126,10 +103,10 @@ static const char * const uCOS_III_thread_state_list[] = { "Pend Timeout Suspended", }; -static int uCOS_III_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address, +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, +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; @@ -164,17 +141,17 @@ static int uCOS_III_find_thread_address(struct rtos *rtos, threadid_t threadid, return ERROR_OK; } -static int uCOS_III_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address) +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 */ symbol_address_t thread_list_address = 0; retval = target_read_memory(rtos->target, - rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address, - params->pointer_width, + rtos->symbols[UCOS_III_VAL_OS_TASK_DBG_LIST_PTR].address, + 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) { @@ -200,39 +177,39 @@ static int uCOS_III_find_last_thread_address(struct rtos *rtos, symbol_address_t return ERROR_OK; } -static int uCOS_III_update_thread_offsets(struct rtos *rtos) +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; const struct thread_offset_map { - enum uCOS_III_symbol_values symbol_value; + enum ucos_iii_symbol_values symbol_value; symbol_address_t *thread_offset; } thread_offset_maps[] = { { - uCOS_III_VAL_OS_TCB_StkPtr_offset, + UCOS_III_VAL_OS_TCB_STK_PTR_OFFSET, ¶ms->thread_stack_offset, }, { - uCOS_III_VAL_OS_TCB_NamePtr_offset, + UCOS_III_VAL_OS_TCB_NAME_PTR_OFFSET, ¶ms->thread_name_offset, }, { - uCOS_III_VAL_OS_TCB_TaskState_offset, + UCOS_III_VAL_OS_TCB_TASK_STATE_OFFSET, ¶ms->thread_state_offset, }, { - uCOS_III_VAL_OS_TCB_Prio_offset, + UCOS_III_VAL_OS_TCB_PRIO_OFFSET, ¶ms->thread_priority_offset, }, { - uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset, + UCOS_III_VAL_OS_TCB_DBG_PREV_PTR_OFFSET, ¶ms->thread_prev_offset, }, { - uCOS_III_VAL_OS_TCB_DbgNextPtr_offset, + UCOS_III_VAL_OS_TCB_DBG_NEXT_PTR_OFFSET, ¶ms->thread_next_offset, }, }; @@ -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) { @@ -255,15 +232,15 @@ static int uCOS_III_update_thread_offsets(struct rtos *rtos) return ERROR_OK; } -static bool uCOS_III_detect_rtos(struct target *target) +static bool ucos_iii_detect_rtos(struct target *target) { - return target->rtos->symbols != NULL && - target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0; + return target->rtos->symbols && + target->rtos->symbols[UCOS_III_VAL_OS_RUNNING].address != 0; } -static int uCOS_III_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv) +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; @@ -271,22 +248,22 @@ static int uCOS_III_reset_handler(struct target *target, enum target_reset_mode return ERROR_OK; } -static int uCOS_III_create(struct target *target) +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))); - if (params == NULL) { + 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 = 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); + target_register_reset_callback(ucos_iii_reset_handler, NULL); return ERROR_OK; } @@ -295,12 +272,12 @@ static int uCOS_III_create(struct target *target) return ERROR_FAIL; } -static int uCOS_III_update_threads(struct rtos *rtos) +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 == NULL) { + if (!rtos->symbols) { LOG_ERROR("uCOS-III: symbol list not loaded"); return ERROR_FAIL; } @@ -312,7 +289,7 @@ static int uCOS_III_update_threads(struct rtos *rtos) uint8_t rtos_running; retval = target_read_u8(rtos->target, - rtos->symbols[uCOS_III_VAL_OSRunning].address, + rtos->symbols[UCOS_III_VAL_OS_RUNNING].address, &rtos_running); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read RTOS running"); @@ -326,7 +303,7 @@ static int uCOS_III_update_threads(struct rtos *rtos) if (!rtos_running) { rtos->thread_details = calloc(1, sizeof(struct thread_detail)); - if (rtos->thread_details == NULL) { + if (!rtos->thread_details) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; } @@ -340,7 +317,7 @@ static int uCOS_III_update_threads(struct rtos *rtos) } /* update thread offsets */ - retval = uCOS_III_update_thread_offsets(rtos); + retval = ucos_iii_update_thread_offsets(rtos); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to update thread offsets"); return retval; @@ -350,8 +327,8 @@ static int uCOS_III_update_threads(struct rtos *rtos) symbol_address_t current_thread_address = 0; retval = target_read_memory(rtos->target, - rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address, - params->pointer_width, + rtos->symbols[UCOS_III_VAL_OS_TCB_CUR_PTR].address, + params->params->pointer_width, 1, (void *)¤t_thread_address); if (retval != ERROR_OK) { @@ -361,7 +338,7 @@ static int uCOS_III_update_threads(struct rtos *rtos) /* read number of tasks */ retval = target_read_u16(rtos->target, - rtos->symbols[uCOS_III_VAL_OSTaskQty].address, + rtos->symbols[UCOS_III_VAL_OS_TASK_QTY].address, (void *)&rtos->thread_count); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread count"); @@ -369,7 +346,7 @@ static int uCOS_III_update_threads(struct rtos *rtos) } rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail)); - if (rtos->thread_details == NULL) { + if (!rtos->thread_details) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; } @@ -380,7 +357,7 @@ static int uCOS_III_update_threads(struct rtos *rtos) */ symbol_address_t thread_address = 0; - retval = uCOS_III_find_last_thread_address(rtos, &thread_address); + retval = ucos_iii_find_last_thread_address(rtos, &thread_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to find last thread address"); return retval; @@ -391,7 +368,7 @@ static int uCOS_III_update_threads(struct rtos *rtos) char thread_str_buffer[UCOS_III_MAX_STRLEN + 1]; /* find or create new threadid */ - retval = uCOS_III_find_or_create_thread(rtos, thread_address, &thread_detail->threadid); + retval = ucos_iii_find_or_create_thread(rtos, thread_address, &thread_detail->threadid); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to find or create thread"); return retval; @@ -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) { @@ -449,8 +426,8 @@ static int uCOS_III_update_threads(struct rtos *rtos) const char *thread_state_str; - if (thread_state < ARRAY_SIZE(uCOS_III_thread_state_list)) - thread_state_str = uCOS_III_thread_state_list[thread_state]; + if (thread_state < ARRAY_SIZE(ucos_iii_thread_state_list)) + thread_state_str = ucos_iii_thread_state_list[thread_state]; else thread_state_str = "Unknown"; @@ -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) { @@ -473,16 +450,16 @@ static int uCOS_III_update_threads(struct rtos *rtos) return ERROR_OK; } -static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, +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 */ symbol_address_t thread_address = 0; - retval = uCOS_III_find_thread_address(rtos, threadid, &thread_address); + retval = ucos_iii_find_thread_address(rtos, threadid, &thread_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to find thread address"); return retval; @@ -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,31 +479,31 @@ 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); } -static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int ucos_iii_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { - *symbol_list = calloc(ARRAY_SIZE(uCOS_III_symbol_list), sizeof(symbol_table_elem_t)); - if (*symbol_list == NULL) { + *symbol_list = calloc(ARRAY_SIZE(ucos_iii_symbol_list), sizeof(struct symbol_table_elem)); + if (!*symbol_list) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; } - for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_symbol_list); i++) - (*symbol_list)[i].symbol_name = uCOS_III_symbol_list[i]; + for (size_t i = 0; i < ARRAY_SIZE(ucos_iii_symbol_list); i++) + (*symbol_list)[i].symbol_name = ucos_iii_symbol_list[i]; return ERROR_OK; } -const struct rtos_type uCOS_III_rtos = { +const struct rtos_type ucos_iii_rtos = { .name = "uCOS-III", - .detect_rtos = uCOS_III_detect_rtos, - .create = uCOS_III_create, - .update_threads = uCOS_III_update_threads, - .get_thread_reg_list = uCOS_III_get_thread_reg_list, - .get_symbol_list_to_lookup = uCOS_III_get_symbol_list_to_lookup, + .detect_rtos = ucos_iii_detect_rtos, + .create = ucos_iii_create, + .update_threads = ucos_iii_update_threads, + .get_thread_reg_list = ucos_iii_get_thread_reg_list, + .get_symbol_list_to_lookup = ucos_iii_get_symbol_list_to_lookup, }; diff --git a/src/rtos/zephyr.c b/src/rtos/zephyr.c new file mode 100644 index 0000000000..a4c60904b5 --- /dev/null +++ b/src/rtos/zephyr.c @@ -0,0 +1,797 @@ +// 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> + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/time_support.h> +#include <jtag/jtag.h> + +#include "helper/log.h" +#include "helper/types.h" +#include "rtos.h" +#include "rtos_standard_stackings.h" +#include "target/target.h" +#include "target/target_type.h" +#include "target/armv7m.h" +#include "target/arc.h" + +#define UNIMPLEMENTED 0xFFFFFFFFU + +/* ARC specific defines */ +#define ARC_AUX_SEC_BUILD_REG 0xdb +#define ARC_REG_NUM 38 + +/* ARM specific defines */ +#define ARM_XPSR_OFFSET 28 + +struct zephyr_thread { + uint32_t ptr, next_ptr; + uint32_t entry; + uint32_t stack_pointer; + uint8_t state; + uint8_t user_options; + int8_t prio; + char name[64]; +}; + +enum zephyr_offsets { + OFFSET_VERSION, + OFFSET_K_CURR_THREAD, + OFFSET_K_THREADS, + OFFSET_T_ENTRY, + OFFSET_T_NEXT_THREAD, + OFFSET_T_STATE, + OFFSET_T_USER_OPTIONS, + OFFSET_T_PRIO, + OFFSET_T_STACK_POINTER, + OFFSET_T_NAME, + OFFSET_T_ARCH, + OFFSET_T_PREEMPT_FLOAT, + OFFSET_T_COOP_FLOAT, + OFFSET_T_ARM_EXC_RETURN, + OFFSET_MAX +}; + +struct zephyr_params { + const char *target_name; + uint8_t size_width; + uint8_t pointer_width; + uint32_t num_offsets; + uint32_t offsets[OFFSET_MAX]; + const struct rtos_register_stacking *callee_saved_stacking; + const struct rtos_register_stacking *cpu_saved_nofp_stacking; + const struct rtos_register_stacking *cpu_saved_fp_stacking; + int (*get_cpu_state)(struct rtos *rtos, target_addr_t *addr, + struct zephyr_params *params, + struct rtos_reg *callee_saved_reg_list, + struct rtos_reg **reg_list, int *num_regs); +}; + +static const struct stack_register_offset arm_callee_saved[] = { + { ARMV7M_R13, 32, 32 }, + { ARMV7M_R4, 0, 32 }, + { ARMV7M_R5, 4, 32 }, + { ARMV7M_R6, 8, 32 }, + { ARMV7M_R7, 12, 32 }, + { ARMV7M_R8, 16, 32 }, + { ARMV7M_R9, 20, 32 }, + { ARMV7M_R10, 24, 32 }, + { ARMV7M_R11, 28, 32 }, +}; + +static const struct stack_register_offset arc_callee_saved[] = { + { ARC_R13, 0, 32 }, + { ARC_R14, 4, 32 }, + { ARC_R15, 8, 32 }, + { ARC_R16, 12, 32 }, + { ARC_R17, 16, 32 }, + { ARC_R18, 20, 32 }, + { ARC_R19, 24, 32 }, + { ARC_R20, 28, 32 }, + { ARC_R21, 32, 32 }, + { ARC_R22, 36, 32 }, + { ARC_R23, 40, 32 }, + { ARC_R24, 44, 32 }, + { ARC_R25, 48, 32 }, + { ARC_GP, 52, 32 }, + { ARC_FP, 56, 32 }, + { ARC_R30, 60, 32 } +}; +static const struct rtos_register_stacking arm_callee_saved_stacking = { + .stack_registers_size = 36, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(arm_callee_saved), + .register_offsets = arm_callee_saved, +}; + +static const struct rtos_register_stacking arc_callee_saved_stacking = { + .stack_registers_size = 64, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(arc_callee_saved), + .register_offsets = arc_callee_saved, +}; + +static const struct stack_register_offset arm_cpu_saved[] = { + { ARMV7M_R0, 0, 32 }, + { ARMV7M_R1, 4, 32 }, + { ARMV7M_R2, 8, 32 }, + { ARMV7M_R3, 12, 32 }, + { ARMV7M_R4, -1, 32 }, + { ARMV7M_R5, -1, 32 }, + { ARMV7M_R6, -1, 32 }, + { ARMV7M_R7, -1, 32 }, + { ARMV7M_R8, -1, 32 }, + { ARMV7M_R9, -1, 32 }, + { ARMV7M_R10, -1, 32 }, + { ARMV7M_R11, -1, 32 }, + { ARMV7M_R12, 16, 32 }, + { ARMV7M_R13, -2, 32 }, + { ARMV7M_R14, 20, 32 }, + { ARMV7M_PC, 24, 32 }, + { ARMV7M_XPSR, 28, 32 }, +}; + +static struct stack_register_offset arc_cpu_saved[] = { + { ARC_R0, -1, 32 }, + { ARC_R1, -1, 32 }, + { ARC_R2, -1, 32 }, + { ARC_R3, -1, 32 }, + { ARC_R4, -1, 32 }, + { ARC_R5, -1, 32 }, + { ARC_R6, -1, 32 }, + { ARC_R7, -1, 32 }, + { ARC_R8, -1, 32 }, + { ARC_R9, -1, 32 }, + { ARC_R10, -1, 32 }, + { ARC_R11, -1, 32 }, + { ARC_R12, -1, 32 }, + { ARC_R13, -1, 32 }, + { ARC_R14, -1, 32 }, + { ARC_R15, -1, 32 }, + { ARC_R16, -1, 32 }, + { ARC_R17, -1, 32 }, + { ARC_R18, -1, 32 }, + { ARC_R19, -1, 32 }, + { ARC_R20, -1, 32 }, + { ARC_R21, -1, 32 }, + { ARC_R22, -1, 32 }, + { ARC_R23, -1, 32 }, + { ARC_R24, -1, 32 }, + { ARC_R25, -1, 32 }, + { ARC_GP, -1, 32 }, + { ARC_FP, -1, 32 }, + { ARC_SP, -1, 32 }, + { ARC_ILINK, -1, 32 }, + { ARC_R30, -1, 32 }, + { ARC_BLINK, 0, 32 }, + { ARC_LP_COUNT, -1, 32 }, + { ARC_PCL, -1, 32 }, + { ARC_PC, -1, 32 }, + { ARC_LP_START, -1, 32 }, + { ARC_LP_END, -1, 32 }, + { ARC_STATUS32, 4, 32 } +}; + + +enum zephyr_symbol_values { + ZEPHYR_VAL__KERNEL, + ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS, + ZEPHYR_VAL__KERNEL_OPENOCD_SIZE_T_SIZE, + ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS, + ZEPHYR_VAL_COUNT +}; + +static target_addr_t zephyr_cortex_m_stack_align(struct target *target, + const uint8_t *stack_data, + const struct rtos_register_stacking *stacking, target_addr_t stack_ptr) +{ + return rtos_cortex_m_stack_align(target, stack_data, stacking, + stack_ptr, ARM_XPSR_OFFSET); +} + +static const struct rtos_register_stacking arm_cpu_saved_nofp_stacking = { + .stack_registers_size = 32, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(arm_cpu_saved), + .calculate_process_stack = zephyr_cortex_m_stack_align, + .register_offsets = arm_cpu_saved, +}; + +static const struct rtos_register_stacking arm_cpu_saved_fp_stacking = { + .stack_registers_size = 32 + 18 * 4, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(arm_cpu_saved), + .calculate_process_stack = zephyr_cortex_m_stack_align, + .register_offsets = arm_cpu_saved, +}; + +/* stack_registers_size is 8 because besides caller registers + * there are only blink and Status32 registers on stack left */ +static struct rtos_register_stacking arc_cpu_saved_stacking = { + .stack_registers_size = 8, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(arc_cpu_saved), + .register_offsets = arc_cpu_saved, +}; + +/* ARCv2 specific implementation */ +static int zephyr_get_arc_state(struct rtos *rtos, target_addr_t *addr, + struct zephyr_params *params, + struct rtos_reg *callee_saved_reg_list, + struct rtos_reg **reg_list, int *num_regs) +{ + + uint32_t real_stack_addr; + int retval = 0; + int num_callee_saved_regs; + const struct rtos_register_stacking *stacking; + + /* Getting real stack address from Kernel thread struct */ + retval = target_read_u32(rtos->target, *addr, &real_stack_addr); + if (retval != ERROR_OK) + return retval; + + /* Getting callee registers */ + retval = rtos_generic_stack_read(rtos->target, + params->callee_saved_stacking, + real_stack_addr, &callee_saved_reg_list, + &num_callee_saved_regs); + if (retval != ERROR_OK) + return retval; + + stacking = params->cpu_saved_nofp_stacking; + + /* Getting blink and status32 registers */ + retval = rtos_generic_stack_read(rtos->target, stacking, + real_stack_addr + num_callee_saved_regs * 4, + reg_list, num_regs); + if (retval != ERROR_OK) + return retval; + + for (int i = 0; i < num_callee_saved_regs; i++) + buf_cpy(callee_saved_reg_list[i].value, + (*reg_list)[callee_saved_reg_list[i].number].value, + callee_saved_reg_list[i].size); + + /* The blink, sp, pc offsets in arc_cpu_saved structure may be changed, + * but the registers number shall not. So the next code searches the + * offsetst of these registers in arc_cpu_saved structure. */ + unsigned short blink_offset = 0, pc_offset = 0, sp_offset = 0; + for (size_t i = 0; i < ARRAY_SIZE(arc_cpu_saved); i++) { + if (arc_cpu_saved[i].number == ARC_BLINK) + blink_offset = i; + if (arc_cpu_saved[i].number == ARC_SP) + sp_offset = i; + if (arc_cpu_saved[i].number == ARC_PC) + pc_offset = i; + } + + if (blink_offset == 0 || sp_offset == 0 || pc_offset == 0) { + LOG_ERROR("Basic registers offsets are missing, check <arc_cpu_saved> struct"); + return ERROR_FAIL; + } + + /* Put blink value into PC */ + buf_cpy((*reg_list)[blink_offset].value, + (*reg_list)[pc_offset].value, sizeof((*reg_list)[blink_offset].value)); + + /* Put address after callee/caller in SP. */ + int64_t stack_top; + + stack_top = real_stack_addr + num_callee_saved_regs * 4 + + arc_cpu_saved_stacking.stack_registers_size; + buf_cpy(&stack_top, (*reg_list)[sp_offset].value, sizeof(stack_top)); + + return retval; +} + +/* ARM Cortex-M-specific implementation */ +static int zephyr_get_arm_state(struct rtos *rtos, target_addr_t *addr, + struct zephyr_params *params, + struct rtos_reg *callee_saved_reg_list, + struct rtos_reg **reg_list, int *num_regs) +{ + + int retval = 0; + int num_callee_saved_regs; + const struct rtos_register_stacking *stacking; + + retval = rtos_generic_stack_read(rtos->target, + params->callee_saved_stacking, + *addr, &callee_saved_reg_list, + &num_callee_saved_regs); + if (retval != ERROR_OK) + return retval; + + *addr = target_buffer_get_u32(rtos->target, + callee_saved_reg_list[0].value); + + if (params->offsets[OFFSET_T_PREEMPT_FLOAT] != UNIMPLEMENTED) + stacking = params->cpu_saved_fp_stacking; + else + stacking = params->cpu_saved_nofp_stacking; + + retval = rtos_generic_stack_read(rtos->target, stacking, *addr, reg_list, + num_regs); + if (retval != ERROR_OK) + return retval; + + for (int i = 1; i < num_callee_saved_regs; i++) + buf_cpy(callee_saved_reg_list[i].value, + (*reg_list)[callee_saved_reg_list[i].number].value, + callee_saved_reg_list[i].size); + return 0; +} + +static struct zephyr_params zephyr_params_list[] = { + { + .target_name = "cortex_m", + .pointer_width = 4, + .callee_saved_stacking = &arm_callee_saved_stacking, + .cpu_saved_nofp_stacking = &arm_cpu_saved_nofp_stacking, + .cpu_saved_fp_stacking = &arm_cpu_saved_fp_stacking, + .get_cpu_state = &zephyr_get_arm_state, + }, + { + .target_name = "cortex_r4", + .pointer_width = 4, + .callee_saved_stacking = &arm_callee_saved_stacking, + .cpu_saved_nofp_stacking = &arm_cpu_saved_nofp_stacking, + .cpu_saved_fp_stacking = &arm_cpu_saved_fp_stacking, + .get_cpu_state = &zephyr_get_arm_state, + }, + { + .target_name = "hla_target", + .pointer_width = 4, + .callee_saved_stacking = &arm_callee_saved_stacking, + .cpu_saved_nofp_stacking = &arm_cpu_saved_nofp_stacking, + .cpu_saved_fp_stacking = &arm_cpu_saved_fp_stacking, + .get_cpu_state = &zephyr_get_arm_state, + + }, + { + .target_name = "arcv2", + .pointer_width = 4, + .callee_saved_stacking = &arc_callee_saved_stacking, + .cpu_saved_nofp_stacking = &arc_cpu_saved_stacking, + .get_cpu_state = &zephyr_get_arc_state, + }, + { + .target_name = NULL + } +}; + +static const struct symbol_table_elem zephyr_symbol_list[] = { + { + .symbol_name = "_kernel", + .optional = false + }, + { + .symbol_name = "_kernel_thread_info_offsets", + .optional = false + }, + { + .symbol_name = "_kernel_thread_info_size_t_size", + .optional = false + }, + { + .symbol_name = "_kernel_thread_info_num_offsets", + .optional = true + }, + { + .symbol_name = NULL + } +}; + +static bool zephyr_detect_rtos(struct target *target) +{ + if (!target->rtos->symbols) { + LOG_INFO("Zephyr: no symbols while detecting RTOS"); + return false; + } + + for (enum zephyr_symbol_values symbol = ZEPHYR_VAL__KERNEL; + symbol != ZEPHYR_VAL_COUNT; symbol++) { + LOG_INFO("Zephyr: does it have symbol %d (%s)?", symbol, + target->rtos->symbols[symbol].optional ? "optional" : "mandatory"); + + if (target->rtos->symbols[symbol].optional) + continue; + if (target->rtos->symbols[symbol].address == 0) + return false; + } + + LOG_INFO("Zephyr: all mandatory symbols found"); + + return true; +} + +static int zephyr_create(struct target *target) +{ + const char *name; + + name = target_type_name(target); + + LOG_INFO("Zephyr: looking for target: %s", name); + + /* ARC specific, check if EM target has security subsystem + * In case of ARC_HAS_SECURE zephyr option enabled + * the thread stack contains blink,sec_stat,status32 register + * values. If ARC_HAS_SECURE is disabled, only blink and status32 + * register values are saved on stack. */ + if (!strcmp(name, "arcv2")) { + uint32_t value; + struct arc_common *arc = target_to_arc(target); + /* Reading SEC_BUILD bcr */ + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, ARC_AUX_SEC_BUILD_REG, &value)); + if (value != 0) { + LOG_DEBUG("ARC EM board has security subsystem, changing offsets"); + arc_cpu_saved[ARC_REG_NUM - 1].offset = 8; + /* After reading callee registers in stack + * now blink,sec_stat,status32 registers + * are located. */ + arc_cpu_saved_stacking.stack_registers_size = 12; + } + } + + for (struct zephyr_params *p = zephyr_params_list; p->target_name; p++) { + if (!strcmp(p->target_name, name)) { + LOG_INFO("Zephyr: target known, params at %p", p); + target->rtos->rtos_specific_params = p; + return ERROR_OK; + } + } + + LOG_ERROR("Could not find target in Zephyr compatibility list"); + return ERROR_FAIL; +} + +struct zephyr_array { + void *ptr; + size_t elements; +}; + +static void zephyr_array_init(struct zephyr_array *array) +{ + array->ptr = NULL; + array->elements = 0; +} + +static void zephyr_array_free(struct zephyr_array *array) +{ + free(array->ptr); + zephyr_array_init(array); +} + +static void *zephyr_array_append(struct zephyr_array *array, size_t size) +{ + if (!(array->elements % 16)) { + void *ptr = realloc(array->ptr, (array->elements + 16) * size); + + if (!ptr) { + LOG_ERROR("Out of memory"); + return NULL; + } + + array->ptr = ptr; + } + + return (unsigned char *)array->ptr + (array->elements++) * size; +} + +static void *zephyr_array_detach_ptr(struct zephyr_array *array) +{ + void *ptr = array->ptr; + + zephyr_array_init(array); + + return ptr; +} + +static uint32_t zephyr_kptr(const struct rtos *rtos, enum zephyr_offsets off) +{ + const struct zephyr_params *params = rtos->rtos_specific_params; + + return rtos->symbols[ZEPHYR_VAL__KERNEL].address + params->offsets[off]; +} + +static int zephyr_fetch_thread(const struct rtos *rtos, + struct zephyr_thread *thread, uint32_t ptr) +{ + const struct zephyr_params *param = rtos->rtos_specific_params; + int retval; + + thread->ptr = ptr; + + retval = target_read_u32(rtos->target, ptr + param->offsets[OFFSET_T_ENTRY], + &thread->entry); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(rtos->target, + ptr + param->offsets[OFFSET_T_NEXT_THREAD], + &thread->next_ptr); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(rtos->target, + ptr + param->offsets[OFFSET_T_STACK_POINTER], + &thread->stack_pointer); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u8(rtos->target, ptr + param->offsets[OFFSET_T_STATE], + &thread->state); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u8(rtos->target, + ptr + param->offsets[OFFSET_T_USER_OPTIONS], + &thread->user_options); + if (retval != ERROR_OK) + return retval; + + uint8_t prio; + retval = target_read_u8(rtos->target, + ptr + param->offsets[OFFSET_T_PRIO], &prio); + if (retval != ERROR_OK) + return retval; + thread->prio = prio; + + thread->name[0] = '\0'; + if (param->offsets[OFFSET_T_NAME] != UNIMPLEMENTED) { + retval = target_read_buffer(rtos->target, + ptr + param->offsets[OFFSET_T_NAME], + sizeof(thread->name) - 1, (uint8_t *)thread->name); + if (retval != ERROR_OK) + return retval; + + thread->name[sizeof(thread->name) - 1] = '\0'; + } + + LOG_DEBUG("Fetched thread%" PRIx32 ": {entry@0x%" PRIx32 + ", state=%" PRIu8 ", useropts=%" PRIu8 ", prio=%" PRId8 "}", + ptr, thread->entry, thread->state, thread->user_options, thread->prio); + + return ERROR_OK; +} + +static int zephyr_fetch_thread_list(struct rtos *rtos, uint32_t current_thread) +{ + struct zephyr_array thread_array; + struct zephyr_thread thread; + struct thread_detail *td; + int64_t curr_id = -1; + uint32_t curr; + int retval; + + retval = target_read_u32(rtos->target, zephyr_kptr(rtos, OFFSET_K_THREADS), + &curr); + if (retval != ERROR_OK) { + LOG_ERROR("Could not fetch current thread pointer"); + return retval; + } + + zephyr_array_init(&thread_array); + + for (; curr; curr = thread.next_ptr) { + retval = zephyr_fetch_thread(rtos, &thread, curr); + if (retval != ERROR_OK) + goto error; + + td = zephyr_array_append(&thread_array, sizeof(*td)); + if (!td) + goto error; + + td->threadid = thread.ptr; + td->exists = true; + + if (thread.name[0]) + td->thread_name_str = strdup(thread.name); + else + td->thread_name_str = alloc_printf("thr_%" PRIx32 "_%" PRIx32, + thread.entry, thread.ptr); + td->extra_info_str = alloc_printf("prio:%" PRId8 ",useropts:%" PRIu8, + thread.prio, thread.user_options); + if (!td->thread_name_str || !td->extra_info_str) + goto error; + + if (td->threadid == current_thread) + curr_id = (int64_t)thread_array.elements - 1; + } + + LOG_DEBUG("Got information for %zu threads", thread_array.elements); + + rtos_free_threadlist(rtos); + + rtos->thread_count = (int)thread_array.elements; + rtos->thread_details = zephyr_array_detach_ptr(&thread_array); + + rtos->current_threadid = curr_id; + rtos->current_thread = current_thread; + + return ERROR_OK; + +error: + td = thread_array.ptr; + for (size_t i = 0; i < thread_array.elements; i++) { + free(td[i].thread_name_str); + free(td[i].extra_info_str); + } + + zephyr_array_free(&thread_array); + + return ERROR_FAIL; +} + +static int zephyr_update_threads(struct rtos *rtos) +{ + struct zephyr_params *param; + int retval; + + if (!rtos->rtos_specific_params) + return ERROR_FAIL; + + param = (struct zephyr_params *)rtos->rtos_specific_params; + + if (!rtos->symbols) { + LOG_ERROR("No symbols for Zephyr"); + return ERROR_FAIL; + } + + if (rtos->symbols[ZEPHYR_VAL__KERNEL].address == 0) { + LOG_ERROR("Can't obtain kernel struct from Zephyr"); + return ERROR_FAIL; + } + + if (rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS].address == 0) { + LOG_ERROR("Please build Zephyr with CONFIG_OPENOCD option set"); + return ERROR_FAIL; + } + + retval = target_read_u8(rtos->target, + rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_SIZE_T_SIZE].address, + ¶m->size_width); + if (retval != ERROR_OK) { + LOG_ERROR("Couldn't determine size of size_t from host"); + return retval; + } + + if (param->size_width != 4) { + LOG_ERROR("Only size_t of 4 bytes are supported"); + return ERROR_FAIL; + } + + if (rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS].address) { + retval = target_read_u32(rtos->target, + rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS].address, + ¶m->num_offsets); + if (retval != ERROR_OK) { + LOG_ERROR("Couldn't not fetch number of offsets from Zephyr"); + return retval; + } + + if (param->num_offsets <= OFFSET_T_STACK_POINTER) { + LOG_ERROR("Number of offsets too small"); + return ERROR_FAIL; + } + } else { + retval = target_read_u32(rtos->target, + rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS].address, + ¶m->offsets[OFFSET_VERSION]); + if (retval != ERROR_OK) { + LOG_ERROR("Couldn't not fetch offsets from Zephyr"); + return retval; + } + + if (param->offsets[OFFSET_VERSION] > 1) { + LOG_ERROR("Unexpected OpenOCD support version %" PRIu32, + param->offsets[OFFSET_VERSION]); + return ERROR_FAIL; + } + switch (param->offsets[OFFSET_VERSION]) { + case 0: + param->num_offsets = OFFSET_T_STACK_POINTER + 1; + break; + case 1: + param->num_offsets = OFFSET_T_COOP_FLOAT + 1; + break; + } + } + /* We can fetch the whole array for version 0, as they're supposed + * to grow only */ + uint32_t address; + address = rtos->symbols[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS].address; + for (size_t i = 0; i < OFFSET_MAX; i++, address += param->size_width) { + if (i >= param->num_offsets) { + param->offsets[i] = UNIMPLEMENTED; + continue; + } + + retval = target_read_u32(rtos->target, address, ¶m->offsets[i]); + if (retval != ERROR_OK) { + LOG_ERROR("Could not fetch offsets from Zephyr"); + return ERROR_FAIL; + } + } + + LOG_DEBUG("Zephyr OpenOCD support version %" PRId32, + param->offsets[OFFSET_VERSION]); + + uint32_t current_thread; + retval = target_read_u32(rtos->target, + zephyr_kptr(rtos, OFFSET_K_CURR_THREAD), ¤t_thread); + if (retval != ERROR_OK) { + LOG_ERROR("Could not obtain current thread ID"); + return retval; + } + + retval = zephyr_fetch_thread_list(rtos, current_thread); + if (retval != ERROR_OK) { + LOG_ERROR("Could not obtain thread list"); + return retval; + } + + return ERROR_OK; +} + +static int zephyr_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) +{ + struct zephyr_params *params; + struct rtos_reg *callee_saved_reg_list = NULL; + target_addr_t addr; + int retval; + + LOG_INFO("Getting thread %" PRId64 " reg list", thread_id); + + if (!rtos) + return ERROR_FAIL; + + if (thread_id == 0) + return ERROR_FAIL; + + params = rtos->rtos_specific_params; + if (!params) + return ERROR_FAIL; + + addr = thread_id + params->offsets[OFFSET_T_STACK_POINTER] + - params->callee_saved_stacking->register_offsets[0].offset; + + retval = params->get_cpu_state(rtos, &addr, params, callee_saved_reg_list, reg_list, num_regs); + + free(callee_saved_reg_list); + + return retval; +} + +static int zephyr_get_symbol_list_to_lookup(struct symbol_table_elem **symbol_list) +{ + *symbol_list = malloc(sizeof(zephyr_symbol_list)); + if (!*symbol_list) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + memcpy(*symbol_list, zephyr_symbol_list, sizeof(zephyr_symbol_list)); + return ERROR_OK; +} + +const struct rtos_type zephyr_rtos = { + .name = "Zephyr", + + .detect_rtos = zephyr_detect_rtos, + .create = zephyr_create, + .update_threads = zephyr_update_threads, + .get_thread_reg_list = zephyr_get_thread_reg_list, + .get_symbol_list_to_lookup = zephyr_get_symbol_list_to_lookup, +}; diff --git a/src/rtt/Makefile.am b/src/rtt/Makefile.am new file mode 100644 index 0000000000..99685547a1 --- /dev/null +++ b/src/rtt/Makefile.am @@ -0,0 +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 new file mode 100644 index 0000000000..e31e75410d --- /dev/null +++ b/src/rtt/rtt.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +#include <helper/log.h> +#include <helper/list.h> +#include <target/target.h> +#include <target/rtt.h> + +#include "rtt.h" + +static struct { + struct rtt_source source; + /** Control block. */ + struct rtt_control ctrl; + struct target *target; + /** Start address to search for the control block. */ + target_addr_t addr; + /** Size of the control block search area. */ + size_t size; + /** Control block identifier. */ + char id[RTT_CB_MAX_ID_LENGTH]; + /** Whether RTT is configured. */ + bool configured; + /** Whether RTT is started. */ + bool started; + /** Whether configuration changed. */ + bool changed; + /** Whether the control block was found. */ + bool found_cb; + + struct rtt_sink_list **sink_list; + size_t sink_list_length; + + unsigned int polling_interval; +} rtt; + +int rtt_init(void) +{ + rtt.sink_list_length = 1; + rtt.sink_list = calloc(rtt.sink_list_length, + sizeof(struct rtt_sink_list *)); + + if (!rtt.sink_list) + return ERROR_FAIL; + + rtt.sink_list[0] = NULL; + rtt.started = false; + + rtt.polling_interval = 100; + + return ERROR_OK; +} + +int rtt_exit(void) +{ + free(rtt.sink_list); + + return ERROR_OK; +} + +static int read_channel_callback(void *user_data) +{ + int ret; + + ret = rtt.source.read(rtt.target, &rtt.ctrl, rtt.sink_list, + rtt.sink_list_length, NULL); + + if (ret != ERROR_OK) { + target_unregister_timer_callback(&read_channel_callback, NULL); + rtt.source.stop(rtt.target, NULL); + return ret; + } + + return ERROR_OK; +} + +int rtt_setup(target_addr_t address, size_t size, const char *id) +{ + size_t id_length = strlen(id); + + if (!id_length || id_length >= RTT_CB_MAX_ID_LENGTH) { + LOG_ERROR("rtt: Invalid control block ID"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + rtt.addr = address; + rtt.size = size; + strncpy(rtt.id, id, id_length + 1); + rtt.changed = true; + rtt.configured = true; + + return ERROR_OK; +} + +int rtt_register_source(const struct rtt_source source, + struct target *target) +{ + if (!source.find_cb || !source.read_cb || !source.read_channel_info) + return ERROR_FAIL; + + if (!source.start || !source.stop) + return ERROR_FAIL; + + if (!source.read || !source.write) + return ERROR_FAIL; + + rtt.source = source; + rtt.target = target; + + return ERROR_OK; +} + +int rtt_start(void) +{ + int ret; + target_addr_t addr = rtt.addr; + + if (rtt.started) + return ERROR_OK; + + if (!rtt.found_cb || rtt.changed) { + rtt.source.find_cb(rtt.target, &addr, rtt.size, rtt.id, + &rtt.found_cb, NULL); + + rtt.changed = false; + + if (rtt.found_cb) { + LOG_INFO("rtt: Control block found at 0x%" TARGET_PRIxADDR, + addr); + rtt.ctrl.address = addr; + } else { + LOG_INFO("rtt: No control block found"); + return ERROR_OK; + } + } + + ret = rtt.source.read_cb(rtt.target, rtt.ctrl.address, &rtt.ctrl, NULL); + + if (ret != ERROR_OK) + return ret; + + ret = rtt.source.start(rtt.target, &rtt.ctrl, NULL); + + if (ret != ERROR_OK) + return ret; + + target_register_timer_callback(&read_channel_callback, + rtt.polling_interval, 1, NULL); + rtt.started = true; + + return ERROR_OK; +} + +int rtt_stop(void) +{ + int ret; + + if (!rtt.configured) { + LOG_ERROR("rtt: Not configured"); + return ERROR_FAIL; + } + + target_unregister_timer_callback(&read_channel_callback, NULL); + rtt.started = false; + + ret = rtt.source.stop(rtt.target, NULL); + + if (ret != ERROR_OK) + return ret; + + return ERROR_OK; +} + +static int adjust_sink_list(size_t length) +{ + struct rtt_sink_list **tmp; + + if (length <= rtt.sink_list_length) + return ERROR_OK; + + tmp = realloc(rtt.sink_list, sizeof(struct rtt_sink_list *) * length); + + if (!tmp) + return ERROR_FAIL; + + for (size_t i = rtt.sink_list_length; i < length; i++) + tmp[i] = NULL; + + rtt.sink_list = tmp; + rtt.sink_list_length = length; + + return ERROR_OK; +} + +int rtt_register_sink(unsigned int channel_index, rtt_sink_read read, + void *user_data) +{ + struct rtt_sink_list *tmp; + + if (channel_index >= rtt.sink_list_length) { + if (adjust_sink_list(channel_index + 1) != ERROR_OK) + return ERROR_FAIL; + } + + LOG_DEBUG("rtt: Registering sink for channel %u", channel_index); + + tmp = malloc(sizeof(struct rtt_sink_list)); + + if (!tmp) + return ERROR_FAIL; + + tmp->read = read; + tmp->user_data = user_data; + tmp->next = rtt.sink_list[channel_index]; + + rtt.sink_list[channel_index] = tmp; + + return ERROR_OK; +} + +int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read, + void *user_data) +{ + struct rtt_sink_list *prev_sink; + + LOG_DEBUG("rtt: Unregistering sink for channel %u", channel_index); + + if (channel_index >= rtt.sink_list_length) + return ERROR_FAIL; + + prev_sink = rtt.sink_list[channel_index]; + + for (struct rtt_sink_list *sink = rtt.sink_list[channel_index]; sink; + prev_sink = sink, sink = sink->next) { + if (sink->read == read && sink->user_data == user_data) { + + if (sink == rtt.sink_list[channel_index]) + rtt.sink_list[channel_index] = sink->next; + else + prev_sink->next = sink->next; + + free(sink); + + return ERROR_OK; + } + } + + return ERROR_OK; +} + +int rtt_get_polling_interval(unsigned int *interval) +{ + if (!interval) + return ERROR_FAIL; + + *interval = rtt.polling_interval; + + return ERROR_OK; +} + +int rtt_set_polling_interval(unsigned int interval) +{ + if (!interval) + return ERROR_FAIL; + + if (rtt.polling_interval != interval) { + target_unregister_timer_callback(&read_channel_callback, NULL); + target_register_timer_callback(&read_channel_callback, interval, 1, + NULL); + } + + rtt.polling_interval = interval; + + return ERROR_OK; +} + +int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer, + size_t *length) +{ + if (channel_index >= rtt.ctrl.num_up_channels) { + LOG_WARNING("rtt: Down-channel %u is not available", channel_index); + return ERROR_OK; + } + + return rtt.source.write(rtt.target, &rtt.ctrl, channel_index, buffer, + length, NULL); +} + +bool rtt_started(void) +{ + return rtt.started; +} + +bool rtt_configured(void) +{ + return rtt.configured; +} + +bool rtt_found_cb(void) +{ + return rtt.found_cb; +} + +const struct rtt_control *rtt_get_control(void) +{ + return &rtt.ctrl; +} + +int rtt_read_channel_info(unsigned int channel_index, + enum rtt_channel_type type, struct rtt_channel_info *info) +{ + return rtt.source.read_channel_info(rtt.target, &rtt.ctrl, + channel_index, type, info, NULL); +} diff --git a/src/rtt/rtt.h b/src/rtt/rtt.h new file mode 100644 index 0000000000..a5630a9515 --- /dev/null +++ b/src/rtt/rtt.h @@ -0,0 +1,276 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> + */ + +#ifndef OPENOCD_RTT_RTT_H +#define OPENOCD_RTT_RTT_H + +#include <stdint.h> +#include <stdbool.h> + +#include <helper/command.h> +#include <target/target.h> + +/** + * Control block ID length in bytes, including the trailing null-terminator. + */ +#define RTT_CB_MAX_ID_LENGTH 16 + +/* Control block size in bytes. */ +#define RTT_CB_SIZE (RTT_CB_MAX_ID_LENGTH + 2 * sizeof(uint32_t)) + +/* Channel structure size in bytes. */ +#define RTT_CHANNEL_SIZE 24 + +/* Minimal channel buffer size in bytes. */ +#define RTT_CHANNEL_BUFFER_MIN_SIZE 2 + +/** RTT control block. */ +struct rtt_control { + /** Control block address on the target. */ + target_addr_t address; + /** Control block identifier, including trailing null-terminator. */ + char id[RTT_CB_MAX_ID_LENGTH]; + /** Maximum number of up-channels. */ + uint32_t num_up_channels; + /** Maximum number of down-channels. */ + uint32_t num_down_channels; +}; + +/** RTT channel. */ +struct rtt_channel { + /** Channel structure address on the target. */ + target_addr_t address; + /** Channel name address on the target. */ + uint32_t name_addr; + /** Buffer address on the target. */ + uint32_t buffer_addr; + /** Channel buffer size in bytes. */ + uint32_t size; + /** Write position within the buffer in bytes. */ + uint32_t write_pos; + /** Read position within the buffer in bytes. */ + uint32_t read_pos; + /** + * Buffer flags. + * + * @note: Not used at the moment. + */ + uint32_t flags; +}; + +/** RTT channel information. */ +struct rtt_channel_info { + /** Channel name. */ + char *name; + /** Length of the name in bytes, including the trailing null-terminator. */ + size_t name_length; + /** Buffer size in bytes. */ + uint32_t size; + /** + * Buffer flags. + * + * @note: Not used at the moment. + */ + uint32_t flags; +}; + +typedef int (*rtt_sink_read)(unsigned int channel, const uint8_t *buffer, + size_t length, void *user_data); + +struct rtt_sink_list { + rtt_sink_read read; + void *user_data; + + struct rtt_sink_list *next; +}; + +/** Channel type. */ +enum rtt_channel_type { + /** Up channel (target to host). */ + RTT_CHANNEL_TYPE_UP, + /** Down channel (host to target). */ + RTT_CHANNEL_TYPE_DOWN +}; + +typedef int (*rtt_source_find_ctrl_block)(struct target *target, + target_addr_t *address, size_t size, const char *id, bool *found, + void *user_data); +typedef int (*rtt_source_read_ctrl_block)(struct target *target, + target_addr_t address, struct rtt_control *ctrl_block, + void *user_data); +typedef int (*rtt_source_read_channel_info)(struct target *target, + const struct rtt_control *ctrl, unsigned int channel, + enum rtt_channel_type type, struct rtt_channel_info *info, + void *user_data); +typedef int (*rtt_source_start)(struct target *target, + const struct rtt_control *ctrl, void *user_data); +typedef int (*rtt_source_stop)(struct target *target, void *user_data); +typedef int (*rtt_source_read)(struct target *target, + const struct rtt_control *ctrl, struct rtt_sink_list **sinks, + size_t num_channels, void *user_data); +typedef int (*rtt_source_write)(struct target *target, + struct rtt_control *ctrl, unsigned int channel, + const uint8_t *buffer, size_t *length, void *user_data); + +/** RTT source. */ +struct rtt_source { + rtt_source_find_ctrl_block find_cb; + rtt_source_read_ctrl_block read_cb; + rtt_source_read_channel_info read_channel_info; + rtt_source_start start; + rtt_source_stop stop; + rtt_source_read read; + rtt_source_write write; +}; + +/** + * Initialize Real-Time Transfer (RTT). + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_init(void); + +/** + * Shutdown Real-Time Transfer (RTT). + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_exit(void); + +/** + * Register an RTT source for a target. + * + * @param[in] source RTT source. + * @param[in,out] target Target. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_register_source(const struct rtt_source source, + struct target *target); + +/** + * Setup RTT. + * + * @param[in] address Start address to search for the control block. + * @param[in] size Size of the control block search area. + * @param[in] id Identifier of the control block. Must be null-terminated. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_setup(target_addr_t address, size_t size, const char *id); + +/** + * Start Real-Time Transfer (RTT). + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_start(void); + +/** + * Stop Real-Time Transfer (RTT). + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_stop(void); + +/** + * Get the polling interval. + * + * @param[out] interval Polling interval in milliseconds. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_get_polling_interval(unsigned int *interval); + +/** + * Set the polling interval. + * + * @param[in] interval Polling interval in milliseconds. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_set_polling_interval(unsigned int interval); + +/** + * Get whether RTT is started. + * + * @returns Whether RTT is started. + */ +bool rtt_started(void); + +/** + * Get whether RTT is configured. + * + * @returns Whether RTT is configured. + */ +bool rtt_configured(void); + +/** + * Get whether RTT control block was found. + * + * @returns Whether RTT was found. + */ +bool rtt_found_cb(void); + +/** + * Get the RTT control block. + * + * @returns The RTT control block. + */ +const struct rtt_control *rtt_get_control(void); + +/** + * Read channel information. + * + * @param[in] channel_index Channel index. + * @param[in] type Channel type. + * @param[out] info Channel information. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_read_channel_info(unsigned int channel_index, + enum rtt_channel_type type, struct rtt_channel_info *info); + +/** + * Register an RTT sink. + * + * @param[in] channel_index Channel index. + * @param[in] read Read callback function. + * @param[in,out] user_data User data to be passed to the callback function. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_register_sink(unsigned int channel_index, rtt_sink_read read, + void *user_data); + +/** + * Unregister an RTT sink. + * + * @param[in] channel_index Channel index. + * @param[in] read Read callback function. + * @param[in,out] user_data User data to be passed to the callback function. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read, + void *user_data); + +/** + * Write to an RTT channel. + * + * @param[in] channel_index Channel index. + * @param[in] buffer Buffer with data that should be written to the channel. + * @param[in,out] length Number of bytes to write. On success, the argument gets + * updated with the actual number of written bytes. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer, + size_t *length); + +extern const struct command_registration rtt_target_command_handlers[]; + +#endif /* OPENOCD_RTT_RTT_H */ diff --git a/src/rtt/tcl.c b/src/rtt/tcl.c new file mode 100644 index 0000000000..2b8822fce8 --- /dev/null +++ b/src/rtt/tcl.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2019-2020 by Marc Schink <dev@zapb.de> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/log.h> +#include <target/rtt.h> + +#include "rtt.h" + +#define CHANNEL_NAME_SIZE 128 + +COMMAND_HANDLER(handle_rtt_setup_command) +{ + struct rtt_source source; + + if (CMD_ARGC != 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + source.find_cb = &target_rtt_find_control_block; + source.read_cb = &target_rtt_read_control_block; + source.start = &target_rtt_start; + source.stop = &target_rtt_stop; + source.read = &target_rtt_read_callback; + source.write = &target_rtt_write_callback; + source.read_channel_info = &target_rtt_read_channel_info; + + target_addr_t address; + uint32_t size; + + COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[0], address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); + + rtt_register_source(source, get_current_target(CMD_CTX)); + + if (rtt_setup(address, size, CMD_ARGV[2]) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_rtt_start_command) +{ + if (CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!rtt_configured()) { + command_print(CMD, "RTT is not configured"); + return ERROR_FAIL; + } + + return rtt_start(); +} + +COMMAND_HANDLER(handle_rtt_stop_command) +{ + if (CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + return rtt_stop(); +} + +COMMAND_HANDLER(handle_rtt_polling_interval_command) +{ + if (CMD_ARGC == 0) { + int ret; + unsigned int interval; + + ret = rtt_get_polling_interval(&interval); + + if (ret != ERROR_OK) { + command_print(CMD, "Failed to get polling interval"); + return ret; + } + + command_print(CMD, "%u ms", interval); + } else if (CMD_ARGC == 1) { + int ret; + unsigned int interval; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], interval); + ret = rtt_set_polling_interval(interval); + + if (ret != ERROR_OK) { + command_print(CMD, "Failed to set polling interval"); + return ret; + } + } else { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_rtt_channels_command) +{ + int ret; + char channel_name[CHANNEL_NAME_SIZE]; + const struct rtt_control *ctrl; + struct rtt_channel_info info; + + if (!rtt_found_cb()) { + command_print(CMD, "rtt: Control block not available"); + return ERROR_FAIL; + } + + ctrl = rtt_get_control(); + + command_print(CMD, "Channels: up=%u, down=%u", ctrl->num_up_channels, + ctrl->num_down_channels); + + command_print(CMD, "Up-channels:"); + + info.name = channel_name; + info.name_length = sizeof(channel_name); + + for (unsigned int i = 0; i < ctrl->num_up_channels; i++) { + ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info); + + if (ret != ERROR_OK) + return ret; + + if (!info.size) + continue; + + command_print(CMD, "%u: %s %u %u", i, info.name, info.size, + info.flags); + } + + command_print(CMD, "Down-channels:"); + + for (unsigned int i = 0; i < ctrl->num_down_channels; i++) { + ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info); + + if (ret != ERROR_OK) + return ret; + + if (!info.size) + continue; + + command_print(CMD, "%u: %s %u %u", i, info.name, info.size, + info.flags); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_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()) { + command_print(CMD, "rtt: Control block not available"); + return ERROR_FAIL; + } + + ctrl = rtt_get_control(); + + info.name = channel_name; + info.name_length = sizeof(channel_name); + + command_print(CMD, "{"); + + for (unsigned int i = 0; i < ctrl->num_up_channels; i++) { + int ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info); + if (ret != ERROR_OK) + return ret; + + if (!info.size) + continue; + + command_print(CMD, + " {\n" + " name %s\n" + " size 0x%" PRIx32 "\n" + " flags 0x%" PRIx32 "\n" + " }", + info.name, info.size, info.flags); + } + + command_print(CMD, "}\n{"); + + for (unsigned int i = 0; i < ctrl->num_down_channels; i++) { + int ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info); + if (ret != ERROR_OK) + return ret; + + if (!info.size) + continue; + + command_print(CMD, + " {\n" + " name %s\n" + " size 0x%" PRIx32 "\n" + " flags 0x%" PRIx32 "\n" + " }", + info.name, info.size, info.flags); + } + + command_print(CMD, "}"); + + return ERROR_OK; +} + +static const struct command_registration rtt_subcommand_handlers[] = { + { + .name = "setup", + .handler = handle_rtt_setup_command, + .mode = COMMAND_ANY, + .help = "setup RTT", + .usage = "<address> <size> <ID>" + }, + { + .name = "start", + .handler = handle_rtt_start_command, + .mode = COMMAND_EXEC, + .help = "start RTT", + .usage = "" + }, + { + .name = "stop", + .handler = handle_rtt_stop_command, + .mode = COMMAND_EXEC, + .help = "stop RTT", + .usage = "" + }, + { + .name = "polling_interval", + .handler = handle_rtt_polling_interval_command, + .mode = COMMAND_EXEC, + .help = "show or set polling interval in ms", + .usage = "[interval]" + }, + { + .name = "channels", + .handler = handle_rtt_channels_command, + .mode = COMMAND_EXEC, + .help = "list available channels", + .usage = "" + }, + { + .name = "channellist", + .handler = handle_channel_list, + .mode = COMMAND_EXEC, + .help = "list available channels", + .usage = "" + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration rtt_target_command_handlers[] = { + { + .name = "rtt", + .mode = COMMAND_EXEC, + .help = "RTT target commands", + .usage = "", + .chain = rtt_subcommand_handlers + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/server/Makefile.am b/src/server/Makefile.am index 804efac16d..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 \ @@ -6,14 +8,11 @@ noinst_LTLIBRARIES += %D%/libserver.la %D%/server.h \ %D%/telnet_server.h \ %D%/gdb_server.h \ - %D%/server_stubs.c \ %D%/tcl_server.c \ - %D%/tcl_server.h - -%C%_libserver_la_CFLAGS = $(AM_CFLAGS) -if IS_MINGW -# FD_* macros are sloppy with their signs on MinGW32 platform -%C%_libserver_la_CFLAGS += -Wno-sign-compare -endif + %D%/tcl_server.h \ + %D%/rtt_server.c \ + %D%/rtt_server.h \ + %D%/ipdbg.c \ + %D%/ipdbg.h STARTUP_TCL_SRCS += %D%/startup.tcl diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index c369665547..c1ee4aa2a1 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 @@ -61,6 +50,15 @@ * found in most modern embedded processors. */ +enum gdb_output_flag { + /* GDB doesn't accept 'O' packets */ + GDB_OUTPUT_NO, + /* GDB doesn't accept 'O' packets but accepts notifications */ + GDB_OUTPUT_NOTIF, + /* GDB accepts 'O' packets */ + GDB_OUTPUT_ALL, +}; + struct target_desc_format { char *tdesc; uint32_t tdesc_length; @@ -75,6 +73,8 @@ struct gdb_connection { enum target_state frontend_state; struct image *vflash_image; bool closed; + /* set to prevent re-entrance from log messages during gdb_get_packet() + * and gdb_put_packet(). */ bool busy; int noack_mode; /* set flag to true if you want the next stepi to return immediately. @@ -97,6 +97,10 @@ struct gdb_connection { struct target_desc_format target_desc; /* temporarily used for thread list support */ 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 @@ -119,7 +123,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 */ @@ -147,6 +151,9 @@ static char gdb_running_type; 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 */ @@ -161,8 +168,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; } } @@ -177,7 +185,7 @@ static int check_pending(struct connection *connection, fd_set read_fds; struct gdb_connection *gdb_con = connection->priv; int t; - if (got_data == NULL) + if (!got_data) got_data = &t; *got_data = 0; @@ -227,44 +235,26 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) if (gdb_con->buf_cnt > 0) break; if (gdb_con->buf_cnt == 0) { + LOG_DEBUG("GDB connection closed by the remote client"); gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } #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_ @@ -348,23 +338,74 @@ static int gdb_putback_char(struct connection *connection, int last_char) static int gdb_write(struct connection *connection, void *data, int len) { struct gdb_connection *gdb_con = connection->priv; - if (gdb_con->closed) + if (gdb_con->closed) { + LOG_DEBUG("GDB socket marked as closed, cannot write to it."); return ERROR_SERVER_REMOTE_CLOSED; + } if (connection_write(connection, data, len) == len) return ERROR_OK; + + LOG_WARNING("Error writing to GDB socket. Dropping the connection."); gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } +static void gdb_log_incoming_packet(struct connection *connection, char *packet) +{ + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) + 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); + const char *nonprint = find_nonprint_char(packet, packet_len); + if (nonprint) { + /* Does packet at least have a prefix that is printable? + * Look within the first 50 chars of the packet. */ + const char *colon = memchr(packet, ':', MIN(50, packet_len)); + const bool packet_has_prefix = (colon); + const bool packet_prefix_printable = (packet_has_prefix && nonprint > colon); + + 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, "{%d} received packet: %.*s<binary-data-%u-bytes>", + gdb_connection->unique_index, prefix_len, packet, payload_len); + } else { + 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, "{%d} received packet: %s", gdb_connection->unique_index, packet); + } +} + +static void gdb_log_outgoing_packet(struct connection *connection, char *packet_buf, + unsigned int packet_len, unsigned char checksum) +{ + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) + 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, "{%d} sending packet: $<binary-data-%u-bytes>#%2.2x", + gdb_connection->unique_index, packet_len, checksum); + else + 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, char *buffer, int len) { int i; unsigned char my_checksum = 0; -#ifdef _DEBUG_GDB_IO_ - char *debug_buffer; -#endif int reply; int retval; struct gdb_connection *gdb_con = connection->priv; @@ -400,11 +441,7 @@ static int gdb_put_packet_inner(struct connection *connection, #endif while (1) { -#ifdef _DEBUG_GDB_IO_ - debug_buffer = strndup(buffer, len); - LOG_DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum); - free(debug_buffer); -#endif + gdb_log_outgoing_packet(connection, buffer, len, my_checksum); char local_buffer[1024]; local_buffer[0] = '$'; @@ -437,22 +474,27 @@ static int gdb_put_packet_inner(struct connection *connection, if (retval != ERROR_OK) return retval; - if (reply == '+') + if (reply == '+') { + gdb_log_incoming_packet(connection, "+"); break; - else if (reply == '-') { + } else if (reply == '-') { /* Stop sending output packets for now */ - log_remove_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_NO; + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); } else if (reply == 0x3) { gdb_con->ctrl_c = true; + gdb_log_incoming_packet(connection, "<Ctrl-C>"); retval = gdb_get_char(connection, &reply); if (retval != ERROR_OK) return retval; - if (reply == '+') + if (reply == '+') { + gdb_log_incoming_packet(connection, "+"); break; - else if (reply == '-') { + } else if (reply == '-') { /* Stop sending output packets for now */ - log_remove_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_NO; + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); } else if (reply == '$') { LOG_ERROR("GDB missing ack(1) - assumed good"); @@ -629,6 +671,7 @@ static int gdb_get_packet_inner(struct connection *connection, case '$': break; case '+': + gdb_log_incoming_packet(connection, "+"); /* According to the GDB documentation * (https://sourceware.org/gdb/onlinedocs/gdb/Packet-Acknowledgment.html): * "gdb sends a final `+` acknowledgment of the stub's `OK` @@ -646,9 +689,11 @@ static int gdb_get_packet_inner(struct connection *connection, } break; case '-': + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative acknowledgment, but no packet pending"); break; case 0x3: + gdb_log_incoming_packet(connection, "<Ctrl-C>"); gdb_con->ctrl_c = true; *len = 0; return ERROR_OK; @@ -705,7 +750,7 @@ static int gdb_output_con(struct connection *connection, const char *line) bin_size = strlen(line); hex_buffer = malloc(bin_size * 2 + 2); - if (hex_buffer == NULL) + if (!hex_buffer) return ERROR_GDB_BUFFER_TOO_SMALL; hex_buffer[0] = 'O'; @@ -728,7 +773,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio { struct gdb_connection *gdb_connection = connection->priv; char sig_reply[65]; - char stop_reason[20]; + char stop_reason[32]; char current_thread[25]; int sig_reply_len; int signal_var; @@ -739,7 +784,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "W00"); } else { struct target *ct; - if (target->rtos != NULL) { + if (target->rtos) { target->rtos->current_threadid = target->rtos->current_thread; target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct); } else { @@ -747,6 +792,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); @@ -778,7 +824,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio } current_thread[0] = '\0'; - if (target->rtos != NULL) + if (target->rtos) snprintf(current_thread, sizeof(current_thread), "thread:%" PRIx64 ";", target->rtos->current_thread); @@ -895,7 +941,7 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec */ if (gdb_connection->frontend_state == TARGET_RUNNING) { /* stop forwarding log packets! */ - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; /* check fileio first */ if (target_get_gdb_fileio_info(target, target->fileio_info) == ERROR_OK) @@ -934,6 +980,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; @@ -955,9 +1002,8 @@ static int gdb_new_connection(struct connection *connection) gdb_connection->target_desc.tdesc = NULL; gdb_connection->target_desc.tdesc_length = 0; gdb_connection->thread_list = NULL; - - /* send ACK to GDB for debug request */ - gdb_write(connection, "+", 1); + gdb_connection->output_flag = GDB_OUTPUT_NO; + gdb_connection->unique_index = next_unique_id++; /* output goes through gdb connection */ command_set_output_handler(connection->cmd_ctx, gdb_output, connection); @@ -969,6 +1015,21 @@ static int gdb_new_connection(struct connection *connection) breakpoint_clear_target(target); watchpoint_clear_target(target); + /* Since version 3.95 (gdb-19990504), with the exclusion of 6.5~6.8, GDB + * sends an ACK at connection with the following comment in its source code: + * "Ack any packet which the remote side has already sent." + * LLDB does the same since the first gdb-remote implementation. + * Remove the initial ACK from the incoming buffer. + */ + retval = gdb_get_char(connection, &initial_ack); + if (retval != ERROR_OK) + return retval; + + if (initial_ack != '+') + gdb_putback_char(connection, initial_ack); + + target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH); + if (target->rtos) { /* clean previous rtos session if supported*/ if (target->rtos->type->clean) @@ -978,18 +1039,6 @@ static int gdb_new_connection(struct connection *connection) rtos_update_threads(target); } - /* remove the initial ACK from the incoming buffer */ - retval = gdb_get_char(connection, &initial_ack); - if (retval != ERROR_OK) - return retval; - - /* FIX!!!??? would we actually ever receive a + here??? - * Not observed. - */ - if (initial_ack != '+') - gdb_putback_char(connection, initial_ack); - target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH); - if (gdb_use_memory_map) { /* Connect must fail if the memory map can't be set up correctly. * @@ -1010,20 +1059,19 @@ static int gdb_new_connection(struct connection *connection) } } - gdb_actual_connections++; - log_printf_lf(all_targets->next != NULL ? LOG_LVL_INFO : LOG_LVL_DEBUG, + 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", @@ -1036,6 +1084,8 @@ static int gdb_new_connection(struct connection *connection) * register callback to be informed about target events */ target_register_event_callback(gdb_target_callback_event_handler, connection); + log_add_callback(gdb_log_callback, connection); + return ERROR_OK; } @@ -1052,7 +1102,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); @@ -1164,6 +1215,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) { @@ -1180,7 +1252,7 @@ static int gdb_get_registers_packet(struct connection *connection, LOG_DEBUG("-"); #endif - if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg_list(connection))) + if ((target->rtos) && (rtos_get_gdb_reg_list(connection) == ERROR_OK)) return ERROR_OK; retval = target_get_gdb_reg_list(target, ®_list, ®_list_size, @@ -1189,7 +1261,7 @@ static int gdb_get_registers_packet(struct connection *connection, return gdb_error(connection, retval); for (i = 0; i < reg_list_size; i++) { - if (reg_list[i] == NULL || reg_list[i]->exist == false) + if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden) continue; reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; } @@ -1197,24 +1269,19 @@ static int gdb_get_registers_packet(struct connection *connection, assert(reg_packet_size > 0); reg_packet = malloc(reg_packet_size + 1); /* plus one for string termination null */ - if (reg_packet == NULL) + if (!reg_packet) return ERROR_FAIL; reg_packet_p = reg_packet; for (i = 0; i < reg_list_size; i++) { - if (reg_list[i] == NULL || reg_list[i]->exist == false) + 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; } @@ -1266,6 +1333,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) @@ -1310,7 +1379,7 @@ static int gdb_get_register_packet(struct connection *connection, LOG_DEBUG("-"); #endif - if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg(connection, reg_num))) + if ((target->rtos) && (rtos_get_gdb_reg(connection, reg_num) == ERROR_OK)) return ERROR_OK; retval = target_get_gdb_reg_list_noread(target, ®_list, ®_list_size, @@ -1318,23 +1387,19 @@ static int gdb_get_register_packet(struct connection *connection, if (retval != ERROR_OK) return gdb_error(connection, retval); - if (reg_list_size <= reg_num) { - LOG_ERROR("gdb requested a non-existing register"); + 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); - } - } - - reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */ + 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); @@ -1366,8 +1431,8 @@ static int gdb_set_register_packet(struct connection *connection, uint8_t *bin_buf = malloc(chars / 2); gdb_target_to_reg(target, separator + 1, chars, bin_buf); - if ((target->rtos != NULL) && - (ERROR_OK == rtos_set_reg(connection, reg_num, bin_buf))) { + if ((target->rtos) && + (rtos_set_reg(connection, reg_num, bin_buf) == ERROR_OK)) { free(bin_buf); gdb_put_packet(connection, "OK", 2); return ERROR_OK; @@ -1380,8 +1445,9 @@ static int gdb_set_register_packet(struct connection *connection, return gdb_error(connection, retval); } - if (reg_list_size <= reg_num) { - LOG_ERROR("gdb requested a non-existing register"); + 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); return ERROR_SERVER_REMOTE_CLOSED; @@ -1424,9 +1490,6 @@ static int gdb_error(struct connection *connection, int retval) return ERROR_OK; } -/* We don't have to worry about the default 2 second timeout for GDB packets, - * because GDB breaks up large memory reads into smaller reads. - */ static int gdb_read_memory_packet(struct connection *connection, char const *packet, int packet_size) { @@ -1462,7 +1525,11 @@ static int gdb_read_memory_packet(struct connection *connection, LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); - retval = target_read_buffer(target, addr, len, buffer); + retval = ERROR_NOT_IMPLEMENTED; + if (target->rtos) + retval = rtos_read_buffer(target, addr, len, buffer); + if (retval == ERROR_NOT_IMPLEMENTED) + retval = target_read_buffer(target, addr, len, buffer); if ((retval != ERROR_OK) && !gdb_report_data_abort) { /* TODO : Here we have to lie and send back all zero's lest stack traces won't work. @@ -1533,7 +1600,11 @@ static int gdb_write_memory_packet(struct connection *connection, if (unhexify(buffer, separator, len) != len) LOG_ERROR("unable to decode memory packet"); - retval = target_write_buffer(target, addr, len, buffer); + retval = ERROR_NOT_IMPLEMENTED; + if (target->rtos) + retval = rtos_write_buffer(target, addr, len, buffer); + if (retval == ERROR_NOT_IMPLEMENTED) + retval = target_write_buffer(target, addr, len, buffer); if (retval == ERROR_OK) gdb_put_packet(connection, "OK", 2); @@ -1602,7 +1673,12 @@ static int gdb_write_memory_binary_packet(struct connection *connection, if (len) { LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); - retval = target_write_buffer(target, addr, len, (uint8_t *)separator); + retval = ERROR_NOT_IMPLEMENTED; + if (target->rtos) + retval = rtos_write_buffer(target, addr, len, (uint8_t *)separator); + if (retval == ERROR_NOT_IMPLEMENTED) + retval = target_write_buffer(target, addr, len, (uint8_t *)separator); + if (retval != ERROR_OK) gdb_connection->mem_write_error = true; } @@ -1700,7 +1776,10 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, case 1: if (packet[0] == 'Z') { 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; @@ -1716,8 +1795,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; @@ -1747,14 +1829,14 @@ static __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))) void xml_printf( int first = 1; for (;; ) { - if ((*xml == NULL) || (!first)) { + if ((!*xml) || (!first)) { /* start by 0 to exercise all the code paths. * Need minimum 2 bytes to fit 1 char and 0 terminator. */ *size = *size * 2 + 2; char *t = *xml; *xml = realloc(*xml, *size); - if (*xml == NULL) { + if (!*xml) { free(t); *retval = ERROR_SERVER_REMOTE_CLOSED; return; @@ -1779,7 +1861,7 @@ static int decode_xfer_read(char const *buf, char **annex, int *ofs, unsigned in { /* Locate the annex. */ const char *annex_end = strchr(buf, ':'); - if (annex_end == NULL) + if (!annex_end) return ERROR_FAIL; /* After the read marker and annex, qXfer looks like a @@ -1793,9 +1875,9 @@ static int decode_xfer_read(char const *buf, char **annex, int *ofs, unsigned in *len = strtoul(separator + 1, NULL, 16); /* Extract the annex if needed */ - if (annex != NULL) { + if (annex) { *annex = strndup(buf, annex_end - buf); - if (*annex == NULL) + if (!*annex) return ERROR_FAIL; } @@ -2014,7 +2096,7 @@ static int lookup_add_arch_defined_types(char const **arch_defined_types_list[], { int tbl_sz = *num_arch_defined_types; - if (type_id != NULL && (strcmp(type_id, ""))) { + if (type_id && (strcmp(type_id, ""))) { for (int j = 0; j < (tbl_sz + 1); j++) { if (!((*arch_defined_types_list)[j])) { (*arch_defined_types_list)[tbl_sz++] = type_id; @@ -2057,7 +2139,7 @@ static int gdb_generate_reg_type_description(struct target *target, } else if (type->type_class == REG_TYPE_CLASS_UNION) { struct reg_data_type_union_field *field; field = type->reg_type_union->fields; - while (field != NULL) { + while (field) { struct reg_data_type *data_type = field->type; if (data_type->type == REG_TYPE_ARCH_DEFINED) { if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, @@ -2077,7 +2159,7 @@ static int gdb_generate_reg_type_description(struct target *target, type->id); field = type->reg_type_union->fields; - while (field != NULL) { + while (field) { xml_printf(&retval, tdesc, pos, size, "<field name=\"%s\" type=\"%s\"/>\n", field->name, field->type->id); @@ -2099,7 +2181,7 @@ static int gdb_generate_reg_type_description(struct target *target, xml_printf(&retval, tdesc, pos, size, "<struct id=\"%s\" size=\"%" PRIu32 "\">\n", type->id, type->reg_type_struct->size); - while (field != NULL) { + while (field) { xml_printf(&retval, tdesc, pos, size, "<field name=\"%s\" start=\"%" PRIu32 "\" end=\"%" PRIu32 "\" type=\"%s\" />\n", field->name, field->bitfield->start, field->bitfield->end, @@ -2108,7 +2190,7 @@ static int gdb_generate_reg_type_description(struct target *target, field = field->next; } } else { - while (field != NULL) { + while (field) { struct reg_data_type *data_type = field->type; if (data_type->type == REG_TYPE_ARCH_DEFINED) { if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, @@ -2125,7 +2207,7 @@ static int gdb_generate_reg_type_description(struct target *target, xml_printf(&retval, tdesc, pos, size, "<struct id=\"%s\">\n", type->id); - while (field != NULL) { + while (field) { xml_printf(&retval, tdesc, pos, size, "<field name=\"%s\" type=\"%s\"/>\n", field->name, field->type->id); @@ -2147,7 +2229,7 @@ static int gdb_generate_reg_type_description(struct target *target, struct reg_data_type_flags_field *field; field = type->reg_type_flags->fields; - while (field != NULL) { + while (field) { xml_printf(&retval, tdesc, pos, size, "<field name=\"%s\" start=\"%" PRIu32 "\" end=\"%" PRIu32 "\" type=\"%s\" />\n", field->name, field->bitfield->start, field->bitfield->end, @@ -2176,11 +2258,11 @@ static int get_reg_features_list(struct target *target, char const **feature_lis *feature_list = calloc(1, sizeof(char *)); for (int i = 0; i < reg_list_size; i++) { - if (reg_list[i]->exist == false) + if (reg_list[i]->exist == false || reg_list[i]->hidden) continue; - if (reg_list[i]->feature != NULL - && reg_list[i]->feature->name != NULL + if (reg_list[i]->feature + && reg_list[i]->feature->name && (strcmp(reg_list[i]->feature->name, ""))) { /* We found a feature, check if the feature is already in the * table. If not, allocate a new entry for the table and @@ -2206,6 +2288,123 @@ static int get_reg_features_list(struct target *target, char const **feature_lis return ERROR_OK; } +/* Create a register list that's the union of all the registers of the SMP + * group this target is in. If the target is not part of an SMP group, this + * returns the same as target_get_gdb_reg_list_noread(). + */ +static int smp_reg_list_noread(struct target *target, + struct reg **combined_list[], int *combined_list_size, + enum target_register_class reg_class) +{ + if (!target->smp) + return target_get_gdb_reg_list_noread(target, combined_list, + combined_list_size, REG_CLASS_ALL); + + unsigned int combined_allocated = 256; + struct reg **local_list = malloc(combined_allocated * sizeof(struct reg *)); + if (!local_list) { + LOG_ERROR("malloc(%zu) failed", combined_allocated * sizeof(struct reg *)); + return ERROR_FAIL; + } + unsigned int local_list_size = 0; + + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { + if (!target_was_examined(head->target)) + continue; + + struct reg **reg_list = NULL; + int reg_list_size; + int result = target_get_gdb_reg_list_noread(head->target, ®_list, + ®_list_size, reg_class); + if (result != ERROR_OK) { + free(local_list); + return result; + } + for (int i = 0; i < reg_list_size; i++) { + bool found = false; + struct reg *a = reg_list[i]; + if (a->exist) { + /* Nested loop makes this O(n^2), but this entire function with + * 5 RISC-V targets takes just 2ms on my computer. Fast enough + * for me. */ + for (unsigned int j = 0; j < local_list_size; j++) { + struct reg *b = local_list[j]; + if (!strcmp(a->name, b->name)) { + found = true; + if (a->size != b->size) { + LOG_ERROR("SMP register %s is %d bits on one " + "target, but %d bits on another target.", + a->name, a->size, b->size); + free(reg_list); + free(local_list); + return ERROR_FAIL; + } + break; + } + } + if (!found) { + LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name); + if (local_list_size >= combined_allocated) { + combined_allocated *= 2; + 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; + } + } + local_list[local_list_size] = a; + local_list_size++; + } + } + } + free(reg_list); + } + + if (local_list_size == 0) { + LOG_ERROR("Unable to get register list"); + free(local_list); + return ERROR_FAIL; + } + + /* Now warn the user about any registers that weren't found in every target. */ + foreach_smp_target(head, target->smp_targets) { + if (!target_was_examined(head->target)) + continue; + + struct reg **reg_list = NULL; + int reg_list_size; + int result = target_get_gdb_reg_list_noread(head->target, ®_list, + ®_list_size, reg_class); + if (result != ERROR_OK) { + free(local_list); + return result; + } + for (unsigned int i = 0; i < local_list_size; i++) { + bool found = false; + struct reg *a = local_list[i]; + for (int j = 0; j < reg_list_size; j++) { + struct reg *b = reg_list[j]; + if (b->exist && !strcmp(a->name, b->name)) { + found = true; + break; + } + } + if (!found) { + LOG_WARNING("Register %s does not exist in %s, which is part of an SMP group where " + "this register does exist.", + a->name, target_name(head->target)); + } + } + free(reg_list); + } + + *combined_list = local_list; + *combined_list_size = local_list_size; + return ERROR_OK; +} + static int gdb_generate_target_description(struct target *target, char **tdesc_out) { int retval = ERROR_OK; @@ -2219,8 +2418,8 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o int size = 0; - retval = target_get_gdb_reg_list_noread(target, ®_list, - ®_list_size, REG_CLASS_ALL); + retval = smp_reg_list_noread(target, ®_list, ®_list_size, + REG_CLASS_ALL); if (retval != ERROR_OK) { LOG_ERROR("get register list failed"); @@ -2252,12 +2451,12 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o /* generate architecture element if supported by target */ architecture = target_get_gdb_arch(target); - if (architecture != NULL) + if (architecture) xml_printf(&retval, &tdesc, &pos, &size, "<architecture>%s</architecture>\n", architecture); /* generate target description according to register list */ - if (features != NULL) { + if (features) { while (features[current_feature]) { char const **arch_defined_types = NULL; int num_arch_defined_types = 0; @@ -2270,14 +2469,14 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o int i; for (i = 0; i < reg_list_size; i++) { - if (reg_list[i]->exist == false) + if (reg_list[i]->exist == false || reg_list[i]->hidden) continue; if (strcmp(reg_list[i]->feature->name, features[current_feature])) continue; const char *type_str; - if (reg_list[i]->reg_data_type != NULL) { + if (reg_list[i]->reg_data_type) { if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) { /* generate <type... first, if there are architecture-defined types. */ if (lookup_add_arch_defined_types(&arch_defined_types, @@ -2315,7 +2514,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o xml_printf(&retval, &tdesc, &pos, &size, " type=\"%s\"", type_str); - if (reg_list[i]->group != NULL) + if (reg_list[i]->group) xml_printf(&retval, &tdesc, &pos, &size, " group=\"%s\"", reg_list[i]->group); @@ -2349,7 +2548,7 @@ error: static int gdb_get_target_description_chunk(struct target *target, struct target_desc_format *target_desc, char **chunk, int32_t offset, uint32_t length) { - if (target_desc == NULL) { + if (!target_desc) { LOG_ERROR("Unable to Generate Target Description"); return ERROR_FAIL; } @@ -2357,7 +2556,7 @@ static int gdb_get_target_description_chunk(struct target *target, struct target char *tdesc = target_desc->tdesc; uint32_t tdesc_length = target_desc->tdesc_length; - if (tdesc == NULL) { + if (!tdesc) { int retval = gdb_generate_target_description(target, &tdesc); if (retval != ERROR_OK) { LOG_ERROR("Unable to Generate Target Description"); @@ -2375,7 +2574,7 @@ static int gdb_get_target_description_chunk(struct target *target, struct target transfer_type = 'l'; *chunk = malloc(length + 2); - if (*chunk == NULL) { + if (!*chunk) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } @@ -2457,22 +2656,28 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou "<?xml version=\"1.0\"?>\n" "<threads>\n"); - if (rtos != NULL) { + if (rtos) { for (int i = 0; i < rtos->thread_count; i++) { struct thread_detail *thread_detail = &rtos->thread_details[i]; if (!thread_detail->exists) continue; - xml_printf(&retval, &thread_list, &pos, &size, - "<thread id=\"%" PRIx64 "\">", thread_detail->threadid); + if (thread_detail->thread_name_str) + xml_printf(&retval, &thread_list, &pos, &size, + "<thread id=\"%" PRIx64 "\" name=\"%s\">", + thread_detail->threadid, + thread_detail->thread_name_str); + else + xml_printf(&retval, &thread_list, &pos, &size, + "<thread id=\"%" PRIx64 "\">", thread_detail->threadid); - if (thread_detail->thread_name_str != NULL) + if (thread_detail->thread_name_str) xml_printf(&retval, &thread_list, &pos, &size, "Name: %s", thread_detail->thread_name_str); - if (thread_detail->extra_info_str != NULL) { - if (thread_detail->thread_name_str != NULL) + if (thread_detail->extra_info_str) { + if (thread_detail->thread_name_str) xml_printf(&retval, &thread_list, &pos, &size, ", "); xml_printf(&retval, &thread_list, &pos, &size, @@ -2498,7 +2703,7 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou static int gdb_get_thread_list_chunk(struct target *target, char **thread_list, char **chunk, int32_t offset, uint32_t length) { - if (*thread_list == NULL) { + if (!*thread_list) { int retval = gdb_generate_thread_list(target, thread_list); if (retval != ERROR_OK) { LOG_ERROR("Unable to Generate Thread List"); @@ -2516,11 +2721,11 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list, transfer_type = 'l'; *chunk = malloc(length + 2 + 3); - /* Allocating extra 3 bytes prevents false positive valgrind report + /* Allocating extra 3 bytes prevents false positive valgrind report * of strlen(chunk) word access: * Invalid read of size 4 * Address 0x4479934 is 44 bytes inside a block of size 45 alloc'd */ - if (*chunk == NULL) { + if (!*chunk) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } @@ -2547,22 +2752,75 @@ static int gdb_query_packet(struct connection *connection, if (strncmp(packet, "qRcmd,", 6) == 0) { if (packet_size > 6) { + Jim_Interp *interp = cmd_ctx->interp; char *cmd; cmd = malloc((packet_size - 6) / 2 + 1); size_t len = unhexify((uint8_t *)cmd, packet + 6, (packet_size - 6) / 2); cmd[len] = 0; /* We want to print all debug output to GDB connection */ - log_add_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_ALL; target_call_timer_callbacks_now(); /* some commands need to know the GDB connection, make note of current * GDB connection. */ current_gdb_connection = gdb_connection; - command_run_line(cmd_ctx, cmd); + + struct target *saved_target_override = cmd_ctx->current_target_override; + cmd_ctx->current_target_override = NULL; + + struct command_context *old_context = Jim_GetAssocData(interp, "context"); + Jim_DeleteAssocData(interp, "context"); + int retval = Jim_SetAssocData(interp, "context", NULL, cmd_ctx); + if (retval == JIM_OK) { + retval = Jim_EvalObj(interp, Jim_NewStringObj(interp, cmd, -1)); + Jim_DeleteAssocData(interp, "context"); + } + int inner_retval = Jim_SetAssocData(interp, "context", NULL, old_context); + if (retval == JIM_OK) + retval = inner_retval; + + cmd_ctx->current_target_override = saved_target_override; + current_gdb_connection = NULL; target_call_timer_callbacks_now(); - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; free(cmd); + if (retval == JIM_RETURN) + retval = interp->returnCode; + int lenmsg; + const char *cretmsg = Jim_GetString(Jim_GetResult(interp), &lenmsg); + char *retmsg; + if (lenmsg && cretmsg[lenmsg - 1] != '\n') { + retmsg = alloc_printf("%s\n", cretmsg); + lenmsg++; + } else { + retmsg = strdup(cretmsg); + } + if (!retmsg) + return ERROR_GDB_BUFFER_TOO_SMALL; + + if (retval == JIM_OK) { + if (lenmsg) { + char *hex_buffer = malloc(lenmsg * 2 + 1); + if (!hex_buffer) { + free(retmsg); + return ERROR_GDB_BUFFER_TOO_SMALL; + } + + size_t pkt_len = hexify(hex_buffer, (const uint8_t *)retmsg, lenmsg, + lenmsg * 2 + 1); + gdb_put_packet(connection, hex_buffer, pkt_len); + free(hex_buffer); + } else { + gdb_put_packet(connection, "OK", 2); + } + } else { + if (lenmsg) + gdb_output_con(connection, retmsg); + gdb_send_error(connection, retval); + } + free(retmsg); + return ERROR_OK; } gdb_put_packet(connection, "OK", 2); return ERROR_OK; @@ -2710,13 +2968,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); @@ -2725,7 +2989,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p /* query for vCont supported */ if (parse[0] == '?') { - if (target->type->step != NULL) { + if (target->type->step) { /* gdb doesn't accept c without C and s without S */ gdb_put_packet(connection, "vCont;c;C;s;S", 13); return true; @@ -2735,14 +2999,13 @@ 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'; LOG_DEBUG("target %s continue", target_name(target)); - log_add_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_ALL; retval = target_resume(target, 1, 0, 0, 0); if (retval == ERROR_TARGET_NOT_HALTED) LOG_INFO("target %s was not halted when resume was requested", target_name(target)); @@ -2770,128 +3033,123 @@ 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 != NULL) { - packet_size -= endp - parse; + if (endp) { parse = endp; } + } else { + thread_id = 0; + } - if (target->rtos != NULL) { - /* FIXME: why is this necessary? rtos state should be up-to-date here already! */ - rtos_update_threads(target); + if (target->rtos) { + /* FIXME: why is this necessary? rtos state should be up-to-date here already! */ + rtos_update_threads(target); - target->rtos->gdb_target_for_threadid(connection, thread_id, &ct); + 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 - */ - if (target->rtos->current_thread != thread_id) - fake_step = true; - } + /* + * check if the thread to be stepped is the current rtos thread + * if not, we must fake the step + */ + if (target->rtos->current_thread != thread_id) + fake_step = true; + } - 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); - log_add_callback(gdb_log_callback, connection); - target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); - - /* - * work around an annoying gdb behaviour: when the current thread - * is changed in gdb, it assumes that the target can follow and also - * make the thread current. This is an assumption that cannot hold - * for a real target running a multi-threading OS. 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 - */ - if (fake_step) { - int sig_reply_len; - char sig_reply[128]; - - LOG_DEBUG("fake step thread %"PRIx64, thread_id); + 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); - sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), - "T05thread:%016"PRIx64";", thread_id); + /* + * work around an annoying gdb behaviour: when the current thread + * is changed in gdb, it assumes that the target can follow and also + * make the thread current. This is an assumption that cannot hold + * for a real target running a multi-threading OS. 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 + */ + if (fake_step) { + int sig_reply_len; + char sig_reply[128]; - gdb_put_packet(connection, sig_reply, sig_reply_len); - log_remove_callback(gdb_log_callback, connection); + LOG_DEBUG("fake step thread %"PRIx64, thread_id); - return true; - } + sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), + "T05thread:%016"PRIx64";", thread_id); - /* 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); - log_remove_callback(gdb_log_callback, connection); - } 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! */ - log_remove_callback(gdb_log_callback, connection); + /* 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; - } else { - LOG_ERROR("Unknown vCont packet"); - return false; + return true; } + + 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; } @@ -2903,7 +3161,7 @@ static char *next_hex_encoded_field(const char **str, char sep) return NULL; const char *end = strchr(hex, sep); - if (end == NULL) + if (!end) hexlen = strlen(hex); else hexlen = end - hex; @@ -2916,7 +3174,7 @@ static char *next_hex_encoded_field(const char **str, char sep) size_t count = hexlen / 2; char *decoded = malloc(count + 1); - if (decoded == NULL) + if (!decoded) return NULL; size_t converted = unhexify((void *)decoded, hex, count); @@ -2961,16 +3219,18 @@ static bool gdb_handle_vrun_packet(struct connection *connection, const char *pa free(next_hex_encoded_field(&parse, ';')); char *cmdline = next_hex_encoded_field(&parse, ';'); - char *arg; - while (cmdline != NULL && (arg = next_hex_encoded_field(&parse, ';')) != NULL) { + while (cmdline) { + char *arg = next_hex_encoded_field(&parse, ';'); + if (!arg) + break; char *new_cmdline = alloc_printf("%s %s", cmdline, arg); free(cmdline); free(arg); cmdline = new_cmdline; } - if (cmdline != NULL) { - if (target->semihosting != NULL) { + if (cmdline) { + if (target->semihosting) { LOG_INFO("GDB set inferior command line to '%s'", cmdline); free(target->semihosting->cmdline); target->semihosting->cmdline = cmdline; @@ -3024,7 +3284,7 @@ static int gdb_v_packet(struct connection *connection, } if (strncmp(packet, "vFlashErase:", 12) == 0) { - unsigned long addr; + target_addr_t addr; unsigned long length; char const *parse = packet + 12; @@ -3033,7 +3293,7 @@ static int gdb_v_packet(struct connection *connection, return ERROR_SERVER_REMOTE_CLOSED; } - addr = strtoul(parse, (char **)&parse, 16); + addr = strtoull(parse, (char **)&parse, 16); if (*(parse++) != ',' || *parse == '\0') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); @@ -3081,7 +3341,7 @@ static int gdb_v_packet(struct connection *connection, if (strncmp(packet, "vFlashWrite:", 12) == 0) { int retval; - unsigned long addr; + target_addr_t addr; unsigned long length; char const *parse = packet + 12; @@ -3089,7 +3349,8 @@ static int gdb_v_packet(struct connection *connection, LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } - addr = strtoul(parse, (char **)&parse, 16); + + addr = strtoull(parse, (char **)&parse, 16); if (*(parse++) != ':') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; @@ -3097,7 +3358,7 @@ static int gdb_v_packet(struct connection *connection, length = packet_size - (parse - packet); /* create a new image if there isn't already one */ - if (gdb_connection->vflash_image == NULL) { + if (!gdb_connection->vflash_image) { gdb_connection->vflash_image = malloc(sizeof(struct image)); image_open(gdb_connection->vflash_image, "", "build"); } @@ -3116,6 +3377,13 @@ static int gdb_v_packet(struct connection *connection, if (strncmp(packet, "vFlashDone", 10) == 0) { uint32_t written; + /* GDB command 'flash-erase' does not send a vFlashWrite, + * so nothing to write here. */ + if (!gdb_connection->vflash_image) { + gdb_put_packet(connection, "OK", 2); + return ERROR_OK; + } + /* process the flashing buffer. No need to erase as GDB * always issues a vFlashErase first. */ target_call_event_callbacks(target, @@ -3210,6 +3478,10 @@ static void gdb_log_callback(void *priv, const char *file, unsigned line, struct connection *connection = priv; struct gdb_connection *gdb_con = connection->priv; + if (gdb_con->output_flag != GDB_OUTPUT_ALL) + /* No out allowed */ + return; + if (gdb_con->busy) { /* do not reply this using the O packet */ return; @@ -3259,20 +3531,10 @@ static int gdb_input_inner(struct connection *connection) /* terminate with zero */ gdb_packet_buffer[packet_size] = '\0'; - if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { - if (packet[0] == 'X') { - /* binary packets spew junk into the debug log stream */ - char buf[50]; - int x; - for (x = 0; (x < 49) && (packet[x] != ':'); x++) - buf[x] = packet[x]; - buf[x] = 0; - LOG_DEBUG("received packet: '%s:<binary-data>'", buf); - } else - LOG_DEBUG("received packet: '%s'", packet); - } - if (packet_size > 0) { + + gdb_log_incoming_packet(connection, gdb_packet_buffer); + retval = ERROR_OK; switch (packet[0]) { case 'T': /* Is thread alive? */ @@ -3301,10 +3563,14 @@ static int gdb_input_inner(struct connection *connection) retval = gdb_set_register_packet(connection, packet, packet_size); break; case 'm': + gdb_con->output_flag = GDB_OUTPUT_NOTIF; retval = gdb_read_memory_packet(connection, packet, packet_size); + gdb_con->output_flag = GDB_OUTPUT_NO; break; case 'M': + gdb_con->output_flag = GDB_OUTPUT_NOTIF; retval = gdb_write_memory_packet(connection, packet, packet_size); + gdb_con->output_flag = GDB_OUTPUT_NO; break; case 'z': case 'Z': @@ -3315,7 +3581,7 @@ static int gdb_input_inner(struct connection *connection) /* '?' is sent after the eventual '!' */ if (!warn_use_ext && !gdb_con->extended_protocol) { warn_use_ext = true; - LOG_WARNING("Prefer GDB command \"target extended-remote %s\" instead of \"target remote %s\"", + LOG_WARNING("Prefer GDB command \"target extended-remote :%s\" instead of \"target remote :%s\"", connection->service->port, connection->service->port); } break; @@ -3323,7 +3589,7 @@ static int gdb_input_inner(struct connection *connection) case 's': { gdb_thread_packet(connection, packet, packet_size); - log_add_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_ALL; if (gdb_con->mem_write_error) { LOG_ERROR("Memory write failure!"); @@ -3366,7 +3632,7 @@ static int gdb_input_inner(struct connection *connection) gdb_sig_halted(connection); /* stop forwarding log packets! */ - log_remove_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_NO; } else { /* We're running/stepping, in which case we can * forward log output until the target is halted @@ -3395,9 +3661,9 @@ static int gdb_input_inner(struct connection *connection) retval = gdb_detach(connection); break; case 'X': + gdb_con->output_flag = GDB_OUTPUT_NOTIF; retval = gdb_write_memory_binary_packet(connection, packet, packet_size); - if (retval != ERROR_OK) - return retval; + gdb_con->output_flag = GDB_OUTPUT_NO; break; case 'k': if (gdb_con->extended_protocol) { @@ -3417,12 +3683,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 */ @@ -3438,7 +3706,7 @@ static int gdb_input_inner(struct connection *connection) * Fretcode,errno,Ctrl-C flag;call-specific attachment */ gdb_con->frontend_state = TARGET_RUNNING; - log_add_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_ALL; gdb_fileio_response_packet(connection, packet, packet_size); break; @@ -3491,13 +3759,76 @@ static int gdb_input(struct connection *connection) return ERROR_OK; } +/* + * Send custom notification packet as keep-alive during memory read/write. + * + * From gdb 7.0 (released 2009-10-06) an unknown notification received during + * memory read/write would be silently dropped. + * Before gdb 7.0 any character, with exclusion of "+-$", would be considered + * as junk and ignored. + * In both cases the reception will reset the timeout counter in gdb, thus + * working as a keep-alive. + * Check putpkt_binary() and getpkt_sane() in gdb commit + * 74531fed1f2d662debc2c209b8b3faddceb55960 + * + * Enable remote debug in gdb with 'set debug remote 1' to either dump the junk + * characters in gdb pre-7.0 and the notification from gdb 7.0. + */ +static void gdb_async_notif(struct connection *connection) +{ + static unsigned char count; + unsigned char checksum = 0; + char buf[22]; + + int len = sprintf(buf, "%%oocd_keepalive:%2.2x", count++); + for (int i = 1; i < len; i++) + checksum += buf[i]; + len += sprintf(buf + len, "#%2.2x", checksum); + +#ifdef _DEBUG_GDB_IO_ + LOG_DEBUG("sending packet '%s'", buf); +#endif + + gdb_write(connection, buf, len); +} + +static void gdb_keep_client_alive(struct connection *connection) +{ + struct gdb_connection *gdb_con = connection->priv; + + switch (gdb_con->output_flag) { + case GDB_OUTPUT_NO: + /* no need for keep-alive */ + break; + case GDB_OUTPUT_NOTIF: + /* send asynchronous notification */ + gdb_async_notif(connection); + break; + case GDB_OUTPUT_ALL: + /* send an empty O packet */ + gdb_output_con(connection, ""); + break; + default: + break; + } +} + +static const struct service_driver gdb_service_driver = { + .name = "gdb", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = gdb_new_connection, + .input_handler = gdb_input, + .connection_closed_handler = gdb_connection_closed, + .keep_client_alive_handler = gdb_keep_client_alive, +}; + static int gdb_target_start(struct target *target, const char *port) { struct gdb_service *gdb_service; int ret; gdb_service = malloc(sizeof(struct gdb_service)); - if (NULL == gdb_service) + if (!gdb_service) return -ENOMEM; LOG_INFO("starting gdb server for %s on %s", target_name(target), port); @@ -3507,19 +3838,14 @@ static int gdb_target_start(struct target *target, const char *port) gdb_service->core[1] = -1; target->gdb_service = gdb_service; - ret = add_service("gdb", - port, 1, &gdb_new_connection, &gdb_input, - &gdb_connection_closed, gdb_service); + ret = add_service(&gdb_service_driver, port, target->gdb_max_connections, gdb_service); /* initialize all targets gdb service with the same pointer */ { struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) curr->gdb_service = gdb_service; - head = head->next; } } return ret; @@ -3581,14 +3907,14 @@ static int gdb_target_add_one(struct target *target) int gdb_target_add_all(struct target *target) { - if (NULL == target) { + if (!target) { LOG_WARNING("gdb services need one or more targets defined"); return ERROR_OK; } - while (NULL != target) { + while (target) { int retval = gdb_target_add_one(target); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; target = target->next; @@ -3602,7 +3928,7 @@ COMMAND_HANDLER(handle_gdb_sync_command) if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; - if (current_gdb_connection == NULL) { + if (!current_gdb_connection) { command_print(CMD, "gdb_sync command can only be run from within gdb using \"monitor gdb_sync\""); return ERROR_FAIL; @@ -3617,7 +3943,7 @@ COMMAND_HANDLER(handle_gdb_sync_command) COMMAND_HANDLER(handle_gdb_port_command) { int retval = CALL_COMMAND_HANDLER(server_pipe_command, &gdb_port); - if (ERROR_OK == retval) { + if (retval == ERROR_OK) { free(gdb_port_next); gdb_port_next = strdup(gdb_port); } @@ -3711,7 +4037,7 @@ COMMAND_HANDLER(handle_gdb_save_tdesc_command) size_t size_written; char *tdesc_filename = alloc_printf("%s.xml", target_type_name(target)); - if (tdesc_filename == NULL) { + if (!tdesc_filename) { retval = ERROR_FAIL; goto out; } @@ -3825,3 +4151,8 @@ 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 993984bc38..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,6 +30,8 @@ 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; diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c new file mode 100644 index 0000000000..e7eb96e13c --- /dev/null +++ b/src/server/ipdbg.c @@ -0,0 +1,1159 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (C) 2020 by Daniel Anselmi <danselmi@gmx.ch> */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/bits.h> +#include <helper/time_support.h> +#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_CREATE_OPTIONS 3 +#define IPDBG_MAX_NUM_OF_CREATE_OPTIONS 10 +#define IPDBG_NUM_OF_START_OPTIONS 4 +#define IPDBG_NUM_OF_STOP_OPTIONS 2 +#define IPDBG_NUM_OF_QUEUE_OPTIONS 2 +#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 + +/* private connection data for IPDBG */ +struct ipdbg_fifo { + size_t count; + size_t rd_idx; + char buffer[IPDBG_BUFFER_SIZE]; +}; + +struct ipdbg_connection { + struct ipdbg_fifo dn_fifo; + struct ipdbg_fifo up_fifo; + bool closed; +}; + +struct ipdbg_service { + struct ipdbg_hub *hub; + struct ipdbg_service *next; + uint16_t port; + struct ipdbg_connection connection; + uint8_t tool; +}; + +struct ipdbg_virtual_ir_info { + uint32_t instruction; + uint32_t length; + 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; + uint32_t active_connections; + uint32_t active_services; + uint32_t valid_mask; + uint32_t xoff_mask; + uint32_t tool_mask; + uint32_t last_dn_tool; + char *name; + size_t using_queue_size; + struct ipdbg_hub *next; + struct jtag_tap *tap; + 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; + +static struct ipdbg_service *ipdbg_first_service; + +static void ipdbg_init_fifo(struct ipdbg_fifo *fifo) +{ + fifo->count = 0; + fifo->rd_idx = 0; +} + +static bool ipdbg_fifo_is_empty(struct ipdbg_fifo *fifo) +{ + return fifo->count == 0; +} + +static bool ipdbg_fifo_is_full(struct ipdbg_fifo *fifo) +{ + return fifo->count == IPDBG_BUFFER_SIZE; +} + +static void ipdbg_zero_rd_idx(struct ipdbg_fifo *fifo) +{ + if (fifo->rd_idx == 0) + return; + + size_t ri = fifo->rd_idx; + for (size_t idx = 0; idx < fifo->count; ++idx) + fifo->buffer[idx] = fifo->buffer[ri++]; + fifo->rd_idx = 0; +} + +static void ipdbg_append_to_fifo(struct ipdbg_fifo *fifo, char data) +{ + if (ipdbg_fifo_is_full(fifo)) + return; + + ipdbg_zero_rd_idx(fifo); + fifo->buffer[fifo->count++] = data; +} + +static char ipdbg_get_from_fifo(struct ipdbg_fifo *fifo) +{ + if (ipdbg_fifo_is_empty(fifo)) + return 0; + + fifo->count--; + return fifo->buffer[fifo->rd_idx++]; +} + +static int ipdbg_move_buffer_to_connection(struct connection *conn, struct ipdbg_fifo *fifo) +{ + if (ipdbg_fifo_is_empty(fifo)) + return ERROR_OK; + + struct ipdbg_connection *connection = conn->priv; + if (connection->closed) + return ERROR_SERVER_REMOTE_CLOSED; + + ipdbg_zero_rd_idx(fifo); + size_t bytes_written = connection_write(conn, fifo->buffer, fifo->count); + if (bytes_written != fifo->count) { + LOG_ERROR("error during write: %zu != %zu", bytes_written, fifo->count); + connection->closed = true; + return ERROR_SERVER_REMOTE_CLOSED; + } + + fifo->count -= bytes_written; + + return ERROR_OK; +} + +static int ipdbg_max_tools_from_data_register_length(uint8_t data_register_length) +{ + int max_tools = 1; + data_register_length -= 10; /* 8 bit payload, 1 xoff-flag, 1 valid-flag; remaining bits used to select tool*/ + while (data_register_length--) + max_tools *= 2; + + /* last tool is used to reset JtagCDC and transfer "XON" to host*/ + return max_tools - 1; +} + +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) { + if (service->hub == hub && service->tool == tool) + break; + } + return service; +} + +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) + ; + iservice->next = service; + } else + ipdbg_first_service = service; +} + +static int ipdbg_create_service(struct ipdbg_hub *hub, uint8_t tool, struct ipdbg_service **service, uint16_t port) +{ + *service = calloc(1, sizeof(struct ipdbg_service)); + if (!*service) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + (*service)->hub = hub; + (*service)->tool = tool; + (*service)->port = port; + + return ERROR_OK; +} + +static int ipdbg_remove_service(struct ipdbg_service *service) +{ + if (!ipdbg_first_service) + return ERROR_FAIL; + + if (service == ipdbg_first_service) { + ipdbg_first_service = ipdbg_first_service->next; + return ERROR_OK; + } + + for (struct ipdbg_service *iservice = ipdbg_first_service; iservice->next; iservice = iservice->next) { + if (service == iservice->next) { + iservice->next = service->next; + return ERROR_OK; + } + } + return ERROR_FAIL; +} + +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) { + if (hub->tap == tap && hub->user_instruction == user_instruction) { + if ((!virtual_ir && !hub->virtual_ir) || + (virtual_ir && hub->virtual_ir && + virtual_ir->instruction == hub->virtual_ir->instruction && + virtual_ir->length == hub->virtual_ir->length && + virtual_ir->value == hub->virtual_ir->value)) { + break; + } + } + } + return hub; +} + +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) + ; + ihub->next = hub; + } else { + ipdbg_first_hub = hub; + } +} + +static int ipdbg_remove_hub(struct ipdbg_hub *hub) +{ + if (!ipdbg_first_hub) + return ERROR_FAIL; + if (hub == ipdbg_first_hub) { + ipdbg_first_hub = ipdbg_first_hub->next; + return ERROR_OK; + } + + for (struct ipdbg_hub *ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next) { + if (hub == ihub->next) { + ihub->next = hub->next; + return ERROR_OK; + } + } + + return ERROR_FAIL; +} + +static void ipdbg_free_hub(struct ipdbg_hub *hub) +{ + if (!hub) + return; + free(hub->connections); + free(hub->virtual_ir); + free(hub->name); + 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); +} + +static struct ipdbg_hub *ipdbg_allocate_hub(uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, + const char *name) +{ + struct ipdbg_hub *new_hub = calloc(1, sizeof(struct ipdbg_hub)); + if (!new_hub) { + LOG_ERROR("Out of memory"); + return NULL; + } + + new_hub->name = strdup(name); + if (!new_hub->name) { + free(new_hub); + LOG_ERROR("Out of memory"); + return NULL; + } + + const size_t dreg_buffer_size = DIV_ROUND_UP(data_register_length, 8); + uint32_t 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(max_tools, sizeof(struct connection *)); + + 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) { + ipdbg_free_hub(new_hub); + LOG_ERROR("Out of memory"); + return NULL; + } + + return new_hub; +} + +static void ipdbg_init_scan_field(struct scan_field *fields, uint8_t *in_value, int num_bits, const uint8_t *out_value) +{ + fields->check_mask = NULL; + fields->check_value = NULL; + fields->in_value = in_value; + fields->num_bits = num_bits; + fields->out_value = out_value; +} + +static int ipdbg_shift_instr(struct ipdbg_hub *hub, uint32_t instr) +{ + if (!hub) + return ERROR_FAIL; + + struct jtag_tap *tap = hub->tap; + if (!tap) + return ERROR_FAIL; + + if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) == instr) { + /* there is already the requested instruction in the ir */ + return ERROR_OK; + } + + 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; + ipdbg_init_scan_field(&fields, NULL, tap->ir_length, ir_out_val); + jtag_add_ir_scan(tap, &fields, TAP_IDLE); + int retval = jtag_execute_queue(); + + free(ir_out_val); + + return retval; +} + +static int ipdbg_shift_vir(struct ipdbg_hub *hub) +{ + if (!hub) + return ERROR_FAIL; + + if (!hub->virtual_ir) + return ERROR_OK; + + int retval = ipdbg_shift_instr(hub, hub->virtual_ir->instruction); + if (retval != ERROR_OK) + return retval; + + struct jtag_tap *tap = hub->tap; + if (!tap) + return ERROR_FAIL; + + 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(); + + return retval; +} + +static int ipdbg_shift_data(struct ipdbg_hub *hub, uint32_t dn_data, uint32_t *up_data) +{ + if (!hub) + return ERROR_FAIL; + + struct jtag_tap *tap = hub->tap; + if (!tap) + return ERROR_FAIL; + + buf_set_u32(hub->scratch_memory.dr_out_vals, 0, hub->data_register_length, dn_data); + + 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(hub->scratch_memory.dr_in_vals, 0, hub->data_register_length); + + return retval; +} + +static int ipdbg_distribute_data_from_hub(struct ipdbg_hub *hub, uint32_t up) +{ + const bool valid_up_data = up & hub->valid_mask; + if (!valid_up_data) + return ERROR_OK; + + const size_t tool = (up >> 8) & hub->tool_mask; + if (tool == hub->tool_mask) { + const uint8_t xon_cmd = up & 0x00ff; + hub->dn_xoff &= ~xon_cmd; + LOG_INFO("received xon cmd: %d\n", xon_cmd); + return ERROR_OK; + } + + struct connection *conn = hub->connections[tool]; + if (conn) { + struct ipdbg_connection *connection = conn->priv; + if (ipdbg_fifo_is_full(&connection->up_fifo)) { + int retval = ipdbg_move_buffer_to_connection(conn, &connection->up_fifo); + if (retval != ERROR_OK) + return retval; + } + ipdbg_append_to_fifo(&connection->up_fifo, 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 < hub->using_queue_size; ++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 < hub->using_queue_size; ++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) | + (0x00fful & ipdbg_get_from_fifo(&connection->dn_fifo)); + uint32_t up = 0; + int ret = ipdbg_shift_data(hub, dn, &up); + if (ret != ERROR_OK) + return ret; + + ret = ipdbg_distribute_data_from_hub(hub, up); + if (ret != ERROR_OK) + return ret; + + 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 < hub->using_queue_size) ? + connection->dn_fifo.count : hub->using_queue_size; + + 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); + } + + int retval = jtag_execute_queue(); + + 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) +{ + struct ipdbg_hub *hub = priv; + + int ret = ipdbg_shift_vir(hub); + if (ret != ERROR_OK) + return ret; + + ret = ipdbg_shift_instr(hub, hub->user_instruction); + if (ret != ERROR_OK) + return ret; + + /* transfer dn buffers to jtag-hub */ + 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)) { + 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; + } + } + } + + /* some transfers to get data from jtag-hub in case there is no dn data */ + 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) { + struct connection *conn = hub->connections[tool]; + if (conn && conn->priv) { + struct ipdbg_connection *connection = conn->priv; + int retval = ipdbg_move_buffer_to_connection(conn, &connection->up_fifo); + if (retval != ERROR_OK) + return retval; + } + } + + 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; + hub->connections[service->tool] = connection; + hub->active_connections++; + if (hub->active_connections > 1) { + /* hub is already initialized */ + return ERROR_OK; + } + + const uint32_t reset_hub = hub->valid_mask | ((hub->max_tools) << 8); + + int ret = ipdbg_shift_vir(hub); + if (ret != ERROR_OK) + return ret; + + ret = ipdbg_shift_instr(hub, hub->user_instruction); + if (ret != ERROR_OK) + return ret; + + ret = ipdbg_shift_data(hub, reset_hub, NULL); + hub->last_dn_tool = hub->tool_mask; + hub->dn_xoff = 0; + 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; + const int periodic = 1; + return target_register_timer_callback(ipdbg_polling_callback, time_ms, periodic, hub); +} + +static int ipdbg_stop_polling(struct ipdbg_service *service) +{ + struct ipdbg_hub *hub = service->hub; + hub->connections[service->tool] = NULL; + hub->active_connections--; + if (hub->active_connections == 0) { + LOG_INFO("IPDBG stop_polling"); + + return target_unregister_timer_callback(ipdbg_polling_callback, hub); + } + + return ERROR_OK; +} + +static int ipdbg_on_new_connection(struct connection *connection) +{ + struct ipdbg_service *service = connection->service->priv; + connection->priv = &service->connection; + /* initialize ipdbg connection information */ + ipdbg_init_fifo(&service->connection.up_fifo); + ipdbg_init_fifo(&service->connection.dn_fifo); + + int retval = ipdbg_start_polling(service, connection); + if (retval != ERROR_OK) { + LOG_ERROR("BUG: ipdbg_start_polling failed"); + return retval; + } + + struct ipdbg_connection *conn = connection->priv; + conn->closed = false; + + LOG_INFO("New IPDBG Connection"); + + return ERROR_OK; +} + +static int ipdbg_on_connection_input(struct connection *connection) +{ + struct ipdbg_connection *conn = connection->priv; + struct ipdbg_fifo *fifo = &conn->dn_fifo; + + if (ipdbg_fifo_is_full(fifo)) + return ERROR_OK; + + ipdbg_zero_rd_idx(fifo); + int bytes_read = connection_read(connection, fifo->buffer + fifo->count, IPDBG_BUFFER_SIZE - fifo->count); + if (bytes_read <= 0) { + if (bytes_read < 0) + LOG_ERROR("error during read: %s", strerror(errno)); + return ERROR_SERVER_REMOTE_CLOSED; + } + + fifo->count += bytes_read; + + return ERROR_OK; +} + +static int ipdbg_on_connection_closed(struct connection *connection) +{ + struct ipdbg_connection *conn = connection->priv; + conn->closed = true; + LOG_INFO("Closed IPDBG Connection"); + + return ipdbg_stop_polling(connection->service->priv); +} + +static const struct service_driver ipdbg_service_driver = { + .name = "ipdbg", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = ipdbg_on_new_connection, + .input_handler = ipdbg_on_connection_input, + .connection_closed_handler = ipdbg_on_connection_closed, + .keep_client_alive_handler = NULL, +}; + +static struct ipdbg_hub *ipdbg_get_hub_by_name(const char *name) +{ + struct ipdbg_hub *hub = NULL; + for (hub = ipdbg_first_hub; hub; hub = hub->next) { + if (strcmp(hub->name, name) == 0) + break; + } + return hub; +}; + +static int ipdbg_stop_service(struct ipdbg_service *service) +{ + int retval = ipdbg_remove_service(service); + if (retval != ERROR_OK) { + LOG_ERROR("BUG: ipdbg_remove_service failed"); + return retval; + } + + char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH]; + snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", service->port); + retval = remove_service("ipdbg", port_str_buffer); + /* The ipdbg_service structure is freed by server.c:remove_service(). + There the "priv" pointer is freed.*/ + if (retval != ERROR_OK) { + LOG_ERROR("BUG: remove_service failed"); + return retval; + } + return ERROR_OK; +} + +int ipdbg_server_free(void) +{ + int retval = ERROR_OK; + for (struct ipdbg_hub *hub = ipdbg_first_hub; hub;) { + for (uint8_t tool = 0; tool < hub->max_tools; ++tool) { + struct ipdbg_service *service = ipdbg_find_service(hub, tool); + if (service) { + int new_retval = ipdbg_stop_service(service); + if (new_retval != ERROR_OK) + retval = new_retval; + hub->active_services--; + } + } + struct ipdbg_hub *next_hub = hub->next; + int new_retval = ipdbg_remove_hub(hub); + if (new_retval != ERROR_OK) + retval = new_retval; + ipdbg_free_hub(hub); + hub = next_hub; + } + return retval; +} + +static int ipdbg_start(struct ipdbg_hub *hub, uint16_t port, uint8_t tool) +{ + LOG_INFO("starting ipdbg service on port %d for tool %d", port, tool); + + struct ipdbg_service *service = NULL; + int retval = ipdbg_create_service(hub, tool, &service, port); + + if (retval != ERROR_OK || !service) { + if (hub->active_services == 0 && hub->active_connections == 0) + ipdbg_free_hub(hub); + return ERROR_FAIL; + } + + char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH]; + snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", port); + retval = add_service(&ipdbg_service_driver, port_str_buffer, 1, service); + if (retval != ERROR_OK) { + free(service); + return retval; + } + ipdbg_add_service(service); + hub->active_services++; + return ERROR_OK; +} + +COMMAND_HANDLER(handle_ipdbg_start_command) +{ + struct ipdbg_hub *hub = CMD_DATA; + + uint16_t port = 4242; + uint8_t tool = 1; + + if (CMD_ARGC > IPDBG_NUM_OF_START_OPTIONS) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned int i = 0; i < CMD_ARGC; ++i) { + if (strcmp(CMD_ARGV[i], "-port") == 0) { + COMMAND_PARSE_ADDITIONAL_NUMBER(u16, i, port, "port number"); + } else if (strcmp(CMD_ARGV[i], "-tool") == 0) { + COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool"); + } else { + command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]); + return ERROR_FAIL; + } + } + + return ipdbg_start(hub, port, tool); +} + +static int ipdbg_stop(struct ipdbg_hub *hub, uint8_t tool) +{ + struct ipdbg_service *service = ipdbg_find_service(hub, tool); + if (!service) { + LOG_ERROR("No service for hub '%s'/tool %d found", hub->name, tool); + return ERROR_FAIL; + } + + int retval = ipdbg_stop_service(service); + hub->active_services--; + + LOG_INFO("stopped ipdbg service for tool %d", tool); + return retval; +} + +COMMAND_HANDLER(handle_ipdbg_stop_command) +{ + struct ipdbg_hub *hub = CMD_DATA; + + uint8_t tool = 1; + + if (CMD_ARGC > IPDBG_NUM_OF_STOP_OPTIONS) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned int i = 0; i < CMD_ARGC; ++i) { + if (strcmp(CMD_ARGV[i], "-tool") == 0) { + COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool"); + } else { + command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]); + return ERROR_FAIL; + } + } + + return ipdbg_stop(hub, tool); +} + +static const struct command_registration ipdbg_hostserver_subcommand_handlers[] = { + { + .name = "start", + .mode = COMMAND_EXEC, + .handler = handle_ipdbg_start_command, + .help = "Starts a IPDBG Host server.", + .usage = "-tool number -port port" + }, { + .name = "stop", + .mode = COMMAND_EXEC, + .handler = handle_ipdbg_stop_command, + .help = "Stops a IPDBG Host server.", + .usage = "-tool number" + }, + COMMAND_REGISTRATION_DONE +}; + +static COMMAND_HELPER(ipdbg_config_queuing, struct ipdbg_hub *hub, unsigned int size) +{ + if (!hub) + return ERROR_FAIL; + + if (hub->active_connections) { + command_print(CMD, "Configuration change not allowed when hub has active connections"); + return ERROR_FAIL; + } + + if (size == 0 || size > IPDBG_SCRATCH_MEMORY_SIZE) { + command_print(CMD, "queuing size out of range! Must be 0 < size <= %d", IPDBG_SCRATCH_MEMORY_SIZE); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + hub->using_queue_size = size; + return ERROR_OK; +} + +COMMAND_HANDLER(handle_ipdbg_cfg_queuing_command) +{ + struct ipdbg_hub *hub = CMD_DATA; + + unsigned int size; + + if (CMD_ARGC != IPDBG_NUM_OF_QUEUE_OPTIONS) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned int i = 0; i < CMD_ARGC; ++i) { + if (strcmp(CMD_ARGV[i], "-size") == 0) { + COMMAND_PARSE_ADDITIONAL_NUMBER(uint, i, size, "size"); + } else { + command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]); + return ERROR_FAIL; + } + } + + return CALL_COMMAND_HANDLER(ipdbg_config_queuing, hub, size); +} + +static const struct command_registration ipdbg_hub_subcommand_handlers[] = { + { + .name = "ipdbg", + .mode = COMMAND_EXEC, + .help = "IPDBG Hub commands.", + .usage = "", + .chain = ipdbg_hostserver_subcommand_handlers + }, + { + .name = "queuing", + .handler = handle_ipdbg_cfg_queuing_command, + .mode = COMMAND_ANY, + .help = "configures queuing between IPDBG Host and Hub.", + .usage = "-size size", + }, + COMMAND_REGISTRATION_DONE +}; + +static int ipdbg_register_hub_command(struct ipdbg_hub *hub, struct command_invocation *cmd) +{ + Jim_Interp *interp = CMD_CTX->interp; + + /* does this command exist? */ + Jim_Cmd *jcmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, hub->name, -1), JIM_NONE); + if (jcmd) { + LOG_ERROR("cannot create Hub because a command with name '%s' already exists", hub->name); + return ERROR_FAIL; + } + + const struct command_registration obj_commands[] = { + { + .name = hub->name, + .mode = COMMAND_EXEC, + .help = "IPDBG Hub command group.", + .usage = "", + .chain = ipdbg_hub_subcommand_handlers + }, + COMMAND_REGISTRATION_DONE + }; + + return register_commands_with_data(CMD_CTX, NULL, obj_commands, hub); +} + +static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length, + struct ipdbg_virtual_ir_info *virtual_ir, const char *name, struct command_invocation *cmd) +{ + struct ipdbg_hub *new_hub = ipdbg_allocate_hub(data_register_length, virtual_ir, name); + if (!new_hub) + return ERROR_FAIL; + + 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; + new_hub->valid_mask = BIT(data_register_length - 1); + new_hub->xoff_mask = BIT(data_register_length - 2); + new_hub->tool_mask = (new_hub->xoff_mask - 1) >> 8; + new_hub->last_dn_tool = new_hub->tool_mask; + new_hub->virtual_ir = virtual_ir; + new_hub->max_tools = ipdbg_max_tools_from_data_register_length(data_register_length); + new_hub->using_queue_size = IPDBG_SCRATCH_MEMORY_SIZE; + + int retval = ipdbg_register_hub_command(new_hub, cmd); + if (retval != ERROR_OK) { + LOG_ERROR("Creating hub failed"); + ipdbg_free_hub(new_hub); + return ERROR_FAIL; + } + + ipdbg_add_hub(new_hub); + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_ipdbg_create_hub_command) +{ + struct jtag_tap *tap = NULL; + uint32_t user_instruction = 0x00; + uint8_t data_register_length = IPDBG_MAX_DR_LENGTH; + bool has_virtual_ir = false; + uint32_t virtual_ir_instruction = 0x00e; + uint32_t virtual_ir_length = 5; + uint32_t virtual_ir_value = 0x11; + struct ipdbg_virtual_ir_info *virtual_ir = NULL; + int user_num = 1; + bool hub_configured = false; + + if (CMD_ARGC < IPDBG_MIN_NUM_OF_CREATE_OPTIONS || CMD_ARGC > IPDBG_MAX_NUM_OF_CREATE_OPTIONS) + return ERROR_COMMAND_SYNTAX_ERROR; + + const char *hub_name = CMD_ARGV[0]; + + for (unsigned int i = 1; i < CMD_ARGC; ++i) { + if (strcmp(CMD_ARGV[i], "-tap") == 0) { + if (i + 1 >= CMD_ARGC || CMD_ARGV[i + 1][0] == '-') { + command_print(CMD, "no TAP name given"); + return ERROR_FAIL; + } + tap = jtag_tap_by_string(CMD_ARGV[i + 1]); + if (!tap) { + command_print(CMD, "Tap %s unknown", CMD_ARGV[i + 1]); + return ERROR_FAIL; + } + ++i; + } else if (strcmp(CMD_ARGV[i], "-ir") == 0) { + COMMAND_PARSE_ADDITIONAL_NUMBER(u32, i, user_instruction, "ir_value to select hub"); + hub_configured = true; + COMMAND_PARSE_OPTIONAL_NUMBER(u8, i, data_register_length); + if (data_register_length < IPDBG_MIN_DR_LENGTH || + data_register_length > IPDBG_MAX_DR_LENGTH) { + command_print(CMD, "length of \"user\"-data register must be at least %d and at most %d.", + 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); + COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_instruction); + has_virtual_ir = true; + } else { + command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]); + return ERROR_FAIL; + } + } + if (!tap) { + command_print(CMD, "no valid tap selected"); + return ERROR_FAIL; + } + + if (!hub_configured) { + command_print(CMD, "hub not configured correctly"); + return ERROR_FAIL; + } + + if (ipdbg_get_hub_by_name(hub_name)) { + LOG_ERROR("IPDBG hub with name '%s' already exists", hub_name); + return ERROR_FAIL; + } + + if (has_virtual_ir) { + virtual_ir = calloc(1, sizeof(struct ipdbg_virtual_ir_info)); + if (!virtual_ir) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + virtual_ir->instruction = virtual_ir_instruction; + virtual_ir->length = virtual_ir_length; + virtual_ir->value = virtual_ir_value; + } + + if (ipdbg_find_hub(tap, user_instruction, virtual_ir)) { + LOG_ERROR("IPDBG hub for given TAP and user-instruction already exists"); + free(virtual_ir); + return ERROR_FAIL; + } + + int retval = ipdbg_create_hub(tap, user_instruction, data_register_length, virtual_ir, hub_name, cmd); + if (retval != ERROR_OK) + free(virtual_ir); + + return retval; +} + +static const struct command_registration ipdbg_config_command_handlers[] = { + { + .name = "create-hub", + .mode = COMMAND_ANY, + .handler = handle_ipdbg_create_hub_command, + .help = "create a IPDBG Hub", + .usage = "name.ipdbghub (-tap device.tap -ir ir_value [dr_length] |" + " -pld name.pld [user]) [-vir [vir_value [length [instr_code]]]]", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration ipdbg_command_handlers[] = { + { + .name = "ipdbg", + .mode = COMMAND_ANY, + .help = "IPDBG Hub/Host commands.", + .usage = "", + .chain = ipdbg_config_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +int ipdbg_register_commands(struct command_context *cmd_ctx) +{ + return register_commands(cmd_ctx, NULL, ipdbg_command_handlers); +} diff --git a/src/server/ipdbg.h b/src/server/ipdbg.h new file mode 100644 index 0000000000..1f4156b7ac --- /dev/null +++ b/src/server/ipdbg.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2020 by Daniel Anselmi <danselmi@gmx.ch> */ + +#ifndef OPENOCD_IPDBG_IPDBG_H +#define OPENOCD_IPDBG_IPDBG_H + +#include <helper/command.h> + +int ipdbg_register_commands(struct command_context *cmd_ctx); +int ipdbg_server_free(void); + +#endif /* OPENOCD_IPDBG_IPDBG_H */ diff --git a/src/server/rtt_server.c b/src/server/rtt_server.c new file mode 100644 index 0000000000..9769153475 --- /dev/null +++ b/src/server/rtt_server.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2016-2017 by Marc Schink <dev@zapb.de> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <rtt/rtt.h> + +#include "server.h" +#include "rtt_server.h" + +/** + * @file + * + * RTT server. + * + * This server allows access to Real Time Transfer (RTT) channels via TCP + * connections. + */ + +struct rtt_service { + unsigned int channel; + char *hello_message; +}; + +static int read_callback(unsigned int channel, const uint8_t *buffer, + size_t length, void *user_data) +{ + int ret; + struct connection *connection; + size_t offset; + + connection = (struct connection *)user_data; + offset = 0; + + while (offset < length) { + ret = connection_write(connection, buffer + offset, length - offset); + + if (ret < 0) { + LOG_ERROR("Failed to write data to socket."); + return ERROR_FAIL; + } + + offset += ret; + } + + return ERROR_OK; +} + +static int rtt_new_connection(struct connection *connection) +{ + int ret; + struct rtt_service *service; + + service = connection->service->priv; + + LOG_DEBUG("rtt: New connection for channel %u", service->channel); + + ret = rtt_register_sink(service->channel, &read_callback, connection); + + if (ret != ERROR_OK) + return ret; + + if (service->hello_message) + connection_write(connection, service->hello_message, strlen(service->hello_message)); + + return ERROR_OK; +} + +static int rtt_connection_closed(struct connection *connection) +{ + struct rtt_service *service; + + service = (struct rtt_service *)connection->service->priv; + rtt_unregister_sink(service->channel, &read_callback, connection); + + LOG_DEBUG("rtt: Connection for channel %u closed", service->channel); + + return ERROR_OK; +} + +static int rtt_input(struct connection *connection) +{ + int bytes_read; + unsigned char buffer[1024]; + struct rtt_service *service; + size_t length; + + service = (struct rtt_service *)connection->service->priv; + bytes_read = connection_read(connection, buffer, sizeof(buffer)); + + if (!bytes_read) + return ERROR_SERVER_REMOTE_CLOSED; + else if (bytes_read < 0) { + LOG_ERROR("error during read: %s", strerror(errno)); + return ERROR_SERVER_REMOTE_CLOSED; + } + + length = bytes_read; + rtt_write_channel(service->channel, buffer, &length); + + return ERROR_OK; +} + +static const struct service_driver rtt_service_driver = { + .name = "rtt", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = rtt_new_connection, + .input_handler = rtt_input, + .connection_closed_handler = rtt_connection_closed, + .keep_client_alive_handler = NULL, +}; + +COMMAND_HANDLER(handle_rtt_start_command) +{ + int ret; + struct rtt_service *service; + + if (CMD_ARGC < 2 || CMD_ARGC > 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + 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) { + free(service); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_rtt_stop_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + remove_service("rtt", CMD_ARGV[0]); + + return ERROR_OK; +} + +static const struct command_registration rtt_server_subcommand_handlers[] = { + { + .name = "start", + .handler = handle_rtt_start_command, + .mode = COMMAND_ANY, + .help = "Start a RTT server", + .usage = "<port> <channel> [message]" + }, + { + .name = "stop", + .handler = handle_rtt_stop_command, + .mode = COMMAND_ANY, + .help = "Stop a RTT server", + .usage = "<port>" + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration rtt_server_command_handlers[] = { + { + .name = "server", + .mode = COMMAND_ANY, + .help = "RTT server", + .usage = "", + .chain = rtt_server_subcommand_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration rtt_command_handlers[] = { + { + .name = "rtt", + .mode = COMMAND_ANY, + .help = "RTT", + .usage = "", + .chain = rtt_server_command_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +int rtt_server_register_commands(struct command_context *ctx) +{ + return register_commands(ctx, NULL, rtt_command_handlers); +} diff --git a/src/server/rtt_server.h b/src/server/rtt_server.h new file mode 100644 index 0000000000..5cea25a00c --- /dev/null +++ b/src/server/rtt_server.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2016-2017 by Marc Schink <dev@zapb.de> + */ + +#ifndef OPENOCD_SERVER_RTT_SERVER_H +#define OPENOCD_SERVER_RTT_SERVER_H + +#include <helper/command.h> + +int rtt_server_register_commands(struct command_context *ctx); + +#endif /* OPENOCD_SERVER_RTT_SERVER_H */ diff --git a/src/server/server.c b/src/server/server.c index 3b55d0d7ca..0649ec942b 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 @@ -27,12 +16,14 @@ #endif #include "server.h" +#include <helper/time_support.h> #include <target/target.h> #include <target/target_request.h> #include <target/openrisc/jsp_server.h> #include "openocd.h" #include "tcl_server.h" #include "telnet_server.h" +#include "ipdbg.h" #include <signal.h> @@ -204,13 +195,8 @@ static void free_service(struct service *c) free(c); } -int add_service(char *name, - const char *port, - int max_connections, - new_connection_handler_t new_connection_handler, - input_handler_t input_handler, - connection_closed_handler_t connection_closed_handler, - void *priv) +int add_service(const struct service_driver *driver, const char *port, + int max_connections, void *priv) { struct service *c, **p; struct hostent *hp; @@ -218,14 +204,16 @@ int add_service(char *name, c = malloc(sizeof(struct service)); - c->name = strdup(name); + c->name = strdup(driver->name); c->port = strdup(port); c->max_connections = 1; /* Only TCP/IP ports can support more than one connection */ c->fd = -1; c->connections = NULL; - c->new_connection = new_connection_handler; - c->input = input_handler; - c->connection_closed = connection_closed_handler; + c->new_connection_during_keep_alive = driver->new_connection_during_keep_alive_handler; + c->new_connection = driver->new_connection_handler; + c->input = driver->input_handler; + c->connection_closed = driver->connection_closed_handler; + c->keep_client_alive = driver->keep_client_alive_handler; c->priv = priv; c->next = NULL; long portnumber; @@ -262,11 +250,11 @@ int add_service(char *name, memset(&c->sin, 0, sizeof(c->sin)); c->sin.sin_family = AF_INET; - if (bindto_name == NULL) + if (!bindto_name) c->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); else { hp = gethostbyname(bindto_name); - if (hp == NULL) { + if (!hp) { LOG_ERROR("couldn't resolve bindto address: %s", bindto_name); close_socket(c->fd); free_service(c); @@ -277,7 +265,7 @@ int add_service(char *name, c->sin.sin_port = htons(c->portnumber); if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) { - LOG_ERROR("couldn't bind %s to socket on port %d: %s", name, c->portnumber, strerror(errno)); + LOG_ERROR("couldn't bind %s to socket on port %d: %s", c->name, c->portnumber, strerror(errno)); close_socket(c->fd); free_service(c); return ERROR_FAIL; @@ -308,7 +296,7 @@ int add_service(char *name, socklen_t addr_in_size = sizeof(addr_in); if (getsockname(c->fd, (struct sockaddr *)&addr_in, &addr_in_size) == 0) LOG_INFO("Listening on port %hu for %s connections", - ntohs(addr_in.sin_port), name); + ntohs(addr_in.sin_port), c->name); } else if (c->type == CONNECTION_STDINOUT) { c->fd = fileno(stdin); @@ -423,6 +411,14 @@ static int remove_services(void) return ERROR_OK; } +void server_keep_clients_alive(void) +{ + for (struct service *s = services; s; s = s->next) + if (s->keep_client_alive) + for (struct connection *c = s->connections; c; c = c->next) + s->keep_client_alive(c); +} + int server_loop(struct command_context *command_context) { struct service *service; @@ -436,6 +432,8 @@ int server_loop(struct command_context *command_context) /* used in accept() */ int retval; + int64_t next_event = timeval_ms() + polling_period; + #ifndef _WIN32 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) LOG_ERROR("couldn't set SIGPIPE to SIG_IGN"); @@ -476,13 +474,15 @@ 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 */ - tv.tv_usec = polling_period * 1000; + /* 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; + else if (timeout_ms > polling_period) + timeout_ms = polling_period; + tv.tv_usec = timeout_ms * 1000; /* Only while we're sleeping we'll let others run */ - openocd_sleep_prelude(); - kept_alive(); retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); - openocd_sleep_postlude(); } if (retval == -1) { @@ -508,9 +508,13 @@ 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 */ + /* 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); FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */ @@ -595,7 +599,7 @@ int server_loop(struct command_context *command_context) return shutdown_openocd == SHUTDOWN_WITH_ERROR_CODE ? ERROR_FAIL : ERROR_OK; } -void sig_handler(int sig) +static void sig_handler(int sig) { /* store only first signal that hits us */ if (shutdown_openocd == CONTINUE_MAIN_LOOP) { @@ -608,7 +612,7 @@ void sig_handler(int sig) #ifdef _WIN32 -BOOL WINAPI ControlHandler(DWORD dwCtrlType) +BOOL WINAPI control_handler(DWORD ctrl_type) { shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE; return TRUE; @@ -633,12 +637,12 @@ int server_host_os_entry(void) * This is an issue if you call init in your config script */ #ifdef _WIN32 - WORD wVersionRequested; - WSADATA wsaData; + WORD version_requested; + WSADATA wsadata; - wVersionRequested = MAKEWORD(2, 2); + version_requested = MAKEWORD(2, 2); - if (WSAStartup(wVersionRequested, &wsaData) != 0) { + if (WSAStartup(version_requested, &wsadata) != 0) { LOG_ERROR("Failed to Open Winsock"); return ERROR_FAIL; } @@ -658,7 +662,7 @@ int server_preinit(void) { #ifdef _WIN32 /* register ctrl-c handler */ - SetConsoleCtrlHandler(ControlHandler, TRUE); + SetConsoleCtrlHandler(control_handler, TRUE); signal(SIGBREAK, sig_handler); signal(SIGINT, sig_handler); @@ -697,7 +701,7 @@ int server_quit(void) target_quit(); #ifdef _WIN32 - SetConsoleCtrlHandler(ControlHandler, FALSE); + SetConsoleCtrlHandler(control_handler, FALSE); return ERROR_OK; #endif @@ -711,6 +715,7 @@ void server_free(void) tcl_service_free(); telnet_service_free(); jsp_service_free(); + ipdbg_server_free(); free(bindto_name); } @@ -744,6 +749,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) { @@ -751,6 +761,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; @@ -818,15 +830,15 @@ static const struct command_registration server_command_handlers[] = { int server_register_commands(struct command_context *cmd_ctx) { int retval = telnet_register_commands(cmd_ctx); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = tcl_register_commands(cmd_ctx); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = jsp_register_commands(cmd_ctx); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; return register_commands(cmd_ctx, NULL, server_command_handlers); diff --git a/src/server/server.h b/src/server/server.h index ff2ada9cbe..ea1e94ec5f 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 @@ -30,6 +19,7 @@ #endif #include <helper/log.h> +#include <helper/replacements.h> #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> @@ -54,9 +44,25 @@ struct connection { struct connection *next; }; -typedef int (*new_connection_handler_t)(struct connection *connection); -typedef int (*input_handler_t)(struct connection *connection); -typedef int (*connection_closed_handler_t)(struct connection *connection); +struct service_driver { + /** the name of the server */ + const char *name; + /** optional minimal setup to accept a connection during keep-alive */ + int (*new_connection_during_keep_alive_handler)(struct connection *connection); + /** + * complete code to accept a new connection. + * If 'new_connection_during_keep_alive_handler' above is present, this can be + * either called alone during the server_loop, or after the function above. + * Check the implementation in gdb_server. + * */ + int (*new_connection_handler)(struct connection *connection); + /** callback to handle incoming data */ + int (*input_handler)(struct connection *connection); + /** callback to tear down the connection */ + int (*connection_closed_handler)(struct connection *connection); + /** called periodically to send keep-alive messages on the connection */ + void (*keep_client_alive_handler)(struct connection *connection); +}; struct service { char *name; @@ -67,17 +73,17 @@ struct service { struct sockaddr_in sin; int max_connections; struct connection *connections; - new_connection_handler_t new_connection; - input_handler_t input; - connection_closed_handler_t connection_closed; + int (*new_connection_during_keep_alive)(struct connection *connection); + int (*new_connection)(struct connection *connection); + int (*input)(struct connection *connection); + int (*connection_closed)(struct connection *connection); + void (*keep_client_alive)(struct connection *connection); void *priv; struct service *next; }; -int add_service(char *name, const char *port, - int max_connections, new_connection_handler_t new_connection_handler, - input_handler_t in_handler, connection_closed_handler_t close_handler, - void *priv); +int add_service(const struct service_driver *driver, const char *port, + int max_connections, void *priv); int remove_service(const char *name, const char *port); int server_host_os_entry(void); @@ -89,6 +95,8 @@ int server_quit(void); void server_free(void); void exit_on_signal(int sig); +void server_keep_clients_alive(void); + int server_loop(struct command_context *command_context); int server_register_commands(struct command_context *context); @@ -96,14 +104,7 @@ 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); -/** - * Used by server_loop(), defined in server_stubs.c - */ -void openocd_sleep_prelude(void); -/** - * Used by server_loop(), defined in server_stubs.c - */ -void openocd_sleep_postlude(void); +bool openocd_is_shutdown_pending(void); /** * Defines an extended command handler function declaration to enable @@ -117,5 +118,6 @@ COMMAND_HELPER(server_port_command, unsigned short *out); #define ERROR_SERVER_REMOTE_CLOSED (-400) #define ERROR_CONNECTION_REJECTED (-401) +#define ERROR_SERVER_INTERRUPTED (-402) #endif /* OPENOCD_SERVER_SERVER_H */ diff --git a/src/server/server_stubs.c b/src/server/server_stubs.c deleted file mode 100644 index a4c017289a..0000000000 --- a/src/server/server_stubs.c +++ /dev/null @@ -1,30 +0,0 @@ -/*************************************************************************** - * 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 "server.h" - -void openocd_sleep_prelude(void) -{ - /* no-op */ -} -void openocd_sleep_postlude(void) -{ - /* no-op */ -} diff --git a/src/server/startup.tcl b/src/server/startup.tcl index dd1b31e417..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, @@ -9,6 +11,9 @@ proc ocd_gdb_restart {target_id} { reset halt } +lappend _telnet_autocomplete_skip prevent_cps +lappend _telnet_autocomplete_skip POST +lappend _telnet_autocomplete_skip Host: proc prevent_cps {} { echo "Possible SECURITY ATTACK detected." echo "It looks like somebody is sending POST or Host: commands to OpenOCD." @@ -19,3 +24,20 @@ proc prevent_cps {} { proc POST {args} { prevent_cps } proc Host: {args} { prevent_cps } + +# list of commands we don't want to appear in autocomplete +lappend _telnet_autocomplete_skip _telnet_autocomplete_helper + +# helper for telnet autocomplete +proc _telnet_autocomplete_helper pattern { + set cmds [info commands $pattern] + + # skip matches in variable '_telnet_autocomplete_skip' + foreach skip $::_telnet_autocomplete_skip { + foreach n [lsearch -all -regexp $cmds "^$skip\$"] { + set cmds [lreplace $cmds $n $n] + } + } + + return [lsort $cmds] +} diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index 1ecb827a1a..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 @@ -145,12 +134,12 @@ static int tcl_new_connection(struct connection *connection) struct tcl_connection *tclc; tclc = calloc(1, sizeof(struct tcl_connection)); - if (tclc == NULL) + if (!tclc) return ERROR_CONNECTION_REJECTED; tclc->tc_line_size = TCL_LINE_INITIAL; tclc->tc_line = malloc(tclc->tc_line_size); - if (tclc->tc_line == NULL) { + if (!tclc->tc_line) { free(tclc); return ERROR_CONNECTION_REJECTED; } @@ -158,7 +147,7 @@ static int tcl_new_connection(struct connection *connection) connection->priv = tclc; struct target *target = get_current_target_or_null(connection->cmd_ctx); - if (target != NULL) + if (target) tclc->tc_laststate = target->state; /* store the connection object on cmd_ctx so we can access it from command handlers */ @@ -192,7 +181,7 @@ static int tcl_input(struct connection *connection) } tclc = connection->priv; - if (tclc == NULL) + if (!tclc) return ERROR_CONNECTION_REJECTED; /* push as much data into the line as possible */ @@ -215,7 +204,7 @@ static int tcl_input(struct connection *connection) tc_line_size_new = TCL_LINE_MAX; tc_line_new = realloc(tclc->tc_line, tc_line_size_new); - if (tc_line_new == NULL) { + if (!tc_line_new) { tclc->tc_linedrop = 1; } else { tclc->tc_line = tc_line_new; @@ -276,6 +265,15 @@ static int tcl_closed(struct connection *connection) return ERROR_OK; } +static const struct service_driver tcl_service_driver = { + .name = "tcl", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = tcl_new_connection, + .input_handler = tcl_input, + .connection_closed_handler = tcl_closed, + .keep_client_alive_handler = NULL, +}; + int tcl_init(void) { if (strcmp(tcl_port, "disabled") == 0) { @@ -283,9 +281,7 @@ int tcl_init(void) return ERROR_OK; } - return add_service("tcl", tcl_port, CONNECTION_LIMIT_UNLIMITED, - &tcl_new_connection, &tcl_input, - &tcl_closed, NULL); + return add_service(&tcl_service_driver, tcl_port, CONNECTION_LIMIT_UNLIMITED, NULL); } COMMAND_HANDLER(handle_tcl_port_command) @@ -298,10 +294,10 @@ COMMAND_HANDLER(handle_tcl_notifications_command) struct connection *connection = NULL; struct tcl_connection *tclc = NULL; - if (CMD_CTX->output_handler_priv != NULL) + if (CMD_CTX->output_handler_priv) connection = CMD_CTX->output_handler_priv; - if (connection != NULL && !strcmp(connection->service->name, "tcl")) { + if (connection && !strcmp(connection->service->name, "tcl")) { tclc = connection->priv; return CALL_COMMAND_HANDLER(handle_command_parse_bool, &tclc->tc_notify, "Target Notification output "); } else { @@ -315,10 +311,10 @@ COMMAND_HANDLER(handle_tcl_trace_command) struct connection *connection = NULL; struct tcl_connection *tclc = NULL; - if (CMD_CTX->output_handler_priv != NULL) + if (CMD_CTX->output_handler_priv) connection = CMD_CTX->output_handler_priv; - if (connection != NULL && !strcmp(connection->service->name, "tcl")) { + if (connection && !strcmp(connection->service->name, "tcl")) { tclc = connection->priv; return CALL_COMMAND_HANDLER(handle_command_parse_bool, &tclc->tc_trace, "Target trace output "); } else { 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 0243c6328e..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 @@ -29,6 +18,7 @@ #include "telnet_server.h" #include <target/target_request.h> #include <helper/configuration.h> +#include <helper/list.h> static char *telnet_port; @@ -58,6 +48,13 @@ static int telnet_write(struct connection *connection, const void *data, return ERROR_SERVER_REMOTE_CLOSED; } +/* output an audible bell */ +static int telnet_bell(struct connection *connection) +{ + /* ("\a" does not work, at least on windows) */ + return telnet_write(connection, "\x07", 1); +} + static int telnet_prompt(struct connection *connection) { struct telnet_connection *t_con = connection->priv; @@ -142,7 +139,7 @@ static void telnet_load_history(struct telnet_connection *t_con) char *history = get_home_dir(TELNET_HISTORY); - if (history == NULL) { + if (!history) { LOG_INFO("unable to get user home directory, telnet history will be disabled"); return; } @@ -151,7 +148,7 @@ static void telnet_load_history(struct telnet_connection *t_con) if (histfp) { - while (fgets(buffer, sizeof(buffer), histfp) != NULL) { + while (fgets(buffer, sizeof(buffer), histfp)) { char *p = strchr(buffer, '\n'); if (p) @@ -178,7 +175,7 @@ static void telnet_save_history(struct telnet_connection *t_con) char *history = get_home_dir(TELNET_HISTORY); - if (history == NULL) { + if (!history) { LOG_INFO("unable to get user home directory, telnet history will be disabled"); return; } @@ -191,7 +188,7 @@ static void telnet_save_history(struct telnet_connection *t_con) i = t_con->current_history + 1; i %= TELNET_LINE_HISTORY_SIZE; - while (t_con->history[i] == NULL && num > 0) { + while (!t_con->history[i] && num > 0) { i++; i %= TELNET_LINE_HISTORY_SIZE; num--; @@ -214,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."); @@ -226,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; @@ -249,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); @@ -312,6 +300,32 @@ static void telnet_history_down(struct connection *connection) telnet_history_go(connection, next_history); } +static void telnet_history_add(struct connection *connection) +{ + struct telnet_connection *t_con = connection->priv; + + /* save only non-blank not repeating lines in the history */ + char *prev_line = t_con->history[(t_con->current_history > 0) ? + t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1]; + + if (*t_con->line && (!prev_line || strcmp(t_con->line, prev_line))) { + /* if the history slot is already taken, free it */ + free(t_con->history[t_con->next_history]); + + /* add line to history */ + t_con->history[t_con->next_history] = strdup(t_con->line); + + /* wrap history at TELNET_LINE_HISTORY_SIZE */ + t_con->next_history = (t_con->next_history + 1) % TELNET_LINE_HISTORY_SIZE; + + /* current history line starts at the new entry */ + t_con->current_history = t_con->next_history; + + free(t_con->history[t_con->current_history]); + t_con->history[t_con->current_history] = strdup(""); + } +} + static int telnet_history_print(struct connection *connection) { struct telnet_connection *tc; @@ -344,10 +358,14 @@ static int telnet_history_print(struct connection *connection) static void telnet_move_cursor(struct connection *connection, size_t pos) { - struct telnet_connection *tc; + struct telnet_connection *tc = connection->priv; size_t tmp; - tc = connection->priv; + if (pos == tc->line_cursor) /* nothing to do */ + return; + + if (pos > tc->line_size) /* out of bounds */ + return; if (pos < tc->line_cursor) { tmp = tc->line_cursor - pos; @@ -366,13 +384,375 @@ static void telnet_move_cursor(struct connection *connection, size_t pos) tc->line_cursor = pos; } +/* check buffer size leaving one spare character for string null termination */ +static inline bool telnet_can_insert(struct connection *connection, size_t len) +{ + struct telnet_connection *t_con = connection->priv; + + return t_con->line_size + len < TELNET_LINE_MAX_SIZE; +} + +/* write to telnet console, and update the telnet_connection members + * this function is capable of inserting in the middle of a line + * please ensure that data does not contain special characters (\n, \r, \t, \b ...) + * + * returns false when it fails to insert the requested data + */ +static bool telnet_insert(struct connection *connection, const void *data, size_t len) +{ + struct telnet_connection *t_con = connection->priv; + + if (!telnet_can_insert(connection, len)) { + telnet_bell(connection); + return false; + } + + if (t_con->line_cursor < t_con->line_size) { + /* we have some content after the cursor */ + memmove(t_con->line + t_con->line_cursor + len, + t_con->line + t_con->line_cursor, + t_con->line_size - t_con->line_cursor); + } + + strncpy(t_con->line + t_con->line_cursor, data, len); + + telnet_write(connection, + t_con->line + t_con->line_cursor, + t_con->line_size + len - t_con->line_cursor); + + t_con->line_size += len; + t_con->line_cursor += len; + + for (size_t i = t_con->line_cursor; i < t_con->line_size; i++) + telnet_write(connection, "\b", 1); + + return true; +} + +static void telnet_delete_character(struct connection *connection) +{ + struct telnet_connection *t_con = connection->priv; + + if (t_con->line_cursor == 0) + return; + + if (t_con->line_cursor != t_con->line_size) { + size_t i; + telnet_write(connection, "\b", 1); + t_con->line_cursor--; + t_con->line_size--; + memmove(t_con->line + t_con->line_cursor, + t_con->line + t_con->line_cursor + 1, + t_con->line_size - + t_con->line_cursor); + + telnet_write(connection, + t_con->line + t_con->line_cursor, + t_con->line_size - + t_con->line_cursor); + telnet_write(connection, " \b", 2); + for (i = t_con->line_cursor; i < t_con->line_size; i++) + telnet_write(connection, "\b", 1); + } else { + t_con->line_size--; + t_con->line_cursor--; + /* back space: move the 'printer' head one char + * back, overwrite with space, move back again */ + telnet_write(connection, "\b \b", 3); + } +} + +static void telnet_remove_character(struct connection *connection) +{ + struct telnet_connection *t_con = connection->priv; + + if (t_con->line_cursor < t_con->line_size) { + size_t i; + t_con->line_size--; + /* remove char from line buffer */ + memmove(t_con->line + t_con->line_cursor, + t_con->line + t_con->line_cursor + 1, + t_con->line_size - t_con->line_cursor); + + /* print remainder of buffer */ + telnet_write(connection, t_con->line + t_con->line_cursor, + t_con->line_size - t_con->line_cursor); + /* overwrite last char with whitespace */ + telnet_write(connection, " \b", 2); + + /* move back to cursor position*/ + for (i = t_con->line_cursor; i < t_con->line_size; i++) + telnet_write(connection, "\b", 1); + } +} + +static int telnet_exec_line(struct connection *connection) +{ + struct telnet_connection *t_con = connection->priv; + struct command_context *command_context = connection->cmd_ctx; + int retval; + + telnet_write(connection, "\r\n\x00", 3); + + if (strcmp(t_con->line, "history") == 0) { + retval = telnet_history_print(connection); + + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; + } + + telnet_history_add(connection); + + t_con->line_size = 0; + + /* to suppress prompt in log callback during command execution */ + t_con->prompt_visible = false; + + if (strcmp(t_con->line, "shutdown") == 0) + telnet_save_history(t_con); + + retval = command_run_line(command_context, t_con->line); + + t_con->line_cursor = 0; + t_con->prompt_visible = true; + + if (retval == ERROR_COMMAND_CLOSE_CONNECTION) + return ERROR_SERVER_REMOTE_CLOSED; + + /* the prompt is always placed at the line beginning */ + telnet_write(connection, "\r", 1); + + retval = telnet_prompt(connection); + if (retval == ERROR_SERVER_REMOTE_CLOSED) + return ERROR_SERVER_REMOTE_CLOSED; + + return ERROR_OK; +} + +static void telnet_cut_line_to_end(struct connection *connection) +{ + struct telnet_connection *t_con = connection->priv; + + /* FIXME: currently this function does not save to clipboard */ + + if (t_con->line_cursor < t_con->line_size) { + /* overwrite with space, until end of line, move back */ + for (size_t i = t_con->line_cursor; i < t_con->line_size; i++) + telnet_write(connection, " ", 1); + for (size_t i = t_con->line_cursor; i < t_con->line_size; i++) + telnet_write(connection, "\b", 1); + t_con->line[t_con->line_cursor] = '\0'; + t_con->line_size = t_con->line_cursor; + } +} + +static void telnet_interrupt(struct connection *connection) +{ + struct telnet_connection *t_con = connection->priv; + + /* print '^C' at line end, and display a new command prompt */ + telnet_move_cursor(connection, t_con->line_size); + telnet_write(connection, "^C\n\r", 4); + t_con->line_cursor = 0; + t_con->line_size = 0; + telnet_prompt(connection); +} + +static void telnet_auto_complete(struct connection *connection) +{ + struct telnet_connection *t_con = connection->priv; + struct command_context *command_context = connection->cmd_ctx; + + struct cmd_match { + char *cmd; + struct list_head lh; + }; + + LIST_HEAD(matches); + + /* - user command sequence, either at line beginning + * or we start over after these characters ';', '[', '{' + * - user variable sequence, start after the character '$' + * and do not contain white spaces */ + bool is_variable_auto_completion = false; + bool have_spaces = false; + size_t seq_start = (t_con->line_cursor == 0) ? 0 : (t_con->line_cursor - 1); + while (1) { + char c = t_con->line[seq_start]; + + if (c == ';' || c == '[' || c == '{') { + seq_start++; + break; + } else if (c == ' ') { + have_spaces = true; + } else if (c == '$' && !have_spaces) { + is_variable_auto_completion = true; + seq_start++; + break; + } + + if (seq_start == 0) + break; + + seq_start--; + } + + /* user command position in the line, ignore leading spaces */ + size_t usr_cmd_pos = seq_start; + while ((usr_cmd_pos < t_con->line_cursor) && isspace(t_con->line[usr_cmd_pos])) + usr_cmd_pos++; + + /* 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, + * because info commands does not tolerate multiple spaces */ + size_t optimized_spaces = 0; + char query[usr_cmd_len + 1]; + for (size_t i = 0; i < usr_cmd_len; i++) { + if ((i < usr_cmd_len - 1) && isspace(t_con->line[usr_cmd_pos + i]) + && isspace(t_con->line[usr_cmd_pos + i + 1])) { + optimized_spaces++; + continue; + } + + query[i - optimized_spaces] = t_con->line[usr_cmd_pos + i]; + } + + usr_cmd_len -= optimized_spaces; + query[usr_cmd_len] = '\0'; + + /* filter commands */ + char *query_cmd; + + if (is_variable_auto_completion) + query_cmd = alloc_printf("lsort [info vars {%s*}]", query); + else + query_cmd = alloc_printf("_telnet_autocomplete_helper {%s*}", query); + + if (!query_cmd) { + LOG_ERROR("Out of memory"); + return; + } + + int retval = Jim_EvalSource(command_context->interp, __FILE__, __LINE__, query_cmd); + free(query_cmd); + if (retval != JIM_OK) + return; + + Jim_Obj *list = Jim_GetResult(command_context->interp); + Jim_IncrRefCount(list); + + /* common prefix length of the matched commands */ + size_t common_len = 0; + char *first_match = NULL; /* used to compute the common prefix length */ + + int len = Jim_ListLength(command_context->interp, list); + for (int i = 0; i < len; i++) { + Jim_Obj *elem = Jim_ListGetIndex(command_context->interp, list, i); + Jim_IncrRefCount(elem); + + char *name = (char *)Jim_GetString(elem, NULL); + + /* validate the command */ + bool ignore_cmd = false; + if (!is_variable_auto_completion) { + Jim_Cmd *jim_cmd = Jim_GetCommand(command_context->interp, elem, JIM_NONE); + + if (!jim_cmd) { + /* Why we are here? Let's ignore it! */ + ignore_cmd = true; + } else if (jimcmd_is_oocd_command(jim_cmd)) { + struct command *cmd = jimcmd_privdata(jim_cmd); + + if (cmd && !cmd->handler && !cmd->jim_handler) { + /* Initial part of a multi-word command. Ignore it! */ + ignore_cmd = true; + } else if (cmd && cmd->mode == COMMAND_CONFIG) { + /* Not executable after config phase. Ignore it! */ + ignore_cmd = true; + } + } + } + + /* save the command in the prediction list */ + if (!ignore_cmd) { + struct cmd_match *match = calloc(1, sizeof(struct cmd_match)); + if (!match) { + LOG_ERROR("Out of memory"); + Jim_DecrRefCount(command_context->interp, elem); + break; /* break the for loop */ + } + + if (list_empty(&matches)) { + common_len = strlen(name); + first_match = name; + } else { + size_t new_common_len = usr_cmd_len; /* save some loops */ + + while (new_common_len < common_len && first_match[new_common_len] == name[new_common_len]) + new_common_len++; + + common_len = new_common_len; + } + + match->cmd = name; + list_add_tail(&match->lh, &matches); + } + + Jim_DecrRefCount(command_context->interp, elem); + } + /* end of command filtering */ + + /* proceed with auto-completion */ + if (list_empty(&matches)) + telnet_bell(connection); + else if (common_len == usr_cmd_len && list_is_singular(&matches) && t_con->line_cursor == t_con->line_size) + telnet_insert(connection, " ", 1); + else if (common_len > usr_cmd_len) { + int completion_size = common_len - usr_cmd_len; + if (telnet_insert(connection, first_match + usr_cmd_len, completion_size)) { + /* in bash this extra space is only added when the cursor in at the end of line */ + if (list_is_singular(&matches) && t_con->line_cursor == t_con->line_size) + telnet_insert(connection, " ", 1); + } + } else if (!list_is_singular(&matches)) { + telnet_write(connection, "\n\r", 2); + + struct cmd_match *match; + list_for_each_entry(match, &matches, lh) { + telnet_write(connection, match->cmd, strlen(match->cmd)); + telnet_write(connection, "\n\r", 2); + } + + telnet_prompt(connection); + telnet_write(connection, t_con->line, t_con->line_size); + + /* restore the terminal visible cursor location */ + for (size_t i = t_con->line_cursor; i < t_con->line_size; i++) + telnet_write(connection, "\b", 1); + } + + /* destroy the command_list */ + struct cmd_match *tmp, *match; + list_for_each_entry_safe(match, tmp, &matches, lh) + free(match); + + Jim_DecrRefCount(command_context->interp, list); +} + static int telnet_input(struct connection *connection) { int bytes_read; unsigned char buffer[TELNET_BUFFER_SIZE]; unsigned char *buf_p; struct telnet_connection *t_con = connection->priv; - struct command_context *command_context = connection->cmd_ctx; bytes_read = connection_read(connection, buffer, TELNET_BUFFER_SIZE); @@ -387,39 +767,16 @@ static int telnet_input(struct connection *connection) while (bytes_read) { switch (t_con->state) { case TELNET_STATE_DATA: - if (*buf_p == 0xff) + if (*buf_p == 0xff) { t_con->state = TELNET_STATE_IAC; - else { + } else { if (isprint(*buf_p)) { /* printable character */ - /* watch buffer size leaving one spare character for - * string null termination */ - if (t_con->line_size == TELNET_LINE_MAX_SIZE-1) { - /* output audible bell if buffer is full - * "\a" does not work, at least on windows */ - telnet_write(connection, "\x07", 1); - } else if (t_con->line_cursor == t_con->line_size) { - telnet_write(connection, buf_p, 1); - t_con->line[t_con->line_size++] = *buf_p; - t_con->line_cursor++; - } else { - size_t i; - memmove(t_con->line + t_con->line_cursor + 1, - t_con->line + t_con->line_cursor, - t_con->line_size - t_con->line_cursor); - t_con->line[t_con->line_cursor] = *buf_p; - t_con->line_size++; - telnet_write(connection, - t_con->line + t_con->line_cursor, - t_con->line_size - t_con->line_cursor); - t_con->line_cursor++; - for (i = t_con->line_cursor; i < t_con->line_size; i++) - telnet_write(connection, "\b", 1); - } - } else { /* non-printable */ + telnet_insert(connection, buf_p, 1); + } else { /* non-printable */ if (*buf_p == 0x1b) { /* escape */ t_con->state = TELNET_STATE_ESCAPE; t_con->last_escape = '\x00'; - } else if ((*buf_p == 0xd) || (*buf_p == 0xa)) { /* CR/LF */ + } else if ((*buf_p == 0xd) || (*buf_p == 0xa)) { /* CR/LF */ int retval; /* skip over combinations with CR/LF and NUL characters */ @@ -434,112 +791,36 @@ static int telnet_input(struct connection *connection) } t_con->line[t_con->line_size] = 0; - telnet_write(connection, "\r\n\x00", 3); - - if (strcmp(t_con->line, "history") == 0) { - retval = telnet_history_print(connection); - - if (retval != ERROR_OK) - return retval; - - continue; - } - - /* save only non-blank not repeating lines in the history */ - char *prev_line = t_con->history[(t_con->current_history > 0) ? - t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1]; - if (*t_con->line && (prev_line == NULL || - strcmp(t_con->line, prev_line))) { - /* if the history slot is already taken, free it */ - free(t_con->history[t_con->next_history]); - - /* add line to history */ - t_con->history[t_con->next_history] = strdup(t_con->line); - - /* wrap history at TELNET_LINE_HISTORY_SIZE */ - t_con->next_history = (t_con->next_history + 1) % - TELNET_LINE_HISTORY_SIZE; - - /* current history line starts at the new entry */ - t_con->current_history = - t_con->next_history; - - free(t_con->history[t_con->current_history]); - t_con->history[t_con->current_history] = strdup(""); - } - - t_con->line_size = 0; - - /* to suppress prompt in log callback during command execution */ - t_con->prompt_visible = false; - - if (strcmp(t_con->line, "shutdown") == 0) - telnet_save_history(t_con); - - retval = command_run_line(command_context, t_con->line); - - t_con->line_cursor = 0; - t_con->prompt_visible = true; - - if (retval == ERROR_COMMAND_CLOSE_CONNECTION) - return ERROR_SERVER_REMOTE_CLOSED; - - /* the prompt is always * placed at the line beginning */ - telnet_write(connection, "\r", 1); - - retval = telnet_prompt(connection); - if (retval == ERROR_SERVER_REMOTE_CLOSED) - return ERROR_SERVER_REMOTE_CLOSED; - + retval = telnet_exec_line(connection); + if (retval != ERROR_OK) + return retval; } else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) { /* delete character */ - if (t_con->line_cursor > 0) { - if (t_con->line_cursor != t_con->line_size) { - size_t i; - telnet_write(connection, "\b", 1); - t_con->line_cursor--; - t_con->line_size--; - memmove(t_con->line + t_con->line_cursor, - t_con->line + t_con->line_cursor + 1, - t_con->line_size - - t_con->line_cursor); - - telnet_write(connection, - t_con->line + t_con->line_cursor, - t_con->line_size - - t_con->line_cursor); - telnet_write(connection, " \b", 2); - for (i = t_con->line_cursor; i < t_con->line_size; i++) - telnet_write(connection, "\b", 1); - } else { - t_con->line_size--; - t_con->line_cursor--; - /* back space: move the 'printer' head one char - * back, overwrite with space, move back again */ - telnet_write(connection, "\b \b", 3); - } - } - } else if (*buf_p == 0x15) /* clear line */ + telnet_delete_character(connection); + } else if (*buf_p == 0x15) { /* clear line */ telnet_clear_line(connection, t_con); - else if (*buf_p == CTRL('B')) { /* cursor left */ - if (t_con->line_cursor > 0) { - telnet_write(connection, "\b", 1); - t_con->line_cursor--; - } + } else if (*buf_p == CTRL('B')) { /* cursor left */ + telnet_move_cursor(connection, t_con->line_cursor - 1); t_con->state = TELNET_STATE_DATA; + } else if (*buf_p == CTRL('C')) { /* interrupt */ + telnet_interrupt(connection); } else if (*buf_p == CTRL('F')) { /* cursor right */ - if (t_con->line_cursor < t_con->line_size) - telnet_write(connection, t_con->line + t_con->line_cursor++, 1); + telnet_move_cursor(connection, t_con->line_cursor + 1); t_con->state = TELNET_STATE_DATA; - } else if (*buf_p == CTRL('P')) /* cursor up */ + } else if (*buf_p == CTRL('P')) { /* cursor up */ telnet_history_up(connection); - else if (*buf_p == CTRL('N')) /* cursor down */ + } else if (*buf_p == CTRL('N')) { /* cursor down */ telnet_history_down(connection); - else if (*buf_p == CTRL('A')) + } else if (*buf_p == CTRL('A')) { /* move the cursor to the beginning of the line */ telnet_move_cursor(connection, 0); - else if (*buf_p == CTRL('E')) + } else if (*buf_p == CTRL('E')) { /* move the cursor to the end of the line */ telnet_move_cursor(connection, t_con->line_size); - else + } else if (*buf_p == CTRL('K')) { /* kill line to end */ + telnet_cut_line_to_end(connection); + } else if (*buf_p == '\t') { + telnet_auto_complete(connection); + } else { LOG_DEBUG("unhandled nonprintable: %2.2x", *buf_p); + } } } break; @@ -572,46 +853,30 @@ static int telnet_input(struct connection *connection) case TELNET_STATE_ESCAPE: if (t_con->last_escape == '[') { if (*buf_p == 'D') { /* cursor left */ - if (t_con->line_cursor > 0) { - telnet_write(connection, "\b", 1); - t_con->line_cursor--; - } + telnet_move_cursor(connection, t_con->line_cursor - 1); t_con->state = TELNET_STATE_DATA; } else if (*buf_p == 'C') { /* cursor right */ - if (t_con->line_cursor < t_con->line_size) - telnet_write(connection, - t_con->line + t_con->line_cursor++, 1); + telnet_move_cursor(connection, t_con->line_cursor + 1); t_con->state = TELNET_STATE_DATA; } else if (*buf_p == 'A') { /* cursor up */ telnet_history_up(connection); } else if (*buf_p == 'B') { /* cursor down */ telnet_history_down(connection); - } else if (*buf_p == '3') + } else if (*buf_p == 'F') { /* end key */ + telnet_move_cursor(connection, t_con->line_size); + t_con->state = TELNET_STATE_DATA; + } else if (*buf_p == 'H') { /* home key */ + telnet_move_cursor(connection, 0); + t_con->state = TELNET_STATE_DATA; + } else if (*buf_p == '3') { t_con->last_escape = *buf_p; - else + } else { t_con->state = TELNET_STATE_DATA; + } } else if (t_con->last_escape == '3') { /* Remove character */ if (*buf_p == '~') { - if (t_con->line_cursor < t_con->line_size) { - size_t i; - t_con->line_size--; - /* remove char from line buffer */ - memmove(t_con->line + t_con->line_cursor, - t_con->line + t_con->line_cursor + 1, - t_con->line_size - t_con->line_cursor); - - /* print remainder of buffer */ - telnet_write(connection, t_con->line + t_con->line_cursor, - t_con->line_size - t_con->line_cursor); - /* overwrite last char with whitespace */ - telnet_write(connection, " \b", 2); - - /* move back to cursor position*/ - for (i = t_con->line_cursor; i < t_con->line_size; i++) - telnet_write(connection, "\b", 1); - } - + telnet_remove_character(connection); t_con->state = TELNET_STATE_DATA; } else t_con->state = TELNET_STATE_DATA; @@ -665,6 +930,15 @@ static int telnet_connection_closed(struct connection *connection) return ERROR_OK; } +static const struct service_driver telnet_service_driver = { + .name = "telnet", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = telnet_new_connection, + .input_handler = telnet_input, + .connection_closed_handler = telnet_connection_closed, + .keep_client_alive_handler = NULL, +}; + int telnet_init(char *banner) { if (strcmp(telnet_port, "disabled") == 0) { @@ -682,8 +956,7 @@ int telnet_init(char *banner) telnet_service->banner = banner; - int ret = add_service("telnet", telnet_port, CONNECTION_LIMIT_UNLIMITED, - telnet_new_connection, telnet_input, telnet_connection_closed, + int ret = add_service(&telnet_service_driver, telnet_port, CONNECTION_LIMIT_UNLIMITED, telnet_service); if (ret != ERROR_OK) { 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 608703434a..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: @@ -31,7 +20,10 @@ #include <jtag/jtag.h> #include "svf.h" +#include "helper/system.h" #include <helper/time_support.h> +#include <helper/nvp.h> +#include <stdbool.h> /* SVF command */ enum svf_command { @@ -149,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; @@ -230,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; @@ -301,7 +298,7 @@ static int svf_realloc_buffers(size_t len) static void svf_free_xxd_para(struct svf_xxr_para *para) { - if (NULL != para) { + if (para) { free(para->tdi); para->tdi = NULL; @@ -350,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)) @@ -373,38 +402,82 @@ 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 == NULL) { + 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; } } - if (svf_fd == NULL) + if (!svf_fd) return ERROR_COMMAND_SYNTAX_ERROR; /* get time */ @@ -416,7 +489,7 @@ COMMAND_HANDLER(handle_svf_command) svf_check_tdo_para_index = 0; svf_check_tdo_para = malloc(sizeof(struct svf_check_tdo_para) * SVF_CHECK_TDO_PARA_SIZE); - if (NULL == svf_check_tdo_para) { + if (!svf_check_tdo_para) { LOG_ERROR("not enough memory"); ret = ERROR_FAIL; goto free_all; @@ -434,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(); } @@ -459,27 +532,31 @@ COMMAND_HANDLER(handle_svf_command) } /* HDR %d TDI (0) */ - if (ERROR_OK != svf_set_padding(&svf_para.hdr_para, header_dr_len, 0)) { - 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 (ERROR_OK != svf_set_padding(&svf_para.hir_para, header_ir_len, 0xFF)) { - 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 (ERROR_OK != svf_set_padding(&svf_para.tdr_para, trailer_dr_len, 0)) { - 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 (ERROR_OK != svf_set_padding(&svf_para.tir_para, trailer_ir_len, 0xFF)) { - 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; } } @@ -491,7 +568,7 @@ COMMAND_HANDLER(handle_svf_command) } rewind(svf_fd); } - while (ERROR_OK == svf_read_command_from_file(svf_fd)) { + while (svf_read_command_from_file(svf_fd) == ERROR_OK) { /* Log Output */ if (svf_quiet) { if (svf_progress_enabled) { @@ -509,7 +586,7 @@ COMMAND_HANDLER(handle_svf_command) LOG_USER_N("%s", svf_read_line); } /* Run Command */ - if (ERROR_OK != svf_run_command(CMD_CTX, svf_command_buffer)) { + if (svf_run_command(CMD_CTX, svf_command_buffer) != ERROR_OK) { LOG_ERROR("fail to run command at line %d", svf_line_number); ret = ERROR_FAIL; break; @@ -517,9 +594,9 @@ COMMAND_HANDLER(handle_svf_command) command_num++; } - if ((!svf_nil) && (ERROR_OK != jtag_execute_queue())) + if ((!svf_nil) && (jtag_execute_queue() != ERROR_OK)) ret = ERROR_FAIL; - else if (ERROR_OK != svf_check_tdo()) + else if (svf_check_tdo() != ERROR_OK) ret = ERROR_FAIL; /* print time */ @@ -538,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); @@ -568,7 +645,7 @@ free_all: svf_free_xxd_para(&svf_para.sdr_para); svf_free_xxd_para(&svf_para.sir_para); - if (ERROR_OK == ret) + if (ret == ERROR_OK) command_print(CMD, "svf file programmed %s for %d commands with %d errors", (svf_ignore_error > 1) ? "unsuccessfully" : "successfully", @@ -586,7 +663,7 @@ static int svf_getline(char **lineptr, size_t *n, FILE *stream) #define MIN_CHUNK 16 /* Buffer is increased by this size each time as required */ size_t i = 0; - if (*lineptr == NULL) { + if (!*lineptr) { *n = MIN_CHUNK; *lineptr = malloc(*n); if (!*lineptr) @@ -674,7 +751,7 @@ static int svf_read_command_from_file(FILE *fd) if (cmd_pos + 3 > svf_command_buffer_size) { svf_command_buffer = realloc(svf_command_buffer, cmd_pos + 3); svf_command_buffer_size = cmd_pos + 3; - if (svf_command_buffer == NULL) { + if (!svf_command_buffer) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } @@ -741,8 +818,8 @@ parse_char: bool svf_tap_state_is_stable(tap_state_t state) { - return (TAP_RESET == state) || (TAP_IDLE == state) - || (TAP_DRPAUSE == state) || (TAP_IRPAUSE == state); + return (state == TAP_RESET) || (state == TAP_IDLE) + || (state == TAP_DRPAUSE) || (state == TAP_IRPAUSE); } static int svf_find_string_in_array(char *str, char **strs, int num_of_element) @@ -760,10 +837,10 @@ static int svf_adjust_array_length(uint8_t **arr, int orig_bit_len, int new_bit_ { int new_byte_len = (new_bit_len + 7) >> 3; - if ((NULL == *arr) || (((orig_bit_len + 7) >> 3) < ((new_bit_len + 7) >> 3))) { + if ((!*arr) || (((orig_bit_len + 7) >> 3) < ((new_bit_len + 7) >> 3))) { free(*arr); *arr = calloc(1, new_byte_len); - if (NULL == *arr) { + if (!*arr) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } @@ -789,7 +866,7 @@ static int svf_copy_hexstring_to_binary(char *str, uint8_t **bin, int orig_bit_l int i, str_len = strlen(str), str_hbyte_len = (bit_len + 3) >> 2; uint8_t ch = 0; - if (ERROR_OK != svf_adjust_array_length(bin, orig_bit_len, bit_len)) { + if (svf_adjust_array_length(bin, orig_bit_len, bit_len) != ERROR_OK) { LOG_ERROR("fail to adjust length of array"); return ERROR_FAIL; } @@ -892,9 +969,9 @@ static int svf_add_check_para(uint8_t enabled, int buffer_offset, int bit_len) static int svf_execute_tap(void) { - if ((!svf_nil) && (ERROR_OK != jtag_execute_queue())) + if ((!svf_nil) && (jtag_execute_queue() != ERROR_OK)) return ERROR_FAIL; - else if (ERROR_OK != svf_check_tdo()) + else if (svf_check_tdo() != ERROR_OK) return ERROR_FAIL; svf_buffer_index = 0; @@ -922,7 +999,7 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) /* flag padding commands skipped due to -tap command */ int padding_command_skipped = 0; - if (ERROR_OK != svf_parse_cmd_string(cmd_str, strlen(cmd_str), argus, &num_of_argu)) + if (svf_parse_cmd_string(cmd_str, strlen(cmd_str), argus, &num_of_argu) != ERROR_OK) return ERROR_FAIL; /* NOTE: we're a bit loose here, because we ignore case in @@ -962,7 +1039,7 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } - if (1 == num_of_argu) { + if (num_of_argu == 1) { /* TODO: set jtag speed to full speed */ svf_para.frequency = 0; } else { @@ -970,7 +1047,7 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) LOG_ERROR("HZ not found in FREQUENCY command"); return ERROR_FAIL; } - if (ERROR_OK != svf_execute_tap()) + if (svf_execute_tap() != ERROR_OK) return ERROR_FAIL; svf_para.frequency = atof(argus[1]); /* TODO: set jtag speed to */ @@ -988,35 +1065,35 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) break; } xxr_para_tmp = &svf_para.hdr_para; - goto XXR_common; + goto xxr_common; case HIR: if (svf_tap_is_specified) { padding_command_skipped = 1; break; } xxr_para_tmp = &svf_para.hir_para; - goto XXR_common; + goto xxr_common; case TDR: if (svf_tap_is_specified) { padding_command_skipped = 1; break; } xxr_para_tmp = &svf_para.tdr_para; - goto XXR_common; + goto xxr_common; case TIR: if (svf_tap_is_specified) { padding_command_skipped = 1; break; } xxr_para_tmp = &svf_para.tir_para; - goto XXR_common; + goto xxr_common; case SDR: xxr_para_tmp = &svf_para.sdr_para; - goto XXR_common; + goto xxr_common; case SIR: xxr_para_tmp = &svf_para.sir_para; - goto XXR_common; -XXR_common: + goto xxr_common; +xxr_common: /* XXR length [TDI (tdi)] [TDO (tdo)][MASK (mask)] [SMASK (smask)] */ if ((num_of_argu > 10) || (num_of_argu % 2)) { LOG_ERROR("invalid parameter of %s", argus[0]); @@ -1090,7 +1167,7 @@ XXR_common: } /* If TDO is absent, no comparison is needed, set the mask to 0 */ if (!(xxr_para_tmp->data_mask & XXR_TDO)) { - if (NULL == xxr_para_tmp->tdo) { + if (!xxr_para_tmp->tdo) { if (ERROR_OK != svf_adjust_array_length(&xxr_para_tmp->tdo, i_tmp, xxr_para_tmp->len)) { @@ -1098,7 +1175,7 @@ XXR_common: return ERROR_FAIL; } } - if (NULL == xxr_para_tmp->mask) { + if (!xxr_para_tmp->mask) { if (ERROR_OK != svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, xxr_para_tmp->len)) { @@ -1109,7 +1186,7 @@ XXR_common: memset(xxr_para_tmp->mask, 0, (xxr_para_tmp->len + 7) >> 3); } /* do scan if necessary */ - if (SDR == command) { + if (command == SDR) { /* check buffer size first, reallocate if necessary */ i = svf_para.hdr_para.len + svf_para.sdr_para.len + svf_para.tdr_para.len; @@ -1199,8 +1276,11 @@ XXR_common: svf_para.dr_end_state); } + if (svf_addcycles) + jtag_add_clocks(svf_addcycles); + svf_buffer_index += (i + 7) >> 3; - } else if (SIR == command) { + } else if (command == SIR) { /* check buffer size first, reallocate if necessary */ i = svf_para.hir_para.len + svf_para.sir_para.len + svf_para.tir_para.len; @@ -1419,7 +1499,7 @@ XXR_common: if (num_of_argu > 2) { /* STATE pathstate1 ... stable_state */ path = malloc((num_of_argu - 1) * sizeof(tap_state_t)); - if (NULL == path) { + if (!path) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } @@ -1433,7 +1513,7 @@ XXR_common: return ERROR_FAIL; } /* OpenOCD refuses paths containing TAP_RESET */ - if (TAP_RESET == path[i]) { + if (path[i] == TAP_RESET) { /* FIXME last state MUST be stable! */ if (i > 0) { if (!svf_nil) @@ -1486,7 +1566,7 @@ XXR_common: return ERROR_FAIL; } if (svf_para.trst_mode != TRST_ABSENT) { - if (ERROR_OK != svf_execute_tap()) + if (svf_execute_tap() != ERROR_OK) return ERROR_FAIL; i_tmp = svf_find_string_in_array(argus[1], (char **)svf_trst_mode_name, @@ -1529,13 +1609,12 @@ XXR_common: if ((svf_buffer_index > 0) && (((command != STATE) && (command != RUNTEST)) || ((command == STATE) && (num_of_argu == 2)))) { - if (ERROR_OK != svf_execute_tap()) + if (svf_execute_tap() != ERROR_OK) return ERROR_FAIL; /* output debug info */ - if ((SIR == command) || (SDR == command)) { + if ((command == SIR) || (command == SDR)) SVF_BUF_LOG(DEBUG, svf_tdi_buffer, svf_check_tdo_para[0].bit_len, "TDO read"); - } } } else { /* for fast executing, execute tap 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 42d809d019..1fc7d2afa6 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -1,12 +1,11 @@ -if OOCD_TRACE -OOCD_TRACE_FILES = %D%/oocd_trace.c -else -OOCD_TRACE_FILES = -endif +# 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) STARTUP_TCL_SRCS += %D%/startup.tcl @@ -20,7 +19,6 @@ noinst_LTLIBRARIES += %D%/libtarget.la $(ARM_MISC_SRC) \ $(AVR32_SRC) \ $(MIPS32_SRC) \ - $(NDS32_SRC) \ $(STM8_SRC) \ $(INTEL_IA32_SRC) \ $(ESIRISC_SRC) \ @@ -33,6 +31,11 @@ noinst_LTLIBRARIES += %D%/libtarget.la $(ARMV8_SRC) \ $(MIPS64_SRC) +if HAVE_CAPSTONE +%C%_libtarget_la_CPPFLAGS += $(CAPSTONE_CFLAGS) +%C%_libtarget_la_LIBADD += $(CAPSTONE_LIBS) +endif + TARGET_CORE_SRC = \ %D%/algorithm.c \ %D%/register.c \ @@ -42,7 +45,8 @@ TARGET_CORE_SRC = \ %D%/target_request.c \ %D%/testee.c \ %D%/semihosting_common.c \ - %D%/smp.c + %D%/smp.c \ + %D%/rtt.c ARMV4_5_SRC = \ %D%/armv4_5.c \ @@ -83,6 +87,7 @@ ARMV8_SRC = \ %D%/armv8_dpm.c \ %D%/armv8_opcodes.c \ %D%/aarch64.c \ + %D%/a64_disassembler.c \ %D%/armv8.c \ %D%/armv8_cache.c @@ -103,8 +108,8 @@ ARM_DEBUG_SRC = \ %D%/trace.c \ %D%/etb.c \ %D%/etm.c \ - $(OOCD_TRACE_FILES) \ %D%/etm_dummy.c \ + %D%/arm_tpiu_swo.c \ %D%/arm_cti.c AVR32_SRC = \ @@ -128,18 +133,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 @@ -163,6 +156,7 @@ ARC_SRC = \ %C%_libtarget_la_SOURCES += \ %D%/algorithm.h \ %D%/arm.h \ + %D%/arm_coresight.h \ %D%/arm_dpm.h \ %D%/arm_jtag.h \ %D%/arm_adi_v5.h \ @@ -170,6 +164,7 @@ ARC_SRC = \ %D%/armv7a_cache_l2x.h \ %D%/armv7a_mmu.h \ %D%/arm_disassembler.h \ + %D%/a64_disassembler.h \ %D%/arm_opcodes.h \ %D%/arm_simulator.h \ %D%/arm_semihosting.h \ @@ -205,16 +200,17 @@ ARC_SRC = \ %D%/etb.h \ %D%/etm.h \ %D%/etm_dummy.h \ + %D%/arm_tpiu_swo.h \ %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 \ %D%/mips32_pracc.h \ %D%/mips32_dmaacc.h \ %D%/mips64_pracc.h \ - %D%/oocd_trace.h \ %D%/register.h \ %D%/target.h \ %D%/target_type.h \ @@ -227,18 +223,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 \ @@ -251,7 +235,10 @@ ARC_SRC = \ %D%/arc.h \ %D%/arc_cmd.h \ %D%/arc_jtag.h \ - %D%/arc_mem.h + %D%/arc_mem.h \ + %D%/rtt.h 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 new file mode 100644 index 0000000000..ca3d3ea7a9 --- /dev/null +++ b/src/target/a64_disassembler.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2019 by Mete Balci * + * metebalci@gmail.com * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/log.h> +#include "target.h" +#include "a64_disassembler.h" + +#if HAVE_CAPSTONE + +#include <capstone.h> + +static void print_opcode(struct command_invocation *cmd, const cs_insn *insn) +{ + uint32_t opcode = 0; + + memcpy(&opcode, insn->bytes, insn->size); + + if (insn->size == 4) { + + uint16_t opcode_high = opcode >> 16; + + opcode = opcode & 0xffff; + + command_print(cmd, + "0x%08" PRIx64" %04x %04x\t%s\t%s", + insn->address, + opcode, + opcode_high, + insn->mnemonic, + insn->op_str); + + } else { + + command_print( + cmd, + "0x%08" PRIx64" %04x\t%s\t%s", + insn->address, + opcode, + insn->mnemonic, + insn->op_str); + + } +} + +int a64_disassemble(struct command_invocation *cmd, struct target *target, target_addr_t address, size_t count) +{ + int ret; + int csret; + csh handle; + + csret = cs_open(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &handle); + + if (csret != CS_ERR_OK) { + + LOG_ERROR("cs_open() failed: %s", cs_strerror(csret)); + return ERROR_FAIL; + + } + + csret = cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON); + + if (csret != CS_ERR_OK) { + + LOG_ERROR("cs_option() failed: %s", cs_strerror(csret)); + cs_close(&handle); + return ERROR_FAIL; + + } + + cs_insn *insn = cs_malloc(handle); + + if (csret != CS_ERR_OK) { + + LOG_ERROR("cs_malloc() failed: %s", cs_strerror(csret)); + cs_close(&handle); + return ERROR_FAIL; + + } + + while (count > 0) { + + uint8_t buffer[4]; + + ret = target_read_buffer(target, address, sizeof(buffer), buffer); + + if (ret != ERROR_OK) { + cs_free(insn, 1); + cs_close(&handle); + return ret; + } + + size_t size = sizeof(buffer); + const uint8_t *tmp = buffer; + + ret = cs_disasm_iter(handle, &tmp, &size, &address, insn); + + if (!ret) { + + LOG_ERROR("cs_disasm_iter() failed: %s", cs_strerror(cs_errno(handle))); + cs_free(insn, 1); + cs_close(&handle); + return ERROR_FAIL; + + } + + print_opcode(cmd, insn); + count--; + + } + + cs_free(insn, 1); + cs_close(&handle); + + return ERROR_OK; +} + +#else + +int a64_disassemble(struct command_invocation *cmd, struct target *target, target_addr_t address, size_t count) +{ + command_print(cmd, "capstone disassembly framework required"); + + return ERROR_FAIL; +} + +#endif diff --git a/src/target/a64_disassembler.h b/src/target/a64_disassembler.h new file mode 100644 index 0000000000..28fcf4b331 --- /dev/null +++ b/src/target/a64_disassembler.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2019 by Mete Balci * + * metebalci@gmail.com * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_AARCH64_DISASSEMBLER_H +#define OPENOCD_TARGET_AARCH64_DISASSEMBLER_H + +#include "target.h" + +int a64_disassemble( + struct command_invocation *cmd, + struct target *target, + target_addr_t address, + size_t count); + +#endif /* OPENOCD_TARGET_AARCH64_DISASSEMBLER_H */ diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 4febc8c96c..2e4d0b5c03 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 @@ -23,14 +11,17 @@ #include "breakpoints.h" #include "aarch64.h" +#include "a64_disassembler.h" #include "register.h" #include "target_request.h" #include "target_type.h" #include "armv8_opcodes.h" #include "armv8_cache.h" +#include "arm_coresight.h" #include "arm_semihosting.h" #include "jtag/interface.h" #include "smp.h" +#include <helper/nvp.h> #include <helper/time_support.h> enum restart_mode { @@ -100,7 +91,9 @@ static int aarch64_restore_system_control_reg(struct target *target) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: + case ARM_MODE_MON: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; @@ -113,7 +106,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; @@ -132,6 +125,7 @@ static int aarch64_mmu_modify(struct target *target, int enable) struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; int retval = ERROR_OK; + enum arm_mode target_mode = ARM_MODE_ANY; uint32_t instr = 0; if (enable) { @@ -157,6 +151,8 @@ static int aarch64_mmu_modify(struct target *target, int enable) switch (armv8->arm.core_mode) { case ARMV8_64_EL0T: + target_mode = ARMV8_64_EL1H; + /* fall through */ case ARMV8_64_EL1T: case ARMV8_64_EL1H: instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL1, 0); @@ -175,7 +171,9 @@ static int aarch64_mmu_modify(struct target *target, int enable) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: + case ARM_MODE_MON: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; @@ -183,9 +181,15 @@ static int aarch64_mmu_modify(struct target *target, int enable) LOG_DEBUG("unknown cpu state 0x%x", armv8->arm.core_mode); break; } + 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) + armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY); + return retval; } @@ -242,7 +246,7 @@ static int aarch64_init_debug_access(struct target *target) /* Write to memory mapped registers directly with no cache or mmu handling */ static int aarch64_dap_write_memap_register_u32(struct target *target, - uint32_t address, + target_addr_t address, uint32_t value) { int retval; @@ -320,15 +324,14 @@ static int aarch64_wait_halt_one(struct target *target) static int aarch64_prepare_halt_smp(struct target *target, bool exc_target, struct target **p_first) { int retval = ERROR_OK; - struct target_list *head = target->head; + struct target_list *head; struct target *first = NULL; LOG_DEBUG("target %s exc %i", target_name(target), exc_target); - while (head != NULL) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; struct armv8_common *armv8 = target_to_armv8(curr); - head = head->next; if (exc_target && curr == target) continue; @@ -349,7 +352,7 @@ static int aarch64_prepare_halt_smp(struct target *target, bool exc_target, stru LOG_DEBUG("target %s prepared", target_name(curr)); - if (first == NULL) + if (!first) first = curr; } @@ -417,7 +420,7 @@ static int aarch64_halt_smp(struct target *target, bool exc_target) struct target_list *head; struct target *curr; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { int halted; curr = head->target; @@ -467,7 +470,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug } /* poll all targets in the group, but skip the target that serves GDB */ - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) @@ -478,7 +481,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug if (curr->state == TARGET_HALTED) continue; /* remember the gdb_service->target */ - if (curr->gdb_service != NULL) + if (curr->gdb_service) gdb_target = curr->gdb_service->target; /* skip it */ if (curr == gdb_target) @@ -491,7 +494,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug } /* after all targets were updated, poll the gdb serving target */ - if (gdb_target != NULL && gdb_target != target) + if (gdb_target && gdb_target != target) aarch64_poll(gdb_target); return ERROR_OK; @@ -588,7 +591,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: @@ -732,7 +735,7 @@ static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoint struct target *first = NULL; uint64_t address; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; /* skip calling target */ @@ -752,7 +755,7 @@ static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoint break; } /* remember the first valid target in the group */ - if (first == NULL) + if (!first) first = curr; } @@ -775,7 +778,7 @@ static int aarch64_step_restart_smp(struct target *target) if (retval != ERROR_OK) return retval; - if (first != NULL) + if (first) retval = aarch64_do_restart_one(first, RESTART_LAZY); if (retval != ERROR_OK) { LOG_DEBUG("error restarting target %s", target_name(first)); @@ -787,7 +790,7 @@ static int aarch64_step_restart_smp(struct target *target) struct target *curr = target; bool all_resumed = true; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; @@ -845,8 +848,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 @@ -875,7 +880,7 @@ static int aarch64_resume(struct target *target, int current, struct target_list *head; bool all_resumed = true; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; @@ -978,25 +983,26 @@ static int aarch64_debug_entry(struct target *target) /* Examine debug reason */ armv8_dpm_report_dscr(dpm, dscr); - /* save address of instruction that triggered the watchpoint? */ + /* save the memory address that triggered the watchpoint */ if (target->debug_reason == DBG_REASON_WATCHPOINT) { uint32_t tmp; - uint64_t wfar = 0; retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_WFAR1, - &tmp); + armv8->debug_base + CPUV8_DBG_EDWAR0, &tmp); if (retval != ERROR_OK) return retval; - wfar = tmp; - wfar = (wfar << 32); - retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_WFAR0, - &tmp); - if (retval != ERROR_OK) - return retval; - wfar |= tmp; - armv8_dpm_report_wfar(&armv8->dpm, wfar); + target_addr_t edwar = tmp; + + /* EDWAR[63:32] has unknown content in aarch32 state */ + if (core_state == ARM_STATE_AARCH64) { + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDWAR1, &tmp); + if (retval != ERROR_OK) + return retval; + edwar |= ((target_addr_t)tmp) << 32; + } + + armv8->dpm.wp_addr = edwar; } retval = armv8_dpm_read_current_registers(&armv8->dpm); @@ -1037,7 +1043,9 @@ static int aarch64_post_debug_entry(struct target *target) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: + case ARM_MODE_MON: instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0); break; @@ -1050,23 +1058,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 = @@ -1083,13 +1094,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; } @@ -1165,6 +1177,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); @@ -1181,6 +1195,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; } @@ -1222,7 +1239,7 @@ static int aarch64_set_breakpoint(struct target *target, struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1235,7 +1252,7 @@ static int aarch64_set_breakpoint(struct target *target, LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); if (breakpoint->length == 2) byte_addr_select = (3 << (breakpoint->address & 0x02)); control = ((matchmode & 0x7) << 20) @@ -1243,23 +1260,23 @@ 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; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, (uint32_t)(bpt_value & 0xFFFFFFFF)); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].brpn, (uint32_t)(bpt_value >> 32)); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; @@ -1295,31 +1312,31 @@ 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->set = 0x11; /* Any nice value but 0 */ + breakpoint->is_set = true; } /* Ensure that halting debug mode is enable */ @@ -1343,7 +1360,7 @@ static int aarch64_set_context_breakpoint(struct target *target, struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1357,7 +1374,7 @@ static int aarch64_set_context_breakpoint(struct target *target, return ERROR_FAIL; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); control = ((matchmode & 0x7) << 20) | (1 << 13) | (byte_addr_select << 5) @@ -1366,12 +1383,12 @@ static int aarch64_set_context_breakpoint(struct target *target, brp_list[brp_i].value = (breakpoint->asid); brp_list[brp_i].control = control; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; @@ -1387,16 +1404,16 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin int retval = ERROR_FAIL; int brp_1 = 0; /* holds the contextID pair */ int brp_2 = 0; /* holds the IVA pair */ - uint32_t control_CTX, control_IVA; - uint8_t CTX_byte_addr_select = 0x0F; - uint8_t IVA_byte_addr_select = 0x0F; - uint8_t CTX_machmode = 0x03; - uint8_t IVA_machmode = 0x01; + uint32_t control_ctx, control_iva; + uint8_t ctx_byte_addr_select = 0x0F; + uint8_t iva_byte_addr_select = 0x0F; + uint8_t ctx_machmode = 0x03; + uint8_t iva_machmode = 0x01; struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1405,7 +1422,7 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin (brp_list[brp_1].type != BRP_CONTEXT)) && (brp_1 < aarch64->brp_num)) brp_1++; - printf("brp(CTX) found num: %d\n", brp_1); + LOG_DEBUG("brp(CTX) found num: %d", brp_1); if (brp_1 >= aarch64->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; @@ -1415,53 +1432,53 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin (brp_list[brp_2].type != BRP_NORMAL)) && (brp_2 < aarch64->brp_num)) brp_2++; - printf("brp(IVA) found num: %d\n", brp_2); + LOG_DEBUG("brp(IVA) found num: %d", brp_2); if (brp_2 >= aarch64->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } - breakpoint->set = brp_1 + 1; - breakpoint->linked_BRP = brp_2; - control_CTX = ((CTX_machmode & 0x7) << 20) + breakpoint_hw_set(breakpoint, brp_1); + breakpoint->linked_brp = brp_2; + control_ctx = ((ctx_machmode & 0x7) << 20) | (brp_2 << 16) | (0 << 14) - | (CTX_byte_addr_select << 5) + | (ctx_byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_1].used = 1; brp_list[brp_1].value = (breakpoint->asid); - brp_list[brp_1].control = control_CTX; + brp_list[brp_1].control = control_ctx; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_1].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_1].brpn, brp_list[brp_1].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_1].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_1].brpn, brp_list[brp_1].control); if (retval != ERROR_OK) return retval; - control_IVA = ((IVA_machmode & 0x7) << 20) + control_iva = ((iva_machmode & 0x7) << 20) | (brp_1 << 16) | (1 << 13) - | (IVA_byte_addr_select << 5) + | (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].control = control_IVA; + 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, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_2].brpn, brp_list[brp_2].value & 0xFFFFFFFF); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_2].BRPn, + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_2].brpn, brp_list[brp_2].value >> 32); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_2].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_2].brpn, brp_list[brp_2].control); if (retval != ERROR_OK) return retval; @@ -1476,16 +1493,16 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - int brp_i = breakpoint->set - 1; - int brp_j = breakpoint->linked_BRP; - if ((brp_i < 0) || (brp_i >= aarch64->brp_num)) { + int brp_i = breakpoint->number; + int brp_j = breakpoint->linked_brp; + if (brp_i >= aarch64->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1495,17 +1512,17 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, (uint32_t)brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].brpn, (uint32_t)brp_list[brp_i].value); if (retval != ERROR_OK) return retval; @@ -1519,28 +1536,28 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br brp_list[brp_j].value = 0; brp_list[brp_j].control = 0; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_j].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_j].brpn, brp_list[brp_j].control); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_j].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_j].brpn, (uint32_t)brp_list[brp_j].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_j].BRPn, + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_j].brpn, (uint32_t)brp_list[brp_j].value); if (retval != ERROR_OK) return retval; - breakpoint->linked_BRP = 0; - breakpoint->set = 0; + breakpoint->linked_brp = 0; + breakpoint->is_set = false; return ERROR_OK; } else { - int brp_i = breakpoint->set - 1; - if ((brp_i < 0) || (brp_i >= aarch64->brp_num)) { + int brp_i = breakpoint->number; + if (brp_i >= aarch64->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1550,54 +1567,54 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].brpn, (uint32_t)brp_list[brp_i].value); if (retval != ERROR_OK) return retval; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } } else { /* 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->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -1650,7 +1667,6 @@ static int aarch64_add_hybrid_breakpoint(struct target *target, return aarch64_set_hybrid_breakpoint(target, breakpoint); /* ??? */ } - static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct aarch64_common *aarch64 = target_to_aarch64(target); @@ -1663,7 +1679,7 @@ static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *b } #endif - if (breakpoint->set) { + if (breakpoint->is_set) { aarch64_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) aarch64->brp_num_available++; @@ -1672,26 +1688,295 @@ static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *b return ERROR_OK; } +/* Setup hardware Watchpoint Register Pair */ +static int aarch64_set_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int retval; + int wp_i = 0; + uint32_t control, offset, length; + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + struct aarch64_brp *wp_list = aarch64->wp_list; + + if (watchpoint->is_set) { + LOG_WARNING("watchpoint already set"); + return ERROR_OK; + } + + while (wp_list[wp_i].used && (wp_i < aarch64->wp_num)) + wp_i++; + if (wp_i >= aarch64->wp_num) { + LOG_ERROR("ERROR Can not find free Watchpoint Register Pair"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + control = (1 << 0) /* enable */ + | (3 << 1) /* both user and privileged access */ + | (1 << 13); /* higher mode control */ + + switch (watchpoint->rw) { + case WPT_READ: + control |= 1 << 3; + break; + case WPT_WRITE: + control |= 2 << 3; + break; + case WPT_ACCESS: + control |= 3 << 3; + break; + } + + /* Match up to 8 bytes. */ + offset = watchpoint->address & 7; + length = watchpoint->length; + if (offset + length > sizeof(uint64_t)) { + length = sizeof(uint64_t) - offset; + LOG_WARNING("Adjust watchpoint match inside 8-byte boundary"); + } + for (; length > 0; offset++, length--) + control |= (1 << offset) << 5; + + wp_list[wp_i].value = watchpoint->address & 0xFFFFFFFFFFFFFFF8ULL; + wp_list[wp_i].control = control; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 16 * wp_list[wp_i].brpn, + (uint32_t)(wp_list[wp_i].value & 0xFFFFFFFF)); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 4 + 16 * wp_list[wp_i].brpn, + (uint32_t)(wp_list[wp_i].value >> 32)); + if (retval != ERROR_OK) + return retval; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WCR_BASE + 16 * wp_list[wp_i].brpn, + control); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("wp %i control 0x%0" PRIx32 " value 0x%" TARGET_PRIxADDR, wp_i, + wp_list[wp_i].control, wp_list[wp_i].value); + + /* Ensure that halting debug mode is enable */ + retval = aarch64_set_dscr_bits(target, DSCR_HDE, DSCR_HDE); + if (retval != ERROR_OK) { + LOG_DEBUG("Failed to set DSCR.HDE"); + return retval; + } + + wp_list[wp_i].used = 1; + watchpoint_set(watchpoint, wp_i); + + return ERROR_OK; +} + +/* Clear hardware Watchpoint Register Pair */ +static int aarch64_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int retval; + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + struct aarch64_brp *wp_list = aarch64->wp_list; + + if (!watchpoint->is_set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + int wp_i = watchpoint->number; + if (wp_i >= aarch64->wp_num) { + LOG_DEBUG("Invalid WP number in watchpoint"); + return ERROR_OK; + } + LOG_DEBUG("rwp %i control 0x%0" PRIx32 " value 0x%0" PRIx64, wp_i, + wp_list[wp_i].control, wp_list[wp_i].value); + wp_list[wp_i].used = 0; + wp_list[wp_i].value = 0; + wp_list[wp_i].control = 0; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WCR_BASE + 16 * wp_list[wp_i].brpn, + wp_list[wp_i].control); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 16 * wp_list[wp_i].brpn, + wp_list[wp_i].value); + if (retval != ERROR_OK) + return retval; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 4 + 16 * wp_list[wp_i].brpn, + (uint32_t)wp_list[wp_i].value); + if (retval != ERROR_OK) + return retval; + watchpoint->is_set = false; + + return ERROR_OK; +} + +static int aarch64_add_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int retval; + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if (aarch64->wp_num_available < 1) { + LOG_INFO("no hardware watchpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + retval = aarch64_set_watchpoint(target, watchpoint); + if (retval == ERROR_OK) + aarch64->wp_num_available--; + + return retval; +} + +static int aarch64_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if (watchpoint->is_set) { + aarch64_unset_watchpoint(target, watchpoint); + aarch64->wp_num_available++; + } + + return ERROR_OK; +} + +/** + * find out which watchpoint hits + * get exception address and compare the address to watchpoints + */ +static int aarch64_hit_watchpoint(struct target *target, + struct watchpoint **hit_watchpoint) +{ + if (target->debug_reason != DBG_REASON_WATCHPOINT) + return ERROR_FAIL; + + struct armv8_common *armv8 = target_to_armv8(target); + + target_addr_t exception_address; + struct watchpoint *wp; + + exception_address = armv8->dpm.wp_addr; + + if (exception_address == 0xFFFFFFFF) + return ERROR_FAIL; + + for (wp = target->watchpoints; wp; wp = wp->next) + if (exception_address >= wp->address && exception_address < (wp->address + wp->length)) { + *hit_watchpoint = wp; + return ERROR_OK; + } + + return ERROR_FAIL; +} + /* * Cortex-A8 Reset functions */ +static int aarch64_enable_reset_catch(struct target *target, bool enable) +{ + struct armv8_common *armv8 = target_to_armv8(target); + uint32_t edecr; + int retval; + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDECR, &edecr); + LOG_DEBUG("EDECR = 0x%08" PRIx32 ", enable=%d", edecr, enable); + if (retval != ERROR_OK) + return retval; + + if (enable) + edecr |= ECR_RCE; + else + edecr &= ~ECR_RCE; + + return mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDECR, edecr); +} + +static int aarch64_clear_reset_catch(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + uint32_t edesr; + int retval; + bool was_triggered; + + /* check if Reset Catch debug event triggered as expected */ + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDESR, &edesr); + if (retval != ERROR_OK) + return retval; + + was_triggered = !!(edesr & ESR_RC); + LOG_DEBUG("Reset Catch debug event %s", + was_triggered ? "triggered" : "NOT triggered!"); + + if (was_triggered) { + /* clear pending Reset Catch debug event */ + edesr &= ~ESR_RC; + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDESR, edesr); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + static int aarch64_assert_reset(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); + enum reset_types reset_config = jtag_get_reset_config(); + int retval; LOG_DEBUG(" "); - /* FIXME when halt is requested, make it work somehow... */ - /* Issue some kind of warm reset. */ if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) target_handle_event(target, TARGET_EVENT_RESET_ASSERT); - else if (jtag_get_reset_config() & RESET_HAS_SRST) { + else if (reset_config & RESET_HAS_SRST) { + bool srst_asserted = false; + + if (target->reset_halt && !(reset_config & RESET_SRST_PULLS_TRST)) { + if (target_was_examined(target)) { + + if (reset_config & RESET_SRST_NO_GATING) { + /* + * SRST needs to be asserted *before* Reset Catch + * debug event can be set up. + */ + 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); + + /* set up Reset Catch debug event to halt the CPU after reset */ + retval = aarch64_enable_reset_catch(target, true); + if (retval != ERROR_OK) + LOG_WARNING("%s: Error enabling Reset Catch debug event; the CPU will not halt immediately after reset!", + target_name(target)); + } else { + LOG_WARNING("%s: Target not examined, will not halt immediately after reset!", + target_name(target)); + } + } + /* REVISIT handle "pulls" cases, if there's * hardware that needs them to work. */ - adapter_assert_reset(); + if (!srst_asserted) + adapter_assert_reset(); } else { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; @@ -1720,23 +2005,41 @@ static int aarch64_deassert_reset(struct target *target) if (!target_was_examined(target)) return ERROR_OK; - retval = aarch64_poll(target); + retval = aarch64_init_debug_access(target); if (retval != ERROR_OK) return retval; - retval = aarch64_init_debug_access(target); + retval = aarch64_poll(target); if (retval != ERROR_OK) return retval; if (target->reset_halt) { + /* clear pending Reset Catch debug event */ + retval = aarch64_clear_reset_catch(target); + if (retval != ERROR_OK) + LOG_WARNING("%s: Clearing Reset Catch debug event failed", + target_name(target)); + + /* disable Reset Catch debug event */ + retval = aarch64_enable_reset_catch(target, false); + if (retval != ERROR_OK) + LOG_WARNING("%s: Disabling Reset Catch debug event failed", + target_name(target)); + if (target->state != TARGET_HALTED) { LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); - retval = target_halt(target); + if (target_was_examined(target)) { + retval = aarch64_halt_one(target, HALT_LAZY); + if (retval != ERROR_OK) + return retval; + } else { + target->state = TARGET_UNKNOWN; + } } } - return retval; + return ERROR_OK; } static int aarch64_write_cpu_memory_slow(struct target *target, @@ -1747,6 +2050,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 */ @@ -1759,22 +2067,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) @@ -1784,8 +2102,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; @@ -1843,7 +2164,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; } @@ -1926,6 +2247,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) */ @@ -1938,36 +2264,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; @@ -2061,7 +2407,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; } @@ -2247,7 +2593,7 @@ static int aarch64_examine_first(struct target *target) struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct adiv5_dap *swjdp = armv8->arm.dap; - struct aarch64_private_config *pc; + struct aarch64_private_config *pc = target->private_config; int i; int retval = ERROR_OK; uint64_t debug, ttypr; @@ -2255,11 +2601,24 @@ static int aarch64_examine_first(struct target *target) uint32_t tmp0, tmp1, tmp2, tmp3; debug = ttypr = cpuid = 0; - /* Search for the APB-AB - it is needed for access to debug registers */ - 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 (!pc) + return ERROR_FAIL; + + 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; + } + } } retval = mem_ap_init(armv8->debug_ap); @@ -2271,20 +2630,13 @@ static int aarch64_examine_first(struct target *target) armv8->debug_ap->memaccess_tck = 10; if (!target->dbgbase_set) { - uint32_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 0x15 -- Processor DAP */ - retval = dap_lookup_cs_component(armv8->debug_ap, dbgbase, 0x15, - &armv8->debug_base, &coreidx); + /* Lookup Processor DAP */ + 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: %08" PRIx32 - " 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; @@ -2334,12 +2686,10 @@ static int aarch64_examine_first(struct target *target) LOG_DEBUG("ttypr = 0x%08" PRIx64, ttypr); LOG_DEBUG("debug = 0x%08" PRIx64, debug); - if (target->private_config == NULL) - return ERROR_FAIL; - - pc = (struct aarch64_private_config *)target->private_config; - if (pc->cti == NULL) + if (!pc->cti) { + LOG_TARGET_ERROR(target, "CTI not specified"); return ERROR_FAIL; + } armv8->cti = pc->cti; @@ -2360,10 +2710,23 @@ static int aarch64_examine_first(struct target *target) aarch64->brp_list[i].type = BRP_CONTEXT; aarch64->brp_list[i].value = 0; aarch64->brp_list[i].control = 0; - aarch64->brp_list[i].BRPn = i; + aarch64->brp_list[i].brpn = i; } - LOG_DEBUG("Configured %i hw breakpoints", aarch64->brp_num); + /* Setup Watchpoint Register Pairs */ + aarch64->wp_num = (uint32_t)((debug >> 20) & 0x0F) + 1; + aarch64->wp_num_available = aarch64->wp_num; + aarch64->wp_list = calloc(aarch64->wp_num, sizeof(struct aarch64_brp)); + for (i = 0; i < aarch64->wp_num; i++) { + aarch64->wp_list[i].used = 0; + aarch64->wp_list[i].type = BRP_NORMAL; + aarch64->wp_list[i].value = 0; + aarch64->wp_list[i].control = 0; + aarch64->wp_list[i].brpn = i; + } + + LOG_DEBUG("Configured %i hw breakpoints, %i watchpoints", + aarch64->brp_num, aarch64->wp_num); target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_NOTHALTED; @@ -2384,6 +2747,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; } @@ -2421,6 +2787,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; @@ -2430,11 +2815,13 @@ static int aarch64_target_create(struct target *target, Jim_Interp *interp) return ERROR_FAIL; aarch64 = calloc(1, sizeof(struct aarch64_common)); - if (aarch64 == NULL) { + if (!aarch64) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } + aarch64->armv8_common.is_armv8r = false; + return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); } @@ -2444,6 +2831,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); @@ -2454,12 +2844,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; } @@ -2476,20 +2870,21 @@ enum aarch64_cfg_param { CFG_CTI, }; -static const Jim_Nvp nvp_config_opts[] = { +static const struct jim_nvp nvp_config_opts[] = { { .name = "-cti", .value = CFG_CTI }, { .name = NULL, .value = -1 } }; -static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) +static int aarch64_jim_configure(struct target *target, struct jim_getopt_info *goi) { struct aarch64_private_config *pc; - Jim_Nvp *n; + struct jim_nvp *n; int e; pc = (struct aarch64_private_config *)target->private_config; - if (pc == NULL) { + if (!pc) { pc = calloc(1, sizeof(struct aarch64_private_config)); + pc->adiv5_config.ap_num = DP_APSEL_INVALID; target->private_config = pc; } @@ -2500,7 +2895,7 @@ static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) * and JIM_ERR if an error occurred during parameter evaluation. * For JIM_CONTINUE, we check our own params. */ - e = adiv5_jim_configure(target, goi); + e = adiv5_jim_configure_ext(target, goi, &pc->adiv5_config, ADI_CONFIGURE_DAP_COMPULSORY); if (e != JIM_CONTINUE) return e; @@ -2509,12 +2904,12 @@ static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) Jim_SetEmptyResult(goi->interp); /* check first if topmost item is for us */ - e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts, + e = jim_nvp_name2value_obj(goi->interp, nvp_config_opts, goi->argv[0], &n); if (e != JIM_OK) return JIM_CONTINUE; - e = Jim_GetOpt_Obj(goi, NULL); + e = jim_getopt_obj(goi, NULL); if (e != JIM_OK) return e; @@ -2523,11 +2918,11 @@ static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) if (goi->isconfigure) { Jim_Obj *o_cti; struct arm_cti *cti; - e = Jim_GetOpt_Obj(goi, &o_cti); + e = jim_getopt_obj(goi, &o_cti); if (e != JIM_OK) return e; cti = cti_instance_by_jim_obj(goi->interp, o_cti); - if (cti == NULL) { + if (!cti) { Jim_SetResultString(goi->interp, "CTI name invalid!", -1); return JIM_ERR; } @@ -2540,7 +2935,7 @@ static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_ERR; } - if (pc == NULL || pc->cti == NULL) { + if (!pc || !pc->cti) { Jim_SetResultString(goi->interp, "CTI not configured", -1); return JIM_ERR; } @@ -2566,7 +2961,6 @@ COMMAND_HANDLER(aarch64_handle_cache_info_command) &armv8->armv8_mmu.armv8_cache); } - COMMAND_HANDLER(aarch64_handle_dbginit_command) { struct target *target = get_current_target(CMD_CTX); @@ -2578,21 +2972,54 @@ COMMAND_HANDLER(aarch64_handle_dbginit_command) return aarch64_init_debug_access(target); } +COMMAND_HANDLER(aarch64_handle_disassemble_command) +{ + struct target *target = get_current_target(CMD_CTX); + + if (!target) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; + } + + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if (aarch64->common_magic != AARCH64_COMMON_MAGIC) { + command_print(CMD, "current target isn't an AArch64"); + return ERROR_FAIL; + } + + int count = 1; + target_addr_t address; + + switch (CMD_ARGC) { + case 2: + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], count); + /* FALL THROUGH */ + case 1: + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return a64_disassemble(CMD, target, address, count); +} + COMMAND_HANDLER(aarch64_mask_interrupts_command) { struct target *target = get_current_target(CMD_CTX); struct aarch64_common *aarch64 = target_to_aarch64(target); - static const 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 Jim_Nvp *n; + const struct nvp *n; if (CMD_ARGC > 0) { - n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); - if (n->name == NULL) { + 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; } @@ -2600,147 +3027,113 @@ 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_context *context; - struct target *target; - struct arm *arm; - int retval; bool is_mcr = false; - int arg_cnt = 0; + unsigned int arg_cnt = 5; - if (Jim_CompareStringImmediate(interp, argv[0], "mcr")) { + if (!strcmp(CMD_NAME, "mcr")) { is_mcr = true; - arg_cnt = 7; - } else { arg_cnt = 6; } - context = current_command_context(interp); - assert(context != NULL); + if (arg_cnt != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; - target = get_current_target(context); - if (target == NULL) { - LOG_ERROR("%s: no current target", __func__); - return JIM_ERR; + struct target *target = get_current_target(CMD_CTX); + if (!target) { + 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; uint32_t op1; uint32_t op2; - uint32_t CRn; - uint32_t CRm; + 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); + /* ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2) */ + 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); + /* ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2) */ + 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[] = { @@ -2758,6 +3151,13 @@ static const struct command_registration aarch64_exec_command_handlers[] = { .help = "Initialize core debug", .usage = "", }, + { + .name = "disassemble", + .handler = aarch64_handle_disassemble_command, + .mode = COMMAND_EXEC, + .help = "Disassemble instructions", + .usage = "address [count]", + }, { .name = "maskisr", .handler = aarch64_mask_interrupts_command, @@ -2768,14 +3168,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", }, @@ -2787,8 +3187,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", @@ -2834,8 +3232,9 @@ struct target_type aarch64_target = { .add_context_breakpoint = aarch64_add_context_breakpoint, .add_hybrid_breakpoint = aarch64_add_hybrid_breakpoint, .remove_breakpoint = aarch64_remove_breakpoint, - .add_watchpoint = NULL, - .remove_watchpoint = NULL, + .add_watchpoint = aarch64_add_watchpoint, + .remove_watchpoint = aarch64_remove_watchpoint, + .hit_watchpoint = aarch64_hit_watchpoint, .commands = aarch64_command_handlers, .target_create = aarch64_target_create, @@ -2849,3 +3248,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 d7886a3d76..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 @@ -46,15 +34,17 @@ struct aarch64_brp { int type; target_addr_t value; uint32_t control; - uint8_t BRPn; + uint8_t brpn; }; 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; @@ -62,7 +52,10 @@ struct aarch64_common { int brp_num_available; struct aarch64_brp *brp_list; - struct armv8_common armv8_common; + /* Watchpoint register pairs */ + int wp_num; + int wp_num_available; + struct aarch64_brp *wp_list; 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 c2100eb471..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 @@ -43,19 +34,21 @@ /*#define DEBUG_WAIT*/ /* JTAG instructions/registers for JTAG-DP and SWJ-DP */ -#define JTAG_DP_ABORT 0x8 -#define JTAG_DP_DPACC 0xA -#define JTAG_DP_APACC 0xB -#define JTAG_DP_IDCODE 0xE +#define JTAG_DP_ABORT 0xF8 +#define JTAG_DP_DPACC 0xFA +#define JTAG_DP_APACC 0xFB +#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; - uint8_t RnW; + 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; @@ -145,19 +129,40 @@ struct dap_cmd { struct dap_cmd_pool { struct list_head lh; struct dap_cmd cmd; -} dap_cmd_pool; +}; -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), - el->RnW == DPAP_READ ? "READ" : "WRITE", + 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) { @@ -179,7 +184,7 @@ static struct dap_cmd *dap_cmd_new(struct adiv5_dap *dap, uint8_t instr, if (list_empty(&dap->cmd_pool)) { pool = calloc(1, sizeof(struct dap_cmd_pool)); - if (pool == NULL) + if (!pool) return NULL; } else { pool = list_first_entry(&dap->cmd_pool, struct dap_cmd_pool, lh); @@ -193,10 +198,10 @@ static struct dap_cmd *dap_cmd_new(struct adiv5_dap *dap, uint8_t instr, INIT_LIST_HEAD(&cmd->lh); cmd->instr = instr; cmd->reg_addr = reg_addr; - cmd->RnW = RnW; - if (outvalue != NULL) + cmd->rnw = rnw; + if (outvalue) memcpy(cmd->outvalue_buf, outvalue, 4); - cmd->invalue = (invalue != NULL) ? invalue : cmd->invalue_buf; + cmd->invalue = (invalue) ? invalue : cmd->invalue_buf; cmd->memaccess_tck = memaccess_tck; return cmd; @@ -253,9 +258,9 @@ static int adi_jtag_dp_scan_cmd(struct adiv5_dap *dap, struct dap_cmd *cmd, uint * For APACC access with any sticky error flag set, this is discarded. */ cmd->fields[0].num_bits = 3; - buf_set_u32(&cmd->out_addr_buf, 0, 3, ((cmd->reg_addr >> 1) & 0x6) | (cmd->RnW & 0x1)); + buf_set_u32(&cmd->out_addr_buf, 0, 3, ((cmd->reg_addr >> 1) & 0x6) | (cmd->rnw & 0x1)); cmd->fields[0].out_value = &cmd->out_addr_buf; - cmd->fields[0].in_value = (ack != NULL) ? ack : &cmd->ack; + cmd->fields[0].in_value = (ack) ? ack : &cmd->ack; /* NOTE: if we receive JTAG_ACK_WAIT, the previous operation did not * complete; data we write is discarded, data we read is unpredictable. @@ -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,10 +298,10 @@ 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 + * Note that only one scan is performed. If rnw is set, a separate scan * will be needed to collect the data which was read; the "invalue" collects * the posted result of a preceding operation, not the current one. * @@ -307,7 +309,7 @@ static int adi_jtag_dp_scan_cmd_sync(struct adiv5_dap *dap, struct dap_cmd *cmd, * @param instr JTAG_DP_APACC (AP access) or JTAG_DP_DPACC (DP access) * @param reg_addr two significant bits; A[3:2]; for APACC access, the * SELECT register has more addressing bits. - * @param RnW false iff outvalue will be written to the DP or AP + * @param rnw false iff outvalue will be written to the DP or AP * @param outvalue points to a 32-bit (little-endian) integer * @param invalue NULL, or points to a 32-bit (little-endian) integer * @param ack points to where the three bit JTAG_ACK_* code will be stored @@ -315,15 +317,15 @@ 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) { struct dap_cmd *cmd; int retval; - cmd = dap_cmd_new(dap, instr, reg_addr, RnW, outvalue, invalue, memaccess_tck); - if (cmd != NULL) + cmd = dap_cmd_new(dap, instr, reg_addr, rnw, outvalue, invalue, memaccess_tck); + if (cmd) cmd->dp_select = dap->select; else return ERROR_JTAG_DEVICE_ERROR; @@ -342,16 +344,38 @@ 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, + retval = adi_jtag_dp_scan(dap, instr, reg_addr, rnw, out_value_buf, (uint8_t *)invalue, memaccess_tck, ack); if (retval != ERROR_OK) return retval; @@ -367,7 +391,7 @@ static int adi_jtag_finish_read(struct adiv5_dap *dap) { int retval = ERROR_OK; - if (dap->last_read != NULL) { + if (dap->last_read) { retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, DP_RDBUFF, DPAP_READ, 0, dap->last_read, 0, NULL); dap->last_read = NULL; @@ -377,21 +401,21 @@ 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; /* Issue the read or write */ retval = adi_jtag_dp_scan_u32(dap, instr, reg_addr, - RnW, outvalue, NULL, memaccess_tck, NULL); + rnw, outvalue, NULL, memaccess_tck, NULL); if (retval != ERROR_OK) return retval; /* For reads, collect posted value; RDBUFF has no other effect. * Assumes read gets acked with OK/FAULT, and CTRL_STAT says "OK". */ - if ((RnW == DPAP_READ) && (invalue != NULL)) { + if ((rnw == DPAP_READ) && (invalue)) { retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, DP_RDBUFF, DPAP_READ, 0, invalue, 0, NULL); if (retval != ERROR_OK) @@ -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; } @@ -435,15 +464,16 @@ 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); + if (prev->rnw == DPAP_READ) { + 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)); @@ -453,8 +483,8 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) } } - if (prev != NULL) { - log_dap_cmd("LST", el); + if (prev) { + log_dap_cmd(dap, "LST", el); /* * At this point we're sure that no previous @@ -466,7 +496,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) */ tmp = dap_cmd_new(dap, JTAG_DP_DPACC, DP_RDBUFF, DPAP_READ, NULL, NULL, 0); - if (tmp == NULL) { + if (!tmp) { retval = ERROR_JTAG_DEVICE_ERROR; goto done; } @@ -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); - if (tmp == NULL) { + 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,16 +610,26 @@ 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_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, + dap->dp_ctrl_stat | SSTICKYORUN, NULL, 0); + if (retval != ERROR_OK) + break; } 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, @@ -633,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; @@ -712,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; + + 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 jtag_dp_q_write(dap, DP_SELECT, sel); + 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 ee30ff7ba4..1231005884 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, @@ -53,57 +43,377 @@ #include <jtag/swd.h> +/* for debug, set do_sync to true to force synchronous transfers */ 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); + + +static int swd_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) +{ + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + assert(swd); + + return swd->switch_seq(seq); +} + static void swd_finish_read(struct adiv5_dap *dap) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); - if (dap->last_read != NULL) { + if (dap->last_read) { swd->read_reg(swd_cmd(true, false, DP_RDBUFF), dap->last_read, 0); dap->last_read = NULL; } } -static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, - uint32_t data); -static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, - uint32_t *data); - static void swd_clear_sticky_errors(struct adiv5_dap *dap) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); - swd->write_reg(swd_cmd(false, false, DP_ABORT), + swd->write_reg(swd_cmd(false, false, DP_ABORT), STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); } static int swd_run_inner(struct adiv5_dap *dap) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + + return swd->run(); +} + +static inline int check_sync(struct adiv5_dap *dap) +{ + return do_sync ? swd_run_inner(dap) : ERROR_OK; +} + +/** Select the DP register bank */ +static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned int reg) +{ + /* Only register address 0 (ADIv6 only) and 4 are banked. */ + if (is_adiv6(dap) ? (reg & 0xf) > 4 : (reg & 0xf) != 4) + return ERROR_OK; + + uint32_t sel = (reg >> 4) & DP_SELECT_DPBANK; + + /* ADIv6 ensures DPBANKSEL = 0 after line reset */ + if ((dap->select_valid || (is_adiv6(dap) && dap->select_dpbanksel_valid)) + && (sel == (dap->select & DP_SELECT_DPBANK))) + return ERROR_OK; + + /* 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); + + LOG_DEBUG_IO("DP BANK SELECT: %" PRIx32, sel); + + /* 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, + uint32_t *data) +{ + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + assert(swd); + + int retval = swd_queue_dp_bankselect(dap, reg); + if (retval != ERROR_OK) + return retval; + + swd->read_reg(swd_cmd(true, false, reg), data, 0); + + return check_sync(dap); +} + +static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg, + uint32_t data) +{ + int retval = ERROR_OK; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + assert(swd); + + swd_finish_read(dap); + + if (reg == DP_SELECT) { + dap->select = data | (dap->select & (0xffffffffull << 32)); + + swd->write_reg(swd_cmd(false, false, reg), data, 0); + + retval = check_sync(dap); + 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); + + /* DP_ABORT write is not banked. + * Prevent writing DP_SELECT before as it would fail on locked up DP */ + if (reg != DP_ABORT) + retval = swd_queue_dp_bankselect(dap, reg); + + if (retval == ERROR_OK) { + swd->write_reg(swd_cmd(false, false, reg), data, 0); + + retval = check_sync(dap); + } + + if (reg == DP_SELECT1) + dap->select1_valid = (retval == ERROR_OK); + + return retval; +} + + +static int swd_multidrop_select_inner(struct adiv5_dap *dap, uint32_t *dpidr_ptr, + uint32_t *dlpidr_ptr, bool clear_sticky) +{ + int retval; + uint32_t dpidr, dlpidr; + + assert(dap_is_multidrop(dap)); + + /* 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) + return retval; + + retval = swd_queue_dp_read_inner(dap, DP_DPIDR, &dpidr); + if (retval != ERROR_OK) + return retval; + + if (clear_sticky) { + /* Clear all sticky errors (including ORUN) */ + swd_clear_sticky_errors(dap); + } else { + /* Ideally just clear ORUN flag which is set by reset */ + retval = swd_queue_dp_write_inner(dap, DP_ABORT, ORUNERRCLR); + if (retval != ERROR_OK) + return retval; + } + + retval = swd_queue_dp_read_inner(dap, DP_DLPIDR, &dlpidr); + if (retval != ERROR_OK) + return retval; + + retval = swd_run_inner(dap); + if (retval != ERROR_OK) + return retval; + + if ((dpidr & DP_DPIDR_VERSION_MASK) < (2UL << DP_DPIDR_VERSION_SHIFT)) { + LOG_INFO("Read DPIDR 0x%08" PRIx32 + " has version < 2. A non multidrop capable device connected?", + dpidr); + return ERROR_FAIL; + } + + /* TODO: check TARGETID if DLIPDR is same for more than one DP */ + uint32_t expected_dlpidr = DP_DLPIDR_PROTVSN | + (dap->multidrop_targetsel & DP_TARGETSEL_INSTANCEID_MASK); + if (dlpidr != expected_dlpidr) { + LOG_INFO("Read incorrect DLPIDR 0x%08" PRIx32 + " (possibly CTRL/STAT value)", + dlpidr); + return ERROR_FAIL; + } + + 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; + + if (dlpidr_ptr) + *dlpidr_ptr = dlpidr; + + return retval; +} + +static int swd_multidrop_select(struct adiv5_dap *dap) +{ + if (!dap_is_multidrop(dap)) + return ERROR_OK; + + if (swd_multidrop_selected_dap == dap) + return ERROR_OK; + + int retval = ERROR_OK; + for (unsigned int retry = 0; ; retry++) { + bool clear_sticky = retry > 0; + + retval = swd_multidrop_select_inner(dap, NULL, NULL, clear_sticky); + if (retval == ERROR_OK) + break; + + swd_multidrop_selected_dap = NULL; + if (retry > 3) { + LOG_ERROR("Failed to select multidrop %s", adiv5_dap_name(dap)); + dap->do_reconnect = true; + return retval; + } + + LOG_DEBUG("Failed to select multidrop %s, retrying...", + adiv5_dap_name(dap)); + } + + dap->do_reconnect = false; + return retval; +} + +static int swd_connect_multidrop(struct adiv5_dap *dap) +{ int retval; + uint32_t dpidr = 0xdeadbeef; + uint32_t dlpidr = 0xdeadbeef; + int64_t timeout = timeval_ms() + 500; + + do { + /* 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; + dap_invalidate_cache(dap); + swd_multidrop_selected_dap = NULL; + + retval = swd_multidrop_select_inner(dap, &dpidr, &dlpidr, true); + if (retval == ERROR_OK) + break; - retval = swd->run(); + swd_multidrop_in_swd_state = false; + alive_sleep(1); + + } while (timeval_ms() < timeout); if (retval != ERROR_OK) { - /* fault response */ - dap->do_reconnect = true; + swd_multidrop_selected_dap = NULL; + LOG_ERROR("Failed to connect multidrop %s", adiv5_dap_name(dap)); + return retval; } + swd_multidrop_in_swd_state = true; + LOG_INFO("SWD DPIDR 0x%08" PRIx32 ", DLPIDR 0x%08" PRIx32, + dpidr, dlpidr); + return retval; } -static int swd_connect(struct adiv5_dap *dap) +static int swd_connect_single(struct adiv5_dap *dap) { - const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + int retval; uint32_t dpidr = 0xdeadbeef; + int64_t timeout = timeval_ms() + 500; + + do { + if (dap->switch_through_dormant) { + swd_send_sequence(dap, JTAG_TO_DORMANT); + swd_send_sequence(dap, DORMANT_TO_SWD); + } else { + swd_send_sequence(dap, JTAG_TO_SWD); + } + + /* Clear link state, including the SELECT cache. */ + 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); + if (retval == ERROR_OK) + break; + } + + alive_sleep(1); + + dap->switch_through_dormant = !dap->switch_through_dormant; + } while (timeval_ms() < timeout); + + if (retval != ERROR_OK) { + LOG_ERROR("Error connecting DP: cannot read IDR"); + return retval; + } + + LOG_INFO("SWD DPIDR 0x%08" PRIx32, dpidr); + + do { + dap->do_reconnect = false; + + /* force clear all sticky faults */ + swd_clear_sticky_errors(dap); + + retval = swd_run_inner(dap); + if (retval != ERROR_WAIT) + break; + + alive_sleep(10); + + } while (timeval_ms() < timeout); + + 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; /* FIXME validate transport config ... is the * configured DAP present (check IDCODE)? - * Is *only* one DAP configured? - * - * MUST READ DPIDR */ /* Check if we should reset srst already when connecting, but not if reconnecting. */ @@ -118,43 +428,37 @@ static int swd_connect(struct adiv5_dap *dap) } } - /* Note, debugport_init() does setup too */ - swd->switch_seq(JTAG_TO_SWD); + if (dap_is_multidrop(dap)) + status = swd_connect_multidrop(dap); + else + status = swd_connect_single(dap); - /* Clear link state, including the SELECT cache. */ - dap->do_reconnect = false; - dap_invalidate_cache(dap); + /* IHI 0031E B4.3.2: + * "A WAIT response must not be issued to the ... + * ... writes to the ABORT register" + * swd_clear_sticky_errors() writes to the ABORT register only. + * + * Unfortunately at least Microchip SAMD51/E53/E54 returns WAIT + * in a corner case. Just try if ABORT resolves the problem. + */ + if (status == ERROR_WAIT) { + LOG_WARNING("Connecting DP: stalled AP operation, issuing ABORT"); - swd_queue_dp_read(dap, DP_DPIDR, &dpidr); + dap->do_reconnect = false; - /* force clear all sticky faults */ - swd_clear_sticky_errors(dap); + status = swd_queue_dp_write_inner(dap, DP_ABORT, + DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR); - status = swd_run_inner(dap); + if (status == ERROR_OK) + status = swd_run_inner(dap); + } - if (status == ERROR_OK) { - LOG_INFO("SWD DPIDR %#8.8" PRIx32, dpidr); - dap->do_reconnect = false; + if (status == ERROR_OK) status = dap_dp_init(dap); - } else - dap->do_reconnect = true; return status; } -static int swd_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) -{ - const struct swd_driver *swd = adiv5_dap_swd_driver(dap); - assert(swd); - - return swd->switch_seq(seq); -} - -static inline int check_sync(struct adiv5_dap *dap) -{ - return do_sync ? swd_run_inner(dap) : ERROR_OK; -} - static int swd_check_reconnect(struct adiv5_dap *dap) { if (dap->do_reconnect) @@ -168,51 +472,31 @@ static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); - swd->write_reg(swd_cmd(false, false, DP_ABORT), - DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); - return check_sync(dap); -} - -/** Select the DP register bank matching bits 7:4 of reg. */ -static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned reg) -{ - /* Only register address 4 is 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)); - - if (sel == dap->select) - return ERROR_OK; - - dap->select = sel; - - int retval = swd_queue_dp_write(dap, DP_SELECT, sel); + /* TODO: Send DAPABORT in swd_multidrop_select_inner() + * in the case the multidrop dap is not selected? + * swd_queue_ap_abort() is not currently used anyway... + */ + int retval = swd_multidrop_select(dap); if (retval != ERROR_OK) - dap->select = DP_SELECT_INVALID; + return retval; - return retval; + swd->write_reg(swd_cmd(false, false, DP_ABORT), + DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); + return check_sync(dap); } static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { - const struct swd_driver *swd = adiv5_dap_swd_driver(dap); - assert(swd); - int retval = swd_check_reconnect(dap); if (retval != ERROR_OK) return retval; - retval = swd_queue_dp_bankselect(dap, reg); + retval = swd_multidrop_select(dap); if (retval != ERROR_OK) return retval; - swd->read_reg(swd_cmd(true, false, reg), data, 0); - - return check_sync(dap); + return swd_queue_dp_read_inner(dap, reg, data); } static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, @@ -225,46 +509,62 @@ static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, if (retval != ERROR_OK) return retval; - swd_finish_read(dap); - if (reg == DP_SELECT) { - dap->select = data & (DP_SELECT_APSEL | DP_SELECT_APBANK | DP_SELECT_DPBANK); - - swd->write_reg(swd_cmd(false, false, reg), data, 0); - - retval = check_sync(dap); - if (retval != ERROR_OK) - dap->select = DP_SELECT_INVALID; - - return retval; - } - - retval = swd_queue_dp_bankselect(dap, reg); + retval = swd_multidrop_select(dap); if (retval != ERROR_OK) return retval; - swd->write_reg(swd_cmd(false, false, reg), data, 0); - - return check_sync(dap); + 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 (is_adiv6(dap)) + sel = ap->ap_num | (reg & 0x00000FF0); + else + sel = (ap->ap_num << 24) | (reg & ADIV5_DP_SELECT_APBANK); + + uint64_t sel_diff = (sel ^ dap->select) & SELECT_AP_MASK; + + 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 & 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 (sel == dap->select) - return ERROR_OK; + if (set_select) { + LOG_DEBUG_IO("AP BANK SELECT: %" PRIx32, (uint32_t)sel); - dap->select = sel; + retval = swd_queue_dp_write(dap, DP_SELECT, (uint32_t)sel); + if (retval != ERROR_OK) + return retval; + } - int retval = swd_queue_dp_write(dap, DP_SELECT, sel); - if (retval != ERROR_OK) - dap->select = DP_SELECT_INVALID; + if (set_select1) { + LOG_DEBUG_IO("AP BANK SELECT1: %" PRIx32, (uint32_t)(sel >> 32)); - return retval; + 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, @@ -278,11 +578,15 @@ static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg, if (retval != ERROR_OK) return retval; + retval = swd_multidrop_select(dap); + if (retval != ERROR_OK) + return retval; + retval = swd_queue_ap_bankselect(ap, reg); if (retval != ERROR_OK) return retval; - swd->read_reg(swd_cmd(true, true, reg), dap->last_read, ap->memaccess_tck); + swd->read_reg(swd_cmd(true, true, reg), dap->last_read, ap->memaccess_tck); dap->last_read = data; return check_sync(dap); @@ -299,12 +603,17 @@ static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned reg, if (retval != ERROR_OK) return retval; + retval = swd_multidrop_select(dap); + if (retval != ERROR_OK) + return retval; + swd_finish_read(dap); + retval = swd_queue_ap_bankselect(ap, reg); if (retval != ERROR_OK) return retval; - swd->write_reg(swd_cmd(false, true, reg), data, ap->memaccess_tck); + swd->write_reg(swd_cmd(false, true, reg), data, ap->memaccess_tck); return check_sync(dap); } @@ -312,21 +621,61 @@ static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned reg, /** Executes all queued DAP operations. */ static int swd_run(struct adiv5_dap *dap) { + int retval = swd_multidrop_select(dap); + if (retval != ERROR_OK) + return retval; + swd_finish_read(dap); - return swd_run_inner(dap); + + retval = swd_run_inner(dap); + if (retval != ERROR_OK) { + /* fault response */ + dap->do_reconnect = true; + } + + return retval; } /** Put the SWJ-DP back to JTAG mode */ static void swd_quit(struct adiv5_dap *dap) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + static bool done; + + /* There is no difference if the sequence is sent at the last + * or the first swd_quit() call, send it just once */ + if (done) + return; + + 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. + * To put SWJ-DPs to power-on state issue + * swd->switch_seq(DORMANT_TO_JTAG); + */ + } else { + if (dap->switch_through_dormant) { + swd->switch_seq(SWD_TO_DORMANT); + swd->switch_seq(DORMANT_TO_JTAG); + } else { + swd->switch_seq(SWD_TO_JTAG); + } + } - swd->switch_seq(SWD_TO_JTAG); - /* flush the queue before exit */ + /* flush the queue to shift out the sequence before exit */ swd->run(); } 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, @@ -348,9 +697,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 8894241c04..25f1a66ab5 100644 --- a/src/target/algorithm.h +++ b/src/target/algorithm.h @@ -1,24 +1,16 @@ +/* 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 #define OPENOCD_TARGET_ALGORITHM_H +#include "helper/types.h" +#include "helper/replacements.h" + enum param_direction { PARAM_IN, PARAM_OUT, diff --git a/src/target/arc.c b/src/target/arc.c index e1b5764363..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 * ***************************************************************************/ @@ -48,6 +48,15 @@ */ +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) @@ -91,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); @@ -225,7 +234,7 @@ static int arc_get_register(struct reg *reg) if (desc->is_core) { /* Accessing to R61/R62 registers causes Jtag hang */ - if (desc->arch_num == CORE_R61_NUM || desc->arch_num == CORE_R62_NUM) { + if (desc->arch_num == ARC_R61 || desc->arch_num == ARC_R62) { LOG_ERROR("It is forbidden to read core registers 61 and 62."); return ERROR_FAIL; } @@ -265,8 +274,8 @@ static int arc_set_register(struct reg *reg, uint8_t *buf) return ERROR_TARGET_NOT_HALTED; /* Accessing to R61/R62 registers causes Jtag hang */ - if (desc->is_core && (desc->arch_num == CORE_R61_NUM || - desc->arch_num == CORE_R62_NUM)) { + if (desc->is_core && (desc->arch_num == ARC_R61 || + desc->arch_num == ARC_R62)) { LOG_ERROR("It is forbidden to write core registers 61 and 62."); return ERROR_FAIL; } @@ -281,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, }; @@ -303,7 +312,7 @@ static int arc_init_reg(struct target *target, struct reg *reg, /* Initialize struct reg */ reg->name = reg_desc->name; reg->size = 32; /* All register in ARC are 32-bit */ - reg->value = ®_desc->reg_value; + reg->value = reg_desc->reg_value; reg->type = &arc_reg_type; reg->arch_info = reg_desc; reg->caller_save = true; /* @todo should be configurable. */ @@ -746,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; @@ -844,27 +876,23 @@ 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. */ if (core_cnt > 0) { retval = arc_jtag_read_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Attempt to read core registers failed."); retval = ERROR_FAIL; goto exit; @@ -872,7 +900,7 @@ static int arc_save_context(struct target *target) } if (aux_cnt > 0) { retval = arc_jtag_read_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Attempt to read aux registers failed."); retval = ERROR_FAIL; goto exit; @@ -882,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++; } } @@ -922,14 +950,15 @@ exit: * Finds an actionpoint that triggered last actionpoint event, as specified by * DEBUG.ASR. * + * @param target * @param actionpoint Pointer to be set to last active actionpoint. Pointer * will be set to NULL if DEBUG.AH is 0. */ static int get_current_actionpoint(struct target *target, struct arc_actionpoint **actionpoint) { - assert(target != NULL); - assert(actionpoint != NULL); + assert(target); + assert(actionpoint); uint32_t debug_ah; /* Check if actionpoint caused halt */ @@ -978,7 +1007,7 @@ static int arc_examine_debug_reason(struct target *target) struct arc_actionpoint *actionpoint = NULL; CHECK_RETVAL(get_current_actionpoint(target, &actionpoint)); - if (actionpoint != NULL) { + if (actionpoint) { if (!actionpoint->used) LOG_WARNING("Target halted by an unused actionpoint."); @@ -1194,7 +1223,7 @@ static int arc_restore_context(struct target *target) * Check before write, if aux and core count is greater than 0. */ if (core_cnt > 0) { retval = arc_jtag_write_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Attempt to write to core registers failed."); retval = ERROR_FAIL; goto exit; @@ -1203,7 +1232,7 @@ static int arc_restore_context(struct target *target) if (aux_cnt > 0) { retval = arc_jtag_write_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("Attempt to write to aux registers failed."); retval = ERROR_FAIL; goto exit; @@ -1250,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 @@ -1259,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); } @@ -1282,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)); @@ -1398,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]; @@ -1425,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]; @@ -1464,7 +1513,7 @@ static int arc_configure_actionpoint(struct target *target, uint32_t ap_num, if (control_tt != AP_AC_TT_DISABLE) { if (arc->actionpoints_num_avail < 1) { - LOG_ERROR("No free actionpoints, maximim amount is %u", + LOG_ERROR("No free actionpoints, maximum amount is %u", arc->actionpoints_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1497,7 +1546,7 @@ static int arc_configure_actionpoint(struct target *target, uint32_t ap_num, static int arc_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1539,7 +1588,7 @@ static int arc_set_breakpoint(struct target *target, return ERROR_COMMAND_ARGUMENT_INVALID; } - breakpoint->set = 64; /* Any nice value but 0 */ + breakpoint->is_set = true; } else if (breakpoint->type == BKPT_HARD) { struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; @@ -1560,7 +1609,7 @@ static int arc_set_breakpoint(struct target *target, breakpoint->address, AP_AC_TT_READWRITE, AP_AC_AT_INST_ADDR); if (retval == ERROR_OK) { - breakpoint->set = bp_num + 1; + breakpoint_hw_set(breakpoint, bp_num); ap_list[bp_num].used = 1; ap_list[bp_num].bp_value = breakpoint->address; ap_list[bp_num].type = ARC_AP_BREAKPOINT; @@ -1574,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; } @@ -1585,7 +1631,7 @@ static int arc_unset_breakpoint(struct target *target, { int retval = ERROR_OK; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -1630,14 +1676,14 @@ static int arc_unset_breakpoint(struct target *target, LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4"); return ERROR_COMMAND_ARGUMENT_INVALID; } - breakpoint->set = 0; + breakpoint->is_set = false; } else if (breakpoint->type == BKPT_HARD) { struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; - unsigned int bp_num = breakpoint->set - 1; + unsigned int bp_num = breakpoint->number; - if ((breakpoint->set == 0) || (bp_num >= arc->actionpoints_num)) { + if (bp_num >= arc->actionpoints_num) { LOG_DEBUG("Invalid actionpoint ID: %u in breakpoint: %" PRIu32, bp_num, breakpoint->unique_id); return ERROR_OK; @@ -1647,11 +1693,11 @@ static int arc_unset_breakpoint(struct target *target, breakpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_INST_ADDR); if (retval == ERROR_OK) { - breakpoint->set = 0; + breakpoint->is_set = false; ap_list[bp_num].used = 0; ap_list[bp_num].bp_value = 0; - LOG_DEBUG("bpid: %" PRIu32 " - released actionpoint ID: %i", + LOG_DEBUG("bpid: %" PRIu32 " - released actionpoint ID: %u", breakpoint->unique_id, bp_num); } } else { @@ -1659,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) { @@ -1672,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; } } @@ -1681,21 +1737,22 @@ static int arc_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state == TARGET_HALTED) { - if (breakpoint->set) + 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; struct breakpoint *next_b; + struct watchpoint *next_w; while (target->breakpoints) { next_b = target->breakpoints->next; @@ -1704,6 +1761,12 @@ void arc_reset_actionpoints(struct target *target) free(target->breakpoints); target->breakpoints = next_b; } + while (target->watchpoints) { + next_w = target->watchpoints->next; + arc_remove_watchpoint(target, target->watchpoints); + free(target->watchpoints); + target->watchpoints = next_w; + } for (unsigned int i = 0; i < arc->actionpoints_num; i++) { if ((ap_list[i].used) && (ap_list[i].reg_address)) arc_remove_auxreg_actionpoint(target, ap_list[i].reg_address); @@ -1800,9 +1863,176 @@ int arc_remove_auxreg_actionpoint(struct target *target, uint32_t auxreg_addr) return retval; } + +static int arc_set_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + unsigned int wp_num; + struct arc_common *arc = target_to_arc(target); + struct arc_actionpoint *ap_list = arc->actionpoints_list; + + if (watchpoint->is_set) { + LOG_WARNING("watchpoint already set"); + return ERROR_OK; + } + + for (wp_num = 0; wp_num < arc->actionpoints_num; wp_num++) { + if (!ap_list[wp_num].used) + break; + } + + if (wp_num >= arc->actionpoints_num) { + LOG_ERROR("No free actionpoints, maximum amount is %u", + arc->actionpoints_num); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (watchpoint->length != 4) { + LOG_ERROR("Only watchpoints of length 4 are supported"); + return ERROR_TARGET_UNALIGNED_ACCESS; + } + + int enable = AP_AC_TT_DISABLE; + switch (watchpoint->rw) { + case WPT_READ: + enable = AP_AC_TT_READ; + break; + case WPT_WRITE: + enable = AP_AC_TT_WRITE; + break; + case WPT_ACCESS: + enable = AP_AC_TT_READWRITE; + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + return ERROR_FAIL; + } + + int retval = arc_configure_actionpoint(target, wp_num, + watchpoint->address, enable, AP_AC_AT_MEMORY_ADDR); + + if (retval == ERROR_OK) { + watchpoint_set(watchpoint, wp_num); + ap_list[wp_num].used = 1; + ap_list[wp_num].bp_value = watchpoint->address; + ap_list[wp_num].type = ARC_AP_WATCHPOINT; + + LOG_DEBUG("wpid: %" PRIu32 ", wp_num %u wp_value 0x%" PRIx32, + watchpoint->unique_id, wp_num, ap_list[wp_num].bp_value); + } + + return retval; +} + +static int arc_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + /* get pointers to arch-specific information */ + struct arc_common *arc = target_to_arc(target); + struct arc_actionpoint *ap_list = arc->actionpoints_list; + + if (!watchpoint->is_set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + unsigned int wp_num = watchpoint->number; + if (wp_num >= arc->actionpoints_num) { + LOG_DEBUG("Invalid actionpoint ID: %u in watchpoint: %" PRIu32, + wp_num, watchpoint->unique_id); + return ERROR_OK; + } + + int retval = arc_configure_actionpoint(target, wp_num, + watchpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_MEMORY_ADDR); + + if (retval == ERROR_OK) { + watchpoint->is_set = false; + ap_list[wp_num].used = 0; + ap_list[wp_num].bp_value = 0; + + LOG_DEBUG("wpid: %" PRIu32 " - releasing actionpoint ID: %u", + watchpoint->unique_id, wp_num); + } + + 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_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + CHECK_RETVAL(arc_set_watchpoint(target, watchpoint)); + + return ERROR_OK; +} + +static int arc_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (watchpoint->is_set) + CHECK_RETVAL(arc_unset_watchpoint(target, watchpoint)); + + return ERROR_OK; +} + +static int arc_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) +{ + assert(target); + assert(hit_watchpoint); + + struct arc_actionpoint *actionpoint = NULL; + CHECK_RETVAL(get_current_actionpoint(target, &actionpoint)); + + if (actionpoint) { + if (!actionpoint->used) + LOG_WARNING("Target halted by unused actionpoint."); + + /* If this check fails - that is some sort of an error in OpenOCD. */ + if (actionpoint->type != ARC_AP_WATCHPOINT) + LOG_WARNING("Target halted by breakpoint, but is treated as a watchpoint."); + + for (struct watchpoint *watchpoint = target->watchpoints; + watchpoint; + watchpoint = watchpoint->next) { + if (actionpoint->bp_value == watchpoint->address) { + *hit_watchpoint = watchpoint; + LOG_DEBUG("Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %u", + watchpoint->unique_id, watchpoint->number); + return ERROR_OK; + } + } + } + + return ERROR_FAIL; +} + /* 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; @@ -1838,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 */ @@ -1847,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, @@ -2002,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; @@ -2106,9 +2352,9 @@ struct target_type arcv2_target = { .add_context_breakpoint = NULL, .add_hybrid_breakpoint = NULL, .remove_breakpoint = arc_remove_breakpoint, - .add_watchpoint = NULL, - .remove_watchpoint = NULL, - .hit_watchpoint = NULL, + .add_watchpoint = arc_add_watchpoint, + .remove_watchpoint = arc_remove_watchpoint, + .hit_watchpoint = arc_hit_watchpoint, .run_algorithm = NULL, .start_algorithm = NULL, diff --git a/src/target/arc.h b/src/target/arc.h index aeb326cb51..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 @@ -45,9 +45,52 @@ #define AUX_STATUS32_REG_HALT_BIT BIT(0) #define AUX_STATUS32_REG_IE_BIT BIT(31) /* STATUS32[31] = IE field */ -/* Reserved core registers */ -#define CORE_R61_NUM (61) -#define CORE_R62_NUM (62) +/* ARC register numbers */ +enum { + ARC_R0, + ARC_R1, + ARC_R2, + ARC_R3, + ARC_R4, + ARC_R5, + ARC_R6, + ARC_R7, + ARC_R8, + ARC_R9, + ARC_R10, + ARC_R11, + ARC_R12, + ARC_R13, + ARC_R14, + ARC_R15, + ARC_R16, + ARC_R17, + ARC_R18, + ARC_R19, + ARC_R20, + ARC_R21, + ARC_R22, + ARC_R23, + ARC_R24, + ARC_R25, + ARC_GP = 26, + ARC_FP = 27, + ARC_SP = 28, + ARC_ILINK = 29, + ARC_R30, + ARC_BLINK = 31, + ARC_LP_COUNT = 60, + + /* Reserved registers */ + ARC_R61 = 61, + ARC_R62 = 62, + + ARC_PCL = 63, + ARC_PC = 64, + ARC_LP_START = 65, + ARC_LP_END = 66, + ARC_STATUS32 = 67, +}; #define CORE_REG_MAX_NUMBER (63) @@ -140,7 +183,7 @@ struct arc_actionpoint { }; struct arc_common { - uint32_t common_magic; + unsigned int common_magic; struct arc_jtag jtag_info; @@ -163,7 +206,7 @@ struct arc_common { bool dcache_invalidated; bool l2cache_invalidated; - /* Indicate if cach was built (for deinit function) */ + /* Indicate if cache was built (for deinit function) */ bool core_aux_cache_built; bool bcr_cache_built; /* Closely Coupled memory(CCM) regions for performance-critical @@ -210,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 18f5cb8f40..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(Jim_GetOptInfo *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 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(Jim_GetOptInfo *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(Jim_GetOptInfo *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) { - Jim_GetOptInfo 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) { - Jim_Nvp *n; - e = Jim_GetOpt_Nvp(&goi, nvp_add_reg_type_flags_opts, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(&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 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; - - Jim_GetOptInfo 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; - - Jim_GetOptInfo 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; - - Jim_GetOptInfo 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)); - if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) { - Jim_SetResultFormatted(goi.interp, "Core register number %i " + uint32_t regnum; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); + if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) { + 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; - - Jim_GetOptInfo 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)); - if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) { - Jim_SetResultFormatted(goi.interp, "Core register number %i " + uint32_t regnum; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); + if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) { + 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) { - Jim_GetOptInfo 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) { - Jim_Nvp *n; - e = Jim_GetOpt_Nvp(&goi, nvp_add_reg_type_struct_opts, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(&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 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) { - Jim_GetOptInfo 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) { - Jim_Nvp *n; - e = Jim_GetOpt_Nvp(&goi, opts_nvp_add_reg, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(&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) { - Jim_GetOptInfo 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) { - Jim_GetOptInfo 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 fd77b37f2c..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 @@ -237,7 +237,7 @@ static void arc_jtag_enque_register_rw(struct arc_jtag *jtag_info, uint32_t *add * @param type Type of registers to write: core or aux. * @param addr Array of registers numbers. * @param count Amount of registers in arrays. - * @param values Array of register values. + * @param buffer Array of register values. */ static int arc_jtag_write_registers(struct arc_jtag *jtag_info, uint32_t type, uint32_t *addr, uint32_t count, const uint32_t *buffer) @@ -272,7 +272,7 @@ static int arc_jtag_write_registers(struct arc_jtag *jtag_info, uint32_t type, * @param type Type of registers to read: core or aux. * @param addr Array of registers numbers. * @param count Amount of registers in arrays. - * @param values Array of register values. + * @param buffer Array of register values. */ static int arc_jtag_read_registers(struct arc_jtag *jtag_info, uint32_t type, uint32_t *addr, uint32_t count, uint32_t *buffer) @@ -337,7 +337,7 @@ int arc_jtag_write_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr, * @param jtag_info * @param addr Array of registers numbers. * @param count Amount of registers in arrays. - * @param values Array of register values. + * @param buffer Array of register values. */ int arc_jtag_write_core_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, const uint32_t *buffer) @@ -361,7 +361,7 @@ int arc_jtag_read_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr, * @param jtag_info * @param addr Array of core register numbers. * @param count Amount of registers in arrays. - * @param values Array of register values. + * @param buffer Array of register values. */ int arc_jtag_read_core_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, uint32_t *buffer) @@ -385,7 +385,7 @@ int arc_jtag_write_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr, * @param jtag_info * @param addr Array of registers numbers. * @param count Amount of registers in arrays. - * @param values Array of register values. + * @param buffer Array of register values. */ int arc_jtag_write_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, const uint32_t *buffer) @@ -409,7 +409,7 @@ int arc_jtag_read_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr, * @param jtag_info * @param addr Array of AUX register numbers. * @param count Amount of registers in arrays. - * @param values Array of register values. + * @param buffer Array of register values. */ int arc_jtag_read_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr, uint32_t count, uint32_t *buffer) 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 96762690fe..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; } @@ -281,7 +281,7 @@ int arc_mem_read(struct target *target, target_addr_t address, uint32_t size, /* arc_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */ /* endianness, but byte array should represent target endianness */ - if (ERROR_OK == retval) { + if (retval == ERROR_OK) { switch (size) { case 4: target_buffer_set_u32_array(target, buffer, count, 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 d97a95edf9..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 @@ -60,6 +49,22 @@ enum arm_core_type { ARM_CORE_TYPE_M_PROFILE, }; +/** ARM Architecture specifying the version and the profile */ +enum arm_arch { + ARM_ARCH_UNKNOWN, + ARM_ARCH_V4, + ARM_ARCH_V6M, + ARM_ARCH_V7M, + 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. * @@ -157,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. @@ -167,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. */ @@ -191,14 +197,8 @@ struct arm { /** Record the current core state: ARM, Thumb, or otherwise. */ enum arm_state core_state; - /** Flag reporting unavailability of the BKPT instruction. */ - bool is_armv4; - - /** Flag reporting armv6m based core. */ - bool is_armv6m; - - /** Flag reporting armv8m based core. */ - bool is_armv8m; + /** ARM architecture version */ + enum arm_arch arch; /** Floating point or VFP version, 0 if disabled. */ int arm_vfp_version; @@ -228,15 +228,25 @@ struct arm { /** Read coprocessor register. */ int (*mrc)(struct target *target, int cpnum, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, + 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 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, @@ -247,20 +257,20 @@ 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 != NULL); + assert(target); return target->arch_info; } static inline bool is_arm(struct arm *arm) { - assert(arm != NULL); + assert(arm); return arm->common_magic == ARM_COMMON_MAGIC; } struct arm_algorithm { - int common_magic; + unsigned int common_magic; enum arm_mode core_mode; enum arm_state core_state; @@ -280,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); @@ -298,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); @@ -316,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 68d4e18944..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 @@ -51,14 +40,14 @@ static int arm11_step(struct target *target, int current, */ static int arm11_check_init(struct arm11_common *arm11) { - CHECK_RETVAL(arm11_read_DSCR(arm11)); + CHECK_RETVAL(arm11_read_dscr(arm11)); if (!(arm11->dscr & DSCR_HALT_DBG_MODE)) { LOG_DEBUG("DSCR %08x", (unsigned) arm11->dscr); LOG_DEBUG("Bringing target into debug mode"); arm11->dscr |= DSCR_HALT_DBG_MODE; - CHECK_RETVAL(arm11_write_DSCR(arm11, arm11->dscr)); + CHECK_RETVAL(arm11_write_dscr(arm11, arm11->dscr)); /* add further reset initialization here */ @@ -104,9 +93,9 @@ static int arm11_debug_entry(struct arm11_common *arm11) /* maybe save wDTR (pending DCC write to debug SW, e.g. libdcc) */ arm11->is_wdtr_saved = !!(arm11->dscr & DSCR_DTR_TX_FULL); if (arm11->is_wdtr_saved) { - arm11_add_debug_SCAN_N(arm11, 0x05, ARM11_TAP_DEFAULT); + arm11_add_debug_scan_n(arm11, 0x05, ARM11_TAP_DEFAULT); - arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; @@ -126,7 +115,7 @@ static int arm11_debug_entry(struct arm11_common *arm11) * but not to issue ITRs(?). The ARMv7 arch spec says it's required * for executing instructions via ITR. */ - CHECK_RETVAL(arm11_write_DSCR(arm11, DSCR_ITR_EN | arm11->dscr)); + CHECK_RETVAL(arm11_write_dscr(arm11, DSCR_ITR_EN | arm11->dscr)); /* From the spec: @@ -143,14 +132,14 @@ static int arm11_debug_entry(struct arm11_common *arm11) /* mcr 15, 0, r0, cr7, cr10, {4} */ arm11_run_instr_no_data1(arm11, 0xee070f9a); - uint32_t dscr = arm11_read_DSCR(arm11); + uint32_t dscr = arm11_read_dscr(arm11); LOG_DEBUG("DRAIN, DSCR %08x", dscr); if (dscr & ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT) { arm11_run_instr_no_data1(arm11, 0xe320f000); - dscr = arm11_read_DSCR(arm11); + dscr = arm11_read_dscr(arm11); LOG_DEBUG("DRAIN, DSCR %08x (DONE)", dscr); @@ -242,7 +231,7 @@ static int arm11_leave_debug_state(struct arm11_common *arm11, bool bpwp) /* spec says clear wDTR and rDTR; we assume they are clear as otherwise our programming would be sloppy */ { - CHECK_RETVAL(arm11_read_DSCR(arm11)); + CHECK_RETVAL(arm11_read_dscr(arm11)); if (arm11->dscr & (DSCR_DTR_RX_FULL | DSCR_DTR_TX_FULL)) { /* @@ -285,23 +274,23 @@ static int arm11_leave_debug_state(struct arm11_common *arm11, bool bpwp) register_cache_invalidate(arm11->arm.core_cache); /* restore DSCR */ - CHECK_RETVAL(arm11_write_DSCR(arm11, arm11->dscr)); + CHECK_RETVAL(arm11_write_dscr(arm11, arm11->dscr)); /* maybe restore rDTR */ if (arm11->is_rdtr_saved) { - arm11_add_debug_SCAN_N(arm11, 0x05, ARM11_TAP_DEFAULT); + arm11_add_debug_scan_n(arm11, 0x05, ARM11_TAP_DEFAULT); - arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; - uint8_t Ready = 0; /* ignored */ - uint8_t Valid = 0; /* ignored */ + uint8_t ready = 0; /* ignored */ + uint8_t valid = 0; /* ignored */ arm11_setup_field(arm11, 32, &arm11->saved_rdtr, NULL, chain5_fields + 0); - arm11_setup_field(arm11, 1, &Ready, NULL, chain5_fields + 1); - arm11_setup_field(arm11, 1, &Valid, NULL, chain5_fields + 2); + arm11_setup_field(arm11, 1, &ready, NULL, chain5_fields + 1); + arm11_setup_field(arm11, 1, &valid, NULL, chain5_fields + 2); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_DRPAUSE); @@ -355,8 +344,7 @@ static int arm11_arch_state(struct target *target) /* REVISIT also display ARM11-specific MMU and cache status ... */ if (target->debug_reason == DBG_REASON_WATCHPOINT) - LOG_USER("Watchpoint triggered at PC %#08x", - (unsigned) arm11->dpm.wp_pc); + LOG_USER("Watchpoint triggered at PC " TARGET_ADDR_FMT, arm11->dpm.wp_addr); return retval; } @@ -377,14 +365,14 @@ static int arm11_halt(struct target *target) return ERROR_OK; } - arm11_add_IR(arm11, ARM11_HALT, TAP_IDLE); + arm11_add_ir(arm11, ARM11_HALT, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); int i = 0; while (1) { - CHECK_RETVAL(arm11_read_DSCR(arm11)); + CHECK_RETVAL(arm11_read_dscr(arm11)); if (arm11->dscr & DSCR_CORE_HALTED) break; @@ -461,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; } @@ -520,13 +508,13 @@ static int arm11_resume(struct target *target, int current, /* activate all watchpoints and breakpoints */ CHECK_RETVAL(arm11_leave_debug_state(arm11, true)); - arm11_add_IR(arm11, ARM11_RESTART, TAP_IDLE); + arm11_add_ir(arm11, ARM11_RESTART, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); int i = 0; while (1) { - CHECK_RETVAL(arm11_read_DSCR(arm11)); + CHECK_RETVAL(arm11_read_dscr(arm11)); LOG_DEBUG("DSCR %08x", (unsigned) arm11->dscr); @@ -563,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; } @@ -662,7 +650,7 @@ static int arm11_step(struct target *target, int current, CHECK_RETVAL(arm11_leave_debug_state(arm11, handle_breakpoints)); - arm11_add_IR(arm11, ARM11_RESTART, TAP_IDLE); + arm11_add_ir(arm11, ARM11_RESTART, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); @@ -673,7 +661,7 @@ static int arm11_step(struct target *target, int current, const uint32_t mask = DSCR_CORE_RESTARTED | DSCR_CORE_HALTED; - CHECK_RETVAL(arm11_read_DSCR(arm11)); + CHECK_RETVAL(arm11_read_dscr(arm11)); LOG_DEBUG("DSCR %08x e", (unsigned) arm11->dscr); if ((arm11->dscr & mask) == mask) @@ -810,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; } @@ -908,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; } @@ -1097,7 +1085,7 @@ static int arm11_target_create(struct target *target, Jim_Interp *interp) { struct arm11_common *arm11; - if (target->tap == NULL) + if (!target->tap) return ERROR_FAIL; if (target->tap->ir_length != 5) { @@ -1152,7 +1140,7 @@ static int arm11_examine(struct target *target) /* check IDCODE */ - arm11_add_IR(arm11, ARM11_IDCODE, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_IDCODE, ARM11_TAP_DEFAULT); struct scan_field idcode_field; @@ -1162,9 +1150,9 @@ static int arm11_examine(struct target *target) /* check DIDR */ - arm11_add_debug_SCAN_N(arm11, 0x00, ARM11_TAP_DEFAULT); + arm11_add_debug_scan_n(arm11, 0x00, ARM11_TAP_DEFAULT); - arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain0_fields[2]; 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 60be0096ff..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 @@ -132,7 +121,7 @@ static const char *arm11_ir_to_string(uint8_t ir) * * \remarks This adds to the JTAG command queue but does \em not execute it. */ -void arm11_add_IR(struct arm11_common *arm11, uint8_t instr, tap_state_t state) +void arm11_add_ir(struct arm11_common *arm11, uint8_t instr, tap_state_t state) { struct jtag_tap *tap = arm11->arm.target->tap; @@ -153,7 +142,7 @@ void arm11_add_IR(struct arm11_common *arm11, uint8_t instr, tap_state_t state) } /** Verify data shifted out from Scan Chain Register (SCREG). */ -static void arm11_in_handler_SCAN_N(uint8_t *in_value) +static void arm11_in_handler_scan_n(uint8_t *in_value) { /* Don't expect JTAG layer to modify bits we didn't ask it to read */ uint8_t v = *in_value & 0x1F; @@ -186,12 +175,12 @@ static void arm11_in_handler_SCAN_N(uint8_t *in_value) * call will end in Pause-DR. The second call, due to the IR * caching, will not go through Capture-DR when shifting in the * new scan chain number. As a result the verification in - * arm11_in_handler_SCAN_N() must fail. + * arm11_in_handler_scan_n() must fail. * * \remarks This adds to the JTAG command queue but does \em not execute it. */ -int arm11_add_debug_SCAN_N(struct arm11_common *arm11, +int arm11_add_debug_scan_n(struct arm11_common *arm11, uint8_t chain, tap_state_t state) { /* Don't needlessly switch the scan chain. @@ -211,7 +200,7 @@ int arm11_add_debug_SCAN_N(struct arm11_common *arm11, #endif JTAG_DEBUG("SCREG <= %d", chain); - arm11_add_IR(arm11, ARM11_SCAN_N, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_SCAN_N, ARM11_TAP_DEFAULT); struct scan_field field; @@ -225,7 +214,7 @@ int arm11_add_debug_SCAN_N(struct arm11_common *arm11, jtag_execute_queue_noclear(); - arm11_in_handler_SCAN_N(tmp); + arm11_in_handler_scan_n(tmp); arm11->jtag_info.cur_scan_chain = chain; @@ -250,7 +239,7 @@ int arm11_add_debug_SCAN_N(struct arm11_common *arm11, * is properly set up. Depending on the instruction, you may also need * to ensure that the rDTR is ready before that Run-Test/Idle state. */ -static void arm11_add_debug_INST(struct arm11_common *arm11, +static void arm11_add_debug_inst(struct arm11_common *arm11, uint32_t inst, uint8_t *flag, tap_state_t state) { JTAG_DEBUG("INST <= 0x%08x", (unsigned) inst); @@ -273,15 +262,15 @@ static void arm11_add_debug_INST(struct arm11_common *arm11, * command queue. It does not require the ARM11 debug TAP to be * in any particular state. */ -int arm11_read_DSCR(struct arm11_common *arm11) +int arm11_read_dscr(struct arm11_common *arm11) { int retval; - retval = arm11_add_debug_SCAN_N(arm11, 0x01, ARM11_TAP_DEFAULT); + retval = arm11_add_debug_scan_n(arm11, 0x01, ARM11_TAP_DEFAULT); if (retval != ERROR_OK) return retval; - arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); uint32_t dscr; struct scan_field chain1_field; @@ -311,14 +300,14 @@ int arm11_read_DSCR(struct arm11_common *arm11) * * \remarks This is a stand-alone function that executes the JTAG command queue. */ -int arm11_write_DSCR(struct arm11_common *arm11, uint32_t dscr) +int arm11_write_dscr(struct arm11_common *arm11, uint32_t dscr) { int retval; - retval = arm11_add_debug_SCAN_N(arm11, 0x01, ARM11_TAP_DEFAULT); + retval = arm11_add_debug_scan_n(arm11, 0x01, ARM11_TAP_DEFAULT); if (retval != ERROR_OK) return retval; - arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain1_field; @@ -353,7 +342,7 @@ int arm11_write_DSCR(struct arm11_common *arm11, uint32_t dscr) */ int arm11_run_instr_data_prepare(struct arm11_common *arm11) { - return arm11_add_debug_SCAN_N(arm11, 0x05, ARM11_TAP_DEFAULT); + return arm11_add_debug_scan_n(arm11, 0x05, ARM11_TAP_DEFAULT); } /** Cleanup after ITR/DTR operations @@ -372,7 +361,7 @@ int arm11_run_instr_data_prepare(struct arm11_common *arm11) */ int arm11_run_instr_data_finish(struct arm11_common *arm11) { - return arm11_add_debug_SCAN_N(arm11, 0x00, ARM11_TAP_DEFAULT); + return arm11_add_debug_scan_n(arm11, 0x00, ARM11_TAP_DEFAULT); } /** @@ -392,16 +381,16 @@ static int arm11_run_instr_no_data(struct arm11_common *arm11, uint32_t *opcode, size_t count) { - arm11_add_IR(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); while (count--) { - arm11_add_debug_INST(arm11, *opcode++, NULL, TAP_IDLE); + arm11_add_debug_inst(arm11, *opcode++, NULL, TAP_IDLE); int i = 0; while (1) { uint8_t flag; - arm11_add_debug_INST(arm11, 0, &flag, count ? TAP_IDLE : TAP_DRPAUSE); + arm11_add_debug_inst(arm11, 0, &flag, count ? TAP_IDLE : TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); @@ -463,33 +452,33 @@ int arm11_run_instr_data_to_core(struct arm11_common *arm11, uint32_t *data, size_t count) { - arm11_add_IR(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); - arm11_add_debug_INST(arm11, opcode, NULL, TAP_DRPAUSE); + arm11_add_debug_inst(arm11, opcode, NULL, TAP_DRPAUSE); - arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; - uint32_t Data; - uint8_t Ready; - uint8_t nRetry; + uint32_t _data; + uint8_t ready; + uint8_t n_retry; - arm11_setup_field(arm11, 32, &Data, NULL, chain5_fields + 0); - arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); - arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); + arm11_setup_field(arm11, 32, &_data, NULL, chain5_fields + 0); + arm11_setup_field(arm11, 1, NULL, &ready, chain5_fields + 1); + arm11_setup_field(arm11, 1, NULL, &n_retry, chain5_fields + 2); while (count--) { int i = 0; do { - Data = *data; + _data = *data; arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); - JTAG_DEBUG("DTR Ready %d nRetry %d", Ready, nRetry); + JTAG_DEBUG("DTR ready %d n_retry %d", ready, n_retry); int64_t then = 0; @@ -504,24 +493,24 @@ int arm11_run_instr_data_to_core(struct arm11_common *arm11, } i++; - } while (!Ready); + } while (!ready); data++; } - arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); int i = 0; do { - Data = 0; + _data = 0; arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); - JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", - (unsigned) Data, Ready, nRetry); + JTAG_DEBUG("DTR _data %08x ready %d n_retry %d", + (unsigned) _data, ready, n_retry); int64_t then = 0; @@ -535,7 +524,7 @@ int arm11_run_instr_data_to_core(struct arm11_common *arm11, } i++; - } while (!Ready); + } while (!ready); return ERROR_OK; } @@ -557,16 +546,12 @@ int arm11_run_instr_data_to_core(struct arm11_common *arm11, * https://lists.berlios.de/pipermail/openocd-development/2009-July/009698.html * https://lists.berlios.de/pipermail/openocd-development/2009-August/009865.html */ -static const tap_state_t arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay[] = { +static const tap_state_t arm11_move_drpause_idle_drpause_with_delay[] = { TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT }; -/* This inner loop can be implemented by the minidriver, oftentimes in hardware... The - * minidriver can call the default implementation as a fallback or implement it - * from scratch. - */ -int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, +static int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode, uint32_t *data, size_t count) @@ -585,26 +570,26 @@ int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, chain5_fields[2].out_value = NULL; chain5_fields[2].in_value = NULL; - uint8_t *Readies; - unsigned readiesNum = count; - unsigned bytes = sizeof(*Readies)*readiesNum; + uint8_t *readies; + unsigned readies_num = count; + unsigned bytes = sizeof(*readies)*readies_num; - Readies = malloc(bytes); - if (Readies == NULL) { + readies = malloc(bytes); + if (!readies) { LOG_ERROR("Out of memory allocating %u bytes", bytes); return ERROR_FAIL; } - uint8_t *ReadyPos = Readies; + uint8_t *ready_pos = readies; while (count--) { chain5_fields[0].out_value = (uint8_t *)(data++); - chain5_fields[1].in_value = ReadyPos++; + chain5_fields[1].in_value = ready_pos++; if (count > 0) { jtag_add_dr_scan(tap, ARRAY_SIZE(chain5_fields), chain5_fields, TAP_DRPAUSE); - jtag_add_pathmove(ARRAY_SIZE(arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay), - arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay); + jtag_add_pathmove(ARRAY_SIZE(arm11_move_drpause_idle_drpause_with_delay), + arm11_move_drpause_idle_drpause_with_delay); } else jtag_add_dr_scan(tap, ARRAY_SIZE(chain5_fields), chain5_fields, TAP_IDLE); } @@ -613,37 +598,22 @@ int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, if (retval == ERROR_OK) { unsigned error_count = 0; - for (size_t i = 0; i < readiesNum; i++) { - if (Readies[i] != 1) + for (size_t i = 0; i < readies_num; i++) { + if (readies[i] != 1) error_count++; } if (error_count > 0) { LOG_ERROR("%u words out of %u not transferred", - error_count, readiesNum); + error_count, readies_num); retval = ERROR_FAIL; } } - free(Readies); + free(readies); return retval; } -int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, - uint32_t opcode, - uint32_t *data, - size_t count); - -#ifndef HAVE_JTAG_MINIDRIVER_H -int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, - uint32_t opcode, - uint32_t *data, - size_t count) -{ - return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count); -} -#endif - /** Execute one instruction via ITR repeatedly while * passing data to the core via DTR on each execution. * @@ -668,11 +638,11 @@ int arm11_run_instr_data_to_core_noack(struct arm11_common *arm11, uint32_t *data, size_t count) { - arm11_add_IR(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); - arm11_add_debug_INST(arm11, opcode, NULL, TAP_DRPAUSE); + arm11_add_debug_inst(arm11, opcode, NULL, TAP_DRPAUSE); - arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); int retval = arm11_run_instr_data_to_core_noack_inner(arm11->arm.target->tap, opcode, @@ -682,7 +652,7 @@ int arm11_run_instr_data_to_core_noack(struct arm11_common *arm11, if (retval != ERROR_OK) return retval; - arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; @@ -759,21 +729,21 @@ int arm11_run_instr_data_from_core(struct arm11_common *arm11, uint32_t *data, size_t count) { - arm11_add_IR(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); - arm11_add_debug_INST(arm11, opcode, NULL, TAP_IDLE); + arm11_add_debug_inst(arm11, opcode, NULL, TAP_IDLE); - arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; - uint32_t Data; - uint8_t Ready; - uint8_t nRetry; + uint32_t _data; + uint8_t ready; + uint8_t n_retry; - arm11_setup_field(arm11, 32, NULL, &Data, chain5_fields + 0); - arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); - arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); + arm11_setup_field(arm11, 32, NULL, &_data, chain5_fields + 0); + arm11_setup_field(arm11, 1, NULL, &ready, chain5_fields + 1); + arm11_setup_field(arm11, 1, NULL, &n_retry, chain5_fields + 2); while (count--) { int i = 0; @@ -784,8 +754,8 @@ int arm11_run_instr_data_from_core(struct arm11_common *arm11, CHECK_RETVAL(jtag_execute_queue()); - JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", - (unsigned) Data, Ready, nRetry); + JTAG_DEBUG("DTR _data %08x ready %d n_retry %d", + (unsigned) _data, ready, n_retry); int64_t then = 0; @@ -800,9 +770,9 @@ int arm11_run_instr_data_from_core(struct arm11_common *arm11, } i++; - } while (!Ready); + } while (!ready); - *data++ = Data; + *data++ = _data; } return ERROR_OK; @@ -875,51 +845,51 @@ int arm11_sc7_run(struct arm11_common *arm11, struct arm11_sc7_action *actions, { int retval; - retval = arm11_add_debug_SCAN_N(arm11, 0x07, ARM11_TAP_DEFAULT); + retval = arm11_add_debug_scan_n(arm11, 0x07, ARM11_TAP_DEFAULT); if (retval != ERROR_OK) return retval; - arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); + arm11_add_ir(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain7_fields[3]; - uint8_t nRW; - uint32_t DataOut; - uint8_t AddressOut; - uint8_t Ready; - uint32_t DataIn; - uint8_t AddressIn; + uint8_t n_rw; + uint32_t data_out; + uint8_t address_out; + uint8_t ready; + uint32_t data_in; + uint8_t address_in; - arm11_setup_field(arm11, 1, &nRW, &Ready, chain7_fields + 0); - arm11_setup_field(arm11, 32, &DataOut, &DataIn, chain7_fields + 1); - arm11_setup_field(arm11, 7, &AddressOut, &AddressIn, chain7_fields + 2); + arm11_setup_field(arm11, 1, &n_rw, &ready, chain7_fields + 0); + arm11_setup_field(arm11, 32, &data_out, &data_in, chain7_fields + 1); + arm11_setup_field(arm11, 7, &address_out, &address_in, chain7_fields + 2); for (size_t i = 0; i < count + 1; i++) { if (i < count) { - nRW = actions[i].write ? 1 : 0; - DataOut = actions[i].value; - AddressOut = actions[i].address; + n_rw = actions[i].write ? 1 : 0; + data_out = actions[i].value; + address_out = actions[i].address; } else { - nRW = 1; - DataOut = 0; - AddressOut = 0; + n_rw = 1; + data_out = 0; + address_out = 0; } /* Timeout here so we don't get stuck. */ int i_n = 0; while (1) { JTAG_DEBUG("SC7 <= c%-3d Data %08x %s", - (unsigned) AddressOut, - (unsigned) DataOut, - nRW ? "write" : "read"); + (unsigned) address_out, + (unsigned) data_out, + n_rw ? "write" : "read"); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE(chain7_fields), chain7_fields, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); - /* 'nRW' is 'Ready' on read out */ - if (Ready) + /* 'n_rw' is 'ready' on read out */ + if (ready) break; int64_t then = 0; @@ -937,17 +907,17 @@ int arm11_sc7_run(struct arm11_common *arm11, struct arm11_sc7_action *actions, i_n++; } - if (!nRW) - JTAG_DEBUG("SC7 => Data %08x", (unsigned) DataIn); + if (!n_rw) + JTAG_DEBUG("SC7 => Data %08x", (unsigned) data_in); if (i > 0) { - if (actions[i - 1].address != AddressIn) + if (actions[i - 1].address != address_in) LOG_WARNING("Scan chain 7 shifted out unexpected address"); if (!actions[i - 1].write) - actions[i - 1].value = DataIn; + actions[i - 1].value = data_in; else { - if (actions[i - 1].value != DataIn) + if (actions[i - 1].value != data_in) LOG_WARNING("Scan chain 7 shifted out unexpected data"); } } diff --git a/src/target/arm11_dbgtap.h b/src/target/arm11_dbgtap.h index be02484117..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 @@ -27,12 +16,12 @@ void arm11_setup_field(struct arm11_common *arm11, int num_bits, void *in_data, void *out_data, struct scan_field *field); -void arm11_add_IR(struct arm11_common *arm11, +void arm11_add_ir(struct arm11_common *arm11, uint8_t instr, tap_state_t state); -int arm11_add_debug_SCAN_N(struct arm11_common *arm11, +int arm11_add_debug_scan_n(struct arm11_common *arm11, uint8_t chain, tap_state_t state); -int arm11_read_DSCR(struct arm11_common *arm11); -int arm11_write_DSCR(struct arm11_common *arm11, uint32_t dscr); +int arm11_read_dscr(struct arm11_common *arm11); +int arm11_write_dscr(struct arm11_common *arm11, uint32_t dscr); int arm11_run_instr_data_prepare(struct arm11_common *arm11); int arm11_run_instr_data_finish(struct arm11_common *arm11); diff --git a/src/target/arm720t.c b/src/target/arm720t.c index e04cab2e79..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 @@ -233,16 +222,6 @@ static void arm720t_pre_restore_context(struct target *target) arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg); } -static int arm720t_verify_pointer(struct command_invocation *cmd, - struct arm720t_common *arm720t) -{ - if (arm720t->common_magic != ARM720T_COMMON_MAGIC) { - command_print(cmd, "target is not an ARM720"); - return ERROR_TARGET_INVALID; - } - return ERROR_OK; -} - static int arm720t_arch_state(struct target *target) { struct arm720t_common *arm720t = target_to_arm720(target); @@ -262,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; @@ -399,11 +378,11 @@ static void arm720t_deinit_target(struct target *target) /* FIXME remove forward decls */ static int arm720t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, + uint32_t crn, uint32_t crm, uint32_t *value); static int arm720t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, + uint32_t crn, uint32_t crm, uint32_t value); static int arm720t_init_arch_info(struct target *target, @@ -437,62 +416,13 @@ static int arm720t_target_create(struct target *target, Jim_Interp *interp) { struct arm720t_common *arm720t = calloc(1, sizeof(*arm720t)); - arm720t->arm7_9_common.arm.is_armv4 = true; + arm720t->arm7_9_common.arm.arch = ARM_ARCH_V4; return arm720t_init_arch_info(target, arm720t, target->tap); } -COMMAND_HANDLER(arm720t_handle_cp15_command) -{ - int retval; - struct target *target = get_current_target(CMD_CTX); - struct arm720t_common *arm720t = target_to_arm720(target); - - retval = arm720t_verify_pointer(CMD, arm720t); - if (retval != ERROR_OK) - return retval; - - if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; - } - - /* one or more argument, access a single register (write if second argument is given */ - if (CMD_ARGC >= 1) { - uint32_t opcode; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], opcode); - - if (CMD_ARGC == 1) { - uint32_t value; - retval = arm720t_read_cp15(target, opcode, &value); - if (retval != ERROR_OK) { - command_print(CMD, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode); - return ERROR_OK; - } - - retval = jtag_execute_queue(); - if (retval != ERROR_OK) - return retval; - - command_print(CMD, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value); - } else if (CMD_ARGC == 2) { - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); - - retval = arm720t_write_cp15(target, opcode, value); - if (retval != ERROR_OK) { - command_print(CMD, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode); - return ERROR_OK; - } - command_print(CMD, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value); - } - } - - return ERROR_OK; -} - static int arm720t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, + uint32_t crn, uint32_t crm, uint32_t *value) { if (cpnum != 15) { @@ -502,14 +432,14 @@ static int arm720t_mrc(struct target *target, int cpnum, /* read "to" r0 */ return arm720t_read_cp15(target, - ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2), + ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2), value); } static int arm720t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, + uint32_t crn, uint32_t crm, uint32_t value) { if (cpnum != 15) { @@ -519,34 +449,14 @@ static int arm720t_mcr(struct target *target, int cpnum, /* write "from" r0 */ return arm720t_write_cp15(target, - ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2), + ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2), value); } -static const struct command_registration arm720t_exec_command_handlers[] = { - { - .name = "cp15", - .handler = arm720t_handle_cp15_command, - .mode = COMMAND_EXEC, - /* prefer using less error-prone "arm mcr" or "arm mrc" */ - .help = "display/modify cp15 register using ARM opcode" - " (DEPRECATED)", - .usage = "instruction [value]", - }, - COMMAND_REGISTRATION_DONE -}; - static const struct command_registration arm720t_command_handlers[] = { { .chain = arm7_9_command_handlers, }, - { - .name = "arm720t", - .mode = COMMAND_ANY, - .help = "arm720t command group", - .usage = "", - .chain = arm720t_exec_command_handlers, - }, COMMAND_REGISTRATION_DONE }; 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 d70d27377e..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 @@ -93,19 +82,20 @@ static void arm7_9_assign_wp(struct arm7_9_common *arm7_9, struct breakpoint *br { if (!arm7_9->wp0_used) { arm7_9->wp0_used = 1; - breakpoint->set = 1; + breakpoint_hw_set(breakpoint, 0); arm7_9->wp_available--; } else if (!arm7_9->wp1_used) { arm7_9->wp1_used = 1; - breakpoint->set = 2; + breakpoint_hw_set(breakpoint, 1); arm7_9->wp_available--; - } else + } else { LOG_ERROR("BUG: no hardware comparator available"); + } - LOG_DEBUG("BPID: %" PRIu32 " (0x%08" TARGET_PRIxADDR ") using hw wp: %d", + LOG_DEBUG("BPID: %" PRIu32 " (0x%08" TARGET_PRIxADDR ") using hw wp: %u", breakpoint->unique_id, breakpoint->address, - breakpoint->set); + breakpoint->number); } /** @@ -141,13 +131,13 @@ static int arm7_9_set_software_breakpoints(struct arm7_9_common *arm7_9) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_VALUE], arm7_9->arm_bkpt); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0x0); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffffu); - embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); + embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); } else if (arm7_9->sw_breakpoints_added == 2) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_VALUE], arm7_9->arm_bkpt); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0x0); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], 0xffffffffu); - embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); + embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE); } else { LOG_ERROR("BUG: both watchpoints used, but wp_available >= 1"); @@ -194,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; } @@ -203,20 +193,20 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break uint32_t mask = (breakpoint->length == 4) ? 0x3u : 0x1u; /* reassign a hw breakpoint */ - if (breakpoint->set == 0) + if (!breakpoint->is_set) arm7_9_assign_wp(arm7_9, breakpoint); - if (breakpoint->set == 1) { + if (breakpoint->number == 0) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], breakpoint->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], 0xffffffffu); - embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); + embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); - } else if (breakpoint->set == 2) { + } else if (breakpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], breakpoint->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], 0xffffffffu); - embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); + embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE); } else { LOG_ERROR("BUG: no hardware comparator available"); @@ -226,7 +216,7 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break retval = jtag_execute_queue(); } else if (breakpoint->type == BKPT_SOFT) { /* did we already set this breakpoint? */ - if (breakpoint->set) + if (breakpoint->is_set) return ERROR_OK; if (breakpoint->length == 4) { @@ -277,7 +267,7 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break arm7_9->sw_breakpoint_count++; - breakpoint->set = 1; + breakpoint->is_set = true; } return retval; @@ -304,7 +294,7 @@ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *bre breakpoint->unique_id, breakpoint->address); - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -312,18 +302,18 @@ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *bre if (breakpoint->type == BKPT_HARD) { LOG_DEBUG("BPID: %" PRIu32 " Releasing hw wp: %d", breakpoint->unique_id, - breakpoint->set); - if (breakpoint->set == 1) { + breakpoint->is_set); + if (breakpoint->number == 0) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); arm7_9->wp0_used = 0; arm7_9->wp_available++; - } else if (breakpoint->set == 2) { + } else if (breakpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); arm7_9->wp1_used = 0; arm7_9->wp_available++; } retval = jtag_execute_queue(); - breakpoint->set = 0; + breakpoint->is_set = false; } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { @@ -368,7 +358,7 @@ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *bre EICE_W1_CONTROL_VALUE], 0); } - breakpoint->set = 0; + breakpoint->is_set = false; } return retval; @@ -461,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; } @@ -479,38 +470,38 @@ 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], - 0xff & ~EICE_W_CTRL_nOPC & ~rw_mask); + 0xff & ~EICE_W_CTRL_NOPC & ~rw_mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], - EICE_W_CTRL_ENABLE | EICE_W_CTRL_nOPC | (watchpoint->rw & 1)); + EICE_W_CTRL_ENABLE | EICE_W_CTRL_NOPC | (watchpoint->rw & 1)); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - watchpoint->set = 1; + watchpoint_set(watchpoint, 1); arm7_9->wp0_used = 2; } else if (!arm7_9->wp1_used) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], 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], - 0xff & ~EICE_W_CTRL_nOPC & ~rw_mask); + 0xff & ~EICE_W_CTRL_NOPC & ~rw_mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], - EICE_W_CTRL_ENABLE | EICE_W_CTRL_nOPC | (watchpoint->rw & 1)); + EICE_W_CTRL_ENABLE | EICE_W_CTRL_NOPC | (watchpoint->rw & 1)); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - watchpoint->set = 2; + watchpoint_set(watchpoint, 2); arm7_9->wp1_used = 2; } else { LOG_ERROR("BUG: no hardware comparator available"); @@ -534,29 +525,29 @@ 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; } - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } - if (watchpoint->set == 1) { + if (watchpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; arm7_9->wp0_used = 0; - } else if (watchpoint->set == 2) { + } else if (watchpoint->number == 2) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; arm7_9->wp1_used = 0; } - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -597,7 +588,7 @@ int arm7_9_remove_watchpoint(struct target *target, struct watchpoint *watchpoin int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); - if (watchpoint->set) { + if (watchpoint->is_set) { retval = arm7_9_unset_watchpoint(target, watchpoint); if (retval != ERROR_OK) return retval; @@ -933,7 +924,7 @@ int arm7_9_assert_reset(struct target *target) embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0x3); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); - embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); + embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); } } @@ -1212,7 +1203,7 @@ int arm7_9_halt(struct target *target) embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], - ~EICE_W_CTRL_nOPC & 0xff); + ~EICE_W_CTRL_NOPC & 0xff); } target->debug_reason = DBG_REASON_DBGRQ; @@ -1269,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; } @@ -1391,11 +1382,16 @@ static int arm7_9_full_context(struct target *target) int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; + struct { + uint32_t value; + uint8_t *reg_p; + } read_cache[6 * (16 + 1)]; + int read_cache_idx = 0; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1433,10 +1429,12 @@ static int arm7_9_full_context(struct target *target) for (j = 0; j < 15; j++) { if (!ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j).valid) { - reg_p[j] = (uint32_t *)ARMV4_5_CORE_REG_MODE( + read_cache[read_cache_idx].reg_p = ARMV4_5_CORE_REG_MODE( arm->core_cache, armv4_5_number_to_mode(i), j).value; + reg_p[j] = &read_cache[read_cache_idx].value; + read_cache_idx++; mask |= 1 << j; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), @@ -1454,9 +1452,10 @@ static int arm7_9_full_context(struct target *target) /* check if the PSR has to be read */ if (!ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).valid) { - arm7_9->read_xpsr(target, - (uint32_t *)ARMV4_5_CORE_REG_MODE(arm->core_cache, - armv4_5_number_to_mode(i), 16).value, 1); + read_cache[read_cache_idx].reg_p = ARMV4_5_CORE_REG_MODE(arm->core_cache, + armv4_5_number_to_mode(i), 16).value; + arm7_9->read_xpsr(target, &read_cache[read_cache_idx].value, 1); + read_cache_idx++; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).valid = true; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), @@ -1472,6 +1471,14 @@ static int arm7_9_full_context(struct target *target) retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; + /* + * FIXME: regs in cache should be tagged as 'valid' only now, + * not before the jtag_execute_queue() + */ + while (read_cache_idx) { + read_cache_idx--; + buf_set_u32(read_cache[read_cache_idx].reg_p, 0, 32, read_cache[read_cache_idx].value); + } return ERROR_OK; } @@ -1500,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; } @@ -1547,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) { @@ -1570,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 " @@ -1668,7 +1673,7 @@ static void arm7_9_enable_watchpoints(struct target *target) struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) arm7_9_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } @@ -1705,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; } @@ -1724,7 +1729,7 @@ int arm7_9_resume(struct target *target, struct breakpoint *breakpoint; breakpoint = breakpoint_find(target, buf_get_u32(arm->pc->value, 0, 32)); - if (breakpoint != NULL) { + if (breakpoint) { LOG_DEBUG("unset breakpoint at 0x%8.8" TARGET_PRIxADDR " (id: %" PRIu32, breakpoint->address, breakpoint->unique_id); @@ -1857,14 +1862,14 @@ void arm7_9_enable_eice_step(struct target *target, uint32_t next_pc) embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], - ~(EICE_W_CTRL_RANGE | EICE_W_CTRL_nOPC) & 0xff); + ~(EICE_W_CTRL_RANGE | EICE_W_CTRL_NOPC) & 0xff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], current_pc); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], 0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], - ~EICE_W_CTRL_nOPC & 0xff); + ~EICE_W_CTRL_NOPC & 0xff); } else { embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); @@ -1876,7 +1881,7 @@ void arm7_9_enable_eice_step(struct target *target, uint32_t next_pc) embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], - ~EICE_W_CTRL_nOPC & 0xff); + ~EICE_W_CTRL_NOPC & 0xff); } } @@ -1903,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; } @@ -1916,7 +1921,7 @@ int arm7_9_step(struct target *target, int current, target_addr_t address, int h /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) breakpoint = breakpoint_find(target, current_pc); - if (breakpoint != NULL) { + if (breakpoint) { retval = arm7_9_unset_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; @@ -2114,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; } @@ -2287,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; } @@ -2514,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; @@ -2659,7 +2664,7 @@ int arm7_9_examine(struct target *target) struct reg_cache *t, **cache_p; t = embeddedice_build_reg_cache(target, arm7_9); - if (t == NULL) + if (!t) return ERROR_FAIL; cache_p = register_get_last_cache_p(&target->reg_cache); 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 01685ab6a4..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 @@ -115,11 +104,9 @@ static inline int arm7tdmi_clock_out_inner(struct arm_jtag *jtag_info, uint32_t /* put an instruction in the ARM7TDMI pipeline or write the data bus, * and optionally read data - * - * FIXME remove the unused "deprecated" parameter */ static inline int arm7tdmi_clock_out(struct arm_jtag *jtag_info, - uint32_t out, uint32_t *deprecated, int breakpoint) + uint32_t out, int breakpoint) { int retval; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); @@ -246,35 +233,35 @@ static void arm7tdmi_change_to_arm(struct target *target, * to allow common handling of ARM and THUMB debugging */ /* fetch STR r0, [r0] */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, STR r0, [r0] in Execute (2) */ arm7tdmi_clock_data_in(jtag_info, r0); /* MOV r0, r15 fetched, STR in Decode */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, STR r0, [r0] in Execute (2) */ arm7tdmi_clock_data_in(jtag_info, pc); /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, data for LDR r0, [PC, #0] */ - arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0); + arm7tdmi_clock_out(jtag_info, 0x0, 0); /* nothing fetched, data from previous cycle is written to register */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* fetch BX */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0); /* NOP fetched, BX in Decode, MOV in Execute */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* NOP fetched, BX in Execute (1) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); jtag_execute_queue(); @@ -301,12 +288,12 @@ static void arm7tdmi_read_core_regs(struct target *target, /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0); /* fetch NOP, STM in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) @@ -329,12 +316,12 @@ static void arm7tdmi_read_core_regs_target_buffer(struct target *target, /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0); /* fetch NOP, STM in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); for (i = 0; i <= 15; i++) { /* nothing fetched, STM still in EXECUTE (1 + i cycle), read databus */ @@ -360,14 +347,14 @@ static void arm7tdmi_read_xpsr(struct target *target, uint32_t *xpsr, int spsr) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* MRS r0, cpsr */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0); /* STR r0, [r15] */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0); /* fetch NOP, STR in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, STR in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, STR still in EXECUTE (2nd cycle) */ arm7tdmi_clock_data_in(jtag_info, xpsr); } @@ -380,25 +367,25 @@ static void arm7tdmi_write_xpsr(struct target *target, uint32_t xpsr, int spsr) LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr); /* MSR1 fetched */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0); /* MSR2 fetched, MSR1 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0); /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0); /* nothing fetched, MSR1 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0); /* nothing fetched, MSR2 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, MSR3 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* NOP fetched, MSR4 in EXECUTE (1) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, MSR4 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); } static void arm7tdmi_write_xpsr_im8(struct target *target, @@ -410,13 +397,13 @@ static void arm7tdmi_write_xpsr_im8(struct target *target, LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); /* MSR fetched */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0); /* NOP fetched, MSR in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* NOP fetched, MSR in EXECUTE (1) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, MSR in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); } static void arm7tdmi_write_core_regs(struct target *target, @@ -429,7 +416,7 @@ static void arm7tdmi_write_core_regs(struct target *target, /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0); /* fetch NOP, LDM in DECODE stage */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); @@ -450,9 +437,9 @@ static void arm7tdmi_load_word_regs(struct target *target, uint32_t mask) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load-multiple into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0); } static void arm7tdmi_load_hword_reg(struct target *target, int num) @@ -461,9 +448,9 @@ static void arm7tdmi_load_hword_reg(struct target *target, int num) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load half-word into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0); } static void arm7tdmi_load_byte_reg(struct target *target, int num) @@ -472,9 +459,9 @@ static void arm7tdmi_load_byte_reg(struct target *target, int num) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load byte into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0); } static void arm7tdmi_store_word_regs(struct target *target, uint32_t mask) @@ -483,9 +470,9 @@ static void arm7tdmi_store_word_regs(struct target *target, uint32_t mask) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store-multiple into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0); } static void arm7tdmi_store_hword_reg(struct target *target, int num) @@ -494,9 +481,9 @@ static void arm7tdmi_store_hword_reg(struct target *target, int num) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store half-word into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0); } static void arm7tdmi_store_byte_reg(struct target *target, int num) @@ -505,9 +492,9 @@ static void arm7tdmi_store_byte_reg(struct target *target, int num) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store byte into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0); } static void arm7tdmi_write_pc(struct target *target, uint32_t pc) @@ -518,7 +505,7 @@ static void arm7tdmi_write_pc(struct target *target, uint32_t pc) /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0); /* fetch NOP, LDM in DECODE stage */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ @@ -540,7 +527,7 @@ static void arm7tdmi_branch_resume(struct target *target) struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_B(0xfffffa, 0), 0); } @@ -556,53 +543,52 @@ static void arm7tdmi_branch_resume_thumb(struct target *target) /* LDMIA r0, [r0] at debug speed * register values will start to appear on 4th DCLK */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0); /* fetch NOP, LDM in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ - arm7tdmi_clock_out(jtag_info, - buf_get_u32(arm->pc->value, 0, 32) | 1, NULL, 0); + arm7tdmi_clock_out(jtag_info, buf_get_u32(arm->pc->value, 0, 32) | 1, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* Branch and eXchange */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0); embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* target is now in Thumb state */ embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* target is now in Thumb state */ embeddedice_read_reg(dbg_stat); /* load r0 value */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0); /* fetch NOP, LDR in Decode */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* fetch NOP, LDR in Execute */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ - arm7tdmi_clock_out(jtag_info, buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32), NULL, 0); + arm7tdmi_clock_out(jtag_info, buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32), 0); /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); embeddedice_read_reg(dbg_stat); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), 0); } static void arm7tdmi_build_reg_cache(struct target *target) @@ -689,7 +675,7 @@ static int arm7tdmi_target_create(struct target *target, Jim_Interp *interp) arm7_9 = calloc(1, sizeof(struct arm7_9_common)); arm7tdmi_init_arch_info(target, arm7_9, target->tap); - arm7_9->arm.is_armv4 = true; + arm7_9->arm.arch = ARM_ARCH_V4; return ERROR_OK; } 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 c96975a77c..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 @@ -245,8 +234,8 @@ static int arm920t_read_cp15_interpreted(struct target *target, uint32_t cp15_opcode, uint32_t address, uint32_t *value) { struct arm *arm = target_to_arm(target); - uint32_t *regs_p[1]; - uint32_t regs[2]; + uint32_t *regs_p[16]; + uint32_t regs[16]; uint32_t cp15c15 = 0x0; struct reg *r = arm->core_cache->reg_list; @@ -295,7 +284,7 @@ int arm920t_write_cp15_interpreted(struct target *target, { uint32_t cp15c15 = 0x0; struct arm *arm = target_to_arm(target); - uint32_t regs[2]; + uint32_t regs[16]; struct reg *r = arm->core_cache->reg_list; /* load value, address into R0, R1 */ @@ -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; @@ -799,11 +788,11 @@ int arm920t_soft_reset_halt(struct target *target) /* FIXME remove forward decls */ static int arm920t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, + uint32_t crn, uint32_t crm, uint32_t *value); static int arm920t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, + uint32_t crn, uint32_t crm, uint32_t value); static int arm920t_init_arch_info(struct target *target, @@ -873,7 +862,7 @@ COMMAND_HANDLER(arm920t_handle_read_cache_command) uint32_t cp15_ctrl, cp15_ctrl_saved; uint32_t regs[16]; uint32_t *regs_p[16]; - uint32_t C15_C_D_Ind, C15_C_I_Ind; + uint32_t c15_c_d_ind, c15_c_i_ind; int i; FILE *output; int segment, index_t; @@ -887,7 +876,7 @@ COMMAND_HANDLER(arm920t_handle_read_cache_command) return ERROR_COMMAND_SYNTAX_ERROR; output = fopen(CMD_ARGV[0], "w"); - if (output == NULL) { + if (!output) { LOG_DEBUG("error opening cache content file"); return ERROR_OK; } @@ -933,7 +922,7 @@ COMMAND_HANDLER(arm920t_handle_read_cache_command) /* read current victim */ arm920t_read_cp15_physical(target, - CP15PHYS_DCACHE_IDX, &C15_C_D_Ind); + CP15PHYS_DCACHE_IDX, &c15_c_d_ind); /* clear interpret mode */ cp15c15 &= ~0x1; @@ -992,7 +981,7 @@ COMMAND_HANDLER(arm920t_handle_read_cache_command) } /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); + regs[0] = 0x0 | (segment << 5) | (c15_c_d_ind << 26); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ @@ -1034,7 +1023,7 @@ COMMAND_HANDLER(arm920t_handle_read_cache_command) /* read current victim */ arm920t_read_cp15_physical(target, CP15PHYS_ICACHE_IDX, - &C15_C_I_Ind); + &c15_c_i_ind); /* clear interpret mode */ cp15c15 &= ~0x1; @@ -1092,7 +1081,7 @@ COMMAND_HANDLER(arm920t_handle_read_cache_command) } /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); + regs[0] = 0x0 | (segment << 5) | (c15_c_d_ind << 26); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ @@ -1156,7 +1145,7 @@ COMMAND_HANDLER(arm920t_handle_read_mmu_command) uint32_t *regs_p[16]; int i; FILE *output; - uint32_t Dlockdown, Ilockdown; + uint32_t d_lockdown, i_lockdown; struct arm920t_tlb_entry d_tlb[64], i_tlb[64]; int victim; struct reg *r; @@ -1169,7 +1158,7 @@ COMMAND_HANDLER(arm920t_handle_read_mmu_command) return ERROR_COMMAND_SYNTAX_ERROR; output = fopen(CMD_ARGV[0], "w"); - if (output == NULL) { + if (!output) { LOG_DEBUG("error opening mmu content file"); return ERROR_OK; } @@ -1213,13 +1202,13 @@ COMMAND_HANDLER(arm920t_handle_read_mmu_command) retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - Dlockdown = regs[1]; + d_lockdown = regs[1]; for (victim = 0; victim < 64; victim += 8) { /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + regs[1] = (d_lockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ @@ -1256,7 +1245,7 @@ COMMAND_HANDLER(arm920t_handle_read_mmu_command) /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + regs[1] = (d_lockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ @@ -1292,7 +1281,7 @@ COMMAND_HANDLER(arm920t_handle_read_mmu_command) } /* restore D TLB lockdown */ - regs[1] = Dlockdown; + regs[1] = d_lockdown; arm9tdmi_write_core_regs(target, 0x2, regs); /* Write D TLB lockdown */ @@ -1319,13 +1308,13 @@ COMMAND_HANDLER(arm920t_handle_read_mmu_command) retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - Ilockdown = regs[1]; + i_lockdown = regs[1]; for (victim = 0; victim < 64; victim += 8) { /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Ilockdown & 0xfc000000) | (victim << 20); + regs[1] = (i_lockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ @@ -1362,7 +1351,7 @@ COMMAND_HANDLER(arm920t_handle_read_mmu_command) /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + regs[1] = (d_lockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ @@ -1398,7 +1387,7 @@ COMMAND_HANDLER(arm920t_handle_read_mmu_command) } /* restore I TLB lockdown */ - regs[1] = Ilockdown; + regs[1] = i_lockdown; arm9tdmi_write_core_regs(target, 0x2, regs); /* Write I TLB lockdown */ @@ -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. @@ -1511,80 +1500,6 @@ COMMAND_HANDLER(arm920t_handle_cp15_command) return ERROR_OK; } -COMMAND_HANDLER(arm920t_handle_cp15i_command) -{ - int retval; - struct target *target = get_current_target(CMD_CTX); - struct arm920t_common *arm920t = target_to_arm920(target); - - retval = arm920t_verify_pointer(CMD, arm920t); - if (retval != ERROR_OK) - return retval; - - - if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for " - "\"%s\" command", CMD_NAME); - return ERROR_OK; - } - - /* one argument, read a register. - * two arguments, write it. - */ - if (CMD_ARGC >= 1) { - uint32_t opcode; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], opcode); - - if (CMD_ARGC == 1) { - uint32_t value; - retval = arm920t_read_cp15_interpreted(target, - opcode, 0x0, &value); - if (retval != ERROR_OK) { - command_print(CMD, - "couldn't execute %8.8" PRIx32, - opcode); - /* REVISIT why lie? "return retval"? */ - return ERROR_OK; - } - - command_print(CMD, "%8.8" PRIx32 ": %8.8" PRIx32, - opcode, value); - } else if (CMD_ARGC == 2) { - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); - retval = arm920t_write_cp15_interpreted(target, - opcode, value, 0); - if (retval != ERROR_OK) { - command_print(CMD, - "couldn't execute %8.8" PRIx32, - opcode); - /* REVISIT why lie? "return retval"? */ - return ERROR_OK; - } - command_print(CMD, "%8.8" PRIx32 ": %8.8" PRIx32, - opcode, value); - } else if (CMD_ARGC == 3) { - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); - uint32_t address; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address); - retval = arm920t_write_cp15_interpreted(target, - opcode, value, address); - if (retval != ERROR_OK) { - command_print(CMD, - "couldn't execute %8.8" PRIx32, opcode); - /* REVISIT why lie? "return retval"? */ - return ERROR_OK; - } - command_print(CMD, "%8.8" PRIx32 ": %8.8" PRIx32 - " %8.8" PRIx32, opcode, value, address); - } - } else - return ERROR_COMMAND_SYNTAX_ERROR; - - return ERROR_OK; -} - COMMAND_HANDLER(arm920t_handle_cache_info_command) { int retval; @@ -1602,7 +1517,7 @@ COMMAND_HANDLER(arm920t_handle_cache_info_command) static int arm920t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, + uint32_t crn, uint32_t crm, uint32_t *value) { if (cpnum != 15) { @@ -1612,13 +1527,13 @@ static int arm920t_mrc(struct target *target, int cpnum, /* read "to" r0 */ return arm920t_read_cp15_interpreted(target, - ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2), + ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2), 0, value); } static int arm920t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, + uint32_t crn, uint32_t crm, uint32_t value) { if (cpnum != 15) { @@ -1628,7 +1543,7 @@ static int arm920t_mcr(struct target *target, int cpnum, /* write "from" r0 */ return arm920t_write_cp15_interpreted(target, - ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2), + ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2), 0, value); } @@ -1640,15 +1555,6 @@ static const struct command_registration arm920t_exec_command_handlers[] = { .help = "display/modify cp15 register", .usage = "regnum [value]", }, - { - .name = "cp15i", - .handler = arm920t_handle_cp15i_command, - .mode = COMMAND_EXEC, - /* prefer using less error-prone "arm mcr" or "arm mrc" */ - .help = "display/modify cp15 register using ARM opcode" - " (DEPRECATED)", - .usage = "instruction [value [address]]", - }, { .name = "cache_info", .handler = arm920t_handle_cache_info_command, 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 95a4f7ca06..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 @@ -46,15 +35,15 @@ #define _DEBUG_INSTRUCTION_EXECUTION_ #endif -#define ARM926EJS_CP15_ADDR(opcode_1, opcode_2, CRn, CRm) ((opcode_1 << 11) | (opcode_2 << 8) | (CRn << 4) | (CRm << 0)) +#define ARM926EJS_CP15_ADDR(opcode_1, opcode_2, crn, crm) ((opcode_1 << 11) | (opcode_2 << 8) | (crn << 4) | (crm << 0)) static int arm926ejs_cp15_read(struct target *target, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, uint32_t *value) + uint32_t crn, uint32_t crm, uint32_t *value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; - uint32_t address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); + uint32_t address = ARM926EJS_CP15_ADDR(op1, op2, crn, crm); struct scan_field fields[4]; uint8_t address_buf[2] = {0, 0}; uint8_t nr_w_buf = 0; @@ -123,22 +112,22 @@ static int arm926ejs_cp15_read(struct target *target, uint32_t op1, uint32_t op2 } static int arm926ejs_mrc(struct target *target, int cpnum, uint32_t op1, - uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value) + uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } - return arm926ejs_cp15_read(target, op1, op2, CRn, CRm, value); + return arm926ejs_cp15_read(target, op1, op2, crn, crm, value); } static int arm926ejs_cp15_write(struct target *target, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, uint32_t value) + uint32_t crn, uint32_t crm, uint32_t value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; - uint32_t address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); + uint32_t address = ARM926EJS_CP15_ADDR(op1, op2, crn, crm); struct scan_field fields[4]; uint8_t value_buf[4]; uint8_t address_buf[2] = {0, 0}; @@ -206,13 +195,13 @@ static int arm926ejs_cp15_write(struct target *target, uint32_t op1, uint32_t op } static int arm926ejs_mcr(struct target *target, int cpnum, uint32_t op1, - uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) + uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } - return arm926ejs_cp15_write(target, op1, op2, CRn, CRm, value); + return arm926ejs_cp15_write(target, op1, op2, crn, crm, value); } static int arm926ejs_examine_debug_reason(struct target *target) @@ -723,7 +712,7 @@ static int arm926ejs_target_create(struct target *target, Jim_Interp *interp) return arm926ejs_init_arch_info(target, arm926ejs, target->tap); } -void arm926ejs_deinit_target(struct target *target) +static void arm926ejs_deinit_target(struct target *target) { struct arm *arm = target_to_arm(target); struct arm926ejs_common *arm926ejs = target_to_arm926(target); @@ -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 d4fd0cb6eb..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,16 +11,17 @@ #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); + uint32_t crn, uint32_t crm, uint32_t *value); int (*write_cp15)(struct target *target, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, uint32_t value); + uint32_t crn, uint32_t crm, uint32_t value); uint32_t cp15_control_reg; uint32_t d_fsr; uint32_t i_fsr; diff --git a/src/target/arm946e.c b/src/target/arm946e.c index 8754c861ce..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 @@ -51,11 +40,11 @@ */ static uint8_t arm946e_preserve_cache; -int arm946e_post_debug_entry(struct target *target); -void arm946e_pre_restore_context(struct target *target); +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); @@ -250,7 +239,7 @@ static uint32_t arm946e_cp15_get_csize(struct target *target, int idsel) return csize ? 1 << (12 + (csize-3)) : 0; } -uint32_t arm946e_invalidate_whole_dcache(struct target *target) +static uint32_t arm946e_invalidate_whole_dcache(struct target *target) { uint32_t csize = arm946e_cp15_get_csize(target, GET_DCACHE_SIZE); if (csize == 0) @@ -306,7 +295,7 @@ uint32_t arm946e_invalidate_whole_dcache(struct target *target) return ERROR_OK; } -uint32_t arm946e_invalidate_whole_icache(struct target *target) +static uint32_t arm946e_invalidate_whole_icache(struct target *target) { /* Check cache presence before flushing - avoid undefined behavior */ uint32_t csize = arm946e_cp15_get_csize(target, GET_ICACHE_SIZE); @@ -327,7 +316,7 @@ uint32_t arm946e_invalidate_whole_icache(struct target *target) return ERROR_OK; } -int arm946e_post_debug_entry(struct target *target) +static int arm946e_post_debug_entry(struct target *target) { uint32_t ctr_reg = 0x0; uint32_t retval = ERROR_OK; @@ -368,7 +357,7 @@ int arm946e_post_debug_entry(struct target *target) return ERROR_OK; } -void arm946e_pre_restore_context(struct target *target) +static void arm946e_pre_restore_context(struct target *target) { uint32_t ctr_reg = 0x0; uint32_t retval; @@ -393,7 +382,7 @@ void arm946e_pre_restore_context(struct target *target) } /* if preserve_cache */ } -uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address, +static uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address, uint32_t size, uint32_t count) { uint32_t cur_addr = 0x0; @@ -458,7 +447,7 @@ uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address, return ERROR_OK; } -uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address, +static uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address, uint32_t size, uint32_t count) { uint32_t cur_addr = 0x0; @@ -509,7 +498,7 @@ uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address, } /** Writes a buffer, in the specified word size, with current MMU settings. */ -int arm946e_write_memory(struct target *target, target_addr_t address, +static int arm946e_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; @@ -557,7 +546,7 @@ int arm946e_write_memory(struct target *target, target_addr_t address, } -int arm946e_read_memory(struct target *target, target_addr_t address, +static int arm946e_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; @@ -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 4810c2b162..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) @@ -781,7 +770,7 @@ static int arm9tdmi_target_create(struct target *target, Jim_Interp *interp) struct arm7_9_common *arm7_9 = calloc(1, sizeof(struct arm7_9_common)); arm9tdmi_init_arch_info(target, arm7_9, target->tap); - arm7_9->arm.is_armv4 = true; + arm7_9->arm.arch = ARM_ARCH_V4; return ERROR_OK; } 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 a09e2698a7..9129acecf9 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 * @@ -13,18 +15,7 @@ * Copyright (C) 2013 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/>. * + * Copyright (C) 2019-2021, Ampere Computing LLC * ***************************************************************************/ /** @@ -32,7 +23,7 @@ * This file implements support for the ARM Debug Interface version 5 (ADIv5) * debugging architecture. Compared with previous versions, this includes * a low pin-count Serial Wire Debug (SWD) alternative to JTAG for message - * transport, and focusses on memory mapped resources as defined by the + * transport, and focuses on memory mapped resources as defined by the * CoreSight architecture. * * A key concept in ADIv5 is the Debug Access Port, or DAP. A DAP has two @@ -59,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 @@ -73,8 +65,10 @@ #include "jtag/interface.h" #include "arm.h" #include "arm_adi_v5.h" +#include "arm_coresight.h" #include "jtag/swd.h" #include "transport/transport.h" +#include <helper/align.h> #include <helper/jep106.h> #include <helper/time_support.h> #include <helper/list.h> @@ -86,7 +80,7 @@ uint32_t tar_block_size(uint32_t address) Return the largest block starting at address that does not cross a tar block size alignment boundary */ -static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, uint32_t address) +static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, target_addr_t address) { return tar_autoincr_block - ((tar_autoincr_block - 1) & address); } @@ -103,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; @@ -113,11 +107,16 @@ static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw) return ERROR_OK; } -static int mem_ap_setup_tar(struct adiv5_ap *ap, uint32_t tar) +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, tar); + 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_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; return retval; @@ -128,9 +127,15 @@ static int mem_ap_setup_tar(struct adiv5_ap *ap, uint32_t tar) return ERROR_OK; } -static int mem_ap_read_tar(struct adiv5_ap *ap, uint32_t *tar) +static int mem_ap_read_tar(struct adiv5_ap *ap, target_addr_t *tar) { - int retval = dap_queue_ap_read(ap, MEM_AP_REG_TAR, tar); + uint32_t lower; + uint32_t upper = 0; + + 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(ap->dap), &upper); + if (retval != ERROR_OK) { ap->tar_valid = false; return retval; @@ -142,6 +147,8 @@ static int mem_ap_read_tar(struct adiv5_ap *ap, uint32_t *tar) return retval; } + *tar = (((target_addr_t)upper) << 32) | (target_addr_t)lower; + ap->tar_value = *tar; ap->tar_valid = true; return ERROR_OK; @@ -158,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; } @@ -198,7 +211,7 @@ static void mem_ap_update_tar_cache(struct adiv5_ap *ap) * * @return ERROR_OK if the transaction was properly queued, else a fault code. */ -static int mem_ap_setup_transfer(struct adiv5_ap *ap, uint32_t csw, uint32_t tar) +static int mem_ap_setup_transfer(struct adiv5_ap *ap, uint32_t csw, target_addr_t tar) { int retval; retval = mem_ap_setup_csw(ap, csw); @@ -221,7 +234,7 @@ static int mem_ap_setup_transfer(struct adiv5_ap *ap, uint32_t csw, uint32_t tar * * @return ERROR_OK for success. Otherwise a fault code. */ -int mem_ap_read_u32(struct adiv5_ap *ap, uint32_t address, +int mem_ap_read_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t *value) { int retval; @@ -231,11 +244,11 @@ int mem_ap_read_u32(struct adiv5_ap *ap, uint32_t address, */ retval = mem_ap_setup_transfer(ap, CSW_32BIT | (ap->csw_value & CSW_ADDRINC_MASK), - address & 0xFFFFFFF0); + address & 0xFFFFFFFFFFFFFFF0ull); 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); } /** @@ -250,7 +263,7 @@ int mem_ap_read_u32(struct adiv5_ap *ap, uint32_t address, * @return ERROR_OK for success; *value holds the result. * Otherwise a fault code. */ -int mem_ap_read_atomic_u32(struct adiv5_ap *ap, uint32_t address, +int mem_ap_read_atomic_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t *value) { int retval; @@ -273,7 +286,7 @@ int mem_ap_read_atomic_u32(struct adiv5_ap *ap, uint32_t address, * * @return ERROR_OK for success. Otherwise a fault code. */ -int mem_ap_write_u32(struct adiv5_ap *ap, uint32_t address, +int mem_ap_write_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t value) { int retval; @@ -283,11 +296,11 @@ int mem_ap_write_u32(struct adiv5_ap *ap, uint32_t address, */ retval = mem_ap_setup_transfer(ap, CSW_32BIT | (ap->csw_value & CSW_ADDRINC_MASK), - address & 0xFFFFFFF0); + address & 0xFFFFFFFFFFFFFFF0ull); 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); } @@ -302,7 +315,7 @@ int mem_ap_write_u32(struct adiv5_ap *ap, uint32_t address, * * @return ERROR_OK for success; the data was written. Otherwise a fault code. */ -int mem_ap_write_atomic_u32(struct adiv5_ap *ap, uint32_t address, +int mem_ap_write_atomic_u32(struct adiv5_ap *ap, target_addr_t address, uint32_t value) { int retval = mem_ap_write_u32(ap, address, value); @@ -313,12 +326,145 @@ int mem_ap_write_atomic_u32(struct adiv5_ap *ap, uint32_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 @@ -326,13 +472,10 @@ int mem_ap_write_atomic_u32(struct adiv5_ap *ap, uint32_t address, * @return ERROR_OK on success, otherwise an error code. */ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t size, uint32_t count, - uint32_t address, bool addrinc) + target_addr_t address, bool addrinc) { 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; - uint32_t addr_xor; int retval = ERROR_OK; /* TI BE-32 Quirks mode: @@ -347,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; } @@ -433,9 +578,9 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz retval = dap_run(dap); if (retval != ERROR_OK) { - uint32_t tar; + target_addr_t tar; if (mem_ap_read_tar(ap, &tar) == ERROR_OK) - LOG_ERROR("Failed to write memory at 0x%08"PRIx32, tar); + LOG_ERROR("Failed to write memory at " TARGET_ADDR_FMT, tar); else LOG_ERROR("Failed to write memory and, additionally, failed to find out where"); } @@ -448,21 +593,20 @@ 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 address Address to be read; it must be readable by the currently selected MEM-AP. + * @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 * should normally be true, except when reading from e.g. a FIFO. * @return ERROR_OK on success, otherwise an error code. */ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint32_t count, - uint32_t adr, bool addrinc) + target_addr_t adr, bool addrinc) { 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; - uint32_t address = adr; + target_addr_t address = adr; int retval = ERROR_OK; /* TI BE-32 Quirks mode: @@ -470,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; @@ -487,10 +627,11 @@ 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 == NULL) { + if (!read_buf) { LOG_ERROR("Failed to allocate read buffer"); return ERROR_FAIL; } @@ -499,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) @@ -537,11 +672,13 @@ 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) { - uint32_t tar; + 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) */ - LOG_ERROR("Failed to read memory at 0x%08"PRIx32, tar); + LOG_ERROR("Failed to read memory at " TARGET_ADDR_FMT, tar); if (nbytes > tar - address) nbytes = tar - address; } else { @@ -550,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++; @@ -594,25 +720,25 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint } int mem_ap_read_buf(struct adiv5_ap *ap, - uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address) + uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address) { return mem_ap_read(ap, buffer, size, count, address, true); } int mem_ap_write_buf(struct adiv5_ap *ap, - const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address) + const uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address) { return mem_ap_write(ap, buffer, size, count, address, true); } int mem_ap_read_buf_noincr(struct adiv5_ap *ap, - uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address) + uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address) { return mem_ap_read(ap, buffer, size, count, address, false); } int mem_ap_write_buf_noincr(struct adiv5_ap *ap, - const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address) + const uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address) { return mem_ap_write(ap, buffer, size, count, address, false); } @@ -629,11 +755,15 @@ 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; - for (i = 0; i <= 255; i++) { + for (i = 0; i <= DP_APSEL_MAX; i++) { /* force csw and tar write on the next mem-ap access */ dap->ap[i].tar_valid = false; dap->ap[i].csw_value = 0; @@ -652,35 +782,22 @@ int dap_dp_init(struct adiv5_dap *dap) LOG_DEBUG("%s", adiv5_dap_name(dap)); + dap->do_reconnect = false; dap_invalidate_cache(dap); /* * Early initialize dap->dp_ctrl_stat. - * In jtag mode only, if the following atomic reads fail and set the - * sticky error, it will trigger the clearing of the sticky. Without this - * initialization system and debug power would be disabled while clearing - * the sticky error bit. + * In jtag mode only, if the following queue run (in dap_dp_poll_register) + * fails and sets the sticky error, it will trigger the clearing + * of the sticky. Without this initialization system and debug power + * would be disabled while clearing the sticky error bit. */ dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; - for (size_t i = 0; i < 30; i++) { - /* DP initialization */ - - retval = dap_dp_read_atomic(dap, DP_CTRL_STAT, NULL); - if (retval == ERROR_OK) - break; - } - /* * This write operation clears the sticky error bit in jtag mode only and * is ignored in swd mode. It also powers-up system and debug domains in * both jtag and swd modes, if not done before. - * Actually we do not need to clear the sticky error here because it has - * been already cleared (if it was set) in the previous atomic read. This - * write could be removed, but this initial part of dap_dp_init() is the - * result of years of fine tuning and there are strong concerns about any - * unnecessary code change. It doesn't harm, so let's keep it here and - * preserve the historical sequence of read/write operations! */ retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat | SSTICKYERR); if (retval != ERROR_OK) @@ -731,6 +848,35 @@ int dap_dp_init(struct adiv5_dap *dap) return retval; } +/** + * Initialize a DAP or do reconnect if DAP is not accessible. + * + * @param dap The DAP being initialized. + */ +int dap_dp_init_or_reconnect(struct adiv5_dap *dap) +{ + LOG_DEBUG("%s", adiv5_dap_name(dap)); + + /* + * Early initialize dap->dp_ctrl_stat. + * In jtag mode only, if the following atomic reads fail and set the + * sticky error, it will trigger the clearing of the sticky. Without this + * initialization system and debug power would be disabled while clearing + * the sticky error bit. + */ + dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; + + dap->do_reconnect = false; + + dap_dp_read_atomic(dap, DP_CTRL_STAT, NULL); + if (dap->do_reconnect) { + /* dap connect calls dap_dp_init() after transport dependent initialization */ + return dap->ops->connect(dap); + } else { + return dap_dp_init(dap); + } +} + /** * Initialize a DAP. This sets up the power domains, prepares the DP * for further use, and arranges to use AP #0 for all AP operations @@ -741,40 +887,40 @@ int dap_dp_init(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; - 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); + /* 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(dap), &cfg); if (retval != ERROR_OK) return retval; - retval = dap_queue_ap_read(ap, MEM_AP_REG_CSW, &csw); + retval = dap_run(dap); if (retval != ERROR_OK) return retval; - retval = dap_queue_ap_read(ap, MEM_AP_REG_CFG, &cfg); - if (retval != ERROR_OK) - return retval; + ap->cfg_reg = cfg; + ap->tar_valid = false; + ap->csw_value = 0; /* force csw and tar write */ - 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. @@ -785,7 +931,7 @@ int mem_ap_init(struct adiv5_ap *ap) ap->unaligned_access_bad = dap->ti_be_32_quirks; LOG_DEBUG("MEM_AP CFG: large data %d, long address %d, big-endian %d", - !!(cfg & 0x04), !!(cfg & 0x02), !!(cfg & 0x01)); + !!(cfg & MEM_AP_REG_CFG_LD), !!(cfg & MEM_AP_REG_CFG_LA), !!(cfg & MEM_AP_REG_CFG_BE)); return ERROR_OK; } @@ -827,202 +973,440 @@ int dap_to_jtag(struct adiv5_dap *dap) return dap_send_sequence(dap, SWD_TO_JTAG); } -/* CID interpretation -- see ARM IHI 0029B section 3 - * and ARM IHI 0031A table 13-3. +/* CID interpretation -- see ARM IHI 0029E table B2-7 + * and ARM IHI 0031E table D1-2. + * + * From 2009/11/25 commit 21378f58b604: + * "OptimoDE DESS" is ARM's semicustom DSPish stuff. + * Let's keep it as is, for the time being */ static const char *class_description[16] = { - "Reserved", "ROM table", "Reserved", "Reserved", - "Reserved", "Reserved", "Reserved", "Reserved", - "Reserved", "CoreSight component", "Reserved", "Peripheral Test Block", - "Reserved", "OptimoDE DESS", - "Generic IP component", "PrimeCell or System component" + [0x0] = "Generic verification component", + [0x1] = "ROM table", + [0x2] = "Reserved", + [0x3] = "Reserved", + [0x4] = "Reserved", + [0x5] = "Reserved", + [0x6] = "Reserved", + [0x7] = "Reserved", + [0x8] = "Reserved", + [0x9] = "CoreSight component", + [0xA] = "Reserved", + [0xB] = "Peripheral Test Block", + [0xC] = "Reserved", + [0xD] = "OptimoDE DESS", /* see above */ + [0xE] = "Generic IP component", + [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; +} ap_types[] = { + { AP_TYPE_JTAG_AP, "JTAG-AP" }, + { AP_TYPE_COM_AP, "COM-AP" }, + { AP_TYPE_AHB3_AP, "MEM-AP AHB3" }, + { AP_TYPE_APB_AP, "MEM-AP APB2 or APB3" }, + { AP_TYPE_AXI_AP, "MEM-AP AXI3 or AXI4" }, + { AP_TYPE_AHB5_AP, "MEM-AP AHB5" }, + { AP_TYPE_APB4_AP, "MEM-AP APB4" }, + { AP_TYPE_AXI5_AP, "MEM-AP AXI5" }, + { AP_TYPE_AHB5H_AP, "MEM-AP AHB5 with enhanced HPROT" }, }; -static bool is_dap_cid_ok(uint32_t cid) +static const char *ap_type_to_description(enum ap_type type) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(ap_types); i++) + if (type == ap_types[i].type) + return ap_types[i].description; + + return "Unknown"; +} + +bool is_ap_num_valid(struct adiv5_dap *dap, uint64_t ap_num) { - return (cid & 0xffff0fff) == 0xb105000d; + 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); - /* IDR bits: - * 31-28 : Revision - * 27-24 : JEDEC bank (0x4 for ARM) - * 23-17 : JEDEC code (0x3B for ARM) - * 16-13 : Class (0b1000=Mem-AP) - * 12-8 : Reserved - * 7-4 : AP Variant (non-zero for JTAG-AP) - * 3-0 : AP Type (0=JTAG-AP 1=AHB-AP 2=APB-AP 4=AXI-AP) - */ - /* Reading register for a non-existent AP should not cause an error, * but just to be sure, try to continue searching if an error does happen. */ - if ((retval == ERROR_OK) && /* Register read success */ - ((id_val & IDR_JEP106) == IDR_JEP106_ARM) && /* Jedec codes match */ - ((id_val & IDR_TYPE) == type_to_find)) { /* type matches*/ - + if (retval == ERROR_OK && (id_val & AP_TYPE_MASK) == type_to_find) { LOG_DEBUG("Found %s at AP index: %d (IDR=0x%08" PRIX32 ")", - (type_to_find == AP_TYPE_AHB3_AP) ? "AHB3-AP" : - (type_to_find == AP_TYPE_AHB5_AP) ? "AHB5-AP" : - (type_to_find == AP_TYPE_APB_AP) ? "APB-AP" : - (type_to_find == AP_TYPE_AXI_AP) ? "AXI-AP" : - (type_to_find == AP_TYPE_JTAG_AP) ? "JTAG-AP" : "Unknown", + 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", - (type_to_find == AP_TYPE_AHB3_AP) ? "AHB3-AP" : - (type_to_find == AP_TYPE_AHB5_AP) ? "AHB5-AP" : - (type_to_find == AP_TYPE_APB_AP) ? "APB-AP" : - (type_to_find == AP_TYPE_AXI_AP) ? "AXI-AP" : - (type_to_find == AP_TYPE_JTAG_AP) ? "JTAG-AP" : "Unknown"); + LOG_DEBUG("No %s found", ap_type_to_description(type_to_find)); return ERROR_FAIL; } -int dap_get_debugbase(struct adiv5_ap *ap, - uint32_t *dbgbase, uint32_t *apid) +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; int retval; + uint32_t baseptr_upper, baseptr_lower; - retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE, dbgbase); + if (ap->cfg_reg == MEM_AP_REG_CFG_INVALID) { + 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(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(dap), &baseptr_upper); + if (retval != ERROR_OK) + return retval; + } + retval = dap_run(dap); if (retval != ERROR_OK) return retval; + if (!is_64bit_ap(ap)) + baseptr_upper = 0; + *dbgbase = (((target_addr_t)baseptr_upper) << 32) | baseptr_lower; + return ERROR_OK; } -int dap_lookup_cs_component(struct adiv5_ap *ap, - uint32_t dbgbase, uint8_t type, uint32_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, component_base, devtype; + uint32_t baseptr_lower, baseptr_upper = 0; int retval; - *addr = 0; - - do { - retval = mem_ap_read_atomic_u32(ap, (dbgbase&0xFFFFF000) | - 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 & 0xFFFFF000) - + (romentry & 0xFFFFF000); + retval = dap_dp_read_atomic(dap, DP_BASEPTR0, &baseptr_lower); + if (retval != ERROR_OK) + return retval; - if (romentry & 0x1) { - uint32_t c_cid1; - retval = mem_ap_read_atomic_u32(ap, component_base | 0xff4, &c_cid1); - if (retval != ERROR_OK) { - LOG_ERROR("Can't read component with base address 0x%" PRIx32 - ", the corresponding core might be turned off", component_base); - return retval; - } - if (((c_cid1 >> 4) & 0x0f) == 1) { - 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; - } + if ((baseptr_lower & DP_BASEPTR0_VALID) != DP_BASEPTR0_VALID) { + command_print(cmd, "System root table not present"); + return ERROR_FAIL; + } - retval = mem_ap_read_atomic_u32(ap, - (component_base & 0xfffff000) | 0xfcc, - &devtype); - if (retval != ERROR_OK) - return retval; - if ((devtype & 0xff) == type) { - if (!*idx) { - *addr = component_base; - break; - } else - (*idx)--; - } - } - entry_offset += 4; - } while (romentry > 0); - - 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, uint32_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((component_base & 0xFFF) == 0); - assert(ap != NULL && cid != NULL && pid != NULL); + assert(IS_ALIGNED(component_base, ARM_CS_ALIGN)); + 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 + 0xFE0, &pid0); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + 0xFE4, &pid1); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + 0xFE8, &pid2); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + 0xFEC, &pid3); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + 0xFD0, &pid4); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + 0xFF0, &cid0); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + 0xFF4, &cid1); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + 0xFF8, &cid2); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + 0xFFC, &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) + /* sort by offset to gain speed */ + + /* + * 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; + } - *cid = (cid3 & 0xff) << 24 + v->cid = (cid3 & 0xff) << 24 | (cid2 & 0xff) << 16 | (cid1 & 0xff) << 8 | (cid0 & 0xff); - *pid = (uint64_t)(pid4 & 0xff) << 32 + v->pid = (uint64_t)(pid4 & 0xff) << 32 | (pid3 & 0xff) << 24 | (pid2 & 0xff) << 16 | (pid1 & 0xff) << 8 @@ -1031,14 +1415,6 @@ static int dap_read_part_id(struct adiv5_ap *ap, uint32_t component_base, uint32 return ERROR_OK; } -/* The designer identity code is encoded as: - * bits 11:8 : JEP106 Bank (number of continuation codes), only valid when bit 7 is 1. - * bit 7 : Set when bits 6:0 represent a JEP106 ID and cleared when bits 6:0 represent - * a legacy ASCII Identity Code. - * bits 6:0 : JEP106 Identity Code (without parity) or legacy ASCII code according to bit 7. - * JEP106 is a standard available from jedec.org - */ - /* Part number interpretations are from Cortex * core specs, the CoreSight components TRM * (ARM DDI 0314H), CoreSight System Design @@ -1046,22 +1422,12 @@ static int dap_read_part_id(struct adiv5_ap *ap, uint32_t component_base, uint32 * from chip observation (e.g. TI SDTI). */ -/* The legacy code only used the part number field to identify CoreSight peripherals. - * This meant that the same part number from two different manufacturers looked the same. - * It is desirable for all future additions to identify with both part number and JEP106. - * "ANY_ID" is a wildcard (any JEP106) only to preserve legacy behavior for legacy entries. - */ - -#define ANY_ID 0x1000 - -#define ARM_ID 0x4BB - -static const struct { +static const struct dap_part_nums { uint16_t designer_id; uint16_t part_num; const char *type; const char *full; -} dap_partnums[] = { +} dap_part_nums[] = { { ARM_ID, 0x000, "Cortex-M3 SCS", "(System Control Space)", }, { ARM_ID, 0x001, "Cortex-M3 ITM", "(Instrumentation Trace Module)", }, { ARM_ID, 0x002, "Cortex-M3 DWT", "(Data Watchpoint and Trace)", }, @@ -1072,9 +1438,12 @@ static const struct { { ARM_ID, 0x00c, "Cortex-M4 SCS", "(System Control Space)", }, { ARM_ID, 0x00d, "CoreSight ETM11", "(Embedded Trace)", }, { ARM_ID, 0x00e, "Cortex-M7 FPB", "(Flash Patch and Breakpoint)", }, + { ARM_ID, 0x193, "SoC-600 TSGEN", "(Timestamp Generator)", }, { ARM_ID, 0x470, "Cortex-M1 ROM", "(ROM Table)", }, { ARM_ID, 0x471, "Cortex-M0 ROM", "(ROM Table)", }, { ARM_ID, 0x490, "Cortex-A15 GIC", "(Generic Interrupt Controller)", }, + { ARM_ID, 0x492, "Cortex-R52 GICD", "(Distributor)", }, + { ARM_ID, 0x493, "Cortex-R52 GICR", "(Redistributor)", }, { ARM_ID, 0x4a1, "Cortex-A53 ROM", "(v8 Memory Map ROM Table)", }, { ARM_ID, 0x4a2, "Cortex-A57 ROM", "(ROM Table)", }, { ARM_ID, 0x4a3, "Cortex-A53 ROM", "(v7 Memory Map ROM Table)", }, @@ -1083,12 +1452,14 @@ static const struct { { ARM_ID, 0x4aa, "Cortex-A35 ROM", "(v8 Memory Map ROM Table)", }, { ARM_ID, 0x4af, "Cortex-A15 ROM", "(ROM Table)", }, { ARM_ID, 0x4b5, "Cortex-R5 ROM", "(ROM Table)", }, + { ARM_ID, 0x4b8, "Cortex-R52 ROM", "(ROM Table)", }, { ARM_ID, 0x4c0, "Cortex-M0+ ROM", "(ROM Table)", }, { ARM_ID, 0x4c3, "Cortex-M3 ROM", "(ROM Table)", }, { ARM_ID, 0x4c4, "Cortex-M4 ROM", "(ROM Table)", }, { ARM_ID, 0x4c7, "Cortex-M7 PPB ROM", "(Private Peripheral Bus ROM Table)", }, { ARM_ID, 0x4c8, "Cortex-M7 ROM", "(ROM Table)", }, { ARM_ID, 0x4e0, "Cortex-A35 ROM", "(v7 Memory Map ROM Table)", }, + { ARM_ID, 0x4e4, "Cortex-A76 ROM", "(ROM Table)", }, { ARM_ID, 0x906, "CoreSight CTI", "(Cross Trigger)", }, { ARM_ID, 0x907, "CoreSight ETB", "(Trace Buffer)", }, { ARM_ID, 0x908, "CoreSight CSTF", "(Trace Funnel)", }, @@ -1127,11 +1498,25 @@ static const struct { { ARM_ID, 0x9a9, "Cortex-M7 TPIU", "(Trace Port Interface Unit)", }, { ARM_ID, 0x9ae, "Cortex-A17 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9af, "Cortex-A15 PMU", "(Performance Monitor Unit)", }, + { ARM_ID, 0x9b6, "Cortex-R52 PMU/CTI/ETM", "(Performance Monitor Unit/Cross Trigger/ETM)", }, { ARM_ID, 0x9b7, "Cortex-R7 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d3, "Cortex-A53 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d7, "Cortex-A57 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d8, "Cortex-A72 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9da, "Cortex-A35 PMU/CTI/ETM", "(Performance Monitor Unit/Cross Trigger/ETM)", }, + { ARM_ID, 0x9e2, "SoC-600 APB-AP", "(APB4 Memory Access Port)", }, + { ARM_ID, 0x9e3, "SoC-600 AHB-AP", "(AHB5 Memory Access Port)", }, + { ARM_ID, 0x9e4, "SoC-600 AXI-AP", "(AXI Memory Access Port)", }, + { ARM_ID, 0x9e5, "SoC-600 APv1 Adapter", "(Access Port v1 Adapter)", }, + { ARM_ID, 0x9e6, "SoC-600 JTAG-AP", "(JTAG Access Port)", }, + { ARM_ID, 0x9e7, "SoC-600 TPIU", "(Trace Port Interface Unit)", }, + { ARM_ID, 0x9e8, "SoC-600 TMC ETR/ETS", "(Embedded Trace Router/Streamer)", }, + { ARM_ID, 0x9e9, "SoC-600 TMC ETB", "(Embedded Trace Buffer)", }, + { ARM_ID, 0x9ea, "SoC-600 TMC ETF", "(Embedded Trace FIFO)", }, + { ARM_ID, 0x9eb, "SoC-600 ATB Funnel", "(Trace Funnel)", }, + { ARM_ID, 0x9ec, "SoC-600 ATB Replicator", "(Trace Replicator)", }, + { ARM_ID, 0x9ed, "SoC-600 CTI", "(Cross Trigger)", }, + { ARM_ID, 0x9ee, "SoC-600 CATU", "(Address Translation Unit)", }, { ARM_ID, 0xc05, "Cortex-A5 Debug", "(Debug Unit)", }, { ARM_ID, 0xc07, "Cortex-A7 Debug", "(Debug Unit)", }, { ARM_ID, 0xc08, "Cortex-A8 Debug", "(Debug Unit)", }, @@ -1145,476 +1530,994 @@ static const struct { { ARM_ID, 0xd04, "Cortex-A35 Debug", "(Debug Unit)", }, { ARM_ID, 0xd07, "Cortex-A57 Debug", "(Debug Unit)", }, { ARM_ID, 0xd08, "Cortex-A72 Debug", "(Debug Unit)", }, - { 0x097, 0x9af, "MSP432 ROM", "(ROM Table)" }, - { 0x09f, 0xcd0, "Atmel CPU with DSU", "(CPU)" }, - { 0x0c1, 0x1db, "XMC4500 ROM", "(ROM Table)" }, - { 0x0c1, 0x1df, "XMC4700/4800 ROM", "(ROM Table)" }, - { 0x0c1, 0x1ed, "XMC1000 ROM", "(ROM Table)" }, - { 0x0E5, 0x000, "SHARC+/Blackfin+", "", }, - { 0x0F0, 0x440, "Qualcomm QDSS Component v1", "(Qualcomm Designed CoreSight Component v1)", }, - { 0x3eb, 0x181, "Tegra 186 ROM", "(ROM Table)", }, - { 0x3eb, 0x202, "Denver ETM", "(Denver Embedded Trace)", }, - { 0x3eb, 0x211, "Tegra 210 ROM", "(ROM Table)", }, - { 0x3eb, 0x302, "Denver Debug", "(Debug Unit)", }, - { 0x3eb, 0x402, "Denver PMU", "(Performance Monitor Unit)", }, - /* legacy comment: 0x113: what? */ - { ANY_ID, 0x120, "TI SDTI", "(System Debug Trace Interface)", }, /* from OMAP3 memmap */ - { ANY_ID, 0x343, "TI DAPCTL", "", }, /* from OMAP3 memmap */ + { ARM_ID, 0xd0b, "Cortex-A76 Debug", "(Debug Unit)", }, + { ARM_ID, 0xd0c, "Neoverse N1", "(Debug Unit)", }, + { ARM_ID, 0xd13, "Cortex-R52 Debug", "(Debug Unit)", }, + { ARM_ID, 0xd49, "Neoverse N2", "(Debug Unit)", }, + { 0x017, 0x120, "TI SDTI", "(System Debug Trace Interface)", }, /* from OMAP3 memmap */ + { 0x017, 0x343, "TI DAPCTL", "", }, /* from OMAP3 memmap */ + { 0x017, 0x9af, "MSP432 ROM", "(ROM Table)" }, + { 0x01f, 0xcd0, "Atmel CPU with DSU", "(CPU)" }, + { 0x041, 0x1db, "XMC4500 ROM", "(ROM Table)" }, + { 0x041, 0x1df, "XMC4700/4800 ROM", "(ROM Table)" }, + { 0x041, 0x1ed, "XMC1000 ROM", "(ROM Table)" }, + { 0x065, 0x000, "SHARC+/Blackfin+", "", }, + { 0x070, 0x440, "Qualcomm QDSS Component v1", "(Qualcomm Designed CoreSight Component v1)", }, + { 0x0bf, 0x100, "Brahma-B53 Debug", "(Debug Unit)", }, + { 0x0bf, 0x9d3, "Brahma-B53 PMU", "(Performance Monitor Unit)", }, + { 0x0bf, 0x4a1, "Brahma-B53 ROM", "(ROM Table)", }, + { 0x0bf, 0x721, "Brahma-B53 ROM", "(ROM Table)", }, + { 0x1eb, 0x181, "Tegra 186 ROM", "(ROM Table)", }, + { 0x1eb, 0x202, "Denver ETM", "(Denver Embedded Trace)", }, + { 0x1eb, 0x211, "Tegra 210 ROM", "(ROM Table)", }, + { 0x1eb, 0x302, "Denver Debug", "(Debug Unit)", }, + { 0x1eb, 0x402, "Denver PMU", "(Performance Monitor Unit)", }, }; -static int dap_rom_display(struct command_invocation *cmd, - struct adiv5_ap *ap, uint32_t dbgbase, int depth) +static const struct dap_part_nums *pidr_to_part_num(unsigned int designer_id, unsigned int part_num) +{ + static const struct dap_part_nums unknown = { + .type = "Unrecognized", + .full = "", + }; + + for (unsigned int i = 0; i < ARRAY_SIZE(dap_part_nums); i++) + if (dap_part_nums[i].designer_id == designer_id && dap_part_nums[i].part_num == part_num) + return &dap_part_nums[i]; + + return &unknown; +} + +static int dap_devtype_display(struct command_invocation *cmd, uint32_t devtype) +{ + const char *major = "Reserved", *subtype = "Reserved"; + const unsigned int minor = (devtype & ARM_CS_C9_DEVTYPE_SUB_MASK) >> ARM_CS_C9_DEVTYPE_SUB_SHIFT; + const unsigned int devtype_major = (devtype & ARM_CS_C9_DEVTYPE_MAJOR_MASK) >> ARM_CS_C9_DEVTYPE_MAJOR_SHIFT; + switch (devtype_major) { + case 0: + major = "Miscellaneous"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 4: + subtype = "Validation component"; + break; + } + break; + case 1: + major = "Trace Sink"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Port"; + break; + case 2: + subtype = "Buffer"; + break; + case 3: + subtype = "Router"; + break; + } + break; + case 2: + major = "Trace Link"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Funnel, router"; + break; + case 2: + subtype = "Filter"; + break; + case 3: + subtype = "FIFO, buffer"; + break; + } + break; + case 3: + major = "Trace Source"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Processor"; + break; + case 2: + subtype = "DSP"; + break; + case 3: + subtype = "Engine/Coprocessor"; + break; + case 4: + subtype = "Bus"; + break; + case 6: + subtype = "Software"; + break; + } + break; + case 4: + major = "Debug Control"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Trigger Matrix"; + break; + case 2: + subtype = "Debug Auth"; + break; + case 3: + subtype = "Power Requestor"; + break; + } + break; + case 5: + major = "Debug Logic"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Processor"; + break; + case 2: + subtype = "DSP"; + break; + case 3: + subtype = "Engine/Coprocessor"; + break; + case 4: + subtype = "Bus"; + break; + case 5: + subtype = "Memory"; + break; + } + break; + case 6: + major = "Performance Monitor"; + switch (minor) { + case 0: + subtype = "other"; + break; + case 1: + subtype = "Processor"; + break; + case 2: + subtype = "DSP"; + break; + case 3: + subtype = "Engine/Coprocessor"; + break; + case 4: + subtype = "Bus"; + break; + case 5: + subtype = "Memory"; + break; + } + break; + } + command_print(cmd, "\t\tType is 0x%02x, %s, %s", + devtype & ARM_CS_C9_DEVTYPE_MASK, + major, subtype); + return ERROR_OK; +} + +/** + * 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); + + 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; + } - uint32_t base_addr = dbgbase & 0xFFFFF000; - command_print(cmd, "\t\tComponent base address 0x%08" PRIx32, base_addr); + 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_dap_cid_ok(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 = (pid >> 36) & 0xf; + uint32_t size = ARM_CS_PIDR_SIZE(v->pid); if (size > 0) - command_print(cmd, "\t\tStart address 0x%08" PRIx32, (uint32_t)(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); - uint8_t class = (cid >> 12) & 0xf; - uint16_t part_num = pid & 0xfff; - uint16_t designer_id = ((pid >> 32) & 0xf) << 8 | ((pid >> 12) & 0xff); + const unsigned int part_num = ARM_CS_PIDR_PART(v->pid); + unsigned int designer_id = ARM_CS_PIDR_DESIGNER(v->pid); - if (designer_id & 0x80) { + if (v->pid & ARM_CS_PIDR_JEDEC) { /* JEP106 code */ - command_print(cmd, "\t\tDesigner is 0x%03" PRIx16 ", %s", - designer_id, jep106_manufacturer(designer_id >> 8, designer_id & 0x7f)); + command_print(cmd, "\t\tDesigner is 0x%03x, %s", + designer_id, jep106_manufacturer(designer_id)); } else { /* Legacy ASCII ID, clear invalid bits */ designer_id &= 0x7f; - command_print(cmd, "\t\tDesigner ASCII code 0x%02" PRIx16 ", %s", + command_print(cmd, "\t\tDesigner ASCII code 0x%02x, %s", designer_id, designer_id == 0x41 ? "ARM" : "<unknown>"); } - /* default values to be overwritten upon finding a match */ - const char *type = "Unrecognized"; - const char *full = ""; + 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) { + 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; + } + + if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) { + dap_devtype_display(cmd, v->devtype_memtype); - /* search dap_partnums[] array for a match */ - for (unsigned entry = 0; entry < ARRAY_SIZE(dap_partnums); entry++) { + /* REVISIT also show ARM_CS_C9_DEVID */ - if ((dap_partnums[entry].designer_id != designer_id) && (dap_partnums[entry].designer_id != ANY_ID)) - continue; + if ((v->devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0) + return ERROR_OK; - if (dap_partnums[entry].part_num != part_num) - continue; + 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); - type = dap_partnums[entry].type; - full = dap_partnums[entry].full; - break; + 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"); + } + return ERROR_OK; } - command_print(cmd, "\t\tPart is 0x%" PRIx16", %s %s", part_num, type, full); - command_print(cmd, "\t\tComponent class is 0x%" PRIx8 ", %s", class, class_description[class]); + /* Class other than 0x1 and 0x9 */ + return ERROR_OK; +} - if (class == 1) { /* ROM Table */ - uint32_t memtype; - retval = mem_ap_read_atomic_u32(ap, base_addr | 0xFCC, &memtype); - if (retval != ERROR_OK) - return retval; +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 (memtype & 0x01) - command_print(cmd, "\t\tMEMTYPE system memory present on bus"); - else - command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus"); + if (depth) + snprintf(tabs, sizeof(tabs), "[L%02d] ", depth); - /* 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 & 0x01) { - /* Recurse */ - retval = dap_rom_display(cmd, ap, base_addr + (romentry & 0xFFFFF000), 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; - } - } - } else if (class == 9) { /* CoreSight component */ - const char *major = "Reserved", *subtype = "Reserved"; + 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; + } - uint32_t devtype; - retval = mem_ap_read_atomic_u32(ap, base_addr | 0xFCC, &devtype); - if (retval != ERROR_OK) - return retval; - unsigned minor = (devtype >> 4) & 0x0f; - switch (devtype & 0x0f) { - case 0: - major = "Miscellaneous"; - switch (minor) { - case 0: - subtype = "other"; - break; - case 4: - subtype = "Validation component"; - break; - } - break; - case 1: - major = "Trace Sink"; - switch (minor) { - case 0: - subtype = "other"; - break; - case 1: - subtype = "Port"; - break; - case 2: - subtype = "Buffer"; - break; - case 3: - subtype = "Router"; - break; - } - break; - case 2: - major = "Trace Link"; - switch (minor) { - case 0: - subtype = "other"; - break; - case 1: - subtype = "Funnel, router"; - break; - case 2: - subtype = "Filter"; - break; - case 3: - subtype = "FIFO, buffer"; - break; - } - break; - case 3: - major = "Trace Source"; - switch (minor) { - case 0: - subtype = "other"; - break; - case 1: - subtype = "Processor"; - break; - case 2: - subtype = "DSP"; - break; - case 3: - subtype = "Engine/Coprocessor"; - break; - case 4: - subtype = "Bus"; - break; - case 6: - subtype = "Software"; - break; - } - break; - case 4: - major = "Debug Control"; - switch (minor) { - case 0: - subtype = "other"; - break; - case 1: - subtype = "Trigger Matrix"; - break; - case 2: - subtype = "Debug Auth"; - break; - case 3: - subtype = "Power Requestor"; - break; - } - break; - case 5: - major = "Debug Logic"; - switch (minor) { - case 0: - subtype = "other"; - break; - case 1: - subtype = "Processor"; - break; - case 2: - subtype = "DSP"; - break; - case 3: - subtype = "Engine/Coprocessor"; - break; - case 4: - subtype = "Bus"; - break; - case 5: - subtype = "Memory"; - break; - } - break; - case 6: - major = "Performance Monitor"; - switch (minor) { - case 0: - subtype = "other"; - break; - case 1: - subtype = "Processor"; - break; - case 2: - subtype = "DSP"; - break; - case 3: - subtype = "Engine/Coprocessor"; - break; - case 4: - subtype = "Bus"; - break; - case 5: - subtype = "Memory"; - break; - } - break; - } - command_print(cmd, "\t\tType is 0x%02" PRIx8 ", %s, %s", - (uint8_t)(devtype & 0xff), - major, subtype); - /* REVISIT also show 0xfc8 DevId */ + 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 dbgbase, apid; - uint8_t mem_ap; + 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; - switch (apid & (IDR_JEP106 | IDR_TYPE)) { - case IDR_JEP106_ARM | AP_TYPE_JTAG_AP: - command_print(cmd, "\tType is JTAG-AP"); - break; - case IDR_JEP106_ARM | AP_TYPE_AHB3_AP: - command_print(cmd, "\tType is MEM-AP AHB3"); - break; - case IDR_JEP106_ARM | AP_TYPE_AHB5_AP: - command_print(cmd, "\tType is MEM-AP AHB5"); - break; - case IDR_JEP106_ARM | AP_TYPE_APB_AP: - command_print(cmd, "\tType is MEM-AP APB"); - break; - case IDR_JEP106_ARM | AP_TYPE_AXI_AP: - command_print(cmd, "\tType is MEM-AP AXI"); - break; - default: - command_print(cmd, "\tUnknown AP type"); - break; - } + 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. - */ - mem_ap = (apid & IDR_CLASS) == AP_CLASS_MEM_AP; - if (mem_ap) { - command_print(cmd, "MEM-AP BASE 0x%8.8" PRIx32, dbgbase); + if ((v->devtype_memtype & ARM_CS_C9_DEVTYPE_MASK) != lookup->type) + return ERROR_OK; - if (dbgbase == 0xFFFFFFFF || (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"); + if (lookup->idx) { + /* search for next one */ + --lookup->idx; + return ERROR_OK; + } - dap_rom_display(cmd, ap, dbgbase & 0xFFFFF000, 0); + /* Found! */ + lookup->component_base = v->component_base; + lookup->ap_num = v->ap->ap_num; + return CORESIGHT_COMPONENT_FOUND; +} + +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, + }; + + 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 { CFG_DAP, - CFG_AP_NUM + CFG_AP_NUM, + CFG_BASEADDR, + CFG_CTIBASE, /* DEPRECATED */ }; -static const Jim_Nvp nvp_config_opts[] = { - { .name = "-dap", .value = CFG_DAP }, - { .name = "-ap-num", .value = CFG_AP_NUM }, +static const struct jim_nvp nvp_config_opts[] = { + { .name = "-dap", .value = CFG_DAP }, + { .name = "-ap-num", .value = CFG_AP_NUM }, + { .name = "-baseaddr", .value = CFG_BASEADDR }, + { .name = "-ctibase", .value = CFG_CTIBASE }, /* DEPRECATED */ { .name = NULL, .value = -1 } }; -int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi) +static int adiv5_jim_spot_configure(struct jim_getopt_info *goi, + struct adiv5_dap **dap_p, uint64_t *ap_num_p, uint32_t *base_p) { - struct adiv5_private_config *pc; - int e; - - pc = (struct adiv5_private_config *)target->private_config; - if (pc == NULL) { - pc = calloc(1, sizeof(struct adiv5_private_config)); - pc->ap_num = DP_APSEL_INVALID; - target->private_config = pc; - } - - target->has_dap = true; - - if (goi->argc > 0) { - Jim_Nvp *n; - - Jim_SetEmptyResult(goi->interp); - - /* check first if topmost item is for us */ - e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts, - goi->argv[0], &n); - if (e != JIM_OK) - return JIM_CONTINUE; - - e = Jim_GetOpt_Obj(goi, NULL); - if (e != JIM_OK) - return e; - - switch (n->value) { - case CFG_DAP: - if (goi->isconfigure) { - Jim_Obj *o_t; - struct adiv5_dap *dap; - e = Jim_GetOpt_Obj(goi, &o_t); - if (e != JIM_OK) - return e; - dap = dap_instance_by_jim_obj(goi->interp, o_t); - if (dap == NULL) { - Jim_SetResultString(goi->interp, "DAP name invalid!", -1); - return JIM_ERR; - } - if (pc->dap != NULL && pc->dap != dap) { - Jim_SetResultString(goi->interp, - "DAP assignment cannot be changed after target was created!", -1); - return JIM_ERR; - } - if (target->tap_configured) { - Jim_SetResultString(goi->interp, - "-chain-position and -dap configparams are mutually exclusive!", -1); - return JIM_ERR; - } - pc->dap = dap; - target->tap = dap->tap; - target->dap_configured = true; - } else { - if (goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, - goi->argc, goi->argv, - "NO PARAMS"); - return JIM_ERR; - } + assert(dap_p && ap_num_p); + + if (!goi->argc) + return JIM_OK; + + Jim_SetEmptyResult(goi->interp); + + struct jim_nvp *n; + int e = jim_nvp_name2value_obj(goi->interp, nvp_config_opts, + goi->argv[0], &n); + if (e != JIM_OK) + return JIM_CONTINUE; + + /* base_p can be NULL, then '-baseaddr' option is treated as unknown */ + if (!base_p && (n->value == CFG_BASEADDR || n->value == CFG_CTIBASE)) + return JIM_CONTINUE; + + e = jim_getopt_obj(goi, NULL); + if (e != JIM_OK) + return e; + + switch (n->value) { + case CFG_DAP: + if (goi->isconfigure) { + Jim_Obj *o_t; + struct adiv5_dap *dap; + e = jim_getopt_obj(goi, &o_t); + if (e != JIM_OK) + return e; + dap = dap_instance_by_jim_obj(goi->interp, o_t); + if (!dap) { + Jim_SetResultString(goi->interp, "DAP name invalid!", -1); + return JIM_ERR; + } + if (*dap_p && *dap_p != dap) { + Jim_SetResultString(goi->interp, + "DAP assignment cannot be changed!", -1); + return JIM_ERR; + } + *dap_p = dap; + } else { + if (goi->argc) + goto err_no_param; + if (!*dap_p) { + Jim_SetResultString(goi->interp, "DAP not configured", -1); + return JIM_ERR; + } + Jim_SetResultString(goi->interp, adiv5_dap_name(*dap_p), -1); + } + break; - if (pc->dap == NULL) { - Jim_SetResultString(goi->interp, "DAP not configured", -1); - return JIM_ERR; - } - Jim_SetResultString(goi->interp, adiv5_dap_name(pc->dap), -1); + 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; + /* 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; } - break; + *ap_num_p = ap_num; + } else { + if (goi->argc) + goto err_no_param; + if (*ap_num_p == DP_APSEL_INVALID) { + Jim_SetResultString(goi->interp, "AP number not configured", -1); + return JIM_ERR; + } + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, *ap_num_p)); + } + break; - case CFG_AP_NUM: - if (goi->isconfigure) { - 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) { - Jim_SetResultString(goi->interp, "Invalid AP number!", -1); - return JIM_ERR; - } - pc->ap_num = ap_num; - } else { - if (goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, - goi->argc, goi->argv, - "NO PARAMS"); - return JIM_ERR; - } + case CFG_CTIBASE: + LOG_WARNING("DEPRECATED! use \'-baseaddr' not \'-ctibase\'"); + /* fall through */ + case CFG_BASEADDR: + if (goi->isconfigure) { + jim_wide base; + e = jim_getopt_wide(goi, &base); + if (e != JIM_OK) + return e; + *base_p = (uint32_t)base; + } else { + if (goi->argc) + goto err_no_param; + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, *base_p)); + } + break; + }; - if (pc->ap_num == DP_APSEL_INVALID) { - Jim_SetResultString(goi->interp, "AP number not configured", -1); - return JIM_ERR; - } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, pc->ap_num)); + return JIM_OK; + +err_no_param: + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); + return JIM_ERR; +} + +int adiv5_jim_configure_ext(struct target *target, struct jim_getopt_info *goi, + struct adiv5_private_config *pc, enum adiv5_configure_dap_optional optional) +{ + int e; + + if (!pc) { + 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; } - break; + pc->ap_num = DP_APSEL_INVALID; + target->private_config = pc; + } + } + + if (optional == ADI_CONFIGURE_DAP_COMPULSORY) + target->has_dap = true; + + e = adiv5_jim_spot_configure(goi, &pc->dap, &pc->ap_num, NULL); + if (e != JIM_OK) + return e; + + if (pc->dap && !target->dap_configured) { + if (target->tap_configured) { + pc->dap = NULL; + Jim_SetResultString(goi->interp, + "-chain-position and -dap configparams are mutually exclusive!", -1); + return JIM_ERR; } + target->tap = pc->dap->tap; + target->dap_configured = true; + target->has_dap = true; } return JIM_OK; } +int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi) +{ + return adiv5_jim_configure_ext(target, goi, NULL, ADI_CONFIGURE_DAP_COMPULSORY); +} + int adiv5_verify_config(struct adiv5_private_config *pc) { - if (pc == NULL) + if (!pc) return ERROR_FAIL; - if (pc->dap == NULL) + if (!pc->dap) return ERROR_FAIL; return ERROR_OK; } +int adiv5_jim_mem_ap_spot_configure(struct adiv5_mem_ap_spot *cfg, + struct jim_getopt_info *goi) +{ + return adiv5_jim_spot_configure(goi, &cfg->dap, &cfg->ap_num, &cfg->base); +} + +int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p) +{ + p->dap = NULL; + p->ap_num = DP_APSEL_INVALID; + p->base = 0; + return ERROR_OK; +} 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; } @@ -1623,23 +2526,35 @@ 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; + uint64_t apsel; + uint32_t baseaddr_lower, baseaddr_upper; + struct adiv5_ap *ap; + target_addr_t baseaddr; int retval; + baseaddr_upper = 0; + switch (CMD_ARGC) { case 0: 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; } @@ -1653,37 +2568,70 @@ COMMAND_HANDLER(dap_baseaddr_command) * though they're not common for now. This should * use the ID register to verify it's a MEM-AP. */ - retval = dap_queue_ap_read(dap_ap(dap, apsel), MEM_AP_REG_BASE, &baseaddr); - if (retval != ERROR_OK) - return retval; - retval = dap_run(dap); + + 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(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(dap), &baseaddr_upper); + } + + if (retval == ERROR_OK) + retval = dap_run(dap); + dap_put_ap(ap); if (retval != ERROR_OK) return retval; - command_print(CMD, "0x%8.8" PRIx32, baseaddr); + if (is_64bit_ap(ap)) { + baseaddr = (((target_addr_t)baseaddr_upper) << 32) | baseaddr_lower; + command_print(CMD, "0x%016" PRIx64, baseaddr); + } else + command_print(CMD, "0x%08" PRIx32, baseaddr_lower); - return retval; + return ERROR_OK; } 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; } @@ -1691,16 +2639,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; } @@ -1716,14 +2663,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; @@ -1734,7 +2686,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); @@ -1743,14 +2700,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; } @@ -1758,7 +2720,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) { @@ -1766,9 +2729,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; } @@ -1777,10 +2739,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; @@ -1792,44 +2762,67 @@ 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: - ap->tar_valid = false; /* invalid, force write */ - retval = mem_ap_setup_tar(ap, value); - break; - default: + } 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; + else { + /* To track independent writes to TAR and TAR64, two tar_valid flags */ + /* should be used. To keep it simple, tar_valid is only invalidated on a */ + /* write fail. This approach causes a later re-write of the TAR and TAR64 */ + /* if tar_valid is false. */ + ap->tar_valid = false; + } + } 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); + else { + /* See above comment for the MEM_AP_REG_TAR failed write case */ + ap->tar_valid = false; + } + } else { retval = dap_queue_ap_write(ap, reg, value); - break; } } else { retval = dap_queue_ap_read(ap, reg, &value); @@ -1837,6 +2830,8 @@ COMMAND_HANDLER(dap_apreg_command) if (retval == ERROR_OK) retval = dap_run(dap); + dap_put_ap(ap); + if (retval != ERROR_OK) return retval; @@ -1886,14 +2881,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", @@ -1958,5 +2960,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 ea71551672..92c3dbc3a6 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 @@ -31,6 +22,10 @@ #include <helper/list.h> #include "arm_jtag.h" +#include "helper/bits.h" + +/* JEP106 ID for ARM */ +#define ARM_ID 0x23B /* three-bit ACK values for SWD access (sent LSB first) */ #define SWD_ACK_OK 0x1 @@ -49,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 */ @@ -61,6 +60,10 @@ #define DLCR_TO_TRN(dlcr) ((uint32_t)(1 + ((3 & (dlcr)) >> 8))) /* 1..4 clocks */ +/* Fields of DP_DPIDR register */ +#define DP_DPIDR_VERSION_SHIFT 12 +#define DP_DPIDR_VERSION_MASK (0xFUL << DP_DPIDR_VERSION_SHIFT) + /* Fields of the DP's AP ABORT register */ #define DAPABORT (1UL << 0) #define STKCMPCLR (1UL << 1) /* SWD-only */ @@ -68,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) @@ -85,27 +95,79 @@ #define CSYSPWRUPREQ (1UL << 30) #define CSYSPWRUPACK (1UL << 31) +#define DP_DLPIDR_PROTVSN 1u + +#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) /* 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_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) @@ -140,31 +202,45 @@ /* APB: initial value of csw_default */ #define CSW_APB_DEFAULT (CSW_DBGSWENABLE) +/* Fields of the MEM-AP's CFG register */ +#define MEM_AP_REG_CFG_BE BIT(0) +#define MEM_AP_REG_CFG_LA BIT(1) +#define MEM_AP_REG_CFG_LD BIT(2) +#define MEM_AP_REG_CFG_INVALID 0xFFFFFFF8 /* Fields of the MEM-AP's IDR register */ -#define IDR_REV (0xFUL << 28) -#define IDR_JEP106 (0x7FFUL << 17) -#define IDR_CLASS (0xFUL << 13) -#define IDR_VARIANT (0xFUL << 4) -#define IDR_TYPE (0xFUL << 0) - -#define IDR_JEP106_ARM 0x04760000 - -#define DP_SELECT_APSEL 0xFF000000 -#define DP_SELECT_APBANK 0x000000F0 -#define DP_SELECT_DPBANK 0x0000000F -#define DP_SELECT_INVALID 0x00FFFF00 /* Reserved bits one */ - -#define DP_APSEL_MAX (255) -#define DP_APSEL_INVALID (-1) +#define AP_REG_IDR_REVISION_MASK (0xF0000000) +#define AP_REG_IDR_REVISION_SHIFT (28) +#define AP_REG_IDR_DESIGNER_MASK (0x0FFE0000) +#define AP_REG_IDR_DESIGNER_SHIFT (17) +#define AP_REG_IDR_CLASS_MASK (0x0001E000) +#define AP_REG_IDR_CLASS_SHIFT (13) +#define AP_REG_IDR_VARIANT_MASK (0x000000F0) +#define AP_REG_IDR_VARIANT_SHIFT (4) +#define AP_REG_IDR_TYPE_MASK (0x0000000F) +#define AP_REG_IDR_TYPE_SHIFT (0) + +#define AP_REG_IDR_CLASS_NONE (0x0) +#define AP_REG_IDR_CLASS_COM (0x1) +#define AP_REG_IDR_CLASS_MEM_AP (0x8) + +#define AP_REG_IDR_VALUE(d, c, t) (\ + (((d) << AP_REG_IDR_DESIGNER_SHIFT) & AP_REG_IDR_DESIGNER_MASK) | \ + (((c) << AP_REG_IDR_CLASS_SHIFT) & AP_REG_IDR_CLASS_MASK) | \ + (((t) << AP_REG_IDR_TYPE_SHIFT) & AP_REG_IDR_TYPE_MASK) \ +) + +#define AP_TYPE_MASK (AP_REG_IDR_DESIGNER_MASK | AP_REG_IDR_CLASS_MASK | AP_REG_IDR_TYPE_MASK) /* FIXME: not SWD specific; should be renamed, e.g. adiv5_special_seq */ enum swd_special_seq { LINE_RESET, JTAG_TO_SWD, + JTAG_TO_DORMANT, SWD_TO_JTAG, SWD_TO_DORMANT, DORMANT_TO_SWD, + DORMANT_TO_JTAG, }; /** @@ -178,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. @@ -194,12 +272,32 @@ 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 * "-1" indicates no cached value. */ - uint32_t tar_value; + target_addr_t tar_value; /** * Configures how many extra tck clocks are added after starting a @@ -211,13 +309,23 @@ 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; /* true if tar_value is in sync with TAR register */ bool tar_valid; + + /* 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; }; @@ -256,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; @@ -279,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 @@ -294,6 +416,24 @@ struct adiv5_dap { /** Flag saying whether to ignore the syspwrupack flag in DAP. Some devices * do not set this bit until later in the bringup sequence */ bool ignore_syspwrupack; + + /** Value to select DP in SWD multidrop mode or DP_TARGETSEL_INVALID */ + uint32_t multidrop_targetsel; + /** TPARTNO and TDESIGNER fields of multidrop_targetsel have been configured */ + bool multidrop_dp_id_valid; + /** TINSTANCE field of multidrop_targetsel has been configured */ + bool multidrop_instance_id_valid; + + /** + * 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; }; /** @@ -304,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); @@ -338,25 +481,50 @@ struct dap_ops { void (*quit)(struct adiv5_dap *dap); }; -/* - * Access Port classes - */ -enum ap_class { - AP_CLASS_NONE = 0x00000, /* No class defined */ - AP_CLASS_MEM_AP = 0x10000, /* MEM-AP */ -}; - /* * Access Port types */ enum ap_type { - AP_TYPE_JTAG_AP = 0x0, /* JTAG-AP - JTAG master for controlling other JTAG devices */ - AP_TYPE_AHB3_AP = 0x1, /* AHB3 Memory-AP */ - AP_TYPE_APB_AP = 0x2, /* APB Memory-AP */ - AP_TYPE_AXI_AP = 0x4, /* AXI Memory-AP */ - AP_TYPE_AHB5_AP = 0x5, /* AHB5 Memory-AP. */ + AP_TYPE_JTAG_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_NONE, 0), /* JTAG-AP */ + AP_TYPE_COM_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_COM, 0), /* COM-AP */ + AP_TYPE_AHB3_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 1), /* AHB3 Memory-AP */ + AP_TYPE_APB_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 2), /* APB2 or APB3 Memory-AP */ + AP_TYPE_AXI_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 4), /* AXI3 or AXI4 Memory-AP */ + AP_TYPE_AHB5_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 5), /* AHB5 Memory-AP */ + AP_TYPE_APB4_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 6), /* APB4 Memory-AP */ + AP_TYPE_AXI5_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 7), /* AXI5 Memory-AP */ + 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 + * 0b1: The AP supports physical addresses larger than 32 bits + * + * @param ap The AP used for reading. + * + * @return true for 64 bit, false for 32 bit + */ +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. * @@ -368,7 +536,7 @@ enum ap_type { static inline int dap_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) { - assert(dap->ops != NULL); + assert(dap->ops); return dap->ops->send_sequence(dap, seq); } @@ -387,7 +555,7 @@ static inline int dap_send_sequence(struct adiv5_dap *dap, static inline int dap_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { - assert(dap->ops != NULL); + assert(dap->ops); return dap->ops->queue_dp_read(dap, reg, data); } @@ -405,7 +573,7 @@ static inline int dap_queue_dp_read(struct adiv5_dap *dap, static inline int dap_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { - assert(dap->ops != NULL); + assert(dap->ops); return dap->ops->queue_dp_write(dap, reg, data); } @@ -422,7 +590,11 @@ static inline int dap_queue_dp_write(struct adiv5_dap *dap, static inline int dap_queue_ap_read(struct adiv5_ap *ap, unsigned reg, uint32_t *data) { - assert(ap->dap->ops != NULL); + 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); } @@ -438,7 +610,11 @@ static inline int dap_queue_ap_read(struct adiv5_ap *ap, static inline int dap_queue_ap_write(struct adiv5_ap *ap, unsigned reg, uint32_t data) { - assert(ap->dap->ops != NULL); + 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); } @@ -455,7 +631,7 @@ static inline int dap_queue_ap_write(struct adiv5_ap *ap, */ static inline int dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) { - assert(dap->ops != NULL); + assert(dap->ops); return dap->ops->queue_ap_abort(dap, ack); } @@ -471,13 +647,13 @@ static inline int dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) */ static inline int dap_run(struct adiv5_dap *dap) { - assert(dap->ops != NULL); + assert(dap->ops); return dap->ops->run(dap); } static inline int dap_sync(struct adiv5_dap *dap) { - assert(dap->ops != NULL); + assert(dap->ops); if (dap->ops->sync) return dap->ops->sync(dap); return ERROR_OK; @@ -526,52 +702,65 @@ static inline int dap_dp_poll_register(struct adiv5_dap *dap, unsigned reg, /* Queued MEM-AP memory mapped single word transfers. */ int mem_ap_read_u32(struct adiv5_ap *ap, - uint32_t address, uint32_t *value); + target_addr_t address, uint32_t *value); int mem_ap_write_u32(struct adiv5_ap *ap, - uint32_t address, uint32_t value); + target_addr_t address, uint32_t value); /* Synchronous MEM-AP memory mapped single word transfers. */ int mem_ap_read_atomic_u32(struct adiv5_ap *ap, - uint32_t address, uint32_t *value); + target_addr_t address, uint32_t *value); int mem_ap_write_atomic_u32(struct adiv5_ap *ap, - uint32_t address, uint32_t value); + target_addr_t address, uint32_t value); /* Synchronous MEM-AP memory mapped bus block transfers. */ int mem_ap_read_buf(struct adiv5_ap *ap, - uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address); + uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address); int mem_ap_write_buf(struct adiv5_ap *ap, - const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address); + const uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address); /* Synchronous, non-incrementing buffer functions for accessing fifos. */ int mem_ap_read_buf_noincr(struct adiv5_ap *ap, - uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address); + uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address); int mem_ap_write_buf_noincr(struct adiv5_ap *ap, - const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address); + const uint8_t *buffer, uint32_t size, uint32_t count, target_addr_t address); /* Initialisation of the debug system, power domains and registers */ int dap_dp_init(struct adiv5_dap *dap); +int dap_dp_init_or_reconnect(struct adiv5_dap *dap); 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, - uint32_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 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) { - return &dap->ap[ap_num]; + return dap->multidrop_dp_id_valid && dap->multidrop_instance_id_valid; } /* Lookup CoreSight component */ int dap_lookup_cs_component(struct adiv5_ap *ap, - uint32_t dbgbase, uint8_t type, uint32_t *addr, int32_t *idx); + uint8_t type, target_addr_t *addr, int32_t idx); struct target; @@ -594,11 +783,30 @@ 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; }; extern int adiv5_verify_config(struct adiv5_private_config *pc); -extern int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi); + +enum adiv5_configure_dap_optional { + ADI_CONFIGURE_DAP_COMPULSORY = false, + ADI_CONFIGURE_DAP_OPTIONAL = true +}; + +extern int adiv5_jim_configure_ext(struct target *target, struct jim_getopt_info *goi, + struct adiv5_private_config *pc, + enum adiv5_configure_dap_optional optional); +extern int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi); + +struct adiv5_mem_ap_spot { + struct adiv5_dap *dap; + uint64_t ap_num; + uint32_t base; +}; + +extern int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p); +extern int adiv5_jim_mem_ap_spot_configure(struct adiv5_mem_ap_spot *cfg, + struct jim_getopt_info *goi); #endif /* OPENOCD_TARGET_ARM_ADI_V5_H */ diff --git a/src/target/arm_coresight.h b/src/target/arm_coresight.h new file mode 100644 index 0000000000..58139dcdbe --- /dev/null +++ b/src/target/arm_coresight.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * General info from: + * ARM CoreSight Architecture Specification v3.0 IHI0029E + */ + +#ifndef OPENOCD_TARGET_ARM_CORESIGHT_H +#define OPENOCD_TARGET_ARM_CORESIGHT_H + +#include <stdbool.h> +#include <stdint.h> + +#include <helper/bits.h> + +#define ARM_CS_ALIGN (0x1000) + +/* mandatory registers */ +#define ARM_CS_PIDR0 (0xFE0) +#define ARM_CS_PIDR1 (0xFE4) +#define ARM_CS_PIDR2 (0xFE8) +#define ARM_CS_PIDR3 (0xFEC) +#define ARM_CS_PIDR4 (0xFD0) +#define ARM_CS_PIDR5 (0xFD4) +#define ARM_CS_PIDR6 (0xFD8) +#define ARM_CS_PIDR7 (0xFDC) + +/* + * When PIDR bit JEDEC is zero, only the lowers 7 bits of DESIGNER are valid + * and represent a legacy ASCII Identity Code. + */ +#define ARM_CS_PIDR_PART(pidr) ((pidr) & 0x0FFF) +#define ARM_CS_PIDR_DESIGNER(pidr) \ +({ \ + typeof(pidr) _x = (pidr); \ + ((_x >> 25) & 0x780) | ((_x >> 12) & 0x7F); \ +}) +#define ARM_CS_PIDR_JEDEC BIT(19) +#define ARM_CS_PIDR_SIZE(pidr) (((pidr) >> 36) & 0x000F) + +#define ARM_CS_CIDR0 (0xFF0) +#define ARM_CS_CIDR1 (0xFF4) +#define ARM_CS_CIDR2 (0xFF8) +#define ARM_CS_CIDR3 (0xFFC) + +#define ARM_CS_CIDR_CLASS_MASK (0x0000F000) +#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) + +static inline bool is_valid_arm_cs_cidr(uint32_t cidr) +{ + return (cidr & ~ARM_CS_CIDR_CLASS_MASK) == 0xB105000D; +} + +/* Class 0x9 only registers */ +#define ARM_CS_C9_DEVARCH (0xFBC) + +#define ARM_CS_C9_DEVARCH_ARCHID_MASK (0x0000FFFF) +#define ARM_CS_C9_DEVARCH_ARCHID_SHIFT (0) +#define ARM_CS_C9_DEVARCH_REVISION_MASK (0x000F0000) +#define ARM_CS_C9_DEVARCH_REVISION_SHIFT (16) +#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) + +#define ARM_CS_C9_DEVID_FORMAT_MASK (0x0000000F) +#define ARM_CS_C9_DEVID_FORMAT_32BIT (0) +#define ARM_CS_C9_DEVID_FORMAT_64BIT (1) +#define ARM_CS_C9_DEVID_SYSMEM_MASK BIT(4) +#define ARM_CS_C9_DEVID_PRR_MASK BIT(5) +#define ARM_CS_C9_DEVID_CP_MASK BIT(5) + +#define ARM_CS_C9_DEVTYPE (0xFCC) + +#define ARM_CS_C9_DEVTYPE_MAJOR_MASK (0x0000000F) +#define ARM_CS_C9_DEVTYPE_MAJOR_SHIFT (0) +#define ARM_CS_C9_DEVTYPE_SUB_MASK (0x000000F0) +#define ARM_CS_C9_DEVTYPE_SUB_SHIFT (4) + +#define ARM_CS_C9_DEVTYPE_MASK (0x000000FF) +#define ARM_CS_C9_DEVTYPE_CORE_DEBUG (0x00000015) + +/* Class 0x1 only registers */ +#define ARM_CS_C1_MEMTYPE ARM_CS_C9_DEVTYPE + +#define ARM_CS_C1_MEMTYPE_SYSMEM_MASK BIT(0) + +/* The coding of ROM entry present differs between Class 0x9 and Class 0x1, + * but we can simplify the whole management */ +#define ARM_CS_ROMENTRY_PRESENT BIT(0) +#define ARM_CS_ROMENTRY_OFFSET_MASK (0xFFFFF000U) + +#endif /* OPENOCD_TARGET_ARM_CORESIGHT_H */ diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 579bacb774..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 @@ -31,28 +19,22 @@ #include "helper/command.h" struct arm_cti { - target_addr_t base; - struct adiv5_ap *ap; -}; - -struct arm_cti_object { struct list_head lh; - struct arm_cti cti; - int ap_num; char *name; + struct adiv5_mem_ap_spot spot; + struct adiv5_ap *ap; }; static LIST_HEAD(all_cti); const char *arm_cti_name(struct arm_cti *self) { - struct arm_cti_object *obj = container_of(self, struct arm_cti_object, cti); - return obj->name; + return self->name; } struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) { - struct arm_cti_object *obj = NULL; + struct arm_cti *obj = NULL; const char *name; bool found = false; @@ -66,17 +48,18 @@ struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) } if (found) - return &obj->cti; + return obj; return NULL; } static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t mask, uint32_t value) { + struct adiv5_ap *ap = self->ap; uint32_t tmp; /* Read register */ - int retval = mem_ap_read_atomic_u32(self->ap, self->base + reg, &tmp); - if (ERROR_OK != retval) + int retval = mem_ap_read_atomic_u32(ap, self->spot.base + reg, &tmp); + if (retval != ERROR_OK) return retval; /* clear bitfield */ @@ -85,26 +68,27 @@ static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t tmp |= value & mask; /* write new value */ - return mem_ap_write_atomic_u32(self->ap, self->base + reg, tmp); + return mem_ap_write_atomic_u32(ap, self->spot.base + reg, tmp); } int arm_cti_enable(struct arm_cti *self, bool enable) { uint32_t val = enable ? 1 : 0; - return mem_ap_write_atomic_u32(self->ap, self->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 = self->ap; int retval; uint32_t tmp; - retval = mem_ap_write_atomic_u32(self->ap, self->base + CTI_INACK, event); + retval = mem_ap_write_atomic_u32(ap, self->spot.base + CTI_INACK, event); if (retval == ERROR_OK) { int64_t then = timeval_ms(); for (;;) { - retval = mem_ap_read_atomic_u32(self->ap, self->base + CTI_TROUT_STATUS, &tmp); + retval = mem_ap_read_atomic_u32(ap, self->spot.base + CTI_TROUT_STATUS, &tmp); if (retval != ERROR_OK) break; if ((tmp & event) == 0) @@ -138,15 +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) { - return mem_ap_write_atomic_u32(self->ap, self->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) { - if (p_value == NULL) + if (!p_value) return ERROR_COMMAND_ARGUMENT_INVALID; - return mem_ap_read_atomic_u32(self->ap, self->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) @@ -225,9 +209,11 @@ static int cti_find_reg_offset(const char *name) int arm_cti_cleanup_all(void) { - struct arm_cti_object *obj, *tmp; + 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); } @@ -237,16 +223,16 @@ int arm_cti_cleanup_all(void) COMMAND_HANDLER(handle_cti_dump) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; + struct adiv5_ap *ap = cti->ap; int retval = ERROR_OK; for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++) - retval = mem_ap_read_u32(cti->ap, - cti->base + cti_names[i].offset, cti_names[i].p_val); + retval = mem_ap_read_u32(ap, + cti->spot.base + cti_names[i].offset, cti_names[i].p_val); if (retval == ERROR_OK) - retval = dap_run(cti->ap->dap); + retval = dap_run(ap->dap); if (retval != ERROR_OK) return JIM_ERR; @@ -260,8 +246,7 @@ COMMAND_HANDLER(handle_cti_dump) COMMAND_HANDLER(handle_cti_enable) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; bool on_off; if (CMD_ARGC != 1) @@ -274,8 +259,7 @@ COMMAND_HANDLER(handle_cti_enable) COMMAND_HANDLER(handle_cti_testmode) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; bool on_off; if (CMD_ARGC != 1) @@ -288,8 +272,7 @@ COMMAND_HANDLER(handle_cti_testmode) COMMAND_HANDLER(handle_cti_write) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; int offset; uint32_t value; @@ -307,8 +290,7 @@ COMMAND_HANDLER(handle_cti_write) COMMAND_HANDLER(handle_cti_read) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; int offset; int retval; uint32_t value; @@ -331,8 +313,7 @@ COMMAND_HANDLER(handle_cti_read) COMMAND_HANDLER(handle_cti_ack) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; uint32_t event; if (CMD_ARGC != 1) @@ -351,8 +332,7 @@ COMMAND_HANDLER(handle_cti_ack) COMMAND_HANDLER(handle_cti_channel) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; int retval = ERROR_OK; uint32_t ch_num; @@ -436,99 +416,47 @@ static const struct command_registration cti_instance_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -enum cti_cfg_param { - CFG_DAP, - CFG_AP_NUM, - CFG_CTIBASE -}; - -static const Jim_Nvp nvp_config_opts[] = { - { .name = "-dap", .value = CFG_DAP }, - { .name = "-ctibase", .value = CFG_CTIBASE }, - { .name = "-ap-num", .value = CFG_AP_NUM }, - { .name = NULL, .value = -1 } -}; - -static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti) +static int cti_configure(struct jim_getopt_info *goi, struct arm_cti *cti) { - struct adiv5_dap *dap = NULL; - Jim_Nvp *n; - jim_wide w; - int e; - /* parse config or cget options ... */ while (goi->argc > 0) { - Jim_SetEmptyResult(goi->interp); + int e = adiv5_jim_mem_ap_spot_configure(&cti->spot, goi); - e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); - return e; - } - switch (n->value) { - case CFG_DAP: { - Jim_Obj *o_t; - e = Jim_GetOpt_Obj(goi, &o_t); - if (e != JIM_OK) - return e; - dap = dap_instance_by_jim_obj(goi->interp, o_t); - if (dap == NULL) { - Jim_SetResultString(goi->interp, "-dap is invalid", -1); - return JIM_ERR; - } - /* loop for more */ - break; - } - case CFG_CTIBASE: - e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) - return e; - cti->cti.base = (uint32_t)w; - /* loop for more */ - break; + if (e == JIM_CONTINUE) + Jim_SetResultFormatted(goi->interp, "unknown option '%s'", + Jim_String(goi->argv[0])); - case CFG_AP_NUM: - e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) - return e; - if (w < 0 || w > DP_APSEL_MAX) { - Jim_SetResultString(goi->interp, "-ap-num is invalid", -1); - return JIM_ERR; - } - cti->ap_num = (uint32_t)w; - } + if (e != JIM_OK) + return JIM_ERR; } - if (dap == NULL) { + if (!cti->spot.dap) { Jim_SetResultString(goi->interp, "-dap required when creating CTI", -1); return JIM_ERR; } - cti->cti.ap = dap_ap(dap, cti->ap_num); - return JIM_OK; } - -static int cti_create(Jim_GetOptInfo *goi) +static int cti_create(struct jim_getopt_info *goi) { struct command_context *cmd_ctx; - static struct arm_cti_object *cti; + static struct arm_cti *cti; Jim_Obj *new_cmd; Jim_Cmd *cmd; const char *cp; int e; cmd_ctx = current_command_context(goi->interp); - assert(cmd_ctx != NULL); + assert(cmd_ctx); if (goi->argc < 3) { Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); return JIM_ERR; } /* COMMAND */ - Jim_GetOpt_Obj(goi, &new_cmd); + jim_getopt_obj(goi, &new_cmd); /* does this command exist? */ - cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG); + cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE); if (cmd) { cp = Jim_GetString(new_cmd, NULL); Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp); @@ -536,10 +464,14 @@ static int cti_create(Jim_GetOptInfo *goi) } /* Create it */ - cti = calloc(1, sizeof(struct arm_cti_object)); - if (cti == NULL) + cti = calloc(1, sizeof(*cti)); + if (!cti) return JIM_ERR; + adiv5_mem_ap_spot_init(&cti->spot); + + /* Do the rest as "configure" options */ + goi->isconfigure = 1; e = cti_configure(goi, cti); if (e != JIM_OK) { free(cti); @@ -566,23 +498,25 @@ static int cti_create(Jim_GetOptInfo *goi) }, COMMAND_REGISTRATION_DONE }; - e = register_commands(cmd_ctx, NULL, cti_commands); - if (ERROR_OK != e) + e = register_commands_with_data(cmd_ctx, NULL, cti_commands, cti); + if (e != ERROR_OK) return JIM_ERR; - struct command *c = command_find_in_context(cmd_ctx, cp); - assert(c); - command_set_handler_data(c, cti); - list_add_tail(&cti->lh, &all_cti); - return (ERROR_OK == e) ? JIM_OK : JIM_ERR; + 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; } static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - Jim_GetOptInfo goi; - Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); + struct jim_getopt_info goi; + jim_getopt_setup(&goi, interp, argc - 1, argv + 1); if (goi.argc < 2) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "<name> [<cti_options> ...]"); @@ -591,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_object *obj; + 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; } @@ -619,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 56442f1835..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,13 +36,16 @@ 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 */ dap->ap[i].tar_autoincr_block = (1<<10); /* 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); @@ -102,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 ..."); @@ -126,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; @@ -141,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); @@ -154,63 +181,159 @@ int dap_cleanup_all(void) enum dap_cfg_param { CFG_CHAIN_POSITION, CFG_IGNORE_SYSPWRUPACK, + CFG_DP_ID, + CFG_INSTANCE_ID, + CFG_ADIV6, + CFG_ADIV5, }; -static const Jim_Nvp nvp_config_opts[] = { - { .name = "-chain-position", .value = CFG_CHAIN_POSITION }, +static const struct jim_nvp nvp_config_opts[] = { + { .name = "-chain-position", .value = CFG_CHAIN_POSITION }, { .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 } }; -static int dap_configure(Jim_GetOptInfo *goi, struct arm_dap_object *dap) +static int dap_configure(struct jim_getopt_info *goi, struct arm_dap_object *dap) { - struct jtag_tap *tap = NULL; - Jim_Nvp *n; + struct jim_nvp *n; int e; - /* parse config or cget options ... */ + /* parse config ... */ while (goi->argc > 0) { Jim_SetEmptyResult(goi->interp); - e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); + e = jim_getopt_nvp(goi, nvp_config_opts, &n); if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); + jim_getopt_nvp_unknown(goi, nvp_config_opts, 0); return e; } switch (n->value) { case CFG_CHAIN_POSITION: { Jim_Obj *o_t; - e = Jim_GetOpt_Obj(goi, &o_t); + e = jim_getopt_obj(goi, &o_t); if (e != JIM_OK) return e; + + struct jtag_tap *tap; tap = jtag_tap_by_jim_obj(goi->interp, o_t); - if (tap == NULL) { + if (!tap) { Jim_SetResultString(goi->interp, "-chain-position is invalid", -1); return JIM_ERR; } + dap->dap.tap = tap; /* loop for more */ break; } case CFG_IGNORE_SYSPWRUPACK: dap->dap.ignore_syspwrupack = true; break; + case CFG_DP_ID: { + jim_wide w; + e = jim_getopt_wide(goi, &w); + if (e != JIM_OK) { + Jim_SetResultFormatted(goi->interp, + "create %s: bad parameter %s", + dap->name, n->name); + return JIM_ERR; + } + if (w < 0 || w > DP_TARGETSEL_DPID_MASK) { + Jim_SetResultFormatted(goi->interp, + "create %s: %s out of range", + dap->name, n->name); + return JIM_ERR; + } + dap->dap.multidrop_targetsel = + (dap->dap.multidrop_targetsel & DP_TARGETSEL_INSTANCEID_MASK) + | (w & DP_TARGETSEL_DPID_MASK); + dap->dap.multidrop_dp_id_valid = true; + break; + } + case CFG_INSTANCE_ID: { + jim_wide w; + e = jim_getopt_wide(goi, &w); + if (e != JIM_OK) { + Jim_SetResultFormatted(goi->interp, + "create %s: bad parameter %s", + dap->name, n->name); + return JIM_ERR; + } + if (w < 0 || w > 15) { + Jim_SetResultFormatted(goi->interp, + "create %s: %s out of range", + dap->name, n->name); + return JIM_ERR; + } + dap->dap.multidrop_targetsel = + (dap->dap.multidrop_targetsel & DP_TARGETSEL_DPID_MASK) + | ((w << DP_TARGETSEL_INSTANCEID_SHIFT) & DP_TARGETSEL_INSTANCEID_MASK); + 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; } } - if (tap == NULL) { - Jim_SetResultString(goi->interp, "-chain-position required when creating DAP", -1); - return JIM_ERR; + return JIM_OK; +} + +static int dap_check_config(struct adiv5_dap *dap) +{ + if (transport_is_jtag() || transport_is_dapdirect_jtag() || transport_is_hla()) + return ERROR_OK; + + struct arm_dap_object *obj; + bool new_multidrop = dap_is_multidrop(dap); + bool had_multidrop = new_multidrop; + uint32_t targetsel = dap->multidrop_targetsel; + unsigned int non_multidrop_count = had_multidrop ? 0 : 1; + + list_for_each_entry(obj, &all_dap, lh) { + struct adiv5_dap *dap_it = &obj->dap; + + if (transport_is_swd()) { + if (dap_is_multidrop(dap_it)) { + had_multidrop = true; + if (new_multidrop && dap_it->multidrop_targetsel == targetsel) { + uint32_t dp_id = targetsel & DP_TARGETSEL_DPID_MASK; + uint32_t instance_id = targetsel >> DP_TARGETSEL_INSTANCEID_SHIFT; + LOG_ERROR("%s and %s have the same multidrop selectors -dp-id 0x%08" + PRIx32 " and -instance-id 0x%" PRIx32, + obj->name, adiv5_dap_name(dap), + dp_id, instance_id); + return ERROR_FAIL; + } + } else { + non_multidrop_count++; + } + } else if (transport_is_dapdirect_swd()) { + non_multidrop_count++; + } } - dap_instance_init(&dap->dap); - dap->dap.tap = tap; + if (non_multidrop_count > 1) { + LOG_ERROR("Two or more SWD non multidrop DAPs are not supported"); + return ERROR_FAIL; + } + if (had_multidrop && non_multidrop_count) { + LOG_ERROR("Mixing of SWD multidrop DAPs and non multidrop DAPs is not supported"); + return ERROR_FAIL; + } - return JIM_OK; + return ERROR_OK; } -static int dap_create(Jim_GetOptInfo *goi) +static int dap_create(struct jim_getopt_info *goi) { struct command_context *cmd_ctx; static struct arm_dap_object *dap; @@ -220,16 +343,16 @@ static int dap_create(Jim_GetOptInfo *goi) int e; cmd_ctx = current_command_context(goi->interp); - assert(cmd_ctx != NULL); + assert(cmd_ctx); if (goi->argc < 3) { Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); return JIM_ERR; } /* COMMAND */ - Jim_GetOpt_Obj(goi, &new_cmd); + jim_getopt_obj(goi, &new_cmd); /* does this command exist? */ - cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG); + cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE); if (cmd) { cp = Jim_GetString(new_cmd, NULL); Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp); @@ -238,19 +361,31 @@ static int dap_create(Jim_GetOptInfo *goi) /* Create it */ dap = calloc(1, sizeof(struct arm_dap_object)); - if (dap == NULL) + if (!dap) return JIM_ERR; - e = dap_configure(goi, dap); - if (e != JIM_OK) { - free(dap); - return e; - } + dap_instance_init(&dap->dap); cp = Jim_GetString(new_cmd, NULL); dap->name = strdup(cp); - struct command_registration dap_commands[] = { + e = dap_configure(goi, dap); + if (e != JIM_OK) + goto err; + + if (!dap->dap.tap) { + Jim_SetResultString(goi->interp, "-chain-position required when creating DAP", -1); + e = JIM_ERR; + goto err; + } + + e = dap_check_config(&dap->dap); + if (e != ERROR_OK) { + e = JIM_ERR; + goto err; + } + + struct command_registration dap_create_commands[] = { { .name = cp, .mode = COMMAND_ANY, @@ -263,25 +398,28 @@ static int dap_create(Jim_GetOptInfo *goi) /* don't expose the instance commands when using hla */ if (transport_is_hla()) - dap_commands[0].chain = NULL; + dap_create_commands[0].chain = NULL; - e = register_commands(cmd_ctx, NULL, dap_commands); - if (ERROR_OK != e) - return JIM_ERR; - - struct command *c = command_find_in_context(cmd_ctx, cp); - assert(c); - command_set_handler_data(c, dap); + e = register_commands_with_data(cmd_ctx, NULL, dap_create_commands, dap); + if (e != ERROR_OK) { + e = JIM_ERR; + goto err; + } list_add_tail(&dap->lh, &all_dap); - return (ERROR_OK == e) ? JIM_OK : JIM_ERR; + return JIM_OK; + +err: + free(dap->name); + free(dap); + return e; } static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - Jim_GetOptInfo goi; - Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); + struct jim_getopt_info goi; + jim_getopt_setup(&goi, interp, argc - 1, argv + 1); if (goi.argc < 2) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "<name> [<dap_options> ...]"); @@ -290,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) @@ -316,9 +450,9 @@ 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 == NULL) { + if (!dap) { LOG_ERROR("DAP instance not available. Probably a HLA target..."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -328,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[] = { @@ -350,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", }, @@ -365,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 59c0537b7d..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 @@ -26,6 +15,10 @@ #include "arm_disassembler.h" #include <helper/log.h> +#if HAVE_CAPSTONE +#include <capstone.h> +#endif + /* * This disassembler supports two main functions for OpenOCD: * @@ -119,36 +112,36 @@ static int evaluate_pld(uint32_t opcode, { /* PLD */ if ((opcode & 0x0d30f000) == 0x0510f000) { - uint8_t Rn; - uint8_t U; + uint8_t rn; + uint8_t u; unsigned offset; instruction->type = ARM_PLD; - Rn = (opcode & 0xf0000) >> 16; - U = (opcode & 0x00800000) >> 23; - if (Rn == 0xf) { + rn = (opcode & 0xf0000) >> 16; + u = (opcode & 0x00800000) >> 23; + if (rn == 0xf) { /* literal */ offset = opcode & 0x0fff; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD %s%d", - address, opcode, U ? "" : "-", offset); + address, opcode, u ? "" : "-", offset); } else { - uint8_t I, R; + uint8_t i, r; - I = (opcode & 0x02000000) >> 25; - R = (opcode & 0x00400000) >> 22; + i = (opcode & 0x02000000) >> 25; + r = (opcode & 0x00400000) >> 22; - if (I) { + if (i) { /* register PLD{W} [<Rn>,+/-<Rm>{, <shift>}] */ offset = (opcode & 0x0F80) >> 7; - uint8_t Rm; - Rm = opcode & 0xf; + uint8_t rm; + rm = opcode & 0xf; if (offset == 0) { /* No shift */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d]", - address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm); + address, opcode, r ? "" : "W", rn, u ? "" : "-", rm); } else { uint8_t shift; @@ -158,22 +151,22 @@ static int evaluate_pld(uint32_t opcode, /* LSL */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSL #0x%x)", - address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset); + address, opcode, r ? "" : "W", rn, u ? "" : "-", rm, offset); } else if (shift == 0x1) { /* LSR */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSR #0x%x)", - address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset); + address, opcode, r ? "" : "W", rn, u ? "" : "-", rm, offset); } else if (shift == 0x2) { /* ASR */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ASR #0x%x)", - address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset); + address, opcode, r ? "" : "W", rn, u ? "" : "-", rm, offset); } else if (shift == 0x3) { /* ROR */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ROR #0x%x)", - address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset); + address, opcode, r ? "" : "W", rn, u ? "" : "-", rm, offset); } } } else { @@ -182,11 +175,11 @@ static int evaluate_pld(uint32_t opcode, if (offset == 0) { snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d]", - address, opcode, R ? "" : "W", Rn); + address, opcode, r ? "" : "W", rn); } else { snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, #%s%d]", - address, opcode, R ? "" : "W", Rn, U ? "" : "-", offset); + address, opcode, r ? "" : "W", rn, u ? "" : "-", offset); } } } @@ -345,13 +338,13 @@ static int evaluate_blx_imm(uint32_t opcode, static int evaluate_b_bl(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { - uint8_t L; + uint8_t l; uint32_t immediate; int offset; uint32_t target_address; immediate = opcode & 0x00ffffff; - L = (opcode & 0x01000000) >> 24; + l = (opcode & 0x01000000) >> 24; /* sign extend 24-bit immediate */ if (immediate & 0x00800000) @@ -364,7 +357,7 @@ static int evaluate_b_bl(uint32_t opcode, target_address = address + 8 + offset; - if (L) + if (l) instruction->type = ARM_BL; else instruction->type = ARM_B; @@ -374,7 +367,7 @@ static int evaluate_b_bl(uint32_t opcode, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tB%s%s 0x%8.8" PRIx32, address, opcode, - (L) ? "L" : "", + (l) ? "L" : "", COND(opcode), target_address); @@ -393,13 +386,13 @@ static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode, /* MCRR or MRRC */ if (((opcode & 0x0ff00000) == 0x0c400000) || ((opcode & 0x0ff00000) == 0x0c500000)) { - uint8_t cp_opcode, Rd, Rn, CRm; + uint8_t cp_opcode, rd, rn, crm; char *mnemonic; cp_opcode = (opcode & 0xf0) >> 4; - Rd = (opcode & 0xf000) >> 12; - Rn = (opcode & 0xf0000) >> 16; - CRm = (opcode & 0xf); + rd = (opcode & 0xf000) >> 12; + rn = (opcode & 0xf0000) >> 16; + crm = (opcode & 0xf); /* MCRR */ if ((opcode & 0x0ff00000) == 0x0c400000) { @@ -420,15 +413,15 @@ static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode, address, opcode, mnemonic, ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode), - COND(opcode), cp_num, cp_opcode, Rd, Rn, CRm); + COND(opcode), cp_num, cp_opcode, rd, rn, crm); } else {/* LDC or STC */ - uint8_t CRd, Rn, offset; - uint8_t U; + uint8_t crd, rn, offset; + uint8_t u; char *mnemonic; char addressing_mode[32]; - CRd = (opcode & 0xf000) >> 12; - Rn = (opcode & 0xf0000) >> 16; + crd = (opcode & 0xf000) >> 12; + rn = (opcode & 0xf0000) >> 16; offset = (opcode & 0xff) << 2; /* load/store */ @@ -440,21 +433,21 @@ static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode, mnemonic = "STC"; } - U = (opcode & 0x00800000) >> 23; + u = (opcode & 0x00800000) >> 23; /* addressing modes */ if ((opcode & 0x01200000) == 0x01000000)/* offset */ snprintf(addressing_mode, 32, "[r%i, #%s%d]", - Rn, U ? "" : "-", offset); + rn, u ? "" : "-", offset); else if ((opcode & 0x01200000) == 0x01200000) /* pre-indexed */ snprintf(addressing_mode, 32, "[r%i, #%s%d]!", - Rn, U ? "" : "-", offset); + rn, u ? "" : "-", offset); else if ((opcode & 0x01200000) == 0x00200000) /* post-indexed */ snprintf(addressing_mode, 32, "[r%i], #%s%d", - Rn, U ? "" : "-", offset); + rn, u ? "" : "-", offset); else if ((opcode & 0x01200000) == 0x00000000) /* unindexed */ snprintf(addressing_mode, 32, "[r%i], {%d}", - Rn, offset >> 2); + rn, offset >> 2); snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 @@ -463,7 +456,7 @@ static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode, ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode), (opcode & (1 << 22)) ? "L" : "", - cp_num, CRd, addressing_mode); + cp_num, crd, addressing_mode); } return ERROR_OK; @@ -477,13 +470,13 @@ static int evaluate_cdp_mcr_mrc(uint32_t opcode, { const char *cond; char *mnemonic; - uint8_t cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2; + uint8_t cp_num, opcode_1, crd_rd, crn, crm, opcode_2; cond = ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode); cp_num = (opcode & 0xf00) >> 8; - CRd_Rd = (opcode & 0xf000) >> 12; - CRn = (opcode & 0xf0000) >> 16; - CRm = (opcode & 0xf); + crd_rd = (opcode & 0xf000) >> 12; + crn = (opcode & 0xf0000) >> 16; + crm = (opcode & 0xf); opcode_2 = (opcode & 0xe0) >> 5; /* CDP or MRC/MCR */ @@ -507,9 +500,9 @@ static int evaluate_cdp_mcr_mrc(uint32_t opcode, cond, cp_num, opcode_1, - CRd_Rd, - CRn, - CRm, + crd_rd, + crn, + crm, opcode_2); } else {/* bit 4 not set -> CDP */ instruction->type = ARM_CDP; @@ -526,9 +519,9 @@ static int evaluate_cdp_mcr_mrc(uint32_t opcode, cond, cp_num, opcode_1, - CRd_Rd, - CRn, - CRm, + crd_rd, + crn, + crm, opcode_2); } @@ -539,60 +532,60 @@ static int evaluate_cdp_mcr_mrc(uint32_t opcode, static int evaluate_load_store(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { - uint8_t I, P, U, B, W, L; - uint8_t Rn, Rd; + uint8_t i, p, u, b, w, l; + uint8_t rn, rd; char *operation;/* "LDR" or "STR" */ char *suffix; /* "", "B", "T", "BT" */ char offset[32]; /* examine flags */ - I = (opcode & 0x02000000) >> 25; - P = (opcode & 0x01000000) >> 24; - U = (opcode & 0x00800000) >> 23; - B = (opcode & 0x00400000) >> 22; - W = (opcode & 0x00200000) >> 21; - L = (opcode & 0x00100000) >> 20; + i = (opcode & 0x02000000) >> 25; + p = (opcode & 0x01000000) >> 24; + u = (opcode & 0x00800000) >> 23; + b = (opcode & 0x00400000) >> 22; + w = (opcode & 0x00200000) >> 21; + l = (opcode & 0x00100000) >> 20; /* target register */ - Rd = (opcode & 0xf000) >> 12; + rd = (opcode & 0xf000) >> 12; /* base register */ - Rn = (opcode & 0xf0000) >> 16; + rn = (opcode & 0xf0000) >> 16; - instruction->info.load_store.Rd = Rd; - instruction->info.load_store.Rn = Rn; - instruction->info.load_store.U = U; + instruction->info.load_store.rd = rd; + instruction->info.load_store.rn = rn; + instruction->info.load_store.u = u; /* determine operation */ - if (L) + if (l) operation = "LDR"; else operation = "STR"; /* determine instruction type and suffix */ - if (B) { - if ((P == 0) && (W == 1)) { - if (L) + if (b) { + if ((p == 0) && (w == 1)) { + if (l) instruction->type = ARM_LDRBT; else instruction->type = ARM_STRBT; suffix = "BT"; } else { - if (L) + if (l) instruction->type = ARM_LDRB; else instruction->type = ARM_STRB; suffix = "B"; } } else { - if ((P == 0) && (W == 1)) { - if (L) + if ((p == 0) && (w == 1)) { + if (l) instruction->type = ARM_LDRT; else instruction->type = ARM_STRT; suffix = "T"; } else { - if (L) + if (l) instruction->type = ARM_LDR; else instruction->type = ARM_STR; @@ -600,10 +593,10 @@ static int evaluate_load_store(uint32_t opcode, } } - if (!I) { /* #+-<offset_12> */ + if (!i) { /* #+-<offset_12> */ uint32_t offset_12 = (opcode & 0xfff); if (offset_12) - snprintf(offset, 32, ", #%s0x%" PRIx32 "", (U) ? "" : "-", offset_12); + snprintf(offset, 32, ", #%s0x%" PRIx32 "", (u) ? "" : "-", offset_12); else snprintf(offset, 32, "%s", ""); @@ -611,11 +604,11 @@ static int evaluate_load_store(uint32_t opcode, instruction->info.load_store.offset.offset = offset_12; } else {/* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */ uint8_t shift_imm, shift; - uint8_t Rm; + uint8_t rm; shift_imm = (opcode & 0xf80) >> 7; shift = (opcode & 0x60) >> 5; - Rm = (opcode & 0xf); + rm = (opcode & 0xf); /* LSR encodes a shift by 32 bit as 0x0 */ if ((shift == 0x1) && (shift_imm == 0x0)) @@ -630,35 +623,35 @@ static int evaluate_load_store(uint32_t opcode, shift = 0x4; instruction->info.load_store.offset_mode = 1; - instruction->info.load_store.offset.reg.Rm = Rm; + instruction->info.load_store.offset.reg.rm = rm; instruction->info.load_store.offset.reg.shift = shift; instruction->info.load_store.offset.reg.shift_imm = shift_imm; if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */ - snprintf(offset, 32, ", %sr%i", (U) ? "" : "-", Rm); + snprintf(offset, 32, ", %sr%i", (u) ? "" : "-", rm); else { /* +-<Rm>, <Shift>, #<shift_imm> */ switch (shift) { case 0x0: /* LSL */ - snprintf(offset, 32, ", %sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm); + snprintf(offset, 32, ", %sr%i, LSL #0x%x", (u) ? "" : "-", rm, shift_imm); break; case 0x1: /* LSR */ - snprintf(offset, 32, ", %sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm); + snprintf(offset, 32, ", %sr%i, LSR #0x%x", (u) ? "" : "-", rm, shift_imm); break; case 0x2: /* ASR */ - snprintf(offset, 32, ", %sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm); + snprintf(offset, 32, ", %sr%i, ASR #0x%x", (u) ? "" : "-", rm, shift_imm); break; case 0x3: /* ROR */ - snprintf(offset, 32, ", %sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm); + snprintf(offset, 32, ", %sr%i, ROR #0x%x", (u) ? "" : "-", rm, shift_imm); break; case 0x4: /* RRX */ - snprintf(offset, 32, ", %sr%i, RRX", (U) ? "" : "-", Rm); + snprintf(offset, 32, ", %sr%i, RRX", (u) ? "" : "-", rm); break; } } } - if (P == 1) { - if (W == 0) { /* offset */ + if (p == 1) { + if (w == 0) { /* offset */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i%s]", @@ -667,8 +660,8 @@ static int evaluate_load_store(uint32_t opcode, operation, COND(opcode), suffix, - Rd, - Rn, + rd, + rn, offset); instruction->info.load_store.index_mode = 0; @@ -681,8 +674,8 @@ static int evaluate_load_store(uint32_t opcode, operation, COND(opcode), suffix, - Rd, - Rn, + rd, + rn, offset); instruction->info.load_store.index_mode = 1; @@ -696,8 +689,8 @@ static int evaluate_load_store(uint32_t opcode, operation, COND(opcode), suffix, - Rd, - Rn, + rd, + rn, offset); instruction->info.load_store.index_mode = 2; @@ -1025,35 +1018,35 @@ undef: static int evaluate_misc_load_store(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { - uint8_t P, U, I, W, L, S, H; - uint8_t Rn, Rd; + uint8_t p, u, i, w, l, s, h; + uint8_t rn, rd; char *operation;/* "LDR" or "STR" */ char *suffix; /* "H", "SB", "SH", "D" */ char offset[32]; /* examine flags */ - P = (opcode & 0x01000000) >> 24; - U = (opcode & 0x00800000) >> 23; - I = (opcode & 0x00400000) >> 22; - W = (opcode & 0x00200000) >> 21; - L = (opcode & 0x00100000) >> 20; - S = (opcode & 0x00000040) >> 6; - H = (opcode & 0x00000020) >> 5; + p = (opcode & 0x01000000) >> 24; + u = (opcode & 0x00800000) >> 23; + i = (opcode & 0x00400000) >> 22; + w = (opcode & 0x00200000) >> 21; + l = (opcode & 0x00100000) >> 20; + s = (opcode & 0x00000040) >> 6; + h = (opcode & 0x00000020) >> 5; /* target register */ - Rd = (opcode & 0xf000) >> 12; + rd = (opcode & 0xf000) >> 12; /* base register */ - Rn = (opcode & 0xf0000) >> 16; + rn = (opcode & 0xf0000) >> 16; - instruction->info.load_store.Rd = Rd; - instruction->info.load_store.Rn = Rn; - instruction->info.load_store.U = U; + instruction->info.load_store.rd = rd; + instruction->info.load_store.rn = rn; + instruction->info.load_store.u = u; /* determine instruction type and suffix */ - if (S) {/* signed */ - if (L) {/* load */ - if (H) { + if (s) {/* signed */ + if (l) {/* load */ + if (h) { operation = "LDR"; instruction->type = ARM_LDRSH; suffix = "SH"; @@ -1065,7 +1058,7 @@ static int evaluate_misc_load_store(uint32_t opcode, } else {/* there are no signed stores, so this is used to encode double-register *load/stores */ suffix = "D"; - if (H) { + if (h) { operation = "STR"; instruction->type = ARM_STRD; } else { @@ -1075,7 +1068,7 @@ static int evaluate_misc_load_store(uint32_t opcode, } } else {/* unsigned */ suffix = "H"; - if (L) {/* load */ + if (l) {/* load */ operation = "LDR"; instruction->type = ARM_LDRH; } else {/* store */ @@ -1084,25 +1077,25 @@ static int evaluate_misc_load_store(uint32_t opcode, } } - if (I) {/* Immediate offset/index (#+-<offset_8>)*/ + if (i) {/* Immediate offset/index (#+-<offset_8>)*/ uint32_t offset_8 = ((opcode & 0xf00) >> 4) | (opcode & 0xf); - snprintf(offset, 32, "#%s0x%" PRIx32 "", (U) ? "" : "-", offset_8); + snprintf(offset, 32, "#%s0x%" PRIx32 "", (u) ? "" : "-", offset_8); instruction->info.load_store.offset_mode = 0; instruction->info.load_store.offset.offset = offset_8; } else {/* Register offset/index (+-<Rm>) */ - uint8_t Rm; - Rm = (opcode & 0xf); - snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm); + uint8_t rm; + rm = (opcode & 0xf); + snprintf(offset, 32, "%sr%i", (u) ? "" : "-", rm); instruction->info.load_store.offset_mode = 1; - instruction->info.load_store.offset.reg.Rm = Rm; + instruction->info.load_store.offset.reg.rm = rm; instruction->info.load_store.offset.reg.shift = 0x0; instruction->info.load_store.offset.reg.shift_imm = 0x0; } - if (P == 1) { - if (W == 0) { /* offset */ + if (p == 1) { + if (w == 0) { /* offset */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]", @@ -1111,8 +1104,8 @@ static int evaluate_misc_load_store(uint32_t opcode, operation, COND(opcode), suffix, - Rd, - Rn, + rd, + rn, offset); instruction->info.load_store.index_mode = 0; @@ -1125,8 +1118,8 @@ static int evaluate_misc_load_store(uint32_t opcode, operation, COND(opcode), suffix, - Rd, - Rn, + rd, + rn, offset); instruction->info.load_store.index_mode = 1; @@ -1140,8 +1133,8 @@ static int evaluate_misc_load_store(uint32_t opcode, operation, COND(opcode), suffix, - Rd, - Rn, + rd, + rn, offset); instruction->info.load_store.index_mode = 2; @@ -1154,7 +1147,7 @@ static int evaluate_misc_load_store(uint32_t opcode, static int evaluate_ldm_stm(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { - uint8_t P, U, S, W, L, Rn; + uint8_t p, u, s, w, l, rn; uint32_t register_list; char *addressing_mode; char *mnemonic; @@ -1163,20 +1156,20 @@ static int evaluate_ldm_stm(uint32_t opcode, int i; int first_reg = 1; - P = (opcode & 0x01000000) >> 24; - U = (opcode & 0x00800000) >> 23; - S = (opcode & 0x00400000) >> 22; - W = (opcode & 0x00200000) >> 21; - L = (opcode & 0x00100000) >> 20; + p = (opcode & 0x01000000) >> 24; + u = (opcode & 0x00800000) >> 23; + s = (opcode & 0x00400000) >> 22; + w = (opcode & 0x00200000) >> 21; + l = (opcode & 0x00100000) >> 20; register_list = (opcode & 0xffff); - Rn = (opcode & 0xf0000) >> 16; + rn = (opcode & 0xf0000) >> 16; - instruction->info.load_store_multiple.Rn = Rn; + instruction->info.load_store_multiple.rn = rn; instruction->info.load_store_multiple.register_list = register_list; - instruction->info.load_store_multiple.S = S; - instruction->info.load_store_multiple.W = W; + instruction->info.load_store_multiple.s = s; + instruction->info.load_store_multiple.w = w; - if (L) { + if (l) { instruction->type = ARM_LDM; mnemonic = "LDM"; } else { @@ -1184,8 +1177,8 @@ static int evaluate_ldm_stm(uint32_t opcode, mnemonic = "STM"; } - if (P) { - if (U) { + if (p) { + if (u) { instruction->info.load_store_multiple.addressing_mode = 1; addressing_mode = "IB"; } else { @@ -1193,7 +1186,7 @@ static int evaluate_ldm_stm(uint32_t opcode, addressing_mode = "DB"; } } else { - if (U) { + if (u) { instruction->info.load_store_multiple.addressing_mode = 0; /* "IA" is the default in UAL syntax */ addressing_mode = ""; @@ -1225,7 +1218,7 @@ static int evaluate_ldm_stm(uint32_t opcode, "\t%s%s%s r%i%s, {%s}%s", address, opcode, mnemonic, addressing_mode, COND(opcode), - Rn, (W) ? "!" : "", reg_list, (S) ? "^" : ""); + rn, (w) ? "!" : "", reg_list, (s) ? "^" : ""); return ERROR_OK; } @@ -1238,12 +1231,12 @@ static int evaluate_mul_and_extra_ld_st(uint32_t opcode, if ((opcode & 0x000000f0) == 0x00000090) { /* Multiply (accumulate) */ if ((opcode & 0x0f800000) == 0x00000000) { - uint8_t Rm, Rs, Rn, Rd, S; - Rm = opcode & 0xf; - Rs = (opcode & 0xf00) >> 8; - Rn = (opcode & 0xf000) >> 12; - Rd = (opcode & 0xf0000) >> 16; - S = (opcode & 0x00100000) >> 20; + uint8_t rm, rs, rn, rd, s; + rm = opcode & 0xf; + rs = (opcode & 0xf00) >> 8; + rn = (opcode & 0xf000) >> 12; + rd = (opcode & 0xf0000) >> 16; + s = (opcode & 0x00100000) >> 20; /* examine A bit (accumulate) */ if (opcode & 0x00200000) { @@ -1254,11 +1247,11 @@ static int evaluate_mul_and_extra_ld_st(uint32_t opcode, address, opcode, COND(opcode), - (S) ? "S" : "", - Rd, - Rm, - Rs, - Rn); + (s) ? "S" : "", + rd, + rm, + rs, + rn); } else { instruction->type = ARM_MUL; snprintf(instruction->text, @@ -1267,10 +1260,10 @@ static int evaluate_mul_and_extra_ld_st(uint32_t opcode, address, opcode, COND(opcode), - (S) ? "S" : "", - Rd, - Rm, - Rs); + (s) ? "S" : "", + rd, + rm, + rs); } return ERROR_OK; @@ -1279,12 +1272,12 @@ static int evaluate_mul_and_extra_ld_st(uint32_t opcode, /* Multiply (accumulate) long */ if ((opcode & 0x0f800000) == 0x00800000) { char *mnemonic = NULL; - uint8_t Rm, Rs, RdHi, RdLow, S; - Rm = opcode & 0xf; - Rs = (opcode & 0xf00) >> 8; - RdHi = (opcode & 0xf000) >> 12; - RdLow = (opcode & 0xf0000) >> 16; - S = (opcode & 0x00100000) >> 20; + uint8_t rm, rs, rd_hi, rd_low, s; + rm = opcode & 0xf; + rs = (opcode & 0xf00) >> 8; + rd_hi = (opcode & 0xf000) >> 12; + rd_low = (opcode & 0xf0000) >> 16; + s = (opcode & 0x00100000) >> 20; switch ((opcode & 0x00600000) >> 21) { case 0x0: @@ -1312,21 +1305,21 @@ static int evaluate_mul_and_extra_ld_st(uint32_t opcode, opcode, mnemonic, COND(opcode), - (S) ? "S" : "", - RdLow, - RdHi, - Rm, - Rs); + (s) ? "S" : "", + rd_low, + rd_hi, + rm, + rs); return ERROR_OK; } /* Swap/swap byte */ if ((opcode & 0x0f800000) == 0x01000000) { - uint8_t Rm, Rd, Rn; - Rm = opcode & 0xf; - Rd = (opcode & 0xf000) >> 12; - Rn = (opcode & 0xf0000) >> 16; + uint8_t rm, rd, rn; + rm = opcode & 0xf; + rd = (opcode & 0xf000) >> 12; + rn = (opcode & 0xf0000) >> 16; /* examine B flag */ instruction->type = (opcode & 0x00400000) ? ARM_SWPB : ARM_SWP; @@ -1338,9 +1331,9 @@ static int evaluate_mul_and_extra_ld_st(uint32_t opcode, opcode, (opcode & 0x00400000) ? "SWPB" : "SWP", COND(opcode), - Rd, - Rm, - Rn); + rd, + rm, + rn); return ERROR_OK; } @@ -1352,8 +1345,8 @@ static int evaluate_mul_and_extra_ld_st(uint32_t opcode, static int evaluate_mrs_msr(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { - int R = (opcode & 0x00400000) >> 22; - char *PSR = (R) ? "SPSR" : "CPSR"; + int r = (opcode & 0x00400000) >> 22; + char *PSR = (r) ? "SPSR" : "CPSR"; /* Move register to status register (MSR) */ if (opcode & 0x00200000) { @@ -1378,7 +1371,7 @@ static int evaluate_mrs_msr(uint32_t opcode, ror(immediate, (rotate * 2)) ); } else {/* register variant */ - uint8_t Rm = opcode & 0xf; + uint8_t rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, r%i", @@ -1390,15 +1383,15 @@ static int evaluate_mrs_msr(uint32_t opcode, (opcode & 0x20000) ? "x" : "", (opcode & 0x40000) ? "s" : "", (opcode & 0x80000) ? "f" : "", - Rm + rm ); } } else {/* Move status register to register (MRS) */ - uint8_t Rd; + uint8_t rd; instruction->type = ARM_MRS; - Rd = (opcode & 0x0000f000) >> 12; + rd = (opcode & 0x0000f000) >> 12; snprintf(instruction->text, 128, @@ -1406,7 +1399,7 @@ static int evaluate_mrs_msr(uint32_t opcode, address, opcode, COND(opcode), - Rd, + rd, PSR); } @@ -1423,37 +1416,37 @@ static int evaluate_misc_instr(uint32_t opcode, /* BX */ if ((opcode & 0x006000f0) == 0x00200010) { - uint8_t Rm; + uint8_t rm; instruction->type = ARM_BX; - Rm = opcode & 0xf; + rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBX%s r%i", - address, opcode, COND(opcode), Rm); + address, opcode, COND(opcode), rm); - instruction->info.b_bl_bx_blx.reg_operand = Rm; + instruction->info.b_bl_bx_blx.reg_operand = rm; instruction->info.b_bl_bx_blx.target_address = -1; } /* BXJ - "Jazelle" support (ARMv5-J) */ if ((opcode & 0x006000f0) == 0x00200020) { - uint8_t Rm; + uint8_t rm; instruction->type = ARM_BX; - Rm = opcode & 0xf; + rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBXJ%s r%i", - address, opcode, COND(opcode), Rm); + address, opcode, COND(opcode), rm); - instruction->info.b_bl_bx_blx.reg_operand = Rm; + instruction->info.b_bl_bx_blx.reg_operand = rm; instruction->info.b_bl_bx_blx.target_address = -1; } /* CLZ */ if ((opcode & 0x006000f0) == 0x00600010) { - uint8_t Rm, Rd; + uint8_t rm, rd; instruction->type = ARM_CLZ; - Rm = opcode & 0xf; - Rd = (opcode & 0xf000) >> 12; + rm = opcode & 0xf; + rd = (opcode & 0xf000) >> 12; snprintf(instruction->text, 128, @@ -1461,30 +1454,30 @@ static int evaluate_misc_instr(uint32_t opcode, address, opcode, COND(opcode), - Rd, - Rm); + rd, + rm); } /* BLX(2) */ if ((opcode & 0x006000f0) == 0x00200030) { - uint8_t Rm; + uint8_t rm; instruction->type = ARM_BLX; - Rm = opcode & 0xf; + rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX%s r%i", - address, opcode, COND(opcode), Rm); + address, opcode, COND(opcode), rm); - instruction->info.b_bl_bx_blx.reg_operand = Rm; + instruction->info.b_bl_bx_blx.reg_operand = rm; instruction->info.b_bl_bx_blx.target_address = -1; } /* Enhanced DSP add/subtracts */ if ((opcode & 0x0000000f0) == 0x00000050) { - uint8_t Rm, Rd, Rn; + uint8_t rm, rd, rn; char *mnemonic = NULL; - Rm = opcode & 0xf; - Rd = (opcode & 0xf000) >> 12; - Rn = (opcode & 0xf0000) >> 16; + rm = opcode & 0xf; + rd = (opcode & 0xf000) >> 12; + rn = (opcode & 0xf0000) >> 16; switch ((opcode & 0x00600000) >> 21) { case 0x0: @@ -1512,9 +1505,9 @@ static int evaluate_misc_instr(uint32_t opcode, opcode, mnemonic, COND(opcode), - Rd, - Rm, - Rn); + rd, + rm, + rn); } /* exception return */ @@ -1567,12 +1560,12 @@ static int evaluate_misc_instr(uint32_t opcode, /* SMLA < x><y> */ if ((opcode & 0x00600000) == 0x00000000) { - uint8_t Rd, Rm, Rs, Rn; - instruction->type = ARM_SMLAxy; - Rd = (opcode & 0xf0000) >> 16; - Rm = (opcode & 0xf); - Rs = (opcode & 0xf00) >> 8; - Rn = (opcode & 0xf000) >> 12; + uint8_t rd, rm, rs, rn; + instruction->type = ARM_SMLAXY; + rd = (opcode & 0xf0000) >> 16; + rm = (opcode & 0xf); + rs = (opcode & 0xf00) >> 8; + rn = (opcode & 0xf000) >> 12; snprintf(instruction->text, 128, @@ -1582,20 +1575,20 @@ static int evaluate_misc_instr(uint32_t opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode), - Rd, - Rm, - Rs, - Rn); + rd, + rm, + rs, + rn); } /* SMLAL < x><y> */ if ((opcode & 0x00600000) == 0x00400000) { - uint8_t RdLow, RdHi, Rm, Rs; - instruction->type = ARM_SMLAxy; - RdHi = (opcode & 0xf0000) >> 16; - RdLow = (opcode & 0xf000) >> 12; - Rm = (opcode & 0xf); - Rs = (opcode & 0xf00) >> 8; + uint8_t rd_low, rd_hi, rm, rs; + instruction->type = ARM_SMLAXY; + rd_hi = (opcode & 0xf0000) >> 16; + rd_low = (opcode & 0xf000) >> 12; + rm = (opcode & 0xf); + rs = (opcode & 0xf00) >> 8; snprintf(instruction->text, 128, @@ -1605,20 +1598,20 @@ static int evaluate_misc_instr(uint32_t opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode), - RdLow, - RdHi, - Rm, - Rs); + rd_low, + rd_hi, + rm, + rs); } /* SMLAW < y> */ if (((opcode & 0x00600000) == 0x00200000) && (x == 0)) { - uint8_t Rd, Rm, Rs, Rn; - instruction->type = ARM_SMLAWy; - Rd = (opcode & 0xf0000) >> 16; - Rm = (opcode & 0xf); - Rs = (opcode & 0xf00) >> 8; - Rn = (opcode & 0xf000) >> 12; + uint8_t rd, rm, rs, rn; + instruction->type = ARM_SMLAWY; + rd = (opcode & 0xf0000) >> 16; + rm = (opcode & 0xf); + rs = (opcode & 0xf00) >> 8; + rn = (opcode & 0xf000) >> 12; snprintf(instruction->text, 128, @@ -1627,19 +1620,19 @@ static int evaluate_misc_instr(uint32_t opcode, opcode, (y) ? "T" : "B", COND(opcode), - Rd, - Rm, - Rs, - Rn); + rd, + rm, + rs, + rn); } /* SMUL < x><y> */ if ((opcode & 0x00600000) == 0x00600000) { - uint8_t Rd, Rm, Rs; - instruction->type = ARM_SMULxy; - Rd = (opcode & 0xf0000) >> 16; - Rm = (opcode & 0xf); - Rs = (opcode & 0xf00) >> 8; + uint8_t rd, rm, rs; + instruction->type = ARM_SMULXY; + rd = (opcode & 0xf0000) >> 16; + rm = (opcode & 0xf); + rs = (opcode & 0xf00) >> 8; snprintf(instruction->text, 128, @@ -1649,18 +1642,18 @@ static int evaluate_misc_instr(uint32_t opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode), - Rd, - Rm, - Rs); + rd, + rm, + rs); } /* SMULW < y> */ if (((opcode & 0x00600000) == 0x00200000) && (x == 1)) { - uint8_t Rd, Rm, Rs; - instruction->type = ARM_SMULWy; - Rd = (opcode & 0xf0000) >> 16; - Rm = (opcode & 0xf); - Rs = (opcode & 0xf00) >> 8; + uint8_t rd, rm, rs; + instruction->type = ARM_SMULWY; + rd = (opcode & 0xf0000) >> 16; + rm = (opcode & 0xf); + rs = (opcode & 0xf00) >> 8; snprintf(instruction->text, 128, @@ -1669,9 +1662,9 @@ static int evaluate_misc_instr(uint32_t opcode, opcode, (y) ? "T" : "B", COND(opcode), - Rd, - Rm, - Rs); + rd, + rm, + rs); } } @@ -1682,24 +1675,24 @@ static int evaluate_mov_imm(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint16_t immediate; - uint8_t Rd; - bool T; + uint8_t rd; + bool t; - Rd = (opcode & 0xf000) >> 12; - T = opcode & 0x00400000; + rd = (opcode & 0xf000) >> 12; + t = opcode & 0x00400000; immediate = (opcode & 0xf0000) >> 4 | (opcode & 0xfff); instruction->type = ARM_MOV; - instruction->info.data_proc.Rd = Rd; + instruction->info.data_proc.rd = rd; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMOV%s%s r%i, #0x%" PRIx16, address, opcode, - T ? "T" : "W", + t ? "T" : "W", COND(opcode), - Rd, + rd, immediate); return ERROR_OK; @@ -1708,20 +1701,20 @@ static int evaluate_mov_imm(uint32_t opcode, static int evaluate_data_proc(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { - uint8_t I, op, S, Rn, Rd; + uint8_t i, op, s, rn, rd; char *mnemonic = NULL; char shifter_operand[32]; - I = (opcode & 0x02000000) >> 25; + i = (opcode & 0x02000000) >> 25; op = (opcode & 0x01e00000) >> 21; - S = (opcode & 0x00100000) >> 20; + s = (opcode & 0x00100000) >> 20; - Rd = (opcode & 0xf000) >> 12; - Rn = (opcode & 0xf0000) >> 16; + rd = (opcode & 0xf000) >> 12; + rn = (opcode & 0xf0000) >> 16; - instruction->info.data_proc.Rd = Rd; - instruction->info.data_proc.Rn = Rn; - instruction->info.data_proc.S = S; + instruction->info.data_proc.rd = rd; + instruction->info.data_proc.rn = rn; + instruction->info.data_proc.s = s; switch (op) { case 0x0: @@ -1790,7 +1783,7 @@ static int evaluate_data_proc(uint32_t opcode, break; } - if (I) {/* immediate shifter operand (#<immediate>)*/ + if (i) {/* immediate shifter operand (#<immediate>)*/ uint8_t immed_8 = opcode & 0xff; uint8_t rotate_imm = (opcode & 0xf00) >> 8; uint32_t immediate; @@ -1802,9 +1795,9 @@ static int evaluate_data_proc(uint32_t opcode, instruction->info.data_proc.variant = 0; instruction->info.data_proc.shifter_operand.immediate.immediate = immediate; } else {/* register-based shifter operand */ - uint8_t shift, Rm; + uint8_t shift, rm; shift = (opcode & 0x60) >> 5; - Rm = (opcode & 0xf); + rm = (opcode & 0xf); if ((opcode & 0x10) != 0x10) { /* Immediate shifts ("<Rm>" or "<Rm>, <shift> *#<shift_immediate>") */ @@ -1812,7 +1805,7 @@ static int evaluate_data_proc(uint32_t opcode, shift_imm = (opcode & 0xf80) >> 7; instruction->info.data_proc.variant = 1; - instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm; + instruction->info.data_proc.shifter_operand.immediate_shift.rm = rm; instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = shift_imm; instruction->info.data_proc.shifter_operand.immediate_shift.shift = shift; @@ -1830,51 +1823,51 @@ static int evaluate_data_proc(uint32_t opcode, shift = 0x4; if ((shift_imm == 0x0) && (shift == 0x0)) - snprintf(shifter_operand, 32, "r%i", Rm); + snprintf(shifter_operand, 32, "r%i", rm); else { if (shift == 0x0) /* LSL */ snprintf(shifter_operand, 32, "r%i, LSL #0x%x", - Rm, + rm, shift_imm); else if (shift == 0x1) /* LSR */ snprintf(shifter_operand, 32, "r%i, LSR #0x%x", - Rm, + rm, shift_imm); else if (shift == 0x2) /* ASR */ snprintf(shifter_operand, 32, "r%i, ASR #0x%x", - Rm, + rm, shift_imm); else if (shift == 0x3) /* ROR */ snprintf(shifter_operand, 32, "r%i, ROR #0x%x", - Rm, + rm, shift_imm); else if (shift == 0x4) /* RRX */ - snprintf(shifter_operand, 32, "r%i, RRX", Rm); + snprintf(shifter_operand, 32, "r%i, RRX", rm); } } else {/* Register shifts ("<Rm>, <shift> <Rs>") */ - uint8_t Rs = (opcode & 0xf00) >> 8; + uint8_t rs = (opcode & 0xf00) >> 8; instruction->info.data_proc.variant = 2; - instruction->info.data_proc.shifter_operand.register_shift.Rm = Rm; - instruction->info.data_proc.shifter_operand.register_shift.Rs = Rs; + instruction->info.data_proc.shifter_operand.register_shift.rm = rm; + instruction->info.data_proc.shifter_operand.register_shift.rs = rs; instruction->info.data_proc.shifter_operand.register_shift.shift = shift; if (shift == 0x0) /* LSL */ - snprintf(shifter_operand, 32, "r%i, LSL r%i", Rm, Rs); + snprintf(shifter_operand, 32, "r%i, LSL r%i", rm, rs); else if (shift == 0x1) /* LSR */ - snprintf(shifter_operand, 32, "r%i, LSR r%i", Rm, Rs); + snprintf(shifter_operand, 32, "r%i, LSR r%i", rm, rs); else if (shift == 0x2) /* ASR */ - snprintf(shifter_operand, 32, "r%i, ASR r%i", Rm, Rs); + snprintf(shifter_operand, 32, "r%i, ASR r%i", rm, rs); else if (shift == 0x3) /* ROR */ - snprintf(shifter_operand, 32, "r%i, ROR r%i", Rm, Rs); + snprintf(shifter_operand, 32, "r%i, ROR r%i", rm, rs); } } @@ -1887,9 +1880,9 @@ static int evaluate_data_proc(uint32_t opcode, opcode, mnemonic, COND(opcode), - (S) ? "S" : "", - Rd, - Rn, + (s) ? "S" : "", + rd, + rn, shifter_operand); } else if ((op == 0xd) || (op == 0xf)) { /* <opcode1>{<cond>}{S} <Rd>, *<shifter_operand> */ @@ -1907,13 +1900,13 @@ static int evaluate_data_proc(uint32_t opcode, opcode, mnemonic, COND(opcode), - (S) ? "S" : "", - Rd, + (s) ? "S" : "", + rd, shifter_operand); } else {/* <opcode2>{<cond>} <Rn>, <shifter_operand> */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, %s", address, opcode, mnemonic, COND(opcode), - Rn, shifter_operand); + rn, shifter_operand); } return ERROR_OK; @@ -2119,9 +2112,9 @@ static int evaluate_b_bl_blx_thumb(uint16_t opcode, static int evaluate_add_sub_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { - uint8_t Rd = (opcode >> 0) & 0x7; - uint8_t Rn = (opcode >> 3) & 0x7; - uint8_t Rm_imm = (opcode >> 6) & 0x7; + uint8_t rd = (opcode >> 0) & 0x7; + uint8_t rn = (opcode >> 3) & 0x7; + uint8_t rm_imm = (opcode >> 6) & 0x7; uint32_t opc = opcode & (1 << 9); uint32_t reg_imm = opcode & (1 << 10); char *mnemonic; @@ -2135,22 +2128,22 @@ static int evaluate_add_sub_thumb(uint16_t opcode, mnemonic = "ADDS"; } - instruction->info.data_proc.Rd = Rd; - instruction->info.data_proc.Rn = Rn; - instruction->info.data_proc.S = 1; + instruction->info.data_proc.rd = rd; + instruction->info.data_proc.rn = rn; + instruction->info.data_proc.s = 1; if (reg_imm) { instruction->info.data_proc.variant = 0;/*immediate*/ - instruction->info.data_proc.shifter_operand.immediate.immediate = Rm_imm; + instruction->info.data_proc.shifter_operand.immediate.immediate = rm_imm; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%d", - address, opcode, mnemonic, Rd, Rn, Rm_imm); + address, opcode, mnemonic, rd, rn, rm_imm); } else { instruction->info.data_proc.variant = 1;/*immediate shift*/ - instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm_imm; + instruction->info.data_proc.shifter_operand.immediate_shift.rm = rm_imm; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, r%i", - address, opcode, mnemonic, Rd, Rn, Rm_imm); + address, opcode, mnemonic, rd, rn, rm_imm); } return ERROR_OK; @@ -2159,8 +2152,8 @@ static int evaluate_add_sub_thumb(uint16_t opcode, static int evaluate_shift_imm_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { - uint8_t Rd = (opcode >> 0) & 0x7; - uint8_t Rm = (opcode >> 3) & 0x7; + uint8_t rd = (opcode >> 0) & 0x7; + uint8_t rm = (opcode >> 3) & 0x7; uint8_t imm = (opcode >> 6) & 0x1f; uint8_t opc = (opcode >> 11) & 0x3; char *mnemonic = NULL; @@ -2186,17 +2179,17 @@ static int evaluate_shift_imm_thumb(uint16_t opcode, if ((imm == 0) && (opc != 0)) imm = 32; - instruction->info.data_proc.Rd = Rd; - instruction->info.data_proc.Rn = -1; - instruction->info.data_proc.S = 1; + instruction->info.data_proc.rd = rd; + instruction->info.data_proc.rn = -1; + instruction->info.data_proc.s = 1; instruction->info.data_proc.variant = 1;/*immediate_shift*/ - instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm; + instruction->info.data_proc.shifter_operand.immediate_shift.rm = rm; instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = imm; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%#2.2x", - address, opcode, mnemonic, Rd, Rm, imm); + address, opcode, mnemonic, rd, rm, imm); return ERROR_OK; } @@ -2205,13 +2198,13 @@ static int evaluate_data_proc_imm_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t imm = opcode & 0xff; - uint8_t Rd = (opcode >> 8) & 0x7; + uint8_t rd = (opcode >> 8) & 0x7; uint32_t opc = (opcode >> 11) & 0x3; char *mnemonic = NULL; - instruction->info.data_proc.Rd = Rd; - instruction->info.data_proc.Rn = Rd; - instruction->info.data_proc.S = 1; + instruction->info.data_proc.rd = rd; + instruction->info.data_proc.rn = rd; + instruction->info.data_proc.s = 1; instruction->info.data_proc.variant = 0;/*immediate*/ instruction->info.data_proc.shifter_operand.immediate.immediate = imm; @@ -2219,12 +2212,12 @@ static int evaluate_data_proc_imm_thumb(uint16_t opcode, case 0: instruction->type = ARM_MOV; mnemonic = "MOVS"; - instruction->info.data_proc.Rn = -1; + instruction->info.data_proc.rn = -1; break; case 1: instruction->type = ARM_CMP; mnemonic = "CMP"; - instruction->info.data_proc.Rd = -1; + instruction->info.data_proc.rd = -1; break; case 2: instruction->type = ARM_ADD; @@ -2238,7 +2231,7 @@ static int evaluate_data_proc_imm_thumb(uint16_t opcode, snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, #%#2.2x", - address, opcode, mnemonic, Rd, imm); + address, opcode, mnemonic, rd, imm); return ERROR_OK; } @@ -2246,27 +2239,27 @@ static int evaluate_data_proc_imm_thumb(uint16_t opcode, static int evaluate_data_proc_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { - uint8_t high_reg, op, Rm, Rd, H1, H2; + uint8_t high_reg, op, rm, rd, h1, h2; char *mnemonic = NULL; bool nop = false; high_reg = (opcode & 0x0400) >> 10; op = (opcode & 0x03C0) >> 6; - Rd = (opcode & 0x0007); - Rm = (opcode & 0x0038) >> 3; - H1 = (opcode & 0x0080) >> 7; - H2 = (opcode & 0x0040) >> 6; + rd = (opcode & 0x0007); + rm = (opcode & 0x0038) >> 3; + h1 = (opcode & 0x0080) >> 7; + h2 = (opcode & 0x0040) >> 6; - instruction->info.data_proc.Rd = Rd; - instruction->info.data_proc.Rn = Rd; - instruction->info.data_proc.S = (!high_reg || (instruction->type == ARM_CMP)); + instruction->info.data_proc.rd = rd; + instruction->info.data_proc.rn = rd; + instruction->info.data_proc.s = (!high_reg || (instruction->type == ARM_CMP)); instruction->info.data_proc.variant = 1 /*immediate shift*/; - instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm; + instruction->info.data_proc.shifter_operand.immediate_shift.rm = rm; if (high_reg) { - Rd |= H1 << 3; - Rm |= H2 << 3; + rd |= h1 << 3; + rm |= h2 << 3; op >>= 2; switch (op) { @@ -2281,24 +2274,24 @@ static int evaluate_data_proc_thumb(uint16_t opcode, case 0x2: instruction->type = ARM_MOV; mnemonic = "MOV"; - if (Rd == Rm) + if (rd == rm) nop = true; break; case 0x3: if ((opcode & 0x7) == 0x0) { - instruction->info.b_bl_bx_blx.reg_operand = Rm; - if (H1) { + instruction->info.b_bl_bx_blx.reg_operand = rm; + if (h1) { instruction->type = ARM_BLX; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tBLX\tr%i", - address, opcode, Rm); + address, opcode, rm); } else { instruction->type = ARM_BX; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tBX\tr%i", - address, opcode, Rm); + address, opcode, rm); } } else { instruction->type = ARM_UNDEFINED_INSTRUCTION; @@ -2325,24 +2318,24 @@ static int evaluate_data_proc_thumb(uint16_t opcode, mnemonic = "LSLS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 0; - instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; - instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; + instruction->info.data_proc.shifter_operand.register_shift.rm = rd; + instruction->info.data_proc.shifter_operand.register_shift.rs = rm; break; case 0x3: instruction->type = ARM_MOV; mnemonic = "LSRS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 1; - instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; - instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; + instruction->info.data_proc.shifter_operand.register_shift.rm = rd; + instruction->info.data_proc.shifter_operand.register_shift.rs = rm; break; case 0x4: instruction->type = ARM_MOV; mnemonic = "ASRS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 2; - instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; - instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; + instruction->info.data_proc.shifter_operand.register_shift.rm = rd; + instruction->info.data_proc.shifter_operand.register_shift.rs = rm; break; case 0x5: instruction->type = ARM_ADC; @@ -2357,8 +2350,8 @@ static int evaluate_data_proc_thumb(uint16_t opcode, mnemonic = "RORS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 3; - instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; - instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; + instruction->info.data_proc.shifter_operand.register_shift.rm = rd; + instruction->info.data_proc.shifter_operand.register_shift.rs = rm; break; case 0x8: instruction->type = ARM_TST; @@ -2369,7 +2362,7 @@ static int evaluate_data_proc_thumb(uint16_t opcode, mnemonic = "RSBS"; instruction->info.data_proc.variant = 0 /*immediate*/; instruction->info.data_proc.shifter_operand.immediate.immediate = 0; - instruction->info.data_proc.Rn = Rm; + instruction->info.data_proc.rn = rm; break; case 0xA: instruction->type = ARM_CMP; @@ -2402,11 +2395,11 @@ static int evaluate_data_proc_thumb(uint16_t opcode, snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tNOP\t\t\t" "; (%s r%i, r%i)", - address, opcode, mnemonic, Rd, Rm); + address, opcode, mnemonic, rd, rm); else snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i", - address, opcode, mnemonic, Rd, Rm); + address, opcode, mnemonic, rd, rm); return ERROR_OK; } @@ -2421,14 +2414,14 @@ static int evaluate_load_literal_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t immediate; - uint8_t Rd = (opcode >> 8) & 0x7; + uint8_t rd = (opcode >> 8) & 0x7; instruction->type = ARM_LDR; immediate = opcode & 0x000000ff; immediate *= 4; - instruction->info.load_store.Rd = Rd; - instruction->info.load_store.Rn = 15 /*PC*/; + instruction->info.load_store.rd = rd; + instruction->info.load_store.rn = 15 /*PC*/; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 0; /*immediate*/ instruction->info.load_store.offset.offset = immediate; @@ -2436,7 +2429,7 @@ static int evaluate_load_literal_thumb(uint16_t opcode, snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t" "LDR\tr%i, [pc, #%#" PRIx32 "]\t; %#8.8" PRIx32, - address, opcode, Rd, immediate, + address, opcode, rd, immediate, thumb_alignpc4(address) + immediate); return ERROR_OK; @@ -2445,9 +2438,9 @@ static int evaluate_load_literal_thumb(uint16_t opcode, static int evaluate_load_store_reg_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { - uint8_t Rd = (opcode >> 0) & 0x7; - uint8_t Rn = (opcode >> 3) & 0x7; - uint8_t Rm = (opcode >> 6) & 0x7; + uint8_t rd = (opcode >> 0) & 0x7; + uint8_t rn = (opcode >> 3) & 0x7; + uint8_t rm = (opcode >> 6) & 0x7; uint8_t opc = (opcode >> 9) & 0x7; char *mnemonic = NULL; @@ -2488,13 +2481,13 @@ static int evaluate_load_store_reg_thumb(uint16_t opcode, snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [r%i, r%i]", - address, opcode, mnemonic, Rd, Rn, Rm); + address, opcode, mnemonic, rd, rn, rm); - instruction->info.load_store.Rd = Rd; - instruction->info.load_store.Rn = Rn; + instruction->info.load_store.rd = rd; + instruction->info.load_store.rn = rn; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 1; /*register*/ - instruction->info.load_store.offset.reg.Rm = Rm; + instruction->info.load_store.offset.reg.rm = rm; return ERROR_OK; } @@ -2503,15 +2496,15 @@ static int evaluate_load_store_imm_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t offset = (opcode >> 6) & 0x1f; - uint8_t Rd = (opcode >> 0) & 0x7; - uint8_t Rn = (opcode >> 3) & 0x7; - uint32_t L = opcode & (1 << 11); - uint32_t B = opcode & (1 << 12); + uint8_t rd = (opcode >> 0) & 0x7; + uint8_t rn = (opcode >> 3) & 0x7; + uint32_t l = opcode & (1 << 11); + uint32_t b = opcode & (1 << 12); char *mnemonic; char suffix = ' '; uint32_t shift = 2; - if (L) { + if (l) { instruction->type = ARM_LDR; mnemonic = "LDR"; } else { @@ -2522,17 +2515,17 @@ static int evaluate_load_store_imm_thumb(uint16_t opcode, if ((opcode&0xF000) == 0x8000) { suffix = 'H'; shift = 1; - } else if (B) { + } else if (b) { suffix = 'B'; shift = 0; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32 "]", - address, opcode, mnemonic, suffix, Rd, Rn, offset << shift); + address, opcode, mnemonic, suffix, rd, rn, offset << shift); - instruction->info.load_store.Rd = Rd; - instruction->info.load_store.Rn = Rn; + instruction->info.load_store.rd = rd; + instruction->info.load_store.rn = rn; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 0; /*immediate*/ instruction->info.load_store.offset.offset = offset << shift; @@ -2544,11 +2537,11 @@ static int evaluate_load_store_stack_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t offset = opcode & 0xff; - uint8_t Rd = (opcode >> 8) & 0x7; - uint32_t L = opcode & (1 << 11); + uint8_t rd = (opcode >> 8) & 0x7; + uint32_t l = opcode & (1 << 11); char *mnemonic; - if (L) { + if (l) { instruction->type = ARM_LDR; mnemonic = "LDR"; } else { @@ -2558,10 +2551,10 @@ static int evaluate_load_store_stack_thumb(uint16_t opcode, snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32 "]", - address, opcode, mnemonic, Rd, offset*4); + address, opcode, mnemonic, rd, offset*4); - instruction->info.load_store.Rd = Rd; - instruction->info.load_store.Rn = 13 /*SP*/; + instruction->info.load_store.rd = rd; + instruction->info.load_store.rn = 13 /*SP*/; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 0; /*immediate*/ instruction->info.load_store.offset.offset = offset*4; @@ -2573,28 +2566,28 @@ static int evaluate_add_sp_pc_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t imm = opcode & 0xff; - uint8_t Rd = (opcode >> 8) & 0x7; - uint8_t Rn; - uint32_t SP = opcode & (1 << 11); + uint8_t rd = (opcode >> 8) & 0x7; + uint8_t rn; + uint32_t sp = opcode & (1 << 11); const char *reg_name; instruction->type = ARM_ADD; - if (SP) { + if (sp) { reg_name = "SP"; - Rn = 13; + rn = 13; } else { reg_name = "PC"; - Rn = 15; + rn = 15; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32, - address, opcode, Rd, reg_name, imm * 4); + address, opcode, rd, reg_name, imm * 4); instruction->info.data_proc.variant = 0 /* immediate */; - instruction->info.data_proc.Rd = Rd; - instruction->info.data_proc.Rn = Rn; + instruction->info.data_proc.rd = rd; + instruction->info.data_proc.rn = rn; instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4; return ERROR_OK; @@ -2621,8 +2614,8 @@ static int evaluate_adjust_stack_thumb(uint16_t opcode, address, opcode, mnemonic, imm*4); instruction->info.data_proc.variant = 0 /* immediate */; - instruction->info.data_proc.Rd = 13 /*SP*/; - instruction->info.data_proc.Rn = 13 /*SP*/; + instruction->info.data_proc.rd = 13 /*SP*/; + instruction->info.data_proc.rn = 13 /*SP*/; instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4; return ERROR_OK; @@ -2646,9 +2639,9 @@ static int evaluate_load_store_multiple_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t reg_list = opcode & 0xff; - uint32_t L = opcode & (1 << 11); - uint32_t R = opcode & (1 << 8); - uint8_t Rn = (opcode >> 8) & 7; + uint32_t l = opcode & (1 << 11); + uint32_t r = opcode & (1 << 8); + uint8_t rn = (opcode >> 8) & 7; uint8_t addr_mode = 0 /* IA */; char reg_names[40]; char *reg_names_p; @@ -2663,28 +2656,28 @@ static int evaluate_load_store_multiple_thumb(uint16_t opcode, if ((opcode & 0xf000) == 0xc000) { /* generic load/store multiple */ char *wback = "!"; - if (L) { + if (l) { instruction->type = ARM_LDM; mnemonic = "LDM"; - if (opcode & (1 << Rn)) + if (opcode & (1 << rn)) wback = ""; } else { instruction->type = ARM_STM; mnemonic = "STM"; } - snprintf(ptr_name, sizeof(ptr_name), "r%i%s, ", Rn, wback); + snprintf(ptr_name, sizeof(ptr_name), "r%i%s, ", rn, wback); } else {/* push/pop */ - Rn = 13;/* SP */ - if (L) { + rn = 13;/* SP */ + if (l) { instruction->type = ARM_LDM; mnemonic = "POP"; - if (R) + if (r) reg_list |= (1 << 15) /*PC*/; } else { instruction->type = ARM_STM; mnemonic = "PUSH"; addr_mode = 3; /*DB*/ - if (R) + if (r) reg_list |= (1 << 14) /*LR*/; } } @@ -2707,7 +2700,7 @@ static int evaluate_load_store_multiple_thumb(uint16_t opcode, address, opcode, mnemonic, ptr_name, reg_names); instruction->info.load_store_multiple.register_list = reg_list; - instruction->info.load_store_multiple.Rn = Rn; + instruction->info.load_store_multiple.rn = rn; instruction->info.load_store_multiple.addressing_mode = addr_mode; return ERROR_OK; @@ -3000,1616 +2993,126 @@ int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, struct arm_instruct return -1; } -static int t2ev_b_bl(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - unsigned offset; - unsigned b21 = 1 << 21; - unsigned b22 = 1 << 22; - - /* instead of combining two smaller 16-bit branch instructions, - * Thumb2 uses only one larger 32-bit instruction. - */ - offset = opcode & 0x7ff; - offset |= (opcode & 0x03ff0000) >> 5; - if (opcode & (1 << 26)) { - offset |= 0xff << 23; - if ((opcode & (1 << 11)) == 0) - b21 = 0; - if ((opcode & (1 << 13)) == 0) - b22 = 0; - } else { - if (opcode & (1 << 11)) - b21 = 0; - if (opcode & (1 << 13)) - b22 = 0; - } - offset |= b21; - offset |= b22; - - - address += 4; - address += offset << 1; - - char *inst; - switch ((opcode >> 12) & 0x5) { - case 0x1: - inst = "B.W"; - instruction->type = ARM_B; - break; - case 0x4: - inst = "BLX"; - instruction->type = ARM_BLX; - address &= 0xfffffffc; - break; - case 0x5: - inst = "BL"; - instruction->type = ARM_BL; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - instruction->info.b_bl_bx_blx.reg_operand = -1; - instruction->info.b_bl_bx_blx.target_address = address; - sprintf(cp, "%s\t%#8.8" PRIx32, inst, address); - - return ERROR_OK; -} - -static int t2ev_cond_b(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - unsigned offset; - unsigned b17 = 1 << 17; - unsigned b18 = 1 << 18; - unsigned cond = (opcode >> 22) & 0x0f; - - offset = opcode & 0x7ff; - offset |= (opcode & 0x003f0000) >> 5; - if (opcode & (1 << 26)) { - offset |= 0x1fff << 19; - if ((opcode & (1 << 11)) == 0) - b17 = 0; - if ((opcode & (1 << 13)) == 0) - b18 = 0; - } else { - if (opcode & (1 << 11)) - b17 = 0; - if (opcode & (1 << 13)) - b18 = 0; - } - offset |= b17; - offset |= b18; - - address += 4; - address += offset << 1; - - instruction->type = ARM_B; - instruction->info.b_bl_bx_blx.reg_operand = -1; - instruction->info.b_bl_bx_blx.target_address = address; - sprintf(cp, "B%s.W\t%#8.8" PRIx32, - arm_condition_strings[cond], - address); - - return ERROR_OK; -} - -static const char *special_name(int number) +int arm_access_size(struct arm_instruction *instruction) { - char *special = "(RESERVED)"; - - switch (number) { - case 0: - special = "apsr"; - break; - case 1: - special = "iapsr"; - break; - case 2: - special = "eapsr"; - break; - case 3: - special = "xpsr"; - break; - case 5: - special = "ipsr"; - break; - case 6: - special = "epsr"; - break; - case 7: - special = "iepsr"; - break; - case 8: - special = "msp"; - break; - case 9: - special = "psp"; - break; - case 16: - special = "primask"; - break; - case 17: - special = "basepri"; - break; - case 18: - special = "basepri_max"; - break; - case 19: - special = "faultmask"; - break; - case 20: - special = "control"; - break; + if ((instruction->type == ARM_LDRB) + || (instruction->type == ARM_LDRBT) + || (instruction->type == ARM_LDRSB) + || (instruction->type == ARM_STRB) + || (instruction->type == ARM_STRBT)) + return 1; + else if ((instruction->type == ARM_LDRH) + || (instruction->type == ARM_LDRSH) + || (instruction->type == ARM_STRH)) + return 2; + else if ((instruction->type == ARM_LDR) + || (instruction->type == ARM_LDRT) + || (instruction->type == ARM_STR) + || (instruction->type == ARM_STRT)) + return 4; + else if ((instruction->type == ARM_LDRD) + || (instruction->type == ARM_STRD)) + return 8; + else { + LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", + instruction->type); + return 0; } - return special; } -static int t2ev_hint(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) +#if HAVE_CAPSTONE +static void print_opcode(struct command_invocation *cmd, const cs_insn *insn) { - const char *mnemonic; + uint32_t opcode = 0; - if (opcode & 0x0700) { - instruction->type = ARM_UNDEFINED_INSTRUCTION; - strcpy(cp, "UNDEFINED"); - return ERROR_OK; - } + memcpy(&opcode, insn->bytes, insn->size); - if (opcode & 0x00f0) { - sprintf(cp, "DBG\t#%d", (int) opcode & 0xf); - return ERROR_OK; - } + if (insn->size == 4) { + uint16_t opcode_high = opcode >> 16; + opcode = opcode & 0xffff; - switch (opcode & 0x0f) { - case 0: - mnemonic = "NOP.W"; - break; - case 1: - mnemonic = "YIELD.W"; - break; - case 2: - mnemonic = "WFE.W"; - break; - case 3: - mnemonic = "WFI.W"; - break; - case 4: - mnemonic = "SEV.W"; - break; - default: - mnemonic = "HINT.W (UNRECOGNIZED)"; - break; + command_print(cmd, "0x%08" PRIx64" %04x %04x\t%s%s%s", + insn->address, opcode, opcode_high, insn->mnemonic, + insn->op_str[0] ? "\t" : "", insn->op_str); + } else { + command_print(cmd, "0x%08" PRIx64" %04x\t%s%s%s", + insn->address, opcode, insn->mnemonic, + insn->op_str[0] ? "\t" : "", insn->op_str); } - strcpy(cp, mnemonic); - return ERROR_OK; } -static int t2ev_misc(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) +int arm_disassemble(struct command_invocation *cmd, struct target *target, + target_addr_t address, size_t count, bool thumb_mode) { - const char *mnemonic; - - switch ((opcode >> 4) & 0x0f) { - case 0: - mnemonic = "LEAVEX"; - break; - case 1: - mnemonic = "ENTERX"; - break; - case 2: - mnemonic = "CLREX"; - break; - case 4: - mnemonic = "DSB"; - break; - case 5: - mnemonic = "DMB"; - break; - case 6: - mnemonic = "ISB"; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - strcpy(cp, mnemonic); - return ERROR_OK; -} + csh handle; + int ret; + cs_insn *insn; + cs_mode mode; -static int t2ev_b_misc(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - /* permanently undefined */ - if ((opcode & 0x07f07000) == 0x07f02000) { - instruction->type = ARM_UNDEFINED_INSTRUCTION; - strcpy(cp, "UNDEFINED"); - return ERROR_OK; + if (!cs_support(CS_ARCH_ARM)) { + LOG_ERROR("ARM architecture not supported by capstone"); + return ERROR_FAIL; } - switch ((opcode >> 12) & 0x5) { - case 0x1: - case 0x4: - case 0x5: - return t2ev_b_bl(opcode, address, instruction, cp); - case 0: - if (((opcode >> 23) & 0x07) != 0x07) - return t2ev_cond_b(opcode, address, instruction, cp); - if (opcode & (1 << 26)) - goto undef; - break; - } + mode = CS_MODE_LITTLE_ENDIAN; - switch ((opcode >> 20) & 0x7f) { - case 0x38: - case 0x39: - sprintf(cp, "MSR\t%s, r%d", special_name(opcode & 0xff), - (int) (opcode >> 16) & 0x0f); - return ERROR_OK; - case 0x3a: - return t2ev_hint(opcode, address, instruction, cp); - case 0x3b: - return t2ev_misc(opcode, address, instruction, cp); - case 0x3c: - sprintf(cp, "BXJ\tr%d", (int) (opcode >> 16) & 0x0f); - return ERROR_OK; - case 0x3e: - case 0x3f: - sprintf(cp, "MRS\tr%d, %s", (int) (opcode >> 8) & 0x0f, - special_name(opcode & 0xff)); - return ERROR_OK; - } + if (thumb_mode) + mode |= CS_MODE_THUMB; -undef: - return ERROR_COMMAND_SYNTAX_ERROR; -} + ret = cs_open(CS_ARCH_ARM, mode, &handle); -static int t2ev_data_mod_immed(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - char *mnemonic = NULL; - int rn = (opcode >> 16) & 0xf; - int rd = (opcode >> 8) & 0xf; - unsigned immed = opcode & 0xff; - unsigned func; - bool one = false; - char *suffix = ""; - char *suffix2 = ""; - - /* ARMv7-M: A5.3.2 Modified immediate constants */ - func = (opcode >> 11) & 0x0e; - if (immed & 0x80) - func |= 1; - if (opcode & (1 << 26)) - func |= 0x10; - - /* "Modified" immediates */ - switch (func >> 1) { - case 0: - break; - case 2: - immed <<= 8; - /* FALLTHROUGH */ - case 1: - immed += immed << 16; - break; - case 3: - immed += immed << 8; - immed += immed << 16; - break; - default: - immed |= 0x80; - immed = ror(immed, func); + if (ret != CS_ERR_OK) { + LOG_ERROR("cs_open() failed: %s", cs_strerror(ret)); + return ERROR_FAIL; } - if (opcode & (1 << 20)) - suffix = "S"; + ret = cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON); - switch ((opcode >> 21) & 0xf) { - case 0: - if (rd == 0xf) { - instruction->type = ARM_TST; - mnemonic = "TST"; - one = true; - suffix = ""; - rd = rn; - } else { - instruction->type = ARM_AND; - mnemonic = "AND"; - } - break; - case 1: - instruction->type = ARM_BIC; - mnemonic = "BIC"; - break; - case 2: - if (rn == 0xf) { - instruction->type = ARM_MOV; - mnemonic = "MOV"; - one = true; - suffix2 = ".W"; - } else { - instruction->type = ARM_ORR; - mnemonic = "ORR"; - } - break; - case 3: - if (rn == 0xf) { - instruction->type = ARM_MVN; - mnemonic = "MVN"; - one = true; - } else { - /* instruction->type = ARM_ORN; */ - mnemonic = "ORN"; - } - break; - case 4: - if (rd == 0xf) { - instruction->type = ARM_TEQ; - mnemonic = "TEQ"; - one = true; - suffix = ""; - rd = rn; - } else { - instruction->type = ARM_EOR; - mnemonic = "EOR"; - } - break; - case 8: - if (rd == 0xf) { - instruction->type = ARM_CMN; - mnemonic = "CMN"; - one = true; - suffix = ""; - rd = rn; - } else { - instruction->type = ARM_ADD; - mnemonic = "ADD"; - suffix2 = ".W"; - } - break; - case 10: - instruction->type = ARM_ADC; - mnemonic = "ADC"; - suffix2 = ".W"; - break; - case 11: - instruction->type = ARM_SBC; - mnemonic = "SBC"; - break; - case 13: - if (rd == 0xf) { - instruction->type = ARM_CMP; - mnemonic = "CMP"; - one = true; - suffix = ""; - rd = rn; - } else { - instruction->type = ARM_SUB; - mnemonic = "SUB"; - } - suffix2 = ".W"; - break; - case 14: - instruction->type = ARM_RSB; - mnemonic = "RSB"; - suffix2 = ".W"; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + if (ret != CS_ERR_OK) { + LOG_ERROR("cs_option() failed: %s", cs_strerror(ret)); + cs_close(&handle); + return ERROR_FAIL; } - if (one) - sprintf(cp, "%s%s\tr%d, #%d\t; %#8.8x", - mnemonic, suffix2, rd, immed, immed); - else - sprintf(cp, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x", - mnemonic, suffix, suffix2, - rd, rn, immed, immed); - - return ERROR_OK; -} - -static int t2ev_data_immed(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - char *mnemonic = NULL; - int rn = (opcode >> 16) & 0xf; - int rd = (opcode >> 8) & 0xf; - unsigned immed; - bool add = false; - bool is_signed = false; - - immed = (opcode & 0x0ff) | ((opcode & 0x7000) >> 4); - if (opcode & (1 << 26)) - immed |= (1 << 11); + insn = cs_malloc(handle); - switch ((opcode >> 20) & 0x1f) { - case 0: - if (rn == 0xf) { - add = true; - goto do_adr; - } - mnemonic = "ADDW"; - break; - case 4: - immed |= (opcode >> 4) & 0xf000; - sprintf(cp, "MOVW\tr%d, #%d\t; %#3.3x", rd, immed, immed); - return ERROR_OK; - case 0x0a: - if (rn == 0xf) - goto do_adr; - mnemonic = "SUBW"; - break; - case 0x0c: - /* move constant to top 16 bits of register */ - immed |= (opcode >> 4) & 0xf000; - sprintf(cp, "MOVT\tr%d, #%d\t; %#4.4x", rd, immed, immed); - return ERROR_OK; - case 0x10: - case 0x12: - is_signed = true; - /* fallthrough */ - case 0x18: - case 0x1a: - /* signed/unsigned saturated add */ - immed = (opcode >> 6) & 0x03; - immed |= (opcode >> 10) & 0x1c; - sprintf(cp, "%sSAT\tr%d, #%d, r%d, %s #%d\t", - is_signed ? "S" : "U", - rd, (int) (opcode & 0x1f) + is_signed, rn, - (opcode & (1 << 21)) ? "ASR" : "LSL", - immed ? immed : 32); - return ERROR_OK; - case 0x14: - is_signed = true; - /* FALLTHROUGH */ - case 0x1c: - /* signed/unsigned bitfield extract */ - immed = (opcode >> 6) & 0x03; - immed |= (opcode >> 10) & 0x1c; - sprintf(cp, "%sBFX\tr%d, r%d, #%d, #%d\t", - is_signed ? "S" : "U", - rd, rn, immed, - (int) (opcode & 0x1f) + 1); - return ERROR_OK; - case 0x16: - immed = (opcode >> 6) & 0x03; - immed |= (opcode >> 10) & 0x1c; - if (rn == 0xf) /* bitfield clear */ - sprintf(cp, "BFC\tr%d, #%d, #%d\t", - rd, immed, - (int) (opcode & 0x1f) + 1 - immed); - else /* bitfield insert */ - sprintf(cp, "BFI\tr%d, r%d, #%d, #%d\t", - rd, rn, immed, - (int) (opcode & 0x1f) + 1 - immed); - return ERROR_OK; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + if (!insn) { + LOG_ERROR("cs_malloc() failed\n"); + cs_close(&handle); + return ERROR_FAIL; } - sprintf(cp, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic, - rd, rn, immed, immed); - return ERROR_OK; + while (count > 0) { + uint8_t buffer[4]; -do_adr: - address = thumb_alignpc4(address); - if (add) - address += immed; - else - address -= immed; - /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better; - * not hiding the pc-relative stuff will sometimes be useful. - */ - sprintf(cp, "ADR.W\tr%d, %#8.8" PRIx32, rd, address); - return ERROR_OK; -} + ret = target_read_buffer(target, address, sizeof(buffer), buffer); -static int t2ev_store_single(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - unsigned op = (opcode >> 20) & 0xf; - char *size = ""; - char *suffix = ""; - char *p1 = ""; - char *p2 = "]"; - unsigned immed; - unsigned rn = (opcode >> 16) & 0x0f; - unsigned rt = (opcode >> 12) & 0x0f; - - if (rn == 0xf) - return ERROR_COMMAND_SYNTAX_ERROR; - - if (opcode & 0x0800) - op |= 1; - switch (op) { - /* byte */ - case 0x8: - case 0x9: - size = "B"; - goto imm12; - case 0x1: - size = "B"; - goto imm8; - case 0x0: - size = "B"; - break; - /* halfword */ - case 0xa: - case 0xb: - size = "H"; - goto imm12; - case 0x3: - size = "H"; - goto imm8; - case 0x2: - size = "H"; - break; - /* word */ - case 0xc: - case 0xd: - goto imm12; - case 0x5: - goto imm8; - case 0x4: - break; - /* error */ - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } + if (ret != ERROR_OK) { + cs_free(insn, 1); + cs_close(&handle); + return ret; + } - sprintf(cp, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]", - size, rt, rn, (int) opcode & 0x0f, - (int) (opcode >> 4) & 0x03); - return ERROR_OK; + size_t size = sizeof(buffer); + const uint8_t *tmp = buffer; -imm12: - immed = opcode & 0x0fff; - sprintf(cp, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x", - size, rt, rn, immed, immed); - return ERROR_OK; + ret = cs_disasm_iter(handle, &tmp, &size, &address, insn); -imm8: - immed = opcode & 0x00ff; + if (!ret) { + LOG_ERROR("cs_disasm_iter() failed: %s", + cs_strerror(cs_errno(handle))); + cs_free(insn, 1); + cs_close(&handle); + return ERROR_FAIL; + } - switch (opcode & 0x700) { - case 0x600: - suffix = "T"; - break; - case 0x000: - case 0x200: - return ERROR_COMMAND_SYNTAX_ERROR; + print_opcode(cmd, insn); + count--; } - /* two indexed modes will write back rn */ - if (opcode & 0x100) { - if (opcode & 0x400) /* pre-indexed */ - p2 = "]!"; - else { /* post-indexed */ - p1 = "]"; - p2 = ""; - } - } + cs_free(insn, 1); + cs_close(&handle); - sprintf(cp, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x", - size, suffix, rt, rn, p1, - (opcode & 0x200) ? "" : "-", - immed, p2, immed); return ERROR_OK; } - -static int t2ev_mul32(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - int ra = (opcode >> 12) & 0xf; - - switch (opcode & 0x007000f0) { - case 0: - if (ra == 0xf) - sprintf(cp, "MUL\tr%d, r%d, r%d", - (int) (opcode >> 8) & 0xf, - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf); - else - sprintf(cp, "MLA\tr%d, r%d, r%d, r%d", - (int) (opcode >> 8) & 0xf, - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf, ra); - break; - case 0x10: - sprintf(cp, "MLS\tr%d, r%d, r%d, r%d", - (int) (opcode >> 8) & 0xf, - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf, ra); - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - return ERROR_OK; -} - -static int t2ev_mul64_div(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - int op = (opcode >> 4) & 0xf; - char *infix = "MUL"; - - op += (opcode >> 16) & 0x70; - switch (op) { - case 0x40: - case 0x60: - infix = "MLA"; - /* FALLTHROUGH */ - case 0: - case 0x20: - sprintf(cp, "%c%sL\tr%d, r%d, r%d, r%d", - (op & 0x20) ? 'U' : 'S', - infix, - (int) (opcode >> 12) & 0xf, - (int) (opcode >> 8) & 0xf, - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf); - break; - case 0x1f: - case 0x3f: - sprintf(cp, "%cDIV\tr%d, r%d, r%d", - (op & 0x20) ? 'U' : 'S', - (int) (opcode >> 8) & 0xf, - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf); - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; -} - -static int t2ev_ldm_stm(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - int rn = (opcode >> 16) & 0xf; - int op = (opcode >> 22) & 0x6; - int t = (opcode >> 21) & 1; - unsigned registers = opcode & 0xffff; - char *mode = ""; - - if (opcode & (1 << 20)) - op |= 1; - - switch (op) { - case 0: - mode = "DB"; - /* FALL THROUGH */ - case 6: - sprintf(cp, "SRS%s\tsp%s, #%d", mode, - t ? "!" : "", - (unsigned) (opcode & 0x1f)); - return ERROR_OK; - case 1: - mode = "DB"; - /* FALL THROUGH */ - case 7: - sprintf(cp, "RFE%s\tr%d%s", mode, - (unsigned) ((opcode >> 16) & 0xf), - t ? "!" : ""); - return ERROR_OK; - case 2: - sprintf(cp, "STM.W\tr%d%s, ", rn, t ? "!" : ""); - break; - case 3: - if (rn == 13 && t) - sprintf(cp, "POP.W\t"); - else - sprintf(cp, "LDM.W\tr%d%s, ", rn, t ? "!" : ""); - break; - case 4: - if (rn == 13 && t) - sprintf(cp, "PUSH.W\t"); - else - sprintf(cp, "STMDB\tr%d%s, ", rn, t ? "!" : ""); - break; - case 5: - sprintf(cp, "LDMDB.W\tr%d%s, ", rn, t ? "!" : ""); - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - cp = strchr(cp, 0); - *cp++ = '{'; - for (t = 0; registers; t++, registers >>= 1) { - if ((registers & 1) == 0) - continue; - registers &= ~1; - sprintf(cp, "r%d%s", t, registers ? ", " : ""); - cp = strchr(cp, 0); - } - *cp++ = '}'; - *cp++ = 0; - - return ERROR_OK; -} - -/* load/store dual or exclusive, table branch */ -static int t2ev_ldrex_strex(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - unsigned op1op2 = (opcode >> 20) & 0x3; - unsigned op3 = (opcode >> 4) & 0xf; - char *mnemonic; - unsigned rn = (opcode >> 16) & 0xf; - unsigned rt = (opcode >> 12) & 0xf; - unsigned rd = (opcode >> 8) & 0xf; - unsigned imm = opcode & 0xff; - char *p1 = ""; - char *p2 = "]"; - - op1op2 |= (opcode >> 21) & 0xc; - switch (op1op2) { - case 0: - mnemonic = "STREX"; - goto strex; - case 1: - mnemonic = "LDREX"; - goto ldrex; - case 2: - case 6: - case 8: - case 10: - case 12: - case 14: - mnemonic = "STRD"; - goto immediate; - case 3: - case 7: - case 9: - case 11: - case 13: - case 15: - mnemonic = "LDRD"; - if (rn == 15) - goto literal; - else - goto immediate; - case 4: - switch (op3) { - case 4: - mnemonic = "STREXB"; - break; - case 5: - mnemonic = "STREXH"; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - rd = opcode & 0xf; - imm = 0; - goto strex; - case 5: - switch (op3) { - case 0: - sprintf(cp, "TBB\t[r%u, r%u]", rn, imm & 0xf); - return ERROR_OK; - case 1: - sprintf(cp, "TBH\t[r%u, r%u, LSL #1]", rn, imm & 0xf); - return ERROR_OK; - case 4: - mnemonic = "LDREXB"; - break; - case 5: - mnemonic = "LDREXH"; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - imm = 0; - goto ldrex; - } - return ERROR_COMMAND_SYNTAX_ERROR; - -strex: - imm <<= 2; - if (imm) - sprintf(cp, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x", - mnemonic, rd, rt, rn, imm, imm); - else - sprintf(cp, "%s\tr%u, r%u, [r%u]", - mnemonic, rd, rt, rn); - return ERROR_OK; - -ldrex: - imm <<= 2; - if (imm) - sprintf(cp, "%s\tr%u, [r%u, #%u]\t; %#2.2x", - mnemonic, rt, rn, imm, imm); - else - sprintf(cp, "%s\tr%u, [r%u]", - mnemonic, rt, rn); - return ERROR_OK; - -immediate: - /* two indexed modes will write back rn */ - if (opcode & (1 << 21)) { - if (opcode & (1 << 24)) /* pre-indexed */ - p2 = "]!"; - else { /* post-indexed */ - p1 = "]"; - p2 = ""; - } - } - - imm <<= 2; - sprintf(cp, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x", - mnemonic, rt, rd, rn, p1, - (opcode & (1 << 23)) ? "" : "-", - imm, p2, imm); - return ERROR_OK; - -literal: - address = thumb_alignpc4(address); - imm <<= 2; - if (opcode & (1 << 23)) - address += imm; - else - address -= imm; - sprintf(cp, "%s\tr%u, r%u, %#8.8" PRIx32, - mnemonic, rt, rd, address); - return ERROR_OK; -} - -static int t2ev_data_shift(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - int op = (opcode >> 21) & 0xf; - int rd = (opcode >> 8) & 0xf; - int rn = (opcode >> 16) & 0xf; - int type = (opcode >> 4) & 0x3; - int immed = (opcode >> 6) & 0x3; - char *mnemonic; - char *suffix = ""; - - immed |= (opcode >> 10) & 0x1c; - if (opcode & (1 << 20)) - suffix = "S"; - - switch (op) { - case 0: - if (rd == 0xf) { - if (!(opcode & (1 << 20))) - return ERROR_COMMAND_SYNTAX_ERROR; - instruction->type = ARM_TST; - mnemonic = "TST"; - suffix = ""; - goto two; - } - instruction->type = ARM_AND; - mnemonic = "AND"; - break; - case 1: - instruction->type = ARM_BIC; - mnemonic = "BIC"; - break; - case 2: - if (rn == 0xf) { - instruction->type = ARM_MOV; - switch (type) { - case 0: - if (immed == 0) { - sprintf(cp, "MOV%s.W\tr%d, r%d", - suffix, rd, - (int) (opcode & 0xf)); - return ERROR_OK; - } - mnemonic = "LSL"; - break; - case 1: - mnemonic = "LSR"; - break; - case 2: - mnemonic = "ASR"; - break; - default: - if (immed == 0) { - sprintf(cp, "RRX%s\tr%d, r%d", - suffix, rd, - (int) (opcode & 0xf)); - return ERROR_OK; - } - mnemonic = "ROR"; - break; - } - goto immediate; - } else { - instruction->type = ARM_ORR; - mnemonic = "ORR"; - } - break; - case 3: - if (rn == 0xf) { - instruction->type = ARM_MVN; - mnemonic = "MVN"; - rn = rd; - goto two; - } else { - /* instruction->type = ARM_ORN; */ - mnemonic = "ORN"; - } - break; - case 4: - if (rd == 0xf) { - if (!(opcode & (1 << 20))) - return ERROR_COMMAND_SYNTAX_ERROR; - instruction->type = ARM_TEQ; - mnemonic = "TEQ"; - suffix = ""; - goto two; - } - instruction->type = ARM_EOR; - mnemonic = "EOR"; - break; - case 8: - if (rd == 0xf) { - if (!(opcode & (1 << 20))) - return ERROR_COMMAND_SYNTAX_ERROR; - instruction->type = ARM_CMN; - mnemonic = "CMN"; - suffix = ""; - goto two; - } - instruction->type = ARM_ADD; - mnemonic = "ADD"; - break; - case 0xa: - instruction->type = ARM_ADC; - mnemonic = "ADC"; - break; - case 0xb: - instruction->type = ARM_SBC; - mnemonic = "SBC"; - break; - case 0xd: - if (rd == 0xf) { - if (!(opcode & (1 << 21))) - return ERROR_COMMAND_SYNTAX_ERROR; - instruction->type = ARM_CMP; - mnemonic = "CMP"; - suffix = ""; - goto two; - } - instruction->type = ARM_SUB; - mnemonic = "SUB"; - break; - case 0xe: - instruction->type = ARM_RSB; - mnemonic = "RSB"; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - sprintf(cp, "%s%s.W\tr%d, r%d, r%d", - mnemonic, suffix, rd, rn, (int) (opcode & 0xf)); - -shift: - cp = strchr(cp, 0); - - switch (type) { - case 0: - if (immed == 0) - return ERROR_OK; - suffix = "LSL"; - break; - case 1: - suffix = "LSR"; - if (immed == 32) - immed = 0; - break; - case 2: - suffix = "ASR"; - if (immed == 32) - immed = 0; - break; - case 3: - if (immed == 0) { - strcpy(cp, ", RRX"); - return ERROR_OK; - } - suffix = "ROR"; - break; - } - sprintf(cp, ", %s #%d", suffix, immed ? immed : 32); - return ERROR_OK; - -two: - sprintf(cp, "%s%s.W\tr%d, r%d", - mnemonic, suffix, rn, (int) (opcode & 0xf)); - goto shift; - -immediate: - sprintf(cp, "%s%s.W\tr%d, r%d, #%d", - mnemonic, suffix, rd, - (int) (opcode & 0xf), immed ? immed : 32); - return ERROR_OK; -} - -static int t2ev_data_reg(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - char *mnemonic; - char *suffix = ""; - - if (((opcode >> 4) & 0xf) == 0) { - switch ((opcode >> 21) & 0x7) { - case 0: - mnemonic = "LSL"; - break; - case 1: - mnemonic = "LSR"; - break; - case 2: - mnemonic = "ASR"; - break; - case 3: - mnemonic = "ROR"; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - instruction->type = ARM_MOV; - if (opcode & (1 << 20)) - suffix = "S"; - sprintf(cp, "%s%s.W\tr%d, r%d, r%d", - mnemonic, suffix, - (int) (opcode >> 8) & 0xf, - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf); - - } else if (opcode & (1 << 7)) { - switch ((opcode >> 20) & 0xf) { - case 0: - case 1: - case 4: - case 5: - switch ((opcode >> 4) & 0x3) { - case 1: - suffix = ", ROR #8"; - break; - case 2: - suffix = ", ROR #16"; - break; - case 3: - suffix = ", ROR #24"; - break; - } - sprintf(cp, "%cXT%c.W\tr%d, r%d%s", - (opcode & (1 << 24)) ? 'U' : 'S', - (opcode & (1 << 26)) ? 'B' : 'H', - (int) (opcode >> 8) & 0xf, - (int) (opcode >> 0) & 0xf, - suffix); - break; - case 8: - case 9: - case 0xa: - case 0xb: - if (opcode & (1 << 6)) - return ERROR_COMMAND_SYNTAX_ERROR; - if (((opcode >> 12) & 0xf) != 0xf) - return ERROR_COMMAND_SYNTAX_ERROR; - if (!(opcode & (1 << 20))) - return ERROR_COMMAND_SYNTAX_ERROR; - - switch (((opcode >> 19) & 0x04) - | ((opcode >> 4) & 0x3)) { - case 0: - mnemonic = "REV.W"; - break; - case 1: - mnemonic = "REV16.W"; - break; - case 2: - mnemonic = "RBIT"; - break; - case 3: - mnemonic = "REVSH.W"; - break; - case 4: - mnemonic = "CLZ"; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - sprintf(cp, "%s\tr%d, r%d", - mnemonic, - (int) (opcode >> 8) & 0xf, - (int) (opcode >> 0) & 0xf); - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - } - - return ERROR_OK; -} - -static int t2ev_load_word(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - int rn = (opcode >> 16) & 0xf; - int immed; - - instruction->type = ARM_LDR; - - if (rn == 0xf) { - immed = opcode & 0x0fff; - if ((opcode & (1 << 23)) == 0) - immed = -immed; - sprintf(cp, "LDR\tr%d, %#8.8" PRIx32, - (int) (opcode >> 12) & 0xf, - thumb_alignpc4(address) + immed); - return ERROR_OK; - } - - if (opcode & (1 << 23)) { - immed = opcode & 0x0fff; - sprintf(cp, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x", - (int) (opcode >> 12) & 0xf, - rn, immed, immed); - return ERROR_OK; - } - - if (!(opcode & (0x3f << 6))) { - sprintf(cp, "LDR.W\tr%d, [r%d, r%d, LSL #%d]", - (int) (opcode >> 12) & 0xf, - rn, - (int) (opcode >> 0) & 0xf, - (int) (opcode >> 4) & 0x3); - return ERROR_OK; - } - - - if (((opcode >> 8) & 0xf) == 0xe) { - immed = opcode & 0x00ff; - - sprintf(cp, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x", - (int) (opcode >> 12) & 0xf, - rn, immed, immed); - return ERROR_OK; - } - - if (((opcode >> 8) & 0xf) == 0xc || (opcode & 0x0900) == 0x0900) { - char *p1 = "]", *p2 = ""; - - if (!(opcode & 0x0500)) - return ERROR_COMMAND_SYNTAX_ERROR; - - immed = opcode & 0x00ff; - - /* two indexed modes will write back rn */ - if (opcode & 0x100) { - if (opcode & 0x400) /* pre-indexed */ - p2 = "]!"; - else { /* post-indexed */ - p1 = "]"; - p2 = ""; - } - } - - sprintf(cp, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x", - (int) (opcode >> 12) & 0xf, - rn, p1, - (opcode & 0x200) ? "" : "-", - immed, p2, immed); - return ERROR_OK; - } - - return ERROR_COMMAND_SYNTAX_ERROR; -} - -static int t2ev_load_byte_hints(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - int rn = (opcode >> 16) & 0xf; - int rt = (opcode >> 12) & 0xf; - int op2 = (opcode >> 6) & 0x3f; - unsigned immed; - char *p1 = "", *p2 = "]"; - char *mnemonic; - - switch ((opcode >> 23) & 0x3) { - case 0: - if ((rn & rt) == 0xf) { -pld_literal: - immed = opcode & 0xfff; - address = thumb_alignpc4(address); - if (opcode & (1 << 23)) - address += immed; - else - address -= immed; - sprintf(cp, "PLD\tr%d, %#8.8" PRIx32, - rt, address); - return ERROR_OK; - } - if (rn == 0x0f && rt != 0x0f) { -ldrb_literal: - immed = opcode & 0xfff; - address = thumb_alignpc4(address); - if (opcode & (1 << 23)) - address += immed; - else - address -= immed; - sprintf(cp, "LDRB\tr%d, %#8.8" PRIx32, - rt, address); - return ERROR_OK; - } - if (rn == 0x0f) - break; - if ((op2 & 0x3c) == 0x38) { - immed = opcode & 0xff; - sprintf(cp, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x", - rt, rn, immed, immed); - return ERROR_OK; - } - if ((op2 & 0x3c) == 0x30) { - if (rt == 0x0f) { - immed = opcode & 0xff; - immed = -immed; -preload_immediate: - p1 = (opcode & (1 << 21)) ? "W" : ""; - sprintf(cp, "PLD%s\t[r%d, #%d]\t; %#6.6x", - p1, rn, immed, immed); - return ERROR_OK; - } - mnemonic = "LDRB"; -ldrxb_immediate_t3: - immed = opcode & 0xff; - if (!(opcode & 0x200)) - immed = -immed; - - /* two indexed modes will write back rn */ - if (opcode & 0x100) { - if (opcode & 0x400) /* pre-indexed */ - p2 = "]!"; - else { /* post-indexed */ - p1 = "]"; - p2 = ""; - } - } -ldrxb_immediate_t2: - sprintf(cp, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x", - mnemonic, rt, rn, p1, - immed, p2, immed); - return ERROR_OK; - } - if ((op2 & 0x24) == 0x24) { - mnemonic = "LDRB"; - goto ldrxb_immediate_t3; - } - if (op2 == 0) { - int rm = opcode & 0xf; - - if (rt == 0x0f) - sprintf(cp, "PLD\t"); - else - sprintf(cp, "LDRB.W\tr%d, ", rt); - immed = (opcode >> 4) & 0x3; - cp = strchr(cp, 0); - sprintf(cp, "[r%d, r%d, LSL #%d]", rn, rm, immed); - return ERROR_OK; - } - break; - case 1: - if ((rn & rt) == 0xf) - goto pld_literal; - if (rt == 0xf) { - immed = opcode & 0xfff; - goto preload_immediate; - } - if (rn == 0x0f) - goto ldrb_literal; - mnemonic = "LDRB.W"; - immed = opcode & 0xfff; - goto ldrxb_immediate_t2; - case 2: - if ((rn & rt) == 0xf) { - immed = opcode & 0xfff; - address = thumb_alignpc4(address); - if (opcode & (1 << 23)) - address += immed; - else - address -= immed; - sprintf(cp, "PLI\t%#8.8" PRIx32, address); - return ERROR_OK; - } - if (rn == 0xf && rt != 0xf) { -ldrsb_literal: - immed = opcode & 0xfff; - address = thumb_alignpc4(address); - if (opcode & (1 << 23)) - address += immed; - else - address -= immed; - sprintf(cp, "LDRSB\t%#8.8" PRIx32, address); - return ERROR_OK; - } - if (rn == 0xf) - break; - if ((op2 & 0x3c) == 0x38) { - immed = opcode & 0xff; - sprintf(cp, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x", - rt, rn, immed, immed); - return ERROR_OK; - } - if ((op2 & 0x3c) == 0x30) { - if (rt == 0xf) { - immed = opcode & 0xff; - immed = -immed; /* pli */ - sprintf(cp, "PLI\t[r%d, #%d]\t; -%#2.2x", - rn, immed, -immed); - return ERROR_OK; - } - mnemonic = "LDRSB"; - goto ldrxb_immediate_t3; - } - if ((op2 & 0x24) == 0x24) { - mnemonic = "LDRSB"; - goto ldrxb_immediate_t3; - } - if (op2 == 0) { - int rm = opcode & 0xf; - - if (rt == 0x0f) - sprintf(cp, "PLI\t"); - else - sprintf(cp, "LDRSB.W\tr%d, ", rt); - immed = (opcode >> 4) & 0x3; - cp = strchr(cp, 0); - sprintf(cp, "[r%d, r%d, LSL #%d]", rn, rm, immed); - return ERROR_OK; - } - break; - case 3: - if (rt == 0xf) { - immed = opcode & 0xfff; - sprintf(cp, "PLI\t[r%d, #%d]\t; %#3.3x", - rn, immed, immed); - return ERROR_OK; - } - if (rn == 0xf) - goto ldrsb_literal; - immed = opcode & 0xfff; - mnemonic = "LDRSB"; - goto ldrxb_immediate_t2; - } - - return ERROR_COMMAND_SYNTAX_ERROR; -} - -static int t2ev_load_halfword(uint32_t opcode, uint32_t address, - struct arm_instruction *instruction, char *cp) -{ - int rn = (opcode >> 16) & 0xf; - int rt = (opcode >> 12) & 0xf; - int op2 = (opcode >> 6) & 0x3f; - char *sign = ""; - unsigned immed; - - if (rt == 0xf) { - sprintf(cp, "HINT (UNALLOCATED)"); - return ERROR_OK; - } - - if (opcode & (1 << 24)) - sign = "S"; - - if ((opcode & (1 << 23)) == 0) { - if (rn == 0xf) { -ldrh_literal: - immed = opcode & 0xfff; - address = thumb_alignpc4(address); - if (opcode & (1 << 23)) - address += immed; - else - address -= immed; - sprintf(cp, "LDR%sH\tr%d, %#8.8" PRIx32, - sign, rt, address); - return ERROR_OK; - } - if (op2 == 0) { - int rm = opcode & 0xf; - - immed = (opcode >> 4) & 0x3; - sprintf(cp, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]", - sign, rt, rn, rm, immed); - return ERROR_OK; - } - if ((op2 & 0x3c) == 0x38) { - immed = opcode & 0xff; - sprintf(cp, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x", - sign, rt, rn, immed, immed); - return ERROR_OK; - } - if ((op2 & 0x3c) == 0x30 || (op2 & 0x24) == 0x24) { - char *p1 = "", *p2 = "]"; - - immed = opcode & 0xff; - if (!(opcode & 0x200)) - immed = -immed; - - /* two indexed modes will write back rn */ - if (opcode & 0x100) { - if (opcode & 0x400) /* pre-indexed */ - p2 = "]!"; - else { /* post-indexed */ - p1 = "]"; - p2 = ""; - } - } - sprintf(cp, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x", - sign, rt, rn, p1, immed, p2, immed); - return ERROR_OK; - } - } else { - if (rn == 0xf) - goto ldrh_literal; - - immed = opcode & 0xfff; - sprintf(cp, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x", - sign, *sign ? "" : ".W", - rt, rn, immed, immed); - return ERROR_OK; - } - - return ERROR_COMMAND_SYNTAX_ERROR; -} - -/* - * REVISIT for Thumb2 instructions, instruction->type and friends aren't - * always set. That means eventual arm_simulate_step() support for Thumb2 - * will need work in this area. - */ -int thumb2_opcode(struct target *target, uint32_t address, struct arm_instruction *instruction) -{ - int retval; - uint16_t op; - uint32_t opcode; - char *cp; - - /* clear low bit ... it's set on function pointers */ - address &= ~1; - - /* clear fields, to avoid confusion */ - memset(instruction, 0, sizeof(struct arm_instruction)); - - /* read first halfword, see if this is the only one */ - retval = target_read_u16(target, address, &op); - if (retval != ERROR_OK) - return retval; - - switch (op & 0xf800) { - case 0xf800: - case 0xf000: - case 0xe800: - /* 32-bit instructions */ - instruction->instruction_size = 4; - opcode = op << 16; - retval = target_read_u16(target, address + 2, &op); - if (retval != ERROR_OK) - return retval; - opcode |= op; - instruction->opcode = opcode; - break; - default: - /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */ - return thumb_evaluate_opcode(op, address, instruction); - } - - snprintf(instruction->text, 128, - "0x%8.8" PRIx32 " 0x%8.8" PRIx32 "\t", - address, opcode); - cp = strchr(instruction->text, 0); - retval = ERROR_FAIL; - - /* ARMv7-M: A5.3.1 Data processing (modified immediate) */ - if ((opcode & 0x1a008000) == 0x10000000) - retval = t2ev_data_mod_immed(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */ - else if ((opcode & 0x1a008000) == 0x12000000) - retval = t2ev_data_immed(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.4 Branches and miscellaneous control */ - else if ((opcode & 0x18008000) == 0x10008000) - retval = t2ev_b_misc(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.5 Load/store multiple */ - else if ((opcode & 0x1e400000) == 0x08000000) - retval = t2ev_ldm_stm(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */ - else if ((opcode & 0x1e400000) == 0x08400000) - retval = t2ev_ldrex_strex(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.7 Load word */ - else if ((opcode & 0x1f700000) == 0x18500000) - retval = t2ev_load_word(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */ - else if ((opcode & 0x1e700000) == 0x18300000) - retval = t2ev_load_halfword(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.9 Load byte, memory hints */ - else if ((opcode & 0x1e700000) == 0x18100000) - retval = t2ev_load_byte_hints(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.10 Store single data item */ - else if ((opcode & 0x1f100000) == 0x18000000) - retval = t2ev_store_single(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.11 Data processing (shifted register) */ - else if ((opcode & 0x1e000000) == 0x0a000000) - retval = t2ev_data_shift(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.12 Data processing (register) - * and A5.3.13 Miscellaneous operations - */ - else if ((opcode & 0x1f000000) == 0x1a000000) - retval = t2ev_data_reg(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */ - else if ((opcode & 0x1f800000) == 0x1b000000) - retval = t2ev_mul32(opcode, address, instruction, cp); - - /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */ - else if ((opcode & 0x1f800000) == 0x1b800000) - retval = t2ev_mul64_div(opcode, address, instruction, cp); - - if (retval == ERROR_OK) - return retval; - - /* - * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD) - * instructions; not yet handled here. - */ - - if (retval == ERROR_COMMAND_SYNTAX_ERROR) { - instruction->type = ARM_UNDEFINED_INSTRUCTION; - strcpy(cp, "UNDEFINED OPCODE"); - return ERROR_OK; - } - - LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32 ")", - opcode); - - strcpy(cp, "(32-bit Thumb2 ...)"); - return ERROR_OK; -} - -int arm_access_size(struct arm_instruction *instruction) -{ - if ((instruction->type == ARM_LDRB) - || (instruction->type == ARM_LDRBT) - || (instruction->type == ARM_LDRSB) - || (instruction->type == ARM_STRB) - || (instruction->type == ARM_STRBT)) - return 1; - else if ((instruction->type == ARM_LDRH) - || (instruction->type == ARM_LDRSH) - || (instruction->type == ARM_STRH)) - return 2; - else if ((instruction->type == ARM_LDR) - || (instruction->type == ARM_LDRT) - || (instruction->type == ARM_STR) - || (instruction->type == ARM_STRT)) - return 4; - else if ((instruction->type == ARM_LDRD) - || (instruction->type == ARM_STRD)) - return 8; - else { - LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", - instruction->type); - return 0; - } -} +#endif /* HAVE_CAPSTONE */ diff --git a/src/target/arm_disassembler.h b/src/target/arm_disassembler.h index 486e903e32..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 @@ -112,11 +101,11 @@ enum arm_instruction_type { ARM_QDADD, ARM_QSUB, ARM_QDSUB, - ARM_SMLAxy, - ARM_SMLALxy, - ARM_SMLAWy, - ARM_SMULxy, - ARM_SMULWy, + ARM_SMLAXY, + ARM_SMLALXY, + ARM_SMLAWY, + ARM_SMULXY, + ARM_SMULWY, ARM_LDRD, ARM_STRD, @@ -133,35 +122,35 @@ union arm_shifter_operand { uint32_t immediate; } immediate; struct { - uint8_t Rm; + uint8_t rm; uint8_t shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */ uint8_t shift_imm; } immediate_shift; struct { - uint8_t Rm; + uint8_t rm; uint8_t shift; - uint8_t Rs; + uint8_t rs; } register_shift; }; struct arm_data_proc_instr { int variant; /* 0: immediate, 1: immediate_shift, 2: register_shift */ - uint8_t S; - uint8_t Rn; - uint8_t Rd; + uint8_t s; + uint8_t rn; + uint8_t rd; union arm_shifter_operand shifter_operand; }; struct arm_load_store_instr { - uint8_t Rd; - uint8_t Rn; - uint8_t U; + uint8_t rd; + uint8_t rn; + uint8_t u; int index_mode; /* 0: offset, 1: pre-indexed, 2: post-indexed */ int offset_mode; /* 0: immediate, 1: (scaled) register */ union { uint32_t offset; struct { - uint8_t Rm; + uint8_t rm; uint8_t shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */ uint8_t shift_imm; } reg; @@ -169,11 +158,11 @@ struct arm_load_store_instr { }; struct arm_load_store_multiple_instr { - uint8_t Rn; + uint8_t rn; uint32_t register_list; uint8_t addressing_mode; /* 0: IA, 1: IB, 2: DA, 3: DB */ - uint8_t S; - uint8_t W; + uint8_t s; + uint8_t w; }; struct arm_instruction { @@ -197,9 +186,11 @@ int arm_evaluate_opcode(uint32_t opcode, uint32_t address, struct arm_instruction *instruction); int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, struct arm_instruction *instruction); -int thumb2_opcode(struct target *target, uint32_t address, - struct arm_instruction *instruction); int arm_access_size(struct arm_instruction *instruction); +#if HAVE_CAPSTONE +int arm_disassemble(struct command_invocation *cmd, struct target *target, + target_addr_t address, size_t count, bool thumb_mode); +#endif #define COND(opcode) (arm_condition_strings[(opcode & 0xf0000000) >> 28]) diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 6bfe355ba2..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 @@ -50,7 +39,7 @@ /* Read coprocessor */ static int dpm_mrc(struct target *target, int cpnum, - uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, + uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { struct arm *arm = target_to_arm(target); @@ -62,12 +51,35 @@ static int dpm_mrc(struct target *target, int cpnum, return retval; LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum, - (int) op1, (int) CRn, - (int) CRm, (int) op2); + (int) op1, (int) crn, + (int) crm, (int) op2); /* read coprocessor register into R0; return via DCC */ retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2), + ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2), + value); + + /* (void) */ dpm->finish(dpm); + 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); @@ -75,7 +87,7 @@ static int dpm_mrc(struct target *target, int cpnum, } static int dpm_mcr(struct target *target, int cpnum, - uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, + uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { struct arm *arm = target_to_arm(target); @@ -87,18 +99,41 @@ static int dpm_mcr(struct target *target, int cpnum, return retval; LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum, - (int) op1, (int) CRn, - (int) CRm, (int) op2); + (int) op1, (int) crn, + (int) crm, (int) op2); /* read DCC into r0; then write coprocessor register from R0 */ retval = dpm->instr_write_data_r0(dpm, - ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2), + ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2), value); /* (void) */ dpm->finish(dpm); 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; +} + /*----------------------------------------------------------------------*/ /* @@ -398,7 +433,7 @@ fail: * or running debugger code. */ static int dpm_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, - struct dpm_bpwp *xp, int *set_p) + struct dpm_bpwp *xp, bool *set_p) { int retval = ERROR_OK; bool disable; @@ -473,7 +508,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct breakpoint *bp = dbp->bp; retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, - bp ? &bp->set : NULL); + bp ? &bp->is_set : NULL); if (retval != ERROR_OK) goto done; } @@ -485,7 +520,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct watchpoint *wp = dwp->wp; retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, - wp ? &wp->set : NULL); + wp ? &wp->is_set : NULL); if (retval != ERROR_OK) goto done; } @@ -514,7 +549,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) continue; if (arm->cpsr == cache->reg_list + i) continue; - if (!cache->reg_list[i].dirty) + if (!cache->reg_list[i].exist || !cache->reg_list[i].dirty) continue; r = cache->reg_list[i].arch_info; @@ -763,7 +798,7 @@ static int arm_dpm_full_context(struct target *target) for (unsigned i = 0; i < cache->num_regs; i++) { struct arm_reg *r; - if (cache->reg_list[i].valid) + if (!cache->reg_list[i].exist || cache->reg_list[i].valid) continue; r = cache->reg_list[i].arch_info; @@ -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; } @@ -1010,7 +1045,7 @@ void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr) /* ?? */ break; } - dpm->wp_pc = addr; + dpm->wp_addr = addr; } /*----------------------------------------------------------------------*/ @@ -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; @@ -1070,7 +1105,7 @@ int arm_dpm_setup(struct arm_dpm *dpm) arm->read_core_reg = arm_dpm_read_core_reg; arm->write_core_reg = arm_dpm_write_core_reg; - if (arm->core_cache == NULL) { + if (!arm->core_cache) { cache = arm_build_reg_cache(target, arm); if (!cache) return ERROR_FAIL; @@ -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) { @@ -1088,9 +1125,11 @@ int arm_dpm_setup(struct arm_dpm *dpm) target->type->remove_breakpoint = dpm_remove_breakpoint; } - /* watchpoint setup */ - target->type->add_watchpoint = dpm_add_watchpoint; - target->type->remove_watchpoint = dpm_remove_watchpoint; + /* watchpoint setup -- optional until it works everywhere */ + if (!target->type->add_watchpoint) { + target->type->add_watchpoint = dpm_add_watchpoint; + target->type->remove_watchpoint = dpm_remove_watchpoint; + } /* FIXME add vector catch support */ diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h index 82707822b1..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); @@ -137,8 +139,12 @@ struct arm_dpm { struct dpm_bp *dbp; struct dpm_wp *dwp; - /** Address of the instruction which triggered a watchpoint. */ - target_addr_t wp_pc; + /** + * Target dependent watchpoint address. + * Either the address of the instruction which triggered a watchpoint + * or the memory address whose access triggered a watchpoint. + */ + target_addr_t wp_addr; /** Recent value of DSCR. */ uint32_t dscr; @@ -237,7 +243,7 @@ void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dcsr); /* OSLSR (OS Lock Status Register) bits */ #define OSLSR_OSLM0 (1 << 0) #define OSLSR_OSLK (1 << 1) -#define OSLSR_nTT (1 << 2) +#define OSLSR_NTT (1 << 2) #define OSLSR_OSLM1 (1 << 3) #define OSLSR_OSLM (OSLSR_OSLM0|OSLSR_OSLM1) diff --git a/src/target/arm_jtag.c b/src/target/arm_jtag.c index f9605acb16..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 @@ -40,7 +29,7 @@ int arm_jtag_set_instr_inner(struct jtag_tap *tap, buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; - if (no_verify_capture == NULL) + if (!no_verify_capture) jtag_add_ir_scan(tap, &field, end_state); else { /* FIX!!!! this is a kludge!!! arm926ejs.c should reimplement this arm_jtag_set_instr to diff --git a/src/target/arm_jtag.h b/src/target/arm_jtag.h index bf5b837486..11b7c3efd7 100644 --- a/src/target/arm_jtag.h +++ b/src/target/arm_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_TARGET_ARM_JTAG_H #define OPENOCD_TARGET_ARM_JTAG_H #include <jtag/jtag.h> +#include <helper/bits.h> struct arm_jtag { struct jtag_tap *tap; @@ -42,7 +32,7 @@ static inline int arm_jtag_set_instr(struct jtag_tap *tap, uint32_t new_instr, void *no_verify_capture, tap_state_t end_state) { /* inline most common code path */ - if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) + if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (new_instr & (BIT(tap->ir_length) - 1))) return arm_jtag_set_instr_inner(tap, new_instr, no_verify_capture, end_state); return ERROR_OK; diff --git a/src/target/arm_opcodes.h b/src/target/arm_opcodes.h index 90f8416000..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 @@ -36,184 +25,206 @@ /* ARM mode instructions */ /* Store multiple increment after - * Rn: base register - * List: for each bit in list: store register - * S: in privileged mode: store user-mode registers - * W = 1: update the base register. W = 0: leave the base register untouched + * rn: base register + * list: for each bit in list: store register + * s: in privileged mode: store user-mode registers + * w = 1: update the base register. w = 0: leave the base register untouched */ -#define ARMV4_5_STMIA(Rn, List, S, W) \ - (0xe8800000 | ((S) << 22) | ((W) << 21) | ((Rn) << 16) | (List)) +#define ARMV4_5_STMIA(rn, list, s, w) \ + (0xe8800000 | ((s) << 22) | ((w) << 21) | ((rn) << 16) | (list)) /* Load multiple increment after - * Rn: base register - * List: for each bit in list: store register - * S: in privileged mode: store user-mode registers - * W = 1: update the base register. W = 0: leave the base register untouched + * rn: base register + * list: for each bit in list: store register + * s: in privileged mode: store user-mode registers + * w = 1: update the base register. w = 0: leave the base register untouched */ -#define ARMV4_5_LDMIA(Rn, List, S, W) \ - (0xe8900000 | ((S) << 22) | ((W) << 21) | ((Rn) << 16) | (List)) +#define ARMV4_5_LDMIA(rn, list, s, w) \ + (0xe8900000 | ((s) << 22) | ((w) << 21) | ((rn) << 16) | (list)) /* MOV r8, r8 */ #define ARMV4_5_NOP (0xe1a08008) /* Move PSR to general purpose register - * R = 1: SPSR R = 0: CPSR - * Rn: target register + * r = 1: SPSR r = 0: CPSR + * rn: target register */ -#define ARMV4_5_MRS(Rn, R) (0xe10f0000 | ((R) << 22) | ((Rn) << 12)) +#define ARMV4_5_MRS(rn, r) (0xe10f0000 | ((r) << 22) | ((rn) << 12)) /* Store register - * Rd: register to store - * Rn: base register + * rd: register to store + * rn: base register */ -#define ARMV4_5_STR(Rd, Rn) (0xe5800000 | ((Rd) << 12) | ((Rn) << 16)) +#define ARMV4_5_STR(rd, rn) (0xe5800000 | ((rd) << 12) | ((rn) << 16)) /* Load register - * Rd: register to load - * Rn: base register + * rd: register to load + * rn: base register */ -#define ARMV4_5_LDR(Rd, Rn) (0xe5900000 | ((Rd) << 12) | ((Rn) << 16)) +#define ARMV4_5_LDR(rd, rn) (0xe5900000 | ((rd) << 12) | ((rn) << 16)) /* Move general purpose register to PSR - * R = 1: SPSR R = 0: CPSR - * Field: Field mask + * r = 1: SPSR r = 0: CPSR + * field: Field mask * 1: control field 2: extension field 4: status field 8: flags field - * Rm: source register + * rm: source register */ -#define ARMV4_5_MSR_GP(Rm, Field, R) \ - (0xe120f000 | (Rm) | ((Field) << 16) | ((R) << 22)) -#define ARMV4_5_MSR_IM(Im, Rotate, Field, R) \ - (0xe320f000 | (Im) | ((Rotate) << 8) | ((Field) << 16) | ((R) << 22)) +#define ARMV4_5_MSR_GP(rm, field, r) \ + (0xe120f000 | (rm) | ((field) << 16) | ((r) << 22)) +#define ARMV4_5_MSR_IM(im, rotate, field, r) \ + (0xe320f000 | (im) | ((rotate) << 8) | ((field) << 16) | ((r) << 22)) /* Load Register Word Immediate Post-Index - * Rd: register to load - * Rn: base register + * rd: register to load + * rn: base register */ -#define ARMV4_5_LDRW_IP(Rd, Rn) (0xe4900004 | ((Rd) << 12) | ((Rn) << 16)) +#define ARMV4_5_LDRW_IP(rd, rn) (0xe4900004 | ((rd) << 12) | ((rn) << 16)) /* Load Register Halfword Immediate Post-Index - * Rd: register to load - * Rn: base register + * rd: register to load + * rn: base register */ -#define ARMV4_5_LDRH_IP(Rd, Rn) (0xe0d000b2 | ((Rd) << 12) | ((Rn) << 16)) +#define ARMV4_5_LDRH_IP(rd, rn) (0xe0d000b2 | ((rd) << 12) | ((rn) << 16)) /* Load Register Byte Immediate Post-Index - * Rd: register to load - * Rn: base register + * rd: register to load + * rn: base register */ -#define ARMV4_5_LDRB_IP(Rd, Rn) (0xe4d00001 | ((Rd) << 12) | ((Rn) << 16)) +#define ARMV4_5_LDRB_IP(rd, rn) (0xe4d00001 | ((rd) << 12) | ((rn) << 16)) /* Store register Word Immediate Post-Index - * Rd: register to store - * Rn: base register + * rd: register to store + * rn: base register */ -#define ARMV4_5_STRW_IP(Rd, Rn) (0xe4800004 | ((Rd) << 12) | ((Rn) << 16)) +#define ARMV4_5_STRW_IP(rd, rn) (0xe4800004 | ((rd) << 12) | ((rn) << 16)) /* Store register Halfword Immediate Post-Index - * Rd: register to store - * Rn: base register + * rd: register to store + * rn: base register */ -#define ARMV4_5_STRH_IP(Rd, Rn) (0xe0c000b2 | ((Rd) << 12) | ((Rn) << 16)) +#define ARMV4_5_STRH_IP(rd, rn) (0xe0c000b2 | ((rd) << 12) | ((rn) << 16)) /* Store register Byte Immediate Post-Index - * Rd: register to store - * Rn: base register + * rd: register to store + * rn: base register */ -#define ARMV4_5_STRB_IP(Rd, Rn) (0xe4c00001 | ((Rd) << 12) | ((Rn) << 16)) +#define ARMV4_5_STRB_IP(rd, rn) (0xe4c00001 | ((rd) << 12) | ((rn) << 16)) /* Branch (and Link) - * Im: Branch target (left-shifted by 2 bits, added to PC) - * L: 1: branch and link 0: branch only + * im: Branch target (left-shifted by 2 bits, added to PC) + * l: 1: branch and link 0: branch only */ -#define ARMV4_5_B(Im, L) (0xea000000 | (Im) | ((L) << 24)) +#define ARMV4_5_B(im, l) (0xea000000 | (im) | ((l) << 24)) /* Branch and exchange (ARM state) - * Rm: register holding branch target address + * rm: register holding branch target address */ -#define ARMV4_5_BX(Rm) (0xe12fff10 | (Rm)) +#define ARMV4_5_BX(rm) (0xe12fff10 | (rm)) /* Copies two words from two ARM core registers * into a doubleword extension register, or * from a doubleword extension register to two ARM core registers. * See Armv7-A arch reference manual section A8.8.345 - * Rt: Arm core register 1 - * Rt2: Arm core register 2 - * Vm: The doubleword extension register - * M: m = UInt(M:Vm); + * rt: Arm core register 1 + * rt2: Arm core register 2 + * vm: The doubleword extension register + * m: m = UInt(m:vm); * op: to_arm_registers = (op == ‘1’); */ -#define ARMV4_5_VMOV(op, Rt2, Rt, M, Vm) \ - (0xec400b10 | ((op) << 20) | ((Rt2) << 16) | \ - ((Rt) << 12) | ((M) << 5) | (Vm)) +#define ARMV4_5_VMOV(op, rt2, rt, m, vm) \ + (0xec400b10 | ((op) << 20) | ((rt2) << 16) | \ + ((rt) << 12) | ((m) << 5) | (vm)) /* Moves the value of the FPSCR to an ARM core register - * Rt: Arm core register + * rt: Arm core register */ -#define ARMV4_5_VMRS(Rt) (0xeef10a10 | ((Rt) << 12)) +#define ARMV4_5_VMRS(rt) (0xeef10a10 | ((rt) << 12)) /* Moves the value of an ARM core register to the FPSCR. - * Rt: Arm core register + * rt: Arm core register */ -#define ARMV4_5_VMSR(Rt) (0xeee10a10 | ((Rt) << 12)) +#define ARMV4_5_VMSR(rt) (0xeee10a10 | ((rt) << 12)) /* Store data from coprocessor to consecutive memory * See Armv7-A arch doc section A8.6.187 - * P: 1=index mode (offset from Rn) - * U: 1=add, 0=subtract Rn address with imm - * D: Opcode D encoding - * W: write back the offset start address to the Rn register - * CP: Coprocessor number (4 bits) - * CRd: Coprocessor source register (4 bits) - * Rn: Base register for memory address (4 bits) + * p: 1=index mode (offset from rn) + * u: 1=add, 0=subtract rn address with imm + * d: Opcode D encoding + * w: write back the offset start address to the rn register + * cp: Coprocessor number (4 bits) + * crd: Coprocessor source register (4 bits) + * rn: Base register for memory address (4 bits) * imm: Immediate value (0 - 1020, must be divisible by 4) */ -#define ARMV4_5_STC(P, U, D, W, CP, CRd, Rn, imm) \ - (0xec000000 | ((P) << 24) | ((U) << 23) | ((D) << 22) | \ - ((W) << 21) | ((Rn) << 16) | ((CRd) << 12) | ((CP) << 8) | ((imm)>>2)) +#define ARMV4_5_STC(p, u, d, w, cp, crd, rn, imm) \ + (0xec000000 | ((p) << 24) | ((u) << 23) | ((d) << 22) | \ + ((w) << 21) | ((rn) << 16) | ((crd) << 12) | ((cp) << 8) | ((imm)>>2)) /* Loads data from consecutive memory to coprocessor * See Armv7-A arch doc section A8.6.51 - * P: 1=index mode (offset from Rn) - * U: 1=add, 0=subtract Rn address with imm - * D: Opcode D encoding - * W: write back the offset start address to the Rn register - * CP: Coprocessor number (4 bits) - * CRd: Coprocessor dest register (4 bits) - * Rn: Base register for memory address (4 bits) + * p: 1=index mode (offset from rn) + * u: 1=add, 0=subtract rn address with imm + * d: Opcode D encoding + * w: write back the offset start address to the rn register + * cp: Coprocessor number (4 bits) + * crd: Coprocessor dest register (4 bits) + * rn: Base register for memory address (4 bits) * imm: Immediate value (0 - 1020, must be divisible by 4) */ -#define ARMV4_5_LDC(P, U, D, W, CP, CRd, Rn, imm) \ - (0xec100000 | ((P) << 24) | ((U) << 23) | ((D) << 22) | \ - ((W) << 21) | ((Rn) << 16) | ((CRd) << 12) | ((CP) << 8) | ((imm) >> 2)) +#define ARMV4_5_LDC(p, u, d, w, cp, crd, rn, imm) \ + (0xec100000 | ((p) << 24) | ((u) << 23) | ((d) << 22) | \ + ((w) << 21) | ((rn) << 16) | ((crd) << 12) | ((cp) << 8) | ((imm) >> 2)) /* Move to ARM register from coprocessor - * CP: Coprocessor number + * cp: Coprocessor number * op1: Coprocessor opcode - * Rd: destination register - * CRn: first coprocessor operand - * CRm: second coprocessor operand + * rd: destination register + * crn: first coprocessor operand + * crm: second coprocessor operand * op2: Second coprocessor opcode */ -#define ARMV4_5_MRC(CP, op1, Rd, CRn, CRm, op2) \ - (0xee100010 | (CRm) | ((op2) << 5) | ((CP) << 8) \ - | ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21)) +#define ARMV4_5_MRC(cp, op1, rd, crn, crm, op2) \ + (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 + * cp: Coprocessor number * op1: Coprocessor opcode - * Rd: destination register - * CRn: first coprocessor operand - * CRm: second coprocessor operand + * rd: destination register + * crn: first coprocessor operand + * crm: second coprocessor operand * op2: Second coprocessor opcode */ -#define ARMV4_5_MCR(CP, op1, Rd, CRn, CRm, op2) \ - (0xee000010 | (CRm) | ((op2) << 5) | ((CP) << 8) \ - | ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21)) +#define ARMV4_5_MCR(cp, op1, rd, crn, crm, op2) \ + (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 + * im: 16-bit immediate */ -#define ARMV5_BKPT(Im) (0xe1200070 | ((Im & 0xfff0) << 4) | (Im & 0xf)) +#define ARMV5_BKPT(im) (0xe1200070 | ((im & 0xfff0) << 4) | (im & 0xf)) /* Thumb mode instructions @@ -228,45 +239,45 @@ */ /* Store register (Thumb mode) - * Rd: source register - * Rn: base register + * rd: source register + * rn: base register */ -#define ARMV4_5_T_STR(Rd, Rn) \ - ((0x6000 | (Rd) | ((Rn) << 3)) | \ - ((0x6000 | (Rd) | ((Rn) << 3)) << 16)) +#define ARMV4_5_T_STR(rd, rn) \ + ((0x6000 | (rd) | ((rn) << 3)) | \ + ((0x6000 | (rd) | ((rn) << 3)) << 16)) /* Load register (Thumb state) - * Rd: destination register - * Rn: base register + * rd: destination register + * rn: base register */ -#define ARMV4_5_T_LDR(Rd, Rn) \ - ((0x6800 | ((Rn) << 3) | (Rd)) \ - | ((0x6800 | ((Rn) << 3) | (Rd)) << 16)) +#define ARMV4_5_T_LDR(rd, rn) \ + ((0x6800 | ((rn) << 3) | (rd)) \ + | ((0x6800 | ((rn) << 3) | (rd)) << 16)) /* Load multiple (Thumb state) - * Rn: base register - * List: for each bit in list: store register + * rn: base register + * list: for each bit in list: store register */ -#define ARMV4_5_T_LDMIA(Rn, List) \ - ((0xc800 | ((Rn) << 8) | (List)) \ - | ((0xc800 | ((Rn) << 8) | (List)) << 16)) +#define ARMV4_5_T_LDMIA(rn, list) \ + ((0xc800 | ((rn) << 8) | (list)) \ + | ((0xc800 | ((rn) << 8) | (list)) << 16)) /* Load register with PC relative addressing - * Rd: register to load + * rd: register to load */ -#define ARMV4_5_T_LDR_PCREL(Rd) \ - ((0x4800 | ((Rd) << 8)) \ - | ((0x4800 | ((Rd) << 8)) << 16)) +#define ARMV4_5_T_LDR_PCREL(rd) \ + ((0x4800 | ((rd) << 8)) \ + | ((0x4800 | ((rd) << 8)) << 16)) /* Move hi register (Thumb mode) - * Rd: destination register - * Rm: source register + * rd: destination register + * rm: source register */ -#define ARMV4_5_T_MOV(Rd, Rm) \ - ((0x4600 | ((Rd) & 0x7) | (((Rd) & 0x8) << 4) | \ - (((Rm) & 0x7) << 3) | (((Rm) & 0x8) << 3)) \ - | ((0x4600 | ((Rd) & 0x7) | (((Rd) & 0x8) << 4) | \ - (((Rm) & 0x7) << 3) | (((Rm) & 0x8) << 3)) << 16)) +#define ARMV4_5_T_MOV(rd, rm) \ + ((0x4600 | ((rd) & 0x7) | (((rd) & 0x8) << 4) | \ + (((rm) & 0x7) << 3) | (((rm) & 0x8) << 3)) \ + | ((0x4600 | ((rd) & 0x7) | (((rd) & 0x8) << 4) | \ + (((rm) & 0x7) << 3) | (((rm) & 0x8) << 3)) << 16)) /* No operation (Thumb mode) * NOTE: this is "MOV r8, r8" ... Thumb2 adds two @@ -275,63 +286,63 @@ #define ARMV4_5_T_NOP (0x46c0 | (0x46c0 << 16)) /* Move immediate to register (Thumb state) - * Rd: destination register - * Im: 8-bit immediate value + * rd: destination register + * im: 8-bit immediate value */ -#define ARMV4_5_T_MOV_IM(Rd, Im) \ - ((0x2000 | ((Rd) << 8) | (Im)) \ - | ((0x2000 | ((Rd) << 8) | (Im)) << 16)) +#define ARMV4_5_T_MOV_IM(rd, im) \ + ((0x2000 | ((rd) << 8) | (im)) \ + | ((0x2000 | ((rd) << 8) | (im)) << 16)) /* Branch and Exchange - * Rm: register containing branch target + * rm: register containing branch target */ -#define ARMV4_5_T_BX(Rm) \ - ((0x4700 | ((Rm) << 3)) \ - | ((0x4700 | ((Rm) << 3)) << 16)) +#define ARMV4_5_T_BX(rm) \ + ((0x4700 | ((rm) << 3)) \ + | ((0x4700 | ((rm) << 3)) << 16)) /* Branch (Thumb state) - * Imm: Branch target + * imm: Branch target */ -#define ARMV4_5_T_B(Imm) \ - ((0xe000 | (Imm)) \ - | ((0xe000 | (Imm)) << 16)) +#define ARMV4_5_T_B(imm) \ + ((0xe000 | (imm)) \ + | ((0xe000 | (imm)) << 16)) /* Breakpoint instruction (ARMv5) (Thumb state) * Im: 8-bit immediate */ -#define ARMV5_T_BKPT(Im) \ - ((0xbe00 | (Im)) \ - | ((0xbe00 | (Im)) << 16)) +#define ARMV5_T_BKPT(im) \ + ((0xbe00 | (im)) \ + | ((0xbe00 | (im)) << 16)) /* Move to Register from Special Register * 32 bit Thumb2 instruction - * Rd: destination register - * SYSm: source special register + * rd: destination register + * sysm: source special register */ -#define ARM_T2_MRS(Rd, SYSm) \ - ((0xF3EF) | ((0x8000 | (Rd << 8) | SYSm) << 16)) +#define ARM_T2_MRS(rd, sysm) \ + ((0xF3EF) | ((0x8000 | (rd << 8) | sysm) << 16)) /* Move from Register from Special Register * 32 bit Thumb2 instruction - * Rd: source register - * SYSm: destination special register + * rd: source register + * sysm: destination special register */ -#define ARM_T2_MSR(SYSm, Rn) \ - ((0xF380 | (Rn << 8)) | ((0x8800 | SYSm) << 16)) +#define ARM_T2_MSR(sysm, rn) \ + ((0xF380 | (rn << 8)) | ((0x8800 | sysm) << 16)) /* Change Processor State. * 16 bit Thumb2 instruction - * Rd: source register + * rd: source register * IF: A_FLAG and/or I_FLAG and/or F_FLAG */ #define A_FLAG 4 #define I_FLAG 2 #define F_FLAG 1 -#define ARM_T2_CPSID(IF) \ - ((0xB660 | (1 << 8) | ((IF)&0x3)) \ - | ((0xB660 | (1 << 8) | ((IF)&0x3)) << 16)) -#define ARM_T2_CPSIE(IF) \ - ((0xB660 | (0 << 8) | ((IF)&0x3)) \ - | ((0xB660 | (0 << 8) | ((IF)&0x3)) << 16)) +#define ARM_T2_CPSID(_if) \ + ((0xB660 | (1 << 8) | ((_if)&0x3)) \ + | ((0xB660 | (1 << 8) | ((_if)&0x3)) << 16)) +#define ARM_T2_CPSIE(_if) \ + ((0xB660 | (0 << 8) | ((_if)&0x3)) \ + | ((0xB660 | (0 << 8) | ((_if)&0x3)) << 16)) #endif /* OPENOCD_TARGET_ARM_OPCODES_H */ diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 61f1e7801f..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/>. * ***************************************************************************/ /** @@ -123,6 +112,22 @@ static int post_result(struct target *target) uint64_t pc = buf_get_u64(arm->core_cache->reg_list[32].value, 0, 64); buf_set_u64(arm->pc->value, 0, 64, pc + 4); arm->pc->dirty = true; + } else if (arm->core_state == ARM_STATE_ARM) { + /* return value in R0 */ + buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result); + arm->core_cache->reg_list[0].dirty = true; + + uint32_t pc = buf_get_u32(arm->core_cache->reg_list[32].value, 0, 32); + buf_set_u32(arm->pc->value, 0, 32, pc + 4); + arm->pc->dirty = true; + } else if (arm->core_state == ARM_STATE_THUMB) { + /* return value in R0 */ + buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result); + arm->core_cache->reg_list[0].dirty = true; + + uint32_t pc = buf_get_u32(arm->core_cache->reg_list[32].value, 0, 32); + buf_set_u32(arm->pc->value, 0, 32, pc + 2); + arm->pc->dirty = true; } } else { /* resume execution, this will be pc+2 to skip over the @@ -275,6 +280,16 @@ int arm_semihosting(struct target *target, int *retval) if (target->debug_reason != DBG_REASON_BREAKPOINT) return 0; + /* According to ARM Semihosting for AArch32 and AArch64: + * The HLT encodings are new in version 2.0 of the semihosting specification. + * Where possible, have semihosting callers continue to use the previously + * existing trap instructions to ensure compatibility with legacy semihosting + * implementations. + * These trap instructions are HLT for A64, SVC on A+R profile A32 or T32, + * and BKPT on M profile. + * However, it is necessary to change from SVC to HLT instructions to support + * AArch32 semihosting properly in a mixed AArch32/AArch64 system. */ + if (arm->core_state == ARM_STATE_AARCH64) { uint32_t insn = 0; r = arm->pc; @@ -284,9 +299,38 @@ int arm_semihosting(struct target *target, int *retval) if (*retval != ERROR_OK) return 1; - /* bkpt 0xAB */ + /* HLT 0xF000 */ if (insn != 0xD45E0000) return 0; + } else if (arm->core_state == ARM_STATE_ARM) { + r = arm->pc; + pc = buf_get_u32(r->value, 0, 32); + + /* A32 instruction => check for HLT 0xF000 (0xE10F0070) */ + uint32_t insn = 0; + + *retval = target_read_u32(target, pc, &insn); + + if (*retval != ERROR_OK) + return 1; + + /* HLT 0xF000*/ + if (insn != 0xE10F0070) + return 0; + } else if (arm->core_state == ARM_STATE_THUMB) { + r = arm->pc; + pc = buf_get_u32(r->value, 0, 32); + + /* T32 instruction => check for HLT 0x3C (0xBABC) */ + uint16_t insn = 0; + *retval = target_read_u16(target, pc, &insn); + + if (*retval != ERROR_OK) + return 1; + + /* HLT 0x3C*/ + if (insn != 0xBABC) + return 0; } else return 1; } else { @@ -312,10 +356,13 @@ int arm_semihosting(struct target *target, int *retval) } /* Check for ARM operation numbers. */ - if (0 <= semihosting->op && semihosting->op <= 0x31) { + if ((semihosting->op >= 0 && semihosting->op <= 0x31) || + (semihosting->op >= 0x100 && semihosting->op <= 0x107)) { + *retval = semihosting_common(target); if (*retval != ERROR_OK) { - LOG_ERROR("Failed semihosting operation"); + LOG_ERROR("Failed semihosting operation (0x%02X)", + semihosting->op); return 0; } } else { 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 245e108acb..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 @@ -31,7 +20,7 @@ #include "register.h" #include <helper/log.h> -static uint32_t arm_shift(uint8_t shift, uint32_t Rm, +static uint32_t arm_shift(uint8_t shift, uint32_t rm, uint32_t shift_amount, uint8_t *carry) { uint32_t return_value = 0; @@ -39,22 +28,22 @@ static uint32_t arm_shift(uint8_t shift, uint32_t Rm, if (shift == 0x0) { /* LSL */ if ((shift_amount > 0) && (shift_amount <= 32)) { - return_value = Rm << shift_amount; - *carry = Rm >> (32 - shift_amount); + return_value = rm << shift_amount; + *carry = rm >> (32 - shift_amount); } else if (shift_amount > 32) { return_value = 0x0; *carry = 0x0; } else /* (shift_amount == 0) */ - return_value = Rm; + return_value = rm; } else if (shift == 0x1) { /* LSR */ if ((shift_amount > 0) && (shift_amount <= 32)) { - return_value = Rm >> shift_amount; - *carry = (Rm >> (shift_amount - 1)) & 1; + return_value = rm >> shift_amount; + *carry = (rm >> (shift_amount - 1)) & 1; } else if (shift_amount > 32) { return_value = 0x0; *carry = 0x0; } else /* (shift_amount == 0) */ - return_value = Rm; + return_value = rm; } else if (shift == 0x2) { /* ASR */ if ((shift_amount > 0) && (shift_amount <= 32)) { /* C right shifts of unsigned values are guaranteed to @@ -62,11 +51,11 @@ static uint32_t arm_shift(uint8_t shift, uint32_t Rm, * shift (shift in signed-bit) by adding the sign bit * manually */ - return_value = Rm >> shift_amount; - if (Rm & 0x80000000) + return_value = rm >> shift_amount; + if (rm & 0x80000000) return_value |= 0xffffffff << (32 - shift_amount); } else if (shift_amount > 32) { - if (Rm & 0x80000000) { + if (rm & 0x80000000) { return_value = 0xffffffff; *carry = 0x1; } else { @@ -74,20 +63,20 @@ static uint32_t arm_shift(uint8_t shift, uint32_t Rm, *carry = 0x0; } } else /* (shift_amount == 0) */ - return_value = Rm; + return_value = rm; } else if (shift == 0x3) { /* ROR */ if (shift_amount == 0) - return_value = Rm; + return_value = rm; else { shift_amount = shift_amount % 32; - return_value = (Rm >> shift_amount) | (Rm << (32 - shift_amount)); + return_value = (rm >> shift_amount) | (rm << (32 - shift_amount)); *carry = (return_value >> 31) & 0x1; } } else if (shift == 0x4) { /* RRX */ - return_value = Rm >> 1; + return_value = rm >> 1; if (*carry) - Rm |= 0x80000000; - *carry = Rm & 0x1; + rm |= 0x80000000; + *carry = rm & 0x1; } return return_value; @@ -111,25 +100,25 @@ static uint32_t arm_shifter_operand(struct arm_sim_interface *sim, if (variant == 0) /* 32-bit immediate */ return_value = shifter_operand.immediate.immediate; else if (variant == 1) {/* immediate shift */ - uint32_t Rm = sim->get_reg_mode(sim, shifter_operand.immediate_shift.Rm); + uint32_t rm = sim->get_reg_mode(sim, shifter_operand.immediate_shift.rm); /* adjust RM in case the PC is being read */ - if (shifter_operand.immediate_shift.Rm == 15) - Rm += 2 * instruction_size; + if (shifter_operand.immediate_shift.rm == 15) + rm += 2 * instruction_size; return_value = arm_shift(shifter_operand.immediate_shift.shift, - Rm, shifter_operand.immediate_shift.shift_imm, + rm, shifter_operand.immediate_shift.shift_imm, shifter_carry_out); } else if (variant == 2) { /* register shift */ - uint32_t Rm = sim->get_reg_mode(sim, shifter_operand.register_shift.Rm); - uint32_t Rs = sim->get_reg_mode(sim, shifter_operand.register_shift.Rs); + uint32_t rm = sim->get_reg_mode(sim, shifter_operand.register_shift.rm); + uint32_t rs = sim->get_reg_mode(sim, shifter_operand.register_shift.rs); /* adjust RM in case the PC is being read */ - if (shifter_operand.register_shift.Rm == 15) - Rm += 2 * instruction_size; + if (shifter_operand.register_shift.rm == 15) + rm += 2 * instruction_size; return_value = arm_shift(shifter_operand.immediate_shift.shift, - Rm, Rs, shifter_carry_out); + rm, rs, shifter_carry_out); } else { LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2"); return_value = 0xffffffff; @@ -324,8 +313,8 @@ static int arm_simulate_step_core(struct target *target, sim->set_reg(sim, 15, target_address); else if (instruction.type == ARM_BL) { uint32_t old_pc = sim->get_reg(sim, 15); - int T = (sim->get_state(sim) == ARM_STATE_THUMB); - sim->set_reg_mode(sim, 14, old_pc + 4 + T); + int t = (sim->get_state(sim) == ARM_STATE_THUMB); + sim->set_reg_mode(sim, 14, old_pc + 4 + t); sim->set_reg(sim, 15, target_address); } else if (instruction.type == ARM_BX) { if (target_address & 0x1) @@ -335,8 +324,8 @@ static int arm_simulate_step_core(struct target *target, sim->set_reg(sim, 15, target_address & 0xfffffffe); } else if (instruction.type == ARM_BLX) { uint32_t old_pc = sim->get_reg(sim, 15); - int T = (sim->get_state(sim) == ARM_STATE_THUMB); - sim->set_reg_mode(sim, 14, old_pc + 4 + T); + int t = (sim->get_state(sim) == ARM_STATE_THUMB); + sim->set_reg_mode(sim, 14, old_pc + 4 + t); if (target_address & 0x1) sim->set_state(sim, ARM_STATE_THUMB); @@ -351,16 +340,16 @@ static int arm_simulate_step_core(struct target *target, /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */ else if (((instruction.type >= ARM_AND) && (instruction.type <= ARM_RSC)) || ((instruction.type >= ARM_ORR) && (instruction.type <= ARM_MVN))) { - uint32_t Rd, Rn, shifter_operand; - uint8_t C = sim->get_cpsr(sim, 29, 1); + uint32_t rd, rn, shifter_operand; + uint8_t c = sim->get_cpsr(sim, 29, 1); uint8_t carry_out; - Rd = 0x0; + rd = 0x0; /* ARM_MOV and ARM_MVN does not use Rn */ if ((instruction.type != ARM_MOV) && (instruction.type != ARM_MVN)) - Rn = sim->get_reg_mode(sim, instruction.info.data_proc.Rn); + rn = sim->get_reg_mode(sim, instruction.info.data_proc.rn); else - Rn = 0; + rn = 0; shifter_operand = arm_shifter_operand(sim, instruction.info.data_proc.variant, @@ -368,53 +357,53 @@ static int arm_simulate_step_core(struct target *target, &carry_out); /* adjust Rn in case the PC is being read */ - if (instruction.info.data_proc.Rn == 15) - Rn += 2 * instruction_size; + if (instruction.info.data_proc.rn == 15) + rn += 2 * instruction_size; if (instruction.type == ARM_AND) - Rd = Rn & shifter_operand; + rd = rn & shifter_operand; else if (instruction.type == ARM_EOR) - Rd = Rn ^ shifter_operand; + rd = rn ^ shifter_operand; else if (instruction.type == ARM_SUB) - Rd = Rn - shifter_operand; + rd = rn - shifter_operand; else if (instruction.type == ARM_RSB) - Rd = shifter_operand - Rn; + rd = shifter_operand - rn; else if (instruction.type == ARM_ADD) - Rd = Rn + shifter_operand; + rd = rn + shifter_operand; else if (instruction.type == ARM_ADC) - Rd = Rn + shifter_operand + (C & 1); + rd = rn + shifter_operand + (c & 1); else if (instruction.type == ARM_SBC) - Rd = Rn - shifter_operand - (C & 1) ? 0 : 1; + rd = rn - shifter_operand - (c & 1) ? 0 : 1; else if (instruction.type == ARM_RSC) - Rd = shifter_operand - Rn - (C & 1) ? 0 : 1; + rd = shifter_operand - rn - (c & 1) ? 0 : 1; else if (instruction.type == ARM_ORR) - Rd = Rn | shifter_operand; + rd = rn | shifter_operand; else if (instruction.type == ARM_BIC) - Rd = Rn & ~(shifter_operand); + rd = rn & ~(shifter_operand); else if (instruction.type == ARM_MOV) - Rd = shifter_operand; + rd = shifter_operand; else if (instruction.type == ARM_MVN) - Rd = ~shifter_operand; + rd = ~shifter_operand; else LOG_WARNING("unhandled instruction type"); if (dry_run_pc) { - if (instruction.info.data_proc.Rd == 15) - *dry_run_pc = Rd & ~1; + if (instruction.info.data_proc.rd == 15) + *dry_run_pc = rd & ~1; else *dry_run_pc = current_pc + instruction_size; return ERROR_OK; } else { - if (instruction.info.data_proc.Rd == 15) { - sim->set_reg_mode(sim, 15, Rd & ~1); - if (Rd & 1) + if (instruction.info.data_proc.rd == 15) { + sim->set_reg_mode(sim, 15, rd & ~1); + if (rd & 1) sim->set_state(sim, ARM_STATE_THUMB); else sim->set_state(sim, ARM_STATE_ARM); return ERROR_OK; } - sim->set_reg_mode(sim, instruction.info.data_proc.Rd, Rd); + sim->set_reg_mode(sim, instruction.info.data_proc.rd, rd); LOG_WARNING("no updating of flags yet"); } } @@ -429,31 +418,31 @@ static int arm_simulate_step_core(struct target *target, /* load register instructions */ else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH)) { uint32_t load_address = 0, modified_address = 0, load_value = 0; - uint32_t Rn = sim->get_reg_mode(sim, instruction.info.load_store.Rn); + uint32_t rn = sim->get_reg_mode(sim, instruction.info.load_store.rn); /* adjust Rn in case the PC is being read */ - if (instruction.info.load_store.Rn == 15) - Rn += 2 * instruction_size; + if (instruction.info.load_store.rn == 15) + rn += 2 * instruction_size; if (instruction.info.load_store.offset_mode == 0) { - if (instruction.info.load_store.U) - modified_address = Rn + instruction.info.load_store.offset.offset; + if (instruction.info.load_store.u) + modified_address = rn + instruction.info.load_store.offset.offset; else - modified_address = Rn - instruction.info.load_store.offset.offset; + modified_address = rn - instruction.info.load_store.offset.offset; } else if (instruction.info.load_store.offset_mode == 1) { uint32_t offset; - uint32_t Rm = sim->get_reg_mode(sim, - instruction.info.load_store.offset.reg.Rm); + uint32_t rm = sim->get_reg_mode(sim, + instruction.info.load_store.offset.reg.rm); uint8_t shift = instruction.info.load_store.offset.reg.shift; uint8_t shift_imm = instruction.info.load_store.offset.reg.shift_imm; uint8_t carry = sim->get_cpsr(sim, 29, 1); - offset = arm_shift(shift, Rm, shift_imm, &carry); + offset = arm_shift(shift, rm, shift_imm, &carry); - if (instruction.info.load_store.U) - modified_address = Rn + offset; + if (instruction.info.load_store.u) + modified_address = rn + offset; else - modified_address = Rn - offset; + modified_address = rn - offset; } else LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)"); @@ -463,7 +452,7 @@ static int arm_simulate_step_core(struct target *target, * the base address register */ load_address = modified_address; - modified_address = Rn; + modified_address = rn; } else if (instruction.info.load_store.index_mode == 1) { /* pre-indexed mode * we load from the modified address, and write it @@ -475,17 +464,17 @@ static int arm_simulate_step_core(struct target *target, * we load from the unmodified address, and write the * modified address back */ - load_address = Rn; + load_address = rn; } - if ((!dry_run_pc) || (instruction.info.load_store.Rd == 15)) { + if ((!dry_run_pc) || (instruction.info.load_store.rd == 15)) { retval = target_read_u32(target, load_address, &load_value); if (retval != ERROR_OK) return retval; } if (dry_run_pc) { - if (instruction.info.load_store.Rd == 15) + if (instruction.info.load_store.rd == 15) *dry_run_pc = load_value & ~1; else *dry_run_pc = current_pc + instruction_size; @@ -494,10 +483,10 @@ static int arm_simulate_step_core(struct target *target, if ((instruction.info.load_store.index_mode == 1) || (instruction.info.load_store.index_mode == 2)) sim->set_reg_mode(sim, - instruction.info.load_store.Rn, + instruction.info.load_store.rn, modified_address); - if (instruction.info.load_store.Rd == 15) { + if (instruction.info.load_store.rd == 15) { sim->set_reg_mode(sim, 15, load_value & ~1); if (load_value & 1) sim->set_state(sim, ARM_STATE_THUMB); @@ -505,13 +494,13 @@ static int arm_simulate_step_core(struct target *target, sim->set_state(sim, ARM_STATE_ARM); return ERROR_OK; } - sim->set_reg_mode(sim, instruction.info.load_store.Rd, load_value); + sim->set_reg_mode(sim, instruction.info.load_store.rd, load_value); } } /* load multiple instruction */ else if (instruction.type == ARM_LDM) { int i; - uint32_t Rn = sim->get_reg_mode(sim, instruction.info.load_store_multiple.Rn); + uint32_t rn = sim->get_reg_mode(sim, instruction.info.load_store_multiple.rn); uint32_t load_values[16]; int bits_set = 0; @@ -522,24 +511,24 @@ static int arm_simulate_step_core(struct target *target, switch (instruction.info.load_store_multiple.addressing_mode) { case 0: /* Increment after */ - /* Rn = Rn; */ + /* rn = rn; */ break; case 1: /* Increment before */ - Rn = Rn + 4; + rn = rn + 4; break; case 2: /* Decrement after */ - Rn = Rn - (bits_set * 4) + 4; + rn = rn - (bits_set * 4) + 4; break; case 3: /* Decrement before */ - Rn = Rn - (bits_set * 4); + rn = rn - (bits_set * 4); break; } for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) { if ((!dry_run_pc) || (i == 15)) - target_read_u32(target, Rn, &load_values[i]); - Rn += 4; + target_read_u32(target, rn, &load_values[i]); + rn += 4; } } @@ -551,7 +540,7 @@ static int arm_simulate_step_core(struct target *target, } else { int update_cpsr = 0; - if (instruction.info.load_store_multiple.S) { + if (instruction.info.load_store_multiple.s) { if (instruction.info.load_store_multiple.register_list & 0x8000) update_cpsr = 1; } @@ -576,8 +565,8 @@ static int arm_simulate_step_core(struct target *target, } /* base register writeback */ - if (instruction.info.load_store_multiple.W) - sim->set_reg_mode(sim, instruction.info.load_store_multiple.Rn, Rn); + if (instruction.info.load_store_multiple.w) + sim->set_reg_mode(sim, instruction.info.load_store_multiple.rn, rn); if (instruction.info.load_store_multiple.register_list & 0x8000) @@ -591,8 +580,8 @@ static int arm_simulate_step_core(struct target *target, if (dry_run_pc) { /* STM wont affect PC (advance by instruction size */ } else { - uint32_t Rn = sim->get_reg_mode(sim, - instruction.info.load_store_multiple.Rn); + uint32_t rn = sim->get_reg_mode(sim, + instruction.info.load_store_multiple.rn); int bits_set = 0; for (i = 0; i < 16; i++) { @@ -602,30 +591,30 @@ static int arm_simulate_step_core(struct target *target, switch (instruction.info.load_store_multiple.addressing_mode) { case 0: /* Increment after */ - /* Rn = Rn; */ + /* rn = rn; */ break; case 1: /* Increment before */ - Rn = Rn + 4; + rn = rn + 4; break; case 2: /* Decrement after */ - Rn = Rn - (bits_set * 4) + 4; + rn = rn - (bits_set * 4) + 4; break; case 3: /* Decrement before */ - Rn = Rn - (bits_set * 4); + rn = rn - (bits_set * 4); break; } for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) { - target_write_u32(target, Rn, sim->get_reg_mode(sim, i)); - Rn += 4; + target_write_u32(target, rn, sim->get_reg_mode(sim, i)); + rn += 4; } } /* base register writeback */ - if (instruction.info.load_store_multiple.W) + if (instruction.info.load_store_multiple.w) sim->set_reg_mode(sim, - instruction.info.load_store_multiple.Rn, Rn); + instruction.info.load_store_multiple.rn, rn); } } else if (!dry_run_pc) { 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 new file mode 100644 index 0000000000..5cea682ec4 --- /dev/null +++ b/src/target/arm_tpiu_swo.c @@ -0,0 +1,1216 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/** + * @file + * This file implements support for the ARM CoreSight components Trace Port + * Interface Unit (TPIU) and Serial Wire Output (SWO). It also supports the + * CoreSight TPIU-Lite and the special TPIU version present with Cortex-M3 + * and Cortex-M4 (that includes SWO). + */ + +/* + * Relevant specifications from ARM include: + * + * CoreSight(tm) Components Technical Reference Manual ARM DDI 0314H + * CoreSight(tm) TPIU-Lite Technical Reference Manual ARM DDI 0317A + * Cortex(tm)-M3 Technical Reference Manual ARM DDI 0337G + * Cortex(tm)-M4 Technical Reference Manual ARM DDI 0439B + * CoreSight(tm) SoC-400 Technical Reference Manual ARM DDI 0480F + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <jim.h> + +#include <helper/bits.h> +#include <helper/command.h> +#include <helper/jim-nvp.h> +#include <helper/list.h> +#include <helper/log.h> +#include <helper/types.h> +#include <jtag/interface.h> +#include <server/server.h> +#include <target/arm_adi_v5.h> +#include <target/target.h> +#include <transport/transport.h> +#include "arm_tpiu_swo.h" + +/* START_DEPRECATED_TPIU */ +#include <target/cortex_m.h> +#include <target/target_type.h> +#define MSG "DEPRECATED \'tpiu config\' command: " +/* END_DEPRECATED_TPIU */ + +#define TCP_SERVICE_NAME "tpiu_swo_trace" + +/* default for Cortex-M3 and Cortex-M4 specific TPIU */ +#define TPIU_SWO_DEFAULT_BASE 0xE0040000 + +#define TPIU_SSPSR_OFFSET 0x000 +#define TPIU_CSPSR_OFFSET 0x004 +#define TPIU_ACPR_OFFSET 0x010 +#define TPIU_SPPR_OFFSET 0x0F0 +#define TPIU_FFSR_OFFSET 0x300 +#define TPIU_FFCR_OFFSET 0x304 +#define TPIU_FSCR_OFFSET 0x308 +#define TPIU_DEVID_OFFSET 0xfc8 + +#define TPIU_ACPR_MAX_PRESCALER 0x1fff +#define TPIU_SPPR_PROTOCOL_SYNC (TPIU_PIN_PROTOCOL_SYNC) +#define TPIU_SPPR_PROTOCOL_MANCHESTER (TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER) +#define TPIU_SPPR_PROTOCOL_UART (TPIU_PIN_PROTOCOL_ASYNC_UART) +#define TPIU_DEVID_NOSUPPORT_SYNC BIT(9) +#define TPIU_DEVID_SUPPORT_MANCHESTER BIT(10) +#define TPIU_DEVID_SUPPORT_UART BIT(11) + +enum arm_tpiu_swo_event { + TPIU_SWO_EVENT_PRE_ENABLE, + TPIU_SWO_EVENT_POST_ENABLE, + TPIU_SWO_EVENT_PRE_DISABLE, + TPIU_SWO_EVENT_POST_DISABLE, +}; + +static const struct jim_nvp nvp_arm_tpiu_swo_event[] = { + { .value = TPIU_SWO_EVENT_PRE_ENABLE, .name = "pre-enable" }, + { .value = TPIU_SWO_EVENT_POST_ENABLE, .name = "post-enable" }, + { .value = TPIU_SWO_EVENT_PRE_DISABLE, .name = "pre-disable" }, + { .value = TPIU_SWO_EVENT_POST_DISABLE, .name = "post-disable" }, +}; + +struct arm_tpiu_swo_event_action { + enum arm_tpiu_swo_event event; + Jim_Interp *interp; + Jim_Obj *body; + struct arm_tpiu_swo_event_action *next; +}; + +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 */ + bool deferred_enable; + bool enabled; + bool en_capture; + /** Handle to output trace data in INTERNAL capture mode */ + /** Synchronous output port width */ + uint32_t port_width; + FILE *file; + /** output mode */ + unsigned int pin_protocol; + /** Enable formatter */ + bool en_formatter; + /** frequency of TRACECLKIN (usually matches HCLK) */ + unsigned int traceclkin_freq; + /** SWO pin frequency */ + unsigned int swo_pin_freq; + /** where to dump the captured output trace data */ + char *out_filename; + /** track TCP connections */ + struct list_head connections; + /* START_DEPRECATED_TPIU */ + bool recheck_ap_cur_target; + /* END_DEPRECATED_TPIU */ +}; + +struct arm_tpiu_swo_connection { + struct list_head lh; + struct connection *connection; +}; + +struct arm_tpiu_swo_priv_connection { + struct arm_tpiu_swo_object *obj; +}; + +static LIST_HEAD(all_tpiu_swo); + +#define ARM_TPIU_SWO_TRACE_BUF_SIZE 4096 + +static int arm_tpiu_swo_poll_trace(void *priv) +{ + struct arm_tpiu_swo_object *obj = priv; + uint8_t buf[ARM_TPIU_SWO_TRACE_BUF_SIZE]; + size_t size = sizeof(buf); + struct arm_tpiu_swo_connection *c; + + int retval = adapter_poll_trace(buf, &size); + if (retval != ERROR_OK || !size) + return retval; + + target_call_trace_callbacks(/*target*/NULL, size, buf); + + if (obj->file) { + if (fwrite(buf, 1, size, obj->file) == size) { + fflush(obj->file); + } else { + LOG_ERROR("Error writing to the SWO trace destination file"); + return ERROR_FAIL; + } + } + + if (obj->out_filename && obj->out_filename[0] == ':') + list_for_each_entry(c, &obj->connections, lh) + if (connection_write(c->connection, buf, size) != (int)size) + LOG_ERROR("Error writing to connection"); /* FIXME: which connection? */ + + return ERROR_OK; +} + +static void arm_tpiu_swo_handle_event(struct arm_tpiu_swo_object *obj, enum arm_tpiu_swo_event event) +{ + for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) { + if (ea->event != event) + continue; + + LOG_DEBUG("TPIU/SWO: %s event: %s (%d) action : %s", + obj->name, + jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name, + event, + Jim_GetString(ea->body, NULL)); + + /* prevent event execution to change current target */ + struct command_context *cmd_ctx = current_command_context(ea->interp); + struct target *saved_target = cmd_ctx->current_target; + int retval = Jim_EvalObj(ea->interp, ea->body); + cmd_ctx->current_target = saved_target; + + if (retval == JIM_RETURN) + retval = ea->interp->returnCode; + if (retval == JIM_OK || retval == ERROR_COMMAND_CLOSE_CONNECTION) + return; + + Jim_MakeErrorMessage(ea->interp); + LOG_USER("Error executing event %s on TPIU/SWO %s:\n%s", + jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name, + obj->name, + Jim_GetString(Jim_GetResult(ea->interp), NULL)); + /* clean both error code and stacktrace before return */ + Jim_Eval(ea->interp, "error \"\" \"\""); + return; + } +} + +static void arm_tpiu_swo_close_output(struct arm_tpiu_swo_object *obj) +{ + if (obj->file) { + fclose(obj->file); + obj->file = NULL; + } + if (obj->out_filename && obj->out_filename[0] == ':') + remove_service(TCP_SERVICE_NAME, &obj->out_filename[1]); +} + +int arm_tpiu_swo_cleanup_all(void) +{ + struct arm_tpiu_swo_object *obj, *tmp; + + list_for_each_entry_safe(obj, tmp, &all_tpiu_swo, lh) { + if (obj->enabled) + arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE); + + arm_tpiu_swo_close_output(obj); + + if (obj->en_capture) { + target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj); + + int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL); + if (retval != ERROR_OK) + LOG_ERROR("Failed to stop adapter's trace"); + } + + if (obj->enabled) + arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE); + + struct arm_tpiu_swo_event_action *ea = obj->event_action; + while (ea) { + struct arm_tpiu_swo_event_action *next = ea->next; + Jim_DecrRefCount(ea->interp, ea->body); + free(ea); + ea = next; + } + + if (obj->ap) + dap_put_ap(obj->ap); + + free(obj->name); + free(obj->out_filename); + free(obj); + } + + return ERROR_OK; +} + +static int arm_tpiu_swo_service_new_connection(struct connection *connection) +{ + struct arm_tpiu_swo_priv_connection *priv = connection->service->priv; + struct arm_tpiu_swo_object *obj = priv->obj; + struct arm_tpiu_swo_connection *c = malloc(sizeof(*c)); + if (!c) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + c->connection = connection; + list_add(&c->lh, &obj->connections); + return ERROR_OK; +} + +static int arm_tpiu_swo_service_input(struct connection *connection) +{ + /* read a dummy buffer to check if the connection is still active */ + long dummy; + int bytes_read = connection_read(connection, &dummy, sizeof(dummy)); + + if (bytes_read == 0) { + return ERROR_SERVER_REMOTE_CLOSED; + } else if (bytes_read == -1) { + LOG_ERROR("error during read: %s", strerror(errno)); + return ERROR_SERVER_REMOTE_CLOSED; + } + + return ERROR_OK; +} + +static int arm_tpiu_swo_service_connection_closed(struct connection *connection) +{ + struct arm_tpiu_swo_priv_connection *priv = connection->service->priv; + struct arm_tpiu_swo_object *obj = priv->obj; + struct arm_tpiu_swo_connection *c, *tmp; + + list_for_each_entry_safe(c, tmp, &obj->connections, lh) + if (c->connection == connection) { + list_del(&c->lh); + free(c); + return ERROR_OK; + } + LOG_ERROR("Failed to find connection to close!"); + return ERROR_FAIL; +} + +COMMAND_HANDLER(handle_arm_tpiu_swo_event_list) +{ + struct arm_tpiu_swo_object *obj = CMD_DATA; + + command_print(CMD, "Event actions for TPIU/SWO %s\n", obj->name); + command_print(CMD, "%-25s | Body", "Event"); + command_print(CMD, "------------------------- | " + "----------------------------------------"); + + for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) { + struct jim_nvp *opt = jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event, ea->event); + command_print(CMD, "%-25s | %s", + opt->name, Jim_GetString(ea->body, NULL)); + } + command_print(CMD, "***END***"); + return ERROR_OK; +} + +enum arm_tpiu_swo_cfg_param { + CFG_PORT_WIDTH, + CFG_PROTOCOL, + CFG_FORMATTER, + CFG_TRACECLKIN, + CFG_BITRATE, + CFG_OUTFILE, + CFG_EVENT, +}; + +static const struct jim_nvp nvp_arm_tpiu_swo_config_opts[] = { + { .name = "-port-width", .value = CFG_PORT_WIDTH }, + { .name = "-protocol", .value = CFG_PROTOCOL }, + { .name = "-formatter", .value = CFG_FORMATTER }, + { .name = "-traceclk", .value = CFG_TRACECLKIN }, + { .name = "-pin-freq", .value = CFG_BITRATE }, + { .name = "-output", .value = CFG_OUTFILE }, + { .name = "-event", .value = CFG_EVENT }, + /* handled by mem_ap_spot, added for jim_getopt_nvp_unknown() */ + { .name = "-dap", .value = -1 }, + { .name = "-ap-num", .value = -1 }, + { .name = "-baseaddr", .value = -1 }, + { .name = NULL, .value = -1 }, +}; + +static const struct jim_nvp nvp_arm_tpiu_swo_protocol_opts[] = { + { .name = "sync", .value = TPIU_SPPR_PROTOCOL_SYNC }, + { .name = "uart", .value = TPIU_SPPR_PROTOCOL_UART }, + { .name = "manchester", .value = TPIU_SPPR_PROTOCOL_MANCHESTER }, + { .name = NULL, .value = -1 }, +}; + +static const struct jim_nvp nvp_arm_tpiu_swo_bool_opts[] = { + { .name = "on", .value = 1 }, + { .name = "yes", .value = 1 }, + { .name = "1", .value = 1 }, + { .name = "true", .value = 1 }, + { .name = "off", .value = 0 }, + { .name = "no", .value = 0 }, + { .name = "0", .value = 0 }, + { .name = "false", .value = 0 }, + { .name = NULL, .value = -1 }, +}; + +static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_swo_object *obj) +{ + assert(obj); + + if (goi->isconfigure && obj->enabled) { + Jim_SetResultFormatted(goi->interp, "Cannot configure TPIU/SWO; %s is enabled!", obj->name); + return JIM_ERR; + } + + /* parse config or cget options ... */ + while (goi->argc > 0) { + Jim_SetEmptyResult(goi->interp); + + int e = adiv5_jim_mem_ap_spot_configure(&obj->spot, goi); + if (e == JIM_OK) + continue; + if (e == JIM_ERR) + return e; + + struct jim_nvp *n; + e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_config_opts, &n); + if (e != JIM_OK) { + jim_getopt_nvp_unknown(goi, nvp_arm_tpiu_swo_config_opts, 0); + return e; + } + + switch (n->value) { + case CFG_PORT_WIDTH: + if (goi->isconfigure) { + jim_wide port_width; + e = jim_getopt_wide(goi, &port_width); + if (e != JIM_OK) + return e; + if (port_width < 1 || port_width > 32) { + Jim_SetResultString(goi->interp, "Invalid port width!", -1); + return JIM_ERR; + } + obj->port_width = (uint32_t)port_width; + } else { + if (goi->argc) + goto err_no_params; + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->port_width)); + } + break; + case CFG_PROTOCOL: + if (goi->isconfigure) { + struct jim_nvp *p; + e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_protocol_opts, &p); + if (e != JIM_OK) + return e; + obj->pin_protocol = p->value; + } else { + if (goi->argc) + goto err_no_params; + struct jim_nvp *p; + e = jim_nvp_value2name(goi->interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p); + if (e != JIM_OK) { + Jim_SetResultString(goi->interp, "protocol error", -1); + return JIM_ERR; + } + Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1)); + } + break; + case CFG_FORMATTER: + if (goi->isconfigure) { + struct jim_nvp *p; + e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_bool_opts, &p); + if (e != JIM_OK) + return e; + obj->en_formatter = p->value; + } else { + if (goi->argc) + goto err_no_params; + struct jim_nvp *p; + e = jim_nvp_value2name(goi->interp, nvp_arm_tpiu_swo_bool_opts, obj->en_formatter, &p); + if (e != JIM_OK) { + Jim_SetResultString(goi->interp, "formatter error", -1); + return JIM_ERR; + } + Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1)); + } + break; + case CFG_TRACECLKIN: + if (goi->isconfigure) { + jim_wide clk; + e = jim_getopt_wide(goi, &clk); + if (e != JIM_OK) + return e; + obj->traceclkin_freq = clk; + } else { + if (goi->argc) + goto err_no_params; + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->traceclkin_freq)); + } + break; + case CFG_BITRATE: + if (goi->isconfigure) { + jim_wide clk; + e = jim_getopt_wide(goi, &clk); + if (e != JIM_OK) + return e; + obj->swo_pin_freq = clk; + } else { + if (goi->argc) + goto err_no_params; + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->swo_pin_freq)); + } + break; + case CFG_OUTFILE: + if (goi->isconfigure) { + const char *s; + e = jim_getopt_string(goi, &s, NULL); + if (e != JIM_OK) + return e; + if (s[0] == ':') { + char *end; + long port = strtol(s + 1, &end, 0); + if (port <= 0 || port > UINT16_MAX || *end != '\0') { + Jim_SetResultFormatted(goi->interp, "Invalid TCP port \'%s\'", s + 1); + return JIM_ERR; + } + } + free(obj->out_filename); + obj->out_filename = strdup(s); + if (!obj->out_filename) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + } else { + if (goi->argc) + goto err_no_params; + if (obj->out_filename) + Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, obj->out_filename, -1)); + } + break; + case CFG_EVENT: + if (goi->isconfigure) { + if (goi->argc < 2) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?"); + return JIM_ERR; + } + } else { + if (goi->argc != 1) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?"); + return JIM_ERR; + } + } + + { + struct jim_nvp *p; + Jim_Obj *o; + struct arm_tpiu_swo_event_action *ea = obj->event_action; + + e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_event, &p); + if (e != JIM_OK) { + jim_getopt_nvp_unknown(goi, nvp_arm_tpiu_swo_event, 1); + return e; + } + + while (ea) { + /* replace existing? */ + if (ea->event == (enum arm_tpiu_swo_event)p->value) + break; + ea = ea->next; + } + + if (goi->isconfigure) { + if (!ea) { + ea = calloc(1, sizeof(*ea)); + if (!ea) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + ea->next = obj->event_action; + obj->event_action = ea; + } + if (ea->body) + Jim_DecrRefCount(ea->interp, ea->body); + ea->event = p->value; + ea->interp = goi->interp; + jim_getopt_obj(goi, &o); + ea->body = Jim_DuplicateObj(goi->interp, o); + Jim_IncrRefCount(ea->body); + } else { + if (ea) + Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, ea->body)); + } + } + break; + } + } + + return JIM_OK; + +err_no_params: + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); + return JIM_ERR; +} + +static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +{ + struct command *c = jim_to_command(interp); + struct jim_getopt_info goi; + + jim_getopt_setup(&goi, interp, argc - 1, argv + 1); + goi.isconfigure = !strcmp(c->name, "configure"); + if (goi.argc < 1) { + Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, + "missing: -option ..."); + return JIM_ERR; + } + struct arm_tpiu_swo_object *obj = c->jim_handler_data; + return arm_tpiu_swo_configure(&goi, obj); +} + +static int wrap_write_u32(struct target *target, struct adiv5_ap *tpiu_ap, + target_addr_t address, uint32_t value) +{ + if (transport_is_hla()) + return target_write_u32(target, address, value); + else + return mem_ap_write_atomic_u32(tpiu_ap, address, value); +} + +static int wrap_read_u32(struct target *target, struct adiv5_ap *tpiu_ap, + target_addr_t address, uint32_t *value) +{ + if (transport_is_hla()) + return target_read_u32(target, address, value); + else + return mem_ap_read_atomic_u32(tpiu_ap, address, value); +} + +static const struct service_driver arm_tpiu_swo_service_driver = { + .name = "tpiu_swo_trace", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = arm_tpiu_swo_service_new_connection, + .input_handler = arm_tpiu_swo_service_input, + .connection_closed_handler = arm_tpiu_swo_service_connection_closed, + .keep_client_alive_handler = NULL, +}; + +COMMAND_HANDLER(handle_arm_tpiu_swo_enable) +{ + struct arm_tpiu_swo_object *obj = CMD_DATA; + uint32_t value; + int retval; + + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (CMD_CTX->mode == COMMAND_CONFIG) { + LOG_DEBUG("%s: enable deferred", obj->name); + obj->deferred_enable = true; + return ERROR_OK; + } + + if (obj->enabled) + return ERROR_OK; + + 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) { + 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); + + /* 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 ERROR_FAIL; + } + if (!target_was_examined(target)) { + LOG_ERROR(MSG "Current target not examined yet"); + 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; + 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#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, obj->ap, obj->spot.base + TPIU_DEVID_OFFSET, &value); + if (retval != ERROR_OK) { + command_print(CMD, "Unable to read %s", obj->name); + return retval; + } + switch (obj->pin_protocol) { + case TPIU_SPPR_PROTOCOL_SYNC: + value = !(value & TPIU_DEVID_NOSUPPORT_SYNC); + break; + case TPIU_SPPR_PROTOCOL_UART: + value &= TPIU_DEVID_SUPPORT_UART; + break; + case TPIU_SPPR_PROTOCOL_MANCHESTER: + value &= TPIU_DEVID_SUPPORT_MANCHESTER; + break; + default: + value = 0; + } + if (!value) { + 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, obj->ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value); + if (retval != ERROR_OK) { + command_print(CMD, "Cannot read TPIU register SSPSR"); + return retval; + } + if (!(value & BIT(obj->port_width - 1))) { + command_print(CMD, "TPIU does not support port-width of %d bits", obj->port_width); + return ERROR_FAIL; + } + } + + uint16_t prescaler = 1; /* dummy value */ + unsigned int swo_pin_freq = obj->swo_pin_freq; /* could be replaced */ + + if (obj->out_filename && strcmp(obj->out_filename, "external") && obj->out_filename[0]) { + if (obj->out_filename[0] == ':') { + struct arm_tpiu_swo_priv_connection *priv = malloc(sizeof(*priv)); + if (!priv) { + LOG_ERROR("Out of memory"); + 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) { + 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) { + 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) { + command_print(CMD, "Failed to start adapter's trace"); + arm_tpiu_swo_close_output(obj); + 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) + command_print(CMD, "Adapter rejected SWO pin frequency %d Hz", obj->swo_pin_freq); + else + command_print(CMD, + "Adapter does not support auto-detection of SWO pin frequency nor a default value"); + + arm_tpiu_swo_close_output(obj); + return ERROR_FAIL; + } + + if (obj->swo_pin_freq != swo_pin_freq) + LOG_INFO("SWO pin data rate adjusted by adapter to %d Hz", swo_pin_freq); + obj->swo_pin_freq = swo_pin_freq; + + target_register_timer_callback(arm_tpiu_swo_poll_trace, 1, + TARGET_TIMER_TYPE_PERIODIC, obj); + + obj->en_capture = true; + } else if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) { + prescaler = (obj->traceclkin_freq + obj->swo_pin_freq / 2) / obj->swo_pin_freq; + if (prescaler > TPIU_ACPR_MAX_PRESCALER) + prescaler = TPIU_ACPR_MAX_PRESCALER; + swo_pin_freq = obj->traceclkin_freq / prescaler; + + if (obj->swo_pin_freq != swo_pin_freq) + LOG_INFO("SWO pin data rate adjusted to %d Hz", swo_pin_freq); + obj->swo_pin_freq = swo_pin_freq; + } + + 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, obj->ap, obj->spot.base + TPIU_ACPR_OFFSET, prescaler - 1); + if (retval != ERROR_OK) + goto error_exit; + + 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, 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, obj->ap, obj->spot.base + TPIU_FFCR_OFFSET, value); + if (retval != ERROR_OK) + goto error_exit; + + arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_ENABLE); + + /* START_DEPRECATED_TPIU */ + target_handle_event(target, TARGET_EVENT_TRACE_CONFIG); + /* END_DEPRECATED_TPIU */ + + obj->enabled = true; + return ERROR_OK; + +error_exit: + command_print(CMD, "Error!"); + + if (obj->en_capture) { + obj->en_capture = false; + + arm_tpiu_swo_close_output(obj); + + target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj); + + 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 retval; +} + +COMMAND_HANDLER(handle_arm_tpiu_swo_disable) +{ + struct arm_tpiu_swo_object *obj = CMD_DATA; + + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!obj->enabled) + return ERROR_OK; + obj->enabled = false; + + arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE); + + if (obj->en_capture) { + obj->en_capture = false; + + arm_tpiu_swo_close_output(obj); + + target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj); + + int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL); + if (retval != ERROR_OK) { + 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 target *target = get_current_target(CMD_CTX); + target_handle_event(target, TARGET_EVENT_TRACE_CONFIG); + /* END_DEPRECATED_TPIU */ + + return ERROR_OK; +} + +static const struct command_registration arm_tpiu_swo_instance_command_handlers[] = { + { + .name = "configure", + .mode = COMMAND_ANY, + .jim_handler = jim_arm_tpiu_swo_configure, + .help = "configure a new TPIU/SWO for use", + .usage = "[attribute value ...]", + }, + { + .name = "cget", + .mode = COMMAND_ANY, + .jim_handler = jim_arm_tpiu_swo_configure, + .help = "returns the specified TPIU/SWO attribute", + .usage = "attribute", + }, + { + .name = "eventlist", + .mode = COMMAND_ANY, + .handler = handle_arm_tpiu_swo_event_list, + .help = "displays a table of events defined for this TPIU/SWO", + .usage = "", + }, + { + .name = "enable", + .mode = COMMAND_ANY, + .handler = handle_arm_tpiu_swo_enable, + .usage = "", + .help = "Enables the TPIU/SWO output", + }, + { + .name = "disable", + .mode = COMMAND_EXEC, + .handler = handle_arm_tpiu_swo_disable, + .usage = "", + .help = "Disables the TPIU/SWO output", + }, + COMMAND_REGISTRATION_DONE +}; + +static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *obj) +{ + struct command_context *cmd_ctx; + Jim_Cmd *cmd; + int e; + + cmd_ctx = current_command_context(interp); + assert(cmd_ctx); + + /* does this command exist? */ + cmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, obj->name, -1), JIM_NONE); + if (cmd) { + Jim_SetResultFormatted(interp, "cannot create TPIU object because a command with name '%s' already exists", + obj->name); + return JIM_ERR; + } + + /* now - create the new tpiu/swo name command */ + const struct command_registration obj_commands[] = { + { + .name = obj->name, + .mode = COMMAND_ANY, + .help = "tpiu/swo instance command group", + .usage = "", + .chain = arm_tpiu_swo_instance_command_handlers, + }, + COMMAND_REGISTRATION_DONE + }; + e = register_commands_with_data(cmd_ctx, NULL, obj_commands, obj); + if (e != ERROR_OK) + return JIM_ERR; + + list_add_tail(&obj->lh, &all_tpiu_swo); + + return JIM_OK; +} + +static int jim_arm_tpiu_swo_create(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 < 1) { + Jim_WrongNumArgs(interp, 1, argv, "name ?option option ...?"); + return JIM_ERR; + } + + struct arm_tpiu_swo_object *obj = calloc(1, sizeof(struct arm_tpiu_swo_object)); + if (!obj) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + INIT_LIST_HEAD(&obj->connections); + adiv5_mem_ap_spot_init(&obj->spot); + obj->spot.base = TPIU_SWO_DEFAULT_BASE; + obj->port_width = 1; + + Jim_Obj *n; + jim_getopt_obj(&goi, &n); + obj->name = strdup(Jim_GetString(n, NULL)); + if (!obj->name) { + LOG_ERROR("Out of memory"); + free(obj); + return JIM_ERR; + } + + /* Do the rest as "configure" options */ + goi.isconfigure = 1; + int e = arm_tpiu_swo_configure(&goi, obj); + if (e != JIM_OK) + goto err_exit; + + if (!obj->spot.dap || obj->spot.ap_num == DP_APSEL_INVALID) { + Jim_SetResultString(goi.interp, "-dap and -ap-num required when creating TPIU", -1); + goto err_exit; + } + + e = arm_tpiu_swo_create(goi.interp, obj); + if (e != JIM_OK) + goto err_exit; + + return JIM_OK; + +err_exit: + free(obj->name); + free(obj->out_filename); + free(obj); + return JIM_ERR; +} + +COMMAND_HANDLER(handle_arm_tpiu_swo_names) +{ + struct arm_tpiu_swo_object *obj; + + 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; +} + +COMMAND_HANDLER(handle_arm_tpiu_swo_init) +{ + struct arm_tpiu_swo_object *obj; + int retval = ERROR_OK; + + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + 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); + if (retval2 != ERROR_OK) + retval = retval2; + } + return retval; +} + +/* START_DEPRECATED_TPIU */ +/* DEPRECATED: emulation of old command 'tpiu config' */ +COMMAND_HANDLER(handle_tpiu_deprecated_config_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm_tpiu_swo_object *obj = NULL; + int retval; + + 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 ERROR_FAIL; + } + + if (!list_empty(&all_tpiu_swo)) { + obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh); + LOG_INFO(MSG "Using %s", obj->name); + } else { + struct cortex_m_common *cm = target_to_cm(target); + struct adiv5_private_config *pc = target->private_config; + struct adiv5_dap *dap = pc->dap; + 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)); + + if (ap_num == DP_APSEL_INVALID && transport_is_hla()) + ap_num = 0; /* HLA should only support AP 0 */ + + if (ap_num == DP_APSEL_INVALID && target_was_examined(target)) + ap_num = cm->armv7m.debug_ap->ap_num; + + if (ap_num == DP_APSEL_INVALID) { + LOG_INFO(MSG "Target %s uses AP autodetection. Adding TPIU on AP 0; can be revised later", + target_name(target)); + ap_num = 0; + set_recheck_ap_cur_target = true; + } + + 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 0x%" PRIx64, + target_name(target), adiv5_dap_name(dap), ap_num); + if (retval != ERROR_OK) + return retval; + + obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh); + if (set_recheck_ap_cur_target) + obj->recheck_ap_cur_target = true; + } + + unsigned int cmd_idx = 0; + if (cmd_idx == CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!strcmp(CMD_ARGV[cmd_idx], "disable")) { + if (CMD_ARGC != cmd_idx + 1) + return ERROR_COMMAND_SYNTAX_ERROR; + LOG_INFO(MSG "Running: \'%s disable\'", obj->name); + return command_run_linef(CMD_CTX, "%s disable", obj->name); + } + + const char *output = NULL; + const char *protocol; + const char *formatter = NULL; + const char *port_width = NULL; + const char *trace_clk; + const char *pin_clk = NULL; + if (!strcmp(CMD_ARGV[cmd_idx], "internal")) { + cmd_idx++; + if (cmd_idx == CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + output = CMD_ARGV[cmd_idx]; + } else if (strcmp(CMD_ARGV[cmd_idx], "external")) + return ERROR_COMMAND_SYNTAX_ERROR; + cmd_idx++; + if (cmd_idx == CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + if (!strcmp(CMD_ARGV[cmd_idx], "sync")) { + protocol = CMD_ARGV[cmd_idx]; + cmd_idx++; + if (cmd_idx == CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + port_width = CMD_ARGV[cmd_idx]; + } else { + if (strcmp(CMD_ARGV[cmd_idx], "manchester") && strcmp(CMD_ARGV[cmd_idx], "uart")) + return ERROR_COMMAND_SYNTAX_ERROR; + protocol = CMD_ARGV[cmd_idx]; + cmd_idx++; + if (cmd_idx == CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + formatter = CMD_ARGV[cmd_idx]; + } + cmd_idx++; + if (cmd_idx == CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + trace_clk = CMD_ARGV[cmd_idx]; + cmd_idx++; + if (cmd_idx != CMD_ARGC) { + pin_clk = CMD_ARGV[cmd_idx]; + cmd_idx++; + } + if (cmd_idx != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + LOG_INFO(MSG "Running: \'%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s\'", + obj->name, protocol, trace_clk, + pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "", + output ? " -output " : "", output ? output : "", + formatter ? " -formatter " : "", formatter ? formatter : "", + port_width ? " -port-width " : "", port_width ? port_width : ""); + + retval = command_run_linef(CMD_CTX, + "%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s", + obj->name, protocol, trace_clk, + pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "", + output ? " -output " : "", output ? output : "", + formatter ? " -formatter " : "", formatter ? formatter : "", + port_width ? " -port-width " : "", port_width ? port_width : ""); + if (retval != ERROR_OK) + return retval; + + LOG_INFO(MSG "Running: \'%s enable\'", obj->name); + retval = command_run_linef(CMD_CTX, "%s enable", obj->name); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static const struct command_registration arm_tpiu_deprecated_subcommand_handlers[] = { + { + .name = "config", + .handler = handle_tpiu_deprecated_config_command, + .mode = COMMAND_ANY, + .help = "Configure TPIU features, DEPRECATED, use \'tpiu create\'", + .usage = "(disable | " + "((external | internal (<filename> | <:port> | -)) " + "(sync <port width> | ((manchester | uart) <formatter enable>)) " + "<TRACECLKIN freq> [<trace freq>]))", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration arm_tpiu_deprecated_command_handlers[] = { + { + .name = "tpiu", + .chain = arm_tpiu_deprecated_subcommand_handlers, + .usage = "", + .help = "tpiu command group", + }, + COMMAND_REGISTRATION_DONE +}; +/* END_DEPRECATED_TPIU */ + +static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = { + { + .name = "create", + .mode = COMMAND_ANY, + .jim_handler = jim_arm_tpiu_swo_create, + .usage = "name [-dap dap] [-ap-num num] [-baseaddr baseaddr]", + .help = "Creates a new TPIU or SWO object", + }, + { + .name = "names", + .mode = COMMAND_ANY, + .handler = handle_arm_tpiu_swo_names, + .usage = "", + .help = "Lists all registered TPIU and SWO objects by name", + }, + { + .name = "init", + .mode = COMMAND_EXEC, + .handler = handle_arm_tpiu_swo_init, + .usage = "", + .help = "Initialize TPIU and SWO", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration arm_tpiu_swo_command_handlers[] = { + { + .name = "tpiu", + .chain = arm_tpiu_swo_subcommand_handlers, + .usage = "", + .help = "tpiu command group", + }, + { + .name = "swo", + .chain = arm_tpiu_swo_subcommand_handlers, + .usage = "", + .help = "swo command group", + }, + COMMAND_REGISTRATION_DONE +}; + +int arm_tpiu_swo_register_commands(struct command_context *cmd_ctx) +{ + return register_commands(cmd_ctx, NULL, arm_tpiu_swo_command_handlers); +} diff --git a/src/target/arm_tpiu_swo.h b/src/target/arm_tpiu_swo.h new file mode 100644 index 0000000000..5904ce2910 --- /dev/null +++ b/src/target/arm_tpiu_swo.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_TARGET_ARM_TPIU_SWO_H +#define OPENOCD_TARGET_ARM_TPIU_SWO_H + +/* Values should match TPIU_SPPR_PROTOCOL_xxx */ +enum tpiu_pin_protocol { + TPIU_PIN_PROTOCOL_SYNC = 0, /**< synchronous trace output */ + TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER = 1, /**< asynchronous output with Manchester coding */ + TPIU_PIN_PROTOCOL_ASYNC_UART = 2, /**< asynchronous output with NRZ coding */ +}; + +/* START_DEPRECATED_TPIU */ +/* DEPRECATED: emulation of old command 'tpiu config' */ +extern const struct command_registration arm_tpiu_deprecated_command_handlers[]; +/* END_DEPRECATED_TPIU */ + +int arm_tpiu_swo_register_commands(struct command_context *cmd_ctx); +int arm_tpiu_swo_cleanup_all(void); + +#endif /* OPENOCD_TARGET_ARM_TPIU_SWO_H */ diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 58bc3390a9..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; } @@ -856,6 +845,9 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) char *sep = "\n"; char *shadow = ""; + if (!arm_mode_data[mode].n_indices) + continue; + /* label this bank of registers (or shadows) */ switch (arm_mode_data[mode].psr) { case ARM_MODE_SYS: @@ -869,6 +861,7 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) continue; /* FALLTHROUGH */ case ARM_MODE_MON: + case ARM_MODE_1176_MON: if (arm->core_type != ARM_CORE_TYPE_SEC_EXT && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; @@ -912,48 +905,49 @@ 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) { - int retval = ERROR_OK; +#if HAVE_CAPSTONE struct target *target = get_current_target(CMD_CTX); - if (target == NULL) { + if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct arm *arm = target_to_arm(target); target_addr_t address; - int count = 1; - int thumb = 0; + unsigned int count = 1; + bool thumb = false; if (!is_arm(arm)) { command_print(CMD, "current target isn't an ARM"); @@ -962,193 +956,230 @@ COMMAND_HANDLER(handle_arm_disassemble_command) if (arm->core_type == ARM_CORE_TYPE_M_PROFILE) { /* armv7m is always thumb mode */ - thumb = 1; + thumb = true; } switch (CMD_ARGC) { case 3: if (strcmp(CMD_ARGV[2], "thumb") != 0) - goto usage; - thumb = 1; + return ERROR_COMMAND_SYNTAX_ERROR; + thumb = true; /* FALL THROUGH */ case 2: - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], count); + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count); /* FALL THROUGH */ case 1: COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); if (address & 0x01) { if (!thumb) { command_print(CMD, "Disassemble as Thumb"); - thumb = 1; + thumb = true; } address &= ~1; } break; default: -usage: - count = 0; - retval = ERROR_COMMAND_SYNTAX_ERROR; - } - - while (count-- > 0) { - struct arm_instruction cur_instruction; - - if (thumb) { - /* Always use Thumb2 disassembly for best handling - * of 32-bit BL/BLX, and to work with newer cores - * (some ARMv6, all ARMv7) that use Thumb2. - */ - retval = thumb2_opcode(target, address, - &cur_instruction); - if (retval != ERROR_OK) - break; - } else { - uint32_t opcode; - - retval = target_read_u32(target, address, &opcode); - if (retval != ERROR_OK) - break; - retval = arm_evaluate_opcode(opcode, address, - &cur_instruction) != ERROR_OK; - if (retval != ERROR_OK) - break; - } - command_print(CMD, "%s", cur_instruction.text); - address += cur_instruction.instruction_size; + return ERROR_COMMAND_SYNTAX_ERROR; } - return retval; + return arm_disassemble(CMD, target, address, count, thumb); +#else + command_print(CMD, "capstone disassembly framework required"); + return ERROR_FAIL; +#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; - context = current_command_context(interp); - assert(context != NULL); + if (!strcmp(CMD_NAME, "mcr")) { + is_mcr = true; + arg_cnt = 6; + } + + if (arg_cnt != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; - target = get_current_target(context); - if (target == NULL) { - LOG_ERROR("%s: no current target", __func__); - return JIM_ERR; + struct target *target = get_current_target(CMD_CTX); + if (!target) { + 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; uint32_t op1; uint32_t op2; - uint32_t CRn; - uint32_t CRm; + 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); + /* ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2) */ + 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); + /* ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2) */ + 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[] = { { @@ -1158,39 +1189,61 @@ static const struct command_registration arm_exec_command_handlers[] = { .help = "display ARM core registers", .usage = "", }, - { - .name = "core_state", - .handler = handle_armv4_5_core_state_command, - .mode = COMMAND_EXEC, - .usage = "['arm'|'thumb']", - .help = "display/change ARM core state", - }, - { - .name = "disassemble", - .handler = handle_arm_disassemble_command, - .mode = COMMAND_EXEC, - .usage = "address [count ['thumb']]", - .help = "disassemble instructions ", - }, { .name = "mcr", .mode = COMMAND_EXEC, - .jim_handler = &jim_mcrmrc, + .handler = handle_armv4_5_mcrmrc, .help = "write coprocessor register", .usage = "cpnum op1 CRn CRm op2 value", }, { .name = "mrc", .mode = COMMAND_EXEC, - .jim_handler = &jim_mcrmrc, + .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_arm_core_state_command, + .mode = COMMAND_EXEC, + .usage = "['arm'|'thumb']", + .help = "display/change ARM core state", + }, + { + .name = "disassemble", + .handler = handle_arm_disassemble_command, + .mode = COMMAND_EXEC, + .usage = "address [count ['thumb']]", + .help = "disassemble instructions", + }, { .chain = semihosting_common_handlers, }, COMMAND_REGISTRATION_DONE }; + const struct command_registration arm_command_handlers[] = { { .name = "arm", @@ -1211,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"; } @@ -1303,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; @@ -1337,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; @@ -1358,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; } @@ -1368,7 +1421,7 @@ int armv4_5_run_algorithm_inner(struct target *target, } /* armv5 and later can terminate with BKPT instruction; less overhead */ - if (!exit_point && arm->is_armv4) { + if (!exit_point && arm->arch == ARM_ARCH_V4) { LOG_ERROR("ARMv4 target needs HW breakpoint location"); return ERROR_FAIL; } @@ -1401,7 +1454,7 @@ int armv4_5_run_algorithm_inner(struct target *target, if (reg_params[i].direction == PARAM_IN) continue; - struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, 0); + struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; @@ -1473,7 +1526,7 @@ int armv4_5_run_algorithm_inner(struct target *target, struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, - 0); + false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); retval = ERROR_COMMAND_SYNTAX_ERROR; @@ -1525,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, @@ -1586,10 +1639,10 @@ 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->is_armv4) + if (arm->arch == ARM_ARCH_V4) exit_var = crc_algorithm->address + sizeof(arm_crc_code_le) - 8; retval = target_run_algorithm(target, 0, NULL, 2, reg_params, @@ -1670,7 +1723,7 @@ int arm_blank_check_memory(struct target *target, buf_set_u32(reg_params[2].value, 0, 32, erased_value); /* armv4 must exit using a hardware breakpoint */ - if (arm->is_armv4) + if (arm->arch == ARM_ARCH_V4) exit_var = check_algorithm->address + sizeof(check_code_le) - 4; retval = target_run_algorithm(target, 0, NULL, 3, reg_params, @@ -1702,7 +1755,7 @@ static int arm_full_context(struct target *target) int retval = ERROR_OK; for (; num_regs && retval == ERROR_OK; num_regs--, reg++) { - if (reg->valid) + if (!reg->exist || reg->valid) continue; retval = armv4_5_get_core_reg(reg); } @@ -1711,22 +1764,38 @@ static int arm_full_context(struct target *target) static int arm_default_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, - uint32_t CRn, uint32_t CRm, + uint32_t crn, uint32_t crm, uint32_t *value) { LOG_ERROR("%s doesn't implement MRC", target_type_name(target)); 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, + uint32_t crn, uint32_t crm, uint32_t value) { LOG_ERROR("%s doesn't implement MCR", target_type_name(target)); 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; @@ -1746,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 768938fd1f..3659941e52 100644 --- a/src/target/armv4_5_cache.h +++ b/src/target/armv4_5_cache.h @@ -1,24 +1,15 @@ +/* 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 #define OPENOCD_TARGET_ARMV4_5_CACHE_H +#include "helper/types.h" + struct command_invocation; struct armv4_5_cachesize { 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 c36744ddfe..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 @@ -38,6 +27,7 @@ #include "arm_opcodes.h" #include "target.h" #include "target_type.h" +#include "smp.h" static void armv7a_show_fault_registers(struct target *target) { @@ -50,7 +40,7 @@ static void armv7a_show_fault_registers(struct target *target) if (retval != ERROR_OK) return; - /* ARMV4_5_MRC(cpnum, op1, r0, CRn, CRm, op2) */ + /* ARMV4_5_MRC(cpnum, op1, r0, crn, crm, op2) */ /* c5/c0 - {data, instruction} fault status registers */ retval = dpm->instr_read_data_r0(dpm, @@ -111,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, @@ -193,8 +183,7 @@ done: static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { struct armv7a_l2x_cache *l2x_cache; - struct target_list *head = target->head; - struct target *curr; + struct target_list *head; struct armv7a_common *armv7a = target_to_armv7a(target); l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache)); @@ -207,15 +196,14 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; /* initialize all target in this cluster (smp target) * l2 cache must be configured after smp declaration */ - while (head != (struct target_list *)NULL) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) { armv7a = target_to_armv7a(curr); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) LOG_ERROR("smp target : outer cache already initialized\n"); armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; } - head = head->next; } return JIM_OK; } @@ -282,7 +270,7 @@ int armv7a_handle_cache_info_command(struct command_invocation *cmd, } } - if (l2x_cache != NULL) + if (l2x_cache) command_print(cmd, "Outer unified cache Base Address 0x%" PRIx32 ", %" PRIu32 " ways", l2x_cache->base, l2x_cache->way); @@ -483,7 +471,7 @@ int armv7a_identify_cache(struct target *target) goto done; /* if no l2 cache initialize l1 data cache flush function function */ - if (armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache == NULL) { + if (!armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache) { armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = armv7a_cache_auto_flush_all_data; } @@ -570,9 +558,6 @@ int armv7a_arch_state(struct target *target) if (arm->core_mode == ARM_MODE_ABT) armv7a_show_fault_registers(target); - if (target->debug_reason == DBG_REASON_WATCHPOINT) - LOG_USER("Watchpoint triggered at PC %#08x", - (unsigned) armv7a->dpm.wp_pc); return ERROR_OK; } @@ -589,7 +574,7 @@ static const struct command_registration l2_cache_commands[] = { }; -const struct command_registration l2x_cache_command_handlers[] = { +static const struct command_registration l2x_cache_command_handlers[] = { { .name = "cache_config", .mode = COMMAND_EXEC, diff --git a/src/target/armv7a.h b/src/target/armv7a.h index 7b62198218..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,13 +87,14 @@ 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 */ struct arm_dpm dpm; - uint32_t debug_base; + target_addr_t debug_base; struct adiv5_ap *debug_ap; /* mdir */ uint8_t multi_processor_system; diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index e5f1fb0602..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 @@ -26,13 +15,14 @@ #include "armv7a_cache.h" #include <helper/time_support.h> #include "arm_opcodes.h" +#include "smp.h" 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; } @@ -50,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; } @@ -138,14 +128,10 @@ int armv7a_cache_auto_flush_all_data(struct target *target) if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr->state == TARGET_HALTED) retval = armv7a_l1_d_cache_clean_inval_all(curr); - - head = head->next; } } else retval = armv7a_l1_d_cache_clean_inval_all(target); @@ -572,7 +558,7 @@ static const struct command_registration arm7a_l1_i_cache_commands[] = { COMMAND_REGISTRATION_DONE }; -const struct command_registration arm7a_l1_di_cache_group_handlers[] = { +static const struct command_registration arm7a_l1_di_cache_group_handlers[] = { { .name = "info", .handler = arm7a_l1_cache_info_cmd, @@ -597,7 +583,7 @@ const struct command_registration arm7a_l1_di_cache_group_handlers[] = { COMMAND_REGISTRATION_DONE }; -const struct command_registration arm7a_cache_group_handlers[] = { +static const struct command_registration arm7a_cache_group_handlers[] = { { .name = "auto", .handler = arm7a_cache_disable_auto_cmd, 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 3607a5122d..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 @@ -27,6 +16,7 @@ #include <helper/time_support.h> #include "target.h" #include "target_type.h" +#include "smp.h" static int arm7a_l2x_sanity_check(struct target *target) { @@ -194,8 +184,7 @@ static int arm7a_handle_l2x_cache_info_command(struct command_invocation *cmd, static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { struct armv7a_l2x_cache *l2x_cache; - struct target_list *head = target->head; - struct target *curr; + struct target_list *head; struct armv7a_common *armv7a = target_to_armv7a(target); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) { @@ -210,8 +199,8 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t /* initialize all targets in this cluster (smp target) * l2 cache must be configured after smp declaration */ - while (head != (struct target_list *)NULL) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) { armv7a = target_to_armv7a(curr); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) { @@ -220,7 +209,6 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t } armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; } - head = head->next; } return ERROR_OK; } @@ -325,7 +313,7 @@ static const struct command_registration arm7a_l2x_cache_commands[] = { .name = "conf", .handler = armv7a_l2x_cache_conf_cmd, .mode = COMMAND_ANY, - .help = "configure l2x cache ", + .help = "configure l2x cache", .usage = "<base_addr> <number_of_way>", }, { 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 b4234b24e6..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 @@ -245,7 +234,7 @@ COMMAND_HANDLER(armv7a_mmu_dump_table) LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR, ttb); first_lvl_ptbl = malloc(sizeof(uint32_t)*(max_pt_idx+1)); - if (first_lvl_ptbl == NULL) + if (!first_lvl_ptbl) return ERROR_FAIL; /* 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 ea6ee6117f..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 * @@ -14,18 +16,8 @@ * 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/>. * + * Copyright (C) 2019 by Tomas Vanek * + * vanekt@fbl.cz * * * * ARMv7-M Architecture, Application Level Reference Manual * * ARM DDI 0405C (September 2008) * @@ -41,6 +33,8 @@ #include "algorithm.h" #include "register.h" #include "semihosting_common.h" +#include <helper/log.h> +#include <helper/binarybuffer.h> #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ @@ -59,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 */ @@ -68,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, }; /* @@ -103,16 +97,48 @@ 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" }, + /* A working register for packing/unpacking special regs, hidden from gdb */ + { ARMV7M_PMSK_BPRI_FLTMSK_CTRL, "pmsk_bpri_fltmsk_ctrl", 32, REG_TYPE_INT, NULL, NULL }, + + /* WARNING: If you use armv7m_write_core_reg() on one of 4 following + * special registers, the new data go to ARMV7M_PMSK_BPRI_FLTMSK_CTRL + * cache only and are not flushed to CPU HW register. + * To trigger write to CPU HW register, add + * armv7m_write_core_reg(,,ARMV7M_PMSK_BPRI_FLTMSK_CTRL,); + */ { ARMV7M_PRIMASK, "primask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV7M_CONTROL, "control", 2, 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 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.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.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" }, { ARMV7M_D1, "d1", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D2, "d2", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, @@ -150,10 +176,16 @@ int armv7m_restore_context(struct target *target) if (armv7m->pre_restore_context) armv7m->pre_restore_context(target); + /* The descending order of register writes is crucial for correct + * packing of ARMV7M_PMSK_BPRI_FLTMSK_CTRL! + * See also comments in the register table above */ for (i = cache->num_regs - 1; i >= 0; i--) { - if (cache->reg_list[i].dirty) { - armv7m->arm.write_core_reg(target, &cache->reg_list[i], i, - ARM_MODE_ANY, cache->reg_list[i].value); + struct reg *r = &cache->reg_list[i]; + + 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; } } @@ -211,87 +243,214 @@ static int armv7m_set_core_reg(struct reg *reg, uint8_t *buf) return ERROR_OK; } +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_MSP: + case ARMV7M_PSP: + /* NOTE: we "know" here that the register identifiers + * match the Cortex-M DCRSR.REGSEL selectors values + * for R0..R14, PC, xPSR, MSP, and PSP. + */ + return arm_reg_id; + + case ARMV7M_PMSK_BPRI_FLTMSK_CTRL: + return ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL; + + case ARMV8M_MSP_NS...ARMV8M_PSPLIM_NS: + return arm_reg_id - ARMV8M_MSP_NS + ARMV8M_REGSEL_MSP_NS; + + case ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S: + return ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_S; + + case ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS: + return ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_NS; + + case ARMV7M_FPSCR: + return ARMV7M_REGSEL_FPSCR; + + case ARMV7M_D0 ... ARMV7M_D15: + return ARMV7M_REGSEL_S0 + 2 * (arm_reg_id - ARMV7M_D0); + + default: + LOG_ERROR("Bad register ID %u", arm_reg_id); + return arm_reg_id; + } +} + +bool armv7m_map_reg_packing(unsigned int arm_reg_id, + unsigned int *reg32_id, uint32_t *offset) +{ + + switch (arm_reg_id) { + + case ARMV7M_PRIMASK...ARMV7M_CONTROL: + *reg32_id = ARMV7M_PMSK_BPRI_FLTMSK_CTRL; + *offset = arm_reg_id - ARMV7M_PRIMASK; + return true; + case ARMV8M_PRIMASK_S...ARMV8M_CONTROL_S: + *reg32_id = ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S; + *offset = arm_reg_id - ARMV8M_PRIMASK_S; + return true; + case ARMV8M_PRIMASK_NS...ARMV8M_CONTROL_NS: + *reg32_id = ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS; + *offset = arm_reg_id - ARMV8M_PRIMASK_NS; + return true; + + default: + return false; + } + +} + static int armv7m_read_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode) { uint32_t reg_value; int retval; - struct arm_reg *armv7m_core_reg; struct armv7m_common *armv7m = target_to_armv7m(target); assert(num < (int)armv7m->arm.core_cache->num_regs); + assert(num == (int)r->number); + + /* If a code calls read_reg, it expects the cache is no more dirty. + * Clear the dirty flag regardless of the later read succeeds or not + * to prevent unwanted cache flush after a read error */ + r->dirty = false; + + if (r->size <= 8) { + /* any 8-bit or shorter register is packed */ + uint32_t offset; + unsigned int reg32_id; + + bool is_packed = armv7m_map_reg_packing(num, ®32_id, &offset); + if (!is_packed) { + /* We should not get here as all 8-bit or shorter registers + * are packed */ + assert(false); + /* assert() does nothing if NDEBUG is defined */ + return ERROR_FAIL; + } + struct reg *r32 = &armv7m->arm.core_cache->reg_list[reg32_id]; - armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info; + /* Read 32-bit container register if not cached */ + if (!r32->valid) { + retval = armv7m_read_core_reg(target, r32, reg32_id, mode); + if (retval != ERROR_OK) + return retval; + } + + /* Copy required bits of 32-bit container register */ + buf_cpy(r32->value + offset, r->value, r->size); - if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) { - /* map D0..D15 to S0..S31 */ - size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0); - retval = armv7m->load_core_reg_u32(target, regidx, ®_value); - if (retval != ERROR_OK) - return retval; - buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, - 0, 32, reg_value); - retval = armv7m->load_core_reg_u32(target, regidx + 1, ®_value); - if (retval != ERROR_OK) - return retval; - buf_set_u32(armv7m->arm.core_cache->reg_list[num].value + 4, - 0, 32, reg_value); } else { - retval = armv7m->load_core_reg_u32(target, - armv7m_core_reg->num, ®_value); + assert(r->size == 32 || r->size == 64); + + struct arm_reg *armv7m_core_reg = r->arch_info; + uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num); + + retval = armv7m->load_core_reg_u32(target, regsel, ®_value); if (retval != ERROR_OK) return retval; - buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value); + buf_set_u32(r->value, 0, 32, reg_value); + + if (r->size == 64) { + retval = armv7m->load_core_reg_u32(target, regsel + 1, ®_value); + if (retval != ERROR_OK) { + r->valid = false; + return retval; + } + buf_set_u32(r->value + 4, 0, 32, reg_value); + + uint64_t q = buf_get_u64(r->value, 0, 64); + LOG_DEBUG("read %s value 0x%016" PRIx64, r->name, q); + } else { + LOG_DEBUG("read %s value 0x%08" PRIx32, r->name, reg_value); + } } - armv7m->arm.core_cache->reg_list[num].valid = true; - armv7m->arm.core_cache->reg_list[num].dirty = false; + r->valid = true; - return retval; + return ERROR_OK; } static int armv7m_write_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode, uint8_t *value) { int retval; - struct arm_reg *armv7m_core_reg; + uint32_t t; struct armv7m_common *armv7m = target_to_armv7m(target); assert(num < (int)armv7m->arm.core_cache->num_regs); + assert(num == (int)r->number); - armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info; + if (value != r->value) { + /* If we are not flushing the cache, store the new value to the cache */ + buf_cpy(value, r->value, r->size); + } - if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) { - /* map D0..D15 to S0..S31 */ - size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0); + if (r->size <= 8) { + /* any 8-bit or shorter register is packed */ + uint32_t offset; + unsigned int reg32_id; + + bool is_packed = armv7m_map_reg_packing(num, ®32_id, &offset); + if (!is_packed) { + /* We should not get here as all 8-bit or shorter registers + * are packed */ + assert(false); + /* assert() does nothing if NDEBUG is defined */ + return ERROR_FAIL; + } + struct reg *r32 = &armv7m->arm.core_cache->reg_list[reg32_id]; - uint32_t t = buf_get_u32(value, 0, 32); - retval = armv7m->store_core_reg_u32(target, regidx, t); - if (retval != ERROR_OK) - goto out_error; + if (!r32->valid) { + /* Before merging with other parts ensure the 32-bit register is valid */ + retval = armv7m_read_core_reg(target, r32, reg32_id, mode); + if (retval != ERROR_OK) + return retval; + } + + /* Write a part to the 32-bit container register */ + buf_cpy(value, r32->value + offset, r->size); + r32->dirty = true; - t = buf_get_u32(value + 4, 0, 32); - retval = armv7m->store_core_reg_u32(target, regidx + 1, t); - if (retval != ERROR_OK) - goto out_error; } else { - uint32_t t = buf_get_u32(value, 0, 32); + assert(r->size == 32 || r->size == 64); + + struct arm_reg *armv7m_core_reg = r->arch_info; + uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num); - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, t); - retval = armv7m->store_core_reg_u32(target, armv7m_core_reg->num, t); + t = buf_get_u32(value, 0, 32); + retval = armv7m->store_core_reg_u32(target, regsel, t); if (retval != ERROR_OK) goto out_error; + + if (r->size == 64) { + t = buf_get_u32(value + 4, 0, 32); + retval = armv7m->store_core_reg_u32(target, regsel + 1, t); + if (retval != ERROR_OK) + goto out_error; + + uint64_t q = buf_get_u64(value, 0, 64); + LOG_DEBUG("write %s value 0x%016" PRIx64, r->name, q); + } else { + LOG_DEBUG("write %s value 0x%08" PRIx32, r->name, t); + } } - armv7m->arm.core_cache->reg_list[num].valid = true; - armv7m->arm.core_cache->reg_list[num].dirty = false; + r->valid = true; + r->dirty = false; return ERROR_OK; out_error: - LOG_ERROR("Error setting register"); - armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid; - return ERROR_JTAG_DEVICE_ERROR; + r->dirty = true; + LOG_ERROR("Error setting register %s", r->name); + return retval; } /** @@ -309,7 +468,7 @@ int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], size = ARMV7M_NUM_CORE_REGS; *reg_list = malloc(sizeof(struct reg *) * size); - if (*reg_list == NULL) + if (!*reg_list) return ERROR_FAIL; for (i = 0; i < size; i++) @@ -325,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; @@ -366,18 +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; } - /* refresh core register cache - * Not needed if core register cache is always consistent with target process state */ + /* 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); + + if (!reg->valid) + LOG_TARGET_WARNING(target, "Storing invalid register %s", reg->name); - armv7m_algorithm_info->context[i] = buf_get_u32( - armv7m->arm.core_cache->reg_list[i].value, - 0, - 32); + armv7m_algorithm_info->context[i] = buf_get_u32(reg->value, 0, 32); } for (int i = 0; i < num_mem_params; i++) { @@ -395,7 +559,7 @@ int armv7m_start_algorithm(struct target *target, continue; struct reg *reg = - register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0); + register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, false); /* uint32_t regvalue; */ if (!reg) { @@ -424,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; @@ -458,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); @@ -511,7 +675,7 @@ int armv7m_wait_algorithm(struct target *target, if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, - 0); + false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); @@ -530,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; } } @@ -571,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), @@ -618,12 +786,11 @@ struct reg_cache *armv7m_build_reg_cache(struct target *target) reg_list[i].name = armv7m_regs[i].name; reg_list[i].size = armv7m_regs[i].bits; - size_t storage_size = DIV_ROUND_UP(armv7m_regs[i].bits, 8); - if (storage_size < 4) - storage_size = 4; - reg_list[i].value = calloc(1, storage_size); + reg_list[i].value = arch_info[i].value; reg_list[i].dirty = false; reg_list[i].valid = false; + reg_list[i].hidden = (i == ARMV7M_PMSK_BPRI_FLTMSK_CTRL || + i == ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS || i == ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S); reg_list[i].type = &armv7m_reg_type; reg_list[i].arch_info = &arch_info[i]; @@ -632,6 +799,9 @@ struct reg_cache *armv7m_build_reg_cache(struct target *target) reg_list[i].exist = true; reg_list[i].caller_save = true; /* gdb defaults to true */ + if (reg_list[i].hidden) + continue; + feature = calloc(1, sizeof(struct reg_feature)); if (feature) { feature->name = armv7m_regs[i].feature; @@ -646,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; @@ -671,7 +841,6 @@ void armv7m_free_reg_cache(struct target *target) free(reg->feature); free(reg->reg_data_type); - free(reg->value); } free(cache->reg_list[0].arch_info); @@ -698,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; @@ -739,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), @@ -802,7 +972,7 @@ int armv7m_blank_check_memory(struct target *target, blocks_to_check = num_blocks; struct algo_block *params = malloc((blocks_to_check+1)*sizeof(struct algo_block)); - if (params == NULL) { + if (!params) { retval = ERROR_FAIL; goto cleanup1; } @@ -846,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, @@ -928,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 01bf19e5c1..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,101 +9,171 @@ * * * 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 #define OPENOCD_TARGET_ARMV7M_H -#include "arm_adi_v5.h" #include "arm.h" #include "armv7m_trace.h" +struct adiv5_ap; + extern const int armv7m_psp_reg_map[]; extern const int armv7m_msp_reg_map[]; const char *armv7m_exception_string(int number); +/* Cortex-M DCRSR.REGSEL selectors */ +enum { + ARMV7M_REGSEL_R0, + ARMV7M_REGSEL_R1, + ARMV7M_REGSEL_R2, + ARMV7M_REGSEL_R3, + + ARMV7M_REGSEL_R4, + ARMV7M_REGSEL_R5, + ARMV7M_REGSEL_R6, + ARMV7M_REGSEL_R7, + + ARMV7M_REGSEL_R8, + ARMV7M_REGSEL_R9, + ARMV7M_REGSEL_R10, + ARMV7M_REGSEL_R11, + + ARMV7M_REGSEL_R12, + ARMV7M_REGSEL_R13, + ARMV7M_REGSEL_R14, + ARMV7M_REGSEL_PC = 15, + + ARMV7M_REGSEL_XPSR = 16, + ARMV7M_REGSEL_MSP, + ARMV7M_REGSEL_PSP, + + ARMV8M_REGSEL_MSP_NS = 0x18, + ARMV8M_REGSEL_PSP_NS, + ARMV8M_REGSEL_MSP_S, + ARMV8M_REGSEL_PSP_S, + ARMV8M_REGSEL_MSPLIM_S, + ARMV8M_REGSEL_PSPLIM_S, + ARMV8M_REGSEL_MSPLIM_NS, + ARMV8M_REGSEL_PSPLIM_NS, + + ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL = 0x14, + ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_S = 0x22, + ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_NS = 0x23, + ARMV7M_REGSEL_FPSCR = 0x21, + + /* 32bit Floating-point registers */ + ARMV7M_REGSEL_S0 = 0x40, + ARMV7M_REGSEL_S1, + ARMV7M_REGSEL_S2, + ARMV7M_REGSEL_S3, + ARMV7M_REGSEL_S4, + ARMV7M_REGSEL_S5, + ARMV7M_REGSEL_S6, + ARMV7M_REGSEL_S7, + ARMV7M_REGSEL_S8, + ARMV7M_REGSEL_S9, + ARMV7M_REGSEL_S10, + ARMV7M_REGSEL_S11, + ARMV7M_REGSEL_S12, + ARMV7M_REGSEL_S13, + ARMV7M_REGSEL_S14, + ARMV7M_REGSEL_S15, + ARMV7M_REGSEL_S16, + ARMV7M_REGSEL_S17, + ARMV7M_REGSEL_S18, + ARMV7M_REGSEL_S19, + ARMV7M_REGSEL_S20, + ARMV7M_REGSEL_S21, + ARMV7M_REGSEL_S22, + ARMV7M_REGSEL_S23, + ARMV7M_REGSEL_S24, + ARMV7M_REGSEL_S25, + ARMV7M_REGSEL_S26, + ARMV7M_REGSEL_S27, + ARMV7M_REGSEL_S28, + ARMV7M_REGSEL_S29, + ARMV7M_REGSEL_S30, + ARMV7M_REGSEL_S31, +}; + /* offsets into armv7m core register cache */ enum { /* for convenience, the first set of indices match - * the Cortex-M3/-M4 DCRSR selectors + * the Cortex-M DCRSR.REGSEL selectors + */ + ARMV7M_R0 = ARMV7M_REGSEL_R0, + ARMV7M_R1 = ARMV7M_REGSEL_R1, + ARMV7M_R2 = ARMV7M_REGSEL_R2, + ARMV7M_R3 = ARMV7M_REGSEL_R3, + + ARMV7M_R4 = ARMV7M_REGSEL_R4, + ARMV7M_R5 = ARMV7M_REGSEL_R5, + ARMV7M_R6 = ARMV7M_REGSEL_R6, + ARMV7M_R7 = ARMV7M_REGSEL_R7, + + ARMV7M_R8 = ARMV7M_REGSEL_R8, + ARMV7M_R9 = ARMV7M_REGSEL_R9, + ARMV7M_R10 = ARMV7M_REGSEL_R10, + ARMV7M_R11 = ARMV7M_REGSEL_R11, + + ARMV7M_R12 = ARMV7M_REGSEL_R12, + ARMV7M_R13 = ARMV7M_REGSEL_R13, + ARMV7M_R14 = ARMV7M_REGSEL_R14, + ARMV7M_PC = ARMV7M_REGSEL_PC, + + ARMV7M_XPSR = ARMV7M_REGSEL_XPSR, + ARMV7M_MSP = ARMV7M_REGSEL_MSP, + ARMV7M_PSP = ARMV7M_REGSEL_PSP, + + /* following indices are arbitrary, do not match DCRSR.REGSEL selectors */ + + /* A block of container and contained registers follows: + * THE ORDER IS IMPORTANT to the end of the block ! */ + /* working register for packing/unpacking special regs, hidden from gdb */ + ARMV7M_PMSK_BPRI_FLTMSK_CTRL, + + /* WARNING: If you use armv7m_write_core_reg() on one of 4 following + * special registers, the new data go to ARMV7M_PMSK_BPRI_FLTMSK_CTRL + * cache only and are not flushed to CPU HW register. + * To trigger write to CPU HW register, add + * armv7m_write_core_reg(,,ARMV7M_PMSK_BPRI_FLTMSK_CTRL,); */ - ARMV7M_R0, - ARMV7M_R1, - ARMV7M_R2, - ARMV7M_R3, - - ARMV7M_R4, - ARMV7M_R5, - ARMV7M_R6, - ARMV7M_R7, - - ARMV7M_R8, - ARMV7M_R9, - ARMV7M_R10, - ARMV7M_R11, - - ARMV7M_R12, - ARMV7M_R13, - ARMV7M_R14, - ARMV7M_PC = 15, - - ARMV7M_xPSR = 16, - ARMV7M_MSP, - ARMV7M_PSP, - - /* this next set of indices is arbitrary */ ARMV7M_PRIMASK, ARMV7M_BASEPRI, ARMV7M_FAULTMASK, ARMV7M_CONTROL, - - /* 32bit Floating-point registers */ - ARMV7M_S0, - ARMV7M_S1, - ARMV7M_S2, - ARMV7M_S3, - ARMV7M_S4, - ARMV7M_S5, - ARMV7M_S6, - ARMV7M_S7, - ARMV7M_S8, - ARMV7M_S9, - ARMV7M_S10, - ARMV7M_S11, - ARMV7M_S12, - ARMV7M_S13, - ARMV7M_S14, - ARMV7M_S15, - ARMV7M_S16, - ARMV7M_S17, - ARMV7M_S18, - ARMV7M_S19, - ARMV7M_S20, - ARMV7M_S21, - ARMV7M_S22, - ARMV7M_S23, - ARMV7M_S24, - ARMV7M_S25, - ARMV7M_S26, - ARMV7M_S27, - ARMV7M_S28, - ARMV7M_S29, - ARMV7M_S30, - ARMV7M_S31, + /* The end of block of container and contained registers */ + + /* ARMv8-M specific registers */ + ARMV8M_MSP_NS, + ARMV8M_PSP_NS, + ARMV8M_MSP_S, + ARMV8M_PSP_S, + ARMV8M_MSPLIM_S, + ARMV8M_PSPLIM_S, + ARMV8M_MSPLIM_NS, + ARMV8M_PSPLIM_NS, + + /* A block of container and contained registers follows: + * THE ORDER IS IMPORTANT to the end of the block ! */ + ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S, + ARMV8M_PRIMASK_S, + ARMV8M_BASEPRI_S, + ARMV8M_FAULTMASK_S, + ARMV8M_CONTROL_S, + /* The end of block of container and contained registers */ + + /* A block of container and contained registers follows: + * THE ORDER IS IMPORTANT to the end of the block ! */ + ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS, + ARMV8M_PRIMASK_NS, + ARMV8M_BASEPRI_NS, + ARMV8M_FAULTMASK_NS, + ARMV8M_CONTROL_NS, + /* The end of block of container and contained registers */ /* 64bit Floating-point registers */ ARMV7M_D0, @@ -121,30 +193,37 @@ enum { ARMV7M_D14, ARMV7M_D15, - /* Floating-point status registers */ - ARMV7M_FPSID, + /* Floating-point status register */ ARMV7M_FPSCR, - ARMV7M_FPEXC, + /* for convenience add registers' block delimiters */ ARMV7M_LAST_REG, + ARMV7M_CORE_FIRST_REG = ARMV7M_R0, + ARMV7M_CORE_LAST_REG = ARMV7M_XPSR, + ARMV7M_FPU_FIRST_REG = ARMV7M_D0, + ARMV7M_FPU_LAST_REG = ARMV7M_FPSCR, + ARMV8M_FIRST_REG = ARMV8M_MSP_NS, + ARMV8M_LAST_REG = ARMV8M_CONTROL_NS, }; enum { FP_NONE = 0, - FPv4_SP, - FPv5_SP, - FPv5_DP, + FPV4_SP, + FPV5_SP, + FPV5_DP, + FPV5_MVE_I, + FPV5_MVE_F, }; -#define ARMV7M_NUM_CORE_REGS (ARMV7M_xPSR + 1) -#define ARMV7M_NUM_CORE_REGS_NOFP (ARMV7M_NUM_CORE_REGS + 6) +#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 { - struct arm arm; + unsigned int common_magic; + + struct arm arm; - int common_magic; int exception_number; /* AP this processor is connected to in the DAP */ @@ -153,14 +232,14 @@ struct armv7m_common { int fp_feature; uint32_t demcr; - /* stlink is a high level adapter, does not support all functions */ - bool stlink; + /* hla_target uses a high level adapter that does not support all functions */ + bool is_hla_target; struct armv7m_trace_config trace_config; /* Direct processor core register read and writes */ - int (*load_core_reg_u32)(struct target *target, uint32_t num, uint32_t *value); - int (*store_core_reg_u32)(struct target *target, uint32_t num, uint32_t value); + int (*load_core_reg_u32)(struct target *target, uint32_t regsel, uint32_t *value); + int (*store_core_reg_u32)(struct target *target, uint32_t regsel, uint32_t value); int (*examine_debug_reason)(struct target *target); int (*post_debug_entry)(struct target *target); @@ -168,19 +247,52 @@ struct armv7m_common { void (*pre_restore_context)(struct target *target); }; +static inline bool is_armv7m(const struct armv7m_common *armv7m) +{ + return armv7m->common_magic == ARMV7M_COMMON_MAGIC; +} + +/** + * @returns the pointer to the target specific struct + * without matching a magic number. + * Use in target specific service routines, where the correct + * type of arch_info is certain. + */ static inline struct armv7m_common * target_to_armv7m(struct target *target) { return container_of(target->arch_info, struct armv7m_common, arm); } -static inline bool is_armv7m(const struct armv7m_common *armv7m) +/** + * @returns the pointer to the target specific struct + * or NULL if the magic number does not match. + * Use in a flash driver or any place where mismatch of the arch_info + * type can happen. + */ +static inline struct armv7m_common * +target_to_armv7m_safe(struct target *target) { - return armv7m->common_magic == ARMV7M_COMMON_MAGIC; + if (!target) + return NULL; + + if (!target->arch_info) + return NULL; + + /* Check the parent type first to prevent peeking memory too far + * from arch_info pointer */ + if (!is_arm(target_to_arm(target))) + return NULL; + + struct armv7m_common *armv7m = target_to_armv7m(target); + if (!is_armv7m(armv7m)) + return NULL; + + return armv7m; } struct armv7m_algorithm { - int common_magic; + unsigned int common_magic; enum arm_mode core_mode; @@ -204,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, @@ -215,13 +327,18 @@ 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); int armv7m_restore_context(struct target *target); +uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id); + +bool armv7m_map_reg_packing(unsigned int arm_reg_id, + unsigned int *reg32_id, uint32_t *offset); + int armv7m_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int armv7m_blank_check_memory(struct target *target, diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c index 6b368f7a09..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 @@ -24,113 +13,44 @@ #include <target/cortex_m.h> #include <target/armv7m_trace.h> #include <jtag/interface.h> +#include <helper/time_support.h> -#define TRACE_BUF_SIZE 4096 - -static int armv7m_poll_trace(void *target) -{ - struct armv7m_common *armv7m = target_to_armv7m(target); - uint8_t buf[TRACE_BUF_SIZE]; - size_t size = sizeof(buf); - int retval; - - retval = adapter_poll_trace(buf, &size); - if (retval != ERROR_OK || !size) - return retval; - - target_call_trace_callbacks(target, size, buf); - - if (armv7m->trace_config.trace_file != NULL) { - if (fwrite(buf, 1, size, armv7m->trace_config.trace_file) == size) - fflush(armv7m->trace_config.trace_file); - else { - LOG_ERROR("Error writing to the trace destination file"); - return ERROR_FAIL; - } - } - - return ERROR_OK; -} - -int armv7m_trace_tpiu_config(struct target *target) +int armv7m_trace_itm_config(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_trace_config *trace_config = &armv7m->trace_config; - uint16_t prescaler; int retval; - target_unregister_timer_callback(armv7m_poll_trace, target); - - retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL, - trace_config->pin_protocol, trace_config->port_size, - &trace_config->trace_freq, trace_config->traceclkin_freq, &prescaler); - - if (retval != ERROR_OK) - return retval; - - if (trace_config->config_type == TRACE_CONFIG_TYPE_EXTERNAL) { - prescaler = trace_config->traceclkin_freq / trace_config->trace_freq; - - if (trace_config->traceclkin_freq % trace_config->trace_freq) { - prescaler++; - - int trace_freq = trace_config->traceclkin_freq / prescaler; - LOG_INFO("Can not obtain %u trace port frequency from %u " - "TRACECLKIN frequency, using %u instead", - trace_config->trace_freq, trace_config->traceclkin_freq, - trace_freq); - - trace_config->trace_freq = trace_freq; - } - } - - if (!trace_config->trace_freq) { - LOG_ERROR("Trace port frequency is 0, can't enable TPIU"); - return ERROR_FAIL; - } - - retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size); - if (retval != ERROR_OK) - return retval; - - retval = target_write_u32(target, TPIU_ACPR, prescaler - 1); - if (retval != ERROR_OK) - return retval; - - retval = target_write_u32(target, TPIU_SPPR, trace_config->pin_protocol); + retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY); if (retval != ERROR_OK) return retval; - uint32_t ffcr; - retval = target_read_u32(target, TPIU_FFCR, &ffcr); + /* pg315 of CoreSight Components + * It is recommended that the ITMEn bit is cleared and waits for the + * ITMBusy bit to be cleared, before changing any fields in the + * Control Register, otherwise the behavior can be unpredictable. + */ + uint32_t itm_tcr; + retval = target_read_u32(target, ITM_TCR, &itm_tcr); if (retval != ERROR_OK) return retval; - if (trace_config->formatter) - ffcr |= (1 << 1); - else - ffcr &= ~(1 << 1); - retval = target_write_u32(target, TPIU_FFCR, ffcr); + retval = target_write_u32(target, + ITM_TCR, + itm_tcr & ~ITM_TCR_ITMENA_BIT + ); if (retval != ERROR_OK) return retval; - if (trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL) - target_register_timer_callback(armv7m_poll_trace, 1, - TARGET_TIMER_TYPE_PERIODIC, target); - - target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG); - - return ERROR_OK; -} - -int armv7m_trace_itm_config(struct target *target) -{ - struct armv7m_common *armv7m = target_to_armv7m(target); - struct armv7m_trace_config *trace_config = &armv7m->trace_config; - int retval; - - retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY); - if (retval != ERROR_OK) - return retval; + int64_t then = timeval_ms() + 1000; + do { + retval = target_read_u32(target, ITM_TCR, &itm_tcr); + if (retval != ERROR_OK) + return retval; + if (timeval_ms() > then) { + LOG_ERROR("timeout waiting for ITM_TCR_BUSY_BIT"); + return ERROR_FAIL; + } + } while (itm_tcr & ITM_TCR_BUSY_BIT); /* Enable ITM, TXENA, set TraceBusID and other parameters */ retval = target_write_u32(target, ITM_TCR, (1 << 0) | (1 << 3) | @@ -152,108 +72,6 @@ int armv7m_trace_itm_config(struct target *target) return ERROR_OK; } -static void close_trace_file(struct armv7m_common *armv7m) -{ - if (armv7m->trace_config.trace_file) - fclose(armv7m->trace_config.trace_file); - armv7m->trace_config.trace_file = NULL; -} - -COMMAND_HANDLER(handle_tpiu_config_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct armv7m_common *armv7m = target_to_armv7m(target); - - unsigned int cmd_idx = 0; - - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - if (!strcmp(CMD_ARGV[cmd_idx], "disable")) { - if (CMD_ARGC == cmd_idx + 1) { - close_trace_file(armv7m); - - armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED; - if (CMD_CTX->mode == COMMAND_EXEC) - return armv7m_trace_tpiu_config(target); - else - return ERROR_OK; - } - } else if (!strcmp(CMD_ARGV[cmd_idx], "external") || - !strcmp(CMD_ARGV[cmd_idx], "internal")) { - close_trace_file(armv7m); - - armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL; - if (!strcmp(CMD_ARGV[cmd_idx], "internal")) { - cmd_idx++; - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - - armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL; - - if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) { - armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab"); - if (!armv7m->trace_config.trace_file) { - LOG_ERROR("Can't open trace destination file"); - return ERROR_FAIL; - } - } - } - cmd_idx++; - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - - if (!strcmp(CMD_ARGV[cmd_idx], "sync")) { - armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_SYNC; - - cmd_idx++; - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size); - } else { - if (!strcmp(CMD_ARGV[cmd_idx], "manchester")) - armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER; - else if (!strcmp(CMD_ARGV[cmd_idx], "uart")) - armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_UART; - else - return ERROR_COMMAND_SYNTAX_ERROR; - - cmd_idx++; - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - - COMMAND_PARSE_ON_OFF(CMD_ARGV[cmd_idx], armv7m->trace_config.formatter); - } - - cmd_idx++; - if (CMD_ARGC == cmd_idx) - return ERROR_COMMAND_SYNTAX_ERROR; - - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.traceclkin_freq); - - cmd_idx++; - if (CMD_ARGC != cmd_idx) { - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq); - cmd_idx++; - } else { - if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_INTERNAL) { - LOG_ERROR("Trace port frequency can't be omitted in external capture mode"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - armv7m->trace_config.trace_freq = 0; - } - - if (CMD_ARGC == cmd_idx) { - if (CMD_CTX->mode == COMMAND_EXEC) - return armv7m_trace_tpiu_config(target); - else - return ERROR_OK; - } - } - - return ERROR_COMMAND_SYNTAX_ERROR; -} - COMMAND_HANDLER(handle_itm_port_command) { struct target *target = get_current_target(CMD_CTX); @@ -276,8 +94,9 @@ COMMAND_HANDLER(handle_itm_port_command) if (CMD_CTX->mode == COMMAND_EXEC) return armv7m_trace_itm_config(target); - else - return ERROR_OK; + + armv7m->trace_config.itm_deferred_config = true; + return ERROR_OK; } COMMAND_HANDLER(handle_itm_ports_command) @@ -295,23 +114,10 @@ COMMAND_HANDLER(handle_itm_ports_command) if (CMD_CTX->mode == COMMAND_EXEC) return armv7m_trace_itm_config(target); - else - return ERROR_OK; -} -static const struct command_registration tpiu_command_handlers[] = { - { - .name = "config", - .handler = handle_tpiu_config_command, - .mode = COMMAND_ANY, - .help = "Configure TPIU features", - .usage = "(disable | " - "((external | internal <filename>) " - "(sync <port width> | ((manchester | uart) <formatter enable>)) " - "<TRACECLKIN freq> [<trace freq>]))", - }, - COMMAND_REGISTRATION_DONE -}; + armv7m->trace_config.itm_deferred_config = true; + return ERROR_OK; +} static const struct command_registration itm_command_handlers[] = { { @@ -332,13 +138,6 @@ static const struct command_registration itm_command_handlers[] = { }; const struct command_registration armv7m_trace_command_handlers[] = { - { - .name = "tpiu", - .mode = COMMAND_ANY, - .help = "tpiu command group", - .usage = "", - .chain = tpiu_command_handlers, - }, { .name = "itm", .mode = COMMAND_ANY, diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h index e5879fb082..5abb0b9406 100644 --- a/src/target/armv7m_trace.h +++ b/src/target/armv7m_trace.h @@ -1,43 +1,20 @@ +/* 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 #define OPENOCD_TARGET_ARMV7M_TRACE_H +#include <helper/command.h> #include <target/target.h> -#include <command.h> /** * @file - * Holds the interface to TPIU, ITM and DWT configuration functions. + * Holds the interface to ITM and DWT configuration functions. */ -enum trace_config_type { - TRACE_CONFIG_TYPE_DISABLED, /**< tracing is disabled */ - TRACE_CONFIG_TYPE_EXTERNAL, /**< trace output is captured externally */ - TRACE_CONFIG_TYPE_INTERNAL /**< trace output is handled by OpenOCD adapter driver */ -}; - -enum tpiu_pin_protocol { - TPIU_PIN_PROTOCOL_SYNC, /**< synchronous trace output */ - TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */ - TPIU_PIN_PROTOCOL_ASYNC_UART /**< asynchronous output with NRZ coding */ -}; - enum itm_ts_prescaler { ITM_TS_PRESCALE1, /**< no prescaling for the timestamp counter */ ITM_TS_PRESCALE4, /**< refclock divided by 4 for the timestamp counter */ @@ -46,16 +23,6 @@ enum itm_ts_prescaler { }; struct armv7m_trace_config { - /** Currently active trace capture mode */ - enum trace_config_type config_type; - - /** Currently active trace output mode */ - enum tpiu_pin_protocol pin_protocol; - /** TPIU formatter enable/disable (in async mode) */ - bool formatter; - /** Synchronous output port width */ - uint32_t port_size; - /** Bitmask of currently enabled ITM stimuli */ uint32_t itm_ter[8]; /** Identifier for multi-source trace stream formatting */ @@ -68,21 +35,12 @@ struct armv7m_trace_config { bool itm_async_timestamps; /** Enable synchronisation packet transmission (for sync port only) */ bool itm_synchro_packets; - - /** Current frequency of TRACECLKIN (usually matches HCLK) */ - unsigned int traceclkin_freq; - /** Current frequency of trace port */ - unsigned int trace_freq; - /** Handle to output trace data in INTERNAL capture mode */ - FILE *trace_file; + /** Config ITM after target examine */ + bool itm_deferred_config; }; extern const struct command_registration armv7m_trace_command_handlers[]; -/** - * Configure hardware accordingly to the current TPIU target settings - */ -int armv7m_trace_tpiu_config(struct target *target); /** * Configure hardware accordingly to the current ITM target settings */ diff --git a/src/target/armv8.c b/src/target/armv8.c index ab60cd371b..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> @@ -77,6 +66,10 @@ static const struct { .name = "HYP", .psr = ARM_MODE_HYP, }, + { + .name = "UND", + .psr = ARM_MODE_UND, + }, { .name = "SYS", .psr = ARM_MODE_SYS, @@ -122,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; @@ -142,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; @@ -199,12 +352,16 @@ 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; } - if (retval == ERROR_OK && regval != NULL) + if (retval == ERROR_OK && regval) *regval = value_64; else retval = ERROR_FAIL; @@ -257,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), @@ -372,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); @@ -407,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: @@ -430,7 +587,7 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re break; } - if (retval == ERROR_OK && regval != NULL) + if (retval == ERROR_OK && regval) *regval = value; return retval; @@ -454,29 +611,31 @@ static int armv8_read_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum, retval = dpm->instr_read_data_r0(dpm, ARMV4_5_VMOV(1, 1, 0, (num >> 4), (num & 0xf)), &value_r0); + if (retval != ERROR_OK) + return retval; /* read r1 via dcc */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0), &value_r1); - if (retval == ERROR_OK) { - *lvalue = value_r1; - *lvalue = ((*lvalue) << 32) | value_r0; - } else + if (retval != ERROR_OK) return retval; + *lvalue = value_r1; + *lvalue = ((*lvalue) << 32) | value_r0; num++; /* repeat above steps for high 64 bits of V register */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_VMOV(1, 1, 0, (num >> 4), (num & 0xf)), &value_r0); + if (retval != ERROR_OK) + return retval; retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0), &value_r1); - if (retval == ERROR_OK) { - *hvalue = value_r1; - *hvalue = ((*hvalue) << 32) | value_r0; - } else + if (retval != ERROR_OK) return retval; + *hvalue = value_r1; + *hvalue = ((*hvalue) << 32) | value_r0; break; default: retval = ERROR_FAIL; @@ -506,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); @@ -541,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: @@ -586,12 +745,16 @@ static int armv8_write_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), value_r1); + if (retval != ERROR_OK) + return retval; /* write value_r0 to r0 via dcc then, * move to double word register from r0:r1: "vmov vm, r0, r1" */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_VMOV(0, 1, 0, (num >> 4), (num & 0xf)), value_r0); + if (retval != ERROR_OK) + return retval; num++; /* repeat above steps for high 64 bits of V register */ @@ -600,6 +763,8 @@ static int armv8_write_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), value_r1); + if (retval != ERROR_OK) + return retval; retval = dpm->instr_write_data_r0(dpm, ARMV4_5_VMOV(0, 1, 0, (num >> 4), (num & 0xf)), value_r0); @@ -727,7 +892,7 @@ static void armv8_show_fault_registers32(struct armv8_common *armv8) if (retval != ERROR_OK) return; - /* ARMV4_5_MRC(cpnum, op1, r0, CRn, CRm, op2) */ + /* ARMV4_5_MRC(cpnum, op1, r0, crn, crm, op2) */ /* c5/c0 - {data, instruction} fault status registers */ retval = dpm->instr_read_data_r0(dpm, @@ -772,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; + LOG_USER_N("Write-Through Transient"); break; - case 1: - ret = 36; + case 0x4: + LOG_USER_N("Write-Back Transient"); break; - case 2: - ret = 40; + case 0x8: + LOG_USER_N("Write-Through Non-transient"); break; - case 3: - ret = 42; - break; - case 4: - ret = 44; - break; - case 5: - ret = 48; - 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 */ @@ -945,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; } @@ -1006,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); } } @@ -1025,7 +1117,7 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) unsigned int argp = 0; int retval; - static const 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) }, @@ -1035,7 +1127,7 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) { .name = "sec_el13", .value = (5 << 1) }, { .name = NULL, .value = -1 }, }; - const Jim_Nvp *n; + const struct nvp *n; if (CMD_ARGC == 0) { const char *sec = NULL, *nsec = NULL; @@ -1045,15 +1137,15 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) if (retval != ERROR_OK) return retval; - n = Jim_Nvp_value2name_simple(nvp_ecatch_modes, edeccr & 0x0f); - if (n->name != NULL) + n = nvp_value2name(nvp_ecatch_modes, edeccr & 0x0f); + if (n->name) sec = n->name; - n = Jim_Nvp_value2name_simple(nvp_ecatch_modes, edeccr & 0xf0); - if (n->name != NULL) + n = nvp_value2name(nvp_ecatch_modes, edeccr & 0xf0); + if (n->name) nsec = n->name; - if (sec == NULL || nsec == NULL) { + if (!sec || !nsec) { LOG_WARNING("Exception Catch: unknown exception catch configuration: EDECCR = %02" PRIx32, edeccr & 0xff); return ERROR_FAIL; } @@ -1062,9 +1154,9 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) return ERROR_OK; } - while (CMD_ARGC > argp) { - n = Jim_Nvp_name2value_simple(nvp_ecatch_modes, CMD_ARGV[argp]); - if (n->name == NULL) { + while (argp < CMD_ARGC) { + n = nvp_name2value(nvp_ecatch_modes, CMD_ARGV[argp]); + if (!n->name) { LOG_ERROR("Unknown option: %s", CMD_ARGV[argp]); return ERROR_FAIL; } @@ -1083,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) { @@ -1098,13 +1199,6 @@ int armv8_handle_cache_info_command(struct command_invocation *cmd, static int armv8_setup_semihosting(struct target *target, int enable) { - struct arm *arm = target_to_arm(target); - - if (arm->core_state != ARM_STATE_AARCH64) { - LOG_ERROR("semihosting only supported in AArch64 state\n"); - return ERROR_FAIL; - } - return ERROR_OK; } @@ -1126,7 +1220,7 @@ int armv8_init_arch_info(struct target *target, struct armv8_common *armv8) return ERROR_OK; } -int armv8_aarch64_state(struct target *target) +static int armv8_aarch64_state(struct target *target) { struct arm *arm = target_to_arm(target); @@ -1176,8 +1270,7 @@ int armv8_arch_state(struct target *target) armv8_show_fault_registers(target); if (target->debug_reason == DBG_REASON_WATCHPOINT) - LOG_USER("Watchpoint triggered at PC %#08x", - (unsigned) armv8->dpm.wp_pc); + LOG_USER("Watchpoint triggered at " TARGET_ADDR_FMT, armv8->dpm.wp_addr); return ERROR_OK; } @@ -1372,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}, @@ -1429,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 { @@ -1457,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"}, @@ -1652,15 +1747,18 @@ struct reg_cache *armv8_build_reg_cache(struct target *target) reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); if (reg_list[i].reg_data_type) { - if (armv8_regs[i].data_type == NULL) + if (!armv8_regs[i].data_type) reg_list[i].reg_data_type->type = armv8_regs[i].type; else *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; @@ -1738,7 +1836,7 @@ void armv8_free_reg_cache(struct target *target) struct reg_cache *cache = NULL, *cache32 = NULL; cache = arm->core_cache; - if (cache != NULL) + if (cache) cache32 = cache->next; armv8_free_cache(cache32, true); armv8_free_cache(cache, false); @@ -1753,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"; @@ -1831,7 +1940,7 @@ int armv8_set_dbgreg_bits(struct armv8_common *armv8, unsigned int reg, unsigned /* Read register */ int retval = mem_ap_read_atomic_u32(armv8->debug_ap, armv8->debug_base + reg, &tmp); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* clear bitfield */ diff --git a/src/target/armv8.h b/src/target/armv8.h index 978b2ad4a1..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,13 +182,14 @@ 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 */ struct arm_dpm dpm; - uint32_t debug_base; + target_addr_t debug_base; struct adiv5_ap *debug_ap; const uint32_t *opcodes; @@ -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; @@ -257,8 +254,8 @@ static inline bool is_armv8(struct armv8_common *armv8) #define CPUV8_DBG_EDESR 0x20 #define CPUV8_DBG_EDECR 0x24 -#define CPUV8_DBG_WFAR0 0x30 -#define CPUV8_DBG_WFAR1 0x34 +#define CPUV8_DBG_EDWAR0 0x30 +#define CPUV8_DBG_EDWAR1 0x34 #define CPUV8_DBG_DSCR 0x088 #define CPUV8_DBG_DRCR 0x090 #define CPUV8_DBG_ECCR 0x098 diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c index 86e4a59615..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 @@ -23,6 +12,7 @@ #include "armv8_cache.h" #include "armv8_dpm.h" #include "armv8_opcodes.h" +#include "smp.h" /* CLIDR cache types */ #define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4 @@ -250,15 +240,12 @@ static int armv8_flush_all_data(struct target *target) /* look if all the other target have been flushed in order to flush level * 2 */ struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->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); } - head = head->next; } } else retval = _armv8_flush_all_data(target); @@ -299,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; @@ -417,7 +405,7 @@ int armv8_identify_cache(struct armv8_common *armv8) armv8->armv8_mmu.armv8_cache.info = 1; /* if no l2 cache initialize l1 data cache flush function function */ - if (armv8->armv8_mmu.armv8_cache.flush_all_data_cache == NULL) { + if (!armv8->armv8_mmu.armv8_cache.flush_all_data_cache) { armv8->armv8_mmu.armv8_cache.display_cache_info = armv8_handle_inner_cache_info_command; armv8->armv8_mmu.armv8_cache.flush_all_data_cache = 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 1e88a445fd..8bb24f225b 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 @@ -55,7 +46,7 @@ enum arm_state armv8_dpm_get_core_state(struct arm_dpm *dpm) dpm->last_el = el; /* In Debug state, each bit gives the current Execution state of each EL */ - if ((rw >> el) & 0b1) + if ((rw >> el) & 1) return ARM_STATE_AARCH64; return ARM_STATE_ARM; @@ -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, @@ -490,7 +481,7 @@ static int dpmv8_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) /* Read coprocessor */ static int dpmv8_mrc(struct target *target, int cpnum, - uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, + uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { struct arm *arm = target_to_arm(target); @@ -502,12 +493,12 @@ static int dpmv8_mrc(struct target *target, int cpnum, return retval; LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum, - (int) op1, (int) CRn, - (int) CRm, (int) op2); + (int) op1, (int) crn, + (int) crm, (int) op2); /* read coprocessor register into R0; return via DCC */ retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2), + ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2), value); /* (void) */ dpm->finish(dpm); @@ -515,7 +506,7 @@ static int dpmv8_mrc(struct target *target, int cpnum, } static int dpmv8_mcr(struct target *target, int cpnum, - uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, + uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { struct arm *arm = target_to_arm(target); @@ -527,12 +518,12 @@ static int dpmv8_mcr(struct target *target, int cpnum, return retval; LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum, - (int) op1, (int) CRn, - (int) CRm, (int) op2); + (int) op1, (int) crn, + (int) crm, (int) op2); /* read DCC into r0; then write coprocessor register from R0 */ retval = dpm->instr_write_data_r0(dpm, - ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2), + ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2), value); /* (void) */ dpm->finish(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,11 +773,17 @@ 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->valid) + if (!r->exist || r->valid) continue; /* Skip reading FP-SIMD registers */ @@ -818,7 +819,7 @@ fail: * or running debugger code. */ static int dpmv8_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, - struct dpm_bpwp *xp, int *set_p) + struct dpm_bpwp *xp, bool *set_p) { int retval = ERROR_OK; bool disable; @@ -892,7 +893,7 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct breakpoint *bp = dbp->bp; retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, - bp ? &bp->set : NULL); + bp ? &bp->is_set : NULL); if (retval != ERROR_OK) goto done; } @@ -904,7 +905,7 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct watchpoint *wp = dwp->wp; retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, - wp ? &wp->set : NULL); + wp ? &wp->is_set : NULL); if (retval != ERROR_OK) goto done; } @@ -922,8 +923,11 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) for (unsigned i = 1; i < cache->num_regs; i++) { struct arm_reg *r; + /* skip non-existent */ + 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) @@ -945,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 */ @@ -1047,7 +1051,7 @@ static int armv8_dpm_full_context(struct target *target) for (unsigned i = 0; i < cache->num_regs; i++) { struct arm_reg *r; - if (cache->reg_list[i].valid) + if (!cache->reg_list[i].exist || cache->reg_list[i].valid) continue; r = cache->reg_list[i].arch_info; @@ -1213,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; } @@ -1279,27 +1283,6 @@ static int dpmv8_remove_watchpoint(struct target *target, struct watchpoint *wp) return retval; } -void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t addr) -{ - switch (dpm->arm->core_state) { - case ARM_STATE_ARM: - case ARM_STATE_AARCH64: - addr -= 8; - break; - case ARM_STATE_THUMB: - case ARM_STATE_THUMB_EE: - addr -= 4; - break; - case ARM_STATE_JAZELLE: - /* ?? */ - break; - default: - LOG_DEBUG("Unknown core_state"); - break; - } - dpm->wp_pc = addr; -} - /* * Handle exceptions taken in debug state. This happens mostly for memory * accesses that violated a MMU policy. Taking an exception while in debug @@ -1320,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; @@ -1337,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); @@ -1428,7 +1411,7 @@ int armv8_dpm_setup(struct arm_dpm *dpm) arm->read_core_reg = armv8_dpm_read_core_reg; arm->write_core_reg = armv8_dpm_write_core_reg; - if (arm->core_cache == NULL) { + if (!arm->core_cache) { cache = armv8_build_reg_cache(target); if (!cache) return ERROR_FAIL; @@ -1465,8 +1448,10 @@ int armv8_dpm_setup(struct arm_dpm *dpm) } /* watchpoint setup */ - target->type->add_watchpoint = dpmv8_add_watchpoint; - target->type->remove_watchpoint = dpmv8_remove_watchpoint; + if (!target->type->add_watchpoint) { + target->type->add_watchpoint = dpmv8_add_watchpoint; + target->type->remove_watchpoint = dpmv8_remove_watchpoint; + } /* FIXME add vector catch support */ diff --git a/src/target/armv8_dpm.h b/src/target/armv8_dpm.h index ee6f699de2..19b33da6f0 100644 --- a/src/target/armv8_dpm.h +++ b/src/target/armv8_dpm.h @@ -1,21 +1,14 @@ +/* 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 #define OPENOCD_TARGET_ARMV8_DPM_H #include "arm_dpm.h" +#include "helper/bits.h" /* forward-declare struct armv8_common */ struct armv8_common; @@ -37,8 +30,6 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode); int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp); -void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t wfar); - /* DSCR bits; see ARMv7a arch spec section C10.3.1. * Not all v7 bits are valid in v6. */ @@ -96,6 +87,12 @@ void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t wfar); #define DRCR_RESTART (1 << 1) #define DRCR_CLEAR_EXCEPTIONS (1 << 2) +/* ECR (Execution Control Register) bits */ +#define ECR_RCE BIT(1) + +/* ESR (Event Status Register) bits */ +#define ESR_RC BIT(1) + /* PRSR (processor debug status register) bits */ #define PRSR_PU (1 << 0) #define PRSR_SPD (1 << 1) 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 239c4c5f18..9200dac723 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 @@ -26,109 +18,109 @@ #define SYSTEM_CUREL_NONCH 0xF #define SYSTEM_AARCH64 0x1 -#define SYSTEM_AAR64_MODE_EL0t 0x0 -#define SYSTEM_AAR64_MODE_EL1t 0x4 -#define SYSTEM_AAR64_MODE_EL1h 0x5 -#define SYSTEM_AAR64_MODE_EL2t 0x8 -#define SYSTEM_AAR64_MODE_EL2h 0x9 -#define SYSTEM_AAR64_MODE_EL3t 0xC -#define SYSTEM_AAR64_MODE_EL3h 0xd +#define SYSTEM_AAR64_MODE_EL0T 0x0 +#define SYSTEM_AAR64_MODE_EL1T 0x4 +#define SYSTEM_AAR64_MODE_EL1H 0x5 +#define SYSTEM_AAR64_MODE_EL2T 0x8 +#define SYSTEM_AAR64_MODE_EL2H 0x9 +#define SYSTEM_AAR64_MODE_EL3T 0xC +#define SYSTEM_AAR64_MODE_EL3H 0xd -#define SYSTEM_DAIF 0b1101101000010001 +#define SYSTEM_DAIF 0xDA11 #define SYSTEM_DAIF_MASK 0x3C0 #define SYSTEM_DAIF_SHIFT 6 -#define SYSTEM_ELR_EL1 0b1100001000000001 -#define SYSTEM_ELR_EL2 0b1110001000000001 -#define SYSTEM_ELR_EL3 0b1111001000000001 - -#define SYSTEM_SCTLR_EL1 0b1100000010000000 -#define SYSTEM_SCTLR_EL2 0b1110000010000000 -#define SYSTEM_SCTLR_EL3 0b1111000010000000 - -#define SYSTEM_FPCR 0b1101101000100000 -#define SYSTEM_FPSR 0b1101101000100001 -#define SYSTEM_DAIF 0b1101101000010001 -#define SYSTEM_NZCV 0b1101101000010000 -#define SYSTEM_SP_EL0 0b1100001000001000 -#define SYSTEM_SP_EL1 0b1110001000001000 -#define SYSTEM_SP_EL2 0b1111001000001000 -#define SYSTEM_SP_SEL 0b1100001000010000 -#define SYSTEM_SPSR_ABT 0b1110001000011001 -#define SYSTEM_SPSR_FIQ 0b1110001000011011 -#define SYSTEM_SPSR_IRQ 0b1110001000011000 -#define SYSTEM_SPSR_UND 0b1110001000011010 - -#define SYSTEM_SPSR_EL1 0b1100001000000000 -#define SYSTEM_SPSR_EL2 0b1110001000000000 -#define SYSTEM_SPSR_EL3 0b1111001000000000 - -#define SYSTEM_ISR_EL1 0b1100011000001000 - -#define SYSTEM_DBG_DSPSR_EL0 0b1101101000101000 -#define SYSTEM_DBG_DLR_EL0 0b1101101000101001 -#define SYSTEM_DBG_DTRRX_EL0 0b1001100000101000 -#define SYSTEM_DBG_DTRTX_EL0 0b1001100000101000 -#define SYSTEM_DBG_DBGDTR_EL0 0b1001100000100000 - -#define SYSTEM_CCSIDR 0b1100100000000000 -#define SYSTEM_CLIDR 0b1100100000000001 -#define SYSTEM_CSSELR 0b1101000000000000 -#define SYSTEM_CTYPE 0b1101100000000001 -#define SYSTEM_CTR 0b1101100000000001 - -#define SYSTEM_DCCISW 0b0100001111110010 -#define SYSTEM_DCCSW 0b0100001111010010 -#define SYSTEM_ICIVAU 0b0101101110101001 -#define SYSTEM_DCCVAU 0b0101101111011001 -#define SYSTEM_DCCIVAC 0b0101101111110001 - -#define SYSTEM_MPIDR 0b1100000000000101 - -#define SYSTEM_TCR_EL1 0b1100000100000010 -#define SYSTEM_TCR_EL2 0b1110000100000010 -#define SYSTEM_TCR_EL3 0b1111000100000010 - -#define SYSTEM_TTBR0_EL1 0b1100000100000000 -#define SYSTEM_TTBR0_EL2 0b1110000100000000 -#define SYSTEM_TTBR0_EL3 0b1111000100000000 -#define SYSTEM_TTBR1_EL1 0b1100000100000001 +#define SYSTEM_ELR_EL1 0xC201 +#define SYSTEM_ELR_EL2 0xE201 +#define SYSTEM_ELR_EL3 0xF201 + +#define SYSTEM_SCTLR_EL1 0xC080 +#define SYSTEM_SCTLR_EL2 0xE080 +#define SYSTEM_SCTLR_EL3 0xF080 + +#define SYSTEM_FPCR 0xDA20 +#define SYSTEM_FPSR 0xDA21 +#define SYSTEM_DAIF 0xDA11 +#define SYSTEM_NZCV 0xDA10 +#define SYSTEM_SP_EL0 0xC208 +#define SYSTEM_SP_EL1 0xE208 +#define SYSTEM_SP_EL2 0xF208 +#define SYSTEM_SP_SEL 0xC210 +#define SYSTEM_SPSR_ABT 0xE219 +#define SYSTEM_SPSR_FIQ 0xE21B +#define SYSTEM_SPSR_IRQ 0xE218 +#define SYSTEM_SPSR_UND 0xE21A + +#define SYSTEM_SPSR_EL1 0xC200 +#define SYSTEM_SPSR_EL2 0xE200 +#define SYSTEM_SPSR_EL3 0xF200 + +#define SYSTEM_ISR_EL1 0xC608 + +#define SYSTEM_DBG_DSPSR_EL0 0xDA28 +#define SYSTEM_DBG_DLR_EL0 0xDA29 +#define SYSTEM_DBG_DTRRX_EL0 0x9828 +#define SYSTEM_DBG_DTRTX_EL0 0x9828 +#define SYSTEM_DBG_DBGDTR_EL0 0x9820 + +#define SYSTEM_CCSIDR 0xC800 +#define SYSTEM_CLIDR 0xC801 +#define SYSTEM_CSSELR 0xD000 +#define SYSTEM_CTYPE 0xD801 +#define SYSTEM_CTR 0xD801 + +#define SYSTEM_DCCISW 0x43F2 +#define SYSTEM_DCCSW 0x43D2 +#define SYSTEM_ICIVAU 0x5BA9 +#define SYSTEM_DCCVAU 0x5BD9 +#define SYSTEM_DCCIVAC 0x5BF1 + +#define SYSTEM_MPIDR 0xC005 + +#define SYSTEM_TCR_EL1 0xC102 +#define SYSTEM_TCR_EL2 0xE102 +#define SYSTEM_TCR_EL3 0xF102 + +#define SYSTEM_TTBR0_EL1 0xC100 +#define SYSTEM_TTBR0_EL2 0xE100 +#define SYSTEM_TTBR0_EL3 0xF100 +#define SYSTEM_TTBR1_EL1 0xC101 /* ARMv8 address translation */ -#define SYSTEM_PAR_EL1 0b1100001110100000 -#define SYSTEM_ATS12E0R 0b0110001111000110 -#define SYSTEM_ATS12E1R 0b0110001111000100 -#define SYSTEM_ATS1E2R 0b0110001111000000 -#define SYSTEM_ATS1E3R 0b0111001111000000 +#define SYSTEM_PAR_EL1 0xC3A0 +#define SYSTEM_ATS12E0R 0x63C6 +#define SYSTEM_ATS12E1R 0x63C4 +#define SYSTEM_ATS1E2R 0x63C0 +#define SYSTEM_ATS1E3R 0x73C0 /* fault status and fault address */ -#define SYSTEM_FAR_EL1 0b1100001100000000 -#define SYSTEM_FAR_EL2 0b1110001100000000 -#define SYSTEM_FAR_EL3 0b1111001100000000 -#define SYSTEM_ESR_EL1 0b1100001010010000 -#define SYSTEM_ESR_EL2 0b1110001010010000 -#define SYSTEM_ESR_EL3 0b1111001010010000 - -#define ARMV8_MRS_DSPSR(Rt) (0xd53b4500 | (Rt)) -#define ARMV8_MSR_DSPSR(Rt) (0xd51b4500 | (Rt)) -#define ARMV8_MRS_DLR(Rt) (0xd53b4520 | (Rt)) -#define ARMV8_MSR_DLR(Rt) (0xd51b4520 | (Rt)) +#define SYSTEM_FAR_EL1 0xC300 +#define SYSTEM_FAR_EL2 0xE300 +#define SYSTEM_FAR_EL3 0xF300 +#define SYSTEM_ESR_EL1 0xC290 +#define SYSTEM_ESR_EL2 0xE290 +#define SYSTEM_ESR_EL3 0xF290 + +#define ARMV8_MRS_DSPSR(rt) (0xd53b4500 | (rt)) +#define ARMV8_MSR_DSPSR(rt) (0xd51b4500 | (rt)) +#define ARMV8_MRS_DLR(rt) (0xd53b4520 | (rt)) +#define ARMV8_MSR_DLR(rt) (0xd51b4520 | (rt)) /* T32 instruction to access coprocessor registers */ -#define ARMV8_MCR_T1(cp, CRn, opc1, CRm, opc2, Rt) ARMV4_5_MCR(cp, opc1, Rt, CRn, CRm, opc2) -#define ARMV8_MRC_T1(cp, CRn, opc1, CRm, opc2, Rt) ARMV4_5_MRC(cp, opc1, Rt, CRn, CRm, opc2) +#define ARMV8_MCR_T1(cp, crn, opc1, crm, opc2, rt) ARMV4_5_MCR(cp, opc1, rt, crn, crm, opc2) +#define ARMV8_MRC_T1(cp, crn, opc1, crm, opc2, rt) ARMV4_5_MRC(cp, opc1, rt, crn, crm, opc2) /* T32 instructions to access DSPSR and DLR */ -#define ARMV8_MRC_DSPSR(Rt) ARMV8_MRC_T1(15, 4, 3, 5, 0, Rt) -#define ARMV8_MCR_DSPSR(Rt) ARMV8_MCR_T1(15, 4, 3, 5, 0, Rt) -#define ARMV8_MRC_DLR(Rt) ARMV8_MRC_T1(15, 4, 3, 5, 1, Rt) -#define ARMV8_MCR_DLR(Rt) ARMV8_MCR_T1(15, 4, 3, 5, 1, Rt) - -#define ARMV8_DCPS1(IM) (0xd4a00001 | (((IM) & 0xFFFF) << 5)) -#define ARMV8_DCPS2(IM) (0xd4a00002 | (((IM) & 0xFFFF) << 5)) -#define ARMV8_DCPS3(IM) (0xd4a00003 | (((IM) & 0xFFFF) << 5)) -#define ARMV8_DCPS(EL, IM) (0xd4a00000 | (((IM) & 0xFFFF) << 5) | EL) -#define ARMV8_DCPS_T1(EL) (0xf78f8000 | EL) +#define ARMV8_MRC_DSPSR(rt) ARMV8_MRC_T1(15, 4, 3, 5, 0, rt) +#define ARMV8_MCR_DSPSR(rt) ARMV8_MCR_T1(15, 4, 3, 5, 0, rt) +#define ARMV8_MRC_DLR(rt) ARMV8_MRC_T1(15, 4, 3, 5, 1, rt) +#define ARMV8_MCR_DLR(rt) ARMV8_MCR_T1(15, 4, 3, 5, 1, rt) + +#define ARMV8_DCPS1(im) (0xd4a00001 | (((im) & 0xFFFF) << 5)) +#define ARMV8_DCPS2(im) (0xd4a00002 | (((im) & 0xFFFF) << 5)) +#define ARMV8_DCPS3(im) (0xd4a00003 | (((im) & 0xFFFF) << 5)) +#define ARMV8_DCPS(el, im) (0xd4a00000 | (((im) & 0xFFFF) << 5) | el) +#define ARMV8_DCPS_T1(el) (0xf78f8000 | el) #define ARMV8_DRPS 0xd6bf03e0 #define ARMV8_ERET_T1 0xf3de8f00 @@ -137,54 +129,56 @@ #define ARMV8_ISB 0xd5033fdf #define ARMV8_ISB_SY_T1 0xf3bf8f6f -#define ARMV8_MRS(System, Rt) (0xd5300000 | ((System) << 5) | (Rt)) +#define ARMV8_MRS(system, rt) (0xd5300000 | ((system) << 5) | (rt)) /* ARM V8 Move to system register. */ -#define ARMV8_MSR_GP(System, Rt) \ - (0xd5100000 | ((System) << 5) | (Rt)) +#define ARMV8_MSR_GP(system, rt) \ + (0xd5100000 | ((system) << 5) | (rt)) /* ARM V8 Move immediate to process state field. */ -#define ARMV8_MSR_IM(Op1, CRm, Op2) \ - (0xd500401f | ((Op1) << 16) | ((CRm) << 8) | ((Op2) << 5)) +#define ARMV8_MSR_IM(op1, crm, op2) \ + (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_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_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_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_BKPT(Im) (0xD4200000 | ((Im & 0xffff) << 5)) -#define ARMV8_HLT(Im) (0x0D4400000 | ((Im & 0xffff) << 5)) -#define ARMV8_HLT_A1(Im) (0xE1000070 | ((Im & 0xFFF0) << 4) | (Im & 0xF)) -#define ARMV8_HLT_T1(Im) (0xba80 | (Im & 0x3f)) +#define ARMV8_BKPT(im) (0xD4200000 | ((im & 0xffff) << 5)) +#define ARMV8_HLT(im) (0x0D4400000 | ((im & 0xffff) << 5)) +#define ARMV8_HLT_A1(im) (0xE1000070 | ((im & 0xFFF0) << 4) | (im & 0xF)) +#define ARMV8_HLT_T1(im) (0xba80 | (im & 0x3f)) -#define ARMV8_MOVFSP_64(Rt) ((1 << 31) | 0x11000000 | (0x1f << 5) | (Rt)) -#define ARMV8_MOVTSP_64(Rt) ((1 << 31) | 0x11000000 | (Rt << 5) | (0x1F)) -#define ARMV8_MOVFSP_32(Rt) (0x11000000 | (0x1f << 5) | (Rt)) -#define ARMV8_MOVTSP_32(Rt) (0x11000000 | (Rt << 5) | (0x1F)) +#define ARMV8_MOVFSP_64(rt) ((1 << 31) | 0x11000000 | (0x1f << 5) | (rt)) +#define ARMV8_MOVTSP_64(rt) ((1 << 31) | 0x11000000 | (rt << 5) | (0x1F)) +#define ARMV8_MOVFSP_32(rt) (0x11000000 | (0x1f << 5) | (rt)) +#define ARMV8_MOVTSP_32(rt) (0x11000000 | (rt << 5) | (0x1F)) -#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_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)) -#define ARMV8_LDRW_IP_T3(Rd, Rn) (0xf8500b04 | (Rn << 16) | (Rd << 12)) +#define ARMV8_LDRB_IP_T3(rd, rn) (0xf8100b01 | (rn << 16) | (rd << 12)) +#define ARMV8_LDRH_IP_T3(rd, rn) (0xf8300b02 | (rn << 16) | (rd << 12)) +#define ARMV8_LDRW_IP_T3(rd, rn) (0xf8500b04 | (rn << 16) | (rd << 12)) -#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_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)) -#define ARMV8_STRW_IP_T3(Rd, Rn) (0xf8400b04 | (Rn << 16) | (Rd << 12)) +#define ARMV8_STRB_IP_T3(rd, rn) (0xf8000b01 | (rn << 16) | (rd << 12)) +#define ARMV8_STRH_IP_T3(rd, rn) (0xf8200b02 | (rn << 16) | (rd << 12)) +#define ARMV8_STRW_IP_T3(rd, rn) (0xf8400b04 | (rn << 16) | (rd << 12)) -#define ARMV8_MOV_GPR_VFP(Rd, Rn, Index) (0x4e083c00 | (Index << 20) | (Rn << 5) | Rd) -#define ARMV8_MOV_VFP_GPR(Rd, Rn, Index) (0x4e081c00 | (Index << 20) | (Rn << 5) | Rd) +#define ARMV8_MOV_GPR_VFP(rd, rn, index) (0x4e083c00 | (index << 20) | (rn << 5) | rd) +#define ARMV8_MOV_VFP_GPR(rd, rn, index) (0x4e081c00 | (index << 20) | (rn << 5) | rd) -#define ARMV8_MRS_FPCR(Rt) (0xd53b4400 | (Rt)) -#define ARMV8_MRS_FPSR(Rt) (0xd53b4420 | (Rt)) -#define ARMV8_MSR_FPCR(Rt) (0xd51b4400 | (Rt)) -#define ARMV8_MSR_FPSR(Rt) (0xd51b4420 | (Rt)) +#define ARMV8_MRS_FPCR(rt) (0xd53b4400 | (rt)) +#define ARMV8_MRS_FPSR(rt) (0xd53b4420 | (rt)) +#define ARMV8_MSR_FPCR(rt) (0xd51b4400 | (rt)) +#define ARMV8_MSR_FPSR(rt) (0xd51b4420 | (rt)) -#define ARMV8_SYS(System, Rt) (0xD5080000 | ((System) << 5) | Rt) +#define ARMV8_SYS(system, rt) (0xD5080000 | ((system) << 5) | rt) enum armv8_opcode { READ_REG_CTR, @@ -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 6221059130..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 @@ -63,7 +52,7 @@ static const struct avr32_core_reg static int avr32_read_core_reg(struct target *target, int num); static int avr32_write_core_reg(struct target *target, int num); -int avr32_ap7k_save_context(struct target *target) +static int avr32_ap7k_save_context(struct target *target) { int retval, i; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); @@ -80,7 +69,7 @@ int avr32_ap7k_save_context(struct target *target) return ERROR_OK; } -int avr32_ap7k_restore_context(struct target *target) +static int avr32_ap7k_restore_context(struct target *target) { int i; @@ -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; } @@ -526,7 +515,7 @@ static int avr32_ap7k_target_create(struct target *target, Jim_Interp *interp) struct avr32_ap7k_common *ap7k = calloc(1, sizeof(struct avr32_ap7k_common)); - ap7k->common_magic = AP7k_COMMON_MAGIC; + ap7k->common_magic = AP7K_COMMON_MAGIC; target->arch_info = ap7k; return ERROR_OK; @@ -555,7 +544,7 @@ static int avr32_ap7k_examine(struct target *target) return ERROR_OK; } -int avr32_ap7k_arch_state(struct target *target) +static int avr32_ap7k_arch_state(struct target *target) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); @@ -565,7 +554,7 @@ int avr32_ap7k_arch_state(struct target *target) return ERROR_OK; } -int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], +static int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { #if 0 diff --git a/src/target/avr32_ap7k.h b/src/target/avr32_ap7k.h index 3f27534a30..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 64ebf12ba3..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 @@ -29,7 +18,7 @@ static int avr32_jtag_set_instr(struct avr32_jtag *jtag_info, int new_instr) int busy = 0; tap = jtag_info->tap; - if (tap == NULL) + if (!tap) return ERROR_FAIL; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) { @@ -55,7 +44,7 @@ static int avr32_jtag_set_instr(struct avr32_jtag *jtag_info, int new_instr) return ERROR_OK; } -int avr32_jtag_nexus_set_address(struct avr32_jtag *jtag_info, +static int avr32_jtag_nexus_set_address(struct avr32_jtag *jtag_info, uint32_t addr, int mode) { struct scan_field fields[2]; @@ -92,7 +81,7 @@ int avr32_jtag_nexus_set_address(struct avr32_jtag *jtag_info, } -int avr32_jtag_nexus_read_data(struct avr32_jtag *jtag_info, +static int avr32_jtag_nexus_read_data(struct avr32_jtag *jtag_info, uint32_t *pdata) { @@ -129,7 +118,7 @@ int avr32_jtag_nexus_read_data(struct avr32_jtag *jtag_info, return ERROR_OK; } -int avr32_jtag_nexus_write_data(struct avr32_jtag *jtag_info, +static int avr32_jtag_nexus_write_data(struct avr32_jtag *jtag_info, uint32_t data) { @@ -184,7 +173,7 @@ int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info, return avr32_jtag_nexus_write_data(jtag_info, value); } -int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave, +static int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave, uint32_t addr, int mode) { struct scan_field fields[2]; @@ -223,7 +212,7 @@ int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave, return ERROR_OK; } -int avr32_jtag_mwa_read_data(struct avr32_jtag *jtag_info, +static int avr32_jtag_mwa_read_data(struct avr32_jtag *jtag_info, uint32_t *pdata) { @@ -260,7 +249,7 @@ int avr32_jtag_mwa_read_data(struct avr32_jtag *jtag_info, return ERROR_OK; } -int avr32_jtag_mwa_write_data(struct avr32_jtag *jtag_info, +static int avr32_jtag_mwa_write_data(struct avr32_jtag *jtag_info, uint32_t data) { 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 71ec0b4317..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 @@ -176,7 +165,7 @@ int avr32_jtag_write_memory16(struct avr32_jtag *jtag_info, */ if (addr & 3) { /* - * mwa_read will read whole world, no nead to fiddle + * mwa_read will read whole world, no need to fiddle * with address. It will be truncated in set_addr */ retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, @@ -248,7 +237,7 @@ int avr32_jtag_write_memory8(struct avr32_jtag *jtag_info, */ if (addr & 3) { /* - * mwa_read will read whole world, no nead to fiddle + * mwa_read will read whole world, no need to fiddle * with address. It will be truncated in set_addr */ retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, 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 eb8d000c42..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 @@ -160,7 +149,7 @@ int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out) static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti) { - if (NULL == tap) { + if (!tap) { LOG_ERROR("invalid tap"); return ERROR_FAIL; } @@ -179,7 +168,7 @@ static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti) { - if (NULL == tap) { + if (!tap) { LOG_ERROR("invalid tap"); return ERROR_FAIL; } 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 c060c7cde7..c39a980570 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 @@ -26,6 +15,12 @@ #include "target.h" #include <helper/log.h> #include "breakpoints.h" +#include "smp.h" + +enum breakpoint_watchpoint { + BREAKPOINT, + WATCHPOINT, +}; static const char * const breakpoint_type_strings[] = { "hardware", @@ -50,17 +45,14 @@ static int breakpoint_add_internal(struct target *target, struct breakpoint **breakpoint_p = &target->breakpoints; const char *reason; int retval; - int n; - n = 0; while (breakpoint) { - n++; if (breakpoint->address == address) { /* FIXME don't assume "same address" means "same * 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; } @@ -73,7 +65,7 @@ static int breakpoint_add_internal(struct target *target, (*breakpoint_p)->asid = 0; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; - (*breakpoint_p)->set = 0; + (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; @@ -91,14 +83,15 @@ static int breakpoint_add_internal(struct target *target, 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("added %s breakpoint at " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")", + LOG_TARGET_DEBUG(target, "added %s breakpoint at " TARGET_ADDR_FMT + " of length 0x%8.8x, (BPID: %" PRIu32 ")", breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->address, (*breakpoint_p)->length, (*breakpoint_p)->unique_id); @@ -114,11 +107,8 @@ static int context_breakpoint_add_internal(struct target *target, struct breakpoint *breakpoint = target->breakpoints; struct breakpoint **breakpoint_p = &target->breakpoints; int retval; - int n; - n = 0; while (breakpoint) { - n++; if (breakpoint->asid == asid) { /* FIXME don't assume "same address" means "same * breakpoint" ... check all the parameters before @@ -137,20 +127,20 @@ static int context_breakpoint_add_internal(struct target *target, (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; - (*breakpoint_p)->set = 0; + (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*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); @@ -167,20 +157,18 @@ static int hybrid_breakpoint_add_internal(struct target *target, struct breakpoint *breakpoint = target->breakpoints; struct breakpoint **breakpoint_p = &target->breakpoints; int retval; - int n; - n = 0; + while (breakpoint) { - n++; if ((breakpoint->asid == asid) && (breakpoint->address == address)) { /* FIXME don't assume "same address" means "same * 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; @@ -193,7 +181,7 @@ static int hybrid_breakpoint_add_internal(struct target *target, (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; - (*breakpoint_p)->set = 0; + (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; @@ -201,13 +189,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, @@ -222,24 +210,25 @@ int breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - if (type == BKPT_SOFT) + + if (type == BKPT_SOFT) { + head = list_first_entry(target->smp_targets, struct target_list, lh); return breakpoint_add_internal(head->target, address, length, type); + } - while (head != (struct target_list *)NULL) { - curr = head->target; - retval = breakpoint_add_internal(curr, address, length, type); + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = breakpoint_add_internal(curr, address, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; - } else + + return ERROR_OK; + } else { return breakpoint_add_internal(target, address, length, type); + } } int context_breakpoint_add(struct target *target, @@ -247,21 +236,20 @@ int context_breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - retval = context_breakpoint_add_internal(curr, asid, length, type); + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = context_breakpoint_add_internal(curr, asid, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; - } else + + return ERROR_OK; + } else { return context_breakpoint_add_internal(target, asid, length, type); + } } int hybrid_breakpoint_add(struct target *target, @@ -270,25 +258,23 @@ int hybrid_breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else 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) +static int breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove) { struct breakpoint *breakpoint = target->breakpoints; struct breakpoint **breakpoint_p = &target->breakpoints; @@ -301,15 +287,22 @@ static void breakpoint_free(struct target *target, struct breakpoint *breakpoint breakpoint = breakpoint->next; } - if (breakpoint == NULL) - return; + if (!breakpoint) + return ERROR_OK; retval = target_remove_breakpoint(target, breakpoint); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(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(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) @@ -324,82 +317,173 @@ static int breakpoint_remove_internal(struct target *target, target_addr_t addre } if (breakpoint) { - breakpoint_free(target, breakpoint); - return 1; + return breakpoint_free(target, breakpoint); } else { - if (!target->smp) - LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); - return 0; + return ERROR_BREAKPOINT_NOT_FOUND; } } -static void breakpoint_remove_all_internal(struct target *target) +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) { struct breakpoint *tmp = breakpoint; breakpoint = breakpoint->next; - breakpoint_free(target, tmp); + int status = breakpoint_free(target, tmp); + if (status != ERROR_OK) + retval = status; } + + return retval; } -void breakpoint_remove(struct target *target, target_addr_t address) +int breakpoint_remove(struct target *target, target_addr_t address) { - int found = 0; + int retval = ERROR_OK; + unsigned int num_found_breakpoints = 0; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - found += breakpoint_remove_internal(curr, address); - head = head->next; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int status = breakpoint_remove_internal(curr, address); + + if (status != ERROR_BREAKPOINT_NOT_FOUND) { + num_found_breakpoints++; + + if (status != ERROR_OK) { + LOG_TARGET_ERROR(curr, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address); + retval = status; + } + } } - if (found == 0) - LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); - } else - breakpoint_remove_internal(target, address); + + } else { + retval = breakpoint_remove_internal(target, address); + + if (retval != ERROR_BREAKPOINT_NOT_FOUND) { + num_found_breakpoints++; + + if (retval != ERROR_OK) + LOG_TARGET_ERROR(target, "failed to remove breakpoint at address " TARGET_ADDR_FMT, address); + } + } + + if (num_found_breakpoints == 0) { + LOG_TARGET_ERROR(target, "no breakpoint at address " TARGET_ADDR_FMT " found", address); + return ERROR_BREAKPOINT_NOT_FOUND; + } + + return retval; } -void breakpoint_remove_all(struct target *target) +static int 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 ERROR_OK; + 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; +} + +static int watchpoint_remove_all_internal(struct target *target) +{ + 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; +} + +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; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - breakpoint_remove_all_internal(curr); - head = head->next; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + + 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 != NULL) - 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; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - breakpoint_clear_target_internal(curr); - head = head->next; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int status = breakpoint_remove_all_internal(curr); + + if (status != ERROR_OK) + retval = status; } - } else - breakpoint_clear_target_internal(target); + } else { + retval = breakpoint_remove_all_internal(target); + } + return retval; } struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) @@ -415,8 +499,8 @@ struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) return NULL; } -int watchpoint_add(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; @@ -429,7 +513,7 @@ int watchpoint_add(struct target *target, target_addr_t address, uint32_t length || 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; @@ -463,7 +547,7 @@ int watchpoint_add(struct target *target, target_addr_t address, uint32_t length 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); @@ -471,8 +555,8 @@ bye: return retval; } - LOG_DEBUG("added %s watchpoint at " TARGET_ADDR_FMT - " of length 0x%8.8" PRIx32 " (WPID: %d)", + LOG_TARGET_DEBUG(target, "added %s watchpoint at " TARGET_ADDR_FMT + " of length 0x%8.8" PRIx32 " (WPID: %d)", watchpoint_rw_strings[(*watchpoint_p)->rw], (*watchpoint_p)->address, (*watchpoint_p)->length, @@ -481,28 +565,27 @@ bye: return ERROR_OK; } -static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove) +int watchpoint_add(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; - int retval; + if (target->smp) { + struct target_list *head; - while (watchpoint) { - if (watchpoint == watchpoint_to_remove) - break; - watchpoint_p = &watchpoint->next; - watchpoint = watchpoint->next; - } + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = watchpoint_add_internal(curr, address, length, rw, value, mask); + if (retval != ERROR_OK) + return retval; + } - if (watchpoint == NULL) - return; - retval = target_remove_watchpoint(target, watchpoint); - LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval); - (*watchpoint_p) = watchpoint->next; - free(watchpoint); + return ERROR_OK; + } else { + return watchpoint_add_internal(target, address, length, rw, value, + mask); + } } -void watchpoint_remove(struct target *target, target_addr_t address) +static int watchpoint_remove_internal(struct target *target, target_addr_t address) { struct watchpoint *watchpoint = target->watchpoints; @@ -512,18 +595,68 @@ void watchpoint_remove(struct target *target, target_addr_t address) watchpoint = watchpoint->next; } - if (watchpoint) - watchpoint_free(target, watchpoint); - else - LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address); + if (watchpoint) { + return watchpoint_free(target, watchpoint); + } else { + return ERROR_WATCHPOINT_NOT_FOUND; + } +} + +int watchpoint_remove(struct target *target, target_addr_t address) +{ + int retval = ERROR_OK; + unsigned int num_found_watchpoints = 0; + if (target->smp) { + struct target_list *head; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + 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; + } + } + } + } else { + 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 != NULL) - 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, @@ -539,7 +672,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 20faf4e6c2..64c0ce2a5a 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 @@ -21,6 +10,8 @@ #include <stdint.h> +#include "helper/types.h" + struct target; enum breakpoint_type { @@ -37,44 +28,64 @@ struct breakpoint { uint32_t asid; int length; enum breakpoint_type type; - int set; + bool is_set; + unsigned int number; uint8_t *orig_instr; struct breakpoint *next; uint32_t unique_id; - int linked_BRP; + 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; - int set; + bool is_set; + unsigned int number; struct watchpoint *next; int 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); -void watchpoint_clear_target(struct target *target); +static inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int hw_number) +{ + breakpoint->is_set = true; + breakpoint->number = hw_number; +} + +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, target_addr_t *address); +static inline void watchpoint_set(struct watchpoint *watchpoint, unsigned int number) +{ + watchpoint->is_set = true; + 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 bd8e49fd9e..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 * @@ -23,18 +25,8 @@ * Copyright (C) 2013 Kamal Dasu * * kdasu.kdev@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/>. * + * Copyright (C) 2016 Chengyu Zheng * + * chengyu.zheng@polimi.it : watchpoint support * * * * Cortex-A8(tm) TRM, ARM DDI 0344H * * Cortex-A9(tm) TRM, ARM DDI 0407F * @@ -53,11 +45,14 @@ #include "armv7a_mmu.h" #include "target_request.h" #include "target_type.h" +#include "arm_coresight.h" #include "arm_opcodes.h" #include "arm_semihosting.h" #include "jtag/interface.h" #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); @@ -80,6 +75,16 @@ static int cortex_a_virt2phys(struct target *target, static int cortex_a_read_cpu_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); +static unsigned int ilog2(unsigned int x) +{ + unsigned int y = 0; + x /= 2; + while (x) { + ++y; + x /= 2; + } + return y; +} /* restore cp15_control_reg at resume */ static int cortex_a_restore_cp15_control_reg(struct target *target) @@ -466,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; @@ -534,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) { @@ -607,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; @@ -624,14 +676,11 @@ static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) static struct target *get_cortex_a(struct target *target, int32_t coreid) { struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; - head = head->next; } return target; } @@ -641,14 +690,12 @@ static int cortex_a_halt_smp(struct target *target) { int retval = 0; struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED) && target_was_examined(curr)) retval += cortex_a_halt(curr); - head = head->next; } return retval; } @@ -669,7 +716,7 @@ static int update_halt_gdb(struct target *target) if (target->gdb_service) gdb_target = target->gdb_service->target; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) @@ -690,7 +737,7 @@ static int update_halt_gdb(struct target *target) } /* after all targets were updated, poll the gdb serving target */ - if (gdb_target != NULL && gdb_target != target) + if (gdb_target && gdb_target != target) cortex_a_poll(gdb_target); return retval; } @@ -712,7 +759,7 @@ static int cortex_a_poll(struct target *target) /* the next polling trigger an halt event sent to gdb */ if ((target->state == TARGET_HALTED) && (target->smp) && (target->gdb_service) && - (target->gdb_service->target == NULL)) { + (!target->gdb_service->target)) { target->gdb_service->target = get_cortex_a(target, target->gdb_service->core[1]); target_call_event_callbacks(target, TARGET_EVENT_HALTED); @@ -808,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 @@ -936,11 +983,10 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) { int retval = 0; struct target_list *head; - struct target *curr; target_addr_t address; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { /* resume current address , not in step mode */ @@ -948,8 +994,6 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) handle_breakpoints, 0); retval += cortex_a_internal_restart(curr); } - head = head->next; - } return retval; } @@ -1115,7 +1159,8 @@ static int cortex_a_post_debug_entry(struct target *target) return ERROR_OK; } -int cortex_a_set_dscr_bits(struct target *target, unsigned long bit_mask, unsigned long value) +static int cortex_a_set_dscr_bits(struct target *target, + unsigned long bit_mask, unsigned long value) { struct armv7a_common *armv7a = target_to_armv7a(target); uint32_t dscr; @@ -1123,7 +1168,7 @@ int cortex_a_set_dscr_bits(struct target *target, unsigned long bit_mask, unsign /* Read DSCR */ int retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* clear bitfield */ @@ -1149,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; } @@ -1177,12 +1222,12 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre stepbreakpoint.length = (arm->core_state == ARM_STATE_THUMB) ? 2 : 4; stepbreakpoint.type = BKPT_HARD; - stepbreakpoint.set = 0; + stepbreakpoint.is_set = false; /* Disable interrupts during single step if requested */ if (cortex_a->isrmasking_mode == CORTEX_A_ISRMASK_ON) { retval = cortex_a_set_dscr_bits(target, DSCR_INT_DIS, DSCR_INT_DIS); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; } @@ -1213,7 +1258,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre /* Re-enable interrupts if they were disabled */ if (cortex_a->isrmasking_mode == CORTEX_A_ISRMASK_ON) { retval = cortex_a_set_dscr_bits(target, DSCR_INT_DIS, 0); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; } @@ -1257,7 +1302,7 @@ static int cortex_a_set_breakpoint(struct target *target, struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1269,22 +1314,22 @@ static int cortex_a_set_breakpoint(struct target *target, LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); if (breakpoint->length == 2) byte_addr_select = (3 << (breakpoint->address & 0x02)); control = ((matchmode & 0x7) << 20) | (byte_addr_select << 5) | (3 << 1) | 1; - brp_list[brp_i].used = 1; + brp_list[brp_i].used = true; brp_list[brp_i].value = (breakpoint->address & 0xFFFFFFFC); brp_list[brp_i].control = control; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, + + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, + + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; @@ -1334,7 +1379,7 @@ static int cortex_a_set_breakpoint(struct target *target, armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length); - breakpoint->set = 0x11; /* Any nice value but 0 */ + breakpoint->is_set = true; } return ERROR_OK; @@ -1351,7 +1396,7 @@ static int cortex_a_set_context_breakpoint(struct target *target, struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1365,20 +1410,20 @@ static int cortex_a_set_context_breakpoint(struct target *target, return ERROR_FAIL; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); control = ((matchmode & 0x7) << 20) | (byte_addr_select << 5) | (3 << 1) | 1; - brp_list[brp_i].used = 1; + brp_list[brp_i].used = true; brp_list[brp_i].value = (breakpoint->asid); brp_list[brp_i].control = control; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, + + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, + + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; @@ -1394,16 +1439,16 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi int retval = ERROR_FAIL; int brp_1 = 0; /* holds the contextID pair */ int brp_2 = 0; /* holds the IVA pair */ - uint32_t control_CTX, control_IVA; - uint8_t CTX_byte_addr_select = 0x0F; - uint8_t IVA_byte_addr_select = 0x0F; - uint8_t CTX_machmode = 0x03; - uint8_t IVA_machmode = 0x01; + uint32_t control_ctx, control_iva; + uint8_t ctx_byte_addr_select = 0x0F; + uint8_t iva_byte_addr_select = 0x0F; + uint8_t ctx_machmode = 0x03; + uint8_t iva_machmode = 0x01; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1412,7 +1457,7 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi (brp_list[brp_1].type != BRP_CONTEXT)) && (brp_1 < cortex_a->brp_num)) brp_1++; - printf("brp(CTX) found num: %d\n", brp_1); + LOG_DEBUG("brp(CTX) found num: %d", brp_1); if (brp_1 >= cortex_a->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; @@ -1422,47 +1467,47 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi (brp_list[brp_2].type != BRP_NORMAL)) && (brp_2 < cortex_a->brp_num)) brp_2++; - printf("brp(IVA) found num: %d\n", brp_2); + LOG_DEBUG("brp(IVA) found num: %d", brp_2); if (brp_2 >= cortex_a->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } - breakpoint->set = brp_1 + 1; - breakpoint->linked_BRP = brp_2; - control_CTX = ((CTX_machmode & 0x7) << 20) + breakpoint_hw_set(breakpoint, brp_1); + breakpoint->linked_brp = brp_2; + control_ctx = ((ctx_machmode & 0x7) << 20) | (brp_2 << 16) | (0 << 14) - | (CTX_byte_addr_select << 5) + | (ctx_byte_addr_select << 5) | (3 << 1) | 1; - brp_list[brp_1].used = 1; + brp_list[brp_1].used = true; brp_list[brp_1].value = (breakpoint->asid); - brp_list[brp_1].control = control_CTX; + brp_list[brp_1].control = control_ctx; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_1].BRPn, + + CPUDBG_BVR_BASE + 4 * brp_list[brp_1].brpn, brp_list[brp_1].value); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_1].BRPn, + + CPUDBG_BCR_BASE + 4 * brp_list[brp_1].brpn, brp_list[brp_1].control); if (retval != ERROR_OK) return retval; - control_IVA = ((IVA_machmode & 0x7) << 20) + control_iva = ((iva_machmode & 0x7) << 20) | (brp_1 << 16) - | (IVA_byte_addr_select << 5) + | (iva_byte_addr_select << 5) | (3 << 1) | 1; - brp_list[brp_2].used = 1; + brp_list[brp_2].used = true; brp_list[brp_2].value = (breakpoint->address & 0xFFFFFFFC); - brp_list[brp_2].control = control_IVA; + brp_list[brp_2].control = control_iva; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_2].BRPn, + + CPUDBG_BVR_BASE + 4 * brp_list[brp_2].brpn, brp_list[brp_2].value); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_2].BRPn, + + CPUDBG_BCR_BASE + 4 * brp_list[brp_2].brpn, brp_list[brp_2].control); if (retval != ERROR_OK) return retval; @@ -1477,31 +1522,31 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - int brp_i = breakpoint->set - 1; - int brp_j = breakpoint->linked_BRP; - if ((brp_i < 0) || (brp_i >= cortex_a->brp_num)) { + int brp_i = breakpoint->number; + int brp_j = breakpoint->linked_brp; + if (brp_i >= cortex_a->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); - brp_list[brp_i].used = 0; + brp_list[brp_i].used = false; brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, + + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, + + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; @@ -1511,45 +1556,45 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_j, brp_list[brp_j].control, brp_list[brp_j].value); - brp_list[brp_j].used = 0; + brp_list[brp_j].used = false; brp_list[brp_j].value = 0; brp_list[brp_j].control = 0; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_j].BRPn, + + CPUDBG_BCR_BASE + 4 * brp_list[brp_j].brpn, brp_list[brp_j].control); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_j].BRPn, + + CPUDBG_BVR_BASE + 4 * brp_list[brp_j].brpn, brp_list[brp_j].value); if (retval != ERROR_OK) return retval; - breakpoint->linked_BRP = 0; - breakpoint->set = 0; + breakpoint->linked_brp = 0; + breakpoint->is_set = false; return ERROR_OK; } else { - int brp_i = breakpoint->set - 1; - if ((brp_i < 0) || (brp_i >= cortex_a->brp_num)) { + int brp_i = breakpoint->number; + if (brp_i >= cortex_a->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); - brp_list[brp_i].used = 0; + brp_list[brp_i].used = false; brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, + + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, + + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } } else { @@ -1581,7 +1626,7 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length); } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -1647,7 +1692,7 @@ static int cortex_a_remove_breakpoint(struct target *target, struct breakpoint * } #endif - if (breakpoint->set) { + if (breakpoint->is_set) { cortex_a_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) cortex_a->brp_num_available++; @@ -1657,6 +1702,200 @@ static int cortex_a_remove_breakpoint(struct target *target, struct breakpoint * return ERROR_OK; } +/** + * Sets a watchpoint for an Cortex-A target in one of the watchpoint units. It is + * considered a bug to call this function when there are no available watchpoint + * units. + * + * @param target Pointer to an Cortex-A target to set a watchpoint on + * @param watchpoint Pointer to the watchpoint to be set + * @return Error status if watchpoint set fails or the result of executing the + * JTAG queue + */ +static int cortex_a_set_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + int retval = ERROR_OK; + int wrp_i = 0; + uint32_t control; + uint32_t address; + uint8_t address_mask; + uint8_t byte_address_select; + uint8_t load_store_access_control = 0x3; + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + struct armv7a_common *armv7a = &cortex_a->armv7a_common; + struct cortex_a_wrp *wrp_list = cortex_a->wrp_list; + + if (watchpoint->is_set) { + LOG_WARNING("watchpoint already set"); + return retval; + } + + /* check available context WRPs */ + while (wrp_list[wrp_i].used && (wrp_i < cortex_a->wrp_num)) + wrp_i++; + + if (wrp_i >= cortex_a->wrp_num) { + LOG_ERROR("ERROR Can not find free Watchpoint Register Pair"); + return ERROR_FAIL; + } + + if (watchpoint->length == 0 || watchpoint->length > 0x80000000U || + (watchpoint->length & (watchpoint->length - 1))) { + LOG_WARNING("watchpoint length must be a power of 2"); + return ERROR_FAIL; + } + + if (watchpoint->address & (watchpoint->length - 1)) { + LOG_WARNING("watchpoint address must be aligned at length"); + return ERROR_FAIL; + } + + /* FIXME: ARM DDI 0406C: address_mask is optional. What to do if it's missing? */ + /* handle wp length 1 and 2 through byte select */ + switch (watchpoint->length) { + case 1: + byte_address_select = BIT(watchpoint->address & 0x3); + address = watchpoint->address & ~0x3; + address_mask = 0; + break; + + case 2: + byte_address_select = 0x03 << (watchpoint->address & 0x2); + address = watchpoint->address & ~0x3; + address_mask = 0; + break; + + case 4: + byte_address_select = 0x0f; + address = watchpoint->address; + address_mask = 0; + break; + + default: + byte_address_select = 0xff; + address = watchpoint->address; + address_mask = ilog2(watchpoint->length); + break; + } + + watchpoint_set(watchpoint, wrp_i); + control = (address_mask << 24) | + (byte_address_select << 5) | + (load_store_access_control << 3) | + (0x3 << 1) | 1; + wrp_list[wrp_i].used = true; + wrp_list[wrp_i].value = address; + wrp_list[wrp_i].control = control; + + retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + + CPUDBG_WVR_BASE + 4 * wrp_list[wrp_i].wrpn, + wrp_list[wrp_i].value); + if (retval != ERROR_OK) + return retval; + + retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + + CPUDBG_WCR_BASE + 4 * wrp_list[wrp_i].wrpn, + wrp_list[wrp_i].control); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("wp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, wrp_i, + wrp_list[wrp_i].control, + wrp_list[wrp_i].value); + + return ERROR_OK; +} + +/** + * Unset an existing watchpoint and clear the used watchpoint unit. + * + * @param target Pointer to the target to have the watchpoint removed + * @param watchpoint Pointer to the watchpoint to be removed + * @return Error status while trying to unset the watchpoint or the result of + * executing the JTAG queue + */ +static int cortex_a_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + int retval; + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + struct armv7a_common *armv7a = &cortex_a->armv7a_common; + struct cortex_a_wrp *wrp_list = cortex_a->wrp_list; + + if (!watchpoint->is_set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + int wrp_i = watchpoint->number; + if (wrp_i >= cortex_a->wrp_num) { + LOG_DEBUG("Invalid WRP number in watchpoint"); + return ERROR_OK; + } + LOG_DEBUG("wrp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, wrp_i, + wrp_list[wrp_i].control, wrp_list[wrp_i].value); + wrp_list[wrp_i].used = false; + wrp_list[wrp_i].value = 0; + wrp_list[wrp_i].control = 0; + retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + + CPUDBG_WCR_BASE + 4 * wrp_list[wrp_i].wrpn, + wrp_list[wrp_i].control); + if (retval != ERROR_OK) + return retval; + retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + + CPUDBG_WVR_BASE + 4 * wrp_list[wrp_i].wrpn, + wrp_list[wrp_i].value); + if (retval != ERROR_OK) + return retval; + watchpoint->is_set = false; + + return ERROR_OK; +} + +/** + * Add a watchpoint to an Cortex-A target. If there are no watchpoint units + * available, an error response is returned. + * + * @param target Pointer to the Cortex-A target to add a watchpoint to + * @param watchpoint Pointer to the watchpoint to be added + * @return Error status while trying to add the watchpoint + */ +static int cortex_a_add_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + + if (cortex_a->wrp_num_available < 1) { + LOG_INFO("no hardware watchpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + int retval = cortex_a_set_watchpoint(target, watchpoint); + if (retval != ERROR_OK) + return retval; + + cortex_a->wrp_num_available--; + return ERROR_OK; +} + +/** + * Remove a watchpoint from an Cortex-A target. The watchpoint will be unset and + * the used watchpoint unit will be reopened. + * + * @param target Pointer to the target to remove a watchpoint from + * @param watchpoint Pointer to the watchpoint to be removed + * @return Result of trying to unset the watchpoint + */ +static int cortex_a_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + + if (watchpoint->is_set) { + cortex_a->wrp_num_available++; + cortex_a_unset_watchpoint(target, watchpoint); + } + return ERROR_OK; +} + + /* * Cortex-A Reset functions */ @@ -1680,10 +1919,10 @@ static int cortex_a_assert_reset(struct target *target) */ /* - * FIXME: fix reset when transport is SWD. This is a temporary + * FIXME: fix reset when transport is not JTAG. This is a temporary * work-around for release v0.10 that is not intended to stay! */ - if (transport_is_swd() || + if (!transport_is_jtag() || (target->reset_halt && (jtag_get_reset_config() & RESET_SRST_NO_GATING))) adapter_assert_reset(); @@ -2033,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; } @@ -2055,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; @@ -2063,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. */ @@ -2097,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. */ @@ -2351,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; } @@ -2373,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; @@ -2381,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. */ @@ -2416,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. */ @@ -2677,16 +2914,27 @@ static int cortex_a_examine_first(struct target *target) struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct adiv5_dap *swjdp = armv7a->arm.dap; + struct adiv5_private_config *pc = target->private_config; int i; int retval = ERROR_OK; uint32_t didr, cpuid, dbg_osreg, dbg_idpfr1; - /* 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; + } + } } retval = mem_ap_init(armv7a->debug_ap); @@ -2698,24 +2946,17 @@ static int cortex_a_examine_first(struct target *target) armv7a->debug_ap->memaccess_tck = 80; if (!target->dbgbase_set) { - uint32_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 0x15 -- Processor DAP */ - retval = dap_lookup_cs_component(armv7a->debug_ap, dbgbase, 0x15, - &armv7a->debug_base, &coreidx); + /* Lookup Processor DAP */ + 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); return retval; } - LOG_DEBUG("Detected core %" PRId32 " dbgbase: %08" PRIx32, + LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT, target->coreid, armv7a->debug_base); } else armv7a->debug_base = target->dbgbase; @@ -2748,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, @@ -2781,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; } @@ -2795,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 @@ -2824,18 +3062,32 @@ static int cortex_a_examine_first(struct target *target) cortex_a->brp_list = calloc(cortex_a->brp_num, sizeof(struct cortex_a_brp)); /* cortex_a->brb_enabled = ????; */ for (i = 0; i < cortex_a->brp_num; i++) { - cortex_a->brp_list[i].used = 0; + cortex_a->brp_list[i].used = false; if (i < (cortex_a->brp_num-cortex_a->brp_num_context)) cortex_a->brp_list[i].type = BRP_NORMAL; else cortex_a->brp_list[i].type = BRP_CONTEXT; cortex_a->brp_list[i].value = 0; cortex_a->brp_list[i].control = 0; - cortex_a->brp_list[i].BRPn = i; + cortex_a->brp_list[i].brpn = i; } LOG_DEBUG("Configured %i hw breakpoints", cortex_a->brp_num); + /* Setup Watchpoint Register Pairs */ + cortex_a->wrp_num = ((didr >> 28) & 0x0F) + 1; + cortex_a->wrp_num_available = cortex_a->wrp_num; + free(cortex_a->wrp_list); + cortex_a->wrp_list = calloc(cortex_a->wrp_num, sizeof(struct cortex_a_wrp)); + for (i = 0; i < cortex_a->wrp_num; i++) { + cortex_a->wrp_list[i].used = false; + cortex_a->wrp_list[i].value = 0; + cortex_a->wrp_list[i].control = 0; + cortex_a->wrp_list[i].wrpn = i; + } + + LOG_DEBUG("Configured %i hw watchpoints", cortex_a->wrp_num); + /* select debug_ap as default */ swjdp->apsel = armv7a->debug_ap->ap_num; @@ -2903,13 +3155,13 @@ static int cortex_a_target_create(struct target *target, Jim_Interp *interp) struct cortex_a_common *cortex_a; struct adiv5_private_config *pc; - if (target->private_config == NULL) + if (!target->private_config) return ERROR_FAIL; pc = (struct adiv5_private_config *)target->private_config; cortex_a = calloc(1, sizeof(struct cortex_a_common)); - if (cortex_a == NULL) { + if (!cortex_a) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -2930,7 +3182,7 @@ static int cortex_r4_target_create(struct target *target, Jim_Interp *interp) return ERROR_FAIL; cortex_a = calloc(1, sizeof(struct cortex_a_common)); - if (cortex_a == NULL) { + if (!cortex_a) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -2958,6 +3210,10 @@ 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); free(dpm->dbp); @@ -2971,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) @@ -3035,16 +3291,16 @@ 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 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 Jim_Nvp *n; + const struct nvp *n; if (CMD_ARGC > 0) { - n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); - if (n->name == NULL) { + 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; } @@ -3052,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; @@ -3063,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 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 Jim_Nvp *n; + const struct nvp *n; if (CMD_ARGC > 0) { - n = Jim_Nvp_name2value_simple(nvp_dacrfixup_modes, CMD_ARGV[0]); - if (n->name == NULL) + 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; @@ -3142,7 +3398,6 @@ static const struct command_registration cortex_a_command_handlers[] = { struct target_type cortexa_target = { .name = "cortex_a", - .deprecated_name = "cortex_a8", .poll = cortex_a_poll, .arch_state = armv7a_arch_state, @@ -3173,8 +3428,8 @@ struct target_type cortexa_target = { .add_context_breakpoint = cortex_a_add_context_breakpoint, .add_hybrid_breakpoint = cortex_a_add_hybrid_breakpoint, .remove_breakpoint = cortex_a_remove_breakpoint, - .add_watchpoint = NULL, - .remove_watchpoint = NULL, + .add_watchpoint = cortex_a_add_watchpoint, + .remove_watchpoint = cortex_a_remove_watchpoint, .commands = cortex_a_command_handlers, .target_create = cortex_a_target_create, @@ -3250,8 +3505,8 @@ struct target_type cortexr4_target = { .add_context_breakpoint = cortex_a_add_context_breakpoint, .add_hybrid_breakpoint = cortex_a_add_hybrid_breakpoint, .remove_breakpoint = cortex_a_remove_breakpoint, - .add_watchpoint = NULL, - .remove_watchpoint = NULL, + .add_watchpoint = cortex_a_add_watchpoint, + .remove_watchpoint = cortex_a_remove_watchpoint, .commands = cortex_r4_command_handlers, .target_create = cortex_r4_target_create, diff --git a/src/target/cortex_a.h b/src/target/cortex_a.h index 197a5992da..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 @@ -64,15 +52,24 @@ enum cortex_a_dacrfixup_mode { }; struct cortex_a_brp { - int used; + bool used; int type; uint32_t value; uint32_t control; - uint8_t BRPn; + uint8_t brpn; +}; + +struct cortex_a_wrp { + bool used; + uint32_t value; + uint32_t control; + uint8_t wrpn; }; struct cortex_a_common { - int common_magic; + unsigned int common_magic; + + struct armv7a_common armv7a_common; /* Context information */ uint32_t cpudbg_dscr; @@ -92,15 +89,15 @@ struct cortex_a_common { int brp_num; int brp_num_available; struct cortex_a_brp *brp_list; + int wrp_num; + int wrp_num_available; + struct cortex_a_wrp *wrp_list; uint32_t cpuid; uint32_t didr; 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 4b0ea50ccc..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) * * * @@ -34,11 +23,15 @@ #include "cortex_m.h" #include "target_request.h" #include "target_type.h" +#include "arm_adi_v5.h" #include "arm_disassembler.h" #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> /* NOTE: most of this should work fine for the Cortex-M1 and * Cortex-M0 cores too, although they're ARMv6-M not ARMv7-M. @@ -51,17 +44,137 @@ * any longer. */ +/* Timeout for register r/w */ +#define DHCSR_S_REGRDY_TIMEOUT (500) + +/* Supported Cortex-M Cores */ +static const struct cortex_m_part_info cortex_m_parts[] = { + { + .impl_part = CORTEX_M0_PARTNO, + .name = "Cortex-M0", + .arch = ARM_ARCH_V6M, + }, + { + .impl_part = CORTEX_M0P_PARTNO, + .name = "Cortex-M0+", + .arch = ARM_ARCH_V6M, + }, + { + .impl_part = CORTEX_M1_PARTNO, + .name = "Cortex-M1", + .arch = ARM_ARCH_V6M, + }, + { + .impl_part = CORTEX_M3_PARTNO, + .name = "Cortex-M3", + .arch = ARM_ARCH_V7M, + .flags = CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K, + }, + { + .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, + }, + { + .impl_part = CORTEX_M7_PARTNO, + .name = "Cortex-M7", + .arch = ARM_ARCH_V7M, + .flags = CORTEX_M_F_HAS_FPV5, + }, + { + .impl_part = CORTEX_M23_PARTNO, + .name = "Cortex-M23", + .arch = ARM_ARCH_V8M, + }, + { + .impl_part = CORTEX_M33_PARTNO, + .name = "Cortex-M33", + .arch = ARM_ARCH_V8M, + .flags = CORTEX_M_F_HAS_FPV5, + }, + { + .impl_part = CORTEX_M35P_PARTNO, + .name = "Cortex-M35P", + .arch = ARM_ARCH_V8M, + .flags = CORTEX_M_F_HAS_FPV5, + }, + { + .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 */ static int cortex_m_store_core_reg_u32(struct target *target, uint32_t num, uint32_t value); static void cortex_m_dwt_free(struct target *target); -static int cortexm_dap_read_coreregister_u32(struct target *target, - uint32_t *value, int regnum) +/** DCB DHCSR register contains S_RETIRE_ST and S_RESET_ST bits cleared + * on a read. Call this helper function each time DHCSR is read + * to preserve S_RESET_ST state in case of a reset event was detected. + */ +static inline void cortex_m_cumulate_dhcsr_sticky(struct cortex_m_common *cortex_m, + uint32_t dhcsr) +{ + cortex_m->dcb_dhcsr_cumulated_sticky |= dhcsr; +} + +/** Read DCB DHCSR register to cortex_m->dcb_dhcsr and cumulate + * sticky bits in cortex_m->dcb_dhcsr_cumulated_sticky + */ +static int cortex_m_read_dhcsr_atomic_sticky(struct target *target) { + struct cortex_m_common *cortex_m = target_to_cm(target); + struct armv7m_common *armv7m = target_to_armv7m(target); + + int retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, + &cortex_m->dcb_dhcsr); + if (retval != ERROR_OK) + return retval; + + cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr); + return ERROR_OK; +} + +static int cortex_m_load_core_reg_u32(struct target *target, + uint32_t regsel, uint32_t *value) +{ + struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = target_to_armv7m(target); int retval; - uint32_t dcrdr; + uint32_t dcrdr, tmp_value; + int64_t then; /* because the DCB_DCRDR is used for the emulated dcc channel * we have to save/restore the DCB_DCRDR when used */ @@ -71,13 +184,33 @@ static int cortexm_dap_read_coreregister_u32(struct target *target, return retval; } - retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regnum); + retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regsel); if (retval != ERROR_OK) return retval; - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DCRDR, value); - if (retval != ERROR_OK) - return retval; + /* check if value from register is ready and pre-read it */ + then = timeval_ms(); + while (1) { + retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DHCSR, + &cortex_m->dcb_dhcsr); + if (retval != ERROR_OK) + return retval; + retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DCRDR, + &tmp_value); + if (retval != ERROR_OK) + return retval; + cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr); + if (cortex_m->dcb_dhcsr & S_REGRDY) + break; + cortex_m->slow_register_read = true; /* Polling (still) needed. */ + if (timeval_ms() > then + DHCSR_S_REGRDY_TIMEOUT) { + LOG_TARGET_ERROR(target, "Timeout waiting for DCRDR transfer ready"); + return ERROR_TIMEOUT_REACHED; + } + keep_alive(); + } + + *value = tmp_value; if (target->dbg_msg_enabled) { /* restore DCB_DCRDR - this needs to be in a separate @@ -89,12 +222,180 @@ static int cortexm_dap_read_coreregister_u32(struct target *target, return retval; } -static int cortexm_dap_write_coreregister_u32(struct target *target, - uint32_t value, int regnum) +static int cortex_m_slow_read_all_regs(struct target *target) +{ + struct cortex_m_common *cortex_m = target_to_cm(target); + struct armv7m_common *armv7m = target_to_armv7m(target); + const unsigned int num_regs = armv7m->arm.core_cache->num_regs; + + /* Opportunistically restore fast read, it'll revert to slow + * if any register needed polling in cortex_m_load_core_reg_u32(). */ + cortex_m->slow_register_read = false; + + for (unsigned int reg_id = 0; reg_id < num_regs; reg_id++) { + struct reg *r = &armv7m->arm.core_cache->reg_list[reg_id]; + if (r->exist) { + int retval = armv7m->arm.read_core_reg(target, r, reg_id, ARM_MODE_ANY); + if (retval != ERROR_OK) + return retval; + } + } + + if (!cortex_m->slow_register_read) + LOG_TARGET_DEBUG(target, "Switching back to fast register reads"); + + return ERROR_OK; +} + +static int cortex_m_queue_reg_read(struct target *target, uint32_t regsel, + uint32_t *reg_value, uint32_t *dhcsr) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + int retval; + + retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regsel); + if (retval != ERROR_OK) + return retval; + + retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DHCSR, dhcsr); + if (retval != ERROR_OK) + return retval; + + return mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, reg_value); +} + +static int cortex_m_fast_read_all_regs(struct target *target) +{ + struct cortex_m_common *cortex_m = target_to_cm(target); + struct armv7m_common *armv7m = target_to_armv7m(target); + int retval; + uint32_t dcrdr; + + /* because the DCB_DCRDR is used for the emulated dcc channel + * we have to save/restore the DCB_DCRDR when used */ + if (target->dbg_msg_enabled) { + retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, &dcrdr); + if (retval != ERROR_OK) + return retval; + } + + const unsigned int num_regs = armv7m->arm.core_cache->num_regs; + const unsigned int n_r32 = ARMV7M_LAST_REG - ARMV7M_CORE_FIRST_REG + 1 + + ARMV7M_FPU_LAST_REG - ARMV7M_FPU_FIRST_REG + 1; + /* we need one 32-bit word for each register except FP D0..D15, which + * need two words */ + uint32_t r_vals[n_r32]; + uint32_t dhcsr[n_r32]; + + unsigned int wi = 0; /* write index to r_vals and dhcsr arrays */ + unsigned int reg_id; /* register index in the reg_list, ARMV7M_R0... */ + for (reg_id = 0; reg_id < num_regs; reg_id++) { + struct reg *r = &armv7m->arm.core_cache->reg_list[reg_id]; + if (!r->exist) + continue; /* skip non existent registers */ + + if (r->size <= 8) { + /* Any 8-bit or shorter register is unpacked from a 32-bit + * container register. Skip it now. */ + continue; + } + + uint32_t regsel = armv7m_map_id_to_regsel(reg_id); + retval = cortex_m_queue_reg_read(target, regsel, &r_vals[wi], + &dhcsr[wi]); + if (retval != ERROR_OK) + return retval; + wi++; + + assert(r->size == 32 || r->size == 64); + if (r->size == 32) + continue; /* done with 32-bit register */ + + assert(reg_id >= ARMV7M_FPU_FIRST_REG && reg_id <= ARMV7M_FPU_LAST_REG); + /* the odd part of FP register (S1, S3...) */ + retval = cortex_m_queue_reg_read(target, regsel + 1, &r_vals[wi], + &dhcsr[wi]); + if (retval != ERROR_OK) + return retval; + wi++; + } + + assert(wi <= n_r32); + + retval = dap_run(armv7m->debug_ap->dap); + if (retval != ERROR_OK) + return retval; + + if (target->dbg_msg_enabled) { + /* restore DCB_DCRDR - this needs to be in a separate + * transaction otherwise the emulated DCC channel breaks */ + retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRDR, dcrdr); + if (retval != ERROR_OK) + return retval; + } + + bool not_ready = false; + for (unsigned int i = 0; i < wi; i++) { + if ((dhcsr[i] & S_REGRDY) == 0) { + not_ready = true; + LOG_TARGET_DEBUG(target, "Register %u was not ready during fast read", i); + } + cortex_m_cumulate_dhcsr_sticky(cortex_m, dhcsr[i]); + } + + if (not_ready) { + /* Any register was not ready, + * fall back to slow read with S_REGRDY polling */ + return ERROR_TIMEOUT_REACHED; + } + + LOG_TARGET_DEBUG(target, "read %u 32-bit registers", wi); + + unsigned int ri = 0; /* read index from r_vals array */ + for (reg_id = 0; reg_id < num_regs; reg_id++) { + struct reg *r = &armv7m->arm.core_cache->reg_list[reg_id]; + if (!r->exist) + continue; /* skip non existent registers */ + + r->dirty = false; + + unsigned int reg32_id; + uint32_t offset; + if (armv7m_map_reg_packing(reg_id, ®32_id, &offset)) { + /* Unpack a partial register from 32-bit container register */ + struct reg *r32 = &armv7m->arm.core_cache->reg_list[reg32_id]; + + /* The container register ought to precede all regs unpacked + * from it in the reg_list. So the value should be ready + * to unpack */ + assert(r32->valid); + buf_cpy(r32->value + offset, r->value, r->size); + + } else { + assert(r->size == 32 || r->size == 64); + buf_set_u32(r->value, 0, 32, r_vals[ri++]); + + if (r->size == 64) { + assert(reg_id >= ARMV7M_FPU_FIRST_REG && reg_id <= ARMV7M_FPU_LAST_REG); + /* the odd part of FP register (S1, S3...) */ + buf_set_u32(r->value + 4, 0, 32, r_vals[ri++]); + } + } + r->valid = true; + } + assert(ri == wi); + + return retval; +} + +static int cortex_m_store_core_reg_u32(struct target *target, + uint32_t regsel, uint32_t value) { + struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = target_to_armv7m(target); int retval; uint32_t dcrdr; + int64_t then; /* because the DCB_DCRDR is used for the emulated dcc channel * we have to save/restore the DCB_DCRDR when used */ @@ -108,10 +409,25 @@ static int cortexm_dap_write_coreregister_u32(struct target *target, if (retval != ERROR_OK) return retval; - retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRSR, regnum | DCRSR_WnR); + retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regsel | DCRSR_WNR); if (retval != ERROR_OK) return retval; + /* check if value is written into register */ + then = timeval_ms(); + while (1) { + retval = cortex_m_read_dhcsr_atomic_sticky(target); + if (retval != ERROR_OK) + return retval; + if (cortex_m->dcb_dhcsr & S_REGRDY) + break; + if (timeval_ms() > then + DHCSR_S_REGRDY_TIMEOUT) { + LOG_TARGET_ERROR(target, "Timeout waiting for DCRDR transfer ready"); + return ERROR_TIMEOUT_REACHED; + } + keep_alive(); + } + if (target->dbg_msg_enabled) { /* restore DCB_DCRDR - this needs to be in a separate * transaction otherwise the emulated DCC channel breaks */ @@ -231,7 +547,7 @@ static int cortex_m_clear_halt(struct target *target) retval = mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_DFSR, cortex_m->nvic_dfsr); if (retval != ERROR_OK) return retval; - LOG_DEBUG(" NVIC_DFSR 0x%" PRIx32 "", cortex_m->nvic_dfsr); + LOG_TARGET_DEBUG(target, "NVIC_DFSR 0x%" PRIx32 "", cortex_m->nvic_dfsr); return ERROR_OK; } @@ -239,7 +555,6 @@ static int cortex_m_clear_halt(struct target *target) static int cortex_m_single_step_core(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); - struct armv7m_common *armv7m = &cortex_m->armv7m; int retval; /* Mask interrupts before clearing halt, if not done already. This avoids @@ -247,16 +562,14 @@ static int cortex_m_single_step_core(struct target *target) * HALT can put the core into an unknown state. */ if (!(cortex_m->dcb_dhcsr & C_MASKINTS)) { - retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR, - DBGKEY | C_MASKINTS | C_HALT | C_DEBUGEN); + retval = cortex_m_write_debug_halt_mask(target, C_MASKINTS, 0); if (retval != ERROR_OK) return retval; } - retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR, - DBGKEY | C_MASKINTS | C_STEP | C_DEBUGEN); + retval = cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); if (retval != ERROR_OK) return retval; - LOG_DEBUG(" "); + LOG_TARGET_DEBUG(target, "single step"); /* restore dhcsr reg */ cortex_m_clear_halt(target); @@ -284,7 +597,6 @@ static int cortex_m_enable_fpb(struct target *target) static int cortex_m_endreset_event(struct target *target) { - int i; int retval; uint32_t dcb_demcr; struct cortex_m_common *cortex_m = target_to_cm(target); @@ -297,18 +609,19 @@ static int cortex_m_endreset_event(struct target *target) retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DEMCR, &dcb_demcr); if (retval != ERROR_OK) return retval; - LOG_DEBUG("DCB_DEMCR = 0x%8.8" PRIx32 "", dcb_demcr); + LOG_TARGET_DEBUG(target, "DCB_DEMCR = 0x%8.8" PRIx32 "", dcb_demcr); /* this register is used for emulated dcc channel */ retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, 0); if (retval != ERROR_OK) return retval; - /* Enable debug requests */ - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; + if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) { + /* Enable debug requests */ retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS); if (retval != ERROR_OK) return retval; @@ -335,21 +648,21 @@ static int cortex_m_endreset_event(struct target *target) /* Enable FPB */ retval = cortex_m_enable_fpb(target); if (retval != ERROR_OK) { - LOG_ERROR("Failed to enable the FPB"); + LOG_TARGET_ERROR(target, "Failed to enable the FPB"); return retval; } cortex_m->fpb_enabled = true; /* Restore FPB registers */ - for (i = 0; i < cortex_m->fp_num_code + cortex_m->fp_num_lit; i++) { + for (unsigned int i = 0; i < cortex_m->fp_num_code + cortex_m->fp_num_lit; i++) { retval = target_write_u32(target, fp_list[i].fpcr_address, fp_list[i].fpcr_value); if (retval != ERROR_OK) return retval; } /* Restore DWT registers */ - for (i = 0; i < cortex_m->dwt_num_comp; i++) { + for (unsigned int i = 0; i < cortex_m->dwt_num_comp; i++) { retval = target_write_u32(target, dwt_list[i].dwt_comparator_address + 0, dwt_list[i].comp); if (retval != ERROR_OK) @@ -369,8 +682,15 @@ 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 = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); + if (retval != ERROR_OK) + return retval; return retval; } @@ -470,7 +790,7 @@ static int cortex_m_examine_exception_reason(struct target *target) } retval = dap_run(swjdp); if (retval == ERROR_OK) - LOG_DEBUG("%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 + LOG_TARGET_DEBUG(target, "%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 ", CFSR 0x%" PRIx32 ", AR 0x%" PRIx32, armv7m_exception_string(armv7m->exception_number), shcsr, except_sr, cfsr, except_ar); @@ -479,22 +799,22 @@ static int cortex_m_examine_exception_reason(struct target *target) static int cortex_m_debug_entry(struct target *target) { - int i; - 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; struct arm *arm = &armv7m->arm; struct reg *r; - LOG_DEBUG(" "); + LOG_TARGET_DEBUG(target, " "); /* Do this really early to minimize the window where the MASKINTS erratum * can pile up pending interrupts. */ cortex_m_set_maskints_for_halt(target); cortex_m_clear_halt(target); - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; @@ -503,45 +823,40 @@ static int cortex_m_debug_entry(struct target *target) return retval; /* examine PE security state */ - bool secure_state = false; - if (armv7m->arm.is_armv8m) { - uint32_t dscsr; - + uint32_t dscsr = 0; + if (armv7m->arm.arch == ARM_ARCH_V8M) { 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 */ + if (!cortex_m->slow_register_read) { + retval = cortex_m_fast_read_all_regs(target); + if (retval == ERROR_TIMEOUT_REACHED) { + cortex_m->slow_register_read = true; + LOG_TARGET_DEBUG(target, "Switched to slow register read"); + } } - /* Examine target state and mode - * First load register accessible through core debug port */ - int num_regs = arm->core_cache->num_regs; + if (cortex_m->slow_register_read) + retval = cortex_m_slow_read_all_regs(target); - for (i = 0; i < num_regs; i++) { - r = &armv7m->arm.core_cache->reg_list[i]; - if (!r->valid) - arm->read_core_reg(target, r, i, ARM_MODE_ANY); - } + if (retval != ERROR_OK) + return retval; r = arm->cpsr; - xPSR = buf_get_u32(r->value, 0, 32); - - /* For IT instructions xPSR must be reloaded on resume and clear on debug exec */ - if (xPSR & 0xf00) { - r->dirty = r->valid; - cortex_m_store_core_reg_u32(target, 16, xPSR & ~0xff); - } + 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; } else { unsigned control = buf_get_u32(arm->core_cache - ->reg_list[ARMV7M_CONTROL].value, 0, 2); + ->reg_list[ARMV7M_CONTROL].value, 0, 3); /* is this thread privileged? */ arm->core_mode = control & 1 @@ -560,7 +875,9 @@ static int cortex_m_debug_entry(struct target *target) if (armv7m->exception_number) cortex_m_examine_exception_reason(target); - LOG_DEBUG("entered debug state in core mode: %s at PC 0x%" PRIx32 ", cpu in %s state, target->state: %s", + 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), buf_get_u32(arm->pc->value, 0, 32), secure_state ? "Secure" : "Non-Secure", @@ -575,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; @@ -584,7 +901,7 @@ static int cortex_m_poll(struct target *target) struct armv7m_common *armv7m = &cortex_m->armv7m; /* Read from Debug Halting Control and Status Register */ - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) { target->state = TARGET_UNKNOWN; return retval; @@ -594,8 +911,7 @@ static int cortex_m_poll(struct target *target) * section B1.5.15 "Unrecoverable exception cases". */ if (cortex_m->dcb_dhcsr & S_LOCKUP) { - LOG_ERROR("%s -- clearing lockup after double fault", - target_name(target)); + LOG_TARGET_ERROR(target, "clearing lockup after double fault"); cortex_m_write_debug_halt_mask(target, C_HALT, 0); target->debug_reason = DBG_REASON_DBGRQ; @@ -605,15 +921,16 @@ static int cortex_m_poll(struct target *target) detected_failure = ERROR_FAIL; /* refresh status bits */ - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; } - if (cortex_m->dcb_dhcsr & S_RESET_ST) { + if (cortex_m->dcb_dhcsr_cumulated_sticky & S_RESET_ST) { + cortex_m->dcb_dhcsr_cumulated_sticky &= ~S_RESET_ST; if (target->state != TARGET_RESET) { target->state = TARGET_RESET; - LOG_INFO("%s: external reset detected", target_name(target)); + LOG_TARGET_INFO(target, "external reset detected"); } return ERROR_OK; } @@ -622,7 +939,7 @@ static int cortex_m_poll(struct target *target) /* Cannot switch context while running so endreset is * called with target->state == TARGET_RESET */ - LOG_DEBUG("Exit from reset with dcb_dhcsr 0x%" PRIx32, + LOG_TARGET_DEBUG(target, "Exit from reset with dcb_dhcsr 0x%" PRIx32, cortex_m->dcb_dhcsr); retval = cortex_m_endreset_event(target); if (retval != ERROR_OK) { @@ -638,31 +955,36 @@ 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) { - LOG_DEBUG(" "); 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; } - /* REVISIT when S_SLEEP is set, it's in a Sleep or DeepSleep state. - * How best to model low power modes? - */ - if (target->state == TARGET_UNKNOWN) { - /* check if processor is retiring instructions */ - if (cortex_m->dcb_dhcsr & S_RETIRE_ST) { + /* Check if processor is retiring instructions or sleeping. + * Unlike S_RESET_ST here we test if the target *is* running now, + * not if it has been running (possibly in the past). Instructions are + * typically processed much faster than OpenOCD polls DHCSR so S_RETIRE_ST + * is read always 1. That's the reason not to use dcb_dhcsr_cumulated_sticky. + */ + if (cortex_m->dcb_dhcsr & S_RETIRE_ST || cortex_m->dcb_dhcsr & S_SLEEP) { target->state = TARGET_RUNNING; retval = ERROR_OK; } @@ -674,7 +996,7 @@ static int cortex_m_poll(struct target *target) register_cache_invalidate(armv7m->arm.core_cache); target->state = TARGET_RUNNING; - LOG_WARNING("%s: external resume detected", target_name(target)); + LOG_TARGET_WARNING(target, "external resume detected"); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); retval = ERROR_OK; } @@ -685,35 +1007,118 @@ 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) { - LOG_DEBUG("target->state: %s", - target_state_name(target)); + int retval = ERROR_OK; + struct target_list *head; - if (target->state == TARGET_HALTED) { - LOG_DEBUG("target was already halted"); - return ERROR_OK; + 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; +} - if (target->state == TARGET_UNKNOWN) - LOG_WARNING("target was in unknown state when halt was requested"); +static int cortex_m_smp_post_halt_poll(struct list_head *smp_targets) +{ + int retval = ERROR_OK; + struct target_list *head; - if (target->state == TARGET_RESET) { - if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { - LOG_ERROR("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; + 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; - return ERROR_OK; + 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) { + LOG_TARGET_DEBUG(target, "target was already halted"); + return ERROR_OK; + } + + if (target->state == TARGET_UNKNOWN) + LOG_TARGET_WARNING(target, "target was in unknown state when halt was requested"); + /* 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. */ @@ -721,21 +1126,33 @@ 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) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; - uint32_t dcb_dhcsr = 0; int retval, timeout = 0; /* on single cortex_m MCU soft_reset_halt should be avoided as same functionality * can be obtained by using 'reset halt' and 'cortex_m reset_config vectreset'. * As this reset only uses VC_CORERESET it would only ever reset the cortex_m * core, not the peripherals */ - LOG_DEBUG("soft_reset_halt is discouraged, please use 'reset halt' instead."); + LOG_TARGET_DEBUG(target, "soft_reset_halt is discouraged, please use 'reset halt' instead."); + + if (!cortex_m->vectreset_supported) { + LOG_TARGET_ERROR(target, "VECTRESET is not supported on this Cortex-M core"); + return ERROR_FAIL; + } /* Set C_DEBUGEN */ retval = cortex_m_write_debug_halt_mask(target, 0, C_STEP | C_MASKINTS); @@ -759,25 +1176,24 @@ static int cortex_m_soft_reset_halt(struct target *target) register_cache_invalidate(cortex_m->armv7m.arm.core_cache); while (timeout < 100) { - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval == ERROR_OK) { retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_DFSR, &cortex_m->nvic_dfsr); if (retval != ERROR_OK) return retval; - if ((dcb_dhcsr & S_HALT) + if ((cortex_m->dcb_dhcsr & S_HALT) && (cortex_m->nvic_dfsr & DFSR_VCATCH)) { - LOG_DEBUG("system reset-halted, DHCSR 0x%08x, " - "DFSR 0x%08x", - (unsigned) dcb_dhcsr, - (unsigned) cortex_m->nvic_dfsr); + LOG_TARGET_DEBUG(target, "system reset-halted, DHCSR 0x%08" PRIx32 ", DFSR 0x%08" PRIx32, + cortex_m->dcb_dhcsr, cortex_m->nvic_dfsr); cortex_m_poll(target); /* FIXME restore user's vector catch config */ return ERROR_OK; - } else - LOG_DEBUG("waiting for system reset-halt, " - "DHCSR 0x%08x, %d ms", - (unsigned) dcb_dhcsr, timeout); + } else { + LOG_TARGET_DEBUG(target, "waiting for system reset-halt, " + "DHCSR 0x%08" PRIx32 ", %d ms", + cortex_m->dcb_dhcsr, timeout); + } } timeout++; alive_sleep(1); @@ -792,14 +1208,14 @@ void cortex_m_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (!breakpoint->set) + if (!breakpoint->is_set) cortex_m_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } } -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; @@ -807,7 +1223,7 @@ static int cortex_m_resume(struct target *target, int current, struct reg *r; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -827,15 +1243,19 @@ static int cortex_m_resume(struct target *target, int current, * in parallel with disabled interrupts can cause local faults * to not be taken. * - * REVISIT this clearly breaks non-debug execution, since the - * PRIMASK register state isn't saved/restored... workaround - * by never resuming app code after debug execution. + * This breaks non-debug (application) execution if not + * called from armv7m_start_algorithm() which saves registers. */ buf_set_u32(r->value, 0, 1, 1); r->dirty = true; r->valid = true; - /* Make sure we are in Thumb mode */ + /* Make sure we are in Thumb mode, set xPSR.T bit */ + /* armv7m_start_algorithm() initializes entire xPSR register. + * This duplicity handles the case when cortex_m_resume() + * is used with the debug_execution flag directly, + * not called through armv7m_start_algorithm(). + */ r = armv7m->arm.cpsr; buf_set_u32(r->value, 24, 1, 1); r->dirty = true; @@ -845,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; } @@ -859,45 +1279,114 @@ 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) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { - LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")", + 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_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - LOG_DEBUG("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) @@ -911,13 +1400,21 @@ static int cortex_m_step(struct target *target, int current, bool isr_timed_out = false; if (target->state != TARGET_HALTED) { - LOG_WARNING("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) + if (!current) { buf_set_u32(pc->value, 0, 32, address); + pc->dirty = true; + pc->valid = true; + } uint32_t pc_value = buf_get_u32(pc->value, 0, 32); @@ -981,7 +1478,7 @@ static int cortex_m_step(struct target *target, int current, * */ if ((pc_value & 0x02) && breakpoint_find(target, pc_value & ~0x03)) { - LOG_DEBUG("Stepping over next instruction with interrupts disabled"); + LOG_TARGET_DEBUG(target, "Stepping over next instruction with interrupts disabled"); cortex_m_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); /* Re-enable interrupts if appropriate */ @@ -1012,16 +1509,14 @@ static int cortex_m_step(struct target *target, int current, cortex_m_set_maskints_for_halt(target); } else { /* Start the core */ - LOG_DEBUG("Starting core to serve pending interrupts"); + LOG_TARGET_DEBUG(target, "Starting core to serve pending interrupts"); int64_t t_start = timeval_ms(); cortex_m_set_maskints_for_run(target); cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP); /* Wait for pending handlers to complete or timeout */ do { - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, - DCB_DHCSR, - &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) { target->state = TARGET_UNKNOWN; return retval; @@ -1038,7 +1533,7 @@ static int cortex_m_step(struct target *target, int current, } if (isr_timed_out) { - LOG_DEBUG("Interrupt handlers didn't complete within time, " + LOG_TARGET_DEBUG(target, "Interrupt handlers didn't complete within time, " "leaving target running"); } else { /* Step over next instruction with interrupts disabled */ @@ -1056,7 +1551,7 @@ static int cortex_m_step(struct target *target, int current, } } - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; @@ -1073,7 +1568,7 @@ static int cortex_m_step(struct target *target, int current, return ERROR_OK; } - LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 + LOG_TARGET_DEBUG(target, "target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32, cortex_m->dcb_dhcsr, cortex_m->nvic_icsr); @@ -1082,7 +1577,7 @@ static int cortex_m_step(struct target *target, int current, return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); - LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 + LOG_TARGET_DEBUG(target, "target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32, cortex_m->dcb_dhcsr, cortex_m->nvic_icsr); @@ -1095,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_DEBUG("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(); @@ -1111,31 +1607,48 @@ 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_ERROR("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_ERROR("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; - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + int retval = cortex_m_read_dhcsr_atomic_sticky(target); + /* Store important errors instead of failing and proceed to reset assert */ if (retval != ERROR_OK || !(cortex_m->dcb_dhcsr & C_DEBUGEN)) @@ -1169,7 +1682,7 @@ static int cortex_m_assert_reset(struct target *target) retval2 = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); if (retval != ERROR_OK || retval2 != ERROR_OK) - LOG_INFO("AP write error, reset will not halt"); + LOG_TARGET_INFO(target, "AP write error, reset will not halt"); } if (jtag_reset_config & RESET_HAS_SRST) { @@ -1180,24 +1693,23 @@ 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 VECRESET 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. */ if (!cortex_m->vectreset_supported && reset_config == CORTEX_M_RESET_VECTRESET) { reset_config = CORTEX_M_RESET_SYSRESETREQ; - LOG_WARNING("VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead."); - LOG_WARNING("Set 'cortex_m reset_config sysresetreq'."); + LOG_TARGET_WARNING(target, "VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead."); + LOG_TARGET_WARNING(target, "Set 'cortex_m reset_config sysresetreq'."); } - LOG_DEBUG("Using Cortex-M %s", (reset_config == CORTEX_M_RESET_SYSRESETREQ) + LOG_TARGET_DEBUG(target, "Using Cortex-M %s", (reset_config == CORTEX_M_RESET_SYSRESETREQ) ? "SYSRESETREQ" : "VECTRESET"); if (reset_config == CORTEX_M_RESET_VECTRESET) { - LOG_WARNING("Only resetting the Cortex-M core, use a reset-init event " + LOG_TARGET_WARNING(target, "Only resetting the Cortex-M core, use a reset-init event " "handler to reset any peripherals or configure hardware srst support."); } @@ -1206,13 +1718,15 @@ static int cortex_m_assert_reset(struct target *target) AIRCR_VECTKEY | ((reset_config == CORTEX_M_RESET_SYSRESETREQ) ? AIRCR_SYSRESETREQ : AIRCR_VECTRESET)); if (retval3 != ERROR_OK) - LOG_DEBUG("Ignoring AP write error right after reset"); - - retval3 = dap_dp_init(armv7m->debug_ap->dap); - if (retval3 != ERROR_OK) - LOG_ERROR("DP initialisation failed"); - - else { + LOG_TARGET_DEBUG(target, "Ignoring AP write error right after reset"); + + retval3 = dap_dp_init_or_reconnect(armv7m->debug_ap->dap); + if (retval3 != ERROR_OK) { + LOG_TARGET_ERROR(target, "DP initialisation failed"); + /* The error return value must not be propagated in this case. + * SYSRESETREQ or VECTRESET have been possibly triggered + * so reset processing should continue */ + } else { /* I do not know why this is necessary, but it * fixes strange effects (step/resume cause NMI * after reset) on LM3S6918 -- Michael Schwingen @@ -1227,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_DEBUG("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(); @@ -1253,11 +1758,12 @@ 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)) { - int retval = dap_dp_init(armv7m->debug_ap->dap); + !(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) { - LOG_ERROR("DP initialisation failed"); + LOG_TARGET_ERROR(target, "DP initialisation failed"); return retval; } } @@ -1268,12 +1774,12 @@ static int cortex_m_deassert_reset(struct target *target) int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; - int fp_num = 0; + unsigned int fp_num = 0; struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; - if (breakpoint->set) { - LOG_WARNING("breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id); + if (breakpoint->is_set) { + LOG_TARGET_WARNING(target, "breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id); return ERROR_OK; } @@ -1282,35 +1788,36 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint while (comparator_list[fp_num].used && (fp_num < cortex_m->fp_num_code)) fp_num++; if (fp_num >= cortex_m->fp_num_code) { - LOG_ERROR("Can not find free FPB Comparator!"); + LOG_TARGET_ERROR(target, "Can not find free FPB Comparator!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = fp_num + 1; + breakpoint_hw_set(breakpoint, fp_num); fpcr_value = breakpoint->address | 1; if (cortex_m->fp_rev == 0) { if (breakpoint->address > 0x1FFFFFFF) { - LOG_ERROR("Cortex-M Flash Patch Breakpoint rev.1 cannot handle HW breakpoint above address 0x1FFFFFFE"); + LOG_TARGET_ERROR(target, "Cortex-M Flash Patch Breakpoint rev.1 " + "cannot handle HW breakpoint above address 0x1FFFFFFE"); return ERROR_FAIL; } uint32_t hilo; hilo = (breakpoint->address & 0x2) ? FPCR_REPLACE_BKPT_HIGH : FPCR_REPLACE_BKPT_LOW; fpcr_value = (fpcr_value & 0x1FFFFFFC) | hilo | 1; } else if (cortex_m->fp_rev > 1) { - LOG_ERROR("Unhandled Cortex-M Flash Patch Breakpoint architecture revision"); + LOG_TARGET_ERROR(target, "Unhandled Cortex-M Flash Patch Breakpoint architecture revision"); return ERROR_FAIL; } comparator_list[fp_num].used = true; comparator_list[fp_num].fpcr_value = fpcr_value; target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); - LOG_DEBUG("fpc_num %i fpcr_value 0x%" PRIx32 "", + LOG_TARGET_DEBUG(target, "fpc_num %i fpcr_value 0x%" PRIx32 "", fp_num, comparator_list[fp_num].fpcr_value); if (!cortex_m->fpb_enabled) { - LOG_DEBUG("FPB wasn't enabled, do it now"); + LOG_TARGET_DEBUG(target, "FPB wasn't enabled, do it now"); retval = cortex_m_enable_fpb(target); if (retval != ERROR_OK) { - LOG_ERROR("Failed to enable the FPB"); + LOG_TARGET_ERROR(target, "Failed to enable the FPB"); return retval; } @@ -1336,15 +1843,15 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint code); if (retval != ERROR_OK) return retval; - breakpoint->set = true; + breakpoint->is_set = true; } - LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", + LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (n=%u)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, breakpoint->length, - breakpoint->set); + (breakpoint->type == BKPT_SOFT) ? 0 : breakpoint->number); return ERROR_OK; } @@ -1355,22 +1862,22 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; - if (!breakpoint->set) { - LOG_WARNING("breakpoint not set"); + if (!breakpoint->is_set) { + LOG_TARGET_WARNING(target, "breakpoint not set"); return ERROR_OK; } - LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", + LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (n=%u)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, breakpoint->length, - breakpoint->set); + (breakpoint->type == BKPT_SOFT) ? 0 : breakpoint->number); if (breakpoint->type == BKPT_HARD) { - int fp_num = breakpoint->set - 1; - if ((fp_num < 0) || (fp_num >= cortex_m->fp_num_code)) { - LOG_DEBUG("Invalid FP Comparator number in breakpoint"); + unsigned int fp_num = breakpoint->number; + if (fp_num >= cortex_m->fp_num_code) { + LOG_TARGET_DEBUG(target, "Invalid FP Comparator number in breakpoint"); return ERROR_OK; } comparator_list[fp_num].used = false; @@ -1385,7 +1892,7 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi if (retval != ERROR_OK) return retval; } - breakpoint->set = false; + breakpoint->is_set = false; return ERROR_OK; } @@ -1393,12 +1900,12 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (breakpoint->length == 3) { - LOG_DEBUG("Using a two byte breakpoint for 32bit Thumb-2 request"); + LOG_TARGET_DEBUG(target, "Using a two byte breakpoint for 32bit Thumb-2 request"); breakpoint->length = 2; } if ((breakpoint->length != 2)) { - LOG_INFO("only breakpoints of two bytes length supported"); + LOG_TARGET_INFO(target, "only breakpoints of two bytes length supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1407,15 +1914,15 @@ int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { - if (!breakpoint->set) + if (!breakpoint->is_set) return ERROR_OK; return cortex_m_unset_breakpoint(target, breakpoint); } -int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint) +static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { - int dwt_num = 0; + unsigned int dwt_num = 0; struct cortex_m_common *cortex_m = target_to_cm(target); /* REVISIT Don't fully trust these "not used" records ... users @@ -1430,17 +1937,18 @@ int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint comparator++, dwt_num++) continue; if (dwt_num >= cortex_m->dwt_num_comp) { - LOG_ERROR("Can not find free DWT Comparator"); + LOG_TARGET_ERROR(target, "Can not find free DWT Comparator"); return ERROR_FAIL; } comparator->used = true; - watchpoint->set = dwt_num + 1; + watchpoint_set(watchpoint, dwt_num); comparator->comp = watchpoint->address; 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 */ @@ -1488,7 +1996,7 @@ int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); - LOG_DEBUG("Watchpoint (ID %d) DWT%d 0x%08x 0x%x 0x%05x", + LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%d 0x%08x 0x%x 0x%05x", watchpoint->unique_id, dwt_num, (unsigned) comparator->comp, (unsigned) comparator->mask, @@ -1496,26 +2004,25 @@ int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint return ERROR_OK; } -int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) +static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_dwt_comparator *comparator; - int dwt_num; - if (!watchpoint->set) { - LOG_WARNING("watchpoint (wpid: %d) not set", + if (!watchpoint->is_set) { + LOG_TARGET_WARNING(target, "watchpoint (wpid: %d) not set", watchpoint->unique_id); return ERROR_OK; } - dwt_num = watchpoint->set - 1; + unsigned int dwt_num = watchpoint->number; - LOG_DEBUG("Watchpoint (ID %d) DWT%d address: 0x%08x clear", + LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%u address: 0x%08x clear", watchpoint->unique_id, dwt_num, (unsigned) watchpoint->address); - if ((dwt_num < 0) || (dwt_num >= cortex_m->dwt_num_comp)) { - LOG_DEBUG("Invalid DWT Comparator number in watchpoint"); + if (dwt_num >= cortex_m->dwt_num_comp) { + LOG_TARGET_DEBUG(target, "Invalid DWT Comparator number in watchpoint"); return ERROR_OK; } @@ -1525,7 +2032,7 @@ int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *watchpoi target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); - watchpoint->set = false; + watchpoint->is_set = false; return ERROR_OK; } @@ -1535,13 +2042,19 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint struct cortex_m_common *cortex_m = target_to_cm(target); if (cortex_m->dwt_comp_available < 1) { - LOG_DEBUG("no comparators?"); + LOG_TARGET_DEBUG(target, "no comparators?"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - /* hardware doesn't support data value masking */ - if (watchpoint->mask != ~(uint32_t)0) { - LOG_DEBUG("watchpoint value masks not supported"); + /* 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; } @@ -1553,28 +2066,16 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint break; } if (mask == 16) { - LOG_DEBUG("unsupported watchpoint length"); + LOG_TARGET_DEBUG(target, "unsupported watchpoint length"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->address & ((1 << mask) - 1)) { - LOG_DEBUG("watchpoint address is unaligned"); - 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_DEBUG("data value watchpoint not YET supported"); + LOG_TARGET_DEBUG(target, "watchpoint address is unaligned"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } cortex_m->dwt_comp_available--; - LOG_DEBUG("dwt_comp_available: %d", cortex_m->dwt_comp_available); + LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available); return ERROR_OK; } @@ -1585,199 +2086,58 @@ 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_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) cortex_m_unset_watchpoint(target, watchpoint); cortex_m->dwt_comp_available++; - LOG_DEBUG("dwt_comp_available: %d", cortex_m->dwt_comp_available); + LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available); return ERROR_OK; } -void cortex_m_enable_watchpoints(struct target *target) -{ - struct watchpoint *watchpoint = target->watchpoints; - - /* set any pending watchpoints */ - while (watchpoint) { - if (!watchpoint->set) - cortex_m_set_watchpoint(target, watchpoint); - watchpoint = watchpoint->next; - } -} - -static int cortex_m_load_core_reg_u32(struct target *target, - uint32_t num, uint32_t *value) +static int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { - int retval; - - /* NOTE: we "know" here that the register identifiers used - * in the v7m header match the Cortex-M3 Debug Core Register - * Selector values for R0..R15, xPSR, MSP, and PSP. - */ - switch (num) { - case 0 ... 18: - /* read a normal core register */ - retval = cortexm_dap_read_coreregister_u32(target, value, num); - - if (retval != ERROR_OK) { - LOG_ERROR("JTAG failure %i", retval); - return ERROR_JTAG_DEVICE_ERROR; - } - LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value); - break; - - case ARMV7M_FPSCR: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, DCB_DCRSR, 0x21); - if (retval != ERROR_OK) - return retval; - retval = target_read_u32(target, DCB_DCRDR, value); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("load from FPSCR value 0x%" PRIx32, *value); - break; - - case ARMV7M_S0 ... ARMV7M_S31: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, DCB_DCRSR, num - ARMV7M_S0 + 0x40); - if (retval != ERROR_OK) - return retval; - retval = target_read_u32(target, DCB_DCRDR, value); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("load from FPU reg S%d value 0x%" PRIx32, - (int)(num - ARMV7M_S0), *value); - break; - - case ARMV7M_PRIMASK: - case ARMV7M_BASEPRI: - case ARMV7M_FAULTMASK: - case ARMV7M_CONTROL: - /* Cortex-M3 packages these four registers as bitfields - * in one Debug Core register. So say r0 and r2 docs; - * it was removed from r1 docs, but still works. - */ - cortexm_dap_read_coreregister_u32(target, value, 20); - - switch (num) { - case ARMV7M_PRIMASK: - *value = buf_get_u32((uint8_t *)value, 0, 1); - break; + if (target->debug_reason != DBG_REASON_WATCHPOINT) + return ERROR_FAIL; - case ARMV7M_BASEPRI: - *value = buf_get_u32((uint8_t *)value, 8, 8); - break; + struct cortex_m_common *cortex_m = target_to_cm(target); - case ARMV7M_FAULTMASK: - *value = buf_get_u32((uint8_t *)value, 16, 1); - break; + for (struct watchpoint *wp = target->watchpoints; wp; wp = wp->next) { + if (!wp->is_set) + continue; - case ARMV7M_CONTROL: - *value = buf_get_u32((uint8_t *)value, 24, 2); - break; - } + unsigned int dwt_num = wp->number; + struct cortex_m_dwt_comparator *comparator = cortex_m->dwt_comparator_list + dwt_num; - LOG_DEBUG("load from special reg %i value 0x%" PRIx32 "", (int)num, *value); - break; + uint32_t dwt_function; + int retval = target_read_u32(target, comparator->dwt_comparator_address + 8, &dwt_function); + if (retval != ERROR_OK) + return ERROR_FAIL; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + /* check the MATCHED bit */ + if (dwt_function & BIT(24)) { + *hit_watchpoint = wp; + return ERROR_OK; + } } - return ERROR_OK; + return ERROR_FAIL; } -static int cortex_m_store_core_reg_u32(struct target *target, - uint32_t num, uint32_t value) +void cortex_m_enable_watchpoints(struct target *target) { - int retval; - uint32_t reg; - struct armv7m_common *armv7m = target_to_armv7m(target); - - /* NOTE: we "know" here that the register identifiers used - * in the v7m header match the Cortex-M3 Debug Core Register - * Selector values for R0..R15, xPSR, MSP, and PSP. - */ - switch (num) { - case 0 ... 18: - retval = cortexm_dap_write_coreregister_u32(target, value, num); - if (retval != ERROR_OK) { - struct reg *r; - - LOG_ERROR("JTAG failure"); - r = armv7m->arm.core_cache->reg_list + num; - r->dirty = r->valid; - return ERROR_JTAG_DEVICE_ERROR; - } - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value); - break; - - case ARMV7M_FPSCR: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, DCB_DCRDR, value); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, DCB_DCRSR, 0x21 | (1<<16)); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("write FPSCR value 0x%" PRIx32, value); - break; - - case ARMV7M_S0 ... ARMV7M_S31: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, DCB_DCRDR, value); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, DCB_DCRSR, (num - ARMV7M_S0 + 0x40) | (1<<16)); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("write FPU reg S%d value 0x%" PRIx32, - (int)(num - ARMV7M_S0), value); - break; - - case ARMV7M_PRIMASK: - case ARMV7M_BASEPRI: - case ARMV7M_FAULTMASK: - case ARMV7M_CONTROL: - /* Cortex-M3 packages these four registers as bitfields - * in one Debug Core register. So say r0 and r2 docs; - * it was removed from r1 docs, but still works. - */ - cortexm_dap_read_coreregister_u32(target, ®, 20); - - switch (num) { - case ARMV7M_PRIMASK: - buf_set_u32((uint8_t *)®, 0, 1, value); - break; - - case ARMV7M_BASEPRI: - buf_set_u32((uint8_t *)®, 8, 8, value); - break; - - case ARMV7M_FAULTMASK: - buf_set_u32((uint8_t *)®, 16, 1, value); - break; - - case ARMV7M_CONTROL: - buf_set_u32((uint8_t *)®, 24, 2, value); - break; - } - - cortexm_dap_write_coreregister_u32(target, reg, 20); - - LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value); - break; + struct watchpoint *watchpoint = target->watchpoints; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + /* set any pending watchpoints */ + while (watchpoint) { + if (!watchpoint->is_set) + cortex_m_set_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; } - - return ERROR_OK; } static int cortex_m_read_memory(struct target *target, target_addr_t address, @@ -1785,7 +2145,7 @@ static int cortex_m_read_memory(struct target *target, target_addr_t address, { struct armv7m_common *armv7m = target_to_armv7m(target); - if (armv7m->arm.is_armv6m) { + if (armv7m->arm.arch == ARM_ARCH_V6M) { /* armv6m does not handle unaligned memory access */ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; @@ -1799,7 +2159,7 @@ static int cortex_m_write_memory(struct target *target, target_addr_t address, { struct armv7m_common *armv7m = target_to_armv7m(target); - if (armv7m->arm.is_armv6m) { + if (armv7m->arm.arch == ARM_ARCH_V6M) { /* armv6m does not handle unaligned memory access */ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; @@ -1819,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); @@ -1835,82 +2199,58 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, struct timeval timeout, now; struct armv7m_common *armv7m = target_to_armv7m(target); uint32_t reg_value; - bool use_pcsr = false; - int retval = ERROR_OK; - struct reg *reg; - - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, seconds, 0); + int retval; retval = target_read_u32(target, DWT_PCSR, ®_value); if (retval != ERROR_OK) { - LOG_ERROR("Error while reading PCSR"); + LOG_TARGET_ERROR(target, "Error while reading PCSR"); return retval; } - - if (reg_value != 0) { - use_pcsr = true; - LOG_INFO("Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can..."); - } else { - LOG_INFO("Starting profiling. Halting and resuming the" - " target as often as we can..."); - reg = register_get_by_name(target->reg_cache, "pc", 1); + if (reg_value == 0) { + LOG_TARGET_INFO(target, "PCSR sampling not supported on this processor."); + return target_profiling_default(target, samples, max_num_samples, num_samples, seconds); } + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, seconds, 0); + + LOG_TARGET_INFO(target, "Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can..."); + /* Make sure the target is running */ target_poll(target); if (target->state == TARGET_HALTED) retval = target_resume(target, 1, 0, 0, 0); if (retval != ERROR_OK) { - LOG_ERROR("Error while resuming target"); + LOG_TARGET_ERROR(target, "Error while resuming target"); return retval; } uint32_t sample_count = 0; for (;;) { - if (use_pcsr) { - if (armv7m && armv7m->debug_ap) { - uint32_t read_count = max_num_samples - sample_count; - if (read_count > 1024) - read_count = 1024; - - retval = mem_ap_read_buf_noincr(armv7m->debug_ap, - (void *)&samples[sample_count], - 4, read_count, DWT_PCSR); - sample_count += read_count; - } else { - target_read_u32(target, DWT_PCSR, &samples[sample_count++]); - } + if (armv7m && armv7m->debug_ap) { + uint32_t read_count = max_num_samples - sample_count; + if (read_count > 1024) + read_count = 1024; + + retval = mem_ap_read_buf_noincr(armv7m->debug_ap, + (void *)&samples[sample_count], + 4, read_count, DWT_PCSR); + sample_count += read_count; } else { - target_poll(target); - if (target->state == TARGET_HALTED) { - reg_value = buf_get_u32(reg->value, 0, 32); - /* current pc, addr = 0, do not handle breakpoints, not debugging */ - retval = target_resume(target, 1, 0, 0, 0); - samples[sample_count++] = reg_value; - target_poll(target); - alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */ - } else if (target->state == TARGET_RUNNING) { - /* We want to quickly sample the PC. */ - retval = target_halt(target); - } else { - LOG_INFO("Target not halted or running"); - retval = ERROR_OK; - break; - } + target_read_u32(target, DWT_PCSR, &samples[sample_count++]); } if (retval != ERROR_OK) { - LOG_ERROR("Error while reading %s", use_pcsr ? "PCSR" : "target pc"); + LOG_TARGET_ERROR(target, "Error while reading PCSR"); return retval; } gettimeofday(&now, NULL); if (sample_count >= max_num_samples || timeval_compare(&now, &timeout) > 0) { - LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); + LOG_TARGET_INFO(target, "Profiling completed. %" PRIu32 " samples.", sample_count); break; } } @@ -2013,22 +2353,22 @@ static void cortex_m_dwt_addreg(struct target *t, struct reg *r, const struct dw r->type = &dwt_reg_type; } -void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target) +static void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target) { uint32_t dwtcr; struct reg_cache *cache; struct cortex_m_dwt_comparator *comparator; - int reg, i; + int reg; target_read_u32(target, DWT_CTRL, &dwtcr); - LOG_DEBUG("DWT_CTRL: 0x%" PRIx32, dwtcr); + LOG_TARGET_DEBUG(target, "DWT_CTRL: 0x%" PRIx32, dwtcr); if (!dwtcr) { - LOG_DEBUG("no DWT"); + LOG_TARGET_DEBUG(target, "no DWT"); return; } target_read_u32(target, DWT_DEVARCH, &cm->dwt_devarch); - LOG_DEBUG("DWT_DEVARCH: 0x%" PRIx32, cm->dwt_devarch); + LOG_TARGET_DEBUG(target, "DWT_DEVARCH: 0x%" PRIx32, cm->dwt_devarch); cm->dwt_num_comp = (dwtcr >> 28) & 0xF; cm->dwt_comp_available = cm->dwt_num_comp; @@ -2037,7 +2377,7 @@ void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target) if (!cm->dwt_comparator_list) { fail0: cm->dwt_num_comp = 0; - LOG_ERROR("out of mem"); + LOG_TARGET_ERROR(target, "out of mem"); return; } @@ -2060,7 +2400,7 @@ fail1: dwt_base_regs + reg); comparator = cm->dwt_comparator_list; - for (i = 0; i < cm->dwt_num_comp; i++, comparator++) { + for (unsigned int i = 0; i < cm->dwt_num_comp; i++, comparator++) { int j; comparator->dwt_comparator_address = DWT_COMP0 + 0x10 * i; @@ -2075,7 +2415,7 @@ fail1: *register_get_last_cache_p(&target->reg_cache) = cache; cm->dwt_cache = cache; - LOG_DEBUG("DWT dwtcr 0x%" PRIx32 ", comp %d, watch%s", + LOG_TARGET_DEBUG(target, "DWT dwtcr 0x%" PRIx32 ", comp %d, watch%s", dwtcr, cm->dwt_num_comp, (dwtcr & (0xf << 24)) ? " only" : "/trigger"); @@ -2107,50 +2447,71 @@ 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; -#define MVFR0_DEFAULT_M4 0x10110021 -#define MVFR1_DEFAULT_M4 0x11000011 + if (armv7m->arm.arch != ARM_ARCH_V8M) + return false; -#define MVFR0_DEFAULT_M7_SP 0x10110021 -#define MVFR0_DEFAULT_M7_DP 0x10110221 -#define MVFR1_DEFAULT_M7_SP 0x11000011 -#define MVFR1_DEFAULT_M7_DP 0x12000011 + 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 0xE000EF40 +#define MVFR0_SP_MASK 0x000000F0 +#define MVFR0_SP 0x00000020 +#define MVFR0_DP_MASK 0x00000F00 +#define MVFR0_DP 0x00000200 + +#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; - int i; + 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); - /* stlink shares the examine handler but does not support + /* hla_target shares the examine handler but does not support * all its calls */ - if (!armv7m->stlink) { - 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_ERROR("Could not find MEM-AP to control the core"); - return retval; + if (!armv7m->is_hla_target) { + 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); } - /* Leave (only) generic DAP stuff for debugport_init(); */ armv7m->debug_ap->memaccess_tck = 8; retval = mem_ap_init(armv7m->debug_ap); @@ -2166,100 +2527,115 @@ int cortex_m_examine(struct target *target) if (retval != ERROR_OK) return retval; - /* Get CPU Type */ - i = (cpuid >> 4) & 0xf; - - /* Check if it is an ARMv8-M core */ - armv7m->arm.is_armv8m = true; + /* Inspect implementor/part to look for recognized cores */ + unsigned int impl_part = cpuid & (ARM_CPUID_IMPLEMENTOR_MASK | ARM_CPUID_PARTNO_MASK); - switch (cpuid & ARM_CPUID_PARTNO_MASK) { - case CORTEX_M23_PARTNO: - i = 23; - break; - - case CORTEX_M33_PARTNO: - i = 33; + for (unsigned int n = 0; n < ARRAY_SIZE(cortex_m_parts); n++) { + if (impl_part == cortex_m_parts[n].impl_part) { + cortex_m->core_info = &cortex_m_parts[n]; break; + } + } - default: - armv7m->arm.is_armv8m = false; - break; + if (!cortex_m->core_info) { + LOG_TARGET_ERROR(target, "Cortex-M CPUID: 0x%x is unrecognized", cpuid); + return ERROR_FAIL; } + armv7m->arm.arch = cortex_m->core_info->arch; + + LOG_TARGET_INFO(target, "%s r%" PRId8 "p%" PRId8 " processor detected", + cortex_m->core_info->name, + (uint8_t)((cpuid >> 20) & 0xf), + (uint8_t)((cpuid >> 0) & 0xf)); - LOG_DEBUG("Cortex-M%d r%" PRId8 "p%" PRId8 " processor detected", - i, (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf)); cortex_m->maskints_erratum = false; - if (i == 7) { + if (impl_part == CORTEX_M7_PARTNO) { uint8_t rev, patch; rev = (cpuid >> 20) & 0xf; patch = (cpuid >> 0) & 0xf; if ((rev == 0) && (patch < 2)) { - LOG_WARNING("Silicon bug: single stepping may enter pending exception handler!"); + LOG_TARGET_WARNING(target, "Silicon bug: single stepping may enter pending exception handler!"); cortex_m->maskints_erratum = true; } } - LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid); + LOG_TARGET_DEBUG(target, "cpuid: 0x%8.8" PRIx32 "", cpuid); - /* VECTRESET is not supported on Cortex-M0, M0+ and M1 */ - cortex_m->vectreset_supported = i > 1; - - if (i == 4) { + 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_DEBUG("Cortex-M%d floating point feature FPv4_SP found", i); - armv7m->fp_feature = FPv4_SP; + 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 (i == 7 || i == 33) { + } 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_DEBUG("Cortex-M%d floating point feature FPv5_SP found", i); - armv7m->fp_feature = FPv5_SP; - } else if ((mvfr0 == MVFR0_DEFAULT_M7_DP) && (mvfr1 == MVFR1_DEFAULT_M7_DP)) { - LOG_DEBUG("Cortex-M%d floating point feature FPv5_DP found", i); - armv7m->fp_feature = FPv5_DP; + 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 ((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; } - } else if (i == 0) { - /* Cortex-M0 does not support unaligned memory access */ - armv7m->arm.is_armv6m = true; } - if (armv7m->fp_feature == FP_NONE && - armv7m->arm.core_cache->num_regs > ARMV7M_NUM_CORE_REGS_NOFP) { - /* free unavailable FPU registers */ - size_t idx; - - for (idx = ARMV7M_NUM_CORE_REGS_NOFP; - idx < armv7m->arm.core_cache->num_regs; - idx++) { - free(armv7m->arm.core_cache->reg_list[idx].value); - free(armv7m->arm.core_cache->reg_list[idx].feature); - free(armv7m->arm.core_cache->reg_list[idx].reg_data_type); - } - armv7m->arm.core_cache->num_regs = ARMV7M_NUM_CORE_REGS_NOFP; - } + /* VECTRESET is supported only on ARMv7-M cores */ + cortex_m->vectreset_supported = armv7m->arm.arch == ARM_ARCH_V7M; + + /* Check for FPU, otherwise mark FPU register as non-existent */ + if (armv7m->fp_feature == FP_NONE) + for (size_t idx = ARMV7M_FPU_FIRST_REG; idx <= ARMV7M_FPU_LAST_REG; idx++) + armv7m->arm.core_cache->reg_list[idx].exist = false; + + 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; - if (!armv7m->stlink) { - if (i == 3 || i == 4) + if (!armv7m->is_hla_target) { + if (cortex_m->core_info->flags & CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K) /* Cortex-M3/M4 have 4096 bytes autoincrement range, * s. ARM IHI 0031C: MEM-AP 7.2.2 */ armv7m->debug_ap->tar_autoincr_block = (1 << 12); - else if (i == 7) - /* Cortex-M7 has only 1024 bytes autoincrement range */ - armv7m->debug_ap->tar_autoincr_block = (1 << 10); } - /* Enable debug requests */ 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)) { + /* Enable debug requests */ uint32_t dhcsr = (cortex_m->dcb_dhcsr | C_DEBUGEN) & ~(C_HALT | C_STEP | C_MASKINTS); retval = target_write_u32(target, DCB_DHCSR, DBGKEY | (dhcsr & 0x0000FFFFUL)); @@ -2273,10 +2649,8 @@ int cortex_m_examine(struct target *target) if (retval != ERROR_OK) return retval; - if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_DISABLED) { - armv7m_trace_tpiu_config(target); + if (armv7m->trace_config.itm_deferred_config) armv7m_trace_itm_config(target); - } /* NOTE: FPB and DWT are both optional. */ @@ -2293,7 +2667,7 @@ int cortex_m_examine(struct target *target) cortex_m->fp_num_code + cortex_m->fp_num_lit, sizeof(struct cortex_m_fp_comparator)); cortex_m->fpb_enabled = fpcr & 1; - for (i = 0; i < cortex_m->fp_num_code + cortex_m->fp_num_lit; i++) { + for (unsigned int i = 0; i < cortex_m->fp_num_code + cortex_m->fp_num_lit; i++) { cortex_m->fp_comparator_list[i].type = (i < cortex_m->fp_num_code) ? FPCR_CODE : FPCR_LITERAL; cortex_m->fp_comparator_list[i].fpcr_address = FP_COMP0 + 4 * i; @@ -2301,7 +2675,7 @@ int cortex_m_examine(struct target *target) /* make sure we clear any breakpoints enabled on the target */ target_write_u32(target, cortex_m->fp_comparator_list[i].fpcr_address, 0); } - LOG_DEBUG("FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", + LOG_TARGET_DEBUG(target, "FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", fpcr, cortex_m->fp_num_code, cortex_m->fp_num_lit); @@ -2311,8 +2685,7 @@ int cortex_m_examine(struct target *target) cortex_m_dwt_setup(cortex_m, target); /* These hardware breakpoints only work for code in flash! */ - LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", - target_name(target), + LOG_TARGET_INFO(target, "target has %d breakpoints, %d watchpoints", cortex_m->fp_num_code, cortex_m->dwt_num_comp); } @@ -2335,7 +2708,7 @@ static int cortex_m_dcc_read(struct target *target, uint8_t *value, uint8_t *ctr *ctrl = (uint8_t)dcrdr; *value = (uint8_t)(dcrdr >> 8); - LOG_DEBUG("data 0x%x ctrl 0x%x", *value, *ctrl); + LOG_TARGET_DEBUG(target, "data 0x%x ctrl 0x%x", *value, *ctrl); /* write ack back to software dcc register * signify we have read data */ @@ -2411,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; @@ -2441,8 +2814,8 @@ static int cortex_m_target_create(struct target *target, Jim_Interp *interp) return ERROR_FAIL; struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common)); - if (cortex_m == NULL) { - LOG_ERROR("No memory creating target"); + if (!cortex_m) { + LOG_TARGET_ERROR(target, "No memory creating target"); return ERROR_FAIL; } @@ -2459,7 +2832,7 @@ static int cortex_m_target_create(struct target *target, Jim_Interp *interp) static int cortex_m_verify_pointer(struct command_invocation *cmd, struct cortex_m_common *cm) { - if (cm->common_magic != CORTEX_M_COMMON_MAGIC) { + if (!is_cortex_m_with_dap_access(cm)) { command_print(cmd, "target is not a Cortex-M"); return ERROR_TARGET_INVALID; } @@ -2468,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) @@ -2498,6 +2870,11 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) if (retval != ERROR_OK) return retval; + if (!target_was_examined(target)) { + LOG_TARGET_ERROR(target, "Target not examined yet"); + return ERROR_FAIL; + } + retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DEMCR, &demcr); if (retval != ERROR_OK) return retval; @@ -2523,7 +2900,7 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) break; } if (i == ARRAY_SIZE(vec_ids)) { - LOG_ERROR("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; } } @@ -2562,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 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 Jim_Nvp *n; + const struct nvp *n; retval = cortex_m_verify_pointer(CMD, cortex_m); @@ -2577,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]); - if (n->name == NULL) + 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; @@ -2613,7 +2990,7 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command) else if (strcmp(*CMD_ARGV, "vectreset") == 0) { if (target_was_examined(target) && !cortex_m->vectreset_supported) - LOG_WARNING("VECTRESET is not supported on your Cortex-M core!"); + LOG_TARGET_WARNING(target, "VECTRESET is not supported on your Cortex-M core!"); else cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; @@ -2662,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[] = { @@ -2671,6 +3051,11 @@ static const struct command_registration cortex_m_command_handlers[] = { { .chain = armv7m_trace_command_handlers, }, + /* START_DEPRECATED_TPIU */ + { + .chain = arm_tpiu_deprecated_command_handlers, + }, + /* END_DEPRECATED_TPIU */ { .name = "cortex_m", .mode = COMMAND_EXEC, @@ -2678,12 +3063,14 @@ static const struct command_registration cortex_m_command_handlers[] = { .usage = "", .chain = cortex_m_exec_command_handlers, }, + { + .chain = rtt_target_command_handlers, + }, COMMAND_REGISTRATION_DONE }; struct target_type cortexm_target = { .name = "cortex_m", - .deprecated_name = "cortex_m3", .poll = cortex_m_poll, .arch_state = armv7m_arch_state, @@ -2714,6 +3101,7 @@ struct target_type cortexm_target = { .remove_breakpoint = cortex_m_remove_breakpoint, .add_watchpoint = cortex_m_add_watchpoint, .remove_watchpoint = cortex_m_remove_watchpoint, + .hit_watchpoint = cortex_m_hit_watchpoint, .commands = cortex_m_command_handlers, .target_create = cortex_m_target_create, diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 354532823d..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,22 +17,62 @@ #include "armv7m.h" #include "helper/bits.h" -#define CORTEX_M_COMMON_MAGIC 0x1A451A45 +#define CORTEX_M_COMMON_MAGIC 0x1A451A45U #define SYSTEM_CONTROL_BASE 0x400FE000 #define ITM_TER0 0xE0000E00 #define ITM_TPR 0xE0000E40 #define ITM_TCR 0xE0000E80 +#define ITM_TCR_ITMENA_BIT BIT(0) +#define ITM_TCR_BUSY_BIT BIT(23) #define ITM_LAR 0xE0000FB0 #define ITM_LAR_KEY 0xC5ACCE55 #define CPUID 0xE000ED00 -#define ARM_CPUID_PARTNO_MASK 0xFFF0 +#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)) + +/** 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, + 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 */ +#define CORTEX_M_F_HAS_FPV4 BIT(0) +#define CORTEX_M_F_HAS_FPV5 BIT(1) +#define CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K BIT(2) -#define CORTEX_M23_PARTNO 0xD200 -#define CORTEX_M33_PARTNO 0xD210 +struct cortex_m_part_info { + enum cortex_m_impl_part impl_part; + const char *name; + enum arm_arch arch; + uint32_t flags; +}; /* Debug Control Block */ #define DCB_DHCSR 0xE000EDF0 @@ -52,7 +81,10 @@ #define DCB_DEMCR 0xE000EDFC #define DCB_DSCSR 0xE000EE08 -#define DCRSR_WnR BIT(16) +#define DAUTHSTATUS 0xE000EFB8 +#define DAUTHSTATUS_SID_MASK 0x00000030 + +#define DCRSR_WNR BIT(16) #define DWT_CTRL 0xE0001000 #define DWT_CYCCNT 0xE0001004 @@ -62,7 +94,8 @@ #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 @@ -125,9 +158,9 @@ #define NVIC_AIRCR 0xE000ED0C #define NVIC_SHCSR 0xE000ED24 #define NVIC_CFSR 0xE000ED28 -#define NVIC_MMFSRb 0xE000ED28 -#define NVIC_BFSRb 0xE000ED29 -#define NVIC_USFSRh 0xE000ED2A +#define NVIC_MMFSRB 0xE000ED28 +#define NVIC_BFSRB 0xE000ED29 +#define NVIC_USFSRH 0xE000ED2A #define NVIC_HFSR 0xE000ED2C #define NVIC_DFSR 0xE000ED30 #define NVIC_MMFAR 0xE000ED34 @@ -184,46 +217,109 @@ 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 */ /* Flash Patch and Breakpoint (FPB) */ - int fp_num_lit; - int fp_num_code; + unsigned int fp_num_lit; + unsigned int fp_num_code; int fp_rev; bool fpb_enabled; struct cortex_m_fp_comparator *fp_comparator_list; /* Data Watchpoint and Trace (DWT) */ - int dwt_num_comp; - int dwt_comp_available; + unsigned int dwt_num_comp; + unsigned int dwt_comp_available; uint32_t dwt_devarch; struct cortex_m_dwt_comparator *dwt_comparator_list; struct reg_cache *dwt_cache; enum cortex_m_soft_reset_config soft_reset_config; bool vectreset_supported; - enum cortex_m_isrmasking_mode isrmasking_mode; - struct armv7m_common armv7m; + const struct cortex_m_part_info *core_info; - int apsel; + bool slow_register_read; /* A register has not been ready, poll S_REGRDY */ + + uint64_t apsel; /* Whether this target has the erratum that makes C_MASKINTS not apply to * already pending interrupts */ bool maskints_erratum; }; +static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m) +{ + return cortex_m->common_magic == CORTEX_M_COMMON_MAGIC; +} + +static inline bool is_cortex_m_with_dap_access(const struct cortex_m_common *cortex_m) +{ + if (!is_cortex_m_or_hla(cortex_m)) + return false; + + return !cortex_m->armv7m.is_hla_target; +} + +/** + * @returns the pointer to the target specific struct + * without matching a magic number. + * Use in target specific service routines, where the correct + * type of arch_info is certain. + */ static inline struct cortex_m_common * target_to_cm(struct target *target) { return container_of(target->arch_info, - struct cortex_m_common, armv7m); + struct cortex_m_common, armv7m.arm); +} + +/** + * @returns the pointer to the target specific struct + * or NULL if the magic number does not match. + * Use in a flash driver or any place where mismatch of the arch_info + * type can happen. + */ +static inline struct cortex_m_common * +target_to_cortex_m_safe(struct target *target) +{ + /* Check the parent types first to prevent peeking memory too far + * from arch_info pointer */ + if (!target_to_armv7m_safe(target)) + return NULL; + + struct cortex_m_common *cortex_m = target_to_cm(target); + if (!is_cortex_m_or_hla(cortex_m)) + return NULL; + + return cortex_m; +} + +/** + * @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_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) + return CORTEX_M_PARTNO_INVALID; + + if (!cortex_m->core_info) + return CORTEX_M_PARTNO_INVALID; + + return cortex_m->core_info->impl_part; } int cortex_m_examine(struct target *target); @@ -231,13 +327,10 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpoint); -int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint); -int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *watchpoint); int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint); int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); void cortex_m_enable_breakpoints(struct target *target); void cortex_m_enable_watchpoints(struct target *target); -void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target); void cortex_m_deinit_target(struct target *target); int cortex_m_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index b825429e0b..80cca1ed50 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 @@ -96,10 +85,10 @@ /* * OBCR Register bit definitions */ -#define OBCR_b0_and_b1 ((0x0) << 10) -#define OBCR_b0_or_b1 ((0x1) << 10) -#define OBCR_b1_after_b0 ((0x2) << 10) -#define OBCR_b0_after_b1 ((0x3) << 10) +#define OBCR_B0_AND_B1 ((0x0) << 10) +#define OBCR_B0_OR_B1 ((0x1) << 10) +#define OBCR_B1_AFTER_B0 ((0x2) << 10) +#define OBCR_B0_AFTER_B1 ((0x3) << 10) #define OBCR_BP_DISABLED (0x0) #define OBCR_BP_MEM_P (0x1) @@ -913,7 +902,7 @@ static int dsp563xx_init_target(struct command_context *cmd_ctx, struct target * dsp563xx_build_reg_cache(target); struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); - dsp563xx->hardware_breakpoints_cleared = 0; + dsp563xx->hardware_breakpoints_cleared = false; dsp563xx->hardware_breakpoint[0].used = BPU_NONE; return ERROR_OK; @@ -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; } @@ -1085,9 +1074,18 @@ static int dsp563xx_poll(struct target *target) if (!dsp563xx->hardware_breakpoints_cleared) { err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OBCR, 0); + if (err != ERROR_OK) + return err; + err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OMLR0, 0); + if (err != ERROR_OK) + return err; + err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OMLR1, 0); - dsp563xx->hardware_breakpoints_cleared = 1; + if (err != ERROR_OK) + return err; + + dsp563xx->hardware_breakpoints_cleared = true; } return ERROR_OK; @@ -1298,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; } @@ -1376,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; } @@ -1402,7 +1400,7 @@ static int dsp563xx_run_algorithm(struct target *target, struct reg *reg = register_get_by_name(dsp563xx->core_cache, reg_params[i].reg_name, - 0); + false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); @@ -1444,7 +1442,7 @@ static int dsp563xx_run_algorithm(struct target *target, struct reg *reg = register_get_by_name(dsp563xx->core_cache, reg_params[i].reg_name, - 0); + false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); continue; @@ -1707,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; } @@ -1876,17 +1874,17 @@ static int dsp563xx_remove_watchpoint(struct target *target, struct watchpoint * return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } -static int dsp563xx_add_custom_watchpoint(struct target *target, uint32_t address, uint32_t memType, +static int dsp563xx_add_custom_watchpoint(struct target *target, uint32_t address, uint32_t mem_type, enum watchpoint_rw rw, enum watchpoint_condition cond) { int err = ERROR_OK; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); - bool wasRunning = false; + bool was_running = false; /* Only set breakpoint when halted */ if (target->state != TARGET_HALTED) { dsp563xx_halt(target); - wasRunning = true; + was_running = true; } if (dsp563xx->hardware_breakpoint[0].used) { @@ -1896,8 +1894,8 @@ static int dsp563xx_add_custom_watchpoint(struct target *target, uint32_t addres uint32_t obcr_value = 0; if (err == ERROR_OK) { - obcr_value |= OBCR_b0_or_b1; - switch (memType) { + obcr_value |= OBCR_B0_OR_B1; + switch (mem_type) { case MEM_X: obcr_value |= OBCR_BP_MEM_X; break; @@ -1908,7 +1906,7 @@ static int dsp563xx_add_custom_watchpoint(struct target *target, uint32_t addres obcr_value |= OBCR_BP_MEM_P; break; default: - LOG_ERROR("Unknown memType parameter (%" PRIu32 ")", memType); + LOG_ERROR("Unknown mem_type parameter (%" PRIu32 ")", mem_type); err = ERROR_TARGET_INVALID; } } @@ -1972,7 +1970,7 @@ static int dsp563xx_add_custom_watchpoint(struct target *target, uint32_t addres if (err == ERROR_OK) dsp563xx->hardware_breakpoint[0].used = BPU_WATCHPOINT; - if (err == ERROR_OK && wasRunning) { + if (err == ERROR_OK && was_running) { /* Resume from current PC */ err = dsp563xx_resume(target, 1, 0x0, 0, 0); } @@ -2142,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), @@ -2243,7 +2241,7 @@ static const struct command_registration dsp563xx_command_handlers[] = { .handler = dsp563xx_remove_watchpoint_command, .mode = COMMAND_EXEC, .help = "remove watchpoint custom", - .usage = " ", + .usage = "", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/dsp563xx.h b/src/target/dsp563xx.h index 18428b8547..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 @@ -52,7 +41,7 @@ struct dsp563xx_common { struct hardware_breakpoint hardware_breakpoint[1]; /*Were the hardware breakpoints cleared on startup?*/ - int hardware_breakpoints_cleared; + bool hardware_breakpoints_cleared; }; struct dsp563xx_core_reg { 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 d6107abc6f..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; } @@ -40,7 +29,7 @@ struct dsp5680xx_common dsp5680xx_context; #define CHECK_HALT(target) if (target->state != TARGET_HALTED) HALT_FAIL #define check_halt_and_debug(target) { CHECK_HALT(target); CHECK_DBG; } -int dsp5680xx_execute_queue(void) +static int dsp5680xx_execute_queue(void) { int retval; @@ -85,7 +74,7 @@ static int dsp5680xx_drscan(struct target *target, uint8_t *d_in, */ int retval = ERROR_OK; - if (NULL == target->tap) { + if (!target->tap) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_INVALID_TAP, "Invalid tap"); @@ -104,7 +93,7 @@ static int dsp5680xx_drscan(struct target *target, uint8_t *d_in, err_check(retval, DSP5680XX_ERROR_JTAG_DRSCAN, "drscan failed!"); } - if (d_out != NULL) + if (d_out) LOG_DEBUG("Data read (%d bits): 0x%04X", len, *d_out); else LOG_DEBUG("Data read was discarded."); @@ -117,7 +106,7 @@ static int dsp5680xx_drscan(struct target *target, uint8_t *d_in, * @param target * @param d_in This is the data that will be shifted into the JTAG IR reg. * @param d_out The data that will be shifted out of the JTAG IR reg will be stored here. - * @apram ir_len Length of the data to be shifted to JTAG IR. + * @param ir_len Length of the data to be shifted to JTAG IR. * */ static int dsp5680xx_irscan(struct target *target, uint32_t *d_in, @@ -127,7 +116,7 @@ static int dsp5680xx_irscan(struct target *target, uint32_t *d_in, uint16_t tap_ir_len = DSP5680XX_JTAG_MASTER_TAP_IRLEN; - if (NULL == target->tap) { + if (!target->tap) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_INVALID_TAP, "Invalid tap"); @@ -140,7 +129,7 @@ static int dsp5680xx_irscan(struct target *target, uint32_t *d_in, } else { struct jtag_tap *t = jtag_tap_by_string("dsp568013.chp"); - if ((t == NULL) + if ((!t) || ((t->enabled) && (ir_len != tap_ir_len))) { retval = ERROR_FAIL; err_check(retval, @@ -172,7 +161,7 @@ static int dsp5680xx_jtag_status(struct target *target, uint8_t *status) dsp5680xx_irscan(target, &instr, &read_from_ir, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); - if (status != NULL) + if (status) *status = (uint8_t) read_from_ir; return ERROR_OK; } @@ -205,7 +194,7 @@ static int jtag_data_write(struct target *target, uint32_t instr, int num_bits, dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &data_read_dummy, num_bits); err_check_propagate(retval); - if (data_read != NULL) + if (data_read) *data_read = data_read_dummy; return retval; } @@ -239,7 +228,7 @@ static int eonce_instruction_exec_single(struct target *target, uint8_t instr, retval = jtag_data_write(target, instr_with_flags, 8, &dr_out_tmp); err_check_propagate(retval); - if (eonce_status != NULL) + if (eonce_status) *eonce_status = (uint8_t) dr_out_tmp; return retval; } @@ -501,7 +490,7 @@ static int core_move_value_to_pc(struct target *target, uint32_t value) return retval; } -static int eonce_load_TX_RX_to_r0(struct target *target) +static int eonce_load_tx_rx_to_r0(struct target *target) { int retval; @@ -512,7 +501,7 @@ static int eonce_load_TX_RX_to_r0(struct target *target) return retval; } -static int core_load_TX_RX_high_addr_to_r0(struct target *target) +static int core_load_tx_rx_high_addr_to_r0(struct target *target) { int retval = 0; @@ -577,9 +566,9 @@ static int switch_tap(struct target *target, struct jtag_tap *master_tap, uint32_t ir_out; /* not used, just to make jtag happy. */ - if (master_tap == NULL) { + if (!master_tap) { master_tap = jtag_tap_by_string("dsp568013.chp"); - if (master_tap == NULL) { + if (!master_tap) { retval = ERROR_FAIL; const char *msg = "Failed to get master tap."; @@ -587,9 +576,9 @@ static int switch_tap(struct target *target, struct jtag_tap *master_tap, msg); } } - if (core_tap == NULL) { + if (!core_tap) { core_tap = jtag_tap_by_string("dsp568013.cpu"); - if (core_tap == NULL) { + if (!core_tap) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_CORE, "Failed to get core tap."); @@ -695,7 +684,7 @@ static int eonce_enter_debug_mode_without_reset(struct target *target, */ err_check_propagate(retval); } - if (eonce_status != NULL) + if (eonce_status) *eonce_status = data_read_from_dr; return retval; } @@ -731,13 +720,13 @@ static int eonce_enter_debug_mode(struct target *target, struct jtag_tap *tap_cpu; tap_chp = jtag_tap_by_string("dsp568013.chp"); - if (tap_chp == NULL) { + if (!tap_chp) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER, "Failed to get master tap."); } tap_cpu = jtag_tap_by_string("dsp568013.cpu"); - if (tap_cpu == NULL) { + if (!tap_cpu) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_CORE, "Failed to get master tap."); @@ -833,7 +822,7 @@ static int eonce_enter_debug_mode(struct target *target, retval = ERROR_TARGET_FAILURE; err_check(retval, DSP5680XX_ERROR_ENTER_DEBUG_MODE, msg); } - if (eonce_status != NULL) + if (eonce_status) *eonce_status = data_read_from_dr; return retval; } @@ -855,7 +844,7 @@ static int eonce_pc_store(struct target *target) err_check_propagate(retval); retval = core_move_r4_to_y(target); err_check_propagate(retval); - retval = eonce_load_TX_RX_to_r0(target); + retval = eonce_load_tx_rx_to_r0(target); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); @@ -892,12 +881,6 @@ static int dsp5680xx_arch_state(struct target *target) return ERROR_OK; } -int dsp5680xx_target_status(struct target *target, uint8_t *jtag_st, - uint16_t *eonce_st) -{ - return target->state; -} - static int dsp5680xx_assert_reset(struct target *target) { target->state = TARGET_RESET; @@ -1076,8 +1059,8 @@ static int dsp5680xx_resume(struct target *target, int current, } /** - * The value of @address determines if it corresponds to P: (program) or X: (dat) memory. - * If the address is over 0x200000 then it is considered X: memory, and @pmem = 0. + * The value of @a address determines if it corresponds to P: (program) or X: (dat) memory. + * If the address is over 0x200000 then it is considered X: memory, and @a pmem = 0. * The special case of 0xFFXXXX is not modified, since it allows to read out the * memory mapped EOnCE registers. * @@ -1116,7 +1099,7 @@ static int dsp5680xx_read_16_single(struct target *t, uint32_t a, else retval = core_move_at_r0_to_y0(target); err_check_propagate(retval); - retval = eonce_load_TX_RX_to_r0(target); + retval = eonce_load_tx_rx_to_r0(target); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); @@ -1153,7 +1136,7 @@ static int dsp5680xx_read_32_single(struct target *t, uint32_t a, err_check_propagate(retval); } /* Get lower part of data to TX/RX */ - retval = eonce_load_TX_RX_to_r0(target); + retval = eonce_load_tx_rx_to_r0(target); err_check_propagate(retval); retval = core_move_y0_at_r0_inc(target); /* This also load TX/RX high to r0 */ err_check_propagate(retval); @@ -1411,32 +1394,26 @@ static int dsp5680xx_write_32(struct target *t, uint32_t a, uint32_t c, } /** - * Writes @buffer to memory. - * The parameter @address determines whether @buffer should be written to + * Writes @a buffer to memory. + * The parameter @a address determines whether @a buffer should be written to * P: (program) memory or X: (dat) memory. * * @param target - * @param address + * @param a address * @param size Bytes (1), Half words (2), Words (4). * @param count In bytes. - * @param buffer + * @param b buffer * * @return */ -static int dsp5680xx_write(struct target *t, target_addr_t a, uint32_t s, uint32_t c, +static int dsp5680xx_write(struct target *target, target_addr_t a, uint32_t size, uint32_t count, const uint8_t *b) { /* TODO Cannot write 32bit to odd address, will write 0x12345678 as 0x5678 0x0012 */ - struct target *target = t; - uint32_t address = a; - uint32_t count = c; - uint8_t const *buffer = b; - uint32_t size = s; - check_halt_and_debug(target); int retval = 0; @@ -1485,12 +1462,12 @@ static int dsp5680xx_write_buffer(struct target *t, target_addr_t a, uint32_t si * * @return */ -static int dsp5680xx_read_buffer(struct target *t, target_addr_t a, uint32_t size, - uint8_t *buf) +static int dsp5680xx_read_buffer(struct target *target, target_addr_t address, uint32_t size, + uint8_t *buffer) { - check_halt_and_debug(t); + check_halt_and_debug(target); /* The "/2" solves the byte/word addressing issue.*/ - return dsp5680xx_read(t, a, 2, size / 2, buf); + return dsp5680xx_read(target, address, 2, size / 2, buffer); } /** @@ -1505,19 +1482,19 @@ static int dsp5680xx_read_buffer(struct target *t, target_addr_t a, uint32_t siz * * @return */ -static int dsp5680xx_checksum_memory(struct target *t, target_addr_t a, uint32_t s, +static int dsp5680xx_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t *checksum) { return ERROR_FAIL; } /** - * Calculates a signature over @word_count words in the data from @buff16. - * The algorithm used is the same the FM uses, so the @return may be used to compare + * Calculates a signature over @a word_count words in the data from @a buff8. + * The algorithm used is the same the FM uses, so the @a return may be used to compare * with the one generated by the FM module, and check if flashing was successful. * This algorithm is based on the perl script available from the Freescale website at FAQ 25630. * - * @param buff16 + * @param buff8 * @param word_count * * @return @@ -1555,7 +1532,7 @@ static int perl_crc(const uint8_t *buff8, uint32_t word_count) * * @return */ -int dsp5680xx_f_SIM_reset(struct target *target) +static int dsp5680xx_f_sim_reset(struct target *target) { int retval = ERROR_OK; @@ -1587,7 +1564,7 @@ static int dsp5680xx_soft_reset_halt(struct target *target) retval = dsp5680xx_halt(target); err_check_propagate(retval); - retval = dsp5680xx_f_SIM_reset(target); + retval = dsp5680xx_f_sim_reset(target); err_check_propagate(retval); return retval; } @@ -1597,7 +1574,7 @@ int dsp5680xx_f_protect_check(struct target *target, uint16_t *protected) int retval; check_halt_and_debug(target); - if (protected == NULL) { + if (!protected) { const char *msg = "NULL pointer not valid."; err_check(ERROR_FAIL, @@ -1612,35 +1589,24 @@ int dsp5680xx_f_protect_check(struct target *target, uint16_t *protected) /** * Executes a command on the FM module. - * Some commands use the parameters @address and @data, others ignore them. + * Some commands use the parameters @a address and @a data, others ignore them. * * @param target - * @param command Command to execute. + * @param c Command to execute. * @param address Command parameter. * @param data Command parameter. * @param hfm_ustat FM status register. - * @param pmem Address is P: (program) memory (@pmem == 1) or X: (dat) memory (@pmem == 0) + * @param pmem Address is P: (program) memory (@a pmem == 1) or X: (dat) memory (@a pmem == 0) * * @return */ -static int dsp5680xx_f_ex(struct target *t, uint16_t c, uint32_t a, uint32_t d, - uint16_t *h, int p) +static int dsp5680xx_f_ex(struct target *target, uint16_t c, uint32_t address, uint32_t data, + uint16_t *hfm_ustat, int pmem) { - struct target *target = t; - uint32_t command = c; - - uint32_t address = a; - - uint32_t data = d; - - uint16_t *hfm_ustat = h; - - int pmem = p; - int retval; - retval = core_load_TX_RX_high_addr_to_r0(target); + retval = core_load_tx_rx_high_addr_to_r0(target); err_check_propagate(retval); retval = core_move_long_to_r2(target, HFM_BASE_ADDR); err_check_propagate(retval); @@ -1750,7 +1716,7 @@ static int set_fm_ck_div(struct target *target) retval = core_move_long_to_r2(target, HFM_BASE_ADDR); err_check_propagate(retval); - retval = core_load_TX_RX_high_addr_to_r0(target); + retval = core_load_tx_rx_high_addr_to_r0(target); err_check_propagate(retval); /* read HFM_CLKD */ retval = core_move_at_r2_to_y0(target); @@ -1793,9 +1759,9 @@ static int set_fm_ck_div(struct target *target) /** * Executes the FM calculate signature command. The FM will calculate over the - * data from @address to @address + @words -1. The result is written to a - * register, then read out by this function and returned in @signature. The - * value @signature may be compared to the one returned by perl_crc to + * data from @a address to @a address + @a words -1. The result is written to a + * register, then read out by this function and returned in @a signature. The + * value @a signature may be compared to the one returned by perl_crc to * verify the flash was written correctly. * * @param target @@ -1805,13 +1771,9 @@ static int set_fm_ck_div(struct target *target) * * @return */ -static int dsp5680xx_f_signature(struct target *t, uint32_t a, uint32_t words, +static int dsp5680xx_f_signature(struct target *target, uint32_t address, uint32_t words, uint16_t *signature) { - struct target *target = t; - - uint32_t address = a; - int retval; uint16_t hfm_ustat; @@ -1856,7 +1818,7 @@ int dsp5680xx_f_erase_check(struct target *target, uint8_t *erased, retval = dsp5680xx_f_ex(target, HFM_ERASE_VERIFY, tmp, 0, &hfm_ustat, 1); err_check_propagate(retval); - if (erased != NULL) + if (erased) *erased = (uint8_t) (hfm_ustat & HFM_USTAT_MASK_BLANK); return retval; } @@ -1909,7 +1871,7 @@ int dsp5680xx_f_erase(struct target *target, int first, int last) * Reset SIM * */ - retval = dsp5680xx_f_SIM_reset(target); + retval = dsp5680xx_f_sim_reset(target); err_check_propagate(retval); /* * Set hfmdiv @@ -1978,7 +1940,8 @@ int dsp5680xx_f_erase(struct target *target, int first, int last) * 0x0000001E 0xA961 bra *-30 */ -const uint16_t pgm_write_pflash[] = { 0x8A46, 0x0013, 0x807D, 0xE700, +static const uint16_t pgm_write_pflash[] = { + 0x8A46, 0x0013, 0x807D, 0xE700, 0xE700, 0x8A44, 0xFFFE, 0x017B, 0xE700, 0xF514, 0x8563, 0x8646, 0x0020, 0x0014, 0x8646, 0x0080, @@ -1988,7 +1951,7 @@ const uint16_t pgm_write_pflash[] = { 0x8A46, 0x0013, 0x807D, 0xE700, 0x0013, 0x0010, 0xA961 }; -const uint32_t pgm_write_pflash_length = 31; +static const uint32_t pgm_write_pflash_length = 31; int dsp5680xx_f_wr(struct target *t, const uint8_t *b, uint32_t a, uint32_t count, int is_flash_lock) @@ -2040,7 +2003,7 @@ int dsp5680xx_f_wr(struct target *t, const uint8_t *b, uint32_t a, uint32_t coun retval = core_move_long_to_r3(target, address); /* Destination address to r3 */ err_check_propagate(retval); - core_load_TX_RX_high_addr_to_r0(target); /* TX/RX reg address to r0 */ + core_load_tx_rx_high_addr_to_r0(target); /* TX/RX reg address to r0 */ err_check_propagate(retval); retval = core_move_long_to_r2(target, HFM_BASE_ADDR); /* FM base address to r2 */ err_check_propagate(retval); @@ -2144,13 +2107,13 @@ int dsp5680xx_f_unlock(struct target *target) struct jtag_tap *tap_cpu; tap_chp = jtag_tap_by_string("dsp568013.chp"); - if (tap_chp == NULL) { + if (!tap_chp) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER, "Failed to get master tap."); } tap_cpu = jtag_tap_by_string("dsp568013.cpu"); - if (tap_cpu == NULL) { + if (!tap_cpu) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE, "Failed to get master tap."); @@ -2237,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); @@ -2252,13 +2215,13 @@ int dsp5680xx_f_lock(struct target *target) jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); tap_chp = jtag_tap_by_string("dsp568013.chp"); - if (tap_chp == NULL) { + if (!tap_chp) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER, "Failed to get master tap."); } tap_cpu = jtag_tap_by_string("dsp568013.cpu"); - if (tap_cpu == NULL) { + if (!tap_cpu) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE, "Failed to get master tap."); diff --git a/src/target/dsp5680xx.h b/src/target/dsp5680xx.h index 72557cea21..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 @@ -238,7 +227,7 @@ * ---------------------------------------------------------------- */ #define MC568013_SIM_BASE_ADDR 0xF140 -#define MC56803x_2x_SIM_BASE_ADDR 0xF100 +#define MC56803X_2X_SIM_BASE_ADDR 0xF100 #define SIM_CMD_RESET 0x10 /** @@ -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 7c53c45c57..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 @@ -645,7 +634,6 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou return ERROR_TARGET_TIMEOUT; } -#ifndef HAVE_JTAG_MINIDRIVER_H /** * This is an inner loop of the open loop DCC write of data to target */ @@ -660,6 +648,3 @@ void embeddedice_write_dcc(struct jtag_tap *tap, buffer += 4; } } -#else -/* provided by minidriver */ -#endif diff --git a/src/target/embeddedice.h b/src/target/embeddedice.h index 4b5c816a6b..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 @@ -69,11 +58,11 @@ enum { EICE_W_CTRL_RANGE = 0x80, EICE_W_CTRL_CHAIN = 0x40, EICE_W_CTRL_EXTERN = 0x20, - EICE_W_CTRL_nTRANS = 0x10, - EICE_W_CTRL_nOPC = 0x8, + EICE_W_CTRL_NTRANS = 0x10, + EICE_W_CTRL_NOPC = 0x8, EICE_W_CTRL_MAS = 0x6, EICE_W_CTRL_ITBIT = 0x2, - EICE_W_CTRL_nRW = 0x1 + EICE_W_CTRL_NRW = 0x1 }; enum { @@ -106,7 +95,7 @@ int embeddedice_send(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size); int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeout); -/* If many embeddedice_write_reg() follow eachother, then the >1 invocations can be +/* If many embeddedice_write_reg() follow each other, then the >1 invocations can be * this faster version of embeddedice_write_reg */ static inline void embeddedice_write_reg_inner(struct jtag_tap *tap, int reg_addr, uint32_t value) diff --git a/src/target/esirisc.c b/src/target/esirisc.c index c928445ccf..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 @@ -56,38 +45,38 @@ static const char * const esirisc_exception_strings[] = { [EID_SYSTEM_CALL] = "SystemCall", [EID_MEMORY_MANAGEMENT] = "MemoryManagement", [EID_UNRECOVERABLE] = "Unrecoverable", - [EID_INTERRUPTn+0] = "Interrupt0", - [EID_INTERRUPTn+1] = "Interrupt1", - [EID_INTERRUPTn+2] = "Interrupt2", - [EID_INTERRUPTn+3] = "Interrupt3", - [EID_INTERRUPTn+4] = "Interrupt4", - [EID_INTERRUPTn+5] = "Interrupt5", - [EID_INTERRUPTn+6] = "Interrupt6", - [EID_INTERRUPTn+7] = "Interrupt7", - [EID_INTERRUPTn+8] = "Interrupt8", - [EID_INTERRUPTn+9] = "Interrupt9", - [EID_INTERRUPTn+10] = "Interrupt10", - [EID_INTERRUPTn+11] = "Interrupt11", - [EID_INTERRUPTn+12] = "Interrupt12", - [EID_INTERRUPTn+13] = "Interrupt13", - [EID_INTERRUPTn+14] = "Interrupt14", - [EID_INTERRUPTn+15] = "Interrupt15", - [EID_INTERRUPTn+16] = "Interrupt16", - [EID_INTERRUPTn+17] = "Interrupt17", - [EID_INTERRUPTn+18] = "Interrupt18", - [EID_INTERRUPTn+19] = "Interrupt19", - [EID_INTERRUPTn+20] = "Interrupt20", - [EID_INTERRUPTn+21] = "Interrupt21", - [EID_INTERRUPTn+22] = "Interrupt22", - [EID_INTERRUPTn+23] = "Interrupt23", - [EID_INTERRUPTn+24] = "Interrupt24", - [EID_INTERRUPTn+25] = "Interrupt25", - [EID_INTERRUPTn+26] = "Interrupt26", - [EID_INTERRUPTn+27] = "Interrupt27", - [EID_INTERRUPTn+28] = "Interrupt28", - [EID_INTERRUPTn+29] = "Interrupt29", - [EID_INTERRUPTn+30] = "Interrupt30", - [EID_INTERRUPTn+31] = "Interrupt31", + [EID_INTERRUPT_N+0] = "Interrupt0", + [EID_INTERRUPT_N+1] = "Interrupt1", + [EID_INTERRUPT_N+2] = "Interrupt2", + [EID_INTERRUPT_N+3] = "Interrupt3", + [EID_INTERRUPT_N+4] = "Interrupt4", + [EID_INTERRUPT_N+5] = "Interrupt5", + [EID_INTERRUPT_N+6] = "Interrupt6", + [EID_INTERRUPT_N+7] = "Interrupt7", + [EID_INTERRUPT_N+8] = "Interrupt8", + [EID_INTERRUPT_N+9] = "Interrupt9", + [EID_INTERRUPT_N+10] = "Interrupt10", + [EID_INTERRUPT_N+11] = "Interrupt11", + [EID_INTERRUPT_N+12] = "Interrupt12", + [EID_INTERRUPT_N+13] = "Interrupt13", + [EID_INTERRUPT_N+14] = "Interrupt14", + [EID_INTERRUPT_N+15] = "Interrupt15", + [EID_INTERRUPT_N+16] = "Interrupt16", + [EID_INTERRUPT_N+17] = "Interrupt17", + [EID_INTERRUPT_N+18] = "Interrupt18", + [EID_INTERRUPT_N+19] = "Interrupt19", + [EID_INTERRUPT_N+20] = "Interrupt20", + [EID_INTERRUPT_N+21] = "Interrupt21", + [EID_INTERRUPT_N+22] = "Interrupt22", + [EID_INTERRUPT_N+23] = "Interrupt23", + [EID_INTERRUPT_N+24] = "Interrupt24", + [EID_INTERRUPT_N+25] = "Interrupt25", + [EID_INTERRUPT_N+26] = "Interrupt26", + [EID_INTERRUPT_N+27] = "Interrupt27", + [EID_INTERRUPT_N+28] = "Interrupt28", + [EID_INTERRUPT_N+29] = "Interrupt29", + [EID_INTERRUPT_N+30] = "Interrupt30", + [EID_INTERRUPT_N+31] = "Interrupt31", }; /* @@ -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) { @@ -472,7 +463,7 @@ static int esirisc_next_breakpoint(struct target *target) LOG_DEBUG("-"); for (int bp_index = 0; breakpoints_p < breakpoints_e; ++breakpoints_p, ++bp_index) - if (*breakpoints_p == NULL) + if (!*breakpoints_p) return bp_index; return -1; @@ -504,11 +495,11 @@ static int esirisc_add_breakpoint(struct target *target, struct breakpoint *brea return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = bp_index + 1; + breakpoint_hw_set(breakpoint, bp_index); esirisc->breakpoints_p[bp_index] = breakpoint; /* specify instruction breakpoint address */ - retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBAn + bp_index, + retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBA_N + bp_index, breakpoint->address); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: IBA", target_name(target)); @@ -539,8 +530,8 @@ static int esirisc_add_breakpoints(struct target *target) LOG_DEBUG("-"); - while (breakpoint != NULL) { - if (breakpoint->set == 0) + while (breakpoint) { + if (!breakpoint->is_set) esirisc_add_breakpoint(target, breakpoint); breakpoint = breakpoint->next; @@ -553,7 +544,7 @@ static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *b { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - int bp_index = breakpoint->set - 1; + unsigned int bp_index = breakpoint->number; uint32_t ibc; int retval; @@ -575,7 +566,7 @@ static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *b } esirisc->breakpoints_p[bp_index] = NULL; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -608,7 +599,7 @@ static int esirisc_next_watchpoint(struct target *target) LOG_DEBUG("-"); for (int wp_index = 0; watchpoints_p < watchpoints_e; ++watchpoints_p, ++wp_index) - if (*watchpoints_p == NULL) + if (!*watchpoints_p) return wp_index; return -1; @@ -630,11 +621,11 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc return ERROR_FAIL; } - watchpoint->set = wp_index + 1; + watchpoint_set(watchpoint, wp_index); esirisc->watchpoints_p[wp_index] = watchpoint; /* specify data breakpoint address */ - retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBAn + wp_index, + retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBA_N + wp_index, watchpoint->address); if (retval != ERROR_OK) { LOG_ERROR("%s: failed to write Debug CSR: DBA", target_name(target)); @@ -723,8 +714,8 @@ static int esirisc_add_watchpoints(struct target *target) LOG_DEBUG("-"); - while (watchpoint != NULL) { - if (watchpoint->set == 0) + while (watchpoint) { + if (!watchpoint->is_set) esirisc_add_watchpoint(target, watchpoint); watchpoint = watchpoint->next; @@ -737,7 +728,7 @@ static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *w { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - int wp_index = watchpoint->set - 1; + unsigned int wp_index = watchpoint->number; uint32_t dbc; int retval; @@ -759,7 +750,7 @@ static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *w } esirisc->watchpoints_p[wp_index] = NULL; - watchpoint->set = 0; + watchpoint->is_set = false; return 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); @@ -890,7 +883,7 @@ static int esirisc_resume_or_step(struct target *target, int current, target_add if (handle_breakpoints) { breakpoint = breakpoint_find(target, address); - if (breakpoint != NULL) + if (breakpoint) esirisc_remove_breakpoint(target, breakpoint); } @@ -1061,7 +1054,7 @@ static int esirisc_debug_entry(struct target *target) case EID_INST_BREAKPOINT: breakpoint = breakpoint_find(target, buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size)); - target->debug_reason = (breakpoint != NULL) ? + target->debug_reason = (breakpoint) ? DBG_REASON_BREAKPOINT : DBG_REASON_DBGRQ; break; @@ -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); @@ -1267,7 +1260,7 @@ static const char *esirisc_get_gdb_arch(struct target *target) * requires additional configuration to properly interact with these * targets in GDB (also see: `esirisc cache_arch`). */ - if (esirisc->gdb_arch == NULL && target_was_examined(target)) + if (!esirisc->gdb_arch && target_was_examined(target)) esirisc->gdb_arch = alloc_printf("esirisc:%d_bit_%d_reg_%s", esirisc->num_bits, esirisc->num_regs, esirisc_cache_arch_name(esirisc)); @@ -1284,7 +1277,7 @@ static int esirisc_get_gdb_reg_list(struct target *target, struct reg **reg_list *reg_list_size = ESIRISC_NUM_REGS; *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); - if (*reg_list == NULL) + if (!*reg_list) return ERROR_FAIL; if (reg_class == REG_CLASS_ALL) @@ -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); @@ -1561,7 +1580,7 @@ static int esirisc_target_create(struct target *target, Jim_Interp *interp) struct jtag_tap *tap = target->tap; struct esirisc_common *esirisc; - if (tap == NULL) + if (!tap) return ERROR_FAIL; if (tap->ir_length != INSTR_LENGTH) { @@ -1571,7 +1590,7 @@ static int esirisc_target_create(struct target *target, Jim_Interp *interp) } esirisc = calloc(1, sizeof(struct esirisc_common)); - if (esirisc == NULL) + if (!esirisc) return ERROR_FAIL; esirisc->target = 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 57deba6167..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 @@ -47,7 +36,7 @@ #define EID_SYSTEM_CALL 0x0b #define EID_MEMORY_MANAGEMENT 0x0c #define EID_UNRECOVERABLE 0x0d -#define EID_INTERRUPTn 0x20 +#define EID_INTERRUPT_N 0x20 /* Exception Entry Points */ #define ENTRY_RESET 0x00 @@ -58,7 +47,7 @@ #define ENTRY_SYSCALL 0x05 #define ENTRY_DEBUG 0x06 #define ENTRY_NMI 0x07 -#define ENTRY_INTERRUPTn 0x08 +#define ENTRY_INTERRUPT_N 0x08 /* Hardware Debug Control */ #define HWDC_R (1<<4) /* Reset & Hardware Failure */ @@ -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 7fd35e5fde..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 @@ -57,7 +46,7 @@ static int esirisc_jtag_get_padding(void) int padding = 0; int bypass_devices = 0; - for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; + for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap; tap = jtag_tap_next_enabled(tap)) if (tap->bypass) bypass_devices++; @@ -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 a946a2ecc7..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 @@ -148,8 +137,8 @@ enum esirisc_reg_num { #define CSR_DEBUG_HWDC 0x03 /* Hardware Debug Control */ #define CSR_DEBUG_DBS 0x04 /* Data Breakpoint Size */ #define CSR_DEBUG_DBR 0x05 /* Data Breakpoint Range */ -#define CSR_DEBUG_IBAn 0x08 /* Instruction Breakpoint Address [0..7] */ -#define CSR_DEBUG_DBAn 0x10 /* Data Breakpoint Address [0..7] */ +#define CSR_DEBUG_IBA_N 0x08 /* Instruction Breakpoint Address [0..7] */ +#define CSR_DEBUG_DBA_N 0x10 /* Data Breakpoint Address [0..7] */ /* Configuration CSRs */ #define CSR_CONFIG_ARCH0 0x00 /* Architectural Configuration 0 */ @@ -160,12 +149,12 @@ enum esirisc_reg_num { #define CSR_CONFIG_IC 0x05 /* Instruction Cache Configuration */ #define CSR_CONFIG_DC 0x06 /* Data Cache Configuration */ #define CSR_CONFIG_INT 0x07 /* Interrupt Configuration */ -#define CSR_CONFIG_ISAn 0x08 /* Instruction Set Configuration [0..6] */ +#define CSR_CONFIG_ISA_N 0x08 /* Instruction Set Configuration [0..6] */ #define CSR_CONFIG_DBG 0x0f /* Debug Configuration */ #define CSR_CONFIG_MID 0x10 /* Manufacturer ID */ #define CSR_CONFIG_REV 0x11 /* Revision Number */ #define CSR_CONFIG_MPID 0x12 /* Multiprocessor ID */ -#define CSR_CONFIG_FREQn 0x13 /* Frequency [0..2] */ +#define CSR_CONFIG_FREQ_N 0x13 /* Frequency [0..2] */ #define CSR_CONFIG_TRACE 0x16 /* Trace Configuration */ /* Trace CSRs */ diff --git a/src/target/esirisc_trace.c b/src/target/esirisc_trace.c index 28d7536af7..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 @@ -551,7 +540,7 @@ static int esirisc_trace_analyze_buffer(struct command_invocation *cmd) size = esirisc_trace_buffer_size(trace_info); buffer = calloc(1, size); - if (buffer == NULL) { + if (!buffer) { command_print(cmd, "out of memory"); return ERROR_FAIL; } @@ -576,7 +565,7 @@ static int esirisc_trace_analyze_memory(struct command_invocation *cmd, int retval; buffer = calloc(1, size); - if (buffer == NULL) { + if (!buffer) { command_print(cmd, "out of memory"); return ERROR_FAIL; } @@ -628,7 +617,7 @@ static int esirisc_trace_dump_buffer(struct command_invocation *cmd, const char size = esirisc_trace_buffer_size(trace_info); buffer = calloc(1, size); - if (buffer == NULL) { + if (!buffer) { command_print(cmd, "out of memory"); return ERROR_FAIL; } @@ -653,7 +642,7 @@ static int esirisc_trace_dump_memory(struct command_invocation *cmd, const char int retval; buffer = calloc(1, size); - if (buffer == NULL) { + if (!buffer) { command_print(cmd, "out of memory"); return ERROR_FAIL; } 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..c49146d787 --- /dev/null +++ b/src/target/espressif/esp_xtensa_smp.c @@ -0,0 +1,1038 @@ +// 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) { + head = list_first_entry(target->smp_targets, struct target_list, lh); + if (head->target != target) + 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 0c03c4dbec..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 @@ -44,7 +33,7 @@ static int etb_set_instr(struct etb *etb, uint32_t new_instr) struct jtag_tap *tap; tap = etb->tap; - if (tap == NULL) + if (!tap) return ERROR_FAIL; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { @@ -349,7 +338,7 @@ COMMAND_HANDLER(handle_etb_config_command) } tap = jtag_tap_by_string(CMD_ARGV[1]); - if (tap == NULL) { + if (!tap) { command_print(CMD, "ETB: TAP %s does not exist", CMD_ARGV[1]); return ERROR_FAIL; } 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 5d079ffa82..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" @@ -27,11 +16,6 @@ #include "register.h" #include "etm_dummy.h" -#if BUILD_OOCD_TRACE == 1 -#include "oocd_trace.h" -#endif - - /* * ARM "Embedded Trace Macrocell" (ETM) support -- direct JTAG access. * @@ -279,7 +263,7 @@ static void etm_reg_add(unsigned bcd_vers, struct arm_jtag *jtag_info, reg->name = r->name; reg->size = r->size; - reg->value = &ereg->value; + reg->value = ereg->value; reg->arch_info = ereg; reg->type = &etm_scan6_type; reg++; @@ -303,7 +287,7 @@ struct reg_cache *etm_build_reg_cache(struct target *target, reg_list = calloc(128, sizeof(struct reg)); arch_info = calloc(128, sizeof(struct etm_reg)); - if (reg_cache == NULL || reg_list == NULL || arch_info == NULL) { + if (!reg_cache || !reg_list || !arch_info) { LOG_ERROR("No memory"); goto fail; } @@ -568,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; } @@ -642,15 +626,11 @@ static int etm_write_reg(struct reg *reg, uint32_t value) static struct etm_capture_driver *etm_capture_drivers[] = { &etb_capture_driver, &etm_dummy_capture_driver, -#if BUILD_OOCD_TRACE == 1 - &oocd_trace_capture_driver, -#endif NULL }; static int etm_read_instruction(struct etm_context *ctx, struct arm_instruction *instruction) { - int i; int section = -1; size_t size_read; uint32_t opcode; @@ -660,7 +640,7 @@ static int etm_read_instruction(struct etm_context *ctx, struct arm_instruction return ERROR_TRACE_IMAGE_UNAVAILABLE; /* search for the section the current instruction belongs to */ - for (i = 0; i < ctx->image->num_sections; i++) { + for (unsigned int i = 0; i < ctx->image->num_sections; i++) { if ((ctx->image->sections[i].base_address <= ctx->current_pc) && (ctx->image->sections[i].base_address + ctx->image->sections[i].size > ctx->current_pc)) { @@ -1425,9 +1405,8 @@ COMMAND_HANDLER(handle_etm_config_command) for (i = 0; etm_capture_drivers[i]; i++) { if (strcmp(CMD_ARGV[4], etm_capture_drivers[i]->name) == 0) { - int retval = register_commands(CMD_CTX, NULL, - etm_capture_drivers[i]->commands); - if (ERROR_OK != retval) { + int retval = register_commands(CMD_CTX, NULL, etm_capture_drivers[i]->commands); + if (retval != ERROR_OK) { free(etm_ctx); return retval; } @@ -1683,15 +1662,15 @@ COMMAND_HANDLER(handle_etm_image_command) } etm_ctx->image = malloc(sizeof(struct image)); - etm_ctx->image->base_address_set = 0; - etm_ctx->image->start_address_set = 0; + etm_ctx->image->base_address_set = false; + etm_ctx->image->start_address_set = false; /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { - etm_ctx->image->base_address_set = 1; + etm_ctx->image->base_address_set = true; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], etm_ctx->image->base_address); } else - etm_ctx->image->base_address_set = 0; + etm_ctx->image->base_address_set = false; if (image_open(etm_ctx->image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL) != ERROR_OK) { @@ -1727,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; } @@ -1817,7 +1796,7 @@ COMMAND_HANDLER(handle_etm_load_command) fileio_read_u32(file, &etm_ctx->trace_depth); } etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth); - if (etm_ctx->trace_data == NULL) { + if (!etm_ctx->trace_data) { command_print(CMD, "not enough memory to perform operation"); fileio_close(file); return ERROR_FAIL; @@ -2116,6 +2095,5 @@ static const struct command_registration etm_exec_command_handlers[] = { static int etm_register_user_commands(struct command_context *cmd_ctx) { - struct command *etm_cmd = command_find_in_context(cmd_ctx, "etm"); - return register_commands(cmd_ctx, etm_cmd, etm_exec_command_handlers); + return register_commands(cmd_ctx, "etm", etm_exec_command_handlers); } 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 1d1351bbc6..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/>. * ***************************************************************************/ /* @@ -373,14 +362,14 @@ static void feroceon_branch_resume_thumb(struct target *target) } static int feroceon_read_cp15(struct target *target, uint32_t op1, - uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value) + uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; int err; - arm9tdmi_clock_out(jtag_info, ARMV4_5_MRC(15, op1, 0, CRn, CRm, op2), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_MRC(15, op1, 0, crn, crm, op2), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); err = arm7_9_execute_sys_speed(target); if (err != ERROR_OK) @@ -396,7 +385,7 @@ static int feroceon_read_cp15(struct target *target, uint32_t op1, } static int feroceon_write_cp15(struct target *target, uint32_t op1, - uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) + uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; @@ -410,7 +399,7 @@ static int feroceon_write_cp15(struct target *target, uint32_t op1, arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_MCR(15, op1, 0, CRn, CRm, op2), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_MCR(15, op1, 0, crn, crm, op2), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); return arm7_9_execute_sys_speed(target); } diff --git a/src/target/hla_target.c b/src/target/hla_target.c index f0dc572764..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 @@ -37,10 +26,12 @@ #include "target_type.h" #include "armv7m.h" #include "cortex_m.h" +#include "arm_adi_v5.h" #include "arm_semihosting.h" #include "target_request.h" +#include <rtt/rtt.h> -#define savedDCRDR dbgbase /* FIXME: using target->dbgbase to preserve DCRDR */ +#define SAVED_DCRDR dbgbase /* FIXME: using target->dbgbase to preserve DCRDR */ #define ARMV7M_SCS_DCRSR DCB_DCRSR #define ARMV7M_SCS_DCRDR DCB_DCRDR @@ -51,184 +42,17 @@ static inline struct hl_interface_s *target_to_adapter(struct target *target) } static int adapter_load_core_reg_u32(struct target *target, - uint32_t num, uint32_t *value) + uint32_t regsel, uint32_t *value) { - int retval; struct hl_interface_s *adapter = target_to_adapter(target); - - LOG_DEBUG("%s", __func__); - - /* NOTE: we "know" here that the register identifiers used - * in the v7m header match the Cortex-M3 Debug Core Register - * Selector values for R0..R15, xPSR, MSP, and PSP. - */ - switch (num) { - case 0 ... 18: - /* read a normal core register */ - retval = adapter->layout->api->read_reg(adapter->handle, num, value); - - if (retval != ERROR_OK) { - LOG_ERROR("JTAG failure %i", retval); - return ERROR_JTAG_DEVICE_ERROR; - } - LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value); - break; - - case ARMV7M_FPSCR: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, 33); - if (retval != ERROR_OK) - return retval; - retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("load from FPSCR value 0x%" PRIx32, *value); - break; - - case ARMV7M_S0 ... ARMV7M_S31: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, num-ARMV7M_S0+64); - if (retval != ERROR_OK) - return retval; - retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("load from FPU reg S%d value 0x%" PRIx32, - (int)(num - ARMV7M_S0), *value); - break; - - case ARMV7M_PRIMASK: - case ARMV7M_BASEPRI: - case ARMV7M_FAULTMASK: - case ARMV7M_CONTROL: - /* Cortex-M3 packages these four registers as bitfields - * in one Debug Core register. So say r0 and r2 docs; - * it was removed from r1 docs, but still works. - */ - retval = adapter->layout->api->read_reg(adapter->handle, 20, value); - if (retval != ERROR_OK) - return retval; - - switch (num) { - case ARMV7M_PRIMASK: - *value = buf_get_u32((uint8_t *) value, 0, 1); - break; - - case ARMV7M_BASEPRI: - *value = buf_get_u32((uint8_t *) value, 8, 8); - break; - - case ARMV7M_FAULTMASK: - *value = buf_get_u32((uint8_t *) value, 16, 1); - break; - - case ARMV7M_CONTROL: - *value = buf_get_u32((uint8_t *) value, 24, 2); - break; - } - - LOG_DEBUG("load from special reg %i value 0x%" PRIx32 "", - (int)num, *value); - break; - - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; + return adapter->layout->api->read_reg(adapter->handle, regsel, value); } static int adapter_store_core_reg_u32(struct target *target, - uint32_t num, uint32_t value) + uint32_t regsel, uint32_t value) { - int retval; - uint32_t reg; - struct armv7m_common *armv7m = target_to_armv7m(target); struct hl_interface_s *adapter = target_to_adapter(target); - - LOG_DEBUG("%s", __func__); - - /* NOTE: we "know" here that the register identifiers used - * in the v7m header match the Cortex-M3 Debug Core Register - * Selector values for R0..R15, xPSR, MSP, and PSP. - */ - switch (num) { - case 0 ... 18: - retval = adapter->layout->api->write_reg(adapter->handle, num, value); - - if (retval != ERROR_OK) { - struct reg *r; - - LOG_ERROR("JTAG failure"); - r = armv7m->arm.core_cache->reg_list + num; - r->dirty = r->valid; - return ERROR_JTAG_DEVICE_ERROR; - } - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value); - break; - - case ARMV7M_FPSCR: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, 33 | (1<<16)); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("write FPSCR value 0x%" PRIx32, value); - break; - - case ARMV7M_S0 ... ARMV7M_S31: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, (num-ARMV7M_S0+64) | (1<<16)); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("write FPU reg S%d value 0x%" PRIx32, - (int)(num - ARMV7M_S0), value); - break; - - case ARMV7M_PRIMASK: - case ARMV7M_BASEPRI: - case ARMV7M_FAULTMASK: - case ARMV7M_CONTROL: - /* Cortex-M3 packages these four registers as bitfields - * in one Debug Core register. So say r0 and r2 docs; - * it was removed from r1 docs, but still works. - */ - - adapter->layout->api->read_reg(adapter->handle, 20, ®); - - switch (num) { - case ARMV7M_PRIMASK: - buf_set_u32((uint8_t *) ®, 0, 1, value); - break; - - case ARMV7M_BASEPRI: - buf_set_u32((uint8_t *) ®, 8, 8, value); - break; - - case ARMV7M_FAULTMASK: - buf_set_u32((uint8_t *) ®, 16, 1, value); - break; - - case ARMV7M_CONTROL: - buf_set_u32((uint8_t *) ®, 24, 2, value); - break; - } - - adapter->layout->api->write_reg(adapter->handle, 20, reg); - - LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value); - break; - - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; + return adapter->layout->api->write_reg(adapter->handle, regsel, value); } static int adapter_examine_debug_reason(struct target *target) @@ -345,7 +169,7 @@ static int adapter_init_arch_info(struct target *target, armv7m->store_core_reg_u32 = adapter_store_core_reg_u32; armv7m->examine_debug_reason = adapter_examine_debug_reason; - armv7m->stlink = true; + armv7m->is_hla_target = true; target_register_timer_callback(hl_handle_target_request, 1, TARGET_TIMER_TYPE_PERIODIC, target); @@ -368,17 +192,19 @@ static int adapter_target_create(struct target *target, { LOG_DEBUG("%s", __func__); struct adiv5_private_config *pc = target->private_config; - if (pc != NULL && 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; } struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common)); - if (cortex_m == NULL) { + if (!cortex_m) { LOG_ERROR("No memory creating target"); return ERROR_FAIL; } + cortex_m->common_magic = CORTEX_M_COMMON_MAGIC; + adapter_init_arch_info(target, cortex_m, target->tap); return ERROR_OK; @@ -392,7 +218,7 @@ static int adapter_load_context(struct target *target) for (int i = 0; i < num_regs; i++) { struct reg *r = &armv7m->arm.core_cache->reg_list[i]; - if (!r->valid) + if (r->exist && !r->valid) armv7m->arm.read_core_reg(target, r, i, ARM_MODE_ANY); } @@ -405,11 +231,11 @@ 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 */ - retval = target_read_u32(target, DCB_DCRDR, &target->savedDCRDR); + retval = target_read_u32(target, DCB_DCRDR, &target->SAVED_DCRDR); if (retval != ERROR_OK) return retval; @@ -423,17 +249,17 @@ 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; } else { unsigned control = buf_get_u32(arm->core_cache - ->reg_list[ARMV7M_CONTROL].value, 0, 2); + ->reg_list[ARMV7M_CONTROL].value, 0, 3); /* is this thread privileged? */ arm->core_mode = control & 1 @@ -521,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); @@ -571,7 +404,7 @@ static int hl_deassert_reset(struct target *target) if (jtag_reset_config & RESET_HAS_SRST) adapter_deassert_reset(); - target->savedDCRDR = 0; /* clear both DCC busy bits on initial resume */ + target->SAVED_DCRDR = 0; /* clear both DCC busy bits on initial resume */ return target->reset_halt ? ERROR_OK : target_resume(target, 1, 0, 0, 0); } @@ -616,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; } @@ -647,8 +480,8 @@ static int adapter_resume(struct target *target, int current, armv7m_restore_context(target); - /* restore savedDCRDR */ - res = target_write_u32(target, DCB_DCRDR, target->savedDCRDR); + /* restore SAVED_DCRDR */ + res = target_write_u32(target, DCB_DCRDR, target->SAVED_DCRDR); if (res != ERROR_OK) return res; @@ -705,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; } @@ -730,8 +563,8 @@ static int adapter_step(struct target *target, int current, armv7m_restore_context(target); - /* restore savedDCRDR */ - res = target_write_u32(target, DCB_DCRDR, target->savedDCRDR); + /* restore SAVED_DCRDR */ + res = target_write_u32(target, DCB_DCRDR, target->SAVED_DCRDR); if (res != ERROR_OK) return res; @@ -786,26 +619,33 @@ static int adapter_write_memory(struct target *target, target_addr_t address, return adapter->layout->api->write_mem(adapter->handle, address, size, count, buffer); } -static const struct command_registration adapter_command_handlers[] = { +static const struct command_registration hla_command_handlers[] = { { .chain = arm_command_handlers, }, { .chain = armv7m_trace_command_handlers, }, + { + .chain = rtt_target_command_handlers, + }, + /* START_DEPRECATED_TPIU */ + { + .chain = arm_tpiu_deprecated_command_handlers, + }, + /* END_DEPRECATED_TPIU */ COMMAND_REGISTRATION_DONE }; struct target_type hla_target = { .name = "hla_target", - .deprecated_name = "stm32_stlink", .init_target = adapter_init_target, .deinit_target = cortex_m_deinit_target, .target_create = adapter_target_create, .target_jim_configure = adiv5_jim_configure, .examine = cortex_m_examine, - .commands = adapter_command_handlers, + .commands = hla_command_handlers, .poll = adapter_poll, .arch_state = armv7m_arch_state, diff --git a/src/target/image.c b/src/target/image.c index 8160e5f929..440fe17d18 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 * @@ -11,18 +13,8 @@ * Copyright (C) 2009 by Franck Hereson * * franck.hereson@secad.fr * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * 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) 2018 by Advantest * + * florian.meister@advantest.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -32,6 +24,7 @@ #include "image.h" #include "target.h" #include <helper/log.h> +#include <server/server.h> /* convert ELF header field to host endianness */ #define field16(elf, field) \ @@ -42,6 +35,10 @@ ((elf->endianness == ELFDATA2LSB) ? \ le_to_h_u32((uint8_t *)&field) : be_to_h_u32((uint8_t *)&field)) +#define field64(elf, field) \ + ((elf->endianness == ELFDATA2LSB) ? \ + le_to_h_u64((uint8_t *)&field) : be_to_h_u64((uint8_t *)&field)) + static int autodetect_image_type(struct image *image, const char *url) { int retval; @@ -49,17 +46,20 @@ static int autodetect_image_type(struct image *image, const char *url) size_t read_bytes; uint8_t buffer[9]; - /* read the first 4 bytes of image */ + /* read the first 9 bytes of image */ retval = fileio_open(&fileio, url, FILEIO_READ, FILEIO_BINARY); 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; @@ -86,8 +86,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; } @@ -95,20 +97,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); @@ -116,7 +120,7 @@ static int identify_image_type(struct image *image, const char *type_string, con } static int image_ihex_buffer_complete_inner(struct image *image, - char *lpszLine, + char *lpsz_line, struct imagesection *section) { struct image_ihex *ihex = image->type_private; @@ -124,7 +128,6 @@ static int image_ihex_buffer_complete_inner(struct image *image, uint32_t full_address; uint32_t cooked_bytes; bool end_rec = false; - int i; /* we can't determine the number of sections that we'll have to create ahead of time, * so we locally hold them until parsing is finished */ @@ -146,7 +149,7 @@ static int image_ihex_buffer_complete_inner(struct image *image, section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; - while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { + while (fileio_fgets(fileio, 1023, lpsz_line) == ERROR_OK) { uint32_t count; uint32_t address; uint32_t record_type; @@ -155,10 +158,10 @@ static int image_ihex_buffer_complete_inner(struct image *image, size_t bytes_read = 0; /* skip comments and blank lines */ - if ((lpszLine[0] == '#') || (strlen(lpszLine + strspn(lpszLine, "\n\t\r ")) == 0)) + if ((lpsz_line[0] == '#') || (strlen(lpsz_line + strspn(lpsz_line, "\n\t\r ")) == 0)) continue; - if (sscanf(&lpszLine[bytes_read], ":%2" SCNx32 "%4" SCNx32 "%2" SCNx32, &count, + if (sscanf(&lpsz_line[bytes_read], ":%2" SCNx32 "%4" SCNx32 "%2" SCNx32, &count, &address, &record_type) != 3) return ERROR_IMAGE_FORMAT_ERROR; bytes_read += 9; @@ -193,7 +196,7 @@ static int image_ihex_buffer_complete_inner(struct image *image, while (count-- > 0) { unsigned value; - sscanf(&lpszLine[bytes_read], "%2x", &value); + sscanf(&lpsz_line[bytes_read], "%2x", &value); ihex->buffer[cooked_bytes] = (uint8_t)value; cal_checksum += (uint8_t)ihex->buffer[cooked_bytes]; bytes_read += 2; @@ -207,7 +210,7 @@ static int image_ihex_buffer_complete_inner(struct image *image, /* copy section information */ image->sections = malloc(sizeof(struct imagesection) * image->num_sections); - for (i = 0; i < image->num_sections; i++) { + for (unsigned int i = 0; i < image->num_sections; i++) { image->sections[i].private = section[i].private; image->sections[i].base_address = section[i].base_address; image->sections[i].size = section[i].size; @@ -219,7 +222,7 @@ static int image_ihex_buffer_complete_inner(struct image *image, } else if (record_type == 2) { /* Linear Address Record */ uint16_t upper_address; - sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); + sscanf(&lpsz_line[bytes_read], "%4hx", &upper_address); cal_checksum += (uint8_t)(upper_address >> 8); cal_checksum += (uint8_t)upper_address; bytes_read += 4; @@ -251,14 +254,14 @@ static int image_ihex_buffer_complete_inner(struct image *image, /* "Start Segment Address Record" will not be supported * but we must consume it, and do not create an error. */ while (count-- > 0) { - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); + sscanf(&lpsz_line[bytes_read], "%2" SCNx32, &dummy); cal_checksum += (uint8_t)dummy; bytes_read += 2; } } else if (record_type == 4) { /* Extended Linear Address Record */ uint16_t upper_address; - sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); + sscanf(&lpsz_line[bytes_read], "%4hx", &upper_address); cal_checksum += (uint8_t)(upper_address >> 8); cal_checksum += (uint8_t)upper_address; bytes_read += 4; @@ -287,21 +290,21 @@ static int image_ihex_buffer_complete_inner(struct image *image, } else if (record_type == 5) { /* Start Linear Address Record */ uint32_t start_address; - sscanf(&lpszLine[bytes_read], "%8" SCNx32, &start_address); + sscanf(&lpsz_line[bytes_read], "%8" SCNx32, &start_address); cal_checksum += (uint8_t)(start_address >> 24); cal_checksum += (uint8_t)(start_address >> 16); cal_checksum += (uint8_t)(start_address >> 8); cal_checksum += (uint8_t)start_address; bytes_read += 8; - image->start_address_set = 1; + image->start_address_set = true; image->start_address = be_to_h_u32((uint8_t *)&start_address); } else { LOG_ERROR("unhandled IHEX record type: %i", (int)record_type); return ERROR_IMAGE_FORMAT_ERROR; } - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); + sscanf(&lpsz_line[bytes_read], "%2" SCNx32, &checksum); if ((uint8_t)checksum != (uint8_t)(~cal_checksum + 1)) { /* checksum failed */ @@ -311,7 +314,7 @@ static int image_ihex_buffer_complete_inner(struct image *image, if (end_rec) { end_rec = false; - LOG_WARNING("continuing after end-of-file record: %.40s", lpszLine); + LOG_WARNING("continuing after end-of-file record: %.40s", lpsz_line); } } } @@ -330,43 +333,50 @@ static int image_ihex_buffer_complete_inner(struct image *image, */ static int image_ihex_buffer_complete(struct image *image) { - char *lpszLine = malloc(1023); - if (lpszLine == NULL) { + char *lpsz_line = malloc(1023); + if (!lpsz_line) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } struct imagesection *section = malloc(sizeof(struct imagesection) * IMAGE_MAX_SECTIONS); - if (section == NULL) { - free(lpszLine); + if (!section) { + free(lpsz_line); LOG_ERROR("Out of memory"); return ERROR_FAIL; } int retval; - retval = image_ihex_buffer_complete_inner(image, lpszLine, section); + retval = image_ihex_buffer_complete_inner(image, lpsz_line, section); free(section); - free(lpszLine); + free(lpsz_line); return retval; } -static int image_elf_read_headers(struct image *image) +static int image_elf32_read_headers(struct image *image) { struct image_elf *elf = image->type_private; size_t read_bytes; uint32_t i, j; int retval; - uint32_t nload, load_to_vaddr = 0; + uint32_t nload; + bool load_to_vaddr = false; - elf->header = malloc(sizeof(Elf32_Ehdr)); + retval = fileio_seek(elf->fileio, 0); + if (retval != ERROR_OK) { + LOG_ERROR("cannot seek to ELF file header, read failed"); + return retval; + } + + elf->header32 = malloc(sizeof(Elf32_Ehdr)); - if (elf->header == NULL) { - LOG_ERROR("insufficient memory to perform operation "); + if (!elf->header32) { + LOG_ERROR("insufficient memory to perform operation"); return ERROR_FILEIO_OPERATION_FAILED; } - retval = fileio_read(elf->fileio, sizeof(Elf32_Ehdr), (uint8_t *)elf->header, &read_bytes); + retval = fileio_read(elf->fileio, sizeof(Elf32_Ehdr), (uint8_t *)elf->header32, &read_bytes); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF file header, read failed"); return ERROR_FILEIO_OPERATION_FAILED; @@ -376,47 +386,156 @@ static int image_elf_read_headers(struct image *image) return ERROR_FILEIO_OPERATION_FAILED; } - if (strncmp((char *)elf->header->e_ident, ELFMAG, SELFMAG) != 0) { - LOG_ERROR("invalid ELF file, bad magic number"); + elf->segment_count = field16(elf, elf->header32->e_phnum); + if (elf->segment_count == 0) { + LOG_ERROR("invalid ELF file, no program headers"); return ERROR_IMAGE_FORMAT_ERROR; } - if (elf->header->e_ident[EI_CLASS] != ELFCLASS32) { - LOG_ERROR("invalid ELF file, only 32bits files are supported"); - return ERROR_IMAGE_FORMAT_ERROR; + + retval = fileio_seek(elf->fileio, field32(elf, elf->header32->e_phoff)); + if (retval != ERROR_OK) { + LOG_ERROR("cannot seek to ELF program header table, read failed"); + return retval; } - elf->endianness = elf->header->e_ident[EI_DATA]; - if ((elf->endianness != ELFDATA2LSB) - && (elf->endianness != ELFDATA2MSB)) { - LOG_ERROR("invalid ELF file, unknown endianness setting"); + elf->segments32 = malloc(elf->segment_count*sizeof(Elf32_Phdr)); + if (!elf->segments32) { + LOG_ERROR("insufficient memory to perform operation"); + return ERROR_FILEIO_OPERATION_FAILED; + } + + retval = fileio_read(elf->fileio, elf->segment_count*sizeof(Elf32_Phdr), + (uint8_t *)elf->segments32, &read_bytes); + if (retval != ERROR_OK) { + LOG_ERROR("cannot read ELF segment headers, read failed"); + return retval; + } + if (read_bytes != elf->segment_count*sizeof(Elf32_Phdr)) { + LOG_ERROR("cannot read ELF segment headers, only partially read"); + return ERROR_FILEIO_OPERATION_FAILED; + } + + /* count useful segments (loadable), ignore BSS section */ + image->num_sections = 0; + for (i = 0; i < elf->segment_count; i++) + if ((field32(elf, + elf->segments32[i].p_type) == PT_LOAD) && + (field32(elf, elf->segments32[i].p_filesz) != 0)) + image->num_sections++; + + if (image->num_sections == 0) { + LOG_ERROR("invalid ELF file, no loadable segments"); return ERROR_IMAGE_FORMAT_ERROR; } - elf->segment_count = field16(elf, elf->header->e_phnum); + /** + * some ELF linkers produce binaries with *all* the program header + * p_paddr fields zero (there can be however one loadable segment + * that has valid physical address 0x0). + * If we have such a binary with more than + * one PT_LOAD header, then use p_vaddr instead of p_paddr + * (ARM ELF standard demands p_paddr = 0 anyway, and BFD + * library uses this approach to workaround zero-initialized p_paddrs + * when obtaining lma - look at elf.c of BDF) + */ + for (nload = 0, i = 0; i < elf->segment_count; i++) + if (elf->segments32[i].p_paddr != 0) + break; + else if ((field32(elf, + elf->segments32[i].p_type) == PT_LOAD) && + (field32(elf, elf->segments32[i].p_memsz) != 0)) + ++nload; + + if (i >= elf->segment_count && nload > 1) + load_to_vaddr = true; + + /* alloc and fill sections array with loadable segments */ + image->sections = malloc(image->num_sections * sizeof(struct imagesection)); + if (!image->sections) { + LOG_ERROR("insufficient memory to perform operation"); + return ERROR_FILEIO_OPERATION_FAILED; + } + + for (i = 0, j = 0; i < elf->segment_count; i++) { + if ((field32(elf, + elf->segments32[i].p_type) == PT_LOAD) && + (field32(elf, elf->segments32[i].p_filesz) != 0)) { + image->sections[j].size = field32(elf, elf->segments32[i].p_filesz); + if (load_to_vaddr) + image->sections[j].base_address = field32(elf, + elf->segments32[i].p_vaddr); + else + image->sections[j].base_address = field32(elf, + elf->segments32[i].p_paddr); + image->sections[j].private = &elf->segments32[i]; + image->sections[j].flags = field32(elf, elf->segments32[i].p_flags); + j++; + } + } + + image->start_address_set = true; + image->start_address = field32(elf, elf->header32->e_entry); + + return ERROR_OK; +} + +static int image_elf64_read_headers(struct image *image) +{ + struct image_elf *elf = image->type_private; + size_t read_bytes; + uint32_t i, j; + int retval; + uint32_t nload; + bool load_to_vaddr = false; + + retval = fileio_seek(elf->fileio, 0); + if (retval != ERROR_OK) { + LOG_ERROR("cannot seek to ELF file header, read failed"); + return retval; + } + + elf->header64 = malloc(sizeof(Elf64_Ehdr)); + + if (!elf->header64) { + LOG_ERROR("insufficient memory to perform operation"); + return ERROR_FILEIO_OPERATION_FAILED; + } + + retval = fileio_read(elf->fileio, sizeof(Elf64_Ehdr), (uint8_t *)elf->header64, &read_bytes); + if (retval != ERROR_OK) { + LOG_ERROR("cannot read ELF file header, read failed"); + return ERROR_FILEIO_OPERATION_FAILED; + } + if (read_bytes != sizeof(Elf64_Ehdr)) { + LOG_ERROR("cannot read ELF file header, only partially read"); + return ERROR_FILEIO_OPERATION_FAILED; + } + + elf->segment_count = field16(elf, elf->header64->e_phnum); if (elf->segment_count == 0) { LOG_ERROR("invalid ELF file, no program headers"); return ERROR_IMAGE_FORMAT_ERROR; } - retval = fileio_seek(elf->fileio, field32(elf, elf->header->e_phoff)); + retval = fileio_seek(elf->fileio, field64(elf, elf->header64->e_phoff)); if (retval != ERROR_OK) { LOG_ERROR("cannot seek to ELF program header table, read failed"); return retval; } - elf->segments = malloc(elf->segment_count*sizeof(Elf32_Phdr)); - if (elf->segments == NULL) { - LOG_ERROR("insufficient memory to perform operation "); + elf->segments64 = malloc(elf->segment_count*sizeof(Elf64_Phdr)); + if (!elf->segments64) { + LOG_ERROR("insufficient memory to perform operation"); return ERROR_FILEIO_OPERATION_FAILED; } - retval = fileio_read(elf->fileio, elf->segment_count*sizeof(Elf32_Phdr), - (uint8_t *)elf->segments, &read_bytes); + retval = fileio_read(elf->fileio, elf->segment_count*sizeof(Elf64_Phdr), + (uint8_t *)elf->segments64, &read_bytes); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF segment headers, read failed"); return retval; } - if (read_bytes != elf->segment_count*sizeof(Elf32_Phdr)) { + if (read_bytes != elf->segment_count*sizeof(Elf64_Phdr)) { LOG_ERROR("cannot read ELF segment headers, only partially read"); return ERROR_FILEIO_OPERATION_FAILED; } @@ -425,11 +544,14 @@ static int image_elf_read_headers(struct image *image) image->num_sections = 0; for (i = 0; i < elf->segment_count; i++) if ((field32(elf, - elf->segments[i].p_type) == PT_LOAD) && - (field32(elf, elf->segments[i].p_filesz) != 0)) + elf->segments64[i].p_type) == PT_LOAD) && + (field64(elf, elf->segments64[i].p_filesz) != 0)) image->num_sections++; - assert(image->num_sections > 0); + if (image->num_sections == 0) { + LOG_ERROR("invalid ELF file, no loadable segments"); + return ERROR_IMAGE_FORMAT_ERROR; + } /** * some ELF linkers produce binaries with *all* the program header @@ -442,44 +564,95 @@ static int image_elf_read_headers(struct image *image) * when obtaining lma - look at elf.c of BDF) */ for (nload = 0, i = 0; i < elf->segment_count; i++) - if (elf->segments[i].p_paddr != 0) + if (elf->segments64[i].p_paddr != 0) break; else if ((field32(elf, - elf->segments[i].p_type) == PT_LOAD) && - (field32(elf, elf->segments[i].p_memsz) != 0)) + elf->segments64[i].p_type) == PT_LOAD) && + (field64(elf, elf->segments64[i].p_memsz) != 0)) ++nload; if (i >= elf->segment_count && nload > 1) - load_to_vaddr = 1; + load_to_vaddr = true; /* alloc and fill sections array with loadable segments */ image->sections = malloc(image->num_sections * sizeof(struct imagesection)); + if (!image->sections) { + LOG_ERROR("insufficient memory to perform operation"); + return ERROR_FILEIO_OPERATION_FAILED; + } + for (i = 0, j = 0; i < elf->segment_count; i++) { if ((field32(elf, - elf->segments[i].p_type) == PT_LOAD) && - (field32(elf, elf->segments[i].p_filesz) != 0)) { - image->sections[j].size = field32(elf, elf->segments[i].p_filesz); + elf->segments64[i].p_type) == PT_LOAD) && + (field64(elf, elf->segments64[i].p_filesz) != 0)) { + image->sections[j].size = field64(elf, elf->segments64[i].p_filesz); if (load_to_vaddr) - image->sections[j].base_address = field32(elf, - elf->segments[i].p_vaddr); + image->sections[j].base_address = field64(elf, + elf->segments64[i].p_vaddr); else - image->sections[j].base_address = field32(elf, - elf->segments[i].p_paddr); - image->sections[j].private = &elf->segments[i]; - image->sections[j].flags = field32(elf, elf->segments[i].p_flags); + image->sections[j].base_address = field64(elf, + elf->segments64[i].p_paddr); + image->sections[j].private = &elf->segments64[i]; + image->sections[j].flags = field64(elf, elf->segments64[i].p_flags); j++; } } - image->start_address_set = 1; - image->start_address = field32(elf, elf->header->e_entry); + image->start_address_set = true; + image->start_address = field64(elf, elf->header64->e_entry); return ERROR_OK; } -static int image_elf_read_section(struct image *image, +static int image_elf_read_headers(struct image *image) +{ + struct image_elf *elf = image->type_private; + size_t read_bytes; + unsigned char e_ident[EI_NIDENT]; + int retval; + + retval = fileio_read(elf->fileio, EI_NIDENT, e_ident, &read_bytes); + if (retval != ERROR_OK) { + LOG_ERROR("cannot read ELF file header, read failed"); + return ERROR_FILEIO_OPERATION_FAILED; + } + if (read_bytes != EI_NIDENT) { + LOG_ERROR("cannot read ELF file header, only partially read"); + return ERROR_FILEIO_OPERATION_FAILED; + } + + if (strncmp((char *)e_ident, ELFMAG, SELFMAG) != 0) { + LOG_ERROR("invalid ELF file, bad magic number"); + return ERROR_IMAGE_FORMAT_ERROR; + } + + elf->endianness = e_ident[EI_DATA]; + if ((elf->endianness != ELFDATA2LSB) + && (elf->endianness != ELFDATA2MSB)) { + LOG_ERROR("invalid ELF file, unknown endianness setting"); + return ERROR_IMAGE_FORMAT_ERROR; + } + + switch (e_ident[EI_CLASS]) { + case ELFCLASS32: + LOG_DEBUG("ELF32 image detected."); + elf->is_64_bit = false; + return image_elf32_read_headers(image); + + case ELFCLASS64: + LOG_DEBUG("ELF64 image detected."); + elf->is_64_bit = true; + return image_elf64_read_headers(image); + + default: + LOG_ERROR("invalid ELF file, only 32/64 bit ELF files are supported"); + return ERROR_IMAGE_FORMAT_ERROR; + } +} + +static int image_elf32_read_section(struct image *image, int section, - uint32_t offset, + target_addr_t offset, uint32_t size, uint8_t *buffer, size_t *size_read) @@ -491,13 +664,13 @@ static int image_elf_read_section(struct image *image, *size_read = 0; - LOG_DEBUG("load segment %d at 0x%" PRIx32 " (sz = 0x%" PRIx32 ")", section, offset, size); + LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size); /* read initialized data in current segment if any */ if (offset < field32(elf, segment->p_filesz)) { /* maximal size present in file for the current segment */ read_size = MIN(size, field32(elf, segment->p_filesz) - offset); - LOG_DEBUG("read elf: size = 0x%zx at 0x%" PRIx32 "", read_size, + LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size, field32(elf, segment->p_offset) + offset); /* read initialized area of the segment */ retval = fileio_seek(elf->fileio, field32(elf, segment->p_offset) + offset); @@ -520,8 +693,66 @@ static int image_elf_read_section(struct image *image, return ERROR_OK; } +static int image_elf64_read_section(struct image *image, + int section, + target_addr_t offset, + uint32_t size, + uint8_t *buffer, + size_t *size_read) +{ + struct image_elf *elf = image->type_private; + Elf64_Phdr *segment = (Elf64_Phdr *)image->sections[section].private; + size_t read_size, really_read; + int retval; + + *size_read = 0; + + LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size); + + /* read initialized data in current segment if any */ + if (offset < field64(elf, segment->p_filesz)) { + /* maximal size present in file for the current segment */ + read_size = MIN(size, field64(elf, segment->p_filesz) - offset); + LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size, + field64(elf, segment->p_offset) + offset); + /* read initialized area of the segment */ + retval = fileio_seek(elf->fileio, field64(elf, segment->p_offset) + offset); + if (retval != ERROR_OK) { + LOG_ERROR("cannot find ELF segment content, seek failed"); + return retval; + } + retval = fileio_read(elf->fileio, read_size, buffer, &really_read); + if (retval != ERROR_OK) { + LOG_ERROR("cannot read ELF segment content, read failed"); + return retval; + } + size -= read_size; + *size_read += read_size; + /* need more data ? */ + if (!size) + return ERROR_OK; + } + + return ERROR_OK; +} + +static int image_elf_read_section(struct image *image, + int section, + target_addr_t offset, + uint32_t size, + uint8_t *buffer, + size_t *size_read) +{ + struct image_elf *elf = image->type_private; + + if (elf->is_64_bit) + return image_elf64_read_section(image, section, offset, size, buffer, size_read); + else + return image_elf32_read_section(image, section, offset, size, buffer, size_read); +} + static int image_mot_buffer_complete_inner(struct image *image, - char *lpszLine, + char *lpsz_line, struct imagesection *section) { struct image_mot *mot = image->type_private; @@ -529,7 +760,6 @@ static int image_mot_buffer_complete_inner(struct image *image, uint32_t full_address; uint32_t cooked_bytes; bool end_rec = false; - int i; /* we can't determine the number of sections that we'll have to create ahead of time, * so we locally hold them until parsing is finished */ @@ -551,7 +781,7 @@ static int image_mot_buffer_complete_inner(struct image *image, section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; - while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { + while (fileio_fgets(fileio, 1023, lpsz_line) == ERROR_OK) { uint32_t count; uint32_t address; uint32_t record_type; @@ -560,11 +790,11 @@ static int image_mot_buffer_complete_inner(struct image *image, uint32_t bytes_read = 0; /* skip comments and blank lines */ - if ((lpszLine[0] == '#') || (strlen(lpszLine + strspn(lpszLine, "\n\t\r ")) == 0)) + if ((lpsz_line[0] == '#') || (strlen(lpsz_line + strspn(lpsz_line, "\n\t\r ")) == 0)) continue; /* get record type and record length */ - if (sscanf(&lpszLine[bytes_read], "S%1" SCNx32 "%2" SCNx32, &record_type, + if (sscanf(&lpsz_line[bytes_read], "S%1" SCNx32 "%2" SCNx32, &record_type, &count) != 2) return ERROR_IMAGE_FORMAT_ERROR; @@ -576,18 +806,18 @@ static int image_mot_buffer_complete_inner(struct image *image, if (record_type == 0) { /* S0 - starting record (optional) */ - int iValue; + int value; while (count-- > 0) { - sscanf(&lpszLine[bytes_read], "%2x", &iValue); - cal_checksum += (uint8_t)iValue; + sscanf(&lpsz_line[bytes_read], "%2x", &value); + cal_checksum += (uint8_t)value; bytes_read += 2; } } else if (record_type >= 1 && record_type <= 3) { switch (record_type) { case 1: /* S1 - 16 bit address data record */ - sscanf(&lpszLine[bytes_read], "%4" SCNx32, &address); + sscanf(&lpsz_line[bytes_read], "%4" SCNx32, &address); cal_checksum += (uint8_t)(address >> 8); cal_checksum += (uint8_t)address; bytes_read += 4; @@ -596,7 +826,7 @@ static int image_mot_buffer_complete_inner(struct image *image, case 2: /* S2 - 24 bit address data record */ - sscanf(&lpszLine[bytes_read], "%6" SCNx32, &address); + sscanf(&lpsz_line[bytes_read], "%6" SCNx32, &address); cal_checksum += (uint8_t)(address >> 16); cal_checksum += (uint8_t)(address >> 8); cal_checksum += (uint8_t)address; @@ -606,7 +836,7 @@ static int image_mot_buffer_complete_inner(struct image *image, case 3: /* S3 - 32 bit address data record */ - sscanf(&lpszLine[bytes_read], "%8" SCNx32, &address); + sscanf(&lpsz_line[bytes_read], "%8" SCNx32, &address); cal_checksum += (uint8_t)(address >> 24); cal_checksum += (uint8_t)(address >> 16); cal_checksum += (uint8_t)(address >> 8); @@ -635,7 +865,7 @@ static int image_mot_buffer_complete_inner(struct image *image, while (count-- > 0) { unsigned value; - sscanf(&lpszLine[bytes_read], "%2x", &value); + sscanf(&lpsz_line[bytes_read], "%2x", &value); mot->buffer[cooked_bytes] = (uint8_t)value; cal_checksum += (uint8_t)mot->buffer[cooked_bytes]; bytes_read += 2; @@ -648,7 +878,7 @@ static int image_mot_buffer_complete_inner(struct image *image, uint32_t dummy; while (count-- > 0) { - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); + sscanf(&lpsz_line[bytes_read], "%2" SCNx32, &dummy); cal_checksum += (uint8_t)dummy; bytes_read += 2; } @@ -658,7 +888,7 @@ static int image_mot_buffer_complete_inner(struct image *image, /* copy section information */ image->sections = malloc(sizeof(struct imagesection) * image->num_sections); - for (i = 0; i < image->num_sections; i++) { + for (unsigned int i = 0; i < image->num_sections; i++) { image->sections[i].private = section[i].private; image->sections[i].base_address = section[i].base_address; image->sections[i].size = section[i].size; @@ -673,7 +903,7 @@ static int image_mot_buffer_complete_inner(struct image *image, } /* account for checksum, will always be 0xFF */ - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); + sscanf(&lpsz_line[bytes_read], "%2" SCNx32, &checksum); cal_checksum += (uint8_t)checksum; if (cal_checksum != 0xFF) { @@ -684,7 +914,7 @@ static int image_mot_buffer_complete_inner(struct image *image, if (end_rec) { end_rec = false; - LOG_WARNING("continuing after end-of-file record: %.40s", lpszLine); + LOG_WARNING("continuing after end-of-file record: %.40s", lpsz_line); } } } @@ -703,23 +933,23 @@ static int image_mot_buffer_complete_inner(struct image *image, */ static int image_mot_buffer_complete(struct image *image) { - char *lpszLine = malloc(1023); - if (lpszLine == NULL) { + char *lpsz_line = malloc(1023); + if (!lpsz_line) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } struct imagesection *section = malloc(sizeof(struct imagesection) * IMAGE_MAX_SECTIONS); - if (section == NULL) { - free(lpszLine); + if (!section) { + free(lpsz_line); LOG_ERROR("Out of memory"); return ERROR_FAIL; } int retval; - retval = image_mot_buffer_complete_inner(image, lpszLine, section); + retval = image_mot_buffer_complete_inner(image, lpsz_line, section); free(section); - free(lpszLine); + free(lpsz_line); return retval; } @@ -739,12 +969,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; @@ -759,14 +990,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; @@ -775,17 +1006,17 @@ 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); - if (target == NULL) { + if (!target) { LOG_ERROR("target '%s' not defined", url); return ERROR_FAIL; } @@ -810,40 +1041,44 @@ 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; - image->base_address_set = 0; + image->base_address_set = false; image->sections = NULL; image->type_private = NULL; } if (image->base_address_set) { /* relocate */ - int section; - for (section = 0; section < image->num_sections; section++) + for (unsigned int section = 0; section < image->num_sections; section++) image->sections[section].base_address += image->base_address; /* we're done relocating. The two statements below are mainly * for documentation purposes: stop anyone from empirically * thinking they should use these values henceforth. */ image->base_address = 0; - image->base_address_set = 0; + image->base_address_set = false; } return retval; + +free_mem_on_error: + free(image->type_private); + image->type_private = NULL; + return retval; }; int image_read_section(struct image *image, int section, - uint32_t offset, + target_addr_t offset, uint32_t size, uint8_t *buffer, size_t *size_read) @@ -853,7 +1088,7 @@ int image_read_section(struct image *image, /* don't read past the end of a section */ if (offset + size > image->sections[section].size) { LOG_DEBUG( - "read past end of section: 0x%8.8" PRIx32 " + 0x%8.8" PRIx32 " > 0x%8.8" PRIx32 "", + "read past end of section: 0x%8.8" TARGET_PRIxADDR " + 0x%8.8" PRIx32 " > 0x%8.8" PRIx32 "", offset, size, image->sections[section].size); @@ -881,9 +1116,9 @@ int image_read_section(struct image *image, *size_read = size; return ERROR_OK; - } else if (image->type == IMAGE_ELF) + } else if (image->type == IMAGE_ELF) { return image_elf_read_section(image, section, offset, size, buffer, size_read); - else if (image->type == IMAGE_MEMORY) { + } else if (image->type == IMAGE_MEMORY) { struct image_memory *image_memory = image->type_private; uint32_t address = image->sections[section].base_address + offset; @@ -936,7 +1171,7 @@ int image_read_section(struct image *image, return ERROR_OK; } -int image_add_section(struct image *image, uint32_t base, uint32_t size, int flags, uint8_t const *data) +int image_add_section(struct image *image, target_addr_t base, uint32_t size, uint64_t flags, uint8_t const *data) { struct imagesection *section; @@ -991,11 +1226,19 @@ void image_close(struct image *image) fileio_close(image_elf->fileio); - free(image_elf->header); - image_elf->header = NULL; + if (image_elf->is_64_bit) { + free(image_elf->header64); + image_elf->header64 = NULL; - free(image_elf->segments); - image_elf->segments = NULL; + free(image_elf->segments64); + image_elf->segments64 = NULL; + } else { + free(image_elf->header32); + image_elf->header32 = NULL; + + free(image_elf->segments32); + image_elf->segments32 = NULL; + } } else if (image->type == IMAGE_MEMORY) { struct image_memory *image_memory = image->type_private; @@ -1009,9 +1252,7 @@ void image_close(struct image *image) free(image_mot->buffer); image_mot->buffer = NULL; } else if (image->type == IMAGE_BUILDER) { - int i; - - for (i = 0; i < image->num_sections; i++) { + for (unsigned int i = 0; i < image->num_sections; i++) { free(image->sections[i].private); image->sections[i].private = NULL; } @@ -1024,7 +1265,7 @@ void image_close(struct image *image) image->sections = NULL; } -int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, uint32_t *checksum) +int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes, uint32_t *checksum) { uint32_t crc = 0xffffffff; LOG_DEBUG("Calculating checksum"); @@ -1055,9 +1296,11 @@ int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, uint32_t *checksu crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buffer++) & 255]; } keep_alive(); + if (openocd_is_shutdown_pending()) + return ERROR_SERVER_INTERRUPTED; } - LOG_DEBUG("Calculating checksum done"); + LOG_DEBUG("Calculating checksum done; checksum=0x%" PRIx32, crc); *checksum = crc; return ERROR_OK; diff --git a/src/target/image.h b/src/target/image.h index 9907a5f3fb..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 * @@ -8,24 +10,15 @@ * 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) 2018 by Advantest * + * florian.meister@advantest.com * ***************************************************************************/ #ifndef OPENOCD_TARGET_IMAGE_H #define OPENOCD_TARGET_IMAGE_H #include <helper/fileio.h> +#include <helper/replacements.h> #ifdef HAVE_ELF_H #include <elf.h> @@ -48,18 +41,18 @@ enum image_type { struct imagesection { target_addr_t base_address; uint32_t size; - int flags; + uint64_t flags; void *private; /* private data */ }; struct image { enum image_type type; /* image type (plain, ihex, ...) */ void *type_private; /* type private data */ - int num_sections; /* number of sections contained in the image */ + unsigned int num_sections; /* number of sections contained in the image */ struct imagesection *sections; /* array of sections */ - int base_address_set; /* whether the image has a base address set (for relocation purposes) */ + bool base_address_set; /* whether the image has a base address set (for relocation purposes) */ long long base_address; /* base address, if one is set */ - int start_address_set; /* whether the image has a start address (entry point) associated */ + bool start_address_set; /* whether the image has a start address (entry point) associated */ uint32_t start_address; /* start address, if one is set */ }; @@ -80,8 +73,15 @@ struct image_memory { struct image_elf { struct fileio *fileio; - Elf32_Ehdr *header; - Elf32_Phdr *segments; + bool is_64_bit; + union { + Elf32_Ehdr *header32; + Elf64_Ehdr *header64; + }; + union { + Elf32_Phdr *segments32; + Elf64_Phdr *segments64; + }; uint32_t segment_count; uint8_t endianness; }; @@ -92,14 +92,14 @@ struct image_mot { }; int image_open(struct image *image, const char *url, const char *type_string); -int image_read_section(struct image *image, int section, uint32_t offset, +int image_read_section(struct image *image, int section, target_addr_t offset, uint32_t size, uint8_t *buffer, size_t *size_read); void image_close(struct image *image); -int image_add_section(struct image *image, uint32_t base, uint32_t size, - int flags, uint8_t const *data); +int image_add_section(struct image *image, target_addr_t base, uint32_t size, + uint64_t flags, uint8_t const *data); -int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, +int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes, uint32_t *checksum); #define ERROR_IMAGE_FORMAT_ERROR (-1400) diff --git a/src/target/lakemont.c b/src/target/lakemont.c index 31b521b3a8..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) @@ -227,7 +216,7 @@ static int irscan(struct target *t, uint8_t *out, { int retval = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); - if (NULL == t->tap) { + if (!t->tap) { retval = ERROR_FAIL; LOG_ERROR("%s invalid target tap", __func__); return retval; @@ -260,7 +249,7 @@ static int drscan(struct target *t, uint8_t *out, uint8_t *in, uint8_t len) int retval = ERROR_OK; uint64_t data = 0; struct x86_32_common *x86_32 = target_to_x86_32(t); - if (NULL == t->tap) { + if (!t->tap) { retval = ERROR_FAIL; LOG_ERROR("%s invalid target tap", __func__); return retval; @@ -283,7 +272,7 @@ static int drscan(struct target *t, uint8_t *out, uint8_t *in, uint8_t len) return retval; } } - if (in != NULL) { + if (in) { if (len >= 8) { for (int n = (len / 8) - 1 ; n >= 0; n--) data = (data << 8) + *(in+n); @@ -381,7 +370,7 @@ struct reg_cache *lakemont_build_reg_cache(struct target *t) struct reg_feature *feature; int i; - if (cache == NULL || reg_list == NULL || arch_info == NULL) { + if (!cache || !reg_list || !arch_info) { free(cache); free(reg_list); free(arch_info); @@ -611,7 +600,7 @@ static int read_all_core_hw_regs(struct target *t) unsigned i; struct x86_32_common *x86_32 = target_to_x86_32(t); for (i = 0; i < (x86_32->cache->num_regs); i++) { - if (NOT_AVAIL_REG == regs[i].pm_idx) + if (regs[i].pm_idx == NOT_AVAIL_REG) continue; err = read_hw_reg(t, regs[i].id, ®val, 1); if (err != ERROR_OK) { @@ -630,7 +619,7 @@ static int write_all_core_hw_regs(struct target *t) unsigned i; struct x86_32_common *x86_32 = target_to_x86_32(t); for (i = 0; i < (x86_32->cache->num_regs); i++) { - if (NOT_AVAIL_REG == regs[i].pm_idx) + if (regs[i].pm_idx == NOT_AVAIL_REG) continue; err = write_hw_reg(t, i, 0, 1); if (err != ERROR_OK) { @@ -940,7 +929,7 @@ int lakemont_poll(struct target *t) */ struct breakpoint *bp = NULL; bp = breakpoint_find(t, eip-1); - if (bp != NULL) { + if (bp) { t->debug_reason = DBG_REASON_BREAKPOINT; if (bp->type == BKPT_SOFT) { /* The EIP is now pointing the next byte after the @@ -1013,7 +1002,7 @@ int lakemont_resume(struct target *t, int current, target_addr_t address, /* running away for a software breakpoint needs some special handling */ uint32_t eip = buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32); bp = breakpoint_find(t, eip); - if (bp != NULL /*&& bp->type == BKPT_SOFT*/) { + if (bp /*&& bp->type == BKPT_SOFT*/) { /* the step will step over the breakpoint */ if (lakemont_step(t, 0, 0, 1) != ERROR_OK) { LOG_ERROR("%s stepping over a software breakpoint at 0x%08" PRIx32 " " @@ -1024,12 +1013,12 @@ int lakemont_resume(struct target *t, int current, target_addr_t address, /* if breakpoints are enabled, we need to redirect these into probe mode */ struct breakpoint *activeswbp = t->breakpoints; - while (activeswbp != NULL && activeswbp->set == 0) + while (activeswbp && !activeswbp->is_set) activeswbp = activeswbp->next; struct watchpoint *activehwbp = t->watchpoints; - while (activehwbp != NULL && activehwbp->set == 0) + while (activehwbp && !activehwbp->is_set) activehwbp = activehwbp->next; - if (activeswbp != NULL || activehwbp != NULL) + if (activeswbp || activehwbp) buf_set_u32(x86_32->cache->reg_list[PMCR].value, 0, 32, 1); if (do_resume(t) != ERROR_OK) return ERROR_FAIL; @@ -1054,7 +1043,7 @@ int lakemont_step(struct target *t, int current, if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; bp = breakpoint_find(t, eip); - if (retval == ERROR_OK && bp != NULL/*&& bp->type == BKPT_SOFT*/) { + if (retval == ERROR_OK && bp/*&& bp->type == BKPT_SOFT*/) { /* TODO: This should only be done for software breakpoints. * Stepping from hardware breakpoints should be possible with the resume flag * Needs testing. @@ -1070,7 +1059,8 @@ int lakemont_step(struct target *t, int current, LOG_DEBUG("EFLAGS [TF] [RF] bits set=0x%08" PRIx32 ", PMCR=0x%08" PRIx32 ", EIP=0x%08" PRIx32, eflags, pmcr, eip); - tapstatus = get_tapstatus(t); + /* Returned value unused. Can this line be removed? */ + get_tapstatus(t); t->debug_reason = DBG_REASON_SINGLESTEP; t->state = TARGET_DEBUG_RUNNING; @@ -1105,7 +1095,7 @@ int lakemont_step(struct target *t, int current, /* try to re-apply the breakpoint, even of step failed * TODO: When a bp was set, we should try to stop the target - fix the return above */ - if (bp != NULL/*&& bp->type == BKPT_SOFT*/) { + if (bp/*&& bp->type == BKPT_SOFT*/) { /* TODO: This should only be done for software breakpoints. * Stepping from hardware breakpoints should be possible with the resume flag * Needs testing. @@ -1128,7 +1118,7 @@ static int lakemont_reset_break(struct target *t) /* prepare resetbreak setting the proper bits in CLTAPC_CPU_VPREQ */ x86_32->curr_tap = jtag_tap_by_position(1); - if (x86_32->curr_tap == NULL) { + if (!x86_32->curr_tap) { x86_32->curr_tap = saved_tap; LOG_ERROR("%s could not select quark_x10xx.cltap", __func__); return ERROR_FAIL; 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 5e1218837e..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" @@ -184,7 +175,7 @@ static int ls1_sap_read_memory(struct target *target, target_addr_t address, LOG_DEBUG("Reading memory at physical address 0x%" TARGET_PRIxADDR "; size %" PRIu32 "; count %" PRIu32, address, size, count); - if (count == 0 || buffer == NULL) + if (count == 0 || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; ls1_sap_set_addr_high(target->tap, 0); @@ -207,7 +198,7 @@ static int ls1_sap_write_memory(struct target *target, target_addr_t address, "; size %" PRIu32 "; count %" PRIu32, address, size, count); - if (count == 0 || buffer == NULL) + if (count == 0 || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; ls1_sap_set_addr_high(target->tap, 0); diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index 7ed41c63c3..61a9475e64 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" @@ -18,15 +10,18 @@ #include "target.h" #include "target_type.h" -#include "arm.h" #include "arm_adi_v5.h" +#include "register.h" #include <jtag/jtag.h> +#define MEM_AP_COMMON_MAGIC 0x4DE4DA50 + struct mem_ap { - struct arm arm; + 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) @@ -35,7 +30,7 @@ static int mem_ap_target_create(struct target *target, Jim_Interp *interp) struct adiv5_private_config *pc; pc = (struct adiv5_private_config *)target->private_config; - if (pc == NULL) + if (!pc) return ERROR_FAIL; if (pc->ap_num == DP_APSEL_INVALID) { @@ -44,17 +39,20 @@ static int mem_ap_target_create(struct target *target, Jim_Interp *interp) } mem_ap = calloc(1, sizeof(struct mem_ap)); - if (mem_ap == NULL) { + if (!mem_ap) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } mem_ap->ap_num = pc->ap_num; - mem_ap->arm.common_magic = ARM_COMMON_MAGIC; - mem_ap->arm.dap = pc->dap; + mem_ap->common_magic = MEM_AP_COMMON_MAGIC; + mem_ap->dap = pc->dap; target->arch_info = mem_ap; + if (!target->gdb_port_override) + target->gdb_port_override = strdup("disabled"); + return ERROR_OK; } @@ -62,13 +60,19 @@ static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *ta { LOG_DEBUG("%s", __func__); target->state = TARGET_UNKNOWN; + target->debug_reason = DBG_REASON_UNDEFINED; return ERROR_OK; } 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; @@ -82,8 +86,10 @@ static int mem_ap_arch_state(struct target *target) static int mem_ap_poll(struct target *target) { - if (target->state == TARGET_UNKNOWN) + if (target->state == TARGET_UNKNOWN) { target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } return ERROR_OK; } @@ -92,6 +98,8 @@ static int mem_ap_halt(struct target *target) { LOG_DEBUG("%s", __func__); target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_DBGRQ; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } @@ -100,6 +108,7 @@ static int mem_ap_resume(struct target *target, int current, target_addr_t addre { LOG_DEBUG("%s", __func__); target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; return ERROR_OK; } @@ -108,12 +117,15 @@ static int mem_ap_step(struct target *target, int current, target_addr_t address { LOG_DEBUG("%s", __func__); target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_DBGRQ; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } static int mem_ap_assert_reset(struct target *target) { target->state = TARGET_RESET; + target->debug_reason = DBG_REASON_UNDEFINED; LOG_DEBUG("%s", __func__); return ERROR_OK; @@ -124,9 +136,16 @@ 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->arm.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; return mem_ap_init(mem_ap->ap); } @@ -135,15 +154,85 @@ static int mem_ap_examine(struct target *target) static int mem_ap_deassert_reset(struct target *target) { - if (target->reset_halt) + if (target->reset_halt) { target->state = TARGET_HALTED; - else + target->debug_reason = DBG_REASON_DBGRQ; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } else { target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } LOG_DEBUG("%s", __func__); return ERROR_OK; } +static int mem_ap_reg_get(struct reg *reg) +{ + return ERROR_OK; +} + +static int mem_ap_reg_set(struct reg *reg, uint8_t *buf) +{ + return ERROR_OK; +} + +static struct reg_arch_type mem_ap_reg_arch_type = { + .get = mem_ap_reg_get, + .set = mem_ap_reg_set, +}; + +static const char *mem_ap_get_gdb_arch(const struct target *target) +{ + return "arm"; +} + +/* + * Dummy ARM register emulation: + * reg[0..15]: 32 bits, r0~r12, sp, lr, pc + * reg[16..23]: 96 bits, f0~f7 + * reg[24]: 32 bits, fps + * reg[25]: 32 bits, cpsr + * + * GDB requires only reg[0..15] + */ +#define NUM_REGS 26 +#define NUM_GDB_REGS 16 +#define MAX_REG_SIZE 96 +#define REG_SIZE(n) ((((n) >= 16) && ((n) < 24)) ? 96 : 32) + +struct mem_ap_alloc_reg_list { + /* reg_list must be the first field */ + struct reg *reg_list[NUM_REGS]; + struct reg regs[NUM_REGS]; + uint8_t regs_value[MAX_REG_SIZE / 8]; +}; + +static int mem_ap_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) +{ + struct mem_ap_alloc_reg_list *mem_ap_alloc = calloc(1, sizeof(struct mem_ap_alloc_reg_list)); + if (!mem_ap_alloc) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + *reg_list = mem_ap_alloc->reg_list; + *reg_list_size = (reg_class == REG_CLASS_ALL) ? NUM_REGS : NUM_GDB_REGS; + struct reg *regs = mem_ap_alloc->regs; + + for (int i = 0; i < NUM_REGS; i++) { + regs[i].number = i; + regs[i].value = mem_ap_alloc->regs_value; + regs[i].size = REG_SIZE(i); + regs[i].exist = true; + regs[i].type = &mem_ap_reg_arch_type; + (*reg_list)[i] = ®s[i]; + } + + return ERROR_OK; +} + static int mem_ap_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { @@ -152,7 +241,7 @@ static int mem_ap_read_memory(struct target *target, target_addr_t address, LOG_DEBUG("Reading memory at physical address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); - if (count == 0 || buffer == NULL) + if (count == 0 || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; return mem_ap_read_buf(mem_ap->ap, buffer, size, count, address); @@ -167,7 +256,7 @@ static int mem_ap_write_memory(struct target *target, target_addr_t address, LOG_DEBUG("Writing memory at physical address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); - if (count == 0 || buffer == NULL) + if (count == 0 || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; return mem_ap_write_buf(mem_ap->ap, buffer, size, count, address); @@ -192,6 +281,9 @@ struct target_type mem_ap_target = { .assert_reset = mem_ap_assert_reset, .deassert_reset = mem_ap_deassert_reset, + .get_gdb_arch = mem_ap_get_gdb_arch, + .get_gdb_reg_list = mem_ap_get_gdb_reg_list, + .read_memory = mem_ap_read_memory, .write_memory = mem_ap_write_memory, }; diff --git a/src/target/mips32.c b/src/target/mips32.c index e1f2b2832b..81faab72da 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,154 @@ 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}; + + +#define zero 0 + +#define AT 1 + +#define v0 2 +#define v1 3 + +#define a0 4 +#define a1 5 +#define a2 6 +#define a3 7 +#define t0 8 +#define t1 9 +#define t2 10 +#define t3 11 +#define t4 12 +#define t5 13 +#define t6 14 +#define t7 15 +#define ta0 12 /* alias for $t4 */ +#define ta1 13 /* alias for $t5 */ +#define ta2 14 /* alias for $t6 */ +#define ta3 15 /* alias for $t7 */ + +#define s0 16 +#define s1 17 +#define s2 18 +#define s3 19 +#define s4 20 +#define s5 21 +#define s6 22 +#define s7 23 +#define s8 30 /* == fp */ + +#define t8 24 +#define t9 25 +#define k0 26 +#define k1 27 + +#define gp 28 + +#define sp 29 +#define fp 30 +#define ra 31 + + +static const struct { + const char *name; +} mips32_dsp_regs[MIPS32NUMDSPREGS] = { + { "hi0"}, + { "hi1"}, + { "hi2"}, + { "hi3"}, + { "lo0"}, + { "lo1"}, + { "lo2"}, + { "lo3"}, + { "control"}, +}; static int mips32_get_core_reg(struct reg *reg) { @@ -184,21 +241,86 @@ 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; return ERROR_OK; } +/** + * mips32_set_all_fpr_width - Set the width of all floating-point registers + * @param[in] mips32: MIPS32 common structure + * @param[in] fp64: Flag indicating whether to set the width to 64 bits (double precision) + * + * @brief Sets the width of all floating-point registers based on the specified flag. + */ +static void mips32_set_all_fpr_width(struct mips32_common *mips32, bool fp64) +{ + struct reg_cache *cache = mips32->core_cache; + struct reg *reg_list = cache->reg_list; + int i; + + for (i = MIPS32_REGLIST_FP_INDEX; i < (MIPS32_REGLIST_FP_INDEX + MIPS32_REG_FP_COUNT); i++) { + reg_list[i].size = fp64 ? 64 : 32; + reg_list[i].reg_data_type->type = fp64 ? REG_TYPE_IEEE_DOUBLE : REG_TYPE_IEEE_SINGLE; + } +} + +/** + * mips32_detect_fpr_mode_change - Detect changes in floating-point register mode + * @param[in] mips32: MIPS32 common structure + * @param[in] cp0_status: Value of the CP0 status register + * + * @brief Detects changes in the floating-point register mode based on the CP0 status register. + * If changes are detected, it updates the internal state + * and logs a warning message indicating the mode change. + */ +static void mips32_detect_fpr_mode_change(struct mips32_common *mips32, uint32_t cp0_status) +{ + if (!mips32->fp_imp) + return; + + /* CP0.Status.FR indicates the working mode of floating-point register. + * When FP = 0, fpr can contain any 32bit data type, + * 64bit data types are stored in even-odd register pairs. + * When FP = 1, fpr can contain any data types.*/ + bool fpu_in_64bit = ((cp0_status & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0); + + /* CP0.Status.CU1 indicated whether CoProcessor1(which is FPU) is present. */ + bool fp_enabled = ((cp0_status & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0); + + if (mips32->fpu_in_64bit != fpu_in_64bit) { + mips32->fpu_in_64bit = fpu_in_64bit; + mips32_set_all_fpr_width(mips32, fpu_in_64bit); + LOG_WARNING("** FP mode changed to %sbit, you must reconnect GDB **", fpu_in_64bit ? "64" : "32"); + } + + if (mips32->fpu_enabled != fp_enabled) { + mips32->fpu_enabled = fp_enabled; + const char *s = fp_enabled ? "enabled" : "disabled"; + LOG_WARNING("** FP is %s, register update %s **", s, s); + } +} + 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 +328,42 @@ 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); + if (cnum == MIPS32_REG_C0_STATUS_INDEX) + mips32_detect_fpr_mode_change(mips32, 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 +371,31 @@ 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; + if (cnum == MIPS32_REG_C0_STATUS_INDEX) + mips32_detect_fpr_mode_change(mips32, 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 +425,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 +447,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 +454,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 +464,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 +501,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 +558,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 +580,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 +592,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 +612,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; } @@ -473,7 +636,7 @@ int mips32_run_algorithm(struct target *target, int num_mem_params, if (reg_params[i].direction == PARAM_IN) continue; - struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0); + struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); @@ -507,7 +670,7 @@ int mips32_run_algorithm(struct target *target, int num_mem_params, for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { - struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0); + struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; @@ -704,15 +867,267 @@ 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 fir_value, status_value; + bool fpu_in_64bit, fp_enabled; + + 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; + } + + fpu_in_64bit = (status_value & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0; + fp_enabled = (status_value & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0; + if (fp_enabled) { + retval = mips32_cp1_control_read(ejtag_info, &fir_value, 0); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read cp1 FIR register"); + return retval; + } + + if ((fir_value >> MIPS32_CP1_FIR_F64_SHIFT) & 0x1) + fp_imp++; + } else { + /* This is the only condition that writes to buf */ + snprintf(buf, sizeof(buf), "yes, disabled"); + fp_imp = MIPS32_FP_IMP_UNKNOWN; + } + + mips32->fpu_in_64bit = fpu_in_64bit; + mips32->fpu_enabled = fp_enabled; + + mips32_set_all_fpr_width(mips32, fpu_in_64bit); + + /* If fpu is not disabled, print out more information */ + if (!buf[0]) + snprintf(buf, sizeof(buf), "yes, %sbit (%s, working in %sbit)", + fp_imp == MIPS32_FP_IMP_64 ? "64" : "32", + fp_enabled ? "enabled" : "disabled", + fpu_in_64bit ? "64" : "32"); + + 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 +1142,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 +1258,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,16 +1360,840 @@ 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, 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; + + + retval = mips32_verify_pointer(CMD, mips32); + if (retval != ERROR_OK) + return retval; + + if (target->state != TARGET_HALTED) { + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; + } + + 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_dsp_enable - Enable access to DSP registers + * @param[in] ctx: Context information for the pracc queue + * @param[in] isa: Instruction Set Architecture identifier + * + * @brief Enables access to DSP registers by modifying the status register. + * + * This function adds instructions to the context queue for enabling + * access to DSP registers by modifying the status register. + */ +static void mips32_dsp_enable(struct pracc_queue_info *ctx, int isa) +{ + /* Save Status Register */ + /* move status to $9 (t1) 2*/ + pracc_add(ctx, 0, MIPS32_MFC0(isa, 9, 12, 0)); + + /* Read it again in order to modify it */ + /* move status to $0 (t0) 3*/ + pracc_add(ctx, 0, MIPS32_MFC0(isa, 8, 12, 0)); + + /* Enable access to DSP registers by setting MX bit in status register */ + /* $15 = MIPS32_PRACC_STACK 4/5/6*/ + pracc_add(ctx, 0, MIPS32_LUI(isa, 15, UPPER16(MIPS32_DSP_ENABLE))); + pracc_add(ctx, 0, MIPS32_ORI(isa, 15, 15, LOWER16(MIPS32_DSP_ENABLE))); + pracc_add(ctx, 0, MIPS32_ISA_OR(8, 8, 15)); + /* Enable DSP - update status registers 7*/ + pracc_add(ctx, 0, MIPS32_MTC0(isa, 8, 12, 0)); +} + +/** + * mips32_dsp_restore - Restore DSP status registers to the previous setting + * @param[in] ctx: Context information pracc queue + * @param[in] isa: isa identifier + * + * @brief Restores the DSP status registers to their previous setting. + * + * This function adds instructions to the context queue for restoring the DSP + * status registers to their values before the operation. + */ +static void mips32_dsp_restore(struct pracc_queue_info *ctx, int isa) +{ + pracc_add(ctx, 0, MIPS32_MTC0(isa, 9, 12, 0)); /* Restore status registers to previous setting */ + pracc_add(ctx, 0, MIPS32_NOP); /* nop */ +} + +/** + * mips32_pracc_read_dsp_reg - Read a value from a MIPS32 DSP register + * @param[in] ejtag_info: EJTAG information structure + * @param[out] val: Pointer to store the read value + * @param[in] reg: Index of the DSP register to read + * + * @brief Reads the value from the specified MIPS32 DSP register using EJTAG access. + * + * This function initiates a sequence of instructions to read the value from the + * specified DSP register. It will enable dsp module if its not enabled + * and restoring the status registers after the read operation. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_pracc_read_dsp_reg(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t reg) +{ + int isa = 0; + + struct pracc_queue_info ctx = { + .max_code = 48, + .ejtag_info = ejtag_info + }; + + uint32_t dsp_read_code[] = { + MIPS32_MFHI(isa, t0), /* mfhi t0 ($ac0) - OPCODE - 0x00004010 */ + MIPS32_DSP_MFHI(t0, 1), /* mfhi t0,$ac1 - OPCODE - 0x00204010 */ + MIPS32_DSP_MFHI(t0, 2), /* mfhi t0,$ac2 - OPCODE - 0x00404010 */ + MIPS32_DSP_MFHI(t0, 3), /* mfhi t0,$ac3 - OPCODE - 0x00604010*/ + MIPS32_MFLO(isa, t0), /* mflo t0 ($ac0) - OPCODE - 0x00004012 */ + MIPS32_DSP_MFLO(t0, 1), /* mflo t0,$ac1 - OPCODE - 0x00204012 */ + MIPS32_DSP_MFLO(t0, 2), /* mflo t0,$ac2 - OPCODE - 0x00404012 */ + MIPS32_DSP_MFLO(t0, 3), /* mflo t0,$ac3 - OPCODE - 0x00604012 */ + MIPS32_DSP_RDDSP(t0, 0x3F), /* rddsp t0, 0x3f (DSPCtl) - OPCODE - 0x7c3f44b8 */ + }; + + /* Check status register to determine if dsp register access is enabled */ + /* Get status register so it can be restored later */ + + ctx.pracc_list = NULL; + + /* Init context queue */ + pracc_queue_init(&ctx); + + if (ctx.retval != ERROR_OK) + goto exit; + + /* Enables DSP whether its already enabled or not */ + mips32_dsp_enable(&ctx, isa); + + /* move AC or Control to $8 (t0) 8*/ + pracc_add(&ctx, 0, dsp_read_code[reg]); + /* Restore status registers to previous setting */ + mips32_dsp_restore(&ctx, isa); + + /* $15 = MIPS32_PRACC_BASE_ADDR 1*/ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 15, PRACC_UPPER_BASE_ADDR)); + /* store $8 to pracc_out 10*/ + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, MIPS32_SW(isa, 8, PRACC_OUT_OFFSET, 15)); + /* move COP0 DeSave to $15 11*/ + pracc_add(&ctx, 0, MIPS32_MFC0(isa, 15, 31, 0)); + /* restore upper 16 of $8 12*/ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(ejtag_info->reg8))); + /* restore lower 16 of $8 13*/ + pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(ejtag_info->reg8))); + /* restore upper 16 of $9 14*/ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 9, UPPER16(ejtag_info->reg9))); + pracc_add(&ctx, 0, MIPS32_SYNC(isa)); + /* jump to start 18*/ + pracc_add(&ctx, 0, MIPS32_B(isa, NEG16(ctx.code_count + 1))); + /* restore lower 16 of $9 15*/ + pracc_add(&ctx, 0, MIPS32_ORI(isa, 9, 9, LOWER16(ejtag_info->reg9))); + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1); +exit: + pracc_queue_free(&ctx); + return ctx.retval; +} + +/** + * mips32_pracc_write_dsp_reg - Write a value to a MIPS32 DSP register + * @param[in] ejtag_info: EJTAG information structure + * @param[in] val: Value to be written to the register + * @param[in] reg: Index of the DSP register to write + * + * @brief Writes the specified value to the specified MIPS32 DSP register. + * + * This function initiates a sequence of instructions to write the given value to the + * specified DSP register. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_pracc_write_dsp_reg(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t reg) +{ + int isa = 0; + + struct pracc_queue_info ctx = { + .max_code = 48, + .ejtag_info = ejtag_info + }; + + uint32_t dsp_write_code[] = { + MIPS32_MTHI(isa, t0), /* mthi t0 ($ac0) - OPCODE - 0x01000011 */ + MIPS32_DSP_MTHI(t0, 1), /* mthi t0, $ac1 - OPCODE - 0x01000811 */ + MIPS32_DSP_MTHI(t0, 2), /* mthi t0, $ac2 - OPCODE - 0x01001011 */ + MIPS32_DSP_MTHI(t0, 3), /* mthi t0, $ac3 - OPCODE - 0x01001811 */ + MIPS32_MTLO(isa, t0), /* mtlo t0 ($ac0) - OPCODE - 0x01000013 */ + MIPS32_DSP_MTLO(t0, 1), /* mtlo t0, $ac1 - OPCODE - 0x01000813 */ + MIPS32_DSP_MTLO(t0, 2), /* mtlo t0, $ac2 - OPCODE - 0x01001013 */ + MIPS32_DSP_MTLO(t0, 3), /* mtlo t0, $ac3 - OPCODE - 0x01001813 */ + MIPS32_DSP_WRDSP(t0, 0x1F), /* wrdsp t0, 0x1f (DSPCtl) - OPCODE - 0x7d00fcf8*/ + }; + + /* Init context queue */ + pracc_queue_init(&ctx); + if (ctx.retval != ERROR_OK) + goto exit; + + /* Enables DSP whether its already enabled or not */ + mips32_dsp_enable(&ctx, isa); + + /* Load val to $8 (t0) */ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(val))); + pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(val))); + + /* move AC or Control to $8 (t0) */ + pracc_add(&ctx, 0, dsp_write_code[reg]); + + /* nop, delay in order to ensure write */ + pracc_add(&ctx, 0, MIPS32_NOP); + /* Restore status registers to previous setting */ + mips32_dsp_restore(&ctx, isa); + + /* move COP0 DeSave to $15 */ + pracc_add(&ctx, 0, MIPS32_MFC0(isa, 15, 31, 0)); + + /* restore $8 */ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(ejtag_info->reg8))); + pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(ejtag_info->reg8))); + + /* restore upper 16 of $9 */ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 9, UPPER16(ejtag_info->reg9))); + + /* jump to start */ + pracc_add(&ctx, 0, MIPS32_B(isa, NEG16(ctx.code_count + 1))); + /* restore lower 16 of $9 */ + pracc_add(&ctx, 0, MIPS32_ORI(isa, 9, 9, LOWER16(ejtag_info->reg9))); + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); +exit: + pracc_queue_free(&ctx); + return ctx.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; + + 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, &config5, 16, 5); + if (retval != ERROR_OK) + return retval; + + /* 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_dsp_find_register_by_name - Find DSP register index by name + * @param[in] reg_name: Name of the DSP register to find + * + * @brief Searches for a DSP register by name and returns its index. + * If no match is found, it returns MIPS32NUMDSPREGS. + * + * @return Index of the found register or MIPS32NUMDSPREGS if not found. + */ +static int mips32_dsp_find_register_by_name(const char *reg_name) +{ + if (reg_name) + for (int i = 0; i < MIPS32NUMDSPREGS; i++) { + if (strcmp(mips32_dsp_regs[i].name, reg_name) == 0) + return i; + } + return MIPS32NUMDSPREGS; +} + +/** + * mips32_dsp_get_all_regs - Get values of all MIPS32 DSP registers + * @param[in] cmd: Command invocation context + * @param[in] ejtag_info: EJTAG information structure + * + * @brief This function iterates through all DSP registers, reads their values, + * and prints each register name along with its corresponding value. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_dsp_get_all_regs(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) +{ + uint32_t value = 0; + for (int i = 0; i < MIPS32NUMDSPREGS; i++) { + int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, i); + if (retval != ERROR_OK) { + command_print(CMD, "couldn't access reg %s", mips32_dsp_regs[i].name); + return retval; + } + command_print(CMD, "%*s: 0x%8.8x", 7, mips32_dsp_regs[i].name, value); + } + return ERROR_OK; +} + +/** + * mips32_dsp_get_register - Get the value of a MIPS32 DSP register + * @param[in] cmd: Command invocation context + * @param[in] ejtag_info: EJTAG information structure + * + * @brief Retrieves the value of a specified MIPS32 DSP register. + * If the register is found, it reads the register value and prints the result. + * If the register is not found, it prints an error message. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_dsp_get_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) +{ + uint32_t value = 0; + int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]); + if (index == MIPS32NUMDSPREGS) { + command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, index); + if (retval != ERROR_OK) + command_print(CMD, "ERROR: Could not access dsp register %s", CMD_ARGV[0]); + else + command_print(CMD, "0x%8.8x", value); + + return retval; +} + +/** + * mips32_dsp_set_register - Set the value of a MIPS32 DSP register + * @param[in] cmd: Command invocation context + * @param[in] ejtag_info: EJTAG information structure + * + * @brief Sets the value of a specified MIPS32 DSP register. + * If the register is found, it writes provided value to the register. + * If the register is not found or there is an error in writing the value, + * it prints an error message. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_dsp_set_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) +{ + uint32_t value; + int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]); + if (index == MIPS32NUMDSPREGS) { + command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + int retval = mips32_pracc_write_dsp_reg(ejtag_info, value, index); + if (retval != ERROR_OK) + command_print(CMD, "Error: could not write to dsp register %s", CMD_ARGV[0]); + + return retval; +} + +/** + * mips32_handle_dsp_command - Handles mips dsp related command + * @param[in] cmd: Command invocation context + * + * @brief Reads or sets the content of each dsp register. + * + * @return ERROR_OK on success; error code on failure. +*/ +COMMAND_HANDLER(mips32_handle_dsp_command) +{ + 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; retval = mips32_verify_pointer(CMD, mips32); if (retval != ERROR_OK) @@ -936,45 +2204,104 @@ COMMAND_HANDLER(mips32_handle_cp0_command) return ERROR_OK; } - /* two or more argument, access a single register/select (write if third argument is given) */ - if (CMD_ARGC < 2) + /* Check for too many command args */ + if (CMD_ARGC >= 3) 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; + /* Check if DSP access supported or not */ + if (!mips32->dsp_imp) { + /* Issue Error Message */ + command_print(CMD, "DSP not implemented by this processor"); + return ERROR_OK; + } - 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; + switch (CMD_ARGC) { + case 0: + retval = mips32_dsp_get_all_regs(CMD, ejtag_info); + break; + case 1: + retval = mips32_dsp_get_register(CMD, ejtag_info); + break; + case 2: + tmp = *CMD_ARGV[0]; + if (isdigit(tmp)) { + command_print(CMD, "Error: invalid dsp command format"); + retval = ERROR_COMMAND_ARGUMENT_INVALID; + } else { + retval = mips32_dsp_set_register(CMD, ejtag_info); } - command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32, - cp0_reg, cp0_sel, value); + break; + default: + command_print(CMD, "Error: invalid argument format, required 0-2, given %d", CMD_ARGC); + retval = ERROR_COMMAND_ARGUMENT_INVALID; + break; + } + 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); - } +/** + * 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 +2330,38 @@ 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 = "dsp", + .handler = mips32_handle_dsp_command, + .mode = COMMAND_EXEC, + .help = "display or set DSP register; " + "with no arguments, displays all registers and their values", + .usage = "[[register_name] [value]]", + }, + { .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 f107b57d53..a557f31172 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 MIPS32NUMDSPREGS 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,14 +454,18 @@ 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 #define MIPS32_OP_COP0 0x10u +#define MIPS32_OP_COP1 0x11u #define MIPS32_OP_J 0x02u #define MIPS32_OP_JR 0x08u #define MIPS32_OP_LUI 0x0Fu #define MIPS32_OP_LW 0x23u +#define MIPS32_OP_LWC1 0x31u +#define MIPS32_OP_LDC1 0x35u #define MIPS32_OP_LB 0x20u #define MIPS32_OP_LBU 0x24u #define MIPS32_OP_LHU 0x25u @@ -155,6 +473,7 @@ struct mips32_algorithm { #define MIPS32_OP_MTHI 0x11u #define MIPS32_OP_MFLO 0x12u #define MIPS32_OP_MTLO 0x13u +#define MIPS32_OP_MUL 0x02u #define MIPS32_OP_RDHWR 0x3Bu #define MIPS32_OP_SB 0x28u #define MIPS32_OP_SH 0x29u @@ -163,11 +482,15 @@ 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 +#define MIPS32_OP_SWC1 0x39u +#define MIPS32_OP_SDC1 0x3Du #define MIPS32_OP_REGIMM 0x01u #define MIPS32_OP_SDBBP 0x3Fu @@ -175,8 +498,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 +511,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) @@ -196,33 +523,47 @@ struct mips32_algorithm { #define MIPS32_ISA_BGTZ(reg, off) MIPS32_I_INST(MIPS32_OP_BGTZ, reg, 0, off) #define MIPS32_ISA_BNE(src, tar, off) MIPS32_I_INST(MIPS32_OP_BNE, src, tar, off) #define MIPS32_ISA_CACHE(op, off, base) MIPS32_I_INST(MIPS32_OP_CACHE, base, op, off) +#define MIPS32_ISA_CFC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_CF, gpr, cpr, 0, 0) #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) #define MIPS32_ISA_LHU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LHU, base, reg, off) #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_LWC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_LWC1, base, reg, off) +#define MIPS32_ISA_LDC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_LDC1, base, reg, off) + +#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_MFC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MF, gpr, cpr, 0, 0) +#define MIPS32_ISA_MFHC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MFH, gpr, cpr, 0, 0) +#define MIPS32_ISA_MTC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MT, gpr, cpr, 0, 0) +#define MIPS32_ISA_MTHC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MTH, gpr, cpr, 0, 0) #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) #define MIPS32_ISA_SH(reg, off, base) MIPS32_I_INST(MIPS32_OP_SH, base, reg, off) #define MIPS32_ISA_SW(reg, off, base) MIPS32_I_INST(MIPS32_OP_SW, base, reg, off) +#define MIPS32_ISA_SWC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_SWC1, base, reg, off) +#define MIPS32_ISA_SDC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_SDC1, 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 +588,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 @@ -260,15 +603,23 @@ struct mips32_algorithm { #define MMIPS32_OP_BGTZ 0x06u #define MMIPS32_OP_BNE 0x2Du #define MMIPS32_OP_CACHE 0x06u +#define MMIPS32_OP_CFC1 0x40u #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 #define MMIPS32_OP_LUI 0x0Du #define MMIPS32_OP_LW 0x3Fu +#define MMIPS32_OP_LWC1 0x27u +#define MMIPS32_OP_LDC1 0x2Fu #define MMIPS32_OP_MFC0 0x03u +#define MMIPS32_OP_MFC1 0x80u +#define MMIPS32_OP_MFHC1 0xC0u #define MMIPS32_OP_MTC0 0x0Bu +#define MMIPS32_OP_MTC1 0xA0u +#define MMIPS32_OP_MTHC1 0xE0u #define MMIPS32_OP_MFLO 0x075u #define MMIPS32_OP_MFHI 0x035u #define MMIPS32_OP_MTLO 0x0F5u @@ -279,6 +630,8 @@ struct mips32_algorithm { #define MMIPS32_OP_SB 0x06u #define MMIPS32_OP_SH 0x0Eu #define MMIPS32_OP_SW 0x3Eu +#define MMIPS32_OP_SWC1 0x26u +#define MMIPS32_OP_SDC1 0x2Eu #define MMIPS32_OP_SLTU 0x390u #define MMIPS32_OP_SLL 0x000u #define MMIPS32_OP_SLTI 0x24u @@ -289,55 +642,68 @@ 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_CFC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_CFC1, MMIPS32_POOL32FXF) #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_MOVN(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_MOVN) +#define MMIPS32_LWC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LWC1, reg, base, off) +#define MMIPS32_LDC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LDC1, reg, base, off) + +#define MMIPS32_MFC0(gpr, cpr, sel) MIPS32_R_INST(MMIPS32_POOL32A, gpr, cpr, sel,\ + MMIPS32_OP_MFC0, MMIPS32_POOL32AXF) +#define MMIPS32_MFC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MFC1, MMIPS32_POOL32FXF) +#define MMIPS32_MFHC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MFHC1, MMIPS32_POOL32FXF) +#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_MTC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MTC1, MMIPS32_POOL32FXF) +#define MMIPS32_MTHC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MTHC1, MMIPS32_POOL32FXF) +#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(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_SWC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SWC1, reg, base, off) +#define MMIPS32_SDC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SDC1, reg, base, off) + +#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 */ @@ -353,30 +719,42 @@ struct mips32_algorithm { #define MIPS32_BGTZ(isa, reg, off) (isa ? MMIPS32_BGTZ(reg, off) : MIPS32_ISA_BGTZ(reg, off)) #define MIPS32_BNE(isa, src, tar, off) (isa ? MMIPS32_BNE(src, tar, off) : MIPS32_ISA_BNE(src, tar, off)) #define MIPS32_CACHE(isa, op, off, base) (isa ? MMIPS32_CACHE(op, off, base) : MIPS32_ISA_CACHE(op, off, base)) +#define MIPS32_CFC1(isa, gpr, cpr) (isa ? MMIPS32_CFC1(gpr, cpr) : MIPS32_ISA_CFC1(gpr, cpr)) #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)) #define MIPS32_LW(isa, reg, off, base) (isa ? MMIPS32_LW(reg, off, base) : MIPS32_ISA_LW(reg, off, base)) +#define MIPS32_LWC1(isa, reg, off, base) (isa ? MMIPS32_LWC1(reg, off, base) : MIPS32_ISA_LWC1(reg, off, base)) #define MIPS32_LUI(isa, reg, val) (isa ? MMIPS32_LUI(reg, val) : MIPS32_ISA_LUI(reg, val)) #define MIPS32_MFC0(isa, gpr, cpr, sel) (isa ? MMIPS32_MFC0(gpr, cpr, sel) : MIPS32_ISA_MFC0(gpr, cpr, sel)) #define MIPS32_MTC0(isa, gpr, cpr, sel) (isa ? MMIPS32_MTC0(gpr, cpr, sel) : MIPS32_ISA_MTC0(gpr, cpr, sel)) +#define MIPS32_MFC1(isa, gpr, cpr) (isa ? MMIPS32_MFC1(gpr, cpr) : MIPS32_ISA_MFC1(gpr, cpr)) +#define MIPS32_MFHC1(isa, gpr, cpr) (isa ? MMIPS32_MFHC1(gpr, cpr) : MIPS32_ISA_MFHC1(gpr, cpr)) +#define MIPS32_MTC1(isa, gpr, cpr) (isa ? MMIPS32_MTC1(gpr, cpr) : MIPS32_ISA_MTC1(gpr, cpr)) +#define MIPS32_MTHC1(isa, gpr, cpr) (isa ? MMIPS32_MTHC1(gpr, cpr) : MIPS32_ISA_MTHC1(gpr, cpr)) #define MIPS32_MFLO(isa, reg) (isa ? MMIPS32_MFLO(reg) : MIPS32_ISA_MFLO(reg)) #define MIPS32_MFHI(isa, reg) (isa ? MMIPS32_MFHI(reg) : MIPS32_ISA_MFHI(reg)) #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)) #define MIPS32_SB(isa, reg, off, base) (isa ? MMIPS32_SB(reg, off, base) : MIPS32_ISA_SB(reg, off, base)) #define MIPS32_SH(isa, reg, off, base) (isa ? MMIPS32_SH(reg, off, base) : MIPS32_ISA_SH(reg, off, base)) #define MIPS32_SW(isa, reg, off, base) (isa ? MMIPS32_SW(reg, off, base) : MIPS32_ISA_SW(reg, off, base)) +#define MIPS32_SWC1(isa, reg, off, base) (isa ? MMIPS32_SWC1(reg, off, base) : MIPS32_ISA_SWC1(reg, off, base)) +#define MIPS32_SDC1(isa, reg, off, base) (isa ? MMIPS32_SDC1(reg, off, base) : MIPS32_ISA_SDC1(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 +772,122 @@ 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 +#define MIPS32_DSP_ENABLE 0x1000000 + +#define MIPS32_S_INST(rs, rac, opcode) \ + (((rs) << 21) | ((rac) << 11) | (opcode)) + +#define MIPS32_DSP_R_INST(rt, immd, opcode, extrw) \ + ((0x1F << 26) | ((immd) << 16) | ((rt) << 11) | ((opcode) << 6) | (extrw)) +#define MIPS32_DSP_W_INST(rs, immd, opcode, extrw) \ + ((0x1F << 26) | ((rs) << 21) | ((immd) << 11) | ((opcode) << 6) | (extrw)) + +#define MIPS32_DSP_MFHI(reg, ac) MIPS32_R_INST(0, ac, 0, reg, 0, MIPS32_OP_MFHI) +#define MIPS32_DSP_MFLO(reg, ac) MIPS32_R_INST(0, ac, 0, reg, 0, MIPS32_OP_MFLO) +#define MIPS32_DSP_MTLO(reg, ac) MIPS32_S_INST(reg, ac, MIPS32_OP_MTLO) +#define MIPS32_DSP_MTHI(reg, ac) MIPS32_S_INST(reg, ac, MIPS32_OP_MTHI) +#define MIPS32_DSP_RDDSP(rt, mask) MIPS32_DSP_R_INST(rt, mask, 0x12, 0x38) +#define MIPS32_DSP_WRDSP(rs, mask) MIPS32_DSP_W_INST(rs, mask, 0x13, 0x38) + + +/* + * 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 +904,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 +912,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 +926,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 9bac40eb0c..aaf3875fb7 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/>. * ***************************************************************************/ /* @@ -68,8 +57,11 @@ #include "config.h" #endif +#include <helper/align.h> #include <helper/time_support.h> +#include <jtag/adapter.h> +#include "mips_cpu.h" #include "mips32.h" #include "mips32_pracc.h" @@ -120,7 +112,7 @@ static void mips32_pracc_finish(struct mips_ejtag *ejtag_info) mips_ejtag_drscan_32_out(ejtag_info, ctrl); } -int mips32_pracc_clean_text_jump(struct mips_ejtag *ejtag_info) +static int mips32_pracc_clean_text_jump(struct mips_ejtag *ejtag_info) { uint32_t jt_code = MIPS32_J(ejtag_info->isa, MIPS32_PRACC_TEXT); pracc_swap16_array(ejtag_info, &jt_code, 1); @@ -159,7 +151,7 @@ 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; @@ -317,7 +309,7 @@ void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr) if (ctx->retval != ERROR_OK) /* On previous out of memory, return */ return; if (ctx->code_count == ctx->max_code) { - void *p = realloc(ctx->pracc_list, sizeof(pa_list) * (ctx->max_code + PRACC_BLOCK)); + void *p = realloc(ctx->pracc_list, sizeof(struct pa_list) * (ctx->max_code + PRACC_BLOCK)); if (p) { ctx->max_code += PRACC_BLOCK; ctx->pracc_list = p; @@ -332,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 */ @@ -373,13 +365,13 @@ int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_in } scan_32; } *scan_in = malloc(sizeof(union scan_in) * (ctx->code_count + ctx->store_count)); - if (scan_in == NULL) { + if (!scan_in) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } unsigned num_clocks = - ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000; + ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000; uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ALL); @@ -453,7 +445,7 @@ exit: return retval; } -int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf) +static int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf) { struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); @@ -461,6 +453,8 @@ int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t 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 */ @@ -483,7 +477,7 @@ int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size uint32_t *data = NULL; if (size != 4) { data = malloc(256 * sizeof(uint32_t)); - if (data == NULL) { + if (!data) { LOG_ERROR("Out of memory"); goto exit; } @@ -517,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; @@ -559,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 */ @@ -580,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 */ @@ -588,6 +588,26 @@ int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_r return ctx.retval; } +int mips32_cp1_control_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp1_c_reg) +{ + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; + pracc_queue_init(&ctx); + + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ + pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa)); + pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, cp1_c_reg)); /* move cp1c reg to $8 */ + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ + 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, 8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1); + pracc_queue_free(&ctx); + return ctx.retval; +} + /** * \b mips32_pracc_sync_cache * @@ -658,7 +678,7 @@ static int mips32_pracc_synchronize_cache(struct mips_ejtag *ejtag_info, goto exit; /* Nothing to do */ /* make sure clsiz is power of 2 */ - if (clsiz & (clsiz - 1)) { + if (!IS_PWR_OF_2(clsiz)) { LOG_DEBUG("clsiz must be power of 2"); ctx.retval = ERROR_FAIL; goto exit; @@ -795,6 +815,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)) { @@ -822,19 +843,43 @@ 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; + bool fpu_in_64bit = ((c0rs[0] & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0); + bool fp_enabled = ((c0rs[0] & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0); + uint32_t rel = (ejtag_info->config[0] & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT; + pracc_queue_init(&ctx); uint32_t cp0_write_code[] = { @@ -846,69 +891,331 @@ 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)); + + /* store FPRs */ + if (mips32->fp_imp && fp_enabled) { + uint64_t *fprs = mips32->core_regs.fpr; + if (fpu_in_64bit) { + for (int i = 0; i != MIPS32_REG_FP_COUNT; i++) { + uint32_t fp_lo = fprs[i] & 0xffffffff; + uint32_t fp_hi = (fprs[i] >> 32) & 0xffffffff; + pracc_add_li32(&ctx, 2, fp_lo, 0); + pracc_add_li32(&ctx, 3, fp_hi, 0); + pracc_add(&ctx, 0, MIPS32_MTC1(ctx.isa, 2, i)); + pracc_add(&ctx, 0, MIPS32_MTHC1(ctx.isa, 3, i)); + } + } else { + for (int i = 0; i != MIPS32_REG_FP_COUNT; i++) { + uint32_t fp_lo = fprs[i] & 0xffffffff; + pracc_add_li32(&ctx, 2, fp_lo, 0); + pracc_add(&ctx, 0, MIPS32_MTC1(ctx.isa, 2, i)); + } + } + + if (rel > MIPS32_RELEASE_1) + 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)); +} - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, regs, 1); +/* 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; + unsigned int offset_fpr = ((uint8_t *)&core_regs->fpr[0]) - (uint8_t *)core_regs; + unsigned int offset_fpcr = ((uint8_t *)&core_regs->fpcr[0]) - (uint8_t *)core_regs; + bool fp_enabled; + + /* + * 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 + */ + + 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]; + + if (ctx.retval != ERROR_OK) + return ctx.retval; + + /* 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 */ + fp_enabled = (mips32->core_regs.cp0[0] & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0; + if (mips32->fp_imp && fp_enabled) { + pracc_queue_init(&ctx); + + mips32_pracc_store_regs_set_base_addr(&ctx); + + /* FCSR */ + pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, 31)); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset_fpcr, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset_fpcr, 1)); + + /* FIR */ + pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, 0)); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset_fpcr + 4, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset_fpcr + 4, 1)); + + /* f0 to f31 */ + if (mips32->fpu_in_64bit) { + for (int i = 0; i != 32; i++) { + size_t offset = offset_fpr + (i * 8); + /* current pracc implementation (or EJTAG itself) only supports 32b access */ + /* so there is no way to use SDC1 */ + + /* lower half */ + pracc_add(&ctx, 0, MIPS32_MFC1(ctx.isa, 8, i)); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset, 1)); + + /* upper half */ + pracc_add(&ctx, 0, MIPS32_MFHC1(ctx.isa, 8, i)); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset + 4, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset + 4, 1)); + } + } else { + for (int i = 0; i != 32; i++) { + size_t offset = offset_fpr + (i * 8); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset, + MIPS32_SWC1(ctx.isa, i, PRACC_OUT_OFFSET + offset, 1)); + } + } + + mips32_pracc_store_regs_restore(&ctx); + + /* 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); + + pracc_queue_free(&ctx); + } 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 @@ -929,13 +1236,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), @@ -945,7 +1256,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 */ }; @@ -965,7 +1278,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 */ }; @@ -1009,7 +1324,7 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are unsigned num_clocks = 0; /* like in legacy code */ if (ejtag_info->mode != 0) - num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000; + num_clocks = ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000; for (int i = 0; i < count; i++) { jtag_add_clocks(num_clocks); @@ -1029,5 +1344,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 911a69c5b0..f78f89153f 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,10 +36,12 @@ #define PRACC_BLOCK 128 /* 1 Kbyte */ -typedef struct { +struct mips32_common; + +struct pa_list { uint32_t instr; uint32_t addr; -} pa_list; +}; struct pracc_queue_info { struct mips_ejtag *ejtag_info; @@ -59,12 +50,13 @@ struct pracc_queue_info { int code_count; int store_count; int max_code; /* max instructions with currently allocated memory */ - pa_list *pracc_list; /* Code and store addresses at dmseg */ + 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 @@ -114,6 +103,21 @@ int mips32_cp0_read(struct mips_ejtag *ejtag_info, int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel); +/** + * mips32_cp1_control_read + * + * @brief Simulates cfc1 ASM instruction (Move Control Word From Floating Point), + * i.e. implements copro C1 Control Register read. + * + * @param[in] ejtag_info + * @param[in] val Storage to hold read value + * @param[in] cp1_c_reg Number of copro C1 control register we want to read + * + * @return ERROR_OK on Success, ERROR_FAIL otherwise + */ +int mips32_cp1_control_read(struct mips_ejtag *ejtag_info, + uint32_t *val, uint32_t cp1_c_reg); + static inline void pracc_swap16_array(struct mips_ejtag *ejtag_info, uint32_t *buf, int count) { if (ejtag_info->isa && ejtag_info->endianness) 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 3080046f3b..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 @@ -20,11 +20,12 @@ #include "mips64.h" #include "mips64_pracc.h" -#include "time_support.h" +#include <helper/time_support.h> +#include <jtag/adapter.h> #define STACK_DEPTH 32 -typedef struct { +struct mips64_pracc_context { uint64_t *local_iparam; unsigned num_iparam; uint64_t *local_oparam; @@ -34,7 +35,7 @@ typedef struct { uint64_t stack[STACK_DEPTH]; unsigned stack_offset; struct mips_ejtag *ejtag_info; -} mips64_pracc_context; +}; static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) { @@ -61,7 +62,7 @@ static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) return ERROR_OK; } -static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address) +static int mips64_pracc_exec_read(struct mips64_pracc_context *ctx, uint64_t address) { struct mips_ejtag *ejtag_info = ctx->ejtag_info; unsigned offset; @@ -79,7 +80,7 @@ static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address) return ERROR_JTAG_DEVICE_ERROR; } - if (ctx->local_iparam == NULL) { + if (!ctx->local_iparam) { LOG_ERROR("Error: unexpected reading of input parameter"); return ERROR_JTAG_DEVICE_ERROR; } @@ -91,7 +92,7 @@ static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address) && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) { offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; - if (ctx->local_oparam == NULL) { + if (!ctx->local_oparam) { LOG_ERROR("Error: unexpected reading of output parameter"); return ERROR_JTAG_DEVICE_ERROR; } @@ -149,7 +150,7 @@ static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address) return jtag_execute_queue(); } -static int mips64_pracc_exec_write(mips64_pracc_context *ctx, uint64_t address) +static int mips64_pracc_exec_write(struct mips64_pracc_context *ctx, uint64_t address) { uint32_t ejtag_ctrl; uint64_t data; @@ -179,7 +180,7 @@ static int mips64_pracc_exec_write(mips64_pracc_context *ctx, uint64_t address) if ((address >= MIPS64_PRACC_PARAM_IN) && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) { offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP; - if (ctx->local_iparam == NULL) { + if (!ctx->local_iparam) { LOG_ERROR("Error: unexpected writing of input parameter"); return ERROR_JTAG_DEVICE_ERROR; } @@ -187,7 +188,7 @@ static int mips64_pracc_exec_write(mips64_pracc_context *ctx, uint64_t address) } else if ((address >= MIPS64_PRACC_PARAM_OUT) && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) { offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; - if (ctx->local_oparam == NULL) { + if (!ctx->local_oparam) { LOG_ERROR("Error: unexpected writing of output parameter"); return ERROR_JTAG_DEVICE_ERROR; } @@ -213,8 +214,8 @@ int mips64_pracc_exec(struct mips_ejtag *ejtag_info, unsigned num_param_out, uint64_t *param_out) { uint32_t ejtag_ctrl; - uint64_t address = 0, address_prev = 0, data; - mips64_pracc_context ctx; + uint64_t address = 0, address_prev = 0; + struct mips64_pracc_context ctx; int retval; int pass = 0; bool first_time_call = true; @@ -243,7 +244,7 @@ int mips64_pracc_exec(struct mips_ejtag *ejtag_info, address_prev = address; else address_prev = 0; - address32 = data = 0; + address32 = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &address32); @@ -283,7 +284,7 @@ int mips64_pracc_exec(struct mips_ejtag *ejtag_info, if (ejtag_ctrl & EJTAG_CTRL_PRNW) { retval = mips64_pracc_exec_write(&ctx, address); if (retval != ERROR_OK) { - printf("ERROR mips64_pracc_exec_write\n"); + LOG_ERROR("mips64_pracc_exec_write() failed"); return retval; } } else { @@ -296,7 +297,7 @@ int mips64_pracc_exec(struct mips_ejtag *ejtag_info, } retval = mips64_pracc_exec_read(&ctx, address); if (retval != ERROR_OK) { - printf("ERROR mips64_pracc_exec_read\n"); + LOG_ERROR("mips64_pracc_exec_read() failed"); return retval; } @@ -1358,8 +1359,6 @@ int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, 0, NULL, 0, NULL); /* next fetch to dmseg should be in FASTDATA_AREA, check */ - address = 0; - mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); retval = mips_ejtag_drscan_32(ejtag_info, &address32); if (retval != ERROR_OK) @@ -1388,7 +1387,7 @@ int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, /* like in legacy code */ unsigned num_clocks = 0; if (ejtag_info->mode != 0) - num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000; + num_clocks = ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000; LOG_DEBUG("num_clocks=%d", num_clocks); for (i = 0; i < count; i++) { jtag_add_clocks(num_clocks); @@ -1411,7 +1410,6 @@ int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, return retval; } - address = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); retval = mips_ejtag_drscan_32(ejtag_info, &address32); if (retval != ERROR_OK) { 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 7544afe52d..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 @@ -32,7 +21,7 @@ void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr) { - assert(ejtag_info->tap != NULL); + assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { @@ -68,7 +57,7 @@ int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info) void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf) { - assert(ejtag_info->tap != NULL); + assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; @@ -94,7 +83,7 @@ int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data) struct jtag_tap *tap; tap = ejtag_info->tap; - if (tap == NULL) + if (!tap) return ERROR_FAIL; struct scan_field field; uint8_t t[8] = { 0 }, r[8]; @@ -119,9 +108,10 @@ int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data) return ERROR_OK; } -void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, uint32_t data_out, uint8_t *data_in) +static void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, + uint32_t data_out, uint8_t *data_in) { - assert(ejtag_info->tap != NULL); + assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; @@ -159,7 +149,7 @@ void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data) int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint8_t *data) { - assert(ejtag_info->tap != NULL); + assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; @@ -180,7 +170,7 @@ int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint8_t *data) void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data) { - assert(ejtag_info->tap != NULL); + assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; @@ -267,11 +257,14 @@ error: int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info) { - pa_list pracc_list = {.instr = MIPS32_DRET(ejtag_info->isa), .addr = 0}; + 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); @@ -295,8 +288,8 @@ static void mips_ejtag_init_mmr(struct mips_ejtag *ejtag_info) ejtag_info->ejtag_dbm_offs = EJTAG_V20_DBM_OFFS; ejtag_info->ejtag_dbv_offs = EJTAG_V20_DBV_OFFS; - ejtag_info->ejtag_iba_step_size = EJTAG_V20_IBAn_STEP; - ejtag_info->ejtag_dba_step_size = EJTAG_V20_DBAn_STEP; + ejtag_info->ejtag_iba_step_size = EJTAG_V20_IBAN_STEP; + ejtag_info->ejtag_dba_step_size = EJTAG_V20_DBAN_STEP; } else { ejtag_info->ejtag_ibs_addr = EJTAG_V25_IBS; ejtag_info->ejtag_iba0_addr = EJTAG_V25_IBA0; @@ -311,8 +304,8 @@ static void mips_ejtag_init_mmr(struct mips_ejtag *ejtag_info) ejtag_info->ejtag_dbc_offs = EJTAG_V25_DBC_OFFS; ejtag_info->ejtag_dbv_offs = EJTAG_V25_DBV_OFFS; - ejtag_info->ejtag_iba_step_size = EJTAG_V25_IBAn_STEP; - ejtag_info->ejtag_dba_step_size = EJTAG_V25_DBAn_STEP; + ejtag_info->ejtag_iba_step_size = EJTAG_V25_IBAN_STEP; + ejtag_info->ejtag_dba_step_size = EJTAG_V25_DBAN_STEP; } } @@ -339,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" : "", @@ -420,7 +413,7 @@ int mips_ejtag_init(struct mips_ejtag *ejtag_info) int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data) { - assert(ejtag_info->tap != NULL); + assert(ejtag_info->tap); struct jtag_tap *tap = ejtag_info->tap; struct scan_field fields[2]; @@ -529,7 +522,7 @@ int mips64_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, bool write_t, uint struct jtag_tap *tap; tap = ejtag_info->tap; - assert(tap != NULL); + assert(tap); struct scan_field fields[2]; uint8_t spracc = 0; diff --git a/src/target/mips_ejtag.h b/src/target/mips_ejtag.h index ace3d281ee..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 @@ -147,33 +137,33 @@ #define EJTAG_V20_IBA0 0xFF300100 #define EJTAG_V20_IBC_OFFS 0x4 /* IBC Offset */ #define EJTAG_V20_IBM_OFFS 0x8 -#define EJTAG_V20_IBAn_STEP 0x10 /* Offset for next channel */ +#define EJTAG_V20_IBAN_STEP 0x10 /* Offset for next channel */ #define EJTAG_V20_DBS 0xFF300008 #define EJTAG_V20_DBA0 0xFF300200 #define EJTAG_V20_DBC_OFFS 0x4 #define EJTAG_V20_DBM_OFFS 0x8 #define EJTAG_V20_DBV_OFFS 0xc -#define EJTAG_V20_DBAn_STEP 0x10 +#define EJTAG_V20_DBAN_STEP 0x10 #define EJTAG_V25_IBS 0xFF301000 #define EJTAG_V25_IBA0 0xFF301100 #define EJTAG_V25_IBM_OFFS 0x8 #define EJTAG_V25_IBASID_OFFS 0x10 #define EJTAG_V25_IBC_OFFS 0x18 -#define EJTAG_V25_IBAn_STEP 0x100 +#define EJTAG_V25_IBAN_STEP 0x100 #define EJTAG_V25_DBS 0xFF302000 #define EJTAG_V25_DBA0 0xFF302100 #define EJTAG_V25_DBM_OFFS 0x8 #define EJTAG_V25_DBASID_OFFS 0x10 #define EJTAG_V25_DBC_OFFS 0x18 #define EJTAG_V25_DBV_OFFS 0x20 -#define EJTAG_V25_DBAn_STEP 0x100 +#define EJTAG_V25_DBAN_STEP 0x100 -#define EJTAG_DBCn_NOSB (1 << 13) -#define EJTAG_DBCn_NOLB (1 << 12) -#define EJTAG_DBCn_BLM_MASK 0xff -#define EJTAG_DBCn_BLM_SHIFT 4 -#define EJTAG_DBCn_BE (1 << 0) +#define EJTAG_DBCN_NOSB (1 << 13) +#define EJTAG_DBCN_NOLB (1 << 12) +#define EJTAG_DBCN_BLM_MASK 0xff +#define EJTAG_DBCN_BLM_SHIFT 4 +#define EJTAG_DBCN_BE (1 << 0) #define EJTAG_VERSION_20 0 #define EJTAG_VERSION_25 1 @@ -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 52b4b32179..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; @@ -128,14 +121,11 @@ static int mips_m4k_debug_entry(struct target *target) static struct target *get_mips_m4k(struct target *target, int32_t coreid) { struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; - head = head->next; } return target; } @@ -144,19 +134,17 @@ static int mips_m4k_halt_smp(struct target *target) { int retval = ERROR_OK; struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { + + foreach_smp_target(head, target->smp_targets) { int ret = ERROR_OK; - curr = head->target; + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED)) 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; } - head = head->next; } return retval; } @@ -186,7 +174,7 @@ static int mips_m4k_poll(struct target *target) /* the next polling trigger an halt event sent to gdb */ if ((target->state == TARGET_HALTED) && (target->smp) && (target->gdb_service) && - (target->gdb_service->target == NULL)) { + (!target->gdb_service->target)) { target->gdb_service->target = get_mips_m4k(target, target->gdb_service->core[1]); target_call_event_callbacks(target, TARGET_EVENT_HALTED); @@ -414,24 +402,21 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han { int retval = ERROR_OK; struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { + foreach_smp_target(head, target->smp_targets) { int ret = ERROR_OK; - curr = head->target; + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING)) { /* resume current address , not in step mode */ ret = mips_m4k_internal_restore(curr, 1, address, 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; } } - head = head->next; } return retval; } @@ -458,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); @@ -552,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); } @@ -601,7 +586,7 @@ static void mips_m4k_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->is_set) mips_m4k_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -615,7 +600,7 @@ static int mips_m4k_set_breakpoint(struct target *target, struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -630,7 +615,7 @@ static int mips_m4k_set_breakpoint(struct target *target, breakpoint->unique_id); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = bp_num + 1; + breakpoint_hw_set(breakpoint, bp_num); comparator_list[bp_num].used = 1; comparator_list[bp_num].bp_value = breakpoint->address; @@ -732,7 +717,7 @@ static int mips_m4k_set_breakpoint(struct target *target, } } - breakpoint->set = 20; /* Any nice value but 0 */ + breakpoint->is_set = true; } return ERROR_OK; @@ -747,14 +732,14 @@ static int mips_m4k_unset_breakpoint(struct target *target, struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { - int bp_num = breakpoint->set - 1; - if ((bp_num < 0) || (bp_num >= mips32->num_inst_bpoints)) { + int bp_num = breakpoint->number; + if (bp_num >= mips32->num_inst_bpoints) { LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %" PRIu32 ")", breakpoint->unique_id); return ERROR_OK; @@ -821,7 +806,7 @@ static int mips_m4k_unset_breakpoint(struct target *target, } } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -859,7 +844,7 @@ static int mips_m4k_remove_breakpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (breakpoint->set) + if (breakpoint->is_set) mips_m4k_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) @@ -880,10 +865,10 @@ static int mips_m4k_set_watchpoint(struct target *target, * and exclude both load and store accesses from watchpoint * condition evaluation */ - int enable = EJTAG_DBCn_NOSB | EJTAG_DBCn_NOLB | EJTAG_DBCn_BE | - (0xff << EJTAG_DBCn_BLM_SHIFT); + int enable = EJTAG_DBCN_NOSB | EJTAG_DBCN_NOLB | EJTAG_DBCN_BE | + (0xff << EJTAG_DBCN_BLM_SHIFT); - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -907,19 +892,19 @@ static int mips_m4k_set_watchpoint(struct target *target, switch (watchpoint->rw) { case WPT_READ: - enable &= ~EJTAG_DBCn_NOLB; + enable &= ~EJTAG_DBCN_NOLB; break; case WPT_WRITE: - enable &= ~EJTAG_DBCn_NOSB; + enable &= ~EJTAG_DBCN_NOSB; break; case WPT_ACCESS: - enable &= ~(EJTAG_DBCn_NOLB | EJTAG_DBCn_NOSB); + enable &= ~(EJTAG_DBCN_NOLB | EJTAG_DBCN_NOSB); break; default: LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } - watchpoint->set = wp_num + 1; + watchpoint_set(watchpoint, wp_num); comparator_list[wp_num].used = 1; comparator_list[wp_num].bp_value = watchpoint->address; @@ -954,13 +939,13 @@ static int mips_m4k_unset_watchpoint(struct target *target, struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips32_comparator *comparator_list = mips32->data_break_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = watchpoint->set - 1; - if ((wp_num < 0) || (wp_num >= mips32->num_data_bpoints)) { + int wp_num = watchpoint->number; + if (wp_num >= mips32->num_data_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } @@ -968,7 +953,7 @@ static int mips_m4k_unset_watchpoint(struct target *target, comparator_list[wp_num].bp_value = 0; target_write_u32(target, comparator_list[wp_num].reg_address + ejtag_info->ejtag_dbc_offs, 0); - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -999,7 +984,7 @@ static int mips_m4k_remove_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) mips_m4k_unset_watchpoint(target, watchpoint); mips32->num_data_bpoints_avail++; @@ -1013,7 +998,7 @@ static void mips_m4k_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) mips_m4k_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } @@ -1040,12 +1025,18 @@ 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; if (size > 1) { t = malloc(count * size * sizeof(uint8_t)); - if (t == NULL) { + if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -1061,7 +1052,7 @@ static int mips_m4k_read_memory(struct target *target, target_addr_t address, /* mips32_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */ /* endianness, but byte array should represent target endianness */ - if (ERROR_OK == retval) { + if (retval == ERROR_OK) { switch (size) { case 4: target_buffer_set_u32_array(target, buffer, count, t); @@ -1112,7 +1103,7 @@ static int mips_m4k_write_memory(struct target *target, target_addr_t address, /* mips32_..._write_mem with size 4/2 requires uint32_t/uint16_t in host */ /* endianness, but byte array represents target endianness */ t = malloc(count * size * sizeof(uint8_t)); - if (t == NULL) { + if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -1137,7 +1128,7 @@ static int mips_m4k_write_memory(struct target *target, target_addr_t address, free(t); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; return ERROR_OK; @@ -1218,7 +1209,7 @@ static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t addre if (address & 0x3u) return ERROR_TARGET_UNALIGNED_ACCESS; - if (mips32->fast_data_area == NULL) { + if (!mips32->fast_data_area) { /* Get memory for block write handler * we preserve this area between calls and gain a speed increase * of about 3kb/sec when writing flash @@ -1237,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); @@ -1250,7 +1241,7 @@ static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t addre /* but byte array represents target endianness */ uint32_t *t = NULL; t = malloc(count * sizeof(uint32_t)); - if (t == NULL) { + if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -1268,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) { @@ -1376,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 f941af5174..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 @@ -62,7 +62,7 @@ static int mips_mips64_debug_entry(struct target *target) mips_mips64_examine_debug_reason(target); LOG_DEBUG("entered debug state at PC 0x%" PRIx64 ", target->state: %s", - *(uint64_t *)pc->value, target_state_name(target)); + buf_get_u64(pc->value, 0, 64), target_state_name(target)); return ERROR_OK; } @@ -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; @@ -346,7 +340,7 @@ static int mips_mips64_set_breakpoint(struct target *target, { int retval; - if (bp->set) { + if (bp->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -373,7 +367,7 @@ static int mips_mips64_set_breakpoint(struct target *target, return retval; } - bp->set = true; + bp->is_set = true; return ERROR_OK; } @@ -385,7 +379,7 @@ static int mips_mips64_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (bp) { - if (!bp->set) { + if (!bp->is_set) { retval = mips_mips64_set_breakpoint(target, bp); if (retval != ERROR_OK) return retval; @@ -410,10 +404,10 @@ static int mips_mips64_set_watchpoint(struct target *target, * and exclude both load and store accesses from watchpoint * condition evaluation */ - int enable = EJTAG_DBCn_NOSB | EJTAG_DBCn_NOLB | EJTAG_DBCn_BE - | (0xff << EJTAG_DBCn_BLM_SHIFT); + int enable = EJTAG_DBCN_NOSB | EJTAG_DBCN_NOLB | EJTAG_DBCN_BE + | (0xff << EJTAG_DBCN_BLM_SHIFT); - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -438,20 +432,20 @@ static int mips_mips64_set_watchpoint(struct target *target, switch (watchpoint->rw) { case WPT_READ: - enable &= ~EJTAG_DBCn_NOLB; + enable &= ~EJTAG_DBCN_NOLB; break; case WPT_WRITE: - enable &= ~EJTAG_DBCn_NOSB; + enable &= ~EJTAG_DBCN_NOSB; break; case WPT_ACCESS: - enable &= ~(EJTAG_DBCn_NOLB | EJTAG_DBCn_NOSB); + enable &= ~(EJTAG_DBCN_NOLB | EJTAG_DBCN_NOSB); break; default: LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } c = &cl[wp_num]; - watchpoint->set = wp_num + 1; + watchpoint_set(watchpoint, wp_num); c->used = true; c->bp_value = watchpoint->address; @@ -491,7 +485,7 @@ static int mips_mips64_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (watchpoint->set == 0) { + if (!watchpoint->is_set) { retval = mips_mips64_set_watchpoint(target, watchpoint); if (retval != ERROR_OK) return retval; @@ -506,11 +500,10 @@ static int mips_mips64_unset_hwbp(struct target *target, struct breakpoint *bp) { struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *comparator_list = mips64->inst_break_list; - int bp_num; - bp_num = bp->set - 1; + int bp_num = bp->number; - if ((bp_num < 0) || (bp_num >= mips64->num_inst_bpoints)) { + if (bp_num >= mips64->num_inst_bpoints) { LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %" PRIu32 ")", bp->unique_id); return ERROR_OK; @@ -568,7 +561,7 @@ static int mips_mips64_unset_breakpoint(struct target *target, /* get pointers to arch-specific information */ int retval; - if (!bp->set) { + if (!bp->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -594,7 +587,7 @@ static int mips_mips64_unset_breakpoint(struct target *target, return retval; } - bp->set = false; + bp->is_set = false; return ERROR_OK; } @@ -613,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; } @@ -632,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); @@ -713,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; } @@ -724,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 */ @@ -811,11 +804,11 @@ 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; } - if (bp->set) + if (bp->is_set) retval = mips_mips64_unset_breakpoint(target, bp); if (bp->type == BKPT_HARD) @@ -831,20 +824,20 @@ static int mips_mips64_unset_watchpoint(struct target *target, struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *comparator_list = mips64->data_break_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = watchpoint->set - 1; - if ((wp_num < 0) || (wp_num >= mips64->num_data_bpoints)) { + int wp_num = watchpoint->number; + if (wp_num >= mips64->num_data_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } comparator_list[wp_num].used = false; comparator_list[wp_num].bp_value = 0; target_write_u64(target, comparator_list[wp_num].reg_address + 0x18, 0); - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -872,11 +865,11 @@ 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; } - if (watchpoint->set) + if (watchpoint->is_set) retval = mips_mips64_unset_watchpoint(target, watchpoint); mips64->num_data_bpoints_avail++; @@ -893,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; } @@ -923,7 +916,7 @@ static int mips_mips64_read_memory(struct target *target, uint64_t address, retval = mips64_pracc_read_mem(ejtag_info, address, size, count, (void *)t); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("mips64_pracc_read_mem filed"); goto read_done; } @@ -1021,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; } @@ -1169,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 487e19c6ad..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" - -const int NDS32_BREAK_16 = 0x00EA; /* 0xEA00 */ -const int NDS32_BREAK_32 = 0x0A000064; /* 0x6400000A */ - -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_FPU == nds32_reg_type(mapped_regnum))) { - retval = ERROR_OK; - } else if ((nds32->audio_enable == false) - && (NDS32_REG_TYPE_AUMR == nds32_reg_type(mapped_regnum))) { - 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) - && ((FD0 <= reg_arch_info->num) && (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 (ERROR_OK == nds32_get_mapped_reg(nds32, MR8, &value)) { - 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_FPU == nds32_reg_type(mapped_regnum))) { - - buf_set_u32(reg->value, 0, 32, 0); - } else if ((nds32->audio_enable == false) && - (NDS32_REG_TYPE_AUMR == nds32_reg_type(mapped_regnum))) { - - 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 (IR0 == mapped_regnum) { - nds32_update_psw(nds32); - } else if (MR0 == mapped_regnum) { - nds32_update_mmu_info(nds32); - } else if ((MR6 == mapped_regnum) || (MR7 == mapped_regnum)) { - /* update lm information */ - nds32_update_lm_info(nds32); - } else if (MR8 == mapped_regnum) { - nds32_update_cache_info(nds32); - } else if (FUCPR == mapped_regnum) { - /* 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) && - ((FD0 <= reg_arch_info->num) && (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 (FD0 <= reg_arch_info[i].num && 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 ((FS0 <= reg_arch_info[i].num) && (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 (R16 <= reg_arch_info[i].num && 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 (R0 <= reg_arch_info[i].num && reg_arch_info[i].num <= IFC_LP) - reg_list[i].feature->name = "org.gnu.gdb.nds32.core"; - else if (CR0 <= reg_arch_info[i].num && reg_arch_info[i].num <= SECUR0) - reg_list[i].feature->name = "org.gnu.gdb.nds32.system"; - else if (D0L24 <= reg_arch_info[i].num && reg_arch_info[i].num <= CBE3) - reg_list[i].feature->name = "org.gnu.gdb.nds32.audio"; - else if (FPCSR <= reg_arch_info[i].num && 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 (ERROR_OK != r->type->get(r)) - 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 (NDS_MEMORY_ACC_CPU == memory->access_channel) - 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 (NDS_MEMORY_SELECT_AUTO != memory->mode) { - 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 ((NDS_MEMORY_ACC_CPU == memory->access_channel) && - (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 ((NDS_MEMORY_ACC_CPU == memory->access_channel) && - (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", 1); - 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 (FD0 <= reg_arch_info->num && 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) || (0x60 <= nds32->edm.version)) - 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.set = 0; - 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 (ERROR_FAIL == nds32_reg_cache_init(target, nds32)) - return ERROR_FAIL; - - if (ERROR_OK != nds32_init_register_table(nds32)) - 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 (ERROR_OK == nds32_probe_tlb(nds32, address, physical)) - return ERROR_OK; - - if (ERROR_OK == nds32_walk_page_table(nds32, address, physical)) - 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 (ERROR_FAIL == target->type->virt2phys(target, cur_address, - &physical_addr)) - 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 (ERROR_OK != aice_step(aice)) - 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 (ERROR_OK != aice_step(aice)) - 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 (ERROR_OK != nds32_read_opcode(nds32, value_pc, &opcode)) - return ERROR_FAIL; - if (ERROR_OK != nds32_evaluate_opcode(nds32, opcode, value_pc, - &instruction)) - 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 (ERROR_OK != result) - 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 (ERROR_OK != nds32->get_watched_address(nds32, - &(nds32->watched_address), reason)) - 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 != NULL) { - /* 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 (ERROR_OK != aice_program_edm(aice, command_sequence)) - 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 (ERROR_OK != aice_program_edm(aice, command_str)) - 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 (TARGET_HALTED != state) - /* TODO: if state == TARGET_HALTED, check ETYPE is DBGI or not */ - if (ERROR_OK != aice_halt(aice)) - 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 (ERROR_OK != nds32->enter_debug_state(nds32, true)) { - 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 (NULL == 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); - - 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_SYSCALL_FSTAT == nds32->active_syscall_id) || - (NDS32_SYSCALL_STAT == nds32->active_syscall_id)) { - /* 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_SYSCALL_GETTIMEOFDAY == nds32->active_syscall_id) { - /* 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 3670fd2891..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 != NULL); - return target->arch_info; -} - -/** */ -static inline struct aice_port_s *target_to_aice(struct target *target) -{ - assert(target != NULL); - return target->tap->priv; -} - -static inline bool is_nds32(struct nds32 *nds32) -{ - assert(nds32 != NULL); - return nds32->common_magic == NDS32_COMMON_MAGIC; -} - -static inline bool nds32_reach_max_interrupt_level(struct nds32 *nds32) -{ - assert(nds32 != NULL); - 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 e494a3e1cd..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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 == NULL) { - 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 1684ea8824..0000000000 --- a/src/target/nds32_cmd.c +++ /dev/null @@ -1,1125 +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 (ERROR_OK != nds32_read_opcode(nds32, read_addr, &opcode)) - return ERROR_FAIL; - if (ERROR_OK != nds32_evaluate_opcode(nds32, opcode, - read_addr, &instruction)) - 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 (ERROR_OK != nds32_read_opcode(nds32, addr, &opcode)) - return ERROR_FAIL; - if (ERROR_OK != nds32_evaluate_opcode(nds32, opcode, addr, &instruction)) - 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); - - Jim_GetOptInfo 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 == NULL) - 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 target *target = Jim_CmdPrivData(goi.interp); - 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); - - Jim_GetOptInfo 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 target *target = Jim_CmdPrivData(goi.interp); - 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); - - Jim_GetOptInfo 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 target *target = Jim_CmdPrivData(goi.interp); - 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); - - Jim_GetOptInfo 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 target *target = Jim_CmdPrivData(goi.interp); - 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); - - Jim_GetOptInfo 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 target *target = Jim_CmdPrivData(goi.interp); - 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 0cfd197d29..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 (0 < length && 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 1dec190f12..0000000000 --- a/src/target/nds32_edm.h +++ /dev/null @@ -1,115 +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 - -/** - * @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 eb66645176..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 */ -extern const int NDS32_BREAK_16; -extern const int NDS32_BREAK_32; - -#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 c4bce1a6a2..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); -} - -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 62512c1114..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 392bd6eb99..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 ((1 <= cur_level) && (cur_level < max_level)) { - if (IR0 == reg_no) { - LOG_DEBUG("Map PSW to IPSW"); - return IR1; - } else if (PC == reg_no) { - LOG_DEBUG("Map PC to IPC"); - return IR9; - } - } else if ((2 <= cur_level) && (cur_level < max_level)) { - if (R26 == reg_no) { - LOG_DEBUG("Mapping P0 to P_P0"); - return IR12; - } else if (R27 == reg_no) { - LOG_DEBUG("Mapping P1 to P_P1"); - return IR13; - } else if (IR1 == reg_no) { - LOG_DEBUG("Mapping IPSW to P_IPSW"); - return IR2; - } else if (IR4 == reg_no) { - LOG_DEBUG("Mapping EVA to P_EVA"); - return IR5; - } else if (IR6 == reg_no) { - LOG_DEBUG("Mapping ITYPE to P_ITYPE"); - return IR7; - } else if (IR9 == reg_no) { - LOG_DEBUG("Mapping IPC to P_IPC"); - return IR10; - } - } else if (cur_level == max_level) { - if (PC == reg_no) { - 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 (ERROR_OK != nds32_examine_debug_reason(nds32)) { - 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 (ERROR_OK != result) { - /* 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 ((NDS_MEMORY_ACC_BUS == memory->access_channel) || - ((NDS_MEMORY_ACC_CPU == memory->access_channel) && - nds32_reach_max_interrupt_level(nds32))) { - if (ERROR_OK == target->type->virt2phys(target, *address, &physical_address)) - *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 ((NDS_MEMORY_ACC_CPU == memory->access_channel) && - (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 ((NDS_MEMORY_ACC_CPU == memory->access_channel) && - (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 ((NDS_MEMORY_ACC_CPU == memory->access_channel) && - (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 ((NDS_MEMORY_ACC_CPU == memory->access_channel) && - (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 e5d146bb6a..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 (ERROR_OK != result) { - /* 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; -} - -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 271ffdd1ce..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->set) { - /** disable virtual hosting */ - - /* remove breakpoint at syscall entry */ - target_remove_breakpoint(nds32->target, syscall_break); - syscall_break->set = 0; - - 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 (ERROR_OK != nds32_examine_debug_reason(nds32)) { - 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->set = 1; - 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 ((NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE == reason) || - (NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE == reason)) { - 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 ((NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP == reason) && 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 ((NDS_MEMORY_ACC_CPU == memory->access_channel) && - (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 (ERROR_OK == target->type->virt2phys(target, address, &physical_address)) - 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 ((NDS_MEMORY_ACC_CPU == memory->access_channel) && - (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 (ERROR_OK == target->type->virt2phys(target, address, &physical_address)) - 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 (NDS_MEMORY_ACC_CPU == origin_access_channel) { - 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 ((NDS_MEMORY_ACC_CPU == memory->access_channel) && - (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 (ERROR_OK == target->type->virt2phys(target, address, &physical_address)) - 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 ((NDS_MEMORY_ACC_CPU == memory->access_channel) && - (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 (ERROR_OK == target->type->virt2phys(target, address, &physical_address)) - 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 86903a51ba..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 (ERROR_OK != result) { - /* 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; -} - -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/oocd_trace.c b/src/target/oocd_trace.c deleted file mode 100644 index f38916a0ba..0000000000 --- a/src/target/oocd_trace.c +++ /dev/null @@ -1,417 +0,0 @@ -/*************************************************************************** - * 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 -#include "config.h" -#endif - -#include "arm.h" -#include "etm.h" -#include "oocd_trace.h" - -/* - * This is "proof of concept" code, for prototype hardware: - * https://lists.berlios.de/pipermail/openocd-development/2007-September/000336.html - */ - -static int oocd_trace_read_reg(struct oocd_trace *oocd_trace, int reg, uint32_t *value) -{ - size_t bytes_written, bytes_read, bytes_to_read; - uint8_t cmd; - - cmd = 0x10 | (reg & 0x7); - bytes_written = write(oocd_trace->tty_fd, &cmd, 1); - if (bytes_written < 1) - return ERROR_FAIL; - - bytes_to_read = 4; - while (bytes_to_read > 0) { - bytes_read = read(oocd_trace->tty_fd, ((uint8_t *)value) + 4 - bytes_to_read, bytes_to_read); - bytes_to_read -= bytes_read; - } - - LOG_DEBUG("reg #%i: 0x%8.8x", reg, *value); - - return ERROR_OK; -} - -static int oocd_trace_write_reg(struct oocd_trace *oocd_trace, int reg, uint32_t value) -{ - size_t bytes_written; - uint8_t data[5]; - - data[0] = 0x18 | (reg & 0x7); - data[1] = value & 0xff; - data[2] = (value & 0xff00) >> 8; - data[3] = (value & 0xff0000) >> 16; - data[4] = (value & 0xff000000) >> 24; - - bytes_written = write(oocd_trace->tty_fd, data, 5); - if (bytes_written < 5) - return ERROR_FAIL; - - LOG_DEBUG("reg #%i: 0x%8.8x", reg, value); - - return ERROR_OK; -} - -static int oocd_trace_read_memory(struct oocd_trace *oocd_trace, uint8_t *data, uint32_t address, uint32_t size) -{ - size_t bytes_written, bytes_to_read; - ssize_t bytes_read; - uint8_t cmd; - - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, address); - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_SDRAM_COUNTER, size); - - cmd = 0x20; - bytes_written = write(oocd_trace->tty_fd, &cmd, 1); - if (bytes_written < 1) - return ERROR_FAIL; - - bytes_to_read = size * 16; - while (bytes_to_read > 0) { - bytes_read = read(oocd_trace->tty_fd, - ((uint8_t *)data) + (size * 16) - bytes_to_read, bytes_to_read); - if (bytes_read < 0) - LOG_DEBUG("read() returned %zi (%s)", bytes_read, strerror(errno)); - else - bytes_to_read -= bytes_read; - } - - return ERROR_OK; -} - -static int oocd_trace_init(struct etm_context *etm_ctx) -{ - uint8_t trash[256]; - struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; - size_t bytes_read; - - oocd_trace->tty_fd = open(oocd_trace->tty, O_RDWR | O_NOCTTY | O_NONBLOCK); - - if (oocd_trace->tty_fd < 0) { - LOG_ERROR("can't open tty"); - return ERROR_ETM_CAPTURE_INIT_FAILED; - } - - /* clear input & output buffers, then switch to "blocking mode" */ - tcflush(oocd_trace->tty_fd, TCOFLUSH); - tcflush(oocd_trace->tty_fd, TCIFLUSH); - fcntl(oocd_trace->tty_fd, F_SETFL, fcntl(oocd_trace->tty_fd, F_GETFL) & ~O_NONBLOCK); - - tcgetattr(oocd_trace->tty_fd, &oocd_trace->oldtio); /* save current port settings */ - - bzero(&oocd_trace->newtio, sizeof(oocd_trace->newtio)); - oocd_trace->newtio.c_cflag = CS8 | CLOCAL | CREAD | B2500000; - - oocd_trace->newtio.c_iflag = IGNPAR | IGNBRK | IXON | IXOFF; - oocd_trace->newtio.c_oflag = 0; - - /* set input mode (non-canonical, no echo,...) */ - oocd_trace->newtio.c_lflag = 0; - - cfmakeraw(&oocd_trace->newtio); - oocd_trace->newtio.c_cc[VTIME] = 1; /* inter-character timer used */ - oocd_trace->newtio.c_cc[VMIN] = 0; /* blocking read until 0 chars received */ - - tcflush(oocd_trace->tty_fd, TCIFLUSH); - tcsetattr(oocd_trace->tty_fd, TCSANOW, &oocd_trace->newtio); - - /* occasionally one bogus character is left in the input buffer - * read up any leftover characters to ensure communication is in sync */ - do { - bytes_read = read(oocd_trace->tty_fd, trash, sizeof(trash)); - if (bytes_read) - LOG_DEBUG("%zi bytes read", bytes_read); - } while (bytes_read > 0); - - return ERROR_OK; -} - -static trace_status_t oocd_trace_status(struct etm_context *etm_ctx) -{ - struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; - uint32_t status; - - oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status); - - /* if tracing is currently idle, return this information */ - if (etm_ctx->capture_status == TRACE_IDLE) - return etm_ctx->capture_status; - else if (etm_ctx->capture_status & TRACE_RUNNING) { - /* check Full bit to identify an overflow */ - if (status & 0x4) - etm_ctx->capture_status |= TRACE_OVERFLOWED; - - /* check Triggered bit to identify trigger condition */ - if (status & 0x2) - etm_ctx->capture_status |= TRACE_TRIGGERED; - - if (status & 0x1) { - etm_ctx->capture_status &= ~TRACE_RUNNING; - etm_ctx->capture_status |= TRACE_COMPLETED; - } - } - - return etm_ctx->capture_status; -} - -static int oocd_trace_read_trace(struct etm_context *etm_ctx) -{ - struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; - uint32_t status, address; - uint32_t first_frame = 0x0; - uint32_t num_frames = 1048576; - uint8_t *trace_data; - uint32_t i; - - oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status); - oocd_trace_read_reg(oocd_trace, OOCD_TRACE_ADDRESS, &address); - - /* check if we overflowed, and adjust first frame of the trace accordingly - * if we didn't overflow, read only up to the frame that would be written next, - * i.e. don't read invalid entries - */ - if (status & 0x4) - first_frame = address; - else - num_frames = address; - - /* read data into temporary array for unpacking - * one frame from OpenOCD + trace corresponds to 16 trace cycles - */ - trace_data = malloc(sizeof(uint8_t) * num_frames * 16); - oocd_trace_read_memory(oocd_trace, trace_data, first_frame, num_frames); - - if (etm_ctx->trace_depth > 0) - free(etm_ctx->trace_data); - - etm_ctx->trace_depth = num_frames * 16; - etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth); - - for (i = 0; i < num_frames * 16; i++) { - etm_ctx->trace_data[i].pipestat = (trace_data[i] & 0x7); - etm_ctx->trace_data[i].packet = (trace_data[i] & 0x78) >> 3; - etm_ctx->trace_data[i].flags = 0; - - if ((trace_data[i] & 0x80) >> 7) - etm_ctx->trace_data[i].flags |= ETMV1_TRACESYNC_CYCLE; - - if (etm_ctx->trace_data[i].pipestat == STAT_TR) { - etm_ctx->trace_data[i].pipestat = etm_ctx->trace_data[i].packet & 0x7; - etm_ctx->trace_data[i].flags |= ETMV1_TRIGGER_CYCLE; - } - } - - free(trace_data); - - return ERROR_OK; -} - -static int oocd_trace_start_capture(struct etm_context *etm_ctx) -{ - struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; - uint32_t control = 0x1; /* 0x1: enabled */ - uint32_t trigger_count; - - if (((etm_ctx->control & ETM_PORT_MODE_MASK) != ETM_PORT_NORMAL) - || ((etm_ctx->control & ETM_PORT_WIDTH_MASK) != ETM_PORT_4BIT)) { - LOG_DEBUG("OpenOCD + trace only supports normal 4-bit ETM mode"); - return ERROR_ETM_PORTMODE_NOT_SUPPORTED; - } - - if ((etm_ctx->control & ETM_PORT_CLOCK_MASK) == ETM_PORT_HALF_CLOCK) - control |= 0x2; /* half rate clock, capture at twice the clock rate */ - - /* OpenOCD + trace holds up to 16 million samples, - * but trigger counts is set in multiples of 16 */ - trigger_count = (1048576 * /* trigger_percent */ 50) / 100; - - /* capturing always starts at address zero */ - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, 0x0); - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_TRIGGER_COUNTER, trigger_count); - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, control); - - /* we're starting a new trace, initialize capture status */ - etm_ctx->capture_status = TRACE_RUNNING; - - return ERROR_OK; -} - -static int oocd_trace_stop_capture(struct etm_context *etm_ctx) -{ - struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; - - /* trace stopped, just clear running flag, but preserve others */ - etm_ctx->capture_status &= ~TRACE_RUNNING; - - oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, 0x0); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_oocd_trace_config_command) -{ - struct target *target; - struct arm *arm; - - if (CMD_ARGC != 2) - return ERROR_COMMAND_SYNTAX_ERROR; - - target = get_current_target(CMD_CTX); - arm = target_to_arm(target); - if (!is_arm(arm)) { - command_print(CMD, "current target isn't an ARM"); - return ERROR_FAIL; - } - - if (arm->etm) { - struct oocd_trace *oocd_trace = malloc(sizeof(struct oocd_trace)); - - arm->etm->capture_driver_priv = oocd_trace; - oocd_trace->etm_ctx = arm->etm; - - /* copy name of TTY device used to communicate with OpenOCD + trace */ - oocd_trace->tty = strndup(CMD_ARGV[1], 256); - } else - LOG_ERROR("target has no ETM defined, OpenOCD + trace left unconfigured"); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_oocd_trace_status_command) -{ - struct target *target; - struct arm *arm; - struct oocd_trace *oocd_trace; - uint32_t status; - - target = get_current_target(CMD_CTX); - - arm = target_to_arm(target); - if (!is_arm(arm)) { - command_print(CMD, "current target isn't an ARM"); - return ERROR_FAIL; - } - - if (!arm->etm) { - command_print(CMD, "current target doesn't have an ETM configured"); - return ERROR_FAIL; - } - - if (strcmp(arm->etm->capture_driver->name, "oocd_trace") != 0) { - command_print(CMD, "current target's ETM capture driver isn't 'oocd_trace'"); - return ERROR_FAIL; - } - - oocd_trace = (struct oocd_trace *)arm->etm->capture_driver_priv; - - oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status); - - if (status & 0x8) - command_print(CMD, "trace clock locked"); - else - command_print(CMD, "no trace clock"); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_oocd_trace_resync_command) -{ - struct target *target; - struct arm *arm; - struct oocd_trace *oocd_trace; - size_t bytes_written; - uint8_t cmd_array[1]; - - target = get_current_target(CMD_CTX); - - arm = target_to_arm(target); - if (!is_arm(arm)) { - command_print(CMD, "current target isn't an ARM"); - return ERROR_FAIL; - } - - if (!arm->etm) { - command_print(CMD, "current target doesn't have an ETM configured"); - return ERROR_FAIL; - } - - if (strcmp(arm->etm->capture_driver->name, "oocd_trace") != 0) { - command_print(CMD, "current target's ETM capture driver isn't 'oocd_trace'"); - return ERROR_FAIL; - } - - oocd_trace = (struct oocd_trace *)arm->etm->capture_driver_priv; - - cmd_array[0] = 0xf0; - - bytes_written = write(oocd_trace->tty_fd, cmd_array, 1); - if (bytes_written < 1) - return ERROR_FAIL; - - command_print(CMD, "requesting traceclock resync"); - LOG_DEBUG("resyncing traceclk pll"); - - return ERROR_OK; -} - -static const struct command_registration oocd_trace_all_command_handlers[] = { - { - .name = "config", - .handler = handle_oocd_trace_config_command, - .mode = COMMAND_CONFIG, - .usage = "<target> <tty>", - }, - { - .name = "status", - .handler = handle_oocd_trace_status_command, - .mode = COMMAND_EXEC, - .usage = "", - .help = "display OpenOCD + trace status", - }, - { - .name = "resync", - .handler = handle_oocd_trace_resync_command, - .mode = COMMAND_EXEC, - .usage = "", - .help = "resync OpenOCD + trace capture clock", - }, - COMMAND_REGISTRATION_DONE -}; -static const struct command_registration oocd_trace_command_handlers[] = { - { - .name = "oocd_trace", - .mode = COMMAND_ANY, - .help = "OpenOCD trace capture driver command group", - .usage = "", - .chain = oocd_trace_all_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - -struct etm_capture_driver oocd_trace_capture_driver = { - .name = "oocd_trace", - .commands = oocd_trace_command_handlers, - .init = oocd_trace_init, - .status = oocd_trace_status, - .start_capture = oocd_trace_start_capture, - .stop_capture = oocd_trace_stop_capture, - .read_trace = oocd_trace_read_trace, -}; diff --git a/src/target/oocd_trace.h b/src/target/oocd_trace.h deleted file mode 100644 index e7584e4c9d..0000000000 --- a/src/target/oocd_trace.h +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************** - * 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_OOCD_TRACE_H -#define OPENOCD_TARGET_OOCD_TRACE_H - -#include <termios.h> - -/* registers */ -enum { - OOCD_TRACE_ID = 0x7, - OOCD_TRACE_ADDRESS = 0x0, - OOCD_TRACE_TRIGGER_COUNTER = 0x01, - OOCD_TRACE_CONTROL = 0x2, - OOCD_TRACE_STATUS = 0x3, - OOCD_TRACE_SDRAM_COUNTER = 0x4, -}; - -/* commands */ -enum { - OOCD_TRACE_NOP = 0x0, - OOCD_TRACE_READ_REG = 0x10, - OOCD_TRACE_WRITE_REG = 0x18, - OOCD_TRACE_READ_RAM = 0x20, -/* OOCD_TRACE_WRITE_RAM = 0x28, */ - OOCD_TRACE_RESYNC = 0xf0, -}; - -struct oocd_trace { - struct etm_context *etm_ctx; - char *tty; - int tty_fd; - struct termios oldtio, newtio; -}; - -extern struct etm_capture_driver oocd_trace_capture_driver; - -#endif /* OPENOCD_TARGET_OOCD_TRACE_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 1d05944bc7..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 @@ -57,7 +46,7 @@ static int telnet_write(struct connection *connection, const void *data, int len return ERROR_SERVER_REMOTE_CLOSED; } -int jsp_poll_read(void *priv) +static int jsp_poll_read(void *priv) { struct jsp_service *jsp_service = (struct jsp_service *)priv; unsigned char out_buffer[10]; @@ -103,7 +92,7 @@ static int jsp_new_connection(struct connection *connection) int retval = target_register_timer_callback(&jsp_poll_read, 1, TARGET_TIMER_TYPE_PERIODIC, jsp_service); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; return ERROR_OK; @@ -187,7 +176,7 @@ static int jsp_connection_closed(struct connection *connection) struct jsp_service *jsp_service = connection->service->priv; int retval = target_unregister_timer_callback(&jsp_poll_read, jsp_service); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; free(connection->priv); @@ -195,19 +184,22 @@ static int jsp_connection_closed(struct connection *connection) return ERROR_OK; } +static const struct service_driver jsp_service_driver = { + .name = "jsp", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = jsp_new_connection, + .input_handler = jsp_input, + .connection_closed_handler = jsp_connection_closed, + .keep_client_alive_handler = NULL, +}; + int jsp_init(struct or1k_jtag *jtag_info, char *banner) { struct jsp_service *jsp_service = malloc(sizeof(struct jsp_service)); jsp_service->banner = banner; jsp_service->jtag_info = jtag_info; - return add_service("jsp", - jsp_port, - 1, - jsp_new_connection, - jsp_input, - jsp_connection_closed, - jsp_service); + return add_service(&jsp_service_driver, jsp_port, 1, jsp_service); } COMMAND_HANDLER(handle_jsp_port_command) 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 d685359be0..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; } @@ -923,9 +912,9 @@ static int or1k_add_breakpoint(struct target *target, struct or1k_du *du_core = or1k_to_du(or1k); uint8_t data; - LOG_DEBUG("Adding breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, set: %d, id: %" PRIu32, + LOG_DEBUG("Adding breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, id: %" PRIu32, breakpoint->address, breakpoint->length, breakpoint->type, - breakpoint->set, breakpoint->unique_id); + breakpoint->unique_id); /* Only support SW breakpoints for now. */ if (breakpoint->type == BKPT_HARD) @@ -981,9 +970,9 @@ static int or1k_remove_breakpoint(struct target *target, struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); - LOG_DEBUG("Removing breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, set: %d, id: %" PRIu32, + LOG_DEBUG("Removing breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, id: %" PRIu32, breakpoint->address, breakpoint->length, breakpoint->type, - breakpoint->set, breakpoint->unique_id); + breakpoint->unique_id); /* Only support SW breakpoints for now. */ if (breakpoint->type == BKPT_HARD) @@ -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; } @@ -1089,12 +1078,12 @@ static int or1k_init_target(struct command_context *cmd_ctx, struct or1k_du *du_core = or1k_to_du(or1k); struct or1k_jtag *jtag = &or1k->jtag; - if (du_core == NULL) { + if (!du_core) { LOG_ERROR("No debug unit selected"); return ERROR_FAIL; } - if (jtag->tap_ip == NULL) { + if (!jtag->tap_ip) { LOG_ERROR("No tap selected"); return ERROR_FAIL; } @@ -1111,7 +1100,7 @@ static int or1k_init_target(struct command_context *cmd_ctx, static int or1k_target_create(struct target *target, Jim_Interp *interp) { - if (target->tap == NULL) + if (!target->tap) return ERROR_FAIL; struct or1k_common *or1k = calloc(1, sizeof(struct or1k_common)); @@ -1200,7 +1189,7 @@ static int or1k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], } -int or1k_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) +static int or1k_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { return ERROR_FAIL; } 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 31b2487763..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 @@ retry_read_full: 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 @@ retry_full_write: 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,8 +912,8 @@ 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)); - if (t == NULL) { + 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 42d3b8c736..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 */ @@ -43,10 +32,10 @@ #include "lakemont.h" #include "x86_32_common.h" -int quark_d20xx_target_create(struct target *t, Jim_Interp *interp) +static int quark_d20xx_target_create(struct target *t, Jim_Interp *interp) { struct x86_32_common *x86_32 = calloc(1, sizeof(struct x86_32_common)); - if (x86_32 == NULL) { + if (!x86_32) { LOG_ERROR("%s out of memory", __func__); return ERROR_FAIL; } @@ -56,7 +45,7 @@ int quark_d20xx_target_create(struct target *t, Jim_Interp *interp) return ERROR_OK; } -int quark_d20xx_init_target(struct command_context *cmd_ctx, struct target *t) +static int quark_d20xx_init_target(struct command_context *cmd_ctx, struct target *t) { return lakemont_init_target(cmd_ctx, t); } 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 4ddda6e6b3..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 @@ -39,21 +28,20 @@ struct reg *register_get_by_number(struct reg_cache *first, uint32_t reg_num, bool search_all) { - unsigned i; struct reg_cache *cache = first; while (cache) { - for (i = 0; i < cache->num_regs; i++) { - if (cache->reg_list[i].exist == false) + for (unsigned int i = 0; i < cache->num_regs; i++) { + if (!cache->reg_list[i].exist) continue; if (cache->reg_list[i].number == reg_num) return &(cache->reg_list[i]); } - if (search_all) - cache = cache->next; - else + if (!search_all) break; + + cache = cache->next; } return NULL; @@ -62,21 +50,20 @@ struct reg *register_get_by_number(struct reg_cache *first, struct reg *register_get_by_name(struct reg_cache *first, const char *name, bool search_all) { - unsigned i; struct reg_cache *cache = first; while (cache) { - for (i = 0; i < cache->num_regs; i++) { - if (cache->reg_list[i].exist == false) + for (unsigned int i = 0; i < cache->num_regs; i++) { + if (!cache->reg_list[i].exist) continue; if (strcmp(cache->reg_list[i].name, name) == 0) return &(cache->reg_list[i]); } - if (search_all) - cache = cache->next; - else + if (!search_all) break; + + cache = cache->next; } return NULL; @@ -106,10 +93,9 @@ 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 n = cache->num_regs; n != 0; n--, reg++) { - if (reg->exist == false) + for (unsigned int n = 0; n < cache->num_regs; n++) { + struct reg *reg = &cache->reg_list[n]; + if (!reg->exist) continue; reg->valid = false; reg->dirty = false; diff --git a/src/target/register.h b/src/target/register.h index 7c53d6e16d..1e4f2e0889 100644 --- a/src/target/register.h +++ b/src/target/register.h @@ -1,27 +1,19 @@ +/* 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 #define OPENOCD_TARGET_REGISTER_H +#include "helper/replacements.h" +#include "helper/types.h" + struct target; enum reg_type { @@ -127,13 +119,15 @@ struct reg { bool caller_save; /* Pointer to place where the value is stored, in the format understood by * the binarybuffer.h functions. */ - void *value; + uint8_t *value; /* The stored value needs to be written to the target. */ bool dirty; /* When true, value is valid. */ bool valid; /* When false, the register doesn't actually exist in the target. */ bool exist; + /* Hide the register from gdb and omit it in 'reg' cmd output */ + bool hidden; /* Size of the register in bits. */ uint32_t size; /* Used for generating XML description of registers. Can be set to NULL for diff --git a/src/target/riscv/Makefile.am b/src/target/riscv/Makefile.am index 83f1a8ca3e..4b6a74f0b8 100644 --- a/src/target/riscv/Makefile.am +++ b/src/target/riscv/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libriscv.la %C%_libriscv_la_SOURCES = \ %D%/asm.h \ diff --git a/src/target/riscv/asm.h b/src/target/riscv/asm.h index d81aa02859..6ceb8c9bd2 100644 --- a/src/target/riscv/asm.h +++ b/src/target/riscv/asm.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + #ifndef TARGET__RISCV__ASM_H #define TARGET__RISCV__ASM_H diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index d041ed1192..d39967e4df 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -9,21 +11,63 @@ #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) +#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)) + 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; struct riscv_batch *out = calloc(1, sizeof(*out)); + if (!out) + goto error0; out->target = target; out->allocated_scans = scans; out->idle_count = idle; - out->data_out = malloc(sizeof(*out->data_out) * (scans) * sizeof(uint64_t)); - out->data_in = malloc(sizeof(*out->data_in) * (scans) * sizeof(uint64_t)); + 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; + }; + 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; + } out->fields = malloc(sizeof(*out->fields) * (scans)); + if (!out->fields) { + LOG_ERROR("Failed to allocate fields in RISC-V batch."); + goto error3; + } + if (bscan_tunnel_ir_width != 0) { + 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; + } + } out->last_scan = RISCV_SCAN_TYPE_INVALID; 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; + } 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: + return NULL; } void riscv_batch_free(struct riscv_batch *batch) @@ -31,6 +75,8 @@ void riscv_batch_free(struct riscv_batch *batch) free(batch->data_in); free(batch->data_out); free(batch->fields); + free(batch->bscan_ctxt); + free(batch->read_keys); free(batch); } @@ -46,21 +92,35 @@ int riscv_batch_run(struct riscv_batch *batch) return ERROR_OK; } - keep_alive(); - riscv_batch_add_nop(batch); for (size_t i = 0; i < batch->used_scans; ++i) { - jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE); + if (bscan_tunnel_ir_width != 0) + 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); + if (batch->idle_count > 0) jtag_add_runtest(batch->idle_count, TAP_IDLE); } + keep_alive(); + if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("Unable to execute JTAG queue"); return ERROR_FAIL; } + keep_alive(); + + 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) { + 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) dump_field(batch->idle_count, batch->fields + i); @@ -72,8 +132,8 @@ void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint 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->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t)); - field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t)); + 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); batch->last_scan = RISCV_SCAN_TYPE_WRITE; @@ -85,35 +145,35 @@ size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned 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->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t)); - field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t)); + 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); batch->last_scan = RISCV_SCAN_TYPE_READ; batch->used_scans++; - /* FIXME We get the read response back on the next scan. For now I'm - * just sticking a NOP in there, but this should be coalesced away. */ - riscv_batch_add_nop(batch); - - batch->read_keys[batch->read_keys_used] = batch->used_scans - 1; + batch->read_keys[batch->read_keys_used] = batch->used_scans; return batch->read_keys_used++; } -uint64_t riscv_batch_get_dmi_read(struct riscv_batch *batch, size_t key) +unsigned riscv_batch_get_dmi_read_op(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); - uint8_t *base = batch->data_in + 8 * index; - return base[0] | - ((uint64_t) base[1]) << 8 | - ((uint64_t) base[2]) << 16 | - ((uint64_t) base[3]) << 24 | - ((uint64_t) base[4]) << 32 | - ((uint64_t) base[5]) << 40 | - ((uint64_t) base[6]) << 48 | - ((uint64_t) base[7]) << 56; + 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); +} + +uint32_t riscv_batch_get_dmi_read_data(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); + 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); } void riscv_batch_add_nop(struct riscv_batch *batch) @@ -121,8 +181,8 @@ 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->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t)); - field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t)); + 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); batch->last_scan = RISCV_SCAN_TYPE_NOP; @@ -137,7 +197,7 @@ void dump_field(int idle, const struct scan_field *field) if (debug_level < LOG_LVL_DEBUG) return; - assert(field->out_value != NULL); + assert(field->out_value); uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits); unsigned int out_op = get_field(out, DTM_DMI_OP); unsigned int out_data = get_field(out, DTM_DMI_DATA); @@ -151,13 +211,17 @@ void dump_field(int idle, const struct scan_field *field) log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, __PRETTY_FUNCTION__, - "%db %di %s %08x @%02x -> %s %08x @%02x", - field->num_bits, idle, - op_string[out_op], out_data, out_address, - status_string[in_op], in_data, in_address); + "%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 %di %s %08x @%02x -> ?", - field->num_bits, idle, op_string[out_op], out_data, out_address); + __FILE__, __LINE__, __PRETTY_FUNCTION__, "%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; +} diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h index 70690a601c..9c42ba81ea 100644 --- a/src/target/riscv/batch.h +++ b/src/target/riscv/batch.h @@ -1,8 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + #ifndef TARGET__RISCV__SCANS_H #define TARGET__RISCV__SCANS_H #include "target/target.h" #include "jtag/jtag.h" +#include "riscv.h" enum riscv_scan_type { RISCV_SCAN_TYPE_INVALID, @@ -27,6 +30,11 @@ struct riscv_batch { uint8_t *data_in; struct scan_field *fields; + /* If in BSCAN mode, this field will be allocated (one per scan), + and utilized to tunnel all the scans in the batch. If not in + BSCAN mode, this field is unallocated and stays NULL */ + riscv_bscan_tunneled_scan_context_t *bscan_ctxt; + /* In JTAG we scan out the previous value's output when performing a * scan. This is a pain for users, so we just provide them the * illusion of not having to do this by eliding all but the last NOP. @@ -54,11 +62,16 @@ int riscv_batch_run(struct riscv_batch *batch); void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data); /* DMI reads must be handled in two parts: the first one schedules a read and - * provides a key, the second one actually obtains the value of that read .*/ + * 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); -uint64_t riscv_batch_get_dmi_read(struct riscv_batch *batch, size_t key); +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); /* Scans in a NOP. */ 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); + #endif diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h index d6ddd4ff1e..8113d47664 100644 --- a/src/target/riscv/debug_defines.h +++ b/src/target/riscv/debug_defines.h @@ -1,1414 +1,3061 @@ +/* + * This file is auto-generated by running 'make debug_defines.h' in + * https://github.com/riscv/riscv-debug-spec/ (d749752) + */ + #define DTM_IDCODE 0x01 /* -* Identifies the release version of this part. + * Identifies the release version of this part. */ -#define DTM_IDCODE_VERSION_OFFSET 28 +#define DTM_IDCODE_VERSION_OFFSET 0x1c #define DTM_IDCODE_VERSION_LENGTH 4 -#define DTM_IDCODE_VERSION (0xfU << DTM_IDCODE_VERSION_OFFSET) +#define DTM_IDCODE_VERSION 0xf0000000U /* -* Identifies the designer's part number of this part. + * Identifies the designer's part number of this part. */ -#define DTM_IDCODE_PARTNUMBER_OFFSET 12 -#define DTM_IDCODE_PARTNUMBER_LENGTH 16 -#define DTM_IDCODE_PARTNUMBER (0xffffU << DTM_IDCODE_PARTNUMBER_OFFSET) +#define DTM_IDCODE_PARTNUMBER_OFFSET 0xc +#define DTM_IDCODE_PARTNUMBER_LENGTH 0x10 +#define DTM_IDCODE_PARTNUMBER 0xffff000 /* -* Identifies the designer/manufacturer of this part. Bits 6:0 must be -* bits 6:0 of the designer/manufacturer's Identification Code as -* assigned by JEDEC Standard JEP106. Bits 10:7 contain the modulo-16 -* count of the number of continuation characters (0x7f) in that same -* Identification Code. + * Identifies the designer/manufacturer of this part. Bits 6:0 must be + * bits 6:0 of the designer/manufacturer's Identification Code as + * assigned by JEDEC Standard JEP106. Bits 10:7 contain the modulo-16 + * count of the number of continuation characters (0x7f) in that same + * Identification Code. */ #define DTM_IDCODE_MANUFID_OFFSET 1 -#define DTM_IDCODE_MANUFID_LENGTH 11 -#define DTM_IDCODE_MANUFID (0x7ffU << DTM_IDCODE_MANUFID_OFFSET) +#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 (0x1U << DTM_IDCODE_1_OFFSET) +#define DTM_IDCODE_1 1 #define DTM_DTMCS 0x10 /* -* Writing 1 to this bit does a hard reset of the DTM, -* causing the DTM to forget about any outstanding DMI transactions. -* In general this should only be used when the Debugger has -* reason to expect that the outstanding DMI transaction will never -* complete (e.g. a reset condition caused an inflight DMI transaction to -* be cancelled). + * Writing 1 to this bit does a hard reset of the DTM, + * causing the DTM to forget about any outstanding DMI transactions, and + * returning all registers and internal state to their reset value. + * In general this should only be used when the Debugger has + * reason to expect that the outstanding DMI transaction will never + * complete (e.g. a reset condition caused an inflight DMI transaction to + * be cancelled). */ -#define DTM_DTMCS_DMIHARDRESET_OFFSET 17 +#define DTM_DTMCS_DMIHARDRESET_OFFSET 0x11 #define DTM_DTMCS_DMIHARDRESET_LENGTH 1 -#define DTM_DTMCS_DMIHARDRESET (0x1U << DTM_DTMCS_DMIHARDRESET_OFFSET) +#define DTM_DTMCS_DMIHARDRESET 0x20000 /* -* Writing 1 to this bit clears the sticky error state -* and allows the DTM to retry or complete the previous -* transaction. + * Writing 1 to this bit clears the sticky error state, but does + * not affect outstanding DMI transactions. */ -#define DTM_DTMCS_DMIRESET_OFFSET 16 +#define DTM_DTMCS_DMIRESET_OFFSET 0x10 #define DTM_DTMCS_DMIRESET_LENGTH 1 -#define DTM_DTMCS_DMIRESET (0x1U << DTM_DTMCS_DMIRESET_OFFSET) -/* -* This is a hint to the debugger of the minimum number of -* cycles a debugger should spend in -* Run-Test/Idle after every DMI scan to avoid a `busy' -* return code (\Fdmistat of 3). A debugger must still -* check \Fdmistat when necessary. -* -* 0: It is not necessary to enter Run-Test/Idle at all. -* -* 1: Enter Run-Test/Idle and leave it immediately. -* -* 2: Enter Run-Test/Idle and stay there for 1 cycle before leaving. -* -* And so on. - */ -#define DTM_DTMCS_IDLE_OFFSET 12 +#define DTM_DTMCS_DMIRESET 0x10000 +/* + * This is a hint to the debugger of the minimum number of + * cycles a debugger should spend in + * Run-Test/Idle after every DMI scan to avoid a `busy' + * return code (\FdtmDtmcsDmistat of 3). A debugger must still + * check \FdtmDtmcsDmistat when necessary. + * + * 0: It is not necessary to enter Run-Test/Idle at all. + * + * 1: Enter Run-Test/Idle and leave it immediately. + * + * 2: Enter Run-Test/Idle and stay there for 1 cycle before leaving. + * + * And so on. + */ +#define DTM_DTMCS_IDLE_OFFSET 0xc #define DTM_DTMCS_IDLE_LENGTH 3 -#define DTM_DTMCS_IDLE (0x7U << DTM_DTMCS_IDLE_OFFSET) -/* -* 0: No error. -* -* 1: Reserved. Interpret the same as 2. -* -* 2: An operation failed (resulted in \Fop of 2). -* -* 3: An operation was attempted while a DMI access was still in -* progress (resulted in \Fop of 3). - */ -#define DTM_DTMCS_DMISTAT_OFFSET 10 +#define DTM_DTMCS_IDLE 0x7000 +/* + * Read-only alias of \FdtmDmiOp. + */ +#define DTM_DTMCS_DMISTAT_OFFSET 0xa #define DTM_DTMCS_DMISTAT_LENGTH 2 -#define DTM_DTMCS_DMISTAT (0x3U << DTM_DTMCS_DMISTAT_OFFSET) +#define DTM_DTMCS_DMISTAT 0xc00 /* -* The size of \Faddress in \Rdmi. + * The size of \FdmSbaddressZeroAddress in \RdtmDmi. */ #define DTM_DTMCS_ABITS_OFFSET 4 #define DTM_DTMCS_ABITS_LENGTH 6 -#define DTM_DTMCS_ABITS (0x3fU << DTM_DTMCS_ABITS_OFFSET) -/* -* 0: Version described in spec version 0.11. -* -* 1: Version described in spec version 0.13 (and later?), which -* reduces the DMI data width to 32 bits. -* -* 15: Version not described in any available version of this spec. - */ +#define DTM_DTMCS_ABITS 0x3f0 #define DTM_DTMCS_VERSION_OFFSET 0 #define DTM_DTMCS_VERSION_LENGTH 4 -#define DTM_DTMCS_VERSION (0xfU << DTM_DTMCS_VERSION_OFFSET) +#define DTM_DTMCS_VERSION 0xf +/* + * 0.11: Version described in spec version 0.11. + */ +#define DTM_DTMCS_VERSION_0_11 0 +/* + * 1.0: Version described in spec versions 0.13 and 1.0. + */ +#define DTM_DTMCS_VERSION_1_0 1 +/* + * custom: Version not described in any available version of this spec. + */ +#define DTM_DTMCS_VERSION_CUSTOM 15 #define DTM_DMI 0x11 /* -* Address used for DMI access. In Update-DR this value is used -* to access the DM over the DMI. + * Address used for DMI access. In Update-DR this value is used + * to access the DM over the DMI. */ -#define DTM_DMI_ADDRESS_OFFSET 34 -#define DTM_DMI_ADDRESS_LENGTH abits -#define DTM_DMI_ADDRESS (((1L<<abits)-1) << DTM_DMI_ADDRESS_OFFSET) +#define DTM_DMI_ADDRESS_OFFSET 0x22 +#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. + * 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 32 -#define DTM_DMI_DATA (0xffffffffULL << DTM_DMI_DATA_OFFSET) -/* -* When the debugger writes this field, it has the following meaning: -* -* 0: Ignore \Fdata and \Faddress. (nop) -* -* Don't send anything over the DMI during Update-DR. -* This operation should never result in a busy or error response. -* The address and data reported in the following Capture-DR -* are undefined. -* -* 1: Read from \Faddress. (read) -* -* 2: Write \Fdata to \Faddress. (write) -* -* 3: Reserved. -* -* When the debugger reads this field, it means the following: -* -* 0: The previous operation completed successfully. -* -* 1: Reserved. -* -* 2: A previous operation failed. The data scanned into \Rdmi in -* this access will be ignored. This status is sticky and can be -* cleared by writing \Fdmireset in \Rdtmcs. -* -* This indicates that the DM itself responded with an error. -* Note: there are no specified cases in which the DM would -* respond with an error, and DMI is not required to support -* returning errors. -* -* 3: An operation was attempted while a DMI request is still in -* progress. The data scanned into \Rdmi in this access will be -* ignored. This status is sticky and can be cleared by writing -* \Fdmireset in \Rdtmcs. If a debugger sees this status, it -* needs to give the target more TCK edges between Update-DR and -* Capture-DR. The simplest way to do that is to add extra transitions -* in Run-Test/Idle. -* -* (The DTM, DM, and/or component may be in different clock domains, -* so synchronization may be required. Some relatively fixed number of -* TCK ticks may be needed for the request to reach the DM, complete, -* and for the response to be synchronized back into the TCK domain.) +#define DTM_DMI_DATA_LENGTH 0x20 +#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 (0x3ULL << DTM_DMI_OP_OFFSET) +#define DTM_DMI_OP 3 +/* + * nop: Ignore \FdmSbdataZeroData and \FdmSbaddressZeroAddress. + * + * Don't send anything over the DMI during Update-DR. + * This operation should never result in a busy or error response. + * The address and data reported in the following Capture-DR + * are undefined. + */ +#define DTM_DMI_OP_NOP 0 +/* + * read: Read from \FdmSbaddressZeroAddress. + */ +#define DTM_DMI_OP_READ 1 +/* + * write: Write \FdmSbdataZeroData to \FdmSbaddressZeroAddress. + */ +#define DTM_DMI_OP_WRITE 2 +/* + * reserved: Reserved. + */ +/* + * When the debugger reads this field, it means the following: + */ +/* + * success: The previous operation completed successfully. + */ +#define DTM_DMI_OP_SUCCESS 0 +/* + * reserved: Reserved. + */ +/* + * failed: A previous operation failed. The data scanned into \RdtmDmi in + * 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. + * There are no specified cases in which the DM would + * respond with an error, and DMI is not required to support + * returning errors. + */ +#define DTM_DMI_OP_FAILED 2 +/* + * busy: An operation was attempted while a DMI request is still in + * progress. The data scanned into \RdtmDmi in this access will be + * ignored. This status is sticky and can be cleared by writing + * \FdtmDtmcsDmireset in \RdtmDtmcs. If a debugger sees this status, it + * needs to give the target more TCK edges between Update-DR and + * Capture-DR. The simplest way to do that is to add extra transitions + * in Run-Test/Idle. + */ +#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 +/* + * none: There is no debug support. + */ +#define CSR_DCSR_DEBUGVER_NONE 0 +/* + * 1.0: Debug support exists as it is described in this document. + */ +#define CSR_DCSR_DEBUGVER_1_0 4 +/* + * custom: There is debug support, but it does not conform to any + * 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 +/* + * exception: {\tt ebreak} instructions in VS-mode behave as described in the + * Privileged Spec. + */ +#define CSR_DCSR_EBREAKVS_EXCEPTION 0 +/* + * debug mode: {\tt ebreak} instructions in VS-mode enter Debug Mode. + */ +#define CSR_DCSR_EBREAKVS_DEBUG_MODE 1 +/* + * 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 +/* + * exception: {\tt ebreak} instructions in VU-mode behave as described in the + * Privileged Spec. + */ +#define CSR_DCSR_EBREAKVU_EXCEPTION 0 /* -* 0: There is no external debug support. -* -* 4: External debug support exists as it is described in this document. -* -* 15: There is external debug support, but it does not conform to any -* available version of this spec. + * debug mode: {\tt ebreak} instructions in VU-mode enter Debug Mode. */ -#define CSR_DCSR_XDEBUGVER_OFFSET 28 -#define CSR_DCSR_XDEBUGVER_LENGTH 4 -#define CSR_DCSR_XDEBUGVER (0xfU << CSR_DCSR_XDEBUGVER_OFFSET) +#define CSR_DCSR_EBREAKVU_DEBUG_MODE 1 /* -* When 1, {\tt ebreak} instructions in Machine Mode enter Debug Mode. + * This bit is hardwired to 0 if the hart does not support virtualization mode. */ -#define CSR_DCSR_EBREAKM_OFFSET 15 +#define CSR_DCSR_EBREAKM_OFFSET 0xf #define CSR_DCSR_EBREAKM_LENGTH 1 -#define CSR_DCSR_EBREAKM (0x1U << CSR_DCSR_EBREAKM_OFFSET) +#define CSR_DCSR_EBREAKM 0x8000 +/* + * exception: {\tt ebreak} instructions in M-mode behave as described in the + * Privileged Spec. + */ +#define CSR_DCSR_EBREAKM_EXCEPTION 0 /* -* When 1, {\tt ebreak} instructions in Supervisor Mode enter Debug Mode. + * debug mode: {\tt ebreak} instructions in M-mode enter Debug Mode. */ -#define CSR_DCSR_EBREAKS_OFFSET 13 +#define CSR_DCSR_EBREAKM_DEBUG_MODE 1 +#define CSR_DCSR_EBREAKS_OFFSET 0xd #define CSR_DCSR_EBREAKS_LENGTH 1 -#define CSR_DCSR_EBREAKS (0x1U << CSR_DCSR_EBREAKS_OFFSET) +#define CSR_DCSR_EBREAKS 0x2000 +/* + * exception: {\tt ebreak} instructions in S-mode behave as described in the + * Privileged Spec. + */ +#define CSR_DCSR_EBREAKS_EXCEPTION 0 +/* + * debug mode: {\tt ebreak} instructions in S-mode enter Debug Mode. + */ +#define CSR_DCSR_EBREAKS_DEBUG_MODE 1 /* -* When 1, {\tt ebreak} instructions in User/Application Mode enter -* Debug Mode. + * This bit is hardwired to 0 if the hart does not support S-mode. */ -#define CSR_DCSR_EBREAKU_OFFSET 12 +#define CSR_DCSR_EBREAKU_OFFSET 0xc #define CSR_DCSR_EBREAKU_LENGTH 1 -#define CSR_DCSR_EBREAKU (0x1U << CSR_DCSR_EBREAKU_OFFSET) -/* -* 0: Interrupts are disabled during single stepping. -* -* 1: Interrupts are enabled during single stepping. -* -* Implementations may hard wire this bit to 0. -* The debugger must read back the value it -* writes to check whether the feature is supported. If not -* supported, interrupt behavior can be emulated by the debugger. - */ -#define CSR_DCSR_STEPIE_OFFSET 11 +#define CSR_DCSR_EBREAKU 0x1000 +/* + * exception: {\tt ebreak} instructions in U-mode behave as described in the + * Privileged Spec. + */ +#define CSR_DCSR_EBREAKU_EXCEPTION 0 +/* + * debug mode: {\tt ebreak} instructions in U-mode enter Debug Mode. + */ +#define CSR_DCSR_EBREAKU_DEBUG_MODE 1 +/* + * 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 (0x1U << CSR_DCSR_STEPIE_OFFSET) -/* -* 0: Increment counters as usual. -* -* 1: Don't increment any counters while in Debug Mode or on {\tt -* ebreak} instructions that cause entry into Debug Mode. These -* counters include the {\tt cycle} and {\tt instret} CSRs. This is -* preferred for most debugging scenarios. -* -* An implementation may choose not to support writing to this bit. -* The debugger must read back the value it writes to check whether -* the feature is supported. - */ -#define CSR_DCSR_STOPCOUNT_OFFSET 10 +#define CSR_DCSR_STEPIE 0x800 +/* + * interrupts disabled: Interrupts (including NMI) are disabled during single stepping. + */ +#define CSR_DCSR_STEPIE_INTERRUPTS_DISABLED 0 +/* + * interrupts enabled: Interrupts (including NMI) are enabled during single stepping. + */ +#define CSR_DCSR_STEPIE_INTERRUPTS_ENABLED 1 +/* + * Implementations may hard wire this bit to 0. + * In that case interrupt behavior can be emulated by the debugger. + * + * 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 (0x1U << CSR_DCSR_STOPCOUNT_OFFSET) +#define CSR_DCSR_STOPCOUNT 0x400 +/* + * normal: Increment counters as usual. + */ +#define CSR_DCSR_STOPCOUNT_NORMAL 0 +/* + * freeze: Don't increment any hart-local counters while in Debug Mode or + * on {\tt ebreak} instructions that cause entry into Debug Mode. + * These counters include the {\tt instret} CSR. On single-hart cores + * {\tt cycle} should be stopped, but on multi-hart cores it must keep + * incrementing. + */ +#define CSR_DCSR_STOPCOUNT_FREEZE 1 /* -* 0: Increment timers as usual. -* -* 1: Don't increment any hart-local timers while in Debug Mode. -* -* An implementation may choose not to support writing to this bit. -* The debugger must read back the value it writes to check whether -* the feature is supported. + * 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 (0x1U << CSR_DCSR_STOPTIME_OFFSET) -/* -* Explains why Debug Mode was entered. -* -* When there are multiple reasons to enter Debug Mode in a single -* cycle, hardware should set \Fcause to the cause with the highest -* priority. -* -* 1: An {\tt ebreak} instruction was executed. (priority 3) -* -* 2: The Trigger Module caused a breakpoint exception. (priority 4) -* -* 3: The debugger requested entry to Debug Mode. (priority 2) -* -* 4: The hart single stepped because \Fstep was set. (priority 1) -* -* Other values are reserved for future use. +#define CSR_DCSR_STOPTIME 0x200 +/* + * normal: Increment \Rtime as usual. + */ +#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. + */ +#define CSR_DCSR_STOPTIME_FREEZE 1 +/* + * An implementation may hardwire this bit to 0 or 1. + */ +/* + * Explains why Debug Mode was entered. + * + * When there are multiple reasons to enter Debug Mode in a single + * 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 (0x7U << CSR_DCSR_CAUSE_OFFSET) +#define CSR_DCSR_CAUSE 0x1c0 +/* + * ebreak: An {\tt ebreak} instruction was executed. + */ +#define CSR_DCSR_CAUSE_EBREAK 1 +/* + * trigger: A Trigger Module trigger fired with action=1. + */ +#define CSR_DCSR_CAUSE_TRIGGER 2 +/* + * haltreq: The debugger requested entry to Debug Mode using \FdmDmcontrolHaltreq. + */ +#define CSR_DCSR_CAUSE_HALTREQ 3 /* -* When 1, \Fmprv in \Rmstatus takes effect during debug mode. -* When 0, it is ignored during debug mode. -* Implementing this bit is optional. -* If not implemented it should be tied to 0. + * step: The hart single stepped because \FcsrDcsrStep was set. */ +#define CSR_DCSR_CAUSE_STEP 4 +/* + * resethaltreq: The hart halted directly out of reset due to \Fresethaltreq. It + * is also acceptable to report 3 when this happens. + */ +#define CSR_DCSR_CAUSE_RESETHALTREQ 5 +/* + * group: The hart halted because it's part of a halt group. + * Harts may report 3 for this cause instead. + */ +#define CSR_DCSR_CAUSE_GROUP 6 +/* + * Other values are reserved for future use. + */ +/* + * Extends the prv field with the virtualization mode the hart was operating + * in when Debug Mode was entered. The encoding is described in Table + * \ref{tab:privmode}. + * A debugger can change this value to change the hart's virtualization mode + * 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 (0x1U << CSR_DCSR_MPRVEN_OFFSET) +#define CSR_DCSR_MPRVEN 0x10 /* -* When set, there is a Non-Maskable-Interrupt (NMI) pending for the hart. -* -* Since an NMI can indicate a hardware error condition, -* reliable debugging may no longer be possible once this bit becomes set. -* This is implementation-dependent. + * disabled: \FcsrMstatusMprv in \Rmstatus is ignored in Debug Mode. + */ +#define CSR_DCSR_MPRVEN_DISABLED 0 +/* + * enabled: \FcsrMstatusMprv in \Rmstatus takes effect in Debug Mode. + */ +#define CSR_DCSR_MPRVEN_ENABLED 1 +/* + * Implementing this bit is optional. It may be tied to either 0 or 1. + */ +/* + * When set, there is a Non-Maskable-Interrupt (NMI) pending for the hart. + * + * Since an NMI can indicate a hardware error condition, + * 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 (0x1U << CSR_DCSR_NMIP_OFFSET) +#define CSR_DCSR_NMIP 8 /* -* When set and not in Debug Mode, the hart will only execute a single -* instruction and then enter Debug Mode. -* If the instruction does not complete due to an exception, -* the hart will immediately enter Debug Mode before executing -* the trap handler, with appropriate exception registers set. + * When set and not in Debug Mode, the hart will only execute a single + * instruction and then enter Debug Mode. See Section~\ref{stepBit} + * for details. + * + * 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 (0x1U << CSR_DCSR_STEP_OFFSET) +#define CSR_DCSR_STEP 4 /* -* Contains the privilege level the hart was operating in when Debug -* Mode was entered. The encoding is described in Table -* \ref{tab:privlevel}. A debugger can change this value to change -* the hart's privilege level when exiting Debug Mode. -* -* Not all privilege levels are supported on all harts. If the -* encoding written is not supported or the debugger is not allowed to -* change to it, the hart may change to any supported privilege level. + * Contains the privilege mode the hart was operating in when Debug + * Mode was entered. The encoding is described in Table + * \ref{tab:privmode}. A debugger can change this value to change + * the hart's privilege mode when exiting Debug Mode. + * + * Not all privilege modes are supported on all harts. If the + * 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 (0x3U << CSR_DCSR_PRV_OFFSET) +#define CSR_DCSR_PRV 3 #define CSR_DPC 0x7b1 #define CSR_DPC_DPC_OFFSET 0 -#define CSR_DPC_DPC_LENGTH MXLEN -#define CSR_DPC_DPC (((1L<<MXLEN)-1) << CSR_DPC_DPC_OFFSET) +#define CSR_DPC_DPC_LENGTH(DXLEN) DXLEN +#define CSR_DPC_DPC(DXLEN) ((1ULL<<DXLEN) + -1) #define CSR_DSCRATCH0 0x7b2 #define CSR_DSCRATCH1 0x7b3 #define CSR_TSELECT 0x7a0 #define CSR_TSELECT_INDEX_OFFSET 0 -#define CSR_TSELECT_INDEX_LENGTH MXLEN -#define CSR_TSELECT_INDEX (((1L<<MXLEN)-1) << CSR_TSELECT_INDEX_OFFSET) +#define CSR_TSELECT_INDEX_LENGTH(XLEN) XLEN +#define CSR_TSELECT_INDEX(XLEN) ((1ULL<<XLEN) + -1) #define CSR_TDATA1 0x7a1 -/* -* 0: There is no trigger at this \Rtselect. -* -* 1: The trigger is a legacy SiFive address match trigger. These -* should not be implemented and aren't further documented here. -* -* 2: The trigger is an address/data match trigger. The remaining bits -* in this register act as described in \Rmcontrol. -* -* 3: The trigger is an instruction count trigger. The remaining bits -* in this register act as described in \Ricount. -* -* 4: The trigger is an interrupt trigger. The remaining bits -* in this register act as described in \Ritrigger. -* -* 5: The trigger is an exception trigger. The remaining bits -* in this register act as described in \Retrigger. -* -* 15: This trigger exists (so enumeration shouldn't terminate), but -* is not currently available. -* -* Other values are reserved for future use. -* -* When this field is written to an unsupported value, it takes on its -* reset value instead. The reset value is any one of the types -* supported by the trigger selected by \Rtselect. - */ -#define CSR_TDATA1_TYPE_OFFSET (MXLEN-4) +#define CSR_TDATA1_TYPE_OFFSET(XLEN) (XLEN + -4) #define CSR_TDATA1_TYPE_LENGTH 4 -#define CSR_TDATA1_TYPE (0xfULL << CSR_TDATA1_TYPE_OFFSET) +#define CSR_TDATA1_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) +/* + * none: There is no trigger at this \RcsrTselect. + */ +#define CSR_TDATA1_TYPE_NONE 0 +/* + * legacy: The trigger is a legacy SiFive address match trigger. These + * should not be implemented and aren't further documented here. + */ +#define CSR_TDATA1_TYPE_LEGACY 1 +/* + * mcontrol: The trigger is an address/data match trigger. The remaining bits + * in this register act as described in \RcsrMcontrol. + */ +#define CSR_TDATA1_TYPE_MCONTROL 2 +/* + * icount: The trigger is an instruction count trigger. The remaining bits + * in this register act as described in \RcsrIcount. + */ +#define CSR_TDATA1_TYPE_ICOUNT 3 +/* + * itrigger: The trigger is an interrupt trigger. The remaining bits + * in this register act as described in \RcsrItrigger. + */ +#define CSR_TDATA1_TYPE_ITRIGGER 4 +/* + * etrigger: The trigger is an exception trigger. The remaining bits + * in this register act as described in \RcsrEtrigger. + */ +#define CSR_TDATA1_TYPE_ETRIGGER 5 +/* + * mcontrol6: The trigger is an address/data match trigger. The remaining bits + * in this register act as described in \RcsrMcontrolSix. This is similar + * to a type 2 trigger, but provides additional functionality and + * should be used instead of type 2 in newer implementations. + */ +#define CSR_TDATA1_TYPE_MCONTROL6 6 +/* + * tmexttrigger: The trigger is a trigger source external to the TM. The + * remaining bits in this register act as described in \RcsrTmexttrigger. + */ +#define CSR_TDATA1_TYPE_TMEXTTRIGGER 7 +/* + * custom: These trigger types are available for non-standard use. + */ +#define CSR_TDATA1_TYPE_CUSTOM_LOW 12 +#define CSR_TDATA1_TYPE_CUSTOM_HIGH 14 +/* + * 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. + */ +#define CSR_TDATA1_TYPE_DISABLED 15 +/* + * Other values are reserved for future use. + */ /* -* 0: Both Debug and M Mode can write the {\tt tdata} registers at the -* selected \Rtselect. -* -* 1: Only Debug Mode can write the {\tt tdata} registers at the -* selected \Rtselect. Writes from other modes are ignored. -* -* This bit is only writable from Debug Mode. + * If \FcsrTdataOneType is 0, then this bit is hard-wired to 0. */ -#define CSR_TDATA1_DMODE_OFFSET (MXLEN-5) +#define CSR_TDATA1_DMODE_OFFSET(XLEN) (XLEN + -5) #define CSR_TDATA1_DMODE_LENGTH 1 -#define CSR_TDATA1_DMODE (0x1ULL << CSR_TDATA1_DMODE_OFFSET) +#define CSR_TDATA1_DMODE(XLEN) (1ULL<<(XLEN + -5)) +/* + * both: Both Debug and M-mode can write the {\tt tdata} registers at the + * selected \RcsrTselect. + */ +#define CSR_TDATA1_DMODE_BOTH 0 +/* + * dmode: Only Debug Mode can write the {\tt tdata} registers at the + * selected \RcsrTselect. Writes from other modes are ignored. + */ +#define CSR_TDATA1_DMODE_DMODE 1 +/* + * This bit is only writable from Debug Mode. + * In ordinary use, external debuggers will always set this bit when + * configuring a trigger. + * When clearing this bit, debuggers should also set the action field + * (whose location depends on \FcsrTdataOneType) to something other + * than 1. + */ /* -* Trigger-specific data. + * If \FcsrTdataOneType is 0, then this field is hard-wired to 0. + * + * Trigger-specific data. */ #define CSR_TDATA1_DATA_OFFSET 0 -#define CSR_TDATA1_DATA_LENGTH (MXLEN - 5) -#define CSR_TDATA1_DATA (((1L<<MXLEN - 5)-1) << CSR_TDATA1_DATA_OFFSET) +#define CSR_TDATA1_DATA_LENGTH(XLEN) (XLEN + -5) +#define CSR_TDATA1_DATA(XLEN) ((1ULL<<(XLEN + -5)) + -1) #define CSR_TDATA2 0x7a2 #define CSR_TDATA2_DATA_OFFSET 0 -#define CSR_TDATA2_DATA_LENGTH MXLEN -#define CSR_TDATA2_DATA (((1L<<MXLEN)-1) << CSR_TDATA2_DATA_OFFSET) +#define CSR_TDATA2_DATA_LENGTH(XLEN) XLEN +#define CSR_TDATA2_DATA(XLEN) ((1ULL<<XLEN) + -1) #define CSR_TDATA3 0x7a3 #define CSR_TDATA3_DATA_OFFSET 0 -#define CSR_TDATA3_DATA_LENGTH MXLEN -#define CSR_TDATA3_DATA (((1L<<MXLEN)-1) << CSR_TDATA3_DATA_OFFSET) +#define CSR_TDATA3_DATA_LENGTH(XLEN) XLEN +#define CSR_TDATA3_DATA(XLEN) ((1ULL<<XLEN) + -1) #define CSR_TINFO 0x7a4 /* -* One bit for each possible \Ftype enumerated in \Rtdataone. Bit N -* corresponds to type N. If the bit is set, then that type is -* supported by the currently selected trigger. -* -* If the currently selected trigger doesn't exist, this field -* contains 1. -* -* If \Ftype is not writable, this register may be unimplemented, in -* which case reading it causes an illegal instruction exception. In -* this case the debugger can read the only supported type from -* \Rtdataone. + * One bit for each possible \FcsrTdataOneType enumerated in \RcsrTdataOne. Bit N + * corresponds to type N. If the bit is set, then that type is + * supported by the currently selected trigger. + * + * If the currently selected trigger doesn't exist, this field + * contains 1. */ #define CSR_TINFO_INFO_OFFSET 0 -#define CSR_TINFO_INFO_LENGTH 16 -#define CSR_TINFO_INFO (0xffffULL << CSR_TINFO_INFO_OFFSET) +#define CSR_TINFO_INFO_LENGTH 0x10 +#define CSR_TINFO_INFO 0xffff +#define CSR_TCONTROL 0x7a5 +/* + * M-mode previous trigger enable field. + * + * \FcsrTcontrolMpte and \FcsrTcontrolMte provide one solution to a problem + * 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 + * \FcsrTcontrolMte. + */ +#define CSR_TCONTROL_MPTE_OFFSET 7 +#define CSR_TCONTROL_MPTE_LENGTH 1 +#define CSR_TCONTROL_MPTE 0x80 +/* + * M-mode trigger enable field. + */ +#define CSR_TCONTROL_MTE_OFFSET 3 +#define CSR_TCONTROL_MTE_LENGTH 1 +#define CSR_TCONTROL_MTE 8 +/* + * disabled: Triggers with action=0 do not match/fire while the hart is in M-mode. + */ +#define CSR_TCONTROL_MTE_DISABLED 0 +/* + * enabled: Triggers do match/fire while the hart is in M-mode. + */ +#define CSR_TCONTROL_MTE_ENABLED 1 +/* + * When a breakpoint 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 + * register, which can be used to set triggers that only fire in that + * specific context. + * + * An implementation may tie any number of high bits in this field to + * 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_MCONTEXT 0x7a8 +#define CSR_MSCONTEXT 0x7aa #define CSR_MCONTROL 0x7a1 -#define CSR_MCONTROL_TYPE_OFFSET (MXLEN-4) +#define CSR_MCONTROL_TYPE_OFFSET(XLEN) (XLEN + -4) #define CSR_MCONTROL_TYPE_LENGTH 4 -#define CSR_MCONTROL_TYPE (0xfULL << CSR_MCONTROL_TYPE_OFFSET) -#define CSR_MCONTROL_DMODE_OFFSET (MXLEN-5) +#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 (0x1ULL << CSR_MCONTROL_DMODE_OFFSET) +#define CSR_MCONTROL_DMODE(XLEN) (1ULL<<(XLEN + -5)) /* -* Specifies the largest naturally aligned powers-of-two (NAPOT) range -* supported by the hardware when \Fmatch is 1. The value is the -* logarithm base 2 of the -* number of bytes in that range. A value of 0 indicates that only -* exact value matches are supported (one byte range). A value of 63 -* corresponds to the maximum NAPOT range, which is $2^{63}$ bytes in -* size. + * Specifies the largest naturally aligned powers-of-two (NAPOT) range + * supported by the hardware when \FcsrMcontrolMatch is 1. The value is the + * logarithm base 2 of the number of bytes in that range. + * A value of 0 indicates \FcsrMcontrolMatch 1 is not supported. + * A value of 63 corresponds to the maximum NAPOT range, which is + * $2^{63}$ bytes in size. */ -#define CSR_MCONTROL_MASKMAX_OFFSET (MXLEN-11) +#define CSR_MCONTROL_MASKMAX_OFFSET(XLEN) (XLEN + -0xb) #define CSR_MCONTROL_MASKMAX_LENGTH 6 -#define CSR_MCONTROL_MASKMAX (0x3fULL << CSR_MCONTROL_MASKMAX_OFFSET) +#define CSR_MCONTROL_MASKMAX(XLEN) (0x3f * (1ULL<<(XLEN + -0xb))) +/* + * 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 /* -* If this optional bit is implemented, the hardware sets it when this -* trigger matches. The trigger's user can set or clear it at any -* time. The trigger's user can use this bit to determine which -* trigger(s) matched. If the bit is not implemented, it is always 0 -* and writing it has no effect. + * 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. */ -#define CSR_MCONTROL_HIT_OFFSET 20 +#define CSR_MCONTROL_HIT_OFFSET 0x14 #define CSR_MCONTROL_HIT_LENGTH 1 -#define CSR_MCONTROL_HIT (0x1ULL << CSR_MCONTROL_HIT_OFFSET) +#define CSR_MCONTROL_HIT 0x100000 /* -* 0: Perform a match on the virtual address. -* -* 1: Perform a match on the data value loaded/stored, or the -* instruction executed. + * This bit determines the contents of the XLEN-bit compare values. */ -#define CSR_MCONTROL_SELECT_OFFSET 19 +#define CSR_MCONTROL_SELECT_OFFSET 0x13 #define CSR_MCONTROL_SELECT_LENGTH 1 -#define CSR_MCONTROL_SELECT (0x1ULL << CSR_MCONTROL_SELECT_OFFSET) -/* -* 0: The action for this trigger will be taken just before the -* instruction that triggered it is executed, but after all preceding -* instructions are are committed. -* -* 1: The action for this trigger will be taken after the instruction -* that triggered it is executed. It should be taken before the next -* instruction is executed, but it is better to implement triggers and -* not implement that suggestion than to not implement them at all. -* -* Most hardware will only implement one timing or the other, possibly -* dependent on \Fselect, \Fexecute, \Fload, and \Fstore. 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 \Ftiming 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 -* \Ftiming of 1. -* -* A chain of triggers that don't all have the same \Ftiming value -* will never fire (unless consecutive instructions match the -* appropriate triggers). - */ -#define CSR_MCONTROL_TIMING_OFFSET 18 +#define CSR_MCONTROL_SELECT 0x80000 +/* + * address: There is at least one compare value and it contains the lowest + * virtual address of the access. + * It is recommended that there are additional compare values for + * the other accessed virtual addresses. + * (E.g. on a 32-bit read from 0x4000, the lowest address is 0x4000 + * and the other addresses are 0x4001, 0x4002, and 0x4003.) + */ +#define CSR_MCONTROL_SELECT_ADDRESS 0 +/* + * data: There is exactly one compare value and it contains the data + * value loaded or stored, or the instruction executed. + * 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 (0x1ULL << CSR_MCONTROL_TIMING_OFFSET) -/* -* The action to take when the trigger fires. The values are explained -* in Table~\ref{tab:action}. - */ -#define CSR_MCONTROL_ACTION_OFFSET 12 -#define CSR_MCONTROL_ACTION_LENGTH 6 -#define CSR_MCONTROL_ACTION (0x3fULL << CSR_MCONTROL_ACTION_OFFSET) -/* -* 0: When this trigger matches, the configured action is taken. -* -* 1: While this trigger does not match, it prevents the trigger with -* the next index from matching. -* -* Because \Fchain affects the next trigger, hardware must zero it in -* writes to \Rmcontrol that set \Fdmode to 0 if the next trigger has -* \Fdmode of 1. -* In addition hardware should ignore writes to \Rmcontrol that set -* \Fdmode to 1 if the previous trigger has both \Fdmode of 0 and -* \Fchain of 1. Debuggers must avoid the latter case by checking -* \Fchain on the previous trigger if they're writing \Rmcontrol. -* -* Implementations that wish to limit the maximum length of a trigger -* chain (eg. to meet timing requirements) may do so by zeroing -* \Fchain in writes to \Rmcontrol that would make the chain too long. - */ -#define CSR_MCONTROL_CHAIN_OFFSET 11 +#define CSR_MCONTROL_TIMING 0x40000 +/* + * 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 \FcsrMcontrolAction) must be set to the virtual address of the + * instruction that matched. + * + * If this is combined with \FcsrMcontrolLoad and + * \FcsrMcontrolSelect=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_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 + * 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 + * preserve the program flow. + */ +#define CSR_MCONTROL_TIMING_AFTER 1 +/* + * Most hardware will only implement one timing or the other, possibly + * dependent on \FcsrMcontrolSelect, \FcsrMcontrolExecute, + * \FcsrMcontrolLoad, and \FcsrMcontrolStore. 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 \FcsrMcontrolTiming 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 + * \FcsrMcontrolTiming of 1. + * + * If a trigger with \FcsrMcontrolTiming of 0 matches, it is + * implementation-dependent whether that prevents a trigger with + * \FcsrMcontrolTiming of 1 matching as well. + */ +/* + * 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 +/* + * 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 + * size is XLEN. + */ +#define CSR_MCONTROL_SIZELO_ANY 0 +/* + * 8bit: The trigger will only match against 8-bit memory accesses. + */ +#define CSR_MCONTROL_SIZELO_8BIT 1 +/* + * 16bit: The trigger will only match against 16-bit memory accesses or + * execution of 16-bit instructions. + */ +#define CSR_MCONTROL_SIZELO_16BIT 2 +/* + * 32bit: The trigger will only match against 32-bit memory accesses or + * execution of 32-bit instructions. + */ +#define CSR_MCONTROL_SIZELO_32BIT 3 +/* + * 48bit: The trigger will only match against execution of 48-bit instructions. + */ +#define CSR_MCONTROL_SIZELO_48BIT 4 +/* + * 64bit: The trigger will only match against 64-bit memory accesses or + * execution of 64-bit instructions. + */ +#define CSR_MCONTROL_SIZELO_64BIT 5 +/* + * 80bit: The trigger will only match against execution of 80-bit instructions. + */ +#define CSR_MCONTROL_SIZELO_80BIT 6 +/* + * 96bit: The trigger will only match against execution of 96-bit instructions. + */ +#define CSR_MCONTROL_SIZELO_96BIT 7 +/* + * 112bit: The trigger will only match against execution of 112-bit instructions. + */ +#define CSR_MCONTROL_SIZELO_112BIT 8 +/* + * 128bit: The trigger will only match against 128-bit memory accesses or + * execution of 128-bit instructions. + */ +#define CSR_MCONTROL_SIZELO_128BIT 9 +/* + * An implementation must support the value of 0, but all other values + * are optional. When an implementation supports address triggers + * (\FcsrMcontrolSelect=0), it is recommended that those triggers + * support every access size that the hart supports, as well as for + * every instruction size that the hart supports. + * + * Implementations such as RV32D or RV64V are able to perform loads + * and stores that are wider than XLEN. Custom extensions may also + * support instructions that are wider than XLEN. Because + * \RcsrTdataTwo is of size XLEN, there is a known limitation that + * data value triggers (\FcsrMcontrolSelect=1) can only be supported + * for access sizes up to XLEN bits. When an implementation supports + * data value triggers (\FcsrMcontrolSelect=1), it is recommended + * that those triggers support every access size up to XLEN that the + * hart supports, as well as for every instruction length up to XLEN + * that the hart supports. + */ +/* + * 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 +/* + * breakpoint: + */ +#define CSR_MCONTROL_ACTION_BREAKPOINT 0 +/* + * debug mode: + */ +#define CSR_MCONTROL_ACTION_DEBUG_MODE 1 +/* + * trace on: + */ +#define CSR_MCONTROL_ACTION_TRACE_ON 2 +/* + * trace off: + */ +#define CSR_MCONTROL_ACTION_TRACE_OFF 3 +/* + * trace notify: + */ +#define CSR_MCONTROL_ACTION_TRACE_NOTIFY 4 +/* + * external0: + */ +#define CSR_MCONTROL_ACTION_EXTERNAL0 8 +/* + * external1: + */ +#define CSR_MCONTROL_ACTION_EXTERNAL1 9 +#define CSR_MCONTROL_CHAIN_OFFSET 0xb #define CSR_MCONTROL_CHAIN_LENGTH 1 -#define CSR_MCONTROL_CHAIN (0x1ULL << CSR_MCONTROL_CHAIN_OFFSET) -/* -* 0: Matches when the value equals \Rtdatatwo. -* -* 1: Matches when the top M bits of the value match the top M bits of -* \Rtdatatwo. M is MXLEN-1 minus the index of the least-significant -* bit containing 0 in \Rtdatatwo. -* -* 2: Matches when the value is greater than (unsigned) or equal to -* \Rtdatatwo. -* -* 3: Matches when the value is less than (unsigned) \Rtdatatwo. -* -* 4: Matches when the lower half of the value equals the lower half -* of \Rtdatatwo after the lower half of the value is ANDed with the -* upper half of \Rtdatatwo. -* -* 5: Matches when the upper half of the value equals the lower half -* of \Rtdatatwo after the upper half of the value is ANDed with the -* upper half of \Rtdatatwo. -* -* Other values are reserved for future use. +#define CSR_MCONTROL_CHAIN 0x800 +/* + * disabled: When this trigger matches, the configured action is taken. + */ +#define CSR_MCONTROL_CHAIN_DISABLED 0 +/* + * enabled: While this trigger does not match, it prevents the trigger with + * the next index from matching. + */ +#define CSR_MCONTROL_CHAIN_ENABLED 1 +/* + * A trigger chain starts on the first trigger with $|chain|=1$ after + * a trigger with $|chain|=0$, or simply on the first trigger if that + * has $|chain|=1$. It ends on the first trigger after that which has + * $|chain|=0$. This final trigger is part of the chain. The action + * on all but the final trigger is ignored. The action on that final + * trigger will be taken if and only if all the triggers in the chain + * match at the same time. + * + * Debuggers should not terminate a chain with a trigger with a + * different type. It is undefined when exactly such a chain fires. + * + * Because \FcsrMcontrolChain affects the next trigger, hardware must zero it in + * writes to \RcsrMcontrol that set \FcsrTdataOneDmode to 0 if the next trigger has + * \FcsrTdataOneDmode of 1. + * In addition hardware should ignore writes to \RcsrMcontrol that set + * \FcsrTdataOneDmode to 1 if the previous trigger has both \FcsrTdataOneDmode of 0 and + * \FcsrMcontrolChain of 1. Debuggers must avoid the latter case by checking + * \FcsrMcontrolChain on the previous trigger if they're writing \RcsrMcontrol. + * + * Implementations that wish to limit the maximum length of a trigger + * 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 (0xfULL << CSR_MCONTROL_MATCH_OFFSET) +#define CSR_MCONTROL_MATCH 0x780 +/* + * equal: Matches when any compare value equals \RcsrTdataTwo. + */ +#define CSR_MCONTROL_MATCH_EQUAL 0 +/* + * napot: Matches when the top $M$ bits of any compare value match the top + * $M$ bits of \RcsrTdataTwo. + * $M$ is $|XLEN|-1$ minus the index of the least-significant + * bit containing 0 in \RcsrTdataTwo. Debuggers should only write values + * to \RcsrTdataTwo such that $M + $\FcsrMcontrolMaskmax$ \geq |XLEN|$ + * and $M\gt0$ , otherwise it's undefined on what conditions the + * trigger will match. + */ +#define CSR_MCONTROL_MATCH_NAPOT 1 +/* + * ge: Matches when any compare value is greater than (unsigned) or + * equal to \RcsrTdataTwo. + */ +#define CSR_MCONTROL_MATCH_GE 2 +/* + * lt: Matches when any compare value is less than (unsigned) + * \RcsrTdataTwo. + */ +#define CSR_MCONTROL_MATCH_LT 3 +/* + * mask low: Matches when $\frac{|XLEN|}{2}-1$:$0$ of any compare value + * equals $\frac{|XLEN|}{2}-1$:$0$ of \RcsrTdataTwo after + * $\frac{|XLEN|}{2}-1$:$0$ of the compare value is ANDed with + * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of \RcsrTdataTwo. + */ +#define CSR_MCONTROL_MATCH_MASK_LOW 4 +/* + * mask high: Matches when $|XLEN|-1$:$\frac{|XLEN|}{2}$ of any compare + * value equals $\frac{|XLEN|}{2}-1$:$0$ of \RcsrTdataTwo after + * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of the compare value is ANDed with + * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of \RcsrTdataTwo. + */ +#define CSR_MCONTROL_MATCH_MASK_HIGH 5 +/* + * not equal: Matches when \FcsrMcontrolMatch$=0$ would not match. + */ +#define CSR_MCONTROL_MATCH_NOT_EQUAL 8 +/* + * not napot: Matches when \FcsrMcontrolMatch$=1$ would not match. + */ +#define CSR_MCONTROL_MATCH_NOT_NAPOT 9 +/* + * not mask low: Matches when \FcsrMcontrolMatch$=4$ would not match. + */ +#define CSR_MCONTROL_MATCH_NOT_MASK_LOW 12 +/* + * not mask high: Matches when \FcsrMcontrolMatch$=5$ would not match. + */ +#define CSR_MCONTROL_MATCH_NOT_MASK_HIGH 13 +/* + * Other values are reserved for future use. + * + * All comparisons only look at the lower XLEN (in the current mode) + * bits of the compare values and of \RcsrTdataTwo. + * When \FcsrMcontrolSelect=1 and access size is N, this is further + * reduced, and comparisons only look at the lower N bits of the + * compare values and of \RcsrTdataTwo. + */ /* -* When set, enable this trigger in M mode. + * When set, enable this trigger in M-mode. */ #define CSR_MCONTROL_M_OFFSET 6 #define CSR_MCONTROL_M_LENGTH 1 -#define CSR_MCONTROL_M (0x1ULL << CSR_MCONTROL_M_OFFSET) +#define CSR_MCONTROL_M 0x40 /* -* When set, enable this trigger in S mode. + * 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 (0x1ULL << CSR_MCONTROL_S_OFFSET) +#define CSR_MCONTROL_S 0x10 /* -* When set, enable this trigger in U mode. + * 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 (0x1ULL << CSR_MCONTROL_U_OFFSET) +#define CSR_MCONTROL_U 8 /* -* When set, the trigger fires on the virtual address or opcode of an -* instruction that is executed. + * 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 (0x1ULL << CSR_MCONTROL_EXECUTE_OFFSET) +#define CSR_MCONTROL_EXECUTE 4 /* -* When set, the trigger fires on the virtual address or data of a store. + * 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 (0x1ULL << CSR_MCONTROL_STORE_OFFSET) +#define CSR_MCONTROL_STORE 2 /* -* When set, the trigger fires on the virtual address or data of a load. + * 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 (0x1ULL << CSR_MCONTROL_LOAD_OFFSET) -#define CSR_ICOUNT 0x7a1 -#define CSR_ICOUNT_TYPE_OFFSET (MXLEN-4) -#define CSR_ICOUNT_TYPE_LENGTH 4 -#define CSR_ICOUNT_TYPE (0xfULL << CSR_ICOUNT_TYPE_OFFSET) -#define CSR_ICOUNT_DMODE_OFFSET (MXLEN-5) -#define CSR_ICOUNT_DMODE_LENGTH 1 -#define CSR_ICOUNT_DMODE (0x1ULL << CSR_ICOUNT_DMODE_OFFSET) +#define CSR_MCONTROL_LOAD 1 +#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)) +/* + * 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 +/* + * 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 +/* + * 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. + */ +#define CSR_MCONTROL6_HIT_OFFSET 0x16 +#define CSR_MCONTROL6_HIT_LENGTH 1 +#define CSR_MCONTROL6_HIT 0x400000 +/* + * 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 /* -* If this optional bit is implemented, the hardware sets it when this -* trigger matches. The trigger's user can set or clear it at any -* time. The trigger's user can use this bit to determine which -* trigger(s) matched. If the bit is not implemented, it is always 0 -* and writing it has no effect. + * address: There is at least one compare value and it contains the lowest + * virtual address of the access. + * In addition, it is recommended that there are additional compare + * values for the other accessed virtual addresses match. + * (E.g. on a 32-bit read from 0x4000, the lowest address is 0x4000 + * and the other addresses are 0x4001, 0x4002, and 0x4003.) */ -#define CSR_ICOUNT_HIT_OFFSET 24 -#define CSR_ICOUNT_HIT_LENGTH 1 -#define CSR_ICOUNT_HIT (0x1ULL << CSR_ICOUNT_HIT_OFFSET) +#define CSR_MCONTROL6_SELECT_ADDRESS 0 /* -* When count is decremented to 0, the trigger fires. Instead of -* changing \Fcount from 1 to 0, it is also acceptable for hardware to -* clear \Fm, \Fs, and \Fu. This allows \Fcount to be hard-wired -* to 1 if this register just exists for single step. + * data: There is exactly one compare value and it contains the data + * value loaded or stored, or the instruction executed. + * 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_ICOUNT_COUNT_OFFSET 10 -#define CSR_ICOUNT_COUNT_LENGTH 14 -#define CSR_ICOUNT_COUNT (0x3fffULL << CSR_ICOUNT_COUNT_OFFSET) +#define CSR_MCONTROL6_TIMING_AFTER 1 /* -* When set, every instruction completed or exception taken in M mode decrements \Fcount -* by 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_ICOUNT_M_OFFSET 9 -#define CSR_ICOUNT_M_LENGTH 1 -#define CSR_ICOUNT_M (0x1ULL << CSR_ICOUNT_M_OFFSET) +#define CSR_MCONTROL6_SIZE_OFFSET 0x10 +#define CSR_MCONTROL6_SIZE_LENGTH 4 +#define CSR_MCONTROL6_SIZE 0xf0000 /* -* When set, every instruction completed or exception taken in S mode decrements \Fcount -* by 1. + * 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 + * size is XLEN. */ -#define CSR_ICOUNT_S_OFFSET 7 -#define CSR_ICOUNT_S_LENGTH 1 -#define CSR_ICOUNT_S (0x1ULL << CSR_ICOUNT_S_OFFSET) +#define CSR_MCONTROL6_SIZE_ANY 0 /* -* When set, every instruction completed or exception taken in U mode decrements \Fcount -* by 1. + * 8bit: The trigger will only match against 8-bit memory accesses. */ -#define CSR_ICOUNT_U_OFFSET 6 -#define CSR_ICOUNT_U_LENGTH 1 -#define CSR_ICOUNT_U (0x1ULL << CSR_ICOUNT_U_OFFSET) +#define CSR_MCONTROL6_SIZE_8BIT 1 /* -* The action to take when the trigger fires. The values are explained -* in Table~\ref{tab:action}. + * 16bit: The trigger will only match against 16-bit memory accesses or + * execution of 16-bit instructions. */ -#define CSR_ICOUNT_ACTION_OFFSET 0 -#define CSR_ICOUNT_ACTION_LENGTH 6 -#define CSR_ICOUNT_ACTION (0x3fULL << CSR_ICOUNT_ACTION_OFFSET) -#define CSR_ITRIGGER 0x7a1 -#define CSR_ITRIGGER_TYPE_OFFSET (MXLEN-4) -#define CSR_ITRIGGER_TYPE_LENGTH 4 -#define CSR_ITRIGGER_TYPE (0xfULL << CSR_ITRIGGER_TYPE_OFFSET) -#define CSR_ITRIGGER_DMODE_OFFSET (MXLEN-5) -#define CSR_ITRIGGER_DMODE_LENGTH 1 -#define CSR_ITRIGGER_DMODE (0x1ULL << CSR_ITRIGGER_DMODE_OFFSET) +#define CSR_MCONTROL6_SIZE_16BIT 2 /* -* If this optional bit is implemented, the hardware sets it when this -* trigger matches. The trigger's user can set or clear it at any -* time. The trigger's user can use this bit to determine which -* trigger(s) matched. If the bit is not implemented, it is always 0 -* and writing it has no effect. + * 32bit: The trigger will only match against 32-bit memory accesses or + * execution of 32-bit instructions. */ -#define CSR_ITRIGGER_HIT_OFFSET (MXLEN-6) -#define CSR_ITRIGGER_HIT_LENGTH 1 -#define CSR_ITRIGGER_HIT (0x1ULL << CSR_ITRIGGER_HIT_OFFSET) +#define CSR_MCONTROL6_SIZE_32BIT 3 /* -* When set, enable this trigger for interrupts that are taken from M -* mode. + * 48bit: The trigger will only match against execution of 48-bit instructions. */ -#define CSR_ITRIGGER_M_OFFSET 9 -#define CSR_ITRIGGER_M_LENGTH 1 -#define CSR_ITRIGGER_M (0x1ULL << CSR_ITRIGGER_M_OFFSET) +#define CSR_MCONTROL6_SIZE_48BIT 4 /* -* When set, enable this trigger for interrupts that are taken from S -* mode. + * 64bit: The trigger will only match against 64-bit memory accesses or + * execution of 64-bit instructions. */ -#define CSR_ITRIGGER_S_OFFSET 7 -#define CSR_ITRIGGER_S_LENGTH 1 -#define CSR_ITRIGGER_S (0x1ULL << CSR_ITRIGGER_S_OFFSET) +#define CSR_MCONTROL6_SIZE_64BIT 5 /* -* When set, enable this trigger for interrupts that are taken from U -* mode. + * 80bit: The trigger will only match against execution of 80-bit instructions. */ -#define CSR_ITRIGGER_U_OFFSET 6 -#define CSR_ITRIGGER_U_LENGTH 1 -#define CSR_ITRIGGER_U (0x1ULL << CSR_ITRIGGER_U_OFFSET) +#define CSR_MCONTROL6_SIZE_80BIT 6 /* -* The action to take when the trigger fires. The values are explained -* in Table~\ref{tab:action}. + * 96bit: The trigger will only match against execution of 96-bit instructions. */ -#define CSR_ITRIGGER_ACTION_OFFSET 0 -#define CSR_ITRIGGER_ACTION_LENGTH 6 -#define CSR_ITRIGGER_ACTION (0x3fULL << CSR_ITRIGGER_ACTION_OFFSET) -#define CSR_ETRIGGER 0x7a1 -#define CSR_ETRIGGER_TYPE_OFFSET (MXLEN-4) -#define CSR_ETRIGGER_TYPE_LENGTH 4 -#define CSR_ETRIGGER_TYPE (0xfULL << CSR_ETRIGGER_TYPE_OFFSET) -#define CSR_ETRIGGER_DMODE_OFFSET (MXLEN-5) -#define CSR_ETRIGGER_DMODE_LENGTH 1 -#define CSR_ETRIGGER_DMODE (0x1ULL << CSR_ETRIGGER_DMODE_OFFSET) +#define CSR_MCONTROL6_SIZE_96BIT 7 /* -* If this optional bit is implemented, the hardware sets it when this -* trigger matches. The trigger's user can set or clear it at any -* time. The trigger's user can use this bit to determine which -* trigger(s) matched. If the bit is not implemented, it is always 0 -* and writing it has no effect. + * 112bit: The trigger will only match against execution of 112-bit instructions. */ -#define CSR_ETRIGGER_HIT_OFFSET (MXLEN-6) -#define CSR_ETRIGGER_HIT_LENGTH 1 -#define CSR_ETRIGGER_HIT (0x1ULL << CSR_ETRIGGER_HIT_OFFSET) +#define CSR_MCONTROL6_SIZE_112BIT 8 /* -* When set, enable this trigger for exceptions that are taken from M -* mode. + * 128bit: The trigger will only match against 128-bit memory accesses or + * execution of 128-bit instructions. */ -#define CSR_ETRIGGER_M_OFFSET 9 -#define CSR_ETRIGGER_M_LENGTH 1 -#define CSR_ETRIGGER_M (0x1ULL << CSR_ETRIGGER_M_OFFSET) +#define CSR_MCONTROL6_SIZE_128BIT 9 /* -* When set, enable this trigger for exceptions that are taken from S -* mode. + * An implementation must support the value of 0, but all other values + * are optional. When an implementation supports address triggers + * (\FcsrMcontrolSixSelect=0), it is recommended that those triggers + * support every access size that the hart supports, as well as for + * every instruction size that the hart supports. + * + * Implementations such as RV32D or RV64V are able to perform loads + * and stores that are wider than XLEN. Custom extensions may also + * support instructions that are wider than XLEN. Because + * \RcsrTdataTwo is of size XLEN, there is a known limitation that + * data value triggers (\FcsrMcontrolSixSelect=1) can only be supported + * for access sizes up to XLEN bits. When an implementation supports + * data value triggers (\FcsrMcontrolSixSelect=1), it is recommended + * that those triggers support every access size up to XLEN that the + * hart supports, as well as for every instruction length up to XLEN + * that the hart supports. */ -#define CSR_ETRIGGER_S_OFFSET 7 -#define CSR_ETRIGGER_S_LENGTH 1 -#define CSR_ETRIGGER_S (0x1ULL << CSR_ETRIGGER_S_OFFSET) /* -* When set, enable this trigger for exceptions that are taken from U -* mode. + * The action to take when the trigger fires. The values are explained + * in Table~\ref{tab:action}. */ -#define CSR_ETRIGGER_U_OFFSET 6 -#define CSR_ETRIGGER_U_LENGTH 1 -#define CSR_ETRIGGER_U (0x1ULL << CSR_ETRIGGER_U_OFFSET) +#define CSR_MCONTROL6_ACTION_OFFSET 0xc +#define CSR_MCONTROL6_ACTION_LENGTH 4 +#define CSR_MCONTROL6_ACTION 0xf000 /* -* The action to take when the trigger fires. The values are explained -* in Table~\ref{tab:action}. + * breakpoint: */ -#define CSR_ETRIGGER_ACTION_OFFSET 0 -#define CSR_ETRIGGER_ACTION_LENGTH 6 -#define CSR_ETRIGGER_ACTION (0x3fULL << CSR_ETRIGGER_ACTION_OFFSET) -#define DMI_DMSTATUS 0x11 +#define CSR_MCONTROL6_ACTION_BREAKPOINT 0 /* -* If 1, then there is an implicit {\tt ebreak} instruction at the -* non-existent word immediately after the Program Buffer. This saves -* the debugger from having to write the {\tt ebreak} itself, and -* allows the Program Buffer to be one word smaller. -* -* This must be 1 when \Fprogbufsize is 1. + * debug mode: */ -#define DMI_DMSTATUS_IMPEBREAK_OFFSET 22 -#define DMI_DMSTATUS_IMPEBREAK_LENGTH 1 -#define DMI_DMSTATUS_IMPEBREAK (0x1U << DMI_DMSTATUS_IMPEBREAK_OFFSET) +#define CSR_MCONTROL6_ACTION_DEBUG_MODE 1 /* -* This field is 1 when all currently selected harts have been reset but the reset has not been acknowledged. + * trace on: */ -#define DMI_DMSTATUS_ALLHAVERESET_OFFSET 19 -#define DMI_DMSTATUS_ALLHAVERESET_LENGTH 1 -#define DMI_DMSTATUS_ALLHAVERESET (0x1U << DMI_DMSTATUS_ALLHAVERESET_OFFSET) +#define CSR_MCONTROL6_ACTION_TRACE_ON 2 /* -* This field is 1 when any currently selected hart has been reset but the reset has not been acknowledged. + * trace off: */ -#define DMI_DMSTATUS_ANYHAVERESET_OFFSET 18 -#define DMI_DMSTATUS_ANYHAVERESET_LENGTH 1 -#define DMI_DMSTATUS_ANYHAVERESET (0x1U << DMI_DMSTATUS_ANYHAVERESET_OFFSET) +#define CSR_MCONTROL6_ACTION_TRACE_OFF 3 /* -* This field is 1 when all currently selected harts have acknowledged -* the previous resume request. + * trace notify: */ -#define DMI_DMSTATUS_ALLRESUMEACK_OFFSET 17 -#define DMI_DMSTATUS_ALLRESUMEACK_LENGTH 1 -#define DMI_DMSTATUS_ALLRESUMEACK (0x1U << DMI_DMSTATUS_ALLRESUMEACK_OFFSET) +#define CSR_MCONTROL6_ACTION_TRACE_NOTIFY 4 /* -* This field is 1 when any currently selected hart has acknowledged -* the previous resume request. + * external0: */ -#define DMI_DMSTATUS_ANYRESUMEACK_OFFSET 16 -#define DMI_DMSTATUS_ANYRESUMEACK_LENGTH 1 -#define DMI_DMSTATUS_ANYRESUMEACK (0x1U << DMI_DMSTATUS_ANYRESUMEACK_OFFSET) +#define CSR_MCONTROL6_ACTION_EXTERNAL0 8 /* -* This field is 1 when all currently selected harts do not exist in this system. + * external1: */ -#define DMI_DMSTATUS_ALLNONEXISTENT_OFFSET 15 -#define DMI_DMSTATUS_ALLNONEXISTENT_LENGTH 1 -#define DMI_DMSTATUS_ALLNONEXISTENT (0x1U << DMI_DMSTATUS_ALLNONEXISTENT_OFFSET) +#define CSR_MCONTROL6_ACTION_EXTERNAL1 9 +#define CSR_MCONTROL6_CHAIN_OFFSET 0xb +#define CSR_MCONTROL6_CHAIN_LENGTH 1 +#define CSR_MCONTROL6_CHAIN 0x800 /* -* This field is 1 when any currently selected hart does not exist in this system. + * disabled: When this trigger matches, the configured action is taken. */ -#define DMI_DMSTATUS_ANYNONEXISTENT_OFFSET 14 -#define DMI_DMSTATUS_ANYNONEXISTENT_LENGTH 1 -#define DMI_DMSTATUS_ANYNONEXISTENT (0x1U << DMI_DMSTATUS_ANYNONEXISTENT_OFFSET) +#define CSR_MCONTROL6_CHAIN_DISABLED 0 /* -* This field is 1 when all currently selected harts are unavailable. + * enabled: While this trigger does not match, it prevents the trigger with + * the next index from matching. */ -#define DMI_DMSTATUS_ALLUNAVAIL_OFFSET 13 -#define DMI_DMSTATUS_ALLUNAVAIL_LENGTH 1 -#define DMI_DMSTATUS_ALLUNAVAIL (0x1U << DMI_DMSTATUS_ALLUNAVAIL_OFFSET) +#define CSR_MCONTROL6_CHAIN_ENABLED 1 /* -* This field is 1 when any currently selected hart is unavailable. - */ -#define DMI_DMSTATUS_ANYUNAVAIL_OFFSET 12 -#define DMI_DMSTATUS_ANYUNAVAIL_LENGTH 1 -#define DMI_DMSTATUS_ANYUNAVAIL (0x1U << DMI_DMSTATUS_ANYUNAVAIL_OFFSET) -/* -* This field is 1 when all currently selected harts are running. - */ -#define DMI_DMSTATUS_ALLRUNNING_OFFSET 11 -#define DMI_DMSTATUS_ALLRUNNING_LENGTH 1 -#define DMI_DMSTATUS_ALLRUNNING (0x1U << DMI_DMSTATUS_ALLRUNNING_OFFSET) -/* -* This field is 1 when any currently selected hart is running. - */ -#define DMI_DMSTATUS_ANYRUNNING_OFFSET 10 -#define DMI_DMSTATUS_ANYRUNNING_LENGTH 1 -#define DMI_DMSTATUS_ANYRUNNING (0x1U << DMI_DMSTATUS_ANYRUNNING_OFFSET) -/* -* This field is 1 when all currently selected harts are halted. - */ -#define DMI_DMSTATUS_ALLHALTED_OFFSET 9 -#define DMI_DMSTATUS_ALLHALTED_LENGTH 1 -#define DMI_DMSTATUS_ALLHALTED (0x1U << DMI_DMSTATUS_ALLHALTED_OFFSET) -/* -* This field is 1 when any currently selected hart is halted. - */ -#define DMI_DMSTATUS_ANYHALTED_OFFSET 8 -#define DMI_DMSTATUS_ANYHALTED_LENGTH 1 -#define DMI_DMSTATUS_ANYHALTED (0x1U << DMI_DMSTATUS_ANYHALTED_OFFSET) -/* -* 0 when authentication is required before using the DM. 1 when the -* authentication check has passed. On components that don't implement -* authentication, this bit must be preset as 1. - */ -#define DMI_DMSTATUS_AUTHENTICATED_OFFSET 7 -#define DMI_DMSTATUS_AUTHENTICATED_LENGTH 1 -#define DMI_DMSTATUS_AUTHENTICATED (0x1U << DMI_DMSTATUS_AUTHENTICATED_OFFSET) -/* -* 0: The authentication module is ready to process the next -* read/write to \Rauthdata. -* -* 1: The authentication module is busy. Accessing \Rauthdata results -* in unspecified behavior. -* -* \Fauthbusy only becomes set in immediate response to an access to -* \Rauthdata. - */ -#define DMI_DMSTATUS_AUTHBUSY_OFFSET 6 -#define DMI_DMSTATUS_AUTHBUSY_LENGTH 1 -#define DMI_DMSTATUS_AUTHBUSY (0x1U << DMI_DMSTATUS_AUTHBUSY_OFFSET) -/* -* 1 if this Debug Module supports halt-on-reset functionality -* controllable by the \Fsetresethaltreq and \Fclrresethaltreq bits. -* 0 otherwise. - */ -#define DMI_DMSTATUS_HASRESETHALTREQ_OFFSET 5 -#define DMI_DMSTATUS_HASRESETHALTREQ_LENGTH 1 -#define DMI_DMSTATUS_HASRESETHALTREQ (0x1U << DMI_DMSTATUS_HASRESETHALTREQ_OFFSET) -/* -* 0: \Rdevtreeaddrzero--\Rdevtreeaddrthree hold information which -* is not relevant to the Device Tree. -* -* 1: \Rdevtreeaddrzero--\Rdevtreeaddrthree registers hold the address of the -* Device Tree. - */ -#define DMI_DMSTATUS_DEVTREEVALID_OFFSET 4 -#define DMI_DMSTATUS_DEVTREEVALID_LENGTH 1 -#define DMI_DMSTATUS_DEVTREEVALID (0x1U << DMI_DMSTATUS_DEVTREEVALID_OFFSET) -/* -* 0: There is no Debug Module present. -* -* 1: There is a Debug Module and it conforms to version 0.11 of this -* specification. -* -* 2: There is a Debug Module and it conforms to version 0.13 of this -* specification. -* -* 15: There is a Debug Module but it does not conform to any -* available version of this spec. - */ -#define DMI_DMSTATUS_VERSION_OFFSET 0 -#define DMI_DMSTATUS_VERSION_LENGTH 4 -#define DMI_DMSTATUS_VERSION (0xfU << DMI_DMSTATUS_VERSION_OFFSET) -#define DMI_DMCONTROL 0x10 -/* -* Writes the halt request bit for all currently selected harts. -* When set to 1, each selected hart will halt if it is not currently -* halted. -* -* Writing 1 or 0 has no effect on a hart which is already halted, but -* the bit must be cleared to 0 before the hart is resumed. -* -* Writes apply to the new value of \Fhartsel and \Fhasel. - */ -#define DMI_DMCONTROL_HALTREQ_OFFSET 31 -#define DMI_DMCONTROL_HALTREQ_LENGTH 1 -#define DMI_DMCONTROL_HALTREQ (0x1U << DMI_DMCONTROL_HALTREQ_OFFSET) -/* -* Writes the resume request bit for all currently selected harts. -* When set to 1, each selected hart will resume if it is currently -* halted. -* -* The resume request bit is ignored while the halt request bit is -* set. -* -* Writes apply to the new value of \Fhartsel and \Fhasel. - */ -#define DMI_DMCONTROL_RESUMEREQ_OFFSET 30 -#define DMI_DMCONTROL_RESUMEREQ_LENGTH 1 -#define DMI_DMCONTROL_RESUMEREQ (0x1U << DMI_DMCONTROL_RESUMEREQ_OFFSET) -/* -* This optional field writes the reset bit for all the currently -* selected harts. To perform a reset the debugger writes 1, and then -* writes 0 to deassert the reset signal. -* -* If this feature is not implemented, the bit always stays 0, so -* after writing 1 the debugger can read the register back to see if -* the feature is supported. -* -* Writes apply to the new value of \Fhartsel and \Fhasel. - */ -#define DMI_DMCONTROL_HARTRESET_OFFSET 29 -#define DMI_DMCONTROL_HARTRESET_LENGTH 1 -#define DMI_DMCONTROL_HARTRESET (0x1U << DMI_DMCONTROL_HARTRESET_OFFSET) -/* -* Writing 1 to this bit clears the {\tt havereset} bits for -* any selected harts. -* -* Writes apply to the new value of \Fhartsel and \Fhasel. - */ -#define DMI_DMCONTROL_ACKHAVERESET_OFFSET 28 -#define DMI_DMCONTROL_ACKHAVERESET_LENGTH 1 -#define DMI_DMCONTROL_ACKHAVERESET (0x1U << DMI_DMCONTROL_ACKHAVERESET_OFFSET) -/* -* Selects the definition of currently selected harts. -* -* 0: There is a single currently selected hart, that selected by \Fhartsel. -* -* 1: There may be multiple currently selected harts -- that selected by \Fhartsel, -* plus those selected by the hart array mask register. -* -* An implementation which does not implement the hart array mask register -* must tie this field to 0. A debugger which wishes to use the hart array -* mask register feature should set this bit and read back to see if the functionality -* is supported. - */ -#define DMI_DMCONTROL_HASEL_OFFSET 26 -#define DMI_DMCONTROL_HASEL_LENGTH 1 -#define DMI_DMCONTROL_HASEL (0x1U << DMI_DMCONTROL_HASEL_OFFSET) -/* -* 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 DMI_DMCONTROL_HARTSELLO_OFFSET 16 -#define DMI_DMCONTROL_HARTSELLO_LENGTH 10 -#define DMI_DMCONTROL_HARTSELLO (0x3ffU << DMI_DMCONTROL_HARTSELLO_OFFSET) -/* -* 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 DMI_DMCONTROL_HARTSELHI_OFFSET 6 -#define DMI_DMCONTROL_HARTSELHI_LENGTH 10 -#define DMI_DMCONTROL_HARTSELHI (0x3ffU << DMI_DMCONTROL_HARTSELHI_OFFSET) -/* -* This optional field writes the halt-on-reset request bit for all -* currently selected harts. -* When set to 1, each selected hart will halt upon the next deassertion -* of its reset. The halt-on-reset request bit is not automatically -* cleared. The debugger must write to \Fclrresethaltreq to clear it. -* -* Writes apply to the new value of \Fhartsel and \Fhasel. -* -* If \Fhasresethaltreq is 0, this field is not implemented. - */ -#define DMI_DMCONTROL_SETRESETHALTREQ_OFFSET 3 -#define DMI_DMCONTROL_SETRESETHALTREQ_LENGTH 1 -#define DMI_DMCONTROL_SETRESETHALTREQ (0x1U << DMI_DMCONTROL_SETRESETHALTREQ_OFFSET) -/* -* This optional field clears the halt-on-reset request bit for all -* currently selected harts. -* -* Writes apply to the new value of \Fhartsel and \Fhasel. - */ -#define DMI_DMCONTROL_CLRRESETHALTREQ_OFFSET 2 -#define DMI_DMCONTROL_CLRRESETHALTREQ_LENGTH 1 -#define DMI_DMCONTROL_CLRRESETHALTREQ (0x1U << DMI_DMCONTROL_CLRRESETHALTREQ_OFFSET) -/* -* This bit controls the reset signal from the DM to the rest of the -* system. The signal should reset every part of the system, including -* every hart, except for the DM and any logic required to access the -* DM. -* To perform a system reset the debugger writes 1, -* and then writes 0 -* to deassert the reset. - */ -#define DMI_DMCONTROL_NDMRESET_OFFSET 1 -#define DMI_DMCONTROL_NDMRESET_LENGTH 1 -#define DMI_DMCONTROL_NDMRESET (0x1U << DMI_DMCONTROL_NDMRESET_OFFSET) -/* -* This bit serves as a reset signal for the Debug Module itself. -* -* 0: The module's state, including authentication mechanism, -* takes its reset values (the \Fdmactive bit is the only bit which can -* be written to something other than its reset value). -* -* 1: The module functions normally. -* -* No other mechanism should exist that may result in resetting the -* Debug Module after power up, including the platform's system reset -* or Debug Transport reset signals. -* -* A debugger may pulse this bit low to get the Debug Module into a -* known state. -* -* Implementations may use this bit to aid debugging, for example by -* preventing the Debug Module from being power gated while debugging -* is active. - */ -#define DMI_DMCONTROL_DMACTIVE_OFFSET 0 -#define DMI_DMCONTROL_DMACTIVE_LENGTH 1 -#define DMI_DMCONTROL_DMACTIVE (0x1U << DMI_DMCONTROL_DMACTIVE_OFFSET) -#define DMI_HARTINFO 0x12 -/* -* Number of {\tt dscratch} registers available for the debugger -* to use during program buffer execution, starting from \Rdscratchzero. -* The debugger can make no assumptions about the contents of these -* registers between commands. - */ -#define DMI_HARTINFO_NSCRATCH_OFFSET 20 -#define DMI_HARTINFO_NSCRATCH_LENGTH 4 -#define DMI_HARTINFO_NSCRATCH (0xfU << DMI_HARTINFO_NSCRATCH_OFFSET) -/* -* 0: The {\tt data} registers are shadowed in the hart by CSR -* registers. Each CSR register is MXLEN bits in size, and corresponds -* to a single argument, per Table~\ref{tab:datareg}. -* -* 1: The {\tt data} registers are shadowed in the hart's memory map. -* Each register takes up 4 bytes in the memory map. - */ -#define DMI_HARTINFO_DATAACCESS_OFFSET 16 -#define DMI_HARTINFO_DATAACCESS_LENGTH 1 -#define DMI_HARTINFO_DATAACCESS (0x1U << DMI_HARTINFO_DATAACCESS_OFFSET) -/* -* If \Fdataaccess is 0: Number of CSR registers dedicated to -* shadowing the {\tt data} registers. -* -* If \Fdataaccess is 1: Number of 32-bit words in the memory map -* dedicated to shadowing the {\tt data} registers. -* -* Since there are at most 12 {\tt data} registers, the value in this -* register must be 12 or smaller. - */ -#define DMI_HARTINFO_DATASIZE_OFFSET 12 -#define DMI_HARTINFO_DATASIZE_LENGTH 4 -#define DMI_HARTINFO_DATASIZE (0xfU << DMI_HARTINFO_DATASIZE_OFFSET) -/* -* If \Fdataaccess is 0: The number of the first CSR dedicated to -* shadowing the {\tt data} registers. -* -* If \Fdataaccess is 1: Signed address of RAM where the {\tt data} -* registers are shadowed, to be used to access relative to \Rzero. - */ -#define DMI_HARTINFO_DATAADDR_OFFSET 0 -#define DMI_HARTINFO_DATAADDR_LENGTH 12 -#define DMI_HARTINFO_DATAADDR (0xfffU << DMI_HARTINFO_DATAADDR_OFFSET) -#define DMI_HAWINDOWSEL 0x14 -/* -* The high bits of this field may be tied to 0, depending on how large -* the array mask register is. Eg. on a system with 48 harts only bit 0 -* of this field may actually be writable. - */ -#define DMI_HAWINDOWSEL_HAWINDOWSEL_OFFSET 0 -#define DMI_HAWINDOWSEL_HAWINDOWSEL_LENGTH 15 -#define DMI_HAWINDOWSEL_HAWINDOWSEL (0x7fffU << DMI_HAWINDOWSEL_HAWINDOWSEL_OFFSET) -#define DMI_HAWINDOW 0x15 -#define DMI_HAWINDOW_MASKDATA_OFFSET 0 -#define DMI_HAWINDOW_MASKDATA_LENGTH 32 -#define DMI_HAWINDOW_MASKDATA (0xffffffffU << DMI_HAWINDOW_MASKDATA_OFFSET) -#define DMI_ABSTRACTCS 0x16 -/* -* Size of the Program Buffer, in 32-bit words. Valid sizes are 0 - 16. - */ -#define DMI_ABSTRACTCS_PROGBUFSIZE_OFFSET 24 -#define DMI_ABSTRACTCS_PROGBUFSIZE_LENGTH 5 -#define DMI_ABSTRACTCS_PROGBUFSIZE (0x1fU << DMI_ABSTRACTCS_PROGBUFSIZE_OFFSET) -/* -* 1: An abstract command is currently being executed. -* -* This bit is set as soon as \Rcommand is written, and is -* not cleared until that command has completed. - */ -#define DMI_ABSTRACTCS_BUSY_OFFSET 12 -#define DMI_ABSTRACTCS_BUSY_LENGTH 1 -#define DMI_ABSTRACTCS_BUSY (0x1U << DMI_ABSTRACTCS_BUSY_OFFSET) -/* -* 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 -* started until the value is reset to 0. -* -* 0 (none): No error. -* -* 1 (busy): An abstract command was executing while \Rcommand, -* \Rabstractcs, \Rabstractauto was written, or when one -* of the {\tt data} or {\tt progbuf} registers was read or written. -* -* 2 (not supported): The requested command is not supported, -* regardless of whether the hart is running or not. -* -* 3 (exception): An exception occurred while executing the command -* (eg. while executing the Program Buffer). -* -* 4 (halt/resume): The abstract command couldn't execute because the -* hart wasn't in the required state (running/halted). -* -* 7 (other): The command failed for another reason. - */ -#define DMI_ABSTRACTCS_CMDERR_OFFSET 8 -#define DMI_ABSTRACTCS_CMDERR_LENGTH 3 -#define DMI_ABSTRACTCS_CMDERR (0x7U << DMI_ABSTRACTCS_CMDERR_OFFSET) -/* -* Number of {\tt data} registers that are implemented as part of the -* abstract command interface. Valid sizes are 0 - 12. - */ -#define DMI_ABSTRACTCS_DATACOUNT_OFFSET 0 -#define DMI_ABSTRACTCS_DATACOUNT_LENGTH 4 -#define DMI_ABSTRACTCS_DATACOUNT (0xfU << DMI_ABSTRACTCS_DATACOUNT_OFFSET) -#define DMI_COMMAND 0x17 -/* -* The type determines the overall functionality of this -* abstract command. - */ -#define DMI_COMMAND_CMDTYPE_OFFSET 24 -#define DMI_COMMAND_CMDTYPE_LENGTH 8 -#define DMI_COMMAND_CMDTYPE (0xffU << DMI_COMMAND_CMDTYPE_OFFSET) -/* -* This field is interpreted in a command-specific manner, -* described for each abstract command. - */ -#define DMI_COMMAND_CONTROL_OFFSET 0 -#define DMI_COMMAND_CONTROL_LENGTH 24 -#define DMI_COMMAND_CONTROL (0xffffffU << DMI_COMMAND_CONTROL_OFFSET) -#define DMI_ABSTRACTAUTO 0x18 -/* -* When a bit in this field is 1, read or write accesses to the corresponding {\tt progbuf} word -* cause the command in \Rcommand to be executed again. - */ -#define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET 16 -#define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_LENGTH 16 -#define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF (0xffffU << DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET) -/* -* When a bit in this field is 1, read or write accesses to the corresponding {\tt data} word -* cause the command in \Rcommand to be executed again. - */ -#define DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET 0 -#define DMI_ABSTRACTAUTO_AUTOEXECDATA_LENGTH 12 -#define DMI_ABSTRACTAUTO_AUTOEXECDATA (0xfffU << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET) -#define DMI_DEVTREEADDR0 0x19 -#define DMI_DEVTREEADDR0_ADDR_OFFSET 0 -#define DMI_DEVTREEADDR0_ADDR_LENGTH 32 -#define DMI_DEVTREEADDR0_ADDR (0xffffffffU << DMI_DEVTREEADDR0_ADDR_OFFSET) -#define DMI_DEVTREEADDR1 0x1a -#define DMI_DEVTREEADDR2 0x1b -#define DMI_DEVTREEADDR3 0x1c -#define DMI_NEXTDM 0x1d -#define DMI_NEXTDM_ADDR_OFFSET 0 -#define DMI_NEXTDM_ADDR_LENGTH 32 -#define DMI_NEXTDM_ADDR (0xffffffffU << DMI_NEXTDM_ADDR_OFFSET) -#define DMI_DATA0 0x04 -#define DMI_DATA0_DATA_OFFSET 0 -#define DMI_DATA0_DATA_LENGTH 32 -#define DMI_DATA0_DATA (0xffffffffU << DMI_DATA0_DATA_OFFSET) -#define DMI_DATA11 0x0f -#define DMI_PROGBUF0 0x20 -#define DMI_PROGBUF0_DATA_OFFSET 0 -#define DMI_PROGBUF0_DATA_LENGTH 32 -#define DMI_PROGBUF0_DATA (0xffffffffU << DMI_PROGBUF0_DATA_OFFSET) -#define DMI_PROGBUF15 0x2f -#define DMI_AUTHDATA 0x30 -#define DMI_AUTHDATA_DATA_OFFSET 0 -#define DMI_AUTHDATA_DATA_LENGTH 32 -#define DMI_AUTHDATA_DATA (0xffffffffU << DMI_AUTHDATA_DATA_OFFSET) -#define DMI_HALTSUM0 0x40 -#define DMI_HALTSUM0_HALTSUM0_OFFSET 0 -#define DMI_HALTSUM0_HALTSUM0_LENGTH 32 -#define DMI_HALTSUM0_HALTSUM0 (0xffffffffU << DMI_HALTSUM0_HALTSUM0_OFFSET) -#define DMI_HALTSUM1 0x13 -#define DMI_HALTSUM1_HALTSUM1_OFFSET 0 -#define DMI_HALTSUM1_HALTSUM1_LENGTH 32 -#define DMI_HALTSUM1_HALTSUM1 (0xffffffffU << DMI_HALTSUM1_HALTSUM1_OFFSET) -#define DMI_HALTSUM2 0x34 -#define DMI_HALTSUM2_HALTSUM2_OFFSET 0 -#define DMI_HALTSUM2_HALTSUM2_LENGTH 32 -#define DMI_HALTSUM2_HALTSUM2 (0xffffffffU << DMI_HALTSUM2_HALTSUM2_OFFSET) -#define DMI_HALTSUM3 0x35 -#define DMI_HALTSUM3_HALTSUM3_OFFSET 0 -#define DMI_HALTSUM3_HALTSUM3_LENGTH 32 -#define DMI_HALTSUM3_HALTSUM3 (0xffffffffU << DMI_HALTSUM3_HALTSUM3_OFFSET) -#define DMI_SBADDRESS3 0x37 -/* -* Accesses bits 127:96 of the physical address in {\tt sbaddress} (if -* the system address bus is that wide). - */ -#define DMI_SBADDRESS3_ADDRESS_OFFSET 0 -#define DMI_SBADDRESS3_ADDRESS_LENGTH 32 -#define DMI_SBADDRESS3_ADDRESS (0xffffffffU << DMI_SBADDRESS3_ADDRESS_OFFSET) -#define DMI_SBCS 0x38 -/* -* 0: The System Bus interface conforms to mainline drafts of this -* spec older than 1 January, 2018. -* -* 1: The System Bus interface conforms to this version of the spec. -* -* Other values are reserved for future versions. - */ -#define DMI_SBCS_SBVERSION_OFFSET 29 -#define DMI_SBCS_SBVERSION_LENGTH 3 -#define DMI_SBCS_SBVERSION (0x7U << DMI_SBCS_SBVERSION_OFFSET) -/* -* Set when the debugger attempts to read data while a read is in -* progress, or when the debugger initiates a new access while one is -* already in progress (while \Fsbbusy is set). It remains set until -* it's explicitly cleared by the debugger. -* -* While this field is non-zero, no more system bus accesses can be -* initiated by the Debug Module. - */ -#define DMI_SBCS_SBBUSYERROR_OFFSET 22 -#define DMI_SBCS_SBBUSYERROR_LENGTH 1 -#define DMI_SBCS_SBBUSYERROR (0x1U << DMI_SBCS_SBBUSYERROR_OFFSET) -/* -* When 1, indicates the system bus master 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. -* -* Writes to \Rsbcs while \Fsbbusy is high result in undefined -* behavior. A debugger must not write to \Rsbcs until it reads -* \Fsbbusy as 0. - */ -#define DMI_SBCS_SBBUSY_OFFSET 21 -#define DMI_SBCS_SBBUSY_LENGTH 1 -#define DMI_SBCS_SBBUSY (0x1U << DMI_SBCS_SBBUSY_OFFSET) -/* -* When 1, every write to \Rsbaddresszero automatically triggers a -* system bus read at the new address. - */ -#define DMI_SBCS_SBREADONADDR_OFFSET 20 -#define DMI_SBCS_SBREADONADDR_LENGTH 1 -#define DMI_SBCS_SBREADONADDR (0x1U << DMI_SBCS_SBREADONADDR_OFFSET) -/* -* Select the access size to use for system bus accesses. -* -* 0: 8-bit -* -* 1: 16-bit -* -* 2: 32-bit -* -* 3: 64-bit -* -* 4: 128-bit -* -* If \Fsbaccess has an unsupported value when the DM starts a bus -* access, the access is not performed and \Fsberror is set to 3. - */ -#define DMI_SBCS_SBACCESS_OFFSET 17 -#define DMI_SBCS_SBACCESS_LENGTH 3 -#define DMI_SBCS_SBACCESS (0x7U << DMI_SBCS_SBACCESS_OFFSET) -/* -* When 1, {\tt sbaddress} is incremented by the access size (in -* bytes) selected in \Fsbaccess after every system bus access. - */ -#define DMI_SBCS_SBAUTOINCREMENT_OFFSET 16 -#define DMI_SBCS_SBAUTOINCREMENT_LENGTH 1 -#define DMI_SBCS_SBAUTOINCREMENT (0x1U << DMI_SBCS_SBAUTOINCREMENT_OFFSET) -/* -* When 1, every read from \Rsbdatazero automatically triggers a -* system bus read at the (possibly auto-incremented) address. - */ -#define DMI_SBCS_SBREADONDATA_OFFSET 15 -#define DMI_SBCS_SBREADONDATA_LENGTH 1 -#define DMI_SBCS_SBREADONDATA (0x1U << DMI_SBCS_SBREADONDATA_OFFSET) -/* -* When the Debug Module's system bus -* master causes a bus 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. -* -* 0: There was no bus error. -* -* 1: There was a timeout. -* -* 2: A bad address was accessed. -* -* 3: There was an alignment error. -* -* 4: An access of unsupported size was requested. -* -* 7: Other. - */ -#define DMI_SBCS_SBERROR_OFFSET 12 -#define DMI_SBCS_SBERROR_LENGTH 3 -#define DMI_SBCS_SBERROR (0x7U << DMI_SBCS_SBERROR_OFFSET) -/* -* Width of system bus addresses in bits. (0 indicates there is no bus -* access support.) - */ -#define DMI_SBCS_SBASIZE_OFFSET 5 -#define DMI_SBCS_SBASIZE_LENGTH 7 -#define DMI_SBCS_SBASIZE (0x7fU << DMI_SBCS_SBASIZE_OFFSET) -/* -* 1 when 128-bit system bus accesses are supported. - */ -#define DMI_SBCS_SBACCESS128_OFFSET 4 -#define DMI_SBCS_SBACCESS128_LENGTH 1 -#define DMI_SBCS_SBACCESS128 (0x1U << DMI_SBCS_SBACCESS128_OFFSET) -/* -* 1 when 64-bit system bus accesses are supported. - */ -#define DMI_SBCS_SBACCESS64_OFFSET 3 -#define DMI_SBCS_SBACCESS64_LENGTH 1 -#define DMI_SBCS_SBACCESS64 (0x1U << DMI_SBCS_SBACCESS64_OFFSET) -/* -* 1 when 32-bit system bus accesses are supported. - */ -#define DMI_SBCS_SBACCESS32_OFFSET 2 -#define DMI_SBCS_SBACCESS32_LENGTH 1 -#define DMI_SBCS_SBACCESS32 (0x1U << DMI_SBCS_SBACCESS32_OFFSET) -/* -* 1 when 16-bit system bus accesses are supported. - */ -#define DMI_SBCS_SBACCESS16_OFFSET 1 -#define DMI_SBCS_SBACCESS16_LENGTH 1 -#define DMI_SBCS_SBACCESS16 (0x1U << DMI_SBCS_SBACCESS16_OFFSET) -/* -* 1 when 8-bit system bus accesses are supported. - */ -#define DMI_SBCS_SBACCESS8_OFFSET 0 -#define DMI_SBCS_SBACCESS8_LENGTH 1 -#define DMI_SBCS_SBACCESS8 (0x1U << DMI_SBCS_SBACCESS8_OFFSET) -#define DMI_SBADDRESS0 0x39 -/* -* Accesses bits 31:0 of the physical address in {\tt sbaddress}. - */ -#define DMI_SBADDRESS0_ADDRESS_OFFSET 0 -#define DMI_SBADDRESS0_ADDRESS_LENGTH 32 -#define DMI_SBADDRESS0_ADDRESS (0xffffffffU << DMI_SBADDRESS0_ADDRESS_OFFSET) -#define DMI_SBADDRESS1 0x3a -/* -* Accesses bits 63:32 of the physical address in {\tt sbaddress} (if -* the system address bus is that wide). - */ -#define DMI_SBADDRESS1_ADDRESS_OFFSET 0 -#define DMI_SBADDRESS1_ADDRESS_LENGTH 32 -#define DMI_SBADDRESS1_ADDRESS (0xffffffffU << DMI_SBADDRESS1_ADDRESS_OFFSET) -#define DMI_SBADDRESS2 0x3b -/* -* Accesses bits 95:64 of the physical address in {\tt sbaddress} (if -* the system address bus is that wide). + * A trigger chain starts on the first trigger with $|chain|=1$ after + * a trigger with $|chain|=0$, or simply on the first trigger if that + * has $|chain|=1$. It ends on the first trigger after that which has + * $|chain|=0$. This final trigger is part of the chain. The action + * on all but the final trigger is ignored. The action on that final + * trigger will be taken if and only if all the triggers in the chain + * match at the same time. + * + * Debuggers should not terminate a chain with a trigger with a + * different type. It is undefined when exactly such a chain fires. + * + * Because \FcsrMcontrolSixChain affects the next trigger, hardware must zero it in + * writes to \RcsrMcontrolSix that set \FcsrTdataOneDmode to 0 if the next trigger has + * \FcsrTdataOneDmode of 1. + * In addition hardware should ignore writes to \RcsrMcontrolSix that set + * \FcsrTdataOneDmode to 1 if the previous trigger has both \FcsrTdataOneDmode of 0 and + * \FcsrMcontrolSixChain of 1. Debuggers must avoid the latter case by checking + * \FcsrMcontrolSixChain on the previous trigger if they're writing \RcsrMcontrolSix. + * + * Implementations that wish to limit the maximum length of a trigger + * chain (eg. to meet timing requirements) may do so by zeroing + * \FcsrMcontrolSixChain in writes to \RcsrMcontrolSix that would make the chain too long. */ -#define DMI_SBADDRESS2_ADDRESS_OFFSET 0 -#define DMI_SBADDRESS2_ADDRESS_LENGTH 32 -#define DMI_SBADDRESS2_ADDRESS (0xffffffffU << DMI_SBADDRESS2_ADDRESS_OFFSET) -#define DMI_SBDATA0 0x3c +#define CSR_MCONTROL6_MATCH_OFFSET 7 +#define CSR_MCONTROL6_MATCH_LENGTH 4 +#define CSR_MCONTROL6_MATCH 0x780 /* -* Accesses bits 31:0 of {\tt sbdata}. - */ -#define DMI_SBDATA0_DATA_OFFSET 0 -#define DMI_SBDATA0_DATA_LENGTH 32 -#define DMI_SBDATA0_DATA (0xffffffffU << DMI_SBDATA0_DATA_OFFSET) -#define DMI_SBDATA1 0x3d + * equal: Matches when any compare value equals \RcsrTdataTwo. + */ +#define CSR_MCONTROL6_MATCH_EQUAL 0 /* -* Accesses bits 63:32 of {\tt sbdata} (if the system bus is that -* wide). - */ -#define DMI_SBDATA1_DATA_OFFSET 0 -#define DMI_SBDATA1_DATA_LENGTH 32 -#define DMI_SBDATA1_DATA (0xffffffffU << DMI_SBDATA1_DATA_OFFSET) -#define DMI_SBDATA2 0x3e + * napot: Matches when the top $M$ bits of any compare value match the top + * $M$ bits of \RcsrTdataTwo. + * $M$ is $|XLEN|-1$ minus the index of the least-significant bit + * containing 0 in \RcsrTdataTwo. + * \RcsrTdataTwo is WARL and if bits $|maskmax6|-1$:0 are written with all + * ones then bit $|maskmax6|-1$ will be set to 0 while the values of bits $|maskmax6|-2$:0 + * are \unspecified. + * Legal values for \RcsrTdataTwo require $M + |maskmax6| \geq |XLEN|$ and $M\gt0$. + * See above for how to determine maskmax6. + */ +#define CSR_MCONTROL6_MATCH_NAPOT 1 /* -* Accesses bits 95:64 of {\tt sbdata} (if the system bus is that -* wide). - */ -#define DMI_SBDATA2_DATA_OFFSET 0 -#define DMI_SBDATA2_DATA_LENGTH 32 -#define DMI_SBDATA2_DATA (0xffffffffU << DMI_SBDATA2_DATA_OFFSET) -#define DMI_SBDATA3 0x3f + * ge: Matches when any compare value is greater than (unsigned) or + * equal to \RcsrTdataTwo. + */ +#define CSR_MCONTROL6_MATCH_GE 2 /* -* Accesses bits 127:96 of {\tt sbdata} (if the system bus is that -* wide). + * lt: Matches when any compare value is less than (unsigned) + * \RcsrTdataTwo. */ -#define DMI_SBDATA3_DATA_OFFSET 0 -#define DMI_SBDATA3_DATA_LENGTH 32 -#define DMI_SBDATA3_DATA (0xffffffffU << DMI_SBDATA3_DATA_OFFSET) -#define SHORTNAME 0x123 +#define CSR_MCONTROL6_MATCH_LT 3 /* -* Description of what this field is used for. + * mask low: Matches when $\frac{|XLEN|}{2}-1$:$0$ of any compare value + * equals $\frac{|XLEN|}{2}-1$:$0$ of \RcsrTdataTwo after + * $\frac{|XLEN|}{2}-1$:$0$ of the compare value is ANDed with + * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of \RcsrTdataTwo. */ -#define SHORTNAME_FIELD_OFFSET 0 -#define SHORTNAME_FIELD_LENGTH 8 -#define SHORTNAME_FIELD (0xffU << SHORTNAME_FIELD_OFFSET) -#define AC_ACCESS_REGISTER None +#define CSR_MCONTROL6_MATCH_MASK_LOW 4 /* -* This is 0 to indicate Access Register Command. + * mask high: Matches when $|XLEN|-1$:$\frac{|XLEN|}{2}$ of any compare + * value equals $\frac{|XLEN|}{2}-1$:$0$ of \RcsrTdataTwo after + * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of the compare value is ANDed with + * $|XLEN|-1$:$\frac{|XLEN|}{2}$ of \RcsrTdataTwo. */ -#define AC_ACCESS_REGISTER_CMDTYPE_OFFSET 24 -#define AC_ACCESS_REGISTER_CMDTYPE_LENGTH 8 -#define AC_ACCESS_REGISTER_CMDTYPE (0xffU << AC_ACCESS_REGISTER_CMDTYPE_OFFSET) -/* -* 2: Access the lowest 32 bits of the register. -* -* 3: Access the lowest 64 bits of the register. -* -* 4: Access the lowest 128 bits of the register. -* -* If \Fsize specifies a size larger than the register's actual size, -* then the access must fail. If a register is accessible, then reads of \Fsize -* less than or equal to the register's actual size must be supported. -* -* This field controls the Argument Width as referenced in -* Table~\ref{tab:datareg}. - */ -#define AC_ACCESS_REGISTER_SIZE_OFFSET 20 -#define AC_ACCESS_REGISTER_SIZE_LENGTH 3 -#define AC_ACCESS_REGISTER_SIZE (0x7U << AC_ACCESS_REGISTER_SIZE_OFFSET) -/* -* When 1, execute the program in the Program Buffer exactly once -* after performing the transfer, if any. - */ -#define AC_ACCESS_REGISTER_POSTEXEC_OFFSET 18 -#define AC_ACCESS_REGISTER_POSTEXEC_LENGTH 1 -#define AC_ACCESS_REGISTER_POSTEXEC (0x1U << AC_ACCESS_REGISTER_POSTEXEC_OFFSET) +#define CSR_MCONTROL6_MATCH_MASK_HIGH 5 /* -* 0: Don't do the operation specified by \Fwrite. -* -* 1: Do the operation specified by \Fwrite. -* -* This bit can be used to just execute the Program Buffer without -* having to worry about placing valid values into \Fsize or \Fregno. + * not equal: Matches when \FcsrMcontrolSixMatch$=0$ would not match. */ -#define AC_ACCESS_REGISTER_TRANSFER_OFFSET 17 -#define AC_ACCESS_REGISTER_TRANSFER_LENGTH 1 -#define AC_ACCESS_REGISTER_TRANSFER (0x1U << AC_ACCESS_REGISTER_TRANSFER_OFFSET) +#define CSR_MCONTROL6_MATCH_NOT_EQUAL 8 /* -* When \Ftransfer is set: -* 0: Copy data from the specified register into {\tt arg0} portion -* of {\tt data}. -* -* 1: Copy data from {\tt arg0} portion of {\tt data} into the -* specified register. + * not napot: Matches when \FcsrMcontrolSixMatch$=1$ would not match. */ -#define AC_ACCESS_REGISTER_WRITE_OFFSET 16 -#define AC_ACCESS_REGISTER_WRITE_LENGTH 1 -#define AC_ACCESS_REGISTER_WRITE (0x1U << AC_ACCESS_REGISTER_WRITE_OFFSET) +#define CSR_MCONTROL6_MATCH_NOT_NAPOT 9 /* -* Number of the register to access, as described in -* Table~\ref{tab:regno}. -* \Rdpc may be used as an alias for PC if this command is -* supported on a non-halted hart. + * not mask low: Matches when \FcsrMcontrolSixMatch$=4$ would not match. */ -#define AC_ACCESS_REGISTER_REGNO_OFFSET 0 -#define AC_ACCESS_REGISTER_REGNO_LENGTH 16 -#define AC_ACCESS_REGISTER_REGNO (0xffffU << AC_ACCESS_REGISTER_REGNO_OFFSET) -#define AC_QUICK_ACCESS None +#define CSR_MCONTROL6_MATCH_NOT_MASK_LOW 12 /* -* This is 1 to indicate Quick Access command. + * not mask high: Matches when \FcsrMcontrolSixMatch$=5$ would not match. */ -#define AC_QUICK_ACCESS_CMDTYPE_OFFSET 24 -#define AC_QUICK_ACCESS_CMDTYPE_LENGTH 8 -#define AC_QUICK_ACCESS_CMDTYPE (0xffU << AC_QUICK_ACCESS_CMDTYPE_OFFSET) -#define VIRT_PRIV virtual +#define CSR_MCONTROL6_MATCH_NOT_MASK_HIGH 13 +/* + * Other values are reserved for future use. + * + * All comparisons only look at the lower XLEN (in the current mode) + * bits of the compare values and of \RcsrTdataTwo. + * When \FcsrMcontrolSelect=1 and access size is N, this is further + * reduced, and comparisons only look at the lower N bits of the + * compare values and of \RcsrTdataTwo. + */ +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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_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)) +/* + * 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 +/* + * 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 +/* + * If this bit is implemented, the hardware sets it when this + * trigger fires. The trigger's user can set or clear it at any + * time. It is used to determine which + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * breakpoint: + */ +#define CSR_ICOUNT_ACTION_BREAKPOINT 0 +/* + * debug mode: + */ +#define CSR_ICOUNT_ACTION_DEBUG_MODE 1 +/* + * trace on: + */ +#define CSR_ICOUNT_ACTION_TRACE_ON 2 +/* + * trace off: + */ +#define CSR_ICOUNT_ACTION_TRACE_OFF 3 +/* + * trace notify: + */ +#define CSR_ICOUNT_ACTION_TRACE_NOTIFY 4 +/* + * external0: + */ +#define CSR_ICOUNT_ACTION_EXTERNAL0 8 +/* + * external1: + */ +#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)) +/* + * If this bit is implemented, the hardware sets it 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. + */ +#define CSR_ITRIGGER_HIT_OFFSET(XLEN) (XLEN + -6) +#define CSR_ITRIGGER_HIT_LENGTH 1 +#define CSR_ITRIGGER_HIT(XLEN) (1ULL<<(XLEN + -6)) +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * breakpoint: + */ +#define CSR_ITRIGGER_ACTION_BREAKPOINT 0 +/* + * debug mode: + */ +#define CSR_ITRIGGER_ACTION_DEBUG_MODE 1 +/* + * trace on: + */ +#define CSR_ITRIGGER_ACTION_TRACE_ON 2 +/* + * trace off: + */ +#define CSR_ITRIGGER_ACTION_TRACE_OFF 3 +/* + * trace notify: + */ +#define CSR_ITRIGGER_ACTION_TRACE_NOTIFY 4 +/* + * external0: + */ +#define CSR_ITRIGGER_ACTION_EXTERNAL0 8 +/* + * external1: + */ +#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)) +/* + * If this bit is implemented, the hardware sets it 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. + */ +#define CSR_ETRIGGER_HIT_OFFSET(XLEN) (XLEN + -6) +#define CSR_ETRIGGER_HIT_LENGTH 1 +#define CSR_ETRIGGER_HIT(XLEN) (1ULL<<(XLEN + -6)) +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * breakpoint: + */ +#define CSR_ETRIGGER_ACTION_BREAKPOINT 0 +/* + * debug mode: + */ +#define CSR_ETRIGGER_ACTION_DEBUG_MODE 1 +/* + * trace on: + */ +#define CSR_ETRIGGER_ACTION_TRACE_ON 2 +/* + * trace off: + */ +#define CSR_ETRIGGER_ACTION_TRACE_OFF 3 +/* + * trace notify: + */ +#define CSR_ETRIGGER_ACTION_TRACE_NOTIFY 4 +/* + * external0: + */ +#define CSR_ETRIGGER_ACTION_EXTERNAL0 8 +/* + * external1: + */ +#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)) +/* + * If this bit is implemented, the hardware sets it 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. + */ +#define CSR_TMEXTTRIGGER_HIT_OFFSET(XLEN) (XLEN + -6) +#define CSR_TMEXTTRIGGER_HIT_LENGTH 1 +#define CSR_TMEXTTRIGGER_HIT(XLEN) (1ULL<<(XLEN + -6)) +/* + * 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 +/* + * Selects any combination of up to 16 external debug 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 +/* + * 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 +/* + * breakpoint: + */ +#define CSR_TMEXTTRIGGER_ACTION_BREAKPOINT 0 +/* + * debug mode: + */ +#define CSR_TMEXTTRIGGER_ACTION_DEBUG_MODE 1 +/* + * trace on: + */ +#define CSR_TMEXTTRIGGER_ACTION_TRACE_ON 2 +/* + * trace off: + */ +#define CSR_TMEXTTRIGGER_ACTION_TRACE_OFF 3 +/* + * trace notify: + */ +#define CSR_TMEXTTRIGGER_ACTION_TRACE_NOTIFY 4 +/* + * external0: + */ +#define CSR_TMEXTTRIGGER_ACTION_EXTERNAL0 8 +/* + * external1: + */ +#define CSR_TMEXTTRIGGER_ACTION_EXTERNAL1 9 +#define CSR_TEXTRA32 0x7a3 +/* + * 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 +/* + * ignore: Ignore \FcsrTextraThirtytwoMhvalue. + */ +#define CSR_TEXTRA32_MHSELECT_IGNORE 0 +/* + * mcontext: This trigger will only match 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 + * \RcsrMcontext/\RcsrHcontext equal \{\FcsrTextraThirtytwoMhvalue, mhselect[2]\}. + * + * 2, 6 (vmid\_select): This trigger will only match if VMID in hgatp equals the lower VMIDMAX + * (defined in the Privileged Spec) bits of \{\FcsrTextraThirtytwoMhvalue, mhselect[2]\}. + * + * 3, 7 (reserved): Reserved. + * + * If the H extension is not supported, the only legal values are 0 and 4. + */ +/* + * When the least significant bit of this field is 1, it causes bits 7:0 + * in the comparison to be ignored, when \FcsrTextraThirtytwoSselect=1. + * 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 +/* + * 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 +/* + * ignore: Ignore \FcsrTextraThirtytwoSvalue. + */ +#define CSR_TEXTRA32_SSELECT_IGNORE 0 +/* + * scontext: This trigger will only match if the low bits of + * \RcsrScontext equal \FcsrTextraThirtytwoSvalue. + */ +#define CSR_TEXTRA32_SSELECT_SCONTEXT 1 +/* + * asid: This trigger will only match 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 + * of \FcsrTextraThirtytwoSvalue. + * \item in all other modes, ASID in \Rsatp equals the lower + * ASIDMAX (defined in the Privileged Spec) bits of + * \FcsrTextraThirtytwoSvalue. + * \end{itemize} + */ +#define CSR_TEXTRA32_SSELECT_ASID 2 +/* + * 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 0xfff8000000000000ULL +#define CSR_TEXTRA64_MHSELECT_OFFSET 0x30 +#define CSR_TEXTRA64_MHSELECT_LENGTH 3 +#define CSR_TEXTRA64_MHSELECT 0x7000000000000ULL +/* + * When the least significant bit of this field is 1, it causes bits 7:0 + * in the comparison to be ignored, when \FcsrTextraSixtyfourSselect=1. + * Likewise, the second bit controls the comparison of bits 15:8, + * third bit controls the comparison of bits 23:16, + * 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 0x1f000000000ULL +#define CSR_TEXTRA64_SVALUE_OFFSET 2 +#define CSR_TEXTRA64_SVALUE_LENGTH 0x22 +#define CSR_TEXTRA64_SVALUE 0xffffffffcULL +#define CSR_TEXTRA64_SSELECT_OFFSET 0 +#define CSR_TEXTRA64_SSELECT_LENGTH 2 +#define CSR_TEXTRA64_SSELECT 3 +#define DM_DMSTATUS 0x11 +#define DM_DMSTATUS_NDMRESETPENDING_OFFSET 0x18 +#define DM_DMSTATUS_NDMRESETPENDING_LENGTH 1 +#define DM_DMSTATUS_NDMRESETPENDING 0x1000000 +/* + * false: Unimplemented, or \FdmDmcontrolNdmreset is zero and no ndmreset is currently + * in progress. + */ +#define DM_DMSTATUS_NDMRESETPENDING_FALSE 0 +/* + * 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 +/* + * current: The per-hart {\tt unavail} bits reflect the current state of the hart. + */ +#define DM_DMSTATUS_STICKYUNAVAIL_CURRENT 0 +/* + * sticky: The per-hart {\tt unavail} bits are sticky. Once they are set, they will + * not clear until the debugger acknowledges them using \FdmDmcontrolAckunavail. + */ +#define DM_DMSTATUS_STICKYUNAVAIL_STICKY 1 +/* + * If 1, then there is an implicit {\tt ebreak} instruction at the + * non-existent word immediately after the Program Buffer. This saves + * the debugger from having to write the {\tt ebreak} itself, and + * allows the Program Buffer to be one word smaller. + * + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * false: Authentication is required before using the DM. + */ +#define DM_DMSTATUS_AUTHENTICATED_FALSE 0 +/* + * true: The authentication check has passed. + */ +#define DM_DMSTATUS_AUTHENTICATED_TRUE 1 +/* + * 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 +/* + * ready: The authentication module is ready to process the next + * read/write to \RdmAuthdata. + */ +#define DM_DMSTATUS_AUTHBUSY_READY 0 +/* + * busy: The authentication module is busy. Accessing \RdmAuthdata results + * in unspecified behavior. + */ +#define DM_DMSTATUS_AUTHBUSY_BUSY 1 +/* + * \FdmDmstatusAuthbusy only becomes set in immediate response to an access to + * \RdmAuthdata. + */ +/* + * 1 if this Debug Module supports halt-on-reset functionality + * 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 +/* + * invalid: \RdmConfstrptrZero--\RdmConfstrptrThree hold information which + * is not relevant to the configuration structure. + */ +#define DM_DMSTATUS_CONFSTRPTRVALID_INVALID 0 +/* + * valid: \RdmConfstrptrZero--\RdmConfstrptrThree hold the address of the + * 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 +/* + * none: There is no Debug Module present. + */ +#define DM_DMSTATUS_VERSION_NONE 0 +/* + * 0.11: There is a Debug Module and it conforms to version 0.11 of this + * specification. + */ +#define DM_DMSTATUS_VERSION_0_11 1 +/* + * 0.13: There is a Debug Module and it conforms to version 0.13 of this + * specification. + */ +#define DM_DMSTATUS_VERSION_0_13 2 +/* + * 1.0: There is a Debug Module and it conforms to version 1.0 of this + * specification. + */ +#define DM_DMSTATUS_VERSION_1_0 3 +/* + * custom: There is a Debug Module but it does not conform to any + * available version of this spec. + */ +#define DM_DMSTATUS_VERSION_CUSTOM 15 +#define DM_DMCONTROL 0x10 +/* + * Writing 0 clears the halt request bit for all currently selected + * harts. This may cancel outstanding halt requests for those harts. + * + * Writing 1 sets the halt request bit for all currently selected + * harts. Running harts will halt whenever their halt request bit is + * set. + * + * 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 +/* + * Writing 1 causes the currently selected harts to resume once, if + * they are halted when the write occurs. It also clears the resume + * ack bit for those harts. + * + * \FdmDmcontrolResumereq is ignored if \FdmDmcontrolHaltreq is set. + * + * 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 +/* + * This optional field writes the reset bit for all the currently + * selected harts. To perform a reset the debugger writes 1, and then + * writes 0 to deassert the reset signal. + * + * While this bit is 1, the debugger must not change which harts are + * selected. + * + * If this feature is not implemented, the bit always stays 0, so + * after writing 1 the debugger can read the register back to see if + * the feature is supported. + * + * 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 +/* + * nop: No effect. + */ +#define DM_DMCONTROL_ACKHAVERESET_NOP 0 +/* + * ack: Clears {\tt havereset} for any selected harts. + */ +#define DM_DMCONTROL_ACKHAVERESET_ACK 1 +/* + * 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 +/* + * nop: No effect. + */ +#define DM_DMCONTROL_ACKUNAVAIL_NOP 0 +/* + * ack: Clears {\tt unavail} for any selected harts that are currently available. + */ +#define DM_DMCONTROL_ACKUNAVAIL_ACK 1 +/* + * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. + */ +/* + * Selects the definition of currently selected harts. + */ +#define DM_DMCONTROL_HASEL_OFFSET 0x1a +#define DM_DMCONTROL_HASEL_LENGTH 1 +#define DM_DMCONTROL_HASEL 0x4000000 +/* + * single: There is a single currently selected hart, that is selected by \Fhartsel. + */ +#define DM_DMCONTROL_HASEL_SINGLE 0 +/* + * multiple: There may be multiple currently selected harts -- the hart + * selected by \Fhartsel, plus those selected by the hart array mask + * register. + */ +#define DM_DMCONTROL_HASEL_MULTIPLE 1 +/* + * An implementation which does not implement the hart array mask register + * must tie this field to 0. A debugger which wishes to use the hart array + * mask register feature should set this bit and read back to see if the functionality + * is supported. + */ +/* + * 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 +/* + * 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 +/* + * This optional field sets \Fkeepalive for all currently selected + * harts, unless \FdmDmcontrolClrkeepalive is simultaneously set to + * 1. + * + * 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 +/* + * 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 +/* + * This optional field writes the halt-on-reset request bit for all + * currently selected harts, unless \FdmDmcontrolClrresethaltreq is + * simultaneously set to 1. + * When set to 1, each selected hart will halt upon the next deassertion + * of its reset. The halt-on-reset request bit is not automatically + * cleared. The debugger must write to \FdmDmcontrolClrresethaltreq to clear it. + * + * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. + * + * 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 +/* + * 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 +/* + * 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 + * every hart, except for the DM and any logic required to access the + * DM. + * To perform a hardware platform reset the debugger writes 1, + * 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 +/* + * This bit serves as a reset signal for the Debug Module itself. + * After changing the value of this bit, the debugger must poll + * \RdmDmcontrol until \FdmDmcontrolDmactive has taken the requested value + * before performing any action that assumes the requested \FdmDmcontrolDmactive + * state change has completed. Hardware may + * 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 +/* + * inactive: The module's state, including authentication mechanism, + * takes its reset values (the \FdmDmcontrolDmactive bit is the only bit which can + * be written to something other than its reset value). Any accesses + * to the module may fail. Specifically, \FdmDmstatusVersion might not return + * correct data. + */ +#define DM_DMCONTROL_DMACTIVE_INACTIVE 0 +/* + * active: The module functions normally. + */ +#define DM_DMCONTROL_DMACTIVE_ACTIVE 1 +/* + * No other mechanism should exist that may result in resetting the + * Debug Module after power up. + * + * To place the Debug Module into a known state, a debugger may write 0 to \FdmDmcontrolDmactive, + * poll until \FdmDmcontrolDmactive is observed 0, write 1 to \FdmDmcontrolDmactive, and + * poll until \FdmDmcontrolDmactive is observed 1. + * + * Implementations may pay attention to this bit to further aid + * debugging, for example by preventing the Debug Module from being + * power gated while debugging is active. + */ +#define DM_HARTINFO 0x12 +/* + * Number of {\tt dscratch} registers available for the debugger + * to use during program buffer execution, starting from \RcsrDscratchZero. + * 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 +/* + * csr: The {\tt data} registers are shadowed in the hart by CSRs. + * Each CSR is DXLEN bits in size, and corresponds + * to a single argument, per Table~\ref{tab:datareg}. + */ +#define DM_HARTINFO_DATAACCESS_CSR 0 +/* + * memory: The {\tt data} registers are shadowed in the hart's memory map. + * Each register takes up 4 bytes in the memory map. + */ +#define DM_HARTINFO_DATAACCESS_MEMORY 1 +/* + * If \FdmHartinfoDataaccess is 0: Number of CSRs dedicated to + * shadowing the {\tt data} registers. + * + * 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 +/* + * If \FdmHartinfoDataaccess is 0: The number of the first CSR dedicated to + * shadowing the {\tt data} registers. + * + * If \FdmHartinfoDataaccess is 1: Address of RAM where the data + * registers are shadowed. This address is sign extended giving a + * 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_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_HAWINDOW 0x15 +#define DM_HAWINDOW_MASKDATA_OFFSET 0 +#define DM_HAWINDOW_MASKDATA_LENGTH 0x20 +#define DM_HAWINDOW_MASKDATA 0xffffffffU +#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 +/* + * ready: There is no abstract command currently being executed. + */ +#define DM_ABSTRACTCS_BUSY_READY 0 +/* + * busy: An abstract command is currently being executed. + */ +#define DM_ABSTRACTCS_BUSY_BUSY 1 +/* + * This bit is set as soon as \RdmCommand is written, and is + * not cleared until that command has completed. + */ +/* + * This optional bit controls whether program buffer and abstract + * memory accesses are performed with the exact and full set of + * 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. + */ +#define DM_ABSTRACTCS_RELAXEDPRIV_OFFSET 0xb +#define DM_ABSTRACTCS_RELAXEDPRIV_LENGTH 1 +#define DM_ABSTRACTCS_RELAXEDPRIV 0x800 +/* + * 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 + * started until the value is reset to 0. + * + * 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 +/* + * none: No error. + */ +#define DM_ABSTRACTCS_CMDERR_NONE 0 +/* + * busy: An abstract command was executing while \RdmCommand, + * \RdmAbstractcs, or \RdmAbstractauto was written, or when one + * of the {\tt data} or {\tt progbuf} registers was read or written. + * This status is only written if \FdmAbstractcsCmderr contains 0. + */ +#define DM_ABSTRACTCS_CMDERR_BUSY 1 +/* + * not supported: The command in \RdmCommand is not supported. It + * may be supported with different options set, but it will not be + * supported at a later time when the hart or system state are + * different. + */ +#define DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED 2 +/* + * exception: An exception occurred while executing the command + * (e.g.\ while executing the Program Buffer). + */ +#define DM_ABSTRACTCS_CMDERR_EXCEPTION 3 +/* + * halt/resume: The abstract command couldn't execute because the + * hart wasn't in the required state (running/halted), or unavailable. + */ +#define DM_ABSTRACTCS_CMDERR_HALT_RESUME 4 +/* + * bus: The abstract command failed due to a bus error (e.g.\ + * alignment, access size, or timeout). + */ +#define DM_ABSTRACTCS_CMDERR_BUS 5 +/* + * reserved: Reserved for future use. + */ +#define DM_ABSTRACTCS_CMDERR_RESERVED 6 +/* + * other: The command failed for another reason. + */ +#define DM_ABSTRACTCS_CMDERR_OTHER 7 +/* + * 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_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 +/* + * 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_ABSTRACTAUTO 0x18 +/* + * When a bit in this field is 1, read or write accesses to the + * corresponding {\tt progbuf} word cause the DM to act as if the + * 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 +/* + * 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_CONFSTRPTR0 0x19 +#define DM_CONFSTRPTR0_ADDR_OFFSET 0 +#define DM_CONFSTRPTR0_ADDR_LENGTH 0x20 +#define DM_CONFSTRPTR0_ADDR 0xffffffffU +#define DM_CONFSTRPTR1 0x1a +#define DM_CONFSTRPTR1_ADDR_OFFSET 0 +#define DM_CONFSTRPTR1_ADDR_LENGTH 0x20 +#define DM_CONFSTRPTR1_ADDR 0xffffffffU +#define DM_CONFSTRPTR2 0x1b +#define DM_CONFSTRPTR2_ADDR_OFFSET 0 +#define DM_CONFSTRPTR2_ADDR_LENGTH 0x20 +#define DM_CONFSTRPTR2_ADDR 0xffffffffU +#define DM_CONFSTRPTR3 0x1c +#define DM_CONFSTRPTR3_ADDR_OFFSET 0 +#define DM_CONFSTRPTR3_ADDR_LENGTH 0x20 +#define DM_CONFSTRPTR3_ADDR 0xffffffffU +#define DM_NEXTDM 0x1d +#define DM_NEXTDM_ADDR_OFFSET 0 +#define DM_NEXTDM_ADDR_LENGTH 0x20 +#define DM_NEXTDM_ADDR 0xffffffffU +#define DM_DATA0 0x04 +#define DM_DATA0_DATA_OFFSET 0 +#define DM_DATA0_DATA_LENGTH 0x20 +#define DM_DATA0_DATA 0xffffffffU +#define DM_DATA1 0x05 +#define DM_DATA2 0x06 +#define DM_DATA3 0x07 +#define DM_DATA4 0x08 +#define DM_DATA5 0x09 +#define DM_DATA6 0x0a +#define DM_DATA7 0x0b +#define DM_DATA8 0x0c +#define DM_DATA9 0x0d +#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_PROGBUF1 0x21 +#define DM_PROGBUF2 0x22 +#define DM_PROGBUF3 0x23 +#define DM_PROGBUF4 0x24 +#define DM_PROGBUF5 0x25 +#define DM_PROGBUF6 0x26 +#define DM_PROGBUF7 0x27 +#define DM_PROGBUF8 0x28 +#define DM_PROGBUF9 0x29 +#define DM_PROGBUF10 0x2a +#define DM_PROGBUF11 0x2b +#define DM_PROGBUF12 0x2c +#define DM_PROGBUF13 0x2d +#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_DMCS2 0x32 +#define DM_DMCS2_GROUPTYPE_OFFSET 0xb +#define DM_DMCS2_GROUPTYPE_LENGTH 1 +#define DM_DMCS2_GROUPTYPE 0x800 +/* + * halt: The remaining fields in this register configure halt groups. + */ +#define DM_DMCS2_GROUPTYPE_HALT 0 +/* + * resume: The remaining fields in this register configure resume groups. + */ +#define DM_DMCS2_GROUPTYPE_RESUME 1 +/* + * This field contains the currently selected DM external trigger. + * + * 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 +/* + * When \FdmDmcsTwoHgselect is 0, contains the group of the hart + * specified by \Fhartsel. + * + * When \FdmDmcsTwoHgselect is 1, contains the group of the DM external + * trigger selected by \FdmDmcsTwoDmexttrigger. + * + * The value written to this field is ignored unless \FdmDmcsTwoHgwrite + * is also written 1. + * + * Group numbers are contiguous starting at 0, with the highest number + * being implementation-dependent, and possibly different between + * different group types. Debuggers should read back this field after + * writing to confirm they are using a hart group that is supported. + * + * 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 +/* + * When 1 is written and \FdmDmcsTwoHgselect is 0, for every selected + * hart the DM will change its group to the value written to \FdmDmcsTwoGroup, + * if the hardware supports that group for that hart. + * Implementations may also change the group of a minimal set of + * unselected harts in the same way, if that is necessary due to + * a hardware limitation. + * + * When 1 is written and \FdmDmcsTwoHgselect is 1, the DM will change + * the group of the DM external trigger selected by \FdmDmcsTwoDmexttrigger + * to the value written to \FdmDmcsTwoGroup, if the hardware supports + * that group for that trigger. + * + * 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 +/* + * harts: Operate on harts. + */ +#define DM_DMCS2_HGSELECT_HARTS 0 +/* + * triggers: Operate on DM external triggers. + */ +#define DM_DMCS2_HGSELECT_TRIGGERS 1 +/* + * 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_HALTSUM1 0x13 +#define DM_HALTSUM1_HALTSUM1_OFFSET 0 +#define DM_HALTSUM1_HALTSUM1_LENGTH 0x20 +#define DM_HALTSUM1_HALTSUM1 0xffffffffU +#define DM_HALTSUM2 0x34 +#define DM_HALTSUM2_HALTSUM2_OFFSET 0 +#define DM_HALTSUM2_HALTSUM2_LENGTH 0x20 +#define DM_HALTSUM2_HALTSUM2 0xffffffffU +#define DM_HALTSUM3 0x35 +#define DM_HALTSUM3_HALTSUM3_OFFSET 0 +#define DM_HALTSUM3_HALTSUM3_LENGTH 0x20 +#define DM_HALTSUM3_HALTSUM3 0xffffffffU +#define DM_SBCS 0x38 +#define DM_SBCS_SBVERSION_OFFSET 0x1d +#define DM_SBCS_SBVERSION_LENGTH 3 +#define DM_SBCS_SBVERSION 0xe0000000U +/* + * legacy: The System Bus interface conforms to mainline drafts of this + * spec older than 1 January, 2018. + */ +#define DM_SBCS_SBVERSION_LEGACY 0 +/* + * 1.0: The System Bus interface conforms to this version of the spec. + */ +#define DM_SBCS_SBVERSION_1_0 1 +/* + * Other values are reserved for future versions. + */ +/* + * Set when the debugger attempts to read data while a read is in + * progress, or when the debugger initiates a new access while one is + * already in progress (while \FdmSbcsSbbusy is set). It remains set until + * it's explicitly cleared by the debugger. + * + * 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 +/* + * When 1, indicates the system bus master 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. + * + * Writes to \RdmSbcs while \FdmSbcsSbbusy is high result in undefined + * 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 +/* + * 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 +/* + * 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 +/* + * 8bit: 8-bit + */ +#define DM_SBCS_SBACCESS_8BIT 0 +/* + * 16bit: 16-bit + */ +#define DM_SBCS_SBACCESS_16BIT 1 +/* + * 32bit: 32-bit + */ +#define DM_SBCS_SBACCESS_32BIT 2 +/* + * 64bit: 64-bit + */ +#define DM_SBCS_SBACCESS_64BIT 3 +/* + * 128bit: 128-bit + */ +#define DM_SBCS_SBACCESS_128BIT 4 +/* + * If \FdmSbcsSbaccess has an unsupported value when the DM starts a bus + * access, the access is not performed and \FdmSbcsSberror is set to 4. + */ +/* + * 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 +/* + * 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 +/* + * When the Debug Module's system bus + * master 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 +/* + * none: There was no bus error. + */ +#define DM_SBCS_SBERROR_NONE 0 +/* + * timeout: There was a timeout. + */ +#define DM_SBCS_SBERROR_TIMEOUT 1 +/* + * address: A bad address was accessed. + */ +#define DM_SBCS_SBERROR_ADDRESS 2 +/* + * alignment: There was an alignment error. + */ +#define DM_SBCS_SBERROR_ALIGNMENT 3 +/* + * size: An access of unsupported size was requested. + */ +#define DM_SBCS_SBERROR_SIZE 4 +/* + * other: Other. + */ +#define DM_SBCS_SBERROR_OTHER 7 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * 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_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_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_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_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_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_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_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_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_CUSTOM 0x1f +#define DM_CUSTOM0 0x70 +#define DM_CUSTOM1 0x71 +#define DM_CUSTOM2 0x72 +#define DM_CUSTOM3 0x73 +#define DM_CUSTOM4 0x74 +#define DM_CUSTOM5 0x75 +#define DM_CUSTOM6 0x76 +#define DM_CUSTOM7 0x77 +#define DM_CUSTOM8 0x78 +#define DM_CUSTOM9 0x79 +#define DM_CUSTOM10 0x7a +#define DM_CUSTOM11 0x7b +#define DM_CUSTOM12 0x7c +#define DM_CUSTOM13 0x7d +#define DM_CUSTOM14 0x7e +#define DM_CUSTOM15 0x7f +#define SHORTNAME 0x123 +/* + * Description of what this field is used for. + */ +#define SHORTNAME_FIELD_OFFSET 0 +#define SHORTNAME_FIELD_LENGTH 8 +#define SHORTNAME_FIELD 0xff +/* + * 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 +/* + * 32bit: Access the lowest 32 bits of the register. + */ +#define AC_ACCESS_REGISTER_AARSIZE_32BIT 2 +/* + * 64bit: Access the lowest 64 bits of the register. + */ +#define AC_ACCESS_REGISTER_AARSIZE_64BIT 3 +/* + * 128bit: Access the lowest 128 bits of the register. + */ +#define AC_ACCESS_REGISTER_AARSIZE_128BIT 4 +/* + * If \FacAccessregisterAarsize specifies a size larger than the register's actual size, + * then the access must fail. If a register is accessible, then reads of \FacAccessregisterAarsize + * less than or equal to the register's actual size must be supported. + * Writing less than the full register may be supported, but what + * happens to the high bits in that case is \unspecified. + * + * 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 +/* + * disabled: No effect. This variant must be supported. + */ +#define AC_ACCESS_REGISTER_AARPOSTINCREMENT_DISABLED 0 +/* + * enabled: After a successful register access, \FacAccessregisterRegno is + * incremented. Incrementing past the highest supported value + * causes \FacAccessregisterRegno to become \unspecified. Supporting + * this variant is optional. It is undefined whether the increment + * 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 +/* + * disabled: No effect. This variant must be supported, and is the only + * supported one if \FdmAbstractcsProgbufsize is 0. + */ +#define AC_ACCESS_REGISTER_POSTEXEC_DISABLED 0 +/* + * enabled: Execute the program in the Program Buffer exactly once after + * performing the transfer, if any. Supporting this variant is + * 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 +/* + * disabled: Don't do the operation specified by \FacAccessregisterWrite. + */ +#define AC_ACCESS_REGISTER_TRANSFER_DISABLED 0 +/* + * enabled: Do the operation specified by \FacAccessregisterWrite. + */ +#define AC_ACCESS_REGISTER_TRANSFER_ENABLED 1 +/* + * This bit can be used to just execute the Program Buffer without + * having to worry about placing valid values into \FacAccessregisterAarsize or \FacAccessregisterRegno. + */ +/* + * When \FacAccessregisterTransfer is set: + */ +#define AC_ACCESS_REGISTER_WRITE_OFFSET 0x10 +#define AC_ACCESS_REGISTER_WRITE_LENGTH 1 +#define AC_ACCESS_REGISTER_WRITE 0x10000 +/* + * arg0: Copy data from the specified register into {\tt arg0} portion + * of {\tt data}. + */ +#define AC_ACCESS_REGISTER_WRITE_ARG0 0 +/* + * register: Copy data from {\tt arg0} portion of {\tt data} into the + * specified register. + */ +#define AC_ACCESS_REGISTER_WRITE_REGISTER 1 +/* + * Number of the register to access, as described in + * Table~\ref{tab:regno}. + * \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 +/* + * 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 +/* + * 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 +/* + * 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 +/* + * physical: Addresses are physical (to the hart they are performed on). + */ +#define AC_ACCESS_MEMORY_AAMVIRTUAL_PHYSICAL 0 +/* + * virtual: Addresses are virtual, and translated the way they would be from + * M-mode, with \FcsrMstatusMprv set. + */ +#define AC_ACCESS_MEMORY_AAMVIRTUAL_VIRTUAL 1 +/* + * Debug Modules on systems without address translation (i.e. virtual addresses equal physical) + * 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 +/* + * 8bit: Access the lowest 8 bits of the memory location. + */ +#define AC_ACCESS_MEMORY_AAMSIZE_8BIT 0 +/* + * 16bit: Access the lowest 16 bits of the memory location. + */ +#define AC_ACCESS_MEMORY_AAMSIZE_16BIT 1 +/* + * 32bit: Access the lowest 32 bits of the memory location. + */ +#define AC_ACCESS_MEMORY_AAMSIZE_32BIT 2 +/* + * 64bit: Access the lowest 64 bits of the memory location. + */ +#define AC_ACCESS_MEMORY_AAMSIZE_64BIT 3 +/* + * 128bit: Access the lowest 128 bits of the memory location. + */ +#define AC_ACCESS_MEMORY_AAMSIZE_128BIT 4 +/* + * After a memory access has completed, if this bit is 1, increment + * {\tt arg1} (which contains the address used) by the number of bytes + * encoded in \FacAccessmemoryAamsize. + * + * 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 +/* + * 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 + * {\tt arg0} are \unspecified. + */ +#define AC_ACCESS_MEMORY_WRITE_ARG0 0 +/* + * memory: Copy data from the low bits of {\tt arg0} into the memory + * location specified in {\tt arg1}. + */ +#define AC_ACCESS_MEMORY_WRITE_MEMORY 1 +/* + * 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 VIRT_PRIV virtual +/* + * Contains the virtualization mode the hart was operating in when Debug + * Mode was entered. The encoding is described in Table \ref{tab:privmode}, + * and matches the virtualization mode encoding from the Privileged Spec. + * 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 /* -* Contains the privilege level the hart was operating in when Debug -* Mode was entered. The encoding is described in Table -* \ref{tab:privlevel}, and matches the privilege level encoding from -* the RISC-V Privileged ISA Specification. A user can write this -* value to change the hart's privilege level when exiting Debug Mode. + * Contains the privilege mode the hart was operating in when Debug + * Mode was entered. The encoding is described in Table + * \ref{tab:privmode}, and matches the privilege mode encoding from + * 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 (0x3U << VIRT_PRIV_PRV_OFFSET) +#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 diff --git a/src/target/riscv/encoding.h b/src/target/riscv/encoding.h index e214c0ca02..c2da4e6767 100644 --- a/src/target/riscv/encoding.h +++ b/src/target/riscv/encoding.h @@ -1,4 +1,11 @@ -/* See LICENSE for license details. */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* Copyright (c) 2022 RISC-V International */ + +/* + * This file is auto-generated by running 'make' in + * https://github.com/riscv/riscv-opcodes (dcdf8d3) + */ #ifndef RISCV_CSR_ENCODING_H #define RISCV_CSR_ENCODING_H @@ -9,10 +16,10 @@ #define MSTATUS_MIE 0x00000008 #define MSTATUS_UPIE 0x00000010 #define MSTATUS_SPIE 0x00000020 -#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_UBE 0x00000040 #define MSTATUS_MPIE 0x00000080 #define MSTATUS_SPP 0x00000100 -#define MSTATUS_HPP 0x00000600 +#define MSTATUS_VS 0x00000600 #define MSTATUS_MPP 0x00001800 #define MSTATUS_FS 0x00006000 #define MSTATUS_XS 0x00018000 @@ -25,13 +32,24 @@ #define MSTATUS32_SD 0x80000000 #define MSTATUS_UXL 0x0000000300000000 #define MSTATUS_SXL 0x0000000C00000000 +#define MSTATUS_SBE 0x0000001000000000 +#define MSTATUS_MBE 0x0000002000000000 +#define MSTATUS_GVA 0x0000004000000000 +#define MSTATUS_MPV 0x0000008000000000 #define MSTATUS64_SD 0x8000000000000000 +#define MSTATUSH_SBE 0x00000010 +#define MSTATUSH_MBE 0x00000020 +#define MSTATUSH_GVA 0x00000040 +#define MSTATUSH_MPV 0x00000080 + #define SSTATUS_UIE 0x00000001 #define SSTATUS_SIE 0x00000002 #define SSTATUS_UPIE 0x00000010 #define SSTATUS_SPIE 0x00000020 +#define SSTATUS_UBE 0x00000040 #define SSTATUS_SPP 0x00000100 +#define SSTATUS_VS 0x00000600 #define SSTATUS_FS 0x00006000 #define SSTATUS_XS 0x00018000 #define SSTATUS_SUM 0x00040000 @@ -40,6 +58,20 @@ #define SSTATUS_UXL 0x0000000300000000 #define SSTATUS64_SD 0x8000000000000000 +#define HSTATUS_VSXL 0x300000000 +#define HSTATUS_VTSR 0x00400000 +#define HSTATUS_VTW 0x00200000 +#define HSTATUS_VTVM 0x00100000 +#define HSTATUS_VGEIN 0x0003f000 +#define HSTATUS_HU 0x00000200 +#define HSTATUS_SPVP 0x00000100 +#define HSTATUS_SPV 0x00000080 +#define HSTATUS_GVA 0x00000040 +#define HSTATUS_VSBE 0x00000020 + +#define USTATUS_UIE 0x00000001 +#define USTATUS_UPIE 0x00000010 + #define DCSR_XDEBUGVER (3U<<30) #define DCSR_NDRESET (1<<29) #define DCSR_FULLRESET (1<<28) @@ -61,6 +93,7 @@ #define DCSR_CAUSE_DEBUGINT 3 #define DCSR_CAUSE_STEP 4 #define DCSR_CAUSE_HALT 5 +#define DCSR_CAUSE_GROUP 6 #define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) #define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) @@ -95,24 +128,104 @@ #define MCONTROL_MATCH_MASK_LOW 4 #define MCONTROL_MATCH_MASK_HIGH 5 +#define MIP_USIP (1 << IRQ_U_SOFT) #define MIP_SSIP (1 << IRQ_S_SOFT) -#define MIP_HSIP (1 << IRQ_H_SOFT) +#define MIP_VSSIP (1 << IRQ_VS_SOFT) #define MIP_MSIP (1 << IRQ_M_SOFT) +#define MIP_UTIP (1 << IRQ_U_TIMER) #define MIP_STIP (1 << IRQ_S_TIMER) -#define MIP_HTIP (1 << IRQ_H_TIMER) +#define MIP_VSTIP (1 << IRQ_VS_TIMER) #define MIP_MTIP (1 << IRQ_M_TIMER) +#define MIP_UEIP (1 << IRQ_U_EXT) #define MIP_SEIP (1 << IRQ_S_EXT) -#define MIP_HEIP (1 << IRQ_H_EXT) +#define MIP_VSEIP (1 << IRQ_VS_EXT) #define MIP_MEIP (1 << IRQ_M_EXT) +#define MIP_SGEIP (1 << IRQ_S_GEXT) +#define MIP_LCOFIP (1 << IRQ_LCOF) + +#define MIP_S_MASK (MIP_SSIP | MIP_STIP | MIP_SEIP) +#define MIP_VS_MASK (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP) +#define MIP_HS_MASK (MIP_VS_MASK | MIP_SGEIP) + +#define MIDELEG_FORCED_MASK MIP_HS_MASK #define SIP_SSIP MIP_SSIP #define SIP_STIP MIP_STIP +#define MENVCFG_FIOM 0x00000001 +#define MENVCFG_CBIE 0x00000030 +#define MENVCFG_CBCFE 0x00000040 +#define MENVCFG_CBZE 0x00000080 +#define MENVCFG_PBMTE 0x4000000000000000 +#define MENVCFG_STCE 0x8000000000000000 + +#define MENVCFGH_PBMTE 0x40000000 +#define MENVCFGH_STCE 0x80000000 + +#define MSTATEEN0_CS 0x00000001 +#define MSTATEEN0_FCSR 0x00000002 +#define MSTATEEN0_HCONTEXT 0x0200000000000000 +#define MSTATEEN0_HENVCFG 0x4000000000000000 +#define MSTATEEN_HSTATEEN 0x8000000000000000 + +#define MSTATEEN0H_HCONTEXT 0x02000000 +#define MSTATEEN0H_HENVCFG 0x40000000 +#define MSTATEENH_HSTATEEN 0x80000000 + +#define MHPMEVENT_VUINH 0x0400000000000000 +#define MHPMEVENT_VSINH 0x0800000000000000 +#define MHPMEVENT_UINH 0x1000000000000000 +#define MHPMEVENT_SINH 0x2000000000000000 +#define MHPMEVENT_MINH 0x4000000000000000 +#define MHPMEVENT_OF 0x8000000000000000 + +#define MHPMEVENTH_VUINH 0x04000000 +#define MHPMEVENTH_VSINH 0x08000000 +#define MHPMEVENTH_UINH 0x10000000 +#define MHPMEVENTH_SINH 0x20000000 +#define MHPMEVENTH_MINH 0x40000000 +#define MHPMEVENTH_OF 0x80000000 + +#define HENVCFG_FIOM 0x00000001 +#define HENVCFG_CBIE 0x00000030 +#define HENVCFG_CBCFE 0x00000040 +#define HENVCFG_CBZE 0x00000080 +#define HENVCFG_PBMTE 0x4000000000000000 +#define HENVCFG_STCE 0x8000000000000000 + +#define HENVCFGH_PBMTE 0x40000000 +#define HENVCFGH_STCE 0x80000000 + +#define HSTATEEN0_CS 0x00000001 +#define HSTATEEN0_FCSR 0x00000002 +#define HSTATEEN0_SCONTEXT 0x0200000000000000 +#define HSTATEEN0_SENVCFG 0x4000000000000000 +#define HSTATEEN_SSTATEEN 0x8000000000000000 + +#define HSTATEEN0H_SCONTEXT 0x02000000 +#define HSTATEEN0H_SENVCFG 0x40000000 +#define HSTATEENH_SSTATEEN 0x80000000 + +#define SENVCFG_FIOM 0x00000001 +#define SENVCFG_CBIE 0x00000030 +#define SENVCFG_CBCFE 0x00000040 +#define SENVCFG_CBZE 0x00000080 + +#define SSTATEEN0_CS 0x00000001 +#define SSTATEEN0_FCSR 0x00000002 + +#define MSECCFG_MML 0x00000001 +#define MSECCFG_MMWP 0x00000002 +#define MSECCFG_RLB 0x00000004 +#define MSECCFG_USEED 0x00000100 +#define MSECCFG_SSEED 0x00000200 + #define PRV_U 0 #define PRV_S 1 -#define PRV_H 2 #define PRV_M 3 +#define PRV_HS (PRV_S + 1) + #define SATP32_MODE 0x80000000 #define SATP32_ASID 0x7FC00000 #define SATP32_PPN 0x003FFFFF @@ -127,6 +240,20 @@ #define SATP_MODE_SV57 10 #define SATP_MODE_SV64 11 +#define HGATP32_MODE 0x80000000 +#define HGATP32_VMID 0x1FC00000 +#define HGATP32_PPN 0x003FFFFF + +#define HGATP64_MODE 0xF000000000000000 +#define HGATP64_VMID 0x03FFF00000000000 +#define HGATP64_PPN 0x00000FFFFFFFFFFF + +#define HGATP_MODE_OFF 0 +#define HGATP_MODE_SV32X4 1 +#define HGATP_MODE_SV39X4 8 +#define HGATP_MODE_SV48X4 9 +#define HGATP_MODE_SV57X4 10 + #define PMP_R 0x01 #define PMP_W 0x02 #define PMP_X 0x04 @@ -138,23 +265,21 @@ #define PMP_NA4 0x10 #define PMP_NAPOT 0x18 +#define IRQ_U_SOFT 0 #define IRQ_S_SOFT 1 -#define IRQ_H_SOFT 2 +#define IRQ_VS_SOFT 2 #define IRQ_M_SOFT 3 +#define IRQ_U_TIMER 4 #define IRQ_S_TIMER 5 -#define IRQ_H_TIMER 6 +#define IRQ_VS_TIMER 6 #define IRQ_M_TIMER 7 +#define IRQ_U_EXT 8 #define IRQ_S_EXT 9 -#define IRQ_H_EXT 10 +#define IRQ_VS_EXT 10 #define IRQ_M_EXT 11 +#define IRQ_S_GEXT 12 #define IRQ_COP 12 -#define IRQ_HOST 13 - -#define DEFAULT_RSTVEC 0x00001000 -#define CLINT_BASE 0x02000000 -#define CLINT_SIZE 0x000c0000 -#define EXT_IO_BASE 0x40000000 -#define DRAM_BASE 0x80000000 +#define IRQ_LCOF 13 /* page table entry (PTE) fields */ #define PTE_V 0x001 /* Valid */ @@ -166,6 +291,10 @@ #define PTE_A 0x040 /* Accessed */ #define PTE_D 0x080 /* Dirty */ #define PTE_SOFT 0x300 /* Reserved for Software */ +#define PTE_RSVD 0x1FC0000000000000 /* Reserved for future standard use */ +#define PTE_PBMT 0x6000000000000000 /* Svpbmt: Page-based memory types */ +#define PTE_N 0x8000000000000000 /* Svnapot: NAPOT translation contiguity */ +#define PTE_ATTR 0xFFC0000000000000 /* All attributes and reserved bits */ #define PTE_PPN_SHIFT 10 @@ -191,7 +320,6 @@ #ifdef __GNUC__ -/* #define read_csr(reg) ({ unsigned long __tmp; \ asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ __tmp; }) @@ -210,7 +338,6 @@ #define clear_csr(reg, bit) ({ unsigned long __tmp; \ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ __tmp; }) - */ #define rdtime() read_csr(time) #define rdcycle() read_csr(cycle) @@ -223,536 +350,2449 @@ #endif #endif -/* Automatically generated by parse-opcodes. */ + +/* Automatically generated by parse_opcodes. */ #ifndef RISCV_ENCODING_H #define RISCV_ENCODING_H -#define MATCH_BEQ 0x63 -#define MASK_BEQ 0x707f -#define MATCH_BNE 0x1063 -#define MASK_BNE 0x707f -#define MATCH_BLT 0x4063 -#define MASK_BLT 0x707f -#define MATCH_BGE 0x5063 -#define MASK_BGE 0x707f -#define MATCH_BLTU 0x6063 -#define MASK_BLTU 0x707f -#define MATCH_BGEU 0x7063 -#define MASK_BGEU 0x707f -#define MATCH_JALR 0x67 -#define MASK_JALR 0x707f -#define MATCH_JAL 0x6f -#define MASK_JAL 0x7f -#define MATCH_LUI 0x37 -#define MASK_LUI 0x7f -#define MATCH_AUIPC 0x17 -#define MASK_AUIPC 0x7f -#define MATCH_ADDI 0x13 -#define MASK_ADDI 0x707f -#define MATCH_SLLI 0x1013 -#define MASK_SLLI 0xfc00707f -#define MATCH_SLTI 0x2013 -#define MASK_SLTI 0x707f -#define MATCH_SLTIU 0x3013 -#define MASK_SLTIU 0x707f -#define MATCH_XORI 0x4013 -#define MASK_XORI 0x707f -#define MATCH_SRLI 0x5013 -#define MASK_SRLI 0xfc00707f -#define MATCH_SRAI 0x40005013 -#define MASK_SRAI 0xfc00707f -#define MATCH_ORI 0x6013 -#define MASK_ORI 0x707f -#define MATCH_ANDI 0x7013 -#define MASK_ANDI 0x707f #define MATCH_ADD 0x33 -#define MASK_ADD 0xfe00707f -#define MATCH_SUB 0x40000033 -#define MASK_SUB 0xfe00707f -#define MATCH_SLL 0x1033 -#define MASK_SLL 0xfe00707f -#define MATCH_SLT 0x2033 -#define MASK_SLT 0xfe00707f -#define MATCH_SLTU 0x3033 -#define MASK_SLTU 0xfe00707f -#define MATCH_XOR 0x4033 -#define MASK_XOR 0xfe00707f -#define MATCH_SRL 0x5033 -#define MASK_SRL 0xfe00707f -#define MATCH_SRA 0x40005033 -#define MASK_SRA 0xfe00707f -#define MATCH_OR 0x6033 -#define MASK_OR 0xfe00707f -#define MATCH_AND 0x7033 -#define MASK_AND 0xfe00707f +#define MASK_ADD 0xfe00707f +#define MATCH_ADD16 0x40000077 +#define MASK_ADD16 0xfe00707f +#define MATCH_ADD32 0x40002077 +#define MASK_ADD32 0xfe00707f +#define MATCH_ADD64 0xc0001077 +#define MASK_ADD64 0xfe00707f +#define MATCH_ADD8 0x48000077 +#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_SLLIW 0x101b -#define MASK_SLLIW 0xfe00707f -#define MATCH_SRLIW 0x501b -#define MASK_SRLIW 0xfe00707f -#define MATCH_SRAIW 0x4000501b -#define MASK_SRAIW 0xfe00707f +#define MASK_ADDIW 0x707f #define MATCH_ADDW 0x3b -#define MASK_ADDW 0xfe00707f -#define MATCH_SUBW 0x4000003b -#define MASK_SUBW 0xfe00707f -#define MATCH_SLLW 0x103b -#define MASK_SLLW 0xfe00707f -#define MATCH_SRLW 0x503b -#define MASK_SRLW 0xfe00707f -#define MATCH_SRAW 0x4000503b -#define MASK_SRAW 0xfe00707f -#define MATCH_LB 0x3 -#define MASK_LB 0x707f -#define MATCH_LH 0x1003 -#define MASK_LH 0x707f -#define MATCH_LW 0x2003 -#define MASK_LW 0x707f -#define MATCH_LD 0x3003 -#define MASK_LD 0x707f -#define MATCH_LBU 0x4003 -#define MASK_LBU 0x707f -#define MATCH_LHU 0x5003 -#define MASK_LHU 0x707f -#define MATCH_LWU 0x6003 -#define MASK_LWU 0x707f -#define MATCH_SB 0x23 -#define MASK_SB 0x707f -#define MATCH_SH 0x1023 -#define MASK_SH 0x707f -#define MATCH_SW 0x2023 -#define MASK_SW 0x707f -#define MATCH_SD 0x3023 -#define MASK_SD 0x707f -#define MATCH_FENCE 0xf -#define MASK_FENCE 0x707f -#define MATCH_FENCE_I 0x100f -#define MASK_FENCE_I 0x707f -#define MATCH_MUL 0x2000033 -#define MASK_MUL 0xfe00707f -#define MATCH_MULH 0x2001033 -#define MASK_MULH 0xfe00707f -#define MATCH_MULHSU 0x2002033 -#define MASK_MULHSU 0xfe00707f -#define MATCH_MULHU 0x2003033 -#define MASK_MULHU 0xfe00707f -#define MATCH_DIV 0x2004033 -#define MASK_DIV 0xfe00707f -#define MATCH_DIVU 0x2005033 -#define MASK_DIVU 0xfe00707f -#define MATCH_REM 0x2006033 -#define MASK_REM 0xfe00707f -#define MATCH_REMU 0x2007033 -#define MASK_REMU 0xfe00707f -#define MATCH_MULW 0x200003b -#define MASK_MULW 0xfe00707f -#define MATCH_DIVW 0x200403b -#define MASK_DIVW 0xfe00707f -#define MATCH_DIVUW 0x200503b -#define MASK_DIVUW 0xfe00707f -#define MATCH_REMW 0x200603b -#define MASK_REMW 0xfe00707f -#define MATCH_REMUW 0x200703b -#define MASK_REMUW 0xfe00707f +#define MASK_ADDW 0xfe00707f +#define MATCH_AES32DSI 0x2a000033 +#define MASK_AES32DSI 0x3e00707f +#define MATCH_AES32DSMI 0x2e000033 +#define MASK_AES32DSMI 0x3e00707f +#define MATCH_AES32ESI 0x22000033 +#define MASK_AES32ESI 0x3e00707f +#define MATCH_AES32ESMI 0x26000033 +#define MASK_AES32ESMI 0x3e00707f +#define MATCH_AES64DS 0x3a000033 +#define MASK_AES64DS 0xfe00707f +#define MATCH_AES64DSM 0x3e000033 +#define MASK_AES64DSM 0xfe00707f +#define MATCH_AES64ES 0x32000033 +#define MASK_AES64ES 0xfe00707f +#define MATCH_AES64ESM 0x36000033 +#define MASK_AES64ESM 0xfe00707f +#define MATCH_AES64IM 0x30001013 +#define MASK_AES64IM 0xfff0707f +#define MATCH_AES64KS1I 0x31001013 +#define MASK_AES64KS1I 0xff00707f +#define MATCH_AES64KS2 0x7e000033 +#define MASK_AES64KS2 0xfe00707f +#define MATCH_AMOADD_D 0x302f +#define MASK_AMOADD_D 0xf800707f #define MATCH_AMOADD_W 0x202f -#define MASK_AMOADD_W 0xf800707f -#define MATCH_AMOXOR_W 0x2000202f -#define MASK_AMOXOR_W 0xf800707f -#define MATCH_AMOOR_W 0x4000202f -#define MASK_AMOOR_W 0xf800707f +#define MASK_AMOADD_W 0xf800707f +#define MATCH_AMOAND_D 0x6000302f +#define MASK_AMOAND_D 0xf800707f #define MATCH_AMOAND_W 0x6000202f -#define MASK_AMOAND_W 0xf800707f -#define MATCH_AMOMIN_W 0x8000202f -#define MASK_AMOMIN_W 0xf800707f +#define MASK_AMOAND_W 0xf800707f +#define MATCH_AMOMAX_D 0xa000302f +#define MASK_AMOMAX_D 0xf800707f #define MATCH_AMOMAX_W 0xa000202f -#define MASK_AMOMAX_W 0xf800707f -#define MATCH_AMOMINU_W 0xc000202f -#define MASK_AMOMINU_W 0xf800707f +#define MASK_AMOMAX_W 0xf800707f +#define MATCH_AMOMAXU_D 0xe000302f +#define MASK_AMOMAXU_D 0xf800707f #define MATCH_AMOMAXU_W 0xe000202f -#define MASK_AMOMAXU_W 0xf800707f -#define MATCH_AMOSWAP_W 0x800202f -#define MASK_AMOSWAP_W 0xf800707f -#define MATCH_LR_W 0x1000202f -#define MASK_LR_W 0xf9f0707f -#define MATCH_SC_W 0x1800202f -#define MASK_SC_W 0xf800707f -#define MATCH_AMOADD_D 0x302f -#define MASK_AMOADD_D 0xf800707f -#define MATCH_AMOXOR_D 0x2000302f -#define MASK_AMOXOR_D 0xf800707f -#define MATCH_AMOOR_D 0x4000302f -#define MASK_AMOOR_D 0xf800707f -#define MATCH_AMOAND_D 0x6000302f -#define MASK_AMOAND_D 0xf800707f +#define MASK_AMOMAXU_W 0xf800707f #define MATCH_AMOMIN_D 0x8000302f -#define MASK_AMOMIN_D 0xf800707f -#define MATCH_AMOMAX_D 0xa000302f -#define MASK_AMOMAX_D 0xf800707f +#define MASK_AMOMIN_D 0xf800707f +#define MATCH_AMOMIN_W 0x8000202f +#define MASK_AMOMIN_W 0xf800707f #define MATCH_AMOMINU_D 0xc000302f -#define MASK_AMOMINU_D 0xf800707f -#define MATCH_AMOMAXU_D 0xe000302f -#define MASK_AMOMAXU_D 0xf800707f +#define MASK_AMOMINU_D 0xf800707f +#define MATCH_AMOMINU_W 0xc000202f +#define MASK_AMOMINU_W 0xf800707f +#define MATCH_AMOOR_D 0x4000302f +#define MASK_AMOOR_D 0xf800707f +#define MATCH_AMOOR_W 0x4000202f +#define MASK_AMOOR_W 0xf800707f #define MATCH_AMOSWAP_D 0x800302f -#define MASK_AMOSWAP_D 0xf800707f -#define MATCH_LR_D 0x1000302f -#define MASK_LR_D 0xf9f0707f -#define MATCH_SC_D 0x1800302f -#define MASK_SC_D 0xf800707f -#define MATCH_ECALL 0x73 -#define MASK_ECALL 0xffffffff -#define MATCH_EBREAK 0x100073 -#define MASK_EBREAK 0xffffffff -#define MATCH_URET 0x200073 -#define MASK_URET 0xffffffff -#define MATCH_SRET 0x10200073 -#define MASK_SRET 0xffffffff -#define MATCH_MRET 0x30200073 -#define MASK_MRET 0xffffffff -#define MATCH_DRET 0x7b200073 -#define MASK_DRET 0xffffffff -#define MATCH_SFENCE_VMA 0x12000073 -#define MASK_SFENCE_VMA 0xfe007fff -#define MATCH_WFI 0x10500073 -#define MASK_WFI 0xffffffff -#define MATCH_CSRRW 0x1073 -#define MASK_CSRRW 0x707f -#define MATCH_CSRRS 0x2073 -#define MASK_CSRRS 0x707f +#define MASK_AMOSWAP_D 0xf800707f +#define MATCH_AMOSWAP_W 0x800202f +#define MASK_AMOSWAP_W 0xf800707f +#define MATCH_AMOXOR_D 0x2000302f +#define MASK_AMOXOR_D 0xf800707f +#define MATCH_AMOXOR_W 0x2000202f +#define MASK_AMOXOR_W 0xf800707f +#define MATCH_AND 0x7033 +#define MASK_AND 0xfe00707f +#define MATCH_ANDI 0x7013 +#define MASK_ANDI 0x707f +#define MATCH_ANDN 0x40007033 +#define MASK_ANDN 0xfe00707f +#define MATCH_AUIPC 0x17 +#define MASK_AUIPC 0x7f +#define MATCH_AVE 0xe0000077 +#define MASK_AVE 0xfe00707f +#define MATCH_BCLR 0x48001033 +#define MASK_BCLR 0xfe00707f +#define MATCH_BCLRI 0x48001013 +#define MASK_BCLRI 0xfc00707f +#define MATCH_BCOMPRESS 0x8006033 +#define MASK_BCOMPRESS 0xfe00707f +#define MATCH_BCOMPRESSW 0x800603b +#define MASK_BCOMPRESSW 0xfe00707f +#define MATCH_BDECOMPRESS 0x48006033 +#define MASK_BDECOMPRESS 0xfe00707f +#define MATCH_BDECOMPRESSW 0x4800603b +#define MASK_BDECOMPRESSW 0xfe00707f +#define MATCH_BEQ 0x63 +#define MASK_BEQ 0x707f +#define MATCH_BEXT 0x48005033 +#define MASK_BEXT 0xfe00707f +#define MATCH_BEXTI 0x48005013 +#define MASK_BEXTI 0xfc00707f +#define MATCH_BFP 0x48007033 +#define MASK_BFP 0xfe00707f +#define MATCH_BFPW 0x4800703b +#define MASK_BFPW 0xfe00707f +#define MATCH_BGE 0x5063 +#define MASK_BGE 0x707f +#define MATCH_BGEU 0x7063 +#define MASK_BGEU 0x707f +#define MATCH_BINV 0x68001033 +#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 +#define MASK_BLTU 0x707f +#define MATCH_BMATFLIP 0x60301013 +#define MASK_BMATFLIP 0xfff0707f +#define MATCH_BMATOR 0x8003033 +#define MASK_BMATOR 0xfe00707f +#define MATCH_BMATXOR 0x48003033 +#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 +#define MASK_BSETI 0xfc00707f +#define MATCH_C_ADD 0x9002 +#define MASK_C_ADD 0xf003 +#define MATCH_C_ADDI 0x1 +#define MASK_C_ADDI 0xe003 +#define MATCH_C_ADDI16SP 0x6101 +#define MASK_C_ADDI16SP 0xef83 +#define MATCH_C_ADDI4SPN 0x0 +#define MASK_C_ADDI4SPN 0xe003 +#define MATCH_C_ADDIW 0x2001 +#define MASK_C_ADDIW 0xe003 +#define MATCH_C_ADDW 0x9c21 +#define MASK_C_ADDW 0xfc63 +#define MATCH_C_AND 0x8c61 +#define MASK_C_AND 0xfc63 +#define MATCH_C_ANDI 0x8801 +#define MASK_C_ANDI 0xec03 +#define MATCH_C_BEQZ 0xc001 +#define MASK_C_BEQZ 0xe003 +#define MATCH_C_BNEZ 0xe001 +#define MASK_C_BNEZ 0xe003 +#define MATCH_C_EBREAK 0x9002 +#define MASK_C_EBREAK 0xffff +#define MATCH_C_FLD 0x2000 +#define MASK_C_FLD 0xe003 +#define MATCH_C_FLDSP 0x2002 +#define MASK_C_FLDSP 0xe003 +#define MATCH_C_FLW 0x6000 +#define MASK_C_FLW 0xe003 +#define MATCH_C_FLWSP 0x6002 +#define MASK_C_FLWSP 0xe003 +#define MATCH_C_FSD 0xa000 +#define MASK_C_FSD 0xe003 +#define MATCH_C_FSDSP 0xa002 +#define MASK_C_FSDSP 0xe003 +#define MATCH_C_FSW 0xe000 +#define MASK_C_FSW 0xe003 +#define MATCH_C_FSWSP 0xe002 +#define MASK_C_FSWSP 0xe003 +#define MATCH_C_J 0xa001 +#define MASK_C_J 0xe003 +#define MATCH_C_JAL 0x2001 +#define MASK_C_JAL 0xe003 +#define MATCH_C_JALR 0x9002 +#define MASK_C_JALR 0xf07f +#define MATCH_C_JR 0x8002 +#define MASK_C_JR 0xf07f +#define MATCH_C_LD 0x6000 +#define MASK_C_LD 0xe003 +#define MATCH_C_LDSP 0x6002 +#define MASK_C_LDSP 0xe003 +#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_MV 0x8002 +#define MASK_C_MV 0xf003 +#define MATCH_C_NOP 0x1 +#define MASK_C_NOP 0xef83 +#define MATCH_C_OR 0x8c41 +#define MASK_C_OR 0xfc63 +#define MATCH_C_SD 0xe000 +#define MASK_C_SD 0xe003 +#define MATCH_C_SDSP 0xe002 +#define MASK_C_SDSP 0xe003 +#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 +#define MASK_C_SRLI 0xec03 +#define MATCH_C_SUB 0x8c01 +#define MASK_C_SUB 0xfc63 +#define MATCH_C_SUBW 0x9c01 +#define MASK_C_SUBW 0xfc63 +#define MATCH_C_SW 0xc000 +#define MASK_C_SW 0xe003 +#define MATCH_C_SWSP 0xc002 +#define MASK_C_SWSP 0xe003 +#define MATCH_C_XOR 0x8c21 +#define MASK_C_XOR 0xfc63 +#define MATCH_CBO_CLEAN 0x10200f +#define MASK_CBO_CLEAN 0xfff07fff +#define MATCH_CBO_FLUSH 0x20200f +#define MASK_CBO_FLUSH 0xfff07fff +#define MATCH_CBO_INVAL 0x200f +#define MASK_CBO_INVAL 0xfff07fff +#define MATCH_CBO_ZERO 0x40200f +#define MASK_CBO_ZERO 0xfff07fff +#define MATCH_CLMUL 0xa001033 +#define MASK_CLMUL 0xfe00707f +#define MATCH_CLMULH 0xa003033 +#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 +#define MASK_CLRS32 0xfff0707f +#define MATCH_CLRS8 0xae000077 +#define MASK_CLRS8 0xfff0707f +#define MATCH_CLZ 0x60001013 +#define MASK_CLZ 0xfff0707f +#define MATCH_CLZ16 0xae900077 +#define MASK_CLZ16 0xfff0707f +#define MATCH_CLZ32 0xaf900077 +#define MASK_CLZ32 0xfff0707f +#define MATCH_CLZ8 0xae100077 +#define MASK_CLZ8 0xfff0707f +#define MATCH_CLZW 0x6000101b +#define MASK_CLZW 0xfff0707f +#define MATCH_CMIX 0x6001033 +#define MASK_CMIX 0x600707f +#define MATCH_CMOV 0x6005033 +#define MASK_CMOV 0x600707f +#define MATCH_CMPEQ16 0x4c000077 +#define MASK_CMPEQ16 0xfe00707f +#define MATCH_CMPEQ8 0x4e000077 +#define MASK_CMPEQ8 0xfe00707f +#define MATCH_CPOP 0x60201013 +#define MASK_CPOP 0xfff0707f +#define MATCH_CPOPW 0x6020101b +#define MASK_CPOPW 0xfff0707f +#define MATCH_CRAS16 0x44000077 +#define MASK_CRAS16 0xfe00707f +#define MATCH_CRAS32 0x44002077 +#define MASK_CRAS32 0xfe00707f +#define MATCH_CRC32_B 0x61001013 +#define MASK_CRC32_B 0xfff0707f +#define MATCH_CRC32_D 0x61301013 +#define MASK_CRC32_D 0xfff0707f +#define MATCH_CRC32_H 0x61101013 +#define MASK_CRC32_H 0xfff0707f +#define MATCH_CRC32_W 0x61201013 +#define MASK_CRC32_W 0xfff0707f +#define MATCH_CRC32C_B 0x61801013 +#define MASK_CRC32C_B 0xfff0707f +#define MATCH_CRC32C_D 0x61b01013 +#define MASK_CRC32C_D 0xfff0707f +#define MATCH_CRC32C_H 0x61901013 +#define MASK_CRC32C_H 0xfff0707f +#define MATCH_CRC32C_W 0x61a01013 +#define MASK_CRC32C_W 0xfff0707f +#define MATCH_CRSA16 0x46000077 +#define MASK_CRSA16 0xfe00707f +#define MATCH_CRSA32 0x46002077 +#define MASK_CRSA32 0xfe00707f #define MATCH_CSRRC 0x3073 -#define MASK_CSRRC 0x707f -#define MATCH_CSRRWI 0x5073 -#define MASK_CSRRWI 0x707f -#define MATCH_CSRRSI 0x6073 -#define MASK_CSRRSI 0x707f +#define MASK_CSRRC 0x707f #define MATCH_CSRRCI 0x7073 -#define MASK_CSRRCI 0x707f -#define MATCH_FADD_S 0x53 -#define MASK_FADD_S 0xfe00007f -#define MATCH_FSUB_S 0x8000053 -#define MASK_FSUB_S 0xfe00007f -#define MATCH_FMUL_S 0x10000053 -#define MASK_FMUL_S 0xfe00007f -#define MATCH_FDIV_S 0x18000053 -#define MASK_FDIV_S 0xfe00007f -#define MATCH_FSGNJ_S 0x20000053 -#define MASK_FSGNJ_S 0xfe00707f -#define MATCH_FSGNJN_S 0x20001053 -#define MASK_FSGNJN_S 0xfe00707f -#define MATCH_FSGNJX_S 0x20002053 -#define MASK_FSGNJX_S 0xfe00707f -#define MATCH_FMIN_S 0x28000053 -#define MASK_FMIN_S 0xfe00707f -#define MATCH_FMAX_S 0x28001053 -#define MASK_FMAX_S 0xfe00707f -#define MATCH_FSQRT_S 0x58000053 -#define MASK_FSQRT_S 0xfff0007f +#define MASK_CSRRCI 0x707f +#define MATCH_CSRRS 0x2073 +#define MASK_CSRRS 0x707f +#define MATCH_CSRRSI 0x6073 +#define MASK_CSRRSI 0x707f +#define MATCH_CSRRW 0x1073 +#define MASK_CSRRW 0x707f +#define MATCH_CSRRWI 0x5073 +#define MASK_CSRRWI 0x707f +#define MATCH_CTZ 0x60101013 +#define MASK_CTZ 0xfff0707f +#define MATCH_CTZW 0x6010101b +#define MASK_CTZW 0xfff0707f +#define MATCH_DIV 0x2004033 +#define MASK_DIV 0xfe00707f +#define MATCH_DIVU 0x2005033 +#define MASK_DIVU 0xfe00707f +#define MATCH_DIVUW 0x200503b +#define MASK_DIVUW 0xfe00707f +#define MATCH_DIVW 0x200403b +#define MASK_DIVW 0xfe00707f +#define MATCH_DRET 0x7b200073 +#define MASK_DRET 0xffffffff +#define MATCH_EBREAK 0x100073 +#define MASK_EBREAK 0xffffffff +#define MATCH_ECALL 0x73 +#define MASK_ECALL 0xffffffff #define MATCH_FADD_D 0x2000053 -#define MASK_FADD_D 0xfe00007f -#define MATCH_FSUB_D 0xa000053 -#define MASK_FSUB_D 0xfe00007f -#define MATCH_FMUL_D 0x12000053 -#define MASK_FMUL_D 0xfe00007f -#define MATCH_FDIV_D 0x1a000053 -#define MASK_FDIV_D 0xfe00007f -#define MATCH_FSGNJ_D 0x22000053 -#define MASK_FSGNJ_D 0xfe00707f -#define MATCH_FSGNJN_D 0x22001053 -#define MASK_FSGNJN_D 0xfe00707f -#define MATCH_FSGNJX_D 0x22002053 -#define MASK_FSGNJX_D 0xfe00707f -#define MATCH_FMIN_D 0x2a000053 -#define MASK_FMIN_D 0xfe00707f -#define MATCH_FMAX_D 0x2a001053 -#define MASK_FMAX_D 0xfe00707f -#define MATCH_FCVT_S_D 0x40100053 -#define MASK_FCVT_S_D 0xfff0007f -#define MATCH_FCVT_D_S 0x42000053 -#define MASK_FCVT_D_S 0xfff0007f -#define MATCH_FSQRT_D 0x5a000053 -#define MASK_FSQRT_D 0xfff0007f +#define MASK_FADD_D 0xfe00007f +#define MATCH_FADD_H 0x4000053 +#define MASK_FADD_H 0xfe00007f #define MATCH_FADD_Q 0x6000053 -#define MASK_FADD_Q 0xfe00007f -#define MATCH_FSUB_Q 0xe000053 -#define MASK_FSUB_Q 0xfe00007f -#define MATCH_FMUL_Q 0x16000053 -#define MASK_FMUL_Q 0xfe00007f -#define MATCH_FDIV_Q 0x1e000053 -#define MASK_FDIV_Q 0xfe00007f -#define MATCH_FSGNJ_Q 0x26000053 -#define MASK_FSGNJ_Q 0xfe00707f -#define MATCH_FSGNJN_Q 0x26001053 -#define MASK_FSGNJN_Q 0xfe00707f -#define MATCH_FSGNJX_Q 0x26002053 -#define MASK_FSGNJX_Q 0xfe00707f -#define MATCH_FMIN_Q 0x2e000053 -#define MASK_FMIN_Q 0xfe00707f -#define MATCH_FMAX_Q 0x2e001053 -#define MASK_FMAX_Q 0xfe00707f -#define MATCH_FCVT_S_Q 0x40300053 -#define MASK_FCVT_S_Q 0xfff0007f -#define MATCH_FCVT_Q_S 0x46000053 -#define MASK_FCVT_Q_S 0xfff0007f -#define MATCH_FCVT_D_Q 0x42300053 -#define MASK_FCVT_D_Q 0xfff0007f -#define MATCH_FCVT_Q_D 0x46100053 -#define MASK_FCVT_Q_D 0xfff0007f -#define MATCH_FSQRT_Q 0x5e000053 -#define MASK_FSQRT_Q 0xfff0007f -#define MATCH_FLE_S 0xa0000053 -#define MASK_FLE_S 0xfe00707f -#define MATCH_FLT_S 0xa0001053 -#define MASK_FLT_S 0xfe00707f -#define MATCH_FEQ_S 0xa0002053 -#define MASK_FEQ_S 0xfe00707f -#define MATCH_FLE_D 0xa2000053 -#define MASK_FLE_D 0xfe00707f -#define MATCH_FLT_D 0xa2001053 -#define MASK_FLT_D 0xfe00707f -#define MATCH_FEQ_D 0xa2002053 -#define MASK_FEQ_D 0xfe00707f -#define MATCH_FLE_Q 0xa6000053 -#define MASK_FLE_Q 0xfe00707f -#define MATCH_FLT_Q 0xa6001053 -#define MASK_FLT_Q 0xfe00707f -#define MATCH_FEQ_Q 0xa6002053 -#define MASK_FEQ_Q 0xfe00707f -#define MATCH_FCVT_W_S 0xc0000053 -#define MASK_FCVT_W_S 0xfff0007f -#define MATCH_FCVT_WU_S 0xc0100053 -#define MASK_FCVT_WU_S 0xfff0007f -#define MATCH_FCVT_L_S 0xc0200053 -#define MASK_FCVT_L_S 0xfff0007f -#define MATCH_FCVT_LU_S 0xc0300053 -#define MASK_FCVT_LU_S 0xfff0007f -#define MATCH_FMV_X_W 0xe0000053 -#define MASK_FMV_X_W 0xfff0707f -#define MATCH_FCLASS_S 0xe0001053 -#define MASK_FCLASS_S 0xfff0707f -#define MATCH_FCVT_W_D 0xc2000053 -#define MASK_FCVT_W_D 0xfff0007f -#define MATCH_FCVT_WU_D 0xc2100053 -#define MASK_FCVT_WU_D 0xfff0007f -#define MATCH_FCVT_L_D 0xc2200053 -#define MASK_FCVT_L_D 0xfff0007f -#define MATCH_FCVT_LU_D 0xc2300053 -#define MASK_FCVT_LU_D 0xfff0007f -#define MATCH_FMV_X_D 0xe2000053 -#define MASK_FMV_X_D 0xfff0707f +#define MASK_FADD_Q 0xfe00007f +#define MATCH_FADD_S 0x53 +#define MASK_FADD_S 0xfe00007f #define MATCH_FCLASS_D 0xe2001053 -#define MASK_FCLASS_D 0xfff0707f -#define MATCH_FCVT_W_Q 0xc6000053 -#define MASK_FCVT_W_Q 0xfff0007f -#define MATCH_FCVT_WU_Q 0xc6100053 -#define MASK_FCVT_WU_Q 0xfff0007f -#define MATCH_FCVT_L_Q 0xc6200053 -#define MASK_FCVT_L_Q 0xfff0007f -#define MATCH_FCVT_LU_Q 0xc6300053 -#define MASK_FCVT_LU_Q 0xfff0007f -#define MATCH_FMV_X_Q 0xe6000053 -#define MASK_FMV_X_Q 0xfff0707f +#define MASK_FCLASS_D 0xfff0707f +#define MATCH_FCLASS_H 0xe4001053 +#define MASK_FCLASS_H 0xfff0707f #define MATCH_FCLASS_Q 0xe6001053 -#define MASK_FCLASS_Q 0xfff0707f -#define MATCH_FCVT_S_W 0xd0000053 -#define MASK_FCVT_S_W 0xfff0007f -#define MATCH_FCVT_S_WU 0xd0100053 -#define MASK_FCVT_S_WU 0xfff0007f -#define MATCH_FCVT_S_L 0xd0200053 -#define MASK_FCVT_S_L 0xfff0007f -#define MATCH_FCVT_S_LU 0xd0300053 -#define MASK_FCVT_S_LU 0xfff0007f -#define MATCH_FMV_W_X 0xf0000053 -#define MASK_FMV_W_X 0xfff0707f -#define MATCH_FCVT_D_W 0xd2000053 -#define MASK_FCVT_D_W 0xfff0007f -#define MATCH_FCVT_D_WU 0xd2100053 -#define MASK_FCVT_D_WU 0xfff0007f +#define MASK_FCLASS_Q 0xfff0707f +#define MATCH_FCLASS_S 0xe0001053 +#define MASK_FCLASS_S 0xfff0707f +#define MATCH_FCVT_D_H 0x42200053 +#define MASK_FCVT_D_H 0xfff0007f #define MATCH_FCVT_D_L 0xd2200053 -#define MASK_FCVT_D_L 0xfff0007f +#define MASK_FCVT_D_L 0xfff0007f #define MATCH_FCVT_D_LU 0xd2300053 -#define MASK_FCVT_D_LU 0xfff0007f -#define MATCH_FMV_D_X 0xf2000053 -#define MASK_FMV_D_X 0xfff0707f -#define MATCH_FCVT_Q_W 0xd6000053 -#define MASK_FCVT_Q_W 0xfff0007f -#define MATCH_FCVT_Q_WU 0xd6100053 -#define MASK_FCVT_Q_WU 0xfff0007f +#define MASK_FCVT_D_LU 0xfff0007f +#define MATCH_FCVT_D_Q 0x42300053 +#define MASK_FCVT_D_Q 0xfff0007f +#define MATCH_FCVT_D_S 0x42000053 +#define MASK_FCVT_D_S 0xfff0007f +#define MATCH_FCVT_D_W 0xd2000053 +#define MASK_FCVT_D_W 0xfff0007f +#define MATCH_FCVT_D_WU 0xd2100053 +#define MASK_FCVT_D_WU 0xfff0007f +#define MATCH_FCVT_H_D 0x44100053 +#define MASK_FCVT_H_D 0xfff0007f +#define MATCH_FCVT_H_L 0xd4200053 +#define MASK_FCVT_H_L 0xfff0007f +#define MATCH_FCVT_H_LU 0xd4300053 +#define MASK_FCVT_H_LU 0xfff0007f +#define MATCH_FCVT_H_Q 0x44300053 +#define MASK_FCVT_H_Q 0xfff0007f +#define MATCH_FCVT_H_S 0x44000053 +#define MASK_FCVT_H_S 0xfff0007f +#define MATCH_FCVT_H_W 0xd4000053 +#define MASK_FCVT_H_W 0xfff0007f +#define MATCH_FCVT_H_WU 0xd4100053 +#define MASK_FCVT_H_WU 0xfff0007f +#define MATCH_FCVT_L_D 0xc2200053 +#define MASK_FCVT_L_D 0xfff0007f +#define MATCH_FCVT_L_H 0xc4200053 +#define MASK_FCVT_L_H 0xfff0007f +#define MATCH_FCVT_L_Q 0xc6200053 +#define MASK_FCVT_L_Q 0xfff0007f +#define MATCH_FCVT_L_S 0xc0200053 +#define MASK_FCVT_L_S 0xfff0007f +#define MATCH_FCVT_LU_D 0xc2300053 +#define MASK_FCVT_LU_D 0xfff0007f +#define MATCH_FCVT_LU_H 0xc4300053 +#define MASK_FCVT_LU_H 0xfff0007f +#define MATCH_FCVT_LU_Q 0xc6300053 +#define MASK_FCVT_LU_Q 0xfff0007f +#define MATCH_FCVT_LU_S 0xc0300053 +#define MASK_FCVT_LU_S 0xfff0007f +#define MATCH_FCVT_Q_D 0x46100053 +#define MASK_FCVT_Q_D 0xfff0007f +#define MATCH_FCVT_Q_H 0x46200053 +#define MASK_FCVT_Q_H 0xfff0007f #define MATCH_FCVT_Q_L 0xd6200053 -#define MASK_FCVT_Q_L 0xfff0007f +#define MASK_FCVT_Q_L 0xfff0007f #define MATCH_FCVT_Q_LU 0xd6300053 -#define MASK_FCVT_Q_LU 0xfff0007f -#define MATCH_FMV_Q_X 0xf6000053 -#define MASK_FMV_Q_X 0xfff0707f -#define MATCH_FLW 0x2007 -#define MASK_FLW 0x707f +#define MASK_FCVT_Q_LU 0xfff0007f +#define MATCH_FCVT_Q_S 0x46000053 +#define MASK_FCVT_Q_S 0xfff0007f +#define MATCH_FCVT_Q_W 0xd6000053 +#define MASK_FCVT_Q_W 0xfff0007f +#define MATCH_FCVT_Q_WU 0xd6100053 +#define MASK_FCVT_Q_WU 0xfff0007f +#define MATCH_FCVT_S_D 0x40100053 +#define MASK_FCVT_S_D 0xfff0007f +#define MATCH_FCVT_S_H 0x40200053 +#define MASK_FCVT_S_H 0xfff0007f +#define MATCH_FCVT_S_L 0xd0200053 +#define MASK_FCVT_S_L 0xfff0007f +#define MATCH_FCVT_S_LU 0xd0300053 +#define MASK_FCVT_S_LU 0xfff0007f +#define MATCH_FCVT_S_Q 0x40300053 +#define MASK_FCVT_S_Q 0xfff0007f +#define MATCH_FCVT_S_W 0xd0000053 +#define MASK_FCVT_S_W 0xfff0007f +#define MATCH_FCVT_S_WU 0xd0100053 +#define MASK_FCVT_S_WU 0xfff0007f +#define MATCH_FCVT_W_D 0xc2000053 +#define MASK_FCVT_W_D 0xfff0007f +#define MATCH_FCVT_W_H 0xc4000053 +#define MASK_FCVT_W_H 0xfff0007f +#define MATCH_FCVT_W_Q 0xc6000053 +#define MASK_FCVT_W_Q 0xfff0007f +#define MATCH_FCVT_W_S 0xc0000053 +#define MASK_FCVT_W_S 0xfff0007f +#define MATCH_FCVT_WU_D 0xc2100053 +#define MASK_FCVT_WU_D 0xfff0007f +#define MATCH_FCVT_WU_H 0xc4100053 +#define MASK_FCVT_WU_H 0xfff0007f +#define MATCH_FCVT_WU_Q 0xc6100053 +#define MASK_FCVT_WU_Q 0xfff0007f +#define MATCH_FCVT_WU_S 0xc0100053 +#define MASK_FCVT_WU_S 0xfff0007f +#define MATCH_FDIV_D 0x1a000053 +#define MASK_FDIV_D 0xfe00007f +#define MATCH_FDIV_H 0x1c000053 +#define MASK_FDIV_H 0xfe00007f +#define MATCH_FDIV_Q 0x1e000053 +#define MASK_FDIV_Q 0xfe00007f +#define MATCH_FDIV_S 0x18000053 +#define MASK_FDIV_S 0xfe00007f +#define MATCH_FENCE 0xf +#define MASK_FENCE 0x707f +#define MATCH_FENCE_I 0x100f +#define MASK_FENCE_I 0x707f +#define MATCH_FEQ_D 0xa2002053 +#define MASK_FEQ_D 0xfe00707f +#define MATCH_FEQ_H 0xa4002053 +#define MASK_FEQ_H 0xfe00707f +#define MATCH_FEQ_Q 0xa6002053 +#define MASK_FEQ_Q 0xfe00707f +#define MATCH_FEQ_S 0xa0002053 +#define MASK_FEQ_S 0xfe00707f #define MATCH_FLD 0x3007 -#define MASK_FLD 0x707f +#define MASK_FLD 0x707f +#define MATCH_FLE_D 0xa2000053 +#define MASK_FLE_D 0xfe00707f +#define MATCH_FLE_H 0xa4000053 +#define MASK_FLE_H 0xfe00707f +#define MATCH_FLE_Q 0xa6000053 +#define MASK_FLE_Q 0xfe00707f +#define MATCH_FLE_S 0xa0000053 +#define MASK_FLE_S 0xfe00707f +#define MATCH_FLH 0x1007 +#define MASK_FLH 0x707f #define MATCH_FLQ 0x4007 -#define MASK_FLQ 0x707f -#define MATCH_FSW 0x2027 -#define MASK_FSW 0x707f -#define MATCH_FSD 0x3027 -#define MASK_FSD 0x707f -#define MATCH_FSQ 0x4027 -#define MASK_FSQ 0x707f +#define MASK_FLQ 0x707f +#define MATCH_FLT_D 0xa2001053 +#define MASK_FLT_D 0xfe00707f +#define MATCH_FLT_H 0xa4001053 +#define MASK_FLT_H 0xfe00707f +#define MATCH_FLT_Q 0xa6001053 +#define MASK_FLT_Q 0xfe00707f +#define MATCH_FLT_S 0xa0001053 +#define MASK_FLT_S 0xfe00707f +#define MATCH_FLW 0x2007 +#define MASK_FLW 0x707f +#define MATCH_FMADD_D 0x2000043 +#define MASK_FMADD_D 0x600007f +#define MATCH_FMADD_H 0x4000043 +#define MASK_FMADD_H 0x600007f +#define MATCH_FMADD_Q 0x6000043 +#define MASK_FMADD_Q 0x600007f #define MATCH_FMADD_S 0x43 -#define MASK_FMADD_S 0x600007f +#define MASK_FMADD_S 0x600007f +#define MATCH_FMAX_D 0x2a001053 +#define MASK_FMAX_D 0xfe00707f +#define MATCH_FMAX_H 0x2c001053 +#define MASK_FMAX_H 0xfe00707f +#define MATCH_FMAX_Q 0x2e001053 +#define MASK_FMAX_Q 0xfe00707f +#define MATCH_FMAX_S 0x28001053 +#define MASK_FMAX_S 0xfe00707f +#define MATCH_FMIN_D 0x2a000053 +#define MASK_FMIN_D 0xfe00707f +#define MATCH_FMIN_H 0x2c000053 +#define MASK_FMIN_H 0xfe00707f +#define MATCH_FMIN_Q 0x2e000053 +#define MASK_FMIN_Q 0xfe00707f +#define MATCH_FMIN_S 0x28000053 +#define MASK_FMIN_S 0xfe00707f +#define MATCH_FMSUB_D 0x2000047 +#define MASK_FMSUB_D 0x600007f +#define MATCH_FMSUB_H 0x4000047 +#define MASK_FMSUB_H 0x600007f +#define MATCH_FMSUB_Q 0x6000047 +#define MASK_FMSUB_Q 0x600007f #define MATCH_FMSUB_S 0x47 -#define MASK_FMSUB_S 0x600007f -#define MATCH_FNMSUB_S 0x4b -#define MASK_FNMSUB_S 0x600007f +#define MASK_FMSUB_S 0x600007f +#define MATCH_FMUL_D 0x12000053 +#define MASK_FMUL_D 0xfe00007f +#define MATCH_FMUL_H 0x14000053 +#define MASK_FMUL_H 0xfe00007f +#define MATCH_FMUL_Q 0x16000053 +#define MASK_FMUL_Q 0xfe00007f +#define MATCH_FMUL_S 0x10000053 +#define MASK_FMUL_S 0xfe00007f +#define MATCH_FMV_D_X 0xf2000053 +#define MASK_FMV_D_X 0xfff0707f +#define MATCH_FMV_H_X 0xf4000053 +#define MASK_FMV_H_X 0xfff0707f +#define MATCH_FMV_W_X 0xf0000053 +#define MASK_FMV_W_X 0xfff0707f +#define MATCH_FMV_X_D 0xe2000053 +#define MASK_FMV_X_D 0xfff0707f +#define MATCH_FMV_X_H 0xe4000053 +#define MASK_FMV_X_H 0xfff0707f +#define MATCH_FMV_X_W 0xe0000053 +#define MASK_FMV_X_W 0xfff0707f +#define MATCH_FNMADD_D 0x200004f +#define MASK_FNMADD_D 0x600007f +#define MATCH_FNMADD_H 0x400004f +#define MASK_FNMADD_H 0x600007f +#define MATCH_FNMADD_Q 0x600004f +#define MASK_FNMADD_Q 0x600007f #define MATCH_FNMADD_S 0x4f -#define MASK_FNMADD_S 0x600007f -#define MATCH_FMADD_D 0x2000043 -#define MASK_FMADD_D 0x600007f -#define MATCH_FMSUB_D 0x2000047 -#define MASK_FMSUB_D 0x600007f +#define MASK_FNMADD_S 0x600007f #define MATCH_FNMSUB_D 0x200004b -#define MASK_FNMSUB_D 0x600007f -#define MATCH_FNMADD_D 0x200004f -#define MASK_FNMADD_D 0x600007f -#define MATCH_FMADD_Q 0x6000043 -#define MASK_FMADD_Q 0x600007f -#define MATCH_FMSUB_Q 0x6000047 -#define MASK_FMSUB_Q 0x600007f +#define MASK_FNMSUB_D 0x600007f +#define MATCH_FNMSUB_H 0x400004b +#define MASK_FNMSUB_H 0x600007f #define MATCH_FNMSUB_Q 0x600004b -#define MASK_FNMSUB_Q 0x600007f -#define MATCH_FNMADD_Q 0x600004f -#define MASK_FNMADD_Q 0x600007f -#define MATCH_C_NOP 0x1 -#define MASK_C_NOP 0xffff -#define MATCH_C_ADDI16SP 0x6101 -#define MASK_C_ADDI16SP 0xef83 -#define MATCH_C_JR 0x8002 -#define MASK_C_JR 0xf07f -#define MATCH_C_JALR 0x9002 -#define MASK_C_JALR 0xf07f -#define MATCH_C_EBREAK 0x9002 -#define MASK_C_EBREAK 0xffff -#define MATCH_C_LD 0x6000 -#define MASK_C_LD 0xe003 -#define MATCH_C_SD 0xe000 -#define MASK_C_SD 0xe003 -#define MATCH_C_ADDIW 0x2001 -#define MASK_C_ADDIW 0xe003 -#define MATCH_C_LDSP 0x6002 -#define MASK_C_LDSP 0xe003 -#define MATCH_C_SDSP 0xe002 -#define MASK_C_SDSP 0xe003 -#define MATCH_C_ADDI4SPN 0x0 -#define MASK_C_ADDI4SPN 0xe003 -#define MATCH_C_FLD 0x2000 -#define MASK_C_FLD 0xe003 -#define MATCH_C_LW 0x4000 -#define MASK_C_LW 0xe003 -#define MATCH_C_FLW 0x6000 -#define MASK_C_FLW 0xe003 -#define MATCH_C_FSD 0xa000 -#define MASK_C_FSD 0xe003 -#define MATCH_C_SW 0xc000 -#define MASK_C_SW 0xe003 -#define MATCH_C_FSW 0xe000 -#define MASK_C_FSW 0xe003 -#define MATCH_C_ADDI 0x1 -#define MASK_C_ADDI 0xe003 -#define MATCH_C_JAL 0x2001 -#define MASK_C_JAL 0xe003 -#define MATCH_C_LI 0x4001 -#define MASK_C_LI 0xe003 -#define MATCH_C_LUI 0x6001 -#define MASK_C_LUI 0xe003 -#define MATCH_C_SRLI 0x8001 -#define MASK_C_SRLI 0xec03 -#define MATCH_C_SRAI 0x8401 -#define MASK_C_SRAI 0xec03 -#define MATCH_C_ANDI 0x8801 -#define MASK_C_ANDI 0xec03 -#define MATCH_C_SUB 0x8c01 -#define MASK_C_SUB 0xfc63 -#define MATCH_C_XOR 0x8c21 -#define MASK_C_XOR 0xfc63 -#define MATCH_C_OR 0x8c41 -#define MASK_C_OR 0xfc63 -#define MATCH_C_AND 0x8c61 -#define MASK_C_AND 0xfc63 -#define MATCH_C_SUBW 0x9c01 -#define MASK_C_SUBW 0xfc63 -#define MATCH_C_ADDW 0x9c21 -#define MASK_C_ADDW 0xfc63 -#define MATCH_C_J 0xa001 -#define MASK_C_J 0xe003 -#define MATCH_C_BEQZ 0xc001 -#define MASK_C_BEQZ 0xe003 -#define MATCH_C_BNEZ 0xe001 -#define MASK_C_BNEZ 0xe003 -#define MATCH_C_SLLI 0x2 -#define MASK_C_SLLI 0xe003 -#define MATCH_C_FLDSP 0x2002 -#define MASK_C_FLDSP 0xe003 -#define MATCH_C_LWSP 0x4002 -#define MASK_C_LWSP 0xe003 -#define MATCH_C_FLWSP 0x6002 -#define MASK_C_FLWSP 0xe003 -#define MATCH_C_MV 0x8002 -#define MASK_C_MV 0xf003 -#define MATCH_C_ADD 0x9002 -#define MASK_C_ADD 0xf003 -#define MATCH_C_FSDSP 0xa002 -#define MASK_C_FSDSP 0xe003 -#define MATCH_C_SWSP 0xc002 -#define MASK_C_SWSP 0xe003 -#define MATCH_C_FSWSP 0xe002 -#define MASK_C_FSWSP 0xe003 -#define MATCH_CUSTOM0 0xb -#define MASK_CUSTOM0 0x707f -#define MATCH_CUSTOM0_RS1 0x200b -#define MASK_CUSTOM0_RS1 0x707f -#define MATCH_CUSTOM0_RS1_RS2 0x300b -#define MASK_CUSTOM0_RS1_RS2 0x707f -#define MATCH_CUSTOM0_RD 0x400b -#define MASK_CUSTOM0_RD 0x707f -#define MATCH_CUSTOM0_RD_RS1 0x600b -#define MASK_CUSTOM0_RD_RS1 0x707f -#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b -#define MASK_CUSTOM0_RD_RS1_RS2 0x707f -#define MATCH_CUSTOM1 0x2b -#define MASK_CUSTOM1 0x707f -#define MATCH_CUSTOM1_RS1 0x202b -#define MASK_CUSTOM1_RS1 0x707f -#define MATCH_CUSTOM1_RS1_RS2 0x302b -#define MASK_CUSTOM1_RS1_RS2 0x707f -#define MATCH_CUSTOM1_RD 0x402b -#define MASK_CUSTOM1_RD 0x707f -#define MATCH_CUSTOM1_RD_RS1 0x602b -#define MASK_CUSTOM1_RD_RS1 0x707f -#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b -#define MASK_CUSTOM1_RD_RS1_RS2 0x707f -#define MATCH_CUSTOM2 0x5b -#define MASK_CUSTOM2 0x707f -#define MATCH_CUSTOM2_RS1 0x205b -#define MASK_CUSTOM2_RS1 0x707f -#define MATCH_CUSTOM2_RS1_RS2 0x305b -#define MASK_CUSTOM2_RS1_RS2 0x707f -#define MATCH_CUSTOM2_RD 0x405b -#define MASK_CUSTOM2_RD 0x707f -#define MATCH_CUSTOM2_RD_RS1 0x605b -#define MASK_CUSTOM2_RD_RS1 0x707f -#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b -#define MASK_CUSTOM2_RD_RS1_RS2 0x707f -#define MATCH_CUSTOM3 0x7b -#define MASK_CUSTOM3 0x707f -#define MATCH_CUSTOM3_RS1 0x207b -#define MASK_CUSTOM3_RS1 0x707f -#define MATCH_CUSTOM3_RS1_RS2 0x307b -#define MASK_CUSTOM3_RS1_RS2 0x707f -#define MATCH_CUSTOM3_RD 0x407b -#define MASK_CUSTOM3_RD 0x707f -#define MATCH_CUSTOM3_RD_RS1 0x607b -#define MASK_CUSTOM3_RD_RS1 0x707f -#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b -#define MASK_CUSTOM3_RD_RS1_RS2 0x707f +#define MASK_FNMSUB_Q 0x600007f +#define MATCH_FNMSUB_S 0x4b +#define MASK_FNMSUB_S 0x600007f +#define MATCH_FSD 0x3027 +#define MASK_FSD 0x707f +#define MATCH_FSGNJ_D 0x22000053 +#define MASK_FSGNJ_D 0xfe00707f +#define MATCH_FSGNJ_H 0x24000053 +#define MASK_FSGNJ_H 0xfe00707f +#define MATCH_FSGNJ_Q 0x26000053 +#define MASK_FSGNJ_Q 0xfe00707f +#define MATCH_FSGNJ_S 0x20000053 +#define MASK_FSGNJ_S 0xfe00707f +#define MATCH_FSGNJN_D 0x22001053 +#define MASK_FSGNJN_D 0xfe00707f +#define MATCH_FSGNJN_H 0x24001053 +#define MASK_FSGNJN_H 0xfe00707f +#define MATCH_FSGNJN_Q 0x26001053 +#define MASK_FSGNJN_Q 0xfe00707f +#define MATCH_FSGNJN_S 0x20001053 +#define MASK_FSGNJN_S 0xfe00707f +#define MATCH_FSGNJX_D 0x22002053 +#define MASK_FSGNJX_D 0xfe00707f +#define MATCH_FSGNJX_H 0x24002053 +#define MASK_FSGNJX_H 0xfe00707f +#define MATCH_FSGNJX_Q 0x26002053 +#define MASK_FSGNJX_Q 0xfe00707f +#define MATCH_FSGNJX_S 0x20002053 +#define MASK_FSGNJX_S 0xfe00707f +#define MATCH_FSH 0x1027 +#define MASK_FSH 0x707f +#define MATCH_FSL 0x4001033 +#define MASK_FSL 0x600707f +#define MATCH_FSLW 0x400103b +#define MASK_FSLW 0x600707f +#define MATCH_FSQ 0x4027 +#define MASK_FSQ 0x707f +#define MATCH_FSQRT_D 0x5a000053 +#define MASK_FSQRT_D 0xfff0007f +#define MATCH_FSQRT_H 0x5c000053 +#define MASK_FSQRT_H 0xfff0007f +#define MATCH_FSQRT_Q 0x5e000053 +#define MASK_FSQRT_Q 0xfff0007f +#define MATCH_FSQRT_S 0x58000053 +#define MASK_FSQRT_S 0xfff0007f +#define MATCH_FSR 0x4005033 +#define MASK_FSR 0x600707f +#define MATCH_FSRI 0x4005013 +#define MASK_FSRI 0x400707f +#define MATCH_FSRIW 0x400501b +#define MASK_FSRIW 0x600707f +#define MATCH_FSRW 0x400503b +#define MASK_FSRW 0x600707f +#define MATCH_FSUB_D 0xa000053 +#define MASK_FSUB_D 0xfe00007f +#define MATCH_FSUB_H 0xc000053 +#define MASK_FSUB_H 0xfe00007f +#define MATCH_FSUB_Q 0xe000053 +#define MASK_FSUB_Q 0xfe00007f +#define MATCH_FSUB_S 0x8000053 +#define MASK_FSUB_S 0xfe00007f +#define MATCH_FSW 0x2027 +#define MASK_FSW 0x707f +#define MATCH_GORC 0x28005033 +#define MASK_GORC 0xfe00707f +#define MATCH_GORCI 0x28005013 +#define MASK_GORCI 0xfc00707f +#define MATCH_GORCIW 0x2800501b +#define MASK_GORCIW 0xfe00707f +#define MATCH_GORCW 0x2800503b +#define MASK_GORCW 0xfe00707f +#define MATCH_GREV 0x68005033 +#define MASK_GREV 0xfe00707f +#define MATCH_GREVI 0x68005013 +#define MASK_GREVI 0xfc00707f +#define MATCH_GREVIW 0x6800501b +#define MASK_GREVIW 0xfe00707f +#define MATCH_GREVW 0x6800503b +#define MASK_GREVW 0xfe00707f +#define MATCH_HFENCE_GVMA 0x62000073 +#define MASK_HFENCE_GVMA 0xfe007fff +#define MATCH_HFENCE_VVMA 0x22000073 +#define MASK_HFENCE_VVMA 0xfe007fff +#define MATCH_HINVAL_GVMA 0x66000073 +#define MASK_HINVAL_GVMA 0xfe007fff +#define MATCH_HINVAL_VVMA 0x26000073 +#define MASK_HINVAL_VVMA 0xfe007fff +#define MATCH_HLV_B 0x60004073 +#define MASK_HLV_B 0xfff0707f +#define MATCH_HLV_BU 0x60104073 +#define MASK_HLV_BU 0xfff0707f +#define MATCH_HLV_D 0x6c004073 +#define MASK_HLV_D 0xfff0707f +#define MATCH_HLV_H 0x64004073 +#define MASK_HLV_H 0xfff0707f +#define MATCH_HLV_HU 0x64104073 +#define MASK_HLV_HU 0xfff0707f +#define MATCH_HLV_W 0x68004073 +#define MASK_HLV_W 0xfff0707f +#define MATCH_HLV_WU 0x68104073 +#define MASK_HLV_WU 0xfff0707f +#define MATCH_HLVX_HU 0x64304073 +#define MASK_HLVX_HU 0xfff0707f +#define MATCH_HLVX_WU 0x68304073 +#define MASK_HLVX_WU 0xfff0707f +#define MATCH_HSV_B 0x62004073 +#define MASK_HSV_B 0xfe007fff +#define MATCH_HSV_D 0x6e004073 +#define MASK_HSV_D 0xfe007fff +#define MATCH_HSV_H 0x66004073 +#define MASK_HSV_H 0xfe007fff +#define MATCH_HSV_W 0x6a004073 +#define MASK_HSV_W 0xfe007fff +#define MATCH_INSB 0xac000077 +#define MASK_INSB 0xff80707f +#define MATCH_JAL 0x6f +#define MASK_JAL 0x7f +#define MATCH_JALR 0x67 +#define MASK_JALR 0x707f +#define MATCH_KABS16 0xad100077 +#define MASK_KABS16 0xfff0707f +#define MATCH_KABS32 0xad200077 +#define MASK_KABS32 0xfff0707f +#define MATCH_KABS8 0xad000077 +#define MASK_KABS8 0xfff0707f +#define MATCH_KABSW 0xad400077 +#define MASK_KABSW 0xfff0707f +#define MATCH_KADD16 0x10000077 +#define MASK_KADD16 0xfe00707f +#define MATCH_KADD32 0x10002077 +#define MASK_KADD32 0xfe00707f +#define MATCH_KADD64 0x90001077 +#define MASK_KADD64 0xfe00707f +#define MATCH_KADD8 0x18000077 +#define MASK_KADD8 0xfe00707f +#define MATCH_KADDH 0x4001077 +#define MASK_KADDH 0xfe00707f +#define MATCH_KADDW 0x1077 +#define MASK_KADDW 0xfe00707f +#define MATCH_KCRAS16 0x14000077 +#define MASK_KCRAS16 0xfe00707f +#define MATCH_KCRAS32 0x14002077 +#define MASK_KCRAS32 0xfe00707f +#define MATCH_KCRSA16 0x16000077 +#define MASK_KCRSA16 0xfe00707f +#define MATCH_KCRSA32 0x16002077 +#define MASK_KCRSA32 0xfe00707f +#define MATCH_KDMABB 0xd2001077 +#define MASK_KDMABB 0xfe00707f +#define MATCH_KDMABB16 0xd8001077 +#define MASK_KDMABB16 0xfe00707f +#define MATCH_KDMABT 0xe2001077 +#define MASK_KDMABT 0xfe00707f +#define MATCH_KDMABT16 0xe8001077 +#define MASK_KDMABT16 0xfe00707f +#define MATCH_KDMATT 0xf2001077 +#define MASK_KDMATT 0xfe00707f +#define MATCH_KDMATT16 0xf8001077 +#define MASK_KDMATT16 0xfe00707f +#define MATCH_KDMBB 0xa001077 +#define MASK_KDMBB 0xfe00707f +#define MATCH_KDMBB16 0xda001077 +#define MASK_KDMBB16 0xfe00707f +#define MATCH_KDMBT 0x1a001077 +#define MASK_KDMBT 0xfe00707f +#define MATCH_KDMBT16 0xea001077 +#define MASK_KDMBT16 0xfe00707f +#define MATCH_KDMTT 0x2a001077 +#define MASK_KDMTT 0xfe00707f +#define MATCH_KDMTT16 0xfa001077 +#define MASK_KDMTT16 0xfe00707f +#define MATCH_KHM16 0x86000077 +#define MASK_KHM16 0xfe00707f +#define MATCH_KHM8 0x8e000077 +#define MASK_KHM8 0xfe00707f +#define MATCH_KHMBB 0xc001077 +#define MASK_KHMBB 0xfe00707f +#define MATCH_KHMBB16 0xdc001077 +#define MASK_KHMBB16 0xfe00707f +#define MATCH_KHMBT 0x1c001077 +#define MASK_KHMBT 0xfe00707f +#define MATCH_KHMBT16 0xec001077 +#define MASK_KHMBT16 0xfe00707f +#define MATCH_KHMTT 0x2c001077 +#define MASK_KHMTT 0xfe00707f +#define MATCH_KHMTT16 0xfc001077 +#define MASK_KHMTT16 0xfe00707f +#define MATCH_KHMX16 0x96000077 +#define MASK_KHMX16 0xfe00707f +#define MATCH_KHMX8 0x9e000077 +#define MASK_KHMX8 0xfe00707f +#define MATCH_KMABB 0x5a001077 +#define MASK_KMABB 0xfe00707f +#define MATCH_KMABB32 0x5a002077 +#define MASK_KMABB32 0xfe00707f +#define MATCH_KMABT 0x6a001077 +#define MASK_KMABT 0xfe00707f +#define MATCH_KMABT32 0x6a002077 +#define MASK_KMABT32 0xfe00707f +#define MATCH_KMADA 0x48001077 +#define MASK_KMADA 0xfe00707f +#define MATCH_KMADRS 0x6c001077 +#define MASK_KMADRS 0xfe00707f +#define MATCH_KMADRS32 0x6c002077 +#define MASK_KMADRS32 0xfe00707f +#define MATCH_KMADS 0x5c001077 +#define MASK_KMADS 0xfe00707f +#define MATCH_KMADS32 0x5c002077 +#define MASK_KMADS32 0xfe00707f +#define MATCH_KMAR64 0x94001077 +#define MASK_KMAR64 0xfe00707f +#define MATCH_KMATT 0x7a001077 +#define MASK_KMATT 0xfe00707f +#define MATCH_KMATT32 0x7a002077 +#define MASK_KMATT32 0xfe00707f +#define MATCH_KMAXDA 0x4a001077 +#define MASK_KMAXDA 0xfe00707f +#define MATCH_KMAXDA32 0x4a002077 +#define MASK_KMAXDA32 0xfe00707f +#define MATCH_KMAXDS 0x7c001077 +#define MASK_KMAXDS 0xfe00707f +#define MATCH_KMAXDS32 0x7c002077 +#define MASK_KMAXDS32 0xfe00707f +#define MATCH_KMDA 0x38001077 +#define MASK_KMDA 0xfe00707f +#define MATCH_KMDA32 0x38002077 +#define MASK_KMDA32 0xfe00707f +#define MATCH_KMMAC 0x60001077 +#define MASK_KMMAC 0xfe00707f +#define MATCH_KMMAC_U 0x70001077 +#define MASK_KMMAC_U 0xfe00707f +#define MATCH_KMMAWB 0x46001077 +#define MASK_KMMAWB 0xfe00707f +#define MATCH_KMMAWB2 0xce001077 +#define MASK_KMMAWB2 0xfe00707f +#define MATCH_KMMAWB2_U 0xde001077 +#define MASK_KMMAWB2_U 0xfe00707f +#define MATCH_KMMAWB_U 0x56001077 +#define MASK_KMMAWB_U 0xfe00707f +#define MATCH_KMMAWT 0x66001077 +#define MASK_KMMAWT 0xfe00707f +#define MATCH_KMMAWT2 0xee001077 +#define MASK_KMMAWT2 0xfe00707f +#define MATCH_KMMAWT2_U 0xfe001077 +#define MASK_KMMAWT2_U 0xfe00707f +#define MATCH_KMMAWT_U 0x76001077 +#define MASK_KMMAWT_U 0xfe00707f +#define MATCH_KMMSB 0x42001077 +#define MASK_KMMSB 0xfe00707f +#define MATCH_KMMSB_U 0x52001077 +#define MASK_KMMSB_U 0xfe00707f +#define MATCH_KMMWB2 0x8e001077 +#define MASK_KMMWB2 0xfe00707f +#define MATCH_KMMWB2_U 0x9e001077 +#define MASK_KMMWB2_U 0xfe00707f +#define MATCH_KMMWT2 0xae001077 +#define MASK_KMMWT2 0xfe00707f +#define MATCH_KMMWT2_U 0xbe001077 +#define MASK_KMMWT2_U 0xfe00707f +#define MATCH_KMSDA 0x4c001077 +#define MASK_KMSDA 0xfe00707f +#define MATCH_KMSDA32 0x4c002077 +#define MASK_KMSDA32 0xfe00707f +#define MATCH_KMSR64 0x96001077 +#define MASK_KMSR64 0xfe00707f +#define MATCH_KMSXDA 0x4e001077 +#define MASK_KMSXDA 0xfe00707f +#define MATCH_KMSXDA32 0x4e002077 +#define MASK_KMSXDA32 0xfe00707f +#define MATCH_KMXDA 0x3a001077 +#define MASK_KMXDA 0xfe00707f +#define MATCH_KMXDA32 0x3a002077 +#define MASK_KMXDA32 0xfe00707f +#define MATCH_KSLL16 0x64000077 +#define MASK_KSLL16 0xfe00707f +#define MATCH_KSLL32 0x64002077 +#define MASK_KSLL32 0xfe00707f +#define MATCH_KSLL8 0x6c000077 +#define MASK_KSLL8 0xfe00707f +#define MATCH_KSLLI16 0x75000077 +#define MASK_KSLLI16 0xff00707f +#define MATCH_KSLLI32 0x84002077 +#define MASK_KSLLI32 0xfe00707f +#define MATCH_KSLLI8 0x7c800077 +#define MASK_KSLLI8 0xff80707f +#define MATCH_KSLLIW 0x36001077 +#define MASK_KSLLIW 0xfe00707f +#define MATCH_KSLLW 0x26001077 +#define MASK_KSLLW 0xfe00707f +#define MATCH_KSLRA16 0x56000077 +#define MASK_KSLRA16 0xfe00707f +#define MATCH_KSLRA16_U 0x66000077 +#define MASK_KSLRA16_U 0xfe00707f +#define MATCH_KSLRA32 0x56002077 +#define MASK_KSLRA32 0xfe00707f +#define MATCH_KSLRA32_U 0x66002077 +#define MASK_KSLRA32_U 0xfe00707f +#define MATCH_KSLRA8 0x5e000077 +#define MASK_KSLRA8 0xfe00707f +#define MATCH_KSLRA8_U 0x6e000077 +#define MASK_KSLRA8_U 0xfe00707f +#define MATCH_KSLRAW 0x6e001077 +#define MASK_KSLRAW 0xfe00707f +#define MATCH_KSLRAW_U 0x7e001077 +#define MASK_KSLRAW_U 0xfe00707f +#define MATCH_KSTAS16 0xc4002077 +#define MASK_KSTAS16 0xfe00707f +#define MATCH_KSTAS32 0xc0002077 +#define MASK_KSTAS32 0xfe00707f +#define MATCH_KSTSA16 0xc6002077 +#define MASK_KSTSA16 0xfe00707f +#define MATCH_KSTSA32 0xc2002077 +#define MASK_KSTSA32 0xfe00707f +#define MATCH_KSUB16 0x12000077 +#define MASK_KSUB16 0xfe00707f +#define MATCH_KSUB32 0x12002077 +#define MASK_KSUB32 0xfe00707f +#define MATCH_KSUB64 0x92001077 +#define MASK_KSUB64 0xfe00707f +#define MATCH_KSUB8 0x1a000077 +#define MASK_KSUB8 0xfe00707f +#define MATCH_KSUBH 0x6001077 +#define MASK_KSUBH 0xfe00707f +#define MATCH_KSUBW 0x2001077 +#define MASK_KSUBW 0xfe00707f +#define MATCH_KWMMUL 0x62001077 +#define MASK_KWMMUL 0xfe00707f +#define MATCH_KWMMUL_U 0x72001077 +#define MASK_KWMMUL_U 0xfe00707f +#define MATCH_LB 0x3 +#define MASK_LB 0x707f +#define MATCH_LBU 0x4003 +#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 +#define MASK_LR_W 0xf9f0707f +#define MATCH_LUI 0x37 +#define MASK_LUI 0x7f +#define MATCH_LW 0x2003 +#define MASK_LW 0x707f +#define MATCH_LWU 0x6003 +#define MASK_LWU 0x707f +#define MATCH_MADDR32 0xc4001077 +#define MASK_MADDR32 0xfe00707f +#define MATCH_MAX 0xa006033 +#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 +#define MASK_MSUBR32 0xfe00707f +#define MATCH_MUL 0x2000033 +#define MASK_MUL 0xfe00707f +#define MATCH_MULH 0x2001033 +#define MASK_MULH 0xfe00707f +#define MATCH_MULHSU 0x2002033 +#define MASK_MULHSU 0xfe00707f +#define MATCH_MULHU 0x2003033 +#define MASK_MULHU 0xfe00707f +#define MATCH_MULR64 0xf0001077 +#define MASK_MULR64 0xfe00707f +#define MATCH_MULSR64 0xe0001077 +#define MASK_MULSR64 0xfe00707f +#define MATCH_MULW 0x200003b +#define MASK_MULW 0xfe00707f +#define MATCH_OR 0x6033 +#define MASK_OR 0xfe00707f +#define MATCH_ORI 0x6013 +#define MASK_ORI 0x707f +#define MATCH_ORN 0x40006033 +#define MASK_ORN 0xfe00707f +#define MATCH_PACK 0x8004033 +#define MASK_PACK 0xfe00707f +#define MATCH_PACKH 0x8007033 +#define MASK_PACKH 0xfe00707f +#define MATCH_PACKU 0x48004033 +#define MASK_PACKU 0xfe00707f +#define MATCH_PACKUW 0x4800403b +#define MASK_PACKUW 0xfe00707f +#define MATCH_PACKW 0x800403b +#define MASK_PACKW 0xfe00707f +#define MATCH_PAUSE 0x100000f +#define MASK_PAUSE 0xffffffff +#define MATCH_PBSAD 0xfc000077 +#define MASK_PBSAD 0xfe00707f +#define MATCH_PBSADA 0xfe000077 +#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 +#define MASK_PKBT32 0xfe00707f +#define MATCH_PKTB16 0x3e001077 +#define MASK_PKTB16 0xfe00707f +#define MATCH_PKTB32 0x3e002077 +#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 +#define MASK_PREFETCH_R 0x1f07fff +#define MATCH_PREFETCH_W 0x306013 +#define MASK_PREFETCH_W 0x1f07fff +#define MATCH_RADD16 0x77 +#define MASK_RADD16 0xfe00707f +#define MATCH_RADD32 0x2077 +#define MASK_RADD32 0xfe00707f +#define MATCH_RADD64 0x80001077 +#define MASK_RADD64 0xfe00707f +#define MATCH_RADD8 0x8000077 +#define MASK_RADD8 0xfe00707f +#define MATCH_RADDW 0x20001077 +#define MASK_RADDW 0xfe00707f +#define MATCH_RCRAS16 0x4000077 +#define MASK_RCRAS16 0xfe00707f +#define MATCH_RCRAS32 0x4002077 +#define MASK_RCRAS32 0xfe00707f +#define MATCH_RCRSA16 0x6000077 +#define MASK_RCRSA16 0xfe00707f +#define MATCH_RCRSA32 0x6002077 +#define MASK_RCRSA32 0xfe00707f +#define MATCH_REM 0x2006033 +#define MASK_REM 0xfe00707f +#define MATCH_REMU 0x2007033 +#define MASK_REMU 0xfe00707f +#define MATCH_REMUW 0x200703b +#define MASK_REMUW 0xfe00707f +#define MATCH_REMW 0x200603b +#define MASK_REMW 0xfe00707f +#define MATCH_ROL 0x60001033 +#define MASK_ROL 0xfe00707f +#define MATCH_ROLW 0x6000103b +#define MASK_ROLW 0xfe00707f +#define MATCH_ROR 0x60005033 +#define MASK_ROR 0xfe00707f +#define MATCH_RORI 0x60005013 +#define MASK_RORI 0xfc00707f +#define MATCH_RORIW 0x6000501b +#define MASK_RORIW 0xfe00707f +#define MATCH_RORW 0x6000503b +#define MASK_RORW 0xfe00707f +#define MATCH_RSTAS16 0xb4002077 +#define MASK_RSTAS16 0xfe00707f +#define MATCH_RSTAS32 0xb0002077 +#define MASK_RSTAS32 0xfe00707f +#define MATCH_RSTSA16 0xb6002077 +#define MASK_RSTSA16 0xfe00707f +#define MATCH_RSTSA32 0xb2002077 +#define MASK_RSTSA32 0xfe00707f +#define MATCH_RSUB16 0x2000077 +#define MASK_RSUB16 0xfe00707f +#define MATCH_RSUB32 0x2002077 +#define MASK_RSUB32 0xfe00707f +#define MATCH_RSUB64 0x82001077 +#define MASK_RSUB64 0xfe00707f +#define MATCH_RSUB8 0xa000077 +#define MASK_RSUB8 0xfe00707f +#define MATCH_RSUBW 0x22001077 +#define MASK_RSUBW 0xfe00707f +#define MATCH_SB 0x23 +#define MASK_SB 0x707f +#define MATCH_SC_D 0x1800302f +#define MASK_SC_D 0xf800707f +#define MATCH_SC_W 0x1800202f +#define MASK_SC_W 0xf800707f +#define MATCH_SCLIP16 0x84000077 +#define MASK_SCLIP16 0xff00707f +#define MATCH_SCLIP32 0xe4000077 +#define MASK_SCLIP32 0xfe00707f +#define MATCH_SCLIP8 0x8c000077 +#define MASK_SCLIP8 0xff80707f +#define MATCH_SCMPLE16 0x1c000077 +#define MASK_SCMPLE16 0xfe00707f +#define MATCH_SCMPLE8 0x1e000077 +#define MASK_SCMPLE8 0xfe00707f +#define MATCH_SCMPLT16 0xc000077 +#define MASK_SCMPLT16 0xfe00707f +#define MATCH_SCMPLT8 0xe000077 +#define MASK_SCMPLT8 0xfe00707f +#define MATCH_SD 0x3023 +#define MASK_SD 0x707f +#define MATCH_SEXT_B 0x60401013 +#define MASK_SEXT_B 0xfff0707f +#define MATCH_SEXT_H 0x60501013 +#define MASK_SEXT_H 0xfff0707f +#define MATCH_SFENCE_INVAL_IR 0x18100073 +#define MASK_SFENCE_INVAL_IR 0xffffffff +#define MATCH_SFENCE_VMA 0x12000073 +#define MASK_SFENCE_VMA 0xfe007fff +#define MATCH_SFENCE_W_INVAL 0x18000073 +#define MASK_SFENCE_W_INVAL 0xffffffff +#define MATCH_SH 0x1023 +#define MASK_SH 0x707f +#define MATCH_SH1ADD 0x20002033 +#define MASK_SH1ADD 0xfe00707f +#define MATCH_SH1ADD_UW 0x2000203b +#define MASK_SH1ADD_UW 0xfe00707f +#define MATCH_SH2ADD 0x20004033 +#define MASK_SH2ADD 0xfe00707f +#define MATCH_SH2ADD_UW 0x2000403b +#define MASK_SH2ADD_UW 0xfe00707f +#define MATCH_SH3ADD 0x20006033 +#define MASK_SH3ADD 0xfe00707f +#define MATCH_SH3ADD_UW 0x2000603b +#define MASK_SH3ADD_UW 0xfe00707f +#define MATCH_SHA256SIG0 0x10201013 +#define MASK_SHA256SIG0 0xfff0707f +#define MATCH_SHA256SIG1 0x10301013 +#define MASK_SHA256SIG1 0xfff0707f +#define MATCH_SHA256SUM0 0x10001013 +#define MASK_SHA256SUM0 0xfff0707f +#define MATCH_SHA256SUM1 0x10101013 +#define MASK_SHA256SUM1 0xfff0707f +#define MATCH_SHA512SIG0 0x10601013 +#define MASK_SHA512SIG0 0xfff0707f +#define MATCH_SHA512SIG0H 0x5c000033 +#define MASK_SHA512SIG0H 0xfe00707f +#define MATCH_SHA512SIG0L 0x54000033 +#define MASK_SHA512SIG0L 0xfe00707f +#define MATCH_SHA512SIG1 0x10701013 +#define MASK_SHA512SIG1 0xfff0707f +#define MATCH_SHA512SIG1H 0x5e000033 +#define MASK_SHA512SIG1H 0xfe00707f +#define MATCH_SHA512SIG1L 0x56000033 +#define MASK_SHA512SIG1L 0xfe00707f +#define MATCH_SHA512SUM0 0x10401013 +#define MASK_SHA512SUM0 0xfff0707f +#define MATCH_SHA512SUM0R 0x50000033 +#define MASK_SHA512SUM0R 0xfe00707f +#define MATCH_SHA512SUM1 0x10501013 +#define MASK_SHA512SUM1 0xfff0707f +#define MATCH_SHA512SUM1R 0x52000033 +#define MASK_SHA512SUM1R 0xfe00707f +#define MATCH_SHFL 0x8001033 +#define MASK_SHFL 0xfe00707f +#define MATCH_SHFLI 0x8001013 +#define MASK_SHFLI 0xfe00707f +#define MATCH_SHFLW 0x800103b +#define MASK_SHFLW 0xfe00707f +#define MATCH_SINVAL_VMA 0x16000073 +#define MASK_SINVAL_VMA 0xfe007fff +#define MATCH_SLL 0x1033 +#define MASK_SLL 0xfe00707f +#define MATCH_SLL16 0x54000077 +#define MASK_SLL16 0xfe00707f +#define MATCH_SLL32 0x54002077 +#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 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_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 +#define MASK_SLLW 0xfe00707f +#define MATCH_SLO 0x20001033 +#define MASK_SLO 0xfe00707f +#define MATCH_SLOI 0x20001013 +#define MASK_SLOI 0xfc00707f +#define MATCH_SLOIW 0x2000101b +#define MASK_SLOIW 0xfe00707f +#define MATCH_SLOW 0x2000103b +#define MASK_SLOW 0xfe00707f +#define MATCH_SLT 0x2033 +#define MASK_SLT 0xfe00707f +#define MATCH_SLTI 0x2013 +#define MASK_SLTI 0x707f +#define MATCH_SLTIU 0x3013 +#define MASK_SLTIU 0x707f +#define MATCH_SLTU 0x3033 +#define MASK_SLTU 0xfe00707f +#define MATCH_SM3P0 0x10801013 +#define MASK_SM3P0 0xfff0707f +#define MATCH_SM3P1 0x10901013 +#define MASK_SM3P1 0xfff0707f +#define MATCH_SM4ED 0x30000033 +#define MASK_SM4ED 0x3e00707f +#define MATCH_SM4KS 0x34000033 +#define MASK_SM4KS 0x3e00707f +#define MATCH_SMAL 0x5e001077 +#define MASK_SMAL 0xfe00707f +#define MATCH_SMALBB 0x88001077 +#define MASK_SMALBB 0xfe00707f +#define MATCH_SMALBT 0x98001077 +#define MASK_SMALBT 0xfe00707f +#define MATCH_SMALDA 0x8c001077 +#define MASK_SMALDA 0xfe00707f +#define MATCH_SMALDRS 0x9a001077 +#define MASK_SMALDRS 0xfe00707f +#define MATCH_SMALDS 0x8a001077 +#define MASK_SMALDS 0xfe00707f +#define MATCH_SMALTT 0xa8001077 +#define MASK_SMALTT 0xfe00707f +#define MATCH_SMALXDA 0x9c001077 +#define MASK_SMALXDA 0xfe00707f +#define MATCH_SMALXDS 0xaa001077 +#define MASK_SMALXDS 0xfe00707f +#define MATCH_SMAQA 0xc8000077 +#define MASK_SMAQA 0xfe00707f +#define MATCH_SMAQA_SU 0xca000077 +#define MASK_SMAQA_SU 0xfe00707f +#define MATCH_SMAR64 0x84001077 +#define MASK_SMAR64 0xfe00707f +#define MATCH_SMAX16 0x82000077 +#define MASK_SMAX16 0xfe00707f +#define MATCH_SMAX32 0x92002077 +#define MASK_SMAX32 0xfe00707f +#define MATCH_SMAX8 0x8a000077 +#define MASK_SMAX8 0xfe00707f +#define MATCH_SMBB16 0x8001077 +#define MASK_SMBB16 0xfe00707f +#define MATCH_SMBT16 0x18001077 +#define MASK_SMBT16 0xfe00707f +#define MATCH_SMBT32 0x18002077 +#define MASK_SMBT32 0xfe00707f +#define MATCH_SMDRS 0x68001077 +#define MASK_SMDRS 0xfe00707f +#define MATCH_SMDRS32 0x68002077 +#define MASK_SMDRS32 0xfe00707f +#define MATCH_SMDS 0x58001077 +#define MASK_SMDS 0xfe00707f +#define MATCH_SMDS32 0x58002077 +#define MASK_SMDS32 0xfe00707f +#define MATCH_SMIN16 0x80000077 +#define MASK_SMIN16 0xfe00707f +#define MATCH_SMIN32 0x90002077 +#define MASK_SMIN32 0xfe00707f +#define MATCH_SMIN8 0x88000077 +#define MASK_SMIN8 0xfe00707f +#define MATCH_SMMUL 0x40001077 +#define MASK_SMMUL 0xfe00707f +#define MATCH_SMMUL_U 0x50001077 +#define MASK_SMMUL_U 0xfe00707f +#define MATCH_SMMWB 0x44001077 +#define MASK_SMMWB 0xfe00707f +#define MATCH_SMMWB_U 0x54001077 +#define MASK_SMMWB_U 0xfe00707f +#define MATCH_SMMWT 0x64001077 +#define MASK_SMMWT 0xfe00707f +#define MATCH_SMMWT_U 0x74001077 +#define MASK_SMMWT_U 0xfe00707f +#define MATCH_SMSLDA 0xac001077 +#define MASK_SMSLDA 0xfe00707f +#define MATCH_SMSLXDA 0xbc001077 +#define MASK_SMSLXDA 0xfe00707f +#define MATCH_SMSR64 0x86001077 +#define MASK_SMSR64 0xfe00707f +#define MATCH_SMTT16 0x28001077 +#define MASK_SMTT16 0xfe00707f +#define MATCH_SMTT32 0x28002077 +#define MASK_SMTT32 0xfe00707f +#define MATCH_SMUL16 0xa0000077 +#define MASK_SMUL16 0xfe00707f +#define MATCH_SMUL8 0xa8000077 +#define MASK_SMUL8 0xfe00707f +#define MATCH_SMULX16 0xa2000077 +#define MASK_SMULX16 0xfe00707f +#define MATCH_SMULX8 0xaa000077 +#define MASK_SMULX8 0xfe00707f +#define MATCH_SMXDS 0x78001077 +#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 +#define MASK_SRA16 0xfe00707f +#define MATCH_SRA16_U 0x60000077 +#define MASK_SRA16_U 0xfe00707f +#define MATCH_SRA32 0x50002077 +#define MASK_SRA32 0xfe00707f +#define MATCH_SRA32_U 0x60002077 +#define MASK_SRA32_U 0xfe00707f +#define MATCH_SRA8 0x58000077 +#define MASK_SRA8 0xfe00707f +#define MATCH_SRA8_U 0x68000077 +#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 MATCH_SRAI16 0x70000077 +#define MASK_SRAI16 0xff00707f +#define MATCH_SRAI16_U 0x71000077 +#define MASK_SRAI16_U 0xff00707f +#define MATCH_SRAI32 0x70002077 +#define MASK_SRAI32 0xfe00707f +#define MATCH_SRAI32_U 0x80002077 +#define MASK_SRAI32_U 0xfe00707f +#define MATCH_SRAI8 0x78000077 +#define MASK_SRAI8 0xff80707f +#define MATCH_SRAI8_U 0x78800077 +#define MASK_SRAI8_U 0xff80707f +#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 +#define MASK_SRAIW_U 0xfe00707f +#define MATCH_SRAW 0x4000503b +#define MASK_SRAW 0xfe00707f +#define MATCH_SRET 0x10200073 +#define MASK_SRET 0xffffffff +#define MATCH_SRL 0x5033 +#define MASK_SRL 0xfe00707f +#define MATCH_SRL16 0x52000077 +#define MASK_SRL16 0xfe00707f +#define MATCH_SRL16_U 0x62000077 +#define MASK_SRL16_U 0xfe00707f +#define MATCH_SRL32 0x52002077 +#define MASK_SRL32 0xfe00707f +#define MATCH_SRL32_U 0x62002077 +#define MASK_SRL32_U 0xfe00707f +#define MATCH_SRL8 0x5a000077 +#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 MATCH_SRLI16 0x72000077 +#define MASK_SRLI16 0xff00707f +#define MATCH_SRLI16_U 0x73000077 +#define MASK_SRLI16_U 0xff00707f +#define MATCH_SRLI32 0x72002077 +#define MASK_SRLI32 0xfe00707f +#define MATCH_SRLI32_U 0x82002077 +#define MASK_SRLI32_U 0xfe00707f +#define MATCH_SRLI8 0x7a000077 +#define MASK_SRLI8 0xff80707f +#define MATCH_SRLI8_U 0x7a800077 +#define MASK_SRLI8_U 0xff80707f +#define MATCH_SRLID 0x505b +#define MASK_SRLID 0xfc00707f +#define MATCH_SRLIW 0x501b +#define MASK_SRLIW 0xfe00707f +#define MATCH_SRLW 0x503b +#define MASK_SRLW 0xfe00707f +#define MATCH_SRO 0x20005033 +#define MASK_SRO 0xfe00707f +#define MATCH_SROI 0x20005013 +#define MASK_SROI 0xfc00707f +#define MATCH_SROIW 0x2000501b +#define MASK_SROIW 0xfe00707f +#define MATCH_SROW 0x2000503b +#define MASK_SROW 0xfe00707f +#define MATCH_STAS16 0xf4002077 +#define MASK_STAS16 0xfe00707f +#define MATCH_STAS32 0xf0002077 +#define MASK_STAS32 0xfe00707f +#define MATCH_STSA16 0xf6002077 +#define MASK_STSA16 0xfe00707f +#define MATCH_STSA32 0xf2002077 +#define MASK_STSA32 0xfe00707f +#define MATCH_SUB 0x40000033 +#define MASK_SUB 0xfe00707f +#define MATCH_SUB16 0x42000077 +#define MASK_SUB16 0xfe00707f +#define MATCH_SUB32 0x42002077 +#define MASK_SUB32 0xfe00707f +#define MATCH_SUB64 0xc2001077 +#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 +#define MASK_SUNPKD810 0xfff0707f +#define MATCH_SUNPKD820 0xac900077 +#define MASK_SUNPKD820 0xfff0707f +#define MATCH_SUNPKD830 0xaca00077 +#define MASK_SUNPKD830 0xfff0707f +#define MATCH_SUNPKD831 0xacb00077 +#define MASK_SUNPKD831 0xfff0707f +#define MATCH_SUNPKD832 0xad300077 +#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 +#define MASK_UCLIP32 0xfe00707f +#define MATCH_UCLIP8 0x8d000077 +#define MASK_UCLIP8 0xff80707f +#define MATCH_UCMPLE16 0x3c000077 +#define MASK_UCMPLE16 0xfe00707f +#define MATCH_UCMPLE8 0x3e000077 +#define MASK_UCMPLE8 0xfe00707f +#define MATCH_UCMPLT16 0x2c000077 +#define MASK_UCMPLT16 0xfe00707f +#define MATCH_UCMPLT8 0x2e000077 +#define MASK_UCMPLT8 0xfe00707f +#define MATCH_UKADD16 0x30000077 +#define MASK_UKADD16 0xfe00707f +#define MATCH_UKADD32 0x30002077 +#define MASK_UKADD32 0xfe00707f +#define MATCH_UKADD64 0xb0001077 +#define MASK_UKADD64 0xfe00707f +#define MATCH_UKADD8 0x38000077 +#define MASK_UKADD8 0xfe00707f +#define MATCH_UKADDH 0x14001077 +#define MASK_UKADDH 0xfe00707f +#define MATCH_UKADDW 0x10001077 +#define MASK_UKADDW 0xfe00707f +#define MATCH_UKCRAS16 0x34000077 +#define MASK_UKCRAS16 0xfe00707f +#define MATCH_UKCRAS32 0x34002077 +#define MASK_UKCRAS32 0xfe00707f +#define MATCH_UKCRSA16 0x36000077 +#define MASK_UKCRSA16 0xfe00707f +#define MATCH_UKCRSA32 0x36002077 +#define MASK_UKCRSA32 0xfe00707f +#define MATCH_UKMAR64 0xb4001077 +#define MASK_UKMAR64 0xfe00707f +#define MATCH_UKMSR64 0xb6001077 +#define MASK_UKMSR64 0xfe00707f +#define MATCH_UKSTAS16 0xe4002077 +#define MASK_UKSTAS16 0xfe00707f +#define MATCH_UKSTAS32 0xe0002077 +#define MASK_UKSTAS32 0xfe00707f +#define MATCH_UKSTSA16 0xe6002077 +#define MASK_UKSTSA16 0xfe00707f +#define MATCH_UKSTSA32 0xe2002077 +#define MASK_UKSTSA32 0xfe00707f +#define MATCH_UKSUB16 0x32000077 +#define MASK_UKSUB16 0xfe00707f +#define MATCH_UKSUB32 0x32002077 +#define MASK_UKSUB32 0xfe00707f +#define MATCH_UKSUB64 0xb2001077 +#define MASK_UKSUB64 0xfe00707f +#define MATCH_UKSUB8 0x3a000077 +#define MASK_UKSUB8 0xfe00707f +#define MATCH_UKSUBH 0x16001077 +#define MASK_UKSUBH 0xfe00707f +#define MATCH_UKSUBW 0x12001077 +#define MASK_UKSUBW 0xfe00707f +#define MATCH_UMAQA 0xcc000077 +#define MASK_UMAQA 0xfe00707f +#define MATCH_UMAR64 0xa4001077 +#define MASK_UMAR64 0xfe00707f +#define MATCH_UMAX16 0x92000077 +#define MASK_UMAX16 0xfe00707f +#define MATCH_UMAX32 0xa2002077 +#define MASK_UMAX32 0xfe00707f +#define MATCH_UMAX8 0x9a000077 +#define MASK_UMAX8 0xfe00707f +#define MATCH_UMIN16 0x90000077 +#define MASK_UMIN16 0xfe00707f +#define MATCH_UMIN32 0xa0002077 +#define MASK_UMIN32 0xfe00707f +#define MATCH_UMIN8 0x98000077 +#define MASK_UMIN8 0xfe00707f +#define MATCH_UMSR64 0xa6001077 +#define MASK_UMSR64 0xfe00707f +#define MATCH_UMUL16 0xb0000077 +#define MASK_UMUL16 0xfe00707f +#define MATCH_UMUL8 0xb8000077 +#define MASK_UMUL8 0xfe00707f +#define MATCH_UMULX16 0xb2000077 +#define MASK_UMULX16 0xfe00707f +#define MATCH_UMULX8 0xba000077 +#define MASK_UMULX8 0xfe00707f +#define MATCH_UNSHFL 0x8005033 +#define MASK_UNSHFL 0xfe00707f +#define MATCH_UNSHFLI 0x8005013 +#define MASK_UNSHFLI 0xfe00707f +#define MATCH_UNSHFLW 0x800503b +#define MASK_UNSHFLW 0xfe00707f +#define MATCH_URADD16 0x20000077 +#define MASK_URADD16 0xfe00707f +#define MATCH_URADD32 0x20002077 +#define MASK_URADD32 0xfe00707f +#define MATCH_URADD64 0xa0001077 +#define MASK_URADD64 0xfe00707f +#define MATCH_URADD8 0x28000077 +#define MASK_URADD8 0xfe00707f +#define MATCH_URADDW 0x30001077 +#define MASK_URADDW 0xfe00707f +#define MATCH_URCRAS16 0x24000077 +#define MASK_URCRAS16 0xfe00707f +#define MATCH_URCRAS32 0x24002077 +#define MASK_URCRAS32 0xfe00707f +#define MATCH_URCRSA16 0x26000077 +#define MASK_URCRSA16 0xfe00707f +#define MATCH_URCRSA32 0x26002077 +#define MASK_URCRSA32 0xfe00707f +#define MATCH_URSTAS16 0xd4002077 +#define MASK_URSTAS16 0xfe00707f +#define MATCH_URSTAS32 0xd0002077 +#define MASK_URSTAS32 0xfe00707f +#define MATCH_URSTSA16 0xd6002077 +#define MASK_URSTSA16 0xfe00707f +#define MATCH_URSTSA32 0xd2002077 +#define MASK_URSTSA32 0xfe00707f +#define MATCH_URSUB16 0x22000077 +#define MASK_URSUB16 0xfe00707f +#define MATCH_URSUB32 0x22002077 +#define MASK_URSUB32 0xfe00707f +#define MATCH_URSUB64 0xa2001077 +#define MASK_URSUB64 0xfe00707f +#define MATCH_URSUB8 0x2a000077 +#define MASK_URSUB8 0xfe00707f +#define MATCH_URSUBW 0x32001077 +#define MASK_URSUBW 0xfe00707f +#define MATCH_VAADD_VV 0x24002057 +#define MASK_VAADD_VV 0xfc00707f +#define MATCH_VAADD_VX 0x24006057 +#define MASK_VAADD_VX 0xfc00707f +#define MATCH_VAADDU_VV 0x20002057 +#define MASK_VAADDU_VV 0xfc00707f +#define MATCH_VAADDU_VX 0x20006057 +#define MASK_VAADDU_VX 0xfc00707f +#define MATCH_VADC_VIM 0x40003057 +#define MASK_VADC_VIM 0xfe00707f +#define MATCH_VADC_VVM 0x40000057 +#define MASK_VADC_VVM 0xfe00707f +#define MATCH_VADC_VXM 0x40004057 +#define MASK_VADC_VXM 0xfe00707f +#define MATCH_VADD_VI 0x3057 +#define MASK_VADD_VI 0xfc00707f +#define MATCH_VADD_VV 0x57 +#define MASK_VADD_VV 0xfc00707f +#define MATCH_VADD_VX 0x4057 +#define MASK_VADD_VX 0xfc00707f +#define MATCH_VAMOADDEI16_V 0x502f +#define MASK_VAMOADDEI16_V 0xf800707f +#define MATCH_VAMOADDEI32_V 0x602f +#define MASK_VAMOADDEI32_V 0xf800707f +#define MATCH_VAMOADDEI64_V 0x702f +#define MASK_VAMOADDEI64_V 0xf800707f +#define MATCH_VAMOADDEI8_V 0x2f +#define MASK_VAMOADDEI8_V 0xf800707f +#define MATCH_VAMOANDEI16_V 0x6000502f +#define MASK_VAMOANDEI16_V 0xf800707f +#define MATCH_VAMOANDEI32_V 0x6000602f +#define MASK_VAMOANDEI32_V 0xf800707f +#define MATCH_VAMOANDEI64_V 0x6000702f +#define MASK_VAMOANDEI64_V 0xf800707f +#define MATCH_VAMOANDEI8_V 0x6000002f +#define MASK_VAMOANDEI8_V 0xf800707f +#define MATCH_VAMOMAXEI16_V 0xa000502f +#define MASK_VAMOMAXEI16_V 0xf800707f +#define MATCH_VAMOMAXEI32_V 0xa000602f +#define MASK_VAMOMAXEI32_V 0xf800707f +#define MATCH_VAMOMAXEI64_V 0xa000702f +#define MASK_VAMOMAXEI64_V 0xf800707f +#define MATCH_VAMOMAXEI8_V 0xa000002f +#define MASK_VAMOMAXEI8_V 0xf800707f +#define MATCH_VAMOMAXUEI16_V 0xe000502f +#define MASK_VAMOMAXUEI16_V 0xf800707f +#define MATCH_VAMOMAXUEI32_V 0xe000602f +#define MASK_VAMOMAXUEI32_V 0xf800707f +#define MATCH_VAMOMAXUEI64_V 0xe000702f +#define MASK_VAMOMAXUEI64_V 0xf800707f +#define MATCH_VAMOMAXUEI8_V 0xe000002f +#define MASK_VAMOMAXUEI8_V 0xf800707f +#define MATCH_VAMOMINEI16_V 0x8000502f +#define MASK_VAMOMINEI16_V 0xf800707f +#define MATCH_VAMOMINEI32_V 0x8000602f +#define MASK_VAMOMINEI32_V 0xf800707f +#define MATCH_VAMOMINEI64_V 0x8000702f +#define MASK_VAMOMINEI64_V 0xf800707f +#define MATCH_VAMOMINEI8_V 0x8000002f +#define MASK_VAMOMINEI8_V 0xf800707f +#define MATCH_VAMOMINUEI16_V 0xc000502f +#define MASK_VAMOMINUEI16_V 0xf800707f +#define MATCH_VAMOMINUEI32_V 0xc000602f +#define MASK_VAMOMINUEI32_V 0xf800707f +#define MATCH_VAMOMINUEI64_V 0xc000702f +#define MASK_VAMOMINUEI64_V 0xf800707f +#define MATCH_VAMOMINUEI8_V 0xc000002f +#define MASK_VAMOMINUEI8_V 0xf800707f +#define MATCH_VAMOOREI16_V 0x4000502f +#define MASK_VAMOOREI16_V 0xf800707f +#define MATCH_VAMOOREI32_V 0x4000602f +#define MASK_VAMOOREI32_V 0xf800707f +#define MATCH_VAMOOREI64_V 0x4000702f +#define MASK_VAMOOREI64_V 0xf800707f +#define MATCH_VAMOOREI8_V 0x4000002f +#define MASK_VAMOOREI8_V 0xf800707f +#define MATCH_VAMOSWAPEI16_V 0x800502f +#define MASK_VAMOSWAPEI16_V 0xf800707f +#define MATCH_VAMOSWAPEI32_V 0x800602f +#define MASK_VAMOSWAPEI32_V 0xf800707f +#define MATCH_VAMOSWAPEI64_V 0x800702f +#define MASK_VAMOSWAPEI64_V 0xf800707f +#define MATCH_VAMOSWAPEI8_V 0x800002f +#define MASK_VAMOSWAPEI8_V 0xf800707f +#define MATCH_VAMOXOREI16_V 0x2000502f +#define MASK_VAMOXOREI16_V 0xf800707f +#define MATCH_VAMOXOREI32_V 0x2000602f +#define MASK_VAMOXOREI32_V 0xf800707f +#define MATCH_VAMOXOREI64_V 0x2000702f +#define MASK_VAMOXOREI64_V 0xf800707f +#define MATCH_VAMOXOREI8_V 0x2000002f +#define MASK_VAMOXOREI8_V 0xf800707f +#define MATCH_VAND_VI 0x24003057 +#define MASK_VAND_VI 0xfc00707f +#define MATCH_VAND_VV 0x24000057 +#define MASK_VAND_VV 0xfc00707f +#define MATCH_VAND_VX 0x24004057 +#define MASK_VAND_VX 0xfc00707f +#define MATCH_VASUB_VV 0x2c002057 +#define MASK_VASUB_VV 0xfc00707f +#define MATCH_VASUB_VX 0x2c006057 +#define MASK_VASUB_VX 0xfc00707f +#define MATCH_VASUBU_VV 0x28002057 +#define MASK_VASUBU_VV 0xfc00707f +#define MATCH_VASUBU_VX 0x28006057 +#define MASK_VASUBU_VX 0xfc00707f +#define MATCH_VCOMPRESS_VM 0x5e002057 +#define MASK_VCOMPRESS_VM 0xfe00707f +#define MATCH_VCPOP_M 0x40082057 +#define MASK_VCPOP_M 0xfc0ff07f +#define MATCH_VDIV_VV 0x84002057 +#define MASK_VDIV_VV 0xfc00707f +#define MATCH_VDIV_VX 0x84006057 +#define MASK_VDIV_VX 0xfc00707f +#define MATCH_VDIVU_VV 0x80002057 +#define MASK_VDIVU_VV 0xfc00707f +#define MATCH_VDIVU_VX 0x80006057 +#define MASK_VDIVU_VX 0xfc00707f +#define MATCH_VFADD_VF 0x5057 +#define MASK_VFADD_VF 0xfc00707f +#define MATCH_VFADD_VV 0x1057 +#define MASK_VFADD_VV 0xfc00707f +#define MATCH_VFCLASS_V 0x4c081057 +#define MASK_VFCLASS_V 0xfc0ff07f +#define MATCH_VFCVT_F_X_V 0x48019057 +#define MASK_VFCVT_F_X_V 0xfc0ff07f +#define MATCH_VFCVT_F_XU_V 0x48011057 +#define MASK_VFCVT_F_XU_V 0xfc0ff07f +#define MATCH_VFCVT_RTZ_X_F_V 0x48039057 +#define MASK_VFCVT_RTZ_X_F_V 0xfc0ff07f +#define MATCH_VFCVT_RTZ_XU_F_V 0x48031057 +#define MASK_VFCVT_RTZ_XU_F_V 0xfc0ff07f +#define MATCH_VFCVT_X_F_V 0x48009057 +#define MASK_VFCVT_X_F_V 0xfc0ff07f +#define MATCH_VFCVT_XU_F_V 0x48001057 +#define MASK_VFCVT_XU_F_V 0xfc0ff07f +#define MATCH_VFDIV_VF 0x80005057 +#define MASK_VFDIV_VF 0xfc00707f +#define MATCH_VFDIV_VV 0x80001057 +#define MASK_VFDIV_VV 0xfc00707f +#define MATCH_VFIRST_M 0x4008a057 +#define MASK_VFIRST_M 0xfc0ff07f +#define MATCH_VFMACC_VF 0xb0005057 +#define MASK_VFMACC_VF 0xfc00707f +#define MATCH_VFMACC_VV 0xb0001057 +#define MASK_VFMACC_VV 0xfc00707f +#define MATCH_VFMADD_VF 0xa0005057 +#define MASK_VFMADD_VF 0xfc00707f +#define MATCH_VFMADD_VV 0xa0001057 +#define MASK_VFMADD_VV 0xfc00707f +#define MATCH_VFMAX_VF 0x18005057 +#define MASK_VFMAX_VF 0xfc00707f +#define MATCH_VFMAX_VV 0x18001057 +#define MASK_VFMAX_VV 0xfc00707f +#define MATCH_VFMERGE_VFM 0x5c005057 +#define MASK_VFMERGE_VFM 0xfe00707f +#define MATCH_VFMIN_VF 0x10005057 +#define MASK_VFMIN_VF 0xfc00707f +#define MATCH_VFMIN_VV 0x10001057 +#define MASK_VFMIN_VV 0xfc00707f +#define MATCH_VFMSAC_VF 0xb8005057 +#define MASK_VFMSAC_VF 0xfc00707f +#define MATCH_VFMSAC_VV 0xb8001057 +#define MASK_VFMSAC_VV 0xfc00707f +#define MATCH_VFMSUB_VF 0xa8005057 +#define MASK_VFMSUB_VF 0xfc00707f +#define MATCH_VFMSUB_VV 0xa8001057 +#define MASK_VFMSUB_VV 0xfc00707f +#define MATCH_VFMUL_VF 0x90005057 +#define MASK_VFMUL_VF 0xfc00707f +#define MATCH_VFMUL_VV 0x90001057 +#define MASK_VFMUL_VV 0xfc00707f +#define MATCH_VFMV_F_S 0x42001057 +#define MASK_VFMV_F_S 0xfe0ff07f +#define MATCH_VFMV_S_F 0x42005057 +#define MASK_VFMV_S_F 0xfff0707f +#define MATCH_VFMV_V_F 0x5e005057 +#define MASK_VFMV_V_F 0xfff0707f +#define MATCH_VFNCVT_F_F_W 0x480a1057 +#define MASK_VFNCVT_F_F_W 0xfc0ff07f +#define MATCH_VFNCVT_F_X_W 0x48099057 +#define MASK_VFNCVT_F_X_W 0xfc0ff07f +#define MATCH_VFNCVT_F_XU_W 0x48091057 +#define MASK_VFNCVT_F_XU_W 0xfc0ff07f +#define MATCH_VFNCVT_ROD_F_F_W 0x480a9057 +#define MASK_VFNCVT_ROD_F_F_W 0xfc0ff07f +#define MATCH_VFNCVT_RTZ_X_F_W 0x480b9057 +#define MASK_VFNCVT_RTZ_X_F_W 0xfc0ff07f +#define MATCH_VFNCVT_RTZ_XU_F_W 0x480b1057 +#define MASK_VFNCVT_RTZ_XU_F_W 0xfc0ff07f +#define MATCH_VFNCVT_X_F_W 0x48089057 +#define MASK_VFNCVT_X_F_W 0xfc0ff07f +#define MATCH_VFNCVT_XU_F_W 0x48081057 +#define MASK_VFNCVT_XU_F_W 0xfc0ff07f +#define MATCH_VFNMACC_VF 0xb4005057 +#define MASK_VFNMACC_VF 0xfc00707f +#define MATCH_VFNMACC_VV 0xb4001057 +#define MASK_VFNMACC_VV 0xfc00707f +#define MATCH_VFNMADD_VF 0xa4005057 +#define MASK_VFNMADD_VF 0xfc00707f +#define MATCH_VFNMADD_VV 0xa4001057 +#define MASK_VFNMADD_VV 0xfc00707f +#define MATCH_VFNMSAC_VF 0xbc005057 +#define MASK_VFNMSAC_VF 0xfc00707f +#define MATCH_VFNMSAC_VV 0xbc001057 +#define MASK_VFNMSAC_VV 0xfc00707f +#define MATCH_VFNMSUB_VF 0xac005057 +#define MASK_VFNMSUB_VF 0xfc00707f +#define MATCH_VFNMSUB_VV 0xac001057 +#define MASK_VFNMSUB_VV 0xfc00707f +#define MATCH_VFRDIV_VF 0x84005057 +#define MASK_VFRDIV_VF 0xfc00707f +#define MATCH_VFREC7_V 0x4c029057 +#define MASK_VFREC7_V 0xfc0ff07f +#define MATCH_VFREDMAX_VS 0x1c001057 +#define MASK_VFREDMAX_VS 0xfc00707f +#define MATCH_VFREDMIN_VS 0x14001057 +#define MASK_VFREDMIN_VS 0xfc00707f +#define MATCH_VFREDOSUM_VS 0xc001057 +#define MASK_VFREDOSUM_VS 0xfc00707f +#define MATCH_VFREDUSUM_VS 0x4001057 +#define MASK_VFREDUSUM_VS 0xfc00707f +#define MATCH_VFRSQRT7_V 0x4c021057 +#define MASK_VFRSQRT7_V 0xfc0ff07f +#define MATCH_VFRSUB_VF 0x9c005057 +#define MASK_VFRSUB_VF 0xfc00707f +#define MATCH_VFSGNJ_VF 0x20005057 +#define MASK_VFSGNJ_VF 0xfc00707f +#define MATCH_VFSGNJ_VV 0x20001057 +#define MASK_VFSGNJ_VV 0xfc00707f +#define MATCH_VFSGNJN_VF 0x24005057 +#define MASK_VFSGNJN_VF 0xfc00707f +#define MATCH_VFSGNJN_VV 0x24001057 +#define MASK_VFSGNJN_VV 0xfc00707f +#define MATCH_VFSGNJX_VF 0x28005057 +#define MASK_VFSGNJX_VF 0xfc00707f +#define MATCH_VFSGNJX_VV 0x28001057 +#define MASK_VFSGNJX_VV 0xfc00707f +#define MATCH_VFSLIDE1DOWN_VF 0x3c005057 +#define MASK_VFSLIDE1DOWN_VF 0xfc00707f +#define MATCH_VFSLIDE1UP_VF 0x38005057 +#define MASK_VFSLIDE1UP_VF 0xfc00707f +#define MATCH_VFSQRT_V 0x4c001057 +#define MASK_VFSQRT_V 0xfc0ff07f +#define MATCH_VFSUB_VF 0x8005057 +#define MASK_VFSUB_VF 0xfc00707f +#define MATCH_VFSUB_VV 0x8001057 +#define MASK_VFSUB_VV 0xfc00707f +#define MATCH_VFWADD_VF 0xc0005057 +#define MASK_VFWADD_VF 0xfc00707f +#define MATCH_VFWADD_VV 0xc0001057 +#define MASK_VFWADD_VV 0xfc00707f +#define MATCH_VFWADD_WF 0xd0005057 +#define MASK_VFWADD_WF 0xfc00707f +#define MATCH_VFWADD_WV 0xd0001057 +#define MASK_VFWADD_WV 0xfc00707f +#define MATCH_VFWCVT_F_F_V 0x48061057 +#define MASK_VFWCVT_F_F_V 0xfc0ff07f +#define MATCH_VFWCVT_F_X_V 0x48059057 +#define MASK_VFWCVT_F_X_V 0xfc0ff07f +#define MATCH_VFWCVT_F_XU_V 0x48051057 +#define MASK_VFWCVT_F_XU_V 0xfc0ff07f +#define MATCH_VFWCVT_RTZ_X_F_V 0x48079057 +#define MASK_VFWCVT_RTZ_X_F_V 0xfc0ff07f +#define MATCH_VFWCVT_RTZ_XU_F_V 0x48071057 +#define MASK_VFWCVT_RTZ_XU_F_V 0xfc0ff07f +#define MATCH_VFWCVT_X_F_V 0x48049057 +#define MASK_VFWCVT_X_F_V 0xfc0ff07f +#define MATCH_VFWCVT_XU_F_V 0x48041057 +#define MASK_VFWCVT_XU_F_V 0xfc0ff07f +#define MATCH_VFWMACC_VF 0xf0005057 +#define MASK_VFWMACC_VF 0xfc00707f +#define MATCH_VFWMACC_VV 0xf0001057 +#define MASK_VFWMACC_VV 0xfc00707f +#define MATCH_VFWMSAC_VF 0xf8005057 +#define MASK_VFWMSAC_VF 0xfc00707f +#define MATCH_VFWMSAC_VV 0xf8001057 +#define MASK_VFWMSAC_VV 0xfc00707f +#define MATCH_VFWMUL_VF 0xe0005057 +#define MASK_VFWMUL_VF 0xfc00707f +#define MATCH_VFWMUL_VV 0xe0001057 +#define MASK_VFWMUL_VV 0xfc00707f +#define MATCH_VFWNMACC_VF 0xf4005057 +#define MASK_VFWNMACC_VF 0xfc00707f +#define MATCH_VFWNMACC_VV 0xf4001057 +#define MASK_VFWNMACC_VV 0xfc00707f +#define MATCH_VFWNMSAC_VF 0xfc005057 +#define MASK_VFWNMSAC_VF 0xfc00707f +#define MATCH_VFWNMSAC_VV 0xfc001057 +#define MASK_VFWNMSAC_VV 0xfc00707f +#define MATCH_VFWREDOSUM_VS 0xcc001057 +#define MASK_VFWREDOSUM_VS 0xfc00707f +#define MATCH_VFWREDUSUM_VS 0xc4001057 +#define MASK_VFWREDUSUM_VS 0xfc00707f +#define MATCH_VFWSUB_VF 0xc8005057 +#define MASK_VFWSUB_VF 0xfc00707f +#define MATCH_VFWSUB_VV 0xc8001057 +#define MASK_VFWSUB_VV 0xfc00707f +#define MATCH_VFWSUB_WF 0xd8005057 +#define MASK_VFWSUB_WF 0xfc00707f +#define MATCH_VFWSUB_WV 0xd8001057 +#define MASK_VFWSUB_WV 0xfc00707f +#define MATCH_VID_V 0x5008a057 +#define MASK_VID_V 0xfdfff07f +#define MATCH_VIOTA_M 0x50082057 +#define MASK_VIOTA_M 0xfc0ff07f +#define MATCH_VL1RE16_V 0x2805007 +#define MASK_VL1RE16_V 0xfff0707f +#define MATCH_VL1RE32_V 0x2806007 +#define MASK_VL1RE32_V 0xfff0707f +#define MATCH_VL1RE64_V 0x2807007 +#define MASK_VL1RE64_V 0xfff0707f +#define MATCH_VL1RE8_V 0x2800007 +#define MASK_VL1RE8_V 0xfff0707f +#define MATCH_VL2RE16_V 0x22805007 +#define MASK_VL2RE16_V 0xfff0707f +#define MATCH_VL2RE32_V 0x22806007 +#define MASK_VL2RE32_V 0xfff0707f +#define MATCH_VL2RE64_V 0x22807007 +#define MASK_VL2RE64_V 0xfff0707f +#define MATCH_VL2RE8_V 0x22800007 +#define MASK_VL2RE8_V 0xfff0707f +#define MATCH_VL4RE16_V 0x62805007 +#define MASK_VL4RE16_V 0xfff0707f +#define MATCH_VL4RE32_V 0x62806007 +#define MASK_VL4RE32_V 0xfff0707f +#define MATCH_VL4RE64_V 0x62807007 +#define MASK_VL4RE64_V 0xfff0707f +#define MATCH_VL4RE8_V 0x62800007 +#define MASK_VL4RE8_V 0xfff0707f +#define MATCH_VL8RE16_V 0xe2805007 +#define MASK_VL8RE16_V 0xfff0707f +#define MATCH_VL8RE32_V 0xe2806007 +#define MASK_VL8RE32_V 0xfff0707f +#define MATCH_VL8RE64_V 0xe2807007 +#define MASK_VL8RE64_V 0xfff0707f +#define MATCH_VL8RE8_V 0xe2800007 +#define MASK_VL8RE8_V 0xfff0707f +#define MATCH_VLE1024_V 0x10007007 +#define MASK_VLE1024_V 0x1df0707f +#define MATCH_VLE1024FF_V 0x11007007 +#define MASK_VLE1024FF_V 0x1df0707f +#define MATCH_VLE128_V 0x10000007 +#define MASK_VLE128_V 0x1df0707f +#define MATCH_VLE128FF_V 0x11000007 +#define MASK_VLE128FF_V 0x1df0707f +#define MATCH_VLE16_V 0x5007 +#define MASK_VLE16_V 0x1df0707f +#define MATCH_VLE16FF_V 0x1005007 +#define MASK_VLE16FF_V 0x1df0707f +#define MATCH_VLE256_V 0x10005007 +#define MASK_VLE256_V 0x1df0707f +#define MATCH_VLE256FF_V 0x11005007 +#define MASK_VLE256FF_V 0x1df0707f +#define MATCH_VLE32_V 0x6007 +#define MASK_VLE32_V 0x1df0707f +#define MATCH_VLE32FF_V 0x1006007 +#define MASK_VLE32FF_V 0x1df0707f +#define MATCH_VLE512_V 0x10006007 +#define MASK_VLE512_V 0x1df0707f +#define MATCH_VLE512FF_V 0x11006007 +#define MASK_VLE512FF_V 0x1df0707f +#define MATCH_VLE64_V 0x7007 +#define MASK_VLE64_V 0x1df0707f +#define MATCH_VLE64FF_V 0x1007007 +#define MASK_VLE64FF_V 0x1df0707f +#define MATCH_VLE8_V 0x7 +#define MASK_VLE8_V 0x1df0707f +#define MATCH_VLE8FF_V 0x1000007 +#define MASK_VLE8FF_V 0x1df0707f +#define MATCH_VLM_V 0x2b00007 +#define MASK_VLM_V 0xfff0707f +#define MATCH_VLOXEI1024_V 0x1c007007 +#define MASK_VLOXEI1024_V 0x1c00707f +#define MATCH_VLOXEI128_V 0x1c000007 +#define MASK_VLOXEI128_V 0x1c00707f +#define MATCH_VLOXEI16_V 0xc005007 +#define MASK_VLOXEI16_V 0x1c00707f +#define MATCH_VLOXEI256_V 0x1c005007 +#define MASK_VLOXEI256_V 0x1c00707f +#define MATCH_VLOXEI32_V 0xc006007 +#define MASK_VLOXEI32_V 0x1c00707f +#define MATCH_VLOXEI512_V 0x1c006007 +#define MASK_VLOXEI512_V 0x1c00707f +#define MATCH_VLOXEI64_V 0xc007007 +#define MASK_VLOXEI64_V 0x1c00707f +#define MATCH_VLOXEI8_V 0xc000007 +#define MASK_VLOXEI8_V 0x1c00707f +#define MATCH_VLSE1024_V 0x18007007 +#define MASK_VLSE1024_V 0x1c00707f +#define MATCH_VLSE128_V 0x18000007 +#define MASK_VLSE128_V 0x1c00707f +#define MATCH_VLSE16_V 0x8005007 +#define MASK_VLSE16_V 0x1c00707f +#define MATCH_VLSE256_V 0x18005007 +#define MASK_VLSE256_V 0x1c00707f +#define MATCH_VLSE32_V 0x8006007 +#define MASK_VLSE32_V 0x1c00707f +#define MATCH_VLSE512_V 0x18006007 +#define MASK_VLSE512_V 0x1c00707f +#define MATCH_VLSE64_V 0x8007007 +#define MASK_VLSE64_V 0x1c00707f +#define MATCH_VLSE8_V 0x8000007 +#define MASK_VLSE8_V 0x1c00707f +#define MATCH_VLUXEI1024_V 0x14007007 +#define MASK_VLUXEI1024_V 0x1c00707f +#define MATCH_VLUXEI128_V 0x14000007 +#define MASK_VLUXEI128_V 0x1c00707f +#define MATCH_VLUXEI16_V 0x4005007 +#define MASK_VLUXEI16_V 0x1c00707f +#define MATCH_VLUXEI256_V 0x14005007 +#define MASK_VLUXEI256_V 0x1c00707f +#define MATCH_VLUXEI32_V 0x4006007 +#define MASK_VLUXEI32_V 0x1c00707f +#define MATCH_VLUXEI512_V 0x14006007 +#define MASK_VLUXEI512_V 0x1c00707f +#define MATCH_VLUXEI64_V 0x4007007 +#define MASK_VLUXEI64_V 0x1c00707f +#define MATCH_VLUXEI8_V 0x4000007 +#define MASK_VLUXEI8_V 0x1c00707f +#define MATCH_VMACC_VV 0xb4002057 +#define MASK_VMACC_VV 0xfc00707f +#define MATCH_VMACC_VX 0xb4006057 +#define MASK_VMACC_VX 0xfc00707f +#define MATCH_VMADC_VI 0x46003057 +#define MASK_VMADC_VI 0xfe00707f +#define MATCH_VMADC_VIM 0x44003057 +#define MASK_VMADC_VIM 0xfe00707f +#define MATCH_VMADC_VV 0x46000057 +#define MASK_VMADC_VV 0xfe00707f +#define MATCH_VMADC_VVM 0x44000057 +#define MASK_VMADC_VVM 0xfe00707f +#define MATCH_VMADC_VX 0x46004057 +#define MASK_VMADC_VX 0xfe00707f +#define MATCH_VMADC_VXM 0x44004057 +#define MASK_VMADC_VXM 0xfe00707f +#define MATCH_VMADD_VV 0xa4002057 +#define MASK_VMADD_VV 0xfc00707f +#define MATCH_VMADD_VX 0xa4006057 +#define MASK_VMADD_VX 0xfc00707f +#define MATCH_VMAND_MM 0x64002057 +#define MASK_VMAND_MM 0xfc00707f +#define MATCH_VMANDN_MM 0x60002057 +#define MASK_VMANDN_MM 0xfc00707f +#define MATCH_VMAX_VV 0x1c000057 +#define MASK_VMAX_VV 0xfc00707f +#define MATCH_VMAX_VX 0x1c004057 +#define MASK_VMAX_VX 0xfc00707f +#define MATCH_VMAXU_VV 0x18000057 +#define MASK_VMAXU_VV 0xfc00707f +#define MATCH_VMAXU_VX 0x18004057 +#define MASK_VMAXU_VX 0xfc00707f +#define MATCH_VMERGE_VIM 0x5c003057 +#define MASK_VMERGE_VIM 0xfe00707f +#define MATCH_VMERGE_VVM 0x5c000057 +#define MASK_VMERGE_VVM 0xfe00707f +#define MATCH_VMERGE_VXM 0x5c004057 +#define MASK_VMERGE_VXM 0xfe00707f +#define MATCH_VMFEQ_VF 0x60005057 +#define MASK_VMFEQ_VF 0xfc00707f +#define MATCH_VMFEQ_VV 0x60001057 +#define MASK_VMFEQ_VV 0xfc00707f +#define MATCH_VMFGE_VF 0x7c005057 +#define MASK_VMFGE_VF 0xfc00707f +#define MATCH_VMFGT_VF 0x74005057 +#define MASK_VMFGT_VF 0xfc00707f +#define MATCH_VMFLE_VF 0x64005057 +#define MASK_VMFLE_VF 0xfc00707f +#define MATCH_VMFLE_VV 0x64001057 +#define MASK_VMFLE_VV 0xfc00707f +#define MATCH_VMFLT_VF 0x6c005057 +#define MASK_VMFLT_VF 0xfc00707f +#define MATCH_VMFLT_VV 0x6c001057 +#define MASK_VMFLT_VV 0xfc00707f +#define MATCH_VMFNE_VF 0x70005057 +#define MASK_VMFNE_VF 0xfc00707f +#define MATCH_VMFNE_VV 0x70001057 +#define MASK_VMFNE_VV 0xfc00707f +#define MATCH_VMIN_VV 0x14000057 +#define MASK_VMIN_VV 0xfc00707f +#define MATCH_VMIN_VX 0x14004057 +#define MASK_VMIN_VX 0xfc00707f +#define MATCH_VMINU_VV 0x10000057 +#define MASK_VMINU_VV 0xfc00707f +#define MATCH_VMINU_VX 0x10004057 +#define MASK_VMINU_VX 0xfc00707f +#define MATCH_VMNAND_MM 0x74002057 +#define MASK_VMNAND_MM 0xfc00707f +#define MATCH_VMNOR_MM 0x78002057 +#define MASK_VMNOR_MM 0xfc00707f +#define MATCH_VMOR_MM 0x68002057 +#define MASK_VMOR_MM 0xfc00707f +#define MATCH_VMORN_MM 0x70002057 +#define MASK_VMORN_MM 0xfc00707f +#define MATCH_VMSBC_VV 0x4e000057 +#define MASK_VMSBC_VV 0xfe00707f +#define MATCH_VMSBC_VVM 0x4c000057 +#define MASK_VMSBC_VVM 0xfe00707f +#define MATCH_VMSBC_VX 0x4e004057 +#define MASK_VMSBC_VX 0xfe00707f +#define MATCH_VMSBC_VXM 0x4c004057 +#define MASK_VMSBC_VXM 0xfe00707f +#define MATCH_VMSBF_M 0x5000a057 +#define MASK_VMSBF_M 0xfc0ff07f +#define MATCH_VMSEQ_VI 0x60003057 +#define MASK_VMSEQ_VI 0xfc00707f +#define MATCH_VMSEQ_VV 0x60000057 +#define MASK_VMSEQ_VV 0xfc00707f +#define MATCH_VMSEQ_VX 0x60004057 +#define MASK_VMSEQ_VX 0xfc00707f +#define MATCH_VMSGT_VI 0x7c003057 +#define MASK_VMSGT_VI 0xfc00707f +#define MATCH_VMSGT_VX 0x7c004057 +#define MASK_VMSGT_VX 0xfc00707f +#define MATCH_VMSGTU_VI 0x78003057 +#define MASK_VMSGTU_VI 0xfc00707f +#define MATCH_VMSGTU_VX 0x78004057 +#define MASK_VMSGTU_VX 0xfc00707f +#define MATCH_VMSIF_M 0x5001a057 +#define MASK_VMSIF_M 0xfc0ff07f +#define MATCH_VMSLE_VI 0x74003057 +#define MASK_VMSLE_VI 0xfc00707f +#define MATCH_VMSLE_VV 0x74000057 +#define MASK_VMSLE_VV 0xfc00707f +#define MATCH_VMSLE_VX 0x74004057 +#define MASK_VMSLE_VX 0xfc00707f +#define MATCH_VMSLEU_VI 0x70003057 +#define MASK_VMSLEU_VI 0xfc00707f +#define MATCH_VMSLEU_VV 0x70000057 +#define MASK_VMSLEU_VV 0xfc00707f +#define MATCH_VMSLEU_VX 0x70004057 +#define MASK_VMSLEU_VX 0xfc00707f +#define MATCH_VMSLT_VV 0x6c000057 +#define MASK_VMSLT_VV 0xfc00707f +#define MATCH_VMSLT_VX 0x6c004057 +#define MASK_VMSLT_VX 0xfc00707f +#define MATCH_VMSLTU_VV 0x68000057 +#define MASK_VMSLTU_VV 0xfc00707f +#define MATCH_VMSLTU_VX 0x68004057 +#define MASK_VMSLTU_VX 0xfc00707f +#define MATCH_VMSNE_VI 0x64003057 +#define MASK_VMSNE_VI 0xfc00707f +#define MATCH_VMSNE_VV 0x64000057 +#define MASK_VMSNE_VV 0xfc00707f +#define MATCH_VMSNE_VX 0x64004057 +#define MASK_VMSNE_VX 0xfc00707f +#define MATCH_VMSOF_M 0x50012057 +#define MASK_VMSOF_M 0xfc0ff07f +#define MATCH_VMUL_VV 0x94002057 +#define MASK_VMUL_VV 0xfc00707f +#define MATCH_VMUL_VX 0x94006057 +#define MASK_VMUL_VX 0xfc00707f +#define MATCH_VMULH_VV 0x9c002057 +#define MASK_VMULH_VV 0xfc00707f +#define MATCH_VMULH_VX 0x9c006057 +#define MASK_VMULH_VX 0xfc00707f +#define MATCH_VMULHSU_VV 0x98002057 +#define MASK_VMULHSU_VV 0xfc00707f +#define MATCH_VMULHSU_VX 0x98006057 +#define MASK_VMULHSU_VX 0xfc00707f +#define MATCH_VMULHU_VV 0x90002057 +#define MASK_VMULHU_VV 0xfc00707f +#define MATCH_VMULHU_VX 0x90006057 +#define MASK_VMULHU_VX 0xfc00707f +#define MATCH_VMV1R_V 0x9e003057 +#define MASK_VMV1R_V 0xfe0ff07f +#define MATCH_VMV2R_V 0x9e00b057 +#define MASK_VMV2R_V 0xfe0ff07f +#define MATCH_VMV4R_V 0x9e01b057 +#define MASK_VMV4R_V 0xfe0ff07f +#define MATCH_VMV8R_V 0x9e03b057 +#define MASK_VMV8R_V 0xfe0ff07f +#define MATCH_VMV_S_X 0x42006057 +#define MASK_VMV_S_X 0xfff0707f +#define MATCH_VMV_V_I 0x5e003057 +#define MASK_VMV_V_I 0xfff0707f +#define MATCH_VMV_V_V 0x5e000057 +#define MASK_VMV_V_V 0xfff0707f +#define MATCH_VMV_V_X 0x5e004057 +#define MASK_VMV_V_X 0xfff0707f +#define MATCH_VMV_X_S 0x42002057 +#define MASK_VMV_X_S 0xfe0ff07f +#define MATCH_VMXNOR_MM 0x7c002057 +#define MASK_VMXNOR_MM 0xfc00707f +#define MATCH_VMXOR_MM 0x6c002057 +#define MASK_VMXOR_MM 0xfc00707f +#define MATCH_VNCLIP_WI 0xbc003057 +#define MASK_VNCLIP_WI 0xfc00707f +#define MATCH_VNCLIP_WV 0xbc000057 +#define MASK_VNCLIP_WV 0xfc00707f +#define MATCH_VNCLIP_WX 0xbc004057 +#define MASK_VNCLIP_WX 0xfc00707f +#define MATCH_VNCLIPU_WI 0xb8003057 +#define MASK_VNCLIPU_WI 0xfc00707f +#define MATCH_VNCLIPU_WV 0xb8000057 +#define MASK_VNCLIPU_WV 0xfc00707f +#define MATCH_VNCLIPU_WX 0xb8004057 +#define MASK_VNCLIPU_WX 0xfc00707f +#define MATCH_VNMSAC_VV 0xbc002057 +#define MASK_VNMSAC_VV 0xfc00707f +#define MATCH_VNMSAC_VX 0xbc006057 +#define MASK_VNMSAC_VX 0xfc00707f +#define MATCH_VNMSUB_VV 0xac002057 +#define MASK_VNMSUB_VV 0xfc00707f +#define MATCH_VNMSUB_VX 0xac006057 +#define MASK_VNMSUB_VX 0xfc00707f +#define MATCH_VNSRA_WI 0xb4003057 +#define MASK_VNSRA_WI 0xfc00707f +#define MATCH_VNSRA_WV 0xb4000057 +#define MASK_VNSRA_WV 0xfc00707f +#define MATCH_VNSRA_WX 0xb4004057 +#define MASK_VNSRA_WX 0xfc00707f +#define MATCH_VNSRL_WI 0xb0003057 +#define MASK_VNSRL_WI 0xfc00707f +#define MATCH_VNSRL_WV 0xb0000057 +#define MASK_VNSRL_WV 0xfc00707f +#define MATCH_VNSRL_WX 0xb0004057 +#define MASK_VNSRL_WX 0xfc00707f +#define MATCH_VOR_VI 0x28003057 +#define MASK_VOR_VI 0xfc00707f +#define MATCH_VOR_VV 0x28000057 +#define MASK_VOR_VV 0xfc00707f +#define MATCH_VOR_VX 0x28004057 +#define MASK_VOR_VX 0xfc00707f +#define MATCH_VREDAND_VS 0x4002057 +#define MASK_VREDAND_VS 0xfc00707f +#define MATCH_VREDMAX_VS 0x1c002057 +#define MASK_VREDMAX_VS 0xfc00707f +#define MATCH_VREDMAXU_VS 0x18002057 +#define MASK_VREDMAXU_VS 0xfc00707f +#define MATCH_VREDMIN_VS 0x14002057 +#define MASK_VREDMIN_VS 0xfc00707f +#define MATCH_VREDMINU_VS 0x10002057 +#define MASK_VREDMINU_VS 0xfc00707f +#define MATCH_VREDOR_VS 0x8002057 +#define MASK_VREDOR_VS 0xfc00707f +#define MATCH_VREDSUM_VS 0x2057 +#define MASK_VREDSUM_VS 0xfc00707f +#define MATCH_VREDXOR_VS 0xc002057 +#define MASK_VREDXOR_VS 0xfc00707f +#define MATCH_VREM_VV 0x8c002057 +#define MASK_VREM_VV 0xfc00707f +#define MATCH_VREM_VX 0x8c006057 +#define MASK_VREM_VX 0xfc00707f +#define MATCH_VREMU_VV 0x88002057 +#define MASK_VREMU_VV 0xfc00707f +#define MATCH_VREMU_VX 0x88006057 +#define MASK_VREMU_VX 0xfc00707f +#define MATCH_VRGATHER_VI 0x30003057 +#define MASK_VRGATHER_VI 0xfc00707f +#define MATCH_VRGATHER_VV 0x30000057 +#define MASK_VRGATHER_VV 0xfc00707f +#define MATCH_VRGATHER_VX 0x30004057 +#define MASK_VRGATHER_VX 0xfc00707f +#define MATCH_VRGATHEREI16_VV 0x38000057 +#define MASK_VRGATHEREI16_VV 0xfc00707f +#define MATCH_VRSUB_VI 0xc003057 +#define MASK_VRSUB_VI 0xfc00707f +#define MATCH_VRSUB_VX 0xc004057 +#define MASK_VRSUB_VX 0xfc00707f +#define MATCH_VS1R_V 0x2800027 +#define MASK_VS1R_V 0xfff0707f +#define MATCH_VS2R_V 0x22800027 +#define MASK_VS2R_V 0xfff0707f +#define MATCH_VS4R_V 0x62800027 +#define MASK_VS4R_V 0xfff0707f +#define MATCH_VS8R_V 0xe2800027 +#define MASK_VS8R_V 0xfff0707f +#define MATCH_VSADD_VI 0x84003057 +#define MASK_VSADD_VI 0xfc00707f +#define MATCH_VSADD_VV 0x84000057 +#define MASK_VSADD_VV 0xfc00707f +#define MATCH_VSADD_VX 0x84004057 +#define MASK_VSADD_VX 0xfc00707f +#define MATCH_VSADDU_VI 0x80003057 +#define MASK_VSADDU_VI 0xfc00707f +#define MATCH_VSADDU_VV 0x80000057 +#define MASK_VSADDU_VV 0xfc00707f +#define MATCH_VSADDU_VX 0x80004057 +#define MASK_VSADDU_VX 0xfc00707f +#define MATCH_VSBC_VVM 0x48000057 +#define MASK_VSBC_VVM 0xfe00707f +#define MATCH_VSBC_VXM 0x48004057 +#define MASK_VSBC_VXM 0xfe00707f +#define MATCH_VSE1024_V 0x10007027 +#define MASK_VSE1024_V 0x1df0707f +#define MATCH_VSE128_V 0x10000027 +#define MASK_VSE128_V 0x1df0707f +#define MATCH_VSE16_V 0x5027 +#define MASK_VSE16_V 0x1df0707f +#define MATCH_VSE256_V 0x10005027 +#define MASK_VSE256_V 0x1df0707f +#define MATCH_VSE32_V 0x6027 +#define MASK_VSE32_V 0x1df0707f +#define MATCH_VSE512_V 0x10006027 +#define MASK_VSE512_V 0x1df0707f +#define MATCH_VSE64_V 0x7027 +#define MASK_VSE64_V 0x1df0707f +#define MATCH_VSE8_V 0x27 +#define MASK_VSE8_V 0x1df0707f +#define MATCH_VSETIVLI 0xc0007057 +#define MASK_VSETIVLI 0xc000707f +#define MATCH_VSETVL 0x80007057 +#define MASK_VSETVL 0xfe00707f +#define MATCH_VSETVLI 0x7057 +#define MASK_VSETVLI 0x8000707f +#define MATCH_VSEXT_VF2 0x4803a057 +#define MASK_VSEXT_VF2 0xfc0ff07f +#define MATCH_VSEXT_VF4 0x4802a057 +#define MASK_VSEXT_VF4 0xfc0ff07f +#define MATCH_VSEXT_VF8 0x4801a057 +#define MASK_VSEXT_VF8 0xfc0ff07f +#define MATCH_VSLIDE1DOWN_VX 0x3c006057 +#define MASK_VSLIDE1DOWN_VX 0xfc00707f +#define MATCH_VSLIDE1UP_VX 0x38006057 +#define MASK_VSLIDE1UP_VX 0xfc00707f +#define MATCH_VSLIDEDOWN_VI 0x3c003057 +#define MASK_VSLIDEDOWN_VI 0xfc00707f +#define MATCH_VSLIDEDOWN_VX 0x3c004057 +#define MASK_VSLIDEDOWN_VX 0xfc00707f +#define MATCH_VSLIDEUP_VI 0x38003057 +#define MASK_VSLIDEUP_VI 0xfc00707f +#define MATCH_VSLIDEUP_VX 0x38004057 +#define MASK_VSLIDEUP_VX 0xfc00707f +#define MATCH_VSLL_VI 0x94003057 +#define MASK_VSLL_VI 0xfc00707f +#define MATCH_VSLL_VV 0x94000057 +#define MASK_VSLL_VV 0xfc00707f +#define MATCH_VSLL_VX 0x94004057 +#define MASK_VSLL_VX 0xfc00707f +#define MATCH_VSM_V 0x2b00027 +#define MASK_VSM_V 0xfff0707f +#define MATCH_VSMUL_VV 0x9c000057 +#define MASK_VSMUL_VV 0xfc00707f +#define MATCH_VSMUL_VX 0x9c004057 +#define MASK_VSMUL_VX 0xfc00707f +#define MATCH_VSOXEI1024_V 0x1c007027 +#define MASK_VSOXEI1024_V 0x1c00707f +#define MATCH_VSOXEI128_V 0x1c000027 +#define MASK_VSOXEI128_V 0x1c00707f +#define MATCH_VSOXEI16_V 0xc005027 +#define MASK_VSOXEI16_V 0x1c00707f +#define MATCH_VSOXEI256_V 0x1c005027 +#define MASK_VSOXEI256_V 0x1c00707f +#define MATCH_VSOXEI32_V 0xc006027 +#define MASK_VSOXEI32_V 0x1c00707f +#define MATCH_VSOXEI512_V 0x1c006027 +#define MASK_VSOXEI512_V 0x1c00707f +#define MATCH_VSOXEI64_V 0xc007027 +#define MASK_VSOXEI64_V 0x1c00707f +#define MATCH_VSOXEI8_V 0xc000027 +#define MASK_VSOXEI8_V 0x1c00707f +#define MATCH_VSRA_VI 0xa4003057 +#define MASK_VSRA_VI 0xfc00707f +#define MATCH_VSRA_VV 0xa4000057 +#define MASK_VSRA_VV 0xfc00707f +#define MATCH_VSRA_VX 0xa4004057 +#define MASK_VSRA_VX 0xfc00707f +#define MATCH_VSRL_VI 0xa0003057 +#define MASK_VSRL_VI 0xfc00707f +#define MATCH_VSRL_VV 0xa0000057 +#define MASK_VSRL_VV 0xfc00707f +#define MATCH_VSRL_VX 0xa0004057 +#define MASK_VSRL_VX 0xfc00707f +#define MATCH_VSSE1024_V 0x18007027 +#define MASK_VSSE1024_V 0x1c00707f +#define MATCH_VSSE128_V 0x18000027 +#define MASK_VSSE128_V 0x1c00707f +#define MATCH_VSSE16_V 0x8005027 +#define MASK_VSSE16_V 0x1c00707f +#define MATCH_VSSE256_V 0x18005027 +#define MASK_VSSE256_V 0x1c00707f +#define MATCH_VSSE32_V 0x8006027 +#define MASK_VSSE32_V 0x1c00707f +#define MATCH_VSSE512_V 0x18006027 +#define MASK_VSSE512_V 0x1c00707f +#define MATCH_VSSE64_V 0x8007027 +#define MASK_VSSE64_V 0x1c00707f +#define MATCH_VSSE8_V 0x8000027 +#define MASK_VSSE8_V 0x1c00707f +#define MATCH_VSSRA_VI 0xac003057 +#define MASK_VSSRA_VI 0xfc00707f +#define MATCH_VSSRA_VV 0xac000057 +#define MASK_VSSRA_VV 0xfc00707f +#define MATCH_VSSRA_VX 0xac004057 +#define MASK_VSSRA_VX 0xfc00707f +#define MATCH_VSSRL_VI 0xa8003057 +#define MASK_VSSRL_VI 0xfc00707f +#define MATCH_VSSRL_VV 0xa8000057 +#define MASK_VSSRL_VV 0xfc00707f +#define MATCH_VSSRL_VX 0xa8004057 +#define MASK_VSSRL_VX 0xfc00707f +#define MATCH_VSSUB_VV 0x8c000057 +#define MASK_VSSUB_VV 0xfc00707f +#define MATCH_VSSUB_VX 0x8c004057 +#define MASK_VSSUB_VX 0xfc00707f +#define MATCH_VSSUBU_VV 0x88000057 +#define MASK_VSSUBU_VV 0xfc00707f +#define MATCH_VSSUBU_VX 0x88004057 +#define MASK_VSSUBU_VX 0xfc00707f +#define MATCH_VSUB_VV 0x8000057 +#define MASK_VSUB_VV 0xfc00707f +#define MATCH_VSUB_VX 0x8004057 +#define MASK_VSUB_VX 0xfc00707f +#define MATCH_VSUXEI1024_V 0x14007027 +#define MASK_VSUXEI1024_V 0x1c00707f +#define MATCH_VSUXEI128_V 0x14000027 +#define MASK_VSUXEI128_V 0x1c00707f +#define MATCH_VSUXEI16_V 0x4005027 +#define MASK_VSUXEI16_V 0x1c00707f +#define MATCH_VSUXEI256_V 0x14005027 +#define MASK_VSUXEI256_V 0x1c00707f +#define MATCH_VSUXEI32_V 0x4006027 +#define MASK_VSUXEI32_V 0x1c00707f +#define MATCH_VSUXEI512_V 0x14006027 +#define MASK_VSUXEI512_V 0x1c00707f +#define MATCH_VSUXEI64_V 0x4007027 +#define MASK_VSUXEI64_V 0x1c00707f +#define MATCH_VSUXEI8_V 0x4000027 +#define MASK_VSUXEI8_V 0x1c00707f +#define MATCH_VWADD_VV 0xc4002057 +#define MASK_VWADD_VV 0xfc00707f +#define MATCH_VWADD_VX 0xc4006057 +#define MASK_VWADD_VX 0xfc00707f +#define MATCH_VWADD_WV 0xd4002057 +#define MASK_VWADD_WV 0xfc00707f +#define MATCH_VWADD_WX 0xd4006057 +#define MASK_VWADD_WX 0xfc00707f +#define MATCH_VWADDU_VV 0xc0002057 +#define MASK_VWADDU_VV 0xfc00707f +#define MATCH_VWADDU_VX 0xc0006057 +#define MASK_VWADDU_VX 0xfc00707f +#define MATCH_VWADDU_WV 0xd0002057 +#define MASK_VWADDU_WV 0xfc00707f +#define MATCH_VWADDU_WX 0xd0006057 +#define MASK_VWADDU_WX 0xfc00707f +#define MATCH_VWMACC_VV 0xf4002057 +#define MASK_VWMACC_VV 0xfc00707f +#define MATCH_VWMACC_VX 0xf4006057 +#define MASK_VWMACC_VX 0xfc00707f +#define MATCH_VWMACCSU_VV 0xfc002057 +#define MASK_VWMACCSU_VV 0xfc00707f +#define MATCH_VWMACCSU_VX 0xfc006057 +#define MASK_VWMACCSU_VX 0xfc00707f +#define MATCH_VWMACCU_VV 0xf0002057 +#define MASK_VWMACCU_VV 0xfc00707f +#define MATCH_VWMACCU_VX 0xf0006057 +#define MASK_VWMACCU_VX 0xfc00707f +#define MATCH_VWMACCUS_VX 0xf8006057 +#define MASK_VWMACCUS_VX 0xfc00707f +#define MATCH_VWMUL_VV 0xec002057 +#define MASK_VWMUL_VV 0xfc00707f +#define MATCH_VWMUL_VX 0xec006057 +#define MASK_VWMUL_VX 0xfc00707f +#define MATCH_VWMULSU_VV 0xe8002057 +#define MASK_VWMULSU_VV 0xfc00707f +#define MATCH_VWMULSU_VX 0xe8006057 +#define MASK_VWMULSU_VX 0xfc00707f +#define MATCH_VWMULU_VV 0xe0002057 +#define MASK_VWMULU_VV 0xfc00707f +#define MATCH_VWMULU_VX 0xe0006057 +#define MASK_VWMULU_VX 0xfc00707f +#define MATCH_VWREDSUM_VS 0xc4000057 +#define MASK_VWREDSUM_VS 0xfc00707f +#define MATCH_VWREDSUMU_VS 0xc0000057 +#define MASK_VWREDSUMU_VS 0xfc00707f +#define MATCH_VWSUB_VV 0xcc002057 +#define MASK_VWSUB_VV 0xfc00707f +#define MATCH_VWSUB_VX 0xcc006057 +#define MASK_VWSUB_VX 0xfc00707f +#define MATCH_VWSUB_WV 0xdc002057 +#define MASK_VWSUB_WV 0xfc00707f +#define MATCH_VWSUB_WX 0xdc006057 +#define MASK_VWSUB_WX 0xfc00707f +#define MATCH_VWSUBU_VV 0xc8002057 +#define MASK_VWSUBU_VV 0xfc00707f +#define MATCH_VWSUBU_VX 0xc8006057 +#define MASK_VWSUBU_VX 0xfc00707f +#define MATCH_VWSUBU_WV 0xd8002057 +#define MASK_VWSUBU_WV 0xfc00707f +#define MATCH_VWSUBU_WX 0xd8006057 +#define MASK_VWSUBU_WX 0xfc00707f +#define MATCH_VXOR_VI 0x2c003057 +#define MASK_VXOR_VI 0xfc00707f +#define MATCH_VXOR_VV 0x2c000057 +#define MASK_VXOR_VV 0xfc00707f +#define MATCH_VXOR_VX 0x2c004057 +#define MASK_VXOR_VX 0xfc00707f +#define MATCH_VZEXT_VF2 0x48032057 +#define MASK_VZEXT_VF2 0xfc0ff07f +#define MATCH_VZEXT_VF4 0x48022057 +#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 +#define MASK_WRS_NTO 0xffffffff +#define MATCH_WRS_STO 0x1d00073 +#define MASK_WRS_STO 0xffffffff +#define MATCH_XNOR 0x40004033 +#define MASK_XNOR 0xfe00707f +#define MATCH_XOR 0x4033 +#define MASK_XOR 0xfe00707f +#define MATCH_XORI 0x4013 +#define MASK_XORI 0x707f +#define MATCH_XPERM16 0x28006033 +#define MASK_XPERM16 0xfe00707f +#define MATCH_XPERM32 0x28000033 +#define MASK_XPERM32 0xfe00707f +#define MATCH_XPERM4 0x28002033 +#define MASK_XPERM4 0xfe00707f +#define MATCH_XPERM8 0x28004033 +#define MASK_XPERM8 0xfe00707f +#define MATCH_ZUNPKD810 0xacc00077 +#define MASK_ZUNPKD810 0xfff0707f +#define MATCH_ZUNPKD820 0xacd00077 +#define MASK_ZUNPKD820 0xfff0707f +#define MATCH_ZUNPKD830 0xace00077 +#define MASK_ZUNPKD830 0xfff0707f +#define MATCH_ZUNPKD831 0xacf00077 +#define MASK_ZUNPKD831 0xfff0707f +#define MATCH_ZUNPKD832 0xad700077 +#define MASK_ZUNPKD832 0xfff0707f + #define CSR_FFLAGS 0x1 #define CSR_FRM 0x2 #define CSR_FCSR 0x3 +#define CSR_VSTART 0x8 +#define CSR_VXSAT 0x9 +#define CSR_VXRM 0xa +#define CSR_VCSR 0xf +#define CSR_SEED 0x15 #define CSR_CYCLE 0xc00 #define CSR_TIME 0xc01 #define CSR_INSTRET 0xc02 @@ -785,16 +2825,73 @@ #define CSR_HPMCOUNTER29 0xc1d #define CSR_HPMCOUNTER30 0xc1e #define CSR_HPMCOUNTER31 0xc1f +#define CSR_VL 0xc20 +#define CSR_VTYPE 0xc21 +#define CSR_VLENB 0xc22 #define CSR_SSTATUS 0x100 +#define CSR_SEDELEG 0x102 +#define CSR_SIDELEG 0x103 #define CSR_SIE 0x104 #define CSR_STVEC 0x105 #define CSR_SCOUNTEREN 0x106 +#define CSR_SENVCFG 0x10a +#define CSR_SSTATEEN0 0x10c +#define CSR_SSTATEEN1 0x10d +#define CSR_SSTATEEN2 0x10e +#define CSR_SSTATEEN3 0x10f #define CSR_SSCRATCH 0x140 #define CSR_SEPC 0x141 #define CSR_SCAUSE 0x142 #define CSR_STVAL 0x143 #define CSR_SIP 0x144 +#define CSR_STIMECMP 0x14d #define CSR_SATP 0x180 +#define CSR_SCONTEXT 0x5a8 +#define CSR_VSSTATUS 0x200 +#define CSR_VSIE 0x204 +#define CSR_VSTVEC 0x205 +#define CSR_VSSCRATCH 0x240 +#define CSR_VSEPC 0x241 +#define CSR_VSCAUSE 0x242 +#define CSR_VSTVAL 0x243 +#define CSR_VSIP 0x244 +#define CSR_VSTIMECMP 0x24d +#define CSR_VSATP 0x280 +#define CSR_HSTATUS 0x600 +#define CSR_HEDELEG 0x602 +#define CSR_HIDELEG 0x603 +#define CSR_HIE 0x604 +#define CSR_HTIMEDELTA 0x605 +#define CSR_HCOUNTEREN 0x606 +#define CSR_HGEIE 0x607 +#define CSR_HENVCFG 0x60a +#define CSR_HSTATEEN0 0x60c +#define CSR_HSTATEEN1 0x60d +#define CSR_HSTATEEN2 0x60e +#define CSR_HSTATEEN3 0x60f +#define CSR_HTVAL 0x643 +#define CSR_HIP 0x644 +#define CSR_HVIP 0x645 +#define CSR_HTINST 0x64a +#define CSR_HGATP 0x680 +#define CSR_HCONTEXT 0x6a8 +#define CSR_HGEIP 0xe12 +#define CSR_SCOUNTOVF 0xda0 +#define CSR_UTVT 0x7 +#define CSR_UNXTI 0x45 +#define CSR_UINTSTATUS 0x46 +#define CSR_USCRATCHCSW 0x48 +#define CSR_USCRATCHCSWL 0x49 +#define CSR_STVT 0x107 +#define CSR_SNXTI 0x145 +#define CSR_SINTSTATUS 0x146 +#define CSR_SSCRATCHCSW 0x148 +#define CSR_SSCRATCHCSWL 0x149 +#define CSR_MTVT 0x307 +#define CSR_MNXTI 0x345 +#define CSR_MINTSTATUS 0x346 +#define CSR_MSCRATCHCSW 0x348 +#define CSR_MSCRATCHCSWL 0x349 #define CSR_MSTATUS 0x300 #define CSR_MISA 0x301 #define CSR_MEDELEG 0x302 @@ -802,15 +2899,35 @@ #define CSR_MIE 0x304 #define CSR_MTVEC 0x305 #define CSR_MCOUNTEREN 0x306 +#define CSR_MENVCFG 0x30a +#define CSR_MSTATEEN0 0x30c +#define CSR_MSTATEEN1 0x30d +#define CSR_MSTATEEN2 0x30e +#define CSR_MSTATEEN3 0x30f +#define CSR_MCOUNTINHIBIT 0x320 #define CSR_MSCRATCH 0x340 #define CSR_MEPC 0x341 #define CSR_MCAUSE 0x342 #define CSR_MTVAL 0x343 #define CSR_MIP 0x344 +#define CSR_MTINST 0x34a +#define CSR_MTVAL2 0x34b #define CSR_PMPCFG0 0x3a0 #define CSR_PMPCFG1 0x3a1 #define CSR_PMPCFG2 0x3a2 #define CSR_PMPCFG3 0x3a3 +#define CSR_PMPCFG4 0x3a4 +#define CSR_PMPCFG5 0x3a5 +#define CSR_PMPCFG6 0x3a6 +#define CSR_PMPCFG7 0x3a7 +#define CSR_PMPCFG8 0x3a8 +#define CSR_PMPCFG9 0x3a9 +#define CSR_PMPCFG10 0x3aa +#define CSR_PMPCFG11 0x3ab +#define CSR_PMPCFG12 0x3ac +#define CSR_PMPCFG13 0x3ad +#define CSR_PMPCFG14 0x3ae +#define CSR_PMPCFG15 0x3af #define CSR_PMPADDR0 0x3b0 #define CSR_PMPADDR1 0x3b1 #define CSR_PMPADDR2 0x3b2 @@ -827,13 +2944,67 @@ #define CSR_PMPADDR13 0x3bd #define CSR_PMPADDR14 0x3be #define CSR_PMPADDR15 0x3bf +#define CSR_PMPADDR16 0x3c0 +#define CSR_PMPADDR17 0x3c1 +#define CSR_PMPADDR18 0x3c2 +#define CSR_PMPADDR19 0x3c3 +#define CSR_PMPADDR20 0x3c4 +#define CSR_PMPADDR21 0x3c5 +#define CSR_PMPADDR22 0x3c6 +#define CSR_PMPADDR23 0x3c7 +#define CSR_PMPADDR24 0x3c8 +#define CSR_PMPADDR25 0x3c9 +#define CSR_PMPADDR26 0x3ca +#define CSR_PMPADDR27 0x3cb +#define CSR_PMPADDR28 0x3cc +#define CSR_PMPADDR29 0x3cd +#define CSR_PMPADDR30 0x3ce +#define CSR_PMPADDR31 0x3cf +#define CSR_PMPADDR32 0x3d0 +#define CSR_PMPADDR33 0x3d1 +#define CSR_PMPADDR34 0x3d2 +#define CSR_PMPADDR35 0x3d3 +#define CSR_PMPADDR36 0x3d4 +#define CSR_PMPADDR37 0x3d5 +#define CSR_PMPADDR38 0x3d6 +#define CSR_PMPADDR39 0x3d7 +#define CSR_PMPADDR40 0x3d8 +#define CSR_PMPADDR41 0x3d9 +#define CSR_PMPADDR42 0x3da +#define CSR_PMPADDR43 0x3db +#define CSR_PMPADDR44 0x3dc +#define CSR_PMPADDR45 0x3dd +#define CSR_PMPADDR46 0x3de +#define CSR_PMPADDR47 0x3df +#define CSR_PMPADDR48 0x3e0 +#define CSR_PMPADDR49 0x3e1 +#define CSR_PMPADDR50 0x3e2 +#define CSR_PMPADDR51 0x3e3 +#define CSR_PMPADDR52 0x3e4 +#define CSR_PMPADDR53 0x3e5 +#define CSR_PMPADDR54 0x3e6 +#define CSR_PMPADDR55 0x3e7 +#define CSR_PMPADDR56 0x3e8 +#define CSR_PMPADDR57 0x3e9 +#define CSR_PMPADDR58 0x3ea +#define CSR_PMPADDR59 0x3eb +#define CSR_PMPADDR60 0x3ec +#define CSR_PMPADDR61 0x3ed +#define CSR_PMPADDR62 0x3ee +#define CSR_PMPADDR63 0x3ef +#define CSR_MSECCFG 0x747 #define CSR_TSELECT 0x7a0 #define CSR_TDATA1 0x7a1 #define CSR_TDATA2 0x7a2 #define CSR_TDATA3 0x7a3 +#define CSR_TINFO 0x7a4 +#define CSR_TCONTROL 0x7a5 +#define CSR_MCONTEXT 0x7a8 +#define CSR_MSCONTEXT 0x7aa #define CSR_DCSR 0x7b0 #define CSR_DPC 0x7b1 -#define CSR_DSCRATCH 0x7b2 +#define CSR_DSCRATCH0 0x7b2 +#define CSR_DSCRATCH1 0x7b3 #define CSR_MCYCLE 0xb00 #define CSR_MINSTRET 0xb02 #define CSR_MHPMCOUNTER3 0xb03 @@ -898,6 +3069,15 @@ #define CSR_MARCHID 0xf12 #define CSR_MIMPID 0xf13 #define CSR_MHARTID 0xf14 +#define CSR_MCONFIGPTR 0xf15 +#define CSR_STIMECMPH 0x15d +#define CSR_VSTIMECMPH 0x25d +#define CSR_HTIMEDELTAH 0x615 +#define CSR_HENVCFGH 0x61a +#define CSR_HSTATEEN0H 0x61c +#define CSR_HSTATEEN1H 0x61d +#define CSR_HSTATEEN2H 0x61e +#define CSR_HSTATEEN3H 0x61f #define CSR_CYCLEH 0xc80 #define CSR_TIMEH 0xc81 #define CSR_INSTRETH 0xc82 @@ -930,6 +3110,42 @@ #define CSR_HPMCOUNTER29H 0xc9d #define CSR_HPMCOUNTER30H 0xc9e #define CSR_HPMCOUNTER31H 0xc9f +#define CSR_MSTATUSH 0x310 +#define CSR_MENVCFGH 0x31a +#define CSR_MSTATEEN0H 0x31c +#define CSR_MSTATEEN1H 0x31d +#define CSR_MSTATEEN2H 0x31e +#define CSR_MSTATEEN3H 0x31f +#define CSR_MHPMEVENT3H 0x723 +#define CSR_MHPMEVENT4H 0x724 +#define CSR_MHPMEVENT5H 0x725 +#define CSR_MHPMEVENT6H 0x726 +#define CSR_MHPMEVENT7H 0x727 +#define CSR_MHPMEVENT8H 0x728 +#define CSR_MHPMEVENT9H 0x729 +#define CSR_MHPMEVENT10H 0x72a +#define CSR_MHPMEVENT11H 0x72b +#define CSR_MHPMEVENT12H 0x72c +#define CSR_MHPMEVENT13H 0x72d +#define CSR_MHPMEVENT14H 0x72e +#define CSR_MHPMEVENT15H 0x72f +#define CSR_MHPMEVENT16H 0x730 +#define CSR_MHPMEVENT17H 0x731 +#define CSR_MHPMEVENT18H 0x732 +#define CSR_MHPMEVENT19H 0x733 +#define CSR_MHPMEVENT20H 0x734 +#define CSR_MHPMEVENT21H 0x735 +#define CSR_MHPMEVENT22H 0x736 +#define CSR_MHPMEVENT23H 0x737 +#define CSR_MHPMEVENT24H 0x738 +#define CSR_MHPMEVENT25H 0x739 +#define CSR_MHPMEVENT26H 0x73a +#define CSR_MHPMEVENT27H 0x73b +#define CSR_MHPMEVENT28H 0x73c +#define CSR_MHPMEVENT29H 0x73d +#define CSR_MHPMEVENT30H 0x73e +#define CSR_MHPMEVENT31H 0x73f +#define CSR_MSECCFGH 0x757 #define CSR_MCYCLEH 0xb80 #define CSR_MINSTRETH 0xb82 #define CSR_MHPMCOUNTER3H 0xb83 @@ -961,6 +3177,7 @@ #define CSR_MHPMCOUNTER29H 0xb9d #define CSR_MHPMCOUNTER30H 0xb9e #define CSR_MHPMCOUNTER31H 0xb9f + #define CAUSE_MISALIGNED_FETCH 0x0 #define CAUSE_FETCH_ACCESS 0x1 #define CAUSE_ILLEGAL_INSTRUCTION 0x2 @@ -971,280 +3188,1333 @@ #define CAUSE_STORE_ACCESS 0x7 #define CAUSE_USER_ECALL 0x8 #define CAUSE_SUPERVISOR_ECALL 0x9 -#define CAUSE_HYPERVISOR_ECALL 0xa +#define CAUSE_VIRTUAL_SUPERVISOR_ECALL 0xa #define CAUSE_MACHINE_ECALL 0xb #define CAUSE_FETCH_PAGE_FAULT 0xc #define CAUSE_LOAD_PAGE_FAULT 0xd #define CAUSE_STORE_PAGE_FAULT 0xf +#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14 +#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15 +#define CAUSE_VIRTUAL_INSTRUCTION 0x16 +#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17 + +#define INSN_FIELD_RD 0xf80 +#define INSN_FIELD_RT 0xf8000 +#define INSN_FIELD_RS1 0xf8000 +#define INSN_FIELD_RS2 0x1f00000 +#define INSN_FIELD_RS3 0xf8000000 +#define INSN_FIELD_AQRL 0x6000000 +#define INSN_FIELD_AQ 0x4000000 +#define INSN_FIELD_RL 0x2000000 +#define INSN_FIELD_FM 0xf0000000 +#define INSN_FIELD_PRED 0xf000000 +#define INSN_FIELD_SUCC 0xf00000 +#define INSN_FIELD_RM 0x7000 +#define INSN_FIELD_FUNCT3 0x7000 +#define INSN_FIELD_FUNCT2 0x6000000 +#define INSN_FIELD_IMM20 0xfffff000 +#define INSN_FIELD_JIMM20 0xfffff000 +#define INSN_FIELD_IMM12 0xfff00000 +#define INSN_FIELD_CSR 0xfff00000 +#define INSN_FIELD_IMM12HI 0xfe000000 +#define INSN_FIELD_BIMM12HI 0xfe000000 +#define INSN_FIELD_IMM12LO 0xf80 +#define INSN_FIELD_BIMM12LO 0xf80 +#define INSN_FIELD_ZIMM 0xf8000 +#define INSN_FIELD_SHAMT 0x7f00000 +#define INSN_FIELD_SHAMTW 0x1f00000 +#define INSN_FIELD_SHAMTW4 0xf00000 +#define INSN_FIELD_SHAMTD 0x3f00000 +#define INSN_FIELD_BS 0xc0000000 +#define INSN_FIELD_RNUM 0xf00000 +#define INSN_FIELD_RC 0x3e000000 +#define INSN_FIELD_IMM2 0x300000 +#define INSN_FIELD_IMM3 0x700000 +#define INSN_FIELD_IMM4 0xf00000 +#define INSN_FIELD_IMM5 0x1f00000 +#define INSN_FIELD_IMM6 0x3f00000 +#define INSN_FIELD_OPCODE 0x7f +#define INSN_FIELD_FUNCT7 0xfe000000 +#define INSN_FIELD_VD 0xf80 +#define INSN_FIELD_VS3 0xf80 +#define INSN_FIELD_VS1 0xf8000 +#define INSN_FIELD_VS2 0x1f00000 +#define INSN_FIELD_VM 0x2000000 +#define INSN_FIELD_WD 0x4000000 +#define INSN_FIELD_AMOOP 0xf8000000 +#define INSN_FIELD_NF 0xe0000000 +#define INSN_FIELD_SIMM5 0xf8000 +#define INSN_FIELD_ZIMM10 0x3ff00000 +#define INSN_FIELD_ZIMM11 0x7ff00000 +#define INSN_FIELD_C_NZUIMM10 0x1fe0 +#define INSN_FIELD_C_UIMM7LO 0x60 +#define INSN_FIELD_C_UIMM7HI 0x1c00 +#define INSN_FIELD_C_UIMM8LO 0x60 +#define INSN_FIELD_C_UIMM8HI 0x1c00 +#define INSN_FIELD_C_UIMM9LO 0x60 +#define INSN_FIELD_C_UIMM9HI 0x1c00 +#define INSN_FIELD_C_NZIMM6LO 0x7c +#define INSN_FIELD_C_NZIMM6HI 0x1000 +#define INSN_FIELD_C_IMM6LO 0x7c +#define INSN_FIELD_C_IMM6HI 0x1000 +#define INSN_FIELD_C_NZIMM10HI 0x1000 +#define INSN_FIELD_C_NZIMM10LO 0x7c +#define INSN_FIELD_C_NZIMM18HI 0x1000 +#define INSN_FIELD_C_NZIMM18LO 0x7c +#define INSN_FIELD_C_IMM12 0x1ffc +#define INSN_FIELD_C_BIMM9LO 0x7c +#define INSN_FIELD_C_BIMM9HI 0x1c00 +#define INSN_FIELD_C_NZUIMM5 0x7c +#define INSN_FIELD_C_NZUIMM6LO 0x7c +#define INSN_FIELD_C_NZUIMM6HI 0x1000 +#define INSN_FIELD_C_UIMM8SPLO 0x7c +#define INSN_FIELD_C_UIMM8SPHI 0x1000 +#define INSN_FIELD_C_UIMM8SP_S 0x1f80 +#define INSN_FIELD_C_UIMM10SPLO 0x7c +#define INSN_FIELD_C_UIMM10SPHI 0x1000 +#define INSN_FIELD_C_UIMM9SPLO 0x7c +#define INSN_FIELD_C_UIMM9SPHI 0x1000 +#define INSN_FIELD_C_UIMM10SP_S 0x1f80 +#define INSN_FIELD_C_UIMM9SP_S 0x1f80 +#define INSN_FIELD_RS1_P 0x380 +#define INSN_FIELD_RS2_P 0x1c +#define INSN_FIELD_RD_P 0x1c +#define INSN_FIELD_RD_RS1_N0 0xf80 +#define INSN_FIELD_RD_RS1_P 0x380 +#define INSN_FIELD_RD_RS1 0xf80 +#define INSN_FIELD_RD_N2 0xf80 +#define INSN_FIELD_RD_N0 0xf80 +#define INSN_FIELD_RS1_N0 0xf80 +#define INSN_FIELD_C_RS2_N0 0x7c +#define INSN_FIELD_C_RS1_N0 0xf80 +#define INSN_FIELD_C_RS2 0x7c #endif #ifdef DECLARE_INSN -DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) -DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) -DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) -DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) -DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) -DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) -DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) -DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) -DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) -DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) -DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) -DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) -DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) -DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) -DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) -DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) -DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) -DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) -DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) DECLARE_INSN(add, MATCH_ADD, MASK_ADD) -DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) -DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) -DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) -DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) -DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) -DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) -DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) -DECLARE_INSN(or, MATCH_OR, MASK_OR) -DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(add16, MATCH_ADD16, MASK_ADD16) +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(slliw, MATCH_SLLIW, MASK_SLLIW) -DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) -DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) -DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) -DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) -DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) -DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) -DECLARE_INSN(lb, MATCH_LB, MASK_LB) -DECLARE_INSN(lh, MATCH_LH, MASK_LH) -DECLARE_INSN(lw, MATCH_LW, MASK_LW) -DECLARE_INSN(ld, MATCH_LD, MASK_LD) -DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) -DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) -DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) -DECLARE_INSN(sb, MATCH_SB, MASK_SB) -DECLARE_INSN(sh, MATCH_SH, MASK_SH) -DECLARE_INSN(sw, MATCH_SW, MASK_SW) -DECLARE_INSN(sd, MATCH_SD, MASK_SD) -DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) -DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) -DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) -DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) -DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) -DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) -DECLARE_INSN(div, MATCH_DIV, MASK_DIV) -DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) -DECLARE_INSN(rem, MATCH_REM, MASK_REM) -DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) -DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) -DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) -DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) -DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) -DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(aes32dsi, MATCH_AES32DSI, MASK_AES32DSI) +DECLARE_INSN(aes32dsmi, MATCH_AES32DSMI, MASK_AES32DSMI) +DECLARE_INSN(aes32esi, MATCH_AES32ESI, MASK_AES32ESI) +DECLARE_INSN(aes32esmi, MATCH_AES32ESMI, MASK_AES32ESMI) +DECLARE_INSN(aes64ds, MATCH_AES64DS, MASK_AES64DS) +DECLARE_INSN(aes64dsm, MATCH_AES64DSM, MASK_AES64DSM) +DECLARE_INSN(aes64es, MATCH_AES64ES, MASK_AES64ES) +DECLARE_INSN(aes64esm, MATCH_AES64ESM, MASK_AES64ESM) +DECLARE_INSN(aes64im, MATCH_AES64IM, MASK_AES64IM) +DECLARE_INSN(aes64ks1i, MATCH_AES64KS1I, MASK_AES64KS1I) +DECLARE_INSN(aes64ks2, MATCH_AES64KS2, MASK_AES64KS2) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) -DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) -DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) -DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) -DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) -DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) -DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) -DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) -DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) -DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) -DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) -DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) -DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) -DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) -DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) -DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) -DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) -DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) -DECLARE_INSN(uret, MATCH_URET, MASK_URET) -DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) -DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) -DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) -DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) -DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) -DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) -DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(andn, MATCH_ANDN, MASK_ANDN) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(ave, MATCH_AVE, MASK_AVE) +DECLARE_INSN(bclr, MATCH_BCLR, MASK_BCLR) +DECLARE_INSN(bclri, MATCH_BCLRI, MASK_BCLRI) +DECLARE_INSN(bcompress, MATCH_BCOMPRESS, MASK_BCOMPRESS) +DECLARE_INSN(bcompressw, MATCH_BCOMPRESSW, MASK_BCOMPRESSW) +DECLARE_INSN(bdecompress, MATCH_BDECOMPRESS, MASK_BDECOMPRESS) +DECLARE_INSN(bdecompressw, MATCH_BDECOMPRESSW, MASK_BDECOMPRESSW) +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bext, MATCH_BEXT, MASK_BEXT) +DECLARE_INSN(bexti, MATCH_BEXTI, MASK_BEXTI) +DECLARE_INSN(bfp, MATCH_BFP, MASK_BFP) +DECLARE_INSN(bfpw, MATCH_BFPW, MASK_BFPW) +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) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +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_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +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_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +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) +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(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) +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) +DECLARE_INSN(clz, MATCH_CLZ, MASK_CLZ) +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(cmix, MATCH_CMIX, MASK_CMIX) +DECLARE_INSN(cmov, MATCH_CMOV, MASK_CMOV) +DECLARE_INSN(cmpeq16, MATCH_CMPEQ16, MASK_CMPEQ16) +DECLARE_INSN(cmpeq8, MATCH_CMPEQ8, MASK_CMPEQ8) +DECLARE_INSN(cpop, MATCH_CPOP, MASK_CPOP) +DECLARE_INSN(cpopw, MATCH_CPOPW, MASK_CPOPW) +DECLARE_INSN(cras16, MATCH_CRAS16, MASK_CRAS16) +DECLARE_INSN(cras32, MATCH_CRAS32, MASK_CRAS32) +DECLARE_INSN(crc32_b, MATCH_CRC32_B, MASK_CRC32_B) +DECLARE_INSN(crc32_d, MATCH_CRC32_D, MASK_CRC32_D) +DECLARE_INSN(crc32_h, MATCH_CRC32_H, MASK_CRC32_H) +DECLARE_INSN(crc32_w, MATCH_CRC32_W, MASK_CRC32_W) +DECLARE_INSN(crc32c_b, MATCH_CRC32C_B, MASK_CRC32C_B) +DECLARE_INSN(crc32c_d, MATCH_CRC32C_D, MASK_CRC32C_D) +DECLARE_INSN(crc32c_h, MATCH_CRC32C_H, MASK_CRC32C_H) +DECLARE_INSN(crc32c_w, MATCH_CRC32C_W, MASK_CRC32C_W) +DECLARE_INSN(crsa16, MATCH_CRSA16, MASK_CRSA16) +DECLARE_INSN(crsa32, MATCH_CRSA32, MASK_CRSA32) DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) -DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) -DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) -DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) -DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) -DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) -DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) -DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) -DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) -DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) -DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) -DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) -DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +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(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) -DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) -DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) -DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) -DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) -DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) -DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) -DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) -DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) -DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) -DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) -DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fadd_h, MATCH_FADD_H, MASK_FADD_H) DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) -DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) -DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) -DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) -DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) -DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) -DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) -DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) -DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) -DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) -DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) -DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) -DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) -DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) -DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) -DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) -DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) -DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) -DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) -DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) -DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) -DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) -DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) -DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) -DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) -DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) -DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) -DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W) -DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) -DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) -DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) -DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) -DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) -DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) -DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) -DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) -DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) -DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) -DECLARE_INSN(fmv_x_q, MATCH_FMV_X_Q, MASK_FMV_X_Q) +DECLARE_INSN(fclass_h, MATCH_FCLASS_H, MASK_FCLASS_H) DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) -DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) -DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) -DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) -DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) -DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X) -DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) -DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_d_h, MATCH_FCVT_D_H, MASK_FCVT_D_H) DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) -DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) -DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) -DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) +DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fcvt_h_d, MATCH_FCVT_H_D, MASK_FCVT_H_D) +DECLARE_INSN(fcvt_h_l, MATCH_FCVT_H_L, MASK_FCVT_H_L) +DECLARE_INSN(fcvt_h_lu, MATCH_FCVT_H_LU, MASK_FCVT_H_LU) +DECLARE_INSN(fcvt_h_q, MATCH_FCVT_H_Q, MASK_FCVT_H_Q) +DECLARE_INSN(fcvt_h_s, MATCH_FCVT_H_S, MASK_FCVT_H_S) +DECLARE_INSN(fcvt_h_w, MATCH_FCVT_H_W, MASK_FCVT_H_W) +DECLARE_INSN(fcvt_h_wu, MATCH_FCVT_H_WU, MASK_FCVT_H_WU) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_l_h, MATCH_FCVT_L_H, MASK_FCVT_L_H) +DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fcvt_lu_h, MATCH_FCVT_LU_H, MASK_FCVT_LU_H) +DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) +DECLARE_INSN(fcvt_q_h, MATCH_FCVT_Q_H, MASK_FCVT_Q_H) DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) -DECLARE_INSN(fmv_q_x, MATCH_FMV_Q_X, MASK_FMV_Q_X) -DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) +DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) +DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_s_h, MATCH_FCVT_S_H, MASK_FCVT_S_H) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_w_h, MATCH_FCVT_W_H, MASK_FCVT_W_H) +DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fcvt_wu_h, MATCH_FCVT_WU_H, MASK_FCVT_WU_H) +DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fdiv_h, MATCH_FDIV_H, MASK_FDIV_H) +DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(feq_h, MATCH_FEQ_H, MASK_FEQ_H) +DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(fle_h, MATCH_FLE_H, MASK_FLE_H) +DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flh, MATCH_FLH, MASK_FLH) DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) -DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) -DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) -DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(flt_h, MATCH_FLT_H, MASK_FLT_H) +DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmadd_h, MATCH_FMADD_H, MASK_FMADD_H) +DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fmax_h, MATCH_FMAX_H, MASK_FMAX_H) +DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmin_h, MATCH_FMIN_H, MASK_FMIN_H) +DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fmsub_h, MATCH_FMSUB_H, MASK_FMSUB_H) +DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) -DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fmul_h, MATCH_FMUL_H, MASK_FMUL_H) +DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(fmv_h_x, MATCH_FMV_H_X, MASK_FMV_H_X) +DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fmv_x_h, MATCH_FMV_X_H, MASK_FMV_X_H) +DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(fnmadd_h, MATCH_FNMADD_H, MASK_FNMADD_H) +DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) -DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) -DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) -DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) -DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) -DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) +DECLARE_INSN(fnmsub_h, MATCH_FNMSUB_H, MASK_FNMSUB_H) DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) -DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) -DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) -DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) -DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) -DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) -DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) -DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) -DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) -DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) -DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) -DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) -DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) -DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) -DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) -DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) -DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) -DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) -DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) -DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) -DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) -DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) -DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) -DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) -DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) -DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) -DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) -DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) -DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) -DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) -DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) -DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) -DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) -DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) -DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) -DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) -DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) -DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) -DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) -DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) -DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) -DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) -DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) -DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) -DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) -DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) -DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) -DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) -DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) -DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) -DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) -DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) -DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) -DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) -DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) -DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) -DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) -DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) -DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) -DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) -DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) -DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) -DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) -DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) -DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) -DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) -DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) -DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnj_h, MATCH_FSGNJ_H, MASK_FSGNJ_H) +DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjn_h, MATCH_FSGNJN_H, MASK_FSGNJN_H) +DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fsgnjx_h, MATCH_FSGNJX_H, MASK_FSGNJX_H) +DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fsh, MATCH_FSH, MASK_FSH) +DECLARE_INSN(fsl, MATCH_FSL, MASK_FSL) +DECLARE_INSN(fslw, MATCH_FSLW, MASK_FSLW) +DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fsqrt_h, MATCH_FSQRT_H, MASK_FSQRT_H) +DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fsr, MATCH_FSR, MASK_FSR) +DECLARE_INSN(fsri, MATCH_FSRI, MASK_FSRI) +DECLARE_INSN(fsriw, MATCH_FSRIW, MASK_FSRIW) +DECLARE_INSN(fsrw, MATCH_FSRW, MASK_FSRW) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fsub_h, MATCH_FSUB_H, MASK_FSUB_H) +DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(gorc, MATCH_GORC, MASK_GORC) +DECLARE_INSN(gorci, MATCH_GORCI, MASK_GORCI) +DECLARE_INSN(gorciw, MATCH_GORCIW, MASK_GORCIW) +DECLARE_INSN(gorcw, MATCH_GORCW, MASK_GORCW) +DECLARE_INSN(grev, MATCH_GREV, MASK_GREV) +DECLARE_INSN(grevi, MATCH_GREVI, MASK_GREVI) +DECLARE_INSN(greviw, MATCH_GREVIW, MASK_GREVIW) +DECLARE_INSN(grevw, MATCH_GREVW, MASK_GREVW) +DECLARE_INSN(hfence_gvma, MATCH_HFENCE_GVMA, MASK_HFENCE_GVMA) +DECLARE_INSN(hfence_vvma, MATCH_HFENCE_VVMA, MASK_HFENCE_VVMA) +DECLARE_INSN(hinval_gvma, MATCH_HINVAL_GVMA, MASK_HINVAL_GVMA) +DECLARE_INSN(hinval_vvma, MATCH_HINVAL_VVMA, MASK_HINVAL_VVMA) +DECLARE_INSN(hlv_b, MATCH_HLV_B, MASK_HLV_B) +DECLARE_INSN(hlv_bu, MATCH_HLV_BU, MASK_HLV_BU) +DECLARE_INSN(hlv_d, MATCH_HLV_D, MASK_HLV_D) +DECLARE_INSN(hlv_h, MATCH_HLV_H, MASK_HLV_H) +DECLARE_INSN(hlv_hu, MATCH_HLV_HU, MASK_HLV_HU) +DECLARE_INSN(hlv_w, MATCH_HLV_W, MASK_HLV_W) +DECLARE_INSN(hlv_wu, MATCH_HLV_WU, MASK_HLV_WU) +DECLARE_INSN(hlvx_hu, MATCH_HLVX_HU, MASK_HLVX_HU) +DECLARE_INSN(hlvx_wu, MATCH_HLVX_WU, MASK_HLVX_WU) +DECLARE_INSN(hsv_b, MATCH_HSV_B, MASK_HSV_B) +DECLARE_INSN(hsv_d, MATCH_HSV_D, MASK_HSV_D) +DECLARE_INSN(hsv_h, MATCH_HSV_H, MASK_HSV_H) +DECLARE_INSN(hsv_w, MATCH_HSV_W, MASK_HSV_W) +DECLARE_INSN(insb, MATCH_INSB, MASK_INSB) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(kabs16, MATCH_KABS16, MASK_KABS16) +DECLARE_INSN(kabs32, MATCH_KABS32, MASK_KABS32) +DECLARE_INSN(kabs8, MATCH_KABS8, MASK_KABS8) +DECLARE_INSN(kabsw, MATCH_KABSW, MASK_KABSW) +DECLARE_INSN(kadd16, MATCH_KADD16, MASK_KADD16) +DECLARE_INSN(kadd32, MATCH_KADD32, MASK_KADD32) +DECLARE_INSN(kadd64, MATCH_KADD64, MASK_KADD64) +DECLARE_INSN(kadd8, MATCH_KADD8, MASK_KADD8) +DECLARE_INSN(kaddh, MATCH_KADDH, MASK_KADDH) +DECLARE_INSN(kaddw, MATCH_KADDW, MASK_KADDW) +DECLARE_INSN(kcras16, MATCH_KCRAS16, MASK_KCRAS16) +DECLARE_INSN(kcras32, MATCH_KCRAS32, MASK_KCRAS32) +DECLARE_INSN(kcrsa16, MATCH_KCRSA16, MASK_KCRSA16) +DECLARE_INSN(kcrsa32, MATCH_KCRSA32, MASK_KCRSA32) +DECLARE_INSN(kdmabb, MATCH_KDMABB, MASK_KDMABB) +DECLARE_INSN(kdmabb16, MATCH_KDMABB16, MASK_KDMABB16) +DECLARE_INSN(kdmabt, MATCH_KDMABT, MASK_KDMABT) +DECLARE_INSN(kdmabt16, MATCH_KDMABT16, MASK_KDMABT16) +DECLARE_INSN(kdmatt, MATCH_KDMATT, MASK_KDMATT) +DECLARE_INSN(kdmatt16, MATCH_KDMATT16, MASK_KDMATT16) +DECLARE_INSN(kdmbb, MATCH_KDMBB, MASK_KDMBB) +DECLARE_INSN(kdmbb16, MATCH_KDMBB16, MASK_KDMBB16) +DECLARE_INSN(kdmbt, MATCH_KDMBT, MASK_KDMBT) +DECLARE_INSN(kdmbt16, MATCH_KDMBT16, MASK_KDMBT16) +DECLARE_INSN(kdmtt, MATCH_KDMTT, MASK_KDMTT) +DECLARE_INSN(kdmtt16, MATCH_KDMTT16, MASK_KDMTT16) +DECLARE_INSN(khm16, MATCH_KHM16, MASK_KHM16) +DECLARE_INSN(khm8, MATCH_KHM8, MASK_KHM8) +DECLARE_INSN(khmbb, MATCH_KHMBB, MASK_KHMBB) +DECLARE_INSN(khmbb16, MATCH_KHMBB16, MASK_KHMBB16) +DECLARE_INSN(khmbt, MATCH_KHMBT, MASK_KHMBT) +DECLARE_INSN(khmbt16, MATCH_KHMBT16, MASK_KHMBT16) +DECLARE_INSN(khmtt, MATCH_KHMTT, MASK_KHMTT) +DECLARE_INSN(khmtt16, MATCH_KHMTT16, MASK_KHMTT16) +DECLARE_INSN(khmx16, MATCH_KHMX16, MASK_KHMX16) +DECLARE_INSN(khmx8, MATCH_KHMX8, MASK_KHMX8) +DECLARE_INSN(kmabb, MATCH_KMABB, MASK_KMABB) +DECLARE_INSN(kmabb32, MATCH_KMABB32, MASK_KMABB32) +DECLARE_INSN(kmabt, MATCH_KMABT, MASK_KMABT) +DECLARE_INSN(kmabt32, MATCH_KMABT32, MASK_KMABT32) +DECLARE_INSN(kmada, MATCH_KMADA, MASK_KMADA) +DECLARE_INSN(kmadrs, MATCH_KMADRS, MASK_KMADRS) +DECLARE_INSN(kmadrs32, MATCH_KMADRS32, MASK_KMADRS32) +DECLARE_INSN(kmads, MATCH_KMADS, MASK_KMADS) +DECLARE_INSN(kmads32, MATCH_KMADS32, MASK_KMADS32) +DECLARE_INSN(kmar64, MATCH_KMAR64, MASK_KMAR64) +DECLARE_INSN(kmatt, MATCH_KMATT, MASK_KMATT) +DECLARE_INSN(kmatt32, MATCH_KMATT32, MASK_KMATT32) +DECLARE_INSN(kmaxda, MATCH_KMAXDA, MASK_KMAXDA) +DECLARE_INSN(kmaxda32, MATCH_KMAXDA32, MASK_KMAXDA32) +DECLARE_INSN(kmaxds, MATCH_KMAXDS, MASK_KMAXDS) +DECLARE_INSN(kmaxds32, MATCH_KMAXDS32, MASK_KMAXDS32) +DECLARE_INSN(kmda, MATCH_KMDA, MASK_KMDA) +DECLARE_INSN(kmda32, MATCH_KMDA32, MASK_KMDA32) +DECLARE_INSN(kmmac, MATCH_KMMAC, MASK_KMMAC) +DECLARE_INSN(kmmac_u, MATCH_KMMAC_U, MASK_KMMAC_U) +DECLARE_INSN(kmmawb, MATCH_KMMAWB, MASK_KMMAWB) +DECLARE_INSN(kmmawb2, MATCH_KMMAWB2, MASK_KMMAWB2) +DECLARE_INSN(kmmawb2_u, MATCH_KMMAWB2_U, MASK_KMMAWB2_U) +DECLARE_INSN(kmmawb_u, MATCH_KMMAWB_U, MASK_KMMAWB_U) +DECLARE_INSN(kmmawt, MATCH_KMMAWT, MASK_KMMAWT) +DECLARE_INSN(kmmawt2, MATCH_KMMAWT2, MASK_KMMAWT2) +DECLARE_INSN(kmmawt2_u, MATCH_KMMAWT2_U, MASK_KMMAWT2_U) +DECLARE_INSN(kmmawt_u, MATCH_KMMAWT_U, MASK_KMMAWT_U) +DECLARE_INSN(kmmsb, MATCH_KMMSB, MASK_KMMSB) +DECLARE_INSN(kmmsb_u, MATCH_KMMSB_U, MASK_KMMSB_U) +DECLARE_INSN(kmmwb2, MATCH_KMMWB2, MASK_KMMWB2) +DECLARE_INSN(kmmwb2_u, MATCH_KMMWB2_U, MASK_KMMWB2_U) +DECLARE_INSN(kmmwt2, MATCH_KMMWT2, MASK_KMMWT2) +DECLARE_INSN(kmmwt2_u, MATCH_KMMWT2_U, MASK_KMMWT2_U) +DECLARE_INSN(kmsda, MATCH_KMSDA, MASK_KMSDA) +DECLARE_INSN(kmsda32, MATCH_KMSDA32, MASK_KMSDA32) +DECLARE_INSN(kmsr64, MATCH_KMSR64, MASK_KMSR64) +DECLARE_INSN(kmsxda, MATCH_KMSXDA, MASK_KMSXDA) +DECLARE_INSN(kmsxda32, MATCH_KMSXDA32, MASK_KMSXDA32) +DECLARE_INSN(kmxda, MATCH_KMXDA, MASK_KMXDA) +DECLARE_INSN(kmxda32, MATCH_KMXDA32, MASK_KMXDA32) +DECLARE_INSN(ksll16, MATCH_KSLL16, MASK_KSLL16) +DECLARE_INSN(ksll32, MATCH_KSLL32, MASK_KSLL32) +DECLARE_INSN(ksll8, MATCH_KSLL8, MASK_KSLL8) +DECLARE_INSN(kslli16, MATCH_KSLLI16, MASK_KSLLI16) +DECLARE_INSN(kslli32, MATCH_KSLLI32, MASK_KSLLI32) +DECLARE_INSN(kslli8, MATCH_KSLLI8, MASK_KSLLI8) +DECLARE_INSN(kslliw, MATCH_KSLLIW, MASK_KSLLIW) +DECLARE_INSN(ksllw, MATCH_KSLLW, MASK_KSLLW) +DECLARE_INSN(kslra16, MATCH_KSLRA16, MASK_KSLRA16) +DECLARE_INSN(kslra16_u, MATCH_KSLRA16_U, MASK_KSLRA16_U) +DECLARE_INSN(kslra32, MATCH_KSLRA32, MASK_KSLRA32) +DECLARE_INSN(kslra32_u, MATCH_KSLRA32_U, MASK_KSLRA32_U) +DECLARE_INSN(kslra8, MATCH_KSLRA8, MASK_KSLRA8) +DECLARE_INSN(kslra8_u, MATCH_KSLRA8_U, MASK_KSLRA8_U) +DECLARE_INSN(kslraw, MATCH_KSLRAW, MASK_KSLRAW) +DECLARE_INSN(kslraw_u, MATCH_KSLRAW_U, MASK_KSLRAW_U) +DECLARE_INSN(kstas16, MATCH_KSTAS16, MASK_KSTAS16) +DECLARE_INSN(kstas32, MATCH_KSTAS32, MASK_KSTAS32) +DECLARE_INSN(kstsa16, MATCH_KSTSA16, MASK_KSTSA16) +DECLARE_INSN(kstsa32, MATCH_KSTSA32, MASK_KSTSA32) +DECLARE_INSN(ksub16, MATCH_KSUB16, MASK_KSUB16) +DECLARE_INSN(ksub32, MATCH_KSUB32, MASK_KSUB32) +DECLARE_INSN(ksub64, MATCH_KSUB64, MASK_KSUB64) +DECLARE_INSN(ksub8, MATCH_KSUB8, MASK_KSUB8) +DECLARE_INSN(ksubh, MATCH_KSUBH, MASK_KSUBH) +DECLARE_INSN(ksubw, MATCH_KSUBW, MASK_KSUBW) +DECLARE_INSN(kwmmul, MATCH_KWMMUL, MASK_KWMMUL) +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) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +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) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(mulr64, MATCH_MULR64, MASK_MULR64) +DECLARE_INSN(mulsr64, MATCH_MULSR64, MASK_MULSR64) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(orn, MATCH_ORN, MASK_ORN) +DECLARE_INSN(pack, MATCH_PACK, MASK_PACK) +DECLARE_INSN(packh, MATCH_PACKH, MASK_PACKH) +DECLARE_INSN(packu, MATCH_PACKU, MASK_PACKU) +DECLARE_INSN(packuw, MATCH_PACKUW, MASK_PACKUW) +DECLARE_INSN(packw, MATCH_PACKW, MASK_PACKW) +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) +DECLARE_INSN(radd16, MATCH_RADD16, MASK_RADD16) +DECLARE_INSN(radd32, MATCH_RADD32, MASK_RADD32) +DECLARE_INSN(radd64, MATCH_RADD64, MASK_RADD64) +DECLARE_INSN(radd8, MATCH_RADD8, MASK_RADD8) +DECLARE_INSN(raddw, MATCH_RADDW, MASK_RADDW) +DECLARE_INSN(rcras16, MATCH_RCRAS16, MASK_RCRAS16) +DECLARE_INSN(rcras32, MATCH_RCRAS32, MASK_RCRAS32) +DECLARE_INSN(rcrsa16, MATCH_RCRSA16, MASK_RCRSA16) +DECLARE_INSN(rcrsa32, MATCH_RCRSA32, MASK_RCRSA32) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(rol, MATCH_ROL, MASK_ROL) +DECLARE_INSN(rolw, MATCH_ROLW, MASK_ROLW) +DECLARE_INSN(ror, MATCH_ROR, MASK_ROR) +DECLARE_INSN(rori, MATCH_RORI, MASK_RORI) +DECLARE_INSN(roriw, MATCH_RORIW, MASK_RORIW) +DECLARE_INSN(rorw, MATCH_RORW, MASK_RORW) +DECLARE_INSN(rstas16, MATCH_RSTAS16, MASK_RSTAS16) +DECLARE_INSN(rstas32, MATCH_RSTAS32, MASK_RSTAS32) +DECLARE_INSN(rstsa16, MATCH_RSTSA16, MASK_RSTSA16) +DECLARE_INSN(rstsa32, MATCH_RSTSA32, MASK_RSTSA32) +DECLARE_INSN(rsub16, MATCH_RSUB16, MASK_RSUB16) +DECLARE_INSN(rsub32, MATCH_RSUB32, MASK_RSUB32) +DECLARE_INSN(rsub64, MATCH_RSUB64, MASK_RSUB64) +DECLARE_INSN(rsub8, MATCH_RSUB8, MASK_RSUB8) +DECLARE_INSN(rsubw, MATCH_RSUBW, MASK_RSUBW) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(sclip16, MATCH_SCLIP16, MASK_SCLIP16) +DECLARE_INSN(sclip32, MATCH_SCLIP32, MASK_SCLIP32) +DECLARE_INSN(sclip8, MATCH_SCLIP8, MASK_SCLIP8) +DECLARE_INSN(scmple16, MATCH_SCMPLE16, MASK_SCMPLE16) +DECLARE_INSN(scmple8, MATCH_SCMPLE8, MASK_SCMPLE8) +DECLARE_INSN(scmplt16, MATCH_SCMPLT16, MASK_SCMPLT16) +DECLARE_INSN(scmplt8, MATCH_SCMPLT8, MASK_SCMPLT8) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(sext_b, MATCH_SEXT_B, MASK_SEXT_B) +DECLARE_INSN(sext_h, MATCH_SEXT_H, MASK_SEXT_H) +DECLARE_INSN(sfence_inval_ir, MATCH_SFENCE_INVAL_IR, MASK_SFENCE_INVAL_IR) +DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) +DECLARE_INSN(sfence_w_inval, MATCH_SFENCE_W_INVAL, MASK_SFENCE_W_INVAL) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sh1add, MATCH_SH1ADD, MASK_SH1ADD) +DECLARE_INSN(sh1add_uw, MATCH_SH1ADD_UW, MASK_SH1ADD_UW) +DECLARE_INSN(sh2add, MATCH_SH2ADD, MASK_SH2ADD) +DECLARE_INSN(sh2add_uw, MATCH_SH2ADD_UW, MASK_SH2ADD_UW) +DECLARE_INSN(sh3add, MATCH_SH3ADD, MASK_SH3ADD) +DECLARE_INSN(sh3add_uw, MATCH_SH3ADD_UW, MASK_SH3ADD_UW) +DECLARE_INSN(sha256sig0, MATCH_SHA256SIG0, MASK_SHA256SIG0) +DECLARE_INSN(sha256sig1, MATCH_SHA256SIG1, MASK_SHA256SIG1) +DECLARE_INSN(sha256sum0, MATCH_SHA256SUM0, MASK_SHA256SUM0) +DECLARE_INSN(sha256sum1, MATCH_SHA256SUM1, MASK_SHA256SUM1) +DECLARE_INSN(sha512sig0, MATCH_SHA512SIG0, MASK_SHA512SIG0) +DECLARE_INSN(sha512sig0h, MATCH_SHA512SIG0H, MASK_SHA512SIG0H) +DECLARE_INSN(sha512sig0l, MATCH_SHA512SIG0L, MASK_SHA512SIG0L) +DECLARE_INSN(sha512sig1, MATCH_SHA512SIG1, MASK_SHA512SIG1) +DECLARE_INSN(sha512sig1h, MATCH_SHA512SIG1H, MASK_SHA512SIG1H) +DECLARE_INSN(sha512sig1l, MATCH_SHA512SIG1L, MASK_SHA512SIG1L) +DECLARE_INSN(sha512sum0, MATCH_SHA512SUM0, MASK_SHA512SUM0) +DECLARE_INSN(sha512sum0r, MATCH_SHA512SUM0R, MASK_SHA512SUM0R) +DECLARE_INSN(sha512sum1, MATCH_SHA512SUM1, MASK_SHA512SUM1) +DECLARE_INSN(sha512sum1r, MATCH_SHA512SUM1R, MASK_SHA512SUM1R) +DECLARE_INSN(shfl, MATCH_SHFL, MASK_SHFL) +DECLARE_INSN(shfli, MATCH_SHFLI, MASK_SHFLI) +DECLARE_INSN(shflw, MATCH_SHFLW, MASK_SHFLW) +DECLARE_INSN(sinval_vma, MATCH_SINVAL_VMA, MASK_SINVAL_VMA) +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_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) +DECLARE_INSN(sloi, MATCH_SLOI, MASK_SLOI) +DECLARE_INSN(sloiw, MATCH_SLOIW, MASK_SLOIW) +DECLARE_INSN(slow, MATCH_SLOW, MASK_SLOW) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(sm3p0, MATCH_SM3P0, MASK_SM3P0) +DECLARE_INSN(sm3p1, MATCH_SM3P1, MASK_SM3P1) +DECLARE_INSN(sm4ed, MATCH_SM4ED, MASK_SM4ED) +DECLARE_INSN(sm4ks, MATCH_SM4KS, MASK_SM4KS) +DECLARE_INSN(smal, MATCH_SMAL, MASK_SMAL) +DECLARE_INSN(smalbb, MATCH_SMALBB, MASK_SMALBB) +DECLARE_INSN(smalbt, MATCH_SMALBT, MASK_SMALBT) +DECLARE_INSN(smalda, MATCH_SMALDA, MASK_SMALDA) +DECLARE_INSN(smaldrs, MATCH_SMALDRS, MASK_SMALDRS) +DECLARE_INSN(smalds, MATCH_SMALDS, MASK_SMALDS) +DECLARE_INSN(smaltt, MATCH_SMALTT, MASK_SMALTT) +DECLARE_INSN(smalxda, MATCH_SMALXDA, MASK_SMALXDA) +DECLARE_INSN(smalxds, MATCH_SMALXDS, MASK_SMALXDS) +DECLARE_INSN(smaqa, MATCH_SMAQA, MASK_SMAQA) +DECLARE_INSN(smaqa_su, MATCH_SMAQA_SU, MASK_SMAQA_SU) +DECLARE_INSN(smar64, MATCH_SMAR64, MASK_SMAR64) +DECLARE_INSN(smax16, MATCH_SMAX16, MASK_SMAX16) +DECLARE_INSN(smax32, MATCH_SMAX32, MASK_SMAX32) +DECLARE_INSN(smax8, MATCH_SMAX8, MASK_SMAX8) +DECLARE_INSN(smbb16, MATCH_SMBB16, MASK_SMBB16) +DECLARE_INSN(smbt16, MATCH_SMBT16, MASK_SMBT16) +DECLARE_INSN(smbt32, MATCH_SMBT32, MASK_SMBT32) +DECLARE_INSN(smdrs, MATCH_SMDRS, MASK_SMDRS) +DECLARE_INSN(smdrs32, MATCH_SMDRS32, MASK_SMDRS32) +DECLARE_INSN(smds, MATCH_SMDS, MASK_SMDS) +DECLARE_INSN(smds32, MATCH_SMDS32, MASK_SMDS32) +DECLARE_INSN(smin16, MATCH_SMIN16, MASK_SMIN16) +DECLARE_INSN(smin32, MATCH_SMIN32, MASK_SMIN32) +DECLARE_INSN(smin8, MATCH_SMIN8, MASK_SMIN8) +DECLARE_INSN(smmul, MATCH_SMMUL, MASK_SMMUL) +DECLARE_INSN(smmul_u, MATCH_SMMUL_U, MASK_SMMUL_U) +DECLARE_INSN(smmwb, MATCH_SMMWB, MASK_SMMWB) +DECLARE_INSN(smmwb_u, MATCH_SMMWB_U, MASK_SMMWB_U) +DECLARE_INSN(smmwt, MATCH_SMMWT, MASK_SMMWT) +DECLARE_INSN(smmwt_u, MATCH_SMMWT_U, MASK_SMMWT_U) +DECLARE_INSN(smslda, MATCH_SMSLDA, MASK_SMSLDA) +DECLARE_INSN(smslxda, MATCH_SMSLXDA, MASK_SMSLXDA) +DECLARE_INSN(smsr64, MATCH_SMSR64, MASK_SMSR64) +DECLARE_INSN(smtt16, MATCH_SMTT16, MASK_SMTT16) +DECLARE_INSN(smtt32, MATCH_SMTT32, MASK_SMTT32) +DECLARE_INSN(smul16, MATCH_SMUL16, MASK_SMUL16) +DECLARE_INSN(smul8, MATCH_SMUL8, MASK_SMUL8) +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) +DECLARE_INSN(sra32, MATCH_SRA32, MASK_SRA32) +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) +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_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) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(srl16, MATCH_SRL16, MASK_SRL16) +DECLARE_INSN(srl16_u, MATCH_SRL16_U, MASK_SRL16_U) +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) +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(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sro, MATCH_SRO, MASK_SRO) +DECLARE_INSN(sroi, MATCH_SROI, MASK_SROI) +DECLARE_INSN(sroiw, MATCH_SROIW, MASK_SROIW) +DECLARE_INSN(srow, MATCH_SROW, MASK_SROW) +DECLARE_INSN(stas16, MATCH_STAS16, MASK_STAS16) +DECLARE_INSN(stas32, MATCH_STAS32, MASK_STAS32) +DECLARE_INSN(stsa16, MATCH_STSA16, MASK_STSA16) +DECLARE_INSN(stsa32, MATCH_STSA32, MASK_STSA32) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +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) +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) +DECLARE_INSN(ucmple16, MATCH_UCMPLE16, MASK_UCMPLE16) +DECLARE_INSN(ucmple8, MATCH_UCMPLE8, MASK_UCMPLE8) +DECLARE_INSN(ucmplt16, MATCH_UCMPLT16, MASK_UCMPLT16) +DECLARE_INSN(ucmplt8, MATCH_UCMPLT8, MASK_UCMPLT8) +DECLARE_INSN(ukadd16, MATCH_UKADD16, MASK_UKADD16) +DECLARE_INSN(ukadd32, MATCH_UKADD32, MASK_UKADD32) +DECLARE_INSN(ukadd64, MATCH_UKADD64, MASK_UKADD64) +DECLARE_INSN(ukadd8, MATCH_UKADD8, MASK_UKADD8) +DECLARE_INSN(ukaddh, MATCH_UKADDH, MASK_UKADDH) +DECLARE_INSN(ukaddw, MATCH_UKADDW, MASK_UKADDW) +DECLARE_INSN(ukcras16, MATCH_UKCRAS16, MASK_UKCRAS16) +DECLARE_INSN(ukcras32, MATCH_UKCRAS32, MASK_UKCRAS32) +DECLARE_INSN(ukcrsa16, MATCH_UKCRSA16, MASK_UKCRSA16) +DECLARE_INSN(ukcrsa32, MATCH_UKCRSA32, MASK_UKCRSA32) +DECLARE_INSN(ukmar64, MATCH_UKMAR64, MASK_UKMAR64) +DECLARE_INSN(ukmsr64, MATCH_UKMSR64, MASK_UKMSR64) +DECLARE_INSN(ukstas16, MATCH_UKSTAS16, MASK_UKSTAS16) +DECLARE_INSN(ukstas32, MATCH_UKSTAS32, MASK_UKSTAS32) +DECLARE_INSN(ukstsa16, MATCH_UKSTSA16, MASK_UKSTSA16) +DECLARE_INSN(ukstsa32, MATCH_UKSTSA32, MASK_UKSTSA32) +DECLARE_INSN(uksub16, MATCH_UKSUB16, MASK_UKSUB16) +DECLARE_INSN(uksub32, MATCH_UKSUB32, MASK_UKSUB32) +DECLARE_INSN(uksub64, MATCH_UKSUB64, MASK_UKSUB64) +DECLARE_INSN(uksub8, MATCH_UKSUB8, MASK_UKSUB8) +DECLARE_INSN(uksubh, MATCH_UKSUBH, MASK_UKSUBH) +DECLARE_INSN(uksubw, MATCH_UKSUBW, MASK_UKSUBW) +DECLARE_INSN(umaqa, MATCH_UMAQA, MASK_UMAQA) +DECLARE_INSN(umar64, MATCH_UMAR64, MASK_UMAR64) +DECLARE_INSN(umax16, MATCH_UMAX16, MASK_UMAX16) +DECLARE_INSN(umax32, MATCH_UMAX32, MASK_UMAX32) +DECLARE_INSN(umax8, MATCH_UMAX8, MASK_UMAX8) +DECLARE_INSN(umin16, MATCH_UMIN16, MASK_UMIN16) +DECLARE_INSN(umin32, MATCH_UMIN32, MASK_UMIN32) +DECLARE_INSN(umin8, MATCH_UMIN8, MASK_UMIN8) +DECLARE_INSN(umsr64, MATCH_UMSR64, MASK_UMSR64) +DECLARE_INSN(umul16, MATCH_UMUL16, MASK_UMUL16) +DECLARE_INSN(umul8, MATCH_UMUL8, MASK_UMUL8) +DECLARE_INSN(umulx16, MATCH_UMULX16, MASK_UMULX16) +DECLARE_INSN(umulx8, MATCH_UMULX8, MASK_UMULX8) +DECLARE_INSN(unshfl, MATCH_UNSHFL, MASK_UNSHFL) +DECLARE_INSN(unshfli, MATCH_UNSHFLI, MASK_UNSHFLI) +DECLARE_INSN(unshflw, MATCH_UNSHFLW, MASK_UNSHFLW) +DECLARE_INSN(uradd16, MATCH_URADD16, MASK_URADD16) +DECLARE_INSN(uradd32, MATCH_URADD32, MASK_URADD32) +DECLARE_INSN(uradd64, MATCH_URADD64, MASK_URADD64) +DECLARE_INSN(uradd8, MATCH_URADD8, MASK_URADD8) +DECLARE_INSN(uraddw, MATCH_URADDW, MASK_URADDW) +DECLARE_INSN(urcras16, MATCH_URCRAS16, MASK_URCRAS16) +DECLARE_INSN(urcras32, MATCH_URCRAS32, MASK_URCRAS32) +DECLARE_INSN(urcrsa16, MATCH_URCRSA16, MASK_URCRSA16) +DECLARE_INSN(urcrsa32, MATCH_URCRSA32, MASK_URCRSA32) +DECLARE_INSN(urstas16, MATCH_URSTAS16, MASK_URSTAS16) +DECLARE_INSN(urstas32, MATCH_URSTAS32, MASK_URSTAS32) +DECLARE_INSN(urstsa16, MATCH_URSTSA16, MASK_URSTSA16) +DECLARE_INSN(urstsa32, MATCH_URSTSA32, MASK_URSTSA32) +DECLARE_INSN(ursub16, MATCH_URSUB16, MASK_URSUB16) +DECLARE_INSN(ursub32, MATCH_URSUB32, MASK_URSUB32) +DECLARE_INSN(ursub64, MATCH_URSUB64, MASK_URSUB64) +DECLARE_INSN(ursub8, MATCH_URSUB8, MASK_URSUB8) +DECLARE_INSN(ursubw, MATCH_URSUBW, MASK_URSUBW) +DECLARE_INSN(vaadd_vv, MATCH_VAADD_VV, MASK_VAADD_VV) +DECLARE_INSN(vaadd_vx, MATCH_VAADD_VX, MASK_VAADD_VX) +DECLARE_INSN(vaaddu_vv, MATCH_VAADDU_VV, MASK_VAADDU_VV) +DECLARE_INSN(vaaddu_vx, MATCH_VAADDU_VX, MASK_VAADDU_VX) +DECLARE_INSN(vadc_vim, MATCH_VADC_VIM, MASK_VADC_VIM) +DECLARE_INSN(vadc_vvm, MATCH_VADC_VVM, MASK_VADC_VVM) +DECLARE_INSN(vadc_vxm, MATCH_VADC_VXM, MASK_VADC_VXM) +DECLARE_INSN(vadd_vi, MATCH_VADD_VI, MASK_VADD_VI) +DECLARE_INSN(vadd_vv, MATCH_VADD_VV, MASK_VADD_VV) +DECLARE_INSN(vadd_vx, MATCH_VADD_VX, MASK_VADD_VX) +DECLARE_INSN(vamoaddei16_v, MATCH_VAMOADDEI16_V, MASK_VAMOADDEI16_V) +DECLARE_INSN(vamoaddei32_v, MATCH_VAMOADDEI32_V, MASK_VAMOADDEI32_V) +DECLARE_INSN(vamoaddei64_v, MATCH_VAMOADDEI64_V, MASK_VAMOADDEI64_V) +DECLARE_INSN(vamoaddei8_v, MATCH_VAMOADDEI8_V, MASK_VAMOADDEI8_V) +DECLARE_INSN(vamoandei16_v, MATCH_VAMOANDEI16_V, MASK_VAMOANDEI16_V) +DECLARE_INSN(vamoandei32_v, MATCH_VAMOANDEI32_V, MASK_VAMOANDEI32_V) +DECLARE_INSN(vamoandei64_v, MATCH_VAMOANDEI64_V, MASK_VAMOANDEI64_V) +DECLARE_INSN(vamoandei8_v, MATCH_VAMOANDEI8_V, MASK_VAMOANDEI8_V) +DECLARE_INSN(vamomaxei16_v, MATCH_VAMOMAXEI16_V, MASK_VAMOMAXEI16_V) +DECLARE_INSN(vamomaxei32_v, MATCH_VAMOMAXEI32_V, MASK_VAMOMAXEI32_V) +DECLARE_INSN(vamomaxei64_v, MATCH_VAMOMAXEI64_V, MASK_VAMOMAXEI64_V) +DECLARE_INSN(vamomaxei8_v, MATCH_VAMOMAXEI8_V, MASK_VAMOMAXEI8_V) +DECLARE_INSN(vamomaxuei16_v, MATCH_VAMOMAXUEI16_V, MASK_VAMOMAXUEI16_V) +DECLARE_INSN(vamomaxuei32_v, MATCH_VAMOMAXUEI32_V, MASK_VAMOMAXUEI32_V) +DECLARE_INSN(vamomaxuei64_v, MATCH_VAMOMAXUEI64_V, MASK_VAMOMAXUEI64_V) +DECLARE_INSN(vamomaxuei8_v, MATCH_VAMOMAXUEI8_V, MASK_VAMOMAXUEI8_V) +DECLARE_INSN(vamominei16_v, MATCH_VAMOMINEI16_V, MASK_VAMOMINEI16_V) +DECLARE_INSN(vamominei32_v, MATCH_VAMOMINEI32_V, MASK_VAMOMINEI32_V) +DECLARE_INSN(vamominei64_v, MATCH_VAMOMINEI64_V, MASK_VAMOMINEI64_V) +DECLARE_INSN(vamominei8_v, MATCH_VAMOMINEI8_V, MASK_VAMOMINEI8_V) +DECLARE_INSN(vamominuei16_v, MATCH_VAMOMINUEI16_V, MASK_VAMOMINUEI16_V) +DECLARE_INSN(vamominuei32_v, MATCH_VAMOMINUEI32_V, MASK_VAMOMINUEI32_V) +DECLARE_INSN(vamominuei64_v, MATCH_VAMOMINUEI64_V, MASK_VAMOMINUEI64_V) +DECLARE_INSN(vamominuei8_v, MATCH_VAMOMINUEI8_V, MASK_VAMOMINUEI8_V) +DECLARE_INSN(vamoorei16_v, MATCH_VAMOOREI16_V, MASK_VAMOOREI16_V) +DECLARE_INSN(vamoorei32_v, MATCH_VAMOOREI32_V, MASK_VAMOOREI32_V) +DECLARE_INSN(vamoorei64_v, MATCH_VAMOOREI64_V, MASK_VAMOOREI64_V) +DECLARE_INSN(vamoorei8_v, MATCH_VAMOOREI8_V, MASK_VAMOOREI8_V) +DECLARE_INSN(vamoswapei16_v, MATCH_VAMOSWAPEI16_V, MASK_VAMOSWAPEI16_V) +DECLARE_INSN(vamoswapei32_v, MATCH_VAMOSWAPEI32_V, MASK_VAMOSWAPEI32_V) +DECLARE_INSN(vamoswapei64_v, MATCH_VAMOSWAPEI64_V, MASK_VAMOSWAPEI64_V) +DECLARE_INSN(vamoswapei8_v, MATCH_VAMOSWAPEI8_V, MASK_VAMOSWAPEI8_V) +DECLARE_INSN(vamoxorei16_v, MATCH_VAMOXOREI16_V, MASK_VAMOXOREI16_V) +DECLARE_INSN(vamoxorei32_v, MATCH_VAMOXOREI32_V, MASK_VAMOXOREI32_V) +DECLARE_INSN(vamoxorei64_v, MATCH_VAMOXOREI64_V, MASK_VAMOXOREI64_V) +DECLARE_INSN(vamoxorei8_v, MATCH_VAMOXOREI8_V, MASK_VAMOXOREI8_V) +DECLARE_INSN(vand_vi, MATCH_VAND_VI, MASK_VAND_VI) +DECLARE_INSN(vand_vv, MATCH_VAND_VV, MASK_VAND_VV) +DECLARE_INSN(vand_vx, MATCH_VAND_VX, MASK_VAND_VX) +DECLARE_INSN(vasub_vv, MATCH_VASUB_VV, MASK_VASUB_VV) +DECLARE_INSN(vasub_vx, MATCH_VASUB_VX, MASK_VASUB_VX) +DECLARE_INSN(vasubu_vv, MATCH_VASUBU_VV, MASK_VASUBU_VV) +DECLARE_INSN(vasubu_vx, MATCH_VASUBU_VX, MASK_VASUBU_VX) +DECLARE_INSN(vcompress_vm, MATCH_VCOMPRESS_VM, MASK_VCOMPRESS_VM) +DECLARE_INSN(vcpop_m, MATCH_VCPOP_M, MASK_VCPOP_M) +DECLARE_INSN(vdiv_vv, MATCH_VDIV_VV, MASK_VDIV_VV) +DECLARE_INSN(vdiv_vx, MATCH_VDIV_VX, MASK_VDIV_VX) +DECLARE_INSN(vdivu_vv, MATCH_VDIVU_VV, MASK_VDIVU_VV) +DECLARE_INSN(vdivu_vx, MATCH_VDIVU_VX, MASK_VDIVU_VX) +DECLARE_INSN(vfadd_vf, MATCH_VFADD_VF, MASK_VFADD_VF) +DECLARE_INSN(vfadd_vv, MATCH_VFADD_VV, MASK_VFADD_VV) +DECLARE_INSN(vfclass_v, MATCH_VFCLASS_V, MASK_VFCLASS_V) +DECLARE_INSN(vfcvt_f_x_v, MATCH_VFCVT_F_X_V, MASK_VFCVT_F_X_V) +DECLARE_INSN(vfcvt_f_xu_v, MATCH_VFCVT_F_XU_V, MASK_VFCVT_F_XU_V) +DECLARE_INSN(vfcvt_rtz_x_f_v, MATCH_VFCVT_RTZ_X_F_V, MASK_VFCVT_RTZ_X_F_V) +DECLARE_INSN(vfcvt_rtz_xu_f_v, MATCH_VFCVT_RTZ_XU_F_V, MASK_VFCVT_RTZ_XU_F_V) +DECLARE_INSN(vfcvt_x_f_v, MATCH_VFCVT_X_F_V, MASK_VFCVT_X_F_V) +DECLARE_INSN(vfcvt_xu_f_v, MATCH_VFCVT_XU_F_V, MASK_VFCVT_XU_F_V) +DECLARE_INSN(vfdiv_vf, MATCH_VFDIV_VF, MASK_VFDIV_VF) +DECLARE_INSN(vfdiv_vv, MATCH_VFDIV_VV, MASK_VFDIV_VV) +DECLARE_INSN(vfirst_m, MATCH_VFIRST_M, MASK_VFIRST_M) +DECLARE_INSN(vfmacc_vf, MATCH_VFMACC_VF, MASK_VFMACC_VF) +DECLARE_INSN(vfmacc_vv, MATCH_VFMACC_VV, MASK_VFMACC_VV) +DECLARE_INSN(vfmadd_vf, MATCH_VFMADD_VF, MASK_VFMADD_VF) +DECLARE_INSN(vfmadd_vv, MATCH_VFMADD_VV, MASK_VFMADD_VV) +DECLARE_INSN(vfmax_vf, MATCH_VFMAX_VF, MASK_VFMAX_VF) +DECLARE_INSN(vfmax_vv, MATCH_VFMAX_VV, MASK_VFMAX_VV) +DECLARE_INSN(vfmerge_vfm, MATCH_VFMERGE_VFM, MASK_VFMERGE_VFM) +DECLARE_INSN(vfmin_vf, MATCH_VFMIN_VF, MASK_VFMIN_VF) +DECLARE_INSN(vfmin_vv, MATCH_VFMIN_VV, MASK_VFMIN_VV) +DECLARE_INSN(vfmsac_vf, MATCH_VFMSAC_VF, MASK_VFMSAC_VF) +DECLARE_INSN(vfmsac_vv, MATCH_VFMSAC_VV, MASK_VFMSAC_VV) +DECLARE_INSN(vfmsub_vf, MATCH_VFMSUB_VF, MASK_VFMSUB_VF) +DECLARE_INSN(vfmsub_vv, MATCH_VFMSUB_VV, MASK_VFMSUB_VV) +DECLARE_INSN(vfmul_vf, MATCH_VFMUL_VF, MASK_VFMUL_VF) +DECLARE_INSN(vfmul_vv, MATCH_VFMUL_VV, MASK_VFMUL_VV) +DECLARE_INSN(vfmv_f_s, MATCH_VFMV_F_S, MASK_VFMV_F_S) +DECLARE_INSN(vfmv_s_f, MATCH_VFMV_S_F, MASK_VFMV_S_F) +DECLARE_INSN(vfmv_v_f, MATCH_VFMV_V_F, MASK_VFMV_V_F) +DECLARE_INSN(vfncvt_f_f_w, MATCH_VFNCVT_F_F_W, MASK_VFNCVT_F_F_W) +DECLARE_INSN(vfncvt_f_x_w, MATCH_VFNCVT_F_X_W, MASK_VFNCVT_F_X_W) +DECLARE_INSN(vfncvt_f_xu_w, MATCH_VFNCVT_F_XU_W, MASK_VFNCVT_F_XU_W) +DECLARE_INSN(vfncvt_rod_f_f_w, MATCH_VFNCVT_ROD_F_F_W, MASK_VFNCVT_ROD_F_F_W) +DECLARE_INSN(vfncvt_rtz_x_f_w, MATCH_VFNCVT_RTZ_X_F_W, MASK_VFNCVT_RTZ_X_F_W) +DECLARE_INSN(vfncvt_rtz_xu_f_w, MATCH_VFNCVT_RTZ_XU_F_W, MASK_VFNCVT_RTZ_XU_F_W) +DECLARE_INSN(vfncvt_x_f_w, MATCH_VFNCVT_X_F_W, MASK_VFNCVT_X_F_W) +DECLARE_INSN(vfncvt_xu_f_w, MATCH_VFNCVT_XU_F_W, MASK_VFNCVT_XU_F_W) +DECLARE_INSN(vfnmacc_vf, MATCH_VFNMACC_VF, MASK_VFNMACC_VF) +DECLARE_INSN(vfnmacc_vv, MATCH_VFNMACC_VV, MASK_VFNMACC_VV) +DECLARE_INSN(vfnmadd_vf, MATCH_VFNMADD_VF, MASK_VFNMADD_VF) +DECLARE_INSN(vfnmadd_vv, MATCH_VFNMADD_VV, MASK_VFNMADD_VV) +DECLARE_INSN(vfnmsac_vf, MATCH_VFNMSAC_VF, MASK_VFNMSAC_VF) +DECLARE_INSN(vfnmsac_vv, MATCH_VFNMSAC_VV, MASK_VFNMSAC_VV) +DECLARE_INSN(vfnmsub_vf, MATCH_VFNMSUB_VF, MASK_VFNMSUB_VF) +DECLARE_INSN(vfnmsub_vv, MATCH_VFNMSUB_VV, MASK_VFNMSUB_VV) +DECLARE_INSN(vfrdiv_vf, MATCH_VFRDIV_VF, MASK_VFRDIV_VF) +DECLARE_INSN(vfrec7_v, MATCH_VFREC7_V, MASK_VFREC7_V) +DECLARE_INSN(vfredmax_vs, MATCH_VFREDMAX_VS, MASK_VFREDMAX_VS) +DECLARE_INSN(vfredmin_vs, MATCH_VFREDMIN_VS, MASK_VFREDMIN_VS) +DECLARE_INSN(vfredosum_vs, MATCH_VFREDOSUM_VS, MASK_VFREDOSUM_VS) +DECLARE_INSN(vfredusum_vs, MATCH_VFREDUSUM_VS, MASK_VFREDUSUM_VS) +DECLARE_INSN(vfrsqrt7_v, MATCH_VFRSQRT7_V, MASK_VFRSQRT7_V) +DECLARE_INSN(vfrsub_vf, MATCH_VFRSUB_VF, MASK_VFRSUB_VF) +DECLARE_INSN(vfsgnj_vf, MATCH_VFSGNJ_VF, MASK_VFSGNJ_VF) +DECLARE_INSN(vfsgnj_vv, MATCH_VFSGNJ_VV, MASK_VFSGNJ_VV) +DECLARE_INSN(vfsgnjn_vf, MATCH_VFSGNJN_VF, MASK_VFSGNJN_VF) +DECLARE_INSN(vfsgnjn_vv, MATCH_VFSGNJN_VV, MASK_VFSGNJN_VV) +DECLARE_INSN(vfsgnjx_vf, MATCH_VFSGNJX_VF, MASK_VFSGNJX_VF) +DECLARE_INSN(vfsgnjx_vv, MATCH_VFSGNJX_VV, MASK_VFSGNJX_VV) +DECLARE_INSN(vfslide1down_vf, MATCH_VFSLIDE1DOWN_VF, MASK_VFSLIDE1DOWN_VF) +DECLARE_INSN(vfslide1up_vf, MATCH_VFSLIDE1UP_VF, MASK_VFSLIDE1UP_VF) +DECLARE_INSN(vfsqrt_v, MATCH_VFSQRT_V, MASK_VFSQRT_V) +DECLARE_INSN(vfsub_vf, MATCH_VFSUB_VF, MASK_VFSUB_VF) +DECLARE_INSN(vfsub_vv, MATCH_VFSUB_VV, MASK_VFSUB_VV) +DECLARE_INSN(vfwadd_vf, MATCH_VFWADD_VF, MASK_VFWADD_VF) +DECLARE_INSN(vfwadd_vv, MATCH_VFWADD_VV, MASK_VFWADD_VV) +DECLARE_INSN(vfwadd_wf, MATCH_VFWADD_WF, MASK_VFWADD_WF) +DECLARE_INSN(vfwadd_wv, MATCH_VFWADD_WV, MASK_VFWADD_WV) +DECLARE_INSN(vfwcvt_f_f_v, MATCH_VFWCVT_F_F_V, MASK_VFWCVT_F_F_V) +DECLARE_INSN(vfwcvt_f_x_v, MATCH_VFWCVT_F_X_V, MASK_VFWCVT_F_X_V) +DECLARE_INSN(vfwcvt_f_xu_v, MATCH_VFWCVT_F_XU_V, MASK_VFWCVT_F_XU_V) +DECLARE_INSN(vfwcvt_rtz_x_f_v, MATCH_VFWCVT_RTZ_X_F_V, MASK_VFWCVT_RTZ_X_F_V) +DECLARE_INSN(vfwcvt_rtz_xu_f_v, MATCH_VFWCVT_RTZ_XU_F_V, MASK_VFWCVT_RTZ_XU_F_V) +DECLARE_INSN(vfwcvt_x_f_v, MATCH_VFWCVT_X_F_V, MASK_VFWCVT_X_F_V) +DECLARE_INSN(vfwcvt_xu_f_v, MATCH_VFWCVT_XU_F_V, MASK_VFWCVT_XU_F_V) +DECLARE_INSN(vfwmacc_vf, MATCH_VFWMACC_VF, MASK_VFWMACC_VF) +DECLARE_INSN(vfwmacc_vv, MATCH_VFWMACC_VV, MASK_VFWMACC_VV) +DECLARE_INSN(vfwmsac_vf, MATCH_VFWMSAC_VF, MASK_VFWMSAC_VF) +DECLARE_INSN(vfwmsac_vv, MATCH_VFWMSAC_VV, MASK_VFWMSAC_VV) +DECLARE_INSN(vfwmul_vf, MATCH_VFWMUL_VF, MASK_VFWMUL_VF) +DECLARE_INSN(vfwmul_vv, MATCH_VFWMUL_VV, MASK_VFWMUL_VV) +DECLARE_INSN(vfwnmacc_vf, MATCH_VFWNMACC_VF, MASK_VFWNMACC_VF) +DECLARE_INSN(vfwnmacc_vv, MATCH_VFWNMACC_VV, MASK_VFWNMACC_VV) +DECLARE_INSN(vfwnmsac_vf, MATCH_VFWNMSAC_VF, MASK_VFWNMSAC_VF) +DECLARE_INSN(vfwnmsac_vv, MATCH_VFWNMSAC_VV, MASK_VFWNMSAC_VV) +DECLARE_INSN(vfwredosum_vs, MATCH_VFWREDOSUM_VS, MASK_VFWREDOSUM_VS) +DECLARE_INSN(vfwredusum_vs, MATCH_VFWREDUSUM_VS, MASK_VFWREDUSUM_VS) +DECLARE_INSN(vfwsub_vf, MATCH_VFWSUB_VF, MASK_VFWSUB_VF) +DECLARE_INSN(vfwsub_vv, MATCH_VFWSUB_VV, MASK_VFWSUB_VV) +DECLARE_INSN(vfwsub_wf, MATCH_VFWSUB_WF, MASK_VFWSUB_WF) +DECLARE_INSN(vfwsub_wv, MATCH_VFWSUB_WV, MASK_VFWSUB_WV) +DECLARE_INSN(vid_v, MATCH_VID_V, MASK_VID_V) +DECLARE_INSN(viota_m, MATCH_VIOTA_M, MASK_VIOTA_M) +DECLARE_INSN(vl1re16_v, MATCH_VL1RE16_V, MASK_VL1RE16_V) +DECLARE_INSN(vl1re32_v, MATCH_VL1RE32_V, MASK_VL1RE32_V) +DECLARE_INSN(vl1re64_v, MATCH_VL1RE64_V, MASK_VL1RE64_V) +DECLARE_INSN(vl1re8_v, MATCH_VL1RE8_V, MASK_VL1RE8_V) +DECLARE_INSN(vl2re16_v, MATCH_VL2RE16_V, MASK_VL2RE16_V) +DECLARE_INSN(vl2re32_v, MATCH_VL2RE32_V, MASK_VL2RE32_V) +DECLARE_INSN(vl2re64_v, MATCH_VL2RE64_V, MASK_VL2RE64_V) +DECLARE_INSN(vl2re8_v, MATCH_VL2RE8_V, MASK_VL2RE8_V) +DECLARE_INSN(vl4re16_v, MATCH_VL4RE16_V, MASK_VL4RE16_V) +DECLARE_INSN(vl4re32_v, MATCH_VL4RE32_V, MASK_VL4RE32_V) +DECLARE_INSN(vl4re64_v, MATCH_VL4RE64_V, MASK_VL4RE64_V) +DECLARE_INSN(vl4re8_v, MATCH_VL4RE8_V, MASK_VL4RE8_V) +DECLARE_INSN(vl8re16_v, MATCH_VL8RE16_V, MASK_VL8RE16_V) +DECLARE_INSN(vl8re32_v, MATCH_VL8RE32_V, MASK_VL8RE32_V) +DECLARE_INSN(vl8re64_v, MATCH_VL8RE64_V, MASK_VL8RE64_V) +DECLARE_INSN(vl8re8_v, MATCH_VL8RE8_V, MASK_VL8RE8_V) +DECLARE_INSN(vle1024_v, MATCH_VLE1024_V, MASK_VLE1024_V) +DECLARE_INSN(vle1024ff_v, MATCH_VLE1024FF_V, MASK_VLE1024FF_V) +DECLARE_INSN(vle128_v, MATCH_VLE128_V, MASK_VLE128_V) +DECLARE_INSN(vle128ff_v, MATCH_VLE128FF_V, MASK_VLE128FF_V) +DECLARE_INSN(vle16_v, MATCH_VLE16_V, MASK_VLE16_V) +DECLARE_INSN(vle16ff_v, MATCH_VLE16FF_V, MASK_VLE16FF_V) +DECLARE_INSN(vle256_v, MATCH_VLE256_V, MASK_VLE256_V) +DECLARE_INSN(vle256ff_v, MATCH_VLE256FF_V, MASK_VLE256FF_V) +DECLARE_INSN(vle32_v, MATCH_VLE32_V, MASK_VLE32_V) +DECLARE_INSN(vle32ff_v, MATCH_VLE32FF_V, MASK_VLE32FF_V) +DECLARE_INSN(vle512_v, MATCH_VLE512_V, MASK_VLE512_V) +DECLARE_INSN(vle512ff_v, MATCH_VLE512FF_V, MASK_VLE512FF_V) +DECLARE_INSN(vle64_v, MATCH_VLE64_V, MASK_VLE64_V) +DECLARE_INSN(vle64ff_v, MATCH_VLE64FF_V, MASK_VLE64FF_V) +DECLARE_INSN(vle8_v, MATCH_VLE8_V, MASK_VLE8_V) +DECLARE_INSN(vle8ff_v, MATCH_VLE8FF_V, MASK_VLE8FF_V) +DECLARE_INSN(vlm_v, MATCH_VLM_V, MASK_VLM_V) +DECLARE_INSN(vloxei1024_v, MATCH_VLOXEI1024_V, MASK_VLOXEI1024_V) +DECLARE_INSN(vloxei128_v, MATCH_VLOXEI128_V, MASK_VLOXEI128_V) +DECLARE_INSN(vloxei16_v, MATCH_VLOXEI16_V, MASK_VLOXEI16_V) +DECLARE_INSN(vloxei256_v, MATCH_VLOXEI256_V, MASK_VLOXEI256_V) +DECLARE_INSN(vloxei32_v, MATCH_VLOXEI32_V, MASK_VLOXEI32_V) +DECLARE_INSN(vloxei512_v, MATCH_VLOXEI512_V, MASK_VLOXEI512_V) +DECLARE_INSN(vloxei64_v, MATCH_VLOXEI64_V, MASK_VLOXEI64_V) +DECLARE_INSN(vloxei8_v, MATCH_VLOXEI8_V, MASK_VLOXEI8_V) +DECLARE_INSN(vlse1024_v, MATCH_VLSE1024_V, MASK_VLSE1024_V) +DECLARE_INSN(vlse128_v, MATCH_VLSE128_V, MASK_VLSE128_V) +DECLARE_INSN(vlse16_v, MATCH_VLSE16_V, MASK_VLSE16_V) +DECLARE_INSN(vlse256_v, MATCH_VLSE256_V, MASK_VLSE256_V) +DECLARE_INSN(vlse32_v, MATCH_VLSE32_V, MASK_VLSE32_V) +DECLARE_INSN(vlse512_v, MATCH_VLSE512_V, MASK_VLSE512_V) +DECLARE_INSN(vlse64_v, MATCH_VLSE64_V, MASK_VLSE64_V) +DECLARE_INSN(vlse8_v, MATCH_VLSE8_V, MASK_VLSE8_V) +DECLARE_INSN(vluxei1024_v, MATCH_VLUXEI1024_V, MASK_VLUXEI1024_V) +DECLARE_INSN(vluxei128_v, MATCH_VLUXEI128_V, MASK_VLUXEI128_V) +DECLARE_INSN(vluxei16_v, MATCH_VLUXEI16_V, MASK_VLUXEI16_V) +DECLARE_INSN(vluxei256_v, MATCH_VLUXEI256_V, MASK_VLUXEI256_V) +DECLARE_INSN(vluxei32_v, MATCH_VLUXEI32_V, MASK_VLUXEI32_V) +DECLARE_INSN(vluxei512_v, MATCH_VLUXEI512_V, MASK_VLUXEI512_V) +DECLARE_INSN(vluxei64_v, MATCH_VLUXEI64_V, MASK_VLUXEI64_V) +DECLARE_INSN(vluxei8_v, MATCH_VLUXEI8_V, MASK_VLUXEI8_V) +DECLARE_INSN(vmacc_vv, MATCH_VMACC_VV, MASK_VMACC_VV) +DECLARE_INSN(vmacc_vx, MATCH_VMACC_VX, MASK_VMACC_VX) +DECLARE_INSN(vmadc_vi, MATCH_VMADC_VI, MASK_VMADC_VI) +DECLARE_INSN(vmadc_vim, MATCH_VMADC_VIM, MASK_VMADC_VIM) +DECLARE_INSN(vmadc_vv, MATCH_VMADC_VV, MASK_VMADC_VV) +DECLARE_INSN(vmadc_vvm, MATCH_VMADC_VVM, MASK_VMADC_VVM) +DECLARE_INSN(vmadc_vx, MATCH_VMADC_VX, MASK_VMADC_VX) +DECLARE_INSN(vmadc_vxm, MATCH_VMADC_VXM, MASK_VMADC_VXM) +DECLARE_INSN(vmadd_vv, MATCH_VMADD_VV, MASK_VMADD_VV) +DECLARE_INSN(vmadd_vx, MATCH_VMADD_VX, MASK_VMADD_VX) +DECLARE_INSN(vmand_mm, MATCH_VMAND_MM, MASK_VMAND_MM) +DECLARE_INSN(vmandn_mm, MATCH_VMANDN_MM, MASK_VMANDN_MM) +DECLARE_INSN(vmax_vv, MATCH_VMAX_VV, MASK_VMAX_VV) +DECLARE_INSN(vmax_vx, MATCH_VMAX_VX, MASK_VMAX_VX) +DECLARE_INSN(vmaxu_vv, MATCH_VMAXU_VV, MASK_VMAXU_VV) +DECLARE_INSN(vmaxu_vx, MATCH_VMAXU_VX, MASK_VMAXU_VX) +DECLARE_INSN(vmerge_vim, MATCH_VMERGE_VIM, MASK_VMERGE_VIM) +DECLARE_INSN(vmerge_vvm, MATCH_VMERGE_VVM, MASK_VMERGE_VVM) +DECLARE_INSN(vmerge_vxm, MATCH_VMERGE_VXM, MASK_VMERGE_VXM) +DECLARE_INSN(vmfeq_vf, MATCH_VMFEQ_VF, MASK_VMFEQ_VF) +DECLARE_INSN(vmfeq_vv, MATCH_VMFEQ_VV, MASK_VMFEQ_VV) +DECLARE_INSN(vmfge_vf, MATCH_VMFGE_VF, MASK_VMFGE_VF) +DECLARE_INSN(vmfgt_vf, MATCH_VMFGT_VF, MASK_VMFGT_VF) +DECLARE_INSN(vmfle_vf, MATCH_VMFLE_VF, MASK_VMFLE_VF) +DECLARE_INSN(vmfle_vv, MATCH_VMFLE_VV, MASK_VMFLE_VV) +DECLARE_INSN(vmflt_vf, MATCH_VMFLT_VF, MASK_VMFLT_VF) +DECLARE_INSN(vmflt_vv, MATCH_VMFLT_VV, MASK_VMFLT_VV) +DECLARE_INSN(vmfne_vf, MATCH_VMFNE_VF, MASK_VMFNE_VF) +DECLARE_INSN(vmfne_vv, MATCH_VMFNE_VV, MASK_VMFNE_VV) +DECLARE_INSN(vmin_vv, MATCH_VMIN_VV, MASK_VMIN_VV) +DECLARE_INSN(vmin_vx, MATCH_VMIN_VX, MASK_VMIN_VX) +DECLARE_INSN(vminu_vv, MATCH_VMINU_VV, MASK_VMINU_VV) +DECLARE_INSN(vminu_vx, MATCH_VMINU_VX, MASK_VMINU_VX) +DECLARE_INSN(vmnand_mm, MATCH_VMNAND_MM, MASK_VMNAND_MM) +DECLARE_INSN(vmnor_mm, MATCH_VMNOR_MM, MASK_VMNOR_MM) +DECLARE_INSN(vmor_mm, MATCH_VMOR_MM, MASK_VMOR_MM) +DECLARE_INSN(vmorn_mm, MATCH_VMORN_MM, MASK_VMORN_MM) +DECLARE_INSN(vmsbc_vv, MATCH_VMSBC_VV, MASK_VMSBC_VV) +DECLARE_INSN(vmsbc_vvm, MATCH_VMSBC_VVM, MASK_VMSBC_VVM) +DECLARE_INSN(vmsbc_vx, MATCH_VMSBC_VX, MASK_VMSBC_VX) +DECLARE_INSN(vmsbc_vxm, MATCH_VMSBC_VXM, MASK_VMSBC_VXM) +DECLARE_INSN(vmsbf_m, MATCH_VMSBF_M, MASK_VMSBF_M) +DECLARE_INSN(vmseq_vi, MATCH_VMSEQ_VI, MASK_VMSEQ_VI) +DECLARE_INSN(vmseq_vv, MATCH_VMSEQ_VV, MASK_VMSEQ_VV) +DECLARE_INSN(vmseq_vx, MATCH_VMSEQ_VX, MASK_VMSEQ_VX) +DECLARE_INSN(vmsgt_vi, MATCH_VMSGT_VI, MASK_VMSGT_VI) +DECLARE_INSN(vmsgt_vx, MATCH_VMSGT_VX, MASK_VMSGT_VX) +DECLARE_INSN(vmsgtu_vi, MATCH_VMSGTU_VI, MASK_VMSGTU_VI) +DECLARE_INSN(vmsgtu_vx, MATCH_VMSGTU_VX, MASK_VMSGTU_VX) +DECLARE_INSN(vmsif_m, MATCH_VMSIF_M, MASK_VMSIF_M) +DECLARE_INSN(vmsle_vi, MATCH_VMSLE_VI, MASK_VMSLE_VI) +DECLARE_INSN(vmsle_vv, MATCH_VMSLE_VV, MASK_VMSLE_VV) +DECLARE_INSN(vmsle_vx, MATCH_VMSLE_VX, MASK_VMSLE_VX) +DECLARE_INSN(vmsleu_vi, MATCH_VMSLEU_VI, MASK_VMSLEU_VI) +DECLARE_INSN(vmsleu_vv, MATCH_VMSLEU_VV, MASK_VMSLEU_VV) +DECLARE_INSN(vmsleu_vx, MATCH_VMSLEU_VX, MASK_VMSLEU_VX) +DECLARE_INSN(vmslt_vv, MATCH_VMSLT_VV, MASK_VMSLT_VV) +DECLARE_INSN(vmslt_vx, MATCH_VMSLT_VX, MASK_VMSLT_VX) +DECLARE_INSN(vmsltu_vv, MATCH_VMSLTU_VV, MASK_VMSLTU_VV) +DECLARE_INSN(vmsltu_vx, MATCH_VMSLTU_VX, MASK_VMSLTU_VX) +DECLARE_INSN(vmsne_vi, MATCH_VMSNE_VI, MASK_VMSNE_VI) +DECLARE_INSN(vmsne_vv, MATCH_VMSNE_VV, MASK_VMSNE_VV) +DECLARE_INSN(vmsne_vx, MATCH_VMSNE_VX, MASK_VMSNE_VX) +DECLARE_INSN(vmsof_m, MATCH_VMSOF_M, MASK_VMSOF_M) +DECLARE_INSN(vmul_vv, MATCH_VMUL_VV, MASK_VMUL_VV) +DECLARE_INSN(vmul_vx, MATCH_VMUL_VX, MASK_VMUL_VX) +DECLARE_INSN(vmulh_vv, MATCH_VMULH_VV, MASK_VMULH_VV) +DECLARE_INSN(vmulh_vx, MATCH_VMULH_VX, MASK_VMULH_VX) +DECLARE_INSN(vmulhsu_vv, MATCH_VMULHSU_VV, MASK_VMULHSU_VV) +DECLARE_INSN(vmulhsu_vx, MATCH_VMULHSU_VX, MASK_VMULHSU_VX) +DECLARE_INSN(vmulhu_vv, MATCH_VMULHU_VV, MASK_VMULHU_VV) +DECLARE_INSN(vmulhu_vx, MATCH_VMULHU_VX, MASK_VMULHU_VX) +DECLARE_INSN(vmv1r_v, MATCH_VMV1R_V, MASK_VMV1R_V) +DECLARE_INSN(vmv2r_v, MATCH_VMV2R_V, MASK_VMV2R_V) +DECLARE_INSN(vmv4r_v, MATCH_VMV4R_V, MASK_VMV4R_V) +DECLARE_INSN(vmv8r_v, MATCH_VMV8R_V, MASK_VMV8R_V) +DECLARE_INSN(vmv_s_x, MATCH_VMV_S_X, MASK_VMV_S_X) +DECLARE_INSN(vmv_v_i, MATCH_VMV_V_I, MASK_VMV_V_I) +DECLARE_INSN(vmv_v_v, MATCH_VMV_V_V, MASK_VMV_V_V) +DECLARE_INSN(vmv_v_x, MATCH_VMV_V_X, MASK_VMV_V_X) +DECLARE_INSN(vmv_x_s, MATCH_VMV_X_S, MASK_VMV_X_S) +DECLARE_INSN(vmxnor_mm, MATCH_VMXNOR_MM, MASK_VMXNOR_MM) +DECLARE_INSN(vmxor_mm, MATCH_VMXOR_MM, MASK_VMXOR_MM) +DECLARE_INSN(vnclip_wi, MATCH_VNCLIP_WI, MASK_VNCLIP_WI) +DECLARE_INSN(vnclip_wv, MATCH_VNCLIP_WV, MASK_VNCLIP_WV) +DECLARE_INSN(vnclip_wx, MATCH_VNCLIP_WX, MASK_VNCLIP_WX) +DECLARE_INSN(vnclipu_wi, MATCH_VNCLIPU_WI, MASK_VNCLIPU_WI) +DECLARE_INSN(vnclipu_wv, MATCH_VNCLIPU_WV, MASK_VNCLIPU_WV) +DECLARE_INSN(vnclipu_wx, MATCH_VNCLIPU_WX, MASK_VNCLIPU_WX) +DECLARE_INSN(vnmsac_vv, MATCH_VNMSAC_VV, MASK_VNMSAC_VV) +DECLARE_INSN(vnmsac_vx, MATCH_VNMSAC_VX, MASK_VNMSAC_VX) +DECLARE_INSN(vnmsub_vv, MATCH_VNMSUB_VV, MASK_VNMSUB_VV) +DECLARE_INSN(vnmsub_vx, MATCH_VNMSUB_VX, MASK_VNMSUB_VX) +DECLARE_INSN(vnsra_wi, MATCH_VNSRA_WI, MASK_VNSRA_WI) +DECLARE_INSN(vnsra_wv, MATCH_VNSRA_WV, MASK_VNSRA_WV) +DECLARE_INSN(vnsra_wx, MATCH_VNSRA_WX, MASK_VNSRA_WX) +DECLARE_INSN(vnsrl_wi, MATCH_VNSRL_WI, MASK_VNSRL_WI) +DECLARE_INSN(vnsrl_wv, MATCH_VNSRL_WV, MASK_VNSRL_WV) +DECLARE_INSN(vnsrl_wx, MATCH_VNSRL_WX, MASK_VNSRL_WX) +DECLARE_INSN(vor_vi, MATCH_VOR_VI, MASK_VOR_VI) +DECLARE_INSN(vor_vv, MATCH_VOR_VV, MASK_VOR_VV) +DECLARE_INSN(vor_vx, MATCH_VOR_VX, MASK_VOR_VX) +DECLARE_INSN(vredand_vs, MATCH_VREDAND_VS, MASK_VREDAND_VS) +DECLARE_INSN(vredmax_vs, MATCH_VREDMAX_VS, MASK_VREDMAX_VS) +DECLARE_INSN(vredmaxu_vs, MATCH_VREDMAXU_VS, MASK_VREDMAXU_VS) +DECLARE_INSN(vredmin_vs, MATCH_VREDMIN_VS, MASK_VREDMIN_VS) +DECLARE_INSN(vredminu_vs, MATCH_VREDMINU_VS, MASK_VREDMINU_VS) +DECLARE_INSN(vredor_vs, MATCH_VREDOR_VS, MASK_VREDOR_VS) +DECLARE_INSN(vredsum_vs, MATCH_VREDSUM_VS, MASK_VREDSUM_VS) +DECLARE_INSN(vredxor_vs, MATCH_VREDXOR_VS, MASK_VREDXOR_VS) +DECLARE_INSN(vrem_vv, MATCH_VREM_VV, MASK_VREM_VV) +DECLARE_INSN(vrem_vx, MATCH_VREM_VX, MASK_VREM_VX) +DECLARE_INSN(vremu_vv, MATCH_VREMU_VV, MASK_VREMU_VV) +DECLARE_INSN(vremu_vx, MATCH_VREMU_VX, MASK_VREMU_VX) +DECLARE_INSN(vrgather_vi, MATCH_VRGATHER_VI, MASK_VRGATHER_VI) +DECLARE_INSN(vrgather_vv, MATCH_VRGATHER_VV, MASK_VRGATHER_VV) +DECLARE_INSN(vrgather_vx, MATCH_VRGATHER_VX, MASK_VRGATHER_VX) +DECLARE_INSN(vrgatherei16_vv, MATCH_VRGATHEREI16_VV, MASK_VRGATHEREI16_VV) +DECLARE_INSN(vrsub_vi, MATCH_VRSUB_VI, MASK_VRSUB_VI) +DECLARE_INSN(vrsub_vx, MATCH_VRSUB_VX, MASK_VRSUB_VX) +DECLARE_INSN(vs1r_v, MATCH_VS1R_V, MASK_VS1R_V) +DECLARE_INSN(vs2r_v, MATCH_VS2R_V, MASK_VS2R_V) +DECLARE_INSN(vs4r_v, MATCH_VS4R_V, MASK_VS4R_V) +DECLARE_INSN(vs8r_v, MATCH_VS8R_V, MASK_VS8R_V) +DECLARE_INSN(vsadd_vi, MATCH_VSADD_VI, MASK_VSADD_VI) +DECLARE_INSN(vsadd_vv, MATCH_VSADD_VV, MASK_VSADD_VV) +DECLARE_INSN(vsadd_vx, MATCH_VSADD_VX, MASK_VSADD_VX) +DECLARE_INSN(vsaddu_vi, MATCH_VSADDU_VI, MASK_VSADDU_VI) +DECLARE_INSN(vsaddu_vv, MATCH_VSADDU_VV, MASK_VSADDU_VV) +DECLARE_INSN(vsaddu_vx, MATCH_VSADDU_VX, MASK_VSADDU_VX) +DECLARE_INSN(vsbc_vvm, MATCH_VSBC_VVM, MASK_VSBC_VVM) +DECLARE_INSN(vsbc_vxm, MATCH_VSBC_VXM, MASK_VSBC_VXM) +DECLARE_INSN(vse1024_v, MATCH_VSE1024_V, MASK_VSE1024_V) +DECLARE_INSN(vse128_v, MATCH_VSE128_V, MASK_VSE128_V) +DECLARE_INSN(vse16_v, MATCH_VSE16_V, MASK_VSE16_V) +DECLARE_INSN(vse256_v, MATCH_VSE256_V, MASK_VSE256_V) +DECLARE_INSN(vse32_v, MATCH_VSE32_V, MASK_VSE32_V) +DECLARE_INSN(vse512_v, MATCH_VSE512_V, MASK_VSE512_V) +DECLARE_INSN(vse64_v, MATCH_VSE64_V, MASK_VSE64_V) +DECLARE_INSN(vse8_v, MATCH_VSE8_V, MASK_VSE8_V) +DECLARE_INSN(vsetivli, MATCH_VSETIVLI, MASK_VSETIVLI) +DECLARE_INSN(vsetvl, MATCH_VSETVL, MASK_VSETVL) +DECLARE_INSN(vsetvli, MATCH_VSETVLI, MASK_VSETVLI) +DECLARE_INSN(vsext_vf2, MATCH_VSEXT_VF2, MASK_VSEXT_VF2) +DECLARE_INSN(vsext_vf4, MATCH_VSEXT_VF4, MASK_VSEXT_VF4) +DECLARE_INSN(vsext_vf8, MATCH_VSEXT_VF8, MASK_VSEXT_VF8) +DECLARE_INSN(vslide1down_vx, MATCH_VSLIDE1DOWN_VX, MASK_VSLIDE1DOWN_VX) +DECLARE_INSN(vslide1up_vx, MATCH_VSLIDE1UP_VX, MASK_VSLIDE1UP_VX) +DECLARE_INSN(vslidedown_vi, MATCH_VSLIDEDOWN_VI, MASK_VSLIDEDOWN_VI) +DECLARE_INSN(vslidedown_vx, MATCH_VSLIDEDOWN_VX, MASK_VSLIDEDOWN_VX) +DECLARE_INSN(vslideup_vi, MATCH_VSLIDEUP_VI, MASK_VSLIDEUP_VI) +DECLARE_INSN(vslideup_vx, MATCH_VSLIDEUP_VX, MASK_VSLIDEUP_VX) +DECLARE_INSN(vsll_vi, MATCH_VSLL_VI, MASK_VSLL_VI) +DECLARE_INSN(vsll_vv, MATCH_VSLL_VV, MASK_VSLL_VV) +DECLARE_INSN(vsll_vx, MATCH_VSLL_VX, MASK_VSLL_VX) +DECLARE_INSN(vsm_v, MATCH_VSM_V, MASK_VSM_V) +DECLARE_INSN(vsmul_vv, MATCH_VSMUL_VV, MASK_VSMUL_VV) +DECLARE_INSN(vsmul_vx, MATCH_VSMUL_VX, MASK_VSMUL_VX) +DECLARE_INSN(vsoxei1024_v, MATCH_VSOXEI1024_V, MASK_VSOXEI1024_V) +DECLARE_INSN(vsoxei128_v, MATCH_VSOXEI128_V, MASK_VSOXEI128_V) +DECLARE_INSN(vsoxei16_v, MATCH_VSOXEI16_V, MASK_VSOXEI16_V) +DECLARE_INSN(vsoxei256_v, MATCH_VSOXEI256_V, MASK_VSOXEI256_V) +DECLARE_INSN(vsoxei32_v, MATCH_VSOXEI32_V, MASK_VSOXEI32_V) +DECLARE_INSN(vsoxei512_v, MATCH_VSOXEI512_V, MASK_VSOXEI512_V) +DECLARE_INSN(vsoxei64_v, MATCH_VSOXEI64_V, MASK_VSOXEI64_V) +DECLARE_INSN(vsoxei8_v, MATCH_VSOXEI8_V, MASK_VSOXEI8_V) +DECLARE_INSN(vsra_vi, MATCH_VSRA_VI, MASK_VSRA_VI) +DECLARE_INSN(vsra_vv, MATCH_VSRA_VV, MASK_VSRA_VV) +DECLARE_INSN(vsra_vx, MATCH_VSRA_VX, MASK_VSRA_VX) +DECLARE_INSN(vsrl_vi, MATCH_VSRL_VI, MASK_VSRL_VI) +DECLARE_INSN(vsrl_vv, MATCH_VSRL_VV, MASK_VSRL_VV) +DECLARE_INSN(vsrl_vx, MATCH_VSRL_VX, MASK_VSRL_VX) +DECLARE_INSN(vsse1024_v, MATCH_VSSE1024_V, MASK_VSSE1024_V) +DECLARE_INSN(vsse128_v, MATCH_VSSE128_V, MASK_VSSE128_V) +DECLARE_INSN(vsse16_v, MATCH_VSSE16_V, MASK_VSSE16_V) +DECLARE_INSN(vsse256_v, MATCH_VSSE256_V, MASK_VSSE256_V) +DECLARE_INSN(vsse32_v, MATCH_VSSE32_V, MASK_VSSE32_V) +DECLARE_INSN(vsse512_v, MATCH_VSSE512_V, MASK_VSSE512_V) +DECLARE_INSN(vsse64_v, MATCH_VSSE64_V, MASK_VSSE64_V) +DECLARE_INSN(vsse8_v, MATCH_VSSE8_V, MASK_VSSE8_V) +DECLARE_INSN(vssra_vi, MATCH_VSSRA_VI, MASK_VSSRA_VI) +DECLARE_INSN(vssra_vv, MATCH_VSSRA_VV, MASK_VSSRA_VV) +DECLARE_INSN(vssra_vx, MATCH_VSSRA_VX, MASK_VSSRA_VX) +DECLARE_INSN(vssrl_vi, MATCH_VSSRL_VI, MASK_VSSRL_VI) +DECLARE_INSN(vssrl_vv, MATCH_VSSRL_VV, MASK_VSSRL_VV) +DECLARE_INSN(vssrl_vx, MATCH_VSSRL_VX, MASK_VSSRL_VX) +DECLARE_INSN(vssub_vv, MATCH_VSSUB_VV, MASK_VSSUB_VV) +DECLARE_INSN(vssub_vx, MATCH_VSSUB_VX, MASK_VSSUB_VX) +DECLARE_INSN(vssubu_vv, MATCH_VSSUBU_VV, MASK_VSSUBU_VV) +DECLARE_INSN(vssubu_vx, MATCH_VSSUBU_VX, MASK_VSSUBU_VX) +DECLARE_INSN(vsub_vv, MATCH_VSUB_VV, MASK_VSUB_VV) +DECLARE_INSN(vsub_vx, MATCH_VSUB_VX, MASK_VSUB_VX) +DECLARE_INSN(vsuxei1024_v, MATCH_VSUXEI1024_V, MASK_VSUXEI1024_V) +DECLARE_INSN(vsuxei128_v, MATCH_VSUXEI128_V, MASK_VSUXEI128_V) +DECLARE_INSN(vsuxei16_v, MATCH_VSUXEI16_V, MASK_VSUXEI16_V) +DECLARE_INSN(vsuxei256_v, MATCH_VSUXEI256_V, MASK_VSUXEI256_V) +DECLARE_INSN(vsuxei32_v, MATCH_VSUXEI32_V, MASK_VSUXEI32_V) +DECLARE_INSN(vsuxei512_v, MATCH_VSUXEI512_V, MASK_VSUXEI512_V) +DECLARE_INSN(vsuxei64_v, MATCH_VSUXEI64_V, MASK_VSUXEI64_V) +DECLARE_INSN(vsuxei8_v, MATCH_VSUXEI8_V, MASK_VSUXEI8_V) +DECLARE_INSN(vwadd_vv, MATCH_VWADD_VV, MASK_VWADD_VV) +DECLARE_INSN(vwadd_vx, MATCH_VWADD_VX, MASK_VWADD_VX) +DECLARE_INSN(vwadd_wv, MATCH_VWADD_WV, MASK_VWADD_WV) +DECLARE_INSN(vwadd_wx, MATCH_VWADD_WX, MASK_VWADD_WX) +DECLARE_INSN(vwaddu_vv, MATCH_VWADDU_VV, MASK_VWADDU_VV) +DECLARE_INSN(vwaddu_vx, MATCH_VWADDU_VX, MASK_VWADDU_VX) +DECLARE_INSN(vwaddu_wv, MATCH_VWADDU_WV, MASK_VWADDU_WV) +DECLARE_INSN(vwaddu_wx, MATCH_VWADDU_WX, MASK_VWADDU_WX) +DECLARE_INSN(vwmacc_vv, MATCH_VWMACC_VV, MASK_VWMACC_VV) +DECLARE_INSN(vwmacc_vx, MATCH_VWMACC_VX, MASK_VWMACC_VX) +DECLARE_INSN(vwmaccsu_vv, MATCH_VWMACCSU_VV, MASK_VWMACCSU_VV) +DECLARE_INSN(vwmaccsu_vx, MATCH_VWMACCSU_VX, MASK_VWMACCSU_VX) +DECLARE_INSN(vwmaccu_vv, MATCH_VWMACCU_VV, MASK_VWMACCU_VV) +DECLARE_INSN(vwmaccu_vx, MATCH_VWMACCU_VX, MASK_VWMACCU_VX) +DECLARE_INSN(vwmaccus_vx, MATCH_VWMACCUS_VX, MASK_VWMACCUS_VX) +DECLARE_INSN(vwmul_vv, MATCH_VWMUL_VV, MASK_VWMUL_VV) +DECLARE_INSN(vwmul_vx, MATCH_VWMUL_VX, MASK_VWMUL_VX) +DECLARE_INSN(vwmulsu_vv, MATCH_VWMULSU_VV, MASK_VWMULSU_VV) +DECLARE_INSN(vwmulsu_vx, MATCH_VWMULSU_VX, MASK_VWMULSU_VX) +DECLARE_INSN(vwmulu_vv, MATCH_VWMULU_VV, MASK_VWMULU_VV) +DECLARE_INSN(vwmulu_vx, MATCH_VWMULU_VX, MASK_VWMULU_VX) +DECLARE_INSN(vwredsum_vs, MATCH_VWREDSUM_VS, MASK_VWREDSUM_VS) +DECLARE_INSN(vwredsumu_vs, MATCH_VWREDSUMU_VS, MASK_VWREDSUMU_VS) +DECLARE_INSN(vwsub_vv, MATCH_VWSUB_VV, MASK_VWSUB_VV) +DECLARE_INSN(vwsub_vx, MATCH_VWSUB_VX, MASK_VWSUB_VX) +DECLARE_INSN(vwsub_wv, MATCH_VWSUB_WV, MASK_VWSUB_WV) +DECLARE_INSN(vwsub_wx, MATCH_VWSUB_WX, MASK_VWSUB_WX) +DECLARE_INSN(vwsubu_vv, MATCH_VWSUBU_VV, MASK_VWSUBU_VV) +DECLARE_INSN(vwsubu_vx, MATCH_VWSUBU_VX, MASK_VWSUBU_VX) +DECLARE_INSN(vwsubu_wv, MATCH_VWSUBU_WV, MASK_VWSUBU_WV) +DECLARE_INSN(vwsubu_wx, MATCH_VWSUBU_WX, MASK_VWSUBU_WX) +DECLARE_INSN(vxor_vi, MATCH_VXOR_VI, MASK_VXOR_VI) +DECLARE_INSN(vxor_vv, MATCH_VXOR_VV, MASK_VXOR_VV) +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) +DECLARE_INSN(xnor, MATCH_XNOR, MASK_XNOR) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(xperm16, MATCH_XPERM16, MASK_XPERM16) +DECLARE_INSN(xperm32, MATCH_XPERM32, MASK_XPERM32) +DECLARE_INSN(xperm4, MATCH_XPERM4, MASK_XPERM4) +DECLARE_INSN(xperm8, MATCH_XPERM8, MASK_XPERM8) +DECLARE_INSN(zunpkd810, MATCH_ZUNPKD810, MASK_ZUNPKD810) +DECLARE_INSN(zunpkd820, MATCH_ZUNPKD820, MASK_ZUNPKD820) +DECLARE_INSN(zunpkd830, MATCH_ZUNPKD830, MASK_ZUNPKD830) +DECLARE_INSN(zunpkd831, MATCH_ZUNPKD831, MASK_ZUNPKD831) +DECLARE_INSN(zunpkd832, MATCH_ZUNPKD832, MASK_ZUNPKD832) #endif #ifdef DECLARE_CSR DECLARE_CSR(fflags, CSR_FFLAGS) DECLARE_CSR(frm, CSR_FRM) DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(vstart, CSR_VSTART) +DECLARE_CSR(vxsat, CSR_VXSAT) +DECLARE_CSR(vxrm, CSR_VXRM) +DECLARE_CSR(vcsr, CSR_VCSR) +DECLARE_CSR(seed, CSR_SEED) DECLARE_CSR(cycle, CSR_CYCLE) DECLARE_CSR(time, CSR_TIME) DECLARE_CSR(instret, CSR_INSTRET) @@ -1277,16 +4547,73 @@ DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) +DECLARE_CSR(vl, CSR_VL) +DECLARE_CSR(vtype, CSR_VTYPE) +DECLARE_CSR(vlenb, CSR_VLENB) DECLARE_CSR(sstatus, CSR_SSTATUS) +DECLARE_CSR(sedeleg, CSR_SEDELEG) +DECLARE_CSR(sideleg, CSR_SIDELEG) DECLARE_CSR(sie, CSR_SIE) DECLARE_CSR(stvec, CSR_STVEC) DECLARE_CSR(scounteren, CSR_SCOUNTEREN) +DECLARE_CSR(senvcfg, CSR_SENVCFG) +DECLARE_CSR(sstateen0, CSR_SSTATEEN0) +DECLARE_CSR(sstateen1, CSR_SSTATEEN1) +DECLARE_CSR(sstateen2, CSR_SSTATEEN2) +DECLARE_CSR(sstateen3, CSR_SSTATEEN3) DECLARE_CSR(sscratch, CSR_SSCRATCH) DECLARE_CSR(sepc, CSR_SEPC) DECLARE_CSR(scause, CSR_SCAUSE) DECLARE_CSR(stval, CSR_STVAL) DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(stimecmp, CSR_STIMECMP) DECLARE_CSR(satp, CSR_SATP) +DECLARE_CSR(scontext, CSR_SCONTEXT) +DECLARE_CSR(vsstatus, CSR_VSSTATUS) +DECLARE_CSR(vsie, CSR_VSIE) +DECLARE_CSR(vstvec, CSR_VSTVEC) +DECLARE_CSR(vsscratch, CSR_VSSCRATCH) +DECLARE_CSR(vsepc, CSR_VSEPC) +DECLARE_CSR(vscause, CSR_VSCAUSE) +DECLARE_CSR(vstval, CSR_VSTVAL) +DECLARE_CSR(vsip, CSR_VSIP) +DECLARE_CSR(vstimecmp, CSR_VSTIMECMP) +DECLARE_CSR(vsatp, CSR_VSATP) +DECLARE_CSR(hstatus, CSR_HSTATUS) +DECLARE_CSR(hedeleg, CSR_HEDELEG) +DECLARE_CSR(hideleg, CSR_HIDELEG) +DECLARE_CSR(hie, CSR_HIE) +DECLARE_CSR(htimedelta, CSR_HTIMEDELTA) +DECLARE_CSR(hcounteren, CSR_HCOUNTEREN) +DECLARE_CSR(hgeie, CSR_HGEIE) +DECLARE_CSR(henvcfg, CSR_HENVCFG) +DECLARE_CSR(hstateen0, CSR_HSTATEEN0) +DECLARE_CSR(hstateen1, CSR_HSTATEEN1) +DECLARE_CSR(hstateen2, CSR_HSTATEEN2) +DECLARE_CSR(hstateen3, CSR_HSTATEEN3) +DECLARE_CSR(htval, CSR_HTVAL) +DECLARE_CSR(hip, CSR_HIP) +DECLARE_CSR(hvip, CSR_HVIP) +DECLARE_CSR(htinst, CSR_HTINST) +DECLARE_CSR(hgatp, CSR_HGATP) +DECLARE_CSR(hcontext, CSR_HCONTEXT) +DECLARE_CSR(hgeip, CSR_HGEIP) +DECLARE_CSR(scountovf, CSR_SCOUNTOVF) +DECLARE_CSR(utvt, CSR_UTVT) +DECLARE_CSR(unxti, CSR_UNXTI) +DECLARE_CSR(uintstatus, CSR_UINTSTATUS) +DECLARE_CSR(uscratchcsw, CSR_USCRATCHCSW) +DECLARE_CSR(uscratchcswl, CSR_USCRATCHCSWL) +DECLARE_CSR(stvt, CSR_STVT) +DECLARE_CSR(snxti, CSR_SNXTI) +DECLARE_CSR(sintstatus, CSR_SINTSTATUS) +DECLARE_CSR(sscratchcsw, CSR_SSCRATCHCSW) +DECLARE_CSR(sscratchcswl, CSR_SSCRATCHCSWL) +DECLARE_CSR(mtvt, CSR_MTVT) +DECLARE_CSR(mnxti, CSR_MNXTI) +DECLARE_CSR(mintstatus, CSR_MINTSTATUS) +DECLARE_CSR(mscratchcsw, CSR_MSCRATCHCSW) +DECLARE_CSR(mscratchcswl, CSR_MSCRATCHCSWL) DECLARE_CSR(mstatus, CSR_MSTATUS) DECLARE_CSR(misa, CSR_MISA) DECLARE_CSR(medeleg, CSR_MEDELEG) @@ -1294,15 +4621,35 @@ DECLARE_CSR(mideleg, CSR_MIDELEG) DECLARE_CSR(mie, CSR_MIE) DECLARE_CSR(mtvec, CSR_MTVEC) DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) +DECLARE_CSR(menvcfg, CSR_MENVCFG) +DECLARE_CSR(mstateen0, CSR_MSTATEEN0) +DECLARE_CSR(mstateen1, CSR_MSTATEEN1) +DECLARE_CSR(mstateen2, CSR_MSTATEEN2) +DECLARE_CSR(mstateen3, CSR_MSTATEEN3) +DECLARE_CSR(mcountinhibit, CSR_MCOUNTINHIBIT) DECLARE_CSR(mscratch, CSR_MSCRATCH) DECLARE_CSR(mepc, CSR_MEPC) DECLARE_CSR(mcause, CSR_MCAUSE) DECLARE_CSR(mtval, CSR_MTVAL) DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(mtinst, CSR_MTINST) +DECLARE_CSR(mtval2, CSR_MTVAL2) DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) DECLARE_CSR(pmpcfg2, CSR_PMPCFG2) DECLARE_CSR(pmpcfg3, CSR_PMPCFG3) +DECLARE_CSR(pmpcfg4, CSR_PMPCFG4) +DECLARE_CSR(pmpcfg5, CSR_PMPCFG5) +DECLARE_CSR(pmpcfg6, CSR_PMPCFG6) +DECLARE_CSR(pmpcfg7, CSR_PMPCFG7) +DECLARE_CSR(pmpcfg8, CSR_PMPCFG8) +DECLARE_CSR(pmpcfg9, CSR_PMPCFG9) +DECLARE_CSR(pmpcfg10, CSR_PMPCFG10) +DECLARE_CSR(pmpcfg11, CSR_PMPCFG11) +DECLARE_CSR(pmpcfg12, CSR_PMPCFG12) +DECLARE_CSR(pmpcfg13, CSR_PMPCFG13) +DECLARE_CSR(pmpcfg14, CSR_PMPCFG14) +DECLARE_CSR(pmpcfg15, CSR_PMPCFG15) DECLARE_CSR(pmpaddr0, CSR_PMPADDR0) DECLARE_CSR(pmpaddr1, CSR_PMPADDR1) DECLARE_CSR(pmpaddr2, CSR_PMPADDR2) @@ -1319,13 +4666,67 @@ DECLARE_CSR(pmpaddr12, CSR_PMPADDR12) DECLARE_CSR(pmpaddr13, CSR_PMPADDR13) DECLARE_CSR(pmpaddr14, CSR_PMPADDR14) DECLARE_CSR(pmpaddr15, CSR_PMPADDR15) +DECLARE_CSR(pmpaddr16, CSR_PMPADDR16) +DECLARE_CSR(pmpaddr17, CSR_PMPADDR17) +DECLARE_CSR(pmpaddr18, CSR_PMPADDR18) +DECLARE_CSR(pmpaddr19, CSR_PMPADDR19) +DECLARE_CSR(pmpaddr20, CSR_PMPADDR20) +DECLARE_CSR(pmpaddr21, CSR_PMPADDR21) +DECLARE_CSR(pmpaddr22, CSR_PMPADDR22) +DECLARE_CSR(pmpaddr23, CSR_PMPADDR23) +DECLARE_CSR(pmpaddr24, CSR_PMPADDR24) +DECLARE_CSR(pmpaddr25, CSR_PMPADDR25) +DECLARE_CSR(pmpaddr26, CSR_PMPADDR26) +DECLARE_CSR(pmpaddr27, CSR_PMPADDR27) +DECLARE_CSR(pmpaddr28, CSR_PMPADDR28) +DECLARE_CSR(pmpaddr29, CSR_PMPADDR29) +DECLARE_CSR(pmpaddr30, CSR_PMPADDR30) +DECLARE_CSR(pmpaddr31, CSR_PMPADDR31) +DECLARE_CSR(pmpaddr32, CSR_PMPADDR32) +DECLARE_CSR(pmpaddr33, CSR_PMPADDR33) +DECLARE_CSR(pmpaddr34, CSR_PMPADDR34) +DECLARE_CSR(pmpaddr35, CSR_PMPADDR35) +DECLARE_CSR(pmpaddr36, CSR_PMPADDR36) +DECLARE_CSR(pmpaddr37, CSR_PMPADDR37) +DECLARE_CSR(pmpaddr38, CSR_PMPADDR38) +DECLARE_CSR(pmpaddr39, CSR_PMPADDR39) +DECLARE_CSR(pmpaddr40, CSR_PMPADDR40) +DECLARE_CSR(pmpaddr41, CSR_PMPADDR41) +DECLARE_CSR(pmpaddr42, CSR_PMPADDR42) +DECLARE_CSR(pmpaddr43, CSR_PMPADDR43) +DECLARE_CSR(pmpaddr44, CSR_PMPADDR44) +DECLARE_CSR(pmpaddr45, CSR_PMPADDR45) +DECLARE_CSR(pmpaddr46, CSR_PMPADDR46) +DECLARE_CSR(pmpaddr47, CSR_PMPADDR47) +DECLARE_CSR(pmpaddr48, CSR_PMPADDR48) +DECLARE_CSR(pmpaddr49, CSR_PMPADDR49) +DECLARE_CSR(pmpaddr50, CSR_PMPADDR50) +DECLARE_CSR(pmpaddr51, CSR_PMPADDR51) +DECLARE_CSR(pmpaddr52, CSR_PMPADDR52) +DECLARE_CSR(pmpaddr53, CSR_PMPADDR53) +DECLARE_CSR(pmpaddr54, CSR_PMPADDR54) +DECLARE_CSR(pmpaddr55, CSR_PMPADDR55) +DECLARE_CSR(pmpaddr56, CSR_PMPADDR56) +DECLARE_CSR(pmpaddr57, CSR_PMPADDR57) +DECLARE_CSR(pmpaddr58, CSR_PMPADDR58) +DECLARE_CSR(pmpaddr59, CSR_PMPADDR59) +DECLARE_CSR(pmpaddr60, CSR_PMPADDR60) +DECLARE_CSR(pmpaddr61, CSR_PMPADDR61) +DECLARE_CSR(pmpaddr62, CSR_PMPADDR62) +DECLARE_CSR(pmpaddr63, CSR_PMPADDR63) +DECLARE_CSR(mseccfg, CSR_MSECCFG) DECLARE_CSR(tselect, CSR_TSELECT) DECLARE_CSR(tdata1, CSR_TDATA1) DECLARE_CSR(tdata2, CSR_TDATA2) DECLARE_CSR(tdata3, CSR_TDATA3) +DECLARE_CSR(tinfo, CSR_TINFO) +DECLARE_CSR(tcontrol, CSR_TCONTROL) +DECLARE_CSR(mcontext, CSR_MCONTEXT) +DECLARE_CSR(mscontext, CSR_MSCONTEXT) DECLARE_CSR(dcsr, CSR_DCSR) DECLARE_CSR(dpc, CSR_DPC) -DECLARE_CSR(dscratch, CSR_DSCRATCH) +DECLARE_CSR(dscratch0, CSR_DSCRATCH0) +DECLARE_CSR(dscratch1, CSR_DSCRATCH1) DECLARE_CSR(mcycle, CSR_MCYCLE) DECLARE_CSR(minstret, CSR_MINSTRET) DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) @@ -1390,6 +4791,15 @@ DECLARE_CSR(mvendorid, CSR_MVENDORID) DECLARE_CSR(marchid, CSR_MARCHID) DECLARE_CSR(mimpid, CSR_MIMPID) DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(mconfigptr, CSR_MCONFIGPTR) +DECLARE_CSR(stimecmph, CSR_STIMECMPH) +DECLARE_CSR(vstimecmph, CSR_VSTIMECMPH) +DECLARE_CSR(htimedeltah, CSR_HTIMEDELTAH) +DECLARE_CSR(henvcfgh, CSR_HENVCFGH) +DECLARE_CSR(hstateen0h, CSR_HSTATEEN0H) +DECLARE_CSR(hstateen1h, CSR_HSTATEEN1H) +DECLARE_CSR(hstateen2h, CSR_HSTATEEN2H) +DECLARE_CSR(hstateen3h, CSR_HSTATEEN3H) DECLARE_CSR(cycleh, CSR_CYCLEH) DECLARE_CSR(timeh, CSR_TIMEH) DECLARE_CSR(instreth, CSR_INSTRETH) @@ -1422,6 +4832,42 @@ DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) +DECLARE_CSR(mstatush, CSR_MSTATUSH) +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(mhpmevent3h, CSR_MHPMEVENT3H) +DECLARE_CSR(mhpmevent4h, CSR_MHPMEVENT4H) +DECLARE_CSR(mhpmevent5h, CSR_MHPMEVENT5H) +DECLARE_CSR(mhpmevent6h, CSR_MHPMEVENT6H) +DECLARE_CSR(mhpmevent7h, CSR_MHPMEVENT7H) +DECLARE_CSR(mhpmevent8h, CSR_MHPMEVENT8H) +DECLARE_CSR(mhpmevent9h, CSR_MHPMEVENT9H) +DECLARE_CSR(mhpmevent10h, CSR_MHPMEVENT10H) +DECLARE_CSR(mhpmevent11h, CSR_MHPMEVENT11H) +DECLARE_CSR(mhpmevent12h, CSR_MHPMEVENT12H) +DECLARE_CSR(mhpmevent13h, CSR_MHPMEVENT13H) +DECLARE_CSR(mhpmevent14h, CSR_MHPMEVENT14H) +DECLARE_CSR(mhpmevent15h, CSR_MHPMEVENT15H) +DECLARE_CSR(mhpmevent16h, CSR_MHPMEVENT16H) +DECLARE_CSR(mhpmevent17h, CSR_MHPMEVENT17H) +DECLARE_CSR(mhpmevent18h, CSR_MHPMEVENT18H) +DECLARE_CSR(mhpmevent19h, CSR_MHPMEVENT19H) +DECLARE_CSR(mhpmevent20h, CSR_MHPMEVENT20H) +DECLARE_CSR(mhpmevent21h, CSR_MHPMEVENT21H) +DECLARE_CSR(mhpmevent22h, CSR_MHPMEVENT22H) +DECLARE_CSR(mhpmevent23h, CSR_MHPMEVENT23H) +DECLARE_CSR(mhpmevent24h, CSR_MHPMEVENT24H) +DECLARE_CSR(mhpmevent25h, CSR_MHPMEVENT25H) +DECLARE_CSR(mhpmevent26h, CSR_MHPMEVENT26H) +DECLARE_CSR(mhpmevent27h, CSR_MHPMEVENT27H) +DECLARE_CSR(mhpmevent28h, CSR_MHPMEVENT28H) +DECLARE_CSR(mhpmevent29h, CSR_MHPMEVENT29H) +DECLARE_CSR(mhpmevent30h, CSR_MHPMEVENT30H) +DECLARE_CSR(mhpmevent31h, CSR_MHPMEVENT31H) +DECLARE_CSR(mseccfgh, CSR_MSECCFGH) DECLARE_CSR(mcycleh, CSR_MCYCLEH) DECLARE_CSR(minstreth, CSR_MINSTRETH) DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) @@ -1465,9 +4911,13 @@ DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) DECLARE_CAUSE("store access", CAUSE_STORE_ACCESS) DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) -DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) +DECLARE_CAUSE("virtual_supervisor_ecall", CAUSE_VIRTUAL_SUPERVISOR_ECALL) DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) DECLARE_CAUSE("fetch page fault", CAUSE_FETCH_PAGE_FAULT) DECLARE_CAUSE("load page fault", CAUSE_LOAD_PAGE_FAULT) DECLARE_CAUSE("store page fault", CAUSE_STORE_PAGE_FAULT) +DECLARE_CAUSE("fetch guest page fault", CAUSE_FETCH_GUEST_PAGE_FAULT) +DECLARE_CAUSE("load guest page fault", CAUSE_LOAD_GUEST_PAGE_FAULT) +DECLARE_CAUSE("virtual instruction", CAUSE_VIRTUAL_INSTRUCTION) +DECLARE_CAUSE("store guest page fault", CAUSE_STORE_GUEST_PAGE_FAULT) #endif diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h index a587952fec..32bc1d577b 100644 --- a/src/target/riscv/gdb_regs.h +++ b/src/target/riscv/gdb_regs.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + #ifndef TARGET__RISCV__GDB_REGS_H #define TARGET__RISCV__GDB_REGS_H @@ -21,6 +23,7 @@ enum gdb_regno { GDB_REGNO_A3, GDB_REGNO_A4, GDB_REGNO_A5, + GDB_REGNO_XPR15 = GDB_REGNO_A5, GDB_REGNO_A6, GDB_REGNO_A7, GDB_REGNO_S2, @@ -75,16 +78,37 @@ enum gdb_regno { GDB_REGNO_FT11, GDB_REGNO_FPR31 = GDB_REGNO_FT11, GDB_REGNO_CSR0 = 65, + 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_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_MISA = CSR_MISA + GDB_REGNO_CSR0, GDB_REGNO_DPC = CSR_DPC + GDB_REGNO_CSR0, GDB_REGNO_DCSR = CSR_DCSR + GDB_REGNO_CSR0, - GDB_REGNO_DSCRATCH = CSR_DSCRATCH + GDB_REGNO_CSR0, + GDB_REGNO_DSCRATCH0 = CSR_DSCRATCH0 + GDB_REGNO_CSR0, GDB_REGNO_MSTATUS = CSR_MSTATUS + GDB_REGNO_CSR0, + 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_CSR4095 = GDB_REGNO_CSR0 + 4095, GDB_REGNO_PRIV = 4161, + /* It's still undecided what register numbers GDB will actually use for + * these. See + * https://groups.google.com/a/groups.riscv.org/d/msg/sw-dev/7lQYiTUN9Ms/gTxGhzaYBQAJ + */ + GDB_REGNO_V0, GDB_REGNO_V1, GDB_REGNO_V2, GDB_REGNO_V3, + GDB_REGNO_V4, GDB_REGNO_V5, GDB_REGNO_V6, GDB_REGNO_V7, + GDB_REGNO_V8, GDB_REGNO_V9, GDB_REGNO_V10, GDB_REGNO_V11, + GDB_REGNO_V12, GDB_REGNO_V13, GDB_REGNO_V14, GDB_REGNO_V15, + GDB_REGNO_V16, GDB_REGNO_V17, GDB_REGNO_V18, GDB_REGNO_V19, + GDB_REGNO_V20, GDB_REGNO_V21, GDB_REGNO_V22, GDB_REGNO_V23, + GDB_REGNO_V24, GDB_REGNO_V25, GDB_REGNO_V26, GDB_REGNO_V27, + GDB_REGNO_V28, GDB_REGNO_V29, GDB_REGNO_V30, GDB_REGNO_V31, GDB_REGNO_COUNT }; diff --git a/src/target/riscv/opcodes.h b/src/target/riscv/opcodes.h index de85aadd8e..8faa154bae 100644 --- a/src/target/riscv/opcodes.h +++ b/src/target/riscv/opcodes.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + #include "encoding.h" #define ZERO 0 @@ -15,202 +17,202 @@ static uint32_t bit(uint32_t value, unsigned int b) return (value >> b) & 1; } +static uint32_t inst_rd(uint32_t r) __attribute__ ((unused)); +static uint32_t inst_rd(uint32_t r) +{ + return bits(r, 4, 0) << 7; +} + +static uint32_t inst_rs1(uint32_t r) __attribute__ ((unused)); +static uint32_t inst_rs1(uint32_t r) +{ + return bits(r, 4, 0) << 15; +} + +static uint32_t inst_rs2(uint32_t r) __attribute__ ((unused)); +static uint32_t inst_rs2(uint32_t r) +{ + return bits(r, 4, 0) << 20; +} + +static uint32_t imm_i(uint32_t imm) __attribute__ ((unused)); +static uint32_t imm_i(uint32_t imm) +{ + return bits(imm, 11, 0) << 20; +} + +static uint32_t imm_s(uint32_t imm) __attribute__ ((unused)); +static uint32_t imm_s(uint32_t imm) +{ + return (bits(imm, 4, 0) << 7) | (bits(imm, 11, 5) << 25); +} + +static uint32_t imm_b(uint32_t imm) __attribute__ ((unused)); +static uint32_t imm_b(uint32_t imm) +{ + return (bit(imm, 11) << 7) | (bits(imm, 4, 1) << 8) | (bits(imm, 10, 5) << 25) | (bit(imm, 12) << 31); +} + +static uint32_t imm_u(uint32_t imm) __attribute__ ((unused)); +static uint32_t imm_u(uint32_t imm) +{ + return bits(imm, 31, 12) << 12; +} + +static uint32_t imm_j(uint32_t imm) __attribute__ ((unused)); +static uint32_t imm_j(uint32_t imm) +{ + return (bits(imm, 19, 12) << 12) | (bit(imm, 11) << 20) | (bits(imm, 10, 1) << 21) | (bit(imm, 20) << 31); +} + static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused)); static uint32_t jal(unsigned int rd, uint32_t imm) { - return (bit(imm, 20) << 31) | - (bits(imm, 10, 1) << 21) | - (bit(imm, 11) << 20) | - (bits(imm, 19, 12) << 12) | - (rd << 7) | - MATCH_JAL; + return imm_j(imm) | inst_rd(rd) | MATCH_JAL; } static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused)); static uint32_t csrsi(unsigned int csr, uint16_t imm) { - return (csr << 20) | - (bits(imm, 4, 0) << 15) | - MATCH_CSRRSI; + return imm_i(csr) | inst_rs1(imm) | MATCH_CSRRSI; } static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 5) << 25) | - (src << 20) | - (base << 15) | - (bits(offset, 4, 0) << 7) | - MATCH_SW; + return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SW; } static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 5) << 25) | - (src << 20) | - (base << 15) | - (bits(offset, 4, 0) << 7) | - MATCH_SD; + return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SD; } static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 5) << 25) | - (src << 20) | - (base << 15) | - (bits(offset, 4, 0) << 7) | - MATCH_SH; + return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SH; } static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 5) << 25) | - (src << 20) | - (base << 15) | - (bits(offset, 4, 0) << 7) | - MATCH_SB; + return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SB; } static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 0) << 20) | - (base << 15) | - (bits(rd, 4, 0) << 7) | - MATCH_LD; + return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LD; } static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 0) << 20) | - (base << 15) | - (bits(rd, 4, 0) << 7) | - MATCH_LW; + return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LW; } static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 0) << 20) | - (base << 15) | - (bits(rd, 4, 0) << 7) | - MATCH_LH; + return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LH; } static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 0) << 20) | - (base << 15) | - (bits(rd, 4, 0) << 7) | - MATCH_LB; + return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LB; } static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused)); static uint32_t csrw(unsigned int source, unsigned int csr) { - return (csr << 20) | (source << 15) | MATCH_CSRRW; + return imm_i(csr) | inst_rs1(source) | MATCH_CSRRW; } static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) { - return (bits(imm, 11, 0) << 20) | - (src << 15) | - (dest << 7) | - MATCH_ADDI; + return imm_i(imm) | inst_rs1(src) | inst_rd(dest) | MATCH_ADDI; } static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused)); static uint32_t csrr(unsigned int rd, unsigned int csr) { - return (csr << 20) | (rd << 7) | MATCH_CSRRS; + return imm_i(csr) | inst_rd(rd) | MATCH_CSRRS; } static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused)); static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) { - return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRS; + return imm_i(csr) | inst_rs1(rs) | inst_rd(rd) | MATCH_CSRRS; } static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused)); static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) { - return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRW; + return imm_i(csr) | inst_rs1(rs) | inst_rd(rd) | MATCH_CSRRW; +} + +static uint32_t csrrci(unsigned int rd, unsigned int zimm, unsigned int csr) __attribute__ ((unused)); +static uint32_t csrrci(unsigned int rd, unsigned int zimm, unsigned int csr) +{ + return imm_i(csr) | inst_rs1(zimm) | inst_rd(rd) | MATCH_CSRRCI; +} + +static uint32_t csrrsi(unsigned int rd, unsigned int zimm, unsigned int csr) __attribute__ ((unused)); +static uint32_t csrrsi(unsigned int rd, unsigned int zimm, unsigned int csr) +{ + return imm_i(csr) | inst_rs1(zimm) | inst_rd(rd) | MATCH_CSRRSI; } static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 5) << 25) | - (bits(src, 4, 0) << 20) | - (base << 15) | - (bits(offset, 4, 0) << 7) | - MATCH_FSW; + return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_FSW; } static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 5) << 25) | - (bits(src, 4, 0) << 20) | - (base << 15) | - (bits(offset, 4, 0) << 7) | - MATCH_FSD; + return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_FSD; } static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 0) << 20) | - (base << 15) | - (bits(dest, 4, 0) << 7) | - MATCH_FLW; + return imm_i(offset) | inst_rs1(base) | inst_rd(dest) | MATCH_FLW; } static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused)); static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) { - return (bits(offset, 11, 0) << 20) | - (base << 15) | - (bits(dest, 4, 0) << 7) | - MATCH_FLD; + return imm_i(offset) | inst_rs1(base) | inst_rd(dest) | MATCH_FLD; } static uint32_t fmv_x_w(unsigned dest, unsigned src) __attribute__ ((unused)); static uint32_t fmv_x_w(unsigned dest, unsigned src) { - return src << 15 | - dest << 7 | - MATCH_FMV_X_W; + return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_X_W; } static uint32_t fmv_x_d(unsigned dest, unsigned src) __attribute__ ((unused)); static uint32_t fmv_x_d(unsigned dest, unsigned src) { - return src << 15 | - dest << 7 | - MATCH_FMV_X_D; + return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_X_D; } static uint32_t fmv_w_x(unsigned dest, unsigned src) __attribute__ ((unused)); static uint32_t fmv_w_x(unsigned dest, unsigned src) { - return src << 15 | - dest << 7 | - MATCH_FMV_W_X; + return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_W_X; } static uint32_t fmv_d_x(unsigned dest, unsigned src) __attribute__ ((unused)); static uint32_t fmv_d_x(unsigned dest, unsigned src) { - return src << 15 | - dest << 7 | - MATCH_FMV_D_X; + return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_D_X; } static uint32_t ebreak(void) __attribute__ ((unused)); @@ -236,9 +238,7 @@ static uint32_t fence_i(void) static uint32_t lui(unsigned int dest, uint32_t imm) __attribute__ ((unused)); static uint32_t lui(unsigned int dest, uint32_t imm) { - return (bits(imm, 19, 0) << 12) | - (dest << 7) | - MATCH_LUI; + return imm_u(imm) | inst_rd(dest) | MATCH_LUI; } /* @@ -285,19 +285,13 @@ static uint32_t nop(void) static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) { - return (bits(imm, 11, 0) << 20) | - (src << 15) | - (dest << 7) | - MATCH_XORI; + return imm_i(imm) | inst_rs1(src) | inst_rd(dest) | MATCH_XORI; } static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) __attribute__ ((unused)); static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) { - return (bits(shamt, 4, 0) << 20) | - (src << 15) | - (dest << 7) | - MATCH_SRLI; + return inst_rs2(shamt) | inst_rs1(src) | inst_rd(dest) | MATCH_SRLI; } static uint32_t fence(void) __attribute__((unused)); @@ -309,5 +303,32 @@ static uint32_t fence(void) static uint32_t auipc(unsigned int dest) __attribute__((unused)); static uint32_t auipc(unsigned int dest) { - return MATCH_AUIPC | (dest << 7); + return MATCH_AUIPC | inst_rd(dest); +} + +static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm) __attribute__((unused)); +static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm) +{ + return (bits(imm, 10, 0) << 20) | inst_rs1(src) | inst_rd(dest) | MATCH_VSETVLI; +} + +static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2) __attribute__((unused)); +static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2) +{ + return inst_rs2(vs2) | inst_rd(rd) | MATCH_VMV_X_S; } + +static uint32_t vmv_s_x(unsigned int vd, unsigned int vs2) __attribute__((unused)); +static uint32_t vmv_s_x(unsigned int vd, unsigned int rs1) +{ + return inst_rs1(rs1) | inst_rd(vd) | MATCH_VMV_S_X; +} + +static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2, + unsigned int rs1, unsigned int vm) __attribute__((unused)); +static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2, + unsigned int rs1, unsigned int vm) +{ + return ((vm & 1) << 25) | inst_rs2(vs2) | inst_rs1(rs1) | inst_rd(vd) | MATCH_VSLIDE1DOWN_VX; +} + diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 5e899b252d..0976539b3c 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -30,7 +32,7 @@ int riscv_program_init(struct riscv_program *p, struct target *target) int riscv_program_write(struct riscv_program *program) { for (unsigned i = 0; i < program->instruction_count; ++i) { - LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", program, i, program->debug_buffer[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) return ERROR_FAIL; @@ -56,7 +58,8 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) 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%08lx) [0x%08lx]", (int)i, (long)p->debug_buffer[i], (long)p->debug_buffer[i]); + LOG_ERROR("ram[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]", + (int)i, p->debug_buffer[i], p->debug_buffer[i]); return ERROR_FAIL; } @@ -79,6 +82,11 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) return ERROR_OK; } +int riscv_program_sdr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +{ + return riscv_program_insert(p, sd(d, b, offset)); +} + int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { return riscv_program_insert(p, sw(d, b, offset)); @@ -94,6 +102,11 @@ 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_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +{ + return riscv_program_insert(p, ld(d, b, offset)); +} + int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { return riscv_program_insert(p, lw(d, b, offset)); @@ -109,6 +122,18 @@ 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_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); + return riscv_program_insert(p, csrrsi(d, z, csr - GDB_REGNO_CSR0)); +} + +int riscv_program_csrrci(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr) +{ + assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); + return riscv_program_insert(p, csrrci(d, z, csr - GDB_REGNO_CSR0)); +} + int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index 310460c281..62a04f0933 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + #ifndef TARGET__RISCV__PROGRAM_H #define TARGET__RISCV__PROGRAM_H @@ -38,31 +40,25 @@ int riscv_program_write(struct riscv_program *program); * program to execute. That's OK, just make sure this eventually terminates. * */ int riscv_program_exec(struct riscv_program *p, struct target *t); -int riscv_program_load(struct riscv_program *p, struct target *t); - -/* Clears a program, removing all the state associated with it. */ -int riscv_program_clear(struct riscv_program *p, struct target *t); /* A lower level interface, you shouldn't use this unless you have a reason. */ int riscv_program_insert(struct riscv_program *p, riscv_insn_t i); -/* There is hardware support for saving at least one register. This register - * doesn't need to be saved/restored the usual way, which is useful during - * early initialization when we can't save/restore arbitrary registerrs to host - * memory. */ -int riscv_program_save_to_dscratch(struct riscv_program *p, enum gdb_regno to_save); - /* Helpers to assemble various instructions. Return 0 on success. These might * assemble into a multi-instruction sequence that overwrites some other * register, but those will be properly saved and restored. */ +int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); 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_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_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); int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr); int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr); diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index cb7b744da5..be296cdd8c 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Support for RISC-V, debug version 0.11. This was never an officially adopted * spec, but SiFive made some silicon that uses it. @@ -14,7 +16,7 @@ #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" -#include "log.h" +#include <helper/log.h> #include "jtag/jtag.h" #include "target/register.h" #include "target/breakpoints.h" @@ -68,8 +70,6 @@ #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) -#define DIM(x) (sizeof(x)/sizeof(*x)) - /* Constants for legacy SiFive hardware breakpoints. */ #define CSR_BPCONTROL_X (1<<0) #define CSR_BPCONTROL_W (1<<1) @@ -152,6 +152,9 @@ typedef enum slot { #define DMINFO_AUTHTYPE (3<<2) #define DMINFO_VERSION 3 +#define DMAUTHDATA0 0x12 +#define DMAUTHDATA1 0x13 + /*** Info about the core being debugged. ***/ #define DBUS_ADDRESS_UNKNOWN 0xffff @@ -204,7 +207,6 @@ typedef struct { * before the interrupt is cleared. */ unsigned int interrupt_high_delay; - bool need_strict_step; bool never_halted; } riscv011_info_t; @@ -217,8 +219,7 @@ 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 hartid, - int regid); +static int get_register(struct target *target, riscv_reg_t *value, int regid); /*** Utility functions. ***/ @@ -226,8 +227,10 @@ static int get_register(struct target *target, riscv_reg_t *value, int hartid, static riscv011_info_t *get_info(const struct target *target) { - riscv_info_t *info = (riscv_info_t *) target->arch_info; - return (riscv011_info_t *) info->version_specific; + struct riscv_info *info = target->arch_info; + assert(info); + assert(info->version_specific); + return info->version_specific; } static unsigned int slot_offset(const struct target *target, slot_t slot) @@ -519,6 +522,8 @@ typedef struct { static scans_t *scans_new(struct target *target, unsigned int scan_count) { scans_t *scans = malloc(sizeof(scans_t)); + if (!scans) + goto error0; scans->scan_count = scan_count; /* This code also gets called before xlen is detected. */ if (riscv_xlen(target)) @@ -527,10 +532,25 @@ static scans_t *scans_new(struct target *target, unsigned int scan_count) scans->scan_size = 2 + 128 / 8; scans->next_scan = 0; scans->in = calloc(scans->scan_size, scans->scan_count); + if (!scans->in) + goto error1; scans->out = calloc(scans->scan_size, scans->scan_count); + if (!scans->out) + goto error2; scans->field = calloc(scans->scan_count, sizeof(struct scan_field)); + if (!scans->field) + goto error3; scans->target = target; return scans; + +error3: + free(scans->out); +error2: + free(scans->in); +error1: + free(scans); +error0: + return NULL; } static scans_t *scans_delete(scans_t *scans) @@ -844,6 +864,8 @@ static int cache_write(struct target *target, unsigned int address, bool run) LOG_DEBUG("enter"); riscv011_info_t *info = get_info(target); scans_t *scans = scans_new(target, info->dramsize + 2); + if (!scans) + return ERROR_FAIL; unsigned int last = info->dramsize; for (unsigned int i = 0; i < info->dramsize; i++) { @@ -1012,7 +1034,7 @@ static int wait_for_state(struct target *target, enum target_state state) } } -static int read_csr(struct target *target, uint64_t *value, uint32_t csr) +static int read_remote_csr(struct target *target, uint64_t *value, uint32_t csr) { riscv011_info_t *info = get_info(target); cache_set32(target, 0, csrr(S0, csr)); @@ -1034,7 +1056,7 @@ static int read_csr(struct target *target, uint64_t *value, uint32_t csr) return ERROR_OK; } -static int write_csr(struct target *target, uint32_t csr, uint64_t value) +static int write_remote_csr(struct target *target, uint32_t csr, uint64_t value) { LOG_DEBUG("csr 0x%x <- 0x%" PRIx64, csr, value); cache_set_load(target, 0, S0, SLOT0); @@ -1062,7 +1084,7 @@ static int maybe_read_tselect(struct target *target) riscv011_info_t *info = get_info(target); if (info->tselect_dirty) { - int result = read_csr(target, &info->tselect, CSR_TSELECT); + int result = read_remote_csr(target, &info->tselect, CSR_TSELECT); if (result != ERROR_OK) return result; info->tselect_dirty = false; @@ -1076,7 +1098,7 @@ static int maybe_write_tselect(struct target *target) riscv011_info_t *info = get_info(target); if (!info->tselect_dirty) { - int result = write_csr(target, CSR_TSELECT, info->tselect); + int result = write_remote_csr(target, CSR_TSELECT, info->tselect); if (result != ERROR_OK) return result; info->tselect_dirty = true; @@ -1115,7 +1137,10 @@ static int execute_resume(struct target *target, bool step) } } - info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU; + 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_EBREAKH, 1); info->dcsr &= ~DCSR_HALT; if (step) @@ -1209,7 +1234,7 @@ static int update_mstatus_actual(struct target *target) /* Force reading the register. In that process mstatus_actual will be * updated. */ riscv_reg_t mstatus; - return get_register(target, &mstatus, 0, GDB_REGNO_MSTATUS); + return get_register(target, &mstatus, GDB_REGNO_MSTATUS); } /*** OpenOCD target functions. ***/ @@ -1255,7 +1280,7 @@ static int register_write(struct target *target, unsigned int number, if (number == S0) { cache_set_load(target, 0, S0, SLOT0); - cache_set32(target, 1, csrw(S0, CSR_DSCRATCH)); + cache_set32(target, 1, csrw(S0, CSR_DSCRATCH0)); cache_set_jump(target, 2); } else if (number == S1) { cache_set_load(target, 0, S0, SLOT0); @@ -1313,10 +1338,8 @@ static int register_write(struct target *target, unsigned int number, return ERROR_OK; } -static int get_register(struct target *target, riscv_reg_t *value, int hartid, - int regid) +static int get_register(struct target *target, riscv_reg_t *value, int regid) { - assert(hartid == 0); riscv011_info_t *info = get_info(target); maybe_write_tselect(target); @@ -1359,10 +1382,8 @@ static int get_register(struct target *target, riscv_reg_t *value, int hartid, return ERROR_OK; } -static int set_register(struct target *target, int hartid, int regid, - uint64_t value) +static int set_register(struct target *target, int regid, uint64_t value) { - assert(hartid == 0); return register_write(target, regid, value); } @@ -1384,37 +1405,19 @@ static int halt(struct target *target) return ERROR_OK; } -static int init_target(struct command_context *cmd_ctx, - struct target *target) -{ - LOG_DEBUG("init"); - riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; - generic_info->get_register = get_register; - generic_info->set_register = set_register; - - generic_info->version_specific = calloc(1, sizeof(riscv011_info_t)); - if (!generic_info->version_specific) - return ERROR_FAIL; - - /* Assume 32-bit until we discover the real value in examine(). */ - generic_info->xlen[0] = 32; - riscv_init_registers(target); - - return ERROR_OK; -} - 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; } static int strict_step(struct target *target, bool announce) { - riscv011_info_t *info = get_info(target); - LOG_DEBUG("enter"); struct watchpoint *watchpoint = target->watchpoints; @@ -1433,16 +1436,12 @@ static int strict_step(struct target *target, bool announce) watchpoint = watchpoint->next; } - info->need_strict_step = false; - return ERROR_OK; } static int step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { - riscv011_info_t *info = get_info(target); - jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); if (!current) { @@ -1455,7 +1454,7 @@ static int step(struct target *target, int current, target_addr_t address, return result; } - if (info->need_strict_step || handle_breakpoints) { + if (handle_breakpoints) { int result = strict_step(target, true); if (result != ERROR_OK) return result; @@ -1486,7 +1485,6 @@ static int examine(struct target *target) } RISCV_INFO(r); - r->hart_count = 1; riscv011_info_t *info = get_info(target); info->addrbits = get_field(dtmcontrol, DTMCONTROL_ADDRBITS); @@ -1528,7 +1526,7 @@ static int examine(struct target *target) } /* Pretend this is a 32-bit system until we have found out the true value. */ - r->xlen[0] = 32; + r->xlen = 32; /* Figure out XLEN, and test writing all of Debug RAM while we're at it. */ cache_set32(target, 0, xori(S1, ZERO, -1)); @@ -1554,13 +1552,13 @@ 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[0] = 32; + generic_info->xlen = 32; } else if (word0 == 0xffffffff && word1 == 3) { - generic_info->xlen[0] = 64; + generic_info->xlen = 64; } else if (word0 == 0xffffffff && word1 == 0xffffffff) { - generic_info->xlen[0] = 128; + generic_info->xlen = 128; } else { uint32_t exception = cache_get32(target, info->dramsize-1); LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x, exception=0x%x", @@ -1570,11 +1568,11 @@ static int examine(struct target *target) } LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target)); - if (read_csr(target, &r->misa[0], CSR_MISA) != ERROR_OK) { + if (read_remote_csr(target, &r->misa, CSR_MISA) != ERROR_OK) { const unsigned old_csr_misa = 0xf10; LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA, old_csr_misa); - if (read_csr(target, &r->misa[0], old_csr_misa) != ERROR_OK) { + if (read_remote_csr(target, &r->misa, old_csr_misa) != ERROR_OK) { /* Maybe this is an old core that still has $misa at the old * address. */ LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa); @@ -1596,7 +1594,7 @@ static int examine(struct target *target) for (size_t i = 0; i < 32; ++i) reg_cache_set(target, i, -1); LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64, - riscv_xlen(target), r->misa[0]); + riscv_xlen(target), r->misa); return ERROR_OK; } @@ -1606,6 +1604,8 @@ static riscv_error_t handle_halt_routine(struct target *target) riscv011_info_t *info = get_info(target); scans_t *scans = scans_new(target, 256); + if (!scans) + return RE_FAIL; /* Read all GPRs as fast as we can, because gdb is going to ask for them * anyway. Reading them one at a time is much slower. */ @@ -1634,8 +1634,8 @@ static riscv_error_t handle_halt_routine(struct target *target) scans_add_read(scans, SLOT0, false); /* Read S0 from dscratch */ - unsigned int csr[] = {CSR_DSCRATCH, CSR_DPC, CSR_DCSR}; - for (unsigned int i = 0; i < DIM(csr); i++) { + unsigned int csr[] = {CSR_DSCRATCH0, CSR_DPC, CSR_DCSR}; + for (unsigned int i = 0; i < ARRAY_SIZE(csr); i++) { scans_add_write32(scans, 0, csrr(S0, csr[i]), true); scans_add_read(scans, SLOT0, false); } @@ -1848,9 +1848,6 @@ static int handle_halt(struct target *target, bool announce) break; case DCSR_CAUSE_HWBP: target->debug_reason = DBG_REASON_WATCHPOINT; - /* If we halted because of a data trigger, gdb doesn't know to do - * the disable-breakpoints-step-enable-breakpoints dance. */ - info->need_strict_step = true; break; case DCSR_CAUSE_DEBUGINT: target->debug_reason = DBG_REASON_DBGRQ; @@ -1935,26 +1932,10 @@ static int riscv011_poll(struct target *target) static int riscv011_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { - riscv011_info_t *info = get_info(target); - + RISCV_INFO(r); jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); - if (!current) { - if (riscv_xlen(target) > 32) { - LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.", - riscv_xlen(target)); - } - int result = register_write(target, GDB_REGNO_PC, address); - if (result != ERROR_OK) - return result; - } - - if (info->need_strict_step || handle_breakpoints) { - int result = strict_step(target, false); - if (result != ERROR_OK) - return result; - } - + r->prepped = false; return resume(target, debug_execution, false); } @@ -1973,8 +1954,11 @@ 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 |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | - DCSR_EBREAKU | DCSR_HALT; + 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_EBREAKH, 1); + info->dcsr |= DCSR_HALT; if (target->reset_halt) info->dcsr |= DCSR_NDRESET; else @@ -2001,8 +1985,13 @@ static int deassert_reset(struct target *target) } static int read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { + if (increment != size) { + LOG_ERROR("read_memory with custom increment not implemented"); + return ERROR_NOT_IMPLEMENTED; + } + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16)); @@ -2029,6 +2018,8 @@ static int read_memory(struct target *target, target_addr_t address, riscv011_info_t *info = get_info(target); const unsigned max_batch_size = 256; scans_t *scans = scans_new(target, max_batch_size); + if (!scans) + return ERROR_FAIL; uint32_t result_value = 0x777; uint32_t i = 0; @@ -2185,6 +2176,8 @@ static int write_memory(struct target *target, target_addr_t address, const unsigned max_batch_size = 256; scans_t *scans = scans_new(target, max_batch_size); + if (!scans) + return ERROR_FAIL; uint32_t result_value = 0x777; uint32_t i = 0; @@ -2304,6 +2297,100 @@ static int arch_state(struct target *target) return ERROR_OK; } +static COMMAND_HELPER(riscv011_print_info, struct target *target) +{ + /* Abstract description. */ + riscv_print_info_line(CMD, "target", "memory.read_while_running8", 0); + riscv_print_info_line(CMD, "target", "memory.write_while_running8", 0); + riscv_print_info_line(CMD, "target", "memory.read_while_running16", 0); + riscv_print_info_line(CMD, "target", "memory.write_while_running16", 0); + riscv_print_info_line(CMD, "target", "memory.read_while_running32", 0); + riscv_print_info_line(CMD, "target", "memory.write_while_running32", 0); + riscv_print_info_line(CMD, "target", "memory.read_while_running64", 0); + riscv_print_info_line(CMD, "target", "memory.write_while_running64", 0); + riscv_print_info_line(CMD, "target", "memory.read_while_running128", 0); + riscv_print_info_line(CMD, "target", "memory.write_while_running128", 0); + + uint32_t dminfo = dbus_read(target, DMINFO); + riscv_print_info_line(CMD, "dm", "authenticated", get_field(dminfo, DMINFO_AUTHENTICATED)); + + return 0; +} + +static int wait_for_authbusy(struct target *target) +{ + time_t start = time(NULL); + while (1) { + uint32_t dminfo = dbus_read(target, DMINFO); + if (!get_field(dminfo, DMINFO_AUTHBUSY)) + break; + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, + dminfo); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static int riscv011_authdata_read(struct target *target, uint32_t *value, unsigned int index) +{ + if (index > 1) { + LOG_ERROR("Spec 0.11 only has a two authdata registers."); + return ERROR_FAIL; + } + + if (wait_for_authbusy(target) != ERROR_OK) + return ERROR_FAIL; + + uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0; + *value = dbus_read(target, authdata_address); + + return ERROR_OK; +} + +static int riscv011_authdata_write(struct target *target, uint32_t value, unsigned int index) +{ + if (index > 1) { + LOG_ERROR("Spec 0.11 only has a two authdata registers."); + return ERROR_FAIL; + } + + if (wait_for_authbusy(target) != ERROR_OK) + return ERROR_FAIL; + + uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0; + dbus_write(target, authdata_address, value); + + return ERROR_OK; +} + +static int init_target(struct command_context *cmd_ctx, + struct target *target) +{ + LOG_DEBUG("init"); + RISCV_INFO(generic_info); + generic_info->get_register = get_register; + generic_info->set_register = set_register; + generic_info->read_memory = read_memory; + generic_info->authdata_read = &riscv011_authdata_read; + generic_info->authdata_write = &riscv011_authdata_write; + generic_info->print_info = &riscv011_print_info; + + generic_info->version_specific = calloc(1, sizeof(riscv011_info_t)); + if (!generic_info->version_specific) + return ERROR_FAIL; + + /* Assume 32-bit until we discover the real value in examine(). */ + generic_info->xlen = 32; + riscv_init_registers(target); + + return ERROR_OK; +} + struct target_type riscv011_target = { .name = "riscv", @@ -2321,7 +2408,6 @@ struct target_type riscv011_target = { .assert_reset = assert_reset, .deassert_reset = deassert_reset, - .read_memory = read_memory, .write_memory = write_memory, .arch_state = arch_state, diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 2f8da5b36d..2f4a8fe2e6 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Support for RISC-V, debug version 0.13, which is currently (2/4/17) the * latest draft. @@ -14,7 +16,7 @@ #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" -#include "log.h" +#include <helper/log.h> #include "jtag/jtag.h" #include "target/register.h" #include "target/breakpoints.h" @@ -27,24 +29,23 @@ #include "asm.h" #include "batch.h" -#define DMI_DATA1 (DMI_DATA0 + 1) -#define DMI_PROGBUF1 (DMI_PROGBUF0 + 1) - 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 int riscv013_step_or_resume_current_hart(struct target *target, + bool step, bool use_hasel); static void 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 hid, int rid); -static int riscv013_set_register(struct target *target, int hartid, int regid, uint64_t value); + riscv_reg_t *value, int rid); +static int riscv013_set_register(struct target *target, int regid, uint64_t value); static int riscv013_select_current_hart(struct target *target); -static int riscv013_halt_current_hart(struct target *target); -static int riscv013_resume_current_hart(struct target *target); +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_on_resume(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, @@ -61,16 +62,9 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t static int register_write_direct(struct target *target, unsigned number, uint64_t value); static int read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer); + 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); -static int riscv013_test_compliance(struct target *target); /** * Since almost everything can be accomplish by scanning the dbus register, all @@ -82,13 +76,12 @@ static int riscv013_test_compliance(struct target *target); #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) -#define DIM(x) (sizeof(x)/sizeof(*x)) - #define CSR_DCSR_CAUSE_SWBP 1 #define CSR_DCSR_CAUSE_TRIGGER 2 #define CSR_DCSR_CAUSE_DEBUGINT 3 #define CSR_DCSR_CAUSE_STEP 4 #define CSR_DCSR_CAUSE_HALT 5 +#define CSR_DCSR_CAUSE_GROUP 6 #define RISCV013_INFO(r) riscv013_info_t *r = get_info(target) @@ -105,12 +98,6 @@ typedef enum { DMI_STATUS_BUSY = 3 } dmi_status_t; -typedef enum { - RE_OK, - RE_FAIL, - RE_AGAIN -} riscv_error_t; - typedef enum slot { SLOT0, SLOT1, @@ -146,12 +133,20 @@ typedef enum { typedef struct { struct list_head list; int abs_chain_position; + + /* 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. */ bool was_reset; /* Targets that are connected to this DM. */ struct list_head target_list; /* The currently selected hartid on this DM. */ int current_hartid; + bool hasel_supported; + + /* The program buffer stores executable code. 0 is an illegal instruction, + * so we use 0 to mean the cached value is invalid. */ + uint32_t progbuf_cache[16]; } dm013_info_t; typedef struct { @@ -160,6 +155,8 @@ typedef struct { } target_list_t; typedef struct { + /* The indexed used to address this hart in its DM. */ + unsigned index; /* Number of address bits in the dbus register. */ unsigned abits; /* Number of abstract command data registers. */ @@ -199,6 +196,8 @@ typedef struct { bool abstract_read_fpr_supported; bool abstract_write_fpr_supported; + 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.) */ @@ -216,12 +215,14 @@ typedef struct { dm013_info_t *dm; } 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; - return (riscv013_info_t *) info->version_specific; + struct riscv_info *info = target->arch_info; + assert(info); + assert(info->version_specific); + return info->version_specific; } /** @@ -247,9 +248,13 @@ static dm013_info_t *get_dm(struct target *target) } if (!dm) { + LOG_DEBUG("[%d] Allocating new DM", target->coreid); dm = calloc(1, sizeof(dm013_info_t)); + if (!dm) + return NULL; dm->abs_chain_position = abs_chain_position; dm->current_hartid = -1; + dm->hart_count = -1; INIT_LIST_HEAD(&dm->target_list); list_add(&dm->list, &dm_list); } @@ -261,6 +266,10 @@ static dm013_info_t *get_dm(struct target *target) return dm; } target_entry = calloc(1, sizeof(*target_entry)); + if (!target_entry) { + info->dm = NULL; + return NULL; + } target_entry->target = target; list_add(&target_entry->list, &dm->target_list); @@ -269,14 +278,14 @@ static dm013_info_t *get_dm(struct target *target) static uint32_t set_hartsel(uint32_t initial, uint32_t index) { - initial &= ~DMI_DMCONTROL_HARTSELLO; - initial &= ~DMI_DMCONTROL_HARTSELHI; + initial &= ~DM_DMCONTROL_HARTSELLO; + initial &= ~DM_DMCONTROL_HARTSELHI; - uint32_t index_lo = index & ((1 << DMI_DMCONTROL_HARTSELLO_LENGTH) - 1); - initial |= index_lo << DMI_DMCONTROL_HARTSELLO_OFFSET; - uint32_t index_hi = index >> DMI_DMCONTROL_HARTSELLO_LENGTH; - assert(index_hi < 1 << DMI_DMCONTROL_HARTSELHI_LENGTH); - initial |= index_hi << DMI_DMCONTROL_HARTSELHI_OFFSET; + uint32_t index_lo = index & ((1 << DM_DMCONTROL_HARTSELLO_LENGTH) - 1); + initial |= index_lo << DM_DMCONTROL_HARTSELLO_OFFSET; + uint32_t index_hi = index >> DM_DMCONTROL_HARTSELLO_LENGTH; + assert(index_hi < 1 << DM_DMCONTROL_HARTSELHI_LENGTH); + initial |= index_hi << DM_DMCONTROL_HARTSELHI_OFFSET; return initial; } @@ -288,56 +297,60 @@ static void decode_dmi(char *text, unsigned address, unsigned data) uint64_t mask; const char *name; } description[] = { - { DMI_DMCONTROL, DMI_DMCONTROL_HALTREQ, "haltreq" }, - { DMI_DMCONTROL, DMI_DMCONTROL_RESUMEREQ, "resumereq" }, - { DMI_DMCONTROL, DMI_DMCONTROL_HARTRESET, "hartreset" }, - { DMI_DMCONTROL, DMI_DMCONTROL_HASEL, "hasel" }, - { DMI_DMCONTROL, DMI_DMCONTROL_HARTSELHI, "hartselhi" }, - { DMI_DMCONTROL, DMI_DMCONTROL_HARTSELLO, "hartsello" }, - { DMI_DMCONTROL, DMI_DMCONTROL_NDMRESET, "ndmreset" }, - { DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE, "dmactive" }, - { DMI_DMCONTROL, DMI_DMCONTROL_ACKHAVERESET, "ackhavereset" }, - - { DMI_DMSTATUS, DMI_DMSTATUS_IMPEBREAK, "impebreak" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ALLHAVERESET, "allhavereset" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ANYHAVERESET, "anyhavereset" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ALLRESUMEACK, "allresumeack" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ANYRESUMEACK, "anyresumeack" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ALLNONEXISTENT, "allnonexistent" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ANYNONEXISTENT, "anynonexistent" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ALLUNAVAIL, "allunavail" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ANYUNAVAIL, "anyunavail" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ALLRUNNING, "allrunning" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ANYRUNNING, "anyrunning" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ALLHALTED, "allhalted" }, - { DMI_DMSTATUS, DMI_DMSTATUS_ANYHALTED, "anyhalted" }, - { DMI_DMSTATUS, DMI_DMSTATUS_AUTHENTICATED, "authenticated" }, - { DMI_DMSTATUS, DMI_DMSTATUS_AUTHBUSY, "authbusy" }, - { DMI_DMSTATUS, DMI_DMSTATUS_DEVTREEVALID, "devtreevalid" }, - { DMI_DMSTATUS, DMI_DMSTATUS_VERSION, "version" }, - - { DMI_ABSTRACTCS, DMI_ABSTRACTCS_PROGBUFSIZE, "progbufsize" }, - { DMI_ABSTRACTCS, DMI_ABSTRACTCS_BUSY, "busy" }, - { DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR, "cmderr" }, - { DMI_ABSTRACTCS, DMI_ABSTRACTCS_DATACOUNT, "datacount" }, - - { DMI_COMMAND, DMI_COMMAND_CMDTYPE, "cmdtype" }, - - { DMI_SBCS, DMI_SBCS_SBREADONADDR, "sbreadonaddr" }, - { DMI_SBCS, DMI_SBCS_SBACCESS, "sbaccess" }, - { DMI_SBCS, DMI_SBCS_SBAUTOINCREMENT, "sbautoincrement" }, - { DMI_SBCS, DMI_SBCS_SBREADONDATA, "sbreadondata" }, - { DMI_SBCS, DMI_SBCS_SBERROR, "sberror" }, - { DMI_SBCS, DMI_SBCS_SBASIZE, "sbasize" }, - { DMI_SBCS, DMI_SBCS_SBACCESS128, "sbaccess128" }, - { DMI_SBCS, DMI_SBCS_SBACCESS64, "sbaccess64" }, - { DMI_SBCS, DMI_SBCS_SBACCESS32, "sbaccess32" }, - { DMI_SBCS, DMI_SBCS_SBACCESS16, "sbaccess16" }, - { DMI_SBCS, DMI_SBCS_SBACCESS8, "sbaccess8" }, + { 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" }, }; text[0] = 0; - for (unsigned i = 0; i < DIM(description); i++) { + 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); @@ -376,10 +389,9 @@ static void dump_field(int idle, const struct scan_field *field) log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, "scan", - "%db %di %s %08x @%02x -> %s %08x @%02x", - field->num_bits, idle, - op_string[out_op], out_data, out_address, - status_string[in_op], in_data, in_address); + "%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]; @@ -395,6 +407,10 @@ static void dump_field(int idle, const struct scan_field *field) static void select_dmi(struct target *target) { + if (bscan_tunnel_ir_width != 0) { + select_dmi_via_bscan(target); + return; + } jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); } @@ -404,6 +420,9 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) uint8_t in_value[4]; uint8_t out_value[4] = { 0 }; + if (bscan_tunnel_ir_width != 0) + return dtmcontrol_scan_via_bscan(target, out); + buf_set_u32(out_value, 0, 32, out); jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); @@ -458,6 +477,7 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, .out_value = out, .in_value = in }; + riscv_bscan_tunneled_scan_context_t bscan_ctxt; if (r->reset_delays_wait >= 0) { r->reset_delays_wait--; @@ -476,8 +496,18 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, buf_set_u32(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out); buf_set_u32(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out); - /* Assume dbus is already selected. */ - jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); + /* I wanted to place this code in a different function, but the way JTAG command + queueing works in the jtag handling functions, the scan fields either have to be + heap allocated, global/static, or else they need to stay on the stack until + the jtag_execute_queue() call. Heap or static fields in this case doesn't seem + the best fit. Declaring stack based field values in a subsidiary function call wouldn't + work. */ + if (bscan_tunnel_ir_width != 0) { + riscv_add_bscan_tunneled_scan(target, &field, &bscan_ctxt); + } else { + /* Assume dbus is already selected. */ + jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); + } int idle_count = info->dmi_busy_delay; if (exec) @@ -489,25 +519,44 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("dmi_scan failed jtag scan"); + if (data_in) + *data_in = ~0; return DMI_STATUS_FAILED; } + if (bscan_tunnel_ir_width != 0) { + /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */ + buffer_shr(in, num_bytes, 1); + } + if (data_in) *data_in = buf_get_u32(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); if (address_in) *address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits); - dump_field(idle_count, &field); - return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); } -/* If dmi_busy_encountered is non-NULL, this function will use it to tell the - * caller whether DMI was ever busy during this call. */ +/** + * @param target + * @param data_in The data we received from the target. + * @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 address The address argument to that operation. + * @param data_out The data to send to the target. + * @param timeout_sec + * @param exec When true, this scan will execute something, so extra RTI + * cycles may be added. + * @param ensure_success + * Scan a nop after the requested operation, ensuring the + * 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, - uint32_t data_out, int timeout_sec, bool exec) + uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) { select_dmi(target); @@ -533,6 +582,8 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, return ERROR_FAIL; } + keep_alive(); + time_t start = time(NULL); /* This first loop performs the request. Note that if for some reason this * stays busy, it is actually due to the previous access. */ @@ -547,6 +598,7 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, break; } else { LOG_ERROR("failed %s at 0x%x, status=%d", op_name, address, status); + dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); return ERROR_FAIL; } if (time(NULL) - start > timeout_sec) @@ -558,34 +610,33 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, return ERROR_FAIL; } - /* This second loop ensures the request succeeded, and gets back data. - * 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, - false); - if (status == DMI_STATUS_BUSY) { - increase_dmi_busy_delay(target); - } else if (status == DMI_STATUS_SUCCESS) { - break; - } else { - LOG_ERROR("failed %s (NOP) at 0x%x, status=%d", op_name, address, - status); - return ERROR_FAIL; - } - if (time(NULL) - start > timeout_sec) - return ERROR_TIMEOUT_REACHED; - } - - if (status != DMI_STATUS_SUCCESS) { - if (status == DMI_STATUS_FAILED || !data_in) { - LOG_ERROR("Failed %s (NOP) at 0x%x; status=%d", op_name, address, - status); - } else { - LOG_ERROR("Failed %s (NOP) at 0x%x; value=0x%x, status=%d", - op_name, address, *data_in, status); + if (ensure_success) { + /* This second loop ensures the request succeeded, and gets back data. + * 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, + false); + if (status == DMI_STATUS_BUSY) { + increase_dmi_busy_delay(target); + if (dmi_busy_encountered) + *dmi_busy_encountered = true; + } else if (status == DMI_STATUS_SUCCESS) { + break; + } else { + if (data_in) { + LOG_ERROR("Failed %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, + status); + } + dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); + return ERROR_FAIL; + } + if (time(NULL) - start > timeout_sec) + return ERROR_TIMEOUT_REACHED; } - return ERROR_FAIL; } return ERROR_OK; @@ -593,10 +644,10 @@ 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, - uint32_t data_out, bool exec) + uint32_t data_out, bool exec, bool ensure_success) { int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, dmi_op, - address, data_out, riscv_command_timeout_sec, exec); + address, data_out, riscv_command_timeout_sec, exec, ensure_success); if (result == ERROR_TIMEOUT_REACHED) { LOG_ERROR("DMI operation didn't complete in %d seconds. The target is " "either really slow or broken. You could increase the " @@ -609,32 +660,39 @@ static int dmi_op(struct target *target, uint32_t *data_in, static int dmi_read(struct target *target, uint32_t *value, uint32_t address) { - return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, false); + return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, false, true); } static int dmi_read_exec(struct target *target, uint32_t *value, uint32_t address) { - return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, true); + return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, true, true); } static int dmi_write(struct target *target, uint32_t address, uint32_t value) { - return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, false); + return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, false, true); } -static int dmi_write_exec(struct target *target, uint32_t address, uint32_t value) +static int dmi_write_exec(struct target *target, uint32_t address, + uint32_t value, bool ensure_success) { - return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, true); + 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 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, - DMI_DMSTATUS, 0, timeout_sec, false); + DM_DMSTATUS, 0, timeout_sec, false, true); if (result != ERROR_OK) return result; - if (authenticated && !get_field(*dmstatus, DMI_DMSTATUS_AUTHENTICATED)) { + 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 " + "signal issue. Try reducing the JTAG clock speed.", + get_field(*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 " "`riscv authdata_write` commands to authenticate.", *dmstatus); @@ -643,7 +701,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) { return dmstatus_read_timeout(target, dmstatus, authenticated, @@ -659,15 +717,15 @@ static void increase_ac_busy_delay(struct target *target) 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: - return set_field(0, AC_ACCESS_REGISTER_SIZE, 2); + return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 2); case 64: - return set_field(0, AC_ACCESS_REGISTER_SIZE, 3); + return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 3); case 128: - return set_field(0, AC_ACCESS_REGISTER_SIZE, 4); + return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 4); default: LOG_ERROR("Unsupported register width: %d", width); return 0; @@ -679,14 +737,14 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) RISCV013_INFO(info); time_t start = time(NULL); while (1) { - if (dmi_read(target, abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + if (dmi_read(target, abstractcs, DM_ABSTRACTCS) != ERROR_OK) return ERROR_FAIL; - if (get_field(*abstractcs, DMI_ABSTRACTCS_BUSY) == 0) + if (get_field(*abstractcs, DM_ABSTRACTCS_BUSY) == 0) return ERROR_OK; if (time(NULL) - start > riscv_command_timeout_sec) { - info->cmderr = get_field(*abstractcs, DMI_ABSTRACTCS_CMDERR); + info->cmderr = get_field(*abstractcs, DM_ABSTRACTCS_CMDERR); if (info->cmderr != CMDERR_NONE) { const char *errors[8] = { "none", @@ -715,12 +773,12 @@ static int execute_abstract_command(struct target *target, uint32_t command) { RISCV013_INFO(info); if (debug_level >= LOG_LVL_DEBUG) { - switch (get_field(command, DMI_COMMAND_CMDTYPE)) { + 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_SIZE), + 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), @@ -732,17 +790,17 @@ static int execute_abstract_command(struct target *target, uint32_t command) } } - dmi_write_exec(target, DMI_COMMAND, command); + if (dmi_write_exec(target, DM_COMMAND, command, false) != ERROR_OK) + return ERROR_FAIL; uint32_t abstractcs = 0; - wait_for_idle(target, &abstractcs); + int result = wait_for_idle(target, &abstractcs); - info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); - if (info->cmderr != 0) { + 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, DMI_ABSTRACTCS, set_field(0, DMI_ABSTRACTCS_CMDERR, - info->cmderr)); + dmi_write(target, DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR); return ERROR_FAIL; } @@ -757,14 +815,14 @@ 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", size_bits); + LOG_ERROR("Unsupported size: %d bits", size_bits); return ~0; case 64: - dmi_read(target, &v, DMI_DATA0 + offset + 1); + dmi_read(target, &v, DM_DATA0 + offset + 1); value |= ((uint64_t) v) << 32; /* falls through */ case 32: - dmi_read(target, &v, DMI_DATA0 + offset); + dmi_read(target, &v, DM_DATA0 + offset); value |= v; } return value; @@ -776,13 +834,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", size_bits); + LOG_ERROR("Unsupported size: %d bits", size_bits); return ERROR_FAIL; case 64: - dmi_write(target, DMI_DATA0 + offset + 1, value >> 32); + dmi_write(target, DM_DATA0 + offset + 1, value >> 32); /* falls through */ case 32: - dmi_write(target, DMI_DATA0 + offset, value); + dmi_write(target, DM_DATA0 + offset, value); } return ERROR_OK; } @@ -793,15 +851,17 @@ static int write_abstract_arg(struct target *target, unsigned index, static uint32_t access_register_command(struct target *target, uint32_t number, unsigned size, uint32_t flags) { - uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0); + uint32_t command = set_field(0, DM_COMMAND_CMDTYPE, 0); switch (size) { case 32: - command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2); + command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 2); break; case 64: - command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3); + command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 3); break; default: + LOG_ERROR("%d-bit register %s not supported.", size, + gdb_regno_name(number)); assert(0); } @@ -821,6 +881,8 @@ static uint32_t access_register_command(struct target *target, uint32_t number, assert(reg_info); command = set_field(command, AC_ACCESS_REGISTER_REGNO, 0xc000 + reg_info->custom_number); + } else { + assert(0); } command |= flags; @@ -839,6 +901,9 @@ static int register_read_abstract(struct target *target, uint64_t *value, if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && !info->abstract_read_csr_supported) return ERROR_FAIL; + /* The spec doesn't define abstract register numbers for vector registers. */ + if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) + return ERROR_FAIL; uint32_t command = access_register_command(target, number, size, AC_ACCESS_REGISTER_TRANSFER); @@ -899,6 +964,45 @@ static int register_write_abstract(struct target *target, uint32_t number, return ERROR_OK; } +/* + * Sets the AAMSIZE field of a memory access abstract command based on + * the width (bits). + */ +static uint32_t abstract_memory_size(unsigned width) +{ + switch (width) { + case 8: + return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 0); + case 16: + return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 1); + case 32: + return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 2); + case 64: + return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 3); + case 128: + return set_field(0, AC_ACCESS_MEMORY_AAMSIZE, 4); + default: + LOG_ERROR("Unsupported memory width: %d", width); + return 0; + } +} + +/* + * Creates a memory access abstract command. + */ +static uint32_t access_memory_command(struct target *target, bool virtual, + unsigned width, bool postincrement, bool 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); + + return command; +} + static int examine_progbuf(struct target *target) { riscv013_info_t *info = get_info(target); @@ -942,7 +1046,7 @@ static int examine_progbuf(struct target *target) } uint32_t written; - if (dmi_read(target, &written, DMI_PROGBUF0) != ERROR_OK) + if (dmi_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, @@ -958,8 +1062,58 @@ static int examine_progbuf(struct target *target) return ERROR_OK; } +static int is_fpu_reg(uint32_t gdb_regno) +{ + return (gdb_regno >= GDB_REGNO_FPR0 && gdb_regno <= GDB_REGNO_FPR31) || + (gdb_regno == GDB_REGNO_CSR0 + CSR_FFLAGS) || + (gdb_regno == GDB_REGNO_CSR0 + CSR_FRM) || + (gdb_regno == GDB_REGNO_CSR0 + CSR_FCSR); +} + +static int is_vector_reg(uint32_t 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_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) +{ + if (is_fpu_reg(regno) || is_vector_reg(regno)) { + if (register_read(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; + } + return ERROR_OK; +} + +static int cleanup_after_register_access(struct target *target, + uint64_t mstatus, int 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; +} + typedef enum { - SPACE_DMI_DATA, + SPACE_DM_DATA, SPACE_DMI_PROGBUF, SPACE_DMI_RAM } memory_space_t; @@ -990,6 +1144,7 @@ static int scratch_reserve(struct target *target, riscv013_info_t *info = get_info(target); + /* Option 1: See if data# registers can be used as the scratch memory */ if (info->dataaccess == 1) { /* Sign extend dataaddr. */ scratch->hart_address = info->dataaddr; @@ -1000,12 +1155,13 @@ static int scratch_reserve(struct target *target, if ((size_bytes + scratch->hart_address - info->dataaddr + 3) / 4 >= info->datasize) { - scratch->memory_space = SPACE_DMI_DATA; + scratch->memory_space = SPACE_DM_DATA; scratch->debug_address = (scratch->hart_address - info->dataaddr) / 4; return ERROR_OK; } } + /* Option 2: See if progbuf can be used as the scratch memory */ if (examine_progbuf(target) != ERROR_OK) return ERROR_FAIL; @@ -1013,13 +1169,15 @@ static int scratch_reserve(struct target *target, unsigned program_size = (program->instruction_count + 1) * 4; scratch->hart_address = (info->progbuf_address + program_size + alignment - 1) & ~(alignment - 1); - if ((size_bytes + scratch->hart_address - info->progbuf_address + 3) / 4 >= - info->progbufsize) { + if ((info->progbuf_writable == YNM_YES) && + ((size_bytes + scratch->hart_address - info->progbuf_address + 3) / 4 >= + info->progbufsize)) { scratch->memory_space = SPACE_DMI_PROGBUF; scratch->debug_address = (scratch->hart_address - info->progbuf_address) / 4; return ERROR_OK; } + /* Option 3: User-configured memory area as scratch RAM */ if (target_alloc_working_area(target, size_bytes + alignment - 1, &scratch->area) == ERROR_OK) { scratch->hart_address = (scratch->area->address + alignment - 1) & @@ -1037,10 +1195,7 @@ static int scratch_reserve(struct target *target, static int scratch_release(struct target *target, scratch_mem_t *scratch) { - if (scratch->area) - return target_free_working_area(target, scratch->area); - - return ERROR_OK; + return target_free_working_area(target, scratch->area); } static int scratch_read64(struct target *target, scratch_mem_t *scratch, @@ -1048,26 +1203,26 @@ static int scratch_read64(struct target *target, scratch_mem_t *scratch, { uint32_t v; switch (scratch->memory_space) { - case SPACE_DMI_DATA: - if (dmi_read(target, &v, DMI_DATA0 + scratch->debug_address) != ERROR_OK) + case SPACE_DM_DATA: + if (dmi_read(target, &v, DM_DATA0 + scratch->debug_address) != ERROR_OK) return ERROR_FAIL; *value = v; - if (dmi_read(target, &v, DMI_DATA1 + scratch->debug_address) != ERROR_OK) + if (dmi_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, DMI_PROGBUF0 + scratch->debug_address) != ERROR_OK) + if (dmi_read(target, &v, DM_PROGBUF0 + scratch->debug_address) != ERROR_OK) return ERROR_FAIL; *value = v; - if (dmi_read(target, &v, DMI_PROGBUF1 + scratch->debug_address) != ERROR_OK) + if (dmi_read(target, &v, DM_PROGBUF1 + scratch->debug_address) != ERROR_OK) return ERROR_FAIL; *value |= ((uint64_t) v) << 32; break; case SPACE_DMI_RAM: { - uint8_t buffer[8]; - if (read_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK) + uint8_t buffer[8] = {0}; + if (read_memory(target, scratch->debug_address, 4, 2, buffer, 4) != ERROR_OK) return ERROR_FAIL; *value = buffer[0] | (((uint64_t) buffer[1]) << 8) | @@ -1087,13 +1242,13 @@ static int scratch_write64(struct target *target, scratch_mem_t *scratch, uint64_t value) { switch (scratch->memory_space) { - case SPACE_DMI_DATA: - dmi_write(target, DMI_DATA0 + scratch->debug_address, value); - dmi_write(target, DMI_DATA1 + scratch->debug_address, value >> 32); + case SPACE_DM_DATA: + dmi_write(target, DM_DATA0 + scratch->debug_address, value); + dmi_write(target, DM_DATA1 + scratch->debug_address, value >> 32); break; case SPACE_DMI_PROGBUF: - dmi_write(target, DMI_PROGBUF0 + scratch->debug_address, value); - dmi_write(target, DMI_PROGBUF1 + scratch->debug_address, value >> 32); + dmi_write(target, DM_PROGBUF0 + scratch->debug_address, value); + dmi_write(target, DM_PROGBUF1 + scratch->debug_address, value >> 32); break; case SPACE_DMI_RAM: { @@ -1126,6 +1281,14 @@ static unsigned register_size(struct target *target, unsigned number) return riscv_xlen(target); } +static bool has_sufficient_progbuf(struct target *target, unsigned size) +{ + RISCV013_INFO(info); + RISCV_INFO(r); + + return info->progbufsize + r->impebreak >= size; +} + /** * Immediately write the new value to the requested register. This mechanism * bypasses any caches. @@ -1133,19 +1296,12 @@ static unsigned register_size(struct target *target, unsigned number) static int register_write_direct(struct target *target, unsigned number, uint64_t value) { - RISCV013_INFO(info); - RISCV_INFO(r); - - LOG_DEBUG("{%d} reg[0x%x] <- 0x%" PRIx64, riscv_current_hartid(target), - number, value); + LOG_DEBUG("{%d} %s <- 0x%" PRIx64, riscv_current_hartid(target), + gdb_regno_name(number), value); int result = register_write_abstract(target, number, value, register_size(target, number)); - if (result == ERROR_OK && target->reg_cache) { - struct reg *reg = &target->reg_cache->reg_list[number]; - buf_set_u64(reg->value, 0, reg->size, value); - } - if (result == ERROR_OK || info->progbufsize + r->impebreak < 2 || + if (result == ERROR_OK || !has_sufficient_progbuf(target, 2) || !riscv_is_halted(target)) return result; @@ -1156,10 +1312,14 @@ static int register_write_direct(struct target *target, unsigned number, if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; + uint64_t mstatus; + if (prep_for_register_access(target, &mstatus, number) != ERROR_OK) + return ERROR_FAIL; + scratch_mem_t scratch; bool use_scratch = false; if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && - riscv_supports_extension(target, riscv_current_hartid(target), 'D') && + 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. */ @@ -1180,15 +1340,28 @@ static int register_write_direct(struct target *target, unsigned number, return ERROR_FAIL; } + } else if (number == GDB_REGNO_VTYPE) { + riscv_program_insert(&program, csrr(S0, CSR_VL)); + riscv_program_insert(&program, vsetvli(ZERO, S0, value)); + } else { if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK) return ERROR_FAIL; if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (riscv_supports_extension(target, riscv_current_hartid(target), 'D')) + if (riscv_supports_extension(target, 'D')) riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); else riscv_program_insert(&program, fmv_w_x(number - GDB_REGNO_FPR0, S0)); + } 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." */ + riscv_reg_t vtype; + if (register_read(target, &vtype, GDB_REGNO_VTYPE) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_insert(&program, vsetvli(ZERO, S0, vtype)) != ERROR_OK) + return ERROR_FAIL; } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { riscv_program_csrw(&program, S0, number); } else { @@ -1207,6 +1380,9 @@ static int register_write_direct(struct target *target, unsigned number, if (use_scratch) scratch_release(target, &scratch); + if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) + return ERROR_FAIL; + /* Restore S0. */ if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; @@ -1214,7 +1390,7 @@ static int register_write_direct(struct target *target, unsigned number, return exec_out; } -/** Return the cached value, or read from the target if necessary. */ +/** Read register value from the target. Also update the cached value. */ static int register_read(struct target *target, uint64_t *value, uint32_t number) { if (number == GDB_REGNO_ZERO) { @@ -1234,14 +1410,11 @@ static int register_read(struct target *target, uint64_t *value, uint32_t number /** Actually read registers from the target right now. */ static int register_read_direct(struct target *target, uint64_t *value, uint32_t number) { - RISCV013_INFO(info); - RISCV_INFO(r); - int result = register_read_abstract(target, value, number, register_size(target, number)); if (result != ERROR_OK && - info->progbufsize + r->impebreak >= 2 && + has_sufficient_progbuf(target, 2) && number > GDB_REGNO_XPR31) { struct riscv_program program; riscv_program_init(&program, target); @@ -1249,22 +1422,18 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t scratch_mem_t scratch; bool use_scratch = false; - uint64_t s0; + riscv_reg_t s0; if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; /* Write program to move data into s0. */ uint64_t mstatus; - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (register_read(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) - return ERROR_FAIL; - if ((mstatus & MSTATUS_FS) == 0) - if (register_write_direct(target, GDB_REGNO_MSTATUS, - set_field(mstatus, MSTATUS_FS, 1)) != ERROR_OK) - return ERROR_FAIL; + if (prep_for_register_access(target, &mstatus, number) != ERROR_OK) + return ERROR_FAIL; - if (riscv_supports_extension(target, riscv_current_hartid(target), 'D') + 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. */ @@ -1280,8 +1449,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t scratch_release(target, &scratch); return ERROR_FAIL; } - } else if (riscv_supports_extension(target, - riscv_current_hartid(target), 'D')) { + } else if (riscv_supports_extension(target, 'D')) { riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); } else { riscv_program_insert(&program, fmv_x_w(S0, number - GDB_REGNO_FPR0)); @@ -1289,7 +1457,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { riscv_program_csrr(&program, S0, number); } else { - LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); + LOG_ERROR("Unsupported register: %s", gdb_regno_name(number)); return ERROR_FAIL; } @@ -1308,10 +1476,8 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t return ERROR_FAIL; } - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && - (mstatus & MSTATUS_FS) == 0) - if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus) != ERROR_OK) - return ERROR_FAIL; + if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) + return ERROR_FAIL; /* Restore S0. */ if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) @@ -1319,14 +1485,14 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t } if (result == ERROR_OK) { - LOG_DEBUG("{%d} reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target), - number, *value); + LOG_DEBUG("{%d} %s = 0x%" PRIx64, riscv_current_hartid(target), + gdb_regno_name(number), *value); } return result; } -int wait_for_authbusy(struct target *target, uint32_t *dmstatus) +static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) { time_t start = time(NULL); while (1) { @@ -1335,7 +1501,7 @@ int wait_for_authbusy(struct target *target, uint32_t *dmstatus) return ERROR_FAIL; if (dmstatus) *dmstatus = value; - if (!get_field(value, DMI_DMSTATUS_AUTHBUSY)) + 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). " @@ -1354,12 +1520,45 @@ int wait_for_authbusy(struct target *target, uint32_t *dmstatus) 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); /* TODO: free register arch_info */ info->version_specific = NULL; } +static int set_haltgroup(struct target *target, bool *supported) +{ + uint32_t write = set_field(DM_DMCS2_HGWRITE, DM_DMCS2_GROUP, target->smp); + if (dmi_write(target, DM_DMCS2, write) != ERROR_OK) + return ERROR_FAIL; + uint32_t read; + if (dmi_read(target, &read, DM_DMCS2) != ERROR_OK) + return ERROR_FAIL; + *supported = get_field(read, DM_DMCS2_GROUP) == (unsigned)target->smp; + return ERROR_OK; +} + +static int discover_vlenb(struct target *target) +{ + RISCV_INFO(r); + riscv_reg_t vlenb; + + if (register_read(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); + + return ERROR_OK; +} + static int examine(struct target *target) { /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ @@ -1382,43 +1581,50 @@ static int examine(struct target *target) } 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); /* Reset the Debug Module. */ dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; if (!dm->was_reset) { - dmi_write(target, DMI_DMCONTROL, 0); - dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); + dmi_write(target, DM_DMCONTROL, 0); + dmi_write(target, DM_DMCONTROL, DM_DMCONTROL_DMACTIVE); dm->was_reset = true; } - dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_HARTSELLO | - DMI_DMCONTROL_HARTSELHI | DMI_DMCONTROL_DMACTIVE); + dmi_write(target, DM_DMCONTROL, DM_DMCONTROL_HARTSELLO | + DM_DMCONTROL_HARTSELHI | DM_DMCONTROL_DMACTIVE | + DM_DMCONTROL_HASEL); uint32_t dmcontrol; - if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) return ERROR_FAIL; - if (!get_field(dmcontrol, DMI_DMCONTROL_DMACTIVE)) { + if (!get_field(dmcontrol, DM_DMCONTROL_DMACTIVE)) { LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", dmcontrol); return ERROR_FAIL; } + dm->hasel_supported = get_field(dmcontrol, DM_DMCONTROL_HASEL); + uint32_t dmstatus; if (dmstatus_read(target, &dmstatus, false) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("dmstatus: 0x%08x", dmstatus); - if (get_field(dmstatus, DMI_DMSTATUS_VERSION) != 2) { - LOG_ERROR("OpenOCD only supports Debug Module version 2, not %d " - "(dmstatus=0x%x)", get_field(dmstatus, DMI_DMSTATUS_VERSION), 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(). */ return ERROR_FAIL; } uint32_t hartsel = - (get_field(dmcontrol, DMI_DMCONTROL_HARTSELHI) << - DMI_DMCONTROL_HARTSELLO_LENGTH) | - get_field(dmcontrol, DMI_DMCONTROL_HARTSELLO); + (get_field(dmcontrol, DM_DMCONTROL_HARTSELHI) << + DM_DMCONTROL_HARTSELLO_LENGTH) | + get_field(dmcontrol, DM_DMCONTROL_HARTSELLO); info->hartsellen = 0; while (hartsel & 1) { info->hartsellen++; @@ -1427,14 +1633,14 @@ static int examine(struct target *target) LOG_DEBUG("hartsellen=%d", info->hartsellen); uint32_t hartinfo; - if (dmi_read(target, &hartinfo, DMI_HARTINFO) != ERROR_OK) + if (dmi_read(target, &hartinfo, DM_HARTINFO) != ERROR_OK) return ERROR_FAIL; - info->datasize = get_field(hartinfo, DMI_HARTINFO_DATASIZE); - info->dataaccess = get_field(hartinfo, DMI_HARTINFO_DATAACCESS); - info->dataaddr = get_field(hartinfo, DMI_HARTINFO_DATAADDR); + info->datasize = get_field(hartinfo, DM_HARTINFO_DATASIZE); + info->dataaccess = get_field(hartinfo, DM_HARTINFO_DATAACCESS); + info->dataaddr = get_field(hartinfo, DM_HARTINFO_DATAADDR); - if (!get_field(dmstatus, DMI_DMSTATUS_AUTHENTICATED)) { + if (!get_field(dmstatus, DM_DMSTATUS_AUTHENTICATED)) { LOG_ERROR("Debugger is not authenticated to target Debug Module. " "(dmstatus=0x%x). Use `riscv authdata_read` and " "`riscv authdata_write` commands to authenticate.", dmstatus); @@ -1445,136 +1651,170 @@ static int examine(struct target *target) return ERROR_OK; } - if (dmi_read(target, &info->sbcs, DMI_SBCS) != ERROR_OK) + if (dmi_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, DMI_ABSTRACTCS) != ERROR_OK) + if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) return ERROR_FAIL; - info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); - info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); + info->datacount = get_field(abstractcs, DM_ABSTRACTCS_DATACOUNT); + info->progbufsize = get_field(abstractcs, DM_ABSTRACTCS_PROGBUFSIZE); LOG_INFO("datacount=%d progbufsize=%d", info->datacount, info->progbufsize); RISCV_INFO(r); - r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); + r->impebreak = get_field(dmstatus, DM_DMSTATUS_IMPEBREAK); - if (info->progbufsize + r->impebreak < 2) { + if (!has_sufficient_progbuf(target, 2)) { LOG_WARNING("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 " + "requires a program buffer size of at least 4. (progbufsize=%d) " + "Use `riscv set_enable_virtual off` to continue." + , info->progbufsize); + } + /* Before doing anything else we must first enumerate the harts. */ + if (dm->hart_count < 0) { + for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) { + r->current_hartid = i; + if (riscv013_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; - /* Don't call any riscv_* functions until after we've counted the number of - * cores and initialized registers. */ - for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) { - if (!riscv_rtos_enabled(target) && i != target->coreid) - continue; + uint32_t s; + if (dmstatus_read(target, &s, true) != ERROR_OK) + return ERROR_FAIL; + if (get_field(s, DM_DMSTATUS_ANYNONEXISTENT)) + break; + dm->hart_count = i + 1; - r->current_hartid = i; - if (riscv013_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; + if (get_field(s, DM_DMSTATUS_ANYHAVERESET)) + dmi_write(target, DM_DMCONTROL, + set_hartsel(DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET, i)); + } - uint32_t s; - if (dmstatus_read(target, &s, true) != ERROR_OK) - return ERROR_FAIL; - if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) - break; - r->hart_count = i + 1; + LOG_DEBUG("Detected %d harts.", dm->hart_count); + } - if (get_field(s, DMI_DMSTATUS_ANYHAVERESET)) - dmi_write(target, DMI_DMCONTROL, - set_hartsel(DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_ACKHAVERESET, i)); + r->current_hartid = target->coreid; - bool halted = riscv_is_halted(target); - if (!halted) { - if (riscv013_halt_current_hart(target) != ERROR_OK) { - LOG_ERROR("Fatal: Hart %d failed to halt during examine()", i); - return ERROR_FAIL; - } - } + if (dm->hart_count == 0) { + LOG_ERROR("No harts found!"); + return ERROR_FAIL; + } - /* Without knowing anything else we can at least mess with the - * program buffer. */ - r->debug_buffer_size[i] = info->progbufsize; + /* Don't call any riscv_* functions until after we've counted the number of + * cores and initialized registers. */ - int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); - if (result == ERROR_OK) - r->xlen[i] = 64; - else - r->xlen[i] = 32; + if (riscv013_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; - if (register_read(target, &r->misa[i], GDB_REGNO_MISA)) { - LOG_ERROR("Fatal: Failed to read MISA from hart %d.", i); + bool halted = riscv_is_halted(target); + if (!halted) { + if (riscv013_halt_go(target) != ERROR_OK) { + LOG_ERROR("Fatal: Hart %d failed to halt during examine()", r->current_hartid); return ERROR_FAIL; } + } - /* Now init registers based on what we discovered. */ - if (riscv_init_registers(target) != ERROR_OK) - return ERROR_FAIL; + /* Without knowing anything else we can at least mess with the + * program buffer. */ + r->debug_buffer_size = info->progbufsize; - /* Display this as early as possible to help people who are using - * really slow simulators. */ - LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, i, r->xlen[i], - r->misa[i]); + int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); + if (result == ERROR_OK) + r->xlen = 64; + else + r->xlen = 32; - if (!halted) - riscv013_resume_current_hart(target); + if (register_read(target, &r->misa, GDB_REGNO_MISA)) { + LOG_ERROR("Fatal: Failed to read MISA from hart %d.", r->current_hartid); + return ERROR_FAIL; } - LOG_DEBUG("Enumerated %d harts", r->hart_count); + if (riscv_supports_extension(target, 'V')) { + if (discover_vlenb(target) != ERROR_OK) + return ERROR_FAIL; + } - if (r->hart_count == 0) { - LOG_ERROR("No harts found!"); + /* Now init registers based on what we discovered. */ + if (riscv_init_registers(target) != ERROR_OK) return ERROR_FAIL; - } + + /* Display this as early as possible to help people who are using + * really slow simulators. */ + LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, r->current_hartid, r->xlen, + r->misa); + + if (!halted) + riscv013_step_or_resume_current_hart(target, false, false); target_set_examined(target); + if (target->smp) { + bool haltgroup_supported; + if (set_haltgroup(target, &haltgroup_supported) != ERROR_OK) + return ERROR_FAIL; + if (haltgroup_supported) + LOG_INFO("Core %d made part of halt group %d.", target->coreid, + target->smp); + else + LOG_INFO("Core %d could not be made part of halt group %d.", + target->coreid, 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_INFO("Examined RISC-V core; found %d harts", riscv_count_harts(target)); - for (int i = 0; i < riscv_count_harts(target); ++i) { - if (riscv_hart_enabled(target, i)) { - LOG_INFO(" hart %d: XLEN=%d, misa=0x%" PRIx64, i, r->xlen[i], - r->misa[i]); - } else { - LOG_INFO(" hart %d: currently disabled", i); - } - } + LOG_INFO(" hart %d: XLEN=%d, misa=0x%" PRIx64, r->current_hartid, r->xlen, + r->misa); return ERROR_OK; } -int riscv013_authdata_read(struct target *target, uint32_t *value) +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."); + return ERROR_FAIL; + } + if (wait_for_authbusy(target, NULL) != ERROR_OK) return ERROR_FAIL; - return dmi_read(target, value, DMI_AUTHDATA); + return dmi_read(target, value, DM_AUTHDATA); } -int riscv013_authdata_write(struct target *target, uint32_t value) +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."); + return ERROR_FAIL; + } + uint32_t before, after; if (wait_for_authbusy(target, &before) != ERROR_OK) return ERROR_FAIL; - dmi_write(target, DMI_AUTHDATA, value); + dmi_write(target, DM_AUTHDATA, value); if (wait_for_authbusy(target, &after) != ERROR_OK) return ERROR_FAIL; - if (!get_field(before, DMI_DMSTATUS_AUTHENTICATED) && - get_field(after, DMI_DMSTATUS_AUTHENTICATED)) { + if (!get_field(before, DM_DMSTATUS_AUTHENTICATED) && + get_field(after, DM_DMSTATUS_AUTHENTICATED)) { LOG_INFO("authdata_write resulted in successful authentication"); int result = ERROR_OK; dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; target_list_t *entry; list_for_each_entry(entry, &dm->target_list, list) { if (examine(entry->target) != ERROR_OK) @@ -1586,101 +1826,563 @@ int riscv013_authdata_write(struct target *target, uint32_t value) return ERROR_OK; } -static int init_target(struct command_context *cmd_ctx, - struct target *target) +static int riscv013_hart_count(struct target *target) { - LOG_DEBUG("init"); - riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; + dm013_info_t *dm = get_dm(target); + assert(dm); + return dm->hart_count; +} - generic_info->get_register = &riscv013_get_register; - generic_info->set_register = &riscv013_set_register; - generic_info->select_current_hart = &riscv013_select_current_hart; - generic_info->is_halted = &riscv013_is_halted; - generic_info->halt_current_hart = &riscv013_halt_current_hart; - generic_info->resume_current_hart = &riscv013_resume_current_hart; - generic_info->step_current_hart = &riscv013_step_current_hart; - generic_info->on_halt = &riscv013_on_halt; - generic_info->on_resume = &riscv013_on_resume; - 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->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; - 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->test_sba_config_reg = &riscv013_test_sba_config_reg; - generic_info->test_compliance = &riscv013_test_compliance; - generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); - if (!generic_info->version_specific) - return ERROR_FAIL; - riscv013_info_t *info = get_info(target); +/* Try to find out the widest memory access size depending on the selected memory access methods. */ +static unsigned riscv013_data_bits(struct target *target) +{ + RISCV013_INFO(info); + RISCV_INFO(r); - info->progbufsize = -1; + for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { + int method = r->mem_access_methods[i]; + + if (method == RISCV_MEM_ACCESS_PROGBUF) { + if (has_sufficient_progbuf(target, 3)) + return riscv_xlen(target); + } else if (method == RISCV_MEM_ACCESS_SYSBUS) { + if (get_field(info->sbcs, DM_SBCS_SBACCESS128)) + return 128; + if (get_field(info->sbcs, DM_SBCS_SBACCESS64)) + return 64; + if (get_field(info->sbcs, DM_SBCS_SBACCESS32)) + return 32; + if (get_field(info->sbcs, DM_SBCS_SBACCESS16)) + return 16; + if (get_field(info->sbcs, DM_SBCS_SBACCESS8)) + return 8; + } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { + /* TODO: Once there is a spec for discovering abstract commands, we can + * take those into account as well. For now we assume abstract commands + * support XLEN-wide accesses. */ + return riscv_xlen(target); + } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) + /* No further mem access method to try. */ + break; + } + LOG_ERROR("Unable to determine supported data bits on this target. Assuming 32 bits."); + return 32; +} - info->dmi_busy_delay = 0; - info->bus_master_read_delay = 0; - info->bus_master_write_delay = 0; - info->ac_busy_delay = 0; +static COMMAND_HELPER(riscv013_print_info, struct target *target) +{ + RISCV013_INFO(info); - /* Assume all these abstract commands are supported until we learn - * otherwise. - * TODO: The spec allows eg. one CSR to be able to be accessed abstractly - * while another one isn't. We don't track that this closely here, but in - * the future we probably should. */ - info->abstract_read_csr_supported = true; - info->abstract_write_csr_supported = true; - info->abstract_read_fpr_supported = true; - info->abstract_write_fpr_supported = true; + /* Abstract description. */ + riscv_print_info_line(CMD, "target", "memory.read_while_running8", get_field(info->sbcs, DM_SBCS_SBACCESS8)); + riscv_print_info_line(CMD, "target", "memory.write_while_running8", get_field(info->sbcs, DM_SBCS_SBACCESS8)); + riscv_print_info_line(CMD, "target", "memory.read_while_running16", get_field(info->sbcs, DM_SBCS_SBACCESS16)); + riscv_print_info_line(CMD, "target", "memory.write_while_running16", get_field(info->sbcs, DM_SBCS_SBACCESS16)); + riscv_print_info_line(CMD, "target", "memory.read_while_running32", get_field(info->sbcs, DM_SBCS_SBACCESS32)); + riscv_print_info_line(CMD, "target", "memory.write_while_running32", get_field(info->sbcs, DM_SBCS_SBACCESS32)); + riscv_print_info_line(CMD, "target", "memory.read_while_running64", get_field(info->sbcs, DM_SBCS_SBACCESS64)); + riscv_print_info_line(CMD, "target", "memory.write_while_running64", get_field(info->sbcs, DM_SBCS_SBACCESS64)); + riscv_print_info_line(CMD, "target", "memory.read_while_running128", get_field(info->sbcs, DM_SBCS_SBACCESS128)); + riscv_print_info_line(CMD, "target", "memory.write_while_running128", get_field(info->sbcs, DM_SBCS_SBACCESS128)); + + /* Lower level description. */ + riscv_print_info_line(CMD, "dm", "abits", info->abits); + riscv_print_info_line(CMD, "dm", "progbufsize", info->progbufsize); + riscv_print_info_line(CMD, "dm", "sbversion", get_field(info->sbcs, DM_SBCS_SBVERSION)); + riscv_print_info_line(CMD, "dm", "sbasize", get_field(info->sbcs, DM_SBCS_SBASIZE)); + riscv_print_info_line(CMD, "dm", "sbaccess128", get_field(info->sbcs, DM_SBCS_SBACCESS128)); + riscv_print_info_line(CMD, "dm", "sbaccess64", get_field(info->sbcs, DM_SBCS_SBACCESS64)); + riscv_print_info_line(CMD, "dm", "sbaccess32", get_field(info->sbcs, DM_SBCS_SBACCESS32)); + riscv_print_info_line(CMD, "dm", "sbaccess16", get_field(info->sbcs, DM_SBCS_SBACCESS16)); + riscv_print_info_line(CMD, "dm", "sbaccess8", get_field(info->sbcs, DM_SBCS_SBACCESS8)); - return ERROR_OK; + uint32_t dmstatus; + if (dmstatus_read(target, &dmstatus, false) == ERROR_OK) + riscv_print_info_line(CMD, "dm", "authenticated", get_field(dmstatus, DM_DMSTATUS_AUTHENTICATED)); + + return 0; } -static int assert_reset(struct target *target) +static int prep_for_vector_access(struct target *target, uint64_t *vtype, + uint64_t *vl, unsigned *debug_vl) { 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)); + return ERROR_FAIL; + } - select_dmi(target); - - uint32_t control_base = set_field(0, DMI_DMCONTROL_DMACTIVE, 1); + /* Save vtype and vl. */ + if (register_read(target, vtype, GDB_REGNO_VTYPE) != ERROR_OK) + return ERROR_FAIL; + if (register_read(target, vl, GDB_REGNO_VL) != ERROR_OK) + return ERROR_FAIL; - if (target->rtos) { - /* There's only one target, and OpenOCD thinks each hart is a thread. - * We must reset them all. */ + if (register_write_direct(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != 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) + return ERROR_FAIL; + + return ERROR_OK; +} + +static int cleanup_after_vector_access(struct target *target, uint64_t vtype, + uint64_t vl) +{ + /* Restore vtype and vl. */ + if (register_write_direct(target, GDB_REGNO_VTYPE, vtype) != ERROR_OK) + return ERROR_FAIL; + if (register_write_direct(target, GDB_REGNO_VL, vl) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; +} + +static int riscv013_get_register_buf(struct target *target, + uint8_t *value, int regno) +{ + assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); + + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + + riscv_reg_t s0; + if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + uint64_t mstatus; + if (prep_for_register_access(target, &mstatus, regno) != ERROR_OK) + return ERROR_FAIL; + + uint64_t vtype, vl; + unsigned debug_vl; + if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != 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)); + + int result = ERROR_OK; + for (unsigned i = 0; i < debug_vl; i++) { + /* 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 + * vector register we tried to read already. + * For other failures, we just return error because things are probably + * 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; + if (register_read_direct(target, &v, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + buf_set_u64(value, xlen * i, xlen, v); + } else { + break; + } + } + + if (cleanup_after_vector_access(target, vtype, vl) != ERROR_OK) + return ERROR_FAIL; + + if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK) + return ERROR_FAIL; + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + + return result; +} + +static int riscv013_set_register_buf(struct target *target, + int regno, const uint8_t *value) +{ + assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); + + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + + riscv_reg_t s0; + if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + uint64_t mstatus; + if (prep_for_register_access(target, &mstatus, regno) != ERROR_OK) + return ERROR_FAIL; + + uint64_t vtype, vl; + unsigned debug_vl; + if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != 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, vslide1down_vx(vnum, vnum, S0, true)); + int result = ERROR_OK; + for (unsigned i = 0; i < debug_vl; i++) { + if (register_write_direct(target, GDB_REGNO_S0, + buf_get_u64(value, xlen * i, xlen)) != 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) + return ERROR_FAIL; + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + + return result; +} + +static uint32_t sb_sbaccess(unsigned int size_bytes) +{ + switch (size_bytes) { + case 1: + return set_field(0, DM_SBCS_SBACCESS, 0); + case 2: + return set_field(0, DM_SBCS_SBACCESS, 1); + case 4: + return set_field(0, DM_SBCS_SBACCESS, 2); + case 8: + return set_field(0, DM_SBCS_SBACCESS, 3); + case 16: + return set_field(0, DM_SBCS_SBACCESS, 4); + } + assert(0); + return 0; +} + +static int sb_write_address(struct target *target, target_addr_t address, + bool ensure_success) +{ + RISCV013_INFO(info); + 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); + if (sbasize > 64) + dmi_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); +} + +static int batch_run(const struct target *target, struct riscv_batch *batch) +{ + RISCV013_INFO(info); + RISCV_INFO(r); + if (r->reset_delays_wait >= 0) { + r->reset_delays_wait -= batch->used_scans; + if (r->reset_delays_wait <= 0) { + batch->idle_count = 0; + info->dmi_busy_delay = 0; + info->ac_busy_delay = 0; + } + } + return riscv_batch_run(batch); +} + +static int sba_supports_access(struct target *target, unsigned int size_bytes) +{ + RISCV013_INFO(info); + switch (size_bytes) { + case 1: + return get_field(info->sbcs, DM_SBCS_SBACCESS8); + case 2: + return get_field(info->sbcs, DM_SBCS_SBACCESS16); + case 4: + return get_field(info->sbcs, DM_SBCS_SBACCESS32); + case 8: + return get_field(info->sbcs, DM_SBCS_SBACCESS64); + case 16: + return get_field(info->sbcs, DM_SBCS_SBACCESS128); + default: + return 0; + } +} + +static int sample_memory_bus_v1(struct target *target, + struct riscv_sample_buf *buf, + const riscv_sample_config_t *config, + int64_t until_ms) +{ + 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."); + return ERROR_NOT_IMPLEMENTED; + } + + if (get_field(info->sbcs, DM_SBCS_SBVERSION) != 1) { + LOG_ERROR("Memory sampling is only implemented for SBA version 1."); + return ERROR_NOT_IMPLEMENTED; + } + + uint32_t sbcs = 0; + uint32_t sbcs_valid = false; + + uint32_t sbaddress0 = 0; + bool sbaddress0_valid = false; + uint32_t sbaddress1 = 0; + bool sbaddress1_valid = false; + + /* How often to read each value in a batch. */ + const unsigned int repeat = 5; + + unsigned int enabled_count = 0; + for (unsigned int i = 0; i < ARRAY_SIZE(config->bucket); i++) { + if (config->bucket[i].enabled) + enabled_count++; + } + + while (timeval_ms() < until_ms) { + /* + * batch_run() adds to the batch, so we can't simply reuse the same + * batch over and over. So we create a new one every time through the + * loop. + */ + struct riscv_batch *batch = riscv_batch_alloc( + target, 1 + enabled_count * 5 * repeat, + info->dmi_busy_delay + info->bus_master_read_delay); + if (!batch) + return ERROR_FAIL; + + unsigned int result_bytes = 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) { + if (!sba_supports_access(target, config->bucket[i].size_bytes)) { + LOG_ERROR("Hardware does not support SBA access for %d-byte memory sampling.", + config->bucket[i].size_bytes); + return ERROR_NOT_IMPLEMENTED; + } + + uint32_t sbcs_write = DM_SBCS_SBREADONADDR; + if (enabled_count == 1) + 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); + sbcs = sbcs_write; + sbcs_valid = true; + } + + if (sbasize > 32 && + (!sbaddress1_valid || + sbaddress1 != config->bucket[i].address >> 32)) { + sbaddress1 = config->bucket[i].address >> 32; + riscv_batch_add_dmi_write(batch, DM_SBADDRESS1, sbaddress1); + 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); + 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); + result_bytes += 1 + config->bucket[i].size_bytes; + } + } + } + + if (buf->used + result_bytes >= buf->size) { + riscv_batch_free(batch); + break; + } + + size_t sbcs_key = riscv_batch_add_dmi_read(batch, DM_SBCS); + + int result = batch_run(target, batch); + if (result != ERROR_OK) + return result; + + uint32_t sbcs_read = riscv_batch_get_dmi_read_data(batch, sbcs_key); + 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. */ + 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); + 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); + riscv_batch_free(batch); + return ERROR_FAIL; + } + + unsigned int read = 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++); + + buf->buf[buf->used] = i; + buf_set_u64(buf->buf + buf->used + 1, 0, config->bucket[i].size_bytes * 8, value); + buf->used += 1 + config->bucket[i].size_bytes; + } + } + } + + riscv_batch_free(batch); + } + + return ERROR_OK; +} + +static int sample_memory(struct target *target, + struct riscv_sample_buf *buf, + riscv_sample_config_t *config, + int64_t until_ms) +{ + if (!config->enabled) + return ERROR_OK; + + return sample_memory_bus_v1(target, buf, config, until_ms); +} + +static int init_target(struct command_context *cmd_ctx, + struct target *target) +{ + LOG_DEBUG("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_current_hart = &riscv013_select_current_hart; + 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->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; + 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->read_memory = read_memory; + generic_info->hart_count = &riscv013_hart_count; + generic_info->data_bits = &riscv013_data_bits; + generic_info->print_info = &riscv013_print_info; + if (!generic_info->version_specific) { + generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); + if (!generic_info->version_specific) + return ERROR_FAIL; + } + generic_info->sample_memory = sample_memory; + riscv013_info_t *info = get_info(target); + + info->progbufsize = -1; + + info->dmi_busy_delay = 0; + info->bus_master_read_delay = 0; + info->bus_master_write_delay = 0; + info->ac_busy_delay = 0; + + /* Assume all these abstract commands are supported until we learn + * otherwise. + * TODO: The spec allows eg. one CSR to be able to be accessed abstractly + * while another one isn't. We don't track that this closely here, but in + * the future we probably should. */ + info->abstract_read_csr_supported = true; + info->abstract_write_csr_supported = true; + info->abstract_read_fpr_supported = true; + info->abstract_write_fpr_supported = true; + + info->has_aampostincrement = YNM_MAYBE; + + return ERROR_OK; +} + +static int assert_reset(struct target *target) +{ + RISCV_INFO(r); + + 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; - for (int i = 0; i < riscv_count_harts(target); ++i) { - if (!riscv_hart_enabled(target, i)) - continue; + uint32_t control = set_hartsel(control_base, target->coreid); + control = set_field(control, DM_DMCONTROL_HALTREQ, + target->reset_halt ? 1 : 0); + dmi_write(target, DM_DMCONTROL, control); - control = set_hartsel(control_base, i); - control = set_field(control, DMI_DMCONTROL_HALTREQ, - target->reset_halt ? 1 : 0); - dmi_write(target, DMI_DMCONTROL, control); - } /* Assert ndmreset */ - control = set_field(control, DMI_DMCONTROL_NDMRESET, 1); - dmi_write(target, DMI_DMCONTROL, control); + control = set_field(control, DM_DMCONTROL_NDMRESET, 1); + dmi_write(target, DM_DMCONTROL, control); } else { /* Reset just this hart. */ uint32_t control = set_hartsel(control_base, r->current_hartid); - control = set_field(control, DMI_DMCONTROL_HALTREQ, + control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); - control = set_field(control, DMI_DMCONTROL_NDMRESET, 1); - dmi_write(target, DMI_DMCONTROL, control); + control = set_field(control, DM_DMCONTROL_NDMRESET, 1); + dmi_write(target, DM_DMCONTROL, control); } 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. */ + memset(dm->progbuf_cache, 0, sizeof(dm->progbuf_cache)); + return ERROR_OK; } @@ -1691,11 +2393,11 @@ static int deassert_reset(struct target *target) select_dmi(target); /* Clear the reset, but make sure haltreq is still set */ - uint32_t control = 0; - control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); - control = set_field(control, DMI_DMCONTROL_DMACTIVE, 1); - dmi_write(target, DMI_DMCONTROL, - set_hartsel(control, r->current_hartid)); + uint32_t control = 0, control_haltreq; + control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); + control_haltreq = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); + dmi_write(target, DM_DMCONTROL, + set_hartsel(control_haltreq, r->current_hartid)); uint32_t dmstatus; int dmi_busy_delay = info->dmi_busy_delay; @@ -1704,24 +2406,15 @@ static int deassert_reset(struct target *target) for (int i = 0; i < riscv_count_harts(target); ++i) { int index = i; if (target->rtos) { - if (!riscv_hart_enabled(target, index)) + if (index != target->coreid) continue; - dmi_write(target, DMI_DMCONTROL, - set_hartsel(control, index)); + dmi_write(target, DM_DMCONTROL, + set_hartsel(control_haltreq, index)); } else { index = r->current_hartid; } - char *operation; - uint32_t expected_field; - if (target->reset_halt) { - operation = "halt"; - expected_field = DMI_DMSTATUS_ALLHALTED; - } else { - operation = "run"; - expected_field = DMI_DMSTATUS_ALLRUNNING; - } - LOG_DEBUG("Waiting for hart %d to %s out of reset.", index, operation); + LOG_DEBUG("Waiting for hart %d to come out of reset.", index); while (1) { int result = dmstatus_read_timeout(target, &dmstatus, true, riscv_reset_timeout_sec); @@ -1732,23 +2425,30 @@ static int deassert_reset(struct target *target) index, riscv_reset_timeout_sec); if (result != ERROR_OK) return result; - if (get_field(dmstatus, expected_field)) + /* 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 %s coming out of reset in %ds; " + LOG_ERROR("Hart %d didn't leave reset in %ds; " "dmstatus=0x%x; " "Increase the timeout with riscv set_reset_timeout_sec.", - index, operation, riscv_reset_timeout_sec, dmstatus); + index, riscv_reset_timeout_sec, dmstatus); return ERROR_FAIL; } } target->state = TARGET_HALTED; - if (get_field(dmstatus, DMI_DMSTATUS_ALLHAVERESET)) { - /* Ack reset. */ - dmi_write(target, DMI_DMCONTROL, + if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) { + /* Ack reset and clear DM_DMCONTROL_HALTREQ if previously set */ + dmi_write(target, DM_DMCONTROL, set_hartsel(control, index) | - DMI_DMCONTROL_ACKHAVERESET); + DM_DMCONTROL_ACKHAVERESET); } if (!target->rtos) @@ -1758,37 +2458,8 @@ static int deassert_reset(struct target *target) return ERROR_OK; } -/** - * @par size in bytes - */ -static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) -{ - switch (size) { - case 8: - buffer[7] = value >> 56; - buffer[6] = value >> 48; - buffer[5] = value >> 40; - buffer[4] = value >> 32; - /* falls through */ - case 4: - buffer[3] = value >> 24; - buffer[2] = value >> 16; - /* falls through */ - case 2: - buffer[1] = value >> 8; - /* falls through */ - case 1: - buffer[0] = value; - break; - default: - assert(false); - } -} - static int execute_fence(struct target *target) { - int old_hartid = riscv_current_hartid(target); - /* FIXME: For non-coherent systems we need to flush the caches right * here, but there's no ISA-defined way of doing that. */ { @@ -1801,23 +2472,6 @@ static int execute_fence(struct target *target) LOG_DEBUG("Unable to execute pre-fence"); } - for (int i = 0; i < riscv_count_harts(target); ++i) { - if (!riscv_hart_enabled(target, i)) - continue; - - riscv_set_current_hartid(target, i); - - 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_DEBUG("Unable to execute fence on hart %d", i); - } - - riscv_set_current_hartid(target, old_hartid); - return ERROR_OK; } @@ -1830,7 +2484,21 @@ static void log_memory_access(target_addr_t address, uint64_t value, char fmt[80]; sprintf(fmt, "M[0x%" TARGET_PRIxADDR "] %ss 0x%%0%d" PRIx64, address, read ? "read" : "write", size_bytes * 2); - value &= (((uint64_t) 0x1) << (size_bytes * 8)) - 1; + switch (size_bytes) { + case 1: + value &= 0xff; + break; + case 2: + value &= 0xffff; + break; + case 4: + value &= 0xffffffffUL; + break; + case 8: + break; + default: + assert(false); + } LOG_DEBUG(fmt, value); } @@ -1840,86 +2508,42 @@ static int read_memory_bus_word(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { uint32_t value; - if (size > 12) { - if (dmi_read(target, &value, DMI_SBDATA3) != ERROR_OK) - return ERROR_FAIL; - write_to_buf(buffer + 12, value, 4); - log_memory_access(address + 12, value, 4, true); - } - if (size > 8) { - if (dmi_read(target, &value, DMI_SBDATA2) != ERROR_OK) - return ERROR_FAIL; - write_to_buf(buffer + 8, value, 4); - log_memory_access(address + 8, value, 4, true); - } - if (size > 4) { - if (dmi_read(target, &value, DMI_SBDATA1) != ERROR_OK) - return ERROR_FAIL; - write_to_buf(buffer + 4, value, 4); - log_memory_access(address + 4, value, 4, true); + int result; + 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); + 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); } - if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) - return ERROR_FAIL; - write_to_buf(buffer, value, MIN(size, 4)); - log_memory_access(address, value, MIN(size, 4), true); return ERROR_OK; } -static uint32_t sb_sbaccess(unsigned size_bytes) -{ - switch (size_bytes) { - case 1: - return set_field(0, DMI_SBCS_SBACCESS, 0); - case 2: - return set_field(0, DMI_SBCS_SBACCESS, 1); - case 4: - return set_field(0, DMI_SBCS_SBACCESS, 2); - case 8: - return set_field(0, DMI_SBCS_SBACCESS, 3); - case 16: - return set_field(0, DMI_SBCS_SBACCESS, 4); - } - assert(0); - return 0; /* Make mingw happy. */ -} - static target_addr_t sb_read_address(struct target *target) { RISCV013_INFO(info); - unsigned sbasize = get_field(info->sbcs, DMI_SBCS_SBASIZE); + unsigned sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); target_addr_t address = 0; uint32_t v; if (sbasize > 32) { - dmi_read(target, &v, DMI_SBADDRESS1); + dmi_read(target, &v, DM_SBADDRESS1); address |= v; address <<= 32; } - dmi_read(target, &v, DMI_SBADDRESS0); + dmi_read(target, &v, DM_SBADDRESS0); address |= v; return address; } -static int sb_write_address(struct target *target, target_addr_t address) -{ - RISCV013_INFO(info); - unsigned sbasize = get_field(info->sbcs, DMI_SBCS_SBASIZE); - /* There currently is no support for >64-bit addresses in OpenOCD. */ - if (sbasize > 96) - dmi_write(target, DMI_SBADDRESS3, 0); - if (sbasize > 64) - dmi_write(target, DMI_SBADDRESS2, 0); - if (sbasize > 32) - dmi_write(target, DMI_SBADDRESS1, address >> 32); - return dmi_write(target, DMI_SBADDRESS0, address); -} - static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) { time_t start = time(NULL); while (1) { - if (dmi_read(target, sbcs, DMI_SBCS) != ERROR_OK) + if (dmi_read(target, sbcs, DM_SBCS) != ERROR_OK) return ERROR_FAIL; - if (!get_field(*sbcs, DMI_SBCS_SBBUSY)) + 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). " @@ -1930,9 +2554,45 @@ static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) } } +static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t *mstatus_old) +{ + if (riscv_enable_virtual && has_sufficient_progbuf(target, 5)) { + /* Read DCSR */ + uint64_t dcsr; + if (register_read(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; + + /* Read and save MSTATUS */ + if (register_read(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) + return ERROR_FAIL; + *mstatus_old = *mstatus; + + /* If we come from m-mode with mprv set, we want to keep mpp */ + if (get_field(dcsr, DCSR_PRV) < 3) { + /* MPP = PRIV */ + *mstatus = set_field(*mstatus, MSTATUS_MPP, get_field(dcsr, DCSR_PRV)); + + /* MPRV = 1 */ + *mstatus = set_field(*mstatus, MSTATUS_MPRV, 1); + + /* Write MSTATUS */ + if (*mstatus != *mstatus_old) + if (register_write_direct(target, GDB_REGNO_MSTATUS, *mstatus) != ERROR_OK) + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + static int read_memory_bus_v0(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { + if (size != increment) { + LOG_ERROR("sba v0 reads only support size==increment"); + return ERROR_NOT_IMPLEMENTED; + } + LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" TARGET_PRIxADDR, size, count, address); uint8_t *t_buffer = buffer; @@ -1940,29 +2600,29 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, riscv_addr_t fin_addr = address + (count * size); uint32_t access = 0; - const int DMI_SBCS_SBSINGLEREAD_OFFSET = 20; - const uint32_t DMI_SBCS_SBSINGLEREAD = (0x1U << DMI_SBCS_SBSINGLEREAD_OFFSET); + const int DM_SBCS_SBSINGLEREAD_OFFSET = 20; + const uint32_t DM_SBCS_SBSINGLEREAD = (0x1U << DM_SBCS_SBSINGLEREAD_OFFSET); - const int DMI_SBCS_SBAUTOREAD_OFFSET = 15; - const uint32_t DMI_SBCS_SBAUTOREAD = (0x1U << DMI_SBCS_SBAUTOREAD_OFFSET); + const int DM_SBCS_SBAUTOREAD_OFFSET = 15; + const uint32_t DM_SBCS_SBAUTOREAD = (0x1U << DM_SBCS_SBAUTOREAD_OFFSET); /* 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, DMI_SBCS) != ERROR_OK) + if (dmi_read(target, &access, DM_SBCS) != ERROR_OK) return ERROR_FAIL; - dmi_write(target, DMI_SBADDRESS0, cur_addr); + dmi_write(target, DM_SBADDRESS0, cur_addr); /* size/2 matching the bit access of the spec 0.13 */ - access = set_field(access, DMI_SBCS_SBACCESS, size/2); - access = set_field(access, DMI_SBCS_SBSINGLEREAD, 1); + 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, DMI_SBCS, access); + dmi_write(target, DM_SBCS, access); /* 3) read */ uint32_t value; - if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("\r\nread_memory: sab: value: 0x%08x", value); - write_to_buf(t_buffer, value, size); + buf_set_u32(t_buffer, 0, 8 * size, value); t_buffer += size; cur_addr += size; } @@ -1971,39 +2631,43 @@ 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, DMI_SBCS) != ERROR_OK) + if (dmi_read(target, &access, DM_SBCS) != ERROR_OK) return ERROR_FAIL; /* set current address */ - dmi_write(target, DMI_SBADDRESS0, cur_addr); + dmi_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, DMI_SBCS_SBACCESS, size/2); - access = set_field(access, DMI_SBCS_SBAUTOREAD, 1); - access = set_field(access, DMI_SBCS_SBSINGLEREAD, 1); - access = set_field(access, DMI_SBCS_SBAUTOINCREMENT, 1); + 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, DMI_SBCS, access); + dmi_write(target, DM_SBCS, access); while (cur_addr < fin_addr) { LOG_DEBUG("\r\nsab:autoincrement: \r\n size: %d\tcount:%d\taddress: 0x%08" PRIx64, size, count, cur_addr); /* read */ uint32_t value; - if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; - write_to_buf(t_buffer, value, size); + buf_set_u32(t_buffer, 0, 8 * size, value); cur_addr += size; t_buffer += size; /* if we are reaching last address, we must clear autoread */ if (cur_addr == fin_addr && count != 1) { - dmi_write(target, DMI_SBCS, 0); - if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + dmi_write(target, DM_SBCS, 0); + if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; - write_to_buf(t_buffer, value, size); + buf_set_u32(t_buffer, 0, 8 * size, value); } } + uint32_t sbcs; + if (dmi_read(target, &sbcs, DM_SBCS) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; } @@ -2011,21 +2675,30 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, * Read the requested memory using the system bus interface. */ static int read_memory_bus_v1(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + 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"); + return ERROR_NOT_IMPLEMENTED; + } + RISCV013_INFO(info); target_addr_t next_address = address; target_addr_t end_address = address + count * size; while (next_address < end_address) { - uint32_t sbcs = set_field(0, DMI_SBCS_SBREADONADDR, 1); - sbcs |= sb_sbaccess(size); - sbcs = set_field(sbcs, DMI_SBCS_SBAUTOINCREMENT, 1); - sbcs = set_field(sbcs, DMI_SBCS_SBREADONDATA, count > 1); - dmi_write(target, DMI_SBCS, sbcs); + uint32_t sbcs_write = set_field(0, DM_SBCS_SBREADONADDR, 1); + sbcs_write |= sb_sbaccess(size); + if (increment == size) + 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) + return ERROR_FAIL; /* This address write will trigger the first read. */ - sb_write_address(target, next_address); + if (sb_write_address(target, next_address, true) != ERROR_OK) + return ERROR_FAIL; if (info->bus_master_read_delay) { jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE); @@ -2035,55 +2708,394 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, } } - for (uint32_t i = (next_address - address) / size; i < count - 1; i++) { - read_memory_bus_word(target, address + i * size, size, - buffer + i * size); - } + /* First value has been read, and is waiting for us to issue a DMI read + * to get it. */ + + static int sbdata[4] = {DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3}; + assert(size <= 16); + target_addr_t next_read = address - 1; + 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); + return ERROR_FAIL; + } + keep_alive(); + dmi_status_t status = dmi_scan(target, NULL, &value, + DMI_OP_READ, sbdata[j], 0, false); + if (status == DMI_STATUS_BUSY) + increase_dmi_busy_delay(target); + else if (status == DMI_STATUS_SUCCESS) + break; + else + 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); + } + next_read = address + i * size + 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); + return ERROR_FAIL; + } + dmi_status_t status = dmi_scan(target, NULL, &value, DMI_OP_NOP, 0, 0, false); + if (status == DMI_STATUS_BUSY) + increase_dmi_busy_delay(target); + else if (status == DMI_STATUS_SUCCESS) + break; + 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); + + /* "Writes to sbcs while sbbusy is high result in undefined behavior. + * A debugger must not write to sbcs until it reads sbbusy as 0." */ + if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK) + return ERROR_FAIL; + + sbcs_write = set_field(sbcs_write, DM_SBCS_SBREADONDATA, 0); + if (dmi_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, + buffer + (count - 1) * size) != ERROR_OK) + return ERROR_FAIL; + + if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK) + return ERROR_FAIL; + } + + 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) + return ERROR_FAIL; + next_address = sb_read_address(target); + info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1; + continue; + } + + unsigned error = get_field(sbcs_read, DM_SBCS_SBERROR); + if (error == 0) { + 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) + return ERROR_FAIL; + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static void log_mem_access_result(struct target *target, bool success, int method, bool read) +{ + RISCV_INFO(r); + bool warn = false; + char msg[60]; + + /* Compose the message */ + snprintf(msg, 60, "%s to %s memory via %s.", + success ? "Succeeded" : "Failed", + read ? "read" : "write", + (method == RISCV_MEM_ACCESS_PROGBUF) ? "program buffer" : + (method == RISCV_MEM_ACCESS_SYSBUS) ? "system bus" : "abstract access"); + + /* Determine the log message severity. Show warnings only once. */ + if (!success) { + if (method == RISCV_MEM_ACCESS_PROGBUF) { + warn = r->mem_access_progbuf_warn; + r->mem_access_progbuf_warn = false; + } + if (method == RISCV_MEM_ACCESS_SYSBUS) { + warn = r->mem_access_sysbus_warn; + r->mem_access_sysbus_warn = false; + } + if (method == RISCV_MEM_ACCESS_ABSTRACT) { + warn = r->mem_access_abstract_warn; + r->mem_access_abstract_warn = false; + } + } + + if (warn) + LOG_WARNING("%s", msg); + else + LOG_DEBUG("%s", msg); +} + +static bool mem_should_skip_progbuf(struct target *target, target_addr_t address, + uint32_t size, bool 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"); + *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"); + *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); + *skip_reason = "skipped (XLEN too short)"; + return true; + } + if (size > 8) { + LOG_DEBUG("Skipping mem %s via progbuf - unsupported size.", + 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)); + *skip_reason = "skipped (too large address)"; + return true; + } + + return false; +} + +static bool mem_should_skip_sysbus(struct target *target, target_addr_t address, + uint32_t size, uint32_t increment, bool 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"); + *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); + *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 - " + "sba reads only support size==increment or also size==0 for sba v1."); + *skip_reason = "skipped (unsupported increment)"; + return true; + } + + return false; +} + +static bool mem_should_skip_abstract(struct target *target, target_addr_t address, + uint32_t size, uint32_t increment, bool 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); + *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)); + *skip_reason = "skipped (too large address)"; + return true; + } + if (read && size != increment) { + LOG_ERROR("Skipping mem read via abstract access - " + "abstract command reads only support size==increment."); + *skip_reason = "skipped (unsupported increment)"; + return true; + } + + return false; +} + +/* + * Performs a memory read using memory access abstract commands. The read sizes + * supported are 1, 2, and 4 bytes despite the spec's support of 8 and 16 byte + * aamsize fields in the memory access abstract command. + */ +static int read_memory_abstract(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +{ + RISCV013_INFO(info); + + int result = ERROR_OK; + bool use_aampostincrement = info->has_aampostincrement != YNM_NO; - sbcs = set_field(sbcs, DMI_SBCS_SBREADONDATA, 0); - dmi_write(target, DMI_SBCS, sbcs); + LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, + size, address); - read_memory_bus_word(target, address + (count - 1) * size, size, - buffer + (count - 1) * size); + memset(buffer, 0, count * size); - if (read_sbcs_nonbusy(target, &sbcs) != ERROR_OK) - return ERROR_FAIL; + /* Convert the size (bytes) to width (bits) */ + unsigned width = size << 3; - if (get_field(sbcs, DMI_SBCS_SBBUSYERROR)) { - /* We read while the target was busy. Slow down and try again. */ - dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR); - next_address = sb_read_address(target); - info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1; - continue; + /* Create the command (physical address, postincrement, read) */ + uint32_t command = access_memory_command(target, false, width, use_aampostincrement, false); + + /* Execute the reads */ + uint8_t *p = buffer; + bool updateaddr = true; + unsigned int width32 = (width < 32) ? 32 : width; + for (uint32_t c = 0; c < count; c++) { + /* Update the address if it is the first time or aampostincrement is not supported by the target. */ + if (updateaddr) { + /* 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()."); + return result; + } } - unsigned error = get_field(sbcs, DMI_SBCS_SBERROR); - if (error == 0) { - next_address = end_address; - } else { - /* Some error indicating the bus access failed, but not because of - * something we did wrong. */ - dmi_write(target, DMI_SBCS, DMI_SBCS_SBERROR); - return ERROR_FAIL; + /* Execute the command */ + result = execute_abstract_command(target, command); + + 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."); + info->has_aampostincrement = YNM_YES; + } else { + LOG_WARNING("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); + if (result == ERROR_OK) { + LOG_DEBUG("aampostincrement is not supported on this target."); + info->has_aampostincrement = YNM_NO; + } + } } + + if (result != ERROR_OK) + return result; + + /* Copy arg0 to buffer (rounded width up to nearest 32) */ + riscv_reg_t value = read_abstract_arg(target, 0, width32); + buf_set_u64(p, 0, 8 * size, value); + + if (info->has_aampostincrement == YNM_YES) + updateaddr = false; + p += size; } - return ERROR_OK; + return result; } -static int batch_run(const struct target *target, struct riscv_batch *batch) +/* + * Performs a memory write using memory access abstract commands. The write + * sizes supported are 1, 2, and 4 bytes despite the spec's support of 8 and 16 + * byte aamsize fields in the memory access abstract command. + */ +static int write_memory_abstract(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) { RISCV013_INFO(info); - RISCV_INFO(r); - if (r->reset_delays_wait >= 0) { - r->reset_delays_wait -= batch->used_scans; - if (r->reset_delays_wait <= 0) { - batch->idle_count = 0; - info->dmi_busy_delay = 0; - info->ac_busy_delay = 0; + 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, + size, address); + + /* Convert the size (bytes) to width (bits) */ + unsigned width = size << 3; + + /* Create the command (physical address, postincrement, write) */ + uint32_t command = access_memory_command(target, false, width, use_aampostincrement, true); + + /* Execute the writes */ + const uint8_t *p = buffer; + bool updateaddr = true; + for (uint32_t c = 0; c < count; c++) { + /* Move data to arg0 */ + 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()."); + return result; + } + + /* Update the address if it is the first time or aampostincrement is not supported by the target. */ + if (updateaddr) { + /* 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()."); + return result; + } + } + + /* Execute the command */ + result = execute_abstract_command(target, command); + + 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."); + info->has_aampostincrement = YNM_YES; + } else { + LOG_WARNING("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); + if (result == ERROR_OK) { + LOG_DEBUG("aampostincrement is not supported on this target."); + info->has_aampostincrement = YNM_NO; + } + } } + + if (result != ERROR_OK) + return result; + + if (info->has_aampostincrement == YNM_YES) + updateaddr = false; + p += size; } - return riscv_batch_run(batch); + + return result; } /** @@ -2091,16 +3103,21 @@ static int batch_run(const struct target *target, struct riscv_batch *batch) * even if cmderr=busy is encountered. */ static int read_memory_progbuf_inner(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { RISCV013_INFO(info); int result = ERROR_OK; - /* Write address to S0, and execute buffer. */ + /* Write address to S0. */ result = register_write_direct(target, GDB_REGNO_S0, address); if (result != ERROR_OK) - goto error; + return result; + + if (increment == 0 && + register_write_direct(target, GDB_REGNO_S2, 0) != ERROR_OK) + return ERROR_FAIL; + uint32_t command = access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); @@ -2108,32 +3125,30 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres return ERROR_FAIL; /* 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; - write_to_buf(buffer, value, size); + buf_set_u64(buffer, 0, 8 * size, value); log_memory_access(address, value, size, true); return ERROR_OK; } - if (dmi_write(target, DMI_ABSTRACTAUTO, - 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET) != 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, DMI_DATA0) != ERROR_OK) + 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. */ - riscv_addr_t read_addr = address + 2 * size; - riscv_addr_t fin_addr = address + (count * size); - while (read_addr < fin_addr) { - LOG_DEBUG("read_addr=0x%" PRIx64 ", fin_addr=0x%" PRIx64, read_addr, - fin_addr); + 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: @@ -2142,15 +3157,16 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres * dm_data0 contains[read_addr-size*2] */ - LOG_DEBUG("creating burst to read from 0x%" PRIx64 - " up to 0x%" PRIx64, read_addr, fin_addr); - assert(read_addr >= address && read_addr < fin_addr); struct riscv_batch *batch = riscv_batch_alloc(target, 32, info->dmi_busy_delay + info->ac_busy_delay); + if (!batch) + return ERROR_FAIL; - size_t reads = 0; - for (riscv_addr_t addr = read_addr; addr < fin_addr; addr += size) { - riscv_batch_add_dmi_read(batch, DMI_DATA0); + 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); reads++; if (riscv_batch_full(batch)) @@ -2163,19 +3179,19 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres * 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, DMI_ABSTRACTCS) != ERROR_OK) + if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) return ERROR_FAIL; - while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) - if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + while (get_field(abstractcs, DM_ABSTRACTCS_BUSY)) + if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) return ERROR_FAIL; - info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); + info->cmderr = get_field(abstractcs, DM_ABSTRACTCS_CMDERR); - riscv_addr_t next_read_addr; + unsigned next_index; unsigned ignore_last = 0; switch (info->cmderr) { case CMDERR_NONE: LOG_DEBUG("successful (partial?) memory read"); - next_read_addr = read_addr + reads * size; + next_index = index + reads; break; case CMDERR_BUSY: LOG_DEBUG("memory read resulted in busy response"); @@ -2183,35 +3199,49 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres increase_ac_busy_delay(target); riscv013_clear_abstract_error(target); - dmi_write(target, DMI_ABSTRACTAUTO, 0); + dmi_write(target, DM_ABSTRACTAUTO, 0); - uint32_t dmi_data0; + 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, DMI_DATA0) != ERROR_OK) { + 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; } /* See how far we got, clobbering dmi_data0. */ - result = register_read_direct(target, &next_read_addr, - GDB_REGNO_S0); + 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; } - write_to_buf(buffer + next_read_addr - 2 * size - address, dmi_data0, size); - log_memory_access(next_read_addr - 2 * size, dmi_data0, size, true); + + 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); /* Restore the command, and execute it. - * Now DMI_DATA0 contains the next value just as it would if no + * Now DM_DATA0 contains the next value just as it would if no * error had occurred. */ - dmi_write_exec(target, DMI_COMMAND, command); - next_read_addr += size; + dmi_write_exec(target, DM_COMMAND, command, true); + next_index++; - dmi_write(target, DMI_ABSTRACTAUTO, - 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + dmi_write(target, DM_ABSTRACTAUTO, + 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); ignore_last = 1; @@ -2226,16 +3256,18 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres /* Now read whatever we got out of the batch. */ dmi_status_t status = DMI_STATUS_SUCCESS; - for (size_t i = 0; i < reads; i++) { - riscv_addr_t receive_addr = read_addr + (i-2) * size; - assert(receive_addr < address + size * count); - if (receive_addr < address) - continue; - if (receive_addr > next_read_addr - (3 + ignore_last) * size) + 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; - uint64_t dmi_out = riscv_batch_get_dmi_read(batch, i); - status = get_field(dmi_out, DTM_DMI_OP); + 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 @@ -2251,28 +3283,41 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres result = ERROR_FAIL; goto error; } - uint32_t value = get_field(dmi_out, DTM_DMI_DATA); - riscv_addr_t offset = receive_addr - address; - write_to_buf(buffer + offset, value, size); - log_memory_access(receive_addr, value, size, true); - - receive_addr += size; + 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); } - read_addr = next_read_addr; + index = next_index; riscv_batch_free(batch); } - dmi_write(target, DMI_ABSTRACTAUTO, 0); + dmi_write(target, DM_ABSTRACTAUTO, 0); if (count > 1) { /* Read the penultimate word. */ - uint32_t value; - if (dmi_read(target, &value, DMI_DATA0) != ERROR_OK) + uint32_t dmi_data0, dmi_data1 = 0; + if (dmi_read(target, &dmi_data0, DM_DATA0) != ERROR_OK) return ERROR_FAIL; - write_to_buf(buffer + size * (count-2), value, size); - log_memory_access(address + size * (count-2), value, size, true); + if (size > 4 && dmi_read(target, &dmi_data1, DM_DATA1) != 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); } /* Read the last word. */ @@ -2280,13 +3325,87 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres result = register_read_direct(target, &value, GDB_REGNO_S1); if (result != ERROR_OK) goto error; - write_to_buf(buffer + size * (count-1), value, size); + buf_set_u64(buffer + size * (count-1), 0, 8 * size, value); log_memory_access(address + size * (count-1), value, size, true); return ERROR_OK; error: - dmi_write(target, DMI_ABSTRACTAUTO, 0); + dmi_write(target, DM_ABSTRACTAUTO, 0); + + return result; +} + +/* 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) +{ + uint64_t mstatus = 0; + uint64_t mstatus_old = 0; + if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) + return ERROR_FAIL; + + uint64_t s0; + int result = ERROR_FAIL; + + if (register_read(target, &s0, 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_s0; + + uint64_t value; + if (register_read(target, &value, GDB_REGNO_S0) != ERROR_OK) + goto restore_s0; + buf_set_u64(buffer, 0, 8 * size, value); + log_memory_access(address, value, size, true); + result = ERROR_OK; + +restore_s0: + if (riscv_set_register(target, GDB_REGNO_S0, s0) != ERROR_OK) + result = ERROR_FAIL; + +restore_mstatus: + if (mstatus != mstatus_old) + if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) + result = ERROR_FAIL; return result; } @@ -2295,8 +3414,14 @@ error: * 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 size, uint32_t count, uint8_t *buffer, uint32_t increment) { + if (riscv_xlen(target) < size * 8) { + LOG_ERROR("XLEN (%d) is too short for %d-bit memory read.", + riscv_xlen(target), size * 8); + return ERROR_FAIL; + } + int result = ERROR_OK; LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, @@ -2306,21 +3431,35 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, memset(buffer, 0, count*size); - /* s0 holds the next address to write to - * s1 holds the next data value to write + if (execute_fence(target) != ERROR_OK) + return ERROR_FAIL; + + if (count == 1) + return read_memory_progbuf_one(target, address, size, buffer); + + uint64_t mstatus = 0; + uint64_t mstatus_old = 0; + if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) + return ERROR_FAIL; + + /* s0 holds the next address to read from + * s1 holds the next data value read + * s2 is a counter in case increment is 0 */ - uint64_t s0, s1; + uint64_t s0, s1, s2; if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; - - if (execute_fence(target) != ERROR_OK) + if (increment == 0 && register_read(target, &s2, GDB_REGNO_S2) != 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); + switch (size) { case 1: riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); @@ -2331,39 +3470,47 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, 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_FAIL; } - riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); + + 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); if (riscv_program_ebreak(&program) != ERROR_OK) return ERROR_FAIL; - riscv_program_write(&program); + if (riscv_program_write(&program) != ERROR_OK) + return ERROR_FAIL; - result = read_memory_progbuf_inner(target, address, size, count, buffer); + result = read_memory_progbuf_inner(target, address, size, count, buffer, increment); 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 size_i = size; uint32_t count_i = 1; uint8_t *buffer_i = buffer; - for (uint32_t i = 0; i < count; i++, address_i += size_i, buffer_i += size_i) { + 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_i, count_i, buffer_i); + 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_i, address_i); + size, address_i); - uint64_t value_i = 0; - write_to_buf(buffer_i, value_i, size_i); + buf_set_u64(buffer_i, 0, 8 * size, 0); } } result = ERROR_OK; @@ -2371,32 +3518,79 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); + if (increment == 0) + riscv_set_register(target, GDB_REGNO_S2, s2); + + /* Restore MSTATUS */ + if (mstatus != mstatus_old) + if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) + return ERROR_FAIL; + return result; } static int read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { - RISCV013_INFO(info); - if (info->progbufsize >= 2 && !riscv_prefer_sba) - return read_memory_progbuf(target, address, size, count, buffer); + if (count == 0) + return ERROR_OK; - if ((get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) || - (get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) || - (get_field(info->sbcs, DMI_SBCS_SBACCESS32) && size == 4) || - (get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) || - (get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) { - if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0) - return read_memory_bus_v0(target, address, size, count, buffer); - else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1) - return read_memory_bus_v1(target, address, size, count, buffer); + if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) { + LOG_ERROR("BUG: Unsupported size for memory read: %d", size); + return ERROR_FAIL; } - if (info->progbufsize >= 2) - return read_memory_progbuf(target, address, size, count, buffer); + int ret = ERROR_FAIL; + RISCV_INFO(r); + RISCV013_INFO(info); - LOG_ERROR("Don't know how to read memory on this target."); - return ERROR_FAIL; + char *progbuf_result = "disabled"; + char *sysbus_result = "disabled"; + char *abstract_result = "disabled"; + + for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { + int method = r->mem_access_methods[i]; + + if (method == RISCV_MEM_ACCESS_PROGBUF) { + if (mem_should_skip_progbuf(target, address, size, true, &progbuf_result)) + continue; + + ret = read_memory_progbuf(target, address, size, count, buffer, increment); + + if (ret != ERROR_OK) + progbuf_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_SYSBUS) { + if (mem_should_skip_sysbus(target, address, size, increment, true, &sysbus_result)) + continue; + + if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0) + ret = read_memory_bus_v0(target, address, size, count, buffer, increment); + else if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 1) + ret = read_memory_bus_v1(target, address, size, count, buffer, increment); + + if (ret != ERROR_OK) + sysbus_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { + if (mem_should_skip_abstract(target, address, size, increment, true, &abstract_result)) + continue; + + ret = read_memory_abstract(target, address, size, count, buffer, increment); + + if (ret != ERROR_OK) + abstract_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) + /* No further mem access method to try. */ + break; + + log_mem_access_result(target, ret == ERROR_OK, method, true); + + if (ret == ERROR_OK) + 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); + return ret; } static int write_memory_bus_v0(struct target *target, target_addr_t address, @@ -2405,7 +3599,7 @@ static int write_memory_bus_v0(struct target *target, target_addr_t address, /*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" TARGET_PRIxADDR, size, count, address); - dmi_write(target, DMI_SBADDRESS0, address); + dmi_write(target, DM_SBADDRESS0, address); int64_t value = 0; int64_t access = 0; riscv_addr_t offset = 0; @@ -2414,42 +3608,24 @@ static int write_memory_bus_v0(struct target *target, target_addr_t address, /* B.8 Writing Memory, single write check if we write in one go */ if (count == 1) { /* count is in bytes here */ - /* check the size */ - switch (size) { - case 1: - value = t_buffer[0]; - break; - case 2: - value = t_buffer[0] - | ((uint32_t) t_buffer[1] << 8); - break; - case 4: - value = t_buffer[0] - | ((uint32_t) t_buffer[1] << 8) - | ((uint32_t) t_buffer[2] << 16) - | ((uint32_t) t_buffer[3] << 24); - break; - default: - LOG_ERROR("unsupported access size: %d", size); - return ERROR_FAIL; - } + value = buf_get_u64(t_buffer, 0, 8 * size); access = 0; - access = set_field(access, DMI_SBCS_SBACCESS, size/2); - dmi_write(target, DMI_SBCS, access); + 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, DMI_SBDATA0, value); + dmi_write(target, DM_SBDATA0, value); return ERROR_OK; } /*B.8 Writing Memory, using autoincrement*/ access = 0; - access = set_field(access, DMI_SBCS_SBACCESS, size/2); - access = set_field(access, DMI_SBCS_SBAUTOINCREMENT, 1); + 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, DMI_SBCS, access); + dmi_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) { @@ -2458,31 +3634,14 @@ static int write_memory_bus_v0(struct target *target, target_addr_t address, t_addr = address + offset; t_buffer = buffer + offset; - switch (size) { - case 1: - value = t_buffer[0]; - break; - case 2: - value = t_buffer[0] - | ((uint32_t) t_buffer[1] << 8); - break; - case 4: - value = t_buffer[0] - | ((uint32_t) t_buffer[1] << 8) - | ((uint32_t) t_buffer[2] << 16) - | ((uint32_t) t_buffer[3] << 24); - break; - default: - LOG_ERROR("unsupported access size: %d", size); - return ERROR_FAIL; - } + value = buf_get_u64(t_buffer, 0, 8 * size); LOG_DEBUG("SAB:autoincrement: expected address: 0x%08x value: 0x%08x" PRIx64, (uint32_t)t_addr, (uint32_t)value); - dmi_write(target, DMI_SBDATA0, value); + dmi_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, DMI_SBCS_SBAUTOINCREMENT, 0); - dmi_write(target, DMI_SBCS, access); + access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 0); + dmi_write(target, DM_SBCS, access); return ERROR_OK; } @@ -2492,30 +3651,47 @@ 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, DMI_SBCS_SBAUTOINCREMENT, 1); - dmi_write(target, DMI_SBCS, sbcs); + sbcs = set_field(sbcs, DM_SBCS_SBAUTOINCREMENT, 1); + dmi_write(target, DM_SBCS, sbcs); target_addr_t next_address = address; target_addr_t end_address = address + count * size; - sb_write_address(target, next_address); + int result; + + sb_write_address(target, next_address, true); while (next_address < end_address) { + LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR, + next_address); + + struct riscv_batch *batch = riscv_batch_alloc( + target, + 32, + info->dmi_busy_delay + info->bus_master_write_delay); + if (!batch) + return ERROR_FAIL; + for (uint32_t i = (next_address - address) / size; i < count; i++) { const uint8_t *p = buffer + i * size; + + if (riscv_batch_available_scans(batch) < (size + 3) / 4) + break; + if (size > 12) - dmi_write(target, DMI_SBDATA3, + 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) - dmi_write(target, DMI_SBDATA2, + 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) - dmi_write(target, DMI_SBDATA1, + riscv_batch_add_dmi_write(batch, DM_SBDATA1, ((uint32_t) p[4]) | (((uint32_t) p[5]) << 8) | (((uint32_t) p[6]) << 16) | @@ -2527,37 +3703,82 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, } if (size > 1) value |= ((uint32_t) p[1]) << 8; - dmi_write(target, DMI_SBDATA0, value); + riscv_batch_add_dmi_write(batch, DM_SBDATA0, value); log_memory_access(address + i * size, value, size, false); + next_address += size; + } - if (info->bus_master_write_delay) { - jtag_add_runtest(info->bus_master_write_delay, TAP_IDLE); - if (jtag_execute_queue() != ERROR_OK) { - LOG_ERROR("Failed to scan idle sequence"); - return ERROR_FAIL; - } + /* Execute the batch of writes */ + result = batch_run(target, batch); + riscv_batch_free(batch); + if (result != ERROR_OK) + return result; + + /* 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, + DM_SBCS, 0, false, true) != ERROR_OK) + return ERROR_FAIL; + if (dmi_busy_encountered) + LOG_DEBUG("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). " + "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) + return ERROR_FAIL; } - if (read_sbcs_nonbusy(target, &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."); + /* Clear the sticky error flag. */ + dmi_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; + } - if (get_field(sbcs, DMI_SBCS_SBBUSYERROR)) { - /* We wrote while the target was busy. Slow down and try again. */ - dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR); + if (get_field(sbcs, DM_SBCS_SBBUSYERROR) || dmi_busy_encountered) { + /* Recover from the case when the write commands were issued too fast. + * Determine the address from which to resume writing. */ next_address = sb_read_address(target); - info->bus_master_write_delay += info->bus_master_write_delay / 10 + 1; + if (next_address < address) { + /* This should never happen, probably buggy hardware. */ + LOG_DEBUG("unexpected sbaddress=0x%" TARGET_PRIxADDR + " - buggy sbautoincrement in hw?", next_address); + /* Fail the whole operation. */ + return ERROR_FAIL; + } + /* Try again - resume writing. */ continue; } - unsigned error = get_field(sbcs, DMI_SBCS_SBERROR); - if (error == 0) { - next_address = end_address; - } else { - /* Some error indicating the bus access failed, but not because of - * something we did wrong. */ - dmi_write(target, DMI_SBCS, DMI_SBCS_SBERROR); + unsigned int sberror = get_field(sbcs, DM_SBCS_SBERROR); + if (sberror != 0) { + /* Sberror indicates the bus access failed, but not because we issued the writes + * too fast. Cannot recover. Sbaddress holds the address where the error occurred + * (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 ")", + 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 + " - buggy sbautoincrement in hw?", next_address); + } + /* Clear the sticky error flag */ + dmi_write(target, DM_SBCS, DM_SBCS_SBERROR); + /* Fail the whole operation */ return ERROR_FAIL; } } @@ -2570,10 +3791,21 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, { 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); + return ERROR_FAIL; + } + LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); select_dmi(target); + uint64_t mstatus = 0; + uint64_t mstatus_old = 0; + if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) + return ERROR_FAIL; + /* s0 holds the next address to write to * s1 holds the next data value to write */ @@ -2588,6 +3820,8 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, /* 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); switch (size) { case 1: @@ -2599,12 +3833,17 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, 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("Unsupported size: %d", size); + LOG_ERROR("write_memory_progbuf(): Unsupported size: %d", size); result = ERROR_FAIL; goto error; } + 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); result = riscv_program_ebreak(&program); @@ -2624,6 +3863,8 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, target, 32, info->dmi_busy_delay + info->ac_busy_delay); + if (!batch) + goto error; /* To write another word, we put it in S1 and execute the program. */ unsigned start = (cur_addr - address) / size; @@ -2631,27 +3872,7 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, unsigned offset = size*i; const uint8_t *t_buffer = buffer + offset; - uint32_t value; - switch (size) { - case 1: - value = t_buffer[0]; - break; - case 2: - value = t_buffer[0] - | ((uint32_t) t_buffer[1] << 8); - break; - case 4: - value = t_buffer[0] - | ((uint32_t) t_buffer[1] << 8) - | ((uint32_t) t_buffer[2] << 16) - | ((uint32_t) t_buffer[3] << 24); - break; - default: - LOG_ERROR("unsupported access size: %d", size); - riscv_batch_free(batch); - result = ERROR_FAIL; - goto error; - } + uint64_t value = buf_get_u64(t_buffer, 0, 8 * size); log_memory_access(address + offset, value, size, false); cur_addr += size; @@ -2665,12 +3886,14 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, } /* Write value. */ - dmi_write(target, DMI_DATA0, 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, 32, + GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_POSTEXEC | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); @@ -2681,12 +3904,14 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, } /* Turn on autoexec */ - dmi_write(target, DMI_ABSTRACTAUTO, - 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + dmi_write(target, DM_ABSTRACTAUTO, + 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); setup_needed = false; } else { - riscv_batch_add_dmi_write(batch, DMI_DATA0, value); + 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; } @@ -2703,13 +3928,14 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, uint32_t abstractcs; bool dmi_busy_encountered; - if (dmi_op(target, &abstractcs, &dmi_busy_encountered, DMI_OP_READ, - DMI_ABSTRACTCS, 0, false) != ERROR_OK) + 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, DMI_ABSTRACTCS_BUSY)) - if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + while (get_field(abstractcs, DM_ABSTRACTCS_BUSY)) + if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) return ERROR_FAIL; - info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); + 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) { @@ -2720,7 +3946,7 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, riscv013_clear_abstract_error(target); increase_ac_busy_delay(target); - dmi_write(target, DMI_ABSTRACTAUTO, 0); + dmi_write(target, DM_ABSTRACTAUTO, 0); result = register_read_direct(target, &cur_addr, GDB_REGNO_S0); if (result != ERROR_OK) goto error; @@ -2734,13 +3960,18 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, } error: - dmi_write(target, DMI_ABSTRACTAUTO, 0); + dmi_write(target, DM_ABSTRACTAUTO, 0); if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) return ERROR_FAIL; if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; + /* Restore MSTATUS */ + if (mstatus != mstatus_old) + if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) + return ERROR_FAIL; + if (execute_fence(target) != ERROR_OK) return ERROR_FAIL; @@ -2750,26 +3981,62 @@ error: 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); + return ERROR_FAIL; + } + + int ret = ERROR_FAIL; + RISCV_INFO(r); RISCV013_INFO(info); - if (info->progbufsize >= 2 && !riscv_prefer_sba) - return write_memory_progbuf(target, address, size, count, buffer); - if ((get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) || - (get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) || - (get_field(info->sbcs, DMI_SBCS_SBACCESS32) && size == 4) || - (get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) || - (get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) { - if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0) - return write_memory_bus_v0(target, address, size, count, buffer); - else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1) - return write_memory_bus_v1(target, address, size, count, buffer); + char *progbuf_result = "disabled"; + char *sysbus_result = "disabled"; + char *abstract_result = "disabled"; + + for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { + int method = r->mem_access_methods[i]; + + if (method == RISCV_MEM_ACCESS_PROGBUF) { + if (mem_should_skip_progbuf(target, address, size, false, &progbuf_result)) + continue; + + ret = write_memory_progbuf(target, address, size, count, buffer); + + if (ret != ERROR_OK) + progbuf_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_SYSBUS) { + if (mem_should_skip_sysbus(target, address, size, 0, false, &sysbus_result)) + continue; + + if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0) + ret = write_memory_bus_v0(target, address, size, count, buffer); + else if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 1) + ret = write_memory_bus_v1(target, address, size, count, buffer); + + if (ret != ERROR_OK) + sysbus_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { + if (mem_should_skip_abstract(target, address, size, 0, false, &abstract_result)) + continue; + + ret = write_memory_abstract(target, address, size, count, buffer); + + if (ret != ERROR_OK) + abstract_result = "failed"; + } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) + /* No further mem access method to try. */ + break; + + log_mem_access_result(target, ret == ERROR_OK, method, false); + + if (ret == ERROR_OK) + return ret; } - if (info->progbufsize >= 2) - return write_memory_progbuf(target, address, size, count, buffer); - - LOG_ERROR("Don't know how to write memory on this target."); - return ERROR_FAIL; + 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); + return ret; } static int arch_state(struct target *target) @@ -2785,35 +4052,38 @@ struct target_type riscv013_target = { .examine = examine, .poll = &riscv_openocd_poll, - .halt = &riscv_openocd_halt, - .resume = &riscv_openocd_resume, + .halt = &riscv_halt, .step = &riscv_openocd_step, .assert_reset = assert_reset, .deassert_reset = deassert_reset, - .read_memory = read_memory, .write_memory = write_memory, - .arch_state = arch_state, + .arch_state = arch_state }; /*** 0.13-specific implementations of various RISC-V helper functions. ***/ static int riscv013_get_register(struct target *target, - riscv_reg_t *value, int hid, int rid) + riscv_reg_t *value, int rid) { - LOG_DEBUG("reading register %s on hart %d", gdb_regno_name(rid), hid); + LOG_DEBUG("[%s] reading register %s", target_name(target), + gdb_regno_name(rid)); - riscv_set_current_hartid(target, hid); + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; int result = ERROR_OK; if (rid == GDB_REGNO_PC) { + /* TODO: move this into riscv.c. */ result = register_read(target, value, GDB_REGNO_DPC); - LOG_DEBUG("read PC from DPC: 0x%" PRIx64, *value); + LOG_DEBUG("[%d] read PC from DPC: 0x%" PRIx64, target->coreid, *value); } else if (rid == GDB_REGNO_PRIV) { uint64_t dcsr; + /* TODO: move this into riscv.c. */ result = register_read(target, &dcsr, GDB_REGNO_DCSR); - *value = get_field(dcsr, CSR_DCSR_PRV); + *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(target, value, rid); if (result != ERROR_OK) @@ -2823,21 +4093,20 @@ static int riscv013_get_register(struct target *target, return result; } -static int riscv013_set_register(struct target *target, int hid, int rid, uint64_t value) +static int riscv013_set_register(struct target *target, int rid, uint64_t value) { - LOG_DEBUG("writing 0x%" PRIx64 " to register %s on hart %d", value, - gdb_regno_name(rid), hid); - - riscv_set_current_hartid(target, hid); + riscv013_select_current_hart(target); + LOG_DEBUG("[%d] writing 0x%" PRIx64 " to register %s", + target->coreid, value, gdb_regno_name(rid)); if (rid <= GDB_REGNO_XPR31) { return register_write_direct(target, rid, value); } else if (rid == GDB_REGNO_PC) { - LOG_DEBUG("writing PC to DPC: 0x%" PRIx64, value); + LOG_DEBUG("[%d] writing PC to DPC: 0x%" PRIx64, target->coreid, value); register_write_direct(target, GDB_REGNO_DPC, value); uint64_t actual_value; register_read_direct(target, &actual_value, GDB_REGNO_DPC); - LOG_DEBUG(" actual DPC written: 0x%016" PRIx64, actual_value); + LOG_DEBUG("[%d] actual DPC written: 0x%016" PRIx64, target->coreid, actual_value); if (value != actual_value) { LOG_ERROR("Written PC (0x%" PRIx64 ") does not match read back " "value (0x%" PRIx64 ")", value, actual_value); @@ -2846,7 +4115,8 @@ static int riscv013_set_register(struct target *target, int hid, int rid, uint64 } else if (rid == GDB_REGNO_PRIV) { uint64_t dcsr; register_read(target, &dcsr, GDB_REGNO_DCSR); - dcsr = set_field(dcsr, CSR_DCSR_PRV, value); + 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); @@ -2860,32 +4130,95 @@ static int riscv013_select_current_hart(struct target *target) RISCV_INFO(r); dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; if (r->current_hartid == dm->current_hartid) return ERROR_OK; uint32_t dmcontrol; /* TODO: can't we just "dmcontrol = DMI_DMACTIVE"? */ - if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) return ERROR_FAIL; dmcontrol = set_hartsel(dmcontrol, r->current_hartid); - int result = dmi_write(target, DMI_DMCONTROL, dmcontrol); + int result = dmi_write(target, DM_DMCONTROL, dmcontrol); dm->current_hartid = r->current_hartid; return result; } -static int riscv013_halt_current_hart(struct target *target) +/* Select all harts that were prepped and that are selectable, clearing the + * prepped flag on the harts that actually were selected. */ +static int select_prepped_harts(struct target *target, bool *use_hasel) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + if (!dm->hasel_supported) { + RISCV_INFO(r); + r->prepped = false; + *use_hasel = false; + return ERROR_OK; + } + + 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); + + target_list_t *entry; + unsigned total_selected = 0; + list_for_each_entry(entry, &dm->target_list, list) { + struct target *t = entry->target; + struct riscv_info *r = riscv_info(t); + riscv013_info_t *info = get_info(t); + unsigned index = info->index; + LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, r->prepped); + r->selected = r->prepped; + if (r->prepped) { + hawindow[index / 32] |= 1 << (index % 32); + r->prepped = false; + total_selected++; + } + index++; + } + + /* Don't use hasel if we only need to talk to one hart. */ + if (total_selected <= 1) { + *use_hasel = false; + return ERROR_OK; + } + + for (unsigned i = 0; i < hawindow_count; i++) { + if (dmi_write(target, DM_HAWINDOWSEL, i) != ERROR_OK) + return ERROR_FAIL; + if (dmi_write(target, DM_HAWINDOW, hawindow[i]) != ERROR_OK) + return ERROR_FAIL; + } + + *use_hasel = true; + return ERROR_OK; +} + +static int riscv013_halt_prep(struct target *target) { + return ERROR_OK; +} + +static int riscv013_halt_go(struct target *target) +{ + bool use_hasel = false; + if (select_prepped_harts(target, &use_hasel) != ERROR_OK) + return ERROR_FAIL; + RISCV_INFO(r); LOG_DEBUG("halting hart %d", r->current_hartid); - if (riscv_is_halted(target)) - LOG_ERROR("Hart %d is already halted!", r->current_hartid); /* Issue the halt command, and then wait for the current hart to halt. */ - uint32_t dmcontrol; - if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) - return ERROR_FAIL; - dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 1); - dmi_write(target, DMI_DMCONTROL, dmcontrol); + uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ; + if (use_hasel) + dmcontrol |= DM_DMCONTROL_HASEL; + dmcontrol = set_hartsel(dmcontrol, r->current_hartid); + dmi_write(target, DM_DMCONTROL, dmcontrol); for (size_t i = 0; i < 256; ++i) if (riscv_is_halted(target)) break; @@ -2894,7 +4227,7 @@ static int riscv013_halt_current_hart(struct target *target) uint32_t dmstatus; if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; - if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) return ERROR_FAIL; LOG_ERROR("unable to halt hart %d", r->current_hartid); @@ -2903,23 +4236,41 @@ static int riscv013_halt_current_hart(struct target *target) return ERROR_FAIL; } - dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 0); - dmi_write(target, DMI_DMCONTROL, dmcontrol); + dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0); + dmi_write(target, DM_DMCONTROL, dmcontrol); + + if (use_hasel) { + target_list_t *entry; + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + 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; + } + } + /* The "else" case is handled in halt_go(). */ return ERROR_OK; } -static int riscv013_resume_current_hart(struct target *target) +static int riscv013_resume_go(struct target *target) { - return riscv013_step_or_resume_current_hart(target, false); + bool use_hasel = false; + if (select_prepped_harts(target, &use_hasel) != ERROR_OK) + return ERROR_FAIL; + + return riscv013_step_or_resume_current_hart(target, false, use_hasel); } static int riscv013_step_current_hart(struct target *target) { - return riscv013_step_or_resume_current_hart(target, true); + return riscv013_step_or_resume_current_hart(target, true, false); } -static int riscv013_on_resume(struct target *target) +static int riscv013_resume_prep(struct target *target) { return riscv013_on_step_or_resume(target, false); } @@ -2939,16 +4290,16 @@ static bool riscv013_is_halted(struct target *target) uint32_t dmstatus; if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return false; - if (get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) + if (get_field(dmstatus, DM_DMSTATUS_ANYUNAVAIL)) LOG_ERROR("Hart %d is unavailable.", riscv_current_hartid(target)); - if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT)) + if (get_field(dmstatus, DM_DMSTATUS_ANYNONEXISTENT)) LOG_ERROR("Hart %d doesn't exist.", riscv_current_hartid(target)); - if (get_field(dmstatus, DMI_DMSTATUS_ANYHAVERESET)) { + if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) { int hartid = riscv_current_hartid(target); LOG_INFO("Hart %d unexpectedly reset!", hartid); /* TODO: Can we make this more obvious to eg. a gdb user? */ - uint32_t dmcontrol = DMI_DMCONTROL_DMACTIVE | - DMI_DMCONTROL_ACKHAVERESET; + uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | + DM_DMCONTROL_ACKHAVERESET; dmcontrol = set_hartsel(dmcontrol, hartid); /* 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 @@ -2956,10 +4307,10 @@ static bool riscv013_is_halted(struct target *target) * that it is halted again once the request goes through. */ if (target->state == TARGET_HALTED) - dmcontrol |= DMI_DMCONTROL_HALTREQ; - dmi_write(target, DMI_DMCONTROL, dmcontrol); + dmcontrol |= DM_DMCONTROL_HALTREQ; + dmi_write(target, DM_DMCONTROL, dmcontrol); } - return get_field(dmstatus, DMI_DMSTATUS_ALLHALTED); + return get_field(dmstatus, DM_DMSTATUS_ALLHALTED); } static enum riscv_halt_reason riscv013_halt_reason(struct target *target) @@ -2969,6 +4320,8 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) if (result != ERROR_OK) return RISCV_HALT_UNKNOWN; + LOG_DEBUG("dcsr.cause: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); + switch (get_field(dcsr, CSR_DCSR_CAUSE)) { case CSR_DCSR_CAUSE_SWBP: return RISCV_HALT_BREAKPOINT; @@ -2984,29 +4337,41 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) case CSR_DCSR_CAUSE_DEBUGINT: case CSR_DCSR_CAUSE_HALT: return RISCV_HALT_INTERRUPT; + case CSR_DCSR_CAUSE_GROUP: + return RISCV_HALT_GROUP; } - LOG_ERROR("Unknown DCSR cause field: %x", (int)get_field(dcsr, CSR_DCSR_CAUSE)); + LOG_ERROR("Unknown DCSR cause field: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); LOG_ERROR(" dcsr=0x%016lx", (long)dcsr); return RISCV_HALT_UNKNOWN; } int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { - return dmi_write(target, DMI_PROGBUF0 + index, 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) + return ERROR_FAIL; + dm->progbuf_cache[index] = data; + } else { + LOG_DEBUG("cache hit for 0x%" PRIx32 " @%d", data, index); + } + return ERROR_OK; } riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) { uint32_t value; - dmi_read(target, &value, DMI_PROGBUF0 + index); + dmi_read(target, &value, DM_PROGBUF0 + index); return value; } int riscv013_execute_debug_buffer(struct target *target) { uint32_t run_program = 0; - run_program = set_field(run_program, AC_ACCESS_REGISTER_SIZE, 2); + run_program = set_field(run_program, AC_ACCESS_REGISTER_AARSIZE, 2); run_program = set_field(run_program, AC_ACCESS_REGISTER_POSTEXEC, 1); run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0); run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000); @@ -3038,357 +4403,6 @@ 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, DMI_SBCS_SBACCESS128); - uint32_t sbaccess64 = get_field(info->sbcs, DMI_SBCS_SBACCESS64); - uint32_t sbaccess32 = get_field(info->sbcs, DMI_SBCS_SBACCESS32); - uint32_t sbaccess16 = get_field(info->sbcs, DMI_SBCS_SBACCESS16); - uint32_t sbaccess8 = get_field(info->sbcs, DMI_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) -{ - RISCV013_INFO(info); - - uint32_t sbaccess128 = get_field(info->sbcs, DMI_SBCS_SBACCESS128); - uint32_t sbaccess64 = get_field(info->sbcs, DMI_SBCS_SBACCESS64); - uint32_t sbaccess32 = get_field(info->sbcs, DMI_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, DMI_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, DMI_SBCS_SBVERSION) != 1) { - LOG_ERROR("System Bus Access unsupported SBVERSION (%d). Only version 1 is supported.", - get_field(sbcs, DMI_SBCS_SBVERSION)); - return ERROR_FAIL; - } - - uint32_t num_sbdata_regs = get_num_sbdata_regs(target); - - uint32_t rd_buf[num_sbdata_regs]; - - /* Test 1: Simple write/read test */ - test_passed = true; - sbcs = set_field(sbcs_orig, DMI_SBCS_SBAUTOINCREMENT, 0); - dmi_write(target, DMI_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, DMI_SBCS_SBACCESS, sbaccess); - dmi_write(target, DMI_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, DMI_SBCS_SBAUTOINCREMENT, 1); - dmi_write(target, DMI_SBCS, sbcs); - - for (uint32_t sbaccess = 0; sbaccess <= (uint32_t)max_sbaccess; sbaccess++) { - sbcs = set_field(sbcs, DMI_SBCS_SBACCESS, sbaccess); - dmi_write(target, DMI_SBCS, sbcs); - - dmi_write(target, DMI_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, DMI_SBDATA0, i); - } - - read_sbcs_nonbusy(target, &sbcs); - - dmi_write(target, DMI_SBADDRESS0, legal_address); - - uint32_t val; - sbcs = set_field(sbcs, DMI_SBCS_SBREADONDATA, 1); - dmi_write(target, DMI_SBCS, sbcs); - dmi_read(target, &val, DMI_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, DMI_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, DMI_SBCS); - if (get_field(rd_val, DMI_SBCS_SBERROR) == 2) { - sbcs = set_field(sbcs_orig, DMI_SBCS_SBERROR, 2); - dmi_write(target, DMI_SBCS, sbcs); - dmi_read(target, &rd_val, DMI_SBCS); - if (get_field(rd_val, DMI_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, DMI_SBCS); - if (get_field(rd_val, DMI_SBCS_SBERROR) == 2) { - sbcs = set_field(sbcs_orig, DMI_SBCS_SBERROR, 2); - dmi_write(target, DMI_SBCS, sbcs); - dmi_read(target, &rd_val, DMI_SBCS); - if (get_field(rd_val, DMI_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, DMI_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, DMI_SBCS_SBACCESS, 4); - - write_memory_sba_simple(target, legal_address, test_patterns, 1, sbcs); - - dmi_read(target, &rd_val, DMI_SBCS); - if (get_field(rd_val, DMI_SBCS_SBERROR) == 4) { - sbcs = set_field(sbcs_orig, DMI_SBCS_SBERROR, 4); - dmi_write(target, DMI_SBCS, sbcs); - dmi_read(target, &rd_val, DMI_SBCS); - if (get_field(rd_val, DMI_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, DMI_SBCS_SBACCESS, 1); - - write_memory_sba_simple(target, legal_address+1, test_patterns, 1, sbcs); - - dmi_read(target, &rd_val, DMI_SBCS); - if (get_field(rd_val, DMI_SBCS_SBERROR) == 3) { - sbcs = set_field(sbcs_orig, DMI_SBCS_SBERROR, 3); - dmi_write(target, DMI_SBCS, sbcs); - dmi_read(target, &rd_val, DMI_SBCS); - if (get_field(rd_val, DMI_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, DMI_SBCS_SBREADONADDR, 1); - dmi_write(target, DMI_SBCS, sbcs); - - for (int i = 0; i < 16; i++) - dmi_write(target, DMI_SBDATA0, 0xdeadbeef); - - for (int i = 0; i < 16; i++) - dmi_write(target, DMI_SBADDRESS0, legal_address); - - dmi_read(target, &rd_val, DMI_SBCS); - if (get_field(rd_val, DMI_SBCS_SBBUSYERROR)) { - sbcs = set_field(sbcs_orig, DMI_SBCS_SBBUSYERROR, 1); - dmi_write(target, DMI_SBCS, sbcs); - dmi_read(target, &rd_val, DMI_SBCS); - if (get_field(rd_val, DMI_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; - } - -} - -void write_memory_sba_simple(struct target *target, target_addr_t addr, - uint32_t *write_data, uint32_t write_size, uint32_t sbcs) -{ - RISCV013_INFO(info); - - uint32_t rd_sbcs; - uint32_t masked_addr; - - uint32_t sba_size = get_field(info->sbcs, DMI_SBCS_SBASIZE); - - read_sbcs_nonbusy(target, &rd_sbcs); - - uint32_t sbcs_no_readonaddr = set_field(sbcs, DMI_SBCS_SBREADONADDR, 0); - dmi_write(target, DMI_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, DMI_SBADDRESS0+i, masked_addr); - else - dmi_write(target, DMI_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, DMI_SBDATA0+i, write_data[i]); -} - -void read_memory_sba_simple(struct target *target, target_addr_t addr, - uint32_t *rd_buf, uint32_t read_size, uint32_t sbcs) -{ - RISCV013_INFO(info); - - uint32_t rd_sbcs; - uint32_t masked_addr; - - uint32_t sba_size = get_field(info->sbcs, DMI_SBCS_SBASIZE); - - read_sbcs_nonbusy(target, &rd_sbcs); - - uint32_t sbcs_readonaddr = set_field(sbcs, DMI_SBCS_SBREADONADDR, 1); - dmi_write(target, DMI_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, DMI_SBADDRESS0+i, masked_addr); - else - dmi_write(target, DMI_SBADDRESS3, masked_addr); - } - - read_sbcs_nonbusy(target, &rd_sbcs); - - for (uint32_t i = 0; i < read_size; i++) - dmi_read(target, &(rd_buf[i]), DMI_SBDATA0+i); -} - int riscv013_dmi_write_u64_bits(struct target *target) { RISCV013_INFO(info); @@ -3397,9 +4411,7 @@ int riscv013_dmi_write_u64_bits(struct target *target) static int maybe_execute_fence_i(struct target *target) { - RISCV013_INFO(info); - RISCV_INFO(r); - if (info->progbufsize + r->impebreak >= 3) + if (has_sufficient_progbuf(target, 3)) return execute_fence(target); return ERROR_OK; } @@ -3416,13 +4428,14 @@ static int riscv013_on_step_or_resume(struct target *target, bool step) if (result != ERROR_OK) return result; dcsr = set_field(dcsr, CSR_DCSR_STEP, step); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, 1); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, 1); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, 1); + 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); return riscv_set_register(target, GDB_REGNO_DCSR, dcsr); } -static int riscv013_step_or_resume_current_hart(struct target *target, bool step) +static int riscv013_step_or_resume_current_hart(struct target *target, + bool step, bool use_hasel) { RISCV_INFO(r); LOG_DEBUG("resuming hart %d (for step?=%d)", r->current_hartid, step); @@ -3431,39 +4444,40 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step return ERROR_FAIL; } - if (maybe_execute_fence_i(target) != ERROR_OK) - return ERROR_FAIL; - /* Issue the resume command, and then wait for the current hart to resume. */ - uint32_t dmcontrol = DMI_DMCONTROL_DMACTIVE; + uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ; + if (use_hasel) + dmcontrol |= DM_DMCONTROL_HASEL; dmcontrol = set_hartsel(dmcontrol, r->current_hartid); - dmi_write(target, DMI_DMCONTROL, dmcontrol | DMI_DMCONTROL_RESUMEREQ); + dmi_write(target, DM_DMCONTROL, dmcontrol); + + dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HASEL, 0); + dmcontrol = set_field(dmcontrol, DM_DMCONTROL_RESUMEREQ, 0); uint32_t dmstatus; for (size_t i = 0; i < 256; ++i) { usleep(10); if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; - if (get_field(dmstatus, DMI_DMSTATUS_ALLRESUMEACK) == 0) + if (get_field(dmstatus, DM_DMSTATUS_ALLRESUMEACK) == 0) continue; - if (step && get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0) + if (step && get_field(dmstatus, DM_DMSTATUS_ALLHALTED) == 0) continue; - dmi_write(target, DMI_DMCONTROL, dmcontrol); + dmi_write(target, DM_DMCONTROL, dmcontrol); return ERROR_OK; } + dmi_write(target, DM_DMCONTROL, dmcontrol); + LOG_ERROR("unable to resume hart %d", r->current_hartid); - if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) - return ERROR_FAIL; - LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; LOG_ERROR(" dmstatus =0x%08x", dmstatus); if (step) { LOG_ERROR(" was stepping, halting"); - riscv013_halt_current_hart(target); + riscv_halt(target); return ERROR_OK; } @@ -3475,9 +4489,9 @@ void 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, DMI_ABSTRACTCS); - while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) { - dmi_read(target, &abstractcs, DMI_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 " @@ -3489,461 +4503,5 @@ void riscv013_clear_abstract_error(struct target *target) } } /* Clear the error status. */ - dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR); -} - -#define COMPLIANCE_TEST(b, message) \ -{ \ - int pass = 0; \ - if (b) { \ - pass = 1; \ - passed_tests++; \ - } \ - LOG_INFO("%s test %d (%s)\n", (pass) ? "PASSED" : "FAILED", total_tests, message); \ - assert(pass); \ - total_tests++; \ -} - -#define COMPLIANCE_MUST_PASS(b) COMPLIANCE_TEST(ERROR_OK == (b), "Regular calls must return ERROR_OK") - -#define COMPLIANCE_READ(target, addr, value) COMPLIANCE_MUST_PASS(dmi_read(target, addr, value)) -#define COMPLIANCE_WRITE(target, addr, value) COMPLIANCE_MUST_PASS(dmi_write(target, addr, value)) - -#define COMPLIANCE_CHECK_RO(target, addr) \ -{ \ - uint32_t orig; \ - uint32_t inverse; \ - COMPLIANCE_READ(target, &orig, addr); \ - COMPLIANCE_WRITE(target, addr, ~orig); \ - COMPLIANCE_READ(target, &inverse, addr); \ - COMPLIANCE_TEST(orig == inverse, "Register must be read-only"); \ -} - -int riscv013_test_compliance(struct target *target) -{ - LOG_INFO("Testing Compliance against RISC-V Debug Spec v0.13"); - - if (!riscv_rtos_enabled(target)) { - LOG_ERROR("Please run with -rtos riscv to run compliance test."); - return ERROR_FAIL; - } - - int total_tests = 0; - int passed_tests = 0; - - uint32_t dmcontrol_orig = DMI_DMCONTROL_DMACTIVE; - uint32_t dmcontrol; - uint32_t testvar; - uint32_t testvar_read; - riscv_reg_t value; - RISCV013_INFO(info); - - /* All the bits of HARTSEL are covered by the examine sequence. */ - - /* hartreset */ - /* This field is optional. Either we can read and write it to 1/0, - or it is tied to 0. This check doesn't really do anything, but - it does attempt to set the bit to 1 and then back to 0, which needs to - work if its implemented. */ - COMPLIANCE_WRITE(target, DMI_DMCONTROL, set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 1)); - COMPLIANCE_WRITE(target, DMI_DMCONTROL, set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 0)); - COMPLIANCE_READ(target, &dmcontrol, DMI_DMCONTROL); - COMPLIANCE_TEST((get_field(dmcontrol, DMI_DMCONTROL_HARTRESET) == 0), - "DMCONTROL.hartreset can be 0 or RW."); - - /* hasel */ - COMPLIANCE_WRITE(target, DMI_DMCONTROL, set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 1)); - COMPLIANCE_WRITE(target, DMI_DMCONTROL, set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 0)); - COMPLIANCE_READ(target, &dmcontrol, DMI_DMCONTROL); - COMPLIANCE_TEST((get_field(dmcontrol, DMI_DMCONTROL_HASEL) == 0), - "DMCONTROL.hasel can be 0 or RW."); - /* TODO: test that hamask registers exist if hasel does. */ - - /* haltreq */ - COMPLIANCE_MUST_PASS(riscv_halt_all_harts(target)); - /* This bit is not actually readable according to the spec, so nothing to check.*/ - - /* DMSTATUS */ - COMPLIANCE_CHECK_RO(target, DMI_DMSTATUS); - - /* resumereq */ - /* This bit is not actually readable according to the spec, so nothing to check.*/ - COMPLIANCE_MUST_PASS(riscv_resume_all_harts(target)); - - /* Halt all harts again so the test can continue.*/ - COMPLIANCE_MUST_PASS(riscv_halt_all_harts(target)); - - /* HARTINFO: Read-Only. This is per-hart, so need to adjust hartsel. */ - uint32_t hartinfo; - COMPLIANCE_READ(target, &hartinfo, DMI_HARTINFO); - for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) { - COMPLIANCE_MUST_PASS(riscv_set_current_hartid(target, hartsel)); - - COMPLIANCE_CHECK_RO(target, DMI_HARTINFO); - - /* $dscratch CSRs */ - uint32_t nscratch = get_field(hartinfo, DMI_HARTINFO_NSCRATCH); - for (unsigned int d = 0; d < nscratch; d++) { - riscv_reg_t testval, testval_read; - /* Because DSCRATCH is not guaranteed to last across PB executions, need to put - this all into one PB execution. Which may not be possible on all implementations.*/ - if (info->progbufsize >= 5) { - for (testval = 0x0011223300112233; - testval != 0xDEAD; - testval = testval == 0x0011223300112233 ? ~testval : 0xDEAD) { - COMPLIANCE_TEST(register_write_direct(target, GDB_REGNO_S0, testval) == ERROR_OK, - "Need to be able to write S0 in order to test DSCRATCH."); - struct riscv_program program32; - riscv_program_init(&program32, target); - riscv_program_csrw(&program32, GDB_REGNO_S0, GDB_REGNO_DSCRATCH + d); - riscv_program_csrr(&program32, GDB_REGNO_S1, GDB_REGNO_DSCRATCH + d); - riscv_program_fence(&program32); - riscv_program_ebreak(&program32); - COMPLIANCE_TEST(riscv_program_exec(&program32, target) == ERROR_OK, - "Accessing DSCRATCH with program buffer should succeed."); - COMPLIANCE_TEST(register_read_direct(target, &testval_read, GDB_REGNO_S1) == ERROR_OK, - "Need to be able to read S1 in order to test DSCRATCH."); - if (riscv_xlen(target) > 32) { - COMPLIANCE_TEST(testval == testval_read, - "All DSCRATCH registers in HARTINFO must be R/W."); - } else { - COMPLIANCE_TEST(testval_read == (testval & 0xFFFFFFFF), - "All DSCRATCH registers in HARTINFO must be R/W."); - } - } - } - } - /* TODO: dataaccess */ - if (get_field(hartinfo, DMI_HARTINFO_DATAACCESS)) { - /* TODO: Shadowed in memory map. */ - /* TODO: datasize */ - /* TODO: dataaddr */ - } else { - /* TODO: Shadowed in CSRs. */ - /* TODO: datasize */ - /* TODO: dataaddr */ - } - - } - - /* HALTSUM -- TODO: More than 32 harts. Would need to loop over this to set hartsel */ - /* TODO: HALTSUM2, HALTSUM3 */ - /* HALTSUM0 */ - uint32_t expected_haltsum0 = 0; - for (int i = 0; i < MIN(riscv_count_harts(target), 32); i++) - expected_haltsum0 |= (1 << i); - - COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM0); - COMPLIANCE_TEST(testvar_read == expected_haltsum0, - "HALTSUM0 should report summary of up to 32 halted harts"); - - COMPLIANCE_WRITE(target, DMI_HALTSUM0, 0xffffffff); - COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM0); - COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O"); - - COMPLIANCE_WRITE(target, DMI_HALTSUM0, 0x0); - COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM0); - COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O"); - - /* HALTSUM1 */ - uint32_t expected_haltsum1 = 0; - for (int i = 0; i < MIN(riscv_count_harts(target), 1024); i += 32) - expected_haltsum1 |= (1 << (i/32)); - - COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM1); - COMPLIANCE_TEST(testvar_read == expected_haltsum1, - "HALTSUM1 should report summary of up to 1024 halted harts"); - - COMPLIANCE_WRITE(target, DMI_HALTSUM1, 0xffffffff); - COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM1); - COMPLIANCE_TEST(testvar_read == expected_haltsum1, "HALTSUM1 should be R/O"); - - COMPLIANCE_WRITE(target, DMI_HALTSUM1, 0x0); - COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM1); - COMPLIANCE_TEST(testvar_read == expected_haltsum1, "HALTSUM1 should be R/O"); - - /* TODO: HAWINDOWSEL */ - - /* TODO: HAWINDOW */ - - /* ABSTRACTCS */ - - uint32_t abstractcs; - COMPLIANCE_READ(target, &abstractcs, DMI_ABSTRACTCS); - - /* Check that all reported Data Words are really R/W */ - for (int invert = 0; invert < 2; invert++) { - for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) { - testvar = (i + 1) * 0x11111111; - if (invert) - testvar = ~testvar; - COMPLIANCE_WRITE(target, DMI_DATA0 + i, testvar); - } - for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) { - testvar = (i + 1) * 0x11111111; - if (invert) - testvar = ~testvar; - COMPLIANCE_READ(target, &testvar_read, DMI_DATA0 + i); - COMPLIANCE_TEST(testvar_read == testvar, "All reported DATA words must be R/W"); - } - } - - /* Check that all reported ProgBuf words are really R/W */ - for (int invert = 0; invert < 2; invert++) { - for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) { - testvar = (i + 1) * 0x11111111; - if (invert) - testvar = ~testvar; - COMPLIANCE_WRITE(target, DMI_PROGBUF0 + i, testvar); - } - for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) { - testvar = (i + 1) * 0x11111111; - if (invert) - testvar = ~testvar; - COMPLIANCE_READ(target, &testvar_read, DMI_PROGBUF0 + i); - COMPLIANCE_TEST(testvar_read == testvar, "All reported PROGBUF words must be R/W"); - } - } - - /* TODO: Cause and clear all error types */ - - /* COMMAND - According to the spec, this register is only W, so can't really check the read result. - But at any rate, this is not legal and should cause an error. */ - COMPLIANCE_WRITE(target, DMI_COMMAND, 0xAAAAAAAA); - COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS); - COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, - "Illegal COMMAND should result in UNSUPPORTED"); - COMPLIANCE_WRITE(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); - - COMPLIANCE_WRITE(target, DMI_COMMAND, 0x55555555); - COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS); - COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, - "Illegal COMMAND should result in UNSUPPORTED"); - COMPLIANCE_WRITE(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); - - /* Basic Abstract Commands */ - for (unsigned int i = 1; i < 32; i = i << 1) { - riscv_reg_t testval = i | ((i + 1ULL) << 32); - riscv_reg_t testval_read; - COMPLIANCE_TEST(ERROR_OK == register_write_direct(target, GDB_REGNO_ZERO + i, testval), - "GPR Writes should be supported."); - COMPLIANCE_MUST_PASS(write_abstract_arg(target, 0, 0xDEADBEEFDEADBEEF, 64)); - COMPLIANCE_TEST(ERROR_OK == register_read_direct(target, &testval_read, GDB_REGNO_ZERO + i), - "GPR Reads should be supported."); - if (riscv_xlen(target) > 32) { - /* Dummy comment to satisfy linter, since removing the branches here doesn't actually compile. */ - COMPLIANCE_TEST(testval == testval_read, "GPR Reads and writes should be supported."); - } else { - /* Dummy comment to satisfy linter, since removing the branches here doesn't actually compile. */ - COMPLIANCE_TEST((testval & 0xFFFFFFFF) == testval_read, "GPR Reads and writes should be supported."); - } - } - - /* ABSTRACTAUTO - See which bits are actually writable */ - COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); - uint32_t abstractauto; - uint32_t busy; - COMPLIANCE_READ(target, &abstractauto, DMI_ABSTRACTAUTO); - COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0x0); - if (abstractauto > 0) { - /* This mechanism only works when you have a reasonable sized progbuf, which is not - a true compliance requirement. */ - if (info->progbufsize >= 3) { - - testvar = 0; - COMPLIANCE_TEST(ERROR_OK == register_write_direct(target, GDB_REGNO_S0, 0), - "Need to be able to write S0 to test ABSTRACTAUTO"); - struct riscv_program program; - COMPLIANCE_MUST_PASS(riscv_program_init(&program, target)); - /* This is also testing that WFI() is a NOP during debug mode. */ - COMPLIANCE_MUST_PASS(riscv_program_insert(&program, wfi())); - COMPLIANCE_MUST_PASS(riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, 1)); - COMPLIANCE_MUST_PASS(riscv_program_ebreak(&program)); - COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0x0); - COMPLIANCE_MUST_PASS(riscv_program_exec(&program, target)); - testvar++; - COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); - COMPLIANCE_READ(target, &abstractauto, DMI_ABSTRACTAUTO); - uint32_t autoexec_data = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECDATA); - uint32_t autoexec_progbuf = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF); - for (unsigned int i = 0; i < 12; i++) { - COMPLIANCE_READ(target, &testvar_read, DMI_DATA0 + i); - do { - COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS); - busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); - } while (busy); - if (autoexec_data & (1 << i)) { - COMPLIANCE_TEST(i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT), - "AUTOEXEC may be writable up to DATACOUNT bits."); - testvar++; - } - } - for (unsigned int i = 0; i < 16; i++) { - COMPLIANCE_READ(target, &testvar_read, DMI_PROGBUF0 + i); - do { - COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS); - busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); - } while (busy); - if (autoexec_progbuf & (1 << i)) { - COMPLIANCE_TEST(i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE), - "AUTOEXEC may be writable up to PROGBUFSIZE bits."); - testvar++; - } - } - - COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0); - COMPLIANCE_TEST(ERROR_OK == register_read_direct(target, &value, GDB_REGNO_S0), - "Need to be able to read S0 to test ABSTRACTAUTO"); - - COMPLIANCE_TEST(testvar == value, - "ABSTRACTAUTO should cause COMMAND to run the expected number of times."); - } - } - - /* Single-Step each hart. */ - for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) { - COMPLIANCE_MUST_PASS(riscv_set_current_hartid(target, hartsel)); - COMPLIANCE_MUST_PASS(riscv013_on_step(target)); - COMPLIANCE_MUST_PASS(riscv013_step_current_hart(target)); - COMPLIANCE_TEST(riscv_halt_reason(target, hartsel) == RISCV_HALT_SINGLESTEP, - "Single Step should result in SINGLESTEP"); - } - - /* Core Register Tests */ - uint64_t bogus_dpc = 0xdeadbeef; - for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) { - COMPLIANCE_MUST_PASS(riscv_set_current_hartid(target, hartsel)); - - /* DCSR Tests */ - COMPLIANCE_MUST_PASS(register_write_direct(target, GDB_REGNO_DCSR, 0x0)); - COMPLIANCE_MUST_PASS(register_read_direct(target, &value, GDB_REGNO_DCSR)); - COMPLIANCE_TEST(value != 0, "Not all bits in DCSR are writable by Debugger"); - COMPLIANCE_MUST_PASS(register_write_direct(target, GDB_REGNO_DCSR, 0xFFFFFFFF)); - COMPLIANCE_MUST_PASS(register_read_direct(target, &value, GDB_REGNO_DCSR)); - COMPLIANCE_TEST(value != 0, "At least some bits in DCSR must be 1"); - - /* DPC. Note that DPC is sign-extended. */ - riscv_reg_t dpcmask = 0xFFFFFFFCUL; - riscv_reg_t dpc; - - if (riscv_xlen(target) > 32) - dpcmask |= (0xFFFFFFFFULL << 32); - - if (riscv_supports_extension(target, riscv_current_hartid(target), 'C')) - dpcmask |= 0x2; - - COMPLIANCE_MUST_PASS(register_write_direct(target, GDB_REGNO_DPC, dpcmask)); - COMPLIANCE_MUST_PASS(register_read_direct(target, &dpc, GDB_REGNO_DPC)); - COMPLIANCE_TEST(dpcmask == dpc, - "DPC must be sign-extended to XLEN and writable to all-1s (except the least significant bits)"); - COMPLIANCE_MUST_PASS(register_write_direct(target, GDB_REGNO_DPC, 0)); - COMPLIANCE_MUST_PASS(register_read_direct(target, &dpc, GDB_REGNO_DPC)); - COMPLIANCE_TEST(dpc == 0, "DPC must be writable to 0."); - if (hartsel == 0) - bogus_dpc = dpc; /* For a later test step */ - } - - /* NDMRESET - Asserting non-debug module reset should not reset Debug Module state. - But it should reset Hart State, e.g. DPC should get a different value. - Also make sure that DCSR reports cause of 'HALT' even though previously we single-stepped. - */ - - /* Write some registers. They should not be impacted by ndmreset. */ - COMPLIANCE_WRITE(target, DMI_COMMAND, 0xFFFFFFFF); - - for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) { - testvar = (i + 1) * 0x11111111; - COMPLIANCE_WRITE(target, DMI_PROGBUF0 + i, testvar); - } - - for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) { - testvar = (i + 1) * 0x11111111; - COMPLIANCE_WRITE(target, DMI_DATA0 + i, testvar); - } - - COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); - COMPLIANCE_READ(target, &abstractauto, DMI_ABSTRACTAUTO); - - /* Pulse reset. */ - target->reset_halt = true; - COMPLIANCE_MUST_PASS(riscv_set_current_hartid(target, 0)); - COMPLIANCE_TEST(ERROR_OK == assert_reset(target), "Must be able to assert NDMRESET"); - COMPLIANCE_TEST(ERROR_OK == deassert_reset(target), "Must be able to deassert NDMRESET"); - - /* Verify that most stuff is not affected by ndmreset. */ - COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS); - COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, - "NDMRESET should not affect DMI_ABSTRACTCS"); - COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTAUTO); - COMPLIANCE_TEST(testvar_read == abstractauto, "NDMRESET should not affect DMI_ABSTRACTAUTO"); - - /* Clean up to avoid future test failures */ - COMPLIANCE_WRITE(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); - COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0); - - for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) { - testvar = (i + 1) * 0x11111111; - COMPLIANCE_READ(target, &testvar_read, DMI_PROGBUF0 + i); - COMPLIANCE_TEST(testvar_read == testvar, "PROGBUF words must not be affected by NDMRESET"); - } - - for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) { - testvar = (i + 1) * 0x11111111; - COMPLIANCE_READ(target, &testvar_read, DMI_DATA0 + i); - COMPLIANCE_TEST(testvar_read == testvar, "DATA words must not be affected by NDMRESET"); - } - - /* Verify that DPC *is* affected by ndmreset. Since we don't know what it *should* be, - just verify that at least it's not the bogus value anymore. */ - - COMPLIANCE_TEST(bogus_dpc != 0xdeadbeef, "BOGUS DPC should have been set somehow (bug in compliance test)"); - COMPLIANCE_MUST_PASS(register_read_direct(target, &value, GDB_REGNO_DPC)); - COMPLIANCE_TEST(bogus_dpc != value, "NDMRESET should move DPC to reset value."); - - COMPLIANCE_TEST(riscv_halt_reason(target, 0) == RISCV_HALT_INTERRUPT, - "After NDMRESET halt, DCSR should report cause of halt"); - - /* DMACTIVE -- deasserting DMACTIVE should reset all the above values. */ - - /* Toggle dmactive */ - COMPLIANCE_WRITE(target, DMI_DMCONTROL, 0); - COMPLIANCE_WRITE(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); - COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS); - COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0, "ABSTRACTCS.cmderr should reset to 0"); - COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTAUTO); - COMPLIANCE_TEST(testvar_read == 0, "ABSTRACTAUTO should reset to 0"); - - for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) { - COMPLIANCE_READ(target, &testvar_read, DMI_PROGBUF0 + i); - COMPLIANCE_TEST(testvar_read == 0, "PROGBUF words should reset to 0"); - } - - for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) { - COMPLIANCE_READ(target, &testvar_read, DMI_DATA0 + i); - COMPLIANCE_TEST(testvar_read == 0, "DATA words should reset to 0"); - } - - /* - * TODO: - * DCSR.cause priorities - * DCSR.stoptime/stopcycle - * DCSR.stepie - * DCSR.ebreak - * DCSR.prv - */ - - /* Halt every hart for any follow-up tests*/ - COMPLIANCE_MUST_PASS(riscv_halt_all_harts(target)); - - uint32_t failed_tests = total_tests - passed_tests; - if (total_tests == passed_tests) { - LOG_INFO("ALL TESTS PASSED\n"); - return ERROR_OK; - } else { - LOG_INFO("%d TESTS FAILED\n", failed_tests); - return ERROR_FAIL; - } + dmi_write(target, DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR); } diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index de2f095be2..9cd4922d20 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #include <assert.h> #include <stdlib.h> #include <time.h> @@ -6,65 +8,24 @@ #include "config.h" #endif +#include <helper/log.h> +#include <helper/time_support.h> #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" -#include "log.h" +#include <target/smp.h> #include "jtag/jtag.h" #include "target/register.h" #include "target/breakpoints.h" -#include "helper/time_support.h" #include "riscv.h" #include "gdb_regs.h" #include "rtos/rtos.h" - -/** - * Since almost everything can be accomplish by scanning the dbus register, all - * functions here assume dbus is already selected. The exception are functions - * called directly by OpenOCD, which can't assume anything about what's - * currently in IR. They should set IR to dbus explicitly. - */ - -/** - * Code structure - * - * At the bottom of the stack are the OpenOCD JTAG functions: - * jtag_add_[id]r_scan - * jtag_execute_query - * jtag_add_runtest - * - * There are a few functions to just instantly shift a register and get its - * value: - * dtmcontrol_scan - * idcode_scan - * dbus_scan - * - * Because doing one scan and waiting for the result is slow, most functions - * batch up a bunch of dbus writes and then execute them all at once. They use - * the scans "class" for this: - * scans_new - * scans_delete - * scans_execute - * scans_add_... - * Usually you new(), call a bunch of add functions, then execute() and look - * at the results by calling scans_get...() - * - * Optimized functions will directly use the scans class above, but slightly - * lazier code will use the cache functions that in turn use the scans - * functions: - * cache_get... - * cache_set... - * cache_write - * cache_set... update a local structure, which is then synced to the target - * with cache_write(). Only Debug RAM words that are actually changed are sent - * to the target. Afterwards use cache_get... to read results. - */ +#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))) -#define DIM(x) (sizeof(x)/sizeof(*x)) - /* Constants for legacy SiFive hardware breakpoints. */ #define CSR_BPCONTROL_X (1<<0) #define CSR_BPCONTROL_W (1<<1) @@ -108,12 +69,6 @@ typedef enum { #define DBUS_DATA_SIZE 34 #define DBUS_ADDRESS_START 36 -typedef enum { - RE_OK, - RE_FAIL, - RE_AGAIN -} riscv_error_t; - typedef enum slot { SLOT0, SLOT1, @@ -154,22 +109,87 @@ typedef enum slot { #define MAX_HWBPS 16 #define DRAM_CACHE_SIZE 16 -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 }; +static bscan_tunnel_type_t bscan_tunnel_type; +int bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */ + +static const uint8_t bscan_zero[4] = {0}; +static const uint8_t bscan_one[4] = {1}; + +static uint8_t ir_user4[4]; +static struct scan_field select_user4 = { + .in_value = NULL, + .out_value = ir_user4 +}; + + +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, + .in_value = NULL, + }, + { + .num_bits = 5, /* initialized in riscv_init_target to ir width of DM */ + .out_value = ir_dbus, + .in_value = NULL, + }, + { + .num_bits = 7, + .out_value = bscan_tunneled_ir_width, + .in_value = NULL, + }, + { + .num_bits = 1, + .out_value = bscan_zero, + .in_value = NULL, + } +}; + +static struct scan_field _bscan_tunnel_nested_tap_select_dmi[] = { + { + .num_bits = 1, + .out_value = bscan_zero, + .in_value = NULL, + }, + { + .num_bits = 7, + .out_value = bscan_tunneled_ir_width, + .in_value = NULL, + }, + { + .num_bits = 0, /* initialized in riscv_init_target to ir width of DM */ + .out_value = ir_dbus, + .in_value = NULL, + }, + { + .num_bits = 3, + .out_value = bscan_zero, + .in_value = NULL, + } +}; +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); + +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; @@ -185,19 +205,174 @@ 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_prefer_sba; +static bool riscv_enable_virt2phys = true; +bool riscv_ebreakm = true; +bool riscv_ebreaks = true; +bool riscv_ebreaku = true; + +bool riscv_enable_virtual; + +static enum { + RO_NORMAL, + RO_REVERSED +} resume_order; + +static const virt2phys_info_t sv32 = { + .name = "Sv32", + .va_bits = 32, + .level = 2, + .pte_shift = 2, + .vpn_shift = {12, 22}, + .vpn_mask = {0x3ff, 0x3ff}, + .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, + .pte_shift = 3, + .vpn_shift = {12, 21, 30}, + .vpn_mask = {0x1ff, 0x1ff, 0x1ff}, + .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, + .pte_shift = 3, + .vpn_shift = {12, 21, 30, 39}, + .vpn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ff}, + .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 enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid); +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; + if (r->sample_buf.used + 5 < r->sample_buf.size) { + if (before) + r->sample_buf.buf[r->sample_buf.used++] = RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE; + else + r->sample_buf.buf[r->sample_buf.used++] = RISCV_SAMPLE_BUF_TIMESTAMP_AFTER; + r->sample_buf.buf[r->sample_buf.used++] = now & 0xff; + r->sample_buf.buf[r->sample_buf.used++] = (now >> 8) & 0xff; + r->sample_buf.buf[r->sample_buf.used++] = (now >> 16) & 0xff; + r->sample_buf.buf[r->sample_buf.used++] = (now >> 24) & 0xff; + } +} + +static int riscv_resume_go_all_harts(struct target *target); + +void select_dmi_via_bscan(struct target *target) +{ + jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE); + if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) + jtag_add_dr_scan(target->tap, bscan_tunnel_data_register_select_dmi_num_fields, + bscan_tunnel_data_register_select_dmi, TAP_IDLE); + else /* BSCAN_TUNNEL_NESTED_TAP */ + jtag_add_dr_scan(target->tap, bscan_tunnel_nested_tap_select_dmi_num_fields, + bscan_tunnel_nested_tap_select_dmi, TAP_IDLE); +} + +uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out) +{ + /* 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}; + uint8_t tunneled_dr_width[4] = {32}; + uint8_t out_value[5] = {0}; + uint8_t in_value[5] = {0}; + + buf_set_u32(out_value, 0, 32, out); + struct scan_field tunneled_ir[4] = {}; + struct scan_field tunneled_dr[4] = {}; + + if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) { + tunneled_ir[0].num_bits = 3; + tunneled_ir[0].out_value = bscan_zero; + tunneled_ir[0].in_value = NULL; + tunneled_ir[1].num_bits = bscan_tunnel_ir_width; + tunneled_ir[1].out_value = ir_dtmcontrol; + tunneled_ir[1].in_value = NULL; + tunneled_ir[2].num_bits = 7; + tunneled_ir[2].out_value = tunneled_ir_width; + tunneled_ir[2].in_value = NULL; + tunneled_ir[3].num_bits = 1; + tunneled_ir[3].out_value = bscan_zero; + tunneled_ir[3].in_value = NULL; + + tunneled_dr[0].num_bits = 3; + tunneled_dr[0].out_value = bscan_zero; + tunneled_dr[0].in_value = NULL; + tunneled_dr[1].num_bits = 32 + 1; + tunneled_dr[1].out_value = out_value; + tunneled_dr[1].in_value = in_value; + tunneled_dr[2].num_bits = 7; + tunneled_dr[2].out_value = tunneled_dr_width; + tunneled_dr[2].in_value = NULL; + tunneled_dr[3].num_bits = 1; + tunneled_dr[3].out_value = bscan_one; + tunneled_dr[3].in_value = NULL; + } else { + /* BSCAN_TUNNEL_NESTED_TAP */ + tunneled_ir[3].num_bits = 3; + tunneled_ir[3].out_value = bscan_zero; + tunneled_ir[3].in_value = NULL; + tunneled_ir[2].num_bits = bscan_tunnel_ir_width; + tunneled_ir[2].out_value = ir_dtmcontrol; + tunneled_ir[1].in_value = NULL; + tunneled_ir[1].num_bits = 7; + tunneled_ir[1].out_value = tunneled_ir_width; + tunneled_ir[2].in_value = NULL; + tunneled_ir[0].num_bits = 1; + tunneled_ir[0].out_value = bscan_zero; + tunneled_ir[0].in_value = NULL; + + tunneled_dr[3].num_bits = 3; + tunneled_dr[3].out_value = bscan_zero; + tunneled_dr[3].in_value = NULL; + tunneled_dr[2].num_bits = 32 + 1; + tunneled_dr[2].out_value = out_value; + tunneled_dr[2].in_value = in_value; + tunneled_dr[1].num_bits = 7; + tunneled_dr[1].out_value = tunneled_dr_width; + tunneled_dr[1].in_value = NULL; + tunneled_dr[0].num_bits = 1; + tunneled_dr[0].out_value = bscan_one; + tunneled_dr[0].in_value = NULL; + } + jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE); + jtag_add_dr_scan(target->tap, ARRAY_SIZE(tunneled_ir), tunneled_ir, TAP_IDLE); + jtag_add_dr_scan(target->tap, ARRAY_SIZE(tunneled_dr), tunneled_dr, TAP_IDLE); + select_dmi_via_bscan(target); -typedef struct { - uint16_t low, high; -} range_t; + int retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("failed jtag scan: %d", retval); + return retval; + } + /* Note the starting offset is bit 1, not bit 0. In BSCAN tunnel, there is a one-bit TCK skew between + output and input */ + uint32_t in = buf_get_u32(in_value, 1, 32); + LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in); -/* In addition to the ones in the standard spec, we'll also expose additional - * CSRs in this list. - * The list is either NULL, or a series of ranges (inclusive), terminated with - * 1,0. */ -range_t *expose_csr; -/* Same, but for custom registers. */ -range_t *expose_custom; + return in; +} static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { @@ -205,6 +380,10 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) uint8_t in_value[4]; uint8_t out_value[4] = { 0 }; + if (bscan_tunnel_ir_width != 0) + return dtmcontrol_scan_via_bscan(target, out); + + buf_set_u32(out_value, 0, 32, out); jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); @@ -231,13 +410,12 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) static struct target_type *get_target_type(struct target *target) { - riscv_info_t *info = (riscv_info_t *) target->arch_info; - - if (!info) { + if (!target->arch_info) { LOG_ERROR("Target has not been initialized"); return NULL; } + RISCV_INFO(info); switch (info->dtm_version) { case 0: return &riscv011_target; @@ -249,21 +427,41 @@ static struct target_type *get_target_type(struct target *target) } } +static int riscv_create_target(struct target *target, Jim_Interp *interp) +{ + LOG_DEBUG("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."); + return ERROR_FAIL; + } + riscv_info_init(target, target->arch_info); + return ERROR_OK; +} + static int riscv_init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("riscv_init_target()"); - target->arch_info = calloc(1, sizeof(riscv_info_t)); - if (!target->arch_info) - return ERROR_FAIL; - riscv_info_t *info = (riscv_info_t *) target->arch_info; - riscv_info_init(target, info); + RISCV_INFO(info); info->cmd_ctx = cmd_ctx; select_dtmcontrol.num_bits = target->tap->ir_length; select_dbus.num_bits = target->tap->ir_length; select_idcode.num_bits = target->tap->ir_length; + if (bscan_tunnel_ir_width != 0) { + assert(target->tap->ir_length >= 6); + uint32_t ir_user4_raw = 0x23 << (target->tap->ir_length - 6); + 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) + bscan_tunnel_data_register_select_dmi[1].num_bits = bscan_tunnel_ir_width; + else /* BSCAN_TUNNEL_NESTED_TAP */ + bscan_tunnel_nested_tap_select_dmi[2].num_bits = bscan_tunnel_ir_width; + } + riscv_semihosting_init(target); target->debug_reason = DBG_REASON_DBGRQ; @@ -280,6 +478,8 @@ static void riscv_free_registers(struct target *target) /* Free the ones we allocated separately. */ for (unsigned i = GDB_REGNO_COUNT; i < target->reg_cache->num_regs; i++) free(target->reg_cache->reg_list[i].arch_info); + for (unsigned int i = 0; i < target->reg_cache->num_regs; i++) + free(target->reg_cache->reg_list[i].value); free(target->reg_cache->reg_list); } free(target->reg_cache); @@ -289,23 +489,33 @@ static void riscv_free_registers(struct target *target) static void riscv_deinit_target(struct target *target) { LOG_DEBUG("riscv_deinit_target()"); + + struct riscv_info *info = target->arch_info; struct target_type *tt = get_target_type(target); - if (tt) { + + if (tt && info && info->version_specific) tt->deinit_target(target); - riscv_info_t *info = (riscv_info_t *) target->arch_info; - free(info->reg_names); - free(info); - } riscv_free_registers(target); - target->arch_info = NULL; -} + if (!info) + return; -static int oldriscv_halt(struct target *target) -{ - struct target_type *tt = get_target_type(target); - return tt->halt(target); + range_list_t *entry, *tmp; + list_for_each_entry_safe(entry, tmp, &info->expose_csr, list) { + free(entry->name); + free(entry); + } + + list_for_each_entry_safe(entry, tmp, &info->expose_custom, list) { + free(entry->name); + free(entry); + } + + free(info->reg_names); + free(target->arch_info); + + target->arch_info = NULL; } static void trigger_from_breakpoint(struct trigger *trigger, @@ -321,7 +531,7 @@ static void trigger_from_breakpoint(struct trigger *trigger, trigger->unique_id = breakpoint->unique_id; } -static int maybe_add_trigger_t1(struct target *target, unsigned hartid, +static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger, uint64_t tdata1) { RISCV_INFO(r); @@ -345,20 +555,19 @@ static int maybe_add_trigger_t1(struct target *target, unsigned hartid, tdata1 = set_field(tdata1, bpcontrol_w, trigger->write); tdata1 = set_field(tdata1, bpcontrol_x, trigger->execute); tdata1 = set_field(tdata1, bpcontrol_u, - !!(r->misa[hartid] & (1 << ('U' - 'A')))); + !!(r->misa & BIT('U' - 'A'))); tdata1 = set_field(tdata1, bpcontrol_s, - !!(r->misa[hartid] & (1 << ('S' - 'A')))); + !!(r->misa & BIT('S' - 'A'))); tdata1 = set_field(tdata1, bpcontrol_h, - !!(r->misa[hartid] & (1 << ('H' - 'A')))); + !!(r->misa & BIT('H' - 'A'))); tdata1 |= bpcontrol_m; tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */ tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */ - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, tdata1); + riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); riscv_reg_t tdata1_rb; - if (riscv_get_register_on_hart(target, &tdata1_rb, hartid, - GDB_REGNO_TDATA1) != ERROR_OK) + if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK) return ERROR_FAIL; LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); @@ -366,16 +575,16 @@ static int maybe_add_trigger_t1(struct target *target, unsigned hartid, 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_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); + riscv_set_register(target, GDB_REGNO_TDATA1, 0); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA2, trigger->address); + riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); return ERROR_OK; } -static int maybe_add_trigger_t2(struct target *target, unsigned hartid, +static int maybe_add_trigger_t2(struct target *target, struct trigger *trigger, uint64_t tdata1) { RISCV_INFO(r); @@ -392,11 +601,9 @@ static int maybe_add_trigger_t2(struct target *target, unsigned hartid, MCONTROL_ACTION_DEBUG_MODE); tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL); tdata1 |= MCONTROL_M; - if (r->misa[hartid] & (1 << ('H' - 'A'))) - tdata1 |= MCONTROL_H; - if (r->misa[hartid] & (1 << ('S' - 'A'))) + if (r->misa & (1 << ('S' - 'A'))) tdata1 |= MCONTROL_S; - if (r->misa[hartid] & (1 << ('U' - 'A'))) + if (r->misa & (1 << ('U' - 'A'))) tdata1 |= MCONTROL_U; if (trigger->execute) @@ -406,10 +613,10 @@ static int maybe_add_trigger_t2(struct target *target, unsigned hartid, if (trigger->write) tdata1 |= MCONTROL_STORE; - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, tdata1); + riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); uint64_t tdata1_rb; - int result = riscv_get_register_on_hart(target, &tdata1_rb, hartid, GDB_REGNO_TDATA1); + int result = riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1); if (result != ERROR_OK) return result; LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); @@ -418,77 +625,103 @@ static int maybe_add_trigger_t2(struct target *target, unsigned hartid, 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_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); + riscv_set_register(target, GDB_REGNO_TDATA1, 0); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA2, trigger->address); + riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); return ERROR_OK; } -static int add_trigger(struct target *target, struct trigger *trigger) +static int maybe_add_trigger_t6(struct target *target, + struct trigger *trigger, uint64_t tdata1) { RISCV_INFO(r); - if (riscv_enumerate_triggers(target) != ERROR_OK) - return ERROR_FAIL; + /* 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; + } + + /* address/data match trigger */ + tdata1 |= MCONTROL_DMODE(riscv_xlen(target)); + tdata1 = set_field(tdata1, CSR_MCONTROL6_ACTION, + MCONTROL_ACTION_DEBUG_MODE); + tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, MCONTROL_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; - /* In RTOS mode, we need to set the same trigger in the same slot on every - * hart, to keep up the illusion that each hart is a thread running on the - * same core. */ + if (trigger->execute) + tdata1 |= CSR_MCONTROL6_EXECUTE; + if (trigger->read) + tdata1 |= CSR_MCONTROL6_LOAD; + if (trigger->write) + tdata1 |= CSR_MCONTROL6_STORE; - /* Otherwise, we just set the trigger on the one hart this target deals - * with. */ + riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); - riscv_reg_t tselect[RISCV_MAX_HARTS]; + 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); - int first_hart = -1; - for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) { - if (!riscv_hart_enabled(target, hartid)) - continue; - if (first_hart < 0) - first_hart = hartid; - int result = riscv_get_register_on_hart(target, &tselect[hartid], - hartid, GDB_REGNO_TSELECT); - if (result != ERROR_OK) - return result; + 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; } - assert(first_hart >= 0); + + riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); + + return ERROR_OK; +} + +static int add_trigger(struct target *target, struct trigger *trigger) +{ + RISCV_INFO(r); + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + riscv_reg_t tselect; + if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) + return ERROR_FAIL; unsigned int i; - for (i = 0; i < r->trigger_count[first_hart]; i++) { + for (i = 0; i < r->trigger_count; i++) { if (r->trigger_unique_id[i] != -1) continue; - riscv_set_register_on_hart(target, first_hart, GDB_REGNO_TSELECT, i); + riscv_set_register(target, GDB_REGNO_TSELECT, i); uint64_t tdata1; - int result = riscv_get_register_on_hart(target, &tdata1, first_hart, - GDB_REGNO_TDATA1); + int result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1); if (result != ERROR_OK) return result; int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); - result = ERROR_OK; - for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) { - if (!riscv_hart_enabled(target, hartid)) - continue; - if (hartid > first_hart) - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, i); - switch (type) { - case 1: - result = maybe_add_trigger_t1(target, hartid, trigger, tdata1); - break; - case 2: - result = maybe_add_trigger_t2(target, hartid, trigger, tdata1); - break; - default: - LOG_DEBUG("trigger %d has unknown type %d", i, type); - continue; - } - - if (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; } @@ -501,14 +734,9 @@ static int add_trigger(struct target *target, struct trigger *trigger) break; } - for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) { - if (!riscv_hart_enabled(target, hartid)) - continue; - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, - tselect[hartid]); - } + riscv_set_register(target, GDB_REGNO_TSELECT, tselect); - if (i >= r->trigger_count[first_hart]) { + if (i >= r->trigger_count) { LOG_ERROR("Couldn't find an available hardware trigger."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -516,7 +744,125 @@ static int add_trigger(struct target *target, struct trigger *trigger) return ERROR_OK; } -int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) +/** + * Write one memory item of given "size". Use memory access of given "access_size". + * Utilize read-modify-write, if needed. + * */ +static int write_by_given_size(struct target *target, target_addr_t address, + uint32_t size, uint8_t *buffer, uint32_t access_size) +{ + assert(size == 1 || size == 2 || size == 4 || size == 8); + assert(access_size == 1 || access_size == 2 || access_size == 4 || access_size == 8); + + if (access_size <= size && address % access_size == 0) + /* Can do the memory access directly without a helper buffer. */ + return target_write_memory(target, address, access_size, size / access_size, buffer); + + unsigned int offset_head = address % access_size; + unsigned int n_blocks = ((size + offset_head) <= access_size) ? 1 : 2; + uint8_t helper_buf[n_blocks * access_size]; + + /* Read from memory */ + if (target_read_memory(target, address - offset_head, access_size, n_blocks, helper_buf) != ERROR_OK) + return ERROR_FAIL; + + /* Modify and write back */ + memcpy(helper_buf + offset_head, buffer, size); + return target_write_memory(target, address - offset_head, access_size, n_blocks, helper_buf); +} + +/** + * Read one memory item of given "size". Use memory access of given "access_size". + * Read larger section of memory and pick out the required portion, if needed. + * */ +static int read_by_given_size(struct target *target, target_addr_t address, + uint32_t size, uint8_t *buffer, uint32_t access_size) +{ + assert(size == 1 || size == 2 || size == 4 || size == 8); + assert(access_size == 1 || access_size == 2 || access_size == 4 || access_size == 8); + + if (access_size <= size && address % access_size == 0) + /* Can do the memory access directly without a helper buffer. */ + return target_read_memory(target, address, access_size, size / access_size, buffer); + + unsigned int offset_head = address % access_size; + unsigned int n_blocks = ((size + offset_head) <= access_size) ? 1 : 2; + uint8_t helper_buf[n_blocks * access_size]; + + /* Read from memory */ + if (target_read_memory(target, address - offset_head, access_size, n_blocks, helper_buf) != ERROR_OK) + return ERROR_FAIL; + + /* Pick the requested portion from the buffer */ + memcpy(buffer, helper_buf + offset_head, size); + return ERROR_OK; +} + +/** + * Write one memory item using any memory access size that will work. + * Utilize read-modify-write, if needed. + * */ +int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) +{ + assert(size == 1 || size == 2 || size == 4 || size == 8); + + /* Find access size that correspond to data size and the alignment. */ + unsigned int preferred_size = size; + while (address % preferred_size != 0) + preferred_size /= 2; + + /* First try the preferred (most natural) access size. */ + if (write_by_given_size(target, address, size, buffer, preferred_size) == ERROR_OK) + return ERROR_OK; + + /* On failure, try other access sizes. + Minimize the number of accesses by trying first the largest size. */ + for (unsigned int access_size = 8; access_size > 0; access_size /= 2) { + if (access_size == preferred_size) + /* Already tried this size. */ + continue; + + if (write_by_given_size(target, address, size, buffer, access_size) == ERROR_OK) + return ERROR_OK; + } + + /* No access attempt succeeded. */ + return ERROR_FAIL; +} + +/** + * Read one memory item using any memory access size that will work. + * Read larger section of memory and pick out the required portion, if needed. + * */ +int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) +{ + assert(size == 1 || size == 2 || size == 4 || size == 8); + + /* Find access size that correspond to data size and the alignment. */ + unsigned int preferred_size = size; + while (address % preferred_size != 0) + preferred_size /= 2; + + /* First try the preferred (most natural) access size. */ + if (read_by_given_size(target, address, size, buffer, preferred_size) == ERROR_OK) + return ERROR_OK; + + /* On failure, try other access sizes. + Minimize the number of accesses by trying first the largest size. */ + for (unsigned int access_size = 8; access_size > 0; access_size /= 2) { + if (access_size == preferred_size) + /* Already tried this size. */ + continue; + + if (read_by_given_size(target, address, size, buffer, access_size) == ERROR_OK) + return ERROR_OK; + } + + /* No access attempt succeeded. */ + return ERROR_FAIL; +} + +static int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { LOG_DEBUG("[%d] @0x%" TARGET_PRIxADDR, target->coreid, breakpoint->address); assert(breakpoint); @@ -532,8 +878,9 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) return ERROR_FAIL; } - if (target_read_memory(target, breakpoint->address, 2, breakpoint->length / 2, - breakpoint->orig_instr) != ERROR_OK) { + /* 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, breakpoint->address); return ERROR_FAIL; @@ -541,9 +888,8 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) uint8_t buff[4] = { 0 }; buf_set_u32(buff, 0, breakpoint->length * CHAR_BIT, breakpoint->length == 4 ? ebreak() : ebreak_c()); - int const retval = target_write_memory(target, breakpoint->address, 2, breakpoint->length / 2, buff); - - if (retval != ERROR_OK) { + /* 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%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); return ERROR_FAIL; @@ -560,7 +906,7 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = true; + breakpoint->is_set = true; return ERROR_OK; } @@ -571,51 +917,38 @@ static int remove_trigger(struct target *target, struct trigger *trigger) if (riscv_enumerate_triggers(target) != ERROR_OK) return ERROR_FAIL; - int first_hart = -1; - for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) { - if (!riscv_hart_enabled(target, hartid)) - continue; - if (first_hart < 0) { - first_hart = hartid; - break; - } - } - assert(first_hart >= 0); - unsigned int i; - for (i = 0; i < r->trigger_count[first_hart]; i++) { + for (i = 0; i < r->trigger_count; i++) { if (r->trigger_unique_id[i] == trigger->unique_id) break; } - if (i >= r->trigger_count[first_hart]) { + if (i >= r->trigger_count) { LOG_ERROR("Couldn't find the hardware resources used by hardware " "trigger."); return ERROR_FAIL; } LOG_DEBUG("[%d] Stop using resource %d for bp %d", target->coreid, i, trigger->unique_id); - for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) { - if (!riscv_hart_enabled(target, hartid)) - continue; - riscv_reg_t tselect; - int result = riscv_get_register_on_hart(target, &tselect, hartid, GDB_REGNO_TSELECT); - if (result != ERROR_OK) - return result; - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, i); - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, tselect); - } + + 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); + 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) { - if (target_write_memory(target, breakpoint->address, 2, breakpoint->length / 2, - breakpoint->orig_instr) != ERROR_OK) { + /* 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 " "0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); return ERROR_FAIL; @@ -633,7 +966,7 @@ int riscv_remove_breakpoint(struct target *target, return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = false; + breakpoint->is_set = false; return ERROR_OK; } @@ -660,7 +993,7 @@ int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint) int result = add_trigger(target, &trigger); if (result != ERROR_OK) return result; - watchpoint->set = true; + watchpoint->is_set = true; return ERROR_OK; } @@ -676,7 +1009,7 @@ int riscv_remove_watchpoint(struct target *target, int result = remove_trigger(target, &trigger); if (result != ERROR_OK) return result; - watchpoint->set = false; + watchpoint->is_set = false; return ERROR_OK; } @@ -687,7 +1020,7 @@ int riscv_remove_watchpoint(struct target *target, * 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) { struct watchpoint *wp = target->watchpoints; @@ -776,7 +1109,7 @@ static int old_or_new_riscv_step(struct target *target, int current, { RISCV_INFO(r); LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); - if (r->is_halted == NULL) + if (!r->is_halted) return oldriscv_step(target, current, address, handle_breakpoints); else return riscv_openocd_step(target, current, address, handle_breakpoints); @@ -793,14 +1126,14 @@ static int riscv_examine(struct target *target) /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ - riscv_info_t *info = (riscv_info_t *) target->arch_info; + RISCV_INFO(info); uint32_t dtmcontrol = dtmcontrol_scan(target, 0); LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); info->dtm_version = get_field(dtmcontrol, DTMCONTROL_VERSION); LOG_DEBUG(" version=0x%x", info->dtm_version); struct target_type *tt = get_target_type(target); - if (tt == NULL) + if (!tt) return ERROR_FAIL; int result = tt->init_target(info->cmd_ctx, target); @@ -819,112 +1152,617 @@ static int oldriscv_poll(struct target *target) static int old_or_new_riscv_poll(struct target *target) { RISCV_INFO(r); - if (r->is_halted == NULL) + if (!r->is_halted) return oldriscv_poll(target); else return riscv_openocd_poll(target); } -static int old_or_new_riscv_halt(struct target *target) -{ - RISCV_INFO(r); - if (r->is_halted == NULL) - return oldriscv_halt(target); - else - return riscv_openocd_halt(target); -} - -static int riscv_assert_reset(struct target *target) +int riscv_select_current_hart(struct target *target) { - LOG_DEBUG("[%d]", target->coreid); - struct target_type *tt = get_target_type(target); - riscv_invalidate_register_cache(target); - return tt->assert_reset(target); + return riscv_set_current_hartid(target, target->coreid); } -static int riscv_deassert_reset(struct target *target) +static int halt_prep(struct target *target) { - LOG_DEBUG("[%d]", target->coreid); - struct target_type *tt = get_target_type(target); - return tt->deassert_reset(target); -} + RISCV_INFO(r); + LOG_DEBUG("[%s] prep hart, debug_reason=%d", target_name(target), + target->debug_reason); + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + if (riscv_is_halted(target)) { + LOG_DEBUG("[%s] Hart is already halted (reason=%d).", + target_name(target), target->debug_reason); + } else { + if (r->halt_prep(target) != ERROR_OK) + return ERROR_FAIL; + r->prepped = true; + } -static int oldriscv_resume(struct target *target, int current, uint32_t address, - int handle_breakpoints, int debug_execution) -{ - struct target_type *tt = get_target_type(target); - return tt->resume(target, current, address, handle_breakpoints, - debug_execution); + return ERROR_OK; } -static int old_or_new_riscv_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int riscv_halt_go_all_harts(struct target *target) { - LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); - if (target->smp) { - struct target_list *targets = target->head; - int result = ERROR_OK; - while (targets) { - struct target *t = targets->target; - riscv_info_t *r = riscv_info(t); - if (r->is_halted == NULL) { - if (oldriscv_resume(t, current, address, handle_breakpoints, - debug_execution) != ERROR_OK) - result = ERROR_FAIL; - } else { - if (riscv_openocd_resume(t, current, address, - handle_breakpoints, debug_execution) != ERROR_OK) - result = ERROR_FAIL; - } - targets = targets->next; - } - return result; + RISCV_INFO(r); + + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + if (riscv_is_halted(target)) { + LOG_DEBUG("[%s] Hart is already halted.", target_name(target)); + } else { + if (r->halt_go(target) != ERROR_OK) + return ERROR_FAIL; } - RISCV_INFO(r); - if (r->is_halted == NULL) - return oldriscv_resume(target, current, address, handle_breakpoints, debug_execution); - else - return riscv_openocd_resume(target, current, address, handle_breakpoints, debug_execution); + riscv_invalidate_register_cache(target); + + return ERROR_OK; } -static int riscv_select_current_hart(struct target *target) +static int halt_go(struct target *target) { RISCV_INFO(r); - if (riscv_rtos_enabled(target)) { - if (r->rtos_hartid == -1) - r->rtos_hartid = target->rtos->current_threadid - 1; - return riscv_set_current_hartid(target, r->rtos_hartid); - } else - return riscv_set_current_hartid(target, target->coreid); + int result; + if (!r->is_halted) { + struct target_type *tt = get_target_type(target); + 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; + + return result; } -static int riscv_read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) +static int halt_finish(struct target *target) { - if (riscv_select_current_hart(target) != ERROR_OK) - return ERROR_FAIL; - struct target_type *tt = get_target_type(target); - return tt->read_memory(target, address, size, count, buffer); + return target_call_event_callbacks(target, TARGET_EVENT_HALTED); +} + +int riscv_halt(struct target *target) +{ + RISCV_INFO(r); + + if (!r->is_halted) { + struct target_type *tt = get_target_type(target); + return tt->halt(target); + } + + LOG_DEBUG("[%d] halting all harts", target->coreid); + + int result = ERROR_OK; + if (target->smp) { + struct target_list *tlist; + foreach_smp_target(tlist, target->smp_targets) { + struct target *t = tlist->target; + if (halt_prep(t) != ERROR_OK) + result = ERROR_FAIL; + } + + foreach_smp_target(tlist, target->smp_targets) { + struct target *t = tlist->target; + struct riscv_info *i = riscv_info(t); + if (i->prepped) { + if (halt_go(t) != ERROR_OK) + result = ERROR_FAIL; + } + } + + foreach_smp_target(tlist, target->smp_targets) { + struct target *t = tlist->target; + if (halt_finish(t) != ERROR_OK) + return ERROR_FAIL; + } + + } else { + if (halt_prep(target) != ERROR_OK) + result = ERROR_FAIL; + if (halt_go(target) != ERROR_OK) + result = ERROR_FAIL; + if (halt_finish(target) != ERROR_OK) + return ERROR_FAIL; + } + + return result; +} + +static int riscv_assert_reset(struct target *target) +{ + LOG_DEBUG("[%d]", target->coreid); + struct target_type *tt = get_target_type(target); + riscv_invalidate_register_cache(target); + return tt->assert_reset(target); +} + +static int riscv_deassert_reset(struct target *target) +{ + LOG_DEBUG("[%d]", target->coreid); + struct target_type *tt = get_target_type(target); + return tt->deassert_reset(target); +} + +static int riscv_resume_prep_all_harts(struct target *target) +{ + RISCV_INFO(r); + + LOG_DEBUG("[%s] prep hart", target_name(target)); + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + if (riscv_is_halted(target)) { + if (r->resume_prep(target) != ERROR_OK) + return ERROR_FAIL; + } else { + LOG_DEBUG("[%s] hart requested resume, but was already resumed", + target_name(target)); + } + + LOG_DEBUG("[%s] mark as prepped", target_name(target)); + r->prepped = true; + + return ERROR_OK; +} + +/* state must be riscv_reg_t state[RISCV_MAX_HWBPS] = {0}; */ +static int disable_triggers(struct target *target, riscv_reg_t *state) +{ + RISCV_INFO(r); + + LOG_DEBUG("deal with triggers"); + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + if (r->manual_hwbp_set) { + /* Look at every trigger that may have been set. */ + riscv_reg_t tselect; + if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) + return ERROR_FAIL; + for (unsigned int t = 0; t < r->trigger_count; t++) { + if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK) + return ERROR_FAIL; + riscv_reg_t tdata1; + if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + return ERROR_FAIL; + if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) { + state[t] = tdata1; + if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) + return ERROR_FAIL; + } + } + if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) + return ERROR_FAIL; + + } else { + /* Just go through the triggers we manage. */ + struct watchpoint *watchpoint = target->watchpoints; + int i = 0; + while (watchpoint) { + LOG_DEBUG("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) + return ERROR_FAIL; + } + watchpoint = watchpoint->next; + i++; + } + } + + return ERROR_OK; +} + +static int enable_triggers(struct target *target, riscv_reg_t *state) +{ + RISCV_INFO(r); + + if (r->manual_hwbp_set) { + /* Look at every trigger that may have been set. */ + riscv_reg_t tselect; + if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) + return ERROR_FAIL; + for (unsigned int t = 0; t < r->trigger_count; t++) { + if (state[t] != 0) { + if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK) + return ERROR_FAIL; + if (riscv_set_register(target, GDB_REGNO_TDATA1, state[t]) != ERROR_OK) + return ERROR_FAIL; + } + } + if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) + return ERROR_FAIL; + + } else { + struct watchpoint *watchpoint = target->watchpoints; + int i = 0; + while (watchpoint) { + LOG_DEBUG("watchpoint %d: cleared=%" PRId64, i, state[i]); + if (state[i]) { + if (riscv_add_watchpoint(target, watchpoint) != ERROR_OK) + return ERROR_FAIL; + } + watchpoint = watchpoint->next; + i++; + } + } + + return ERROR_OK; +} + +/** + * Get everything ready to resume. + */ +static int resume_prep(struct target *target, int current, + target_addr_t address, int handle_breakpoints, int debug_execution) +{ + RISCV_INFO(r); + LOG_DEBUG("[%d]", target->coreid); + + 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 (enable_triggers(target, trigger_state) != ERROR_OK) + return ERROR_FAIL; + } + + if (r->is_halted) { + if (riscv_resume_prep_all_harts(target) != ERROR_OK) + return ERROR_FAIL; + } + + LOG_DEBUG("[%d] mark as prepped", target->coreid); + r->prepped = true; + + return ERROR_OK; +} + +/** + * Resume all the harts that have been prepped, as close to instantaneous as + * possible. + */ +static int resume_go(struct target *target, int current, + target_addr_t address, int handle_breakpoints, int debug_execution) +{ + RISCV_INFO(r); + int result; + if (!r->is_halted) { + struct target_type *tt = get_target_type(target); + result = tt->resume(target, current, address, handle_breakpoints, + debug_execution); + } else { + result = riscv_resume_go_all_harts(target); + } + + return result; +} + +static int resume_finish(struct target *target) +{ + register_cache_invalidate(target->reg_cache); + + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + return target_call_event_callbacks(target, TARGET_EVENT_RESUMED); +} + +/** + * @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. + */ +static int riscv_resume( + struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution, + bool single_hart) +{ + LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); + int result = ERROR_OK; + 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, + debug_execution) != ERROR_OK) + result = ERROR_FAIL; + } + + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_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; + if (resume_finish(t) != ERROR_OK) + return 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) != 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) +{ + return riscv_resume(target, current, address, handle_breakpoints, + debug_execution, false); +} + +static int riscv_mmu(struct target *target, int *enabled) +{ + if (!riscv_enable_virt2phys) { + *enabled = 0; + 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."); + 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."); + return ERROR_FAIL; + } + + 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; + return ERROR_OK; + } + + riscv_reg_t satp; + if (riscv_get_register(target, &satp, GDB_REGNO_SATP) != ERROR_OK) { + LOG_DEBUG("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; + } else { + LOG_DEBUG("MMU is enabled."); + *enabled = 1; + } + + return ERROR_OK; +} + +static int riscv_address_translate(struct target *target, + 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; + + 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); + + /* 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 " + "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; + 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); + uint8_t buffer[8]; + assert(info->pte_shift <= 3); + int retval = r->read_memory(target, pte_address, + 4, (1 << info->pte_shift) / 4, buffer, 4); + if (retval != ERROR_OK) + return ERROR_FAIL; + + if (info->pte_shift == 2) + pte = buf_get_u32(buffer, 0, 32); + else + pte = buf_get_u64(buffer, 0, 64); + + LOG_DEBUG("i=%d; PTE @0x%" TARGET_PRIxADDR " = 0x%" PRIx64, i, + pte_address, pte); + + if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) + return ERROR_FAIL; + + if ((pte & PTE_R) || (pte & PTE_X)) /* Found leaf PTE. */ + break; + + i--; + if (i < 0) + break; + ppn_value = pte >> PTE_PPN_SHIFT; + table_address = ppn_value << RISCV_PGSHIFT; + } + + if (i < 0) { + LOG_ERROR("Couldn't find the PTE."); + return ERROR_FAIL; + } + + /* Make sure to clear out the high bits that may be set. */ + *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]; + *physical &= ~(((target_addr_t)info->pa_ppn_mask[i]) << + info->pa_ppn_shift[i]); + *physical |= (ppn_value << info->pa_ppn_shift[i]); + i++; + } + LOG_DEBUG("0x%" TARGET_PRIxADDR " -> 0x%" TARGET_PRIxADDR, virtual, + *physical); + + return ERROR_OK; +} + +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_address_translate(target, virtual, physical) == ERROR_OK) + return ERROR_OK; + } + + return ERROR_FAIL; +} + +static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + RISCV_INFO(r); + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + return r->read_memory(target, phys_address, size, count, buffer, size); +} + +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); + return ERROR_OK; + } + + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + + target_addr_t physical_addr; + if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK) + address = physical_addr; + + RISCV_INFO(r); + return r->read_memory(target, address, 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) +{ + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + struct target_type *tt = get_target_type(target); + return tt->write_memory(target, phys_address, size, count, buffer); } 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); + return ERROR_OK; + } + if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; + + target_addr_t physical_addr; + if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK) + address = physical_addr; + struct target_type *tt = get_target_type(target); return tt->write_memory(target, address, size, count, buffer); } +static const char *riscv_get_gdb_arch(const struct target *target) +{ + switch (riscv_xlen(target)) { + case 32: + return "riscv:rv32"; + case 64: + return "riscv:rv64"; + } + LOG_ERROR("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) { RISCV_INFO(r); - LOG_DEBUG("rtos_hartid=%d, current_hartid=%d, reg_class=%d, read=%d", - r->rtos_hartid, r->current_hartid, reg_class, read); + LOG_DEBUG("[%s] {%d} reg_class=%d, read=%d", + target_name(target), r->current_hartid, reg_class, read); if (!target->reg_cache) { LOG_ERROR("Target not initialized. Return ERROR_FAIL."); @@ -954,20 +1792,26 @@ 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 && !target->reg_cache->reg_list[i].valid) { + if (read && + target->reg_cache->reg_list[i].exist && + !target->reg_cache->reg_list[i].valid) { if (target->reg_cache->reg_list[i].type->get( &target->reg_cache->reg_list[i]) != ERROR_OK) - /* This function is called when first connecting to gdb, - * resulting in an attempt to read all kinds of registers which - * probably will fail. Ignore these failures, and when - * encountered stop reading to save time. */ - read = false; + return ERROR_FAIL; } } return ERROR_OK; } +static int riscv_get_gdb_reg_list_noread(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class) +{ + return riscv_get_gdb_reg_list_internal(target, reg_list, reg_list_size, + reg_class, false); +} + static int riscv_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) @@ -986,9 +1830,9 @@ 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_t *info = (riscv_info_t *) target->arch_info; + RISCV_INFO(info); if (num_mem_params > 0) { LOG_ERROR("Memory parameters are not supported for RISC-V algorithms."); @@ -996,23 +1840,21 @@ static int riscv_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; } /* Save registers */ - struct reg *reg_pc = register_get_by_name(target->reg_cache, "pc", 1); + struct reg *reg_pc = register_get_by_name(target->reg_cache, "pc", true); 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); uint64_t saved_regs[32]; for (int i = 0; i < num_reg_params; i++) { - if (reg_params[i].direction == PARAM_IN) - continue; - LOG_DEBUG("save %s", reg_params[i].reg_name); - struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0); + 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); return ERROR_FAIL; @@ -1032,8 +1874,11 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, if (r->type->get(r) != ERROR_OK) return ERROR_FAIL; saved_regs[r->number] = buf_get_u64(r->value, 0, r->size); - if (r->type->set(r, reg_params[i].value) != ERROR_OK) - return ERROR_FAIL; + + if (reg_params[i].direction == PARAM_OUT || reg_params[i].direction == PARAM_IN_OUT) { + if (r->type->set(r, reg_params[i].value) != ERROR_OK) + return ERROR_FAIL; + } } @@ -1043,7 +1888,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, LOG_DEBUG("Disabling Interrupts"); struct reg *reg_mstatus = register_get_by_name(target->reg_cache, - "mstatus", 1); + "mstatus", true); if (!reg_mstatus) { LOG_ERROR("Couldn't find mstatus!"); return ERROR_FAIL; @@ -1052,14 +1897,14 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, reg_mstatus->type->get(reg_mstatus); current_mstatus = buf_get_u64(reg_mstatus->value, 0, reg_mstatus->size); uint64_t ie_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; - buf_set_u64(mstatus_bytes, 0, info->xlen[0], set_field(current_mstatus, + buf_set_u64(mstatus_bytes, 0, info->xlen, set_field(current_mstatus, ie_mask, 0)); reg_mstatus->type->set(reg_mstatus, mstatus_bytes); /* Run algorithm */ LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point); - if (oldriscv_resume(target, 0, entry_point, 0, 0) != ERROR_OK) + if (riscv_resume(target, 0, entry_point, 0, 0, true) != ERROR_OK) return ERROR_FAIL; int64_t start = timeval_ms(); @@ -1067,11 +1912,28 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, LOG_DEBUG("poll()"); int64_t now = timeval_ms(); if (now - start > timeout_ms) { - LOG_ERROR("Algorithm timed out after %d ms.", timeout_ms); - LOG_ERROR(" now = 0x%08x", (uint32_t) now); - LOG_ERROR(" start = 0x%08x", (uint32_t) start); - oldriscv_halt(target); + LOG_ERROR("Algorithm timed out after %" PRId64 " ms.", now - start); + riscv_halt(target); old_or_new_riscv_poll(target); + enum gdb_regno regnums[] = { + GDB_REGNO_RA, GDB_REGNO_SP, GDB_REGNO_GP, GDB_REGNO_TP, + GDB_REGNO_T0, GDB_REGNO_T1, GDB_REGNO_T2, GDB_REGNO_FP, + GDB_REGNO_S1, GDB_REGNO_A0, GDB_REGNO_A1, GDB_REGNO_A2, + GDB_REGNO_A3, GDB_REGNO_A4, GDB_REGNO_A5, GDB_REGNO_A6, + GDB_REGNO_A7, GDB_REGNO_S2, GDB_REGNO_S3, GDB_REGNO_S4, + GDB_REGNO_S5, GDB_REGNO_S6, GDB_REGNO_S7, GDB_REGNO_S8, + GDB_REGNO_S9, GDB_REGNO_S10, GDB_REGNO_S11, GDB_REGNO_T3, + GDB_REGNO_T4, GDB_REGNO_T5, GDB_REGNO_T6, + GDB_REGNO_PC, + GDB_REGNO_MSTATUS, GDB_REGNO_MEPC, GDB_REGNO_MCAUSE, + }; + for (unsigned i = 0; i < ARRAY_SIZE(regnums); i++) { + enum gdb_regno regno = regnums[i]; + 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); + } return ERROR_TARGET_TIMEOUT; } @@ -1080,10 +1942,14 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, return result; } + /* The current hart id might have been changed in poll(). */ + if (riscv_select_current_hart(target) != ERROR_OK) + return ERROR_FAIL; + if (reg_pc->type->get(reg_pc) != ERROR_OK) return ERROR_FAIL; uint64_t final_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size); - if (final_pc != exit_point) { + if (exit_point && final_pc != exit_point) { LOG_ERROR("PC ended up at 0x%" PRIx64 " instead of 0x%" TARGET_PRIxADDR, final_pc, exit_point); return ERROR_FAIL; @@ -1091,36 +1957,121 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, /* Restore Interrupts */ LOG_DEBUG("Restoring Interrupts"); - buf_set_u64(mstatus_bytes, 0, info->xlen[0], current_mstatus); + buf_set_u64(mstatus_bytes, 0, info->xlen, current_mstatus); reg_mstatus->type->set(reg_mstatus, mstatus_bytes); /* Restore registers */ uint8_t buf[8] = { 0 }; - buf_set_u64(buf, 0, info->xlen[0], saved_pc); + buf_set_u64(buf, 0, info->xlen, saved_pc); if (reg_pc->type->set(reg_pc, buf) != ERROR_OK) return ERROR_FAIL; for (int i = 0; i < num_reg_params; i++) { + if (reg_params[i].direction == PARAM_IN || + 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); + return ERROR_FAIL; + } + buf_cpy(r->value, reg_params[i].value, reg_params[i].size); + } LOG_DEBUG("restore %s", reg_params[i].reg_name); - struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0); - buf_set_u64(buf, 0, info->xlen[0], saved_regs[r->number]); - if (r->type->set(r, buf) != ERROR_OK) + 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); return ERROR_FAIL; + } } return ERROR_OK; } -/* Should run code on the target to perform CRC of -memory. Not yet implemented. -*/ - static int riscv_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { - *checksum = 0xFFFFFFFF; - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + struct working_area *crc_algorithm; + struct reg_param reg_params[2]; + int retval; + + LOG_DEBUG("address=0x%" TARGET_PRIxADDR "; count=0x%" PRIx32, address, count); + + static const uint8_t riscv32_crc_code[] = { +#include "../../../contrib/loaders/checksum/riscv32_crc.inc" + }; + static const uint8_t riscv64_crc_code[] = { +#include "../../../contrib/loaders/checksum/riscv64_crc.inc" + }; + + static const uint8_t *crc_code; + + unsigned xlen = riscv_xlen(target); + unsigned crc_code_size; + if (xlen == 32) { + crc_code = riscv32_crc_code; + crc_code_size = sizeof(riscv32_crc_code); + } else { + crc_code = riscv64_crc_code; + crc_code_size = sizeof(riscv64_crc_code); + } + + if (count < crc_code_size * 4) { + /* Don't use the algorithm for relatively small buffers. It's faster + * just to read the memory. target_checksum_memory() will take care of + * that if we fail. */ + return ERROR_FAIL; + } + + retval = target_alloc_working_area(target, crc_code_size, &crc_algorithm); + if (retval != ERROR_OK) + return retval; + + if (crc_algorithm->address + crc_algorithm->size > address && + crc_algorithm->address < address + count) { + /* Region to checksum overlaps with the work area we've been assigned. + * Bail. (Would be better to manually checksum what we read there, and + * use the algorithm for the rest.) */ + target_free_working_area(target, crc_algorithm); + return ERROR_FAIL; + } + + 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", + crc_algorithm->address, retval); + target_free_working_area(target, crc_algorithm); + return retval; + } + + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + buf_set_u64(reg_params[0].value, 0, xlen, address); + buf_set_u64(reg_params[1].value, 0, xlen, count); + + /* 20 second timeout/megabyte */ + unsigned int timeout = 20000 * (1 + (count / (1024 * 1024))); + + retval = target_run_algorithm(target, 0, NULL, 2, reg_params, + crc_algorithm->address, + 0, /* Leave exit point unspecified because we don't know. */ + timeout, NULL); + + if (retval == ERROR_OK) + *checksum = buf_get_u32(reg_params[0].value, 0, 32); + else + LOG_ERROR("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); + + return retval; } /*** OpenOCD Helper Functions ***/ @@ -1149,15 +2100,16 @@ static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid) } else if (target->state != TARGET_RUNNING && !halted) { LOG_DEBUG(" triggered running"); target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; return RPH_DISCOVERED_RUNNING; } return RPH_NO_CHANGE; } -int set_debug_reason(struct target *target, int hartid) +static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_reason) { - switch (riscv_halt_reason(target, hartid)) { + switch (halt_reason) { case RISCV_HALT_BREAKPOINT: target->debug_reason = DBG_REASON_BREAKPOINT; break; @@ -1165,6 +2117,7 @@ int set_debug_reason(struct target *target, int hartid) target->debug_reason = DBG_REASON_WATCHPOINT; break; case RISCV_HALT_INTERRUPT: + case RISCV_HALT_GROUP: target->debug_reason = DBG_REASON_DBGRQ; break; case RISCV_HALT_SINGLESTEP: @@ -1176,7 +2129,55 @@ int set_debug_reason(struct target *target, int hartid) case RISCV_HALT_ERROR: return ERROR_FAIL; } - return ERROR_OK; + LOG_DEBUG("[%s] debug_reason=%d", target_name(target), target->debug_reason); + return ERROR_OK; +} + +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); + + uint64_t start = timeval_ms(); + riscv_sample_buf_maybe_add_timestamp(target, true); + int result = ERROR_OK; + if (r->sample_memory) { + result = r->sample_memory(target, &r->sample_buf, &r->sample_config, + start + TARGET_DEFAULT_POLLING_INTERVAL); + if (result != ERROR_NOT_IMPLEMENTED) + goto exit; + } + + /* Default slow path. */ + while (timeval_ms() - start < TARGET_DEFAULT_POLLING_INTERVAL) { + for (unsigned int i = 0; i < ARRAY_SIZE(r->sample_config.bucket); i++) { + if (r->sample_config.bucket[i].enabled && + r->sample_buf.used + 1 + r->sample_config.bucket[i].size_bytes < r->sample_buf.size) { + assert(i < RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE); + r->sample_buf.buf[r->sample_buf.used] = i; + result = riscv_read_phys_memory( + target, r->sample_config.bucket[i].address, + r->sample_config.bucket[i].size_bytes, 1, + r->sample_buf.buf + r->sample_buf.used + 1); + if (result == ERROR_OK) + r->sample_buf.used += 1 + r->sample_config.bucket[i].size_bytes; + else + goto exit; + } + } + } + +exit: + riscv_sample_buf_maybe_add_timestamp(target, false); + if (result != ERROR_OK) { + LOG_INFO("Turning off memory sampling because it failed."); + r->sample_config.enabled = false; + } + return result; } /*** OpenOCD Interface ***/ @@ -1184,225 +2185,119 @@ int riscv_openocd_poll(struct target *target) { LOG_DEBUG("polling all harts"); int halted_hart = -1; - if (riscv_rtos_enabled(target)) { - /* Check every hart for an event. */ - for (int i = 0; i < riscv_count_harts(target); ++i) { - enum riscv_poll_hart out = riscv_poll_hart(target, i); + + 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; + struct riscv_info *r = riscv_info(t); + enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid); switch (out) { case RPH_NO_CHANGE: + break; case RPH_DISCOVERED_RUNNING: - continue; + t->state = TARGET_RUNNING; + t->debug_reason = DBG_REASON_NOTHALTED; + break; case RPH_DISCOVERED_HALTED: - halted_hart = i; + t->state = TARGET_HALTED; + enum riscv_halt_reason halt_reason = + riscv_halt_reason(t, r->current_hartid); + if (set_debug_reason(t, halt_reason) != ERROR_OK) + return ERROR_FAIL; + + if (halt_reason == RISCV_HALT_BREAKPOINT) { + int retval; + switch (riscv_semihosting(t, &retval)) { + case SEMIHOSTING_NONE: + case SEMIHOSTING_WAITING: + /* This hart should remain halted. */ + should_remain_halted++; + break; + case SEMIHOSTING_HANDLED: + /* This hart should be resumed, along with any other + * harts that halted due to haltgroups. */ + should_resume++; + break; + case SEMIHOSTING_ERROR: + return retval; + } + } else if (halt_reason != RISCV_HALT_GROUP) { + should_remain_halted++; + } break; + case RPH_ERROR: return ERROR_FAIL; } } - if (halted_hart == -1) { - LOG_DEBUG(" no harts just halted, target->state=%d", target->state); - return ERROR_OK; + + 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); } - LOG_DEBUG(" hart %d halted", halted_hart); - /* If we're here then at least one hart triggered. That means - * we want to go and halt _every_ hart in the system, as that's - * the invariant we hold here. Some harts might have already - * halted (as we're either in single-step mode or they also - * triggered a breakpoint), so don't attempt to halt those - * harts. */ - for (int i = 0; i < riscv_count_harts(target); ++i) - riscv_halt_one_hart(target, i); - - } else if (target->smp) { - bool halt_discovered = false; - bool newly_halted[128] = {0}; - unsigned i = 0; - for (struct target_list *list = target->head; list != NULL; - list = list->next, i++) { + /* Sample memory if any target is running. */ + foreach_smp_target(list, target->smp_targets) { struct target *t = list->target; - riscv_info_t *r = riscv_info(t); - assert(i < DIM(newly_halted)); - enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid); - switch (out) { - case RPH_NO_CHANGE: - break; - case RPH_DISCOVERED_RUNNING: - t->state = TARGET_RUNNING; - break; - case RPH_DISCOVERED_HALTED: - halt_discovered = true; - newly_halted[i] = true; - t->state = TARGET_HALTED; - if (set_debug_reason(t, r->current_hartid) != ERROR_OK) - return ERROR_FAIL; - break; - case RPH_ERROR: - return ERROR_FAIL; + if (t->state == TARGET_RUNNING) { + sample_memory(target); + break; } } - if (halt_discovered) { - LOG_DEBUG("Halt other targets in this SMP group."); - i = 0; - for (struct target_list *list = target->head; list != NULL; - list = list->next, i++) { - struct target *t = list->target; - riscv_info_t *r = riscv_info(t); - if (t->state != TARGET_HALTED) { - if (riscv_halt_one_hart(t, r->current_hartid) != ERROR_OK) - return ERROR_FAIL; - t->state = TARGET_HALTED; - if (set_debug_reason(t, r->current_hartid) != ERROR_OK) - return ERROR_FAIL; - newly_halted[i] = true; - } - } - - /* Now that we have all our ducks in a row, tell the higher layers - * what just happened. */ - i = 0; - for (struct target_list *list = target->head; list != NULL; - list = list->next, i++) { - struct target *t = list->target; - if (newly_halted[i]) - target_call_event_callbacks(t, TARGET_EVENT_HALTED); - } - } return ERROR_OK; } else { enum riscv_poll_hart out = riscv_poll_hart(target, riscv_current_hartid(target)); - if (out == RPH_NO_CHANGE || out == RPH_DISCOVERED_RUNNING) + 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) + } else if (out == RPH_ERROR) { return ERROR_FAIL; + } halted_hart = riscv_current_hartid(target); LOG_DEBUG(" hart %d halted", halted_hart); - } - - target->state = TARGET_HALTED; - if (set_debug_reason(target, halted_hart) != ERROR_OK) - return ERROR_FAIL; - if (riscv_rtos_enabled(target)) { - target->rtos->current_threadid = halted_hart + 1; - target->rtos->current_thread = halted_hart + 1; - riscv_set_rtos_hartid(target, halted_hart); + enum riscv_halt_reason halt_reason = riscv_halt_reason(target, halted_hart); + if (set_debug_reason(target, halt_reason) != ERROR_OK) + return ERROR_FAIL; + target->state = TARGET_HALTED; } - target->state = TARGET_HALTED; - if (target->debug_reason == DBG_REASON_BREAKPOINT) { int retval; - if (riscv_semihosting(target, &retval) != 0) - return retval; - } - - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - return ERROR_OK; -} - -int riscv_openocd_halt(struct target *target) -{ - RISCV_INFO(r); - int result; - - LOG_DEBUG("[%d] halting all harts", target->coreid); - - if (target->smp) { - LOG_DEBUG("Halt other targets in this SMP group."); - struct target_list *targets = target->head; - result = ERROR_OK; - while (targets) { - struct target *t = targets->target; - targets = targets->next; - if (t->state != TARGET_HALTED) { - if (riscv_halt_all_harts(t) != ERROR_OK) - result = ERROR_FAIL; - } + switch (riscv_semihosting(target, &retval)) { + case SEMIHOSTING_NONE: + case SEMIHOSTING_WAITING: + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + break; + case SEMIHOSTING_HANDLED: + if (riscv_resume(target, true, 0, 0, 0, false) != ERROR_OK) + return ERROR_FAIL; + break; + case SEMIHOSTING_ERROR: + return retval; } } else { - result = riscv_halt_all_harts(target); - } - - if (riscv_rtos_enabled(target)) { - if (r->rtos_hartid != -1) { - LOG_DEBUG("halt requested on RTOS hartid %d", r->rtos_hartid); - target->rtos->current_threadid = r->rtos_hartid + 1; - target->rtos->current_thread = r->rtos_hartid + 1; - } else - LOG_DEBUG("halt requested, but no known RTOS hartid"); - } - - target->state = TARGET_HALTED; - target->debug_reason = DBG_REASON_DBGRQ; - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - return result; -} - -int riscv_openocd_resume( - struct target *target, - int current, - target_addr_t address, - int handle_breakpoints, - int debug_execution) -{ - LOG_DEBUG("debug_reason=%d", target->debug_reason); - - 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. */ - struct watchpoint *watchpoint = target->watchpoints; - bool trigger_temporarily_cleared[RISCV_MAX_HWBPS] = {0}; - - int i = 0; - int result = ERROR_OK; - while (watchpoint && result == ERROR_OK) { - LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set); - trigger_temporarily_cleared[i] = watchpoint->set; - if (watchpoint->set) - result = riscv_remove_watchpoint(target, watchpoint); - watchpoint = watchpoint->next; - i++; - } - - if (result == ERROR_OK) - result = riscv_step_rtos_hart(target); - - watchpoint = target->watchpoints; - i = 0; - while (watchpoint) { - LOG_DEBUG("watchpoint %d: cleared=%d", i, trigger_temporarily_cleared[i]); - if (trigger_temporarily_cleared[i]) { - if (result == ERROR_OK) - result = riscv_add_watchpoint(target, watchpoint); - else - riscv_add_watchpoint(target, watchpoint); - } - watchpoint = watchpoint->next; - i++; - } - - if (result != ERROR_OK) - return result; - } - - int out = riscv_resume_all_harts(target); - if (out != ERROR_OK) { - LOG_ERROR("unable to resume all harts"); - return out; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); } - register_cache_invalidate(target->reg_cache); - target->state = TARGET_RUNNING; - target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - return out; + return ERROR_OK; } int riscv_openocd_step(struct target *target, int current, @@ -1413,6 +2308,10 @@ int riscv_openocd_step(struct target *target, int current, if (!current) riscv_set_register(target, GDB_REGNO_PC, address); + riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0}; + if (disable_triggers(target, trigger_state) != ERROR_OK) + return ERROR_FAIL; + int out = riscv_step_rtos_hart(target); if (out != ERROR_OK) { LOG_ERROR("unable to step rtos hart"); @@ -1420,6 +2319,10 @@ int riscv_openocd_step(struct target *target, int current, } register_cache_invalidate(target->reg_cache); + + if (enable_triggers(target, trigger_state) != ERROR_OK) + return ERROR_FAIL; + target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); target->state = TARGET_HALTED; @@ -1462,136 +2365,242 @@ COMMAND_HANDLER(riscv_set_reset_timeout_sec) return ERROR_OK; } -COMMAND_HANDLER(riscv_test_compliance) { - +COMMAND_HANDLER(riscv_set_mem_access) +{ struct target *target = get_current_target(CMD_CTX); - RISCV_INFO(r); + int progbuf_cnt = 0; + int sysbus_cnt = 0; + int abstract_cnt = 0; - if (CMD_ARGC > 0) { - LOG_ERROR("Command does not take any parameters."); + if (CMD_ARGC < 1 || CMD_ARGC > RISCV_NUM_MEM_ACCESS_METHODS) { + LOG_ERROR("Command takes 1 to %d parameters", RISCV_NUM_MEM_ACCESS_METHODS); return ERROR_COMMAND_SYNTAX_ERROR; } - if (r->test_compliance) { - return r->test_compliance(target); - } else { - LOG_ERROR("This target does not support this command (may implement an older version of the spec)."); - return ERROR_FAIL; + /* Check argument validity */ + for (unsigned int i = 0; i < CMD_ARGC; i++) { + if (strcmp("progbuf", CMD_ARGV[i]) == 0) { + progbuf_cnt++; + } else if (strcmp("sysbus", CMD_ARGV[i]) == 0) { + sysbus_cnt++; + } else if (strcmp("abstract", CMD_ARGV[i]) == 0) { + abstract_cnt++; + } else { + LOG_ERROR("Unknown argument '%s'. " + "Must be one of: 'progbuf', 'sysbus' or 'abstract'.", CMD_ARGV[i]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } + if (progbuf_cnt > 1 || sysbus_cnt > 1 || abstract_cnt > 1) { + LOG_ERROR("Syntax error - duplicate arguments to `riscv set_mem_access`."); + return ERROR_COMMAND_SYNTAX_ERROR; } + + /* Args are valid, store them */ + for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) + r->mem_access_methods[i] = RISCV_MEM_ACCESS_UNSPECIFIED; + for (unsigned int i = 0; i < CMD_ARGC; i++) { + if (strcmp("progbuf", CMD_ARGV[i]) == 0) + r->mem_access_methods[i] = RISCV_MEM_ACCESS_PROGBUF; + else if (strcmp("sysbus", CMD_ARGV[i]) == 0) + r->mem_access_methods[i] = RISCV_MEM_ACCESS_SYSBUS; + else if (strcmp("abstract", CMD_ARGV[i]) == 0) + r->mem_access_methods[i] = 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_prefer_sba) +COMMAND_HANDLER(riscv_set_enable_virtual) { if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_prefer_sba); + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virtual); return ERROR_OK; } -void parse_error(const char *string, char c, unsigned position) +static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const char *reg_type, unsigned int max_val) { - char buf[position+2]; - for (unsigned i = 0; i < position; i++) - buf[i] = ' '; - buf[position] = '^'; - buf[position + 1] = 0; - - LOG_ERROR("Parse error at character %c in:", c); - LOG_ERROR("%s", string); - LOG_ERROR("%s", buf); -} + char *args = strdup(tcl_arg); + if (!args) + return ERROR_FAIL; -int parse_ranges(range_t **ranges, const char **argv) -{ - for (unsigned pass = 0; pass < 2; pass++) { - unsigned range = 0; + /* For backward compatibility, allow multiple parameters within one TCL argument, separated by ',' */ + char *arg = strtok(args, ","); + while (arg) { unsigned low = 0; - bool parse_low = true; unsigned high = 0; - for (unsigned i = 0; i == 0 || argv[0][i-1]; i++) { - char c = argv[0][i]; - if (isspace(c)) { - /* Ignore whitespace. */ - continue; + char *name = NULL; + + char *dash = strchr(arg, '-'); + char *equals = strchr(arg, '='); + unsigned int pos; + + if (!dash && !equals) { + /* Expecting single register number. */ + if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) { + LOG_ERROR("Failed to parse single register number from '%s'.", arg); + free(args); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else if (dash && !equals) { + /* Expecting register range - two numbers separated by a dash: ##-## */ + *dash = 0; + dash++; + if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) { + LOG_ERROR("Failed to parse single register number from '%s'.", arg); + free(args); + return ERROR_COMMAND_SYNTAX_ERROR; + } + if (sscanf(dash, "%u%n", &high, &pos) != 1 || pos != strlen(dash)) { + LOG_ERROR("Failed to parse single register number from '%s'.", dash); + free(args); + return ERROR_COMMAND_SYNTAX_ERROR; + } + if (high < low) { + LOG_ERROR("Incorrect range encountered [%u, %u].", low, high); + free(args); + return ERROR_FAIL; + } + } else if (!dash && equals) { + /* Expecting single register number with textual name specified: ##=name */ + *equals = 0; + equals++; + if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) { + LOG_ERROR("Failed to parse single register number from '%s'.", arg); + free(args); + return ERROR_COMMAND_SYNTAX_ERROR; } - if (parse_low) { - if (isdigit(c)) { - low *= 10; - low += c - '0'; - } else if (c == '-') { - parse_low = false; - } else if (c == ',' || c == 0) { - if (pass == 1) { - (*ranges)[range].low = low; - (*ranges)[range].high = low; - } - low = 0; - range++; - } else { - parse_error(argv[0], c, i); - return ERROR_COMMAND_SYNTAX_ERROR; - } + name = calloc(1, strlen(equals) + strlen(reg_type) + 2); + if (!name) { + LOG_ERROR("Failed to allocate register name."); + free(args); + return ERROR_FAIL; + } - } else { - if (isdigit(c)) { - high *= 10; - high += c - '0'; - } else if (c == ',' || c == 0) { - parse_low = true; - if (pass == 1) { - (*ranges)[range].low = low; - (*ranges)[range].high = high; - } - low = 0; - high = 0; - range++; - } else { - parse_error(argv[0], c, i); - return ERROR_COMMAND_SYNTAX_ERROR; - } + /* Register prefix: "csr_" or "custom_" */ + strcpy(name, reg_type); + name[strlen(reg_type)] = '_'; + + if (sscanf(equals, "%[_a-zA-Z0-9]%n", name + strlen(reg_type) + 1, &pos) != 1 || pos != strlen(equals)) { + LOG_ERROR("Failed to parse register name from '%s'.", equals); + free(args); + free(name); + return ERROR_COMMAND_SYNTAX_ERROR; } + } else { + LOG_ERROR("Invalid argument '%s'.", arg); + free(args); + return ERROR_COMMAND_SYNTAX_ERROR; } - if (pass == 0) { - free(*ranges); - *ranges = calloc(range + 2, sizeof(range_t)); - } else { - (*ranges)[range].low = 1; - (*ranges)[range].high = 0; + high = high > low ? high : low; + + if (high > max_val) { + LOG_ERROR("Cannot expose %s register number %u, maximum allowed value is %u.", reg_type, high, max_val); + free(name); + free(args); + return ERROR_FAIL; + } + + /* Check for overlap, name uniqueness. */ + range_list_t *entry; + list_for_each_entry(entry, ranges, list) { + if ((entry->low <= high) && (low <= entry->high)) { + if (low == high) + LOG_WARNING("Duplicate %s register number - " + "Register %u has already been exposed previously", reg_type, low); + else + LOG_WARNING("Overlapping register ranges - Register range starting from %u overlaps " + "with already exposed register/range at %u.", low, entry->low); + } + + if (entry->name && name && (strcasecmp(entry->name, name) == 0)) { + LOG_ERROR("Duplicate register name \"%s\" found.", name); + free(name); + free(args); + return ERROR_FAIL; + } + } + + range_list_t *range = calloc(1, sizeof(range_list_t)); + if (!range) { + LOG_ERROR("Failed to allocate range list."); + free(name); + free(args); + return ERROR_FAIL; } + + range->low = low; + range->high = high; + range->name = name; + list_add(&range->list, ranges); + + arg = strtok(NULL, ","); } + free(args); return ERROR_OK; } COMMAND_HANDLER(riscv_set_expose_csrs) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); + if (CMD_ARGC == 0) { + LOG_ERROR("Command expects parameters"); return ERROR_COMMAND_SYNTAX_ERROR; } - return parse_ranges(&expose_csr, CMD_ARGV); + 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->expose_csr, CMD_ARGV[i], "csr", 0xfff); + if (ret != ERROR_OK) + break; + } + + return ret; } COMMAND_HANDLER(riscv_set_expose_custom) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); + if (CMD_ARGC == 0) { + LOG_ERROR("Command expects parameters"); return ERROR_COMMAND_SYNTAX_ERROR; } - return parse_ranges(&expose_custom, CMD_ARGV); + 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->expose_custom, CMD_ARGV[i], "custom", 0x3fff); + if (ret != ERROR_OK) + break; + } + + return ret; } COMMAND_HANDLER(riscv_authdata_read) { - if (CMD_ARGC != 0) { - LOG_ERROR("Command takes no parameters"); + unsigned int index = 0; + if (CMD_ARGC == 0) { + /* nop */ + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index); + } else { + LOG_ERROR("Command takes at most one parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1609,9 +2618,9 @@ COMMAND_HANDLER(riscv_authdata_read) if (r->authdata_read) { uint32_t value; - if (r->authdata_read(target, &value) != ERROR_OK) + if (r->authdata_read(target, &value, index) != ERROR_OK) return ERROR_FAIL; - command_print(CMD, "0x%" PRIx32, value); + command_print_sameline(CMD, "0x%08" PRIx32, value); return ERROR_OK; } else { LOG_ERROR("authdata_read is not implemented for this target."); @@ -1621,23 +2630,28 @@ COMMAND_HANDLER(riscv_authdata_read) COMMAND_HANDLER(riscv_authdata_write) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 argument"); + uint32_t value; + unsigned int index = 0; + + 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 { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); } struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], value); - - if (r->authdata_write) { - return r->authdata_write(target, value); - } else { + if (!r->authdata_write) { LOG_ERROR("authdata_write is not implemented for this target."); return ERROR_FAIL; } + + return r->authdata_write(target, value, index); } COMMAND_HANDLER(riscv_dmi_read) @@ -1695,112 +2709,202 @@ COMMAND_HANDLER(riscv_dmi_write) } } -COMMAND_HANDLER(riscv_test_sba_config_reg) +COMMAND_HANDLER(riscv_reset_delays) { - if (CMD_ARGC != 4) { - LOG_ERROR("Command takes exactly 4 arguments"); + int wait = 0; + + if (CMD_ARGC > 1) { + LOG_ERROR("Command takes at most one argument"); return ERROR_COMMAND_SYNTAX_ERROR; } + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], wait); + struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); + r->reset_delays_wait = wait; + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_set_ir) +{ + if (CMD_ARGC != 2) { + LOG_ERROR("Command takes exactly 2 arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + uint32_t value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + if (!strcmp(CMD_ARGV[0], "idcode")) + buf_set_u32(ir_idcode, 0, 32, value); + else if (!strcmp(CMD_ARGV[0], "dtmcs")) + buf_set_u32(ir_dtmcontrol, 0, 32, value); + else if (!strcmp(CMD_ARGV[0], "dmi")) + buf_set_u32(ir_dbus, 0, 32, value); + else + return ERROR_FAIL; - target_addr_t legal_address; - uint32_t num_words; - target_addr_t illegal_address; - bool run_sbbusyerror_test; + return ERROR_OK; +} - 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); +COMMAND_HANDLER(riscv_resume_order) +{ + if (CMD_ARGC > 1) { + LOG_ERROR("Command takes at most one argument"); + return ERROR_COMMAND_SYNTAX_ERROR; + } - if (r->test_sba_config_reg) { - return r->test_sba_config_reg(target, legal_address, num_words, - illegal_address, run_sbbusyerror_test); + if (!strcmp(CMD_ARGV[0], "normal")) { + resume_order = RO_NORMAL; + } else if (!strcmp(CMD_ARGV[0], "reversed")) { + resume_order = RO_REVERSED; } else { - LOG_ERROR("test_sba_config_reg is not implemented for this target."); + LOG_ERROR("Unsupported resume order: %s", CMD_ARGV[0]); return ERROR_FAIL; } + + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_use_bscan_tunnel) +{ + int irwidth = 0; + int tunnel_type = BSCAN_TUNNEL_NESTED_TAP; + + if (CMD_ARGC > 2) { + LOG_ERROR("Command takes at most two arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth); + } else if (CMD_ARGC == 2) { + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tunnel_type); + } + if (tunnel_type == BSCAN_TUNNEL_NESTED_TAP) + LOG_INFO("Nested Tap based Bscan Tunnel Selected"); + else if (tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) + LOG_INFO("Simple Register based Bscan Tunnel Selected"); + else + LOG_INFO("Invalid Tunnel type selected ! : selecting default Nested Tap Type"); + + bscan_tunnel_type = tunnel_type; + bscan_tunnel_ir_width = irwidth; + 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) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreakm); + return ERROR_OK; } -COMMAND_HANDLER(riscv_reset_delays) +COMMAND_HANDLER(riscv_set_ebreaks) { - int wait = 0; - - if (CMD_ARGC > 1) { - LOG_ERROR("Command takes at most one argument"); + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } - - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], wait); - - struct target *target = get_current_target(CMD_CTX); - RISCV_INFO(r); - r->reset_delays_wait = wait; + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaks); return ERROR_OK; } -COMMAND_HANDLER(riscv_set_ir) +COMMAND_HANDLER(riscv_set_ebreaku) { - if (CMD_ARGC != 2) { - LOG_ERROR("Command takes exactly 2 arguments"); + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaku); + return ERROR_OK; +} - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); +COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key, + unsigned int value) +{ + char full_key[80]; + snprintf(full_key, sizeof(full_key), "%s.%s", section, key); + command_print(CMD, "%-21s %3d", full_key, value); + return 0; +} - if (!strcmp(CMD_ARGV[0], "idcode")) { - buf_set_u32(ir_idcode, 0, 32, value); - return ERROR_OK; - } else if (!strcmp(CMD_ARGV[0], "dtmcs")) { - buf_set_u32(ir_dtmcontrol, 0, 32, value); - return ERROR_OK; - } else if (!strcmp(CMD_ARGV[0], "dmi")) { - buf_set_u32(ir_dbus, 0, 32, value); - return ERROR_OK; - } else { - return ERROR_FAIL; - } +COMMAND_HANDLER(handle_info) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + /* 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); + + if (r->print_info) + return CALL_COMMAND_HANDLER(r->print_info, target); + + return 0; } static const struct command_registration riscv_exec_command_handlers[] = { { - .name = "test_compliance", - .handler = riscv_test_compliance, + .name = "info", + .handler = handle_info, .mode = COMMAND_EXEC, - .usage = "riscv test_compliance", - .help = "Runs a basic compliance test suite against the RISC-V Debug Spec." + .usage = "", + .help = "Displays some information OpenOCD detected about the target." }, { .name = "set_command_timeout_sec", .handler = riscv_set_command_timeout_sec, .mode = COMMAND_ANY, - .usage = "riscv set_command_timeout_sec [sec]", + .usage = "[sec]", .help = "Set the wall-clock timeout (in seconds) for individual commands" }, { .name = "set_reset_timeout_sec", .handler = riscv_set_reset_timeout_sec, .mode = COMMAND_ANY, - .usage = "riscv set_reset_timeout_sec [sec]", + .usage = "[sec]", .help = "Set the wall-clock timeout (in seconds) after reset is deasserted" }, { - .name = "set_prefer_sba", - .handler = riscv_set_prefer_sba, + .name = "set_mem_access", + .handler = riscv_set_mem_access, + .mode = COMMAND_ANY, + .usage = "method1 [method2] [method3]", + .help = "Set which memory access methods shall be used and in which order " + "of priority. Method can be one of: 'progbuf', 'sysbus' or 'abstract'." + }, + { + .name = "set_enable_virtual", + .handler = riscv_set_enable_virtual, .mode = COMMAND_ANY, - .usage = "riscv set_prefer_sba on|off", - .help = "When on, prefer to use System Bus Access to access memory. " - "When off, prefer to use the Program Buffer to access memory." + .usage = "on|off", + .help = "When on, memory accesses are performed on physical or virtual " + "memory depending on the current system configuration. " + "When off (default), all memory accessses are performed on physical memory." }, { .name = "expose_csrs", .handler = riscv_set_expose_csrs, - .mode = COMMAND_ANY, - .usage = "riscv expose_csrs n0[-m0][,n1[-m1]]...", + .mode = COMMAND_CONFIG, + .usage = "n0[-m0|=name0][,n1[-m1|=name1]]...", .help = "Configure a list of inclusive ranges for CSRs to expose in " "addition to the standard ones. This must be executed before " "`init`." @@ -1808,8 +2912,8 @@ static const struct command_registration riscv_exec_command_handlers[] = { { .name = "expose_custom", .handler = riscv_set_expose_custom, - .mode = COMMAND_ANY, - .usage = "riscv expose_custom n0[-m0][,n1[-m1]]...", + .mode = COMMAND_CONFIG, + .usage = "n0[-m0|=name0][,n1[-m1|=name1]]...", .help = "Configure a list of inclusive ranges for custom registers to " "expose. custom0 is accessed as abstract register number 0xc000, " "etc. This must be executed before `init`." @@ -1817,61 +2921,102 @@ static const struct command_registration riscv_exec_command_handlers[] = { { .name = "authdata_read", .handler = riscv_authdata_read, + .usage = "[index]", .mode = COMMAND_ANY, - .usage = "riscv authdata_read", - .help = "Return the 32-bit value read from authdata." + .help = "Return the 32-bit value read from authdata or authdata0 " + "(index=0), or authdata1 (index=1)." }, { .name = "authdata_write", .handler = riscv_authdata_write, .mode = COMMAND_ANY, - .usage = "riscv authdata_write value", - .help = "Write the 32-bit value to authdata." + .usage = "[index] value", + .help = "Write the 32-bit value to authdata or authdata0 (index=0), " + "or authdata1 (index=1)." }, { .name = "dmi_read", .handler = riscv_dmi_read, .mode = COMMAND_ANY, - .usage = "riscv dmi_read address", + .usage = "address", .help = "Perform a 32-bit DMI read at address, returning the value." }, { .name = "dmi_write", .handler = riscv_dmi_write, .mode = COMMAND_ANY, - .usage = "riscv dmi_write address value", + .usage = "address value", .help = "Perform a 32-bit DMI write of value at address." }, - { - .name = "test_sba_config_reg", - .handler = riscv_test_sba_config_reg, - .mode = COMMAND_ANY, - .usage = "riscv test_sba_config_reg 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." - }, { .name = "reset_delays", .handler = riscv_reset_delays, .mode = COMMAND_ANY, - .usage = "reset_delays [wait]", + .usage = "[wait]", .help = "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." }, + { + .name = "resume_order", + .handler = riscv_resume_order, + .mode = COMMAND_ANY, + .usage = "normal|reversed", + .help = "Choose the order that harts are resumed in when `hasel` is not " + "supported. Normal order is from lowest hart index to highest. " + "Reversed order is from highest hart index to lowest." + }, { .name = "set_ir", .handler = riscv_set_ir, .mode = COMMAND_ANY, - .usage = "riscv set_ir_idcode [idcode|dtmcs|dmi] value", + .usage = "[idcode|dtmcs|dmi] value", .help = "Set IR value for specified JTAG register." }, + { + .name = "use_bscan_tunnel", + .handler = riscv_use_bscan_tunnel, + .mode = COMMAND_ANY, + .usage = "value [type]", + .help = "Enable or disable use of a BSCAN tunnel to reach DM. Supply " + "the width of the DM transport TAP's instruction register to " + "enable. Supply a value of 0 to disable. Pass A second argument " + "(optional) to indicate Bscan Tunnel Type {0:(default) NESTED_TAP , " + "1: DATA_REGISTER}" + }, + { + .name = "set_enable_virt2phys", + .handler = riscv_set_enable_virt2phys, + .mode = COMMAND_ANY, + .usage = "on|off", + .help = "When on (default), enable translation from virtual address to " + "physical address." + }, + { + .name = "set_ebreakm", + .handler = riscv_set_ebreakm, + .mode = COMMAND_ANY, + .usage = "on|off", + .help = "Control dcsr.ebreakm. When off, M-mode ebreak instructions " + "don't trap to OpenOCD. Defaults to on." + }, + { + .name = "set_ebreaks", + .handler = riscv_set_ebreaks, + .mode = COMMAND_ANY, + .usage = "on|off", + .help = "Control dcsr.ebreaks. When off, S-mode ebreak instructions " + "don't trap to OpenOCD. Defaults to on." + }, + { + .name = "set_ebreaku", + .handler = riscv_set_ebreaku, + .mode = COMMAND_ANY, + .usage = "on|off", + .help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions " + "don't trap to OpenOCD. Defaults to on." + }, COMMAND_REGISTRATION_DONE }; @@ -1888,9 +3033,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, @@ -1908,14 +3052,23 @@ const struct command_registration riscv_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -unsigned riscv_address_bits(struct target *target) +static unsigned riscv_xlen_nonconst(struct target *target) +{ + return riscv_xlen(target); +} + +static unsigned int riscv_data_bits(struct target *target) { + RISCV_INFO(r); + if (r->data_bits) + return r->data_bits(target); return riscv_xlen(target); } struct target_type riscv_target = { .name = "riscv", + .target_create = riscv_create_target, .init_target = riscv_init_target, .deinit_target = riscv_deinit_target, .examine = riscv_examine, @@ -1923,8 +3076,8 @@ struct target_type riscv_target = { /* poll current target status */ .poll = old_or_new_riscv_poll, - .halt = old_or_new_riscv_halt, - .resume = old_or_new_riscv_resume, + .halt = riscv_halt, + .resume = riscv_target_resume, .step = old_or_new_riscv_step, .assert_reset = riscv_assert_reset, @@ -1932,10 +3085,17 @@ struct target_type riscv_target = { .read_memory = riscv_read_memory, .write_memory = riscv_write_memory, + .read_phys_memory = riscv_read_phys_memory, + .write_phys_memory = riscv_write_phys_memory, .checksum_memory = riscv_checksum_memory, + .mmu = riscv_mmu, + .virt2phys = riscv_virt2phys, + + .get_gdb_arch = riscv_get_gdb_arch, .get_gdb_reg_list = riscv_get_gdb_reg_list, + .get_gdb_reg_list_noread = riscv_get_gdb_reg_list_noread, .add_breakpoint = riscv_add_breakpoint, .remove_breakpoint = riscv_remove_breakpoint, @@ -1950,100 +3110,66 @@ struct target_type riscv_target = { .commands = riscv_command_handlers, - .address_bits = riscv_address_bits + .address_bits = riscv_xlen_nonconst, + .data_bits = riscv_data_bits }; /*** 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->common_magic = RISCV_COMMON_MAGIC; + r->dtm_version = 1; - r->registers_initialized = false; r->current_hartid = target->coreid; + r->version_specific = NULL; memset(r->trigger_unique_id, 0xff, sizeof(r->trigger_unique_id)); - for (size_t h = 0; h < RISCV_MAX_HARTS; ++h) { - r->xlen[h] = -1; - - for (size_t e = 0; e < RISCV_MAX_REGISTERS; ++e) - r->valid_saved_registers[h][e] = false; - } -} - -int riscv_halt_all_harts(struct target *target) -{ - for (int i = 0; i < riscv_count_harts(target); ++i) { - if (!riscv_hart_enabled(target, i)) - continue; + r->xlen = -1; - riscv_halt_one_hart(target, i); - } + 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; - riscv_invalidate_register_cache(target); + r->mem_access_progbuf_warn = true; + r->mem_access_sysbus_warn = true; + r->mem_access_abstract_warn = true; - return ERROR_OK; + INIT_LIST_HEAD(&r->expose_csr); + INIT_LIST_HEAD(&r->expose_custom); } -int riscv_halt_one_hart(struct target *target, int hartid) +static int riscv_resume_go_all_harts(struct target *target) { RISCV_INFO(r); - LOG_DEBUG("halting hart %d", hartid); - if (riscv_set_current_hartid(target, hartid) != ERROR_OK) + + LOG_DEBUG("[%s] resuming hart", target_name(target)); + if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; if (riscv_is_halted(target)) { - LOG_DEBUG(" hart %d requested halt, but was already halted", hartid); - return ERROR_OK; - } - - int result = r->halt_current_hart(target); - register_cache_invalidate(target->reg_cache); - return result; -} - -int riscv_resume_all_harts(struct target *target) -{ - for (int i = 0; i < riscv_count_harts(target); ++i) { - if (!riscv_hart_enabled(target, i)) - continue; - - riscv_resume_one_hart(target, i); + if (r->resume_go(target) != ERROR_OK) + return ERROR_FAIL; + } else { + LOG_DEBUG("[%s] hart requested resume, but was already resumed", + target_name(target)); } riscv_invalidate_register_cache(target); return ERROR_OK; } -int riscv_resume_one_hart(struct target *target, int hartid) -{ - RISCV_INFO(r); - LOG_DEBUG("resuming hart %d", hartid); - if (riscv_set_current_hartid(target, hartid) != ERROR_OK) - return ERROR_FAIL; - if (!riscv_is_halted(target)) { - LOG_DEBUG(" hart %d requested resume, but was already resumed", hartid); - return ERROR_OK; - } - - r->on_resume(target); - return r->resume_current_hart(target); -} - -int riscv_step_rtos_hart(struct target *target) +/* Steps the hart that's currently selected in the RTOS, or if there is no RTOS + * then the only hart. */ +static int riscv_step_rtos_hart(struct target *target) { RISCV_INFO(r); - int hartid = r->current_hartid; - if (riscv_rtos_enabled(target)) { - hartid = r->rtos_hartid; - if (hartid == -1) { - LOG_DEBUG("GDB has asked me to step \"any\" thread, so I'm stepping hart 0."); - hartid = 0; - } - } - if (riscv_set_current_hartid(target, hartid) != ERROR_OK) + if (riscv_select_current_hart(target) != ERROR_OK) return ERROR_FAIL; - LOG_DEBUG("stepping hart %d", hartid); + LOG_DEBUG("[%s] stepping", target_name(target)); if (!riscv_is_halted(target)) { LOG_ERROR("Hart isn't halted before single step!"); @@ -2062,7 +3188,7 @@ int riscv_step_rtos_hart(struct target *target) return ERROR_OK; } -bool riscv_supports_extension(struct target *target, int hartid, char letter) +bool riscv_supports_extension(struct target *target, char letter) { RISCV_INFO(r); unsigned num; @@ -2072,25 +3198,13 @@ bool riscv_supports_extension(struct target *target, int hartid, char letter) num = letter - 'A'; else return false; - return r->misa[hartid] & (1 << num); -} - -int riscv_xlen(const struct target *target) -{ - return riscv_xlen_of_hart(target, riscv_current_hartid(target)); + return r->misa & BIT(num); } -int riscv_xlen_of_hart(const struct target *target, int hartid) +unsigned riscv_xlen(const struct target *target) { RISCV_INFO(r); - assert(r->xlen[hartid] != -1); - return r->xlen[hartid]; -} - -extern struct rtos_type riscv_rtos; -bool riscv_rtos_enabled(const struct target *target) -{ - return false; + return r->xlen; } int riscv_set_current_hartid(struct target *target, int hartid) @@ -2101,31 +3215,22 @@ int riscv_set_current_hartid(struct target *target, int hartid) int previous_hartid = riscv_current_hartid(target); r->current_hartid = hartid; - assert(riscv_hart_enabled(target, hartid)); LOG_DEBUG("setting hartid to %d, was %d", hartid, previous_hartid); if (r->select_current_hart(target) != ERROR_OK) return ERROR_FAIL; - /* This might get called during init, in which case we shouldn't be - * setting up the register cache. */ - if (target_was_examined(target) && riscv_rtos_enabled(target)) - riscv_invalidate_register_cache(target); - return ERROR_OK; } -void riscv_invalidate_register_cache(struct target *target) +/* Invalidates the register cache. */ +static void riscv_invalidate_register_cache(struct target *target) { - RISCV_INFO(r); - LOG_DEBUG("[%d]", target->coreid); 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; } - - r->registers_initialized = true; } int riscv_current_hartid(const struct target *target) @@ -2134,74 +3239,130 @@ int riscv_current_hartid(const struct target *target) return r->current_hartid; } -void riscv_set_all_rtos_harts(struct target *target) -{ - RISCV_INFO(r); - r->rtos_hartid = -1; -} - -void riscv_set_rtos_hartid(struct target *target, int hartid) -{ - LOG_DEBUG("setting RTOS hartid %d", hartid); - RISCV_INFO(r); - r->rtos_hartid = hartid; -} - int riscv_count_harts(struct target *target) { - if (target == NULL) + if (!target) return 1; RISCV_INFO(r); - if (r == NULL) + if (!r || !r->hart_count) return 1; - return r->hart_count; + return r->hart_count(target); } -bool riscv_has_register(struct target *target, int hartid, int regid) +/** + * If write is true: + * return true iff we are guaranteed that the register will contain exactly + * the value we just wrote when it's read. + * If write is false: + * 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) { - return 1; + /* GPRs, FPRs, vector registers are just normal data stores. */ + if (regno <= GDB_REGNO_XPR31 || + (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) || + (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31)) + return true; + + /* Most CSRs won't change value on us, but we can't assume it about arbitrary + * CSRs. */ + switch (regno) { + case GDB_REGNO_DPC: + return true; + + case GDB_REGNO_VSTART: + case GDB_REGNO_VXSAT: + case GDB_REGNO_VXRM: + case GDB_REGNO_VLENB: + case GDB_REGNO_VL: + case GDB_REGNO_VTYPE: + case GDB_REGNO_MISA: + case GDB_REGNO_DCSR: + case GDB_REGNO_DSCRATCH0: + case GDB_REGNO_MSTATUS: + case GDB_REGNO_MEPC: + case GDB_REGNO_MCAUSE: + case GDB_REGNO_SATP: + /* + * WARL registers might not contain the value we just wrote, but + * these ones won't spontaneously change their value either. * + */ + return !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. */ + 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 r, riscv_reg_t v) -{ - return riscv_set_register_on_hart(target, riscv_current_hartid(target), r, v); -} - -int riscv_set_register_on_hart(struct target *target, int hartid, - enum gdb_regno regid, uint64_t value) +int riscv_set_register(struct target *target, enum gdb_regno regid, riscv_reg_t value) { RISCV_INFO(r); - LOG_DEBUG("{%d} %s <- %" PRIx64, hartid, gdb_regno_name(regid), value); + LOG_DEBUG("[%s] %s <- %" PRIx64, target_name(target), gdb_regno_name(regid), value); assert(r->set_register); - return r->set_register(target, hartid, regid, value); -} -int riscv_get_register(struct target *target, riscv_reg_t *value, - enum gdb_regno r) -{ - return riscv_get_register_on_hart(target, value, - riscv_current_hartid(target), r); + 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; + + struct reg *reg = &target->reg_cache->reg_list[regid]; + buf_set_u64(reg->value, 0, reg->size, value); + + int result = r->set_register(target, regid, value); + if (result == ERROR_OK) + reg->valid = gdb_regno_cacheable(regid, true); + else + reg->valid = false; + LOG_DEBUG("[%s] wrote 0x%" PRIx64 " to %s valid=%d", + target_name(target), value, reg->name, reg->valid); + return result; } -int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value, - int hartid, enum gdb_regno regid) +int riscv_get_register(struct target *target, riscv_reg_t *value, + enum gdb_regno regid) { RISCV_INFO(r); + keep_alive(); + struct reg *reg = &target->reg_cache->reg_list[regid]; + if (!reg->exist) { + LOG_DEBUG("[%s] %s does not exist.", + target_name(target), gdb_regno_name(regid)); + return ERROR_FAIL; + } - if (reg && reg->valid && hartid == riscv_current_hartid(target)) { + if (reg && 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; return ERROR_OK; } - int result = r->get_register(target, value, hartid, regid); + int result = r->get_register(target, value, regid); - LOG_DEBUG("{%d} %s: %" PRIx64, hartid, gdb_regno_name(regid), *value); + if (result == ERROR_OK) + reg->valid = gdb_regno_cacheable(regid, false); + + LOG_DEBUG("[%s] %s: %" PRIx64, target_name(target), + gdb_regno_name(regid), *value); return result; } @@ -2212,7 +3373,7 @@ bool riscv_is_halted(struct target *target) return r->is_halted(target); } -enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid) +static enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid) { RISCV_INFO(r); if (riscv_set_current_hartid(target, hartid) != ERROR_OK) @@ -2227,7 +3388,7 @@ enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid) size_t riscv_debug_buffer_size(struct target *target) { RISCV_INFO(r); - return r->debug_buffer_size[riscv_current_hartid(target)]; + return r->debug_buffer_size; } int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn) @@ -2273,15 +3434,6 @@ int riscv_dmi_write_u64_bits(struct target *target) return r->dmi_write_u64_bits(target); } -bool riscv_hart_enabled(struct target *target, int hartid) -{ - /* FIXME: Add a hart mask to the RTOS. */ - if (riscv_rtos_enabled(target)) - return hartid < riscv_count_harts(target); - - return hartid == target->coreid; -} - /** * Count triggers, and initialize trigger_count for each hart. * trigger_count is initialized even if this function fails to discover @@ -2298,54 +3450,61 @@ int riscv_enumerate_triggers(struct target *target) r->triggers_enumerated = true; /* At the very least we tried. */ - for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) { - if (!riscv_hart_enabled(target, hartid)) - continue; + riscv_reg_t tselect; + int result = riscv_get_register(target, &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. */ + if (result != ERROR_OK) { + LOG_DEBUG("[%s] Cannot access tselect register. " + "Assuming that triggers are not implemented.", target_name(target)); + r->trigger_count = 0; + return ERROR_OK; + } - riscv_reg_t tselect; - int result = riscv_get_register_on_hart(target, &tselect, hartid, - GDB_REGNO_TSELECT); + 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) + break; + uint64_t tdata1; + result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1); if (result != ERROR_OK) return result; - for (unsigned t = 0; t < RISCV_MAX_TRIGGERS; ++t) { - r->trigger_count[hartid] = t; - - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, t); - uint64_t tselect_rb; - result = riscv_get_register_on_hart(target, &tselect_rb, hartid, - 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) + int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); + if (type == 0) + 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 & MCONTROL_DMODE(riscv_xlen(target))) + riscv_set_register(target, GDB_REGNO_TDATA1, 0); + break; + case 6: + if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) + riscv_set_register(target, GDB_REGNO_TDATA1, 0); break; - uint64_t tdata1; - result = riscv_get_register_on_hart(target, &tdata1, hartid, - GDB_REGNO_TDATA1); - if (result != ERROR_OK) - return result; - - int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); - switch (type) { - case 1: - /* On these older cores we don't support software using - * triggers. */ - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); - break; - case 2: - if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); - break; - } } + } - riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, tselect); + riscv_set_register(target, GDB_REGNO_TSELECT, tselect); - LOG_INFO("[%d] Found %d triggers", hartid, r->trigger_count[hartid]); - } + LOG_INFO("[%s] Found %d triggers", target_name(target), r->trigger_count); return ERROR_OK; } @@ -2357,10 +3516,68 @@ const char *gdb_regno_name(enum gdb_regno regno) 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: @@ -2381,12 +3598,86 @@ const char *gdb_regno_name(enum gdb_regno regno) return "dpc"; case GDB_REGNO_DCSR: return "dcsr"; - case GDB_REGNO_DSCRATCH: - return "dscratch"; + 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); @@ -2404,20 +3695,29 @@ static int register_get(struct reg *reg) { riscv_reg_info_t *reg_info = reg->arch_info; struct target *target = reg_info->target; - uint64_t value; - int result = riscv_get_register(target, &value, reg->number); - if (result != ERROR_OK) - return result; - buf_set_u64(reg->value, 0, reg->size, value); - /* CSRs (and possibly other extension) registers may change value at any - * time. */ - if (reg->number <= GDB_REGNO_XPR31 || - (reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) || - reg->number == GDB_REGNO_PC) - reg->valid = true; - LOG_DEBUG("[%d]{%d} read 0x%" PRIx64 " from %s (valid=%d)", - target->coreid, riscv_current_hartid(target), value, reg->name, - reg->valid); + RISCV_INFO(r); + + 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)); + return ERROR_FAIL; + } + + if (r->get_register_buf(target, reg->value, reg->number) != ERROR_OK) + return ERROR_FAIL; + } else { + uint64_t value; + int result = riscv_get_register(target, &value, reg->number); + if (result != ERROR_OK) + 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); + free(str); return ERROR_OK; } @@ -2425,22 +3725,47 @@ 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; + 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); + 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) + 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; + /* When enumerating triggers, we clear any triggers with DMODE set, + * assuming they were left over from a previous debug session. So make + * sure that is done before a user might be setting their own triggers. + */ + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + } + + 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)); + return ERROR_FAIL; + } + + if (r->set_register_buf(target, reg->number, reg->value) != ERROR_OK) + return ERROR_FAIL; + } else { + uint64_t value = buf_get_u64(buf, 0, reg->size); + if (riscv_set_register(target, reg->number, value) != ERROR_OK) + return ERROR_FAIL; + } - uint64_t value = buf_get_u64(buf, 0, reg->size); - - LOG_DEBUG("[%d]{%d} write 0x%" PRIx64 " to %s (valid=%d)", - target->coreid, riscv_current_hartid(target), value, reg->name, - reg->valid); - struct reg *r = &target->reg_cache->reg_list[reg->number]; - /* CSRs (and possibly other extension) registers may change value at any - * time. */ - if (reg->number <= GDB_REGNO_XPR31 || - (reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) || - reg->number == GDB_REGNO_PC) - r->valid = true; - memcpy(r->value, buf, (r->size + 7) / 8); - - riscv_set_register(target, reg->number, value); return ERROR_OK; } @@ -2466,16 +3791,15 @@ int riscv_init_registers(struct target *target) riscv_free_registers(target); target->reg_cache = calloc(1, sizeof(*target->reg_cache)); + if (!target->reg_cache) + return ERROR_FAIL; target->reg_cache->name = "RISC-V Registers"; target->reg_cache->num_regs = GDB_REGNO_COUNT; - if (expose_custom) { - for (unsigned i = 0; expose_custom[i].low <= expose_custom[i].high; i++) { - for (unsigned number = expose_custom[i].low; - number <= expose_custom[i].high; - number++) - target->reg_cache->num_regs++; - } + 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; } LOG_DEBUG("create register cache for %d registers", @@ -2483,11 +3807,15 @@ int riscv_init_registers(struct target *target) 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) + return ERROR_FAIL; char *reg_name = info->reg_names; static struct reg_feature feature_cpu = { @@ -2499,6 +3827,9 @@ int riscv_init_registers(struct target *target) static struct reg_feature feature_csr = { .name = "org.gnu.gdb.riscv.csr" }; + static struct reg_feature feature_vector = { + .name = "org.gnu.gdb.riscv.vector" + }; static struct reg_feature feature_virtual = { .name = "org.gnu.gdb.riscv.virtual" }; @@ -2506,27 +3837,131 @@ int riscv_init_registers(struct target *target) .name = "org.gnu.gdb.riscv.custom" }; - static struct reg_data_type type_ieee_single = { - .type = REG_TYPE_IEEE_SINGLE, - .id = "ieee_single" + /* These types are built into gdb. */ + static struct reg_data_type type_ieee_single = { .type = REG_TYPE_IEEE_SINGLE, .id = "ieee_single" }; + static struct reg_data_type type_ieee_double = { .type = REG_TYPE_IEEE_DOUBLE, .id = "ieee_double" }; + static struct reg_data_type_union_field single_double_fields[] = { + {"float", &type_ieee_single, single_double_fields + 1}, + {"double", &type_ieee_double, NULL}, + }; + static struct reg_data_type_union single_double_union = { + .fields = single_double_fields }; - static struct reg_data_type type_ieee_double = { - .type = REG_TYPE_IEEE_DOUBLE, - .id = "ieee_double" + static struct reg_data_type type_ieee_single_double = { + .type = REG_TYPE_ARCH_DEFINED, + .id = "FPU_FD", + .type_class = REG_TYPE_CLASS_UNION, + { .reg_type_union = &single_double_union } }; + static struct reg_data_type type_uint8 = { .type = REG_TYPE_UINT8, .id = "uint8" }; + static struct reg_data_type type_uint16 = { .type = REG_TYPE_UINT16, .id = "uint16" }; + static struct reg_data_type type_uint32 = { .type = REG_TYPE_UINT32, .id = "uint32" }; + static struct reg_data_type type_uint64 = { .type = REG_TYPE_UINT64, .id = "uint64" }; + static struct reg_data_type type_uint128 = { .type = REG_TYPE_UINT128, .id = "uint128" }; + + /* This is roughly the XML we want: + * <vector id="bytes" type="uint8" count="16"/> + * <vector id="shorts" type="uint16" count="8"/> + * <vector id="words" type="uint32" count="4"/> + * <vector id="longs" type="uint64" count="2"/> + * <vector id="quads" type="uint128" count="1"/> + * <union id="riscv_vector_type"> + * <field name="b" type="bytes"/> + * <field name="s" type="shorts"/> + * <field name="w" type="words"/> + * <field name="l" type="longs"/> + * <field name="q" type="quads"/> + * </union> + */ + + info->vector_uint8.type = &type_uint8; + info->vector_uint8.count = info->vlenb; + info->type_uint8_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_uint8_vector.id = "bytes"; + info->type_uint8_vector.type_class = REG_TYPE_CLASS_VECTOR; + info->type_uint8_vector.reg_type_vector = &info->vector_uint8; + + info->vector_uint16.type = &type_uint16; + info->vector_uint16.count = info->vlenb / 2; + info->type_uint16_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_uint16_vector.id = "shorts"; + info->type_uint16_vector.type_class = REG_TYPE_CLASS_VECTOR; + info->type_uint16_vector.reg_type_vector = &info->vector_uint16; + + info->vector_uint32.type = &type_uint32; + info->vector_uint32.count = info->vlenb / 4; + info->type_uint32_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_uint32_vector.id = "words"; + info->type_uint32_vector.type_class = REG_TYPE_CLASS_VECTOR; + info->type_uint32_vector.reg_type_vector = &info->vector_uint32; + + info->vector_uint64.type = &type_uint64; + info->vector_uint64.count = info->vlenb / 8; + info->type_uint64_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_uint64_vector.id = "longs"; + info->type_uint64_vector.type_class = REG_TYPE_CLASS_VECTOR; + info->type_uint64_vector.reg_type_vector = &info->vector_uint64; + + info->vector_uint128.type = &type_uint128; + info->vector_uint128.count = info->vlenb / 16; + info->type_uint128_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_uint128_vector.id = "quads"; + info->type_uint128_vector.type_class = REG_TYPE_CLASS_VECTOR; + info->type_uint128_vector.reg_type_vector = &info->vector_uint128; + + info->vector_fields[0].name = "b"; + info->vector_fields[0].type = &info->type_uint8_vector; + if (info->vlenb >= 2) { + info->vector_fields[0].next = info->vector_fields + 1; + info->vector_fields[1].name = "s"; + info->vector_fields[1].type = &info->type_uint16_vector; + } else { + info->vector_fields[0].next = NULL; + } + if (info->vlenb >= 4) { + info->vector_fields[1].next = info->vector_fields + 2; + info->vector_fields[2].name = "w"; + info->vector_fields[2].type = &info->type_uint32_vector; + } else { + info->vector_fields[1].next = NULL; + } + if (info->vlenb >= 8) { + info->vector_fields[2].next = info->vector_fields + 3; + info->vector_fields[3].name = "l"; + info->vector_fields[3].type = &info->type_uint64_vector; + } else { + info->vector_fields[2].next = NULL; + } + if (info->vlenb >= 16) { + info->vector_fields[3].next = info->vector_fields + 4; + info->vector_fields[4].name = "q"; + info->vector_fields[4].type = &info->type_uint128_vector; + } else { + info->vector_fields[3].next = NULL; + } + info->vector_fields[4].next = NULL; + + info->vector_union.fields = info->vector_fields; + + info->type_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_vector.id = "riscv_vector"; + 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, DIM(csr_info), sizeof(*csr_info), cmp_csr_info); + qsort(csr_info, ARRAY_SIZE(csr_info), sizeof(*csr_info), cmp_csr_info); unsigned csr_info_index = 0; - unsigned custom_range_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; /* When gdb requests register N, gdb_get_register_packet() assumes that this @@ -2547,6 +3982,11 @@ int riscv_init_registers(struct target *target) * 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 || + !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: @@ -2655,12 +4095,13 @@ int riscv_init_registers(struct target *target) r->feature = &feature_cpu; } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { r->caller_save = true; - if (riscv_supports_extension(target, riscv_current_hartid(target), - 'D')) { - r->reg_data_type = &type_ieee_double; + if (riscv_supports_extension(target, 'D')) { r->size = 64; - } else if (riscv_supports_extension(target, - riscv_current_hartid(target), 'F')) { + if (riscv_supports_extension(target, 'F')) + r->reg_data_type = &type_ieee_single_double; + else + r->reg_data_type = &type_ieee_double; + } else if (riscv_supports_extension(target, 'F')) { r->reg_data_type = &type_ieee_single; r->size = 32; } else { @@ -2772,7 +4213,7 @@ int riscv_init_registers(struct target *target) unsigned csr_number = number - GDB_REGNO_CSR0; while (csr_info[csr_info_index].number < csr_number && - csr_info_index < DIM(csr_info) - 1) { + csr_info_index < ARRAY_SIZE(csr_info) - 1) { csr_info_index++; } if (csr_info[csr_info_index].number == csr_number) { @@ -2791,8 +4232,7 @@ int riscv_init_registers(struct target *target) case CSR_FFLAGS: case CSR_FRM: case CSR_FCSR: - r->exist = riscv_supports_extension(target, - riscv_current_hartid(target), 'F'); + r->exist = riscv_supports_extension(target, 'F'); r->group = "float"; r->feature = &feature_fpu; break; @@ -2806,18 +4246,19 @@ int riscv_init_registers(struct target *target) case CSR_SCAUSE: case CSR_STVAL: case CSR_SATP: - r->exist = riscv_supports_extension(target, - riscv_current_hartid(target), 'S'); + r->exist = riscv_supports_extension(target, 'S'); break; case CSR_MEDELEG: case CSR_MIDELEG: /* "In systems with only M-mode, or with both M-mode and * U-mode but without U-mode trap support, the medeleg and * mideleg registers should not exist." */ - r->exist = riscv_supports_extension(target, riscv_current_hartid(target), 'S') || - riscv_supports_extension(target, riscv_current_hartid(target), 'N'); + r->exist = riscv_supports_extension(target, 'S') || + riscv_supports_extension(target, 'N'); break; + case CSR_PMPCFG1: + case CSR_PMPCFG3: case CSR_CYCLEH: case CSR_TIMEH: case CSR_INSTRETH: @@ -2883,16 +4324,32 @@ int riscv_init_registers(struct target *target) case CSR_MHPMCOUNTER31H: r->exist = riscv_xlen(target) == 32; break; + + case CSR_VSTART: + case CSR_VXSAT: + case CSR_VXRM: + case CSR_VL: + case CSR_VTYPE: + case CSR_VLENB: + r->exist = riscv_supports_extension(target, 'V'); + break; } - if (!r->exist && expose_csr) { - for (unsigned i = 0; expose_csr[i].low <= expose_csr[i].high; i++) { - if (csr_number >= expose_csr[i].low && csr_number <= expose_csr[i].high) { - LOG_INFO("Exposing additional CSR %d", csr_number); + 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); + r->exist = true; break; } - } } } else if (number == GDB_REGNO_PRIV) { @@ -2901,36 +4358,95 @@ int riscv_init_registers(struct target *target) r->feature = &feature_virtual; r->size = 8; - } else { + } else if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) { + r->caller_save = false; + r->exist = riscv_supports_extension(target, 'V') && info->vlenb; + 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) { /* Custom registers. */ - assert(expose_custom); + assert(!list_empty(&info->expose_custom)); + + range_list_t *range = list_first_entry(&info->expose_custom, range_list_t, list); - range_t *range = &expose_custom[custom_range_index]; - assert(range->low <= range->high); unsigned custom_number = range->low + custom_within_range; r->group = "custom"; r->feature = &feature_custom; r->arch_info = calloc(1, sizeof(riscv_reg_info_t)); - assert(r->arch_info); + if (!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; + } + + LOG_DEBUG("Exposing additional custom register %d (name=%s)", + number, range->name ? range->name : reg_name); + custom_within_range++; if (custom_within_range > range->high - range->low) { custom_within_range = 0; - custom_range_index++; + list_rotate_left(&info->expose_custom); } } - if (reg_name[0]) + 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 = &info->reg_cache_values[number]; + 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)); } return ERROR_OK; } + + +void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field, + riscv_bscan_tunneled_scan_context_t *ctxt) +{ + jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE); + + memset(ctxt->tunneled_dr, 0, sizeof(ctxt->tunneled_dr)); + if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) { + ctxt->tunneled_dr[3].num_bits = 1; + ctxt->tunneled_dr[3].out_value = bscan_one; + ctxt->tunneled_dr[2].num_bits = 7; + ctxt->tunneled_dr_width = field->num_bits; + ctxt->tunneled_dr[2].out_value = &ctxt->tunneled_dr_width; + /* for BSCAN tunnel, there is a one-TCK skew between shift in and shift out, so + scanning num_bits + 1, and then will right shift the input field after executing the queues */ + + ctxt->tunneled_dr[1].num_bits = field->num_bits + 1; + ctxt->tunneled_dr[1].out_value = field->out_value; + ctxt->tunneled_dr[1].in_value = field->in_value; + + ctxt->tunneled_dr[0].num_bits = 3; + ctxt->tunneled_dr[0].out_value = bscan_zero; + } else { + /* BSCAN_TUNNEL_NESTED_TAP */ + ctxt->tunneled_dr[0].num_bits = 1; + ctxt->tunneled_dr[0].out_value = bscan_one; + ctxt->tunneled_dr[1].num_bits = 7; + ctxt->tunneled_dr_width = field->num_bits; + ctxt->tunneled_dr[1].out_value = &ctxt->tunneled_dr_width; + /* for BSCAN tunnel, there is a one-TCK skew between shift in and shift out, so + scanning num_bits + 1, and then will right shift the input field after executing the queues */ + ctxt->tunneled_dr[2].num_bits = field->num_bits + 1; + ctxt->tunneled_dr[2].out_value = field->out_value; + ctxt->tunneled_dr[2].in_value = field->in_value; + ctxt->tunneled_dr[3].num_bits = 3; + ctxt->tunneled_dr[3].out_value = bscan_zero; + } + jtag_add_dr_scan(target->tap, ARRAY_SIZE(ctxt->tunneled_dr), ctxt->tunneled_dr, TAP_IDLE); +} diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index ba50d2c514..aba0864e6d 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + #ifndef RISCV_H #define RISCV_H @@ -6,9 +8,15 @@ struct riscv_program; #include <stdint.h> #include "opcodes.h" #include "gdb_regs.h" +#include "jtag/jtag.h" +#include "target/register.h" +#include "target/semihosting_common.h" +#include <helper/command.h> + +#define RISCV_COMMON_MAGIC 0x52495356U /* The register cache is statically allocated. */ -#define RISCV_MAX_HARTS 32 +#define RISCV_MAX_HARTS 1024 #define RISCV_MAX_REGISTERS 5000 #define RISCV_MAX_TRIGGERS 32 #define RISCV_MAX_HWBPS 16 @@ -16,6 +24,14 @@ struct riscv_program; #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_PGSHIFT 12 + +# define PG_MAX_LEVEL 4 + +#define RISCV_NUM_MEM_ACCESS_METHODS 3 + extern struct target_type riscv011_target; extern struct target_type riscv013_target; @@ -26,12 +42,20 @@ typedef uint64_t riscv_reg_t; typedef uint32_t riscv_insn_t; typedef uint64_t riscv_addr_t; +enum riscv_mem_access_method { + RISCV_MEM_ACCESS_UNSPECIFIED, + RISCV_MEM_ACCESS_PROGBUF, + RISCV_MEM_ACCESS_SYSBUS, + RISCV_MEM_ACCESS_ABSTRACT +}; + enum riscv_halt_reason { RISCV_HALT_INTERRUPT, RISCV_HALT_BREAKPOINT, RISCV_HALT_SINGLESTEP, RISCV_HALT_TRIGGER, RISCV_HALT_UNKNOWN, + RISCV_HALT_GROUP, RISCV_HALT_ERROR }; @@ -40,44 +64,55 @@ typedef struct { unsigned custom_number; } riscv_reg_info_t; +#define RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE 0x80 +#define RISCV_SAMPLE_BUF_TIMESTAMP_AFTER 0x81 +struct riscv_sample_buf { + uint8_t *buf; + unsigned int used; + unsigned int size; +}; + +typedef struct { + bool enabled; + struct { + bool enabled; + target_addr_t address; + uint32_t size_bytes; + } bucket[16]; +} riscv_sample_config_t; + typedef struct { + struct list_head list; + uint16_t low, high; + char *name; +} range_list_t; + +struct riscv_info { + unsigned int common_magic; + unsigned dtm_version; struct command_context *cmd_ctx; void *version_specific; - /* The number of harts on this system. */ - int hart_count; - - /* The hart that the RTOS thinks is currently being debugged. */ - int rtos_hartid; - /* The hart that is currently being debugged. Note that this is * different than the hartid that the RTOS is expected to use. This * one will change all the time, it's more of a global argument to * every function than an actual */ int current_hartid; - /* Enough space to store all the registers we might need to save. */ - /* FIXME: This should probably be a bunch of register caches. */ - uint64_t saved_registers[RISCV_MAX_HARTS][RISCV_MAX_REGISTERS]; - bool valid_saved_registers[RISCV_MAX_HARTS][RISCV_MAX_REGISTERS]; - - /* OpenOCD's register cache points into here. This is not per-hart because - * we just invalidate the entire cache when we change which hart is - * selected. */ - uint64_t reg_cache_values[RISCV_MAX_REGISTERS]; - /* 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; /* It's possible that each core has a different supported ISA set. */ - int xlen[RISCV_MAX_HARTS]; - riscv_reg_t misa[RISCV_MAX_HARTS]; + int xlen; + riscv_reg_t misa; + /* Cached value of vlenb. 0 if vlenb is not readable for some reason. */ + unsigned int vlenb; /* The number of triggers per hart. */ - unsigned trigger_count[RISCV_MAX_HARTS]; + 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. @@ -86,10 +121,7 @@ typedef struct { int trigger_unique_id[RISCV_MAX_HWBPS]; /* The number of entries in the debug buffer. */ - int debug_buffer_size[RISCV_MAX_HARTS]; - - /* This avoids invalidating the register cache too often. */ - bool registers_initialized; + int debug_buffer_size; /* This hart contains an implicit ebreak at the end of the program buffer. */ bool impebreak; @@ -100,19 +132,31 @@ typedef struct { * delays, causing them to be relearned. Used for testing. */ int reset_delays_wait; + /* This target has been prepped and is ready to step/resume. */ + bool prepped; + /* This target was selected using hasel. */ + bool selected; + /* Helper functions that target the various RISC-V debug spec * implementations. */ - int (*get_register)(struct target *target, - riscv_reg_t *value, int hid, int rid); - int (*set_register)(struct target *target, int hartid, int regid, - uint64_t value); + 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, + const uint8_t *buf); int (*select_current_hart)(struct target *target); bool (*is_halted)(struct target *target); - int (*halt_current_hart)(struct target *target); - int (*resume_current_hart)(struct target *target); + /* 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); - int (*on_resume)(struct target *target); + /* Get this target as ready as possible to resume, without actually + * resuming. */ + int (*resume_prep)(struct target *target); + int (*halt_prep)(struct target *target); + 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, @@ -124,17 +168,86 @@ typedef struct { void (*fill_dmi_read_u64)(struct target *target, char *buf, int a); void (*fill_dmi_nop_u64)(struct target *target, char *buf); - int (*authdata_read)(struct target *target, uint32_t *value); - int (*authdata_write)(struct target *target, uint32_t value); + int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index); + int (*authdata_write)(struct target *target, uint32_t value, unsigned int index); 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); + int (*sample_memory)(struct target *target, + struct riscv_sample_buf *buf, + riscv_sample_config_t *config, + int64_t until_ms); + + 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); + + /* Storage for vector register types. */ + struct reg_data_type_vector vector_uint8; + struct reg_data_type_vector vector_uint16; + struct reg_data_type_vector vector_uint32; + struct reg_data_type_vector vector_uint64; + struct reg_data_type_vector vector_uint128; + struct reg_data_type type_uint8_vector; + struct reg_data_type type_uint16_vector; + struct reg_data_type type_uint32_vector; + struct reg_data_type type_uint64_vector; + struct reg_data_type type_uint128_vector; + struct reg_data_type_union_field vector_fields[5]; + struct reg_data_type_union vector_union; + struct reg_data_type type_vector; + + /* Set when trigger registers are changed by the user. This indicates we eed + * to beware that we may hit a trigger that we didn't realize had been set. */ + bool manual_hwbp_set; + + /* Memory access methods to use, ordered by priority, highest to lowest. */ + int mem_access_methods[RISCV_NUM_MEM_ACCESS_METHODS]; + + /* Different memory regions may need different methods but single configuration is applied + * for all. Following flags are used to warn only once about failing memory access method. */ + bool mem_access_progbuf_warn; + bool mem_access_sysbus_warn; + bool mem_access_abstract_warn; + + /* In addition to the ones in the standard spec, we'll also expose additional + * CSRs in this list. */ + struct list_head expose_csr; + /* Same, but for custom registers. + * Custom registers are for non-standard extensions and use abstract register numbers + * from range 0xc000 ... 0xffff. */ + struct list_head expose_custom; + + riscv_sample_config_t sample_config; + struct riscv_sample_buf sample_buf; +}; + +COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key, + unsigned int value); - int (*test_compliance)(struct target *target); -} riscv_info_t; +typedef struct { + uint8_t tunneled_dr_width; + struct scan_field tunneled_dr[4]; +} riscv_bscan_tunneled_scan_context_t; + +typedef struct { + const char *name; + int level; + unsigned va_bits; + unsigned pte_shift; + unsigned vpn_shift[PG_MAX_LEVEL]; + unsigned vpn_mask[PG_MAX_LEVEL]; + unsigned pte_ppn_shift[PG_MAX_LEVEL]; + unsigned pte_ppn_mask[PG_MAX_LEVEL]; + unsigned pa_ppn_shift[PG_MAX_LEVEL]; + unsigned pa_ppn_mask[PG_MAX_LEVEL]; +} virt2phys_info_t; /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ extern int riscv_command_timeout_sec; @@ -142,34 +255,42 @@ extern int riscv_command_timeout_sec; /* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ extern int riscv_reset_timeout_sec; -extern bool riscv_prefer_sba; +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) -{ return target->arch_info; } -#define RISCV_INFO(R) riscv_info_t *R = riscv_info(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) 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 *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; + +uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out); +void select_dmi_via_bscan(struct target *target); + /*** OpenOCD Interface */ int riscv_openocd_poll(struct target *target); -int riscv_openocd_halt(struct target *target); - -int riscv_openocd_resume( - struct target *target, - int current, - target_addr_t address, - int handle_breakpoints, - int debug_execution -); +int riscv_halt(struct target *target); int riscv_openocd_step( struct target *target, @@ -183,62 +304,34 @@ 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); - -/* Run control, possibly for multiple harts. The _all_harts versions resume - * all the enabled harts, which when running in RTOS mode is all the harts on - * the system. */ -int riscv_halt_all_harts(struct target *target); -int riscv_halt_one_hart(struct target *target, int hartid); -int riscv_resume_all_harts(struct target *target); -int riscv_resume_one_hart(struct target *target, int hartid); - -/* 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, int hartid, char letter); +bool riscv_supports_extension(struct target *target, char letter); /* Returns XLEN for the given (or current) hart. */ -int riscv_xlen(const struct target *target); -int riscv_xlen_of_hart(const struct target *target, int hartid); - -bool riscv_rtos_enabled(const struct target *target); +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. */ -/* When using the RTOS to debug, this selects the hart that is currently being - * debugged. This doesn't propagate to the hardware. */ -void riscv_set_all_rtos_harts(struct target *target); -void riscv_set_rtos_hartid(struct target *target, int hartid); - /* Lists the number of harts in the system, which are assumed to be * consecutive and start with mhartid=0. */ int riscv_count_harts(struct target *target); -/* Returns TRUE if the target has the given register on the given hart. */ -bool riscv_has_register(struct target *target, int hartid, int regid); - -/* Returns the value of the given register on the given hart. 32-bit registers - * are zero extended to 64 bits. */ +/** Set register, updating the cache. */ int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v); -int riscv_set_register_on_hart(struct target *target, int hid, enum gdb_regno rid, uint64_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); -int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value, - int hartid, enum gdb_regno regid); /* 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 hartid); /* These helper functions let the generic program interface get target-specific * information. */ @@ -253,25 +346,22 @@ void riscv_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t void riscv_fill_dmi_read_u64(struct target *target, char *buf, int a); int riscv_dmi_write_u64_bits(struct target *target); -/* Invalidates the register cache. */ -void riscv_invalidate_register_cache(struct target *target); - -/* Returns TRUE when a hart is enabled in this target. */ -bool riscv_hart_enabled(struct target *target, int hartid); - 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); -int 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); + +int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); +int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); #endif diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c index c4b6653729..da237ef337 100644 --- a/src/target/riscv/riscv_semihosting.c +++ b/src/target/riscv/riscv_semihosting.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/>. * ***************************************************************************/ /** @@ -39,10 +28,9 @@ #include "config.h" #endif -#include "log.h" +#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); @@ -60,35 +48,38 @@ void riscv_semihosting_init(struct target *target) /** * Check for and process a semihosting request using the ARM protocol). 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 target to process. * @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 */ -int riscv_semihosting(struct target *target, int *retval) +enum semihosting_result riscv_semihosting(struct target *target, int *retval) { struct semihosting *semihosting = target->semihosting; - if (!semihosting) - return 0; + if (!semihosting) { + LOG_DEBUG(" -> NONE (!semihosting)"); + return SEMIHOSTING_NONE; + } - if (!semihosting->is_active) - return 0; + if (!semihosting->is_active) { + LOG_DEBUG(" -> NONE (!semihosting->is_active)"); + return SEMIHOSTING_NONE; + } - riscv_reg_t dpc; - int result = riscv_get_register(target, &dpc, GDB_REGNO_DPC); + riscv_reg_t pc; + int result = riscv_get_register(target, &pc, GDB_REGNO_PC); if (result != ERROR_OK) - return 0; + return SEMIHOSTING_ERROR; - uint8_t tmp[12]; + uint8_t tmp_buf[12]; - /* Read the current instruction, including the bracketing */ - *retval = target_read_memory(target, dpc - 4, 2, 6, tmp); - if (*retval != ERROR_OK) - return 0; + /* Read three uncompressed instructions: The previous, the current one (pointed to by PC) and the next one */ + for (int i = 0; i < 3; i++) { + /* 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); + if (*retval != ERROR_OK) + return SEMIHOSTING_ERROR; + } /* * The instructions that trigger a semihosting call, @@ -98,15 +89,15 @@ int riscv_semihosting(struct target *target, int *retval) * 00100073 ebreak * 40705013 srai zero,zero,0x7 */ - uint32_t pre = target_buffer_get_u32(target, tmp); - uint32_t ebreak = target_buffer_get_u32(target, tmp + 4); - uint32_t post = target_buffer_get_u32(target, tmp + 8); - LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, dpc); + 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. */ - return 0; + LOG_DEBUG(" -> NONE (no magic)"); + return SEMIHOSTING_NONE; } /* @@ -114,52 +105,58 @@ int riscv_semihosting(struct target *target, int *retval) * operation to complete. */ if (!semihosting->hit_fileio) { - /* RISC-V uses A0 and A1 to pass function arguments */ riscv_reg_t r0; riscv_reg_t r1; result = riscv_get_register(target, &r0, GDB_REGNO_A0); - if (result != ERROR_OK) - return 0; + if (result != ERROR_OK) { + LOG_DEBUG(" -> ERROR (couldn't read a0)"); + return SEMIHOSTING_ERROR; + } result = riscv_get_register(target, &r1, GDB_REGNO_A1); - if (result != ERROR_OK) - return 0; + if (result != ERROR_OK) { + LOG_DEBUG(" -> ERROR (couldn't read a1)"); + return SEMIHOSTING_ERROR; + } semihosting->op = r0; semihosting->param = r1; semihosting->word_size_bytes = riscv_xlen(target) / 8; /* Check for ARM operation numbers. */ - if (0 <= semihosting->op && semihosting->op <= 0x31) { + if ((semihosting->op >= 0 && semihosting->op <= 0x31) || + (semihosting->op >= 0x100 && semihosting->op <= 0x107)) { + *retval = semihosting_common(target); if (*retval != ERROR_OK) { - LOG_ERROR("Failed semihosting operation"); - return 0; + LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); + return SEMIHOSTING_ERROR; } } else { /* Unknown operation number, not a semihosting call. */ - return 0; + LOG_DEBUG(" -> NONE (unknown operation number)"); + 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 SEMIHOSTING_ERROR; + /* * Resume target if we are not waiting on a fileio * operation to complete. */ if (semihosting->is_resumable && !semihosting->hit_fileio) { - /* Resume right after the EBREAK 4 bytes instruction. */ - *retval = target_resume(target, 0, dpc+4, 0, 0); - if (*retval != ERROR_OK) { - LOG_ERROR("Failed to resume target"); - return 0; - } - - return 1; + LOG_DEBUG(" -> HANDLED"); + return SEMIHOSTING_HANDLED; } - return 0; + LOG_DEBUG(" -> WAITING"); + return SEMIHOSTING_WAITING; } /* ------------------------------------------------------------------------- @@ -171,7 +168,7 @@ int riscv_semihosting(struct target *target, int *retval) */ static int riscv_semihosting_setup(struct target *target, int enable) { - LOG_DEBUG("enable=%d", enable); + LOG_DEBUG("[%s] enable=%d", target_name(target), enable); struct semihosting *semihosting = target->semihosting; if (semihosting) diff --git a/src/target/rtt.c b/src/target/rtt.c new file mode 100644 index 0000000000..5ce049ae18 --- /dev/null +++ b/src/target/rtt.c @@ -0,0 +1,412 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stddef.h> +#include <stdint.h> +#include <helper/log.h> +#include <helper/binarybuffer.h> +#include <helper/command.h> +#include <rtt/rtt.h> +#include <target/rtt.h> + +#include "target.h" + +static int read_rtt_channel(struct target *target, + const struct rtt_control *ctrl, unsigned int channel_index, + enum rtt_channel_type type, struct rtt_channel *channel) +{ + int ret; + uint8_t buf[RTT_CHANNEL_SIZE]; + target_addr_t address; + + address = ctrl->address + RTT_CB_SIZE + (channel_index * RTT_CHANNEL_SIZE); + + if (type == RTT_CHANNEL_TYPE_DOWN) + address += ctrl->num_up_channels * RTT_CHANNEL_SIZE; + + ret = target_read_buffer(target, address, RTT_CHANNEL_SIZE, buf); + + if (ret != ERROR_OK) + return ret; + + channel->address = address; + channel->name_addr = buf_get_u32(buf + 0, 0, 32); + channel->buffer_addr = buf_get_u32(buf + 4, 0, 32); + channel->size = buf_get_u32(buf + 8, 0, 32); + channel->write_pos = buf_get_u32(buf + 12, 0, 32); + channel->read_pos = buf_get_u32(buf + 16, 0, 32); + channel->flags = buf_get_u32(buf + 20, 0, 32); + + return ERROR_OK; +} + +int target_rtt_start(struct target *target, const struct rtt_control *ctrl, + void *user_data) +{ + return ERROR_OK; +} + +int target_rtt_stop(struct target *target, void *user_data) +{ + return ERROR_OK; +} + +static int read_channel_name(struct target *target, target_addr_t address, + char *name, size_t length) +{ + size_t offset; + + offset = 0; + + while (offset < length) { + int ret; + size_t read_length; + + read_length = MIN(32, length - offset); + ret = target_read_buffer(target, address + offset, read_length, + (uint8_t *)name + offset); + + if (ret != ERROR_OK) + return ret; + + if (memchr(name + offset, '\0', read_length)) + return ERROR_OK; + + offset += read_length; + } + + name[length - 1] = '\0'; + + return ERROR_OK; +} + +static int write_to_channel(struct target *target, + const struct rtt_channel *channel, const uint8_t *buffer, + size_t *length) +{ + int ret; + uint32_t len; + + if (!*length) + return ERROR_OK; + + if (channel->write_pos == channel->read_pos) { + uint32_t first_length; + + len = MIN(*length, channel->size - 1); + first_length = MIN(len, channel->size - channel->write_pos); + + ret = target_write_buffer(target, + channel->buffer_addr + channel->write_pos, first_length, + buffer); + + if (ret != ERROR_OK) + return ret; + + ret = target_write_buffer(target, channel->buffer_addr, + len - first_length, buffer + first_length); + + if (ret != ERROR_OK) + return ret; + } else if (channel->write_pos < channel->read_pos) { + len = MIN(*length, channel->read_pos - channel->write_pos - 1); + + if (!len) { + *length = 0; + return ERROR_OK; + } + + ret = target_write_buffer(target, + channel->buffer_addr + channel->write_pos, len, buffer); + + if (ret != ERROR_OK) + return ret; + } else { + uint32_t first_length; + + len = MIN(*length, + channel->size - channel->write_pos + channel->read_pos - 1); + + if (!len) { + *length = 0; + return ERROR_OK; + } + + first_length = MIN(len, channel->size - channel->write_pos); + + ret = target_write_buffer(target, + channel->buffer_addr + channel->write_pos, first_length, + buffer); + + if (ret != ERROR_OK) + return ret; + + buffer = buffer + first_length; + + ret = target_write_buffer(target, channel->buffer_addr, + len - first_length, buffer); + + if (ret != ERROR_OK) + return ret; + } + + ret = target_write_u32(target, channel->address + 12, + (channel->write_pos + len) % channel->size); + + if (ret != ERROR_OK) + return ret; + + *length = len; + + return ERROR_OK; +} + +static bool channel_is_active(const struct rtt_channel *channel) +{ + if (!channel) + return false; + + if (!channel->size) + return false; + + return true; +} + +int target_rtt_write_callback(struct target *target, struct rtt_control *ctrl, + unsigned int channel_index, const uint8_t *buffer, size_t *length, + void *user_data) +{ + int ret; + struct rtt_channel channel; + + ret = read_rtt_channel(target, ctrl, channel_index, + RTT_CHANNEL_TYPE_DOWN, &channel); + + if (ret != ERROR_OK) { + LOG_ERROR("rtt: Failed to read down-channel %u description", + channel_index); + return ret; + } + + if (!channel_is_active(&channel)) { + LOG_WARNING("rtt: Down-channel %u is not active", channel_index); + return ERROR_OK; + } + + if (channel.size < RTT_CHANNEL_BUFFER_MIN_SIZE) { + LOG_WARNING("rtt: Down-channel %u is not large enough", + channel_index); + return ERROR_OK; + } + + ret = write_to_channel(target, &channel, buffer, length); + + if (ret != ERROR_OK) + return ret; + + LOG_DEBUG("rtt: Wrote %zu bytes into down-channel %u", *length, + channel_index); + + return ERROR_OK; +} + +int target_rtt_read_control_block(struct target *target, + target_addr_t address, struct rtt_control *ctrl, void *user_data) +{ + int ret; + uint8_t buf[RTT_CB_SIZE]; + + ret = target_read_buffer(target, address, RTT_CB_SIZE, buf); + + if (ret != ERROR_OK) + return ret; + + memcpy(ctrl->id, buf, RTT_CB_MAX_ID_LENGTH); + ctrl->id[RTT_CB_MAX_ID_LENGTH - 1] = '\0'; + ctrl->num_up_channels = buf_get_u32(buf + RTT_CB_MAX_ID_LENGTH + 0, + 0, 32); + ctrl->num_down_channels = buf_get_u32(buf + RTT_CB_MAX_ID_LENGTH + 4, + 0, 32); + + return ERROR_OK; +} + +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 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 = *address; addr < address_end; addr += sizeof(buf)) { + int ret; + + 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; + + 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; + } + + if (buf[buf_off] == id[id_matched_length]) + id_matched_length++; + + if (id_matched_length == id_length) { + *address = addr + buf_off + 1 - id_length; + *found = true; + return ERROR_OK; + } + } + } + + return ERROR_OK; +} + +int target_rtt_read_channel_info(struct target *target, + const struct rtt_control *ctrl, unsigned int channel_index, + enum rtt_channel_type type, struct rtt_channel_info *info, + void *user_data) +{ + int ret; + struct rtt_channel channel; + + ret = read_rtt_channel(target, ctrl, channel_index, type, &channel); + + if (ret != ERROR_OK) { + LOG_ERROR("rtt: Failed to read channel %u description", + channel_index); + return ret; + } + + ret = read_channel_name(target, channel.name_addr, info->name, + info->name_length); + + if (ret != ERROR_OK) + return ret; + + info->size = channel.size; + info->flags = channel.flags; + + return ERROR_OK; +} + +static int read_from_channel(struct target *target, + const struct rtt_channel *channel, uint8_t *buffer, + size_t *length) +{ + int ret; + uint32_t len; + + if (!*length) + return ERROR_OK; + + if (channel->read_pos == channel->write_pos) { + len = 0; + } else if (channel->read_pos < channel->write_pos) { + len = MIN(*length, channel->write_pos - channel->read_pos); + + ret = target_read_buffer(target, + channel->buffer_addr + channel->read_pos, len, buffer); + + if (ret != ERROR_OK) + return ret; + } else { + uint32_t first_length; + + len = MIN(*length, + channel->size - channel->read_pos + channel->write_pos); + first_length = MIN(len, channel->size - channel->read_pos); + + ret = target_read_buffer(target, + channel->buffer_addr + channel->read_pos, first_length, buffer); + + if (ret != ERROR_OK) + return ret; + + ret = target_read_buffer(target, channel->buffer_addr, + len - first_length, buffer + first_length); + + if (ret != ERROR_OK) + return ret; + } + + if (len > 0) { + ret = target_write_u32(target, channel->address + 16, + (channel->read_pos + len) % channel->size); + + if (ret != ERROR_OK) + return ret; + } + + *length = len; + + return ERROR_OK; +} + +int target_rtt_read_callback(struct target *target, + const struct rtt_control *ctrl, struct rtt_sink_list **sinks, + size_t num_channels, void *user_data) +{ + num_channels = MIN(num_channels, ctrl->num_up_channels); + + for (size_t i = 0; i < num_channels; i++) { + int ret; + struct rtt_channel channel; + uint8_t buffer[1024]; + size_t length; + + if (!sinks[i]) + continue; + + ret = read_rtt_channel(target, ctrl, i, RTT_CHANNEL_TYPE_UP, + &channel); + + if (ret != ERROR_OK) { + LOG_ERROR("rtt: Failed to read up-channel %zu description", i); + return ret; + } + + if (!channel_is_active(&channel)) { + LOG_WARNING("rtt: Up-channel %zu is not active", i); + continue; + } + + if (channel.size < RTT_CHANNEL_BUFFER_MIN_SIZE) { + LOG_WARNING("rtt: Up-channel %zu is not large enough", i); + continue; + } + + length = sizeof(buffer); + ret = read_from_channel(target, &channel, buffer, &length); + + if (ret != ERROR_OK) { + LOG_ERROR("rtt: Failed to read from up-channel %zu", i); + return ret; + } + + for (struct rtt_sink_list *sink = sinks[i]; sink; sink = sink->next) + sink->read(i, buffer, length, sink->user_data); + } + + return ERROR_OK; +} diff --git a/src/target/rtt.h b/src/target/rtt.h new file mode 100644 index 0000000000..f3acda5468 --- /dev/null +++ b/src/target/rtt.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> + */ + +#ifndef OPENOCD_TARGET_RTT_H +#define OPENOCD_TARGET_RTT_H + +#include <stdint.h> +#include <stdbool.h> + +#include <target/target.h> +#include <rtt/rtt.h> + +int target_rtt_start(struct target *target, const struct rtt_control *ctrl, + void *user_data); +int target_rtt_stop(struct target *target, void *user_data); +int target_rtt_find_control_block(struct target *target, + target_addr_t *address, size_t size, const char *id, bool *found, + void *user_data); +int target_rtt_read_control_block(struct target *target, + target_addr_t address, struct rtt_control *ctrl, void *user_data); +int target_rtt_write_callback(struct target *target, + struct rtt_control *ctrl, unsigned int channel_index, + const uint8_t *buffer, size_t *length, void *user_data); +int target_rtt_read_callback(struct target *target, + const struct rtt_control *ctrl, struct rtt_sink_list **sinks, + size_t length, void *user_data); +int target_rtt_read_channel_info(struct target *target, + const struct rtt_control *ctrl, unsigned int channel_index, + enum rtt_channel_type type, struct rtt_channel_info *info, + void *user_data); + +#endif /* OPENOCD_TARGET_RTT_H */ diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 9650556092..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,21 +39,53 @@ #include <helper/binarybuffer.h> #include <helper/log.h> +#include <server/gdb_server.h> #include <sys/stat.h> -static const int open_modeflags[12] = { +/** + * It is not possible to use O_... flags defined in sys/stat.h because they + * are not guaranteed to match the values defined by the GDB Remote Protocol. + * See https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags + */ +enum { + TARGET_O_RDONLY = 0x000, + TARGET_O_WRONLY = 0x001, + TARGET_O_RDWR = 0x002, + TARGET_O_APPEND = 0x008, + TARGET_O_CREAT = 0x200, + TARGET_O_TRUNC = 0x400, + /* O_EXCL=0x800 is not required in this implementation. */ +}; + +/* GDB remote protocol does not differentiate between text and binary open modes. */ +static const int open_gdb_modeflags[12] = { + TARGET_O_RDONLY, + TARGET_O_RDONLY, + TARGET_O_RDWR, + TARGET_O_RDWR, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND +}; + +static const int open_host_modeflags[12] = { O_RDONLY, O_RDONLY | O_BINARY, O_RDWR, - O_RDWR | O_BINARY, + O_RDWR | O_BINARY, O_WRONLY | O_CREAT | O_TRUNC, - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - O_RDWR | O_CREAT | O_TRUNC, - O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + O_RDWR | O_CREAT | O_TRUNC, + O_RDWR | O_CREAT | O_TRUNC | O_BINARY, O_WRONLY | O_CREAT | O_APPEND, O_WRONLY | O_CREAT | O_APPEND | O_BINARY, - O_RDWR | O_CREAT | O_APPEND, - O_RDWR | O_CREAT | O_APPEND | O_BINARY + O_RDWR | O_CREAT | O_APPEND, + O_RDWR | O_CREAT | O_APPEND | O_BINARY }; static int semihosting_common_fileio_info(struct target *target, @@ -72,23 +93,12 @@ 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. * * @param target Pointer to the target to initialize. + * @param setup + * @param post_result * @return An error status if there is a problem during initialization. */ int semihosting_common_init(struct target *target, void *setup, @@ -97,7 +107,7 @@ int semihosting_common_init(struct target *target, void *setup, LOG_DEBUG(" "); target->fileio_info = malloc(sizeof(*target->fileio_info)); - if (target->fileio_info == NULL) { + if (!target->fileio_info) { LOG_ERROR("out of memory"); return ERROR_FAIL; } @@ -105,12 +115,17 @@ int semihosting_common_init(struct target *target, void *setup, struct semihosting *semihosting; semihosting = malloc(sizeof(*target->semihosting)); - if (semihosting == NULL) { + if (!semihosting) { LOG_ERROR("out of memory"); return ERROR_FAIL; } semihosting->is_active = false; + semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE; + semihosting->tcp_connection = NULL; + semihosting->stdin_fd = -1; + semihosting->stdout_fd = -1; + semihosting->stderr_fd = -1; semihosting->is_fileio = false; semihosting->hit_fileio = false; semihosting->is_resumable = false; @@ -121,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; @@ -136,6 +153,211 @@ int semihosting_common_init(struct target *target, void *setup, return ERROR_OK; } +struct semihosting_tcp_service { + struct semihosting *semihosting; + char *name; + int error; +}; + +static bool semihosting_is_redirected(struct semihosting *semihosting, int fd) +{ + if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_NONE) + return false; + + bool is_read_op = false; + + switch (semihosting->op) { + /* check debug semihosting operations: READC, WRITEC and WRITE0 */ + case SEMIHOSTING_SYS_READC: + is_read_op = true; + /* fall through */ + case SEMIHOSTING_SYS_WRITEC: + case SEMIHOSTING_SYS_WRITE0: + /* debug operations are redirected when CFG is either DEBUG or ALL */ + if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_STDIO) + return false; + break; + + /* check stdio semihosting operations: READ and WRITE */ + case SEMIHOSTING_SYS_READ: + is_read_op = true; + /* fall through */ + case SEMIHOSTING_SYS_WRITE: + /* stdio operations are redirected when CFG is either STDIO or ALL */ + if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_DEBUG) + return false; + break; + + default: + return false; + } + + if (is_read_op) + return fd == semihosting->stdin_fd; + + /* write operation */ + return fd == semihosting->stdout_fd || fd == semihosting->stderr_fd; +} + +static ssize_t semihosting_redirect_write(struct semihosting *semihosting, void *buf, int size) +{ + if (!semihosting->tcp_connection) { + LOG_ERROR("No connected TCP client for semihosting"); + semihosting->sys_errno = EBADF; /* Bad file number */ + return -1; + } + + struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv; + + int retval = connection_write(semihosting->tcp_connection, buf, size); + + if (retval < 0) + log_socket_error(service->name); + + return retval; +} + +static ssize_t semihosting_write(struct semihosting *semihosting, int fd, void *buf, int size) +{ + if (semihosting_is_redirected(semihosting, fd)) + return semihosting_redirect_write(semihosting, buf, size); + + /* default write */ + 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) +{ + if (!semihosting->tcp_connection) { + LOG_ERROR("No connected TCP client for semihosting"); + semihosting->sys_errno = EBADF; /* Bad file number */ + return -1; + } + + struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv; + + service->error = ERROR_OK; + semihosting->tcp_connection->input_pending = true; + + int retval = connection_read(semihosting->tcp_connection, buf, size); + + if (retval <= 0) + service->error = ERROR_SERVER_REMOTE_CLOSED; + + if (retval < 0) + log_socket_error(service->name); + + semihosting->tcp_connection->input_pending = false; + + return retval; +} + +static inline int semihosting_putchar(struct semihosting *semihosting, int fd, int c) +{ + if (semihosting_is_redirected(semihosting, fd)) + return semihosting_redirect_write(semihosting, &c, 1); + + /* default putchar */ + return putchar(c); +} + +static inline ssize_t semihosting_read(struct semihosting *semihosting, int fd, void *buf, int size) +{ + if (semihosting_is_redirected(semihosting, fd)) + return semihosting_redirect_read(semihosting, buf, size); + + /* default read */ + ssize_t result = read(fd, buf, size); + if (result == -1) + semihosting->sys_errno = errno; + + return result; +} + +static inline int semihosting_getchar(struct semihosting *semihosting, int fd) +{ + if (semihosting_is_redirected(semihosting, fd)) { + unsigned char c; + + if (semihosting_redirect_read(semihosting, &c, 1) > 0) + return c; + + return EOF; + } + + /* default getchar */ + return getchar(); +} + +/** + * User operation parameter string storage buffer. Contains valid data when the + * TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running. + */ +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 @@ -165,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, (int)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) { @@ -224,19 +447,25 @@ int semihosting_common(struct target *target) return retval; else { int fd = semihosting_get_field(target, 0, fields); + /* Do not allow to close OpenOCD's own standard streams */ + if (fd == 0 || fd == 1 || fd == 2) { + LOG_DEBUG("ignoring semihosting attempt to close %s", + (fd == 0) ? "stdin" : + (fd == 1) ? "stdout" : "stderr"); + /* Just pretend success */ + semihosting->result = 0; + break; + } + /* Close the descriptor */ if (semihosting->is_fileio) { - if (fd == 0 || fd == 1 || fd == 2) { - semihosting->result = 0; - break; - } semihosting->hit_fileio = true; fileio_info->identifier = "close"; 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; @@ -323,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, @@ -338,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, @@ -347,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, @@ -414,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, @@ -461,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; @@ -504,7 +733,7 @@ int semihosting_common(struct target *target) uint64_t addr = semihosting_get_field(target, 0, fields); size_t size = semihosting_get_field(target, 1, fields); - char *arg = semihosting->cmdline != NULL ? + char *arg = semihosting->cmdline ? semihosting->cmdline : ""; uint32_t len = strlen(arg) + 1; if (len > size) @@ -521,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; @@ -612,8 +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); - 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; @@ -680,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) { @@ -698,20 +935,22 @@ 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"; fileio_info->param_1 = addr; fileio_info->param_2 = len; - fileio_info->param_3 = open_modeflags[mode]; + fileio_info->param_3 = open_gdb_modeflags[mode]; fileio_info->param_4 = 0644; } } else { @@ -720,35 +959,33 @@ 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) { - semihosting->result = dup( - STDIN_FILENO); - semihosting->sys_errno = errno; - LOG_DEBUG("dup(STDIN)=%d", - (int)semihosting->result); + fd = dup(STDIN_FILENO); + semihosting->stdin_fd = fd; + LOG_DEBUG("dup(STDIN)=%d", fd); } else if (mode < 8) { - semihosting->result = dup( - STDOUT_FILENO); - semihosting->sys_errno = errno; - LOG_DEBUG("dup(STDOUT)=%d", - (int)semihosting->result); + fd = dup(STDOUT_FILENO); + semihosting->stdout_fd = fd; + LOG_DEBUG("dup(STDOUT)=%d", fd); } else { - semihosting->result = dup( - STDERR_FILENO); - semihosting->sys_errno = errno; - LOG_DEBUG("dup(STDERR)=%d", - (int)semihosting->result); + fd = dup(STDERR_FILENO); + semihosting->stderr_fd = fd; + 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 * written file */ semihosting->result = open((char *)fn, - open_modeflags[mode], + 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); @@ -810,13 +1047,12 @@ int semihosting_common(struct target *target) semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { - semihosting->result = read(fd, buf, len); - semihosting->sys_errno = errno; - LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%d", + semihosting->result = semihosting_read(semihosting, fd, buf, len); + 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, @@ -851,8 +1087,8 @@ int semihosting_common(struct target *target) LOG_ERROR("SYS_READC not supported by semihosting fileio"); return ERROR_FAIL; } - semihosting->result = getchar(); - LOG_DEBUG("getchar()=%d", (int)semihosting->result); + semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd); + LOG_DEBUG("getchar()=%" PRId64, semihosting->result); break; case SEMIHOSTING_SYS_REMOVE: /* 0x0E */ @@ -897,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); } @@ -967,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); } @@ -1014,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; } @@ -1075,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); @@ -1154,13 +1388,12 @@ int semihosting_common(struct target *target) free(buf); return retval; } - semihosting->result = write(fd, buf, len); - semihosting->sys_errno = errno; - LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%d", + semihosting->result = semihosting_write(semihosting, fd, buf, len); + 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. * */ @@ -1199,7 +1432,7 @@ int semihosting_common(struct target *target) retval = target_read_memory(target, addr, 1, 1, &c); if (retval != ERROR_OK) return retval; - putchar(c); + semihosting_putchar(semihosting, semihosting->stdout_fd, c); semihosting->result = 0; } break; @@ -1243,12 +1476,80 @@ int semihosting_common(struct target *target) return retval; if (!c) break; - putchar(c); + semihosting_putchar(semihosting, semihosting->stdout_fd, c); } while (1); semihosting->result = 0; } break; + 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). + * + * Reads the user operation parameters from target, then fires the + * corresponding target event. When the target callbacks returned, + * cleans up the command parameter buffer. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field data block: + * - field 1 Contains a pointer to the bound command parameter + * string + * - field 2 Contains the command parameter string length + * + * Return + * On exit, the RETURN REGISTER contains the return status. + */ + 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" + " op=0x%x", semihosting->op); + return retval; + } + + uint64_t addr = semihosting_get_field(target, 0, fields); + + size_t len = semihosting_get_field(target, 1, fields); + if (len > SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH) { + LOG_ERROR("The maximum length for user defined command " + "parameter is %u, received length is %zu (op=0x%x)", + SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH, + len, + semihosting->op); + return ERROR_FAIL; + } + + semihosting_user_op_params = malloc(len + 1); + if (!semihosting_user_op_params) + return ERROR_FAIL; + semihosting_user_op_params[len] = 0; + + 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 (%s)", + semihosting->op, + semihosting_opcode_to_str(semihosting->op)); + free(semihosting_user_op_params); + semihosting_user_op_params = NULL; + return retval; + } + + 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 */ /* * Returns the number of elapsed target ticks since execution @@ -1375,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 @@ -1384,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 */ @@ -1403,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; @@ -1421,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; @@ -1433,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; @@ -1446,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) { @@ -1457,15 +1765,79 @@ static void semihosting_set_field(struct target *target, uint64_t value, target_buffer_set_u32(target, fields + (index * 4), value); } +/* ------------------------------------------------------------------------- + * Semihosting redirect over TCP structs and functions */ + +static int semihosting_service_new_connection_handler(struct connection *connection) +{ + struct semihosting_tcp_service *service = connection->service->priv; + service->semihosting->tcp_connection = connection; + + return ERROR_OK; +} + +static int semihosting_service_input_handler(struct connection *connection) +{ + struct semihosting_tcp_service *service = connection->service->priv; + + if (!connection->input_pending) { + /* consume received data, not for semihosting IO */ + const int buf_len = 100; + char buf[buf_len]; + int bytes_read = connection_read(connection, buf, buf_len); + + if (bytes_read == 0) { + return ERROR_SERVER_REMOTE_CLOSED; + } else if (bytes_read == -1) { + LOG_ERROR("error during read: %s", strerror(errno)); + return ERROR_SERVER_REMOTE_CLOSED; + } + } else if (service->error != ERROR_OK) { + return ERROR_SERVER_REMOTE_CLOSED; + } + + return ERROR_OK; +} + +static int semihosting_service_connection_closed_handler(struct connection *connection) +{ + struct semihosting_tcp_service *service = connection->service->priv; + if (service) { + free(service->name); + free(service); + } + + return ERROR_OK; +} + +static void semihosting_tcp_close_cnx(struct semihosting *semihosting) +{ + if (!semihosting->tcp_connection) + return; + + struct service *service = semihosting->tcp_connection->service; + remove_service(service->name, service->port); + semihosting->tcp_connection = NULL; + +} + +static const struct service_driver semihosting_service_driver = { + .name = "semihosting", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = semihosting_service_new_connection_handler, + .input_handler = semihosting_service_input_handler, + .connection_closed_handler = semihosting_service_connection_closed_handler, + .keep_client_alive_handler = NULL, +}; /* ------------------------------------------------------------------------- * Common semihosting commands handlers. */ -static __COMMAND_HANDLER(handle_common_semihosting_command) +COMMAND_HANDLER(handle_common_semihosting_command) { struct target *target = get_current_target(CMD_CTX); - if (target == NULL) { + if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } @@ -1502,11 +1874,96 @@ static __COMMAND_HANDLER(handle_common_semihosting_command) return ERROR_OK; } -static __COMMAND_HANDLER(handle_common_semihosting_fileio_command) +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; + } + + 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; + } + + enum semihosting_redirect_config cfg; + const char *port; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[0], "disable") == 0) { + cfg = SEMIHOSTING_REDIRECT_CFG_NONE; + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + } else if (strcmp(CMD_ARGV[0], "tcp") == 0) { + if (CMD_ARGC < 2 || CMD_ARGC > 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + port = CMD_ARGV[1]; + + cfg = SEMIHOSTING_REDIRECT_CFG_ALL; + if (CMD_ARGC == 3) { + if (strcmp(CMD_ARGV[2], "debug") == 0) + cfg = SEMIHOSTING_REDIRECT_CFG_DEBUG; + else if (strcmp(CMD_ARGV[2], "stdio") == 0) + cfg = SEMIHOSTING_REDIRECT_CFG_STDIO; + else if (strcmp(CMD_ARGV[2], "all") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + semihosting_tcp_close_cnx(semihosting); + semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE; + + if (cfg != SEMIHOSTING_REDIRECT_CFG_NONE) { + struct semihosting_tcp_service *service = + calloc(1, sizeof(struct semihosting_tcp_service)); + if (!service) { + LOG_ERROR("Failed to allocate semihosting TCP service."); + return ERROR_FAIL; + } + + service->semihosting = semihosting; + + service->name = alloc_printf("%s semihosting service", target_name(target)); + if (!service->name) { + LOG_ERROR("Out of memory"); + free(service); + return ERROR_FAIL; + } + + int ret = add_service(&semihosting_service_driver, + port, 1, service); + + if (ret != ERROR_OK) { + LOG_ERROR("failed to initialize %s", service->name); + free(service->name); + free(service); + return ERROR_FAIL; + } + } + + semihosting->redirect_cfg = cfg; + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_common_semihosting_fileio_command) +{ + struct target *target = get_current_target(CMD_CTX); + + if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } @@ -1532,12 +1989,12 @@ static __COMMAND_HANDLER(handle_common_semihosting_fileio_command) return ERROR_OK; } -static __COMMAND_HANDLER(handle_common_semihosting_cmdline) +COMMAND_HANDLER(handle_common_semihosting_cmdline) { struct target *target = get_current_target(CMD_CTX); unsigned int i; - if (target == NULL) { + if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } @@ -1553,7 +2010,7 @@ static __COMMAND_HANDLER(handle_common_semihosting_cmdline) for (i = 1; i < CMD_ARGC; i++) { char *cmdline = alloc_printf("%s %s", semihosting->cmdline, CMD_ARGV[i]); - if (cmdline == NULL) + if (!cmdline) break; free(semihosting->cmdline); semihosting->cmdline = cmdline; @@ -1565,11 +2022,11 @@ static __COMMAND_HANDLER(handle_common_semihosting_cmdline) return ERROR_OK; } -static __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) +COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) { struct target *target = get_current_target(CMD_CTX); - if (target == NULL) { + if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } @@ -1595,34 +2052,117 @@ static __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) return ERROR_OK; } +COMMAND_HANDLER(handle_common_semihosting_read_user_param_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct semihosting *semihosting = target->semihosting; + + if (CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!semihosting->is_active) { + LOG_ERROR("semihosting not yet enabled for current target"); + return ERROR_FAIL; + } + + if (!semihosting_user_op_params) { + LOG_ERROR("This command is usable only from a registered user " + "semihosting event callback."); + return ERROR_FAIL; + } + + command_print_sameline(CMD, "%s", semihosting_user_op_params); + + 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[] = { { - "semihosting", + .name = "semihosting", .handler = handle_common_semihosting_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting operations", }, { - "semihosting_cmdline", + .name = "semihosting_redirect", + .handler = handle_common_semihosting_redirect_command, + .mode = COMMAND_EXEC, + .usage = "(disable | tcp <port> ['debug'|'stdio'|'all'])", + .help = "redirect semihosting IO", + }, + { + .name = "semihosting_cmdline", .handler = handle_common_semihosting_cmdline, .mode = COMMAND_EXEC, .usage = "arguments", .help = "command line arguments to be passed to program", }, { - "semihosting_fileio", + .name = "semihosting_fileio", .handler = handle_common_semihosting_fileio_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting fileio operations", }, { - "semihosting_resexit", + .name = "semihosting_resexit", .handler = handle_common_semihosting_resumable_exit_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting resumable exit", }, + { + .name = "semihosting_read_user_param", + .handler = handle_common_semihosting_read_user_param_command, + .mode = COMMAND_EXEC, + .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 8fb5e0c3a4..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 @@ -25,6 +14,8 @@ #include <stdint.h> #include <stdbool.h> #include <time.h> +#include "helper/replacements.h" +#include <server/server.h> /* * According to: @@ -74,8 +65,16 @@ enum semihosting_operation_numbers { SEMIHOSTING_SYS_WRITE = 0x05, SEMIHOSTING_SYS_WRITEC = 0x03, SEMIHOSTING_SYS_WRITE0 = 0x04, + 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*/ +#define SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH (1024 * 1024) + /* * Codes used by SEMIHOSTING_SYS_EXIT (formerly * SEMIHOSTING_REPORT_EXCEPTION). @@ -88,6 +87,20 @@ enum semihosting_reported_exceptions { ADP_STOPPED_RUN_TIME_ERROR = ((2 << 16) + 35), }; +enum semihosting_redirect_config { + SEMIHOSTING_REDIRECT_CFG_NONE, + SEMIHOSTING_REDIRECT_CFG_DEBUG, + SEMIHOSTING_REDIRECT_CFG_STDIO, + 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; /* @@ -98,6 +111,15 @@ struct semihosting { /** A flag reporting whether semihosting is active. */ bool is_active; + /** Semihosting STDIO file descriptors */ + int stdin_fd, stdout_fd, stderr_fd; + + /** redirection configuration, NONE by default */ + enum semihosting_redirect_config redirect_cfg; + + /** Handle to redirect semihosting print via tcp */ + struct connection *tcp_connection; + /** A flag reporting whether semihosting fileio is active. */ bool is_fileio; @@ -152,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 acd4628e2e..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) { @@ -111,18 +108,18 @@ COMMAND_HANDLER(default_handle_smp_command) } if (!strcmp(CMD_ARGV[0], "on")) { - foreach_smp_target(head, target->head) + foreach_smp_target(head, target->smp_targets) head->target->smp = 1; return ERROR_OK; } if (!strcmp(CMD_ARGV[0], "off")) { - foreach_smp_target(head, target->head) + foreach_smp_target(head, target->smp_targets) head->target->smp = 0; /* fixes the target display to the debugger */ - if (target->head) + if (!list_empty(target->smp_targets)) target->gdb_service->target = target; return ERROR_OK; @@ -131,37 +128,18 @@ COMMAND_HANDLER(default_handle_smp_command) return ERROR_COMMAND_SYNTAX_ERROR; } -COMMAND_HANDLER(deprecated_handle_smp_on_command) -{ - const char *argv[] = {"on", NULL}; - - LOG_WARNING("\'smp_on\' is deprecated, please use \'smp on\' instead."); - CMD_ARGC = 1; - CMD_ARGV = argv; - return CALL_COMMAND_HANDLER(default_handle_smp_command); -} - -COMMAND_HANDLER(deprecated_handle_smp_off_command) -{ - const char *argv[] = {"off", NULL}; - - LOG_WARNING("\'smp_off\' is deprecated, please use \'smp off\' instead."); - CMD_ARGC = 1; - CMD_ARGV = argv; - return CALL_COMMAND_HANDLER(default_handle_smp_command); -} - COMMAND_HANDLER(handle_smp_gdb_command) { struct target *target = get_current_target(CMD_CTX); int retval = ERROR_OK; - struct target_list *head; - head = target->head; - if (head != (struct target_list *)NULL) { + + LOG_WARNING(DEPRECATED_MSG); + + if (!list_empty(target->smp_targets)) { if (CMD_ARGC == 1) { int coreid = 0; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], coreid); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; target->gdb_service->core[1] = coreid; @@ -180,20 +158,6 @@ const struct command_registration smp_command_handlers[] = { .help = "smp handling", .usage = "[on|off]", }, - { - .name = "smp_on", - .handler = deprecated_handle_smp_on_command, - .mode = COMMAND_EXEC, - .help = "Restart smp handling", - .usage = "", - }, - { - .name = "smp_off", - .handler = deprecated_handle_smp_off_command, - .mode = COMMAND_EXEC, - .help = "Stop smp handling", - .usage = "", - }, { .name = "smp_gdb", .handler = handle_smp_gdb_command, diff --git a/src/target/smp.h b/src/target/smp.h index f024b40235..20835a0522 100644 --- a/src/target/smp.h +++ b/src/target/smp.h @@ -1,33 +1,29 @@ +/* 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 #define OPENOCD_TARGET_SMP_H +#include <helper/list.h> #include "server/server.h" #define foreach_smp_target(pos, head) \ - for (pos = head; (pos != NULL); pos = pos->next) + list_for_each_entry(pos, head, lh) + +#define foreach_smp_target_direction(forward, pos, head) \ + list_for_each_entry_direction(forward, pos, head, lh) 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 ca39b18161..75e0edc77d 100644 --- a/src/target/startup.tcl +++ b/src/target/startup.tcl @@ -1,7 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Defines basic Tcl procs for OpenOCD target module proc new_target_name { } { - return [target number [expr [target count] - 1 ]] + return [target number [expr {[target count] - 1}]] } global in_process_reset @@ -16,7 +18,7 @@ proc ocd_process_reset { MODE } { } set in_process_reset 1 - set success [expr [catch {ocd_process_reset_inner $MODE} result]==0] + set success [expr {[catch {ocd_process_reset_inner $MODE} result] == 0}] set in_process_reset 0 if {$success} { @@ -30,18 +32,17 @@ proc ocd_process_reset_inner { MODE } { set targets [target names] # If this target must be halted... - set halt -1 - if { 0 == [string compare $MODE halt] } { - set halt 1 - } - if { 0 == [string compare $MODE init] } { - set halt 1; - } - if { 0 == [string compare $MODE run ] } { - set halt 0; - } - if { $halt < 0 } { - return -code error "Invalid mode: $MODE, must be one of: halt, init, or run"; + switch $MODE { + halt - + init { + set halt 1 + } + run { + set halt 0 + } + default { + return -code error "Invalid mode: $MODE, must be one of: halt, init, or run"; + } } # Target event handlers *might* change which TAPs are enabled @@ -113,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 @@ -130,14 +142,14 @@ proc ocd_process_reset_inner { MODE } { # Did we succeed? set s [$t curstate] - if { 0 != [string compare $s "halted" ] } { + if { $s != "halted" } { return -code error [format "TARGET: %s - Not halted" $t] } } } #Pass 2 - if needed "init" - if { 0 == [string compare init $MODE] } { + if { $MODE == "init" } { foreach t $targets { if {[using_jtag] && ![jtag tapisenabled [$t cget -chain-position]]} { continue @@ -179,12 +191,6 @@ proc using_hla {} { ######### -# Temporary migration aid. May be removed starting in January 2011. -proc armv4_5 params { - echo "DEPRECATED! use 'arm $params' not 'armv4_5 $params'" - arm $params -} - # Target/chain configuration scripts can either execute commands directly # or define a procedure which is executed once all configuration # scripts have completed. @@ -213,13 +219,78 @@ proc init_target_events {} { proc init_board {} { } -# deprecated target name cmds -proc cortex_m3 args { - echo "DEPRECATED! use 'cortex_m' not 'cortex_m3'" - eval cortex_m $args +lappend _telnet_autocomplete_skip _post_init_target_array_mem +proc _post_init_target_array_mem {} { + set targets [target names] + lappend targets "" + + 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] + } +} +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" +proc "aarch64 smp_on" {args} { + echo "DEPRECATED! use 'aarch64 smp on' not 'aarch64 smp_on'" + eval aarch64 smp on $args +} + +lappend _telnet_autocomplete_skip "aarch64 smp_off" +proc "aarch64 smp_off" {args} { + echo "DEPRECATED! use 'aarch64 smp off' not 'aarch64 smp_off'" + eval aarch64 smp off $args +} + +lappend _telnet_autocomplete_skip "cortex_a smp_on" +proc "cortex_a smp_on" {args} { + echo "DEPRECATED! use 'cortex_a smp on' not 'cortex_a smp_on'" + eval cortex_a smp on $args +} + +lappend _telnet_autocomplete_skip "cortex_a smp_off" +proc "cortex_a smp_off" {args} { + echo "DEPRECATED! use 'cortex_a smp off' not 'cortex_a smp_off'" + eval cortex_a smp off $args +} + +lappend _telnet_autocomplete_skip "mips_m4k smp_on" +proc "mips_m4k smp_on" {args} { + echo "DEPRECATED! use 'mips_m4k smp on' not 'mips_m4k smp_on'" + eval mips_m4k smp on $args } -proc cortex_a8 args { - echo "DEPRECATED! use 'cortex_a' not 'cortex_a8'" - eval cortex_a $args +lappend _telnet_autocomplete_skip "mips_m4k smp_off" +proc "mips_m4k smp_off" {args} { + echo "DEPRECATED! use 'mips_m4k smp off' not 'mips_m4k smp_off'" + eval mips_m4k smp off $args } diff --git a/src/target/stm8.c b/src/target/stm8.c index 78bf6a27ae..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 @@ -159,7 +148,6 @@ struct stm8_algorithm { struct stm8_core_reg { uint32_t num; struct target *target; - struct stm8_common *stm8_common; }; enum hw_break_type { @@ -554,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; } @@ -1006,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; } @@ -1170,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"; } @@ -1221,7 +1209,6 @@ static struct reg_cache *stm8_build_reg_cache(struct target *target) for (i = 0; i < num_regs; i++) { arch_info[i].num = stm8_regs[i].id; arch_info[i].target = target; - arch_info[i].stm8_common = stm8; reg_list[i].name = stm8_regs[i].name; reg_list[i].size = stm8_regs[i].bits; @@ -1316,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; } @@ -1372,7 +1359,7 @@ static void stm8_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->is_set) stm8_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -1385,7 +1372,7 @@ static int stm8_set_breakpoint(struct target *target, struct stm8_comparator *comparator_list = stm8->hw_break_list; int retval; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1400,7 +1387,7 @@ static int stm8_set_breakpoint(struct target *target, breakpoint->unique_id); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = bp_num + 1; + breakpoint_hw_set(breakpoint, bp_num); comparator_list[bp_num].used = true; comparator_list[bp_num].bp_value = breakpoint->address; comparator_list[bp_num].type = HWBRK_EXEC; @@ -1437,7 +1424,7 @@ static int stm8_set_breakpoint(struct target *target, } else { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = 1; /* Any nice value but 0 */ + breakpoint->is_set = true; } return ERROR_OK; @@ -1478,14 +1465,14 @@ static int stm8_unset_breakpoint(struct target *target, struct stm8_comparator *comparator_list = stm8->hw_break_list; int retval; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { - int bp_num = breakpoint->set - 1; - if ((bp_num < 0) || (bp_num >= stm8->num_hw_bpoints)) { + int bp_num = breakpoint->number; + if (bp_num >= stm8->num_hw_bpoints) { LOG_DEBUG("Invalid comparator number in breakpoint (bpid: %" PRIu32 ")", breakpoint->unique_id); return ERROR_OK; @@ -1519,7 +1506,7 @@ static int stm8_unset_breakpoint(struct target *target, } else return ERROR_FAIL; } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -1531,11 +1518,11 @@ 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; } - if (breakpoint->set) + if (breakpoint->is_set) stm8_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) @@ -1552,7 +1539,7 @@ static int stm8_set_watchpoint(struct target *target, int wp_num = 0; int ret; - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -1595,7 +1582,7 @@ static int stm8_set_watchpoint(struct target *target, return ret; } - watchpoint->set = wp_num + 1; + watchpoint_set(watchpoint, wp_num); LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", wp_num, @@ -1629,7 +1616,7 @@ static void stm8_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) stm8_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } @@ -1642,18 +1629,18 @@ static int stm8_unset_watchpoint(struct target *target, struct stm8_common *stm8 = target_to_stm8(target); struct stm8_comparator *comparator_list = stm8->hw_break_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = watchpoint->set - 1; - if ((wp_num < 0) || (wp_num >= stm8->num_hw_bpoints)) { + int wp_num = watchpoint->number; + if (wp_num >= stm8->num_hw_bpoints) { LOG_DEBUG("Invalid hw comparator number in watchpoint"); return ERROR_OK; } comparator_list[wp_num].used = false; - watchpoint->set = 0; + watchpoint->is_set = false; stm8_set_hwbreak(target, comparator_list); @@ -1667,11 +1654,11 @@ 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; } - if (watchpoint->set) + if (watchpoint->is_set) stm8_unset_watchpoint(target, watchpoint); stm8->num_hw_bpoints_avail++; @@ -1797,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; @@ -1832,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); @@ -1876,7 +1863,7 @@ static int stm8_run_algorithm(struct target *target, int num_mem_params, continue; struct reg *reg = register_get_by_name(stm8->core_cache, - reg_params[i].reg_name, 0); + reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); @@ -1910,7 +1897,7 @@ static int stm8_run_algorithm(struct target *target, int num_mem_params, for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(stm8->core_cache, - reg_params[i].reg_name, 0); + reg_params[i].reg_name, false); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); @@ -1945,7 +1932,7 @@ static int stm8_run_algorithm(struct target *target, int num_mem_params, return ERROR_OK; } -int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) +static int stm8_jim_configure(struct target *target, struct jim_getopt_info *goi) { struct stm8_common *stm8 = target_to_stm8(target); jim_wide w; @@ -1954,7 +1941,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) arg = Jim_GetString(goi->argv[0], NULL); if (!strcmp(arg, "-blocksize")) { - e = Jim_GetOpt_String(goi, &arg, NULL); + e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; @@ -1964,7 +1951,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_ERR; } - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; @@ -1973,7 +1960,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_OK; } if (!strcmp(arg, "-flashstart")) { - e = Jim_GetOpt_String(goi, &arg, NULL); + e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; @@ -1983,7 +1970,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_ERR; } - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; @@ -1992,7 +1979,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_OK; } if (!strcmp(arg, "-flashend")) { - e = Jim_GetOpt_String(goi, &arg, NULL); + e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; @@ -2002,7 +1989,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_ERR; } - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; @@ -2011,7 +1998,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_OK; } if (!strcmp(arg, "-eepromstart")) { - e = Jim_GetOpt_String(goi, &arg, NULL); + e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; @@ -2021,7 +2008,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_ERR; } - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; @@ -2030,7 +2017,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_OK; } if (!strcmp(arg, "-eepromend")) { - e = Jim_GetOpt_String(goi, &arg, NULL); + e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; @@ -2040,7 +2027,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_ERR; } - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; @@ -2049,7 +2036,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_OK; } if (!strcmp(arg, "-optionstart")) { - e = Jim_GetOpt_String(goi, &arg, NULL); + e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; @@ -2059,7 +2046,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_ERR; } - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; @@ -2068,7 +2055,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_OK; } if (!strcmp(arg, "-optionend")) { - e = Jim_GetOpt_String(goi, &arg, NULL); + e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; @@ -2078,7 +2065,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_ERR; } - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; @@ -2087,7 +2074,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_OK; } if (!strcmp(arg, "-enable_step_irq")) { - e = Jim_GetOpt_String(goi, &arg, NULL); + e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; @@ -2096,7 +2083,7 @@ int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_OK; } if (!strcmp(arg, "-enable_stm8l")) { - e = Jim_GetOpt_String(goi, &arg, NULL); + e = jim_getopt_string(goi, &arg, NULL); if (e != JIM_OK) return e; @@ -2159,7 +2146,7 @@ static const struct command_registration stm8_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -const struct command_registration stm8_command_handlers[] = { +static const struct command_registration stm8_command_handlers[] = { { .name = "stm8", .mode = COMMAND_ANY, diff --git a/src/target/stm8.h b/src/target/stm8.h index da7f1f119e..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]; @@ -70,6 +60,4 @@ target_to_stm8(struct target *target) return target->arch_info; } -const struct command_registration stm8_command_handlers[]; - #endif /* OPENOCD_TARGET_STM8_H */ diff --git a/src/target/target.c b/src/target/target.c index fa609efdb3..45698a66c5 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,25 +24,14 @@ * * * 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 #include "config.h" #endif +#include <helper/align.h> +#include <helper/nvp.h> #include <helper/time_support.h> #include <jtag/jtag.h> #include <flash/nor/core.h> @@ -55,6 +46,8 @@ #include "rtos/rtos.h" #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 @@ -63,55 +56,11 @@ 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); -static int target_profiling_default(struct target *target, uint32_t *samples, - uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); - -/* 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; static struct target_type *target_types[] = { &arm7tdmi_target, @@ -125,6 +74,7 @@ static struct target_type *target_types[] = { &feroceon_target, &dragonite_target, &xscale_target, + &xtensa_chip_target, &cortexm_target, &cortexa_target, &cortexr4_target, @@ -137,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, @@ -149,6 +99,7 @@ static struct target_type *target_types[] = { &esirisc_target, &arcv2_target, &aarch64_target, + &armv8r_target, &mips_mips64_target, NULL, }; @@ -156,11 +107,18 @@ static struct target_type *target_types[] = { struct target *all_targets; static struct target_event_callback *target_event_callbacks; static struct target_timer_callback *target_timer_callbacks; -LIST_HEAD(target_reset_callback_list); -LIST_HEAD(target_trace_callback_list); -static const int polling_interval = 100; +static int64_t target_timer_next_event_value; +static LIST_HEAD(target_reset_callback_list); +static LIST_HEAD(target_trace_callback_list); +static const int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; +static LIST_HEAD(empty_smp_targets); + +enum nvp_assert { + NVP_DEASSERT, + NVP_ASSERT, +}; -static const Jim_Nvp nvp_assert[] = { +static const struct nvp nvp_assert[] = { { .name = "assert", NVP_ASSERT }, { .name = "deassert", NVP_DEASSERT }, { .name = "T", NVP_ASSERT }, @@ -170,7 +128,7 @@ static const Jim_Nvp nvp_assert[] = { { .name = NULL, .value = -1 } }; -static const 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" }, @@ -187,16 +145,16 @@ static const Jim_Nvp nvp_error_target[] = { static const char *target_strerror_safe(int err) { - const Jim_Nvp *n; + const struct nvp *n; - n = Jim_Nvp_value2name_simple(nvp_error_target, err); - if (n->name == NULL) + n = nvp_value2name(nvp_error_target, err); + if (!n->name) return "unknown"; else return n->name; } -static const Jim_Nvp nvp_target_event[] = { +static const struct jim_nvp nvp_target_event[] = { { .value = TARGET_EVENT_GDB_HALT, .name = "gdb-halt" }, { .value = TARGET_EVENT_HALTED, .name = "halted" }, @@ -236,10 +194,19 @@ static const 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" }, + { .name = NULL, .value = -1 } }; -static const 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 }, @@ -248,7 +215,7 @@ static const Jim_Nvp nvp_target_state[] = { { .name = NULL, .value = -1 }, }; -static const 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 }, @@ -261,7 +228,7 @@ static const Jim_Nvp nvp_target_debug_reason[] = { { .name = NULL, .value = -1 }, }; -static const Jim_Nvp nvp_target_endian[] = { +static const struct jim_nvp nvp_target_endian[] = { { .name = "big", .value = TARGET_BIG_ENDIAN }, { .name = "little", .value = TARGET_LITTLE_ENDIAN }, { .name = "be", .value = TARGET_BIG_ENDIAN }, @@ -269,7 +236,7 @@ static const Jim_Nvp nvp_target_endian[] = { { .name = NULL, .value = -1 }, }; -static const 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 }, @@ -277,11 +244,11 @@ static const 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)); @@ -290,10 +257,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*)"; @@ -308,7 +275,7 @@ const char *target_state_name(struct target *t) const char *target_event_name(enum target_event event) { const char *cp; - cp = Jim_Nvp_value2name_simple(nvp_target_event, event)->name; + cp = jim_nvp_value2name_simple(nvp_target_event, event)->name; if (!cp) { LOG_ERROR("Invalid target event: %d", (int)(event)); cp = "(*BUG*unknown*BUG*)"; @@ -319,7 +286,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*)"; @@ -327,23 +294,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; @@ -479,56 +429,37 @@ 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; /* try as tcltarget name */ for (target = all_targets; target; target = target->next) { - if (target_name(target) == NULL) + if (!target_name(target)) continue; if (strcmp(id, target_name(target)) == 0) 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) { struct target *target = get_current_target_or_null(cmd_ctx); - if (target == NULL) { + if (!target) { LOG_ERROR("BUG: current_target out of bounds"); exit(-1); } @@ -639,7 +570,18 @@ int target_resume(struct target *target, int current, target_addr_t address, * we poll. The CPU can even halt at the current PC as a result of * a software breakpoint being inserted by (a bug?) the application. */ + /* + * resume() triggers the event 'resumed'. The execution of TCL commands + * in the event handler causes the polling of targets. If the target has + * already halted for a breakpoint, polling will run the 'halted' event + * handler before the pending 'resumed' handler. + * Disable polling during resume() to guarantee the execution of handlers + * in the correct order. + */ + bool save_poll_mask = jtag_poll_mask(); retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution); + jtag_poll_unmask(save_poll_mask); + if (retval != ERROR_OK) return retval; @@ -652,9 +594,9 @@ static int target_process_reset(struct command_invocation *cmd, enum target_rese { char buf[100]; int retval; - Jim_Nvp *n; - n = Jim_Nvp_value2name_simple(nvp_reset_modes, reset_mode); - if (n->name == NULL) { + const struct nvp *n; + n = nvp_value2name(nvp_reset_modes, reset_mode); + if (!n->name) { LOG_ERROR("invalid reset mode"); return ERROR_FAIL; } @@ -667,14 +609,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); @@ -706,6 +646,15 @@ static int no_mmu(struct target *target, int *enabled) return ERROR_OK; } +/** + * Reset the @c examined flag for the given target. + * Pure paranoia -- targets are zeroed on allocation. + */ +static inline void target_reset_examined(struct target *target) +{ + target->examined = false; +} + static int default_examine(struct target *target) { target_set_examined(target); @@ -722,16 +671,23 @@ 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; } + target_set_examined(target); target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); + LOG_TARGET_INFO(target, "Examination succeed"); return ERROR_OK; } @@ -768,14 +724,16 @@ int target_examine(void) if (target->defer_examine) continue; - retval = target_examine_one(target); - if (retval != ERROR_OK) - return retval; + int retval2 = target_examine_one(target); + if (retval2 != ERROR_OK) { + LOG_WARNING("target %s examination failed", target_name(target)); + retval = retval2; + } } return retval; } -const char *target_type_name(struct target *target) +const char *target_type_name(const struct target *target) { return target->type->name; } @@ -803,13 +761,20 @@ static int target_soft_reset_halt(struct target *target) * algorithm. * * @param target used to run the algorithm + * @param num_mem_params + * @param mem_params + * @param num_reg_params + * @param reg_param + * @param entry_point + * @param exit_point + * @param timeout_ms * @param arch_info target-specific description of the algorithm. */ 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, - uint32_t entry_point, uint32_t exit_point, - int timeout_ms, void *arch_info) + target_addr_t entry_point, target_addr_t exit_point, + unsigned int timeout_ms, void *arch_info) { int retval = ERROR_FAIL; @@ -838,12 +803,18 @@ done: * Executes a target-specific native code algorithm and leaves it running. * * @param target used to run the algorithm + * @param num_mem_params + * @param mem_params + * @param num_reg_params + * @param reg_params + * @param entry_point + * @param exit_point * @param arch_info target-specific description of the algorithm. */ int target_start_algorithm(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, + target_addr_t entry_point, target_addr_t exit_point, void *arch_info) { int retval = ERROR_FAIL; @@ -876,12 +847,18 @@ done: * Waits for an algorithm started with target_start_algorithm() to complete. * * @param target used to run the algorithm + * @param num_mem_params + * @param mem_params + * @param num_reg_params + * @param reg_params + * @param exit_point + * @param timeout_ms * @param arch_info target-specific description of the algorithm. */ 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, - uint32_t exit_point, int timeout_ms, + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { int retval = ERROR_FAIL; @@ -947,6 +924,7 @@ done: * @param entry_point address on the target to execute to start the algorithm * @param exit_point address at which to set a breakpoint to catch the * end of the algorithm; can be 0 if target triggers a breakpoint itself + * @param arch_info */ int target_run_flash_async_algorithm(struct target *target, @@ -972,7 +950,7 @@ int target_run_flash_async_algorithm(struct target *target, uint32_t rp = fifo_start_addr; /* validate block_size is 2^n */ - assert(!block_size || !(block_size & (block_size - 1))); + assert(IS_PWR_OF_2(block_size)); retval = target_write_u32(target, wp_addr, wp); if (retval != ERROR_OK) @@ -1010,7 +988,7 @@ int target_run_flash_async_algorithm(struct target *target, break; } - if (((rp - fifo_start_addr) & (block_size - 1)) || rp < fifo_start_addr || rp >= fifo_end_addr) { + if (!IS_ALIGNED(rp - fifo_start_addr, block_size) || rp < fifo_start_addr || rp >= fifo_end_addr) { LOG_ERROR("corrupted fifo read pointer 0x%" PRIx32, rp); break; } @@ -1031,11 +1009,11 @@ int target_run_flash_async_algorithm(struct target *target, * programming. The exact delay shouldn't matter as long as it's * less than buffer size / flash speed. This is very unlikely to * run when using high latency connections such as USB. */ - alive_sleep(10); + alive_sleep(2); /* to stop an infinite loop on some targets check and increment a timeout * this issue was observed on a stellaris using the new ICDI interface */ - if (timeout++ >= 500) { + if (timeout++ >= 2500) { LOG_ERROR("timeout waiting for algorithm, a target reset is recommended"); return ERROR_FLASH_OPERATION_FAILED; } @@ -1049,6 +1027,10 @@ int target_run_flash_async_algorithm(struct target *target, if (thisrun_bytes > count * block_size) thisrun_bytes = count * block_size; + /* Force end of large blocks to be word aligned */ + if (thisrun_bytes >= 16) + thisrun_bytes -= (rp + thisrun_bytes) & 0x03; + /* Write data to fifo */ retval = target_write_buffer(target, wp, thisrun_bytes, buffer); if (retval != ERROR_OK) @@ -1098,6 +1080,160 @@ int target_run_flash_async_algorithm(struct target *target, return retval; } +int target_run_read_async_algorithm(struct target *target, + uint8_t *buffer, uint32_t count, int block_size, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t buffer_start, uint32_t buffer_size, + uint32_t entry_point, uint32_t exit_point, void *arch_info) +{ + int retval; + int timeout = 0; + + const uint8_t *buffer_orig = buffer; + + /* Set up working area. First word is write pointer, second word is read pointer, + * rest is fifo data area. */ + uint32_t wp_addr = buffer_start; + uint32_t rp_addr = buffer_start + 4; + uint32_t fifo_start_addr = buffer_start + 8; + uint32_t fifo_end_addr = buffer_start + buffer_size; + + uint32_t wp = fifo_start_addr; + uint32_t rp = fifo_start_addr; + + /* validate block_size is 2^n */ + assert(IS_PWR_OF_2(block_size)); + + retval = target_write_u32(target, wp_addr, wp); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, rp_addr, rp); + if (retval != ERROR_OK) + return retval; + + /* Start up algorithm on target */ + retval = target_start_algorithm(target, num_mem_params, mem_params, + num_reg_params, reg_params, + entry_point, + exit_point, + arch_info); + + if (retval != ERROR_OK) { + LOG_ERROR("error starting target flash read algorithm"); + return retval; + } + + while (count > 0) { + retval = target_read_u32(target, wp_addr, &wp); + if (retval != ERROR_OK) { + LOG_ERROR("failed to get write pointer"); + break; + } + + LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32, + (size_t)(buffer - buffer_orig), count, wp, rp); + + if (wp == 0) { + LOG_ERROR("flash read algorithm aborted by target"); + retval = ERROR_FLASH_OPERATION_FAILED; + break; + } + + if (!IS_ALIGNED(wp - fifo_start_addr, block_size) || wp < fifo_start_addr || wp >= fifo_end_addr) { + LOG_ERROR("corrupted fifo write pointer 0x%" PRIx32, wp); + break; + } + + /* Count the number of bytes available in the fifo without + * crossing the wrap around. */ + uint32_t thisrun_bytes; + if (wp >= rp) + thisrun_bytes = wp - rp; + else + thisrun_bytes = fifo_end_addr - rp; + + if (thisrun_bytes == 0) { + /* Throttle polling a bit if transfer is (much) faster than flash + * reading. The exact delay shouldn't matter as long as it's + * less than buffer size / flash speed. This is very unlikely to + * run when using high latency connections such as USB. */ + alive_sleep(2); + + /* to stop an infinite loop on some targets check and increment a timeout + * this issue was observed on a stellaris using the new ICDI interface */ + if (timeout++ >= 2500) { + LOG_ERROR("timeout waiting for algorithm, a target reset is recommended"); + return ERROR_FLASH_OPERATION_FAILED; + } + continue; + } + + /* Reset our timeout */ + timeout = 0; + + /* Limit to the amount of data we actually want to read */ + if (thisrun_bytes > count * block_size) + thisrun_bytes = count * block_size; + + /* Force end of large blocks to be word aligned */ + if (thisrun_bytes >= 16) + thisrun_bytes -= (rp + thisrun_bytes) & 0x03; + + /* Read data from fifo */ + retval = target_read_buffer(target, rp, thisrun_bytes, buffer); + if (retval != ERROR_OK) + break; + + /* Update counters and wrap write pointer */ + buffer += thisrun_bytes; + count -= thisrun_bytes / block_size; + rp += thisrun_bytes; + if (rp >= fifo_end_addr) + rp = fifo_start_addr; + + /* Store updated write pointer to target */ + retval = target_write_u32(target, rp_addr, rp); + if (retval != ERROR_OK) + break; + + /* Avoid GDB timeouts */ + keep_alive(); + + if (openocd_is_shutdown_pending()) { + retval = ERROR_SERVER_INTERRUPTED; + break; + } + } + + if (retval != ERROR_OK) { + /* abort flash write algorithm on target */ + target_write_u32(target, rp_addr, 0); + } + + int retval2 = target_wait_algorithm(target, num_mem_params, mem_params, + num_reg_params, reg_params, + exit_point, + 10000, + arch_info); + + if (retval2 != ERROR_OK) { + LOG_ERROR("error waiting for target flash write algorithm"); + retval = retval2; + } + + if (retval == ERROR_OK) { + /* check if algorithm set wp = 0 after fifo writer loop finished */ + retval = target_read_u32(target, wp_addr, &wp); + if (retval == ERROR_OK && wp == 0) { + LOG_ERROR("flash read algorithm aborted by target"); + retval = ERROR_FLASH_OPERATION_FAILED; + } + } + + return retval; +} + int target_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { @@ -1158,7 +1294,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); @@ -1168,7 +1304,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); @@ -1178,7 +1314,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); @@ -1194,7 +1330,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); @@ -1208,11 +1344,11 @@ 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; } - if (target->type->hit_watchpoint == NULL) { + if (!target->type->hit_watchpoint) { /* For backward compatible, if hit_watchpoint is not implemented, * return ERROR_FAIL such that gdb_server will not take the nonsense * information. */ @@ -1222,9 +1358,9 @@ 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 == NULL) + if (!target->type->get_gdb_arch) return NULL; return target->type->get_gdb_arch(target); } @@ -1262,13 +1398,13 @@ 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) { /* - * based on current code, we can simply exclude all the targets that - * don't provide get_gdb_reg_list; this could change with new targets. + * exclude all the targets that don't provide get_gdb_reg_list + * or that have explicit gdb_max_connection == 0 */ - return !!target->type->get_gdb_reg_list; + return !!target->type->get_gdb_reg_list && !!target->gdb_max_connections; } int target_step(struct target *target, @@ -1290,7 +1426,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); @@ -1299,7 +1435,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); @@ -1321,24 +1457,18 @@ unsigned target_address_bits(struct target *target) return 32; } -int target_profiling(struct target *target, uint32_t *samples, - uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) +unsigned int target_data_bits(struct target *target) { - if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (profiling)", target->cmd_name); - return ERROR_TARGET_NOT_HALTED; - } - return target->type->profiling(target, samples, max_num_samples, - num_samples, seconds); + if (target->type->data_bits) + return target->type->data_bits(target); + return 32; } -/** - * Reset the @c examined flag for the given target. - * Pure paranoia -- targets are zeroed on allocation. - */ -static void target_reset_examined(struct target *target) +static int target_profiling(struct target *target, uint32_t *samples, + uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { - target->examined = false; + return target->type->profiling(target, samples, max_num_samples, + num_samples, seconds); } static int handle_target(void *priv); @@ -1349,16 +1479,16 @@ static int target_init_one(struct command_context *cmd_ctx, target_reset_examined(target); struct target_type *type = target->type; - if (type->examine == NULL) + if (!type->examine) type->examine = default_examine; - if (type->check_reset == NULL) + if (!type->check_reset) type->check_reset = default_check_reset; - assert(type->init_target != NULL); + assert(type->init_target); int retval = type->init_target(cmd_ctx, target); - if (ERROR_OK != retval) { + if (retval != ERROR_OK) { LOG_ERROR("target '%s' init failed", target_name(target)); return retval; } @@ -1367,7 +1497,7 @@ static int target_init_one(struct command_context *cmd_ctx, * implement it in stages, but warn if we need to do so. */ if (type->mmu) { - if (type->virt2phys == NULL) { + if (!type->virt2phys) { LOG_ERROR("type '%s' is missing virt2phys", type->name); type->virt2phys = identity_virt2phys; } @@ -1385,19 +1515,19 @@ static int target_init_one(struct command_context *cmd_ctx, type->virt2phys = identity_virt2phys; } - if (target->type->read_buffer == NULL) + if (!target->type->read_buffer) target->type->read_buffer = target_read_buffer_default; - if (target->type->write_buffer == NULL) + if (!target->type->write_buffer) target->type->write_buffer = target_write_buffer_default; - if (target->type->get_gdb_fileio_info == NULL) + if (!target->type->get_gdb_fileio_info) target->type->get_gdb_fileio_info = target_get_gdb_fileio_info_default; - if (target->type->gdb_fileio_end == NULL) + if (!target->type->gdb_fileio_end) target->type->gdb_fileio_end = target_gdb_fileio_end_default; - if (target->type->profiling == NULL) + if (!target->type->profiling) target->type->profiling = target_profiling_default; return ERROR_OK; @@ -1410,7 +1540,7 @@ static int target_init(struct command_context *cmd_ctx) for (target = all_targets; target; target = target->next) { retval = target_init_one(cmd_ctx, target); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; } @@ -1418,12 +1548,12 @@ static int target_init(struct command_context *cmd_ctx) return ERROR_OK; retval = target_register_user_commands(cmd_ctx); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = target_register_timer_callback(&handle_target, polling_interval, TARGET_TIMER_TYPE_PERIODIC, cmd_ctx->interp); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; return ERROR_OK; @@ -1444,15 +1574,15 @@ COMMAND_HANDLER(handle_target_init_command) target_initialized = true; retval = command_run_line(CMD_CTX, "init_targets"); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = command_run_line(CMD_CTX, "init_target_events"); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; retval = command_run_line(CMD_CTX, "init_board"); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; LOG_DEBUG("Initializing targets..."); @@ -1464,7 +1594,7 @@ int target_register_event_callback(int (*callback)(struct target *target, { struct target_event_callback **callbacks_p = &target_event_callbacks; - if (callback == NULL) + if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; if (*callbacks_p) { @@ -1486,11 +1616,11 @@ int target_register_reset_callback(int (*callback)(struct target *target, { struct target_reset_callback *entry; - if (callback == NULL) + if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; entry = malloc(sizeof(struct target_reset_callback)); - if (entry == NULL) { + if (!entry) { LOG_ERROR("error allocating buffer for reset callback entry"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1508,11 +1638,11 @@ int target_register_trace_callback(int (*callback)(struct target *target, { struct target_trace_callback *entry; - if (callback == NULL) + if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; entry = malloc(sizeof(struct target_trace_callback)); - if (entry == NULL) { + if (!entry) { LOG_ERROR("error allocating buffer for trace callback entry"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1530,7 +1660,7 @@ int target_register_timer_callback(int (*callback)(void *priv), { struct target_timer_callback **callbacks_p = &target_timer_callbacks; - if (callback == NULL) + if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; if (*callbacks_p) { @@ -1545,8 +1675,8 @@ int target_register_timer_callback(int (*callback)(void *priv), (*callbacks_p)->time_ms = time_ms; (*callbacks_p)->removed = false; - gettimeofday(&(*callbacks_p)->when, NULL); - timeval_add_time(&(*callbacks_p)->when, 0, time_ms * 1000); + (*callbacks_p)->when = timeval_ms() + time_ms; + target_timer_next_event_value = MIN(target_timer_next_event_value, (*callbacks_p)->when); (*callbacks_p)->priv = priv; (*callbacks_p)->next = NULL; @@ -1560,7 +1690,7 @@ int target_unregister_event_callback(int (*callback)(struct target *target, struct target_event_callback **p = &target_event_callbacks; struct target_event_callback *c = target_event_callbacks; - if (callback == NULL) + if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; while (c) { @@ -1582,7 +1712,7 @@ int target_unregister_reset_callback(int (*callback)(struct target *target, { struct target_reset_callback *entry; - if (callback == NULL) + if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; list_for_each_entry(entry, &target_reset_callback_list, list) { @@ -1601,7 +1731,7 @@ int target_unregister_trace_callback(int (*callback)(struct target *target, { struct target_trace_callback *entry; - if (callback == NULL) + if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; list_for_each_entry(entry, &target_trace_callback_list, list) { @@ -1617,7 +1747,7 @@ int target_unregister_trace_callback(int (*callback)(struct target *target, int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) { - if (callback == NULL) + if (!callback) return ERROR_COMMAND_SYNTAX_ERROR; for (struct target_timer_callback *c = target_timer_callbacks; @@ -1642,7 +1772,7 @@ int target_call_event_callbacks(struct target *target, enum target_event event) } LOG_DEBUG("target event %i (%s) for core %s", event, - Jim_Nvp_value2name_simple(nvp_target_event, event)->name, + target_event_name(event), target_name(target)); target_handle_event(target, event); @@ -1661,7 +1791,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); @@ -1680,15 +1810,14 @@ int target_call_trace_callbacks(struct target *target, size_t len, uint8_t *data } static int target_timer_callback_periodic_restart( - struct target_timer_callback *cb, struct timeval *now) + struct target_timer_callback *cb, int64_t *now) { - cb->when = *now; - timeval_add_time(&cb->when, 0, cb->time_ms * 1000L); + cb->when = *now + cb->time_ms; return ERROR_OK; } static int target_call_timer_callback(struct target_timer_callback *cb, - struct timeval *now) + int64_t *now) { cb->callback(cb->priv); @@ -1710,8 +1839,12 @@ static int target_call_timer_callbacks_check_time(int checktime) keep_alive(); - struct timeval now; - gettimeofday(&now, NULL); + int64_t now = timeval_ms(); + + /* Initialize to a default value that's a ways into the future. + * The loop below will make it closer to now if there are + * callbacks that want to be called sooner. */ + target_timer_next_event_value = now + 1000; /* Store an address of the place containing a pointer to the * next item; initially, that's a standalone "root of the @@ -1727,11 +1860,14 @@ static int target_call_timer_callbacks_check_time(int checktime) bool call_it = (*callback)->callback && ((!checktime && (*callback)->type == TARGET_TIMER_TYPE_PERIODIC) || - timeval_compare(&now, &(*callback)->when) >= 0); + now >= (*callback)->when); if (call_it) target_call_timer_callback(*callback, &now); + if (!(*callback)->removed && (*callback)->when < target_timer_next_event_value) + target_timer_next_event_value = (*callback)->when; + callback = &(*callback)->next; } @@ -1750,6 +1886,11 @@ int target_call_timer_callbacks_now(void) return target_call_timer_callbacks_check_time(0); } +int64_t target_timer_next_event(void) +{ + return target_timer_next_event_value; +} + /* Prints the working area layout for debug purposes */ static void print_wa_layout(struct target *target) { @@ -1773,7 +1914,7 @@ static void target_split_working_area(struct working_area *area, uint32_t size) if (size < area->size) { struct working_area *new_wa = malloc(sizeof(*new_wa)); - if (new_wa == NULL) + if (!new_wa) return; new_wa->next = area->next; @@ -1825,7 +1966,7 @@ static void target_merge_working_areas(struct target *target) int target_alloc_working_area_try(struct target *target, uint32_t size, struct working_area **area) { /* Reevaluate working area address based on MMU state*/ - if (target->working_areas == NULL) { + if (!target->working_areas) { int retval; int enabled; @@ -1861,7 +2002,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; @@ -1872,8 +2013,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; @@ -1884,7 +2024,7 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w c = c->next; } - if (c == NULL) + if (!c) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* Split the working area into the requested size */ @@ -1894,9 +2034,9 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w size, c->address); if (target->backup_working_area) { - if (c->backup == NULL) { + if (!c->backup) { c->backup = malloc(c->size); - if (c->backup == NULL) + if (!c->backup) return ERROR_FAIL; } @@ -1932,7 +2072,7 @@ static int target_restore_working_area(struct target *target, struct working_are { int retval = ERROR_OK; - if (target->backup_working_area && area->backup != NULL) { + if (target->backup_working_area && area->backup) { retval = target_write_memory(target, area->address, 4, area->size / 4, area->backup); if (retval != ERROR_OK) LOG_ERROR("failed to restore %" PRIu32 " bytes of working area at address " TARGET_ADDR_FMT, @@ -1945,11 +2085,10 @@ static int target_restore_working_area(struct target *target, struct working_are /* Restore the area's backup memory, if any, and return the area to the allocation pool */ static int target_free_working_area_restore(struct target *target, struct working_area *area, int restore) { - int retval = ERROR_OK; - - if (area->free) - return retval; + if (!area || area->free) + return ERROR_OK; + int retval = ERROR_OK; if (restore) { retval = target_restore_working_area(target, area); /* REVISIT: Perhaps the area should be freed even if restoring fails. */ @@ -2027,8 +2166,8 @@ uint32_t target_get_working_area_avail(struct target *target) struct working_area *c = target->working_areas; uint32_t max_size = 0; - if (c == NULL) - return target->working_area_size; + if (!c) + return ALIGN_DOWN(target->working_area_size, 4); while (c) { if (c->free && max_size < c->size) @@ -2042,9 +2181,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); @@ -2061,13 +2205,15 @@ static void target_destroy(struct target *target) /* release the targets SMP list */ if (target->smp) { - struct target_list *head = target->head; - while (head != NULL) { - struct target_list *pos = head->next; + struct target_list *head, *tmp; + + list_for_each_entry_safe(head, tmp, target->smp_targets, lh) { + list_del(&head->lh); head->target->smp = 0; free(head); - head = pos; } + if (target->smp_targets != &empty_smp_targets) + free(target->smp_targets); target->smp = 0; } @@ -2113,7 +2259,7 @@ void target_quit(void) int target_arch_state(struct target *target) { int retval; - if (target == NULL) { + if (!target) { LOG_WARNING("No target has been configured"); return ERROR_OK; } @@ -2141,7 +2287,7 @@ static int target_gdb_fileio_end_default(struct target *target, return ERROR_OK; } -static int target_profiling_default(struct target *target, uint32_t *samples, +int target_profiling_default(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { struct timeval timeout, now; @@ -2154,7 +2300,7 @@ static int target_profiling_default(struct target *target, uint32_t *samples, uint32_t sample_count = 0; /* hopefully it is safe to cache! We want to stop/restart as quickly as possible. */ - struct reg *reg = register_get_by_name(target->reg_cache, "pc", 1); + struct reg *reg = register_get_by_name(target->reg_cache, "pc", true); int retval = ERROR_OK; for (;;) { @@ -2221,10 +2367,13 @@ static int target_write_buffer_default(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) { uint32_t size; + unsigned int data_bytes = target_data_bits(target) / 8; - /* Align up to maximum 4 bytes. The loop condition makes sure the next pass + /* Align up to maximum bytes. The loop condition makes sure the next pass * will have something to do with the size we leave to it. */ - for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { + for (size = 1; + size < data_bytes && count >= size * 2 + (address & size); + size *= 2) { if (address & size) { int retval = target_write_memory(target, address, size, 1, buffer); if (retval != ERROR_OK) @@ -2282,10 +2431,13 @@ int target_read_buffer(struct target *target, target_addr_t address, uint32_t si static int target_read_buffer_default(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer) { uint32_t size; + unsigned int data_bytes = target_data_bits(target) / 8; - /* Align up to maximum 4 bytes. The loop condition makes sure the next pass + /* Align up to maximum bytes. The loop condition makes sure the next pass * will have something to do with the size we leave to it. */ - for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { + for (size = 1; + size < data_bytes && count >= size * 2 + (address & size); + size *= 2) { if (address & size) { int retval = target_read_memory(target, address, size, 1, buffer); if (retval != ERROR_OK) @@ -2322,11 +2474,15 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_ LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } + if (!target->type->checksum_memory) { + LOG_ERROR("Target %s doesn't support checksum_memory", target_name(target)); + return ERROR_FAIL; + } retval = target->type->checksum_memory(target, address, size, &checksum); if (retval != ERROR_OK) { buffer = malloc(size); - if (buffer == NULL) { + if (!buffer) { LOG_ERROR("error allocating buffer for section (%" PRIu32 " bytes)", size); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -2361,8 +2517,8 @@ int target_blank_check_memory(struct target *target, return ERROR_FAIL; } - if (target->type->blank_check_memory == NULL) - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + if (!target->type->blank_check_memory) + return ERROR_NOT_IMPLEMENTED; return target->type->blank_check_memory(target, blocks, num_blocks, erased_value); } @@ -2626,7 +2782,7 @@ int target_write_phys_u8(struct target *target, target_addr_t address, uint8_t v static int find_target(struct command_invocation *cmd, const char *name) { struct target *target = get_target(name); - if (target == NULL) { + if (!target) { command_print(cmd, "Target: %s is unknown, try one of:\n", name); return ERROR_FAIL; } @@ -2656,10 +2812,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 = ' '; @@ -2674,15 +2830,14 @@ 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), - Jim_Nvp_value2name_simple(nvp_target_endian, + jim_nvp_value2name_simple(nvp_target_endian, target->endianness)->name, target->tap->dotted_name, state); - target = target->next; } return retval; @@ -2690,57 +2845,57 @@ COMMAND_HANDLER(handle_targets_command) /* every 300ms we check for reset & powerdropout and issue a "reset halt" if so. */ -static int powerDropout; -static int srstAsserted; +static int power_dropout; +static int srst_asserted; -static int runPowerRestore; -static int runPowerDropout; -static int runSrstAsserted; -static int runSrstDeasserted; +static int run_power_restore; +static int run_power_dropout; +static int run_srst_asserted; +static int run_srst_deasserted; static int sense_handler(void) { - static int prevSrstAsserted; - static int prevPowerdropout; + static int prev_srst_asserted; + static int prev_power_dropout; - int retval = jtag_power_dropout(&powerDropout); + int retval = jtag_power_dropout(&power_dropout); if (retval != ERROR_OK) return retval; - int powerRestored; - powerRestored = prevPowerdropout && !powerDropout; - if (powerRestored) - runPowerRestore = 1; + int power_restored; + power_restored = prev_power_dropout && !power_dropout; + if (power_restored) + run_power_restore = 1; int64_t current = timeval_ms(); - static int64_t lastPower; - bool waitMore = lastPower + 2000 > current; - if (powerDropout && !waitMore) { - runPowerDropout = 1; - lastPower = current; + static int64_t last_power; + bool wait_more = last_power + 2000 > current; + if (power_dropout && !wait_more) { + run_power_dropout = 1; + last_power = current; } - retval = jtag_srst_asserted(&srstAsserted); + retval = jtag_srst_asserted(&srst_asserted); if (retval != ERROR_OK) return retval; - int srstDeasserted; - srstDeasserted = prevSrstAsserted && !srstAsserted; + int srst_deasserted; + srst_deasserted = prev_srst_asserted && !srst_asserted; - static int64_t lastSrst; - waitMore = lastSrst + 2000 > current; - if (srstDeasserted && !waitMore) { - runSrstDeasserted = 1; - lastSrst = current; + static int64_t last_srst; + wait_more = last_srst + 2000 > current; + if (srst_deasserted && !wait_more) { + run_srst_deasserted = 1; + last_srst = current; } - if (!prevSrstAsserted && srstAsserted) - runSrstAsserted = 1; + if (!prev_srst_asserted && srst_asserted) + run_srst_asserted = 1; - prevSrstAsserted = srstAsserted; - prevPowerdropout = powerDropout; + prev_srst_asserted = srst_asserted; + prev_power_dropout = power_dropout; - if (srstDeasserted || powerRestored) { + if (srst_deasserted || power_restored) { /* Other than logging the event we can't do anything here. * Issuing a reset is a particularly bad idea as we might * be inside a reset already. @@ -2771,21 +2926,21 @@ static int handle_target(void *priv) * clearing the flags after running these events. */ int did_something = 0; - if (runSrstAsserted) { + if (run_srst_asserted) { LOG_INFO("srst asserted detected, running srst_asserted proc."); Jim_Eval(interp, "srst_asserted"); did_something = 1; } - if (runSrstDeasserted) { + if (run_srst_deasserted) { Jim_Eval(interp, "srst_deasserted"); did_something = 1; } - if (runPowerDropout) { + if (run_power_dropout) { LOG_INFO("Power dropout detected, running power_dropout proc."); Jim_Eval(interp, "power_dropout"); did_something = 1; } - if (runPowerRestore) { + if (run_power_restore) { Jim_Eval(interp, "power_restore"); did_something = 1; } @@ -2797,10 +2952,10 @@ static int handle_target(void *priv) /* clear action flags */ - runSrstAsserted = 0; - runSrstDeasserted = 0; - runPowerRestore = 0; - runPowerDropout = 0; + run_srst_asserted = 0; + run_srst_deasserted = 0; + run_power_restore = 0; + run_power_dropout = 0; recursive = 0; } @@ -2826,7 +2981,7 @@ static int handle_target(void *priv) target->backoff.count = 0; /* only poll target if we've got power and srst isn't asserted */ - if (!powerDropout && !srstAsserted) { + if (!power_dropout && !srst_asserted) { /* polling may fail silently until the target has been examined */ retval = target_poll(target); if (retval != ERROR_OK) { @@ -2848,7 +3003,7 @@ static int handle_target(void *priv) /* Target examination could have failed due to unstable connection, * but we set the examined flag anyway to repoll it later */ if (retval != ERROR_OK) { - target->examined = true; + target_set_examined(target); LOG_USER("Examination failed, GDB will be halted. Polling again in %dms", target->backoff.times * polling_interval); return retval; @@ -2865,20 +3020,20 @@ static int handle_target(void *priv) COMMAND_HANDLER(handle_reg_command) { - struct target *target; - struct reg *reg = NULL; - unsigned count = 0; - char *value; - LOG_DEBUG("-"); - target = get_current_target(CMD_CTX); + 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 */ if (CMD_ARGC == 0) { struct reg_cache *cache = target->reg_cache; - count = 0; + unsigned int count = 0; while (cache) { unsigned i; @@ -2887,11 +3042,11 @@ COMMAND_HANDLER(handle_reg_command) for (i = 0, reg = cache->reg_list; i < cache->num_regs; i++, reg++, count++) { - if (reg->exist == false) + if (reg->exist == false || reg->hidden) continue; /* only print cached values if they are valid */ if (reg->valid) { - value = buf_to_hex_str(reg->value, + char *value = buf_to_hex_str(reg->value, reg->size); command_print(CMD, "(%i) %s (/%" PRIu32 "): 0x%s%s", @@ -2919,7 +3074,7 @@ COMMAND_HANDLER(handle_reg_command) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); struct reg_cache *cache = target->reg_cache; - count = 0; + unsigned int count = 0; while (cache) { unsigned i; for (i = 0; i < cache->num_regs; i++) { @@ -2936,17 +3091,17 @@ 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 */ - reg = register_get_by_name(target->reg_cache, CMD_ARGV[0], 1); + reg = register_get_by_name(target->reg_cache, CMD_ARGV[0], true); if (!reg) goto not_found; } - assert(reg != NULL); /* give clang a hint that we *know* reg is != NULL here */ + assert(reg); /* give clang a hint that we *know* reg is != NULL here */ if (!reg->exist) goto not_found; @@ -2955,11 +3110,16 @@ 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) - reg->type->get(reg); - value = buf_to_hex_str(reg->value, reg->size); + if (!reg->valid) { + int retval = reg->type->get(reg); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read register '%s'", reg->name); + return retval; + } + } + char *value = buf_to_hex_str(reg->value, reg->size); command_print(CMD, "%s (/%i): 0x%s", reg->name, (int)(reg->size), value); free(value); return ERROR_OK; @@ -2968,26 +3128,29 @@ COMMAND_HANDLER(handle_reg_command) /* set register value */ if (CMD_ARGC == 2) { uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); - if (buf == NULL) + if (!buf) return ERROR_FAIL; str_to_buf(CMD_ARGV[1], strlen(CMD_ARGV[1]), buf, reg->size, 0); - reg->type->set(reg, buf); - - value = buf_to_hex_str(reg->value, reg->size); - command_print(CMD, "%s (/%i): 0x%s", reg->name, (int)(reg->size), value); - free(value); + int retval = reg->type->set(reg, buf); + if (retval != ERROR_OK) { + LOG_ERROR("Could not write to register '%s'", reg->name); + } else { + char *value = buf_to_hex_str(reg->value, reg->size); + command_print(CMD, "%s (/%i): 0x%s", reg->name, (int)(reg->size), value); + free(value); + } free(buf); - return ERROR_OK; + return retval; } return ERROR_COMMAND_SYNTAX_ERROR; 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) @@ -3027,7 +3190,7 @@ COMMAND_HANDLER(handle_wait_halt_command) unsigned ms = DEFAULT_HALT_TIMEOUT; if (1 == CMD_ARGC) { int retval = parse_uint(CMD_ARGV[0], &ms); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return ERROR_COMMAND_SYNTAX_ERROR; } @@ -3041,7 +3204,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; @@ -3058,15 +3221,18 @@ 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 (openocd_is_shutdown_pending()) + return ERROR_SERVER_INTERRUPTED; + } 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; } } @@ -3083,13 +3249,13 @@ COMMAND_HANDLER(handle_halt_command) target->verbose_halt_msg = true; int retval = target_halt(target); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; if (CMD_ARGC == 1) { unsigned wait_local; retval = parse_uint(CMD_ARGV[0], &wait_local); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return ERROR_COMMAND_SYNTAX_ERROR; if (!wait_local) return ERROR_OK; @@ -3102,7 +3268,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); @@ -3116,9 +3282,9 @@ COMMAND_HANDLER(handle_reset_command) enum target_reset_mode reset_mode = RESET_RUN; if (CMD_ARGC == 1) { - const Jim_Nvp *n; - n = Jim_Nvp_name2value_simple(nvp_reset_modes, CMD_ARGV[0]); - if ((n->name == NULL) || (n->value == RESET_UNKNOWN)) + 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; } @@ -3277,14 +3443,14 @@ COMMAND_HANDLER(handle_md_command) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count); uint8_t *buffer = calloc(count, size); - if (buffer == NULL) { + if (!buffer) { LOG_ERROR("Failed to allocate md read buffer"); return ERROR_FAIL; } struct target *target = get_current_target(CMD_CTX); int retval = fn(target, address, size, count, buffer); - if (ERROR_OK == retval) + if (retval == ERROR_OK) target_handle_md_output(CMD, target, address, size, count, buffer); free(buffer); @@ -3308,7 +3474,7 @@ static int target_fill_mem(struct target *target, * to fill large memory areas with any sane speed */ const unsigned chunk_size = 16384; uint8_t *target_buf = malloc(chunk_size * data_size); - if (target_buf == NULL) { + if (!target_buf) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -3344,6 +3510,11 @@ static int target_fill_mem(struct target *target, break; /* avoid GDB timeouts */ keep_alive(); + + if (openocd_is_shutdown_pending()) { + retval = ERROR_SERVER_INTERRUPTED; + break; + } } free(target_buf); @@ -3398,7 +3569,7 @@ COMMAND_HANDLER(handle_mw_command) return target_fill_mem(target, address, fn, wordsize, value, count); } -static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image, +static COMMAND_HELPER(parse_load_image_command, struct image *image, target_addr_t *min_address, target_addr_t *max_address) { if (CMD_ARGC < 1 || CMD_ARGC > 5) @@ -3410,11 +3581,11 @@ static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image, target_addr_t addr; COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr); image->base_address = addr; - image->base_address_set = 1; + image->base_address_set = true; } else - image->base_address_set = 0; + image->base_address_set = false; - image->start_address_set = 0; + image->start_address_set = false; if (CMD_ARGC >= 4) COMMAND_PARSE_ADDRESS(CMD_ARGV[3], *min_address); @@ -3437,12 +3608,11 @@ COMMAND_HANDLER(handle_load_image_command) uint32_t image_size; target_addr_t min_address = 0; target_addr_t max_address = -1; - int i; struct image image; - int retval = CALL_COMMAND_HANDLER(parse_load_image_command_CMD_ARGV, + int retval = CALL_COMMAND_HANDLER(parse_load_image_command, &image, &min_address, &max_address); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; struct target *target = get_current_target(CMD_CTX); @@ -3455,9 +3625,9 @@ COMMAND_HANDLER(handle_load_image_command) image_size = 0x0; retval = ERROR_OK; - for (i = 0; i < image.num_sections; i++) { + for (unsigned int i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); - if (buffer == NULL) { + if (!buffer) { command_print(CMD, "error allocating buffer for section (%d bytes)", (int)(image.sections[i].size)); @@ -3503,7 +3673,7 @@ COMMAND_HANDLER(handle_load_image_command) free(buffer); } - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { + if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "downloaded %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); @@ -3560,7 +3730,7 @@ COMMAND_HANDLER(handle_dump_image_command) free(buffer); - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { + if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { size_t filesize; retval = fileio_size(fileio, &filesize); if (retval != ERROR_OK) @@ -3588,7 +3758,6 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver uint8_t *buffer; size_t buf_cnt; uint32_t image_size; - int i; int retval; uint32_t checksum = 0; uint32_t mem_checksum = 0; @@ -3612,13 +3781,13 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver target_addr_t addr; COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr); image.base_address = addr; - image.base_address_set = 1; + image.base_address_set = true; } else { - image.base_address_set = 0; + image.base_address_set = false; image.base_address = 0x0; } - image.start_address_set = 0; + image.start_address_set = false; retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) @@ -3627,12 +3796,12 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver image_size = 0x0; int diffs = 0; retval = ERROR_OK; - for (i = 0; i < image.num_sections; i++) { + for (unsigned int i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); - if (buffer == NULL) { + if (!buffer) { command_print(CMD, - "error allocating buffer for section (%d bytes)", - (int)(image.sections[i].size)); + "error allocating buffer for section (%" PRIu32 " bytes)", + image.sections[i].size); break; } retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt); @@ -3688,6 +3857,12 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver } } keep_alive(); + if (openocd_is_shutdown_pending()) { + retval = ERROR_SERVER_INTERRUPTED; + free(data); + free(buffer); + goto done; + } } } free(data); @@ -3706,7 +3881,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver done: if (diffs > 0) retval = ERROR_FAIL; - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { + if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "verified %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); @@ -3740,26 +3915,26 @@ 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, %i, 0x%s", + command_print(cmd, "Software breakpoint(IVA): addr=" TARGET_ADDR_FMT ", len=0x%x, orig_instr=0x%s", breakpoint->address, breakpoint->length, - breakpoint->set, buf); + buf); free(buf); } else { if ((breakpoint->address == 0) && (breakpoint->asid != 0)) - command_print(cmd, "Context breakpoint: 0x%8.8" PRIx32 ", 0x%x, %i", + command_print(cmd, "Context breakpoint: asid=0x%8.8" PRIx32 ", len=0x%x, num=%u", breakpoint->asid, - breakpoint->length, breakpoint->set); + breakpoint->length, breakpoint->number); else if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - command_print(cmd, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i", + command_print(cmd, "Hybrid breakpoint(IVA): addr=" TARGET_ADDR_FMT ", len=0x%x, num=%u", breakpoint->address, - breakpoint->length, breakpoint->set); + 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, %i", + command_print(cmd, "Hardware breakpoint(IVA): addr=" TARGET_ADDR_FMT ", len=0x%x, num=%u", breakpoint->address, - breakpoint->length, breakpoint->set); + breakpoint->length, breakpoint->number); } breakpoint = breakpoint->next; @@ -3776,27 +3951,27 @@ static int handle_bp_command_set(struct command_invocation *cmd, if (asid == 0) { retval = breakpoint_add(target, addr, length, hw); /* error is always logged in breakpoint_add(), do not print it again */ - if (ERROR_OK == retval) + if (retval == ERROR_OK) command_print(cmd, "breakpoint set at " TARGET_ADDR_FMT "", addr); } else if (addr == 0) { - if (target->type->add_context_breakpoint == NULL) { - LOG_ERROR("Context breakpoint not available"); + if (!target->type->add_context_breakpoint) { + LOG_TARGET_ERROR(target, "Context breakpoint not available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = context_breakpoint_add(target, asid, length, hw); /* error is always logged in context_breakpoint_add(), do not print it again */ - if (ERROR_OK == retval) + if (retval == ERROR_OK) command_print(cmd, "Context breakpoint set at 0x%8.8" PRIx32 "", asid); } else { - if (target->type->add_hybrid_breakpoint == NULL) { - LOG_ERROR("Hybrid breakpoint not available"); + if (!target->type->add_hybrid_breakpoint) { + LOG_TARGET_ERROR(target, "Hybrid breakpoint not available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = hybrid_breakpoint_add(target, addr, asid, length, hw); /* error is always logged in hybrid_breakpoint_add(), do not print it again */ - if (ERROR_OK == retval) + if (retval == ERROR_OK) command_print(cmd, "Hybrid breakpoint set at 0x%8.8" PRIx32 "", asid); } return retval; @@ -3848,21 +4023,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) @@ -3873,13 +4058,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; @@ -3888,17 +4074,22 @@ COMMAND_HANDLER(handle_wp_command) } enum watchpoint_rw type = WPT_ACCESS; - uint32_t addr = 0; + 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]) { @@ -3912,13 +4103,13 @@ 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 */ case 2: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); break; default: @@ -3927,24 +4118,38 @@ COMMAND_HANDLER(handle_wp_command) int retval = watchpoint_add(target, addr, length, type, data_value, data_mask); - if (ERROR_OK != retval) - LOG_ERROR("Failure setting watchpoints"); + if (retval != ERROR_OK) + LOG_TARGET_ERROR(target, "Failure setting watchpoints"); return retval; } COMMAND_HANDLER(handle_rwp_command) { - if (CMD_ARGC != 1) - return ERROR_COMMAND_SYNTAX_ERROR; + int retval; - uint32_t addr; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; 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; } /** @@ -3970,44 +4175,44 @@ COMMAND_HANDLER(handle_virt2phys_command) return retval; } -static void writeData(FILE *f, const void *data, size_t len) +static void write_data(FILE *f, const void *data, size_t len) { size_t written = fwrite(data, 1, len, f); if (written != len) LOG_ERROR("failed to write %zu bytes: %s", len, strerror(errno)); } -static void writeLong(FILE *f, int l, struct target *target) +static void write_long(FILE *f, int l, struct target *target) { uint8_t val[4]; target_buffer_set_u32(target, val, l); - writeData(f, val, 4); + write_data(f, val, 4); } -static void writeString(FILE *f, char *s) +static void write_string(FILE *f, char *s) { - writeData(f, s, strlen(s)); + write_data(f, s, strlen(s)); } typedef unsigned char UNIT[2]; /* unit of profiling */ /* Dump a gmon.out histogram file. */ -static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filename, bool with_range, +static void write_gmon(uint32_t *samples, uint32_t sample_num, const char *filename, bool with_range, uint32_t start_address, uint32_t end_address, struct target *target, uint32_t duration_ms) { uint32_t i; FILE *f = fopen(filename, "w"); - if (f == NULL) + if (!f) return; - writeString(f, "gmon"); - writeLong(f, 0x00000001, target); /* Version */ - writeLong(f, 0, target); /* padding */ - writeLong(f, 0, target); /* padding */ - writeLong(f, 0, target); /* padding */ + write_string(f, "gmon"); + write_long(f, 0x00000001, target); /* Version */ + write_long(f, 0, target); /* padding */ + write_long(f, 0, target); /* padding */ + write_long(f, 0, target); /* padding */ uint8_t zero = 0; /* GMON_TAG_TIME_HIST */ - writeData(f, &zero, 1); + write_data(f, &zero, 1); /* figure out bucket size */ uint32_t min; @@ -4018,7 +4223,7 @@ static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filena } else { min = samples[0]; max = samples[0]; - for (i = 0; i < sampleNum; i++) { + for (i = 0; i < sample_num; i++) { if (min > samples[i]) min = samples[i]; if (max < samples[i]) @@ -4027,53 +4232,61 @@ static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filena /* 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 addressSpace = max - min; - assert(addressSpace >= 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. */ - static const uint32_t maxBuckets = 128 * 1024; /* maximum buckets. */ - uint32_t numBuckets = addressSpace / sizeof(UNIT); - if (numBuckets > maxBuckets) - numBuckets = maxBuckets; - int *buckets = malloc(sizeof(int) * numBuckets); - if (buckets == NULL) { + static const uint32_t max_buckets = 128 * 1024; /* maximum buckets. */ + uint32_t num_buckets = address_space / sizeof(UNIT); + if (num_buckets > max_buckets) + num_buckets = max_buckets; + int *buckets = malloc(sizeof(int) * num_buckets); + if (!buckets) { fclose(f); return; } - memset(buckets, 0, sizeof(int) * numBuckets); - for (i = 0; i < sampleNum; i++) { + memset(buckets, 0, sizeof(int) * num_buckets); + for (i = 0; i < sample_num; i++) { uint32_t address = samples[i]; if ((address < min) || (max <= address)) continue; long long a = address - min; - long long b = numBuckets; - long long c = addressSpace; + long long b = num_buckets; + long long c = address_space; int index_t = (a * b) / c; /* danger!!!! int32 overflows */ buckets[index_t]++; } /* append binary memory gmon.out &profile_hist_hdr ((char*)&profile_hist_hdr + sizeof(struct gmon_hist_hdr)) */ - writeLong(f, min, target); /* low_pc */ - writeLong(f, max, target); /* high_pc */ - writeLong(f, numBuckets, target); /* # of buckets */ - float sample_rate = sampleNum / (duration_ms / 1000.0); - writeLong(f, sample_rate, target); - writeString(f, "seconds"); + write_long(f, min, target); /* low_pc */ + write_long(f, max, target); /* high_pc */ + write_long(f, num_buckets, target); /* # of buckets */ + float sample_rate = sample_num / (duration_ms / 1000.0); + write_long(f, sample_rate, target); + write_string(f, "seconds"); for (i = 0; i < (15-strlen("seconds")); i++) - writeData(f, &zero, 1); - writeString(f, "s"); + write_data(f, &zero, 1); + write_string(f, "s"); /*append binary memory gmon.out profile_hist_data (profile_hist_data + profile_hist_hdr.hist_size) */ - char *data = malloc(2 * numBuckets); - if (data != NULL) { - for (i = 0; i < numBuckets; i++) { + char *data = malloc(2 * num_buckets); + if (data) { + for (i = 0; i < num_buckets; i++) { int val; val = buckets[i]; if (val > 65535) @@ -4082,7 +4295,7 @@ static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filena data[i * 2 + 1] = (val >> 8) & 0xff; } free(buckets); - writeData(f, data, numBuckets * 2); + write_data(f, data, num_buckets * 2); free(data); } else free(buckets); @@ -4099,15 +4312,29 @@ 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; + bool halted_before_profiling = target->state == TARGET_HALTED; 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 == NULL) { + if (!samples) { LOG_ERROR("No memory to store samples."); return ERROR_FAIL; } @@ -4133,12 +4360,23 @@ COMMAND_HANDLER(handle_profile_command) free(samples); return retval; } - if (target->state == TARGET_RUNNING) { + + if (target->state == TARGET_RUNNING && halted_before_profiling) { + /* The target was halted before we started and is running now. Halt it, + * for consistency. */ retval = target_halt(target); if (retval != ERROR_OK) { free(samples); return retval; } + } else if (target->state == TARGET_HALTED && !halted_before_profiling) { + /* The target was running before we started and is halted now. Resume + * it, for consistency. */ + retval = target_resume(target, 1, 0, 0, 0); + if (retval != ERROR_OK) { + free(samples); + return retval; + } } retval = target_poll(target); @@ -4147,15 +4385,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]); @@ -4164,373 +4393,230 @@ COMMAND_HANDLER(handle_profile_command) return retval; } -static int new_int_array_element(Jim_Interp *interp, const char *varname, int idx, uint32_t val) +COMMAND_HANDLER(handle_target_read_memory) { - char *namebuf; - Jim_Obj *nameObjPtr, *valObjPtr; - 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; - nameObjPtr = Jim_NewStringObj(interp, namebuf, -1); - valObjPtr = Jim_NewIntObj(interp, val); - if (!nameObjPtr || !valObjPtr) { - free(namebuf); - return JIM_ERR; - } + /* Arg 1: Memory address. */ + target_addr_t addr; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], addr); - Jim_IncrRefCount(nameObjPtr); - Jim_IncrRefCount(valObjPtr); - result = Jim_SetVariable(interp, nameObjPtr, valObjPtr); - Jim_DecrRefCount(interp, nameObjPtr); - Jim_DecrRefCount(interp, valObjPtr); - 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 jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct command_context *context; - struct target *target; + /* Arg 3: Number of elements to read. */ + unsigned int count; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], count); - context = current_command_context(interp); - assert(context != NULL); + /* 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; + } - target = get_current_target(context); - if (target == NULL) { - LOG_ERROR("mem2array: no current target"); - return JIM_ERR; + is_phys = true; } - return target_mem2array(interp, target, argc - 1, argv + 1); -} - -static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv) -{ - long l; - uint32_t width; - int len; - uint32_t addr; - uint32_t count; - uint32_t v; - const char *varname; - const char *phys; - bool is_phys; - int n, e, retval; - uint32_t i; - - /* argv[1] = name of array to receive the data - * argv[2] = desired width - * argv[3] = memory address - * argv[4] = count of times to read - */ - - if (argc < 4 || argc > 5) { - Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]"); - 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; } - varname = Jim_GetString(argv[0], &len); - /* given "foo" get space for worse case "foo(%d)" .. add 20 */ - e = Jim_GetLong(interp, argv[1], &l); - width = l; - if (e != JIM_OK) - return e; + const unsigned int width = width_bits / 8; - e = Jim_GetLong(interp, argv[2], &l); - addr = l; - if (e != JIM_OK) - return e; - e = Jim_GetLong(interp, argv[3], &l); - len = l; - if (e != JIM_OK) - return e; - is_phys = false; - if (argc > 4) { - phys = Jim_GetString(argv[4], &n); - if (!strncmp(phys, "phys", n)) - is_phys = true; - else - return JIM_ERR; - } - switch (width) { - case 8: - width = 1; - break; - case 16: - width = 2; - break; - case 32: - width = 4; - break; - default: - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL); - return JIM_ERR; - } - 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; - } - /* absurd transfer size? */ - if (len > 65536) { - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: absurd > 64K item request", 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))) { - /* all is well */ - } else { - char buf[100]; - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - sprintf(buf, "mem2array address: 0x%08" PRIx32 " 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 */ - n = 0; + struct target *target = get_current_target(CMD_CTX); - size_t buffersize = 4096; + const size_t buffersize = 4096; uint8_t *buffer = malloc(buffersize); - if (buffer == NULL) - 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(count, max_chunk_len); - count = len; /* in objects.. */ - if (count > (buffersize / width)) - count = (buffersize / width); + int retval; if (is_phys) - retval = target_read_phys_memory(target, addr, width, count, buffer); + retval = target_read_phys_memory(target, addr, width, chunk_len, buffer); else - retval = target_read_memory(target, addr, width, count, buffer); + retval = target_read_memory(target, addr, width, chunk_len, buffer); + if (retval != ERROR_OK) { - /* BOO !*/ - LOG_ERROR("mem2array: Read @ 0x%08" PRIx32 ", w=%" PRIu32 ", cnt=%" PRIu32 ", failed", - addr, - width, - count); - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL); - e = JIM_ERR; - break; - } else { - v = 0; /* shut up gcc */ - for (i = 0; i < count ; i++, n++) { - switch (width) { - 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_int_array_element(interp, varname, n, v); - } - len -= count; - addr += count * width; + 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; } - } - - free(buffer); - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); + for (size_t i = 0; i < chunk_len ; i++) { + uint64_t v = 0; - return e; -} - -static int get_int_array_element(Jim_Interp *interp, const char *varname, int idx, uint32_t *val) -{ - char *namebuf; - Jim_Obj *nameObjPtr, *valObjPtr; - int result; - long l; + 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; + } - namebuf = alloc_printf("%s(%d)", varname, idx); - if (!namebuf) - return JIM_ERR; + command_print_sameline(CMD, "%s0x%" PRIx64, separator, v); + separator = " "; + } - nameObjPtr = Jim_NewStringObj(interp, namebuf, -1); - if (!nameObjPtr) { - free(namebuf); - return JIM_ERR; + count -= chunk_len; + addr += chunk_len * width; } - Jim_IncrRefCount(nameObjPtr); - valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG); - Jim_DecrRefCount(interp, nameObjPtr); - free(namebuf); - if (valObjPtr == NULL) - return JIM_ERR; - - result = Jim_GetLong(interp, valObjPtr, &l); - /* printf("%s(%d) => 0%08x\n", varname, idx, val); */ - *val = l; - return result; -} - -static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct command_context *context; - struct target *target; - - context = current_command_context(interp); - assert(context != NULL); - - target = get_current_target(context); - if (target == NULL) { - LOG_ERROR("array2mem: no current target"); - return JIM_ERR; - } + free(buffer); - return target_array2mem(interp, target, argc-1, argv + 1); + return ERROR_OK; } -static int target_array2mem(Jim_Interp *interp, struct target *target, - int argc, Jim_Obj *const *argv) +static int target_jim_write_memory(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) { - long l; - uint32_t width; - int len; - uint32_t addr; - uint32_t count; - uint32_t v; - const char *varname; - const char *phys; - bool is_phys; - int n, e, retval; - uint32_t i; - - /* argv[1] = name of array to get the data - * argv[2] = desired width - * argv[3] = memory address - * argv[4] = count to write + /* + * 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, 0, argv, "varname width addr nelems [phys]"); + Jim_WrongNumArgs(interp, 1, argv, "address width data ['phys']"); return JIM_ERR; } - varname = Jim_GetString(argv[0], &len); - /* given "foo" get space for worse case "foo(%d)" .. add 20 */ - e = Jim_GetLong(interp, argv[1], &l); - width = l; + /* 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); - addr = l; - if (e != JIM_OK) - return e; - e = Jim_GetLong(interp, argv[3], &l); - len = l; + if (e != JIM_OK) return e; - is_phys = false; + + 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) { - phys = Jim_GetString(argv[4], &n); - if (!strncmp(phys, "phys", n)) - is_phys = true; - else - return JIM_ERR; - } - switch (width) { - case 8: - width = 1; - break; - case 16: - width = 2; - break; - case 32: - width = 4; - break; - default: - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), - "Invalid width param, must be 8/16/32", NULL); + 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; } - 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); + + 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; } - /* absurd transfer size? */ - if (len > 65536) { - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), - "array2mem: absurd > 64K item request", NULL); + + 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 ((width == 1) || - ((width == 2) && ((addr & 1) == 0)) || - ((width == 4) && ((addr & 3) == 0))) { - /* all is well */ - } else { - char buf[100]; - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - sprintf(buf, "array2mem address: 0x%08" PRIx32 " is not aligned for %" PRIu32 " byte reads", - addr, - width); - Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL); + if (count > 65536) { + Jim_SetResultString(interp, "write_memory: too large memory write request, exceeds 64K elements", -1); return JIM_ERR; } - /* Transfer loop */ - - /* index counter */ - n = 0; - /* assume ok */ - e = JIM_OK; + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx != NULL); + struct target *target = get_current_target(cmd_ctx); - size_t buffersize = 4096; + const size_t buffersize = 4096; uint8_t *buffer = malloc(buffersize); - if (buffer == NULL) + + 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); - while (len) { - /* Slurp... in buffer size chunks */ + 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); - count = len; /* in objects.. */ - if (count > (buffersize / width)) - count = (buffersize / width); + const uint64_t v = element_wide; - v = 0; /* shut up gcc */ - for (i = 0; i < count; i++, n++) { - get_int_array_element(interp, varname, n, &v); 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; @@ -4542,30 +4628,29 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, break; } } - len -= count; + + count -= chunk_len; + + int retval; if (is_phys) - retval = target_write_phys_memory(target, addr, width, count, buffer); + retval = target_write_phys_memory(target, addr, width, chunk_len, buffer); else - retval = target_write_memory(target, addr, width, count, buffer); + retval = target_write_memory(target, addr, width, chunk_len, buffer); + if (retval != ERROR_OK) { - /* BOO !*/ - LOG_ERROR("array2mem: Write @ 0x%08" PRIx32 ", w=%" PRIu32 ", cnt=%" PRIu32 ", failed", - addr, - width, - count); - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL); + LOG_ERROR("write_memory: write at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", + addr, width_bits, chunk_len); + Jim_SetResultString(interp, "write_memory: failed to write memory", -1); e = JIM_ERR; break; } - addr += count * width; + + addr += chunk_len * width; } free(buffer); - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - return e; } @@ -4577,14 +4662,13 @@ void target_handle_event(struct target *target, enum target_event e) struct target_event_action *teap; int retval; - for (teap = target->event_action; teap != NULL; teap = teap->next) { + 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, - Jim_Nvp_value2name_simple(nvp_target_event, e)->name, + target_event_name(e), Jim_GetString(teap->body, NULL)); /* Override current target by the target an event @@ -4608,7 +4692,7 @@ void target_handle_event(struct target *target, enum target_event e) if (retval != JIM_OK) { Jim_MakeErrorMessage(teap->interp); LOG_USER("Error executing event %s on target %s:\n%s", - Jim_Nvp_value2name_simple(nvp_target_event, e)->name, + target_event_name(e), target_name(target), Jim_GetString(Jim_GetResult(teap->interp), NULL)); /* clean both error code and stacktrace before return */ @@ -4618,14 +4702,160 @@ void target_handle_event(struct target *target, enum target_event e) } } +static int target_jim_get_reg(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + bool force = false; + + if (argc == 3) { + const char *option = Jim_GetString(argv[1], NULL); + + if (!strcmp(option, "-force")) { + argc--; + argv++; + force = true; + } else { + Jim_SetResultFormatted(interp, "invalid option '%s'", option); + return JIM_ERR; + } + } + + if (argc != 2) { + Jim_WrongNumArgs(interp, 1, argv, "[-force] list"); + return JIM_ERR; + } + + const int length = Jim_ListLength(interp, argv[1]); + + Jim_Obj *result_dict = Jim_NewDictObj(interp, NULL, 0); + + if (!result_dict) + return JIM_ERR; + + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx != NULL); + const struct target *target = get_current_target(cmd_ctx); + + for (int i = 0; i < length; i++) { + Jim_Obj *elem = Jim_ListGetIndex(interp, argv[1], i); + + if (!elem) + return JIM_ERR; + + const char *reg_name = Jim_String(elem); + + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, + false); + + if (!reg || !reg->exist) { + Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name); + return JIM_ERR; + } + + if (force || !reg->valid) { + int retval = reg->type->get(reg); + + if (retval != ERROR_OK) { + Jim_SetResultFormatted(interp, "failed to read register '%s'", + reg_name); + return JIM_ERR; + } + } + + char *reg_value = buf_to_hex_str(reg->value, reg->size); + + if (!reg_value) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + char *tmp = alloc_printf("0x%s", reg_value); + + free(reg_value); + + if (!tmp) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + Jim_DictAddElement(interp, result_dict, elem, + Jim_NewStringObj(interp, tmp, -1)); + + free(tmp); + } + + Jim_SetResult(interp, result_dict); + + return JIM_OK; +} + +static int target_jim_set_reg(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + if (argc != 2) { + Jim_WrongNumArgs(interp, 1, argv, "dict"); + return JIM_ERR; + } + + 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); + assert(cmd_ctx); + const struct target *target = get_current_target(cmd_ctx); + + for (unsigned int i = 0; i < length; i += 2) { + const char *reg_name = Jim_String(dict[i]); + const char *reg_value = Jim_String(dict[i + 1]); + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, + false); + + if (!reg || !reg->exist) { + Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name); + return JIM_ERR; + } + + uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); + + if (!buf) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + str_to_buf(reg_value, strlen(reg_value), buf, reg->size, 0); + int retval = reg->type->set(reg, buf); + free(buf); + + if (retval != ERROR_OK) { + Jim_SetResultFormatted(interp, "failed to set '%s' to register '%s'", + reg_value, reg_name); + return JIM_ERR; + } + } + + return JIM_OK; +} + /** * 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; - for (teap = target->event_action; teap != NULL; teap = teap->next) { + for (teap = target->event_action; teap; teap = teap->next) { if (teap->event == event) return true; } @@ -4646,9 +4876,10 @@ enum target_cfg_param { TCFG_RTOS, TCFG_DEFER_EXAMINE, TCFG_GDB_PORT, + TCFG_GDB_MAX_CONNECTIONS, }; -static Jim_Nvp nvp_config_opts[] = { +static struct jim_nvp nvp_config_opts[] = { { .name = "-type", .value = TCFG_TYPE }, { .name = "-event", .value = TCFG_EVENT }, { .name = "-work-area-virt", .value = TCFG_WORK_AREA_VIRT }, @@ -4662,12 +4893,13 @@ static Jim_Nvp nvp_config_opts[] = { { .name = "-rtos", .value = TCFG_RTOS }, { .name = "-defer-examine", .value = TCFG_DEFER_EXAMINE }, { .name = "-gdb-port", .value = TCFG_GDB_PORT }, + { .name = "-gdb-max-connections", .value = TCFG_GDB_MAX_CONNECTIONS }, { .name = NULL, .value = -1 } }; -static int target_configure(Jim_GetOptInfo *goi, struct target *target) +static int target_configure(struct jim_getopt_info *goi, struct target *target) { - Jim_Nvp *n; + struct jim_nvp *n; Jim_Obj *o; jim_wide w; int e; @@ -4675,7 +4907,7 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) /* parse config or cget options ... */ while (goi->argc > 0) { Jim_SetEmptyResult(goi->interp); - /* Jim_GetOpt_Debug(goi); */ + /* jim_getopt_debug(goi); */ if (target->type->target_jim_configure) { /* target defines a configure function */ @@ -4691,9 +4923,9 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) } /* otherwise we 'continue' below */ } - e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); + e = jim_getopt_nvp(goi, nvp_config_opts, &n); if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); + jim_getopt_nvp_unknown(goi, nvp_config_opts, 0); return e; } switch (n->value) { @@ -4722,9 +4954,9 @@ no_params: return JIM_ERR; } - e = Jim_GetOpt_Nvp(goi, nvp_target_event, &n); + e = jim_getopt_nvp(goi, nvp_target_event, &n); if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(goi, nvp_target_event, 1); + jim_getopt_nvp_unknown(goi, nvp_target_event, 1); return e; } @@ -4752,15 +4984,20 @@ no_params: } if (goi->isconfigure) { + /* START_DEPRECATED_TPIU */ + if (n->value == TARGET_EVENT_TRACE_CONFIG) + LOG_INFO("DEPRECATED target event %s; use TPIU events {pre,post}-{enable,disable}", n->name); + /* END_DEPRECATED_TPIU */ + bool replace = true; - if (teap == NULL) { + if (!teap) { /* create new */ teap = calloc(1, sizeof(*teap)); replace = false; } teap->event = n->value; teap->interp = goi->interp; - Jim_GetOpt_Obj(goi, &o); + jim_getopt_obj(goi, &o); if (teap->body) Jim_DecrRefCount(teap->interp, teap->body); teap->body = Jim_DuplicateObj(goi->interp, o); @@ -4784,7 +5021,7 @@ no_params: Jim_SetEmptyResult(goi->interp); } else { /* get */ - if (teap == NULL) + if (!teap) Jim_SetEmptyResult(goi->interp); else Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, teap->body)); @@ -4796,7 +5033,7 @@ no_params: case TCFG_WORK_AREA_VIRT: if (goi->isconfigure) { target_free_all_working_areas(target); - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; target->working_area_virt = w; @@ -4812,7 +5049,7 @@ no_params: case TCFG_WORK_AREA_PHYS: if (goi->isconfigure) { target_free_all_working_areas(target); - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; target->working_area_phys = w; @@ -4828,7 +5065,7 @@ no_params: case TCFG_WORK_AREA_SIZE: if (goi->isconfigure) { target_free_all_working_areas(target); - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; target->working_area_size = w; @@ -4843,25 +5080,25 @@ no_params: case TCFG_WORK_AREA_BACKUP: if (goi->isconfigure) { target_free_all_working_areas(target); - e = Jim_GetOpt_Wide(goi, &w); + 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; case TCFG_ENDIAN: if (goi->isconfigure) { - e = Jim_GetOpt_Nvp(goi, nvp_target_endian, &n); + e = jim_getopt_nvp(goi, nvp_target_endian, &n); if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(goi, nvp_target_endian, 1); + jim_getopt_nvp_unknown(goi, nvp_target_endian, 1); return e; } target->endianness = n->value; @@ -4869,10 +5106,10 @@ no_params: if (goi->argc != 0) goto no_params; } - n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness); - if (n->name == NULL) { + n = jim_nvp_value2name_simple(nvp_target_endian, target->endianness); + if (!n->name) { target->endianness = TARGET_LITTLE_ENDIAN; - n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness); + n = jim_nvp_value2name_simple(nvp_target_endian, target->endianness); } Jim_SetResultString(goi->interp, n->name, -1); /* loop for more */ @@ -4880,7 +5117,7 @@ no_params: case TCFG_COREID: if (goi->isconfigure) { - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; target->coreid = (int32_t)w; @@ -4904,11 +5141,11 @@ no_params: } target_free_all_working_areas(target); - e = Jim_GetOpt_Obj(goi, &o_t); + e = jim_getopt_obj(goi, &o_t); if (e != JIM_OK) return e; tap = jtag_tap_by_jim_obj(goi->interp, o_t); - if (tap == NULL) + if (!tap) return JIM_ERR; target->tap = tap; target->tap_configured = true; @@ -4921,7 +5158,7 @@ no_params: break; case TCFG_DBGBASE: if (goi->isconfigure) { - e = Jim_GetOpt_Wide(goi, &w); + e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; target->dbgbase = (uint32_t)w; @@ -4958,17 +5195,37 @@ no_params: } const char *s; - e = Jim_GetOpt_String(goi, &s, NULL); + e = jim_getopt_string(goi, &s, NULL); if (e != JIM_OK) return e; + free(target->gdb_port_override); target->gdb_port_override = strdup(s); } else { if (goi->argc != 0) goto no_params; } - Jim_SetResultString(goi->interp, target->gdb_port_override ? : "undefined", -1); + Jim_SetResultString(goi->interp, target->gdb_port_override ? target->gdb_port_override : "undefined", -1); /* loop for more */ break; + + case TCFG_GDB_MAX_CONNECTIONS: + if (goi->isconfigure) { + struct command_context *cmd_ctx = current_command_context(goi->interp); + if (cmd_ctx->mode != COMMAND_CONFIG) { + Jim_SetResultString(goi->interp, "-gdb-max-connections must be configured before 'init'", -1); + return JIM_ERR; + } + + e = jim_getopt_wide(goi, &w); + if (e != JIM_OK) + return e; + target->gdb_max_connections = (w < 0) ? CONNECTION_LIMIT_UNLIMITED : (int)w; + } else { + if (goi->argc != 0) + goto no_params; + } + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->gdb_max_connections)); + break; } } /* while (goi->argc) */ @@ -4979,227 +5236,192 @@ no_params: static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { - Jim_GetOptInfo goi; + struct command *c = jim_to_command(interp); + struct jim_getopt_info goi; - Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); - goi.isconfigure = !strcmp(Jim_GetString(argv[0], NULL), "configure"); + jim_getopt_setup(&goi, interp, argc - 1, argv + 1); + goi.isconfigure = !strcmp(c->name, "configure"); if (goi.argc < 1) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "missing: -option ..."); return JIM_ERR; } - struct target *target = Jim_CmdPrivData(goi.interp); + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx); + struct target *target = get_current_target(cmd_ctx); return target_configure(&goi, target); } -static int jim_target_mem2array(Jim_Interp *interp, - int argc, Jim_Obj *const *argv) -{ - struct target *target = Jim_CmdPrivData(interp); - return target_mem2array(interp, target, argc - 1, argv + 1); -} - -static int jim_target_array2mem(Jim_Interp *interp, - int argc, Jim_Obj *const *argv) -{ - struct target *target = Jim_CmdPrivData(interp); - 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; - Jim_GetOptInfo 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 target *target = Jim_CmdPrivData(interp); - 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) - return JIM_ERR; - return JIM_OK; + int retval = target->type->examine(target); + if (retval != ERROR_OK) { + target_reset_examined(target); + return retval; + } + + target_set_examined(target); + + 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 target *target = Jim_CmdPrivData(interp); + 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 target *target = Jim_CmdPrivData(interp); + 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 target *target = Jim_CmdPrivData(interp); + 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 target *target = Jim_CmdPrivData(interp); - 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) { - Jim_GetOptInfo 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; } - Jim_Nvp *n; - int e = Jim_GetOpt_Nvp(&goi, nvp_assert, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(&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 target *target = Jim_CmdPrivData(goi.interp); - 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) target_reset_examined(target); /* determine if we should halt or not. */ - target->reset_halt = !!a; + target->reset_halt = (a != 0); /* When this happens - all workareas are invalid. */ target_free_all_working_areas_restore(target, 0); /* 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 target *target = Jim_CmdPrivData(interp); - 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) { - Jim_GetOptInfo 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; } - Jim_Nvp *n; - int e = Jim_GetOpt_Nvp(&goi, nvp_target_state, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(&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 target *target = Jim_CmdPrivData(interp); - if (!target->tap->enabled) - return jim_target_tap_disabled(interp); - e = target_wait_state(target, n->value, a); - if (e != ERROR_OK) { - Jim_Obj *eObj = 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, - eObj, 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' @@ -5209,47 +5431,73 @@ 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, "------------------------- | " "----------------------------------------"); while (teap) { - Jim_Nvp *opt = Jim_Nvp_value2name_simple(nvp_target_event, teap->event); command_print(CMD, "%-25s | %s", - opt->name, Jim_GetString(teap->body, NULL)); + target_event_name(teap->event), + Jim_GetString(teap->body, NULL)); teap = teap->next; } 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 target *target = Jim_CmdPrivData(interp); - 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) { - Jim_GetOptInfo goi; - Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); + 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, "%s <eventname>", cmd_name); return JIM_ERR; } - Jim_Nvp *n; - int e = Jim_GetOpt_Nvp(&goi, nvp_target_event, &n); + struct jim_nvp *n; + int e = jim_getopt_nvp(&goi, nvp_target_event, &n); if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(&goi, nvp_target_event, 1); + jim_getopt_nvp_unknown(&goi, nvp_target_event, 1); return e; } - struct target *target = Jim_CmdPrivData(interp); + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx); + struct target *target = get_current_target(cmd_ctx); target_handle_event(target, n->value); return JIM_OK; } @@ -5326,20 +5574,32 @@ static const struct command_registration target_instance_command_handlers[] = { .usage = "address [count]", }, { - .name = "array2mem", + .name = "get_reg", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_get_reg, + .help = "Get register values from the target", + .usage = "list", + }, + { + .name = "set_reg", .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", + .jim_handler = target_jim_set_reg, + .help = "Set target register values", + .usage = "dict", }, { - .name = "mem2array", + .name = "read_memory", .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", + .handler = handle_target_read_memory, + .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory", + .usage = "address width count ['phys']", + }, + { + .name = "write_memory", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_write_memory, + .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", + .usage = "address width data ['phys']", }, { .name = "eventlist", @@ -5351,57 +5611,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", @@ -5413,7 +5688,7 @@ static const struct command_registration target_instance_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static int target_create(Jim_GetOptInfo *goi) +static int target_create(struct jim_getopt_info *goi) { Jim_Obj *new_cmd; Jim_Cmd *cmd; @@ -5424,7 +5699,7 @@ static int target_create(Jim_GetOptInfo *goi) struct command_context *cmd_ctx; cmd_ctx = current_command_context(goi->interp); - assert(cmd_ctx != NULL); + assert(cmd_ctx); if (goi->argc < 3) { Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ?type? ..options..."); @@ -5432,9 +5707,9 @@ static int target_create(Jim_GetOptInfo *goi) } /* COMMAND */ - Jim_GetOpt_Obj(goi, &new_cmd); + jim_getopt_obj(goi, &new_cmd); /* does this command exist? */ - cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG); + cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE); if (cmd) { cp = Jim_GetString(new_cmd, NULL); Jim_SetResultFormatted(goi->interp, "Command/target: %s Exists", cp); @@ -5442,11 +5717,11 @@ static int target_create(Jim_GetOptInfo *goi) } /* TYPE */ - e = Jim_GetOpt_String(goi, &cp, NULL); + e = jim_getopt_string(goi, &cp, NULL); 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"); @@ -5456,21 +5731,12 @@ static int target_create(Jim_GetOptInfo *goi) } /* now does target type exist */ for (x = 0 ; target_types[x] ; x++) { - if (0 == strcmp(cp, target_types[x]->name)) { + if (strcmp(cp, target_types[x]->name) == 0) { /* found */ break; } - - /* check for deprecated name */ - if (target_types[x]->deprecated_name) { - if (0 == strcmp(cp, target_types[x]->deprecated_name)) { - /* found */ - LOG_WARNING("target name is deprecated use: \'%s\'", target_types[x]->name); - break; - } - } } - if (target_types[x] == NULL) { + if (!target_types[x]) { Jim_SetResultFormatted(goi->interp, "Unknown target type %s, try one of ", cp); for (x = 0 ; target_types[x] ; x++) { if (target_types[x + 1]) { @@ -5495,8 +5761,8 @@ static int target_create(Jim_GetOptInfo *goi) return JIM_ERR; } - /* set target number */ - target->target_number = new_target_number(); + /* set empty smp cluster */ + target->smp_targets = &empty_smp_targets; /* allocate memory for each unique target type */ target->type = malloc(sizeof(struct target_type)); @@ -5508,16 +5774,13 @@ static int target_create(Jim_GetOptInfo *goi) memcpy(target->type, target_types[x], sizeof(struct target_type)); - /* will be set by "-endian" */ - target->endianness = TARGET_ENDIAN_UNKNOWN; - /* default to first core, override with -coreid */ target->coreid = 0; 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; @@ -5549,6 +5812,7 @@ static int target_create(Jim_GetOptInfo *goi) target->rtos_auto_detect = false; target->gdb_port_override = NULL; + target->gdb_max_connections = 1; /* Do the rest as "configure" options */ goi->isconfigure = 1; @@ -5567,7 +5831,7 @@ static int target_create(Jim_GetOptInfo *goi) } } /* tap must be set after target was configured */ - if (target->tap == NULL) + if (!target->tap) e = JIM_ERR; } @@ -5614,7 +5878,7 @@ static int target_create(Jim_GetOptInfo *goi) /* create the target specific commands */ if (target->type->commands) { e = register_commands(cmd_ctx, NULL, target->type->commands); - if (ERROR_OK != e) + if (e != ERROR_OK) LOG_ERROR("unable to register '%s' commands", cp); } @@ -5638,7 +5902,7 @@ static int target_create(Jim_GetOptInfo *goi) }, COMMAND_REGISTRATION_DONE }; - e = register_commands(cmd_ctx, NULL, target_commands); + e = register_commands_override_target(cmd_ctx, NULL, target_commands, target); if (e != ERROR_OK) { if (target->type->deinit_target) target->type->deinit_target(target); @@ -5651,10 +5915,6 @@ static int target_create(Jim_GetOptInfo *goi) return JIM_ERR; } - struct command *c = command_find_in_context(cmd_ctx, cp); - assert(c); - command_set_handler_data(c, target); - /* append to end of list */ append_to_list_all_targets(target); @@ -5662,105 +5922,128 @@ static int target_create(Jim_GetOptInfo *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 != NULL); + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - Jim_SetResultString(interp, target_name(get_current_target(cmd_ctx)), -1); - return JIM_OK; + struct target *target = get_current_target_or_null(CMD_CTX); + if (target) + 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; NULL != 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) { - int i; - const char *targetname; - int retval, len; - struct target *target = (struct target *) NULL; - struct target_list *head, *curr, *new; - curr = (struct target_list *) NULL; - head = (struct target_list *) NULL; - - retval = 0; - LOG_DEBUG("%d", argc); - /* argv[1] = target to associate in smp - * argv[2] = target to associate in smp - * argv[3] ... - */ + struct target *target = get_target(targetname); + LOG_DEBUG("%s ", targetname); + if (!target) + return NULL; - 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; - new->next = (struct target_list *)NULL; - if (head == (struct target_list *)NULL) { - head = new; - curr = head; - } else { - curr->next = new; - curr = new; + 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) +{ + struct target *target = NULL; + 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; } } - /* now parse the list of cpu and put the target in smp mode*/ - curr = head; + *result = target; + return ERROR_OK; +} + +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 ERROR_FAIL; + } + INIT_LIST_HEAD(lh); - while (curr != (struct target_list *)NULL) { - target = curr->target; - target->smp = 1; - target->head = head; - curr = curr->next; + 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*/ + 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) { - Jim_GetOptInfo goi; - Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); + struct jim_getopt_info goi; + jim_getopt_setup(&goi, interp, argc - 1, argv + 1); if (goi.argc < 3) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "<name> <target_type> [<target_options> ...]"); @@ -5787,26 +6070,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" }, @@ -5814,7 +6100,7 @@ static const struct command_registration target_subcommand_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct FastLoad { +struct fast_load { target_addr_t address; uint8_t *data; int length; @@ -5822,11 +6108,11 @@ struct FastLoad { }; static int fastload_num; -static struct FastLoad *fastload; +static struct fast_load *fastload; static void free_fastload(void) { - if (fastload != NULL) { + if (fastload) { for (int i = 0; i < fastload_num; i++) free(fastload[i].data); free(fastload); @@ -5841,13 +6127,12 @@ COMMAND_HANDLER(handle_fast_load_image_command) uint32_t image_size; target_addr_t min_address = 0; target_addr_t max_address = -1; - int i; struct image image; - int retval = CALL_COMMAND_HANDLER(parse_load_image_command_CMD_ARGV, + int retval = CALL_COMMAND_HANDLER(parse_load_image_command, &image, &min_address, &max_address); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; struct duration bench; @@ -5860,16 +6145,16 @@ COMMAND_HANDLER(handle_fast_load_image_command) image_size = 0x0; retval = ERROR_OK; fastload_num = image.num_sections; - fastload = malloc(sizeof(struct FastLoad)*image.num_sections); - if (fastload == NULL) { + fastload = malloc(sizeof(struct fast_load)*image.num_sections); + if (!fastload) { command_print(CMD, "out of memory"); image_close(&image); return ERROR_FAIL; } - memset(fastload, 0, sizeof(struct FastLoad)*image.num_sections); - for (i = 0; i < image.num_sections; i++) { + memset(fastload, 0, sizeof(struct fast_load)*image.num_sections); + for (unsigned int i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); - if (buffer == NULL) { + if (!buffer) { command_print(CMD, "error allocating buffer for section (%d bytes)", (int)(image.sections[i].size)); retval = ERROR_FAIL; @@ -5900,7 +6185,7 @@ COMMAND_HANDLER(handle_fast_load_image_command) fastload[i].address = image.sections[i].base_address + offset; fastload[i].data = malloc(length); - if (fastload[i].data == NULL) { + if (!fastload[i].data) { free(buffer); command_print(CMD, "error allocating buffer for section (%" PRIu32 " bytes)", length); @@ -5919,7 +6204,7 @@ COMMAND_HANDLER(handle_fast_load_image_command) free(buffer); } - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { + if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD, "Loaded %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); @@ -5941,7 +6226,7 @@ COMMAND_HANDLER(handle_fast_load_command) { if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; - if (fastload == NULL) { + if (!fastload) { LOG_ERROR("No image in memory"); return ERROR_FAIL; } @@ -6009,8 +6294,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) @@ -6027,7 +6312,7 @@ COMMAND_HANDLER(handle_ps_command) static void binprint(struct command_invocation *cmd, const char *text, const uint8_t *buf, int size) { - if (text != NULL) + if (text) command_print_sameline(cmd, "%s", text); for (int i = 0; i < size; i++) command_print_sameline(cmd, " %02x", buf[i]); @@ -6041,8 +6326,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) @@ -6127,8 +6412,7 @@ next: out: free(test_pattern); - if (wa != NULL) - target_free_working_area(target, wa); + target_free_working_area(target, wa); /* Test writes */ num_bytes = test_size + 4 + 4 + 4; @@ -6212,8 +6496,7 @@ nextw: free(test_pattern); - if (wa != NULL) - target_free_working_area(target, wa); + target_free_working_area(target, wa); return retval; } @@ -6224,8 +6507,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", @@ -6385,21 +6668,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", @@ -6426,35 +6709,47 @@ static const struct command_registration target_exec_command_handlers[] = { .usage = "filename [offset [type]]", }, { - .name = "mem2array", + .name = "get_reg", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_get_reg, + .help = "Get register values from the target", + .usage = "list", + }, + { + .name = "set_reg", .mode = COMMAND_EXEC, - .jim_handler = jim_mem2array, - .help = "read 8/16/32 bit memory and return as a TCL array " - "for script processing", - .usage = "arrayname bitwidth address count", + .jim_handler = target_jim_set_reg, + .help = "Set target register values", + .usage = "dict", }, { - .name = "array2mem", + .name = "read_memory", .mode = COMMAND_EXEC, - .jim_handler = jim_array2mem, - .help = "convert a TCL array to memory locations " - "and write the 8/16/32 bit values", - .usage = "arrayname bitwidth address count", + .handler = handle_target_read_memory, + .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory", + .usage = "address width count ['phys']", + }, + { + .name = "write_memory", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_write_memory, + .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", + .usage = "address width data ['phys']", }, { .name = "reset_nag", .handler = handle_target_reset_nag, .mode = COMMAND_ANY, .help = "Nag after each reset about options that could have been " - "enabled to improve performance. ", + "enabled to improve performance.", .usage = "['enable'|'disable']", }, { .name = "ps", .handler = handle_ps_command, .mode = COMMAND_EXEC, - .help = "list all tasks ", - .usage = " ", + .help = "list all tasks", + .usage = "", }, { .name = "test_mem_access", @@ -6480,3 +6775,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 c69aa934a6..d5c0e0e8c7 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,25 +15,15 @@ * * * 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 #define OPENOCD_TARGET_TARGET_H #include <helper/list.h> +#include "helper/replacements.h" +#include "helper/system.h" +#include <helper/types.h> #include <jim.h> struct reg; @@ -47,7 +39,7 @@ struct gdb_fileio_info; /* * TARGET_UNKNOWN = 0: we don't know anything about the target yet - * TARGET_RUNNING = 1: the target is executing user code + * TARGET_RUNNING = 1: the target is executing or ready to execute user code * TARGET_HALTED = 2: the target is not executing code, and ready to talk to the * debugger. on an xscale it means that the debug handler is executing * TARGET_RESET = 3: the target is being held in reset (only a temporary state, @@ -66,11 +58,6 @@ enum target_state { TARGET_DEBUG_RUNNING = 4, }; -enum nvp_assert { - NVP_DEASSERT, - NVP_ASSERT, -}; - enum target_reset_mode { RESET_UNKNOWN = 0, RESET_RUN = 1, /* reset and let target run */ @@ -129,7 +116,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? */ @@ -155,7 +141,7 @@ struct target { struct target_event_action *event_action; - int reset_halt; /* attempt resetting the CPU into the halted mode? */ + bool reset_halt; /* attempt resetting the CPU into the halted mode? */ target_addr_t working_area; /* working area (initialised RAM). Evaluated * upon first allocation from virtual/physical address. */ bool working_area_virt_spec; /* virtual address specified? */ @@ -163,7 +149,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 */ @@ -198,8 +184,14 @@ struct target { bool rtos_auto_detect; /* A flag that indicates that the RTOS has been specified as "auto" * and must be detected when symbols are offered */ struct backoff_timer backoff; - int smp; /* add some target attributes for smp support */ - struct target_list *head; + 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 @@ -211,13 +203,15 @@ struct target { char *gdb_port_override; /* target-specific override for gdb_port */ + int gdb_max_connections; /* max number of simultaneous gdb connections */ + /* The semihosting information, extracted from the target. */ struct semihosting *semihosting; }; struct target_list { + struct list_head lh; struct target *target; - struct target_list *next; }; struct gdb_fileio_info { @@ -229,19 +223,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 { @@ -290,6 +284,15 @@ enum target_event { TARGET_EVENT_GDB_FLASH_WRITE_END, 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, }; struct target_event_action { @@ -299,7 +302,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); @@ -329,7 +332,7 @@ struct target_timer_callback { unsigned int time_ms; enum target_timer_type type; bool removed; - struct timeval when; + int64_t when; /* output of timeval_ms() */ void *priv; struct target_timer_callback *next; }; @@ -403,8 +406,12 @@ int target_call_timer_callbacks(void); * a synchronous command completes. */ int target_call_timer_callbacks_now(void); +/** + * Returns when the next registered event will take place. Callers can use this + * to go to sleep until that time occurs. + */ +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); @@ -415,7 +422,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 @@ -426,7 +433,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; } @@ -495,7 +502,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. @@ -521,7 +528,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. @@ -538,8 +545,8 @@ int target_step(struct target *target, 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, - uint32_t entry_point, uint32_t exit_point, - int timeout_ms, void *arch_info); + target_addr_t entry_point, target_addr_t exit_point, + unsigned int timeout_ms, void *arch_info); /** * Starts an algorithm in the background on the @a target given. @@ -549,7 +556,7 @@ int target_run_algorithm(struct target *target, int target_start_algorithm(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, + target_addr_t entry_point, target_addr_t exit_point, void *arch_info); /** @@ -560,7 +567,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, - uint32_t exit_point, int timeout_ms, + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); /** @@ -575,6 +582,18 @@ int target_run_flash_async_algorithm(struct target *target, uint32_t entry_point, uint32_t exit_point, void *arch_info); +/** + * This routine is a wrapper for asynchronous algorithms. + * + */ +int target_run_read_async_algorithm(struct target *target, + uint8_t *buffer, uint32_t count, int block_size, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t buffer_start, uint32_t buffer_size, + uint32_t entry_point, uint32_t exit_point, + void *arch_info); + /** * Read @a count items of @a size bytes from the memory of @a target at * the @a address given. @@ -640,7 +659,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. @@ -668,8 +687,15 @@ target_addr_t target_address_max(struct target *target); */ unsigned target_address_bits(struct target *target); +/** + * Return the number of data bits this target supports. + * + * This routine is a wrapper for target->type->data_bits. + */ +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); @@ -698,6 +724,13 @@ int target_alloc_working_area(struct target *target, */ int target_alloc_working_area_try(struct target *target, uint32_t size, struct working_area **area); +/** + * Free a working area. + * Restore target data if area backup is configured. + * @param target + * @param area Pointer to the area to be freed or NULL + * @returns ERROR_OK if successful; error code if restore failed + */ int target_free_working_area(struct target *target, struct working_area *area); void target_free_all_working_areas(struct target *target); uint32_t target_get_working_area_avail(struct target *target); @@ -748,6 +781,9 @@ void target_handle_md_output(struct command_invocation *cmd, struct target *target, target_addr_t address, unsigned size, unsigned count, const uint8_t *buffer); +int target_profiling_default(struct target *target, uint32_t *samples, uint32_t + max_num_samples, uint32_t *num_samples, uint32_t seconds); + #define ERROR_TARGET_INVALID (-300) #define ERROR_TARGET_INIT_FAILED (-301) #define ERROR_TARGET_TIMEOUT (-302) @@ -761,7 +797,13 @@ void target_handle_md_output(struct command_invocation *cmd, #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 32a907233f..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 @@ -158,7 +147,7 @@ static int add_debug_msg_receiver(struct command_context *cmd_ctx, struct target { struct debug_msg_receiver **p = &target->dbgmsg; - if (target == NULL) + if (!target) return ERROR_COMMAND_SYNTAX_ERROR; /* see if there's already a list */ @@ -186,9 +175,9 @@ static struct debug_msg_receiver *find_debug_msg_receiver(struct command_context int do_all_targets = 0; /* if no target has been specified search all of them */ - if (target == NULL) { + if (!target) { /* if no targets haven been specified */ - if (all_targets == NULL) + if (!all_targets) return NULL; target = all_targets; @@ -217,9 +206,9 @@ int delete_debug_msg_receiver(struct command_context *cmd_ctx, struct target *ta int do_all_targets = 0; /* if no target has been specified search all of them */ - if (target == NULL) { + if (!target) { /* if no targets haven been specified */ - if (all_targets == NULL) + if (!all_targets) return ERROR_OK; target = all_targets; @@ -234,7 +223,7 @@ int delete_debug_msg_receiver(struct command_context *cmd_ctx, struct target *ta if (c->cmd_ctx == cmd_ctx) { *p = next; free(c); - if (*p == NULL) { + if (!*p) { /* disable callback */ target->dbg_msg_enabled = 0; } @@ -256,13 +245,13 @@ COMMAND_HANDLER(handle_target_request_debugmsgs_command) int receiving = 0; - if (target->type->target_request_data == NULL) { + if (!target->type->target_request_data) { LOG_ERROR("Target %s does not support target requests", target_name(target)); return ERROR_OK; } /* see if receiver is already registered */ - if (find_debug_msg_receiver(CMD_CTX, target) != NULL) + if (find_debug_msg_receiver(CMD_CTX, target)) receiving = 1; if (CMD_ARGC > 0) { 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 4bdea721e8..bc42c2d16e 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,25 +9,12 @@ * * * 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 #define OPENOCD_TARGET_TARGET_TYPE_H -#include <jim-nvp.h> +#include <helper/jim-nvp.h> struct target; @@ -40,7 +29,6 @@ struct target_type { * field directly, use target_type_name() instead. */ const char *name; - const char *deprecated_name; /* poll current target status */ int (*poll)(struct target *target); @@ -80,7 +68,7 @@ struct target_type { * state correctly. * * Otherwise the following would fail, as there will not - * be any "poll" invoked inbetween the "reset run" and + * be any "poll" invoked between the "reset run" and * "halt". * * reset run; halt @@ -95,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 @@ -193,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, @@ -201,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; @@ -211,11 +199,11 @@ struct target_type { /* called for various config parameters */ /* returns JIM_CONTINUE - if option not understood */ /* otherwise: JIM_OK, or JIM_ERR, */ - int (*target_jim_configure)(struct target *target, Jim_GetOptInfo *goi); + int (*target_jim_configure)(struct target *target, struct jim_getopt_info *goi); /* target commands specifically handled by the target */ /* returns JIM_OK, or JIM_ERR, or JIM_CONTINUE - if option not understood */ - int (*target_jim_commands)(struct target *target, Jim_GetOptInfo *goi); + int (*target_jim_commands)(struct target *target, struct jim_getopt_info *goi); /** * This method is used to perform target setup that requires @@ -243,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); @@ -287,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, @@ -296,6 +304,50 @@ struct target_type { * typically be 32 for 32-bit targets, and 64 for 64-bit targets. If not * implemented, it's assumed to be 32. */ unsigned (*address_bits)(struct target *target); + + /* Return the number of system bus data bits this target supports. This + * will typically be 32 for 32-bit targets, and 64 for 64-bit targets. If + * not implemented, it's assumed to be 32. */ + 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 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 2966bbd94c..e3d787eddf 100644 --- a/src/target/trace.h +++ b/src/target/trace.h @@ -1,24 +1,15 @@ +/* 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 #define OPENOCD_TARGET_TRACE_H +#include "helper/types.h" + struct target; struct command_context; diff --git a/src/target/x86_32_common.c b/src/target/x86_32_common.c index b85e451194..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 */ @@ -75,7 +64,7 @@ int x86_32_get_gdb_reg_list(struct target *t, *reg_list_size = x86_32->cache->num_regs; LOG_DEBUG("num_regs=%d, reg_class=%d", (*reg_list_size), reg_class); *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); - if (*reg_list == NULL) { + if (!*reg_list) { LOG_ERROR("%s out of memory", __func__); return ERROR_FAIL; } @@ -95,7 +84,7 @@ int x86_32_common_init_arch_info(struct target *t, struct x86_32_common *x86_32) x86_32->num_hw_bpoints = MAX_DEBUG_REGS; x86_32->hw_break_list = calloc(x86_32->num_hw_bpoints, sizeof(struct x86_32_dbg_reg)); - if (x86_32->hw_break_list == NULL) { + if (!x86_32->hw_break_list) { LOG_ERROR("%s out of memory", __func__); return ERROR_FAIL; } @@ -157,7 +146,7 @@ int x86_32_common_read_phys_mem(struct target *t, target_addr_t phys_address, * with the original instructions again. */ struct swbp_mem_patch *iter = x86_32->swbbp_mem_patch_list; - while (iter != NULL) { + while (iter) { if (iter->physaddr >= phys_address && iter->physaddr < phys_address+(size*count)) { uint32_t offset = iter->physaddr - phys_address; buffer[offset] = iter->orig_byte; @@ -245,20 +234,20 @@ int x86_32_common_write_phys_mem(struct target *t, target_addr_t phys_address, * breakpoint instruction. */ newbuffer = malloc(size*count); - if (newbuffer == NULL) { + if (!newbuffer) { LOG_ERROR("%s out of memory", __func__); return ERROR_FAIL; } memcpy(newbuffer, buffer, size*count); struct swbp_mem_patch *iter = x86_32->swbbp_mem_patch_list; - while (iter != NULL) { + while (iter) { if (iter->physaddr >= phys_address && iter->physaddr < phys_address+(size*count)) { uint32_t offset = iter->physaddr - phys_address; newbuffer[offset] = SW_BP_OPCODE; /* update the breakpoint */ struct breakpoint *pbiter = t->breakpoints; - while (pbiter != NULL && pbiter->unique_id != iter->swbp_unique_id) + while (pbiter && pbiter->unique_id != iter->swbp_unique_id) pbiter = pbiter->next; if (pbiter) pbiter->orig_instr[0] = buffer[offset]; @@ -456,7 +445,7 @@ int calcaddr_physfromlin(struct target *t, target_addr_t addr, target_addr_t *ph { uint8_t entry_buffer[8]; - if (physaddr == NULL || t == NULL) + if (!physaddr || !t) return ERROR_FAIL; struct x86_32_common *x86_32 = target_to_x86_32(t); @@ -472,10 +461,10 @@ int calcaddr_physfromlin(struct target *t, target_addr_t addr, target_addr_t *ph } uint32_t cr4 = buf_get_u32(x86_32->cache->reg_list[CR4].value, 0, 32); - bool isPAE = cr4 & 0x00000020; /* PAE - Physical Address Extension */ + bool is_pae = cr4 & 0x00000020; /* PAE - Physical Address Extension */ uint32_t cr3 = buf_get_u32(x86_32->cache->reg_list[CR3].value, 0, 32); - if (isPAE) { + if (is_pae) { uint32_t pdpt_base = cr3 & 0xFFFFF000; /* lower 12 bits of CR3 must always be 0 */ uint32_t pdpt_index = (addr & 0xC0000000) >> 30; /* A[31:30] index to PDPT */ uint32_t pdpt_addr = pdpt_base + (8 * pdpt_index); @@ -862,7 +851,7 @@ int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp) { if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; - if (wp->set) + if (wp->is_set) unset_watchpoint(t, wp); return ERROR_OK; } @@ -883,7 +872,7 @@ int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp) LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; - if (bp->set) + if (bp->is_set) unset_breakpoint(t, bp); return ERROR_OK; @@ -995,7 +984,7 @@ static int set_hwbp(struct target *t, struct breakpoint *bp) } if (set_debug_regs(t, bp->address, hwbp_num, DR7_BP_EXECUTE, 1) != ERROR_OK) return ERROR_FAIL; - bp->set = hwbp_num + 1; + breakpoint_hw_set(bp, hwbp_num); debug_reg_list[hwbp_num].used = 1; debug_reg_list[hwbp_num].bp_value = bp->address; LOG_USER("%s hardware breakpoint %" PRIu32 " set at 0x%08" PRIx32 " (hwreg=%" PRIu8 ")", __func__, @@ -1007,9 +996,9 @@ static int unset_hwbp(struct target *t, struct breakpoint *bp) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; - int hwbp_num = bp->set - 1; + int hwbp_num = bp->number; - if ((hwbp_num < 0) || (hwbp_num >= x86_32->num_hw_bpoints)) { + if (hwbp_num >= x86_32->num_hw_bpoints) { LOG_ERROR("%s invalid breakpoint number=%d, bpid=%" PRIu32, __func__, hwbp_num, bp->unique_id); return ERROR_OK; @@ -1055,11 +1044,11 @@ static int set_swbp(struct target *t, struct breakpoint *bp) __func__, readback, *bp->orig_instr); return ERROR_FAIL; } - bp->set = SW_BP_OPCODE; /* just non 0 */ + bp->is_set = true; /* add the memory patch */ struct swbp_mem_patch *new_patch = malloc(sizeof(struct swbp_mem_patch)); - if (new_patch == NULL) { + if (!new_patch) { LOG_ERROR("%s out of memory", __func__); return ERROR_FAIL; } @@ -1069,10 +1058,10 @@ static int set_swbp(struct target *t, struct breakpoint *bp) new_patch->swbp_unique_id = bp->unique_id; struct swbp_mem_patch *addto = x86_32->swbbp_mem_patch_list; - if (addto == NULL) + if (!addto) x86_32->swbbp_mem_patch_list = new_patch; else { - while (addto->next != NULL) + while (addto->next) addto = addto->next; addto->next = new_patch; } @@ -1107,15 +1096,15 @@ static int unset_swbp(struct target *t, struct breakpoint *bp) /* remove from patch */ struct swbp_mem_patch *iter = x86_32->swbbp_mem_patch_list; - if (iter != NULL) { + if (iter) { if (iter->swbp_unique_id == bp->unique_id) { /* it's the first item */ x86_32->swbbp_mem_patch_list = iter->next; free(iter); } else { - while (iter->next != NULL && iter->next->swbp_unique_id != bp->unique_id) + while (iter->next && iter->next->swbp_unique_id != bp->unique_id) iter = iter->next; - if (iter->next != NULL) { + if (iter->next) { /* it's the next one */ struct swbp_mem_patch *freeme = iter->next; iter->next = iter->next->next; @@ -1134,7 +1123,7 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp) int error = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); - if (bp->set) { + if (bp->is_set) { LOG_ERROR("breakpoint already set"); return error; } @@ -1164,7 +1153,7 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp) static int unset_breakpoint(struct target *t, struct breakpoint *bp) { LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); - if (!bp->set) { + if (!bp->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -1182,7 +1171,7 @@ static int unset_breakpoint(struct target *t, struct breakpoint *bp) return ERROR_FAIL; } } - bp->set = 0; + bp->is_set = false; return ERROR_OK; } @@ -1193,7 +1182,7 @@ static int set_watchpoint(struct target *t, struct watchpoint *wp) int wp_num = 0; LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, wp->rw, wp->address); - if (wp->set) { + if (wp->is_set) { LOG_ERROR("%s watchpoint already set", __func__); return ERROR_OK; } @@ -1233,7 +1222,7 @@ static int set_watchpoint(struct target *t, struct watchpoint *wp) LOG_ERROR("%s only 'access' or 'write' watchpoints are supported", __func__); break; } - wp->set = wp_num + 1; + watchpoint_set(wp, wp_num); debug_reg_list[wp_num].used = 1; debug_reg_list[wp_num].bp_value = wp->address; LOG_USER("'%s' watchpoint %d set at " TARGET_ADDR_FMT " with length %" PRIu32 " (hwreg=%d)", @@ -1248,13 +1237,13 @@ static int unset_watchpoint(struct target *t, struct watchpoint *wp) struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, wp->rw, wp->address); - if (!wp->set) { + if (!wp->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = wp->set - 1; - if ((wp_num < 0) || (wp_num >= x86_32->num_hw_bpoints)) { + int wp_num = wp->number; + if (wp_num >= x86_32->num_hw_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } @@ -1263,7 +1252,7 @@ static int unset_watchpoint(struct target *t, struct watchpoint *wp) debug_reg_list[wp_num].used = 0; debug_reg_list[wp_num].bp_value = 0; - wp->set = 0; + wp->is_set = false; LOG_USER("'%s' watchpoint %d removed from " TARGET_ADDR_FMT " with length %" PRIu32 " (hwreg=%d)", wp->rw == WPT_READ ? "read" : wp->rw == WPT_WRITE ? @@ -1428,7 +1417,7 @@ COMMAND_HANDLER(handle_iod_command) uint8_t *buffer = calloc(count, size); struct target *target = get_current_target(CMD_CTX); int retval = x86_32_common_read_io(target, address, size, buffer); - if (ERROR_OK == retval) + if (retval == ERROR_OK) handle_iod_output(CMD, target, address, size, count, buffer); free(buffer); return retval; 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 6d1d426d52..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 @@ -150,7 +139,7 @@ static int xscale_verify_pointer(struct command_invocation *cmd, static int xscale_jtag_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_state_t end_state) { - assert(tap != NULL); + assert(tap); if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; @@ -1087,7 +1076,7 @@ static void xscale_enable_watchpoints(struct target *target) struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) xscale_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } @@ -1099,7 +1088,7 @@ static void xscale_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->is_set) xscale_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -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; } @@ -1158,7 +1147,7 @@ static int xscale_resume(struct target *target, int current, struct breakpoint *breakpoint; breakpoint = breakpoint_find(target, buf_get_u32(arm->pc->value, 0, 32)); - if (breakpoint != NULL) { + if (breakpoint) { uint32_t next_pc; enum trace_mode saved_trace_mode; @@ -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; } @@ -1421,7 +1410,7 @@ static int xscale_step(struct target *target, int current, if (handle_breakpoints) breakpoint = breakpoint_find(target, buf_get_u32(arm->pc->value, 0, 32)); - if (breakpoint != NULL) { + if (breakpoint) { retval = xscale_unset_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; @@ -1506,7 +1495,7 @@ static int xscale_deassert_reset(struct target *target) /* mark all hardware breakpoints as unset */ while (breakpoint) { if (breakpoint->type == BKPT_HARD) - breakpoint->set = 0; + breakpoint->is_set = false; breakpoint = breakpoint->next; } @@ -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,11 +2073,11 @@ 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; } - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -2098,11 +2087,13 @@ static int xscale_set_breakpoint(struct target *target, if (!xscale->ibcr0_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value); xscale->ibcr0_used = 1; - breakpoint->set = 1; /* breakpoint set on first breakpoint register */ + /* breakpoint set on first breakpoint register */ + breakpoint_hw_set(breakpoint, 0); } else if (!xscale->ibcr1_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value); xscale->ibcr1_used = 1; - breakpoint->set = 2; /* breakpoint set on second breakpoint register */ + /* breakpoint set on second breakpoint register */ + breakpoint_hw_set(breakpoint, 1); } else {/* bug: availability previously verified in xscale_add_breakpoint() */ LOG_ERROR("BUG: no hardware comparator available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -2133,7 +2124,7 @@ static int xscale_set_breakpoint(struct target *target, if (retval != ERROR_OK) return retval; } - breakpoint->set = 1; + breakpoint->is_set = true; xscale_send_u32(target, 0x50); /* clean dcache */ xscale_send_u32(target, xscale->cache_clean_address); @@ -2172,24 +2163,24 @@ 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; } - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { - if (breakpoint->set == 1) { + if (breakpoint->number == 0) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0); xscale->ibcr0_used = 0; - } else if (breakpoint->set == 2) { + } else if (breakpoint->number == 1) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0); xscale->ibcr1_used = 0; } - breakpoint->set = 0; + breakpoint->is_set = false; } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { @@ -2203,7 +2194,7 @@ static int xscale_unset_breakpoint(struct target *target, if (retval != ERROR_OK) return retval; } - breakpoint->set = 0; + breakpoint->is_set = false; xscale_send_u32(target, 0x50); /* clean dcache */ xscale_send_u32(target, xscale->cache_clean_address); @@ -2219,11 +2210,11 @@ 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; } - if (breakpoint->set) + if (breakpoint->is_set) xscale_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) @@ -2241,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; } @@ -2279,13 +2270,13 @@ static int xscale_set_watchpoint(struct target *target, xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address); dbcon_value |= enable; xscale_set_reg_u32(dbcon, dbcon_value); - watchpoint->set = 1; + watchpoint_set(watchpoint, 0); xscale->dbr0_used = 1; } else if (!xscale->dbr1_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address); dbcon_value |= enable << 2; xscale_set_reg_u32(dbcon, dbcon_value); - watchpoint->set = 2; + watchpoint_set(watchpoint, 1); xscale->dbr1_used = 1; } else { LOG_ERROR("BUG: no hardware comparator available"); @@ -2305,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 */ @@ -2345,16 +2336,16 @@ 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; } - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } - if (watchpoint->set == 1) { + if (watchpoint->number == 0) { if (watchpoint->length > 4) { dbcon_value &= ~0x103; /* clear DBCON[M] as well */ xscale->dbr1_used = 0; /* DBR1 was used for mask */ @@ -2363,12 +2354,12 @@ static int xscale_unset_watchpoint(struct target *target, xscale_set_reg_u32(dbcon, dbcon_value); xscale->dbr0_used = 0; - } else if (watchpoint->set == 2) { + } else if (watchpoint->number == 1) { dbcon_value &= ~0xc; xscale_set_reg_u32(dbcon, dbcon_value); xscale->dbr1_used = 0; } - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -2378,11 +2369,11 @@ 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; } - if (watchpoint->set) + if (watchpoint->is_set) xscale_unset_watchpoint(target, watchpoint); if (watchpoint->length > 4) @@ -2499,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; } @@ -2582,7 +2573,6 @@ static int xscale_read_instruction(struct target *target, uint32_t pc, struct arm_instruction *instruction) { struct xscale_common *const xscale = target_to_xscale(target); - int i; int section = -1; size_t size_read; uint32_t opcode; @@ -2592,7 +2582,7 @@ static int xscale_read_instruction(struct target *target, uint32_t pc, return ERROR_TRACE_IMAGE_UNAVAILABLE; /* search for the section the current instruction belongs to */ - for (i = 0; i < xscale->trace.image->num_sections; i++) { + for (unsigned int i = 0; i < xscale->trace.image->num_sections; i++) { if ((xscale->trace.image->sections[i].base_address <= pc) && (xscale->trace.image->sections[i].base_address + xscale->trace.image->sections[i].size > pc)) { @@ -2883,7 +2873,7 @@ static void xscale_build_reg_cache(struct target *target) /* fill in values for the xscale reg cache */ (*cache_p)->name = "XScale registers"; (*cache_p)->next = NULL; - (*cache_p)->reg_list = malloc(num_regs * sizeof(struct reg)); + (*cache_p)->reg_list = calloc(num_regs, sizeof(struct reg)); (*cache_p)->num_regs = num_regs; for (i = 0; i < num_regs; i++) { @@ -3049,7 +3039,7 @@ COMMAND_HANDLER(xscale_handle_debug_handler_command) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[0]); - if (target == NULL) { + if (!target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } @@ -3084,7 +3074,7 @@ COMMAND_HANDLER(xscale_handle_cache_clean_address_command) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[0]); - if (target == NULL) { + if (!target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } @@ -3141,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; @@ -3159,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) { @@ -3189,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; @@ -3357,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) { @@ -3428,15 +3418,15 @@ COMMAND_HANDLER(xscale_handle_trace_image_command) } xscale->trace.image = malloc(sizeof(struct image)); - xscale->trace.image->base_address_set = 0; - xscale->trace.image->start_address_set = 0; + xscale->trace.image->base_address_set = false; + xscale->trace.image->start_address_set = false; /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { - xscale->trace.image->base_address_set = 1; + xscale->trace.image->base_address_set = true; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], xscale->trace.image->base_address); } else - xscale->trace.image->base_address_set = 0; + xscale->trace.image->base_address_set = false; if (image_open(xscale->trace.image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL) != ERROR_OK) { @@ -3461,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) @@ -3524,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..ac4a49ccf4 --- /dev/null +++ b/src/target/xtensa/xtensa_chip.c @@ -0,0 +1,199 @@ +// 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) +{ + return adiv5_jim_configure_ext(target, goi, NULL, ADI_CONFIGURE_DAP_OPTIONAL); +} + +/** 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 9214dcd774..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 @@ -42,6 +31,7 @@ */ #include <helper/log.h> +#include <helper/replacements.h> #include <transport/transport.h> extern struct command_context *global_cmd_ctx; @@ -105,7 +95,7 @@ int allow_transports(struct command_context *ctx, const char * const *vector) * of one transport; C code should be definitive about what * can be used when all goes well. */ - if (allowed_transports != NULL || session) { + if (allowed_transports || session) { LOG_ERROR("Can't modify the set of allowed transports."); return ERROR_FAIL; } @@ -114,23 +104,13 @@ 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]); } return ERROR_OK; } -/** - * Used to verify correct adapter driver initialization. - * - * @returns true if the adapter declares one or more transports. - */ -bool transports_are_declared(void) -{ - return allowed_transports != NULL; -} - /** * Registers a transport. There are general purpose transports * (such as JTAG), as well as relatively proprietary ones which are @@ -206,7 +186,7 @@ COMMAND_HELPER(transport_list_parse, char ***vector) /* our return vector must be NULL terminated */ argv = calloc(n + 1, sizeof(char *)); - if (argv == NULL) + if (!argv) return ERROR_FAIL; for (unsigned i = 0; i < n; i++) { @@ -272,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[] = { @@ -353,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 809564e789..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 @@ -92,8 +81,6 @@ COMMAND_HELPER(transport_list_parse, char ***vector); int allow_transports(struct command_context *ctx, const char * const *vector); -bool transports_are_declared(void); - bool transport_is_jtag(void); bool transport_is_swd(void); bool transport_is_dapdirect_jtag(void); 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 eaa5a3aae1..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: @@ -39,6 +28,7 @@ #endif #include "xsvf.h" +#include "helper/system.h" #include <jtag/jtag.h> #include <svf/svf.h> @@ -486,7 +476,7 @@ COMMAND_HANDLER(handle_xsvf_command) field.out_value = dr_out_buf; field.in_value = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); - if (tap == NULL) + if (!tap) jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, @@ -695,7 +685,7 @@ COMMAND_HANDLER(handle_xsvf_command) field.in_value = NULL; - if (tap == NULL) + if (!tap) jtag_add_plain_ir_scan(field.num_bits, field.out_value, field.in_value, my_end_state); else @@ -929,7 +919,7 @@ COMMAND_HANDLER(handle_xsvf_command) if (attempt > 0 && verbose) LOG_USER("LSDR retry %d", attempt); - if (tap == NULL) + if (!tap) jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, @@ -1056,7 +1046,7 @@ int xsvf_register_commands(struct command_context *cmd_ctx) /* -PSUEDO-Code from Xilinx Appnote XAPP067.pdf : +PSEUDO-Code from Xilinx Appnote XAPP067.pdf : the following pseudo code clarifies the intent of the xrepeat support.The flow given is for the entire processing of an SVF file, not an XSVF file. 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 52ca83db2e..03d758e7c8 100644 --- a/tcl/bitsbytes.tcl +++ b/tcl/bitsbytes.tcl @@ -1,34 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #---------------------------------------- # Purpose - Create some $BIT variables # Create $K and $M variables # and some bit field extraction variables. -# Creat helper variables ... +# Create helper variables ... # BIT0.. BIT31 -for { set x 0 } { $x < 32 } { set x [expr $x + 1]} { +for { set x 0 } { $x < 32 } { set x [expr {$x + 1}]} { set vn [format "BIT%d" $x] global $vn - set $vn [expr (1 << $x)] + set $vn [expr {1 << $x}] } # Create K bytes values # __1K ... to __2048K -for { set x 1 } { $x < 2048 } { set x [expr $x * 2]} { +for { set x 1 } { $x < 2048 } { set x [expr {$x * 2}]} { set vn [format "__%dK" $x] global $vn - set $vn [expr (1024 * $x)] + set $vn [expr {1024 * $x}] } # Create M bytes values # __1M ... to __2048K -for { set x 1 } { $x < 2048 } { set x [expr $x * 2]} { +for { set x 1 } { $x < 2048 } { set x [expr {$x * 2}]} { set vn [format "__%dM" $x] global $vn - set $vn [expr (1024 * 1024 * $x)] + set $vn [expr {1024 * 1024 * $x}] } proc create_mask { MSB LSB } { - return [expr (((1 << ($MSB - $LSB + 1))-1) << $LSB)] + return [expr {((1 << ($MSB - $LSB + 1))-1) << $LSB}] } # Cut Bits $MSB to $LSB out of this value. @@ -36,7 +38,7 @@ proc create_mask { MSB LSB } { # Result: 0x02340000 proc extract_bitfield { VALUE MSB LSB } { - return [expr [create_mask $MSB $LSB] & $VALUE] + return [expr {[create_mask $MSB $LSB] & $VALUE}] } @@ -47,13 +49,13 @@ proc extract_bitfield { VALUE MSB LSB } { # Result: 0x00000234 # proc normalize_bitfield { VALUE MSB LSB } { - return [expr [extract_bitfield $VALUE $MSB $LSB ] >> $LSB] + return [expr {[extract_bitfield $VALUE $MSB $LSB ] >> $LSB}] } proc show_normalize_bitfield { VALUE MSB LSB } { set m [create_mask $MSB $LSB] - set mr [expr $VALUE & $m] - set sr [expr $mr >> $LSB] + set mr [expr {$VALUE & $m}] + set sr [expr {$mr >> $LSB}] echo [format "((0x%08x & 0x%08x) -> 0x%08x) >> %2d => (0x%x) %5d " $VALUE $m $mr $LSB $sr $sr] return $sr } 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 eb4c863fa7..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 @@ -12,7 +14,7 @@ adapter driver usb_blaster source [find target/altera_fpgasoc.cfg] # If the USB Blaster II were supported, these settings would be needed -#usb_blaster_vid_pid 0x6810 0x09fb -#usb_blaster_device_desc "USB-Blaster II" +#usb_blaster vid_pid 0x09fb 0x6810 +#usb_blaster device_desc "USB-Blaster II" adapter speed 100 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 new file mode 100644 index 0000000000..736be12258 --- /dev/null +++ b/tcl/board/ampere_emag8180.cfg @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# OpenOCD Board Configuration for eMAG Development Platform +# +# Copyright (c) 2019-2021, Ampere Computing LLC +# + +# +# Configure JTAG speed +# + +adapter speed 2000 + +# +# Configure Resets +# + +jtag_ntrst_delay 100 +reset_config trst_only + +# +# Configure Targets +# + +source [find target/ampere_emag.cfg] 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 96d859cd3b..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] @@ -5,5 +7,5 @@ source [find target/samsung_s3c4510.cfg] # # FIXME: # Add (A) sdram configuration -# Add (B) flash cfi programing configuration +# Add (B) flash cfi programming configuration # 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 5ab408391e..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 # @@ -23,7 +25,7 @@ adapter speed 25000 # openocd -f board/arty_s7.cfg -c "init;\ # jtagspi_init 0 bscan_spi_xc7s??.bit;\ # jtagspi_program bitstream.bin 0;\ -# xc7s_program xc7s.tap;\ +# xc7_program xc7.tap;\ # shutdown" # # jtagspi flash proxies can be found at: 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 8395ba33bc..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 @@ -32,13 +34,12 @@ $_TARGETNAME configure -event reset-start { } proc peek32 {address} { - mem2array t 32 $address 1 - return $t(0) + return [read_memory $address 32 1] } # Wait for an expression to be true with a timeout proc wait_state {expression} { - for {set i 0} {$i < 1000} {set i [expr $i + 1]} { + for {set i 0} {$i < 1000} {set i [expr {$i + 1}]} { if {[uplevel 1 $expression] == 0} { return } 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 3963e9373d..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 ################################################################################ @@ -29,30 +31,30 @@ proc at91sam9261ek_reset_init { } { ;# set master_pll_div 1 ;# set master_pll_mul 13 - set val [expr $::AT91_WDT_WDV] ;# Counter Value - set val [expr ($val | $::AT91_WDT_WDDIS)] ;# Watchdog Disable - set val [expr ($val | $::AT91_WDT_WDD)] ;# Delta Value - set val [expr ($val | $::AT91_WDT_WDDBGHLT)] ;# Debug Halt - set val [expr ($val | $::AT91_WDT_WDIDLEHLT)] ;# Idle Halt + set val $::AT91_WDT_WDV ;# Counter Value + set val [expr {$val | $::AT91_WDT_WDDIS}] ;# Watchdog Disable + set val [expr {$val | $::AT91_WDT_WDD}] ;# Delta Value + set val [expr {$val | $::AT91_WDT_WDDBGHLT}] ;# Debug Halt + set val [expr {$val | $::AT91_WDT_WDIDLEHLT}] ;# Idle Halt set config(wdt_mr_val) $val ;# EBI_CSA, no pull-ups for D[15:0], CS1 SDRAM, CS3 NAND Flash set config(matrix_ebicsa_addr) $::AT91_MATRIX_EBICSA - set config(matrix_ebicsa_val) [expr ($::AT91_MATRIX_DBPUC | $::AT91_MATRIX_CS1A_SDRAMC)] + set config(matrix_ebicsa_val) [expr {$::AT91_MATRIX_DBPUC | $::AT91_MATRIX_CS1A_SDRAMC}] ;# SDRAMC_CR - Configuration register - set val [expr $::AT91_SDRAMC_NC_9] - set val [expr ($val | $::AT91_SDRAMC_NR_13)] - set val [expr ($val | $::AT91_SDRAMC_NB_4)] - set val [expr ($val | $::AT91_SDRAMC_CAS_3)] - set val [expr ($val | $::AT91_SDRAMC_DBW_32)] - set val [expr ($val | (2 << 8))] ;# Write Recovery Delay - set val [expr ($val | (7 << 12))] ;# Row Cycle Delay - set val [expr ($val | (3 << 16))] ;# Row Precharge Delay - set val [expr ($val | (2 << 20))] ;# Row to Column Delay - set val [expr ($val | (5 << 24))] ;# Active to Precharge Delay - set val [expr ($val | (8 << 28))] ;# Exit Self Refresh to Active Delay + set val $::AT91_SDRAMC_NC_9 + set val [expr {$val | $::AT91_SDRAMC_NR_13}] + set val [expr {$val | $::AT91_SDRAMC_NB_4}] + set val [expr {$val | $::AT91_SDRAMC_CAS_3}] + set val [expr {$val | $::AT91_SDRAMC_DBW_32}] + set val [expr {$val | (2 << 8)}] ;# Write Recovery Delay + set val [expr {$val | (7 << 12)}] ;# Row Cycle Delay + set val [expr {$val | (3 << 16)}] ;# Row Precharge Delay + set val [expr {$val | (2 << 20)}] ;# Row to Column Delay + set val [expr {$val | (5 << 24)}] ;# Active to Precharge Delay + set val [expr {$val | (8 << 28)}] ;# Exit Self Refresh to Active Delay set config(sdram_cr_val) $val diff --git a/tcl/board/at91sam9263-ek.cfg b/tcl/board/at91sam9263-ek.cfg index 645b1a7bd0..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 ################################################################################ @@ -24,11 +26,11 @@ proc at91sam9263ek_reset_init { } { set config(master_pll_div) 14 set config(master_pll_mul) 171 - set val [expr $::AT91_WDT_WDV] ;# Counter Value - set val [expr ($val | $::AT91_WDT_WDDIS)] ;# Watchdog Disable - set val [expr ($val | $::AT91_WDT_WDD)] ;# Delta Value - set val [expr ($val | $::AT91_WDT_WDDBGHLT)] ;# Debug Halt - set val [expr ($val | $::AT91_WDT_WDIDLEHLT)] ;# Idle Halt + set val $::AT91_WDT_WDV ;# Counter Value + set val [expr {$val | $::AT91_WDT_WDDIS}] ;# Watchdog Disable + set val [expr {$val | $::AT91_WDT_WDD}] ;# Delta Value + set val [expr {$val | $::AT91_WDT_WDDBGHLT}] ;# Debug Halt + set val [expr {$val | $::AT91_WDT_WDIDLEHLT}] ;# Idle Halt set config(wdt_mr_val) $val @@ -36,23 +38,23 @@ proc at91sam9263ek_reset_init { } { ;# EBI_CSA, no pull-ups for D[15:0], CS1 SDRAM, CS3 NAND Flash set config(matrix_ebicsa_addr) $::AT91_MATRIX_EBI0CSA - set val [expr $::AT91_MATRIX_EBI0_DBPUC] - set val [expr ($val | $::AT91_MATRIX_EBI0_VDDIOMSEL_3_3V)] - set val [expr ($val | $::AT91_MATRIX_EBI0_CS1A_SDRAMC)] + set val $::AT91_MATRIX_EBI0_DBPUC + set val [expr {$val | $::AT91_MATRIX_EBI0_VDDIOMSEL_3_3V}] + set val [expr {$val | $::AT91_MATRIX_EBI0_CS1A_SDRAMC}] set config(matrix_ebicsa_val) $val ;# SDRAMC_CR - Configuration register - set val [expr $::AT91_SDRAMC_NC_9] - set val [expr ($val | $::AT91_SDRAMC_NR_13)] - set val [expr ($val | $::AT91_SDRAMC_NB_4)] - set val [expr ($val | $::AT91_SDRAMC_CAS_3)] - set val [expr ($val | $::AT91_SDRAMC_DBW_32)] - set val [expr ($val | (1 << 8))] ;# Write Recovery Delay - set val [expr ($val | (7 << 12))] ;# Row Cycle Delay - set val [expr ($val | (2 << 16))] ;# Row Precharge Delay - set val [expr ($val | (2 << 20))] ;# Row to Column Delay - set val [expr ($val | (5 << 24))] ;# Active to Precharge Delay - set val [expr ($val | (1 << 28))] ;# Exit Self Refresh to Active Delay + set val $::AT91_SDRAMC_NC_9 + set val [expr {$val | $::AT91_SDRAMC_NR_13}] + set val [expr {$val | $::AT91_SDRAMC_NB_4}] + set val [expr {$val | $::AT91_SDRAMC_CAS_3}] + set val [expr {$val | $::AT91_SDRAMC_DBW_32}] + set val [expr {$val | (1 << 8)}] ;# Write Recovery Delay + set val [expr {$val | (7 << 12)}] ;# Row Cycle Delay + set val [expr {$val | (2 << 16)}] ;# Row Precharge Delay + set val [expr {$val | (2 << 20)}] ;# Row to Column Delay + set val [expr {$val | (5 << 24)}] ;# Active to Precharge Delay + set val [expr {$val | (1 << 28)}] ;# Exit Self Refresh to Active Delay set config(sdram_cr_val) $val diff --git a/tcl/board/at91sam9g20-ek.cfg b/tcl/board/at91sam9g20-ek.cfg index 03296c50e3..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 @@ -40,9 +38,7 @@ at91sam9 rdy_busy 0 0xfffff800 13 at91sam9 ce 0 0xfffff800 14 proc read_register {register} { - set result "" - mem2array result 32 $register 1 - return $result(0) + return [read_memory $register 32 1] } proc at91sam9g20_reset_start { } { @@ -77,25 +73,25 @@ proc at91sam9g20_reset_init { } { # Wait for MOSCS in PMC_SR to assert indicating oscillator is again stable after change to CKGR_MOR. mww 0xfffffc20 0x00004001 - while { [expr [read_register 0xfffffc68] & 0x01] != 1 } { sleep 1 } + while { [expr {[read_register 0xfffffc68] & 0x01}] != 1 } { sleep 1 } # Set PLLA Register for 792.576 MHz (divider: bypass, multiplier: 43). # Wait for LOCKA signal in PMC_SR to assert indicating PLLA is stable. mww 0xfffffc28 0x202a3f01 - while { [expr [read_register 0xfffffc68] & 0x02] != 2 } { sleep 1 } + while { [expr {[read_register 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 0x00000101 - while { [expr [read_register 0xfffffc68] & 0x08] != 8 } { sleep 1 } + while { [expr {[read_register 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 [read_register 0xfffffc68] & 0x08] != 8 } { sleep 1 } + while { [expr {[read_register 0xfffffc68] & 0x08}] != 8 } { sleep 1 } # Processor and master clocks are now operating and stable at maximum frequency possible: # -> MCLK = 132.096 MHz @@ -153,7 +149,7 @@ proc at91sam9g20_reset_init { } { nand probe nandflash_cs3 - # The AT91SAM9G20-EK evaluation board has build-in serial data flash also. + # The AT91SAM9G20-EK evaluation board has built-in serial data flash also. # Now setup SDRAM. This is tricky and configuration is very important for reliability! The current calculations # are based on 2 x Micron MT48LC16M16A2-75 memory (4 M x 16 bit x 4 banks). If you use this file as a reference 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..3c92b500c1 --- /dev/null +++ b/tcl/board/bemicro_cycloneiii.cfg @@ -0,0 +1,25 @@ +# 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 create-hub cycloneiii.ipdbghub -tap cycloneiii.tap -ir 0x00e" +# "cycloneiii.ipdbghub ipdbg start -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 954e540083..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 # @@ -8,10 +10,10 @@ # adapter driver ftdi -ftdi_device_desc "Digilent USB Device" -ftdi_vid_pid 0x0403 0x6014 +ftdi device_desc "Digilent USB Device" +ftdi vid_pid 0x0403 0x6014 -ftdi_layout_init 0x8008 0x800b +ftdi layout_init 0x8008 0x800b adapter speed 25000 diff --git a/tcl/board/digilent_atlys.cfg b/tcl/board/digilent_atlys.cfg index f298e3d73d..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 @@ -5,7 +7,7 @@ # ID 1443:0007 Digilent Development board JTAG # # However, the ixo-usb-jtag project provides an alternative open firmware for -# the on board programmer. When using thie firmware the board will then +# the on board programmer. When using this firmware the board will then # enumerate as: # ID 16c0:06ad Van Ooijen Technische Informatica # (With SerialNumber == hw_nexys) diff --git a/tcl/board/digilent_cmod_s7.cfg b/tcl/board/digilent_cmod_s7.cfg new file mode 100644 index 0000000000..4fa45a17a7 --- /dev/null +++ b/tcl/board/digilent_cmod_s7.cfg @@ -0,0 +1,26 @@ +# 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 create-hub xc7.ipdbghub -tap xc7.tap -ir 0x02" +# "xc7.ipdbghub ipdbg start -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_nexys_video.cfg b/tcl/board/digilent_nexys_video.cfg new file mode 100644 index 0000000000..b60ec912fc --- /dev/null +++ b/tcl/board/digilent_nexys_video.cfg @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Digilent Nexys Video with Xilinx Artix-7 FPGA +# https://reference.digilentinc.com/programmable-logic/nexys-video/start + +adapter driver ftdi +adapter speed 30000 + +ftdi device_desc "Digilent USB Device" +ftdi vid_pid 0x0403 0x6010 + +# channel 0 is dedicated for Digilent's DPTI Interface +# channel 1 is used for JTAG +ftdi channel 1 + +# just TCK TDI TDO TMS, no reset +ftdi layout_init 0x0088 0x008b +reset_config none + +# Enable sampling on falling edge for high JTAG speeds. +ftdi tdo_sample_edge falling + +transport select jtag + +source [find cpld/xilinx-xc7.cfg] +source [find cpld/jtagspi.cfg] 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 0c971e9a0b..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/ @@ -80,14 +82,14 @@ proc dm355evm_init {} { # VTPIOCR impedance calibration set addr [dict get $dm355 sysbase] - set addr [expr $addr + 0x70] + set addr [expr {$addr + 0x70}] # clear CLR, LOCK, PWRDN; wait a clock; set CLR mmw $addr 0 0x20c0 mmw $addr 0x2000 0 # wait for READY - while { [expr [mrw $addr] & 0x8000] == 0 } { sleep 1 } + while { [expr {[mrw $addr] & 0x8000}] == 0 } { sleep 1 } # set IO_READY; then LOCK and PWRSAVE; then PWRDN mmw $addr 0x4000 0 @@ -108,24 +110,24 @@ proc dm355evm_init {} { set addr [dict get $dm355 ddr_emif] # DDRPHYCR1 - mww [expr $addr + 0xe4] 0x50006404 + mww [expr {$addr + 0xe4}] 0x50006404 # PBBPR -- burst priority - mww [expr $addr + 0x20] 0xfe + mww [expr {$addr + 0x20}] 0xfe # SDCR -- unlock boot config; init for DDR2, relock, unlock SDTIM* - mmw [expr $addr + 0x08] 0x00800000 0 - mmw [expr $addr + 0x08] 0x0013c632 0x03870fff + mmw [expr {$addr + 0x08}] 0x00800000 0 + mmw [expr {$addr + 0x08}] 0x0013c632 0x03870fff # SDTIMR0, SDTIMR1 - mww [expr $addr + 0x10] 0x2a923249 - mww [expr $addr + 0x14] 0x4c17c763 + mww [expr {$addr + 0x10}] 0x2a923249 + mww [expr {$addr + 0x14}] 0x4c17c763 # SDCR -- relock SDTIM* - mmw [expr $addr + 0x08] 0 0x00008000 + mmw [expr {$addr + 0x08}] 0 0x00008000 # SDRCR -- refresh rate (171 MHz * 7.8usec) - mww [expr $addr + 0x0c] 1336 + mww [expr {$addr + 0x0c}] 1336 ######################## # ASYNC EMIF @@ -138,13 +140,13 @@ proc dm355evm_init {} { #set nand_timings 0x0400008c # AWCCR - mww [expr $addr + 0x04] 0xff + mww [expr {$addr + 0x04}] 0xff # CS0 == socketed NAND (default MT29F16G08FAA, 2GByte) - mww [expr $addr + 0x10] $nand_timings + mww [expr {$addr + 0x10}] $nand_timings # CS1 == dm9000 Ethernet - mww [expr $addr + 0x14] 0x00a00505 + mww [expr {$addr + 0x14}] 0x00a00505 # NANDFCR -- only CS0 has NAND - mww [expr $addr + 0x60] 0x01 + mww [expr {$addr + 0x60}] 0x01 # default: both chipselects to the NAND socket are used nand probe 0 @@ -156,27 +158,27 @@ proc dm355evm_init {} { set addr [dict get $dm355 uart0] # PWREMU_MGNT -- rx + tx in reset - mww [expr $addr + 0x30] 0 + mww [expr {$addr + 0x30}] 0 # DLL, DLH -- 115200 baud - mwb [expr $addr + 0x20] 0x0d - mwb [expr $addr + 0x24] 0x00 + mwb [expr {$addr + 0x20}] 0x0d + mwb [expr {$addr + 0x24}] 0x00 # FCR - clear and disable FIFOs - mwb [expr $addr + 0x08] 0x07 - mwb [expr $addr + 0x08] 0x00 + mwb [expr {$addr + 0x08}] 0x07 + mwb [expr {$addr + 0x08}] 0x00 # IER - disable IRQs - mwb [expr $addr + 0x04] 0x00 + mwb [expr {$addr + 0x04}] 0x00 # LCR - 8-N-1 - mwb [expr $addr + 0x0c] 0x03 + mwb [expr {$addr + 0x0c}] 0x03 # MCR - no flow control or loopback - mwb [expr $addr + 0x10] 0x00 + mwb [expr {$addr + 0x10}] 0x00 # PWREMU_MGNT -- rx + tx normal, free running during JTAG halt - mww [expr $addr + 0x30] 0xe001 + mww [expr {$addr + 0x30}] 0xe001 ######################## diff --git a/tcl/board/dm365evm.cfg b/tcl/board/dm365evm.cfg index 3b29dd866c..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 @@ -56,10 +58,10 @@ if { $CS0 == "NAND" } { #set nand_timings 0x0400008c # CS0 == socketed NAND (default MT29F16G08FAA, 2 GBytes) - mww [expr $a_emif + 0x10] $nand_timings + mww [expr {$a_emif + 0x10}] $nand_timings # NANDFCR -- CS0 has NAND - mww [expr $a_emif + 0x60] 0x01 + mww [expr {$a_emif + 0x60}] 0x01 } proc flashprobe {} { nand probe 0 @@ -80,10 +82,10 @@ if { $CS0 == "NAND" } { davinci_pinmux $dm365 2 0x00000055 # CS0 == OneNAND (KFG1G16U2B-DIB6, 128 KBytes) - mww [expr $a_emif + 0x10] 0x00000001 + mww [expr {$a_emif + 0x10}] 0x00000001 # ONENANDCTRL -- CS0 has OneNAND, enable sync reads - mww [expr $a_emif + 0x5c] 0x0441 + mww [expr {$a_emif + 0x5c}] 0x0441 } proc flashprobe {} { } } @@ -133,11 +135,11 @@ proc dm365evm_init {} { set a_emif [dict get $dm365 a_emif] # AWCCR - mww [expr $a_emif + 0x04] 0xff + mww [expr {$a_emif + 0x04}] 0xff # CS0 == NAND or OneNAND cs0_setup $a_emif # CS1 == CPLD - mww [expr $a_emif + 0x14] 0x00a00505 + mww [expr {$a_emif + 0x14}] 0x00a00505 # FIXME setup UART0 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 a9974d9bcb..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 # @@ -8,6 +10,6 @@ # source [find interface/ftdi/dp_busblaster.cfg] -ftdi_channel 1 +ftdi channel 1 jtag newtap xc2c32a tap -expected-id 0x06e1c093 -irlen 8 diff --git a/tcl/board/dp_busblaster_v4.cfg b/tcl/board/dp_busblaster_v4.cfg new file mode 100644 index 0000000000..2c2f0e9d1a --- /dev/null +++ b/tcl/board/dp_busblaster_v4.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Dangerous Prototypes - Bus Blaster +# +# http://dangerousprototypes.com/docs/Bus_Blaster +# +# The Bus Blaster has a configurable buffer between the FTDI FT2232H +# and the JTAG header which allows it to emulate various debugger +# types. This config works with KT-Link compatible implementation from +# https://raw.githubusercontent.com/dergraaf/busblaster_v4/master/ktlink/ktlink.svf +# +# To reprogram the on-board CPLD do: +# openocd -f board/dp_busblaster_v4.cfg -c "adapter speed 1000; init; svf <path_to_svf>; shutdown" +# + +source [find interface/ftdi/dp_busblaster.cfg] +ftdi channel 1 + +jtag newtap xc2c64a tap -expected-id 0x06e5c093 -irlen 8 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..71769f6074 --- /dev/null +++ b/tcl/board/ecp5_evaluation.cfg @@ -0,0 +1,26 @@ +# 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 create-hub ecp5.ipdbghub -tap ecp5.tap -ir 0x32 +#ecp5.ipdbghub ipdbg start -tool 0 -port 5555 + +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 422db0d88f..d6342499fb 100644 --- a/tcl/board/eir.cfg +++ b/tcl/board/eir.cfg @@ -1,7 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Elector Internet Radio board # http://www.ethernut.de/en/hardware/eir/index.html -source [find target/sam7se512.cfg] +source [find target/at91sam7se512.cfg] $_TARGETNAME configure -event reset-init { # WDT_MR, disable watchdog 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 8ef9179de1..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/ @@ -8,9 +10,7 @@ source [find target/lpc2478.cfg] # Helper # proc read_register {register} { - set result "" - mem2array result 32 $register 1 - return $result(0) + return [read_memory $register 32 1] } proc init_board {} { @@ -26,7 +26,7 @@ proc init_board {} { global _CHIPNAME # A working area will help speeding the flash programming - $_TARGETNAME configure -work-area-phys 0x40000200 -work-area-size [expr 0x10000-0x200-0x20] -work-area-backup 0 + $_TARGETNAME configure -work-area-phys 0x40000200 -work-area-size [expr {0x10000-0x200-0x20}] -work-area-backup 0 # External 16-bit flash at chip select CS0 (SST39VF3201-70, 4 MiB) flash bank $_CHIPNAME.extflash cfi 0x80000000 0x400000 2 2 $_TARGETNAME jedec_probe @@ -125,7 +125,7 @@ proc init_board {} { # proc enable_pll {} { # Disconnect PLL in case it is already connected - if {[expr [read_register 0xE01FC080] & 0x03] == 3} { + if {[expr {[read_register 0xE01FC080] & 0x03}] == 3} { # Disconnect it, but leave it enabled # (This MUST be done in two steps) mww 0xE01FC080 0x00000001 ;# PLLCON: disconnect PLL 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/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/evb-lan9255.cfg b/tcl/board/evb-lan9255.cfg new file mode 100644 index 0000000000..3fd6f603b9 --- /dev/null +++ b/tcl/board/evb-lan9255.cfg @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip LAN9255 evaluation board +# https://www.microchip.com/en-us/development-tool/EV25Y25A +# + +set CHIPNAME same53 + +source [find target/atsame5x.cfg] + +reset_config srst_only 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..6cb07362b9 --- /dev/null +++ b/tcl/board/gowin_runber.cfg @@ -0,0 +1,20 @@ +# 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 create-hub gw1n.ipdbghub -tap gw1n.tap -ir 0x42 +#gw1n.ipdbghubipdbg start -tool 0 -port 5555 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 f0103ed451..ddadc88c0b 100644 --- a/tcl/board/gumstix-aerocore.cfg +++ b/tcl/board/gumstix-aerocore.cfg @@ -1,10 +1,12 @@ +# 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 -ftdi_vid_pid 0x0403 0x6011 +ftdi vid_pid 0x0403 0x6011 -ftdi_layout_init 0x0000 0x001b -ftdi_layout_signal nTRST -data 0x0010 +ftdi layout_init 0x0000 0x001b +ftdi layout_signal nTRST -data 0x0010 source [find target/stm32f4x.cfg] reset_config trst_only 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 add424d4ed..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) ################################################################################ @@ -26,15 +28,13 @@ proc flash_init { } { } proc mread32 {addr} { - set value(0) 0 - mem2array value 32 $addr 1 - return $value(0) + return [read_memory $addr 32 1] } proc init_clocks { } { puts "Enabling all clocks " set accesskey [mread32 0x101c0070] - mww 0x101c0070 [expr $accesskey] + mww 0x101c0070 $accesskey mww 0x101c0028 0x00007511 } @@ -42,7 +42,7 @@ proc init_clocks { } { proc init_sdrambus { } { puts "Initializing external SDRAM Bus 16 Bit " set accesskey [mread32 0x101c0070] - mww 0x101c0070 [expr $accesskey] + mww 0x101c0070 $accesskey mww 0x101c0C40 0x00000050 puts "Configuring SDRAM controller for K4S561632E (32MB) " 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 2fe1f3cdae..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/ @@ -34,7 +36,7 @@ flash bank $_FLASHNAME cfi 0x5C000000 0x400000 2 2 $_TARGETNAME jedec_probe $_TARGETNAME configure -event reset-init { # Flash - mww 0x20200010 0x00000007 ;# FBWST: 7 wait states, not chached + mww 0x20200010 0x00000007 ;# FBWST: 7 wait states, not cached # Use PLL mww 0xFFFF8020 0x00000001 ;# XTAL_OSC_CONTROL: enable, 1-20 MHz 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 dce9c470e1..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> ;# @@ -45,7 +47,7 @@ proc sodimm_init { } { ; # ARM errata ID #468414 set tR [arm mrc 15 0 1 0 1] - arm mcr 15 0 1 0 1 [expr $tR | (1<<5)] ; # enable L1NEON bit + arm mcr 15 0 1 0 1 [expr {$tR | (1<<5)}] ; # enable L1NEON bit init_l2cc init_aips @@ -69,7 +71,7 @@ proc init_l2cc { } { set tR [arm mrc 15 0 1 0 1] ; #bic r0, r0, #0x2 ; #mcr 15, 0, r0, c1, c0, 1 - arm mcr 15 0 1 0 1 [expr $tR & ~(1<<2)] + arm mcr 15 0 1 0 1 [expr {$tR & ~(1 << 2)}] ; #/* reconfigure L2 cache aux control reg */ ; #mov r0, #0xC0 /* tag RAM */ @@ -79,7 +81,7 @@ proc init_l2cc { } { ; #orr r0, r0, #(1 << 22) /* disable write allocate */ ; #mcr 15, 1, r0, c9, c0, 2 - arm mcr 15 1 9 0 2 [expr 0xC4 | (1<<24) | (1<<23) | (1<22)] + arm mcr 15 1 9 0 2 [expr {0xC4 | (1<<24) | (1<<23) | (1<<22)}] } @@ -93,10 +95,10 @@ proc init_aips { } { set VAL 0x77777777 # dap apsel 1 - mww [expr $AIPS1_BASE_ADDR + 0x0] $VAL - mww [expr $AIPS1_BASE_ADDR + 0x4] $VAL - mww [expr $AIPS2_BASE_ADDR + 0x0] $VAL - mww [expr $AIPS2_BASE_ADDR + 0x4] $VAL + mww [expr {$AIPS1_BASE_ADDR + 0x0}] $VAL + mww [expr {$AIPS1_BASE_ADDR + 0x4}] $VAL + mww [expr {$AIPS2_BASE_ADDR + 0x0}] $VAL + mww [expr {$AIPS2_BASE_ADDR + 0x4}] $VAL # dap apsel 0 } @@ -104,22 +106,22 @@ proc init_aips { } { proc init_clock { } { global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR - set CCM_BASE_ADDR [expr $AIPS1_BASE_ADDR + 0x000D4000] + set CCM_BASE_ADDR [expr {$AIPS1_BASE_ADDR + 0x000D4000}] set CLKCTL_CCSR 0x0C set CLKCTL_CBCDR 0x14 set CLKCTL_CBCMR 0x18 - set PLL1_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x00080000] - set PLL2_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x00084000] - set PLL3_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x00088000] - set PLL4_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x0008C000] + set PLL1_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00080000}] + set PLL2_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00084000}] + set PLL3_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00088000}] + set PLL4_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x0008C000}] set CLKCTL_CSCMR1 0x1C set CLKCTL_CDHIPR 0x48 - set PLATFORM_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x000A0000] + set PLATFORM_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x000A0000}] set CLKCTL_CSCDR1 0x24 set CLKCTL_CCDR 0x04 ; # Switch ARM to step clock - mww [expr $CCM_BASE_ADDR + $CLKCTL_CCSR] 0x4 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x4 return echo "not returned" @@ -127,52 +129,52 @@ proc init_clock { } { setup_pll $PLL3_BASE_ADDR 400 ; # Switch peripheral to PLL3 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCMR] 0x00015154 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCDR] [expr 0x02888945 | (1<<16)] - while {[mrw [expr $CCM_BASE_ADDR + $CLKCTL_CDHIPR]] != 0} { sleep 1 } + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00015154 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x02888945 | (1<<16)}] + while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL2_BASE_ADDR 400 ; # Switch peripheral to PLL2 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCDR] [expr 0x00808145 | (2<<10) | (9<<16) | (1<<19)] + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x00808145 | (2<<10) | (9<<16) | (1<<19)}] - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCMR] 0x00016154 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00016154 ; # change uart clk parent to pll2 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CSCMR1] [expr [mrw [expr $CCM_BASE_ADDR + $CLKCTL_CSCMR1]] & 0xfcffffff | 0x01000000] + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}]] & 0xfcffffff | 0x01000000}] ; # make sure change is effective - while {[mrw [expr $CCM_BASE_ADDR + $CLKCTL_CDHIPR]] != 0} { sleep 1 } + while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL3_BASE_ADDR 216 setup_pll $PLL4_BASE_ADDR 455 ; # Set the platform clock dividers - mww [expr $PLATFORM_BASE_ADDR + 0x14] 0x00000124 + mww [expr {$PLATFORM_BASE_ADDR + 0x14}] 0x00000124 - mww [expr $CCM_BASE_ADDR + 0x10] 0 + mww [expr {$CCM_BASE_ADDR + 0x10}] 0 ; # Switch ARM back to PLL 1. - mww [expr $CCM_BASE_ADDR + $CLKCTL_CCSR] 0x0 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x0 ; # make uart div=6 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CSCDR1] [expr [mrw [expr $CCM_BASE_ADDR + $CLKCTL_CSCDR1]] & 0xffffffc0 | 0x0a] + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}]] & 0xffffffc0 | 0x0a}] ; # Restore the default values in the Gate registers - mww [expr $CCM_BASE_ADDR + 0x68] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x6C] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x70] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x74] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x78] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x7C] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x80] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x84] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x68}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x6C}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x70}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x74}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x78}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x7C}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x80}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x84}] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + $CLKCTL_CCDR] 0x00000 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCDR}] 0x00000 ; # for cko - for ARM div by 8 - mww [expr $CCM_BASE_ADDR + 0x60] [expr 0x000A0000 & 0x00000F0] + mww [expr {$CCM_BASE_ADDR + 0x60}] [expr {0x000A0000 & 0x00000F0}] } @@ -187,68 +189,68 @@ proc setup_pll { PLL_ADDR CLK } { set PLL_DP_HFS_MFN 0x24 if {$CLK == 1000} { - set DP_OP [expr (10 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (12 - 1)] + set DP_OP [expr {(10 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {12 - 1}] set DP_MFN 5 } elseif {$CLK == 850} { - set DP_OP [expr (8 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (48 - 1)] + set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {48 - 1}] set DP_MFN 41 } elseif {$CLK == 800} { - set DP_OP [expr (8 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (3 - 1)] + set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 700} { - set DP_OP [expr (7 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (24 - 1)] + set DP_OP [expr {(7 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {24 - 1}] set DP_MFN 7 } elseif {$CLK == 600} { - set DP_OP [expr (6 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (4 - 1)] + set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {4 - 1}] set DP_MFN 1 } elseif {$CLK == 665} { - set DP_OP [expr (6 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (96 - 1)] + set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {96 - 1}] set DP_MFN 89 } elseif {$CLK == 532} { - set DP_OP [expr (5 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (24 - 1)] + set DP_OP [expr {(5 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {24 - 1}] set DP_MFN 13 } elseif {$CLK == 455} { - set DP_OP [expr (8 << 4) + ((2 - 1) << 0)] - set DP_MFD [expr (48 - 1)] + set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] + set DP_MFD [expr {48 - 1}] set DP_MFN 71 } elseif {$CLK == 400} { - set DP_OP [expr (8 << 4) + ((2 - 1) << 0)] - set DP_MFD [expr (3 - 1)] + set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] + set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 216} { - set DP_OP [expr (6 << 4) + ((3 - 1) << 0)] - set DP_MFD [expr (4 - 1)] + set DP_OP [expr {(6 << 4) + ((3 - 1) << 0)}] + set DP_MFD [expr {4 - 1}] set DP_MFN 3 } else { error "Error (setup_dll): clock not found!" } - mww [expr $PLL_ADDR + $PLL_DP_CTL] 0x00001232 - mww [expr $PLL_ADDR + $PLL_DP_CONFIG] 0x2 + mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 + mww [expr {$PLL_ADDR + $PLL_DP_CONFIG}] 0x2 - mww [expr $PLL_ADDR + $PLL_DP_OP] $DP_OP - mww [expr $PLL_ADDR + $PLL_DP_HFS_MFD] $DP_OP + mww [expr {$PLL_ADDR + $PLL_DP_OP}] $DP_OP + mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_OP - mww [expr $PLL_ADDR + $PLL_DP_MFD] $DP_MFD - mww [expr $PLL_ADDR + $PLL_DP_HFS_MFD] $DP_MFD + mww [expr {$PLL_ADDR + $PLL_DP_MFD}] $DP_MFD + mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_MFD - mww [expr $PLL_ADDR + $PLL_DP_MFN] $DP_MFN - mww [expr $PLL_ADDR + $PLL_DP_HFS_MFN] $DP_MFN + mww [expr {$PLL_ADDR + $PLL_DP_MFN}] $DP_MFN + mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFN}] $DP_MFN - mww [expr $PLL_ADDR + $PLL_DP_CTL] 0x00001232 - while {[expr [mrw [expr $PLL_ADDR + $PLL_DP_CTL]] & 0x1] == 0} { sleep 1 } + mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 + while {[expr {[mrw [expr {$PLL_ADDR + $PLL_DP_CTL}]] & 0x1}] == 0} { sleep 1 } } proc CPU_2_BE_32 { L } { - return [expr (($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)] + return [expr {(($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)}] } diff --git a/tcl/board/icnova_sam9g45_sodimm.cfg b/tcl/board/icnova_sam9g45_sodimm.cfg index 30dc34748d..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) # @@ -43,9 +45,7 @@ flash bank $_FLASHNAME cfi 0x10000000 0x00800000 2 2 $_TARGETNAME proc read_register {register} { - set result "" - mem2array result 32 $register 1 - return $result(0) + return [read_memory $register 32 1] } proc at91sam9g45_start { } { @@ -89,27 +89,27 @@ proc at91sam9g45_init { } { # Wait for MOSCS in PMC_SR to assert indicating oscillator is again stable after change to CKGR_MOR. mww 0xfffffc20 0x00004001 - while { [expr [read_register 0xfffffc68] & 0x01] != 1 } { sleep 1 } + while { [expr {[read_register 0xfffffc68] & 0x01}] != 1 } { sleep 1 } # Set PLLA Register for 792.576 MHz (divider: bypass, multiplier: 43). # Wait for LOCKA signal in PMC_SR to assert indicating PLLA is stable. #mww 0xfffffc28 0x202a3f01 mww 0xfffffc28 0x20c73f03 - while { [expr [read_register 0xfffffc68] & 0x02] != 2 } { sleep 1 } + while { [expr {[read_register 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 0x00000101 mww 0xfffffc30 0x00001301 - while { [expr [read_register 0xfffffc68] & 0x08] != 8 } { sleep 1 } + while { [expr {[read_register 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 [read_register 0xfffffc68] & 0x08] != 8 } { sleep 1 } + while { [expr {[read_register 0xfffffc68] & 0x08}] != 8 } { sleep 1 } # Processor and master clocks are now operating and stable at maximum frequency possible: # -> MCLK = 132.096 MHz @@ -214,7 +214,7 @@ proc at91sam9g45_init { } { sleep 1 # 9. Enable DLL Reset (set DLL bit) - set CR [expr [read_register 0xffffe608] | 0x80] + set CR [expr {[read_register 0xffffe608] | 0x80}] mww 0xffffe608 $CR # 10. mode register cycle to reset the DLL @@ -236,7 +236,7 @@ proc at91sam9g45_init { } { # 12.3 delay 10 cycles # 13. disable DLL reset (clear DLL bit) - set CR [expr [read_register 0xffffe608] & 0xffffff7f] + set CR [expr {[read_register 0xffffe608] & 0xffffff7f}] mww 0xffffe608 $CR # 14. mode register set cycle @@ -244,7 +244,7 @@ proc at91sam9g45_init { } { mww 0x70000000 0x1 # 15. program OCD field (set OCD bits) - set CR [expr [read_register 0xffffe608] | 0x7000] + set CR [expr {[read_register 0xffffe608] | 0x7000}] mww 0xffffe608 $CR # 16. (EMRS1) @@ -253,7 +253,7 @@ proc at91sam9g45_init { } { # 16.1 delay 2 cycles # 17. disable OCD field (clear OCD bits) - set CR [expr [read_register 0xffffe608] & 0xffff8fff] + set CR [expr {[read_register 0xffffe608] & 0xffff8fff}] mww 0xffffe608 $CR # 18. (EMRS1) 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 2dce157dbc..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] @@ -6,7 +8,7 @@ $_TARGETNAME configure -event reset-init { imx31pdk_init } proc self_test {} { echo "Running 100 iterations of test." dump_image /ram/test 0x80000000 0x40000 - for {set i 0} {$i < 100} {set i [expr $i+1]} { + for {set i 0} {$i < 100} {set i [expr {$i+1}]} { echo "Iteration $i" reset init mww 0x80000000 0x12345678 0x10000 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 baeb3cd9d1..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 # @@ -44,7 +46,7 @@ proc m53evk_init { } { ; # ARM errata ID #468414 set tR [arm mrc 15 0 1 0 1] - arm mcr 15 0 1 0 1 [expr $tR | (1<<5)] ; # enable L1NEON bit + arm mcr 15 0 1 0 1 [expr {$tR | (1<<5)}] ; # enable L1NEON bit init_l2cc init_aips @@ -65,7 +67,7 @@ proc init_l2cc { } { set tR [arm mrc 15 0 1 0 1] ; #bic r0, r0, #0x2 ; #mcr 15, 0, r0, c1, c0, 1 - arm mcr 15 0 1 0 1 [expr $tR & ~(1<<2)] + arm mcr 15 0 1 0 1 [expr {$tR & ~(1 << 2)}] ; #/* reconfigure L2 cache aux control reg */ ; #mov r0, #0xC0 /* tag RAM */ @@ -75,7 +77,7 @@ proc init_l2cc { } { ; #orr r0, r0, #(1 << 22) /* disable write allocate */ ; #mcr 15, 1, r0, c9, c0, 2 - arm mcr 15 1 9 0 2 [expr 0xC4 | (1<<24) | (1<<23) | (1<22)] + arm mcr 15 1 9 0 2 [expr {0xC4 | (1<<24) | (1<<23) | (1<<22)}] } @@ -89,10 +91,10 @@ proc init_aips { } { set VAL 0x77777777 # dap apsel 1 - mww [expr $AIPS1_BASE_ADDR + 0x0] $VAL - mww [expr $AIPS1_BASE_ADDR + 0x4] $VAL - mww [expr $AIPS2_BASE_ADDR + 0x0] $VAL - mww [expr $AIPS2_BASE_ADDR + 0x4] $VAL + mww [expr {$AIPS1_BASE_ADDR + 0x0}] $VAL + mww [expr {$AIPS1_BASE_ADDR + 0x4}] $VAL + mww [expr {$AIPS2_BASE_ADDR + 0x0}] $VAL + mww [expr {$AIPS2_BASE_ADDR + 0x4}] $VAL # dap apsel 0 } @@ -100,22 +102,22 @@ proc init_aips { } { proc init_clock { } { global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR - set CCM_BASE_ADDR [expr $AIPS1_BASE_ADDR + 0x000D4000] + set CCM_BASE_ADDR [expr {$AIPS1_BASE_ADDR + 0x000D4000}] set CLKCTL_CCSR 0x0C set CLKCTL_CBCDR 0x14 set CLKCTL_CBCMR 0x18 - set PLL1_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x00080000] - set PLL2_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x00084000] - set PLL3_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x00088000] - set PLL4_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x0008C000] + set PLL1_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00080000}] + set PLL2_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00084000}] + set PLL3_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00088000}] + set PLL4_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x0008C000}] set CLKCTL_CSCMR1 0x1C set CLKCTL_CDHIPR 0x48 - set PLATFORM_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x000A0000] + set PLATFORM_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x000A0000}] set CLKCTL_CSCDR1 0x24 set CLKCTL_CCDR 0x04 ; # Switch ARM to step clock - mww [expr $CCM_BASE_ADDR + $CLKCTL_CCSR] 0x4 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x4 return echo "not returned" @@ -123,52 +125,52 @@ proc init_clock { } { setup_pll $PLL3_BASE_ADDR 400 ; # Switch peripheral to PLL3 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCMR] 0x00015154 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCDR] [expr 0x02888945 | (1<<16)] - while {[mrw [expr $CCM_BASE_ADDR + $CLKCTL_CDHIPR]] != 0} { sleep 1 } + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00015154 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x02888945 | (1<<16)}] + while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL2_BASE_ADDR 400 ; # Switch peripheral to PLL2 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCDR] [expr 0x00808145 | (2<<10) | (9<<16) | (1<<19)] + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x00808145 | (2<<10) | (9<<16) | (1<<19)}] - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCMR] 0x00016154 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00016154 ; # change uart clk parent to pll2 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CSCMR1] [expr [mrw [expr $CCM_BASE_ADDR + $CLKCTL_CSCMR1]] & 0xfcffffff | 0x01000000] + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}]] & 0xfcffffff | 0x01000000}] ; # make sure change is effective - while {[mrw [expr $CCM_BASE_ADDR + $CLKCTL_CDHIPR]] != 0} { sleep 1 } + while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL3_BASE_ADDR 216 setup_pll $PLL4_BASE_ADDR 455 ; # Set the platform clock dividers - mww [expr $PLATFORM_BASE_ADDR + 0x14] 0x00000124 + mww [expr {$PLATFORM_BASE_ADDR + 0x14}] 0x00000124 - mww [expr $CCM_BASE_ADDR + 0x10] 0 + mww [expr {$CCM_BASE_ADDR + 0x10}] 0 ; # Switch ARM back to PLL 1. - mww [expr $CCM_BASE_ADDR + $CLKCTL_CCSR] 0x0 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x0 ; # make uart div=6 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CSCDR1] [expr [mrw [expr $CCM_BASE_ADDR + $CLKCTL_CSCDR1]] & 0xffffffc0 | 0x0a] + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}]] & 0xffffffc0 | 0x0a}] ; # Restore the default values in the Gate registers - mww [expr $CCM_BASE_ADDR + 0x68] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x6C] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x70] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x74] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x78] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x7C] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x80] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x84] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x68}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x6C}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x70}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x74}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x78}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x7C}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x80}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x84}] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + $CLKCTL_CCDR] 0x00000 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCDR}] 0x00000 ; # for cko - for ARM div by 8 - mww [expr $CCM_BASE_ADDR + 0x60] [expr 0x000A0000 & 0x00000F0] + mww [expr {$CCM_BASE_ADDR + 0x60}] [expr {0x000A0000 & 0x00000F0}] } @@ -183,68 +185,68 @@ proc setup_pll { PLL_ADDR CLK } { set PLL_DP_HFS_MFN 0x24 if {$CLK == 1000} { - set DP_OP [expr (10 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (12 - 1)] + set DP_OP [expr {(10 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {12 - 1}] set DP_MFN 5 } elseif {$CLK == 850} { - set DP_OP [expr (8 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (48 - 1)] + set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {48 - 1}] set DP_MFN 41 } elseif {$CLK == 800} { - set DP_OP [expr (8 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (3 - 1)] + set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 700} { - set DP_OP [expr (7 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (24 - 1)] + set DP_OP [expr {(7 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {24 - 1}] set DP_MFN 7 } elseif {$CLK == 600} { - set DP_OP [expr (6 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (4 - 1)] + set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {4 - 1}] set DP_MFN 1 } elseif {$CLK == 665} { - set DP_OP [expr (6 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (96 - 1)] + set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {96 - 1}] set DP_MFN 89 } elseif {$CLK == 532} { - set DP_OP [expr (5 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (24 - 1)] + set DP_OP [expr {(5 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {24 - 1}] set DP_MFN 13 } elseif {$CLK == 455} { - set DP_OP [expr (8 << 4) + ((2 - 1) << 0)] - set DP_MFD [expr (48 - 1)] + set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] + set DP_MFD [expr {48 - 1}] set DP_MFN 71 } elseif {$CLK == 400} { - set DP_OP [expr (8 << 4) + ((2 - 1) << 0)] - set DP_MFD [expr (3 - 1)] + set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] + set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 216} { - set DP_OP [expr (6 << 4) + ((3 - 1) << 0)] - set DP_MFD [expr (4 - 1)] + set DP_OP [expr {(6 << 4) + ((3 - 1) << 0)}] + set DP_MFD [expr {4 - 1}] set DP_MFN 3 } else { error "Error (setup_dll): clock not found!" } - mww [expr $PLL_ADDR + $PLL_DP_CTL] 0x00001232 - mww [expr $PLL_ADDR + $PLL_DP_CONFIG] 0x2 + mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 + mww [expr {$PLL_ADDR + $PLL_DP_CONFIG}] 0x2 - mww [expr $PLL_ADDR + $PLL_DP_OP] $DP_OP - mww [expr $PLL_ADDR + $PLL_DP_HFS_MFD] $DP_OP + mww [expr {$PLL_ADDR + $PLL_DP_OP}] $DP_OP + mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_OP - mww [expr $PLL_ADDR + $PLL_DP_MFD] $DP_MFD - mww [expr $PLL_ADDR + $PLL_DP_HFS_MFD] $DP_MFD + mww [expr {$PLL_ADDR + $PLL_DP_MFD}] $DP_MFD + mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_MFD - mww [expr $PLL_ADDR + $PLL_DP_MFN] $DP_MFN - mww [expr $PLL_ADDR + $PLL_DP_HFS_MFN] $DP_MFN + mww [expr {$PLL_ADDR + $PLL_DP_MFN}] $DP_MFN + mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFN}] $DP_MFN - mww [expr $PLL_ADDR + $PLL_DP_CTL] 0x00001232 - while {[expr [mrw [expr $PLL_ADDR + $PLL_DP_CTL]] & 0x1] == 0} { sleep 1 } + mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 + while {[expr {[mrw [expr {$PLL_ADDR + $PLL_DP_CTL}]] & 0x1}] == 0} { sleep 1 } } proc CPU_2_BE_32 { L } { - return [expr (($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)] + return [expr {(($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)}] } diff --git a/tcl/board/imx53loco.cfg b/tcl/board/imx53loco.cfg index 18caca5749..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 # @@ -19,7 +21,7 @@ adapter speed 3000 jtag_rclk 1000 $_TARGETNAME configure -event "reset-start" { jtag_rclk 1000 } -#jtag_nsrst_delay 200 +#adapter srst delay 200 #jtag_ntrst_delay 200 $_TARGETNAME configure -event "reset-assert" { @@ -46,7 +48,7 @@ proc loco_init { } { ; # ARM errata ID #468414 set tR [arm mrc 15 0 1 0 1] - arm mcr 15 0 1 0 1 [expr $tR | (1<<5)] ; # enable L1NEON bit + arm mcr 15 0 1 0 1 [expr {$tR | (1<<5)}] ; # enable L1NEON bit init_l2cc init_aips @@ -70,7 +72,7 @@ proc init_l2cc { } { set tR [arm mrc 15 0 1 0 1] ; #bic r0, r0, #0x2 ; #mcr 15, 0, r0, c1, c0, 1 - arm mcr 15 0 1 0 1 [expr $tR & ~(1<<2)] + arm mcr 15 0 1 0 1 [expr {$tR & ~(1 << 2)}] ; #/* reconfigure L2 cache aux control reg */ ; #mov r0, #0xC0 /* tag RAM */ @@ -80,7 +82,7 @@ proc init_l2cc { } { ; #orr r0, r0, #(1 << 22) /* disable write allocate */ ; #mcr 15, 1, r0, c9, c0, 2 - arm mcr 15 1 9 0 2 [expr 0xC4 | (1<<24) | (1<<23) | (1<22)] + arm mcr 15 1 9 0 2 [expr {0xC4 | (1<<24) | (1<<23) | (1<<22)}] } @@ -94,10 +96,10 @@ proc init_aips { } { set VAL 0x77777777 # dap apsel 1 - mww [expr $AIPS1_BASE_ADDR + 0x0] $VAL - mww [expr $AIPS1_BASE_ADDR + 0x4] $VAL - mww [expr $AIPS2_BASE_ADDR + 0x0] $VAL - mww [expr $AIPS2_BASE_ADDR + 0x4] $VAL + mww [expr {$AIPS1_BASE_ADDR + 0x0}] $VAL + mww [expr {$AIPS1_BASE_ADDR + 0x4}] $VAL + mww [expr {$AIPS2_BASE_ADDR + 0x0}] $VAL + mww [expr {$AIPS2_BASE_ADDR + 0x4}] $VAL # dap apsel 0 } @@ -105,22 +107,22 @@ proc init_aips { } { proc init_clock { } { global AIPS1_BASE_ADDR global AIPS2_BASE_ADDR - set CCM_BASE_ADDR [expr $AIPS1_BASE_ADDR + 0x000D4000] + set CCM_BASE_ADDR [expr {$AIPS1_BASE_ADDR + 0x000D4000}] set CLKCTL_CCSR 0x0C set CLKCTL_CBCDR 0x14 set CLKCTL_CBCMR 0x18 - set PLL1_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x00080000] - set PLL2_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x00084000] - set PLL3_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x00088000] - set PLL4_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x0008C000] + set PLL1_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00080000}] + set PLL2_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00084000}] + set PLL3_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x00088000}] + set PLL4_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x0008C000}] set CLKCTL_CSCMR1 0x1C set CLKCTL_CDHIPR 0x48 - set PLATFORM_BASE_ADDR [expr $AIPS2_BASE_ADDR + 0x000A0000] + set PLATFORM_BASE_ADDR [expr {$AIPS2_BASE_ADDR + 0x000A0000}] set CLKCTL_CSCDR1 0x24 set CLKCTL_CCDR 0x04 ; # Switch ARM to step clock - mww [expr $CCM_BASE_ADDR + $CLKCTL_CCSR] 0x4 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x4 return echo "not returned" @@ -128,52 +130,52 @@ proc init_clock { } { setup_pll $PLL3_BASE_ADDR 400 ; # Switch peripheral to PLL3 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCMR] 0x00015154 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCDR] [expr 0x02888945 | (1<<16)] - while {[mrw [expr $CCM_BASE_ADDR + $CLKCTL_CDHIPR]] != 0} { sleep 1 } + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00015154 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x02888945 | (1<<16)}] + while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL2_BASE_ADDR 400 ; # Switch peripheral to PLL2 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCDR] [expr 0x00808145 | (2<<10) | (9<<16) | (1<<19)] + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCDR}] [expr {0x00808145 | (2<<10) | (9<<16) | (1<<19)}] - mww [expr $CCM_BASE_ADDR + $CLKCTL_CBCMR] 0x00016154 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CBCMR}] 0x00016154 ; # change uart clk parent to pll2 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CSCMR1] [expr [mrw [expr $CCM_BASE_ADDR + $CLKCTL_CSCMR1]] & 0xfcffffff | 0x01000000] + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCMR1}]] & 0xfcffffff | 0x01000000}] ; # make sure change is effective - while {[mrw [expr $CCM_BASE_ADDR + $CLKCTL_CDHIPR]] != 0} { sleep 1 } + while {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CDHIPR}]] != 0} { sleep 1 } setup_pll $PLL3_BASE_ADDR 216 setup_pll $PLL4_BASE_ADDR 455 ; # Set the platform clock dividers - mww [expr $PLATFORM_BASE_ADDR + 0x14] 0x00000124 + mww [expr {$PLATFORM_BASE_ADDR + 0x14}] 0x00000124 - mww [expr $CCM_BASE_ADDR + 0x10] 0 + mww [expr {$CCM_BASE_ADDR + 0x10}] 0 ; # Switch ARM back to PLL 1. - mww [expr $CCM_BASE_ADDR + $CLKCTL_CCSR] 0x0 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCSR}] 0x0 ; # make uart div=6 - mww [expr $CCM_BASE_ADDR + $CLKCTL_CSCDR1] [expr [mrw [expr $CCM_BASE_ADDR + $CLKCTL_CSCDR1]] & 0xffffffc0 | 0x0a] + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}] [expr {[mrw [expr {$CCM_BASE_ADDR + $CLKCTL_CSCDR1}]] & 0xffffffc0 | 0x0a}] ; # Restore the default values in the Gate registers - mww [expr $CCM_BASE_ADDR + 0x68] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x6C] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x70] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x74] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x78] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x7C] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x80] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + 0x84] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x68}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x6C}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x70}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x74}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x78}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x7C}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x80}] 0xFFFFFFFF + mww [expr {$CCM_BASE_ADDR + 0x84}] 0xFFFFFFFF - mww [expr $CCM_BASE_ADDR + $CLKCTL_CCDR] 0x00000 + mww [expr {$CCM_BASE_ADDR + $CLKCTL_CCDR}] 0x00000 ; # for cko - for ARM div by 8 - mww [expr $CCM_BASE_ADDR + 0x60] [expr 0x000A0000 & 0x00000F0] + mww [expr {$CCM_BASE_ADDR + 0x60}] [expr {0x000A0000 & 0x00000F0}] } @@ -188,68 +190,68 @@ proc setup_pll { PLL_ADDR CLK } { set PLL_DP_HFS_MFN 0x24 if {$CLK == 1000} { - set DP_OP [expr (10 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (12 - 1)] + set DP_OP [expr {(10 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {12 - 1}] set DP_MFN 5 } elseif {$CLK == 850} { - set DP_OP [expr (8 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (48 - 1)] + set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {48 - 1}] set DP_MFN 41 } elseif {$CLK == 800} { - set DP_OP [expr (8 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (3 - 1)] + set DP_OP [expr {(8 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 700} { - set DP_OP [expr (7 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (24 - 1)] + set DP_OP [expr {(7 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {24 - 1}] set DP_MFN 7 } elseif {$CLK == 600} { - set DP_OP [expr (6 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (4 - 1)] + set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {4 - 1}] set DP_MFN 1 } elseif {$CLK == 665} { - set DP_OP [expr (6 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (96 - 1)] + set DP_OP [expr {(6 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {96 - 1}] set DP_MFN 89 } elseif {$CLK == 532} { - set DP_OP [expr (5 << 4) + ((1 - 1) << 0)] - set DP_MFD [expr (24 - 1)] + set DP_OP [expr {(5 << 4) + ((1 - 1) << 0)}] + set DP_MFD [expr {24 - 1}] set DP_MFN 13 } elseif {$CLK == 455} { - set DP_OP [expr (8 << 4) + ((2 - 1) << 0)] - set DP_MFD [expr (48 - 1)] + set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] + set DP_MFD [expr {48 - 1}] set DP_MFN 71 } elseif {$CLK == 400} { - set DP_OP [expr (8 << 4) + ((2 - 1) << 0)] - set DP_MFD [expr (3 - 1)] + set DP_OP [expr {(8 << 4) + ((2 - 1) << 0)}] + set DP_MFD [expr {3 - 1}] set DP_MFN 1 } elseif {$CLK == 216} { - set DP_OP [expr (6 << 4) + ((3 - 1) << 0)] - set DP_MFD [expr (4 - 1)] + set DP_OP [expr {(6 << 4) + ((3 - 1) << 0)}] + set DP_MFD [expr {4 - 1}] set DP_MFN 3 } else { error "Error (setup_dll): clock not found!" } - mww [expr $PLL_ADDR + $PLL_DP_CTL] 0x00001232 - mww [expr $PLL_ADDR + $PLL_DP_CONFIG] 0x2 + mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 + mww [expr {$PLL_ADDR + $PLL_DP_CONFIG}] 0x2 - mww [expr $PLL_ADDR + $PLL_DP_OP] $DP_OP - mww [expr $PLL_ADDR + $PLL_DP_HFS_MFD] $DP_OP + mww [expr {$PLL_ADDR + $PLL_DP_OP}] $DP_OP + mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_OP - mww [expr $PLL_ADDR + $PLL_DP_MFD] $DP_MFD - mww [expr $PLL_ADDR + $PLL_DP_HFS_MFD] $DP_MFD + mww [expr {$PLL_ADDR + $PLL_DP_MFD}] $DP_MFD + mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFD}] $DP_MFD - mww [expr $PLL_ADDR + $PLL_DP_MFN] $DP_MFN - mww [expr $PLL_ADDR + $PLL_DP_HFS_MFN] $DP_MFN + mww [expr {$PLL_ADDR + $PLL_DP_MFN}] $DP_MFN + mww [expr {$PLL_ADDR + $PLL_DP_HFS_MFN}] $DP_MFN - mww [expr $PLL_ADDR + $PLL_DP_CTL] 0x00001232 - while {[expr [mrw [expr $PLL_ADDR + $PLL_DP_CTL]] & 0x1] == 0} { sleep 1 } + mww [expr {$PLL_ADDR + $PLL_DP_CTL}] 0x00001232 + while {[expr {[mrw [expr {$PLL_ADDR + $PLL_DP_CTL}]] & 0x1}] == 0} { sleep 1 } } proc CPU_2_BE_32 { L } { - return [expr (($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)] + return [expr {(($L & 0x000000FF) << 24) | (($L & 0x0000FF00) << 8) | (($L & 0x00FF0000) >> 8) | (($L & 0xFF000000) >> 24)}] } 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 06cc1e6c0d..d85e1ca152 100644 --- a/tcl/board/kasli.cfg +++ b/tcl/board/kasli.cfg @@ -1,9 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + adapter driver ftdi -ftdi_device_desc "Quad RS232-HS" -ftdi_vid_pid 0x0403 0x6011 -ftdi_channel 0 -ftdi_layout_init 0x0008 0x000b -# ftdi_location 1:8 +ftdi device_desc "Quad RS232-HS" +ftdi vid_pid 0x0403 0x6011 +ftdi channel 0 +ftdi layout_init 0x0008 0x000b +# adapter usb location 1:8 reset_config none transport select jtag 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 a39f15c672..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 @@ -37,7 +39,7 @@ jtag_ntrst_delay 30 arm11 memwrite burst disable adapter speed 1000 -ftdi_tdo_sample_edge falling +ftdi tdo_sample_edge falling proc kindle2_init {} { imx3x_reset 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/lambdaconcept_ecpix-5.cfg b/tcl/board/lambdaconcept_ecpix-5.cfg new file mode 100644 index 0000000000..19b9c1cb43 --- /dev/null +++ b/tcl/board/lambdaconcept_ecpix-5.cfg @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# LambdaConcept ECPIX-5 +# http://docs.lambdaconcept.com/ecpix-5/ +# Currently there are following board variants: +# ECPIX-5 45F - LFE5UM5G-45F +# ECPIX-5 85F - LFE5UM5G-85F +# +# This boards have two JTAG interfaces: +# - CN4, micro USB port connected to FT2232HQ chip: +# ADBUS0 TCK +# ADBUS1 TDI +# ADBUS2 TDO +# ADBUS3 TMS +# BDBUS0 UART_TXD +# BDBUS1 UART_RXD +# This interface should be used with following config: +# interface/ftdi/lambdaconcept_ecpix-5.cfg +# - CN3, 6 pin connector +# See schematics for more details: +# http://docs.lambdaconcept.com/ecpix-5/_static/resources/SCH_ECPIX-5_R02.PDF +# +# No reset lines are implemented. So it is not possible to remote reset the FPGA +# by using any of this interfaces + +source [find interface/ftdi/lambdaconcept_ecpix-5.cfg] +source [find fpga/lattice_ecp5.cfg] diff --git a/tcl/board/lemaker_hikey.cfg b/tcl/board/lemaker_hikey.cfg index ee677c34b8..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 # @@ -17,7 +19,7 @@ proc core_up { args } { global _TARGETNAME # examine remaining cores - foreach _core [set args] { + foreach _core $args { ${_TARGETNAME}$_core arp_examine } } 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 01080a0b16..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 @@ -55,7 +57,7 @@ $_TARGETNAME configure -event reset-init { # # global MCB1700_CCLK - adapter speed [expr $MCB1700_CCLK / 8] + adapter speed [expr {$MCB1700_CCLK / 8}] # Do not remap 0x0000-0x0020 to anything but the flash (i.e. select # "User Flash Mode" where interrupt vectors are _not_ remapped, 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_sama5d27_som1_kit1.cfg b/tcl/board/microchip_sama5d27_som1_kit1.cfg new file mode 100644 index 0000000000..8e920405cb --- /dev/null +++ b/tcl/board/microchip_sama5d27_som1_kit1.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip SAMA5D27-SOM1-EK1 +# https://www.microchip.com/DevelopmentTools/ProductDetails/PartNO/ATSAMA5D27-SOM1-EK1 +# This board provide two jtag interfaces: +# J11 - 10 pin interface +# J10 - USB interface connected to the J-Link-OB. +# This functionality is implemented with an ATSAM3U4C microcontroller and +# provides JTAG functions and a bridge USB/Serial debug port (CDC). +# +# Jumper J7 disables the J-Link-OB-ATSAM3U4C JTAG functionality. +# - Jumper J7 not installed: J-Link-OB-ATSAM3U4C is enabled and fully functional. +# - Jumper J7 installed: J-Link-OB-ATSAM3U4C is disabled and an external JTAG +# controller can be used through the 10-pin JTAG port J11. + +source [find interface/jlink.cfg] +reset_config srst_only + +source [find target/at91sama5d2.cfg] diff --git a/tcl/board/microchip_same51_curiosity_nano.cfg b/tcl/board/microchip_same51_curiosity_nano.cfg new file mode 100644 index 0000000000..32e2885491 --- /dev/null +++ b/tcl/board/microchip_same51_curiosity_nano.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip SAME51 Curiosity Nano evaluation kit. +# +# https://www.microchip.com/en-us/development-tool/EV76S68A +# + +source [find interface/cmsis-dap.cfg] + +set CHIPNAME same51 + +source [find target/atsame5x.cfg] + +reset_config srst_only 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 9dca5a37c9..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) @@ -38,7 +40,7 @@ # it's apt-get install libusb-dev. When I made my config I only included # --enable-jlink and --enable-usbdevs # -# I HAVE NOT Tested this throughly, so there could still be problems. +# I HAVE NOT Tested this thoroughly, so there could still be problems. # But it should get you way ahead of the game from where I started. # If you find problems (and fixes) please post them to # openocd-development@lists.berlios.de and join the developers and @@ -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_corvettef1.cfg b/tcl/board/nds32_corvettef1.cfg index 1a3782c688..7300ce04a2 100644 --- a/tcl/board/nds32_corvettef1.cfg +++ b/tcl/board/nds32_corvettef1.cfg @@ -4,15 +4,15 @@ # ADP-Corvette-F1 R2.0 # http://www.andestech.com/en/products-solutions/andeshape-platforms/corvette-f1-r2/ -adapter_khz 10000 +adapter speed 10000 adapter driver ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Dual RS232-HS" +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 +ftdi layout_init 0x0c08 0x0f1b +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 reset_config srst_only source [find target/nds32v5.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 0e9ff5b1f6..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 # @@ -19,6 +21,6 @@ adapter driver sysfsgpio transport select jtag # TCK TMS TDI TDO -sysfsgpio_jtag_nums 136 139 137 138 +sysfsgpio jtag_nums 136 139 137 138 source [find cpld/xilinx-xc6s.cfg] diff --git a/tcl/board/npcx_evb.cfg b/tcl/board/npcx_evb.cfg new file mode 100644 index 0000000000..4f28bc9649 --- /dev/null +++ b/tcl/board/npcx_evb.cfg @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Nuvoton NPCX Evaluation Board + +source [find interface/jlink.cfg] +transport select swd + +source [find target/npcx.cfg] diff --git a/tcl/board/numato_mimas_a7.cfg b/tcl/board/numato_mimas_a7.cfg index d4012bada7..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 # @@ -8,13 +10,13 @@ # Therefore, prefer external power supply. adapter driver ftdi -ftdi_device_desc "Mimas Artix 7 FPGA Module" -ftdi_vid_pid 0x2a19 0x1009 +ftdi device_desc "Mimas Artix 7 FPGA Module" +ftdi vid_pid 0x2a19 0x1009 # channel 0 is for custom purpose by users (like uart, fifo etc) # channel 1 is reserved for JTAG (by-default) or SPI (possible via changing solder jumpers) -ftdi_channel 1 -ftdi_tdo_sample_edge falling +ftdi channel 1 +ftdi tdo_sample_edge falling # FTDI Pin Layout @@ -28,7 +30,7 @@ ftdi_tdo_sample_edge falling # OE_N is JTAG buffer output enable signal (active-low) # PROG_B is not used, so left as input to FTDI. # -ftdi_layout_init 0x0008 0x004b +ftdi layout_init 0x0008 0x004b reset_config none adapter speed 30000 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-k64f.cfg b/tcl/board/nxp_frdm-k64f.cfg new file mode 100644 index 0000000000..1581c9594b --- /dev/null +++ b/tcl/board/nxp_frdm-k64f.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is an NXP Freedom eval board with a single MK64FN1M0VLL12 chip. +# https://www.nxp.com/design/development-boards/freedom-development-boards/mcu-boards/freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F +# + +source [find interface/cmsis-dap.cfg] + +# Set working area to 16 KiB +set WORKAREASIZE 0x4000 + +set CHIPNAME k64f +reset_config srst_only + +source [find target/kx.cfg] 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 c595e3a679..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 @@ -27,7 +29,7 @@ proc imx7_uart_dbgconf { } { } proc check_bits_set_32 { addr mask } { - while { [expr [mrw $addr] & $mask == 0] } { } + while { [expr {[mrw $addr] & $mask} == 0] } { } } proc apply_dcd { } { 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/nxp_rdb-ls1046a.cfg b/tcl/board/nxp_rdb-ls1046a.cfg new file mode 100644 index 0000000000..fde1829fb4 --- /dev/null +++ b/tcl/board/nxp_rdb-ls1046a.cfg @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1046ARDB (Reference Design Board) +# This is for the "console" USB port on the front panel +# You must ensure that SW4-7 is in the "off" position + +# NXP K20 +# The firmware implements the old CMSIS-DAP v1 USB HID interface +# You must pass --enable-cmsis-dap to ./configure to enable it +source [find interface/cmsis-dap.cfg] + +transport select jtag +reset_config srst_only + +source [find target/ls1046a.cfg] + +# The adapter can't handle 10MHz +adapter speed 5000 diff --git a/tcl/board/nxp_rdb-ls1088a.cfg b/tcl/board/nxp_rdb-ls1088a.cfg new file mode 100644 index 0000000000..40483f2d6b --- /dev/null +++ b/tcl/board/nxp_rdb-ls1088a.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1088ARDB (Reference Design Board) +# This is for the "main" JTAG connector J55 + +transport select jtag +reset_config srst_only + +# To access the CPLD, populate J48 and add `-c 'set CWTAP 1'` to your command +# line. At the time of this writing, programming is unsupported. +if { [info exists CWTAP] } { + source [find cpld/altera-epm240.cfg] +} else { + source [find target/ls1088a.cfg] +} 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 426ead6aa9..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/sam7x256.cfg] +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_h405.cfg b/tcl/board/olimex_stm32_h405.cfg new file mode 100644 index 0000000000..f2f1d7f244 --- /dev/null +++ b/tcl/board/olimex_stm32_h405.cfg @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Olimex STM32-H405 eval board +# https://www.olimex.com/Products/ARM/ST/STM32-H405/ + +# Work-area size (RAM size) = 128kB for STM32F405RG device +set WORKAREASIZE 0x20000 + +source [find target/stm32f4x.cfg] 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/open-bldc.cfg b/tcl/board/open-bldc.cfg deleted file mode 100644 index da8654c8d5..0000000000 --- a/tcl/board/open-bldc.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Open Source Brush Less DC Motor Controller -# http://open-bldc.org - -# Work-area size (RAM size) = 20kB for STM32F103RB device -set WORKAREASIZE 0x5000 - -source [find target/stm32.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/pico-debug.cfg b/tcl/board/pico-debug.cfg new file mode 100644 index 0000000000..ba59f860a3 --- /dev/null +++ b/tcl/board/pico-debug.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# pico-debug is a virtual CMSIS-DAP debug adapter +# it runs on the very same RP2040 target being debugged without additional hardware +# https://github.com/majbthrd/pico-debug + +source [find interface/cmsis-dap.cfg] +adapter speed 4000 + +set CHIPNAME rp2040 +source [find target/rp2040-core0.cfg] 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 8b8314a0ea..3af5735a8b 100644 --- a/tcl/board/quark_d2000_refboard.cfg +++ b/tcl/board/quark_d2000_refboard.cfg @@ -1,12 +1,14 @@ +# 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 adapter driver ftdi -ftdi_vid_pid 0x0403 0x6014 -ftdi_channel 0 +ftdi vid_pid 0x0403 0x6014 +ftdi channel 0 -ftdi_layout_init 0x0000 0x030b -ftdi_layout_signal nTRST -data 0x0100 -noe 0x0100 +ftdi layout_init 0x0000 0x030b +ftdi layout_signal nTRST -data 0x0100 -noe 0x0100 source [find target/quark_d20xx.cfg] 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/quicklogic_quickfeather.cfg b/tcl/board/quicklogic_quickfeather.cfg new file mode 100644 index 0000000000..b522eff7e4 --- /dev/null +++ b/tcl/board/quicklogic_quickfeather.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# QuickLogic EOS S3 QuickFeather +# https://www.quicklogic.com/products/eos-s3/quickfeather-development-kit/ + +source [find target/eos_s3.cfg] + +reset_config srst_only + +transport select swd diff --git a/tcl/board/radiona_ulx3s.cfg b/tcl/board/radiona_ulx3s.cfg new file mode 100644 index 0000000000..eb9b02719e --- /dev/null +++ b/tcl/board/radiona_ulx3s.cfg @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Radiona ULX3S +# https://radiona.org/ulx3s/ +# Currently there are following board variants: +# CS-ULX3S-01 - LFE5U 12F +# CS-ULX3S-02 - LFE5U 45F +# CS-ULX3S-03 - LFE5U 85F +# +# two JTAG interfaces: +# - US1, micro USB port connected to FT231XQ +# This interface should be used with following config: +# interface/ft232r/radiona_ulx3s.cfg +# - J4, 6 pin connector +# +# Both of this interfaces share the JTAG lines (TDI, TMS, TCK, TDO) between +# Lattice ECP5 FPGA chip and ESP32 WiFi controller. +# Note: TRST_N of the ESP32 is pulled up by default and can be pulled down over +# J3 interface. +# See schematics for more information: +# https://github.com/emard/ulx3s/blob/master/doc/schematics_v308.pdf +# https://github.com/emard/ulx3s/blob/master/doc/schematics_v314.pdf +# https://github.com/emard/ulx3s/blob/master/doc/schematics_v315.pdf +# https://github.com/emard/ulx3s/blob/master/doc/schematics_v316.pdf + +source [find interface/ft232r/radiona_ulx3s.cfg] +source [find fpga/lattice_ecp5.cfg] 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 a6e80650ed..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 # @@ -6,7 +8,7 @@ if { [info exists USE_EXTERNAL_DEBUGGER] } { echo "Using external debugger" } else { source [find interface/altera-usb-blaster2.cfg] - usb_blaster_device_desc "Arria10 IDK" + usb_blaster device_desc "Arria10 IDK" } source [find fpga/altera-10m50.cfg] 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_falcon.cfg b/tcl/board/renesas_falcon.cfg new file mode 100644 index 0000000000..c796f85b58 --- /dev/null +++ b/tcl/board/renesas_falcon.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Renesas R-Car V3U Falcon Board Config + +# The Falcon board comes with either an V3U SOC. + +echo "\nFalcon:" +if { ![info exists SOC] } { + set SOC V3U +} +source [find target/renesas_rcar_gen3.cfg] 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/rpi3.cfg b/tcl/board/rpi3.cfg new file mode 100644 index 0000000000..fd93a9d9d8 --- /dev/null +++ b/tcl/board/rpi3.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Raspberry Pi 3 board with BCM2837 chip +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837/README.md +# +# Enable JTAG GPIO on Raspberry Pi boards +# https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md + +source [find target/bcm2837.cfg] +transport select jtag + +# Raspberry Pi boards only expose Test Reset (TRST) pin, no System Reset (SRST) +reset_config trst_only diff --git a/tcl/board/rpi4b.cfg b/tcl/board/rpi4b.cfg new file mode 100644 index 0000000000..5b046af7b5 --- /dev/null +++ b/tcl/board/rpi4b.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Raspberry Pi 4 model B board with BCM2711 chip +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/README.md +# +# Enable JTAG GPIO on Raspberry Pi boards +# https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md + +source [find target/bcm2711.cfg] +transport select jtag + +# Raspberry Pi boards only expose Test Reset (TRST) pin, no System Reset (SRST) +reset_config trst_only 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 009eb78c2a..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+). @@ -11,19 +13,19 @@ # which features an Artix 7 FPGA. adapter driver ftdi -ftdi_device_desc "Quad RS232-HS" -ftdi_vid_pid 0x0403 0x6011 -ftdi_channel 0 +ftdi device_desc "Quad RS232-HS" +ftdi vid_pid 0x0403 0x6011 +ftdi channel 0 # Use this to distinguish multiple boards by topology -#ftdi_location 5:1 +#adapter usb location 5:1 # sampling on falling edge generally seems to work and accelerates things but # is not fully tested -#ftdi_tdo_sample_edge falling +#ftdi tdo_sample_edge falling # EN_USB_JTAG on ADBUS7: out, high # USB_nTRST on ADBUS4: out, high, but R46 is DNP -ftdi_layout_init 0x0098 0x008b -#ftdi_layout_signal EN_USB -data 0x0080 -#ftdi_layout_signal nTRST -data 0x0010 +ftdi layout_init 0x0098 0x008b +#ftdi layout_signal EN_USB -data 0x0080 +#ftdi layout_signal nTRST -data 0x0010 reset_config none adapter speed 5000 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 b7a255ea25..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: @@ -14,8 +16,8 @@ $_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work- flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 init if {[ info exists pulse_srst]} { - ftdi_set_signal nSRST 0 - ftdi_set_signal nSRST z + ftdi set_signal nSRST 0 + ftdi set_signal nSRST z } halt flash protect 0 64 last off diff --git a/tcl/board/sifive-e51arty.cfg b/tcl/board/sifive-e51arty.cfg index 20ad575517..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: @@ -14,8 +16,8 @@ $_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work- flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 init if {[ info exists pulse_srst]} { - ftdi_set_signal nSRST 0 - ftdi_set_signal nSRST z + ftdi set_signal nSRST 0 + ftdi set_signal nSRST z } halt flash protect 0 64 last off diff --git a/tcl/board/sifive-hifive1-revb.cfg b/tcl/board/sifive-hifive1-revb.cfg index 292f1027aa..e5fe104ac8 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 196f540bba..f69dc4fcc0 100644 --- a/tcl/board/sifive-hifive1.cfg +++ b/tcl/board/sifive-hifive1.cfg @@ -1,15 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + adapter speed 10000 adapter driver ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Dual RS232-HS" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0008 0x001b -ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020 +ftdi layout_init 0x0008 0x001b +ftdi layout_signal nSRST -oe 0x0020 -data 0x0020 #Reset Stretcher logic on FE310 is ~1 second long #This doesn't apply if you use -# ftdi_set_signal, but still good to document +# ftdi set_signal, but still good to document #adapter srst delay 1500 set _CHIPNAME riscv @@ -23,8 +25,8 @@ flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME init #reset -- This type of reset is not implemented yet if {[ info exists pulse_srst]} { - ftdi_set_signal nSRST 0 - ftdi_set_signal nSRST z + ftdi set_signal nSRST 0 + ftdi set_signal nSRST z #Wait for the reset stretcher #It will work without this, but #will incur lots of delays for later commands. 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 fed7343dec..24022e5a80 100644 --- a/tcl/board/snps_hsdk.cfg +++ b/tcl/board/snps_hsdk.cfg @@ -1,15 +1,15 @@ +# 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) # source [find interface/ftdi/snps_sdp.cfg] -adapter_khz 10000 +adapter speed 10000 # ARCs supports only JTAG. transport select jtag 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_b-l475e-iot01a.cfg b/tcl/board/st_b-l475e-iot01a.cfg new file mode 100644 index 0000000000..e75c99d7a5 --- /dev/null +++ b/tcl/board/st_b-l475e-iot01a.cfg @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is an B-L475E-IOT01A Discovery kit for IoT node with a single STM32L475VGT6 chip. +# http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 96KB +set WORKAREASIZE 0x18000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32l4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) + mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PE11: NCS, PE10: CLK, PE15: BK1_IO3, PE14: BK1_IO2, PE13: BK1_IO1, PE12: BK1_IO0 + + # PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V + + # Port E: PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V + mmw 0x48001000 0xAAA00000 0x55500000 ;# MODER + mmw 0x48001008 0xFFF00000 0x00000000 ;# OSPEEDR + mmw 0x48001024 0xAAAAAA00 0x55555500 ;# AFRH + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00160100 ;# QUADSPI_DCR: FSIZE=0x16, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK + sleep 1 + mmw 0x40021000 0x00000100 0x00000000 ;# HSI on + mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI + mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 + mmw 0x40021000 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} 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_8s208rb.cfg b/tcl/board/st_nucleo_8s208rb.cfg new file mode 100644 index 0000000000..0d3c0c9125 --- /dev/null +++ b/tcl/board/st_nucleo_8s208rb.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is a ST NUCLEO 8S208RB board with a single STM8S208RBT6 chip. +# https://www.st.com/en/evaluation-tools/nucleo-8s208rb.html + +source [find interface/stlink-dap.cfg] + +transport select swim + +# 128 KiB flash and 2 KiB EEPROM +set FLASHEND 0x27fff +set EEPROMEND 0x47ff + +source [find target/stm8s.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_g0.cfg b/tcl/board/st_nucleo_g0.cfg new file mode 100644 index 0000000000..f8e67a0432 --- /dev/null +++ b/tcl/board/st_nucleo_g0.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is for all ST NUCLEO with any STM32G0. Known boards at the moment: +# NUCLEO-G031K8 +# https://www.st.com/en/evaluation-tools/nucleo-g031k8.html +# NUCLEO-G070RB +# https://www.st.com/en/evaluation-tools/nucleo-g070rb.html +# NUCLEO-G071RB +# https://www.st.com/en/evaluation-tools/nucleo-g071rb.html +# NUCLEO-G0B1RE +# https://www.st.com/en/evaluation-tools/nucleo-g0b1re.html + +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32g0x.cfg] + +reset_config srst_only diff --git a/tcl/board/st_nucleo_g4.cfg b/tcl/board/st_nucleo_g4.cfg new file mode 100644 index 0000000000..8e583e77d5 --- /dev/null +++ b/tcl/board/st_nucleo_g4.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is for all ST NUCLEO with any STM32G4. Known boards at the moment: +# NUCLEO-G431KB +# https://www.st.com/en/evaluation-tools/nucleo-g431kb.html +# NUCLEO-G431RB +# https://www.st.com/en/evaluation-tools/nucleo-g431rb.html +# NUCLEO-G474RE +# https://www.st.com/en/evaluation-tools/nucleo-g474re.html +# NUCLEO-G491RE +# https://www.st.com/en/evaluation-tools/nucleo-g491re.html + +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32g4x.cfg] + +reset_config srst_only 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_l5.cfg b/tcl/board/st_nucleo_l5.cfg new file mode 100644 index 0000000000..6450f08b8d --- /dev/null +++ b/tcl/board/st_nucleo_l5.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is for STM32L5 Nucleo Dev Boards. +# http://www.st.com/en/evaluation-tools/stm32-mcu-nucleo.html + +source [find interface/stlink-dap.cfg] + +transport select dapdirect_swd + +source [find target/stm32l5x.cfg] + +# use hardware reset +reset_config srst_only srst_nogate 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 a5e5896b32..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 @@ -8,3 +10,5 @@ set WORKAREASIZE 0x40000 source [find target/stm32f7x.cfg] + +reset_config srst_only 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 new file mode 100644 index 0000000000..757b25d75c --- /dev/null +++ b/tcl/board/stm32f412g-disco.cfg @@ -0,0 +1,72 @@ +# 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 + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 128KB +set WORKAREASIZE 0x20000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000000FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOHEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PB02: CLK, PG06: BK1_NCS, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 + + # PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V + + # Port B: PB02:AF09:V + mmw 0x40020400 0x00000020 0x00000010 ;# MODER + mmw 0x40020408 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x00000900 0x00000600 ;# AFRL + + # Port F: PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V + mmw 0x40021400 0x000AA000 0x00055000 ;# MODER + mmw 0x40021408 0x000FF000 0x00000000 ;# OSPEEDR + mmw 0x40021420 0x99000000 0x66000000 ;# AFRL + mmw 0x40021424 0x000000AA 0x00000055 ;# AFRH + + # Port G: PG06:AF10:V + mmw 0x40021800 0x00002000 0x00001000 ;# MODER + mmw 0x40021808 0x00003000 0x00000000 ;# OSPEEDR + mmw 0x40021820 0x0A000000 0x05000000 ;# AFRL + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000003 ;# 3 WS for 96 MHz HCLK + sleep 1 + mww 0x40023804 0x24001808 ;# 96 MHz: HSI, PLLM=8, PLLN=96, PLLP=2 + mww 0x40023808 0x00001000 ;# APB1: /2, APB2: /1 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32f413h-disco.cfg b/tcl/board/stm32f413h-disco.cfg new file mode 100644 index 0000000000..6abf495514 --- /dev/null +++ b/tcl/board/stm32f413h-disco.cfg @@ -0,0 +1,85 @@ +# 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 + +# +# Untested!!! +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 128KB +set WORKAREASIZE 0x20000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000000FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOHEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PG06: BK1_NCS, PB02: CLK, PD13: BK1_IO3, PE02: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 + + # PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V + + # Port B: PB02:AF09:V + mmw 0x40020400 0x00000020 0x00000010 ;# MODER + mmw 0x40020408 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x00000900 0x00000600 ;# AFRL + + # Port D: PD13:AF09:V + mmw 0x40020C00 0x08000000 0x04000000 ;# MODER + mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR + mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH + + # Port E: PE02:AF09:V + mmw 0x40021000 0x00000020 0x00000010 ;# MODER + mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40021020 0x00000900 0x00000600 ;# AFRL + + # Port F: PF09:AF10:V, PF08:AF10:V + mmw 0x40021400 0x000A0000 0x00050000 ;# MODER + mmw 0x40021408 0x000F0000 0x00000000 ;# OSPEEDR + mmw 0x40021424 0x000000AA 0x00000055 ;# AFRH + + # Port G: PG06:AF10:V + mmw 0x40021800 0x00002000 0x00001000 ;# MODER + mmw 0x40021808 0x00003000 0x00000000 ;# OSPEEDR + mmw 0x40021820 0x0A000000 0x05000000 ;# AFRL + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000003 ;# 3 WS for 96 MHz HCLK + sleep 1 + mww 0x40023804 0x24001808 ;# 96 MHz: HSI, PLLM=8, PLLN=96, PLLP=2 + mww 0x40023808 0x00001000 ;# APB1: /2, APB2: /1 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} 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 new file mode 100644 index 0000000000..7ce57f6e75 --- /dev/null +++ b/tcl/board/stm32f469i-disco.cfg @@ -0,0 +1,67 @@ +# 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 + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 128KB +set WORKAREASIZE 0x20000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PF10: CLK, PB06: BK1_NCS, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 + + # PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V + + # Port B: PB06:AF10:V + mmw 0x40020400 0x00002000 0x00001000 ;# MODER + mmw 0x40020408 0x00003000 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x0A000000 0x05000000 ;# AFRL + + # Port F: PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V + mmw 0x40021400 0x002AA000 0x00155000 ;# MODER + mmw 0x40021408 0x003FF000 0x00000000 ;# OSPEEDR + mmw 0x40021420 0x99000000 0x66000000 ;# AFRL + mmw 0x40021424 0x000009AA 0x00000655 ;# AFRH + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000005 ;# 5 WS for 160 MHz HCLK + sleep 1 + mww 0x40023804 0x24002808 ;# 160 MHz: HSI, PLLM=8, PLLN=160, PLLP=2 + mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} 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 new file mode 100644 index 0000000000..2dee2f9023 --- /dev/null +++ b/tcl/board/stm32f723e-disco.cfg @@ -0,0 +1,78 @@ +# 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 + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 128KB +set WORKAREASIZE 0x20000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f7x.cfg] + +reset_config srst_only + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PC10: BK1_IO1, PC09: BK1_IO0 + + # PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V + + # Port B: PB06:AF10:V, PB02:AF09:V + mmw 0x40020400 0x00002020 0x00001010 ;# MODER + mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL + + # Port C: PC10:AF09:V, PC09:AF09:V + mmw 0x40020800 0x00280000 0x00140000 ;# MODER + mmw 0x40020808 0x003C0000 0x00000000 ;# OSPEEDR + mmw 0x40020824 0x00000990 0x00000660 ;# AFRH + + # Port D: PD13:AF09:V + mmw 0x40020C00 0x08000000 0x04000000 ;# MODER + mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR + mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH + + # Port E: PE02:AF09:V + mmw 0x40021000 0x00000020 0x00000010 ;# MODER + mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40021020 0x00000900 0x00000600 ;# AFRL + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00190100 ;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 4-byte addresses + mww 0xA0001014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK + sleep 1 + mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 + mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32f746g-disco.cfg b/tcl/board/stm32f746g-disco.cfg new file mode 100644 index 0000000000..fed1d8ec9b --- /dev/null +++ b/tcl/board/stm32f746g-disco.cfg @@ -0,0 +1,73 @@ +# 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 + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 256KB +set WORKAREASIZE 0x40000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f7x.cfg] + +reset_config srst_only + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PD12: BK1_IO1, PD11: BK1_IO0 + + # PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PE02:AF09:V + + # Port B: PB06:AF10:V, PB02:AF09:V + mmw 0x40020400 0x00002020 0x00001010 ;# MODER + mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL + + # Port D: PD13:AF09:V, PD12:AF09:V, PD11:AF09:V + mmw 0x40020C00 0x0A800000 0x05400000 ;# MODER + mmw 0x40020C08 0x0FC00000 0x00000000 ;# OSPEEDR + mmw 0x40020C24 0x00999000 0x00666000 ;# AFRH + + # Port E: PE02:AF09:V + mmw 0x40021000 0x00000020 0x00000010 ;# MODER + mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40021020 0x00000900 0x00000600 ;# AFRL + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK + sleep 1 + mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 + mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32f769i-disco.cfg b/tcl/board/stm32f769i-disco.cfg new file mode 100644 index 0000000000..2969bb9272 --- /dev/null +++ b/tcl/board/stm32f769i-disco.cfg @@ -0,0 +1,83 @@ +# 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 + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 256KB +set WORKAREASIZE 0x40000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f7x.cfg] + +reset_config srst_only + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PC10: BK1_IO1, PC09: BK1_IO0 + + # PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V + + # Port B: PB06:AF10:V, PB02:AF09:V + mmw 0x40020400 0x00002020 0x00001010 ;# MODER + mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL + + # Port C: PC10:AF09:V, PC09:AF09:V + mmw 0x40020800 0x00280000 0x00140000 ;# MODER + mmw 0x40020808 0x003C0000 0x00000000 ;# OSPEEDR + mmw 0x40020824 0x00000990 0x00000660 ;# AFRH + + # Port D: PD13:AF09:V + mmw 0x40020C00 0x08000000 0x04000000 ;# MODER + mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR + mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH + + # Port E: PE02:AF09:V + mmw 0x40021000 0x00000020 0x00000010 ;# MODER + mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40021020 0x00000900 0x00000600 ;# AFRL + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00190100 ;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # exit qpi mode + mww 0xA0001014 0x000033f5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + + # 1-line memory-mapped read mode with 4-byte addresses + mww 0xA0001014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ + + # 4-line qpi mode + mww 0xA0001014 0x00003135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=EQIO + + # 4-line memory-mapped read mode with 4-byte addresses + mww 0xA0001014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0xA, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=4READ4B +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK + sleep 1 + mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 + mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32f7discovery.cfg b/tcl/board/stm32f7discovery.cfg index 7d1bc9665c..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 @@ -10,3 +12,5 @@ transport select hla_swd set WORKAREASIZE 0x40000 source [find target/stm32f7x.cfg] + +reset_config srst_only diff --git a/tcl/board/stm32h735g-disco.cfg b/tcl/board/stm32h735g-disco.cfg new file mode 100644 index 0000000000..4097ae28b2 --- /dev/null +++ b/tcl/board/stm32h735g-disco.cfg @@ -0,0 +1,126 @@ +# 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 +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +set CHIPNAME stm32h735igk6 + +# enable stmqspi +if {![info exists OCTOSPI1]} { + set OCTOSPI1 1 + set OCTOSPI2 0 +} + +source [find target/stm32h7x.cfg] + +reset_config srst_only + +# OCTOSPI initialization +# octo: 8-line mode +proc octospi_init { octo } { + global a b + mmw 0x58024540 0x000006FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x58024534 0x00284000 0 ;# RCC_AHB3ENR |= IOMNGREN, OSPI2EN, OSPI1EN (enable clocks) + sleep 1 ;# Wait for clock startup + + mww 0x5200B404 0x03010111 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI1 + mww 0x5200B408 0x00000000 ;# OCTOSPIM_P2CR: disable Port 2 + + # PG06: OCSPI1_NCS, PF10: OCSPI1_CLK, PB02: OCSPI1_DQS, PD07: OCSPI1_IO7, PG09: OCSPI1_IO6, PD05: OCSPI1_IO5, + # PD04: OCSPI1_IO4, PD13: OCSPI1_IO3, PE02: OCSPI1_IO2, PD12: OCSPI1_IO1, PD11: OCSPI1_IO0 + + # PB02:AF10:V, PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PD07:AF10:V, PD05:AF10:V + # PD04:AF10:V, PE02:AF09:V, PF10:AF09:V, PG09:AF09:V, PG06:AF10:V + # Port B: PB02:AF10:V + mmw 0x58020400 0x00000020 0x00000010 ;# MODER + mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x5802040C 0x00000000 0x00000030 ;# PUPDR + mmw 0x58020420 0x00000A00 0x00000500 ;# AFRL + # Port D: PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V + mmw 0x58020C00 0x0A808A00 0x05404500 ;# MODER + mmw 0x58020C08 0x0FC0CF00 0x00000000 ;# OSPEEDR + mmw 0x58020C0C 0x00000000 0x0FC0CF00 ;# PUPDR + mmw 0x58020C20 0xA0AA0000 0x50550000 ;# AFRL + mmw 0x58020C24 0x00999000 0x00666000 ;# AFRH + # Port E: PE02:AF09:V + mmw 0x58021000 0x00000020 0x00000010 ;# MODER + mmw 0x58021008 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x5802100C 0x00000000 0x00000030 ;# PUPDR + mmw 0x58021020 0x00000900 0x00000600 ;# AFRL + # Port F: PF10:AF09:V + mmw 0x58021400 0x00200000 0x00100000 ;# MODER + mmw 0x58021408 0x00300000 0x00000000 ;# OSPEEDR + mmw 0x5802140C 0x00000000 0x00300000 ;# PUPDR + mmw 0x58021424 0x00000900 0x00000600 ;# AFRH + # Port G: PG09:AF09:V, PG06:AF10:V + mmw 0x58021800 0x00082000 0x00041000 ;# MODER + mmw 0x58021808 0x000C3000 0x00000000 ;# OSPEEDR + mmw 0x5802180C 0x00000000 0x000C3000 ;# PUPDR + mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL + mmw 0x58021824 0x00000090 0x00000060 ;# AFRH + + # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses + mww 0x52005130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 + mww 0x52005008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 + mww 0x5200500C 0x00000005 ;# OCTOSPI_DCR2: PRESCALER=5 + + mww 0x52005108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 + mww 0x52005100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 + mww 0x52005110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B + + flash probe $a ;# load configuration from CR, TCR, CCR, IR register values + + if { $octo == 1 } { + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 ;# Read Status Register + stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable + + # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses + mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 + mww 0x52005108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 + mww 0x52005100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 + mww 0x52005110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read + + flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values + + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 0 0x04 ;# Write Disable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + } +} + +$_CHIPNAME.cpu0 configure -event reset-init { + global OCTOSPI1 + global OCTOSPI2 + + mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK + + mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on + mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock + mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 + mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 + mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 + mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI + mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide + mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 + mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 + sleep 1 + mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock + sleep 1 + + adapter speed 24000 + + if { $OCTOSPI1 } { + octospi_init 1 + } +} diff --git a/tcl/board/stm32h745i-disco.cfg b/tcl/board/stm32h745i-disco.cfg new file mode 100644 index 0000000000..1c0bc6748c --- /dev/null +++ b/tcl/board/stm32h745i-disco.cfg @@ -0,0 +1,49 @@ +# 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 +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +set CHIPNAME stm32h745xih6 + +# enable stmqspi +if {![info exists QUADSPI]} { + set QUADSPI 1 +} + +source [find target/stm32h7x_dual_bank.cfg] + +reset_config srst_only + +source [find board/stm32h7x_dual_qspi.cfg] + +$_CHIPNAME.cpu0 configure -event reset-init { + global QUADSPI + + mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK + + mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on + mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock + mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 + mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 + mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 + mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI + mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide + mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 + mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 + sleep 1 + mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock + sleep 1 + + adapter speed 24000 + + if { $QUADSPI } { + qspi_init 1 + } +} + diff --git a/tcl/board/stm32h747i-disco.cfg b/tcl/board/stm32h747i-disco.cfg new file mode 100644 index 0000000000..e0a348ef08 --- /dev/null +++ b/tcl/board/stm32h747i-disco.cfg @@ -0,0 +1,140 @@ +# 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 +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +set CHIPNAME stm32h747xih6 + +# enable stmqspi +if {![info exists QUADSPI]} { + set QUADSPI 1 +} + +source [find target/stm32h7x_dual_bank.cfg] + +reset_config srst_only + +# QUADSPI initialization +# qpi: 4-line mode +proc qspi_init { qpi } { + global a + mmw 0x580244E0 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x580244D4 0x00004000 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PG06: BK1_NCS, PB02: CLK, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PD11: BK1_IO0, + # PG14: BK2_IO3, PG09: BK2_IO2, PH03: BK2_IO1, PH02: BK2_IO0 + + # PB02:AF09:V, PD11:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V, PG14:AF09:H + # PG09:AF09:V, PG06:AF10:H, PH03:AF09:V, PH02:AF09:V + + # Port B: PB02:AF09:V + mmw 0x58020400 0x00000020 0x00000010 ;# MODER + mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x58020420 0x00000900 0x00000600 ;# AFRL + # Port D: PD11:AF09:V + mmw 0x58020C00 0x00800000 0x00400000 ;# MODER + mmw 0x58020C08 0x00C00000 0x00000000 ;# OSPEEDR + mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH + # Port F: PF09:AF10:V, PF07:AF09:V, PF06:AF09:V + mmw 0x58021400 0x0008A000 0x00045000 ;# MODER + mmw 0x58021408 0x000CF000 0x00000000 ;# OSPEEDR + mmw 0x58021420 0x99000000 0x66000000 ;# AFRL + mmw 0x58021424 0x000000A0 0x00000050 ;# AFRH + # Port G: PG14:AF09:H, PG09:AF09:V, PG06:AF10:H + mmw 0x58021800 0x20082000 0x10041000 ;# MODER + mmw 0x58021808 0x200C2000 0x10001000 ;# OSPEEDR + mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL + mmw 0x58021824 0x09000090 0x06000060 ;# AFRH + # Port H: PH03:AF09:V, PH02:AF09:V + mmw 0x58021C00 0x000000A0 0x00000050 ;# MODER + mmw 0x58021C08 0x000000F0 0x00000000 ;# OSPEEDR + mmw 0x58021C20 0x00009900 0x00006600 ;# AFRL + + # correct FSIZE is 0x1A, however, this causes trouble when + # reading the last bytes at end of bank in *memory mapped* mode + + # for dual flash mode 2 * mt25ql512 + mww 0x52005000 0x05500058 ;# QUADSPI_CR: PRESCALER=5, APMS=1, FTHRES=0, FSEL=0, DFM=1, SSHIFT=1, TCEN=1 + mww 0x52005004 0x001A0200 ;# QUADSPI_DCR: FSIZE=0x1A, CSHT=0x02, CKMODE=0 + + mww 0x52005030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0x52005014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1 + mmw 0x52005000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # Exit QPI mode + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=Exit QPI + sleep 1 + + if { $qpi == 1 } { + # Write Enable + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable + sleep 1 + + # Configure dummy clocks via volatile configuration register + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes + mww 0x52005014 0x01000181 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Volatile Conf. Reg. + mwh 0x52005020 0xABAB ;# QUADSPI_DR: 0xAB 0xAB for 10 dummy clocks + sleep 1 + + # Write Enable + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable + sleep 1 + + # Enable QPI mode via enhanced volatile configuration register + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes + mww 0x52005014 0x01000161 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enhanced Conf. Reg. + mwh 0x52005020 0x3F3F ;# QUADSPI_DR: 0x3F 0x3F to enable QPI and DPI mode + sleep 1 + + # Enter QPI mode + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Enter QPI + sleep 1 + + # memory-mapped fast read mode with 4-byte addresses and 10 dummy cycles (for read only) + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x3, DCYC=0xA, ADSIZE=0x3, ADMODE=0x3, IMODE=0x3, INSTR=Fast READ + } else { + # memory-mapped read mode with 4-byte addresses + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ + } +} + +$_CHIPNAME.cpu0 configure -event reset-init { + global QUADSPI + + mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK + + mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on + mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock + mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 + mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 + mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 + mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI + mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide + mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 + mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 + sleep 1 + mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock + sleep 1 + + adapter speed 24000 + + if { $QUADSPI } { + qspi_init 1 + } +} + diff --git a/tcl/board/stm32h750b-disco.cfg b/tcl/board/stm32h750b-disco.cfg new file mode 100644 index 0000000000..efb32b1dfb --- /dev/null +++ b/tcl/board/stm32h750b-disco.cfg @@ -0,0 +1,49 @@ +# 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 +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +set CHIPNAME stm32h750xbh6 + +# enable stmqspi +if {![info exists QUADSPI]} { + set QUADSPI 1 +} + +source [find target/stm32h7x.cfg] + +reset_config srst_only + +source [find board/stm32h7x_dual_qspi.cfg] + +$_CHIPNAME.cpu0 configure -event reset-init { + global QUADSPI + + mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK + + mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on + mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock + mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 + mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 + mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 + mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI + mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide + mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 + mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 + sleep 1 + mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock + sleep 1 + + adapter speed 24000 + + if { $QUADSPI } { + qspi_init 1 + } +} + diff --git a/tcl/board/stm32h7b3i-disco.cfg b/tcl/board/stm32h7b3i-disco.cfg new file mode 100644 index 0000000000..58ad9f7814 --- /dev/null +++ b/tcl/board/stm32h7b3i-disco.cfg @@ -0,0 +1,132 @@ +# 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 +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +set CHIPNAME stm32h7b3lih6q + +# enable stmqspi +if {![info exists OCTOSPI1]} { + set OCTOSPI1 1 + set OCTOSPI2 0 +} + +source [find target/stm32h7x_dual_bank.cfg] + +reset_config srst_only + +# OCTOSPI initialization +# octo: 8-line mode +proc octospi_init { octo } { + global a b + mmw 0x58024540 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x58024534 0x00284000 0 ;# RCC_AHB3ENR |= IOMNGREN, OSPI2EN, OSPI1EN (enable clocks) + sleep 1 ;# Wait for clock startup + + mww 0x5200B404 0x03010111 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI1 + mww 0x5200B408 0x00000000 ;# OCTOSPIM_P2CR: disable Port 2 + + # PG06: OCSPI1_NCS, PB02: OCSPI1_CLK, PC05: OCSPI1_DQS, PD07: OCSPI1_IO7, PG09: OCSPI1_IO6, PH03: OCSPI1_IO5, + # PC01: OCSPI1_IO4, PF06: OCSPI1_IO3, PF07: OCSPI1_IO2, PF09: OCSPI1_IO1, PD11: OCSPI1_IO0 + + # PB02:AF09:V, PC05:AF10:V, PC01:AF10:V, PD11:AF09:V, PD07:AF10:V, PF09:AF10:V + # PF07:AF10:V, PF06:AF10:V, PG09:AF09:V, PG06:AF10:V, PH03:AF09:V + # Port B: PB02:AF09:V + mmw 0x58020400 0x00000020 0x00000010 ;# MODER + mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x5802040C 0x00000000 0x00000030 ;# PUPDR + mmw 0x58020420 0x00000900 0x00000600 ;# AFRL + # Port C: PC05:AF10:V, PC01:AF10:V + mmw 0x58020800 0x00000808 0x00000404 ;# MODER + mmw 0x58020808 0x00000C0C 0x00000000 ;# OSPEEDR + mmw 0x5802080C 0x00000000 0x00000C0C ;# PUPDR + mmw 0x58020820 0x00A000A0 0x00500050 ;# AFRL + # Port D: PD11:AF09:V, PD07:AF10:V + mmw 0x58020C00 0x00808000 0x00404000 ;# MODER + mmw 0x58020C08 0x00C0C000 0x00000000 ;# OSPEEDR + mmw 0x58020C0C 0x00000000 0x00C0C000 ;# PUPDR + mmw 0x58020C20 0xA0000000 0x50000000 ;# AFRL + mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH + # Port F: PF09:AF10:V, PF07:AF10:V, PF06:AF10:V + mmw 0x58021400 0x0008A000 0x00045000 ;# MODER + mmw 0x58021408 0x000CF000 0x00000000 ;# OSPEEDR + mmw 0x5802140C 0x00000000 0x000CF000 ;# PUPDR + mmw 0x58021420 0xAA000000 0x55000000 ;# AFRL + mmw 0x58021424 0x000000A0 0x00000050 ;# AFRH + # Port G: PG09:AF09:V, PG06:AF10:V + mmw 0x58021800 0x00082000 0x00041000 ;# MODER + mmw 0x58021808 0x000C3000 0x00000000 ;# OSPEEDR + mmw 0x5802180C 0x00000000 0x000C3000 ;# PUPDR + mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL + mmw 0x58021824 0x00000090 0x00000060 ;# AFRH + # Port H: PH03:AF09:V + mmw 0x58021C00 0x00000080 0x00000040 ;# MODER + mmw 0x58021C08 0x000000C0 0x00000000 ;# OSPEEDR + mmw 0x58021C0C 0x00000000 0x000000C0 ;# PUPDR + mmw 0x58021C20 0x00009000 0x00006000 ;# AFRL + + # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses + mww 0x52005130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 + mww 0x52005008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 + mww 0x5200500C 0x00000005 ;# OCTOSPI_DCR2: PRESCALER=5 + + mww 0x52005108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 + mww 0x52005100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 + mww 0x52005110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B + + flash probe $a ;# load configuration from CR, TCR, CCR, IR register values + + if { $octo == 1 } { + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 ;# Read Status Register + stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable + + # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses + mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 + mww 0x52005108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 + mww 0x52005100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 + mww 0x52005110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read + + flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values + + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 0 0x04 ;# Write Disable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + } +} + +$_CHIPNAME.cpu0 configure -event reset-init { + global OCTOSPI1 + global OCTOSPI2 + + mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK + + mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on + mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock + mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 + mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 + mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 + mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI + mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide + mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 + mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 + sleep 1 + mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock + sleep 1 + + adapter speed 24000 + + if { $OCTOSPI1 } { + octospi_init 1 + } +} 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 new file mode 100644 index 0000000000..0349fadc54 --- /dev/null +++ b/tcl/board/stm32h7x_dual_qspi.cfg @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# stm32h754i-disco and stm32h750b-dk dual quad qspi. + +# QUADSPI initialization +# qpi: 4-line mode +proc qspi_init { qpi } { + global a + mmw 0x580244E0 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x580244D4 0x00004000 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PG06: BK1_NCS, PF10: CLK, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PD11: BK1_IO0, + # PG14: BK2_IO3, PG09: BK2_IO2, PH03: BK2_IO1, PH02: BK2_IO0 + + # PD11:AF09:V, PF10:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V, PG14:AF09:H + # PG09:AF09:V, PG06:AF10:H, PH03:AF09:V, PH02:AF09:V + + # Port D: PD11:AF09:V + mmw 0x58020C00 0x00800000 0x00400000 ;# MODER + mmw 0x58020C08 0x00C00000 0x00000000 ;# OSPEEDR + mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH + # Port F: PF10:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V + mmw 0x58021400 0x0028A000 0x00145000 ;# MODER + mmw 0x58021408 0x003CF000 0x00000000 ;# OSPEEDR + mmw 0x58021420 0x99000000 0x66000000 ;# AFRL + mmw 0x58021424 0x000009A0 0x00000650 ;# AFRH + # Port G: PG14:AF09:H, PG09:AF09:V, PG06:AF10:H + mmw 0x58021800 0x20082000 0x10041000 ;# MODER + mmw 0x58021808 0x200C2000 0x10001000 ;# OSPEEDR + mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL + mmw 0x58021824 0x09000090 0x06000060 ;# AFRH + # Port H: PH03:AF09:V, PH02:AF09:V + mmw 0x58021C00 0x000000A0 0x00000050 ;# MODER + mmw 0x58021C08 0x000000F0 0x00000000 ;# OSPEEDR + mmw 0x58021C20 0x00009900 0x00006600 ;# AFRL + + # correct FSIZE is 0x1A, however, this causes trouble when + # reading the last bytes at end of bank in *memory mapped* mode + + # for dual flash mode 2 * mt25ql512 + mww 0x52005000 0x05500058 ;# QUADSPI_CR: PRESCALER=5, APMS=1, FTHRES=0, FSEL=0, DFM=1, SSHIFT=1, TCEN=1 + mww 0x52005004 0x001A0200 ;# QUADSPI_DCR: FSIZE=0x1A, CSHT=0x02, CKMODE=0 + + mww 0x52005030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0x52005014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1 + mmw 0x52005000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # Exit QPI mode + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=Exit QPI + sleep 1 + + if { $qpi == 1 } { + # Write Enable + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable + sleep 1 + + # Configure dummy clocks via volatile configuration register + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes + mww 0x52005014 0x01000181 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Volatile Conf. Reg. + mwh 0x52005020 0xABAB ;# QUADSPI_DR: 0xAB 0xAB for 10 dummy clocks + sleep 1 + + # Write Enable + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable + sleep 1 + + # Enable QPI mode via enhanced volatile configuration register + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes + mww 0x52005014 0x01000161 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enhanced Conf. Reg. + mwh 0x52005020 0x3F3F ;# QUADSPI_DR: 0x3F 0x3F to enable QPI and DPI mode + sleep 1 + + # Enter QPI mode + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Enter QPI + sleep 1 + + # memory-mapped fast read mode with 4-byte addresses and 10 dummy cycles (for read only) + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x3, DCYC=0xA, ADSIZE=0x3, ADMODE=0x3, IMODE=0x3, INSTR=Fast READ + } else { + # memory-mapped read mode with 4-byte addresses + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ + } +} 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 new file mode 100644 index 0000000000..a32d20fb3f --- /dev/null +++ b/tcl/board/stm32l476g-disco.cfg @@ -0,0 +1,58 @@ +# 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 + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 96KB +set WORKAREASIZE 0x18000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32l4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) + mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PE11: NCS, PE10: CLK, PE15: BK1_IO3, PE14: BK1_IO2, PE13: BK1_IO1, PE12: BK1_IO0 + + # PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V + + # Port E: PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V + mmw 0x48001000 0xAAA00000 0x55500000 ;# MODER + mmw 0x48001008 0xFFF00000 0x00000000 ;# OSPEEDR + mmw 0x48001024 0xAAAAAA00 0x55555500 ;# AFRH + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK + sleep 1 + mmw 0x40021000 0x00000100 0x00000000 ;# HSI on + mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI + mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 + mmw 0x40021000 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32l496g-disco.cfg b/tcl/board/stm32l496g-disco.cfg new file mode 100644 index 0000000000..1ba2299ca9 --- /dev/null +++ b/tcl/board/stm32l496g-disco.cfg @@ -0,0 +1,68 @@ +# 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 + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 96KB +set WORKAREASIZE 0x18000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32l4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) + mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PB11: BK1_NCS, PA03: CLK, PA06: BK1_IO3, PA07: BK1_IO2, PB00: BK1_IO1, PB01: BK1_IO0 + + # PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V + + # Port A: PA07:AF10:V, PA06:AF10:V, PA03:AF10:V + mmw 0x48000000 0x0000A080 0x00005040 ;# MODER + mmw 0x48000008 0x0000F0C0 0x00000000 ;# OSPEEDR + mmw 0x48000020 0xAA00A000 0x55005000 ;# AFRL + + # Port B: PB11:AF10:V, PB01:AF10:V, PB00:AF10:V + mmw 0x48000400 0x0080000A 0x00400005 ;# MODER + mmw 0x48000408 0x00C0000F 0x00000000 ;# OSPEEDR + mmw 0x48000420 0x000000AA 0x00000055 ;# AFRL + mmw 0x48000424 0x0000A000 0x00005000 ;# AFRH + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00160100 ;# QUADSPI_DCR: FSIZE=0x16, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK + sleep 1 + mmw 0x40021000 0x00000100 0x00000000 ;# HSI on + mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI + mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 + mmw 0x40021000 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} 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 new file mode 100644 index 0000000000..20d781a1a4 --- /dev/null +++ b/tcl/board/stm32l4p5g-disco.cfg @@ -0,0 +1,132 @@ +# 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 + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 96KB +set WORKAREASIZE 0x18000 + +# enable stmqspi +set OCTOSPI1 1 +set OCTOSPI2 0 + +source [find target/stm32l4x.cfg] + +# OCTOSPI initialization +# octo: 8-line mode +proc octospi_init { octo } { + global a b + mmw 0x4002104C 0x001001FF 0 ;# RCC_AHB2ENR |= OSPIMEN, GPIOAEN-GPIOIEN (enable clocks) + mmw 0x40021050 0x00000300 0 ;# RCC_AHB3ENR |= OSPI2EN, OSPI1EN (enable clocks) + mmw 0x40021058 0x10000000 0 ;# RCC_APB1ENR1 |= PWREN (enable clock) + sleep 1 ;# Wait for clock startup + + mmw 0x40007004 0x00000200 0 ;# PWR_CR2 |= IOSV (required for use of GPOIG, cf. RM0432) + + mww 0x50061C04 0x07050333 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI2 + mww 0x50061C08 0x03010111 ;# OCTOSPIM_P2CR: assign Port 2 to OCTOSPI1 + + # PE11: P1_NCS, PE10: P1_CLK, PG06: P1_DQS, PD07: P1_IO7, PC03: P1_IO6, PD05: P1_IO5 + # PD04: P1_IO4, PA06: P1_IO3, PA07: P1_IO2, PE13: P1_IO1, PE11: P1_IO0 + + # PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V + # PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V + + # Port A: PA07:AF10:V, PA06:AF10:V + mmw 0x48000000 0x0000A000 0x00005000 ;# MODER + mmw 0x48000008 0x0000F000 0x00000000 ;# OSPEEDR + mmw 0x4800000C 0x00000000 0x0000F000 ;# PUPDR + mmw 0x48000020 0xAA000000 0x55000000 ;# AFRL + # Port C: PC03:AF10:V + mmw 0x48000800 0x00000080 0x00000040 ;# MODER + mmw 0x48000808 0x000000C0 0x00000000 ;# OSPEEDR + mmw 0x4800080C 0x00000000 0x000000C0 ;# PUPDR + mmw 0x48000820 0x0000A000 0x00005000 ;# AFRL + # Port D: PD07:AF10:V, PD05:AF10:V, PD04:AF10:V + mmw 0x48000C00 0x00008A00 0x00004500 ;# MODER + mmw 0x48000C08 0x0000CF00 0x00000000 ;# OSPEEDR + mmw 0x48000C0C 0x00000000 0x0000CF00 ;# PUPDR + mmw 0x48000C20 0xA0AA0000 0x50550000 ;# AFRL + # Port E: PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V + mmw 0x48001000 0x0AA00000 0x05500000 ;# MODER + mmw 0x48001008 0x0FF00000 0x00000000 ;# OSPEEDR + mmw 0x4800100C 0x00000000 0x0FF00000 ;# PUPDR + mmw 0x48001024 0x00AAAA00 0x00555500 ;# AFRH + # Port G: PG06:AF03:V + mmw 0x48001800 0x00002000 0x00001000 ;# MODER + mmw 0x48001808 0x00003000 0x00000000 ;# OSPEEDR + mmw 0x4800180C 0x00000000 0x00003000 ;# PUPDR + mmw 0x48001820 0x03000000 0x0C000000 ;# AFRL + + # PG12: P2_NCS, PF04: P2_CLK, PF12: P2_DQS, PG10: P2_IO7, PG09: P2_IO6, PG01: P2_IO5 + # PG00: P2_IO4, PF03: P2_IO3, PF02: P2_IO2, PF01: P2_IO1, PF00: P2_IO0 + + # PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V + # PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V + + # Port F: PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V + mmw 0x48001400 0x020002AA 0x01000155 ;# MODER + mmw 0x48001408 0x030003FF 0x00000000 ;# OSPEEDR + mmw 0x4800140C 0x00000000 0x030003FF ;# PUPDR + mmw 0x48001420 0x00055555 0x000AAAAA ;# AFRL + mmw 0x48001424 0x00050000 0x000A0000 ;# AFRH + # Port G: PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V + mmw 0x48001800 0x0228000A 0x01140005 ;# MODER + mmw 0x48001808 0x033C000F 0x00000000 ;# OSPEEDR + mmw 0x4800180C 0x00000000 0x033C000F ;# PUPDR + mmw 0x48001820 0x00000055 0x000000AA ;# AFRL + mmw 0x48001824 0x00050550 0x000A0AA0 ;# AFRH + + # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses + mww 0xA0001130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 + mww 0xA0001008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 + mww 0xA000100C 0x00000001 ;# OCTOSPI_DCR2: PRESCALER=1 + + mww 0xA0001108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 + mww 0xA0001100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 + mww 0xA0001110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B + + if { $octo == 1 } { + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 ;# Read Status Register + stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable + + # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses + mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 + mww 0xA0001108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 + mww 0xA0001100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 + mww 0xA0001110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read + + flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values + + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 0 0x04 ;# Write Disable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + } +} + +$_TARGETNAME configure -event reset-init { + mmw 0x40022000 0x00000003 0x0000000C ;# 3 WS for 72 MHz HCLK + sleep 1 + mmw 0x40021000 0x00000100 0x00000000 ;# HSI on + mww 0x4002100C 0x01002432 ;# RCC_PLLCFGR 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI + mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 + mmw 0x40021000 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 24000 + + octospi_init 1 +} + diff --git a/tcl/board/stm32l4r9i-disco.cfg b/tcl/board/stm32l4r9i-disco.cfg new file mode 100644 index 0000000000..f364ad3d58 --- /dev/null +++ b/tcl/board/stm32l4r9i-disco.cfg @@ -0,0 +1,102 @@ +# 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 + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 96KB +set WORKAREASIZE 0x18000 + +# enable stmqspi +set OCTOSPI1 1 +set OCTOSPI2 0 + +source [find target/stm32l4x.cfg] + +# OCTOSPI initialization +# octo: 8-line mode +proc octospi_init { octo } { + global a b + mmw 0x4002104C 0x001001FF 0 ;# RCC_AHB2ENR |= OSPIMEN, GPIOAEN-GPIOIEN (enable clocks) + mmw 0x40021050 0x00000300 0 ;# RCC_AHB3ENR |= OSPI2EN, OSPI1EN (enable clocks) + mmw 0x40021058 0x10000000 0 ;# RCC_APB1ENR1 |= PWREN (enable clock) + sleep 1 ;# Wait for clock startup + + mmw 0x40007004 0x00000200 0 ;# PWR_CR2 |= IOSV (required for use of GPOIG, cf. RM0432) + + mww 0x50061C04 0x00000000 ;# OCTOSPIM_P1CR: disable Port 1 + mww 0x50061C08 0x03010111 ;# OCTOSPIM_P2CR: assign Port 2 to OCTOSPI1 + + # PG12: P2_NCS, PI06: P2_CLK, PG15: P2_DQS, PG10: P2_IO7, PG09: P2_IO6, PH10: P2_IO5, + # PH09: P2_IO4, PH08: P2_IO3, PI09: P2_IO2, PI10: P2_IO1, PI11: P2_IO0 + + # PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V + # PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V + + # Port G: PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V + mmw 0x48001800 0x82280000 0x41140000 ;# MODER + mmw 0x48001808 0xC33C0000 0x00000000 ;# OSPEEDR + mmw 0x48001824 0x50050550 0xA00A0AA0 ;# AFRH + + # Port H: PH10:AF05:V, PH09:AF05:V, PH08:AF05:V + mmw 0x48001C00 0x002A0000 0x00150000 ;# MODER + mmw 0x48001C08 0x003F0000 0x00000000 ;# OSPEEDR + mmw 0x48001C24 0x00000555 0x00000AAA ;# AFRH + + # Port I: PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V + mmw 0x48002000 0x00A82000 0x00541000 ;# MODER + mmw 0x48002008 0x00FC3000 0x00000000 ;# OSPEEDR + mmw 0x48002020 0x05000000 0x0A000000 ;# AFRL + mmw 0x48002024 0x00005550 0x0000AAA0 ;# AFRH + + # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses + mww 0xA0001130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 + mww 0xA0001008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 + mww 0xA000100C 0x00000001 ;# OCTOSPI_DCR2: PRESCALER=1 + + mww 0xA0001108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 + mww 0xA0001100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 + mww 0xA0001110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B + + if { $octo == 1 } { + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 ;# Read Status Register + stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable + + # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses + mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 + mww 0xA0001108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 + mww 0xA0001100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 + mww 0xA0001110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read + + flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values + + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 0 0x04 ;# Write Disable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + } +} + +$_TARGETNAME configure -event reset-init { + mmw 0x40022000 0x00000003 0x0000000C ;# 3 WS for 72 MHz HCLK + sleep 1 + mmw 0x40021000 0x00000100 0x00000000 ;# HSI on + mww 0x4002100C 0x01002432 ;# RCC_PLLCFGR 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI + mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 + mmw 0x40021000 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + octospi_init 1 +} 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 new file mode 100644 index 0000000000..6328ddb4c0 --- /dev/null +++ b/tcl/board/stm32mp13x_dk.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# board MB1635x +# http://www.st.com/en/evaluation-tools/stm32mp135f-dk.html + +source [find interface/stlink-dap.cfg] + +transport select dapdirect_swd + +source [find target/stm32mp13x.cfg] + +reset_config srst_only 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_am625evm.cfg b/tcl/board/ti_am625evm.cfg new file mode 100644 index 0000000000..4906fd0967 --- /dev/null +++ b/tcl/board/ti_am625evm.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2021-2022 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments am625 EVM/SK +# Link: https://www.ti.com/lit/zip/sprr448 +# + +# AM625 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 am625 +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 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_am642evm.cfg b/tcl/board/ti_am642evm.cfg new file mode 100644 index 0000000000..e97fdcf138 --- /dev/null +++ b/tcl/board/ti_am642evm.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments AM642 EVM +# + +# AM642 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 am642 +} + +source [find target/ti_k3.cfg] + +adapter speed 250 diff --git a/tcl/board/ti_am654evm.cfg b/tcl/board/ti_am654evm.cfg new file mode 100644 index 0000000000..a661f6068f --- /dev/null +++ b/tcl/board/ti_am654evm.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments AM654 EVM/IDK Base Board +# + +# AM654 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 70 + +if { ![info exists SOC] } { + set SOC am654 +} + +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_j7200evm.cfg b/tcl/board/ti_j7200evm.cfg new file mode 100644 index 0000000000..cc70056fb4 --- /dev/null +++ b/tcl/board/ti_j7200evm.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments J7200 EVM +# + +# J7200 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 j7200 +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 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_j721evm.cfg b/tcl/board/ti_j721evm.cfg new file mode 100644 index 0000000000..d0c4b74965 --- /dev/null +++ b/tcl/board/ti_j721evm.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments J721E EVM +# + +# J721E 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 j721e +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 diff --git a/tcl/board/ti_j721s2evm.cfg b/tcl/board/ti_j721s2evm.cfg new file mode 100644 index 0000000000..72418b57b6 --- /dev/null +++ b/tcl/board/ti_j721s2evm.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments J721s2 EVM +# Link(SoM): https://www.ti.com/lit/zip/sprr439 +# + +# J721s2 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 j721s2 +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 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 87cab26907..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 @@ -12,5 +14,5 @@ reset_config trst_only # xds100v2 config says add this to the end init -ftdi_set_signal PWR_RST 1 +ftdi set_signal PWR_RST 1 jtag arp_init 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 d0951ce646..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 # @@ -10,7 +12,7 @@ adapter speed 10000 # SRST-only reset configuration reset_config srst_only srst_push_pull -source [find tcl/target/hi3798.cfg] +source [find target/hi3798.cfg] # make sure the default target is the boot core targets ${_TARGETNAME}0 @@ -19,7 +21,7 @@ proc core_up { args } { global _TARGETNAME # examine remaining cores - foreach _core [set args] { + foreach _core $args { ${_TARGETNAME}$_core arp_examine } } 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..ca44f0b8ce --- /dev/null +++ b/tcl/board/trion_t20_bga256.cfg @@ -0,0 +1,30 @@ +# 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 create-hub trion.ipdbghub -tap trion.tap -ir 0x8 +#trion.ipdbghub ipdbg start -tool 0 -port 5555 + +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 846bf58f5c..5bf8fd03e7 100644 --- a/tcl/board/tx25_stk5.cfg +++ b/tcl/board/tx25_stk5.cfg @@ -1,10 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # ------------------------------------------------------------------------- # KaRo TX25 CPU Module on a StarterkitV base board # http://www.karo-electronics.com/tx25.html # ------------------------------------------------------------------------- -source [find tcl/target/imx25.cfg] +source [find target/imx25.cfg] #------------------------------------------------------------------------- # Declare Nand 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 227cf42f6b..ba269f5d07 100644 --- a/tcl/board/uptech_2410.cfg +++ b/tcl/board/uptech_2410.cfg @@ -1,5 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Target Configuration for the Uptech 2410 board. -# This configuration hould also work on smdk2410, but I havn't tested it yet. +# This configuration should also work on smdk2410, but I haven't tested it yet. # Author: xionglingfeng@Gmail.com source [find target/samsung_s3c2410.cfg] 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 new file mode 100644 index 0000000000..0c3eebd7a7 --- /dev/null +++ b/tcl/board/vd_a53x2_jtag.cfg @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex A53x2 through JTAG + +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} +set CPUTAPID 0x5ba00477 + +# 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 tbench.u_vd_jtag_bfm 10ns + +# 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 new file mode 100644 index 0000000000..3b32e17be3 --- /dev/null +++ b/tcl/board/vd_m4_jtag.cfg @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex m4 through JTAG + +source [find interface/vdebug.cfg] + +set CHIPNAME m4 +set MEMSTART 0x00000000 +set MEMSIZE 0x10000 +set CPUTAPID 0x4ba00477 + +# vdebug select transport +transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 25000 +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 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 new file mode 100644 index 0000000000..a3f5a84886 --- /dev/null +++ b/tcl/board/vd_pulpissimo_jtag.cfg @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV Ibex core with Pulpissimo through JTAG + +source [find interface/vdebug.cfg] + +set _CHIPNAME ibex +set _HARTID 0x20 +set _CPUTAPID 0x249511c3 + +# vdebug select transport +transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 12500 +adapter srst delay 10 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 40ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[0\].sram_i.mem_array 0x1c000000 0x8000 +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[1\].sram_i.mem_array 0x1c008000 0x8000 +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2\[0\].sram_i.mem_array 0x1c010000 0x80000 + +# need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 +jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x05 -irmask 0x1f -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_riscv.cfg] diff --git a/tcl/board/vd_swerv_jtag.cfg b/tcl/board/vd_swerv_jtag.cfg new file mode 100644 index 0000000000..c5d33f268a --- /dev/null +++ b/tcl/board/vd_swerv_jtag.cfg @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV swerv core with Swerv through JTAG + +source [find interface/vdebug.cfg] + +set _CHIPNAME rv32 +set _HARTID 0x00 +set _CPUTAPID 0x1000008b +set _MEMSTART 0x00000000 +set _MEMSIZE 0x10000 + +# 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 tbench.u_vd_jtag_bfm 10ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.i_ahb_ic.mem $_MEMSTART $_MEMSIZE + +# need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 +jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_riscv.cfg] 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/board/zy1000.cfg b/tcl/board/zy1000.cfg deleted file mode 100644 index e0d1ccf844..0000000000 --- a/tcl/board/zy1000.cfg +++ /dev/null @@ -1,117 +0,0 @@ -#Script for ZY1000 - -#Atmel ties SRST & TRST together, at which point it makes -#no sense to use TRST, but use TMS instead. -# -#The annoying thing with tying SRST & TRST together is that -#there is no way to halt the CPU *before and during* the -#SRST reset, which means that the CPU will run a number -#of cycles before it can be halted(as much as milliseconds). -reset_config srst_only srst_pulls_trst - - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME zy1000 -} - -if { [info exists ENDIAN] } { - set _ENDIAN $ENDIAN -} else { - set _ENDIAN little -} - - -#jtag scan chain -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x1f0f0f0f -} -jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME - -# at CPU CLK <32kHz this must be disabled -arm7_9 fast_memory_access enable -arm7_9 dcc_downloads enable - -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME cfi 0x01000000 0x200000 2 2 $_TARGETNAME - -$_TARGETNAME configure -event reset-init { - # Set up chip selects & timings - mww 0xFFE00000 0x0100273D - mww 0xFFE00004 0x08002125 - mww 0xFFEe0008 0x02002125 - mww 0xFFE0000c 0x03002125 - mww 0xFFE00010 0x40000000 - mww 0xFFE00014 0x50000000 - mww 0xFFE00018 0x60000000 - mww 0xFFE0001c 0x70000000 - mww 0xFFE00020 0x00000001 - mww 0xFFE00024 0x00000000 - - # remap - mww 0xFFFFF124 0xFFFFFFFF - mww 0xffff0010 0x100 - mww 0xffff0034 0x100 - - #disable 16x5x UART interrupts - mww 0x08020004 0 -} - -$_TARGETNAME configure -event gdb-attach { - # Without this gdb-attach will first time as probe will fail - reset init -} - -# required for usable performance. Used for lots of -# other things than flash programming. -$_TARGETNAME configure -work-area-phys 0x00020000 -work-area-size 0x20000 -work-area-backup 0 - -adapter speed 16000 - - -proc production_info {} { - return "Serial number is official MAC number. Format XXXXXXXXXXXX" -} - -# There is no return value from this procedure. If it is -# successful it does not throw an exception -# -# Progress messages are output via puts -proc production {firmwarefile serialnumber} { - if {[string length $serialnumber]!=12} { - echo "Invalid serial number" - return - } - - echo "Power cycling target" - power off - sleep 3000 - power on - sleep 1000 - reset init - flash write_image erase $firmwarefile 0x1000000 bin - verify_image $firmwarefile 0x1000000 bin - - # Big endian... weee!!!! - echo "Setting MAC number to $serialnumber" - flash fillw [expr 0x1030000-0x8] "0x[string range $serialnumber 2 3][string range $serialnumber 0 1]0000" 1 - flash fillw [expr 0x1030000-0x4] "0x[string range $serialnumber 10 11][string range $serialnumber 8 9][string range $serialnumber 6 7][string range $serialnumber 4 5]" 1 - echo "Production successful" -} - - -proc production_test {} { - power on - sleep 1000 - target_request debugmsgs enable - reset run - sleep 25000 - target_request debugmsgs disable - return "See IP address above..." -} diff --git a/tcl/chip/atmel/at91/aic.tcl b/tcl/chip/atmel/at91/aic.tcl index ba0f2a91ba..6657b601af 100644 --- a/tcl/chip/atmel/at91/aic.tcl +++ b/tcl/chip/atmel/at91/aic.tcl @@ -1,38 +1,40 @@ -set AIC_SMR [expr $AT91C_BASE_AIC + 0x00000000 ] +# 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 ] +set AIC_SVR [expr {$AT91C_BASE_AIC + 0x00000080} ] global AIC_SVR -set AIC_IVR [expr $AT91C_BASE_AIC + 0x00000100 ] +set AIC_IVR [expr {$AT91C_BASE_AIC + 0x00000100} ] global AIC_IVR -set AIC_FVR [expr $AT91C_BASE_AIC + 0x00000104 ] +set AIC_FVR [expr {$AT91C_BASE_AIC + 0x00000104} ] global AIC_FVR -set AIC_ISR [expr $AT91C_BASE_AIC + 0x00000108 ] +set AIC_ISR [expr {$AT91C_BASE_AIC + 0x00000108} ] global AIC_ISR -set AIC_IPR [expr $AT91C_BASE_AIC + 0x0000010C ] +set AIC_IPR [expr {$AT91C_BASE_AIC + 0x0000010C} ] global AIC_IPR -set AIC_IMR [expr $AT91C_BASE_AIC + 0x00000110 ] +set AIC_IMR [expr {$AT91C_BASE_AIC + 0x00000110} ] global AIC_IMR -set AIC_CISR [expr $AT91C_BASE_AIC + 0x00000114 ] +set AIC_CISR [expr {$AT91C_BASE_AIC + 0x00000114} ] global AIC_CISR -set AIC_IECR [expr $AT91C_BASE_AIC + 0x00000120 ] +set AIC_IECR [expr {$AT91C_BASE_AIC + 0x00000120} ] global AIC_IECR -set AIC_IDCR [expr $AT91C_BASE_AIC + 0x00000124 ] +set AIC_IDCR [expr {$AT91C_BASE_AIC + 0x00000124} ] global AIC_IDCR -set AIC_ICCR [expr $AT91C_BASE_AIC + 0x00000128 ] +set AIC_ICCR [expr {$AT91C_BASE_AIC + 0x00000128} ] global AIC_ICCR -set AIC_ISCR [expr $AT91C_BASE_AIC + 0x0000012C ] +set AIC_ISCR [expr {$AT91C_BASE_AIC + 0x0000012C} ] global AIC_ISCR -set AIC_EOICR [expr $AT91C_BASE_AIC + 0x00000130 ] +set AIC_EOICR [expr {$AT91C_BASE_AIC + 0x00000130} ] global AIC_EOICR -set AIC_SPU [expr $AT91C_BASE_AIC + 0x00000134 ] +set AIC_SPU [expr {$AT91C_BASE_AIC + 0x00000134} ] global AIC_SPU -set AIC_DCR [expr $AT91C_BASE_AIC + 0x00000138 ] +set AIC_DCR [expr {$AT91C_BASE_AIC + 0x00000138} ] global AIC_DCR -set AIC_FFER [expr $AT91C_BASE_AIC + 0x00000140 ] +set AIC_FFER [expr {$AT91C_BASE_AIC + 0x00000140} ] global AIC_FFER -set AIC_FFDR [expr $AT91C_BASE_AIC + 0x00000144 ] +set AIC_FFDR [expr {$AT91C_BASE_AIC + 0x00000144} ] global AIC_FFDR -set AIC_FFSR [expr $AT91C_BASE_AIC + 0x00000148 ] +set AIC_FFSR [expr {$AT91C_BASE_AIC + 0x00000148} ] global AIC_FFSR @@ -54,36 +56,36 @@ proc show_AIC_IMR_helper { NAME ADDR VAL } { proc show_AIC { } { global AIC_SMR - if [catch { mem2array aaa 32 $AIC_SMR [expr 32 * 4] } msg ] { + if [catch { set aaa [read_memory $AIC_SMR 32 [expr {32 * 4}]] } msg ] { error [format "%s (%s)" $msg AIC_SMR] } echo "AIC_SMR: Mode & Type" global AT91C_ID for { set x 0 } { $x < 32 } { } { echo -n " " - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) $aaa($x)] + echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) [lindex $aaa $x]] incr x } global AIC_SVR - if [catch { mem2array aaa 32 $AIC_SVR [expr 32 * 4] } msg ] { + if [catch { set aaa [read_memory $AIC_SVR 32 [expr {32 * 4}]] } msg ] { error [format "%s (%s)" $msg AIC_SVR] } echo "AIC_SVR: Vectors" for { set x 0 } { $x < 32 } { } { echo -n " " - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) $aaa($x)] + echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) [lindex $aaa $x]] incr x } 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 88b137024a..a75cecd6a1 100644 --- a/tcl/chip/atmel/at91/at91_pmc.cfg +++ b/tcl/chip/atmel/at91/at91_pmc.cfg @@ -1,113 +1,115 @@ -set AT91_PMC_SCER [expr ($AT91_PMC + 0x00)] ;# System Clock Enable Register -set AT91_PMC_SCDR [expr ($AT91_PMC + 0x04)] ;# System Clock Disable Register +# SPDX-License-Identifier: GPL-2.0-or-later -set AT91_PMC_SCSR [expr ($AT91_PMC + 0x08)] ;# System Clock Status Register -set AT91_PMC_PCK [expr (1 << 0)] ;# Processor Clock -set AT91RM9200_PMC_UDP [expr (1 << 1)] ;# USB Devcice Port Clock [AT91RM9200 only] -set AT91RM9200_PMC_MCKUDP [expr (1 << 2)] ;# USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] -set AT91CAP9_PMC_DDR [expr (1 << 2)] ;# DDR Clock [CAP9 revC & some SAM9 only] -set AT91RM9200_PMC_UHP [expr (1 << 4)] ;# USB Host Port Clock [AT91RM9200 only] -set AT91SAM926x_PMC_UHP [expr (1 << 6)] ;# USB Host Port Clock [AT91SAM926x only] -set AT91CAP9_PMC_UHP [expr (1 << 6)] ;# USB Host Port Clock [AT91CAP9 only] -set AT91SAM926x_PMC_UDP [expr (1 << 7)] ;# USB Devcice Port Clock [AT91SAM926x only] -set AT91_PMC_PCK0 [expr (1 << 8)] ;# Programmable Clock 0 -set AT91_PMC_PCK1 [expr (1 << 9)] ;# Programmable Clock 1 -set AT91_PMC_PCK2 [expr (1 << 10)] ;# Programmable Clock 2 -set AT91_PMC_PCK3 [expr (1 << 11)] ;# Programmable Clock 3 -set AT91_PMC_HCK0 [expr (1 << 16)] ;# AHB Clock (USB host) [AT91SAM9261 only] -set AT91_PMC_HCK1 [expr (1 << 17)] ;# AHB Clock (LCD) [AT91SAM9261 only] +set AT91_PMC_SCER [expr {$AT91_PMC + 0x00}] ;# System Clock Enable Register +set AT91_PMC_SCDR [expr {$AT91_PMC + 0x04}] ;# System Clock Disable Register -set AT91_PMC_PCER [expr ($AT91_PMC + 0x10)] ;# Peripheral Clock Enable Register -set AT91_PMC_PCDR [expr ($AT91_PMC + 0x14)] ;# Peripheral Clock Disable Register -set AT91_PMC_PCSR [expr ($AT91_PMC + 0x18)] ;# Peripheral Clock Status Register +set AT91_PMC_SCSR [expr {$AT91_PMC + 0x08}] ;# System Clock Status Register +set AT91_PMC_PCK [expr {1 << 0}] ;# Processor Clock +set AT91RM9200_PMC_UDP [expr {1 << 1}] ;# USB Devcice Port Clock [AT91RM9200 only] +set AT91RM9200_PMC_MCKUDP [expr {1 << 2}] ;# USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] +set AT91CAP9_PMC_DDR [expr {1 << 2}] ;# DDR Clock [CAP9 revC & some SAM9 only] +set AT91RM9200_PMC_UHP [expr {1 << 4}] ;# USB Host Port Clock [AT91RM9200 only] +set AT91SAM926x_PMC_UHP [expr {1 << 6}] ;# USB Host Port Clock [AT91SAM926x only] +set AT91CAP9_PMC_UHP [expr {1 << 6}] ;# USB Host Port Clock [AT91CAP9 only] +set AT91SAM926x_PMC_UDP [expr {1 << 7}] ;# USB Devcice Port Clock [AT91SAM926x only] +set AT91_PMC_PCK0 [expr {1 << 8}] ;# Programmable Clock 0 +set AT91_PMC_PCK1 [expr {1 << 9}] ;# Programmable Clock 1 +set AT91_PMC_PCK2 [expr {1 << 10}] ;# Programmable Clock 2 +set AT91_PMC_PCK3 [expr {1 << 11}] ;# Programmable Clock 3 +set AT91_PMC_HCK0 [expr {1 << 16}] ;# AHB Clock (USB host) [AT91SAM9261 only] +set AT91_PMC_HCK1 [expr {1 << 17}] ;# AHB Clock (LCD) [AT91SAM9261 only] -set AT91_CKGR_UCKR [expr ($AT91_PMC + 0x1C)] ;# UTMI Clock Register [some SAM9, CAP9] -set AT91_PMC_UPLLEN [expr (1 << 16)] ;# UTMI PLL Enable -set AT91_PMC_UPLLCOUNT [expr (0xf << 20)] ;# UTMI PLL Start-up Time -set AT91_PMC_BIASEN [expr (1 << 24)] ;# UTMI BIAS Enable -set AT91_PMC_BIASCOUNT [expr (0xf << 28)] ;# UTMI BIAS Start-up Time +set AT91_PMC_PCER [expr {$AT91_PMC + 0x10}] ;# Peripheral Clock Enable Register +set AT91_PMC_PCDR [expr {$AT91_PMC + 0x14}] ;# Peripheral Clock Disable Register +set AT91_PMC_PCSR [expr {$AT91_PMC + 0x18}] ;# Peripheral Clock Status Register -set AT91_CKGR_MOR [expr ($AT91_PMC + 0x20)] ;# Main Oscillator Register [not on SAM9RL] -set AT91_PMC_MOSCEN [expr (1 << 0)] ;# Main Oscillator Enable -set AT91_PMC_OSCBYPASS [expr (1 << 1)] ;# Oscillator Bypass [SAM9x, CAP9] -set AT91_PMC_OSCOUNT [expr (0xff << 8)] ;# Main Oscillator Start-up Time +set AT91_CKGR_UCKR [expr {$AT91_PMC + 0x1C}] ;# UTMI Clock Register [some SAM9, CAP9] +set AT91_PMC_UPLLEN [expr {1 << 16}] ;# UTMI PLL Enable +set AT91_PMC_UPLLCOUNT [expr {0xf << 20}] ;# UTMI PLL Start-up Time +set AT91_PMC_BIASEN [expr {1 << 24}] ;# UTMI BIAS Enable +set AT91_PMC_BIASCOUNT [expr {0xf << 28}] ;# UTMI BIAS Start-up Time -set AT91_CKGR_MCFR [expr ($AT91_PMC + 0x24)] ;# Main Clock Frequency Register -set AT91_PMC_MAINF [expr (0xffff << 0)] ;# Main Clock Frequency -set AT91_PMC_MAINRDY [expr (1 << 16)] ;# Main Clock Ready +set AT91_CKGR_MOR [expr {$AT91_PMC + 0x20}] ;# Main Oscillator Register [not on SAM9RL] +set AT91_PMC_MOSCEN [expr {1 << 0}] ;# Main Oscillator Enable +set AT91_PMC_OSCBYPASS [expr {1 << 1}] ;# Oscillator Bypass [SAM9x, CAP9] +set AT91_PMC_OSCOUNT [expr {0xff << 8}] ;# Main Oscillator Start-up Time -set AT91_CKGR_PLLAR [expr ($AT91_PMC + 0x28)] ;# PLL A Register -set AT91_CKGR_PLLBR [expr ($AT91_PMC + 0x2c)] ;# PLL B Register -set AT91_PMC_DIV [expr (0xff << 0)] ;# Divider -set AT91_PMC_PLLCOUNT [expr (0x3f << 8)] ;# PLL Counter -set AT91_PMC_OUT [expr (3 << 14)] ;# PLL Clock Frequency Range -set AT91_PMC_MUL [expr (0x7ff << 16)] ;# PLL Multiplier -set AT91_PMC_USBDIV [expr (3 << 28)] ;# USB Divisor (PLLB only) -set AT91_PMC_USBDIV_1 [expr (0 << 28)] -set AT91_PMC_USBDIV_2 [expr (1 << 28)] -set AT91_PMC_USBDIV_4 [expr (2 << 28)] -set AT91_PMC_USB96M [expr (1 << 28)] ;# Divider by 2 Enable (PLLB only) -set AT91_PMC_PLLA_WR_ERRATA [expr (1 << 29)] ;# Bit 29 must always be set to 1 when programming the CKGR_PLLAR register +set AT91_CKGR_MCFR [expr {$AT91_PMC + 0x24}] ;# Main Clock Frequency Register +set AT91_PMC_MAINF [expr {0xffff << 0}] ;# Main Clock Frequency +set AT91_PMC_MAINRDY [expr {1 << 16}] ;# Main Clock Ready -set AT91_PMC_MCKR [expr ($AT91_PMC + 0x30)] ;# Master Clock Register -set AT91_PMC_CSS [expr (3 << 0)] ;# Master Clock Selection -set AT91_PMC_CSS_SLOW [expr (0 << 0)] -set AT91_PMC_CSS_MAIN [expr (1 << 0)] -set AT91_PMC_CSS_PLLA [expr (2 << 0)] -set AT91_PMC_CSS_PLLB [expr (3 << 0)] -set AT91_PMC_CSS_UPLL [expr (3 << 0)] ;# [some SAM9 only] -set AT91_PMC_PRES [expr (7 << 2)] ;# Master Clock Prescaler -set AT91_PMC_PRES_1 [expr (0 << 2)] -set AT91_PMC_PRES_2 [expr (1 << 2)] -set AT91_PMC_PRES_4 [expr (2 << 2)] -set AT91_PMC_PRES_8 [expr (3 << 2)] -set AT91_PMC_PRES_16 [expr (4 << 2)] -set AT91_PMC_PRES_32 [expr (5 << 2)] -set AT91_PMC_PRES_64 [expr (6 << 2)] -set AT91_PMC_MDIV [expr (3 << 8)] ;# Master Clock Division -set AT91RM9200_PMC_MDIV_1 [expr (0 << 8)] ;# [AT91RM9200 only] -set AT91RM9200_PMC_MDIV_2 [expr (1 << 8)] -set AT91RM9200_PMC_MDIV_3 [expr (2 << 8)] -set AT91RM9200_PMC_MDIV_4 [expr (3 << 8)] -set AT91SAM9_PMC_MDIV_1 [expr (0 << 8)] ;# [SAM9,CAP9 only] -set AT91SAM9_PMC_MDIV_2 [expr (1 << 8)] -set AT91SAM9_PMC_MDIV_4 [expr (2 << 8)] -set AT91SAM9_PMC_MDIV_6 [expr (3 << 8)] ;# [some SAM9 only] -set AT91SAM9_PMC_MDIV_3 [expr (3 << 8)] ;# [some SAM9 only] -set AT91_PMC_PDIV [expr (1 << 12)] ;# Processor Clock Division [some SAM9 only] -set AT91_PMC_PDIV_1 [expr (0 << 12)] -set AT91_PMC_PDIV_2 [expr (1 << 12)] -set AT91_PMC_PLLADIV2 [expr (1 << 12)] ;# PLLA divisor by 2 [some SAM9 only] -set AT91_PMC_PLLADIV2_OFF [expr (0 << 12)] -set AT91_PMC_PLLADIV2_ON [expr (1 << 12)] +set AT91_CKGR_PLLAR [expr {$AT91_PMC + 0x28}] ;# PLL A Register +set AT91_CKGR_PLLBR [expr {$AT91_PMC + 0x2c}] ;# PLL B Register +set AT91_PMC_DIV [expr {0xff << 0}] ;# Divider +set AT91_PMC_PLLCOUNT [expr {0x3f << 8}] ;# PLL Counter +set AT91_PMC_OUT [expr {3 << 14}] ;# PLL Clock Frequency Range +set AT91_PMC_MUL [expr {0x7ff << 16}] ;# PLL Multiplier +set AT91_PMC_USBDIV [expr {3 << 28}] ;# USB Divisor (PLLB only) +set AT91_PMC_USBDIV_1 [expr {0 << 28}] +set AT91_PMC_USBDIV_2 [expr {1 << 28}] +set AT91_PMC_USBDIV_4 [expr {2 << 28}] +set AT91_PMC_USB96M [expr {1 << 28}] ;# Divider by 2 Enable (PLLB only) +set AT91_PMC_PLLA_WR_ERRATA [expr {1 << 29}] ;# Bit 29 must always be set to 1 when programming the CKGR_PLLAR register -set AT91_PMC_USB [expr ($AT91_PMC + 0x38)] ;# USB Clock Register [some SAM9 only] -set AT91_PMC_USBS [expr (0x1 << 0)] ;# USB OHCI Input clock selection -set AT91_PMC_USBS_PLLA [expr (0 << 0)] -set AT91_PMC_USBS_UPLL [expr (1 << 0)] -set AT91_PMC_OHCIUSBDIV [expr (0xF << 8)] ;# Divider for USB OHCI Clock +set AT91_PMC_MCKR [expr {$AT91_PMC + 0x30}] ;# Master Clock Register +set AT91_PMC_CSS [expr {3 << 0}] ;# Master Clock Selection +set AT91_PMC_CSS_SLOW [expr {0 << 0}] +set AT91_PMC_CSS_MAIN [expr {1 << 0}] +set AT91_PMC_CSS_PLLA [expr {2 << 0}] +set AT91_PMC_CSS_PLLB [expr {3 << 0}] +set AT91_PMC_CSS_UPLL [expr {3 << 0}] ;# [some SAM9 only] +set AT91_PMC_PRES [expr {7 << 2}] ;# Master Clock Prescaler +set AT91_PMC_PRES_1 [expr {0 << 2}] +set AT91_PMC_PRES_2 [expr {1 << 2}] +set AT91_PMC_PRES_4 [expr {2 << 2}] +set AT91_PMC_PRES_8 [expr {3 << 2}] +set AT91_PMC_PRES_16 [expr {4 << 2}] +set AT91_PMC_PRES_32 [expr {5 << 2}] +set AT91_PMC_PRES_64 [expr {6 << 2}] +set AT91_PMC_MDIV [expr {3 << 8}] ;# Master Clock Division +set AT91RM9200_PMC_MDIV_1 [expr {0 << 8}] ;# [AT91RM9200 only] +set AT91RM9200_PMC_MDIV_2 [expr {1 << 8}] +set AT91RM9200_PMC_MDIV_3 [expr {2 << 8}] +set AT91RM9200_PMC_MDIV_4 [expr {3 << 8}] +set AT91SAM9_PMC_MDIV_1 [expr {0 << 8}] ;# [SAM9,CAP9 only] +set AT91SAM9_PMC_MDIV_2 [expr {1 << 8}] +set AT91SAM9_PMC_MDIV_4 [expr {2 << 8}] +set AT91SAM9_PMC_MDIV_6 [expr {3 << 8}] ;# [some SAM9 only] +set AT91SAM9_PMC_MDIV_3 [expr {3 << 8}] ;# [some SAM9 only] +set AT91_PMC_PDIV [expr {1 << 12}] ;# Processor Clock Division [some SAM9 only] +set AT91_PMC_PDIV_1 [expr {0 << 12}] +set AT91_PMC_PDIV_2 [expr {1 << 12}] +set AT91_PMC_PLLADIV2 [expr {1 << 12}] ;# PLLA divisor by 2 [some SAM9 only] +set AT91_PMC_PLLADIV2_OFF [expr {0 << 12}] +set AT91_PMC_PLLADIV2_ON [expr {1 << 12}] -;# set AT91_PMC_PCKR(n) [expr ($AT91_PMC + 0x40 + ((n) * 4))] ;# Programmable Clock 0-N Registers -set AT91_PMC_CSSMCK [expr (0x1 << 8)] ;# CSS or Master Clock Selection -set AT91_PMC_CSSMCK_CSS [expr (0 << 8)] -set AT91_PMC_CSSMCK_MCK [expr (1 << 8)] +set AT91_PMC_USB [expr {$AT91_PMC + 0x38}] ;# USB Clock Register [some SAM9 only] +set AT91_PMC_USBS [expr {0x1 << 0}] ;# USB OHCI Input clock selection +set AT91_PMC_USBS_PLLA [expr {0 << 0}] +set AT91_PMC_USBS_UPLL [expr {1 << 0}] +set AT91_PMC_OHCIUSBDIV [expr {0xF << 8}] ;# Divider for USB OHCI Clock -set AT91_PMC_IER [expr ($AT91_PMC + 0x60)] ;# Interrupt Enable Register -set AT91_PMC_IDR [expr ($AT91_PMC + 0x64)] ;# Interrupt Disable Register -set AT91_PMC_SR [expr ($AT91_PMC + 0x68)] ;# Status Register -set AT91_PMC_MOSCS [expr (1 << 0)] ;# MOSCS Flag -set AT91_PMC_LOCKA [expr (1 << 1)] ;# PLLA Lock -set AT91_PMC_LOCKB [expr (1 << 2)] ;# PLLB Lock -set AT91_PMC_MCKRDY [expr (1 << 3)] ;# Master Clock -set AT91_PMC_LOCKU [expr (1 << 6)] ;# UPLL Lock [some SAM9, AT91CAP9 only] -set AT91_PMC_OSCSEL [expr (1 << 7)] ;# Slow Clock Oscillator [AT91CAP9 revC only] -set AT91_PMC_PCK0RDY [expr (1 << 8)] ;# Programmable Clock 0 -set AT91_PMC_PCK1RDY [expr (1 << 9)] ;# Programmable Clock 1 -set AT91_PMC_PCK2RDY [expr (1 << 10)] ;# Programmable Clock 2 -set AT91_PMC_PCK3RDY [expr (1 << 11)] ;# Programmable Clock 3 -set AT91_PMC_IMR [expr ($AT91_PMC + 0x6c)] ;# Interrupt Mask Register +;# set AT91_PMC_PCKR(n) [expr {$AT91_PMC + 0x40 + ((n) * 4)}] ;# Programmable Clock 0-N Registers +set AT91_PMC_CSSMCK [expr {0x1 << 8}] ;# CSS or Master Clock Selection +set AT91_PMC_CSSMCK_CSS [expr {0 << 8}] +set AT91_PMC_CSSMCK_MCK [expr {1 << 8}] -set AT91_PMC_PROT [expr ($AT91_PMC + 0xe4)] ;# Protect Register [AT91CAP9 revC only] +set AT91_PMC_IER [expr {$AT91_PMC + 0x60}] ;# Interrupt Enable Register +set AT91_PMC_IDR [expr {$AT91_PMC + 0x64}] ;# Interrupt Disable Register +set AT91_PMC_SR [expr {$AT91_PMC + 0x68}] ;# Status Register +set AT91_PMC_MOSCS [expr {1 << 0}] ;# MOSCS Flag +set AT91_PMC_LOCKA [expr {1 << 1}] ;# PLLA Lock +set AT91_PMC_LOCKB [expr {1 << 2}] ;# PLLB Lock +set AT91_PMC_MCKRDY [expr {1 << 3}] ;# Master Clock +set AT91_PMC_LOCKU [expr {1 << 6}] ;# UPLL Lock [some SAM9, AT91CAP9 only] +set AT91_PMC_OSCSEL [expr {1 << 7}] ;# Slow Clock Oscillator [AT91CAP9 revC only] +set AT91_PMC_PCK0RDY [expr {1 << 8}] ;# Programmable Clock 0 +set AT91_PMC_PCK1RDY [expr {1 << 9}] ;# Programmable Clock 1 +set AT91_PMC_PCK2RDY [expr {1 << 10}] ;# Programmable Clock 2 +set AT91_PMC_PCK3RDY [expr {1 << 11}] ;# Programmable Clock 3 +set AT91_PMC_IMR [expr {$AT91_PMC + 0x6c}] ;# Interrupt Mask Register + +set AT91_PMC_PROT [expr {$AT91_PMC + 0xe4}] ;# Protect Register [AT91CAP9 revC only] set AT91_PMC_PROTKEY 0x504d4301 ;# Activation Code -set AT91_PMC_VER [expr ($AT91_PMC + 0xfc)] ;# PMC Module Version [AT91CAP9 only] +set AT91_PMC_VER [expr {$AT91_PMC + 0xfc}] ;# PMC Module Version [AT91CAP9 only] diff --git a/tcl/chip/atmel/at91/at91_rstc.cfg b/tcl/chip/atmel/at91/at91_rstc.cfg index ed60822278..fd174380a7 100644 --- a/tcl/chip/atmel/at91/at91_rstc.cfg +++ b/tcl/chip/atmel/at91/at91_rstc.cfg @@ -1,21 +1,23 @@ -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 -set AT91_RSTC_EXTRST [expr (1 << 3)] ;# External Reset -set AT91_RSTC_KEY [expr (0xa5 << 24)] ;# KEY Password +# SPDX-License-Identifier: GPL-2.0-or-later -set AT91_RSTC_SR [expr ($AT91_RSTC + 0x04)] ;# Reset Controller Status Register -set AT91_RSTC_URSTS [expr (1 << 0)] ;# User Reset Status -set AT91_RSTC_RSTTYP [expr (7 << 8)] ;# Reset Type -set AT91_RSTC_RSTTYP_GENERAL [expr (0 << 8)] -set AT91_RSTC_RSTTYP_WAKEUP [expr (1 << 8)] -set AT91_RSTC_RSTTYP_WATCHDOG [expr (2 << 8)] -set AT91_RSTC_RSTTYP_SOFTWARE [expr (3 << 8)] -set AT91_RSTC_RSTTYP_USER [expr (4 << 8)] -set AT91_RSTC_NRSTL [expr (1 << 16)] ;# NRST Pin Level -set AT91_RSTC_SRCMP [expr (1 << 17)] ;# Software Reset Command in Progress +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 +set AT91_RSTC_EXTRST [expr {1 << 3}] ;# External Reset +set AT91_RSTC_KEY [expr {0xa5 << 24}] ;# KEY Password -set AT91_RSTC_MR [expr ($AT91_RSTC + 0x08)] ;# Reset Controller Mode Register -set AT91_RSTC_URSTEN [expr (1 << 0)] ;# User Reset Enable -set AT91_RSTC_URSTIEN [expr (1 << 4)] ;# User Reset Interrupt Enable -set AT91_RSTC_ERSTL [expr (0xf << 8)] ;# External Reset Length +set AT91_RSTC_SR [expr {$AT91_RSTC + 0x04}] ;# Reset Controller Status Register +set AT91_RSTC_URSTS [expr {1 << 0}] ;# User Reset Status +set AT91_RSTC_RSTTYP [expr {7 << 8}] ;# Reset Type +set AT91_RSTC_RSTTYP_GENERAL [expr {0 << 8}] +set AT91_RSTC_RSTTYP_WAKEUP [expr {1 << 8}] +set AT91_RSTC_RSTTYP_WATCHDOG [expr {2 << 8}] +set AT91_RSTC_RSTTYP_SOFTWARE [expr {3 << 8}] +set AT91_RSTC_RSTTYP_USER [expr {4 << 8}] +set AT91_RSTC_NRSTL [expr {1 << 16}] ;# NRST Pin Level +set AT91_RSTC_SRCMP [expr {1 << 17}] ;# Software Reset Command in Progress + +set AT91_RSTC_MR [expr {$AT91_RSTC + 0x08}] ;# Reset Controller Mode Register +set AT91_RSTC_URSTEN [expr {1 << 0}] ;# User Reset Enable +set AT91_RSTC_URSTIEN [expr {1 << 4}] ;# User Reset Interrupt Enable +set AT91_RSTC_ERSTL [expr {0xf << 8}] ;# External Reset Length diff --git a/tcl/chip/atmel/at91/at91_wdt.cfg b/tcl/chip/atmel/at91/at91_wdt.cfg index a263cc7f6b..8bba62e16f 100644 --- a/tcl/chip/atmel/at91/at91_wdt.cfg +++ b/tcl/chip/atmel/at91/at91_wdt.cfg @@ -1,17 +1,19 @@ -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 +# SPDX-License-Identifier: GPL-2.0-or-later -set AT91_WDT_MR [expr ($AT91_WDT + 0x04)] ;# Watchdog Mode Register -set AT91_WDT_WDV [expr (0xfff << 0)] ;# Counter Value -set AT91_WDT_WDFIEN [expr (1 << 12)] ;# Fault Interrupt Enable -set AT91_WDT_WDRSTEN [expr (1 << 13)] ;# Reset Processor -set AT91_WDT_WDRPROC [expr (1 << 14)] ;# Timer Restart -set AT91_WDT_WDDIS [expr (1 << 15)] ;# Watchdog Disable -set AT91_WDT_WDD [expr (0xfff << 16)] ;# Delta Value -set AT91_WDT_WDDBGHLT [expr (1 << 28)] ;# Debug Halt -set AT91_WDT_WDIDLEHLT [expr (1 << 29)] ;# Idle Halt +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 -set AT91_WDT_SR [expr ($AT91_WDT + 0x08)] ;# Watchdog Status Register -set AT91_WDT_WDUNF [expr (1 << 0)] ;# Watchdog Underflow -set AT91_WDT_WDERR [expr (1 << 1)] ;# Watchdog Error +set AT91_WDT_MR [expr {$AT91_WDT + 0x04}] ;# Watchdog Mode Register +set AT91_WDT_WDV [expr {0xfff << 0}] ;# Counter Value +set AT91_WDT_WDFIEN [expr {1 << 12}] ;# Fault Interrupt Enable +set AT91_WDT_WDRSTEN [expr {1 << 13}] ;# Reset Processor +set AT91_WDT_WDRPROC [expr {1 << 14}] ;# Timer Restart +set AT91_WDT_WDDIS [expr {1 << 15}] ;# Watchdog Disable +set AT91_WDT_WDD [expr {0xfff << 16}] ;# Delta Value +set AT91_WDT_WDDBGHLT [expr {1 << 28}] ;# Debug Halt +set AT91_WDT_WDIDLEHLT [expr {1 << 29}] ;# Idle Halt + +set AT91_WDT_SR [expr {$AT91_WDT + 0x08}] ;# Watchdog Status Register +set AT91_WDT_WDUNF [expr {1 << 0}] ;# Watchdog Underflow +set AT91_WDT_WDERR [expr {1 << 1}] ;# Watchdog Error 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 dc8de23762..c3656bd41d 100644 --- a/tcl/chip/atmel/at91/at91sam9261_matrix.cfg +++ b/tcl/chip/atmel/at91/at91sam9261_matrix.cfg @@ -1,46 +1,47 @@ +# 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) -set AT91_MATRIX_RCB1 [expr (1 << 1)] ;# Remap Command for AHB Master 1 (ARM926EJ-S Data Master) +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) +set AT91_MATRIX_RCB1 [expr {1 << 1}] ;# Remap Command for AHB Master 1 (ARM926EJ-S Data Master) -set AT91_MATRIX_SCFG0 [expr ($AT91_MATRIX + 0x04)] ;# Slave Configuration Register 0 -set AT91_MATRIX_SCFG1 [expr ($AT91_MATRIX + 0x08)] ;# Slave Configuration Register 1 -set AT91_MATRIX_SCFG2 [expr ($AT91_MATRIX + 0x0C)] ;# Slave Configuration Register 2 -set AT91_MATRIX_SCFG3 [expr ($AT91_MATRIX + 0x10)] ;# Slave Configuration Register 3 -set AT91_MATRIX_SCFG4 [expr ($AT91_MATRIX + 0x14)] ;# Slave Configuration Register 4 -set AT91_MATRIX_SLOT_CYCLE [expr (0xff << 0)] ;# Maximum Number of Allowed Cycles for a Burst -set AT91_MATRIX_DEFMSTR_TYPE [expr (3 << 16)] ;# Default Master Type -set AT91_MATRIX_DEFMSTR_TYPE_NONE [expr (0 << 16)] -set AT91_MATRIX_DEFMSTR_TYPE_LAST [expr (1 << 16)] -set AT91_MATRIX_DEFMSTR_TYPE_FIXED [expr (2 << 16)] -set AT91_MATRIX_FIXED_DEFMSTR [expr (7 << 18)] ;# Fixed Index of Default Master +set AT91_MATRIX_SCFG0 [expr {$AT91_MATRIX + 0x04}] ;# Slave Configuration Register 0 +set AT91_MATRIX_SCFG1 [expr {$AT91_MATRIX + 0x08}] ;# Slave Configuration Register 1 +set AT91_MATRIX_SCFG2 [expr {$AT91_MATRIX + 0x0C}] ;# Slave Configuration Register 2 +set AT91_MATRIX_SCFG3 [expr {$AT91_MATRIX + 0x10}] ;# Slave Configuration Register 3 +set AT91_MATRIX_SCFG4 [expr {$AT91_MATRIX + 0x14}] ;# Slave Configuration Register 4 +set AT91_MATRIX_SLOT_CYCLE [expr {0xff << 0}] ;# Maximum Number of Allowed Cycles for a Burst +set AT91_MATRIX_DEFMSTR_TYPE [expr {3 << 16}] ;# Default Master Type +set AT91_MATRIX_DEFMSTR_TYPE_NONE [expr {0 << 16}] +set AT91_MATRIX_DEFMSTR_TYPE_LAST [expr {1 << 16}] +set AT91_MATRIX_DEFMSTR_TYPE_FIXED [expr {2 << 16}] +set AT91_MATRIX_FIXED_DEFMSTR [expr {7 << 18}] ;# Fixed Index of Default Master -set AT91_MATRIX_TCR [expr ($AT91_MATRIX + 0x24)] ;# TCM Configuration Register -set AT91_MATRIX_ITCM_SIZE [expr (0xf << 0)] ;# Size of ITCM enabled memory block -set AT91_MATRIX_ITCM_0 [expr (0 << 0)] -set AT91_MATRIX_ITCM_16 [expr (5 << 0)] -set AT91_MATRIX_ITCM_32 [expr (6 << 0)] -set AT91_MATRIX_ITCM_64 [expr (7 << 0)] -set AT91_MATRIX_DTCM_SIZE [expr (0xf << 4)] ;# Size of DTCM enabled memory block -set AT91_MATRIX_DTCM_0 [expr (0 << 4)] -set AT91_MATRIX_DTCM_16 [expr (5 << 4)] -set AT91_MATRIX_DTCM_32 [expr (6 << 4)] -set AT91_MATRIX_DTCM_64 [expr (7 << 4)] +set AT91_MATRIX_TCR [expr {$AT91_MATRIX + 0x24}] ;# TCM Configuration Register +set AT91_MATRIX_ITCM_SIZE [expr {0xf << 0}] ;# Size of ITCM enabled memory block +set AT91_MATRIX_ITCM_0 [expr {0 << 0}] +set AT91_MATRIX_ITCM_16 [expr {5 << 0}] +set AT91_MATRIX_ITCM_32 [expr {6 << 0}] +set AT91_MATRIX_ITCM_64 [expr {7 << 0}] +set AT91_MATRIX_DTCM_SIZE [expr {0xf << 4}] ;# Size of DTCM enabled memory block +set AT91_MATRIX_DTCM_0 [expr {0 << 4}] +set AT91_MATRIX_DTCM_16 [expr {5 << 4}] +set AT91_MATRIX_DTCM_32 [expr {6 << 4}] +set AT91_MATRIX_DTCM_64 [expr {7 << 4}] -set AT91_MATRIX_EBICSA [expr ($AT91_MATRIX + 0x30)] ;# EBI Chip Select Assignment Register -set AT91_MATRIX_CS1A [expr (1 << 1)] ;# Chip Select 1 Assignment -set AT91_MATRIX_CS1A_SMC [expr (0 << 1)] -set AT91_MATRIX_CS1A_SDRAMC [expr (1 << 1)] -set AT91_MATRIX_CS3A [expr (1 << 3)] ;# Chip Select 3 Assignment -set AT91_MATRIX_CS3A_SMC [expr (0 << 3)] -set AT91_MATRIX_CS3A_SMC_SMARTMEDIA [expr (1 << 3)] -set AT91_MATRIX_CS4A [expr (1 << 4)] ;# Chip Select 4 Assignment -set AT91_MATRIX_CS4A_SMC [expr (0 << 4)] -set AT91_MATRIX_CS4A_SMC_CF1 [expr (1 << 4)] -set AT91_MATRIX_CS5A [expr (1 << 5)] ;# Chip Select 5 Assignment -set AT91_MATRIX_CS5A_SMC [expr (0 << 5)] -set AT91_MATRIX_CS5A_SMC_CF2 [expr (1 << 5)] -set AT91_MATRIX_DBPUC [expr (1 << 8)] ;# Data Bus Pull-up Configuration +set AT91_MATRIX_EBICSA [expr {$AT91_MATRIX + 0x30}] ;# EBI Chip Select Assignment Register +set AT91_MATRIX_CS1A [expr {1 << 1}] ;# Chip Select 1 Assignment +set AT91_MATRIX_CS1A_SMC [expr {0 << 1}] +set AT91_MATRIX_CS1A_SDRAMC [expr {1 << 1}] +set AT91_MATRIX_CS3A [expr {1 << 3}] ;# Chip Select 3 Assignment +set AT91_MATRIX_CS3A_SMC [expr {0 << 3}] +set AT91_MATRIX_CS3A_SMC_SMARTMEDIA [expr {1 << 3}] +set AT91_MATRIX_CS4A [expr {1 << 4}] ;# Chip Select 4 Assignment +set AT91_MATRIX_CS4A_SMC [expr {0 << 4}] +set AT91_MATRIX_CS4A_SMC_CF1 [expr {1 << 4}] +set AT91_MATRIX_CS5A [expr {1 << 5}] ;# Chip Select 5 Assignment +set AT91_MATRIX_CS5A_SMC [expr {0 << 5}] +set AT91_MATRIX_CS5A_SMC_CF2 [expr {1 << 5}] +set AT91_MATRIX_DBPUC [expr {1 << 8}] ;# Data Bus Pull-up Configuration -set AT91_MATRIX_USBPUCR [expr ($AT91_MATRIX + 0x34)] ;# USB Pad Pull-Up Control Register -set AT91_MATRIX_USBPUCR_PUON [expr (1 << 30)] ;# USB Device PAD Pull-up Enable +set AT91_MATRIX_USBPUCR [expr {$AT91_MATRIX + 0x34}] ;# USB Pad Pull-Up Control Register +set AT91_MATRIX_USBPUCR_PUON [expr {1 << 30}] ;# USB Device PAD Pull-up Enable 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 f287cd9bf2..20a31079a0 100644 --- a/tcl/chip/atmel/at91/at91sam9263_matrix.cfg +++ b/tcl/chip/atmel/at91/at91sam9263_matrix.cfg @@ -1,110 +1,112 @@ -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 -set AT91_MATRIX_MCFG3 [expr ($AT91_MATRIX + 0x0C)] ;# Master Configuration Register 3 -set AT91_MATRIX_MCFG4 [expr ($AT91_MATRIX + 0x10)] ;# Master Configuration Register 4 -set AT91_MATRIX_MCFG5 [expr ($AT91_MATRIX + 0x14)] ;# Master Configuration Register 5 -set AT91_MATRIX_MCFG6 [expr ($AT91_MATRIX + 0x18)] ;# Master Configuration Register 6 -set AT91_MATRIX_MCFG7 [expr ($AT91_MATRIX + 0x1C)] ;# Master Configuration Register 7 -set AT91_MATRIX_MCFG8 [expr ($AT91_MATRIX + 0x20)] ;# Master Configuration Register 8 -set AT91_MATRIX_ULBT [expr (7 << 0)] ;# Undefined Length Burst Type -set AT91_MATRIX_ULBT_INFINITE [expr (0 << 0)] -set AT91_MATRIX_ULBT_SINGLE [expr (1 << 0)] -set AT91_MATRIX_ULBT_FOUR [expr (2 << 0)] -set AT91_MATRIX_ULBT_EIGHT [expr (3 << 0)] -set AT91_MATRIX_ULBT_SIXTEEN [expr (4 << 0)] +# SPDX-License-Identifier: GPL-2.0-or-later -set AT91_MATRIX_SCFG0 [expr ($AT91_MATRIX + 0x40)] ;# Slave Configuration Register 0 -set AT91_MATRIX_SCFG1 [expr ($AT91_MATRIX + 0x44)] ;# Slave Configuration Register 1 -set AT91_MATRIX_SCFG2 [expr ($AT91_MATRIX + 0x48)] ;# Slave Configuration Register 2 -set AT91_MATRIX_SCFG3 [expr ($AT91_MATRIX + 0x4C)] ;# Slave Configuration Register 3 -set AT91_MATRIX_SCFG4 [expr ($AT91_MATRIX + 0x50)] ;# Slave Configuration Register 4 -set AT91_MATRIX_SCFG5 [expr ($AT91_MATRIX + 0x54)] ;# Slave Configuration Register 5 -set AT91_MATRIX_SCFG6 [expr ($AT91_MATRIX + 0x58)] ;# Slave Configuration Register 6 -set AT91_MATRIX_SCFG7 [expr ($AT91_MATRIX + 0x5C)] ;# Slave Configuration Register 7 -set AT91_MATRIX_SLOT_CYCLE [expr (0xff << 0)] ;# Maximum Number of Allowed Cycles for a Burst -set AT91_MATRIX_DEFMSTR_TYPE [expr (3 << 16)] ;# Default Master Type -set AT91_MATRIX_DEFMSTR_TYPE_NONE [expr (0 << 16)] -set AT91_MATRIX_DEFMSTR_TYPE_LAST [expr (1 << 16)] -set AT91_MATRIX_DEFMSTR_TYPE_FIXED [expr (2 << 16)] -set AT91_MATRIX_FIXED_DEFMSTR [expr (0xf << 18)] ;# Fixed Index of Default Master -set AT91_MATRIX_ARBT [expr (3 << 24)] ;# Arbitration Type -set AT91_MATRIX_ARBT_ROUND_ROBIN [expr (0 << 24)] -set AT91_MATRIX_ARBT_FIXED_PRIORITY [expr (1 << 24)] +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 +set AT91_MATRIX_MCFG3 [expr {$AT91_MATRIX + 0x0C}] ;# Master Configuration Register 3 +set AT91_MATRIX_MCFG4 [expr {$AT91_MATRIX + 0x10}] ;# Master Configuration Register 4 +set AT91_MATRIX_MCFG5 [expr {$AT91_MATRIX + 0x14}] ;# Master Configuration Register 5 +set AT91_MATRIX_MCFG6 [expr {$AT91_MATRIX + 0x18}] ;# Master Configuration Register 6 +set AT91_MATRIX_MCFG7 [expr {$AT91_MATRIX + 0x1C}] ;# Master Configuration Register 7 +set AT91_MATRIX_MCFG8 [expr {$AT91_MATRIX + 0x20}] ;# Master Configuration Register 8 +set AT91_MATRIX_ULBT [expr {7 << 0}] ;# Undefined Length Burst Type +set AT91_MATRIX_ULBT_INFINITE [expr {0 << 0}] +set AT91_MATRIX_ULBT_SINGLE [expr {1 << 0}] +set AT91_MATRIX_ULBT_FOUR [expr {2 << 0}] +set AT91_MATRIX_ULBT_EIGHT [expr {3 << 0}] +set AT91_MATRIX_ULBT_SIXTEEN [expr {4 << 0}] -set AT91_MATRIX_PRAS0 [expr ($AT91_MATRIX + 0x80)] ;# Priority Register A for Slave 0 -set AT91_MATRIX_PRBS0 [expr ($AT91_MATRIX + 0x84)] ;# Priority Register B for Slave 0 -set AT91_MATRIX_PRAS1 [expr ($AT91_MATRIX + 0x88)] ;# Priority Register A for Slave 1 -set AT91_MATRIX_PRBS1 [expr ($AT91_MATRIX + 0x8C)] ;# Priority Register B for Slave 1 -set AT91_MATRIX_PRAS2 [expr ($AT91_MATRIX + 0x90)] ;# Priority Register A for Slave 2 -set AT91_MATRIX_PRBS2 [expr ($AT91_MATRIX + 0x94)] ;# Priority Register B for Slave 2 -set AT91_MATRIX_PRAS3 [expr ($AT91_MATRIX + 0x98)] ;# Priority Register A for Slave 3 -set AT91_MATRIX_PRBS3 [expr ($AT91_MATRIX + 0x9C)] ;# Priority Register B for Slave 3 -set AT91_MATRIX_PRAS4 [expr ($AT91_MATRIX + 0xA0)] ;# Priority Register A for Slave 4 -set AT91_MATRIX_PRBS4 [expr ($AT91_MATRIX + 0xA4)] ;# Priority Register B for Slave 4 -set AT91_MATRIX_PRAS5 [expr ($AT91_MATRIX + 0xA8)] ;# Priority Register A for Slave 5 -set AT91_MATRIX_PRBS5 [expr ($AT91_MATRIX + 0xAC)] ;# Priority Register B for Slave 5 -set AT91_MATRIX_PRAS6 [expr ($AT91_MATRIX + 0xB0)] ;# Priority Register A for Slave 6 -set AT91_MATRIX_PRBS6 [expr ($AT91_MATRIX + 0xB4)] ;# Priority Register B for Slave 6 -set AT91_MATRIX_PRAS7 [expr ($AT91_MATRIX + 0xB8)] ;# Priority Register A for Slave 7 -set AT91_MATRIX_PRBS7 [expr ($AT91_MATRIX + 0xBC)] ;# Priority Register B for Slave 7 -set AT91_MATRIX_M0PR [expr (3 << 0)] ;# Master 0 Priority -set AT91_MATRIX_M1PR [expr (3 << 4)] ;# Master 1 Priority -set AT91_MATRIX_M2PR [expr (3 << 8)] ;# Master 2 Priority -set AT91_MATRIX_M3PR [expr (3 << 12)] ;# Master 3 Priority -set AT91_MATRIX_M4PR [expr (3 << 16)] ;# Master 4 Priority -set AT91_MATRIX_M5PR [expr (3 << 20)] ;# Master 5 Priority -set AT91_MATRIX_M6PR [expr (3 << 24)] ;# Master 6 Priority -set AT91_MATRIX_M7PR [expr (3 << 28)] ;# Master 7 Priority -set AT91_MATRIX_M8PR [expr (3 << 0)] ;# Master 8 Priority (in Register B) +set AT91_MATRIX_SCFG0 [expr {$AT91_MATRIX + 0x40}] ;# Slave Configuration Register 0 +set AT91_MATRIX_SCFG1 [expr {$AT91_MATRIX + 0x44}] ;# Slave Configuration Register 1 +set AT91_MATRIX_SCFG2 [expr {$AT91_MATRIX + 0x48}] ;# Slave Configuration Register 2 +set AT91_MATRIX_SCFG3 [expr {$AT91_MATRIX + 0x4C}] ;# Slave Configuration Register 3 +set AT91_MATRIX_SCFG4 [expr {$AT91_MATRIX + 0x50}] ;# Slave Configuration Register 4 +set AT91_MATRIX_SCFG5 [expr {$AT91_MATRIX + 0x54}] ;# Slave Configuration Register 5 +set AT91_MATRIX_SCFG6 [expr {$AT91_MATRIX + 0x58}] ;# Slave Configuration Register 6 +set AT91_MATRIX_SCFG7 [expr {$AT91_MATRIX + 0x5C}] ;# Slave Configuration Register 7 +set AT91_MATRIX_SLOT_CYCLE [expr {0xff << 0}] ;# Maximum Number of Allowed Cycles for a Burst +set AT91_MATRIX_DEFMSTR_TYPE [expr {3 << 16}] ;# Default Master Type +set AT91_MATRIX_DEFMSTR_TYPE_NONE [expr {0 << 16}] +set AT91_MATRIX_DEFMSTR_TYPE_LAST [expr {1 << 16}] +set AT91_MATRIX_DEFMSTR_TYPE_FIXED [expr {2 << 16}] +set AT91_MATRIX_FIXED_DEFMSTR [expr {0xf << 18}] ;# Fixed Index of Default Master +set AT91_MATRIX_ARBT [expr {3 << 24}] ;# Arbitration Type +set AT91_MATRIX_ARBT_ROUND_ROBIN [expr {0 << 24}] +set AT91_MATRIX_ARBT_FIXED_PRIORITY [expr {1 << 24}] -set AT91_MATRIX_MRCR [expr ($AT91_MATRIX + 0x100)] ;# Master Remap Control Register -set AT91_MATRIX_RCB0 [expr (1 << 0)] ;# Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) -set AT91_MATRIX_RCB1 [expr (1 << 1)] ;# Remap Command for AHB Master 1 (ARM926EJ-S Data Master) -set AT91_MATRIX_RCB2 [expr (1 << 2)] -set AT91_MATRIX_RCB3 [expr (1 << 3)] -set AT91_MATRIX_RCB4 [expr (1 << 4)] -set AT91_MATRIX_RCB5 [expr (1 << 5)] -set AT91_MATRIX_RCB6 [expr (1 << 6)] -set AT91_MATRIX_RCB7 [expr (1 << 7)] -set AT91_MATRIX_RCB8 [expr (1 << 8)] +set AT91_MATRIX_PRAS0 [expr {$AT91_MATRIX + 0x80}] ;# Priority Register A for Slave 0 +set AT91_MATRIX_PRBS0 [expr {$AT91_MATRIX + 0x84}] ;# Priority Register B for Slave 0 +set AT91_MATRIX_PRAS1 [expr {$AT91_MATRIX + 0x88}] ;# Priority Register A for Slave 1 +set AT91_MATRIX_PRBS1 [expr {$AT91_MATRIX + 0x8C}] ;# Priority Register B for Slave 1 +set AT91_MATRIX_PRAS2 [expr {$AT91_MATRIX + 0x90}] ;# Priority Register A for Slave 2 +set AT91_MATRIX_PRBS2 [expr {$AT91_MATRIX + 0x94}] ;# Priority Register B for Slave 2 +set AT91_MATRIX_PRAS3 [expr {$AT91_MATRIX + 0x98}] ;# Priority Register A for Slave 3 +set AT91_MATRIX_PRBS3 [expr {$AT91_MATRIX + 0x9C}] ;# Priority Register B for Slave 3 +set AT91_MATRIX_PRAS4 [expr {$AT91_MATRIX + 0xA0}] ;# Priority Register A for Slave 4 +set AT91_MATRIX_PRBS4 [expr {$AT91_MATRIX + 0xA4}] ;# Priority Register B for Slave 4 +set AT91_MATRIX_PRAS5 [expr {$AT91_MATRIX + 0xA8}] ;# Priority Register A for Slave 5 +set AT91_MATRIX_PRBS5 [expr {$AT91_MATRIX + 0xAC}] ;# Priority Register B for Slave 5 +set AT91_MATRIX_PRAS6 [expr {$AT91_MATRIX + 0xB0}] ;# Priority Register A for Slave 6 +set AT91_MATRIX_PRBS6 [expr {$AT91_MATRIX + 0xB4}] ;# Priority Register B for Slave 6 +set AT91_MATRIX_PRAS7 [expr {$AT91_MATRIX + 0xB8}] ;# Priority Register A for Slave 7 +set AT91_MATRIX_PRBS7 [expr {$AT91_MATRIX + 0xBC}] ;# Priority Register B for Slave 7 +set AT91_MATRIX_M0PR [expr {3 << 0}] ;# Master 0 Priority +set AT91_MATRIX_M1PR [expr {3 << 4}] ;# Master 1 Priority +set AT91_MATRIX_M2PR [expr {3 << 8}] ;# Master 2 Priority +set AT91_MATRIX_M3PR [expr {3 << 12}] ;# Master 3 Priority +set AT91_MATRIX_M4PR [expr {3 << 16}] ;# Master 4 Priority +set AT91_MATRIX_M5PR [expr {3 << 20}] ;# Master 5 Priority +set AT91_MATRIX_M6PR [expr {3 << 24}] ;# Master 6 Priority +set AT91_MATRIX_M7PR [expr {3 << 28}] ;# Master 7 Priority +set AT91_MATRIX_M8PR [expr {3 << 0}] ;# Master 8 Priority (in Register B) -set AT91_MATRIX_TCMR [expr ($AT91_MATRIX + 0x114)] ;# TCM Configuration Register -set AT91_MATRIX_ITCM_SIZE [expr (0xf << 0)] ;# Size of ITCM enabled memory block -set AT91_MATRIX_ITCM_0 [expr (0 << 0)] -set AT91_MATRIX_ITCM_16 [expr (5 << 0)] -set AT91_MATRIX_ITCM_32 [expr (6 << 0)] -set AT91_MATRIX_DTCM_SIZE [expr (0xf << 4)] ;# Size of DTCM enabled memory block -set AT91_MATRIX_DTCM_0 [expr (0 << 4)] -set AT91_MATRIX_DTCM_16 [expr (5 << 4)] -set AT91_MATRIX_DTCM_32 [expr (6 << 4)] +set AT91_MATRIX_MRCR [expr {$AT91_MATRIX + 0x100}] ;# Master Remap Control Register +set AT91_MATRIX_RCB0 [expr {1 << 0}] ;# Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) +set AT91_MATRIX_RCB1 [expr {1 << 1}] ;# Remap Command for AHB Master 1 (ARM926EJ-S Data Master) +set AT91_MATRIX_RCB2 [expr {1 << 2}] +set AT91_MATRIX_RCB3 [expr {1 << 3}] +set AT91_MATRIX_RCB4 [expr {1 << 4}] +set AT91_MATRIX_RCB5 [expr {1 << 5}] +set AT91_MATRIX_RCB6 [expr {1 << 6}] +set AT91_MATRIX_RCB7 [expr {1 << 7}] +set AT91_MATRIX_RCB8 [expr {1 << 8}] -set AT91_MATRIX_EBI0CSA [expr ($AT91_MATRIX + 0x120)] ;# EBI0 Chip Select Assignment Register -set AT91_MATRIX_EBI0_CS1A [expr (1 << 1)] ;# Chip Select 1 Assignment -set AT91_MATRIX_EBI0_CS1A_SMC [expr (0 << 1)] -set AT91_MATRIX_EBI0_CS1A_SDRAMC [expr (1 << 1)] -set AT91_MATRIX_EBI0_CS3A [expr (1 << 3)] ;# Chip Select 3 Assignmen -set AT91_MATRIX_EBI0_CS3A_SMC [expr (0 << 3)] -set AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA [expr (1 << 3)] -set AT91_MATRIX_EBI0_CS4A [expr (1 << 4)] ;# Chip Select 4 Assignment -set AT91_MATRIX_EBI0_CS4A_SMC [expr (0 << 4)] -set AT91_MATRIX_EBI0_CS4A_SMC_CF1 [expr (1 << 4)] -set AT91_MATRIX_EBI0_CS5A [expr (1 << 5)] ;# Chip Select 5 Assignment -set AT91_MATRIX_EBI0_CS5A_SMC [expr (0 << 5)] -set AT91_MATRIX_EBI0_CS5A_SMC_CF2 [expr (1 << 5)] -set AT91_MATRIX_EBI0_DBPUC [expr (1 << 8)] ;# Data Bus Pull-up Configuration -set AT91_MATRIX_EBI0_VDDIOMSEL [expr (1 << 16)] ;# Memory voltage selection -set AT91_MATRIX_EBI0_VDDIOMSEL_1_8V [expr (0 << 16)] -set AT91_MATRIX_EBI0_VDDIOMSEL_3_3V [expr (1 << 16)] +set AT91_MATRIX_TCMR [expr {$AT91_MATRIX + 0x114}] ;# TCM Configuration Register +set AT91_MATRIX_ITCM_SIZE [expr {0xf << 0}] ;# Size of ITCM enabled memory block +set AT91_MATRIX_ITCM_0 [expr {0 << 0}] +set AT91_MATRIX_ITCM_16 [expr {5 << 0}] +set AT91_MATRIX_ITCM_32 [expr {6 << 0}] +set AT91_MATRIX_DTCM_SIZE [expr {0xf << 4}] ;# Size of DTCM enabled memory block +set AT91_MATRIX_DTCM_0 [expr {0 << 4}] +set AT91_MATRIX_DTCM_16 [expr {5 << 4}] +set AT91_MATRIX_DTCM_32 [expr {6 << 4}] -set AT91_MATRIX_EBI1CSA [expr ($AT91_MATRIX + 0x124)] ;# EBI1 Chip Select Assignment Register -set AT91_MATRIX_EBI1_CS1A [expr (1 << 1)] ;# Chip Select 1 Assignment -set AT91_MATRIX_EBI1_CS1A_SMC [expr (0 << 1)] -set AT91_MATRIX_EBI1_CS1A_SDRAMC [expr (1 << 1)] -set AT91_MATRIX_EBI1_CS2A [expr (1 << 3)] ;# Chip Select 3 Assignment -set AT91_MATRIX_EBI1_CS2A_SMC [expr (0 << 3)] -set AT91_MATRIX_EBI1_CS2A_SMC_SMARTMEDIA [expr (1 << 3)] -set AT91_MATRIX_EBI1_DBPUC [expr (1 << 8)] ;# Data Bus Pull-up Configuration -set AT91_MATRIX_EBI1_VDDIOMSEL [expr (1 << 16)] ;# Memory voltage selection -set AT91_MATRIX_EBI1_VDDIOMSEL_1_8V [expr (0 << 16)] -set AT91_MATRIX_EBI1_VDDIOMSEL_3_3V [expr (1 << 16)] +set AT91_MATRIX_EBI0CSA [expr {$AT91_MATRIX + 0x120}] ;# EBI0 Chip Select Assignment Register +set AT91_MATRIX_EBI0_CS1A [expr {1 << 1}] ;# Chip Select 1 Assignment +set AT91_MATRIX_EBI0_CS1A_SMC [expr {0 << 1}] +set AT91_MATRIX_EBI0_CS1A_SDRAMC [expr {1 << 1}] +set AT91_MATRIX_EBI0_CS3A [expr {1 << 3}] ;# Chip Select 3 Assignmen +set AT91_MATRIX_EBI0_CS3A_SMC [expr {0 << 3}] +set AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA [expr {1 << 3}] +set AT91_MATRIX_EBI0_CS4A [expr {1 << 4}] ;# Chip Select 4 Assignment +set AT91_MATRIX_EBI0_CS4A_SMC [expr {0 << 4}] +set AT91_MATRIX_EBI0_CS4A_SMC_CF1 [expr {1 << 4}] +set AT91_MATRIX_EBI0_CS5A [expr {1 << 5}] ;# Chip Select 5 Assignment +set AT91_MATRIX_EBI0_CS5A_SMC [expr {0 << 5}] +set AT91_MATRIX_EBI0_CS5A_SMC_CF2 [expr {1 << 5}] +set AT91_MATRIX_EBI0_DBPUC [expr {1 << 8}] ;# Data Bus Pull-up Configuration +set AT91_MATRIX_EBI0_VDDIOMSEL [expr {1 << 16}] ;# Memory voltage selection +set AT91_MATRIX_EBI0_VDDIOMSEL_1_8V [expr {0 << 16}] +set AT91_MATRIX_EBI0_VDDIOMSEL_3_3V [expr {1 << 16}] + +set AT91_MATRIX_EBI1CSA [expr {$AT91_MATRIX + 0x124}] ;# EBI1 Chip Select Assignment Register +set AT91_MATRIX_EBI1_CS1A [expr {1 << 1}] ;# Chip Select 1 Assignment +set AT91_MATRIX_EBI1_CS1A_SMC [expr {0 << 1}] +set AT91_MATRIX_EBI1_CS1A_SDRAMC [expr {1 << 1}] +set AT91_MATRIX_EBI1_CS2A [expr {1 << 3}] ;# Chip Select 3 Assignment +set AT91_MATRIX_EBI1_CS2A_SMC [expr {0 << 3}] +set AT91_MATRIX_EBI1_CS2A_SMC_SMARTMEDIA [expr {1 << 3}] +set AT91_MATRIX_EBI1_DBPUC [expr {1 << 8}] ;# Data Bus Pull-up Configuration +set AT91_MATRIX_EBI1_VDDIOMSEL [expr {1 << 16}] ;# Memory voltage selection +set AT91_MATRIX_EBI1_VDDIOMSEL_1_8V [expr {0 << 16}] +set AT91_MATRIX_EBI1_VDDIOMSEL_3_3V [expr {1 << 16}] diff --git a/tcl/chip/atmel/at91/at91sam9_init.cfg b/tcl/chip/atmel/at91/at91sam9_init.cfg index 2d78d241db..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]] @@ -11,9 +13,9 @@ proc at91sam9_reset_start { } { jtag_rclk 8 halt wait_halt 10000 - set rstc_mr_val [expr $::AT91_RSTC_KEY] - set rstc_mr_val [expr ($rstc_mr_val | (5 << 8))] - set rstc_mr_val [expr ($rstc_mr_val | $::AT91_RSTC_URSTEN)] + set rstc_mr_val $::AT91_RSTC_KEY + set rstc_mr_val [expr {$rstc_mr_val | (5 << 8)}] + set rstc_mr_val [expr {$rstc_mr_val | $::AT91_RSTC_URSTEN}] mww $::AT91_RSTC_MR $rstc_mr_val ;# RSTC_MR : enable user reset. } @@ -21,28 +23,28 @@ proc at91sam9_reset_init { config } { mww $::AT91_WDT_MR $config(wdt_mr_val) ;# disable watchdog - set ckgr_mor [expr ($::AT91_PMC_MOSCEN | (255 << 8))] + set ckgr_mor [expr {$::AT91_PMC_MOSCEN | (255 << 8)}] mww $::AT91_CKGR_MOR $ckgr_mor ;# CKGR_MOR - enable main osc. - while { [expr [mrw $::AT91_PMC_SR] & $::AT91_PMC_MOSCS] != $::AT91_PMC_MOSCS } { sleep 1 } + while { [expr {[mrw $::AT91_PMC_SR] & $::AT91_PMC_MOSCS}] != $::AT91_PMC_MOSCS } { sleep 1 } - set pllar_val [expr $::AT91_PMC_PLLA_WR_ERRATA] ;# Bit 29 must be 1 when prog - set pllar_val [expr ($pllar_val | $::AT91_PMC_OUT)] - set pllar_val [expr ($pllar_val | $::AT91_PMC_PLLCOUNT)] - set pllar_val [expr ($pllar_val | ($config(master_pll_mul) - 1) << 16)] - set pllar_val [expr ($pllar_val | $config(master_pll_div))] + set pllar_val $::AT91_PMC_PLLA_WR_ERRATA ;# Bit 29 must be 1 when prog + set pllar_val [expr {$pllar_val | $::AT91_PMC_OUT}] + set pllar_val [expr {$pllar_val | $::AT91_PMC_PLLCOUNT}] + set pllar_val [expr {$pllar_val | ($config(master_pll_mul) - 1) << 16}] + set pllar_val [expr {$pllar_val | $config(master_pll_div)}] mww $::AT91_CKGR_PLLAR $pllar_val ;# CKGR_PLLA - (18.432MHz/13)*141 = 199.9 MHz - while { [expr [mrw $::AT91_PMC_SR] & $::AT91_PMC_LOCKA] != $::AT91_PMC_LOCKA } { sleep 1 } + while { [expr {[mrw $::AT91_PMC_SR] & $::AT91_PMC_LOCKA}] != $::AT91_PMC_LOCKA } { sleep 1 } ;# PCK/2 = MCK Master Clock from PLLA - set mckr_val [expr $::AT91_PMC_CSS_PLLA] - set mckr_val [expr ($mckr_val | $::AT91_PMC_PRES_1)] - set mckr_val [expr ($mckr_val | $::AT91SAM9_PMC_MDIV_2)] - set mckr_val [expr ($mckr_val | $::AT91_PMC_PDIV_1)] + set mckr_val $::AT91_PMC_CSS_PLLA + set mckr_val [expr {$mckr_val | $::AT91_PMC_PRES_1}] + set mckr_val [expr {$mckr_val | $::AT91SAM9_PMC_MDIV_2}] + set mckr_val [expr {$mckr_val | $::AT91_PMC_PDIV_1}] mww $::AT91_PMC_MCKR $mckr_val ;# PMC_MCKR (MCLK: 0x102 - (CLK/2)MHZ, 0x202 - (CLK/3)MHz) - while { [expr [mrw $::AT91_PMC_SR] & $::AT91_PMC_MCKRDY] != $::AT91_PMC_MCKRDY } { sleep 1 } + while { [expr {[mrw $::AT91_PMC_SR] & $::AT91_PMC_MCKRDY}] != $::AT91_PMC_MCKRDY } { sleep 1 } ## switch JTAG clock to highspeed clock jtag_rclk 0 @@ -50,20 +52,20 @@ proc at91sam9_reset_init { config } { arm7_9 dcc_downloads enable ;# Enable faster DCC downloads arm7_9 fast_memory_access enable - set rstc_mr_val [expr ($::AT91_RSTC_KEY)] - set rstc_mr_val [expr ($rstc_mr_val | $::AT91_RSTC_URSTEN)] + set rstc_mr_val $::AT91_RSTC_KEY + set rstc_mr_val [expr {$rstc_mr_val | $::AT91_RSTC_URSTEN}] mww $::AT91_RSTC_MR $rstc_mr_val ;# user reset enable if { [info exists config(sdram_piod)] } { - set pdr_addr [expr ($::AT91_PIOD + $::PIO_PDR)] - set pudr_addr [expr ($::AT91_PIOD + $::PIO_PUDR)] - set asr_addr [expr ($::AT91_PIOD + $::PIO_ASR)] + set pdr_addr [expr {$::AT91_PIOD + $::PIO_PDR}] + set pudr_addr [expr {$::AT91_PIOD + $::PIO_PUDR}] + set asr_addr [expr {$::AT91_PIOD + $::PIO_ASR}] mww $pdr_addr 0xffff0000 ;# define PDC[31:16] as DATA[31:16] mww $pudr_addr 0xffff0000 ;# no pull-up for D[31:16] mww $asr_addr 0xffff0000 } else { - set pdr_addr [expr ($::AT91_PIOC + $::PIO_PDR)] - set pudr_addr [expr ($::AT91_PIOC + $::PIO_PUDR)] + set pdr_addr [expr {$::AT91_PIOC + $::PIO_PDR}] + set pudr_addr [expr {$::AT91_PIOC + $::PIO_PUDR}] mww $pdr_addr 0xffff0000 ;# define PDC[31:16] as DATA[31:16] mww $pudr_addr 0xffff0000 ;# no pull-up for D[31:16] } diff --git a/tcl/chip/atmel/at91/at91sam9_sdramc.cfg b/tcl/chip/atmel/at91/at91sam9_sdramc.cfg index dbca497b28..658b6c361a 100644 --- a/tcl/chip/atmel/at91/at91sam9_sdramc.cfg +++ b/tcl/chip/atmel/at91/at91sam9_sdramc.cfg @@ -1,7 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later # SDRAM Controller (SDRAMC) registers -set AT91_SDRAMC_MR [expr ($AT91_SDRAMC + 0x00)] ;# SDRAM Controller Mode Register -set AT91_SDRAMC_MODE [expr (0xf << 0)] ;# Command Mode +set AT91_SDRAMC_MR [expr {$AT91_SDRAMC + 0x00}] ;# SDRAM Controller Mode Register +set AT91_SDRAMC_MODE [expr {0xf << 0}] ;# Command Mode set AT91_SDRAMC_MODE_NORMAL 0 set AT91_SDRAMC_MODE_NOP 1 set AT91_SDRAMC_MODE_PRECHARGE 2 @@ -10,57 +11,57 @@ set AT91_SDRAMC_MODE_REFRESH 4 set AT91_SDRAMC_MODE_EXT_LMR 5 set AT91_SDRAMC_MODE_DEEP 6 -set AT91_SDRAMC_TR [expr ($AT91_SDRAMC + 0x04)] ;# SDRAM Controller Refresh Timer Register -set AT91_SDRAMC_COUNT [expr (0xfff << 0)] ;# Refresh Timer Counter +set AT91_SDRAMC_TR [expr {$AT91_SDRAMC + 0x04}] ;# SDRAM Controller Refresh Timer Register +set AT91_SDRAMC_COUNT [expr {0xfff << 0}] ;# Refresh Timer Counter -set AT91_SDRAMC_CR [expr ($AT91_SDRAMC + 0x08)] ;# SDRAM Controller Configuration Register -set AT91_SDRAMC_NC [expr (3 << 0)] ;# Number of Column Bits -set AT91_SDRAMC_NC_8 [expr (0 << 0)] -set AT91_SDRAMC_NC_9 [expr (1 << 0)] -set AT91_SDRAMC_NC_10 [expr (2 << 0)] -set AT91_SDRAMC_NC_11 [expr (3 << 0)] -set AT91_SDRAMC_NR [expr (3 << 2)] ;# Number of Row Bits -set AT91_SDRAMC_NR_11 [expr (0 << 2)] -set AT91_SDRAMC_NR_12 [expr (1 << 2)] -set AT91_SDRAMC_NR_13 [expr (2 << 2)] -set AT91_SDRAMC_NB [expr (1 << 4)] ;# Number of Banks -set AT91_SDRAMC_NB_2 [expr (0 << 4)] -set AT91_SDRAMC_NB_4 [expr (1 << 4)] -set AT91_SDRAMC_CAS [expr (3 << 5)] ;# CAS Latency -set AT91_SDRAMC_CAS_1 [expr (1 << 5)] -set AT91_SDRAMC_CAS_2 [expr (2 << 5)] -set AT91_SDRAMC_CAS_3 [expr (3 << 5)] -set AT91_SDRAMC_DBW [expr (1 << 7)] ;# Data Bus Width -set AT91_SDRAMC_DBW_32 [expr (0 << 7)] -set AT91_SDRAMC_DBW_16 [expr (1 << 7)] -set AT91_SDRAMC_TWR [expr (0xf << 8)] ;# Write Recovery Delay -set AT91_SDRAMC_TRC [expr (0xf << 12)] ;# Row Cycle Delay -set AT91_SDRAMC_TRP [expr (0xf << 16)] ;# Row Precharge Delay -set AT91_SDRAMC_TRCD [expr (0xf << 20)] ;# Row to Column Delay -set AT91_SDRAMC_TRAS [expr (0xf << 24)] ;# Active to Precharge Delay -set AT91_SDRAMC_TXSR [expr (0xf << 28)] ;# Exit Self Refresh to Active Delay +set AT91_SDRAMC_CR [expr {$AT91_SDRAMC + 0x08}] ;# SDRAM Controller Configuration Register +set AT91_SDRAMC_NC [expr {3 << 0}] ;# Number of Column Bits +set AT91_SDRAMC_NC_8 [expr {0 << 0}] +set AT91_SDRAMC_NC_9 [expr {1 << 0}] +set AT91_SDRAMC_NC_10 [expr {2 << 0}] +set AT91_SDRAMC_NC_11 [expr {3 << 0}] +set AT91_SDRAMC_NR [expr {3 << 2}] ;# Number of Row Bits +set AT91_SDRAMC_NR_11 [expr {0 << 2}] +set AT91_SDRAMC_NR_12 [expr {1 << 2}] +set AT91_SDRAMC_NR_13 [expr {2 << 2}] +set AT91_SDRAMC_NB [expr {1 << 4}] ;# Number of Banks +set AT91_SDRAMC_NB_2 [expr {0 << 4}] +set AT91_SDRAMC_NB_4 [expr {1 << 4}] +set AT91_SDRAMC_CAS [expr {3 << 5}] ;# CAS Latency +set AT91_SDRAMC_CAS_1 [expr {1 << 5}] +set AT91_SDRAMC_CAS_2 [expr {2 << 5}] +set AT91_SDRAMC_CAS_3 [expr {3 << 5}] +set AT91_SDRAMC_DBW [expr {1 << 7}] ;# Data Bus Width +set AT91_SDRAMC_DBW_32 [expr {0 << 7}] +set AT91_SDRAMC_DBW_16 [expr {1 << 7}] +set AT91_SDRAMC_TWR [expr {0xf << 8}] ;# Write Recovery Delay +set AT91_SDRAMC_TRC [expr {0xf << 12}] ;# Row Cycle Delay +set AT91_SDRAMC_TRP [expr {0xf << 16}] ;# Row Precharge Delay +set AT91_SDRAMC_TRCD [expr {0xf << 20}] ;# Row to Column Delay +set AT91_SDRAMC_TRAS [expr {0xf << 24}] ;# Active to Precharge Delay +set AT91_SDRAMC_TXSR [expr {0xf << 28}] ;# Exit Self Refresh to Active Delay -set AT91_SDRAMC_LPR [expr ($AT91_SDRAMC + 0x10)] ;# SDRAM Controller Low Power Register -set AT91_SDRAMC_LPCB [expr (3 << 0)] ;# Low-power Configurations +set AT91_SDRAMC_LPR [expr {$AT91_SDRAMC + 0x10}] ;# SDRAM Controller Low Power Register +set AT91_SDRAMC_LPCB [expr {3 << 0}] ;# Low-power Configurations set AT91_SDRAMC_LPCB_DISABLE 0 set AT91_SDRAMC_LPCB_SELF_REFRESH 1 set AT91_SDRAMC_LPCB_POWER_DOWN 2 set AT91_SDRAMC_LPCB_DEEP_POWER_DOWN 3 -set AT91_SDRAMC_PASR [expr (7 << 4)] ;# Partial Array Self Refresh -set AT91_SDRAMC_TCSR [expr (3 << 8)] ;# Temperature Compensated Self Refresh -set AT91_SDRAMC_DS [expr (3 << 10)] ;# Drive Strength -set AT91_SDRAMC_TIMEOUT [expr (3 << 12)] ;# Time to define when Low Power Mode is enabled -set AT91_SDRAMC_TIMEOUT_0_CLK_CYCLES [expr (0 << 12)] -set AT91_SDRAMC_TIMEOUT_64_CLK_CYCLES [expr (1 << 12)] -set AT91_SDRAMC_TIMEOUT_128_CLK_CYCLES [expr (2 << 12)] +set AT91_SDRAMC_PASR [expr {7 << 4}] ;# Partial Array Self Refresh +set AT91_SDRAMC_TCSR [expr {3 << 8}] ;# Temperature Compensated Self Refresh +set AT91_SDRAMC_DS [expr {3 << 10}] ;# Drive Strength +set AT91_SDRAMC_TIMEOUT [expr {3 << 12}] ;# Time to define when Low Power Mode is enabled +set AT91_SDRAMC_TIMEOUT_0_CLK_CYCLES [expr {0 << 12}] +set AT91_SDRAMC_TIMEOUT_64_CLK_CYCLES [expr {1 << 12}] +set AT91_SDRAMC_TIMEOUT_128_CLK_CYCLES [expr {2 << 12}] -set AT91_SDRAMC_IER [expr ($AT91_SDRAMC + 0x14)] ;# SDRAM Controller Interrupt Enable Register -set AT91_SDRAMC_IDR [expr ($AT91_SDRAMC + 0x18)] ;# SDRAM Controller Interrupt Disable Register -set AT91_SDRAMC_IMR [expr ($AT91_SDRAMC + 0x1C)] ;# SDRAM Controller Interrupt Mask Register -set AT91_SDRAMC_ISR [expr ($AT91_SDRAMC + 0x20)] ;# SDRAM Controller Interrupt Status Register -set AT91_SDRAMC_RES [expr (1 << 0)] ;# Refresh Error Status +set AT91_SDRAMC_IER [expr {$AT91_SDRAMC + 0x14}] ;# SDRAM Controller Interrupt Enable Register +set AT91_SDRAMC_IDR [expr {$AT91_SDRAMC + 0x18}] ;# SDRAM Controller Interrupt Disable Register +set AT91_SDRAMC_IMR [expr {$AT91_SDRAMC + 0x1C}] ;# SDRAM Controller Interrupt Mask Register +set AT91_SDRAMC_ISR [expr {$AT91_SDRAMC + 0x20}] ;# SDRAM Controller Interrupt Status Register +set AT91_SDRAMC_RES [expr {1 << 0}] ;# Refresh Error Status -set AT91_SDRAMC_MDR [expr ($AT91_SDRAMC + 0x24)] ;# SDRAM Memory Device Register -set AT91_SDRAMC_MD [expr (3 << 0)] ;# Memory Device Type +set AT91_SDRAMC_MDR [expr {$AT91_SDRAMC + 0x24}] ;# SDRAM Memory Device Register +set AT91_SDRAMC_MD [expr {3 << 0}] ;# Memory Device Type set AT91_SDRAMC_MD_SDRAM 0 set AT91_SDRAMC_MD_LOW_POWER_SDRAM 1 diff --git a/tcl/chip/atmel/at91/at91sam9_smc.cfg b/tcl/chip/atmel/at91/at91sam9_smc.cfg index 7dc7638582..c096c4a2cb 100644 --- a/tcl/chip/atmel/at91/at91sam9_smc.cfg +++ b/tcl/chip/atmel/at91/at91sam9_smc.cfg @@ -1,20 +1,22 @@ -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 -set AT91_SMC_EXNWMODE_DISABLE [expr (0 << 4)] -set AT91_SMC_EXNWMODE_FROZEN [expr (2 << 4)] -set AT91_SMC_EXNWMODE_READY [expr (3 << 4)] -set AT91_SMC_BAT [expr (1 << 8)] ;# Byte Access Type -set AT91_SMC_BAT_SELECT [expr (0 << 8)] -set AT91_SMC_BAT_WRITE [expr (1 << 8)] -set AT91_SMC_DBW [expr (3 << 12)] ;# Data Bus Width */ -set AT91_SMC_DBW_8 [expr (0 << 12)] -set AT91_SMC_DBW_16 [expr (1 << 12)] -set AT91_SMC_DBW_32 [expr (2 << 12)] -set AT91_SMC_TDFMODE [expr (1 << 20)] ;# TDF Optimization - Enabled -set AT91_SMC_PMEN [expr (1 << 24)] ;# Page Mode Enabled -set AT91_SMC_PS [expr (3 << 28)] ;# Page Size -set AT91_SMC_PS_4 [expr (0 << 28)] -set AT91_SMC_PS_8 [expr (1 << 28)] -set AT91_SMC_PS_16 [expr (2 << 28)] -set AT91_SMC_PS_32 [expr (3 << 28)] +# 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 +set AT91_SMC_EXNWMODE_DISABLE [expr {0 << 4}] +set AT91_SMC_EXNWMODE_FROZEN [expr {2 << 4}] +set AT91_SMC_EXNWMODE_READY [expr {3 << 4}] +set AT91_SMC_BAT [expr {1 << 8}] ;# Byte Access Type +set AT91_SMC_BAT_SELECT [expr {0 << 8}] +set AT91_SMC_BAT_WRITE [expr {1 << 8}] +set AT91_SMC_DBW [expr {3 << 12}] ;# Data Bus Width */ +set AT91_SMC_DBW_8 [expr {0 << 12}] +set AT91_SMC_DBW_16 [expr {1 << 12}] +set AT91_SMC_DBW_32 [expr {2 << 12}] +set AT91_SMC_TDFMODE [expr {1 << 20}] ;# TDF Optimization - Enabled +set AT91_SMC_PMEN [expr {1 << 24}] ;# Page Mode Enabled +set AT91_SMC_PS [expr {3 << 28}] ;# Page Size +set AT91_SMC_PS_4 [expr {0 << 28}] +set AT91_SMC_PS_8 [expr {1 << 28}] +set AT91_SMC_PS_16 [expr {2 << 28}] +set AT91_SMC_PS_32 [expr {3 << 28}] 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 2dd74fab92..1ef83733bb 100644 --- a/tcl/chip/atmel/at91/rtt.tcl +++ b/tcl/chip/atmel/at91/rtt.tcl @@ -1,15 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later -set RTTC_RTMR [expr $AT91C_BASE_RTTC + 0x00] -set RTTC_RTAR [expr $AT91C_BASE_RTTC + 0x04] -set RTTC_RTVR [expr $AT91C_BASE_RTTC + 0x08] -set RTTC_RTSR [expr $AT91C_BASE_RTTC + 0x0c] +set RTTC_RTMR [expr {$AT91C_BASE_RTTC + 0x00}] +set RTTC_RTAR [expr {$AT91C_BASE_RTTC + 0x04}] +set RTTC_RTVR [expr {$AT91C_BASE_RTTC + 0x08}] +set RTTC_RTSR [expr {$AT91C_BASE_RTTC + 0x0c}] global RTTC_RTMR global RTTC_RTAR global RTTC_RTVR global RTTC_RTSR proc show_RTTC_RTMR_helper { NAME ADDR VAL } { - set rtpres [expr $VAL & 0x0ffff] + set rtpres [expr {$VAL & 0x0ffff}] global BIT16 BIT17 if { $rtpres == 0 } { set rtpres 65536; @@ -17,7 +18,7 @@ proc show_RTTC_RTMR_helper { NAME ADDR VAL } { global AT91C_SLOWOSC_FREQ # Nasty hack, make this a float by tacking a .0 on the end # otherwise, jim makes the value an integer - set f [expr $AT91C_SLOWOSC_FREQ.0 / $rtpres.0] + set f [expr "$AT91C_SLOWOSC_FREQ.0 / $rtpres.0"] echo [format "\tPrescale value: 0x%04x (%5d) => %f Hz" $rtpres $rtpres $f] if { $VAL & $BIT16 } { echo "\tBit16 -> Alarm IRQ Enabled" diff --git a/tcl/chip/atmel/at91/sam9_smc.cfg b/tcl/chip/atmel/at91/sam9_smc.cfg index db943cb242..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 @@ -26,30 +28,30 @@ # tdf_cycles proc sam9_smc_config { cs smc_config } { ;# Setup Register for CS n - set AT91_SMC_SETUP [expr ($::AT91_SMC + 0x00 + ((cs)*0x10))] - set val [expr ($smc_config(nwe_setup) << 0)] - set val [expr ($val | $smc_config(ncs_write_setup) << 8] - set val [expr ($val | $smc_config(nrd_setup)) << 16] - set val [expr ($val | $smc_config(ncs_read_setup) << 24] + set AT91_SMC_SETUP [expr {$::AT91_SMC + 0x00 + $cs * 0x10}] + set val [expr {$smc_config(nwe_setup) << 0}] + set val [expr {$val | $smc_config(ncs_write_setup) << 8}] + set val [expr {$val | $smc_config(nrd_setup)) << 16}] + set val [expr {$val | $smc_config(ncs_read_setup) << 24}] mww $AT91_SMC_SETUP $val ;# Pulse Register for CS n - set AT91_SMC_PULSE [expr ($::AT91_SMC + 0x04 + ((cs)*0x10))] - set val [expr ($smc_config(nwe_pulse) << 0)] - set val [expr ($val | $smc_config(ncs_write_pulse) << 8] - set val [expr ($val | $smc_config(nrd_pulse) << 16] - set val [expr ($val | $smc_config(ncs_read_pulse) << 24] + set AT91_SMC_PULSE [expr {$::AT91_SMC + 0x04 + $cs * 0x10}] + set val [expr {$smc_config(nwe_pulse) << 0}] + set val [expr {$val | $smc_config(ncs_write_pulse) << 8}] + set val [expr {$val | $smc_config(nrd_pulse) << 16}] + set val [expr {$val | $smc_config(ncs_read_pulse) << 24}] mww $AT91_SMC_PULSE $val ;# Cycle Register for CS n - set AT91_SMC_CYCLE [expr ($::AT91_SMC + 0x08 + ((cs)*0x10))] - set val [expr ($smc_config(write_cycle) << 0)] - set val [expr ($val | $smc_config(read_cycle) << 16] + set AT91_SMC_CYCLE [expr {$::AT91_SMC + 0x08 + $cs * 0x10}] + set val [expr {$smc_config(write_cycle) << 0}] + set val [expr {$val | $smc_config(read_cycle) << 16}] mww $AT91_SMC_CYCLE $val ;# Mode Register for CS n - set AT91_SMC_MODE [expr ($::AT91_SMC + 0x0c + ((cs)*0x10))] - set val [expr ($smc_config(mode) << 0)] - set val [expr ($val | $smc_config(tdf_cycles) << 16] + set AT91_SMC_MODE [expr {$::AT91_SMC + 0x0c + $cs * 0x10}] + set val [expr {$smc_config(mode) << 0}] + set val [expr {$val | $smc_config(tdf_cycles) << 16}] mww $AT91_SMC_MODE $val } diff --git a/tcl/chip/atmel/at91/usarts.tcl b/tcl/chip/atmel/at91/usarts.tcl index ecc4f60342..62a651bbdc 100644 --- a/tcl/chip/atmel/at91/usarts.tcl +++ b/tcl/chip/atmel/at91/usarts.tcl @@ -1,20 +1,22 @@ +# 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] -set DBGU_IER [expr $AT91C_BASE_DBGU + 0x00000008] -set DBGU_IDR [expr $AT91C_BASE_DBGU + 0x0000000C] -set DBGU_IMR [expr $AT91C_BASE_DBGU + 0x00000010] -set DBGU_CSR [expr $AT91C_BASE_DBGU + 0x00000014] -set DBGU_RHR [expr $AT91C_BASE_DBGU + 0x00000018] -set DBGU_THR [expr $AT91C_BASE_DBGU + 0x0000001C] -set DBGU_BRGR [expr $AT91C_BASE_DBGU + 0x00000020] +set DBGU_CR [expr {$AT91C_BASE_DBGU + 0x00000000}] +set DBGU_MR [expr {$AT91C_BASE_DBGU + 0x00000004}] +set DBGU_IER [expr {$AT91C_BASE_DBGU + 0x00000008}] +set DBGU_IDR [expr {$AT91C_BASE_DBGU + 0x0000000C}] +set DBGU_IMR [expr {$AT91C_BASE_DBGU + 0x00000010}] +set DBGU_CSR [expr {$AT91C_BASE_DBGU + 0x00000014}] +set DBGU_RHR [expr {$AT91C_BASE_DBGU + 0x00000018}] +set DBGU_THR [expr {$AT91C_BASE_DBGU + 0x0000001C}] +set DBGU_BRGR [expr {$AT91C_BASE_DBGU + 0x00000020}] # no RTOR # no TTGR # no FIDI # no NER -set DBGU_CIDR [expr $AT91C_BASE_DBGU + 0x00000040] -set DBGU_EXID [expr $AT91C_BASE_DBGU + 0x00000044] -set DBGU_FNTR [expr $AT91C_BASE_DBGU + 0x00000048] +set DBGU_CIDR [expr {$AT91C_BASE_DBGU + 0x00000040}] +set DBGU_EXID [expr {$AT91C_BASE_DBGU + 0x00000044}] +set DBGU_FNTR [expr {$AT91C_BASE_DBGU + 0x00000048}] set USx_CR 0x00000000 @@ -54,7 +56,7 @@ proc show_mmr_USx_MR_helper { NAME ADDR VAL } { 2 { set s "Force=0" } 3 { set s "Force=1" } * { - set $x [expr $x & 6] + set $x [expr {$x & 6}] switch -exact $x { 4 { set s "None" } 6 { set s "Multidrop Mode" } @@ -63,7 +65,7 @@ proc show_mmr_USx_MR_helper { NAME ADDR VAL } { } echo [format "\tParity: %s " $s] - set x [expr 5 + [show_normalize_bitfield $VAL 7 6]] + set x [expr {5 + [show_normalize_bitfield $VAL 7 6]}] echo [format "\tDatabits: %d" $x] set x [show_normalize_bitfield $VAL 13 12] @@ -89,7 +91,7 @@ foreach WHO { US0 US1 US2 US3 US4 US5 US6 US7 US8 US9 } { set vn [set WHO]_[set REG] # vn = USx_IER # vv = variable value - set vv [expr $$n + [set USx_[set REG]]] + set vv [expr "$$n + [set USx_[set REG]]"] # And VV is the address in memory of that register diff --git a/tcl/chip/st/spear/quirk_no_srst.tcl b/tcl/chip/st/spear/quirk_no_srst.tcl index fd02d07c1d..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 @@ -24,7 +26,7 @@ set sp_reset_mode "" proc sp_is_halted {} { global sp_target_name - return [expr [string compare [$sp_target_name curstate] "halted" ] == 0] + return [expr {[string compare [$sp_target_name curstate] "halted" ] == 0}] } # wait for reset button to be pressed, causing CPU to get halted @@ -38,8 +40,8 @@ proc sp_reset_deassert_post {} { poll on echo "====> Press reset button on the board <====" - for {set i 0} { [sp_is_halted] == 0 } { set i [expr $i + 1]} { - echo -n "$bar([expr $i & 3])\r" + for {set i 0} { [sp_is_halted] == 0 } { set i [expr {$i + 1}]} { + echo -n "$bar([expr {$i & 3}])\r" sleep 200 } diff --git a/tcl/chip/st/spear/spear3xx.tcl b/tcl/chip/st/spear/spear3xx.tcl index ef38841379..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 # @@ -19,7 +21,7 @@ proc sp3xx_clock_default {} { mww 0xfca00014 0x0ffffff8 ;# set pll timeout to minimum (100us ?!?) # DDRCORE disable to change frequency - set val [expr ([mrw 0xfca8002c] & ~0x20000000) | 0x40000000] + set val [expr {([mrw 0xfca8002c] & ~0x20000000) | 0x40000000}] mww 0xfca8002c $val mww 0xfca8002c $val ;# Yes, write twice! @@ -29,7 +31,7 @@ proc sp3xx_clock_default {} { mww 0xfca80008 0x00001c0e ;# enable mww 0xfca80008 0x00001c06 ;# strobe mww 0xfca80008 0x00001c0e - while { [expr [mrw 0xfca80008] & 0x01] == 0x00 } { sleep 1 } + while { [expr {[mrw 0xfca80008] & 0x01}] == 0x00 } { sleep 1 } # programming PLL2 mww 0xfca80018 0xa600010c ;# M=166, P=1, N=12 @@ -37,13 +39,13 @@ proc sp3xx_clock_default {} { mww 0xfca80014 0x00001c0e ;# enable mww 0xfca80014 0x00001c06 ;# strobe mww 0xfca80014 0x00001c0e - while { [expr [mrw 0xfca80014] & 0x01] == 0x00 } { sleep 1 } + while { [expr {[mrw 0xfca80014] & 0x01}] == 0x00 } { sleep 1 } mww 0xfca80028 0x00000082 ;# enable plltimeen mww 0xfca80024 0x00000511 ;# set hclkdiv="/2" & pclkdiv="/2" mww 0xfca00000 0x00000004 ;# setting SYSCTL to NORMAL mode - while { [expr [mrw 0xfca00000] & 0x20] != 0x20 } { sleep 1 } + while { [expr {[mrw 0xfca00000] & 0x20}] != 0x20 } { sleep 1 } # Select source of DDR clock #mmw 0xfca80020 0x10000000 0x70000000 ;# PLL1 diff --git a/tcl/chip/st/spear/spear3xx_ddr.tcl b/tcl/chip/st/spear/spear3xx_ddr.tcl index a9787d11d4..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 @@ -28,7 +30,7 @@ proc sp3xx_ddr_init {ddr_type {ddr_chips 1}} { if { $ddr_chips == 2 } { echo [format \ "Double chip DDR memory. Total memory size 0x%08x byte" \ - [expr 2 * $ddr_size]] + [expr {2 * $ddr_size}]] } else { echo [format \ "Single chip DDR memory. Memory size 0x%08x byte" \ 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 07718b6493..afa4cbfd6a 100644 --- a/tcl/chip/st/stm32/stm32_rcc.tcl +++ b/tcl/chip/st/stm32/stm32_rcc.tcl @@ -1,14 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later -set RCC_CR [expr $RCC_BASE + 0x00] -set RCC_CFGR [expr $RCC_BASE + 0x04] -set RCC_CIR [expr $RCC_BASE + 0x08] -set RCC_APB2RSTR [expr $RCC_BASE + 0x0c] -set RCC_APB1RSTR [expr $RCC_BASE + 0x10] -set RCC_AHBENR [expr $RCC_BASE + 0x14] -set RCC_APB2ENR [expr $RCC_BASE + 0x18] -set RCC_APB1ENR [expr $RCC_BASE + 0x1c] -set RCC_BDCR [expr $RCC_BASE + 0x20] -set RCC_CSR [expr $RCC_BASE + 0x24] +set RCC_CR [expr {$RCC_BASE + 0x00}] +set RCC_CFGR [expr {$RCC_BASE + 0x04}] +set RCC_CIR [expr {$RCC_BASE + 0x08}] +set RCC_APB2RSTR [expr {$RCC_BASE + 0x0c}] +set RCC_APB1RSTR [expr {$RCC_BASE + 0x10}] +set RCC_AHBENR [expr {$RCC_BASE + 0x14}] +set RCC_APB2ENR [expr {$RCC_BASE + 0x18}] +set RCC_APB1ENR [expr {$RCC_BASE + 0x1c}] +set RCC_BDCR [expr {$RCC_BASE + 0x20}] +set RCC_CSR [expr {$RCC_BASE + 0x24}] proc show_RCC_CR { } { diff --git a/tcl/chip/st/stm32/stm32_regs.tcl b/tcl/chip/st/stm32/stm32_regs.tcl index 0c1f6257ce..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 @@ -11,78 +13,78 @@ set FSMC_R_BASE 0xA0000000 # /*Peripheral memory map */ set APB1PERIPH_BASE [set PERIPH_BASE] -set APB2PERIPH_BASE [expr $PERIPH_BASE + 0x10000] -set AHBPERIPH_BASE [expr $PERIPH_BASE + 0x20000] +set APB2PERIPH_BASE [expr {$PERIPH_BASE + 0x10000}] +set AHBPERIPH_BASE [expr {$PERIPH_BASE + 0x20000}] -set TIM2_BASE [expr $APB1PERIPH_BASE + 0x0000] -set TIM3_BASE [expr $APB1PERIPH_BASE + 0x0400] -set TIM4_BASE [expr $APB1PERIPH_BASE + 0x0800] -set TIM5_BASE [expr $APB1PERIPH_BASE + 0x0C00] -set TIM6_BASE [expr $APB1PERIPH_BASE + 0x1000] -set TIM7_BASE [expr $APB1PERIPH_BASE + 0x1400] -set RTC_BASE [expr $APB1PERIPH_BASE + 0x2800] -set WWDG_BASE [expr $APB1PERIPH_BASE + 0x2C00] -set IWDG_BASE [expr $APB1PERIPH_BASE + 0x3000] -set SPI2_BASE [expr $APB1PERIPH_BASE + 0x3800] -set SPI3_BASE [expr $APB1PERIPH_BASE + 0x3C00] -set USART2_BASE [expr $APB1PERIPH_BASE + 0x4400] -set USART3_BASE [expr $APB1PERIPH_BASE + 0x4800] -set UART4_BASE [expr $APB1PERIPH_BASE + 0x4C00] -set UART5_BASE [expr $APB1PERIPH_BASE + 0x5000] -set I2C1_BASE [expr $APB1PERIPH_BASE + 0x5400] -set I2C2_BASE [expr $APB1PERIPH_BASE + 0x5800] -set CAN_BASE [expr $APB1PERIPH_BASE + 0x6400] -set BKP_BASE [expr $APB1PERIPH_BASE + 0x6C00] -set PWR_BASE [expr $APB1PERIPH_BASE + 0x7000] -set DAC_BASE [expr $APB1PERIPH_BASE + 0x7400] +set TIM2_BASE [expr {$APB1PERIPH_BASE + 0x0000}] +set TIM3_BASE [expr {$APB1PERIPH_BASE + 0x0400}] +set TIM4_BASE [expr {$APB1PERIPH_BASE + 0x0800}] +set TIM5_BASE [expr {$APB1PERIPH_BASE + 0x0C00}] +set TIM6_BASE [expr {$APB1PERIPH_BASE + 0x1000}] +set TIM7_BASE [expr {$APB1PERIPH_BASE + 0x1400}] +set RTC_BASE [expr {$APB1PERIPH_BASE + 0x2800}] +set WWDG_BASE [expr {$APB1PERIPH_BASE + 0x2C00}] +set IWDG_BASE [expr {$APB1PERIPH_BASE + 0x3000}] +set SPI2_BASE [expr {$APB1PERIPH_BASE + 0x3800}] +set SPI3_BASE [expr {$APB1PERIPH_BASE + 0x3C00}] +set USART2_BASE [expr {$APB1PERIPH_BASE + 0x4400}] +set USART3_BASE [expr {$APB1PERIPH_BASE + 0x4800}] +set UART4_BASE [expr {$APB1PERIPH_BASE + 0x4C00}] +set UART5_BASE [expr {$APB1PERIPH_BASE + 0x5000}] +set I2C1_BASE [expr {$APB1PERIPH_BASE + 0x5400}] +set I2C2_BASE [expr {$APB1PERIPH_BASE + 0x5800}] +set CAN_BASE [expr {$APB1PERIPH_BASE + 0x6400}] +set BKP_BASE [expr {$APB1PERIPH_BASE + 0x6C00}] +set PWR_BASE [expr {$APB1PERIPH_BASE + 0x7000}] +set DAC_BASE [expr {$APB1PERIPH_BASE + 0x7400}] -set AFIO_BASE [expr $APB2PERIPH_BASE + 0x0000] -set EXTI_BASE [expr $APB2PERIPH_BASE + 0x0400] -set GPIOA_BASE [expr $APB2PERIPH_BASE + 0x0800] -set GPIOB_BASE [expr $APB2PERIPH_BASE + 0x0C00] -set GPIOC_BASE [expr $APB2PERIPH_BASE + 0x1000] -set GPIOD_BASE [expr $APB2PERIPH_BASE + 0x1400] -set GPIOE_BASE [expr $APB2PERIPH_BASE + 0x1800] -set GPIOF_BASE [expr $APB2PERIPH_BASE + 0x1C00] -set GPIOG_BASE [expr $APB2PERIPH_BASE + 0x2000] -set ADC1_BASE [expr $APB2PERIPH_BASE + 0x2400] -set ADC2_BASE [expr $APB2PERIPH_BASE + 0x2800] -set TIM1_BASE [expr $APB2PERIPH_BASE + 0x2C00] -set SPI1_BASE [expr $APB2PERIPH_BASE + 0x3000] -set TIM8_BASE [expr $APB2PERIPH_BASE + 0x3400] -set USART1_BASE [expr $APB2PERIPH_BASE + 0x3800] -set ADC3_BASE [expr $APB2PERIPH_BASE + 0x3C00] +set AFIO_BASE [expr {$APB2PERIPH_BASE + 0x0000}] +set EXTI_BASE [expr {$APB2PERIPH_BASE + 0x0400}] +set GPIOA_BASE [expr {$APB2PERIPH_BASE + 0x0800}] +set GPIOB_BASE [expr {$APB2PERIPH_BASE + 0x0C00}] +set GPIOC_BASE [expr {$APB2PERIPH_BASE + 0x1000}] +set GPIOD_BASE [expr {$APB2PERIPH_BASE + 0x1400}] +set GPIOE_BASE [expr {$APB2PERIPH_BASE + 0x1800}] +set GPIOF_BASE [expr {$APB2PERIPH_BASE + 0x1C00}] +set GPIOG_BASE [expr {$APB2PERIPH_BASE + 0x2000}] +set ADC1_BASE [expr {$APB2PERIPH_BASE + 0x2400}] +set ADC2_BASE [expr {$APB2PERIPH_BASE + 0x2800}] +set TIM1_BASE [expr {$APB2PERIPH_BASE + 0x2C00}] +set SPI1_BASE [expr {$APB2PERIPH_BASE + 0x3000}] +set TIM8_BASE [expr {$APB2PERIPH_BASE + 0x3400}] +set USART1_BASE [expr {$APB2PERIPH_BASE + 0x3800}] +set ADC3_BASE [expr {$APB2PERIPH_BASE + 0x3C00}] -set SDIO_BASE [expr $PERIPH_BASE + 0x18000] +set SDIO_BASE [expr {$PERIPH_BASE + 0x18000}] -set DMA1_BASE [expr $AHBPERIPH_BASE + 0x0000] -set DMA1_Channel1_BASE [expr $AHBPERIPH_BASE + 0x0008] -set DMA1_Channel2_BASE [expr $AHBPERIPH_BASE + 0x001C] -set DMA1_Channel3_BASE [expr $AHBPERIPH_BASE + 0x0030] -set DMA1_Channel4_BASE [expr $AHBPERIPH_BASE + 0x0044] -set DMA1_Channel5_BASE [expr $AHBPERIPH_BASE + 0x0058] -set DMA1_Channel6_BASE [expr $AHBPERIPH_BASE + 0x006C] -set DMA1_Channel7_BASE [expr $AHBPERIPH_BASE + 0x0080] -set DMA2_BASE [expr $AHBPERIPH_BASE + 0x0400] -set DMA2_Channel1_BASE [expr $AHBPERIPH_BASE + 0x0408] -set DMA2_Channel2_BASE [expr $AHBPERIPH_BASE + 0x041C] -set DMA2_Channel3_BASE [expr $AHBPERIPH_BASE + 0x0430] -set DMA2_Channel4_BASE [expr $AHBPERIPH_BASE + 0x0444] -set DMA2_Channel5_BASE [expr $AHBPERIPH_BASE + 0x0458] -set RCC_BASE [expr $AHBPERIPH_BASE + 0x1000] -set CRC_BASE [expr $AHBPERIPH_BASE + 0x3000] +set DMA1_BASE [expr {$AHBPERIPH_BASE + 0x0000}] +set DMA1_Channel1_BASE [expr {$AHBPERIPH_BASE + 0x0008}] +set DMA1_Channel2_BASE [expr {$AHBPERIPH_BASE + 0x001C}] +set DMA1_Channel3_BASE [expr {$AHBPERIPH_BASE + 0x0030}] +set DMA1_Channel4_BASE [expr {$AHBPERIPH_BASE + 0x0044}] +set DMA1_Channel5_BASE [expr {$AHBPERIPH_BASE + 0x0058}] +set DMA1_Channel6_BASE [expr {$AHBPERIPH_BASE + 0x006C}] +set DMA1_Channel7_BASE [expr {$AHBPERIPH_BASE + 0x0080}] +set DMA2_BASE [expr {$AHBPERIPH_BASE + 0x0400}] +set DMA2_Channel1_BASE [expr {$AHBPERIPH_BASE + 0x0408}] +set DMA2_Channel2_BASE [expr {$AHBPERIPH_BASE + 0x041C}] +set DMA2_Channel3_BASE [expr {$AHBPERIPH_BASE + 0x0430}] +set DMA2_Channel4_BASE [expr {$AHBPERIPH_BASE + 0x0444}] +set DMA2_Channel5_BASE [expr {$AHBPERIPH_BASE + 0x0458}] +set RCC_BASE [expr {$AHBPERIPH_BASE + 0x1000}] +set CRC_BASE [expr {$AHBPERIPH_BASE + 0x3000}] # /*Flash registers base address */ -set FLASH_R_BASE [expr $AHBPERIPH_BASE + 0x2000] +set FLASH_R_BASE [expr {$AHBPERIPH_BASE + 0x2000}] # /*Flash Option Bytes base address */ set OB_BASE 0x1FFFF800 # /*FSMC Bankx registers base address */ -set FSMC_Bank1_R_BASE [expr $FSMC_R_BASE + 0x0000] -set FSMC_Bank1E_R_BASE [expr $FSMC_R_BASE + 0x0104] -set FSMC_Bank2_R_BASE [expr $FSMC_R_BASE + 0x0060] -set FSMC_Bank3_R_BASE [expr $FSMC_R_BASE + 0x0080] -set FSMC_Bank4_R_BASE [expr $FSMC_R_BASE + 0x00A0] +set FSMC_Bank1_R_BASE [expr {$FSMC_R_BASE + 0x0000}] +set FSMC_Bank1E_R_BASE [expr {$FSMC_R_BASE + 0x0104}] +set FSMC_Bank2_R_BASE [expr {$FSMC_R_BASE + 0x0060}] +set FSMC_Bank3_R_BASE [expr {$FSMC_R_BASE + 0x0080}] +set FSMC_Bank4_R_BASE [expr {$FSMC_R_BASE + 0x00A0}] # /*Debug MCU registers base address */ set DBGMCU_BASE 0xE0042000 @@ -90,6 +92,6 @@ set DBGMCU_BASE 0xE0042000 # /*System Control Space memory map */ set SCS_BASE 0xE000E000 -set SysTick_BASE [expr $SCS_BASE + 0x0010] -set NVIC_BASE [expr $SCS_BASE + 0x0100] -set SCB_BASE [expr $SCS_BASE + 0x0D00] +set SysTick_BASE [expr {$SCS_BASE + 0x0010}] +set NVIC_BASE [expr {$SCS_BASE + 0x0100}] +set SCB_BASE [expr {$SCS_BASE + 0x0D00}] 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 62f2b73b7c..185925a16f 100644 --- a/tcl/cpld/altera-epm240.cfg +++ b/tcl/cpld/altera-epm240.cfg @@ -1,6 +1,13 @@ -# Altera MAXII EPM240T100C CPLD -# 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 epm240 tap -expected-id 0x020a10dd -irlen 10 +# SPDX-License-Identifier: GPL-2.0-or-later + +# file altera-epm240.cfg replaced by altera-maxii.cfg +echo "DEPRECATED: use altera-maxii.cfg instead of deprecated altera-epm240.cfg" + +#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 +adapter speed 5000 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 e9a9157178..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 @@ -29,9 +29,8 @@ proc arc_common_reset { {target ""} } { # vector located at the interrupt vector base address, which is the first # entry (offset 0x00) in the vector table. set int_vector_base [arc jtag get-aux-reg 0x25] - set start_pc "" - mem2array start_pc 32 $int_vector_base 1 - arc jtag set-aux-reg 0x6 $start_pc(0) + set start_pc [read_memory $int_vector_base 32 1] + arc jtag set-aux-reg 0x6 $start_pc # It is OK to do uncached writes - register cache will be invalidated by # the reset_assert() function. diff --git a/tcl/cpu/arc/em.tcl b/tcl/cpu/arc/em.tcl index f0455bb742..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] @@ -27,6 +27,6 @@ proc arc_em_reset { {target ""} } { # This is specific to ARC EM. set debug [arc jtag get-aux-reg 5] if { !($debug & (1 << 20)) } { - arc jtag set-aux-reg 5 [expr $debug | (1 << 20)] + arc jtag set-aux-reg 5 [expr {$debug | (1 << 20)}] } } diff --git a/tcl/cpu/arc/hs.tcl b/tcl/cpu/arc/hs.tcl index f39f2a7d00..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] @@ -48,7 +48,7 @@ proc arc_hs_reset { {target ""} } { $target arc jtag set-aux-reg 0x904 1 set l2_ctrl [$target arc jtag get-aux-reg 0x903] set l2_ctrl [$target arc jtag get-aux-reg 0x903] - while { [expr $l2_ctrl & 0x100] != 0 } { + while { [expr {$l2_ctrl & 0x100}] != 0 } { set l2_ctrl [$target arc jtag get-aux-reg 0x903] } } diff --git a/tcl/cpu/arc/v2.tcl b/tcl/cpu/arc/v2.tcl index a3172c220a..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] @@ -41,7 +41,7 @@ proc arc_v2_examine_target { {target ""} } { # 0b01 - 4 actionpoints # 0b10 - 8 actionpoints # 0b11 - reserved. - set ap_num [expr 0x2 << ($ap_build_type & 3)] + set ap_num [expr {0x2 << ($ap_build_type & 3)}] # Expression on top may produce 16 action points - which is a # reserved value for now. if { $ap_num < 16 } { @@ -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 @@ -341,6 +341,6 @@ proc arc_v2_reset { {target ""} } { # to write directly via JTAG layer... set num_ap [arc num-actionpoints] for {set i 0} {$i < $num_ap} {incr i} { - arc jtag set-aux-reg [expr 0x222 + $i * 3] 0 + arc jtag set-aux-reg [expr {0x222 + $i * 3}] 0 } } 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 new file mode 100644 index 0000000000..cdc63f0c11 --- /dev/null +++ b/tcl/fpga/lattice_ecp5.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME ecp5 +} + +# Lattice ECP5 family +# TAP IDs are extracted from BSDL files found on this page: +# https://www.latticesemi.com/Products/FPGAandCPLD/ECP5 +# +# 0x01111043 - LAE5UM_25F/LFE5UM_25F +# 0x01112043 - LAE5UM_45F/LFE5UM_45F +# 0x01113043 - LAE5UM_85F/LFE5UM_85 +# 0x21111043 - LFE5U_12F +# 0x41111043 - LFE5U_25F +# 0x41112043 - LFE5U_45F +# 0x41113043 - LFE5U_85F +# 0x81111043 - LFE5UM5G-25 +# 0x81112043 - LFE5UM5G-45 +# 0x81113043 - LFE5UM5G-85 + +jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ + -expected-id 0x01111043 -expected-id 0x01112043 -expected-id 0x01113043 \ + -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 a1d5ba3761..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 @@ -30,7 +32,7 @@ proc xilinx_get_dna {tap chip} { # Print out the "Device DNA" in the same format that impact uses. proc xilinx_print_dna {dna} { - set dna [expr $dna >> 64 - 57] + set dna [expr {$dna >> 64 - 57}] echo [format "DNA = %057b (0x%016x)" $dna $dna] } diff --git a/tcl/fpga/xilinx-xadc.cfg b/tcl/fpga/xilinx-xadc.cfg index d4be4f5414..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 @@ -16,7 +18,7 @@ proc xadc_cmd {cmd addr data} { READ 0x01 WRITE 0x02 } - return [expr ($cmds($cmd) << 26) | ($addr << 16) | ($data << 0)] + return [expr {($cmds($cmd) << 26) | ($addr << 16) | ($data << 0)}] } # XADC register addresses @@ -101,7 +103,7 @@ proc xadc_select {tap} { proc xadc_xfer {tap cmd addr data} { set ret [drscan $tap 32 [xadc_cmd $cmd $addr $data]] runtest 10 - return [expr 0x$ret] + return [expr "0x$ret"] } # XADC register write @@ -118,17 +120,17 @@ proc xadc_read {tap addr} { # convert 16 bit register code from ADC measurement on # external voltages (VAUX) to Volt proc xadc_volt {code} { - return [expr $code * 1./(1 << 16)] + return [expr {$code * 1./(1 << 16)}] } # convert 16 bit temperature measurement to Celsius proc xadc_temp {code} { - return [expr $code * 503.975/(1 << 16) - 273.15] + return [expr {$code * 503.975/(1 << 16) - 273.15}] } # convert 16 bit suppply voltage measurement to Volt proc xadc_sup {code} { - return [expr $code * 3./(1 << 16)] + return [expr {$code * 3./(1 << 16)}] } # perform a single channel measurement using default settings diff --git a/tcl/interface/altera-usb-blaster.cfg b/tcl/interface/altera-usb-blaster.cfg index 84e77b13ce..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 # @@ -5,7 +7,7 @@ # adapter driver usb_blaster -usb_blaster_lowlevel_driver ftdi +usb_blaster lowlevel_driver ftdi # These are already the defaults. -# usb_blaster_vid_pid 0x09FB 0x6001 -# usb_blaster_device_desc "USB-Blaster" +# usb_blaster vid_pid 0x09FB 0x6001 +# usb_blaster device_desc "USB-Blaster" diff --git a/tcl/interface/altera-usb-blaster2.cfg b/tcl/interface/altera-usb-blaster2.cfg index 4642b1dcfc..93f9809b03 100644 --- a/tcl/interface/altera-usb-blaster2.cfg +++ b/tcl/interface/altera-usb-blaster2.cfg @@ -1,8 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Altera USB-Blaster II # adapter driver usb_blaster -usb_blaster_vid_pid 0x09fb 0x6010 0x09fb 0x6810 -usb_blaster_lowlevel_driver ublast2 -usb_blaster_firmware /path/to/quartus/blaster_6810.hex +usb_blaster vid_pid 0x09fb 0x6010 0x09fb 0x6810 +usb_blaster lowlevel_driver ublast2 +usb_blaster firmware /path/to/quartus/blaster_6810.hex 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 265e37e068..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 # @@ -7,19 +9,19 @@ adapter driver buspirate # you need to specify port on which BP lives -#buspirate_port /dev/ttyUSB0 +#buspirate port /dev/ttyUSB0 # communication speed setting -buspirate_speed normal ;# or fast +buspirate speed normal ;# or fast # voltage regulator Enabled = 1 Disabled = 0 -#buspirate_vreg 0 +#buspirate vreg 0 # pin mode normal or open-drain (jtag only) -#buspirate_mode normal +#buspirate mode normal # pullup state Enabled = 1 Disabled = 0 -#buspirate_pullup 0 +#buspirate pullup 0 # this depends on the cable, you are safe with this option reset_config srst_only 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 1cb1d6151a..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 # @@ -5,4 +7,4 @@ # adapter driver parport -parport_cable chameleon +parport cable chameleon diff --git a/tcl/interface/cmsis-dap.cfg b/tcl/interface/cmsis-dap.cfg index 887d2d7134..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 # @@ -7,4 +9,4 @@ adapter driver cmsis-dap # Optionally specify the serial number of CMSIS-DAP usb device. -#cmsis_dap_serial 02200201E6661E601B98E3B9 +# adapter serial 02200201E6661E601B98E3B9 diff --git a/tcl/interface/dln-2-gpiod.cfg b/tcl/interface/dln-2-gpiod.cfg index 5407a244e8..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 e0a4b97d04..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 # @@ -12,5 +14,5 @@ if { [info exists PARPORTADDR] } { } adapter driver parport -parport_port $_PARPORTADDR -parport_cable flashlink +parport port $_PARPORTADDR +parport cable flashlink 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 new file mode 100644 index 0000000000..3fc3d7105e --- /dev/null +++ b/tcl/interface/ft232r/radiona_ulx3s.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# This adapter is integrated in to Radiona ULX3S board: +# board/radiona_ulx3s.cfg +# See schematics for the ft232r layout: +# https://github.com/emard/ulx3s/blob/master/doc/schematics_v316.pdf + +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 diff --git a/tcl/interface/ftdi/100ask-openjtag.cfg b/tcl/interface/ftdi/100ask-openjtag.cfg index 3cbd37e06d..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 # @@ -8,9 +10,9 @@ # adapter driver ftdi -ftdi_device_desc "USB<=>JTAG&RS232" -ftdi_vid_pid 0x1457 0x5118 +ftdi device_desc "USB<=>JTAG&RS232" +ftdi vid_pid 0x1457 0x5118 -ftdi_layout_init 0x0f08 0x0f1b -ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 -ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_init 0x0f08 0x0f1b +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 diff --git a/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg b/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg new file mode 100644 index 0000000000..6256aa0c2b --- /dev/null +++ b/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Ashling Opella-LD +# +# https://www.ashling.com/Opella-LD/ +# + +adapter driver ftdi +ftdi device_desc "Opella-LD Debug Probe" +ftdi vid_pid 0x0B6B 0x0040 +ftdi tdo_sample_edge falling +ftdi layout_init 0x0A68 0xFF7B +ftdi channel 0 +ftdi layout_signal JTAGOE -ndata 0x0010 +ftdi layout_signal nTRST -data 0x0020 +ftdi layout_signal nSRST -data 0x0040 +ftdi layout_signal SWD_EN -data 0x0100 +ftdi layout_signal SWDIO_OE -data 0x0200 +ftdi layout_signal LED -ndata 0x0800 +transport select jtag diff --git a/tcl/interface/ftdi/ashling-opella-ld-swd.cfg b/tcl/interface/ftdi/ashling-opella-ld-swd.cfg new file mode 100644 index 0000000000..4a4e4e0680 --- /dev/null +++ b/tcl/interface/ftdi/ashling-opella-ld-swd.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Ashling Opella-LD +# +# https://www.ashling.com/Opella-LD/ +# + +adapter driver ftdi +ftdi device_desc "Opella-LD Debug Probe" +ftdi vid_pid 0x0B6B 0x0040 +ftdi layout_init 0x0860 0x0b7b +ftdi channel 0 +ftdi layout_signal JTAGOE -data 0x0010 +ftdi layout_signal nTRST -data 0x0020 +ftdi layout_signal nSRST -data 0x0040 +ftdi layout_signal SWD_EN -data 0x0100 +ftdi layout_signal SWDIO_OE -data 0x0200 +ftdi layout_signal LED -ndata 0x0800 +transport select swd diff --git a/tcl/interface/ftdi/axm0432.cfg b/tcl/interface/ftdi/axm0432.cfg index 6cc1752e24..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 # @@ -10,9 +12,9 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "Symphony SoundBite" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Symphony SoundBite" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0c08 0x0c2b -ftdi_layout_signal nTRST -data 0x0800 -ftdi_layout_signal nSRST -data 0x0400 +ftdi layout_init 0x0c08 0x0c2b +ftdi layout_signal nTRST -data 0x0800 +ftdi layout_signal nSRST -data 0x0400 diff --git a/tcl/interface/ftdi/c232hm.cfg b/tcl/interface/ftdi/c232hm.cfg index 27cf766745..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 @@ -14,18 +16,18 @@ # http://www.ftdichip.com/Support/Documents/AppNotes/AN_129_FTDI_Hi_Speed_USB_To_JTAG_Example.pdf adapter driver ftdi -#ftdi_device_desc "C232HM-DDHSL-0" -#ftdi_device_desc "C232HM-EDHSL-0" +#ftdi device_desc "C232HM-DDHSL-0" +#ftdi device_desc "C232HM-EDHSL-0" # Common PID for FT232H -ftdi_vid_pid 0x0403 0x6014 +ftdi vid_pid 0x0403 0x6014 # Layout # High data byte 0x40 configures red LED on ACBUS6 initially high (unlit, since active-low) # Low data byte 0x08 configures TMS on ACBUS3 initially high (asserted); TCK, TDI low # High direction byte 0x40 configures red LED on ACBUS6 as high (output) # Low direction byte 0x0b configures TDO on ACBUS2 as low (input) -ftdi_layout_init 0x4008 0x400b +ftdi layout_init 0x4008 0x400b # ---A*BUS-------CCCCCCCC|DDDDDDDD # --------\______76543210|76543210 @@ -35,12 +37,12 @@ ftdi_layout_init 0x4008 0x400b #GPIOL2 0x0040 = 00000000|01000000 = ADBUS6 #GPIOL3 0x0080 = 00000000|10000000 = ADBUS7 # -ndata treats the LED as active-low for expected behavior (toggle when transferring) -ftdi_layout_signal LED -ndata 0x4000 +ftdi layout_signal LED -ndata 0x4000 # Available for aliasing as desired -ftdi_layout_signal GPIOL0 -data 0x0010 -oe 0x0010 -ftdi_layout_signal GPIOL1 -data 0x0020 -oe 0x0020 -ftdi_layout_signal GPIOL2 -data 0x0040 -oe 0x0040 -ftdi_layout_signal GPIOL3 -data 0x0080 -oe 0x0080 +ftdi layout_signal GPIOL0 -data 0x0010 -oe 0x0010 +ftdi layout_signal GPIOL1 -data 0x0020 -oe 0x0020 +ftdi layout_signal GPIOL2 -data 0x0040 -oe 0x0040 +ftdi layout_signal GPIOL3 -data 0x0080 -oe 0x0080 # C232HM FT232H JTAG/Other # Num Color Name Func 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 a23ddbfb5e..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 67427c5c0a..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 2bc516cc60..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 # @@ -5,9 +7,9 @@ # adapter driver ftdi -ftdi_device_desc "Cortino" -ftdi_vid_pid 0x0640 0x0032 +ftdi device_desc "Cortino" +ftdi vid_pid 0x0640 0x0032 -ftdi_layout_init 0x0108 0x010b -ftdi_layout_signal nTRST -data 0x0100 -ftdi_layout_signal nSRST -data 0x0200 -oe 0x0200 +ftdi layout_init 0x0108 0x010b +ftdi layout_signal nTRST -data 0x0100 +ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 diff --git a/tcl/interface/ftdi/digilent-hs1.cfg b/tcl/interface/ftdi/digilent-hs1.cfg index dfba3393ad..6a632ed268 100644 --- a/tcl/interface/ftdi/digilent-hs1.cfg +++ b/tcl/interface/ftdi/digilent-hs1.cfg @@ -1,11 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # this supports JTAG-HS1 and JTAG-SMT1 # (the later being the OEM on-board version) adapter driver ftdi -ftdi_device_desc "Digilent Adept USB Device" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Digilent Adept USB Device" +ftdi vid_pid 0x0403 0x6010 # channel 1 does not have any functionality -ftdi_channel 0 +ftdi channel 0 # just TCK TDI TDO TMS, no reset -ftdi_layout_init 0x0088 0x008b +ftdi layout_init 0x0088 0x008b reset_config none diff --git a/tcl/interface/ftdi/digilent-hs2.cfg b/tcl/interface/ftdi/digilent-hs2.cfg index ae6ba01bb3..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 device_desc "Digilent Adept USB Device" +ftdi vid_pid 0x0403 0x6014 -ftdi_channel 0 -ftdi_layout_init 0x00e8 0x60eb +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 7160bed8e7..78a233feb5 100644 --- a/tcl/interface/ftdi/digilent_jtag_hs3.cfg +++ b/tcl/interface/ftdi/digilent_jtag_hs3.cfg @@ -1,13 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Digilent JTAG-HS3 # adapter driver ftdi -ftdi_vid_pid 0x0403 0x6014 -ftdi_device_desc "Digilent USB Device" +ftdi vid_pid 0x0403 0x6014 +ftdi device_desc "Digilent USB Device" # From Digilent support: # The SRST pin is [...] 0x20 and 0x10 is the /OE (active low output enable) -ftdi_layout_init 0x2088 0x308b -ftdi_layout_signal nSRST -data 0x2000 -noe 0x1000 +ftdi layout_init 0x2088 0x308b +ftdi layout_signal nSRST -data 0x2000 -noe 0x1000 diff --git a/tcl/interface/ftdi/digilent_jtag_smt2.cfg b/tcl/interface/ftdi/digilent_jtag_smt2.cfg index 493ed6af56..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 # @@ -8,10 +10,10 @@ # adapter driver ftdi -ftdi_vid_pid 0x0403 0x6014 +ftdi vid_pid 0x0403 0x6014 -ftdi_layout_init 0x2088 0x3f8b -ftdi_layout_signal nSRST -data 0x2000 -ftdi_layout_signal GPIO2 -data 0x2000 -ftdi_layout_signal GPIO1 -data 0x0200 -ftdi_layout_signal GPIO0 -data 0x0100 +ftdi layout_init 0x20e8 0x3feb +ftdi layout_signal nSRST -data 0x2000 +ftdi layout_signal GPIO2 -data 0x2000 +ftdi layout_signal GPIO1 -data 0x0200 +ftdi layout_signal GPIO0 -data 0x0100 diff --git a/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg b/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg index bc783a46cb..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 # @@ -8,11 +10,11 @@ # https://www.xilinx.com/products/boards-and-kits/kcu105.html#documentation # # Note that the digilent_jtag_smt2 layout does not work and hangs while -# the ftdi_device_desc from digilent_hs2 is wrong. +# the ftdi device_desc from digilent_hs2 is wrong. adapter driver ftdi -ftdi_device_desc "Digilent USB Device" -ftdi_vid_pid 0x0403 0x6014 -ftdi_channel 0 -ftdi_layout_init 0x00e8 0x60eb +ftdi device_desc "Digilent USB Device" +ftdi vid_pid 0x0403 0x6014 +ftdi channel 0 +ftdi layout_init 0x00e8 0x60eb reset_config none diff --git a/tcl/interface/ftdi/dlp-usb1232h.cfg b/tcl/interface/ftdi/dlp-usb1232h.cfg index 9ddc2c80a8..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 # @@ -13,9 +15,9 @@ echo "in ft2232.c. Please report your experience with this file to openocd-devel echo "mailing list, so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Dual RS232-HS" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0008 0x000b -ftdi_layout_signal nTRST -data 0x0010 -oe 0x0010 -ftdi_layout_signal nSRST -data 0x0040 -oe 0x0040 +ftdi layout_init 0x0008 0x000b +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 +ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 diff --git a/tcl/interface/ftdi/dp_busblaster.cfg b/tcl/interface/ftdi/dp_busblaster.cfg index 86ab4d8408..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 # @@ -12,9 +14,9 @@ echo "Info : If you need SWD support, flash KT-Link buffer from https://github.c and use dp_busblaster_kt-link.cfg instead" adapter driver ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Dual RS232-HS" +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 +ftdi layout_init 0x0c08 0x0f1b +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 diff --git a/tcl/interface/ftdi/dp_busblaster_kt-link.cfg b/tcl/interface/ftdi/dp_busblaster_kt-link.cfg index d49a4c98f4..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) # @@ -10,12 +12,12 @@ # adapter driver ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Dual RS232-HS" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x8c28 0xff3b -ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 -ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 -ftdi_layout_signal LED -ndata 0x8000 -ftdi_layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 -ftdi_layout_signal SWDIO_OE -ndata 0x1000 +ftdi layout_init 0x8c28 0xff3b +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 +ftdi layout_signal LED -ndata 0x8000 +ftdi layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 +ftdi layout_signal SWDIO_OE -ndata 0x1000 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 42ed18ec3c..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 # @@ -18,9 +20,9 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Dual RS232-HS" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0008 0x000b -ftdi_layout_signal nTRST -data 0x0010 -oe 0x0010 -ftdi_layout_signal nSRST -data 0x0040 -oe 0x0040 +ftdi layout_init 0x0008 0x000b +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 +ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 diff --git a/tcl/interface/ftdi/flossjtag.cfg b/tcl/interface/ftdi/flossjtag.cfg index c4ad81dccb..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 # @@ -18,12 +20,12 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_vid_pid 0x0403 0x6010 -ftdi_device_desc "FLOSS-JTAG" -#ftdi_serial "FJ000001" +ftdi vid_pid 0x0403 0x6010 +ftdi device_desc "FLOSS-JTAG" +# adapter serial "FJ000001" -ftdi_layout_init 0x0008 0x180b -ftdi_layout_signal nTRST -data 0x0010 -oe 0x0010 -ftdi_layout_signal nSRST -data 0x0040 -oe 0x0040 -ftdi_layout_signal LED -data 0x0800 -ftdi_layout_signal LED2 -data 0x1000 +ftdi layout_init 0x0008 0x180b +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 +ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 +ftdi layout_signal LED -data 0x0800 +ftdi layout_signal LED2 -data 0x1000 diff --git a/tcl/interface/ftdi/flyswatter.cfg b/tcl/interface/ftdi/flyswatter.cfg index 5e9d4816da..8bce00dbbf 100644 --- a/tcl/interface/ftdi/flyswatter.cfg +++ b/tcl/interface/ftdi/flyswatter.cfg @@ -1,14 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TinCanTools Flyswatter # -# http://www.tincantools.com/product.php?productid=16134 +# http://web.archive.org/web/20150419072034/http://www.tincantools.com/JTAG/Flyswatter.html # adapter driver ftdi -ftdi_device_desc "Flyswatter" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Flyswatter" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0818 0x0cfb -ftdi_layout_signal nTRST -data 0x0010 -ftdi_layout_signal nSRST -oe 0x0020 -ftdi_layout_signal LED -data 0x0c00 +ftdi layout_init 0x0818 0x0cfb +ftdi layout_signal nTRST -data 0x0010 +ftdi layout_signal nSRST -oe 0x0020 +ftdi layout_signal LED -data 0x0c00 diff --git a/tcl/interface/ftdi/flyswatter2.cfg b/tcl/interface/ftdi/flyswatter2.cfg index 45dd0bacb9..ebc00fe601 100644 --- a/tcl/interface/ftdi/flyswatter2.cfg +++ b/tcl/interface/ftdi/flyswatter2.cfg @@ -1,14 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TinCanTools Flyswatter2 # -# http://www.tincantools.com/product.php?productid=16153 +# https://www.tincantools.com/product/flyswatter2/ # adapter driver ftdi -ftdi_device_desc "Flyswatter2" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Flyswatter2" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0538 0x057b -ftdi_layout_signal LED -ndata 0x0400 -ftdi_layout_signal nTRST -data 0x0010 -ftdi_layout_signal nSRST -data 0x0020 -noe 0x0100 +ftdi layout_init 0x0538 0x057b +ftdi layout_signal LED -ndata 0x0400 +ftdi layout_signal nTRST -data 0x0010 +ftdi layout_signal nSRST -data 0x0020 -noe 0x0100 diff --git a/tcl/interface/ftdi/ft232h-module-swd.cfg b/tcl/interface/ftdi/ft232h-module-swd.cfg index 98a8c844fd..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 @@ -8,27 +10,27 @@ adapter driver ftdi -ftdi_vid_pid 0x0403 0x6014 +ftdi vid_pid 0x0403 0x6014 # data MSB..LSB direction (1:out) MSB..LSB # 0000'0000'0011'0000 0000'0000'0011'1011 -ftdi_layout_init 0x0030 0x003b +ftdi layout_init 0x0030 0x003b # 0xfff8 0xfffb # Those signal are only required on some platforms or may required to be # enabled explicitly (e.g. nrf5x chips). -ftdi_layout_signal nSRST -data 0x0010 -oe 0x0010 -ftdi_layout_signal nTRST -data 0x0020 -oe 0x0020 +ftdi layout_signal nSRST -data 0x0010 -oe 0x0010 +ftdi layout_signal nTRST -data 0x0020 -oe 0x0020 # swd enable -ftdi_layout_signal SWD_EN -data 0 +ftdi layout_signal SWD_EN -data 0 # tri-state (configure as input) TDO/TIO when reading -ftdi_layout_signal SWDIO_OE -data 0 +ftdi layout_signal SWDIO_OE -data 0 transport select swd # re-configure TDO as tri-state -#ftdi_layout_signal TDO -data 0x0002 -oe 0x0002 -#ftdi_layout_signal TDI -data 0x0004 +#ftdi layout_signal TDO -data 0x0002 -oe 0x0002 +#ftdi layout_signal TDI -data 0x0004 # Adafruit FT232H JTAG SWD # Name Pin Name Func Func diff --git a/tcl/interface/ftdi/gw16042.cfg b/tcl/interface/ftdi/gw16042.cfg index 1288f77b18..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 # @@ -18,9 +20,9 @@ # adapter driver ftdi -ftdi_device_desc "USB-JTAG" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "USB-JTAG" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0058 0x007b -ftdi_layout_signal nTRST -data 0x0010 -ftdi_layout_signal nSRST -oe 0x0020 +ftdi layout_init 0x0058 0x007b +ftdi layout_signal nTRST -data 0x0010 +ftdi layout_signal nSRST -oe 0x0020 diff --git a/tcl/interface/ftdi/hie-jtag.cfg b/tcl/interface/ftdi/hie-jtag.cfg new file mode 100644 index 0000000000..6694df0484 --- /dev/null +++ b/tcl/interface/ftdi/hie-jtag.cfg @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Hofstädtler Industrie-Electronic (HIE) JTAG Debugger +# +# https://www.hofstaedtler.com/jtag +# + +adapter driver ftdi +ftdi channel 0 +ftdi vid_pid 0x0403 0x6014 +ftdi device_desc "HIE JTAG Debugger" + +ftdi layout_init 0x0c08 0x4f1b + +# define both Reset signals +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 + +# Toggle USB LED +ftdi layout_signal LED -ndata 0x4000 diff --git a/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg index 3802f6d2cd..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 # @@ -10,9 +12,9 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "NXHX 10-ETM" -ftdi_vid_pid 0x0640 0x0028 +ftdi device_desc "NXHX 10-ETM" +ftdi vid_pid 0x0640 0x0028 -ftdi_layout_init 0x0308 0x030b -ftdi_layout_signal nTRST -data 0x0100 -ftdi_layout_signal nSRST -data 0x0200 +ftdi layout_init 0x0308 0x030b +ftdi layout_signal nTRST -data 0x0100 +ftdi layout_signal nSRST -data 0x0200 diff --git a/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg index f2e64b4f5e..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 # @@ -10,9 +12,9 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "NXHX 500-ETM" -ftdi_vid_pid 0x0640 0x0028 +ftdi device_desc "NXHX 500-ETM" +ftdi vid_pid 0x0640 0x0028 -ftdi_layout_init 0x0308 0x030b -ftdi_layout_signal nTRST -data 0x0100 -ftdi_layout_signal nSRST -data 0x0200 +ftdi layout_init 0x0308 0x030b +ftdi layout_signal nTRST -data 0x0100 +ftdi layout_signal nSRST -data 0x0200 diff --git a/tcl/interface/ftdi/hilscher_nxhx500_re.cfg b/tcl/interface/ftdi/hilscher_nxhx500_re.cfg index 38f3c690e4..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 # @@ -10,9 +12,9 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "NXHX 500-RE" -ftdi_vid_pid 0x0640 0x0028 +ftdi device_desc "NXHX 500-RE" +ftdi vid_pid 0x0640 0x0028 -ftdi_layout_init 0x0308 0x030b -ftdi_layout_signal nTRST -data 0x0100 -ftdi_layout_signal nSRST -data 0x0200 +ftdi layout_init 0x0308 0x030b +ftdi layout_signal nTRST -data 0x0100 +ftdi layout_signal nSRST -data 0x0200 diff --git a/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg index bff081f184..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 # @@ -10,9 +12,9 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "NXHX 50-ETM" -ftdi_vid_pid 0x0640 0x0028 +ftdi device_desc "NXHX 50-ETM" +ftdi vid_pid 0x0640 0x0028 -ftdi_layout_init 0x0308 0x030b -ftdi_layout_signal nTRST -data 0x0100 -ftdi_layout_signal nSRST -data 0x0200 +ftdi layout_init 0x0308 0x030b +ftdi layout_signal nTRST -data 0x0100 +ftdi layout_signal nSRST -data 0x0200 diff --git a/tcl/interface/ftdi/hilscher_nxhx50_re.cfg b/tcl/interface/ftdi/hilscher_nxhx50_re.cfg index f9fbd015a5..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 # @@ -10,9 +12,9 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "NXHX50-RE" -ftdi_vid_pid 0x0640 0x0028 +ftdi device_desc "NXHX50-RE" +ftdi vid_pid 0x0640 0x0028 -ftdi_layout_init 0x0308 0x030b -ftdi_layout_signal nTRST -data 0x0100 -ftdi_layout_signal nSRST -data 0x0200 +ftdi layout_init 0x0308 0x030b +ftdi layout_signal nTRST -data 0x0100 +ftdi layout_signal nSRST -data 0x0200 diff --git a/tcl/interface/ftdi/hitex_lpc1768stick.cfg b/tcl/interface/ftdi/hitex_lpc1768stick.cfg index 9fe80f126b..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 # @@ -6,9 +8,9 @@ adapter driver ftdi -ftdi_device_desc "LPC1768-Stick" -ftdi_vid_pid 0x0640 0x0026 +ftdi device_desc "LPC1768-Stick" +ftdi vid_pid 0x0640 0x0026 -ftdi_layout_init 0x0388 0x038b -ftdi_layout_signal nTRST -data 0x0100 -ftdi_layout_signal nSRST -data 0x0080 -noe 0x200 +ftdi layout_init 0x0388 0x038b +ftdi layout_signal nTRST -data 0x0100 +ftdi layout_signal nSRST -data 0x0080 -noe 0x200 diff --git a/tcl/interface/ftdi/hitex_str9-comstick.cfg b/tcl/interface/ftdi/hitex_str9-comstick.cfg index 2b3dc3690e..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 # @@ -5,9 +7,9 @@ # adapter driver ftdi -ftdi_device_desc "STR9-comStick" -ftdi_vid_pid 0x0640 0x002c +ftdi device_desc "STR9-comStick" +ftdi vid_pid 0x0640 0x002c -ftdi_layout_init 0x0108 0x010b -ftdi_layout_signal nTRST -data 0x0100 -ftdi_layout_signal nSRST -data 0x0200 -oe 0x0200 +ftdi layout_init 0x0108 0x010b +ftdi layout_signal nTRST -data 0x0100 +ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 diff --git a/tcl/interface/ftdi/icebear.cfg b/tcl/interface/ftdi/icebear.cfg index 04c27319ed..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 # @@ -10,9 +12,9 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "ICEbear JTAG adapter" -ftdi_vid_pid 0x0403 0xc140 +ftdi device_desc "ICEbear JTAG adapter" +ftdi vid_pid 0x0403 0xc140 -ftdi_layout_init 0x0028 0x002b -ftdi_layout_signal nTRST -data 0x0010 -oe 0x0010 -ftdi_layout_signal nSRST -data 0x0020 +ftdi layout_init 0x0028 0x002b +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 +ftdi layout_signal nSRST -data 0x0020 diff --git a/tcl/interface/ftdi/imx8mp-evk.cfg b/tcl/interface/ftdi/imx8mp-evk.cfg index 4e04e8cd7f..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 # @@ -11,18 +13,18 @@ # adapter driver ftdi -ftdi_vid_pid 0x0403 0x6011 -ftdi_channel 0 +ftdi vid_pid 0x0403 0x6011 +ftdi channel 0 -ftdi_layout_init 0x00f8 0x000b +ftdi layout_init 0x00f8 0x000b -ftdi_layout_signal RESET_B -data 0x0010 -oe 0x0010 +ftdi layout_signal RESET_B -data 0x0010 -oe 0x0010 # Called SYS_nRST in schematics -ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020 -ftdi_layout_signal IO_nRST -data 0x0040 -oe 0x0040 -ftdi_layout_signal ONOFF_B -data 0x0080 -oe 0x0080 +ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 +ftdi layout_signal IO_nRST -data 0x0040 -oe 0x0040 +ftdi layout_signal ONOFF_B -data 0x0080 -oe 0x0080 -ftdi_layout_signal GPIO1 -data 0x0100 -oe 0x0100 -ftdi_layout_signal GPIO2 -data 0x0200 -oe 0x0200 -ftdi_layout_signal GPIO3 -data 0x0400 -oe 0x0400 -ftdi_layout_signal GPIO4 -data 0x0800 -oe 0x0800 +ftdi layout_signal GPIO1 -data 0x0100 -oe 0x0100 +ftdi layout_signal GPIO2 -data 0x0200 -oe 0x0200 +ftdi layout_signal GPIO3 -data 0x0400 -oe 0x0400 +ftdi layout_signal GPIO4 -data 0x0800 -oe 0x0800 diff --git a/tcl/interface/ftdi/incircuit-icprog.cfg b/tcl/interface/ftdi/incircuit-icprog.cfg index e0bd5ef591..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 @@ -7,8 +9,8 @@ # adapter driver ftdi -ftdi_vid_pid 0x0403 0x6010 +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0508 0x0f1b -ftdi_layout_signal nSRST -noe 0x0400 -data 0x0800 -ftdi_layout_signal nTRST -noe 0x0100 -data 0x0200 +ftdi layout_init 0x0508 0x0f1b +ftdi layout_signal nSRST -noe 0x0400 -data 0x0800 +ftdi layout_signal nTRST -noe 0x0100 -data 0x0200 diff --git a/tcl/interface/ftdi/iotlab-usb.cfg b/tcl/interface/ftdi/iotlab-usb.cfg index caa0596fd9..b7a004e848 100644 --- a/tcl/interface/ftdi/iotlab-usb.cfg +++ b/tcl/interface/ftdi/iotlab-usb.cfg @@ -1,11 +1,13 @@ +# 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 # adapter driver ftdi -ftdi_vid_pid 0x0403 0x6010 +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0008 0x000b -ftdi_layout_signal nTRST -data 0x0010 -oe 0x0010 -ftdi_layout_signal nSRST -data 0x0040 -oe 0x0040 +ftdi layout_init 0x0008 0x000b +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 +ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 diff --git a/tcl/interface/ftdi/isodebug.cfg b/tcl/interface/ftdi/isodebug.cfg index ead28644ce..0a6e0807ec 100644 --- a/tcl/interface/ftdi/isodebug.cfg +++ b/tcl/interface/ftdi/isodebug.cfg @@ -1,27 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # isodebug v1 # 5 kV isolated JTAG/SWD + UART adapter by Unjo AB adapter driver ftdi -ftdi_vid_pid 0x22b7 0x150d +ftdi vid_pid 0x22b7 0x150d -ftdi_layout_init 0x0ff8 0xfffb +ftdi layout_init 0x0ff8 0xfffb -ftdi_layout_signal LED -ndata 0x0100 -ftdi_layout_signal nTRST -data 0x0200 -ftdi_layout_signal nSRST -noe 0x0400 -ftdi_layout_signal SWDIO_OE -data 0x0008 +ftdi layout_signal LED -ndata 0x0100 +ftdi layout_signal nTRST -data 0x0200 +ftdi layout_signal nSRST -noe 0x0400 +ftdi layout_signal SWDIO_OE -data 0x0008 # Mode signals, either of these needs to be high to drive the JTAG/SWD pins. # The power-on state is low for both signals but the init setting above sets # JTAG_EN high. -ftdi_layout_signal SWD_EN -data 0x1000 -ftdi_layout_signal JTAG_EN -data 0x0800 +ftdi layout_signal SWD_EN -data 0x1000 +ftdi layout_signal JTAG_EN -data 0x0800 # In SWD mode, the JTAG_EN signal doubles as SWO_EN_N which switches the # second FTDI channel UART RxD to the SWO pin instead of the separate RxD # pin. Note that the default init state has this pin high so when OpenOCD # starts in SWD mode, SWO is by default disabled. To enable SWO tracing, -# issue the command 'ftdi_set_signal SWO_EN 1' where tracing is configured. +# issue the command 'ftdi set_signal SWO_EN 1' where tracing is configured. # To switch back to using the separate UART, SWO_EN needs to be disabled # before exiting OpenOCD, or the adapter replugged. -ftdi_layout_signal SWO_EN -nalias JTAG_EN +ftdi layout_signal SWO_EN -nalias JTAG_EN diff --git a/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg b/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg index 82eeaa7b56..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 # @@ -5,12 +7,12 @@ # adapter driver ftdi -ftdi_device_desc "JTAG-lock-pick Tiny 2" -ftdi_vid_pid 0x0403 0x8220 +ftdi device_desc "JTAG-lock-pick Tiny 2" +ftdi vid_pid 0x0403 0x8220 -ftdi_layout_init 0x8c28 0xff3b -ftdi_layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 -ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 -ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 -ftdi_layout_signal SWDIO_OE -ndata 0x1000 -ftdi_layout_signal LED -ndata 0x8000 +ftdi layout_init 0x8c28 0xff3b +ftdi layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 +ftdi layout_signal SWDIO_OE -ndata 0x1000 +ftdi layout_signal LED -ndata 0x8000 diff --git a/tcl/interface/ftdi/jtagkey.cfg b/tcl/interface/ftdi/jtagkey.cfg index 06463ab91d..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 # @@ -5,9 +7,9 @@ # adapter driver ftdi -ftdi_device_desc "Amontec JTAGkey" -ftdi_vid_pid 0x0403 0xcff8 +ftdi device_desc "Amontec JTAGkey" +ftdi vid_pid 0x0403 0xcff8 -ftdi_layout_init 0x0c08 0x0f1b -ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 -ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 +ftdi layout_init 0x0c08 0x0f1b +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 diff --git a/tcl/interface/ftdi/jtagkey2.cfg b/tcl/interface/ftdi/jtagkey2.cfg index ba151d3b5e..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 # @@ -5,9 +7,9 @@ # adapter driver ftdi -ftdi_device_desc "Amontec JTAGkey-2" -ftdi_vid_pid 0x0403 0xcff8 +ftdi device_desc "Amontec JTAGkey-2" +ftdi vid_pid 0x0403 0xcff8 -ftdi_layout_init 0x0c08 0x0f1b -ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 -ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 +ftdi layout_init 0x0c08 0x0f1b +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 diff --git a/tcl/interface/ftdi/jtagkey2p.cfg b/tcl/interface/ftdi/jtagkey2p.cfg index acb5047e9a..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 # @@ -5,9 +7,9 @@ # adapter driver ftdi -ftdi_device_desc "Amontec JTAGkey-2P" -ftdi_vid_pid 0x0403 0xcff8 +ftdi device_desc "Amontec JTAGkey-2P" +ftdi vid_pid 0x0403 0xcff8 -ftdi_layout_init 0x0c08 0x0f1b -ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 -ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 +ftdi layout_init 0x0c08 0x0f1b +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 diff --git a/tcl/interface/ftdi/kt-link.cfg b/tcl/interface/ftdi/kt-link.cfg index 5fc5db9d0e..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 # @@ -5,12 +7,12 @@ # adapter driver ftdi -ftdi_device_desc "KT-LINK" -ftdi_vid_pid 0x0403 0xbbe2 +ftdi device_desc "KT-LINK" +ftdi vid_pid 0x0403 0xbbe2 -ftdi_layout_init 0x8c28 0xff3b -ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 -ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 -ftdi_layout_signal LED -data 0x8000 -ftdi_layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 -ftdi_layout_signal SWDIO_OE -ndata 0x1000 +ftdi layout_init 0x8c28 0xff3b +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 +ftdi layout_signal LED -data 0x8000 +ftdi layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 +ftdi layout_signal SWDIO_OE -ndata 0x1000 diff --git a/tcl/interface/ftdi/lambdaconcept_ecpix-5.cfg b/tcl/interface/ftdi/lambdaconcept_ecpix-5.cfg new file mode 100644 index 0000000000..df4955f8a1 --- /dev/null +++ b/tcl/interface/ftdi/lambdaconcept_ecpix-5.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# This adapter is integrated in to LambdaConcept ECPIX-5 board: +# interface/ftdi/lambdaconcept_ecpix-5.cfg +# See schematics for the ftdi layout: +# http://docs.lambdaconcept.com/ecpix-5/_static/resources/SCH_ECPIX-5_R02.PDF + +adapter driver ftdi +adapter speed 10000 +ftdi device_desc "Dual RS232-HS" +ftdi vid_pid 0x0403 0x6010 + +ftdi layout_init 0xfff8 0xfffb +transport select jtag diff --git a/tcl/interface/ftdi/lisa-l.cfg b/tcl/interface/ftdi/lisa-l.cfg index 4e52f7b7ef..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 # @@ -10,11 +12,11 @@ echo "in ft2232.c. Please report your experience with this file to openocd-devel echo "mailing list, so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "Lisa/L" -ftdi_vid_pid 0x0403 0x6010 -ftdi_channel 1 +ftdi device_desc "Lisa/L" +ftdi vid_pid 0x0403 0x6010 +ftdi channel 1 -ftdi_layout_init 0x0008 0x180b -ftdi_layout_signal nTRST -data 0x0010 -oe 0x0010 -ftdi_layout_signal nSRST -data 0x0040 -oe 0x0040 -ftdi_layout_signal LED -data 0x1800 +ftdi layout_init 0x0008 0x180b +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 +ftdi layout_signal nSRST -data 0x0040 -oe 0x0040 +ftdi layout_signal LED -data 0x1800 diff --git a/tcl/interface/ftdi/luminary-icdi.cfg b/tcl/interface/ftdi/luminary-icdi.cfg index 8bc783e92b..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 @@ -16,10 +18,10 @@ # adapter driver ftdi -ftdi_device_desc "Luminary Micro ICDI Board" -ftdi_vid_pid 0x0403 0xbcda +ftdi device_desc "Luminary Micro ICDI Board" +ftdi vid_pid 0x0403 0xbcda -ftdi_layout_init 0x00a8 0x00eb -ftdi_layout_signal nSRST -noe 0x0020 -ftdi_layout_signal SWD_EN -ndata 0x0080 -ftdi_layout_signal SWDIO_OE -data 0x0008 +ftdi layout_init 0x00a8 0x00eb +ftdi layout_signal nSRST -noe 0x0020 +ftdi layout_signal SWD_EN -ndata 0x0080 +ftdi layout_signal SWDIO_OE -data 0x0008 diff --git a/tcl/interface/ftdi/luminary-lm3s811.cfg b/tcl/interface/ftdi/luminary-lm3s811.cfg index aac915e343..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 # @@ -12,10 +14,10 @@ # adapter driver ftdi -ftdi_device_desc "LM3S811 Evaluation Board" -ftdi_vid_pid 0x0403 0xbcd9 +ftdi device_desc "LM3S811 Evaluation Board" +ftdi vid_pid 0x0403 0xbcd9 -ftdi_layout_init 0x0088 0x008b -ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020 -ftdi_layout_signal SWD_EN -ndata 0x0080 -ftdi_layout_signal SWDIO_OE -data 0x0008 +ftdi layout_init 0x0088 0x008b +ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 +ftdi layout_signal SWD_EN -ndata 0x0080 +ftdi layout_signal SWDIO_OE -data 0x0008 diff --git a/tcl/interface/ftdi/luminary.cfg b/tcl/interface/ftdi/luminary.cfg index 5e34f8cea1..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 # @@ -25,10 +27,10 @@ # adapter driver ftdi -ftdi_device_desc "Stellaris Evaluation Board" -ftdi_vid_pid 0x0403 0xbcd9 +ftdi device_desc "Stellaris Evaluation Board" +ftdi vid_pid 0x0403 0xbcd9 -ftdi_layout_init 0x00a8 0x00eb -ftdi_layout_signal nSRST -noe 0x0020 -ftdi_layout_signal SWD_EN -ndata 0x0080 -ftdi_layout_signal SWDIO_OE -data 0x0008 +ftdi layout_init 0x00a8 0x00eb +ftdi layout_signal nSRST -noe 0x0020 +ftdi layout_signal SWD_EN -ndata 0x0080 +ftdi layout_signal SWDIO_OE -data 0x0008 diff --git a/tcl/interface/ftdi/m53evk.cfg b/tcl/interface/ftdi/m53evk.cfg index 6597f2d305..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 # @@ -5,10 +7,10 @@ # adapter driver ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Dual RS232-HS" +ftdi vid_pid 0x0403 0x6010 -ftdi_channel 0 -ftdi_layout_init 0x0008 0x000b -ftdi_layout_signal nTRST -data 0x0010 -oe 0x0010 -ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020 +ftdi channel 0 +ftdi layout_init 0x0008 0x000b +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 +ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 diff --git a/tcl/interface/ftdi/mbftdi.cfg b/tcl/interface/ftdi/mbftdi.cfg index c0ff865745..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 # @@ -10,7 +12,7 @@ # adapter driver ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Dual RS232-HS" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0008 0x000b +ftdi layout_init 0x0008 0x000b diff --git a/tcl/interface/ftdi/minimodule-swd.cfg b/tcl/interface/ftdi/minimodule-swd.cfg index 4bc331edb9..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. @@ -38,17 +40,17 @@ adapter driver ftdi #Select your module type and channel -#ftdi_device_desc "FT2232H MiniModule" -ftdi_vid_pid 0x0403 0x6010 -#ftdi_channel 1 +#ftdi device_desc "FT2232H MiniModule" +ftdi vid_pid 0x0403 0x6010 +#ftdi channel 1 -#ftdi_device_desc "FT4232H MiniModule" -#ftdi_vid_pid 0x0403 0x6011 -#ftdi_channel 1 +#ftdi device_desc "FT4232H MiniModule" +#ftdi vid_pid 0x0403 0x6011 +#ftdi channel 1 -ftdi_layout_init 0x0000 0x000b -ftdi_layout_signal nSRST -data 0x0010 -oe 0x0010 -ftdi_layout_signal SWD_EN -data 0 -ftdi_layout_signal SWDIO_OE -data 0 +ftdi layout_init 0x0000 0x000b +ftdi layout_signal nSRST -data 0x0010 -oe 0x0010 +ftdi layout_signal SWD_EN -data 0 +ftdi layout_signal SWDIO_OE -data 0 transport select swd diff --git a/tcl/interface/ftdi/minimodule.cfg b/tcl/interface/ftdi/minimodule.cfg index 5dcce1fcf9..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 # @@ -5,12 +7,12 @@ # adapter driver ftdi -ftdi_device_desc "FT2232H MiniModule" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "FT2232H MiniModule" +ftdi vid_pid 0x0403 0x6010 # Every pin set as high impedance except TCK, TDI, TDO and TMS -ftdi_layout_init 0x0008 0x000b +ftdi layout_init 0x0008 0x000b # nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip) # This choice is arbitrary. Use other GPIO pin if desired. -ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020 +ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 diff --git a/tcl/interface/ftdi/minispartan6.cfg b/tcl/interface/ftdi/minispartan6.cfg index 97a6abe04a..f12bae621c 100644 --- a/tcl/interface/ftdi/minispartan6.cfg +++ b/tcl/interface/ftdi/minispartan6.cfg @@ -1,14 +1,16 @@ +# 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 # The miniSpartan6+ sadly doesn't have a custom device description, so we just # have to hope you got it right. -#ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 +#ftdi device_desc "Dual RS232-HS" +ftdi vid_pid 0x0403 0x6010 # interface 1 is the uart -ftdi_channel 0 +ftdi channel 0 # just TCK TDI TDO TMS, no reset -ftdi_layout_init 0x0008 0x000b +ftdi layout_init 0x0008 0x000b reset_config none # this generally works fast: the fpga can handle 30MHz, the spi flash can handle # 54MHz with simple read, no dummy cycles, and wait-for-write-completion diff --git a/tcl/interface/ftdi/miniwiggler.cfg b/tcl/interface/ftdi/miniwiggler.cfg new file mode 100644 index 0000000000..ebaa97920b --- /dev/null +++ b/tcl/interface/ftdi/miniwiggler.cfg @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Infineon DAP miniWiggler V3 +# +# https://www.infineon.com/cms/en/product/evaluation-boards/kit_miniwiggler_3_usb/ +# +# Layout: FTDI FT2232 +# ADBUS0 TCK +# ADBUS1 TDI +# ADBUS2 TDO +# ADBUS3 TMS +# ADBUS4 nOE (output enable) +# ADBUS5 +# ADBUS6 +# ADBUS7 Blue LED +# +# ACBUS0 nTRST +# ACBUS1 nSRST +# ACUBS2 +# ACBUS3 +# ACBUS4 +# ACBUS5 +# ACBUS6 +# ACBUS7 +# + +adapter driver ftdi +ftdi device_desc "DAS JDS miniWiggler V3.1" +ftdi vid_pid 0x058b 0x0043 + +ftdi channel 0 +ftdi layout_init 0x0008 0x001b +ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 +ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 diff --git a/tcl/interface/ftdi/neodb.cfg b/tcl/interface/ftdi/neodb.cfg index 1cfb3526ca..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 # @@ -5,10 +7,10 @@ # adapter driver ftdi -ftdi_device_desc "Debug Board for Neo1973" -ftdi_vid_pid 0x1457 0x5118 +ftdi device_desc "Debug Board for Neo1973" +ftdi vid_pid 0x1457 0x5118 -ftdi_layout_init 0x0508 0x0f1b -ftdi_layout_signal nTRST -data 0x0200 -noe 0x0100 -ftdi_layout_signal nSRST -data 0x0800 -noe 0x0400 -ftdi_layout_signal nNOR_WP -data 0x0010 -oe 0x0010 +ftdi layout_init 0x0508 0x0f1b +ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 +ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 +ftdi layout_signal nNOR_WP -data 0x0010 -oe 0x0010 diff --git a/tcl/interface/ftdi/ngxtech.cfg b/tcl/interface/ftdi/ngxtech.cfg index 3aa79ab310..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 # @@ -11,9 +13,9 @@ echo "experience with this file to openocd-devel mailing list, so it could be ma echo "as working or fixed." adapter driver ftdi -ftdi_device_desc "NGX JTAG" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "NGX JTAG" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0508 0x0f1b -ftdi_layout_signal nTRST -data 0x0200 -noe 0x0100 -ftdi_layout_signal nSRST -data 0x0800 -noe 0x0400 +ftdi layout_init 0x0508 0x0f1b +ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 +ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 diff --git a/tcl/interface/ftdi/olimex-arm-jtag-swd.cfg b/tcl/interface/ftdi/olimex-arm-jtag-swd.cfg index 2153fd65f5..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/ @@ -5,5 +7,5 @@ transport select swd -ftdi_layout_signal SWD_EN -nalias nTRST -ftdi_layout_signal SWDIO_OE -alias TMS +ftdi layout_signal SWD_EN -nalias nTRST +ftdi layout_signal SWDIO_OE -alias TMS diff --git a/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg b/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg index c8e3befb7d..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 # @@ -5,10 +7,10 @@ # adapter driver ftdi -ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-OCD-H" -ftdi_vid_pid 0x15ba 0x002b +ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-OCD-H" +ftdi vid_pid 0x15ba 0x002b -ftdi_layout_init 0x0908 0x0b1b -ftdi_layout_signal nSRST -oe 0x0200 -ftdi_layout_signal nTRST -data 0x0100 -ftdi_layout_signal LED -data 0x0800 +ftdi layout_init 0x0908 0x0b1b +ftdi layout_signal nSRST -oe 0x0200 +ftdi layout_signal nTRST -data 0x0100 +ftdi layout_signal LED -data 0x0800 diff --git a/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg b/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg index f9126d40d2..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 # @@ -5,10 +7,10 @@ # adapter driver ftdi -ftdi_device_desc "Olimex OpenOCD JTAG" -ftdi_vid_pid 0x15ba 0x0003 +ftdi device_desc "Olimex OpenOCD JTAG" +ftdi vid_pid 0x15ba 0x0003 -ftdi_layout_init 0x0c08 0x0f1b -ftdi_layout_signal nSRST -oe 0x0200 -ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 -ftdi_layout_signal LED -data 0x0800 +ftdi layout_init 0x0c08 0x0f1b +ftdi layout_signal nSRST -oe 0x0200 +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal LED -data 0x0800 diff --git a/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg b/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg index eac25b6da7..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 # @@ -5,10 +7,10 @@ # adapter driver ftdi -ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" -ftdi_vid_pid 0x15ba 0x002a +ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" +ftdi vid_pid 0x15ba 0x002a -ftdi_layout_init 0x0808 0x0a1b -ftdi_layout_signal nSRST -oe 0x0200 -ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100 -ftdi_layout_signal LED -data 0x0800 +ftdi layout_init 0x0808 0x0a1b +ftdi layout_signal nSRST -oe 0x0200 +ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 +ftdi layout_signal LED -data 0x0800 diff --git a/tcl/interface/ftdi/olimex-jtag-tiny.cfg b/tcl/interface/ftdi/olimex-jtag-tiny.cfg index 4811f4dda0..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 # @@ -5,10 +7,10 @@ # adapter driver ftdi -ftdi_device_desc "Olimex OpenOCD JTAG TINY" -ftdi_vid_pid 0x15ba 0x0004 +ftdi device_desc "Olimex OpenOCD JTAG TINY" +ftdi vid_pid 0x15ba 0x0004 -ftdi_layout_init 0x0808 0x0a1b -ftdi_layout_signal nSRST -oe 0x0200 -ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100 -ftdi_layout_signal LED -data 0x0800 +ftdi layout_init 0x0808 0x0a1b +ftdi layout_signal nSRST -oe 0x0200 +ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 +ftdi layout_signal LED -data 0x0800 diff --git a/tcl/interface/ftdi/oocdlink.cfg b/tcl/interface/ftdi/oocdlink.cfg index deba4a504e..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 # @@ -11,9 +13,9 @@ echo "experience with this file to openocd-devel mailing list, so it could be ma echo "as working or fixed." adapter driver ftdi -ftdi_device_desc "OOCDLink" -ftdi_vid_pid 0x0403 0xbaf8 +ftdi device_desc "OOCDLink" +ftdi vid_pid 0x0403 0xbaf8 -ftdi_layout_init 0x0508 0x0f1b -ftdi_layout_signal nTRST -data 0x0200 -noe 0x0100 -ftdi_layout_signal nSRST -data 0x0800 -noe 0x0400 +ftdi layout_init 0x0508 0x0f1b +ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 +ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 diff --git a/tcl/interface/ftdi/opendous_ftdi.cfg b/tcl/interface/ftdi/opendous_ftdi.cfg index 50f32fb3a2..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 # @@ -8,10 +10,10 @@ # adapter driver ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 -ftdi_channel 1 +ftdi device_desc "Dual RS232-HS" +ftdi vid_pid 0x0403 0x6010 +ftdi channel 1 -ftdi_layout_init 0x0c08 0x0f1b -ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 -ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 +ftdi layout_init 0x0c08 0x0f1b +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 diff --git a/tcl/interface/ftdi/openocd-usb-hs.cfg b/tcl/interface/ftdi/openocd-usb-hs.cfg index 6f67689f61..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 # @@ -5,9 +7,9 @@ # adapter driver ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Dual RS232-HS" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0508 0x0f1b -ftdi_layout_signal nTRST -data 0x0200 -noe 0x0100 -ftdi_layout_signal nSRST -data 0x0800 -noe 0x0400 +ftdi layout_init 0x0508 0x0f1b +ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 +ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 diff --git a/tcl/interface/ftdi/openocd-usb.cfg b/tcl/interface/ftdi/openocd-usb.cfg index ed80a05d90..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 # @@ -5,9 +7,9 @@ # adapter driver ftdi -ftdi_device_desc "Dual RS232" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Dual RS232" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0508 0x0f1b -ftdi_layout_signal nTRST -data 0x0200 -noe 0x0100 -ftdi_layout_signal nSRST -data 0x0800 -noe 0x0400 +ftdi layout_init 0x0508 0x0f1b +ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 +ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 diff --git a/tcl/interface/ftdi/openrd.cfg b/tcl/interface/ftdi/openrd.cfg index 535c5e896f..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 # @@ -5,10 +7,10 @@ # adapter driver ftdi -ftdi_device_desc "OpenRD JTAGKey FT2232D B" -ftdi_vid_pid 0x0403 0x9e90 -ftdi_channel 0 +ftdi device_desc "OpenRD JTAGKey FT2232D B" +ftdi vid_pid 0x0403 0x9e90 +ftdi channel 0 -ftdi_layout_init 0x0608 0x0f1b -ftdi_layout_signal nTRST -data 0x0200 -ftdi_layout_signal nSRST -noe 0x0400 +ftdi layout_init 0x0608 0x0f1b +ftdi layout_signal nTRST -data 0x0200 +ftdi layout_signal nSRST -noe 0x0400 diff --git a/tcl/interface/ftdi/pipistrello.cfg b/tcl/interface/ftdi/pipistrello.cfg index 2074924a3f..29ecd12292 100644 --- a/tcl/interface/ftdi/pipistrello.cfg +++ b/tcl/interface/ftdi/pipistrello.cfg @@ -1,12 +1,14 @@ +# 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 -ftdi_device_desc "Pipistrello LX45" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "Pipistrello LX45" +ftdi vid_pid 0x0403 0x6010 # interface 1 is the uart -ftdi_channel 0 +ftdi channel 0 # just TCK TDI TDO TMS, no reset -ftdi_layout_init 0x0008 0x000b +ftdi layout_init 0x0008 0x000b reset_config none # this generally works fast: the fpga can handle 30MHz, the spi flash can handle # 54MHz with simple read, no dummy cycles, and wait-for-write-completion diff --git a/tcl/interface/ftdi/pls_spc5.cfg b/tcl/interface/ftdi/pls_spc5.cfg new file mode 100644 index 0000000000..3b3c2d6475 --- /dev/null +++ b/tcl/interface/ftdi/pls_spc5.cfg @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PLS SPC5-UDESTK +# +# https://www.st.com/en/development-tools/spc5-udestk.html +# +# Reference the SPC56D Discovery schematics. +# +# Layout: FTDI FT2232 +# ADBUS0 TCK +# ADBUS1 TDI +# ADBUS2 TDO +# ADBUS3 TMS +# ADBUS4 TMS +# ADBUS5 RTCK +# ADBUS6 +# ADBUS7 LED1 +# +# ACBUS0 nTRST +# ACBUS1 nSRST (external pull-down) +# ACUBS2 +# ACBUS3 +# ACBUS4 +# ACBUS5 nSRST direction (input=L, output=H, external pull-down) +# ACBUS6 TMS direction (input=L, output=H, external pull-up) +# ACBUS7 LED2 +# + +adapter driver ftdi +ftdi device_desc "PLS USB/JTAG Adapter for SPC5xxx" +ftdi vid_pid 0x263d 0x4001 + +ftdi channel 0 +ftdi layout_init 0x0008 0x000b +ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 +ftdi layout_signal nSRST -ndata 0x2000 -oe 0x2000 diff --git a/tcl/interface/ftdi/redbee-econotag.cfg b/tcl/interface/ftdi/redbee-econotag.cfg index b6f6d23bad..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 # @@ -14,8 +16,8 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_vid_pid 0x0403 0x6010 +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0c08 0x0c2b -ftdi_layout_signal nTRST -data 0x0800 -ftdi_layout_signal nSRST -data 0x0400 +ftdi layout_init 0x0c08 0x0c2b +ftdi layout_signal nTRST -data 0x0800 +ftdi layout_signal nSRST -data 0x0400 diff --git a/tcl/interface/ftdi/redbee-usb.cfg b/tcl/interface/ftdi/redbee-usb.cfg index 52ab93e025..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 # @@ -14,9 +16,9 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_vid_pid 0x0403 0x6010 -ftdi_channel 1 +ftdi vid_pid 0x0403 0x6010 +ftdi channel 1 -ftdi_layout_init 0x0c08 0x0c2b -ftdi_layout_signal nTRST -data 0x0800 -ftdi_layout_signal nSRST -data 0x0400 +ftdi layout_init 0x0c08 0x0c2b +ftdi layout_signal nTRST -data 0x0800 +ftdi layout_signal nSRST -data 0x0400 diff --git a/tcl/interface/ftdi/rowley-cc-arm-swd.cfg b/tcl/interface/ftdi/rowley-cc-arm-swd.cfg index 9a96dbd925..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 @@ -6,5 +8,5 @@ transport select swd -ftdi_layout_signal SWD_EN -nalias nTRST -ftdi_layout_signal SWDIO_OE -alias TMS +ftdi layout_signal SWD_EN -nalias nTRST +ftdi layout_signal SWDIO_OE -alias TMS diff --git a/tcl/interface/ftdi/sheevaplug.cfg b/tcl/interface/ftdi/sheevaplug.cfg index d4ec72e667..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 # @@ -5,10 +7,10 @@ # adapter driver ftdi -ftdi_device_desc "SheevaPlug JTAGKey FT2232D B" -ftdi_vid_pid 0x9e88 0x9e8f -ftdi_channel 0 +ftdi device_desc "SheevaPlug JTAGKey FT2232D B" +ftdi vid_pid 0x9e88 0x9e8f +ftdi channel 0 -ftdi_layout_init 0x0608 0x0f1b -ftdi_layout_signal nTRST -data 0x0200 -ftdi_layout_signal nSRST -noe 0x0400 +ftdi layout_init 0x0608 0x0f1b +ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 +ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 diff --git a/tcl/interface/ftdi/signalyzer-lite.cfg b/tcl/interface/ftdi/signalyzer-lite.cfg index 4778420058..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) # @@ -10,9 +12,9 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "Signalyzer LITE" -ftdi_vid_pid 0x0403 0xbca1 +ftdi device_desc "Signalyzer LITE" +ftdi vid_pid 0x0403 0xbca1 -ftdi_layout_init 0x0008 0x000b -ftdi_layout_signal nTRST -data 0x0010 -oe 0x0010 -ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020 +ftdi layout_init 0x0008 0x000b +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 +ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 diff --git a/tcl/interface/ftdi/signalyzer.cfg b/tcl/interface/ftdi/signalyzer.cfg index 2439298352..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) # @@ -10,9 +12,9 @@ echo "Please report your experience with this file to openocd-devel mailing list echo "so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "Signalyzer" -ftdi_vid_pid 0x0403 0xbca0 +ftdi device_desc "Signalyzer" +ftdi vid_pid 0x0403 0xbca0 -ftdi_layout_init 0x0008 0x000b -ftdi_layout_signal nTRST -data 0x0010 -oe 0x0010 -ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020 +ftdi layout_init 0x0008 0x000b +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 +ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 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 3aed2ae20a..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 @@ -11,8 +11,8 @@ # adapter driver ftdi -ftdi_vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0088 0x008b -ftdi_channel 1 +ftdi vid_pid 0x0403 0x6010 +ftdi layout_init 0x0088 0x008b +ftdi channel 1 diff --git a/tcl/interface/ftdi/steppenprobe.cfg b/tcl/interface/ftdi/steppenprobe.cfg new file mode 100644 index 0000000000..f84efe61ed --- /dev/null +++ b/tcl/interface/ftdi/steppenprobe.cfg @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Steppenprobe +# https://github.com/diegoherranz/steppenprobe +# + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +# Initial Layout +ftdi layout_init 0x0058 0x99fb +# Signal Data Direction Notes +# TCK 0 1 (out) +# TDI 0 1 (out) +# TDO 0 0 (in) +# TMS 1 1 (out) JTAG IEEE std recommendation +# LED 1 1 (out) LED off +# SWD_EN 0 1 (out) OpenOCD sets this high for SWD +# SWDIO_OE 1 1 (out) Ext. buffer tristated +# SRST 0 1 (out) Translates to nSRST=Z + +# Unused 0 1 (out) +# GPIO_A 0 0 (in) +# GPIO_B 0 0 (in) +# Unused 0 1 (out) +# Unused 0 1 (out) +# GPIO_C 0 0 (in) +# GPIO_D 0 0 (in) +# Unused 0 1 (out) + +# Signals definition +ftdi layout_signal LED -ndata 0x0010 +ftdi layout_signal SWD_EN -data 0x0020 +ftdi layout_signal SWDIO_OE -ndata 0x0040 +ftdi layout_signal nSRST -oe 0x0080 + +ftdi layout_signal GPIO_A -data 0x0200 -oe 0x0200 -input 0x0200 +ftdi layout_signal GPIO_B -data 0x0400 -oe 0x0400 -input 0x0400 +ftdi layout_signal GPIO_C -data 0x2000 -oe 0x2000 -input 0x2000 +ftdi layout_signal GPIO_D -data 0x4000 -oe 0x4000 -input 0x4000 diff --git a/tcl/interface/ftdi/stm32-stick.cfg b/tcl/interface/ftdi/stm32-stick.cfg index 7ae02bd800..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 # @@ -5,9 +7,9 @@ # adapter driver ftdi -ftdi_device_desc "STM32-PerformanceStick" -ftdi_vid_pid 0x0640 0x002d +ftdi device_desc "STM32-PerformanceStick" +ftdi vid_pid 0x0640 0x002d -ftdi_layout_init 0x0388 0x038b -ftdi_layout_signal nTRST -data 0x0100 -ftdi_layout_signal nSRST -data 0x0080 -noe 0x200 +ftdi layout_init 0x0388 0x038b +ftdi layout_signal nTRST -data 0x0100 +ftdi layout_signal nSRST -data 0x0080 -noe 0x200 diff --git a/tcl/interface/ftdi/swd-resistor-hack.cfg b/tcl/interface/ftdi/swd-resistor-hack.cfg index 04f3a73975..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); @@ -5,7 +7,7 @@ # # You also need to have reliable GND connection between the target and # adapter. Vref of the adapter should be supplied with a voltage equal -# to the target's (preferrably connect it to Vcc). You can also +# to the target's (preferably connect it to Vcc). You can also # optionally connect nSRST. Leave everything else unconnected. # # FTDI Target @@ -23,4 +25,4 @@ transport select swd -ftdi_layout_signal SWD_EN -data 0 +ftdi layout_signal SWD_EN -data 0 diff --git a/tcl/interface/ftdi/ti-icdi.cfg b/tcl/interface/ftdi/ti-icdi.cfg index 55085eaee0..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. @@ -7,9 +9,9 @@ # adapter driver ftdi -ftdi_vid_pid 0x0451 0xc32a +ftdi vid_pid 0x0451 0xc32a -ftdi_layout_init 0x00a8 0x00eb -ftdi_layout_signal nSRST -noe 0x0020 -ftdi_layout_signal SWD_EN -ndata 0x0080 -ftdi_layout_signal SWDIO_OE -data 0x0008 +ftdi layout_init 0x00a8 0x00eb +ftdi layout_signal nSRST -noe 0x0020 +ftdi layout_signal SWD_EN -ndata 0x0080 +ftdi layout_signal SWDIO_OE -data 0x0008 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 7f576e91d2..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 # @@ -5,8 +7,8 @@ # adapter driver ftdi -ftdi_vid_pid 0x0403 0x8a99 +ftdi vid_pid 0x0403 0x8a99 -ftdi_layout_init 0x0038 0x087b -ftdi_layout_signal nTRST -data 0x0020 -oe 0x0020 -ftdi_layout_signal nSRST -data 0x0010 -oe 0x0010 +ftdi layout_init 0x0038 0x087b +ftdi layout_signal nTRST -data 0x0020 -oe 0x0020 +ftdi layout_signal nSRST -data 0x0010 -oe 0x0010 diff --git a/tcl/interface/ftdi/tumpa.cfg b/tcl/interface/ftdi/tumpa.cfg index 1a4e3cdfa3..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) # @@ -5,10 +7,10 @@ # adapter driver ftdi -ftdi_vid_pid 0x0403 0x8a98 0x0403 0x6010 +ftdi vid_pid 0x0403 0x8a98 0x0403 0x6010 -ftdi_layout_init 0x0038 0x087b -ftdi_layout_signal nTRST -data 0x0020 -ftdi_layout_signal nSRST -data 0x0010 +ftdi layout_init 0x0038 0x087b +ftdi layout_signal nTRST -data 0x0020 +ftdi layout_signal nSRST -data 0x0010 reset_config srst_push_pull diff --git a/tcl/interface/ftdi/turtelizer2-revB.cfg b/tcl/interface/ftdi/turtelizer2-revB.cfg index 34ae861298..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) # @@ -10,9 +12,9 @@ echo "in ft2232.c. Please report your experience with this file to openocd-devel echo "mailing list, so it could be marked as working or fixed." adapter driver ftdi -ftdi_device_desc "Turtelizer JTAG/RS232 Adapter" -ftdi_vid_pid 0x0403 0xbdc8 +ftdi device_desc "Turtelizer JTAG/RS232 Adapter" +ftdi vid_pid 0x0403 0xbdc8 -ftdi_layout_init 0x0008 0x0c5b -ftdi_layout_signal nSRST -oe 0x0040 -ftdi_layout_signal LED -data 0x0c00 +ftdi layout_init 0x0008 0x0c5b +ftdi layout_signal nSRST -oe 0x0040 +ftdi layout_signal LED -data 0x0c00 diff --git a/tcl/interface/ftdi/turtelizer2-revC.cfg b/tcl/interface/ftdi/turtelizer2-revC.cfg index f5192fb310..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) # @@ -5,10 +7,10 @@ # adapter driver ftdi -ftdi_device_desc "Turtelizer JTAG/RS232 Adapter" -ftdi_vid_pid 0x0403 0xbdc8 +ftdi device_desc "Turtelizer JTAG/RS232 Adapter" +ftdi vid_pid 0x0403 0xbdc8 -ftdi_layout_init 0x0008 0x0c7b -ftdi_layout_signal nTRST -oe 0x0020 -ftdi_layout_signal nSRST -oe 0x0040 -ftdi_layout_signal LED -ndata 0x0c00 +ftdi layout_init 0x0008 0x0c7b +ftdi layout_signal nTRST -oe 0x0020 +ftdi layout_signal nSRST -oe 0x0040 +ftdi layout_signal LED -ndata 0x0c00 diff --git a/tcl/interface/ftdi/um232h.cfg b/tcl/interface/ftdi/um232h.cfg index 2dabbec4a6..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 # @@ -8,12 +10,12 @@ # adapter driver ftdi -#ftdi_device_desc "UM232H" -ftdi_vid_pid 0x0403 0x6014 +#ftdi device_desc "UM232H" +ftdi vid_pid 0x0403 0x6014 -ftdi_layout_init 0xfff8 0xfffb -ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100 -ftdi_layout_signal nSRST -data 0x0200 -oe 0x0200 +ftdi layout_init 0xfff8 0xfffb +ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 +ftdi layout_signal nSRST -data 0x0200 -oe 0x0200 # UM232H FT232H JTAG # Name Pin Name Func diff --git a/tcl/interface/ftdi/vpaclink.cfg b/tcl/interface/ftdi/vpaclink.cfg index ed4895a6bd..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 # @@ -11,9 +13,9 @@ echo "experience with this file to openocd-devel mailing list, so it could be ma echo "as working or fixed." adapter driver ftdi -ftdi_device_desc "VPACLink" -ftdi_vid_pid 0x0403 0x6010 +ftdi device_desc "VPACLink" +ftdi vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0508 0x0f1b -ftdi_layout_signal nTRST -data 0x0200 -noe 0x0100 -ftdi_layout_signal nSRST -data 0x0800 -noe 0x0400 +ftdi layout_init 0x0508 0x0f1b +ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 +ftdi layout_signal nSRST -data 0x0800 -noe 0x0400 diff --git a/tcl/interface/ftdi/xds100v2.cfg b/tcl/interface/ftdi/xds100v2.cfg index 860a7585d9..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 # @@ -8,9 +10,9 @@ # adapter driver ftdi -ftdi_vid_pid 0x0403 0xa6d0 0x0403 0x6010 +ftdi vid_pid 0x0403 0xa6d0 0x0403 0x6010 -ftdi_layout_init 0x0038 0x597b +ftdi layout_init 0x0038 0x597b # 8000 z - unused # 4000 0 > CPLD loopback (all target side pins high-Z) @@ -45,14 +47,14 @@ ftdi_layout_init 0x0038 0x597b # changing the USB configuration to zero.) # -ftdi_layout_signal nTRST -data 0x0010 -ftdi_layout_signal nSRST -oe 0x0100 -ftdi_layout_signal EMU_EN -data 0x0020 -ftdi_layout_signal EMU0 -oe 0x0040 -ftdi_layout_signal EMU1 -oe 0x1000 -ftdi_layout_signal PWR_RST -data 0x0800 -ftdi_layout_signal LOOPBACK -data 0x4000 +ftdi layout_signal nTRST -data 0x0010 +ftdi layout_signal nSRST -oe 0x0100 +ftdi layout_signal EMU_EN -data 0x0020 +ftdi layout_signal EMU0 -oe 0x0040 +ftdi layout_signal EMU1 -oe 0x1000 +ftdi layout_signal PWR_RST -data 0x0800 +ftdi layout_signal LOOPBACK -data 0x4000 -echo "\nInfo : to use this adapter you MUST add ``init; ftdi_set_signal PWR_RST 1; jtag arp_init'' to the end of your config file!\n" +echo "\nInfo : to use this adapter you MUST add ``init; ftdi set_signal PWR_RST 1; jtag arp_init'' to the end of your config file!\n" # note: rising edge on PWR_RST is also needed after power-cycling the # target diff --git a/tcl/interface/ftdi/xds100v3.cfg b/tcl/interface/ftdi/xds100v3.cfg index 6c705823ad..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 # @@ -8,4 +10,4 @@ source [find interface/ftdi/xds100v2.cfg] # The USB ids are different. -ftdi_vid_pid 0x0403 0xa6d1 +ftdi vid_pid 0x0403 0xa6d1 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 51f420b7ff..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 # @@ -11,4 +13,4 @@ adapter driver jlink # # Example: Select J-Link with serial number 123456789 # -# jlink serial 123456789 +# adapter serial 123456789 diff --git a/tcl/interface/jtag_dpi.cfg b/tcl/interface/jtag_dpi.cfg new file mode 100644 index 0000000000..225d4d5451 --- /dev/null +++ b/tcl/interface/jtag_dpi.cfg @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Provide support for the Cadence JTAG BFM +# +# Copyright (c) 2020, Ampere Computing LLC +# + +adapter driver jtag_dpi + +# Set the DPI JTAG server port +if { [info exists DPI_PORT] } { + set _DPI_PORT $DPI_PORT +} else { + set _DPI_PORT 5555 +} + +# Set the DPI JTAG server address +if { [info exists DPI_ADDRESS] } { + set _DPI_ADDRESS $DPI_ADDRESS +} else { + set _DPI_ADDRESS "127.0.0.1" +} + +jtag_dpi set_port $_DPI_PORT +jtag_dpi set_address $_DPI_ADDRESS diff --git a/tcl/interface/jtag_hat_rpi2.cfg b/tcl/interface/jtag_hat_rpi2.cfg new file mode 100644 index 0000000000..cd1cbfb8af --- /dev/null +++ b/tcl/interface/jtag_hat_rpi2.cfg @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Blinkinlabs JTAG_Hat +# +# https://github.com/blinkinlabs/jtag_hat +# + +adapter driver bcm2835gpio + +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 +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 +adapter gpio swclk -chip 0 11 +adapter gpio swdio -chip 0 25 + +# Direction pin for SWDIO level shifting buffer +adapter gpio swdio_dir -chip 0 6 + +# 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 + +# or if you have both connected +#reset_config trst_and_srst diff --git a/tcl/interface/jtag_vpi.cfg b/tcl/interface/jtag_vpi.cfg index e665a6331d..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 @@ -14,5 +16,5 @@ if { [info exists VPI_ADDRESS] } { set _VPI_ADDRESS "127.0.0.1" } -jtag_vpi_set_port $_VPI_PORT -jtag_vpi_set_address $_VPI_ADDRESS +jtag_vpi set_port $_VPI_PORT +jtag_vpi set_address $_VPI_ADDRESS diff --git a/tcl/interface/kitprog.cfg b/tcl/interface/kitprog.cfg index 29fce489bf..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 # @@ -9,4 +11,4 @@ adapter driver kitprog # Optionally specify the serial number of the KitProg you want to use. -#kitprog_serial 1926402735485200 +# adapter serial 1926402735485200 diff --git a/tcl/interface/nds32-aice.cfg b/tcl/interface/nds32-aice.cfg deleted file mode 100644 index 3b21025b51..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" -aice 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 9a5827b147..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 # @@ -5,4 +7,4 @@ # adapter driver openjtag -openjtag_device_desc "Open JTAG Project" +openjtag device_desc "Open JTAG Project" 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 4c0b260b9f..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 # @@ -15,5 +17,5 @@ if { [info exists PARPORTADDR] } { } adapter driver parport -parport_port $_PARPORTADDR -parport_cable wiggler +parport port $_PARPORTADDR +parport cable wiggler diff --git a/tcl/interface/parport_dlc5.cfg b/tcl/interface/parport_dlc5.cfg index e9beaaf414..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) # @@ -11,5 +13,5 @@ if { [info exists PARPORTADDR] } { } adapter driver parport -parport_port $_PARPORTADDR -parport_cable dlc5 +parport port $_PARPORTADDR +parport cable dlc5 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 2d0547f310..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 e53b0f3b02..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 ac4de18f9b..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 +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 @@ -17,4 +19,4 @@ st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0 # Optionally specify the serial number of usb device # e.g. -# st-link serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" +# adapter serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" 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 54cd63eb69..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,11 +8,11 @@ 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 +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 # firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial # number reset issues. # eg. -#hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" +# adapter serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" diff --git a/tcl/interface/sysfsgpio-raspberrypi.cfg b/tcl/interface/sysfsgpio-raspberrypi.cfg index ebb1502193..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 # @@ -12,19 +14,19 @@ adapter driver sysfsgpio # Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Header pin numbers: 23 22 19 21 -sysfsgpio_jtag_nums 11 25 10 9 +sysfsgpio jtag_nums 11 25 10 9 # Each of the SWD lines need a gpio number set: swclk swdio # Header pin numbers: 23 22 -sysfsgpio_swd_nums 11 25 +sysfsgpio swd_nums 11 25 # If you define trst or srst, use appropriate reset_config # Header pin numbers: TRST - 26, SRST - 18 -# sysfsgpio_trst_num 7 +# sysfsgpio trst_num 7 # reset_config trst_only -# sysfsgpio_srst_num 24 +# sysfsgpio srst_num 24 # reset_config srst_only srst_push_pull # or if you have both connected, diff --git a/tcl/interface/ti-icdi.cfg b/tcl/interface/ti-icdi.cfg index 9b46b437ca..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 # @@ -11,3 +13,7 @@ adapter driver hla hla_layout ti-icdi hla_vid_pid 0x1cbe 0x00fd +# Optionally specify the serial number of TI-ICDI devices, for when using +# multiple devices. Serial numbers can be obtained using lsusb -v +# Ex. +# adapter serial "0F003065" 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 8617c78c36..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 @@ -30,8 +32,8 @@ # driver but ixo-usb-jtag requires the ftdi driver. adapter driver usb_blaster -usb_blaster_vid_pid 0x16C0 0x06AD -usb_blaster_device_desc "Van Ooijen Technische Informatica" +usb_blaster vid_pid 0x16C0 0x06AD +usb_blaster device_desc "Van Ooijen Technische Informatica" # ixo-usb-jtag is only compatible with the ublast1 protocol implemented via the # ftdi modes, using ublast2 will cause openocd to hang. -usb_blaster_lowlevel_driver ftdi +usb_blaster lowlevel_driver ftdi 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 new file mode 100644 index 0000000000..7350bb9a91 --- /dev/null +++ b/tcl/interface/vdebug.cfg @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface + +if { [info exists VDEBUGHOST] } { + set _VDEBUGHOST $VDEBUGHOST +} else { + set _VDEBUGHOST localhost +} +if { [info exists VDEBUGPORT] } { + set _VDEBUGPORT $VDEBUGPORT +} else { + set _VDEBUGPORT 8192 +} + +adapter driver vdebug +# vdebug server:port +vdebug server $_VDEBUGHOST:$_VDEBUGPORT + +# example config debug level and log +#debug_level 3 +#log_output vd_ocd.log + +# example config listen on all interfaces, disable tcl/telnet server +bindto 0.0.0.0 +#gdb_port 3333 +#telnet_port disabled +tcl_port disabled + +# transaction batching: 0 - no batching, 1 - (default) wr, 2 - rw +vdebug batching 1 + +# Polling values +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 edc438d3bd..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 # @@ -9,4 +11,4 @@ adapter driver xds110 # Use serial number option to use a specific XDS110 # when more than one are connected to the host. -#xds110_serial 00000000 +# adapter serial 00000000 diff --git a/tcl/mem_helper.tcl b/tcl/mem_helper.tcl index 5955793e25..0229d54b78 100644 --- a/tcl/mem_helper.tcl +++ b/tcl/mem_helper.tcl @@ -1,10 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Helper for common memory read/modify/write procedures # mrw: "memory read word", returns value of $reg proc mrw {reg} { - set value "" - mem2array value 32 $reg 1 - return $value(0) + return [read_memory $reg 32 1] } add_usage_text mrw "address" @@ -12,9 +12,7 @@ add_help_text mrw "Returns value of word in memory." # mrh: "memory read halfword", returns value of $reg proc mrh {reg} { - set value "" - mem2array value 16 $reg 1 - return $value(0) + return [read_memory $reg 16 1] } add_usage_text mrh "address" @@ -22,9 +20,7 @@ add_help_text mrh "Returns value of halfword in memory." # mrb: "memory read byte", returns value of $reg proc mrb {reg} { - set value "" - mem2array value 8 $reg 1 - return $value(0) + return [read_memory $reg 8 1] } add_usage_text mrb "address" @@ -34,7 +30,7 @@ add_help_text mrb "Returns value of byte in memory." # $reg <== ((value & ~$clearbits) | $setbits) proc mmw {reg setbits clearbits} { set old [mrw $reg] - set new [expr ($old & ~$clearbits) | $setbits] + set new [expr {($old & ~$clearbits) | $setbits}] mww $reg $new } diff --git a/tcl/memory.tcl b/tcl/memory.tcl index 3066c11139..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. @@ -43,9 +45,9 @@ set RWX_NO_ACCESS 0 set RWX_X_ONLY $BIT0 set RWX_W_ONLY $BIT1 set RWX_R_ONLY $BIT2 -set RWX_RW [expr $RWX_R_ONLY + $RWX_W_ONLY] -set RWX_R_X [expr $RWX_R_ONLY + $RWX_X_ONLY] -set RWX_RWX [expr $RWX_R_ONLY + $RWX_W_ONLY + $RWX_X_ONLY] +set RWX_RW [expr {$RWX_R_ONLY + $RWX_W_ONLY}] +set RWX_R_X [expr {$RWX_R_ONLY + $RWX_X_ONLY}] +set RWX_RWX [expr {$RWX_R_ONLY + $RWX_W_ONLY + $RWX_X_ONLY}] set UNKNOWN(0,RWX) $RWX_NO_ACCESS # WIDTH - access width @@ -54,11 +56,11 @@ set ACCESS_WIDTH_NONE 0 set ACCESS_WIDTH_8 $BIT0 set ACCESS_WIDTH_16 $BIT1 set ACCESS_WIDTH_32 $BIT2 -set ACCESS_WIDTH_ANY [expr $ACCESS_WIDTH_8 + $ACCESS_WIDTH_16 + $ACCESS_WIDTH_32] +set ACCESS_WIDTH_ANY [expr {$ACCESS_WIDTH_8 + $ACCESS_WIDTH_16 + $ACCESS_WIDTH_32}] set UNKNOWN(0,ACCESS_WIDTH) $ACCESS_WIDTH_NONE proc iswithin { ADDRESS BASE LEN } { - return [expr ((($ADDRESS - $BASE) >= 0) && (($BASE + $LEN - $ADDRESS) > 0))] + return [expr {(($ADDRESS - $BASE) >= 0) && (($BASE + $LEN - $ADDRESS) > 0)}] } proc address_info { ADDRESS } { @@ -79,108 +81,96 @@ proc address_info { ADDRESS } { } proc memread32 {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 32 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 32 1] } msg ] { + return $foo } else { error "memread32: $msg" } } proc memread16 {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 16 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 16 1] } msg ] { + return $foo } else { error "memread16: $msg" } } proc memread8 {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 8 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 8 1] } msg ] { + return $foo } else { error "memread8: $msg" } } proc memwrite32 {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 32 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 32 $DATA } msg ] { + return $DATA } else { error "memwrite32: $msg" } } proc memwrite16 {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 16 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 16 $DATA } msg ] { + return $DATA } else { error "memwrite16: $msg" } } proc memwrite8 {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 8 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 8 $DATA } msg ] { + return $DATA } else { error "memwrite8: $msg" } } proc memread32_phys {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 32 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 32 1 phys] } msg ] { + return $foo } else { error "memread32: $msg" } } proc memread16_phys {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 16 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 16 1 phys] } msg ] { + return $foo } else { error "memread16: $msg" } } proc memread8_phys {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 8 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 8 1 phys] } msg ] { + return $foo } else { error "memread8: $msg" } } proc memwrite32_phys {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 32 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 32 $DATA phys } msg ] { + return $DATA } else { error "memwrite32: $msg" } } proc memwrite16_phys {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 16 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 16 $DATA phys } msg ] { + return $DATA } else { error "memwrite16: $msg" } } proc memwrite8_phys {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 8 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 8 $DATA phys } msg ] { + return $DATA } else { error "memwrite8: $msg" } diff --git a/tcl/mmr_helpers.tcl b/tcl/mmr_helpers.tcl index e6b1c67042..5c37fcfdc1 100644 --- a/tcl/mmr_helpers.tcl +++ b/tcl/mmr_helpers.tcl @@ -1,8 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later proc proc_exists { NAME } { set n [info commands $NAME] set l [string length $n] - return [expr $l != 0] + return [expr {$l != 0}] } # Give: REGISTER name - must be a global variable. @@ -45,14 +46,14 @@ proc show_mmr32_bits { NAMES VAL } { for { set x 24 } { $x >= 0 } { incr x -8 } { echo -n " " for { set y 7 } { $y >= 0 } { incr y -1 } { - set s $MYNAMES([expr $x + $y]) - echo -n [format "%2d: %-*s | " [expr $x + $y] $w $s ] + set s $MYNAMES([expr {$x + $y}]) + echo -n [format "%2d: %-*s | " [expr {$x + $y}] $w $s ] } echo "" echo -n " " for { set y 7 } { $y >= 0 } { incr y -1 } { - echo -n [format " %d%*s | " [expr !!($VAL & (1 << ($x + $y)))] [expr $w -1] ""] + echo -n [format " %d%*s | " [expr {!!($VAL & (1 << ($x + $y)))}] [expr {$w -1}] ""] } echo "" } @@ -60,7 +61,7 @@ proc show_mmr32_bits { NAMES VAL } { proc show_mmr_bitfield { MSB LSB VAL FIELDNAME FIELDVALUES } { - set width [expr (($MSB - $LSB + 1) + 7) / 4] + set width [expr {(($MSB - $LSB + 1) + 7) / 4}] set nval [show_normalize_bitfield $VAL $MSB $LSB ] set name0 [lindex $FIELDVALUES 0 ] if [ string compare $name0 _NUMBER_ ] { @@ -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/1986\320\262\320\2651\321\202.cfg" "b/tcl/target/1986\320\262\320\2651\321\202.cfg" index b7c9d63316..a3172ccab1 100644 --- "a/tcl/target/1986\320\262\320\2651\321\202.cfg" +++ "b/tcl/target/1986\320\262\320\2651\321\202.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/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 02d8c7e82e..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] } { @@ -85,8 +87,8 @@ $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x4000 # FIXME: unify with target/am437x.cfg source [find mem_helper.tcl] set WDT1_BASE_ADDR 0x44e35000 -set WDT1_W_PEND_WSPR [expr $WDT1_BASE_ADDR + 0x0034] -set WDT1_WSPR [expr $WDT1_BASE_ADDR + 0x0048] +set WDT1_W_PEND_WSPR [expr {$WDT1_BASE_ADDR + 0x0034}] +set WDT1_WSPR [expr {$WDT1_BASE_ADDR + 0x0048}] proc disable_watchdog { } { global WDT1_WSPR global WDT1_W_PEND_WSPR @@ -103,10 +105,10 @@ proc disable_watchdog { } { # Empty body to make sure this executes as fast as possible. # We don't want any delays here otherwise romcode might start # executing and end up changing state of certain IPs. - while { [expr [mrw $WDT1_W_PEND_WSPR] & 0x10] } { } + while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } mww phys $WDT1_WSPR $WDT_DISABLE_SEQ2 - while { [expr [mrw $WDT1_W_PEND_WSPR] & 0x10] } { } + while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } } } $_TARGETNAME configure -event reset-end { disable_watchdog } diff --git a/tcl/target/am437x.cfg b/tcl/target/am437x.cfg index 8ce0941df0..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] @@ -5,432 +7,432 @@ source [find mem_helper.tcl] ## AM437x Registers ## ############################################################################### set PRCM_BASE_ADDR 0x44df0000 -set REVISION_PRM [expr $PRCM_BASE_ADDR + 0x0000] -set PRM_IRQSTATUS_MPU [expr $PRCM_BASE_ADDR + 0x0004] -set PRM_IRQENABLE_MPU [expr $PRCM_BASE_ADDR + 0x0008] -set PRM_IRQSTATUS_M3 [expr $PRCM_BASE_ADDR + 0x000c] -set PRM_IRQENABLE_M3 [expr $PRCM_BASE_ADDR + 0x0010] -set PM_MPU_PWRSTCTRL [expr $PRCM_BASE_ADDR + 0x0300] -set PM_MPU_PWRSTST [expr $PRCM_BASE_ADDR + 0x0304] -set RM_MPU_RSTST [expr $PRCM_BASE_ADDR + 0x0314] -set RM_MPU_CONTEXT [expr $PRCM_BASE_ADDR + 0x0324] -set PM_GFX_PWRSTCTRL [expr $PRCM_BASE_ADDR + 0x0400] -set PM_GFX_PWRSTST [expr $PRCM_BASE_ADDR + 0x0404] -set RM_GFX_RSTCTRL [expr $PRCM_BASE_ADDR + 0x0410] -set RM_GFX_RSTST [expr $PRCM_BASE_ADDR + 0x0414] -set RM_GFX_CONTEXT [expr $PRCM_BASE_ADDR + 0x0424] -set RM_RTC_CONTEXT [expr $PRCM_BASE_ADDR + 0x0524] -set RM_WKUP_RSTCTRL [expr $PRCM_BASE_ADDR + 0x2010] -set RM_WKUP_RSTST [expr $PRCM_BASE_ADDR + 0x2014] -set CM_L3_AON_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x2800] -set CM_WKUP_DEBUGSS_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2820] -set CM_L3S_TSC_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x2900] -set CM_WKUP_ADC_TSC_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2920] -set CM_L4_WKUP_AON_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x2a00] -set CM_WKUP_L4WKUP_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2a20] -set CM_WKUP_WKUP_M3_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2a28] -set CM_WKUP_SYNCTIMER_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2a30] -set CM_WKUP_CLKDIV32K_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2a38] -set CM_WKUP_USBPHY0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2a40] -set CM_WKUP_USBPHY1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2a48] -set CM_WKUP_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x2b00] -set CM_WKUP_TIMER0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2b20] -set CM_WKUP_TIMER1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2b28] -set CM_WKUP_WDT0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2b30] -set CM_WKUP_WDT1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2b38] -set CM_WKUP_I2C0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2b40] -set CM_WKUP_UART0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2b48] -set CM_WKUP_SMARTREFLEX0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2b50] -set CM_WKUP_SMARTREFLEX1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2b58] -set CM_WKUP_CONTROL_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2b60] -set CM_WKUP_GPIO0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x2b68] -set CM_CLKMODE_DPLL_CORE [expr $PRCM_BASE_ADDR + 0x2d20] -set CM_IDLEST_DPLL_CORE [expr $PRCM_BASE_ADDR + 0x2d24] -set CM_CLKSEL_DPLL_CORE [expr $PRCM_BASE_ADDR + 0x2d2c] -set CM_DIV_M4_DPLL_CORE [expr $PRCM_BASE_ADDR + 0x2d38] -set CM_DIV_M5_DPLL_CORE [expr $PRCM_BASE_ADDR + 0x2d3c] -set CM_DIV_M6_DPLL_CORE [expr $PRCM_BASE_ADDR + 0x2d40] -set CM_SSC_DELTAMSTEP_DPLL_CORE [expr $PRCM_BASE_ADDR + 0x2d48] -set CM_SSC_MODFREQDIV_DPLL_CORE [expr $PRCM_BASE_ADDR + 0x2d4c] -set CM_CLKMODE_DPLL_MPU [expr $PRCM_BASE_ADDR + 0x2d60] -set CM_IDLEST_DPLL_MPU [expr $PRCM_BASE_ADDR + 0x2d64] -set CM_CLKSEL_DPLL_MPU [expr $PRCM_BASE_ADDR + 0x2d6c] -set CM_DIV_M2_DPLL_MPU [expr $PRCM_BASE_ADDR + 0x2d70] -set CM_SSC_DELTAMSTEP_DPLL_MPU [expr $PRCM_BASE_ADDR + 0x2d88] -set CM_SSC_MODFREQDIV_DPLL_MPU [expr $PRCM_BASE_ADDR + 0x2d8c] -set CM_CLKMODE_DPLL_DDR [expr $PRCM_BASE_ADDR + 0x2da0] -set CM_IDLEST_DPLL_DDR [expr $PRCM_BASE_ADDR + 0x2da4] -set CM_CLKSEL_DPLL_DDR [expr $PRCM_BASE_ADDR + 0x2dac] -set CM_DIV_M2_DPLL_DDR [expr $PRCM_BASE_ADDR + 0x2db0] -set CM_DIV_M4_DPLL_DDR [expr $PRCM_BASE_ADDR + 0x2db8] -set CM_SSC_DELTAMSTEP_DPLL_DDR [expr $PRCM_BASE_ADDR + 0x2dc8] -set CM_SSC_MODFREQDIV_DPLL_DDR [expr $PRCM_BASE_ADDR + 0x2dcc] -set CM_CLKMODE_DPLL_PER [expr $PRCM_BASE_ADDR + 0x2de0] -set CM_IDLEST_DPLL_PER [expr $PRCM_BASE_ADDR + 0x2de4] -set CM_CLKSEL_DPLL_PER [expr $PRCM_BASE_ADDR + 0x2dec] -set CM_DIV_M2_DPLL_PER [expr $PRCM_BASE_ADDR + 0x2df0] -set CM_CLKSEL2_DPLL_PER [expr $PRCM_BASE_ADDR + 0x2e04] -set CM_SSC_DELTAMSTEP_DPLL_PER [expr $PRCM_BASE_ADDR + 0x2e08] -set CM_SSC_MODFREQDIV_DPLL_PER [expr $PRCM_BASE_ADDR + 0x2e0c] -set CM_CLKDCOLDO_DPLL_PER [expr $PRCM_BASE_ADDR + 0x2e14] -set CM_CLKMODE_DPLL_DISP [expr $PRCM_BASE_ADDR + 0x2e20] -set CM_IDLEST_DPLL_DISP [expr $PRCM_BASE_ADDR + 0x2e24] -set CM_CLKSEL_DPLL_DISP [expr $PRCM_BASE_ADDR + 0x2e2c] -set CM_DIV_M2_DPLL_DISP [expr $PRCM_BASE_ADDR + 0x2e30] -set CM_SSC_DELTAMSTEP_DPLL_DISP [expr $PRCM_BASE_ADDR + 0x2e48] -set CM_SSC_MODFREQDIV_DPLL_DISP [expr $PRCM_BASE_ADDR + 0x2e4c] -set CM_CLKMODE_DPLL_EXTDEV [expr $PRCM_BASE_ADDR + 0x2e60] -set CM_IDLEST_DPLL_EXTDEV [expr $PRCM_BASE_ADDR + 0x2e64] -set CM_CLKSEL_DPLL_EXTDEV [expr $PRCM_BASE_ADDR + 0x2e6c] -set CM_DIV_M2_DPLL_EXTDEV [expr $PRCM_BASE_ADDR + 0x2e70] -set CM_CLKSEL2_DPLL_EXTDEV [expr $PRCM_BASE_ADDR + 0x2e84] -set CM_SSC_DELTAMSTEP_DPLL_EXTDEV [expr $PRCM_BASE_ADDR + 0x2e88] -set CM_SSC_MODFREQDIV_DPLL_EXTDEV [expr $PRCM_BASE_ADDR + 0x2e8c] -set CM_SHADOW_FREQ_CONFIG1 [expr $PRCM_BASE_ADDR + 0x2fa0] -set CM_SHADOW_FREQ_CONFIG2 [expr $PRCM_BASE_ADDR + 0x2fa4] -set CM_CLKOUT1_CTRL [expr $PRCM_BASE_ADDR + 0x4100] -set CM_DLL_CTRL [expr $PRCM_BASE_ADDR + 0x4104] -set CM_CLKOUT2_CTRL [expr $PRCM_BASE_ADDR + 0x4108] -set CLKSEL_TIMER1MS_CLK [expr $PRCM_BASE_ADDR + 0x4200] -set CLKSEL_TIMER2_CLK [expr $PRCM_BASE_ADDR + 0x4204] -set CLKSEL_TIMER3_CLK [expr $PRCM_BASE_ADDR + 0x4208] -set CLKSEL_TIMER4_CLK [expr $PRCM_BASE_ADDR + 0x420c] -set CLKSEL_TIMER5_CLK [expr $PRCM_BASE_ADDR + 0x4210] -set CLKSEL_TIMER6_CLK [expr $PRCM_BASE_ADDR + 0x4214] -set CLKSEL_TIMER7_CLK [expr $PRCM_BASE_ADDR + 0x4218] -set CLKSEL_TIMER8_CLK [expr $PRCM_BASE_ADDR + 0x421c] -set CLKSEL_TIMER9_CLK [expr $PRCM_BASE_ADDR + 0x4220] -set CLKSEL_TIMER10_CLK [expr $PRCM_BASE_ADDR + 0x4224] -set CLKSEL_TIMER11_CLK [expr $PRCM_BASE_ADDR + 0x4228] -set CLKSEL_WDT1_CLK [expr $PRCM_BASE_ADDR + 0x422c] -set CLKSEL_SYNCTIMER_CLK [expr $PRCM_BASE_ADDR + 0x4230] -set CLKSEL_MAC_CLK [expr $PRCM_BASE_ADDR + 0x4234] -set CLKSEL_CPTS_RFT_CLK [expr $PRCM_BASE_ADDR + 0x4238] -set CLKSEL_GFX_FCLK [expr $PRCM_BASE_ADDR + 0x423c] -set CLKSEL_GPIO0_DBCLK [expr $PRCM_BASE_ADDR + 0x4240] -set CLKSEL_LCDC_PIXEL_CLK [expr $PRCM_BASE_ADDR + 0x4244] -set CLKSEL_ICSS_OCP_CLK [expr $PRCM_BASE_ADDR + 0x4248] -set CLKSEL_DLL_AGING_CLK [expr $PRCM_BASE_ADDR + 0x4250] -set CLKSEL_USBPHY32KHZ_GCLK [expr $PRCM_BASE_ADDR + 0x4260] -set CM_MPU_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x8300] -set CM_MPU_MPU_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8320] -set CM_GFX_L3_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x8400] -set CM_GFX_GFX_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8420] -set CM_RTC_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x8500] -set CM_RTC_RTC_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8520] -set CM_PER_L3_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x8800] -set CM_PER_L3_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8820] -set CM_PER_AES0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8828] -set CM_PER_DES_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8830] -set CM_PER_CRYPTODMA_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8838] -set CM_PER_L3_INSTR_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8840] -set CM_PER_MSTR_EXPS_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8848] -set CM_PER_OCMCRAM_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8850] -set CM_PER_SHA0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8858] -set CM_PER_SLV_EXPS_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8860] -set CM_PER_VPFE0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8868] -set CM_PER_VPFE1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8870] -set CM_PER_TPCC_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8878] -set CM_PER_TPTC0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8880] -set CM_PER_TPTC1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8888] -set CM_PER_TPTC2_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8890] -set CM_PER_DLL_AGING_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8898] -set CM_PER_L4HS_CLKCTRL [expr $PRCM_BASE_ADDR + 0x88a0] -set CM_PER_L4FW_CLKCTRL [expr $PRCM_BASE_ADDR + 0x88a8] -set CM_PER_L3S_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x8a00] -set CM_PER_GPMC_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8a20] -set CM_PER_IEEE5000_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8a28] -set CM_PER_MCASP0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8a38] -set CM_PER_MCASP1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8a40] -set CM_PER_MMC2_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8a48] -set CM_PER_QSPI_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8a58] -set CM_PER_USB_OTG_SS0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8a60] -set CM_PER_USB_OTG_SS1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8a68] -set CM_PER_ICSS_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x8b00] -set CM_PER_ICSS_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8b20] -set CM_PER_L4LS_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x8c00] -set CM_PER_L4LS_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c20] -set CM_PER_DCAN0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c28] -set CM_PER_DCAN1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c30] -set CM_PER_EPWMSS0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c38] -set CM_PER_EPWMSS1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c40] -set CM_PER_EPWMSS2_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c48] -set CM_PER_EPWMSS3_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c50] -set CM_PER_EPWMSS4_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c58] -set CM_PER_EPWMSS5_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c60] -set CM_PER_ELM_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c68] -set CM_PER_GPIO1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c78] -set CM_PER_GPIO2_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c80] -set CM_PER_GPIO3_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c88] -set CM_PER_GPIO4_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c90] -set CM_PER_GPIO5_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8c98] -set CM_PER_HDQ1W_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8ca0] -set CM_PER_I2C1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8ca8] -set CM_PER_I2C2_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8cb0] -set CM_PER_MAILBOX0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8cb8] -set CM_PER_MMC0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8cc0] -set CM_PER_MMC1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8cc8] -set CM_PER_PKA_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8cd0] -set CM_PER_RNG_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8ce0] -set CM_PER_SPARE0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8ce8] -set CM_PER_SPARE1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8cf0] -set CM_PER_SPI0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d00] -set CM_PER_SPI1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d08] -set CM_PER_SPI2_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d10] -set CM_PER_SPI3_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d18] -set CM_PER_SPI4_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d20] -set CM_PER_SPINLOCK_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d28] -set CM_PER_TIMER2_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d30] -set CM_PER_TIMER3_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d38] -set CM_PER_TIMER4_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d40] -set CM_PER_TIMER5_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d48] -set CM_PER_TIMER6_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d50] -set CM_PER_TIMER7_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d58] -set CM_PER_TIMER8_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d60] -set CM_PER_TIMER9_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d68] -set CM_PER_TIMER10_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d70] -set CM_PER_TIMER11_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d78] -set CM_PER_UART1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d80] -set CM_PER_UART2_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d88] -set CM_PER_UART3_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d90] -set CM_PER_UART4_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8d98] -set CM_PER_UART5_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8da0] -set CM_PER_USBPHYOCP2SCP0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8db8] -set CM_PER_USBPHYOCP2SCP1_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8dc0] -set CM_PER_EMIF_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x8f00] -set CM_PER_EMIF_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8f20] -set CM_PER_DLL_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8f28] -set CM_PER_EMIF_FW_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8f30] -set CM_PER_OTFA_EMIF_CLKCTRL [expr $PRCM_BASE_ADDR + 0x8f38] -set CM_PER_DSS_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x9200] -set CM_PER_DSS_CLKCTRL [expr $PRCM_BASE_ADDR + 0x9220] -set CM_PER_CPSW_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x9300] -set CM_PER_CPGMAC0_CLKCTRL [expr $PRCM_BASE_ADDR + 0x9320] -set CM_PER_OCPWP_L3_CLKSTCTRL [expr $PRCM_BASE_ADDR + 0x9400] -set CM_PER_OCPWP_CLKCTRL [expr $PRCM_BASE_ADDR + 0x9420] +set REVISION_PRM [expr {$PRCM_BASE_ADDR + 0x0000}] +set PRM_IRQSTATUS_MPU [expr {$PRCM_BASE_ADDR + 0x0004}] +set PRM_IRQENABLE_MPU [expr {$PRCM_BASE_ADDR + 0x0008}] +set PRM_IRQSTATUS_M3 [expr {$PRCM_BASE_ADDR + 0x000c}] +set PRM_IRQENABLE_M3 [expr {$PRCM_BASE_ADDR + 0x0010}] +set PM_MPU_PWRSTCTRL [expr {$PRCM_BASE_ADDR + 0x0300}] +set PM_MPU_PWRSTST [expr {$PRCM_BASE_ADDR + 0x0304}] +set RM_MPU_RSTST [expr {$PRCM_BASE_ADDR + 0x0314}] +set RM_MPU_CONTEXT [expr {$PRCM_BASE_ADDR + 0x0324}] +set PM_GFX_PWRSTCTRL [expr {$PRCM_BASE_ADDR + 0x0400}] +set PM_GFX_PWRSTST [expr {$PRCM_BASE_ADDR + 0x0404}] +set RM_GFX_RSTCTRL [expr {$PRCM_BASE_ADDR + 0x0410}] +set RM_GFX_RSTST [expr {$PRCM_BASE_ADDR + 0x0414}] +set RM_GFX_CONTEXT [expr {$PRCM_BASE_ADDR + 0x0424}] +set RM_RTC_CONTEXT [expr {$PRCM_BASE_ADDR + 0x0524}] +set RM_WKUP_RSTCTRL [expr {$PRCM_BASE_ADDR + 0x2010}] +set RM_WKUP_RSTST [expr {$PRCM_BASE_ADDR + 0x2014}] +set CM_L3_AON_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2800}] +set CM_WKUP_DEBUGSS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2820}] +set CM_L3S_TSC_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2900}] +set CM_WKUP_ADC_TSC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2920}] +set CM_L4_WKUP_AON_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2a00}] +set CM_WKUP_L4WKUP_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a20}] +set CM_WKUP_WKUP_M3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a28}] +set CM_WKUP_SYNCTIMER_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a30}] +set CM_WKUP_CLKDIV32K_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a38}] +set CM_WKUP_USBPHY0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a40}] +set CM_WKUP_USBPHY1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2a48}] +set CM_WKUP_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x2b00}] +set CM_WKUP_TIMER0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b20}] +set CM_WKUP_TIMER1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b28}] +set CM_WKUP_WDT0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b30}] +set CM_WKUP_WDT1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b38}] +set CM_WKUP_I2C0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b40}] +set CM_WKUP_UART0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b48}] +set CM_WKUP_SMARTREFLEX0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b50}] +set CM_WKUP_SMARTREFLEX1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b58}] +set CM_WKUP_CONTROL_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b60}] +set CM_WKUP_GPIO0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x2b68}] +set CM_CLKMODE_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d20}] +set CM_IDLEST_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d24}] +set CM_CLKSEL_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d2c}] +set CM_DIV_M4_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d38}] +set CM_DIV_M5_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d3c}] +set CM_DIV_M6_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d40}] +set CM_SSC_DELTAMSTEP_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d48}] +set CM_SSC_MODFREQDIV_DPLL_CORE [expr {$PRCM_BASE_ADDR + 0x2d4c}] +set CM_CLKMODE_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d60}] +set CM_IDLEST_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d64}] +set CM_CLKSEL_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d6c}] +set CM_DIV_M2_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d70}] +set CM_SSC_DELTAMSTEP_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d88}] +set CM_SSC_MODFREQDIV_DPLL_MPU [expr {$PRCM_BASE_ADDR + 0x2d8c}] +set CM_CLKMODE_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2da0}] +set CM_IDLEST_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2da4}] +set CM_CLKSEL_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2dac}] +set CM_DIV_M2_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2db0}] +set CM_DIV_M4_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2db8}] +set CM_SSC_DELTAMSTEP_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2dc8}] +set CM_SSC_MODFREQDIV_DPLL_DDR [expr {$PRCM_BASE_ADDR + 0x2dcc}] +set CM_CLKMODE_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2de0}] +set CM_IDLEST_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2de4}] +set CM_CLKSEL_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2dec}] +set CM_DIV_M2_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2df0}] +set CM_CLKSEL2_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e04}] +set CM_SSC_DELTAMSTEP_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e08}] +set CM_SSC_MODFREQDIV_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e0c}] +set CM_CLKDCOLDO_DPLL_PER [expr {$PRCM_BASE_ADDR + 0x2e14}] +set CM_CLKMODE_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e20}] +set CM_IDLEST_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e24}] +set CM_CLKSEL_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e2c}] +set CM_DIV_M2_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e30}] +set CM_SSC_DELTAMSTEP_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e48}] +set CM_SSC_MODFREQDIV_DPLL_DISP [expr {$PRCM_BASE_ADDR + 0x2e4c}] +set CM_CLKMODE_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e60}] +set CM_IDLEST_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e64}] +set CM_CLKSEL_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e6c}] +set CM_DIV_M2_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e70}] +set CM_CLKSEL2_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e84}] +set CM_SSC_DELTAMSTEP_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e88}] +set CM_SSC_MODFREQDIV_DPLL_EXTDEV [expr {$PRCM_BASE_ADDR + 0x2e8c}] +set CM_SHADOW_FREQ_CONFIG1 [expr {$PRCM_BASE_ADDR + 0x2fa0}] +set CM_SHADOW_FREQ_CONFIG2 [expr {$PRCM_BASE_ADDR + 0x2fa4}] +set CM_CLKOUT1_CTRL [expr {$PRCM_BASE_ADDR + 0x4100}] +set CM_DLL_CTRL [expr {$PRCM_BASE_ADDR + 0x4104}] +set CM_CLKOUT2_CTRL [expr {$PRCM_BASE_ADDR + 0x4108}] +set CLKSEL_TIMER1MS_CLK [expr {$PRCM_BASE_ADDR + 0x4200}] +set CLKSEL_TIMER2_CLK [expr {$PRCM_BASE_ADDR + 0x4204}] +set CLKSEL_TIMER3_CLK [expr {$PRCM_BASE_ADDR + 0x4208}] +set CLKSEL_TIMER4_CLK [expr {$PRCM_BASE_ADDR + 0x420c}] +set CLKSEL_TIMER5_CLK [expr {$PRCM_BASE_ADDR + 0x4210}] +set CLKSEL_TIMER6_CLK [expr {$PRCM_BASE_ADDR + 0x4214}] +set CLKSEL_TIMER7_CLK [expr {$PRCM_BASE_ADDR + 0x4218}] +set CLKSEL_TIMER8_CLK [expr {$PRCM_BASE_ADDR + 0x421c}] +set CLKSEL_TIMER9_CLK [expr {$PRCM_BASE_ADDR + 0x4220}] +set CLKSEL_TIMER10_CLK [expr {$PRCM_BASE_ADDR + 0x4224}] +set CLKSEL_TIMER11_CLK [expr {$PRCM_BASE_ADDR + 0x4228}] +set CLKSEL_WDT1_CLK [expr {$PRCM_BASE_ADDR + 0x422c}] +set CLKSEL_SYNCTIMER_CLK [expr {$PRCM_BASE_ADDR + 0x4230}] +set CLKSEL_MAC_CLK [expr {$PRCM_BASE_ADDR + 0x4234}] +set CLKSEL_CPTS_RFT_CLK [expr {$PRCM_BASE_ADDR + 0x4238}] +set CLKSEL_GFX_FCLK [expr {$PRCM_BASE_ADDR + 0x423c}] +set CLKSEL_GPIO0_DBCLK [expr {$PRCM_BASE_ADDR + 0x4240}] +set CLKSEL_LCDC_PIXEL_CLK [expr {$PRCM_BASE_ADDR + 0x4244}] +set CLKSEL_ICSS_OCP_CLK [expr {$PRCM_BASE_ADDR + 0x4248}] +set CLKSEL_DLL_AGING_CLK [expr {$PRCM_BASE_ADDR + 0x4250}] +set CLKSEL_USBPHY32KHZ_GCLK [expr {$PRCM_BASE_ADDR + 0x4260}] +set CM_MPU_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8300}] +set CM_MPU_MPU_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8320}] +set CM_GFX_L3_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8400}] +set CM_GFX_GFX_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8420}] +set CM_RTC_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8500}] +set CM_RTC_RTC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8520}] +set CM_PER_L3_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8800}] +set CM_PER_L3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8820}] +set CM_PER_AES0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8828}] +set CM_PER_DES_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8830}] +set CM_PER_CRYPTODMA_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8838}] +set CM_PER_L3_INSTR_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8840}] +set CM_PER_MSTR_EXPS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8848}] +set CM_PER_OCMCRAM_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8850}] +set CM_PER_SHA0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8858}] +set CM_PER_SLV_EXPS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8860}] +set CM_PER_VPFE0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8868}] +set CM_PER_VPFE1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8870}] +set CM_PER_TPCC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8878}] +set CM_PER_TPTC0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8880}] +set CM_PER_TPTC1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8888}] +set CM_PER_TPTC2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8890}] +set CM_PER_DLL_AGING_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8898}] +set CM_PER_L4HS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x88a0}] +set CM_PER_L4FW_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x88a8}] +set CM_PER_L3S_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8a00}] +set CM_PER_GPMC_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a20}] +set CM_PER_IEEE5000_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a28}] +set CM_PER_MCASP0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a38}] +set CM_PER_MCASP1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a40}] +set CM_PER_MMC2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a48}] +set CM_PER_QSPI_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a58}] +set CM_PER_USB_OTG_SS0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a60}] +set CM_PER_USB_OTG_SS1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8a68}] +set CM_PER_ICSS_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8b00}] +set CM_PER_ICSS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8b20}] +set CM_PER_L4LS_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8c00}] +set CM_PER_L4LS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c20}] +set CM_PER_DCAN0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c28}] +set CM_PER_DCAN1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c30}] +set CM_PER_EPWMSS0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c38}] +set CM_PER_EPWMSS1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c40}] +set CM_PER_EPWMSS2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c48}] +set CM_PER_EPWMSS3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c50}] +set CM_PER_EPWMSS4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c58}] +set CM_PER_EPWMSS5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c60}] +set CM_PER_ELM_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c68}] +set CM_PER_GPIO1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c78}] +set CM_PER_GPIO2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c80}] +set CM_PER_GPIO3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c88}] +set CM_PER_GPIO4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c90}] +set CM_PER_GPIO5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8c98}] +set CM_PER_HDQ1W_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ca0}] +set CM_PER_I2C1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ca8}] +set CM_PER_I2C2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cb0}] +set CM_PER_MAILBOX0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cb8}] +set CM_PER_MMC0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cc0}] +set CM_PER_MMC1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cc8}] +set CM_PER_PKA_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cd0}] +set CM_PER_RNG_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ce0}] +set CM_PER_SPARE0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8ce8}] +set CM_PER_SPARE1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8cf0}] +set CM_PER_SPI0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d00}] +set CM_PER_SPI1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d08}] +set CM_PER_SPI2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d10}] +set CM_PER_SPI3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d18}] +set CM_PER_SPI4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d20}] +set CM_PER_SPINLOCK_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d28}] +set CM_PER_TIMER2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d30}] +set CM_PER_TIMER3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d38}] +set CM_PER_TIMER4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d40}] +set CM_PER_TIMER5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d48}] +set CM_PER_TIMER6_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d50}] +set CM_PER_TIMER7_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d58}] +set CM_PER_TIMER8_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d60}] +set CM_PER_TIMER9_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d68}] +set CM_PER_TIMER10_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d70}] +set CM_PER_TIMER11_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d78}] +set CM_PER_UART1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d80}] +set CM_PER_UART2_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d88}] +set CM_PER_UART3_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d90}] +set CM_PER_UART4_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8d98}] +set CM_PER_UART5_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8da0}] +set CM_PER_USBPHYOCP2SCP0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8db8}] +set CM_PER_USBPHYOCP2SCP1_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8dc0}] +set CM_PER_EMIF_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x8f00}] +set CM_PER_EMIF_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f20}] +set CM_PER_DLL_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f28}] +set CM_PER_EMIF_FW_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f30}] +set CM_PER_OTFA_EMIF_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x8f38}] +set CM_PER_DSS_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x9200}] +set CM_PER_DSS_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x9220}] +set CM_PER_CPSW_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x9300}] +set CM_PER_CPGMAC0_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x9320}] +set CM_PER_OCPWP_L3_CLKSTCTRL [expr {$PRCM_BASE_ADDR + 0x9400}] +set CM_PER_OCPWP_CLKCTRL [expr {$PRCM_BASE_ADDR + 0x9420}] set CONTROL_BASE_ADDR 0x44e10000 -set CONTROL_STATUS [expr $CONTROL_BASE_ADDR + 0x0040] -set DEVICE_ID [expr $CONTROL_BASE_ADDR + 0x0600] -set DEV_FEATURE [expr $CONTROL_BASE_ADDR + 0x0604] -set DEV_ATTRIBUTE [expr $CONTROL_BASE_ADDR + 0x0610] -set MAC_ID0_LO [expr $CONTROL_BASE_ADDR + 0x0630] -set MAC_ID0_HI [expr $CONTROL_BASE_ADDR + 0x0634] -set MAC_ID1_LO [expr $CONTROL_BASE_ADDR + 0x0638] -set MAC_ID1_HI [expr $CONTROL_BASE_ADDR + 0x063c] -set USB_VID_PID [expr $CONTROL_BASE_ADDR + 0x07f4] -set CONTROL_CONF_ECAP0_IN_PWM0_OUT [expr $CONTROL_BASE_ADDR + 0x0964] -set CONTROL_CONF_SPI4_CS0 [expr $CONTROL_BASE_ADDR + 0x0a5c] -set CONTROL_CONF_SPI2_SCLK [expr $CONTROL_BASE_ADDR + 0x0a60] -set CONTROL_CONF_SPI2_D0 [expr $CONTROL_BASE_ADDR + 0x0a64] -set CONTROL_CONF_XDMA_EVENT_INTR0 [expr $CONTROL_BASE_ADDR + 0x0a70] -set CONTROL_CONF_XDMA_EVENT_INTR1 [expr $CONTROL_BASE_ADDR + 0x0a74] -set CONTROL_CONF_GPMC_A0 [expr $CONTROL_BASE_ADDR + 0x0840] -set DDR_IO_CTRL [expr $CONTROL_BASE_ADDR + 0x0e04] -set VTP_CTRL_REG [expr $CONTROL_BASE_ADDR + 0x0e0c] -set VREF_CTRL [expr $CONTROL_BASE_ADDR + 0x0e14] -set DDR_CKE_CTRL [expr $CONTROL_BASE_ADDR + 0x131c] -set DDR_ADDRCTRL_IOCTRL [expr $CONTROL_BASE_ADDR + 0x1404] -set DDR_ADDRCTRL_WD0_IOCTRL [expr $CONTROL_BASE_ADDR + 0x1408] -set DDR_ADDRCTRL_WD1_IOCTRL [expr $CONTROL_BASE_ADDR + 0x140c] -set DDR_DATA0_IOCTRL [expr $CONTROL_BASE_ADDR + 0x1440] -set DDR_DATA1_IOCTRL [expr $CONTROL_BASE_ADDR + 0x1444] -set DDR_DATA2_IOCTRL [expr $CONTROL_BASE_ADDR + 0x1448] -set DDR_DATA3_IOCTRL [expr $CONTROL_BASE_ADDR + 0x144c] -set EMIF_SDRAM_CONFIG_EXT [expr $CONTROL_BASE_ADDR + 0x1460] -set EMIF_SDRAM_STATUS_EXT [expr $CONTROL_BASE_ADDR + 0x1464] +set CONTROL_STATUS [expr {$CONTROL_BASE_ADDR + 0x0040}] +set DEVICE_ID [expr {$CONTROL_BASE_ADDR + 0x0600}] +set DEV_FEATURE [expr {$CONTROL_BASE_ADDR + 0x0604}] +set DEV_ATTRIBUTE [expr {$CONTROL_BASE_ADDR + 0x0610}] +set MAC_ID0_LO [expr {$CONTROL_BASE_ADDR + 0x0630}] +set MAC_ID0_HI [expr {$CONTROL_BASE_ADDR + 0x0634}] +set MAC_ID1_LO [expr {$CONTROL_BASE_ADDR + 0x0638}] +set MAC_ID1_HI [expr {$CONTROL_BASE_ADDR + 0x063c}] +set USB_VID_PID [expr {$CONTROL_BASE_ADDR + 0x07f4}] +set CONTROL_CONF_ECAP0_IN_PWM0_OUT [expr {$CONTROL_BASE_ADDR + 0x0964}] +set CONTROL_CONF_SPI4_CS0 [expr {$CONTROL_BASE_ADDR + 0x0a5c}] +set CONTROL_CONF_SPI2_SCLK [expr {$CONTROL_BASE_ADDR + 0x0a60}] +set CONTROL_CONF_SPI2_D0 [expr {$CONTROL_BASE_ADDR + 0x0a64}] +set CONTROL_CONF_XDMA_EVENT_INTR0 [expr {$CONTROL_BASE_ADDR + 0x0a70}] +set CONTROL_CONF_XDMA_EVENT_INTR1 [expr {$CONTROL_BASE_ADDR + 0x0a74}] +set CONTROL_CONF_GPMC_A0 [expr {$CONTROL_BASE_ADDR + 0x0840}] +set DDR_IO_CTRL [expr {$CONTROL_BASE_ADDR + 0x0e04}] +set VTP_CTRL_REG [expr {$CONTROL_BASE_ADDR + 0x0e0c}] +set VREF_CTRL [expr {$CONTROL_BASE_ADDR + 0x0e14}] +set DDR_CKE_CTRL [expr {$CONTROL_BASE_ADDR + 0x131c}] +set DDR_ADDRCTRL_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1404}] +set DDR_ADDRCTRL_WD0_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1408}] +set DDR_ADDRCTRL_WD1_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x140c}] +set DDR_DATA0_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1440}] +set DDR_DATA1_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1444}] +set DDR_DATA2_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x1448}] +set DDR_DATA3_IOCTRL [expr {$CONTROL_BASE_ADDR + 0x144c}] +set EMIF_SDRAM_CONFIG_EXT [expr {$CONTROL_BASE_ADDR + 0x1460}] +set EMIF_SDRAM_STATUS_EXT [expr {$CONTROL_BASE_ADDR + 0x1464}] set GPIO0_BASE_ADDR 0x44e07000 -set GPIO0_SYSCONFIG [expr $GPIO0_BASE_ADDR + 0x0010] -set GPIO0_SYSSTATUS [expr $GPIO0_BASE_ADDR + 0x0114] -set GPIO0_CTRL [expr $GPIO0_BASE_ADDR + 0x0130] -set GPIO0_OE [expr $GPIO0_BASE_ADDR + 0x0134] -set GPIO0_CLEARDATAOUT [expr $GPIO0_BASE_ADDR + 0x0190] -set GPIO0_SETDATAOUT [expr $GPIO0_BASE_ADDR + 0x0194] +set GPIO0_SYSCONFIG [expr {$GPIO0_BASE_ADDR + 0x0010}] +set GPIO0_SYSSTATUS [expr {$GPIO0_BASE_ADDR + 0x0114}] +set GPIO0_CTRL [expr {$GPIO0_BASE_ADDR + 0x0130}] +set GPIO0_OE [expr {$GPIO0_BASE_ADDR + 0x0134}] +set GPIO0_CLEARDATAOUT [expr {$GPIO0_BASE_ADDR + 0x0190}] +set GPIO0_SETDATAOUT [expr {$GPIO0_BASE_ADDR + 0x0194}] set GPIO5_BASE_ADDR 0x48322000 -set GPIO5_SYSCONFIG [expr $GPIO5_BASE_ADDR + 0x0010] -set GPIO5_SYSSTATUS [expr $GPIO5_BASE_ADDR + 0x0114] -set GPIO5_CTRL [expr $GPIO5_BASE_ADDR + 0x0130] -set GPIO5_OE [expr $GPIO5_BASE_ADDR + 0x0134] -set GPIO5_CLEARDATAOUT [expr $GPIO5_BASE_ADDR + 0x0190] -set GPIO5_SETDATAOUT [expr $GPIO5_BASE_ADDR + 0x0194] +set GPIO5_SYSCONFIG [expr {$GPIO5_BASE_ADDR + 0x0010}] +set GPIO5_SYSSTATUS [expr {$GPIO5_BASE_ADDR + 0x0114}] +set GPIO5_CTRL [expr {$GPIO5_BASE_ADDR + 0x0130}] +set GPIO5_OE [expr {$GPIO5_BASE_ADDR + 0x0134}] +set GPIO5_CLEARDATAOUT [expr {$GPIO5_BASE_ADDR + 0x0190}] +set GPIO5_SETDATAOUT [expr {$GPIO5_BASE_ADDR + 0x0194}] set GPIO1_BASE_ADDR 0x4804c000 -set GPIO1_SYSCONFIG [expr $GPIO1_BASE_ADDR + 0x0010] -set GPIO1_SYSSTATUS [expr $GPIO1_BASE_ADDR + 0x0114] -set GPIO1_CTRL [expr $GPIO1_BASE_ADDR + 0x0130] -set GPIO1_OE [expr $GPIO1_BASE_ADDR + 0x0134] -set GPIO1_CLEARDATAOUT [expr $GPIO1_BASE_ADDR + 0x0190] -set GPIO1_SETDATAOUT [expr $GPIO1_BASE_ADDR + 0x0194] +set GPIO1_SYSCONFIG [expr {$GPIO1_BASE_ADDR + 0x0010}] +set GPIO1_SYSSTATUS [expr {$GPIO1_BASE_ADDR + 0x0114}] +set GPIO1_CTRL [expr {$GPIO1_BASE_ADDR + 0x0130}] +set GPIO1_OE [expr {$GPIO1_BASE_ADDR + 0x0134}] +set GPIO1_CLEARDATAOUT [expr {$GPIO1_BASE_ADDR + 0x0190}] +set GPIO1_SETDATAOUT [expr {$GPIO1_BASE_ADDR + 0x0194}] set EMIF_BASE_ADDR 0x4c000000 -set EMIF_STATUS [expr $EMIF_BASE_ADDR + 0x0004] -set EMIF_SDRAM_CONFIG [expr $EMIF_BASE_ADDR + 0x0008] -set EMIF_SDRAM_CONFIG_2 [expr $EMIF_BASE_ADDR + 0x000c] -set EMIF_SDRAM_REF_CTRL [expr $EMIF_BASE_ADDR + 0x0010] -set EMIF_SDRAM_REF_CTRL_SHDW [expr $EMIF_BASE_ADDR + 0x0014] -set EMIF_SDRAM_TIM_1 [expr $EMIF_BASE_ADDR + 0x0018] -set EMIF_SDRAM_TIM_1_SHDW [expr $EMIF_BASE_ADDR + 0x001c] -set EMIF_SDRAM_TIM_2 [expr $EMIF_BASE_ADDR + 0x0020] -set EMIF_SDRAM_TIM_2_SHDW [expr $EMIF_BASE_ADDR + 0x0024] -set EMIF_SDRAM_TIM_3 [expr $EMIF_BASE_ADDR + 0x0028] -set EMIF_SDRAM_TIM_3_SHDW [expr $EMIF_BASE_ADDR + 0x002c] -set EMIF_LPDDR2_NVM_TIM [expr $EMIF_BASE_ADDR + 0x0030] -set EMIF_LPDDR2_NVM_TIM_SHDW [expr $EMIF_BASE_ADDR + 0x0034] -set EMIF_PWR_MGMT_CTRL [expr $EMIF_BASE_ADDR + 0x0038] -set EMIF_PWR_MGMT_CTRL_SHDW [expr $EMIF_BASE_ADDR + 0x003c] -set EMIF_LPDDR2_MODE_REG_DATA [expr $EMIF_BASE_ADDR + 0x0040] -set EMIF_LPDDR2_MODE_REG_CFG [expr $EMIF_BASE_ADDR + 0x0050] -set EMIF_OCP_CONFIG [expr $EMIF_BASE_ADDR + 0x0054] -set EMIF_OCP_CFG_VAL_1 [expr $EMIF_BASE_ADDR + 0x0058] -set EMIF_OCP_CFG_VAL_2 [expr $EMIF_BASE_ADDR + 0x005c] -set EMIF_IODFT_TLGC [expr $EMIF_BASE_ADDR + 0x0060] -set EMIF_IODFT_CTRL_MISR_RSLT [expr $EMIF_BASE_ADDR + 0x0064] -set EMIF_IODFT_ADDR_MISR_RSLT [expr $EMIF_BASE_ADDR + 0x0068] -set EMIF_IODFT_DATA_MISR_RSLT_1 [expr $EMIF_BASE_ADDR + 0x006c] -set EMIF_IODFT_DATA_MISR_RSLT_2 [expr $EMIF_BASE_ADDR + 0x0070] -set EMIF_IODFT_DATA_MISR_RSLT_3 [expr $EMIF_BASE_ADDR + 0x0074] -set EMIF_PERF_CNT_1 [expr $EMIF_BASE_ADDR + 0x0080] -set EMIF_PERF_CNT_2 [expr $EMIF_BASE_ADDR + 0x0084] -set EMIF_PERF_CNT_CFG [expr $EMIF_BASE_ADDR + 0x0088] -set EMIF_PERF_CNT_SEL [expr $EMIF_BASE_ADDR + 0x008c] -set EMIF_PERF_CNT_TIM [expr $EMIF_BASE_ADDR + 0x0090] -set EMIF_MISC_REG [expr $EMIF_BASE_ADDR + 0x0094] -set EMIF_DLL_CALIB_CTRL [expr $EMIF_BASE_ADDR + 0x0098] -set EMIF_DLL_CALIB_CTRL_SHDW [expr $EMIF_BASE_ADDR + 0x009c] -set EMIF_IRQ_EOI [expr $EMIF_BASE_ADDR + 0x00a0] -set EMIF_IRQSTATUS_RAW_SYS [expr $EMIF_BASE_ADDR + 0x00a4] -set EMIF_IRQSTATUS_SYS [expr $EMIF_BASE_ADDR + 0x00ac] -set EMIF_IRQENABLE_SET_SYS [expr $EMIF_BASE_ADDR + 0x00b4] -set EMIF_IRQENABLE_CLR_SYS [expr $EMIF_BASE_ADDR + 0x00bc] -set EMIF_ZQ_CONFIG [expr $EMIF_BASE_ADDR + 0x00c8] -set EMIF_TEMP_ALERT_CONFIG [expr $EMIF_BASE_ADDR + 0x00cc] -set EMIF_OCP_ERR_LOG [expr $EMIF_BASE_ADDR + 0x00d0] -set EMIF_RDWR_LVL_RMP_WIN [expr $EMIF_BASE_ADDR + 0x00d4] -set EMIF_RDWR_LVL_RMP_CTRL [expr $EMIF_BASE_ADDR + 0x00d8] -set EMIF_RDWR_LVL_CTRL [expr $EMIF_BASE_ADDR + 0x00dc] -set EMIF_DDR_PHY_CTRL_1 [expr $EMIF_BASE_ADDR + 0x00e4] -set EMIF_DDR_PHY_CTRL_1_SHDW [expr $EMIF_BASE_ADDR + 0x00e8] -set EMIF_DDR_PHY_CTRL_2 [expr $EMIF_BASE_ADDR + 0x00ec] -set EMIF_PRI_COS_MAP [expr $EMIF_BASE_ADDR + 0x0100] -set EMIF_CONNID_COS_1_MAP [expr $EMIF_BASE_ADDR + 0x0104] -set EMIF_CONNID_COS_2_MAP [expr $EMIF_BASE_ADDR + 0x0108] -set ECC_CTRL [expr $EMIF_BASE_ADDR + 0x0110] -set ECC_ADDR_RNG_1 [expr $EMIF_BASE_ADDR + 0x0114] -set ECC_ADDR_RNG_2 [expr $EMIF_BASE_ADDR + 0x0118] -set EMIF_RD_WR_EXEC_THRSH [expr $EMIF_BASE_ADDR + 0x0120] -set COS_CONFIG [expr $EMIF_BASE_ADDR + 0x0124] - -set PHY_STATUS_1 [expr $EMIF_BASE_ADDR + 0x0144] -set PHY_STATUS_2 [expr $EMIF_BASE_ADDR + 0x0148] -set PHY_STATUS_3 [expr $EMIF_BASE_ADDR + 0x014c] -set PHY_STATUS_4 [expr $EMIF_BASE_ADDR + 0x0150] -set PHY_STATUS_5 [expr $EMIF_BASE_ADDR + 0x0154] -set PHY_STATUS_6 [expr $EMIF_BASE_ADDR + 0x0158] -set PHY_STATUS_7 [expr $EMIF_BASE_ADDR + 0x015c] -set PHY_STATUS_8 [expr $EMIF_BASE_ADDR + 0x0160] -set PHY_STATUS_9 [expr $EMIF_BASE_ADDR + 0x0164] -set PHY_STATUS_10 [expr $EMIF_BASE_ADDR + 0x0168] -set PHY_STATUS_11 [expr $EMIF_BASE_ADDR + 0x016c] -set PHY_STATUS_12 [expr $EMIF_BASE_ADDR + 0x0170] -set PHY_STATUS_13 [expr $EMIF_BASE_ADDR + 0x0174] -set PHY_STATUS_14 [expr $EMIF_BASE_ADDR + 0x0178] -set PHY_STATUS_15 [expr $EMIF_BASE_ADDR + 0x017c] -set PHY_STATUS_16 [expr $EMIF_BASE_ADDR + 0x0180] -set PHY_STATUS_17 [expr $EMIF_BASE_ADDR + 0x0184] -set PHY_STATUS_18 [expr $EMIF_BASE_ADDR + 0x0188] -set PHY_STATUS_19 [expr $EMIF_BASE_ADDR + 0x018c] -set PHY_STATUS_20 [expr $EMIF_BASE_ADDR + 0x0190] -set PHY_STATUS_21 [expr $EMIF_BASE_ADDR + 0x0194] -set PHY_STATUS_22 [expr $EMIF_BASE_ADDR + 0x0198] -set PHY_STATUS_23 [expr $EMIF_BASE_ADDR + 0x019c] -set PHY_STATUS_24 [expr $EMIF_BASE_ADDR + 0x01a0] -set PHY_STATUS_25 [expr $EMIF_BASE_ADDR + 0x01a4] -set PHY_STATUS_26 [expr $EMIF_BASE_ADDR + 0x01a8] -set PHY_STATUS_27 [expr $EMIF_BASE_ADDR + 0x01ac] -set PHY_STATUS_28 [expr $EMIF_BASE_ADDR + 0x01b0] - -set EXT_PHY_CTRL_1 [expr $EMIF_BASE_ADDR + 0x0200] -set EXT_PHY_CTRL_1_SHDW [expr $EMIF_BASE_ADDR + 0x0204] -set EXT_PHY_CTRL_2 [expr $EMIF_BASE_ADDR + 0x0208] -set EXT_PHY_CTRL_2_SHDW [expr $EMIF_BASE_ADDR + 0x020c] -set EXT_PHY_CTRL_3 [expr $EMIF_BASE_ADDR + 0x0210] -set EXT_PHY_CTRL_3_SHDW [expr $EMIF_BASE_ADDR + 0x0214] -set EXT_PHY_CTRL_4 [expr $EMIF_BASE_ADDR + 0x0218] -set EXT_PHY_CTRL_4_SHDW [expr $EMIF_BASE_ADDR + 0x021c] -set EXT_PHY_CTRL_5 [expr $EMIF_BASE_ADDR + 0x0220] -set EXT_PHY_CTRL_5_SHDW [expr $EMIF_BASE_ADDR + 0x0224] -set EXT_PHY_CTRL_6 [expr $EMIF_BASE_ADDR + 0x0228] -set EXT_PHY_CTRL_6_SHDW [expr $EMIF_BASE_ADDR + 0x022c] -set EXT_PHY_CTRL_7 [expr $EMIF_BASE_ADDR + 0x0230] -set EXT_PHY_CTRL_7_SHDW [expr $EMIF_BASE_ADDR + 0x0234] -set EXT_PHY_CTRL_8 [expr $EMIF_BASE_ADDR + 0x0238] -set EXT_PHY_CTRL_8_SHDW [expr $EMIF_BASE_ADDR + 0x023c] -set EXT_PHY_CTRL_9 [expr $EMIF_BASE_ADDR + 0x0240] -set EXT_PHY_CTRL_9_SHDW [expr $EMIF_BASE_ADDR + 0x0244] -set EXT_PHY_CTRL_10 [expr $EMIF_BASE_ADDR + 0x0248] -set EXT_PHY_CTRL_10_SHDW [expr $EMIF_BASE_ADDR + 0x024c] -set EXT_PHY_CTRL_11 [expr $EMIF_BASE_ADDR + 0x0250] -set EXT_PHY_CTRL_11_SHDW [expr $EMIF_BASE_ADDR + 0x0254] -set EXT_PHY_CTRL_12 [expr $EMIF_BASE_ADDR + 0x0258] -set EXT_PHY_CTRL_12_SHDW [expr $EMIF_BASE_ADDR + 0x025c] -set EXT_PHY_CTRL_13 [expr $EMIF_BASE_ADDR + 0x0260] -set EXT_PHY_CTRL_13_SHDW [expr $EMIF_BASE_ADDR + 0x0264] -set EXT_PHY_CTRL_14 [expr $EMIF_BASE_ADDR + 0x0268] -set EXT_PHY_CTRL_14_SHDW [expr $EMIF_BASE_ADDR + 0x026c] -set EXT_PHY_CTRL_15 [expr $EMIF_BASE_ADDR + 0x0270] -set EXT_PHY_CTRL_15_SHDW [expr $EMIF_BASE_ADDR + 0x0274] -set EXT_PHY_CTRL_16 [expr $EMIF_BASE_ADDR + 0x0278] -set EXT_PHY_CTRL_16_SHDW [expr $EMIF_BASE_ADDR + 0x027c] -set EXT_PHY_CTRL_17 [expr $EMIF_BASE_ADDR + 0x0280] -set EXT_PHY_CTRL_17_SHDW [expr $EMIF_BASE_ADDR + 0x0284] -set EXT_PHY_CTRL_18 [expr $EMIF_BASE_ADDR + 0x0288] -set EXT_PHY_CTRL_18_SHDW [expr $EMIF_BASE_ADDR + 0x028c] -set EXT_PHY_CTRL_19 [expr $EMIF_BASE_ADDR + 0x0290] -set EXT_PHY_CTRL_19_SHDW [expr $EMIF_BASE_ADDR + 0x0294] -set EXT_PHY_CTRL_20 [expr $EMIF_BASE_ADDR + 0x0298] -set EXT_PHY_CTRL_20_SHDW [expr $EMIF_BASE_ADDR + 0x029c] -set EXT_PHY_CTRL_21 [expr $EMIF_BASE_ADDR + 0x02a0] -set EXT_PHY_CTRL_21_SHDW [expr $EMIF_BASE_ADDR + 0x02a4] -set EXT_PHY_CTRL_22 [expr $EMIF_BASE_ADDR + 0x02a8] -set EXT_PHY_CTRL_22_SHDW [expr $EMIF_BASE_ADDR + 0x02ac] -set EXT_PHY_CTRL_23 [expr $EMIF_BASE_ADDR + 0x02b0] -set EXT_PHY_CTRL_23_SHDW [expr $EMIF_BASE_ADDR + 0x02b4] -set EXT_PHY_CTRL_24 [expr $EMIF_BASE_ADDR + 0x02b8] -set EXT_PHY_CTRL_24_SHDW [expr $EMIF_BASE_ADDR + 0x02bc] -set EXT_PHY_CTRL_25 [expr $EMIF_BASE_ADDR + 0x02c0] -set EXT_PHY_CTRL_25_SHDW [expr $EMIF_BASE_ADDR + 0x02c4] -set EXT_PHY_CTRL_26 [expr $EMIF_BASE_ADDR + 0x02c8] -set EXT_PHY_CTRL_26_SHDW [expr $EMIF_BASE_ADDR + 0x02cc] -set EXT_PHY_CTRL_27 [expr $EMIF_BASE_ADDR + 0x02d0] -set EXT_PHY_CTRL_27_SHDW [expr $EMIF_BASE_ADDR + 0x02d4] -set EXT_PHY_CTRL_28 [expr $EMIF_BASE_ADDR + 0x02d8] -set EXT_PHY_CTRL_28_SHDW [expr $EMIF_BASE_ADDR + 0x02dc] -set EXT_PHY_CTRL_29 [expr $EMIF_BASE_ADDR + 0x02e0] -set EXT_PHY_CTRL_29_SHDW [expr $EMIF_BASE_ADDR + 0x02e4] -set EXT_PHY_CTRL_30 [expr $EMIF_BASE_ADDR + 0x02e8] -set EXT_PHY_CTRL_30_SHDW [expr $EMIF_BASE_ADDR + 0x02ec] -set EXT_PHY_CTRL_31 [expr $EMIF_BASE_ADDR + 0x02f0] -set EXT_PHY_CTRL_31_SHDW [expr $EMIF_BASE_ADDR + 0x02f4] -set EXT_PHY_CTRL_32 [expr $EMIF_BASE_ADDR + 0x02f8] -set EXT_PHY_CTRL_32_SHDW [expr $EMIF_BASE_ADDR + 0x02fc] -set EXT_PHY_CTRL_33 [expr $EMIF_BASE_ADDR + 0x0300] -set EXT_PHY_CTRL_33_SHDW [expr $EMIF_BASE_ADDR + 0x0304] -set EXT_PHY_CTRL_34 [expr $EMIF_BASE_ADDR + 0x0308] -set EXT_PHY_CTRL_34_SHDW [expr $EMIF_BASE_ADDR + 0x030c] -set EXT_PHY_CTRL_35 [expr $EMIF_BASE_ADDR + 0x0310] -set EXT_PHY_CTRL_35_SHDW [expr $EMIF_BASE_ADDR + 0x0314] -set EXT_PHY_CTRL_36 [expr $EMIF_BASE_ADDR + 0x0318] -set EXT_PHY_CTRL_36_SHDW [expr $EMIF_BASE_ADDR + 0x031c] +set EMIF_STATUS [expr {$EMIF_BASE_ADDR + 0x0004}] +set EMIF_SDRAM_CONFIG [expr {$EMIF_BASE_ADDR + 0x0008}] +set EMIF_SDRAM_CONFIG_2 [expr {$EMIF_BASE_ADDR + 0x000c}] +set EMIF_SDRAM_REF_CTRL [expr {$EMIF_BASE_ADDR + 0x0010}] +set EMIF_SDRAM_REF_CTRL_SHDW [expr {$EMIF_BASE_ADDR + 0x0014}] +set EMIF_SDRAM_TIM_1 [expr {$EMIF_BASE_ADDR + 0x0018}] +set EMIF_SDRAM_TIM_1_SHDW [expr {$EMIF_BASE_ADDR + 0x001c}] +set EMIF_SDRAM_TIM_2 [expr {$EMIF_BASE_ADDR + 0x0020}] +set EMIF_SDRAM_TIM_2_SHDW [expr {$EMIF_BASE_ADDR + 0x0024}] +set EMIF_SDRAM_TIM_3 [expr {$EMIF_BASE_ADDR + 0x0028}] +set EMIF_SDRAM_TIM_3_SHDW [expr {$EMIF_BASE_ADDR + 0x002c}] +set EMIF_LPDDR2_NVM_TIM [expr {$EMIF_BASE_ADDR + 0x0030}] +set EMIF_LPDDR2_NVM_TIM_SHDW [expr {$EMIF_BASE_ADDR + 0x0034}] +set EMIF_PWR_MGMT_CTRL [expr {$EMIF_BASE_ADDR + 0x0038}] +set EMIF_PWR_MGMT_CTRL_SHDW [expr {$EMIF_BASE_ADDR + 0x003c}] +set EMIF_LPDDR2_MODE_REG_DATA [expr {$EMIF_BASE_ADDR + 0x0040}] +set EMIF_LPDDR2_MODE_REG_CFG [expr {$EMIF_BASE_ADDR + 0x0050}] +set EMIF_OCP_CONFIG [expr {$EMIF_BASE_ADDR + 0x0054}] +set EMIF_OCP_CFG_VAL_1 [expr {$EMIF_BASE_ADDR + 0x0058}] +set EMIF_OCP_CFG_VAL_2 [expr {$EMIF_BASE_ADDR + 0x005c}] +set EMIF_IODFT_TLGC [expr {$EMIF_BASE_ADDR + 0x0060}] +set EMIF_IODFT_CTRL_MISR_RSLT [expr {$EMIF_BASE_ADDR + 0x0064}] +set EMIF_IODFT_ADDR_MISR_RSLT [expr {$EMIF_BASE_ADDR + 0x0068}] +set EMIF_IODFT_DATA_MISR_RSLT_1 [expr {$EMIF_BASE_ADDR + 0x006c}] +set EMIF_IODFT_DATA_MISR_RSLT_2 [expr {$EMIF_BASE_ADDR + 0x0070}] +set EMIF_IODFT_DATA_MISR_RSLT_3 [expr {$EMIF_BASE_ADDR + 0x0074}] +set EMIF_PERF_CNT_1 [expr {$EMIF_BASE_ADDR + 0x0080}] +set EMIF_PERF_CNT_2 [expr {$EMIF_BASE_ADDR + 0x0084}] +set EMIF_PERF_CNT_CFG [expr {$EMIF_BASE_ADDR + 0x0088}] +set EMIF_PERF_CNT_SEL [expr {$EMIF_BASE_ADDR + 0x008c}] +set EMIF_PERF_CNT_TIM [expr {$EMIF_BASE_ADDR + 0x0090}] +set EMIF_MISC_REG [expr {$EMIF_BASE_ADDR + 0x0094}] +set EMIF_DLL_CALIB_CTRL [expr {$EMIF_BASE_ADDR + 0x0098}] +set EMIF_DLL_CALIB_CTRL_SHDW [expr {$EMIF_BASE_ADDR + 0x009c}] +set EMIF_IRQ_EOI [expr {$EMIF_BASE_ADDR + 0x00a0}] +set EMIF_IRQSTATUS_RAW_SYS [expr {$EMIF_BASE_ADDR + 0x00a4}] +set EMIF_IRQSTATUS_SYS [expr {$EMIF_BASE_ADDR + 0x00ac}] +set EMIF_IRQENABLE_SET_SYS [expr {$EMIF_BASE_ADDR + 0x00b4}] +set EMIF_IRQENABLE_CLR_SYS [expr {$EMIF_BASE_ADDR + 0x00bc}] +set EMIF_ZQ_CONFIG [expr {$EMIF_BASE_ADDR + 0x00c8}] +set EMIF_TEMP_ALERT_CONFIG [expr {$EMIF_BASE_ADDR + 0x00cc}] +set EMIF_OCP_ERR_LOG [expr {$EMIF_BASE_ADDR + 0x00d0}] +set EMIF_RDWR_LVL_RMP_WIN [expr {$EMIF_BASE_ADDR + 0x00d4}] +set EMIF_RDWR_LVL_RMP_CTRL [expr {$EMIF_BASE_ADDR + 0x00d8}] +set EMIF_RDWR_LVL_CTRL [expr {$EMIF_BASE_ADDR + 0x00dc}] +set EMIF_DDR_PHY_CTRL_1 [expr {$EMIF_BASE_ADDR + 0x00e4}] +set EMIF_DDR_PHY_CTRL_1_SHDW [expr {$EMIF_BASE_ADDR + 0x00e8}] +set EMIF_DDR_PHY_CTRL_2 [expr {$EMIF_BASE_ADDR + 0x00ec}] +set EMIF_PRI_COS_MAP [expr {$EMIF_BASE_ADDR + 0x0100}] +set EMIF_CONNID_COS_1_MAP [expr {$EMIF_BASE_ADDR + 0x0104}] +set EMIF_CONNID_COS_2_MAP [expr {$EMIF_BASE_ADDR + 0x0108}] +set ECC_CTRL [expr {$EMIF_BASE_ADDR + 0x0110}] +set ECC_ADDR_RNG_1 [expr {$EMIF_BASE_ADDR + 0x0114}] +set ECC_ADDR_RNG_2 [expr {$EMIF_BASE_ADDR + 0x0118}] +set EMIF_RD_WR_EXEC_THRSH [expr {$EMIF_BASE_ADDR + 0x0120}] +set COS_CONFIG [expr {$EMIF_BASE_ADDR + 0x0124}] + +set PHY_STATUS_1 [expr {$EMIF_BASE_ADDR + 0x0144}] +set PHY_STATUS_2 [expr {$EMIF_BASE_ADDR + 0x0148}] +set PHY_STATUS_3 [expr {$EMIF_BASE_ADDR + 0x014c}] +set PHY_STATUS_4 [expr {$EMIF_BASE_ADDR + 0x0150}] +set PHY_STATUS_5 [expr {$EMIF_BASE_ADDR + 0x0154}] +set PHY_STATUS_6 [expr {$EMIF_BASE_ADDR + 0x0158}] +set PHY_STATUS_7 [expr {$EMIF_BASE_ADDR + 0x015c}] +set PHY_STATUS_8 [expr {$EMIF_BASE_ADDR + 0x0160}] +set PHY_STATUS_9 [expr {$EMIF_BASE_ADDR + 0x0164}] +set PHY_STATUS_10 [expr {$EMIF_BASE_ADDR + 0x0168}] +set PHY_STATUS_11 [expr {$EMIF_BASE_ADDR + 0x016c}] +set PHY_STATUS_12 [expr {$EMIF_BASE_ADDR + 0x0170}] +set PHY_STATUS_13 [expr {$EMIF_BASE_ADDR + 0x0174}] +set PHY_STATUS_14 [expr {$EMIF_BASE_ADDR + 0x0178}] +set PHY_STATUS_15 [expr {$EMIF_BASE_ADDR + 0x017c}] +set PHY_STATUS_16 [expr {$EMIF_BASE_ADDR + 0x0180}] +set PHY_STATUS_17 [expr {$EMIF_BASE_ADDR + 0x0184}] +set PHY_STATUS_18 [expr {$EMIF_BASE_ADDR + 0x0188}] +set PHY_STATUS_19 [expr {$EMIF_BASE_ADDR + 0x018c}] +set PHY_STATUS_20 [expr {$EMIF_BASE_ADDR + 0x0190}] +set PHY_STATUS_21 [expr {$EMIF_BASE_ADDR + 0x0194}] +set PHY_STATUS_22 [expr {$EMIF_BASE_ADDR + 0x0198}] +set PHY_STATUS_23 [expr {$EMIF_BASE_ADDR + 0x019c}] +set PHY_STATUS_24 [expr {$EMIF_BASE_ADDR + 0x01a0}] +set PHY_STATUS_25 [expr {$EMIF_BASE_ADDR + 0x01a4}] +set PHY_STATUS_26 [expr {$EMIF_BASE_ADDR + 0x01a8}] +set PHY_STATUS_27 [expr {$EMIF_BASE_ADDR + 0x01ac}] +set PHY_STATUS_28 [expr {$EMIF_BASE_ADDR + 0x01b0}] + +set EXT_PHY_CTRL_1 [expr {$EMIF_BASE_ADDR + 0x0200}] +set EXT_PHY_CTRL_1_SHDW [expr {$EMIF_BASE_ADDR + 0x0204}] +set EXT_PHY_CTRL_2 [expr {$EMIF_BASE_ADDR + 0x0208}] +set EXT_PHY_CTRL_2_SHDW [expr {$EMIF_BASE_ADDR + 0x020c}] +set EXT_PHY_CTRL_3 [expr {$EMIF_BASE_ADDR + 0x0210}] +set EXT_PHY_CTRL_3_SHDW [expr {$EMIF_BASE_ADDR + 0x0214}] +set EXT_PHY_CTRL_4 [expr {$EMIF_BASE_ADDR + 0x0218}] +set EXT_PHY_CTRL_4_SHDW [expr {$EMIF_BASE_ADDR + 0x021c}] +set EXT_PHY_CTRL_5 [expr {$EMIF_BASE_ADDR + 0x0220}] +set EXT_PHY_CTRL_5_SHDW [expr {$EMIF_BASE_ADDR + 0x0224}] +set EXT_PHY_CTRL_6 [expr {$EMIF_BASE_ADDR + 0x0228}] +set EXT_PHY_CTRL_6_SHDW [expr {$EMIF_BASE_ADDR + 0x022c}] +set EXT_PHY_CTRL_7 [expr {$EMIF_BASE_ADDR + 0x0230}] +set EXT_PHY_CTRL_7_SHDW [expr {$EMIF_BASE_ADDR + 0x0234}] +set EXT_PHY_CTRL_8 [expr {$EMIF_BASE_ADDR + 0x0238}] +set EXT_PHY_CTRL_8_SHDW [expr {$EMIF_BASE_ADDR + 0x023c}] +set EXT_PHY_CTRL_9 [expr {$EMIF_BASE_ADDR + 0x0240}] +set EXT_PHY_CTRL_9_SHDW [expr {$EMIF_BASE_ADDR + 0x0244}] +set EXT_PHY_CTRL_10 [expr {$EMIF_BASE_ADDR + 0x0248}] +set EXT_PHY_CTRL_10_SHDW [expr {$EMIF_BASE_ADDR + 0x024c}] +set EXT_PHY_CTRL_11 [expr {$EMIF_BASE_ADDR + 0x0250}] +set EXT_PHY_CTRL_11_SHDW [expr {$EMIF_BASE_ADDR + 0x0254}] +set EXT_PHY_CTRL_12 [expr {$EMIF_BASE_ADDR + 0x0258}] +set EXT_PHY_CTRL_12_SHDW [expr {$EMIF_BASE_ADDR + 0x025c}] +set EXT_PHY_CTRL_13 [expr {$EMIF_BASE_ADDR + 0x0260}] +set EXT_PHY_CTRL_13_SHDW [expr {$EMIF_BASE_ADDR + 0x0264}] +set EXT_PHY_CTRL_14 [expr {$EMIF_BASE_ADDR + 0x0268}] +set EXT_PHY_CTRL_14_SHDW [expr {$EMIF_BASE_ADDR + 0x026c}] +set EXT_PHY_CTRL_15 [expr {$EMIF_BASE_ADDR + 0x0270}] +set EXT_PHY_CTRL_15_SHDW [expr {$EMIF_BASE_ADDR + 0x0274}] +set EXT_PHY_CTRL_16 [expr {$EMIF_BASE_ADDR + 0x0278}] +set EXT_PHY_CTRL_16_SHDW [expr {$EMIF_BASE_ADDR + 0x027c}] +set EXT_PHY_CTRL_17 [expr {$EMIF_BASE_ADDR + 0x0280}] +set EXT_PHY_CTRL_17_SHDW [expr {$EMIF_BASE_ADDR + 0x0284}] +set EXT_PHY_CTRL_18 [expr {$EMIF_BASE_ADDR + 0x0288}] +set EXT_PHY_CTRL_18_SHDW [expr {$EMIF_BASE_ADDR + 0x028c}] +set EXT_PHY_CTRL_19 [expr {$EMIF_BASE_ADDR + 0x0290}] +set EXT_PHY_CTRL_19_SHDW [expr {$EMIF_BASE_ADDR + 0x0294}] +set EXT_PHY_CTRL_20 [expr {$EMIF_BASE_ADDR + 0x0298}] +set EXT_PHY_CTRL_20_SHDW [expr {$EMIF_BASE_ADDR + 0x029c}] +set EXT_PHY_CTRL_21 [expr {$EMIF_BASE_ADDR + 0x02a0}] +set EXT_PHY_CTRL_21_SHDW [expr {$EMIF_BASE_ADDR + 0x02a4}] +set EXT_PHY_CTRL_22 [expr {$EMIF_BASE_ADDR + 0x02a8}] +set EXT_PHY_CTRL_22_SHDW [expr {$EMIF_BASE_ADDR + 0x02ac}] +set EXT_PHY_CTRL_23 [expr {$EMIF_BASE_ADDR + 0x02b0}] +set EXT_PHY_CTRL_23_SHDW [expr {$EMIF_BASE_ADDR + 0x02b4}] +set EXT_PHY_CTRL_24 [expr {$EMIF_BASE_ADDR + 0x02b8}] +set EXT_PHY_CTRL_24_SHDW [expr {$EMIF_BASE_ADDR + 0x02bc}] +set EXT_PHY_CTRL_25 [expr {$EMIF_BASE_ADDR + 0x02c0}] +set EXT_PHY_CTRL_25_SHDW [expr {$EMIF_BASE_ADDR + 0x02c4}] +set EXT_PHY_CTRL_26 [expr {$EMIF_BASE_ADDR + 0x02c8}] +set EXT_PHY_CTRL_26_SHDW [expr {$EMIF_BASE_ADDR + 0x02cc}] +set EXT_PHY_CTRL_27 [expr {$EMIF_BASE_ADDR + 0x02d0}] +set EXT_PHY_CTRL_27_SHDW [expr {$EMIF_BASE_ADDR + 0x02d4}] +set EXT_PHY_CTRL_28 [expr {$EMIF_BASE_ADDR + 0x02d8}] +set EXT_PHY_CTRL_28_SHDW [expr {$EMIF_BASE_ADDR + 0x02dc}] +set EXT_PHY_CTRL_29 [expr {$EMIF_BASE_ADDR + 0x02e0}] +set EXT_PHY_CTRL_29_SHDW [expr {$EMIF_BASE_ADDR + 0x02e4}] +set EXT_PHY_CTRL_30 [expr {$EMIF_BASE_ADDR + 0x02e8}] +set EXT_PHY_CTRL_30_SHDW [expr {$EMIF_BASE_ADDR + 0x02ec}] +set EXT_PHY_CTRL_31 [expr {$EMIF_BASE_ADDR + 0x02f0}] +set EXT_PHY_CTRL_31_SHDW [expr {$EMIF_BASE_ADDR + 0x02f4}] +set EXT_PHY_CTRL_32 [expr {$EMIF_BASE_ADDR + 0x02f8}] +set EXT_PHY_CTRL_32_SHDW [expr {$EMIF_BASE_ADDR + 0x02fc}] +set EXT_PHY_CTRL_33 [expr {$EMIF_BASE_ADDR + 0x0300}] +set EXT_PHY_CTRL_33_SHDW [expr {$EMIF_BASE_ADDR + 0x0304}] +set EXT_PHY_CTRL_34 [expr {$EMIF_BASE_ADDR + 0x0308}] +set EXT_PHY_CTRL_34_SHDW [expr {$EMIF_BASE_ADDR + 0x030c}] +set EXT_PHY_CTRL_35 [expr {$EMIF_BASE_ADDR + 0x0310}] +set EXT_PHY_CTRL_35_SHDW [expr {$EMIF_BASE_ADDR + 0x0314}] +set EXT_PHY_CTRL_36 [expr {$EMIF_BASE_ADDR + 0x0318}] +set EXT_PHY_CTRL_36_SHDW [expr {$EMIF_BASE_ADDR + 0x031c}] set WDT1_BASE_ADDR 0x44e35000 -set WDT1_W_PEND_WSPR [expr $WDT1_BASE_ADDR + 0x0034] -set WDT1_WSPR [expr $WDT1_BASE_ADDR + 0x0048] +set WDT1_W_PEND_WSPR [expr {$WDT1_BASE_ADDR + 0x0034}] +set WDT1_WSPR [expr {$WDT1_BASE_ADDR + 0x0048}] set RTC_BASE_ADDR 0x44e3e000 -set RTC_KICK0R [expr $RTC_BASE_ADDR + 0x6c] -set RTC_KICK1R [expr $RTC_BASE_ADDR + 0x70] +set RTC_KICK0R [expr {$RTC_BASE_ADDR + 0x6c}] +set RTC_KICK1R [expr {$RTC_BASE_ADDR + 0x70}] if { [info exists CHIPNAME] } { @@ -512,23 +514,23 @@ proc disable_watchdog { } { # Empty body to make sure this executes as fast as possible. # We don't want any delays here otherwise romcode might start # executing and end up changing state of certain IPs. - while { [expr [mrw $WDT1_W_PEND_WSPR] & 0x10] } { } + while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } mww phys $WDT1_WSPR $WDT_DISABLE_SEQ2 - while { [expr [mrw $WDT1_W_PEND_WSPR] & 0x10] } { } + while { [expr {[mrw $WDT1_W_PEND_WSPR] & 0x10}] } { } } } proc ceil { x y } { - return [ expr ($x + $y - 1) / $y ] + return [ expr {($x + $y - 1) / $y} ] } proc device_type { } { global CONTROL_STATUS set tmp [ mrw $CONTROL_STATUS ] - set tmp [ expr $tmp & 0x700 ] - set tmp [ expr $tmp >> 8 ] + set tmp [ expr {$tmp & 0x700} ] + set tmp [ expr {$tmp >> 8} ] return $tmp } @@ -542,8 +544,8 @@ proc get_input_clock_frequency { } { } set freq [ mrw $CONTROL_STATUS ] - set freq [ expr $freq & 0x00c00000 ] - set freq [ expr $freq >> 22 ] + set freq [ expr {$freq & 0x00c00000} ] + set freq [ expr {$freq >> 22} ] switch $freq { 0 { @@ -578,12 +580,12 @@ proc mpu_pll_config { CLKIN N M M2 } { mww $CM_CLKMODE_DPLL_MPU 0x4 while { !([ mrw $CM_IDLEST_DPLL_MPU ] & 0x0100) } { } - set clksel [ expr $clksel & (~0x7ffff) ] - set clksel [ expr $clksel | ($M << 0x8) | $N ] + set clksel [ expr {$clksel & (~0x7ffff)} ] + set clksel [ expr {$clksel | ($M << 0x8) | $N} ] mww $CM_CLKSEL_DPLL_MPU $clksel - set div_m2 [ expr $div_m2 & (~0x1f) ] - set div_m2 [ expr $div_m2 | $M2 ] + set div_m2 [ expr {$div_m2 & (~0x1f)} ] + set div_m2 [ expr {$div_m2 | $M2} ] mww $CM_DIV_M2_DPLL_MPU $div_m2 mww $CM_CLKMODE_DPLL_MPU 0x7 @@ -605,8 +607,8 @@ proc core_pll_config { CLKIN N M M4 M5 M6 } { mww $CM_CLKMODE_DPLL_CORE 0x4 while { !([ mrw $CM_IDLEST_DPLL_CORE ] & 0x0100) } { } - set clksel [ expr $clksel & (~0x7ffff) ] - set clksel [ expr $clksel | ($M << 0x8) | $N ] + set clksel [ expr {$clksel & (~0x7ffff)} ] + set clksel [ expr {$clksel | ($M << 0x8) | $N} ] mww $CM_CLKSEL_DPLL_CORE $clksel mww $CM_DIV_M4_DPLL_CORE $M4 mww $CM_DIV_M5_DPLL_CORE $M5 @@ -624,8 +626,8 @@ proc per_pll_config { CLKIN N M M2 } { global CM_DIV_M2_DPLL_PER global CM_IDLEST_DPLL_PER - set x [ expr $M * $CLKIN / 1000000 ] - set y [ expr ($N + 1) * 250 ] + set x [ expr {$M * $CLKIN / 1000000} ] + set y [ expr {($N + 1) * 250} ] set sd [ ceil $x $y ] set clksel [ mrw $CM_CLKSEL_DPLL_PER ] @@ -634,12 +636,12 @@ proc per_pll_config { CLKIN N M M2 } { mww $CM_CLKMODE_DPLL_PER 0x4 while { !([ mrw $CM_IDLEST_DPLL_PER ] & 0x0100) } { } - set clksel [ expr $clksel & (~0xff0fffff) ] - set clksel [ expr $clksel | ($M << 0x8) | $N ] - set clksel [ expr $clksel | ($sd << 24) ] + set clksel [ expr {$clksel & (~0xff0fffff)} ] + set clksel [ expr {$clksel | ($M << 0x8) | $N} ] + set clksel [ expr {$clksel | ($sd << 24)} ] mww $CM_CLKSEL_DPLL_PER $clksel - set div_m2 [ expr 0xffffff80 | $M2 ] + set div_m2 [ expr {0xffffff80 | $M2} ] mww $CM_CLKMODE_DPLL_PER 0x7 while { !([ mrw $CM_IDLEST_DPLL_PER ] & 0x01) } { } @@ -660,11 +662,11 @@ proc ddr_pll_config { CLKIN N M M2 M4 } { mww $CM_CLKMODE_DPLL_DDR 0x4 while { !([ mrw $CM_IDLEST_DPLL_DDR ] & 0x0100) } { } - set clksel [ expr $clksel & (~0x7ffff) ] - set clksel [ expr $clksel | ($M << 8) | $N ] + set clksel [ expr {$clksel & (~0x7ffff)} ] + set clksel [ expr {$clksel | ($M << 8) | $N} ] mww $CM_CLKSEL_DPLL_DDR $clksel - set div_m2 [ expr ($div_m2 & 0xffffffe0) | $M2 ] + set div_m2 [ expr {($div_m2 & 0xffffffe0) | $M2} ] mww $CM_DIV_M2_DPLL_DDR $div_m2 mww $CM_DIV_M4_DPLL_DDR $M4 @@ -725,13 +727,13 @@ proc emif_prcm_clk_enable { } { proc vtp_enable { } { global VTP_CTRL_REG - set vtp [ expr [ mrw $VTP_CTRL_REG ] | 0x40 ] + set vtp [ expr {[ mrw $VTP_CTRL_REG ] | 0x40 }] mww $VTP_CTRL_REG $vtp - set vtp [ expr [ mrw $VTP_CTRL_REG ] & ~0x01 ] + set vtp [ expr {[ mrw $VTP_CTRL_REG ] & ~0x01 }] mww $VTP_CTRL_REG $vtp - set vtp [ expr [ mrw $VTP_CTRL_REG ] | 0x01 ] + set vtp [ expr {[ mrw $VTP_CTRL_REG ] | 0x01 }] mww $VTP_CTRL_REG $vtp } @@ -849,18 +851,18 @@ proc config_ddr_phy { } { set gatelvl_num_dq0 0x0f set wrlvl_num_dq0 0x0f - mww $EXT_PHY_CTRL_1 [ expr ($slave_ratio << 20) | ($slave_ratio << 10) | $slave_ratio ] - mww $EXT_PHY_CTRL_1_SHDW [ expr ($slave_ratio << 20) | ($slave_ratio << 10) | $slave_ratio ] - mww $EXT_PHY_CTRL_26 [ expr ($gatelvl_init_ratio << 16) | $gatelvl_init_ratio ] - mww $EXT_PHY_CTRL_26_SHDW [ expr ($gatelvl_init_ratio << 16) | $gatelvl_init_ratio ] - mww $EXT_PHY_CTRL_27 [ expr ($gatelvl_init_ratio << 16) | $gatelvl_init_ratio ] - mww $EXT_PHY_CTRL_27_SHDW [ expr ($gatelvl_init_ratio << 16) | $gatelvl_init_ratio ] - mww $EXT_PHY_CTRL_28 [ expr ($gatelvl_init_ratio << 16) | $gatelvl_init_ratio ] - mww $EXT_PHY_CTRL_28_SHDW [ expr ($gatelvl_init_ratio << 16) | $gatelvl_init_ratio ] - mww $EXT_PHY_CTRL_29 [ expr ($gatelvl_init_ratio << 16) | $gatelvl_init_ratio ] - mww $EXT_PHY_CTRL_29_SHDW [ expr ($gatelvl_init_ratio << 16) | $gatelvl_init_ratio ] - mww $EXT_PHY_CTRL_30 [ expr ($gatelvl_init_ratio << 16) | $gatelvl_init_ratio ] - mww $EXT_PHY_CTRL_30_SHDW [ expr ($gatelvl_init_ratio << 16) | $gatelvl_init_ratio ] + mww $EXT_PHY_CTRL_1 [ expr {($slave_ratio << 20) | ($slave_ratio << 10) | $slave_ratio} ] + mww $EXT_PHY_CTRL_1_SHDW [ expr {($slave_ratio << 20) | ($slave_ratio << 10) | $slave_ratio} ] + mww $EXT_PHY_CTRL_26 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] + mww $EXT_PHY_CTRL_26_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] + mww $EXT_PHY_CTRL_27 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] + mww $EXT_PHY_CTRL_27_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] + mww $EXT_PHY_CTRL_28 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] + mww $EXT_PHY_CTRL_28_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] + mww $EXT_PHY_CTRL_29 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] + mww $EXT_PHY_CTRL_29_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] + mww $EXT_PHY_CTRL_30 [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] + mww $EXT_PHY_CTRL_30_SHDW [ expr {($gatelvl_init_ratio << 16) | $gatelvl_init_ratio} ] mww $EXT_PHY_CTRL_31 0x00 mww $EXT_PHY_CTRL_31_SHDW 0x00 mww $EXT_PHY_CTRL_32 0x00 @@ -873,14 +875,14 @@ proc config_ddr_phy { } { mww $EXT_PHY_CTRL_35_SHDW 0x00 mww $EXT_PHY_CTRL_22 0x00 mww $EXT_PHY_CTRL_22_SHDW 0x00 - mww $EXT_PHY_CTRL_23 [ expr ($wr_dqs_slave_delay << 16) | $rd_dqs_slave_delay ] - mww $EXT_PHY_CTRL_23_SHDW [ expr ($wr_dqs_slave_delay << 16) | $rd_dqs_slave_delay ] - mww $EXT_PHY_CTRL_24 [ expr ($dq_offset << 24) | ($gatelvl_init_mode << 16) | $wr_data_slave_delay ] - mww $EXT_PHY_CTRL_24_SHDW [ expr ($dq_offset << 24) | ($gatelvl_init_mode << 16) | $wr_data_slave_delay << 0 ] - mww $EXT_PHY_CTRL_25 [ expr ($dq_offset << 21) | ($dq_offset << 14) | ($dq_offset << 7) | $dq_offset ] - mww $EXT_PHY_CTRL_25_SHDW [ expr ($dq_offset << 21) | ($dq_offset << 14) | ($dq_offset << 7) | $dq_offset ] - mww $EXT_PHY_CTRL_36 [ expr ($wrlvl_num_dq0 << 4) | $gatelvl_num_dq0 ] - mww $EXT_PHY_CTRL_36_SHDW [ expr ($wrlvl_num_dq0 << 4) | $gatelvl_num_dq0 ] + mww $EXT_PHY_CTRL_23 [ expr {($wr_dqs_slave_delay << 16) | $rd_dqs_slave_delay} ] + mww $EXT_PHY_CTRL_23_SHDW [ expr {($wr_dqs_slave_delay << 16) | $rd_dqs_slave_delay} ] + mww $EXT_PHY_CTRL_24 [ expr {($dq_offset << 24) | ($gatelvl_init_mode << 16) | $wr_data_slave_delay} ] + mww $EXT_PHY_CTRL_24_SHDW [ expr {($dq_offset << 24) | ($gatelvl_init_mode << 16) | $wr_data_slave_delay << 0} ] + mww $EXT_PHY_CTRL_25 [ expr {($dq_offset << 21) | ($dq_offset << 14) | ($dq_offset << 7) | $dq_offset} ] + mww $EXT_PHY_CTRL_25_SHDW [ expr {($dq_offset << 21) | ($dq_offset << 14) | ($dq_offset << 7) | $dq_offset} ] + mww $EXT_PHY_CTRL_36 [ expr {($wrlvl_num_dq0 << 4) | $gatelvl_num_dq0} ] + mww $EXT_PHY_CTRL_36_SHDW [ expr {($wrlvl_num_dq0 << 4) | $gatelvl_num_dq0} ] } proc config_ddr_timing { } { @@ -948,7 +950,7 @@ proc config_ddr3 { SDRAM_CONFIG } { emif_prcm_clk_enable vtp_enable - set dll [ expr [ mrw $CM_DLL_CTRL ] & ~0x01 ] + set dll [ expr {[ mrw $CM_DLL_CTRL ] & ~0x01 }] mww $CM_DLL_CTRL $dll while { !([ mrw $CM_DLL_CTRL ] & 0x04) } { } @@ -978,7 +980,7 @@ proc config_ddr3 { SDRAM_CONFIG } { sleep 10 - set tmp [ expr [ mrw $EXT_PHY_CTRL_36 ] | 0x0100 ] + set tmp [ expr {[ mrw $EXT_PHY_CTRL_36 ] | 0x0100 }] mww $EXT_PHY_CTRL_36 $tmp mww $EXT_PHY_CTRL_36_SHDW $tmp 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 new file mode 100644 index 0000000000..0b0bd9e88d --- /dev/null +++ b/tcl/target/ampere_emag.cfg @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# OpenOCD Target Configuration for eMAG ARMv8 Processor +# +# Copyright (c) 2019-2021, Ampere Computing LLC +# + +# +# Configure defaults for target +# Can be overriden in board configuration file +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME emag +} + +if { [info exists NUMCORES] } { + set _NUMCORES $NUMCORES +} else { + set _NUMCORES 32 +} + +if { [info exists ENDIAN] } { + set _ENDIAN $ENDIAN +} else { + set _ENDIAN little +} + +if { [info exists CPUTAPID ] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x4BA00477 +} + +# +# Configure JTAG TAP +# + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0x3 -expected-id $_CPUTAPID +set _TAPNAME $_CHIPNAME.cpu + +set _DAPNAME ${_TAPNAME}_dap +set _APNUM 1 +dap create $_DAPNAME -chain-position $_TAPNAME +$_DAPNAME apsel $_APNUM + +# Create the DAP AP0 MEM-AP AHB-AP target +target create AHB mem_ap -endian $_ENDIAN -dap $_DAPNAME -ap-num 0 + +# Create the DAP AP1 MEM-AP APB-AP target +target create APB mem_ap -endian $_ENDIAN -dap $_DAPNAME -ap-num 1 + +# +# Configure target CPUs +# + +# Build string used to enable smp mode +set _SMP_STR "target smp" + +for {set _i 0} {$_i < $_NUMCORES} {incr _i} { + # Format a string to reference which CPU target to use + set _TARGETNAME [format "${_TAPNAME}_%02d" $_i] + + # Create and configure Cross Trigger Interface (CTI) - required for halt and resume + set _CTINAME $_TARGETNAME.cti + cti create $_CTINAME -dap $_DAPNAME -ap-num $_APNUM -baseaddr [expr {0xFC020000 + ($_i << 20)}] + + # Create the target + target create $_TARGETNAME aarch64 -endian $_ENDIAN -dap $_DAPNAME -ap-num $_APNUM -cti $_CTINAME -coreid $_i + set _SMP_STR "$_SMP_STR $_TARGETNAME" + + # Clear CTI output/input enables that are not configured by OpenOCD for aarch64 + $_TARGETNAME configure -event examine-start [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 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 + }] + + # Enable OpenOCD HWTHREAD RTOS feature for GDB thread (CPU) selection support + # This feature presents CPU cores ("hardware threads") in an SMP system as threads to GDB + $_TARGETNAME configure -rtos hwthread +} +eval $_SMP_STR 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 new file mode 100644 index 0000000000..30ddc92a9d --- /dev/null +++ b/tcl/target/at91sama5d2.cfg @@ -0,0 +1,44 @@ +# 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 +# the SAM-BA monitor, when no boot file has been found in any external Flash +# memory. +# For more JTAG related information see, : +# https://ww1.microchip.com/downloads/en/DeviceDoc/SAMA5D2-Series-Data-sheet-ds60001476G.pdf +# +# If JTAGSEL pin: +# - 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 +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +# Cortex-A5 target +set _TARGETNAME $_CHIPNAME.cpu_a5 +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +target create $_TARGETNAME.0 cortex_a -dap $_CHIPNAME.dap 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/bcm2711.cfg b/tcl/target/bcm2711.cfg new file mode 100644 index 0000000000..f8d2b3a65b --- /dev/null +++ b/tcl/target/bcm2711.cfg @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# The Broadcom BCM2711 used in Raspberry Pi 4 +# No documentation was found on Broadcom website + +# Partial information is available in raspberry pi website: +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/ + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bcm2711 +} + +if { [info exists CHIPCORES] } { + set _cores $CHIPCORES +} else { + set _cores 4 +} + +if { [info exists USE_SMP] } { + set _USE_SMP $USE_SMP +} else { + set _USE_SMP 0 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 +adapter speed 4000 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# MEM-AP for direct access +target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 + +# these addresses are obtained from the ROM table via 'dap info 0' command +set _DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} +set _CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} + +set _smp_command "target smp" + +for { set _core 0 } { $_core < $_cores } { incr _core } { + set _CTINAME $_CHIPNAME.cti$_core + set _TARGETNAME $_CHIPNAME.cpu$_core + + cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 0 -baseaddr [lindex $_CTIBASE $_core] + target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME + + set _smp_command "$_smp_command $_TARGETNAME" +} + +if {$_USE_SMP} { + eval $_smp_command +} + +# default target is cpu0 +targets $_CHIPNAME.cpu0 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/bcm2835.cfg b/tcl/target/bcm2835.cfg new file mode 100644 index 0000000000..32a03666c4 --- /dev/null +++ b/tcl/target/bcm2835.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Broadcom chip used in the Raspberry Pi Model A, B, B+, +# the Compute Module, and the Raspberry Pi Zero. + +# Partial information is available in raspberry pi website: +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bcm2835 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x07b7617F +} + +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 5 +adapter speed 4000 + +target create $_CHIPNAME.cpu0 arm11 -chain-position $_CHIPNAME.cpu diff --git a/tcl/target/bcm2836.cfg b/tcl/target/bcm2836.cfg new file mode 100644 index 0000000000..04921315ed --- /dev/null +++ b/tcl/target/bcm2836.cfg @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# The Broadcom chip used in the Raspberry Pi 2 Model B + +# Partial information is available in raspberry pi website: +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bcm2836 +} + +if { [info exists CHIPCORES] } { + set _cores $CHIPCORES +} else { + set _cores 4 +} + +if { [info exists USE_SMP] } { + set _USE_SMP $USE_SMP +} else { + set _USE_SMP 0 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 +adapter speed 4000 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# MEM-AP for direct access +target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 + +# these addresses are obtained from the ROM table via 'dap info 0' command +set _DBGBASE {0x80010000 0x80012000 0x80014000 0x80016000} + +set _smp_command "target smp" + +for { set _core 0 } { $_core < $_cores } { incr _core } { + set _TARGETNAME $_CHIPNAME.cpu$_core + + target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -coreid $_core -dbgbase [lindex $_DBGBASE $_core] + $_TARGETNAME configure -event reset-assert-post { cortex_a dbginit } + + set _smp_command "$_smp_command $_CHIPNAME.cpu$_core" +} + +if {$_USE_SMP} { + eval $_smp_command +} + +# default target is cpu0 +targets $_CHIPNAME.cpu0 diff --git a/tcl/target/bcm2837.cfg b/tcl/target/bcm2837.cfg new file mode 100644 index 0000000000..749de31037 --- /dev/null +++ b/tcl/target/bcm2837.cfg @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Broadcom chip used in the Raspberry Pi 3, +# and in later models of the Raspberry Pi 2. + +# Partial information is available in raspberry pi website: +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837 +# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837b0 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bcm2837 +} + +if { [info exists CHIPCORES] } { + set _cores $CHIPCORES +} else { + set _cores 4 +} + +if { [info exists USE_SMP] } { + set _USE_SMP $USE_SMP +} else { + set _USE_SMP 0 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 +adapter speed 4000 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# MEM-AP for direct access +target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0 + +# these addresses are obtained from the ROM table via 'dap info 0' command +set _DBGBASE {0x80010000 0x80012000 0x80014000 0x80016000} +set _CTIBASE {0x80018000 0x80019000 0x8001a000 0x8001b000} + +set _smp_command "target smp" + +for { set _core 0 } { $_core < $_cores } { incr _core } { + set _CTINAME $_CHIPNAME.cti$_core + set _TARGETNAME $_CHIPNAME.cpu$_core + + cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 0 -baseaddr [lindex $_CTIBASE $_core] + target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME + $_TARGETNAME configure -event reset-assert-post { aarch64 dbginit } + + set _smp_command "$_smp_command $_TARGETNAME" +} + +if {$_USE_SMP} { + eval $_smp_command +} + +# default target is cpu0 +targets $_CHIPNAME.cpu0 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 b31dfe8d67..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 @@ -46,7 +48,7 @@ set _cores 16 # Create each core for { set _core $_core_start } { $_core < $_core_start + $_cores } { incr _core 1 } { - cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" @@ -72,7 +74,7 @@ proc core_up { args } { global _TARGETNAME # Examine remaining cores - foreach _core [set args] { + foreach _core $args { ${_TARGETNAME}$_core arp_examine } } diff --git a/tcl/target/bluenrg-x.cfg b/tcl/target/bluenrg-x.cfg index a9d321ee6b..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,16 +49,19 @@ 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))] { + if [expr {$WDOG_VALUE & (1 << 1)}] { set WDOG_VALUE_SET 1 - mww 0x40700008 [expr ($WDOG_VALUE & 0xFFFFFFFD)] + mww 0x40700008 [expr {$WDOG_VALUE & 0xFFFFFFFD}] } } } @@ -64,8 +69,8 @@ $_TARGETNAME configure -event resumed { global WDOG_VALUE global WDOG_VALUE_SET set _JTAG_IDCODE [mrw 0x40000004] - if {$_JTAG_IDCODE != 0x0201E041} { - if [expr $WDOG_VALUE_SET] { + 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 set WDOG_VALUE_SET 0 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 53b2c5d480..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. @@ -26,14 +27,14 @@ proc configC100 {} { dict set configC100 w_amba 1 dict set configC100 x_amba 1 # y = amba_clk * (w+1)*(x+1)*2/xtal_clk - dict set configC100 y_amba [expr ([dict get $configC100 CONFIG_SYS_HZ_CLOCK] * ( ([dict get $configC100 w_amba]+1 ) * ([dict get $configC100 x_amba]+1 ) *2 ) / [dict get $configC100 CFG_REFCLKFREQ]) ] + dict set configC100 y_amba [expr {[dict get $configC100 CONFIG_SYS_HZ_CLOCK] * ( ([dict get $configC100 w_amba]+1 ) * ([dict get $configC100 x_amba]+1 ) *2 ) / [dict get $configC100 CFG_REFCLKFREQ]} ] # Arm Clk 450MHz, must be a multiple of 25 MHz dict set configC100 CFG_ARM_CLOCK 450000000 dict set configC100 w_arm 0 dict set configC100 x_arm 1 # y = arm_clk * (w+1)*(x+1)*2/xtal_clk - dict set configC100 y_arm [expr ([dict get $configC100 CFG_ARM_CLOCK] * ( ([dict get $configC100 w_arm]+1 ) * ([dict get $configC100 x_arm]+1 ) *2 ) / [dict get $configC100 CFG_REFCLKFREQ]) ] + dict set configC100 y_arm [expr {[dict get $configC100 CFG_ARM_CLOCK] * ( ([dict get $configC100 w_arm]+1 ) * ([dict get $configC100 x_arm]+1 ) *2 ) / [dict get $configC100 CFG_REFCLKFREQ]} ] } @@ -43,7 +44,7 @@ proc setupTelo {} { # setup GPIO used as control signals for C100 setupGPIO - # This will allow acces to lower 8MB or NOR + # This will allow access to lower 8MB or NOR lowGPIO5 # setup NOR size,timing,etc. setupNOR @@ -79,7 +80,7 @@ proc setupNOR {} { #mww $EX_CS0_TMG3_REG # set EBUS clock 165/5=33MHz mww $EX_CLOCK_DIV_REG 0x5 - # everthing else is OK with default + # everything else is OK with default } proc bootNOR {} { @@ -111,23 +112,23 @@ proc setupGPIO {} { set GPIO_OE_REG [regs GPIO_OE_REG] # set GPIO29=GPIO17=1, GPIO5=0 - mww $GPIO_OUTPUT_REG [expr 1<<29 | 1<<17] + mww $GPIO_OUTPUT_REG [expr {1<<29 | 1<<17}] # enable [as output] GPIO29,GPIO17,GPIO5 - mww $GPIO_OE_REG [expr 1<<29 | 1<<17 | 1<<5] + mww $GPIO_OE_REG [expr {1<<29 | 1<<17 | 1<<5}] } proc highGPIO5 {} { echo "GPIO5 high" set GPIO_OUTPUT_REG [regs GPIO_OUTPUT_REG] # set GPIO5=1 - mmw $GPIO_OUTPUT_REG [expr 1 << 5] 0x0 + mmw $GPIO_OUTPUT_REG [expr {1 << 5}] 0x0 } proc lowGPIO5 {} { echo "GPIO5 low" set GPIO_OUTPUT_REG [regs GPIO_OUTPUT_REG] # set GPIO5=0 - mmw $GPIO_OUTPUT_REG 0x0 [expr 1 << 5] + mmw $GPIO_OUTPUT_REG 0x0 [expr {1 << 5}] } proc boardID {id} { @@ -159,11 +160,11 @@ proc boardID {id} { proc ooma_board_detect {} { set GPIO_BOOTSTRAP_REG [regs GPIO_BOOTSTRAP_REG] - # read the current value of the BOOTSRAP pins + # read the current value of the BOOTSTRAP pins set tmp [mrw $GPIO_BOOTSTRAP_REG] echo [format "GPIO_BOOTSTRAP_REG (0x%x): 0x%x" $GPIO_BOOTSTRAP_REG $tmp] # extract the GPBP bits - set gpbt [expr ($tmp &0x1C00) >> 10 | ($tmp & 0x40) >>3] + set gpbt [expr {($tmp &0x1C00) >> 10 | ($tmp & 0x40) >>3}] # display board ID echo [format "This is %s (0x%x)" [dict get [boardID $gpbt] $gpbt name] $gpbt] @@ -226,13 +227,13 @@ proc configureDDR2regs_256M {} { set wr_dqs_shift 0x40 # start DDRC - mw64bit $DENALI_CTL_02_DATA [expr $DENALI_CTL_02_VAL | (1 << 32)] + mw64bit $DENALI_CTL_02_DATA [expr {$DENALI_CTL_02_VAL | (1 << 32)}] # wait int_status[2] (DRAM init complete) echo -n "Waiting for DDR2 controller to init..." - set tmp [mrw [expr $DENALI_CTL_08_DATA + 4]] - while { [expr $tmp & 0x040000] == 0 } { + set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] + while { [expr {$tmp & 0x040000}] == 0 } { sleep 1 - set tmp [mrw [expr $DENALI_CTL_08_DATA + 4]] + set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] } echo "done." @@ -294,16 +295,16 @@ proc configureDDR2regs_128M {} { set wr_dqs_shift 0x40 # start DDRC - mw64bit $DENALI_CTL_02_DATA [expr $DENALI_CTL_02_VAL | (1 << 32)] + mw64bit $DENALI_CTL_02_DATA [expr {$DENALI_CTL_02_VAL | (1 << 32)}] # wait int_status[2] (DRAM init complete) echo -n "Waiting for DDR2 controller to init..." - set tmp [mrw [expr $DENALI_CTL_08_DATA + 4]] - while { [expr $tmp & 0x040000] == 0 } { + set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] + while { [expr {$tmp & 0x040000}] == 0 } { sleep 1 - set tmp [mrw [expr $DENALI_CTL_08_DATA + 4]] + set tmp [mrw [expr {$DENALI_CTL_08_DATA + 4}]] } # This is not necessary - #mw64bit $DENALI_CTL_11_DATA [expr ($DENALI_CTL_11_VAL & ~0x00007F0000000000) | ($wr_dqs_shift << 40) ] + #mw64bit $DENALI_CTL_11_DATA [expr {($DENALI_CTL_11_VAL & ~0x00007F0000000000) | ($wr_dqs_shift << 40)} ] echo "done." # do ddr2 training sequence @@ -341,14 +342,14 @@ proc setupUART0 {} { # Enable Divisor Latch access mmw $UART0_LCR $LCR_DLAB 0x0 # set the divisor to $tmp - mww $UART0_DLL [expr $tmp & 0xff] - mww $UART0_DLH [expr $tmp >> 8] + mww $UART0_DLL [expr {$tmp & 0xff}] + mww $UART0_DLH [expr {$tmp >> 8}] # Disable Divisor Latch access mmw $UART0_LCR 0x0 $LCR_DLAB # set the UART to 8N1 - mmw $UART0_LCR [expr $LCR_ONE_STOP | $LCR_CHAR_LEN_8 ] 0x0 + mmw $UART0_LCR [expr {$LCR_ONE_STOP | $LCR_CHAR_LEN_8} ] 0x0 # reset FIFO - mmw $UART0_IIR [expr $FCR_XMITRES | $FCR_RCVRRES | $FCR_FIFOEN ] 0x0 + mmw $UART0_IIR [expr {$FCR_XMITRES | $FCR_RCVRRES | $FCR_FIFOEN} ] 0x0 # enable FFUART mww $UART0_IER $IER_UUE } @@ -362,7 +363,7 @@ proc putcUART0 {char} { # convert the 'char' to digit set tmp [ scan $char %c ] # /* wait for room in the tx FIFO on FFUART */ - while {[expr [mrw $UART0_LSR] & $LSR_TEMT] == 0} { sleep 1 } + while {[expr {[mrw $UART0_LSR] & $LSR_TEMT}] == 0} { sleep 1 } mww $UART0_THR $tmp if { $char == "\n" } { putcUART0 \r } } @@ -372,7 +373,7 @@ proc putsUART0 {str} { set len [string length $str] while { $index < $len } { putcUART0 [string index $str $index] - set index [expr $index + 1] + set index [expr {$index + 1}] } } diff --git a/tcl/target/c100helper.tcl b/tcl/target/c100helper.tcl index 725ba709c9..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:" @@ -13,35 +14,33 @@ proc helpC100 {} { echo "10) showArmClk: will show current config registers for Arm Bus Clock" echo "11) setupArmClk: will setup Amba Bus Clock=450MHz" echo "12) ooma_board_detect: will show which version of Telo you have" - echo "13) setupDDR2: will configure DDR2 controller, you must have PLLs configureg" + echo "13) setupDDR2: will configure DDR2 controller, you must have PLLs configured" echo "14) showDDR2: will show DDR2 config registers" echo "15) showWatchdog: will show current register config for watchdog" echo "16) reboot: will trigger watchdog and reboot Telo (hw reset)" echo "17) bootNOR: will boot Telo from NOR" - echo "18) setupUART0: will configure UART0 for 115200 8N1, PLLs have to be confiured" + echo "18) setupUART0: will configure UART0 for 115200 8N1, PLLs have to be configured" echo "19) putcUART0: will print a character on UART0" echo "20) putsUART0: will print a string on UART0" - echo "21) trainDDR2: will run DDR2 training program" - echo "22) flashUBOOT: will prgram NOR sectors 0-3 with u-boot.bin" + echo "21) trainDDR2: will run DDR2 training program" + echo "22) flashUBOOT: will program NOR sectors 0-3 with u-boot.bin" } source [find mem_helper.tcl] # read a 64-bit register (memory mapped) proc mr64bit {reg} { - set value "" - mem2array value 32 $reg 2 - return $value + return [read_memory $reg 32 2] } # write a 64-bit register (memory mapped) proc mw64bit {reg value} { - set high [expr $value >> 32] - set low [expr $value & 0xffffffff] + set high [expr {$value >> 32}] + set low [expr {$value & 0xffffffff}] #echo [format "mw64bit(0x%x): 0x%08x%08x" $reg $high $low] mww $reg $low - mww [expr $reg+4] $high + mww [expr {$reg+4}] $high } @@ -117,21 +116,21 @@ proc showAmbaClk {} { set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] echo [format "CLKCORE_AHB_CLK_CNTRL (0x%x): 0x%x" $CLKCORE_AHB_CLK_CNTRL [mrw $CLKCORE_AHB_CLK_CNTRL]] - mem2array value 32 $CLKCORE_AHB_CLK_CNTRL 1 + set value [read_memory $CLKCORE_AHB_CLK_CNTRL 32 1] # see if the PLL is in bypass mode - set bypass [expr ($value(0) & $PLL_CLK_BYPASS) >> 24 ] + set bypass [expr {($value & $PLL_CLK_BYPASS) >> 24}] echo [format "PLL bypass bit: %d" $bypass] if {$bypass == 1} { - echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr $CFG_REFCLKFREQ/1000000]] + echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr {$CFG_REFCLKFREQ/1000000}]] } else { # nope, extract x,y,w and compute the PLL output freq. - set x [expr ($value(0) & 0x0001F0000) >> 16] + set x [expr {($value & 0x0001F0000) >> 16}] echo [format "x: %d" $x] - set y [expr ($value(0) & 0x00000007F)] + set y [expr {($value & 0x00000007F)}] echo [format "y: %d" $y] - set w [expr ($value(0) & 0x000000300) >> 8] + set w [expr {($value & 0x000000300) >> 8}] echo [format "w: %d" $w] - echo [format "Amba PLL Clk: %d (MHz)" [expr ($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000]] + echo [format "Amba PLL Clk: %d (MHz)" [expr {($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000}]] } } @@ -154,7 +153,7 @@ proc setupAmbaClk {} { set x [config x_amba] set y [config y_amba] - echo [format "Setting Amba PLL to lock to %d MHz" [expr $CONFIG_SYS_HZ_CLOCK/1000000]] + echo [format "Setting Amba PLL to lock to %d MHz" [expr {$CONFIG_SYS_HZ_CLOCK/1000000}]] #echo [format "setupAmbaClk: w= %d" $w] #echo [format "setupAmbaClk: x= %d" $x] #echo [format "setupAmbaClk: y= %d" $y] @@ -174,10 +173,10 @@ proc setupAmbaClk {} { sleep 1 # set X, W and X mmw $CLKCORE_AHB_CLK_CNTRL 0x0 0xFFFFFF - mmw $CLKCORE_AHB_CLK_CNTRL [expr (($x << 16) + ($w << 8) + $y)] 0x0 + mmw $CLKCORE_AHB_CLK_CNTRL [expr {($x << 16) + ($w << 8) + $y}] 0x0 # wait for PLL to lock echo "Waiting for Amba PLL to lock" - while {[expr [mrw $CLKCORE_PLL_STATUS] & $AHBCLK_PLL_LOCK] == 0} { sleep 1 } + while {[expr {[mrw $CLKCORE_PLL_STATUS] & $AHBCLK_PLL_LOCK]} == 0} { sleep 1 } # remove the internal PLL bypass mmw $CLKCORE_AHB_CLK_CNTRL 0x0 $AHB_PLL_BY_CTRL # remove PLL from BYPASS mode using MUX @@ -192,21 +191,21 @@ proc showArmClk {} { set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] echo [format "CLKCORE_ARM_CLK_CNTRL (0x%x): 0x%x" $CLKCORE_ARM_CLK_CNTRL [mrw $CLKCORE_ARM_CLK_CNTRL]] - mem2array value 32 $CLKCORE_ARM_CLK_CNTRL 1 + set value [read_memory $CLKCORE_ARM_CLK_CNTRL 32 1] # see if the PLL is in bypass mode - set bypass [expr ($value(0) & $PLL_CLK_BYPASS) >> 24 ] + set bypass [expr {($value & $PLL_CLK_BYPASS) >> 24}] echo [format "PLL bypass bit: %d" $bypass] if {$bypass == 1} { - echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr $CFG_REFCLKFREQ/1000000]] + echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr {$CFG_REFCLKFREQ/1000000}]] } else { # nope, extract x,y,w and compute the PLL output freq. - set x [expr ($value(0) & 0x0001F0000) >> 16] + set x [expr {($value & 0x0001F0000) >> 16}] echo [format "x: %d" $x] - set y [expr ($value(0) & 0x00000007F)] + set y [expr {($value & 0x00000007F)}] echo [format "y: %d" $y] - set w [expr ($value(0) & 0x000000300) >> 8] + set w [expr {($value & 0x000000300) >> 8}] echo [format "w: %d" $w] - echo [format "Arm PLL Clk: %d (MHz)" [expr ($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000]] + echo [format "Arm PLL Clk: %d (MHz)" [expr {($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000}]] } } @@ -228,7 +227,7 @@ proc setupArmClk {} { set x [config x_arm] set y [config y_arm] - echo [format "Setting Arm PLL to lock to %d MHz" [expr $CFG_ARM_CLOCK/1000000]] + echo [format "Setting Arm PLL to lock to %d MHz" [expr {$CFG_ARM_CLOCK/1000000}]] #echo [format "setupArmClk: w= %d" $w] #echo [format "setupArmaClk: x= %d" $x] #echo [format "setupArmaClk: y= %d" $y] @@ -248,10 +247,10 @@ proc setupArmClk {} { sleep 1 # set X, W and X mmw $CLKCORE_ARM_CLK_CNTRL 0x0 0xFFFFFF - mmw $CLKCORE_ARM_CLK_CNTRL [expr (($x << 16) + ($w << 8) + $y)] 0x0 + mmw $CLKCORE_ARM_CLK_CNTRL [expr {($x << 16) + ($w << 8) + $y}] 0x0 # wait for PLL to lock echo "Waiting for Amba PLL to lock" - while {[expr [mrw $CLKCORE_PLL_STATUS] & $FCLK_PLL_LOCK] == 0} { sleep 1 } + while {[expr {[mrw $CLKCORE_PLL_STATUS] & $FCLK_PLL_LOCK]} == 0} { sleep 1 } # remove the internal PLL bypass mmw $CLKCORE_ARM_CLK_CNTRL 0x0 $ARM_PLL_BY_CTRL # remove PLL from BYPASS mode using MUX @@ -281,11 +280,11 @@ proc setupDDR2 {} { # and not reset. mmw $BLOCK_RESET_REG 0x0 $DDR_RST - set M [expr 1024 * 1024] - set DDR_SZ_1024M [expr 1024 * $M] - set DDR_SZ_256M [expr 256 * $M] - set DDR_SZ_128M [expr 128 * $M] - set DDR_SZ_64M [expr 64 * $M] + set M [expr {1024 * 1024}] + set DDR_SZ_1024M [expr {1024 * $M}] + set DDR_SZ_256M [expr {256 * $M}] + set DDR_SZ_128M [expr {128 * $M}] + set DDR_SZ_64M [expr {64 * $M}] # ooma_board_detect returns DDR2 memory size set tmp [ooma_board_detect] if {$tmp == "128M"} { @@ -299,7 +298,7 @@ proc setupDDR2 {} { } # Memory setup register - mww $MEMORY_MAX_ADDR [expr ($ddr_size - 1) + $MEMORY_BASE_ADDR] + mww $MEMORY_MAX_ADDR [expr {($ddr_size - 1) + $MEMORY_BASE_ADDR}] # disable ROM remap mww $MEMORY_CR 0x0 # Take DDR controller out of reset @@ -442,12 +441,12 @@ proc initC100 {} { # APB init # // Setting APB Bus Wait states to 1, set post write # (*(volatile u32*)(APB_ACCESS_WS_REG)) = 0x40; - mww [expr $APB_ACCESS_WS_REG] 0x40 + mww $APB_ACCESS_WS_REG 0x40 # AHB init # // enable all 6 masters for ARAM - mmw $ASA_ARAM_TC_CR_REG [expr $ASA_TC_REQIDMAEN | $ASA_TC_REQTDMEN | $ASA_TC_REQIPSECUSBEN | $ASA_TC_REQARM0EN | $ASA_TC_REQARM1EN | $ASA_TC_REQMDMAEN] 0x0 + mmw $ASA_ARAM_TC_CR_REG [expr {$ASA_TC_REQIDMAEN | $ASA_TC_REQTDMEN | $ASA_TC_REQIPSECUSBEN | $ASA_TC_REQARM0EN | $ASA_TC_REQARM1EN | $ASA_TC_REQMDMAEN}] 0x0 # // enable all 6 masters for EBUS - mmw $ASA_EBUS_TC_CR_REG [expr $ASA_TC_REQIDMAEN | $ASA_TC_REQTDMEN | $ASA_TC_REQIPSECUSBEN | $ASA_TC_REQARM0EN | $ASA_TC_REQARM1EN | $ASA_TC_REQMDMAEN] 0x0 + mmw $ASA_EBUS_TC_CR_REG [expr {$ASA_TC_REQIDMAEN | $ASA_TC_REQTDMEN | $ASA_TC_REQIPSECUSBEN | $ASA_TC_REQARM0EN | $ASA_TC_REQARM1EN | $ASA_TC_REQMDMAEN}] 0x0 # ARAM init # // disable pipeline mode in ARAM diff --git a/tcl/target/c100regs.tcl b/tcl/target/c100regs.tcl index a2c7a60d05..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 @@ -35,43 +37,43 @@ dict set regsC100 EXP_CS4_BASEADDR 0x30000000 dict set regsC100 DDR_BASEADDR 0x80000000 -dict set regsC100 TDM_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x000000] -dict set regsC100 PHI_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x010000] -dict set regsC100 TDMA_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x020000] -dict set regsC100 ASA_DDR_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x040000] -dict set regsC100 ASA_ARAM_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x048000] -dict set regsC100 TIMER_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x050000] -dict set regsC100 ASD_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x060000] -dict set regsC100 GPIO_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x070000] -dict set regsC100 UART0_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x090000] -dict set regsC100 UART1_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x094000] -dict set regsC100 SPI_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x098000] -dict set regsC100 I2C_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x09C000] -dict set regsC100 INTC_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x0A0000] -dict set regsC100 CLKCORE_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x0B0000] -dict set regsC100 PUI_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x0B0000] -dict set regsC100 GEMAC_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x0D0000] -dict set regsC100 IDMA_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x0E0000] -dict set regsC100 MEMCORE_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x0F0000] -dict set regsC100 ASA_EBUS_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x100000] -dict set regsC100 ASA_AAB_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x108000] -dict set regsC100 GEMAC1_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x190000] -dict set regsC100 EBUS_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x1A0000] -dict set regsC100 MDMA_BASEADDR [expr [dict get $regsC100 APB_BASEADDR ] + 0x1E0000] +dict set regsC100 TDM_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x000000}] +dict set regsC100 PHI_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x010000}] +dict set regsC100 TDMA_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x020000}] +dict set regsC100 ASA_DDR_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x040000}] +dict set regsC100 ASA_ARAM_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x048000}] +dict set regsC100 TIMER_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x050000}] +dict set regsC100 ASD_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x060000}] +dict set regsC100 GPIO_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x070000}] +dict set regsC100 UART0_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x090000}] +dict set regsC100 UART1_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x094000}] +dict set regsC100 SPI_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x098000}] +dict set regsC100 I2C_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x09C000}] +dict set regsC100 INTC_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0A0000}] +dict set regsC100 CLKCORE_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0B0000}] +dict set regsC100 PUI_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0B0000}] +dict set regsC100 GEMAC_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0D0000}] +dict set regsC100 IDMA_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0E0000}] +dict set regsC100 MEMCORE_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x0F0000}] +dict set regsC100 ASA_EBUS_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x100000}] +dict set regsC100 ASA_AAB_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x108000}] +dict set regsC100 GEMAC1_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x190000}] +dict set regsC100 EBUS_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x1A0000}] +dict set regsC100 MDMA_BASEADDR [expr {[dict get $regsC100 APB_BASEADDR ] + 0x1E0000}] #//////////////////////////////////////////////////////////// #// AHB block // #//////////////////////////////////////////////////////////// -dict set regsC100 ASA_ARAM_PRI_REG [expr [dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x00] -dict set regsC100 ASA_ARAM_TC_REG [expr [dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x04] -dict set regsC100 ASA_ARAM_TC_CR_REG [expr [dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x08] -dict set regsC100 ASA_ARAM_STAT_REG [expr [dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x0C] +dict set regsC100 ASA_ARAM_PRI_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x00}] +dict set regsC100 ASA_ARAM_TC_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x04}] +dict set regsC100 ASA_ARAM_TC_CR_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x08}] +dict set regsC100 ASA_ARAM_STAT_REG [expr {[dict get $regsC100 ASA_ARAM_BASEADDR ] + 0x0C}] -dict set regsC100 ASA_EBUS_PRI_REG [expr [dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x00] -dict set regsC100 ASA_EBUS_TC_REG [expr [dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x04] -dict set regsC100 ASA_EBUS_TC_CR_REG [expr [dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x08] -dict set regsC100 ASA_EBUS_STAT_REG [expr [dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x0C] +dict set regsC100 ASA_EBUS_PRI_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x00}] +dict set regsC100 ASA_EBUS_TC_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x04}] +dict set regsC100 ASA_EBUS_TC_CR_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x08}] +dict set regsC100 ASA_EBUS_STAT_REG [expr {[dict get $regsC100 ASA_EBUS_BASEADDR ] + 0x0C}] dict set regsC100 IDMA_MASTER 0 dict set regsC100 TDMA_MASTER 1 @@ -87,16 +89,16 @@ dict set regsC100 MDMA_MASTER 5 #define ARM1_PRIORITY(level) (level << 16) #define MDMA_PRIORITY(level) (level << 20) -dict set regsC100 ASA_TC_REQIDMAEN [expr 1<<18] -dict set regsC100 ASA_TC_REQTDMEN [expr 1<<19] -dict set regsC100 ASA_TC_REQIPSECUSBEN [expr 1<<20] -dict set regsC100 ASA_TC_REQARM0EN [expr 1<<21] -dict set regsC100 ASA_TC_REQARM1EN [expr 1<<22] -dict set regsC100 ASA_TC_REQMDMAEN [expr 1<<23] +dict set regsC100 ASA_TC_REQIDMAEN [expr {1<<18}] +dict set regsC100 ASA_TC_REQTDMEN [expr {1<<19}] +dict set regsC100 ASA_TC_REQIPSECUSBEN [expr {1<<20}] +dict set regsC100 ASA_TC_REQARM0EN [expr {1<<21}] +dict set regsC100 ASA_TC_REQARM1EN [expr {1<<22}] +dict set regsC100 ASA_TC_REQMDMAEN [expr {1<<23}] dict set regsC100 MEMORY_BASE_ADDR 0x80000000 -dict set regsC100 MEMORY_MAX_ADDR [expr [dict get $regsC100 ASD_BASEADDR ] + 0x10] -dict set regsC100 MEMORY_CR [expr [dict get $regsC100 ASD_BASEADDR ] + 0x14] +dict set regsC100 MEMORY_MAX_ADDR [expr {[dict get $regsC100 ASD_BASEADDR ] + 0x10}] +dict set regsC100 MEMORY_CR [expr {[dict get $regsC100 ASD_BASEADDR ] + 0x14}] dict set regsC100 ROM_REMAP_EN 0x1 #define HAL_asb_priority(level) \ @@ -115,33 +117,33 @@ dict set regsC100 ROM_REMAP_EN 0x1 #// INTC block // #//////////////////////////////////////////////////////////// -dict set regsC100 INTC_ARM1_CONTROL_REG [expr [dict get $regsC100 INTC_BASEADDR ] + 0x18] +dict set regsC100 INTC_ARM1_CONTROL_REG [expr {[dict get $regsC100 INTC_BASEADDR ] + 0x18}] #//////////////////////////////////////////////////////////// #// TIMER block // #//////////////////////////////////////////////////////////// -dict set regsC100 TIMER0_CNTR_REG [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x00] -dict set regsC100 TIMER0_CURR_COUNT [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x04] -dict set regsC100 TIMER1_CNTR_REG [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x08] -dict set regsC100 TIMER1_CURR_COUNT [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x0C] +dict set regsC100 TIMER0_CNTR_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x00}] +dict set regsC100 TIMER0_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x04}] +dict set regsC100 TIMER1_CNTR_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x08}] +dict set regsC100 TIMER1_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x0C}] -dict set regsC100 TIMER2_CNTR_REG [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x18] -dict set regsC100 TIMER2_LBOUND_REG [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x10] -dict set regsC100 TIMER2_HBOUND_REG [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x14] -dict set regsC100 TIMER2_CURR_COUNT [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x1C] +dict set regsC100 TIMER2_CNTR_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x18}] +dict set regsC100 TIMER2_LBOUND_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x10}] +dict set regsC100 TIMER2_HBOUND_REG [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x14}] +dict set regsC100 TIMER2_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x1C}] -dict set regsC100 TIMER3_LOBND [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x20] -dict set regsC100 TIMER3_HIBND [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x24] -dict set regsC100 TIMER3_CTRL [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x28] -dict set regsC100 TIMER3_CURR_COUNT [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x2C] +dict set regsC100 TIMER3_LOBND [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x20}] +dict set regsC100 TIMER3_HIBND [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x24}] +dict set regsC100 TIMER3_CTRL [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x28}] +dict set regsC100 TIMER3_CURR_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x2C}] -dict set regsC100 TIMER_MASK [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x40] -dict set regsC100 TIMER_STATUS [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x50] -dict set regsC100 TIMER_ACK [expr [dict get $regsC100 TIMER_BASEADDR ] + 0x50] -dict set regsC100 TIMER_WDT_HIGH_BOUND [expr [dict get $regsC100 TIMER_BASEADDR ] + 0xD0] -dict set regsC100 TIMER_WDT_CONTROL [expr [dict get $regsC100 TIMER_BASEADDR ] + 0xD4] -dict set regsC100 TIMER_WDT_CURRENT_COUNT [expr [dict get $regsC100 TIMER_BASEADDR ] + 0xD8] +dict set regsC100 TIMER_MASK [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x40}] +dict set regsC100 TIMER_STATUS [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x50}] +dict set regsC100 TIMER_ACK [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0x50}] +dict set regsC100 TIMER_WDT_HIGH_BOUND [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0xD0}] +dict set regsC100 TIMER_WDT_CONTROL [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0xD4}] +dict set regsC100 TIMER_WDT_CURRENT_COUNT [expr {[dict get $regsC100 TIMER_BASEADDR ] + 0xD8}] @@ -149,40 +151,40 @@ dict set regsC100 TIMER_WDT_CURRENT_COUNT [expr [dict get $regsC100 TIMER_BASEAD #// EBUS block #//////////////////////////////////////////////////////////// -dict set regsC100 EX_SWRST_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x00] -dict set regsC100 EX_CSEN_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x04] -dict set regsC100 EX_CS0_SEG_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x08] -dict set regsC100 EX_CS1_SEG_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x0C] -dict set regsC100 EX_CS2_SEG_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x10] -dict set regsC100 EX_CS3_SEG_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x14] -dict set regsC100 EX_CS4_SEG_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x18] -dict set regsC100 EX_CS0_CFG_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x1C] -dict set regsC100 EX_CS1_CFG_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x20] -dict set regsC100 EX_CS2_CFG_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x24] -dict set regsC100 EX_CS3_CFG_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x28] -dict set regsC100 EX_CS4_CFG_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x2C] -dict set regsC100 EX_CS0_TMG1_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x30] -dict set regsC100 EX_CS1_TMG1_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x34] -dict set regsC100 EX_CS2_TMG1_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x38] -dict set regsC100 EX_CS3_TMG1_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x3C] -dict set regsC100 EX_CS4_TMG1_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x40] -dict set regsC100 EX_CS0_TMG2_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x44] -dict set regsC100 EX_CS1_TMG2_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x48] -dict set regsC100 EX_CS2_TMG2_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x4C] -dict set regsC100 EX_CS3_TMG2_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x50] -dict set regsC100 EX_CS4_TMG2_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x54] -dict set regsC100 EX_CS0_TMG3_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x58] -dict set regsC100 EX_CS1_TMG3_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x5C] -dict set regsC100 EX_CS2_TMG3_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x60] -dict set regsC100 EX_CS3_TMG3_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x64] -dict set regsC100 EX_CS4_TMG3_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x68] -dict set regsC100 EX_CLOCK_DIV_REG [expr [dict get $regsC100 EBUS_BASEADDR ] + 0x6C] - -dict set regsC100 EX_MFSM_REG [expr [dict get $regsC100 EBUS_BASEADDR] + 0x100] -dict set regsC100 EX_MFSM_REG [expr [dict get $regsC100 EBUS_BASEADDR] + 0x100] -dict set regsC100 EX_CSFSM_REG [expr [dict get $regsC100 EBUS_BASEADDR] + 0x104] -dict set regsC100 EX_WRFSM_REG [expr [dict get $regsC100 EBUS_BASEADDR] + 0x108] -dict set regsC100 EX_RDFSM_REG [expr [dict get $regsC100 EBUS_BASEADDR] + 0x10C] +dict set regsC100 EX_SWRST_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x00}] +dict set regsC100 EX_CSEN_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x04}] +dict set regsC100 EX_CS0_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x08}] +dict set regsC100 EX_CS1_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x0C}] +dict set regsC100 EX_CS2_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x10}] +dict set regsC100 EX_CS3_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x14}] +dict set regsC100 EX_CS4_SEG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x18}] +dict set regsC100 EX_CS0_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x1C}] +dict set regsC100 EX_CS1_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x20}] +dict set regsC100 EX_CS2_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x24}] +dict set regsC100 EX_CS3_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x28}] +dict set regsC100 EX_CS4_CFG_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x2C}] +dict set regsC100 EX_CS0_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x30}] +dict set regsC100 EX_CS1_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x34}] +dict set regsC100 EX_CS2_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x38}] +dict set regsC100 EX_CS3_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x3C}] +dict set regsC100 EX_CS4_TMG1_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x40}] +dict set regsC100 EX_CS0_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x44}] +dict set regsC100 EX_CS1_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x48}] +dict set regsC100 EX_CS2_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x4C}] +dict set regsC100 EX_CS3_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x50}] +dict set regsC100 EX_CS4_TMG2_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x54}] +dict set regsC100 EX_CS0_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x58}] +dict set regsC100 EX_CS1_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x5C}] +dict set regsC100 EX_CS2_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x60}] +dict set regsC100 EX_CS3_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x64}] +dict set regsC100 EX_CS4_TMG3_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x68}] +dict set regsC100 EX_CLOCK_DIV_REG [expr {[dict get $regsC100 EBUS_BASEADDR ] + 0x6C}] + +dict set regsC100 EX_MFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x100}] +dict set regsC100 EX_MFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x100}] +dict set regsC100 EX_CSFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x104}] +dict set regsC100 EX_WRFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x108}] +dict set regsC100 EX_RDFSM_REG [expr {[dict get $regsC100 EBUS_BASEADDR] + 0x10C}] dict set regsC100 EX_CLK_EN 0x00000001 @@ -211,21 +213,21 @@ dict set regsC100 EX_RDY_EDGE 0x00000800 #//////////////////////////////////////////////////////////// # GPIO outputs register -dict set regsC100 GPIO_OUTPUT_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x00] +dict set regsC100 GPIO_OUTPUT_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x00}] # GPIO Output Enable register -dict set regsC100 GPIO_OE_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x04] -dict set regsC100 GPIO_HI_INT_ENABLE_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x08] -dict set regsC100 GPIO_LO_INT_ENABLE_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x0C] +dict set regsC100 GPIO_OE_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x04}] +dict set regsC100 GPIO_HI_INT_ENABLE_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x08}] +dict set regsC100 GPIO_LO_INT_ENABLE_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x0C}] # GPIO input register -dict set regsC100 GPIO_INPUT_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x10] -dict set regsC100 APB_ACCESS_WS_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x14] -dict set regsC100 MUX_CONF_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x18] -dict set regsC100 SYSCONF_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x1C] -dict set regsC100 GPIO_ARM_ID_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x30] -dict set regsC100 GPIO_BOOTSTRAP_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x40] -dict set regsC100 GPIO_LOCK_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x38] -dict set regsC100 GPIO_IOCTRL_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x44] -dict set regsC100 GPIO_DEVID_REG [expr [dict get $regsC100 GPIO_BASEADDR ] + 0x50] +dict set regsC100 GPIO_INPUT_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x10}] +dict set regsC100 APB_ACCESS_WS_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x14}] +dict set regsC100 MUX_CONF_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x18}] +dict set regsC100 SYSCONF_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x1C}] +dict set regsC100 GPIO_ARM_ID_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x30}] +dict set regsC100 GPIO_BOOTSTRAP_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x40}] +dict set regsC100 GPIO_LOCK_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x38}] +dict set regsC100 GPIO_IOCTRL_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x44}] +dict set regsC100 GPIO_DEVID_REG [expr {[dict get $regsC100 GPIO_BASEADDR ] + 0x50}] dict set regsC100 GPIO_IOCTRL_A15A16 0x00000001 dict set regsC100 GPIO_IOCTRL_A17A18 0x00000002 @@ -258,31 +260,31 @@ dict set regsC100 GPIO_BOTH_EDGES 3 #// UART #//////////////////////////////////////////////////////////// -dict set regsC100 UART0_RBR [expr [dict get $regsC100 UART0_BASEADDR ] + 0x00] -dict set regsC100 UART0_THR [expr [dict get $regsC100 UART0_BASEADDR ] + 0x00] -dict set regsC100 UART0_DLL [expr [dict get $regsC100 UART0_BASEADDR ] + 0x00] -dict set regsC100 UART0_IER [expr [dict get $regsC100 UART0_BASEADDR ] + 0x04] -dict set regsC100 UART0_DLH [expr [dict get $regsC100 UART0_BASEADDR ] + 0x04] -dict set regsC100 UART0_IIR [expr [dict get $regsC100 UART0_BASEADDR ] + 0x08] -dict set regsC100 UART0_FCR [expr [dict get $regsC100 UART0_BASEADDR ] + 0x08] -dict set regsC100 UART0_LCR [expr [dict get $regsC100 UART0_BASEADDR ] + 0x0C] -dict set regsC100 UART0_MCR [expr [dict get $regsC100 UART0_BASEADDR ] + 0x10] -dict set regsC100 UART0_LSR [expr [dict get $regsC100 UART0_BASEADDR ] + 0x14] -dict set regsC100 UART0_MSR [expr [dict get $regsC100 UART0_BASEADDR ] + 0x18] -dict set regsC100 UART0_SCR [expr [dict get $regsC100 UART0_BASEADDR ] + 0x1C] - -dict set regsC100 UART1_RBR [expr [dict get $regsC100 UART1_BASEADDR ] + 0x00] -dict set regsC100 UART1_THR [expr [dict get $regsC100 UART1_BASEADDR ] + 0x00] -dict set regsC100 UART1_DLL [expr [dict get $regsC100 UART1_BASEADDR ] + 0x00] -dict set regsC100 UART1_IER [expr [dict get $regsC100 UART1_BASEADDR ] + 0x04] -dict set regsC100 UART1_DLH [expr [dict get $regsC100 UART1_BASEADDR ] + 0x04] -dict set regsC100 UART1_IIR [expr [dict get $regsC100 UART1_BASEADDR ] + 0x08] -dict set regsC100 UART1_FCR [expr [dict get $regsC100 UART1_BASEADDR ] + 0x08] -dict set regsC100 UART1_LCR [expr [dict get $regsC100 UART1_BASEADDR ] + 0x0C] -dict set regsC100 UART1_MCR [expr [dict get $regsC100 UART1_BASEADDR ] + 0x10] -dict set regsC100 UART1_LSR [expr [dict get $regsC100 UART1_BASEADDR ] + 0x14] -dict set regsC100 UART1_MSR [expr [dict get $regsC100 UART1_BASEADDR ] + 0x18] -dict set regsC100 UART1_SCR [expr [dict get $regsC100 UART1_BASEADDR ] + 0x1C] +dict set regsC100 UART0_RBR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x00}] +dict set regsC100 UART0_THR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x00}] +dict set regsC100 UART0_DLL [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x00}] +dict set regsC100 UART0_IER [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x04}] +dict set regsC100 UART0_DLH [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x04}] +dict set regsC100 UART0_IIR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x08}] +dict set regsC100 UART0_FCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x08}] +dict set regsC100 UART0_LCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x0C}] +dict set regsC100 UART0_MCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x10}] +dict set regsC100 UART0_LSR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x14}] +dict set regsC100 UART0_MSR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x18}] +dict set regsC100 UART0_SCR [expr {[dict get $regsC100 UART0_BASEADDR ] + 0x1C}] + +dict set regsC100 UART1_RBR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x00}] +dict set regsC100 UART1_THR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x00}] +dict set regsC100 UART1_DLL [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x00}] +dict set regsC100 UART1_IER [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x04}] +dict set regsC100 UART1_DLH [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x04}] +dict set regsC100 UART1_IIR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x08}] +dict set regsC100 UART1_FCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x08}] +dict set regsC100 UART1_LCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x0C}] +dict set regsC100 UART1_MCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x10}] +dict set regsC100 UART1_LSR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x14}] +dict set regsC100 UART1_MSR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x18}] +dict set regsC100 UART1_SCR [expr {[dict get $regsC100 UART1_BASEADDR ] + 0x1C}] # /* default */ dict set regsC100 LCR_CHAR_LEN_5 0x00 @@ -308,51 +310,51 @@ dict set regsC100 LCR_PSB 0x80 dict set regsC100 LCR_DLAB 0x80 #/* FIFO Error Status */ -dict set regsC100 LSR_FIFOE [expr 1 << 7] +dict set regsC100 LSR_FIFOE [expr {1 << 7}] #/* Transmitter Empty */ -dict set regsC100 LSR_TEMT [expr 1 << 6] +dict set regsC100 LSR_TEMT [expr {1 << 6}] #/* Transmit Data Request */ -dict set regsC100 LSR_TDRQ [expr 1 << 5] +dict set regsC100 LSR_TDRQ [expr {1 << 5}] #/* Break Interrupt */ -dict set regsC100 LSR_BI [expr 1 << 4] +dict set regsC100 LSR_BI [expr {1 << 4}] #/* Framing Error */ -dict set regsC100 LSR_FE [expr 1 << 3] +dict set regsC100 LSR_FE [expr {1 << 3}] #/* Parity Error */ -dict set regsC100 LSR_PE [expr 1 << 2] +dict set regsC100 LSR_PE [expr {1 << 2}] #/* Overrun Error */ -dict set regsC100 LSR_OE [expr 1 << 1] +dict set regsC100 LSR_OE [expr {1 << 1}] #/* Data Ready */ -dict set regsC100 LSR_DR [expr 1 << 0] +dict set regsC100 LSR_DR [expr {1 << 0}] #/* DMA Requests Enable */ -dict set regsC100 IER_DMAE [expr 1 << 7] +dict set regsC100 IER_DMAE [expr {1 << 7}] #/* UART Unit Enable */ -dict set regsC100 IER_UUE [expr 1 << 6] +dict set regsC100 IER_UUE [expr {1 << 6}] #/* NRZ coding Enable */ -dict set regsC100 IER_NRZE [expr 1 << 5] +dict set regsC100 IER_NRZE [expr {1 << 5}] #/* Receiver Time Out Interrupt Enable */ -dict set regsC100 IER_RTIOE [expr 1 << 4] +dict set regsC100 IER_RTIOE [expr {1 << 4}] #/* Modem Interrupt Enable */ -dict set regsC100 IER_MIE [expr 1 << 3] +dict set regsC100 IER_MIE [expr {1 << 3}] #/* Receiver Line Status Interrupt Enable */ -dict set regsC100 IER_RLSE [expr 1 << 2] +dict set regsC100 IER_RLSE [expr {1 << 2}] #/* Transmit Data request Interrupt Enable */ -dict set regsC100 IER_TIE [expr 1 << 1] +dict set regsC100 IER_TIE [expr {1 << 1}] #/* Receiver Data Available Interrupt Enable */ -dict set regsC100 IER_RAVIE [expr 1 << 0] +dict set regsC100 IER_RAVIE [expr {1 << 0}] #/* FIFO Mode Enable Status */ -dict set regsC100 IIR_FIFOES1 [expr 1 << 7] +dict set regsC100 IIR_FIFOES1 [expr {1 << 7}] #/* FIFO Mode Enable Status */ -dict set regsC100 IIR_FIFOES0 [expr 1 << 6] +dict set regsC100 IIR_FIFOES0 [expr {1 << 6}] #/* Time Out Detected */ -dict set regsC100 IIR_TOD [expr 1 << 3] +dict set regsC100 IIR_TOD [expr {1 << 3}] #/* Interrupt Source Encoded */ -dict set regsC100 IIR_IID2 [expr 1 << 2] +dict set regsC100 IIR_IID2 [expr {1 << 2}] #/* Interrupt Source Encoded */ -dict set regsC100 IIR_IID1 [expr 1 << 1] +dict set regsC100 IIR_IID1 [expr {1 << 1}] #/* Interrupt Pending (active low) */ -dict set regsC100 IIR_IP [expr 1 << 0] +dict set regsC100 IIR_IP [expr {1 << 0}] #/* UART 16550 FIFO Control Register */ dict set regsC100 FCR_FIFOEN 0x01 @@ -372,17 +374,17 @@ dict set regsC100 IER_TXTH 0x02 #// CLK + RESET block #//////////////////////////////////////////////////////////// -dict set regsC100 CLKCORE_ARM_CLK_CNTRL [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x00] -dict set regsC100 CLKCORE_AHB_CLK_CNTRL [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x04] -dict set regsC100 CLKCORE_PLL_STATUS [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x08] -dict set regsC100 CLKCORE_CLKDIV_CNTRL [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x0C] -dict set regsC100 CLKCORE_TDM_CLK_CNTRL [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x10] -dict set regsC100 CLKCORE_FSYNC_CNTRL [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x14] -dict set regsC100 CLKCORE_CLK_PWR_DWN [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x18] -dict set regsC100 CLKCORE_RNG_CNTRL [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x1C] -dict set regsC100 CLKCORE_RNG_STATUS [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x20] -dict set regsC100 CLKCORE_ARM_CLK_CNTRL2 [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x24] -dict set regsC100 CLKCORE_TDM_REF_DIV_RST [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x40] +dict set regsC100 CLKCORE_ARM_CLK_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x00}] +dict set regsC100 CLKCORE_AHB_CLK_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x04}] +dict set regsC100 CLKCORE_PLL_STATUS [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x08}] +dict set regsC100 CLKCORE_CLKDIV_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x0C}] +dict set regsC100 CLKCORE_TDM_CLK_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x10}] +dict set regsC100 CLKCORE_FSYNC_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x14}] +dict set regsC100 CLKCORE_CLK_PWR_DWN [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x18}] +dict set regsC100 CLKCORE_RNG_CNTRL [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x1C}] +dict set regsC100 CLKCORE_RNG_STATUS [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x20}] +dict set regsC100 CLKCORE_ARM_CLK_CNTRL2 [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x24}] +dict set regsC100 CLKCORE_TDM_REF_DIV_RST [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x40}] dict set regsC100 ARM_PLL_BY_CTRL 0x80000000 dict set regsC100 ARM_AHB_BYP 0x04000000 @@ -429,8 +431,8 @@ dict set regsC100 FCLK_PLL_LOCK 0x00000001 #// reset block -dict set regsC100 BLOCK_RESET_REG [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x100] -dict set regsC100 CSP_RESET_REG [expr [dict get $regsC100 CLKCORE_BASEADDR ] + 0x104] +dict set regsC100 BLOCK_RESET_REG [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x100}] +dict set regsC100 CSP_RESET_REG [expr {[dict get $regsC100 CLKCORE_BASEADDR ] + 0x104}] dict set regsC100 RNG_RST 0x1000 dict set regsC100 IPSEC_RST 0x0800 @@ -451,42 +453,42 @@ dict set regsC100 PCI_RST 0x0001 #//////////////////////////////////////////////////////////////// dict set regsC100 DDR_CONFIG_BASEADDR 0x0D000000 -dict set regsC100 DENALI_CTL_00_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x00] -dict set regsC100 DENALI_CTL_01_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x08] -dict set regsC100 DENALI_CTL_02_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x10] -dict set regsC100 DENALI_CTL_03_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x18] -dict set regsC100 DENALI_CTL_04_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x20] -dict set regsC100 DENALI_CTL_05_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x28] -dict set regsC100 DENALI_CTL_06_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x30] -dict set regsC100 DENALI_CTL_07_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x38] -dict set regsC100 DENALI_CTL_08_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x40] -dict set regsC100 DENALI_CTL_09_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x48] -dict set regsC100 DENALI_CTL_10_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x50] -dict set regsC100 DENALI_CTL_11_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x58] -dict set regsC100 DENALI_CTL_12_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x60] -dict set regsC100 DENALI_CTL_13_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x68] -dict set regsC100 DENALI_CTL_14_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x70] -dict set regsC100 DENALI_CTL_15_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x78] -dict set regsC100 DENALI_CTL_16_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x80] -dict set regsC100 DENALI_CTL_17_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x88] -dict set regsC100 DENALI_CTL_18_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x90] -dict set regsC100 DENALI_CTL_19_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x98] -dict set regsC100 DENALI_CTL_20_DATA [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0xA0] +dict set regsC100 DENALI_CTL_00_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x00}] +dict set regsC100 DENALI_CTL_01_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x08}] +dict set regsC100 DENALI_CTL_02_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x10}] +dict set regsC100 DENALI_CTL_03_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x18}] +dict set regsC100 DENALI_CTL_04_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x20}] +dict set regsC100 DENALI_CTL_05_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x28}] +dict set regsC100 DENALI_CTL_06_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x30}] +dict set regsC100 DENALI_CTL_07_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x38}] +dict set regsC100 DENALI_CTL_08_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x40}] +dict set regsC100 DENALI_CTL_09_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x48}] +dict set regsC100 DENALI_CTL_10_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x50}] +dict set regsC100 DENALI_CTL_11_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x58}] +dict set regsC100 DENALI_CTL_12_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x60}] +dict set regsC100 DENALI_CTL_13_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x68}] +dict set regsC100 DENALI_CTL_14_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x70}] +dict set regsC100 DENALI_CTL_15_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x78}] +dict set regsC100 DENALI_CTL_16_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x80}] +dict set regsC100 DENALI_CTL_17_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x88}] +dict set regsC100 DENALI_CTL_18_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x90}] +dict set regsC100 DENALI_CTL_19_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x98}] +dict set regsC100 DENALI_CTL_20_DATA [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0xA0}] # 32-bit value -dict set regsC100 DENALI_READY_CHECK [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x44] +dict set regsC100 DENALI_READY_CHECK [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x44}] # 8-bit -dict set regsC100 DENALI_WR_DQS [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x5D] +dict set regsC100 DENALI_WR_DQS [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x5D}] # 8-bit -dict set regsC100 DENALI_DQS_OUT [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x5A] +dict set regsC100 DENALI_DQS_OUT [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x5A}] # 8-bit -dict set regsC100 DENALI_DQS_DELAY0 [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x4F] +dict set regsC100 DENALI_DQS_DELAY0 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] + 0x4F}] # 8-bit -dict set regsC100 DENALI_DQS_DELAY1 [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x50] +dict set regsC100 DENALI_DQS_DELAY1 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x50}] # 8-bit -dict set regsC100 DENALI_DQS_DELAY2 [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x51] +dict set regsC100 DENALI_DQS_DELAY2 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x51}] # 8-bit -dict set regsC100 DENALI_DQS_DELAY3 [expr [dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x52] +dict set regsC100 DENALI_DQS_DELAY3 [expr {[dict get $regsC100 DDR_CONFIG_BASEADDR ] +0x52}] # end of proc regsC100 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 859a92539a..54afb64289 100644 --- a/tcl/target/davinci.cfg +++ b/tcl/target/davinci.cfg @@ -1,10 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Utility code for DaVinci-family chips # # davinci_pinmux: assigns PINMUX$reg <== $value proc davinci_pinmux {soc reg value} { - mww [expr [dict get $soc sysbase] + 4 * $reg] $value + mww [expr {[dict get $soc sysbase] + 4 * $reg}] $value } source [find mem_helper.tcl] @@ -22,53 +24,53 @@ source [find mem_helper.tcl] # PLL version 0x02: tested on dm355 # REVISIT: On dm6446/dm357 the PLLRST polarity is different. proc pll_v02_setup {pll_addr mult config} { - set pll_ctrl_addr [expr $pll_addr + 0x100] + set pll_ctrl_addr [expr {$pll_addr + 0x100}] set pll_ctrl [mrw $pll_ctrl_addr] # 1 - clear CLKMODE (bit 8) iff using on-chip oscillator # NOTE: this assumes we should clear that bit - set pll_ctrl [expr $pll_ctrl & ~0x0100] + set pll_ctrl [expr {$pll_ctrl & ~0x0100}] mww $pll_ctrl_addr $pll_ctrl # 2 - clear PLLENSRC (bit 5) - set pll_ctrl [expr $pll_ctrl & ~0x0020] + set pll_ctrl [expr {$pll_ctrl & ~0x0020}] mww $pll_ctrl_addr $pll_ctrl # 3 - clear PLLEN (bit 0) ... enter bypass mode - set pll_ctrl [expr $pll_ctrl & ~0x0001] + set pll_ctrl [expr {$pll_ctrl & ~0x0001}] mww $pll_ctrl_addr $pll_ctrl # 4 - wait at least 4 refclk cycles sleep 1 # 5 - set PLLRST (bit 3) - set pll_ctrl [expr $pll_ctrl | 0x0008] + set pll_ctrl [expr {$pll_ctrl | 0x0008}] mww $pll_ctrl_addr $pll_ctrl # 6 - set PLLDIS (bit 4) - set pll_ctrl [expr $pll_ctrl | 0x0010] + set pll_ctrl [expr {$pll_ctrl | 0x0010}] mww $pll_ctrl_addr $pll_ctrl # 7 - clear PLLPWRDN (bit 1) - set pll_ctrl [expr $pll_ctrl & ~0x0002] + set pll_ctrl [expr {$pll_ctrl & ~0x0002}] mww $pll_ctrl_addr $pll_ctrl # 8 - clear PLLDIS (bit 4) - set pll_ctrl [expr $pll_ctrl & ~0x0010] + set pll_ctrl [expr {$pll_ctrl & ~0x0010}] mww $pll_ctrl_addr $pll_ctrl # 9 - optional: write prediv, postdiv, and pllm # NOTE: for dm355 PLL1, postdiv is controlled via MISC register - mww [expr $pll_addr + 0x0110] [expr ($mult - 1) & 0xff] + mww [expr {$pll_addr + 0x0110}] [expr {($mult - 1) & 0xff}] if { [dict exists $config prediv] } { set div [dict get $config prediv] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0114] $div + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0114}] $div } if { [dict exists $config postdiv] } { set div [dict get $config postdiv] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0128] $div + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0128}] $div } # 10 - optional: set plldiv1, plldiv2, ... @@ -78,47 +80,47 @@ proc pll_v02_setup {pll_addr mult config} { set go 0 if { [dict exists $config div1] } { set div [dict get $config div1] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0118] $div + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0118}] $div set go 1 } if { [dict exists $config div2] } { set div [dict get $config div2] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x011c] $div + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x011c}] $div set go 1 } if { [dict exists $config div3] } { set div [dict get $config div3] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0120] $div + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0120}] $div set go 1 } if { [dict exists $config div4] } { set div [dict get $config div4] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0160] $div + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0160}] $div set go 1 } if { [dict exists $config div5] } { set div [dict get $config div5] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0164] $div + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0164}] $div set go 1 } if {$go != 0} { # write pllcmd.GO; poll pllstat.GO - mww [expr $pll_addr + 0x0138] 0x01 - set pllstat [expr $pll_addr + 0x013c] - while {[expr [mrw $pllstat] & 0x01] != 0} { sleep 1 } + mww [expr {$pll_addr + 0x0138}] 0x01 + set pllstat [expr {$pll_addr + 0x013c}] + while {[expr {[mrw $pllstat] & 0x01}] != 0} { sleep 1 } } - mww [expr $pll_addr + 0x0138] 0x00 + mww [expr {$pll_addr + 0x0138}] 0x00 # 11 - wait at least 5 usec for reset to finish # (assume covered by overheads including JTAG messaging) # 12 - clear PLLRST (bit 3) - set pll_ctrl [expr $pll_ctrl & ~0x0008] + set pll_ctrl [expr {$pll_ctrl & ~0x0008}] mww $pll_ctrl_addr $pll_ctrl # 13 - wait at least 8000 refclk cycles for PLL to lock @@ -126,53 +128,53 @@ proc pll_v02_setup {pll_addr mult config} { sleep 3 # 14 - set PLLEN (bit 0) ... leave bypass mode - set pll_ctrl [expr $pll_ctrl | 0x0001] + set pll_ctrl [expr {$pll_ctrl | 0x0001}] mww $pll_ctrl_addr $pll_ctrl } # PLL version 0x03: tested on dm365 proc pll_v03_setup {pll_addr mult config} { - set pll_ctrl_addr [expr $pll_addr + 0x100] - set pll_secctrl_addr [expr $pll_addr + 0x108] + set pll_ctrl_addr [expr {$pll_addr + 0x100}] + set pll_secctrl_addr [expr {$pll_addr + 0x108}] set pll_ctrl [mrw $pll_ctrl_addr] # 1 - power up the PLL - set pll_ctrl [expr $pll_ctrl & ~0x0002] + set pll_ctrl [expr {$pll_ctrl & ~0x0002}] mww $pll_ctrl_addr $pll_ctrl # 2 - clear PLLENSRC (bit 5) - set pll_ctrl [expr $pll_ctrl & ~0x0020] + set pll_ctrl [expr {$pll_ctrl & ~0x0020}] mww $pll_ctrl_addr $pll_ctrl # 2 - clear PLLEN (bit 0) ... enter bypass mode - set pll_ctrl [expr $pll_ctrl & ~0x0001] + set pll_ctrl [expr {$pll_ctrl & ~0x0001}] mww $pll_ctrl_addr $pll_ctrl # 3 - wait at least 4 refclk cycles sleep 1 # 4 - set PLLRST (bit 3) - set pll_ctrl [expr $pll_ctrl | 0x0008] + set pll_ctrl [expr {$pll_ctrl | 0x0008}] mww $pll_ctrl_addr $pll_ctrl # 5 - wait at least 5 usec sleep 1 # 6 - clear PLLRST (bit 3) - set pll_ctrl [expr $pll_ctrl & ~0x0008] + set pll_ctrl [expr {$pll_ctrl & ~0x0008}] mww $pll_ctrl_addr $pll_ctrl # 9 - optional: write prediv, postdiv, and pllm - mww [expr $pll_addr + 0x0110] [expr ($mult / 2) & 0x1ff] + mww [expr {$pll_addr + 0x0110}] [expr {($mult / 2) & 0x1ff}] if { [dict exists $config prediv] } { set div [dict get $config prediv] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0114] $div + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0114}] $div } if { [dict exists $config postdiv] } { set div [dict get $config postdiv] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0128] $div + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0128}] $div } # 10 - write start sequence to PLLSECCTL @@ -187,99 +189,99 @@ proc pll_v03_setup {pll_addr mult config} { set aln 0 if { [dict exists $config div1] } { set div [dict get $config div1] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0118] $div - set aln [expr $aln | 0x1] + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0118}] $div + set aln [expr {$aln | 0x1}] } else { - mww [expr $pll_addr + 0x0118] 0 + mww [expr {$pll_addr + 0x0118}] 0 } if { [dict exists $config div2] } { set div [dict get $config div2] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x011c] $div - set aln [expr $aln | 0x2] + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x011c}] $div + set aln [expr {$aln | 0x2}] } else { - mww [expr $pll_addr + 0x011c] 0 + mww [expr {$pll_addr + 0x011c}] 0 } if { [dict exists $config div3] } { set div [dict get $config div3] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0120] $div - set aln [expr $aln | 0x4] + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0120}] $div + set aln [expr {$aln | 0x4}] } else { - mww [expr $pll_addr + 0x0120] 0 + mww [expr {$pll_addr + 0x0120}] 0 } if { [dict exists $config oscdiv] } { set div [dict get $config oscdiv] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0124] $div + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0124}] $div } else { - mww [expr $pll_addr + 0x0124] 0 + mww [expr {$pll_addr + 0x0124}] 0 } if { [dict exists $config div4] } { set div [dict get $config div4] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0160] $div - set aln [expr $aln | 0x8] + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0160}] $div + set aln [expr {$aln | 0x8}] } else { - mww [expr $pll_addr + 0x0160] 0 + mww [expr {$pll_addr + 0x0160}] 0 } if { [dict exists $config div5] } { set div [dict get $config div5] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0164] $div - set aln [expr $aln | 0x10] + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0164}] $div + set aln [expr {$aln | 0x10}] } else { - mww [expr $pll_addr + 0x0164] 0 + mww [expr {$pll_addr + 0x0164}] 0 } if { [dict exists $config div6] } { set div [dict get $config div6] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0168] $div - set aln [expr $aln | 0x20] + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0168}] $div + set aln [expr {$aln | 0x20}] } else { - mww [expr $pll_addr + 0x0168] 0 + mww [expr {$pll_addr + 0x0168}] 0 } if { [dict exists $config div7] } { set div [dict get $config div7] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x016c] $div - set aln [expr $aln | 0x40] + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x016c}] $div + set aln [expr {$aln | 0x40}] } else { - mww [expr $pll_addr + 0x016c] 0 + mww [expr {$pll_addr + 0x016c}] 0 } if { [dict exists $config div8] } { set div [dict get $config div8] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0170] $div - set aln [expr $aln | 0x80] + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0170}] $div + set aln [expr {$aln | 0x80}] } else { - mww [expr $pll_addr + 0x0170] 0 + mww [expr {$pll_addr + 0x0170}] 0 } if { [dict exists $config div9] } { set div [dict get $config div9] - set div [expr 0x8000 | ($div - 1)] - mww [expr $pll_addr + 0x0174] $div - set aln [expr $aln | 0x100] + set div [expr {0x8000 | ($div - 1)}] + mww [expr {$pll_addr + 0x0174}] $div + set aln [expr {$aln | 0x100}] } else { - mww [expr $pll_addr + 0x0174] 0 + mww [expr {$pll_addr + 0x0174}] 0 } if {$aln != 0} { # clear pllcmd.GO - mww [expr $pll_addr + 0x0138] 0x00 - # write alingment flags - mww [expr $pll_addr + 0x0140] $aln + mww [expr {$pll_addr + 0x0138}] 0x00 + # write alignment flags + mww [expr {$pll_addr + 0x0140}] $aln # write pllcmd.GO; poll pllstat.GO - mww [expr $pll_addr + 0x0138] 0x01 - set pllstat [expr $pll_addr + 0x013c] - while {[expr [mrw $pllstat] & 0x01] != 0} { sleep 1 } + mww [expr {$pll_addr + 0x0138}] 0x01 + set pllstat [expr {$pll_addr + 0x013c}] + while {[expr {[mrw $pllstat] & 0x01}] != 0} { sleep 1 } } - mww [expr $pll_addr + 0x0138] 0x00 + mww [expr {$pll_addr + 0x0138}] 0x00 set addr [dict get $config ctladdr] - while {[expr [mrw $addr] & 0x0e000000] != 0x0e000000} { sleep 1 } + while {[expr {[mrw $addr] & 0x0e000000}] != 0x0e000000} { sleep 1 } # 12 - set PLLEN (bit 0) ... leave bypass mode - set pll_ctrl [expr $pll_ctrl | 0x0001] + set pll_ctrl [expr {$pll_ctrl | 0x0001}] mww $pll_ctrl_addr $pll_ctrl } @@ -290,29 +292,29 @@ proc pll_v03_setup {pll_addr mult config} { proc psc_enable {module} { set psc_addr 0x01c41000 # write MDCTL - mmw [expr $psc_addr + 0x0a00 + (4 * $module)] 0x03 0x1f + mmw [expr {$psc_addr + 0x0a00 + (4 * $module)}] 0x03 0x1f } # prepare a non-DSP module to be reset; finish with psc_go proc psc_reset {module} { set psc_addr 0x01c41000 # write MDCTL - mmw [expr $psc_addr + 0x0a00 + (4 * $module)] 0x01 0x1f + mmw [expr {$psc_addr + 0x0a00 + (4 * $module)}] 0x01 0x1f } # execute non-DSP PSC transition(s) set up by psc_enable, psc_reset, etc proc psc_go {} { set psc_addr 0x01c41000 - set ptstat_addr [expr $psc_addr + 0x0128] + set ptstat_addr [expr {$psc_addr + 0x0128}] # just in case PTSTAT.go isn't clear - while { [expr [mrw $ptstat_addr] & 0x01] != 0 } { sleep 1 } + while { [expr {[mrw $ptstat_addr] & 0x01}] != 0 } { sleep 1 } # write PTCMD.go ... ignoring any DSP power domain - mww [expr $psc_addr + 0x0120] 1 + mww [expr {$psc_addr + 0x0120}] 1 # wait for PTSTAT.go to clear (again ignoring DSP power domain) - while { [expr [mrw $ptstat_addr] & 0x01] != 0 } { sleep 1 } + while { [expr {[mrw $ptstat_addr] & 0x01}] != 0 } { sleep 1 } } # @@ -344,34 +346,34 @@ proc davinci_wdog_reset {} { # # EMUMGT_CLKSPEED: write FREE bit to run despite emulation halt - mww phys [expr $timer2_phys + 0x28] 0x00004000 + mww phys [expr {$timer2_phys + 0x28}] 0x00004000 # # Part II -- in case watchdog hasn't been set up # # TCR: disable, force internal clock source - mww phys [expr $timer2_phys + 0x20] 0 + mww phys [expr {$timer2_phys + 0x20}] 0 # TGCR: reset, force to 64-bit wdog mode, un-reset ("initial" state) - mww phys [expr $timer2_phys + 0x24] 0 - mww phys [expr $timer2_phys + 0x24] 0x110b + mww phys [expr {$timer2_phys + 0x24}] 0 + mww phys [expr {$timer2_phys + 0x24}] 0x110b # clear counter (TIM12, TIM34) and period (PRD12, PRD34) registers # so watchdog triggers ASAP - mww phys [expr $timer2_phys + 0x10] 0 - mww phys [expr $timer2_phys + 0x14] 0 - mww phys [expr $timer2_phys + 0x18] 0 - mww phys [expr $timer2_phys + 0x1c] 0 + mww phys [expr {$timer2_phys + 0x10}] 0 + mww phys [expr {$timer2_phys + 0x14}] 0 + mww phys [expr {$timer2_phys + 0x18}] 0 + mww phys [expr {$timer2_phys + 0x1c}] 0 # WDTCR: put into pre-active state, then active - mww phys [expr $timer2_phys + 0x28] 0xa5c64000 - mww phys [expr $timer2_phys + 0x28] 0xda7e4000 + mww phys [expr {$timer2_phys + 0x28}] 0xa5c64000 + mww phys [expr {$timer2_phys + 0x28}] 0xda7e4000 # # Part III -- it's ready to rumble # # WDTCR: write invalid WDKEY to trigger reset - mww phys [expr $timer2_phys + 0x28] 0x00004000 + mww phys [expr {$timer2_phys + 0x28}] 0x00004000 } 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 c789efc723..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 # @@ -43,6 +45,8 @@ $_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME efm32 0 0 0 0 $_TARGETNAME +flash bank userdata.flash efm32 0x0FE00000 0 0 0 $_TARGETNAME +flash bank lockbits.flash efm32 0x0FE04000 0 0 0 $_TARGETNAME if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to diff --git a/tcl/target/efm32_stlink.cfg b/tcl/target/efm32_stlink.cfg deleted file mode 100644 index 230155ea02..0000000000 --- a/tcl/target/efm32_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/efm32_stlink.cfg is deprecated, please switch to target/efm32.cfg" -source [find target/efm32.cfg] 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/eos_s3.cfg b/tcl/target/eos_s3.cfg new file mode 100644 index 0000000000..150ef4e31c --- /dev/null +++ b/tcl/target/eos_s3.cfg @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# QuickLogic EOS S3 +# https://www.quicklogic.com/products/soc/eos-s3-microcontroller/ + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME eos_s3 +} + +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x80000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x4ba00477 + } { + set _CPUTAPID 0x2ba01477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -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 + +# For now we use SRAM only for software upload +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +adapter speed 4000 + +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/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/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 new file mode 100644 index 0000000000..ac8cd6a198 --- /dev/null +++ b/tcl/target/esp_common.cfg @@ -0,0 +1,189 @@ +# 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] + +# 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" +} + +# by default current dir (when OOCD has been started) +set _SEMIHOST_BASEDIR "." +if { [info exists ESP_SEMIHOST_BASEDIR] } { + set _SEMIHOST_BASEDIR $ESP_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 + + if { $ARCH == "xtensa"} { + configure_esp_xtensa_default_settings + } else { + # riscv targets are not upstreamed yet. + # they can be found at the official Espressif fork. + } +} + +#################### 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 + esp halted_event_handler + } +} + +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 { } { + configure_event_examine_end + configure_event_reset_assert_post + configure_event_gdb_attach +} + +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 e53fdc8787..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) # @@ -11,7 +13,7 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x8000 } -$_TARGETNAME configure -work-area-phys [expr 0x20000000 - $_WORKAREASIZE] \ +$_TARGETNAME configure -work-area-phys [expr {0x20000000 - $_WORKAREASIZE}] \ -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash diff --git a/tcl/target/fm4_s6e2cc.cfg b/tcl/target/fm4_s6e2cc.cfg index 60b73b9747..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) # @@ -11,7 +13,7 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x18000 } -$_TARGETNAME configure -work-area-phys [expr 0x20000000 - $_WORKAREASIZE] \ +$_TARGETNAME configure -work-area-phys [expr {0x20000000 - $_WORKAREASIZE}] \ -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash diff --git a/tcl/target/gd32e23x.cfg b/tcl/target/gd32e23x.cfg new file mode 100644 index 0000000000..2504274135 --- /dev/null +++ b/tcl/target/gd32e23x.cfg @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for GigaDevice gd32e23x Cortex-M23 Series + +# https://www.gigadevice.com/microcontroller/gd32e230c8t6/ + +# +# gd32e23x 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 gd32e23x +} + +# Work-area is a space in RAM used for flash programming +# By default use 4kB (as found on some GD32E230s) +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1000 +} + +# Allow overriding the Flash bank size +if { [info exists FLASH_SIZE] } { + set _FLASH_SIZE $FLASH_SIZE +} else { + # autodetect size + set _FLASH_SIZE 0 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + # this is the SW-DP tap id not the jtag tap id + set _CPUTAPID 0x0bf11477 +} + +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 + +# flash size will be probed +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME + +# SWD speed (may be updated to higher value in board config file) +adapter speed 1000 + +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 { + # Debug clock enable + # RCU_APB2EN |= DBGMCUEN + mmw 0x40021018 0x00400000 0 + + # Stop watchdog counters during halt + # DBG_CTL0 |= WWDGT_HOLD | FWDGT_HOLD | STB_HOLD | DSLP_HOLD | SLP_HOLD + mmw 0x40015804 0x00000307 0 +} diff --git a/tcl/target/gd32vf103.cfg b/tcl/target/gd32vf103.cfg index 0f4dcf375e..54a74e8cc5 100644 --- a/tcl/target/gd32vf103.cfg +++ b/tcl/target/gd32vf103.cfg @@ -1,9 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # GigaDevice GD32VF103 target # # https://www.gigadevice.com/products/microcontrollers/gd32/risc-v/ # +source [find mem_helper.tcl] + transport select jtag if { [info exists CHIPNAME] } { @@ -12,10 +16,11 @@ if { [info exists CHIPNAME] } { set _CHIPNAME gd32vf103 } +# The smallest RAM size 6kB (GD32VF103C4/T4/R4) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x800 + set _WORKAREASIZE 0x1800 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d @@ -23,4 +28,92 @@ jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME +proc default_mem_access {} { + riscv set_mem_access progbuf +} + +default_mem_access + $_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 + +# DBGMCU_CR register cannot be set in examine-end event as the running RISC-V CPU +# does not allow the debugger to access memory. +# Stop watchdogs at least before flash programming. +$_TARGETNAME configure -event reset-init { + # DBGMCU_CR |= DBG_WWDG_STOP | DBG_IWDG_STOP + mmw 0xE0042004 0x00000300 0 +} + +# 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 aa811d44de..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] } { @@ -30,7 +32,7 @@ set $_TARGETNAME.cti(3) 0x80320000 set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { - cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" @@ -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 c2feb0b36b..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] } { @@ -37,7 +39,7 @@ set $_TARGETNAME.cti(7) 0x801DB000 set _cores 8 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { - cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" @@ -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" } @@ -57,7 +58,7 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { eval $_smp_command -cti create cti.sys -dap $_CHIPNAME.dap -ap-num 0 -ctibase 0x80003000 +cti create cti.sys -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80003000 # declare the auxiliary Cortex-M3 core on AP #2 (runs mcuimage.bin) target create ${_TARGETNAME}.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine 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 93375fd819..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] } { @@ -26,9 +28,7 @@ set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME proc mread32 {addr} { - set value(0) 0 - mem2array value 32 $addr 1 - return $value(0) + return [read_memory $addr 32 1] } # This function must be called on netX100/500 right after halt @@ -36,10 +36,10 @@ proc mread32 {addr} { proc sdram_fix { } { set accesskey [mread32 0x00100070] - mww 0x00100070 [expr $accesskey] + mww 0x00100070 $accesskey mww 0x0010002c 0x00000001 - if {[expr [mread32 0x0010002c] & 0x07] == 0x07} { + if {[expr {[mread32 0x0010002c] & 0x07}] == 0x07} { puts "SDRAM Fix was not executed. Probably your CPU halted too late and the register is already locked!" } else { puts "SDRAM Fix succeeded!" diff --git a/tcl/target/icepick.cfg b/tcl/target/icepick.cfg index d1250711bf..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 @@ -54,8 +56,8 @@ proc icepick_c_disconnect {jrc} { proc icepick_c_router {jrc rw block register payload} { set new_dr_value \ - [expr ( ($rw & 0x1) << 31) | ( ($block & 0x7) << 28) | \ - ( ($register & 0xF) << 24) | ( $payload & 0xFFFFFF ) ] + [expr { ( ($rw & 0x1) << 31) | ( ($block & 0x7) << 28) | \ + ( ($register & 0xF) << 24) | ( $payload & 0xFFFFFF ) } ] # echo "\tNew router value:\t0x[format %x $new_dr_value]" @@ -84,7 +86,7 @@ proc icepick_c_tapenable {jrc port} { set block 0x2 } elseif { $port < 32 } { # Test tap - set tap [expr ($port - 16)] + set tap [expr {$port - 16}] set block 0x1 } else { echo "ERROR: Invalid ICEPick C port number: $port" diff --git a/tcl/target/imx.cfg b/tcl/target/imx.cfg index ccfddb6f7c..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 @@ -10,7 +12,7 @@ proc setc15 {regs value} { echo [format "set p15 0x%04x, 0x%08x" $regs $value] - arm mcr 15 [expr ($regs>>12)&0x7] [expr ($regs>>0)&0xf] [expr ($regs>>4)&0xf] [expr ($regs>>8)&0x7] $value + arm mcr 15 [expr {($regs>>12)&0x7}] [expr {($regs>>0)&0xf}] [expr {($regs>>4)&0xf}] [expr {($regs>>8)&0x7}] $value } 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 e3b7d24e1e..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 # @@ -35,16 +37,17 @@ set CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} for { set _core 0 } { $_core < $_cores } { incr _core } { cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ - -ctibase [lindex $CTIBASE $_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 new file mode 100644 index 0000000000..33f9ca16d8 --- /dev/null +++ b/tcl/target/imx8qm.cfg @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# NXP i.MX8QuadMax +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME imx8qm +} + +# CoreSight Debug Access Port (DAP) +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + # TAPID is from FreeScale! + set _DAP_TAPID 0x1890101d +} + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ + -expected-id $_DAP_TAPID + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# AXI: Main SOC bus on AP #0 +target create ${_CHIPNAME}.axi mem_ap -dap ${_CHIPNAME}.dap -ap-num 0 + +# 4x Cortex-A53 on AP #6 +set _A53_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} +set _A53_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} + +cti create $_CHIPNAME.a53_cti.0 -dap $_CHIPNAME.dap \ + -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 0] +cti create $_CHIPNAME.a53_cti.1 -dap $_CHIPNAME.dap \ + -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 1] +cti create $_CHIPNAME.a53_cti.2 -dap $_CHIPNAME.dap \ + -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 2] +cti create $_CHIPNAME.a53_cti.3 -dap $_CHIPNAME.dap \ + -ap-num 6 -baseaddr [lindex $_A53_CTIBASE 3] +target create $_CHIPNAME.a53.0 aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.a53_cti.0 -dbgbase [lindex $_A53_DBGBASE 0] +target create $_CHIPNAME.a53.1 aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.a53_cti.1 -dbgbase [lindex $_A53_DBGBASE 1] -defer-examine +target create $_CHIPNAME.a53.2 aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.a53_cti.2 -dbgbase [lindex $_A53_DBGBASE 2] -defer-examine +target create $_CHIPNAME.a53.3 aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.a53_cti.3 -dbgbase [lindex $_A53_DBGBASE 3] -defer-examine + +# 2x Cortex-A72 on AP #6 +set _A72_DBGBASE {0x80210000 0x80310000} +set _A72_CTIBASE {0x80220000 0x80220000} + +cti create $_CHIPNAME.a72_cti.0 -dap $_CHIPNAME.dap \ + -ap-num 6 -baseaddr [lindex $_A72_CTIBASE 0] +cti create $_CHIPNAME.a72_cti.1 -dap $_CHIPNAME.dap \ + -ap-num 6 -baseaddr [lindex $_A72_CTIBASE 1] +target create $_CHIPNAME.a72.0 aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.a72_cti.0 -dbgbase [lindex $_A72_DBGBASE 0] -defer-examine +target create $_CHIPNAME.a72.1 aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.a72_cti.1 -dbgbase [lindex $_A72_DBGBASE 1] -defer-examine + +# All Cortex-A in SMP +target smp \ + $_CHIPNAME.a53.0 \ + $_CHIPNAME.a53.1 \ + $_CHIPNAME.a53.2 \ + $_CHIPNAME.a53.3 \ + $_CHIPNAME.a72.0 \ + $_CHIPNAME.a72.1 + +# SCU: Cortex-M4 core +# always running imx SC firmware +target create ${_CHIPNAME}.scu cortex_m -dap ${_CHIPNAME}.dap -ap-num 1 + +# AHB from SCU perspective +target create ${_CHIPNAME}.scu_ahb mem_ap -dap ${_CHIPNAME}.dap -ap-num 4 + +# Cortex-M4 M4_0 core on AP #2 (default off) +target create ${_CHIPNAME}.m4_0 cortex_m -dap ${_CHIPNAME}.dap -ap-num 2 \ + -defer-examine + +# Cortex-M4 M4_1 core on AP #3 (default off) +target create ${_CHIPNAME}.m4_1 cortex_m -dap ${_CHIPNAME}.dap -ap-num 3 \ + -defer-examine + +# Debug APB bus +target create ${_CHIPNAME}.apb mem_ap -dap ${_CHIPNAME}.dap -ap-num 6 + +# Default target is boot core a53.0 +targets $_CHIPNAME.a53.0 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 624fe29da8..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] } { @@ -72,11 +74,11 @@ proc ixp42x_init_sdram { SDRAM_CFG REFRESH CASLAT } { switch $CASLAT { 2 { - set SDRAM_CFG [expr $SDRAM_CFG | $::IXP42x_SDRAM_CL2 ] + set SDRAM_CFG [expr {$SDRAM_CFG | $::IXP42x_SDRAM_CL2} ] set CASCMD $::IXP425_SDRAM_IR_MODE_SET_CAS2_CMD } 3 { - set SDRAM_CFG [expr $SDRAM_CFG | $::IXP42x_SDRAM_CL3 ] + set SDRAM_CFG [expr {$SDRAM_CFG | $::IXP42x_SDRAM_CL3} ] set CASCMD $::IXP425_SDRAM_IR_MODE_SET_CAS3_CMD } default { error [format "unsupported cas latency \"%s\" " $CASLAT] } 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/kl25z_hla.cfg b/tcl/target/kl25z_hla.cfg deleted file mode 100644 index e4deac6157..0000000000 --- a/tcl/target/kl25z_hla.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/kl25z_hla.cfg is deprecated, please switch to target/kl25.cfg" -source [find target/kl25.cfg] 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 1bc77b20d1..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 @@ -56,7 +58,7 @@ proc set_sysclk_500khz {} { echo "Notice: sysclock set to 500kHz." } -# Do not remap the ARM interrupt vectors to anything but the beginning ot the flash. +# Do not remap the ARM interrupt vectors to anything but the beginning of the flash. # Table System memory remap register (SYSMEMREMAP, address 0x4004 8000) bit description # Bit Symbol Value Description # 0 map - interrupt vector remap. 0 after boot. 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 19d3e58389..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 # @@ -25,7 +27,7 @@ jtag newtap $_CHIPNAME sap -irlen 8 -expected-id $_SAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap -cti create $_CHIPNAME.cti -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0x80420000 +cti create $_CHIPNAME.cti -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80420000 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -dbgbase 0x80410000 -cti $_CHIPNAME.cti 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/ls1046a.cfg b/tcl/target/ls1046a.cfg new file mode 100644 index 0000000000..3d96a994ed --- /dev/null +++ b/tcl/target/ls1046a.cfg @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1046A + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME ls1046a +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +if { [info exists SAP_TAPID] } { + set _SAP_TAPID $SAP_TAPID +} else { + set _SAP_TAPID 0x06b3001d +} + +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 0 + +set _CPU_BASE 0x80400000 +set _CPU_STRIDE 0x100000 +set _CPU_DBGOFF 0x10000 +set _CPU_CTIOFF 0x20000 + +set _TARGETS {} +for {set i 0} {$i < 4} {incr i} { + set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] + cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 1 \ + -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] + target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ + -coreid $i {*}[expr {$i ? {-defer-examine} : {-rtos hwthread} }] + lappend _TARGETS $_CHIPNAME.cpu$i +} + +target smp {*}$_TARGETS + +jtag newtap $_CHIPNAME sap -irlen 8 -expected-id $_SAP_TAPID +target create $_CHIPNAME.sap ls1_sap -chain-position $_CHIPNAME.sap -endian big + +proc core_up { args } { + foreach core $args { + $::_CHIPNAME.cpu$core arp_examine + } +} + +targets $_CHIPNAME.cpu0 + +adapter speed 10000 diff --git a/tcl/target/ls1088a.cfg b/tcl/target/ls1088a.cfg new file mode 100644 index 0000000000..193d6ddc77 --- /dev/null +++ b/tcl/target/ls1088a.cfg @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1088A + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME ls1088a +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +set _CPUS 8 + +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 5e75135885..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 # # !!!!!! @@ -44,7 +46,7 @@ set _smp_command "" for { set _core 0 } { $_core < $_cores } { incr _core 1 } { - cti create cti$_core -dap $_CHIPNAME.dap -ctibase [lindex $_ctis $_core] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [lindex $_ctis $_core] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core \ @@ -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 new file mode 100644 index 0000000000..84bb0b7a53 --- /dev/null +++ b/tcl/target/npcx.cfg @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for Nuvoton NPCX Cortex-M4 Series + +# Adapt based on what transport is active. +source [find target/swj-dp.tcl] + +# Set Chipname +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME npcx +} + +# SWD DAP ID of Nuvoton NPCX Cortex-M4. +if { [info exists CPUDAPID ] } { + set _CPUDAPID $CPUDAPID +} else { + set _CPUDAPID 0x4BA00477 +} + +# Work-area is a space in RAM used for flash programming +# By default use 32kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + 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 +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x200c0000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# Initial JTAG/SWD speed +# For safety purposes, set for the lowest cpu clock configuration +# 4MHz / 6 = 666KHz, so use 600KHz for it +adapter speed 600 + +# For safety purposes, set for the lowest cpu clock configuration +$_TARGETNAME configure -event reset-start {adapter speed 600} + +# use sysresetreq to perform a system reset +cortex_m reset_config sysresetreq + +# flash configuration +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME $_FIUNAME diff --git a/tcl/target/nrf51.cfg b/tcl/target/nrf51.cfg index d51a50e231..3781eccb50 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 # @@ -43,13 +45,11 @@ if {![using_hla]} { cortex_m reset_config sysresetreq } -flash bank $_CHIPNAME.flash nrf51 0x00000000 0 1 1 $_TARGETNAME -flash bank $_CHIPNAME.uicr nrf51 0x10001000 0 1 1 $_TARGETNAME +flash bank $_CHIPNAME.flash nrf5 0x00000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.uicr nrf5 0x10001000 0 0 0 $_TARGETNAME -# # The chip should start up from internal 16Mhz RC, so setting adapter # clock to 1Mhz should be OK -# adapter speed 1000 proc enable_all_ram {} { @@ -58,4 +58,4 @@ proc enable_all_ram {} { # resetting we enable all banks via the RAMON register mww 0x40000524 0xF } -$_TARGETNAME configure -event reset-end { enable_all_ram } +$_TARGETNAME configure -event reset-init { enable_all_ram } diff --git a/tcl/target/nrf51_stlink.tcl b/tcl/target/nrf51_stlink.tcl deleted file mode 100644 index 7e23c5a744..0000000000 --- a/tcl/target/nrf51_stlink.tcl +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/nrf51_stlink.cfg is deprecated, please switch to target/nrf51.cfg" -source [find target/nrf51.cfg] diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg index 88f2c6912a..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 @@ -53,7 +56,7 @@ flash bank $_CHIPNAME.uicr nrf5 0x10001000 0 1 1 $_TARGETNAME # Test if MEM-AP is locked by UICR APPROTECT proc nrf52_check_ap_lock {} { set dap [[target current] cget -dap] - set err [catch {set APPROTECTSTATUS [ocd_$dap apreg 1 0xc]}] + set err [catch {set APPROTECTSTATUS [$dap apreg 1 0xc]}] if {$err == 0 && $APPROTECTSTATUS != 1} { echo "****** WARNING ******" echo "nRF52 device has AP lock engaged (see UICR APPROTECT register)." @@ -71,7 +74,7 @@ proc nrf52_recover {} { set target [target current] set dap [$target cget -dap] - set IDR [ocd_$dap apreg 1 0xfc] + set IDR [$dap apreg 1 0xfc] if {$IDR != 0x02880000} { echo "Error: Cannot access nRF52 CTRL-AP!" return @@ -79,37 +82,86 @@ proc nrf52_recover {} { poll off - # Assert reset - $dap apreg 1 0 1 - - # Reset ERASEALLSTATUS event - $dap apreg 1 8 0 - - # Trigger ERASEALL task + # Reset and trigger ERASEALL task $dap apreg 1 4 0 $dap apreg 1 4 1 for {set i 0} {1} {incr i} { - set ERASEALLSTATUS [ocd_$dap apreg 1 8] - if {$ERASEALLSTATUS == 1} { + set ERASEALLSTATUS [$dap apreg 1 8] + if {$ERASEALLSTATUS == 0} { echo "$target device has been successfully erased and unlocked." break } - if {$i >= 5} { + if {$i == 0} { + echo "Waiting for chip erase..." + } + if {$i >= 150} { echo "Error: $target recovery failed." break } sleep 100 } + # Assert reset + $dap apreg 1 0 1 + # Deassert reset $dap apreg 1 0 0 - if {$ERASEALLSTATUS == 1} { - sleep 100 - $target arp_examine - poll on - } + # Reset ERASEALL task + $dap apreg 1 4 0 + + sleep 100 + $target arp_examine + poll on } 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 6e3e78d37f..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] } { @@ -91,7 +93,7 @@ set _TARGETNAME $_CHIPNAME.cpu # 0x80000000 | (coreid << CORTEX_A8_PADDRDBG_CPU_SHIFT) set _coreid 0 -set _dbgbase [expr 0x80000000 | ($_coreid << 13)] +set _dbgbase [expr {0x80000000 | ($_coreid << 13)}] echo "Using dbgbase = [format 0x%x $_dbgbase]" dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu diff --git a/tcl/target/omap4460.cfg b/tcl/target/omap4460.cfg index 218eb64e92..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] } { @@ -91,7 +93,7 @@ set _TARGETNAME $_CHIPNAME.cpu # 0x80000000 | (coreid << CORTEX_A8_PADDRDBG_CPU_SHIFT) set _coreid 0 -set _dbgbase [expr 0x80000000 | ($_coreid << 13)] +set _dbgbase [expr {0x80000000 | ($_coreid << 13)}] echo "Using dbgbase = [format 0x%x $_dbgbase]" dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu 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 360a0ddf3d..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] } { @@ -69,4 +71,4 @@ set ENABLE_JSP_MULTI 4 # on burst reads and writes to improve download speeds. # This option must match the RTL configured option. -du_select adv [expr $ADBG_USE_HISPEED | $ENABLE_JSP_SERVER | $ENABLE_JSP_MULTI] +du_select adv [expr {$ADBG_USE_HISPEED | $ENABLE_JSP_SERVER | $ENABLE_JSP_MULTI}] diff --git a/tcl/target/pic32mx.cfg b/tcl/target/pic32mx.cfg index 51a6bbddb2..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 { @@ -42,7 +44,7 @@ target create $_TARGETNAME mips_m4k -endian $_ENDIAN -chain-position $_TARGETNAM global _PIC32MX_DATASIZE global _WORKAREASIZE set _PIC32MX_DATASIZE 0x800 -set _PIC32MX_PROGSIZE [expr ($_WORKAREASIZE - $_PIC32MX_DATASIZE)] +set _PIC32MX_PROGSIZE [expr {$_WORKAREASIZE - $_PIC32MX_DATASIZE}] $_TARGETNAME configure -work-area-phys 0xa0000800 -work-area-size $_PIC32MX_PROGSIZE -work-area-backup 0 $_TARGETNAME configure -event reset-init { diff --git a/tcl/target/psoc4.cfg b/tcl/target/psoc4.cfg index b568282079..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 # @@ -60,7 +62,7 @@ adapter speed 1500 # # Newer families like PSoC 4000, 4100M, 4200M, 4100L, 4200L and PSoC 4 BLE # clear TEST_MODE flag during device reset so workaround is not possible. -# Use a KitProg adapter for theese devices or "reset halt" will not stop +# Use a KitProg adapter for these devices or "reset halt" will not stop # before executing user code. # # 3) SWD cannot be connected during system initialization after reset. @@ -74,22 +76,22 @@ if {![using_hla]} { } proc psoc4_get_family_id {} { - set err [catch "mem2array romtable_pid 32 0xF0000FE0 3"] + set err [catch {set romtable_pid [read_memory 0xF0000FE0 32 3]}] if { $err } { return 0 } - if { [expr $romtable_pid(0) & 0xffffff00 ] - || [expr $romtable_pid(1) & 0xffffff00 ] - || [expr $romtable_pid(2) & 0xffffff00 ] } { + if { [expr {[lindex $romtable_pid 0] & 0xffffff00 }] + || [expr {[lindex $romtable_pid 1] & 0xffffff00 }] + || [expr {[lindex $romtable_pid 2] & 0xffffff00 }] } { echo "Unexpected data in ROMTABLE" return 0 } - set designer_id [expr (( $romtable_pid(1) & 0xf0 ) >> 4) | (( $romtable_pid(2) & 0xf ) << 4 ) ] + set designer_id [expr {(( [lindex $romtable_pid 1] & 0xf0 ) >> 4) | (( [lindex $romtable_pid 2] & 0xf ) << 4 ) }] if { $designer_id != 0xb4 } { echo [format "ROMTABLE Designer ID 0x%02x is not Cypress" $designer_id] return 0 } - set family_id [expr ( $romtable_pid(0) & 0xff ) | (( $romtable_pid(1) & 0xf ) << 8 ) ] + set family_id [expr {( [lindex $romtable_pid 0] & 0xff ) | (( [lindex $romtable_pid 1] & 0xf ) << 8 ) }] return $family_id } @@ -193,9 +195,9 @@ proc ocd_process_reset_inner { MODE } { } # Set registers to reset vector values - mem2array value 32 0 2 - reg pc [expr $value(1) & 0xfffffffe ] - reg msp $value(0) + set value [read_memory 0x0 32 2] + reg pc [expr {[lindex $value 1] & 0xfffffffe}] + reg msp [lindex $value 0] if { $PSOC4_TEST_MODE_WORKAROUND } { catch { mww $TEST_MODE 0 } diff --git a/tcl/target/psoc5lp.cfg b/tcl/target/psoc5lp.cfg index b4e8d05fa6..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 # @@ -34,7 +36,7 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x2000 } -$_TARGETNAME configure -work-area-phys [expr 0x20000000 - $_WORKAREASIZE / 2] \ +$_TARGETNAME configure -work-area-phys [expr {0x20000000 - $_WORKAREASIZE / 2}] \ -work-area-size $_WORKAREASIZE -work-area-backup 0 source [find mem_helper.tcl] @@ -43,15 +45,15 @@ $_TARGETNAME configure -event reset-init { # Configure Target Device (PSoC 5LP Device Programming Specification 5.2) set PANTHER_DBG_CFG 0x4008000C - set PANTHER_DBG_CFG_BYPASS [expr 1 << 1] + set PANTHER_DBG_CFG_BYPASS [expr {1 << 1}] mmw $PANTHER_DBG_CFG $PANTHER_DBG_CFG_BYPASS 0 set PM_ACT_CFG0 0x400043A0 mww $PM_ACT_CFG0 0xBF set FASTCLK_IMO_CR 0x40004200 - set FASTCLK_IMO_CR_F_RANGE_2 [expr 2 << 0] - set FASTCLK_IMO_CR_F_RANGE_MASK [expr 7 << 0] + set FASTCLK_IMO_CR_F_RANGE_2 [expr {2 << 0}] + set FASTCLK_IMO_CR_F_RANGE_MASK [expr {7 << 0}] mmw $FASTCLK_IMO_CR $FASTCLK_IMO_CR_F_RANGE_2 $FASTCLK_IMO_CR_F_RANGE_MASK } 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 91baa6c908..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 @@ -87,12 +89,14 @@ dap create $_DAPNAME -chain-position $_CHIPNAME.cpu set CA15_DBGBASE {0x800B0000 0x800B2000 0x800B4000 0x800B6000} set CA7_DBGBASE {0x800F0000 0x800F2000 0x800F4000 0x800F6000} +set _targets "" set smp_targets "" proc setup_ca {core_name dbgbase num boot} { global _CHIPNAME global _DAPNAME global smp_targets + global _targets for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $_CHIPNAME.$core_name.$_core set _CTINAME $_TARGETNAME.cti @@ -123,3 +127,4 @@ if { [string equal $_boot_core CA15] } { source [find target/renesas_rcar_reset_common.cfg] eval "target smp $smp_targets" +targets $_targets diff --git a/tcl/target/renesas_rcar_gen3.cfg b/tcl/target/renesas_rcar_gen3.cfg index 72f185d61b..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 @@ -7,6 +9,7 @@ # H3: Cortex-A57 x 4, Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) # M3W: Cortex-A57 x 2, Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) # M3N: Cortex-A57 x 2, Cortex-R7 x 2 (Lock-Step) +# V3U: Cortex-A76 x 8, Cortex-R52 x2 (Lock-Step) # V3H: Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step) # V3M: Cortex-A53 x 2, Cortex-R7 x 2 (Lock-Step) # E3: Cortex-A53 x 1, Cortex-R7 x 2 (Lock-Step) @@ -24,6 +27,12 @@ if { [info exists SOC] } { set _soc H3 } +set _num_ca53 0 +set _num_ca57 0 +set _num_ca76 0 +set _num_cr52 0 +set _num_cr7 0 + # Set configuration for each SOC and the default 'BOOT_CORE' switch $_soc { H3 { @@ -75,6 +84,12 @@ switch $_soc { set _num_cr7 0 set _boot_core CA53 } + V3U { + set _CHIPNAME r8a779a0 + set _num_ca76 8 + set _num_cr52 1 + set _boot_core CA76 + } default { error "'$_soc' is invalid!" } @@ -96,7 +111,7 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x5ba00477 } -echo "\t$_soc - $_num_ca57 CA57(s), $_num_ca53 CA53(s), $_num_cr7 CR7(s)" +echo "\t$_soc - $_num_ca76 CA76(s), $_num_ca57 CA57(s), $_num_ca53 CA53(s), $_num_cr52 CR52(s), $_num_cr7 CR7(s)" echo "\tBoot Core - $_boot_core\n" set _DAPNAME $_CHIPNAME.dap @@ -105,24 +120,30 @@ set _DAPNAME $_CHIPNAME.dap jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID dap create $_DAPNAME -chain-position $_CHIPNAME.cpu +set CA76_DBGBASE {0x81410000 0x81510000 0x81610000 0x81710000 0x81c10000 0x81d10000 0x81e10000 0x81f10000} +set CA76_CTIBASE {0x81420000 0x81520000 0x81620000 0x81720000 0x81c20000 0x81d20000 0x81e20000 0x81f20000} set CA57_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set CA57_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} set CA53_DBGBASE {0x80C10000 0x80D10000 0x80E10000 0x80F10000} set CA53_CTIBASE {0x80C20000 0x80D20000 0x80E20000 0x80F20000} +set CR52_DBGBASE 0x80c10000 +set CR52_CTIBASE 0x80c20000 set CR7_DBGBASE 0x80910000 set CR7_CTIBASE 0x80918000 +set _targets "" set smp_targets "" proc setup_a5x {core_name dbgbase ctibase num boot} { global _CHIPNAME global _DAPNAME global smp_targets + global _targets for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $_CHIPNAME.$core_name.$_core set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $_DAPNAME -ap-num 1 \ - -ctibase [lindex $ctibase $_core] + -baseaddr [lindex $ctibase $_core] set _command "target create $_TARGETNAME aarch64 -dap $_DAPNAME \ -ap-num 1 -dbgbase [lindex $dbgbase $_core] -cti $_CTINAME" if { $_core == 0 && $boot == 1 } { @@ -135,33 +156,46 @@ proc setup_a5x {core_name dbgbase ctibase num boot} { } } -proc setup_cr7 {dbgbase ctibase boot} { +proc setup_crx {core_name dbgbase ctibase num boot} { global _CHIPNAME global _DAPNAME - set _TARGETNAME $_CHIPNAME.r7 - set _CTINAME $_TARGETNAME.cti - cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -ctibase $ctibase - set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \ - -ap-num 1 -dbgbase $dbgbase" - if { $boot == 1 } { - set _targets "$_TARGETNAME" - } else { - set _command "$_command -defer-examine" + 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 + 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 { + set _command "$_command -defer-examine" + } + eval $_command } - eval $_command } # Organize target list based on the boot core -if { [string equal $_boot_core CA57] } { +if { [string equal $_boot_core CA76] } { + setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 1 + 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 $CR7_DBGBASE $CR7_CTIBASE 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 $CR7_DBGBASE $CR7_CTIBASE 0 + setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 +} elseif { [string equal $_boot_core CR52] } { + setup_crx r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 1 + setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 0 } else { - setup_cr7 $CR7_DBGBASE $CR7_CTIBASE 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 } @@ -169,3 +203,4 @@ if { [string equal $_boot_core CA57] } { source [find target/renesas_rcar_reset_common.cfg] eval "target smp $smp_targets" +targets $_targets 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 new file mode 100644 index 0000000000..a3d5f48fbc --- /dev/null +++ b/tcl/target/renesas_rz_g2.cfg @@ -0,0 +1,201 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Renesas RZ/G2 SOCs +# - There are a combination of Cortex-A57s, Cortex-A53s, Cortex-A55, Cortex-R7 +# and Cortex-M33 for each SOC +# - 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/G2LC: Cortex-A55 x2, Cortex-M33 +# RZ/G2UL: Cortex-A55 x1, Cortex-M33 + +# Usage: +# There are 2 configuration options: +# SOC: Selects the supported SOC. (Default 'G2L') +# BOOT_CORE: Selects the booting core. 'CA57', 'CA53' or 'CA55' + +transport select jtag +reset_config trst_and_srst srst_gates_jtag +adapter speed 4000 +adapter srst delay 500 + +if { [info exists SOC] } { + set _soc $SOC +} else { + set _soc G2L +} + +set _num_ca57 0 +set _num_ca55 0 +set _num_ca53 0 +set _num_cr7 0 +set _num_cm33 0 + +# Set configuration for each SOC and the default 'BOOT_CORE' +switch $_soc { + G2H { + set _CHIPNAME r8a774ex + set _num_ca57 4 + set _num_ca53 4 + set _num_cr7 1 + set _boot_core CA57 + set _ap_num 1 + } + G2M { + set _CHIPNAME r8a774ax + set _num_ca57 2 + set _num_ca53 4 + set _num_cr7 1 + set _boot_core CA57 + set _ap_num 1 + } + G2N { + set _CHIPNAME r8a774bx + set _num_ca57 2 + set _num_ca53 0 + set _num_cr7 1 + set _boot_core CA57 + set _ap_num 1 + } + G2E { + set _CHIPNAME r8a774c0 + set _num_ca57 0 + set _num_ca53 2 + set _num_cr7 1 + set _boot_core CA53 + set _ap_num 1 + } + G2L { + set _CHIPNAME r9a07g044l + set _num_ca55 2 + set _num_cm33 1 + 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!" + } +} + +# If configured, override the default 'CHIPNAME' +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} + +# If configured, override the default 'BOOT_CORE' +if { [info exists BOOT_CORE] } { + set _boot_core $BOOT_CORE +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x6ba00477 +} + +echo "\t$_soc - $_num_ca57 CA57(s), $_num_ca55 CA55(s), $_num_ca53 CA53(s), $_num_cr7 CR7(s), \ + $_num_cm33 CM33(s)" +echo "\tBoot Core - $_boot_core\n" + +set _DAPNAME $_CHIPNAME.dap + + +# TAP and DAP +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID \ + -ignore-version +dap create $_DAPNAME -chain-position $_CHIPNAME.cpu +echo "$_CHIPNAME.cpu" + +set CA57_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} +set CA57_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} +set CA55_DBGBASE {0x10E10000 0x10F10000} +set CA55_CTIBASE {0x10E20000 0x10F20000} +set CA53_DBGBASE {0x80C10000 0x80D10000 0x80E10000 0x80F10000} +set CA53_CTIBASE {0x80C20000 0x80D20000 0x80E20000 0x80F20000} +set CR7_DBGBASE 0x80910000 +set CR7_CTIBASE 0x80918000 +set CM33_DBGBASE 0xE000E000 +set CM33_CTIBASE 0xE0042000 + +set smp_targets "" + +proc setup_a5x {core_name dbgbase ctibase num boot} { + for { set _core 0 } { $_core < $num } { incr _core } { + set _TARGETNAME $::_CHIPNAME.$core_name.$_core + set _CTINAME $_TARGETNAME.cti + cti create $_CTINAME -dap $::_DAPNAME -ap-num $::_ap_num \ + -baseaddr [lindex $ctibase $_core] + target create $_TARGETNAME aarch64 -dap $::_DAPNAME \ + -ap-num $::_ap_num -dbgbase [lindex $dbgbase $_core] -cti $_CTINAME + if { $_core > 0 || $boot == 0 } { + $_TARGETNAME configure -defer-examine + } + set ::smp_targets "$::smp_targets $_TARGETNAME" + } +} + +proc setup_cr7 {dbgbase ctibase} { + set _TARGETNAME $::_CHIPNAME.r7 + set _CTINAME $_TARGETNAME.cti + cti create $_CTINAME -dap $::_DAPNAME -ap-num 1 -baseaddr $ctibase + target create $_TARGETNAME cortex_r4 -dap $::_DAPNAME \ + -ap-num 1 -dbgbase $dbgbase -defer-examine +} + +proc setup_cm33 {dbgbase ctibase} { + set _TARGETNAME $::_CHIPNAME.m33 + set _CTINAME $_TARGETNAME.cti + cti create $_CTINAME -dap $::_DAPNAME -ap-num 2 -baseaddr $ctibase + target create $_TARGETNAME cortex_m -dap $::_DAPNAME \ + -ap-num 2 -dbgbase $dbgbase -defer-examine +} + +# Organize target list based on the boot core +if { $_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 $CR7_DBGBASE $CR7_CTIBASE +} elseif { $_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 $CR7_DBGBASE $CR7_CTIBASE +} elseif { $_boot_core == "CA55" } { + setup_a5x a55 $CA55_DBGBASE $CA55_CTIBASE $_num_ca55 1 + setup_cm33 $CM33_DBGBASE $CM33_CTIBASE +} +echo "SMP targets:$smp_targets" +eval "target smp $smp_targets" + +if { $_soc == "G2L" || $_soc == "G2LC" || $_soc == "G2UL" } { + target create $_CHIPNAME.axi_ap mem_ap -dap $_DAPNAME -ap-num 1 +} + +proc init_reset {mode} { + # Assert both resets: equivalent to a power-on reset + adapter assert trst assert srst + + # Deassert TRST to begin TAP communication + adapter deassert trst assert srst + + # TAP should now be responsive, validate the scan-chain + jtag arp_init +} 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 d3d409eaf1..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 @@ -28,7 +30,7 @@ swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID -ignore-version dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 -# declare the 8 main application cores +# declare the 4 main application cores set _TARGETNAME $_CHIPNAME.core set _smp_command "" @@ -45,7 +47,7 @@ set $_TARGETNAME.cti(3) 0x8101b000 set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { - cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core \ @@ -53,6 +55,7 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { if { $_core != 0 } { set _smp_command "$_smp_command ${_TARGETNAME}$_core" + set _command "$_command -defer-examine" } else { # uncomment to use hardware threads pseudo rtos # set _command "$_command -rtos hwthread" diff --git a/tcl/target/rk3399.cfg b/tcl/target/rk3399.cfg new file mode 100644 index 0000000000..1e90414fdb --- /dev/null +++ b/tcl/target/rk3399.cfg @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Rockchip RK3399 Target +# https://rockchip.fr/RK3399%20datasheet%20V1.8.pdf +# https://rockchip.fr/Rockchip%20RK3399%20TRM%20V1.4%20Part1.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME rk3399 +} + +# +# Main DAP +# +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba02477 +} + +adapter speed 12000 + +transport select swd + +# declare the one SWD tap to access the DAP +swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID -ignore-version + +# create the DAP +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 +set _TARGETNAME $_CHIPNAME.lcore +# declare the 6 main application cores +set _smp_command "" + +set $_TARGETNAME.base(0) 0x80030000 +set $_TARGETNAME.base(1) 0x80032000 +set $_TARGETNAME.base(2) 0x80034000 +set $_TARGETNAME.base(3) 0x80036000 +set $_TARGETNAME.cti(0) 0x80038000 +set $_TARGETNAME.cti(1) 0x80039000 +set $_TARGETNAME.cti(2) 0x8003a000 +set $_TARGETNAME.cti(3) 0x8003b000 + + +set _TARGETNAME $_CHIPNAME.bcore +set $_TARGETNAME.base(4) 0x80210000 +set $_TARGETNAME.base(5) 0x80310000 +set $_TARGETNAME.cti(4) 0x80220000 +set $_TARGETNAME.cti(5) 0x80320000 + +set _cores 6 +for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + if {$_core < 4} { + set _TARGETNAME $_CHIPNAME.lcore + } else { + set _TARGETNAME $_CHIPNAME.bcore + } + + + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 1 + + target create ${_TARGETNAME}$_core aarch64 \ + -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core \ + -dbgbase [set $_TARGETNAME.base($_core)] + + if { $_core != 0 } { + ${_TARGETNAME}$_core configure -defer-examine + } else { + # uncomment to use hardware threads pseudo rtos + # ${_TARGETNAME}$_core configure -rtos hwthread" + ${_TARGETNAME}$_core configure -work-area-size 0x30000 -work-area-phys 0xff8c0000 \ + -work-area-backup 0 + } + set _smp_command "$_smp_command ${_TARGETNAME}$_core" +} + +target smp $_smp_command + +targets rk3399.lcore0 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 2f7fecbe32..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. @@ -20,7 +20,7 @@ jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -expected-id 0x200444b1 \ -expected-id 0x200044b1 set _coreid 0 -set _dbgbase [expr 0x00000000 | ($_coreid << 13)] +set _dbgbase [expr {0x00000000 | ($_coreid << 13)}] target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME \ -coreid 0 -dbgbase $_dbgbase -endian little diff --git a/tcl/target/snps_hsdk.cfg b/tcl/target/snps_hsdk.cfg index 634e07adc4..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. @@ -13,7 +13,7 @@ source [find cpu/arc/hs.tcl] set _coreid 0 -set _dbgbase [expr ($_coreid << 13)] +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. @@ -30,8 +30,8 @@ $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase # Flush L2$. $_TARGETNAME configure -event reset-assert "arc_hs_reset $_TARGETNAME" -set _coreid [expr $_coreid + 1] -set _dbgbase [expr ($_coreid << 13)] +set _coreid [expr {$_coreid + 1}] +set _dbgbase [expr {$_coreid << 13}] arc_hs_init_regs @@ -46,8 +46,8 @@ target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase $_TARGETNAME configure -event reset-assert "arc_common_reset $_TARGETNAME" -set _coreid [expr $_coreid + 1] -set _dbgbase [expr ($_coreid << 13)] +set _coreid [expr {$_coreid + 1}] +set _dbgbase [expr {$_coreid << 13}] arc_hs_init_regs @@ -62,8 +62,8 @@ target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase $_TARGETNAME configure -event reset-assert "arc_common_reset $_TARGETNAME" -set _coreid [expr $_coreid + 1] -set _dbgbase [expr ($_coreid << 13)] +set _coreid [expr {$_coreid + 1}] +set _dbgbase [expr {$_coreid << 13}] arc_hs_init_regs @@ -78,8 +78,8 @@ target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME $_TARGETNAME configure -coreid $_coreid $_TARGETNAME configure -dbgbase $_dbgbase $_TARGETNAME configure -event reset-assert "arc_common_reset $_TARGETNAME" -set _coreid [expr $_coreid + 1] -set _dbgbase [expr 0x00000000 | ($_coreid << 13)] +set _coreid [expr {$_coreid + 1}] +set _dbgbase [expr {0x00000000 | ($_coreid << 13)}] arc_hs_init_regs # Enable L2 cache support for core 1. 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 3cab4d1406..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. @@ -83,7 +85,7 @@ proc reset_peripherals {family} { mmw $SYSCTL_RCC2 $SYSCTL_RCC2_BYPASS2 0 # RCC and RCC2 to their reset values - mww $SYSCTL_RCC [expr (0x078e3ad0 | ([mrw $SYSCTL_RCC] & $SYSCTL_RCC_MOSCDIS))] + mww $SYSCTL_RCC [expr {0x078e3ad0 | ([mrw $SYSCTL_RCC] & $SYSCTL_RCC_MOSCDIS)}] mww $SYSCTL_RCC2 0x07806810 mww $SYSCTL_RCC 0x078e3ad1 @@ -121,8 +123,8 @@ proc reset_peripherals {family} { mww $SYSCTL_MISC 0xffffffff # Wait for any pending flash operations to complete - while {[expr [mrw $FLASH_FMC] & 0xffff] != 0} { sleep 1 } - while {[expr [mrw $FLASH_FMC2] & 0xffff] != 0} { sleep 1 } + while {[expr {[mrw $FLASH_FMC] & 0xffff}] != 0} { sleep 1 } + while {[expr {[mrw $FLASH_FMC2] & 0xffff}] != 0} { sleep 1 } # Reset the flash controller registers mww $FLASH_FMA 0 @@ -152,7 +154,7 @@ $_TARGETNAME configure -event reset-start { if {$_DEVICECLASS != 0xff} { set device_class $_DEVICECLASS } else { - set device_class [expr (([mrw 0x400fe000] >> 16) & 0xff)] + set device_class [expr {([mrw 0x400fe000] >> 16) & 0xff}] } if {$device_class == 0 || $device_class == 1 || diff --git a/tcl/target/stellaris_icdi.cfg b/tcl/target/stellaris_icdi.cfg deleted file mode 100644 index f856a7a8d8..0000000000 --- a/tcl/target/stellaris_icdi.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stellaris_icdi.cfg is deprecated, please switch to target/stellaris.cfg" -source [find target/stellaris.cfg] diff --git a/tcl/target/stm32_stlink.cfg b/tcl/target/stm32_stlink.cfg deleted file mode 100644 index 295292e3e5..0000000000 --- a/tcl/target/stm32_stlink.cfg +++ /dev/null @@ -1 +0,0 @@ -echo "WARNING: stm32_stlink.cfg is deprecated (and does nothing, you can safely remove it.)" 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/stm32f0x_stlink.cfg b/tcl/target/stm32f0x_stlink.cfg deleted file mode 100644 index cecfb7a78c..0000000000 --- a/tcl/target/stm32f0x_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32f0x_stlink.cfg is deprecated, please switch to target/stm32f0x.cfg" -source [find target/stm32f0x.cfg] 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/stm32f1x_stlink.cfg b/tcl/target/stm32f1x_stlink.cfg deleted file mode 100644 index 0a3e6430ed..0000000000 --- a/tcl/target/stm32f1x_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32f1x_stlink.cfg is deprecated, please switch to target/stm32f1x.cfg" -source [find target/stm32f1x.cfg] 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/stm32f2x_stlink.cfg b/tcl/target/stm32f2x_stlink.cfg deleted file mode 100644 index 451b2b5e2e..0000000000 --- a/tcl/target/stm32f2x_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32f2x_stlink.cfg is deprecated, please switch to target/stm32f2x.cfg" -source [find target/stm32f2x.cfg] 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/stm32f3x_stlink.cfg b/tcl/target/stm32f3x_stlink.cfg deleted file mode 100644 index 87693586dc..0000000000 --- a/tcl/target/stm32f3x_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32f3x_stlink.cfg is deprecated, please switch to target/stm32f3x.cfg" -source [find target/stm32f3x.cfg] diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index b95e783c52..35d8275b55 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -1,7 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32f4x family # -# stm32 devices support both JTAG and SWD transports. +# stm32f4 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] @@ -52,6 +54,12 @@ flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32f2x 0x1fff7800 0 0 0 $_TARGETNAME +if { [info exists QUADSPI] && $QUADSPI } { + set a [llength [flash list]] + set _QSPINAME $_CHIPNAME.qspi + flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 +} + # JTAG speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz # # Since we may be running of an RC oscilator, we crank down the speed a @@ -83,13 +91,44 @@ $_TARGETNAME configure -event examine-end { mmw 0xE0042008 0x00001800 0 } -$_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 - # assignment - mmw 0xE0042004 0x00000020 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 {_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 + mmw 0x40021008 0x00003ff0 0x00000000 + } + } + } else { + # Set TRACE_IOEN; TRACE_MODE to async + mmw 0xE0042004 0x00000020 0x000000c0 + } } +$_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) mww 0x40023804 0x08012008 ;# RCC_PLLCFGR 16 Mhz /8 (M) * 128 (N) /4(P) diff --git a/tcl/target/stm32f4x_stlink.cfg b/tcl/target/stm32f4x_stlink.cfg deleted file mode 100644 index af3e8a098c..0000000000 --- a/tcl/target/stm32f4x_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32f4x_stlink.cfg is deprecated, please switch to target/stm32f4x.cfg" -source [find target/stm32f4x.cfg] diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg index 6ad4b65f8f..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 # @@ -12,7 +14,7 @@ if { [info exists CHIPNAME] } { set _CHIPNAME stm32f7x } - set _ENDIAN little +set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 128kB @@ -64,6 +66,12 @@ flash bank $_CHIPNAME.otp stm32f2x 0x1ff0f000 0 0 0 $_TARGETNAME # the Flash via ITCM alias as virtual flash bank $_CHIPNAME.itcm-flash.alias virtual 0x00200000 0 0 0 $_TARGETNAME $_FLASHNAME +if { [info exists QUADSPI] && $QUADSPI } { + set a [llength [flash list]] + set _QSPINAME $_CHIPNAME.qspi + flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 +} + # adapter speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz adapter speed 2000 @@ -76,7 +84,7 @@ if {[using_jtag]} { # # This target is compatible with connect_assert_srst, which may be set in a # board file. -reset_config srst_only srst_nogate +reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to @@ -101,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 50836ea826..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 # @@ -38,8 +40,8 @@ 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 stm32l4x 0 0 0 0 $_TARGETNAME +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 diff --git a/tcl/target/stm32g4x.cfg b/tcl/target/stm32g4x.cfg index 9f144a07ef..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 # @@ -47,8 +49,8 @@ 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 stm32l4x 0 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] @@ -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 43a8b024e5..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 # @@ -77,6 +79,8 @@ if {![using_hla]} { # STM32H7 provides an APB-AP at access port 2, which allows the access to # the debug and trace features on the system APB System Debug Bus (APB-D). target create $_CHIPNAME.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 + swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE00E3000 + tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE00F5000 } target create $_CHIPNAME.cpu0 cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap -ap-num 0 @@ -104,6 +108,23 @@ if {[set $_CHIPNAME.DUAL_CORE]} { # Make sure that cpu0 is selected targets $_CHIPNAME.cpu0 +if { [info exists QUADSPI] && $QUADSPI } { + set a [llength [flash list]] + set _QSPINAME $_CHIPNAME.qspi + flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_CHIPNAME.cpu0 0x52005000 +} else { + if { [info exists OCTOSPI1] && $OCTOSPI1 } { + set a [llength [flash list]] + set _OCTOSPINAME1 $_CHIPNAME.octospi1 + flash bank $_OCTOSPINAME1 stmqspi 0x90000000 0 0 0 $_CHIPNAME.cpu0 0x52005000 + } + if { [info exists OCTOSPI2] && $OCTOSPI2 } { + set b [llength [flash list]] + set _OCTOSPINAME2 $_CHIPNAME.octospi2 + flash bank $_OCTOSPINAME2 stmqspi 0x70000000 0 0 0 $_CHIPNAME.cpu0 0x5200A000 + } +} + # Clock after reset is HSI at 64 MHz, no need of PLL adapter speed 1800 @@ -123,7 +144,7 @@ if {[using_jtag]} { # usage does not work with HLA, so is not done by default. That change could be # made in a local configuration file if connect_assert_srst mode is needed for # a specific application and a non-HLA adapter is in use. -reset_config srst_only srst_nogate +reset_config srst_nogate if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to @@ -149,8 +170,10 @@ $_CHIPNAME.cpu0 configure -event examine-end { stm32h7x_dbgmcu_mmw 0x004 0x00600000 0 # Enable debug during low power modes (uses more power) - # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP in D3, D2 & D1 Domains - stm32h7x_dbgmcu_mmw 0x004 0x000001BF 0 + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP D1 Domain + stm32h7x_dbgmcu_mmw 0x004 0x00000007 0 + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP D2 Domain + stm32h7x_dbgmcu_mmw 0x004 0x00000038 0 # Stop watchdog counters during halt # DBGMCU_APB3FZ1 |= WWDG1 @@ -159,13 +182,20 @@ $_CHIPNAME.cpu0 configure -event examine-end { stm32h7x_dbgmcu_mmw 0x03C 0x00000800 0 # DBGMCU_APB4FZ1 |= WDGLSD1 | WDGLSD2 stm32h7x_dbgmcu_mmw 0x054 0x000C0000 0 -} -$_CHIPNAME.cpu0 configure -event trace-config { - # Set TRACECLKEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins - # assignment + # Enable clock for tracing + # DBGMCU_CR |= TRACECLKEN stm32h7x_dbgmcu_mmw 0x004 0x00100000 0 + + # RM0399 (id 0x450) M7+M4 with SWO Funnel + # RM0433 (id 0x450) M7 with SWO Funnel + # RM0455 (id 0x480) M7 without SWO Funnel + # RM0468 (id 0x483) M7 without SWO Funnel + # Enable CM7 and CM4 slave ports in SWO trace Funnel + # Works ok also on devices single core and without SWO funnel + # Hack, use stm32h7x_dbgmcu_mmw with big offset to control SWTF + # SWTF_CTRL |= ENS0 | ENS1 + stm32h7x_dbgmcu_mmw 0x3000 0x00000003 0 } $_CHIPNAME.cpu0 configure -event reset-init { @@ -173,10 +203,19 @@ $_CHIPNAME.cpu0 configure -event reset-init { adapter speed 4000 } +# get _CHIPNAME from current target +proc stm32h7x_get_chipname {} { + set t [target current] + set sep [string last "." $t] + if {$sep == -1} { + return $t + } + return [string range $t 0 [expr {$sep - 1}]] +} + if {[set $_CHIPNAME.DUAL_CORE]} { $_CHIPNAME.cpu1 configure -event examine-end { - # get _CHIPNAME from the current target - set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + set _CHIPNAME [stm32h7x_get_chipname] global $_CHIPNAME.USE_CTI # Stop watchdog counters during halt @@ -195,15 +234,13 @@ if {[set $_CHIPNAME.DUAL_CORE]} { # like mrw, but with target selection proc stm32h7x_mrw {used_target reg} { - set value "" - $used_target mem2array value 32 $reg 1 - return $value(0) + return [$used_target read_memory $reg 32 1] } # like mmw, but with target selection proc stm32h7x_mmw {used_target reg setbits clearbits} { set old [stm32h7x_mrw $used_target $reg] - set new [expr ($old & ~$clearbits) | $setbits] + set new [expr {($old & ~$clearbits) | $setbits}] $used_target mww $reg $new } @@ -212,13 +249,12 @@ proc stm32h7x_mmw {used_target reg setbits clearbits} { proc stm32h7x_dbgmcu_mmw {reg_offset setbits clearbits} { # use $_CHIPNAME.ap2 if possible, and use the proper dbgmcu base address if {![using_hla]} { - # get _CHIPNAME from the current target - set _CHIPNAME [regsub ".(cpu|ap)\\d*$" [target current] ""] + set _CHIPNAME [stm32h7x_get_chipname] set used_target $_CHIPNAME.ap2 - set reg_addr [expr 0xE00E1000 + $reg_offset] + set reg_addr [expr {0xE00E1000 + $reg_offset}] } { set used_target [target current] - set reg_addr [expr 0x5C001000 + $reg_offset] + set reg_addr [expr {0x5C001000 + $reg_offset}] } stm32h7x_mmw $used_target $reg_addr $setbits $clearbits @@ -226,8 +262,8 @@ proc stm32h7x_dbgmcu_mmw {reg_offset setbits clearbits} { if {[set $_CHIPNAME.USE_CTI]} { # create CTI instances for both cores - cti create $_CHIPNAME.cti0 -dap $_CHIPNAME.dap -ap-num 0 -ctibase 0xE0043000 - cti create $_CHIPNAME.cti1 -dap $_CHIPNAME.dap -ap-num 3 -ctibase 0xE0043000 + cti create $_CHIPNAME.cti0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0043000 + cti create $_CHIPNAME.cti1 -dap $_CHIPNAME.dap -ap-num 3 -baseaddr 0xE0043000 $_CHIPNAME.cpu0 configure -event halted { stm32h7x_cti_prepare_restart_all } $_CHIPNAME.cpu1 configure -event halted { stm32h7x_cti_prepare_restart_all } @@ -236,8 +272,7 @@ if {[set $_CHIPNAME.USE_CTI]} { $_CHIPNAME.cpu1 configure -event debug-halted { stm32h7x_cti_prepare_restart_all } proc stm32h7x_cti_start {} { - # get _CHIPNAME from the current target - set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + set _CHIPNAME [stm32h7x_get_chipname] # Configure Cores' CTIs to halt each other # TRIGIN0 (DBGTRIGGER) and TRIGOUT0 (EDBGRQ) at CTM_CHANNEL_0 @@ -252,8 +287,7 @@ if {[set $_CHIPNAME.USE_CTI]} { } proc stm32h7x_cti_stop {} { - # get _CHIPNAME from the current target - set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + set _CHIPNAME [stm32h7x_get_chipname] $_CHIPNAME.cti0 enable off $_CHIPNAME.cti1 enable off @@ -265,8 +299,7 @@ if {[set $_CHIPNAME.USE_CTI]} { } proc stm32h7x_cti_prepare_restart {cti} { - # get _CHIPNAME from the current target - set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + set _CHIPNAME [stm32h7x_get_chipname] # Acknowlodge EDBGRQ at TRIGOUT0 $_CHIPNAME.$cti write INACK 0x01 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 46e6f7e0db..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 # @@ -15,11 +17,11 @@ if { [info exists CHIPNAME] } { set _ENDIAN little # Work-area is a space in RAM used for flash programming -# Smallest current target has 64kB ram, use 32kB by default to avoid surprises +# By default use 40kB (Available RAM in smallest device STM32L412) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x8000 + set _WORKAREASIZE 0xa000 } #jtag scan chain @@ -48,7 +50,25 @@ 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 stm32l4x 0 0 0 0 $_TARGETNAME +flash bank $_FLASHNAME stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME + +if { [info exists QUADSPI] && $QUADSPI } { + set a [llength [flash list]] + set _QSPINAME $_CHIPNAME.qspi + flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 +} else { + if { [info exists OCTOSPI1] && $OCTOSPI1 } { + set a [llength [flash list]] + set _OCTOSPINAME1 $_CHIPNAME.octospi1 + flash bank $_OCTOSPINAME1 stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 + } + if { [info exists OCTOSPI2] && $OCTOSPI2 } { + set b [llength [flash list]] + set _OCTOSPINAME2 $_CHIPNAME.octospi2 + flash bank $_OCTOSPINAME2 stmqspi 0x70000000 0 0 0 $_TARGETNAME 0xA0001400 + } +} # 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 @@ -71,12 +91,61 @@ if {![using_hla]} { cortex_m reset_config sysresetreq } +$_TARGETNAME configure -event examine-end { + # Enable debug during low power modes (uses more power) + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP + mmw 0xE0042004 0x00000007 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= 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 {_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 + mmw 0x48001008 0x00003ff0 0x00000000 + } + } + } else { + # Set TRACE_IOEN; TRACE_MODE to async + mmw 0xE0042004 0x00000020 0x000000c0 + } +} + +$_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). # Use MSI 24 MHz clock, compliant even with VOS == 2. # 3 WS compliant with VOS == 2 and 24 MHz. mww 0x40022000 0x00000103 ;# FLASH_ACR = PRFTBE | 3(Latency) mww 0x40021000 0x00000099 ;# RCC_CR = MSI_ON | MSIRGSEL | MSI Range 9 + # Boost JTAG frequency adapter speed 4000 } @@ -85,19 +154,3 @@ $_TARGETNAME configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 500 } - -$_TARGETNAME configure -event examine-end { - # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP - mmw 0xE0042004 0x00000007 0 - - # Stop watchdog counters during halt - # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP - mmw 0xE0042008 0x00001800 0 -} - -$_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 - # assignment - mmw 0xE0042004 0x00000020 0 -} diff --git a/tcl/target/stm32l5x.cfg b/tcl/target/stm32l5x.cfg new file mode 100644 index 0000000000..c43b699d25 --- /dev/null +++ b/tcl/target/stm32l5x.cfg @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32l5x family +# stm32l5x 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 stm32l5x +} + +source [find target/stm32x5x_common.cfg] + +proc stm32l5x_clock_config {} { + set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] + # MCU clock is MSI (4MHz) after reset, set MCU freq at 110 MHz with PLL + # RCC_APB1ENR1 = PWREN + mww [expr {0x40021058 + $offset}] 0x10000000 + # delay for register clock enable (read back reg) + mrw [expr {0x40021058 + $offset}] + # PWR_CR1 : VOS Range 0 + mww [expr {0x40007000 + $offset}] 0 + # while (PWR_SR2 & VOSF) + while {([mrw [expr {0x40007014 + $offset}]] & 0x0400)} {} + # FLASH_ACR : 5 WS for 110 MHz HCLK + mww 0x40022000 0x00000005 + # RCC_PLLCFGR = PLLP=PLLQ=0, PLLR=00=2, PLLREN=1, PLLN=55, PLLM=0000=1, PLLSRC=MSI 4MHz + # fVCO = 4 x 55 /1 = 220 + # SYSCLOCK = fVCO/PLLR = 220/2 = 110 MHz + mww [expr {0x4002100C + $offset}] 0x01003711 + # RCC_CR |= PLLON + mmw [expr {0x40021000 + $offset}] 0x01000000 0 + # while !(RCC_CR & PLLRDY) + while {!([mrw [expr {0x40021000 + $offset}]] & 0x02000000)} {} + # RCC_CFGR |= SW_PLL + mmw [expr {0x40021008 + $offset}] 0x00000003 0 + # while ((RCC_CFGR & SWS) != PLL) + while {([mrw [expr {0x40021008 + $offset}]] & 0x0C) != 0x0C} {} +} + +$_TARGETNAME configure -event reset-init { + stm32l5x_clock_config + # Boost JTAG frequency + adapter speed 4000 +} diff --git a/tcl/target/stm32lx_stlink.cfg b/tcl/target/stm32lx_stlink.cfg deleted file mode 100644 index 5f694b546f..0000000000 --- a/tcl/target/stm32lx_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32lx_stlink.cfg is deprecated, please switch to target/stm32l1.cfg" -source [find target/stm32l1.cfg] diff --git a/tcl/target/stm32mp13x.cfg b/tcl/target/stm32mp13x.cfg new file mode 100644 index 0000000000..bcf25c9049 --- /dev/null +++ b/tcl/target/stm32mp13x.cfg @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# STMicroelectronics STM32MP13x (Single Cortex-A7) +# http://www.st.com/stm32mp1 + +# HLA does not support custom CSW nor AP other than 0 +if { [using_hla] } { + echo "ERROR: HLA transport cannot work with this target." + echo "ERROR: To use STLink switch to DAP mode, as in \"board/stm32mp13x_dk.cfg\"." + shutdown +} + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32mp13x +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } else { + set _CPUTAPID 0x6ba02477 + } +} + +# Chip Level TAP Controller, only in jtag mode +if { [info exists CLCTAPID] } { + set _CLCTAPID $CLCTAPID +} else { + set _CLCTAPID 0x06501041 +} + +swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 +if { [using_jtag] } { + jtag newtap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 +} + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack + +# NOTE: keep ap-num and dbgbase to speed-up examine after reset +# NOTE: do not change the order of target create +target create $_CHIPNAME.ap1 mem_ap -dap $_CHIPNAME.dap -ap-num 1 +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 +target create $_CHIPNAME.cpu cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 + +$_CHIPNAME.cpu cortex_a maskisr on +$_CHIPNAME.cpu cortex_a dacrfixup on + +# interface does not work while srst is asserted +# this is target specific, valid for every board +# srst resets the debug unit, behavior equivalent to "srst_pulls_trst" +reset_config srst_gates_jtag srst_pulls_trst + +adapter speed 5000 +adapter srst pulse_width 200 +# bootrom has an internal timeout of 1 second for detecting the boot flash. +# wait at least 1 second to guarantee we are out of bootrom +adapter srst delay 1100 + +add_help_text axi_secure "Set secure mode for following AXI accesses" +proc axi_secure {} { + $::_CHIPNAME.dap apsel 0 + $::_CHIPNAME.dap apcsw 0x10006000 +} + +add_help_text axi_nsecure "Set non-secure mode for following AXI accesses" +proc axi_nsecure {} { + $::_CHIPNAME.dap apsel 0 + $::_CHIPNAME.dap apcsw 0x30006000 +} + +axi_secure + +proc dbgmcu_enable_debug {} { + # keep clock enabled in low-power + ## catch {$::_CHIPNAME.ap1 mww 0xe0081004 0x00000004} + # freeze watchdog 1 and 2 on core halted + catch {$::_CHIPNAME.ap1 mww 0xe008102c 0x00000004} + catch {$::_CHIPNAME.ap1 mww 0xe008104c 0x00000008} +} + +proc toggle_cpu_dbg_claim0 {} { + # toggle CPU0 DBG_CLAIM[0] + $::_CHIPNAME.ap1 mww 0xe00d0fa0 1 + $::_CHIPNAME.ap1 mww 0xe00d0fa4 1 +} + +# FIXME: most of handlers below will be removed once reset framework get merged +$_CHIPNAME.ap1 configure -event reset-deassert-pre { + adapter deassert srst deassert trst + catch {dap init} + catch {$::_CHIPNAME.dap apid 1} +} +$_CHIPNAME.cpu configure -event reset-deassert-pre {$::_CHIPNAME.cpu arp_examine} +$_CHIPNAME.cpu configure -event reset-deassert-post {toggle_cpu_dbg_claim0; dbgmcu_enable_debug} +$_CHIPNAME.ap1 configure -event examine-start {dap init} +$_CHIPNAME.ap1 configure -event examine-end {dbgmcu_enable_debug} diff --git a/tcl/target/stm32mp15x.cfg b/tcl/target/stm32mp15x.cfg index f2ba94eec3..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 @@ -59,10 +61,13 @@ $_CHIPNAME.cpu1 cortex_a maskisr on $_CHIPNAME.cpu0 cortex_a dacrfixup on $_CHIPNAME.cpu1 cortex_a dacrfixup on -cti create $_CHIPNAME.cti.sys -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0xE0094000 -cti create $_CHIPNAME.cti.cpu0 -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0xE00D8000 -cti create $_CHIPNAME.cti.cpu1 -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0xE00D9000 -cti create $_CHIPNAME.cti.cm4 -dap $_CHIPNAME.dap -ap-num 2 -ctibase 0xE0043000 +cti create $_CHIPNAME.cti.sys -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0094000 +cti create $_CHIPNAME.cti.cpu0 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE00D8000 +cti create $_CHIPNAME.cti.cpu1 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE00D9000 +cti create $_CHIPNAME.cti.cm4 -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE0043000 + +swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0083000 +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0093000 # interface does not work while srst is asserted # this is target specific, valid for every board @@ -94,6 +99,9 @@ axi_secure proc dbgmcu_enable_debug {} { # set debug enable bits in DBGMCU_CR to get ap2 and cm4 visible catch {$::_CHIPNAME.ap1 mww 0xe0081004 0x00000007} + # freeze watchdog 1 and 2 on cores halted + catch {$::_CHIPNAME.ap1 mww 0xe008102c 0x00000004} + catch {$::_CHIPNAME.ap1 mww 0xe008104c 0x00000008} } proc toggle_cpu0_dbg_claim0 {} { @@ -103,14 +111,18 @@ proc toggle_cpu0_dbg_claim0 {} { } proc detect_cpu1 {} { - $::_CHIPNAME.ap1 mem2array cpu1_prsr 32 0xE00D2314 1 - set dual_core [expr $cpu1_prsr(0) & 1] + set cpu1_prsr [$::_CHIPNAME.ap1 read_memory 0xE00D2314 32 1] + set dual_core [expr {$cpu1_prsr & 1}] if {! $dual_core} {$::_CHIPNAME.cpu1 configure -defer-examine} } +proc rcc_enable_traceclk {} { + $::_CHIPNAME.ap2 mww 0x5000080c 0x301 +} + # FIXME: most of handler below will be removed once reset framework get merged -$_CHIPNAME.ap1 configure -event reset-deassert-pre {adapter deassert srst deassert trst;dap init;catch {$::_CHIPNAME.dap apid 1}} -$_CHIPNAME.ap2 configure -event reset-deassert-pre {dbgmcu_enable_debug} +$_CHIPNAME.ap1 configure -event reset-deassert-pre {adapter deassert srst deassert trst;catch {dap init};catch {$::_CHIPNAME.dap apid 1}} +$_CHIPNAME.ap2 configure -event reset-deassert-pre {dbgmcu_enable_debug;rcc_enable_traceclk} $_CHIPNAME.cpu0 configure -event reset-deassert-pre {$::_CHIPNAME.cpu0 arp_examine} $_CHIPNAME.cpu1 configure -event reset-deassert-pre {$::_CHIPNAME.cpu1 arp_examine allow-defer} $_CHIPNAME.cpu0 configure -event reset-deassert-post {toggle_cpu0_dbg_claim0} @@ -118,4 +130,4 @@ $_CHIPNAME.cm4 configure -event reset-deassert-post {$::_CHIPNAME.cm4 arp_exami $_CHIPNAME.ap1 configure -event examine-start {dap init} $_CHIPNAME.ap2 configure -event examine-start {dbgmcu_enable_debug} $_CHIPNAME.cpu0 configure -event examine-end {detect_cpu1} -$_CHIPNAME.ap2 configure -event examine-end {$::_CHIPNAME.cm4 arp_examine} +$_CHIPNAME.ap2 configure -event examine-end {rcc_enable_traceclk;$::_CHIPNAME.cm4 arp_examine} diff --git a/tcl/target/stm32u5x.cfg b/tcl/target/stm32u5x.cfg new file mode 100644 index 0000000000..44b51e2b65 --- /dev/null +++ b/tcl/target/stm32u5x.cfg @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32u5x family +# stm32u5x 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 stm32u5x +} + +source [find target/stm32x5x_common.cfg] + +proc stm32u5x_clock_config {} { + set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] + # MCU clock is at MSI 4MHz after reset, set MCU freq at 160 MHz with PLL + + # Enable voltage range 1 for frequency above 100 Mhz + # RCC_AHB3ENR = PWREN + mww [expr {0x46020C94 + $offset}] 0x00000004 + # delay for register clock enable (read back reg) + mrw [expr {0x46020C94 + $offset}] + # PWR_VOSR : VOS Range 1 + mmw [expr {0x4602080C + $offset}] 0x00030000 0 + # while !(PWR_VOSR & VOSRDY) + while {!([mrw [expr {0x4602080C + $offset}]] & 0x00008000)} {} + # FLASH_ACR : 4 WS for 160 MHz HCLK + mww [expr {0x40022000 + $offset}] 0x00000004 + # RCC_PLL1CFGR => PLL1MBOOST=0, PLL1M=0=/1, PLL1FRACEN=0, PLL1SRC=MSI 4MHz + # PLL1REN=1, PLL1RGE => VCOInputRange=PLLInputRange_4_8 + mww [expr {0x46020C28 + $offset}] 0x00040009 + # Enable EPOD Booster + mmw [expr {0x4602080C + $offset}] 0x00040000 0 + # while !(PWR_VOSR & BOOSTRDY) + while {!([mrw [expr {0x4602080C + $offset}]] & 0x00004000)} {} + # RCC_PLL1DIVR => PLL1P=PLL1Q=PLL1R=000001=/2, PLL1N=0x4F=80 + # fVCO = 4 x 80 /1 = 320 + # SYSCLOCK = fVCO/PLL1R = 320/2 = 160 MHz + mww [expr {0x46020C34 + $offset}] 0x0101024F + # RCC_CR |= PLL1ON + mmw [expr {0x46020C00 + $offset}] 0x01000000 0 + # while !(RCC_CR & PLL1RDY) + while {!([mrw [expr {0x46020C00 + $offset}]] & 0x02000000)} {} + # RCC_CFGR1 |= SW_PLL + mmw [expr {0x46020C1C + $offset}] 0x00000003 0 + # while ((RCC_CFGR1 & SWS) != PLL) + while {([mrw [expr {0x46020C1C + $offset}]] & 0x0C) != 0x0C} {} +} + +$_TARGETNAME configure -event reset-init { + stm32u5x_clock_config + # Boost JTAG frequency + adapter speed 4000 +} diff --git a/tcl/target/stm32w108_stlink.cfg b/tcl/target/stm32w108_stlink.cfg deleted file mode 100644 index 120feea947..0000000000 --- a/tcl/target/stm32w108_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32w108xx_stlink.cfg is deprecated, please switch to target/stm32w108xx.cfg" -source [find target/stm32w108xx.cfg] 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 90f53bb967..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 # @@ -46,8 +48,8 @@ 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 stm32l4x 0 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 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 @@ -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 ba16fab6b2..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 # @@ -12,16 +14,47 @@ if { [info exists CHIPNAME] } { set _CHIPNAME stm32wlx } -set _ENDIAN little +if { [info exists DUAL_CORE] } { + set $_CHIPNAME.DUAL_CORE $DUAL_CORE + unset DUAL_CORE +} else { + set $_CHIPNAME.DUAL_CORE 0 +} + +if { [info exists WKUP_CM0P] } { + set $_CHIPNAME.WKUP_CM0P $WKUP_CM0P + unset WKUP_CM0P +} else { + set $_CHIPNAME.WKUP_CM0P 0 +} + +# Issue a warning when hla is used, and fallback to single core configuration +if { [set $_CHIPNAME.DUAL_CORE] && [using_hla] } { + echo "Warning : hla does not support multicore debugging" + set $_CHIPNAME.DUAL_CORE 0 + set $_CHIPNAME.WKUP_CM0P 0 +} +# setup the Work-area start address and size # Work-area is a space in RAM used for flash programming -# By default use 20kB + +# Memory map for known devices: +# STM32WL x5JC x5JB x5J8 +# FLASH 256 128 64 +# SRAM1 32 16 0 +# SRAM2 32 32 20 + +# By default use 8kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x5000 + set _WORKAREASIZE 0x2000 } +# Use SRAM2 as work area (some devices do not have SRAM1): +set WORKAREASTART_CM4 0x20008000 +set WORKAREASTART_CM0P [expr {$WORKAREASTART_CM4 + $_WORKAREASIZE}] + #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID @@ -41,36 +74,20 @@ if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } -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 - -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32l4x 0 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 +target create $_CHIPNAME.cpu0 cortex_m -endian little -dap $_CHIPNAME.dap -adapter srst delay 100 -if {[using_jtag]} { - jtag_ntrst_delay 100 -} +$_CHIPNAME.cpu0 configure -work-area-phys $WORKAREASTART_CM4 -work-area-size $_WORKAREASIZE -work-area-backup 0 -reset_config srst_nogate +flash bank $_CHIPNAME.flash.cpu0 stm32l4x 0x08000000 0 0 0 $_CHIPNAME.cpu0 +flash bank $_CHIPNAME.otp.cpu0 stm32l4x 0x1fff7000 0 0 0 $_CHIPNAME.cpu0 if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to # perform a soft reset - cortex_m reset_config sysresetreq + $_CHIPNAME.cpu0 cortex_m reset_config sysresetreq } -$_TARGETNAME configure -event reset-init { +$_CHIPNAME.cpu0 configure -event reset-init { # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 4 MHz. # Configure system to use MSI 24 MHz clock, compliant with VOS default Range1. # 2 WS compliant with VOS=Range1 and 24 MHz. @@ -80,12 +97,12 @@ $_TARGETNAME configure -event reset-init { adapter speed 4000 } -$_TARGETNAME configure -event reset-start { +$_CHIPNAME.cpu0 configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 500 } -$_TARGETNAME configure -event examine-end { +$_CHIPNAME.cpu0 configure -event examine-end { # Enable debug during low power modes (uses more power) # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 @@ -93,8 +110,76 @@ $_TARGETNAME configure -event examine-end { # Stop watchdog counters during halt # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE004203C 0x00001800 0 + + set _CHIPNAME [stm32wlx_get_chipname] + global $_CHIPNAME.WKUP_CM0P + + if {[set $_CHIPNAME.WKUP_CM0P]} { + stm32wlx_wkup_cm0p + } +} + +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 + + $_CHIPNAME.cpu0 configure -work-area-phys $WORKAREASTART_CM0P -work-area-size $_WORKAREASIZE -work-area-backup 0 + + flash bank $_CHIPNAME.flash.cpu1 stm32l4x 0x08000000 0 0 0 $_CHIPNAME.cpu1 + flash bank $_CHIPNAME.otp.cpu1 stm32l4x 0x1fff7000 0 0 0 $_CHIPNAME.cpu1 + + if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + $_CHIPNAME.cpu1 cortex_m reset_config sysresetreq + } + + proc stm32wlx_wkup_cm0p {} { + set _CHIPNAME [stm32wlx_get_chipname] + + # enable CPU2 boot after reset and after wakeup from Stop or Standby mode + # PWR_CR4 |= C2BOOT + stm32wlx_mmw $_CHIPNAME.cpu0 0x5800040C 0x00008000 0 + } +} + +# get _CHIPNAME from current target +proc stm32wlx_get_chipname {} { + set t [target current] + set sep [string last "." $t] + if {$sep == -1} { + return $t + } + return [string range $t 0 [expr {$sep - 1}]] +} + +# like mrw, but with target selection +proc stm32wlx_mrw {used_target reg} { + return [$used_target read_memory $reg 32 1] +} + +# like mmw, but with target selection +proc stm32wlx_mmw {used_target reg setbits clearbits} { + set old [stm32wlx_mrw $used_target $reg] + set new [expr {($old & ~$clearbits) | $setbits}] + $used_target mww $reg $new } -$_TARGETNAME configure -event trace-config { - # nothing to do +# Make sure that cpu0 is selected +targets $_CHIPNAME.cpu0 + +# 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 diff --git a/tcl/target/stm32x5x_common.cfg b/tcl/target/stm32x5x_common.cfg new file mode 100644 index 0000000000..fb3aeb18c1 --- /dev/null +++ b/tcl/target/stm32x5x_common.cfg @@ -0,0 +1,169 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# common script for stm32l5x and stm32u5x families + +# 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] } { + # STM32L5x: RM0438 Rev5, Section 52.2.8 JTAG debug port - Table 425. JTAG-DP data registers + # STM32U5x: RM0456 Rev1, Section 65.2.8 JTAG debug port - Table 661. JTAG-DP data registers + # Corresponds to Cortex®-M33 JTAG debug port ID code + set _CPUTAPID 0x0ba04477 + } { + # SWD IDCODE (single drop, arm) + set _CPUTAPID 0x0be12477 + } +} + +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 + +# use non-secure RAM by default +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# create sec/ns flash and otp memories (sizes will be probed) +flash bank $_CHIPNAME.flash_ns stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash_alias_s stm32l4x 0x0C000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x0BFA0000 0 0 0 $_TARGETNAME + +# Common knowledge 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://review.openocd.org/3366 +adapter speed 500 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +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 +} + +proc stm32x5x_is_secure {} { + # read Debug Security Control and Status Register (DSCSR) and check CDS (bit 16) + set DSCSR [mrw 0xE000EE08] + return [expr {($DSCSR & (1 << 16)) != 0}] +} + +proc stm32x5x_ahb_ap_non_secure_access {} { + # 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 {} { + if {![using_hla]} { + # SPROT=0=Secure access, Priv=1 + [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 + } +} + +$_TARGETNAME configure -event reset-start { + # Reset clock is MSI (4 MHz) + adapter speed 480 +} + +$_TARGETNAME configure -event examine-end { + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP + mmw 0xE0044004 0x00000006 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE0044008 0x00001800 0 +} + +$_TARGETNAME configure -event halted { + set secure [stm32x5x_is_secure] + + if {$secure} { + set secure_str "Secure" + stm32x5x_ahb_ap_secure_access + } else { + set secure_str "Non-Secure" + stm32x5x_ahb_ap_non_secure_access + } + + # print the secure state only when it changes + set _TARGETNAME [target current] + global $_TARGETNAME.secure + + if {![info exists $_TARGETNAME.secure] || $secure != [set $_TARGETNAME.secure]} { + echo "CPU in $secure_str state" + # update saved security state + set $_TARGETNAME.secure $secure + } +} + +$_TARGETNAME configure -event gdb-flash-erase-start { + set use_secure_workarea 0 + # check if FLASH_OPTR.TZEN is enabled + set FLASH_OPTR [mrw 0x40022040] + if {[expr {$FLASH_OPTR & 0x80000000}] == 0} { + echo "TZEN option bit disabled" + stm32x5x_ahb_ap_non_secure_access + } else { + stm32x5x_ahb_ap_secure_access + echo "TZEN option bit enabled" + + # check if FLASH_OPTR.RDP is not Level 0.5 + if {[expr {$FLASH_OPTR & 0xFF}] != 0x55} { + set use_secure_workarea 1 + } + } + + set _TARGETNAME [target current] + set workarea_addr [$_TARGETNAME cget -work-area-phys] + echo "workarea_addr $workarea_addr" + + if {$use_secure_workarea} { + set workarea_addr [expr {$workarea_addr | 0x10000000}] + } else { + set workarea_addr [expr {$workarea_addr & ~0x10000000}] + } + + $_TARGETNAME configure -work-area-phys $workarea_addr +} + +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 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 74269aa66c..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 # @@ -26,11 +28,11 @@ proc ocd_process_reset_inner { MODE } { soft_reset_halt # Initialize MSP, PSP, and PC from vector table at flash 0x01000800 - mem2array boot 32 0x01000800 2 + set boot [read_memory 0x01000800 32 2] - reg msp $boot(0) - reg psp $boot(0) - reg pc $boot(1) + reg msp [lindex $boot 0] + reg psp [lindex $boot 0] + reg pc [lindex $boot 1] if { 0 == [string compare $MODE run ] } { resume 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 91c008765d..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 # @@ -90,7 +92,7 @@ target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME # NOTE that work-area-virt presumes a Linux 2.6.30-rc2+ kernel, # and that the work area is used only with a kernel mmu context ... $_TARGETNAME configure \ - -work-area-virt [expr 0xfffe0000 + 0x4000] \ + -work-area-virt [expr {0xfffe0000 + 0x4000}] \ -work-area-phys [dict get $dm355 sram1] \ -work-area-size 0x4000 \ -work-area-backup 0 diff --git a/tcl/target/ti_dm365.cfg b/tcl/target/ti_dm365.cfg index 8b52746bd1..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 # @@ -82,7 +84,7 @@ target create $_TARGETNAME arm926ejs -chain-position $_TARGETNAME # NOTE that work-area-virt presumes a Linux 2.6.30-rc2+ kernel, # and that the work area is used only with a kernel mmu context ... $_TARGETNAME configure \ - -work-area-virt [expr 0xfffe0000 + 0x4000] \ + -work-area-virt [expr {0xfffe0000 + 0x4000}] \ -work-area-phys [dict get $dm365 sram1] \ -work-area-size 0x4000 \ -work-area-backup 0 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 new file mode 100644 index 0000000000..ebea821793 --- /dev/null +++ b/tcl/target/ti_k3.cfg @@ -0,0 +1,491 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# 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 +# * J7200: https://www.ti.com/lit/pdf/spruiu1 +# Has 2 ARMV8 Cores and 4 R5 Cores 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 { + set _soc am654 +} + +# set V8_SMP_DEBUG to non 0 value in board if you'd like to use SMP debug +if { [info exists V8_SMP_DEBUG] } { + set _v8_smp_debug $V8_SMP_DEBUG +} else { + set _v8_smp_debug 0 +} + +# Common Definitions + +# System Controller is the very first processor - all current SoCs have it. +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 +set ARMV8_DBGBASE {0x90410000 0x90510000 0x90810000 0x90910000} +set ARMV8_CTIBASE {0x90420000 0x90520000 0x90820000 0x90920000} + +# And we add up the R5s +# (0)MCU 0 (1)MCU 1 (2)MAIN_0_0 (3)MAIN_0_1 (4)MAIN_1_0 (5)MAIN_1_1 +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} + +# General Purpose MCU (M4) may be present on some very few SoCs +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 _K3_DAP_TAPID 0x0bb5a02f + + # AM654 has 2 clusters of 2 A53 cores each. + set _armv8_cpu_name a53 + set _armv8_cores 4 + + # AM654 has 1 cluster of 2 R5s cores. + set _r5_cores 2 + set R5_NAMES {mcu_r5.0 mcu_r5.1} + + # Sysctrl power-ap unlock offsets + set _sysctrl_ap_unlock_offsets {0xf0 0x50} + } + am243 - + am642 { + set _K3_DAP_TAPID 0x0bb3802f + + # AM642 has 1 clusters of 2 A53 cores each. + set _armv8_cpu_name a53 + set _armv8_cores 2 + set ARMV8_DBGBASE {0x90010000 0x90110000} + set ARMV8_CTIBASE {0x90020000 0x90120000} + + # AM642 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 {0x9d410000 0x9d412000 0x9d510000 0x9d512000} + set R5_CTIBASE {0x9d418000 0x9d419000 0x9d518000 0x9d519000} + + # M4 processor + set _gp_mcu_cores 1 + + # Overrides for am243 + if { "$_soc" == "am243" } { + # Uses the same JTAG ID + set _armv8_cores 0 + } + } + am625 { + set _K3_DAP_TAPID 0x0bb7e02f + + # AM625 has 1 clusters 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} + + # AM625 has 1 cluster of 1 R5s core. + set _r5_cores 1 + set R5_NAMES {main0_r5.0} + set R5_DBGBASE {0x9d410000} + set R5_CTIBASE {0x9d418000} + + # sysctrl CTI base + set CM3_CTIBASE {0x20001000} + # Sysctrl power-ap unlock offsets + set _sysctrl_ap_unlock_offsets {0xf0 0x78} + + # 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 _K3_DAP_TAPID 0x0bb6402f + # J721E has 1 cluster of 2 A72 cores. + set _armv8_cpu_name a72 + set _armv8_cores 2 + + # 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 _K3_DAP_TAPID 0x0bb6d02f + + # J7200 has 1 cluster of 2 A72 cores. + set _armv8_cpu_name a72 + set _armv8_cores 2 + + # J7200 has 2 clusters of 2 R5 cores each. + set _r5_cores 4 + set R5_DBGBASE {0x9d010000 0x9d012000 0x9d110000 0x9d112000} + set R5_CTIBASE {0x9d018000 0x9d019000 0x9d118000 0x9d119000} + + # M3 CTI base + set CM3_CTIBASE {0x20001000} + } + j721s2 { + set _K3_DAP_TAPID 0x0bb7502f + + # J721s2 has 1 cluster of 2 A72 cores. + set _armv8_cpu_name a72 + set _armv8_cores 2 + + # J721s2 has 3 clusters of 2 R5 cores each. + set _r5_cores 6 + + # sysctrl CTI base + set CM3_CTIBASE {0x20001000} + # Sysctrl power-ap unlock offsets + set _sysctrl_ap_unlock_offsets {0xf0 0x78} + + # M4 processor + 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!" + } +} + +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 + +set _CTINAME $_CHIPNAME.cti + +# sysctrl is always present +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 {} { + # To access sysctrl, we need to enable the JTAG access for the same. + # Ensure Power-AP unlocked + $::_CHIPNAME.dap apreg 3 [lindex $::_sysctrl_ap_unlock_offsets 0] 0x00190000 + $::_CHIPNAME.dap apreg 3 [lindex $::_sysctrl_ap_unlock_offsets 1] 0x00102098 + + $::_TARGETNAME.sysctrl arp_examine +} + +$_TARGETNAME.sysctrl configure -event gdb-attach { + sysctrl_up + # gdb-attach default rule + halt 1000 +} + +proc _cpu_no_smp_up {} { + set _current_target [target current] + set _current_type [$_current_target cget -type] + + $_current_target arp_examine + $_current_target $_current_type dbginit +} + +proc _armv8_smp_up {} { + for { set _core 0 } { $_core < $::_armv8_cores } { incr _core } { + $::_TARGETNAME.$::_armv8_cpu_name.$_core arp_examine + $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 dbginit + $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 smp on + } + # Set Default target as core 0 + targets $::_TARGETNAME.$::_armv8_cpu_name.0 +} + +set _v8_smp_targets "" + +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 -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" + + if { $_v8_smp_debug == 0 } { + $_TARGETNAME.$_armv8_cpu_name.$_core configure -event gdb-attach { + _cpu_no_smp_up + # gdb-attach default rule + halt 1000 + } + } else { + $_TARGETNAME.$_armv8_cpu_name.$_core configure -event gdb-attach { + _armv8_smp_up + # gdb-attach default rule + halt 1000 + } + } +} + +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 + } + } + } 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 $_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 $_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 + # gdb-attach default rule + halt 1000 + } +} + +proc r5_up { args } { + foreach _core $args { + targets $_core + _cpu_no_smp_up + } +} + +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 \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.gp_mcu] + $_TARGETNAME.gp_mcu configure -event reset-assert { } + + proc gp_mcu_up {} { + # To access GP MCU, we need to enable the JTAG access for the same. + # Ensure Power-AP unlocked + $::_CHIPNAME.dap apreg 3 [lindex $::_gp_mcu_ap_unlock_offsets 0] 0x00190000 + $::_CHIPNAME.dap apreg 3 [lindex $::_gp_mcu_ap_unlock_offsets 1] 0x00102098 + + $::_TARGETNAME.gp_mcu arp_examine + } + + $_TARGETNAME.gp_mcu configure -event gdb-attach { + gp_mcu_up + # gdb-attach default rule + 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 36e0db71d2..417fdd18f2 100644 --- a/tcl/target/u8500.cfg +++ b/tcl/target/u8500.cfg @@ -1,16 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) ST-Ericsson SA 2011 # Author : michel.jaouen@stericsson.com # U8500 target proc mmu_off {} { set cp [arm mrc 15 0 1 0 0] - set cp [expr ($cp & ~1)] + set cp [expr {$cp & ~1}] arm mcr 15 0 1 0 0 $cp } proc mmu_on {} { set cp [arm mrc 15 0 1 0 0] - set cp [expr ($cp | 1)] + set cp [expr {$cp | 1}] arm mcr 15 0 1 0 0 $cp } @@ -18,12 +20,12 @@ proc ocd_gdb_restart {target_id} { global _TARGETNAME_1 global _SMP targets $_TARGETNAME_1 - if { [expr ($_SMP == 1)] } { + if { $_SMP == 1 } { cortex_a smp off } rst_run halt - if { [expr ($_SMP == 1)]} { + if { $_SMP == 1 } { cortex_a smp on } } @@ -52,9 +54,9 @@ proc pwrsts { } { irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 0 set pwrsts [drscan $_CHIPNAME.jrc 16 0] - echo "pwrsts ="$pwrsts - set a9 [expr (0x$pwrsts & 0xc)] - set ape [expr (0x$pwrsts & 0x3)] + echo "pwrsts ="$pwrsts + set a9 [expr "0x$pwrsts & 0xc"] + set ape [expr "0x$pwrsts & 0x3"] if {[string equal "0" $ape]} { echo "ape off" } else { @@ -81,12 +83,12 @@ proc poll_pwrsts { } { irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 0 set pwrsts [drscan $_CHIPNAME.jrc 16 0] - set pwrsts [expr (0x$pwrsts & 0xc)] + set pwrsts [expr "0x$pwrsts & 0xc"] while {[string equal "4" $pwrsts] && $i<20} { irscan $_CHIPNAME.jrc 0x3a drscan $_CHIPNAME.jrc 4 0; set pwrsts [drscan $_CHIPNAME.jrc 16 0] - set pwrsts [expr (0x$pwrsts & 0xc)] + set pwrsts [expr "0x$pwrsts & 0xc"] if {![string equal "4" $pwrsts]} { set result 1 } else { @@ -239,7 +241,7 @@ proc secsts1 { } { drscan $_CHIPNAME.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 - set secsts1 [expr (0x$secsts1 & 0x4)] + set secsts1 [expr "0x$secsts1 & 0x4"] if {![string equal "4" $secsts1]} { echo "APE target secured" } else { @@ -254,7 +256,7 @@ proc att { } { drscan $_CHIPNAME.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 - set secsts1 [expr (0x$secsts1 & 0x4)] + set secsts1 [expr "0x$secsts1 & 0x4"] if {[string equal "4" $secsts1]} { if {[poll_pwrsts]==1} { enable_apetap @@ -291,13 +293,13 @@ proc rst_run { } { drscan $_CHIPNAME.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 - set secsts1 [expr (0x$secsts1 & 0x4)] + set secsts1 [expr "0x$secsts1 & 0x4"] while {![string equal "4" $secsts1]} { irscan u8500.jrc 0x3a drscan u8500.jrc 4 4 set secsts1 [drscan $_CHIPNAME.jrc 16 0] echo "secsts1 ="$secsts1 - set secsts1 [expr (0x$secsts1 & 0x4)] + set secsts1 [expr "0x$secsts1 & 0x4"] } echo "ape debugable" enable_apetap diff --git a/tcl/target/vd_aarch64.cfg b/tcl/target/vd_aarch64.cfg new file mode 100644 index 0000000000..177416bd0a --- /dev/null +++ b/tcl/target/vd_aarch64.cfg @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm v8 64b Cortex A + +if {![info exists CORES]} { + set CORES 1 +} +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 _DAPNAME $CHIPNAME.dap + +dap create $_DAPNAME $_DAP6 -chain-position $_TARGETNAME + +for { set _core 0 } { $_core < $CORES } { incr _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 _cmd "$_cmd -defer-examine" + set _smp_cmd "$_smp_cmd $_TARGETNAME.$_core" + } else { + set _smp_cmd "target smp $_TARGETNAME.$_core" + } + eval $_cmd +} +eval $_smp_cmd + +set _TARGETCUR $_TARGETNAME.0 +targets $_TARGETCUR diff --git a/tcl/target/vd_cortex_m.cfg b/tcl/target/vd_cortex_m.cfg new file mode 100644 index 0000000000..7db9d3aba4 --- /dev/null +++ b/tcl/target/vd_cortex_m.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# ARM Cortex M + +if {![info exists CHIPNAME]} { + set CHIPNAME cortex_m +} +set _TARGETNAME $CHIPNAME.cpu +set _DAPNAME $CHIPNAME.dap + +dap create $_DAPNAME -chain-position $_TARGETNAME + +target create $_TARGETNAME cortex_m -dap $_DAPNAME diff --git a/tcl/target/vd_riscv.cfg b/tcl/target/vd_riscv.cfg new file mode 100644 index 0000000000..f08cb1ac8b --- /dev/null +++ b/tcl/target/vd_riscv.cfg @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV core + +if {![info exists _HARTID]} { + set _HARTID 0x00 +} +if {![info exists _CHIPNAME]} { + set _CHIPNAME riscv +} +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $_HARTID + +riscv set_reset_timeout_sec 120 +riscv set_command_timeout_sec 120 +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 9be781cd8f..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) @@ -74,7 +76,7 @@ set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core } { cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ - -ctibase [lindex $CTIBASE $_core] + -baseaddr [lindex $CTIBASE $_core] set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" @@ -84,20 +86,21 @@ 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" } eval $_command } +target create uscale.axi mem_ap -dap uscale.dap -ap-num 0 + eval $_smp_command targets $_TARGETNAME.0 proc core_up { args } { global _TARGETNAME - foreach { core } [set args] { + foreach core $args { $_TARGETNAME.$core arp_examine } } 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..5a88b6e9d5 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/target/\320\2721879x\320\2611\321\217.cfg" "b/tcl/target/\320\2721879x\320\2611\321\217.cfg" index 0a8467f49b..8dd330d054 100644 --- "a/tcl/target/\320\2721879x\320\2611\321\217.cfg" +++ "b/tcl/target/\320\2721879x\320\2611\321\217.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/test/selftest.cfg b/tcl/test/selftest.cfg index be420ca0ca..10efb0c6df 100644 --- a/tcl/test/selftest.cfg +++ b/tcl/test/selftest.cfg @@ -1,13 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later add_help_text selftest "run selftest using working ram <tmpfile> <address> <size>" proc selftest {tmpfile address size} { - for {set i 0} {$i < $size } {set i [expr $i+4]} { - mww [expr $address+$i] $i + for {set i 0} {$i < $size } {set i [expr {$i+4}]} { + mww [expr {$address+$i}] $i } - for {set i 0} {$i < 10 } {set i [expr $i+1]} { + for {set i 0} {$i < 10 } {set i [expr {$i+1}]} { echo "Test iteration $i" dump_image $tmpfile $address $size verify_image $tmpfile $address bin 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 02f94d3078..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 @@ -74,7 +76,7 @@ proc memTestDataBus { address } { # * #*********************************************************************************** proc memTestAddressBus { baseAddress nBytes } { - set addressMask [expr $nBytes - 1] + set addressMask [expr {$nBytes - 1}] set pattern 0xAAAAAAAA set antipattern 0x55555555 @@ -83,16 +85,16 @@ proc memTestAddressBus { baseAddress nBytes } { echo "addressMask: [convertToHex $addressMask]" echo "memTestAddressBus: Writing the default pattern at each of the power-of-two offsets..." - for {set offset 32} {[expr $offset & $addressMask] != 0} {set offset [expr $offset << 1] } { - set addr [expr $baseAddress + $offset] + for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}] } { + set addr [expr {$baseAddress + $offset}] memwrite32 $addr $pattern } echo "memTestAddressBus: Checking for address bits stuck high..." memwrite32 $baseAddress $antipattern - for {set offset 32} {[expr $offset & $addressMask] != 0} {set offset [expr $offset << 1]} { - set addr [expr $baseAddress + $offset] + for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}]} { + set addr [expr {$baseAddress + $offset}] set data [memread32 $addr] if {$data != $pattern} { @@ -103,8 +105,8 @@ proc memTestAddressBus { baseAddress nBytes } { echo "memTestAddressBus: Checking for address bits stuck low or shorted..." memwrite32 $baseAddress $pattern - for {set testOffset 32} {[expr $testOffset & $addressMask] != 0} {set testOffset [expr $testOffset << 1] } { - set addr [expr $baseAddress + $testOffset] + for {set testOffset 32} {[expr {$testOffset & $addressMask}] != 0} {set testOffset [expr {$testOffset << 1}] } { + set addr [expr {$baseAddress + $testOffset}] memwrite32 $addr $antipattern set data [memread32 $baseAddress] @@ -113,8 +115,8 @@ proc memTestAddressBus { baseAddress nBytes } { return $pattern } - for {set offset 32} {[expr $offset & $addressMask] != 0} {set offset [expr $offset << 1]} { - set addr [expr $baseAddress + $offset] + for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}]} { + set addr [expr {$baseAddress + $offset}] set data [memread32 $baseAddress] if {(($data != $pattern) && ($offset != $testOffset))} { @@ -122,7 +124,7 @@ proc memTestAddressBus { baseAddress nBytes } { return $pattern } } - set addr [expr $baseAddress + $testOffset] + set addr [expr {$baseAddress + $testOffset}] memwrite32 $addr $pattern } } @@ -153,12 +155,12 @@ proc memTestDevice { baseAddress nBytes } { echo "memTestDevice: Filling memory with a known pattern..." for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { - memwrite32 [expr $baseAddress + $offset] $pattern + memwrite32 [expr {$baseAddress + $offset}] $pattern } echo "memTestDevice: Checking each location and inverting it for the second pass..." for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { - set addr [expr $baseAddress + $offset] + set addr [expr {$baseAddress + $offset}] set data [memread32 $addr] if {$data != $pattern} { @@ -166,18 +168,18 @@ proc memTestDevice { baseAddress nBytes } { return $pattern } - set antiPattern [expr ~$pattern] - memwrite32 [expr $baseAddress + $offset] $antiPattern + set antiPattern [expr {~$pattern}] + memwrite32 [expr {$baseAddress + $offset}] $antiPattern } echo "memTestDevice: Checking each location for the inverted pattern and zeroing it..." for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { - set antiPattern [expr ~$pattern & ((1<<32) - 1)] - set addr [expr $baseAddress + $offset] + set antiPattern [expr {~$pattern & ((1<<32) - 1)}] + set addr [expr {$baseAddress + $offset}] set data [memread32 $addr] set dataHex [convertToHex $data] set antiPatternHex [convertToHex $antiPattern] - if {[expr $dataHex != $antiPatternHex]} { + if {$dataHex != $antiPatternHex} { echo "FAILED memTestDevice_antipattern: Address: [convertToHex $addr], antiPattern: $antiPatternHex, Returned: $dataHex, offset: $offset" return $pattern } diff --git a/tcl/tools/test_cpu_speed.tcl b/tcl/tools/test_cpu_speed.tcl new file mode 100644 index 0000000000..f1a3fb30e0 --- /dev/null +++ b/tcl/tools/test_cpu_speed.tcl @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Description: +# Measure the CPU clock frequency of an ARM Cortex-M based device. +# +# Return: +# The CPU clock frequency in Hz. A negative value indicates that the loop +# counter was saturated. +# +# Note: +# You may need to adapt the number of cycles for your device. +# +add_help_text cortex_m_test_cpu_speed "Measure the CPU clock frequency of an ARM Cortex-M based device" +add_usage_text cortex_m_test_cpu_speed {address [timeout [cycles_per_loop]]} +proc cortex_m_test_cpu_speed { address { timeout 200 } { cycles_per_loop 4 } } { + set loop_counter_start 0xffffffff + + halt + + # Backup registers and memory. + 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 + # CPU clock frequency: + # + # 3801: subs r0, #1 + # d1fd: bne #-2 + # e7fe: b #-4 + write_memory $address 16 {0x3801 0xd1fd 0xe7fe} + + set_reg "pc $address r0 $loop_counter_start" + resume + sleep $timeout + halt + + # Get the loop counter value from register r0. + set loop_counter_end [dict values [get_reg r0]] + set loop_counter_diff [expr {$loop_counter_start - $loop_counter_end}] + + # Restore registers and memory. + set_reg $backup_regs + write_memory $address 16 $backup_mem + + if { [expr {$loop_counter_end == 0}] } { + return -1 + } + + return [expr {double($loop_counter_diff) * $cycles_per_loop / $timeout * 1000}] +} diff --git a/testing/build.test1/Makefile b/testing/build.test1/Makefile deleted file mode 100644 index 02b7523077..0000000000 --- a/testing/build.test1/Makefile +++ /dev/null @@ -1,95 +0,0 @@ -# -*- mode: makefile -*- -# -default: _complain_ -include ./local.uses - -%: _complain_ - - -_complain_: - @echo "" - @echo " Try the target: cygwin.buildtest or linux.buildtest " - @echo "" - -remove.install: - rm -rf ${INSTALL_DIR} - -.PHONY: remove.install - -cygwin.buildtest: - ${MAKE} -f Makefile.ftd2xx clean all - ${MAKE} -f Makefile.openocd cygwin.easy.permutations - ${MAKE} -f Makefile.openocd mingw32.easy.permutations - ${MAKE} -f Makefile.libftdi all - ${MAKE} -f Makefile.openocd cygwin.libftdi - -linux.buildtest: - ${MAKE} linux.easy.buildtest - ${MAKE} linux.ftd2xx_installed - ${MAKE} linux.ft2232_libftdi - @echo "" - @echo "" - @echo "========================================" - @echo " Linux Build Tests Complete " - @echo "========================================" - @echo "" - @echo "" - - -linux.easy.buildtest: - @test -d openocd || (echo "Where the source to openocd?" && exit 1) - ${MAKE} -f Makefile.openocd bootstrap - ${MAKE} -f Makefile.ftd2xx all - ${MAKE} -f Makefile.openocd linux.easy.permutations - -linux.ftd2xx_installed: - ${MAKE} remove.install - ${MAKE} linux.ftd2xx_installed.setup - ${MAKE} -f Makefile.openocd $@ - - linux.ft2232_libftdi: - ${MAKE} remove.install - ${MAKE} -f Makefile.libusb all - ${MAKE} -f Makefile.confuse all - ${MAKE} -f Makefile.libftdi all - ${MAKE} -f Makefile.openocd $@ - -# This target is used to "install" files from -# the FTDICHIP.COM tar.gz unpack directory -# into "a proper place" - where they should be found. -linux.ftd2xx_installed.setup: - mkdir -p ${INSTALL_DIR}/include - mkdir -p ${EXEC_PREFIX}/lib - @# - @# Sanity check - make sure the .H file is findable - @# - @f=$(FTD2XX_LINUX_DIR)/ftd2xx.h && \ - test -f $$f || (echo "Error: $$f not found" ; exit 1) - @# - @# Header files are simple... just copy them. - @# - cp $(FTD2XX_LINUX_DIR)/ftd2xx.h $(PREFIX)/include/. - cp $(FTD2XX_LINUX_DIR)/WinTypes.h $(PREFIX)/include/. - @# - @# .SO files are harder. - @# (1) copy them, (2) make links - @# - cp $(FTD2XX_LINUX_DIR)/libftd2xx.so.$(FTD2XX_LINUX_VERSION) $(EXEC_PREFIX)/lib/. - cd $(EXEC_PREFIX)/lib && rm -f libftd2xx.so.0 - cd $(EXEC_PREFIX)/lib && ln -s libftd2xx.so.$(FTD2XX_LINUX_VERSION) libftd2xx.so.0 - cd $(EXEC_PREFIX)/lib && rm -f libftd2xx.so - cd $(EXEC_PREFIX)/lib && ln -s libftd2xx.so.$(FTD2XX_LINUX_VERSION) libftd2xx.so - - -all.download: - mkdir -p ${VIRGINS} - ${MAKE} -f Makefile.confuse download - ${MAKE} -f Makefile.libftdi download - ${MAKE} -f Makefile.ftd2xx download - ${MAKE} -f Makefile.libusb download - -.PHONY: linux.buildtest \ - linux.easy.buildtest \ - linux.ftd2xx_installed \ - linux.ft22232_libftdi \ - linux.ftd2xx_installed.setup diff --git a/testing/build.test1/Makefile.confuse b/testing/build.test1/Makefile.confuse deleted file mode 100644 index 9d5a0673f8..0000000000 --- a/testing/build.test1/Makefile.confuse +++ /dev/null @@ -1,46 +0,0 @@ -# -*- mode: makefile -*- -default: _complain_ -include ./local.uses - -TARFILE_LOCAL=${VIRGINS}/confuse-${LIBCONFUSE_VERSION}.tar.gz -TARFILE_URL =http://www.intra2net.com/de/produkte/opensource/ftdi/TGZ/confuse-${LIBCONFUSE_VERSION}.tar.gz - -CONFUSE_SRC_DIR =${HERE}/confuse-${LIBCONFUSE_VERSION} -CONFUSE_BUILD_DIR =${HERE}/confuse-build - -download: - wget -O ${TARFILE_LOCAL} ${TARFILE_URL} - -unpack: - rm -rf ${CONFUSE_SRC_DIR} - tar xfz ${TARFILE_LOCAL} - -clean:: - rm -rf ${CONFUSE_SRC_DIR} - -configure: - rm -rf ${CONFUSE_BUILD_DIR} - mkdir ${CONFUSE_BUILD_DIR} - cd ${CONFUSE_BUILD_DIR} && ${CONFUSE_SRC_DIR}/configure \ - --prefix=${PREFIX} \ - --exec-prefix=${EXEC_PREFIX} - -clean:: - rm -rf ${CONFUSE_BUILD_DIR} - -build: - cd ${CONFUSE_BUILD_DIR} && ${MAKE} - -install: - cd ${CONFUSE_BUILD_DIR} && ${MAKE} install - -all: unpack configure build install - -_complain_: - @echo "" - @echo "Please try one of these targets: bootstrap, clean, configure, build, install" - @echo " Or read the makefile and learn about the permutation test targets" - @echo "" - @echo "You also might find the download and unpack targets helpful." - @echo "" - @exit 1 diff --git a/testing/build.test1/Makefile.ftd2xx b/testing/build.test1/Makefile.ftd2xx deleted file mode 100644 index 3f19e7720d..0000000000 --- a/testing/build.test1/Makefile.ftd2xx +++ /dev/null @@ -1,88 +0,0 @@ -# -*- mode: makefile -*- -# -default: _complain_ - -include ./local.uses - -# WARNING... the file on the ftdi chip site has a SPACE in the filename GRRR!!! -# We fix that with the "-O" option to wget. -ZIPFILE_LOCAL=${VIRGINS}/cdm.${FTD2XX_WIN32_VERSION}.zip -ZIPFILE_URL ="http://www.ftdichip.com/Drivers/CDM/CDM ${FTD2XX_WIN32_VERSION}.zip" - -TARFILE_LOCAL=${VIRGINS}/libftd2xx${FTD2XX_LINUX_VERSION}.tar.gz -TARFILE_URL =http://www.ftdichip.com/Drivers/D2XX/Linux/libftd2xx${FTD2XX_LINUX_VERSION}.tar.gz - -TARFILE_64_LOCAL=${VIRGINS}/libftd2xx${FTD2XX_LINUX_VERSION}_x86_64.tar.gz -TARFILE_64_URL =http://www.ftdichip.com/Drivers/D2XX/Linux/libftd2xx${FTD2XX_LINUX_VERSION}_x86_64.tar.gz - - -download.win32: - mkdir -p ${VIRGINS} - wget -O ${ZIPFILE_LOCAL} ${ZIPFILE_URL} - -unpack.win32: - rm -rf ${FTD2XX_WIN32_DIR} - mkdir -p ${FTD2XX_WIN32_DIR} - cd ${FTD2XX_WIN32_DIR} && unzip ${ZIPFILE_LOCAL} - -clean:: - rm -rf ${FTD2XX_WIN32_DIR} - -download.linux: - mkdir -p ${VIRGINS} - wget -O ${TARFILE_LOCAL} ${TARFILE_URL} - -clean:: - rm -rf ${FTD2XX_LINUX_DIR} - -unpack.linux: - rm -rf ${FTD2XX_LINUX_DIR} - mkdir -p ${FTD2XX_LINUX_DIR} - tar xfz ${TARFILE_LOCAL} - -download.linux.x86_64: - mkdir -p ${VIRGINS} - wget -O ${TARFILE_LOCAL} ${TARFILE_URL} - -unpack.linux.x86_64: - rm -rf ${FTD2XX_LINUX_64_DIR} - mkdir -p ${FTD2XX_LINUX_64_DIR} - tar xfz ${TARFILE_64_LOCAL} - -clean:: - rm -rf ${FTD2XX_LINUX_64_DIR} - -download: download.win32 download.linux - -unpack.cygwin unpack.mingw32: unpack.win32 - -unpack: unpack.${BUILD_SYSNAME} - -# Nothing to do here -build: - @echo "Done" - -#Nothing to do here -configure: - @echo "Done" - -# Nothing to do here -install: - @echo "Done" - -all: unpack configure build install - -.PHONY: install - -# Nothing to do here -clean:: - @echo "Done" - -_complain_: - @echo "" - @echo "Please try one of these targets: bootstrap, clean, configure, build, install" - @echo " Or read the makefile and learn about the permutation test targets" - @echo "" - @echo "You also might find the download and unpack targets helpful." - @echo "" - @exit 1 diff --git a/testing/build.test1/Makefile.libftdi b/testing/build.test1/Makefile.libftdi deleted file mode 100644 index 1a9612c053..0000000000 --- a/testing/build.test1/Makefile.libftdi +++ /dev/null @@ -1,51 +0,0 @@ -# -*- mode: makefile -*- -default: _complain_ -include ./local.uses - -TARFILE_LOCAL = ${VIRGINS}/libftdi-${LIBFTDI_VERSION}.tar.gz -TARFILE_URL = http://www.intra2net.com/de/produkte/opensource/ftdi/TGZ/libftdi-${LIBFTDI_VERSION}.tar.gz - -LIBFTDI_SRC_DIR = ${HERE}/libftdi-${LIBFTDI_VERSION} -LIBFTDI_BUILD_DIR= ${HERE}/libftdi-build - -download: - mkdir -p virgins - wget -O ${TARFILE_LOCAL} ${TARFILE_URL} - -clean:: - rm -rf ${LIBFTDI_SRC_DIR} - -unpack: - tar xf ${TARFILE_LOCAL} - -PATH := ${EXEC_PREFIX}/bin:${PATH} -export PATH - -clean:: - rm -rf ${LIBFTDI_BUILD_DIR} - -configure: - rm -rf ${LIBFTDI_BUILD_DIR} - mkdir -p ${LIBFTDI_BUILD_DIR} - cd ${LIBFTDI_BUILD_DIR} && ${LIBFTDI_SRC_DIR}/configure \ - --prefix=${PREFIX} \ - --exec-prefix=${EXEC_PREFIX} - -build: - cd ${LIBFTDI_BUILD_DIR} && ${MAKE} - -install: - cd ${LIBFTDI_BUILD_DIR} && ${MAKE} install - -all: unpack configure build install - -.PHONY: install - -_complain_: - @echo "" - @echo "Please try one of these targets: bootstrap, clean, configure, build, install" - @echo " Or read the makefile and learn about the permutation test targets" - @echo "" - @echo "You also might find the download and unpack targets helpful." - @echo "" - @exit 1 diff --git a/testing/build.test1/Makefile.libusb b/testing/build.test1/Makefile.libusb deleted file mode 100644 index 815592a189..0000000000 --- a/testing/build.test1/Makefile.libusb +++ /dev/null @@ -1,55 +0,0 @@ -# -*- mode: makefile -*- -default: _complain_ - -include ./local.uses - -ifeq (x"$BUILD_SYSNAME",x"cygwin") -$(error Please use the Win32 specific port of LibUSB not the Unix version) -endif -ifeq (x"$BUILD_SYSNAME",x"mingw32") -$(error Please use the win32 specific port of LibUSB not the Unix version) -endif - -TARFILE_LOCAL = ${VIRGINS}/libusb-${LIBUSB_VERSION_linux}.tar.bz2 -TARFILE_URL = http://downloads.sourceforge.net/libusb/libusb-${LIBUSB_VERSION_linux}.tar.gz - -LIBUSB_SRC_DIR = ${HERE}/libusb-${LIBUSB_VERSION} -LIBUSB_BUILD_DIR = ${HERE}/libusb-build - -download: - wget -O ${TARFILE_LOCAL} ${TARFILE_URL} - -unpack: - rm -rf ${LIBUSB_SRC_DIR} - tar xfz ${TARFILE_LOCAL} - -clean:: - rm -rf ${LIBUSB_SRC_DIR} - -configure: - rm -rf ${LIBUSB_BUILD_DIR} - mkdir -p ${LIBUSB_BUILD_DIR} - cd ${LIBUSB_BUILD_DIR} && ${LIBUSB_SRC_DIR}/configure \ - --prefix=${PREFIX} --exec-prefix=${EXEC_PREFIX} - -clean:: - rm -rf ${LIBUSB_BUILD_DIR} - -build: - cd ${LIBUSB_BUILD_DIR} && ${MAKE} - -install: - cd ${LIBUSB_BUILD_DIR} && ${MAKE} install - -all: unpack configure build install - -.PHONY: install - -_complain_: - @echo "" - @echo "Please try one of these targets: bootstrap, clean, configure, build, install" - @echo " Or read the makefile and learn about the permutation test targets" - @echo "" - @echo "You also might find the download and unpack targets helpful." - @echo "" - @exit 1 diff --git a/testing/build.test1/Makefile.openocd b/testing/build.test1/Makefile.openocd deleted file mode 100644 index 6b0cb56ff0..0000000000 --- a/testing/build.test1/Makefile.openocd +++ /dev/null @@ -1,193 +0,0 @@ -# -*- mode: makefile -*- -# -default: _complain_ - -include ./local.uses - - -SRC_DIR ?= $(HERE)/openocd -BUILD_SUFFIX ?= $(BUILD_MACHINE) -BUILD_DIR =$(HERE)/openocd.$(BUILD_SUFFIX) - -checkout: - svn co https://svn.berlios.de/svnroot/repos/openocd/trunk openocd - -remove.install: - rm -rf ${INSTALL_DIR} - -#======================================== -# Win32 Build Permutations -# none -# parport -# ftd2xx - (ftdichip) -# libftd -CONFIG_OPTIONS_win32_none = -CONFIG_OPTIONS_win32_parport = --enable-parport -CONFIG_OPTIONS_win32_ftd2xx = --enable-parport --enable-ft2232_ftd2xx --with-ftd2xx-win32-zipdir=$(FTD2XX_WIN32_DIR) - -CYGWIN_EASY_PERMUTATIONS += none -CYGWIN_EASY_PERMUTATIONS += parport -CYGWIN_EASY_PERMUTATIONS += ftd2xx - -MINGW32_EASY_PERMUTATIONS += none -MINGW32_EASY_PERMUTATIONS += parport -MINGW32_EASY_PERMUTATIONS += ftd2xx - - -# This is not a possible permutation, it is manual :-( -# Why? Because "libftdi" installs things into install/include -# which would efect the 'ftd2xx' win32 build -CONFIG_OPTIONS_win32_libftdi = --enable-parport --enable-ft2232_libftdi - -# Default build for win32... is the ftd2xx type build. -PERMUTE_win32 ?= ftd2xx -CONFIG_OPTIONS_win32 ?= $(CONFIG_OPTIONS_win32_$(PERMUTE_win32)) -CONFIG_OPTIONS_cygwin = $(CONFIG_OPTIONS_win32) -CONFIG_OPTIONS_mingw32 = $(CONFIG_OPTIONS_win32) - -#======================================== -# Linux Build Permuatations -# none -# parport -# ft2232_ftd2xx -# ft2232_libftdi -CONFIG_OPTIONS_linux_none = -LINUX_EASY_PERMUTATIONS += none - -CONFIG_OPTIONS_linux_parport = --enable-parport -LINUX_EASY_PERMUTATIONS += parport - -CONFIG_OPTIONS_linux_ft2232_libftdi = --enable-parport --enable-ft2232-libftdi -#this cannot be done as part of the permutations. -#LINUX_EASY_PERMUTATIONS += ft2232_libftdi - -CONFIG_OPTIONS_linux_ft2232_ftd2xx_static = \ - --enable-parport \ - --enable-ft2232-ftd2xx --with-ftd2xx-lib=static --with-ftd2xx-linux-tardir=$(FTD2XX_LINUX_DIR) -LINUX_EASY_PERMUTATIONS += ft2232_ftd2xx_static - -# this is not a possible permutation it is manual :-( -# why? because it interfers with the other permutations -# by "installing files" in the $(INSTALL_DIR) -CONFIG_OPTIONS_linux_ftd2xx_installed = \ - --enable-parport \ - --enable-ft2232-ftd2xx \ - --with-ftd2xx-lib=shared - -# The default build permutation is -PERMUTE_linux ?= ft2232_ftd2xx_static -CONFIG_OPTIONS_linux = $(CONFIG_OPTIONS_linux_$(PERMUTE_linux)) - -CONFIG_OPTIONS_darwin=\ - --enable-ftd2232-libftdi - -# Which build are we doing? -CONFIG_OPTIONS := $(CONFIG_OPTIONS_$(BUILD_SYSNAME)) - -bootstrap: - cd $(SRC_DIR) && bash ./bootstrap - -clean:: - rm -rf $(BUILD_DIR) - -ifndef CFLAGS -_CFLAGS=true -else -_CFLAGS=export CFLAGS="${CFLAGS}" -endif - - -# if this was given... then pass it on -configure: - @echo " Build Sysname: $(BUILD_SYSNAME)" - @echo " Config Options: $(CONFIG_OPTIONS)" - rm -rf $(BUILD_DIR) - mkdir $(BUILD_DIR) - ${_CFLAGS} && \ - cd $(BUILD_DIR) && \ - $(SRC_DIR)/configure \ - --prefix=$(PREFIX) \ - --exec-prefix=$(EXEC_PREFIX) \ - $(CONFIG_OPTIONS) - -build: - cd $(BUILD_DIR) && $(MAKE) - -install: - cd $(BUILD_DIR) && $(MAKE) install - -all: configure build install - -.PHONY: install - -# The "cygwin.libftdi" requires that libftdi be built -# and installed *PRIOR* to running this target. -# it is not part of the permutations because ... -# it interfers with the ftd2xx based builds -cygwin.libftdi: - $(MAKE) -f Makefile.openocd bootstrap - $(MAKE) BUILD_SUFFIX=$@ PERMUTE_win32=libftdi -f Makefile.openocd all - -cygwin.easy.permutations: remove.install ${CYGWIN_EASY_PERMUTATIONS:%=_cygwin.%} - -_cygwin.%: - @echo "" - @echo "" - @echo "========================================" - @echo "Permutation Build... $@" - @echo "========================================" - @echo "" - @echo "" - $(MAKE) PERMUTE_win32=$* BUILD_SUFFIX=cygwin.$* -f Makefile.openocd all - $(EXEC_PREFIX)/bin/openocd -v - -mingw32.easy.permutations: remove.install ${MINGW32_EASY_PERMUTATIONS:%=_mingw32.%} - -# I (duane) build openocd-mingw32 via Cygwin. -# Sadly, the "mingw32" buid for cygwin does not include -# the required "elf.h" header files... so ... -# we have them in our own private helper place. -_mingw32.%: - @echo "" - @echo "" - @echo "========================================" - @echo "Permutation Build... $@" - @echo "========================================" - @echo "" - @echo "" - CFLAGS="-mno-cygwin -I$(HERE)/mingw32_help/include" \ - $(MAKE) -f Makefile.openocd all ;\ - $(EXEC_PREFIX)/bin/openocd -v - -win32.permutations: mingw32.permutations cygwin.permutations - - -# SMOKE TEST - Build every linux permuation... -# If "openocd -v" does exit(0) we are good enough. - -linux.easy.permutations: remove.install ${LINUX_EASY_PERMUTATIONS:%=_linux.%} - - -_linux.%: - @echo "" - @echo "" - @echo "========================================" - @echo "Permutation Build... $@" - @echo "========================================" - @echo "" - @echo "" - $(MAKE) PERMUTE_linux=$* BUILD_SUFFIX=linux.$* -f Makefile.openocd all - $(EXEC_PREFIX)/bin/openocd -v - -linux.ftd2xx_installed: - ${MAKE} -f Makefile.openocd _$@ - -linux.ft2232_libftdi: - ${MAKE} -f Makefile.openocd _$@ - -_complain_: - @echo "" - @echo "Please try one of these targets: bootstrap, clean, configure, build, install" - @echo " Or read the makefile and learn about the permutation test targets" - @echo "" - @exit 1 diff --git a/testing/build.test1/README.TXT b/testing/build.test1/README.TXT deleted file mode 100644 index 7f4d401e84..0000000000 --- a/testing/build.test1/README.TXT +++ /dev/null @@ -1,38 +0,0 @@ --- Duane Ellis'es test case for building numerous openocd configurations... -Dec 26,2008 ---------------------------------------------------------------------------- - -1) Make a directory some where.. - - mkdir ~/test - -2) Change to that directory - - cd ~/test - -3) Checkout OpenOCD in that directory. - - cd ~/test - svn co https://svn.berlios.de/svnroot/repos/openocd/trunk openocd - -4) Copy the "build.test1" directory to the "~/work" directory. - - - cd ~/test - cp ~/openocd/testing/build.test1/. ~/test/. - -5) If needed, download various components. - - cd ~/work - make all.download - - -6) For Linux - type: - - cd ~/work - make linux.buildtest - -7) For Cygwin - type: - - cd ~/work - make cygwin.buildtest diff --git a/testing/build.test1/local.uses b/testing/build.test1/local.uses deleted file mode 100644 index 6c6795b54c..0000000000 --- a/testing/build.test1/local.uses +++ /dev/null @@ -1,39 +0,0 @@ -# -*- mode: makefile -*- -HERE := $(shell pwd) - -# Solve problems on systems with DASH.. Grrr... -SHELL=/bin/bash -export SHELL - -VIRGINS=${HERE}/virgins - -# Determine the build platform. -BUILD_SYSNAME_Linux =linux -BUILD_SYSNAME_linux =linux -BUILD_SYSNAME_CYGWIN_NT =cygwin -BUILD_SYSNAME_MINGW32_NT =mingw32 -BUILD_SYSNAME_Darwin =darwin -BUILD_SYSNAME_darwin =darwin -BUILD_SYSNAME :=$(BUILD_SYSNAME_$(shell uname --sysname | cut -d'-' -f1)) - -# And machine (ie: i686, x86_64, or what) -BUILD_MACHINE :=$(BUILD_SYSNAME).$(shell uname -m) - - -INSTALL_DIR := $(HERE)/install -PREFIX := ${INSTALL_DIR} -EXEC_PREFIX := ${INSTALL_DIR}/${BUILD_MACHINE} - -LIBFTDI_VERSION=0.14 -LIBCONFUSE_VERSION=2.5 - -LIBUSB_VERSION_linux=0.1.12 - -LIBUSB_VERSION=${LIBUSB_VERSION_${BUILD_SYSNAME}} - -FTD2XX_WIN32_VERSION=2.04.14 -FTD2XX_WIN32_DIR = ${HERE}/ftd2xx.win32 - -FTD2XX_LINUX_VERSION=0.4.16 -FTD2XX_LINUX_DIR = ${HERE}/libftd2xx${FTD2XX_LINUX_VERSION} -FTD2XX_LINUX_64_DIR = ${HERE}/libftd2xx${FTD2XX_LINUX_VERSION}_x86_64 diff --git a/testing/build.test1/mingw32_help/include/elf.h b/testing/build.test1/mingw32_help/include/elf.h deleted file mode 100644 index 23d4aa2d56..0000000000 --- a/testing/build.test1/mingw32_help/include/elf.h +++ /dev/null @@ -1,38 +0,0 @@ -/* elf.h - - Copyright 2005 Red Hat, Inc. - -This file is part of Cygwin. - -This software is a copyrighted work licensed under the terms of the -Cygwin license. Please consult the file "CYGWIN_LICENSE" for -details. */ - -#ifndef _ELF_H_ -#define _ELF_H_ - -#include <stdint.h> - -typedef signed char int8_t; -typedef unsigned char u_int8_t; -typedef short int16_t; -typedef unsigned short u_int16_t; -typedef int int32_t; -typedef unsigned int u_int32_t; -typedef long long int64_t; -typedef unsigned long long u_int64_t; -typedef int32_t register_t; - - -#ifdef __cplusplus -extern "C" { -#endif -#include <sys/types.h> -#include <sys/elf32.h> -#include <sys/elf64.h> -#include <sys/elf_generic.h> -#ifdef __cplusplus -} -#endif - -#endif /*_ELF_H_*/ diff --git a/testing/build.test1/mingw32_help/include/sys/cdefs.h b/testing/build.test1/mingw32_help/include/sys/cdefs.h deleted file mode 100644 index 606205a586..0000000000 --- a/testing/build.test1/mingw32_help/include/sys/cdefs.h +++ /dev/null @@ -1,22 +0,0 @@ -/* sys/cdefs.h - - Copyright 1998, 2000, 2001 Red Hat, Inc. - -This file is part of Cygwin. - -This software is a copyrighted work licensed under the terms of the -Cygwin license. Please consult the file "CYGWIN_LICENSE" for -details. */ - -#ifndef _SYS_CDEFS_H -#define _SYS_CDEFS_H -#ifdef __cplusplus -#define __BEGIN_DECLS extern "C" { -#define __END_DECLS } -#else -#define __BEGIN_DECLS -#define __END_DECLS -#endif -#define __P(protos) protos /* full-blown ANSI C */ -#define __CONCAT(__x,__y) __x##__y -#endif diff --git a/testing/build.test1/mingw32_help/include/sys/elf32.h b/testing/build.test1/mingw32_help/include/sys/elf32.h deleted file mode 100644 index 5dfe9c8b05..0000000000 --- a/testing/build.test1/mingw32_help/include/sys/elf32.h +++ /dev/null @@ -1,156 +0,0 @@ -/*- - * Copyright (c) 1996-1998 John D. Polstra. - * 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 AUTHOR 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 AUTHOR 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. - * - * $FreeBSD: src/sys/sys/elf32.h,v 1.8 2002/05/30 08:32:18 dfr Exp $ - */ - -#ifndef _SYS_ELF32_H_ -#define _SYS_ELF32_H_ 1 - -#include <sys/elf_common.h> - -/* - * ELF definitions common to all 32-bit architectures. - */ - -typedef u_int32_t Elf32_Addr; -typedef u_int16_t Elf32_Half; -typedef u_int32_t Elf32_Off; -typedef int32_t Elf32_Sword; -typedef u_int32_t Elf32_Word; -typedef u_int32_t Elf32_Size; -typedef Elf32_Off Elf32_Hashelt; - -/* - * ELF header. - */ - -typedef struct { - unsigned char e_ident[EI_NIDENT]; /* File identification. */ - Elf32_Half e_type; /* File type. */ - Elf32_Half e_machine; /* Machine architecture. */ - Elf32_Word e_version; /* ELF format version. */ - Elf32_Addr e_entry; /* Entry point. */ - Elf32_Off e_phoff; /* Program header file offset. */ - Elf32_Off e_shoff; /* Section header file offset. */ - Elf32_Word e_flags; /* Architecture-specific flags. */ - Elf32_Half e_ehsize; /* Size of ELF header in bytes. */ - Elf32_Half e_phentsize; /* Size of program header entry. */ - Elf32_Half e_phnum; /* Number of program header entries. */ - Elf32_Half e_shentsize; /* Size of section header entry. */ - Elf32_Half e_shnum; /* Number of section header entries. */ - Elf32_Half e_shstrndx; /* Section name strings section. */ -} Elf32_Ehdr; - -/* - * Section header. - */ - -typedef struct { - Elf32_Word sh_name; /* Section name (index into the - section header string table). */ - Elf32_Word sh_type; /* Section type. */ - Elf32_Word sh_flags; /* Section flags. */ - Elf32_Addr sh_addr; /* Address in memory image. */ - Elf32_Off sh_offset; /* Offset in file. */ - Elf32_Size sh_size; /* Size in bytes. */ - Elf32_Word sh_link; /* Index of a related section. */ - Elf32_Word sh_info; /* Depends on section type. */ - Elf32_Size sh_addralign; /* Alignment in bytes. */ - Elf32_Size sh_entsize; /* Size of each entry in section. */ -} Elf32_Shdr; - -/* - * Program header. - */ - -typedef struct { - Elf32_Word p_type; /* Entry type. */ - Elf32_Off p_offset; /* File offset of contents. */ - Elf32_Addr p_vaddr; /* Virtual address in memory image. */ - Elf32_Addr p_paddr; /* Physical address (not used). */ - Elf32_Size p_filesz; /* Size of contents in file. */ - Elf32_Size p_memsz; /* Size of contents in memory. */ - Elf32_Word p_flags; /* Access permission flags. */ - Elf32_Size p_align; /* Alignment in memory and file. */ -} Elf32_Phdr; - -/* - * Dynamic structure. The ".dynamic" section contains an array of them. - */ - -typedef struct { - Elf32_Sword d_tag; /* Entry type. */ - union { - Elf32_Size d_val; /* Integer value. */ - Elf32_Addr d_ptr; /* Address value. */ - } d_un; -} Elf32_Dyn; - -/* - * Relocation entries. - */ - -/* Relocations that don't need an addend field. */ -typedef struct { - Elf32_Addr r_offset; /* Location to be relocated. */ - Elf32_Word r_info; /* Relocation type and symbol index. */ -} Elf32_Rel; - -/* Relocations that need an addend field. */ -typedef struct { - Elf32_Addr r_offset; /* Location to be relocated. */ - Elf32_Word r_info; /* Relocation type and symbol index. */ - Elf32_Sword r_addend; /* Addend. */ -} Elf32_Rela; - -/* Macros for accessing the fields of r_info. */ -#define ELF32_R_SYM(info) ((info) >> 8) -#define ELF32_R_TYPE(info) ((unsigned char)(info)) - -/* Macro for constructing r_info from field values. */ -#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) - -/* - * Symbol table entries. - */ - -typedef struct { - Elf32_Word st_name; /* String table index of name. */ - Elf32_Addr st_value; /* Symbol value. */ - Elf32_Size st_size; /* Size of associated object. */ - unsigned char st_info; /* Type and binding information. */ - unsigned char st_other; /* Reserved (not used). */ - Elf32_Half st_shndx; /* Section index of symbol. */ -} Elf32_Sym; - -/* Macros for accessing the fields of st_info. */ -#define ELF32_ST_BIND(info) ((info) >> 4) -#define ELF32_ST_TYPE(info) ((info) & 0xf) - -/* Macro for constructing st_info from field values. */ -#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) - -#endif /* !_SYS_ELF32_H_ */ diff --git a/testing/build.test1/mingw32_help/include/sys/elf64.h b/testing/build.test1/mingw32_help/include/sys/elf64.h deleted file mode 100644 index 48556be5f6..0000000000 --- a/testing/build.test1/mingw32_help/include/sys/elf64.h +++ /dev/null @@ -1,172 +0,0 @@ -/*- - * Copyright (c) 1996-1998 John D. Polstra. - * 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 AUTHOR 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 AUTHOR 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. - * - * $FreeBSD: src/sys/sys/elf64.h,v 1.10 2002/05/30 08:32:18 dfr Exp $ - */ - -#ifndef _SYS_ELF64_H_ -#define _SYS_ELF64_H_ 1 - -#include <sys/elf_common.h> - -/* - * ELF definitions common to all 64-bit architectures. - */ - -typedef uint64_t Elf64_Addr; -typedef uint16_t Elf64_Half; -typedef uint32_t Elf64_Word; -typedef int32_t Elf64_Sword; -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; -typedef uint64_t Elf64_Off; -typedef uint16_t Elf64_Section; -typedef Elf64_Half Elf64_Versym; -typedef uint16_t Elf64_Quarter; - -/* - * Types of dynamic symbol hash table bucket and chain elements. - * - * This is inconsistent among 64 bit architectures, so a machine dependent - * typedef is required. - */ - -#ifdef __alpha__ -typedef Elf64_Off Elf64_Hashelt; -#else -typedef Elf64_Half Elf64_Hashelt; -#endif - -/* - * ELF header. - */ - -typedef struct { - unsigned char e_ident[EI_NIDENT]; /* File identification. */ - Elf64_Half e_type; /* File type. */ - Elf64_Half e_machine; /* Machine architecture. */ - Elf64_Word e_version; /* ELF format version. */ - Elf64_Addr e_entry; /* Entry point. */ - Elf64_Off e_phoff; /* Program header file offset. */ - Elf64_Off e_shoff; /* Section header file offset. */ - Elf64_Word e_flags; /* Architecture-specific flags. */ - Elf64_Half e_ehsize; /* Size of ELF header in bytes. */ - Elf64_Half e_phentsize; /* Size of program header entry. */ - Elf64_Half e_phnum; /* Number of program header entries. */ - Elf64_Half e_shentsize; /* Size of section header entry. */ - Elf64_Half e_shnum; /* Number of section header entries. */ - Elf64_Half e_shstrndx; /* Section name strings section. */ -} Elf64_Ehdr; - -/* - * Section header. - */ - -typedef struct { - Elf64_Word sh_name; /* Section name (index into the - section header string table). */ - Elf64_Word sh_type; /* Section type. */ - Elf64_Xword sh_flags; /* Section flags. */ - Elf64_Addr sh_addr; /* Address in memory image. */ - Elf64_Off sh_offset; /* Offset in file. */ - Elf64_Xword sh_size; /* Size in bytes. */ - Elf64_Word sh_link; /* Index of a related section. */ - Elf64_Word sh_info; /* Depends on section type. */ - Elf64_Xword sh_addralign; /* Alignment in bytes. */ - Elf64_Xword sh_entsize; /* Size of each entry in section. */ -} Elf64_Shdr; - -/* - * Program header. - */ - -typedef struct { - Elf64_Word p_type; /* Entry type. */ - Elf64_Word p_flags; /* Access permission flags. */ - Elf64_Off p_offset; /* File offset of contents. */ - Elf64_Addr p_vaddr; /* Virtual address in memory image. */ - Elf64_Addr p_paddr; /* Physical address (not used). */ - Elf64_Xword p_filesz; /* Size of contents in file. */ - Elf64_Xword p_memsz; /* Size of contents in memory. */ - Elf64_Xword p_align; /* Alignment in memory and file. */ -} Elf64_Phdr; - -/* - * Dynamic structure. The ".dynamic" section contains an array of them. - */ - -typedef struct { - Elf64_Sxword d_tag; /* Entry type. */ - union { - Elf64_Xword d_val; /* Integer value. */ - Elf64_Addr d_ptr; /* Address value. */ - } d_un; -} Elf64_Dyn; - -/* - * Relocation entries. - */ - -/* Relocations that don't need an addend field. */ -typedef struct { - Elf64_Addr r_offset; /* Location to be relocated. */ - Elf64_Xword r_info; /* Relocation type and symbol index. */ -} Elf64_Rel; - -/* Relocations that need an addend field. */ -typedef struct { - Elf64_Addr r_offset; /* Location to be relocated. */ - Elf64_Xword r_info; /* Relocation type and symbol index. */ - Elf64_Sxword r_addend; /* Addend. */ -} Elf64_Rela; - -/* Macros for accessing the fields of r_info. */ -#define ELF64_R_SYM(info) ((info) >> 32) -#define ELF64_R_TYPE(info) ((unsigned char)(info)) - -/* Macro for constructing r_info from field values. */ -#define ELF64_R_INFO(sym, type) (((sym) << 32) + (unsigned char)(type)) - -/* - * Symbol table entries. - */ - -typedef struct { - Elf64_Word st_name; /* String table index of name. */ - unsigned char st_info; /* Type and binding information. */ - unsigned char st_other; /* Reserved (not used). */ - Elf64_Section st_shndx; /* Section index of symbol. */ - Elf64_Addr st_value; /* Symbol value. */ - Elf64_Xword st_size; /* Size of associated object. */ -} Elf64_Sym; - -/* Macros for accessing the fields of st_info. */ -#define ELF64_ST_BIND(info) ((info) >> 4) -#define ELF64_ST_TYPE(info) ((info) & 0xf) - -/* Macro for constructing st_info from field values. */ -#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) - -#endif /* !_SYS_ELF64_H_ */ diff --git a/testing/build.test1/mingw32_help/include/sys/elf_common.h b/testing/build.test1/mingw32_help/include/sys/elf_common.h deleted file mode 100644 index b864f0464f..0000000000 --- a/testing/build.test1/mingw32_help/include/sys/elf_common.h +++ /dev/null @@ -1,299 +0,0 @@ -/*- - * Copyright (c) 1998 John D. Polstra. - * 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 AUTHOR 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 AUTHOR 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. - * - * $FreeBSD: src/sys/sys/elf_common.h,v 1.15 2004/05/05 02:38:54 marcel Exp $ - */ - -#ifndef _SYS_ELF_COMMON_H_ -#define _SYS_ELF_COMMON_H_ 1 - -/* - * ELF definitions that are independent of architecture or word size. - */ - -/* - * Note header. The ".note" section contains an array of notes. Each - * begins with this header, aligned to a word boundary. Immediately - * following the note header is n_namesz bytes of name, padded to the - * next word boundary. Then comes n_descsz bytes of descriptor, again - * padded to a word boundary. The values of n_namesz and n_descsz do - * not include the padding. - */ - -typedef struct { - u_int32_t n_namesz; /* Length of name. */ - u_int32_t n_descsz; /* Length of descriptor. */ - u_int32_t n_type; /* Type of this note. */ -} Elf_Note; - -/* Indexes into the e_ident array. Keep synced with - http://www.sco.com/developer/gabi/ch4.eheader.html */ -#define EI_MAG0 0 /* Magic number, byte 0. */ -#define EI_MAG1 1 /* Magic number, byte 1. */ -#define EI_MAG2 2 /* Magic number, byte 2. */ -#define EI_MAG3 3 /* Magic number, byte 3. */ -#define EI_CLASS 4 /* Class of machine. */ -#define EI_DATA 5 /* Data format. */ -#define EI_VERSION 6 /* ELF format version. */ -#define EI_OSABI 7 /* Operating system / ABI identification */ -#define EI_ABIVERSION 8 /* ABI version */ -#define OLD_EI_BRAND 8 /* Start of architecture identification. */ -#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ -#define EI_NIDENT 16 /* Size of e_ident array. */ - -/* Values for the magic number bytes. */ -#define ELFMAG0 0x7f -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' -#define ELFMAG "\177ELF" /* magic string */ -#define SELFMAG 4 /* magic string size */ - -/* Values for e_ident[EI_VERSION] and e_version. */ -#define EV_NONE 0 -#define EV_CURRENT 1 - -/* Values for e_ident[EI_CLASS]. */ -#define ELFCLASSNONE 0 /* Unknown class. */ -#define ELFCLASS32 1 /* 32-bit architecture. */ -#define ELFCLASS64 2 /* 64-bit architecture. */ - -/* Values for e_ident[EI_DATA]. */ -#define ELFDATANONE 0 /* Unknown data format. */ -#define ELFDATA2LSB 1 /* 2's complement little-endian. */ -#define ELFDATA2MSB 2 /* 2's complement big-endian. */ - -/* Values for e_ident[EI_OSABI]. */ -#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ -#define ELFOSABI_NONE ELFOSABI_SYSV /* symbol used in old spec */ -#define ELFOSABI_HPUX 1 /* HP-UX operating system */ -#define ELFOSABI_NETBSD 2 /* NetBSD */ -#define ELFOSABI_LINUX 3 /* GNU/Linux */ -#define ELFOSABI_HURD 4 /* GNU/Hurd */ -#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ -#define ELFOSABI_SOLARIS 6 /* Solaris */ -#define ELFOSABI_MONTEREY 7 /* Monterey */ -#define ELFOSABI_IRIX 8 /* IRIX */ -#define ELFOSABI_FREEBSD 9 /* FreeBSD */ -#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ -#define ELFOSABI_MODESTO 11 /* Novell Modesto */ -#define ELFOSABI_OPENBSD 12 /* OpenBSD */ -#define ELFOSABI_ARM 97 /* ARM */ -#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ - -/* e_ident */ -#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ - (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ - (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ - (ehdr).e_ident[EI_MAG3] == ELFMAG3) - -/* Values for e_type. */ -#define ET_NONE 0 /* Unknown type. */ -#define ET_REL 1 /* Relocatable. */ -#define ET_EXEC 2 /* Executable. */ -#define ET_DYN 3 /* Shared object. */ -#define ET_CORE 4 /* Core file. */ - -/* Values for e_machine. */ -#define EM_NONE 0 /* Unknown machine. */ -#define EM_M32 1 /* AT&T WE32100. */ -#define EM_SPARC 2 /* Sun SPARC. */ -#define EM_386 3 /* Intel i386. */ -#define EM_68K 4 /* Motorola 68000. */ -#define EM_88K 5 /* Motorola 88000. */ -#define EM_486 6 /* Intel i486. */ -#define EM_860 7 /* Intel i860. */ -#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ - -/* Extensions. This list is not complete. */ -#define EM_S370 9 /* IBM System/370 */ -#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ /* Depreciated */ -#define EM_PARISC 15 /* HPPA */ -#define EM_SPARC32PLUS 18 /* SPARC v8plus */ -#define EM_PPC 20 /* PowerPC 32-bit */ -#define EM_PPC64 21 /* PowerPC 64-bit */ -#define EM_ARM 40 /* ARM */ -#define EM_SPARCV9 43 /* SPARC v9 64-bit */ -#define EM_IA_64 50 /* Intel IA-64 Processor */ -#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ -#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI */ - -/* Special section indexes. */ -#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ -#define SHN_LORESERVE 0xff00 /* First of reserved range. */ -#define SHN_LOPROC 0xff00 /* First processor-specific. */ -#define SHN_HIPROC 0xff1f /* Last processor-specific. */ -#define SHN_ABS 0xfff1 /* Absolute values. */ -#define SHN_COMMON 0xfff2 /* Common data. */ -#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ - -/* sh_type */ -#define SHT_NULL 0 /* inactive */ -#define SHT_PROGBITS 1 /* program defined information */ -#define SHT_SYMTAB 2 /* symbol table section */ -#define SHT_STRTAB 3 /* string table section */ -#define SHT_RELA 4 /* relocation section with addends */ -#define SHT_HASH 5 /* symbol hash table section */ -#define SHT_DYNAMIC 6 /* dynamic section */ -#define SHT_NOTE 7 /* note section */ -#define SHT_NOBITS 8 /* no space section */ -#define SHT_REL 9 /* relocation section - no addends */ -#define SHT_SHLIB 10 /* reserved - purpose unknown */ -#define SHT_DYNSYM 11 /* dynamic symbol table section */ -#define SHT_NUM 12 /* number of section types */ -#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ -#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ -#define SHT_LOPROC 0x70000000 /* reserved range for processor */ -#define SHT_HIPROC 0x7fffffff /* specific section header types */ -#define SHT_LOUSER 0x80000000 /* reserved range for application */ -#define SHT_HIUSER 0xffffffff /* specific indexes */ - -/* Flags for sh_flags. */ -#define SHF_WRITE 0x1 /* Section contains writable data. */ -#define SHF_ALLOC 0x2 /* Section occupies memory. */ -#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ -#define SHF_TLS 0x400 /* Section contains TLS data. */ -#define SHF_MASKPROC 0xf0000000 /* Reserved for processor-specific. */ - -/* Values for p_type. */ -#define PT_NULL 0 /* Unused entry. */ -#define PT_LOAD 1 /* Loadable segment. */ -#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ -#define PT_INTERP 3 /* Pathname of interpreter. */ -#define PT_NOTE 4 /* Auxiliary information. */ -#define PT_SHLIB 5 /* Reserved (not used). */ -#define PT_PHDR 6 /* Location of program header itself. */ -#define PT_TLS 7 /* Thread local storage segment */ - -#define PT_COUNT 8 /* Number of defined p_type values. */ - -#define PT_LOOS 0x60000000 /* OS-specific */ -#define PT_HIOS 0x6fffffff /* OS-specific */ -#define PT_LOPROC 0x70000000 /* First processor-specific type. */ -#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ - -/* Values for p_flags. */ -#define PF_X 0x1 /* Executable. */ -#define PF_W 0x2 /* Writable. */ -#define PF_R 0x4 /* Readable. */ - -/* Values for d_tag. */ -#define DT_NULL 0 /* Terminating entry. */ -#define DT_NEEDED 1 /* String table offset of a needed shared - library. */ -#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ -#define DT_PLTGOT 3 /* Processor-dependent address. */ -#define DT_HASH 4 /* Address of symbol hash table. */ -#define DT_STRTAB 5 /* Address of string table. */ -#define DT_SYMTAB 6 /* Address of symbol table. */ -#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ -#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ -#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ -#define DT_STRSZ 10 /* Size of string table. */ -#define DT_SYMENT 11 /* Size of each symbol table entry. */ -#define DT_INIT 12 /* Address of initialization function. */ -#define DT_FINI 13 /* Address of finalization function. */ -#define DT_SONAME 14 /* String table offset of shared object - name. */ -#define DT_RPATH 15 /* String table offset of library path. [sup] */ -#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ -#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ -#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ -#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ -#define DT_PLTREL 20 /* Type of relocation used for PLT. */ -#define DT_DEBUG 21 /* Reserved (not used). */ -#define DT_TEXTREL 22 /* Indicates there may be relocations in - non-writable segments. [sup] */ -#define DT_JMPREL 23 /* Address of PLT relocations. */ -#define DT_BIND_NOW 24 /* [sup] */ -#define DT_INIT_ARRAY 25 /* Address of the array of pointers to - initialization functions */ -#define DT_FINI_ARRAY 26 /* Address of the array of pointers to - termination functions */ -#define DT_INIT_ARRAYSZ 27 /* Size in bytes of the array of - initialization functions. */ -#define DT_FINI_ARRAYSZ 28 /* Size in bytes of the array of - terminationfunctions. */ -#define DT_RUNPATH 29 /* String table offset of a null-terminated - library search path string. */ -#define DT_FLAGS 30 /* Object specific flag values. */ -#define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING - and less than DT_LOOS follow the rules for - the interpretation of the d_un union - as follows: even == 'd_ptr', even == 'd_val' - or none */ -#define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to - pre-initialization functions. */ -#define DT_PREINIT_ARRAYSZ 33 /* Size in bytes of the array of - pre-initialization functions. */ - -#define DT_COUNT 33 /* Number of defined d_tag values. */ - -#define DT_LOOS 0x6000000d /* First OS-specific */ -#define DT_HIOS 0x6fff0000 /* Last OS-specific */ -#define DT_LOPROC 0x70000000 /* First processor-specific type. */ -#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ - -/* Values for DT_FLAGS */ -#define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may - make reference to the $ORIGIN substitution - string */ -#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ -#define DF_TEXTREL 0x0004 /* Indicates there may be relocations in - non-writable segments. */ -#define DF_BIND_NOW 0x0008 /* Indicates that the dynamic linker should - process all relocations for the object - containing this entry before transferring - control to the program. */ -#define DF_STATIC_TLS 0x0010 /* Indicates that the shared object or - executable contains code using a static - thread-local storage scheme. */ - -/* Values for n_type. Used in core files. */ -#define NT_PRSTATUS 1 /* Process status. */ -#define NT_FPREGSET 2 /* Floating point registers. */ -#define NT_PRPSINFO 3 /* Process state info. */ - -/* Symbol Binding - ELFNN_ST_BIND - st_info */ -#define STB_LOCAL 0 /* Local symbol */ -#define STB_GLOBAL 1 /* Global symbol */ -#define STB_WEAK 2 /* like global - lower precedence */ -#define STB_LOPROC 13 /* reserved range for processor */ -#define STB_HIPROC 15 /* specific symbol bindings */ - -/* Symbol type - ELFNN_ST_TYPE - st_info */ -#define STT_NOTYPE 0 /* Unspecified type. */ -#define STT_OBJECT 1 /* Data object. */ -#define STT_FUNC 2 /* Function. */ -#define STT_SECTION 3 /* Section. */ -#define STT_FILE 4 /* Source file. */ -#define STT_TLS 6 /* TLS object. */ -#define STT_LOPROC 13 /* reserved range for processor */ -#define STT_HIPROC 15 /* specific symbol types */ - -/* Special symbol table indexes. */ -#define STN_UNDEF 0 /* Undefined symbol index. */ - -#endif /* !_SYS_ELF_COMMON_H_ */ diff --git a/testing/build.test1/mingw32_help/include/sys/elf_generic.h b/testing/build.test1/mingw32_help/include/sys/elf_generic.h deleted file mode 100644 index dbe9f1e839..0000000000 --- a/testing/build.test1/mingw32_help/include/sys/elf_generic.h +++ /dev/null @@ -1,91 +0,0 @@ -/*- - * Copyright (c) 1998 John D. Polstra. - * 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 AUTHOR 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 AUTHOR 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. - * - * $FreeBSD: src/sys/sys/elf_generic.h,v 1.6 2002/07/20 02:56:11 peter Exp $ - */ - -#ifndef _SYS_ELF_GENERIC_H_ -#define _SYS_ELF_GENERIC_H_ 1 - -#include <sys/cdefs.h> - -/* - * Definitions of generic ELF names which relieve applications from - * needing to know the word size. - */ - -#ifndef __ELF_WORD_SIZE -# define __ELF_WORD_SIZE 32 -#endif - -#if __ELF_WORD_SIZE != 32 && __ELF_WORD_SIZE != 64 -#error "__ELF_WORD_SIZE must be defined as 32 or 64" -#endif - -#define ELF_CLASS __CONCAT(ELFCLASS,__ELF_WORD_SIZE) - -#if BYTE_ORDER == LITTLE_ENDIAN -#define ELF_DATA ELFDATA2LSB -#elif BYTE_ORDER == BIG_ENDIAN -#define ELF_DATA ELFDATA2MSB -#else -#error "Unknown byte order" -#endif - -#if __ELF_WORD_SIZE == 32 -#define __elfN(x) elf32_##x -#define __ElfN(x) Elf32_##x -#define __ELFN(x) ELF32_##x -#else -#define __elfN(x) elf364_##x -#define __ElfN(x) Elf364_##x -#define __ELFN(x) ELF364_##x -#endif -#define __ElfType(x) typedef __ElfN(x) Elf_##x - -#define FOO -__ElfType(Addr); -__ElfType(Half); -__ElfType(Off); -__ElfType(Sword); -__ElfType(Word); -__ElfType(Size); -__ElfType(Hashelt); -__ElfType(Ehdr); -__ElfType(Shdr); -__ElfType(Phdr); -__ElfType(Dyn); -__ElfType(Rel); -__ElfType(Rela); -__ElfType(Sym); - -#define ELF_R_SYM __ELFN(R_SYM) -#define ELF_R_TYPE __ELFN(R_TYPE) -#define ELF_R_INFO __ELFN(R_INFO) -#define ELF_ST_BIND __ELFN(ST_BIND) -#define ELF_ST_TYPE __ELFN(ST_TYPE) -#define ELF_ST_INFO __ELFN(ST_INFO) - -#endif /* !_SYS_ELF_GENERIC_H_ */ diff --git a/testing/build.test2/Makefile b/testing/build.test2/Makefile deleted file mode 100644 index d4c428edda..0000000000 --- a/testing/build.test2/Makefile +++ /dev/null @@ -1,193 +0,0 @@ -# -*- mode: makefile -*- -#======================================== -# DO NOT DELETE THE LINE BELOW -_default: default -# DO NOT DELETE THE LINE_ABOVE -#======================================== - -#======================================== -# -# There are no user configurable options here. -# -# All user configurable options are in local.uses -# -include ./local.uses -# -#======================================== - -#======================================== -# This is the USB driver for the FTDI2XX chips. -# It is a "closed" solution from FTDICHIP.COM -# Some claim it is faster then the open/free -# solution: win32-libusb+libftdi. -# -ftd2xx.download: - mkdir -p ${VIRGINS} - wget -O ${FTD2XX_ZIPFILE_LOCAL} \ - ${FTD2XX_ZIPFILE_URL} - -ftd2xx.unpack: - rm -rf ${FTD2XX_WIN32_DIR} - mkdir -p ${FTD2XX_WIN32_DIR} - cd ${FTD2XX_WIN32_DIR} && unzip \ - ${FTD2XX_ZIPFILE_LOCAL} - -ftd2xx.build: - @echo "Nothing to do for: $@" - -ftd2xx.configure: - @echo "Nothing to do for: $@" - -ftd2xx.install: - @echo "Nothing to do for: $@" - -clean:: - rm -rf ${FTD2XX_WIN32_DIR} - -ftd2xx.all: ftd2xx.unpack ftd2xx.configure \ - ftd2xx.build ftd2xx.install - - -#========================================- -# LIBFTDI - requires LIBCONFUSE.. -# So we handle it here :-( - -libconfuse.download: - mkdir -p virgins - wget -O ${LIBCONFUSE_TARFILE_LOCAL} \ - ${LIBCONFUSE_TARFILE_URL} - -libconfuse.unpack: - tar xfz ${LIBCONFUSE_TARFILE_LOCAL} - -clean:: - rm -rf ${LIBCONFUSE_SRC_DIR} - -libconfuse.configure: - rm -rf ${LIBCONFUSE_BUILD_DIR} - mkdir -p ${LIBCONFUSE_BUILD_DIR} - cd ${LIBCONFUSE_BUILD_DIR} && \ - ${LIBCONFUSE_SRC_DIR}/configure \ - --prefix=${PREFIX} - -clean:: - rm -rf ${LIBCONFUSE_BUILD_DIR} - -libconfuse.build: - cd ${LIBCONFUSE_BUILD_DIR} && ${MAKE} - -libconfuse.install: - cd ${LIBCONFUSE_BUILD_DIR} && ${MAKE} install - -libconfuse.all: libconfuse.unpack libconfuse.configure \ - libconfuse.build libconfuse.install - -#======================================== -# LIBFTDI - the open source (and free) -# alternative to (closed) FTD2XX drivers. - -libftdi.download: - mkdir -p virgins - wget -O ${LIBFTDI_TARFILE_LOCAL} \ - ${LIBFTDI_TARFILE_URL} - -libftdi.unpack: - tar xfz ${LIBFTDI_TARFILE_LOCAL} - -clean:: - rm -rf ${LIBFTDI_SRC_DIR} - -libftdi.configure: - rm -rf ${LIBFTDI_BUILD_DIR} - mkdir -p ${LIBFTDI_BUILD_DIR} - cd ${LIBFTDI_BUILD_DIR} && \ - ${LIBFTDI_SRC_DIR}/configure \ - --prefix=${PREFIX} - -clean:: - rm -rf ${LIBFTDI_BUILD_DIR} - -libftdi.build: - cd ${LIBFTDI_BUILD_DIR} && ${MAKE} - -libftdi.install: - cd ${LIBFTDI_BUILD_DIR} && ${MAKE} install - -libftdi.all: libftdi.unpack libftdi.configure \ - libftdi.build libftdi.install - -#======================================== -# Openocd... - -openocd.bootstrap: - cd ${OPENOCD_SRC_DIR} && bash ./bootstrap - -openocd.configure: - rm -rf ${OPENOCD_BUILD_DIR} - mkdir -p ${OPENOCD_BUILD_DIR} - cd ${OPENOCD_BUILD_DIR} && ${OPENOCD_SRC_DIR}/configure \ - --prefix=${INSTALL_DIR} \ - ${OPENOCD_CONFIG_OPTIONS} - -openocd.build: - cd ${OPENOCD_BUILD_DIR} && ${MAKE} - -openocd.docs: - cd ${OPENOCD_BUILD_DIR}/docs && ${MAKE} - -openocd.docs.pdf: - cd ${OPENOCD_BUILD_DIR}/docs && ${MAKE} pdf - -openocd.docs.html: - cd ${OPENOCD_BUILD_DIR}/docs && ${MAKE} html - -# fixme: -# need to add a "make one huge html file target" - -openocd.install: - cd ${OPENOCD_BUILD_DIR} && ${MAKE} install - -#======================================== -# The world... - -# Manual step. -download.all: \ - ftd2xx.download \ - libconfuse.download \ - libftdi.download - -ifeq (x"${FT2232_DRIVER}",x"ftd2xx") -prebuild: ftd2xx.all -endif - -ifeq (x"${FT2232_DRIVER}",x"libftdi") -prebuild: libconfuse.all libftdi.all -endif - -remake: \ - openocd.bootstrap \ - openocd.configure \ - openocd.build \ - openocd.install - -initial.build : download.all prebuild remake - -all: - @echo "" - @echo " This makefile does not support an 'all' target" - @echo "" - @echo " If this is your *FIRST* time building... " - @echo " Then use this command: \"make initial.build\"" - @echo "" - @echo " The \"default\" target is for openocd developers" - @echo " and rebuilds openocd completely.." - @echo "" - -default: - test -d ${OPENOCD_SRC_DIR} || (echo "Where is: The OPENOCD source?"; exit 1) - ${MAKE} remake - -whatis_%: - @echo "" - @echo "Makevariable: $* => ${${*}}" - @echo "" diff --git a/testing/build.test2/README.txt b/testing/build.test2/README.txt deleted file mode 100644 index 382105ef01..0000000000 --- a/testing/build.test2/README.txt +++ /dev/null @@ -1,58 +0,0 @@ - -This makefile is how I Duane Ellis (openocd@duaneellis.com) builds -openocd test purposes on Cygwin. I have included it here so others -might also make use of the same configuration that I use to develop -Openocd. - ---Duane Ellis - -To make use of it do the following: - -(1) Check out openocd in the standard way. - -For example - in cygwin, type this: - - bash$ mkdir -p /home/duane/test - bash$ cd /home/duane/test - bash$ svn co https://svn.berlios.de/svnroot/repos/openocd/trunk openocd - -(2) COPY this folder "right above" where you have OpenOCD. - - bash$ cd /home/duane/test - bash$ cp ./openocd/testing/build.test2/* /home/duane/test/. - -(3) OPTIONALLY - - You might want to review the file "local.uses" - Change options and so forth at the top of the file. - -(4) Initially, you need to download some additional files. - These include "libftdi", "libconfuse", and the ftd2xx drivers. - -(5) You also need to build the supporting libraries and install them - (They are installed "locally" only) - - Type this command: - - bash$ cd /home/duane/test - - bash$ make initial.build - - which: (1) downloads files - (2) builds the libs - (3) builds OpenOCD - -(6) As you hack upon OpenOCD... to rebuild OpenOCD... - - bash$ cd /home/duane/test - - bash$ make remake - - which: (1) re-bootstraps - (2) re-configures - (3) re-builds - (4) re-installs. - -======= -**END** -======= diff --git a/testing/build.test2/local.uses b/testing/build.test2/local.uses deleted file mode 100644 index edde31b0c4..0000000000 --- a/testing/build.test2/local.uses +++ /dev/null @@ -1,161 +0,0 @@ -# -*- mode: makefile -*- -#======================================== -# DO NOT REMOVE THE LINE BELOW -HERE := $(shell pwd) -# DO NOT REMOVE THE LINE ABOVE -#======================================== - -# These are common CYGWIN build settings. -# Comment out things you do not want. -# Or unComment things you want. - -# PCs always have printer ports... -X86_PRINTER_PORT ?= y - -# Chose *ONE* of these three solutions. -#FTD2232_DRIVER = none -FT2232_DRIVER = ftd2xx -#FT2232_DRIVER = libftdi - -# Do you have "libusb" installed? -ifeq (x"${FT2232_DRIVER}",x"libftdi") -# With LIBFTDI... LIBUSB is manditory. -USE_LIBUSB = y -endif - -# By default... we assume libusb not present. -USE_LIBUSB ?= n - -#======================================== -# DO NOT EDIT SETTINGS BELOW THIS LINE -#======================================== - - - -#======================================== -# House keeping... - -# Solve problems on systems with DASH.. Grrr... -SHELL=/bin/bash -export SHELL - -VIRGINS ?= ${HERE}/virgins -INSTALL_DIR ?= $(HERE)/install -PREFIX ?= ${INSTALL_DIR} - -# Determine the build platform. -BUILD_SYSNAME_Linux =linux -BUILD_SYSNAME_linux =linux -BUILD_SYSNAME_CYGWIN_NT =cygwin -BUILD_SYSNAME_MINGW32_NT =mingw32 -BUILD_SYSNAME_Darwin =darwin -BUILD_SYSNAME_darwin =darwin -BUILD_SYSNAME :=$(BUILD_SYSNAME_$(shell uname --sysname | cut -d'-' -f1)) - -# And machine (ie: i686, x86_64, or what ever) -BUILD_MACHINE :=$(BUILD_SYSNAME).$(shell uname -m) - - -#======================================== -# - -FTD2XX_LINUX_VERSION=0.4.16 -FTD2XX_LINUX_DIR = ${HERE}/libftd2xx${FTD2XX_LINUX_VERSION} -FTD2XX_LINUX_64_DIR = ${HERE}/libftd2xx${FTD2XX_LINUX_VERSION}_x86_64 - - -# Wiggler type interfaces are here. -OPENOCD_CONFIG_OPTIONS_printer_y += --enable-parport -OPENOCD_CONFIG_OPTIONS_printer_y += --enable-parport-giveio -OPENOCD_CONFIG_OPTIONS_printer_y += --enable-gw16012 -OPENOCD_CONFIG_OPTIONS_printer_y += --enable-parport-giveio -OPENOCD_CONFIG_OPTIONS_printer_y += --enable-amtjtagaccel - - -# FTD2XX only supports these -OPENOCD_CONFIG_OPTIONS_ft2232_none = -OPENOCD_CONFIG_OPTIONS_ft2232_ftd2xx = --enable-ft2232_ftd2xx --enable-presto_ftd2xx --with-ftd2xx-win32-zipdir=${FTD2XX_WIN32_DIR} -OPENOCD_CONFIG_OPTIONS_ft2232_libftdi = --enable-ft2232_libftdi --enable-presto_libftdi - -# LIBUSB - adds support for these. -OPENOCD_CONFIG_OPTIONS_libusb_y += --enable-jlink -OPENOCD_CONFIG_OPTIONS_libusb_y += --enable-usbprog -OPENOCD_CONFIG_OPTIONS_libusb_y += --enable-rlink -OPENOCD_CONFIG_OPTIONS_libusb_y += --enable-vsllink -OPENOCD_CONFIG_OPTIONS_libusb_y += --enable-usbprog - -#======================================== -# EXPLICITY NOT SUPPORTED INTERFACES -# -# zy1000.c -# This is a standalone hardware box -# it is *NOT* a cygwin thing. -# -# at91rm9200.c -# This is a uC/Linux (or linux) that -# runs uC/Linux and uses the gpio pins -# to bit-bang JTAG stuff. -# -# ep93xx.c -# Just like at91rm9200 - different chip. - -#======================================== -# Build OPENOCD config options... -# Always enable "dummy" -OPENOCD_CONFIG_OPTIONS += --enable-dummy -# -# Today: Cannot enable 'oocd_trace' on cygwin. -# it assumes/uses termios functions like -# cfmakeraw() which do not exist on cygwin. -# -#OPENOCD_CONFIG_OPTIONS += --enable-oocd-trace -# -# Add printer options.. -OPENOCD_CONFIG_OPTIONS += ${OPENOCD_CONFIG_OPTIONS_printer_${X86_PRINTER_PORT}} - -# Add the FTD2232 based options. -OPENOCD_CONFIG_OPTIONS += ${OPENOCD_CONFIG_OPTIONS_ft2232_${FT2232_DRIVER}} - -# Add LIBUSB based options. -OPENOCD_CONFIG_OPTIONS += ${OPENOCD_CONFIG_OPTIONS_libusb_${USE_LIBUSB}} - - -#======================================== -# WARNING... the file on the ftdi chip site has a SPACE in the filename GRRR!!! -# We fix that with the "-O" option to wget. -FTD2XX_WIN32_VERSION=2.04.14 -FTD2XX_WIN32_DIR = ${HERE}/ftd2xx.win32 - -FTD2XX_ZIPFILE_LOCAL=${VIRGINS}/cdm.${FTD2XX_WIN32_VERSION}.zip -# Damn thing has a space in the F-ing filename! -FTD2XX_ZIPFILE_URL ="http://www.ftdichip.com/Drivers/CDM/CDM ${FTD2XX_WIN32_VERSION}.zip" - - -#======================================== -# LIBCONFUSE - used by LIBFTDI.. -LIBCONFUSE_VERSION=2.5 -LIBCONFUSE_TARFILE_LOCAL=${VIRGINS}/confuse-${LIBCONFUSE_VERSION}.tar.gz -LIBCONFUSE_TARFILE_URL =http://www.intra2net.com/de/produkte/opensource/ftdi/TGZ/confuse-${LIBCONFUSE_VERSION}.tar.gz - -LIBCONFUSE_SRC_DIR =${HERE}/confuse-${LIBCONFUSE_VERSION} -LIBCONFUSE_BUILD_DIR =${HERE}/confuse-build - - -#======================================== -# LIBFTDI... (which uses libusb, and libconfuse) -LIBFTDI_VERSION=0.14 -LIBFTDI_TARFILE_LOCAL = ${VIRGINS}/libftdi-${LIBFTDI_VERSION}.tar.gz -LIBFTDI_TARFILE_URL = http://www.intra2net.com/de/produkte/opensource/ftdi/TGZ/libftdi-${LIBFTDI_VERSION}.tar.gz - -LIBFTDI_SRC_DIR = ${HERE}/libftdi-${LIBFTDI_VERSION} -LIBFTDI_BUILD_DIR= ${HERE}/libftdi-build - -#======================================== -# Finally - OpenOCD... -# -OPENOCD_BUILD_DIR =${HERE}/openocd-build -OPENOCD_SRC_DIR =${HERE}/openocd - -#======================================== -# END .. -#======================================== diff --git a/testing/examples/cortex/cm3-ftest.cfg b/testing/examples/cortex/cm3-ftest.cfg index 6f3fa5c819..02c8da11ad 100644 --- a/testing/examples/cortex/cm3-ftest.cfg +++ b/testing/examples/cortex/cm3-ftest.cfg @@ -50,7 +50,7 @@ proc load_and_run { name halfwords n_instr } { echo "# code to trigger $name vector" set addr 0x20000000 - # array2mem should be faster, though we'd need to + # write_memory should be faster, though we'd need to # compute the resulting $addr ourselves foreach opcode $halfwords { mwh $addr $opcode 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/initial.sh b/tools/initial.sh index 446b98bdaf..eafc9c1387 100755 --- a/tools/initial.sh +++ b/tools/initial.sh @@ -11,7 +11,7 @@ add_remote() { remote_exist=`grep remote .git/config | grep review | wc -l` if [ "x$remote_exist" = "x0" ] ; then - git remote add review ssh://$USERNAME@openocd.zylin.com:29418/openocd.git + git remote add review ssh://$USERNAME@review.openocd.org:29418/openocd.git git config remote.review.push HEAD:refs/for/master else echo "Remote review exists" @@ -25,7 +25,7 @@ update_commit_msg() mv commit-msg $save_file printf "%-30s" "Updating commit-msg" status="OK" - wget -o log http://openocd.zylin.com/tools/hooks/commit-msg || status="FAIL" + wget -o log https://review.openocd.org/tools/hooks/commit-msg || status="FAIL" echo $status if [ $status = "FAIL" ] ; then mv $save_file commit-msg 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 0a119f1ba1..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 @@ Version: $V 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 @@ Options: 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 @@ EOM 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 @@ if (-f $conf) { 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 @@ if ($tree) { } 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 @@ our $Sparse = qr{ __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 @@ our $Attribute = qr{ __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 @@ our $UTF8 = qr { | \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 @@ our @typeList = ( 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 @@ for my $filename (@ARGV) { } 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) { - 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,136 +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; } +# 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"; - 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) + 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); + } + } + } + +# 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)/; + } + } + } } - 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 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 @@ -1753,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 && @@ -1783,7 +4210,7 @@ sub process { } my $s = $stat; - $s =~ s/\{.*$//s; + $s =~ s/{.*$//s; # Ignore goto labels. if ($s =~ /$Ident:\*$/s) { @@ -1835,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); @@ -1879,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"); @@ -1898,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 @@ -1920,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; } @@ -1977,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"); } @@ -1998,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) { @@ -2024,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); + } } # @@ -2039,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@//.*@@; @@ -2059,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; @@ -2087,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; } @@ -2099,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. @@ -2116,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/; @@ -2155,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/; @@ -2173,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); @@ -2195,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: @@ -2251,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\[/; + } } } @@ -2270,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. @@ -2284,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. @@ -2350,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 =~ /^$;+$/) { @@ -2359,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. @@ -2393,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 @@ -2428,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. @@ -2452,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;/; } } @@ -2482,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) { ## } @@ -2494,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; @@ -2617,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. @@ -2644,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"); + } + } } } @@ -2668,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); } @@ -2677,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 @@ -2693,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 @@ -2709,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"; @@ -2735,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); + } } } } @@ -2754,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 @@ -2858,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; @@ -2869,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. @@ -2879,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); + } } } } @@ -2944,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); } } @@ -3016,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"; @@ -3029,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. @@ -3043,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 @@ -3070,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*\&/) { @@ -3093,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/@) { @@ -3265,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); } } @@ -3290,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(); @@ -3311,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