diff --git a/.checkpatch.conf b/.checkpatch.conf index f432503e1a..b95dbe2711 100644 --- a/.checkpatch.conf +++ b/.checkpatch.conf @@ -14,7 +14,6 @@ --ignore ENOSYS --ignore FILE_PATH_CHANGES --ignore GERRIT_CHANGE_ID ---ignore LINE_SPACING --ignore LOGICAL_CONTINUATIONS --ignore MACRO_WITH_FLOW_CONTROL --ignore PARENTHESIS_ALIGNMENT @@ -23,6 +22,5 @@ --ignore PREFER_KERNEL_TYPES --ignore SPLIT_STRING --ignore SSCANF_TO_KSTRTO ---ignore SWITCH_CASE_INDENT_LEVEL --ignore TRACING_LOGGING --ignore VOLATILE diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..3ab5668a51 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# EditorConfig: https://editorconfig.org/ + +# top-most EditorConfig file +root = true + +# All (Defaults) +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab +indent_size = 4 +tab_width = 4 + +[*.patch,*.diff] +trim_trailing_whitespace = false diff --git a/HACKING b/HACKING index b1d224dbf6..785179efe9 100644 --- a/HACKING +++ b/HACKING @@ -77,32 +77,6 @@ patch: src/openocd -s ../tcl -f /path/to/openocd.cfg @endcode -- Runtime coverage testing - - Apply the following patch to prevent OpenOCD from killing itself: - @code ---- a/src/openocd.c -+++ b/src/openocd.c -@@ -372,8 +372,6 @@ int openocd_main(int argc, char *argv[]) - - if (ERROR_FAIL == ret) - return EXIT_FAILURE; -- else if (ERROR_OK != ret) -- exit_on_signal(ret); - - return ret; - } - @endcode - - Configure your OpenOCD binary with coverage support as follows: - @code - LDFLAGS="-fprofile-arcs -ftest-coverage" - CFLAGS="-fprofile-arcs -ftest-coverage" ./configure - @endcode - - Now every time OpenOCD is run, coverage info in your build directory is - updated. Running `gcov src/path/file.c` will generate a report. - - Sparse Static Analyzer Using this tool allows identifying some bug in C code. @@ -195,7 +169,9 @@ git remote add review https://USERNAME:PASSWORD@review.openocd.org/p/openocd.git Gerrit server, even if you plan to use several local branches for different 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: + -# You will need to install this hook to automatically add the + field "Change-Id:" in the commit message, as required by Gerrit. + We will look into a better solution: @code wget https://review.openocd.org/tools/hooks/commit-msg mv commit-msg .git/hooks @@ -272,6 +248,12 @@ doc: fix typos @code git pull --rebase origin master @endcode + +-# When you create a new version of an old patch, check that the new patch + keeps the same 'Change-Id:' field of the old patch. + This allows the Gerrit server to recognize the patch as a new version of + the older one and keeps track of the history and the review process. + -# Send the patches to the Gerrit server for review: @code git push review diff --git a/LICENSES/dual/CC-BY-4.0 b/LICENSES/dual/CC-BY-4.0 new file mode 100644 index 0000000000..e20b7a455e --- /dev/null +++ b/LICENSES/dual/CC-BY-4.0 @@ -0,0 +1,409 @@ +Valid-License-Identifier: CC-BY-4.0 +SPDX-URL: https://spdx.org/licenses/CC-BY-4.0 +Usage-Guide: + Do NOT use on OpenOCD code. This license 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". + To use the Creative Commons Attribution 4.0 International license put + the following SPDX tag/value pair into a comment according to the + placement guidelines in the licensing rules documentation: + SPDX-License-Identifier: CC-BY-4.0 +License-Text: + +Creative Commons Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the "Licensor." The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/LICENSES/license-rules.txt b/LICENSES/license-rules.txt index ecc8e4db16..66aaaa5b4d 100644 --- a/LICENSES/license-rules.txt +++ b/LICENSES/license-rules.txt @@ -187,7 +187,21 @@ OpenOCD, can be broken down into: License-Text: Full license text -2. Exceptions: +2. Dual Licensing Only: + + These licenses should only be used to dual license code with another + license in addition to a preferred license. These licenses are available + from the directory:: + + LICENSES/dual/ + + 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. + +3. Exceptions: Some licenses can be amended with exceptions which grant certain rights which the original license does not. These exceptions are available @@ -244,7 +258,7 @@ OpenOCD, can be broken down into: License-Text: Full license text -3. Stand-alone licenses: +4. Stand-alone licenses: These licenses should only be used for stand-alone applications that are distributed with OpenOCD but are not included in the OpenOCD binary. diff --git a/LICENSES/preferred/GFDL-1.2 b/LICENSES/preferred/GFDL-1.2 index 9217d9c8ec..ded6f4d453 100644 --- a/LICENSES/preferred/GFDL-1.2 +++ b/LICENSES/preferred/GFDL-1.2 @@ -18,7 +18,7 @@ License-Text: 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. diff --git a/LICENSES/preferred/GPL-2.0 b/LICENSES/preferred/GPL-2.0 index 687bdddb11..25d8343cd0 100644 --- a/LICENSES/preferred/GPL-2.0 +++ b/LICENSES/preferred/GPL-2.0 @@ -15,7 +15,7 @@ License-Text: 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. @@ -317,8 +317,7 @@ the "copyright" line and a pointer to where the full notice is found. GNU 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. + with this program; if not, see . Also add information on how to contact you by electronic and paper mail. diff --git a/LICENSES/preferred/LGPL-2.1 b/LICENSES/preferred/LGPL-2.1 index 8738a8d578..b19c23d17c 100644 --- a/LICENSES/preferred/LGPL-2.1 +++ b/LICENSES/preferred/LGPL-2.1 @@ -16,7 +16,7 @@ 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. @@ -486,9 +486,9 @@ 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. +along with this library; if not, see . + +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 diff --git a/Makefile.am b/Makefile.am index 0884c07878..b6aa282215 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,8 +1,6 @@ # 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 +AUTOMAKE_OPTIONS = foreign 1.14 .DELETE_ON_ERROR: @@ -28,12 +26,12 @@ dist_man_MANS = EXTRA_DIST = DISTCLEANFILES = -SUBDIRS += testing -DIST_SUBDIRS += testing - SUBDIRS += tools/syntacore DIST_SUBDIRS += tools/syntacore +SUBDIRS += testing +DIST_SUBDIRS += testing + # common flags used in openocd build AM_CFLAGS = $(GCC_WARNINGS) AM_LDFLAGS = @@ -54,11 +52,12 @@ EXTRA_DIST += \ BUGS \ HACKING \ NEWTAPS \ - README.Windows \ - README.macOS \ + README.Windows.md \ + README.macOS.md \ $(EXTRA_DIST_NEWS) \ Doxyfile.in \ LICENSES/license-rules.txt \ + LICENSES/dual/CC-BY-4.0 \ LICENSES/exceptions/eCos-exception-2.0 \ LICENSES/preferred/BSD-1-Clause \ LICENSES/preferred/BSD-2-Clause \ diff --git a/README.Windows b/README.Windows.md similarity index 60% rename from README.Windows rename to README.Windows.md index 64bf5c0c6f..9b6f770f6b 100644 --- a/README.Windows +++ b/README.Windows.md @@ -1,29 +1,19 @@ -Building OpenOCD for Windows ----------------------------- +# OpenOCD for Windows + +This README contains instructions that are specific to Windows. + +## Building You can build OpenOCD for Windows natively with either MinGW-w64/MSYS -or Cygwin (plain MinGW might work with --disable-werror but is not +or Cygwin (plain MinGW might work with `--disable-werror` but is not recommended as it doesn't provide enough C99 compatibility). Alternatively, one can cross-compile it using MinGW-w64 on a *nix -host. See README for the generic instructions. +host. See [README](README.md) for the generic instructions. Also, the MSYS2 project provides both ready-made binaries and an easy way to self-compile from their software repository out of the box. -Native MinGW-w64/MSYS compilation ------------------------------ - -As MSYS doesn't come with pkg-config pre-installed, you need to add it -manually. The easiest way to do that is to download pkg-config-lite -from: - - http://sourceforge.net/projects/pkgconfiglite/ - -Then simply unzip the archive to the root directory of your MinGW-w64 -installation. - -USB adapters ------------- +## USB adapters For the adapters that use a HID-based protocol, e.g. CMSIS-DAP, you do not need to perform any additional configuration. @@ -31,9 +21,7 @@ not need to perform any additional configuration. For all the others you usually need to have WinUSB.sys (or libusbK.sys) driver installed. Some vendor software (e.g. for ST-LINKv2) does it on its own. For the other cases the easiest way to -assign WinUSB to a device is to use the latest Zadig installer: - - http://zadig.akeo.ie +assign WinUSB to a device is to use the latest Zadig installer: When using a composite USB device, it's often necessary to assign WinUSB.sys to the composite parent instead of the specific @@ -42,7 +30,7 @@ Zadig installer. 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. +activate the `IgnoreHWSerNum` registry setting for the USB device. That setting forces Windows to associate the driver per port instead of per serial number, the same behaviour as when the device does not contain @@ -52,5 +40,5 @@ port depending on which application to use. For more information, see: - 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.macOS b/README.macOS deleted file mode 100644 index 91d5e9261b..0000000000 --- a/README.macOS +++ /dev/null @@ -1,54 +0,0 @@ -Building OpenOCD for macOS --------------------------- - -There are a few prerequisites you will need first: - -- 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/) - or -- 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 -manually from the sources. - - -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 [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 [libftdi1] - -You should also specify LDFLAGS and CPPFLAGS to allow configure to use -MacPorts' libraries, so run configure like this: - LDFLAGS=-L/opt/local/lib CPPFLAGS=-I/opt/local/include ./configure [options] - - -See README for the generic building instructions. - -If you're using a USB adapter and have a driver kext matched to it, -you will need to unload it prior to running OpenOCD. E.g. with Apple -driver (OS X 10.9 or later) for FTDI run: - sudo kextunload -b com.apple.driver.AppleUSBFTDI -for FTDI vendor driver use: - sudo kextunload FTDIUSBSerialDriver.kext - -To learn more on the topic please refer to the official libusb FAQ: -https://github.com/libusb/libusb/wiki/FAQ diff --git a/README.macOS.md b/README.macOS.md new file mode 100644 index 0000000000..a531024d9f --- /dev/null +++ b/README.macOS.md @@ -0,0 +1,72 @@ +# OpenOCD for macOS + +This README contains instructions that are specific to macOS. + +## Building + +There are a few prerequisites you will need first: + +- Xcode (install from the AppStore) +- Command Line Tools (install from Xcode -> Preferences -> Downloads) +- One of the following tools: + - Gentoo Prefix () + - Homebrew () + - MacPorts () + +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 +manually from the sources. + +With Homebrew you can either run: + +```sh +brew install [--HEAD] open-ocd +``` + +Where ``--HEAD`` asks ``brew`` to install the current Git version instead of the +lastest release. + +You can also run: + +```sh +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: + +```sh +sudo port install libtool automake autoconf pkgconfig libusb [libftdi1] +``` + +You should also specify LDFLAGS and CPPFLAGS to allow `configure` to use +MacPorts' libraries, so run configure like this: + +```sh +LDFLAGS=-L/opt/local/lib CPPFLAGS=-I/opt/local/include ./configure [options] +``` + +See [README](README.md) for the generic building instructions. + +If you're using a USB adapter and have a driver kext matched to it, +you will need to unload it prior to running OpenOCD. E.g. with Apple +driver (OS X 10.9 or later) for FTDI run: + +```sh +sudo kextunload -b com.apple.driver.AppleUSBFTDI +``` + +for FTDI vendor driver use: + +```sh +sudo kextunload FTDIUSBSerialDriver.kext +``` + +To learn more on the topic please refer to the official libusb FAQ: diff --git a/README b/README.md similarity index 72% rename from README rename to README.md index 875c85de3b..bf26d59038 100644 --- a/README +++ b/README.md @@ -1,4 +1,4 @@ -# Welcome to OpenOCD! +# Welcome to OpenOCD OpenOCD provides on-chip programming and debugging support with a layered architecture of JTAG interface and TAP support including: @@ -24,53 +24,119 @@ This README file contains an overview of the following topics: - the installation and build process, - packaging tips. - -# Quickstart for the impatient +## Quickstart for the impatient If you have a popular board then just start OpenOCD with its config, e.g.: - openocd -f board/stm32f4discovery.cfg +```sh +openocd -f board/stm32f4discovery.cfg +``` If you are connecting a particular adapter with some specific target, you need to source both the jtag interface and the target configs, e.g.: -``` +```sh openocd -f interface/ftdi/jtagkey2.cfg -c "transport select jtag" \ - -f target/ti_calypso.cfg + -f target/ti/calypso.cfg ``` -``` +```sh openocd -f interface/stlink.cfg -c "transport select swd" \ -f target/stm32l0.cfg ``` After OpenOCD startup, connect GDB with - (gdb) target extended-remote localhost:3333 +```gdb +(gdb) target extended-remote localhost:3333 +``` + +## Installing OpenOCD + +The easiest way to install OpenOCD is through your operating system's package +manager. + +- Debian / Ubuntu + + ```sh + sudo apt install openocd + ``` + +- Fedora + + ```sh + sudo dnf install openocd + ``` + +- macOS (via Homebrew) + + ```sh + brew install open-ocd + ``` + +- Windows (via MSYS2) + + ```sh + pacman -S mingw-w64-x86_64-openocd + ``` + +These packages are often more stable than the bleeding-edge Git mainline, where +active development happens. +"Packagers" create binary releases of OpenOCD after the developers publish new +source code releases. +Older OpenOCD versions are not suitable for diagnosing issues in the current +release. +Users should stay in touch with their distribution maintainers or interface +vendors to ensure that appropriate updates are provided regularly. + +If you use one of these binary packages, you must contact the Packager for +support or for newer binary versions. +The OpenOCD developers do not provide direct support for packaged binaries. + +## A Note to OpenOCD Packagers + +You are a PACKAGER of OpenOCD if you: + +- Sell dongles and include pre-built binaries; +- Supply tools or IDEs (a development solution integrating OpenOCD); +- Build packages (e.g. RPM or DEB files for a GNU/Linux distribution). + +As a PACKAGER, you will experience first reports of most issues. +When you fix those problems for your users, your solution may help +prevent hundreds (if not thousands) of other questions from other users. + +If something does not work for you, please work to inform the OpenOCD +developers know how to improve the system or documentation to avoid +future problems, and follow-up to help us ensure the issue will be fully +resolved in our future releases. + +That said, the OpenOCD developers would also like you to follow a few +suggestions: +- Send patches, including config files, upstream, participate in the + discussions; +- Enable all the options OpenOCD supports, even those unrelated to your + particular hardware; +- Use "ftdi" interface adapter driver for the FTDI-based devices. -# OpenOCD Documentation +## OpenOCD Documentation In addition to the in-tree documentation, the latest manuals may be viewed online at the following URLs: - OpenOCD User's Guide: - http://openocd.org/doc/html/index.html +- OpenOCD User's Guide: - OpenOCD Developer's Manual: - http://openocd.org/doc/doxygen/html/index.html +- OpenOCD Developer's Manual: These reflect the latest development versions, so the following section introduces how to build the complete documentation from the package. For more information, refer to these documents or contact the developers -by subscribing to the OpenOCD developer mailing list: - - openocd-devel@lists.sourceforge.net +by subscribing to the OpenOCD developer mailing list: openocd-devel@lists.sourceforge.net -## Building the OpenOCD Documentation +### Building the OpenOCD Documentation By default the OpenOCD build process prepares documentation in the "Info format" and installs it the standard way, so that `info openocd` @@ -81,23 +147,28 @@ following different formats: If `PDFVIEWER` is set, this creates and views the PDF User Guide. - make pdf && ${PDFVIEWER} doc/openocd.pdf +```sh +make pdf && ${PDFVIEWER} doc/openocd.pdf +``` If `HTMLVIEWER` is set, this creates and views the HTML User Guide. - make html && ${HTMLVIEWER} doc/openocd.html/index.html +```sh +make html && ${HTMLVIEWER} doc/openocd.html/index.html +``` The OpenOCD Developer Manual contains information about the internal architecture and other details about the code: Note: make sure doxygen is installed, type doxygen --version - make doxygen && ${HTMLVIEWER} doxygen/index.html - +```sh +make doxygen && ${HTMLVIEWER} doxygen/index.html +``` -# Supported hardware +## Supported hardware -## JTAG adapters +### JTAG adapters AM335x, ARM-JTAG-EW, ARM-USB-OCD, ARM-USB-TINY, AT91RM9200, axm0432, BCM2835, Bus Blaster, Buspirate, Cadence DPI, Cadence vdebug, Chameleon, CMSIS-DAP, @@ -114,7 +185,7 @@ sysfsgpio, Tigard, TI XDS110, TUMPA, Turtelizer, ULINK, USB-A9260, USB-Blaster, USB-JTAG, USBprog, VPACLink, VSLLink, Wiggler, XDS100v2, Xilinx XVC/PCIe, Xverve. -## Debug targets +### Debug targets ARM: AArch64, ARM11, ARM7, ARM9, Cortex-A/R (v7-A/R), Cortex-M (ARMv{6/7/8}-M), FA526, Feroceon/Dragonite, XScale. @@ -122,7 +193,7 @@ 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 +### Flash drivers ADUC702x, AT91SAM, AT91SAM9 (NAND), ATH79, ATmega128RFA1, Atmel SAM, AVR, CFI, DSP5680xx, EFM32, EM357, eSi-RISC, eSi-TSMC, EZR32HG, FM3, FM4, Freedom E SPI, @@ -135,66 +206,22 @@ 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. - -# Installing OpenOCD - -## A Note to OpenOCD Users - -If you would rather be working "with" OpenOCD rather than "on" it, your -operating system or JTAG interface supplier may provide binaries for -you in a convenient-enough package. - -Such packages may be more stable than git mainline, where -bleeding-edge development takes place. These "Packagers" produce -binary releases of OpenOCD after the developers produces new "release" -versions of the source code. Previous versions of OpenOCD cannot be -used to diagnose problems with the current release, so users are -encouraged to keep in contact with their distribution package -maintainers or interface vendors to ensure suitable upgrades appear -regularly. - -Users of these binary versions of OpenOCD must contact their Packager to -ask for support or newer versions of the binaries; the OpenOCD -developers do not support packages directly. - -## A Note to OpenOCD Packagers - -You are a PACKAGER of OpenOCD if you: - -- Sell dongles and include pre-built binaries; -- Supply tools or IDEs (a development solution integrating OpenOCD); -- Build packages (e.g. RPM or DEB files for a GNU/Linux distribution). - -As a PACKAGER, you will experience first reports of most issues. -When you fix those problems for your users, your solution may help -prevent hundreds (if not thousands) of other questions from other users. - -If something does not work for you, please work to inform the OpenOCD -developers know how to improve the system or documentation to avoid -future problems, and follow-up to help us ensure the issue will be fully -resolved in our future releases. - -That said, the OpenOCD developers would also like you to follow a few -suggestions: - -- Send patches, including config files, upstream, participate in the - discussions; -- Enable all the options OpenOCD supports, even those unrelated to your - particular hardware; -- Use "ftdi" interface adapter driver for the FTDI-based devices. - - -# Building OpenOCD +## Building OpenOCD The INSTALL file contains generic instructions for running `configure` and compiling the OpenOCD source code. That file is provided by default for all GNU autotools packages. If you are not familiar with the GNU autotools, then you should read those instructions first. +Note: if the INSTALL file is not present, it means you are using the +source code from a development branch, not from an OpenOCD release. +In this case, follow the instructions 'Compiling OpenOCD' below and +the file will be created by the first command `./bootstrap`. + The remainder of this document tries to provide some instructions for those looking for a quick-install. -## OpenOCD Dependencies +### OpenOCD Dependencies GCC or Clang is currently required to build OpenOCD. The developers have begun to enforce strict code warnings (-Wall, -Werror, -Wextra, @@ -211,7 +238,7 @@ You'll also need: - pkg-config >= 0.23 or pkgconf - libjim >= 0.79 -Additionally, for building from git: +Additionally, for building from Git: - autoconf >= 2.69 - automake >= 1.14 @@ -219,9 +246,8 @@ Additionally, for building from git: Optional USB-based adapter drivers need libusb-1.0. -Optional USB-Blaster, ASIX Presto and OpenJTAG interface adapter -drivers need: - - libftdi: http://www.intra2net.com/en/developer/libftdi/index.php +Optional USB-Blaster, ASIX Presto and OpenJTAG interface adapter drivers need +[libftdi](http://www.intra2net.com/en/developer/libftdi/index.php) library. Optional CMSIS-DAP adapter driver needs HIDAPI library. @@ -236,64 +262,49 @@ Optional development script checkpatch needs: - perl - python - python-ply +- pymarkdownlnt -## Permissions delegation - -Running OpenOCD with root/administrative permissions is strongly -discouraged for security reasons. - -For USB devices on GNU/Linux you should use the contrib/60-openocd.rules -file. It probably belongs somewhere in /etc/udev/rules.d, but -consult your operating system documentation to be sure. Do not forget -to add yourself to the "plugdev" group. - -For parallel port adapters on GNU/Linux and FreeBSD please change your -"ppdev" (parport* or ppi*) device node permissions accordingly. - -For parport adapters on Windows you need to run install_giveio.bat -(it's also possible to use "ioperm" with Cygwin instead) to give -ordinary users permissions for accessing the "LPT" registers directly. - -## Compiling OpenOCD +### Compiling OpenOCD To build OpenOCD, use the following sequence of commands: - ./bootstrap - ./configure [options] - make - sudo make install +```sh +./bootstrap +./configure [options] +make +sudo make install +``` -The `bootstrap` command is only necessary when building from the Git repository. The `configure` step generates the Makefiles required to build -OpenOCD, usually with one or more options provided to it. The first -'make' step will build OpenOCD and place the final executable in -'./src/'. The final (optional) step, `make install`, places all of -the files in the required location. +The `bootstrap` command is only necessary when building from the Git repository. +The `configure` step generates the Makefiles required to build OpenOCD, usually +with one or more options provided to it. +The first 'make' step will build OpenOCD and place the final executable in './src/'. +The final (optional) step, `make install`, places all of the files in the +required location. To see the list of all the supported options, run `./configure --help` -## Cross-compiling Options +### Cross-compiling Options Cross-compiling is supported the standard autotools way, you just need to specify the cross-compiling target triplet in the --host option, e.g. for cross-building for Windows 32-bit with MinGW on Debian: - ./configure --host=i686-w64-mingw32 [options] - -To make pkg-config work nicely for cross-compiling, you might need an -additional wrapper script as described at +```sh +./configure --host=i686-w64-mingw32 [options] +``` - https://autotools.io/pkgconfig/cross-compiling.html +To make pkg-config work nicely for cross-compiling, you might need an additional +wrapper script as described at . This is needed to tell pkg-config where to look for the target libraries that OpenOCD depends on. Alternatively, you can specify `*_CFLAGS` and `*_LIBS` environment variables directly, see `./configure --help` for the details. -For a more or less complete script that does all this for you, see +For a more or less complete script that does all this for you, see `contrib/cross-build.sh`. - contrib/cross-build.sh - -## Parallel Port Dongles +### Parallel Port Dongles If you want to access the parallel port using the PPDEV interface you have to specify both `--enable-parport` and `--enable-parport-ppdev`, since @@ -304,31 +315,45 @@ use both the `--enable-parport` and the `--enable-parport-giveio` option if you want to use giveio instead of ioperm parallel port access method. +### Obtaining OpenOCD From Git -# Obtaining OpenOCD From GIT - -You can download the current GIT version with a GIT client of your -choice from the main repository: - - git://git.code.sf.net/p/openocd/code +You can download the current Git version with a Git client of your +choice from the main repository: `git://git.code.sf.net/p/openocd/code` You may prefer to use a mirror: - http://repo.or.cz/r/openocd.git - git://repo.or.cz/openocd.git +- +- git://repo.or.cz/openocd.git -Using the GIT command line client, you might use the following command +Using the Git command line client, you might use the following command to set up a local copy of the current repository (make sure there is no directory called "openocd" in the current directory): - git clone git://git.code.sf.net/p/openocd/code openocd +```sh +git clone git://git.code.sf.net/p/openocd/code openocd +``` Then you can update that at your convenience using `git pull`. -There is also a gitweb interface, which you can use either to browse -the repository or to download arbitrary snapshots using HTTP: - - http://repo.or.cz/w/openocd.git +There is also a gitweb interface, which you can use either to browse the +repository or to download arbitrary snapshots using HTTP: . Snapshots are compressed tarballs of the source tree, about 1.3 MBytes each at this writing. + +## Permissions delegation + +Running OpenOCD with root/administrative permissions is strongly +discouraged for security reasons. + +For USB devices on GNU/Linux you should use the contrib/60-openocd.rules +file. It probably belongs somewhere in /etc/udev/rules.d, but +consult your operating system documentation to be sure. Do not forget +to add yourself to the "plugdev" group. + +For parallel port adapters on GNU/Linux and FreeBSD please change your +"ppdev" (parport* or ppi*) device node permissions accordingly. + +For parport adapters on Windows you need to run install_giveio.bat +(it's also possible to use "ioperm" with Cygwin instead) to give +ordinary users permissions for accessing the "LPT" registers directly. diff --git a/configure.ac b/configure.ac index 390c1375b0..97a81f2456 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ AS_IF([test "x$MAKEINFO" = "x"], [ ]) AC_SUBST([MAKEINFO]) -AM_INIT_AUTOMAKE([-Wall -Wno-portability dist-bzip2 dist-zip subdir-objects]) +AM_INIT_AUTOMAKE([foreign -Wall -Wno-portability dist-bzip2 dist-zip subdir-objects]) AC_CONFIG_HEADERS([config.h]) @@ -24,7 +24,6 @@ AC_LANG([C]) AC_PROG_CC # 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, @@ -49,6 +48,8 @@ AC_TYPE_LONG_LONG_INT AC_SEARCH_LIBS([ioperm], [ioperm]) AC_SEARCH_LIBS([dlopen], [dl]) AC_SEARCH_LIBS([openpty], [util]) +# Older versions of Linux put clock_gettime in librt +AC_SEARCH_LIBS([clock_gettime], [rt]) AC_CHECK_HEADERS([sys/socket.h]) AC_CHECK_HEADERS([elf.h]) @@ -57,17 +58,14 @@ AC_CHECK_TYPE([Elf64_Ehdr], AC_DEFINE([HAVE_ELF64], [1], [Define to 1 if the system has the type 'Elf64_Ehdr'.]), [], [[#include ]]) -AC_MSG_CHECKING([for glibc]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int v = __GLIBC__;return 0;]])], - [have_glibc=yes], [have_glibc=no]) -AC_MSG_RESULT($have_glibc) - AC_CHECK_HEADERS([fcntl.h]) -AC_CHECK_HEADERS([malloc.h]) +AC_CHECK_HEADERS([linux/pci.h]) +AC_CHECK_HEADERS([linux/spi/spidev.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([poll.h]) AC_CHECK_HEADERS([strings.h]) AC_CHECK_HEADERS([sys/ioctl.h]) +AC_CHECK_HEADERS([sys/mman.h]) AC_CHECK_HEADERS([sys/param.h]) AC_CHECK_HEADERS([sys/select.h]) AC_CHECK_HEADERS([sys/stat.h]) @@ -97,9 +95,11 @@ AC_C_BIGENDIAN AC_CHECK_FUNCS([strndup]) AC_CHECK_FUNCS([strnlen]) -AC_CHECK_FUNCS([gettimeofday]) +AC_CHECK_FUNCS([clock_gettime]) AC_CHECK_FUNCS([usleep]) AC_CHECK_FUNCS([realpath]) +AC_CHECK_FUNCS([mallinfo]) +AC_CHECK_FUNCS([mallinfo2]) # guess-rev.sh only exists in the repository, not in the released archives AC_MSG_CHECKING([whether to build a release]) @@ -129,6 +129,8 @@ m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], [-])]) m4_define([USB1_ADAPTERS], [[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]], [[ftdi_cjtag], [cJTAG (OScan1, JScan3) tunneled thru MPSSE], [FTDI_CJTAG]], + [[ch347], [CH347 based devices], [CH347]], + [[cklink], [T-Head CK-Link JTAG Probe], [CKLINK]], [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], @@ -165,6 +167,9 @@ m4_define([LIBFTDI_USB1_ADAPTERS], m4_define([LIBGPIOD_ADAPTERS], [[[linuxgpiod], [Linux GPIO bitbang through libgpiod], [LINUXGPIOD]]]) +m4_define([DMEM_ADAPTER], + [[[dmem], [CoreSight Direct Memory], [DMEM]]]) + m4_define([SYSFSGPIO_ADAPTER], [[[sysfsgpio], [Linux GPIO bitbang through sysfs], [SYSFSGPIO]]]) @@ -174,12 +179,18 @@ m4_define([REMOTE_BITBANG_ADAPTER], m4_define([LIBJAYLINK_ADAPTERS], [[[jlink], [SEGGER J-Link Programmer], [JLINK]]]) -m4_define([PCIE_ADAPTERS], - [[[xlnx_pcie_xvc], [Xilinx XVC/PCIe], [XLNX_PCIE_XVC]]]) +m4_define([XVC_ADAPTERS], + [[[xlnx_xvc], [Xilinx XVC PCIe and AXI drives], [XLNX_XVC]]]) m4_define([SERIAL_PORT_ADAPTERS], [[[buspirate], [Bus Pirate], [BUS_PIRATE]]]) +m4_define([PARALLEL_PORT_ADAPTER], + [[[parport], [PC Parallel Port], [PARPORT]]]) + +m4_define([NETWORK_ADAPTERS], + [[[xvc], [Xilinx XVC TCP], [XVC]]]) + m4_define([LINUXSPIDEV_ADAPTER], [[[linuxspidev], [Linux spidev driver], [LINUXSPIDEV]]]) m4_define([VDEBUG_ADAPTER], @@ -197,8 +208,18 @@ m4_define([RSHIM_ADAPTER], m4_define([AMTJTAGACCEL_ADAPTER], [[[amtjtagaccel], [Amontec JTAG-Accelerator driver], [AMTJTAGACCEL]]]) -# The word 'Adapter' in "Dummy Adapter" below must begin with a capital letter -# because there is an M4 macro called 'adapter'. +m4_define([CMSIS_DAP_TCP_ADAPTER], + [[[cmsis_dap_tcp], [CMSIS-DAP v2 compliant dongle (TCP)], [CMSIS_DAP_TCP]]]) + +m4_define([HOST_ARM_BITBANG_ADAPTERS], + [[[ep93xx], [Bitbanging on EP93xx-based SBCs], [EP93XX]], + [[at91rm9200], [Bitbanging on AT91RM9200-based SBCs], [AT91RM9200]]]) + +m4_define([HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS], + [[[bcm2835gpio], [Bitbanging on BCM2835 (as found in Raspberry Pi)], [BCM2835GPIO]], + [[imx_gpio], [Bitbanging on NXP IMX processors], [IMX_GPIO]], + [[am335xgpio], [Bitbanging on AM335x (as found in Beaglebones)], [AM335XGPIO]]]) + m4_define([DUMMY_ADAPTER], [[[dummy], [Dummy Adapter], [DUMMY]]]) @@ -249,66 +270,16 @@ AS_IF([test "x$enable_gcov" = "xyes"], [ AC_DEFINE([USE_GCOV], [0], [0 to leave coverage collection disabled.]) ]) -# set default verbose options, overridden by following options -debug_usb_io=no -debug_usb_comms=no - -AC_ARG_ENABLE([verbose], - AS_HELP_STRING([--enable-verbose], - [Enable verbose JTAG I/O messages (for debugging).]), - [ - debug_usb_io=$enableval - debug_usb_comms=$enableval - ], []) - -AC_ARG_ENABLE([verbose_usb_io], - AS_HELP_STRING([--enable-verbose-usb-io], - [Enable verbose USB I/O messages (for debugging)]), - [debug_usb_io=$enableval], []) - -AC_ARG_ENABLE([verbose_usb_comms], - AS_HELP_STRING([--enable-verbose-usb-comms], - [Enable verbose USB communication messages (for debugging)]), - [debug_usb_comms=$enableval], []) - -AC_MSG_CHECKING([whether to enable verbose USB I/O messages]); -AC_MSG_RESULT([$debug_usb_io]) -AS_IF([test "x$debug_usb_io" = "xyes"], [ - AC_DEFINE([_DEBUG_USB_IO_],[1], [Print verbose USB I/O messages]) -]) - -AC_MSG_CHECKING([whether to enable verbose USB communication messages]); -AC_MSG_RESULT([$debug_usb_comms]) -AS_IF([test "x$debug_usb_comms" = "xyes"], [ - AC_DEFINE([_DEBUG_USB_COMMS_],[1], [Print verbose USB communication messages]) -]) - -debug_malloc=no -AC_ARG_ENABLE([malloc_logging], - AS_HELP_STRING([--enable-malloc-logging], - [Include free space in logging messages (requires malloc.h).]), - [debug_malloc=$enableval], []) - -AC_MSG_CHECKING([whether to enable malloc free space logging]); -AC_MSG_RESULT([$debug_malloc]) -AS_IF([test "x$debug_malloc" = "xyes" -a "x$have_glibc" = "xyes"], [ - AC_DEFINE([_DEBUG_FREE_SPACE_],[1], [Include malloc free space in logging]) -]) - -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]), - AS_HELP_STRING([--enable-ADAPTER_OPT([adapter])[[[=yes/no/auto]]]], - [Enable building support for the ]ADAPTER_DESC([adapter])[ (default is $2)]), + m4_foreach([adapter_driver], [$1], + [AC_ARG_ENABLE(ADAPTER_OPT([adapter_driver]), + AS_HELP_STRING([--enable-ADAPTER_OPT([adapter_driver])[[[=yes/no/auto]]]], + [Enable building support for the ]ADAPTER_DESC([adapter_driver])[ (default is $2)]), [case "${enableval}" in yes|no|auto) ;; - *) AC_MSG_ERROR([Option --enable-ADAPTER_OPT([adapter]) has invalid value "${enableval}".]) ;; + *) AC_MSG_ERROR([Option --enable-ADAPTER_OPT([adapter_driver]) has invalid value "${enableval}".]) ;; esac], - [ADAPTER_VAR([adapter])=$2]) + [ADAPTER_VAR([adapter_driver])=$2]) ]) ]) @@ -319,6 +290,7 @@ AC_ARG_ADAPTERS([ LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, + DMEM_ADAPTER, SYSFSGPIO_ADAPTER, REMOTE_BITBANG_ADAPTER, LINUXSPIDEV_ADAPTER, @@ -328,14 +300,26 @@ AC_ARG_ADAPTERS([ JTAG_DPI_ADAPTER, JTAG_VPI_ADAPTER, RSHIM_ADAPTER, - AMTJTAGACCEL_ADAPTER, - PCIE_ADAPTERS, - LIBJAYLINK_ADAPTERS + XVC_ADAPTERS, + LIBJAYLINK_ADAPTERS, + CMSIS_DAP_TCP_ADAPTER, + NETWORK_ADAPTERS ],[auto]) -AC_ARG_ENABLE([parport], - AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]), - [build_parport=$enableval], [build_parport=no]) +AC_ARG_ADAPTERS([ + PARALLEL_PORT_ADAPTER, + AMTJTAGACCEL_ADAPTER + ],[no]) + +# The following adapters use bitbanging and can actually be built on all architectures, +# which is useful to verify that they still build fine. +# We could enable them automatically only on the architectures where they actually occur: +# HOST_ARM_BITBANG_ADAPTERS: when ${host_cpu} matches arm* +# HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS: when ${host_cpu} matches arm*|aarch64 +# However, conditionally changing the meaning of 'auto' requires +# a more flexible logic around. +AC_ARG_ADAPTERS([HOST_ARM_BITBANG_ADAPTERS],[no]) +AC_ARG_ADAPTERS([HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS],[no]) AC_ARG_ENABLE([parport_ppdev], AS_HELP_STRING([--disable-parport-ppdev], @@ -344,42 +328,9 @@ AC_ARG_ENABLE([parport_ppdev], AC_ARG_ENABLE([parport_giveio], AS_HELP_STRING([--enable-parport-giveio], - [Enable use of giveio for parport (for CygWin only)]), + [Enable use of giveio for parport (deprecated, for CygWin only)]), [parport_use_giveio=$enableval], [parport_use_giveio=]) -AS_CASE(["${host_cpu}"], - [arm*|aarch64], [ - AC_ARG_ENABLE([bcm2835gpio], - AS_HELP_STRING([--enable-bcm2835gpio], [Enable building support for bitbanging on BCM2835 (as found in Raspberry Pi)]), - [build_bcm2835gpio=$enableval], [build_bcm2835gpio=no]) - 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}"], - [arm*], [ - AC_ARG_ENABLE([ep93xx], - AS_HELP_STRING([--enable-ep93xx], [Enable building support for EP93xx based SBCs]), - [build_ep93xx=$enableval], [build_ep93xx=no]) - - AC_ARG_ENABLE([at91rm9200], - AS_HELP_STRING([--enable-at91rm9200], [Enable building support for AT91RM9200 based SBCs]), - [build_at91rm9200=$enableval], [build_at91rm9200=no]) - ], - [ - build_ep93xx=no - build_at91rm9200=no -]) - AC_ARG_ENABLE([gw16012], AS_HELP_STRING([--enable-gw16012], [Enable building support for the Gateworks GW16012 JTAG Programmer]), [build_gw16012=$enableval], [build_gw16012=no]) @@ -401,7 +352,7 @@ AS_CASE([$host_os], ]) ]) - AS_IF([test "x$build_dmem" = "xyes"], [ + AS_IF([test "x$enable_dmem" = "xyes"], [ AC_MSG_ERROR([dmem is only available on linux]) ]) ]) @@ -410,9 +361,8 @@ AS_CASE(["${host_cpu}"], [i?86|x86*], [], [ AS_IF([test "x$parport_use_ppdev" = "xno"], [ - AC_MSG_WARN([--disable-parport-ppdev is not supported by the host CPU]) + AC_MSG_ERROR([--disable-parport-ppdev is not supported by the host CPU]) ]) - parport_use_ppdev=yes ]) can_build_buspirate=yes @@ -433,7 +383,7 @@ AS_CASE([$host_os], ], [ is_cygwin=yes # sys/io.h needed under cygwin for parport access - AS_IF([test "x$build_parport" = "xyes"], [ + AS_IF([test "x$enable_parport" != "xno"], [ AC_CHECK_HEADERS([sys/io.h],[],AC_MSG_ERROR([Please install the cygwin ioperm package])) ]) ]) @@ -496,58 +446,10 @@ AS_IF([test "x$is_darwin" = "xyes"], [ AC_DEFINE([IS_DARWIN], [0], [0 if not building for Darwin.]) ]) -AS_IF([test "x$build_parport" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_PARPORT], [1], [1 if you want parport.]) -], [ - AC_DEFINE([BUILD_PARPORT], [0], [0 if you don't want parport.]) -]) - -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$ADAPTER_VAR([dummy])" != "xno"], [ build_bitbang=yes ]) -AS_IF([test "x$build_ep93xx" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_EP93XX], [1], [1 if you want ep93xx.]) -], [ - AC_DEFINE([BUILD_EP93XX], [0], [0 if you don't want ep93xx.]) -]) - -AS_IF([test "x$build_at91rm9200" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_AT91RM9200], [1], [1 if you want at91rm9200.]) -], [ - AC_DEFINE([BUILD_AT91RM9200], [0], [0 if you don't want at91rm9200.]) -]) - -AS_IF([test "x$build_bcm2835gpio" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_BCM2835GPIO], [1], [1 if you want bcm2835gpio.]) -], [ - AC_DEFINE([BUILD_BCM2835GPIO], [0], [0 if you don't want bcm2835gpio.]) -]) - -AS_IF([test "x$build_imx_gpio" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_IMX_GPIO], [1], [1 if you want imx_gpio.]) -], [ - 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.]) ], [ @@ -606,10 +508,6 @@ AS_IF([test "x$enable_capstone" != xno], [ ]) ]) -AS_IF([test "x$enable_capstone" == xno], [ - AC_DEFINE([HAVE_CAPSTONE], [0], [0 if you don't have Capstone disassembly framework.]) -]) - for hidapi_lib in hidapi hidapi-hidraw hidapi-libusb; do PKG_CHECK_MODULES([HIDAPI],[$hidapi_lib],[ use_hidapi=yes @@ -627,11 +525,19 @@ PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [ PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no]) ]) -PKG_CHECK_MODULES([LIBGPIOD], [libgpiod < 2.0], [ +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([LIBGPIOD], [libgpiod], [ + use_libgpiod=yes + AC_DEFINE([HAVE_LIBGPIOD_V1], [1], [define if libgpiod is version v1.x]) + + 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]) @@ -642,21 +548,24 @@ PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], # Arg $3: What prerequisites are missing, to be shown in an error message # if an adapter was requested but cannot be enabled. m4_define([PROCESS_ADAPTERS], [ - m4_foreach([adapter], [$1], [ + m4_foreach([adapter_driver], [$1], [ 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]).) + AS_IF([test "x$ADAPTER_VAR([adapter_driver])" != "xno"], [ + AC_DEFINE([BUILD_]ADAPTER_SYM([adapter_driver]), [1], + [1 if you want the ]ADAPTER_DESC([adapter_driver]).) ], [ - AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [0], [0 if you do not want the ]ADAPTER_DESC([adapter]).) + AC_DEFINE([BUILD_]ADAPTER_SYM([adapter_driver]), [0], + [0 if you do not want the ]ADAPTER_DESC([adapter_driver]).) ]) ], [ - AS_IF([test "x$ADAPTER_VAR([adapter])" = "xyes"], [ - AC_MSG_ERROR([$3 is required for [adapter] "ADAPTER_DESC([adapter])".]) + AS_IF([test "x$ADAPTER_VAR([adapter_driver])" = "xyes"], [ + AC_MSG_ERROR([$3 is required for [adapter_driver] "ADAPTER_DESC([adapter_driver])".]) ]) - ADAPTER_VAR([adapter])=no - AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [0], [0 if you do not want the ]ADAPTER_DESC([adapter]).) + ADAPTER_VAR([adapter_driver])=no + AC_DEFINE([BUILD_]ADAPTER_SYM([adapter_driver]), [0], + [0 if you do not want the ]ADAPTER_DESC([adapter_driver]).) ]) - AM_CONDITIONAL(ADAPTER_SYM([adapter]), [test "x$ADAPTER_VAR([adapter])" != "xno"]) + AM_CONDITIONAL(ADAPTER_SYM([adapter_driver]), [test "x$ADAPTER_VAR([adapter_driver])" != "xno"]) ]) ]) @@ -666,20 +575,33 @@ PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libu 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"], [Linux libgpiod]) +PROCESS_ADAPTERS([DMEM_ADAPTER], ["x$is_linux" = "xyes" -a "x$ac_cv_header_sys_mman_h" = "xyes"], [Linux /dev/mem]) PROCESS_ADAPTERS([SYSFSGPIO_ADAPTER], ["x$is_linux" = "xyes"], [Linux sysfs]) PROCESS_ADAPTERS([REMOTE_BITBANG_ADAPTER], [true], [unused]) -PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_libjaylink" = "xyes"], [libjaylink-0.2]) -PROCESS_ADAPTERS([PCIE_ADAPTERS], ["x$is_linux" = "xyes"], [Linux build]) +PROCESS_ADAPTERS([CMSIS_DAP_TCP_ADAPTER], [true], [unused]) +PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.2]) +PROCESS_ADAPTERS([XVC_ADAPTERS], + ["x$is_linux" = "xyes" -a "x$ac_cv_header_linux_pci_h" = "xyes" -a "x$ac_cv_header_sys_mman_h" = "xyes"], + [Linux build with headers linux/pci.h and sys/mman.h]) PROCESS_ADAPTERS([SERIAL_PORT_ADAPTERS], ["x$can_build_buspirate" = "xyes"], [internal error: validation should happen beforehand]) -PROCESS_ADAPTERS([LINUXSPIDEV_ADAPTER], ["x$is_linux" = "xyes"], [Linux spidev]) +PROCESS_ADAPTERS([PARALLEL_PORT_ADAPTER], [true], [unused]) +PROCESS_ADAPTERS([LINUXSPIDEV_ADAPTER], ["x$is_linux" = "xyes" -a "x$ac_cv_header_linux_spi_spidev_h" = "xyes"], + [Linux spidev]) PROCESS_ADAPTERS([VDEBUG_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([JTAG_DPI_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([JTAG_VPI_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([RSHIM_ADAPTER], ["x$can_build_rshim" = "xyes"], [internal error: validation should happen beforehand]) PROCESS_ADAPTERS([AMTJTAGACCEL_ADAPTER], [true], [unused]) +PROCESS_ADAPTERS([HOST_ARM_BITBANG_ADAPTERS], ["x$ac_cv_header_sys_mman_h" = "xyes"], [header sys/mman.h]) +PROCESS_ADAPTERS([HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS], ["x$ac_cv_header_sys_mman_h" = "xyes"], [header sys/mman.h]) PROCESS_ADAPTERS([DUMMY_ADAPTER], [true], [unused]) +PROCESS_ADAPTERS([NETWORK_ADAPTERS], [true], [unused]) + +AS_IF([test "x$enable_xvc" != "xno"], [ + build_bitbang=yes +]) AS_IF([test "x$enable_linuxgpiod" != "xno"], [ build_bitbang=yes @@ -693,6 +615,26 @@ AS_IF([test "x$enable_remote_bitbang" != "xno"], [ build_bitbang=yes ]) +AS_IF([test "x$enable_bcm2835gpio" != "xno"], [ + build_bitbang=yes +]) + +AS_IF([test "x$enable_imx_gpio" != "xno"], [ + build_bitbang=yes +]) + +AS_IF([test "x$enable_am335xgpio" != "xno"], [ + build_bitbang=yes +]) + +AS_IF([test "x$enable_ep93xx" != "xno"], [ + build_bitbang=yes +]) + +AS_IF([test "x$enable_at91rm9200" != "xno"], [ + build_bitbang=yes +]) + AS_IF([test "x$enable_stlink" != "xno" -o "x$enable_ti_icdi" != "xno" -o "x$enable_nulink" != "xno"], [ AC_DEFINE([BUILD_HLADAPTER], [1], [1 if you want the High Level JTAG driver.]) AM_CONDITIONAL([HLADAPTER], [true]) @@ -703,6 +645,8 @@ AS_IF([test "x$enable_stlink" != "xno" -o "x$enable_ti_icdi" != "xno" -o "x$enab AM_CONDITIONAL([HLADAPTER_STLINK], [test "x$enable_stlink" != "xno"]) AM_CONDITIONAL([HLADAPTER_ICDI], [test "x$enable_ti_icdi" != "xno"]) AM_CONDITIONAL([HLADAPTER_NULINK], [test "x$enable_nulink" != "xno"]) +AM_CONDITIONAL([CMSIS_DAP_CORE], + [test "x$enable_cmsis_dap" != "xno" -o "x$enable_cmsis_dap_v2" != "xno" -o "x$enable_cmsis_dap_tcp" != "xno"]) # Presto needs the bitq module AS_IF([test "x$enable_presto" != "xno"], [ @@ -715,13 +659,7 @@ AS_IF([test "x$enable_esp_usb_jtag" != "xno"], [ ]) AM_CONDITIONAL([RELEASE], [test "x$build_release" = "xyes"]) -AM_CONDITIONAL([PARPORT], [test "x$build_parport" = "xyes"]) AM_CONDITIONAL([GIVEIO], [test "x$parport_use_giveio" = "xyes"]) -AM_CONDITIONAL([EP93XX], [test "x$build_ep93xx" = "xyes"]) -AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"]) -AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"]) -AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) -AM_CONDITIONAL([AM335XGPIO], [test "x$build_am335xgpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"]) @@ -735,11 +673,11 @@ AM_CONDITIONAL([USE_LIBFTDI], [test "x$use_libftdi" = "xyes"]) 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([DMEM], [test "x$build_dmem" = "xyes"]) AM_CONDITIONAL([HAVE_CAPSTONE], [test "x$enable_capstone" != "xno"]) AM_CONDITIONAL([HAVE_JIMTCL_PKG_CONFIG], [test "x$have_jimtcl_pkg_config" = "xyes"]) + AM_CONDITIONAL([USE_GCOV], [test "x$enable_gcov" = "xyes"]) # Look for environ alternatives. Possibility #1: is environ in unistd.h or stdlib.h? @@ -779,11 +717,13 @@ AC_DEFINE([_GNU_SOURCE],[1],[Use GNU C library extensions (e.g. stdndup).]) GCC_WARNINGS="-Wall -Wstrict-prototypes -Wformat-security -Wshadow" AS_IF([test "x${gcc_wextra}" = "xyes"], [ GCC_WARNINGS="${GCC_WARNINGS} -Wextra -Wno-unused-parameter" + GCC_WARNINGS="${GCC_WARNINGS} -Wno-gnu-folding-constant" 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" + GCC_WARNINGS="${GCC_WARNINGS} -Wsign-compare" ]) AS_IF([test "x${gcc_werror}" = "xyes"], [ GCC_WARNINGS="${GCC_WARNINGS} -Werror" @@ -810,28 +750,52 @@ AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ AC_MSG_WARN([Using the internal jimtcl is deprecated and will not be possible in the future.]) ]) +AS_IF([test "x$enable_amtjtagaccel" != "xno"], [ + echo + echo + AC_MSG_WARN([Amontec JTAG-Accelerator adapter is deprecated and support will be removed in the next release!]) +]) +AS_IF([test "x$build_gw16012" = "xyes"], [ + echo + echo + AC_MSG_WARN([Gateworks GW16012 JTAG adapter is deprecated and support will be removed in the next release!]) +]) + +AS_IF([test "x$parport_use_giveio" = "xyes" || test [ "x$enable_parport" != "xno" -a "x$parport_use_ppdev" = "xno"]], [ + echo + echo + AC_MSG_WARN([Parallel port access with direct I/O is deprecated and support will be removed in the next release!]) +]) + echo echo echo OpenOCD configuration summary echo --------------------------------------------------- -m4_foreach([adapter], [USB1_ADAPTERS, +m4_foreach([adapter_driver], [USB1_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, + DMEM_ADAPTER, SYSFSGPIO_ADAPTER, REMOTE_BITBANG_ADAPTER, - LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS, + LIBJAYLINK_ADAPTERS, XVC_ADAPTERS, + SERIAL_PORT_ADAPTERS, + PARALLEL_PORT_ADAPTER, + NETWORK_ADAPTERS, LINUXSPIDEV_ADAPTER, VDEBUG_ADAPTER, JTAG_DPI_ADAPTER, JTAG_VPI_ADAPTER, RSHIM_ADAPTER, AMTJTAGACCEL_ADAPTER, + HOST_ARM_BITBANG_ADAPTERS, + HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS, + CMSIS_DAP_TCP_ADAPTER, DUMMY_ADAPTER, OPTIONAL_LIBRARIES, COVERAGE], - [s=m4_format(["%-41s"], ADAPTER_DESC([adapter])) - AS_CASE([$ADAPTER_VAR([adapter])], + [s=m4_format(["%-49s"], ADAPTER_DESC([adapter_driver])) + AS_CASE([$ADAPTER_VAR([adapter_driver])], [auto], [ echo "$s"yes '(auto)' ], @@ -843,8 +807,8 @@ m4_foreach([adapter], [USB1_ADAPTERS, ], [ AC_MSG_ERROR(m4_normalize([ - Error in [adapter] "ADAPTER_ARG([adapter])": Variable "ADAPTER_VAR([adapter])" - has invalid value "$ADAPTER_VAR([adapter])".])) + Error in [adapter_driver] "ADAPTER_ARG([adapter_driver])": Variable "ADAPTER_VAR([adapter_driver])" + has invalid value "$ADAPTER_VAR([adapter_driver])".])) ]) ]) echo diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules index 29f8d7a6d4..775a25f249 100644 --- a/contrib/60-openocd.rules +++ b/contrib/60-openocd.rules @@ -190,6 +190,10 @@ 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" +# Microchip RISC-V Debug +ATTRS{idVendor}=="1514", ATTRS{idProduct}=="2008", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1514", ATTRS{idProduct}=="200a", 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" @@ -216,6 +220,11 @@ ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="06ad", MODE="660", GROUP="plugdev", # USBprog with OpenOCD firmware ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev", TAG+="uaccess" +# WCH CH347T chip in mode 3 +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55dd", MODE="660", GROUP="plugdev", TAG+="uaccess" +# WCH CH347F chip +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55de", MODE="660", GROUP="plugdev", TAG+="uaccess" + # TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -245,11 +254,15 @@ ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="1106", MODE="660", GROUP="plugdev", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1002", MODE="660", GROUP="plugdev", TAG+="uaccess" +# T-Head CK-Link Lite (PingTouGe Semiconductor) +ATTRS{idVendor}=="32bf", ATTRS{idProduct}=="b210", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Bouffalo Lab BL616/BL702 CK-Link clones +ATTRS{idVendor}=="42bf", ATTRS{idProduct}=="b210", 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 diff --git a/contrib/firmware/angie/c/Makefile b/contrib/firmware/angie/c/Makefile index 1bcc1f7d1e..a8817daa16 100644 --- a/contrib/firmware/angie/c/Makefile +++ b/contrib/firmware/angie/c/Makefile @@ -22,6 +22,8 @@ AS = $(PREFIX)sdas8051 # the OpenOCD driver, but the resulting file is smaller. PACKIHX = $(PREFIX)packihx +MAKEBIN = $(PREFIX)makebin + # GNU binutils size. Used to print the size of the IHX file generated by SDCC. SIZE = size @@ -38,10 +40,8 @@ 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 +OBJECTS = main.rel usb.rel delay.rel USBJmpTb.rel gpif.rel i2c.rel serial.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 \ @@ -73,7 +73,7 @@ clean: rm -f *.asm *.lst *.rel *.rst *.sym *.ihx *.lk *.map *.mem bin: angie_firmware.ihx - makebin -p angie_firmware.ihx angie_firmware.bin + $(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/include/i2c.h b/contrib/firmware/angie/c/include/i2c.h index d0404923b3..7a199c15a5 100644 --- a/contrib/firmware/angie/c/include/i2c.h +++ b/contrib/firmware/angie/c/include/i2c.h @@ -14,6 +14,7 @@ #include #include +bool get_status(void); void start_cd(void); void repeated_start(void); void stop_cd(void); diff --git a/contrib/firmware/angie/c/include/io.h b/contrib/firmware/angie/c/include/io.h index 19289d11d8..447aec3b4c 100644 --- a/contrib/firmware/angie/c/include/io.h +++ b/contrib/firmware/angie/c/include/io.h @@ -14,44 +14,26 @@ #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 */ +#define PIN_SDA_DIR IOA0 /* PA1 Not Connected */ -#define PIN_RDWR_B IOA2 -#define PIN_CSI_B IOA3 -#define PIN_INIT_B IOA4 -#define PIN_PROGRAM_B IOA5 +#define PIN_RDWR_B IOA2 +#define PIN_SDA IOA3 +#define PIN_SCL 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 +/* PB0 Not Connected */ +/* PB1 Not Connected */ +/* PB2 Not Connected */ +/* PB3 Not Connected */ +/* PB4 Not Connected */ +/* PB5 Not Connected */ /* 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 @@ -63,10 +45,10 @@ /* PC7 Not Connected */ /* PORT D */ -#define PIN_SDA IOD0 -#define PIN_SCL IOD1 -#define PIN_SDA_DIR IOD2 -#define PIN_SCL_DIR IOD3 +/* PD0 Not Connected */ +/* PD1 Not Connected */ +/* PD2 Not Connected */ +/* PD3 Not Connected */ /* PD4 Not Connected */ /* PD5 Not Connected */ /* PD6 Not Connected */ diff --git a/contrib/firmware/angie/c/include/jtag.h b/contrib/firmware/angie/c/include/jtag.h deleted file mode 100644 index 6d5df64805..0000000000 --- a/contrib/firmware/angie/c/include/jtag.h +++ /dev/null @@ -1,31 +0,0 @@ -/* 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/protocol.h b/contrib/firmware/angie/c/include/protocol.h deleted file mode 100644 index a12644b27d..0000000000 --- a/contrib/firmware/angie/c/include/protocol.h +++ /dev/null @@ -1,20 +0,0 @@ -/* 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 index c22476a1a6..735ccaa8a7 100644 --- a/contrib/firmware/angie/c/include/reg_ezusb.h +++ b/contrib/firmware/angie/c/include/reg_ezusb.h @@ -634,10 +634,10 @@ SFRX(CT4, 0xE6FE); 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); +SFRX(EP2FIFOBUF[1024], 0xF000); +SFRX(EP4FIFOBUF[1024], 0xF400); +SFRX(EP6FIFOBUF[1024], 0xF800); +SFRX(EP8FIFOBUF[1024], 0xFC00); /* Error Correction Code (ECC) Registers (FX2LP/FX1 only) */ SFRX(ECCCFG, 0xE628); diff --git a/contrib/firmware/angie/c/include/usb.h b/contrib/firmware/angie/c/include/usb.h index ad8be787e4..fb4067d621 100644 --- a/contrib/firmware/angie/c/include/usb.h +++ b/contrib/firmware/angie/c/include/usb.h @@ -104,7 +104,7 @@ struct usb_endpoint_descriptor { struct usb_language_descriptor { uint8_t blength; /**< Size of this descriptor in bytes. */ uint8_t bdescriptortype; /**< STRING descriptor type. */ - uint16_t wlangid[]; /**< LANGID codes. */ + uint16_t wlangid; /**< LANGID codes. */ }; /** USB String Descriptor. See USB 2.0 Spec */ @@ -125,13 +125,7 @@ struct setup_data { 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; +extern volatile __xdata __at(0xE6B8) struct setup_data setup_data; /* * USB Request Types (bmRequestType): See USB 2.0 Spec @@ -278,8 +272,8 @@ 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); +bool usb_handle_vcommands(void); +void set_gpif_cnt(uint32_t count); void i2c_recieve(void); void ep_init(void); diff --git a/contrib/firmware/angie/c/src/gpif.c b/contrib/firmware/angie/c/src/gpif.c index f4028be400..0e0d01300d 100644 --- a/contrib/firmware/angie/c/src/gpif.c +++ b/contrib/firmware/angie/c/src/gpif.c @@ -19,15 +19,15 @@ const char wavedata[128] = { /* 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, +/* LenBr */ 0x01, 0x3F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x02, 0x07, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, +/* Output*/ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +/* LFun */ 0x00, 0x09, 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, +/* LenBr */ 0x01, 0xBF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +/* LFun */ 0x00, 0x09, 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, @@ -47,7 +47,7 @@ const char flowstates[36] = { /* DO NOT EDIT ... */ const char initdata[7] = { -/* Regs */ 0xE0, 0x00, 0x00, 0x07, 0xEE, 0xF2, 0x00 +/* Regs */ 0xE0, 0x00, 0x00, 0x03, 0xEE, 0xF1, 0x00 }; /* END DO NOT EDIT */ diff --git a/contrib/firmware/angie/c/src/i2c.c b/contrib/firmware/angie/c/src/i2c.c index 10a463bf7d..4cf82955fc 100644 --- a/contrib/firmware/angie/c/src/i2c.c +++ b/contrib/firmware/angie/c/src/i2c.c @@ -12,14 +12,26 @@ #include "delay.h" #include "reg_ezusb.h" +bool get_status(void) +{ + PIN_SDA_DIR = 1; + OEA = 0xF7; + delay_us(1); + bool sda_state = PIN_SDA; + PIN_T0 = sda_state; + delay_us(1); + OEA = 0xFF; + delay_us(1); + return sda_state; +} + void start_cd(void) { - PIN_SCL_DIR = 0; - PIN_SDA_DIR = 0; + PIN_SDA_DIR = 0; // SP6 SDA: OUT delay_us(10); - PIN_SDA = 0; //SDA = 1; + PIN_SDA = 0; delay_us(1); - PIN_SCL = 0; //SCL = 1; + PIN_SCL = 0; delay_us(1); } @@ -43,9 +55,7 @@ void stop_cd(void) delay_us(1); PIN_SDA = 1; delay_us(1); - PIN_SDA_DIR = 1; - delay_us(1); - PIN_SCL_DIR = 1; + PIN_SDA_DIR = 1; // SP6 SDA: IN delay_us(1); } @@ -79,16 +89,16 @@ void send_nack(void) bool get_ack(void) { - PIN_SDA_DIR = 1; + PIN_SDA_DIR = 1; // SP6 SDA: IN delay_us(1); - OED = 0xFE; + OEA = 0xF7; // FX2 SDA: IN PIN_SCL = 1; delay_us(1); bool ack = PIN_SDA; PIN_SCL = 0; delay_us(1); - OED = 0xFF; - PIN_SDA_DIR = 0; + OEA = 0xFF; // FX2 SDA: OUT + PIN_SDA_DIR = 0; // SP6 SDA: OUT delay_us(1); return ack; } @@ -123,8 +133,8 @@ void send_byte(uint8_t input) uint8_t receive_byte(void) { - PIN_SDA_DIR = 1; //FX2 <-- FPGA - OED = 0xFE; + PIN_SDA_DIR = 1; // SP6 SDA: IN + OEA = 0xF7; // FX2 SDA: IN uint8_t input = 0x00; for (uint8_t i = 0; i < 8; i++) { PIN_SCL = 1; @@ -138,7 +148,7 @@ uint8_t receive_byte(void) PIN_SCL = 0; delay_us(1); } - OED = 0xFF; - PIN_SDA_DIR = 0; + OEA = 0xFF; // FX2 SDA: OUT + PIN_SDA_DIR = 0; // SP6 SDA: OUT return input; } diff --git a/contrib/firmware/angie/c/src/jtag.c b/contrib/firmware/angie/c/src/jtag.c deleted file mode 100644 index 9a44cd0bfc..0000000000 --- a/contrib/firmware/angie/c/src/jtag.c +++ /dev/null @@ -1,674 +0,0 @@ -// 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 index 9290af2ab5..8729b3ecba 100644 --- a/contrib/firmware/angie/c/src/main.c +++ b/contrib/firmware/angie/c/src/main.c @@ -11,13 +11,12 @@ *****************************************************************************/ #include "usb.h" +#include "serial.h" #include "delay.h" -#include "protocol.h" #include "reg_ezusb.h" -#include #include -extern void sudav_isr(void)__interrupt SUDAV_ISR; +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; @@ -65,7 +64,7 @@ void gpif_init(void); int main(void) { CPUCS = ((CPUCS & ~bmclkspd) | (CLK_48M << 3) | CLKOE); /* required for sio0_init */ - sio0_init(57600); /* needed for printf */ + sio0_init(115200); /* needed for printf */ ep_init(); gpif_init(); @@ -74,12 +73,10 @@ int main(void) /* Perform ReNumeration */ USBCS |= (DISCON | RENUM); - delay_ms(250); + delay_ms(50); USBCS &= ~DISCON; - /* Begin executing command(s). This function never returns. */ - command_loop(); - - /* Never reached, but SDCC complains about missing return statement */ - return 0; + /* stay here */ + while (1) + ; } diff --git a/contrib/firmware/angie/c/src/protocol.c b/contrib/firmware/angie/c/src/protocol.c deleted file mode 100644 index e32808db8f..0000000000 --- a/contrib/firmware/angie/c/src/protocol.c +++ /dev/null @@ -1,192 +0,0 @@ -// 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/usb.c b/contrib/firmware/angie/c/src/usb.c index ed23dcfa5a..4b3db0a60f 100644 --- a/contrib/firmware/angie/c/src/usb.c +++ b/contrib/firmware/angie/c/src/usb.c @@ -11,133 +11,119 @@ *****************************************************************************/ #include "usb.h" -#include "stdint.h" #include "delay.h" #include "io.h" #include "reg_ezusb.h" -#include -#include -#include +#include "fx2macros.h" +#include "serial.h" #include "i2c.h" +#include +#include +#include -/* 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; +// #define PRINTF_DEBUG -volatile __xdata __at 0xE6B8 struct setup_data setup_data; +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 +#define NUM_ENDPOINTS 2 __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, + .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, + .blength = sizeof(struct usb_config_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_CONFIGURATION, + .wtotallength = sizeof(struct usb_config_descriptor) + + 2 * 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 */ + .iconfiguration = 2, /* 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, + .blength = sizeof(struct usb_interface_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_INTERFACE, + .binterfacenumber = 0, .balternatesetting = 0, - .bnumendpoints = NUM_ENDPOINTS, - .binterfaceclass = 0XFF, + .bnumendpoints = NUM_ENDPOINTS, + .binterfaceclass = 0XFF, .binterfacesubclass = 0x00, .binterfaceprotocol = 0x00, - .iinterface = 4 + .iinterface = 0 }; -__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_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_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_endpoint_descriptor bulk_ep4_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (4 | USB_DIR_IN), + .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, + .blength = sizeof(struct usb_interface_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_INTERFACE, + .binterfacenumber = 1, .balternatesetting = 0, - .bnumendpoints = 2, - .binterfaceclass = 0x0A, + .bnumendpoints = NUM_ENDPOINTS, + .binterfaceclass = 0x0A, .binterfacesubclass = 0x00, .binterfaceprotocol = 0x00, - .iinterface = 0x00 + .iinterface = 0 }; __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 + .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 + .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 */ + .blength = 4, + .bdescriptortype = DESCRIPTOR_TYPE_STRING, + .wlangid = 0x0409 /* US English */ }; __code struct usb_string_descriptor strmanufacturer = @@ -149,156 +135,146 @@ __code struct usb_string_descriptor strproduct = __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] = { +__code struct usb_string_descriptor *__code en_string_descriptors[3] = { &strmanufacturer, &strproduct, - &strserialnumber, - &strconfigdescr + &strserialnumber }; -void sudav_isr(void)__interrupt SUDAV_ISR +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 sof_isr(void)__interrupt(SOF_ISR) { } -void sutok_isr(void)__interrupt SUTOK_ISR +void sutok_isr(void)__interrupt(SUTOK_ISR) { } -void suspend_isr(void)__interrupt SUSPEND_ISR +void suspend_isr(void)__interrupt(SUSPEND_ISR) { } -void usbreset_isr(void)__interrupt USBRESET_ISR +void usbreset_isr(void)__interrupt(USBRESET_ISR) { } -void highspeed_isr(void)__interrupt HIGHSPEED_ISR +void highspeed_isr(void)__interrupt(HIGHSPEED_ISR) { } -void ep0ack_isr(void)__interrupt EP0ACK_ISR +void ep0ack_isr(void)__interrupt(EP0ACK_ISR) { } -void stub_isr(void)__interrupt STUB_ISR +void stub_isr(void)__interrupt(STUB_ISR) { } -void ep0in_isr(void)__interrupt EP0IN_ISR +void ep0in_isr(void)__interrupt(EP0IN_ISR) { } -void ep0out_isr(void)__interrupt EP0OUT_ISR +void ep0out_isr(void)__interrupt(EP0OUT_ISR) { } -void ep1in_isr(void)__interrupt EP1IN_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 +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 ep2_isr(void)__interrupt(EP2_ISR) { } -void ep4_isr(void)__interrupt EP4_ISR +void ep4_isr(void)__interrupt(EP4_ISR) { } -void ep6_isr(void)__interrupt EP6_ISR +void ep6_isr(void)__interrupt(EP6_ISR) { - ep6_out = true; + REVCTL = 0; /* REVCTL.0 and REVCTL.1 set to 0 */ + i2c_recieve(); /* Execute I2C communication */ EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ EPIRQ = 0x40; /* Clear individual EP6OUT IRQ */ - } -void ep8_isr(void)__interrupt EP8_ISR +void ep8_isr(void)__interrupt(EP8_ISR) { - EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ - EPIRQ = 0x80; /* Clear individual EP8IN IRQ */ + EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ + EPIRQ = 0x80; /* Clear individual EP8IN IRQ */ } -void ibn_isr(void)__interrupt IBN_ISR +void ibn_isr(void)__interrupt(IBN_ISR) { } -void ep0pingnak_isr(void)__interrupt EP0PINGNAK_ISR +void ep0pingnak_isr(void)__interrupt(EP0PINGNAK_ISR) { } -void ep1pingnak_isr(void)__interrupt EP1PINGNAK_ISR +void ep1pingnak_isr(void)__interrupt(EP1PINGNAK_ISR) { } -void ep2pingnak_isr(void)__interrupt EP2PINGNAK_ISR +void ep2pingnak_isr(void)__interrupt(EP2PINGNAK_ISR) { } -void ep4pingnak_isr(void)__interrupt EP4PINGNAK_ISR +void ep4pingnak_isr(void)__interrupt(EP4PINGNAK_ISR) { } -void ep6pingnak_isr(void)__interrupt EP6PINGNAK_ISR +void ep6pingnak_isr(void)__interrupt(EP6PINGNAK_ISR) { } -void ep8pingnak_isr(void)__interrupt EP8PINGNAK_ISR +void ep8pingnak_isr(void)__interrupt(EP8PINGNAK_ISR) { } -void errorlimit_isr(void)__interrupt ERRORLIMIT_ISR +void errorlimit_isr(void)__interrupt(ERRORLIMIT_ISR) { } -void ep2piderror_isr(void)__interrupt EP2PIDERROR_ISR +void ep2piderror_isr(void)__interrupt(EP2PIDERROR_ISR) { } -void ep4piderror_isr(void)__interrupt EP4PIDERROR_ISR +void ep4piderror_isr(void)__interrupt(EP4PIDERROR_ISR) { } -void ep6piderror_isr(void)__interrupt EP6PIDERROR_ISR +void ep6piderror_isr(void)__interrupt(EP6PIDERROR_ISR) { } -void ep8piderror_isr(void)__interrupt EP8PIDERROR_ISR +void ep8piderror_isr(void)__interrupt(EP8PIDERROR_ISR) { } -void ep2pflag_isr(void)__interrupt EP2PFLAG_ISR +void ep2pflag_isr(void)__interrupt(EP2PFLAG_ISR) { } -void ep4pflag_isr(void)__interrupt EP4PFLAG_ISR +void ep4pflag_isr(void)__interrupt(EP4PFLAG_ISR) { } -void ep6pflag_isr(void)__interrupt EP6PFLAG_ISR +void ep6pflag_isr(void)__interrupt(EP6PFLAG_ISR) { } -void ep8pflag_isr(void)__interrupt EP8PFLAG_ISR +void ep8pflag_isr(void)__interrupt(EP8PFLAG_ISR) { } -void ep2eflag_isr(void)__interrupt EP2EFLAG_ISR +void ep2eflag_isr(void)__interrupt(EP2EFLAG_ISR) { } -void ep4eflag_isr(void)__interrupt EP4EFLAG_ISR +void ep4eflag_isr(void)__interrupt(EP4EFLAG_ISR) { } -void ep6eflag_isr(void)__interrupt EP6EFLAG_ISR +void ep6eflag_isr(void)__interrupt(EP6EFLAG_ISR) { } -void ep8eflag_isr(void)__interrupt EP8EFLAG_ISR +void ep8eflag_isr(void)__interrupt(EP8EFLAG_ISR) { } -void ep2fflag_isr(void)__interrupt EP2FFLAG_ISR +void ep2fflag_isr(void)__interrupt(EP2FFLAG_ISR) { } -void ep4fflag_isr(void)__interrupt EP4FFLAG_ISR +void ep4fflag_isr(void)__interrupt(EP4FFLAG_ISR) { } -void ep6fflag_isr(void)__interrupt EP6FFLAG_ISR +void ep6fflag_isr(void)__interrupt(EP6FFLAG_ISR) { } -void ep8fflag_isr(void)__interrupt EP8FFLAG_ISR +void ep8fflag_isr(void)__interrupt(EP8FFLAG_ISR) { } -void gpifcomplete_isr(void)__interrupt GPIFCOMPLETE_ISR +void gpifcomplete_isr(void)__interrupt(GPIFCOMPLETE_ISR) { } -void gpifwaveform_isr(void)__interrupt GPIFWAVEFORM_ISR +void gpifwaveform_isr(void)__interrupt(GPIFWAVEFORM_ISR) { } @@ -348,63 +324,6 @@ void usb_reset_data_toggle(uint8_t ep) 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. * @@ -500,12 +419,17 @@ bool usb_handle_get_descriptor(void) case DESCRIPTOR_TYPE_STRING: if (setup_data.windex == 0) { /* Supply language descriptor */ - SUDPTRH = HI8(&language_descriptor); - SUDPTRL = LO8(&language_descriptor); + __xdata struct usb_language_descriptor temp_descriptor; + memcpy(&temp_descriptor, &language_descriptor, sizeof(language_descriptor)); + SUDPTRH = HI8(&temp_descriptor); + SUDPTRL = LO8(&temp_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]); + __xdata uint8_t temp_descriptors[3]; + memcpy(temp_descriptors, en_string_descriptors[descriptor_index - 1], + ((struct usb_string_descriptor *)en_string_descriptors[descriptor_index - 1])->blength); + SUDPTRH = HI8(temp_descriptors); + SUDPTRL = LO8(temp_descriptors); } else { return false; } @@ -523,15 +447,28 @@ bool usb_handle_get_descriptor(void) 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; + usb_reset_data_toggle(USB_DIR_IN | 4); + usb_reset_data_toggle(USB_DIR_OUT | 6); + usb_reset_data_toggle(USB_DIR_IN | 8); /* Unstall all valid OUT endpoints, reset bytecounts */ - EP1OUTCS = 0; - EP1OUTBC = 0; + EP2CS = 0; + EP4CS = 0; + EP6CS = 0; + EP8CS = 0; + syncdelay(3); + EP2BCH = 0; + EP2BCL = 0x80; + syncdelay(3); + EP4BCH = 0; + EP4BCL = 0x80; + syncdelay(3); + EP6BCH = 0; + EP6BCL = 0x80; + syncdelay(3); + EP8BCH = 0; + EP8BCL = 0x80; syncdelay(3); } @@ -551,14 +488,14 @@ void set_gpif_cnt(uint32_t count) * Vendor commands handling: */ #define VR_CFGOPEN 0xB0 -#define VR_CFGCLOSE 0xB1 +#define VR_DATAOUTOPEN 0xB2 uint8_t ix; uint8_t bcnt; uint8_t __xdata *eptr; uint16_t wcnt; uint32_t __xdata gcnt; -bool usb_handle_send_bitstream(void) +bool usb_handle_vcommands(void) { eptr = EP0BUF; /* points to EP0BUF 64-byte register */ wcnt = setup_data.wlength; /* total transfer count */ @@ -582,43 +519,69 @@ bool usb_handle_send_bitstream(void) /* 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 */ + /* Apply RPGM- pulse */ + PIN_PROGRAM_B = 0; + syncdelay(1); + /* Negate RPGM- pulse */ + PIN_PROGRAM_B = 1; + /* FPGA init time < 10mS */ + delay_ms(10); + /* Initialize GPIF interface transfer count */ + set_gpif_cnt(gcnt); PIN_RDWR_B = 0; - PIN_CSI_B = 0; - GPIFTRIG = GPIF_EP2; /* Trigger GPIF OUT transfer on EP2 */ - syncdelay(3); + PIN_SDA = 0; + /* Trigger GPIF OUT transfer on EP2 */ + GPIFTRIG = GPIF_EP2; + while (!(GPIFTRIG & BMGPIFDONE)) // poll GPIFTRIG.7 GPIF Done bit + ; + PIN_SDA = 1; + PIN_RDWR_B = 1; + #ifdef PRINTF_DEBUG + printf("Program SP6 Done.\n"); + #endif + /* Choose wich Waveform to use */ + GPIFWFSELECT = 0xF6; 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; - } + case VR_DATAOUTOPEN: + /* Clear bytecount / to allow new data in / to stops NAKing */ EP0BCH = 0; - EP0BCL = (uint8_t)(setup_data.wlength); /* Signal buffer is filled */ + 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]); + /* REVCTL.0 and REVCTL.1 set to 1 */ + REVCTL = 0x3; + /* Angie board FPGA bitstream download */ + PIN_RDWR_B = 0; + /* Initialize GPIF interface transfer count */ + GPIFTCB3 = (uint8_t)(((uint32_t)(gcnt) >> 24) & 0x000000ff); + GPIFTCB2 = (uint8_t)(((uint32_t)(gcnt) >> 16) & 0x000000ff); + GPIFTCB1 = (uint8_t)(((uint32_t)(gcnt) >> 8) & 0x000000ff); + GPIFTCB0 = (uint8_t)((uint32_t)(gcnt) & 0x000000ff); + /* Trigger GPIF OUT transfer on EP2 */ + GPIFTRIG = GPIF_EP2; + while (!(GPIFTRIG & BMGPIFDONE)) // poll GPIFTRIG.7 GPIF Done bit + ; + PIN_RDWR_B = 1; + /* Initialize GPIF interface transfer count */ + GPIFTCB3 = (uint8_t)(((uint32_t)(gcnt) >> 24) & 0x000000ff); + GPIFTCB2 = (uint8_t)(((uint32_t)(gcnt) >> 16) & 0x000000ff); + GPIFTCB1 = (uint8_t)(((uint32_t)(gcnt) >> 8) & 0x000000ff); + GPIFTCB0 = (uint8_t)((uint32_t)(gcnt) & 0x000000ff); + /* Initialize AUTOIN transfer count */ + EP4AUTOINLENH = (uint8_t)(((uint32_t)(gcnt) >> 8) & 0x000000ff); + EP4AUTOINLENL = (uint8_t)((uint32_t)(gcnt) & 0x000000ff); + /* Trigger GPIF IN transfer on EP4 */ + GPIFTRIG = BMGPIFREAD | GPIF_EP4; + while (!(GPIFTRIG & BMGPIFDONE)) // poll GPIFTRIG.7 GPIF Done bit + ; + /* REVCTL.0 and REVCTL.1 set to 0 */ + REVCTL = 0; break; default: return true; /* Error: unknown VR command */ @@ -633,8 +596,12 @@ void usb_handle_setup_data(void) { switch (setup_data.brequest) { case GET_STATUS: - if (!usb_handle_get_status()) - STALL_EP0(); + EP0BUF[0] = 0; + EP0BUF[1] = 0; + /* Send response */ + EP0BCH = 0; + EP0BCL = 2; + syncdelay(3); break; case CLEAR_FEATURE: if (!usb_handle_clear_feature()) @@ -672,8 +639,9 @@ void usb_handle_setup_data(void) case GET_INTERFACE: /* ANGIE only has one interface, return its number */ EP0BUF[0] = interface_descriptor00.binterfacenumber; + EP0BUF[1] = interface_descriptor01.binterfacenumber; EP0BCH = 0; - EP0BCL = 1; + EP0BCL = 2; syncdelay(3); break; case SET_INTERFACE: @@ -684,7 +652,7 @@ void usb_handle_setup_data(void) break; default: /* if not Vendor command, Stall EndPoint 0 */ - if (usb_handle_send_bitstream()) + if (usb_handle_vcommands()) STALL_EP0(); break; } @@ -695,29 +663,21 @@ void usb_handle_setup_data(void) */ void ep_init(void) { - EP1INCFG = 0xA0; - syncdelay(3); - EP1OUTCFG = 0xA0; - syncdelay(3); - EP2CFG = 0xA0; - syncdelay(3); - EP4CFG = 0x00; + EP1INCFG = 0x00; /* non VALID */ syncdelay(3); - EP6CFG = 0xA2; - syncdelay(3); - EP8CFG = 0xE2; + EP1OUTCFG = 0x00; /* non VALID */ syncdelay(3); - /* arm EP1-OUT */ - EP1OUTBC = 0; + /* JTAG */ + EP2CFG = 0xA2; /* VALID | OUT | BULK | 512 Bytes | Double buffer */ syncdelay(3); - EP1OUTBC = 0; + EP4CFG = 0xE2; /* VALID | IN | BULK | 512 Bytes | Double buffer */ syncdelay(3); - /* arm EP1-IN */ - EP1INBC = 0; + /* I2C */ + EP6CFG = 0xA2; /* VALID | OUT | BULK | 512 Bytes | Double buffer */ syncdelay(3); - EP1INBC = 0; + EP8CFG = 0xE2; /* VALID | IN | BULK | 512 Bytes | Double buffer */ syncdelay(3); /* arm EP6-OUT */ @@ -726,31 +686,45 @@ void ep_init(void) EP6BCL = 0x80; syncdelay(3); + /* REVCTL.0 and REVCTL.1 set to 1 */ + REVCTL = 0x3; + /* Arm both EP2 buffers to “prime the pump” */ + OUTPKTEND = 0x82; + syncdelay(3); + OUTPKTEND = 0x82; + syncdelay(3); + /* Standard procedure to reset FIFOs */ FIFORESET = BMNAKALL; /* NAK all transfers during the reset */ syncdelay(3); - FIFORESET = 0x02; /* reset EP2 FIFO */ + FIFORESET = BMNAKALL | 0x02; /* reset EP2 FIFO */ + syncdelay(3); + FIFORESET = BMNAKALL | 0x04; /* reset EP4 FIFO */ syncdelay(3); FIFORESET = 0x00; /* deactivate the NAK all */ syncdelay(3); + + /* configure EP2 in AUTO mode with 8-bit interface */ EP2FIFOCFG = 0x00; syncdelay(3); - EP2FIFOCFG = BMAUTOOUT; /* Automatic 8-bit GPIF OUT mode */ + EP2FIFOCFG = BMAUTOOUT; /* 8-bit Auto OUT mode */ + syncdelay(3); + EP4FIFOCFG = BMAUTOIN | BMZEROLENIN; /* 8-bit Auto IN 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 rdwr = EP6FIFOBUF[0]; //read: 1 + uint8_t reg_byte_check = EP6FIFOBUF[1]; //register given: 1 else: 0 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); + /* i2c bus state byte */ + EP8FIFOBUF[0] = get_status(); /* start: */ start_cd(); @@ -760,12 +734,10 @@ void i2c_recieve(void) 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(); - } + for (int i = 0; i < reg_byte_check; i++) { + send_byte(EP6FIFOBUF[i + 4]); + /* ack(): */ + ack = get_ack(); } /* repeated start: */ @@ -776,14 +748,14 @@ void i2c_recieve(void) ack = get_ack(); /* receive data */ - for (uint8_t i = 0; i < count - 1; i++) { + for (int i = 1; i < count; i++) { EP8FIFOBUF[i] = receive_byte(); /* send ack: */ send_ack(); } - EP8FIFOBUF[count - 1] = receive_byte(); + EP8FIFOBUF[count] = receive_byte(); /* send Nack: */ send_nack(); @@ -791,44 +763,46 @@ void i2c_recieve(void) /* stop */ stop_cd(); - EP8BCH = 0; //EP8 + EP8BCH = (count + 1) >> 8; //EP8 syncdelay(3); - EP8BCL = count; //EP8 + EP8BCL = count + 1; //EP8 EP6BCL = 0x80; //EP6 syncdelay(3); EP6BCL = 0x80; //EP6 } else { - uint8_t rdwr = EP6FIFOBUF[0]; //write + uint8_t rdwr = EP6FIFOBUF[0]; //write: 0 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(): */ + // i2c bus state byte + EP8FIFOBUF[0] = get_status(); + + /* start(): */ start_cd(); -/* address: */ + /* address: */ send_byte(address); //write -/* ack(): */ + /* ack(): */ if (!get_ack()) ack_cnt++; -/* send data */ - for (uint8_t i = 0; i < count; i++) { + /* send data */ + for (int i = 0; i < count; i++) { send_byte(EP6FIFOBUF[i + 3]); - /* get ack: */ if (!get_ack()) ack_cnt++; } -/* stop */ + /* stop */ stop_cd(); - EP8FIFOBUF[0] = ack_cnt; + EP8FIFOBUF[1] = ack_cnt; EP8BCH = 0; //EP8 syncdelay(3); - EP8BCL = 1; //EP8 + EP8BCL = 2; //EP8 EP6BCL = 0x80; //EP6 syncdelay(3); @@ -841,9 +815,6 @@ void i2c_recieve(void) **/ void interrupt_init(void) { - /* Enable Interrupts */ - EA = 1; - /* Enable USB interrupt (EIE register) */ EUSB = 1; EICON |= 0x20; @@ -851,17 +822,22 @@ void interrupt_init(void) /* Enable INT 2 & 4 Autovectoring */ INTSETUP |= (AV2EN | AV4EN); - /* Enable individual EP1OUT&IN & EP6&8 interrupts */ - EPIE |= 0xCC; + /* Enable individual EP6&8 interrupts */ + EPIE |= 0xC0; /* Clear individual USB interrupt IRQ */ - EPIRQ = 0xCC; + EPIRQ = 0xC0; /* Enable SUDAV interrupt */ USBIEN |= SUDAVI; /* Clear SUDAV interrupt */ USBIRQ = SUDAVI; + + /* Enable Interrupts (Do not confuse this with + * EA External Access pin, see ANGIE Schematic) + */ + EA = 1; } /** @@ -870,25 +846,12 @@ void interrupt_init(void) void io_init(void) { /* PORT A */ - PORTACFG = 0x01; /* 0: normal ou 1: alternate function (each bit) */ - OEA = 0xEF; /* all OUT exept INIT_B IN */ + PORTACFG = 0x0; /* 0: normal ou 1: alternate function (each bit) */ + OEA = 0xEF; 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) */ + PORTCCFG = 0x0; /* 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/src/angie_bitstream.ucf b/contrib/firmware/angie/hdl/src/angie_bitstream.ucf index 9eb0c85c39..48c5b94079 100644 --- a/contrib/firmware/angie/hdl/src/angie_bitstream.ucf +++ b/contrib/firmware/angie/hdl/src/angie_bitstream.ucf @@ -1,8 +1,8 @@ ## 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 +## Project Context: nanoXplore USB to JTAG/I2C Adapter Board, Spartan6 +## Design Name: ANGIE USB to JTAG/I2C Adapter FPGA source code +## Module Name: angie_bitstream.ucf ## Target Device: XC6SLX9-2 TQ144 ## Tool versions: ISE Webpack 13.2 -> 14.2 ## Author: Ahmed BOUDJELIDA nanoXplore SAS @@ -10,41 +10,65 @@ # 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' ; +CONFIG VCCAUX = "3.3"; + +# Timing +# net IH24 period = 40; # Constrain at 25MHz +# net IH40 period = 25; # Constrain at 40MHz +# DCMs placement on Spartan6 +# INST S6MOD_CKMUL.H48_DCM LOC = DCM0; + +# Clock 48MHz +net IFCLK_I LOC = 'P123' ; + +net GD_IO<0> LOC = 'P48' ; +net GD_IO<1> LOC = 'P43' ; +net GD_IO<2> LOC = 'P44' ; +net GD_IO<3> LOC = 'P45' ; +net GD_IO<4> LOC = 'P46' ; +net GD_IO<5> LOC = 'P61' ; +net GD_IO<6> LOC = 'P62' ; +net GD_IO<7> LOC = 'P65' ; + +net PA2_I LOC = 'P47' ; +#net PA3_I LOC = 'P64' ; +net JPW_I LOC = 'P14' ; + +net GCTL0_I LOC = 'P70' ; +#net GCTL1_I LOC = 'P55' ; +#net GCTL2_I LOC = 'P67' ; +net GRDY1_I LOC = 'P118' ; + +#net SDA_IO LOC = 'P50' ; +net SDA_IO LOC = 'P64' ; #PA3 +#net SCL_I LOC = 'P51' ; +net SCL_I LOC = 'P39' ; #PA4 switch +net SDA_DIR_I LOC = 'P66' ; #PA0 switch +#net SCL_DIR_I LOC = 'P57' ; + +net SO_SDA_OUT_O LOC = 'P140' ; +net SO_SDA_IN_I LOC = 'P1' ; +net SO_SCL_O LOC = 'P137' ; + +net SO_TRST_O LOC = 'P32' ; +net SO_TMS_O LOC = 'P27' ; +net SO_TCK_O LOC = 'P30' ; +net SO_TDI_O LOC = 'P26' ; +net SO_SRST_O LOC = 'P12' ; +net SI_TDO_I LOC = 'P16' ; + +net ST_0_O LOC = 'P29' ; +net ST_1_O LOC = 'P21' ; +net ST_2_O LOC = 'P11' ; +net ST_3_O LOC = 'P7' ; +net ST_4_O LOC = 'P134' ; +net ST_5_O LOC = 'P139' ; + +net FTP_O<0> LOC = 'P121' ; +net FTP_O<1> LOC = 'P120' ; +net FTP_O<2> LOC = 'P119' ; +net FTP_O<3> LOC = 'P116' ; +net FTP_O<4> LOC = 'P111' ; +net FTP_O<5> LOC = 'P112' ; +net FTP_O<6> LOC = 'P115' ; +net FTP_O<7> LOC = 'P114' ; diff --git a/contrib/firmware/angie/hdl/src/angie_bitstream.vhd b/contrib/firmware/angie/hdl/src/angie_bitstream.vhd index 6004bf2ff5..737a84ce58 100644 --- a/contrib/firmware/angie/hdl/src/angie_bitstream.vhd +++ b/contrib/firmware/angie/hdl/src/angie_bitstream.vhd @@ -1,103 +1,415 @@ -- 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 +-- Project Context: nanoXplore USB to JTAG/I2C Adapter Board, Spartan6 +-- Design Name: ANGIE USB to JTAG/I2C Adapter FPGA source code +-- Module Name: angie_bitstream.vhd -- Target Device: XC6SLX9-2 TQ144 -- Tool versions: ISE Webpack 13.2 -> 14.2 -- Author: Ahmed BOUDJELIDA nanoXplore SAS ---------------------------------------------------------------------------- - +library work; +use work.all; 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 + +entity angie_bitstream is port( + SDA_IO : inout std_logic; + SDA_DIR_I : in std_logic; + SCL_I : in std_logic; + + JPW_I : in std_logic; --Devkit power + + SO_SDA_OUT_O : out std_logic; + SO_SDA_IN_I : in std_logic; + SO_SCL_O : out std_logic; + + ST_0_O : out std_logic; + ST_1_O : out std_logic; + ST_2_O : out std_logic; + ST_3_O : out std_logic; + ST_4_O : out std_logic; + ST_5_O : out std_logic; + + SO_TRST_O : out std_logic; + SO_TMS_O : out std_logic; + SO_TCK_O : out std_logic; + SO_TDI_O : out std_logic; + SO_SRST_O : out std_logic; + SI_TDO_I : in std_logic; + + PA2_I : in std_logic; -- GPIF IN + + -- Clock 48MHz + IFCLK_I : in std_logic; + + GCTL0_I : in std_logic; + GRDY1_I : out std_logic; + GD_IO : inout std_logic_vector(7 downto 0); + FTP_O : out std_logic_vector(15 downto 0) +); +end angie_bitstream; + +architecture A_angie_bitstream of angie_bitstream is +----------------------------------------Fifo out (PC to devkit) +signal rst_o, clk_wr_o, clk_rd_o : std_logic; +signal write_en_o, read_en_o : std_logic; +signal data_in_o, data_out_o : std_logic_vector(7 downto 0); +signal empty_o, full_o : std_logic; + +----------------------------------------Fifo in (devkit to PC) +signal rst_i, clk_wr_i, clk_rd_i : std_logic; +signal write_en_i, read_en_i : std_logic; +signal data_in_i, data_out_i : std_logic_vector(7 downto 0); +signal empty_i, full_i : std_logic; + +signal wr_o, rd_i : std_logic; + +----------------------------------------MAE +signal transit1, transit2 : std_logic; + +----------------------------------------DFF +signal pa2_dff_clk, pa2_dff_rst, pa2_dff_d, pa2_dff_q : std_logic; +signal trst_clk, trst_rst, trst_d, trst_q : std_logic; +signal tms_clk, tms_rst, tms_d, tms_q : std_logic; +signal tdi_clk, tdi_rst, tdi_d, tdi_q : std_logic; +signal tdo_clk, tdo_rst, tdo_d, tdo_q : std_logic; + +----------------------------------------clk_div +signal clk_div_in, clk_div_out, reset_clk_div : std_logic; +signal clk_div2_in, clk_div2_out, reset_clk_div2 : std_logic; + +----------------------------------------MAE +type State_Type is (IDLE, WRITE_OUT, WRITE_IN, DELAY, READ_IN); +signal state, state2 : State_Type; +signal reset_mae, reset_mae2 : std_logic; + +-- Add Component DFF +component DFF + Port ( + clk : in std_logic; + reset : in std_logic; + d : in std_logic; + q : out std_logic + ); +end component; + +-- Add Component Clk_div +component clk_div +Port ( + clk_in : in std_logic; + reset : in std_logic; + clk_out : out std_logic ); -end S609; +end component; + +-- Add component FIFO 64B +component fifo_generator_v9_3 +PORT ( + rst : IN STD_LOGIC; + wr_clk : IN STD_LOGIC; + rd_clk : IN STD_LOGIC; + din : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + wr_en : IN STD_LOGIC; + rd_en : IN STD_LOGIC; + dout : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + full : OUT STD_LOGIC; + empty : OUT STD_LOGIC + ); +end component; + +signal state1_debug, state2_debug : std_logic; -architecture A_S609 of S609 is begin +-------------------------------------------------------------I2C : +SDA_IO <= not(SO_SDA_IN_I) when (SDA_DIR_I = '1') else 'Z'; +SO_SDA_OUT_O <= SDA_IO; +ST_5_O <= SDA_DIR_I; ---Directions: -ST_0 <= '0'; -ST_1 <= '1'; +SO_SCL_O <= SCL_I when (JPW_I = '1') else '0'; +ST_4_O <= '0'; ---TDO: -TDO <= not SI_TDO; +------------------------------------------------------------JTAG : +-- Instantiate the Clk div by 10 +clk_div_inst : clk_div +port map ( + clk_in => clk_div_in, + reset => reset_clk_div, + clk_out => clk_div_out +); +-- Instantiate the Clk div by 10 +clk_div2_inst : clk_div +port map ( + clk_in => clk_div2_in, + reset => reset_clk_div2, + clk_out => clk_div2_out +); ---TRST - TCK - TMS - TDI: -SO_TRST <= TRST; -SO_TMS <= TMS; -SO_TCK <= TCK; -SO_TDI <= TDI; -ST_2 <= SRST; -SO_SRST <= '0'; +-- Instantiate DFFs +DFF_inst_PA2 : DFF +port map ( + clk => pa2_dff_clk, + reset => pa2_dff_rst, + d => pa2_dff_d, + q => pa2_dff_q +); + +DFF_inst_TRST : DFF +port map ( + clk => trst_clk, + reset => trst_rst, + d => trst_d, + q => trst_q +); -SO_SCL <= SCL; +DFF_inst_TMS : DFF +port map ( + clk => tms_clk, + reset => tms_rst, + d => tms_d, + q => tms_q +); -SDA <= not(SO_SDA_IN) when (SDA_DIR = '1') else 'Z'; -SO_SDA_OUT <= SDA; +DFF_inst_TDI : DFF +port map ( + clk => tdi_clk, + reset => tdi_rst, + d => tdi_d, + q => tdi_q +); + +DFF_inst_TDO : DFF +port map ( + clk => tdo_clk, + reset => tdo_rst, + d => tdo_d, + q => tdo_q +); -process(SDA_DIR) +-- Instantiate the FIFO OUT +U0 : fifo_generator_v9_3 +port map ( + rst => rst_o, + wr_clk => clk_wr_o, + rd_clk => clk_rd_o, + din => data_in_o, + wr_en => write_en_o, + rd_en => read_en_o, + dout => data_out_o, + full => full_o, + empty => empty_o +); +-- Instantiate the FIFO IN +U1 : fifo_generator_v9_3 +port map ( + rst => rst_i, + wr_clk => clk_wr_i, + rd_clk => clk_rd_i, + din => data_in_i, + wr_en => write_en_i, + rd_en => read_en_i, + dout => data_out_i, + full => full_i, + empty => empty_i +); + +--------------- clock dividers +clk_div_in <= IFCLK_I; -- 48Mhz +clk_div2_in <= clk_div_out; -- 24Mhz + +--------------- DFFs +pa2_dff_clk <= IFCLK_I; +trst_clk <= IFCLK_I; +tms_clk <= IFCLK_I; +tdi_clk <= IFCLK_I; +tdo_clk <= IFCLK_I; + +--------------- FIFOs +clk_wr_o <= IFCLK_I; +clk_rd_o <= clk_div2_out; +clk_wr_i <= clk_div2_out; +clk_rd_i <= IFCLK_I; + +--------------------------- GPIF ready : +GRDY1_I <= '1'; + +-------------------------------PA2 DFF : +pa2_dff_rst <= '0'; +pa2_dff_d <= PA2_I; + +-------------------- FX2<->Fifo Enable pins : +write_en_o <= not(wr_o) and not(GCTL0_I); +read_en_i <= not(rd_i) and not(GCTL0_I); + +---------------- FX2->Fifo Data : +data_in_o <= GD_IO; + +------------ FIFO_OUT->Devkit : +SO_TRST_O <= trst_q; +trst_d <= data_out_o(4); +SO_TMS_O <= tms_q; +tms_d <= data_out_o(3); +SO_TDI_O <= tdi_q; +tdi_d <= data_out_o(1); +------------ +SO_TCK_O <= data_out_o(0); + +-------------------- FIFO_OUT->FIFO_IN : +--data_in_i <= data_out_o; + +-------------------- FIFO_IN<-Devkit : +data_in_i(0) <= '0'; +data_in_i(1) <= '0'; +data_in_i(2) <= tdo_q; +tdo_d <= not SI_TDO_I; +data_in_i(3) <= '0'; +data_in_i(4) <= '0'; +data_in_i(5) <= '0'; +data_in_i(6) <= '0'; +data_in_i(7) <= '0'; + +-------------------- FX2<-FIFO_IN : +GD_IO <= data_out_i when (state = READ_IN) else "ZZZZZZZZ"; + +state1_debug <= '1' when state = READ_IN else '0'; +state2_debug <= '1' when state2 = WRITE_IN else '0'; + +--Points de test: +FTP_O(0) <= IFCLK_I; +FTP_O(1) <= GCTL0_I; +FTP_O(2) <= GD_IO(0); +FTP_O(3) <= GD_IO(1); +FTP_O(4) <= JPW_I; +FTP_O(5) <= PA2_I; +FTP_O(6) <= empty_o; +FTP_O(7) <= not SI_TDO_I; + +process(pa2_dff_d, pa2_dff_q) begin - if(SDA_DIR = '0') then - ST_5 <= '0'; - else - ST_5 <= '1'; - end if; + if pa2_dff_d = '0' and pa2_dff_q = '1' then + reset_mae <= '1'; -- Reset State Machine + reset_mae2 <= '1'; -- Reset State Machine + rst_o <= '1'; -- Reset OUT + rst_i <= '1'; -- Reset IN + reset_clk_div <= '1'; + reset_clk_div2 <= '1'; + trst_rst <= '1'; + tms_rst <= '1'; + tdi_rst <= '1'; + tdo_rst <= '1'; + else + reset_mae <= '0'; -- No Reset State Machine + reset_mae2 <= '0'; -- Reset State Machine + rst_o <= '0'; -- No Reset OUT + rst_i <= '0'; -- No Reset IN + reset_clk_div <= '0'; + reset_clk_div2 <= '0'; + trst_rst <= '0'; + tms_rst <= '0'; + tdi_rst <= '0'; + tdo_rst <= '0'; + end if; end process; -process(SCL_DIR) +process(clk_div2_out, reset_mae2) begin - if(SCL_DIR = '0') then - ST_4 <= '0'; - else - ST_4 <= '1'; - end if; + if reset_mae2 = '1' then + state2 <= IDLE; + elsif rising_edge(clk_div2_out) then + case state2 is + when IDLE => + read_en_o <= '0'; -- Disable read OUT + write_en_i <= '0'; -- Disable write IN + transit2 <= '1'; + if transit1 = '0' and PA2_I = '0' then + state2 <= WRITE_IN; + else + state2 <= IDLE; + end if; + + when WRITE_IN => + read_en_o <= '1'; -- Enable read OUT + write_en_i <= '1'; -- Enable write IN + if PA2_I = '1' then + state2 <= DELAY; -- Change state to DELAY + else + state2 <= WRITE_IN; -- Stay in WRITE_IN state + end if; + + when DELAY => + transit2 <= '0'; -- Enable READ IN + if empty_o = '1' then + read_en_o <= '0'; -- Disable read OUT + write_en_i <= '0'; -- Disable write IN + state2 <= IDLE; -- Change state to IDLE + else + state2 <= DELAY; -- Stay in READ_IN state + end if; + + when others => + state2 <= IDLE; + end case; + 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; +process(IFCLK_I, reset_mae) +begin + if reset_mae = '1' then + state <= IDLE; + elsif rising_edge(IFCLK_I) then + case state is + when IDLE => + wr_o <= '1'; -- Disable write OUT + rd_i <= '1'; -- Disable read IN + transit1 <= '1'; + if PA2_I = '0' then + state <= WRITE_OUT; -- Change state to RESET + else + state <= IDLE; -- Stay in IDLE state + end if; + + when WRITE_OUT => + wr_o <= '0'; -- Enable write OUT + if empty_o = '0' then + transit1 <= '0'; -- Enable Rd OUT & Wr IN + state <= DELAY; -- Change state to DELAY + else + state <= WRITE_OUT; -- Stay in WRITE_OUT state + end if; + + when DELAY => + if transit2 = '0' then + wr_o <= '1'; -- Disable write OUT + state <= READ_IN; + else + state <= DELAY; + end if; + + when READ_IN => + rd_i <= '0'; -- Enable read IN + if empty_i = '1' then + rd_i <= '1'; -- Enable read IN + state <= IDLE; -- Change state to IDLE + else + state <= READ_IN; -- Stay in READ_IN state + end if; + + when others => + state <= IDLE; + end case; + end if; +end process; + +-- OUT signals direction +-- TRST, TMS, TCK and TDI : out +ST_0_O <= '0'; +-- TDO : in +ST_1_O <= '1'; +-- SRST : out +ST_2_O <= '1'; +SO_SRST_O <= '0'; +-- MOD : in +ST_3_O <= '1'; + +end A_angie_bitstream; diff --git a/contrib/firmware/angie/hdl/src/clk_div.vhd b/contrib/firmware/angie/hdl/src/clk_div.vhd new file mode 100644 index 0000000000..e69850d572 --- /dev/null +++ b/contrib/firmware/angie/hdl/src/clk_div.vhd @@ -0,0 +1,33 @@ +library ieee; +use ieee.std_logic_1164.ALL; +use ieee.numeric_std.ALL; + +entity clk_div is + Port ( + clk_in : in std_logic; + reset : in std_logic; + clk_out : out std_logic + ); +end clk_div; + +architecture behavioral of clk_div is + -- Division factor N = 4, so we need a 2-bit counter (2^2 = 4) +-- signal counter : unsigned(1 downto 0) := (others => '0'); + signal tmp : std_logic; +begin + process(clk_in, reset) + begin + if reset = '1' then +-- counter <= (others => '0'); + tmp <= '0'; + elsif rising_edge(clk_in) then +-- if counter = (2**2 - 1) then +-- counter <= (others => '0'); + tmp <= NOT tmp; -- Toggle the output clock +-- else +-- counter <= counter + 1; +-- end if; + end if; + end process; + clk_out <= tmp; +end behavioral; \ No newline at end of file diff --git a/contrib/firmware/angie/hdl/src/dff.vhd b/contrib/firmware/angie/hdl/src/dff.vhd new file mode 100644 index 0000000000..c5ccf06d33 --- /dev/null +++ b/contrib/firmware/angie/hdl/src/dff.vhd @@ -0,0 +1,23 @@ +library ieee; +use ieee.std_logic_1164.ALL; +use ieee.std_logic_arith.ALL; +use ieee.std_logic_unsigned.ALL; + +entity DFF is +port ( clk : in std_logic; + reset : in std_logic; + d : in std_logic; + q : out std_logic); +end DFF; + +architecture Behavioral of DFF is +begin + process(clk, reset) + begin + if reset = '1' then + q <= '1'; -- Reset output to 0 + elsif rising_edge(clk) then + q <= d; -- Capture D at the rising edge of the clock + end if; + end process; +end Behavioral; \ No newline at end of file diff --git a/contrib/loaders/flash/at91sam7x/main.c b/contrib/loaders/flash/at91sam7x/main.c index a29c6e605b..e988e1848b 100644 --- a/contrib/loaders/flash/at91sam7x/main.c +++ b/contrib/loaders/flash/at91sam7x/main.c @@ -70,23 +70,23 @@ int main (void) for (;;) { cmd = dcc_rd(); switch (cmd&OCL_CMD_MASK) { - case OCL_PROBE: - dcc_wr(OCL_CMD_DONE | flash_init()); - dcc_wr(0x100000); /* base */ - dcc_wr(flash_page_count*flash_page_size); /* size */ - dcc_wr(1); /* num_sectors */ - dcc_wr(4096 | ((unsigned long) flash_page_size << 16)); /* buflen and bufalign */ - break; - case OCL_ERASE_ALL: - dcc_wr(OCL_CMD_DONE | flash_erase_all()); - break; - case OCL_FLASH_BLOCK: - cmd_flash(cmd); - break; - default: - /* unknown command */ - dcc_wr(OCL_CMD_ERR); - break; + case OCL_PROBE: + dcc_wr(OCL_CMD_DONE | flash_init()); + dcc_wr(0x100000); /* base */ + dcc_wr(flash_page_count * flash_page_size); /* size */ + dcc_wr(1); /* num_sectors */ + dcc_wr(4096 | ((unsigned long)flash_page_size << 16)); /* buflen and bufalign */ + break; + case OCL_ERASE_ALL: + dcc_wr(OCL_CMD_DONE | flash_erase_all()); + break; + case OCL_FLASH_BLOCK: + cmd_flash(cmd); + break; + default: + /* unknown command */ + dcc_wr(OCL_CMD_ERR); + break; } } diff --git a/contrib/loaders/flash/at91sam7x/samflash.c b/contrib/loaders/flash/at91sam7x/samflash.c index fcb76fbf98..8be0bdbb84 100644 --- a/contrib/loaders/flash/at91sam7x/samflash.c +++ b/contrib/loaders/flash/at91sam7x/samflash.c @@ -22,38 +22,38 @@ int flash_init(void) nvpsiz = (inr(DBGU_CIDR) >> 8)&0xf; switch (nvpsiz) { - case 3: - /* AT91SAM7x32 */ - flash_page_count = 256; - flash_page_size = 128; - flash_lock_pages = 256/8; - break; - case 5: - /* AT91SAM7x64 */ - flash_page_count = 512; - flash_page_size = 128; - flash_lock_pages = 512/16; - break; - case 7: - /* AT91SAM7x128*/ - flash_page_count = 512; - flash_page_size = 256; - flash_lock_pages = 512/8; - break; - case 9: - /* AT91SAM7x256 */ - flash_page_count = 1024; - flash_page_size = 256; - flash_lock_pages = 1024/16; - break; - case 10: - /* AT91SAM7x512 */ - flash_page_count = 2048; - flash_page_size = 256; - flash_lock_pages = 2048/32; - break; - default: - return FLASH_STAT_INITE; + case 3: + /* AT91SAM7x32 */ + flash_page_count = 256; + flash_page_size = 128; + flash_lock_pages = 256 / 8; + break; + case 5: + /* AT91SAM7x64 */ + flash_page_count = 512; + flash_page_size = 128; + flash_lock_pages = 512 / 16; + break; + case 7: + /* AT91SAM7x128*/ + flash_page_count = 512; + flash_page_size = 256; + flash_lock_pages = 512 / 8; + break; + case 9: + /* AT91SAM7x256 */ + flash_page_count = 1024; + flash_page_size = 256; + flash_lock_pages = 1024 / 16; + break; + case 10: + /* AT91SAM7x512 */ + flash_page_count = 2048; + flash_page_size = 256; + flash_lock_pages = 2048 / 32; + break; + default: + return FLASH_STAT_INITE; } return FLASH_STAT_OK; } diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c index 1bc72d5921..3c1988f112 100644 --- a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c +++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c @@ -52,7 +52,7 @@ static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t addres /* Clear the IRQ flags */ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQRAW)) = 0x0000003F; /* Load the flash address to write */ - *((volatile uint32_t *)(flash_regs_base + FLASH_REG_ADDRESS)) = (uint16_t)((address + index - MFB_BOTTOM) >> 2); + *((volatile uint32_t *)(flash_regs_base + FLASH_REG_ADDRESS)) = (uint32_t)((address + index - MFB_BOTTOM) >> 2); /* Prepare and load the data to flash */ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA0)) = flash_word[0]; *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA1)) = flash_word[1]; diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc index ff05634bb2..146a6bedeb 100644 --- a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc +++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc @@ -1,17 +1,19 @@ /* Autogenerated with ../../../../src/helper/bin2char.sh */ -0x05,0x93,0x43,0x68,0x14,0x9e,0x09,0x93,0x05,0x9b,0x05,0x00,0x07,0x91,0x06,0x92, -0x01,0x24,0xb1,0x46,0x00,0x2b,0x68,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0, -0x2b,0x68,0x00,0x2b,0x61,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x5e,0xd9,0x6b,0x68, -0x07,0x9a,0xd3,0x1a,0x0f,0x2b,0xef,0xdd,0x4a,0x46,0x00,0x21,0x03,0x93,0xd1,0x60, -0x00,0x2b,0x42,0xd0,0x40,0x22,0x4a,0x44,0x90,0x46,0x44,0x22,0x4a,0x44,0x00,0x92, -0x48,0x22,0x4a,0x44,0x93,0x46,0x4c,0x22,0x27,0x4f,0x4a,0x44,0xbc,0x46,0x4e,0x46, -0x92,0x46,0x06,0x99,0x4b,0x46,0x61,0x44,0x08,0x00,0x00,0x99,0x18,0x36,0x6a,0x68, -0x08,0x95,0x8c,0x46,0x55,0x46,0xda,0x46,0xb3,0x46,0x10,0x33,0x04,0x92,0x11,0x68, -0x5e,0x46,0x00,0x91,0x51,0x68,0x97,0x68,0x01,0x91,0xd1,0x68,0x02,0x91,0x3f,0x21, -0x19,0x60,0x81,0x03,0x09,0x0c,0x31,0x60,0x46,0x46,0x00,0x99,0x31,0x60,0x66,0x46, -0x01,0x99,0x31,0x60,0x56,0x46,0x02,0x99,0x37,0x60,0x29,0x60,0xcc,0x26,0x49,0x46, -0x0e,0x60,0x19,0x68,0x0c,0x42,0xfc,0xd0,0x04,0x99,0x03,0x9e,0x10,0x32,0x10,0x30, -0x51,0x1a,0x8e,0x42,0xdb,0xd8,0x08,0x9d,0x6a,0x60,0x03,0x9a,0x06,0x9b,0x94,0x46, -0x63,0x44,0x06,0x93,0x07,0x9a,0x6b,0x68,0x9a,0x42,0x01,0xd8,0x09,0x9b,0x6b,0x60, -0x05,0x9b,0x03,0x9a,0x9b,0x1a,0x05,0x93,0x96,0xd1,0x00,0xbe,0x2b,0x68,0x6a,0x68, -0x9b,0x1a,0x9f,0xd5,0x90,0xe7,0xc0,0x46,0x00,0x00,0xfc,0xef, +0x16,0x9e,0x05,0x00,0x01,0x24,0xb1,0x46,0x06,0x93,0x43,0x68,0x08,0x91,0x07,0x92, +0x09,0x93,0x06,0x9b,0x00,0x2b,0x6f,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0, +0x2b,0x68,0x00,0x2b,0x68,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x65,0xd9,0x6b,0x68, +0x08,0x9a,0xd3,0x1a,0x0b,0x93,0x0b,0x9b,0x0f,0x2b,0xea,0xdd,0x4a,0x46,0x00,0x21, +0x0b,0x9b,0xd1,0x60,0x04,0x93,0x00,0x2b,0x43,0xd0,0x31,0x4a,0x07,0x9b,0x94,0x46, +0x40,0x22,0x4a,0x44,0x90,0x46,0x44,0x22,0x4a,0x44,0x63,0x44,0x94,0x46,0x48,0x22, +0x4a,0x44,0x93,0x46,0x05,0x93,0x4c,0x22,0x4b,0x46,0x4a,0x44,0x10,0x33,0x4e,0x46, +0x92,0x46,0x00,0x93,0x2b,0x00,0x18,0x36,0x6a,0x68,0x55,0x46,0xb2,0x46,0x5e,0x46, +0x9b,0x46,0x10,0x68,0x57,0x68,0x01,0x90,0x3f,0x20,0x00,0x9b,0x02,0x97,0x97,0x68, +0x03,0x97,0xd7,0x68,0x18,0x60,0x53,0x46,0x05,0x98,0x40,0x18,0x80,0x08,0x18,0x60, +0x43,0x46,0x01,0x98,0x18,0x60,0x63,0x46,0x02,0x98,0x18,0x60,0x03,0x98,0x4b,0x46, +0x30,0x60,0xcc,0x20,0x2f,0x60,0x18,0x60,0x00,0x9b,0x18,0x68,0x04,0x42,0xfc,0xd0, +0x58,0x46,0x10,0x32,0x42,0x60,0x04,0x98,0x10,0x31,0x00,0x93,0x88,0x42,0xd8,0xd8, +0x5d,0x46,0x07,0x9a,0x0b,0x9b,0x94,0x46,0x9c,0x44,0x63,0x46,0x08,0x9a,0x07,0x93, +0x6b,0x68,0x93,0x42,0x01,0xd3,0x09,0x9b,0x6b,0x60,0x06,0x9a,0x0b,0x9b,0xd3,0x1a, +0x06,0x93,0x06,0x9b,0x00,0x2b,0x8f,0xd1,0x00,0xbe,0x2b,0x68,0x6a,0x68,0x9b,0x1a, +0x0b,0x93,0x0b,0x9b,0x00,0x2b,0x00,0xdb,0x95,0xe7,0x00,0x23,0x0b,0x93,0x92,0xe7, +0x00,0x00,0xfc,0xef, diff --git a/contrib/loaders/flash/cc26xx/main.c b/contrib/loaders/flash/cc26xx/main.c index 6b626a3b84..bd5eaf3354 100644 --- a/contrib/loaders/flash/cc26xx/main.c +++ b/contrib/loaders/flash/cc26xx/main.c @@ -98,35 +98,32 @@ int main(void) /* Perform requested task */ switch (g_cfg[g_curr_buf].cmd) { - case CMD_ERASE_ALL: - status = flashloader_erase_all(); - break; - case CMD_PROGRAM: - status = - flashloader_program( - (uint8_t *)g_cfg[g_curr_buf].buf_addr, - g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); - break; - case CMD_ERASE_AND_PROGRAM: - status = - flashloader_erase_and_program( - (uint8_t *)g_cfg[g_curr_buf].buf_addr, - g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); - break; - case CMD_ERASE_AND_PROGRAM_WITH_RETAIN: - status = - flashloader_program_with_retain( - (uint8_t *)g_cfg[g_curr_buf].buf_addr, - g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); - break; - case CMD_ERASE_SECTORS: - status = - flashloader_erase_sectors(g_cfg[g_curr_buf].dest, - g_cfg[g_curr_buf].len); - break; - default: - status = STATUS_FAILED_UNKNOWN_COMMAND; - break; + case CMD_ERASE_ALL: + status = flashloader_erase_all(); + break; + case CMD_PROGRAM: + status = + flashloader_program((uint8_t *)g_cfg[g_curr_buf].buf_addr, + g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); + break; + case CMD_ERASE_AND_PROGRAM: + status = + flashloader_erase_and_program((uint8_t *)g_cfg[g_curr_buf].buf_addr, + g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); + break; + case CMD_ERASE_AND_PROGRAM_WITH_RETAIN: + status = + flashloader_program_with_retain((uint8_t *)g_cfg[g_curr_buf].buf_addr, + g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); + break; + case CMD_ERASE_SECTORS: + status = + flashloader_erase_sectors(g_cfg[g_curr_buf].dest, + g_cfg[g_curr_buf].len); + break; + default: + status = STATUS_FAILED_UNKNOWN_COMMAND; + break; } restore_cache_state(); diff --git a/contrib/loaders/flash/hpmicro/Makefile b/contrib/loaders/flash/hpmicro/Makefile new file mode 100644 index 0000000000..304363171a --- /dev/null +++ b/contrib/loaders/flash/hpmicro/Makefile @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 HPMicro +# +BIN2C = ../../../../src/helper/bin2char.sh + + +PROJECT=hpm_xpi_flash +CROSS_COMPILE ?= riscv32-unknown-elf- +CC=$(CROSS_COMPILE)gcc +AS=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump +LD=$(CROSS_COMPILE)ld +LDSCRIPT=linker.ld + +OPT=-O3 + +ASFLAGS= +CFLAGS=$(OPT) -fomit-frame-pointer -Wall +LDFLAGS=-nostartfiles -T$(LDSCRIPT) -Wl,-Map=$(PROJECT).map -static -Wl,--gc-sections +OBJS=$(ASRC:.S=.o) $(SRC:.c=.o) + +SRC=openocd_flash_algo.c +ASRC=func_table.S + +all: $(OBJS) $(PROJECT).elf $(PROJECT).bin $(PROJECT).lst $(PROJECT).inc + +%o: %c + @$(CC) -c $(CFLAGS) -I . $< -o $@ + +%o: %S + @$(AS) -c $(ASFLAGS) -I . $< -o $@ + +%elf: $(OBJS) + @$(CC) $(OBJS) $(LDFLAGS) -o $@ + +%lst: %elf + @$(OBJDUMP) -h -S $< > $@ + +%bin: %elf + @$(OBJCOPY) -Obinary $< $@ + +%inc: %bin + $(BIN2C) < $< > $@ + +clean: + @-rm -f *.o *.elf *.lst *.bin *.inc + +.PHONY: all clean + +.INTERMEDIATE: $(patsubst %.S,%.o,$(SRCS)) $(patsubst %.S,%.elf,$(SRCS)) $(patsubst %.S,%.bin,$(SRCS)) diff --git a/contrib/loaders/flash/hpmicro/README b/contrib/loaders/flash/hpmicro/README new file mode 100644 index 0000000000..a6c047a11f --- /dev/null +++ b/contrib/loaders/flash/hpmicro/README @@ -0,0 +1,7 @@ +The loader relies on the romapi provided by HPMicro devices. + +- hpm_common.h and all the hpm_romapi_*.c/h are reused from hpm_sdk +(v1.9.0 https://github.com/hpmicro/hpm_sdk/releases). + +Due to different coding rules, these source code needs to be updated +accordingly to pass the coding rule check for openocd. diff --git a/contrib/loaders/flash/hpmicro/func_table.S b/contrib/loaders/flash/hpmicro/func_table.S new file mode 100644 index 0000000000..d5f34265ec --- /dev/null +++ b/contrib/loaders/flash/hpmicro/func_table.S @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2021 HPMicro + */ + .section .func_table, "ax" + .global _init +_init: + jal flash_init + ebreak + jal flash_erase + ebreak + jal flash_program + ebreak + jal flash_read + ebreak + jal flash_get_info + ebreak + jal flash_erase_chip + ebreak + jal flash_deinit + ebreak diff --git a/contrib/loaders/flash/hpmicro/hpm_common.h b/contrib/loaders/flash/hpmicro/hpm_common.h new file mode 100644 index 0000000000..8190fbfed5 --- /dev/null +++ b/contrib/loaders/flash/hpmicro/hpm_common.h @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2021-2023 HPMicro + */ + +#ifndef _HPM_COMMON_H +#define _HPM_COMMON_H + +#include +#include +#include +#include +#include + +/** + * + * @brief COMMON driver APIs + * @defgroup common_interface COMMON driver APIs + * @{ + * + */ + +#define __R volatile const /* Define "read-only" permission */ +#define __RW volatile /* Define "read-write" permission */ +#define __W volatile /* Define "write-only" permission */ + +#ifndef __I +#define __I __R +#endif + +#ifndef __IO +#define __IO __RW +#endif + +#ifndef __O +#define __O __W +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#define HPM_BITSMASK(val, offset) ((uint32_t)(val) << (offset)) +#define IS_HPM_BITMASK_SET(val, mask) (((uint32_t)(val) & (uint32_t)(mask)) != 0U) +#define IS_HPM_BIT_SET(val, offset) (((uint32_t)(val) & (1UL << (offset))) != 0U) +#define IS_HPM_BITMASK_CLR(val, mask) (((uint32_t)(val) & (uint32_t)(mask)) == 0U) +#define IS_HPM_BIT_CLR(val, offset) (((uint32_t)(val) & (1UL << (offset))) == 0U) + +#define HPM_BREAK_IF(cond) do {if (cond) break; } while (0) +#define HPM_CONTINUE_IF(cond) do {if (cond) continue; } while (0) + +#define HPM_CHECK_RET(x) \ + do { \ + stat = (x); \ + if (status_success != stat) { \ + return stat; \ + } \ + } while (false) + +#define SIZE_1KB (1024UL) +#define SIZE_1MB (1048576UL) + +typedef uint32_t hpm_stat_t; + +/* @brief Enum definition for the Status group + * Rule: + * [Group] 0-999 for the SoC driver and the corresponding components + * 1000 or above for the application status group + * [Code] Valid value: 0-999 + * + */ +#define MAKE_STATUS(group, code) ((uint32_t)(group) * 1000U + (uint32_t)(code)) +/* @brief System status group definitions */ +enum { + status_group_common = 0, + status_group_uart = 1, + status_group_i2c = 2, + status_group_spi = 3, + status_group_usb = 4, + status_group_i2s = 5, + status_group_xpi = 6, + status_group_l1c, + status_group_dma, + status_group_femc, + status_group_sdp, + status_group_xpi_nor, + status_group_otp, + status_group_lcdc, + status_group_mbx, + status_group_rng, + status_group_pdma, + status_group_wdg, + status_group_pmic_sec, + status_group_can, + status_group_sdxc, + status_group_pcfg, + status_group_clk, + status_group_pllctl, + status_group_pllctlv2, + status_group_ffa, + status_group_mcan, + + status_group_middleware_start = 500, + status_group_sdmmc = status_group_middleware_start, + status_group_audio_codec, + status_group_dma_manager, +}; + +/* @brief Common status code definitions */ +enum { + status_success = MAKE_STATUS(status_group_common, 0), + status_fail = MAKE_STATUS(status_group_common, 1), + status_invalid_argument = MAKE_STATUS(status_group_common, 2), + status_timeout = MAKE_STATUS(status_group_common, 3), +}; + +#if defined(__GNUC__) + +/* alway_inline */ +#define ATTR_ALWAYS_INLINE __attribute__((always_inline)) + +/* weak */ +#define ATTR_WEAK __attribute__((weak)) + +/* alignment */ +#define ATTR_ALIGN(alignment) __attribute__((aligned(alignment))) + +/* place var_declare at section_name, e.x. PLACE_AT(".target_section", var); */ +#define ATTR_PLACE_AT(section_name) __attribute__((section(section_name))) + +#define ATTR_PLACE_AT_WITH_ALIGNMENT(section_name, alignment) \ +ATTR_PLACE_AT(section_name) ATTR_ALIGN(alignment) + +#define ATTR_PLACE_AT_NONCACHEABLE ATTR_PLACE_AT(".noncacheable.bss") +#define ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE ATTR_ALIGN(alignment) + +#define ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_PLACE_AT(".noncacheable.bss") +#define ATTR_PLACE_AT_NONCACHEABLE_BSS_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_ALIGN(alignment) + +/* initialize variable x with y using PLACE_AT_NONCACHEABLE_INIT(x) = {y}; */ +#define ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_PLACE_AT(".noncacheable.init") +#define ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_ALIGN(alignment) + +#define ATTR_RAMFUNC ATTR_PLACE_AT(".fast") +#define ATTR_RAMFUNC_WITH_ALIGNMENT(alignment) \ + ATTR_RAMFUNC ATTR_ALIGN(alignment) + +#define ATTR_SHARE_MEM ATTR_PLACE_AT(".sh_mem") + +#define NOP() __asm volatile("nop") +#define WFI() __asm volatile("wfi") + +#define HPM_ATTR_MACHINE_INTERRUPT __attribute__ ((section(".isr_vector"), interrupt("machine"), aligned(4))) + +#elif defined(__ICCRISCV__) + +/* alway_inline */ +#define ATTR_ALWAYS_INLINE __attribute__((always_inline)) + +/* weak */ +#define ATTR_WEAK __weak + +/* alignment */ +#define ATTR_ALIGN(alignment) __attribute__((aligned(alignment))) + +/* place var_declare at section_name, e.x. PLACE_AT(".target_section", var); */ +#define ATTR_PLACE_AT(section_name) __attribute__((section(section_name))) + +#define ATTR_PLACE_AT_WITH_ALIGNMENT(section_name, alignment) \ +ATTR_PLACE_AT(section_name) ATTR_ALIGN(alignment) + +#define ATTR_PLACE_AT_NONCACHEABLE ATTR_PLACE_AT(".noncacheable.bss") +#define ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE ATTR_ALIGN(alignment) + +#define ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_PLACE_AT(".noncacheable.bss") +#define ATTR_PLACE_AT_NONCACHEABLE_BSS_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_ALIGN(alignment) + +/* initialize variable x with y using PLACE_AT_NONCACHEABLE_INIT(x) = {y}; */ +#define ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_PLACE_AT(".noncacheable.init") +#define ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(alignment) \ + ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_ALIGN(alignment) + +#define ATTR_RAMFUNC ATTR_PLACE_AT(".fast") +#define ATTR_RAMFUNC_WITH_ALIGNMENT(alignment) \ + ATTR_RAMFUNC ATTR_ALIGN(alignment) + +#define ATTR_SHARE_MEM ATTR_PLACE_AT(".sh_mem") + +#define NOP() __asm volatile("nop") +#define WFI() __asm volatile("wfi") + +#define HPM_ATTR_MACHINE_INTERRUPT __machine __interrupt + +#else +#error Unknown toolchain +#endif +#endif /* _HPM_COMMON_H */ diff --git a/contrib/loaders/flash/hpmicro/hpm_romapi.h b/contrib/loaders/flash/hpmicro/hpm_romapi.h new file mode 100644 index 0000000000..d19f551994 --- /dev/null +++ b/contrib/loaders/flash/hpmicro/hpm_romapi.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2021-2023 HPMicro + */ + +#ifndef HPM_ROMAPI_H +#define HPM_ROMAPI_H + +/** + * @brief ROM APIs + * @defgroup romapi_interface ROM APIs + * @{ + */ + +#include "hpm_common.h" +#include "hpm_romapi_xpi_def.h" +#include "hpm_romapi_xpi_soc_def.h" +#include "hpm_romapi_xpi_nor_def.h" + +/*********************************************************************************************************************** + * + * + * Definitions + * + * + **********************************************************************************************************************/ + +/** + * @brief Bootloader API table + */ +struct bootloader_api_table_t { + /**< Bootloader API table: version */ + const uint32_t version; + /**< Bootloader API table: copyright string address */ + const char *copyright; + /**< Bootloader API table: run_bootloader API */ + const uint32_t reserved0; + /**< Bootloader API table: otp driver interface address */ + const uint32_t reserved1; + /**< Bootloader API table: xpi driver interface address */ + const struct xpi_driver_interface_t *xpi_driver_if; + /**< Bootloader API table: xpi nor driver interface address */ + const struct xpi_nor_driver_interface_t *xpi_nor_driver_if; + /**< Bootloader API table: xpi ram driver interface address */ + const uint32_t reserved2; +}; + +/**< Bootloader API table Root */ +#define ROM_API_TABLE_ROOT ((const struct bootloader_api_table_t *)0x2001FF00U) + +#endif /* HPM_ROMAPI_H */ diff --git a/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_def.h b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_def.h new file mode 100644 index 0000000000..b4d73bd105 --- /dev/null +++ b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_def.h @@ -0,0 +1,254 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2021 HPMicro + */ +#ifndef HPM_ROMAPI_XPI_DEF_H +#define HPM_ROMAPI_XPI_DEF_H + +/** + * @brief XPI ROM APIs + * @defgroup xpi_interface XPI driver APIs + * @{ + */ + +#include "hpm_common.h" + +/** + * @brief XPI Read Sample Clock source options + */ +enum xpi_rxclksrc_type_t { + xpi_rxclksrc_internal_loopback = 0, /**< Internal loopback */ + xpi_rxclksrc_dqs_loopback = 1, /**< Loopback from DQS pad */ + xpi_rxclksrc_external_dqs = 3, /**< Read is driven by External DQS pad */ +}; + +/** + * @brief XPI pad definitions + */ +#define XPI_1PAD (0U) /**< Single pad */ +#define XPI_2PADS (1U) /**< Dual pads */ +#define XPI_4PADS (2U) /**< Quad pads */ +#define XPI_8PADS (3U) /**< Octal pads */ + +/** + * @brief XPI IO pin group options + */ +enum xpi_io_group_t { + xpi_io_1st_group, /**< First/Primary group */ + xpi_io_2nd_group, /**< Second/Secondary group */ +}; + +/** + * @brief XPI Transfer Channel type definitions + */ +enum xpi_xfer_channel_t { + xpi_xfer_channel_a1, /**< The address is based on the device connected to Channel A1 */ + xpi_xfer_channel_a2, /**< The address is based on the device connected to Channel A2 */ + xpi_xfer_channel_b1, /**< The address is based on the device connected to Channel B1 */ + xpi_xfer_channel_b2, /**< The address is based on the device connected to Channel B2 */ + xpi_xfer_channel_auto, /**< The channel is auto determined */ +}; + +/** + * @brief XPI Channel definitions + */ +enum xpi_channel_t { + xpi_channel_a1, /**< Port: Channel A1 */ + xpi_channel_a2, /**< Port: Channel A2 */ + xpi_channel_b1, /**< Port: Channel B1 */ + xpi_channel_b2, /**< Port: Channel B2 */ +}; + +/** + * @brief XPI APB Transfer type + */ +enum xpi_apb_xfer_type_t { + xpi_apb_xfer_type_cmd, /**< APB Command Type: Command only */ + xpi_apb_xfer_type_config, /**< APB Command Type: Configuration */ + xpi_apb_xfer_type_read, /**< APB Command Type: Read */ + xpi_apb_xfer_type_write, /**< APB Command Type: Write */ +}; + +/** + * @brief XPI Xfer Mode + */ +enum xpi_xfer_mode_t { + xpi_xfer_mode_polling, /**< Transfer mode: Polling */ + xpi_xfer_mode_dma, /**< Transfer mode: DMA */ + xpi_xfer_mode_interrupt, /**< Transfer mode: Interrupt */ +}; + +/** + * @brief XPI Xfer context + */ +struct xpi_xfer_ctx_t { + uint32_t addr; /**< device address for XPI transfer */ + uint8_t channel; /**< channel for XPI transfer */ + uint8_t cmd_type; /**< command type for XPI transfer */ + uint8_t seq_idx; /**< Sequence index for XPI transfer */ + uint8_t seq_num; /**< Sequence number for XPI transfer */ + uint32_t *buf; /**< Buffer for XPI transfer */ + uint32_t xfer_size; /**< Transfer size in bytes */ +}; + +/** + * @brief XPI instruction sequence + */ +struct xpi_instr_seq_t { + uint32_t entry[4]; +}; + +/** + * @brief XPI Phase definitions + */ +#define XPI_PHASE_STOP (0x00U) /**< Phase: Stop */ +#define XPI_PHASE_CMD_SDR (0x01U) /**< Phase: Send CMD in SDR mode */ +#define XPI_PHASE_RADDR_SDR (0x02U) /**< Phase: Send Row Address in SDR Mode */ +#define XPI_PHASE_CADDR_SDR (0x03U) /**< Phase: Send Column Address in SDR Mode */ +#define XPI_PHASE_MODE4_SDR (0x06U) /**< Phase: Send Mode 4 in SDR Mode */ +#define XPI_PHASE_MODE8_SDR (0x07U) /**< Phase: Send Mode 8 in SDR Mode */ +#define XPI_PHASE_WRITE_SDR (0x08U) /**< Phase: Write data in SDR Mode */ +#define XPI_PHASE_READ_SDR (0x09U) /**< Phase: Read data in SDR Mode */ +#define XPI_PHASE_DUMMY_SDR (0X0CU) /**< Phase: Send Dummy in SDR Mode */ +#define XPI_PHASE_DUMMY_RWDS_SDR (0x0DU) /**< Phase: Send Dummy RWDS in SDR Mode */ + +#define XPI_PHASE_CMD_DDR (0x21U) /**< Phase: Send CMD in DDR Mode */ +#define XPI_PHASE_RADDR_DDR (0x22U) /**< Phase: Send Raw Address in DDR Mode */ +#define XPI_PHASE_CADDR_DDR (0x23U) /**< Phase: Send Column address in DDR Mode */ +#define XPI_PHASE_MODE4_DDR (0x26U) /**< Phase: Send Mode 4 in DDR Mode */ +#define XPI_PHASE_MODE8_DDR (0x27U) /**< Phase: Send Mode 8 in DDR Mode */ +#define XPI_PHASE_WRITE_DDR (0x28U) /**< Phase: Write data in DDR Mode */ +#define XPI_PHASE_READ_DDR (0x29U) /**< Phase: Read data in SDR Mode */ +#define XPI_PHASE_DUMMY_DDR (0x2CU) /**< Phase: Send DUMMY in DDR Mode */ +#define XPI_PHASE_DUMMY_RWDS_DDR (0x2DU) /**< Phase: Send DUMMY RWDS in DDR Mode */ + +/** + * @brief XPI API command error codes + */ +enum { + status_xpi_apb_jump_on_cs = MAKE_STATUS(status_group_xpi, 1), + status_xpi_apb_unknown_inst = MAKE_STATUS(status_group_xpi, 2), + status_xpi_apb_dummy_sdr_in_ddr_seq = MAKE_STATUS(status_group_xpi, 3), + status_xpi_apb_dummy_ddr_in_sdr_seq = MAKE_STATUS(status_group_xpi, 4), + status_xpi_apb_exceed_addr_range = MAKE_STATUS(status_group_xpi, 5), + status_xpi_apb_seq_timeout = MAKE_STATUS(status_group_xpi, 6), + status_xpi_apb_cross_boundary = MAKE_STATUS(status_group_xpi, 7), +}; + +/** + * @brief Delay line definitions + */ +enum { + xpi_dll_half_cycle = 0xFU, + xpi_dll_quarter_cycle = 0x7U, + xpi_dll_sdr_default_cycle = xpi_dll_half_cycle, + xpi_dll_ddr_default_cycle = xpi_dll_quarter_cycle, +}; + +/** + * @brief XPI configuration structure + */ +struct xpi_config_t { + uint8_t rxclk_src; /**< Read sample clock source */ + uint8_t reserved0[7]; /**< Reserved */ + uint8_t tx_watermark_in_dwords; /**< Tx watermark in double words */ + uint8_t rx_watermark_in_dwords; /**< Rx watermark in double words */ + uint8_t enable_differential_clk; /**< Enable differential clock */ + uint8_t reserved1[5]; /**< Reserved */ + uint32_t access_flags; /**< Access flags */ +}; + +/** + * @brief XPI Device Configuration structure + */ +struct xpi_device_config_t { + uint32_t size_in_kbytes; /**< Device size in kbytes */ + uint32_t serial_root_clk_freq; /**< XPI serial root clock frequency */ + + uint8_t enable_write_mask; /**< Enable write mask, typically for PSRAM/HyperRAM */ + uint8_t data_valid_time; /**< Data valid time, Unit 0.1ns */ + uint8_t reserved0[2]; + + uint8_t cs_hold_time; /**< CS hold time, cycles in terms of FLASH clock */ + uint8_t cs_setup_time; /**< CS setup time, cycles in terms of FLASH clock */ + uint16_t cs_interval; /**< CS interval, cycles in terms of FLASH clock */ + + uint8_t reserved1; + uint8_t column_addr_size; /**< Column address bits */ + uint8_t enable_word_address; /**< Enable word address, for HyperFLASH/HyperRAM */ + uint8_t dly_target; /**< Delay target */ + + uint8_t ahb_write_seq_idx; /**< AHB write sequence index */ + uint8_t ahb_write_seq_num; /**< AHB write sequence number */ + uint8_t ahb_read_seq_idx; /**< AHB read sequence index */ + uint8_t ahb_read_seq_num; /**< AHB read sequence number */ + + uint8_t ahb_write_wait_interval; /**< AHB write wait interval, in terms of FLASH clock */ + uint8_t reserved2[3]; +}; + +/** + * @brief SUB Instruction + * @param [in] phase Name + * @param [in] pad Pad for Phase + * @param [in] op Operand for Phase + */ +#define SUB_INSTR(phase, pad, op) ((uint32_t)(((uint16_t)(phase) << 10) | ((uint16_t)(pad) << 8) | ((uint16_t)(op)))) +/** + * @brief Generate a single word INSTRUCTION sequence word + * @note Here intentionally use the MACRO because when the arguments are constant value, the compiler + * can generate the const entry word during pre-processing + */ +#define XPI_INSTR_SEQ(phase0, pad0, op0, phase1, pad1, op1) \ + (SUB_INSTR(phase0, pad0, op0) | (SUB_INSTR(phase1, pad1, op1) << 16)) + +struct xpi_ahb_buffer_cfg_t { + struct { + uint8_t priority; /* Offset: 0x00 */ + uint8_t master_idx; /* Offset: 0x01 */ + uint8_t buf_size_in_dword; /* Offset: 0x02 */ + bool enable_prefetch; /* Offset: 0x03 */ + } entry[8]; +}; + +/** + * @brief XPI driver interface + */ +struct xpi_driver_interface_t { + /**< XPI driver interface: version */ + uint32_t version; + /**< XPI driver interface: get default configuration */ + hpm_stat_t (*get_default_config)(struct xpi_config_t *xpi_config); + /**< XPI driver interface: get default device configuration */ + hpm_stat_t (*get_default_device_config)(struct xpi_device_config_t *dev_config); + /**< XPI driver interface: initialize the XPI using xpi_config */ + hpm_stat_t (*init)(uint32_t *base, struct xpi_config_t *xpi_config); + /**< XPI driver interface: configure the AHB buffer */ + hpm_stat_t (*config_ahb_buffer)(uint32_t *base, struct xpi_ahb_buffer_cfg_t *ahb_buf_cfg); + /**< XPI driver interface: configure the device */ + hpm_stat_t (*config_device)(uint32_t *base, struct xpi_device_config_t *dev_cfg, enum xpi_channel_t channel); + /**< XPI driver interface: update instruction talbe */ + hpm_stat_t (*update_instr_table)(uint32_t *base, const uint32_t *inst_base, uint32_t seq_idx, uint32_t num); + /**< XPI driver interface: transfer command/data using block interface */ + hpm_stat_t (*transfer_blocking)(uint32_t *base, struct xpi_xfer_ctx_t *xfer); + /**< Software reset the XPI controller */ + void (*software_reset)(uint32_t *base); + /**< XPI driver interface: Check whether IP is idle */ + bool (*is_idle)(uint32_t *base); + /**< XPI driver interface: update delay line setting */ + void (*update_dllcr)(uint32_t *base, + uint32_t serial_root_clk_freq, + uint32_t data_valid_time, + enum xpi_channel_t channel, + uint32_t dly_target); + /**< XPI driver interface: Get absolute address for APB transfer */ + hpm_stat_t + (*get_abs_apb_xfer_addr)(uint32_t *base, enum xpi_xfer_channel_t channel, uint32_t in_addr, uint32_t *out_addr); +}; + +/** + * @} + */ + +#endif /* HPM_ROMAPI_XPI_DEF_H */ diff --git a/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_nor_def.h b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_nor_def.h new file mode 100644 index 0000000000..edde8402fd --- /dev/null +++ b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_nor_def.h @@ -0,0 +1,426 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2021 HPMicro + */ +#ifndef HPM_ROMAPI_XPI_NOR_DEF_H +#define HPM_ROMAPI_XPI_NOR_DEF_H + +/** + * @brief XPI NOR ROM APIs + * @defgroup xpi_nor_interface XPI NOR driver APIs + * @ingroup romapi_interfaces + * @{ + */ + +#include "hpm_common.h" +#include "hpm_romapi_xpi_def.h" + +#define XPI_NOR_CFG_TAG 0x524f4E58U /**< ASCII: "XNOR" */ + +/** + * @brief XPI NOR properties + */ +enum { + xpi_nor_property_total_size, /**< Total size in bytes */ + xpi_nor_property_page_size, /**< Page size in bytes */ + xpi_nor_property_sector_size, /**xpi_nor_driver_if->version >= 0x56010300) + +struct hpm_flash_info_t { + uint32_t total_sz_in_bytes; + uint32_t sector_sz_in_bytes; +}; + +__attribute__ ((section(".flash_algo.data"))) struct xpi_nor_config_t nor_config; +__attribute__ ((section(".flash_algo.data"))) bool xpi_inited = false; +__attribute__ ((section(".flash_algo.data"))) uint32_t channel = xpi_channel_a1; +__attribute__ ((section(".flash_algo.data"))) uint32_t *xpi_base; + +__attribute__ ((section(".flash_algo.text"))) void refresh_device_size(uint32_t *base, + struct xpi_nor_config_option_t *option) +{ + volatile uint32_t *dev_size = (volatile uint32_t *)((uint32_t)base + 0x60); + bool enable_channelb = false; + if (option->header.words > 1) + enable_channelb = option->option1.connection_sel == xpi_nor_connection_sel_chnb_cs0; + if (enable_channelb) { + dev_size[0] = 0; + dev_size[1] = 0; + } +} + +__attribute__ ((section(".flash_algo.text"))) uint32_t flash_init(uint32_t flash_base, uint32_t header, + uint32_t opt0, uint32_t opt1, uint32_t xpi_base_addr) +{ + uint32_t i = 0; + struct xpi_nor_config_option_t cfg_option; + hpm_stat_t stat = status_success; + + xpi_base = (uint32_t *)xpi_base_addr; + if (xpi_inited) + return stat; + + __asm volatile("csrc %0, %1" : : "i"(CSR_MCACHE_CTL), "r"(HPM_MCACHE_CTL_DC_EN_MASK)); + for (i = 0; i < sizeof(cfg_option); i++) + *((uint8_t *)&cfg_option + i) = 0; + for (i = 0; i < sizeof(nor_config); i++) + *((uint8_t *)&nor_config + i) = 0; + + cfg_option.header.U = header; + cfg_option.option0.U = opt0; + cfg_option.option1.U = opt1; + + if (opt1 & XPI_USE_PORT_B_MASK) + channel = xpi_channel_b1; + else + channel = xpi_channel_a1; + + stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->auto_config(xpi_base, &nor_config, &cfg_option); + if (stat) + return stat; + + if (ROMAPI_SUPPORTS_HYBRIDXPI()) + ROM_API_TABLE_ROOT->xpi_nor_driver_if->enable_hybrid_xpi(xpi_base); + + refresh_device_size(xpi_base, &cfg_option); + + nor_config.device_info.clk_freq_for_non_read_cmd = 0; + if (!xpi_inited) + xpi_inited = true; + return stat; +} + +__attribute__ ((section(".flash_algo.text"))) uint32_t flash_erase(uint32_t flash_base, uint32_t address, uint32_t size) +{ + hpm_stat_t stat = status_success; + uint32_t left, start, block_size, align; + + left = size; + start = address; + if (ROMAPI_SUPPORTS_HYBRIDXPI()) + start += flash_base; + block_size = nor_config.device_info.block_size_kbytes * 1024; + if (left >= block_size) { + align = block_size - (start % block_size); + if (align != block_size) { + stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase(xpi_base, channel, &nor_config, start, align); + if (stat != status_success) + return stat; + left -= align; + start += align; + } + while (left > block_size) { + stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase_block(xpi_base, channel, &nor_config, start); + if (stat != status_success) + break; + left -= block_size; + start += block_size; + } + } + if (stat == status_success && left) + stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase(xpi_base, channel, &nor_config, start, left); + return stat; +} + +__attribute__ ((section(".flash_algo.text"))) uint32_t flash_program(uint32_t flash_base, uint32_t address, + uint32_t *buf, uint32_t size) +{ + hpm_stat_t stat; + + if (ROMAPI_SUPPORTS_HYBRIDXPI()) + address += flash_base; + stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->program(xpi_base, channel, &nor_config, buf, address, size); + return stat; +} + +__attribute__ ((section(".flash_algo.text"))) uint32_t flash_read(uint32_t flash_base, uint32_t *buf, + uint32_t address, uint32_t size) +{ + hpm_stat_t stat; + + if (ROMAPI_SUPPORTS_HYBRIDXPI()) + address += flash_base; + stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->read(xpi_base, channel, &nor_config, buf, address, size); + return stat; +} + +__attribute__ ((section(".flash_algo.text"))) uint32_t flash_get_info(uint32_t flash_base, + struct hpm_flash_info_t *flash_info) +{ + if (!flash_info) + return status_invalid_argument; + + flash_info->total_sz_in_bytes = nor_config.device_info.size_in_kbytes << 10; + flash_info->sector_sz_in_bytes = nor_config.device_info.sector_size_kbytes << 10; + return status_success; +} + +__attribute__ ((section(".flash_algo.text"))) uint32_t flash_erase_chip(uint32_t flash_base) +{ + return ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase_chip(xpi_base, channel, &nor_config); +} + +__attribute__ ((section(".flash_algo.text"))) void flash_deinit(void) +{ +} diff --git a/contrib/loaders/flash/max32xxx/Makefile b/contrib/loaders/flash/max32xxx/Makefile index 1565c811c1..fe7666f840 100644 --- a/contrib/loaders/flash/max32xxx/Makefile +++ b/contrib/loaders/flash/max32xxx/Makefile @@ -1,21 +1,30 @@ # SPDX-License-Identifier: GPL-2.0-or-later +TARGET=max32xxx_write +ENTRY=algo_write + BIN2C = ../../../../src/helper/bin2char.sh -CROSS_COMPILE ?= arm-none-eabi- -AS = $(CROSS_COMPILE)as -OBJCOPY = $(CROSS_COMPILE)objcopy +PREFIX=arm-none-eabi +CFLAGS=-mthumb -mcpu=cortex-m4 -Wa,-mimplicit-it=thumb + +all: $(TARGET).inc -all: max32xxx.inc +%.o: %.c + $(PREFIX)-gcc $(CFLAGS) -Os -Wall -c ${<} -o ${@} -%.elf: %.s - $(AS) $< -o $@ +%.elf: %.o + $(PREFIX)-ld -nostdlib --entry $(ENTRY) ${<} -o ${@} + $(PREFIX)-size ${@} %.bin: %.elf - $(OBJCOPY) -Obinary $< $@ + $(PREFIX)-objcopy -O binary ${<} ${@} %.inc: %.bin $(BIN2C) < $< > $@ +%.dasm: %.o + $(PREFIX)-objdump -S ${<} > ${TARGET}.dasm + clean: - -rm -f *.elf *.bin *.inc + rm -rf $(TARGET).bin $(TARGET).elf $(TARGET).o $(TARGET).dasm $(TARGET).inc diff --git a/contrib/loaders/flash/max32xxx/algo_options.h b/contrib/loaders/flash/max32xxx/algo_options.h new file mode 100644 index 0000000000..a4902e08a0 --- /dev/null +++ b/contrib/loaders/flash/max32xxx/algo_options.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2016 by Maxim Integrated * + * Copyright (C) 2025 Analog Devices, Inc. * + ***************************************************************************/ + +#define OPTIONS_128 0x01 /* Perform 128 bit flash writes */ +#define OPTIONS_ENC 0x02 /* Encrypt the flash contents */ +#define OPTIONS_AUTH 0x04 /* Authenticate the flash contents */ +#define OPTIONS_COUNT 0x08 /* Add counter values to authentication */ +#define OPTIONS_INTER 0x10 /* Interleave the authentication and count values*/ +#define OPTIONS_RELATIVE_XOR 0x20 /* Only XOR the offset of the address when encrypting */ +#define OPTIONS_KEYSIZE 0x40 /* Use a 256 bit KEY */ diff --git a/contrib/loaders/flash/max32xxx/flc_regs.h b/contrib/loaders/flash/max32xxx/flc_regs.h new file mode 100644 index 0000000000..9179589ddd --- /dev/null +++ b/contrib/loaders/flash/max32xxx/flc_regs.h @@ -0,0 +1,238 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2016 by Maxim Integrated * + * Copyright (C) 2025 Analog Devices, Inc. * + ***************************************************************************/ + +#ifndef _FLC_REGS_H_ +#define _FLC_REGS_H_ + +/* **** Includes **** */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__ICCARM__) +#pragma system_include +#endif + +/*/ @cond */ +/* + If types are not defined elsewhere (CMSIS) define them here +*/ +#ifndef __IO +#define __IO volatile +#endif +#ifndef __I +#define __I volatile const +#endif +#ifndef __O +#define __O volatile +#endif +#ifndef __R +#define __R volatile const +#endif +/*/ @endcond */ + +/* **** Definitions **** */ + +/** + * @ingroup flc + * @defgroup flc_registers Registers + * @brief Registers, Bit Masks and Bit Positions for the FLC Peripheral Module. + * @description Flash Memory Control. + */ + +/** + * @ingroup flc_registers + * Structure type to access the FLC Registers. + */ +struct mxc_flc_regs { + __IO uint32_t addr; /**< \b 0x00:<\tt> FLC ADDR Register */ + __IO uint32_t clkdiv; /**< \b 0x04:<\tt> FLC CLKDIV Register */ + __IO uint32_t cn; /**< \b 0x08:<\tt> FLC CN Register */ + __R uint32_t rsv_0xc_0x23[6]; + __IO uint32_t intr; /**< \b 0x024:<\tt> FLC INTR Register */ + __R uint32_t rsv_0x28_0x2f[2]; + __IO uint32_t data[4]; /**< \b 0x30:<\tt> FLC DATA Register */ + __O uint32_t acntl; /**< \b 0x40:<\tt> FLC ACNTL Register */ +}; + +/* Register offsets for module FLC */ +/** + * @ingroup flc_registers + * @defgroup FLC_Register_Offsets Register Offsets + * @brief FLC Peripheral Register Offsets from the FLC Base Peripheral Address. + * @{ + */ +#define MXC_R_FLC_ADDR ((uint32_t)0x00000000UL) /**< Offset from FLC Base Address: 0x0x000 */ +#define MXC_R_FLC_CLKDIV ((uint32_t)0x00000004UL) /**< Offset from FLC Base Address: 0x0x004 */ +#define MXC_R_FLC_CN ((uint32_t)0x00000008UL) /**< Offset from FLC Base Address: 0x0x008 */ +#define MXC_R_FLC_INTR ((uint32_t)0x00000024UL) /**< Offset from FLC Base Address: 0x0x024 */ +#define MXC_R_FLC_DATA ((uint32_t)0x00000030UL) /**< Offset from FLC Base Address: 0x0x030 */ +#define MXC_R_FLC_ACNTL ((uint32_t)0x00000040UL) /**< Offset from FLC Base Address: 0x0x040 */ +/**@} end of group flc_registers */ + +/** + * @ingroup flc_registers + * @defgroup ADDR_Register + * @brief Flash Write Address. + * @{ + */ +#define MXC_F_FLC_ADDR_ADDR_POS 0 /**< ADDR_ADDR Position */ +#define MXC_F_FLC_ADDR_ADDR ((uint32_t)(0xFFFFFFFFUL << MXC_F_FLC_ADDR_ADDR_POS)) /**< ADDR_ADDR Mask */ + +/**@} end of group ADDR_Register */ + +/** + * @ingroup flc_registers + * @defgroup CLKDIV_Register + * @brief Flash Clock Divide. The clock (PLL0) is divided by this value to generate a 1 + * MHz clock for Flash controller. + * @{ + */ +#define MXC_F_FLC_CLKDIV_CLKDIV_POS 0 /**< CLKDIV_CLKDIV Position */ +#define MXC_F_FLC_CLKDIV_CLKDIV ((uint32_t)(0xFFUL << MXC_F_FLC_CLKDIV_CLKDIV_POS)) /**< CLKDIV_CLKDIV Mask */ + +/**@} end of group CLKDIV_Register */ + +/** + * @ingroup flc_registers + * @defgroup CN_Register + * @brief Flash Control Register. + * @{ + */ +#define MXC_F_FLC_CN_WR_POS 0 /**< CN_WR Position */ +#define MXC_F_FLC_CN_WR ((uint32_t)(0x1UL << MXC_F_FLC_CN_WR_POS)) /**< CN_WR Mask */ +#define MXC_V_FLC_CN_WR_COMPLETE ((uint32_t)0x0UL) /**< CN_WR_COMPLETE Value */ +#define MXC_S_FLC_CN_WR_COMPLETE (MXC_V_FLC_CN_WR_COMPLETE << MXC_F_FLC_CN_WR_POS) /**< CN_WR_COMPLETE Setting */ +#define MXC_V_FLC_CN_WR_START ((uint32_t)0x1UL) /**< CN_WR_START Value */ +#define MXC_S_FLC_CN_WR_START (MXC_V_FLC_CN_WR_START << MXC_F_FLC_CN_WR_POS) /**< CN_WR_START Setting */ + +#define MXC_F_FLC_CN_ME_POS 1 /**< CN_ME Position */ +#define MXC_F_FLC_CN_ME ((uint32_t)(0x1UL << MXC_F_FLC_CN_ME_POS)) /**< CN_ME Mask */ + +#define MXC_F_FLC_CN_PGE_POS 2 /**< CN_PGE Position */ +#define MXC_F_FLC_CN_PGE ((uint32_t)(0x1UL << MXC_F_FLC_CN_PGE_POS)) /**< CN_PGE Mask */ + +#define MXC_F_FLC_CN_WDTH_POS 4 /**< CN_WDTH Position */ +#define MXC_F_FLC_CN_WDTH ((uint32_t)(0x1UL << MXC_F_FLC_CN_WDTH_POS)) /**< CN_WDTH Mask */ +#define MXC_V_FLC_CN_WDTH_SIZE128 ((uint32_t)0x0UL) /**< CN_WDTH_SIZE128 Value */ +#define MXC_S_FLC_CN_WDTH_SIZE128 (MXC_V_FLC_CN_WDTH_SIZE128 << MXC_F_FLC_CN_WDTH_POS) /**< CN_WDTH_SIZE128 Setting */ +#define MXC_V_FLC_CN_WDTH_SIZE32 ((uint32_t)0x1UL) /**< CN_WDTH_SIZE32 Value */ +#define MXC_S_FLC_CN_WDTH_SIZE32 (MXC_V_FLC_CN_WDTH_SIZE32 << MXC_F_FLC_CN_WDTH_POS) /**< CN_WDTH_SIZE32 Setting */ + +#define MXC_F_FLC_CN_ERASE_CODE_POS 8 /**< CN_ERASE_CODE Position */ +#define MXC_F_FLC_CN_ERASE_CODE ((uint32_t)(0xFFUL << MXC_F_FLC_CN_ERASE_CODE_POS)) /**< CN_ERASE_CODE Mask */ +#define MXC_V_FLC_CN_ERASE_CODE_NOP ((uint32_t)0x0UL) /**< CN_ERASE_CODE_NOP Value */ +#define MXC_S_FLC_CN_ERASE_CODE_NOP \ + (MXC_V_FLC_CN_ERASE_CODE_NOP << MXC_F_FLC_CN_ERASE_CODE_POS) /**< CN_ERASE_CODE_NOP Setting */ +#define MXC_V_FLC_CN_ERASE_CODE_ERASEPAGE ((uint32_t)0x55UL) /**< CN_ERASE_CODE_ERASEPAGE Value */ +#define MXC_S_FLC_CN_ERASE_CODE_ERASEPAGE \ + (MXC_V_FLC_CN_ERASE_CODE_ERASEPAGE << MXC_F_FLC_CN_ERASE_CODE_POS) /**< CN_ERASE_CODE_ERASEPAGE Setting */ +#define MXC_V_FLC_CN_ERASE_CODE_ERASEALL ((uint32_t)0xAAUL) /**< CN_ERASE_CODE_ERASEALL Value */ +#define MXC_S_FLC_CN_ERASE_CODE_ERASEALL \ + (MXC_V_FLC_CN_ERASE_CODE_ERASEALL << MXC_F_FLC_CN_ERASE_CODE_POS) /**< CN_ERASE_CODE_ERASEALL Setting */ + +#define MXC_F_FLC_CN_PEND_POS 24 /**< CN_PEND Position */ +#define MXC_F_FLC_CN_PEND ((uint32_t)(0x1UL << MXC_F_FLC_CN_PEND_POS)) /**< CN_PEND Mask */ +#define MXC_V_FLC_CN_PEND_IDLE ((uint32_t)0x0UL) /**< CN_PEND_IDLE Value */ +#define MXC_S_FLC_CN_PEND_IDLE (MXC_V_FLC_CN_PEND_IDLE << MXC_F_FLC_CN_PEND_POS) /**< CN_PEND_IDLE Setting */ +#define MXC_V_FLC_CN_PEND_BUSY ((uint32_t)0x1UL) /**< CN_PEND_BUSY Value */ +#define MXC_S_FLC_CN_PEND_BUSY (MXC_V_FLC_CN_PEND_BUSY << MXC_F_FLC_CN_PEND_POS) /**< CN_PEND_BUSY Setting */ + +#define MXC_F_FLC_CN_LVE_POS 25 /**< CN_LVE Position */ +#define MXC_F_FLC_CN_LVE ((uint32_t)(0x1UL << MXC_F_FLC_CN_LVE_POS)) /**< CN_LVE Mask */ +#define MXC_V_FLC_CN_LVE_DIS ((uint32_t)0x0UL) /**< CN_LVE_DIS Value */ +#define MXC_S_FLC_CN_LVE_DIS (MXC_V_FLC_CN_LVE_DIS << MXC_F_FLC_CN_LVE_POS) /**< CN_LVE_DIS Setting */ +#define MXC_V_FLC_CN_LVE_EN ((uint32_t)0x1UL) /**< CN_LVE_EN Value */ +#define MXC_S_FLC_CN_LVE_EN (MXC_V_FLC_CN_LVE_EN << MXC_F_FLC_CN_LVE_POS) /**< CN_LVE_EN Setting */ + +#define MXC_F_FLC_CN_BRST_POS 27 /**< CN_BRST Position */ +#define MXC_F_FLC_CN_BRST ((uint32_t)(0x1UL << MXC_F_FLC_CN_BRST_POS)) /**< CN_BRST Mask */ +#define MXC_V_FLC_CN_BRST_DISABLE ((uint32_t)0x0UL) /**< CN_BRST_DISABLE Value */ +#define MXC_S_FLC_CN_BRST_DISABLE (MXC_V_FLC_CN_BRST_DISABLE << MXC_F_FLC_CN_BRST_POS) /**< CN_BRST_DISABLE Setting */ +#define MXC_V_FLC_CN_BRST_ENABLE ((uint32_t)0x1UL) /**< CN_BRST_ENABLE Value */ +#define MXC_S_FLC_CN_BRST_ENABLE (MXC_V_FLC_CN_BRST_ENABLE << MXC_F_FLC_CN_BRST_POS) /**< CN_BRST_ENABLE Setting */ + +#define MXC_F_FLC_CN_UNLOCK_POS 28 /**< CN_UNLOCK Position */ +#define MXC_F_FLC_CN_UNLOCK ((uint32_t)(0xFUL << MXC_F_FLC_CN_UNLOCK_POS)) /**< CN_UNLOCK Mask */ +#define MXC_V_FLC_CN_UNLOCK_UNLOCKED ((uint32_t)0x2UL) /**< CN_UNLOCK_UNLOCKED Value */ +#define MXC_S_FLC_CN_UNLOCK_UNLOCKED \ + (MXC_V_FLC_CN_UNLOCK_UNLOCKED << MXC_F_FLC_CN_UNLOCK_POS) /**< CN_UNLOCK_UNLOCKED Setting */ +#define MXC_V_FLC_CN_UNLOCK_LOCKED ((uint32_t)0x3UL) /**< CN_UNLOCK_LOCKED Value */ +#define MXC_S_FLC_CN_UNLOCK_LOCKED \ + (MXC_V_FLC_CN_UNLOCK_LOCKED << MXC_F_FLC_CN_UNLOCK_POS) /**< CN_UNLOCK_LOCKED Setting */ + +/**@} end of group CN_Register */ + +/** + * @ingroup flc_registers + * @defgroup INTR_Register + * @brief Flash Interrupt Register. + * @{ + */ +#define MXC_F_FLC_INTR_DONE_POS 0 /**< INTR_DONE Position */ +#define MXC_F_FLC_INTR_DONE ((uint32_t)(0x1UL << MXC_F_FLC_INTR_DONE_POS)) /**< INTR_DONE Mask */ +#define MXC_V_FLC_INTR_DONE_INACTIVE ((uint32_t)0x0UL) /**< INTR_DONE_INACTIVE Value */ +#define MXC_S_FLC_INTR_DONE_INACTIVE \ + (MXC_V_FLC_INTR_DONE_INACTIVE << MXC_F_FLC_INTR_DONE_POS) /**< INTR_DONE_INACTIVE Setting */ +#define MXC_V_FLC_INTR_DONE_PENDING ((uint32_t)0x1UL) /**< INTR_DONE_PENDING Value */ +#define MXC_S_FLC_INTR_DONE_PENDING \ + (MXC_V_FLC_INTR_DONE_PENDING << MXC_F_FLC_INTR_DONE_POS) /**< INTR_DONE_PENDING Setting */ + +#define MXC_F_FLC_INTR_AF_POS 1 /**< INTR_AF Position */ +#define MXC_F_FLC_INTR_AF ((uint32_t)(0x1UL << MXC_F_FLC_INTR_AF_POS)) /**< INTR_AF Mask */ +#define MXC_V_FLC_INTR_AF_NOERROR ((uint32_t)0x0UL) /**< INTR_AF_NOERROR Value */ +#define MXC_S_FLC_INTR_AF_NOERROR (MXC_V_FLC_INTR_AF_NOERROR << MXC_F_FLC_INTR_AF_POS) /**< INTR_AF_NOERROR Setting */ +#define MXC_V_FLC_INTR_AF_ERROR ((uint32_t)0x1UL) /**< INTR_AF_ERROR Value */ +#define MXC_S_FLC_INTR_AF_ERROR (MXC_V_FLC_INTR_AF_ERROR << MXC_F_FLC_INTR_AF_POS) /**< INTR_AF_ERROR Setting */ + +#define MXC_F_FLC_INTR_DONEIE_POS 8 /**< INTR_DONEIE Position */ +#define MXC_F_FLC_INTR_DONEIE ((uint32_t)(0x1UL << MXC_F_FLC_INTR_DONEIE_POS)) /**< INTR_DONEIE Mask */ +#define MXC_V_FLC_INTR_DONEIE_DISABLE ((uint32_t)0x0UL) /**< INTR_DONEIE_DISABLE Value */ +#define MXC_S_FLC_INTR_DONEIE_DISABLE \ + (MXC_V_FLC_INTR_DONEIE_DISABLE << MXC_F_FLC_INTR_DONEIE_POS) /**< INTR_DONEIE_DISABLE Setting */ +#define MXC_V_FLC_INTR_DONEIE_ENABLE ((uint32_t)0x1UL) /**< INTR_DONEIE_ENABLE Value */ +#define MXC_S_FLC_INTR_DONEIE_ENABLE \ + (MXC_V_FLC_INTR_DONEIE_ENABLE << MXC_F_FLC_INTR_DONEIE_POS) /**< INTR_DONEIE_ENABLE Setting */ + +#define MXC_F_FLC_INTR_AFIE_POS 9 /**< INTR_AFIE Position */ +#define MXC_F_FLC_INTR_AFIE ((uint32_t)(0x1UL << MXC_F_FLC_INTR_AFIE_POS)) /**< INTR_AFIE Mask */ + +/**@} end of group INTR_Register */ + +/** + * @ingroup flc_registers + * @defgroup DATA_Register + * @brief Flash Write Data. + * @{ + */ +#define MXC_F_FLC_DATA_DATA_POS 0 /**< DATA_DATA Position */ +#define MXC_F_FLC_DATA_DATA ((uint32_t)(0xFFFFFFFFUL << MXC_F_FLC_DATA_DATA_POS)) /**< DATA_DATA Mask */ + +/**@} end of group DATA_Register */ + +/** + * @ingroup flc_registers + * @defgroup ACNTL_Register + * @brief Access Control Register. Writing the ACNTL register with the following values in + * the order shown, allows read and write access to the system and user Information + * block: pflc-acntl = 0x3a7f5ca3; pflc-acntl = 0xa1e34f20; pflc-acntl = + * 0x9608b2c1. When unlocked, a write of any word will disable access to system and + * user information block. Readback of this register is always zero. + * @{ + */ +#define MXC_F_FLC_ACNTL_ACNTL_POS 0 /**< ACNTL_ACNTL Position */ +#define MXC_F_FLC_ACNTL_ACNTL ((uint32_t)(0xFFFFFFFFUL << MXC_F_FLC_ACNTL_ACNTL_POS)) /**< ACNTL_ACNTL Mask */ + +/**@} end of group ACNTL_Register */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLC_REGS_H_ */ diff --git a/contrib/loaders/flash/max32xxx/gcr_regs.h b/contrib/loaders/flash/max32xxx/gcr_regs.h new file mode 100644 index 0000000000..0c5ccdbf3e --- /dev/null +++ b/contrib/loaders/flash/max32xxx/gcr_regs.h @@ -0,0 +1,777 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2016 by Maxim Integrated * + * Copyright (C) 2025 Analog Devices, Inc. * + ***************************************************************************/ + +#ifndef _GCR_REGS_H_ +#define _GCR_REGS_H_ + +/* **** Includes **** */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__ICCARM__) +#pragma system_include +#endif + +#if defined(__CC_ARM) +#pragma anon_unions +#endif +/*/ @cond */ +/* + If types are not defined elsewhere (CMSIS) define them here +*/ +#ifndef __IO +#define __IO volatile +#endif +#ifndef __I +#define __I volatile const +#endif +#ifndef __O +#define __O volatile +#endif +#ifndef __R +#define __R volatile const +#endif +/*/ @endcond */ + +/* **** Definitions **** */ + +/** + * @ingroup gcr + * @defgroup gcr_registers GCR_Registers + * @brief Registers, Bit Masks and Bit Positions for the GCR Peripheral Module. + * @details Global Control Registers. + */ + +/** + * @ingroup gcr_registers + * Structure type to access the GCR Registers. + */ +struct mxc_gcr_regs { + __IO uint32_t scon; /**< \b 0x00: GCR SCON Register */ + __IO uint32_t rstr0; /**< \b 0x04: GCR RSTR0 Register */ + __IO uint32_t clkcn; /**< \b 0x08: GCR CLKCN Register */ + __IO uint32_t pm; /**< \b 0x0C: GCR PM Register */ + __R uint32_t rsv_0x10_0x17[2]; + __IO uint32_t pckdiv; /**< \b 0x18: GCR PCKDIV Register */ + __R uint32_t rsv_0x1c_0x23[2]; + __IO uint32_t perckcn0; /**< \b 0x24: GCR PERCKCN0 Register */ + __IO uint32_t memckcn; /**< \b 0x28: GCR MEMCKCN Register */ + __IO uint32_t memzcn; /**< \b 0x2C: GCR MEMZCN Register */ + __R uint32_t rsv_0x30_0x3f[4]; + __IO uint32_t sysst; /**< \b 0x40: GCR SYSST Register */ + __IO uint32_t rstr1; /**< \b 0x44: GCR RSTR1 Register */ + __IO uint32_t perckcn1; /**< \b 0x48: GCR PERCKCN1 Register */ + __IO uint32_t evten; /**< \b 0x4C: GCR EVTEN Register */ + __I uint32_t revision; /**< \b 0x50: GCR REVISION Register */ + __IO uint32_t syssie; /**< \b 0x54: GCR SYSSIE Register */ + __R uint32_t rsv_0x58_0x63[3]; + __IO uint32_t eccerr; /**< \b 0x64: GCR ECCERR Register */ + __IO uint32_t eccnded; /**< \b 0x68: GCR ECCNDED Register */ + __IO uint32_t eccirqen; /**< \b 0x6C: GCR ECCIRQEN Register */ + __IO uint32_t eccerrad; /**< \b 0x70: GCR ECCERRAD Register */ +}; + +/* Register offsets for module GCR */ +/** + * @ingroup gcr_registers + * @defgroup GCR_Register_Offsets Register Offsets + * @brief GCR Peripheral Register Offsets from the GCR Base Peripheral Address. + * @{ + */ +#define MXC_R_GCR_SCON ((uint32_t)0x00000000UL) /**< Offset from GCR Base Address: 0x0000 */ +#define MXC_R_GCR_RSTR0 ((uint32_t)0x00000004UL) /**< Offset from GCR Base Address: 0x0004 */ +#define MXC_R_GCR_CLKCN ((uint32_t)0x00000008UL) /**< Offset from GCR Base Address: 0x0008 */ +#define MXC_R_GCR_PM ((uint32_t)0x0000000CUL) /**< Offset from GCR Base Address: 0x000C */ +#define MXC_R_GCR_PCKDIV ((uint32_t)0x00000018UL) /**< Offset from GCR Base Address: 0x0018 */ +#define MXC_R_GCR_PERCKCN0 ((uint32_t)0x00000024UL) /**< Offset from GCR Base Address: 0x0024 */ +#define MXC_R_GCR_MEMCKCN ((uint32_t)0x00000028UL) /**< Offset from GCR Base Address: 0x0028 */ +#define MXC_R_GCR_MEMZCN ((uint32_t)0x0000002CUL) /**< Offset from GCR Base Address: 0x002C */ +#define MXC_R_GCR_SYSST ((uint32_t)0x00000040UL) /**< Offset from GCR Base Address: 0x0040 */ +#define MXC_R_GCR_RSTR1 ((uint32_t)0x00000044UL) /**< Offset from GCR Base Address: 0x0044 */ +#define MXC_R_GCR_PERCKCN1 ((uint32_t)0x00000048UL) /**< Offset from GCR Base Address: 0x0048 */ +#define MXC_R_GCR_EVTEN ((uint32_t)0x0000004CUL) /**< Offset from GCR Base Address: 0x004C */ +#define MXC_R_GCR_REVISION ((uint32_t)0x00000050UL) /**< Offset from GCR Base Address: 0x0050 */ +#define MXC_R_GCR_SYSSIE ((uint32_t)0x00000054UL) /**< Offset from GCR Base Address: 0x0054 */ +#define MXC_R_GCR_ECCERR ((uint32_t)0x00000064UL) /**< Offset from GCR Base Address: 0x0064 */ +#define MXC_R_GCR_ECCNDED ((uint32_t)0x00000068UL) /**< Offset from GCR Base Address: 0x0068 */ +#define MXC_R_GCR_ECCIRQEN ((uint32_t)0x0000006CUL) /**< Offset from GCR Base Address: 0x006C */ +#define MXC_R_GCR_ECCERRAD ((uint32_t)0x00000070UL) /**< Offset from GCR Base Address: 0x0070 */ + /**@} end of group gcr_registers */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_SCON GCR_SCON + * @brief System Control. + * @{ + */ +#define MXC_F_GCR_SCON_BSTAPEN_POS 0 /**< SCON_BSTAPEN Position */ +#define MXC_F_GCR_SCON_BSTAPEN ((uint32_t)(0x1UL << MXC_F_GCR_SCON_BSTAPEN_POS)) /**< SCON_BSTAPEN Mask */ +#define MXC_V_GCR_SCON_BSTAPEN_DIS ((uint32_t)0x0UL) /**< SCON_BSTAPEN_DIS Value */ +#define MXC_S_GCR_SCON_BSTAPEN_DIS \ + (MXC_V_GCR_SCON_BSTAPEN_DIS << MXC_F_GCR_SCON_BSTAPEN_POS) /**< SCON_BSTAPEN_DIS Setting */ +#define MXC_V_GCR_SCON_BSTAPEN_EN ((uint32_t)0x1UL) /**< SCON_BSTAPEN_EN Value */ +#define MXC_S_GCR_SCON_BSTAPEN_EN \ + (MXC_V_GCR_SCON_BSTAPEN_EN << MXC_F_GCR_SCON_BSTAPEN_POS) /**< SCON_BSTAPEN_EN Setting */ + +#define MXC_F_GCR_SCON_SBUSARB_POS 1 /**< SCON_SBUSARB Position */ +#define MXC_F_GCR_SCON_SBUSARB ((uint32_t)(0x3UL << MXC_F_GCR_SCON_SBUSARB_POS)) /**< SCON_SBUSARB Mask */ +#define MXC_V_GCR_SCON_SBUSARB_FIX ((uint32_t)0x0UL) /**< SCON_SBUSARB_FIX Value */ +#define MXC_S_GCR_SCON_SBUSARB_FIX \ + (MXC_V_GCR_SCON_SBUSARB_FIX << MXC_F_GCR_SCON_SBUSARB_POS) /**< SCON_SBUSARB_FIX Setting */ +#define MXC_V_GCR_SCON_SBUSARB_ROUND ((uint32_t)0x1UL) /**< SCON_SBUSARB_ROUND Value */ +#define MXC_S_GCR_SCON_SBUSARB_ROUND \ + (MXC_V_GCR_SCON_SBUSARB_ROUND << MXC_F_GCR_SCON_SBUSARB_POS) /**< SCON_SBUSARB_ROUND Setting */ + +#define MXC_F_GCR_SCON_FLASH_PAGE_FLIP_POS 4 /**< SCON_FLASH_PAGE_FLIP Position */ +#define MXC_F_GCR_SCON_FLASH_PAGE_FLIP \ + ((uint32_t)(0x1UL << MXC_F_GCR_SCON_FLASH_PAGE_FLIP_POS)) /**< SCON_FLASH_PAGE_FLIP Mask */ +#define MXC_V_GCR_SCON_FLASH_PAGE_FLIP_NORMAL ((uint32_t)0x0UL) /**< SCON_FLASH_PAGE_FLIP_NORMAL Value */ +#define MXC_S_GCR_SCON_FLASH_PAGE_FLIP_NORMAL \ + (MXC_V_GCR_SCON_FLASH_PAGE_FLIP_NORMAL \ + << MXC_F_GCR_SCON_FLASH_PAGE_FLIP_POS) /**< SCON_FLASH_PAGE_FLIP_NORMAL Setting */ +#define MXC_V_GCR_SCON_FLASH_PAGE_FLIP_SWAPPED ((uint32_t)0x1UL) /**< SCON_FLASH_PAGE_FLIP_SWAPPED Value */ +#define MXC_S_GCR_SCON_FLASH_PAGE_FLIP_SWAPPED \ + (MXC_V_GCR_SCON_FLASH_PAGE_FLIP_SWAPPED \ + << MXC_F_GCR_SCON_FLASH_PAGE_FLIP_POS) /**< SCON_FLASH_PAGE_FLIP_SWAPPED Setting */ + +#define MXC_F_GCR_SCON_CCACHE_FLUSH_POS 6 /**< SCON_CCACHE_FLUSH Position */ +#define MXC_F_GCR_SCON_CCACHE_FLUSH \ + ((uint32_t)(0x1UL << MXC_F_GCR_SCON_CCACHE_FLUSH_POS)) /**< SCON_CCACHE_FLUSH Mask */ +#define MXC_V_GCR_SCON_CCACHE_FLUSH_NORMAL ((uint32_t)0x0UL) /**< SCON_CCACHE_FLUSH_NORMAL Value */ +#define MXC_S_GCR_SCON_CCACHE_FLUSH_NORMAL \ + (MXC_V_GCR_SCON_CCACHE_FLUSH_NORMAL << MXC_F_GCR_SCON_CCACHE_FLUSH_POS) /**< SCON_CCACHE_FLUSH_NORMAL Setting */ +#define MXC_V_GCR_SCON_CCACHE_FLUSH_FLUSH ((uint32_t)0x1UL) /**< SCON_CCACHE_FLUSH_FLUSH Value */ +#define MXC_S_GCR_SCON_CCACHE_FLUSH_FLUSH \ + (MXC_V_GCR_SCON_CCACHE_FLUSH_FLUSH << MXC_F_GCR_SCON_CCACHE_FLUSH_POS) /**< SCON_CCACHE_FLUSH_FLUSH Setting */ + +#define MXC_F_GCR_SCON_CCHK_POS 13 /**< SCON_CCHK Position */ +#define MXC_F_GCR_SCON_CCHK ((uint32_t)(0x1UL << MXC_F_GCR_SCON_CCHK_POS)) /**< SCON_CCHK Mask */ +#define MXC_V_GCR_SCON_CCHK_COMPLETE ((uint32_t)0x0UL) /**< SCON_CCHK_COMPLETE Value */ +#define MXC_S_GCR_SCON_CCHK_COMPLETE \ + (MXC_V_GCR_SCON_CCHK_COMPLETE << MXC_F_GCR_SCON_CCHK_POS) /**< SCON_CCHK_COMPLETE Setting */ +#define MXC_V_GCR_SCON_CCHK_START ((uint32_t)0x1UL) /**< SCON_CCHK_START Value */ +#define MXC_S_GCR_SCON_CCHK_START (MXC_V_GCR_SCON_CCHK_START << MXC_F_GCR_SCON_CCHK_POS) /**< SCON_CCHK_START Setting \ + */ + +#define MXC_F_GCR_SCON_CHKRES_POS 15 /**< SCON_CHKRES Position */ +#define MXC_F_GCR_SCON_CHKRES ((uint32_t)(0x1UL << MXC_F_GCR_SCON_CHKRES_POS)) /**< SCON_CHKRES Mask */ +#define MXC_V_GCR_SCON_CHKRES_PASS ((uint32_t)0x0UL) /**< SCON_CHKRES_PASS Value */ +#define MXC_S_GCR_SCON_CHKRES_PASS \ + (MXC_V_GCR_SCON_CHKRES_PASS << MXC_F_GCR_SCON_CHKRES_POS) /**< SCON_CHKRES_PASS Setting */ +#define MXC_V_GCR_SCON_CHKRES_FAIL ((uint32_t)0x1UL) /**< SCON_CHKRES_FAIL Value */ +#define MXC_S_GCR_SCON_CHKRES_FAIL \ + (MXC_V_GCR_SCON_CHKRES_FAIL << MXC_F_GCR_SCON_CHKRES_POS) /**< SCON_CHKRES_FAIL Setting */ + +#define MXC_F_GCR_SCON_OVR_POS 16 /**< SCON_OVR Position */ +#define MXC_F_GCR_SCON_OVR ((uint32_t)(0x3UL << MXC_F_GCR_SCON_OVR_POS)) /**< SCON_OVR Mask */ +#define MXC_V_GCR_SCON_OVR_0_9V ((uint32_t)0x0UL) /**< SCON_OVR_0_9V Value */ +#define MXC_S_GCR_SCON_OVR_0_9V (MXC_V_GCR_SCON_OVR_0_9V << MXC_F_GCR_SCON_OVR_POS) /**< SCON_OVR_0_9V Setting */ +#define MXC_V_GCR_SCON_OVR_1_0V ((uint32_t)0x1UL) /**< SCON_OVR_1_0V Value */ +#define MXC_S_GCR_SCON_OVR_1_0V (MXC_V_GCR_SCON_OVR_1_0V << MXC_F_GCR_SCON_OVR_POS) /**< SCON_OVR_1_0V Setting */ +#define MXC_V_GCR_SCON_OVR_1_1V ((uint32_t)0x2UL) /**< SCON_OVR_1_1V Value */ +#define MXC_S_GCR_SCON_OVR_1_1V (MXC_V_GCR_SCON_OVR_1_1V << MXC_F_GCR_SCON_OVR_POS) /**< SCON_OVR_1_1V Setting */ + +#define MXC_F_GCR_SCON_MEMPROT_EN_POS 20 /**< SCON_MEMPROT_EN Position */ +#define MXC_F_GCR_SCON_MEMPROT_EN ((uint32_t)(0x1UL << MXC_F_GCR_SCON_MEMPROT_EN_POS)) /**< SCON_MEMPROT_EN Mask */ +#define MXC_V_GCR_SCON_MEMPROT_EN_DIS ((uint32_t)0x0UL) /**< SCON_MEMPROT_EN_DIS Value */ +#define MXC_S_GCR_SCON_MEMPROT_EN_DIS \ + (MXC_V_GCR_SCON_MEMPROT_EN_DIS << MXC_F_GCR_SCON_MEMPROT_EN_POS) /**< SCON_MEMPROT_EN_DIS Setting */ +#define MXC_V_GCR_SCON_MEMPROT_EN_EN ((uint32_t)0x1UL) /**< SCON_MEMPROT_EN_EN Value */ +#define MXC_S_GCR_SCON_MEMPROT_EN_EN \ + (MXC_V_GCR_SCON_MEMPROT_EN_EN << MXC_F_GCR_SCON_MEMPROT_EN_POS) /**< SCON_MEMPROT_EN_EN Setting */ + +#define MXC_F_GCR_SCON_MEMPROT_KEYSZ_POS 21 /**< SCON_MEMPROT_KEYSZ Position */ +#define MXC_F_GCR_SCON_MEMPROT_KEYSZ \ + ((uint32_t)(0x1UL << MXC_F_GCR_SCON_MEMPROT_KEYSZ_POS)) /**< SCON_MEMPROT_KEYSZ Mask */ +#define MXC_V_GCR_SCON_MEMPROT_KEYSZ_128 ((uint32_t)0x0UL) /**< SCON_MEMPROT_KEYSZ_128 Value */ +#define MXC_S_GCR_SCON_MEMPROT_KEYSZ_128 \ + (MXC_V_GCR_SCON_MEMPROT_KEYSZ_128 << MXC_F_GCR_SCON_MEMPROT_KEYSZ_POS) /**< SCON_MEMPROT_KEYSZ_128 Setting */ +#define MXC_V_GCR_SCON_MEMPROT_KEYSZ_256 ((uint32_t)0x1UL) /**< SCON_MEMPROT_KEYSZ_256 Value */ +#define MXC_S_GCR_SCON_MEMPROT_KEYSZ_256 \ + (MXC_V_GCR_SCON_MEMPROT_KEYSZ_256 << MXC_F_GCR_SCON_MEMPROT_KEYSZ_POS) /**< SCON_MEMPROT_KEYSZ_256 Setting */ + +/**@} end of group GCR_SCON_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_RSTR0 GCR_RSTR0 + * @brief Reset. + * @{ + */ +#define MXC_F_GCR_RSTR0_DMA_POS 0 /**< RSTR0_DMA Position */ +#define MXC_F_GCR_RSTR0_DMA ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_DMA_POS)) /**< RSTR0_DMA Mask */ +#define MXC_V_GCR_RSTR0_DMA_RESET_DONE ((uint32_t)0x0UL) /**< RSTR0_DMA_RESET_DONE Value */ +#define MXC_S_GCR_RSTR0_DMA_RESET_DONE \ + (MXC_V_GCR_RSTR0_DMA_RESET_DONE << MXC_F_GCR_RSTR0_DMA_POS) /**< RSTR0_DMA_RESET_DONE Setting */ +#define MXC_V_GCR_RSTR0_DMA_BUSY ((uint32_t)0x1UL) /**< RSTR0_DMA_BUSY Value */ +#define MXC_S_GCR_RSTR0_DMA_BUSY (MXC_V_GCR_RSTR0_DMA_BUSY << MXC_F_GCR_RSTR0_DMA_POS) /**< RSTR0_DMA_BUSY Setting */ + +#define MXC_F_GCR_RSTR0_WDT_POS 1 /**< RSTR0_WDT Position */ +#define MXC_F_GCR_RSTR0_WDT ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_WDT_POS)) /**< RSTR0_WDT Mask */ + +#define MXC_F_GCR_RSTR0_GPIO0_POS 2 /**< RSTR0_GPIO0 Position */ +#define MXC_F_GCR_RSTR0_GPIO0 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_GPIO0_POS)) /**< RSTR0_GPIO0 Mask */ + +#define MXC_F_GCR_RSTR0_GPIO1_POS 3 /**< RSTR0_GPIO1 Position */ +#define MXC_F_GCR_RSTR0_GPIO1 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_GPIO1_POS)) /**< RSTR0_GPIO1 Mask */ + +#define MXC_F_GCR_RSTR0_TIMER0_POS 5 /**< RSTR0_TIMER0 Position */ +#define MXC_F_GCR_RSTR0_TIMER0 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_TIMER0_POS)) /**< RSTR0_TIMER0 Mask */ + +#define MXC_F_GCR_RSTR0_TIMER1_POS 6 /**< RSTR0_TIMER1 Position */ +#define MXC_F_GCR_RSTR0_TIMER1 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_TIMER1_POS)) /**< RSTR0_TIMER1 Mask */ + +#define MXC_F_GCR_RSTR0_TIMER2_POS 7 /**< RSTR0_TIMER2 Position */ +#define MXC_F_GCR_RSTR0_TIMER2 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_TIMER2_POS)) /**< RSTR0_TIMER2 Mask */ + +#define MXC_F_GCR_RSTR0_TIMER3_POS 8 /**< RSTR0_TIMER3 Position */ +#define MXC_F_GCR_RSTR0_TIMER3 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_TIMER3_POS)) /**< RSTR0_TIMER3 Mask */ + +#define MXC_F_GCR_RSTR0_UART0_POS 11 /**< RSTR0_UART0 Position */ +#define MXC_F_GCR_RSTR0_UART0 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_UART0_POS)) /**< RSTR0_UART0 Mask */ + +#define MXC_F_GCR_RSTR0_SPI0_POS 13 /**< RSTR0_SPI0 Position */ +#define MXC_F_GCR_RSTR0_SPI0 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_SPI0_POS)) /**< RSTR0_SPI0 Mask */ + +#define MXC_F_GCR_RSTR0_SPI1_POS 14 /**< RSTR0_SPI1 Position */ +#define MXC_F_GCR_RSTR0_SPI1 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_SPI1_POS)) /**< RSTR0_SPI1 Mask */ + +#define MXC_F_GCR_RSTR0_I2C0_POS 16 /**< RSTR0_I2C0 Position */ +#define MXC_F_GCR_RSTR0_I2C0 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_I2C0_POS)) /**< RSTR0_I2C0 Mask */ + +#define MXC_F_GCR_RSTR0_CRYPTO_POS 18 /**< RSTR0_CRYPTO Position */ +#define MXC_F_GCR_RSTR0_CRYPTO ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_CRYPTO_POS)) /**< RSTR0_CRYPTO Mask */ + +#define MXC_F_GCR_RSTR0_SMPHR_POS 22 /**< RSTR0_SMPHR Position */ +#define MXC_F_GCR_RSTR0_SMPHR ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_SMPHR_POS)) /**< RSTR0_SMPHR Mask */ + +#define MXC_F_GCR_RSTR0_TRNG_POS 24 /**< RSTR0_TRNG Position */ +#define MXC_F_GCR_RSTR0_TRNG ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_TRNG_POS)) /**< RSTR0_TRNG Mask */ + +#define MXC_F_GCR_RSTR0_SRST_POS 29 /**< RSTR0_SRST Position */ +#define MXC_F_GCR_RSTR0_SRST ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_SRST_POS)) /**< RSTR0_SRST Mask */ + +#define MXC_F_GCR_RSTR0_PRST_POS 30 /**< RSTR0_PRST Position */ +#define MXC_F_GCR_RSTR0_PRST ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_PRST_POS)) /**< RSTR0_PRST Mask */ + +#define MXC_F_GCR_RSTR0_SYSTEM_POS 31 /**< RSTR0_SYSTEM Position */ +#define MXC_F_GCR_RSTR0_SYSTEM ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_SYSTEM_POS)) /**< RSTR0_SYSTEM Mask */ + +/**@} end of group GCR_RSTR0_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_CLKCN GCR_CLKCN + * @brief Clock Control. + * @{ + */ +#define MXC_F_GCR_CLKCN_PSC_POS 6 /**< CLKCN_PSC Position */ +#define MXC_F_GCR_CLKCN_PSC ((uint32_t)(0x7UL << MXC_F_GCR_CLKCN_PSC_POS)) /**< CLKCN_PSC Mask */ +#define MXC_V_GCR_CLKCN_PSC_DIV1 ((uint32_t)0x0UL) /**< CLKCN_PSC_DIV1 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV1 (MXC_V_GCR_CLKCN_PSC_DIV1 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV1 Setting */ +#define MXC_V_GCR_CLKCN_PSC_DIV2 ((uint32_t)0x1UL) /**< CLKCN_PSC_DIV2 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV2 (MXC_V_GCR_CLKCN_PSC_DIV2 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV2 Setting */ +#define MXC_V_GCR_CLKCN_PSC_DIV4 ((uint32_t)0x2UL) /**< CLKCN_PSC_DIV4 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV4 (MXC_V_GCR_CLKCN_PSC_DIV4 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV4 Setting */ +#define MXC_V_GCR_CLKCN_PSC_DIV8 ((uint32_t)0x3UL) /**< CLKCN_PSC_DIV8 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV8 (MXC_V_GCR_CLKCN_PSC_DIV8 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV8 Setting */ +#define MXC_V_GCR_CLKCN_PSC_DIV16 ((uint32_t)0x4UL) /**< CLKCN_PSC_DIV16 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV16 (MXC_V_GCR_CLKCN_PSC_DIV16 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV16 Setting \ + */ +#define MXC_V_GCR_CLKCN_PSC_DIV32 ((uint32_t)0x5UL) /**< CLKCN_PSC_DIV32 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV32 (MXC_V_GCR_CLKCN_PSC_DIV32 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV32 Setting \ + */ +#define MXC_V_GCR_CLKCN_PSC_DIV64 ((uint32_t)0x6UL) /**< CLKCN_PSC_DIV64 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV64 (MXC_V_GCR_CLKCN_PSC_DIV64 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV64 Setting \ + */ +#define MXC_V_GCR_CLKCN_PSC_DIV128 ((uint32_t)0x7UL) /**< CLKCN_PSC_DIV128 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV128 \ + (MXC_V_GCR_CLKCN_PSC_DIV128 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV128 Setting */ + +#define MXC_F_GCR_CLKCN_CLKSEL_POS 9 /**< CLKCN_CLKSEL Position */ +#define MXC_F_GCR_CLKCN_CLKSEL ((uint32_t)(0x7UL << MXC_F_GCR_CLKCN_CLKSEL_POS)) /**< CLKCN_CLKSEL Mask */ +#define MXC_V_GCR_CLKCN_CLKSEL_HIRC ((uint32_t)0x0UL) /**< CLKCN_CLKSEL_HIRC Value */ +#define MXC_S_GCR_CLKCN_CLKSEL_HIRC \ + (MXC_V_GCR_CLKCN_CLKSEL_HIRC << MXC_F_GCR_CLKCN_CLKSEL_POS) /**< CLKCN_CLKSEL_HIRC Setting */ +#define MXC_V_GCR_CLKCN_CLKSEL_LIRC8 ((uint32_t)0x3UL) /**< CLKCN_CLKSEL_LIRC8 Value */ +#define MXC_S_GCR_CLKCN_CLKSEL_LIRC8 \ + (MXC_V_GCR_CLKCN_CLKSEL_LIRC8 << MXC_F_GCR_CLKCN_CLKSEL_POS) /**< CLKCN_CLKSEL_LIRC8 Setting */ +#define MXC_V_GCR_CLKCN_CLKSEL_HIRC8 ((uint32_t)0x5UL) /**< CLKCN_CLKSEL_HIRC8 Value */ +#define MXC_S_GCR_CLKCN_CLKSEL_HIRC8 \ + (MXC_V_GCR_CLKCN_CLKSEL_HIRC8 << MXC_F_GCR_CLKCN_CLKSEL_POS) /**< CLKCN_CLKSEL_HIRC8 Setting */ + +#define MXC_F_GCR_CLKCN_CKRDY_POS 13 /**< CLKCN_CKRDY Position */ +#define MXC_F_GCR_CLKCN_CKRDY ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_CKRDY_POS)) /**< CLKCN_CKRDY Mask */ +#define MXC_V_GCR_CLKCN_CKRDY_BUSY ((uint32_t)0x0UL) /**< CLKCN_CKRDY_BUSY Value */ +#define MXC_S_GCR_CLKCN_CKRDY_BUSY \ + (MXC_V_GCR_CLKCN_CKRDY_BUSY << MXC_F_GCR_CLKCN_CKRDY_POS) /**< CLKCN_CKRDY_BUSY Setting */ +#define MXC_V_GCR_CLKCN_CKRDY_READY ((uint32_t)0x1UL) /**< CLKCN_CKRDY_READY Value */ +#define MXC_S_GCR_CLKCN_CKRDY_READY \ + (MXC_V_GCR_CLKCN_CKRDY_READY << MXC_F_GCR_CLKCN_CKRDY_POS) /**< CLKCN_CKRDY_READY Setting */ + +#define MXC_F_GCR_CLKCN_HIRC_EN_POS 18 /**< CLKCN_HIRC_EN Position */ +#define MXC_F_GCR_CLKCN_HIRC_EN ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_HIRC_EN_POS)) /**< CLKCN_HIRC_EN Mask */ +#define MXC_V_GCR_CLKCN_HIRC_EN_DIS ((uint32_t)0x0UL) /**< CLKCN_HIRC_EN_DIS Value */ +#define MXC_S_GCR_CLKCN_HIRC_EN_DIS \ + (MXC_V_GCR_CLKCN_HIRC_EN_DIS << MXC_F_GCR_CLKCN_HIRC_EN_POS) /**< CLKCN_HIRC_EN_DIS Setting */ +#define MXC_V_GCR_CLKCN_HIRC_EN_EN ((uint32_t)0x1UL) /**< CLKCN_HIRC_EN_EN Value */ +#define MXC_S_GCR_CLKCN_HIRC_EN_EN \ + (MXC_V_GCR_CLKCN_HIRC_EN_EN << MXC_F_GCR_CLKCN_HIRC_EN_POS) /**< CLKCN_HIRC_EN_EN Setting */ + +#define MXC_F_GCR_CLKCN_HIRC8M_EN_POS 20 /**< CLKCN_HIRC8M_EN Position */ +#define MXC_F_GCR_CLKCN_HIRC8M_EN ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_HIRC8M_EN_POS)) /**< CLKCN_HIRC8M_EN Mask */ + +#define MXC_F_GCR_CLKCN_HIRC8M_VS_POS 21 /**< CLKCN_HIRC8M_VS Position */ +#define MXC_F_GCR_CLKCN_HIRC8M_VS ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_HIRC8M_VS_POS)) /**< CLKCN_HIRC8M_VS Mask */ +#define MXC_V_GCR_CLKCN_HIRC8M_VS_VCOR ((uint32_t)0x0UL) /**< CLKCN_HIRC8M_VS_VCOR Value */ +#define MXC_S_GCR_CLKCN_HIRC8M_VS_VCOR \ + (MXC_V_GCR_CLKCN_HIRC8M_VS_VCOR << MXC_F_GCR_CLKCN_HIRC8M_VS_POS) /**< CLKCN_HIRC8M_VS_VCOR Setting */ +#define MXC_V_GCR_CLKCN_HIRC8M_VS_1V ((uint32_t)0x1UL) /**< CLKCN_HIRC8M_VS_1V Value */ +#define MXC_S_GCR_CLKCN_HIRC8M_VS_1V \ + (MXC_V_GCR_CLKCN_HIRC8M_VS_1V << MXC_F_GCR_CLKCN_HIRC8M_VS_POS) /**< CLKCN_HIRC8M_VS_1V Setting */ + +#define MXC_F_GCR_CLKCN_HIRC_RDY_POS 26 /**< CLKCN_HIRC_RDY Position */ +#define MXC_F_GCR_CLKCN_HIRC_RDY ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_HIRC_RDY_POS)) /**< CLKCN_HIRC_RDY Mask */ +#define MXC_V_GCR_CLKCN_HIRC_RDY_NOT ((uint32_t)0x0UL) /**< CLKCN_HIRC_RDY_NOT Value */ +#define MXC_S_GCR_CLKCN_HIRC_RDY_NOT \ + (MXC_V_GCR_CLKCN_HIRC_RDY_NOT << MXC_F_GCR_CLKCN_HIRC_RDY_POS) /**< CLKCN_HIRC_RDY_NOT Setting */ +#define MXC_V_GCR_CLKCN_HIRC_RDY_READY ((uint32_t)0x1UL) /**< CLKCN_HIRC_RDY_READY Value */ +#define MXC_S_GCR_CLKCN_HIRC_RDY_READY \ + (MXC_V_GCR_CLKCN_HIRC_RDY_READY << MXC_F_GCR_CLKCN_HIRC_RDY_POS) /**< CLKCN_HIRC_RDY_READY Setting */ + +#define MXC_F_GCR_CLKCN_HIRC8M_RDY_POS 28 /**< CLKCN_HIRC8M_RDY Position */ +#define MXC_F_GCR_CLKCN_HIRC8M_RDY ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_HIRC8M_RDY_POS)) /**< CLKCN_HIRC8M_RDY Mask */ + +#define MXC_F_GCR_CLKCN_LIRC8K_RDY_POS 29 /**< CLKCN_LIRC8K_RDY Position */ +#define MXC_F_GCR_CLKCN_LIRC8K_RDY ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_LIRC8K_RDY_POS)) /**< CLKCN_LIRC8K_RDY Mask */ + +/**@} end of group GCR_CLKCN_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_PM GCR_PM + * @brief Power Management. + * @{ + */ +#define MXC_F_GCR_PM_MODE_POS 0 /**< PM_MODE Position */ +#define MXC_F_GCR_PM_MODE ((uint32_t)(0x7UL << MXC_F_GCR_PM_MODE_POS)) /**< PM_MODE Mask */ +#define MXC_V_GCR_PM_MODE_ACTIVE ((uint32_t)0x0UL) /**< PM_MODE_ACTIVE Value */ +#define MXC_S_GCR_PM_MODE_ACTIVE (MXC_V_GCR_PM_MODE_ACTIVE << MXC_F_GCR_PM_MODE_POS) /**< PM_MODE_ACTIVE Setting */ +#define MXC_V_GCR_PM_MODE_DEEPSLEEP ((uint32_t)0x2UL) /**< PM_MODE_DEEPSLEEP Value */ +#define MXC_S_GCR_PM_MODE_DEEPSLEEP \ + (MXC_V_GCR_PM_MODE_DEEPSLEEP << MXC_F_GCR_PM_MODE_POS) /**< PM_MODE_DEEPSLEEP Setting */ +#define MXC_V_GCR_PM_MODE_SHUTDOWN ((uint32_t)0x3UL) /**< PM_MODE_SHUTDOWN Value */ +#define MXC_S_GCR_PM_MODE_SHUTDOWN \ + (MXC_V_GCR_PM_MODE_SHUTDOWN << MXC_F_GCR_PM_MODE_POS) /**< PM_MODE_SHUTDOWN Setting */ +#define MXC_V_GCR_PM_MODE_BACKUP ((uint32_t)0x4UL) /**< PM_MODE_BACKUP Value */ +#define MXC_S_GCR_PM_MODE_BACKUP (MXC_V_GCR_PM_MODE_BACKUP << MXC_F_GCR_PM_MODE_POS) /**< PM_MODE_BACKUP Setting */ + +#define MXC_F_GCR_PM_GPIOWKEN_POS 4 /**< PM_GPIOWKEN Position */ +#define MXC_F_GCR_PM_GPIOWKEN ((uint32_t)(0x1UL << MXC_F_GCR_PM_GPIOWKEN_POS)) /**< PM_GPIOWKEN Mask */ +#define MXC_V_GCR_PM_GPIOWKEN_DIS ((uint32_t)0x0UL) /**< PM_GPIOWKEN_DIS Value */ +#define MXC_S_GCR_PM_GPIOWKEN_DIS \ + (MXC_V_GCR_PM_GPIOWKEN_DIS << MXC_F_GCR_PM_GPIOWKEN_POS) /**< PM_GPIOWKEN_DIS Setting */ +#define MXC_V_GCR_PM_GPIOWKEN_EN ((uint32_t)0x1UL) /**< PM_GPIOWKEN_EN Value */ +#define MXC_S_GCR_PM_GPIOWKEN_EN (MXC_V_GCR_PM_GPIOWKEN_EN << MXC_F_GCR_PM_GPIOWKEN_POS) /**< PM_GPIOWKEN_EN Setting \ + */ + +#define MXC_F_GCR_PM_HIRCPD_POS 15 /**< PM_HIRCPD Position */ +#define MXC_F_GCR_PM_HIRCPD ((uint32_t)(0x1UL << MXC_F_GCR_PM_HIRCPD_POS)) /**< PM_HIRCPD Mask */ +#define MXC_V_GCR_PM_HIRCPD_ACTIVE ((uint32_t)0x0UL) /**< PM_HIRCPD_ACTIVE Value */ +#define MXC_S_GCR_PM_HIRCPD_ACTIVE \ + (MXC_V_GCR_PM_HIRCPD_ACTIVE << MXC_F_GCR_PM_HIRCPD_POS) /**< PM_HIRCPD_ACTIVE Setting */ +#define MXC_V_GCR_PM_HIRCPD_DEEPSLEEP ((uint32_t)0x1UL) /**< PM_HIRCPD_DEEPSLEEP Value */ +#define MXC_S_GCR_PM_HIRCPD_DEEPSLEEP \ + (MXC_V_GCR_PM_HIRCPD_DEEPSLEEP << MXC_F_GCR_PM_HIRCPD_POS) /**< PM_HIRCPD_DEEPSLEEP Setting */ + +#define MXC_F_GCR_PM_HIRC8MPD_POS 17 /**< PM_HIRC8MPD Position */ +#define MXC_F_GCR_PM_HIRC8MPD ((uint32_t)(0x1UL << MXC_F_GCR_PM_HIRC8MPD_POS)) /**< PM_HIRC8MPD Mask */ + +/**@} end of group GCR_PM_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_PCKDIV GCR_PCKDIV + * @brief Peripheral Clock Divider. + * @{ + */ +#define MXC_F_GCR_PCKDIV_PCF_POS 0 /**< PCKDIV_PCF Position */ +#define MXC_F_GCR_PCKDIV_PCF ((uint32_t)(0x7UL << MXC_F_GCR_PCKDIV_PCF_POS)) /**< PCKDIV_PCF Mask */ +#define MXC_V_GCR_PCKDIV_PCF_96MHZ ((uint32_t)0x2UL) /**< PCKDIV_PCF_96MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_96MHZ \ + (MXC_V_GCR_PCKDIV_PCF_96MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_96MHZ Setting */ +#define MXC_V_GCR_PCKDIV_PCF_48MHZ ((uint32_t)0x3UL) /**< PCKDIV_PCF_48MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_48MHZ \ + (MXC_V_GCR_PCKDIV_PCF_48MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_48MHZ Setting */ +#define MXC_V_GCR_PCKDIV_PCF_24MHZ ((uint32_t)0x4UL) /**< PCKDIV_PCF_24MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_24MHZ \ + (MXC_V_GCR_PCKDIV_PCF_24MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_24MHZ Setting */ +#define MXC_V_GCR_PCKDIV_PCF_12MHZ ((uint32_t)0x5UL) /**< PCKDIV_PCF_12MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_12MHZ \ + (MXC_V_GCR_PCKDIV_PCF_12MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_12MHZ Setting */ +#define MXC_V_GCR_PCKDIV_PCF_6MHZ ((uint32_t)0x6UL) /**< PCKDIV_PCF_6MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_6MHZ \ + (MXC_V_GCR_PCKDIV_PCF_6MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_6MHZ Setting */ +#define MXC_V_GCR_PCKDIV_PCF_3MHZ ((uint32_t)0x7UL) /**< PCKDIV_PCF_3MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_3MHZ \ + (MXC_V_GCR_PCKDIV_PCF_3MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_3MHZ Setting */ + +#define MXC_F_GCR_PCKDIV_PCFWEN_POS 3 /**< PCKDIV_PCFWEN Position */ +#define MXC_F_GCR_PCKDIV_PCFWEN ((uint32_t)(0x1UL << MXC_F_GCR_PCKDIV_PCFWEN_POS)) /**< PCKDIV_PCFWEN Mask */ +#define MXC_V_GCR_PCKDIV_PCFWEN_DISABLED ((uint32_t)0x0UL) /**< PCKDIV_PCFWEN_DISABLED Value */ +#define MXC_S_GCR_PCKDIV_PCFWEN_DISABLED \ + (MXC_V_GCR_PCKDIV_PCFWEN_DISABLED << MXC_F_GCR_PCKDIV_PCFWEN_POS) /**< PCKDIV_PCFWEN_DISABLED Setting */ +#define MXC_V_GCR_PCKDIV_PCFWEN_ENABLED ((uint32_t)0x1UL) /**< PCKDIV_PCFWEN_ENABLED Value */ +#define MXC_S_GCR_PCKDIV_PCFWEN_ENABLED \ + (MXC_V_GCR_PCKDIV_PCFWEN_ENABLED << MXC_F_GCR_PCKDIV_PCFWEN_POS) /**< PCKDIV_PCFWEN_ENABLED Setting */ + +#define MXC_F_GCR_PCKDIV_AONCD_POS 14 /**< PCKDIV_AONCD Position */ +#define MXC_F_GCR_PCKDIV_AONCD ((uint32_t)(0x3UL << MXC_F_GCR_PCKDIV_AONCD_POS)) /**< PCKDIV_AONCD Mask */ +#define MXC_V_GCR_PCKDIV_AONCD_DIV_4 ((uint32_t)0x0UL) /**< PCKDIV_AONCD_DIV_4 Value */ +#define MXC_S_GCR_PCKDIV_AONCD_DIV_4 \ + (MXC_V_GCR_PCKDIV_AONCD_DIV_4 << MXC_F_GCR_PCKDIV_AONCD_POS) /**< PCKDIV_AONCD_DIV_4 Setting */ +#define MXC_V_GCR_PCKDIV_AONCD_DIV_8 ((uint32_t)0x1UL) /**< PCKDIV_AONCD_DIV_8 Value */ +#define MXC_S_GCR_PCKDIV_AONCD_DIV_8 \ + (MXC_V_GCR_PCKDIV_AONCD_DIV_8 << MXC_F_GCR_PCKDIV_AONCD_POS) /**< PCKDIV_AONCD_DIV_8 Setting */ +#define MXC_V_GCR_PCKDIV_AONCD_DIV_16 ((uint32_t)0x2UL) /**< PCKDIV_AONCD_DIV_16 Value */ +#define MXC_S_GCR_PCKDIV_AONCD_DIV_16 \ + (MXC_V_GCR_PCKDIV_AONCD_DIV_16 << MXC_F_GCR_PCKDIV_AONCD_POS) /**< PCKDIV_AONCD_DIV_16 Setting */ +#define MXC_V_GCR_PCKDIV_AONCD_DIV_32 ((uint32_t)0x3UL) /**< PCKDIV_AONCD_DIV_32 Value */ +#define MXC_S_GCR_PCKDIV_AONCD_DIV_32 \ + (MXC_V_GCR_PCKDIV_AONCD_DIV_32 << MXC_F_GCR_PCKDIV_AONCD_POS) /**< PCKDIV_AONCD_DIV_32 Setting */ + +/**@} end of group GCR_PCKDIV_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_PERCKCN0 GCR_PERCKCN0 + * @brief Peripheral Clock Disable. + * @{ + */ +#define MXC_F_GCR_PERCKCN0_GPIO0D_POS 0 /**< PERCKCN0_GPIO0D Position */ +#define MXC_F_GCR_PERCKCN0_GPIO0D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_GPIO0D_POS)) /**< PERCKCN0_GPIO0D Mask */ +#define MXC_V_GCR_PERCKCN0_GPIO0D_EN ((uint32_t)0x0UL) /**< PERCKCN0_GPIO0D_EN Value */ +#define MXC_S_GCR_PERCKCN0_GPIO0D_EN \ + (MXC_V_GCR_PERCKCN0_GPIO0D_EN << MXC_F_GCR_PERCKCN0_GPIO0D_POS) /**< PERCKCN0_GPIO0D_EN Setting */ +#define MXC_V_GCR_PERCKCN0_GPIO0D_DIS ((uint32_t)0x1UL) /**< PERCKCN0_GPIO0D_DIS Value */ +#define MXC_S_GCR_PERCKCN0_GPIO0D_DIS \ + (MXC_V_GCR_PERCKCN0_GPIO0D_DIS << MXC_F_GCR_PERCKCN0_GPIO0D_POS) /**< PERCKCN0_GPIO0D_DIS Setting */ + +#define MXC_F_GCR_PERCKCN0_GPIO1D_POS 1 /**< PERCKCN0_GPIO1D Position */ +#define MXC_F_GCR_PERCKCN0_GPIO1D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_GPIO1D_POS)) /**< PERCKCN0_GPIO1D Mask */ + +#define MXC_F_GCR_PERCKCN0_DMAD_POS 5 /**< PERCKCN0_DMAD Position */ +#define MXC_F_GCR_PERCKCN0_DMAD ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_DMAD_POS)) /**< PERCKCN0_DMAD Mask */ + +#define MXC_F_GCR_PERCKCN0_SPI0D_POS 6 /**< PERCKCN0_SPI0D Position */ +#define MXC_F_GCR_PERCKCN0_SPI0D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_SPI0D_POS)) /**< PERCKCN0_SPI0D Mask */ + +#define MXC_F_GCR_PERCKCN0_SPI1D_POS 7 /**< PERCKCN0_SPI1D Position */ +#define MXC_F_GCR_PERCKCN0_SPI1D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_SPI1D_POS)) /**< PERCKCN0_SPI1D Mask */ + +#define MXC_F_GCR_PERCKCN0_UART0D_POS 9 /**< PERCKCN0_UART0D Position */ +#define MXC_F_GCR_PERCKCN0_UART0D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_UART0D_POS)) /**< PERCKCN0_UART0D Mask */ + +#define MXC_F_GCR_PERCKCN0_I2C0D_POS 13 /**< PERCKCN0_I2C0D Position */ +#define MXC_F_GCR_PERCKCN0_I2C0D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_I2C0D_POS)) /**< PERCKCN0_I2C0D Mask */ + +#define MXC_F_GCR_PERCKCN0_CRYPTOD_POS 14 /**< PERCKCN0_CRYPTOD Position */ +#define MXC_F_GCR_PERCKCN0_CRYPTOD ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_CRYPTOD_POS)) /**< PERCKCN0_CRYPTOD Mask */ + +#define MXC_F_GCR_PERCKCN0_T0D_POS 15 /**< PERCKCN0_T0D Position */ +#define MXC_F_GCR_PERCKCN0_T0D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_T0D_POS)) /**< PERCKCN0_T0D Mask */ + +#define MXC_F_GCR_PERCKCN0_T1D_POS 16 /**< PERCKCN0_T1D Position */ +#define MXC_F_GCR_PERCKCN0_T1D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_T1D_POS)) /**< PERCKCN0_T1D Mask */ + +#define MXC_F_GCR_PERCKCN0_T2D_POS 17 /**< PERCKCN0_T2D Position */ +#define MXC_F_GCR_PERCKCN0_T2D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_T2D_POS)) /**< PERCKCN0_T2D Mask */ + +#define MXC_F_GCR_PERCKCN0_T3D_POS 18 /**< PERCKCN0_T3D Position */ +#define MXC_F_GCR_PERCKCN0_T3D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_T3D_POS)) /**< PERCKCN0_T3D Mask */ + +/**@} end of group GCR_PERCKCN0_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_MEMCKCN GCR_MEMCKCN + * @brief Memory Clock Control Register. + * @{ + */ +#define MXC_F_GCR_MEMCKCN_FWS_POS 0 /**< MEMCKCN_FWS Position */ +#define MXC_F_GCR_MEMCKCN_FWS ((uint32_t)(0x7UL << MXC_F_GCR_MEMCKCN_FWS_POS)) /**< MEMCKCN_FWS Mask */ + +#define MXC_F_GCR_MEMCKCN_SYSRAM0LS_POS 16 /**< MEMCKCN_SYSRAM0LS Position */ +#define MXC_F_GCR_MEMCKCN_SYSRAM0LS \ + ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_SYSRAM0LS_POS)) /**< MEMCKCN_SYSRAM0LS Mask */ +#define MXC_V_GCR_MEMCKCN_SYSRAM0LS_ACTIVE ((uint32_t)0x0UL) /**< MEMCKCN_SYSRAM0LS_ACTIVE Value */ +#define MXC_S_GCR_MEMCKCN_SYSRAM0LS_ACTIVE \ + (MXC_V_GCR_MEMCKCN_SYSRAM0LS_ACTIVE << MXC_F_GCR_MEMCKCN_SYSRAM0LS_POS) /**< MEMCKCN_SYSRAM0LS_ACTIVE Setting */ +#define MXC_V_GCR_MEMCKCN_SYSRAM0LS_LIGHT_SLEEP ((uint32_t)0x1UL) /**< MEMCKCN_SYSRAM0LS_LIGHT_SLEEP Value */ +#define MXC_S_GCR_MEMCKCN_SYSRAM0LS_LIGHT_SLEEP \ + (MXC_V_GCR_MEMCKCN_SYSRAM0LS_LIGHT_SLEEP \ + << MXC_F_GCR_MEMCKCN_SYSRAM0LS_POS) /**< MEMCKCN_SYSRAM0LS_LIGHT_SLEEP Setting */ + +#define MXC_F_GCR_MEMCKCN_SYSRAM1LS_POS 17 /**< MEMCKCN_SYSRAM1LS Position */ +#define MXC_F_GCR_MEMCKCN_SYSRAM1LS \ + ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_SYSRAM1LS_POS)) /**< MEMCKCN_SYSRAM1LS Mask */ + +#define MXC_F_GCR_MEMCKCN_SYSRAM2LS_POS 18 /**< MEMCKCN_SYSRAM2LS Position */ +#define MXC_F_GCR_MEMCKCN_SYSRAM2LS \ + ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_SYSRAM2LS_POS)) /**< MEMCKCN_SYSRAM2LS Mask */ + +#define MXC_F_GCR_MEMCKCN_SYSRAM3LS_POS 19 /**< MEMCKCN_SYSRAM3LS Position */ +#define MXC_F_GCR_MEMCKCN_SYSRAM3LS \ + ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_SYSRAM3LS_POS)) /**< MEMCKCN_SYSRAM3LS Mask */ + +#define MXC_F_GCR_MEMCKCN_SYSRAM4LS_POS 20 /**< MEMCKCN_SYSRAM4LS Position */ +#define MXC_F_GCR_MEMCKCN_SYSRAM4LS \ + ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_SYSRAM4LS_POS)) /**< MEMCKCN_SYSRAM4LS Mask */ + +#define MXC_F_GCR_MEMCKCN_ICACHELS_POS 24 /**< MEMCKCN_ICACHELS Position */ +#define MXC_F_GCR_MEMCKCN_ICACHELS ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_ICACHELS_POS)) /**< MEMCKCN_ICACHELS Mask */ + +#define MXC_F_GCR_MEMCKCN_ROMLS_POS 29 /**< MEMCKCN_ROMLS Position */ +#define MXC_F_GCR_MEMCKCN_ROMLS ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_ROMLS_POS)) /**< MEMCKCN_ROMLS Mask */ + +/**@} end of group GCR_MEMCKCN_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_MEMZCN GCR_MEMZCN + * @brief Memory Zeroize Control. + * @{ + */ +#define MXC_F_GCR_MEMZCN_SRAM0Z_POS 0 /**< MEMZCN_SRAM0Z Position */ +#define MXC_F_GCR_MEMZCN_SRAM0Z ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_SRAM0Z_POS)) /**< MEMZCN_SRAM0Z Mask */ +#define MXC_V_GCR_MEMZCN_SRAM0Z_NOP ((uint32_t)0x0UL) /**< MEMZCN_SRAM0Z_NOP Value */ +#define MXC_S_GCR_MEMZCN_SRAM0Z_NOP \ + (MXC_V_GCR_MEMZCN_SRAM0Z_NOP << MXC_F_GCR_MEMZCN_SRAM0Z_POS) /**< MEMZCN_SRAM0Z_NOP Setting */ +#define MXC_V_GCR_MEMZCN_SRAM0Z_START ((uint32_t)0x1UL) /**< MEMZCN_SRAM0Z_START Value */ +#define MXC_S_GCR_MEMZCN_SRAM0Z_START \ + (MXC_V_GCR_MEMZCN_SRAM0Z_START << MXC_F_GCR_MEMZCN_SRAM0Z_POS) /**< MEMZCN_SRAM0Z_START Setting */ + +#define MXC_F_GCR_MEMZCN_SRAM1Z_POS 1 /**< MEMZCN_SRAM1Z Position */ +#define MXC_F_GCR_MEMZCN_SRAM1Z ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_SRAM1Z_POS)) /**< MEMZCN_SRAM1Z Mask */ + +#define MXC_F_GCR_MEMZCN_SRAM2Z_POS 2 /**< MEMZCN_SRAM2Z Position */ +#define MXC_F_GCR_MEMZCN_SRAM2Z ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_SRAM2Z_POS)) /**< MEMZCN_SRAM2Z Mask */ + +#define MXC_F_GCR_MEMZCN_SRAM3Z_POS 3 /**< MEMZCN_SRAM3Z Position */ +#define MXC_F_GCR_MEMZCN_SRAM3Z ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_SRAM3Z_POS)) /**< MEMZCN_SRAM3Z Mask */ + +#define MXC_F_GCR_MEMZCN_SRAM4Z_POS 4 /**< MEMZCN_SRAM4Z Position */ +#define MXC_F_GCR_MEMZCN_SRAM4Z ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_SRAM4Z_POS)) /**< MEMZCN_SRAM4Z Mask */ + +#define MXC_F_GCR_MEMZCN_ICACHEZ_POS 8 /**< MEMZCN_ICACHEZ Position */ +#define MXC_F_GCR_MEMZCN_ICACHEZ ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_ICACHEZ_POS)) /**< MEMZCN_ICACHEZ Mask */ + +/**@} end of group GCR_MEMZCN_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_SYSST GCR_SYSST + * @brief System Status Register. + * @{ + */ +#define MXC_F_GCR_SYSST_ICECLOCK_POS 0 /**< SYSST_ICECLOCK Position */ +#define MXC_F_GCR_SYSST_ICECLOCK ((uint32_t)(0x1UL << MXC_F_GCR_SYSST_ICECLOCK_POS)) /**< SYSST_ICECLOCK Mask */ +#define MXC_V_GCR_SYSST_ICECLOCK_UNLOCKED ((uint32_t)0x0UL) /**< SYSST_ICECLOCK_UNLOCKED Value */ +#define MXC_S_GCR_SYSST_ICECLOCK_UNLOCKED \ + (MXC_V_GCR_SYSST_ICECLOCK_UNLOCKED << MXC_F_GCR_SYSST_ICECLOCK_POS) /**< SYSST_ICECLOCK_UNLOCKED Setting */ +#define MXC_V_GCR_SYSST_ICECLOCK_LOCKED ((uint32_t)0x1UL) /**< SYSST_ICECLOCK_LOCKED Value */ +#define MXC_S_GCR_SYSST_ICECLOCK_LOCKED \ + (MXC_V_GCR_SYSST_ICECLOCK_LOCKED << MXC_F_GCR_SYSST_ICECLOCK_POS) /**< SYSST_ICECLOCK_LOCKED Setting */ + +/**@} end of group GCR_SYSST_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_RSTR1 GCR_RSTR1 + * @brief Reset 1. + * @{ + */ +#define MXC_F_GCR_RSTR1_WDT1_POS 8 /**< RSTR1_WDT1 Position */ +#define MXC_F_GCR_RSTR1_WDT1 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR1_WDT1_POS)) /**< RSTR1_WDT1 Mask */ +#define MXC_V_GCR_RSTR1_WDT1_RESET_DONE ((uint32_t)0x0UL) /**< RSTR1_WDT1_RESET_DONE Value */ +#define MXC_S_GCR_RSTR1_WDT1_RESET_DONE \ + (MXC_V_GCR_RSTR1_WDT1_RESET_DONE << MXC_F_GCR_RSTR1_WDT1_POS) /**< RSTR1_WDT1_RESET_DONE Setting */ +#define MXC_V_GCR_RSTR1_WDT1_BUSY ((uint32_t)0x1UL) /**< RSTR1_WDT1_BUSY Value */ +#define MXC_S_GCR_RSTR1_WDT1_BUSY \ + (MXC_V_GCR_RSTR1_WDT1_BUSY << MXC_F_GCR_RSTR1_WDT1_POS) /**< RSTR1_WDT1_BUSY Setting */ + +#define MXC_F_GCR_RSTR1_PUFC_POS 27 /**< RSTR1_PUFC Position */ +#define MXC_F_GCR_RSTR1_PUFC ((uint32_t)(0x1UL << MXC_F_GCR_RSTR1_PUFC_POS)) /**< RSTR1_PUFC Mask */ + +#define MXC_F_GCR_RSTR1_CSPIS_POS 28 /**< RSTR1_CSPIS Position */ +#define MXC_F_GCR_RSTR1_CSPIS ((uint32_t)(0x1UL << MXC_F_GCR_RSTR1_CSPIS_POS)) /**< RSTR1_CSPIS Mask */ + +/**@} end of group GCR_RSTR1_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_PERCKCN1 GCR_PERCKCN1 + * @brief Peripheral Clock Disable. + * @{ + */ +#define MXC_F_GCR_PERCKCN1_TRNGD_POS 2 /**< PERCKCN1_TRNGD Position */ +#define MXC_F_GCR_PERCKCN1_TRNGD ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN1_TRNGD_POS)) /**< PERCKCN1_TRNGD Mask */ +#define MXC_V_GCR_PERCKCN1_TRNGD_EN ((uint32_t)0x0UL) /**< PERCKCN1_TRNGD_EN Value */ +#define MXC_S_GCR_PERCKCN1_TRNGD_EN \ + (MXC_V_GCR_PERCKCN1_TRNGD_EN << MXC_F_GCR_PERCKCN1_TRNGD_POS) /**< PERCKCN1_TRNGD_EN Setting */ +#define MXC_V_GCR_PERCKCN1_TRNGD_DIS ((uint32_t)0x1UL) /**< PERCKCN1_TRNGD_DIS Value */ +#define MXC_S_GCR_PERCKCN1_TRNGD_DIS \ + (MXC_V_GCR_PERCKCN1_TRNGD_DIS << MXC_F_GCR_PERCKCN1_TRNGD_POS) /**< PERCKCN1_TRNGD_DIS Setting */ + +#define MXC_F_GCR_PERCKCN1_PUFCD_POS 3 /**< PERCKCN1_PUFCD Position */ +#define MXC_F_GCR_PERCKCN1_PUFCD ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN1_PUFCD_POS)) /**< PERCKCN1_PUFCD Mask */ + +#define MXC_F_GCR_PERCKCN1_ICACHED_POS 11 /**< PERCKCN1_ICACHED Position */ +#define MXC_F_GCR_PERCKCN1_ICACHED ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN1_ICACHED_POS)) /**< PERCKCN1_ICACHED Mask */ + +#define MXC_F_GCR_PERCKCN1_CSPISD_POS 30 /**< PERCKCN1_CSPISD Position */ +#define MXC_F_GCR_PERCKCN1_CSPISD ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN1_CSPISD_POS)) /**< PERCKCN1_CSPISD Mask */ + +/**@} end of group GCR_PERCKCN1_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_EVTEN GCR_EVTEN + * @brief Event Enable Register. + * @{ + */ +#define MXC_F_GCR_EVTEN_CPU0DMAEVENT_POS 0 /**< EVTEN_CPU0DMAEVENT Position */ +#define MXC_F_GCR_EVTEN_CPU0DMAEVENT \ + ((uint32_t)(0x1UL << MXC_F_GCR_EVTEN_CPU0DMAEVENT_POS)) /**< EVTEN_CPU0DMAEVENT Mask */ + +#define MXC_F_GCR_EVTEN_CPU0RXEVENT_POS 1 /**< EVTEN_CPU0RXEVENT Position */ +#define MXC_F_GCR_EVTEN_CPU0RXEVENT \ + ((uint32_t)(0x1UL << MXC_F_GCR_EVTEN_CPU0RXEVENT_POS)) /**< EVTEN_CPU0RXEVENT Mask */ + +#define MXC_F_GCR_EVTEN_CPU0TXEVENT_POS 2 /**< EVTEN_CPU0TXEVENT Position */ +#define MXC_F_GCR_EVTEN_CPU0TXEVENT \ + ((uint32_t)(0x1UL << MXC_F_GCR_EVTEN_CPU0TXEVENT_POS)) /**< EVTEN_CPU0TXEVENT Mask */ + +/**@} end of group GCR_EVTEN_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_REVISION GCR_REVISION + * @brief Revision Register. + * @{ + */ +#define MXC_F_GCR_REVISION_REVISION_POS 0 /**< REVISION_REVISION Position */ +#define MXC_F_GCR_REVISION_REVISION \ + ((uint32_t)(0xFFFFUL << MXC_F_GCR_REVISION_REVISION_POS)) /**< REVISION_REVISION Mask */ + +/**@} end of group GCR_REVISION_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_SYSSIE GCR_SYSSIE + * @brief System Status Interrupt Enable Register. + * @{ + */ +#define MXC_F_GCR_SYSSIE_ICEULIE_POS 0 /**< SYSSIE_ICEULIE Position */ +#define MXC_F_GCR_SYSSIE_ICEULIE ((uint32_t)(0x1UL << MXC_F_GCR_SYSSIE_ICEULIE_POS)) /**< SYSSIE_ICEULIE Mask */ +#define MXC_V_GCR_SYSSIE_ICEULIE_DIS ((uint32_t)0x0UL) /**< SYSSIE_ICEULIE_DIS Value */ +#define MXC_S_GCR_SYSSIE_ICEULIE_DIS \ + (MXC_V_GCR_SYSSIE_ICEULIE_DIS << MXC_F_GCR_SYSSIE_ICEULIE_POS) /**< SYSSIE_ICEULIE_DIS Setting */ +#define MXC_V_GCR_SYSSIE_ICEULIE_EN ((uint32_t)0x1UL) /**< SYSSIE_ICEULIE_EN Value */ +#define MXC_S_GCR_SYSSIE_ICEULIE_EN \ + (MXC_V_GCR_SYSSIE_ICEULIE_EN << MXC_F_GCR_SYSSIE_ICEULIE_POS) /**< SYSSIE_ICEULIE_EN Setting */ + +/**@} end of group GCR_SYSSIE_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_ECCERR GCR_ECCERR + * @brief ECC Error Register + * @{ + */ +#define MXC_F_GCR_ECCERR_SYSRAM0ECCERR_POS 0 /**< ECCERR_SYSRAM0ECCERR Position */ +#define MXC_F_GCR_ECCERR_SYSRAM0ECCERR \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCERR_SYSRAM0ECCERR_POS)) /**< ECCERR_SYSRAM0ECCERR Mask */ + +#define MXC_F_GCR_ECCERR_SYSRAM1ECCERR_POS 1 /**< ECCERR_SYSRAM1ECCERR Position */ +#define MXC_F_GCR_ECCERR_SYSRAM1ECCERR \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCERR_SYSRAM1ECCERR_POS)) /**< ECCERR_SYSRAM1ECCERR Mask */ + +#define MXC_F_GCR_ECCERR_SYSRAM2ECCERR_POS 2 /**< ECCERR_SYSRAM2ECCERR Position */ +#define MXC_F_GCR_ECCERR_SYSRAM2ECCERR \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCERR_SYSRAM2ECCERR_POS)) /**< ECCERR_SYSRAM2ECCERR Mask */ + +#define MXC_F_GCR_ECCERR_SYSRAM3ECCERR_POS 3 /**< ECCERR_SYSRAM3ECCERR Position */ +#define MXC_F_GCR_ECCERR_SYSRAM3ECCERR \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCERR_SYSRAM3ECCERR_POS)) /**< ECCERR_SYSRAM3ECCERR Mask */ + +#define MXC_F_GCR_ECCERR_SYSRAM4ECCERR_POS 4 /**< ECCERR_SYSRAM4ECCERR Position */ +#define MXC_F_GCR_ECCERR_SYSRAM4ECCERR \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCERR_SYSRAM4ECCERR_POS)) /**< ECCERR_SYSRAM4ECCERR Mask */ + +/**@} end of group GCR_ECCERR_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_ECCNDED GCR_ECCNDED + * @brief ECC Not Double Error Detect Register + * @{ + */ +#define MXC_F_GCR_ECCNDED_SYSRAM0ECCNDED_POS 0 /**< ECCNDED_SYSRAM0ECCNDED Position */ +#define MXC_F_GCR_ECCNDED_SYSRAM0ECCNDED \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCNDED_SYSRAM0ECCNDED_POS)) /**< ECCNDED_SYSRAM0ECCNDED Mask */ + +#define MXC_F_GCR_ECCNDED_SYSRAM1ECCNDED_POS 1 /**< ECCNDED_SYSRAM1ECCNDED Position */ +#define MXC_F_GCR_ECCNDED_SYSRAM1ECCNDED \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCNDED_SYSRAM1ECCNDED_POS)) /**< ECCNDED_SYSRAM1ECCNDED Mask */ + +#define MXC_F_GCR_ECCNDED_SYSRAM2ECCNDED_POS 2 /**< ECCNDED_SYSRAM2ECCNDED Position */ +#define MXC_F_GCR_ECCNDED_SYSRAM2ECCNDED \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCNDED_SYSRAM2ECCNDED_POS)) /**< ECCNDED_SYSRAM2ECCNDED Mask */ + +#define MXC_F_GCR_ECCNDED_SYSRAM3ECCNDED_POS 3 /**< ECCNDED_SYSRAM3ECCNDED Position */ +#define MXC_F_GCR_ECCNDED_SYSRAM3ECCNDED \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCNDED_SYSRAM3ECCNDED_POS)) /**< ECCNDED_SYSRAM3ECCNDED Mask */ + +#define MXC_F_GCR_ECCNDED_SYSRAM4ECCNDED_POS 4 /**< ECCNDED_SYSRAM4ECCNDED Position */ +#define MXC_F_GCR_ECCNDED_SYSRAM4ECCNDED \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCNDED_SYSRAM4ECCNDED_POS)) /**< ECCNDED_SYSRAM4ECCNDED Mask */ + +/**@} end of group GCR_ECCNDED_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_ECCIRQEN GCR_ECCIRQEN + * @brief ECC IRQ Enable Register + * @{ + */ +#define MXC_F_GCR_ECCIRQEN_ECCERAD_POS 0 /**< ECCIRQEN_ECCERAD Position */ +#define MXC_F_GCR_ECCIRQEN_ECCERAD \ + ((uint32_t)(0x7FFFFFFFUL << MXC_F_GCR_ECCIRQEN_ECCERAD_POS)) /**< ECCIRQEN_ECCERAD Mask */ + +/**@} end of group GCR_ECCIRQEN_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_ECCERRAD GCR_ECCERRAD + * @brief ECC Error Address Register + * @{ + */ +#define MXC_F_GCR_ECCERRAD_ECCERAD_POS 0 /**< ECCERRAD_ECCERAD Position */ +#define MXC_F_GCR_ECCERRAD_ECCERAD \ + ((uint32_t)(0x7FFFFFFFUL << MXC_F_GCR_ECCERRAD_ECCERAD_POS)) /**< ECCERRAD_ECCERAD Mask */ + +/**@} end of group GCR_ECCERRAD_Register */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GCR_REGS_H_ */ diff --git a/contrib/loaders/flash/max32xxx/max32xxx.inc b/contrib/loaders/flash/max32xxx/max32xxx.inc deleted file mode 100644 index 442165d0d1..0000000000 --- a/contrib/loaders/flash/max32xxx/max32xxx.inc +++ /dev/null @@ -1,6 +0,0 @@ -/* Autogenerated with ../../../../src/helper/bin2char.sh */ -0xdf,0xf8,0x44,0x40,0xd0,0xf8,0x00,0x80,0xb8,0xf1,0x00,0x0f,0x1a,0xd0,0x47,0x68, -0x47,0x45,0xf7,0xd0,0x22,0x60,0x02,0xf1,0x04,0x02,0x57,0xf8,0x04,0x8b,0xc4,0xf8, -0x30,0x80,0xa5,0x68,0x45,0xf0,0x01,0x05,0xa5,0x60,0xd4,0xf8,0x08,0x80,0x18,0xf0, -0x01,0x0f,0xfa,0xd1,0x8f,0x42,0x28,0xbf,0x00,0xf1,0x08,0x07,0x47,0x60,0x01,0x3b, -0x03,0xb1,0xdf,0xe7,0x00,0xbe,0x00,0xbf,0x00,0x00,0x00,0x40, diff --git a/contrib/loaders/flash/max32xxx/max32xxx.s b/contrib/loaders/flash/max32xxx/max32xxx.s deleted file mode 100644 index 38a4f12c32..0000000000 --- a/contrib/loaders/flash/max32xxx/max32xxx.s +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/*************************************************************************** - * Copyright (C) 2016 by Maxim Integrated * - * Kevin Gillespie +#else +#define printf(...) +#endif + +/***** Definitions *****/ +#define MXC_BASE_TPU ((uint32_t)0x40001000UL) +#define MXC_TPU ((struct mxc_tpu_regs *)MXC_BASE_TPU) +#define MXC_BASE_GCR ((uint32_t)0x40000000UL) +#define MXC_GCR ((struct mxc_gcr_regs *)MXC_BASE_GCR) + +/******************************************************************************/ +#define getbyte(temp8) \ +/* Wait for the Read FIFO to not equal the Write FIFO */ \ + do { while (*read_ptr == *write_ptr); \ + temp8 = **read_ptr; \ +/* Increment and wrap around the read pointer */ \ + if ((*read_ptr + 1) >= (uint8_t *)(work_end - 8 - 256)) { \ + *read_ptr = (uint8_t *)(work_start + 8); \ + } else { \ + (*read_ptr)++; \ + } \ + len--; \ + addr++; } while (0) + +/******************************************************************************/ +#ifndef ALGO_TEST +__attribute__ ((naked, section(".algo"))) +#endif +void algo_write(uint8_t *work_start, uint8_t *work_end, uint32_t len, uint32_t addr) +{ + printf(" > %s starting\n", __func__); + + volatile uint8_t * (*write_ptr) = (volatile uint8_t **)work_start; + volatile uint8_t * (*read_ptr) = (volatile uint8_t **)(work_start + 4); + uint32_t *flc_base = (uint32_t *)(work_end - 4 - 128); + uint32_t *options = (uint32_t *)(work_end - 8 - 128); + uint32_t *enc_buffer = (uint32_t *)(work_end - 8 - 256); + uint8_t temp8; + uint32_t addr_save; + int i; + struct mxc_flc_regs *MXC_FLC = (struct mxc_flc_regs *)*flc_base; + + printf(" > w%08x r%08x o%08x f%08x b%08x b%08x\n", + (uint32_t)write_ptr, (uint32_t)read_ptr, (uint32_t)*options, (uint32_t)*flc_base, + (uint32_t)enc_buffer, (uint32_t)(enc_buffer + 256)); + + if (*options & OPTIONS_ENC) { + /* Enable Memory Protection */ + MXC_GCR->scon |= MXC_F_GCR_SCON_MEMPROT_EN; + + /* Set the keysize */ + if (*options & OPTIONS_KEYSIZE) + MXC_GCR->scon |= MXC_F_GCR_SCON_MEMPROT_KEYSZ; + else + MXC_GCR->scon &= ~(MXC_F_GCR_SCON_MEMPROT_KEYSZ); + } else { + /* Disable memory protection */ + MXC_GCR->scon &= ~MXC_F_GCR_SCON_MEMPROT_EN; + } + + if (*options & OPTIONS_ENC) { + /* Setup the AES */ + + /* Enable CRYPTO clock */ + if ((MXC_GCR->clkcn & MXC_F_GCR_CLKCN_HIRC_EN) == 0) + MXC_GCR->clkcn |= MXC_F_GCR_CLKCN_HIRC_EN; + + /* Disable CRYPTO clock gate */ + if (MXC_GCR->perckcn0 & MXC_F_GCR_PERCKCN0_CRYPTOD) + MXC_GCR->perckcn0 &= ~(MXC_F_GCR_PERCKCN0_CRYPTOD); + + /* Reset Crypto block and clear state */ + MXC_TPU->ctrl = MXC_F_TPU_CTRL_RST; + + /* Set the legacy bit */ + MXC_TPU->ctrl |= MXC_F_TPU_CTRL_FLAG_MODE; + + /* Byte swap the input and output */ + MXC_TPU->ctrl |= MXC_F_TPU_CTRL_BSO; + MXC_TPU->ctrl |= MXC_F_TPU_CTRL_BSI; + } + + while (len) { + if ((*options & OPTIONS_128) == 0) { + /* Save the current address before we read from the working area */ + addr_save = addr; + + /* 32-bit write */ + MXC_FLC->cn |= MXC_F_FLC_CN_WDTH; + + enc_buffer[0] = 0; + for (i = 0; i < 4; i++) { + /* Get data from the working area, pad with 0xFF */ + if (len) { + getbyte(temp8); + __asm("nop\n"); + } else { + temp8 = 0xFF; + __asm("nop\n"); + } + enc_buffer[0] |= (temp8 << (i * 8)); + } + + /* 32-bit write */ + MXC_FLC->cn |= MXC_F_FLC_CN_WDTH; + + MXC_FLC->addr = addr_save; + MXC_FLC->data[0] = enc_buffer[0]; + + /* Enable the write */ + MXC_FLC->cn |= MXC_F_FLC_CN_WR; + + /* Wait for the operation to complete */ + do {} while (MXC_FLC->cn & MXC_F_FLC_CN_WR); + + /* Check access violations */ + if (MXC_FLC->intr & MXC_F_FLC_INTR_AF) { + MXC_FLC->intr &= ~MXC_F_FLC_INTR_AF; + #ifndef ALGO_TEST + #ifdef __riscv + __asm("ebreak\n"); + #else + __asm("bkpt\n"); + #endif + #else + printf(" > Error writing to flash\n"); + return; + #endif + } + } else { + /* Save the current address before we read from the working area */ + addr_save = addr; + + /* Fill the buffer with the plain text data from the working area */ + for (i = 0; i < 4; i++) { + /* Get data from the working area, pad with 0xFF */ + enc_buffer[i] = 0; + if (len) { + getbyte(temp8); + __asm("nop\n"); + } else { + temp8 = 0xFF; + __asm("nop\n"); + } + enc_buffer[i] |= (temp8 << (0)); + /* Get data from the working area, pad with 0xFF */ + if (len) { + getbyte(temp8); + __asm("nop\n"); + } else { + temp8 = 0xFF; + __asm("nop\n"); + } + enc_buffer[i] |= (temp8 << (8)); + /* Get data from the working area, pad with 0xFF */ + if (len) { + getbyte(temp8); + __asm("nop\n"); + } else { + temp8 = 0xFF; + __asm("nop\n"); + } + enc_buffer[i] |= (temp8 << (16)); + /* Get data from the working area, pad with 0xFF */ + if (len) { + getbyte(temp8); + __asm("nop\n"); + } else { + temp8 = 0xFF; + __asm("nop\n"); + } + enc_buffer[i] |= (temp8 << (24)); + } + + if (*options & OPTIONS_ENC) { + /* XOR data with the address */ + for (i = 0; i < 4; i++) { + if (*options & OPTIONS_RELATIVE_XOR) + enc_buffer[i] ^= ((addr_save & 0x00FFFFFF) + i * 4); + else + enc_buffer[i] ^= (addr_save + i * 4); + } + + /* Encrypt the plain text + * Clear interrupt flags*/ + MXC_TPU->ctrl |= MXC_F_TPU_CTRL_CPH_DONE; + + MXC_TPU->cipher_ctrl = ((0x0 << MXC_F_TPU_CIPHER_CTRL_MODE_POS) | + (0x0 << MXC_F_TPU_CIPHER_CTRL_ENC_POS)); + + if (*options & OPTIONS_KEYSIZE) { + /* ECB, AES-256, encrypt */ + MXC_TPU->cipher_ctrl |= + (0x3 << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS); + } else { + /* ECB, AES-128, encrypt */ + MXC_TPU->cipher_ctrl |= + (0x1 << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS); + } + + /* Set the key source */ + MXC_TPU->cipher_ctrl = + ((MXC_TPU->cipher_ctrl & ~MXC_F_TPU_CIPHER_CTRL_SRC) | + (0x3 << MXC_F_TPU_CIPHER_CTRL_SRC_POS)); + + /* Copy data to start the operation */ + MXC_TPU->din[0] = enc_buffer[0]; + MXC_TPU->din[1] = enc_buffer[1]; + MXC_TPU->din[2] = enc_buffer[2]; + MXC_TPU->din[3] = enc_buffer[3]; + + /* Wait until operation is complete */ + do {} while (!(MXC_TPU->ctrl & MXC_F_TPU_CTRL_CPH_DONE)); + + /* Copy the data out */ + enc_buffer[0] = MXC_TPU->dout[0]; + enc_buffer[1] = MXC_TPU->dout[1]; + enc_buffer[2] = MXC_TPU->dout[2]; + enc_buffer[3] = MXC_TPU->dout[3]; + } + + /* 128-bit write */ + MXC_FLC->cn &= ~MXC_F_FLC_CN_WDTH; + + MXC_FLC->addr = addr_save; + MXC_FLC->data[0] = enc_buffer[0]; + MXC_FLC->data[1] = enc_buffer[1]; + MXC_FLC->data[2] = enc_buffer[2]; + MXC_FLC->data[3] = enc_buffer[3]; + + /* Enable the write */ + MXC_FLC->cn |= MXC_F_FLC_CN_WR; + + /* Wait for the operation to complete */ + do {} while (MXC_FLC->cn & MXC_F_FLC_CN_WR); + + /* Check access violations */ + if (MXC_FLC->intr & MXC_F_FLC_INTR_AF) { + MXC_FLC->intr &= ~MXC_F_FLC_INTR_AF; + #ifndef ALGO_TEST + #ifdef __riscv + __asm("ebreak\n"); + #else + __asm("bkpt\n"); + #endif + printf(" > Error writing to flash\n"); + return; + #endif + } + } + } + + #ifndef ALGO_TEST + #ifdef __riscv + __asm("ebreak\n"); + #else + __asm("bkpt\n"); + #endif + #else + printf(" > %s returning\n", __func__); + return; + #endif +} diff --git a/contrib/loaders/flash/max32xxx/max32xxx_write_arm.inc b/contrib/loaders/flash/max32xxx/max32xxx_write_arm.inc new file mode 100644 index 0000000000..cdc373071a --- /dev/null +++ b/contrib/loaders/flash/max32xxx/max32xxx_write_arm.inc @@ -0,0 +1,57 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x51,0xe9,0x22,0x54,0x15,0xf0,0x02,0x0f,0x4f,0xf0,0x80,0x45,0x00,0x93,0xa1,0xf5, +0x84,0x76,0x2f,0x68,0x00,0xf0,0x90,0x80,0x47,0xf4,0x80,0x17,0x2f,0x60,0x51,0xf8, +0x88,0x7c,0x17,0xf0,0x40,0x0f,0x2f,0x68,0x14,0xbf,0x47,0xf4,0x00,0x17,0x27,0xf4, +0x00,0x17,0x2f,0x60,0x51,0xf8,0x88,0x5c,0xad,0x07,0x1e,0xd5,0x4f,0xf0,0x80,0x45, +0xaf,0x68,0x7b,0x03,0x5e,0xbf,0xaf,0x68,0x47,0xf4,0x80,0x27,0xaf,0x60,0x6f,0x6a, +0x7f,0x04,0x42,0xbf,0x6f,0x6a,0x27,0xf4,0x80,0x47,0x6f,0x62,0xc0,0x4d,0x01,0x27, +0x2f,0x60,0x2f,0x68,0x47,0xf4,0x80,0x47,0x2f,0x60,0x2f,0x68,0x47,0xf0,0x10,0x07, +0x2f,0x60,0x2f,0x68,0x47,0xf0,0x20,0x07,0x2f,0x60,0xa1,0xf1,0xfc,0x05,0x03,0x95, +0x00,0xf1,0x08,0x05,0x01,0x95,0xa1,0xf5,0x82,0x75,0x02,0x95,0xb4,0x4d,0xa1,0xf5, +0x80,0x7c,0x00,0x2a,0x00,0xf0,0x63,0x81,0x51,0xf8,0x88,0x7c,0x17,0xf0,0x01,0x0e, +0x50,0xd1,0xa7,0x68,0x47,0xf0,0x10,0x07,0xa7,0x60,0x00,0x9f,0xc6,0xf8,0x00,0xe0, +0x00,0x2a,0x44,0xd0,0xd0,0xf8,0x04,0x90,0xd0,0xf8,0x00,0x80,0xc1,0x45,0xf9,0xd0, +0xd0,0xf8,0x04,0x80,0xd0,0xf8,0x04,0x90,0x98,0xf8,0x00,0x80,0x09,0xf1,0x01,0x09, +0x4e,0x45,0x8d,0xbf,0xd0,0xf8,0x04,0x90,0x01,0x9b,0x43,0x60,0x09,0xf1,0x01,0x09, +0x88,0xbf,0xc0,0xf8,0x04,0x90,0x01,0x3a,0x01,0x37,0x33,0x68,0x08,0xfa,0x0e,0xf8, +0x0e,0xf1,0x08,0x0e,0x43,0xea,0x08,0x08,0xbe,0xf1,0x20,0x0f,0xc6,0xf8,0x00,0x80, +0xd6,0xd1,0xd4,0xf8,0x08,0xe0,0x00,0x9b,0x4e,0xf0,0x10,0x0e,0xc4,0xf8,0x08,0xe0, +0x23,0x60,0x33,0x68,0x23,0x63,0xa3,0x68,0x43,0xf0,0x01,0x03,0xa3,0x60,0xa3,0x68, +0xdb,0x07,0xfc,0xd4,0x63,0x6a,0x9b,0x07,0x04,0xd5,0x63,0x6a,0x23,0xf0,0x02,0x03, +0x63,0x62,0x00,0xbe,0x00,0x97,0xac,0xe7,0x27,0xf4,0x80,0x17,0x79,0xe7,0x4f,0xf0, +0xff,0x08,0xd2,0xe7,0xa1,0xf5,0x86,0x78,0x00,0x9f,0xc1,0x46,0x00,0x23,0x49,0xf8, +0x04,0x3f,0x00,0x2a,0x00,0xf0,0x06,0x81,0xd0,0xf8,0x04,0xa0,0xd0,0xf8,0x00,0xe0, +0xf2,0x45,0xf9,0xd0,0xd0,0xf8,0x04,0xe0,0xd0,0xf8,0x04,0xa0,0x9e,0xf8,0x00,0xe0, +0x0a,0xf1,0x01,0x0a,0x56,0x45,0x8d,0xbf,0xd0,0xf8,0x04,0xa0,0x01,0x9b,0x43,0x60, +0x0a,0xf1,0x01,0x0a,0x88,0xbf,0xc0,0xf8,0x04,0xa0,0x01,0x3a,0x01,0x37,0xc9,0xf8, +0x00,0xe0,0x00,0x2a,0x00,0xf0,0xe9,0x80,0xd0,0xf8,0x04,0xb0,0xd0,0xf8,0x00,0xa0, +0xd3,0x45,0xf9,0xd0,0xd0,0xf8,0x04,0xa0,0x9a,0xf8,0x00,0xb0,0xd0,0xf8,0x04,0xa0, +0x0a,0xf1,0x01,0x0a,0x56,0x45,0x8d,0xbf,0xd0,0xf8,0x04,0xa0,0x01,0x9b,0x43,0x60, +0x0a,0xf1,0x01,0x0a,0x88,0xbf,0xc0,0xf8,0x04,0xa0,0x01,0x3a,0x01,0x37,0x4e,0xea, +0x0b,0x2e,0xc9,0xf8,0x00,0xe0,0x00,0x2a,0x00,0xf0,0xca,0x80,0xd0,0xf8,0x04,0xb0, +0xd0,0xf8,0x00,0xa0,0xd3,0x45,0xf9,0xd0,0xd0,0xf8,0x04,0xa0,0x9a,0xf8,0x00,0xb0, +0xd0,0xf8,0x04,0xa0,0x0a,0xf1,0x01,0x0a,0x56,0x45,0x8d,0xbf,0xd0,0xf8,0x04,0xa0, +0x01,0x9b,0x43,0x60,0x0a,0xf1,0x01,0x0a,0x88,0xbf,0xc0,0xf8,0x04,0xa0,0x01,0x3a, +0x01,0x37,0x4e,0xea,0x0b,0x4e,0xc9,0xf8,0x00,0xe0,0x00,0x2a,0x00,0xf0,0xab,0x80, +0xd0,0xf8,0x04,0xb0,0xd0,0xf8,0x00,0xa0,0xd3,0x45,0xf9,0xd0,0xd0,0xf8,0x04,0xa0, +0x9a,0xf8,0x00,0xb0,0xd0,0xf8,0x04,0xa0,0x0a,0xf1,0x01,0x0a,0x56,0x45,0x8d,0xbf, +0xd0,0xf8,0x04,0xa0,0x01,0x9b,0x43,0x60,0x0a,0xf1,0x01,0x0a,0x88,0xbf,0xc0,0xf8, +0x04,0xa0,0x01,0x3a,0x01,0x37,0x03,0x9b,0x4e,0xea,0x0b,0x6e,0x99,0x45,0xc9,0xf8, +0x00,0xe0,0x7f,0xf4,0x73,0xaf,0x51,0xf8,0x88,0x3c,0x9b,0x07,0x55,0xd5,0x00,0x9b, +0x4f,0xf0,0x00,0x0e,0x23,0xf0,0x7f,0x4a,0x51,0xf8,0x88,0x3c,0x58,0xf8,0x04,0x9f, +0x9b,0x06,0x56,0xbf,0x00,0x9b,0x0a,0xeb,0x0e,0x0b,0x0e,0xeb,0x03,0x0b,0x0e,0xf1, +0x04,0x0e,0x8b,0xea,0x09,0x09,0xbe,0xf1,0x10,0x0f,0xc8,0xf8,0x00,0x90,0xeb,0xd1, +0xd5,0xf8,0x00,0xe0,0x4e,0xf0,0x00,0x6e,0xc5,0xf8,0x00,0xe0,0x4f,0xf0,0x00,0x0e, +0xc5,0xf8,0x04,0xe0,0x51,0xf8,0x88,0x3c,0xd5,0xf8,0x04,0xe0,0x5b,0x06,0x4c,0xbf, +0x4e,0xf0,0x30,0x0e,0x4e,0xf0,0x10,0x0e,0xc5,0xf8,0x04,0xe0,0xd5,0xf8,0x04,0xe0, +0x4e,0xf0,0x0c,0x0e,0xc5,0xf8,0x04,0xe0,0x33,0x68,0x2b,0x62,0x02,0x9b,0x1b,0x68, +0x6b,0x62,0xdc,0xf8,0x00,0x30,0xab,0x62,0x51,0xf8,0xfc,0x3c,0xeb,0x62,0xd5,0xf8, +0x00,0xe0,0x1e,0xf0,0x00,0x6f,0xfa,0xd0,0xd5,0xf8,0x30,0xe0,0xc6,0xf8,0x00,0xe0, +0x02,0x9b,0xd5,0xf8,0x34,0xe0,0xc3,0xf8,0x00,0xe0,0xd5,0xf8,0x38,0xe0,0xcc,0xf8, +0x00,0xe0,0xd5,0xf8,0x3c,0xe0,0x41,0xf8,0xfc,0xec,0xd4,0xf8,0x08,0xe0,0x00,0x9b, +0x2e,0xf0,0x10,0x0e,0xc4,0xf8,0x08,0xe0,0x23,0x60,0x33,0x68,0x23,0x63,0x02,0x9b, +0x1b,0x68,0x63,0x63,0xdc,0xf8,0x00,0x30,0xa3,0x63,0x51,0xf8,0xfc,0x3c,0xe3,0x63, +0xa3,0x68,0x43,0xf0,0x01,0x03,0xa3,0x60,0xa3,0x68,0xdb,0x07,0xfc,0xd4,0x63,0x6a, +0x9b,0x07,0x7f,0xf5,0xef,0xae,0x63,0x6a,0x23,0xf0,0x02,0x03,0x63,0x62,0x00,0xbe, +0x00,0x10,0x00,0x40,0x4f,0xf0,0xff,0x0e,0x11,0xe7,0x4f,0xf0,0xff,0x0b,0x2e,0xe7, +0x4f,0xf0,0xff,0x0b,0x4d,0xe7,0x4f,0xf0,0xff,0x0b,0x6c,0xe7, diff --git a/contrib/loaders/flash/max32xxx/tpu_regs.h b/contrib/loaders/flash/max32xxx/tpu_regs.h new file mode 100644 index 0000000000..f750148af2 --- /dev/null +++ b/contrib/loaders/flash/max32xxx/tpu_regs.h @@ -0,0 +1,572 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2016 by Maxim Integrated * + * Copyright (C) 2025 Analog Devices, Inc. * + ***************************************************************************/ + +#ifndef _TPU_REGS_H_ +#define _TPU_REGS_H_ + +/* **** Includes **** */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__ICCARM__) +#pragma system_include +#endif + +/*/ @cond */ +/* + If types are not defined elsewhere (CMSIS) define them here +*/ +#ifndef __IO +#define __IO volatile +#endif +#ifndef __I +#define __I volatile const +#endif +#ifndef __O +#define __O volatile +#endif +#ifndef __R +#define __R volatile const +#endif +/*/ @endcond */ + +/* **** Definitions **** */ + +/** + * @ingroup tpu + * @defgroup tpu_registers Registers + * @brief Registers, Bit Masks and Bit Positions for the TPU Peripheral Module. + * @description The Trust Protection Unit used to assist the computationally intensive operations of several common + * cryptographic algorithms. + */ + +/** + * @ingroup tpu_registers + * Structure type to access the TPU Registers. + */ +struct mxc_tpu_regs { + __IO uint32_t ctrl; /**< \b 0x00:<\tt> TPU CTRL Register */ + __IO uint32_t cipher_ctrl; /**< \b 0x04:<\tt> TPU CIPHER_CTRL Register */ + __IO uint32_t hash_ctrl; /**< \b 0x08:<\tt> TPU HASH_CTRL Register */ + __IO uint32_t crc_ctrl; /**< \b 0x0C:<\tt> TPU CRC_CTRL Register */ + __IO uint32_t dma_src; /**< \b 0x10:<\tt> TPU DMA_SRC Register */ + __IO uint32_t dma_dest; /**< \b 0x14:<\tt> TPU DMA_DEST Register */ + __IO uint32_t dma_cnt; /**< \b 0x18:<\tt> TPU DMA_CNT Register */ + __IO uint32_t maa_ctrl; /**< \b 0x1C:<\tt> TPU MAA_CTRL Register */ + __O uint32_t din[4]; /**< \b 0x20:<\tt> TPU DIN Register */ + __I uint32_t dout[4]; /**< \b 0x30:<\tt> TPU DOUT Register */ + __IO uint32_t crc_poly; /**< \b 0x40:<\tt> TPU CRC_POLY Register */ + __IO uint32_t crc_val; /**< \b 0x44:<\tt> TPU CRC_VAL Register */ + __I uint32_t crc_prng; /**< \b 0x48:<\tt> TPU CRC_PRNG Register */ + __IO uint32_t ham_ecc; /**< \b 0x4C:<\tt> TPU HAM_ECC Register */ + __IO uint32_t cipher_init[4]; /**< \b 0x50:<\tt> TPU CIPHER_INIT Register */ + __O uint32_t cipher_key[8]; /**< \b 0x60:<\tt> TPU CIPHER_KEY Register */ + __IO uint32_t hash_digest[16]; /**< \b 0x80:<\tt> TPU HASH_DIGEST Register */ + __IO uint32_t hash_msg_sz[4]; /**< \b 0xC0:<\tt> TPU HASH_MSG_SZ Register */ + __IO uint32_t maa_maws; /**< \b 0xD0:<\tt> TPU MAA_MAWS Register */ +}; + +/* Register offsets for module TPU */ +/** + * @ingroup tpu_registers + * @defgroup TPU_Register_Offsets Register Offsets + * @brief TPU Peripheral Register Offsets from the TPU Base Peripheral Address. + * @{ + */ +#define MXC_R_TPU_CTRL ((uint32_t)0x00000000UL) /**< Offset from TPU Base Address: 0x0x000 */ +#define MXC_R_TPU_CIPHER_CTRL ((uint32_t)0x00000004UL) /**< Offset from TPU Base Address: 0x0x004 */ +#define MXC_R_TPU_HASH_CTRL ((uint32_t)0x00000008UL) /**< Offset from TPU Base Address: 0x0x008 */ +#define MXC_R_TPU_CRC_CTRL ((uint32_t)0x0000000CUL) /**< Offset from TPU Base Address: 0x0x00C */ +#define MXC_R_TPU_DMA_SRC ((uint32_t)0x00000010UL) /**< Offset from TPU Base Address: 0x0x010 */ +#define MXC_R_TPU_DMA_DEST ((uint32_t)0x00000014UL) /**< Offset from TPU Base Address: 0x0x014 */ +#define MXC_R_TPU_DMA_CNT ((uint32_t)0x00000018UL) /**< Offset from TPU Base Address: 0x0x018 */ +#define MXC_R_TPU_MAA_CTRL ((uint32_t)0x0000001CUL) /**< Offset from TPU Base Address: 0x0x01C */ +#define MXC_R_TPU_DIN ((uint32_t)0x00000020UL) /**< Offset from TPU Base Address: 0x0x020 */ +#define MXC_R_TPU_DOUT ((uint32_t)0x00000030UL) /**< Offset from TPU Base Address: 0x0x030 */ +#define MXC_R_TPU_CRC_POLY ((uint32_t)0x00000040UL) /**< Offset from TPU Base Address: 0x0x040 */ +#define MXC_R_TPU_CRC_VAL ((uint32_t)0x00000044UL) /**< Offset from TPU Base Address: 0x0x044 */ +#define MXC_R_TPU_CRC_PRNG ((uint32_t)0x00000048UL) /**< Offset from TPU Base Address: 0x0x048 */ +#define MXC_R_TPU_HAM_ECC ((uint32_t)0x0000004CUL) /**< Offset from TPU Base Address: 0x0x04C */ +#define MXC_R_TPU_CIPHER_INIT ((uint32_t)0x00000050UL) /**< Offset from TPU Base Address: 0x0x050 */ +#define MXC_R_TPU_CIPHER_KEY ((uint32_t)0x00000060UL) /**< Offset from TPU Base Address: 0x0x060 */ +#define MXC_R_TPU_HASH_DIGEST ((uint32_t)0x00000080UL) /**< Offset from TPU Base Address: 0x0x080 */ +#define MXC_R_TPU_HASH_MSG_SZ ((uint32_t)0x000000C0UL) /**< Offset from TPU Base Address: 0x0x0C0 */ +#define MXC_R_TPU_MAA_MAWS ((uint32_t)0x000000D0UL) /**< Offset from TPU Base Address: 0x0x0D0 */ + /**@} end of group tpu_registers */ + +/** + * @ingroup tpu_registers + * @defgroup CTRL_Register + * @brief Crypto Control Register. + * @{ + */ +#define MXC_F_TPU_CTRL_RST_POS 0 /**< CTRL_RST Position */ +#define MXC_F_TPU_CTRL_RST ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_RST_POS)) /**< CTRL_RST Mask */ + +#define MXC_F_TPU_CTRL_INTR_POS 1 /**< CTRL_INTR Position */ +#define MXC_F_TPU_CTRL_INTR ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_INTR_POS)) /**< CTRL_INTR Mask */ + +#define MXC_F_TPU_CTRL_SRC_POS 2 /**< CTRL_SRC Position */ +#define MXC_F_TPU_CTRL_SRC ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_SRC_POS)) /**< CTRL_SRC Mask */ + +#define MXC_F_TPU_CTRL_BSO_POS 4 /**< CTRL_BSO Position */ +#define MXC_F_TPU_CTRL_BSO ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_BSO_POS)) /**< CTRL_BSO Mask */ + +#define MXC_F_TPU_CTRL_BSI_POS 5 /**< CTRL_BSI Position */ +#define MXC_F_TPU_CTRL_BSI ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_BSI_POS)) /**< CTRL_BSI Mask */ + +#define MXC_F_TPU_CTRL_WAIT_EN_POS 6 /**< CTRL_WAIT_EN Position */ +#define MXC_F_TPU_CTRL_WAIT_EN ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_WAIT_EN_POS)) /**< CTRL_WAIT_EN Mask */ + +#define MXC_F_TPU_CTRL_WAIT_POL_POS 7 /**< CTRL_WAIT_POL Position */ +#define MXC_F_TPU_CTRL_WAIT_POL ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_WAIT_POL_POS)) /**< CTRL_WAIT_POL Mask */ + +#define MXC_F_TPU_CTRL_WRSRC_POS 8 /**< CTRL_WRSRC Position */ +#define MXC_F_TPU_CTRL_WRSRC ((uint32_t)(0x3UL << MXC_F_TPU_CTRL_WRSRC_POS)) /**< CTRL_WRSRC Mask */ +#define MXC_V_TPU_CTRL_WRSRC_NONE ((uint32_t)0x0UL) /**< CTRL_WRSRC_NONE Value */ +#define MXC_S_TPU_CTRL_WRSRC_NONE \ + (MXC_V_TPU_CTRL_WRSRC_NONE << MXC_F_TPU_CTRL_WRSRC_POS) /**< CTRL_WRSRC_NONE Setting */ +#define MXC_V_TPU_CTRL_WRSRC_CIPHEROUTPUT ((uint32_t)0x1UL) /**< CTRL_WRSRC_CIPHEROUTPUT Value */ +#define MXC_S_TPU_CTRL_WRSRC_CIPHEROUTPUT \ + (MXC_V_TPU_CTRL_WRSRC_CIPHEROUTPUT << MXC_F_TPU_CTRL_WRSRC_POS) /**< CTRL_WRSRC_CIPHEROUTPUT Setting */ +#define MXC_V_TPU_CTRL_WRSRC_READFIFO ((uint32_t)0x2UL) /**< CTRL_WRSRC_READFIFO Value */ +#define MXC_S_TPU_CTRL_WRSRC_READFIFO \ + (MXC_V_TPU_CTRL_WRSRC_READFIFO << MXC_F_TPU_CTRL_WRSRC_POS) /**< CTRL_WRSRC_READFIFO Setting */ +#define MXC_V_TPU_CTRL_WRSRC_RFU ((uint32_t)0x3UL) /**< CTRL_WRSRC_RFU Value */ +#define MXC_S_TPU_CTRL_WRSRC_RFU (MXC_V_TPU_CTRL_WRSRC_RFU << MXC_F_TPU_CTRL_WRSRC_POS) /**< CTRL_WRSRC_RFU Setting */ + +#define MXC_F_TPU_CTRL_RDSRC_POS 10 /**< CTRL_RDSRC Position */ +#define MXC_F_TPU_CTRL_RDSRC ((uint32_t)(0x3UL << MXC_F_TPU_CTRL_RDSRC_POS)) /**< CTRL_RDSRC Mask */ +#define MXC_V_TPU_CTRL_RDSRC_DMADISABLED ((uint32_t)0x0UL) /**< CTRL_RDSRC_DMADISABLED Value */ +#define MXC_S_TPU_CTRL_RDSRC_DMADISABLED \ + (MXC_V_TPU_CTRL_RDSRC_DMADISABLED << MXC_F_TPU_CTRL_RDSRC_POS) /**< CTRL_RDSRC_DMADISABLED Setting */ +#define MXC_V_TPU_CTRL_RDSRC_DMAORAPB ((uint32_t)0x1UL) /**< CTRL_RDSRC_DMAORAPB Value */ +#define MXC_S_TPU_CTRL_RDSRC_DMAORAPB \ + (MXC_V_TPU_CTRL_RDSRC_DMAORAPB << MXC_F_TPU_CTRL_RDSRC_POS) /**< CTRL_RDSRC_DMAORAPB Setting */ +#define MXC_V_TPU_CTRL_RDSRC_RNG ((uint32_t)0x2UL) /**< CTRL_RDSRC_RNG Value */ +#define MXC_S_TPU_CTRL_RDSRC_RNG (MXC_V_TPU_CTRL_RDSRC_RNG << MXC_F_TPU_CTRL_RDSRC_POS) /**< CTRL_RDSRC_RNG Setting */ + +#define MXC_F_TPU_CTRL_FLAG_MODE_POS 14 /**< CTRL_FLAG_MODE Position */ +#define MXC_F_TPU_CTRL_FLAG_MODE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_FLAG_MODE_POS)) /**< CTRL_FLAG_MODE Mask */ + +#define MXC_F_TPU_CTRL_DMADNEMSK_POS 15 /**< CTRL_DMADNEMSK Position */ +#define MXC_F_TPU_CTRL_DMADNEMSK ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_DMADNEMSK_POS)) /**< CTRL_DMADNEMSK Mask */ + +#define MXC_F_TPU_CTRL_DMA_DONE_POS 24 /**< CTRL_DMA_DONE Position */ +#define MXC_F_TPU_CTRL_DMA_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_DMA_DONE_POS)) /**< CTRL_DMA_DONE Mask */ + +#define MXC_F_TPU_CTRL_GLS_DONE_POS 25 /**< CTRL_GLS_DONE Position */ +#define MXC_F_TPU_CTRL_GLS_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_GLS_DONE_POS)) /**< CTRL_GLS_DONE Mask */ + +#define MXC_F_TPU_CTRL_HSH_DONE_POS 26 /**< CTRL_HSH_DONE Position */ +#define MXC_F_TPU_CTRL_HSH_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_HSH_DONE_POS)) /**< CTRL_HSH_DONE Mask */ + +#define MXC_F_TPU_CTRL_CPH_DONE_POS 27 /**< CTRL_CPH_DONE Position */ +#define MXC_F_TPU_CTRL_CPH_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_CPH_DONE_POS)) /**< CTRL_CPH_DONE Mask */ + +#define MXC_F_TPU_CTRL_MAA_DONE_POS 28 /**< CTRL_MAA_DONE Position */ +#define MXC_F_TPU_CTRL_MAA_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_MAA_DONE_POS)) /**< CTRL_MAA_DONE Mask */ + +#define MXC_F_TPU_CTRL_ERR_POS 29 /**< CTRL_ERR Position */ +#define MXC_F_TPU_CTRL_ERR ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_ERR_POS)) /**< CTRL_ERR Mask */ + +#define MXC_F_TPU_CTRL_RDY_POS 30 /**< CTRL_RDY Position */ +#define MXC_F_TPU_CTRL_RDY ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_RDY_POS)) /**< CTRL_RDY Mask */ + +#define MXC_F_TPU_CTRL_DONE_POS 31 /**< CTRL_DONE Position */ +#define MXC_F_TPU_CTRL_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_DONE_POS)) /**< CTRL_DONE Mask */ + +/**@} end of group CTRL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CIPHER_CTRL_Register + * @brief Cipher Control Register. + * @{ + */ +#define MXC_F_TPU_CIPHER_CTRL_ENC_POS 0 /**< CIPHER_CTRL_ENC Position */ +#define MXC_F_TPU_CIPHER_CTRL_ENC ((uint32_t)(0x1UL << MXC_F_TPU_CIPHER_CTRL_ENC_POS)) /**< CIPHER_CTRL_ENC Mask */ + +#define MXC_F_TPU_CIPHER_CTRL_KEY_POS 1 /**< CIPHER_CTRL_KEY Position */ +#define MXC_F_TPU_CIPHER_CTRL_KEY ((uint32_t)(0x1UL << MXC_F_TPU_CIPHER_CTRL_KEY_POS)) /**< CIPHER_CTRL_KEY Mask */ + +#define MXC_F_TPU_CIPHER_CTRL_SRC_POS 2 /**< CIPHER_CTRL_SRC Position */ +#define MXC_F_TPU_CIPHER_CTRL_SRC ((uint32_t)(0x3UL << MXC_F_TPU_CIPHER_CTRL_SRC_POS)) /**< CIPHER_CTRL_SRC Mask */ +#define MXC_V_TPU_CIPHER_CTRL_SRC_CIPHERKEY ((uint32_t)0x0UL) /**< CIPHER_CTRL_SRC_CIPHERKEY Value */ +#define MXC_S_TPU_CIPHER_CTRL_SRC_CIPHERKEY \ + (MXC_V_TPU_CIPHER_CTRL_SRC_CIPHERKEY << MXC_F_TPU_CIPHER_CTRL_SRC_POS) /**< CIPHER_CTRL_SRC_CIPHERKEY Setting */ +#define MXC_V_TPU_CIPHER_CTRL_SRC_REGFILE ((uint32_t)0x2UL) /**< CIPHER_CTRL_SRC_REGFILE Value */ +#define MXC_S_TPU_CIPHER_CTRL_SRC_REGFILE \ + (MXC_V_TPU_CIPHER_CTRL_SRC_REGFILE << MXC_F_TPU_CIPHER_CTRL_SRC_POS) /**< CIPHER_CTRL_SRC_REGFILE Setting */ +#define MXC_V_TPU_CIPHER_CTRL_SRC_QSPIKEY_REGFILE ((uint32_t)0x3UL) /**< CIPHER_CTRL_SRC_QSPIKEY_REGFILE Value */ +#define MXC_S_TPU_CIPHER_CTRL_SRC_QSPIKEY_REGFILE \ + (MXC_V_TPU_CIPHER_CTRL_SRC_QSPIKEY_REGFILE \ + << MXC_F_TPU_CIPHER_CTRL_SRC_POS) /**< CIPHER_CTRL_SRC_QSPIKEY_REGFILE Setting */ + +#define MXC_F_TPU_CIPHER_CTRL_CIPHER_POS 4 /**< CIPHER_CTRL_CIPHER Position */ +#define MXC_F_TPU_CIPHER_CTRL_CIPHER \ + ((uint32_t)(0x7UL << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS)) /**< CIPHER_CTRL_CIPHER Mask */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_DIS ((uint32_t)0x0UL) /**< CIPHER_CTRL_CIPHER_DIS Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_DIS \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_DIS << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_DIS Setting */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_AES128 ((uint32_t)0x1UL) /**< CIPHER_CTRL_CIPHER_AES128 Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_AES128 \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_AES128 << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_AES128 Setting \ + */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_AES192 ((uint32_t)0x2UL) /**< CIPHER_CTRL_CIPHER_AES192 Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_AES192 \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_AES192 << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_AES192 Setting \ + */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_AES256 ((uint32_t)0x3UL) /**< CIPHER_CTRL_CIPHER_AES256 Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_AES256 \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_AES256 << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_AES256 Setting \ + */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_DES ((uint32_t)0x4UL) /**< CIPHER_CTRL_CIPHER_DES Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_DES \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_DES << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_DES Setting */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_TDES ((uint32_t)0x5UL) /**< CIPHER_CTRL_CIPHER_TDES Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_TDES \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_TDES << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_TDES Setting */ + +#define MXC_F_TPU_CIPHER_CTRL_MODE_POS 8 /**< CIPHER_CTRL_MODE Position */ +#define MXC_F_TPU_CIPHER_CTRL_MODE ((uint32_t)(0x7UL << MXC_F_TPU_CIPHER_CTRL_MODE_POS)) /**< CIPHER_CTRL_MODE Mask */ +#define MXC_V_TPU_CIPHER_CTRL_MODE_ECB ((uint32_t)0x0UL) /**< CIPHER_CTRL_MODE_ECB Value */ +#define MXC_S_TPU_CIPHER_CTRL_MODE_ECB \ + (MXC_V_TPU_CIPHER_CTRL_MODE_ECB << MXC_F_TPU_CIPHER_CTRL_MODE_POS) /**< CIPHER_CTRL_MODE_ECB Setting */ +#define MXC_V_TPU_CIPHER_CTRL_MODE_CBC ((uint32_t)0x1UL) /**< CIPHER_CTRL_MODE_CBC Value */ +#define MXC_S_TPU_CIPHER_CTRL_MODE_CBC \ + (MXC_V_TPU_CIPHER_CTRL_MODE_CBC << MXC_F_TPU_CIPHER_CTRL_MODE_POS) /**< CIPHER_CTRL_MODE_CBC Setting */ +#define MXC_V_TPU_CIPHER_CTRL_MODE_CFB ((uint32_t)0x2UL) /**< CIPHER_CTRL_MODE_CFB Value */ +#define MXC_S_TPU_CIPHER_CTRL_MODE_CFB \ + (MXC_V_TPU_CIPHER_CTRL_MODE_CFB << MXC_F_TPU_CIPHER_CTRL_MODE_POS) /**< CIPHER_CTRL_MODE_CFB Setting */ +#define MXC_V_TPU_CIPHER_CTRL_MODE_OFB ((uint32_t)0x3UL) /**< CIPHER_CTRL_MODE_OFB Value */ +#define MXC_S_TPU_CIPHER_CTRL_MODE_OFB \ + (MXC_V_TPU_CIPHER_CTRL_MODE_OFB << MXC_F_TPU_CIPHER_CTRL_MODE_POS) /**< CIPHER_CTRL_MODE_OFB Setting */ +#define MXC_V_TPU_CIPHER_CTRL_MODE_CTR ((uint32_t)0x4UL) /**< CIPHER_CTRL_MODE_CTR Value */ +#define MXC_S_TPU_CIPHER_CTRL_MODE_CTR \ + (MXC_V_TPU_CIPHER_CTRL_MODE_CTR << MXC_F_TPU_CIPHER_CTRL_MODE_POS) /**< CIPHER_CTRL_MODE_CTR Setting */ + +/**@} end of group CIPHER_CTRL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup HASH_CTRL_Register + * @brief HASH Control Register. + * @{ + */ +#define MXC_F_TPU_HASH_CTRL_INIT_POS 0 /**< HASH_CTRL_INIT Position */ +#define MXC_F_TPU_HASH_CTRL_INIT ((uint32_t)(0x1UL << MXC_F_TPU_HASH_CTRL_INIT_POS)) /**< HASH_CTRL_INIT Mask */ + +#define MXC_F_TPU_HASH_CTRL_XOR_POS 1 /**< HASH_CTRL_XOR Position */ +#define MXC_F_TPU_HASH_CTRL_XOR ((uint32_t)(0x1UL << MXC_F_TPU_HASH_CTRL_XOR_POS)) /**< HASH_CTRL_XOR Mask */ + +#define MXC_F_TPU_HASH_CTRL_HASH_POS 2 /**< HASH_CTRL_HASH Position */ +#define MXC_F_TPU_HASH_CTRL_HASH ((uint32_t)(0x7UL << MXC_F_TPU_HASH_CTRL_HASH_POS)) /**< HASH_CTRL_HASH Mask */ +#define MXC_V_TPU_HASH_CTRL_HASH_DIS ((uint32_t)0x0UL) /**< HASH_CTRL_HASH_DIS Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_DIS \ + (MXC_V_TPU_HASH_CTRL_HASH_DIS << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_DIS Setting */ +#define MXC_V_TPU_HASH_CTRL_HASH_SHA1 ((uint32_t)0x1UL) /**< HASH_CTRL_HASH_SHA1 Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_SHA1 \ + (MXC_V_TPU_HASH_CTRL_HASH_SHA1 << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_SHA1 Setting */ +#define MXC_V_TPU_HASH_CTRL_HASH_SHA224 ((uint32_t)0x2UL) /**< HASH_CTRL_HASH_SHA224 Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_SHA224 \ + (MXC_V_TPU_HASH_CTRL_HASH_SHA224 << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_SHA224 Setting */ +#define MXC_V_TPU_HASH_CTRL_HASH_SHA256 ((uint32_t)0x3UL) /**< HASH_CTRL_HASH_SHA256 Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_SHA256 \ + (MXC_V_TPU_HASH_CTRL_HASH_SHA256 << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_SHA256 Setting */ +#define MXC_V_TPU_HASH_CTRL_HASH_SHA384 ((uint32_t)0x4UL) /**< HASH_CTRL_HASH_SHA384 Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_SHA384 \ + (MXC_V_TPU_HASH_CTRL_HASH_SHA384 << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_SHA384 Setting */ +#define MXC_V_TPU_HASH_CTRL_HASH_SHA512 ((uint32_t)0x5UL) /**< HASH_CTRL_HASH_SHA512 Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_SHA512 \ + (MXC_V_TPU_HASH_CTRL_HASH_SHA512 << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_SHA512 Setting */ + +#define MXC_F_TPU_HASH_CTRL_LAST_POS 5 /**< HASH_CTRL_LAST Position */ +#define MXC_F_TPU_HASH_CTRL_LAST ((uint32_t)(0x1UL << MXC_F_TPU_HASH_CTRL_LAST_POS)) /**< HASH_CTRL_LAST Mask */ + +/**@} end of group HASH_CTRL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CRC_CTRL_Register + * @brief CRC Control Register. + * @{ + */ +#define MXC_F_TPU_CRC_CTRL_CRC_POS 0 /**< CRC_CTRL_CRC Position */ +#define MXC_F_TPU_CRC_CTRL_CRC ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_CRC_POS)) /**< CRC_CTRL_CRC Mask */ + +#define MXC_F_TPU_CRC_CTRL_MSB_POS 1 /**< CRC_CTRL_MSB Position */ +#define MXC_F_TPU_CRC_CTRL_MSB ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_MSB_POS)) /**< CRC_CTRL_MSB Mask */ + +#define MXC_F_TPU_CRC_CTRL_PRNG_POS 2 /**< CRC_CTRL_PRNG Position */ +#define MXC_F_TPU_CRC_CTRL_PRNG ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_PRNG_POS)) /**< CRC_CTRL_PRNG Mask */ + +#define MXC_F_TPU_CRC_CTRL_ENT_POS 3 /**< CRC_CTRL_ENT Position */ +#define MXC_F_TPU_CRC_CTRL_ENT ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_ENT_POS)) /**< CRC_CTRL_ENT Mask */ + +#define MXC_F_TPU_CRC_CTRL_HAM_POS 4 /**< CRC_CTRL_HAM Position */ +#define MXC_F_TPU_CRC_CTRL_HAM ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_HAM_POS)) /**< CRC_CTRL_HAM Mask */ + +#define MXC_F_TPU_CRC_CTRL_HRST_POS 5 /**< CRC_CTRL_HRST Position */ +#define MXC_F_TPU_CRC_CTRL_HRST ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_HRST_POS)) /**< CRC_CTRL_HRST Mask */ + +/**@} end of group CRC_CTRL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup DMA_SRC_Register + * @brief Crypto DMA Source Address. + * @{ + */ +#define MXC_F_TPU_DMA_SRC_ADDR_POS 0 /**< DMA_SRC_ADDR Position */ +#define MXC_F_TPU_DMA_SRC_ADDR ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_DMA_SRC_ADDR_POS)) /**< DMA_SRC_ADDR Mask */ + +/**@} end of group DMA_SRC_Register */ + +/** + * @ingroup tpu_registers + * @defgroup DMA_DEST_Register + * @brief Crypto DMA Destination Address. + * @{ + */ +#define MXC_F_TPU_DMA_DEST_ADDR_POS 0 /**< DMA_DEST_ADDR Position */ +#define MXC_F_TPU_DMA_DEST_ADDR ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_DMA_DEST_ADDR_POS)) /**< DMA_DEST_ADDR Mask */ + +/**@} end of group DMA_DEST_Register */ + +/** + * @ingroup tpu_registers + * @defgroup DMA_CNT_Register + * @brief Crypto DMA Byte Count. + * @{ + */ +#define MXC_F_TPU_DMA_CNT_ADDR_POS 0 /**< DMA_CNT_ADDR Position */ +#define MXC_F_TPU_DMA_CNT_ADDR ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_DMA_CNT_ADDR_POS)) /**< DMA_CNT_ADDR Mask */ + +/**@} end of group DMA_CNT_Register */ + +/** + * @ingroup tpu_registers + * @defgroup MAA_CTRL_Register + * @brief MAA Control Register. + * @{ + */ +#define MXC_F_TPU_MAA_CTRL_STC_POS 0 /**< MAA_CTRL_STC Position */ +#define MXC_F_TPU_MAA_CTRL_STC ((uint32_t)(0x1UL << MXC_F_TPU_MAA_CTRL_STC_POS)) /**< MAA_CTRL_STC Mask */ + +#define MXC_F_TPU_MAA_CTRL_CLC_POS 1 /**< MAA_CTRL_CLC Position */ +#define MXC_F_TPU_MAA_CTRL_CLC ((uint32_t)(0x7UL << MXC_F_TPU_MAA_CTRL_CLC_POS)) /**< MAA_CTRL_CLC Mask */ +#define MXC_V_TPU_MAA_CTRL_CLC_EXP ((uint32_t)0x0UL) /**< MAA_CTRL_CLC_EXP Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_EXP \ + (MXC_V_TPU_MAA_CTRL_CLC_EXP << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_EXP Setting */ +#define MXC_V_TPU_MAA_CTRL_CLC_SQ ((uint32_t)0x1UL) /**< MAA_CTRL_CLC_SQ Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_SQ \ + (MXC_V_TPU_MAA_CTRL_CLC_SQ << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_SQ Setting */ +#define MXC_V_TPU_MAA_CTRL_CLC_MUL ((uint32_t)0x2UL) /**< MAA_CTRL_CLC_MUL Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_MUL \ + (MXC_V_TPU_MAA_CTRL_CLC_MUL << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_MUL Setting */ +#define MXC_V_TPU_MAA_CTRL_CLC_SQMUL ((uint32_t)0x3UL) /**< MAA_CTRL_CLC_SQMUL Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_SQMUL \ + (MXC_V_TPU_MAA_CTRL_CLC_SQMUL << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_SQMUL Setting */ +#define MXC_V_TPU_MAA_CTRL_CLC_ADD ((uint32_t)0x4UL) /**< MAA_CTRL_CLC_ADD Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_ADD \ + (MXC_V_TPU_MAA_CTRL_CLC_ADD << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_ADD Setting */ +#define MXC_V_TPU_MAA_CTRL_CLC_SUB ((uint32_t)0x5UL) /**< MAA_CTRL_CLC_SUB Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_SUB \ + (MXC_V_TPU_MAA_CTRL_CLC_SUB << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_SUB Setting */ + +#define MXC_F_TPU_MAA_CTRL_OCALC_POS 4 /**< MAA_CTRL_OCALC Position */ +#define MXC_F_TPU_MAA_CTRL_OCALC ((uint32_t)(0x1UL << MXC_F_TPU_MAA_CTRL_OCALC_POS)) /**< MAA_CTRL_OCALC Mask */ + +#define MXC_F_TPU_MAA_CTRL_MAAER_POS 7 /**< MAA_CTRL_MAAER Position */ +#define MXC_F_TPU_MAA_CTRL_MAAER ((uint32_t)(0x1UL << MXC_F_TPU_MAA_CTRL_MAAER_POS)) /**< MAA_CTRL_MAAER Mask */ + +#define MXC_F_TPU_MAA_CTRL_AMS_POS 8 /**< MAA_CTRL_AMS Position */ +#define MXC_F_TPU_MAA_CTRL_AMS ((uint32_t)(0x3UL << MXC_F_TPU_MAA_CTRL_AMS_POS)) /**< MAA_CTRL_AMS Mask */ + +#define MXC_F_TPU_MAA_CTRL_BMS_POS 10 /**< MAA_CTRL_BMS Position */ +#define MXC_F_TPU_MAA_CTRL_BMS ((uint32_t)(0x3UL << MXC_F_TPU_MAA_CTRL_BMS_POS)) /**< MAA_CTRL_BMS Mask */ + +#define MXC_F_TPU_MAA_CTRL_EMS_POS 12 /**< MAA_CTRL_EMS Position */ +#define MXC_F_TPU_MAA_CTRL_EMS ((uint32_t)(0x3UL << MXC_F_TPU_MAA_CTRL_EMS_POS)) /**< MAA_CTRL_EMS Mask */ + +#define MXC_F_TPU_MAA_CTRL_MMS_POS 14 /**< MAA_CTRL_MMS Position */ +#define MXC_F_TPU_MAA_CTRL_MMS ((uint32_t)(0x3UL << MXC_F_TPU_MAA_CTRL_MMS_POS)) /**< MAA_CTRL_MMS Mask */ + +#define MXC_F_TPU_MAA_CTRL_AMA_POS 16 /**< MAA_CTRL_AMA Position */ +#define MXC_F_TPU_MAA_CTRL_AMA ((uint32_t)(0xFUL << MXC_F_TPU_MAA_CTRL_AMA_POS)) /**< MAA_CTRL_AMA Mask */ + +#define MXC_F_TPU_MAA_CTRL_BMA_POS 20 /**< MAA_CTRL_BMA Position */ +#define MXC_F_TPU_MAA_CTRL_BMA ((uint32_t)(0xFUL << MXC_F_TPU_MAA_CTRL_BMA_POS)) /**< MAA_CTRL_BMA Mask */ + +#define MXC_F_TPU_MAA_CTRL_RMA_POS 24 /**< MAA_CTRL_RMA Position */ +#define MXC_F_TPU_MAA_CTRL_RMA ((uint32_t)(0xFUL << MXC_F_TPU_MAA_CTRL_RMA_POS)) /**< MAA_CTRL_RMA Mask */ + +#define MXC_F_TPU_MAA_CTRL_TMA_POS 28 /**< MAA_CTRL_TMA Position */ +#define MXC_F_TPU_MAA_CTRL_TMA ((uint32_t)(0xFUL << MXC_F_TPU_MAA_CTRL_TMA_POS)) /**< MAA_CTRL_TMA Mask */ + +/**@} end of group MAA_CTRL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup DIN_Register + * @brief Crypto Data Input. Data input can be written to this register instead of using + * the DMA. This register writes to the FIFO. This register occupies four + * successive words to allow the use of multi-store instructions. Words can be + * written to any location, they will be placed in the FIFO in the order they are + * written. The endian swap input control bit affects this register. + * @{ + */ +#define MXC_F_TPU_DIN_DATA_POS 0 /**< DIN_DATA Position */ +#define MXC_F_TPU_DIN_DATA ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_DIN_DATA_POS)) /**< DIN_DATA Mask */ + +/**@} end of group DIN_Register */ + +/** + * @ingroup tpu_registers + * @defgroup DOUT_Register + * @brief Crypto Data Output. Resulting data from cipher calculation. Data is placed in + * the lower words of these four registers depending on the algorithm. For block + * cipher modes, this register holds the result of most recent encryption or + * decryption operation. These registers are affected by the endian swap bits. + * @{ + */ +#define MXC_F_TPU_DOUT_DATA_POS 0 /**< DOUT_DATA Position */ +#define MXC_F_TPU_DOUT_DATA ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_DOUT_DATA_POS)) /**< DOUT_DATA Mask */ + +/**@} end of group DOUT_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CRC_POLY_Register + * @brief CRC Polynomial. The polynomial to be used for Galois Field calculations (CRC or + * LFSR) should be written to this register. This register is affected by the MSB + * control bit. + * @{ + */ +#define MXC_F_TPU_CRC_POLY_POLY_POS 0 /**< CRC_POLY_POLY Position */ +#define MXC_F_TPU_CRC_POLY_POLY ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_CRC_POLY_POLY_POS)) /**< CRC_POLY_POLY Mask */ + +/**@} end of group CRC_POLY_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CRC_VAL_Register + * @brief CRC Value. This is the state for the Galois Field. This register holds the + * result of a CRC calculation or the current state of the LFSR. This register is + * affected by the MSB control bit. + * @{ + */ +#define MXC_F_TPU_CRC_VAL_VAL_POS 0 /**< CRC_VAL_VAL Position */ +#define MXC_F_TPU_CRC_VAL_VAL ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_CRC_VAL_VAL_POS)) /**< CRC_VAL_VAL Mask */ + +/**@} end of group CRC_VAL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CRC_PRNG_Register + * @brief Pseudo Random Value. Output of the Galois Field shift register. This holds the + * resulting pseudo-random number if entropy is disabled or true random number if + * entropy is enabled. + * @{ + */ +#define MXC_F_TPU_CRC_PRNG_PRNG_POS 0 /**< CRC_PRNG_PRNG Position */ +#define MXC_F_TPU_CRC_PRNG_PRNG ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_CRC_PRNG_PRNG_POS)) /**< CRC_PRNG_PRNG Mask */ + +/**@} end of group CRC_PRNG_Register */ + +/** + * @ingroup tpu_registers + * @defgroup HAM_ECC_Register + * @brief Hamming ECC Register. + * @{ + */ +#define MXC_F_TPU_HAM_ECC_ECC_POS 0 /**< HAM_ECC_ECC Position */ +#define MXC_F_TPU_HAM_ECC_ECC ((uint32_t)(0xFFFFUL << MXC_F_TPU_HAM_ECC_ECC_POS)) /**< HAM_ECC_ECC Mask */ + +#define MXC_F_TPU_HAM_ECC_PAR_POS 16 /**< HAM_ECC_PAR Position */ +#define MXC_F_TPU_HAM_ECC_PAR ((uint32_t)(0x1UL << MXC_F_TPU_HAM_ECC_PAR_POS)) /**< HAM_ECC_PAR Mask */ + +/**@} end of group HAM_ECC_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CIPHER_INIT_Register + * @brief Initial Vector. For block cipher operations that use CBC, CFB, OFB, or CNTR + * modes, this register holds the initial value. This register is updated with each + * encryption or decryption operation. This register is affected by the endian swap + * bits. + * @{ + */ +#define MXC_F_TPU_CIPHER_INIT_IVEC_POS 0 /**< CIPHER_INIT_IVEC Position */ +#define MXC_F_TPU_CIPHER_INIT_IVEC \ + ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_CIPHER_INIT_IVEC_POS)) /**< CIPHER_INIT_IVEC Mask */ + +/**@} end of group CIPHER_INIT_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CIPHER_KEY_Register + * @brief Cipher Key. This register holds the key used for block cipher operations. The + * lower words are used for block ciphers that use shorter key lengths. This + * register is affected by the endian swap input control bits. + * @{ + */ +#define MXC_F_TPU_CIPHER_KEY_KEY_POS 0 /**< CIPHER_KEY_KEY Position */ +#define MXC_F_TPU_CIPHER_KEY_KEY \ + ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_CIPHER_KEY_KEY_POS)) /**< CIPHER_KEY_KEY Mask \ + */ + +/**@} end of group CIPHER_KEY_Register */ + +/** + * @ingroup tpu_registers + * @defgroup HASH_DIGEST_Register + * @brief This register holds the calculated hash value. This register is affected by the + * endian swap bits. + * @{ + */ +#define MXC_F_TPU_HASH_DIGEST_HASH_POS 0 /**< HASH_DIGEST_HASH Position */ +#define MXC_F_TPU_HASH_DIGEST_HASH \ + ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_HASH_DIGEST_HASH_POS)) /**< HASH_DIGEST_HASH Mask */ + +/**@} end of group HASH_DIGEST_Register */ + +/** + * @ingroup tpu_registers + * @defgroup HASH_MSG_SZ_Register + * @brief Message Size. This register holds the lowest 32-bit of message size in bytes. + * @{ + */ +#define MXC_F_TPU_HASH_MSG_SZ_MSGSZ_POS 0 /**< HASH_MSG_SZ_MSGSZ Position */ +#define MXC_F_TPU_HASH_MSG_SZ_MSGSZ \ + ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_HASH_MSG_SZ_MSGSZ_POS)) /**< HASH_MSG_SZ_MSGSZ Mask */ + +/**@} end of group HASH_MSG_SZ_Register */ + +/** + * @ingroup tpu_registers + * @defgroup MAA_MAWS_Register + * @brief MAA Word Size. This register defines the number of bits for a modular operation. + * This register must be set to a valid value prior to the MAA operation start. + * Valid values are from 1 to 2048. Invalid values are ignored and will not + * initiate a MAA operation. + * @{ + */ +#define MXC_F_TPU_MAA_MAWS_MAWS_POS 0 /**< MAA_MAWS_MAWS Position */ +#define MXC_F_TPU_MAA_MAWS_MAWS ((uint32_t)(0xFFFUL << MXC_F_TPU_MAA_MAWS_MAWS_POS)) /**< MAA_MAWS_MAWS Mask */ + +/**@} end of group MAA_MAWS_Register */ + +#ifdef __cplusplus +} +#endif + +#endif /* _TPU_REGS_H_ */ diff --git a/contrib/loaders/flash/msp432/driverlib.c b/contrib/loaders/flash/msp432/driverlib.c index 6f483b83da..b897755d16 100644 --- a/contrib/loaders/flash/msp432/driverlib.c +++ b/contrib/loaders/flash/msp432/driverlib.c @@ -67,20 +67,20 @@ static bool __pcm_set_core_voltage_level_advanced(uint_fast8_t voltage_level, reg_value = PCM->CTL0; switch (pcm_get_power_state()) { - case PCM_AM_LF_VCORE1: - case PCM_AM_DCDC_VCORE1: - case PCM_AM_LDO_VCORE0: - PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE1) - | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); - break; - case PCM_AM_LF_VCORE0: - case PCM_AM_DCDC_VCORE0: - case PCM_AM_LDO_VCORE1: - PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE0) - | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); - break; - default: - break; + case PCM_AM_LF_VCORE1: + case PCM_AM_DCDC_VCORE1: + case PCM_AM_LDO_VCORE0: + PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE1) + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + case PCM_AM_LF_VCORE0: + case PCM_AM_DCDC_VCORE0: + case PCM_AM_LDO_VCORE1: + PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE0) + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + default: + break; } if (blocking) { @@ -117,22 +117,22 @@ uint8_t pcm_get_power_mode(void) current_power_state = pcm_get_power_state(); switch (current_power_state) { - case PCM_AM_LDO_VCORE0: - case PCM_AM_LDO_VCORE1: - case PCM_LPM0_LDO_VCORE0: - case PCM_LPM0_LDO_VCORE1: - default: - return PCM_LDO_MODE; - case PCM_AM_DCDC_VCORE0: - case PCM_AM_DCDC_VCORE1: - case PCM_LPM0_DCDC_VCORE0: - case PCM_LPM0_DCDC_VCORE1: - return PCM_DCDC_MODE; - case PCM_LPM0_LF_VCORE0: - case PCM_LPM0_LF_VCORE1: - case PCM_AM_LF_VCORE1: - case PCM_AM_LF_VCORE0: - return PCM_LF_MODE; + case PCM_AM_DCDC_VCORE0: + case PCM_AM_DCDC_VCORE1: + case PCM_LPM0_DCDC_VCORE0: + case PCM_LPM0_DCDC_VCORE1: + return PCM_DCDC_MODE; + case PCM_LPM0_LF_VCORE0: + case PCM_LPM0_LF_VCORE1: + case PCM_AM_LF_VCORE1: + case PCM_AM_LF_VCORE0: + return PCM_LF_MODE; + case PCM_AM_LDO_VCORE0: + case PCM_AM_LDO_VCORE1: + case PCM_LPM0_LDO_VCORE0: + case PCM_LPM0_LDO_VCORE1: + default: + return PCM_LDO_MODE; } } @@ -141,23 +141,23 @@ uint8_t pcm_get_core_voltage_level(void) uint8_t current_power_state = pcm_get_power_state(); switch (current_power_state) { - case PCM_AM_LDO_VCORE0: - case PCM_AM_DCDC_VCORE0: - case PCM_AM_LF_VCORE0: - case PCM_LPM0_LDO_VCORE0: - case PCM_LPM0_DCDC_VCORE0: - case PCM_LPM0_LF_VCORE0: - default: - return PCM_VCORE0; - case PCM_AM_LDO_VCORE1: - case PCM_AM_DCDC_VCORE1: - case PCM_AM_LF_VCORE1: - case PCM_LPM0_LDO_VCORE1: - case PCM_LPM0_DCDC_VCORE1: - case PCM_LPM0_LF_VCORE1: - return PCM_VCORE1; - case PCM_LPM3: - return PCM_VCORELPM3; + case PCM_AM_LDO_VCORE1: + case PCM_AM_DCDC_VCORE1: + case PCM_AM_LF_VCORE1: + case PCM_LPM0_LDO_VCORE1: + case PCM_LPM0_DCDC_VCORE1: + case PCM_LPM0_LF_VCORE1: + return PCM_VCORE1; + case PCM_LPM3: + return PCM_VCORELPM3; + case PCM_AM_LDO_VCORE0: + case PCM_AM_DCDC_VCORE0: + case PCM_AM_LF_VCORE0: + case PCM_LPM0_LDO_VCORE0: + case PCM_LPM0_DCDC_VCORE0: + case PCM_LPM0_LF_VCORE0: + default: + return PCM_VCORE0; } } @@ -186,44 +186,44 @@ static bool __pcm_set_power_mode_advanced(uint_fast8_t power_mode, reg_value = PCM->CTL0; switch (current_power_state) { - case PCM_AM_DCDC_VCORE0: - case PCM_AM_LF_VCORE0: - PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE0 - | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); - break; - case PCM_AM_LF_VCORE1: - case PCM_AM_DCDC_VCORE1: - PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE1 - | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); - break; - case PCM_AM_LDO_VCORE1: { - if (power_mode == PCM_DCDC_MODE) { - PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE1 - | (reg_value & ~(PCM_CTL0_KEY_MASK - | PCM_CTL0_AMR_MASK))); - } else if (power_mode == PCM_LF_MODE) { - PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE1 - | (reg_value & ~(PCM_CTL0_KEY_MASK - | PCM_CTL0_AMR_MASK))); - } else - return false; - break; + case PCM_AM_DCDC_VCORE0: + case PCM_AM_LF_VCORE0: + PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE0 + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + case PCM_AM_LF_VCORE1: + case PCM_AM_DCDC_VCORE1: + PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE1 + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + case PCM_AM_LDO_VCORE1: + if (power_mode == PCM_DCDC_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE1 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else if (power_mode == PCM_LF_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE1 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else { + return false; } - case PCM_AM_LDO_VCORE0: { - if (power_mode == PCM_DCDC_MODE) { - PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE0 - | (reg_value & ~(PCM_CTL0_KEY_MASK - | PCM_CTL0_AMR_MASK))); - } else if (power_mode == PCM_LF_MODE) { - PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE0 - | (reg_value & ~(PCM_CTL0_KEY_MASK - | PCM_CTL0_AMR_MASK))); - } else - return false; - break; + break; + case PCM_AM_LDO_VCORE0: + if (power_mode == PCM_DCDC_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE0 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else if (power_mode == PCM_LF_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE0 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else { + return false; } - default: - break; + break; + default: + break; } if (blocking) { @@ -231,8 +231,9 @@ static bool __pcm_set_power_mode_advanced(uint_fast8_t power_mode, if (bool_timeout && !(--time_out)) return false; } - } else + } else { return true; + } current_power_mode = pcm_get_power_mode(); current_power_state = pcm_get_power_state(); @@ -256,76 +257,76 @@ static bool __pcm_set_power_state_advanced(uint_fast8_t power_state, return true; switch (power_state) { - case PCM_AM_LDO_VCORE0: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, - timeout, blocking); - case PCM_AM_LDO_VCORE1: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, - timeout, blocking); - case PCM_AM_DCDC_VCORE0: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, - timeout, blocking); - case PCM_AM_DCDC_VCORE1: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, - timeout, blocking); - case PCM_AM_LF_VCORE0: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, - timeout, blocking); - case PCM_AM_LF_VCORE1: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, - timeout, blocking); - case PCM_LPM0_LDO_VCORE0: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM0_LDO_VCORE1: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM0_DCDC_VCORE0: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM0_DCDC_VCORE1: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM0_LF_VCORE0: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM0_LF_VCORE1: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM3: - return pcm_goto_lpm3(); - case PCM_LPM4: - return pcm_goto_lpm4(); - case PCM_LPM45: - return pcm_shutdown_device(PCM_LPM45); - case PCM_LPM35_VCORE0: - return pcm_shutdown_device(PCM_LPM35_VCORE0); - default: - return false; + case PCM_AM_LDO_VCORE0: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking); + case PCM_AM_LDO_VCORE1: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking); + case PCM_AM_DCDC_VCORE0: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking); + case PCM_AM_DCDC_VCORE1: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking); + case PCM_AM_LF_VCORE0: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking); + case PCM_AM_LF_VCORE1: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking); + case PCM_LPM0_LDO_VCORE0: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_LDO_VCORE1: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_DCDC_VCORE0: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_DCDC_VCORE1: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_LF_VCORE0: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_LF_VCORE1: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM3: + return pcm_goto_lpm3(); + case PCM_LPM4: + return pcm_goto_lpm4(); + case PCM_LPM45: + return pcm_shutdown_device(PCM_LPM45); + case PCM_LPM35_VCORE0: + return pcm_shutdown_device(PCM_LPM35_VCORE0); + default: + return false; } return false; diff --git a/contrib/loaders/flash/msp432/main_msp432e4x.c b/contrib/loaders/flash/msp432/main_msp432e4x.c index 7974f48c77..7c9cf468df 100644 --- a/contrib/loaders/flash/msp432/main_msp432e4x.c +++ b/contrib/loaders/flash/msp432/main_msp432e4x.c @@ -30,37 +30,37 @@ int main(void) while (1) { switch (FLASH_LOADER->FLASH_FUNCTION) { - case FLASH_INIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_init(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_MASS_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_mass_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_SECTOR_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_sector_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_PROGRAM: - case FLASH_CONTINUOUS_PROGRAM: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_continous_write(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_EXIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_exit(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_NO_COMMAND: - break; - default: - FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; - break; + case FLASH_INIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_init(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_MASS_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_mass_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_SECTOR_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_sector_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_PROGRAM: + case FLASH_CONTINUOUS_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_continous_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_EXIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_exit(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_NO_COMMAND: + break; + default: + FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; + break; } } } diff --git a/contrib/loaders/flash/msp432/main_msp432p401x.c b/contrib/loaders/flash/msp432/main_msp432p401x.c index 47fb7fa476..024d047224 100644 --- a/contrib/loaders/flash/msp432/main_msp432p401x.c +++ b/contrib/loaders/flash/msp432/main_msp432p401x.c @@ -49,41 +49,41 @@ int main(void) while (1) { switch (FLASH_LOADER->FLASH_FUNCTION) { - case FLASH_INIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_init(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_MASS_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_mass_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_SECTOR_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_sector_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_PROGRAM: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_write(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_CONTINUOUS_PROGRAM: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_continous_write(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_EXIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_exit(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_NO_COMMAND: - break; - default: - FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; - break; + case FLASH_INIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_init(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_MASS_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_mass_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_SECTOR_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_sector_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_CONTINUOUS_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_continous_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_EXIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_exit(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_NO_COMMAND: + break; + default: + FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; + break; } } } diff --git a/contrib/loaders/flash/msp432/main_msp432p411x.c b/contrib/loaders/flash/msp432/main_msp432p411x.c index efc05a3b78..391057f2e5 100644 --- a/contrib/loaders/flash/msp432/main_msp432p411x.c +++ b/contrib/loaders/flash/msp432/main_msp432p411x.c @@ -52,41 +52,41 @@ int main(void) while (1) { switch (FLASH_LOADER->FLASH_FUNCTION) { - case FLASH_INIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_init(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_MASS_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_mass_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_SECTOR_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_sector_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_PROGRAM: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_write(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_CONTINUOUS_PROGRAM: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_continous_write(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_EXIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_exit(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_NO_COMMAND: - break; - default: - FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; - break; + case FLASH_INIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_init(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_MASS_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_mass_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_SECTOR_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_sector_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_CONTINUOUS_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_continous_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_EXIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_exit(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_NO_COMMAND: + break; + default: + FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; + break; } } } diff --git a/contrib/loaders/flash/silabs/Makefile b/contrib/loaders/flash/silabs/Makefile new file mode 100644 index 0000000000..7323494ec0 --- /dev/null +++ b/contrib/loaders/flash/silabs/Makefile @@ -0,0 +1,32 @@ +# 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 +CFLAGS = -c -mthumb -nostdlib -nostartfiles -Os -g -fPIC + +all: silabs_s0_s1.inc silabs_s2.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/efm32.S b/contrib/loaders/flash/silabs/silabs_s0_s1.S similarity index 100% rename from contrib/loaders/flash/efm32.S rename to contrib/loaders/flash/silabs/silabs_s0_s1.S diff --git a/contrib/loaders/flash/silabs/silabs_s0_s1.inc b/contrib/loaders/flash/silabs/silabs_s0_s1.inc new file mode 100644 index 0000000000..40e616b322 --- /dev/null +++ b/contrib/loaders/flash/silabs/silabs_s0_s1.inc @@ -0,0 +1,7 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x01,0x26,0x86,0x60,0x16,0x68,0x00,0x2e,0x22,0xd0,0x55,0x68,0xb5,0x42,0xf9,0xd0, +0x04,0x61,0x01,0x26,0xc6,0x60,0xc6,0x69,0x06,0x27,0x3e,0x42,0x16,0xd1,0xc6,0x69, +0x08,0x27,0x3e,0x42,0xfb,0xd0,0x2e,0x68,0x86,0x61,0x08,0x26,0xc6,0x60,0x04,0x35, +0x04,0x34,0xc6,0x69,0x01,0x27,0x3e,0x42,0xfb,0xd1,0x9d,0x42,0x01,0xd3,0x15,0x46, +0x08,0x35,0x55,0x60,0x01,0x39,0x00,0x29,0x02,0xd0,0xdb,0xe7,0x00,0x20,0x50,0x60, +0x30,0x46,0x00,0xbe, diff --git a/contrib/loaders/flash/silabs/silabs_s2.S b/contrib/loaders/flash/silabs/silabs_s2.S new file mode 100644 index 0000000000..d7f43855ce --- /dev/null +++ b/contrib/loaders/flash/silabs/silabs_s2.S @@ -0,0 +1,97 @@ +/* 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 * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + + /* Params: + * r0 - flash base (in), status (out) + * r1 - count (word-32bit) + * r2 - workarea start + * r3 - workarea end + * r4 - target address + * Clobbered: + * r5 - rp + * r6 - wp, tmp + * r7 - tmp + */ + +/* offsets of registers from flash reg base */ +#define EFM32_MSC_WRITECTRL_OFFSET 0x00c +#define EFM32_MSC_WRITECMD_OFFSET 0x010 +#define EFM32_MSC_ADDRB_OFFSET 0x014 +#define EFM32_MSC_WDATA_OFFSET 0x018 +#define EFM32_MSC_STATUS_OFFSET 0x01c + + /* set WREN to 1 */ + movs r6, #1 + str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] + +wait_fifo: + ldr r6, [r2, #0] /* read wp */ + cmp r6, #0 /* abort if wp == 0 */ + beq exit + ldr r5, [r2, #4] /* read rp */ + cmp r5, r6 /* wait until rp != wp */ + beq wait_fifo + + /* store address in MSC_ADDRB */ + str r4, [r0, #EFM32_MSC_ADDRB_OFFSET] + /* set LADDRIM bit */ + movs r6, #1 + str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] + /* check status for INVADDR and/or LOCKED */ + ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] + movs r7, #6 + tst r6, r7 + bne error + + /* wait for WDATAREADY */ +wait_wdataready: + ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] + movs r7, #8 + tst r6, r7 + beq wait_wdataready + + /* load data to WDATA */ + ldr r6, [r5] + str r6, [r0, #EFM32_MSC_WDATA_OFFSET] + /* set WRITEONCE bit */ + movs r6, #8 + str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] + + adds r5, #4 /* rp++ */ + adds r4, #4 /* target_address++ */ + + /* wait until BUSY flag is reset */ +busy: + ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] + movs r7, #1 + tst r6, r7 + bne busy + + cmp r5, r3 /* wrap rp at end of buffer */ + bcc no_wrap + adds r5, r2, #0 + adds r5, #8 +no_wrap: + str r5, [r2, #4] /* store rp */ + subs r1, r1, #1 /* decrement word count */ + cmp r1, #0 + beq exit /* loop if not done */ + b wait_fifo +error: + movs r0, #0 + str r0, [r2, #4] /* set rp = 0 on error */ +exit: + adds r0, r6, #0 + bkpt #0 diff --git a/contrib/loaders/flash/silabs/silabs_s2.inc b/contrib/loaders/flash/silabs/silabs_s2.inc new file mode 100644 index 0000000000..f0ef04edda --- /dev/null +++ b/contrib/loaders/flash/silabs/silabs_s2.inc @@ -0,0 +1,7 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x01,0x26,0xc6,0x60,0x16,0x68,0x00,0x2e,0x22,0xd0,0x55,0x68,0xb5,0x42,0xf9,0xd0, +0x44,0x61,0x01,0x26,0x06,0x61,0xc6,0x69,0x06,0x27,0x3e,0x42,0x16,0xd1,0xc6,0x69, +0x08,0x27,0x3e,0x42,0xfb,0xd0,0x2e,0x68,0x86,0x61,0x08,0x26,0x06,0x61,0x04,0x35, +0x04,0x34,0xc6,0x69,0x01,0x27,0x3e,0x42,0xfb,0xd1,0x9d,0x42,0x01,0xd3,0x15,0x1c, +0x08,0x35,0x55,0x60,0x01,0x39,0x00,0x29,0x02,0xd0,0xdb,0xe7,0x00,0x20,0x50,0x60, +0x30,0x1c,0x00,0xbe, diff --git a/contrib/loaders/flash/stm32/stm32h7rx.S b/contrib/loaders/flash/stm32/stm32h7rx.S new file mode 100644 index 0000000000..bfc4929d09 --- /dev/null +++ b/contrib/loaders/flash/stm32/stm32h7rx.S @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2017 by STMicroelectronics * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m4 + .thumb + +/* + * Code limitations: + * The workarea must have size multiple of 4 bytes, since R/W + * operations are all at 32 bits. + * The workarea must be big enough to contain rp, wp and data, thus the minimum + * workarea size is: min_wa_size = sizeof(rp, wp, data) = 4 + 4 + sizeof(data). + * - for 0x450 devices: sizeof(data) = 32 bytes, thus min_wa_size = 40 bytes. + * - for 0x480 devices: sizeof(data) = 16 bytes, thus min_wa_size = 24 bytes. + * To benefit from concurrent host write-to-buffer and target + * write-to-flash, the workarea must be way bigger than the minimum. + * + * To avoid confusions the write word size is got from .block_size member of + * struct stm32h7x_part_info defined in stm32h7x.c +*/ + +/* + * Params : + * r0 = workarea start, status (out) + * r1 = workarea end + * r2 = target address + * r3 = count (of write words) + * r4 = size of write word + * r5 = flash reg base + * + * Clobbered: + * r6 - rp + * r7 - wp, status, tmp + * r8 - loop index, tmp + */ + +#define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */ +#define STM32_FLASH_SR_OFFSET 0x14 /* offset of SR register in FLASH struct */ +#define STM32_FLASH_ICR_OFFSET 0x28 /* offset of SR register in FLASH struct */ +#define STM32_CR_PROG 0x00000002 /* PG */ +#define STM32_SR_QW_MASK 0x00000004 /* QW */ +#define STM32_SR_ERROR_MASK 0x1F2E0000 /* DBECCERR | SNECCERR | RDSERR | RDPERR | OPERR + | INCERR | STRBERR | PGSERR | WRPERR */ + + .thumb_func + .global _start +_start: + ldr r6, [r0, #4] /* read rp */ + +wait_fifo: + ldr r7, [r0, #0] /* read wp */ + cbz r7, exit /* abort if wp == 0, status = 0 */ + subs r7, r7, r6 /* number of bytes available for read in r7 */ + ittt mi /* if wrapped around */ + addmi r7, r1 /* add size of buffer */ + submi r7, r0 + submi r7, #8 + cmp r7, r4 /* wait until data buffer is full */ + bcc wait_fifo + + mov r7, #STM32_CR_PROG + str r7, [r5, #STM32_FLASH_CR_OFFSET] + + mov r8, #4 + udiv r8, r4, r8 /* number of words is size of write word divided by 4*/ +write_flash: + dsb + ldr r7, [r6], #0x04 /* read one word from src, increment ptr */ + str r7, [r2], #0x04 /* write one word to dst, increment ptr */ + dsb + cmp r6, r1 /* if rp >= end of buffer ... */ + it cs + addcs r6, r0, #8 /* ... then wrap at buffer start */ + subs r8, r8, #1 /* decrement loop index */ + bne write_flash /* loop if not done */ + +busy: + ldr r7, [r5, #STM32_FLASH_SR_OFFSET] + tst r7, #STM32_SR_QW_MASK + bne busy /* operation in progress, wait ... */ + + ldr r7, [r5, #STM32_FLASH_ICR_OFFSET] + ldr r8, =STM32_SR_ERROR_MASK + tst r7, r8 + bne error /* fail... */ + + str r6, [r0, #4] /* store rp */ + subs r3, r3, #1 /* decrement count */ + bne wait_fifo /* loop if not done */ + b exit + +error: + movs r8, #0 + str r8, [r0, #4] /* set rp = 0 on error */ + +exit: + mov r0, r7 /* return status in r0 */ + bkpt #0x00 + + .pool diff --git a/contrib/loaders/flash/stm32/stm32h7rx.inc b/contrib/loaders/flash/stm32/stm32h7rx.inc new file mode 100644 index 0000000000..feecab6230 --- /dev/null +++ b/contrib/loaders/flash/stm32/stm32h7rx.inc @@ -0,0 +1,8 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x46,0x68,0x07,0x68,0x77,0xb3,0xbf,0x1b,0x42,0xbf,0x7f,0x18,0x3f,0x1a,0x08,0x3f, +0xa7,0x42,0xf6,0xd3,0x4f,0xf0,0x02,0x07,0x2f,0x61,0x4f,0xf0,0x04,0x08,0xb4,0xfb, +0xf8,0xf8,0xbf,0xf3,0x4f,0x8f,0x56,0xf8,0x04,0x7b,0x42,0xf8,0x04,0x7b,0xbf,0xf3, +0x4f,0x8f,0x8e,0x42,0x28,0xbf,0x00,0xf1,0x08,0x06,0xb8,0xf1,0x01,0x08,0xf0,0xd1, +0x6f,0x69,0x17,0xf0,0x04,0x0f,0xfb,0xd1,0xaf,0x6a,0xdf,0xf8,0x1c,0x80,0x17,0xea, +0x08,0x0f,0x03,0xd1,0x46,0x60,0x01,0x3b,0xd3,0xd1,0x03,0xe0,0x5f,0xf0,0x00,0x08, +0xc0,0xf8,0x04,0x80,0x38,0x46,0x00,0xbe,0x00,0x00,0x2e,0x1f, diff --git a/doc/fdl.texi b/doc/fdl.texi index 2189f80a66..72916a9fb7 100644 --- a/doc/fdl.texi +++ b/doc/fdl.texi @@ -7,7 +7,7 @@ @display Copyright @copyright{} 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. diff --git a/doc/manual/helper.txt b/doc/manual/helper.txt index 6cf3c977bf..29e84e6f0b 100644 --- a/doc/manual/helper.txt +++ b/doc/manual/helper.txt @@ -97,18 +97,6 @@ registration, while the @c unregister_command() and These may be called at any time, allowing the command set to change in response to system actions. -@subsection helpercmdjim Jim Command Registration - -The command_registration structure provides support for registering -native Jim command handlers (@c jim_handler) too. For these handlers, -the module can provide help and usage support; however, this mechanism -allows Jim handlers to be called as sub-commands of other commands. -These commands may be registered with a private data value (@c -jim_handler_data) that will be available when called, as with low-level -Jim command registration. - -A command may have a normal @c handler or a @c jim_handler, but not both. - @subsection helpercmdregisterchains Command Chaining When using register_commands(), the array of commands may reference diff --git a/doc/manual/primer/docs.txt b/doc/manual/primer/docs.txt index 1aefa17e6d..ccf4550d51 100644 --- a/doc/manual/primer/docs.txt +++ b/doc/manual/primer/docs.txt @@ -16,7 +16,6 @@ OpenOCD presently produces several kinds of documentation: - Provides overview, usage, reference, and FAQ for each device. - Written using LaTeX language with custom macros. - Created with 'make references'. - - See @subpage primerlatex and @ref stylelatex. - The Manual: - Focuses on developing the OpenOCD software. - Details the architecture, driver interfaces, and processes. @@ -44,19 +43,6 @@ the Texinfo web site for the Texinfo manual and more information. OpenOCD style guidelines for Texinfo documentation can be found on the @ref styletexinfo page. - */ -/** @page primerlatex LaTeX Primer - -The OpenOCD project provides a number of reference guides using the -LaTeX typesetting language. - -- OpenOCD Quick Reference Sheets -- OpenOCD Hardware Reference Guides - -These documents have not yet been produced, so this Primer serves as -a placeholder to describe how they are created and can be extended. -The same holds true for the @ref stylelatex page. - */ /** @page primerdoxygen Doxygen Primer @@ -118,7 +104,6 @@ This file contains the Doxygen source code for the @ref primerdocs. The @ref primerdocs page also contains the following sections: - @ref primertexinfo -- @ref primerlatex - @ref primerdoxygen */ diff --git a/doc/manual/server.txt b/doc/manual/server.txt index 20e48c1f43..3c31e6fc62 100644 --- a/doc/manual/server.txt +++ b/doc/manual/server.txt @@ -190,7 +190,6 @@ Remember: OpenOCD runs on: -# FreeBSD -# Cygwin -# MinGW32 --# Ecos How can we get that to work? diff --git a/doc/manual/style.txt b/doc/manual/style.txt index f7a12988fc..e8a375cddd 100644 --- a/doc/manual/style.txt +++ b/doc/manual/style.txt @@ -22,7 +22,6 @@ providing documentation, either as part of the C code or stand-alone. - @subpage styledoxygen - @subpage styletexinfo -- @subpage stylelatex Feedback would be welcome to improve the OpenOCD guidelines. @@ -46,7 +45,7 @@ OpenOCD project. - use TAB characters for indentation; do NOT use spaces. - displayed TAB width is 4 characters. - use Unix line endings ('\\n'); do NOT use DOS endings ('\\r\\n') -- limit adjacent empty lines to at most two (2). +- do NOT use multiple empty lines. - remove any trailing empty lines at the end of source files - do not "comment out" code from the tree nor put it within a block @code @@ -449,13 +448,6 @@ be as productive as possible. Needing to look at OpenOCD source code, to figure out how to use it is a bad sign, though it's OK to need to look at the User's guide to figure out what a config script is doing. - */ -/** @page stylelatex LaTeX Style Guide - -This page needs to provide style guidelines for using LaTeX, the -typesetting language used by The References for OpenOCD Hardware. -Likewise, the @ref primerlatex for using this guide needs to be completed. - */ /** @page styleperl Perl Style Guide @@ -510,7 +502,6 @@ documentation languages: - @ref stylec - @ref styledoxygen - @ref styletexinfo -- @ref stylelatex - @ref styleperl - @ref styleautotools diff --git a/doc/openocd.texi b/doc/openocd.texi index 1a61cd3c4b..33d7bce320 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-2022 The OpenOCD Project +@item Copyright @copyright{} 2008-2025 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} @@ -154,15 +154,15 @@ USB-based, parallel port-based, and other standalone boxes that run OpenOCD internally. @xref{Debug Adapter Hardware}. @b{GDB Debug:} It allows ARM7 (ARM7TDMI and ARM720t), ARM9 (ARM920T, -ARM922T, ARM926EJ--S, ARM966E--S), XScale (PXA25x, IXP42x), Cortex-M3 -(Stellaris LM3, STMicroelectronics STM32 and Energy Micro EFM32) and +ARM922T, ARM926EJ--S, ARM966E--S), XScale (PXA25x, IXP42x), Cortex-M +(Stellaris LM3, STMicroelectronics STM32 and Silicon Labs EFM32/EFR32) and Intel Quark (x10xx) based cores to be debugged via the GDB protocol. @b{Flash Programming:} Flash writing is supported for external CFI-compatible NOR flashes (Intel and AMD/Spansion command set) and several internal flashes (LPC1700, LPC1800, LPC2000, LPC4300, AT91SAM7, AT91SAM3U, -STR7x, STR9x, LM3, STM32x and EFM32). Preliminary support for various NAND flash -controllers (LPC3180, Orion, S3C24xx, more) is included. +STR7x, STR9x, LM3, STM32x and EFM32/EFR32). Preliminary support for various NAND +flash controllers (LPC3180, Orion, S3C24xx, more) is included. @section OpenOCD Web Site @@ -239,7 +239,7 @@ needing a Git client: @uref{http://repo.or.cz/w/openocd.git} -The @file{README} file contains the instructions for building the project +The @file{README.md} file contains the instructions for building the project from the repository or a snapshot. Developers that want to contribute patches to the OpenOCD system are @@ -529,9 +529,8 @@ debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/ @section IBM PC Parallel Printer Port Based -The two well-known ``JTAG Parallel Ports'' cables are the Xilinx DLC5 -and the Macraigor Wiggler. There are many clones and variations of -these on the market. +The two well-known JTAG parallel port cables are the Xilinx DLC5 and the Macraigor Wiggler. +There are many clones and variations of these on the market. Note that parallel ports are becoming much less common, so if you have the choice you should probably avoid these adapters in favor @@ -553,7 +552,7 @@ produced, PDF schematics are easily found and it is easy to make. @* Link: @url{http://www.ccac.rwth-aachen.de/~michaels/index.php/hardware/armjtag} @item @b{Wiggler_ntrst_inverted} -@* Yet another variation - See the source code, src/jtag/parport.c +@* Yet another variation, see configuration in @file{interface/parport/wiggler-ntrst-inverted.cfg} @item @b{old_amt_wiggler} @* Unknown - probably not on the market today @@ -613,6 +612,15 @@ 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. +@* Link: @url{https://www.xilinx.com/products/intellectual-property/debug-bridge.html} + +@item @b{xlnx_axi_xvc} +@* A JTAG driver exposing JTAG to OpenOCD over AXI-mapped registers. +@* Link: @url{https://docs.amd.com/r/en-US/pg437-axi-jtag/Introduction} +@* Link: @url{https://china.xilinx.com/support/documentation/application_notes/xapp1251-xvc-zynq-petalinux.pdf} + +@item @b{xvc} +@* A JTAG driver using Xilinx Virtual Cable over TCP to OpenOCD as JTAG interface. @item @b{linuxspidev} @* A SPI based SWD driver using Linux SPI devices. @@ -625,7 +633,11 @@ emulation model of target hardware. 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. +@* A JTAG driver to communicate with builtin debug modules of Espressif ESP32-C3, ESP32-C6, ESP32-H2 and ESP32-S3 chips using OpenOCD. + +@item @b{ch347} +@* A JTAG driver that works with the WCH CH347F and CH347T chips. +When using the CH347T, it must be configured to operate in mode 3 (UART + JTAG). @end itemize @@ -804,8 +816,7 @@ itself), use the @option{-d} command line switch. This sets the @option{debug_level} to "3", outputting the most information, including debug messages. The default setting is "2", outputting only informational messages, warnings and errors. You can also change this -setting from within a telnet or gdb session using @command{debug_level} -(@pxref{debuglevel,,debug_level}). +setting from within a telnet or gdb session using @ref{debuglevel,,@command{debug_level}}. You can redirect all output from the server to a file using the @option{-l } switch. @@ -1185,9 +1196,10 @@ monitor mode debug, only "halt mode" debug.} @cindex ARM semihosting When linked with a special runtime library provided with many toolchains@footnote{See chapter 8 "Semihosting" in -@uref{http://infocenter.arm.com/help/topic/com.arm.doc.dui0203i/DUI0203I_rvct_developer_guide.pdf, -ARM DUI 0203I}, the "RealView Compilation Tools Developer Guide". -The CodeSourcery EABI toolchain also includes a semihosting library.}, +@uref{https://developer.arm.com/documentation/dui0203/latest/semihosting, +ARM DUI 0203}. +A semihosting library if available in newlib/libgloss, in U-Boot, +in the CodeSourcery EABI toolchain, and others.}, your target code can use I/O facilities on the debug host. That library provides a small set of system calls which are handled by OpenOCD. It can let the debugger provide your system console and a file system, @@ -1382,11 +1394,11 @@ 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' +@deffn {Command} {find} filename Prints full path to @var{filename} according to OpenOCD search rules. @end deffn -@deffn {Command} {ocd_find} 'filename' +@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. @@ -1432,7 +1444,6 @@ In addition to target-specific utility code, another way that board and target config files communicate is by following a convention on how to use certain variables. -The full Tcl/Tk language supports ``namespaces'', but Jim Tcl does not. Thus the rule we follow in OpenOCD is this: Variables that begin with a leading underscore are temporary in nature, and can be modified and used at will within a target configuration file. @@ -1763,10 +1774,10 @@ There are more complex examples too, with chips that have multiple TAPs. Ones worth looking at include: @itemize -@item @file{target/omap3530.cfg} -- with disabled ARM and DSP, +@item @file{target/ti/omap3530.cfg} -- with disabled ARM and DSP, plus a JRC to enable them @item @file{target/str912.cfg} -- with flash, CPU, and boundary scan -@item @file{target/ti_dm355.cfg} -- with ETM, ARM, and JRC (this JRC +@item @file{target/ti/dm355.cfg} -- with ETM, ARM, and JRC (this JRC is not currently used) @end itemize @@ -2360,6 +2371,11 @@ MMU: disabled, D-Cache: disabled, I-Cache: enabled @end example @end deffn +@deffn {Command} {poll_interval} [milliseconds] +Set the polling interval of target's state. +With no parameter, it prints out the current value of polling interval. +@end deffn + @node Debug Adapter Configuration @chapter Debug Adapter Configuration @cindex config file, interface @@ -2431,13 +2447,14 @@ dict get [adapter list] ftdi @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} @ + @option{led} | @option{user0} @ [ @ 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} @ + @option{-exit-inactive} | @option{-exit-active} | @option{-exit-input} | @option{-exit-no-change} @ ] ]} Define the GPIO mapping that the adapter will use. The following signals can be @@ -2450,6 +2467,7 @@ JTAG transport signals @item @option{swdio_dir}: optional swdio buffer control signal @item @option{srst}: system reset signal @item @option{led}: optional activity led +@item @option{user0}: optional, user-specific signal @end itemize @@ -2472,17 +2490,28 @@ equivalent to issuing the single command @command{gpio led 7 -chip 1 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. +swdio. Accordingly, the final state before the adapter terminates its operation, +so-called “exit state”, can be set. By default the state and configuration of an +output pin is not changed when the driver terminates its operation. 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 +@deffn {Config Command} {adapter usb vid_pid} (vid pid)+ +Specifies the USB vendor and product IDs of the adapter to use. +Currently, up to 16 [@var{vid}, @var{pid}] pairs may be given, e.g. +@example +adapter usb vid_pid 0xc251 0xf001 0x0d28 0x0204 +@end example +@end deffn + @deffn {Config Command} {adapter usb location} [-[.]...] 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 @@ -2493,12 +2522,20 @@ 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 usb product_name} name +Specifies the USB product name (the @emph{iProduct} string) of the adapter to use. +If this is not set, the product name is not used during device selection. +@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. + +For jlink adapters, the @var{serial_string} is also compared +against the adapter's nickname. @end deffn @section Interface Drivers @@ -2508,6 +2545,8 @@ enabled when OpenOCD is configured, in order to be made available at run time. @deffn {Interface Driver} {amt_jtagaccel} +@b{Note: This adapter is deprecated and support will be removed in the next release!} + Amontec Chameleon in its JTAG Accelerator configuration, connected to a PC's EPP mode parallel port. This defines some driver-specific commands: @@ -2544,36 +2583,109 @@ and a specific set of GPIOs is used. @c chooses among list of bit configs ... only one option @end deffn -@deffn {Interface Driver} {cmsis-dap} -ARM CMSIS-DAP compliant based adapter v1 (USB HID based) -or v2 (USB bulk). +@deffn {Interface Driver} {ch347} +Driver for WCH CH347F and CH347T chips. +When using the CH347T, it must be configured to operate in mode 3 (UART + JTAG). -@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 -@end example +@b{WARNING:} WCH CH347T chips have rather poor performance +with respect to the USB HS connection. Upgrade firmware to the latest version! +@itemize @bullet +@item Chip version 2.41: +@itemize @minus +@item JTAG timing is very weird, some clock pulses are +much shorter then the requested clock frequency. +@item SWD is not implemented. +@end itemize +@item Chip version 4.41: +@itemize @minus +@item SWD clock is limited to 1 MHz maximum. +@item SWD reading AP reg CH347 erroneously drives +SWDIO to H for 392 ns after the last ACK bit. Some devices get so upset +that send wrong data with parity error. A resistor in the SWDIO circuit +mitigates the problem. +@item A long SWD operation causes that USB host disconnects the adapter. +@end itemize +@item Chip version 5.44: +@itemize @minus +@item Maximal SWD clock speed is 5 MHz +@item A long SWD operation causes that USB host disconnects the adapter. +@end itemize +@end itemize + +The driver supports activity LED through the generic +command @ref{adapter gpio, @command{adapter gpio led}}. @end deffn -@deffn {Config Command} {cmsis-dap backend} [@option{auto}|@option{usb_bulk}|@option{hid}] +@deffn {Interface Driver} {cklink} +Driver for the T-Head CK-Link Lite V2 JTAG probe and Bouffalo Lab +BL616/BL702 clones, including the built-in debugger on Bouffalo BL618 +evaluation boards. Communication is over USB bulk endpoints using a +T-Head DebugServer-compatible framed command protocol. + +The driver only supports JTAG transport and a single-TAP chain. The +probe runs at a fixed clock; @command{adapter speed} requests are +accepted but ignored (with a one-time warning). @command{JTAG_TMS} and +@command{JTAG_PATHMOVE} are not supported by this probe's protocol. + +By default the driver matches 0x42bf/0xb210 (Bouffalo) and +0x32bf/0xb210 (T-Head). The built-in list can be overridden via +@command{adapter usb vid_pid}. +@end deffn + +@deffn {Interface Driver} {cmsis-dap} +ARM CMSIS-DAP compliant based adapter v1 (USB HID based) +or v2 (USB bulk or TCP/IP). + +@deffn {Config Command} {cmsis-dap backend} [@option{auto}|@option{usb_bulk}|@option{hid}|@option{tcp}] Specifies how to communicate with the adapter: @itemize @minus -@item @option{hid} Use HID generic reports - CMSIS-DAP v1 +@item @option{hid} Use USB 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. +@item @option{tcp} Use TCP/IP instead of USB +@item @option{auto} First try USB bulk CMSIS-DAP v2, if not found try USB HID +CMSIS-DAP v1, if not found try TCP (if @command{cmsis-dap tcp host} is +configured). This is the default if @command{cmsis-dap backend} is not +specified. @end itemize @end deffn -@deffn {Config Command} {cmsis-dap usb interface} [number] +@deffn {Config Command} {cmsis-dap usb interface} number Specifies the @var{number} of the USB interface to use in v2 mode (USB bulk). In most cases need not to be specified and interfaces are searched by interface string or for user class interface. @end deffn +@deffn {Config Command} {cmsis-dap tcp host} hostname +Specifies the @var{hostname} or IP address of the remote programmer. For use +with 'tcp' backend only. +@example +cmsis-dap backend tcp +cmsis-dap tcp host 192.168.1.4 +@end example +@end deffn + +@deffn {Config Command} {cmsis-dap tcp port} port +Specifies the TCP @var{port} number used by the remote programmer for DAP +commands. The default port is 4441. For use with 'tcp' backend only. +@example +cmsis-dap backend tcp +cmsis-dap tcp host 192.168.1.4 +cmsis-dap tcp port 4441 +@end example +@end deffn + +@deffn {Config Command} {cmsis-dap tcp min_timeout} milliseconds +Sets a lower bound on the requested timeout in @var{milliseconds} to wait for +response packets from the remote programmer when using the 'tcp' backend. The +user may want to use a larger value on slower networks, to avoid getting +command mismatch errors. Default value is 150 milliseconds. For use with 'tcp' +backend only. +@example +cmsis-dap tcp min_timeout 200 +@end example +@end deffn + @deffn {Command} {cmsis-dap quirk} [@option{enable}|@option{disable}] Enables or disables the following workarounds of known CMSIS-DAP adapter quirks: @@ -2649,20 +2761,6 @@ 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]+ -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 -@end example -@end deffn - -@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 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. @@ -2807,11 +2905,6 @@ 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} -The vendor ID and product ID of the adapter. If not specified, default -0x0403:0x6001 is used. -@end deffn - @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. @@ -2912,22 +3005,25 @@ remote_bitbang host mysocket @deffn {Interface Driver} {usb_blaster} 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: +for FTDI chips. -@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): +Use @command{adapter usb vid_pid} to specify the vendor and product ID of the +FT245 device. If not specified, default values are used. + +For example, Altera USB-Blaster (default): @example -usb_blaster vid_pid 0x09FB 0x6001 +adapter usb vid_pid 0x09FB 0x6001 @end example The following VID/PID is for Kolja Waschk's USB JTAG: @example -usb_blaster vid_pid 0x16C0 0x06AD +adapter usb vid_pid 0x16C0 0x06AD @end example -@end deffn + +Note that the second VID/PID pair passed to @command{adapter usb vid_pid} is +used to detect uninitialized devices. + +This driver has several commands, used for configuration before initializing the +JTAG scan chain: @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 @@ -2956,6 +3052,8 @@ image. To be used with USB-Blaster II only. @end deffn @deffn {Interface Driver} {gw16012} +@b{Note: This adapter is deprecated and support will be removed in the next release!} + Gateworks GW16012 JTAG programmer. This has one driver-specific command: @@ -3107,61 +3205,66 @@ version, and target voltage. @end deffn @deffn {Interface Driver} {parport} -Supports PC parallel port bit-banging cables: -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 -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: - -@itemize @minus -@item @b{altium} Altium Universal JTAG cable. -@item @b{arm-jtag} Same as original wiggler except SRST and -TRST connections reversed and TRST is also inverted. -@item @b{chameleon} The Amontec Chameleon's CPLD when operated -in configuration mode. This is only used to -program the Chameleon itself, not a connected target. -@item @b{dlc5} The Xilinx Parallel cable III. -@item @b{flashlink} The ST Parallel cable. -@item @b{lattice} Lattice ispDOWNLOAD Cable -@item @b{old_amt_wiggler} The Wiggler configuration that comes with -some versions of -Amontec's Chameleon Programmer. The new version available from -the website uses the original Wiggler layout ('@var{wiggler}') -@item @b{triton} The parallel port adapter found on the -``Karo Triton 1 Development Board''. -This is also the layout used by the HollyGates design -(see @uref{http://www.lartmaker.nl/projects/jtag/}). -@item @b{wiggler} The original Wiggler layout, also supported by -several clones, such as the Olimex ARM-JTAG -@item @b{wiggler2} Same as original wiggler except an led is fitted on D5. -@item @b{wiggler_ntrst_inverted} Same as original wiggler except TRST is inverted. -@end itemize +This driver supports PC parallel port bit-banging adapters. +Only JTAG is supported as transport protocol. +The driver supports Linux, FreeBSD, and Windows. +However, the Windows support is untested and unmaintained. + +The pin configuration is handled by the generic command @ref{adapter gpio, @command{adapter gpio}}. +In addition to the JTAG signals, the driver also supports the activity LED signal. + +The data and status pins of the parallel port are used as output and input pins, respectively. +The pin direction is given in the following table. + +@multitable @columnfractions .2 .1 .1 .1 .1 .1 .1 .1 .1 +@headitem Pin direction +@item Input +@tab ~11 +@tab 10 +@tab 12 +@tab 13 +@tab 15 +@tab - +@tab - +@tab - +@item Output +@tab 9 +@tab 8 +@tab 7 +@tab 6 +@tab 5 +@tab 4 +@tab 3 +@tab 2 +@end multitable + +@deffn {Config Command} {parport port} file +Specify the device file of the parallel port device. +The parallel port device file is usually @file{/dev/parportX} on Linux and @file{/dev/ppiX} on FreeBSD. + +For legacy reason, the port number @var{X} can be specified instead of the device file. +@b{Note:} Using the port number is a deprecated feature and will be removed in the future. + +When using direct I/O, the number is the I/O port number. +The default port number is 0x378 (LTP1). +@b{Note:} Direct I/O support is deprecated and will be removed in the future. @end deffn -@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. +@deffn {Config Command} {parport write_on_exit} (@option{on}|@option{off}) +@b{Note:} This command is deprecated and will be removed in the future. +Use the command @command{adapter gpio} to configure the pin states before the adapter terminates its operation. -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 -you may encounter a problem. +Configure whether the driver sets the value specified by @command{adapter gpio} to the output pins on shutdown. @end deffn -@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. -When the optional @var{nanoseconds} parameter is given, -that setting is changed before displaying the current value. +@deffn {Config Command} {parport toggling_time} time +Configure how many nanoseconds the hardware needs to toggle TCK. +The driver uses this value to obey the @command{adapter speed} configuration. The default setting should work reasonably well on commodity PC hardware. However, you may want to calibrate for your specific hardware. + @quotation Tip To measure the toggling time with a logic analyzer or a digital storage oscilloscope, follow the procedure below: @@ -3169,15 +3272,18 @@ oscilloscope, follow the procedure below: > parport toggling_time 1000 > adapter speed 500 @end example + This sets the maximum JTAG clock speed of the hardware, but the actual speed probably deviates from the requested 500 kHz. Now, measure the time between the two closest spaced TCK transitions. 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 @end example + Now the clock speed will be a better match for @command{adapter speed} command given in OpenOCD scripts and event handlers. @@ -3189,20 +3295,6 @@ match with the rate you specified in the @command{adapter speed} command; be conservative. @end quotation @end deffn - -@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 - -For example, the interface configuration file for a -classic ``Wiggler'' cable on LPT2 might look something like this: - -@example -adapter driver parport -parport port 0x278 -parport cable wiggler -@end example @end deffn @deffn {Interface Driver} {presto} @@ -3250,10 +3342,6 @@ Currently Not Supported. Specifies the adapter layout to use. @end deffn -@deffn {Config Command} {hla vid_pid} [vid pid]+ -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). @@ -3302,10 +3390,6 @@ 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. @@ -3374,9 +3458,26 @@ The string will be of the format "DDDD:BB:SS.F" such as "0000:65:00.1". @end deffn @end deffn +@deffn {Interface Driver} {xlnx_axi_xvc} +This driver supports the Xilinx JTAG mapping over AXI using the AXI to JTAG +Converter or the AXI-to-JTAG mode of the debug bridge. +It is commonly found in Xilinx MPSoC based designs. It allows debugging +fabric based JTAG/SWD devices such as Cortex-M1/M3 or RISC-V softcores. Access to this +is exposed via extended capability registers in the AXI-mapped configuration space. + +@deffn {Config Command} {xlnx_axi_xvc dev_addr} addr +Specifies the address of the AXI-mapped registers via parameter @var{addr}. + +The correct value for @var{addr} is specified in the "Address Editor" tab +in Vivado. +@end deffn +@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. +This GPIO interface is present in Raspberry Pi 0-4 which is a cheap +single-board computer exposing some GPIOs on its expansion header. + +@emph{Note:} for Raspberry Pi 5, use @b{linuxgpiod} not this driver. The driver accesses memory-mapped GPIO peripheral registers directly for maximum performance, but the only possible race condition is for @@ -3385,8 +3486,7 @@ 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}}. +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 @file{interface/raspberrypi-gpio-connector.cfg} for pinout. @@ -3415,9 +3515,7 @@ and drive strength is reduced to 4 mA (2 mA on RPi 4). @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}. +0x20000000. For RPi2 and RPi3, use 0x3F000000. For RPi4, use 0xFE000000. @end deffn @end deffn @@ -3554,20 +3652,6 @@ Currently valid @var{variant} values include: (see @uref{http://www.cypress.com/?rID=82870}). @end itemize @end deffn - -@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 @@ -3616,7 +3700,24 @@ 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. +Specifies the hostname or IP address of the SystemVerilog DPI server interface. +@end deffn +@end deffn + +@deffn {Interface Driver} {jtag_vpi} +A JTAG driver acting as a client for the JTAG VPI server interface. + +@deffn {Config Command} {jtag_vpi set_address} address +Specifies the hostname or IP address of the JTAG VPI server. +@end deffn + +@deffn {Config Command} {jtag_vpi set_port} port +Specifies the TCP/IP port number of the JTAG VPI server. +@end deffn + +@deffn {Config Command} {jtag_vpi stop_sim_on_exit} (@option{on}|@option{off}) +Specifies whether simulation stop command shall be sent before OpenOCD exits. +The default is @option{off}. @end deffn @end deffn @@ -3683,7 +3784,7 @@ buspirate led 1 @end deffn @deffn {Interface Driver} {esp_usb_jtag} -Espressif JTAG driver to communicate with ESP32-C3, ESP32-S3 chips and ESP USB Bridge board using OpenOCD. +Espressif JTAG driver to communicate with ESP32-C3, ESP32-C6, ESP32-H2 and 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. @@ -3698,13 +3799,6 @@ 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 @@ -3755,7 +3849,7 @@ 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 +See @file{tcl/board/ti/am625-self-hosted.cfg} for a sample configuration file. @deffn {Command} {dmem info} @@ -3792,6 +3886,34 @@ Set the emulated address and address window size. Both of these parameters must be aligned to page size. @end deffn +@deffn {Interface Driver} {xvc} +This driver implements bitbang mode of JTAG devices +using Xilinx Virtual Cable messages over TCP/IP. +This implementation is XVC protocol 1.0/1.1 compatible. However, 'mrd' and 'mwr' +extensions introduced in version 1.1 are not supported. Refer to: +@url{https://github.com/Xilinx/XilinxVirtualCable} for protocol specification. + +An implementation of XVC server to gpiod is available in +@url{https://pypi.org/project/xvc-gpiod} +and is suitable for testing this driver. + +Example configuration: + +@example +xvc host 192.168.3.192 +xvc port 5000 +@end example +@end deffn + +@deffn {Config Command} {xvc host} @var{hostname} +Specifies the hostname of the remote debugger or UNIX socket to connect to. +@end deffn + +@deffn {Config Command} {xvc port} @var{number} +Specifies the port of the remote process to connect to. +'0' is a special case where UNIX sockets are used. +@end deffn + @end deffn @section Transport Configuration @@ -5061,6 +5183,10 @@ 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{esp32c2} -- this is an Espressif SoC with single RISC-V core. +@item @code{esp32c3} -- this is an Espressif SoC with single RISC-V core. +@item @code{esp32c6} -- this is an Espressif SoC with single RISC-V core. +@item @code{esp32h2} -- this is an Espressif SoC with single RISC-V core. @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. @@ -5469,7 +5595,8 @@ Displays the current target state: @code{debug-running}, @code{halted}, @code{reset}, -@code{running}, or @code{unknown}. +@code{running}, +@code{unavailable} or @code{unknown}. (Also, @pxref{eventpolling,,Event Polling}.) @end deffn @@ -5528,6 +5655,20 @@ Otherwise, or if the optional @var{phys} flag is specified, If @var{count} is specified, fills that many units of consecutive address. @end deffn +@deffn {Command} {$target_name disassemble} address [count [instruction_set]] +@deffnx {Command} {$target_name disassemble} list +This command requires Capstone library installed. + +Disassembles @var{count} instructions starting at @var{address}. +If @var{count} is not specified, a single instruction is disassembled. + +It uses the target @var{$target_name} to read the instructions from memory, +then disassemble them using either the instruction set detected on the same +target or the one provided with @var{instruction_set}. + +With parameter @var{list} it dumps the list of supported instruction set. +@end deffn + @anchor{targetevents} @section Target Events @cindex target events @@ -5899,6 +6040,24 @@ 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 read_memory} address width count +This function provides an efficient way to read flash memory from a Tcl script. +A Tcl list containing the requested memory elements is returned by this function. + +@itemize +@item @var{address} ... flash memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{count} ... number of elements to read +@end itemize + +For example, the following command reads two 32 bit words from the flash +memory at address 0x08000000: + +@example +flash read_memory 0x08000000 32 2 +@end example +@end deffn + @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} @@ -6024,7 +6183,7 @@ Some drivers also activate driver-specific commands. 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. -The @var{virtual} driver defines one mandatory parameters, +The @var{virtual} driver defines one mandatory parameter, @itemize @item @var{master_bank} The bank that this virtual address refers to. @@ -6042,6 +6201,28 @@ flash bank vbank1 virtual 0x9fc00000 0 0 0 \ @end example @end deffn +@deffn {Flash Driver} ro_alias +Similar as @var{virtual} driver but suppresses write +and erase. Use to build a complete memory map for gdb. +Bank size will be copied from the master physical bank. + +The @var{virtual} driver defines one mandatory parameter, + +@itemize +@item @var{master_bank} The bank that this virtual address refers to. +@end itemize +@end deffn + +@deffn {Flash Driver} read_only +A stub driver without write and erase. +Use to define a ROM region for the gdb memory map. + +@example +flash bank $_CHIPNAME.sysrom read_only 0x1ff00000 0xedc0 0 0 \ + $_TARGETNAME +@end example +@end deffn + @subsection External Flash @deffn {Flash Driver} {cfi} @@ -6089,6 +6270,22 @@ flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME @c "cfi part_id" disabled @end deffn +@deffn {Flash Driver} {hpm_xpi} +All members of the HPMxxxx microcontroller family from HPMicro. +Additional parameters are required to configure the driver: @option{io_base} is +the base address of the configuration register interface, @option{opt0} and +@option{opt1} are the options for the flash. + +@example +flash bank $@{_FLASHNAME@}0 hpm_xpi base_address size_bytes 0 0 $_TARGETNAME \ + io_base opt0 opt1 +@end example + +@deffn {Command} {hpm_xpi mass_erase} bank_id +Erase all pages in data memory for the bank identified by @option{bank_id}. +@end deffn +@end deffn + @anchor{jtagspi} @deffn {Flash Driver} {jtagspi} @cindex Generic JTAG2SPI driver @@ -6592,6 +6789,50 @@ the flash. @end deffn @end deffn +@deffn {Flash Driver} {artery} +@cindex artery +This driver supports Artery Technology devices from the following series: + +@itemize +@item AT32F403A / AT32F407 +@item AT32F413 +@item AT32F415 +@item AT32F421 +@item AT32F423 +@item AT32F425 +@item AT32F435 / AT32F437 +@item AT32WB415 +@end itemize + +Devices with dual-bank flash memory are currently not supported. +Also, access to user data in the user system data (USD) area is not supported. + +The driver supports flash write protection and flash access protection (FAP). +For the FAP, only the low-level protection is implemented. + +@b{Note:} a change of the flash write protection or FAP requires a device reset for the changes to take effect. + +The @var{artery} driver provides the following additional commands: + +@deffn {Command} {artery fap enable} +Enable low-level flash access protection (FAP). +@end deffn + +@deffn {Command} {artery fap disable} +Disable flash access protection (FAP). +@end deffn + +@deffn {Command} {artery fap state} +Get the flash access protection (FAP) state. +The state is a boolean value that indicates whether the FAP is configured in level 'low' or higher. +@end deffn + +@deffn {Command} {artery mass_erase} +Erase entire bank. +@end deffn + +@end deffn + @deffn {Flash Driver} {at91samd} @cindex at91samd All members of the ATSAM D2x, D1x, D0x, ATSAMR, ATSAML and ATSAMC microcontroller @@ -6836,10 +7077,27 @@ 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}. +The same driver provides interface for PIC32CZ CA70 series. This +Cortex-M7 family from Microchip is both binary and pin to pin compatible +with Atmel's SAM series. The PIC series is a replacement of the original +SAM series from Atmel after the company acquisition by Microchip. + @example flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME @end example +These families also have a user signature area located at the beginning +of an embedded flash. This is a 512 bytes large page whose data are not +erased by assering ERASE pin or by software ERASE command. It can be +used to store configuration, keys, trimming values and so on. The area +overlaps with the beginning of standard flash and uses special commands +to perform write/read operations. OpenOCD locates the signature area +at fake address above 32 bit address space, specifically at 0x100000000. + +@example +flash bank $_SIGNATURENAME atsamv 0x100000000 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}, @@ -6924,6 +7182,34 @@ 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} {bl602} +Supports RISC-V chips Bouffalo Lab BL602, BL702 and BL702L series. +Both internal and external flashes are supported. The driver automatically +recognizes the specific version's flash parameters and autoconfigures itself. +Due to how the SFlash and XIP in those chips works, it is recommended to probe +the flash before usage, and reset the chip after work with flash is finished. + +This driver does not generate boot header which is required to have working +firmware. This header must be inside of ELF with proper Load Memory Address +and other parts of firmware must have proper LMA based on boot header configuration. + +The @var{bl602} driver needs following parameters, +which must appear in the following order: + +@itemize +@item @var{chip_type} ... required, may be +@option{bl602}, +@option{bl702}, +@option{bl702l} +@end itemize + +Example: + +@example +flash bank $_FLASHNAME bl602 0x23000000 0 0 0 $_TARGETNAME bl602 +@end example +@end deffn + @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 @@ -6951,25 +7237,25 @@ flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME @end deffn @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. +All members of the EFM32/EFR32 microcontroller family from Silicon Labs (former +Energy Micro) include internal flash and use Arm Cortex-M3, Cortex-M4 or +Cortex-M33 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 +flash bank $_FLASHNAME efm32 0x80000000 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. +past 512 bytes on chips with larger page sizes. The latter is used by the +Silicon Labs 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: +A special feature of Silicon Labs Series 0/1 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: @example efm32 debuglock num @end example @@ -8259,10 +8545,16 @@ data). This is the only way to unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). The @var{num} parameter is a value shown by @command{flash banks}. @end deffn + +@deffn {Command} {stm32lx option_load} num +Forces a re-load of the option byte registers. +This command will cause a system reset of the device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn @end deffn @deffn {Flash Driver} {stm32l4x} -All members of the STM32 C0, G0, G4, L4, L4+, L5, U0, U5, WB and WL +All members of the STM32 C0, G0, G4, L4, L4+, L5, U0, U5, WB, WBA and WL microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M0+, M4 and M33 cores. The driver automatically recognizes a number of these chips using @@ -8320,10 +8612,8 @@ is the register offset of the Option byte to read. For example to read the FLASH_OPTR register: @example -stm32l4x option_read 0 0x20 -# Option Register (for STM32L4x): <0x40022020> = 0xffeff8aa -# Option Register (for STM32WBx): <0x58004020> = ... -# The correct flash base address will be used automatically +> stm32l4x option_read 0 0x20 +0xffeff8aa @end example The above example will read out the FLASH_OPTR register which contains the RDP @@ -9262,7 +9552,12 @@ port is 6666. @section Server Commands @deffn {Command} {exit} -Exits the current telnet session. +Exits the current telnet or Tcl session but the OpenOCD process remains running. +This command should only be used in telnet or Tcl sessions (and not directly +in Tcl scripts). + +Note: To terminate the whole OpenOCD process, use the +@command{shutdown} command instead. @end deffn @deffn {Command} {help} [string] @@ -9312,16 +9607,18 @@ will proceed to quit. @end deffn @anchor{debuglevel} -@deffn {Command} {debug_level} [n] +@deffn {Command} {debug_level} [number] @cindex message level -Display debug level. -If @var{n} (from 0..4) is provided, then set it to that level. +Without arguments it displays the current debug level. +If @var{number} (from 0..4) is provided, then set it to that level. This affects the kind of messages sent to the server log. Level 0 is error messages only; level 1 adds warnings; level 2 adds informational messages; level 3 adds debugging messages; -and level 4 adds verbose low-level debug messages. +level 4 adds verbose low-level debug messages; +and level 5 adds USB communication messages +and amount of free heap space if mallinfo is available. The default is level 2, but that can be overridden on the command line along with the location of that log file (which is normally the server's standard output). @@ -9342,7 +9639,7 @@ Redirect logging to @var{filename}. If used without an argument or 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 @@ -9735,12 +10032,14 @@ 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 [asid] len [@option{hw} | @option{hw_ctx}]] With no parameters, lists all active breakpoints. Else sets a breakpoint on code execution starting at @var{address} for @var{length} bytes. -This is a software breakpoint, unless @option{hw} is specified -in which case it will be a hardware breakpoint. +This is a software breakpoint, unless @option{hw} or @option{hw_ctx} +is specified in which case it will be a hardware, context or hybrid breakpoint. +The context and hybrid breakpoints require an additional parameter @var{asid}: +address space identifier. (@xref{arm9vectorcatch,,arm9 vector_catch}, or @pxref{xscalevectorcatch,,xscale vector_catch}, for similar mechanisms that do not consume hardware breakpoints.) @@ -9877,11 +10176,11 @@ 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' +@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' +@deffn {Command} {add_usage_text} command_name help_string Add or replace usage text on the given @var{command_name}. @end deffn @@ -10223,24 +10522,6 @@ 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}]] -@cindex disassemble -Disassembles @var{count} instructions starting at @var{address}. -If @var{count} is not specified, a single instruction is disassembled. -If @option{thumb} is specified, or the low bit of the address is set, -Thumb2 (mixed 16/32-bit) instructions are used; -else ARM (32-bit) instructions are used. -(Processors may also support the Jazelle state, but -those instructions are not currently understood by OpenOCD.) - -Note that all Thumb instructions are Thumb2 instructions, -so older processors (without Thumb2 support) will still -see correct disassembly of Thumb code. -Also, ThumbEE opcodes are the same as Thumb2, -with a handful of exceptions. -ThumbEE disassembly currently has no explicit support. -@end deffn - @deffn {Command} {arm mcr} pX op1 CRn CRm op2 value Write @var{value} to a coprocessor @var{pX} register passing parameters @var{CRn}, @@ -10955,6 +11236,10 @@ Enable or disable trace output for all ITM stimulus ports. @subsection Cortex-M specific commands @cindex Cortex-M +@deffn {Command} {cortex_m cache_info} +Report information about the type and size of the cache, if present. +@end deffn + @deffn {Command} {cortex_m maskisr} (@option{auto}|@option{on}|@option{off}|@option{steponly}) Control masking (disabling) interrupts during target step/resume. @@ -11040,12 +11325,6 @@ 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 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 @@ -11645,7 +11924,7 @@ Display/set the current core displayed in GDB. This is needed only if @code{riscv smp} was used. @end deffn -@deffn {Command} {riscv use_bscan_tunnel} width [type] +@deffn {Config Command} {riscv use_bscan_tunnel} width [type] Enable or disable use of a BSCAN tunnel to reach the Debug Module. Supply the @var{width} of the DM transport TAP's instruction register to enable. The @var{width} should fit into 7 bits. Supply a value of 0 to disable. @@ -11669,7 +11948,7 @@ tunneled DR scan consists of: @end enumerate @end deffn -@deffn {Command} {riscv set_bscan_tunnel_ir} value +@deffn {Config Command} {riscv set_bscan_tunnel_ir} value Allows the use_bscan_tunnel feature to target non Xilinx device by specifying the JTAG TAP IR used to access the bscan tunnel. @end deffn @@ -12781,7 +13060,7 @@ If your device/vendor is not supported you have to use the first variant. @end deffn -@deffn {Command} {$hub_name ipdbg start} @option{-tool @var{number}} @option{-port @var{number}} +@deffn {Command} {$hub_name 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: @@ -12791,7 +13070,7 @@ Command options: @end itemize @end deffn -@deffn {Command} {$hub_name ipdbg stop} @option{-tool @var{number}} +@deffn {Command} {$hub_name stop} @option{-tool @var{number}} Stops a IPDBG JTAG-Host server. Command options: @itemize @bullet @@ -12802,21 +13081,21 @@ Command options: Examples: @example ipdbg create-hub xc6s.ipdbghub -tap xc6s.tap -hub 0x02 -xc6s.ipdbghub ipdbg start -port 4242 -tool 4 +xc6s.ipdbghub 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 +max10m50.ipdbghub 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 +xc7.ipdbghub 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. @@ -13221,14 +13500,6 @@ contrib/rtos-helpers/FreeRTOS-openocd.c contrib/rtos-helpers/uCOS-III-openocd.c @end table -@section RTOS Commands -@cindex RTOS Commands - -@deffn {Config Command} {freertos_ticktype_size} (2|4|8) -Pass the size (in bytes) of FreeRTOS TickType_t to OpenOCD. To make sure the -calculation of offsets and sizes is correct. Defaults to 4. -@end deffn - @anchor{usingopenocdsmpwithgdb} @section Using OpenOCD SMP with GDB @cindex SMP diff --git a/doc/usb_adapters/ch347/1a86_55dd_easydevkit.txt b/doc/usb_adapters/ch347/1a86_55dd_easydevkit.txt new file mode 100644 index 0000000000..9a0ae71edf --- /dev/null +++ b/doc/usb_adapters/ch347/1a86_55dd_easydevkit.txt @@ -0,0 +1,146 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Link: https://www.easydevkits.com +# PCB: ESP32-WROVER-E WCH JTAG DevKit v0.1 +# Chip: CH347T in mode 3 (UART+JTAG mode) +# Product id of 0x55dd is only valid if the chip is started in mode 3 +# These are the other product ids: mode 0 = 0x55da, mode 1 = 0x55db, mode 2 = 0x55dc +# The similar chip CH347F has no modes and always product id 0x55de + +Bus 001 Device 013: ID 1a86:55dd QinHeng Electronics EasyDevKit +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x1a86 QinHeng Electronics + idProduct 0x55dd + bcdDevice 4.41 + iManufacturer 1 EasyDevKits + iProduct 2 EasyDevKit + iSerial 3 ACBACJGAAB + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0062 + 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 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 Call Management: + bmCapabilities 0x00 + bDataInterface 1 + CDC ACM: + bmCapabilities 0x02 + line coding and serial state + CDC Union: + bMasterInterface 0 + bSlaveInterface 1 + 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 + 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 0x04 EP 4 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 0x84 EP 4 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 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 0x86 EP 6 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 255 Vendor Specific Class + bDeviceSubClass 0 + bDeviceProtocol 255 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/git-hooks/commit-msg b/git-hooks/commit-msg deleted file mode 100755 index 99d96cdd53..0000000000 --- a/git-hooks/commit-msg +++ /dev/null @@ -1,191 +0,0 @@ -#!/bin/sh -# From Gerrit Code Review 2.13.5 -# -# Part of Gerrit Code Review (https://www.gerritcodereview.com/) -# -# Copyright (C) 2009 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -unset GREP_OPTIONS - -CHANGE_ID_AFTER="Bug|Issue|Test|Feature|Fixes|Fixed" -MSG="$1" - -# Check for, and add if missing, a unique Change-Id -# -add_ChangeId() { - clean_message=`sed -e ' - /^diff --git .*/{ - s/// - q - } - /^Signed-off-by:/d - /^#/d - ' "$MSG" | git stripspace` - if test -z "$clean_message" - then - return - fi - - # Do not add Change-Id to temp commits - if echo "$clean_message" | head -1 | grep -q '^\(fixup\|squash\)!' - then - return - fi - - if test "false" = "`git config --bool --get gerrit.createChangeId`" - then - return - fi - - # Does Change-Id: already exist? if so, exit (no change). - if grep -i '^Change-Id:' "$MSG" >/dev/null - then - return - fi - - id=`_gen_ChangeId` - T="$MSG.tmp.$$" - AWK=awk - if [ -x /usr/xpg4/bin/awk ]; then - # Solaris AWK is just too broken - AWK=/usr/xpg4/bin/awk - fi - - # Get core.commentChar from git config or use default symbol - commentChar=`git config --get core.commentChar` - commentChar=${commentChar:-#} - - # How this works: - # - parse the commit message as (textLine+ blankLine*)* - # - assume textLine+ to be a footer until proven otherwise - # - exception: the first block is not footer (as it is the title) - # - read textLine+ into a variable - # - then count blankLines - # - once the next textLine appears, print textLine+ blankLine* as these - # aren't footer - # - in END, the last textLine+ block is available for footer parsing - $AWK ' - BEGIN { - # while we start with the assumption that textLine+ - # is a footer, the first block is not. - isFooter = 0 - footerComment = 0 - blankLines = 0 - } - - # Skip lines starting with commentChar without any spaces before it. - /^'"$commentChar"'/ { next } - - # Skip the line starting with the diff command and everything after it, - # up to the end of the file, assuming it is only patch data. - # If more than one line before the diff was empty, strip all but one. - /^diff --git / { - blankLines = 0 - while (getline) { } - next - } - - # Count blank lines outside footer comments - /^$/ && (footerComment == 0) { - blankLines++ - next - } - - # Catch footer comment - /^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) { - footerComment = 1 - } - - /]$/ && (footerComment == 1) { - footerComment = 2 - } - - # We have a non-blank line after blank lines. Handle this. - (blankLines > 0) { - print lines - for (i = 0; i < blankLines; i++) { - print "" - } - - lines = "" - blankLines = 0 - isFooter = 1 - footerComment = 0 - } - - # Detect that the current block is not the footer - (footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) { - isFooter = 0 - } - - { - # We need this information about the current last comment line - if (footerComment == 2) { - footerComment = 0 - } - if (lines != "") { - lines = lines "\n"; - } - lines = lines $0 - } - - # Footer handling: - # If the last block is considered a footer, splice in the Change-Id at the - # right place. - # Look for the right place to inject Change-Id by considering - # CHANGE_ID_AFTER. Keys listed in it (case insensitive) come first, - # then Change-Id, then everything else (eg. Signed-off-by:). - # - # Otherwise just print the last block, a new line and the Change-Id as a - # block of its own. - END { - unprinted = 1 - if (isFooter == 0) { - print lines "\n" - lines = "" - } - changeIdAfter = "^(" tolower("'"$CHANGE_ID_AFTER"'") "):" - numlines = split(lines, footer, "\n") - for (line = 1; line <= numlines; line++) { - if (unprinted && match(tolower(footer[line]), changeIdAfter) != 1) { - unprinted = 0 - print "Change-Id: I'"$id"'" - } - print footer[line] - } - if (unprinted) { - print "Change-Id: I'"$id"'" - } - }' "$MSG" > "$T" && mv "$T" "$MSG" || rm -f "$T" -} -_gen_ChangeIdInput() { - echo "tree `git write-tree`" - if parent=`git rev-parse "HEAD^0" 2>/dev/null` - then - echo "parent $parent" - fi - echo "author `git var GIT_AUTHOR_IDENT`" - echo "committer `git var GIT_COMMITTER_IDENT`" - echo - printf '%s' "$clean_message" -} -_gen_ChangeId() { - _gen_ChangeIdInput | - git hash-object -t commit --stdin -} - - -add_ChangeId diff --git a/git-hooks/pre-push b/git-hooks/pre-push deleted file mode 100755 index a7e126655e..0000000000 --- a/git-hooks/pre-push +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -./tools/checkpatch.sh diff --git a/src/flash/nand/arm_io.c b/src/flash/nand/arm_io.c index dd012e161a..8261c6386d 100644 --- a/src/flash/nand/arm_io.c +++ b/src/flash/nand/arm_io.c @@ -56,10 +56,8 @@ static int arm_code_to_working_area(struct target *target, target_buffer_set_u32_array(target, code_buf, code_size / 4, code); /* copy code to work area */ - retval = target_write_memory(target, (*area)->address, + return target_write_memory(target, (*area)->address, 4, code_size / 4, code_buf); - - return retval; } /** @@ -282,7 +280,5 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size) destroy_reg_param(®_params[2]); /* read from work area to the host's memory */ - retval = target_read_buffer(target, target_buf, size, data); - - return retval; + return target_read_buffer(target, target_buf, size, data); } diff --git a/src/flash/nand/at91sam9.c b/src/flash/nand/at91sam9.c index 41cb07bc90..acc9e36348 100644 --- a/src/flash/nand/at91sam9.c +++ b/src/flash/nand/at91sam9.c @@ -250,15 +250,12 @@ static int at91sam9_read_block_data(struct nand_device *nand, uint8_t *data, int { struct at91sam9_nand *info = nand->controller_priv; struct arm_nand_data *io = &info->io; - int status; if (!at91sam9_halted(nand->target, "read block")) return ERROR_NAND_OPERATION_FAILED; io->chunk_size = nand->page_size; - status = arm_nandread(io, data, size); - - return status; + return arm_nandread(io, data, size); } /** @@ -274,15 +271,12 @@ static int at91sam9_write_block_data(struct nand_device *nand, uint8_t *data, in { struct at91sam9_nand *info = nand->controller_priv; struct arm_nand_data *io = &info->io; - int status; if (!at91sam9_halted(nand->target, "write block")) return ERROR_NAND_OPERATION_FAILED; io->chunk_size = nand->page_size; - status = arm_nandwrite(io, data, size); - - return status; + return arm_nandwrite(io, data, size); } /** @@ -469,9 +463,7 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page, return retval; } - retval = nand_write_finish(nand); - - return retval; + return nand_write_finish(nand); } /** diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c index c5430aeb05..6fe8d4023a 100644 --- a/src/flash/nand/core.c +++ b/src/flash/nand/core.c @@ -21,7 +21,7 @@ void nand_device_add(struct nand_device *c) { if (nand_devices) { struct nand_device *p = nand_devices; - while (p && p->next) + while (p->next) p = p->next; p->next = c; } else @@ -310,16 +310,15 @@ int nand_probe(struct nand_device *nand) retval = nand->controller->init(nand); if (retval != ERROR_OK) { switch (retval) { - case ERROR_NAND_OPERATION_FAILED: - LOG_DEBUG("controller initialization failed"); - return ERROR_NAND_OPERATION_FAILED; - case ERROR_NAND_OPERATION_NOT_SUPPORTED: - LOG_ERROR( - "BUG: controller reported that it doesn't support default parameters"); - return ERROR_NAND_OPERATION_FAILED; - default: - LOG_ERROR("BUG: unknown controller initialization failure"); - return ERROR_NAND_OPERATION_FAILED; + case ERROR_NAND_OPERATION_FAILED: + LOG_DEBUG("controller initialization failed"); + return ERROR_NAND_OPERATION_FAILED; + case ERROR_NAND_OPERATION_NOT_SUPPORTED: + LOG_ERROR("BUG: controller reported that it doesn't support default parameters"); + return ERROR_NAND_OPERATION_FAILED; + default: + LOG_ERROR("BUG: unknown controller initialization failure"); + return ERROR_NAND_OPERATION_FAILED; } } @@ -450,18 +449,18 @@ int nand_probe(struct nand_device *nand) /* erase size */ if (nand->device->erase_size == 0) { switch ((id_buff[4] >> 4) & 3) { - case 0: - nand->erase_size = 64 << 10; - break; - case 1: - nand->erase_size = 128 << 10; - break; - case 2: - nand->erase_size = 256 << 10; - break; - case 3: - nand->erase_size = 512 << 10; - break; + case 0: + nand->erase_size = 64 << 10; + break; + case 1: + nand->erase_size = 128 << 10; + break; + case 2: + nand->erase_size = 256 << 10; + break; + case 3: + nand->erase_size = 512 << 10; + break; } } else nand->erase_size = nand->device->erase_size; @@ -470,19 +469,18 @@ int nand_probe(struct nand_device *nand) retval = nand->controller->init(nand); if (retval != ERROR_OK) { switch (retval) { - case ERROR_NAND_OPERATION_FAILED: - LOG_DEBUG("controller initialization failed"); - return ERROR_NAND_OPERATION_FAILED; - case ERROR_NAND_OPERATION_NOT_SUPPORTED: - LOG_ERROR( - "controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)", + case ERROR_NAND_OPERATION_FAILED: + LOG_DEBUG("controller initialization failed"); + return ERROR_NAND_OPERATION_FAILED; + case ERROR_NAND_OPERATION_NOT_SUPPORTED: + LOG_ERROR("controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)", nand->bus_width, nand->address_cycles, nand->page_size); - return ERROR_NAND_OPERATION_FAILED; - default: - LOG_ERROR("BUG: unknown controller initialization failure"); - return ERROR_NAND_OPERATION_FAILED; + return ERROR_NAND_OPERATION_FAILED; + default: + LOG_ERROR("BUG: unknown controller initialization failure"); + return ERROR_NAND_OPERATION_FAILED; } } diff --git a/src/flash/nand/davinci.c b/src/flash/nand/davinci.c index 17040fe172..d27b4c748c 100644 --- a/src/flash/nand/davinci.c +++ b/src/flash/nand/davinci.c @@ -256,17 +256,17 @@ static int davinci_write_page(struct nand_device *nand, uint32_t page, /* If we're not given OOB, write 0xff where we don't write ECC codes. */ switch (nand->page_size) { - case 512: - oob_size = 16; - break; - case 2048: - oob_size = 64; - break; - case 4096: - oob_size = 128; - break; - default: - return ERROR_NAND_OPERATION_FAILED; + case 512: + oob_size = 16; + break; + case 2048: + oob_size = 64; + break; + case 4096: + oob_size = 128; + break; + default: + return ERROR_NAND_OPERATION_FAILED; } if (!oob) { ooballoc = malloc(oob_size); @@ -391,15 +391,15 @@ static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page, * for 16-bit OOB, those extra bytes are discontiguous. */ switch (nand->page_size) { - case 512: - oob_offset = 0; - break; - case 2048: - oob_offset = 40; - break; - default: - oob_offset = 80; - break; + case 512: + oob_offset = 0; + break; + case 2048: + oob_offset = 40; + break; + default: + oob_offset = 80; + break; } davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); @@ -482,15 +482,15 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page, * the standard ECC logic can't handle. */ switch (nand->page_size) { - case 512: - l = ecc512; - break; - case 2048: - l = ecc2048; - break; - default: - l = ecc4096; - break; + case 512: + l = ecc512; + break; + case 2048: + l = ecc2048; + break; + default: + l = ecc4096; + break; } davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); @@ -741,19 +741,19 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command) info->read_page = nand_read_page_raw; switch (eccmode) { - case HWECC1: - /* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */ - info->write_page = davinci_write_page_ecc1; - break; - case HWECC4: - /* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */ - info->write_page = davinci_write_page_ecc4; - break; - case HWECC4_INFIX: - /* Same 4-bit ECC HW, with problematic page/ecc layout */ - info->read_page = davinci_read_page_ecc4infix; - info->write_page = davinci_write_page_ecc4infix; - break; + case HWECC1: + /* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */ + info->write_page = davinci_write_page_ecc1; + break; + case HWECC4: + /* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */ + info->write_page = davinci_write_page_ecc4; + break; + case HWECC4_INFIX: + /* Same 4-bit ECC HW, with problematic page/ecc layout */ + info->read_page = davinci_read_page_ecc4infix; + info->write_page = davinci_write_page_ecc4infix; + break; } return ERROR_OK; diff --git a/src/flash/nand/driver.c b/src/flash/nand/driver.c index 5d99102c85..eda033b5b7 100644 --- a/src/flash/nand/driver.c +++ b/src/flash/nand/driver.c @@ -10,30 +10,32 @@ #ifdef HAVE_CONFIG_H #include #endif + +#include #include "core.h" #include "driver.h" static struct nand_flash_controller *nand_flash_controllers[] = { - &nonce_nand_controller, + // Keep in alphabetic order the list of drivers + &at91sam9_nand_controller, &davinci_nand_controller, + &imx31_nand_flash_controller, &lpc3180_nand_controller, &lpc32xx_nand_controller, + &mxc_nand_flash_controller, + &nonce_nand_controller, + &nuc910_nand_controller, &orion_nand_controller, &s3c2410_nand_controller, &s3c2412_nand_controller, &s3c2440_nand_controller, &s3c2443_nand_controller, &s3c6400_nand_controller, - &mxc_nand_flash_controller, - &imx31_nand_flash_controller, - &at91sam9_nand_controller, - &nuc910_nand_controller, - NULL }; struct nand_flash_controller *nand_driver_find_by_name(const char *name) { - for (unsigned int i = 0; nand_flash_controllers[i]; i++) { + for (size_t i = 0; i < ARRAY_SIZE(nand_flash_controllers); i++) { struct nand_flash_controller *controller = nand_flash_controllers[i]; if (strcmp(name, controller->name) == 0) return controller; @@ -42,7 +44,7 @@ struct nand_flash_controller *nand_driver_find_by_name(const char *name) } int nand_driver_walk(nand_driver_walker_t f, void *x) { - for (unsigned int i = 0; nand_flash_controllers[i]; i++) { + for (size_t i = 0; i < ARRAY_SIZE(nand_flash_controllers); i++) { int retval = (*f)(nand_flash_controllers[i], x); if (retval != ERROR_OK) return retval; diff --git a/src/flash/nand/driver.h b/src/flash/nand/driver.h index 4e84f10fbd..d26e77c75b 100644 --- a/src/flash/nand/driver.h +++ b/src/flash/nand/driver.h @@ -89,6 +89,7 @@ typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void *); */ int nand_driver_walk(nand_driver_walker_t f, void *x); +// Keep in alphabetic order the list of drivers 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; diff --git a/src/flash/nand/lpc3180.c b/src/flash/nand/lpc3180.c index d221c34d9e..050c636645 100644 --- a/src/flash/nand/lpc3180.c +++ b/src/flash/nand/lpc3180.c @@ -88,7 +88,6 @@ static float lpc3180_cycle_time(struct nand_device *nand) int sysclk; int hclk; int hclk_pll; - float cycle; /* calculate timings */ @@ -119,9 +118,7 @@ static float lpc3180_cycle_time(struct nand_device *nand) LOG_DEBUG("LPC3180 HCLK currently clocked at %i kHz", hclk); - cycle = (1.0 / hclk) * 1000000.0; - - return cycle; + return (1.0 / hclk) * 1000000.0; } static int lpc3180_init(struct nand_device *nand) diff --git a/src/flash/nand/lpc32xx.c b/src/flash/nand/lpc32xx.c index c67f2aa303..132a579d33 100644 --- a/src/flash/nand/lpc32xx.c +++ b/src/flash/nand/lpc32xx.c @@ -121,7 +121,6 @@ static float lpc32xx_cycle_time(struct nand_device *nand) int sysclk; int hclk; int hclk_pll; - float cycle; int retval; /* calculate timings */ @@ -169,9 +168,7 @@ static float lpc32xx_cycle_time(struct nand_device *nand) LOG_DEBUG("LPC32xx HCLK currently clocked at %i kHz", hclk); - cycle = (1.0 / hclk) * 1000000.0; - - return cycle; + return (1.0 / hclk) * 1000000.0; } static int lpc32xx_init(struct nand_device *nand) diff --git a/src/flash/nand/mx3.c b/src/flash/nand/mx3.c index 86e94685b7..23c18947ba 100644 --- a/src/flash/nand/mx3.c +++ b/src/flash/nand/mx3.c @@ -256,23 +256,23 @@ static int imx31_command(struct nand_device *nand, uint8_t command) } switch (command) { - case NAND_CMD_READOOB: - command = NAND_CMD_READ0; - in_sram_address = MX3_NF_SPARE_BUFFER0; /* set read point for - * data_read() and - * read_block_data() to - * spare area in SRAM - * buffer */ - break; - case NAND_CMD_READ1: - command = NAND_CMD_READ0; - /* - * offset == one half of page size - */ - in_sram_address = MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1); - break; - default: - in_sram_address = MX3_NF_MAIN_BUFFER0; + case NAND_CMD_READOOB: + command = NAND_CMD_READ0; + in_sram_address = MX3_NF_SPARE_BUFFER0; /* set read point for + * data_read() and + * read_block_data() to + * spare area in SRAM + * buffer */ + break; + case NAND_CMD_READ1: + command = NAND_CMD_READ0; + /* + * offset == one half of page size + */ + in_sram_address = MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1); + break; + default: + in_sram_address = MX3_NF_MAIN_BUFFER0; } target_write_u16(target, MX3_NF_FCMD, command); @@ -291,20 +291,20 @@ static int imx31_command(struct nand_device *nand, uint8_t command) */ sign_of_sequental_byte_read = 0; switch (command) { - case NAND_CMD_READID: - mx3_nf_info->optype = MX3_NF_DATAOUT_NANDID; - mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; - break; - case NAND_CMD_STATUS: - mx3_nf_info->optype = MX3_NF_DATAOUT_NANDSTATUS; - mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; - break; - case NAND_CMD_READ0: - mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; - mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; - break; - default: - mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; + case NAND_CMD_READID: + mx3_nf_info->optype = MX3_NF_DATAOUT_NANDID; + mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; + break; + case NAND_CMD_STATUS: + mx3_nf_info->optype = MX3_NF_DATAOUT_NANDSTATUS; + mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; + break; + case NAND_CMD_READ0: + mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; + mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; + break; + default: + mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; } return ERROR_OK; } @@ -647,46 +647,46 @@ static int do_data_output(struct nand_device *nand) struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; switch (mx3_nf_info->fin) { - case MX3_NF_FIN_DATAOUT: - /* - * start data output operation (set MX3_NF_BIT_OP_DONE==0) - */ - target_write_u16 (target, MX3_NF_CFG2, - MX3_NF_BIT_DATAOUT_TYPE(mx3_nf_info->optype)); - { - int poll_result; - poll_result = poll_for_complete_op(target, "data output"); - if (poll_result != ERROR_OK) - return poll_result; + case MX3_NF_FIN_DATAOUT: + /* + * start data output operation (set MX3_NF_BIT_OP_DONE==0) + */ + target_write_u16 (target, MX3_NF_CFG2, + MX3_NF_BIT_DATAOUT_TYPE(mx3_nf_info->optype)); + { + int poll_result; + poll_result = poll_for_complete_op(target, "data output"); + if (poll_result != ERROR_OK) + return poll_result; + } + mx3_nf_info->fin = MX3_NF_FIN_NONE; + /* + * ECC stuff + */ + if (mx3_nf_info->optype == MX3_NF_DATAOUT_PAGE + && mx3_nf_info->flags.hw_ecc_enabled) { + uint16_t ecc_status; + target_read_u16 (target, MX3_NF_ECCSTATUS, &ecc_status); + switch (ecc_status & 0x000c) { + case 1 << 2: + LOG_DEBUG("main area read with 1 (correctable) error"); + break; + case 2 << 2: + LOG_DEBUG("main area read with more than 1 (incorrectable) error"); + return ERROR_NAND_OPERATION_FAILED; } - mx3_nf_info->fin = MX3_NF_FIN_NONE; - /* - * ECC stuff - */ - if ((mx3_nf_info->optype == MX3_NF_DATAOUT_PAGE) - && mx3_nf_info->flags.hw_ecc_enabled) { - uint16_t ecc_status; - target_read_u16 (target, MX3_NF_ECCSTATUS, &ecc_status); - switch (ecc_status & 0x000c) { - case 1 << 2: - LOG_DEBUG("main area read with 1 (correctable) error"); - break; - case 2 << 2: - LOG_DEBUG("main area read with more than 1 (incorrectable) error"); - return ERROR_NAND_OPERATION_FAILED; - } - switch (ecc_status & 0x0003) { - case 1: - LOG_DEBUG("spare area read with 1 (correctable) error"); - break; - case 2: - LOG_DEBUG("main area read with more than 1 (incorrectable) error"); - return ERROR_NAND_OPERATION_FAILED; - } + switch (ecc_status & 0x0003) { + case 1: + LOG_DEBUG("spare area read with 1 (correctable) error"); + break; + case 2: + LOG_DEBUG("main area read with more than 1 (incorrectable) error"); + return ERROR_NAND_OPERATION_FAILED; } - break; - case MX3_NF_FIN_NONE: - break; + } + break; + case MX3_NF_FIN_NONE: + break; } return ERROR_OK; } diff --git a/src/flash/nand/mxc.c b/src/flash/nand/mxc.c index 845a3bb9a6..f37468f8dc 100644 --- a/src/flash/nand/mxc.c +++ b/src/flash/nand/mxc.c @@ -338,26 +338,26 @@ static int mxc_command(struct nand_device *nand, uint8_t command) return validate_target_result; switch (command) { - case NAND_CMD_READOOB: - command = NAND_CMD_READ0; - /* set read point for data_read() and read_block_data() to - * spare area in SRAM buffer - */ - if (nfc_is_v1()) - in_sram_address = MXC_NF_V1_SPARE_BUFFER0; - else - in_sram_address = MXC_NF_V2_SPARE_BUFFER0; - break; - case NAND_CMD_READ1: - command = NAND_CMD_READ0; - /* - * offset == one half of page size - */ - in_sram_address = MXC_NF_MAIN_BUFFER0 + (nand->page_size >> 1); - break; - default: - in_sram_address = MXC_NF_MAIN_BUFFER0; - break; + case NAND_CMD_READOOB: + command = NAND_CMD_READ0; + /* set read point for data_read() and read_block_data() to + * spare area in SRAM buffer + */ + if (nfc_is_v1()) + in_sram_address = MXC_NF_V1_SPARE_BUFFER0; + else + in_sram_address = MXC_NF_V2_SPARE_BUFFER0; + break; + case NAND_CMD_READ1: + command = NAND_CMD_READ0; + /* + * offset == one half of page size + */ + in_sram_address = MXC_NF_MAIN_BUFFER0 + (nand->page_size >> 1); + break; + default: + in_sram_address = MXC_NF_MAIN_BUFFER0; + break; } target_write_u16(target, MXC_NF_FCMD, command); @@ -374,24 +374,24 @@ static int mxc_command(struct nand_device *nand, uint8_t command) sign_of_sequental_byte_read = 0; /* Handle special read command and adjust NF_CFG2(FDO) */ switch (command) { - case NAND_CMD_READID: - mxc_nf_info->optype = MXC_NF_DATAOUT_NANDID; - mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; - break; - case NAND_CMD_STATUS: - mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS; - mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; - target_write_u16 (target, MXC_NF_BUFADDR, 0); - in_sram_address = 0; - break; - case NAND_CMD_READ0: - mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; - mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; - break; - default: - /* Other command use the default 'One page data out' FDO */ - mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; - break; + case NAND_CMD_READID: + mxc_nf_info->optype = MXC_NF_DATAOUT_NANDID; + mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; + break; + case NAND_CMD_STATUS: + mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS; + mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; + target_write_u16 (target, MXC_NF_BUFADDR, 0); + in_sram_address = 0; + break; + case NAND_CMD_READ0: + mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; + mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; + break; + default: + /* Other command use the default 'One page data out' FDO */ + mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; + break; } return ERROR_OK; } @@ -857,20 +857,20 @@ static int ecc_status_v1(struct nand_device *nand) target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status); switch (ecc_status & 0x000c) { - case 1 << 2: - LOG_INFO("main area read with 1 (correctable) error"); - break; - case 2 << 2: - LOG_INFO("main area read with more than 1 (incorrectable) error"); - return ERROR_NAND_OPERATION_FAILED; + case 1 << 2: + LOG_INFO("main area read with 1 (correctable) error"); + break; + case 2 << 2: + LOG_INFO("main area read with more than 1 (incorrectable) error"); + return ERROR_NAND_OPERATION_FAILED; } switch (ecc_status & 0x0003) { - case 1: - LOG_INFO("spare area read with 1 (correctable) error"); - break; - case 2: - LOG_INFO("main area read with more than 1 (incorrectable) error"); - return ERROR_NAND_OPERATION_FAILED; + case 1: + LOG_INFO("spare area read with 1 (correctable) error"); + break; + case 2: + LOG_INFO("main area read with more than 1 (incorrectable) error"); + return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } @@ -904,31 +904,31 @@ static int do_data_output(struct nand_device *nand) struct target *target = nand->target; int poll_result; switch (mxc_nf_info->fin) { - case MXC_NF_FIN_DATAOUT: - /* - * start data output operation (set MXC_NF_BIT_OP_DONE==0) - */ - target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_DATAOUT_TYPE(mxc_nf_info->optype)); - poll_result = poll_for_complete_op(nand, "data output"); - if (poll_result != ERROR_OK) - return poll_result; + case MXC_NF_FIN_DATAOUT: + /* + * start data output operation (set MXC_NF_BIT_OP_DONE==0) + */ + target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_DATAOUT_TYPE(mxc_nf_info->optype)); + poll_result = poll_for_complete_op(nand, "data output"); + if (poll_result != ERROR_OK) + return poll_result; - mxc_nf_info->fin = MXC_NF_FIN_NONE; - /* - * ECC stuff - */ - if (mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE && mxc_nf_info->flags.hw_ecc_enabled) { - int ecc_status; - if (nfc_is_v1()) - ecc_status = ecc_status_v1(nand); - else - ecc_status = ecc_status_v2(nand); - if (ecc_status != ERROR_OK) - return ecc_status; - } - break; - case MXC_NF_FIN_NONE: - break; + mxc_nf_info->fin = MXC_NF_FIN_NONE; + /* + * ECC stuff + */ + if (mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE && mxc_nf_info->flags.hw_ecc_enabled) { + int ecc_status; + if (nfc_is_v1()) + ecc_status = ecc_status_v1(nand); + else + ecc_status = ecc_status_v2(nand); + if (ecc_status != ERROR_OK) + return ecc_status; + } + break; + case MXC_NF_FIN_NONE: + break; } return ERROR_OK; } diff --git a/src/flash/nand/tcl.c b/src/flash/nand/tcl.c index 67a62770fb..0d6686d007 100644 --- a/src/flash/nand/tcl.c +++ b/src/flash/nand/tcl.c @@ -50,21 +50,22 @@ COMMAND_HANDLER(handle_nand_info_command) int last = -1; switch (CMD_ARGC) { - default: - return ERROR_COMMAND_SYNTAX_ERROR; - case 1: - first = 0; - last = INT32_MAX; - break; - case 2: - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], i); - first = last = i; - i = 0; - break; - case 3: - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last); - break; + case 1: + first = 0; + last = INT32_MAX; + break; + case 2: + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], i); + first = i; + last = i; + i = 0; + break; + case 3: + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } struct nand_device *p; diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 7a81b282b6..5c4737f7ac 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -12,6 +12,7 @@ NOR_DRIVERS = \ %D%/aduc702x.c \ %D%/aducm360.c \ %D%/ambiqmicro.c \ + %D%/artery.c \ %D%/at91sam4.c \ %D%/at91sam4l.c \ %D%/at91samd.c \ @@ -21,6 +22,7 @@ NOR_DRIVERS = \ %D%/atsamv.c \ %D%/atsame5.c \ %D%/avrf.c \ + %D%/bl602.c \ %D%/bluenrg-x.c \ %D%/cc3220sf.c \ %D%/cc26xx.c \ @@ -58,6 +60,7 @@ NOR_DRIVERS = \ %D%/psoc5lp.c \ %D%/psoc6.c \ %D%/qn908x.c \ + %D%/read_only.c \ %D%/renesas_rpchf.c \ %D%/rp2xxx.c \ %D%/rsl10.c \ @@ -82,9 +85,11 @@ NOR_DRIVERS = \ %D%/w600.c \ %D%/xcf.c \ %D%/xmc1xxx.c \ - %D%/xmc4xxx.c + %D%/xmc4xxx.c \ + %D%/hpm_xpi.c NORHEADERS = \ + %D%/artery.h \ %D%/core.h \ %D%/cc3220sf.h \ %D%/bluenrg-x.h \ diff --git a/src/flash/nor/aducm360.c b/src/flash/nor/aducm360.c index aa573acded..a5fd2cd249 100644 --- a/src/flash/nor/aducm360.c +++ b/src/flash/nor/aducm360.c @@ -440,7 +440,6 @@ static int aducm360_write_modified(struct flash_bank *bank, uint32_t count) { uint32_t value; - int res = ERROR_OK; uint32_t i, j, a, d; struct target *target = bank->target; @@ -464,7 +463,7 @@ static int aducm360_write_modified(struct flash_bank *bank, } aducm360_set_write_enable(target, 0); - return res; + return ERROR_OK; } /* ----------------------------------------------------------------------- */ diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c index bb893778ce..cb9fa5ed77 100644 --- a/src/flash/nor/ambiqmicro.c +++ b/src/flash/nor/ambiqmicro.c @@ -190,37 +190,36 @@ static int ambiqmicro_read_part_info(struct flash_bank *bank) ambiqmicro_info->target_class = (part_num & 0xFF000000) >> 24; switch (ambiqmicro_info->target_class) { - case 1: /* 1 - Apollo */ - case 5: /* 5 - Apollo Bootloader */ - bank->base = bank->bank_number * 0x40000; - ambiqmicro_info->pagesize = 2048; - ambiqmicro_info->flshsiz = + case 1: /* 1 - Apollo */ + case 5: /* 5 - Apollo Bootloader */ + bank->base = bank->bank_number * 0x40000; + ambiqmicro_info->pagesize = 2048; + ambiqmicro_info->flshsiz = apollo_flash_size[(part_num & 0x00F00000) >> 20]; - ambiqmicro_info->sramsiz = + ambiqmicro_info->sramsiz = apollo_sram_size[(part_num & 0x000F0000) >> 16]; - ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz / - ambiqmicro_info->pagesize; - if (ambiqmicro_info->num_pages > 128) { - ambiqmicro_info->num_pages = 128; - ambiqmicro_info->flshsiz = 1024 * 256; - } - break; + ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz / + ambiqmicro_info->pagesize; + if (ambiqmicro_info->num_pages > 128) { + ambiqmicro_info->num_pages = 128; + ambiqmicro_info->flshsiz = 1024 * 256; + } + break; - default: - LOG_INFO("Unknown Class. Using Apollo-64 as default."); + default: + LOG_INFO("Unknown Class. Using Apollo-64 as default."); - bank->base = bank->bank_number * 0x40000; - ambiqmicro_info->pagesize = 2048; - ambiqmicro_info->flshsiz = apollo_flash_size[1]; - ambiqmicro_info->sramsiz = apollo_sram_size[0]; - ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz / + bank->base = bank->bank_number * 0x40000; + ambiqmicro_info->pagesize = 2048; + ambiqmicro_info->flshsiz = apollo_flash_size[1]; + ambiqmicro_info->sramsiz = apollo_sram_size[0]; + ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz / ambiqmicro_info->pagesize; - if (ambiqmicro_info->num_pages > 128) { - ambiqmicro_info->num_pages = 128; - ambiqmicro_info->flshsiz = 1024 * 256; - } - break; - + if (ambiqmicro_info->num_pages > 128) { + ambiqmicro_info->num_pages = 128; + ambiqmicro_info->flshsiz = 1024 * 256; + } + break; } if (ambiqmicro_info->target_class < ARRAY_SIZE(ambiqmicro_parts)) @@ -309,9 +308,9 @@ static int ambiqmicro_exec_command(struct target *target, */ target_poll(target); alive_sleep(100); - LOG_DEBUG("state = %d", target->state); } else { - LOG_ERROR("Target not halted or running %d", target->state); + LOG_ERROR("Target not halted or running (state is %s)", + target_state_name(target)); break; } } diff --git a/src/flash/nor/artery.c b/src/flash/nor/artery.c new file mode 100644 index 0000000000..797d60de51 --- /dev/null +++ b/src/flash/nor/artery.c @@ -0,0 +1,2608 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2023 by Marc Schink + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include +#include +#include +#include +#include + +#include "artery.h" + +// Flash timeout values in milliseconds. +#define FLASH_MASS_ERASE_TIMEOUT 2400 +#define FLASH_ERASE_TIMEOUT 500 +#define FLASH_WRITE_TIMEOUT 5 +#define HICK_STABLE_TIMEOUT 1000 + +/* + * Flash memory register assignment for the following device series: + * - AT32F403A / AT32F407 + * - AT32F413 + * - AT32F415 + * - AT32F421 + * - AT32F423 + * - AT32F425 + * - AT32WB415 + */ +static const uint32_t flash_regs_f4xx_wb415[ARTERY_FLASH_REG_INDEX_NUM] = { + [ARTERY_FLASH_REG_PSR] = 0x00, + [ARTERY_FLASH_REG_UNLOCK] = 0x04, + [ARTERY_FLASH_REG_USD_UNLOCK] = 0x08, + [ARTERY_FLASH_REG_STS] = 0x0c, + [ARTERY_FLASH_REG_CTRL] = 0x10, + [ARTERY_FLASH_REG_ADDR] = 0x14, + [ARTERY_FLASH_REG_USD] = 0x1c, + [ARTERY_FLASH_REG_EPPS0] = 0x20, + // [ARTERY_FLASH_REG_EPPS1] not available. +}; + +// Flash memory register assignment for the AT32F435 / AT32F437 series. +static const uint32_t flash_regs_f435_f437[ARTERY_FLASH_REG_INDEX_NUM] = { + [ARTERY_FLASH_REG_PSR] = 0x00, + [ARTERY_FLASH_REG_UNLOCK] = 0x04, + [ARTERY_FLASH_REG_USD_UNLOCK] = 0x08, + [ARTERY_FLASH_REG_STS] = 0x0c, + [ARTERY_FLASH_REG_CTRL] = 0x10, + [ARTERY_FLASH_REG_ADDR] = 0x14, + [ARTERY_FLASH_REG_USD] = 0x1c, + [ARTERY_FLASH_REG_EPPS0] = 0x20, + [ARTERY_FLASH_REG_EPPS1] = 0x2c, +}; + +/* + * User system data (USD) offsets for the following device series: + * - AT32F415 + * - AT32F421 + * - AT32F423 + * - AT32F425 + * - AT32WB415 + */ +static const uint32_t usd_offsets_f4xx_wb415[ARTERY_USD_INDEX_NUM] = { + [ARTERY_USD_FAP_INDEX] = 0x00, + [ARTERY_USD_SSB_INDEX] = 0x02, + [ARTERY_USD_DATA_INDEX] = 0x04, + [ARTERY_USD_EPP_INDEX] = 0x08, + // [ARTERY_USD_EPP_EXT_INDEX] not available. + [ARTERY_USD_DATA_EXT_INDEX] = 0x10, +}; + +// User system data (USD) offsets for the AT32F403A / AT32F407 / AT32F413 series. +static const uint32_t usd_offsets_f403a_f407_f413[ARTERY_USD_INDEX_NUM] = { + [ARTERY_USD_FAP_INDEX] = 0x00, + [ARTERY_USD_SSB_INDEX] = 0x02, + [ARTERY_USD_DATA_INDEX] = 0x04, + [ARTERY_USD_EPP_INDEX] = 0x08, + // [ARTERY_USD_EPP_EXT_INDEX] not available. + [ARTERY_USD_DATA_EXT_INDEX] = 0x14, +}; + +// User system data (USD) offsets for the AT32F435 / AT32F437 series. +static const uint32_t usd_offsets_f435_f437[ARTERY_USD_INDEX_NUM] = { + [ARTERY_USD_FAP_INDEX] = 0x00, + [ARTERY_USD_SSB_INDEX] = 0x02, + [ARTERY_USD_DATA_INDEX] = 0x04, + [ARTERY_USD_EPP_INDEX] = 0x08, + [ARTERY_USD_EPP_EXT_INDEX] = 0x14, + [ARTERY_USD_DATA_EXT_INDEX] = 0x4c, +}; + +static const struct artery_series_info artery_series[] = { + [ARTERY_SERIES_F403A_F407] = { + .has_fap_high_level = false, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f403a_f407_f413, + }, + [ARTERY_SERIES_F413] = { + .has_fap_high_level = false, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f403a_f407_f413, + }, + [ARTERY_SERIES_F415] = { + .has_fap_high_level = true, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f4xx_wb415, + }, + [ARTERY_SERIES_F421] = { + .has_fap_high_level = true, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f4xx_wb415, + }, + [ARTERY_SERIES_F423] = { + .has_fap_high_level = true, + .has_epp_ext = false, + .flash_regs_base = 0x40023C00, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40023800, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f4xx_wb415, + }, + [ARTERY_SERIES_F425] = { + .has_fap_high_level = true, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f4xx_wb415, + }, + [ARTERY_SERIES_F435_F437] = { + .has_fap_high_level = false, + .has_epp_ext = true, + .flash_regs_base = 0x40023C00, + .flash_regs = flash_regs_f435_f437, + .crm_base = 0x40023800, + .usd_base = 0x1FFFC000, + .usd_offsets = usd_offsets_f435_f437, + }, + [ARTERY_SERIES_WB415] = { + .has_fap_high_level = true, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f4xx_wb415, + }, +}; + +static const struct artery_part_info artery_parts[] = { + { + .pid = 0x70050240, + .name = "AT32F403AVCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70050241, + .name = "AT32F403ARCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70050242, + .name = "AT32F403ACCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70050243, + .name = "AT32F403ACCU7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70050249, + .name = "AT32F407VCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x7005024a, + .name = "AT32F407RCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502cd, + .name = "AT32F403AVET7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502ce, + .name = "AT32F403ARET7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502cf, + .name = "AT32F403ACET7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502d0, + .name = "AT32F403ACEU7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502d1, + .name = "AT32F407VET7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502d2, + .name = "AT32F407RET7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70050254, + .name = "AT32F407AVCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030240, + .name = "AT32F413RCT7", + .series = ARTERY_SERIES_F413, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700301c1, + .name = "AT32F413RBT7", + .series = ARTERY_SERIES_F413, + .flash_size = 128, + .page_size = 1024, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030242, + .name = "AT32F413CCT7", + .series = ARTERY_SERIES_F413, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700301c3, + .name = "AT32F413CBT7", + .series = ARTERY_SERIES_F413, + .flash_size = 128, + .page_size = 1024, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030244, + .name = "AT32F413KCU7-4", + .series = ARTERY_SERIES_F413, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700301c5, + .name = "AT32F413KBU7-4", + .series = ARTERY_SERIES_F413, + .flash_size = 128, + .page_size = 1024, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030106, + .name = "AT32F413C8T7", + .series = ARTERY_SERIES_F413, + .flash_size = 64, + .page_size = 1024, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030247, + .name = "AT32F413CCU7", + .series = ARTERY_SERIES_F413, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700301ca, + .name = "AT32F413CBU7", + .series = ARTERY_SERIES_F413, + .flash_size = 128, + .page_size = 1024, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030240, + .name = "AT32F415RCT7", + .series = ARTERY_SERIES_F415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x70030241, + .name = "AT32F415CCT7", + .series = ARTERY_SERIES_F415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x70030242, + .name = "AT32F415KCU7-4", + .series = ARTERY_SERIES_F415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x70030243, + .name = "AT32F415RCT7-7", + .series = ARTERY_SERIES_F415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x700301c4, + .name = "AT32F415RBT7", + .series = ARTERY_SERIES_F415, + .flash_size = 128, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x700301c5, + .name = "AT32F415CBT7", + .series = ARTERY_SERIES_F415, + .flash_size = 128, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x700301c6, + .name = "AT32F415KBU7-4", + .series = ARTERY_SERIES_F415, + .flash_size = 128, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x700301c7, + .name = "AT32F415RBT7-7", + .series = ARTERY_SERIES_F415, + .flash_size = 128, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x70030108, + .name = "AT32F415R8T7", + .series = ARTERY_SERIES_F415, + .flash_size = 64, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x70030109, + .name = "AT32F415C8T7", + .series = ARTERY_SERIES_F415, + .flash_size = 64, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x7003010a, + .name = "AT32F415K8U7-4", + .series = ARTERY_SERIES_F415, + .flash_size = 64, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x7003024c, + .name = "AT32F415CCU7", + .series = ARTERY_SERIES_F415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x700301cd, + .name = "AT32F415CBU7", + .series = ARTERY_SERIES_F415, + .flash_size = 128, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x50020100, + .name = "AT32F421C8T7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020101, + .name = "AT32F421K8T7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020102, + .name = "AT32F421K8U7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020103, + .name = "AT32F421K8U7-4", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020104, + .name = "AT32F421F8U7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020105, + .name = "AT32F421F8P7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020086, + .name = "AT32F421C6T7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020087, + .name = "AT32F421K6T7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020088, + .name = "AT32F421K6U7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020089, + .name = "AT32F421K6U7-4", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5002008a, + .name = "AT32F421F6U7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5002008b, + .name = "AT32F421F6P7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5001000c, + .name = "AT32F421C4T7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5001000d, + .name = "AT32F421K4T7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5001000e, + .name = "AT32F421K4U7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5001000f, + .name = "AT32F421K4U7-4", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50010010, + .name = "AT32F421F4U7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50010011, + .name = "AT32F421F4P7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020112, + .name = "AT32F421G8U7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020093, + .name = "AT32F421G6U7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50010014, + .name = "AT32F421G4U7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3240, + .name = "AT32F423VCT7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21c1, + .name = "AT32F423VBT7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70032102, + .name = "AT32F423V8T7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3243, + .name = "AT32F423RCT7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21c4, + .name = "AT32F423RBT7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70032105, + .name = "AT32F423R8T7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3246, + .name = "AT32F423RCT7-7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21c7, + .name = "AT32F423RBT7-7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70032108, + .name = "AT32F423R8T7-7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3249, + .name = "AT32F423CCT7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21ca, + .name = "AT32F423CBT7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x7003210b, + .name = "AT32F423C8T7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a324c, + .name = "AT32F423CCU7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21cd, + .name = "AT32F423CBU7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x7003210e, + .name = "AT32F423C8U7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3250, + .name = "AT32F423TCU7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21d1, + .name = "AT32F423TBU7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70032112, + .name = "AT32F423T8U7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3253, + .name = "AT32F423KCU7-4", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21d4, + .name = "AT32F423KBU7-4", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70032115, + .name = "AT32F423K8U7-4", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092100, + .name = "AT32F425R8T7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092081, + .name = "AT32F425R6T7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092103, + .name = "AT32F425R8T7-7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092084, + .name = "AT32F425R6T7-7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092106, + .name = "AT32F425C8T7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092087, + .name = "AT32F425C6T7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092109, + .name = "AT32F425C8U7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5009208a, + .name = "AT32F425C6U7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5009210c, + .name = "AT32F425K8T7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5009208d, + .name = "AT32F425K6T7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5009210f, + .name = "AT32F425K8U7-4", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092090, + .name = "AT32F425K6U7-4", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092112, + .name = "AT32F425F8P7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092093, + .name = "AT32F425F6P7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70084598, + .name = "AT32F435ZDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083242, + .name = "AT32F435ZCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x70084599, + .name = "AT32F435VDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083245, + .name = "AT32F435VCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459a, + .name = "AT32F435RDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083248, + .name = "AT32F435RCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459b, + .name = "AT32F435CDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x7008324b, + .name = "AT32F435CCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459c, + .name = "AT32F435CDU7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x7008324e, + .name = "AT32F435CCU7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459d, + .name = "AT32F437ZDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083251, + .name = "AT32F437ZCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459e, + .name = "AT32F437VDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083254, + .name = "AT32F437VCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459f, + .name = "AT32F437RDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083257, + .name = "AT32F437RCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x70030250, + .name = "AT32WB415CCU7-7", + .series = ARTERY_SERIES_WB415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, +}; + +/* flash bank artery 0 0 */ +FLASH_BANK_COMMAND_HANDLER(artery_flash_bank_command) +{ + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct artery_flash_bank *artery_info = calloc(1, + sizeof(struct artery_flash_bank)); + + if (!artery_info) + return ERROR_FAIL; + + bank->driver_priv = artery_info; + artery_info->probed = false; + + return ERROR_OK; +} + +static int artery_read_flash_register(struct flash_bank *bank, + enum artery_flash_reg_index reg, uint32_t *value) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const struct artery_series_info *series_info = &artery_series[part_info->series]; + uint32_t reg_addr = series_info->flash_regs_base + series_info->flash_regs[reg]; + + return target_read_u32(bank->target, reg_addr, value); +} + +static int artery_write_flash_register(struct flash_bank *bank, + enum artery_flash_reg_index reg, uint32_t value) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const struct artery_series_info *series_info = &artery_series[part_info->series]; + uint32_t reg_addr = series_info->flash_regs_base + series_info->flash_regs[reg]; + + return target_write_u32(bank->target, reg_addr, value); +} + +static int artery_wait_flash_busy(struct flash_bank *bank, unsigned int timeout) +{ + const int64_t start_time = timeval_ms(); + + while (true) { + uint32_t status; + int retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_STS, + &status); + + if (retval != ERROR_OK) + return retval; + + if (!(status & FLASH_STS_OBF)) + break; + + if ((timeval_ms() - start_time) > timeout) { + LOG_ERROR("Timed out waiting for flash"); + return ERROR_FAIL; + } + + keep_alive(); + } + + return ERROR_OK; +} + +static int artery_enable_hiclk(struct flash_bank *bank) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const struct artery_series_info *series_info = &artery_series[part_info->series]; + uint32_t crm_base = series_info->crm_base; + struct target *target = bank->target; + + uint32_t crm_ctrl; + int ret = target_read_u32(target, crm_base + CRM_REG_CTRL, &crm_ctrl); + + if (ret != ERROR_OK) + return ret; + + // High speed internal clock (HICK) is already enabled and ready. + if (crm_ctrl & CRM_CTRL_HICKSTBL) + return ERROR_OK; + + crm_ctrl |= CRM_CTRL_HICKEN; + ret = target_write_u32(target, crm_base + CRM_REG_CTRL, crm_ctrl); + + if (ret != ERROR_OK) + return ret; + + const int64_t start_time = timeval_ms(); + + while (true) { + ret = target_read_u32(target, crm_base + CRM_REG_CTRL, &crm_ctrl); + + if (ret != ERROR_OK) + return ret; + + if (crm_ctrl & CRM_CTRL_HICKSTBL) + break; + + if ((timeval_ms() - start_time) > HICK_STABLE_TIMEOUT) { + LOG_ERROR("Timed out waiting for flash"); + return ERROR_FAIL; + } + + keep_alive(); + } + + return ERROR_OK; +} + +static int artery_usd_unlock(struct flash_bank *bank) +{ + uint32_t ctrl; + int retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_CTRL_USDULKS) + return ERROR_OK; + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_USD_UNLOCK, KEY1); + + if (retval != ERROR_OK) + return retval; + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_USD_UNLOCK, KEY2); + + if (retval != ERROR_OK) + return retval; + + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (!(ctrl & FLASH_CTRL_USDULKS)) { + LOG_ERROR("Failed to unlock user system data"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int artery_usd_lock(struct flash_bank *bank) +{ + uint32_t ctrl; + + int retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (!(ctrl & FLASH_CTRL_USDULKS)) + return ERROR_OK; + + ctrl &= ~FLASH_CTRL_USDULKS; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) + return retval; + + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_CTRL_USDULKS) { + LOG_ERROR("Failed to lock user system data"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +// Initialize the device for flash memory operations. +static int artery_init_flash(struct flash_bank *bank) +{ + /* + * The internal high speed clock (HICK) must be enabled before any flash + * operation is performed. + */ + int retval = artery_enable_hiclk(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to enable HICLK"); + return retval; + } + + uint32_t ctrl; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (!(ctrl & FLASH_CTRL_OPLK)) + return ERROR_OK; + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_UNLOCK, KEY1); + + if (retval != ERROR_OK) + return retval; + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_UNLOCK, KEY2); + + if (retval != ERROR_OK) + return retval; + + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_CTRL_OPLK) { + LOG_ERROR("Failed to initialize flash memory"); + return ERROR_FAIL; + } + + return artery_usd_unlock(bank); +} + +// Deinitialize the flash memory controller. +static int artery_deinit_flash(struct flash_bank *bank) +{ + int retval = artery_usd_lock(bank); + + if (retval != ERROR_OK) + return retval; + + uint32_t ctrl; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_CTRL_OPLK) + return ERROR_OK; + + ctrl |= FLASH_CTRL_OPLK; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) + return retval; + + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (!(ctrl & FLASH_CTRL_OPLK)) { + LOG_ERROR("Failed to lock flash"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int artery_read_protection(struct flash_bank *bank, uint64_t *protection) +{ + uint32_t epps0; + int retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_EPPS0, + &epps0); + + if (retval != ERROR_OK) + return retval; + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + + uint64_t prot = epps0; + + if (artery_series[part_info->series].has_epp_ext) { + uint32_t epps1; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_EPPS1, + &epps1); + + if (retval != ERROR_OK) + return retval; + + prot |= (((uint64_t)epps1) << 32); + } + + *protection = prot; + + return ERROR_OK; +} + +static int artery_protect_check(struct flash_bank *bank) +{ + uint64_t prot; + int retval = artery_read_protection(bank, &prot); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read flash protection settings"); + return retval; + } + + for (unsigned int i = 0; i < bank->num_prot_blocks; i++) { + const bool protected = !(prot & (UINT64_C(1) << i)); + bank->prot_blocks[i].is_protected = protected ? 1 : 0; + } + + return ERROR_OK; +} + +static int artery_erase(struct flash_bank *bank, unsigned int first, + unsigned int last) +{ + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = artery_init_flash(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + return retval; + } + + // Clear the EPPERR bit, otherwise we may read an invalid value later on. + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_STS, + FLASH_STS_EPPERR); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_STS register"); + goto flash_deinit; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + for (unsigned int i = first; i <= last; i++) { + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_ADDR, + bank->base + bank->sectors[i].offset); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_ADDR register"); + goto flash_deinit; + } + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, + FLASH_CTRL_SECERS | FLASH_CTRL_ERSTR); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + goto flash_deinit; + } + + retval = artery_wait_flash_busy(bank, FLASH_ERASE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + uint32_t sts; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_STS, &sts); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FLASH_STS register"); + goto flash_deinit; + } + + if (sts & FLASH_STS_EPPERR) { + LOG_ERROR("Sector %u is write protected", i); + retval = ERROR_FLASH_PROTECTED; + goto flash_deinit; + } + } + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval_deinit != ERROR_OK) + return retval_deinit; + + return retval; +} + +static int artery_usd_init(struct flash_bank *bank, uint8_t **buffer) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + uint32_t usd_size = part_info->usd_size; + + *buffer = malloc(usd_size); + + if (!*buffer) { + LOG_ERROR("Failed to allocate USD buffer"); + return ERROR_FAIL; + } + + memset(*buffer, 0xff, usd_size); + + return ERROR_OK; +} + +static int artery_usd_read(struct flash_bank *bank, uint8_t *buffer) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const struct artery_series_info *series_info = &artery_series[part_info->series]; + + return target_read_buffer(bank->target, series_info->usd_base, + part_info->usd_size, buffer); +} + +static uint8_t artery_usd_read_buffer(const uint8_t *buffer, uint32_t base, + uint32_t offset) +{ + return buffer[base + (offset * 2)]; +} + +static int artery_usd_load(const struct artery_part_info *part_info, + const uint8_t *buffer, struct artery_usd *usd) +{ + const uint32_t *usd_regs = artery_series[part_info->series].usd_offsets; + + uint8_t fap_level = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_FAP_INDEX], 0); + + switch (fap_level) { + case ARTERY_FAP_LEVEL_DISABLED: + case ARTERY_FAP_LEVEL_HIGH: + usd->fap_level = fap_level; + break; + default: + usd->fap_level = ARTERY_FAP_LEVEL_LOW; + } + + usd->ssb = artery_usd_read_buffer(buffer, usd_regs[ARTERY_USD_SSB_INDEX], 0); + usd->protection = 0; + + for (unsigned int i = 0; i < 4; i++) { + const uint8_t prot = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_EPP_INDEX], i); + usd->protection |= (prot << (i * 8)); + } + + if (artery_series[part_info->series].has_epp_ext) { + usd->protection_ext = 0; + + for (unsigned int i = 0; i < 4; i++) { + const uint8_t prot = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_EPP_INDEX], i); + usd->protection_ext |= (prot << (i * 8)); + } + } + + // All devices have at least two bytes of user data. + usd->data[0] = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_DATA_INDEX], 0); + usd->data[1] = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_DATA_INDEX], 1); + + for (unsigned int i = 0; i < part_info->usd_data_size - 2; i++) { + usd->data[i + 2] = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_DATA_EXT_INDEX], i); + } + + return ERROR_OK; +} + +static void artery_usd_write_buffer(uint8_t *buffer, uint32_t base, + uint32_t offset, uint8_t data) +{ + buffer[base + (offset * 2)] = data; + buffer[base + (offset * 2) + 1] = ~data; +} + +static void artery_usd_update(const struct artery_part_info *part_info, + uint8_t *buffer, const struct artery_usd *usd) +{ + const uint32_t *usd_regs = artery_series[part_info->series].usd_offsets; + + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_FAP_INDEX], 0, + usd->fap_level); + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_SSB_INDEX], 0, + usd->ssb); + + for (unsigned int i = 0; i < 4; i++) { + const uint8_t prot = usd->protection >> (i * 8); + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_EPP_INDEX], i, prot); + } + + if (artery_series[part_info->series].has_epp_ext) { + for (unsigned int i = 0; i < 4; i++) { + const uint8_t prot = usd->protection_ext >> (i * 8); + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_EPP_EXT_INDEX], + i, prot); + } + } + + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_DATA_INDEX], 0, + usd->data[0]); + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_DATA_INDEX], 1, + usd->data[1]); + + for (unsigned int i = 0; i < part_info->usd_data_size - 2; i++) { + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_DATA_EXT_INDEX], i, + usd->data[i + 2]); + } +} + +static int artery_usd_write(struct flash_bank *bank, const uint8_t *buffer) +{ + struct target *target = bank->target; + + int retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + // Clear the PRGMERR bit, otherwise we may read an invalid value later on. + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_STS, + FLASH_STS_PRGMERR); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_STS register"); + return retval; + } + + // Set the USDULKS bit to avoid locking the USD area. + uint32_t ctrl = FLASH_CTRL_USDULKS | FLASH_CTRL_USDPRGM; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + return retval; + } + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + + const target_addr_t usd_base = artery_series[part_info->series].usd_base; + const uint32_t usd_size = part_info->usd_size; + + unsigned int bytes_written = 0; + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + while (bytes_written < usd_size) { + uint32_t tmp; + memcpy(&tmp, buffer + bytes_written, sizeof(tmp)); + + if (tmp != 0xffffffff) { + retval = target_write_u32(target, usd_base + bytes_written, tmp); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write user system data"); + return retval; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + } + + bytes_written += 4; + } + + uint32_t sts; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_STS, &sts); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FLASH_STS register"); + return retval; + } + + if (sts & FLASH_STS_PRGMERR) { + LOG_ERROR("Failed to program user system data"); + return ERROR_FLASH_OPERATION_FAILED; + } + + return ERROR_OK; +} + +static int artery_usd_erase(struct flash_bank *bank) +{ + int retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + // Set the USDULKS bit to avoid locking the USD area. + uint32_t ctrl = FLASH_CTRL_USDULKS | FLASH_CTRL_USDERS | FLASH_CTRL_ERSTR; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + return retval; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + uint32_t sts; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_STS, &sts); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FLASH_STS register"); + return retval; + } + + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FLASH_CTRL register"); + return retval; + } + + return ERROR_OK; +} + +static int artery_get_fap(struct flash_bank *bank, + enum artery_fap_level *fap_level) +{ + uint32_t usd; + int retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_USD, + &usd); + + if (retval != ERROR_OK) + return retval; + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const struct artery_series_info *series_info = &artery_series[part_info->series]; + + const bool fap_high = series_info->has_fap_high_level && (usd & FLASH_USD_FAP_HL); + const bool fap_low = usd & FLASH_USD_FAP; + + if (fap_high && fap_low) + *fap_level = ARTERY_FAP_LEVEL_HIGH; + else if (fap_low) + *fap_level = ARTERY_FAP_LEVEL_LOW; + else + *fap_level = ARTERY_FAP_LEVEL_DISABLED; + + return ERROR_OK; +} + +static int artery_protect(struct flash_bank *bank, int set, unsigned int first, + unsigned int last) +{ + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + enum artery_fap_level fap_level; + int retval = artery_get_fap(bank, &fap_level); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FAP level"); + return retval; + } + + if (fap_level != ARTERY_FAP_LEVEL_DISABLED) { + LOG_ERROR("Protection cannot be modified when FAP is active"); + return ERROR_FAIL; + } + + uint8_t *usd_buffer; + retval = artery_usd_init(bank, &usd_buffer); + + if (retval != ERROR_OK) + return retval; + + retval = artery_usd_read(bank, usd_buffer); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read user system data"); + return retval; + } + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + + struct artery_usd usd; + retval = artery_usd_load(part_info, usd_buffer, &usd); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to load user system data"); + free(usd_buffer); + return retval; + } + + for (unsigned int i = first; i <= MIN(31, last); i++) { + if (bank->prot_blocks[i].is_protected == set) + continue; + + if (set) + usd.protection &= ~BIT(i); + else + usd.protection |= BIT(i); + } + + for (unsigned int i = 32; i <= last; i++) { + if (bank->prot_blocks[i].is_protected == set) + continue; + + if (set) + usd.protection_ext &= ~BIT(i - 32); + else + usd.protection_ext |= BIT(i - 32); + } + + artery_usd_update(part_info, usd_buffer, &usd); + retval = artery_init_flash(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + free(usd_buffer); + return retval; + } + + retval = artery_usd_erase(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to erase user system data"); + free(usd_buffer); + goto flash_deinit; + } + + retval = artery_usd_write(bank, usd_buffer); + + free(usd_buffer); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write user system data"); + goto flash_deinit; + } + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval_deinit != ERROR_OK) + return retval_deinit; + + return retval; +} + +static int artery_write_without_loader(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + + int retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, + FLASH_CTRL_FPRGM); + + if (retval != ERROR_OK) { + LOG_ERROR("failed to write ctrl register"); + return retval; + } + + const uint32_t block_size = 4; + + uint32_t bytes_written = 0; + target_addr_t address = bank->base + offset; + + for (uint32_t i = 0; i < count / block_size; i++) { + retval = target_write_memory(target, address, block_size, 1, + buffer + bytes_written); + + if (retval != ERROR_OK) + return retval; + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + address += block_size; + bytes_written += block_size; + } + + return ERROR_OK; +} + +static int artery_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = artery_init_flash(bank); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + return retval; + } + + retval = artery_write_without_loader(bank, buffer, offset, count); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write flash memory"); + goto flash_deinit; + } + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval != ERROR_OK) + return retval; + + return retval_deinit; +} + +static int artery_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + + const struct cortex_m_common *cortex_m = target_to_cortex_m_safe(target); + + if (!cortex_m) { + LOG_ERROR("Target is not a Cortex-M device"); + return ERROR_TARGET_INVALID; + } + + struct artery_flash_bank *artery_info = bank->driver_priv; + + artery_info->probed = false; + + int retval = target_read_u32(target, DEBUG_IDCODE, &artery_info->idcode); + + if (retval != ERROR_OK) + return retval; + + const uint32_t pid = artery_info->idcode; + const bool has_fpu = cortex_m->armv7m.fp_feature != FP_NONE; + bool check_device_series = false; + enum artery_series device_series; + + /* + * The following PIDs are used for AT32F413 and AT32F415 devices. In order + * to distinguish between the series, we use the presence of the FPU. Note + * that we do not rely on the unqiue device ID (UID) which also encodes the + * device series. The reason is that the UID registers are not accessible + * when the flash access protection (FAP) is active. + */ + switch (pid) { + case 0x700301C5: + case 0x70030240: + case 0x70030242: + check_device_series = true; + device_series = has_fpu ? ARTERY_SERIES_F413 : ARTERY_SERIES_F415; + break; + default: + break; + } + + artery_info->part_info = NULL; + + for (size_t i = 0; i < ARRAY_SIZE(artery_parts); i++) { + if (check_device_series && artery_parts[i].series != device_series) + continue; + + if (artery_parts[i].pid == pid) { + artery_info->part_info = &artery_parts[i]; + break; + } + } + + if (!artery_info->part_info) { + LOG_ERROR("Cannot identify target as an Artery device"); + return ERROR_FAIL; + } + + const struct artery_part_info *part_info = artery_info->part_info; + + LOG_INFO("Device ID = 0x%08" PRIx32 " (%s)", artery_info->idcode, + part_info->name); + LOG_INFO("Flash size = %d KiB", part_info->flash_size); + + free(bank->sectors); + + bank->base = FLASH_BASE; + bank->size = part_info->flash_size * 1024; + + const unsigned int num_pages = (bank->size) / part_info->page_size; + + // Ensure that the flash infrastructure uses an alignment of 4 bytes. + bank->write_start_alignment = 4; + bank->write_end_alignment = 4; + + bank->num_sectors = num_pages; + bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + + if (!bank->sectors) { + LOG_ERROR("Failed to allocate bank sectors"); + return ERROR_FAIL; + } + + for (unsigned int i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * part_info->page_size; + bank->sectors[i].size = part_info->page_size; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + free(bank->prot_blocks); + + /* + * Flash erase/program protection (EPPx) registers configuration for each + * device series. + * + * - AT32F403A / AT32F407 + * - AT32F413 + * + * Each bit represents a sector of 4 KiB. The last bit represents the + * entire remaining flash memory and extension area. + * + * - AT32F415 + * - AT32WB415 + * + * Each bit represents a sector of 2 KiB. The last bit represents the + * entire remaining flash memory and extension area. + * + * - AT32F421 + * - AT32F423 + * - AT32F425 + * + * Each bit represents a sector of 4 KiB. Some bits may not used + * depending on the flash memory size. The last bit represents only the + * flash memory extension area. + * + * - AT32F435 / AT32F437 + * + * This device series has an additional erase/program protection (EPP) + * register. + * + * The first 32 bits represent a flash sector of 4 KiB per bit. + * + * The additional 32 bits represent a sector of 128 KiB each. The + * second last bit covers the remaining flash memory. The last bit is + * always reserved. + * + */ + if (part_info->series == ARTERY_SERIES_F435_F437) { + // See description above. + const unsigned int num_prot_blocks_1 = 32; + const unsigned int num_prot_blocks_2 = MIN(31, DIV_ROUND_UP(part_info->flash_size - 128, 128)); + const unsigned int num_prot_blocks = num_prot_blocks_1 + num_prot_blocks_2; + bank->num_prot_blocks = num_prot_blocks; + bank->prot_blocks = malloc(sizeof(struct flash_sector) * num_prot_blocks); + + if (!bank->prot_blocks) { + LOG_ERROR("Failed to allocate protection blocks"); + return ERROR_FAIL; + } + + const uint32_t prot_block_size = 4096; + + unsigned int i; + uint32_t block_offset = 0; + + for (i = 0; i < 32; i++) { + bank->prot_blocks[i].offset = block_offset; + bank->prot_blocks[i].size = prot_block_size; + bank->prot_blocks[i].is_erased = -1; + bank->prot_blocks[i].is_protected = -1; + + block_offset += prot_block_size; + } + + const uint32_t prot_block_size_2 = 128 * 1024; + + for (; i < (num_prot_blocks - 1); i++) { + bank->prot_blocks[i].offset = block_offset; + bank->prot_blocks[i].size = prot_block_size_2; + bank->prot_blocks[i].is_erased = -1; + bank->prot_blocks[i].is_protected = -1; + + block_offset += prot_block_size_2; + } + + bank->prot_blocks[i].offset = block_offset; + bank->prot_blocks[i].size = bank->size - block_offset; + bank->prot_blocks[i].is_erased = -1; + bank->prot_blocks[i].is_protected = -1; + } else { + uint32_t prot_block_size; + + switch (part_info->series) { + case ARTERY_SERIES_F403A_F407: + case ARTERY_SERIES_F413: + case ARTERY_SERIES_F421: + case ARTERY_SERIES_F423: + case ARTERY_SERIES_F425: + prot_block_size = 4096; + break; + case ARTERY_SERIES_F415: + case ARTERY_SERIES_WB415: + prot_block_size = 2048; + break; + default: + LOG_ERROR("Unknown Artery device series"); + return ERROR_FAIL; + } + + const unsigned int num_prot_blocks = MIN(bank->size / prot_block_size, 32); + bank->num_prot_blocks = num_prot_blocks; + bank->prot_blocks = malloc(sizeof(struct flash_sector) * num_prot_blocks); + + if (!bank->prot_blocks) { + LOG_ERROR("Failed to allocate protection blocks"); + return ERROR_FAIL; + } + + unsigned int i; + + for (i = 0; i < (num_prot_blocks - 1); i++) { + bank->prot_blocks[i].offset = i * prot_block_size; + bank->prot_blocks[i].size = prot_block_size; + bank->prot_blocks[i].is_erased = -1; + bank->prot_blocks[i].is_protected = -1; + } + + bank->prot_blocks[i].offset = i * prot_block_size; + bank->prot_blocks[i].size = (bank->size - (i * prot_block_size)); + bank->prot_blocks[i].is_erased = -1; + bank->prot_blocks[i].is_protected = -1; + } + + artery_info->probed = true; + + return ERROR_OK; +} + +static int artery_auto_probe(struct flash_bank *bank) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + + if (artery_info->probed) + return ERROR_OK; + + return artery_probe(bank); +} + +static int artery_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + + if (!part_info) { + command_print_sameline(cmd, "Cannot identify target device"); + return ERROR_OK; + } + + command_print_sameline(cmd, "%s - %u KiB flash", part_info->name, + part_info->flash_size); + + return ERROR_OK; +} + +static int artery_mass_erase(struct flash_bank *bank) +{ + int retval = artery_init_flash(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + return retval; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + // Clear the EPPERR bit, otherwise we may read an invalid value later on. + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_STS, + FLASH_STS_EPPERR); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + goto flash_deinit; + } + + uint32_t ctrl = FLASH_CTRL_BANKERS | FLASH_CTRL_ERSTR; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + goto flash_deinit; + } + + retval = artery_wait_flash_busy(bank, FLASH_MASS_ERASE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + uint32_t sts; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_STS, &sts); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FLASH_STS register"); + goto flash_deinit; + } + + if (sts & FLASH_STS_EPPERR) { + LOG_ERROR("Mass erase operation failed"); + goto flash_deinit; + } + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval != ERROR_OK) + return retval; + + return retval_deinit; +} + +COMMAND_HANDLER(artery_handle_fap_enable_command) +{ + 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 (retval != ERROR_OK) + return retval; + + enum artery_fap_level fap_level; + retval = artery_get_fap(bank, &fap_level); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to read FAP state"); + return retval; + } + + if (fap_level != ARTERY_FAP_LEVEL_DISABLED) { + command_print(CMD, "flash access protection is already enabled"); + return ERROR_FAIL; + } + + uint8_t *usd_buffer; + retval = artery_usd_init(bank, &usd_buffer); + + if (retval != ERROR_OK) + return retval; + + retval = artery_usd_read(bank, usd_buffer); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to read user system data"); + return retval; + } + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + + struct artery_usd usd; + retval = artery_usd_load(part_info, usd_buffer, &usd); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to load user system data"); + return retval; + } + + usd.fap_level = ARTERY_FAP_LEVEL_LOW; + artery_usd_update(part_info, usd_buffer, &usd); + + retval = artery_init_flash(bank); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + goto flash_deinit; + } + + retval = artery_usd_erase(bank); + + if (retval != ERROR_OK) { + free(usd_buffer); + command_print(CMD, "failed to erase user system data"); + goto flash_deinit; + } + + retval = artery_usd_write(bank, usd_buffer); + free(usd_buffer); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to write user system data"); + goto flash_deinit; + } + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval_deinit != ERROR_OK) + return retval_deinit; + + return retval; +} + +/* + * We use a dedicated operation to perform the FAP unlock operation that only + * writes the corresponding FAP byte(s) instead of the entire user system + * data (USD) area. The reason is that directly after the FAP byte(s) are + * written, a device reset is performed and all other writes to the USD area + * would fail and generate errors. +*/ +static int artery_disable_fap(struct flash_bank *bank) +{ + int retval = artery_init_flash(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + return retval; + } + + retval = artery_usd_erase(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to erase user system data"); + goto flash_deinit; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + // Clear the PRGMERR bit, otherwise we may read an invalid value later on. + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_STS, + FLASH_STS_PRGMERR); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_STS register"); + goto flash_deinit; + } + + // Set the USDULKS bit to avoid locking the USD area. + uint32_t ctrl = FLASH_CTRL_USDULKS | FLASH_CTRL_USDPRGM; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + goto flash_deinit; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + uint16_t buffer; + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const uint32_t *usd_regs = artery_series[part_info->series].usd_offsets; + + artery_usd_write_buffer((uint8_t *)&buffer, usd_regs[ARTERY_USD_FAP_INDEX], 0, + ARTERY_FAP_LEVEL_DISABLED); + + const target_addr_t usd_base = artery_series[part_info->series].usd_base; + retval = target_write_u16(bank->target, usd_base, buffer); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FAP level"); + goto flash_deinit; + } + + /* + * Note that we do not need to deinitialize the flash memory because the + * device performed a reset anyway. + */ + + return ERROR_OK; + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval_deinit != ERROR_OK) + return retval_deinit; + + return retval; +} + +COMMAND_HANDLER(artery_handle_fap_disable_command) +{ + 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 (retval != ERROR_OK) + return retval; + + enum artery_fap_level fap_level; + retval = artery_get_fap(bank, &fap_level); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to read FAP state"); + return retval; + } + + if (fap_level == ARTERY_FAP_LEVEL_DISABLED) { + command_print(CMD, "flash access protection is not enabled"); + return ERROR_FAIL; + } + + retval = artery_disable_fap(bank); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to disable flash access protection"); + return retval; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(artery_handle_fap_state_command) +{ + 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 (retval != ERROR_OK) + return retval; + + enum artery_fap_level fap_level; + retval = artery_get_fap(bank, &fap_level); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to read FAP level"); + return retval; + } + + const bool fap_enabled = fap_level != ARTERY_FAP_LEVEL_DISABLED; + command_print(CMD, "%u", fap_enabled); + + return ERROR_OK; +} + +COMMAND_HANDLER(artery_handle_mass_erase_command) +{ + 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 (retval != ERROR_OK) + return retval; + + retval = artery_mass_erase(bank); + + if (retval != ERROR_OK) { + command_print(CMD, "Mass erase failed"); + return retval; + } + + return ERROR_OK; +} + +static const struct command_registration artery_fap_command_handlers[] = { + { + .name = "enable", + .handler = artery_handle_fap_enable_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "Enable flash access protection (FAP)", + }, + { + .name = "disable", + .handler = artery_handle_fap_disable_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "Disable flash access protection (FAP)", + }, + { + .name = "state", + .handler = artery_handle_fap_state_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "Get the flash access protection (FAP) state", + }, + + COMMAND_REGISTRATION_DONE, +}; + +static const struct command_registration artery_exec_command_handlers[] = { + { + .name = "fap", + .mode = COMMAND_ANY, + .help = "flash access protection (FAP) command group", + .usage = "", + .chain = artery_fap_command_handlers, + }, + { + .name = "mass_erase", + .handler = artery_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "Erase entire flash memory", + }, + COMMAND_REGISTRATION_DONE, +}; + +static const struct command_registration artery_command_handlers[] = { + { + .name = "artery", + .mode = COMMAND_ANY, + .help = "artery flash command group", + .usage = "", + .chain = artery_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE, +}; + +const struct flash_driver artery_flash = { + .name = "artery", + .commands = artery_command_handlers, + .flash_bank_command = artery_flash_bank_command, + .erase = artery_erase, + .protect = artery_protect, + .write = artery_write, + .read = default_flash_read, + .probe = artery_probe, + .auto_probe = artery_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = artery_protect_check, + .info = artery_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/artery.h b/src/flash/nor/artery.h new file mode 100644 index 0000000000..dcfa70a6e3 --- /dev/null +++ b/src/flash/nor/artery.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2023 by Marc Schink + */ + +#ifndef OPENOCD_FLASH_NOR_ARTERY +#define OPENOCD_FLASH_NOR_ARTERY + +#define DEBUG_IDCODE 0xE0042000 + +#define FLASH_BASE 0x08000000 + +enum artery_series { + ARTERY_SERIES_F403A_F407 = 0, + ARTERY_SERIES_F413, + ARTERY_SERIES_F415, + ARTERY_SERIES_F421, + ARTERY_SERIES_F423, + ARTERY_SERIES_F425, + ARTERY_SERIES_F435_F437, + ARTERY_SERIES_WB415, +}; + +enum artery_flash_reg_index { + ARTERY_FLASH_REG_PSR = 0, + ARTERY_FLASH_REG_UNLOCK, + ARTERY_FLASH_REG_USD_UNLOCK, + ARTERY_FLASH_REG_STS, + ARTERY_FLASH_REG_CTRL, + ARTERY_FLASH_REG_ADDR, + ARTERY_FLASH_REG_USD, + ARTERY_FLASH_REG_EPPS0, + ARTERY_FLASH_REG_EPPS1, + ARTERY_FLASH_REG_INDEX_NUM, +}; + +enum artery_usd_reg_index { + ARTERY_USD_FAP_INDEX = 0, + ARTERY_USD_SSB_INDEX, + ARTERY_USD_DATA_INDEX, + ARTERY_USD_EPP_INDEX, + ARTERY_USD_EPP_EXT_INDEX, + ARTERY_USD_DATA_EXT_INDEX, + ARTERY_USD_INDEX_NUM, +}; + +enum artery_fap_level { + ARTERY_FAP_LEVEL_DISABLED = 0xa5, + ARTERY_FAP_LEVEL_LOW = 0xff, + ARTERY_FAP_LEVEL_HIGH = 0xcc, +}; + +struct artery_part_info { + uint32_t pid; + const char *name; + enum artery_series series; + // Flash size in bytes. + uint32_t flash_size; + // Page / sector size in bytes. + uint32_t page_size; + // User system data (USD) area size including the inverse bytes. + uint32_t usd_size; + // User data area (part of the USD) size excluding the inverse bytes. + uint32_t usd_data_size; +}; + +struct artery_flash_bank { + bool probed; + uint32_t idcode; + const struct artery_part_info *part_info; +}; + +struct artery_series_info { + bool has_fap_high_level; + bool has_epp_ext; + uint32_t flash_regs_base; + const uint32_t *flash_regs; + uint32_t crm_base; + uint32_t usd_base; + const uint32_t *usd_offsets; +}; + +#define ARTERY_USD_DATA_MAX_SIZE 2012 + +struct artery_usd { + enum artery_fap_level fap_level; + uint8_t ssb; + uint32_t protection; + uint32_t protection_ext; + uint8_t data[ARTERY_USD_DATA_MAX_SIZE]; +}; + +#define CRM_REG_CTRL 0x000 + +/* CRM_CTRL register bits. */ +#define CRM_CTRL_HICKSTBL BIT(0) +#define CRM_CTRL_HICKEN BIT(1) + +/* FLASH_CTRL register bits. */ +#define FLASH_CTRL_USDULKS BIT(9) +#define FLASH_CTRL_OPLK BIT(7) +#define FLASH_CTRL_ERSTR BIT(6) +#define FLASH_CTRL_USDERS BIT(5) +#define FLASH_CTRL_USDPRGM BIT(4) +#define FLASH_CTRL_BANKERS BIT(2) +#define FLASH_CTRL_SECERS BIT(1) +#define FLASH_CTRL_FPRGM BIT(0) + +/* FLASH_STS register bits. */ +#define FLASH_STS_OBF BIT(0) +#define FLASH_STS_PRGMERR BIT(2) +#define FLASH_STS_EPPERR BIT(4) +#define FLASH_STS_ODF BIT(5) + +/* FLASH_USD register bits. */ +#define FLASH_USD_FAP BIT(1) +#define FLASH_USD_FAP_HL BIT(26) + +#define FLASH_USD_SSB_OFFSET 2 +#define FLASH_USD_USER_D0_OFFSET 10 +#define FLASH_USD_USER_D1_OFFSET 18 + +/* Flash and USD unlock keys. */ +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +#endif /* OPENOCD_FLASH_NOR_ARTERY */ diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c index b86a18da75..2479505626 100644 --- a/src/flash/nor/at91sam3.c +++ b/src/flash/nor/at91sam3.c @@ -69,10 +69,7 @@ static float _tomhz(uint32_t freq_hz) { - float f; - - f = ((float)(freq_hz)) / 1000000.0; - return f; + return ((float)freq_hz) / 1000000.0; } /* How the chip is configured. */ @@ -2040,40 +2037,39 @@ static int efc_start_command(struct sam3_bank_private *private, /* Check command & argument */ switch (command) { - - case AT91C_EFC_FCMD_WP: - case AT91C_EFC_FCMD_WPL: - case AT91C_EFC_FCMD_EWP: - case AT91C_EFC_FCMD_EWPL: - /* case AT91C_EFC_FCMD_EPL: */ - /* case AT91C_EFC_FCMD_EPA: */ - case AT91C_EFC_FCMD_SLB: - case AT91C_EFC_FCMD_CLB: - n = (private->size_bytes / private->page_size); - if (argument >= n) - LOG_ERROR("*BUG*: Embedded flash has only %" PRIu32 " pages", n); - break; - - case AT91C_EFC_FCMD_SFB: - case AT91C_EFC_FCMD_CFB: - if (argument >= private->chip->details.n_gpnvms) { - LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", - private->chip->details.n_gpnvms); - } - break; - - case AT91C_EFC_FCMD_GETD: - case AT91C_EFC_FCMD_EA: - case AT91C_EFC_FCMD_GLB: - case AT91C_EFC_FCMD_GFB: - case AT91C_EFC_FCMD_STUI: - case AT91C_EFC_FCMD_SPUI: - if (argument != 0) - LOG_ERROR("Argument is meaningless for cmd: %d", command); - break; - default: - LOG_ERROR("Unknown command %d", command); - break; + case AT91C_EFC_FCMD_WP: + case AT91C_EFC_FCMD_WPL: + case AT91C_EFC_FCMD_EWP: + case AT91C_EFC_FCMD_EWPL: + /* case AT91C_EFC_FCMD_EPL: */ + /* case AT91C_EFC_FCMD_EPA: */ + case AT91C_EFC_FCMD_SLB: + case AT91C_EFC_FCMD_CLB: + n = (private->size_bytes / private->page_size); + if (argument >= n) + LOG_ERROR("*BUG*: Embedded flash has only %" PRIu32 " pages", n); + break; + + case AT91C_EFC_FCMD_SFB: + case AT91C_EFC_FCMD_CFB: + if (argument >= private->chip->details.n_gpnvms) { + LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", + private->chip->details.n_gpnvms); + } + break; + + case AT91C_EFC_FCMD_GETD: + case AT91C_EFC_FCMD_EA: + case AT91C_EFC_FCMD_GLB: + case AT91C_EFC_FCMD_GFB: + case AT91C_EFC_FCMD_STUI: + case AT91C_EFC_FCMD_SPUI: + if (argument != 0) + LOG_ERROR("Argument is meaningless for cmd: %d", command); + break; + default: + LOG_ERROR("Unknown command %d", command); + break; } if (command == AT91C_EFC_FCMD_SPUI) { @@ -2571,18 +2567,18 @@ static void sam3_explain_ckgr_mor(struct sam3_chip *chip) chip->cfg.rc_freq = 0; if (rcen) { switch (v) { - default: - chip->cfg.rc_freq = 0; - break; - case 0: - chip->cfg.rc_freq = 4 * 1000 * 1000; - break; - case 1: - chip->cfg.rc_freq = 8 * 1000 * 1000; - break; - case 2: - chip->cfg.rc_freq = 12 * 1000 * 1000; - break; + case 0: + chip->cfg.rc_freq = 4 * 1000 * 1000; + break; + case 1: + chip->cfg.rc_freq = 8 * 1000 * 1000; + break; + case 2: + chip->cfg.rc_freq = 12 * 1000 * 1000; + break; + default: + chip->cfg.rc_freq = 0; + break; } } @@ -2683,30 +2679,30 @@ static void sam3_explain_mckr(struct sam3_chip *chip) css = sam3_reg_fieldname(chip, "CSS", chip->cfg.PMC_MCKR, 0, 2); switch (css & 3) { - case 0: - fin = chip->cfg.slow_freq; - cp = "slowclk"; - break; - case 1: - fin = chip->cfg.mainosc_freq; - cp = "mainosc"; - break; - case 2: - fin = chip->cfg.plla_freq; - cp = "plla"; - break; - case 3: - if (chip->cfg.CKGR_UCKR & (1 << 16)) { - fin = 480 * 1000 * 1000; - cp = "upll"; - } else { - fin = 0; - cp = "upll (*ERROR* UPLL is disabled)"; - } - break; - default: - assert(0); - break; + case 0: + fin = chip->cfg.slow_freq; + cp = "slowclk"; + break; + case 1: + fin = chip->cfg.mainosc_freq; + cp = "mainosc"; + break; + case 2: + fin = chip->cfg.plla_freq; + cp = "plla"; + break; + case 3: + if (chip->cfg.CKGR_UCKR & (1 << 16)) { + fin = 480 * 1000 * 1000; + cp = "upll"; + } else { + fin = 0; + cp = "upll (*ERROR* UPLL is disabled)"; + } + break; + default: + assert(0); + break; } LOG_USER("%s (%3.03f Mhz)", @@ -2714,41 +2710,41 @@ static void sam3_explain_mckr(struct sam3_chip *chip) _tomhz(fin)); pres = sam3_reg_fieldname(chip, "PRES", chip->cfg.PMC_MCKR, 4, 3); switch (pres & 0x07) { - case 0: - pdiv = 1; - cp = "selected clock"; - break; - case 1: - pdiv = 2; - cp = "clock/2"; - break; - case 2: - pdiv = 4; - cp = "clock/4"; - break; - case 3: - pdiv = 8; - cp = "clock/8"; - break; - case 4: - pdiv = 16; - cp = "clock/16"; - break; - case 5: - pdiv = 32; - cp = "clock/32"; - break; - case 6: - pdiv = 64; - cp = "clock/64"; - break; - case 7: - pdiv = 6; - cp = "clock/6"; - break; - default: - assert(0); - break; + case 0: + pdiv = 1; + cp = "selected clock"; + break; + case 1: + pdiv = 2; + cp = "clock/2"; + break; + case 2: + pdiv = 4; + cp = "clock/4"; + break; + case 3: + pdiv = 8; + cp = "clock/8"; + break; + case 4: + pdiv = 16; + cp = "clock/16"; + break; + case 5: + pdiv = 32; + cp = "clock/32"; + break; + case 6: + pdiv = 64; + cp = "clock/64"; + break; + case 7: + pdiv = 6; + cp = "clock/6"; + break; + default: + assert(0); + break; } LOG_USER("(%s)", cp); fin = fin / pdiv; @@ -3011,39 +3007,39 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command) } switch (bank->base) { - default: - LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x or 0x%08x " - "[at91sam3u series] or 0x%08x [at91sam3s series] or " - "0x%08x [at91sam3n series] or 0x%08x or 0x%08x or 0x%08x[at91sam3ax series] )", - ((unsigned int)(bank->base)), - ((unsigned int)(FLASH_BANK0_BASE_U)), - ((unsigned int)(FLASH_BANK1_BASE_U)), - ((unsigned int)(FLASH_BANK_BASE_S)), - ((unsigned int)(FLASH_BANK_BASE_N)), - ((unsigned int)(FLASH_BANK0_BASE_AX)), - ((unsigned int)(FLASH_BANK1_BASE_256K_AX)), - ((unsigned int)(FLASH_BANK1_BASE_512K_AX))); - return ERROR_FAIL; - - /* at91sam3s and at91sam3n series only has bank 0*/ - /* at91sam3u and at91sam3ax series has the same address for bank 0*/ - case FLASH_BANK_BASE_S: - case FLASH_BANK0_BASE_U: - bank->driver_priv = &(chip->details.bank[0]); - bank->bank_number = 0; - 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 = &(chip->details.bank[1]); - bank->bank_number = 1; - chip->details.bank[1].chip = chip; - chip->details.bank[1].bank = bank; - break; + /* at91sam3s and at91sam3n series only has bank 0*/ + /* at91sam3u and at91sam3ax series has the same address for bank 0*/ + case FLASH_BANK_BASE_S: + case FLASH_BANK0_BASE_U: + bank->driver_priv = &chip->details.bank[0]; + bank->bank_number = 0; + 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 = &chip->details.bank[1]; + bank->bank_number = 1; + chip->details.bank[1].chip = chip; + chip->details.bank[1].bank = bank; + break; + + default: + LOG_ERROR("Address " TARGET_ADDR_FMT " invalid bank address (try 0x%08x or 0x%08x " + "[at91sam3u series] or 0x%08x [at91sam3s series] or " + "0x%08x [at91sam3n series] or 0x%08x or 0x%08x or 0x%08x[at91sam3ax series] )", + bank->base, + FLASH_BANK0_BASE_U, + FLASH_BANK1_BASE_U, + FLASH_BANK_BASE_S, + FLASH_BANK_BASE_N, + FLASH_BANK0_BASE_AX, + FLASH_BANK1_BASE_256K_AX, + FLASH_BANK1_BASE_512K_AX); + return ERROR_FAIL; } /* we initialize after probing. */ @@ -3574,22 +3570,22 @@ COMMAND_HANDLER(sam3_handle_gpnvm_command) } switch (CMD_ARGC) { - default: - return ERROR_COMMAND_SYNTAX_ERROR; - case 0: - goto showall; - case 1: + case 0: + goto showall; + case 1: + who = -1; + break; + case 2: + if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) { who = -1; - break; - case 2: - if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) - who = -1; - else { - uint32_t v32; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); - who = v32; - } - break; + } else { + uint32_t v32; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); + who = v32; + } + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if (strcmp("show", CMD_ARGV[0]) == 0) { @@ -3641,26 +3637,26 @@ COMMAND_HANDLER(sam3_handle_slowclk_command) return ERROR_OK; switch (CMD_ARGC) { - case 0: - /* show */ - break; - case 1: - { - /* set */ - uint32_t v; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); - if (v > 200000) { - /* absurd slow clock of 200Khz? */ - command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); - return ERROR_COMMAND_SYNTAX_ERROR; - } - chip->cfg.slow_freq = v; - break; - } - default: - /* error */ - command_print(CMD, "Too many parameters"); + case 0: + /* show */ + break; + case 1: + { + /* set */ + uint32_t v; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); + if (v > 200000) { + /* absurd slow clock of 200Khz? */ + command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); return ERROR_COMMAND_SYNTAX_ERROR; + } + chip->cfg.slow_freq = v; + break; + } + default: + /* error */ + command_print(CMD, "Too many parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "Slowclk freq: %d.%03dkhz", (int)(chip->cfg.slow_freq / 1000), diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index 26a803784d..a2d720cce4 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -64,10 +64,7 @@ static float _tomhz(uint32_t freq_hz) { - float f; - - f = ((float)(freq_hz)) / 1000000.0; - return f; + return ((float)freq_hz) / 1000000.0; } /* How the chip is configured. */ @@ -1490,40 +1487,39 @@ static int efc_start_command(struct sam4_bank_private *private, /* Check command & argument */ switch (command) { - - case AT91C_EFC_FCMD_WP: - case AT91C_EFC_FCMD_WPL: - case AT91C_EFC_FCMD_EWP: - case AT91C_EFC_FCMD_EWPL: - /* case AT91C_EFC_FCMD_EPL: */ - case AT91C_EFC_FCMD_EPA: - case AT91C_EFC_FCMD_SLB: - case AT91C_EFC_FCMD_CLB: - n = (private->size_bytes / private->page_size); - if (argument >= n) - LOG_ERROR("*BUG*: Embedded flash has only %" PRIu32 " pages", n); - break; - - case AT91C_EFC_FCMD_SFB: - case AT91C_EFC_FCMD_CFB: - if (argument >= private->chip->details.n_gpnvms) { - LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", - private->chip->details.n_gpnvms); - } - break; - - case AT91C_EFC_FCMD_GETD: - case AT91C_EFC_FCMD_EA: - case AT91C_EFC_FCMD_GLB: - case AT91C_EFC_FCMD_GFB: - case AT91C_EFC_FCMD_STUI: - case AT91C_EFC_FCMD_SPUI: - if (argument != 0) - LOG_ERROR("Argument is meaningless for cmd: %d", command); - break; - default: - LOG_ERROR("Unknown command %d", command); - break; + case AT91C_EFC_FCMD_WP: + case AT91C_EFC_FCMD_WPL: + case AT91C_EFC_FCMD_EWP: + case AT91C_EFC_FCMD_EWPL: + /* case AT91C_EFC_FCMD_EPL: */ + case AT91C_EFC_FCMD_EPA: + case AT91C_EFC_FCMD_SLB: + case AT91C_EFC_FCMD_CLB: + n = (private->size_bytes / private->page_size); + if (argument >= n) + LOG_ERROR("*BUG*: Embedded flash has only %" PRIu32 " pages", n); + break; + + case AT91C_EFC_FCMD_SFB: + case AT91C_EFC_FCMD_CFB: + if (argument >= private->chip->details.n_gpnvms) { + LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", + private->chip->details.n_gpnvms); + } + break; + + case AT91C_EFC_FCMD_GETD: + case AT91C_EFC_FCMD_EA: + case AT91C_EFC_FCMD_GLB: + case AT91C_EFC_FCMD_GFB: + case AT91C_EFC_FCMD_STUI: + case AT91C_EFC_FCMD_SPUI: + if (argument != 0) + LOG_ERROR("Argument is meaningless for cmd: %d", command); + break; + default: + LOG_ERROR("Unknown command %d", command); + break; } if (command == AT91C_EFC_FCMD_SPUI) { @@ -1678,21 +1674,21 @@ static int flashd_erase_pages(struct sam4_bank_private *private, LOG_DEBUG("Here"); uint8_t erase_pages; switch (num_pages) { - case 4: - erase_pages = 0x00; - break; - case 8: - erase_pages = 0x01; - break; - case 16: - erase_pages = 0x02; - break; - case 32: - erase_pages = 0x03; - break; - default: - erase_pages = 0x00; - break; + case 4: + erase_pages = 0x00; + break; + case 8: + erase_pages = 0x01; + break; + case 16: + erase_pages = 0x02; + break; + case 32: + erase_pages = 0x03; + break; + default: + erase_pages = 0x00; + break; } /* AT91C_EFC_FCMD_EPA @@ -2080,18 +2076,18 @@ static void sam4_explain_ckgr_mor(struct sam4_chip *chip) chip->cfg.rc_freq = 0; if (rcen) { switch (v) { - default: - chip->cfg.rc_freq = 0; - break; - case 0: - chip->cfg.rc_freq = 4 * 1000 * 1000; - break; - case 1: - chip->cfg.rc_freq = 8 * 1000 * 1000; - break; - case 2: - chip->cfg.rc_freq = 12 * 1000 * 1000; - break; + case 0: + chip->cfg.rc_freq = 4 * 1000 * 1000; + break; + case 1: + chip->cfg.rc_freq = 8 * 1000 * 1000; + break; + case 2: + chip->cfg.rc_freq = 12 * 1000 * 1000; + break; + default: + chip->cfg.rc_freq = 0; + break; } } @@ -2192,30 +2188,30 @@ static void sam4_explain_mckr(struct sam4_chip *chip) css = sam4_reg_fieldname(chip, "CSS", chip->cfg.PMC_MCKR, 0, 2); switch (css & 3) { - case 0: - fin = chip->cfg.slow_freq; - cp = "slowclk"; - break; - case 1: - fin = chip->cfg.mainosc_freq; - cp = "mainosc"; - break; - case 2: - fin = chip->cfg.plla_freq; - cp = "plla"; - break; - case 3: - if (chip->cfg.CKGR_UCKR & (1 << 16)) { - fin = 480 * 1000 * 1000; - cp = "upll"; - } else { - fin = 0; - cp = "upll (*ERROR* UPLL is disabled)"; - } - break; - default: - assert(0); - break; + case 0: + fin = chip->cfg.slow_freq; + cp = "slowclk"; + break; + case 1: + fin = chip->cfg.mainosc_freq; + cp = "mainosc"; + break; + case 2: + fin = chip->cfg.plla_freq; + cp = "plla"; + break; + case 3: + if (chip->cfg.CKGR_UCKR & (1 << 16)) { + fin = 480 * 1000 * 1000; + cp = "upll"; + } else { + fin = 0; + cp = "upll (*ERROR* UPLL is disabled)"; + } + break; + default: + assert(0); + break; } LOG_USER("%s (%3.03f Mhz)", @@ -2223,41 +2219,41 @@ static void sam4_explain_mckr(struct sam4_chip *chip) _tomhz(fin)); pres = sam4_reg_fieldname(chip, "PRES", chip->cfg.PMC_MCKR, 4, 3); switch (pres & 0x07) { - case 0: - pdiv = 1; - cp = "selected clock"; - break; - case 1: - pdiv = 2; - cp = "clock/2"; - break; - case 2: - pdiv = 4; - cp = "clock/4"; - break; - case 3: - pdiv = 8; - cp = "clock/8"; - break; - case 4: - pdiv = 16; - cp = "clock/16"; - break; - case 5: - pdiv = 32; - cp = "clock/32"; - break; - case 6: - pdiv = 64; - cp = "clock/64"; - break; - case 7: - pdiv = 6; - cp = "clock/6"; - break; - default: - assert(0); - break; + case 0: + pdiv = 1; + cp = "selected clock"; + break; + case 1: + pdiv = 2; + cp = "clock/2"; + break; + case 2: + pdiv = 4; + cp = "clock/4"; + break; + case 3: + pdiv = 8; + cp = "clock/8"; + break; + case 4: + pdiv = 16; + cp = "clock/16"; + break; + case 5: + pdiv = 32; + cp = "clock/32"; + break; + case 6: + pdiv = 64; + cp = "clock/64"; + break; + case 7: + pdiv = 6; + cp = "clock/6"; + break; + default: + assert(0); + break; } LOG_USER("(%s)", cp); fin = fin / pdiv; @@ -2504,32 +2500,32 @@ FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command) } switch (bank->base) { - default: - LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x" - "[at91sam4s series] )", - ((unsigned int)(bank->base)), - ((unsigned int)(FLASH_BANK_BASE_S))); - return ERROR_FAIL; - - /* at91sam4s series only has bank 0*/ - /* 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 = &(chip->details.bank[0]); - bank->bank_number = 0; - 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 = &(chip->details.bank[1]); - bank->bank_number = 1; - chip->details.bank[1].chip = chip; - chip->details.bank[1].bank = bank; - break; + /* at91sam4s series only has bank 0*/ + /* 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 = &chip->details.bank[0]; + bank->bank_number = 0; + 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 = &chip->details.bank[1]; + bank->bank_number = 1; + chip->details.bank[1].chip = chip; + chip->details.bank[1].bank = bank; + break; + + default: + LOG_ERROR("Address " TARGET_ADDR_FMT " invalid bank address (try 0x%08x" + "[at91sam4s series] )", + bank->base, + FLASH_BANK_BASE_S); + return ERROR_FAIL; } /* we initialize after probing. */ @@ -3122,22 +3118,22 @@ COMMAND_HANDLER(sam4_handle_gpnvm_command) } switch (CMD_ARGC) { - default: - return ERROR_COMMAND_SYNTAX_ERROR; - case 0: - goto showall; - case 1: + case 0: + goto showall; + case 1: + who = -1; + break; + case 2: + if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) { who = -1; - break; - case 2: - if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) - who = -1; - else { - uint32_t v32; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); - who = v32; - } - break; + } else { + uint32_t v32; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); + who = v32; + } + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if (strcmp("show", CMD_ARGV[0]) == 0) { @@ -3189,26 +3185,26 @@ COMMAND_HANDLER(sam4_handle_slowclk_command) return ERROR_OK; switch (CMD_ARGC) { - case 0: - /* show */ - break; - case 1: - { - /* set */ - uint32_t v; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); - if (v > 200000) { - /* absurd slow clock of 200Khz? */ - command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); - return ERROR_COMMAND_SYNTAX_ERROR; - } - chip->cfg.slow_freq = v; - break; - } - default: - /* error */ - command_print(CMD, "Too many parameters"); + case 0: + /* show */ + break; + case 1: + { + /* set */ + uint32_t v; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); + if (v > 200000) { + /* absurd slow clock of 200Khz? */ + command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); return ERROR_COMMAND_SYNTAX_ERROR; + } + chip->cfg.slow_freq = v; + break; + } + default: + /* error */ + command_print(CMD, "Too many parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "Slowclk freq: %d.%03dkhz", (int)(chip->cfg.slow_freq / 1000), diff --git a/src/flash/nor/at91sam4l.c b/src/flash/nor/at91sam4l.c index ddf42a8c5f..f6aff73b74 100644 --- a/src/flash/nor/at91sam4l.c +++ b/src/flash/nor/at91sam4l.c @@ -185,9 +185,7 @@ static int sam4l_flash_command(struct target *target, uint8_t cmd, int page) if (err != 0) LOG_ERROR("%s got error status 0x%08" PRIx32, __func__, err); - res = sam4l_flash_wait_until_ready(target); - - return res; + return sam4l_flash_wait_until_ready(target); } FLASH_BANK_COMMAND_HANDLER(sam4l_flash_bank_command) @@ -282,19 +280,19 @@ static int sam4l_probe(struct flash_bank *bank) chip->ram_kb = sam4l_ram_sizes[0xF & (id >> 16)]; switch (0xF & (id >> 8)) { - case 0x07: - chip->flash_kb = 128; - break; - case 0x09: - chip->flash_kb = 256; - break; - case 0x0A: - chip->flash_kb = 512; - break; - default: - LOG_ERROR("Unknown flash size (chip ID is %08" PRIx32 "), assuming 128K", id); - chip->flash_kb = 128; - break; + case 0x07: + chip->flash_kb = 128; + break; + case 0x09: + chip->flash_kb = 256; + break; + case 0x0A: + chip->flash_kb = 512; + break; + default: + LOG_ERROR("Unknown flash size (chip ID is %08" PRIx32 "), assuming 128K", id); + chip->flash_kb = 128; + break; } /* Retrieve the Flash parameters */ @@ -505,9 +503,7 @@ static int sam4l_write_page(struct sam4l_info *chip, struct target *target, res = sam4l_flash_command(target, SAM4L_FCMD_EP, -1); if (res != ERROR_OK) return res; - res = sam4l_flash_command(target, SAM4L_FCMD_WP, -1); - - return res; + return sam4l_flash_command(target, SAM4L_FCMD_WP, -1); } /* Write partial contents into page-aligned 'address' on the Flash from host diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c index 86c80765fc..a4c92a93c6 100644 --- a/src/flash/nor/at91sam7.c +++ b/src/flash/nor/at91sam7.c @@ -193,44 +193,41 @@ static void at91sam7_read_clock_info(struct flash_bank *bank) at91sam7_info->mck_valid = 0; at91sam7_info->mck_freq = 0; switch (mckr & PMC_MCKR_CSS) { - case 0: /* Slow Clock */ + case 0: /* Slow Clock */ + at91sam7_info->mck_valid = 1; + tmp = RC_FREQ; + break; + + case 1: /* Main Clock */ + if ((mcfr & CKGR_MCFR_MAINRDY) && at91sam7_info->ext_freq == 0) { at91sam7_info->mck_valid = 1; - tmp = RC_FREQ; - break; - - case 1: /* Main Clock */ - if ((mcfr & CKGR_MCFR_MAINRDY) && - (at91sam7_info->ext_freq == 0)) { - at91sam7_info->mck_valid = 1; - tmp = RC_FREQ / 16ul * (mcfr & 0xffff); - } else if (at91sam7_info->ext_freq != 0) { - at91sam7_info->mck_valid = 1; - tmp = at91sam7_info->ext_freq; - } - break; - - case 2: /* Reserved */ - break; - - case 3: /* PLL Clock */ - if ((mcfr & CKGR_MCFR_MAINRDY) && - (at91sam7_info->ext_freq == 0)) { - target_read_u32(target, CKGR_PLLR, &pllr); - if (!(pllr & CKGR_PLLR_DIV)) - break; /* 0 Hz */ - at91sam7_info->mck_valid = 1; - mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff); - /* Integer arithmetic should have sufficient precision - * as long as PLL is properly configured. */ - tmp = mainfreq / (pllr & CKGR_PLLR_DIV)* - (((pllr & CKGR_PLLR_MUL) >> 16) + 1); - } else if ((at91sam7_info->ext_freq != 0) && - ((pllr&CKGR_PLLR_DIV) != 0)) { - at91sam7_info->mck_valid = 1; - tmp = at91sam7_info->ext_freq / (pllr&CKGR_PLLR_DIV)* - (((pllr & CKGR_PLLR_MUL) >> 16) + 1); - } - break; + tmp = RC_FREQ / 16ul * (mcfr & 0xffff); + } else if (at91sam7_info->ext_freq != 0) { + at91sam7_info->mck_valid = 1; + tmp = at91sam7_info->ext_freq; + } + break; + + case 2: /* Reserved */ + break; + + case 3: /* PLL Clock */ + if ((mcfr & CKGR_MCFR_MAINRDY) && at91sam7_info->ext_freq == 0) { + target_read_u32(target, CKGR_PLLR, &pllr); + if (!(pllr & CKGR_PLLR_DIV)) + break; /* 0 Hz */ + at91sam7_info->mck_valid = 1; + mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff); + /* Integer arithmetic should have sufficient precision + * as long as PLL is properly configured. */ + tmp = mainfreq / (pllr & CKGR_PLLR_DIV) * + (((pllr & CKGR_PLLR_MUL) >> 16) + 1); + } else if ((at91sam7_info->ext_freq != 0) && ((pllr & CKGR_PLLR_DIV) != 0)) { + at91sam7_info->mck_valid = 1; + tmp = at91sam7_info->ext_freq / (pllr & CKGR_PLLR_DIV) * + (((pllr & CKGR_PLLR_MUL) >> 16) + 1); + } + break; } /* Prescaler adjust */ @@ -277,7 +274,7 @@ static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode) if (at91sam7_info->mck_freq > 30000000ul) fws = 1; - LOG_DEBUG("fmcn[%i]: %i", bank->bank_number, (int)(fmcn)); + LOG_DEBUG("fmcn[%u]: %" PRIu32, bank->bank_number, fmcn); fmr = fmcn << 16 | fws << 8; target_write_u32(target, mc_fmr[bank->bank_number], fmr); } @@ -291,14 +288,14 @@ static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t wait while ((!((status = at91sam7_get_flash_status(bank->target, bank->bank_number)) & waitbits)) && (timeout-- > 0)) { - LOG_DEBUG("status[%i]: 0x%" PRIx32 "", (int)bank->bank_number, status); + LOG_DEBUG("status[%u]: 0x%" PRIx32, bank->bank_number, status); alive_sleep(1); } - LOG_DEBUG("status[%i]: 0x%" PRIx32 "", bank->bank_number, status); + LOG_DEBUG("status[%u]: 0x%" PRIx32, bank->bank_number, status); if (status & 0x0C) { - LOG_ERROR("status register: 0x%" PRIx32 "", status); + LOG_ERROR("status register: 0x%" PRIx32, status); if (status & 0x4) LOG_ERROR("Lock Error Bit Detected, Operation Abort"); if (status & 0x8) @@ -319,7 +316,7 @@ static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd; target_write_u32(target, mc_fcr[bank->bank_number], fcr); - LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %i, page number: %u", + LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %u, page number: %" PRIu16, fcr, bank->bank_number + 1, pagen); @@ -418,130 +415,130 @@ static int at91sam7_read_part_info(struct flash_bank *bank) /* check flash size */ switch ((cidr >> 8)&0x000F) { - case FLASH_SIZE_8KB: - break; - - case FLASH_SIZE_16KB: - banks_num = 1; - sectors_num = 8; - pages_per_sector = 32; - page_size = 64; - base_address = 0x00100000; - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S161/16"; - } - break; - - case FLASH_SIZE_32KB: - banks_num = 1; - sectors_num = 8; - pages_per_sector = 32; - page_size = 128; - base_address = 0x00100000; - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S321/32"; - } - if (arch == 0x72) { - num_nvmbits = 3; - target_name_t = "AT91SAM7SE32"; - } - break; - - case FLASH_SIZE_64KB: - banks_num = 1; - sectors_num = 16; - pages_per_sector = 32; - page_size = 128; - base_address = 0x00100000; - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S64"; - } - break; - - case FLASH_SIZE_128KB: - banks_num = 1; - sectors_num = 8; - pages_per_sector = 64; - page_size = 256; - base_address = 0x00100000; - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S128"; - } - if (arch == 0x71) { - num_nvmbits = 3; - target_name_t = "AT91SAM7XC128"; - } - if (arch == 0x72) { - num_nvmbits = 3; - target_name_t = "AT91SAM7SE128"; - } - if (arch == 0x75) { - num_nvmbits = 3; - target_name_t = "AT91SAM7X128"; - } - break; - - case FLASH_SIZE_256KB: - banks_num = 1; - sectors_num = 16; - pages_per_sector = 64; - page_size = 256; - base_address = 0x00100000; - if (arch == 0x60) { - num_nvmbits = 3; - target_name_t = "AT91SAM7A3"; - } - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S256"; - } - if (arch == 0x71) { - num_nvmbits = 3; - target_name_t = "AT91SAM7XC256"; - } - if (arch == 0x72) { - num_nvmbits = 3; - target_name_t = "AT91SAM7SE256"; - } - if (arch == 0x75) { - num_nvmbits = 3; - target_name_t = "AT91SAM7X256"; - } - break; - - case FLASH_SIZE_512KB: - banks_num = 2; - sectors_num = 16; - pages_per_sector = 64; - page_size = 256; - base_address = 0x00100000; - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S512"; - } - if (arch == 0x71) { - num_nvmbits = 3; - target_name_t = "AT91SAM7XC512"; - } - if (arch == 0x72) { - num_nvmbits = 3; - target_name_t = "AT91SAM7SE512"; - } - if (arch == 0x75) { - num_nvmbits = 3; - target_name_t = "AT91SAM7X512"; - } - break; + case FLASH_SIZE_8KB: + break; + + case FLASH_SIZE_16KB: + banks_num = 1; + sectors_num = 8; + pages_per_sector = 32; + page_size = 64; + base_address = 0x00100000; + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S161/16"; + } + break; + + case FLASH_SIZE_32KB: + banks_num = 1; + sectors_num = 8; + pages_per_sector = 32; + page_size = 128; + base_address = 0x00100000; + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S321/32"; + } + if (arch == 0x72) { + num_nvmbits = 3; + target_name_t = "AT91SAM7SE32"; + } + break; + + case FLASH_SIZE_64KB: + banks_num = 1; + sectors_num = 16; + pages_per_sector = 32; + page_size = 128; + base_address = 0x00100000; + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S64"; + } + break; + + case FLASH_SIZE_128KB: + banks_num = 1; + sectors_num = 8; + pages_per_sector = 64; + page_size = 256; + base_address = 0x00100000; + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S128"; + } + if (arch == 0x71) { + num_nvmbits = 3; + target_name_t = "AT91SAM7XC128"; + } + if (arch == 0x72) { + num_nvmbits = 3; + target_name_t = "AT91SAM7SE128"; + } + if (arch == 0x75) { + num_nvmbits = 3; + target_name_t = "AT91SAM7X128"; + } + break; + + case FLASH_SIZE_256KB: + banks_num = 1; + sectors_num = 16; + pages_per_sector = 64; + page_size = 256; + base_address = 0x00100000; + if (arch == 0x60) { + num_nvmbits = 3; + target_name_t = "AT91SAM7A3"; + } + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S256"; + } + if (arch == 0x71) { + num_nvmbits = 3; + target_name_t = "AT91SAM7XC256"; + } + if (arch == 0x72) { + num_nvmbits = 3; + target_name_t = "AT91SAM7SE256"; + } + if (arch == 0x75) { + num_nvmbits = 3; + target_name_t = "AT91SAM7X256"; + } + break; + + case FLASH_SIZE_512KB: + banks_num = 2; + sectors_num = 16; + pages_per_sector = 64; + page_size = 256; + base_address = 0x00100000; + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S512"; + } + if (arch == 0x71) { + num_nvmbits = 3; + target_name_t = "AT91SAM7XC512"; + } + if (arch == 0x72) { + num_nvmbits = 3; + target_name_t = "AT91SAM7SE512"; + } + if (arch == 0x75) { + num_nvmbits = 3; + target_name_t = "AT91SAM7X512"; + } + break; - case FLASH_SIZE_1024KB: - break; + case FLASH_SIZE_1024KB: + break; - case FLASH_SIZE_2048KB: - break; + case FLASH_SIZE_2048KB: + break; } if (strcmp(target_name_t, "Unknown") == 0) { @@ -915,7 +912,7 @@ static int at91sam7_write(struct flash_bank *bank, const uint8_t *buffer, uint32 dst_min_alignment = at91sam7_info->pagesize; if (offset % dst_min_alignment) { - LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", + LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, dst_min_alignment); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index d6d8938b67..20f9bedfdc 100644 --- a/src/flash/nor/atsamv.c +++ b/src/flash/nor/atsamv.c @@ -12,6 +12,9 @@ * atsamv, atsams, and atsame support * Copyright (C) 2015 Morgan Quigley * + * atsamv extension of user signature area + * Copyright (C) 2024-2025 Elektroline Inc. + * * 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 @@ -24,6 +27,7 @@ #include "imp.h" #include +#include #define REG_NAME_WIDTH (12) @@ -40,18 +44,39 @@ #define SAMV_EFC_FCMD_SFB (0xB) /* (EFC) Set Fuse Bit */ #define SAMV_EFC_FCMD_CFB (0xC) /* (EFC) Clear Fuse Bit */ #define SAMV_EFC_FCMD_GFB (0xD) /* (EFC) Get Fuse Bit */ +#define SAMV_EFC_FCMD_WUS (0x12) /* (EFC) Write User Signature */ +#define SAMV_EFC_FCMD_EUS (0x13) /* (EFC) Erase User Signature */ +#define SAMV_EFC_FCMD_STUS (0x14) /* (EFC) Start Read User Signature */ +#define SAMV_EFC_FCMD_SPUS (0x15) /* (EFC) Stop Read User Signature */ + +#define SAMV_EFC_FMR_SCOD BIT(16) /* Sequantial Code Optimalization Disable */ + +#define SAMV_EFC_FSR_FRDY_SET 1 +#define SAMV_EFC_FRS_FRDY_CLR 0 #define OFFSET_EFC_FMR 0 #define OFFSET_EFC_FCR 4 #define OFFSET_EFC_FSR 8 #define OFFSET_EFC_FRR 12 +#define TIMEOUT_MS_FRS_CHANGE 10 /* Timeout for FRS ready bit change */ +#define TIMEOUT_MS_CMD_DEFAULT 50 /* Default timeout for command */ +#define TIMEOUT_MS_CMD_ERASE 24000 /* Timeout for erase commands */ + #define SAMV_CHIPID_CIDR (0x400E0940) #define SAMV_NUM_GPNVM_BITS 9 #define SAMV_CONTROLLER_ADDR (0x400e0c00) #define SAMV_SECTOR_SIZE 16384 #define SAMV_PAGE_SIZE 512 #define SAMV_FLASH_BASE 0x00400000 +/* This is a workaround. Flash Signature area is actually located at the + * beginning of the flash memory at the address range overlapping the + * first page of program flash. Since OpenOCD does not support write to + * a bank outside of address range, we use address above maximum 32-bit + * address space. + */ +#define SAMV_FLASH_SIGNATURE_BASE 0x100000000 +#define SAMV_FLASH_SIGNATURE_SIZE SAMV_PAGE_SIZE struct samv_flash_bank { bool probed; @@ -59,6 +84,7 @@ struct samv_flash_bank { unsigned int gpnvm[SAMV_NUM_GPNVM_BITS]; }; + /* The actual sector size of the SAMV7 flash memory is 128K bytes. * 16 sectors for a 2048KB device. The lock regions are 16KB per lock * region, with a 2048KB device having 128 lock regions. @@ -72,6 +98,36 @@ static int samv_efc_get_status(struct target *target, uint32_t *v) return r; } +static int samv_efc_wait_status(struct target *target, uint8_t desired, + int64_t timeout, uint32_t *status) +{ + uint32_t v; + int64_t ms_now, ms_end; + int r; + + if (status) + *status = 0; + + ms_end = timeout + timeval_ms(); + + do { + r = samv_efc_get_status(target, &v); + if (r != ERROR_OK) + return r; + + if (status) + *status = v; + ms_now = timeval_ms(); + if (ms_now > ms_end) { + /* error */ + LOG_ERROR("Command timeout"); + return ERROR_FLASH_BUSY; + } + } while ((v & 1) != desired); + + return ERROR_OK; +} + static int samv_efc_get_result(struct target *target, uint32_t *v) { uint32_t rv; @@ -81,15 +137,20 @@ static int samv_efc_get_result(struct target *target, uint32_t *v) return r; } +static inline int samv_efc_get_mode(struct target *target, uint32_t *v) +{ + return target_read_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FMR, v); +} + +static inline int samv_efc_set_mode(struct target *target, uint32_t v) +{ + return target_write_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FMR, v); +} + static int samv_efc_start_command(struct target *target, - unsigned int command, unsigned int argument) + uint8_t command, unsigned int argument) { uint32_t v; - samv_efc_get_status(target, &v); - if (!(v & 1)) { - LOG_ERROR("flash controller is not ready"); - return ERROR_FAIL; - } v = (0x5A << 24) | (argument << 8) | command; LOG_DEBUG("starting flash command: 0x%08x", (unsigned int)(v)); @@ -100,32 +161,33 @@ static int samv_efc_start_command(struct target *target, } static int samv_efc_perform_command(struct target *target, - unsigned int command, unsigned int argument, uint32_t *status) + uint8_t command, unsigned int argument, uint32_t *status) { int r; uint32_t v; - int64_t ms_now, ms_end; + int64_t timeout; if (status) *status = 0; + r = samv_efc_get_status(target, &v); + if (r != ERROR_OK) + return r; + if ((v & 1) != 0x1) + return ERROR_FAIL; r = samv_efc_start_command(target, command, argument); if (r != ERROR_OK) return r; - ms_end = 10000 + timeval_ms(); + if (command == SAMV_EFC_FCMD_EA || command == SAMV_EFC_FCMD_EPA || + command == SAMV_EFC_FCMD_EUS) + timeout = TIMEOUT_MS_CMD_ERASE; + else + timeout = TIMEOUT_MS_CMD_DEFAULT; - do { - r = samv_efc_get_status(target, &v); - if (r != ERROR_OK) - return r; - ms_now = timeval_ms(); - if (ms_now > ms_end) { - /* error */ - LOG_ERROR("Command timeout"); - return ERROR_FAIL; - } - } while ((v & 1) == 0); + r = samv_efc_wait_status(target, SAMV_EFC_FSR_FRDY_SET, timeout, &v); + if (r != ERROR_OK) + return r; /* if requested, copy the flash controller error bits back to the caller */ if (status) @@ -133,26 +195,71 @@ static int samv_efc_perform_command(struct target *target, return ERROR_OK; } +static int samv_efc_read_sequence(struct target *target, uint8_t start_cmd, + uint8_t stop_cmd, uint8_t *buf, size_t read_size) +{ + uint32_t v; + uint32_t addr = SAMV_FLASH_BASE; + int r; + + samv_efc_get_mode(target, &v); + v |= SAMV_EFC_FMR_SCOD; + samv_efc_set_mode(target, v); + + r = samv_efc_start_command(target, start_cmd, 0); + if (r != ERROR_OK) { + samv_efc_start_command(target, stop_cmd, 0); + goto rs_finish; + } + + r = samv_efc_wait_status(target, SAMV_EFC_FRS_FRDY_CLR, + TIMEOUT_MS_FRS_CHANGE, NULL); + if (r != ERROR_OK) + goto rs_finish; + + r = target_read_memory(target, addr, sizeof(uint32_t), + read_size / sizeof(uint32_t), buf); + if (r != ERROR_OK) { + LOG_ERROR("flash program failed to read page @ 0x%" PRIx32 "", addr); + goto rs_finish; + } + + r = samv_efc_start_command(target, stop_cmd, 0); + if (r != ERROR_OK) + goto rs_finish; + + r = samv_efc_wait_status(target, SAMV_EFC_FSR_FRDY_SET, + TIMEOUT_MS_FRS_CHANGE, NULL); + if (r != ERROR_OK) + goto rs_finish; + +rs_finish: + v &= ~SAMV_EFC_FMR_SCOD; + samv_efc_set_mode(target, v); + + return r; +} + static int samv_erase_pages(struct target *target, int first_page, int num_pages, uint32_t *status) { uint8_t erase_pages; switch (num_pages) { - case 4: - erase_pages = 0x00; - break; - case 8: - erase_pages = 0x01; - break; - case 16: - erase_pages = 0x02; - break; - case 32: - erase_pages = 0x03; - break; - default: - erase_pages = 0x00; - break; + case 4: + erase_pages = 0x00; + break; + case 8: + erase_pages = 0x01; + break; + case 16: + erase_pages = 0x02; + break; + case 32: + erase_pages = 0x03; + break; + default: + erase_pages = 0x00; + break; } /* SAMV_EFC_FCMD_EPA @@ -230,6 +337,17 @@ static int samv_set_gpnvm(struct target *target, unsigned int gpnvm) return r; } +static int samv_erase_user_signature(struct target *target) +{ + int r; + + r = samv_efc_perform_command(target, SAMV_EFC_FCMD_EUS, 0, NULL); + if (r != ERROR_OK) + LOG_ERROR("error performing user signature write"); + + return r; +} + static int samv_flash_unlock(struct target *target, unsigned int start_sector, unsigned int end_sector) { @@ -292,7 +410,6 @@ static int samv_protect_check(struct flash_bank *bank) FLASH_BANK_COMMAND_HANDLER(samv_flash_bank_command) { - LOG_INFO("flash bank command"); struct samv_flash_bank *samv_info; samv_info = calloc(1, sizeof(struct samv_flash_bank)); bank->driver_priv = samv_info; @@ -306,11 +423,19 @@ static int samv_get_device_id(struct flash_bank *bank, uint32_t *device_id) static int samv_probe(struct flash_bank *bank) { + if (bank->base == SAMV_FLASH_SIGNATURE_BASE) { + bank->size = SAMV_FLASH_SIGNATURE_SIZE; + bank->num_sectors = 1; + bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); + bank->sectors[0].size = SAMV_FLASH_SIGNATURE_SIZE; + return ERROR_OK; + } + uint32_t device_id; int r = samv_get_device_id(bank, &device_id); if (r != ERROR_OK) return r; - LOG_INFO("device id = 0x%08" PRIx32 "", device_id); + LOG_INFO("device id = 0x%08" PRIx32, device_id); uint8_t eproc = (device_id >> 5) & 0x7; if (eproc != 0) { @@ -320,18 +445,18 @@ static int samv_probe(struct flash_bank *bank) uint8_t nvm_size_code = (device_id >> 8) & 0xf; switch (nvm_size_code) { - case 10: - bank->size = 512 * 1024; - break; - case 12: - bank->size = 1024 * 1024; - break; - case 14: - bank->size = 2048 * 1024; - break; - default: - LOG_ERROR("unrecognized flash size code: %d", nvm_size_code); - return ERROR_FAIL; + case 10: + bank->size = 512 * 1024; + break; + case 12: + bank->size = 1024 * 1024; + break; + case 14: + bank->size = 2048 * 1024; + break; + default: + LOG_ERROR("unrecognized flash size code: %d", nvm_size_code); + return ERROR_FAIL; } struct samv_flash_bank *samv_info = bank->driver_priv; @@ -377,16 +502,19 @@ static int samv_erase(struct flash_bank *bank, unsigned int first, if (r != ERROR_OK) return r; + if (bank->base == SAMV_FLASH_SIGNATURE_BASE) + return samv_erase_user_signature(bank->target); + /* easy case: we've been requested to erase the entire flash */ if ((first == 0) && ((last + 1) == bank->num_sectors)) return samv_efc_perform_command(bank->target, SAMV_EFC_FCMD_EA, 0, NULL); - LOG_INFO("erasing lock regions %u-%u...", first, last); + LOG_DEBUG("erasing lock regions %u-%u...", first, last); for (unsigned int i = first; i <= last; i++) { uint32_t status; r = samv_erase_pages(bank->target, (i * page_count), page_count, &status); - LOG_INFO("erasing lock region %u", i); + LOG_DEBUG("erasing lock region %u", i); if (r != ERROR_OK) LOG_ERROR("error performing erase page @ lock region number %u", i); if (status & (1 << 2)) { @@ -418,45 +546,130 @@ static int samv_protect(struct flash_bank *bank, int set, unsigned int first, return r; } -static int samv_page_read(struct target *target, +static int samv_read_standard_page(struct target *target, unsigned int page_num, uint8_t *buf) { uint32_t addr = SAMV_FLASH_BASE + page_num * SAMV_PAGE_SIZE; int r = target_read_memory(target, addr, 4, SAMV_PAGE_SIZE / 4, buf); if (r != ERROR_OK) - LOG_ERROR("flash program failed to read page @ 0x%08x", - (unsigned int)(addr)); + LOG_ERROR("flash program failed to read page @ 0x%08" PRIx32 "", + addr); return r; } -static int samv_page_write(struct target *target, +static int samv_read_user_signature(struct target *target, uint8_t *buf) +{ + return samv_efc_read_sequence(target, SAMV_EFC_FCMD_STUS, + SAMV_EFC_FCMD_SPUS, buf, SAMV_PAGE_SIZE); +} + +static int samv_page_read(struct target *target, + target_addr_t base, unsigned int page_num, uint8_t *buf) +{ + int r; + if (base == SAMV_FLASH_SIGNATURE_BASE) + r = samv_read_user_signature(target, buf); + else + r = samv_read_standard_page(target, page_num, buf); + + return r; +} + +static int samv_write_user_signature(struct target *target, + unsigned int pagenum, const uint8_t *buf) +{ + const uint32_t addr = SAMV_FLASH_BASE; + int r; + + r = target_write_memory(target, addr, sizeof(uint32_t), + SAMV_PAGE_SIZE / sizeof(uint32_t), buf); + if (r != ERROR_OK) { + LOG_ERROR("failed to buffer page at 0x%08" PRIx32 "", addr); + return r; + } + + r = samv_efc_perform_command(target, SAMV_EFC_FCMD_WUS, 0, NULL); + if (r != ERROR_OK) + LOG_ERROR("error performing user signature write"); + + return r; +} + +static int samv_write_standard_page(struct target *target, unsigned int pagenum, const uint8_t *buf) { uint32_t status; const uint32_t addr = SAMV_FLASH_BASE + pagenum * SAMV_PAGE_SIZE; int r; - LOG_DEBUG("write page %u at address 0x%08x", pagenum, (unsigned int)addr); + LOG_DEBUG("write page %u at address 0x%08" PRIx32 "", pagenum, addr); r = target_write_memory(target, addr, 4, SAMV_PAGE_SIZE / 4, buf); if (r != ERROR_OK) { - LOG_ERROR("failed to buffer page at 0x%08x", (unsigned int)addr); + LOG_ERROR("failed to buffer page at 0x%08" PRIx32 "", addr); return r; } r = samv_efc_perform_command(target, SAMV_EFC_FCMD_WP, pagenum, &status); if (r != ERROR_OK) - LOG_ERROR("error performing write page at 0x%08x", (unsigned int)addr); + LOG_ERROR("error performing write page at 0x%08" PRIx32 "", addr); if (status & (1 << 2)) { - LOG_ERROR("page at 0x%08x is locked", (unsigned int)addr); + LOG_ERROR("page at 0x%08" PRIx32 " is locked", addr); return ERROR_FAIL; } if (status & (1 << 1)) { - LOG_ERROR("flash command error at 0x%08x", (unsigned int)addr); + LOG_ERROR("flash command error at 0x%08" PRIx32 "", addr); return ERROR_FAIL; } return ERROR_OK; } +static int samv_page_write(struct target *target, + target_addr_t base, unsigned int pagenum, const uint8_t *buf) +{ + int r; + if (base == SAMV_FLASH_SIGNATURE_BASE) + r = samv_write_user_signature(target, pagenum, buf); + else + r = samv_write_standard_page(target, pagenum, buf); + + return r; +} + +static int samv_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + int r; + uint8_t pagebuffer[SAMV_PAGE_SIZE] = {0}; + struct target *target = bank->target; + + LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32 "", offset, count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Reads past end of flash. Extra data discarded."); + count = bank->size - offset; + } + + LOG_DEBUG("offset: 0x%08" PRIx32 ", count: 0x%08" PRIx32 "", offset, count); + + if (bank->base == SAMV_FLASH_SIGNATURE_BASE) { + r = samv_read_user_signature(target, pagebuffer); + if (r != ERROR_OK) + return r; + memcpy(buffer, pagebuffer + offset, count); + } else { + r = target_read_memory(target, offset, 1, count, buffer); + if (r != ERROR_OK) + return r; + } + + return ERROR_OK; +} + static int samv_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { @@ -470,10 +683,10 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, if ((offset + count) > bank->size) { LOG_ERROR("flash write error - past end of bank"); - LOG_ERROR(" offset: 0x%08x, count 0x%08x, bank end: 0x%08x", - (unsigned int)(offset), - (unsigned int)(count), - (unsigned int)(bank->size)); + LOG_ERROR(" offset: 0x%08" PRIx32 ", count 0x%08" PRIx32 ", bank end: 0x%08" PRIx32 "", + offset, + count, + bank->size); return ERROR_FAIL; } @@ -481,9 +694,8 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t page_cur = offset / SAMV_PAGE_SIZE; uint32_t page_end = (offset + count - 1) / SAMV_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)); + LOG_DEBUG("offset: 0x%08" PRIx32 ", count: 0x%08" PRIx32 "", offset, count); + LOG_DEBUG("page start: %" PRIu32 ", page end: %" PRIu32 "", page_cur, page_end); /* Special case: all one page */ /* Otherwise: */ @@ -497,14 +709,14 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, /* handle special case - all one page. */ if (page_cur == page_end) { LOG_DEBUG("special case, all in one page"); - r = samv_page_read(bank->target, page_cur, pagebuffer); + r = samv_page_read(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; - page_offset = offset & (SAMV_PAGE_SIZE-1); + page_offset = offset & (SAMV_PAGE_SIZE - 1); memcpy(pagebuffer + page_offset, buffer, count); - r = samv_page_write(bank->target, page_cur, pagebuffer); + r = samv_page_write(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; return ERROR_OK; @@ -515,7 +727,7 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, if (page_offset) { LOG_DEBUG("non-aligned start"); /* read the partial page */ - r = samv_page_read(bank->target, page_cur, pagebuffer); + r = samv_page_read(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; @@ -523,11 +735,11 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t n = SAMV_PAGE_SIZE - page_offset; memcpy(pagebuffer + page_offset, buffer, n); - r = samv_page_write(bank->target, page_cur, pagebuffer); + r = samv_page_write(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; - count -= n; + count -= n; offset += n; buffer += n; page_cur++; @@ -537,11 +749,11 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, assert(offset % SAMV_PAGE_SIZE == 0); /* step 2) handle the full pages */ - LOG_DEBUG("full page loop: cur=%d, end=%d, count = 0x%08x", - (int)page_cur, (int)page_end, (unsigned int)(count)); + LOG_DEBUG("full page loop: cur=%" PRIu32 ", end=%" PRIu32 ", count = 0x%08" PRIx32 "", + page_cur, page_end, count); while ((page_cur < page_end) && (count >= SAMV_PAGE_SIZE)) { - r = samv_page_write(bank->target, page_cur, buffer); + r = samv_page_write(bank->target, bank->base, page_cur, buffer); if (r != ERROR_OK) return r; count -= SAMV_PAGE_SIZE; @@ -551,13 +763,13 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, /* step 3) write final page, if it's partial (otherwise it's already done) */ if (count) { - LOG_DEBUG("final partial page, count = 0x%08x", (unsigned int)(count)); + LOG_DEBUG("final partial page, count = 0x%08" PRIx32 "", count); /* we have a partial page */ - r = samv_page_read(bank->target, page_cur, pagebuffer); + r = samv_page_read(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; memcpy(pagebuffer, buffer, count); /* data goes at start of page */ - r = samv_page_write(bank->target, page_cur, pagebuffer); + r = samv_page_write(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; } @@ -600,22 +812,22 @@ COMMAND_HANDLER(samv_handle_gpnvm_command) int who = 0; switch (CMD_ARGC) { - case 0: - goto showall; - case 1: + case 0: + goto showall; + case 1: + who = -1; + break; + case 2: + if (!strcmp(CMD_ARGV[0], "show") && !strcmp(CMD_ARGV[1], "all")) { who = -1; - break; - case 2: - if (!strcmp(CMD_ARGV[0], "show") && !strcmp(CMD_ARGV[1], "all")) - who = -1; - else { - uint32_t v32; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); - who = v32; - } - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + } else { + uint32_t v32; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); + who = v32; + } + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } unsigned int v = 0; @@ -691,7 +903,7 @@ const struct flash_driver atsamv_flash = { .erase = samv_erase, .protect = samv_protect, .write = samv_write, - .read = default_flash_read, + .read = samv_read, .probe = samv_probe, .auto_probe = samv_auto_probe, .erase_check = default_flash_blank_check, diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c index 1d317a10c6..af83822490 100644 --- a/src/flash/nor/avrf.c +++ b/src/flash/nor/avrf.c @@ -126,7 +126,7 @@ static int avr_jtagprg_chiperase(struct avr_common *avr) AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; - LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value); + LOG_DEBUG("poll_value = 0x%04" PRIx32, poll_value); } while (!(poll_value & 0x0200)); return ERROR_OK; @@ -187,7 +187,7 @@ static int avr_jtagprg_writeflashpage(struct avr_common *avr, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; - LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value); + LOG_DEBUG("poll_value = 0x%04" PRIx32, poll_value); } while (!(poll_value & 0x0200)); return ERROR_OK; @@ -253,8 +253,8 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } - LOG_DEBUG("offset is 0x%08" PRIx32 "", offset); - LOG_DEBUG("count is %" PRIu32 "", count); + LOG_DEBUG("offset is 0x%08" PRIx32, offset); + LOG_DEBUG("count is %" PRIu32, count); if (avr_jtagprg_enterprogmode(avr) != ERROR_OK) return ERROR_FAIL; @@ -308,7 +308,7 @@ static int avrf_probe(struct flash_bank *bank) if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; - LOG_INFO("device id = 0x%08" PRIx32 "", device_id); + LOG_INFO("device id = 0x%08" PRIx32, device_id); if (EXTRACT_MFG(device_id) != 0x1F) LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), @@ -373,7 +373,7 @@ static int avrf_info(struct flash_bank *bank, struct command_invocation *cmd) if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; - LOG_INFO("device id = 0x%08" PRIx32 "", device_id); + LOG_INFO("device id = 0x%08" PRIx32, device_id); if (EXTRACT_MFG(device_id) != 0x1F) LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), @@ -390,7 +390,7 @@ static int avrf_info(struct flash_bank *bank, struct command_invocation *cmd) if (avr_info) { /* chip found */ - command_print_sameline(cmd, "%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 { diff --git a/src/flash/nor/bl602.c b/src/flash/nor/bl602.c new file mode 100644 index 0000000000..63e15509c1 --- /dev/null +++ b/src/flash/nor/bl602.c @@ -0,0 +1,760 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2024 by Marek Kraus * + * gamelaster@gami.ee * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include +#include +#include "spi.h" +#include "target/riscv/opcodes.h" +#include "target/riscv/gdb_regs.h" + +/* + * Flash bank driver for Bouffalo chips with BL602-like flash controller + * + * Supported chips (series): BL602, BL702 and BL702L + * Not supported but compatible chips (series): BL616, BL606P and BL808 + * + * SFlash supports both direct access and eXecute In Place (XIP) via L1 cache (L1C). + * If XIP is configured and direct access is needed, + * then the state needs to be saved and some settings need to be reset for it to work properly. + * The only way to do this is to save/restore the entire SFlash core configuration, which has not been tested. + * Because of this, on every OpenOCD flash probe, GPIO and SFlash will be reconfigured, resulting in XIP not working. + * So it's recommended to reset the device after every OpenOCD flash operation. + * + * QSPI write is not supported yet. + */ + +// SFlash CFG definitions +#define SFLASH_CFG_SIZE 84 +#define SFLASH_CFG_BUSY_BIT_POS 0x2D +#define SFLASH_CFG_BUSY_INDEX_POS 0x2A +#define SFLASH_CFG_BUSY_READ_REG_LEN_POS 0x33 +#define SFLASH_CFG_FAST_READ_CMD_POS 0x18 +#define SFLASH_CFG_JEDEC_ID_CMD_DMY_CLK_POS 0x09 +#define SFLASH_CFG_JEDEC_ID_CMD_POS 0x08 +#define SFLASH_CFG_PAGE_PROGRAM_CMD_POS 0x15 +#define SFLASH_CFG_PAGE_SIZE_POS 0x0E +#define SFLASH_CFG_READ_STATUS_REG1_POS 0x34 +#define SFLASH_CFG_SECTOR_ERASE_CMD_POS 0x11 +#define SFLASH_CFG_SECTOR_SIZE_POS 0x0C +#define SFLASH_CFG_TIME_ERASE_SECTOR_POS 0x48 +#define SFLASH_CFG_TIME_PAGE_PGM_POS 0x4E +#define SFLASH_CFG_WRITE_ENABLE_BIT_POS 0x2B +#define SFLASH_CFG_WRITE_ENABLE_CMD_POS 0x14 +#define SFLASH_CFG_WRITE_ENABLE_INDEX_POS 0x28 +#define SFLASH_CFG_WRITE_ENABLE_READ_REG_LEN_POS 0x2F + +#define BL602_DEFAULT_TIMEOUT_MS 5000 + +enum bflb_series { + BFLB_SERIES_BL602, + BFLB_SERIES_BL702, + BFLB_SERIES_BL702L, +}; + +struct bl602_part_info { + uint32_t idcode; + enum bflb_series series; + uint32_t romapi_get_jedec_id; + uint32_t romapi_sflash_init_gpio; + uint32_t romapi_sflash_init; + uint32_t romapi_sflash_program; + uint32_t romapi_sflash_read; + uint32_t romapi_sflash_erase_sector; +}; + +struct bl602_flash_bank { + // flag indicating successful flash probe + bool probed; + enum bflb_series series; + const struct bl602_part_info *part_info; + uint8_t sflash_cfg[SFLASH_CFG_SIZE]; + // detected model of SPI flash + const struct flash_device *dev; +}; + +static const struct bl602_part_info bl602_parts[] = { + { + .idcode = 0x20000c05, + .series = BFLB_SERIES_BL602, + .romapi_get_jedec_id = 0x210109bc, + .romapi_sflash_init_gpio = 0x21010a20, + .romapi_sflash_init = 0x21010980, + .romapi_sflash_program = 0x210109b4, + .romapi_sflash_read = 0x210109fc, + .romapi_sflash_erase_sector = 0x210109a4, + }, + { + .idcode = 0x20000e05, + .series = BFLB_SERIES_BL702, + .romapi_get_jedec_id = 0x210189a4, + .romapi_sflash_init_gpio = 0x21018a78, + .romapi_sflash_init = 0x21018960, + .romapi_sflash_program = 0x2101899c, + .romapi_sflash_read = 0x210189d8, + .romapi_sflash_erase_sector = 0x2101898c, + }, + { + .idcode = 0x20000e05, + .series = BFLB_SERIES_BL702L, + .romapi_get_jedec_id = 0x21010d10, + .romapi_sflash_init_gpio = 0x21010c54, + .romapi_sflash_init = 0x21010cc8, + .romapi_sflash_program = 0x21010d08, + .romapi_sflash_read = 0x21010d44, + .romapi_sflash_erase_sector = 0x21010cf8, + }, +}; + +static int bl602_call_func(struct target *target, uint32_t func_addr, + uint32_t arg_data[], unsigned int n_args, uint32_t *return_data, unsigned int timeout_ms) +{ + static const char * const reg_names[] = { "a0", "a1", "a2", "a3", "a4", "a5" }; + struct reg_param reg_params[ARRAY_SIZE(reg_names) + 1]; + unsigned int n_reg_params = 0; + + assert(n_args <= ARRAY_SIZE(reg_names)); // only allow register arguments + + struct working_area *trampoline_algorithm; + + uint32_t trampoline_code[] = { + ebreak(), + }; + + int retval = target_alloc_working_area(target, sizeof(trampoline_code), + &trampoline_algorithm); + if (retval != ERROR_OK) { + LOG_ERROR("No working area available, can't do trampoline"); + return retval; + } + + retval = target_write_buffer(target, trampoline_algorithm->address, + sizeof(trampoline_code), (uint8_t *)trampoline_code); + if (retval != ERROR_OK) { + LOG_ERROR("Writing trampoline code failed, can't do trampoline"); + goto cleanup; + } + + // initialize a0 register, which is used both as arg and also return register. + if (!return_data || n_args > 0) { + init_reg_param(®_params[0], reg_names[0], 32, PARAM_IN); + if (n_args > 0) { + buf_set_u32(reg_params[0].value, 0, 32, arg_data[0]); + reg_params[0].direction = PARAM_IN_OUT; + } + n_reg_params++; + } + // initialize rest of registers, if any + for (unsigned int i = 1; i < n_args; ++i) { + init_reg_param(®_params[i], reg_names[i], 32, PARAM_OUT); + buf_set_u32(reg_params[i].value, 0, 32, arg_data[i]); + n_reg_params++; + } + // set return address to the ebreak instruction in working area + init_reg_param(®_params[n_reg_params], "ra", 32, PARAM_OUT); + buf_set_u32(reg_params[n_reg_params].value, 0, 32, trampoline_algorithm->address); + n_reg_params++; + + retval = target_run_algorithm(target, + 0, NULL, + n_reg_params, reg_params, + func_addr, + trampoline_algorithm->address, + timeout_ms, NULL); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", + trampoline_algorithm->address, retval); + goto cleanup; + } + + if (return_data) + *return_data = buf_get_u32(reg_params[0].value, 0, 32); + +cleanup: + for (unsigned int i = 0; i < n_reg_params; i++) + destroy_reg_param(®_params[i]); + + target_free_working_area(target, trampoline_algorithm); + return retval; +} + +static int bl602_call_romapi_func(struct target *target, uint32_t romapi_func_addr, + uint32_t arg_data[], unsigned int n_args, uint32_t *return_data, unsigned int timeout_ms) +{ + uint32_t func_addr; + + int retval = target_read_u32(target, romapi_func_addr, &func_addr); + if (retval != ERROR_OK) + return retval; + + return bl602_call_func(target, func_addr, arg_data, n_args, return_data, timeout_ms); +} + +static int bl602_alloc_bounce_buffer(struct flash_bank *bank, + struct working_area **working_area, uint32_t count) +{ + struct bl602_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + + unsigned int avail_pages = target_get_working_area_avail(target) / priv->dev->pagesize; + if (avail_pages == 0) { + LOG_ERROR("Not enough space for bounce buffer. Can't continue"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* We try to allocate working area rounded down to device page size, + * at least 1 page, at most the write data size */ + unsigned int chunk_size = MIN(MAX(avail_pages - 1, 1) * priv->dev->pagesize, count); + int retval = target_alloc_working_area(target, chunk_size, working_area); + if (retval != ERROR_OK) { + LOG_ERROR("Could not allocate bounce buffer for flash manipulation. Can't continue"); + return retval; + } + + LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, (*working_area)->address); + + return ERROR_OK; +} + +static int bl602_alloc_sflash_cfg(struct flash_bank *bank, + struct working_area **working_area) +{ + struct bl602_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + + int retval = target_alloc_working_area(target, sizeof(priv->sflash_cfg), + working_area); + if (retval != ERROR_OK) { + LOG_ERROR("No working area available, can't alloc sflash cfg"); + return retval; + } + + retval = target_write_buffer(target, (*working_area)->address, + sizeof(priv->sflash_cfg), priv->sflash_cfg); + if (retval != ERROR_OK) + target_free_working_area(target, *working_area); + return retval; +} + +static int bl602_flash_gpio_init(struct flash_bank *bank) +{ + struct bl602_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + const struct bl602_part_info *part_info = priv->part_info; + + uint32_t flash_pin_cfg = 0; + + // Read device info from eFuse + if (part_info->series == BFLB_SERIES_BL702 || + part_info->series == BFLB_SERIES_BL702L) { + // Read device_info register + uint32_t device_info; + int retval = target_read_u32(target, 0x40007074, &device_info); + if (retval != ERROR_OK || device_info == 0x0) { + /* device_info being 0x0 shouldn't happen, since eFuse is loaded in BootROM, + * but better to handle it */ + LOG_ERROR("Failed to read device info from eFuse"); + return retval; + } + + uint32_t flash_cfg = (device_info >> 26) & 0x03; + uint32_t sf_swap_cfg = (device_info >> 22) & 0x03; + uint32_t sf_reverse_cfg = (device_info >> 29) & 0x01; // BL702L only + if (part_info->series == BFLB_SERIES_BL702) { + flash_pin_cfg = (flash_cfg << 2) | sf_swap_cfg; + } else { // BL702L + flash_pin_cfg = sf_swap_cfg + (sf_reverse_cfg != 0 ? 5 : 1); + } + } else if (part_info->series == BFLB_SERIES_BL602) { + // Structure is not known. + uint32_t sw_usage; + int retval = target_read_u32(target, 0x40007010, &sw_usage); + if (retval != ERROR_OK || sw_usage == 0x0) { + /* sw_usage being 0x0 shouldn't happen, since eFuse is loaded in BootROM, + * but better to handle it */ + LOG_ERROR("Failed to read sw usage from eFuse"); + return retval; + } + + // We only assume it is sf_swap_cfg + uint32_t sf_swap_cfg = (sw_usage >> 16) & 0x03; + flash_pin_cfg = sf_swap_cfg; + } + + // initialize flash GPIOs + uint32_t args[] = { + flash_pin_cfg, + 1, // restoreDefault + }; + + int retval = bl602_call_romapi_func(target, part_info->romapi_sflash_init_gpio, + args, ARRAY_SIZE(args), NULL, BL602_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to invoke spi flash gpio init function"); + return retval; + } + + return ERROR_OK; +} + +static const uint8_t bl602_sflash_ctrl_cfg[] = { + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00 +}; + +/* The structure of SF_Ctrl_Cfg_Type is same as on BL602 and BL702, + * but BL702L's BootROM was compiled without -fshort-enums flag. + * That caused that first three fields (enums) are 4 bytes instead of 1 byte. */ +static const uint8_t bl702l_sflash_ctrl_cfg[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0xe1, 0xfd, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x21, +}; + +static int bl602_flash_init(struct flash_bank *bank) +{ + struct bl602_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + const struct bl602_part_info *part_info = priv->part_info; + + int retval = bl602_flash_gpio_init(bank); + if (retval != ERROR_OK) + return retval; + + // initialize SFlash peripheral + // structure for this can be found in official SDK by name SF_Ctrl_Cfg_Type + const uint8_t *sflash_ctrl_cfg = NULL; + uint16_t sflash_ctrl_cfg_size = 0; + + switch (part_info->series) { + case BFLB_SERIES_BL602: + case BFLB_SERIES_BL702: + sflash_ctrl_cfg = bl602_sflash_ctrl_cfg; + sflash_ctrl_cfg_size = ARRAY_SIZE(bl602_sflash_ctrl_cfg); + break; + case BFLB_SERIES_BL702L: + sflash_ctrl_cfg = bl702l_sflash_ctrl_cfg; + sflash_ctrl_cfg_size = ARRAY_SIZE(bl702l_sflash_ctrl_cfg); + break; + default: + LOG_ERROR("No SFlash Control Config available for this chip"); + return ERROR_NOT_IMPLEMENTED; + } + + struct working_area *sflash_ctrl_cfg_area; + retval = target_alloc_working_area(target, sflash_ctrl_cfg_size, + &sflash_ctrl_cfg_area); + if (retval != ERROR_OK) { + LOG_WARNING("No working area available, can't init SFlash"); + return retval; + } + + retval = target_write_buffer(target, sflash_ctrl_cfg_area->address, + sflash_ctrl_cfg_size, sflash_ctrl_cfg); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write SFlash Control CFG into working area"); + goto cleanup; + } + + uint32_t args[] = { + sflash_ctrl_cfg_area->address, + }; + + retval = bl602_call_romapi_func(target, part_info->romapi_sflash_init, + args, ARRAY_SIZE(args), NULL, BL602_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to invoke SFlash init function"); + goto cleanup; + } + +cleanup: + target_free_working_area(target, sflash_ctrl_cfg_area); + return retval; +} + +static int bl602_flash_read_id(struct flash_bank *bank, uint32_t *jedec_id) +{ + struct bl602_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + const struct bl602_part_info *part_info = priv->part_info; + + struct working_area *data_area; + int retval = target_alloc_working_area(target, sizeof(uint32_t) + SFLASH_CFG_SIZE, + &data_area); + if (retval != ERROR_OK) { + LOG_ERROR("No working area available, can't read flash id"); + return retval; + } + + retval = target_write_buffer(target, data_area->address + sizeof(uint32_t), + SFLASH_CFG_SIZE, priv->sflash_cfg); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write data required for flash id read"); + goto cleanup; + } + + uint32_t args[2] = { + data_area->address + 4, // SFlash CFG + data_area->address, // JEDEC ID pointer + }; + + retval = bl602_call_romapi_func(target, part_info->romapi_get_jedec_id, + args, ARRAY_SIZE(args), NULL, BL602_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to invoke get jedec id function"); + goto cleanup; + } + + retval = target_read_u32(target, data_area->address, jedec_id); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read flash id from target"); + goto cleanup; + } + + *jedec_id &= 0x00FFFFFF; + +cleanup: + target_free_working_area(target, data_area); + + return retval; +} + +static int bl602_erase(struct flash_bank *bank, unsigned int first, + unsigned int last) +{ + struct bl602_flash_bank *priv = bank->driver_priv; + const struct bl602_part_info *part_info = priv->part_info; + struct target *target = bank->target; + struct working_area *sflash_cfg_area = NULL; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = bl602_alloc_sflash_cfg(bank, &sflash_cfg_area); + if (retval != ERROR_OK) + return retval; + + uint32_t return_value; + + for (unsigned int sector = first; sector <= last; sector++) { + LOG_INFO("Erasing sector %d", sector); + uint32_t args[] = { + sflash_cfg_area->address, + sector, + }; + retval = bl602_call_romapi_func(target, part_info->romapi_sflash_erase_sector, + args, ARRAY_SIZE(args), &return_value, BL602_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to invoke flash erase code on target"); + break; + } + if (return_value != 0) { + LOG_ERROR("Erase flash function returned wrong value: %02X", return_value); + retval = ERROR_FAIL; + break; + } + } + + target_free_working_area(target, sflash_cfg_area); + return retval; +} + +static int bl602_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct bl602_flash_bank *priv = bank->driver_priv; + const struct bl602_part_info *part_info = priv->part_info; + struct target *target = bank->target; + struct working_area *bounce_area = NULL; + struct working_area *sflash_cfg_area = NULL; + + 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 > priv->dev->size_in_bytes) { + LOG_WARNING("Write past end of flash. Extra data discarded"); + count = priv->dev->size_in_bytes - offset; + } + + int retval = bl602_alloc_sflash_cfg(bank, &sflash_cfg_area); + if (retval != ERROR_OK) + return retval; + + retval = bl602_alloc_bounce_buffer(bank, &bounce_area, count); + if (retval != ERROR_OK) + goto cleanup; + + unsigned int chunk_size = bounce_area->size; + uint32_t return_value; + + while (count > 0) { + uint32_t write_size = count > chunk_size ? chunk_size : count; + LOG_INFO("Writing %d bytes to offset 0x%" PRIx32, write_size, offset); + retval = target_write_buffer(target, bounce_area->address, write_size, buffer); + if (retval != ERROR_OK) { + LOG_ERROR("Could not load data into target bounce buffer"); + goto cleanup; + } + uint32_t args[] = { + sflash_cfg_area->address, + 0x0, // io_mode + offset, + bounce_area->address, + write_size, + }; + retval = bl602_call_romapi_func(target, part_info->romapi_sflash_program, + args, ARRAY_SIZE(args), &return_value, BL602_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to invoke flash programming code on target"); + goto cleanup; + } + if (return_value != 0) { + LOG_ERROR("Write flash function returned wrong value: %02X", return_value); + retval = ERROR_FAIL; + goto cleanup; + } + + buffer += write_size; + offset += write_size; + count -= write_size; + } + + +cleanup: + target_free_working_area(target, bounce_area); + target_free_working_area(target, sflash_cfg_area); + return retval; +} + +static int bl602_read(struct flash_bank *bank, + uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct bl602_flash_bank *priv = bank->driver_priv; + const struct bl602_part_info *part_info = priv->part_info; + struct target *target = bank->target; + struct working_area *bounce_area = NULL; + struct working_area *sflash_cfg_area = NULL; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > priv->dev->size_in_bytes) { + LOG_WARNING("Read past end of flash"); + count = priv->dev->size_in_bytes - offset; + } + + int retval = bl602_alloc_sflash_cfg(bank, &sflash_cfg_area); + if (retval != ERROR_OK) + return retval; + + retval = bl602_alloc_bounce_buffer(bank, &bounce_area, count); + if (retval != ERROR_OK) + goto cleanup; + + unsigned int chunk_size = bounce_area->size; + + while (count > 0) { + uint32_t read_size = count > chunk_size ? chunk_size : count; + LOG_DEBUG("Read %d bytes from offset 0x%" PRIx32, read_size, offset); + uint32_t args[] = { + sflash_cfg_area->address, + 0x0, // io_mode + false, // continous_read + offset, + bounce_area->address, + read_size, + }; + uint32_t return_value; + retval = bl602_call_romapi_func(target, part_info->romapi_sflash_read, + args, ARRAY_SIZE(args), &return_value, BL602_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to invoke flash read code on target"); + break; + } + if (return_value != 0) { + LOG_ERROR("Read flash function returned wrong value: %02X", return_value); + retval = ERROR_FAIL; + break; + } + + retval = target_read_buffer(target, bounce_area->address, read_size, buffer); + if (retval != ERROR_OK) { + LOG_ERROR("Could not load data from target bounce buffer"); + break; + } + + buffer += read_size; + offset += read_size; + count -= read_size; + } + +cleanup: + target_free_working_area(target, bounce_area); + target_free_working_area(target, sflash_cfg_area); + + return retval; +} + +static int bl602_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct bl602_flash_bank *priv = bank->driver_priv; + + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + + priv->probed = false; + + for (unsigned int n = 0; n < ARRAY_SIZE(bl602_parts); n++) { + const struct bl602_part_info *part_info = &bl602_parts[n]; + if (priv->series == part_info->series) { + if (target->tap->idcode != part_info->idcode) { + LOG_ERROR("TAP IDCODE is not valid for selected chip type"); + return ERROR_FAIL; + } + priv->part_info = part_info; + break; + } + } + + if (!priv->part_info) { + LOG_ERROR("Cannot identify target as an BL602 family device"); + return ERROR_FAIL; + } + + int retval = bl602_flash_init(bank); + if (retval != ERROR_OK) { + LOG_ERROR("Initialization of flash failed"); + return retval; + } + + uint32_t jedec_id; + retval = bl602_flash_read_id(bank, &jedec_id); + if (retval != ERROR_OK) { + LOG_ERROR("Cannot identify flash JEDEC ID"); + return retval; + } + + priv->dev = NULL; + for (const struct flash_device *p = flash_devices; p->name ; p++) { + if (p->device_id == jedec_id) { + priv->dev = p; + break; + } + } + + if (!priv->dev) { + LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", jedec_id); + return ERROR_FAIL; + } + LOG_INFO("Found flash device '%s' (ID 0x%08" PRIx32 ")", priv->dev->name, + priv->dev->device_id); + + // set correct size value + bank->size = priv->dev->size_in_bytes; + bank->num_sectors = bank->size / priv->dev->sectorsize; + bank->write_start_alignment = 8; + bank->write_end_alignment = 8; + + bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors); + if (!bank->sectors) + return ERROR_FAIL; + + priv->sflash_cfg[SFLASH_CFG_PAGE_PROGRAM_CMD_POS] = priv->dev->pprog_cmd; + priv->sflash_cfg[SFLASH_CFG_PAGE_SIZE_POS] = priv->dev->pagesize & 0xFF; + priv->sflash_cfg[SFLASH_CFG_PAGE_SIZE_POS + 1] = (priv->dev->pagesize >> 8) & 0xFF; + priv->sflash_cfg[SFLASH_CFG_FAST_READ_CMD_POS] = priv->dev->read_cmd; + priv->sflash_cfg[SFLASH_CFG_SECTOR_SIZE_POS] = priv->dev->sectorsize / 1024; + priv->sflash_cfg[SFLASH_CFG_SECTOR_ERASE_CMD_POS] = priv->dev->erase_cmd; + + priv->probed = true; + + return retval; +} + +static int bl602_auto_probe(struct flash_bank *bank) +{ + struct bl602_flash_bank *priv = bank->driver_priv; + + if (priv->probed) + return ERROR_OK; + + return bl602_probe(bank); +} + +/* + * flash bank bl602 0 0 0 + */ +FLASH_BANK_COMMAND_HANDLER(bl602_flash_bank_command) +{ + if (CMD_ARGC < 7) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct bl602_flash_bank *priv; + priv = malloc(sizeof(struct bl602_flash_bank)); + priv->probed = false; + priv->part_info = NULL; + + if (strcmp(CMD_ARGV[6], "bl602") == 0) { + priv->series = BFLB_SERIES_BL602; + } else if (strcmp(CMD_ARGV[6], "bl702") == 0) { + priv->series = BFLB_SERIES_BL702; + } else if (strcmp(CMD_ARGV[6], "bl702l") == 0) { + priv->series = BFLB_SERIES_BL702L; + } else { + LOG_ERROR("Unknown BL602 chip type: %s", CMD_ARGV[6]); + free(priv); + return ERROR_FLASH_BANK_INVALID; + } + + // initialize default sflash_cfg fields + priv->sflash_cfg[SFLASH_CFG_JEDEC_ID_CMD_POS] = 0x9F; + priv->sflash_cfg[SFLASH_CFG_JEDEC_ID_CMD_DMY_CLK_POS] = 0x0; + priv->sflash_cfg[SFLASH_CFG_TIME_PAGE_PGM_POS] = 200; + priv->sflash_cfg[SFLASH_CFG_WRITE_ENABLE_CMD_POS] = 0x06; + priv->sflash_cfg[SFLASH_CFG_WRITE_ENABLE_INDEX_POS] = 0; + priv->sflash_cfg[SFLASH_CFG_WRITE_ENABLE_READ_REG_LEN_POS] = 1; + priv->sflash_cfg[SFLASH_CFG_WRITE_ENABLE_BIT_POS] = 1; + priv->sflash_cfg[SFLASH_CFG_READ_STATUS_REG1_POS] = 0x05; + priv->sflash_cfg[SFLASH_CFG_BUSY_INDEX_POS] = 0; + priv->sflash_cfg[SFLASH_CFG_BUSY_READ_REG_LEN_POS] = 1; + priv->sflash_cfg[SFLASH_CFG_BUSY_BIT_POS] = 0; + priv->sflash_cfg[SFLASH_CFG_TIME_ERASE_SECTOR_POS] = 1000 & 0xFF; + priv->sflash_cfg[SFLASH_CFG_TIME_ERASE_SECTOR_POS + 1] = (1000 >> 8) & 0xFF; + + // set up driver_priv + bank->driver_priv = priv; + + return ERROR_OK; +} + +const struct flash_driver bl602_flash = { + .name = "bl602", + .flash_bank_command = bl602_flash_bank_command, + .erase = bl602_erase, + .write = bl602_write, + .read = bl602_read, + .probe = bl602_probe, + .auto_probe = bl602_auto_probe, + .erase_check = default_flash_blank_check, + .free_driver_priv = default_flash_free_driver_priv +}; diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index 9ced2e9718..7bc8ce35c7 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -11,6 +11,7 @@ #include #include "helper/types.h" +#include "helper/align.h" #include #include #include @@ -19,6 +20,7 @@ #define BLUENRG2_JTAG_REG (flash_priv_data_2.jtag_idcode_reg) #define BLUENRGLP_JTAG_REG (flash_priv_data_lp.jtag_idcode_reg) +#define BLUENRGLPF_JTAG_REG (flash_priv_data_lpf.jtag_idcode_reg) #define DIE_ID_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->die_id_reg) #define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg) @@ -63,7 +65,7 @@ static const struct flash_ctrl_priv_data flash_priv_data_lp = { .flash_regs_base = 0x40001000, .flash_page_size = 2048, .jtag_idcode = 0x0201E041, - .part_name = "BLUENRG-LP", + .part_name = "STM32WB07 (BLUENRG-LP)", }; static const struct flash_ctrl_priv_data flash_priv_data_lps = { @@ -73,7 +75,27 @@ static const struct flash_ctrl_priv_data flash_priv_data_lps = { .flash_regs_base = 0x40001000, .flash_page_size = 2048, .jtag_idcode = 0x02028041, - .part_name = "BLUENRG-LPS", + .part_name = "STM32WB05 (BLUENRG-LPS)", +}; + +static const struct flash_ctrl_priv_data flash_priv_data_lpf = { + .die_id_reg = 0x40000000, + .jtag_idcode_reg = 0x40000004, + .flash_base = 0x10040000, + .flash_regs_base = 0x40001000, + .flash_page_size = 2048, + .jtag_idcode = 0x02032041, + .part_name = "STM32WB09 (BLUENRG-LPF)", +}; + +static const struct flash_ctrl_priv_data flash_priv_data_spirit3 = { + .die_id_reg = 0x40000000, + .jtag_idcode_reg = 0x40000004, + .flash_base = 0x10040000, + .flash_regs_base = 0x40001000, + .flash_page_size = 2048, + .jtag_idcode = 0x02027041, + .part_name = "STM32WL33/WL3R (SPIRIT3/3R)", }; struct bluenrgx_flash_bank { @@ -86,7 +108,10 @@ 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_priv_data_lps, + &flash_priv_data_lpf, + &flash_priv_data_spirit3 +}; /* flash_bank bluenrg-x 0 0 0 0 */ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) @@ -130,8 +155,45 @@ static inline int bluenrgx_write_flash_reg(struct flash_bank *bank, uint32_t reg return target_write_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value); } -static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, - unsigned int last) +static int bluenrgx_wait_for_interrupt(struct flash_bank *bank, uint32_t interrupt_flag) +{ + bool flag_raised = false; + for (unsigned int j = 0; j < 100; j++) { + uint32_t value; + if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value) != ERROR_OK) { + LOG_ERROR("Register read failed"); + return ERROR_FAIL; + } + + if (value & interrupt_flag) { + flag_raised = true; + break; + } + } + + /* clear the interrupt */ + if (flag_raised) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, interrupt_flag) != ERROR_OK) { + LOG_ERROR("Cannot clear interrupt flag"); + return ERROR_FAIL; + } + + return ERROR_OK; + } + + LOG_ERROR("Erase command failed (timeout)"); + return ERROR_TIMEOUT_REACHED; +} + +static inline int bluenrgx_wait_for_command(struct flash_bank *bank) +{ + if (bluenrgx_wait_for_interrupt(bank, FLASH_INT_CMDSTART) == ERROR_OK) + return bluenrgx_wait_for_interrupt(bank, FLASH_INT_CMDDONE); + + return ERROR_FAIL; +} + +static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int retval = ERROR_OK; struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; @@ -173,19 +235,8 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, return ERROR_FAIL; } - for (unsigned int i = 0; i < 100; i++) { - uint32_t value; - if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { - LOG_ERROR("Register write failed"); - return ERROR_FAIL; - } - if (value & FLASH_INT_CMDDONE) - break; - if (i == 99) { - LOG_ERROR("Mass erase command failed (timeout)"); - retval = ERROR_FAIL; - } - } + if (bluenrgx_wait_for_command(bank) != ERROR_OK) + return ERROR_FAIL; } else { command = FLASH_CMD_ERASE_PAGE; @@ -209,19 +260,8 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, return ERROR_FAIL; } - for (unsigned int j = 0; j < 100; j++) { - uint32_t value; - if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { - LOG_ERROR("Register write failed"); - return ERROR_FAIL; - } - if (value & FLASH_INT_CMDDONE) - break; - if (j == 99) { - LOG_ERROR("Erase command failed (timeout)"); - retval = ERROR_FAIL; - } - } + if (bluenrgx_wait_for_command(bank) != ERROR_OK) + return ERROR_FAIL; } } @@ -229,12 +269,12 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, } -static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, +static int bluenrgx_write_with_loader(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; struct target *target = bank->target; - uint32_t buffer_size = 16384 + 8; + uint32_t max_buffer_size = 16384 + 8; struct working_area *write_algorithm; struct working_area *write_algorithm_stack; struct working_area *source; @@ -251,22 +291,6 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, #include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc" }; - /* check preconditions */ - if (!bluenrgx_info->probed) - return ERROR_FLASH_BANK_NOT_PROBED; - - if ((offset + count) > bank->size) { - LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %" PRIu32 ", size=%" PRIu32, - (offset + count), - bank->size); - return ERROR_FLASH_DST_OUT_OF_BANK; - } - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); @@ -279,6 +303,23 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) return retval; + /* Compute usable buffer size by excluding 128 bytes for write_algorithm_stack + * and 8 bytes for read and write pointers. + */ + uint32_t buffer_size = target_get_working_area_avail(target) - 128 - 8; + /* buffer size should be multiple of FLASH_DATA_WIDTH*/ + buffer_size = ALIGN_DOWN(buffer_size, FLASH_DATA_WIDTH); + buffer_size += 8; + + 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 > max_buffer_size) { + /* probably won't benefit from more than 16k ... */ + buffer_size = max_buffer_size; + } + /* memory buffer */ if (target_alloc_working_area(target, buffer_size, &source)) { LOG_WARNING("no large enough working area available"); @@ -302,10 +343,10 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, init_reg_param(®_params[4], "sp", 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] + * 34 ldr r6, [sp, #88] * ^^^ offset */ - init_mem_param(&mem_params[0], write_algorithm_stack->address + 80, 32, PARAM_OUT); + init_mem_param(&mem_params[0], write_algorithm_stack->address + 88, 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! @@ -353,6 +394,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, if (error != 0) LOG_ERROR("flash write failed = %08" PRIx32, error); } + if (retval == ERROR_OK) { uint32_t rp; /* Read back rp and check that is valid */ @@ -364,6 +406,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_stack); @@ -378,6 +421,80 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, return retval; } +static int bluenrgx_write_without_loader(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + unsigned int data_count = count / FLASH_DATA_WIDTH; + + while (data_count--) { + /* clear flags */ + if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS, offset >> 2) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (target_write_memory(target, bluenrgx_get_flash_reg(bank, FLASH_REG_DATA0), + FLASH_WORD_LEN, FLASH_DATA_WIDTH_W, buffer) != ERROR_OK) { + LOG_ERROR("Failed to write data"); + return ERROR_FAIL; + } + + if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, FLASH_CMD_BURSTWRITE) != ERROR_OK) { + LOG_ERROR("Failed"); + return ERROR_FAIL; + } + + if (bluenrgx_wait_for_command(bank) != ERROR_OK) + return ERROR_FAIL; + + /* increment offset, and buffer */ + offset += FLASH_DATA_WIDTH; + buffer += FLASH_DATA_WIDTH; + } + + return ERROR_OK; +} + +static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + int retval = ERROR_OK; + + /* check preconditions */ + if (!bluenrgx_info->probed) + return ERROR_FLASH_BANK_NOT_PROBED; + + if ((offset + count) > bank->size) { + LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %" PRIu32 ", size=%" PRIu32, + (offset + count), + bank->size); + return ERROR_FLASH_DST_OUT_OF_BANK; + } + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + assert(offset % FLASH_WORD_LEN == 0); + assert(count % FLASH_WORD_LEN == 0); + + retval = bluenrgx_write_with_loader(bank, buffer, offset, count); + /* 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 = bluenrgx_write_without_loader(bank, buffer, offset, count); + } + return retval; +} + static int bluenrgx_probe(struct flash_bank *bank) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; @@ -387,7 +504,9 @@ static int bluenrgx_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - if ((idcode != flash_priv_data_lp.jtag_idcode) && (idcode != flash_priv_data_lps.jtag_idcode)) { + if (idcode != flash_priv_data_lp.jtag_idcode && idcode != flash_priv_data_lps.jtag_idcode + && idcode != flash_priv_data_lpf.jtag_idcode + && idcode != flash_priv_data_spirit3.jtag_idcode) { retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode); if (retval != ERROR_OK) return retval; @@ -414,7 +533,7 @@ static int bluenrgx_probe(struct flash_bank *bank) return retval; bank->size = (size_info + 1) * FLASH_WORD_LEN; - bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info); + bank->num_sectors = bank->size / FLASH_PAGE_SIZE(bluenrgx_info); bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { @@ -474,4 +593,5 @@ const struct flash_driver bluenrgx_flash = { .protect_check = NULL, .auto_probe = bluenrgx_auto_probe, .info = bluenrgx_get_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/bluenrg-x.h b/src/flash/nor/bluenrg-x.h index 720cb6e618..03c66cd81a 100644 --- a/src/flash/nor/bluenrg-x.h +++ b/src/flash/nor/bluenrg-x.h @@ -28,7 +28,12 @@ #define FLASH_CMD_WRITE 0x33 #define FLASH_CMD_BURSTWRITE 0xCC #define FLASH_INT_CMDDONE 0x01 +#define FLASH_INT_CMDSTART 0x02 +/* Flash Controller constants */ #define FLASH_WORD_LEN 4 +#define FLASH_DATA_WIDTH_W 4 +#define FLASH_DATA_WIDTH 16 + #endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */ diff --git a/src/flash/nor/cc26xx.c b/src/flash/nor/cc26xx.c index 54d61421ce..f7c2011beb 100644 --- a/src/flash/nor/cc26xx.c +++ b/src/flash/nor/cc26xx.c @@ -51,22 +51,22 @@ static uint32_t cc26xx_device_type(uint32_t icepick_id, uint32_t user_id) uint32_t device_type = 0; switch (icepick_id & ICEPICK_ID_MASK) { - case CC26X0_ICEPICK_ID: - device_type = CC26X0_TYPE; - break; - case CC26X1_ICEPICK_ID: - device_type = CC26X1_TYPE; - break; - case CC13X0_ICEPICK_ID: - device_type = CC13X0_TYPE; - break; - case CC13X2_CC26X2_ICEPICK_ID: - default: - if ((user_id & USER_ID_CC13_MASK) != 0) - device_type = CC13X2_TYPE; - else - device_type = CC26X2_TYPE; - break; + case CC26X0_ICEPICK_ID: + device_type = CC26X0_TYPE; + break; + case CC26X1_ICEPICK_ID: + device_type = CC26X1_TYPE; + break; + case CC13X0_ICEPICK_ID: + device_type = CC13X0_TYPE; + break; + case CC13X2_CC26X2_ICEPICK_ID: + default: + if ((user_id & USER_ID_CC13_MASK) != 0) + device_type = CC13X2_TYPE; + else + device_type = CC26X2_TYPE; + break; } return device_type; @@ -77,17 +77,17 @@ static uint32_t cc26xx_sector_length(uint32_t icepick_id) uint32_t sector_length; switch (icepick_id & ICEPICK_ID_MASK) { - case CC26X0_ICEPICK_ID: - case CC26X1_ICEPICK_ID: - case CC13X0_ICEPICK_ID: - /* Chameleon family device */ - sector_length = CC26X0_SECTOR_LENGTH; - break; - case CC13X2_CC26X2_ICEPICK_ID: - default: - /* Agama family device */ - sector_length = CC26X2_SECTOR_LENGTH; - break; + case CC26X0_ICEPICK_ID: + case CC26X1_ICEPICK_ID: + case CC13X0_ICEPICK_ID: + /* Chameleon family device */ + sector_length = CC26X0_SECTOR_LENGTH; + break; + case CC13X2_CC26X2_ICEPICK_ID: + default: + /* Agama family device */ + sector_length = CC26X2_SECTOR_LENGTH; + break; } return sector_length; @@ -112,10 +112,10 @@ static int cc26xx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) return retval; elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; + + keep_alive(); }; if (status != CC26XX_BUFFER_EMPTY) { @@ -321,8 +321,6 @@ static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, struct cc26xx_bank *cc26xx_bank = bank->driver_priv; struct cc26xx_algo_params algo_params[2]; uint32_t size = 0; - long long start_ms; - long long elapsed_ms; uint32_t address; uint32_t index; @@ -343,7 +341,6 @@ static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, /* Write requested data, ping-ponging between two buffers */ index = 0; - start_ms = timeval_ms(); address = bank->base + offset; while (count > 0) { @@ -381,9 +378,7 @@ static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, buffer += size; address += size; - elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); + keep_alive(); } /* If no error yet, wait for last buffer to finish */ @@ -427,31 +422,31 @@ static int cc26xx_probe(struct flash_bank *bank) /* Set up appropriate flash helper algorithm */ switch (cc26xx_bank->icepick_id & ICEPICK_ID_MASK) { - case CC26X0_ICEPICK_ID: - case CC26X1_ICEPICK_ID: - case CC13X0_ICEPICK_ID: - /* Chameleon family device */ - cc26xx_bank->algo_code = cc26x0_algo; - cc26xx_bank->algo_size = sizeof(cc26x0_algo); - cc26xx_bank->algo_working_size = CC26X0_WORKING_SIZE; - cc26xx_bank->buffer_addr[0] = CC26X0_ALGO_BUFFER_0; - cc26xx_bank->buffer_addr[1] = CC26X0_ALGO_BUFFER_1; - cc26xx_bank->params_addr[0] = CC26X0_ALGO_PARAMS_0; - cc26xx_bank->params_addr[1] = CC26X0_ALGO_PARAMS_1; - max_sectors = CC26X0_MAX_SECTORS; - break; - case CC13X2_CC26X2_ICEPICK_ID: - default: - /* Agama family device */ - cc26xx_bank->algo_code = cc26x2_algo; - cc26xx_bank->algo_size = sizeof(cc26x2_algo); - cc26xx_bank->algo_working_size = CC26X2_WORKING_SIZE; - cc26xx_bank->buffer_addr[0] = CC26X2_ALGO_BUFFER_0; - cc26xx_bank->buffer_addr[1] = CC26X2_ALGO_BUFFER_1; - cc26xx_bank->params_addr[0] = CC26X2_ALGO_PARAMS_0; - cc26xx_bank->params_addr[1] = CC26X2_ALGO_PARAMS_1; - max_sectors = CC26X2_MAX_SECTORS; - break; + case CC26X0_ICEPICK_ID: + case CC26X1_ICEPICK_ID: + case CC13X0_ICEPICK_ID: + /* Chameleon family device */ + cc26xx_bank->algo_code = cc26x0_algo; + cc26xx_bank->algo_size = sizeof(cc26x0_algo); + cc26xx_bank->algo_working_size = CC26X0_WORKING_SIZE; + cc26xx_bank->buffer_addr[0] = CC26X0_ALGO_BUFFER_0; + cc26xx_bank->buffer_addr[1] = CC26X0_ALGO_BUFFER_1; + cc26xx_bank->params_addr[0] = CC26X0_ALGO_PARAMS_0; + cc26xx_bank->params_addr[1] = CC26X0_ALGO_PARAMS_1; + max_sectors = CC26X0_MAX_SECTORS; + break; + case CC13X2_CC26X2_ICEPICK_ID: + default: + /* Agama family device */ + cc26xx_bank->algo_code = cc26x2_algo; + cc26xx_bank->algo_size = sizeof(cc26x2_algo); + cc26xx_bank->algo_working_size = CC26X2_WORKING_SIZE; + cc26xx_bank->buffer_addr[0] = CC26X2_ALGO_BUFFER_0; + cc26xx_bank->buffer_addr[1] = CC26X2_ALGO_BUFFER_1; + cc26xx_bank->params_addr[0] = CC26X2_ALGO_PARAMS_0; + cc26xx_bank->params_addr[1] = CC26X2_ALGO_PARAMS_1; + max_sectors = CC26X2_MAX_SECTORS; + break; } retval = target_read_u32(target, CC26XX_FLASH_SIZE_INFO, &value); @@ -505,25 +500,25 @@ static int cc26xx_info(struct flash_bank *bank, struct command_invocation *cmd) const char *device; switch (cc26xx_bank->device_type) { - case CC26X0_TYPE: - device = "CC26x0"; - break; - case CC26X1_TYPE: - device = "CC26x1"; - break; - case CC13X0_TYPE: - device = "CC13x0"; - break; - case CC13X2_TYPE: - device = "CC13x2"; - break; - case CC26X2_TYPE: - device = "CC26x2"; - break; - case CC26XX_NO_TYPE: - default: - device = "Unrecognized"; - break; + case CC26X0_TYPE: + device = "CC26x0"; + break; + case CC26X1_TYPE: + device = "CC26x1"; + break; + case CC13X0_TYPE: + device = "CC13x0"; + break; + case CC13X2_TYPE: + device = "CC13x2"; + break; + case CC26X2_TYPE: + device = "CC26x2"; + break; + case CC26XX_NO_TYPE: + default: + device = "Unrecognized"; + break; } command_print_sameline(cmd, diff --git a/src/flash/nor/cc3220sf.c b/src/flash/nor/cc3220sf.c index 74cb7aea57..0418aeac2b 100644 --- a/src/flash/nor/cc3220sf.c +++ b/src/flash/nor/cc3220sf.c @@ -65,10 +65,10 @@ static int cc3220sf_mass_erase(struct flash_bank *bank) done = true; } else { elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; + + keep_alive(); } } @@ -152,10 +152,10 @@ static int cc3220sf_erase(struct flash_bank *bank, unsigned int first, done = true; } else { elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; + + keep_alive(); } } diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index 2a15e49132..108b66750c 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -945,14 +945,14 @@ int cfi_erase(struct flash_bank *bank, unsigned int first, return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { - case 1: - case 3: - return cfi_intel_erase(bank, first, last); - case 2: - return cfi_spansion_erase(bank, first, last); - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + case 1: + case 3: + return cfi_intel_erase(bank, first, last); + case 2: + return cfi_spansion_erase(bank, first, last); + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } return ERROR_OK; @@ -1084,12 +1084,12 @@ int cfi_protect(struct flash_bank *bank, int set, unsigned int first, return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { - case 1: - case 3: - return cfi_intel_protect(bank, set, first, last); - default: - LOG_WARNING("protect: cfi primary command set %i unsupported", cfi_info->pri_id); - return ERROR_OK; + case 1: + case 3: + return cfi_intel_protect(bank, set, first, last); + default: + LOG_WARNING("protect: cfi primary command set %i unsupported", cfi_info->pri_id); + return ERROR_OK; } } @@ -1100,16 +1100,16 @@ static uint32_t cfi_command_val(struct flash_bank *bank, uint8_t cmd) uint8_t buf[CFI_MAX_BUS_WIDTH]; cfi_command(bank, cmd, buf); switch (bank->bus_width) { - case 1: - return buf[0]; - case 2: - return target_buffer_get_u16(target, buf); - case 4: - return target_buffer_get_u32(target, buf); - default: - LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", - bank->bus_width); - return 0; + case 1: + return buf[0]; + case 2: + return target_buffer_get_u16(target, buf); + case 4: + return target_buffer_get_u32(target, buf); + default: + LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", + bank->bus_width); + return 0; } } @@ -1214,22 +1214,22 @@ static int cfi_intel_write_block(struct flash_bank *bank, const uint8_t *buffer, /* prepare algorithm code for target endian */ switch (bank->bus_width) { - case 1: - target_code_src = word_8_code; - target_code_size = sizeof(word_8_code); - break; - case 2: - target_code_src = word_16_code; - target_code_size = sizeof(word_16_code); - break; - case 4: - target_code_src = word_32_code; - target_code_size = sizeof(word_32_code); - break; - default: - LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", - bank->bus_width); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + case 1: + target_code_src = word_8_code; + target_code_size = sizeof(word_8_code); + break; + case 2: + target_code_src = word_16_code; + target_code_size = sizeof(word_16_code); + break; + case 4: + target_code_src = word_32_code; + target_code_size = sizeof(word_32_code); + break; + default: + LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", + bank->bus_width); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ @@ -1448,22 +1448,22 @@ static int cfi_spansion_write_block_mips(struct flash_bank *bank, const uint8_t const uint32_t *target_code_src = NULL; switch (bank->bus_width) { - case 2: - /* Check for DQ5 support */ - if (cfi_info->status_poll_mask & (1 << 5)) { - target_code_src = mips_word_16_code; - target_code_size = sizeof(mips_word_16_code); - } else { - LOG_ERROR("Need DQ5 support"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - /* target_code_src = mips_word_16_code_dq7only; */ - /* target_code_size = sizeof(mips_word_16_code_dq7only); */ - } - break; - default: - LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", - bank->bus_width); + case 2: + /* Check for DQ5 support */ + if (cfi_info->status_poll_mask & (1 << 5)) { + target_code_src = mips_word_16_code; + target_code_size = sizeof(mips_word_16_code); + } else { + LOG_ERROR("Need DQ5 support"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + /* target_code_src = mips_word_16_code_dq7only; */ + /* target_code_size = sizeof(mips_word_16_code_dq7only); */ + } + break; + default: + LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", + bank->bus_width); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ @@ -1800,49 +1800,49 @@ static int cfi_spansion_write_block(struct flash_bank *bank, const uint8_t *buff const uint32_t *target_code_src = NULL; switch (bank->bus_width) { - case 1: + case 1: + if (is_armv7m(target_to_armv7m(target))) { + LOG_ERROR("Unknown ARM architecture"); + return ERROR_FAIL; + } + target_code_src = armv4_5_word_8_code; + target_code_size = sizeof(armv4_5_word_8_code); + break; + case 2: + /* Check for DQ5 support */ + if (cfi_info->status_poll_mask & (1 << 5)) { if (is_armv7m(target_to_armv7m(target))) { - LOG_ERROR("Unknown ARM architecture"); - return ERROR_FAIL; + /* armv7m target */ + target_code_src = armv7m_word_16_code; + target_code_size = sizeof(armv7m_word_16_code); + } else { /* armv4_5 target */ + target_code_src = armv4_5_word_16_code; + target_code_size = sizeof(armv4_5_word_16_code); } - target_code_src = armv4_5_word_8_code; - target_code_size = sizeof(armv4_5_word_8_code); - break; - case 2: - /* Check for DQ5 support */ - if (cfi_info->status_poll_mask & (1 << 5)) { - if (is_armv7m(target_to_armv7m(target))) { - /* armv7m target */ - target_code_src = armv7m_word_16_code; - target_code_size = sizeof(armv7m_word_16_code); - } else { /* armv4_5 target */ - target_code_src = armv4_5_word_16_code; - target_code_size = sizeof(armv4_5_word_16_code); - } - } else { - /* No DQ5 support. Use DQ7 DATA# polling only. */ - if (is_armv7m(target_to_armv7m(target))) { - /* armv7m target */ - target_code_src = armv7m_word_16_code_dq7only; - target_code_size = sizeof(armv7m_word_16_code_dq7only); - } else { /* armv4_5 target */ - target_code_src = armv4_5_word_16_code_dq7only; - target_code_size = sizeof(armv4_5_word_16_code_dq7only); - } - } - break; - case 4: + } else { + /* No DQ5 support. Use DQ7 DATA# polling only. */ if (is_armv7m(target_to_armv7m(target))) { - LOG_ERROR("Unknown ARM architecture"); - return ERROR_FAIL; + /* armv7m target */ + target_code_src = armv7m_word_16_code_dq7only; + target_code_size = sizeof(armv7m_word_16_code_dq7only); + } else { /* armv4_5 target */ + target_code_src = armv4_5_word_16_code_dq7only; + target_code_size = sizeof(armv4_5_word_16_code_dq7only); } - target_code_src = armv4_5_word_32_code; - target_code_size = sizeof(armv4_5_word_32_code); - break; - default: - LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", - bank->bus_width); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + break; + case 4: + if (is_armv7m(target_to_armv7m(target))) { + LOG_ERROR("Unknown ARM architecture"); + return ERROR_FAIL; + } + target_code_src = armv4_5_word_32_code; + target_code_size = sizeof(armv4_5_word_32_code); + break; + default: + LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", + bank->bus_width); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ @@ -2172,14 +2172,14 @@ int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) struct cfi_flash_bank *cfi_info = bank->driver_priv; switch (cfi_info->pri_id) { - case 1: - case 3: - return cfi_intel_write_word(bank, word, address); - case 2: - return cfi_spansion_write_word(bank, word, address); - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + case 1: + case 3: + return cfi_intel_write_word(bank, word, address); + case 2: + return cfi_spansion_write_word(bank, word, address); + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } return ERROR_FLASH_OPERATION_FAILED; @@ -2197,14 +2197,14 @@ static int cfi_write_words(struct flash_bank *bank, const uint8_t *word, } switch (cfi_info->pri_id) { - case 1: - case 3: - return cfi_intel_write_words(bank, word, wordcount, address); - case 2: - return cfi_spansion_write_words(bank, word, wordcount, address); - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + case 1: + case 3: + return cfi_intel_write_words(bank, word, wordcount, address); + case 2: + return cfi_spansion_write_words(bank, word, wordcount, address); + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } return ERROR_FLASH_OPERATION_FAILED; @@ -2345,18 +2345,18 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of /* handle blocks of bus_size aligned bytes */ blk_count = count & ~(bank->bus_width - 1); /* round down, leave tail bytes */ switch (cfi_info->pri_id) { - /* try block writes (fails without working area) */ - case 1: - case 3: - retval = cfi_intel_write_block(bank, buffer, write_p, blk_count); - break; - case 2: - retval = cfi_spansion_write_block(bank, buffer, write_p, blk_count); - break; - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - retval = ERROR_FLASH_OPERATION_FAILED; - break; + /* try block writes (fails without working area) */ + case 1: + case 3: + retval = cfi_intel_write_block(bank, buffer, write_p, blk_count); + break; + case 2: + retval = cfi_spansion_write_block(bank, buffer, write_p, blk_count); + break; + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + retval = ERROR_FLASH_OPERATION_FAILED; + break; } if (retval == ERROR_OK) { /* Increment pointers and decrease count on successful block write */ @@ -2581,22 +2581,22 @@ int cfi_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; switch (bank->chip_width) { - case 1: - cfi_info->manufacturer = *value_buf0; - cfi_info->device_id = *value_buf1; - break; - case 2: - cfi_info->manufacturer = target_buffer_get_u16(target, value_buf0); - cfi_info->device_id = target_buffer_get_u16(target, value_buf1); - break; - case 4: - cfi_info->manufacturer = target_buffer_get_u32(target, value_buf0); - cfi_info->device_id = target_buffer_get_u32(target, value_buf1); - break; - default: - LOG_ERROR("Unsupported bank chipwidth %u, can't probe memory", - bank->chip_width); - return ERROR_FLASH_OPERATION_FAILED; + case 1: + cfi_info->manufacturer = *value_buf0; + cfi_info->device_id = *value_buf1; + break; + case 2: + cfi_info->manufacturer = target_buffer_get_u16(target, value_buf0); + cfi_info->device_id = target_buffer_get_u16(target, value_buf1); + break; + case 4: + cfi_info->manufacturer = target_buffer_get_u32(target, value_buf0); + cfi_info->device_id = target_buffer_get_u32(target, value_buf1); + break; + default: + LOG_ERROR("Unsupported bank chipwidth %u, can't probe memory", + bank->chip_width); + return ERROR_FLASH_OPERATION_FAILED; } LOG_INFO("Flash Manufacturer/Device: 0x%04x 0x%04x", @@ -2722,7 +2722,7 @@ int cfi_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; LOG_DEBUG( - "erase region[%i]: %" PRIu32 " blocks of size 0x%" PRIx32 "", + "erase region[%i]: %" PRIu32 " blocks of size 0x%" PRIx32, i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256); @@ -2734,25 +2734,25 @@ int cfi_probe(struct flash_bank *bank) * the sector layout to be able to apply fixups */ switch (cfi_info->pri_id) { - /* Intel command set (standard and extended) */ - case 0x0001: - case 0x0003: - cfi_read_intel_pri_ext(bank); - break; - /* AMD/Spansion, Atmel, ... command set */ - case 0x0002: - cfi_info->status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7; /* - *default - *for - *all - *CFI - *flashes - **/ - cfi_read_0002_pri_ext(bank); - break; - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + /* Intel command set (standard and extended) */ + case 0x0001: + case 0x0003: + cfi_read_intel_pri_ext(bank); + break; + /* AMD/Spansion, Atmel, ... command set */ + case 0x0002: + cfi_info->status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7; /* + *default + *for + *all + *CFI + *flashes + **/ + cfi_read_0002_pri_ext(bank); + break; + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } /* return to read array mode @@ -2798,18 +2798,18 @@ int cfi_probe(struct flash_bank *bank) /* apply fixups depending on the primary command set */ switch (cfi_info->pri_id) { - /* Intel command set (standard and extended) */ - case 0x0001: - case 0x0003: - cfi_fixup(bank, cfi_0001_fixups); - break; - /* AMD/Spansion, Atmel, ... command set */ - case 0x0002: - cfi_fixup(bank, cfi_0002_fixups); - break; - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + /* Intel command set (standard and extended) */ + case 0x0001: + case 0x0003: + cfi_fixup(bank, cfi_0001_fixups); + break; + /* AMD/Spansion, Atmel, ... command set */ + case 0x0002: + cfi_fixup(bank, cfi_0002_fixups); + break; + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } if ((cfi_info->dev_size * bank->bus_width / bank->chip_width) != bank->size) { @@ -2849,7 +2849,7 @@ int cfi_probe(struct flash_bank *bank) } if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width)) { LOG_WARNING( - "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", + "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32, (cfi_info->dev_size * bank->bus_width / bank->chip_width), offset); } @@ -2939,14 +2939,14 @@ int cfi_protect_check(struct flash_bank *bank) return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { - case 1: - case 3: - return cfi_intel_protect_check(bank); - case 2: - return cfi_spansion_protect_check(bank); - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + case 1: + case 3: + return cfi_intel_protect_check(bank); + case 2: + return cfi_spansion_protect_check(bank); + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } return ERROR_OK; @@ -3011,16 +3011,16 @@ int cfi_get_info(struct flash_bank *bank, struct command_invocation *cmd) 1 << cfi_info->max_buf_write_size); switch (cfi_info->pri_id) { - case 1: - case 3: - cfi_intel_info(bank, cmd); - break; - case 2: - cfi_spansion_info(bank, cmd); - break; - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + case 1: + case 3: + cfi_intel_info(bank, cmd); + break; + case 2: + cfi_spansion_info(bank, cmd); + break; + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } return ERROR_OK; diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 5c4f2accaf..2c41d18530 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -44,6 +44,11 @@ int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first, int retval; unsigned int num_blocks; + if (!bank->driver->protect) { + LOG_ERROR("Flash protection is not supported"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + if (bank->num_prot_blocks) num_blocks = bank->num_prot_blocks; else @@ -59,11 +64,6 @@ int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first, /* force "set" to 0/1 */ set = !!set; - if (!bank->driver->protect) { - LOG_ERROR("Flash protection is not supported."); - return ERROR_FLASH_OPER_UNSUPPORTED; - } - /* DANGER! * * We must not use any cached information about protection state!!!! @@ -223,15 +223,8 @@ void flash_free_all_banks(void) else LOG_WARNING("Flash driver of %s does not support free_driver_priv()", bank->name); - /* For 'virtual' flash driver bank->sectors and bank->prot_blocks pointers are copied from - * master flash_bank structure. They point to memory locations allocated by master flash driver - * so master driver is responsible for releasing them. - * Avoid UB caused by double-free memory corruption if flash bank is 'virtual'. */ - - if (strcmp(bank->driver->name, "virtual") != 0) { - free(bank->sectors); - free(bank->prot_blocks); - } + free(bank->sectors); + free(bank->prot_blocks); free(bank->name); free(bank); @@ -343,6 +336,10 @@ static int default_flash_mem_blank_check(struct flash_bank *bank) } uint8_t *buffer = malloc(buffer_size); + if (!buffer) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } for (unsigned int i = 0; i < bank->num_sectors; i++) { uint32_t j; @@ -389,8 +386,10 @@ 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) + if (!block_array) { + LOG_WARNING("Running slow fallback erase check - limited host memory available"); return default_flash_mem_blank_check(bank); + } for (unsigned int i = 0; i < bank->num_sectors; i++) { block_array[i].address = bank->base + bank->sectors[i].offset; @@ -400,17 +399,18 @@ int default_flash_blank_check(struct flash_bank *bank) bool fast_check = true; for (unsigned int i = 0; i < bank->num_sectors; ) { + unsigned int checked; retval = target_blank_check_memory(target, block_array + i, bank->num_sectors - i, - bank->erased_value); - if (retval < 1) { + bank->erased_value, &checked); + if (retval != ERROR_OK) { /* Run slow fallback if the first run gives no result * otherwise use possibly incomplete results */ if (i == 0) fast_check = false; break; } - i += retval; /* add number of blocks done this round */ + i += checked; /* add number of blocks done this round */ } if (fast_check) { @@ -419,9 +419,9 @@ int default_flash_blank_check(struct flash_bank *bank) retval = ERROR_OK; } else { if (retval == ERROR_NOT_IMPLEMENTED) - LOG_USER("Running slow fallback erase check"); + LOG_DEBUG("Running slow fallback erase check"); else - LOG_USER("Running slow fallback erase check - add working memory"); + LOG_WARNING("Running slow fallback erase check - add working memory"); retval = default_flash_mem_blank_check(bank); } @@ -735,11 +735,25 @@ int flash_write_unlock_verify(struct target *target, struct image *image, unsigned int section; uint32_t section_offset; struct flash_bank *c; - int *padding; section = 0; section_offset = 0; + /* allocate padding array */ + int *padding = calloc(image->num_sections, sizeof(*padding)); + + /* This fn requires all sections to be in ascending order of addresses, + * whereas an image can have sections out of order. */ + struct imagesection **sections = malloc(sizeof(struct imagesection *) * + image->num_sections); + + if (!padding || !sections) { + LOG_ERROR("Out of memory"); + free(padding); + free(sections); + return ERROR_FAIL; + } + if (written) *written = 0; @@ -750,14 +764,6 @@ int flash_write_unlock_verify(struct target *target, struct image *image, flash_set_dirty(); } - /* allocate padding array */ - padding = calloc(image->num_sections, sizeof(*padding)); - - /* This fn requires all sections to be in ascending order of addresses, - * whereas an image can have sections out of order. */ - struct imagesection **sections = malloc(sizeof(struct imagesection *) * - image->num_sections); - for (unsigned int i = 0; i < image->num_sections; i++) sections[i] = &image->sections[i]; diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index f8cf5e2698..55ea3c7e5b 100644 --- a/src/flash/nor/core.h +++ b/src/flash/nor/core.h @@ -84,6 +84,8 @@ struct flash_bank { target_addr_t base; /**< The base address of this bank */ uint32_t size; /**< The size of this chip bank, in bytes */ + bool read_only; /**< a ROM region - mainly to list in gdb memory map */ + unsigned int chip_width; /**< Width of the chip in bytes (1,2,4 bytes) */ unsigned int bus_width; /**< Maximum bus width, in bytes (1,2,4 bytes) */ diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 3b57ef9ff0..afb73a3fb2 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -237,9 +237,11 @@ struct flash_driver { */ const struct flash_driver *flash_driver_find_by_name(const char *name); +// Keep in alphabetic order this list of drivers 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 artery_flash; extern const struct flash_driver at91sam3_flash; extern const struct flash_driver at91sam4_flash; extern const struct flash_driver at91sam4l_flash; @@ -249,6 +251,7 @@ 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 bl602_flash; extern const struct flash_driver bluenrgx_flash; extern const struct flash_driver cc26xx_flash; extern const struct flash_driver cc3220sf_flash; @@ -263,6 +266,7 @@ 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 hpm_xpi_flash; extern const struct flash_driver jtagspi_flash; extern const struct flash_driver kinetis_flash; extern const struct flash_driver kinetis_ke_flash; @@ -288,7 +292,9 @@ 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 read_only_flash; extern const struct flash_driver renesas_rpchf_flash; +extern const struct flash_driver ro_alias_flash; extern const struct flash_driver rp2xxx_flash; extern const struct flash_driver rsl10_flash; extern const struct flash_driver sh_qspi_flash; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3770bfbd3c..094b5a76ba 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -7,6 +7,8 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif + +#include #include "imp.h" /** @@ -14,9 +16,11 @@ * @todo Make this dynamically extendable with loadable modules. */ static const struct flash_driver * const flash_drivers[] = { + // Keep in alphabetic order the list of drivers &aduc702x_flash, &aducm360_flash, &ambiqmicro_flash, + &artery_flash, &at91sam3_flash, &at91sam4_flash, &at91sam4l_flash, @@ -26,9 +30,10 @@ static const struct flash_driver * const flash_drivers[] = { &atsame5_flash, &atsamv_flash, &avr_flash, + &bl602_flash, &bluenrgx_flash, - &cc3220sf_flash, &cc26xx_flash, + &cc3220sf_flash, &cfi_flash, &dsp5680xx_flash, &dw_spi_flash, @@ -37,9 +42,10 @@ static const struct flash_driver * const flash_drivers[] = { &eneispif_flash, &esirisc_flash, &faux_flash, + &fespi_flash, &fm3_flash, &fm4_flash, - &fespi_flash, + &hpm_xpi_flash, &jtagspi_flash, &kinetis_flash, &kinetis_ke_flash, @@ -54,46 +60,47 @@ static const struct flash_driver * const flash_drivers[] = { &mspm0_flash, &niietcm4_flash, &npcx_flash, - &nrf5_flash, &nrf51_flash, + &nrf5_flash, &numicro_flash, &ocl_flash, &pic32mx_flash, &psoc4_flash, - &psoc5lp_flash, &psoc5lp_eeprom_flash, + &psoc5lp_flash, &psoc5lp_nvl_flash, &psoc6_flash, &qn908x_flash, + &read_only_flash, + &ro_alias_flash, &renesas_rpchf_flash, &rp2xxx_flash, + &rsl10_flash, &sh_qspi_flash, &sim3x_flash, &stellaris_flash, &stm32f1x_flash, &stm32f2x_flash, - &stm32lx_flash, - &stm32l4x_flash, &stm32h7x_flash, - &stmsmi_flash, + &stm32l4x_flash, + &stm32lx_flash, &stmqspi_flash, + &stmsmi_flash, &str7x_flash, &str9x_flash, &str9xpec_flash, &swm050_flash, &tms470_flash, &virtual_flash, + &w600_flash, &xcf_flash, &xmc1xxx_flash, &xmc4xxx_flash, - &w600_flash, - &rsl10_flash, - NULL, }; const struct flash_driver *flash_driver_find_by_name(const char *name) { - for (unsigned int i = 0; flash_drivers[i]; i++) { + for (size_t i = 0; i < ARRAY_SIZE(flash_drivers); i++) { if (strcmp(name, flash_drivers[i]->name) == 0) return flash_drivers[i]; } diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index f8e0886570..9f5f1b111e 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -16,8 +16,17 @@ * Copyright (C) 2014 Nemui Trinomius * * nemuisan_kawausogasuki@live.jp * * * + * Copyright (C) 2021 Michael Teichgräber * + * mteichgraeber@gmx.de * + * * * Copyright (C) 2021 Doug Brunner * * doug.a.brunner@gmail.com * + * * + * Copyright (C) 2022 Mikrodust AB * + * henrik.persson@mikrodust.com * + * * + * Copyright (c) 2026 Silicon Laboratories Inc. * + * jerome.pouiller@silabs.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -26,57 +35,143 @@ #include "imp.h" #include +#include #include #include #include -#define EFM_FAMILY_ID_GIANT_GECKO 72 -#define EFM_FAMILY_ID_LEOPARD_GECKO 74 - -#define EFM32_FLASH_ERASE_TMO 100 -#define EFM32_FLASH_WDATAREADY_TMO 100 -#define EFM32_FLASH_WRITE_TMO 100 +/* Datasheet specifies ~22ms for page erase on first chip generation. 100ms + * provides reasonable margin. + */ +#define EFM32_FLASH_OPERATION_TIMEOUT 100 -#define EFM32_FLASH_BASE 0 +#define EFM32_FLASH_BASE_V1 0x00000000 +#define EFM32_FLASH_BASE_V2 0x08000000 /* size in bytes, not words; must fit all Gecko devices */ -#define LOCKWORDS_SZ 512 +#define LOCKWORDS_SZ 512 #define EFM32_MSC_INFO_BASE 0x0fe00000 +#define EFM32_MSC_USER_DATA (EFM32_MSC_INFO_BASE + 0x0000) +#define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE + 0x4000) +#define EFM32_MSC_LOCK_BITS_EXTRA (EFM32_MSC_INFO_BASE + 0x4200) + +struct efm32_dev_info_addr { + target_addr_t part_num; + target_addr_t part_rev; +#define EFM32_DI_PARTINFO_NUM_MASK 0x0000ffff +#define EFM32_DI_PARTINFO_FAMILY_MASK 0x00ff0000 +#define EFM32_DI_PARTINFO_TYPE_MASK 0x3f000000 + target_addr_t part_info; +#define EFM32_DI_PARTINFO_PAGE_SZ_MASK 0x000000ff +#define EFM32_DI_PARTINFO_PAGE_SZ_UD_MASK 0x0000ff00 + target_addr_t page_size; + target_addr_t flash_sz; + target_addr_t ram_sz; +}; + +#define EFM32_DI_PART_FAMILY (EFM32_MSC_INFO_BASE + 0x81fe) + +static const struct efm32_dev_info_addr efm32_dev_info_addr[] = { + [0] = { + .part_num = EFM32_MSC_INFO_BASE + 0x81fc, + .part_rev = EFM32_MSC_INFO_BASE + 0x81ff, + .part_info = 0x00000000, // Not used in Series 0/1 + .page_size = EFM32_MSC_INFO_BASE + 0x81e7, + .flash_sz = EFM32_MSC_INFO_BASE + 0x81f8, + .ram_sz = EFM32_MSC_INFO_BASE + 0x81fa, + }, + [1] = { + .part_num = EFM32_MSC_INFO_BASE + 0x81fc, + .part_rev = EFM32_MSC_INFO_BASE + 0x81ff, + .part_info = 0x0000000, // Not used in Series 0/1 + .page_size = EFM32_MSC_INFO_BASE + 0x81e7, + .flash_sz = EFM32_MSC_INFO_BASE + 0x81f8, + .ram_sz = EFM32_MSC_INFO_BASE + 0x81fa, + }, + [2] = { + .part_num = 0x00000000, // Not used in Series 2 + .part_rev = EFM32_MSC_INFO_BASE + 0x8002, + .part_info = EFM32_MSC_INFO_BASE + 0x8004, + .page_size = EFM32_MSC_INFO_BASE + 0x8008, + .flash_sz = EFM32_MSC_INFO_BASE + 0x800c, + .ram_sz = EFM32_MSC_INFO_BASE + 0x800e, + }, +}; + +// Offsets relative to msc_regbase +struct efm32_msc_offset { +#define EFM32_MSC_WRITECTRL_WREN_MASK 0x0001 + target_addr_t off_writectrl; + +#define EFM32_MSC_WRITECMD_LADDRIM_MASK 0x0001 +#define EFM32_MSC_WRITECMD_ERASEPAGE_MASK 0x0002 +#define EFM32_MSC_WRITECMD_WRITEONCE_MASK 0x0008 + target_addr_t off_writecmd; + target_addr_t off_addrb; + target_addr_t off_wdata; + target_addr_t off_userdatasize; + +#define EFM32_MSC_STATUS_BUSY_MASK 0x0001 +#define EFM32_MSC_STATUS_LOCKED_MASK 0x0002 +#define EFM32_MSC_STATUS_INVADDR_MASK 0x0004 +#define EFM32_MSC_STATUS_WDATAREADY_MASK 0x0008 + target_addr_t off_status; + +#define EFM32_MSC_LOCK_LOCKKEY 0x1b71 + target_addr_t off_lock; + + const uint8_t *flash_write_code; + size_t flash_write_code_len; +}; + +// see contrib/loaders/flash/efm32.S for source +static const uint8_t efm32_flash_write_code_s0_s1[] = { +#include "../../../contrib/loaders/flash/silabs/silabs_s0_s1.inc" +}; + +static const uint8_t efm32_flash_write_code_s2[] = { +#include "../../../contrib/loaders/flash/silabs/silabs_s2.inc" +}; + +static const struct efm32_msc_offset efm32_msc_offset[] = { + [0] = { + .off_writectrl = 0x0008, + .off_writecmd = 0x000c, + .off_addrb = 0x0010, + .off_wdata = 0x0018, + .off_status = 0x001c, + .off_lock = 0x003c, + .off_userdatasize = 0x0000, // Does not exist in Series 0/1 + .flash_write_code = efm32_flash_write_code_s0_s1, + .flash_write_code_len = sizeof(efm32_flash_write_code_s0_s1), + }, + [1] = { + .off_writectrl = 0x0008, + .off_writecmd = 0x000c, + .off_addrb = 0x0010, + .off_wdata = 0x0018, + .off_status = 0x001c, + .off_lock = 0x0040, + .off_userdatasize = 0x0000, // Does not exist in Series 0/1 + .flash_write_code = efm32_flash_write_code_s0_s1, + .flash_write_code_len = sizeof(efm32_flash_write_code_s0_s1), + }, + [2] = { + .off_writectrl = 0x000c, + .off_writecmd = 0x0010, + .off_addrb = 0x0014, + .off_wdata = 0x0018, + .off_status = 0x001c, + .off_lock = 0x003c, + .off_userdatasize = 0x0034, + .flash_write_code = efm32_flash_write_code_s2, + .flash_write_code_len = sizeof(efm32_flash_write_code_s2), + }, +}; -#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 */ -#define EFM32_MSC_DI_PAGE_SIZE (EFM32_MSC_DEV_INFO+0x1e7) -#define EFM32_MSC_DI_FLASH_SZ (EFM32_MSC_DEV_INFO+0x1f8) -#define EFM32_MSC_DI_RAM_SZ (EFM32_MSC_DEV_INFO+0x1fa) -#define EFM32_MSC_DI_PART_NUM (EFM32_MSC_DEV_INFO+0x1fc) -#define EFM32_MSC_DI_PART_FAMILY (EFM32_MSC_DEV_INFO+0x1fe) -#define EFM32_MSC_DI_PROD_REV (EFM32_MSC_DEV_INFO+0x1ff) - -#define EFM32_MSC_REGBASE 0x400c0000 -#define EFM32_MSC_REGBASE_SERIES1 0x400e0000 -#define EFM32_MSC_REG_WRITECTRL 0x008 -#define EFM32_MSC_WRITECTRL_WREN_MASK 0x1 -#define EFM32_MSC_REG_WRITECMD 0x00c -#define EFM32_MSC_WRITECMD_LADDRIM_MASK 0x1 -#define EFM32_MSC_WRITECMD_ERASEPAGE_MASK 0x2 -#define EFM32_MSC_WRITECMD_WRITEONCE_MASK 0x8 -#define EFM32_MSC_REG_ADDRB 0x010 -#define EFM32_MSC_REG_WDATA 0x018 -#define EFM32_MSC_REG_STATUS 0x01c -#define EFM32_MSC_STATUS_BUSY_MASK 0x1 -#define EFM32_MSC_STATUS_LOCKED_MASK 0x2 -#define EFM32_MSC_STATUS_INVADDR_MASK 0x4 -#define EFM32_MSC_STATUS_WDATAREADY_MASK 0x8 -#define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10 -#define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20 -#define EFM32_MSC_REG_LOCK 0x03c -#define EFM32_MSC_REG_LOCK_SERIES1 0x040 -#define EFM32_MSC_LOCK_LOCKKEY 0x1b71 +// Series 2 only +#define EFM32_CMU_REG_CLKEN1_SET 0x50009068 enum efm32_bank_index { EFM32_BANK_INDEX_MAIN, @@ -85,316 +180,345 @@ enum efm32_bank_index { EFM32_N_BANKS }; -static int efm32x_get_bank_index(target_addr_t base) +static int efm32_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; + case EFM32_FLASH_BASE_V1: + case EFM32_FLASH_BASE_V2: + 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; - - /* EFM32 series (EFM32LG995F is the "old" series 0, while EFR32MG12P132 - is the "new" series 1). Determines location of MSC registers. */ + uint8_t part_id; int series; + const char *name; + uint32_t msc_regbase; - /* Page size in bytes, or 0 to read from EFM32_MSC_DI_PAGE_SIZE */ + // Page size in bytes, or 0 to read from msc_di->page_size int page_size; - - /* MSC register base address, or 0 to use default */ - uint32_t msc_regbase; }; struct efm32_info { const struct efm32_family_data *family_data; + const struct efm32_dev_info_addr *di_addr; + const struct efm32_msc_offset *msc_offset; + uint16_t part_num; // Series 0/1 only + uint32_t part_info; // Series 2 only + uint8_t part_rev; uint16_t flash_sz_kib; uint16_t ram_sz_kib; - uint16_t part_num; - uint8_t part_family; - uint8_t prod_rev; uint16_t page_size; + uint16_t page_size_ud; }; -struct efm32x_flash_chip { +struct efm32_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 lb_page[LOCKWORDS_SZ / 4]; 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, "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 }, - { 28, "EFR32MG2P Mighty", .series = 1 }, - { 29, "EFR32MG2B Mighty", .series = 1 }, - { 30, "EFR32MG2V Mighty", .series = 1 }, - { 31, "EFR32BG12P Blue", .series = 1 }, - { 32, "EFR32BG12B Blue", .series = 1 }, - { 33, "EFR32BG12V Blue", .series = 1 }, - { 37, "EFR32FG12P Flex", .series = 1 }, - { 38, "EFR32FG12B Flex", .series = 1 }, - { 39, "EFR32FG12V Flex", .series = 1 }, - { 40, "EFR32MG13P Mighty", .series = 1 }, - { 41, "EFR32MG13B Mighty", .series = 1 }, - { 42, "EFR32MG13V Mighty", .series = 1 }, - { 43, "EFR32BG13P Blue", .series = 1 }, - { 44, "EFR32BG13B Blue", .series = 1 }, - { 45, "EFR32BG13V Blue", .series = 1 }, - { 46, "EFR32ZG13P Zen", .series = 1 }, - { 49, "EFR32FG13P Flex", .series = 1 }, - { 50, "EFR32FG13B Flex", .series = 1 }, - { 51, "EFR32FG13V Flex", .series = 1 }, - { 52, "EFR32MG14P Mighty", .series = 1 }, - { 53, "EFR32MG14B Mighty", .series = 1 }, - { 54, "EFR32MG14V Mighty", .series = 1 }, - { 55, "EFR32BG14P Blue", .series = 1 }, - { 56, "EFR32BG14B Blue", .series = 1 }, - { 57, "EFR32BG14V Blue", .series = 1 }, - { 58, "EFR32ZG14P Zen", .series = 1 }, - { 61, "EFR32FG14P Flex", .series = 1 }, - { 62, "EFR32FG14B Flex", .series = 1 }, - { 63, "EFR32FG14V Flex", .series = 1 }, - { 71, "EFM32G", .series = 0, .page_size = 512 }, - { 72, "EFM32GG Giant", .series = 0 }, - { 73, "EFM32TG Tiny", .series = 0, .page_size = 512 }, - { 74, "EFM32LG Leopard", .series = 0 }, - { 75, "EFM32WG Wonder", .series = 0 }, - { 76, "EFM32ZG Zero", .series = 0, .page_size = 1024 }, - { 77, "EFM32HG Happy", .series = 0, .page_size = 1024 }, - { 81, "EFM32PG1B Pearl", .series = 1 }, - { 83, "EFM32JG1B Jade", .series = 1 }, - { 85, "EFM32PG12B Pearl", .series = 1 }, - { 87, "EFM32JG12B Jade", .series = 1 }, - { 89, "EFM32PG13B Pearl", .series = 1 }, - { 91, "EFM32JG13B Jade", .series = 1 }, - { 100, "EFM32GG11B Giant", .series = 1, .msc_regbase = 0x40000000 }, - { 103, "EFM32TG11B Tiny", .series = 1, .msc_regbase = 0x40000000 }, - { 106, "EFM32GG12B Giant", .series = 1, .msc_regbase = 0x40000000 }, - { 120, "EZR32WG Wonder", .series = 0 }, - { 121, "EZR32LG Leopard", .series = 0 }, - { 122, "EZR32HG Happy", .series = 0, .page_size = 1024 }, + { 16, 1, "EFR32MG1P Mighty", .msc_regbase = 0x400e0000 }, + { 17, 1, "EFR32MG1B Mighty", .msc_regbase = 0x400e0000 }, + { 18, 1, "EFR32MG1V Mighty", .msc_regbase = 0x400e0000 }, + { 19, 1, "EFR32BG1P Blue", .msc_regbase = 0x400e0000 }, + { 20, 1, "EFR32BG1B Blue", .msc_regbase = 0x400e0000 }, + { 21, 1, "EFR32BG1V Blue", .msc_regbase = 0x400e0000 }, + { 25, 1, "EFR32FG1P Flex", .msc_regbase = 0x400e0000 }, + { 26, 1, "EFR32FG1B Flex", .msc_regbase = 0x400e0000 }, + { 27, 1, "EFR32FG1V Flex", .msc_regbase = 0x400e0000 }, + { 28, 1, "EFR32MG12P Mighty", .msc_regbase = 0x400e0000 }, + { 29, 1, "EFR32MG12B Mighty", .msc_regbase = 0x400e0000 }, + { 30, 1, "EFR32MG12V Mighty", .msc_regbase = 0x400e0000 }, + { 31, 1, "EFR32BG12P Blue", .msc_regbase = 0x400e0000 }, + { 32, 1, "EFR32BG12B Blue", .msc_regbase = 0x400e0000 }, + { 33, 1, "EFR32BG12V Blue", .msc_regbase = 0x400e0000 }, + { 37, 1, "EFR32FG12P Flex", .msc_regbase = 0x400e0000 }, + { 38, 1, "EFR32FG12B Flex", .msc_regbase = 0x400e0000 }, + { 39, 1, "EFR32FG12V Flex", .msc_regbase = 0x400e0000 }, + { 40, 1, "EFR32MG13P Mighty", .msc_regbase = 0x400e0000 }, + { 41, 1, "EFR32MG13B Mighty", .msc_regbase = 0x400e0000 }, + { 42, 1, "EFR32MG13V Mighty", .msc_regbase = 0x400e0000 }, + { 43, 1, "EFR32BG13P Blue", .msc_regbase = 0x400e0000 }, + { 44, 1, "EFR32BG13B Blue", .msc_regbase = 0x400e0000 }, + { 45, 1, "EFR32BG13V Blue", .msc_regbase = 0x400e0000 }, + { 46, 1, "EFR32ZG13P Zen", .msc_regbase = 0x400e0000 }, + { 49, 1, "EFR32FG13P Flex", .msc_regbase = 0x400e0000 }, + { 50, 1, "EFR32FG13B Flex", .msc_regbase = 0x400e0000 }, + { 51, 1, "EFR32FG13V Flex", .msc_regbase = 0x400e0000 }, + { 52, 1, "EFR32MG14P Mighty", .msc_regbase = 0x400e0000 }, + { 53, 1, "EFR32MG14B Mighty", .msc_regbase = 0x400e0000 }, + { 54, 1, "EFR32MG14V Mighty", .msc_regbase = 0x400e0000 }, + { 55, 1, "EFR32BG14P Blue", .msc_regbase = 0x400e0000 }, + { 56, 1, "EFR32BG14B Blue", .msc_regbase = 0x400e0000 }, + { 57, 1, "EFR32BG14V Blue", .msc_regbase = 0x400e0000 }, + { 58, 1, "EFR32ZG14P Zen", .msc_regbase = 0x400e0000 }, + { 61, 1, "EFR32FG14P Flex", .msc_regbase = 0x400e0000 }, + { 62, 1, "EFR32FG14B Flex", .msc_regbase = 0x400e0000 }, + { 63, 1, "EFR32FG14V Flex", .msc_regbase = 0x400e0000 }, + { 71, 0, "EFM32G", .msc_regbase = 0x400c0000, .page_size = 512 }, + { 72, 0, "EFM32GG Giant", .msc_regbase = 0x400c0000 }, + { 73, 0, "EFM32TG Tiny", .msc_regbase = 0x400c0000, .page_size = 512 }, + { 74, 0, "EFM32LG Leopard", .msc_regbase = 0x400c0000 }, + { 75, 0, "EFM32WG Wonder", .msc_regbase = 0x400c0000 }, + { 76, 0, "EFM32ZG Zero", .msc_regbase = 0x400c0000, .page_size = 1024 }, + { 77, 0, "EFM32HG Happy", .msc_regbase = 0x400c0000, .page_size = 1024 }, + { 81, 1, "EFM32PG1B Pearl", .msc_regbase = 0x400e0000 }, + { 83, 1, "EFM32JG1B Jade", .msc_regbase = 0x400e0000 }, + { 85, 1, "EFM32PG12B Pearl", .msc_regbase = 0x400e0000 }, + { 87, 1, "EFM32JG12B Jade", .msc_regbase = 0x400e0000 }, + { 89, 1, "EFM32PG13B Pearl", .msc_regbase = 0x400e0000 }, + { 91, 1, "EFM32JG13B Jade", .msc_regbase = 0x400e0000 }, + { 100, 1, "EFM32GG11B Giant", .msc_regbase = 0x40000000 }, + { 103, 1, "EFM32TG11B Tiny", .msc_regbase = 0x40000000 }, + { 106, 1, "EFM32GG12B Giant", .msc_regbase = 0x40000000 }, + { 120, 0, "EZR32WG Wonder", .msc_regbase = 0x400c0000 }, + { 121, 0, "EZR32LG Leopard", .msc_regbase = 0x400c0000 }, + { 122, 0, "EZR32HG Happy", .msc_regbase = 0x400c0000, .page_size = 1024 }, + { 128, 2, "EFR32/EFM32 Series-2", .msc_regbase = 0x50030000 }, }; const struct flash_driver efm32_flash; -static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t addr, uint32_t count); +static int efm32_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 efm32_write_only_lockbits(struct flash_bank *bank); -static int efm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_sz) +static int efm32_read_reg_u32(struct flash_bank *bank, target_addr_t offset, + uint32_t *value) { - return target_read_u16(bank->target, EFM32_MSC_DI_FLASH_SZ, flash_sz); -} + struct efm32_flash_chip *efm32_info = bank->driver_priv; -static int efm32x_get_ram_size(struct flash_bank *bank, uint16_t *ram_sz) -{ - return target_read_u16(bank->target, EFM32_MSC_DI_RAM_SZ, ram_sz); -} - -static int efm32x_get_part_num(struct flash_bank *bank, uint16_t *pnum) -{ - return target_read_u16(bank->target, EFM32_MSC_DI_PART_NUM, pnum); -} - -static int efm32x_get_part_family(struct flash_bank *bank, uint8_t *pfamily) -{ - return target_read_u8(bank->target, EFM32_MSC_DI_PART_FAMILY, pfamily); -} - -static int efm32x_get_prod_rev(struct flash_bank *bank, uint8_t *prev) -{ - return target_read_u8(bank->target, EFM32_MSC_DI_PROD_REV, prev); + return target_read_u32(bank->target, + efm32_info->info.family_data->msc_regbase + offset, + value); } -static int efm32x_read_reg_u32(struct flash_bank *bank, target_addr_t offset, - uint32_t *value) +static int efm32_write_reg_u32(struct flash_bank *bank, target_addr_t offset, + uint32_t value) { - struct efm32x_flash_chip *efm32x_info = bank->driver_priv; - uint32_t base = efm32x_info->reg_base; + struct efm32_flash_chip *efm32_info = bank->driver_priv; - return target_read_u32(bank->target, base + offset, value); + return target_write_u32(bank->target, + efm32_info->info.family_data->msc_regbase + offset, + value); } -static int efm32x_write_reg_u32(struct flash_bank *bank, target_addr_t offset, - uint32_t value) -{ - 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) +static int efm32_read_info(struct flash_bank *bank) { + struct efm32_flash_chip *efm32_info = bank->driver_priv; + struct efm32_info *efm32_mcu_info = &efm32_info->info; int ret; - 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)); + memset(efm32_mcu_info, 0, sizeof(struct efm32_info)); - ret = efm32x_get_flash_size(bank, &(efm32_info->flash_sz_kib)); + uint8_t val8; + ret = target_read_u8(bank->target, EFM32_DI_PART_FAMILY, &val8); if (ret != ERROR_OK) return ret; + for (size_t i = 0; i < ARRAY_SIZE(efm32_families); i++) { + if (efm32_families[i].part_id == val8) + efm32_mcu_info->family_data = &efm32_families[i]; + } + if (!efm32_mcu_info->family_data) { + LOG_ERROR("Unknown MCU family %d", val8); + return ERROR_FAIL; + } - ret = efm32x_get_ram_size(bank, &(efm32_info->ram_sz_kib)); - if (ret != ERROR_OK) - return ret; + efm32_mcu_info->di_addr = &efm32_dev_info_addr[efm32_mcu_info->family_data->series]; + efm32_mcu_info->msc_offset = &efm32_msc_offset[efm32_mcu_info->family_data->series]; - ret = efm32x_get_part_num(bank, &(efm32_info->part_num)); + if (efm32_mcu_info->family_data->series == 2) { + ret = target_read_u32(bank->target, + efm32_mcu_info->di_addr->part_info, + &efm32_mcu_info->part_info); + if (ret != ERROR_OK) + return ret; + } else { + ret = target_read_u16(bank->target, + efm32_mcu_info->di_addr->part_num, + &efm32_mcu_info->part_num); + if (ret != ERROR_OK) + return ret; + } + + ret = target_read_u8(bank->target, + efm32_mcu_info->di_addr->part_rev, + &efm32_mcu_info->part_rev); if (ret != ERROR_OK) return ret; - ret = efm32x_get_part_family(bank, &(efm32_info->part_family)); + ret = target_read_u16(bank->target, + efm32_mcu_info->di_addr->flash_sz, + &efm32_mcu_info->flash_sz_kib); if (ret != ERROR_OK) return ret; - ret = efm32x_get_prod_rev(bank, &(efm32_info->prod_rev)); + ret = target_read_u16(bank->target, + efm32_mcu_info->di_addr->ram_sz, + &efm32_mcu_info->ram_sz_kib); if (ret != ERROR_OK) return ret; - for (size_t i = 0; i < ARRAY_SIZE(efm32_families); i++) { - if (efm32_families[i].family_id == efm32_info->part_family) - efm32_info->family_data = &efm32_families[i]; - } - - if (!efm32_info->family_data) { - LOG_ERROR("Unknown MCU family %d", efm32_info->part_family); - return ERROR_FAIL; - } - - switch (efm32_info->family_data->series) { - case 0: - efm32x_info->reg_base = EFM32_MSC_REGBASE; - efm32x_info->reg_lock = EFM32_MSC_REG_LOCK; - break; - case 1: - efm32x_info->reg_base = EFM32_MSC_REGBASE_SERIES1; - efm32x_info->reg_lock = EFM32_MSC_REG_LOCK_SERIES1; - break; - } - - if (efm32_info->family_data->msc_regbase != 0) - efm32x_info->reg_base = efm32_info->family_data->msc_regbase; - - if (efm32_info->family_data->page_size != 0) { - efm32_info->page_size = efm32_info->family_data->page_size; + efm32_mcu_info->page_size_ud = 0; + if (efm32_mcu_info->family_data->page_size != 0) { + efm32_mcu_info->page_size = efm32_mcu_info->family_data->page_size; + } else if ((efm32_mcu_info->family_data->part_id == 72 || + efm32_mcu_info->family_data->part_id == 74) && + efm32_mcu_info->part_rev < 18) { + /* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid for MCUs + * with part_rev < 18 + */ + if (efm32_mcu_info->flash_sz_kib < 512) + efm32_mcu_info->page_size = 2048; + else + efm32_mcu_info->page_size = 4096; } else { - uint8_t pg_size = 0; - ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE, - &pg_size); + uint32_t val32; + ret = target_read_u32(bank->target, + efm32_mcu_info->di_addr->page_size, + &val32); if (ret != ERROR_OK) return ret; - efm32_info->page_size = (1 << ((pg_size+10) & 0xff)); - - if (efm32_info->part_family == EFM_FAMILY_ID_GIANT_GECKO || - efm32_info->part_family == EFM_FAMILY_ID_LEOPARD_GECKO) { - /* Giant or Leopard Gecko */ - if (efm32_info->prod_rev < 18) { - /* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid - for MCUs with PROD_REV < 18 */ - if (efm32_info->flash_sz_kib < 512) - efm32_info->page_size = 2048; - else - efm32_info->page_size = 4096; - } - } - - if ((efm32_info->page_size != 2048) && - (efm32_info->page_size != 4096)) { - LOG_ERROR("Invalid page size %u", efm32_info->page_size); - return ERROR_FAIL; - } + efm32_mcu_info->page_size = BIT(FIELD_GET(EFM32_DI_PARTINFO_PAGE_SZ_MASK, val32)) * 1024; + if (efm32_mcu_info->family_data->series == 2) + efm32_mcu_info->page_size_ud = FIELD_GET(EFM32_DI_PARTINFO_PAGE_SZ_UD_MASK, val32) * 1024; + } + if (!efm32_mcu_info->page_size_ud) + efm32_mcu_info->page_size_ud = efm32_mcu_info->page_size; + + if (efm32_mcu_info->page_size != 512 && + efm32_mcu_info->page_size != 1024 && + efm32_mcu_info->page_size != 2048 && + efm32_mcu_info->page_size != 4096 && + efm32_mcu_info->page_size != 8192) { + LOG_ERROR("Invalid page size %u", efm32_mcu_info->page_size); + return ERROR_FAIL; } return ERROR_OK; } /* flash bank efm32 0 0 */ -FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command) +FLASH_BANK_COMMAND_HANDLER(efm32_flash_bank_command) { - struct efm32x_flash_chip *efm32x_info = NULL; - if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; - int bank_index = efm32x_get_bank_index(bank->base); + int bank_index = efm32_get_bank_index(bank->base); if (bank_index < 0) { LOG_ERROR("Flash bank with base address %" PRIx32 " is not supported", - (uint32_t) bank->base); + (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; + struct efm32_flash_chip *efm32_info = NULL; + 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) { + efm32_info = bank->driver_priv; break; } } - if (!efm32x_info) { + if (!efm32_info) { /* target not matched, make a new one */ - efm32x_info = calloc(1, sizeof(struct efm32x_flash_chip)); + efm32_info = calloc(1, sizeof(struct efm32_flash_chip)); - memset(efm32x_info->lb_page, 0xff, LOCKWORDS_SZ); + memset(efm32_info->lb_page, 0xff, LOCKWORDS_SZ); } - ++efm32x_info->refcount; - bank->driver_priv = efm32x_info; + ++efm32_info->refcount; + bank->driver_priv = efm32_info; return ERROR_OK; } /** - * Remove flash structure corresponding to this bank, - * if and only if it's not used by any others + * 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) +static void efm32_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); + struct efm32_flash_chip *efm32_info = bank->driver_priv; + + if (efm32_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. + */ + --efm32_info->refcount; + if (efm32_info->refcount == 0) { + free(efm32_info); bank->driver_priv = NULL; } } } +static int efm32_msc_clock_enable(struct flash_bank *bank) +{ + struct efm32_flash_chip *efm32_info = bank->driver_priv; + + if (efm32_info->info.family_data->series == 0 || + efm32_info->info.family_data->series == 1) + return ERROR_OK; + + unsigned int s2_family = FIELD_GET(EFM32_DI_PARTINFO_FAMILY_MASK, + efm32_info->info.part_info); + uint32_t msc_clken; + switch (s2_family) { + case 21: + msc_clken = 0; + break; + case 22: + case 27: + case 29: + msc_clken = BIT(17); + break; + case 23: + case 24: + case 25: + case 26: + case 28: + msc_clken = BIT(16); + break; + default: + LOG_WARNING("Don't know EFR/EFM Gx family number, can't set MSC register. Use default values.."); + msc_clken = BIT(16); + } + int ret = target_write_u32(bank->target, + EFM32_CMU_REG_CLKEN1_SET, + msc_clken); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to enable MSC clock"); + return ret; + } + + return ERROR_OK; +} + /* 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) +static int efm32_set_reg_bits(struct flash_bank *bank, uint32_t reg, + uint32_t bitmask, int set) { int ret = 0; uint32_t reg_val = 0; - ret = efm32x_read_reg_u32(bank, reg, ®_val); + ret = efm32_read_reg_u32(bank, reg, ®_val); if (ret != ERROR_OK) return ret; @@ -403,41 +527,49 @@ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, else reg_val &= ~bitmask; - return efm32x_write_reg_u32(bank, reg, reg_val); + return efm32_write_reg_u32(bank, reg, reg_val); } -static int efm32x_set_wren(struct flash_bank *bank, int write_enable) +static int efm32_set_wren(struct flash_bank *bank, int write_enable) { - return efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECTRL, - EFM32_MSC_WRITECTRL_WREN_MASK, write_enable); + struct efm32_flash_chip *efm32_info = bank->driver_priv; + + return efm32_set_reg_bits(bank, + efm32_info->info.msc_offset->off_writectrl, + EFM32_MSC_WRITECTRL_WREN_MASK, write_enable); } -static int efm32x_msc_lock(struct flash_bank *bank, int lock) +static int efm32_msc_lock(struct flash_bank *bank, int lock) { - 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)); + struct efm32_flash_chip *efm32_info = bank->driver_priv; + + return efm32_write_reg_u32(bank, + efm32_info->info.msc_offset->off_lock, + lock ? 0 : EFM32_MSC_LOCK_LOCKKEY); } -static int efm32x_wait_status(struct flash_bank *bank, int timeout, - uint32_t wait_mask, int wait_for_set) +static int efm32_wait_status(struct flash_bank *bank, int timeout_ms, + uint32_t wait_mask, bool wait_for_set) { - int ret = 0; + struct efm32_flash_chip *efm32_info = bank->driver_priv; + int64_t start_ms = timeval_ms(); uint32_t status = 0; while (1) { - ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); + int ret = efm32_read_reg_u32(bank, + efm32_info->info.msc_offset->off_status, + &status); if (ret != ERROR_OK) - break; + return ret; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32, status); - if (((status & wait_mask) == 0) && (wait_for_set == 0)) + if (!(status & wait_mask) && !wait_for_set) break; - else if (((status & wait_mask) != 0) && wait_for_set) + if ((status & wait_mask) && wait_for_set) break; - if (timeout-- <= 0) { + if (timeval_ms() - start_ms > timeout_ms) { LOG_ERROR("timed out waiting for MSC status"); return ERROR_FAIL; } @@ -445,13 +577,10 @@ static int efm32x_wait_status(struct flash_bank *bank, int timeout, alive_sleep(1); } - if (status & EFM32_MSC_STATUS_ERASEABORTED_MASK) - LOG_WARNING("page erase was aborted"); - - return ret; + return ERROR_OK; } -static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) +static int efm32_erase_page(struct flash_bank *bank, uint32_t addr) { /* this function DOES NOT set WREN; must be set already */ /* 1. write address to ADDRB @@ -460,20 +589,27 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) 4. write ERASEPAGE 5. wait until !STATUS_BUSY */ - int ret = 0; - uint32_t status = 0; + struct efm32_flash_chip *efm32_info = bank->driver_priv; + int ret; + LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr); - ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); + ret = efm32_write_reg_u32(bank, + efm32_info->info.msc_offset->off_addrb, + addr); if (ret != ERROR_OK) return ret; - ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, - EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); + ret = efm32_set_reg_bits(bank, + efm32_info->info.msc_offset->off_writecmd, + EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ret != ERROR_OK) return ret; - ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); + uint32_t status; + ret = efm32_read_reg_u32(bank, + efm32_info->info.msc_offset->off_status, + &status); if (ret != ERROR_OK) return ret; @@ -487,17 +623,18 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) return ERROR_FAIL; } - ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, - EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1); + ret = efm32_set_reg_bits(bank, + efm32_info->info.msc_offset->off_writecmd, + EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1); if (ret != ERROR_OK) return ret; - return efm32x_wait_status(bank, EFM32_FLASH_ERASE_TMO, - EFM32_MSC_STATUS_BUSY_MASK, 0); + return efm32_wait_status(bank, EFM32_FLASH_OPERATION_TIMEOUT, + EFM32_MSC_STATUS_BUSY_MASK, false); } -static int efm32x_erase(struct flash_bank *bank, unsigned int first, - unsigned int last) +static int efm32_erase(struct flash_bank *bank, unsigned int first, + unsigned int last) { struct target *target = bank->target; int ret = 0; @@ -507,26 +644,32 @@ static int efm32x_erase(struct flash_bank *bank, unsigned int first, return ERROR_TARGET_NOT_HALTED; } - efm32x_msc_lock(bank, 0); - ret = efm32x_set_wren(bank, 1); + ret = efm32_msc_clock_enable(bank); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to enable MSC clock"); + return ret; + } + + efm32_msc_lock(bank, 0); + ret = efm32_set_wren(bank, 1); 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->base + bank->sectors[i].offset); + ret = efm32_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); + ret = efm32_set_wren(bank, 0); + efm32_msc_lock(bank, 1); if (ret != ERROR_OK) return ret; if (bank->base == EFM32_MSC_LOCK_BITS) { - ret = efm32x_write_only_lockbits(bank); + ret = efm32_write_only_lockbits(bank); if (ret != ERROR_OK) LOG_ERROR("Failed to restore lockbits after erase"); } @@ -534,9 +677,9 @@ static int efm32x_erase(struct flash_bank *bank, unsigned int first, return ret; } -static int efm32x_read_lock_data(struct flash_bank *bank) +static int efm32_read_lock_data(struct flash_bank *bank) { - struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + struct efm32_flash_chip *efm32_info = bank->driver_priv; struct target *target = bank->target; int data_size = 0; uint32_t *ptr = NULL; @@ -547,10 +690,10 @@ static int efm32x_read_lock_data(struct flash_bank *bank) /* calculate the number of 32-bit words to read (one lock bit per sector) */ data_size = (bank->num_sectors + 31) / 32; - ptr = efm32x_info->lb_page; + ptr = efm32_info->lb_page; for (int i = 0; i < data_size; i++, ptr++) { - ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+i*4, ptr); + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + i * 4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read PLW %d", i); return ret; @@ -560,48 +703,48 @@ static int efm32x_read_lock_data(struct flash_bank *bank) /* also, read ULW, DLW, MLW, ALW and CLW words */ /* ULW, word 126 */ - ptr = efm32x_info->lb_page + 126; - ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+126*4, ptr); + ptr = efm32_info->lb_page + 126; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 126 * 4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read ULW"); return ret; } /* DLW, word 127 */ - ptr = efm32x_info->lb_page + 127; - ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+127*4, ptr); + ptr = efm32_info->lb_page + 127; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 127 * 4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read DLW"); return ret; } /* 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); + ptr = efm32_info->lb_page + 125; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 125 * 4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read MLW"); return ret; } /* 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); + ptr = efm32_info->lb_page + 124; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 124 * 4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read ALW"); return ret; } /* CLW1, word 123, present in EFR32 */ - ptr = efm32x_info->lb_page + 123; - ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+123*4, ptr); + ptr = efm32_info->lb_page + 123; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 123 * 4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read CLW1"); return ret; } /* 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); + ptr = efm32_info->lb_page + 122; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 122 * 4, ptr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read CLW0"); return ret; @@ -610,24 +753,29 @@ static int efm32x_read_lock_data(struct flash_bank *bank) return ERROR_OK; } -static int efm32x_write_only_lockbits(struct flash_bank *bank) +static int efm32_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); + struct efm32_flash_chip *efm32_info = bank->driver_priv; + + return efm32_priv_write(bank, (uint8_t *)efm32_info->lb_page, + EFM32_MSC_LOCK_BITS, LOCKWORDS_SZ); } -static int efm32x_write_lock_data(struct flash_bank *bank) +static int efm32_write_lock_data(struct flash_bank *bank) { - struct efm32x_flash_chip *efm32x_info = bank->driver_priv; - int ret = 0; + struct efm32_flash_chip *efm32_info = bank->driver_priv; /* 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; + assert(efm32_info->info.page_size >= LOCKWORDS_SZ); + + uint32_t extra_bytes = efm32_info->info.page_size - LOCKWORDS_SZ; uint8_t *extra_data = NULL; + int ret; if (extra_bytes) { extra_data = malloc(extra_bytes); - ret = target_read_buffer(bank->target, EFM32_MSC_LOCK_BITS_EXTRA, extra_bytes, extra_data); + 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); @@ -635,7 +783,7 @@ static int efm32x_write_lock_data(struct flash_bank *bank) } } - ret = efm32x_erase_page(bank, EFM32_MSC_LOCK_BITS); + ret = efm32_erase_page(bank, EFM32_MSC_LOCK_BITS); if (ret != ERROR_OK) { LOG_ERROR("Failed to erase LB page"); if (extra_data) @@ -644,7 +792,9 @@ static int efm32x_write_lock_data(struct flash_bank *bank) } if (extra_data) { - ret = efm32x_priv_write(bank, extra_data, EFM32_MSC_LOCK_BITS_EXTRA, extra_bytes); + ret = efm32_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"); @@ -652,47 +802,46 @@ static int efm32x_write_lock_data(struct flash_bank *bank) } } - return efm32x_write_only_lockbits(bank); + return efm32_write_only_lockbits(bank); } -static int efm32x_get_page_lock(struct flash_bank *bank, size_t page) +static int efm32_get_page_lock(struct flash_bank *bank, size_t page) { - struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + struct efm32_flash_chip *efm32_info = bank->driver_priv; uint32_t dw = 0; uint32_t mask = 0; 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; + case EFM32_FLASH_BASE_V1: + case EFM32_FLASH_BASE_V2: + dw = efm32_info->lb_page[page >> 5]; + mask = BIT(page & 0x1f); + break; + case EFM32_MSC_USER_DATA: + dw = efm32_info->lb_page[126]; + mask = BIT(0); + break; + case EFM32_MSC_LOCK_BITS: + dw = efm32_info->lb_page[126]; + mask = BIT(1); + break; } return (dw & mask) ? 0 : 1; } -static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set) +static int efm32_set_page_lock(struct flash_bank *bank, size_t page, int set) { - struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + struct efm32_flash_chip *efm32_info = bank->driver_priv; - if (bank->base != EFM32_FLASH_BASE) { + if (bank->base != EFM32_FLASH_BASE_V1 && + bank->base != EFM32_FLASH_BASE_V2) { 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; - - mask = 1 << (page & 0x1f); - + uint32_t *dw = &efm32_info->lb_page[page >> 5]; + uint32_t mask = BIT(page & 0x1f); if (!set) *dw |= mask; else @@ -701,26 +850,36 @@ static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set) return ERROR_OK; } -static int efm32x_protect(struct flash_bank *bank, int set, unsigned int first, - unsigned int last) +static int efm32_protect(struct flash_bank *bank, int set, unsigned int first, + unsigned int last) { + struct efm32_flash_chip *efm32_info = bank->driver_priv; struct target *target = bank->target; int ret = 0; + if (efm32_info->info.family_data->series == 2) + return ERROR_FLASH_OPER_UNSUPPORTED; + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } + ret = efm32_read_lock_data(bank); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read LB data"); + return ret; + } + for (unsigned int i = first; i <= last; i++) { - ret = efm32x_set_page_lock(bank, i, set); + ret = efm32_set_page_lock(bank, i, set); if (ret != ERROR_OK) { LOG_ERROR("Failed to set lock on page %d", i); return ret; } } - ret = efm32x_write_lock_data(bank); + ret = efm32_write_lock_data(bank); if (ret != ERROR_OK) { LOG_ERROR("Failed to write LB page"); return ret; @@ -729,146 +888,74 @@ static int efm32x_protect(struct flash_bank *bank, int set, unsigned int first, return ERROR_OK; } -static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, - uint32_t address, uint32_t count) +static int efm32_write_block(struct flash_bank *bank, const uint8_t *buf, + uint32_t address, uint32_t count) { + struct efm32_flash_chip *efm32_info = bank->driver_priv; struct target *target = bank->target; - uint32_t buffer_size = 16384; - struct working_area *write_algorithm; - struct working_area *source; - struct reg_param reg_params[5]; - struct armv7m_algorithm armv7m_info; - struct efm32x_flash_chip *efm32x_info = bank->driver_priv; - int ret = ERROR_OK; - - /* see contrib/loaders/flash/efm32.S for src */ - static const uint8_t efm32x_flash_write_code[] = { - /* #define EFM32_MSC_WRITECTRL_OFFSET 0x008 */ - /* #define EFM32_MSC_WRITECMD_OFFSET 0x00c */ - /* #define EFM32_MSC_ADDRB_OFFSET 0x010 */ - /* #define EFM32_MSC_WDATA_OFFSET 0x018 */ - /* #define EFM32_MSC_STATUS_OFFSET 0x01c */ - - 0x01, 0x26, /* movs r6, #1 */ - 0x86, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] */ - - /* wait_fifo: */ - 0x16, 0x68, /* ldr r6, [r2, #0] */ - 0x00, 0x2e, /* cmp r6, #0 */ - 0x22, 0xd0, /* beq exit */ - 0x55, 0x68, /* ldr r5, [r2, #4] */ - 0xb5, 0x42, /* cmp r5, r6 */ - 0xf9, 0xd0, /* beq wait_fifo */ - - 0x04, 0x61, /* str r4, [r0, #EFM32_MSC_ADDRB_OFFSET] */ - 0x01, 0x26, /* movs r6, #1 */ - 0xc6, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] */ - 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */ - 0x06, 0x27, /* movs r7, #6 */ - 0x3e, 0x42, /* tst r6, r7 */ - 0x16, 0xd1, /* bne error */ - - /* wait_wdataready: */ - 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */ - 0x08, 0x27, /* movs r7, #8 */ - 0x3e, 0x42, /* tst r6, r7 */ - 0xfb, 0xd0, /* beq wait_wdataready */ - - 0x2e, 0x68, /* ldr r6, [r5] */ - 0x86, 0x61, /* str r6, [r0, #EFM32_MSC_WDATA_OFFSET] */ - 0x08, 0x26, /* movs r6, #8 */ - 0xc6, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] */ - - 0x04, 0x35, /* adds r5, #4 */ - 0x04, 0x34, /* adds r4, #4 */ - - /* busy: */ - 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */ - 0x01, 0x27, /* movs r7, #1 */ - 0x3e, 0x42, /* tst r6, r7 */ - 0xfb, 0xd1, /* bne busy */ - - 0x9d, 0x42, /* cmp r5, r3 */ - 0x01, 0xd3, /* bcc no_wrap */ - 0x15, 0x46, /* mov r5, r2 */ - 0x08, 0x35, /* adds r5, #8 */ - - /* no_wrap: */ - 0x55, 0x60, /* str r5, [r2, #4] */ - 0x01, 0x39, /* subs r1, r1, #1 */ - 0x00, 0x29, /* cmp r1, #0 */ - 0x02, 0xd0, /* beq exit */ - 0xdb, 0xe7, /* b wait_fifo */ - - /* error: */ - 0x00, 0x20, /* movs r0, #0 */ - 0x50, 0x60, /* str r0, [r2, #4] */ - - /* exit: */ - 0x30, 0x46, /* mov r0, r6 */ - 0x00, 0xbe, /* bkpt #0 */ - }; - + struct working_area *write_algorithm, *source; + int ret; /* flash write code */ - if (target_alloc_working_area(target, sizeof(efm32x_flash_write_code), - &write_algorithm) != ERROR_OK) { + ret = target_alloc_working_area(target, + efm32_info->info.msc_offset->flash_write_code_len, + &write_algorithm); + if (ret) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - ret = target_write_buffer(target, write_algorithm->address, - sizeof(efm32x_flash_write_code), efm32x_flash_write_code); - if (ret != ERROR_OK) + efm32_info->info.msc_offset->flash_write_code_len, + efm32_info->info.msc_offset->flash_write_code); + if (ret) return ret; /* 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; - } + uint32_t buffer_size = target_get_working_area_avail(target); + if (buffer_size <= 256) { + LOG_WARNING("no large enough working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } + buffer_size = MIN(buffer_size, 16 * 1024); + ret = target_alloc_working_area(target, buffer_size, &source); + if (ret) + return ret; + 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 (word-32bit) */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ - buf_set_u32(reg_params[0].value, 0, 32, efm32x_info->reg_base); + buf_set_u32(reg_params[0].value, 0, 32, efm32_info->info.family_data->msc_regbase); buf_set_u32(reg_params[1].value, 0, 32, 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); - armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; - armv7m_info.core_mode = ARM_MODE_THREAD; - + struct armv7m_algorithm armv7m_info = { + .common_magic = ARMV7M_COMMON_MAGIC, + .core_mode = ARM_MODE_THREAD, + }; ret = target_run_flash_async_algorithm(target, buf, count, 4, - 0, NULL, - 5, reg_params, - source->address, source->size, - write_algorithm->address, 0, - &armv7m_info); + 0, NULL, + 5, reg_params, + source->address, source->size, + write_algorithm->address, 0, + &armv7m_info); if (ret == ERROR_FLASH_OPERATION_FAILED) { - LOG_ERROR("flash write failed at address 0x%"PRIx32, - buf_get_u32(reg_params[4].value, 0, 32)); + 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) & - EFM32_MSC_STATUS_LOCKED_MASK) { + EFM32_MSC_STATUS_LOCKED_MASK) { LOG_ERROR("flash memory write protected"); } if (buf_get_u32(reg_params[0].value, 0, 32) & - EFM32_MSC_STATUS_INVADDR_MASK) { + EFM32_MSC_STATUS_INVADDR_MASK) { LOG_ERROR("invalid flash memory write address"); } } @@ -885,8 +972,8 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, return ret; } -static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, - uint32_t val) +static int efm32_write_word(struct flash_bank *bank, uint32_t addr, + uint32_t val) { /* this function DOES NOT set WREN; must be set already */ /* 1. write address to ADDRB @@ -900,23 +987,28 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, /* FIXME: EFM32G ref states (7.3.2) that writes should be * performed twice per dword */ - - int ret = 0; - uint32_t status = 0; + struct efm32_flash_chip *efm32_info = bank->driver_priv; + int ret; /* if not called, GDB errors will be reported during large writes */ keep_alive(); - ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); + ret = efm32_write_reg_u32(bank, + efm32_info->info.msc_offset->off_addrb, + addr); if (ret != ERROR_OK) return ret; - ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, - EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); + ret = efm32_set_reg_bits(bank, + efm32_info->info.msc_offset->off_writecmd, + EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ret != ERROR_OK) return ret; - ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); + uint32_t status; + ret = efm32_read_reg_u32(bank, + efm32_info->info.msc_offset->off_status, + &status); if (ret != ERROR_OK) return ret; @@ -930,28 +1022,31 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, return ERROR_FAIL; } - ret = efm32x_wait_status(bank, EFM32_FLASH_WDATAREADY_TMO, - EFM32_MSC_STATUS_WDATAREADY_MASK, 1); + ret = efm32_wait_status(bank, EFM32_FLASH_OPERATION_TIMEOUT, + EFM32_MSC_STATUS_WDATAREADY_MASK, true); if (ret != ERROR_OK) { LOG_ERROR("Wait for WDATAREADY failed"); return ret; } - ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WDATA, val); + ret = efm32_write_reg_u32(bank, + efm32_info->info.msc_offset->off_wdata, + val); 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); + ret = efm32_write_reg_u32(bank, + efm32_info->info.msc_offset->off_writecmd, + EFM32_MSC_WRITECMD_WRITEONCE_MASK); 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); + ret = efm32_wait_status(bank, EFM32_FLASH_OPERATION_TIMEOUT, + EFM32_MSC_STATUS_BUSY_MASK, false); if (ret != ERROR_OK) { LOG_ERROR("Wait for BUSY failed"); return ret; @@ -960,8 +1055,8 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, return ERROR_OK; } -static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t addr, uint32_t count) +static int efm32_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; @@ -972,8 +1067,7 @@ static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, } if (addr & 0x3) { - LOG_ERROR("addr 0x%" PRIx32 " breaks required 4-byte " - "alignment", addr); + LOG_ERROR("addr 0x%" PRIx32 " breaks required 4-byte alignment", addr); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } @@ -982,12 +1076,11 @@ static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, count = (old_count | 3) + 1; new_buffer = malloc(count); if (!new_buffer) { - LOG_ERROR("odd number of bytes to write and no memory " - "for padding buffer"); + LOG_ERROR("odd number of bytes to write and no memory for padding buffer"); return ERROR_FAIL; } - LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %" PRIu32 " " - "and padding with 0xff", old_count, count); + LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %" + PRIu32 " and padding with 0xff", old_count, count); memset(new_buffer, 0xff, count); buffer = memcpy(new_buffer, buffer, old_count); } @@ -995,26 +1088,29 @@ static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t words_remaining = count / 4; int retval, retval2; + retval = efm32_msc_clock_enable(bank); + if (retval != ERROR_OK) + goto cleanup; + /* unlock flash registers */ - efm32x_msc_lock(bank, 0); - retval = efm32x_set_wren(bank, 1); + efm32_msc_lock(bank, 0); + retval = efm32_set_wren(bank, 1); if (retval != ERROR_OK) goto cleanup; /* try using a block write */ - retval = efm32x_write_block(bank, buffer, addr, words_remaining); + retval = efm32_write_block(bank, buffer, addr, words_remaining); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single word accesses */ - LOG_WARNING("couldn't use block writes, falling back to single " - "memory accesses"); + LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); while (words_remaining > 0) { uint32_t value; memcpy(&value, buffer, sizeof(uint32_t)); - retval = efm32x_write_word(bank, addr, value); + retval = efm32_write_word(bank, addr, value); if (retval != ERROR_OK) goto reset_pg_and_lock; @@ -1025,8 +1121,8 @@ static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, } reset_pg_and_lock: - retval2 = efm32x_set_wren(bank, 0); - efm32x_msc_lock(bank, 1); + retval2 = efm32_set_wren(bank, 0); + efm32_msc_lock(bank, 1); if (retval == ERROR_OK) retval = retval2; @@ -1035,34 +1131,77 @@ static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer, return retval; } -static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) +static int efm32_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); + return efm32_priv_write(bank, buffer, bank->base + offset, count); +} + +static char *efm32_get_str_identifier(struct efm32_info *efm32_mcu_info, + char *buf, size_t len) +{ + if (!efm32_mcu_info->part_info) { + snprintf(buf, len, "%s Gecko, rev %" PRIu8, + efm32_mcu_info->family_data->name, + efm32_mcu_info->part_rev); + return buf; + } + unsigned int dev_num = FIELD_GET(EFM32_DI_PARTINFO_NUM_MASK, + efm32_mcu_info->part_info); + unsigned int dev_family = FIELD_GET(EFM32_DI_PARTINFO_FAMILY_MASK, + efm32_mcu_info->part_info); + unsigned int dev_type = FIELD_GET(EFM32_DI_PARTINFO_TYPE_MASK, + efm32_mcu_info->part_info); + + const char *types = "FMBZxP"; + if (dev_type > strlen(types)) { + snprintf(buf, len, "Unknown MCU family %u", dev_type); + return buf; + } + + char dev_num_letter = 'A' + (dev_num / 1000); + unsigned int dev_num_digits = dev_num % 1000; + + snprintf(buf, len, "%s%cG%u %c%03u, rev %" PRIu8, + types[dev_type] == 'P' ? "EFM32" : "EFR32", + types[dev_type], + dev_family, + dev_num_letter, + dev_num_digits, + efm32_mcu_info->part_rev); + return buf; } -static int efm32x_probe(struct flash_bank *bank) +static int efm32_probe(struct flash_bank *bank) { - struct efm32x_flash_chip *efm32x_info = bank->driver_priv; - struct efm32_info *efm32_mcu_info = &(efm32x_info->info); + struct efm32_flash_chip *efm32_info = bank->driver_priv; + struct efm32_info *efm32_mcu_info = &efm32_info->info; + int bank_index = efm32_get_bank_index(bank->base); + uint32_t base_address = EFM32_FLASH_BASE_V2; + char strbuf[256]; int ret; - int bank_index = efm32x_get_bank_index(bank->base); assert(bank_index >= 0); - efm32x_info->probed[bank_index] = false; - memset(efm32x_info->lb_page, 0xff, LOCKWORDS_SZ); + efm32_info->probed[bank_index] = false; + memset(efm32_info->lb_page, 0xff, LOCKWORDS_SZ); - ret = efm32x_read_info(bank); + ret = efm32_read_info(bank); if (ret != ERROR_OK) return ret; - LOG_INFO("detected part: %s Gecko, rev %d", - efm32_mcu_info->family_data->name, efm32_mcu_info->prod_rev); + if (efm32_mcu_info->family_data->series == 0 || + efm32_mcu_info->family_data->series == 1 || + FIELD_GET(EFM32_DI_PARTINFO_FAMILY_MASK, efm32_mcu_info->part_info) == 21 || + FIELD_GET(EFM32_DI_PARTINFO_FAMILY_MASK, efm32_mcu_info->part_info) == 22) + base_address = EFM32_FLASH_BASE_V1; + + LOG_INFO("detected part: %s", + efm32_get_str_identifier(efm32_mcu_info, strbuf, sizeof(strbuf))); LOG_INFO("flash size = %d KiB", efm32_mcu_info->flash_sz_kib); LOG_INFO("flash page size = %d B", efm32_mcu_info->page_size); @@ -1071,56 +1210,67 @@ static int efm32x_probe(struct flash_bank *bank) free(bank->sectors); bank->sectors = NULL; - if (bank->base == EFM32_FLASH_BASE) { - bank->num_sectors = efm32_mcu_info->flash_sz_kib * 1024 / - efm32_mcu_info->page_size; + uint32_t page_size; + if (bank->base == base_address) { /* main flash */ + page_size = efm32_mcu_info->page_size; + bank->num_sectors = efm32_mcu_info->flash_sz_kib * 1024 / page_size; assert(bank->num_sectors > 0); + } else if (efm32_info->info.family_data->series != 2) { + page_size = efm32_mcu_info->page_size_ud; + bank->num_sectors = 1; + } else { + ret = efm32_msc_clock_enable(bank); + if (ret != ERROR_OK) + return ret; - ret = efm32x_read_lock_data(bank); + uint32_t userdatasize; + ret = efm32_read_reg_u32(bank, + efm32_info->info.msc_offset->off_userdatasize, + &userdatasize); if (ret != ERROR_OK) { - LOG_ERROR("Failed to read LB data"); + LOG_ERROR("Failed to read page size"); 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; + page_size = efm32_mcu_info->page_size_ud; + bank->num_sectors = (userdatasize * 256) / page_size; } + bank->size = bank->num_sectors * page_size; + bank->sectors = alloc_block_array(0, page_size, bank->num_sectors); + if (!bank->sectors) + return ERROR_FAIL; - efm32x_info->probed[bank_index] = true; + efm32_info->probed[bank_index] = true; return ERROR_OK; } -static int efm32x_auto_probe(struct flash_bank *bank) +static int efm32_auto_probe(struct flash_bank *bank) { - struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + struct efm32_flash_chip *efm32_info = bank->driver_priv; + int bank_index = efm32_get_bank_index(bank->base); - int bank_index = efm32x_get_bank_index(bank->base); assert(bank_index >= 0); - if (efm32x_info->probed[bank_index]) + if (efm32_info->probed[bank_index]) return ERROR_OK; - return efm32x_probe(bank); + return efm32_probe(bank); } -static int efm32x_protect_check(struct flash_bank *bank) +static int efm32_protect_check(struct flash_bank *bank) { + struct efm32_flash_chip *efm32_info = bank->driver_priv; struct target *target = bank->target; int ret = 0; + if (efm32_info->info.family_data->series == 2) + return ERROR_FLASH_OPER_UNSUPPORTED; + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - ret = efm32x_read_lock_data(bank); + ret = efm32_read_lock_data(bank); if (ret != ERROR_OK) { LOG_ERROR("Failed to read LB data"); return ret; @@ -1129,67 +1279,72 @@ static int efm32x_protect_check(struct flash_bank *bank) assert(bank->sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_protected = efm32x_get_page_lock(bank, i); + bank->sectors[i].is_protected = efm32_get_page_lock(bank, i); return ERROR_OK; } -static int get_efm32x_info(struct flash_bank *bank, struct command_invocation *cmd) +static int efm32_get_info(struct flash_bank *bank, struct command_invocation *cmd) { - struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + struct efm32_flash_chip *efm32_info = bank->driver_priv; + char strbuf[256]; int ret; - ret = efm32x_read_info(bank); + ret = efm32_read_info(bank); if (ret != ERROR_OK) { LOG_ERROR("Failed to read EFM32 info"); return ret; } - command_print_sameline(cmd, "%s Gecko, rev %d", efm32x_info->info.family_data->name, - efm32x_info->info.prod_rev); + command_print_sameline(cmd, "%s", + efm32_get_str_identifier(&efm32_info->info, + strbuf, + sizeof(strbuf))); return ERROR_OK; } -COMMAND_HANDLER(efm32x_handle_debuglock_command) +COMMAND_HANDLER(efm32_handle_debuglock_command) { - struct target *target = NULL; - 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 (retval != ERROR_OK) - return retval; - - struct efm32x_flash_chip *efm32x_info = bank->driver_priv; + int ret = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ret != ERROR_OK) + return ret; - target = bank->target; + struct efm32_flash_chip *efm32_info = 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 *ptr; - ptr = efm32x_info->lb_page + 127; + uint32_t *ptr = efm32_info->lb_page + 127; *ptr = 0; - retval = efm32x_write_lock_data(bank); - if (retval != ERROR_OK) { + ret = efm32_msc_clock_enable(bank); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to enable MSC clock"); + return ret; + } + + ret = efm32_write_lock_data(bank); + if (ret != ERROR_OK) { LOG_ERROR("Failed to write LB page"); - return retval; + return ret; } - command_print(CMD, "efm32x debug interface locked, reset the device to apply"); + command_print(CMD, "efm32 debug interface locked, reset the device to apply"); return ERROR_OK; } -static const struct command_registration efm32x_exec_command_handlers[] = { +static const struct command_registration efm32_exec_command_handlers[] = { { .name = "debuglock", - .handler = efm32x_handle_debuglock_command, + .handler = efm32_handle_debuglock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Lock the debug interface of the device.", @@ -1197,29 +1352,29 @@ static const struct command_registration efm32x_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const struct command_registration efm32x_command_handlers[] = { +static const struct command_registration efm32_command_handlers[] = { { .name = "efm32", .mode = COMMAND_ANY, - .help = "efm32 flash command group", + .help = "Silicon Labs (EFM32 and EFR32) flash command group", .usage = "", - .chain = efm32x_exec_command_handlers, + .chain = efm32_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver efm32_flash = { - .name = "efm32", - .commands = efm32x_command_handlers, - .flash_bank_command = efm32x_flash_bank_command, - .erase = efm32x_erase, - .protect = efm32x_protect, - .write = efm32x_write, - .read = default_flash_read, - .probe = efm32x_probe, - .auto_probe = efm32x_auto_probe, - .erase_check = default_flash_blank_check, - .protect_check = efm32x_protect_check, - .info = get_efm32x_info, - .free_driver_priv = efm32x_free_driver_priv, + .name = "efm32", + .commands = efm32_command_handlers, + .flash_bank_command = efm32_flash_bank_command, + .erase = efm32_erase, + .protect = efm32_protect, + .write = efm32_write, + .read = default_flash_read, + .probe = efm32_probe, + .auto_probe = efm32_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = efm32_protect_check, + .info = efm32_get_info, + .free_driver_priv = efm32_free_driver_priv, }; diff --git a/src/flash/nor/em357.c b/src/flash/nor/em357.c index 207346f10d..cf005ca22d 100644 --- a/src/flash/nor/em357.c +++ b/src/flash/nor/em357.c @@ -115,7 +115,7 @@ static int em357_wait_status_busy(struct flash_bank *bank, int timeout) retval = em357_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32, status); if ((status & FLASH_BSY) == 0) break; if (timeout-- <= 0) { @@ -670,36 +670,36 @@ static int em357_probe(struct flash_bank *bank) em357_info->probed = false; switch (bank->size) { - case 0x10000: - /* 64k -- 64 1k pages */ - num_pages = 64; - page_size = 1024; - break; - case 0x20000: - /* 128k -- 128 1k pages */ - num_pages = 128; - page_size = 1024; - break; - case 0x30000: - /* 192k -- 96 2k pages */ - num_pages = 96; - page_size = 2048; - break; - case 0x40000: - /* 256k -- 128 2k pages */ - num_pages = 128; - page_size = 2048; - break; - case 0x80000: - /* 512k -- 256 2k pages */ - num_pages = 256; - page_size = 2048; - break; - default: - LOG_WARNING("No size specified for em357 flash driver, assuming 192k!"); - num_pages = 96; - page_size = 2048; - break; + case 0x10000: + /* 64k -- 64 1k pages */ + num_pages = 64; + page_size = 1024; + break; + case 0x20000: + /* 128k -- 128 1k pages */ + num_pages = 128; + page_size = 1024; + break; + case 0x30000: + /* 192k -- 96 2k pages */ + num_pages = 96; + page_size = 2048; + break; + case 0x40000: + /* 256k -- 128 2k pages */ + num_pages = 128; + page_size = 2048; + break; + case 0x80000: + /* 512k -- 256 2k pages */ + num_pages = 256; + page_size = 2048; + break; + default: + LOG_WARNING("No size specified for em357 flash driver, assuming 192k!"); + num_pages = 96; + page_size = 2048; + break; } /* Enable FPEC CLK */ diff --git a/src/flash/nor/fm3.c b/src/flash/nor/fm3.c index 48f4493ab6..486f6d4353 100644 --- a/src/flash/nor/fm3.c +++ b/src/flash/nor/fm3.c @@ -309,8 +309,7 @@ static int fm3_erase(struct flash_bank *bank, unsigned int first, write_algorithm->address, 0, 100000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("Error executing flash erase programming algorithm"); - retval = ERROR_FLASH_OPERATION_FAILED; - return retval; + return ERROR_FLASH_OPERATION_FAILED; } retval = fm3_busy_wait(target, offset, 500); @@ -329,9 +328,8 @@ static int fm3_erase(struct flash_bank *bank, unsigned int first, if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, 0x40000000, &u32_dummy_read); /* dummy read of FASZR */ - - return retval; + // dummy read of FASZR + return target_read_u32(target, 0x40000000, &u32_dummy_read); } static int fm3_write_block(struct flash_bank *bank, const uint8_t *buffer, @@ -907,8 +905,7 @@ static int fm3_chip_erase(struct flash_bank *bank) write_algorithm->address, 0, 100000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("Error executing flash erase programming algorithm"); - retval = ERROR_FLASH_OPERATION_FAILED; - return retval; + return ERROR_FLASH_OPERATION_FAILED; } target_free_working_area(target, write_algorithm); @@ -925,9 +922,8 @@ static int fm3_chip_erase(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, 0x40000000, &u32_dummy_read); /* dummy read of FASZR */ - - return retval; + // dummy read of FASZR + return target_read_u32(target, 0x40000000, &u32_dummy_read); } COMMAND_HANDLER(fm3_handle_chip_erase_command) diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c index 2db79ef502..4c8f14c9ac 100644 --- a/src/flash/nor/fm4.c +++ b/src/flash/nor/fm4.c @@ -605,7 +605,7 @@ static bool fm4_name_match(const char *s, const char *pattern) if (!pattern[i]) return true; /* Use x as wildcard */ - if (pattern[i] != 'x' && tolower(s[i]) != tolower(pattern[i])) + if (pattern[i] != 'x' && tolower((unsigned char)s[i]) != tolower((unsigned char)pattern[i])) return false; i++; } diff --git a/src/flash/nor/hpm_xpi.c b/src/flash/nor/hpm_xpi.c new file mode 100644 index 0000000000..3cb1f407aa --- /dev/null +++ b/src/flash/nor/hpm_xpi.c @@ -0,0 +1,523 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2025 hpmicro + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "imp.h" +#include +#include +#include +#include +#include +#include "target/riscv/program.h" + +#include "../../../contrib/loaders/flash/hpmicro/hpm_xpi_flash.h" +static uint8_t flash_algo[] = { +#include "../../../contrib/loaders/flash/hpmicro/hpm_xpi_flash.inc" +}; +#define TIMEOUT_IN_MS (10000U) +#define ERASE_CHIP_TIMEOUT_IN_MS (100000U) +#define SECTOR_ERASE_TIMEOUT_IN_MS (100) +#define TYPICAL_TIMEOUT_IN_MS (500U) +#define BLOCK_SIZE (4096U) +#define NOR_CFG_OPT_HEADER (0xFCF90000UL) + +struct hpm_flash_info { + uint32_t total_sz_in_bytes; + uint32_t sector_sz_in_bytes; +}; + +struct hpm_xpi_priv { + uint32_t io_base; + uint32_t header; + uint32_t opt0; + uint32_t opt1; + bool probed; +}; + +static int hpm_xpi_run_algo_flash_init(struct flash_bank *bank, + target_addr_t algo_entry) +{ + struct reg_param reg_params[6]; + struct target *target = bank->target; + struct hpm_xpi_priv *xpi_priv = bank->driver_priv; + + int xlen = riscv_xlen(target); + 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], "ra", xlen, PARAM_OUT); + buf_set_u64(reg_params[0].value, 0, xlen, bank->base); + buf_set_u64(reg_params[1].value, 0, xlen, xpi_priv->header); + buf_set_u64(reg_params[2].value, 0, xlen, xpi_priv->opt0); + buf_set_u64(reg_params[3].value, 0, xlen, xpi_priv->opt1); + buf_set_u64(reg_params[4].value, 0, xlen, xpi_priv->io_base); + buf_set_u64(reg_params[5].value, 0, xlen, algo_entry + FLASH_INIT + 4); + int retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, + algo_entry, algo_entry + FLASH_INIT + 4, TYPICAL_TIMEOUT_IN_MS, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute run algorithm: %d", retval); + goto err; + } + + uint32_t stat = buf_get_u32(reg_params[0].value, 0, xlen); + if (stat) { + retval = ERROR_TARGET_FAILURE; + LOG_ERROR("init flash failed on target: 0x%" PRIx32, retval); + goto err; + } + +err: + for (size_t k = 0; k < ARRAY_SIZE(reg_params); k++) + destroy_reg_param(®_params[k]); + + return retval; +} + +static int hpm_xpi_probe(struct flash_bank *bank) +{ + struct hpm_flash_info flash_info = {0}; + struct working_area *data_wa = NULL; + struct flash_sector *sectors = NULL; + struct working_area *wa; + struct target *target = bank->target; + + struct hpm_xpi_priv *xpi_priv = bank->driver_priv; + + if (xpi_priv->probed) { + xpi_priv->probed = false; + bank->size = 0; + bank->num_sectors = 0; + free(bank->sectors); + bank->sectors = NULL; + } + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = target_alloc_working_area(target, sizeof(flash_algo), &wa); + if (retval != ERROR_OK) { + LOG_WARNING("Couldn't allocate %zd-byte working area", + sizeof(flash_algo)); + return retval; + } + + retval = target_write_buffer(target, wa->address, + sizeof(flash_algo), flash_algo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d", + wa->address, retval); + target_free_working_area(target, wa); + return retval; + } + + retval = hpm_xpi_run_algo_flash_init(bank, wa->address); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to run init flash algorithm: %d", retval); + return retval; + } + + if (target_alloc_working_area(target, sizeof(flash_info), + &data_wa) != ERROR_OK) { + LOG_WARNING("Couldn't allocate %zd-byte working area", + sizeof(flash_info)); + goto err; + } + + int xlen = riscv_xlen(target); + struct reg_param reg_params[3]; + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + init_reg_param(®_params[2], "ra", xlen, PARAM_OUT); + buf_set_u64(reg_params[0].value, 0, xlen, bank->base); + buf_set_u64(reg_params[1].value, 0, xlen, data_wa->address); + buf_set_u64(reg_params[2].value, 0, xlen, wa->address + FLASH_GET_INFO + 4); + + retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, + wa->address + FLASH_GET_INFO, wa->address + FLASH_GET_INFO + 4, TYPICAL_TIMEOUT_IN_MS, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to run algorithm at: %d", retval); + goto err; + } + + uint32_t stat = buf_get_u32(reg_params[0].value, 0, xlen); + if (stat) { + retval = ERROR_TARGET_FAILURE; + LOG_ERROR("flash get info failed on target: 0x%" PRIx32, retval); + goto err; + } + + target_read_u32(target, data_wa->address, &flash_info.total_sz_in_bytes); + target_read_u32(target, data_wa->address + 4, &flash_info.sector_sz_in_bytes); + + bank->size = flash_info.total_sz_in_bytes; + bank->num_sectors = flash_info.total_sz_in_bytes / flash_info.sector_sz_in_bytes; + + /* create and fill sectors array */ + 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 * (flash_info.sector_sz_in_bytes); + sectors[sector].size = flash_info.sector_sz_in_bytes; + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + xpi_priv->probed = true; + +err: + for (size_t k = 0; k < ARRAY_SIZE(reg_params); k++) + destroy_reg_param(®_params[k]); + target_free_working_area(target, data_wa); + target_free_working_area(target, wa); + return retval; +} + +static int hpm_xpi_auto_probe(struct flash_bank *bank) +{ + struct hpm_xpi_priv *xpi_priv = bank->driver_priv; + if (xpi_priv->probed) + return ERROR_OK; + return hpm_xpi_probe(bank); +} + +static int hpm_xpi_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct working_area *data_wa = NULL; + struct working_area *wa = NULL; + uint32_t data_size = BLOCK_SIZE; + uint32_t left = count, i = 0; + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = target_alloc_working_area(target, sizeof(flash_algo), &wa); + if (retval != ERROR_OK) { + LOG_WARNING("Couldn't allocate %zd-byte working area", + sizeof(flash_algo)); + return retval; + } + + retval = target_write_buffer(target, wa->address, + sizeof(flash_algo), flash_algo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d", + wa->address, retval); + target_free_working_area(target, wa); + return retval; + } + + retval = hpm_xpi_run_algo_flash_init(bank, wa->address); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to run init flash algorithm: %d", retval); + return retval; + } + + /* memory buffer */ + uint32_t avail_buffer_size; + avail_buffer_size = target_get_working_area_avail(target); + if (avail_buffer_size <= 256) { + /* we already allocated the writing code, but failed to get a + * buffer, free the algorithm */ + target_free_working_area(target, wa); + LOG_WARNING("no large enough working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + data_size = MIN(data_size, avail_buffer_size); + retval = target_alloc_working_area(target, data_size, &data_wa); + if (retval != ERROR_OK) { + LOG_WARNING("Couldn't allocate %d-byte working area", data_size); + return retval; + } + + int xlen = riscv_xlen(target); + struct reg_param reg_params[4]; + 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); + + while (left) { + uint32_t trans_size = MIN(data_size, left); + retval = target_write_buffer(target, data_wa->address, trans_size, buffer + i * data_size); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write buffer to 0x%" TARGET_PRIxADDR ": %d", data_wa->address, retval); + goto err; + } + + buf_set_u32(reg_params[0].value, 0, xlen, bank->base); + buf_set_u32(reg_params[1].value, 0, xlen, offset + i * data_size); + buf_set_u32(reg_params[2].value, 0, xlen, data_wa->address); + buf_set_u32(reg_params[3].value, 0, xlen, trans_size); + + retval = target_run_algorithm(target, 0, NULL, 4, reg_params, + wa->address + FLASH_PROGRAM, wa->address + FLASH_PROGRAM + 4, TIMEOUT_IN_MS, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", wa->address, retval); + goto err; + } + + uint32_t stat = buf_get_u32(reg_params[0].value, 0, xlen); + if (stat) { + retval = ERROR_FLASH_OPERATION_FAILED; + LOG_ERROR("flash write failed on target: 0x%" PRIx32, retval); + goto err; + } + i++; + left -= trans_size; + } + +err: + if (data_wa) + target_free_working_area(target, data_wa); + + for (size_t k = 0; k < ARRAY_SIZE(reg_params); k++) + destroy_reg_param(®_params[k]); + + target_free_working_area(target, wa); + return retval; +} + +static int hpm_xpi_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + struct target *target = bank->target; + struct working_area *wa = NULL; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = target_alloc_working_area(target, sizeof(flash_algo), &wa); + if (retval != ERROR_OK) { + LOG_WARNING("Couldn't allocate %zd-byte working area", + sizeof(flash_algo)); + return retval; + } + + retval = target_write_buffer(target, wa->address, + sizeof(flash_algo), flash_algo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d", + wa->address, retval); + target_free_working_area(target, wa); + return retval; + } + + retval = hpm_xpi_run_algo_flash_init(bank, wa->address); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to run init flash algorithm: %d", retval); + return retval; + } + + LOG_DEBUG("from sector %u to sector %u", first, last); + + int xlen = riscv_xlen(target); + struct reg_param reg_params[3]; + 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); + + buf_set_u32(reg_params[0].value, 0, xlen, bank->base); + buf_set_u32(reg_params[1].value, 0, xlen, first * bank->sectors[0].size); + buf_set_u32(reg_params[2].value, 0, xlen, (last - first + 1) * bank->sectors[0].size); + + retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, + wa->address + FLASH_ERASE, wa->address + FLASH_ERASE + 4, + SECTOR_ERASE_TIMEOUT_IN_MS * (last - first + 1), NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", wa->address, retval); + goto err; + } + + uint32_t stat = buf_get_u32(reg_params[0].value, 0, xlen); + if (stat) { + retval = ERROR_FLASH_OPERATION_FAILED; + LOG_ERROR("flash erase failed on target: 0x%" PRIx32, retval); + goto err; + } + +err: + target_free_working_area(target, wa); + for (size_t k = 0; k < ARRAY_SIZE(reg_params); k++) + destroy_reg_param(®_params[k]); + return retval; +} + +static int hpm_xpi_erase_chip(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct working_area *wa = NULL; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = target_alloc_working_area(target, sizeof(flash_algo), &wa); + if (retval != ERROR_OK) { + LOG_WARNING("Couldn't allocate %zd-byte working area", + sizeof(flash_algo)); + return retval; + } + + retval = target_write_buffer(target, wa->address, + sizeof(flash_algo), flash_algo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d", + wa->address, retval); + target_free_working_area(target, wa); + return retval; + } + + retval = hpm_xpi_run_algo_flash_init(bank, wa->address); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to run init flash algorithm: %d", retval); + return retval; + } + + int xlen = riscv_xlen(target); + struct reg_param reg_params[1]; + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + buf_set_u64(reg_params[0].value, 0, xlen, bank->base); + + retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, + wa->address + FLASH_ERASE_CHIP, wa->address + FLASH_ERASE_CHIP + 4, ERASE_CHIP_TIMEOUT_IN_MS, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", wa->address, retval); + goto err; + } + + uint32_t stat = buf_get_u32(reg_params[0].value, 0, xlen); + if (stat) { + retval = ERROR_FLASH_OPERATION_FAILED; + LOG_ERROR("flash erase chip failed on target: 0x%" PRIx32, retval); + goto err; + } + +err: + target_free_working_area(target, wa); + for (size_t k = 0; k < ARRAY_SIZE(reg_params); k++) + destroy_reg_param(®_params[k]); + return retval; +} + +COMMAND_HANDLER(hpm_xpi_handle_erase_chip_command) +{ + int retval; + struct flash_bank *bank; + struct target *target; + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; + + target = bank->target; + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + return hpm_xpi_erase_chip(bank); +} + +static const struct command_registration hpm_xpi_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = hpm_xpi_handle_erase_chip_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "erase entire flash device", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration hpm_xpi_command_handlers[] = { + { + .name = "hpm_xpi", + .mode = COMMAND_ANY, + .help = "hpm_xpi command group", + .usage = "", + .chain = hpm_xpi_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +FLASH_BANK_COMMAND_HANDLER(hpm_xpi_flash_bank_command) +{ + struct hpm_xpi_priv *xpi_priv; + uint32_t io_base; + uint32_t header; + uint32_t opt0; + uint32_t opt1; + + if (CMD_ARGC < 7) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], io_base); + + switch (CMD_ARGC) { + case 7: + header = NOR_CFG_OPT_HEADER + 1; + opt1 = 0; + opt0 = 7; + break; + case 8: + header = NOR_CFG_OPT_HEADER + 1; + opt1 = 0; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], opt0); + break; + case 9: + header = NOR_CFG_OPT_HEADER + 2; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], opt0); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[8], opt1); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + xpi_priv = malloc(sizeof(struct hpm_xpi_priv)); + if (!xpi_priv) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + bank->driver_priv = xpi_priv; + xpi_priv->io_base = io_base; + xpi_priv->header = header; + xpi_priv->opt0 = opt0; + xpi_priv->opt1 = opt1; + xpi_priv->probed = false; + + return ERROR_OK; +} + +const struct flash_driver hpm_xpi_flash = { + .name = "hpm_xpi", + .flash_bank_command = hpm_xpi_flash_bank_command, + .commands = hpm_xpi_command_handlers, + .erase = hpm_xpi_erase, + .write = hpm_xpi_write, + .read = default_flash_read, + .verify = default_flash_verify, + .probe = hpm_xpi_probe, + .auto_probe = hpm_xpi_auto_probe, + .erase_check = default_flash_blank_check, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c index 4b975390be..e1bb17ab1f 100644 --- a/src/flash/nor/jtagspi.c +++ b/src/flash/nor/jtagspi.c @@ -230,7 +230,7 @@ COMMAND_HANDLER(jtagspi_handle_set) */ retval = CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, 0, &bank, false); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; info = bank->driver_priv; @@ -420,7 +420,7 @@ COMMAND_HANDLER(jtagspi_handle_always_4byte) 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; jtagspi_info = bank->driver_priv; diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 85c306bd44..266b447c04 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -1224,7 +1224,6 @@ static int kinetis_disable_wdog(struct kinetis_chip *k_chip) COMMAND_HANDLER(kinetis_disable_wdog_handler) { - int result; struct target *target = get_current_target(CMD_CTX); struct kinetis_chip *k_chip = kinetis_get_chip(target); @@ -1234,8 +1233,7 @@ COMMAND_HANDLER(kinetis_disable_wdog_handler) if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; - result = kinetis_disable_wdog(k_chip); - return result; + return kinetis_disable_wdog(k_chip); } @@ -1589,8 +1587,7 @@ static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat) switch (k_chip->sysmodectrlr_type) { case KINETIS_SMC: - result = target_read_u8(target, SMC_PMSTAT, pmstat); - return result; + return target_read_u8(target, SMC_PMSTAT, pmstat); case KINETIS_SMC32: result = target_read_u32(target, SMC32_PMSTAT, &stat32); @@ -2145,24 +2142,24 @@ static int kinetis_probe_chip_s32k(struct kinetis_chip *k_chip) 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; + 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; diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c index 8207504b5f..51d5cb504b 100644 --- a/src/flash/nor/kinetis_ke.c +++ b/src/flash/nor/kinetis_ke.c @@ -238,19 +238,18 @@ static int kinetis_ke_prepare_flash(struct flash_bank *bank) * Trim internal clock */ switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { - - case KINETIS_KE_SRSID_KEX2: - /* Both KE02_20 and KE02_40 should get the same trim value */ - trim_value = 0x4C; - break; - - case KINETIS_KE_SRSID_KEX4: - trim_value = 0x54; - break; - - case KINETIS_KE_SRSID_KEX6: - trim_value = 0x58; - break; + case KINETIS_KE_SRSID_KEX2: + /* Both KE02_20 and KE02_40 should get the same trim value */ + trim_value = 0x4C; + break; + + case KINETIS_KE_SRSID_KEX4: + trim_value = 0x54; + break; + + case KINETIS_KE_SRSID_KEX6: + trim_value = 0x58; + break; } result = target_read_u8(target, ICS_C4, &c4); @@ -293,54 +292,52 @@ static int kinetis_ke_prepare_flash(struct flash_bank *bank) * Configure SIM (bus clock) */ switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { + /* KE02 sub-family operates on SIM_BUSDIV */ + case KINETIS_KE_SRSID_KEX2: + bus_reg_val = 0; + bus_reg_addr = SIM_BUSDIV; + bus_clock = 20000000; + break; + + /* KE04 and KE06 sub-family operates on SIM_CLKDIV + * Clocks are divided by: + * DIV1 = core clock = 48MHz + * DIV2 = bus clock = 24Mhz + * DIV3 = timer clocks + * So we need to configure SIM_CLKDIV, DIV1 and DIV2 value + */ + case KINETIS_KE_SRSID_KEX4: + /* KE04 devices have the SIM_CLKDIV register at a different offset + * depending on the pin count. */ + switch (KINETIS_KE_SRSID_PINCOUNT(kinfo->sim_srsid)) { + /* 16, 20 and 24 pins */ + case 1: + case 2: + case 3: + bus_reg_addr = SIM_CLKDIV_KE04_16_20_24; + break; - /* KE02 sub-family operates on SIM_BUSDIV */ - case KINETIS_KE_SRSID_KEX2: - bus_reg_val = 0; - bus_reg_addr = SIM_BUSDIV; - bus_clock = 20000000; + /* 44, 64 and 80 pins */ + case 5: + case 7: + case 8: + bus_reg_addr = SIM_CLKDIV_KE04_44_64_80; break; - /* KE04 and KE06 sub-family operates on SIM_CLKDIV - * Clocks are divided by: - * DIV1 = core clock = 48MHz - * DIV2 = bus clock = 24Mhz - * DIV3 = timer clocks - * So we need to configure SIM_CLKDIV, DIV1 and DIV2 value - */ - case KINETIS_KE_SRSID_KEX4: - /* KE04 devices have the SIM_CLKDIV register at a different offset - * depending on the pin count. */ - switch (KINETIS_KE_SRSID_PINCOUNT(kinfo->sim_srsid)) { - - /* 16, 20 and 24 pins */ - case 1: - case 2: - case 3: - bus_reg_addr = SIM_CLKDIV_KE04_16_20_24; - break; - - /* 44, 64 and 80 pins */ - case 5: - case 7: - case 8: - bus_reg_addr = SIM_CLKDIV_KE04_44_64_80; - break; - - default: - LOG_ERROR("KE04 - Unknown pin count"); - return ERROR_FAIL; - } + default: + LOG_ERROR("KE04 - Unknown pin count"); + return ERROR_FAIL; + } - bus_reg_val = SIM_CLKDIV_OUTDIV2_MASK; - bus_clock = 24000000; - break; + bus_reg_val = SIM_CLKDIV_OUTDIV2_MASK; + bus_clock = 24000000; + break; - case KINETIS_KE_SRSID_KEX6: - bus_reg_val = SIM_CLKDIV_OUTDIV2_MASK; - bus_reg_addr = SIM_CLKDIV_KE06; - bus_clock = 24000000; - break; + case KINETIS_KE_SRSID_KEX6: + bus_reg_val = SIM_CLKDIV_OUTDIV2_MASK; + bus_reg_addr = SIM_CLKDIV_KE06; + bus_clock = 24000000; + break; } result = target_write_u32(target, bus_reg_addr, bus_reg_val); @@ -357,20 +354,19 @@ static int kinetis_ke_prepare_flash(struct flash_bank *bank) c2 &= ~ICS_C2_BDIV_MASK; switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { - - case KINETIS_KE_SRSID_KEX2: - /* Note: since there are two KE02 types, the KE02_40 @ 40MHz and the - * KE02_20 @ 20MHz, we divide here the ~40MHz ICSFLLCLK down to 20MHz, - * for compatibility. - */ - c2 |= ICS_C2_BDIV(1); - break; - - case KINETIS_KE_SRSID_KEX4: - case KINETIS_KE_SRSID_KEX6: - /* For KE04 and KE06, the ICSFLLCLK can be 48MHz. */ - c2 |= ICS_C2_BDIV(0); - break; + case KINETIS_KE_SRSID_KEX2: + /* Note: since there are two KE02 types, the KE02_40 @ 40MHz and the + * KE02_20 @ 20MHz, we divide here the ~40MHz ICSFLLCLK down to 20MHz, + * for compatibility. + */ + c2 |= ICS_C2_BDIV(1); + break; + + case KINETIS_KE_SRSID_KEX4: + case KINETIS_KE_SRSID_KEX6: + /* For KE04 and KE06, the ICSFLLCLK can be 48MHz. */ + c2 |= ICS_C2_BDIV(0); + break; } result = target_write_u8(target, ICS_C2, c2); @@ -1052,21 +1048,21 @@ static int kinetis_ke_probe(struct flash_bank *bank) } switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { - case KINETIS_KE_SRSID_KEX2: - LOG_INFO("KE02 sub-family"); - break; + case KINETIS_KE_SRSID_KEX2: + LOG_INFO("KE02 sub-family"); + break; - case KINETIS_KE_SRSID_KEX4: - LOG_INFO("KE04 sub-family"); - break; + case KINETIS_KE_SRSID_KEX4: + LOG_INFO("KE04 sub-family"); + break; - case KINETIS_KE_SRSID_KEX6: - LOG_INFO("KE06 sub-family"); - break; + case KINETIS_KE_SRSID_KEX6: + LOG_INFO("KE06 sub-family"); + break; - default: - LOG_ERROR("Unsupported KE sub-family"); - return ERROR_FLASH_OPER_UNSUPPORTED; + default: + LOG_ERROR("Unsupported KE sub-family"); + return ERROR_FLASH_OPER_UNSUPPORTED; } /* We can only retrieve the ke0x part, but there is no way to know @@ -1077,41 +1073,40 @@ static int kinetis_ke_probe(struct flash_bank *bank) kinfo->sector_size = 512; switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { - - case KINETIS_KE_SRSID_KEX2: - /* Max. 64KB */ - bank->size = 0x00010000; - bank->num_sectors = 128; - - /* KE02 uses the FTMRH flash controller, - * and registers have a different offset from the - * FTMRE flash controller. Sort this out here. - */ - kinfo->ftmrx_fclkdiv_addr = 0x40020000; - kinfo->ftmrx_fccobix_addr = 0x40020002; - kinfo->ftmrx_fstat_addr = 0x40020006; - kinfo->ftmrx_fprot_addr = 0x40020008; - kinfo->ftmrx_fccobhi_addr = 0x4002000A; - kinfo->ftmrx_fccoblo_addr = 0x4002000B; - break; - - case KINETIS_KE_SRSID_KEX6: - case KINETIS_KE_SRSID_KEX4: - /* Max. 128KB */ - bank->size = 0x00020000; - bank->num_sectors = 256; - - /* KE04 and KE06 use the FTMRE flash controller, - * and registers have a different offset from the - * FTMRH flash controller. Sort this out here. - */ - kinfo->ftmrx_fclkdiv_addr = 0x40020003; - kinfo->ftmrx_fccobix_addr = 0x40020001; - kinfo->ftmrx_fstat_addr = 0x40020005; - kinfo->ftmrx_fprot_addr = 0x4002000B; - kinfo->ftmrx_fccobhi_addr = 0x40020009; - kinfo->ftmrx_fccoblo_addr = 0x40020008; - break; + case KINETIS_KE_SRSID_KEX2: + /* Max. 64KB */ + bank->size = 0x00010000; + bank->num_sectors = 128; + + /* KE02 uses the FTMRH flash controller, + * and registers have a different offset from the + * FTMRE flash controller. Sort this out here. + */ + kinfo->ftmrx_fclkdiv_addr = 0x40020000; + kinfo->ftmrx_fccobix_addr = 0x40020002; + kinfo->ftmrx_fstat_addr = 0x40020006; + kinfo->ftmrx_fprot_addr = 0x40020008; + kinfo->ftmrx_fccobhi_addr = 0x4002000A; + kinfo->ftmrx_fccoblo_addr = 0x4002000B; + break; + + case KINETIS_KE_SRSID_KEX6: + case KINETIS_KE_SRSID_KEX4: + /* Max. 128KB */ + bank->size = 0x00020000; + bank->num_sectors = 256; + + /* KE04 and KE06 use the FTMRE flash controller, + * and registers have a different offset from the + * FTMRH flash controller. Sort this out here. + */ + kinfo->ftmrx_fclkdiv_addr = 0x40020003; + kinfo->ftmrx_fccobix_addr = 0x40020001; + kinfo->ftmrx_fstat_addr = 0x40020005; + kinfo->ftmrx_fprot_addr = 0x4002000B; + kinfo->ftmrx_fccobhi_addr = 0x40020009; + kinfo->ftmrx_fccoblo_addr = 0x40020008; + break; } free(bank->sectors); diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c index 09d35f604a..1b338ee2e6 100644 --- a/src/flash/nor/lpc2000.c +++ b/src/flash/nor/lpc2000.c @@ -383,40 +383,40 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) /* variant 2 has a uniform layout, only number of sectors differs */ switch (bank->size) { - case 4 * 1024: - lpc2000_info->cmd51_max_buffer = 1024; - bank->num_sectors = 1; - break; - case 8 * 1024: - lpc2000_info->cmd51_max_buffer = 1024; - bank->num_sectors = 2; - break; - case 16 * 1024: - bank->num_sectors = 4; - break; - case 32 * 1024: - bank->num_sectors = 8; - break; - case 64 * 1024: - bank->num_sectors = 9; - break; - case 128 * 1024: - bank->num_sectors = 11; - break; - case 256 * 1024: - bank->num_sectors = 15; - break; - case 500 * 1024: - bank->num_sectors = 27; - break; - case 512 * 1024: - case 504 * 1024: - bank->num_sectors = 28; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); - break; + case 4 * 1024: + lpc2000_info->cmd51_max_buffer = 1024; + bank->num_sectors = 1; + break; + case 8 * 1024: + lpc2000_info->cmd51_max_buffer = 1024; + bank->num_sectors = 2; + break; + case 16 * 1024: + bank->num_sectors = 4; + break; + case 32 * 1024: + bank->num_sectors = 8; + break; + case 64 * 1024: + bank->num_sectors = 9; + break; + case 128 * 1024: + bank->num_sectors = 11; + break; + case 256 * 1024: + bank->num_sectors = 15; + break; + case 500 * 1024: + bank->num_sectors = 27; + break; + case 512 * 1024: + case 504 * 1024: + bank->num_sectors = 28; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); + break; } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -448,37 +448,37 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) lpc2000_info->iap_max_stack = 128; switch (bank->size) { - case 4 * 1024: - lpc2000_info->cmd51_max_buffer = 256; - bank->num_sectors = 1; - break; - case 8 * 1024: - lpc2000_info->cmd51_max_buffer = 512; - bank->num_sectors = 2; - break; - case 16 * 1024: - lpc2000_info->cmd51_max_buffer = 512; - bank->num_sectors = 4; - break; - case 32 * 1024: - lpc2000_info->cmd51_max_buffer = 1024; - bank->num_sectors = 8; - break; - case 64 * 1024: - bank->num_sectors = 16; - break; - case 128 * 1024: - bank->num_sectors = 18; + case 4 * 1024: + lpc2000_info->cmd51_max_buffer = 256; + bank->num_sectors = 1; break; - case 256 * 1024: - bank->num_sectors = 22; - break; - case 512 * 1024: - bank->num_sectors = 30; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 8 * 1024: + lpc2000_info->cmd51_max_buffer = 512; + bank->num_sectors = 2; + break; + case 16 * 1024: + lpc2000_info->cmd51_max_buffer = 512; + bank->num_sectors = 4; + break; + case 32 * 1024: + lpc2000_info->cmd51_max_buffer = 1024; + bank->num_sectors = 8; + break; + case 64 * 1024: + bank->num_sectors = 16; + break; + case 128 * 1024: + bank->num_sectors = 18; + break; + case 256 * 1024: + bank->num_sectors = 22; + break; + case 512 * 1024: + bank->num_sectors = 30; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -497,18 +497,18 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) lpc2000_info->iap_max_stack = 208; switch (bank->size) { - case 256 * 1024: - bank->num_sectors = 11; - break; - case 384 * 1024: - bank->num_sectors = 13; - break; - case 512 * 1024: - bank->num_sectors = 15; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 256 * 1024: + bank->num_sectors = 11; + break; + case 384 * 1024: + bank->num_sectors = 13; + break; + case 512 * 1024: + bank->num_sectors = 15; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -529,30 +529,30 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) lpc2000_info->cmd51_max_buffer = 256; /* smallest MCU in the series, LPC810, has 1 kB of SRAM */ switch (bank->size) { - case 4 * 1024: - bank->num_sectors = 4; - break; - case 8 * 1024: - bank->num_sectors = 8; - break; - case 16 * 1024: - bank->num_sectors = 16; - break; - case 30 * 1024: - lpc2000_info->cmd51_max_buffer = 1024; /* For LPC8N04 and NHS31xx, have 8kB of SRAM */ - bank->num_sectors = 30; /* There have only 30kB of writable Flash out of 32kB */ - break; - case 32 * 1024: - lpc2000_info->cmd51_max_buffer = 1024; /* For LPC824, has 8kB of SRAM */ - bank->num_sectors = 32; - break; - case 64 * 1024: - lpc2000_info->cmd51_max_buffer = 1024; /* For LPC844, has 8kB of SRAM */ - bank->num_sectors = 64; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 4 * 1024: + bank->num_sectors = 4; + break; + case 8 * 1024: + bank->num_sectors = 8; + break; + case 16 * 1024: + bank->num_sectors = 16; + break; + case 30 * 1024: + lpc2000_info->cmd51_max_buffer = 1024; /* For LPC8N04 and NHS31xx, have 8kB of SRAM */ + bank->num_sectors = 30; /* There have only 30kB of writable Flash out of 32kB */ + break; + case 32 * 1024: + lpc2000_info->cmd51_max_buffer = 1024; /* For LPC824, has 8kB of SRAM */ + bank->num_sectors = 32; + break; + case 64 * 1024: + lpc2000_info->cmd51_max_buffer = 1024; /* For LPC844, has 8kB of SRAM */ + bank->num_sectors = 64; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -602,18 +602,18 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) lpc2000_info->iap_max_stack = 128; switch (bank->size) { - case 64 * 1024: - bank->num_sectors = 16; - break; - case 128 * 1024: - bank->num_sectors = 32; - break; - case 256 * 1024: - bank->num_sectors = 64; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 64 * 1024: + bank->num_sectors = 16; + break; + case 128 * 1024: + bank->num_sectors = 32; + break; + case 256 * 1024: + bank->num_sectors = 64; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -633,15 +633,15 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) lpc2000_info->iap_max_stack = 128; switch (bank->size) { - case 256 * 1024: - bank->num_sectors = 8; - break; - case 512 * 1024: - bank->num_sectors = 16; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 256 * 1024: + bank->num_sectors = 8; + break; + case 512 * 1024: + bank->num_sectors = 16; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -686,24 +686,24 @@ 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: - 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: - 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; - default: - LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); - exit(-1); + 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: + 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; + default: + LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); + exit(-1); } int retval = target_write_memory(target, (*iap_working_area)->address, 4, 2, jump_gate); @@ -729,36 +729,36 @@ 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: - armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; - armv7m_info.core_mode = ARM_MODE_THREAD; - iap_entry_point = 0x1fff1ff1; - break; - 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: - 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: - 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 */ - target_read_u32(target, 0x10400100, &iap_entry_point); - break; - default: - LOG_ERROR("BUG: unknown lpc2000->variant encountered"); - exit(-1); + 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: + 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: + 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: + 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 */ + target_read_u32(target, 0x10400100, &iap_entry_point); + break; + default: + LOG_ERROR("BUG: unknown lpc2000->variant encountered"); + exit(-1); } if (lpc2000_info->iap_entry_alternative != 0x0) @@ -791,43 +791,43 @@ 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: - /* IAP stack */ - init_reg_param(®_params[3], "sp", 32, PARAM_OUT); - buf_set_u32(reg_params[3].value, 0, 32, - iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); - - /* return address */ - init_reg_param(®_params[4], "lr", 32, PARAM_OUT); - buf_set_u32(reg_params[4].value, 0, 32, (iap_working_area->address + 0x04) | 1); - /* bit0 of LR = 1 to return in Thumb mode */ - - 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: - /* IAP stack */ - init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT); - buf_set_u32(reg_params[3].value, 0, 32, - iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); - - /* return address */ - init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT); - buf_set_u32(reg_params[4].value, 0, 32, iap_working_area->address + 0x04); - - target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, - iap_working_area->address + 0x4, 10000, &arm_algo); - break; - default: - LOG_ERROR("BUG: unknown lpc2000->variant encountered"); - exit(-1); + 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, + iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); + + /* return address */ + init_reg_param(®_params[4], "lr", 32, PARAM_OUT); + buf_set_u32(reg_params[4].value, 0, 32, (iap_working_area->address + 0x04) | 1); + /* bit0 of LR = 1 to return in Thumb mode */ + + 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: + /* IAP stack */ + init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT); + buf_set_u32(reg_params[3].value, 0, 32, + iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); + + /* return address */ + init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT); + buf_set_u32(reg_params[4].value, 0, 32, iap_working_area->address + 0x04); + + target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, + iap_working_area->address + 0x4, 10000, &arm_algo); + break; + default: + LOG_ERROR("BUG: unknown lpc2000->variant encountered"); + exit(-1); } int status_code = target_buffer_get_u32(target, mem_params[1].value); @@ -877,24 +877,24 @@ static int lpc2000_iap_blank_check(struct flash_bank *bank, unsigned int first, int status_code = lpc2000_iap_call(bank, iap_working_area, 53, param_table, result_table); switch (status_code) { - case ERROR_FLASH_OPERATION_FAILED: - retval = ERROR_FLASH_OPERATION_FAILED; - break; - case LPC2000_CMD_SUCCESS: - bank->sectors[i].is_erased = 1; - break; - case LPC2000_SECTOR_NOT_BLANK: - bank->sectors[i].is_erased = 0; - break; - case LPC2000_INVALID_SECTOR: - bank->sectors[i].is_erased = 0; - break; - case LPC2000_BUSY: - retval = ERROR_FLASH_BUSY; - break; - default: - LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code); - exit(-1); + case ERROR_FLASH_OPERATION_FAILED: + retval = ERROR_FLASH_OPERATION_FAILED; + break; + case LPC2000_CMD_SUCCESS: + bank->sectors[i].is_erased = 1; + break; + case LPC2000_SECTOR_NOT_BLANK: + bank->sectors[i].is_erased = 0; + break; + case LPC2000_INVALID_SECTOR: + bank->sectors[i].is_erased = 0; + break; + case LPC2000_BUSY: + retval = ERROR_FLASH_BUSY; + break; + default: + LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code); + exit(-1); } } @@ -1002,6 +1002,28 @@ static int lpc2000_erase(struct flash_bank *bank, unsigned int first, /* Prepare sectors */ int status_code = lpc2000_iap_call(bank, iap_working_area, 50, param_table, result_table); switch (status_code) { + case ERROR_FLASH_OPERATION_FAILED: + retval = ERROR_FLASH_OPERATION_FAILED; + break; + case LPC2000_CMD_SUCCESS: + break; + case LPC2000_INVALID_SECTOR: + retval = ERROR_FLASH_SECTOR_INVALID; + break; + default: + LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); + retval = ERROR_FLASH_OPERATION_FAILED; + break; + } + + if (retval == ERROR_OK) { + /* Erase sectors */ + param_table[2] = lpc2000_info->cclk; + 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); + switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; @@ -1011,31 +1033,9 @@ static int lpc2000_erase(struct flash_bank *bank, unsigned int first, retval = ERROR_FLASH_SECTOR_INVALID; break; default: - LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); + LOG_WARNING("lpc2000 erase sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; - } - - if (retval == ERROR_OK) { - /* Erase sectors */ - param_table[2] = lpc2000_info->cclk; - 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); - switch (status_code) { - case ERROR_FLASH_OPERATION_FAILED: - retval = ERROR_FLASH_OPERATION_FAILED; - break; - case LPC2000_CMD_SUCCESS: - break; - case LPC2000_INVALID_SECTOR: - retval = ERROR_FLASH_SECTOR_INVALID; - break; - default: - LOG_WARNING("lpc2000 erase sectors returned %i", status_code); - retval = ERROR_FLASH_OPERATION_FAILED; - break; } } @@ -1145,18 +1145,18 @@ static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ int status_code = lpc2000_iap_call(bank, iap_working_area, 50, param_table, result_table); switch (status_code) { - case ERROR_FLASH_OPERATION_FAILED: - retval = ERROR_FLASH_OPERATION_FAILED; - break; - case LPC2000_CMD_SUCCESS: - break; - case LPC2000_INVALID_SECTOR: - retval = ERROR_FLASH_SECTOR_INVALID; - break; - default: - LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); - retval = ERROR_FLASH_OPERATION_FAILED; - break; + case ERROR_FLASH_OPERATION_FAILED: + retval = ERROR_FLASH_OPERATION_FAILED; + break; + case LPC2000_CMD_SUCCESS: + break; + case LPC2000_INVALID_SECTOR: + retval = ERROR_FLASH_SECTOR_INVALID; + break; + default: + LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); + retval = ERROR_FLASH_OPERATION_FAILED; + break; } /* Exit if error occurred */ @@ -1187,18 +1187,18 @@ static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ param_table[3] = lpc2000_info->cclk; status_code = lpc2000_iap_call(bank, iap_working_area, 51, param_table, result_table); switch (status_code) { - case ERROR_FLASH_OPERATION_FAILED: - retval = ERROR_FLASH_OPERATION_FAILED; - break; - case LPC2000_CMD_SUCCESS: - break; - case LPC2000_INVALID_SECTOR: - retval = ERROR_FLASH_SECTOR_INVALID; - break; - default: - LOG_WARNING("lpc2000 returned %i", status_code); - retval = ERROR_FLASH_OPERATION_FAILED; - break; + case ERROR_FLASH_OPERATION_FAILED: + retval = ERROR_FLASH_OPERATION_FAILED; + break; + case LPC2000_CMD_SUCCESS: + break; + case LPC2000_INVALID_SECTOR: + retval = ERROR_FLASH_SECTOR_INVALID; + break; + default: + LOG_WARNING("lpc2000 returned %i", status_code); + retval = ERROR_FLASH_OPERATION_FAILED; + break; } /* Exit if error occurred */ @@ -1267,240 +1267,240 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) } switch (part_id) { - case LPC1110_1: - case LPC1110_2: - lpc2000_info->variant = LPC1100; - bank->size = 4 * 1024; - break; - - case LPC1111_002_1: - case LPC1111_002_2: - case LPC1111_101_1: - case LPC1111_101_2: - case LPC1111_103_1: - case LPC1111_201_1: - case LPC1111_201_2: - case LPC1111_203_1: - case LPC11A11_001_1: - case LPC11E11_101: - case LPC1311: - case LPC1311_1: - lpc2000_info->variant = LPC1100; - bank->size = 8 * 1024; - break; - - case LPC1112_101_1: - case LPC1112_101_2: - case LPC1112_102_1: - case LPC1112_102_2: - case LPC1112_103_1: - case LPC1112_201_1: - case LPC1112_201_2: - case LPC1112_203_1: - case LPC11A02_1: - case LPC11C12_301_1: - case LPC11C22_301_1: - case LPC11A12_101_1: - case LPC11E12_201: - case LPC11U12_201_1: - case LPC11U12_201_2: - case LPC1342: - lpc2000_info->variant = LPC1100; - bank->size = 16 * 1024; - break; - - case LPC1113_201_1: - case LPC1113_201_2: - case LPC1113_203_1: - case LPC1113_301_1: - case LPC1113_301_2: - case LPC1113_303_1: - case LPC11A13_201_1: - case LPC11E13_301: - case LPC11U13_201_1: - case LPC11U13_201_2: - case LPC11U23_301: - lpc2000_info->variant = LPC1100; - bank->size = 24 * 1024; - break; - - case LPC1114_102_1: - case LPC1114_102_2: - case LPC1114_201_1: - case LPC1114_201_2: - case LPC1114_203_1: - case LPC1114_301_1: - case LPC1114_301_2: - case LPC1114_303_1: - case LPC11A04_1: - case LPC11A14_301_1: - case LPC11A14_301_2: - case LPC11C14_301_1: - case LPC11C24_301_1: - case LPC11E14_401: - case LPC11U14_201_1: - case LPC11U14_201_2: - case LPC11U24_301: - case LPC11U24_401: - case LPC1313: - case LPC1313_1: - case LPC1315: - case LPC1343: - case LPC1343_1: - case LPC1345: - lpc2000_info->variant = LPC1100; - bank->size = 32 * 1024; - break; - - case LPC1751_1: - case LPC1751_2: - lpc2000_info->variant = LPC1700; - bank->size = 32 * 1024; - break; - - case LPC11U34_311: - lpc2000_info->variant = LPC1100; - bank->size = 40 * 1024; - break; - - case LPC1114_323_1: - case LPC11U34_421: - case LPC1316: - case LPC1346: - lpc2000_info->variant = LPC1100; - bank->size = 48 * 1024; - break; - - case LPC1114_333_1: - lpc2000_info->variant = LPC1100; - bank->size = 56 * 1024; - break; - - case LPC1115_303_1: - case LPC11U35_401: - case LPC11U35_501: - case LPC11E66: - case LPC11U66: - case LPC1317: - case LPC1347: - lpc2000_info->variant = LPC1100; - bank->size = 64 * 1024; - break; - - case LPC1752: - case LPC4072: - lpc2000_info->variant = LPC1700; - bank->size = 64 * 1024; - break; + case LPC1110_1: + case LPC1110_2: + lpc2000_info->variant = LPC1100; + bank->size = 4 * 1024; + break; + + case LPC1111_002_1: + case LPC1111_002_2: + case LPC1111_101_1: + case LPC1111_101_2: + case LPC1111_103_1: + case LPC1111_201_1: + case LPC1111_201_2: + case LPC1111_203_1: + case LPC11A11_001_1: + case LPC11E11_101: + case LPC1311: + case LPC1311_1: + lpc2000_info->variant = LPC1100; + bank->size = 8 * 1024; + break; + + case LPC1112_101_1: + case LPC1112_101_2: + case LPC1112_102_1: + case LPC1112_102_2: + case LPC1112_103_1: + case LPC1112_201_1: + case LPC1112_201_2: + case LPC1112_203_1: + case LPC11A02_1: + case LPC11C12_301_1: + case LPC11C22_301_1: + case LPC11A12_101_1: + case LPC11E12_201: + case LPC11U12_201_1: + case LPC11U12_201_2: + case LPC1342: + lpc2000_info->variant = LPC1100; + bank->size = 16 * 1024; + break; + + case LPC1113_201_1: + case LPC1113_201_2: + case LPC1113_203_1: + case LPC1113_301_1: + case LPC1113_301_2: + case LPC1113_303_1: + case LPC11A13_201_1: + case LPC11E13_301: + case LPC11U13_201_1: + case LPC11U13_201_2: + case LPC11U23_301: + lpc2000_info->variant = LPC1100; + bank->size = 24 * 1024; + break; + + case LPC1114_102_1: + case LPC1114_102_2: + case LPC1114_201_1: + case LPC1114_201_2: + case LPC1114_203_1: + case LPC1114_301_1: + case LPC1114_301_2: + case LPC1114_303_1: + case LPC11A04_1: + case LPC11A14_301_1: + case LPC11A14_301_2: + case LPC11C14_301_1: + case LPC11C24_301_1: + case LPC11E14_401: + case LPC11U14_201_1: + case LPC11U14_201_2: + case LPC11U24_301: + case LPC11U24_401: + case LPC1313: + case LPC1313_1: + case LPC1315: + case LPC1343: + case LPC1343_1: + case LPC1345: + lpc2000_info->variant = LPC1100; + bank->size = 32 * 1024; + break; - case LPC11E36_501: - case LPC11U36_401: - lpc2000_info->variant = LPC1100; - bank->size = 96 * 1024; - break; + case LPC1751_1: + case LPC1751_2: + lpc2000_info->variant = LPC1700; + bank->size = 32 * 1024; + break; - case LPC11E37_401: - case LPC11E37_501: - case LPC11U37_401: - case LPC11U37H_401: - case LPC11U37_501: - case LPC11E67: - case LPC11E68: - case LPC11U67_1: - case LPC11U67_2: - lpc2000_info->variant = LPC1100; - bank->size = 128 * 1024; - break; + case LPC11U34_311: + lpc2000_info->variant = LPC1100; + bank->size = 40 * 1024; + break; - case LPC1754: - case LPC1764: - case LPC1774: - case LPC4074: - lpc2000_info->variant = LPC1700; - bank->size = 128 * 1024; - break; + case LPC1114_323_1: + case LPC11U34_421: + case LPC1316: + case LPC1346: + lpc2000_info->variant = LPC1100; + bank->size = 48 * 1024; + break; - case LPC11U68_1: - case LPC11U68_2: - lpc2000_info->variant = LPC1100; - bank->size = 256 * 1024; - break; + case LPC1114_333_1: + lpc2000_info->variant = LPC1100; + bank->size = 56 * 1024; + break; + + case LPC1115_303_1: + case LPC11U35_401: + case LPC11U35_501: + case LPC11E66: + case LPC11U66: + case LPC1317: + case LPC1347: + lpc2000_info->variant = LPC1100; + bank->size = 64 * 1024; + break; - case LPC1756: - case LPC1763: - case LPC1765: - case LPC1766: - case LPC1776: - case LPC1785: - case LPC1786: - case LPC4076: - lpc2000_info->variant = LPC1700; - bank->size = 256 * 1024; - break; + case LPC1752: + case LPC4072: + lpc2000_info->variant = LPC1700; + bank->size = 64 * 1024; + break; - case LPC1758: - case LPC1759: - case LPC1767: - case LPC1768: - case LPC1769: - case LPC1777: - case LPC1778: - case LPC1787: - case LPC1788: - case LPC4078: - case LPC4088: - lpc2000_info->variant = LPC1700; - bank->size = 512 * 1024; - break; + case LPC11E36_501: + case LPC11U36_401: + lpc2000_info->variant = LPC1100; + bank->size = 96 * 1024; + break; + + case LPC11E37_401: + case LPC11E37_501: + case LPC11U37_401: + case LPC11U37H_401: + case LPC11U37_501: + case LPC11E67: + case LPC11E68: + case LPC11U67_1: + case LPC11U67_2: + lpc2000_info->variant = LPC1100; + bank->size = 128 * 1024; + break; - case LPC810_021: - lpc2000_info->variant = LPC800; - bank->size = 4 * 1024; - break; + case LPC1754: + case LPC1764: + case LPC1774: + case LPC4074: + lpc2000_info->variant = LPC1700; + bank->size = 128 * 1024; + break; - case LPC811_001: - lpc2000_info->variant = LPC800; - bank->size = 8 * 1024; - break; + case LPC11U68_1: + case LPC11U68_2: + lpc2000_info->variant = LPC1100; + bank->size = 256 * 1024; + break; + + case LPC1756: + case LPC1763: + case LPC1765: + case LPC1766: + case LPC1776: + case LPC1785: + case LPC1786: + case LPC4076: + lpc2000_info->variant = LPC1700; + bank->size = 256 * 1024; + break; + + case LPC1758: + case LPC1759: + case LPC1767: + case LPC1768: + case LPC1769: + case LPC1777: + case LPC1778: + case LPC1787: + case LPC1788: + case LPC4078: + case LPC4088: + lpc2000_info->variant = LPC1700; + bank->size = 512 * 1024; + break; - case LPC812_101: - case LPC812_101_1: - case LPC812_101_2: - case LPC812_101_3: - case LPC822_101: - case LPC822_101_1: - lpc2000_info->variant = LPC800; - bank->size = 16 * 1024; - break; + case LPC810_021: + lpc2000_info->variant = LPC800; + bank->size = 4 * 1024; + break; - case LPC824_201: - case LPC824_201_1: - lpc2000_info->variant = LPC800; - bank->size = 32 * 1024; - break; + case LPC811_001: + lpc2000_info->variant = LPC800; + bank->size = 8 * 1024; + break; + + case LPC812_101: + case LPC812_101_1: + case LPC812_101_2: + case LPC812_101_3: + case LPC822_101: + case LPC822_101_1: + lpc2000_info->variant = LPC800; + bank->size = 16 * 1024; + break; - case LPC8N04: - case NHS3100: - case NHS3152: - case NHS3153: - lpc2000_info->variant = LPC800; - bank->size = 30 * 1024; - break; + case LPC824_201: + case LPC824_201_1: + lpc2000_info->variant = LPC800; + bank->size = 32 * 1024; + break; - case LPC844_201: - case LPC844_201_1: - case LPC844_201_2: - case LPC845_301: - case LPC845_301_1: - case LPC845_301_2: - case LPC845_301_3: - lpc2000_info->variant = LPC800; - bank->size = 64 * 1024; - break; + case LPC8N04: + case NHS3100: + case NHS3152: + case NHS3153: + lpc2000_info->variant = LPC800; + bank->size = 30 * 1024; + break; + + case LPC844_201: + case LPC844_201_1: + case LPC844_201_2: + case LPC845_301: + case LPC845_301_1: + case LPC845_301_2: + case LPC845_301_3: + lpc2000_info->variant = LPC800; + bank->size = 64 * 1024; + break; - default: - LOG_ERROR("BUG: unknown Part ID encountered: 0x%" PRIx32, part_id); - exit(-1); + default: + LOG_ERROR("BUG: unknown Part ID encountered: 0x%" PRIx32, part_id); + exit(-1); } return ERROR_OK; diff --git a/src/flash/nor/lpc288x.c b/src/flash/nor/lpc288x.c index 3006db1cbf..d7a4fdf24f 100644 --- a/src/flash/nor/lpc288x.c +++ b/src/flash/nor/lpc288x.c @@ -279,7 +279,7 @@ static int lpc288x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ /* all writes must start on a sector boundary... */ if (offset % bank->sectors[i].size) { LOG_INFO( - "offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", + "offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, bank->sectors[i].size); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; @@ -293,7 +293,7 @@ static int lpc288x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ /* Range check... */ if (first_sector == 0xffffffff || last_sector == 0xffffffff) { - LOG_INFO("Range check failed %" PRIx32 " %" PRIx32 "", offset, count); + LOG_INFO("Range check failed %" PRIx32 " %" PRIx32, offset, count); return ERROR_FLASH_DST_OUT_OF_BANK; } diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c index f950f21db7..c5db16c92a 100644 --- a/src/flash/nor/lpcspifi.c +++ b/src/flash/nor/lpcspifi.c @@ -445,11 +445,10 @@ static int lpcspifi_erase(struct flash_bank *bank, unsigned int first, " Will use bulk erase instead of sector-by-sector erase."); retval = lpcspifi_bulk_erase(bank); - if (retval == ERROR_OK) { - retval = lpcspifi_set_hw_mode(bank); - return retval; - } else - LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase."); + if (retval == ERROR_OK) + return lpcspifi_set_hw_mode(bank); + + LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase."); } if (lpcspifi_info->dev->erase_cmd == 0x00) @@ -554,9 +553,7 @@ static int lpcspifi_erase(struct flash_bank *bank, unsigned int first, destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); - retval = lpcspifi_set_hw_mode(bank); - - return retval; + return lpcspifi_set_hw_mode(bank); } static int lpcspifi_protect(struct flash_bank *bank, int set, @@ -749,8 +746,7 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer, destroy_reg_param(®_params[4]); /* Switch to HW mode before return to prompt */ - retval = lpcspifi_set_hw_mode(bank); - return retval; + return lpcspifi_set_hw_mode(bank); } /* Return ID of flash device */ diff --git a/src/flash/nor/max32xxx.c b/src/flash/nor/max32xxx.c index 267fd43120..e91b9b67d5 100644 --- a/src/flash/nor/max32xxx.c +++ b/src/flash/nor/max32xxx.c @@ -2,7 +2,7 @@ /*************************************************************************** * Copyright (C) 2016 by Maxim Integrated * - * Kevin Gillespie * + * Copyright (C) 2025 Analog Devices, Inc. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -13,90 +13,112 @@ #include #include #include - -/* Register Addresses */ -#define FLSH_ADDR 0x000 -#define FLSH_CLKDIV 0x004 -#define FLSH_CN 0x008 -#define PR1E_ADDR 0x00C -#define PR2S_ADDR 0x010 -#define PR2E_ADDR 0x014 -#define PR3S_ADDR 0x018 -#define PR3E_ADDR 0x01C -#define FLSH_MD 0x020 -#define FLSH_INT 0x024 -#define FLSH_DATA0 0x030 -#define FLSH_DATA1 0x034 -#define FLSH_DATA2 0x038 -#define FLSH_DATA3 0x03C -#define FLSH_BL_CTRL 0x170 -#define FLSH_PROT 0x300 - -#define ARM_PID_REG 0xE00FFFE0 -#define MAX326XX_ID_REG 0x40000838 - -/* Register settings */ -#define FLSH_INT_AF 0x00000002 - -#define FLSH_CN_UNLOCK_MASK 0xF0000000 -#define FLSH_CN_UNLOCK_VALUE 0x20000000 - -#define FLSH_CN_PEND 0x01000000 - -#define FLSH_CN_ERASE_CODE_MASK 0x0000FF00 -#define FLSH_CN_ERASE_CODE_PGE 0x00005500 -#define FLSH_CN_ERASE_CODE_ME 0x0000AA00 - -#define FLSH_CN_PGE 0x00000004 -#define FLSH_CN_ME 0x00000002 -#define FLSH_CN_WR 0x00000001 -#define FLASH_BL_CTRL_23 0x00020000 -#define FLASH_BL_CTRL_IFREN 0x00000001 - -#define ARM_PID_DEFAULT_CM3 0xB4C3 -#define ARM_PID_DEFAULT_CM4 0xB4C4 -#define MAX326XX_ID 0x4D +#include +#include + +// Register addresses +#define FLC_ADDR 0x00000000 +#define FLC_CLKDIV 0x00000004 +#define FLC_CN 0x00000008 +#define FLC_PR1E_ADDR 0x0000000C +#define FLC_PR2S_ADDR 0x00000010 +#define FLC_PR2E_ADDR 0x00000014 +#define FLC_PR3S_ADDR 0x00000018 +#define FLC_PR3E_ADDR 0x0000001C +#define FLC_MD 0x00000020 +#define FLC_INT 0x00000024 +#define FLC_DATA0 0x00000030 +#define FLC_DATA1 0x00000034 +#define FLC_DATA2 0x00000038 +#define FLC_DATA3 0x0000003C +#define FLC_BL_CTRL 0x00000170 +#define FLC_PROT 0x00000300 + +#define ARM_PID_REG 0xE00FFFE0 +#define MAX326XX_ID_REG 0x40000838 + +// Register settings +#define FLC_INT_AF 0x00000002 + +#define FLC_CN_UNLOCK_MASK 0xF0000000 +#define FLC_CN_UNLOCK_VALUE 0x20000000 + +#define FLC_CN_PEND 0x01000000 +#define FLC_CN_ERASE_CODE_MASK 0x0000FF00 +#define FLC_CN_ERASE_CODE_PGE 0x00005500 +#define FLC_CN_ERASE_CODE_ME 0x0000AA00 +#define FLC_CN_32BIT 0x00000010 +#define FLC_CN_PGE 0x00000004 +#define FLC_CN_ME 0x00000002 +#define FLC_CN_WR 0x00000001 +#define FLC_CN_PGE 0x00000004 +#define FLC_CN_ME 0x00000002 +#define FLC_CN_WR 0x00000001 + +#define FLC_BL_CTRL_23 0x00020000 +#define FLC_BL_CTRL_IFREN 0x00000001 + +#define MASK_FLASH_BUSY (0x048800E0 & ~0x04000000) +#define MASK_DISABLE_INTS (0xFFFFFCFC) +#define MASK_FLASH_UNLOCKED (0xF588FFEF & ~0x04000000) +#define MASK_FLASH_LOCK (0xF588FFEF & ~0x04000000) +#define MASK_FLASH_ERASE (0xF588FFEF & ~0x04000000) +#define MASK_FLASH_ERASED (0xF48800EB & ~0x04000000) +#define MASK_ACCESS_VIOLATIONS (0xFFFFFCFC) +#define MASK_FLASH_WRITE (0xF588FFEF & ~0x04000000) +#define MASK_WRITE_ALIGNED (0xF588FFEF & ~0x04000000) +#define MASK_WRITE_COMPLETE (0xF488FFEE & ~0x04000000) +#define MASK_WRITE_BURST (0xF588FFEF & ~0x04000000) +#define MASK_BURST_COMPLETE (0xF488FFEE & ~0x04000000) +#define MASK_WRITE_REMAINING (0xF588FFEF & ~0x04000000) +#define MASK_REMAINING_COMPLETE (0xF488FFEE & ~0x04000000) +#define MASK_MASS_ERASE (0xF588FFEF & ~0x04000000) +#define MASK_ERASE_COMPLETE (0xF48800ED & ~0x04000000) + +#define ARM_PID_DEFAULT_CM3 0x0000B4C3 +#define ARM_PID_DEFAULT_CM4 0x0000B4C4 +#define MAX326XX_ID 0x0000004D + +#define OPTIONS_128 0x01 // Perform 128 bit flash writes +#define OPTIONS_ENC 0x02 // Encrypt the flash contents +#define OPTIONS_AUTH 0x04 // Authenticate the flash contents +#define OPTIONS_COUNT 0x08 // Add counter values to authentication +#define OPTIONS_INTER 0x10 // Interleave the authentication and count values +#define OPTIONS_RELATIVE_XOR 0x20 // Only XOR the offset of the address when encrypting +#define OPTIONS_KEYSIZE 0x40 // Use a 256 bit KEY static int max32xxx_mass_erase(struct flash_bank *bank); struct max32xxx_flash_bank { bool probed; - int max326xx; + bool max326xx; unsigned int flash_size; unsigned int flc_base; unsigned int sector_size; unsigned int clkdiv_value; - uint32_t int_state; - unsigned int burst_size_bits; + unsigned int int_state; + unsigned int options; }; -/* see contrib/loaders/flash/max32xxx/max32xxx.s for src */ -static const uint8_t write_code[] = { -#include "../../../contrib/loaders/flash/max32xxx/max32xxx.inc" +static const uint8_t write_code_arm[] = { +#include "../../../contrib/loaders/flash/max32xxx/max32xxx_write_arm.inc" }; -/* Config Command: flash bank name driver base size chip_width bus_width target [driver_option] - flash bank max32xxx 0 0 [burst_bits] - */ FLASH_BANK_COMMAND_HANDLER(max32xxx_flash_bank_command) { struct max32xxx_flash_bank *info; - if (CMD_ARGC < 9) { - LOG_WARNING("incomplete flash bank max32xxx configuration: 0 0 [burst_bits]"); + if (CMD_ARGC != 10) { + LOG_ERROR("incorrect flash bank max32xxx configuration: 0 0 "); return ERROR_FLASH_BANK_INVALID; } info = calloc(1, sizeof(struct max32xxx_flash_bank)); - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], info->flash_size); - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[6], info->flc_base); - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[7], info->sector_size); - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[8], info->clkdiv_value); - - if (CMD_ARGC > 9) - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[9], info->burst_size_bits); - else - info->burst_size_bits = 32; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], info->flash_size); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->flc_base); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], info->sector_size); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[8], info->clkdiv_value); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[9], info->options); info->int_state = 0; bank->driver_priv = info; @@ -114,63 +136,67 @@ static int get_info(struct flash_bank *bank, struct command_invocation *cmd) return ERROR_OK; } -/*************************************************************************** -* flash operations -***************************************************************************/ +static bool max32xxx_flash_busy(uint32_t flash_cn) +{ + if (flash_cn & (FLC_CN_PGE | FLC_CN_ME | FLC_CN_WR)) + return true; + + return false; +} static int max32xxx_flash_op_pre(struct flash_bank *bank) { struct target *target = bank->target; struct max32xxx_flash_bank *info = bank->driver_priv; - uint32_t flsh_cn; + uint32_t flash_cn; uint32_t bootloader; - /* Check if the flash controller is busy */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - if (flsh_cn & (FLSH_CN_PEND | FLSH_CN_ERASE_CODE_MASK | FLSH_CN_PGE | - FLSH_CN_ME | FLSH_CN_WR)) + // Check if the flash controller is busy + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + if (max32xxx_flash_busy(flash_cn)) return ERROR_FLASH_BUSY; - /* Refresh flash controller timing */ - target_write_u32(target, info->flc_base + FLSH_CLKDIV, info->clkdiv_value); + // Refresh flash controller timing + target_write_u32(target, info->flc_base + FLC_CLKDIV, info->clkdiv_value); - /* Clear and disable flash programming interrupts */ - target_read_u32(target, info->flc_base + FLSH_INT, &info->int_state); - target_write_u32(target, info->flc_base + FLSH_INT, 0x00000000); + // Clear and disable flash programming interrupts + target_read_u32(target, info->flc_base + FLC_INT, &info->int_state); + target_write_u32(target, info->flc_base + FLC_INT, 0); - /* Clear the lower bit in the bootloader configuration register in case flash page 0 has been replaced */ - if (target_read_u32(target, info->flc_base + FLSH_BL_CTRL, &bootloader) != ERROR_OK) { - LOG_ERROR("Read failure on FLSH_BL_CTRL"); + /* Clear the lower bit in the bootloader configuration register in case flash page 0 has + * been replaced */ + if (target_read_u32(target, info->flc_base + FLC_BL_CTRL, &bootloader) != ERROR_OK) { + LOG_ERROR("Read failure on FLC_BL_CTRL"); return ERROR_FAIL; } - if (bootloader & FLASH_BL_CTRL_23) { - LOG_WARNING("FLSH_BL_CTRL indicates BL mode 2 or mode 3."); - if (bootloader & FLASH_BL_CTRL_IFREN) { + if (bootloader & FLC_BL_CTRL_23) { + LOG_WARNING("FLC_BL_CTRL indicates BL mode 2 or mode 3."); + if (bootloader & FLC_BL_CTRL_IFREN) { LOG_WARNING("Flash page 0 swapped out, attempting to swap back in for programming"); - bootloader &= ~(FLASH_BL_CTRL_IFREN); - if (target_write_u32(target, info->flc_base + FLSH_BL_CTRL, bootloader) != ERROR_OK) { - LOG_ERROR("Write failure on FLSH_BL_CTRL"); + bootloader &= ~(FLC_BL_CTRL_IFREN); + if (target_write_u32(target, info->flc_base + FLC_BL_CTRL, + bootloader) != ERROR_OK) { + LOG_ERROR("Write failure on FLC_BL_CTRL"); return ERROR_FAIL; } - if (target_read_u32(target, info->flc_base + FLSH_BL_CTRL, &bootloader) != ERROR_OK) { - LOG_ERROR("Read failure on FLSH_BL_CTRL"); + if (target_read_u32(target, info->flc_base + FLC_BL_CTRL, + &bootloader) != ERROR_OK) { + LOG_ERROR("Read failure on FLC_BL_CTRL"); return ERROR_FAIL; } - if (bootloader & FLASH_BL_CTRL_IFREN) { - /* Bummer */ + if (bootloader & FLC_BL_CTRL_IFREN) LOG_ERROR("Unable to swap flash page 0 back in. Writes to page 0 will fail."); - } } } - /* Unlock flash */ - flsh_cn &= ~FLSH_CN_UNLOCK_MASK; - flsh_cn |= FLSH_CN_UNLOCK_VALUE; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Unlock flash + flash_cn &= ~(FLC_CN_UNLOCK_MASK); + flash_cn |= FLC_CN_UNLOCK_VALUE; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* Confirm flash is unlocked */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - if ((flsh_cn & FLSH_CN_UNLOCK_VALUE) != FLSH_CN_UNLOCK_VALUE) + // Confirm flash is unlocked + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + if ((flash_cn & FLC_CN_UNLOCK_VALUE) != FLC_CN_UNLOCK_VALUE) return ERROR_FAIL; return ERROR_OK; @@ -180,15 +206,15 @@ static int max32xxx_flash_op_post(struct flash_bank *bank) { struct target *target = bank->target; struct max32xxx_flash_bank *info = bank->driver_priv; - uint32_t flsh_cn; + uint32_t flash_cn; - /* Restore flash programming interrupts */ - target_write_u32(target, info->flc_base + FLSH_INT, info->int_state); + // Restore flash programming interrupts + target_write_u32(target, info->flc_base + FLC_INT, info->int_state); - /* Lock flash */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn &= ~FLSH_CN_UNLOCK_MASK; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Lock flash + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn &= ~(FLC_CN_UNLOCK_MASK); + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); return ERROR_OK; } @@ -208,12 +234,12 @@ static int max32xxx_protect_check(struct flash_bank *bank) return ERROR_FLASH_OPER_UNSUPPORTED; } - /* Check the protection */ + // Check the protection for (unsigned int i = 0; i < bank->num_sectors; i++) { - if (i%32 == 0) - target_read_u32(target, info->flc_base + FLSH_PROT + ((i/32)*4), &temp_reg); + if (i % 32 == 0) + target_read_u32(target, info->flc_base + FLC_PROT + ((i / 32) * 4), &temp_reg); - if (temp_reg & (0x1 << i%32)) + if (temp_reg & (0x1 << i % 32)) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; @@ -222,9 +248,9 @@ static int max32xxx_protect_check(struct flash_bank *bank) } static int max32xxx_erase(struct flash_bank *bank, unsigned int first, - unsigned int last) + unsigned int last) { - uint32_t flsh_cn, flsh_int; + uint32_t flash_cn, flash_int; struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; int retval; @@ -238,13 +264,13 @@ static int max32xxx_erase(struct flash_bank *bank, unsigned int first, if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; - if ((last < first) || (last >= bank->num_sectors)) + if (last < first || last >= bank->num_sectors) return ERROR_FLASH_SECTOR_INVALID; - if ((first == 0) && (last == (bank->num_sectors - 1))) + if (first == 0 && last == (bank->num_sectors - 1)) return max32xxx_mass_erase(bank); - /* Prepare to issue flash operation */ + // Prepare to issue flash operation retval = max32xxx_flash_op_pre(bank); if (retval != ERROR_OK) @@ -252,43 +278,43 @@ static int max32xxx_erase(struct flash_bank *bank, unsigned int first, int erased = 0; for (unsigned int banknr = first; banknr <= last; banknr++) { - - /* Check the protection */ + // Check the protection if (bank->sectors[banknr].is_protected == 1) { LOG_WARNING("Flash sector %u is protected", banknr); continue; - } else + } else { erased = 1; + } - /* Address is first word in page */ - target_write_u32(target, info->flc_base + FLSH_ADDR, banknr * info->sector_size); + // Address is first word in page + target_write_u32(target, info->flc_base + FLC_ADDR, banknr * info->sector_size); - /* Write page erase code */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn |= FLSH_CN_ERASE_CODE_PGE; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Write page erase code + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn |= FLC_CN_ERASE_CODE_PGE; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* Issue page erase command */ - flsh_cn |= 0x4; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Issue page erase command + flash_cn |= FLC_CN_PGE; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* Wait until erase complete */ + // Wait until erase complete retry = 1000; do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + } while ((--retry > 0) && max32xxx_flash_busy(flash_cn)); if (retry <= 0) { - LOG_ERROR("Timed out waiting for flash page erase @ 0x%08x", - banknr * info->sector_size); + LOG_ERROR("Timed out waiting for flash page erase @ 0x%08" PRIx32, + (banknr * info->sector_size)); return ERROR_FLASH_OPERATION_FAILED; } - /* Check access violations */ - target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); - if (flsh_int & FLSH_INT_AF) { + // Check access violations + target_read_u32(target, info->flc_base + FLC_INT, &flash_int); + if (flash_int & FLC_INT_AF) { LOG_ERROR("Error erasing flash page %i", banknr); - target_write_u32(target, info->flc_base + FLSH_INT, 0); + target_write_u32(target, info->flc_base + FLC_INT, 0); max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } @@ -307,7 +333,7 @@ static int max32xxx_erase(struct flash_bank *bank, unsigned int first, } static int max32xxx_protect(struct flash_bank *bank, int set, - unsigned int first, unsigned int last) + unsigned int first, unsigned int last) { struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; @@ -324,22 +350,22 @@ static int max32xxx_protect(struct flash_bank *bank, int set, if (!info->max326xx) return ERROR_FLASH_OPER_UNSUPPORTED; - if ((last < first) || (last >= bank->num_sectors)) + if (last < first || last >= bank->num_sectors) return ERROR_FLASH_SECTOR_INVALID; - /* Setup the protection on the pages given */ + // Setup the protection on the pages given for (unsigned int page = first; page <= last; page++) { if (set) { - /* Set the write/erase bit for this page */ - target_read_u32(target, info->flc_base + FLSH_PROT + (page/32), &temp_reg); - temp_reg |= (0x1 << page%32); - target_write_u32(target, info->flc_base + FLSH_PROT + (page/32), temp_reg); + // Set the write/erase bit for this page + target_read_u32(target, info->flc_base + FLC_PROT + (page / 32), &temp_reg); + temp_reg |= (0x1 << page % 32); + target_write_u32(target, info->flc_base + FLC_PROT + (page / 32), temp_reg); bank->sectors[page].is_protected = 1; } else { - /* Clear the write/erase bit for this page */ - target_read_u32(target, info->flc_base + FLSH_PROT + (page/32), &temp_reg); - temp_reg &= ~(0x1 << page%32); - target_write_u32(target, info->flc_base + FLSH_PROT + (page/32), temp_reg); + // Clear the write/erase bit for this page + target_read_u32(target, info->flc_base + FLC_PROT + (page / 32), &temp_reg); + temp_reg &= ~(0x1 << page % 32); + target_write_u32(target, info->flc_base + FLC_PROT + (page / 32), temp_reg); bank->sectors[page].is_protected = 0; } } @@ -348,38 +374,41 @@ static int max32xxx_protect(struct flash_bank *bank, int set, } static int max32xxx_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t wcount) + uint32_t offset, uint32_t len) { struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; + const char *target_type_name = (const char *)target->type->name; uint32_t buffer_size = 16384; struct working_area *source; struct working_area *write_algorithm; - uint32_t address = bank->base + offset; struct reg_param reg_params[5]; + struct mem_param mem_param[2]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - /* power of two, and multiple of word size */ + // power of two, and multiple of word size static const unsigned int buf_min = 128; + uint8_t *write_code; + int write_code_size; + - /* for small buffers it's faster not to download an algorithm */ - if (wcount * 4 < buf_min) + if (strcmp(target_type_name, "cortex_m") == 0) { + write_code = (uint8_t *)write_code_arm; + write_code_size = sizeof(write_code_arm); + } else { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } - LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "", - bank, buffer, offset, wcount); + LOG_DEBUG("bank=%p buffer=%p offset=%08" PRIx32 " len=%08" PRIx32 "", + bank, buffer, offset, len); - /* flash write code */ - if (target_alloc_working_area(target, sizeof(write_code), &write_algorithm) != ERROR_OK) { + // flash write code + if (target_alloc_working_area(target, write_code_size, &write_algorithm) != ERROR_OK) { LOG_DEBUG("no working area for block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - /* plus a buffer big enough for this data */ - if (wcount * 4 < buffer_size) - buffer_size = wcount * 4; - - /* memory buffer */ + // memory buffer while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; @@ -392,24 +421,53 @@ static int max32xxx_write_block(struct flash_bank *bank, const uint8_t *buffer, target_name(target), buffer_size); } - target_write_buffer(target, write_algorithm->address, sizeof(write_code), + target_write_buffer(target, write_algorithm->address, write_code_size, write_code); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; - 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); + + // TODO: a0-a3 for RISCV + + if (strcmp(target_type_name, "cortex_m") == 0) { + 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); + } else { + init_reg_param(®_params[0], "a0", 32, PARAM_OUT); + init_reg_param(®_params[1], "a1", 32, PARAM_OUT); + init_reg_param(®_params[2], "a2", 32, PARAM_OUT); + init_reg_param(®_params[3], "a3", 32, PARAM_OUT); + } + init_reg_param(®_params[4], "sp", 32, PARAM_OUT); 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, wcount); - buf_set_u32(reg_params[4].value, 0, 32, info->flc_base); - retval = target_run_flash_async_algorithm(target, buffer, wcount, 4, 0, NULL, - 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); + buf_set_u32(reg_params[2].value, 0, 32, len); + buf_set_u32(reg_params[3].value, 0, 32, offset); + buf_set_u32(reg_params[4].value, 0, 32, source->address + source->size); + + // mem_params for options + init_mem_param(&mem_param[0], source->address + (source->size - 8 - 128), 4, PARAM_OUT); + init_mem_param(&mem_param[1], source->address + (source->size - 4 - 128), 4, PARAM_OUT); + buf_set_u32(mem_param[0].value, 0, 32, info->options); + buf_set_u32(mem_param[1].value, 0, 32, info->flc_base); + + // leave room for stack, 32-bit options and encryption buffer + retval = target_run_flash_async_algorithm(target, + buffer, + len, + 1, + 2, + mem_param, + 5, + reg_params, + source->address, + (source->size - 8 - 256), + write_algorithm->address, + 0, + &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) LOG_ERROR("error %d executing max32xxx flash write algorithm", retval); @@ -429,10 +487,9 @@ static int max32xxx_write(struct flash_bank *bank, const uint8_t *buffer, { struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; - uint32_t flsh_cn, flsh_int; + uint32_t flash_cn, flash_int; uint32_t address = offset; uint32_t remaining = count; - uint32_t words_remaining; int retval; int retry; @@ -447,67 +504,74 @@ static int max32xxx_write(struct flash_bank *bank, const uint8_t *buffer, if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; - if (offset & 0x3) { - LOG_WARNING("offset size must be word aligned"); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + if ((info->options & OPTIONS_128) == 0) { + if (offset & 0x3) { + LOG_ERROR("offset size must be 32-bit aligned"); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + } else { + if (offset & 0xF) { + LOG_ERROR("offset size must be 128-bit aligned"); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; - /* Prepare to issue flash operation */ + // Prepare to issue flash operation retval = max32xxx_flash_op_pre(bank); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + max32xxx_flash_op_post(bank); return retval; + } - if (remaining >= 4) { - /* write in 32-bit units */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn &= 0xF7FFFFFF; - flsh_cn |= 0x00000010; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - - /* try using a block write */ - words_remaining = remaining / 4; - retval = max32xxx_write_block(bank, buffer, offset, words_remaining); + if (remaining >= 16) { + // try using a block write + retval = max32xxx_write_block(bank, buffer, offset, remaining); if (retval != ERROR_OK) { - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + if (info->options & OPTIONS_ENC) { + LOG_ERROR("Must use algorithm in working area for encryption"); + return ERROR_FLASH_OPERATION_FAILED; + } LOG_DEBUG("writing flash word-at-a-time"); - else { + } else { max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } } else { - /* all 32-bit words have been written */ - buffer += words_remaining * 4; - address += words_remaining * 4; - remaining -= words_remaining * 4; + // all words_remaining have been written + buffer += remaining; + address += remaining; + remaining -= remaining; } } - if ((remaining >= 4) && ((address & 0x1F) != 0)) { - /* write in 32-bit units until we are 128-bit aligned */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn &= 0xF7FFFFFF; - flsh_cn |= 0x00000010; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + if (((info->options & OPTIONS_128) == 0) && remaining >= 4) { + // write in 32-bit units + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn |= FLC_CN_32BIT; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - while ((remaining >= 4) && ((address & 0x1F) != 0)) { - target_write_u32(target, info->flc_base + FLSH_ADDR, address); - target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, buffer); - flsh_cn |= 0x00000001; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - /* Wait until flash operation is complete */ + while (remaining >= 4) { + target_write_u32(target, info->flc_base + FLC_ADDR, address); + target_write_buffer(target, info->flc_base + FLC_DATA0, 4, buffer); + flash_cn |= FLC_CN_WR; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); + // Wait until flash operation is complete retry = 10; do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + } while ((--retry > 0) && max32xxx_flash_busy(flash_cn)); if (retry <= 0) { - LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); + LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, + address); + max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } @@ -517,31 +581,32 @@ static int max32xxx_write(struct flash_bank *bank, const uint8_t *buffer, } } - if ((info->burst_size_bits == 128) && (remaining >= 16)) { - /* write in 128-bit bursts while we can */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - - flsh_cn &= 0xFFFFFFEF; - flsh_cn |= 0x08000000; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - target_write_u32(target, info->flc_base + FLSH_ADDR, address); + if ((info->options & OPTIONS_128) && remaining >= 16) { + // write in 128-bit units + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn &= ~(FLC_CN_32BIT); + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); while (remaining >= 16) { + target_write_u32(target, info->flc_base + FLC_ADDR, address); + if ((address & 0xFFF) == 0) LOG_DEBUG("Writing @ 0x%08" PRIx32, address); - target_write_buffer(target, info->flc_base + FLSH_DATA0, 16, buffer); - flsh_cn |= 0x00000001; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - /* Wait until flash operation is complete */ + target_write_buffer(target, info->flc_base + FLC_DATA0, 16, buffer); + flash_cn |= FLC_CN_WR; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); + // Wait until flash operation is complete retry = 10; do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + } while ((--retry > 0) && max32xxx_flash_busy(flash_cn)); if (retry <= 0) { - LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); + LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, + address); + max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } @@ -551,73 +616,92 @@ static int max32xxx_write(struct flash_bank *bank, const uint8_t *buffer, } } - if (remaining >= 4) { + if (((info->options & OPTIONS_128) == 0) && remaining > 0) { + // write remaining bytes in a 32-bit unit + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn |= FLC_CN_32BIT; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* write in 32-bit units while we can */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn &= 0xF7FFFFFF; - flsh_cn |= 0x00000010; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + uint8_t last_word[4] = {0xFF, 0xFF, 0xFF, 0xFF}; + uint32_t i = 0; - while (remaining >= 4) { - target_write_u32(target, info->flc_base + FLSH_ADDR, address); - target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, buffer); - flsh_cn |= 0x00000001; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - /* Wait until flash operation is complete */ - retry = 10; + while (remaining > 0) { + last_word[i++] = *buffer; + buffer++; + remaining--; + } - do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + target_write_u32(target, info->flc_base + FLC_ADDR, address); + target_write_buffer(target, info->flc_base + FLC_DATA0, 4, last_word); + flash_cn |= FLC_CN_WR; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - if (retry <= 0) { - LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); - return ERROR_FLASH_OPERATION_FAILED; - } + // Wait until flash operation is complete + retry = 10; - buffer += 4; - address += 4; - remaining -= 4; + do { + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + } while ((--retry > 0) && max32xxx_flash_busy(flash_cn)); + + if (retry <= 0) { + LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); + max32xxx_flash_op_post(bank); + return ERROR_FLASH_OPERATION_FAILED; } } - if (remaining > 0) { - /* write remaining bytes in a 32-bit unit */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn &= 0xF7FFFFFF; - flsh_cn |= 0x00000010; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + if ((info->options & OPTIONS_128) && remaining > 0) { + // write remaining bytes in a 128-bit unit + if (target_read_u32(target, info->flc_base + FLC_CN, &flash_cn) != ERROR_OK) { + max32xxx_flash_op_post(bank); + return ERROR_FAIL; + } + + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn &= ~(FLC_CN_32BIT); + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); + + uint8_t last_words[16] = {0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF}; - uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff}; - int i = 0; + uint32_t i = 0; while (remaining > 0) { - last_word[i++] = *buffer; + last_words[i++] = *buffer; buffer++; remaining--; } - target_write_u32(target, info->flc_base + FLSH_ADDR, address); - target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, last_word); - flsh_cn |= 0x00000001; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - /* Wait until flash operation is complete */ - retry = 10; + target_write_u32(target, info->flc_base + FLC_ADDR, address); + target_write_buffer(target, info->flc_base + FLC_DATA0, 4, last_words); + target_write_buffer(target, info->flc_base + FLC_DATA0 + 4, 4, last_words + 4); + target_write_buffer(target, info->flc_base + FLC_DATA0 + 8, 4, last_words + 8); + target_write_buffer(target, info->flc_base + FLC_DATA0 + 12, 4, last_words + 12); + flash_cn |= FLC_CN_WR; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); + // Wait until flash operation is complete + retry = 10; do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + if (target_read_u32(target, info->flc_base + FLC_CN, + &flash_cn) != ERROR_OK) { + max32xxx_flash_op_post(bank); + return ERROR_FAIL; + } + } while ((--retry > 0) && (flash_cn & FLC_CN_PEND)); if (retry <= 0) { LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); + max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } } - /* Check access violations */ - target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); - if (flsh_int & FLSH_INT_AF) { + // Check access violations + target_read_u32(target, info->flc_base + FLC_INT, &flash_int); + if (flash_int & FLC_INT_AF) { LOG_ERROR("Flash Error writing 0x%" PRIx32 " bytes at 0x%08" PRIx32, count, offset); max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; @@ -638,7 +722,7 @@ static int max32xxx_probe(struct flash_bank *bank) free(bank->sectors); - /* provide this for the benefit of the NOR flash framework */ + // provide this for the benefit of the NOR flash framework bank->size = info->flash_size; bank->num_sectors = info->flash_size / info->sector_size; bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); @@ -650,24 +734,24 @@ static int max32xxx_probe(struct flash_bank *bank) bank->sectors[i].is_protected = -1; } - /* Probe to determine if this part is in the max326xx family */ - info->max326xx = 0; + // Probe to determine if this part is in the max326xx family + info->max326xx = false; target_read_u32(target, ARM_PID_REG, &arm_id[0]); - target_read_u32(target, ARM_PID_REG+4, &arm_id[1]); + target_read_u32(target, ARM_PID_REG + 4, &arm_id[1]); arm_pid = (arm_id[1] << 8) + arm_id[0]; LOG_DEBUG("arm_pid = 0x%x", arm_pid); - if ((arm_pid == ARM_PID_DEFAULT_CM3) || arm_pid == ARM_PID_DEFAULT_CM4) { + if (arm_pid == ARM_PID_DEFAULT_CM3 || arm_pid == ARM_PID_DEFAULT_CM4) { uint32_t max326xx_id; target_read_u32(target, MAX326XX_ID_REG, &max326xx_id); LOG_DEBUG("max326xx_id = 0x%" PRIx32, max326xx_id); max326xx_id = ((max326xx_id & 0xFF000000) >> 24); if (max326xx_id == MAX326XX_ID) - info->max326xx = 1; + info->max326xx = true; } LOG_DEBUG("info->max326xx = %d", info->max326xx); - /* Initialize the protection bits for each flash page */ + // Initialize the protection bits for each flash page if (max32xxx_protect_check(bank) == ERROR_FLASH_OPER_UNSUPPORTED) LOG_WARNING("Flash protection not supported on this device"); @@ -679,7 +763,7 @@ static int max32xxx_mass_erase(struct flash_bank *bank) { struct target *target = NULL; struct max32xxx_flash_bank *info = NULL; - uint32_t flsh_cn, flsh_int; + uint32_t flash_cn, flash_int; int retval; int retry; info = bank->driver_priv; @@ -693,50 +777,50 @@ static int max32xxx_mass_erase(struct flash_bank *bank) if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; - int not_protected = 0; + bool protected = true; for (unsigned int i = 0; i < bank->num_sectors; i++) { if (bank->sectors[i].is_protected == 1) LOG_WARNING("Flash sector %u is protected", i); else - not_protected = 1; + protected = false; } - if (!not_protected) { + if (protected) { LOG_ERROR("All pages protected"); return ERROR_FAIL; } - /* Prepare to issue flash operation */ + // Prepare to issue flash operation retval = max32xxx_flash_op_pre(bank); if (retval != ERROR_OK) return retval; - /* Write mass erase code */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn |= FLSH_CN_ERASE_CODE_ME; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Write mass erase code + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn |= FLC_CN_ERASE_CODE_ME; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* Issue mass erase command */ - flsh_cn |= 0x2; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Issue mass erase command + flash_cn |= FLC_CN_ME; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* Wait until erase complete */ + // Wait until erase complete retry = 1000; do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + } while ((--retry > 0) && max32xxx_flash_busy(flash_cn)); if (retry <= 0) { LOG_ERROR("Timed out waiting for flash mass erase"); return ERROR_FLASH_OPERATION_FAILED; } - /* Check access violations */ - target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); - if (flsh_int & FLSH_INT_AF) { + // Check access violations + target_read_u32(target, info->flc_base + FLC_INT, &flash_int); + if (flash_int & FLC_INT_AF) { LOG_ERROR("Error mass erasing"); - target_write_u32(target, info->flc_base + FLSH_INT, 0); + target_write_u32(target, info->flc_base + FLC_INT, 0); return ERROR_FLASH_OPERATION_FAILED; } @@ -784,34 +868,34 @@ COMMAND_HANDLER(max32xxx_handle_protection_set_command) return retval; info = bank->driver_priv; - /* Convert the range to the page numbers */ - if (sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr) != 1) { + // Convert the range to the page numbers + if (sscanf(CMD_ARGV[1], "0x%" SCNx32, &addr) != 1) { LOG_WARNING("Error parsing address"); command_print(CMD, "max32xxx protection_set "); return ERROR_FAIL; } - /* Mask off the top portion on the address */ + // Mask off the top portion on the address addr = (addr & 0x0FFFFFFF); - if (sscanf(CMD_ARGV[2], "0x%"SCNx32, &len) != 1) { + if (sscanf(CMD_ARGV[2], "0x%" SCNx32, &len) != 1) { LOG_WARNING("Error parsing length"); command_print(CMD, "max32xxx protection_set "); return ERROR_FAIL; } - /* Check the address is in the range of the flash */ - if ((addr+len) >= info->flash_size) + // Check the address is in the range of the flash + if ((addr + len) >= info->flash_size) return ERROR_FLASH_SECTOR_INVALID; if (len == 0) return ERROR_OK; - /* Convert the address and length to the page boundaries */ + // Convert the address and length to the page boundaries addr = addr - (addr % info->sector_size); if (len % info->sector_size) len = len + info->sector_size - (len % info->sector_size); - /* Convert the address and length to page numbers */ + // Convert the address and length to page numbers addr = (addr / info->sector_size); len = addr + (len / info->sector_size) - 1; @@ -840,34 +924,34 @@ COMMAND_HANDLER(max32xxx_handle_protection_clr_command) return retval; info = bank->driver_priv; - /* Convert the range to the page numbers */ - if (sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr) != 1) { + // Convert the range to the page numbers + if (sscanf(CMD_ARGV[1], "0x%" SCNx32, &addr) != 1) { LOG_WARNING("Error parsing address"); command_print(CMD, "max32xxx protection_clr "); return ERROR_FAIL; } - /* Mask off the top portion on the address */ + // Mask off the top portion on the address addr = (addr & 0x0FFFFFFF); - if (sscanf(CMD_ARGV[2], "0x%"SCNx32, &len) != 1) { + if (sscanf(CMD_ARGV[2], "0x%" SCNx32, &len) != 1) { LOG_WARNING("Error parsing length"); command_print(CMD, "max32xxx protection_clr "); return ERROR_FAIL; } - /* Check the address is in the range of the flash */ - if ((addr+len) >= info->flash_size) + // Check the address is in the range of the flash + if ((addr + len) >= info->flash_size) return ERROR_FLASH_SECTOR_INVALID; if (len == 0) return ERROR_OK; - /* Convert the address and length to the page boundaries */ + // Convert the address and length to the page boundaries addr = addr - (addr % info->sector_size); if (len % info->sector_size) len = len + info->sector_size - (len % info->sector_size); - /* Convert the address and length to page numbers */ + // Convert the address and length to page numbers addr = (addr / info->sector_size); len = addr + (len / info->sector_size) - 1; @@ -895,7 +979,7 @@ COMMAND_HANDLER(max32xxx_handle_protection_check_command) return retval; info = bank->driver_priv; - /* Update the protection array */ + // Update the protection array retval = max32xxx_protect_check(bank); if (retval != ERROR_OK) { LOG_WARNING("Error updating the protection array"); @@ -905,10 +989,10 @@ COMMAND_HANDLER(max32xxx_handle_protection_check_command) LOG_WARNING("s: a:
p:"); for (unsigned int i = 0; i < bank->num_sectors; i += 4) { LOG_WARNING("s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d", - (i+0), (i+0)*info->sector_size, bank->sectors[(i+0)].is_protected, - (i+1), (i+1)*info->sector_size, bank->sectors[(i+1)].is_protected, - (i+2), (i+2)*info->sector_size, bank->sectors[(i+2)].is_protected, - (i+3), (i+3)*info->sector_size, bank->sectors[(i+3)].is_protected); + (i + 0), (i + 0) * info->sector_size, bank->sectors[(i + 0)].is_protected, + (i + 1), (i + 1) * info->sector_size, bank->sectors[(i + 1)].is_protected, + (i + 2), (i + 2) * info->sector_size, bank->sectors[(i + 2)].is_protected, + (i + 3), (i + 3) * info->sector_size, bank->sectors[(i + 3)].is_protected); } return ERROR_OK; @@ -970,4 +1054,5 @@ const struct flash_driver max32xxx_flash = { .erase_check = default_flash_blank_check, .protect_check = max32xxx_protect_check, .info = get_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c index b5e2b0bf86..ac87098b3c 100644 --- a/src/flash/nor/msp432.c +++ b/src/flash/nor/msp432.c @@ -90,56 +90,56 @@ static int msp432_device_type(uint32_t family_type, uint32_t device_id, /* Examine the device ID and hardware revision to get the device type */ switch (device_id) { - case 0xA000: - case 0xA001: - case 0xA002: - case 0xA003: - case 0xA004: - case 0xA005: - /* Device is definitely MSP432P401x, check hardware revision */ - if (hardware_rev == 0x41 || hardware_rev == 0x42) { - /* Rev A or B of the silicon has been deprecated */ - device_type = MSP432P401X_DEPR; - } else if (hardware_rev >= 0x43 && hardware_rev <= 0x49) { - /* Current and future revisions of the MSP432P401x device */ - device_type = MSP432P401X; - } else { - /* Unknown or unanticipated hardware revision */ - device_type = MSP432P401X_GUESS; - } - break; - case 0xA010: - case 0xA012: - case 0xA016: - case 0xA019: - case 0xA01F: - case 0xA020: - case 0xA022: - case 0xA026: - case 0xA029: - case 0xA02F: - /* Device is definitely MSP432P411x, check hardware revision */ - if (hardware_rev >= 0x41 && hardware_rev <= 0x49) { - /* Current and future revisions of the MSP432P411x device */ - device_type = MSP432P411X; - } else { - /* Unknown or unanticipated hardware revision */ - device_type = MSP432P411X_GUESS; - } - break; - case 0xFFFF: - /* Device is very early silicon that has been deprecated */ + case 0xA000: + case 0xA001: + case 0xA002: + case 0xA003: + case 0xA004: + case 0xA005: + /* Device is definitely MSP432P401x, check hardware revision */ + if (hardware_rev == 0x41 || hardware_rev == 0x42) { + /* Rev A or B of the silicon has been deprecated */ device_type = MSP432P401X_DEPR; - break; - default: - if (device_id < 0xA010) { - /* Wild guess that this is an MSP432P401x */ - device_type = MSP432P401X_GUESS; - } else { - /* Reasonable guess that this is a new variant */ - device_type = MSP432P411X_GUESS; - } - break; + } else if (hardware_rev >= 0x43 && hardware_rev <= 0x49) { + /* Current and future revisions of the MSP432P401x device */ + device_type = MSP432P401X; + } else { + /* Unknown or unanticipated hardware revision */ + device_type = MSP432P401X_GUESS; + } + break; + case 0xA010: + case 0xA012: + case 0xA016: + case 0xA019: + case 0xA01F: + case 0xA020: + case 0xA022: + case 0xA026: + case 0xA029: + case 0xA02F: + /* Device is definitely MSP432P411x, check hardware revision */ + if (hardware_rev >= 0x41 && hardware_rev <= 0x49) { + /* Current and future revisions of the MSP432P411x device */ + device_type = MSP432P411X; + } else { + /* Unknown or unanticipated hardware revision */ + device_type = MSP432P411X_GUESS; + } + break; + case 0xFFFF: + /* Device is very early silicon that has been deprecated */ + device_type = MSP432P401X_DEPR; + break; + default: + if (device_id < 0xA010) { + /* Wild guess that this is an MSP432P401x */ + device_type = MSP432P401X_GUESS; + } else { + /* Reasonable guess that this is a new variant */ + device_type = MSP432P411X_GUESS; + } + break; } } @@ -149,22 +149,22 @@ static int msp432_device_type(uint32_t family_type, uint32_t device_id, static const char *msp432_return_text(uint32_t return_code) { switch (return_code) { - case FLASH_BUSY: - return "FLASH_BUSY"; - case FLASH_SUCCESS: - return "FLASH_SUCCESS"; - case FLASH_ERROR: - return "FLASH_ERROR"; - case FLASH_TIMEOUT_ERROR: - return "FLASH_TIMEOUT_ERROR"; - case FLASH_VERIFY_ERROR: - return "FLASH_VERIFY_WRONG"; - case FLASH_WRONG_COMMAND: - return "FLASH_WRONG_COMMAND"; - case FLASH_POWER_ERROR: - return "FLASH_POWER_ERROR"; - default: - return "UNDEFINED_RETURN_CODE"; + case FLASH_BUSY: + return "FLASH_BUSY"; + case FLASH_SUCCESS: + return "FLASH_SUCCESS"; + case FLASH_ERROR: + return "FLASH_ERROR"; + case FLASH_TIMEOUT_ERROR: + return "FLASH_TIMEOUT_ERROR"; + case FLASH_VERIFY_ERROR: + return "FLASH_VERIFY_WRONG"; + case FLASH_WRONG_COMMAND: + return "FLASH_WRONG_COMMAND"; + case FLASH_POWER_ERROR: + return "FLASH_POWER_ERROR"; + default: + return "UNDEFINED_RETURN_CODE"; } } @@ -199,9 +199,7 @@ static int msp432_exec_cmd(struct target *target, struct msp432_algo_params return retval; /* Write out command to target memory */ - retval = target_write_u32(target, ALGO_FLASH_COMMAND_ADDR, command); - - return retval; + return target_write_u32(target, ALGO_FLASH_COMMAND_ADDR, command); } static int msp432_wait_return_code(struct target *target) @@ -219,10 +217,10 @@ static int msp432_wait_return_code(struct target *target) return retval; elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; + + keep_alive(); }; if (return_code != FLASH_SUCCESS) { @@ -244,14 +242,14 @@ static int msp432_wait_inactive(struct target *target, uint32_t buffer) int retval; switch (buffer) { - case 1: /* Buffer 1 */ - status_addr = ALGO_BUFFER1_STATUS_ADDR; - break; - case 2: /* Buffer 2 */ - status_addr = ALGO_BUFFER2_STATUS_ADDR; - break; - default: - return ERROR_FAIL; + case 1: /* Buffer 1 */ + status_addr = ALGO_BUFFER1_STATUS_ADDR; + break; + case 2: /* Buffer 2 */ + status_addr = ALGO_BUFFER2_STATUS_ADDR; + break; + default: + return ERROR_FAIL; } start_ms = timeval_ms(); @@ -261,10 +259,10 @@ static int msp432_wait_inactive(struct target *target, uint32_t buffer) return retval; elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; + + keep_alive(); }; if (status_code != BUFFER_INACTIVE) { @@ -295,27 +293,27 @@ static int msp432_init(struct flash_bank *bank) /* Choose appropriate flash helper algorithm */ switch (msp432_bank->device_type) { - case MSP432P401X: - case MSP432P401X_DEPR: - case MSP432P401X_GUESS: - default: - loader_code = msp432p401x_algo; - loader_size = sizeof(msp432p401x_algo); - algo_entry_addr = P4_ALGO_ENTRY_ADDR; - break; - case MSP432P411X: - case MSP432P411X_GUESS: - loader_code = msp432p411x_algo; - loader_size = sizeof(msp432p411x_algo); - algo_entry_addr = P4_ALGO_ENTRY_ADDR; - break; - case MSP432E401Y: - case MSP432E411Y: - case MSP432E4X_GUESS: - loader_code = msp432e4x_algo; - loader_size = sizeof(msp432e4x_algo); - algo_entry_addr = E4_ALGO_ENTRY_ADDR; - break; + case MSP432P401X: + case MSP432P401X_DEPR: + case MSP432P401X_GUESS: + default: + loader_code = msp432p401x_algo; + loader_size = sizeof(msp432p401x_algo); + algo_entry_addr = P4_ALGO_ENTRY_ADDR; + break; + case MSP432P411X: + case MSP432P411X_GUESS: + loader_code = msp432p411x_algo; + loader_size = sizeof(msp432p411x_algo); + algo_entry_addr = P4_ALGO_ENTRY_ADDR; + break; + case MSP432E401Y: + case MSP432E411Y: + case MSP432E4X_GUESS: + loader_code = msp432e4x_algo; + loader_size = sizeof(msp432e4x_algo); + algo_entry_addr = E4_ALGO_ENTRY_ADDR; + break; } /* Issue warnings if this is a device we may not be able to flash */ @@ -393,9 +391,7 @@ static int msp432_init(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = msp432_wait_return_code(target); - - return retval; + return msp432_wait_return_code(target); } static int msp432_quit(struct flash_bank *bank) @@ -678,8 +674,6 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, struct msp432_algo_params algo_params; uint32_t size; uint32_t data_ready = BUFFER_DATA_READY; - long long start_ms; - long long elapsed_ms; bool is_info = bank->base == P4_FLASH_INFO_BASE; @@ -753,7 +747,6 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, } /* Write requested data, one buffer at a time */ - start_ms = timeval_ms(); while (count > 0) { if (count > ALGO_BUFFER_SIZE) @@ -786,9 +779,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, count -= size; buffer += size; - elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); + keep_alive(); } /* Confirm that the flash helper algorithm is finished */ @@ -985,43 +976,43 @@ static int msp432_info(struct flash_bank *bank, struct command_invocation *cmd) struct msp432_bank *msp432_bank = bank->driver_priv; switch (msp432_bank->device_type) { - case MSP432P401X_DEPR: - if (msp432_bank->device_id == 0xFFFF) { - /* Very early pre-production silicon currently deprecated */ - command_print_sameline(cmd, "MSP432P401x pre-production device (deprecated silicon)\n" - SUPPORT_MESSAGE); - } else { - /* Revision A or B silicon, also deprecated */ - command_print_sameline(cmd, "MSP432P401x Device Rev %c (deprecated silicon)\n" - SUPPORT_MESSAGE, (char)msp432_bank->hardware_rev); - } - break; - case MSP432P401X: - command_print_sameline(cmd, "MSP432P401x Device Rev %c\n", - (char)msp432_bank->hardware_rev); - break; - case MSP432P411X: - command_print_sameline(cmd, "MSP432P411x Device Rev %c\n", - (char)msp432_bank->hardware_rev); - break; - case MSP432E401Y: - command_print_sameline(cmd, "MSP432E401Y Device\n"); - break; - case MSP432E411Y: - command_print_sameline(cmd, "MSP432E411Y Device\n"); - break; - case MSP432E4X_GUESS: - 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: - command_print_sameline(cmd, - "Unrecognized MSP432P4 Device ID and Hardware Rev (%04" PRIX32 ", %02" PRIX32 ")", - msp432_bank->device_id, msp432_bank->hardware_rev); - break; + case MSP432P401X_DEPR: + if (msp432_bank->device_id == 0xFFFF) { + /* Very early pre-production silicon currently deprecated */ + command_print_sameline(cmd, "MSP432P401x pre-production device (deprecated silicon)\n" + SUPPORT_MESSAGE); + } else { + /* Revision A or B silicon, also deprecated */ + command_print_sameline(cmd, "MSP432P401x Device Rev %c (deprecated silicon)\n" + SUPPORT_MESSAGE, (char)msp432_bank->hardware_rev); + } + break; + case MSP432P401X: + command_print_sameline(cmd, "MSP432P401x Device Rev %c\n", + (char)msp432_bank->hardware_rev); + break; + case MSP432P411X: + command_print_sameline(cmd, "MSP432P411x Device Rev %c\n", + (char)msp432_bank->hardware_rev); + break; + case MSP432E401Y: + command_print_sameline(cmd, "MSP432E401Y Device\n"); + break; + case MSP432E411Y: + command_print_sameline(cmd, "MSP432E411Y Device\n"); + break; + case MSP432E4X_GUESS: + 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: + command_print_sameline(cmd, + "Unrecognized MSP432P4 Device ID and Hardware Rev (%04" PRIX32 ", %02" PRIX32 ")", + msp432_bank->device_id, msp432_bank->hardware_rev); + break; } return ERROR_OK; diff --git a/src/flash/nor/mspm0.c b/src/flash/nor/mspm0.c index 4731c89ccf..1ba35374d9 100644 --- a/src/flash/nor/mspm0.c +++ b/src/flash/nor/mspm0.c @@ -77,6 +77,20 @@ #define SYSCTL_BASE 0x400AF000 #define SYSCTL_SECCFG_SECSTATUS (SYSCTL_BASE + 0x00003048) +/* + * SYSCTL SOCLOCK MCLKCFG register (offset 0x1104 from SYSCTL_BASE). + * Used for the FLASH_ERR_01 workaround: accessing FACTORYREGION while MCLK + * is sourced from HSCLK (SYSPLL/HFXT, implying MCLK > 32 MHz) with flash + * wait-state 2 active causes a hard fault on MSPM0G devices. The flash + * controller enforces its wait-state timing for all AHB masters, including + * the DAP AHB-AP used by OpenOCD. Temporarily switching MCLK to SYSOSC + * (≤ 32 MHz on all MSPM0 variants) before reading FACTORYREGION avoids this. + */ +#define SYSCTL_MCLKCFG (SYSCTL_BASE + 0x00001104) +#define SYSCTL_MCLKCFG_USEHSCLK BIT(16) +#define SYSCTL_MCLKCFG_FLASHWAIT_MASK GENMASK(11, 8) +#define SYSCTL_MCLKCFG_FLASHWAIT_2 (2U << 8) + /* TI manufacturer ID */ #define TI_MANUFACTURER_ID 0x17 @@ -128,6 +142,7 @@ struct mspm0_family_info { /* https://www.ti.com/lit/ds/symlink/mspm0l1346.pdf Table 8-13 and so on */ static const struct mspm0_part_info mspm0l_parts[] = { + /* MSPM0L110x */ { "MSPM0L1105TDGS20R", 0x51DB, 0x16 }, { "MSPM0L1105TDGS28R", 0x51DB, 0x83 }, { "MSPM0L1105TDYYR", 0x51DB, 0x54 }, @@ -138,6 +153,7 @@ static const struct mspm0_part_info mspm0l_parts[] = { { "MSPM0L1106TDYYR", 0x5552, 0x9D }, { "MSPM0L1106TRGER", 0x5552, 0x90 }, { "MSPM0L1106TRHBR", 0x5552, 0x53 }, + /* MSPM0L130x (covers MSPM0L134x) */ { "MSPM0L1303SRGER", 0xef0, 0x17 }, { "MSPM0L1303TRGER", 0xef0, 0xe2 }, { "MSPM0L1304QDGS20R", 0xd717, 0x91 }, @@ -188,20 +204,24 @@ static const struct mspm0_part_info mspm0l_parts[] = { { "MSPM0L1346TDGS28R", 0xf2b5, 0xef }, }; -/* https://www.ti.com/lit/ds/symlink/mspm0g3506.pdf Table 8-20 */ -static const struct mspm0_part_info mspm0g_parts[] = { +/* https://www.ti.com/lit/ds/symlink/mspm0g3506.pdf Table 8-22 */ +static const struct mspm0_part_info mspm0g_parts_bb88[] = { + /* MSPM0G110x */ { "MSPM0G1105TPTR", 0x8934, 0xD }, { "MSPM0G1105TRGZR", 0x8934, 0xFE }, { "MSPM0G1106TPMR", 0x477B, 0xD4 }, { "MSPM0G1106TPTR", 0x477B, 0x71 }, { "MSPM0G1106TRGZR", 0x477B, 0xBB }, - { "MSPM0G1106TRHBR", 0x477B, 0x0 }, + { "MSPM0G1106TRHBR", 0x477B, 0x01 }, + { "MSPM0G1106TYCJR", 0x477B, 0x09 }, { "MSPM0G1107TDGS28R", 0x807B, 0x82 }, { "MSPM0G1107TPMR", 0x807B, 0xB3 }, { "MSPM0G1107TPTR", 0x807B, 0x32 }, { "MSPM0G1107TRGER", 0x807B, 0x79 }, { "MSPM0G1107TRGZR", 0x807B, 0x20 }, { "MSPM0G1107TRHBR", 0x807B, 0xBC }, + { "MSPM0G1107TYCJR", 0x807B, 0x7A }, + /* MSPM0G150x */ { "MSPM0G1505SDGS28R", 0x13C4, 0x73 }, { "MSPM0G1505SPMR", 0x13C4, 0x53 }, { "MSPM0G1505SPTR", 0x13C4, 0x3E }, @@ -213,11 +233,16 @@ static const struct mspm0_part_info mspm0g_parts[] = { { "MSPM0G1506SRGER", 0x5AE0, 0x67 }, { "MSPM0G1506SRGZR", 0x5AE0, 0x75 }, { "MSPM0G1506SRHBR", 0x5AE0, 0x57 }, + { "MSPM0G1506SRPTR", 0x5AE0, 0x36 }, + { "MSPM0G1506SYCJR", 0x5AE0, 0x9E }, { "MSPM0G1507SDGS28R", 0x2655, 0x6D }, { "MSPM0G1507SPMR", 0x2655, 0x97 }, + { "MSPM0G1507SPTR", 0x2655, 0x2E }, { "MSPM0G1507SRGER", 0x2655, 0x83 }, { "MSPM0G1507SRGZR", 0x2655, 0xD3 }, { "MSPM0G1507SRHBR", 0x2655, 0x4D }, + { "MSPM0G1507SYCJR", 0x2655, 0x65 }, + /* MSPM0G310x */ { "MSPM0G3105SDGS20R", 0x4749, 0x21 }, { "MSPM0G3105SDGS28R", 0x4749, 0xDD }, { "MSPM0G3105SRHBR", 0x4749, 0xBE }, @@ -227,12 +252,12 @@ static const struct mspm0_part_info mspm0g_parts[] = { { "MSPM0G3107SDGS20R", 0xAB39, 0x5C }, { "MSPM0G3107SDGS28R", 0xAB39, 0xCC }, { "MSPM0G3107SRHBR", 0xAB39, 0xB7 }, + /* MSPM0G350x */ { "MSPM0G3505SDGS28R", 0xc504, 0x8e }, { "MSPM0G3505SPMR", 0xc504, 0x1d }, { "MSPM0G3505SPTR", 0xc504, 0x93 }, { "MSPM0G3505SRGZR", 0xc504, 0xc7 }, { "MSPM0G3505SRHBR", 0xc504, 0xe7 }, - { "MSPM0G3505TDGS28R", 0xc504, 0xdf }, { "MSPM0G3506SDGS28R", 0x151f, 0x8 }, { "MSPM0G3506SPMR", 0x151f, 0xd4 }, { "MSPM0G3506SPTR", 0x151f, 0x39 }, @@ -243,27 +268,109 @@ static const struct mspm0_part_info mspm0g_parts[] = { { "MSPM0G3507SPTR", 0xae2d, 0x3f }, { "MSPM0G3507SRGZR", 0xae2d, 0xf7 }, { "MSPM0G3507SRHBR", 0xae2d, 0x4c }, - { "M0G3107QPMRQ1", 0x4e2f, 0x51 }, - { "M0G3107QPTRQ1", 0x4e2f, 0xc7}, - { "M0G3107QRGZRQ1", 0x4e2f, 0x8a }, - { "M0G3107QRHBRQ1", 0x4e2f, 0x9a}, - { "M0G3107QDGS28RQ1", 0x4e2f, 0xd5}, - { "M0G3107QDGS28RQ1", 0x4e2f, 0x67}, - { "M0G3107QDGS20RQ1", 0x4e2f, 0xfd}, - { "M0G3106QPMRQ1", 0x54C7, 0x08}, - { "M0G3105QDGS32RQ1", 0x1349, 0x08}, - { "M0G3106QPTRQ1", 0x54C7, 0x3F}, - { "M0G3105QDGS28RQ1", 0x1349, 0x1B}, - { "M0G3106QRGZRQ1", 0x94AD, 0xE6}, + /* MSPM0G310x-Q1 */ { "M0G3105QDGS20RQ1", 0x1349, 0xFB}, - { "M0G3106QRHBRQ1", 0x94AD, 0x20}, - { "M0G3106QDGS32RQ1", 0x94AD, 0x8D}, - { "M0G3106QDGS28RQ1", 0x94AD, 0x03}, - { "M0G3106QDGS20RQ1", 0x94AD, 0x6F}, + { "M0G3105QDGS28RQ1", 0x1349, 0x1B}, + { "M0G3105QDGS32RQ1", 0x1349, 0x08}, { "M0G3105QPMRQ1", 0x1349, 0xD0}, { "M0G3105QPTRQ1", 0x1349, 0xEF}, { "M0G3105QRGZRQ1", 0x1349, 0x70}, { "M0G3105QRHBRQ1", 0x1349, 0x01}, + { "M0G3106QDGS20RQ1", 0x94AD, 0x6F}, + { "M0G3106QDGS28RQ1", 0x94AD, 0x03}, + { "M0G3106QDGS32RQ1", 0x94AD, 0x8D}, + { "M0G3106QPMRQ1", 0x54C7, 0x08}, + { "M0G3106QPTRQ1", 0x54C7, 0x3F}, + { "M0G3106QRGZRQ1", 0x94AD, 0xE6}, + { "M0G3106QRHBRQ1", 0x94AD, 0x20}, + { "M0G3107QDGS20RQ1", 0x4e2f, 0xfd}, + { "M0G3107QDGS28RQ1", 0x4e2f, 0x67}, + { "M0G3107QDGS28RQ1", 0x4e2f, 0xd5}, + { "M0G3107QPMRQ1", 0x4e2f, 0x51 }, + { "M0G3107QPTRQ1", 0x4e2f, 0xc7}, + { "M0G3107QRGZRQ1", 0x4e2f, 0x8a }, + { "M0G3107QRHBRQ1", 0x4e2f, 0x9a}, + /* MSPM0G350x-Q1 */ + { "M0G3505QDGS28RQ1", 0x704E, 0x4C }, + { "M0G3505QDGS32RQ1", 0x704E, 0x7F }, + { "M0G3505QPMRQ1", 0x704E, 0x7B }, + { "M0G3505QPTRQ1", 0x704E, 0x9C }, + { "M0G3505QRGZRQ1", 0x704E, 0xC9 }, + { "M0G3505QRHBRQ1", 0x704E, 0x26 }, + { "M0G3506QDGS28RQ1", 0xEE12, 0x71 }, + { "M0G3506QDGS32RQ1", 0xEE12, 0x6C }, + { "M0G3506QPMRQ1", 0xEE12, 0x7B }, + { "M0G3506QPTRQ1", 0xEE12, 0x5A }, + { "M0G3506QRGZRQ1", 0xEE12, 0xD2 }, + { "M0G3506QRHBRQ1", 0xEE12, 0xFC }, + { "M0G3507QDGS28RQ1", 0x34E0, 0xEA }, + { "M0G3507QDGS32RQ1", 0x34E0, 0xF6 }, + { "M0G3507QPMRQ1", 0x34E0, 0x26 }, + { "M0G3507QRGZRQ1", 0x34E0, 0xC5 }, + { "M0G3507QRHBRQ1", 0x34E0, 0xAC }, + { "M0G3507QSPTRQ1", 0x34E0, 0xE3 }, +}; + +/* https://www.ti.com/lit/gpn/mspm0g1518 Table 8-21 and so on */ +static const struct mspm0_part_info mspm0g_parts_bba9[] = { + /* MSPM0Gx51x */ + { "MSPM0G1518SPMR", 0x2120, 0x13 }, + { "MSPM0G1518SPNR", 0x2120, 0x16 }, + { "MSPM0G1518SPTR", 0x2120, 0x12 }, + { "MSPM0G1518SPZR", 0x2120, 0x18 }, + { "MSPM0G1518SRGZR", 0x2120, 0x11 }, + { "MSPM0G1518SRHBR", 0x2120, 0x10 }, + { "MSPM0G1518SZAWR", 0x2120, 0x19 }, + { "MSPM0G1519SPMR", 0x2407, 0x13 }, + { "MSPM0G1519SPNR", 0x2407, 0x16 }, + { "MSPM0G1519SPTR", 0x2407, 0x12 }, + { "MSPM0G1519SPZR", 0x2407, 0x18 }, + { "MSPM0G1519SRGZR", 0x2407, 0x11 }, + { "MSPM0G1519SRHBR", 0x2407, 0x10 }, + { "MSPM0G1519SZAWR", 0x2407, 0x19 }, + { "MSPM0G3518SPMR", 0x1205, 0x13 }, + { "MSPM0G3518SPNR", 0x1205, 0x15 }, + { "MSPM0G3518SPTR", 0x1205, 0x12 }, + { "MSPM0G3518SPZR", 0x1205, 0x16 }, + { "MSPM0G3518SRGZR", 0x1205, 0x11 }, + { "MSPM0G3518SRHBR", 0x1205, 0x10 }, + { "MSPM0G3518SZAWR", 0x1205, 0x19 }, + { "MSPM0G3519SPMR", 0x1508, 0x13 }, + { "MSPM0G3519SPNR", 0x1508, 0x15 }, + { "MSPM0G3519SPTR", 0x1508, 0x12 }, + { "MSPM0G3519SPZR", 0x1508, 0x16 }, + { "MSPM0G3519SRGZR", 0x1508, 0x11 }, + { "MSPM0G3519SRHBR", 0x1508, 0x10 }, + { "MSPM0G3519SZAWR", 0x1508, 0x19 }, + /* MSPM0G351x-Q1 */ + { "M0G3518QPMRQ1", 0x4009, 0x13 }, + { "M0G3518QPNRQ1", 0x4009, 0x14 }, + { "M0G3518QPTRQ1", 0x4009, 0x12 }, + { "M0G3518QPZRQ1", 0x4009, 0x15 }, + { "M0G3518QRGZRQ1", 0x4009, 0x11 }, + { "M0G3518QRHBRQ1", 0x4009, 0x10 }, + { "M0G3519QPMRQ1", 0x3512, 0x13 }, + { "M0G3519AQPMRQ1", 0x3512, 0x16 }, + { "M0G3519QPNRQ1", 0x3512, 0x14 }, + { "M0G3519QPTRQ1", 0x3512, 0x12 }, + { "M0G3519QPZRQ1", 0x3512, 0x15 }, + { "M0G3519QRGZRQ1", 0x3512, 0x11 }, + { "M0G3519QRHBRQ1", 0x3512, 0x10 }, + /* MSPM0G352x-Q1 */ + { "M0G3529QPMRQ1", 0xF8D1, 0x13 }, +}; + +/* https://www.ti.com/lit/gpn/mspm0g5187 Table 8-24*/ +static const struct mspm0_part_info mspm0g_parts_bbbc[] = { + /* MSPM0G5187 */ + { "MSPM0G5187S28YCJR", 0x5610, 0x18 }, + { "MSPM0G5187SDGS20R", 0x5610, 0x16 }, + { "MSPM0G5187SPMR", 0x5610, 0x10 }, + { "MSPM0G5187SPTR", 0x5610, 0x11 }, + { "MSPM0G5187SRHBR", 0x5610, 0x13 }, + { "MSPM0G5187SRGER", 0x5610, 0x14 }, + { "MSPM0G5187SRGZR", 0x5610, 0x12 }, + { "MSPM0G5187SRUYR", 0x5610, 0x17 }, }; /* https://www.ti.com/lit/gpn/mspm0c1104 Table 8-12 and so on */ @@ -305,7 +412,9 @@ static const struct mspm0_part_info mspm0lx22x_parts[] = { static const struct mspm0_family_info mspm0_finf[] = { { "MSPM0L", 0xbb82, ARRAY_SIZE(mspm0l_parts), mspm0l_parts }, { "MSPM0Lx22x", 0xbb9f, ARRAY_SIZE(mspm0lx22x_parts), mspm0lx22x_parts }, - { "MSPM0G", 0xbb88, ARRAY_SIZE(mspm0g_parts), mspm0g_parts }, + { "MSPM0G", 0xbb88, ARRAY_SIZE(mspm0g_parts_bb88), mspm0g_parts_bb88 }, + { "MSPM0G", 0xbba9, ARRAY_SIZE(mspm0g_parts_bba9), mspm0g_parts_bba9 }, + { "MSPM0G", 0xbbbc, ARRAY_SIZE(mspm0g_parts_bbbc), mspm0g_parts_bbbc }, { "MSPM0C", 0xbba1, ARRAY_SIZE(mspm0c_parts), mspm0c_parts }, }; @@ -379,30 +488,94 @@ static int mspm0_read_part_info(struct flash_bank *bank) struct target *target = bank->target; const struct mspm0_family_info *minfo = NULL; + /* + * FLASH_ERR_01 workaround: on MSPM0G devices the flash controller + * rejects any bus-master access to FACTORYREGION when MCLK is sourced + * from HSCLK (SYSPLL/HFXT) and flash wait-state 2 is active + * (required for MCLK > 32 MHz). This applies to DAP AHB-AP reads too, + * not just CPU accesses. If both conditions are true, temporarily + * switch MCLK back to SYSOSC (≤ 32 MHz on every MSPM0 variant) for the + * FACTORYREGION reads and restore afterwards. The SYSCTL_MCLKCFG write + * does not take place on L/C parts: USEHSCLK is never set there because + * those cores do not exceed 32 MHz. + */ + uint32_t saved_mclkcfg = 0; + bool mclk_switched = false; + uint32_t mclkcfg; + int retval = target_read_u32(target, SYSCTL_MCLKCFG, &mclkcfg); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read SYSCTL_MCLKCFG to check FLASH_ERR_01"); + return retval; + } + + if ((mclkcfg & SYSCTL_MCLKCFG_USEHSCLK) && + ((mclkcfg & SYSCTL_MCLKCFG_FLASHWAIT_MASK) == SYSCTL_MCLKCFG_FLASHWAIT_2)) { + saved_mclkcfg = mclkcfg; + retval = target_write_u32(target, SYSCTL_MCLKCFG, + mclkcfg & ~SYSCTL_MCLKCFG_USEHSCLK); + if (retval == ERROR_OK) { + mclk_switched = true; + /* + * Read back MCLKCFG to flush the write, then add an + * explicit delay to allow the MCLK source mux to fully + * settle on SYSOSC before the flash controller timing is + * used for FACTORYREGION accesses. + */ + uint32_t dummy; + retval = target_read_u32(target, SYSCTL_MCLKCFG, &dummy); + if (retval != ERROR_OK) { + LOG_ERROR("MSPM0: FLASH_ERR_01 workaround: " + "readback flush failed"); + goto restore_mclk; + } + alive_sleep(1); + LOG_DEBUG("MSPM0: FLASH_ERR_01 workaround ACTIVE: " + "Lowering MCLK before FACTORYREGION read"); + } else { + LOG_ERROR("MSPM0: FLASH_ERR_01 workaround: " + "could not lower MCLK before FACTORYREGION read"); + } + } + /* Read and parse chip identification and flash version register */ uint32_t did; - int retval = target_read_u32(target, MSPM0_DID, &did); + retval = target_read_u32(target, MSPM0_DID, &did); if (retval != ERROR_OK) { LOG_ERROR("Failed to read device ID"); - return retval; + goto restore_mclk; } retval = target_read_u32(target, MSPM0_TRACEID, &mspm0_info->traceid); if (retval != ERROR_OK) { LOG_ERROR("Failed to read trace ID"); - return retval; + goto restore_mclk; } uint32_t userid; retval = target_read_u32(target, MSPM0_USERID, &userid); if (retval != ERROR_OK) { LOG_ERROR("Failed to read user ID"); - return retval; + goto restore_mclk; } uint32_t flashram; retval = target_read_u32(target, MSPM0_SRAMFLASH, &flashram); if (retval != ERROR_OK) { LOG_ERROR("Failed to read sramflash register"); - return retval; + goto restore_mclk; } + +restore_mclk: + if (mclk_switched) { + int retval2 = target_write_u32(target, SYSCTL_MCLKCFG, saved_mclkcfg); + if (retval2 != ERROR_OK) { + LOG_ERROR("MSPM0: FLASH_ERR_01 workaround: " + "could not restore MCLK after FACTORYREGION read"); + return retval2; + } + LOG_DEBUG("MSPM0: FLASH_ERR_01 workaround: " + "restored MCLK after FACTORYREGION read"); + } + if (retval != ERROR_OK) + return retval; + uint32_t flashdesc; retval = target_read_u32(target, FCTL_REG_DESC, &flashdesc); if (retval != ERROR_OK) { @@ -429,7 +602,7 @@ static int mspm0_read_part_info(struct flash_bank *bank) LOG_WARNING("Unknown Device ID[0x%" PRIx32 "], cannot identify target", did); LOG_DEBUG("did 0x%" PRIx32 ", traceid 0x%" PRIx32 ", userid 0x%" PRIx32 - ", flashram 0x%" PRIx32 "", did, mspm0_info->traceid, userid, + ", flashram 0x%" PRIx32, did, mspm0_info->traceid, userid, flashram); return ERROR_FLASH_OPERATION_FAILED; } @@ -737,10 +910,10 @@ static int mspm0_fctl_wait_cmd_ok(struct flash_bank *bank) return retval; elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > MSPM0_FLASH_TIMEOUT_MS) break; + + keep_alive(); } if ((return_code & FCTL_STATCMD_CMDPASS_MASK) != FCTL_STATCMD_CMDPASS_STATPASS) { @@ -1062,6 +1235,19 @@ static int mspm0_probe(struct flash_bank *bank) mspm0_info->protect_reg_count = 1; break; case MSPM0_FLASH_BASE_MAIN: + if (!mspm0_info->main_flash_size_kb) { + /* + * FACTORYREGION was unreadable when this bank was probed + * (e.g. device not yet halted, MCLK still at HSCLK on + * first examine). Clear did so the next auto_probe call + * re-runs mspm0_read_part_info with the target in a known + * state. + */ + LOG_WARNING("MSPM0: main flash size is 0 — " + "FACTORYREGION data incomplete, scheduling re-probe"); + mspm0_info->did = 0; + return ERROR_FLASH_BANK_NOT_PROBED; + } bank->size = (mspm0_info->main_flash_size_kb * 1024); bank->num_sectors = bank->size / mspm0_info->sector_size; /* diff --git a/src/flash/nor/niietcm4.c b/src/flash/nor/niietcm4.c index aaf0726550..4251d13dfe 100644 --- a/src/flash/nor/niietcm4.c +++ b/src/flash/nor/niietcm4.c @@ -1165,10 +1165,8 @@ static int niietcm4_erase(struct flash_bank *bank, unsigned int first, return ERROR_TARGET_NOT_HALTED; } - if ((first == 0) && (last == (bank->num_sectors - 1))) { - retval = niietcm4_mass_erase(bank); - return retval; - } + if (first == 0 && last == (bank->num_sectors - 1)) + return niietcm4_mass_erase(bank); /* chose between main bootflash and info bootflash */ uint32_t flash_cmd, flash_addr; diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 5cb552aa94..b92bb5b7cb 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -796,8 +796,8 @@ static int nrf5_read_ficr_more_info(struct nrf5_info *chip) if (res != ERROR_OK) return res; - res = target_read_u32(target, ficr_base + ficr_offsets->info_flash, &chip->ficr_info.flash); - return res; + return target_read_u32(target, ficr_base + ficr_offsets->info_flash, + &chip->ficr_info.flash); } /* nRF51 series only */ @@ -1121,8 +1121,7 @@ static int nrf5_erase_page(struct flash_bank *bank, return res; } - res = nrf5_wait_for_nvmc(chip); - return res; + return nrf5_wait_for_nvmc(chip); } /* Start a low level flash write for the specified region */ diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c index a0c6e0c815..5809494df0 100644 --- a/src/flash/nor/numicro.c +++ b/src/flash/nor/numicro.c @@ -567,7 +567,7 @@ static int numicro_reg_unlock(struct target *target) if (retval != ERROR_OK) return retval; - LOG_DEBUG("protected = 0x%08" PRIx32 "", is_protected); + 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 - m_address_bias_offset, REG_KEY1); @@ -828,7 +828,7 @@ static int numicro_protect_check(struct flash_bank *bank) 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]); + LOG_DEBUG("CONFIG0: 0x%" PRIx32 ",CONFIG1: 0x%" PRIx32, config[0], config[1]); if ((config[0] & (1<<7)) == 0) LOG_INFO("CBS=0: Boot From LPROM"); @@ -908,7 +908,7 @@ static int numicro_erase(struct flash_bank *bank, unsigned int first, if (retval != ERROR_OK) return retval; if ((status & ISPCON_ISPFF) != 0) { - LOG_DEBUG("failure: 0x%" PRIx32 "", status); + 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 - m_address_bias_offset, (status | ISPCON_ISPFF)); if (retval != ERROR_OK) @@ -1007,7 +1007,7 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) return retval; if ((status & ISPCON_ISPFF) != 0) { - LOG_DEBUG("failure: 0x%" PRIx32 "", status); + 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 - m_address_bias_offset, @@ -1037,7 +1037,7 @@ static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_ return ERROR_FLASH_OPERATION_FAILED; } - LOG_INFO("Device ID: 0x%08" PRIx32 "", part_id); + LOG_INFO("Device ID: 0x%08" PRIx32, part_id); /* search part numbers */ for (size_t i = 0; i < ARRAY_SIZE(numicro_parts); i++) { if (part_id == numicro_parts[i].partid) { diff --git a/src/flash/nor/ocl.c b/src/flash/nor/ocl.c index 61af908f58..6db7368f94 100644 --- a/src/flash/nor/ocl.c +++ b/src/flash/nor/ocl.c @@ -82,9 +82,9 @@ static int ocl_erase(struct flash_bank *bank, unsigned int first, if (dcc_buffer[1] != OCL_CMD_DONE) { if (dcc_buffer[0] == OCL_ERASE_ALL) - LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32 "", dcc_buffer[1]); + LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32, dcc_buffer[1]); else - LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08" PRIx32 "", dcc_buffer[1]); + LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08" PRIx32, dcc_buffer[1]); return ERROR_FLASH_OPERATION_FAILED; } @@ -132,21 +132,21 @@ static int ocl_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of /* copy data to DCC buffer in proper byte order and properly aligned */ for (i = 0; i < runlen; i++) { switch (byteofs++) { - case 0: - *dcc_bufptr &= *(buffer++) | 0xffffff00; - break; - case 1: - *dcc_bufptr &= ((*(buffer++)) << 8) | 0xffff00ff; - break; - case 2: - *dcc_bufptr &= ((*(buffer++)) << 16) | 0xff00ffff; - break; - case 3: - *dcc_bufptr &= ((*(buffer++)) << 24) | 0x00ffffff; - chksum ^= *(dcc_bufptr++); - *dcc_bufptr = 0xffffffff; - byteofs = 0; - break; + case 0: + *dcc_bufptr &= *(buffer++) | 0xffffff00; + break; + case 1: + *dcc_bufptr &= ((*(buffer++)) << 8) | 0xffff00ff; + break; + case 2: + *dcc_bufptr &= ((*(buffer++)) << 16) | 0xff00ffff; + break; + case 3: + *dcc_bufptr &= ((*(buffer++)) << 24) | 0x00ffffff; + chksum ^= *(dcc_bufptr++); + *dcc_bufptr = 0xffffffff; + byteofs = 0; + break; } } @@ -178,7 +178,7 @@ static int ocl_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of } if (dcc_buffer[0] != OCL_CMD_DONE) { - LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32 "", dcc_buffer[0]); + LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32, dcc_buffer[0]); free(dcc_buffer); return ERROR_FLASH_OPERATION_FAILED; } @@ -217,7 +217,7 @@ static int ocl_probe(struct flash_bank *bank) return retval; if (dcc_buffer[0] != OCL_CMD_DONE) { - LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32 "", dcc_buffer[0]); + LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32, dcc_buffer[0]); return ERROR_FLASH_OPERATION_FAILED; } diff --git a/src/flash/nor/pic32mx.c b/src/flash/nor/pic32mx.c index 982c9610a4..59e67cfe22 100644 --- a/src/flash/nor/pic32mx.c +++ b/src/flash/nor/pic32mx.c @@ -608,7 +608,7 @@ static int pic32mx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ } LOG_DEBUG("writing to flash at address " TARGET_ADDR_FMT " at offset 0x%8.8" PRIx32 - " count: 0x%8.8" PRIx32 "", bank->base, offset, count); + " count: 0x%8.8" PRIx32, bank->base, offset, count); if (offset & 0x3) { LOG_WARNING("offset 0x%" PRIx32 "breaks required 4-byte alignment", offset); @@ -900,7 +900,7 @@ COMMAND_HANDLER(pic32mx_handle_unlock_command) mchip_cmd = MCHP_STATUS; mips_ejtag_drscan_8(ejtag_info, &mchip_cmd); if (timeout-- == 0) { - LOG_DEBUG("timeout waiting for unlock: 0x%" PRIx8 "", mchip_cmd); + LOG_DEBUG("timeout waiting for unlock: 0x%" PRIx8, mchip_cmd); break; } alive_sleep(1); diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index 72cf0ee05b..88f9b1310e 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -178,7 +178,7 @@ static const char *psoc4_decode_chip_protection(uint8_t protection) case PSOC4_CHIP_PROT_KILL: return "protection KILL"; default: - LOG_WARNING("Unknown protection state 0x%02" PRIx8 "", protection); + LOG_WARNING("Unknown protection state 0x%02" PRIx8, protection); return ""; } } @@ -658,7 +658,7 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, memset(row_buffer + chunk_size, bank->default_padded_value, psoc4_info->row_size - chunk_size); } memcpy(row_buffer + row_offset, buffer, chunk_size); - LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32 "", + LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32, offset, row_offset, chunk_size); uint32_t macro_idx = row_num / PSOC4_ROWS_PER_MACRO; @@ -858,7 +858,7 @@ static int get_psoc4_info(struct flash_bank *bank, struct command_invocation *cm "/0x%02" PRIx16 ", silicon id 0x%08" PRIx32, psoc4_info->family_id, family_id, silicon_id); else { - command_print_sameline(cmd, "%s silicon id 0x%08" PRIx32 "", + command_print_sameline(cmd, "%s silicon id 0x%08" PRIx32, family->name, silicon_id); } diff --git a/src/flash/nor/psoc5lp.c b/src/flash/nor/psoc5lp.c index e8c9019505..e51c1cb1c0 100644 --- a/src/flash/nor/psoc5lp.c +++ b/src/flash/nor/psoc5lp.c @@ -237,8 +237,7 @@ static int psoc5lp_get_device_id(struct target *target, uint32_t *id) retval = target_read_u32(target, PANTHER_DEVICE_ID, id); /* dummy read */ if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, PANTHER_DEVICE_ID, id); - return retval; + return target_read_u32(target, PANTHER_DEVICE_ID, id); } static int psoc5lp_find_device(struct target *target, @@ -297,8 +296,7 @@ static int psoc5lp_spc_write_opcode(struct target *target, uint8_t opcode) retval = target_write_u8(target, SPC_CPU_DATA, SPC_KEY2 + opcode); if (retval != ERROR_OK) return retval; - retval = target_write_u8(target, SPC_CPU_DATA, opcode); - return retval; + return target_write_u8(target, SPC_CPU_DATA, opcode); } static void psoc5lp_spc_write_opcode_buffer(struct target *target, @@ -1081,17 +1079,18 @@ static int psoc5lp_erase_check(struct flash_bank *bank) bool fast_check = true; for (unsigned int i = 0; i < num_sectors; ) { + unsigned int checked; retval = armv7m_blank_check_memory(target, block_array + i, num_sectors - i, - bank->erased_value); - if (retval < 1) { + bank->erased_value, &checked); + if (retval != ERROR_OK) { /* Run slow fallback if the first run gives no result * otherwise use possibly incomplete results */ if (i == 0) fast_check = false; break; } - i += retval; /* add number of blocks done this round */ + i += checked; /* add number of blocks done this round */ } if (fast_check) { diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index 662910aa04..b53be7847b 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -420,17 +420,17 @@ static int psoc6_protect_check(struct flash_bank *bank) return hr; switch (psoc6_info->protection) { - case PROTECTION_VIRGIN: - case PROTECTION_NORMAL: - is_protected = 0; - break; - - case PROTECTION_UNKNOWN: - case PROTECTION_SECURE: - case PROTECTION_DEAD: - default: - is_protected = 1; - break; + case PROTECTION_VIRGIN: + case PROTECTION_NORMAL: + is_protected = 0; + break; + + case PROTECTION_UNKNOWN: + case PROTECTION_SECURE: + case PROTECTION_DEAD: + default: + is_protected = 1; + break; } for (unsigned int i = 0; i < bank->num_sectors; i++) @@ -463,17 +463,17 @@ static int psoc6_protect(struct flash_bank *bank, int set, unsigned int first, static const char *protection_to_str(uint8_t protection) { switch (protection) { - case PROTECTION_VIRGIN: - return "VIRGIN"; - case PROTECTION_NORMAL: - return "NORMAL"; - case PROTECTION_SECURE: - return "SECURE"; - case PROTECTION_DEAD: - return "DEAD"; - case PROTECTION_UNKNOWN: - default: - return "UNKNOWN"; + case PROTECTION_VIRGIN: + return "VIRGIN"; + case PROTECTION_NORMAL: + return "NORMAL"; + case PROTECTION_SECURE: + return "SECURE"; + case PROTECTION_DEAD: + return "DEAD"; + case PROTECTION_UNKNOWN: + default: + return "UNKNOWN"; } } @@ -868,9 +868,7 @@ COMMAND_HANDLER(psoc6_handle_mass_erase_command) if (hr != ERROR_OK) return hr; - hr = psoc6_erase(bank, 0, bank->num_sectors - 1); - - return hr; + return psoc6_erase(bank, 0, bank->num_sectors - 1); } /** *********************************************************************************************** diff --git a/src/flash/nor/qn908x.c b/src/flash/nor/qn908x.c index 8cd7a2f04a..a881d549b1 100644 --- a/src/flash/nor/qn908x.c +++ b/src/flash/nor/qn908x.c @@ -257,7 +257,7 @@ static int qn908x_update_reg(struct target *target, target_addr_t reg, } if (mask == 0xffffffff) { LOG_DEBUG("Updated reg at " TARGET_ADDR_FMT ": ?? -> 0x%.08" - PRIx32 "", reg, new_value); + PRIx32, reg, new_value); } else { LOG_DEBUG("Updated reg at " TARGET_ADDR_FMT ": 0x%.08" PRIx32 " -> 0x%.08" PRIx32, reg, orig_value, new_value); diff --git a/src/flash/nor/read_only.c b/src/flash/nor/read_only.c new file mode 100644 index 0000000000..5459d9b3a2 --- /dev/null +++ b/src/flash/nor/read_only.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2019 by Tomas Vanek + * + * To declare a read-only region for GDB memory map. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" + +FLASH_BANK_COMMAND_HANDLER(rom_bank_command) +{ + bank->read_only = true; + return ERROR_OK; +} + +static int rom_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + LOG_ERROR("Erase of read-only memory refused"); + return ERROR_FAIL; +} + +static int rom_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + LOG_ERROR("Write to read-only memory refused"); + return ERROR_FAIL; +} + +static int rom_probe(struct flash_bank *bank) +{ + return ERROR_OK; +} + +const struct flash_driver read_only_flash = { + .name = "read_only", + .flash_bank_command = rom_bank_command, + .erase = rom_erase, + .write = rom_write, + .read = default_flash_read, + .probe = rom_probe, + .auto_probe = rom_probe, + .erase_check = default_flash_blank_check, + + // ROM driver doesn't set driver_priv, free(NULL) makes no harm + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/rp2xxx.c b/src/flash/nor/rp2xxx.c index 85c5911041..30c6e99141 100644 --- a/src/flash/nor/rp2xxx.c +++ b/src/flash/nor/rp2xxx.c @@ -41,10 +41,18 @@ #define BOOTROM_STATE_RESET_OTHER_CORE 0x02 #define BOOTROM_STATE_RESET_GLOBAL_STATE 0x04 -#define ACCESSCTRL_LOCK_OFFSET 0x40060000u -#define ACCESSCTRL_LOCK_DEBUG_BITS 0x00000008u -#define ACCESSCTRL_CFGRESET_OFFSET 0x40060008u -#define ACCESSCTRL_WRITE_PASSWORD 0xacce0000u +#define ACCESSCTRL_LOCK_OFFSET 0x40060000u +#define ACCESSCTRL_CFGRESET_OFFSET 0x40060008u +#define ACCESSCTRL_GPIO_NSMASK0_OFFSET 0x4006000cu +#define ACCESSCTRL_GPIO_ROM_OFFSET 0x40060014u +#define ACCESSCTRL_GPIO_XIP_AUX_OFFSET 0x400600e8u + +#define ACCESSCTRL_SAVE_BASE ACCESSCTRL_GPIO_NSMASK0_OFFSET +#define ACCESSCTRL_SAVE_SIZE \ + (ACCESSCTRL_GPIO_XIP_AUX_OFFSET + 4 - ACCESSCTRL_SAVE_BASE) + +#define ACCESSCTRL_LOCK_DEBUG_BITS 0x00000008u +#define ACCESSCTRL_WRITE_PASSWORD 0xacce0000u #define RP2040_SSI_DR0 0x18000060 #define RP2040_QSPI_CTRL 0x4001800c @@ -209,6 +217,10 @@ struct rp2xxx_flash_bank { bool size_override; struct flash_device spi_dev; /* detected model of SPI flash */ unsigned int sfdp_dummy, sfdp_dummy_detect; + + struct cortex_m_saved_security saved_security; + bool accessctrl_dirty; + uint8_t saved_accessctrl[ACCESSCTRL_SAVE_SIZE]; /* in target byte order */ }; #ifndef LOG_ROM_SYMBOL_DEBUG @@ -599,8 +611,28 @@ static int rp2xxx_call_rom_func(struct target *target, struct rp2xxx_flash_bank return rp2xxx_call_rom_func_batch(target, priv, &call, 1); } -static int rp2350_init_accessctrl(struct target *target) +static int rp2350_save_accessctrl(struct target *target, struct rp2xxx_flash_bank *priv) +{ + return target_read_memory(target, ACCESSCTRL_SAVE_BASE, 4, ACCESSCTRL_SAVE_SIZE / 4, + priv->saved_accessctrl); +} + +static int rp2350_restore_accessctrl(struct target *target, struct rp2xxx_flash_bank *priv) { + // Add write passwords to all ACCESSCTRL regs from ACCESSCTRL_GPIO_ROM to the end + // (exclude not keyed ACCESSCTRL_GPIO_NSMASK0 and ACCESSCTRL_GPIO_NSMASK1 + for (unsigned int i = ACCESSCTRL_GPIO_ROM_OFFSET - ACCESSCTRL_SAVE_BASE; + i < ACCESSCTRL_SAVE_SIZE; i += 4) + target_buffer_set_u32(target, priv->saved_accessctrl + i, + target_buffer_get_u32(target, priv->saved_accessctrl + i) | ACCESSCTRL_WRITE_PASSWORD); + + return target_write_memory(target, ACCESSCTRL_SAVE_BASE, 4, ACCESSCTRL_SAVE_SIZE / 4, + priv->saved_accessctrl); +} + +static int rp2350_init_accessctrl(struct target *target, struct rp2xxx_flash_bank *priv) +{ + priv->accessctrl_dirty = false; // Attempt to reset ACCESSCTRL, in case Secure access to SRAM has been // blocked, which will stop us from loading/running algorithms such as RCP // init. (Also ROM, QMI regs are needed later) @@ -618,6 +650,13 @@ static int rp2350_init_accessctrl(struct target *target) if (accessctrl_lock_reg & ACCESSCTRL_LOCK_DEBUG_BITS) { LOG_ERROR("ACCESSCTRL is locked, so can't reset permissions. Following steps might fail"); } else { + int retval = rp2350_save_accessctrl(target, priv); + if (retval == ERROR_OK) + priv->accessctrl_dirty = true; + // If the ACCESSCTRL backup copy is valid, mark it dirty + // as we immediately proceed to ACCESSCTRL config reset. + // Don't fail on save ACCESSCTRL error, not vital for ROM API call + LOG_DEBUG("Reset ACCESSCTRL permissions via CFGRESET"); return target_write_u32(target, ACCESSCTRL_CFGRESET_OFFSET, ACCESSCTRL_WRITE_PASSWORD | 1u); } @@ -630,23 +669,12 @@ static int rp2350_init_arm_core0(struct target *target, struct rp2xxx_flash_bank // run in the Secure state, so flip the state now before attempting to // execute any code on the core. int retval; - uint32_t dscsr; - retval = target_read_u32(target, DCB_DSCSR, &dscsr); + retval = cortex_m_set_secure(target, &priv->saved_security); if (retval != ERROR_OK) { - LOG_ERROR("RP2350 init ARM core: DSCSR read failed"); + LOG_ERROR("RP2350 init ARM core: set secure mode failed"); return retval; } - LOG_DEBUG("DSCSR: 0x%08" PRIx32, dscsr); - if (!(dscsr & DSCSR_CDS)) { - LOG_DEBUG("Setting Current Domain Secure in DSCSR"); - retval = target_write_u32(target, DCB_DSCSR, (dscsr & ~DSCSR_CDSKEY) | DSCSR_CDS); - if (retval != ERROR_OK) { - LOG_ERROR("RP2350 init ARM core: DSCSR read failed"); - return retval; - } - } - if (!priv->stack) { LOG_ERROR("No stack for flash programming code"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -713,7 +741,7 @@ static int setup_for_raw_flash_cmd(struct target *target, struct rp2xxx_flash_ba } if (IS_RP2350(priv->id)) { - err = rp2350_init_accessctrl(target); + err = rp2350_init_accessctrl(target, priv); if (err != ERROR_OK) { LOG_ERROR("Failed to init ACCESSCTRL before ROM call"); return err; @@ -840,6 +868,22 @@ static void cleanup_after_raw_flash_cmd(struct target *target, struct rp2xxx_fla driver state. Best to clean up our allocations manually after completing each flash call, so we know to make fresh ones next time. */ LOG_DEBUG("Cleaning up after flash operations"); + + if (IS_RP2350(priv->id)) { + int retval1 = ERROR_OK; + if (priv->accessctrl_dirty) { + retval1 = rp2350_restore_accessctrl(target, priv); + priv->accessctrl_dirty = false; + } + + int retval2 = ERROR_OK; + if (is_arm(target_to_arm(target))) + retval2 = cortex_m_security_restore(target, &priv->saved_security); + + if (retval1 != ERROR_OK || retval2 != ERROR_OK) + LOG_WARNING("RP2xxx: security state was not restored properly. Debug 'resume' will probably fail, use 'reset' instead"); + /* Don't fail on security restore error, not vital for flash operation */ + } if (priv->stack) { target_free_working_area(target, priv->stack); priv->stack = 0; diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index bf654f9f6b..f1ca5f0e5e 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -125,6 +125,8 @@ const struct flash_device flash_devices[] = { FLASH_ID("micron mt25ql01", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021ba20, 0x100, 0x10000, 0x8000000), FLASH_ID("micron mt25qu01", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021bb20, 0x100, 0x10000, 0x8000000), FLASH_ID("micron mt25ql02", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0022ba20, 0x100, 0x10000, 0x10000000), + FLASH_ID("bsemi by25q16es", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x00154068, 0x100, 0x10000, 0x200000), + FLASH_ID("boya by25q128as", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x00184068, 0x100, 0x10000, 0x1000000), FLASH_ID("win w25q80bv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540ef, 0x100, 0x10000, 0x200000), FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001570ef, 0x100, 0x10000, 0x200000), /* QPI / DTR */ @@ -184,6 +186,16 @@ const struct flash_device flash_devices[] = { 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), + FLASH_ID("puya p25q05", 0x03, 0x6b, 0x02, 0x20, 0xc7, 0x00106085, 0x100, 0x1000, 0x10000), + FLASH_ID("puya p25q10", 0x03, 0x6b, 0x02, 0x20, 0xc7, 0x00116085, 0x100, 0x1000, 0x20000), + FLASH_ID("puya p25q20", 0x03, 0x6b, 0x02, 0x20, 0xc7, 0x00126085, 0x100, 0x1000, 0x40000), + FLASH_ID("puya p25q40", 0x03, 0x6b, 0x02, 0x20, 0xc7, 0x00136085, 0x100, 0x1000, 0x80000), + FLASH_ID("puya p25q80", 0x03, 0x6b, 0x02, 0x52, 0xc7, 0x00146085, 0x100, 0x8000, 0x100000), + FLASH_ID("puya p25q16", 0x03, 0x6b, 0x02, 0xd8, 0xc7, 0x00156085, 0x100, 0x10000, 0x200000), + FLASH_ID("puya p25q32", 0x03, 0x6b, 0x02, 0xd8, 0xc7, 0x00166085, 0x100, 0x10000, 0x400000), + FLASH_ID("puya p25q64", 0x03, 0x6b, 0x02, 0xd8, 0xc7, 0x00176085, 0x100, 0x10000, 0x800000), + FLASH_ID("puya p25q128", 0x03, 0x6b, 0x02, 0xd8, 0xc7, 0x00186085, 0x100, 0x10000, 0x1000000), + /* FRAM, no erase commands, no write page or sectors */ diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index f7dcc6f0e3..bf598b1179 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -573,13 +573,13 @@ static void stellaris_read_clock_info(struct flash_bank *bank) unsigned long mainfreq; target_read_u32(target, SCB_BASE | RCC, &rcc); - LOG_DEBUG("Stellaris RCC %" PRIx32 "", rcc); + LOG_DEBUG("Stellaris RCC %" PRIx32, rcc); target_read_u32(target, SCB_BASE | RCC2, &rcc2); - LOG_DEBUG("Stellaris RCC2 %" PRIx32 "", rcc); + LOG_DEBUG("Stellaris RCC2 %" PRIx32, rcc); target_read_u32(target, SCB_BASE | PLLCFG, &pllcfg); - LOG_DEBUG("Stellaris PLLCFG %" PRIx32 "", pllcfg); + LOG_DEBUG("Stellaris PLLCFG %" PRIx32, pllcfg); stellaris_info->rcc = rcc; stellaris_info->rcc2 = rcc2; @@ -608,30 +608,30 @@ static void stellaris_read_clock_info(struct flash_bank *bank) stellaris_info->mck_desc = ""; switch (oscsrc) { - case 0: /* MOSC */ - mainfreq = rcc_xtal[xtal]; - break; - case 1: /* IOSC */ - mainfreq = stellaris_info->iosc_freq; - stellaris_info->mck_desc = stellaris_info->iosc_desc; - break; - case 2: /* IOSC/4 */ - mainfreq = stellaris_info->iosc_freq / 4; - stellaris_info->mck_desc = stellaris_info->iosc_desc; - break; - case 3: /* lowspeed */ - /* Sandstorm doesn't have this 30K +/- 30% osc */ - mainfreq = 30000; - stellaris_info->mck_desc = " (±30%)"; - break; - case 8: /* hibernation osc */ - /* not all parts support hibernation */ - mainfreq = 32768; - break; - - default: /* NOTREACHED */ - mainfreq = 0; - break; + case 0: /* MOSC */ + mainfreq = rcc_xtal[xtal]; + break; + case 1: /* IOSC */ + mainfreq = stellaris_info->iosc_freq; + stellaris_info->mck_desc = stellaris_info->iosc_desc; + break; + case 2: /* IOSC/4 */ + mainfreq = stellaris_info->iosc_freq / 4; + stellaris_info->mck_desc = stellaris_info->iosc_desc; + break; + case 3: /* lowspeed */ + /* Sandstorm doesn't have this 30K +/- 30% osc */ + mainfreq = 30000; + stellaris_info->mck_desc = " (±30%)"; + break; + case 8: /* hibernation osc */ + /* not all parts support hibernation */ + mainfreq = 32768; + break; + + default: /* NOTREACHED */ + mainfreq = 0; + break; } /* PLL is used if it's not bypassed; its output is 200 MHz @@ -659,7 +659,7 @@ static int stellaris_read_part_info(struct flash_bank *bank) target_read_u32(target, SCB_BASE | DID1, &did1); target_read_u32(target, SCB_BASE | DC0, &stellaris_info->dc0); target_read_u32(target, SCB_BASE | DC1, &stellaris_info->dc1); - LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32 "", + LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32, did0, did1, stellaris_info->dc0, stellaris_info->dc1); ver = DID0_VER(did0); @@ -702,35 +702,35 @@ static int stellaris_read_part_info(struct flash_bank *bank) } switch (stellaris_info->target_class) { - case 0: /* Sandstorm */ - /* - * Current (2009-August) parts seem to be rev C2 and use 12 MHz. - * Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz - * (LM3S618), but some other C0 parts are 12 MHz (LM3S811). - */ - if (((did0 >> 8) & 0xff) < 2) { - stellaris_info->iosc_freq = 15000000; - stellaris_info->iosc_desc = " (±50%)"; - } - break; + case 0: /* Sandstorm */ + /* + * Current (2009-August) parts seem to be rev C2 and use 12 MHz. + * Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz + * (LM3S618), but some other C0 parts are 12 MHz (LM3S811). + */ + if (((did0 >> 8) & 0xff) < 2) { + stellaris_info->iosc_freq = 15000000; + stellaris_info->iosc_desc = " (±50%)"; + } + break; - case 1: /* Fury */ - break; + case 1: /* Fury */ + break; - case 4: /* Tempest */ - case 5: /* Blizzard */ - case 6: /* Firestorm */ - case 0xa: /* Snowflake */ - stellaris_info->iosc_freq = 16000000; /* +/- 1% */ - stellaris_info->iosc_desc = " (±1%)"; - /* FALL THROUGH */ + case 4: /* Tempest */ + case 5: /* Blizzard */ + case 6: /* Firestorm */ + case 0xa: /* Snowflake */ + stellaris_info->iosc_freq = 16000000; /* +/- 1% */ + stellaris_info->iosc_desc = " (±1%)"; + /* FALL THROUGH */ - case 3: /* DustDevil */ - stellaris_info->xtal_mask = 0x1f; - break; + case 3: /* DustDevil */ + stellaris_info->xtal_mask = 0x1f; + break; - default: - LOG_WARNING("Unknown did0 class"); + default: + LOG_WARNING("Unknown did0 class"); } for (i = 0; stellaris_parts[i].partno; i++) { @@ -871,7 +871,7 @@ static int stellaris_erase(struct flash_bank *bank, unsigned int first, /* Check access violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { - LOG_WARNING("Error erasing flash page %i, flash_cris 0x%" PRIx32 "", + LOG_WARNING("Error erasing flash page %i, flash_cris 0x%" PRIx32, banknr, flash_cris); target_write_u32(target, FLASH_CRIS, 0); return ERROR_FLASH_OPERATION_FAILED; @@ -967,7 +967,7 @@ static int stellaris_protect(struct flash_bank *bank, int set, /* Check access violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { - LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris); + LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32, flash_cris); target_write_u32(target, FLASH_CRIS, 0); return ERROR_FLASH_OPERATION_FAILED; } @@ -1035,7 +1035,7 @@ static int stellaris_write_block(struct flash_bank *bank, if (wcount * 4 < buf_min) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "", + LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32, bank, buffer, offset, wcount); /* flash write code */ @@ -1115,7 +1115,7 @@ static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_TARGET_NOT_HALTED; } - LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "", + LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32, bank, buffer, offset, count); if (stellaris_info->did1 == 0) @@ -1153,7 +1153,7 @@ static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, /* if an error occurred, we examine the reason, and quit */ target_read_u32(target, FLASH_CRIS, &flash_cris); - LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32 "", flash_cris); + LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32, flash_cris); return ERROR_FLASH_OPERATION_FAILED; } } else { @@ -1165,7 +1165,7 @@ static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, while (words_remaining > 0) { if (!(address & 0xff)) - LOG_DEBUG("0x%" PRIx32 "", address); + LOG_DEBUG("0x%" PRIx32, address); /* Program one word */ target_write_u32(target, FLASH_FMA, address); @@ -1189,7 +1189,7 @@ static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, memcpy(last_word, buffer+bytes_written, bytes_remaining); if (!(address & 0xff)) - LOG_DEBUG("0x%" PRIx32 "", address); + LOG_DEBUG("0x%" PRIx32, address); /* Program one word */ target_write_u32(target, FLASH_FMA, address); @@ -1205,7 +1205,7 @@ static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, /* Check access violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { - LOG_DEBUG("flash_cris 0x%" PRIx32 "", flash_cris); + LOG_DEBUG("flash_cris 0x%" PRIx32, flash_cris); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 5a3c2da663..f512a26e9c 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -170,7 +170,7 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) retval = stm32x_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32, status); if ((status & FLASH_BSY) == 0) break; if (timeout-- <= 0) { @@ -825,7 +825,7 @@ static int stm32x_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - LOG_INFO("device id = 0x%08" PRIx32 "", dbgmcu_idcode); + LOG_INFO("device id = 0x%08" PRIx32, dbgmcu_idcode); uint16_t device_id = dbgmcu_idcode & 0xfff; uint16_t rev_id = dbgmcu_idcode >> 16; @@ -1444,8 +1444,8 @@ COMMAND_HANDLER(stm32x_handle_options_read_command) if (optionbyte & (1 << OPT_ERROR)) command_print(CMD, "option byte complement error"); - command_print(CMD, "option byte register = 0x%" PRIx32 "", optionbyte); - command_print(CMD, "write protection register = 0x%" PRIx32 "", protection); + command_print(CMD, "option byte register = 0x%" PRIx32, optionbyte); + command_print(CMD, "write protection register = 0x%" PRIx32, protection); command_print(CMD, "read protection: %s", (optionbyte & (1 << OPT_READOUT)) ? "on" : "off"); @@ -1465,7 +1465,7 @@ COMMAND_HANDLER(stm32x_handle_options_read_command) if (stm32x_info->has_dual_banks) command_print(CMD, "boot: bank %d", (optionbyte & (1 << OPT_BFB2)) ? 0 : 1); - command_print(CMD, "user data = 0x%02" PRIx16 "", user_data); + command_print(CMD, "user data = 0x%02" PRIx16, user_data); return ERROR_OK; } diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 3bafde56f8..5276d323c9 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -250,6 +250,10 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) return ERROR_COMMAND_SYNTAX_ERROR; stm32x_info = malloc(sizeof(struct stm32x_flash_bank)); + if (!stm32x_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } bank->driver_priv = stm32x_info; stm32x_info->probed = false; diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index c02fae992c..c91ab51602 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -9,71 +9,127 @@ #include "imp.h" #include +#include #include #include - /* Erase time can be as high as 1000ms, 10x this and it's toast... */ #define FLASH_ERASE_TIMEOUT 10000 #define FLASH_WRITE_TIMEOUT 5 +#define MASS_ERASE_TIMEOUT 30000 + +static const uint8_t stm32h7_flash_write_code[] = { +#include "../../../contrib/loaders/flash/stm32/stm32h7x.inc" +}; + +static const uint8_t stm32h7rs_flash_write_code[] = { +#include "../../../contrib/loaders/flash/stm32/stm32h7rx.inc" +}; + +enum stm32h7_flash_reg_index { + STM32_FLASH_ACR_INDEX, + STM32_FLASH_KEYR_INDEX, + STM32_FLASH_OPTKEYR_INDEX, + STM32_FLASH_SR_INDEX, + STM32_FLASH_CR_INDEX, + STM32_FLASH_ICR_CCR_INDEX, + STM32_FLASH_OPTCR_INDEX, + STM32_FLASH_OPTSR_INDEX, + STM32_FLASH_OPTSR_CUR_INDEX, + STM32_FLASH_OPTSR_PRG_INDEX, + STM32_FLASH_OPTCCR_INDEX, + STM32_FLASH_WPSN_CUR_INDEX, + STM32_FLASH_WPSN_PRG_INDEX, + STM32_FLASH_ISR_INDEX, + STM32_FLASH_REG_INDEX_NUM, +}; /* RM 433 */ /* Same Flash registers for both banks, */ /* access depends on Flash Base address */ -#define FLASH_ACR 0x00 -#define FLASH_KEYR 0x04 -#define FLASH_OPTKEYR 0x08 -#define FLASH_CR 0x0C -#define FLASH_SR 0x10 -#define FLASH_CCR 0x14 -#define FLASH_OPTCR 0x18 -#define FLASH_OPTSR_CUR 0x1C -#define FLASH_OPTSR_PRG 0x20 -#define FLASH_OPTCCR 0x24 -#define FLASH_WPSN_CUR 0x38 -#define FLASH_WPSN_PRG 0x3C +static const uint32_t stm32h7_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { + [STM32_FLASH_ACR_INDEX] = 0x00, + [STM32_FLASH_KEYR_INDEX] = 0x04, + [STM32_FLASH_OPTKEYR_INDEX] = 0x08, + [STM32_FLASH_SR_INDEX] = 0x10, + [STM32_FLASH_CR_INDEX] = 0x0C, + [STM32_FLASH_ICR_CCR_INDEX] = 0x14, + [STM32_FLASH_OPTCR_INDEX] = 0x18, + [STM32_FLASH_OPTSR_CUR_INDEX] = 0x1C, + [STM32_FLASH_OPTSR_PRG_INDEX] = 0x20, + [STM32_FLASH_OPTCCR_INDEX] = 0x24, + [STM32_FLASH_WPSN_CUR_INDEX] = 0x38, + [STM32_FLASH_WPSN_PRG_INDEX] = 0x3C +}; +static const uint32_t stm32h7rs_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { + [STM32_FLASH_ACR_INDEX] = 0x00, + [STM32_FLASH_KEYR_INDEX] = 0x04, + [STM32_FLASH_OPTKEYR_INDEX] = 0x100, + [STM32_FLASH_SR_INDEX] = 0x14, + [STM32_FLASH_CR_INDEX] = 0x10, + [STM32_FLASH_ICR_CCR_INDEX] = 0x28, + [STM32_FLASH_OPTCR_INDEX] = 0x104, + [STM32_FLASH_OPTSR_INDEX] = 0x10C, + [STM32_FLASH_ISR_INDEX] = 0x24, +}; /* FLASH_CR register bits */ -#define FLASH_LOCK (1 << 0) -#define FLASH_PG (1 << 1) -#define FLASH_SER (1 << 2) -#define FLASH_BER (1 << 3) +#define FLASH_LOCK BIT(0) +#define FLASH_PG BIT(1) +#define FLASH_SER BIT(2) +#define FLASH_BER BIT(3) #define FLASH_PSIZE_8 (0 << 4) #define FLASH_PSIZE_16 (1 << 4) #define FLASH_PSIZE_32 (2 << 4) #define FLASH_PSIZE_64 (3 << 4) -#define FLASH_FW (1 << 6) -#define FLASH_START (1 << 7) +#define FLASH_FW BIT(6) +#define FLASH_START BIT(7) + +/* FLASH_ISR register bits for H7RS */ +#define FLASH_CRCRDERRF BIT(28) /* CRC read error flag */ +#define FLASH_CRCENDF BIT(27) /* CRC end flag */ +#define FLASH_DBECCERRF BIT(26) /* ECC double error flag */ +#define FLASH_SNECCERRF BIT(25) /* ECC single error flag */ +#define FLASH_RDSERRF BIT(24) /* Read security error flag */ +#define FLASH_INCERRF BIT(21) /* Inconsistency error flag */ +#define FLASH_OBLERRF BIT(20) /* Option byte loading error flag */ +#define FLASH_STRBERRF BIT(19) /* Strobe error flag */ +#define FLASH_PGSERRF BIT(18) /* Programming sequence error flag */ +#define FLASH_WRPERRF BIT(17) /* Write protection error flag */ +#define FLASH_EOPF BIT(16) /* End-of-program flag */ /* FLASH_SR register bits */ -#define FLASH_BSY (1 << 0) /* Operation in progress */ -#define FLASH_QW (1 << 2) /* Operation queue in progress */ -#define FLASH_WRPERR (1 << 17) /* Write protection error */ -#define FLASH_PGSERR (1 << 18) /* Programming sequence error */ -#define FLASH_STRBERR (1 << 19) /* Strobe error */ -#define FLASH_INCERR (1 << 21) /* Inconsistency error */ -#define FLASH_OPERR (1 << 22) /* Operation error */ -#define FLASH_RDPERR (1 << 23) /* Read Protection error */ -#define FLASH_RDSERR (1 << 24) /* Secure Protection error */ -#define FLASH_SNECCERR (1 << 25) /* Single ECC error */ -#define FLASH_DBECCERR (1 << 26) /* Double ECC error */ +#define FLASH_BSY BIT(0) /* Operation in progress */ +#define FLASH_QW BIT(2) /* Operation queue in progress */ +#define FLASH_WRPERR BIT(17) /* Write protection error */ +#define FLASH_PGSERR BIT(18) /* Programming sequence error */ +#define FLASH_STRBERR BIT(19) /* Strobe error */ +#define FLASH_INCERR BIT(21) /* Inconsistency error */ +#define FLASH_OPERR BIT(22) /* Operation error */ +#define FLASH_RDPERR BIT(23) /* Read Protection error */ +#define FLASH_RDSERR BIT(24) /* Secure Protection error */ +#define FLASH_SNECCERR BIT(25) /* Single ECC error */ +#define FLASH_DBECCERR BIT(26) /* Double ECC error */ #define FLASH_ERROR (FLASH_WRPERR | FLASH_PGSERR | FLASH_STRBERR | FLASH_INCERR | FLASH_OPERR | \ FLASH_RDPERR | FLASH_RDSERR | FLASH_SNECCERR | FLASH_DBECCERR) +/* Possible errors for H7RS */ +#define FLASH_ERROR_H7RS (FLASH_CRCRDERRF | FLASH_CRCENDF | FLASH_DBECCERRF | FLASH_SNECCERRF | FLASH_RDSERRF | \ + FLASH_INCERRF | FLASH_OBLERRF | FLASH_STRBERRF | FLASH_PGSERRF | FLASH_WRPERRF | FLASH_EOPF) /* FLASH_OPTCR register bits */ -#define OPT_LOCK (1 << 0) -#define OPT_START (1 << 1) +#define OPT_LOCK BIT(0) +#define OPT_START BIT(1) /* FLASH_OPTSR register bits */ -#define OPT_BSY (1 << 0) +#define OPT_BSY BIT(0) #define OPT_RDP_POS 8 #define OPT_RDP_MASK (0xff << OPT_RDP_POS) -#define OPT_OPTCHANGEERR (1 << 30) +#define OPT_OPTCHANGEERR BIT(30) /* FLASH_OPTCCR register bits */ -#define OPT_CLR_OPTCHANGEERR (1 << 30) +#define OPT_CLR_OPTCHANGEERR BIT(30) /* register unlock keys */ #define KEY1 0x45670123 @@ -93,19 +149,20 @@ #define DEVID_STM32H74_H75XX 0x450 #define DEVID_STM32H7A_H7BXX 0x480 #define DEVID_STM32H72_H73XX 0x483 +#define DEVID_STM32H7R_H7SXX 0x485 -struct stm32h7x_rev { +struct stm32h7_rev { uint16_t rev; const char *str; }; -/* stm32h7x_part_info permits the store each device information and specificities. +/* stm32h7_part_info permits the store each device information and specificities. * the default unit is byte unless the suffix '_kb' is used. */ -struct stm32h7x_part_info { +struct stm32h7_part_info { uint16_t id; const char *device_str; - const struct stm32h7x_rev *revs; + const struct stm32h7_rev *revs; size_t num_revs; unsigned int page_size_kb; unsigned int block_size; /* flash write word size in bytes */ @@ -117,40 +174,49 @@ struct stm32h7x_part_info { uint32_t wps_mask; /* function to compute flash_cr register values */ uint32_t (*compute_flash_cr)(uint32_t cmd, int snb); + int (*get_flash_error_status)(struct flash_bank *bank, uint32_t *status); + uint32_t flash_error; + const uint8_t *write_code; + size_t write_code_size; }; -struct stm32h7x_flash_bank { +struct stm32h7_flash_bank { bool probed; uint32_t idcode; uint32_t user_bank_size; uint32_t flash_regs_base; /* Address of flash reg controller */ - const struct stm32h7x_part_info *part_info; + const uint32_t *flash_regs; + const struct stm32h7_part_info *part_info; }; -enum stm32h7x_opt_rdp { +enum stm32h7_opt_rdp { OPT_RDP_L0 = 0xaa, OPT_RDP_L1 = 0x00, OPT_RDP_L2 = 0xcc }; -static const struct stm32h7x_rev stm32h74_h75xx_revs[] = { +static const struct stm32h7_rev stm32h74_h75xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, { 0x2003, "V" }, }; -static const struct stm32h7x_rev stm32h7a_h7bxx_revs[] = { +static const struct stm32h7_rev stm32h7a_h7bxx_revs[] = { { 0x1000, "A"}, }; -static const struct stm32h7x_rev stm32h72_h73xx_revs[] = { +static const struct stm32h7_rev stm32h72_h73xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, }; +static const struct stm32h7_rev stm32h7r_h7sxx_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, +}; + static uint32_t stm32h74_h75xx_compute_flash_cr(uint32_t cmd, int snb) { return cmd | (snb << 8); } -static uint32_t stm32h7a_h7bxx_compute_flash_cr(uint32_t cmd, int snb) +static uint32_t stm32h7a_h7b_h7r_h7sxx_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); @@ -161,81 +227,115 @@ static uint32_t stm32h7a_h7bxx_compute_flash_cr(uint32_t cmd, int snb) return cmd | (tmp >> 2) | (snb << 6); } -static const struct stm32h7x_part_info stm32h7x_parts[] = { +static int stm32h7_get_flash_status(struct flash_bank *bank, uint32_t *status); +static int stm32h7rs_get_flash_status(struct flash_bank *bank, uint32_t *status); + +static const struct stm32h7_part_info stm32h7_parts[] = { + { + .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, + .max_flash_size_kb = 2048, + .max_bank_size_kb = 1024, + .has_dual_bank = true, + .fsize_addr = 0x1FF1E880, + .wps_group_size = 1, + .wps_mask = 0xFF, + .compute_flash_cr = stm32h74_h75xx_compute_flash_cr, + .get_flash_error_status = stm32h7_get_flash_status, + .flash_error = FLASH_ERROR, + .write_code = stm32h7_flash_write_code, + .write_code_size = sizeof(stm32h7_flash_write_code), + }, { - .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, - .max_flash_size_kb = 2048, - .max_bank_size_kb = 1024, - .has_dual_bank = true, - .fsize_addr = 0x1FF1E880, - .wps_group_size = 1, - .wps_mask = 0xFF, - .compute_flash_cr = stm32h74_h75xx_compute_flash_cr, + .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, + .max_flash_size_kb = 2048, + .max_bank_size_kb = 1024, + .has_dual_bank = true, + .fsize_addr = 0x08FFF80C, + .wps_group_size = 4, + .wps_mask = 0xFFFFFFFF, + .compute_flash_cr = stm32h7a_h7b_h7r_h7sxx_compute_flash_cr, + .get_flash_error_status = stm32h7_get_flash_status, + .flash_error = FLASH_ERROR, + .write_code = stm32h7_flash_write_code, + .write_code_size = sizeof(stm32h7_flash_write_code), }, { - .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, - .max_flash_size_kb = 2048, - .max_bank_size_kb = 1024, - .has_dual_bank = true, - .fsize_addr = 0x08FFF80C, - .wps_group_size = 4, - .wps_mask = 0xFFFFFFFF, - .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, + .get_flash_error_status = stm32h7_get_flash_status, + .flash_error = FLASH_ERROR, + .write_code = stm32h7_flash_write_code, + .write_code_size = sizeof(stm32h7_flash_write_code), }, { - .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, + .id = DEVID_STM32H7R_H7SXX, + .revs = stm32h7r_h7sxx_revs, + .num_revs = ARRAY_SIZE(stm32h7r_h7sxx_revs), + .device_str = "STM32H7Rx/7Sx", + .page_size_kb = 8, + .block_size = 16, + .max_flash_size_kb = 64, + .max_bank_size_kb = 64, + .has_dual_bank = false, + .fsize_addr = 0x08FFF80C, + .wps_group_size = 1, + .wps_mask = 0xFF, + .compute_flash_cr = stm32h7a_h7b_h7r_h7sxx_compute_flash_cr, + .get_flash_error_status = stm32h7rs_get_flash_status, + .flash_error = FLASH_ERROR_H7RS, + .write_code = stm32h7rs_flash_write_code, + .write_code_size = sizeof(stm32h7rs_flash_write_code), }, }; /* flash bank stm32x 0 0 */ -FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) +FLASH_BANK_COMMAND_HANDLER(stm32h7_flash_bank_command) { - struct stm32h7x_flash_bank *stm32x_info; + struct stm32h7_flash_bank *stm32h7_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; - stm32x_info = malloc(sizeof(struct stm32h7x_flash_bank)); - bank->driver_priv = stm32x_info; + stm32h7_info = malloc(sizeof(struct stm32h7_flash_bank)); + bank->driver_priv = stm32h7_info; - stm32x_info->probed = false; - stm32x_info->user_bank_size = bank->size; + stm32h7_info->probed = false; + stm32h7_info->user_bank_size = bank->size; return ERROR_OK; } -static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) +static inline uint32_t stm32h7_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) { - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; - return reg_offset + stm32x_info->flash_regs_base; + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; + return reg_offset + stm32h7_info->flash_regs_base; } -static inline int stm32x_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) +static int stm32h7_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) { - uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset); + uint32_t reg_addr = stm32h7_get_flash_reg(bank, reg_offset); int retval = target_read_u32(bank->target, reg_addr, value); if (retval != ERROR_OK) @@ -244,9 +344,16 @@ static inline int stm32x_read_flash_reg(struct flash_bank *bank, uint32_t reg_of return retval; } -static inline int stm32x_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) +static inline int stm32h7_read_flash_reg_by_index(struct flash_bank *bank, + enum stm32h7_flash_reg_index reg_index, uint32_t *value) { - uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset); + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; + return stm32h7_read_flash_reg(bank, stm32h7_info->flash_regs[reg_index], value); +} + +static int stm32h7_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) +{ + uint32_t reg_addr = stm32h7_get_flash_reg(bank, reg_offset); int retval = target_write_u32(bank->target, reg_addr, value); if (retval != ERROR_OK) @@ -255,19 +362,32 @@ static inline int stm32x_write_flash_reg(struct flash_bank *bank, uint32_t reg_o return retval; } -static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) +static inline int stm32h7_write_flash_reg_by_index(struct flash_bank *bank, + enum stm32h7_flash_reg_index reg_index, uint32_t value) +{ + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; + return stm32h7_write_flash_reg(bank, stm32h7_info->flash_regs[reg_index], value); +} + +static int stm32h7_get_flash_status(struct flash_bank *bank, uint32_t *status) +{ + return stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, status); +} + +static int stm32h7rs_get_flash_status(struct flash_bank *bank, uint32_t *status) { - return stm32x_read_flash_reg(bank, FLASH_SR, status); + return stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_ISR_INDEX, status); } -static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout) +static int stm32h7_wait_flash_op_queue(struct flash_bank *bank, int timeout) { uint32_t status; int retval; + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; /* wait for flash operations completion */ for (;;) { - retval = stm32x_get_flash_status(bank, &status); + retval = stm32h7_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; @@ -282,28 +402,28 @@ static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout) } if (status & FLASH_WRPERR) { - LOG_ERROR("wait_flash_op_queue, WRPERR detected"); + LOG_ERROR("wait_flash_op_queue, write protection error"); retval = ERROR_FAIL; } /* Clear error + EOP flags but report errors */ - if (status & FLASH_ERROR) { + if (status & stm32h7_info->part_info->flash_error) { if (retval == ERROR_OK) retval = ERROR_FAIL; /* If this operation fails, we ignore it and report the original retval */ - stm32x_write_flash_reg(bank, FLASH_CCR, status); + stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_ICR_CCR_INDEX, status); } return retval; } -static int stm32x_unlock_reg(struct flash_bank *bank) +static int stm32h7_unlock_reg(struct flash_bank *bank) { uint32_t ctrl; /* first check if not already unlocked * otherwise writing on FLASH_KEYR will fail */ - int retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl); + int retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl); if (retval != ERROR_OK) return retval; @@ -311,15 +431,15 @@ static int stm32x_unlock_reg(struct flash_bank *bank) return ERROR_OK; /* unlock flash registers for bank */ - retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY1); + retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY1); if (retval != ERROR_OK) return retval; - retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY2); + retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY2); if (retval != ERROR_OK) return retval; - retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl); + retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl); if (retval != ERROR_OK) return retval; @@ -330,11 +450,11 @@ static int stm32x_unlock_reg(struct flash_bank *bank) return ERROR_OK; } -static int stm32x_unlock_option_reg(struct flash_bank *bank) +static int stm32h7_unlock_option_reg(struct flash_bank *bank) { uint32_t ctrl; - int retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl); + int retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_OPTCR_INDEX, &ctrl); if (retval != ERROR_OK) return retval; @@ -342,15 +462,15 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank) return ERROR_OK; /* unlock option registers */ - retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY1); + retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY1); if (retval != ERROR_OK) return retval; - retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY2); + retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY2); if (retval != ERROR_OK) return retval; - retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl); + retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_OPTCR_INDEX, &ctrl); if (retval != ERROR_OK) return retval; @@ -362,37 +482,37 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank) return ERROR_OK; } -static inline int stm32x_lock_reg(struct flash_bank *bank) +static inline int stm32h7_lock_reg(struct flash_bank *bank) { - return stm32x_write_flash_reg(bank, FLASH_CR, FLASH_LOCK); + return stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK); } -static inline int stm32x_lock_option_reg(struct flash_bank *bank) +static inline int stm32h7_lock_option_reg(struct flash_bank *bank) { - return stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_LOCK); + return stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_OPTCR_INDEX, OPT_LOCK); } -static int stm32x_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) +static int stm32h7_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) { int retval, retval2; /* unlock option bytes for modification */ - retval = stm32x_unlock_option_reg(bank); + retval = stm32h7_unlock_option_reg(bank); if (retval != ERROR_OK) goto flash_options_lock; /* write option bytes */ - retval = stm32x_write_flash_reg(bank, reg_offset, value); + retval = stm32h7_write_flash_reg_by_index(bank, reg_offset, value); if (retval != ERROR_OK) goto flash_options_lock; /* Remove OPT error flag before programming */ - retval = stm32x_write_flash_reg(bank, FLASH_OPTCCR, OPT_CLR_OPTCHANGEERR); + retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_OPTCCR_INDEX, OPT_CLR_OPTCHANGEERR); if (retval != ERROR_OK) goto flash_options_lock; /* start programming cycle */ - retval = stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_START); + retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_OPTCR_INDEX, OPT_START); if (retval != ERROR_OK) goto flash_options_lock; @@ -400,9 +520,9 @@ static int stm32x_write_option(struct flash_bank *bank, uint32_t reg_offset, uin int timeout = FLASH_ERASE_TIMEOUT; uint32_t status; for (;;) { - retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_CUR, &status); + retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_OPTSR_CUR_INDEX, &status); if (retval != ERROR_OK) { - LOG_ERROR("stm32x_options_program: failed to read FLASH_OPTSR_CUR"); + LOG_ERROR("stm32h7_options_program: failed to read FLASH_OPTSR_CUR"); goto flash_options_lock; } if ((status & OPT_BSY) == 0) @@ -423,32 +543,32 @@ static int stm32x_write_option(struct flash_bank *bank, uint32_t reg_offset, uin } flash_options_lock: - retval2 = stm32x_lock_option_reg(bank); + retval2 = stm32h7_lock_option_reg(bank); if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash options"); return (retval == ERROR_OK) ? retval2 : retval; } -static int stm32x_modify_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask) +static int stm32h7_modify_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask) { uint32_t data; - int retval = stm32x_read_flash_reg(bank, reg_offset, &data); + int retval = stm32h7_read_flash_reg_by_index(bank, reg_offset, &data); if (retval != ERROR_OK) return retval; data = (data & ~mask) | (value & mask); - return stm32x_write_option(bank, reg_offset, data); + return stm32h7_write_option(bank, reg_offset, data); } -static int stm32x_protect_check(struct flash_bank *bank) +static int stm32h7_protect_check(struct flash_bank *bank) { uint32_t protection; /* read 'write protection' settings */ - int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection); + int retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_WPSN_CUR_INDEX, &protection); if (retval != ERROR_OK) { LOG_DEBUG("unable to read WPSN_CUR register"); return retval; @@ -460,10 +580,10 @@ static int stm32x_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int stm32x_erase(struct flash_bank *bank, unsigned int first, +static int stm32h7_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; int retval, retval2; assert(first < bank->num_sectors); @@ -472,7 +592,7 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, if (bank->target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - retval = stm32x_unlock_reg(bank); + retval = stm32h7_unlock_reg(bank); if (retval != ERROR_OK) goto flash_lock; @@ -488,19 +608,19 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, */ for (unsigned int i = first; i <= last; i++) { LOG_DEBUG("erase sector %u", i); - retval = stm32x_write_flash_reg(bank, FLASH_CR, - stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64, i)); + retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, + stm32h7_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64, i)); if (retval != ERROR_OK) { LOG_ERROR("Error erase sector %u", i); goto flash_lock; } - retval = stm32x_write_flash_reg(bank, FLASH_CR, - stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64 | FLASH_START, i)); + retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, + stm32h7_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64 | FLASH_START, i)); if (retval != ERROR_OK) { LOG_ERROR("Error erase sector %u", i); goto flash_lock; } - retval = stm32x_wait_flash_op_queue(bank, FLASH_ERASE_TIMEOUT); + retval = stm32h7_wait_flash_op_queue(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) { LOG_ERROR("erase time-out or operation error sector %u", i); @@ -509,18 +629,18 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, } flash_lock: - retval2 = stm32x_lock_reg(bank); + retval2 = stm32h7_lock_reg(bank); if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash"); return (retval == ERROR_OK) ? retval2 : retval; } -static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, +static int stm32h7_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; + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; uint32_t protection; if (target->state != TARGET_HALTED) { @@ -529,7 +649,7 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, } /* read 'write protection' settings */ - int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection); + int retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_WPSN_CUR_INDEX, &protection); if (retval != ERROR_OK) { LOG_DEBUG("unable to read WPSN_CUR register"); return retval; @@ -543,24 +663,24 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, } /* apply WRPSN mask */ - protection &= stm32x_info->part_info->wps_mask; + protection &= stm32h7_info->part_info->wps_mask; - LOG_DEBUG("stm32x_protect, option_bytes written WPSN 0x%" PRIx32, protection); + LOG_DEBUG("stm32h7_protect, option_bytes written WPSN 0x%" PRIx32, protection); /* apply new option value */ - return stm32x_write_option(bank, FLASH_WPSN_PRG, protection); + return stm32h7_write_option(bank, STM32_FLASH_WPSN_PRG_INDEX, protection); } -static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, +static int stm32h7_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; /* * If the size of the data part of the buffer is not a multiple of .block_size, we get * "corrupted fifo read" pointer in target_run_flash_async_algorithm() */ - uint32_t data_size = 512 * stm32x_info->part_info->block_size; + uint32_t data_size = 512 * stm32h7_info->part_info->block_size; uint32_t buffer_size = 8 + data_size; struct working_area *write_algorithm; struct working_area *source; @@ -569,24 +689,21 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - static const uint8_t stm32x_flash_write_code[] = { -#include "../../../contrib/loaders/flash/stm32/stm32h7x.inc" - }; - - if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), + if (target_alloc_working_area(target, stm32h7_info->part_info->write_code_size, &write_algorithm) != ERROR_OK) { 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(stm32x_flash_write_code), - stm32x_flash_write_code); + stm32h7_info->part_info->write_code_size, + stm32h7_info->part_info->write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } + /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { data_size /= 2; @@ -617,13 +734,13 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, 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, stm32x_info->part_info->block_size); - buf_set_u32(reg_params[5].value, 0, 32, stm32x_info->flash_regs_base); + buf_set_u32(reg_params[4].value, 0, 32, stm32h7_info->part_info->block_size); + buf_set_u32(reg_params[5].value, 0, 32, stm32h7_info->flash_regs_base); retval = target_run_flash_async_algorithm(target, buffer, count, - stm32x_info->part_info->block_size, + stm32h7_info->part_info->block_size, 0, NULL, ARRAY_SIZE(reg_params), reg_params, source->address, source->size, @@ -631,17 +748,17 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { - LOG_ERROR("error executing stm32h7x flash write algorithm"); + LOG_ERROR("error executing stm32h7 flash write algorithm"); uint32_t flash_sr = buf_get_u32(reg_params[0].value, 0, 32); if (flash_sr & FLASH_WRPERR) LOG_ERROR("flash memory write protected"); - if ((flash_sr & FLASH_ERROR) != 0) { - LOG_ERROR("flash write failed, FLASH_SR = 0x%08" PRIx32, flash_sr); + if ((flash_sr & stm32h7_info->part_info->flash_error) != 0) { + LOG_ERROR("flash write failed, status = 0x%08" PRIx32, flash_sr); /* Clear error + EOP flags but report errors */ - stm32x_write_flash_reg(bank, FLASH_CCR, flash_sr); + stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_ICR_CCR_INDEX, flash_sr); retval = ERROR_FAIL; } } @@ -658,11 +775,11 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } -static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, +static int stm32h7_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; uint32_t address = bank->base + offset; int retval, retval2; @@ -672,20 +789,20 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, } /* should be enforced via bank->write_start_alignment */ - assert(!(offset % stm32x_info->part_info->block_size)); + assert(!(offset % stm32h7_info->part_info->block_size)); /* should be enforced via bank->write_end_alignment */ - assert(!(count % stm32x_info->part_info->block_size)); + assert(!(count % stm32h7_info->part_info->block_size)); - retval = stm32x_unlock_reg(bank); + retval = stm32h7_unlock_reg(bank); if (retval != ERROR_OK) goto flash_lock; - uint32_t blocks_remaining = count / stm32x_info->part_info->block_size; + uint32_t blocks_remaining = count / stm32h7_info->part_info->block_size; /* multiple words (n * .block_size) to be programmed in block */ if (blocks_remaining) { - retval = stm32x_write_block(bank, buffer, offset, blocks_remaining); + retval = stm32h7_write_block(bank, buffer, offset, blocks_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), @@ -693,8 +810,8 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } } else { - buffer += blocks_remaining * stm32x_info->part_info->block_size; - address += blocks_remaining * stm32x_info->part_info->block_size; + buffer += blocks_remaining * stm32h7_info->part_info->block_size; + address += blocks_remaining * stm32h7_info->part_info->block_size; blocks_remaining = 0; } if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) @@ -711,33 +828,33 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, 4. Wait for flash operations completion */ while (blocks_remaining > 0) { - retval = stm32x_write_flash_reg(bank, FLASH_CR, - stm32x_info->part_info->compute_flash_cr(FLASH_PG | FLASH_PSIZE_64, 0)); + retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, + stm32h7_info->part_info->compute_flash_cr(FLASH_PG | FLASH_PSIZE_64, 0)); if (retval != ERROR_OK) goto flash_lock; - retval = target_write_buffer(target, address, stm32x_info->part_info->block_size, buffer); + retval = target_write_buffer(target, address, stm32h7_info->part_info->block_size, buffer); if (retval != ERROR_OK) goto flash_lock; - retval = stm32x_wait_flash_op_queue(bank, FLASH_WRITE_TIMEOUT); + retval = stm32h7_wait_flash_op_queue(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) goto flash_lock; - buffer += stm32x_info->part_info->block_size; - address += stm32x_info->part_info->block_size; + buffer += stm32h7_info->part_info->block_size; + address += stm32h7_info->part_info->block_size; blocks_remaining--; } flash_lock: - retval2 = stm32x_lock_reg(bank); + retval2 = stm32h7_lock_reg(bank); if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash"); return (retval == ERROR_OK) ? retval2 : retval; } -static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id) +static int stm32h7_read_id_code(struct flash_bank *bank, uint32_t *id) { /* read stm32 device id register */ int retval = target_read_u32(bank->target, DBGMCU_IDCODE_REGISTER, id); @@ -746,50 +863,55 @@ static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id) return ERROR_OK; } -static int stm32x_probe(struct flash_bank *bank) +static int stm32h7_probe(struct flash_bank *bank) { struct target *target = bank->target; - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; uint16_t flash_size_in_kb; uint32_t device_id; - stm32x_info->probed = false; - stm32x_info->part_info = NULL; + stm32h7_info->probed = false; + stm32h7_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); + int retval = stm32h7_read_id_code(bank, &stm32h7_info->idcode); if (retval != ERROR_OK) return retval; - LOG_DEBUG("device id = 0x%08" PRIx32, stm32x_info->idcode); + LOG_DEBUG("device id = 0x%08" PRIx32, stm32h7_info->idcode); - device_id = stm32x_info->idcode & 0xfff; + device_id = stm32h7_info->idcode & 0xfff; + if (device_id == DEVID_STM32H7R_H7SXX) { + stm32h7_info->flash_regs = stm32h7rs_flash_regs; + } else { + stm32h7_info->flash_regs = stm32h7_flash_regs; + } - for (unsigned int n = 0; n < ARRAY_SIZE(stm32h7x_parts); n++) { - if (device_id == stm32h7x_parts[n].id) - stm32x_info->part_info = &stm32h7x_parts[n]; + for (unsigned int n = 0; n < ARRAY_SIZE(stm32h7_parts); n++) { + if (device_id == stm32h7_parts[n].id) + stm32h7_info->part_info = &stm32h7_parts[n]; } - if (!stm32x_info->part_info) { + if (!stm32h7_info->part_info) { LOG_WARNING("Cannot identify target as a STM32H7xx family."); return ERROR_FAIL; } else { - LOG_INFO("Device: %s", stm32x_info->part_info->device_str); + LOG_INFO("Device: %s", stm32h7_info->part_info->device_str); } /* update the address of controller */ if (bank->base == FLASH_BANK0_ADDRESS) - stm32x_info->flash_regs_base = FLASH_REG_BASE_B0; + stm32h7_info->flash_regs_base = FLASH_REG_BASE_B0; else if (bank->base == FLASH_BANK1_ADDRESS) - stm32x_info->flash_regs_base = FLASH_REG_BASE_B1; + stm32h7_info->flash_regs_base = FLASH_REG_BASE_B1; else { LOG_WARNING("Flash register base not defined for bank %u", bank->bank_number); return ERROR_FAIL; } - LOG_DEBUG("flash_regs_base: 0x%" PRIx32, stm32x_info->flash_regs_base); + LOG_DEBUG("flash_regs_base: 0x%" PRIx32, stm32h7_info->flash_regs_base); /* get flash size from target */ /* STM32H74x/H75x, the second core (Cortex-M4) cannot read the flash size */ @@ -798,19 +920,19 @@ static int stm32x_probe(struct flash_bank *bank) && 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); + retval = target_read_u16(target, stm32h7_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; + flash_size_in_kb = stm32h7_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 "k", flash_size_in_kb); /* setup bank size */ const uint32_t bank1_base = FLASH_BANK0_ADDRESS; - const uint32_t bank2_base = bank1_base + stm32x_info->part_info->max_bank_size_kb * 1024; - bool has_dual_bank = stm32x_info->part_info->has_dual_bank; + const uint32_t bank2_base = bank1_base + stm32h7_info->part_info->max_bank_size_kb * 1024; + bool has_dual_bank = stm32h7_info->part_info->has_dual_bank; switch (device_id) { case DEVID_STM32H74_H75XX: @@ -828,6 +950,7 @@ static int stm32x_probe(struct flash_bank *bank) flash_size_in_kb /= 2; break; case DEVID_STM32H72_H73XX: + case DEVID_STM32H7R_H7SXX: break; default: LOG_ERROR("unsupported device"); @@ -860,27 +983,27 @@ static int stm32x_probe(struct flash_bank *bank) /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have an invalid flash size register value */ - if (stm32x_info->user_bank_size) { + if (stm32h7_info->user_bank_size) { LOG_INFO("ignoring flash probed value, using configured bank size"); - flash_size_in_kb = stm32x_info->user_bank_size / 1024; + flash_size_in_kb = stm32h7_info->user_bank_size / 1024; } else if (flash_size_in_kb == 0xffff) { /* die flash size */ - flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb; + flash_size_in_kb = stm32h7_info->part_info->max_flash_size_kb; } /* did we assign flash size? */ assert(flash_size_in_kb != 0xffff); bank->size = flash_size_in_kb * 1024; - bank->write_start_alignment = stm32x_info->part_info->block_size; - bank->write_end_alignment = stm32x_info->part_info->block_size; + bank->write_start_alignment = stm32h7_info->part_info->block_size; + bank->write_end_alignment = stm32h7_info->part_info->block_size; /* setup sectors */ - bank->num_sectors = flash_size_in_kb / stm32x_info->part_info->page_size_kb; + bank->num_sectors = flash_size_in_kb / stm32h7_info->part_info->page_size_kb; assert(bank->num_sectors > 0); free(bank->sectors); - bank->sectors = alloc_block_array(0, stm32x_info->part_info->page_size_kb * 1024, + bank->sectors = alloc_block_array(0, stm32h7_info->part_info->page_size_kb * 1024, bank->num_sectors); if (!bank->sectors) { @@ -889,7 +1012,7 @@ static int stm32x_probe(struct flash_bank *bank) } /* setup protection blocks */ - const uint32_t wpsn = stm32x_info->part_info->wps_group_size; + const uint32_t wpsn = stm32h7_info->part_info->wps_group_size; assert(bank->num_sectors % wpsn == 0); bank->num_prot_blocks = bank->num_sectors / wpsn; @@ -897,7 +1020,7 @@ static int stm32x_probe(struct flash_bank *bank) free(bank->prot_blocks); - bank->prot_blocks = alloc_block_array(0, stm32x_info->part_info->page_size_kb * wpsn * 1024, + bank->prot_blocks = alloc_block_array(0, stm32h7_info->part_info->page_size_kb * wpsn * 1024, bank->num_prot_blocks); if (!bank->prot_blocks) { @@ -905,28 +1028,28 @@ static int stm32x_probe(struct flash_bank *bank) return ERROR_FAIL; } - stm32x_info->probed = true; + stm32h7_info->probed = true; return ERROR_OK; } -static int stm32x_auto_probe(struct flash_bank *bank) +static int stm32h7_auto_probe(struct flash_bank *bank) { - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; - if (stm32x_info->probed) + if (stm32h7_info->probed) return ERROR_OK; - return stm32x_probe(bank); + return stm32h7_probe(bank); } /* This method must return a string displaying information about the bank */ -static int stm32x_get_info(struct flash_bank *bank, struct command_invocation *cmd) +static int stm32h7_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; + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; + const struct stm32h7_part_info *info = stm32h7_info->part_info; - if (!stm32x_info->probed) { - int retval = stm32x_probe(bank); + if (!stm32h7_info->probed) { + int retval = stm32h7_probe(bank); if (retval != ERROR_OK) { command_print_sameline(cmd, "Unable to find bank information."); return retval; @@ -935,7 +1058,7 @@ static int stm32x_get_info(struct flash_bank *bank, struct command_invocation *c if (info) { const char *rev_str = NULL; - uint16_t rev_id = stm32x_info->idcode >> 16; + uint16_t rev_id = stm32h7_info->idcode >> 16; for (unsigned int i = 0; i < info->num_revs; i++) if (rev_id == info->revs[i].rev) @@ -943,11 +1066,11 @@ static int stm32x_get_info(struct flash_bank *bank, struct command_invocation *c if (rev_str) { command_print_sameline(cmd, "%s - Rev: %s", - stm32x_info->part_info->device_str, rev_str); + stm32h7_info->part_info->device_str, rev_str); } else { command_print_sameline(cmd, "%s - Rev: unknown (0x%04" PRIx16 ")", - stm32x_info->part_info->device_str, rev_id); + stm32h7_info->part_info->device_str, rev_id); } } else { command_print_sameline(cmd, "Cannot identify target as a STM32H7x"); @@ -956,7 +1079,7 @@ static int stm32x_get_info(struct flash_bank *bank, struct command_invocation *c return ERROR_OK; } -static int stm32x_set_rdp(struct flash_bank *bank, enum stm32h7x_opt_rdp new_rdp) +static int stm32h7_set_rdp(struct flash_bank *bank, enum stm32h7_opt_rdp new_rdp) { struct target *target = bank->target; uint32_t optsr, cur_rdp; @@ -967,7 +1090,7 @@ static int stm32x_set_rdp(struct flash_bank *bank, enum stm32h7x_opt_rdp new_rdp return ERROR_TARGET_NOT_HALTED; } - retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_PRG, &optsr); + retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_OPTSR_PRG_INDEX, &optsr); if (retval != ERROR_OK) { LOG_DEBUG("unable to read FLASH_OPTSR_PRG register"); @@ -997,10 +1120,10 @@ static int stm32x_set_rdp(struct flash_bank *bank, enum stm32h7x_opt_rdp new_rdp optsr = (optsr & ~OPT_RDP_MASK) | (new_rdp << OPT_RDP_POS); /* apply new option value */ - return stm32x_write_option(bank, FLASH_OPTSR_PRG, optsr); + return stm32h7_write_option(bank, STM32_FLASH_OPTSR_PRG_INDEX, optsr); } -COMMAND_HANDLER(stm32x_handle_lock_command) +COMMAND_HANDLER(stm32h7_handle_lock_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -1010,7 +1133,7 @@ COMMAND_HANDLER(stm32x_handle_lock_command) if (retval != ERROR_OK) return retval; - retval = stm32x_set_rdp(bank, OPT_RDP_L1); + retval = stm32h7_set_rdp(bank, OPT_RDP_L1); if (retval != ERROR_OK) command_print(CMD, "%s failed to lock device", bank->driver->name); @@ -1020,7 +1143,7 @@ COMMAND_HANDLER(stm32x_handle_lock_command) return retval; } -COMMAND_HANDLER(stm32x_handle_unlock_command) +COMMAND_HANDLER(stm32h7_handle_unlock_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -1030,7 +1153,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) if (retval != ERROR_OK) return retval; - retval = stm32x_set_rdp(bank, OPT_RDP_L0); + retval = stm32h7_set_rdp(bank, OPT_RDP_L0); if (retval != ERROR_OK) command_print(CMD, "%s failed to unlock device", bank->driver->name); @@ -1040,45 +1163,45 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) return retval; } -static int stm32x_mass_erase(struct flash_bank *bank) +static int stm32h7_mass_erase(struct flash_bank *bank) { int retval, retval2; struct target *target = bank->target; - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - retval = stm32x_unlock_reg(bank); + retval = stm32h7_unlock_reg(bank); if (retval != ERROR_OK) goto flash_lock; /* mass erase flash memory bank */ - retval = stm32x_write_flash_reg(bank, FLASH_CR, - stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64, 0)); + retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, + stm32h7_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64, 0)); if (retval != ERROR_OK) goto flash_lock; - retval = stm32x_write_flash_reg(bank, FLASH_CR, - stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64 | FLASH_START, 0)); + retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, + stm32h7_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64 | FLASH_START, 0)); if (retval != ERROR_OK) goto flash_lock; - retval = stm32x_wait_flash_op_queue(bank, 30000); + retval = stm32h7_wait_flash_op_queue(bank, MASS_ERASE_TIMEOUT); if (retval != ERROR_OK) goto flash_lock; flash_lock: - retval2 = stm32x_lock_reg(bank); + retval2 = stm32h7_lock_reg(bank); if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash"); return (retval == ERROR_OK) ? retval2 : retval; } -COMMAND_HANDLER(stm32x_handle_mass_erase_command) +COMMAND_HANDLER(stm32h7_handle_mass_erase_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -1088,7 +1211,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) if (retval != ERROR_OK) return retval; - retval = stm32x_mass_erase(bank); + retval = stm32h7_mass_erase(bank); if (retval == ERROR_OK) command_print(CMD, "stm32h7x mass erase complete"); else @@ -1097,7 +1220,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) return retval; } -COMMAND_HANDLER(stm32x_handle_option_read_command) +COMMAND_HANDLER(stm32h7_handle_option_read_command) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; @@ -1110,17 +1233,16 @@ COMMAND_HANDLER(stm32x_handle_option_read_command) uint32_t reg_offset, value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); - retval = stm32x_read_flash_reg(bank, reg_offset, &value); + retval = stm32h7_read_flash_reg_by_index(bank, reg_offset, &value); if (retval != ERROR_OK) return retval; - command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32, - stm32x_get_flash_reg(bank, reg_offset), value); + command_print(CMD, "0x%" PRIx32, value); - return retval; + return ERROR_OK; } -COMMAND_HANDLER(stm32x_handle_option_write_command) +COMMAND_HANDLER(stm32h7_handle_option_write_command) { if (CMD_ARGC != 3 && CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; @@ -1137,41 +1259,41 @@ COMMAND_HANDLER(stm32x_handle_option_write_command) if (CMD_ARGC > 3) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], mask); - return stm32x_modify_option(bank, reg_offset, value, mask); + return stm32h7_modify_option(bank, reg_offset, value, mask); } -static const struct command_registration stm32h7x_exec_command_handlers[] = { +static const struct command_registration stm32h7_exec_command_handlers[] = { { .name = "lock", - .handler = stm32x_handle_lock_command, + .handler = stm32h7_handle_lock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Lock entire flash device.", }, { .name = "unlock", - .handler = stm32x_handle_unlock_command, + .handler = stm32h7_handle_unlock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Unlock entire protected flash device.", }, { .name = "mass_erase", - .handler = stm32x_handle_mass_erase_command, + .handler = stm32h7_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase entire flash device.", }, { .name = "option_read", - .handler = stm32x_handle_option_read_command, + .handler = stm32h7_handle_option_read_command, .mode = COMMAND_EXEC, .usage = "bank_id reg_offset", .help = "Read and display device option bytes.", }, { .name = "option_write", - .handler = stm32x_handle_option_write_command, + .handler = stm32h7_handle_option_write_command, .mode = COMMAND_EXEC, .usage = "bank_id reg_offset value [mask]", .help = "Write device option bit fields with provided value.", @@ -1179,29 +1301,29 @@ static const struct command_registration stm32h7x_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const struct command_registration stm32h7x_command_handlers[] = { +static const struct command_registration stm32h7_command_handlers[] = { { .name = "stm32h7x", .mode = COMMAND_ANY, .help = "stm32h7x flash command group", .usage = "", - .chain = stm32h7x_exec_command_handlers, + .chain = stm32h7_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; const struct flash_driver stm32h7x_flash = { .name = "stm32h7x", - .commands = stm32h7x_command_handlers, - .flash_bank_command = stm32x_flash_bank_command, - .erase = stm32x_erase, - .protect = stm32x_protect, - .write = stm32x_write, + .commands = stm32h7_command_handlers, + .flash_bank_command = stm32h7_flash_bank_command, + .erase = stm32h7_erase, + .protect = stm32h7_protect, + .write = stm32h7_write, .read = default_flash_read, - .probe = stm32x_probe, - .auto_probe = stm32x_auto_probe, + .probe = stm32h7_probe, + .auto_probe = stm32h7_auto_probe, .erase_check = default_flash_blank_check, - .protect_check = stm32x_protect_check, - .info = stm32x_get_info, + .protect_check = stm32h7_protect_check, + .info = stm32h7_get_info, .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index f16333201b..34676659b2 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -152,6 +152,9 @@ /* 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) +/* the registers WRPxyR have UNLOCK bit - writing zero locks the write + * protection region permanently! */ +#define F_WRP_HAS_LOCK BIT(5) /* end of STM32L4 flags ******************************************************/ @@ -284,12 +287,16 @@ struct stm32l4_wrp { }; /* human readable list of families this drivers supports (sorted alphabetically) */ -static const char *device_families = "STM32C0/G0/G4/L4/L4+/L5/U0/U5/WB/WL"; +static const char *device_families = "STM32C0/G0/G4/L4/L4+/L5/U0/U3/U5/WB/WBA/WL"; static const struct stm32l4_rev stm32l47_l48xx_revs[] = { { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" } }; +static const struct stm32l4_rev stm32u3b_u3cxx_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, +}; + static const struct stm32l4_rev stm32l43_l44xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; @@ -347,6 +354,10 @@ static const struct stm32l4_rev stm32u0xx_revs[] = { { 0x1000, "A" }, }; +static const struct stm32l4_rev stm32u37_u38xx_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, +}; + static const struct stm32l4_rev stm32g43_g44xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; @@ -393,6 +404,14 @@ static const struct stm32l4_rev stm32wba5x_revs[] = { { 0x1000, "A" }, }; +static const struct stm32l4_rev stm32wba6x_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, +}; + +static const struct stm32l4_rev stm32wba2x_revs[] = { + { 0x1000, "A" }, +}; + static const struct stm32l4_rev stm32wb1xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, }; @@ -422,6 +441,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_base = 0x1FFF7000, .otp_size = 1024, }, + { + .id = DEVID_STM32U3B_U3CXX, + .revs = stm32u3b_u3cxx_revs, + .num_revs = ARRAY_SIZE(stm32u3b_u3cxx_revs), + .device_str = "STM32U3B/U3Cxx", + .max_flash_size_kb = 2048, + .flags = F_HAS_DUAL_BANK | F_HAS_TZ | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BFA07A0, + .otp_base = 0x0BFA0000, + .otp_size = 512, + }, { .id = DEVID_STM32L43_L44XX, .revs = stm32l43_l44xx_revs, @@ -500,7 +531,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32u53_u54xx_revs), .device_str = "STM32U535/U545", .max_flash_size_kb = 512, - .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ + | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, .flash_regs_base = 0x40022000, .fsize_addr = 0x0BFA07A0, .otp_base = 0x0BFA0000, @@ -686,13 +718,26 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_base = 0x1FFF6800, .otp_size = 1024, }, + { + .id = DEVID_STM32U37_U38XX, + .revs = stm32u37_u38xx_revs, + .num_revs = ARRAY_SIZE(stm32u37_u38xx_revs), + .device_str = "STM32U37/U38xx", + .max_flash_size_kb = 1024, + .flags = F_HAS_DUAL_BANK | F_HAS_TZ | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BFA07A0, + .otp_base = 0x0BFA0000, + .otp_size = 512, + }, { .id = DEVID_STM32U59_U5AXX, .revs = stm32u59_u5axx_revs, .num_revs = ARRAY_SIZE(stm32u59_u5axx_revs), .device_str = "STM32U59/U5Axx", .max_flash_size_kb = 4096, - .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ + | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, .flash_regs_base = 0x40022000, .fsize_addr = 0x0BFA07A0, .otp_base = 0x0BFA0000, @@ -704,7 +749,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .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, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ + | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, .flash_regs_base = 0x40022000, .fsize_addr = 0x0BFA07A0, .otp_base = 0x0BFA0000, @@ -716,7 +762,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32u5f_u5gxx_revs), .device_str = "STM32U5F/U5Gxx", .max_flash_size_kb = 4096, - .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ + | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, .flash_regs_base = 0x40022000, .fsize_addr = 0x0BFA07A0, .otp_base = 0x0BFA0000, @@ -728,10 +775,36 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .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, + .flags = F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS + | F_WRP_HAS_LOCK, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BF907A0, + .otp_base = 0x0BF90000, + .otp_size = 512, + }, + { + .id = DEVID_STM32WBA6X, + .revs = stm32wba6x_revs, + .num_revs = ARRAY_SIZE(stm32wba6x_revs), + .device_str = "STM32WBA6x", + .max_flash_size_kb = 2048, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ + | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, .flash_regs_base = 0x40022000, - .fsize_addr = 0x0FF907A0, - .otp_base = 0x0FF90000, + .fsize_addr = 0x0BFA07A0, + .otp_base = 0x0BFA0000, + .otp_size = 512, + }, + { + .id = DEVID_STM32WBA2X, + .revs = stm32wba2x_revs, + .num_revs = ARRAY_SIZE(stm32wba2x_revs), + .device_str = "STM32WBA2x", + .max_flash_size_kb = 512, + .flags = F_HAS_TZ | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BF8D7A0, + .otp_base = 0x0BF8D000, .otp_size = 512, }, { @@ -974,7 +1047,7 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) 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); + LOG_DEBUG("status: 0x%" PRIx32, status); if ((status & stm32l4_info->sr_bsy_mask) == 0) break; if (timeout-- <= 0) { @@ -1287,6 +1360,8 @@ static int stm32l4_write_one_wrpxy(struct flash_bank *bank, struct stm32l4_wrp * int wrp_end = wrpxy->last - wrpxy->offset; uint32_t wrp_value = (wrp_start & stm32l4_info->wrpxxr_mask) | ((wrp_end & stm32l4_info->wrpxxr_mask) << 16); + if (stm32l4_info->part_info->flags & F_WRP_HAS_LOCK) + wrp_value |= FLASH_WRPXYR_UNLOCK; return stm32l4_write_option(bank, stm32l4_info->flash_regs[wrpxy->reg_idx], wrp_value, 0xffffffff); } @@ -1371,6 +1446,10 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first, 4. Wait for the BSY bit to be cleared */ + retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + if (retval != ERROR_OK) + goto err_lock; + for (unsigned int i = first; i <= last; i++) { uint32_t erase_flags; erase_flags = FLASH_PER | FLASH_STRT; @@ -1776,6 +1855,9 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) goto err_lock; + retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + goto err_lock; /* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5, * the debug is possible only in non-secure state. @@ -1818,7 +1900,7 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) 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}; + uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_L5, DBGMCU_IDCODE_G0}; for (unsigned int i = 0; i < ARRAY_SIZE(dbgmcu_idcode); i++) { retval = target_read_u32(target, dbgmcu_idcode[i], id); @@ -2142,6 +2224,16 @@ static int stm32l4_probe(struct flash_bank *bank) stm32l4_info->bank1_sectors = num_pages / 2; } break; + case DEVID_STM32U3B_U3CXX: + case DEVID_STM32U37_U38XX: + page_size_kb = 4; + 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_STM32U53_U54XX: case DEVID_STM32U57_U58XX: case DEVID_STM32U59_U5AXX: @@ -2168,13 +2260,25 @@ static int stm32l4_probe(struct flash_bank *bank) } break; case DEVID_STM32WBA5X: - /* single bank flash */ + case DEVID_STM32WBA6X: + /* according to RM0493 Rev 7, Chapter 7.3.1 + * WBA5xx have 8K page size and are always + * single bank. + * According to RM0515 Rev 4, Chapter 7.3.1 + * WBA6xx have 8K page size and are always + * DUAL BANK + */ page_size_kb = 8; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; + if (stm32l4_info->optr & FLASH_U5_DUALBANK) { + stm32l4_info->dual_bank_mode = true; + stm32l4_info->bank1_sectors = num_pages / 2; + } break; case DEVID_STM32WB5XX: case DEVID_STM32WB3XX: + case DEVID_STM32WBA2X: /* single bank flash */ page_size_kb = 4; num_pages = flash_size_kb / page_size_kb; @@ -2400,19 +2504,18 @@ COMMAND_HANDLER(stm32l4_handle_option_read_command) if (retval != ERROR_OK) return retval; - uint32_t reg_offset, reg_addr; + uint32_t reg_offset; uint32_t value = 0; 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 (retval != ERROR_OK) return retval; - command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "", reg_addr, value); + command_print(CMD, "0x%" PRIx32, value); - return retval; + return ERROR_OK; } COMMAND_HANDLER(stm32l4_handle_option_write_command) @@ -2439,8 +2542,7 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command) "INFO: a reset or power cycle is required " "for the new settings to take effect.", bank->driver->name); - retval = stm32l4_write_option(bank, reg_offset, value, mask); - return retval; + return stm32l4_write_option(bank, reg_offset, value, mask); } COMMAND_HANDLER(stm32l4_handle_trustzone_command) diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h index 07b3615a24..7ee62d6636 100644 --- a/src/flash/nor/stm32l4x.h +++ b/src/flash/nor/stm32l4x.h @@ -69,6 +69,9 @@ #define FLASH_U5_DUALBANK BIT(21) #define FLASH_TZEN BIT(31) +/* FLASH_WRPxyR register bits */ +#define FLASH_WRPXYR_UNLOCK 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)) @@ -86,11 +89,13 @@ /* Supported device IDs */ #define DEVID_STM32L47_L48XX 0x415 +#define DEVID_STM32U3B_U3CXX 0x42A #define DEVID_STM32L43_L44XX 0x435 #define DEVID_STM32C01XX 0x443 #define DEVID_STM32C05XX 0x44C #define DEVID_STM32C09XX 0x44D #define DEVID_STM32C03XX 0x453 +#define DEVID_STM32U37_U38XX 0x454 #define DEVID_STM32U53_U54XX 0x455 #define DEVID_STM32G05_G06XX 0x456 #define DEVID_STM32U031XX 0x459 @@ -116,6 +121,8 @@ #define DEVID_STM32WB5XX 0x495 #define DEVID_STM32WB3XX 0x496 #define DEVID_STM32WLE_WL5XX 0x497 +#define DEVID_STM32WBA6X 0x4B0 +#define DEVID_STM32WBA2X 0x4B2 /* known Flash base addresses */ #define STM32_FLASH_BANK_BASE 0x08000000 diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index 1459e942d1..2e949c5dba 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -90,6 +90,7 @@ static int stm32lx_lock_program_memory(struct flash_bank *bank); static int stm32lx_enable_write_half_page(struct flash_bank *bank); static int stm32lx_erase_sector(struct flash_bank *bank, int sector); static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank); +static int stm32lx_obl_launch(struct flash_bank *bank); static int stm32lx_lock(struct flash_bank *bank); static int stm32lx_unlock(struct flash_bank *bank); static int stm32lx_mass_erase(struct flash_bank *bank); @@ -354,6 +355,26 @@ COMMAND_HANDLER(stm32lx_handle_unlock_command) return retval; } +COMMAND_HANDLER(stm32lx_handle_option_load_command) +{ + 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 (retval != ERROR_OK) + return retval; + + retval = stm32lx_obl_launch(bank); + if (retval != ERROR_OK) { + command_print(CMD, "failed to load option bytes"); + return retval; + } + + return ERROR_OK; +} + static int stm32lx_protect_check(struct flash_bank *bank) { int retval; @@ -745,7 +766,7 @@ static int stm32lx_probe(struct flash_bank *bank) stm32lx_info->idcode = device_id; - LOG_DEBUG("device id = 0x%08" PRIx32 "", device_id); + LOG_DEBUG("device id = 0x%08" PRIx32, device_id); for (n = 0; n < ARRAY_SIZE(stm32lx_parts); n++) { if ((device_id & 0xfff) == stm32lx_parts[n].id) { @@ -921,6 +942,13 @@ static const struct command_registration stm32lx_exec_command_handlers[] = { .usage = "bank_id", .help = "Lower the readout protection from Level 1 to 0.", }, + { + .name = "option_load", + .handler = stm32lx_handle_option_load_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Force re-load of device options (will cause device reset).", + }, COMMAND_REGISTRATION_DONE }; @@ -1048,10 +1076,8 @@ static int stm32lx_enable_write_half_page(struct flash_bank *bank) return retval; reg32 |= FLASH_PECR__PROG; - retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, + return target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, reg32); - - return retval; } static int stm32lx_lock_program_memory(struct flash_bank *bank) @@ -1204,7 +1230,7 @@ static int stm32lx_wait_until_bsy_clear_timeout(struct flash_bank *bank, int tim if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32, status); if ((status & FLASH_SR__BSY) == 0) break; @@ -1238,7 +1264,10 @@ static int stm32lx_obl_launch(struct flash_bank *bank) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; - int retval; + + int retval = stm32lx_unlock_options_bytes(bank); + if (retval != ERROR_OK) + return retval; /* This will fail as the target gets immediately rebooted */ target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c index df58f6c55d..174643b7e6 100644 --- a/src/flash/nor/stmqspi.c +++ b/src/flash/nor/stmqspi.c @@ -1800,9 +1800,7 @@ static int find_sfdp_dummy(struct flash_bank *bank, int len) err: /* Abort operation */ - retval = stmqspi_abort(bank); - - return retval; + return stmqspi_abort(bank); } /* Read SFDP parameter block */ @@ -1978,24 +1976,24 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) /* 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; + 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) diff --git a/src/flash/nor/stmsmi.c b/src/flash/nor/stmsmi.c index 1aa244728f..85f3580788 100644 --- a/src/flash/nor/stmsmi.c +++ b/src/flash/nor/stmsmi.c @@ -531,21 +531,21 @@ static int stmsmi_probe(struct flash_bank *bank) } switch (bank->base - target_device->smi_base) { - case 0: - stmsmi_info->bank_num = SMI_SEL_BANK0; - break; - case SMI_BANK_SIZE: - stmsmi_info->bank_num = SMI_SEL_BANK1; - break; - case 2*SMI_BANK_SIZE: - stmsmi_info->bank_num = SMI_SEL_BANK2; - break; - case 3*SMI_BANK_SIZE: - stmsmi_info->bank_num = SMI_SEL_BANK3; - break; - default: - LOG_ERROR("Invalid SMI base address " TARGET_ADDR_FMT, bank->base); - return ERROR_FAIL; + case 0: + stmsmi_info->bank_num = SMI_SEL_BANK0; + break; + case SMI_BANK_SIZE: + stmsmi_info->bank_num = SMI_SEL_BANK1; + break; + case 2 * SMI_BANK_SIZE: + stmsmi_info->bank_num = SMI_SEL_BANK2; + break; + case 3 * SMI_BANK_SIZE: + stmsmi_info->bank_num = SMI_SEL_BANK3; + break; + default: + LOG_ERROR("Invalid SMI base address " TARGET_ADDR_FMT, bank->base); + return ERROR_FAIL; } io_base = target_device->io_base; stmsmi_info->io_base = io_base; diff --git a/src/flash/nor/str7x.c b/src/flash/nor/str7x.c index b91e22e044..e84721333b 100644 --- a/src/flash/nor/str7x.c +++ b/src/flash/nor/str7x.c @@ -131,21 +131,21 @@ static int str7x_build_block_list(struct flash_bank *bank) int b0_sectors = 0, b1_sectors = 0; switch (bank->size) { - case 16 * 1024: - b1_sectors = 2; - break; - case 64 * 1024: - b0_sectors = 5; - break; - case 128 * 1024: - b0_sectors = 6; - break; - case 256 * 1024: - b0_sectors = 8; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 16 * 1024: + b1_sectors = 2; + break; + case 64 * 1024: + b0_sectors = 5; + break; + case 128 * 1024: + b0_sectors = 6; + break; + case 256 * 1024: + b0_sectors = 8; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } num_sectors = b0_sectors + b1_sectors; @@ -335,7 +335,7 @@ static int str7x_erase(struct flash_bank *bank, unsigned int first, for (unsigned int i = first; i <= last; i++) sectors |= str7x_info->sector_bits[i]; - LOG_DEBUG("sectors: 0x%" PRIx32 "", sectors); + LOG_DEBUG("sectors: 0x%" PRIx32, sectors); /* clear FLASH_ER register */ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0); @@ -736,7 +736,7 @@ COMMAND_HANDLER(str7x_handle_disable_jtag_command) target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), ®); protection_regs = ~(reg >> 16); - while (((protection_regs) != 0) && (protection_level < 16)) { + while ((protection_regs != 0) && (protection_level < 16)) { protection_regs >>= 1; protection_level++; } @@ -753,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 + protection_level))); + ~(1U << (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 1a26b839e9..9efac241a0 100644 --- a/src/flash/nor/str9x.c +++ b/src/flash/nor/str9x.c @@ -66,36 +66,36 @@ static int str9x_build_block_list(struct flash_bank *bank) str9x_info->bank1 = 0; switch (bank->size) { - case (256 * 1024): - b0_sectors = 4; - break; - case (512 * 1024): - b0_sectors = 8; - break; - case (1024 * 1024): - bank1start = 0x00100000; - str9x_info->variant = 1; - b0_sectors = 16; - break; - case (2048 * 1024): - bank1start = 0x00200000; - str9x_info->variant = 1; - b0_sectors = 32; - break; - case (128 * 1024): - str9x_info->variant = 1; - str9x_info->bank1 = 1; - b1_sectors = 8; - bank1start = bank->base; - break; - case (32 * 1024): - str9x_info->bank1 = 1; - b1_sectors = 4; - bank1start = bank->base; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case (256 * 1024): + b0_sectors = 4; + break; + case (512 * 1024): + b0_sectors = 8; + break; + case (1024 * 1024): + bank1start = 0x00100000; + str9x_info->variant = 1; + b0_sectors = 16; + break; + case (2048 * 1024): + bank1start = 0x00200000; + str9x_info->variant = 1; + b0_sectors = 32; + break; + case (128 * 1024): + str9x_info->variant = 1; + str9x_info->bank1 = 1; + b1_sectors = 8; + bank1start = bank->base; + break; + case (32 * 1024): + str9x_info->bank1 = 1; + b1_sectors = 4; + bank1start = bank->base; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } num_sectors = b0_sectors + b1_sectors; diff --git a/src/flash/nor/str9xpec.c b/src/flash/nor/str9xpec.c index eff7df5a11..b7156a1ae2 100644 --- a/src/flash/nor/str9xpec.c +++ b/src/flash/nor/str9xpec.c @@ -171,7 +171,6 @@ static int str9xpec_isc_disable(struct flash_bank *bank) static int str9xpec_read_config(struct flash_bank *bank) { struct scan_field field; - uint8_t status; struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; @@ -190,9 +189,7 @@ static int str9xpec_read_config(struct flash_bank *bank) jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); - status = str9xpec_isc_status(tap); - - return status; + return str9xpec_isc_status(tap); } static int str9xpec_build_block_list(struct flash_bank *bank) @@ -206,28 +203,28 @@ static int str9xpec_build_block_list(struct flash_bank *bank) int b1_size = 0x2000; switch (bank->size) { - case (256 * 1024): - b0_sectors = 4; - break; - case (512 * 1024): - b0_sectors = 8; - break; - case (1024 * 1024): - b0_sectors = 16; - break; - case (2048 * 1024): - b0_sectors = 32; - break; - case (128 * 1024): - b1_size = 0x4000; - b1_sectors = 8; - break; - case (32 * 1024): - b1_sectors = 4; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case (256 * 1024): + b0_sectors = 4; + break; + case (512 * 1024): + b0_sectors = 8; + break; + case (1024 * 1024): + b0_sectors = 16; + break; + case (2048 * 1024): + b0_sectors = 32; + break; + case (128 * 1024): + b1_size = 0x4000; + b1_sectors = 8; + break; + case (32 * 1024): + b1_sectors = 4; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } num_sectors = b0_sectors + b1_sectors; @@ -487,11 +484,7 @@ static int str9xpec_lock_device(struct flash_bank *bank) static int str9xpec_unlock_device(struct flash_bank *bank) { - uint8_t status; - - status = str9xpec_erase_area(bank, 0, 255); - - return status; + return str9xpec_erase_area(bank, 0, 255); } static int str9xpec_protect(struct flash_bank *bank, int set, @@ -735,7 +728,7 @@ COMMAND_HANDLER(str9xpec_handle_part_id_command) idcode = buf_get_u32(buffer, 0, 32); - command_print(CMD, "str9xpec part id: 0x%8.8" PRIx32 "", idcode); + command_print(CMD, "str9xpec part id: 0x%8.8" PRIx32, idcode); free(buffer); diff --git a/src/flash/nor/swm050.c b/src/flash/nor/swm050.c index dcf59d380e..880c44e198 100644 --- a/src/flash/nor/swm050.c +++ b/src/flash/nor/swm050.c @@ -67,8 +67,7 @@ static int swm050_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); - retval = ERROR_TARGET_NOT_HALTED; - return retval; + return ERROR_TARGET_NOT_HALTED; } /* Perform write */ diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index a19b1a6833..57e53dca1e 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -192,7 +192,7 @@ COMMAND_HANDLER(handle_flash_erase_check_command) command_print(CMD, "successfully checked erase state"); else { command_print(CMD, - "unknown error when checking erase state of flash bank #%s at " + "Error: checking erase state of flash bank #%s at " TARGET_ADDR_FMT, CMD_ARGV[0], p->base); @@ -275,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 ((retval == ERROR_OK) && (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)); @@ -323,7 +323,7 @@ COMMAND_HANDLER(handle_flash_erase_command) retval = flash_driver_erase(p, first, last); - if ((retval == ERROR_OK) && (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)); @@ -449,7 +449,7 @@ COMMAND_HANDLER(handle_flash_write_image_command) return retval; } - if ((retval == ERROR_OK) && (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)); @@ -501,7 +501,7 @@ COMMAND_HANDLER(handle_flash_verify_image_command) return retval; } - if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { + 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)); @@ -535,20 +535,20 @@ COMMAND_HANDLER(handle_flash_fill_command) return retval; switch (CMD_NAME[4]) { - case 'd': - wordsize = 8; - break; - case 'w': - wordsize = 4; - break; - case 'h': - wordsize = 2; - break; - case 'b': - wordsize = 1; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'd': + wordsize = 8; + break; + case 'w': + wordsize = 4; + break; + case 'h': + wordsize = 2; + break; + case 'b': + wordsize = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if ((wordsize < sizeof(pattern)) && (pattern >> (8 * wordsize) != 0)) { @@ -588,25 +588,25 @@ COMMAND_HANDLER(handle_flash_fill_command) uint8_t *ptr = buffer + padding_at_start; switch (wordsize) { - case 8: - for (i = 0; i < count; i++, ptr += wordsize) - target_buffer_set_u64(target, ptr, pattern); - break; - case 4: - for (i = 0; i < count; i++, ptr += wordsize) - target_buffer_set_u32(target, ptr, pattern); - break; - case 2: - for (i = 0; i < count; i++, ptr += wordsize) - target_buffer_set_u16(target, ptr, pattern); - break; - case 1: - memset(ptr, pattern, count); - ptr += count; - break; - default: - LOG_ERROR("BUG: can't happen"); - exit(-1); + case 8: + for (i = 0; i < count; i++, ptr += wordsize) + target_buffer_set_u64(target, ptr, pattern); + break; + case 4: + for (i = 0; i < count; i++, ptr += wordsize) + target_buffer_set_u32(target, ptr, pattern); + break; + case 2: + for (i = 0; i < count; i++, ptr += wordsize) + target_buffer_set_u16(target, ptr, pattern); + break; + case 1: + memset(ptr, pattern, count); + ptr += count; + break; + default: + LOG_ERROR("BUG: can't happen"); + exit(-1); } if (padding_at_end) { @@ -631,18 +631,18 @@ COMMAND_HANDLER(handle_flash_fill_command) uint64_t readback = 0; switch (wordsize) { - case 8: - readback = target_buffer_get_u64(target, ptr); - break; - case 4: - readback = target_buffer_get_u32(target, ptr); - break; - case 2: - readback = target_buffer_get_u16(target, ptr); - break; - case 1: - readback = *ptr; - break; + case 8: + readback = target_buffer_get_u64(target, ptr); + break; + case 4: + readback = target_buffer_get_u32(target, ptr); + break; + case 2: + readback = target_buffer_get_u16(target, ptr); + break; + case 1: + readback = *ptr; + break; } if (readback != pattern) { LOG_ERROR( @@ -655,7 +655,7 @@ COMMAND_HANDLER(handle_flash_fill_command) ptr += wordsize; } - if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { + if (retval == ERROR_OK && duration_measure(&bench) == ERROR_OK) { command_print(CMD, "wrote %" PRIu32 " bytes to " TARGET_ADDR_FMT " in %fs (%0.3f KiB/s)", size_bytes, address, duration_elapsed(&bench), duration_kbps(&bench, size_bytes)); @@ -683,17 +683,17 @@ COMMAND_HANDLER(handle_flash_md_command) unsigned int wordsize; switch (CMD_NAME[2]) { - case 'w': - wordsize = 4; - break; - case 'h': - wordsize = 2; - break; - case 'b': - wordsize = 1; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'w': + wordsize = 4; + break; + case 'h': + wordsize = 2; + break; + case 'b': + wordsize = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if (count == 0) @@ -728,6 +728,124 @@ COMMAND_HANDLER(handle_flash_md_command) return retval; } +COMMAND_HANDLER(handle_flash_read_memory_command) +{ + /* + * CMD_ARGV[0] = memory address + * CMD_ARGV[1] = desired element width in bits + * CMD_ARGV[2] = number of elements to read + */ + + if (CMD_ARGC != 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* Arg 1: Memory address. */ + target_addr_t addr; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], addr); + + /* Arg 2: Bit width of one element. */ + unsigned int width_bits; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], width_bits); + + /* Arg 3: Number of elements to read. */ + unsigned int count; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], count); + + 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; + } + + if (count > 65536) { + command_print(CMD, "too large read request, exceeds 64K elements"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + const unsigned int width = width_bits / 8; + /* -1 is needed to handle cases when (addr + count * width) results in zero + * due to overflow. + */ + if ((addr + count * width - 1) < addr) { + command_print(CMD, "memory region wraps over address zero"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + struct target *target = get_current_target(CMD_CTX); + struct flash_bank *bank; + int retval = get_flash_bank_by_addr(target, addr, true, &bank); + if (retval != ERROR_OK) + return retval; + + uint32_t offset = addr - bank->base; + uint32_t sizebytes = count * width_bits; + if (offset + sizebytes > bank->size) { + command_print(CMD, "cannot cross flash bank borders"); + return ERROR_FAIL; + } + + const size_t buffer_size = 4096; + uint8_t *buffer = malloc(buffer_size); + + if (!buffer) { + command_print(CMD, "failed to allocate memory"); + return ERROR_FAIL; + } + + char *separator = ""; + while (count > 0) { + const unsigned int max_chunk_len = buffer_size / width; + const size_t chunk_len = MIN(count, max_chunk_len); + + retval = flash_driver_read(bank, buffer, offset, chunk_len * width); + + if (retval != ERROR_OK) { + LOG_DEBUG("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, "failed to read memory"); + free(buffer); + return retval; + } + + for (size_t i = 0; i < chunk_len ; i++) { + uint64_t v = 0; + + switch (width) { + case 8: + v = target_buffer_get_u64(target, &buffer[i * width]); + break; + case 4: + v = target_buffer_get_u32(target, &buffer[i * width]); + break; + case 2: + v = target_buffer_get_u16(target, &buffer[i * width]); + break; + case 1: + v = buffer[i]; + break; + } + + command_print_sameline(CMD, "%s0x%" PRIx64, separator, v); + separator = " "; + } + + count -= chunk_len; + offset += chunk_len * width; + } + + free(buffer); + + return ERROR_OK; +} COMMAND_HANDLER(handle_flash_write_bank_command) { @@ -832,7 +950,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command) free(buffer); - if ((retval == ERROR_OK) && (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, @@ -1171,6 +1289,13 @@ static const struct command_registration flash_exec_command_handlers[] = { .usage = "address [count]", .help = "Display words from flash.", }, + { + .name = "read_memory", + .mode = COMMAND_EXEC, + .handler = handle_flash_read_memory_command, + .help = "Read Tcl list of 8/16/32/64 bit numbers from flash memory", + .usage = "address width count", + }, { .name = "write_bank", .handler = handle_flash_write_bank_command, @@ -1317,8 +1442,7 @@ COMMAND_HANDLER(handle_flash_banks_command) if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned int n = 0; - for (struct flash_bank *p = flash_bank_list(); p; p = p->next, n++) { + for (struct flash_bank *p = flash_bank_list(); p; p = p->next) { command_print(CMD, "#%d : %s (%s) at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32 ", " "buswidth %u, chipwidth %u", p->bank_number, p->name, p->driver->name, p->base, p->size, @@ -1335,7 +1459,7 @@ COMMAND_HANDLER(handle_flash_list) for (struct flash_bank *p = flash_bank_list(); p; p = p->next) { command_print(CMD, "{\n" - " name %s\n" + " name {%s}\n" " driver %s\n" " base " TARGET_ADDR_FMT "\n" " size 0x%" PRIx32 "\n" diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c index 00ee77bb80..1c8432a205 100644 --- a/src/flash/nor/tms470.c +++ b/src/flash/nor/tms470.c @@ -125,7 +125,7 @@ static int tms470_read_part_info(struct flash_bank *bank) /* read and parse the device identification register */ target_read_u32(target, 0xFFFFFFF0, &device_ident_reg); - LOG_INFO("device_ident_reg = 0x%08" PRIx32 "", device_ident_reg); + LOG_INFO("device_ident_reg = 0x%08" PRIx32, device_ident_reg); if ((device_ident_reg & 7) == 0) { LOG_WARNING("Cannot identify target as a TMS470 family."); @@ -148,100 +148,100 @@ static int tms470_read_part_info(struct flash_bank *bank) * bank structure. */ switch (part_number) { - case 0x0a: - part_name = "TMS470R1A256"; - - if (bank->base >= 0x00040000) { - LOG_ERROR("No %s flash bank contains base address " - TARGET_ADDR_FMT ".", - part_name, - bank->base); - return ERROR_FLASH_OPERATION_FAILED; - } + case 0x0a: + part_name = "TMS470R1A256"; + + if (bank->base >= 0x00040000) { + LOG_ERROR("No %s flash bank contains base address " + TARGET_ADDR_FMT ".", + part_name, + bank->base); + return ERROR_FLASH_OPERATION_FAILED; + } + tms470_info->ordinal = 0; + bank->base = 0x00000000; + bank->size = 256 * 1024; + bank->num_sectors = TMS470R1A256_NUM_SECTORS; + bank->sectors = malloc(sizeof(tms470r1a256_sectors)); + if (!bank->sectors) + return ERROR_FLASH_OPERATION_FAILED; + (void)memcpy(bank->sectors, tms470r1a256_sectors, sizeof(tms470r1a256_sectors)); + break; + + case 0x2b: + part_name = "TMS470R1A288"; + + if (bank->base < 0x00008000) { tms470_info->ordinal = 0; bank->base = 0x00000000; + bank->size = 32 * 1024; + bank->num_sectors = TMS470R1A288_BANK0_NUM_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)); + } else if ((bank->base >= 0x00040000) && (bank->base < 0x00080000)) { + tms470_info->ordinal = 1; + bank->base = 0x00040000; bank->size = 256 * 1024; - bank->num_sectors = TMS470R1A256_NUM_SECTORS; - bank->sectors = malloc(sizeof(tms470r1a256_sectors)); + bank->num_sectors = TMS470R1A288_BANK1_NUM_SECTORS; + bank->sectors = malloc(sizeof(tms470r1a288_bank1_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, tms470r1a256_sectors, sizeof(tms470r1a256_sectors)); - break; + (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); + return ERROR_FLASH_OPERATION_FAILED; + } + break; - case 0x2b: - part_name = "TMS470R1A288"; - - if (bank->base < 0x00008000) { - tms470_info->ordinal = 0; - bank->base = 0x00000000; - bank->size = 32 * 1024; - bank->num_sectors = TMS470R1A288_BANK0_NUM_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)); - } 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)); - if (!bank->sectors) - return ERROR_FLASH_OPERATION_FAILED; - (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); - return ERROR_FLASH_OPERATION_FAILED; - } - break; + case 0x2d: + part_name = "TMS470R1A384"; - case 0x2d: - part_name = "TMS470R1A384"; - - if (bank->base < 0x00020000) { - tms470_info->ordinal = 0; - bank->base = 0x00000000; - bank->size = 128 * 1024; - bank->num_sectors = TMS470R1A384_BANK0_NUM_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)); - } 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)); - if (!bank->sectors) - return ERROR_FLASH_OPERATION_FAILED; - (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)); - if (!bank->sectors) - return ERROR_FLASH_OPERATION_FAILED; - (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); + if (bank->base < 0x00020000) { + tms470_info->ordinal = 0; + bank->base = 0x00000000; + bank->size = 128 * 1024; + bank->num_sectors = TMS470R1A384_BANK0_NUM_SECTORS; + bank->sectors = malloc(sizeof(tms470r1a384_bank0_sectors)); + if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; - } - break; - - default: - LOG_WARNING("Could not identify part 0x%02" PRIx32 " as a member of the TMS470 family.", - part_number); + (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)); + if (!bank->sectors) + return ERROR_FLASH_OPERATION_FAILED; + (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)); + if (!bank->sectors) + return ERROR_FLASH_OPERATION_FAILED; + (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); return ERROR_FLASH_OPERATION_FAILED; + } + break; + + default: + LOG_WARNING("Could not identify part 0x%02" PRIx32 " as a member of the TMS470 family.", + part_number); + return ERROR_FLASH_OPERATION_FAILED; } /* turn off memory selects */ @@ -300,7 +300,7 @@ COMMAND_HANDLER(tms470_handle_flash_keyset_command) if (keys_set) { command_print(CMD, - "using flash keys 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 "", + "using flash keys 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32, flash_keys[0], flash_keys[1], flash_keys[2], @@ -419,7 +419,7 @@ static int tms470_try_flash_keys(struct target *target, const uint32_t *key_set) */ target_read_u32(target, 0x00001FF0 + 4 * i, &tmp); - LOG_INFO("tms470 writing fmpkey = 0x%08" PRIx32 "", key_set[i]); + LOG_INFO("tms470 writing fmpkey = 0x%08" PRIx32, key_set[i]); target_write_u32(target, 0xFFE89C0C, key_set[i]); } @@ -490,7 +490,6 @@ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *ban uint32_t fmmac2, fmmac1, fmmaxep, k, delay, glbctrl, sysclk; struct target *target = bank->target; struct tms470_flash_bank *tms470_info = bank->driver_priv; - int result = ERROR_OK; /* * Select the desired bank to be programmed by writing BANK[2:0] of @@ -500,7 +499,7 @@ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *ban fmmac2 &= ~0x0007; fmmac2 |= (tms470_info->ordinal & 7); target_write_u32(target, 0xFFE8BC04, fmmac2); - LOG_DEBUG("set fmmac2 = 0x%04" PRIx32 "", fmmac2); + LOG_DEBUG("set fmmac2 = 0x%04" PRIx32, fmmac2); /* * Disable level 1 sector protection by setting bit 15 of FMMAC1. @@ -508,7 +507,7 @@ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *ban target_read_u32(target, 0xFFE8BC00, &fmmac1); fmmac1 |= 0x8000; target_write_u32(target, 0xFFE8BC00, fmmac1); - LOG_DEBUG("set fmmac1 = 0x%04" PRIx32 "", fmmac1); + LOG_DEBUG("set fmmac1 = 0x%04" PRIx32, fmmac1); /* * FMTCREG = 0x2fc0; @@ -542,7 +541,7 @@ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *ban LOG_DEBUG("set fmptr3 = 0x9b64"); } target_write_u32(target, 0xFFE8A080, fmmaxep); - LOG_DEBUG("set fmmaxep = 0x%04" PRIx32 "", fmmaxep); + LOG_DEBUG("set fmmaxep = 0x%04" PRIx32, fmmaxep); /* * FMPTR4 = 0xa000 @@ -562,58 +561,58 @@ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *ban 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)); + LOG_DEBUG("set fmpsetup = 0x%04" PRIx32, (delay << 4) | (delay << 8)); /* * FMPVEVACCESS, based on delay. */ k = delay | (delay << 8); target_write_u32(target, 0xFFE8A05C, k); - LOG_DEBUG("set fmpvevaccess = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmpvevaccess = 0x%04" PRIx32, k); /* * FMPCHOLD, FMPVEVHOLD, FMPVEVSETUP, based on delay. */ k <<= 1; target_write_u32(target, 0xFFE8A034, k); - LOG_DEBUG("set fmpchold = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmpchold = 0x%04" PRIx32, k); target_write_u32(target, 0xFFE8A040, k); - LOG_DEBUG("set fmpvevhold = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmpvevhold = 0x%04" PRIx32, k); target_write_u32(target, 0xFFE8A024, k); - LOG_DEBUG("set fmpvevsetup = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmpvevsetup = 0x%04" PRIx32, k); /* * FMCVACCESS, based on delay. */ k = delay * 16; target_write_u32(target, 0xFFE8A060, k); - LOG_DEBUG("set fmcvaccess = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmcvaccess = 0x%04" PRIx32, k); /* * FMCSETUP, based on delay. */ k = 0x3000 | delay * 20; target_write_u32(target, 0xFFE8A020, k); - LOG_DEBUG("set fmcsetup = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmcsetup = 0x%04" PRIx32, k); /* * FMEHOLD, based on delay. */ k = (delay * 20) << 2; target_write_u32(target, 0xFFE8A038, k); - LOG_DEBUG("set fmehold = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmehold = 0x%04" PRIx32, k); /* * PWIDTH, CWIDTH, EWIDTH, based on delay. */ target_write_u32(target, 0xFFE8A050, delay * 8); - LOG_DEBUG("set fmpwidth = 0x%04" PRIx32 "", delay * 8); + LOG_DEBUG("set fmpwidth = 0x%04" PRIx32, delay * 8); target_write_u32(target, 0xFFE8A058, delay * 1000); - LOG_DEBUG("set fmcwidth = 0x%04" PRIx32 "", delay * 1000); + LOG_DEBUG("set fmcwidth = 0x%04" PRIx32, delay * 1000); target_write_u32(target, 0xFFE8A054, delay * 5400); - LOG_DEBUG("set fmewidth = 0x%04" PRIx32 "", delay * 5400); + LOG_DEBUG("set fmewidth = 0x%04" PRIx32, delay * 5400); - return result; + return ERROR_OK; } /* ---------------------------------------------------------------------- */ @@ -625,7 +624,7 @@ static int tms470_flash_status(struct flash_bank *bank) uint32_t fmmstat; target_read_u32(target, 0xFFE8BC0C, &fmmstat); - LOG_DEBUG("set fmmstat = 0x%04" PRIx32 "", fmmstat); + LOG_DEBUG("set fmmstat = 0x%04" PRIx32, fmmstat); if (fmmstat & 0x0080) { LOG_WARNING("tms470 flash command: erase still active after busy clear."); @@ -680,7 +679,7 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector) */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10); - LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl | 0x10); + LOG_DEBUG("set glbctrl = 0x%08" PRIx32, glbctrl | 0x10); /* Force normal read mode. */ target_read_u32(target, 0xFFE89C00, &orig_fmregopt); @@ -697,11 +696,11 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector) if (sector < 16) { target_read_u32(target, 0xFFE88008, &fmbsea); target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector)); - LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea | (1 << sector)); + LOG_DEBUG("set fmbsea = 0x%04" PRIx32, fmbsea | (1 << sector)); } else { target_read_u32(target, 0xFFE8800C, &fmbseb); target_write_u32(target, 0xFFE8800C, fmbseb | (1 << (sector - 16))); - LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb | (1 << (sector - 16))); + LOG_DEBUG("set fmbseb = 0x%04" PRIx32, fmbseb | (1 << (sector - 16))); } bank->sectors[sector].is_protected = 0; @@ -729,17 +728,17 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector) if (sector < 16) { target_write_u32(target, 0xFFE88008, fmbsea); - LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea); + LOG_DEBUG("set fmbsea = 0x%04" PRIx32, fmbsea); bank->sectors[sector].is_protected = fmbsea & (1 << sector) ? 0 : 1; } else { target_write_u32(target, 0xFFE8800C, fmbseb); - LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb); + LOG_DEBUG("set fmbseb = 0x%04" PRIx32, fmbseb); bank->sectors[sector].is_protected = fmbseb & (1 << (sector - 16)) ? 0 : 1; } target_write_u32(target, 0xFFE89C00, orig_fmregopt); - LOG_DEBUG("set fmregopt = 0x%08" PRIx32 "", orig_fmregopt); + LOG_DEBUG("set fmregopt = 0x%08" PRIx32, orig_fmregopt); target_write_u32(target, 0xFFFFFFDC, glbctrl); - LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl); + LOG_DEBUG("set glbctrl = 0x%08" PRIx32, glbctrl); return result; } @@ -920,7 +919,7 @@ static int tms470_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t uint16_t word = (((uint16_t) buffer[i]) << 8) | (uint16_t) buffer[i + 1]; if (word != 0xffff) { - LOG_INFO("writing 0x%04x at 0x%08" PRIx32 "", word, addr); + LOG_INFO("writing 0x%04x at 0x%08" PRIx32, word, addr); /* clear status register */ target_write_u16(target, addr, 0x0040); @@ -940,7 +939,7 @@ static int tms470_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t } while (fmmstat & 0x0100); if (fmmstat & 0x3ff) { - LOG_ERROR("fmstat = 0x%04" PRIx32 "", fmmstat); + LOG_ERROR("fmstat = 0x%04" PRIx32, fmmstat); LOG_ERROR( "Could not program word 0x%04x at address 0x%08" PRIx32 ".", word, @@ -949,7 +948,7 @@ static int tms470_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t break; } } else - LOG_INFO("skipping 0xffff at 0x%08" PRIx32 "", addr); + LOG_INFO("skipping 0xffff at 0x%08" PRIx32, addr); } /* restore */ diff --git a/src/flash/nor/virtual.c b/src/flash/nor/virtual.c index c5e33385e6..5b8a3c5b7a 100644 --- a/src/flash/nor/virtual.c +++ b/src/flash/nor/virtual.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/*************************************************************************** - * Copyright (C) 2010 by Spencer Oliver * - * spen@spen-soft.co.uk * - ***************************************************************************/ +/* + * Copyright (C) 2010 by Spencer Oliver + * + * Copyright (C) 2019 by Tomas Vanek + */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -31,6 +32,9 @@ static void virtual_update_bank_info(struct flash_bank *bank) /* update the info we do not have */ bank->size = master_bank->size; + if (bank->read_only) + return; + bank->chip_width = master_bank->chip_width; bank->bus_width = master_bank->bus_width; bank->erased_value = master_bank->erased_value; @@ -93,34 +97,24 @@ static int virtual_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct flash_bank *master_bank = virtual_get_master_bank(bank); - int retval; if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ - retval = master_bank->driver->erase(master_bank, first, last); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; + return master_bank->driver->erase(master_bank, first, last); } static int virtual_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct flash_bank *master_bank = virtual_get_master_bank(bank); - int retval; if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ - retval = master_bank->driver->write(master_bank, buffer, offset, count); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; + return master_bank->driver->write(master_bank, buffer, offset, count); } static int virtual_probe(struct flash_bank *bank) @@ -177,34 +171,37 @@ static int virtual_info(struct flash_bank *bank, struct command_invocation *cmd) static int virtual_blank_check(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); - int retval; if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ - retval = master_bank->driver->erase_check(master_bank); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; + return master_bank->driver->erase_check(master_bank); } static int virtual_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct flash_bank *master_bank = virtual_get_master_bank(bank); - int retval; if (!master_bank) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ - retval = master_bank->driver->read(master_bank, buffer, offset, count); - if (retval != ERROR_OK) - return retval; + return master_bank->driver->read(master_bank, buffer, offset, count); +} - return ERROR_OK; +void virtual_flash_free_driver_priv(struct flash_bank *bank) +{ + free(bank->driver_priv); + bank->driver_priv = NULL; + + /* For 'virtual' flash driver bank->sectors and bank->prot_blocks pointers are copied from + * master flash_bank structure. They point to memory locations allocated by master flash driver + * so master driver is responsible for releasing them. + * Avoid UB caused by double-free memory corruption if flash bank is 'virtual'. */ + bank->sectors = NULL; + bank->prot_blocks = NULL; } const struct flash_driver virtual_flash = { @@ -219,5 +216,62 @@ const struct flash_driver virtual_flash = { .erase_check = virtual_blank_check, .protect_check = virtual_protect_check, .info = virtual_info, - .free_driver_priv = default_flash_free_driver_priv, + .free_driver_priv = virtual_flash_free_driver_priv, +}; + +FLASH_BANK_COMMAND_HANDLER(ro_alias_bank_command) +{ + if (CMD_ARGC < 7) + return ERROR_COMMAND_SYNTAX_ERROR; + + // get the master flash bank + const char *bank_name = CMD_ARGV[6]; + struct flash_bank *master_bank = get_flash_bank_by_name_noprobe(bank_name); + + if (!master_bank) { + LOG_ERROR("master flash bank '%s' does not exist", bank_name); + return ERROR_FLASH_OPERATION_FAILED; + } + + // save master bank name - use this to get settings later + bank->driver_priv = strdup(bank_name); + + bank->read_only = true; + + return ERROR_OK; +} + +static int ro_alias_erase(struct flash_bank *bank, + unsigned int first, unsigned int last) +{ + char *bank_name = bank->driver_priv; + + LOG_ERROR("Erase of read-only flash alias refused. Use master flash bank '%s'", + bank_name); + + return ERROR_FAIL; +} + +static int ro_alias_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + char *bank_name = bank->driver_priv; + + LOG_ERROR("Write to read-only flash alias refused. Use master flash bank '%s'", + bank_name); + + return ERROR_FAIL; +} + +const struct flash_driver ro_alias_flash = { + .name = "ro_alias", + .flash_bank_command = ro_alias_bank_command, + .erase = ro_alias_erase, + .write = ro_alias_write, + .read = virtual_flash_read, + .probe = virtual_probe, + .auto_probe = virtual_auto_probe, + .erase_check = virtual_blank_check, + .info = virtual_info, + .free_driver_priv = virtual_flash_free_driver_priv, }; diff --git a/src/flash/nor/w600.c b/src/flash/nor/w600.c index 20968dcaaa..ba4a42969b 100644 --- a/src/flash/nor/w600.c +++ b/src/flash/nor/w600.c @@ -128,13 +128,13 @@ static int w600_start_do(struct flash_bank *bank, uint32_t cmd, uint32_t addr, if (len > 0) cmd |= QFLASH_CMD_DATALEN(len - 1) | QFLASH_CMD_DATA; - LOG_DEBUG("WRITE CMD: 0x%08" PRIx32 "", cmd); + LOG_DEBUG("WRITE CMD: 0x%08" PRIx32, cmd); int retval = target_write_u32(target, QFLASH_CMD_INFO, cmd); if (retval != ERROR_OK) return retval; addr |= QFLASH_START; - LOG_DEBUG("WRITE START: 0x%08" PRIx32 "", addr); + LOG_DEBUG("WRITE START: 0x%08" PRIx32, addr); retval = target_write_u32(target, QFLASH_CMD_START, addr); if (retval != ERROR_OK) return retval; @@ -148,7 +148,7 @@ static int w600_start_do(struct flash_bank *bank, uint32_t cmd, uint32_t addr, LOG_DEBUG("READ START..."); retval = target_read_u32(target, QFLASH_CMD_START, &status); if (retval == ERROR_OK) - LOG_DEBUG("READ START: 0x%08" PRIx32 "", status); + LOG_DEBUG("READ START: 0x%08" PRIx32, status); else LOG_DEBUG("READ START FAILED"); @@ -283,7 +283,7 @@ static int w600_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - LOG_INFO("flash_id id = 0x%08" PRIx32 "", flash_id); + LOG_INFO("flash_id id = 0x%08" PRIx32, flash_id); w600_info->id = flash_id; w600_info->param = NULL; for (i = 0; i < ARRAY_SIZE(w600_param); i++) { @@ -360,7 +360,7 @@ static int get_w600_info(struct flash_bank *bank, struct command_invocation *cmd if (retval != ERROR_OK) return retval; - command_print_sameline(cmd, "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 4011fa42be..04ee0d34a3 100644 --- a/src/flash/nor/xcf.c +++ b/src/flash/nor/xcf.c @@ -87,14 +87,14 @@ static const char *product_name(const struct flash_bank *bank) { switch (bank->target->tap->idcode & ID_MEANINGFUL_MASK) { - case ID_XCF08P: - return xcf_name_list[0]; - case ID_XCF16P: - return xcf_name_list[1]; - case ID_XCF32P: - return xcf_name_list[2]; - default: - return xcf_name_list[3]; + case ID_XCF08P: + return xcf_name_list[0]; + case ID_XCF16P: + return xcf_name_list[1]; + case ID_XCF32P: + return xcf_name_list[2]; + default: + return xcf_name_list[3]; } } @@ -601,18 +601,18 @@ static int xcf_probe(struct flash_bank *bank) /* guess number of blocks using chip ID */ id = bank->target->tap->idcode; switch (id & ID_MEANINGFUL_MASK) { - case ID_XCF08P: - bank->num_sectors = 1; - break; - case ID_XCF16P: - bank->num_sectors = 2; - break; - case ID_XCF32P: - bank->num_sectors = 4; - break; - default: - LOG_ERROR("Unknown flash device ID 0x%" PRIX32, id); - return ERROR_FAIL; + case ID_XCF08P: + bank->num_sectors = 1; + break; + case ID_XCF16P: + bank->num_sectors = 2; + break; + case ID_XCF32P: + bank->num_sectors = 4; + break; + default: + LOG_ERROR("Unknown flash device ID 0x%" PRIX32, id); + return ERROR_FAIL; } bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector)); diff --git a/src/flash/nor/xmc4xxx.c b/src/flash/nor/xmc4xxx.c index 54fd5a5867..ceed055fcb 100644 --- a/src/flash/nor/xmc4xxx.c +++ b/src/flash/nor/xmc4xxx.c @@ -231,12 +231,12 @@ struct xmc4xxx_command_seq { }; /* Sector capacities. See section 8 of xmc4x00_rm */ -static const unsigned int sector_capacity_8[8] = { - 16, 16, 16, 16, 16, 16, 16, 128 +static const unsigned int sector_capacity_9[9] = { + 16, 16, 16, 16, 16, 16, 16, 16, 128 }; -static const unsigned int sector_capacity_9[9] = { - 16, 16, 16, 16, 16, 16, 16, 128, 256 +static const unsigned int sector_capacity_10[10] = { + 16, 16, 16, 16, 16, 16, 16, 16, 128, 256 }; static const unsigned int sector_capacity_12[12] = { @@ -272,12 +272,12 @@ static int xmc4xxx_load_bank_layout(struct flash_bank *bank) LOG_DEBUG("%u sectors", bank->num_sectors); switch (bank->num_sectors) { - case 8: - capacity = sector_capacity_8; - break; case 9: capacity = sector_capacity_9; break; + case 10: + capacity = sector_capacity_10; + break; case 12: capacity = sector_capacity_12; break; @@ -361,11 +361,11 @@ static int xmc4xxx_probe(struct flash_bank *bank) * we understand the type of controller we're dealing with */ switch (flash_id) { case FLASH_ID_XMC4100_4200: - bank->num_sectors = 8; + bank->num_sectors = 9; LOG_DEBUG("XMC4xxx: XMC4100/4200 detected."); break; case FLASH_ID_XMC4400: - bank->num_sectors = 9; + bank->num_sectors = 10; LOG_DEBUG("XMC4xxx: XMC4400 detected."); break; case FLASH_ID_XMC4500: @@ -522,9 +522,7 @@ static int xmc4xxx_erase_sector(struct flash_bank *bank, uint32_t address, } /* Now we must wait for the erase operation to end */ - res = xmc4xxx_wait_status_busy(bank, FLASH_OP_TIMEOUT); - - return res; + return xmc4xxx_wait_status_busy(bank, FLASH_OP_TIMEOUT); } static int xmc4xxx_erase(struct flash_bank *bank, unsigned int first, @@ -569,8 +567,7 @@ static int xmc4xxx_erase(struct flash_bank *bank, unsigned int first, } clear_status_and_exit: - res = xmc4xxx_clear_flash_status(bank); - return res; + return xmc4xxx_clear_flash_status(bank); } @@ -1131,7 +1128,6 @@ static int xmc4xxx_flash_protect(struct flash_bank *bank, int level, bool read_p static int xmc4xxx_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { - int ret; struct xmc4xxx_flash_bank *fb = bank->driver_priv; /* Check for flash passwords */ @@ -1144,14 +1140,11 @@ static int xmc4xxx_protect(struct flash_bank *bank, int set, unsigned int first, if (set == 0) { LOG_WARNING("Flash protection will be temporarily disabled" " for all pages (User 0 only)!"); - ret = xmc4xxx_temp_unprotect(bank, 0); - return ret; + return xmc4xxx_temp_unprotect(bank, 0); } /* Install write protection for user 0 on the specified pages */ - ret = xmc4xxx_flash_protect(bank, 0, false, first, last); - - return ret; + return xmc4xxx_flash_protect(bank, 0, false, first, last); } static int xmc4xxx_protect_check(struct flash_bank *bank) @@ -1290,9 +1283,7 @@ COMMAND_HANDLER(xmc4xxx_handle_flash_unprotect_command) COMMAND_PARSE_NUMBER(s32, CMD_ARGV[1], level); - res = xmc4xxx_flash_unprotect(bank, level); - - return res; + return xmc4xxx_flash_unprotect(bank, level); } static const struct command_registration xmc4xxx_exec_command_handlers[] = { diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am index 39d93d66ac..1a61f78719 100644 --- a/src/helper/Makefile.am +++ b/src/helper/Makefile.am @@ -3,6 +3,7 @@ noinst_LTLIBRARIES += %D%/libhelper.la %C%_libhelper_la_SOURCES = \ + %D%/base64.c \ %D%/binarybuffer.c \ %D%/options.c \ %D%/time_support_common.c \ @@ -18,7 +19,9 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/jim-nvp.c \ %D%/nvp.c \ %D%/align.h \ + %D%/base64.h \ %D%/binarybuffer.h \ + %D%/bitfield.h \ %D%/bits.h \ %D%/configuration.h \ %D%/list.h \ @@ -29,13 +32,12 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/crc32.h \ %D%/time_support.h \ %D%/replacements.h \ + %D%/string_choices.h \ %D%/fileio.h \ %D%/system.h \ %D%/jep106.h \ %D%/jep106.inc \ %D%/jim-nvp.h \ - %D%/base64.c \ - %D%/base64.h \ %D%/nvp.h \ %D%/compiler.h diff --git a/src/helper/base64.c b/src/helper/base64.c index effa8acda0..5e0ee0846e 100644 --- a/src/helper/base64.c +++ b/src/helper/base64.c @@ -1,9 +1,11 @@ +// SPDX-License-Identifier: BSD-3-Clause + /* * Base64 encoding/decoding (RFC1341) * Copyright (c) 2005-2011, Jouni Malinen * - * This software may be distributed under the terms of the BSD license. - * See README for more details. + * Original file from FreeBSD code + * https://cgit.freebsd.org/src/tree/contrib/wpa/src/utils/base64.c?id=f05cddf940db */ @@ -42,7 +44,7 @@ unsigned char *base64_encode(const unsigned char *src, size_t len, if (olen < len) return NULL; /* integer overflow */ out = malloc(olen); - if (out == NULL) + if (!out) return NULL; end = src + len; @@ -105,7 +107,7 @@ unsigned char *base64_decode(const unsigned char *src, size_t len, memset(dtable, 0x80, 256); for (i = 0; i < sizeof(base64_table) - 1; i++) - dtable[base64_table[i]] = (unsigned char) i; + dtable[base64_table[i]] = (unsigned char)i; dtable['='] = 0; count = 0; @@ -118,9 +120,10 @@ unsigned char *base64_decode(const unsigned char *src, size_t len, return NULL; olen = count / 4 * 3; - pos = out = malloc(olen); - if (out == NULL) + out = malloc(olen); + if (!out) return NULL; + pos = out; count = 0; for (i = 0; i < len; i++) { @@ -138,11 +141,11 @@ unsigned char *base64_decode(const unsigned char *src, size_t len, *pos++ = (block[2] << 6) | block[3]; count = 0; if (pad) { - if (pad == 1) + if (pad == 1) { pos--; - else if (pad == 2) + } else if (pad == 2) { pos -= 2; - else { + } else { /* Invalid padding */ free(out); return NULL; diff --git a/src/helper/base64.h b/src/helper/base64.h index dbabb606ab..d3e0462131 100644 --- a/src/helper/base64.h +++ b/src/helper/base64.h @@ -1,9 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /* * Base64 encoding/decoding (RFC1341) * Copyright (c) 2005, Jouni Malinen * - * This software may be distributed under the terms of the BSD license. - * See README for more details. + * Original file from FreeBSD code + * https://cgit.freebsd.org/src/tree/contrib/wpa/src/utils/base64.h?id=f05cddf940db */ #ifndef BASE64_H diff --git a/src/helper/bitfield.h b/src/helper/bitfield.h new file mode 100644 index 0000000000..9f397282cf --- /dev/null +++ b/src/helper/bitfield.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* +* Copyright (c) 2020-2024 The FreeBSD Foundation +* +* This software was developed by Björn Zeeb under sponsorship from +* the FreeBSD Foundation. +*/ + +#ifndef OPENOCD_HELPER_BITFIELD_H +#define OPENOCD_HELPER_BITFIELD_H + +/** + * These macros come from FreeBSD, check source on + * https://cgit.freebsd.org/src/tree/sys/compat/linuxkpi/common/include/linux/bitfield.h + * Which does not include example usages of them. + */ + +#define __bf_shf(x) (__builtin_ffsll(x) - 1) + +/** + * FIELD_FIT(_mask, _value) - Check if a value fits in the specified bitfield mask + * @_mask: Bitfield mask + * @_value: Value to check + * + * This macro checks whether a given value fits within the range defined by the + * specified bitfield mask. It ensures that no bits outside the mask are set. + * + * Return: true if the value fits, false otherwise. + */ +#define FIELD_FIT(_mask, _value) \ + (!(((typeof(_mask))(_value) << __bf_shf(_mask)) & ~(_mask))) + +/** + * FIELD_PREP(_mask, _value) - Prepare a value for insertion into a bitfield + * @_mask: Bitfield mask + * @_value: Value to insert + * + * This macro prepares a value for insertion into a bitfield by shifting the + * value into the position defined by the mask and applying the mask. + * + * Return: The prepared bitfield value. + */ +#define FIELD_PREP(_mask, _value) \ + (((typeof(_mask))(_value) << __bf_shf(_mask)) & (_mask)) + +/** + * FIELD_GET(_mask, _value) - Extract a value from a bitfield + * @_mask: Bitfield mask + * @_value: Bitfield value to extract from + * + * This macro extracts a value from a bitfield by masking and shifting the + * relevant bits down to the least significant position. + * + * Return: The extracted value. + */ +#define FIELD_GET(_mask, _value) \ + ((typeof(_mask))(((_value) & (_mask)) >> __bf_shf(_mask))) + +#endif /* OPENOCD_HELPER_BITFIELD_H */ diff --git a/src/helper/command.c b/src/helper/command.c index 218f0581ef..bf2c91814e 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -45,26 +45,22 @@ static enum command_mode get_command_mode(Jim_Interp *interp, const char *cmd_na /* set of functions to wrap jimtcl internal data */ static inline bool jimcmd_is_proc(Jim_Cmd *cmd) { +#if defined(JIM_CMD_ISPROC) + // JIM_VERSION >= 84 + return cmd->flags & JIM_CMD_ISPROC; +#else return cmd->isproc; +#endif } bool jimcmd_is_oocd_command(Jim_Cmd *cmd) { - return !cmd->isproc && cmd->u.native.cmdProc == jim_command_dispatch; + return !jimcmd_is_proc(cmd) && cmd->u.native.cmdProc == jim_command_dispatch; } void *jimcmd_privdata(Jim_Cmd *cmd) { - return cmd->isproc ? NULL : cmd->u.native.privData; -} - -static int command_retval_set(Jim_Interp *interp, int retval) -{ - int *return_retval = Jim_GetAssocData(interp, "retval"); - if (return_retval) - *return_retval = retval; - - return (retval == ERROR_OK) ? JIM_OK : retval; + return jimcmd_is_proc(cmd) ? NULL : cmd->u.native.privData; } extern struct command_context *global_cmd_ctx; @@ -73,7 +69,7 @@ extern struct command_context *global_cmd_ctx; * Do nothing in case we are not at debug level 3 */ static void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv) { - if (debug_level < LOG_LVL_DEBUG) + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; char *dbg = alloc_printf("command -"); @@ -130,13 +126,13 @@ static struct command *command_new(struct command_context *cmd_ctx, assert(cr->name); /* - * If it is a non-jim command with no .usage specified, + * If it is a command with no .usage specified, * log an error. * * strlen(.usage) == 0 means that the command takes no * arguments. */ - if (!cr->jim_handler && !cr->usage) + if (!cr->usage) LOG_ERROR("BUG: command '%s' does not have the " "'.usage' field filled out", full_name); @@ -152,7 +148,6 @@ static struct command *command_new(struct command_context *cmd_ctx, } c->handler = cr->handler; - c->jim_handler = cr->jim_handler; c->mode = cr->mode; if (cr->help || cr->usage) @@ -350,50 +345,54 @@ void command_output_text(struct command_context *context, const char *data) context->output_handler(context, data); } -void command_print_sameline(struct command_invocation *cmd, const char *format, ...) +static void command_vprint(struct command_invocation *cmd, + va_list ap, const char *format, bool add_lf) { - char *string; + assert(cmd); + + // Quit on previous allocation error + if (cmd->output == CMD_PRINT_OOM) + return; + char *string = alloc_vprintf(format, ap); + if (!string) + goto alloc_error; + + char *output = cmd->output ? cmd->output : ""; + output = alloc_printf("%s%s%s", output, string, add_lf ? "\n" : ""); + free(string); + if (!output) + goto alloc_error; + + free(cmd->output); + cmd->output = output; + + return; + +alloc_error: + LOG_ERROR("Out of memory"); + free(cmd->output); + cmd->output = CMD_PRINT_OOM; +} + +void command_print_sameline(struct command_invocation *cmd, const char *format, ...) +{ va_list ap; va_start(ap, format); - string = alloc_vprintf(format, ap); - if (string && cmd) { - /* we want this collected in the log + we also want to pick it up as a tcl return - * value. - * - * The latter bit isn't precisely neat, but will do for now. - */ - Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1); - /* We already printed it above - * command_output_text(context, string); */ - free(string); - } + bool add_lf = false; + command_vprint(cmd, ap, format, add_lf); va_end(ap); } void command_print(struct command_invocation *cmd, const char *format, ...) { - char *string; - va_list ap; va_start(ap, format); - string = alloc_vprintf(format, ap); - 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 - * value. - * - * The latter bit isn't precisely neat, but will do for now. - */ - Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1); - /* We already printed it above - * command_output_text(context, string); */ - free(string); - } + bool add_lf = true; + command_vprint(cmd, ap, format, add_lf); va_end(ap); } @@ -406,28 +405,25 @@ static bool command_can_run(struct command_context *cmd_ctx, struct command *c, /* Many commands may be run only before/after 'init' */ const char *when; switch (c->mode) { - case COMMAND_CONFIG: - when = "before"; - break; - case COMMAND_EXEC: - when = "after"; - break; - /* handle the impossible with humor; it guarantees a bug report! */ - default: - when = "if Cthulhu is summoned by"; - break; + case COMMAND_CONFIG: + when = "before"; + break; + case COMMAND_EXEC: + when = "after"; + break; + /* handle the impossible with humor; it guarantees a bug report! */ + default: + when = "if Cthulhu is summoned by"; + break; } LOG_ERROR("The '%s' command must be used %s 'init'.", full_name ? full_name : c->name, when); return false; } -static int exec_command(Jim_Interp *interp, struct command_context *context, +static int jim_exec_command(Jim_Interp *interp, struct command_context *context, struct command *c, int argc, Jim_Obj * const *argv) { - if (c->jim_handler) - return c->jim_handler(interp, argc, argv); - /* use c->handler */ const char **words = malloc(argc * sizeof(char *)); if (!words) { @@ -445,36 +441,57 @@ static int exec_command(Jim_Interp *interp, struct command_context *context, .argc = argc - 1, .argv = words + 1, .jimtcl_argv = argv + 1, + .output = NULL, }; - cmd.output = Jim_NewEmptyStringObj(context->interp); - Jim_IncrRefCount(cmd.output); - int retval = c->handler(&cmd); + + // Handle allocation error in command_print() + if (cmd.output == CMD_PRINT_OOM) { + cmd.output = NULL; + if (retval == ERROR_OK) + retval = ERROR_FAIL; + } + if (retval == ERROR_COMMAND_SYNTAX_ERROR) { - /* Print help for command */ - command_run_linef(context, "usage %s", words[0]); + // Print command syntax + Jim_EvalObjPrefix(context->interp, Jim_NewStringObj(context->interp, "usage", -1), 1, argv); } else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) { /* just fall through for a shutdown request */ } else { if (retval != ERROR_OK) LOG_DEBUG("Command '%s' failed with error code %d", 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); + if (cmd.output) { + /* + * Use the command output as the Tcl result. + * Drop last '\n' to allow command output concatenation + * while keep using command_print() everywhere. + */ + int len = strlen(cmd.output); + if (len && cmd.output[len - 1] == '\n') + --len; + Jim_SetResultString(context->interp, cmd.output, len); + } else { + Jim_SetEmptyResult(context->interp); + } } - Jim_DecrRefCount(context->interp, cmd.output); - + free(cmd.output); free(words); - return command_retval_set(interp, retval); + + if (retval == ERROR_OK) + return JIM_OK; + + // used by telnet server to close one connection + if (retval == ERROR_COMMAND_CLOSE_CONNECTION) + return JIM_EXIT; + + Jim_Obj *error_code = Jim_NewListObj(context->interp, NULL, 0); + Jim_ListAppendElement(context->interp, error_code, Jim_NewStringObj(context->interp, "OpenOCD", -1)); + Jim_ListAppendElement(context->interp, error_code, Jim_NewIntObj(context->interp, retval)); + Jim_SetGlobalVariableStr(context->interp, "errorCode", error_code); + + return JIM_ERR; } int command_run_line(struct command_context *context, char *line) @@ -484,7 +501,6 @@ int command_run_line(struct command_context *context, char *line) * results */ /* run the line thru a script engine */ - int retval = ERROR_FAIL; int retcode; /* Beware! This code needs to be reentrant. It is also possible * for OpenOCD commands to be invoked directly from Tcl. This would @@ -499,20 +515,17 @@ int command_run_line(struct command_context *context, char *line) Jim_DeleteAssocData(interp, "context"); retcode = Jim_SetAssocData(interp, "context", NULL, context); if (retcode == JIM_OK) { - /* associated the return value */ - Jim_DeleteAssocData(interp, "retval"); - retcode = Jim_SetAssocData(interp, "retval", NULL, &retval); - if (retcode == JIM_OK) { - retcode = Jim_Eval_Named(interp, line, NULL, 0); - - Jim_DeleteAssocData(interp, "retval"); - } + retcode = Jim_Eval_Named(interp, line, NULL, 0); Jim_DeleteAssocData(interp, "context"); int inner_retcode = Jim_SetAssocData(interp, "context", NULL, old_context); if (retcode == JIM_OK) retcode = inner_retcode; } context->current_target_override = saved_target_override; + + if (retcode == JIM_RETURN) + retcode = interp->returnCode; + if (retcode == JIM_OK) { const char *result; int reslen; @@ -522,25 +535,19 @@ int command_run_line(struct command_context *context, char *line) command_output_text(context, result); command_output_text(context, "\n"); } - retval = ERROR_OK; - } else if (retcode == JIM_EXIT) { - /* ignore. - * exit(Jim_GetExitCode(interp)); */ - } else if (retcode == ERROR_COMMAND_CLOSE_CONNECTION) { - return retcode; - } else { - Jim_MakeErrorMessage(interp); - /* error is broadcast */ - LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL)); + return ERROR_OK; + } - if (retval == ERROR_OK) { - /* It wasn't a low level OpenOCD command that failed */ - return ERROR_FAIL; - } - return retval; + if (retcode == JIM_EXIT) { + // used by telnet server to close one connection + return ERROR_COMMAND_CLOSE_CONNECTION; } - return retval; + Jim_MakeErrorMessage(interp); + /* error is broadcast */ + LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL)); + + return ERROR_FAIL; } int command_run_linef(struct command_context *context, const char *format, ...) @@ -684,12 +691,16 @@ static COMMAND_HELPER(command_help_show_list, bool show_help, const char *cmd_ma #define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n)) -static void command_help_show_indent(unsigned int n) +static COMMAND_HELPER(command_help_show_indent, unsigned int n) { for (unsigned int i = 0; i < n; i++) - LOG_USER_N(" "); + command_print_sameline(CMD, " "); + + return ERROR_OK; } -static void command_help_show_wrap(const char *str, unsigned int n, unsigned int n2) + +static COMMAND_HELPER(command_help_show_wrap, + const char *str, unsigned int n, unsigned int n2) { const char *cp = str, *last = str; while (*cp) { @@ -702,11 +713,13 @@ static void command_help_show_wrap(const char *str, unsigned int n, unsigned int } while ((next - last < HELP_LINE_WIDTH(n)) && *next != '\0'); if (next - last < HELP_LINE_WIDTH(n)) cp = next; - command_help_show_indent(n); - LOG_USER("%.*s", (int)(cp - last), last); + CALL_COMMAND_HANDLER(command_help_show_indent, n); + command_print(CMD, "%.*s", (int)(cp - last), last); last = cp + 1; n = n2; } + + return ERROR_OK; } static COMMAND_HELPER(command_help_show, struct help_entry *c, @@ -725,10 +738,10 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c, if (is_match) { if (c->usage && strlen(c->usage) > 0) { char *msg = alloc_printf("%s %s", c->cmd_name, c->usage); - command_help_show_wrap(msg, n, n + 5); + CALL_COMMAND_HANDLER(command_help_show_wrap, msg, n, n + 5); free(msg); } else { - command_help_show_wrap(c->cmd_name, n, n + 5); + CALL_COMMAND_HANDLER(command_help_show_wrap, c->cmd_name, n, n + 5); } } @@ -742,16 +755,16 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c, const char *stage_msg = ""; switch (mode) { - case COMMAND_CONFIG: - stage_msg = " (configuration command)"; - break; - case COMMAND_ANY: - stage_msg = " (command valid any time)"; - break; - case COMMAND_UNKNOWN: - default: - stage_msg = " (?mode error?)"; - break; + case COMMAND_CONFIG: + stage_msg = " (configuration command)"; + break; + case COMMAND_ANY: + stage_msg = " (command valid any time)"; + break; + case COMMAND_UNKNOWN: + default: + stage_msg = " (?mode error?)"; + break; } msg = alloc_printf("%s%s", c->help ? c->help : "", stage_msg); } else @@ -762,7 +775,7 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c, return ERROR_FAIL; } - command_help_show_wrap(msg, n + 3, n + 3); + CALL_COMMAND_HANDLER(command_help_show_wrap, msg, n + 3, n + 3); free(msg); } @@ -841,7 +854,7 @@ static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *a script_debug(interp, argc, argv); struct command *c = jim_to_command(interp); - if (!c->jim_handler && !c->handler) { + if (!c->handler) { Jim_EvalObjPrefix(interp, Jim_NewStringObj(interp, "usage", -1), 1, argv); return JIM_ERR; } @@ -867,7 +880,7 @@ static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *a if (c->jim_override_target) cmd_ctx->current_target_override = c->jim_override_target; - int retval = exec_command(interp, cmd_ctx, c, argc, argv); + int retval = jim_exec_command(interp, cmd_ctx, c, argc, argv); if (c->jim_override_target) cmd_ctx->current_target_override = saved_target_override; @@ -912,19 +925,19 @@ COMMAND_HANDLER(handle_command_mode) const char *mode_str; switch (mode) { - case COMMAND_ANY: - mode_str = "any"; - break; - case COMMAND_CONFIG: - mode_str = "config"; - break; - case COMMAND_EXEC: - mode_str = "exec"; - break; - case COMMAND_UNKNOWN: - default: - mode_str = "unknown"; - break; + case COMMAND_ANY: + mode_str = "any"; + break; + case COMMAND_CONFIG: + mode_str = "config"; + break; + case COMMAND_EXEC: + mode_str = "exec"; + break; + case COMMAND_UNKNOWN: + default: + mode_str = "unknown"; + break; } command_print(CMD, "%s", mode_str); return ERROR_OK; @@ -1329,19 +1342,19 @@ COMMAND_HELPER(command_parse_str_to_buf, const char *str, void *buf, unsigned in COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label) { switch (CMD_ARGC) { - case 1: { - const char *in = CMD_ARGV[0]; - if (command_parse_bool_arg(in, out) != ERROR_OK) { - LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in); - return ERROR_COMMAND_SYNTAX_ERROR; - } - } - /* fallthrough */ - case 0: - LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled"); - break; - default: + case 1: { + const char *in = CMD_ARGV[0]; + if (command_parse_bool_arg(in, out) != ERROR_OK) { + LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in); return ERROR_COMMAND_SYNTAX_ERROR; + } + } + /* fallthrough */ + case 0: + LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled"); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } diff --git a/src/helper/command.h b/src/helper/command.h index 18fe561782..aa23574067 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -80,9 +80,14 @@ struct command_invocation { unsigned int argc; const char **argv; Jim_Obj * const *jimtcl_argv; - Jim_Obj *output; + char *output; }; +/** + * Assigned to command_invocation::output on allocation error + */ +#define CMD_PRINT_OOM ((char *)(-1L)) + /** * Return true if the command @c cmd is registered by OpenOCD. */ @@ -197,7 +202,6 @@ typedef __COMMAND_HANDLER((*command_handler_t)); struct command { char *name; command_handler_t handler; - Jim_CmdProc *jim_handler; void *jim_handler_data; /* Command handlers can use it for any handler specific data */ struct target *jim_override_target; @@ -234,7 +238,6 @@ static inline struct command *jim_to_command(Jim_Interp *interp) struct command_registration { const char *name; command_handler_t handler; - Jim_CmdProc *jim_handler; enum command_mode mode; const char *help; /** a string listing the options and arguments, required or optional */ diff --git a/src/helper/configuration.c b/src/helper/configuration.c index 16732eb3dd..447b0dfefa 100644 --- a/src/helper/configuration.c +++ b/src/helper/configuration.c @@ -71,17 +71,18 @@ char *find_file(const char *file) full_path = alloc_printf("%s", file); fp = fopen(full_path, mode); - while (!fp) { - free(full_path); - full_path = NULL; - dir = *search_dirs++; + if (script_search_dirs) + while (!fp) { + free(full_path); + full_path = NULL; + dir = *search_dirs++; - if (!dir) - break; + if (!dir) + break; - full_path = alloc_printf("%s/%s", dir, file); - fp = fopen(full_path, mode); - } + full_path = alloc_printf("%s/%s", dir, file); + fp = fopen(full_path, mode); + } if (fp) { fclose(fp); diff --git a/src/helper/fileio.c b/src/helper/fileio.c index a290a5d2ff..1059c67060 100644 --- a/src/helper/fileio.c +++ b/src/helper/fileio.c @@ -49,24 +49,24 @@ static inline int fileio_open_local(struct fileio *fileio) ssize_t file_size; switch (fileio->access) { - case FILEIO_READ: - strcpy(file_access, "r"); - break; - case FILEIO_WRITE: - strcpy(file_access, "w"); - break; - case FILEIO_READWRITE: - strcpy(file_access, "w+"); - break; - case FILEIO_APPEND: - strcpy(file_access, "a"); - break; - case FILEIO_APPENDREAD: - strcpy(file_access, "a+"); - break; - default: - LOG_ERROR("BUG: access neither read, write nor readwrite"); - return ERROR_COMMAND_SYNTAX_ERROR; + case FILEIO_READ: + strcpy(file_access, "r"); + break; + case FILEIO_WRITE: + strcpy(file_access, "w"); + break; + case FILEIO_READWRITE: + strcpy(file_access, "w+"); + break; + case FILEIO_APPEND: + strcpy(file_access, "a"); + break; + case FILEIO_APPENDREAD: + strcpy(file_access, "a+"); + break; + default: + LOG_ERROR("BUG: access neither read, write nor readwrite"); + return ERROR_COMMAND_SYNTAX_ERROR; } /* win32 always opens in binary mode */ diff --git a/src/helper/jep106.inc b/src/helper/jep106.inc index 8bbaf4ca5c..a066f0a2e4 100644 --- a/src/helper/jep106.inc +++ b/src/helper/jep106.inc @@ -2,13 +2,13 @@ /* * The manufacturer's standard identification code list appears in JEP106. - * Copyright (c) 2025 JEDEC. All rights reserved. + * Copyright (c) 2026 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 JEP106BL February 2025. */ +/* This file is aligned to revision JEP106BO May 2026. */ [0][0x01 - 1] = "AMD", [0][0x02 - 1] = "AMI", @@ -78,7 +78,7 @@ [0][0x42 - 1] = "Macronix", [0][0x43 - 1] = "Xerox", [0][0x44 - 1] = "Plus Logic", -[0][0x45 - 1] = "Western Digital Technologies Inc", +[0][0x45 - 1] = "SanDisk Technologies Inc", [0][0x46 - 1] = "Elan Circuit Tech.", [0][0x47 - 1] = "European Silicon Str.", [0][0x48 - 1] = "Apple Computer", @@ -205,7 +205,7 @@ [1][0x43 - 1] = "Suwa Electronics", [1][0x44 - 1] = "Transmeta", [1][0x45 - 1] = "Micron CMS", -[1][0x46 - 1] = "American Computer & Digital Components Inc", +[1][0x46 - 1] = "American Computer Digital Components", [1][0x47 - 1] = "Enhance 3000 Inc", [1][0x48 - 1] = "Tower Semiconductor", [1][0x49 - 1] = "CPU Design", @@ -1450,7 +1450,7 @@ [11][0x34 - 1] = "Acacia Communications", [11][0x35 - 1] = "Beijinjinshengyihe Technology Co Ltd", [11][0x36 - 1] = "Zyzyx", -[11][0x37 - 1] = "C-SKY Microsystems Co Ltd", +[11][0x37 - 1] = "C-SKY Microsystems Co Ltd (XuanTie)", [11][0x38 - 1] = "Shenzhen Hystou Technology Co Ltd", [11][0x39 - 1] = "Syzexion", [11][0x3a - 1] = "Kembona", @@ -1798,7 +1798,7 @@ [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][0x19 - 1] = "Guangdong LeapFive Technology Limited", [14][0x1a - 1] = "Jin JuQuan", [14][0x1b - 1] = "Huaxuan Technology (Shenzhen) Co Ltd", [14][0x1c - 1] = "Gigastone Corporation", @@ -1900,7 +1900,7 @@ [14][0x7c - 1] = "ForwardEdge ASIC", [14][0x7d - 1] = "Beijing Future Signet Technology Co Ltd", [14][0x7e - 1] = "Fine Made Microelectronics Group Co Ltd", -[15][0x01 - 1] = "Changxin Memory Technology (Shanghai)", +[15][0x01 - 1] = "CXSH", [15][0x02 - 1] = "Synconv", [15][0x03 - 1] = "MULTIUNIT", [15][0x04 - 1] = "Zero ASIC Corporation", @@ -1915,7 +1915,7 @@ [15][0x0d - 1] = "AUTOTALKS", [15][0x0e - 1] = "Shenzhen Ranshuo Technology Co Limited", [15][0x0f - 1] = "ScaleFlux", -[15][0x10 - 1] = "XC Memory", +[15][0x10 - 1] = "XCMemory Co Ltd", [15][0x11 - 1] = "Guangzhou Beimu Technology Co Ltd", [15][0x12 - 1] = "Rays Semiconductor Nanjing Co Ltd", [15][0x13 - 1] = "Milli-Centi Intelligence Technology Jiangsu", @@ -2049,4 +2049,167 @@ [16][0x15 - 1] = "Hangzhou Lishu Technology Co Ltd", [16][0x16 - 1] = "Tier IV Inc", [16][0x17 - 1] = "Wuhan Xuanluzhe Network Technology Co", +[16][0x18 - 1] = "EA Semi (Shanghai) Limited", +[16][0x19 - 1] = "Tech Vision Information Technology Co", +[16][0x1a - 1] = "Zhihe Computing Technology", +[16][0x1b - 1] = "Beijing Apexichips Tech", +[16][0x1c - 1] = "Yemas Holdingsl Limited", +[16][0x1d - 1] = "Eluktronics", +[16][0x1e - 1] = "Walton Digi-Tech Industries Ltd", +[16][0x1f - 1] = "Beijing Qixin Gongli Technology Co Ltd", +[16][0x20 - 1] = "M.RED", +[16][0x21 - 1] = "Shenzhen Damay Semiconductor Co Ltd", +[16][0x22 - 1] = "Corelab Tech Singapore Holding PTE LTD", +[16][0x23 - 1] = "EmBestor Technology Inc", +[16][0x24 - 1] = "XConn Technologies", +[16][0x25 - 1] = "Flagchip", +[16][0x26 - 1] = "CUNNUC", +[16][0x27 - 1] = "SGMicro", +[16][0x28 - 1] = "Lanxin Computing (Shenzhen) Technology", +[16][0x29 - 1] = "FuturePlus Systems LLC", +[16][0x2a - 1] = "Shenzhen Jielong Storage Technology Co", +[16][0x2b - 1] = "Precision Planting LLC", +[16][0x2c - 1] = "Sichuan ZeroneStor Microelectronics Tech", +[16][0x2d - 1] = "The University of Tokyo", +[16][0x2e - 1] = "Aodu (Fujian) Information Technology Co", +[16][0x2f - 1] = "Bytera Memory Inc", +[16][0x30 - 1] = "XSemitron Technology Inc", +[16][0x31 - 1] = "Cloud Ridge Ltd", +[16][0x32 - 1] = "Shenzhen XinChiTai Technology Co Ltd", +[16][0x33 - 1] = "Shenzhen Xinxin Semiconductor Co Ltd", +[16][0x34 - 1] = "Shenzhen ShineKing Electronics Co Ltd.", +[16][0x35 - 1] = "Shenzhen Shande Semiconductor Co. Ltd.", +[16][0x36 - 1] = "AheadComputing", +[16][0x37 - 1] = "Beijing Ronghua Kangweiye Technology", +[16][0x38 - 1] = "Shanghai Yunsilicon Technology Co Ltd", +[16][0x39 - 1] = "Shenzhen Wolongtai Technology Co Ltd.", +[16][0x3a - 1] = "Vervesemi Microelectronics", +[16][0x3b - 1] = "HRDWYR Ventures Private Limited", +[16][0x3c - 1] = "ENE Technology Inc", +[16][0x3d - 1] = "GOFATOO", +[16][0x3e - 1] = "Shenzhen Jingchu Technology Co Ltd", +[16][0x3f - 1] = "NEVETA", +[16][0x40 - 1] = "RZX", +[16][0x41 - 1] = "Shenzhen Zhongcheng Qingcong Technology Co", +[16][0x42 - 1] = "Shenzhen Heyloo Electronic Technology Co", +[16][0x43 - 1] = "Shenzhen Shanghaowang Electronic Technology", +[16][0x44 - 1] = "Shanghai Qimingxin Semiconductor Technology", +[16][0x45 - 1] = "Great Wall Global Information Technology", +[16][0x46 - 1] = "Beijing Memsilicon Technology Co Ltd", +[16][0x47 - 1] = "Openchip & Software Technologies S L", +[16][0x48 - 1] = "FlashLeap Tech (Shenzhen) Co Ltd", +[16][0x49 - 1] = "Shenzhen JinShanDe Technology Co Ltd", +[16][0x4a - 1] = "RUIBOHU", +[16][0x4b - 1] = "ETA Semiconductor Ltd", +[16][0x4c - 1] = "L&T Semiconductor Technologies Limited", +[16][0x4d - 1] = "RAYSMEM", +[16][0x4e - 1] = "Sichuan Zhongzhao Yongye Semiconductor", +[16][0x4f - 1] = "Shenzhen Ruiyuanchuangxin Technology", +[16][0x50 - 1] = "CSSI South Africa (Pty) Ltd", +[16][0x51 - 1] = "Jeju Semiconductor Corp", +[16][0x52 - 1] = "Origin Code LLC", +[16][0x53 - 1] = "Chengdu Masscore Microelectronics Tech", +[16][0x54 - 1] = "Shenzhen Whalekom Technology Co Ltd", +[16][0x55 - 1] = "femtoAI", +[16][0x56 - 1] = "Shanghai Chip4Tao Technology Co Ltd", +[16][0x57 - 1] = "Shenzhenshijimokkejiyouxiangongsi", +[16][0x58 - 1] = "DEGUA", +[16][0x59 - 1] = "TENGYIN CELESTIALSTORAGE", +[16][0x5a - 1] = "Shenzhen Minder Semiconductor Co Ltd", +[16][0x5b - 1] = "GUANGSUJIE", +[16][0x5c - 1] = "HVLANYN Technology", +[16][0x5d - 1] = "Theo End (Shenzhen) Computing Tech Co", +[16][0x5e - 1] = "Shenzhen Heroje Electronics Co Ltd", +[16][0x5f - 1] = "Guangdong Yuecun Microelectronics Co", +[16][0x60 - 1] = "Foxin Technology", +[16][0x61 - 1] = "JinTech Semiconductor Co Limited", +[16][0x62 - 1] = "Shenzhen Hongred Information Technology Co", +[16][0x63 - 1] = "ZST Inc", +[16][0x64 - 1] = "Veris Danismanlik Limited Sirketi", +[16][0x65 - 1] = "Starblaze", +[16][0x66 - 1] = "Siptechx", +[16][0x67 - 1] = "Djelec", +[16][0x68 - 1] = "Ambarella Corporation", +[16][0x69 - 1] = "SiliconX", +[16][0x6a - 1] = "Shenzhen Tencent Computer System Co", +[16][0x6b - 1] = "Shenzhen Econo Electronic Co Ltd (China)", +[16][0x6c - 1] = "Pu Sl Technology (Shenzhen) Co Limited", +[16][0x6d - 1] = "Shenzhen Kimviking Technology Co Ltd", +[16][0x6e - 1] = "Shenzhen Touch Think Intelligence Co Ltd", +[16][0x6f - 1] = "Beijing Institute of Open Source Chip", +[16][0x70 - 1] = "BYTE International Co Ltd", +[16][0x71 - 1] = "Shenzhen ITZR Technology Co Ltd", +[16][0x72 - 1] = "Centre Development Advanced Computing", +[16][0x73 - 1] = "Overlord Labs", +[16][0x74 - 1] = "Shenzhen Chaocun Technology Co Ltd", +[16][0x75 - 1] = "Shenzhen Yuqi Electronics Co Ltd", +[16][0x76 - 1] = "Transsemi Miceoelectronics Co Ltd", +[16][0x77 - 1] = "Pu Sl Technology (Shenzhen) Co Limited", +[16][0x78 - 1] = "Shenzhen Xingjiachen Electronics Co Ltd", +[16][0x79 - 1] = "Shenzhen Xingjiachen Electronics Co Ltd", +[16][0x7a - 1] = "Shenyang Lianxin Chuangxiang Technology", +[16][0x7b - 1] = "Plusetech Technology (Shenzhen) Co Ltd", +[16][0x7c - 1] = "ChongQing YuJia Smart Storage Digital", +[16][0x7d - 1] = "CTST Co Ltd", +[16][0x7e - 1] = "SSK Corporation", +[17][0x01 - 1] = "Shenzhen Xinruiyun Storage Technology", +[17][0x02 - 1] = "JSC Megapolis-Telecom Region", +[17][0x03 - 1] = "Minpo Corporation", +[17][0x04 - 1] = "Shenzhen Yingzhong Technology Co Ltd", +[17][0x05 - 1] = "Moment Semiconductor Inc", +[17][0x06 - 1] = "Yiweihong (Shenzhen) Electronic Technology Co", +[17][0x07 - 1] = "Shenzhen Dawei Microelectronics Technology Co", +[17][0x08 - 1] = "Shenzhen Zhuoran Electronics Co Ltd", +[17][0x09 - 1] = "Mengxw Electron Ltd", +[17][0x0a - 1] = "Origin Storage Ltd", +[17][0x0b - 1] = "Shanghai RuiPan Electronic Information Tech", +[17][0x0c - 1] = "Fortell Research Inc", +[17][0x0d - 1] = "Jiyi Semiconductor Co Ltd", +[17][0x0e - 1] = "Shenzhen Silicon Hermit Technology Ltd", +[17][0x0f - 1] = "HuiRong Electronic System Engineering Co LTD", +[17][0x10 - 1] = "ALBSEMI (Hangzhou) Co Ltd", +[17][0x11 - 1] = "ULX", +[17][0x12 - 1] = "Sichuan Huazhixincun Technology Co Ltd", +[17][0x13 - 1] = "Shenzhen Yunyue Semiconductor Co Ltd.", +[17][0x14 - 1] = "Fortune Sky Enterprise Limited", +[17][0x15 - 1] = "Shenzhen Tianchuang Weiye Technology", +[17][0x16 - 1] = "Shanghai Simchip Technology Group", +[17][0x17 - 1] = "SVOD Project SRO", +[17][0x18 - 1] = "Shenzhen Xunnaying Technology Co Ltd", +[17][0x19 - 1] = "Zhejiang Xinhan Intelligent Manufacturing", +[17][0x1a - 1] = "Shenzhen Tranvita Technology Co Ltd", +[17][0x1b - 1] = "Zhongke Zhichun (Zhuhai) Technology Co", +[17][0x1c - 1] = "Shenzhen Yunmemory AI Technology Co", +[17][0x1d - 1] = "Shenzhen KEHB Electronics Co Ltd", +[17][0x1e - 1] = "Shenzhen EVOC Storage Technology Co", +[17][0x1f - 1] = "Beijing ZhanChuang ZhenHua Technology Co", +[17][0x20 - 1] = "Sichuan Huakun Zhenyu Intelligent Technology", +[17][0x21 - 1] = "Hunan Hongen Electronics Co Ltd", +[17][0x22 - 1] = "Shenzhen Youjing Microelectronics Technology", +[17][0x23 - 1] = "Shenzhen Coosure Electronics Co Ltd", +[17][0x24 - 1] = "Seavo Future Technology (Shenzhen) Co Ltd", +[17][0x25 - 1] = "ShenZhen Goodtimes Technology Co Ltd", +[17][0x26 - 1] = "Shanxi Bluestone Guangzhi Technology Co Ltd", +[17][0x27 - 1] = "Shenzhen Lianrunfeng Electronic Technology Co", +[17][0x28 - 1] = "Shenzhen Seapiy Technology Co Ltd", +[17][0x29 - 1] = "Aivres Systems Inc", +[17][0x2a - 1] = "Liveseek", +[17][0x2b - 1] = "Shenzhen KingSpec Electronics Technology", +[17][0x2c - 1] = "Shenzhen Qiben Electronics Co Ltd", +[17][0x2d - 1] = "Guangdong Shunwei Microelectronics Tech", +[17][0x2e - 1] = "Efficient Computer", +[17][0x2f - 1] = "Shenzhen Powerleader Storage Technology", +[17][0x30 - 1] = "Shenzhen Chuangzhan Semiconductor Co Ltd", +[17][0x31 - 1] = "Shenzhen Xbnow Technology Co Ltd", +[17][0x32 - 1] = "YCHIPWAY Semiconductor Technology", +[17][0x33 - 1] = "Shenzhen Yansen Industrial Storage Co Ltd", +[17][0x34 - 1] = "ARIA Sensing Srl", +[17][0x35 - 1] = "EverModule Technology Co Ltd", +[17][0x36 - 1] = "The AIO", +[17][0x37 - 1] = "North Magna Limited", +[17][0x38 - 1] = "Unisemi Power Inc", +[17][0x39 - 1] = "Shenzhen RongPei Technology Co Ltd", +[17][0x3a - 1] = "HKIC International Electronics Limited", +[17][0x3b - 1] = "Shenzhen DTX Space Technology Co Ltd", +[17][0x3c - 1] = "Ranxin Technology", /* EOF */ diff --git a/src/helper/log.c b/src/helper/log.c index 8f7ab00397..8263cfc601 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -24,24 +24,8 @@ #include -#ifdef _DEBUG_FREE_SPACE_ -#ifdef HAVE_MALLOC_H +#if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2) #include -#else -#error "malloc.h is required to use --enable-malloc-logging" -#endif - -#ifdef __GLIBC__ -#if __GLIBC_PREREQ(2, 33) -#define FORDBLKS_FORMAT " %zu" -#else -/* glibc older than 2.33 (2021-02-01) use mallinfo(). Overwrite it */ -#define mallinfo2 mallinfo -#define FORDBLKS_FORMAT " %d" -#endif -#else -#error "GNU glibc is required to use --enable-malloc-logging" -#endif #endif int debug_level = LOG_LVL_INFO; @@ -53,16 +37,17 @@ static int64_t last_time; static int64_t start; -static const char * const log_strings[6] = { +static const char * const log_strings[7] = { "User : ", "Error: ", "Warn : ", /* want a space after each colon, all same width, colons aligned */ "Info : ", "Debug: ", - "Debug: " + "Debug: ", + "Debug: ", /* corresponds to LOG_LVL_DEBUG_USB */ }; -static int count; +static unsigned int count; /* forward the log to the listeners */ static void log_forward(const char *file, unsigned int line, const char *function, const char *string) @@ -77,6 +62,32 @@ static void log_forward(const char *file, unsigned int line, const char *functio } } +// whitespace + SIZE_MAX + zero termination +#define MEM_STR_LEN (1 + 21 + 1) +static void get_free_memory_space(char *s) +{ +#if defined(HAVE_MALLINFO2) + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_MALLOC)) { + struct mallinfo2 info = mallinfo2(); + snprintf(s, MEM_STR_LEN, " %zu", info.fordblks); + return; + } +#elif defined(HAVE_MALLINFO) + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_MALLOC)) { + struct mallinfo info = mallinfo(); +#if IS_CYGWIN + snprintf(s, MEM_STR_LEN, " %zu", info.fordblks); +#else + snprintf(s, MEM_STR_LEN, " %d", info.fordblks); +#endif + return; + } +#endif + + // empty string + *s = 0; +} + /* The log_puts() serves two somewhat different goals: * * - logging @@ -93,7 +104,7 @@ static void log_puts(enum log_levels level, const char *function, const char *string) { - char *f; + const char *f; if (!log_output) { /* log_init() not called yet; print on stderr */ @@ -113,21 +124,16 @@ static void log_puts(enum log_levels level, if (f) file = f + 1; - if (debug_level >= LOG_LVL_DEBUG) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { /* print with count and time information */ int64_t t = timeval_ms() - start; -#ifdef _DEBUG_FREE_SPACE_ - struct mallinfo2 info = mallinfo2(); -#endif - fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()" -#ifdef _DEBUG_FREE_SPACE_ - FORDBLKS_FORMAT -#endif - ": %s", log_strings[level + 1], count, t, file, line, function, -#ifdef _DEBUG_FREE_SPACE_ - info.fordblks, -#endif - string); + + char free_memory[MEM_STR_LEN]; + get_free_memory_space(free_memory); + + fprintf(log_output, "%s%u %" PRId64 " %s:%d %s()%s: %s", + log_strings[level + 1], count, t, file, line, function, + free_memory, string); } else { /* if we are using gdb through pipes then we do not want any output * to the pipe otherwise we get repeated strings */ @@ -152,10 +158,11 @@ void log_printf(enum log_levels level, char *string; va_list ap; - count++; if (level > debug_level) return; + count++; + va_start(ap, format); string = alloc_vprintf(format, ap); @@ -172,11 +179,11 @@ void log_vprintf_lf(enum log_levels level, const char *file, unsigned int line, { char *tmp; - count++; - if (level > debug_level) return; + count++; + tmp = alloc_vprintf(format, args); if (!tmp) @@ -207,18 +214,19 @@ void log_printf_lf(enum log_levels level, COMMAND_HANDLER(handle_debug_level_command) { - if (CMD_ARGC == 1) { + if (!CMD_ARGC) { + command_print(CMD, "%i", debug_level); + } else if (CMD_ARGC == 1) { int new_level; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], new_level); - if ((new_level > LOG_LVL_DEBUG_IO) || (new_level < LOG_LVL_SILENT)) { - LOG_ERROR("level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG_IO); - return ERROR_COMMAND_SYNTAX_ERROR; + if (new_level > LOG_LVL_DEBUG_USB || new_level < LOG_LVL_SILENT) { + command_print(CMD, "level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG_USB); + return ERROR_COMMAND_ARGUMENT_INVALID; } debug_level = new_level; - } else if (CMD_ARGC > 1) + } else { return ERROR_COMMAND_SYNTAX_ERROR; - - command_print(CMD, "debug_level: %i", debug_level); + } return ERROR_OK; } @@ -261,11 +269,11 @@ static const struct command_registration log_command_handlers[] = { .name = "debug_level", .handler = handle_debug_level_command, .mode = COMMAND_ANY, - .help = "Sets the verbosity level of debugging output. " + .help = "Sets or display the verbosity level of debugging output. " "0 shows errors only; 1 adds warnings; " "2 (default) adds other info; 3 adds debugging; " "4 adds extra verbose debugging.", - .usage = "number", + .usage = "[number]", }, COMMAND_REGISTRATION_DONE }; @@ -353,6 +361,8 @@ char *alloc_vprintf(const char *fmt, va_list ap) int len; char *string; + assert(fmt); + /* determine the length of the buffer needed */ va_copy(ap_copy, ap); len = vsnprintf(NULL, 0, fmt, ap_copy); @@ -361,7 +371,8 @@ char *alloc_vprintf(const char *fmt, va_list ap) /* allocate and make room for terminating zero. */ /* FIXME: The old version always allocated at least one byte extra and * other code depend on that. They should be probably be fixed, but for - * now reserve the extra byte. */ + * now reserve the extra byte. Apparently the last user of such hack is + * log_vprintf_lf() that adds a trailing newline. */ string = malloc(len + 2); if (!string) return NULL; @@ -519,7 +530,7 @@ void log_socket_error(const char *socket_desc) const char *find_nonprint_char(const char *buf, unsigned int buf_len) { for (unsigned int i = 0; i < buf_len; i++) { - if (!isprint(buf[i])) + if (!isprint((unsigned char)buf[i])) return buf + i; } return NULL; diff --git a/src/helper/log.h b/src/helper/log.h index ac24f8e833..01917abe23 100644 --- a/src/helper/log.h +++ b/src/helper/log.h @@ -15,6 +15,7 @@ #define OPENOCD_HELPER_LOG_H #include +#include /* To achieve C99 printf compatibility in MinGW, gnu_printf should be * used for __attribute__((format( ... ))), with GCC v4.4 or later @@ -36,6 +37,13 @@ * LOG_LVL_INFO - state information, etc. * LOG_LVL_DEBUG - debug statements, execution trace * LOG_LVL_DEBUG_IO - verbose debug, low-level I/O trace + * LOG_LVL_DEBUG_USB - verbose USB trace + * In the past this corresponded to build configuration options + --enable-verbose and --enable-verbose-usb-comms. + * LOG_LVL_DEBUG_MALLOC - log messages will include the amount of free heap space + * maintained by malloc in its free list, if mallinfo is available. + * In the past this corresponded to build configuration + * option --enable-malloc-logging. */ enum log_levels { LOG_LVL_SILENT = -3, @@ -46,6 +54,10 @@ enum log_levels { LOG_LVL_INFO = 2, LOG_LVL_DEBUG = 3, LOG_LVL_DEBUG_IO = 4, + // LOG_LVL_DEBUG_USB and LOG_LVL_DEBUG_MALLOC have the same value at the moment. + // In the future, these logging categories will be individually switchable. + LOG_LVL_DEBUG_USB = 5, + LOG_LVL_DEBUG_MALLOC = 5, }; void log_printf(enum log_levels level, const char *file, unsigned int line, @@ -86,9 +98,9 @@ int log_add_callback(log_callback_fn fn, void *priv); int log_remove_callback(log_callback_fn fn, void *priv); char *alloc_vprintf(const char *fmt, va_list ap) - __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 0))); + __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 0))) __nonnull((1)); char *alloc_printf(const char *fmt, ...) - __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 2))); + __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 2))) __nonnull((1)); const char *find_nonprint_char(const char *buf, unsigned int buf_len); @@ -99,17 +111,19 @@ extern int debug_level; #define LOG_LEVEL_IS(FOO) ((debug_level) >= (FOO)) +#define LOG_DEBUG_USB(expr, ...) LOG_CUSTOM_LEVEL(LOG_LVL_DEBUG_USB, expr, ##__VA_ARGS__) + #define LOG_DEBUG_IO(expr ...) \ do { \ - if (debug_level >= LOG_LVL_DEBUG_IO) \ - log_printf_lf(LOG_LVL_DEBUG, \ + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) \ + log_printf_lf(LOG_LVL_DEBUG_IO, \ __FILE__, __LINE__, __func__, \ expr); \ } while (0) #define LOG_DEBUG(expr ...) \ do { \ - if (debug_level >= LOG_LVL_DEBUG) \ + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) \ log_printf_lf(LOG_LVL_DEBUG, \ __FILE__, __LINE__, __func__, \ expr); \ @@ -118,7 +132,7 @@ extern int debug_level; #define LOG_CUSTOM_LEVEL(level, expr ...) \ do { \ enum log_levels _level = level; \ - if (debug_level >= _level) \ + if (LOG_LEVEL_IS(_level)) \ log_printf_lf(_level, \ __FILE__, __LINE__, __func__, \ expr); \ diff --git a/src/helper/options.c b/src/helper/options.c index 735b8af5f6..9eb26a4762 100644 --- a/src/helper/options.c +++ b/src/helper/options.c @@ -151,7 +151,7 @@ static char *find_relative_path(const char *from, const char *to) while (from[0] != '\0') { if (from[0] != '/') i++; - char *next = strchr(from, '/'); + const char *next = strchr(from, '/'); if (!next) break; from = next + 1; @@ -277,44 +277,44 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) break; switch (c) { - case 0: - break; - case 'h': /* --help | -h */ - help_flag = 1; - break; - case 'v': /* --version | -v */ - version_flag = 1; - break; - case 'f': /* --file | -f */ - { - char *command = alloc_printf("script {%s}", optarg); - add_config_command(command); - free(command); - break; - } - case 's': /* --search | -s */ - add_script_search_dir(optarg); - break; - case 'd': /* --debug | -d */ - { - int retval = command_run_linef(cmd_ctx, "debug_level %s", optarg ? optarg : "3"); - if (retval != ERROR_OK) - return retval; - break; - } - case 'l': /* --log_output | -l */ - { - int retval = command_run_linef(cmd_ctx, "log_output %s", optarg); - if (retval != ERROR_OK) - return retval; - break; - } - case 'c': /* --command | -c */ - add_config_command(optarg); - break; - default: /* '?' */ - /* getopt will emit an error message, all we have to do is bail. */ - return ERROR_FAIL; + case 0: + break; + case 'h': /* --help | -h */ + help_flag = 1; + break; + case 'v': /* --version | -v */ + version_flag = 1; + break; + case 'f': /* --file | -f */ + { + char *command = alloc_printf("script {%s}", optarg); + add_config_command(command); + free(command); + break; + } + case 's': /* --search | -s */ + add_script_search_dir(optarg); + break; + case 'd': /* --debug | -d */ + { + int retval = command_run_linef(cmd_ctx, "debug_level %s", optarg ? optarg : "3"); + if (retval != ERROR_OK) + return retval; + break; + } + case 'l': /* --log_output | -l */ + { + int retval = command_run_linef(cmd_ctx, "log_output %s", optarg); + if (retval != ERROR_OK) + return retval; + break; + } + case 'c': /* --command | -c */ + add_config_command(optarg); + break; + default: /* '?' */ + /* getopt will emit an error message, all we have to do is bail. */ + return ERROR_FAIL; } } diff --git a/src/helper/replacements.c b/src/helper/replacements.c index 782d975184..de7ee84ec6 100644 --- a/src/helper/replacements.c +++ b/src/helper/replacements.c @@ -19,6 +19,7 @@ #define IN_REPLACEMENTS_C #include "replacements.h" +#include #include #include @@ -58,51 +59,6 @@ void *fill_malloc(size_t size) #include #endif -/* replacements for gettimeofday */ -#ifndef HAVE_GETTIMEOFDAY - -/* Windows */ -#ifdef _WIN32 - -#ifndef __GNUC__ -#define EPOCHFILETIME (116444736000000000i64) -#else -#define EPOCHFILETIME (116444736000000000LL) -#endif - -int gettimeofday(struct timeval *tv, struct timezone *tz) -{ - FILETIME ft; - LARGE_INTEGER li; - __int64 t; - static int tzflag; - - if (tv) { - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = li.QuadPart; /* In 100-nanosecond intervals */ - t -= EPOCHFILETIME; /* Offset to the Epoch time */ - t /= 10; /* In microseconds */ - tv->tv_sec = (long)(t / 1000000); - tv->tv_usec = (long)(t % 1000000); - } - - if (tz) { - if (!tzflag) { - _tzset(); - tzflag++; - } - tz->tz_minuteswest = _timezone / 60; - tz->tz_dsttime = _daylight; - } - - return 0; -} -#endif /* _WIN32 */ - -#endif /* HAVE_GETTIMEOFDAY */ - #ifndef HAVE_STRNLEN size_t strnlen(const char *s, size_t maxlen) { @@ -126,6 +82,12 @@ char *strndup(const char *s, size_t n) #endif #ifdef _WIN32 + +static bool safe_fd_isset(int fd, fd_set *set) +{ + return set && OCD_FD_ISSET(fd, set); +} + int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv) { DWORD ms_total, limit; @@ -138,8 +100,6 @@ 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 && FD_ISSET(fd, set)) - /* calculate how long we need to wait in milliseconds */ if (!tv) ms_total = INFINITE; @@ -152,19 +112,34 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time FD_ZERO(&sock_write); FD_ZERO(&sock_except); + /* On Windows, if all provided sets are empty/NULL an error code of -1 is returned + * and WSAGetLastError() returns WSAEINVAL instead of delaying. + * We check for this case, delay and return 0 instead of calling select(). */ + if (rfds && rfds->fd_count == 0) + rfds = NULL; + if (wfds && wfds->fd_count == 0) + wfds = NULL; + if (efds && efds->fd_count == 0) + efds = NULL; + if (!rfds && !wfds && !efds && tv) { + sleep(tv->tv_sec); + usleep(tv->tv_usec); + return 0; + } + /* build an array of handles for non-sockets */ for (i = 0; i < max_fd; i++) { - if (SAFE_FD_ISSET(i, rfds) || SAFE_FD_ISSET(i, wfds) || SAFE_FD_ISSET(i, efds)) { + if (safe_fd_isset(i, rfds) || safe_fd_isset(i, wfds) || safe_fd_isset(i, efds)) { intptr_t handle = (intptr_t) _get_osfhandle(i); handles[n_handles] = (HANDLE)handle; if (handles[n_handles] == INVALID_HANDLE_VALUE) { /* socket */ - if (SAFE_FD_ISSET(i, rfds)) - FD_SET(i, &sock_read); - if (SAFE_FD_ISSET(i, wfds)) - FD_SET(i, &sock_write); - if (SAFE_FD_ISSET(i, efds)) - FD_SET(i, &sock_except); + if (safe_fd_isset(i, rfds)) + OCD_FD_SET(i, &sock_read); + if (safe_fd_isset(i, wfds)) + OCD_FD_SET(i, &sock_write); + if (safe_fd_isset(i, efds)) + OCD_FD_SET(i, &sock_except); if (i > sock_max_fd) sock_max_fd = i; } else { @@ -227,7 +202,7 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time retcode = 0; for (i = 0; i < n_handles; i++) { if (WaitForSingleObject(handles[i], 0) == WAIT_OBJECT_0) { - if (SAFE_FD_ISSET(handle_slot_to_fd[i], rfds)) { + if (safe_fd_isset(handle_slot_to_fd[i], rfds)) { DWORD bytes; intptr_t handle = (intptr_t) _get_osfhandle( handle_slot_to_fd[i]); @@ -236,20 +211,20 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time NULL, &bytes, NULL)) { /* check to see if gdb pipe has data available */ if (bytes) { - FD_SET(handle_slot_to_fd[i], &aread); + OCD_FD_SET(handle_slot_to_fd[i], &aread); retcode++; } } else { - FD_SET(handle_slot_to_fd[i], &aread); + OCD_FD_SET(handle_slot_to_fd[i], &aread); retcode++; } } - if (SAFE_FD_ISSET(handle_slot_to_fd[i], wfds)) { - FD_SET(handle_slot_to_fd[i], &awrite); + if (safe_fd_isset(handle_slot_to_fd[i], wfds)) { + OCD_FD_SET(handle_slot_to_fd[i], &awrite); retcode++; } - if (SAFE_FD_ISSET(handle_slot_to_fd[i], efds)) { - FD_SET(handle_slot_to_fd[i], &aexcept); + if (safe_fd_isset(handle_slot_to_fd[i], efds)) { + OCD_FD_SET(handle_slot_to_fd[i], &aexcept); retcode++; } } diff --git a/src/helper/replacements.h b/src/helper/replacements.h index ecc0e5e955..c48bc79a87 100644 --- a/src/helper/replacements.h +++ b/src/helper/replacements.h @@ -51,21 +51,6 @@ struct timeval { #endif -/* gettimeofday() */ -#ifndef HAVE_GETTIMEOFDAY - -#ifdef _WIN32 -struct timezone { - int tz_minuteswest; - int tz_dsttime; -}; -#endif -struct timezone; - -int gettimeofday(struct timeval *tv, struct timezone *tz); - -#endif - void *clear_malloc(size_t size); void *fill_malloc(size_t size); @@ -141,6 +126,7 @@ struct sockaddr_un { #endif #if IS_MINGW == 1 +#if defined(__x86_64__) || defined(__i386__) static inline unsigned char inb(unsigned short int port) { unsigned char _v; @@ -152,6 +138,7 @@ static inline void outb(unsigned char value, unsigned short int port) { __asm__ __volatile__ ("outb %b0,%w1" : : "a" (value), "Nd" (port)); } +#endif /* mingw does not have ffs, so use gcc builtin types */ #define ffs __builtin_ffs @@ -162,6 +149,18 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time #endif /* _WIN32 */ +/* Socket descriptor is unsigned on Windows. + * Add a cast to prevent sign mismatch warnings (-Wsign-compare). */ +#ifdef _WIN32 +#define OCD_FD_SET(fd, set) FD_SET((SOCKET)(fd), (set)) +#define OCD_FD_CLR(fd, set) FD_CLR((SOCKET)(fd), (set)) +#define OCD_FD_ISSET(fd, set) FD_ISSET((SOCKET)(fd), (set)) +#else +#define OCD_FD_SET(fd, set) FD_SET((fd), (set)) +#define OCD_FD_CLR(fd, set) FD_CLR((fd), (set)) +#define OCD_FD_ISSET(fd, set) FD_ISSET((fd), (set)) +#endif + /* generic socket functions for Windows and Posix */ static inline int write_socket(int handle, const void *buffer, unsigned int count) { @@ -225,6 +224,20 @@ static inline int socket_select(int max_fd, #endif } +static inline int socket_recv_timeout(int fd, unsigned long timeout_msec) +{ +#ifdef _WIN32 + DWORD timeout = timeout_msec; + return setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, + sizeof(timeout)); +#else + struct timeval tv; + tv.tv_sec = timeout_msec / 1000; + tv.tv_usec = (timeout_msec % 1000) * 1000; + return setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv)); +#endif +} + #ifndef HAVE_ELF_H typedef uint32_t Elf32_Addr; diff --git a/src/helper/startup.tcl b/src/helper/startup.tcl index e6e76e68fd..d5926491c0 100644 --- a/src/helper/startup.tcl +++ b/src/helper/startup.tcl @@ -7,7 +7,8 @@ # Try flipping / and \ to find file if the filename does not # match the precise spelling -proc find {filename} { +# lappend _telnet_autocomplete_skip _find_internal +proc _find_internal {filename} { if {[catch {ocd_find $filename} t]==0} { return $t } @@ -20,6 +21,65 @@ proc find {filename} { # make sure error message matches original input string return -code error "Can't find $filename" } + +proc find {filename} { + if {[catch {_find_internal $filename} t]==0} { + return $t + } + + # Check in vendor specific folder: + + # - path/to/a/certain/vendor_config_file + # - path/to/a/certain/vendor-config_file + # replaced either with + # - path/to/a/certain/vendor/config_file + # or + # - path/to/a/certain/vendor/config-file + regsub {([/\\])([^/\\_-]*)[_-]([^/\\]*$)} $filename "\\1\\2\\1\\3" f + if {[catch {_find_internal $f} t]==0} { + echo "WARNING: '$filename' is deprecated, use '$f' instead" + return $t + } + regsub {([/\\])([^/\\_]*)_([^/\\]*$)} $f "\\1\\2-\\3" f + regsub {([/\\])([^/\\_]*)_([^/\\]*$)} $f "\\1\\2-\\3" f + if {[catch {_find_internal $f} t]==0} { + echo "WARNING: '$filename' is deprecated, use '$f' instead" + return $t + } + + foreach vendor {gigadevice nordic sifive st ti} { + # - path/to/a/certain/config_file + # replaced either with + # - path/to/a/certain/${vendor}/config_file + # or + # - path/to/a/certain/${vendor}/config-file + regsub {([/\\])([^/\\]*$)} $filename "\\1$vendor\\1\\2" f + if {[catch {_find_internal $f} t]==0} { + echo "WARNING: '$filename' is deprecated, use '$f' instead" + return $t + } + regsub {([/\\])([^/\\_]*)_([^/\\]*$)} $f "\\1\\2-\\3" f + regsub {([/\\])([^/\\_]*)_([^/\\]*$)} $f "\\1\\2-\\3" f + if {[catch {_find_internal $f} t]==0} { + echo "WARNING: '$filename' is deprecated, use '$f' instead" + return $t + } + } + + # at last, check for explicit renaming + if {[catch { + source [_find_internal file_renaming.cfg] + set unixname [string map {\\ /} $filename] + regsub {^(.*/|)((board|chip|cpld|cpu|fpga|interface|target|test|tools)/.*.cfg$)} $unixname {{\1} {\2}} split + set newname [lindex $split 0][dict get $_file_renaming [lindex $split 1]] + _find_internal $newname + } t]==0} { + echo "WARNING: '$filename' is deprecated, use '$newname' instead" + return $t + } + + return -code error "Can't find $filename" +} add_usage_text find "" add_help_text find "print full path to file according to OpenOCD search rules" diff --git a/src/helper/string_choices.h b/src/helper/string_choices.h new file mode 100644 index 0000000000..7e535845da --- /dev/null +++ b/src/helper/string_choices.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_HELPER_STRING_CHOICES_H +#define OPENOCD_HELPER_STRING_CHOICES_H + +#include + +/* + * This file contains helper functions that return one of two strings depending + * on a boolean value. The format of these functions is 'str_$true_$false' where + * $true and $false are the two corresponding strings. + * + * These helper functions are beneficial because they improve code consistency + * and reduce the number of hardcoded strings. + */ + +static inline const char *str_enabled_disabled(bool value) +{ + return value ? "enabled" : "disabled"; +} + +#endif /* OPENOCD_HELPER_STRING_CHOICES_H */ diff --git a/src/helper/system.h b/src/helper/system.h index bd96d626ab..60308abcd6 100644 --- a/src/helper/system.h +++ b/src/helper/system.h @@ -39,13 +39,6 @@ #include #endif -#ifdef __ECOS -/* missing from eCos */ -#ifndef EFAULT -#define EFAULT 14 /* Bad address */ -#endif -#endif - #ifdef HAVE_NETINET_IN_H #include #endif diff --git a/src/helper/time_support.c b/src/helper/time_support.c index dda3cb3e4e..535b0626f1 100644 --- a/src/helper/time_support.c +++ b/src/helper/time_support.c @@ -15,79 +15,45 @@ #include "config.h" #endif +#include + #include "time_support.h" -/* calculate difference between two struct timeval values */ -int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) +int duration_start(struct duration *duration) { - if (x->tv_usec < y->tv_usec) { - int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; - y->tv_usec -= 1000000 * nsec; - y->tv_sec += nsec; - } - if (x->tv_usec - y->tv_usec > 1000000) { - int nsec = (x->tv_usec - y->tv_usec) / 1000000; - y->tv_usec += 1000000 * nsec; - y->tv_sec -= nsec; - } - - result->tv_sec = x->tv_sec - y->tv_sec; - result->tv_usec = x->tv_usec - y->tv_usec; - - /* Return 1 if result is negative. */ - return x->tv_sec < y->tv_sec; -} + int64_t now = timeval_ms(); -int timeval_add_time(struct timeval *result, long sec, long usec) -{ - result->tv_sec += sec; - result->tv_usec += usec; + if (now < 0) + return ERROR_FAIL; - while (result->tv_usec > 1000000) { - result->tv_usec -= 1000000; - result->tv_sec++; - } + duration->start_ms = now; - return 0; + return ERROR_OK; } -/* compare two timevals and return -1/0/+1 accordingly */ -int timeval_compare(const struct timeval *x, const struct timeval *y) +int duration_measure(struct duration *duration) { - if (x->tv_sec < y->tv_sec) - return -1; - else if (x->tv_sec > y->tv_sec) - return 1; - else if (x->tv_usec < y->tv_usec) - return -1; - else if (x->tv_usec > y->tv_usec) - return 1; - else - return 0; -} + int64_t now = timeval_ms(); -int duration_start(struct duration *duration) -{ - return gettimeofday(&duration->start, NULL); -} + if (now < 0) + return ERROR_FAIL; -int duration_measure(struct duration *duration) -{ - struct timeval end; - int retval = gettimeofday(&end, NULL); - if (retval == 0) - timeval_subtract(&duration->elapsed, &end, &duration->start); - return retval; + duration->elapsed_ms = now - duration->start_ms; + + return ERROR_OK; } float duration_elapsed(const struct duration *duration) { - float t = duration->elapsed.tv_sec; - t += (float)duration->elapsed.tv_usec / 1000000.0; - return t; + return ((float)duration->elapsed_ms) / 1000; } float duration_kbps(const struct duration *duration, size_t count) { - return count / (1024.0 * duration_elapsed(duration)); + int64_t elapsed_ms = duration->elapsed_ms; + + if (elapsed_ms == 0) + elapsed_ms = 1; + + return 1000 * count / (1024 * (float)elapsed_ms); } diff --git a/src/helper/time_support.h b/src/helper/time_support.h index c984296819..36d08c4431 100644 --- a/src/helper/time_support.h +++ b/src/helper/time_support.h @@ -21,16 +21,12 @@ #include #endif -int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y); -int timeval_add_time(struct timeval *result, long sec, long usec); -int timeval_compare(const struct timeval *x, const struct timeval *y); - /** @returns gettimeofday() timeval as 64-bit in ms */ int64_t timeval_ms(void); struct duration { - struct timeval start; - struct timeval elapsed; + int64_t start_ms; + int64_t elapsed_ms; }; /** Update the duration->start field to start the @a duration measurement. */ diff --git a/src/helper/time_support_common.c b/src/helper/time_support_common.c index 9d17a315bf..6d78c1f42f 100644 --- a/src/helper/time_support_common.c +++ b/src/helper/time_support_common.c @@ -9,6 +9,9 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * + * * + * Copyright (C) 2026 by Grant Ramsay * + * grant.ramsay@hotmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -17,14 +20,44 @@ #include "time_support.h" +#ifdef _WIN32 +#include +#endif + /* simple and low overhead fetching of ms counter. Use only * the difference between ms counters returned from this fn. + * Use QueryPerformanceCounter for Windows, else + * clock_gettime with CLOCK_MONOTONIC_RAW if available, else + * clock_gettime with CLOCK_MONOTONIC if available, else + * fallback to gettimeofday (susceptible to NTP adjustments) */ int64_t timeval_ms(void) { +#ifdef _WIN32 + static LARGE_INTEGER frequency; + LARGE_INTEGER now; + // frequency is static and only read once on the first call + if (frequency.QuadPart == 0 && !QueryPerformanceFrequency(&frequency)) + return -1; + if (!QueryPerformanceCounter(&now)) + return -1; + return (now.QuadPart * 1000) / frequency.QuadPart; +#elif defined(HAVE_CLOCK_GETTIME) +#ifdef CLOCK_MONOTONIC_RAW + clockid_t clk_id = CLOCK_MONOTONIC_RAW; +#else + clockid_t clk_id = CLOCK_MONOTONIC; +#endif + struct timespec now; + int retval = clock_gettime(clk_id, &now); + if (retval < 0) + return retval; + return (int64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000; +#else struct timeval now; int retval = gettimeofday(&now, NULL); if (retval < 0) return retval; return (int64_t)now.tv_sec * 1000 + now.tv_usec / 1000; +#endif } diff --git a/src/helper/types.h b/src/helper/types.h index 53249e5b79..8b02d213b1 100644 --- a/src/helper/types.h +++ b/src/helper/types.h @@ -51,7 +51,7 @@ * Compute the number of elements of a variable length array. * * const char *strs[] = { "a", "b", "c" }; - * unsigned num_strs = ARRAY_SIZE(strs); + * size_t num_strs = ARRAY_SIZE(strs); * */ #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) @@ -276,62 +276,6 @@ static inline int parity_u32(uint32_t x) #endif } -#if defined(__ECOS) - -/* eCos plain lacks these definition... A series of upstream patches - * could probably repair it, but it seems like too much work to be - * worth it. - */ - -#if !defined(_STDINT_H) -#define PRId32 "d" -#define PRIi32 "i" -#define PRIo32 "o" -#define PRIu32 "u" -#define PRIx32 "x" -#define PRIX32 "X" -#define SCNx32 "x" -#define PRId8 PRId32 -#define SCNx64 "llx" -#define PRId64 "lld" -#define PRIi64 "lli" -#define PRIo64 "llo" -#define PRIu64 "llu" -#define PRIx64 "llx" -#define PRIX64 "llX" - -typedef CYG_ADDRWORD intptr_t; -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; -#define INT8_MAX 0x7f -#define INT8_MIN (-INT8_MAX - 1) -# define UINT8_MAX (255) -#define INT16_MAX 0x7fff -#define INT16_MIN (-INT16_MAX - 1) -# define UINT16_MAX (65535) -#define INT32_MAX 0x7fffffffL -#define INT32_MIN (-INT32_MAX - 1L) -# define UINT32_MAX (4294967295U) -#define INT64_MAX 0x7fffffffffffffffLL -#define INT64_MIN (-INT64_MAX - 1LL) -#define UINT64_MAX (__CONCAT(INT64_MAX, U) * 2ULL + 1ULL) -#endif - - #ifndef LLONG_MAX - #define ULLONG_MAX UINT64_C(0xFFFFFFFFFFFFFFFF) - #define LLONG_MAX INT64_C(0x7FFFFFFFFFFFFFFF) - #define LLONG_MIN ULLONG_MAX - #endif - - -#define ULLONG_MAX 18446744073709551615 - -/* C99, eCos is C90 compliant (with bits of C99) */ -#define isblank(c) ((c) == ' ' || (c) == '\t') - - -#endif - typedef uint64_t target_addr_t; #define TARGET_ADDR_MAX UINT64_MAX #define TARGET_PRIdADDR PRId64 diff --git a/src/helper/util.c b/src/helper/util.c index 2e9f6155ee..1ced8bd5f4 100644 --- a/src/helper/util.c +++ b/src/helper/util.c @@ -40,3 +40,26 @@ int util_init(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, util_command_handlers); } + +bool is_memory_regions_overlap(target_addr_t start1, + unsigned int size1, + target_addr_t start2, + unsigned int size2) +{ + /* Two memory regions: [S1,E1] and [S2,E2] where: + * E1 = S1 + size1 - 1, E2 = S2 + size2 - 1 + * + * After normalization: + * Region 1: [0, size1 - 1] + * Region 2: [start2 - start1, (start2 - start1) + size2 - 1] + * + * Intersection cases: + * 1. Normalized region 2 wraps around 0 (unsigned overflow) + * 2. Start of normalized region 2 is within region 1 + */ + start2 -= start1; + target_addr_t end1 = size1 - 1; + target_addr_t end2 = start2 + size2 - 1; + + return start2 > end2 || start2 <= end1; +} diff --git a/src/helper/util.h b/src/helper/util.h index 3ccdc4fdfe..c101356784 100644 --- a/src/helper/util.h +++ b/src/helper/util.h @@ -10,5 +10,7 @@ struct command_context; int util_init(struct command_context *cmd_ctx); +bool is_memory_regions_overlap(target_addr_t start1, unsigned int size1, + target_addr_t start2, unsigned int size2); #endif /* OPENOCD_HELPER_UTIL_H */ diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 6785a74ef1..dcdc047f31 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -34,12 +34,18 @@ enum adapter_clk_mode { #define DEFAULT_CLOCK_SPEED_KHZ 100U +#define MAX_USB_IDS 16 + /** * Adapter configuration */ static struct { bool adapter_initialized; char *usb_location; + // vid = pid = 0 marks the end of the list. + uint16_t usb_vids[MAX_USB_IDS + 1]; + uint16_t usb_pids[MAX_USB_IDS + 1]; + char *product_name; char *serial; enum adapter_clk_mode clock_mode; int speed_khz; @@ -53,17 +59,19 @@ static const struct gpio_map { enum adapter_gpio_direction direction; bool permit_drive_option; bool permit_init_state_option; + bool permit_exit_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, }, + [ADAPTER_GPIO_IDX_TDO] = { "tdo", ADAPTER_GPIO_DIRECTION_INPUT, false, true, true }, + [ADAPTER_GPIO_IDX_TDI] = { "tdi", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, true }, + [ADAPTER_GPIO_IDX_TMS] = { "tms", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, true }, + [ADAPTER_GPIO_IDX_TCK] = { "tck", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, true }, + [ADAPTER_GPIO_IDX_SWDIO] = { "swdio", ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL, true, true, true }, + [ADAPTER_GPIO_IDX_SWDIO_DIR] = { "swdio_dir", ADAPTER_GPIO_DIRECTION_OUTPUT, true, false, false }, + [ADAPTER_GPIO_IDX_SWCLK] = { "swclk", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, true }, + [ADAPTER_GPIO_IDX_TRST] = { "trst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, true }, + [ADAPTER_GPIO_IDX_SRST] = { "srst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, true }, + [ADAPTER_GPIO_IDX_LED] = { "led", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, true }, + [ADAPTER_GPIO_IDX_USER0] = { "user0", ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL, true, true, true }, }; static int adapter_config_khz(unsigned int khz); @@ -194,6 +202,7 @@ int adapter_quit(void) free(adapter_config.serial); free(adapter_config.usb_location); + free(adapter_config.product_name); struct jtag_tap *t = jtag_all_taps(); while (t) { @@ -269,15 +278,15 @@ int adapter_config_rclk(unsigned int fallback_speed_khz) 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; + 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; } @@ -323,11 +332,26 @@ static void adapter_usb_set_location(const char *location) } #endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ +const uint16_t *adapter_usb_get_vids(void) +{ + return adapter_config.usb_vids; +} + +const uint16_t *adapter_usb_get_pids(void) +{ + return adapter_config.usb_pids; +} + const char *adapter_usb_get_location(void) { return adapter_config.usb_location; } +const char *adapter_usb_get_product_name(void) +{ + return adapter_config.product_name; +} + bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len) { size_t path_step, string_length; @@ -613,34 +637,34 @@ COMMAND_HANDLER(handle_reset_config_command) /* minimal JTAG has neither SRST nor TRST (so that's the default) */ switch (new_cfg & (RESET_HAS_TRST | RESET_HAS_SRST)) { - case RESET_HAS_SRST: - modes[0] = "srst_only"; - break; - case RESET_HAS_TRST: - modes[0] = "trst_only"; - break; - case RESET_TRST_AND_SRST: - modes[0] = "trst_and_srst"; - break; - default: - modes[0] = "none"; - break; + case RESET_HAS_SRST: + modes[0] = "srst_only"; + break; + case RESET_HAS_TRST: + modes[0] = "trst_only"; + break; + case RESET_TRST_AND_SRST: + modes[0] = "trst_and_srst"; + break; + default: + modes[0] = "none"; + break; } /* normally SRST and TRST are decoupled; but bugs happen ... */ switch (new_cfg & (RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST)) { - case RESET_SRST_PULLS_TRST: - modes[1] = "srst_pulls_trst"; - break; - case RESET_TRST_PULLS_SRST: - modes[1] = "trst_pulls_srst"; - break; - case RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST: - modes[1] = "combined"; - break; - default: - modes[1] = "separate"; - break; + case RESET_SRST_PULLS_TRST: + modes[1] = "srst_pulls_trst"; + break; + case RESET_TRST_PULLS_SRST: + modes[1] = "trst_pulls_srst"; + break; + case RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST: + modes[1] = "combined"; + break; + default: + modes[1] = "separate"; + break; } /* TRST-less connectors include Altera, Xilinx, and minimal JTAG */ @@ -850,6 +874,7 @@ static COMMAND_HELPER(helper_adapter_gpio_print_config, enum adapter_gpio_config const char *drive = ""; const char *pull = ""; const char *init_state = ""; + const char *exit_state = ""; if (gpio_config->gpio_num == ADAPTER_GPIO_NOT_SET) { command_print(CMD, "adapter gpio %s: not configured", gpio_map[gpio_idx].name); @@ -908,9 +933,27 @@ static COMMAND_HELPER(helper_adapter_gpio_print_config, enum adapter_gpio_config } } - command_print(CMD, "adapter gpio %s (%s): num %u, chip %d, active-%s%s%s%s", + if (gpio_map[gpio_idx].permit_exit_state_option) { + switch (gpio_config->exit_state) { + case ADAPTER_GPIO_EXIT_STATE_NO_CHANGE: + exit_state = ", exit-state no-change"; + break; + case ADAPTER_GPIO_EXIT_STATE_INACTIVE: + exit_state = ", exit-state inactive"; + break; + case ADAPTER_GPIO_EXIT_STATE_ACTIVE: + exit_state = ", exit-state active"; + break; + case ADAPTER_GPIO_EXIT_STATE_INPUT: + exit_state = ", exit-state input"; + break; + } + } + + + command_print(CMD, "adapter gpio %s (%s): num %u, chip %d, active-%s%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); + drive, pull, init_state, exit_state); return ERROR_OK; } @@ -936,8 +979,8 @@ COMMAND_HANDLER(adapter_gpio_config_handler) 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; + command_print(CMD, "adapter has no gpio named %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } if (CMD_ARGC == 1) { @@ -949,7 +992,7 @@ COMMAND_HANDLER(adapter_gpio_config_handler) while (i < CMD_ARGC) { LOG_DEBUG("Processing %s", CMD_ARGV[i]); - if (isdigit(*CMD_ARGV[i])) { + if (isdigit((unsigned char)*CMD_ARGV[i])) { COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i], gpio_config->gpio_num); ++i; continue; @@ -1031,9 +1074,34 @@ COMMAND_HANDLER(adapter_gpio_config_handler) } } - LOG_ERROR("illegal option for adapter %s %s: %s", + if (gpio_map[gpio_idx].permit_exit_state_option) { + if (strcmp(CMD_ARGV[i], "-exit-no-change") == 0) { + ++i; + gpio_config->exit_state = ADAPTER_GPIO_EXIT_STATE_NO_CHANGE; + continue; + } + if (strcmp(CMD_ARGV[i], "-exit-inactive") == 0) { + ++i; + gpio_config->exit_state = ADAPTER_GPIO_EXIT_STATE_INACTIVE; + continue; + } + if (strcmp(CMD_ARGV[i], "-exit-active") == 0) { + ++i; + gpio_config->exit_state = ADAPTER_GPIO_EXIT_STATE_ACTIVE; + continue; + } + + if (gpio_map[gpio_idx].direction == ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL && + strcmp(CMD_ARGV[i], "-exit-input") == 0) { + ++i; + gpio_config->exit_state = ADAPTER_GPIO_EXIT_STATE_INPUT; + continue; + } + } + + command_print(CMD, "illegal option for adapter %s %s: %s", CMD_NAME, gpio_map[gpio_idx].name, CMD_ARGV[i]); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } /* Force swdio_dir init state to be compatible with swdio init state */ @@ -1058,7 +1126,61 @@ COMMAND_HANDLER(handle_usb_location_command) } #endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ +COMMAND_HANDLER(handle_usb_vid_pid_command) +{ + if (MAX_USB_IDS * 2 < CMD_ARGC) { + LOG_WARNING("ignoring extra IDs in 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 vid_pid configuration directive"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + unsigned int i; + for (i = 0; i < CMD_ARGC; i += 2) { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], adapter_config.usb_vids[i / 2]); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], adapter_config.usb_pids[i / 2]); + } + + /* null termination */ + adapter_config.usb_vids[i / 2] = 0; + adapter_config.usb_pids[i / 2] = 0; + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_usb_product_name_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(adapter_config.product_name); + adapter_config.product_name = NULL; + + if (*CMD_ARGV[0]) + adapter_config.product_name = strdup(CMD_ARGV[0]); + + return ERROR_OK; +} + static const struct command_registration adapter_usb_command_handlers[] = { + { + .name = "vid_pid", + .handler = &handle_usb_vid_pid_command, + .mode = COMMAND_CONFIG, + .help = "set the USB VID and PID of the USB device", + .usage = "(vid pid)*", + }, + { + .name = "product_name", + .handler = &handle_usb_product_name_command, + .mode = COMMAND_CONFIG, + .help = "set the USB product name of the USB device", + .usage = "name", + }, #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS { .name = "location", @@ -1168,7 +1290,8 @@ static const struct command_registration adapter_command_handlers[] = { "[-active-high|-active-low] " "[-push-pull|-open-drain|-open-source] " "[-pull-none|-pull-up|-pull-down]" - "[-init-inactive|-init-active|-init-input] ]", + "[-init-inactive|-init-active|-init-input] ]" + "[-exit-no-change|-exit-inactive|-exit-active|-exit-input] ]", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/adapter.h b/src/jtag/adapter.h index 556952f8d7..c22ac53fe1 100644 --- a/src/jtag/adapter.h +++ b/src/jtag/adapter.h @@ -33,6 +33,14 @@ enum adapter_gpio_init_state { ADAPTER_GPIO_INIT_STATE_INPUT, }; +/** Supported exit states for GPIO */ +enum adapter_gpio_exit_state { + ADAPTER_GPIO_EXIT_STATE_NO_CHANGE, /* Should be zero so it is the default state */ + ADAPTER_GPIO_EXIT_STATE_INACTIVE, + ADAPTER_GPIO_EXIT_STATE_ACTIVE, + ADAPTER_GPIO_EXIT_STATE_INPUT, +}; + /** Supported pull directions for GPIO */ enum adapter_gpio_pull { ADAPTER_GPIO_PULL_NONE, @@ -52,6 +60,7 @@ enum adapter_gpio_config_index { ADAPTER_GPIO_IDX_SWCLK, ADAPTER_GPIO_IDX_SRST, ADAPTER_GPIO_IDX_LED, + ADAPTER_GPIO_IDX_USER0, ADAPTER_GPIO_IDX_NUM, /* must be the last item */ }; @@ -61,6 +70,7 @@ struct adapter_gpio_config { unsigned int chip_num; enum adapter_gpio_drive_mode drive; /* For outputs only */ enum adapter_gpio_init_state init_state; + enum adapter_gpio_exit_state exit_state; bool active_low; enum adapter_gpio_pull pull; }; @@ -82,9 +92,17 @@ bool is_adapter_initialized(void); /** @returns USB location string set with command 'adapter usb location' */ const char *adapter_usb_get_location(void); +/** @returns USB product name set with command 'adapter usb product_name' */ +const char *adapter_usb_get_product_name(void); + /** @returns true if USB location string is "-[.[...]]" */ bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len); +/** @returns USB VIDs set with command 'adapter usb vid_pid' */ +const uint16_t *adapter_usb_get_vids(void); +/** @returns USB PIDs set with command 'adapter usb vid_pid' */ +const uint16_t *adapter_usb_get_pids(void); + /** @returns The current adapter speed setting. */ int adapter_get_speed(int *speed); @@ -119,6 +137,8 @@ const char *adapter_gpio_get_name(enum adapter_gpio_config_index idx); */ const struct adapter_gpio_config *adapter_gpio_get_config(void); +extern struct adapter_driver *adapter_driver; + #define ADAPTER_GPIO_NOT_SET UINT_MAX #endif /* OPENOCD_JTAG_ADAPTER_H */ diff --git a/src/jtag/core.c b/src/jtag/core.c index 06fe2a428f..204c18c6b0 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -115,8 +115,6 @@ struct jtag_event_callback { /* callbacks to inform high-level handlers about JTAG state changes */ static struct jtag_event_callback *jtag_event_callbacks; -extern struct adapter_driver *adapter_driver; - void jtag_set_flush_queue_sleep(int ms) { jtag_flush_queue_sleep = ms; @@ -148,19 +146,16 @@ 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) + * It can also be masked with mask(). */ + if (!jtag_poll_en || !jtag_poll) return false; - if (!transport_is_jtag()) - return jtag_poll; - - if (!jtag_poll || jtag_trst != 0) + /* On JTAG transport it is also implicitly disabled while TRST is active */ + if (transport_is_jtag() && jtag_trst == 1) return false; - return jtag_srst == 0 || (jtag_reset_config & RESET_SRST_NO_GATING); + + /* On any transport while SRST is gating the JTAG clock or other debug HW */ + return jtag_srst != 1 || (jtag_reset_config & RESET_SRST_NO_GATING); } bool jtag_poll_get_enabled(void) @@ -559,6 +554,10 @@ void jtag_add_pathmove(unsigned int num_states, const enum tap_state *path) { enum tap_state cur_state = cmd_queue_cur_state; + // quit if there is nothing to do + if (num_states == 0) + return; + /* the last state has to be a stable state */ if (!tap_is_state_stable(path[num_states - 1])) { LOG_ERROR("BUG: TAP path doesn't finish in a stable state"); @@ -1002,60 +1001,60 @@ int default_interface_jtag_execute_queue(void) struct jtag_command *cmd = jtag_command_queue_get(); int result = adapter_driver->jtag_ops->execute_queue(cmd); - while (debug_level >= LOG_LVL_DEBUG_IO && cmd) { + while (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO) && cmd) { switch (cmd->type) { - case JTAG_SCAN: - LOG_DEBUG_IO("JTAG %s SCAN to %s", - cmd->cmd.scan->ir_scan ? "IR" : "DR", - tap_state_name(cmd->cmd.scan->end_state)); - for (unsigned int i = 0; i < cmd->cmd.scan->num_fields; i++) { - struct scan_field *field = cmd->cmd.scan->fields + i; - if (field->out_value) { - char *str = buf_to_hex_str(field->out_value, field->num_bits); - LOG_DEBUG_IO(" %ub out: %s", field->num_bits, str); - free(str); - } - if (field->in_value) { - char *str = buf_to_hex_str(field->in_value, field->num_bits); - LOG_DEBUG_IO(" %ub in: %s", field->num_bits, str); - free(str); - } + case JTAG_SCAN: + LOG_DEBUG_IO("JTAG %s SCAN to %s", + cmd->cmd.scan->ir_scan ? "IR" : "DR", + tap_state_name(cmd->cmd.scan->end_state)); + for (unsigned int i = 0; i < cmd->cmd.scan->num_fields; i++) { + struct scan_field *field = cmd->cmd.scan->fields + i; + if (field->out_value) { + char *str = buf_to_hex_str(field->out_value, field->num_bits); + LOG_DEBUG_IO(" %ub out: %s", field->num_bits, str); + free(str); } - break; - case JTAG_TLR_RESET: - LOG_DEBUG_IO("JTAG TLR RESET to %s", - tap_state_name(cmd->cmd.statemove->end_state)); - break; - case JTAG_RUNTEST: - LOG_DEBUG_IO("JTAG RUNTEST %d cycles to %s", - cmd->cmd.runtest->num_cycles, - tap_state_name(cmd->cmd.runtest->end_state)); - break; - case JTAG_RESET: - { - const char *reset_str[3] = { - "leave", "deassert", "assert" - }; - LOG_DEBUG_IO("JTAG RESET %s TRST, %s SRST", - reset_str[cmd->cmd.reset->trst + 1], - reset_str[cmd->cmd.reset->srst + 1]); + if (field->in_value) { + char *str = buf_to_hex_str(field->in_value, field->num_bits); + LOG_DEBUG_IO(" %ub in: %s", field->num_bits, str); + free(str); } - break; - case JTAG_PATHMOVE: - LOG_DEBUG_IO("JTAG PATHMOVE (TODO)"); - break; - case JTAG_SLEEP: - LOG_DEBUG_IO("JTAG SLEEP (TODO)"); - break; - case JTAG_STABLECLOCKS: - LOG_DEBUG_IO("JTAG STABLECLOCKS (TODO)"); - break; - case JTAG_TMS: - LOG_DEBUG_IO("JTAG TMS (TODO)"); - break; - default: - LOG_ERROR("Unknown JTAG command: %d", cmd->type); - break; + } + break; + case JTAG_TLR_RESET: + LOG_DEBUG_IO("JTAG TLR RESET to %s", + tap_state_name(cmd->cmd.statemove->end_state)); + break; + case JTAG_RUNTEST: + LOG_DEBUG_IO("JTAG RUNTEST %d cycles to %s", + cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + break; + case JTAG_RESET: + { + const char *reset_str[3] = { + "leave", "deassert", "assert" + }; + LOG_DEBUG_IO("JTAG RESET %s TRST, %s SRST", + reset_str[cmd->cmd.reset->trst + 1], + reset_str[cmd->cmd.reset->srst + 1]); + } + break; + case JTAG_PATHMOVE: + LOG_DEBUG_IO("JTAG PATHMOVE (TODO)"); + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("JTAG SLEEP (TODO)"); + break; + case JTAG_STABLECLOCKS: + LOG_DEBUG_IO("JTAG STABLECLOCKS (TODO)"); + break; + case JTAG_TMS: + LOG_DEBUG_IO("JTAG TMS (TODO)"); + break; + default: + LOG_ERROR("Unknown JTAG command: %d", cmd->type); + break; } cmd = cmd->next; } @@ -1586,22 +1585,22 @@ int jtag_init_inner(struct command_context *cmd_ctx) */ retval = jtag_examine_chain(); switch (retval) { - case ERROR_OK: - /* complete success */ - break; - default: - /* For backward compatibility reasons, try coping with - * configuration errors involving only ID mismatches. - * We might be able to talk to the devices. - * - * Also the device might be powered down during startup. - * - * After OpenOCD starts, we can try to power on the device - * and run a reset. - */ - LOG_ERROR("Trying to use configured scan chain anyway..."); - issue_setup = false; - break; + case ERROR_OK: + /* complete success */ + break; + default: + /* For backward compatibility reasons, try coping with + * configuration errors involving only ID mismatches. + * We might be able to talk to the devices. + * + * Also the device might be powered down during startup. + * + * After OpenOCD starts, we can try to power on the device + * and run a reset. + */ + LOG_ERROR("Trying to use configured scan chain anyway..."); + issue_setup = false; + break; } /* Now look at IR values. Problems here will prevent real diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index f10ed971ea..652ac4eb6e 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -120,8 +120,6 @@ endif if ANGIE angiedir = $(pkgdatadir)/angie DRIVERFILES += %D%/angie.c - DRIVERFILES += %D%/angie/include/msgtypes.h - EXTRA_DIST += %D%/angie/README dist_angie_DATA = %D%/angie/angie_firmware.bin dist_angie_DATA += %D%/angie/angie_bitstream.bit %C%_libocdjtagdrivers_la_LIBADD += -lm @@ -172,8 +170,8 @@ endif if LINUXSPIDEV DRIVERFILES += %D%/linuxspidev.c endif -if XLNX_PCIE_XVC -DRIVERFILES += %D%/xlnx-pcie-xvc.c +if XLNX_XVC +DRIVERFILES += %D%/xlnx-xvc.c endif if BCM2835GPIO DRIVERFILES += %D%/bcm2835gpio.c @@ -181,15 +179,17 @@ endif if OPENJTAG DRIVERFILES += %D%/openjtag.c endif +if CMSIS_DAP_CORE +DRIVERFILES += %D%/cmsis_dap.c +endif 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 +if CMSIS_DAP_TCP +DRIVERFILES += %D%/cmsis_dap_tcp.c endif if IMX_GPIO DRIVERFILES += %D%/imx_gpio.c @@ -203,6 +203,15 @@ endif if AM335XGPIO DRIVERFILES += %D%/am335xgpio.c endif +if CH347 +DRIVERFILES += %D%/ch347.c +endif +if CKLINK +DRIVERFILES += %D%/cklink.c +endif +if XVC +DRIVERFILES += %D%/xvc.c +endif DRIVERHEADERS = \ %D%/bitbang.h \ diff --git a/src/jtag/drivers/amt_jtagaccel.c b/src/jtag/drivers/amt_jtagaccel.c index 633c20413a..6f1718896e 100644 --- a/src/jtag/drivers/amt_jtagaccel.c +++ b/src/jtag/drivers/amt_jtagaccel.c @@ -332,43 +332,43 @@ static int amt_jtagaccel_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - if (cmd->cmd.reset->trst == 1) - tap_set_state(TAP_RESET); - amt_jtagaccel_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %i", - cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); - amt_jtagaccel_end_state(cmd->cmd.runtest->end_state); - amt_jtagaccel_runtest(cmd->cmd.runtest->num_cycles); - break; - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - amt_jtagaccel_end_state(cmd->cmd.statemove->end_state); - amt_jtagaccel_state_move(); - break; - case JTAG_SCAN: - LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); - amt_jtagaccel_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - type = jtag_scan_type(cmd->cmd.scan); - amt_jtagaccel_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); - if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - free(buffer); - break; - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - jtag_sleep(cmd->cmd.sleep->us); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", + cmd->cmd.reset->trst, + cmd->cmd.reset->srst); + if (cmd->cmd.reset->trst == 1) + tap_set_state(TAP_RESET); + amt_jtagaccel_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %i cycles, end in %i", + cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + amt_jtagaccel_end_state(cmd->cmd.runtest->end_state); + amt_jtagaccel_runtest(cmd->cmd.runtest->num_cycles); + break; + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + amt_jtagaccel_end_state(cmd->cmd.statemove->end_state); + amt_jtagaccel_state_move(); + break; + case JTAG_SCAN: + LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); + amt_jtagaccel_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + amt_jtagaccel_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + free(buffer); + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + jtag_sleep(cmd->cmd.sleep->us); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } @@ -419,6 +419,8 @@ static int amt_jtagaccel_init(void) #endif uint8_t ar_status; + LOG_WARNING("This adapter is deprecated and support will be removed in the next release!"); + #if PARPORT_USE_PPDEV == 1 if (device_handle > 0) { LOG_ERROR("device is already opened"); diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c index 56a118eaed..fdaeeae248 100644 --- a/src/jtag/drivers/angie.c +++ b/src/jtag/drivers/angie.c @@ -1,274 +1,398 @@ // 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. * - * - * - ***************************************************************************/ +/**************************************************************************** + * File : angie.c + * Contents : Driver code for NanoXplore USB-JTAG ANGIE + * adapter hardware. + * Based on FT232R driver code by: Serge Vakulenko + * + * Copyright 2024, Ahmed BOUDJELIDA, NanoXplore SAS. + * + ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include -#include -#include -#include "helper/system.h" -#include +#if IS_CYGWIN == 1 +#include "windows.h" +#undef LOG_ERROR +#endif + +// project specific includes +#include #include #include +#include +#include "libusb_helper.h" #include #include -#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 +// system includes +#include +#include +#include +#include +#include + +/* + * Sync bit bang mode is implemented as described in FTDI Application + * Note AN232R-01: "Bit Bang Modes for the ANGIE and FT245R". + */ -/** 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 +/** + * USB endpoints. + */ +#define IN_EP 0x84 +#define OUT_EP 0x02 -/** 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 +/** + * 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 +#define CPU_RESET 0x01 /** Value to write into CPUCS to put EZ-USB ANGIE out of reset. */ -#define CPU_START 0x00 +#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 +#define FIRMWARE_ADDR 0x0000 /** Delay (in microseconds) to wait while EZ-USB performs ReNumeration. */ -#define ANGIE_RENUMERATION_DELAY_US 1500000 +#define ANGIE_RENUMERATION_DELAY_US 800000 /** Default location of ANGIE firmware image. */ -#define ANGIE_FIRMWARE_FILE PKGDATADIR "/angie/angie_firmware.bin" +#define ANGIE_FIRMWARE_FILE PKGDATADIR "/angie/angie_firmware.bin" /** Default location of ANGIE firmware image. */ -#define ANGIE_BITSTREAM_FILE PKGDATADIR "/angie/angie_bitstream.bit" +#define ANGIE_BITSTREAM_FILE PKGDATADIR "/angie/angie_bitstream.bit" + +/** + * Maximum size of a single firmware section. + * Entire EZ-USB ANGIE code space = 16kB + */ +#define ANGIE_FW_SECTION_SIZE 16384 + +/** Vendor Requests */ +#define VR_CFGOPEN 0xB0 +#define VR_DATAOUTOPEN 0xB2 + +#define ANGIE_VID 0x584E /* NX Vendor id */ +#define ANGIE_NPROG_PID 0x424E /* ANGIE non programmed */ +#define ANGIE_PROG_OOCD_PID 0x414F /* ANGIE programmed OpenOCD */ +#define ANGIE_PROG_NXB2_PID 0x4a55 /* ANGIE programmed Nxbase2 */ + +#define TCK_GPIO 0 +#define TDI_GPIO 1 +#define TDO_GPIO 2 +#define TMS_GPIO 3 +#define NTRST_GPIO 4 +#define NSYSRST_GPIO 6 -/** Maximum size of a single firmware section. Entire EZ-USB ANGIE code space = 16kB */ -#define SECTION_BUFFERSIZE 16384 +#define ANGIE_XFER_BUFFER_TOTAL_SIZE (16 * 1024) +#define ANGIE_USB_BULK_SIZE 512 -/** Tuning of OpenOCD SCAN commands split into multiple ANGIE commands. */ -#define SPLIT_SCAN_THRESHOLD 10 +/** USB timeout delay in milliseconds */ +#define ANGIE_USB_TIMEOUT_MS 1000 -/** ANGIE hardware type */ -enum angie_type { - ANGIE, +/** + * List of elements used in a multiple commands reply. + */ +struct read_queue { + struct list_head list; }; -enum angie_payload_direction { - PAYLOAD_DIRECTION_OUT, - PAYLOAD_DIRECTION_IN +/** + * Entry element used to forge a reply buffer for openocd JTAG core. + */ +struct read_queue_entry { + const struct scan_command *cmd; + int reply_buffer_offset; + uint8_t *buffer; + struct list_head list; }; -enum angie_delay_type { - DELAY_CLOCK_TCK, - DELAY_CLOCK_TMS, - DELAY_SCAN_IN, - DELAY_SCAN_OUT, - DELAY_SCAN_IO +/** + * Angie device main context + */ +struct angie { + struct libusb_device_handle *usbdev; + uint8_t xfer_buffer[ANGIE_XFER_BUFFER_TOTAL_SIZE]; + size_t xfer_buffer_len; + uint8_t reply_buffer[ANGIE_XFER_BUFFER_TOTAL_SIZE]; + size_t reply_buffer_len; + struct read_queue read_queue; }; /** - * ANGIE command (ANGIE command queue element). + * Angie device singleton + */ +struct angie *angie_handle; + +/** + * Init read queue list * - * 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(). + * @param queue: pointer on the read queue head + */ +static void angie_read_queue_init(struct read_queue *queue) +{ + INIT_LIST_HEAD(&queue->list); +} + + +/** + * Add a single entry to the read 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 + * @param queue: read queue list + * @param entry to append + */ +static void angie_read_queue_add(struct read_queue *queue, + struct read_queue_entry *entry) +{ + list_add_tail(&entry->list, &queue->list); +} + +/** + * Execute elements enqueued in the read queue list * - * The last command sets #needs_postprocessing to true. + * @param queue: read queue list + * @param device: pointer on the angie device */ -struct angie_cmd { - uint8_t id; /**< ANGIE command ID */ +static void angie_read_queue_execute(struct read_queue *queue, + struct angie *device) +{ + struct read_queue_entry *entry; + struct read_queue_entry *tmp; + + list_for_each_entry_safe(entry, tmp, &queue->list, list) { + int scan_size = jtag_scan_size(entry->cmd); + + // iterate over each bit in scan data + for (int bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { + // calculate byte index + int bytec = bit_cnt / 8; + // calculate bit mask: isolate the specific bit in corresponding byte + int bcval = 1 << (bit_cnt % 8); + // extract tdo value using index: "bit0_index + bit_cnt*2 + 1" + int val = device->reply_buffer[entry->reply_buffer_offset + bit_cnt * 2 + 1]; + if (val & (1 << TDO_GPIO)) + entry->buffer[bytec] |= bcval; + else + entry->buffer[bytec] &= ~bcval; + } + + jtag_read_buffer(entry->buffer, entry->cmd); - uint8_t *payload_out; /**< Pointer where OUT payload shall be stored */ - uint8_t payload_out_size; /**< OUT direction payload size for this command */ + list_del(&entry->list); + free(entry->buffer); + free(entry); + } +} - 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 */ +/** + * Clear the read queue list + * + * @param queue: read queue list + */ +static void angie_read_queue_clean(struct read_queue *queue) +{ + struct read_queue_entry *entry; + struct read_queue_entry *tmp; - /** Indicates if this command needs post-processing */ - bool needs_postprocessing; + list_for_each_entry_safe(entry, tmp, &queue->list, list) { + list_del(&entry->list); + free(entry->buffer); + free(entry); + } +} - /** Indicates if angie_clear_queue() should free payload_in_start */ - bool free_payload_in_start; +/** + * Flush a chunk of Angie's buffer + * + * USB write is done by configuring GPIF register on the target and calling + * a USB bulk transfer. + * Sequentially a USB read transferred is issued of the same size. + * All the operation are synchronous. + * Then the read queue list is executed once the read buffer has been retrieved. + * + * @param device: Angie device pointer + * @param xfer_size: amount of bytes to transfer + * @param offset: total bytes already sent during this transfer, this will + * offset the receive buffer accordingly + * @param bytes_sent: will contain the amount of bytes sent + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_buffer_flush_chunk(struct angie *device, + int xfer_size, + int offset, + int *bytes_sent) +{ + uint8_t gpifcnt[4]; + int sent_chunk_size = 0, bytes_received = 0; - /** Pointer to corresponding OpenOCD command for post-processing */ - struct jtag_command *cmd_origin; + if (bytes_sent) + *bytes_sent = 0; - struct angie_cmd *next; /**< Pointer to next command (linked list) */ -}; + h_u32_to_be(gpifcnt, xfer_size); -/** 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 */ -}; + int ret = jtag_libusb_control_transfer(device->usbdev, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + VR_DATAOUTOPEN, 0, 0, (char *)gpifcnt, sizeof(gpifcnt), + ANGIE_USB_TIMEOUT_MS, NULL); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to send GPIF count to target"); + return ret; + } -/**************************** 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(enum tap_state 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 ****************************/ + ret = jtag_libusb_bulk_write(device->usbdev, OUT_EP, + (char *)device->xfer_buffer + offset, + xfer_size, ANGIE_USB_TIMEOUT_MS, &sent_chunk_size); + if (ret != ERROR_OK) { + LOG_ERROR("USB bulk transfer failed"); + return ret; + } + + ret = jtag_libusb_bulk_read(device->usbdev, IN_EP, + (char *)device->reply_buffer + offset, + sent_chunk_size, ANGIE_USB_TIMEOUT_MS, &bytes_received); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read USB reply"); + return ret; + } + + if (sent_chunk_size == xfer_size && bytes_received == xfer_size) { + device->reply_buffer_len += xfer_size; + device->xfer_buffer_len -= xfer_size; + if (bytes_sent) + *bytes_sent += sent_chunk_size; + } else { + return ERROR_FAIL; + } + + return ERROR_OK; +} /** - * Opens the ANGIE device + * Flush Angie transfer buffer * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * Flush is done by chunks of 512 bytes to match hardware internal FIFOs. + * Then the read queue list is executed once the read buffer has been retrieved. + * + * @param device: Angie device pointer + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_usb_open(struct angie *device) +static int angie_buffer_flush(struct angie *device) +{ + if (device->xfer_buffer_len == 0) + return ERROR_OK; + + int total_bytes_sent = 0; + device->reply_buffer_len = 0; + + do { + int sent_chunk_size; + size_t xfer_size = MIN(device->xfer_buffer_len, ANGIE_USB_BULK_SIZE); + int ret = angie_buffer_flush_chunk(device, xfer_size, + total_bytes_sent, &sent_chunk_size); + if (ret != ERROR_OK) + return ret; + total_bytes_sent += sent_chunk_size; + } while (device->xfer_buffer_len > 0); + + angie_read_queue_execute(&device->read_queue, device); + + return ERROR_OK; +} + +/** + * Check if transfer buffer has enough remaining space for a given size. + * If the buffer is not large enough, flush it. + * + * @param device: Angie device pointer + * @param size to check + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_buffer_flush_check(struct angie *device, size_t size) +{ + if (device->xfer_buffer_len + size >= ANGIE_XFER_BUFFER_TOTAL_SIZE) + return angie_buffer_flush(device); + return ERROR_OK; +} + +/** + * Append a single byte value to the transfer buffer + * + * @param device: Angie device pointer + * @param value to append + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_buffer_append_simple(struct angie *device, uint8_t value) { - 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}; + if (device->xfer_buffer_len >= ANGIE_XFER_BUFFER_TOTAL_SIZE) { + int ret = angie_buffer_flush(device); + if (ret != ERROR_OK) + return ret; + } + device->xfer_buffer[device->xfer_buffer_len++] = value; + return ERROR_OK; +} - int ret = jtag_libusb_open(vids, pids, NULL, &usb_device_handle, NULL); +/** + * Append a bit-bang JTAG value to the transfer buffer. + * + * @param device: Angie device pointer + * @param tck value + * @param tms value + * @param tdi value + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_buffer_append(struct angie *device, int tck, int tms, int tdi) +{ + uint8_t val = (1 << NTRST_GPIO) | (1 << NSYSRST_GPIO); + if (tck) + val |= (1 << TCK_GPIO); + if (tms) + val |= (1 << TMS_GPIO); + if (tdi) + val |= (1 << TDI_GPIO); + + return angie_buffer_append_simple(device, val); +} +/** + * Open Angie USB interface + * + * @param device: Angie device pointer + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_usb_open(struct angie *device) +{ + uint16_t avids[] = { + ANGIE_VID, + ANGIE_VID, + ANGIE_VID, + 0, + }; + uint16_t apids[] = { + ANGIE_NPROG_PID, + ANGIE_PROG_OOCD_PID, + ANGIE_PROG_NXB2_PID, + 0, + }; + struct libusb_device_handle *usb_dev; + + int ret = jtag_libusb_open(avids, apids, NULL, &usb_dev, NULL); if (ret != ERROR_OK) { - LOG_ERROR("Could not find and open ANGIE"); + LOG_ERROR("Failed to open ANGIE USB interface"); return ret; } - device->usb_device_handle = usb_device_handle; - device->type = ANGIE; + device->usbdev = usb_dev; return ERROR_OK; } @@ -276,80 +400,84 @@ static int angie_usb_open(struct angie *device) /** * 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 + * @param device: Angie device pointer + * @return ERROR_OK on success, negative error code otherwise */ static int angie_usb_close(struct angie *device) { - if (device->usb_device_handle) { - if (libusb_release_interface(device->usb_device_handle, 0) != 0) { + int ret = ERROR_OK; + + if (device->usbdev) { + if (libusb_release_interface(device->usbdev, 0) != LIBUSB_SUCCESS) { LOG_ERROR("Could not release interface 0"); - return ERROR_FAIL; + ret = ERROR_FAIL; } - jtag_libusb_close(device->usb_device_handle); - device->usb_device_handle = NULL; + jtag_libusb_close(device->usbdev); + device->usbdev = NULL; } - return ERROR_OK; -} -/******************* ANGIE CPU (EZ-USB) specific functions ********************/ + return ret; +} /** * 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 device: Angie device pointer * @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 + * @return ERROR_OK on success, negative error code otherwise */ 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); + return jtag_libusb_control_transfer(device->usbdev, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, + ANGIE_USB_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. + * 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. - * 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 + * @param device: Angie device pointer + * @param address: address of the firmware section + * @param data: pointer to the data to be sent + * @param size: size of the data + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_load_firmware_and_renumerate(struct angie *device, - const char *filename, uint32_t delay_us) +static int angie_write_firmware_section(struct angie *device, uint16_t address, + uint8_t *data, size_t size) { - int ret; + int bytes_remaining = size; - /* 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 */ + // Send section data in chunks of up to 64 bytes to ANGIE + while (bytes_remaining > 0) { + int chunk_size; + int transferred; - ret = angie_load_firmware(device, filename); - if (ret != ERROR_OK) - return ret; + if (bytes_remaining > 64) + chunk_size = 64; + else + chunk_size = bytes_remaining; - ret = angie_usb_close(device); - if (ret != ERROR_OK) - return ret; + int ret = jtag_libusb_control_transfer(device->usbdev, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + REQUEST_FIRMWARE_LOAD, address, FIRMWARE_ADDR, (char *)data, + chunk_size, ANGIE_USB_TIMEOUT_MS, &transferred); - usleep(delay_us); + if (ret != ERROR_OK) + return ret; - ret = angie_usb_open(device); - if (ret != ERROR_OK) - return ret; + if (transferred != chunk_size) { + // Abort if libusb sent less data than requested + return ERROR_FAIL; + } - ret = libusb_claim_interface(angie_handle->usb_device_handle, 0); - if (ret != LIBUSB_SUCCESS) - return ERROR_FAIL; + bytes_remaining -= chunk_size; + address += chunk_size; + data += chunk_size; + } return ERROR_OK; } @@ -358,18 +486,16 @@ static int angie_load_firmware_and_renumerate(struct angie *device, * 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 + * @param device: Angie device pointer + * @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 + * @return ERROR_OK on success, negative error code otherwise */ 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); + int ret = angie_cpu_reset(device, CPU_RESET); if (ret != ERROR_OK) { LOG_ERROR("Could not halt ANGIE CPU"); return ret; @@ -384,12 +510,34 @@ static int angie_load_firmware(struct angie *device, const char *filename) return ret; } - /* Download all sections in the image to ANGIE */ + uint8_t *data = malloc(ANGIE_FW_SECTION_SIZE); + if (!data) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + // 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); + size_t size_read; + uint32_t size = angie_firmware_image.sections[i].size; + int addr = angie_firmware_image.sections[i].base_address; + + LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04" PRIx32 ")", + i, addr, size); + + ret = image_read_section(&angie_firmware_image, i, 0, + size, data, &size_read); + if (ret != ERROR_OK) + goto exit; + if (size_read != size) { + ret = ERROR_FAIL; + goto exit; + } + + ret = angie_write_firmware_section(device, addr, data, size); if (ret != ERROR_OK) { LOG_ERROR("Could not write firmware section"); - return ret; + goto exit; } } @@ -398,9 +546,52 @@ static int angie_load_firmware(struct angie *device, const char *filename) ret = angie_cpu_reset(device, CPU_START); if (ret != ERROR_OK) { LOG_ERROR("Could not restart ANGIE CPU"); - return ret; + goto exit; } +exit: + free(data); + return ret; +} + +/** + * Puts the ANGIE's EZ-USB microcontroller into reset state, downloads + * the firmware image, resumes the microcontroller and re-enumerates + * USB devices. + * + * @param device: Angie device pointer + * 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 ERROR_OK on success, negative error code otherwise + */ +static int angie_load_firmware_and_renumerate(struct angie *device, + const char *filename, + uint32_t delay_us) +{ + /* + * 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. + */ + + int 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; + + if (libusb_claim_interface(angie_handle->usbdev, 0) != LIBUSB_SUCCESS) + return ERROR_FAIL; + return ERROR_OK; } @@ -408,1982 +599,772 @@ static int angie_load_firmware(struct angie *device, const char *filename) * 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 + * @param device: Angie device pointer + * @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 + * @return ERROR_OK on success, negative error code otherwise */ static int angie_load_bitstream(struct angie *device, const char *filename) { - int ret, transferred; + int ret = ERROR_OK, 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 */ + // 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; + ret = ERROR_FAIL; + goto exit; } - /* Get the size of the bitstream file */ + // Get the size of the bitstream file fseek(bitstream_file, 0, SEEK_END); - bitstream_size = ftell(bitstream_file); + size_t bitstream_size = ftell(bitstream_file); fseek(bitstream_file, 0, SEEK_SET); - /* Allocate memory for the bitstream data */ + // 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; + ret = ERROR_FAIL; + goto exit; } - /* Read the bitstream data from the file */ + // 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; + ret = ERROR_FAIL; + goto exit; } + // CFG Open 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); + ret = jtag_libusb_control_transfer(device->usbdev, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + VR_CFGOPEN, 0, 0, (char *)gpifcnt, sizeof(gpifcnt), + ANGIE_USB_TIMEOUT_MS, &transferred); if (ret != ERROR_OK) { LOG_ERROR("Failed opencfg"); - /* Abort if libusb sent less data than requested */ - return ERROR_FAIL; + goto exit; } - /* Send the bitstream data to the microcontroller */ + // 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); + ret = jtag_libusb_bulk_write(device->usbdev, OUT_EP, bitstream_data, + bitstream_size, ANGIE_USB_TIMEOUT_MS, &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; + goto exit; } LOG_INFO("Bitstream sent successfully."); - /* Clean up */ +exit: free(bitstream_data); - fclose(bitstream_file); + if (bitstream_file) + 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; + return ret; } /** - * Send an i2c write operation to dev-board components. + * Check if Angie firmware must be updated * - * @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 + * @param device: Angie device pointer + * @return true if update is needed, false otherwise */ -static int angie_i2c_write(struct angie *device, uint8_t *i2c_data, uint8_t i2c_data_size) +static bool angie_is_firmware_needed(struct angie *device) { - 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; - } + struct libusb_device_descriptor desc; - usleep(500); + // Get String Descriptor to determine if firmware needs to be loaded + int ret = libusb_get_device_descriptor(libusb_get_device(angie_handle->usbdev), + &desc); + if (ret != LIBUSB_SUCCESS) + // Could not get descriptor -> Unconfigured or original Keil firmware + return true; + else if (desc.idProduct != ANGIE_PROG_OOCD_PID) + return true; - // 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 false; +} + +/** + * Set TAP end state + * + * @param state + */ +static void angie_set_end_state(enum tap_state 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); } - return ERROR_OK; } /** - * Configure dev-board gpio extender modules by configuring their - * register 3 and register 1 responsible for IO directions and values. + * Move TAP to given state * - * @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 + * @param device: Angie device pointer + * @param skip: number of state to skip during move + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_io_extender_config(struct angie *device, uint8_t i2c_adr, uint8_t cfg_value) +static int angie_state_move(struct angie *device, int skip) { - uint8_t ioconfig[3] = {i2c_adr, 3, cfg_value}; - int ret = angie_i2c_write(device, ioconfig, 3); + int ret; + int tms = 0; + uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + // tms_scan has 8 bits that we bitbang one by one + for (int i = skip; i < tms_count; i++) { + tms = (tms_scan >> i) & 1; + ret = angie_buffer_append(device, 0, tms, 0); + if (ret != ERROR_OK) + return ret; + ret = angie_buffer_append(device, 1, tms, 0); + if (ret != ERROR_OK) + return ret; + } + ret = angie_buffer_append(device, 0, tms, 0); if (ret != ERROR_OK) return ret; - usleep(500); - return ret; + tap_set_state(tap_get_end_state()); + + return ERROR_OK; } /** - * Send one contiguous firmware section to the ANGIE's EZ-USB microcontroller - * over the USB bus. + * Return JTAG SCAN command size in bytes * - * @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 + * @param device: Angie device pointer + * @param cmd: SCAN command + * @return size of command in the transfer buffer in bytes */ -static int angie_write_firmware_section(struct angie *device, - struct image *firmware_image, int section_index) +static int angie_jtag_scan_size(struct angie *device, + const struct scan_command *cmd) { - 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; + int cmd_size = 0; + int count = 0; - size = (uint16_t)firmware_image->sections[section_index].size; - addr = (uint16_t)firmware_image->sections[section_index].base_address; + // move to TAP_IRSHIFT or TAP_DRSHIFT state + if (cmd->ir_scan) + count = tap_get_tms_path_len(tap_get_state(), TAP_IRSHIFT); + else + count = tap_get_tms_path_len(tap_get_state(), TAP_DRSHIFT); + cmd_size += count * 2 + 1; + + // add scan size + cmd_size += jtag_scan_size(cmd) * 2; + + /* + * move to cmd specified end state + * Also, see below function + * we *KNOW* the above loop transitioned out of + * the shift state, so we skip the first state + * and move directly to the end state. + */ + if (cmd->ir_scan) + count = tap_get_tms_path_len(TAP_IRSHIFT, cmd->end_state) - 1; + else + count = tap_get_tms_path_len(TAP_DRSHIFT, cmd->end_state) - 1; + cmd_size += count * 2 + 1; - LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04" PRIx16 ")", section_index, addr, - size); + return cmd_size; +} - /* Copy section contents to local buffer */ - ret = image_read_section(firmware_image, section_index, 0, size, data, - &size_read); +/** + * Execute JTAG SCAN command + * + * @param device: Angie device pointer + * @param cmd: SCAN command + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_jtag_execute_scan(struct angie *device, + const struct scan_command *cmd) +{ + uint8_t *buffer = NULL; + LOG_DEBUG_IO("SCAN: size=%d %s scan end in %s", jtag_scan_size(cmd), + (cmd->ir_scan) ? "IR" : "DR", tap_state_name(cmd->end_state)); + if (cmd->ir_scan) { + if (tap_get_state() != TAP_IRSHIFT) + angie_set_end_state(TAP_IRSHIFT); + } else { + if (tap_get_state() != TAP_DRSHIFT) + angie_set_end_state(TAP_DRSHIFT); + } + int ret = angie_state_move(device, 0); 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(enum tap_state 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(scan_size_bytes, sizeof(uint8_t)); - - 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; - } + angie_set_end_state(cmd->end_state); + + // Execute scan + int scan_size = jtag_build_buffer(cmd, &buffer); + enum scan_type type = jtag_scan_type(cmd); + + // starting byte index + int start_offset = device->xfer_buffer_len; + + // iterate over each bit in all scan data + int tms = 0; + int tdi = 0; + for (int i = 0; i < scan_size; i++) { + // calculate tms + // if we finish shifting tdi bits : '1' , else '0' + tms = (i == scan_size - 1) ? 1 : 0; + // calculate byte index + int bytec = i / 8; + // calculate bit mask: isolate the specific bit in corresponding byte + int bcval = 1 << (i % 8); + // if type is not SCAN_IN (not just reading data) + // and the bit masked is '1' then tdi = '1' + tdi = 0; + if (type != SCAN_IN && (buffer[bytec] & bcval)) + tdi = 1; + // write tdi and tms twice in tck=0 and tck=1 + ret = angie_buffer_append(device, 0, tms, tdi); + if (ret != ERROR_OK) { + free(buffer); + return ret; + } + ret = angie_buffer_append(device, 1, tms, tdi); + if (ret != ERROR_OK) { + free(buffer); + return ret; + } + } + angie_set_end_state(cmd->end_state); + if (tap_get_state() != tap_get_end_state()) { + /* + * We *KNOW* the above loop transitioned out of + * the shift state, so we skip the first state + * and move directly to the end state. + */ + ret = angie_state_move(device, 1); if (ret != ERROR_OK) { - free(tdi_buffer_start); - free(tdo_buffer_start); + free(buffer); return ret; } } - free(tdi_buffer_start); + if (jtag_scan_type(cmd) != SCAN_OUT) { + // queue read back buffer for further processing + struct read_queue_entry *entry = malloc(sizeof(*entry)); + if (!entry) { + LOG_ERROR("Out of memory"); + free(buffer); + return ERROR_FAIL; + } - /* Set current state to the end state requested by the command */ - tap_set_state(cmd->cmd.scan->end_state); + entry->reply_buffer_offset = start_offset; + entry->cmd = cmd; + entry->buffer = buffer; + angie_read_queue_add(&device->read_queue, entry); + } else { + // built buffer won't be of later use + free(buffer); + } return ERROR_OK; } /** - * Move the TAP into the Test Logic Reset state. + * Return JTAG RUNTEST command size in bytes * - * @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 + * @param device: Angie device pointer + * @param cmd: RUNTEST command + * @return size of command in the transfer buffer in bytes */ -static int angie_queue_tlr_reset(struct angie *device, struct jtag_command *cmd) +static int angie_jtag_runtest_size(struct angie *device, + const struct runtest_command *cmd) { - int ret = angie_append_clock_tms_cmd(device, 5, 0xff); + int cmd_size = 0; - if (ret == ERROR_OK) - tap_set_state(TAP_RESET); + if (tap_get_state() != TAP_IDLE) + cmd_size += tap_get_tms_path_len(tap_get_state(), TAP_IDLE) * 2 + 1; + cmd_size += cmd->num_cycles * 2 + 1; + if (tap_get_end_state() != TAP_IDLE) + cmd_size += tap_get_tms_path_len(TAP_IDLE, tap_get_end_state()) * 2 + 1; - return ret; + return cmd_size; } /** - * Run Test. + * Execute JTAG RUNTEST command * - * 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 + * @param device: Angie device pointer + * @param cmd: SCAN command + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_queue_runtest(struct angie *device, struct jtag_command *cmd) +static int angie_jtag_execute_runtest(struct angie *device, + const struct runtest_command *cmd) { int ret; + enum tap_state saved_end_state = tap_get_end_state(); + + LOG_DEBUG_IO("RUNTEST: %d cycles", cmd->num_cycles); - /* Only perform statemove if the TAP currently isn't in the TAP_IDLE state */ + // only do a state_move when we're not already in IDLE if (tap_get_state() != TAP_IDLE) { angie_set_end_state(TAP_IDLE); - angie_queue_statemove(device); + ret = angie_state_move(device, 0); + if (ret != ERROR_OK) + return ret; } - /* Generate the clock cycles */ - ret = angie_append_clock_tck_cmd(device, cmd->cmd.runtest->num_cycles); + // execute num_cycles + for (unsigned int i = 0; i < cmd->num_cycles; i++) { + ret = angie_buffer_append(device, 0, 0, 0); + if (ret != ERROR_OK) + return ret; + ret = angie_buffer_append(device, 1, 0, 0); + if (ret != ERROR_OK) + return ret; + } + ret = angie_buffer_append(device, 0, 0, 0); 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); + // finish in end_state + angie_set_end_state(saved_end_state); + if (tap_get_state() != tap_get_end_state()) { + ret = angie_state_move(device, 0); + if (ret != ERROR_OK) + return ret; } return ERROR_OK; } /** - * Execute a JTAG_RESET command + * Execute JTAG TMS command + * Clock a bunch of TMS transitions, to change the JTAG + * state machine. * - * @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 + * @param device: Angie device pointer + * @param cmd: TMS command + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_reset(int trst, int srst) +static int angie_jtag_execute_tms(struct angie *device, + const struct tms_command *cmd) { - 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; + unsigned int num_bits = cmd->num_bits; + const uint8_t *bits = cmd->bits; - 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; + LOG_DEBUG_IO("TMS: %d bits", num_bits); - angie_clear_queue(device); + int tms = 0; + for (unsigned int i = 0; i < num_bits; i++) { + tms = ((bits[i / 8] >> (i % 8)) & 1); + int ret = angie_buffer_append(device, 0, tms, 0); + if (ret != ERROR_OK) + return ret; + ret = angie_buffer_append(device, 1, tms, 0); + if (ret != ERROR_OK) + return ret; + } - return ERROR_OK; + return angie_buffer_append(device, 0, tms, 0); } /** - * Move to one TAP state or several states in succession. + * Execute JTAG RESET command + * Control /TRST and /SYSRST pins. + * Perform immediate bitbang transaction. * - * @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 + * @param device: Angie device pointer + * @param cmd: RESET command + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_queue_pathmove(struct angie *device, struct jtag_command *cmd) +static int angie_jtag_execute_reset(struct angie *device, + const struct reset_command *cmd) { - int ret, state_count; - enum tap_state *path; - uint8_t tms_sequence; + LOG_DEBUG_IO("RESET: trst %i srst %i", cmd->trst, cmd->srst); + + uint8_t out_value = (1 << NTRST_GPIO) | (1 << NSYSRST_GPIO); + if (cmd->trst == 1 || + (cmd->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) + tap_set_state(TAP_RESET); - unsigned int num_states = cmd->cmd.pathmove->num_states; - path = cmd->cmd.pathmove->path; - state_count = 0; + if (cmd->trst == 1) + out_value &= ~(1 << NTRST_GPIO); // switch /TRST low + else if (cmd->trst == 0) + out_value |= (1 << NTRST_GPIO); // switch /TRST high - while (num_states > 0) { - unsigned int batch_size; + if (cmd->srst == 1) + out_value &= ~(1 << NSYSRST_GPIO); // switch /SYSRST low + else if (cmd->srst == 0) + out_value |= (1 << NSYSRST_GPIO); // switch /SYSRST high - tms_sequence = 0; + return angie_buffer_append_simple(device, out_value); +} - /* Determine batch size */ - if (num_states >= 8) - batch_size = 8; - else - batch_size = num_states; - - for (unsigned int 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--; - } +/** + * Execute JTAG STABLECLOCKS command + * Issues a number of clock cycles while staying in a stable state. + * Because the TMS value required to stay in the RESET state is a 1, whereas + * the TMS value required to stay in any of the other stable states is a 0, + * this function checks the current stable state to decide on the value of TMS + * to use. + * + * @param device: Angie device pointer + * @param cmd: STABLECLOCKS command + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_jtag_execute_stableclocks(struct angie *device, + const struct stableclocks_command *cmd) +{ + int tms = (tap_get_state() == TAP_RESET ? 1 : 0); - /* 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); + // send num_cycles clocks onto the cable + for (unsigned int i = 0; i < cmd->num_cycles; i++) { + int ret = angie_buffer_append(device, 1, tms, 0); + if (ret != ERROR_OK) + return ret; + ret = angie_buffer_append(device, 0, tms, 0); if (ret != ERROR_OK) return ret; } + LOG_DEBUG_IO("clocks %i while in %s", cmd->num_cycles, + tap_state_name(tap_get_state())); + return ERROR_OK; } /** - * Sleep for a specific amount of time. + * Execute JTAG STATEMOVE command * - * @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 + * @param device: Angie device pointer + * @param cmd: STATEMOVE command + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_queue_sleep(struct angie *device, struct jtag_command *cmd) +static int angie_jtag_execute_statemove(struct angie *device, + const struct statemove_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); + LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->end_state)); + angie_set_end_state(cmd->end_state); + return angie_state_move(device, 0); } /** - * Generate TCK cycles while remaining in a stable state. + * Execute JTAG PATHMOVE command * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param cmd pointer to the command that shall be executed. + * @param device: Angie device pointer + * @param cmd: PATHMOVE command + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_queue_stableclocks(struct angie *device, struct jtag_command *cmd) +static int angie_jtag_execute_pathmove(struct angie *device, + const struct pathmove_command *cmd) { int ret; - - if (!tap_is_state_stable(tap_get_state())) { - LOG_ERROR("JTAG_STABLECLOCKS: state not stable"); - return ERROR_FAIL; - } - - unsigned int 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; + int num_states = cmd->num_states; + int tms = 0; + + LOG_DEBUG_IO("pathmove: %i states, end in %s", cmd->num_states, + tap_state_name(cmd->path[cmd->num_states - 1])); + + int state_count = 0; + while (num_states) { + if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) { + tms = 0; + } else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) { + tms = 1; } else { - ret = angie_append_clock_tck_cmd(device, num_cycles); - num_cycles = 0; + LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", + tap_state_name(tap_get_state()), + tap_state_name(cmd->path[state_count])); + return ERROR_JTAG_DEVICE_ERROR; } + ret = angie_buffer_append(device, 0, tms, 0); + if (ret != ERROR_OK) + return ret; + ret = angie_buffer_append(device, 1, tms, 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; + tap_set_state(cmd->path[state_count]); + state_count++; + num_states--; } + ret = angie_buffer_append(device, 0, tms, 0); + if (ret != ERROR_OK) + return ret; - return ret; + tap_set_end_state(tap_get_state()); + + return ERROR_OK; } /** - * Perform post-processing of commands after ANGIE queue has been executed. + * Process command size in bytes * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @param cmd: JTAG command + * @return command size in the transfer buffer in bytes */ -static int angie_post_process_queue(struct angie *device) +static size_t angie_cmd_size(struct angie *device, const struct jtag_command *cmd) { - 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; + switch (cmd->type) { + case JTAG_SCAN: + return angie_jtag_scan_size(device, cmd->cmd.scan); + case JTAG_TMS: + return cmd->cmd.tms->num_bits + 2 + 1; + case JTAG_RESET: + return 1; + case JTAG_RUNTEST: + return angie_jtag_runtest_size(device, cmd->cmd.runtest); + case JTAG_STABLECLOCKS: + return cmd->cmd.stableclocks->num_cycles * 2; + case JTAG_TLR_RESET: // renamed from JTAG_STATEMOVE + return tap_get_tms_path_len(tap_get_state(), + cmd->cmd.statemove->end_state) * 2 + 1; + case JTAG_PATHMOVE: + return cmd->cmd.pathmove->num_states * 2 + 1; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + return 0; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + return 0; } - - return ERROR_OK; } -/**************************** JTAG driver functions ***************************/ - /** - * Executes the JTAG Command Queue. + * Execute JTAG commands 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 + * @param cmd_queue to execute + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_execute_queue(struct jtag_command *cmd_queue) +static int angie_jtag_execute_queue(struct jtag_command *cmd_queue) { + int retval = ERROR_OK; struct jtag_command *cmd = cmd_queue; - int ret; + struct angie *device = angie_handle; while (cmd) { + retval = angie_buffer_flush_check(device, angie_cmd_size(device, cmd)); + if (retval != ERROR_OK) + return retval; + 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; + case JTAG_SCAN: + retval = angie_jtag_execute_scan(device, cmd->cmd.scan); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_TMS: + retval = angie_jtag_execute_tms(device, cmd->cmd.tms); + if (retval != ERROR_OK) + return retval; + retval = angie_buffer_flush(device); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_RESET: + angie_jtag_execute_reset(device, cmd->cmd.reset); + retval = angie_buffer_flush(device); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_RUNTEST: + retval = angie_jtag_execute_runtest(device, cmd->cmd.runtest); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_STABLECLOCKS: + /* this is only allowed while in a stable state. A check for a stable + * state was done in jtag_add_clocks() + */ + retval = angie_jtag_execute_stableclocks(device, cmd->cmd.stableclocks); + if (retval != ERROR_OK) + return retval; + retval = angie_buffer_flush(device); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_TLR_RESET: // renamed from JTAG_STATEMOVE + retval = angie_jtag_execute_statemove(device, cmd->cmd.statemove); + if (retval != ERROR_OK) + return retval; + retval = angie_buffer_flush(device); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_PATHMOVE: + retval = angie_jtag_execute_pathmove(device, cmd->cmd.pathmove); + if (retval != ERROR_OK) + return retval; + retval = angie_buffer_flush(device); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + jtag_sleep(cmd->cmd.sleep->us); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + 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; + return angie_buffer_flush(device); } /** - * Set the TCK frequency of the ANGIE adapter. + * Angie quit method * - * @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 + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_khz(int khz, int *jtag_speed) +static int angie_quit(void) { - 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 (!angie_handle) + return ERROR_OK; + int ret = angie_usb_close(angie_handle); 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); -} + angie_read_queue_clean(&angie_handle->read_queue); -/** - * 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; + free(angie_handle); + angie_handle = NULL; return ERROR_OK; } /** - * Initiates the firmware download to the ANGIE adapter and prepares - * the USB handle. + * Angie initialization method * - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @return ERROR_OK on success, negative error code otherwise */ 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)); + int ret; + angie_handle = calloc(1, sizeof(*angie_handle)); if (!angie_handle) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; + ret = ERROR_FAIL; + goto exit; } - ret = angie_usb_open(angie_handle); - if (ret != ERROR_OK) { - free(angie_handle); - angie_handle = NULL; - return ret; - } + angie_read_queue_init(&angie_handle->read_queue); - /* 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; - } + ret = angie_usb_open(angie_handle); + if (ret != ERROR_OK) + goto exit; - if (download_firmware) { + if (angie_is_firmware_needed(angie_handle)) { 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 = libusb_claim_interface(angie_handle->usbdev, 0); + if (ret != LIBUSB_SUCCESS) { + LOG_ERROR("Failed to claim interface 0"); + ret = ERROR_FAIL; + goto exit; } + ret = angie_load_firmware_and_renumerate(angie_handle, - ANGIE_FIRMWARE_FILE, ANGIE_RENUMERATION_DELAY_US); + 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; - } + return ERROR_OK; +exit: + 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. */ +/** + * Angie set speed method + * + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_speed(int divisor) +{ + int baud = (divisor == 0) ? 3000000 : + (divisor == 1) ? 2000000 : + 3000000 / divisor; + LOG_DEBUG("angie speed(%d) rate %d bits/sec", divisor, baud); - ret = jtag_libusb_bulk_write(angie_handle->usb_device_handle, angie_handle->ep_in, - dummy, 64, 200, &transferred); + return ERROR_OK; +} - 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 set khz method + * + * @param khz + * @param divisor returned to caller + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_khz(int khz, int *divisor) +{ + if (khz == 0) { + LOG_DEBUG("RCLK not supported"); + return ERROR_FAIL; } - 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; + // Calculate frequency divisor. + if (khz > 2500) { + *divisor = 0; // Special case: 3 MHz + } else if (khz > 1700) { + *divisor = 1; // Special case: 2 MHz + } else { + *divisor = (2 * 3000 / khz + 1) / 2; + if (*divisor > 0x3FFF) + *divisor = 0x3FFF; } - - /* 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. + * Angie set speed div * - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param divisor + * @param khz returned to caller + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_quit(void) +static int angie_speed_div(int divisor, int *khz) { - int ret = angie_usb_close(angie_handle); - free(angie_handle); - angie_handle = NULL; - - return ret; + // Maximum 3 Mbaud for bit bang mode + if (divisor == 0) + *khz = 30000; + else if (divisor == 1) + *khz = 20000; + else + *khz = 30000 / divisor; + return ERROR_OK; } static struct jtag_interface angie_interface = { - .execute_queue = angie_execute_queue, + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = angie_jtag_execute_queue, }; struct adapter_driver angie_adapter_driver = { @@ -2393,7 +1374,6 @@ struct adapter_driver angie_adapter_driver = { .init = angie_init, .quit = angie_quit, - .reset = angie_reset, .speed = angie_speed, .khz = angie_khz, .speed_div = angie_speed_div, diff --git a/src/jtag/drivers/angie/README b/src/jtag/drivers/angie/README deleted file mode 100644 index c727154c48..0000000000 --- a/src/jtag/drivers/angie/README +++ /dev/null @@ -1,3 +0,0 @@ -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 index 7b3a88f7c8..71fbb85e60 100644 Binary files a/src/jtag/drivers/angie/angie_bitstream.bit 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 index 68486ef8f0..ecf2cfd513 100644 Binary files a/src/jtag/drivers/angie/angie_firmware.bin 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 deleted file mode 100644 index fb045e98c3..0000000000 --- a/src/jtag/drivers/angie/include/msgtypes.h +++ /dev/null @@ -1,172 +0,0 @@ -/* 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/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index 9d8c592edb..38c73efc2e 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -76,9 +76,7 @@ static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length); /* helper functions */ static int armjtagew_get_version_info(void); -#ifdef _DEBUG_USB_COMMS_ static void armjtagew_debug_buffer(uint8_t *buffer, int length); -#endif static struct armjtagew *armjtagew_handle; @@ -94,69 +92,68 @@ static int armjtagew_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %u cycles, end in %i", - cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %u cycles, end in %i", + cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + + armjtagew_end_state(cmd->cmd.runtest->end_state); + armjtagew_runtest(cmd->cmd.runtest->num_cycles); + break; - armjtagew_end_state(cmd->cmd.runtest->end_state); - armjtagew_runtest(cmd->cmd.runtest->num_cycles); - break; + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + armjtagew_end_state(cmd->cmd.statemove->end_state); + armjtagew_state_move(); + break; - armjtagew_end_state(cmd->cmd.statemove->end_state); - armjtagew_state_move(); - break; + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %u states, end in %i", + cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %u states, end in %i", - cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + armjtagew_path_move(cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path); + break; - armjtagew_path_move(cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path); - break; + case JTAG_SCAN: + LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); - case JTAG_SCAN: - LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); + armjtagew_end_state(cmd->cmd.scan->end_state); - armjtagew_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + LOG_DEBUG_IO("scan input, length = %d", scan_size); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - LOG_DEBUG_IO("scan input, length = %d", scan_size); + armjtagew_debug_buffer(buffer, (scan_size + 7) / 8); -#ifdef _DEBUG_USB_COMMS_ - armjtagew_debug_buffer(buffer, (scan_size + 7) / 8); -#endif - type = jtag_scan_type(cmd->cmd.scan); - armjtagew_scan(cmd->cmd.scan->ir_scan, - type, buffer, - scan_size, cmd->cmd.scan); - break; - - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - - armjtagew_tap_execute(); - - if (cmd->cmd.reset->trst == 1) - tap_set_state(TAP_RESET); - armjtagew_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - armjtagew_tap_execute(); - jtag_sleep(cmd->cmd.sleep->us); - break; - - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + type = jtag_scan_type(cmd->cmd.scan); + armjtagew_scan(cmd->cmd.scan->ir_scan, + type, buffer, + scan_size, cmd->cmd.scan); + break; + + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", + cmd->cmd.reset->trst, + cmd->cmd.reset->srst); + + armjtagew_tap_execute(); + + if (cmd->cmd.reset->trst == 1) + tap_set_state(TAP_RESET); + armjtagew_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + armjtagew_tap_execute(); + jtag_sleep(cmd->cmd.sleep->us); + break; + + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } @@ -641,9 +638,7 @@ static int armjtagew_tap_execute(void) LOG_DEBUG_IO("pending scan result, length = %d", length); -#ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(buffer, byte_length); -#endif if (jtag_read_buffer(buffer, command) != ERROR_OK) { armjtagew_tap_init(); @@ -743,9 +738,8 @@ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length) 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 + if (result != ERROR_OK) return -1; return transferred; @@ -760,29 +754,29 @@ static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length) LOG_DEBUG_IO("armjtagew_usb_read, result = %d", result); -#ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(usb_in_buffer, result); -#endif + if (result != ERROR_OK) return -1; return transferred; } -#ifdef _DEBUG_USB_COMMS_ #define BYTES_PER_LINE 16 static void armjtagew_debug_buffer(uint8_t *buffer, int length) { + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG_USB)) + return; + char line[8 + 3 * BYTES_PER_LINE + 1]; 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); + LOG_DEBUG_USB("%s", line); /* Prevent GDB timeout (writing to log might take some time) */ keep_alive(); } } -#endif diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index 1a105aac44..eccbe06b8d 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -31,28 +31,22 @@ static off_t bcm2835_peri_base = 0x20000000; #define BCM2835_GPIO_MODE_OUTPUT 1 /* GPIO setup macros */ -#define MODE_GPIO(_g) ({ \ - typeof(_g) g = (_g); \ - *(pio_base + (g / 10)) >> ((g % 10) * 3) & 7; \ -}) +#define BCM2835_GPIO_REG_READ(offset) \ + (*(pio_base + (offset))) -#define INP_GPIO(_g) do { \ - typeof(_g) g1 = (_g); \ - *(pio_base + (g1 / 10)) &= ~(7 << ((g1 % 10) * 3)); \ -} while (0) +#define BCM2835_GPIO_REG_WRITE(offset, value) \ + (*(pio_base + (offset)) = (value)) -#define SET_MODE_GPIO(_g, m) do { \ - typeof(_g) g = (_g); \ - /* clear the mode bits first, then set as necessary */ \ - INP_GPIO(g); \ - *(pio_base + (g / 10)) |= ((m) << ((g % 10) * 3)); \ -} while (0) +#define BCM2835_GPIO_SET_REG_BITS(offset, bit_mask) \ + (*(pio_base + (offset)) |= (bit_mask)) -#define OUT_GPIO(g) SET_MODE_GPIO(g, BCM2835_GPIO_MODE_OUTPUT) +#define BCM2835_GPIO_CLEAR_REG_BITS(offset, bit_mask) \ + (*(pio_base + (offset)) &= ~(bit_mask)) -#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 */ +#define BCM2835_GPIO_MODE_ADDR(gpio_pin_num) (pio_base + ((gpio_pin_num) / 10)) +#define BCM2835_GPIO_SET_ADDR(gpio_pin_num) (pio_base + 7 + ((gpio_pin_num) / 32)) +#define BCM2835_GPIO_CLR_ADDR(gpio_pin_num) (pio_base + 10 + ((gpio_pin_num) / 32)) +#define BCM2835_GPIO_LEVEL_ADDR(gpio_pin_num) (pio_base + 13 + ((gpio_pin_num) / 32)) static int dev_mem_fd; static volatile uint32_t *pio_base = MAP_FAILED; @@ -66,10 +60,75 @@ static unsigned int jtag_delay; static const struct adapter_gpio_config *adapter_gpio_config; static struct initial_gpio_state { unsigned int mode; - unsigned int output_level; + bool output_level; } initial_gpio_state[ADAPTER_GPIO_IDX_NUM]; static uint32_t initial_drive_strength_etc; +static struct { + volatile uint32_t *swdio_clr_set_addr[2]; + uint32_t swdio_mask; + volatile uint32_t *swdio_read_level_addr; + uint32_t swdio_level_shift_bits; + bool swdio_active_low; + volatile uint32_t *swdio_mode_addr; + uint32_t swdio_mode_input_mask; + uint32_t swdio_mode_output_mask; + volatile uint32_t *swclk_clr_set_addr[2]; + uint32_t swclk_mask; + volatile uint32_t *tdi_clr_set_addr[2]; + uint32_t tdi_mask; + volatile uint32_t *tms_clr_set_addr[2]; + uint32_t tms_mask; + volatile uint32_t *tck_clr_set_addr[2]; + uint32_t tck_mask; + volatile uint32_t *tdo_read_level_addr; + uint32_t tdo_level_shift_bits; + bool tdo_active_low; +} gpio_control; + +/* GPFSEL[0,5], read the function select bits of specified GPIO pin number */ +static inline unsigned int bcm2835_get_mode(unsigned int gpio_pin_num) +{ + return (BCM2835_GPIO_REG_READ((gpio_pin_num / 10)) >> ((gpio_pin_num % 10) * 3) & 7); +} + +/* GPLEV[13,14], current level of the pin */ +static inline bool bcm2835_get_level(unsigned int gpio_pin_num) +{ + return ((BCM2835_GPIO_REG_READ((13 + (gpio_pin_num / 32))) >> (gpio_pin_num % 32)) & 1); +} + +/* set GPIO pin as input */ +static inline void bcm2835_set_input(unsigned int gpio_pin_num) +{ + BCM2835_GPIO_CLEAR_REG_BITS((gpio_pin_num / 10), (7 << ((gpio_pin_num % 10) * 3))); +} + +/* clear the mode bits first, then set as necessary */ +static inline void bcm2835_set_mode(unsigned int gpio_pin_num, unsigned char mode) +{ + bcm2835_set_input(gpio_pin_num); + BCM2835_GPIO_SET_REG_BITS((gpio_pin_num / 10), (mode << ((gpio_pin_num % 10) * 3))); +} + +/* set GPIO pin as output */ +static inline void bcm2835_set_output(unsigned int gpio_pin_num) +{ + bcm2835_set_mode(gpio_pin_num, BCM2835_GPIO_MODE_OUTPUT); +} + +/* GPSET[7,8], sets bits which are 1, ignores bits which are 0 */ +static inline void bcm2835_gpio_set(unsigned int gpio_pin_num) +{ + BCM2835_GPIO_REG_WRITE((7 + (gpio_pin_num / 32)), (1 << (gpio_pin_num % 32))); +} + +/* GPCLR[10,11], clears bits which are 1, ignores bits which are 0 */ +static inline void bcm2835_gpio_clear(unsigned int gpio_pin_num) +{ + BCM2835_GPIO_REG_WRITE((10 + (gpio_pin_num / 32)), (1 << (gpio_pin_num % 32))); +} + static inline const char *bcm2835_get_mem_dev(void) { if (bcm2835_peri_mem_dev) @@ -96,7 +155,7 @@ static inline void bcm2835_delay(void) static bool is_gpio_config_valid(enum adapter_gpio_config_index idx) { /* Only chip 0 is supported, accept unset value (-1) too */ - return adapter_gpio_config[idx].gpio_num <= 31; + return adapter_gpio_config[idx].gpio_num <= 53; } static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value) @@ -105,27 +164,27 @@ static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int va switch (gpio_config->drive) { case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: if (value) - GPIO_SET = 1 << gpio_config->gpio_num; + bcm2835_gpio_set(gpio_config->gpio_num); else - GPIO_CLR = 1 << gpio_config->gpio_num; + bcm2835_gpio_clear(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); + bcm2835_set_input(gpio_config->gpio_num); } else { - GPIO_CLR = 1 << gpio_config->gpio_num; - OUT_GPIO(gpio_config->gpio_num); + bcm2835_gpio_clear(gpio_config->gpio_num); + bcm2835_set_output(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); + bcm2835_gpio_set(gpio_config->gpio_num); + bcm2835_set_output(gpio_config->gpio_num); } else { - INP_GPIO(gpio_config->gpio_num); + bcm2835_set_input(gpio_config->gpio_num); } break; } @@ -135,12 +194,12 @@ static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int va static void restore_gpio(enum adapter_gpio_config_index idx) { if (is_gpio_config_valid(idx)) { - SET_MODE_GPIO(adapter_gpio_config[idx].gpio_num, initial_gpio_state[idx].mode); + bcm2835_set_mode(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; + bcm2835_gpio_set(adapter_gpio_config[idx].gpio_num); else - GPIO_CLR = 1 << adapter_gpio_config[idx].gpio_num; + bcm2835_gpio_clear(adapter_gpio_config[idx].gpio_num); } } bcm2835_gpio_synchronize(); @@ -151,9 +210,8 @@ static void initialize_gpio(enum adapter_gpio_config_index idx) 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; + initial_gpio_state[idx].mode = bcm2835_get_mode(adapter_gpio_config[idx].gpio_num); + initial_gpio_state[idx].output_level = bcm2835_get_level(adapter_gpio_config[idx].gpio_num); 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); @@ -171,35 +229,29 @@ static void initialize_gpio(enum adapter_gpio_config_index idx) set_gpio_value(&adapter_gpio_config[idx], 1); break; case ADAPTER_GPIO_INIT_STATE_INPUT: - INP_GPIO(adapter_gpio_config[idx].gpio_num); + bcm2835_set_input(adapter_gpio_config[idx].gpio_num); 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) - OUT_GPIO(adapter_gpio_config[idx].gpio_num); + bcm2835_set_output(adapter_gpio_config[idx].gpio_num); bcm2835_gpio_synchronize(); } static enum bb_value bcm2835gpio_read(void) { - 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); + bool value = ((*gpio_control.tdo_read_level_addr >> gpio_control.tdo_level_shift_bits) & 1); + return (value ^ gpio_control.tdo_active_low) ? BB_HIGH : BB_LOW; } static int bcm2835gpio_write(int tck, int tms, int tdi) { - 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_control.tdi_clr_set_addr[tdi] = gpio_control.tdi_mask; + *gpio_control.tms_clr_set_addr[tms] = gpio_control.tms_mask; + *gpio_control.tck_clr_set_addr[tck] = gpio_control.tck_mask; /* Write clock last */ - GPIO_SET = set; - GPIO_CLR = clear; bcm2835_gpio_synchronize(); bcm2835_delay(); @@ -210,16 +262,9 @@ static int bcm2835gpio_write(int tck, int tms, int tdi) /* Requires push-pull drive mode for swclk and swdio */ static int bcm2835gpio_swd_write_fast(int swclk, int swdio) { - 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); + *gpio_control.swdio_clr_set_addr[swdio] = gpio_control.swdio_mask; + *gpio_control.swclk_clr_set_addr[swclk] = gpio_control.swclk_mask; /* Write clock last */ - 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; - - GPIO_SET = set; - GPIO_CLR = clear; bcm2835_gpio_synchronize(); bcm2835_delay(); @@ -266,9 +311,11 @@ static void bcm2835_swdio_drive(bool is_output) 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); + /* per bcm2835_set_output, clear mode bits then set the pin to output */ + *gpio_control.swdio_mode_addr = (gpio_control.swdio_mode_output_mask | + (*gpio_control.swdio_mode_addr & gpio_control.swdio_mode_input_mask)); } else { - INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); + *gpio_control.swdio_mode_addr &= gpio_control.swdio_mode_input_mask; if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR)) set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0); } @@ -277,9 +324,8 @@ static void bcm2835_swdio_drive(bool is_output) static int bcm2835_swdio_read(void) { - 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); + bool value = ((*gpio_control.swdio_read_level_addr >> gpio_control.swdio_level_shift_bits) & 1); + return (int)(value ^ gpio_control.swdio_active_low); } static int bcm2835gpio_khz(int khz, int *jtag_speed) @@ -515,6 +561,26 @@ LOG_INFO("pads conf set to %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]); initialize_gpio(ADAPTER_GPIO_IDX_TMS); initialize_gpio(ADAPTER_GPIO_IDX_TCK); initialize_gpio(ADAPTER_GPIO_IDX_TRST); + + /* flip the addresses used when pins are active low */ + unsigned char idx = adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].active_low ? 1 : 0; + gpio_control.tms_clr_set_addr[idx] = BCM2835_GPIO_CLR_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num); + gpio_control.tms_clr_set_addr[!idx] = BCM2835_GPIO_SET_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num); + gpio_control.tms_mask = (1 << (adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num % 32)); + + idx = adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].active_low ? 1 : 0; + gpio_control.tdi_clr_set_addr[idx] = BCM2835_GPIO_CLR_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num); + gpio_control.tdi_clr_set_addr[!idx] = BCM2835_GPIO_SET_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num); + gpio_control.tdi_mask = (1 << (adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num % 32)); + + idx = adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].active_low ? 1 : 0; + gpio_control.tck_clr_set_addr[idx] = BCM2835_GPIO_CLR_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num); + gpio_control.tck_clr_set_addr[!idx] = BCM2835_GPIO_SET_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num); + gpio_control.tck_mask = (1 << (adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num % 32)); + + gpio_control.tdo_read_level_addr = BCM2835_GPIO_LEVEL_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num); + gpio_control.tdo_level_shift_bits = (adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num % 32); + gpio_control.tdo_active_low = adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].active_low; } const struct bitbang_interface *bcm2835gpio_bitbang = &bcm2835gpio_bitbang_swd_write_generic; @@ -538,6 +604,30 @@ LOG_INFO("pads conf set to %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]); 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) { + /* flip the addresses used when pins are active low */ + unsigned char idx = adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0; + gpio_control.swdio_clr_set_addr[idx] = + BCM2835_GPIO_CLR_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); + gpio_control.swdio_clr_set_addr[!idx] = + BCM2835_GPIO_SET_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); + gpio_control.swdio_mask = (1 << (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num % 32)); + gpio_control.swdio_read_level_addr = + BCM2835_GPIO_LEVEL_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); + gpio_control.swdio_level_shift_bits = (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num % 32); + gpio_control.swdio_active_low = adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low; + gpio_control.swdio_mode_addr = BCM2835_GPIO_MODE_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); + gpio_control.swdio_mode_input_mask = + ~(7 << ((adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num % 10) * 3)); + gpio_control.swdio_mode_output_mask = + (1 << ((adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num % 10) * 3)); + + idx = adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].active_low ? 1 : 0; + gpio_control.swclk_clr_set_addr[idx] = + BCM2835_GPIO_CLR_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num); + gpio_control.swclk_clr_set_addr[!idx] = + BCM2835_GPIO_SET_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num); + gpio_control.swclk_mask = (1 << (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num % 32)); + LOG_DEBUG("BCM2835 GPIO using fast mode for SWD write"); bcm2835gpio_bitbang = &bcm2835gpio_bitbang_swd_write_fast; } else { @@ -570,7 +660,7 @@ static int bcm2835gpio_quit(void) * 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); + bcm2835_set_input(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); diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index c2e763ddb3..501830cc0f 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -236,14 +236,14 @@ static int bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, buffered++; } else { switch (bitbang_interface->read()) { - case BB_LOW: - buffer[bytec] &= ~bcval; - break; - case BB_HIGH: - buffer[bytec] |= bcval; - break; - default: - return ERROR_FAIL; + case BB_LOW: + buffer[bytec] &= ~bcval; + break; + case BB_HIGH: + buffer[bytec] |= bcval; + break; + default: + return ERROR_FAIL; } } } @@ -256,14 +256,14 @@ static int bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, bit_cnt == scan_size - 1)) { for (unsigned int i = bit_cnt + 1 - buffered; i <= bit_cnt; i++) { switch (bitbang_interface->read_sample()) { - case BB_LOW: - buffer[i/8] &= ~(1 << (i % 8)); - break; - case BB_HIGH: - buffer[i/8] |= 1 << (i % 8); - break; - default: - return ERROR_FAIL; + case BB_LOW: + buffer[i / 8] &= ~(1 << (i % 8)); + break; + case BB_HIGH: + buffer[i / 8] |= 1 << (i % 8); + break; + default: + return ERROR_FAIL; } } buffered = 0; @@ -315,64 +315,66 @@ int bitbang_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %u cycles, end in %s", - cmd->cmd.runtest->num_cycles, - tap_state_name(cmd->cmd.runtest->end_state)); - bitbang_end_state(cmd->cmd.runtest->end_state); - if (bitbang_runtest(cmd->cmd.runtest->num_cycles) != ERROR_OK) - return ERROR_FAIL; - break; - - case JTAG_STABLECLOCKS: - /* this is only allowed while in a stable state. A check for a stable - * state was done in jtag_add_clocks() - */ - if (bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles) != ERROR_OK) - return ERROR_FAIL; - break; - - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %s", - tap_state_name(cmd->cmd.statemove->end_state)); - bitbang_end_state(cmd->cmd.statemove->end_state); - if (bitbang_state_move(0) != ERROR_OK) - return ERROR_FAIL; - break; - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %u states, end in %s", - cmd->cmd.pathmove->num_states, - tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); - if (bitbang_path_move(cmd->cmd.pathmove) != ERROR_OK) - return ERROR_FAIL; - break; - case JTAG_SCAN: - bitbang_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - LOG_DEBUG_IO("%s scan %d bits; end in %s", - (cmd->cmd.scan->ir_scan) ? "IR" : "DR", - scan_size, - tap_state_name(cmd->cmd.scan->end_state)); - type = jtag_scan_type(cmd->cmd.scan); - if (bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, - scan_size) != ERROR_OK) - return ERROR_FAIL; - if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %u cycles, end in %s", + cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + bitbang_end_state(cmd->cmd.runtest->end_state); + if (bitbang_runtest(cmd->cmd.runtest->num_cycles) != ERROR_OK) + return ERROR_FAIL; + break; + + case JTAG_STABLECLOCKS: + /* this is only allowed while in a stable state. A check for a stable + * state was done in jtag_add_clocks() + */ + if (bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles) != ERROR_OK) + return ERROR_FAIL; + break; + + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %s", + tap_state_name(cmd->cmd.statemove->end_state)); + bitbang_end_state(cmd->cmd.statemove->end_state); + if (bitbang_state_move(0) != ERROR_OK) + return ERROR_FAIL; + break; + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %u states, end in %s", + cmd->cmd.pathmove->num_states, + tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); + if (bitbang_path_move(cmd->cmd.pathmove) != ERROR_OK) + return ERROR_FAIL; + break; + case JTAG_SCAN: + bitbang_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + LOG_DEBUG_IO("%s scan %d bits; end in %s", + (cmd->cmd.scan->ir_scan) ? "IR" : "DR", + scan_size, + tap_state_name(cmd->cmd.scan->end_state)); + type = jtag_scan_type(cmd->cmd.scan); + if (bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, + scan_size) != ERROR_OK) { free(buffer); - break; - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, 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); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + return ERROR_FAIL; + } + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + free(buffer); + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, 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); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c index 4283616adc..7a1a93c1b6 100644 --- a/src/jtag/drivers/buspirate.c +++ b/src/jtag/drivers/buspirate.c @@ -941,24 +941,24 @@ static void buspirate_swd_set_feature(int fd, char feat, char action) uint8_t tmp[1]; switch (feat) { - case FEATURE_TRST: - LOG_DEBUG("Buspirate TRST feature not available in SWD mode"); - return; - case FEATURE_LED: - LOG_ERROR("Buspirate LED feature not available in SWD mode"); - return; - case FEATURE_SRST: - swd_features = (action == ACTION_ENABLE) ? swd_features | 0x02 : swd_features & 0x0D; - break; - case FEATURE_PULLUP: - swd_features = (action == ACTION_ENABLE) ? swd_features | 0x04 : swd_features & 0x0B; - break; - case FEATURE_VREG: - swd_features = (action == ACTION_ENABLE) ? swd_features | 0x08 : swd_features & 0x07; - break; - default: - LOG_DEBUG("Buspirate unknown feature %d", feat); - return; + case FEATURE_TRST: + LOG_DEBUG("Buspirate TRST feature not available in SWD mode"); + return; + case FEATURE_LED: + LOG_ERROR("Buspirate LED feature not available in SWD mode"); + return; + case FEATURE_SRST: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x02 : swd_features & 0x0D; + break; + case FEATURE_PULLUP: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x04 : swd_features & 0x0B; + break; + case FEATURE_VREG: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x08 : swd_features & 0x07; + break; + default: + LOG_DEBUG("Buspirate unknown feature %d", feat); + return; } tmp[0] = CMD_RAW_PERIPH | swd_features; @@ -1157,9 +1157,7 @@ static unsigned char buspirate_jtag_command(int fd, /* TODO add support for WIN32 and others ! */ static int buspirate_serial_open(char *port) { - int fd; - fd = open(buspirate_port, O_RDWR | O_NOCTTY | O_NDELAY); - return fd; + return open(buspirate_port, O_RDWR | O_NOCTTY | O_NDELAY); } diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c new file mode 100644 index 0000000000..8a7cd7d326 --- /dev/null +++ b/src/jtag/drivers/ch347.c @@ -0,0 +1,2399 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Driver for CH347-JTAG interface V1.1 * + * * + * Copyright (C) 2022 by oidcat. * + * Author: oidcatiot@163.com * + * * + * Enhancements by EasyDevKits - info@easydevkits.com * + * * + * CH347 is a high-speed USB bus converter chip that provides UART, I2C * + * and SPI synchronous serial ports and JTAG interface through USB bus. * + * * + * The JTAG interface by CH347 can supports transmission frequency * + * configuration up to 60MHz. * + * * + * The USB2.0 to JTAG scheme based on CH347 can be used to build * + * customized USB high-speed JTAG debugger and other products. * + * * + * _____________ * + * | |____JTAG/SWD (TDO,TDI,TMS,TCK,TRST) * + * USB__| CH347T/F | * + * |_____________|____UART(TXD1,RXD1,RTS1,CTS1,DTR1) * + * ______|______ * + * | | * + * | 8 MHz XTAL | * + * |_____________| * + * * + * This CH347 driver is only tested for the CH347T chip in mode 3. * + * The CH347 datasheet mention another chip the CH347F which was not * + * available for testing. * + * * + * The datasheet for the wch-ic.com's CH347 part is here: * + * https://www.wch-ic.com/downloads/CH347DS1_PDF.html * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if IS_CYGWIN == 1 +#include "windows.h" +#undef LOG_ERROR +#endif + +// project specific includes +#include +#include +#include +#include +#include +#include +#include +#include +#include "libusb_helper.h" + +// system includes +#include +#include +#include +#include +#include + +#define TDI_H BIT(4) +#define TDI_L 0 +#define TMS_H BIT(1) +#define TMS_L 0 +#define TCK_H BIT(0) +#define TCK_L 0 +#define TRST_H BIT(5) +#define TRST_L 0 +#define LED_ON 1 +#define LED_OFF 0 +#define GPIO_CNT 8 // the CH347 has 8 GPIO's +/* mask which GPIO's are available in mode 3 of CH347T only GPIO3 (Pin11 / SCL), GPIO4 (Pin15 / ACT), + GPIO5 (Pin9 / TRST) and GPIO6 (Pin2 / CTS1) are possible. Tested only with CH347T not CH347F chip. + pin numbers are for CH347T */ +#define USEABLE_GPIOS 0x78 +/* For GPIO command: always set bits 7 and 6 for GPIO enable + bits 5 and 4 for pin direction output bit 3 is the data bit */ +#define GPIO_SET_L (BIT(4) | BIT(5) | BIT(6) | BIT(7)) // value for setting a GPIO to low +#define GPIO_SET_H (BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7)) // value for setting a GPIO to high + +#define VENDOR_VERSION 0x5F // for getting the chip version + +// maybe the hardware of the CH347 chip can capture only this amount of TDO bits +#define HW_TDO_BUF_SIZE 4096 +// Don't send more than this amount of bytes via libusb in one packet. Also that is the limit for LARGER_PACK mode. +#define LARGER_PACK_MAX_SIZE 51200 +// The data length contained in each command packet during USB high-speed operation +#define UCMDPKT_DATA_MAX_BYTES_USBHS 507 +#define USBC_PACKET_USBHS 512 // Maximum data length per packet at USB high speed +#define CH347_CMD_HEADER 3 // Protocol header length (1 byte command type + 2 bytes data length) +#define CH347_CMD_INIT_READ_LEN 1 // for JTAG_INIT/SWD_INIT we have only one data byte +// if we send 9 in the init command we get the STANDARD mode or LARGER_PACK mode flag +#define CH347_CMD_INIT_GET_MODE_CLOCK_INDEX_VALUE 9 +// No more bits are allowed per CH347_CMD_JTAG_BIT_OP command; this should be dividable by 8 +#define MAX_BITS_PER_BIT_OP 248 + +/* Protocol transmission format: CMD (1 byte) + Length (2 bytes) + Data + Parameter acquisition, used to obtain firmware version, JTAG interface related parameters, etc */ +#define CH347_CMD_INFO_RD 0xCA +#define CH347_CMD_GPIO 0xCC // GPIO Command +#define CH347_CMD_JTAG_INIT 0xD0 // JTAG Interface initialization command +#define CH347_CMD_JTAG_BIT_OP 0xD1 // JTAG interface pin bit control command +#define CH347_CMD_JTAG_BIT_OP_RD 0xD2 // JTAG interface pin bit control and read commands +#define CH347_CMD_JTAG_DATA_SHIFT 0xD3 // JTAG interface data shift command +#define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 // JTAG interface data shift and read command +// for a single command these amount of data can be read at max +#define CH347_SINGLE_CMD_MAX_READ MAX(GPIO_CNT, CH347_CMD_INIT_READ_LEN) + +// for SWD +#define CH347_CMD_SWD_INIT 0xE5 // SWD Interface Initialization Command +#define CH347_CMD_SWD 0xE8 // SWD Command group header +#define CH347_CMD_SWD_REG_W 0xA0 // SWD Interface write reg +#define CH347_CMD_SWD_SEQ_W 0xA1 // SWD Interface write spec seq +#define CH347_CMD_SWD_REG_R 0xA2 // SWD Interface read reg +#define CH347_MAX_PROCESSING_US 7000 // max time in us for packet processing + // USB hosts disconnect the adapter if SWD processing takes more! +#define CH347_MAX_SEND_BUF USBC_PACKET_USBHS +#define CH347_MAX_RECV_BUF USBC_PACKET_USBHS +#define CH347_MAX_CMD_BUF 128 +#define CH347_SWD_CLOCK_MAX 5000 +#define CH347_SWD_CLOCK_BASE 1000 +// limited by the longest sequence processing time +#define CH347_SWD_CLOCK_MAX_DIVISOR (CH347_MAX_PROCESSING_US / swd_seq_dormant_to_swd_len) + +#define CH347_EPOUT 0x06u // the usb endpoint number for writing +#define CH347_EPIN 0x86u // the usb endpoint number for reading +#define CH347T_MPHSI_INTERFACE 2 // the CH347T JTAG interface is number 2 +#define CH347F_MPHSI_INTERFACE 4 // the CH347F JTAG interface is number 4 +#define USB_WRITE_TIMEOUT 500 // write timeout in milliseconds +#define USB_READ_TIMEOUT 500 // read timeout in milliseconds +// BCD version for devices that can use bytewise mode below this version only bitwise mode can be used +#define BYTEWISE_MODE_VERSION 0x241 +/* if the configuration is not setting the vendor id / product id we search for vendor id 1a86 + and product id's 0x55dd (CH347T chip in mode 3), 0x55de (CH347F chip) and 0x55e7 (other chip) */ +#define DEFAULT_VENDOR_ID 0x1a86 +#define DEFAULT_CH347T_PRODUCT_ID 0x55dd +#define DEFAULT_CH347F_PRODUCT_ID 0x55de +#define DEFAULT_OTHER_PRODUCT_ID 0x55e7 + +/* There are 3 different CH347 variants. The datasheet mentions the CH347T chip which has the product id 0x55dd + as default when it's configured to mode 3. The CH347F chip is also mentioned in the datasheet and has the + default product id 0x55de. The 3rd variant is not mentioned in a datasheet but was found here + https://github.com/WCHSoftGroup/ch347 + The code from WCHSoftGroup is also searching for this product id */ +enum ch347_variant { + CH347T = 0, // The CH347T chip + CH347F = 1, // The CH347F chip + OTHER_PRODUCT_ID = 2, // other product id not mentioned in the datasheet +}; + +/* STANDARD_PACK means that we can send only one USBC_PACKET_USBHS-sized USB packet + and then read data back. LARGER_PACK means, we can send packets as large as + LARGER_PACK_MAX_SIZE. libusb splits there large packets into smaller USB packets and + transmit the data. Then we read back the data in a bigger packet. */ +enum pack_size { + UNSET = -1, + STANDARD_PACK = 0, + LARGER_PACK = 1, +}; + +// for STANDARD_PACK mode: these are the 6 possible speeds; values in kHz +static const int ch347_standard_pack_clock_speeds[] = { + 1875, // 1.875 MHz (60000 : 32) + 3750, // 3.75 MHz (60000 : 16) + 7500, // 7.5 MHz (60000 : 8) + 15000, // 15 MHz (60000 : 4) + 30000, // 30 MHz (60000 : 2) + 60000 // 60 MHz +}; + +// for LARGER_PACK mode: these are the 8 possible speeds; values in kHz +static const int ch347_larger_pack_clock_speeds[] = { + 469, // 468.75 kHz (60000 : 128) + 938, // 937.5 kHz (60000 : 64) + 1875, // 1.875 MHz (60000 : 32) + 3750, // 3.75 MHz (60000 : 16) + 7500, // 7.5 MHz (60000 : 8) + 15000, // 15 MHz (60000 : 4) + 30000, // 30 MHz (60000 : 2) + 60000 // 60 MHz +}; + +struct ch347_cmd { + uint8_t type; // the command type + uint8_t *write_data; // data bytes for write + uint16_t write_data_len; // count of data bytes in the write_data buffer + uint16_t read_len; // if >0 a read is needed after this command + uint16_t tdo_bit_count; // how many TDO bits are needed to shift in by this read + struct list_head queue; // for handling a queue (list) +}; + +struct ch347_scan { + struct scan_field *fields; // array of scan_field's for data from the device + int fields_len; // scan_fields array length + struct list_head queue; // for handling a queue (list) +}; + +struct ch347_info { + // Record the CH347 pin status + int tms_pin; + int tdi_pin; + int tck_pin; + int trst_pin; + + enum ch347_variant chip_variant; // ch347_variant for explanation + // if true then we can't us the bytewise commands due to a bug of the chip; depends on BYTEWISE_MODE_VERSION + bool use_bitwise_mode; + enum pack_size pack_size; // see: pack_size for explanation + int max_len; // in STANDARD_PACK or bitwise mode we can send only one USBC_PACKET_USBHS sized package + bool swclk_5mhz_supported; + + // a "scratchpad" where we record all bytes for one command + uint8_t scratchpad_cmd_type; // command type + uint8_t scratchpad[UCMDPKT_DATA_MAX_BYTES_USBHS]; // scratchpad buffer + int scratchpad_idx; // current index in scratchpad + + // after a command is complete it will be stored for later processing + struct list_head cmd_queue; + // all data input scan fields are queued here + struct list_head scan_queue; + // read buffer for the single commands like CH347_CMD_GPIO and CH347_CMD_JTAG_INIT + uint8_t single_read[CH347_SINGLE_CMD_MAX_READ]; + int singe_read_len; // data length in single_read +}; + +struct ch347_swd_io { + uint8_t usb_cmd; // 0xA0, 0xA1, 0xA2 + uint8_t cmd; + uint32_t *dst; + uint32_t value; + struct list_head list_entry; +}; + +struct ch347_swd_context { + uint8_t send_buf[CH347_MAX_SEND_BUF]; + uint8_t recv_buf[CH347_MAX_RECV_BUF]; + int send_len; + int recv_len; + int need_recv_len; + int queued_retval; + int sent_cmd_count; + unsigned int clk_divisor; + unsigned int total_swd_clk; + struct list_head send_cmd_head; + struct list_head free_cmd_head; + struct ch347_swd_io ch347_cmd_buf[CH347_MAX_CMD_BUF]; +}; + +static struct ch347_swd_context ch347_swd_context; +static bool swd_mode; +static uint16_t default_ch347_vids[] = {DEFAULT_VENDOR_ID, DEFAULT_VENDOR_ID, DEFAULT_VENDOR_ID, 0}; +static uint16_t default_ch347_pids[] = {DEFAULT_CH347T_PRODUCT_ID, + DEFAULT_CH347F_PRODUCT_ID, DEFAULT_OTHER_PRODUCT_ID, 0}; +static uint8_t ch347_activity_led_gpio_pin = 0xFF; +static bool ch347_activity_led_active_high; +static struct ch347_info ch347; +static struct libusb_device_handle *ch347_handle; + +/* there are "single" commands. These commands can't be chained together and + need to be send as single command and need a read after write */ +static inline bool ch347_is_single_cmd_type(uint8_t type) +{ + return type == CH347_CMD_GPIO || type == CH347_CMD_JTAG_INIT || type == CH347_CMD_SWD_INIT; +} + +static void log_buf_dump(const uint8_t *data, unsigned int size, bool recv) +{ + unsigned int i = 0, j = 0; + unsigned int n = size * 3 + 1; + char *str = malloc(n); + if (!str) + return; + + while (i < size && j < n) { + uint8_t cmd = data[i++]; + hexify(str + j, &cmd, 1, n - j); + j += 2; + str[j++] = ' '; + + unsigned int cmd_payload_size = le_to_h_u16(data + i); + if (i + 2 <= size && j + 4 < n) { + hexify(str + j, data + i, 2, n - j); + i += 2; + j += 4; + str[j++] = ' '; + } + + if (cmd == CH347_CMD_SWD) { + // nested SWD commands + str[j] = '\0'; + if (i + cmd_payload_size > size) { + LOG_DEBUG_IO("%s - bad size", str); + cmd_payload_size = size - i; + } else { + LOG_DEBUG_IO("%s", str); + } + j = 0; + unsigned int swd_base_i = i; + + while (i < swd_base_i + cmd_payload_size) { + uint8_t swd_cmd = data[i++]; + hexify(str + j, &swd_cmd, 1, n - j); + j += 2; + str[j++] = ' '; + + unsigned int swd_bits = 0; + unsigned int swd_payload_size = 0; + if (!recv) { + if (i + 2 <= size) { + swd_bits = le_to_h_u16(data + i); + hexify(str + j, data + i, 2, n - j); + i += 2; + j += 4; + str[j++] = ' '; + } + } + + switch (swd_cmd) { + case CH347_CMD_SWD_REG_W: + if (recv) + swd_payload_size = 1; + else + swd_payload_size = DIV_ROUND_UP(swd_bits, 8); + break; + case CH347_CMD_SWD_SEQ_W: + if (!recv) + swd_payload_size = DIV_ROUND_UP(swd_bits, 8); + break; + case CH347_CMD_SWD_REG_R: + if (recv) + swd_payload_size = 1 + 4 + 1; + else + swd_payload_size = 1; + break; + } + + hexify(str + j, data + i, MIN(swd_payload_size, size - i), n - j); + i += swd_payload_size; + j += 2 * swd_payload_size; + str[j] = '\0'; + if (i > size) + LOG_DEBUG_IO(" %s - bad size", str); + else + LOG_DEBUG_IO(" %s", str); + j = 0; + } + } else { + hexify(str + j, data + i, MIN(cmd_payload_size, size - i), n - j); + i += cmd_payload_size; + j += 2 * cmd_payload_size; + str[j] = '\0'; + if (i > size) + LOG_DEBUG_IO("%s - bad size", str); + else + LOG_DEBUG_IO("%s", str); + j = 0; + } + } + free(str); +} + +/** + * @brief writes data to the CH347 via libusb driver + * + * @param data Point to the data buffer + * @param length Data length in and out + * @return ERROR_OK at success + */ +static int ch347_write_data(uint8_t *data, int *length) +{ + int write_len = *length; + int i = 0; + int transferred = 0; + + while (true) { + int retval = jtag_libusb_bulk_write(ch347_handle, CH347_EPOUT, (char *)&data[i], + write_len, USB_WRITE_TIMEOUT, &transferred); + if (retval != ERROR_OK) { + LOG_ERROR("CH347 write fail"); + *length = 0; + return retval; + } + i += transferred; + if (i >= *length) + break; + write_len = *length - i; + } + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + LOG_DEBUG_IO("size=%d, buf=", i); + log_buf_dump(data, i, false); + } + + *length = i; + return ERROR_OK; +} + +/** + * @brief reads data from the CH347 via libusb driver + * + * @param data Point to the data buffer + * @param length Data length in and out + * @return ERROR_OK at success + */ +static int ch347_read_data(uint8_t *data, int *length) +{ + int read_len = *length; + int i = 0; + int transferred = 0; + + while (true) { + int retval = jtag_libusb_bulk_read(ch347_handle, CH347_EPIN, (char *)&data[i], + read_len, USB_READ_TIMEOUT, &transferred); + if (retval != ERROR_OK) { + LOG_ERROR("CH347 read fail"); + *length = 0; + return retval; + } + + i += transferred; + if (i >= *length) + break; + read_len = *length - i; + } + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + LOG_DEBUG_IO("size=%d, buf=", i); + log_buf_dump(data, i, true); + } + + *length = i; + return ERROR_OK; +} + +/** + * @brief calculates the amount of bits and bytes that should be read + * for this command + * + * @param cmd command for the calculation + */ +static void ch347_cmd_calc_reads(struct ch347_cmd *cmd) +{ + cmd->read_len = 0; + cmd->tdo_bit_count = 0; + + switch (cmd->type) { + case CH347_CMD_GPIO: + // for GPIO we need to read back the same amount of data that we had send + cmd->read_len = cmd->write_data_len; + break; + case CH347_CMD_JTAG_INIT: + case CH347_CMD_SWD_INIT: + // for JTAG_INIT/SWD_INIT the amount is fixed + cmd->read_len = CH347_CMD_INIT_READ_LEN; + break; + case CH347_CMD_JTAG_BIT_OP_RD: + // for bit operations we need to count the TCK high edges + for (int i = 0; i < cmd->write_data_len; i++) { + if ((cmd->write_data[i] & TCK_H) == TCK_H) { + cmd->read_len++; + cmd->tdo_bit_count++; + } + } + break; + case CH347_CMD_JTAG_DATA_SHIFT_RD: + // for byte operations: need to read one byte back for each data byte + cmd->read_len = cmd->write_data_len; + // we occupy 8 bits per byte in the TDO hardware buffer + cmd->tdo_bit_count = cmd->read_len * 8; + break; + } +} + +/** + * @brief copy the scratchpad content into a new command in the command queue + * + * @param scan_fields array of scan_field's for data from the device + * @param scan_fields_len array length + * @return ERROR_OK at success + */ +static int ch347_cmd_from_scratchpad(void) +{ + // nothing to do if no bytes are recorded + if (!ch347.scratchpad_idx) + return ERROR_OK; + + // malloc for the command and data bytes + struct ch347_cmd *cmd = malloc(sizeof(struct ch347_cmd)); + if (cmd) + cmd->write_data = malloc(ch347.scratchpad_idx); + if (!cmd || !cmd->write_data) { + LOG_ERROR("malloc failed"); + free(cmd); + return ERROR_FAIL; + } + + // copy data, calculate the reads and add to the command queue + cmd->type = ch347.scratchpad_cmd_type; + cmd->write_data_len = ch347.scratchpad_idx; + memcpy(cmd->write_data, ch347.scratchpad, ch347.scratchpad_idx); + ch347_cmd_calc_reads(cmd); + list_add_tail(&cmd->queue, &ch347.cmd_queue); + + // cleanup the scratchpad for the next command + ch347.scratchpad_cmd_type = 0; + ch347.scratchpad_idx = 0; + return ERROR_OK; +} + +/** + * @brief Reads data back from CH347 and decode it byte- and bitwise into the buffer + * + * @param decoded_buf Point to a buffer to place the data to be decoded; need to be sized + * to the decoded size length; not the raw_read_len + * @param decoded_buf_len length of the decoded_buf + * @param raw_read_len Data length in bytes that should be read via libusb; the decoded length can be shorter + * @return ERROR_OK at success + */ +static int ch347_read_scan(uint8_t *decoded_buf, int decoded_buf_len, int raw_read_len) +{ + int read_len = raw_read_len; + uint8_t *read_buf = malloc(read_len); + if (!read_buf) { + LOG_ERROR("malloc failed"); + return ERROR_FAIL; + } + + int retval = ch347_read_data(read_buf, &read_len); + if (retval != ERROR_OK) { + free(read_buf); + return retval; + } + + int rd_idx = 0; + int decoded_buf_idx = 0; + + while (rd_idx < read_len) { + unsigned int type = read_buf[rd_idx++]; + uint16_t data_len = le_to_h_u16(&read_buf[rd_idx]); + rd_idx += 2; + if (decoded_buf_idx > decoded_buf_len) { + LOG_ERROR("CH347 decoded_buf too small"); + free(read_buf); + return ERROR_FAIL; + } + + // nothing to decode? Only read to make the CH347 happy! + if (!decoded_buf) { + rd_idx += data_len; + continue; + } + + switch (type) { + case CH347_CMD_GPIO: + case CH347_CMD_JTAG_INIT: + case CH347_CMD_SWD_INIT: + case CH347_CMD_JTAG_DATA_SHIFT_RD: + // for all bytewise commands: copy the data bytes + memcpy(&decoded_buf[decoded_buf_idx], &read_buf[rd_idx], data_len); + decoded_buf_idx += data_len; + rd_idx += data_len; + break; + case CH347_CMD_JTAG_BIT_OP_RD: + // for CH347_CMD_JTAG_BIT_OP_RD we need to copy bit by bit + for (int i = 0; i < data_len; i++) { + if (read_buf[rd_idx + i] & BIT(0)) + decoded_buf[decoded_buf_idx + i / 8] |= BIT(i % 8); + else + decoded_buf[decoded_buf_idx + i / 8] &= ~(BIT(i % 8)); + } + rd_idx += data_len; + decoded_buf_idx += DIV_ROUND_UP(data_len, 8); + break; + default: + LOG_ERROR("CH347 read command fail"); + free(read_buf); + return ERROR_FAIL; + } + } + + free(read_buf); + return ERROR_OK; +} + +/** + * @brief Used to put the data from the decoded buffer into the scan command fields + * + * @param decoded_buf Point to a buffer for the decoded data + * @param decoded_buf_len length of the decoded_buf + * @return ERROR_OK at success + */ +static int ch347_scan_data_to_fields(uint8_t *decoded_buf, int decoded_buf_len) +{ + int byte_offset = 0; + struct ch347_scan *scan; + struct ch347_scan *tmp; + int bit_offset = 0; + list_for_each_entry_safe(scan, tmp, &ch347.scan_queue, queue) { + for (int i = 0; i < scan->fields_len; i++) { + int num_bits = scan->fields[i].num_bits; + LOG_DEBUG("fields[%d].in_value[%d], read from bit offset: %d", i, num_bits, bit_offset); + // only if we need the value + if (scan->fields[i].in_value) { + uint8_t *capture_buf = malloc(DIV_ROUND_UP(num_bits, 8)); + if (!capture_buf) { + LOG_ERROR("malloc failed"); + return ERROR_FAIL; + } + uint8_t *captured = buf_set_buf(decoded_buf, bit_offset, capture_buf, 0, num_bits); + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + char *str = buf_to_hex_str(captured, num_bits); + LOG_DEBUG_IO("size=%d, buf=[%s]", num_bits, str); + free(str); + } + + buf_cpy(captured, scan->fields[i].in_value, num_bits); + free(capture_buf); + } else { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) + LOG_DEBUG_IO("field skipped"); + } + bit_offset += num_bits; + } + list_del(&scan->queue); + free(scan); + /* after one round of scan field processing the + next data bits are read from the next data byte + => round up and calculate the next start bit */ + byte_offset = DIV_ROUND_UP(bit_offset, 8); + bit_offset = byte_offset * 8; + } + + // if not all bytes are transferred: put the rest into single_read buffer + if (byte_offset < decoded_buf_len) { + ch347.singe_read_len = decoded_buf_len - byte_offset; + LOG_DEBUG("single read of %d bytes", ch347.singe_read_len); + if (ch347.singe_read_len > CH347_SINGLE_CMD_MAX_READ) { + LOG_ERROR("Can't read more than %d bytes for a single command!", CH347_SINGLE_CMD_MAX_READ); + ch347.singe_read_len = CH347_SINGLE_CMD_MAX_READ; + } + memcpy(ch347.single_read, &decoded_buf[byte_offset], ch347.singe_read_len); + } + + return ERROR_OK; +} + +/** + * @brief Sends the write buffer via libusb + * and if LARGER_PACK mode is active read also data back + * + * @return ERROR_OK at success + */ +static int ch347_cmd_transmit_queue(void) +{ + // queue last command + int retval = ch347_cmd_from_scratchpad(); + if (retval != ERROR_OK) + return retval; + + // nothing to do! => done here + if (list_empty(&ch347.cmd_queue)) + return ERROR_OK; + + // calculate the needed buffer length for all decoded bytes + struct ch347_cmd *cmd; + int decoded_buf_len = 0; + list_for_each_entry(cmd, &ch347.cmd_queue, queue) + if (cmd->read_len > 0) + decoded_buf_len += ch347_is_single_cmd_type(cmd->type) ? + cmd->read_len : DIV_ROUND_UP(cmd->tdo_bit_count, 8); + + // create the buffer for all decoded bytes + uint8_t *decoded_buf = NULL; + int decoded_buf_idx = 0; + if (decoded_buf_len > 0) { + decoded_buf = malloc(decoded_buf_len); + if (!decoded_buf) { + LOG_ERROR("malloc failed"); + return ERROR_FAIL; + } + } + + while (!list_empty(&ch347.cmd_queue)) { + struct ch347_cmd *last_cmd = NULL; + int total_len = 0; + int total_tdo_count = 0; + int bytes_to_write = 0; + + list_for_each_entry(cmd, &ch347.cmd_queue, queue) { + total_len += CH347_CMD_HEADER + cmd->write_data_len; + total_tdo_count += cmd->tdo_bit_count; + // don't exceed max length or max TDO bit count + if (total_len >= ch347.max_len || total_tdo_count >= HW_TDO_BUF_SIZE) + break; + // remember the last cmd to send and bytes to send + last_cmd = cmd; + bytes_to_write = total_len; + } + + // sanity checks + if (!last_cmd || bytes_to_write == 0) { + LOG_ERROR("Nothing to send!"); + free(decoded_buf); + return ERROR_FAIL; + } + + // create the write buffer + uint8_t *write_buf = malloc(bytes_to_write); + if (!write_buf) { + LOG_ERROR("malloc failed"); + free(decoded_buf); + return ERROR_FAIL; + } + + int idx = 0; + int bytes_to_read = 0; + int current_decoded_buf_len = 0; + struct ch347_cmd *tmp; + + list_for_each_entry_safe(cmd, tmp, &ch347.cmd_queue, queue) { + // copy command to buffer + write_buf[idx++] = cmd->type; + h_u16_to_le(&write_buf[idx], cmd->write_data_len); + idx += 2; + memcpy(&write_buf[idx], cmd->write_data, cmd->write_data_len); + idx += cmd->write_data_len; + // need to read something back? + if (cmd->read_len > 0) { + bytes_to_read += CH347_CMD_HEADER + cmd->read_len; + current_decoded_buf_len += ch347_is_single_cmd_type(cmd->type) ? + cmd->read_len : DIV_ROUND_UP(cmd->tdo_bit_count, 8); + } + + // cmd data no longer needed + list_del(&cmd->queue); + free(cmd->write_data); + free(cmd); + + if (cmd == last_cmd) + break; + } + + // write data to device + retval = ch347_write_data(write_buf, &idx); + free(write_buf); + if (retval != ERROR_OK) { + free(decoded_buf); + return retval; + } + + if (!bytes_to_read) + continue; + + // Need only to execute a read without decoding the data to make the CH347 happy? + if (!current_decoded_buf_len) { + // read but don't decode anything + retval = ch347_read_scan(NULL, 0, bytes_to_read); + } else { + retval = ch347_read_scan(&decoded_buf[decoded_buf_idx], current_decoded_buf_len, bytes_to_read); + decoded_buf_idx += current_decoded_buf_len; + } + + if (retval != ERROR_OK) { + free(decoded_buf); + return retval; + } + } + + // something decoded from the data read back from CH347? + if (decoded_buf) { + // put the decoded data into the scan fields or single_read buffer + retval = ch347_scan_data_to_fields(decoded_buf, decoded_buf_len); + free(decoded_buf); + } + + return retval; +} + +/** + * @brief starts the next command in the scratchpad. If it's the same command type + * it can concat the data bytes. no need to make a new command for this case + * + * @param type command type + */ +static int ch347_cmd_start_next(uint8_t type) +{ + // different command type or non chainable command? (GPIO commands can't be concat) + uint8_t prev_type = ch347.scratchpad_cmd_type; + if (prev_type != type || ch347_is_single_cmd_type(type)) { + // something written in the scratchpad? => store it as command + if (prev_type != 0 && ch347.scratchpad_idx > 0) { + int retval = ch347_cmd_from_scratchpad(); + if (retval != ERROR_OK) + return retval; + + /* if the last queued command is not chainable we should send it immediately + because e.g. the GPIO command can't be combined with any other command */ + if (ch347_is_single_cmd_type(prev_type)) { + retval = ch347_cmd_transmit_queue(); + if (retval != ERROR_OK) + return retval; + } + } + + /* before we can send non chainable command ("single" like GPIO command) we should send all + other commands because we can't send it together with other commands */ + if (ch347_is_single_cmd_type(type)) { + int retval = ch347_cmd_transmit_queue(); + if (retval != ERROR_OK) + return retval; + } + + // store the next command type + ch347.scratchpad_cmd_type = type; + } + + return ERROR_OK; +} + +/** + * @brief queue the scan fields into the scan queue + * + * @param scan_fields array of scan field's for data from the device + * @param scan_fields_len array length + * @return ERROR_OK at success + */ +static int ch347_scan_queue_fields(struct scan_field *scan_fields, int scan_fields_len) +{ + // malloc for the scan struct + struct ch347_scan *scan = malloc(sizeof(struct ch347_scan)); + if (!scan) { + LOG_ERROR("malloc failed"); + return ERROR_FAIL; + } + + scan->fields = scan_fields; + scan->fields_len = scan_fields_len; + list_add_tail(&scan->queue, &ch347.scan_queue); + return ERROR_OK; +} + +/** + * @brief Function executes the single command and deliver one byte from the buffer + * that's read back from USB + * + * @param read_buf_idx index of the byte that should be returned + * @param byte returns byte at index or if index is out of range the first byte + * @return ERROR_OK at success + */ +static int ch347_single_read_get_byte(int read_buf_idx, uint8_t *byte) +{ + int retval = ch347_cmd_transmit_queue(); + if (retval != ERROR_OK) + return retval; + + if (read_buf_idx > CH347_SINGLE_CMD_MAX_READ || read_buf_idx < 0) { + LOG_ERROR("read_buf_idx out of range"); + return ERROR_FAIL; + } + + *byte = ch347.single_read[read_buf_idx]; + return ERROR_OK; +} + +/** + * @brief checks if the scratchpad is full. If it's full the function creates + * a command from it and puts it into the command queue + */ +static void ch347_scratchpad_check_full(void) +{ + // if full create a new command in the queue + if (ch347.scratchpad_idx == UCMDPKT_DATA_MAX_BYTES_USBHS) { + uint8_t type = ch347.scratchpad_cmd_type; + ch347_cmd_from_scratchpad(); + ch347.scratchpad_cmd_type = type; + } +} + +/** + * @brief adds one byte to the scratchpad + * if scratchpad is full after this byte the command will be created from the + * scratchpad and the scratchpad is cleared for the next command + * + * @param byte add this byte + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_byte(uint8_t byte) +{ + if (ch347.scratchpad_cmd_type == 0) { + LOG_ERROR("call ch347_next_cmd first!"); + return ERROR_FAIL; + } + + ch347.scratchpad[ch347.scratchpad_idx++] = byte; + ch347_scratchpad_check_full(); + return ERROR_OK; +} + +/** + * @brief adds the output pin byte to the scratchpad + * if scratchpad is full after this byte the command will be created from the + * scratchpad and the scratchpad is cleared for the next command + * + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_pin_byte(void) +{ + return ch347_scratchpad_add_byte(ch347.tms_pin | ch347.tdi_pin | ch347.tck_pin | ch347.trst_pin); +} + +/** + * @brief adds bytes from a buffer to the scratchpad + * if scratchpad is full after this byte the command will be created from the + * scratchpad and the scratchpad is cleared for the next command + * + * @param bytes add this bytes + * @param count byte count + * + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_bytes(uint8_t *bytes, int count) +{ + if (ch347.scratchpad_cmd_type == 0) { + LOG_ERROR("call ch347_next_cmd first!"); + return ERROR_FAIL; + } + + int remaining = count; + int bytes_idx = 0; + while (remaining > 0) { + int bytes_to_store = ch347.scratchpad_idx + remaining <= UCMDPKT_DATA_MAX_BYTES_USBHS ? + remaining : UCMDPKT_DATA_MAX_BYTES_USBHS - ch347.scratchpad_idx; + + if (bytes) + memcpy(&ch347.scratchpad[ch347.scratchpad_idx], &bytes[bytes_idx], bytes_to_store); + else + memset(&ch347.scratchpad[ch347.scratchpad_idx], 0, bytes_to_store); + + ch347.scratchpad_idx += bytes_to_store; + bytes_idx += bytes_to_store; + remaining -= bytes_to_store; + ch347_scratchpad_check_full(); + } + + return ERROR_OK; +} + +/** + * @brief Function used to change the TMS value at the + * rising edge of TCK to switch its TAP state + * + * @param tms TMS value to be changed; true = output TMS high; false = output TMS low + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_clock_tms(bool tms) +{ + ch347.tms_pin = tms ? TMS_H : TMS_L; + ch347.tck_pin = TCK_L; + int retval = ch347_scratchpad_add_pin_byte(); + if (retval != ERROR_OK) + return retval; + + ch347.tck_pin = TCK_H; + return ch347_scratchpad_add_pin_byte(); +} + +/** + * @brief Function adds a certain amount of TCK pulses without changing the TMS pin + * + * @param count Amount of L/H TCK pulses to add + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_stableclocks(int count) +{ + if (ch347.scratchpad_cmd_type == 0) { + int retval = ch347_cmd_start_next(CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + } + + bool tms = ch347.tms_pin == TMS_H; + for (int i = 0; i < count; i++) { + int retval = ch347_scratchpad_add_clock_tms(tms); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +/** + * @brief Function to ensure that the clock is in a low state + * + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_idle_clock(void) +{ + ch347.tck_pin = TCK_L; + return ch347_scratchpad_add_pin_byte(); +} + +/** + * @brief Function that performs state switching by changing the value of TMS + * + * @param tms_value The TMS values that need to be switched form one byte of data in the switching order + * @param step The number of bit values that need to be read from the tms_value value + * @param skip Count from the skip bit of tms_value to step + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_tms_change(const uint8_t *tms_value, int step, int skip) +{ + LOG_DEBUG_IO("TMS Value: %02x..., step = %d, skip = %d", tms_value[0], step, skip); + + int retval = ch347_cmd_start_next(CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + + for (int i = skip; i < step; i++) { + retval = ch347_scratchpad_add_clock_tms((tms_value[i / 8] >> (i % 8)) & BIT(0)); + if (retval != ERROR_OK) + return retval; + } + + return ch347_scratchpad_add_idle_clock(); +} + +/** + * @brief Obtain the current Tap status and switch to the status TMS value passed down by cmd + * + * @param cmd Upper layer transfer command parameters + * @return ERROR_OK at success; ERROR_JTAG_TRANSITION_INVALID if no transition is possible + */ +static int ch347_scratchpad_add_move_path(struct pathmove_command *cmd) +{ + LOG_DEBUG_IO("num_states=%d, last_state=%d", cmd->num_states, cmd->path[cmd->num_states - 1]); + + int retval = ch347_cmd_start_next(CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + + for (unsigned int i = 0; i < cmd->num_states; i++) { + if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) { + retval = ch347_scratchpad_add_clock_tms(0); + if (retval != ERROR_OK) + return retval; + } else if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) { + retval = ch347_scratchpad_add_clock_tms(1); + if (retval != ERROR_OK) + return retval; + } else { + LOG_ERROR("No transition possible!"); + return ERROR_JTAG_TRANSITION_INVALID; + } + tap_set_state(cmd->path[i]); + } + + return ch347_scratchpad_add_idle_clock(); +} + +/** + * @brief Toggle the tap state to the target state + * + * @param state Pre switch target path + * @param skip Number of digits to skip + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_move_state(enum tap_state state, int skip) +{ + uint8_t tms_scan; + int tms_len; + + LOG_DEBUG_IO("from %s to %s", tap_state_name(tap_get_state()), tap_state_name(state)); + // don't do anything if we are already in the right state; but do execute always the TAP_RESET + if (tap_get_state() == state && state != TAP_RESET) + return ERROR_OK; + + tms_scan = tap_get_tms_path(tap_get_state(), state); + tms_len = tap_get_tms_path_len(tap_get_state(), state); + int retval = ch347_scratchpad_add_tms_change(&tms_scan, tms_len, skip); + tap_set_state(state); + return retval; +} + +/** + * @brief CH347 Batch read/write function + * + * @param cmd The scan command + * @param bits Read and write data this time + * @param bits_len Incoming data length in bits + * @param scan The transmission method of incoming data to determine whether to perform data reading + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_write_read(struct scan_command *cmd, uint8_t *bits, int bits_len, enum scan_type scan) +{ + // the bits and bytes to transfer + int byte_count = bits_len / 8; + int bit_count = bits_len % 8; + + // only bytes are not possible because we need to set TMS high for the last bit + if (byte_count > 0 && bit_count == 0) { + // make one byte to eight bits + byte_count--; + bit_count = 8; + } + + // in bitwise mode only bits are allowed + if (ch347.use_bitwise_mode) { + byte_count = 0; + bit_count = bits_len; + } + + bool is_read = (scan == SCAN_IN || scan == SCAN_IO); + + // if we need to send bytes + if (byte_count > 0) { + // start the next cmd and copy the data out bytes to it + int retval = ch347_cmd_start_next(is_read ? CH347_CMD_JTAG_DATA_SHIFT_RD : CH347_CMD_JTAG_DATA_SHIFT); + if (retval != ERROR_OK) + return retval; + + if (bits) + retval = ch347_scratchpad_add_bytes(bits, byte_count); + else + retval = ch347_scratchpad_add_bytes(NULL, byte_count); + + if (retval != ERROR_OK) + return retval; + } + + // bits are always need to send; no possibility to not send bits + int retval = ch347_cmd_start_next(is_read ? CH347_CMD_JTAG_BIT_OP_RD : CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + + ch347.tms_pin = TMS_L; + ch347.tdi_pin = TDI_L; + + for (int i = 0; i < bit_count; i++) { + if (bits) + ch347.tdi_pin = ((bits[byte_count + i / 8] >> i % 8) & BIT(0)) ? TDI_H : TDI_L; + + // for the last bit set TMS high to exit the shift state + if (i + 1 == bit_count) + ch347.tms_pin = TMS_H; + + ch347.tck_pin = TCK_L; + retval = ch347_scratchpad_add_pin_byte(); + if (retval != ERROR_OK) + return retval; + + ch347.tck_pin = TCK_H; + retval = ch347_scratchpad_add_pin_byte(); + if (retval != ERROR_OK) + return retval; + + /* cut the package after each MAX_BITS_PER_BIT_OP bits because it + needs a dividable by 8 bits package */ + if (i > 0 && (i + 1) % MAX_BITS_PER_BIT_OP == 0) { + retval = ch347_cmd_from_scratchpad(); + if (retval != ERROR_OK) + return retval; + + retval = ch347_cmd_start_next(is_read ? CH347_CMD_JTAG_BIT_OP_RD : CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + } + } + + // one TCK_L after the last bit + retval = ch347_scratchpad_add_idle_clock(); + if (retval != ERROR_OK) + return retval; + + // if read is involved we need to queue the scan fields + if (is_read) + return ch347_scan_queue_fields(cmd->fields, cmd->num_fields); + + return ERROR_OK; +} + +/** + * @brief Toggle the Tap state to run test/idle + * + * @param cycles how many clock cycles for output + * @param state JTAG end state + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_run_test(int cycles, enum tap_state state) +{ + LOG_DEBUG_IO("cycles=%d, end_state=%d", cycles, state); + int retval; + if (tap_get_state() != TAP_IDLE) { + retval = ch347_scratchpad_add_move_state(TAP_IDLE, 0); + if (retval != ERROR_OK) + return retval; + } + + retval = ch347_scratchpad_add_stableclocks(cycles); + if (retval != ERROR_OK) + return retval; + + return ch347_scratchpad_add_move_state(state, 0); +} + +/** + * @brief Switch to SHIFT-DR or SHIFT-IR status for scanning + * + * @param cmd Upper layer transfer command parameters + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_scan(struct scan_command *cmd) +{ + static const char *const type2str[] = {"", "SCAN_IN", "SCAN_OUT", "SCAN_IO"}; + + enum scan_type type = jtag_scan_type(cmd); + uint8_t *buf = NULL; + int scan_bits = jtag_build_buffer(cmd, &buf); + + // add a move to IRSHIFT or DRSHIFT state + int retval; + if (cmd->ir_scan) + retval = ch347_scratchpad_add_move_state(TAP_IRSHIFT, 0); + else + retval = ch347_scratchpad_add_move_state(TAP_DRSHIFT, 0); + + if (retval != ERROR_OK) { + free(buf); + return retval; + } + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + char *log_buf = buf_to_hex_str(buf, scan_bits); + LOG_DEBUG_IO("scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d", + cmd->ir_scan ? "IRSCAN" : "DRSCAN", + type2str[type], + scan_bits, log_buf, cmd->end_state); + free(log_buf); + } + + retval = ch347_scratchpad_add_write_read(cmd, buf, scan_bits, type); + free(buf); + if (retval != ERROR_OK) + return retval; + + // add a move to the final state + return ch347_scratchpad_add_move_state(cmd->end_state, 1); +} + +/** + * @brief Sets a GPIO bit + * + * @param gpio GPIO bit number 0-7 + * @param data true for high; false for low + * @return ERROR_OK at success + */ +static int ch347_gpio_set(int gpio, bool data) +{ + int retval = ch347_cmd_start_next(CH347_CMD_GPIO); + if (retval != ERROR_OK) + return retval; + + uint8_t gpios[GPIO_CNT]; + memset(gpios, 0, GPIO_CNT); + /* always set bits 7 and 6 for GPIO enable + bits 5 and 4 for pin direction output + bit 3 is the data bit */ + gpios[gpio] = data == 0 ? GPIO_SET_L : GPIO_SET_H; + retval = ch347_scratchpad_add_bytes(gpios, GPIO_CNT); + if (retval != ERROR_OK) + return retval; + + // check in the read if the bit is set/cleared correctly + uint8_t byte; + retval = ch347_single_read_get_byte(gpio, &byte); + if (retval != ERROR_OK) + return retval; + + if ((byte & BIT(6)) >> 6 != data) { + LOG_ERROR("Output not set."); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +/** + * @brief Turn the activity LED on or off + * + * @param led_state LED_ON or LED_OFF + * @return ERROR_OK at success or if pin is not configured + */ +static int ch347_activity_led_set(int led_state) +{ + if (ch347_activity_led_gpio_pin != 0xFF) + return ch347_gpio_set(ch347_activity_led_gpio_pin, ch347_activity_led_active_high ? led_state : 1 - led_state); + + // not configured => also OK + return ERROR_OK; +} + +/** + * @brief Control (assert/deassert) the signals SRST and TRST on the interface. + * + * @param trst 1 to assert TRST, 0 to deassert TRST. + * @param srst 1 to assert SRST, 0 to deassert SRST. + * @return Always ERROR_FAIL for asserting via SRST and TRST in SWD mode. + * ERROR_OK for assert/deassert in JTAG mode for TRST + */ +static int ch347_reset(int trst, int srst) +{ + LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst); + if (srst) { + LOG_ERROR("Asserting SRST not supported!"); + return ERROR_FAIL; + } + + if (swd_mode) { + if (trst) + LOG_WARNING("Asserting TRST not supported in SWD mode!"); + return ERROR_OK; + } + + int retval = ch347_cmd_start_next(CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + + ch347.trst_pin = trst ? TRST_L : TRST_H; + retval = ch347_scratchpad_add_pin_byte(); + if (retval != ERROR_OK) + return retval; + + retval = ch347_scratchpad_add_idle_clock(); + if (retval != ERROR_OK) + return retval; + + return ch347_cmd_transmit_queue(); +} + +/** + * @brief Flushes the command buffer and sleeps for a specific timespan + * + * @param us Sleep time in microseconds + * @return ERROR_OK at success + */ +static int ch347_sleep(int us) +{ + LOG_DEBUG_IO("us=%d", us); + int retval = ch347_cmd_transmit_queue(); + jtag_sleep(us); + return retval; +} + +/** + * @brief Executes the command queue + * + * @return Success returns ERROR_OK + */ +static int ch347_execute_queue(struct jtag_command *cmd_queue) +{ + struct jtag_command *cmd = cmd_queue; + + int retval = ch347_activity_led_set(LED_ON); + if (retval != ERROR_OK) + return retval; + + while (retval == ERROR_OK && cmd) { + switch (cmd->type) { + case JTAG_RUNTEST: + retval = ch347_scratchpad_add_run_test(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); + break; + case JTAG_STABLECLOCKS: + retval = ch347_scratchpad_add_stableclocks(cmd->cmd.stableclocks->num_cycles); + break; + case JTAG_TLR_RESET: + retval = ch347_scratchpad_add_move_state(cmd->cmd.statemove->end_state, 0); + break; + case JTAG_PATHMOVE: + retval = ch347_scratchpad_add_move_path(cmd->cmd.pathmove); + break; + case JTAG_TMS: + retval = ch347_scratchpad_add_tms_change(cmd->cmd.tms->bits, cmd->cmd.tms->num_bits, 0); + break; + case JTAG_SLEEP: + retval = ch347_sleep(cmd->cmd.sleep->us); + break; + case JTAG_SCAN: + retval = ch347_scratchpad_add_scan(cmd->cmd.scan); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%X", cmd->type); + retval = ERROR_FAIL; + break; + } + + cmd = cmd->next; + } + + if (retval != ERROR_OK) + return retval; + + retval = ch347_cmd_transmit_queue(); + if (retval != ERROR_OK) + return retval; + + return ch347_activity_led_set(LED_OFF); +} + +/** + * @brief opens the CH347 device via libusb driver + * + * @return ERROR_OK on success + */ +static int ch347_open_device(void) +{ + const uint16_t *ch347_vids = default_ch347_vids; + const uint16_t *ch347_pids = default_ch347_pids; + + if (adapter_usb_get_vids()[0] != 0) { + ch347_vids = adapter_usb_get_vids(); + ch347_pids = adapter_usb_get_pids(); + } + + int retval = jtag_libusb_open(ch347_vids, ch347_pids, + adapter_usb_get_product_name(), &ch347_handle, NULL); + if (retval != ERROR_OK) { + char error_message[256]; + snprintf(error_message, sizeof(error_message), "CH347 not found. Tried VID/PID pairs: "); + for (int i = 0; ch347_vids[i] != 0; i++) + snprintf(error_message + strlen(error_message), sizeof(error_message) - strlen(error_message), + "%04x:%04x ", ch347_vids[i], ch347_pids[i]); + + LOG_ERROR("%s", error_message); + return retval; + } + + struct libusb_device_descriptor ch347_device_descriptor; + libusb_device *device = libusb_get_device(ch347_handle); + if (!device) { + LOG_ERROR("CH347 error calling libusb_get_device"); + jtag_libusb_close(ch347_handle); + return ERROR_FAIL; + } + + retval = libusb_get_device_descriptor(device, &ch347_device_descriptor); + if (retval != ERROR_OK) { + LOG_ERROR("CH347 error getting device descriptor: %s", libusb_error_name(retval)); + jtag_libusb_close(ch347_handle); + return retval; + } + + // Fix for CH347F on ARM64 + // Force set configuration 1 (required on some ARM64 platforms) + retval = libusb_set_configuration(ch347_handle, 1); + if (retval != LIBUSB_SUCCESS && retval != LIBUSB_ERROR_BUSY) + LOG_WARNING("CH347 set_configuration failed: %s", libusb_error_name(retval)); + + // CH347T / CH347F detection + // if we can claim interface 4 we found a CH347F chip; if we can claim interface 2 we found CH347T chip + retval = libusb_claim_interface(ch347_handle, CH347F_MPHSI_INTERFACE); + if (retval != ERROR_OK) { + retval = libusb_claim_interface(ch347_handle, CH347T_MPHSI_INTERFACE); + if (retval != ERROR_OK) { + LOG_ERROR("CH347 unable to claim interface: %s", libusb_error_name(retval)); + jtag_libusb_close(ch347_handle); + return retval; + } + ch347.chip_variant = CH347T; + } else { + ch347.chip_variant = CH347F; + } + + char firmware_version; + retval = jtag_libusb_control_transfer(ch347_handle, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + VENDOR_VERSION, 0, 0, &firmware_version, sizeof(firmware_version), + USB_WRITE_TIMEOUT, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("CH347 unable to get firmware version"); + jtag_libusb_close(ch347_handle); + return retval; + } + + char manufacturer[256 + 1]; + if (libusb_get_string_descriptor_ascii(ch347_handle, ch347_device_descriptor.iManufacturer, + (unsigned char *)manufacturer, sizeof(manufacturer) - 1) < 0) { + strcpy(manufacturer, "(unknown)"); + } + char product[256 + 1]; + if (libusb_get_string_descriptor_ascii(ch347_handle, ch347_device_descriptor.iProduct, + (unsigned char *)product, sizeof(product) - 1) < 0) { + strcpy(product, "(unknown)"); + } + char serial_number[256 + 1]; + if (libusb_get_string_descriptor_ascii(ch347_handle, ch347_device_descriptor.iSerialNumber, + (unsigned char *)serial_number, sizeof(serial_number) - 1) < 0) { + strcpy(serial_number, "(unknown)"); + } + + LOG_INFO("CH347 %s from vendor %s with serial number %s found. (Chip version=%X.%2X, Firmware=0x%02X)", + product, + manufacturer, + serial_number, + (ch347_device_descriptor.bcdDevice >> 8) & 0xFF, + ch347_device_descriptor.bcdDevice & 0xFF, + firmware_version); + + if (ch347.chip_variant == CH347T && ch347_device_descriptor.bcdDevice < BYTEWISE_MODE_VERSION) { + LOG_INFO("CH347T old version of the chip, JTAG only working in bitwise mode. For bytewise mode at least version %X.%X is needed.", + (BYTEWISE_MODE_VERSION >> 8) & 0xFF, + BYTEWISE_MODE_VERSION & 0xFF); + ch347.use_bitwise_mode = true; + } else { + ch347.use_bitwise_mode = false; + } + + if (ch347.chip_variant == CH347T) { + if (swd_mode) { + ch347.swclk_5mhz_supported = ch347_device_descriptor.bcdDevice >= 0x544; + + if (ch347_device_descriptor.bcdDevice < 0x441) + LOG_WARNING("CH347T version older than 4.41 probably does not support SWD transport"); + + if (ch347_device_descriptor.bcdDevice == 0x441) + LOG_WARNING("If CH347T version 4.41 cannot connect or SWD fails often, insert a resistor to SWDIO circuit"); + + } else if (ch347_device_descriptor.bcdDevice == 0x241) { + LOG_WARNING("CH347T version 2.41 has very weird clock timing, may not work with a slower JTAG device"); + } + + if (ch347_device_descriptor.bcdDevice < 0x544) + LOG_INFO("Please upgrade CH347T firmware to a production version >= 5.44"); + + } else if (ch347.chip_variant == CH347F) { + ch347.swclk_5mhz_supported = ch347_device_descriptor.bcdDevice >= 0x101; + + if (ch347_device_descriptor.bcdDevice < 0x101) + LOG_INFO("Please upgrade CH347F firmware to a production version >= 1.1"); + } + + return ERROR_OK; +} + +/** + * @brief CH347 Device Release Function + * + * @return ERROR_OK on success + */ +static int ch347_quit(void) +{ + // on close set the LED on, because the state without JTAG is on + ch347_activity_led_set(LED_ON); + int retval = ch347_cmd_transmit_queue(); + jtag_libusb_close(ch347_handle); + LOG_DEBUG_IO("CH347 close"); + return retval; +} + +/** + * @brief Sends the CH347_CMD_JTAG_INIT (D0) command to get the JTAG + * interface initialized with the speed index or asking with special clock index 9 + * for the LARGER_PACK mode support + * + * @param clock_index Clock index; special clock index 9 is used for checking + * if the device supports the LARGER_PACK mode + * @param supports_larger_pack_mode returns true if the device supports the LARGER_PACK mode + * for newer CH347 devices; false if the device supports only the older STANDARD_PACK mode + * @return ERROR_OK on success + */ +static int ch347_adapter_init(uint8_t clock_index, bool *supports_larger_pack_mode) +{ + int retval = ch347_cmd_start_next(CH347_CMD_JTAG_INIT); + if (retval != ERROR_OK) + return retval; + + retval = ch347_scratchpad_add_byte(0); + if (retval != ERROR_OK) + return retval; + + retval = ch347_scratchpad_add_byte(clock_index); + if (retval != ERROR_OK) + return retval; + + for (int i = 0; i < 4; i++) { + retval = ch347_scratchpad_add_pin_byte(); + if (retval != ERROR_OK) + return retval; + } + + uint8_t mode; + retval = ch347_single_read_get_byte(0, &mode); + if (retval != ERROR_OK) + return retval; + + *supports_larger_pack_mode = mode != 0; + return ERROR_OK; +} + +/** + * @brief Sends the CH347_CMD_JTAG_INIT (D0) command to ask the JTAG + * interface with special clock index 9 for the LARGER_PACK mode support + * + * @param supports_larger_pack_mode returns true if the device supports the LARGER_PACK mode + * for newer CH347 devices; false if the device supports only the older STANDARD_PACK mode + * @return ERROR_OK on success + */ +static int ch347_adapter_supports_larger_pack_mode(bool *supports_larger_pack_mode) +{ + return ch347_adapter_init(CH347_CMD_INIT_GET_MODE_CLOCK_INDEX_VALUE, supports_larger_pack_mode); +} + +/** + * @brief Sends the CH347_CMD_JTAG_INIT (D0) command to get the JTAG + * interface initialized with the speed index + * + * @param clock_index Clock index + * @return ERROR_OK on success + */ +static int ch347_adapter_set_speed(uint8_t clock_index) +{ + bool unused; + return ch347_adapter_init(clock_index, &unused); +} + +/** + * @brief swd init function + * @param clock_divisor Divisor of base SWD frequency 1 MHz or 0 for fast 5 MHz clock + * + * @return ERROR_OK on success + */ +static int ch347_swd_init_cmd(uint8_t clock_divisor) +{ + int retval = ch347_cmd_start_next(CH347_CMD_SWD_INIT); + if (retval != ERROR_OK) + return retval; + + uint8_t cmd_data[] = {0x40, 0x42, 0x0f, 0x00, clock_divisor, 0x00, 0x00, 0x00 }; + retval = ch347_scratchpad_add_bytes(cmd_data, ARRAY_SIZE(cmd_data)); + if (retval != ERROR_OK) + return retval; + + /* TODO: CH347_CMD_SWD_INIT reads one data byte. + But how can we decide if SWD init was successfully executed? + Return an error code if init was failed */ + uint8_t init_result = 0; + retval = ch347_single_read_get_byte(0, &init_result); + LOG_DEBUG("SWD init clk div %" PRIu8 ", result %02" PRIx8, + clock_divisor, init_result); + ch347_swd_context.clk_divisor = clock_divisor; + return retval; +} + +/** + * @brief Initializes the JTAG interface and set CH347 TCK frequency + * + * @param speed_index speed index for JTAG_INIT command + * @return Success returns ERROR_OK, failed returns ERROR_FAIL + */ +static int ch347_speed_set(int speed_index) +{ + if (swd_mode) + return ch347_swd_init_cmd(speed_index); + + int retval = ch347_adapter_set_speed(speed_index); + if (retval != ERROR_OK) { + LOG_ERROR("Couldn't set CH347 speed"); + return retval; + } + + return ERROR_OK; +} + +/** + * @brief inits ch347.pack_size and ch347.max_len + * + * @return ERROR_OK on success + */ +static int ch347_init_pack_size(void) +{ + // already set? + if (ch347.pack_size != UNSET) + return ERROR_OK; + + // set the lower limit for starting + ch347.max_len = MIN(USBC_PACKET_USBHS, LARGER_PACK_MAX_SIZE); + bool supports_larger_pack_mode; + int retval = ch347_adapter_supports_larger_pack_mode(&supports_larger_pack_mode); + if (retval != ERROR_OK) + return retval; + + ch347.pack_size = supports_larger_pack_mode ? LARGER_PACK : STANDARD_PACK; + ch347.max_len = ch347.pack_size == STANDARD_PACK || ch347.use_bitwise_mode ? + USBC_PACKET_USBHS : LARGER_PACK_MAX_SIZE; + return ERROR_OK; +} + +/** + * @brief returns the speed in kHz by the give speed index + * + * @param speed_idx CH347 speed index + * @param khz Output of the speed in kHz + * @return ERROR_OK on success + */ +static int ch347_speed_get(int speed_idx, int *khz) +{ + if (swd_mode) { + if (speed_idx) + *khz = DIV_ROUND_UP(CH347_SWD_CLOCK_BASE, speed_idx); + else + *khz = CH347_SWD_CLOCK_MAX; + return ERROR_OK; + } + + int retval = ch347_init_pack_size(); + if (retval != ERROR_OK) + return retval; + const int *speeds = ch347.pack_size == STANDARD_PACK ? + ch347_standard_pack_clock_speeds : ch347_larger_pack_clock_speeds; + *khz = speeds[speed_idx]; + return ERROR_OK; +} + +/** + * @brief multiplies the input speed by 1000 + * + * @param khz Speed in kHz + * @param speed_idx CH347 speed index + * @return ERROR_OK at success; ERROR_FAIL if khz is zero + */ +static int ch347_speed_get_index(int khz, int *speed_idx) +{ + if (khz == 0) { + LOG_ERROR("Adaptive clocking not supported"); + return ERROR_FAIL; + } + + if (swd_mode) { + if (khz >= CH347_SWD_CLOCK_MAX && ch347.swclk_5mhz_supported) { + *speed_idx = 0; + } else { + // Don't allow too low clk speeds: packet processing is limited to ~8 msec + // or triggers host USB disconnect + *speed_idx = MIN(DIV_ROUND_UP(CH347_SWD_CLOCK_BASE, khz), + (int)CH347_SWD_CLOCK_MAX_DIVISOR); + } + return ERROR_OK; + } + + // when checking with speed index 9 we can see if the device supports STANDARD_PACK or LARGER_PACK mode + int retval = ch347_init_pack_size(); + if (retval != ERROR_OK) + return retval; + // depending on pack size there are different fixed clock speeds possible + const int *speeds = ch347.pack_size == STANDARD_PACK ? + ch347_standard_pack_clock_speeds : ch347_larger_pack_clock_speeds; + int length = ch347.pack_size == STANDARD_PACK ? + ARRAY_SIZE(ch347_standard_pack_clock_speeds) : ARRAY_SIZE(ch347_larger_pack_clock_speeds); + int idx = -1; + int lower_bound = 0; + // find the suitable speed index + for (int i = 0; i < length; i++) { + if (khz >= lower_bound && khz <= speeds[i]) { + idx = i; + break; + } + lower_bound = speeds[i]; + } + // too high! => use max possible speed + if (idx == -1) { + LOG_INFO("Speed %d kHz is higher than highest speed of %d kHz. Using %d khz!", + khz, speeds[length - 1], speeds[length - 1]); + idx = length - 1; + } else if (speeds[idx] != khz) { + LOG_INFO("Requested speed of %d kHz is not possible. Using the next higher speed of %d kHz!", + khz, speeds[idx]); + } + *speed_idx = idx; + return ERROR_OK; +} + +static const struct command_registration ch347_command_handlers[] = { + { + .name = "ch347", + .mode = COMMAND_ANY, + .help = "perform ch347 management", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +/** + * @brief Configure which GPIO pin is used as the activity LED. + * + * Updates the global activity LED GPIO pin and polarity settings + * based on the provided configuration. If the given GPIO is not + * usable, the function returns without making changes. + * + * @param led_config Pointer to the GPIO configuration structure for the LED pin + */ +static void ch347_configure_activity_led(const struct adapter_gpio_config *led_config) +{ + uint8_t gpio = led_config->gpio_num; + if (gpio >= GPIO_CNT || (BIT(gpio) & USEABLE_GPIOS) == 0) + return; + + ch347_activity_led_gpio_pin = gpio; + ch347_activity_led_active_high = !led_config->active_low; +} + +/** + * @brief CH347 Initialization function + * + * @return ERROR_OK on success + */ +static int ch347_init(void) +{ + int retval = ch347_open_device(); + + if (retval != ERROR_OK) { + LOG_ERROR("CH347 open error"); + return retval; + } + + LOG_DEBUG_IO("CH347 open success"); + + // CH347 JTAG init + ch347.tck_pin = TCK_L; + ch347.tms_pin = TMS_H; + ch347.tdi_pin = TDI_L; + ch347.trst_pin = TRST_H; + INIT_LIST_HEAD(&ch347.cmd_queue); + INIT_LIST_HEAD(&ch347.scan_queue); + + ch347.pack_size = UNSET; + + ch347_configure_activity_led(&adapter_gpio_get_config()[ADAPTER_GPIO_IDX_LED]); + + if (!swd_mode) { + tap_set_state(TAP_RESET); + } else { + retval = ch347_init_pack_size(); + if (retval != ERROR_OK) + return retval; + + retval = ch347_swd_init_cmd(1); + } + return retval; +} + +/** + * @brief Initialization for the swd mode + * + * @return Always ERROR_OK + */ +static int ch347_swd_init(void) +{ + LOG_INFO("CH347 SWD mode enabled"); + swd_mode = true; + memset(&ch347_swd_context, 0, sizeof(ch347_swd_context)); + + INIT_LIST_HEAD(&ch347_swd_context.send_cmd_head); + INIT_LIST_HEAD(&ch347_swd_context.free_cmd_head); + + ch347_swd_context.queued_retval = ERROR_OK; + // 0XE8 + 2byte len + N byte cmds + ch347_swd_context.send_len = CH347_CMD_HEADER; + // 0XE8 + 2byte len + N byte ack + data + ch347_swd_context.need_recv_len = CH347_CMD_HEADER; + struct ch347_swd_io *pswd_io = ch347_swd_context.ch347_cmd_buf; + for (int i = 0; i < CH347_MAX_CMD_BUF; i++, pswd_io++) { + INIT_LIST_HEAD(&pswd_io->list_entry); + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.free_cmd_head); + } + return ERROR_OK; +} + +static struct ch347_swd_io *ch347_get_one_swd_io(void) +{ + struct ch347_swd_io *pswd_io; + if (list_empty(&ch347_swd_context.free_cmd_head)) + return NULL; + + pswd_io = list_first_entry(&ch347_swd_context.free_cmd_head, + struct ch347_swd_io, list_entry); + list_del_init(&pswd_io->list_entry); + pswd_io->cmd = 0; + pswd_io->usb_cmd = CH347_CMD_SWD_SEQ_W; + pswd_io->dst = NULL; + return pswd_io; +} + +static int ch347_swd_queue_flush(void) +{ + int length = ch347_swd_context.send_len; + ch347_swd_context.send_buf[0] = CH347_CMD_SWD; + h_u16_to_le(&ch347_swd_context.send_buf[1], length - CH347_CMD_HEADER); + int retval = ch347_write_data(ch347_swd_context.send_buf, &length); + if (retval != ERROR_OK) { + ch347_swd_context.queued_retval = retval; + LOG_DEBUG("CH347WriteData error"); + return retval; + } + + ch347_swd_context.recv_len = 0; + length = ch347_swd_context.need_recv_len; + retval = ch347_read_data(&ch347_swd_context.recv_buf[ch347_swd_context.recv_len], &length); + if (retval != ERROR_OK) { + ch347_swd_context.queued_retval = retval; + LOG_DEBUG("CH347ReadData error"); + return retval; + } + + ch347_swd_context.recv_len += length; + if (ch347_swd_context.need_recv_len > ch347_swd_context.recv_len) { + LOG_ERROR("write/read failed %d %d", + ch347_swd_context.recv_len, + ch347_swd_context.need_recv_len); + retval = ERROR_FAIL; + } + + return retval; +} + +static void ch347_write_swd_reg(uint8_t cmd, const uint32_t out) +{ + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = CH347_CMD_SWD_REG_W; + // 8bit + 32bit +1bit + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x29; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = cmd; + h_u32_to_le(&ch347_swd_context.send_buf[ch347_swd_context.send_len], out); + ch347_swd_context.send_len += 4; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = parity_u32(out); + // 0xA0 + 1 byte(3bit ACK) + ch347_swd_context.need_recv_len += (1 + 1); + ch347_swd_context.total_swd_clk += 46; +} + +static void ch347_write_spec_seq(const uint8_t *out, uint8_t out_len) +{ + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = + CH347_CMD_SWD_SEQ_W; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out_len; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; + for (uint8_t i = 0; i < DIV_ROUND_UP(out_len, 8); i++) + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out ? out[i] : 0x00; + ch347_swd_context.need_recv_len += 1; // 0xA1 + ch347_swd_context.total_swd_clk += out_len; +} + +static void ch347_read_swd_reg(uint8_t cmd) +{ + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = CH347_CMD_SWD_REG_R; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x22; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = cmd; + // 0xA2 + 1 byte(3bit ACK) + 4 byte(data) + 1 byte(1bit parity+1bit trn) + ch347_swd_context.need_recv_len += 1 + 1 + 4 + 1; + ch347_swd_context.total_swd_clk += 46; +} + +static int ch347_swd_switch_out(enum swd_special_seq seq, const uint8_t *out, unsigned int out_len) +{ + if ((ch347_swd_context.send_len + (1 + 2 + DIV_ROUND_UP(out_len, 8))) > CH347_MAX_SEND_BUF) + return ERROR_FAIL; + if ((ch347_swd_context.need_recv_len + 2) > CH347_MAX_RECV_BUF) + return ERROR_FAIL; + + struct ch347_swd_io *pswd_io = ch347_get_one_swd_io(); + if (pswd_io) { + ch347_write_spec_seq(out, out_len); + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); + return ERROR_OK; + } else { + return ERROR_FAIL; + } +} + +// check read/write REG can fill in remaining buff +static bool ch347_chk_buf_size(uint8_t cmd, uint32_t ap_delay_clk) +{ + bool flush = false; + int send_len = ch347_swd_context.send_len; + int recv_len = ch347_swd_context.need_recv_len; + int len; + do { + if (cmd & SWD_CMD_RNW) { + len = 1 + 1 + 1 + 1; // 0xA2 + len + rev + cmd + if (send_len + len > CH347_MAX_SEND_BUF) + break; + send_len += len; + len = 1 + 1 + 4 + 1; + /* 0xA2 + 1byte(3bit ack) + 4byte(data) + + 1byte(1bit parity+1bit trn) */ + if (recv_len + len > CH347_MAX_RECV_BUF) + break; + recv_len += len; + } else { // write reg + len = 1 + 1 + 1 + 1 + 4 + 1; + // 0xA0 + len + rev + cmd +data + parity + if (send_len + len > CH347_MAX_SEND_BUF) + break; + send_len += len; + len = 1 + 1; // 0xA0 + 1byte(3bit ack) + if (recv_len + len > CH347_MAX_RECV_BUF) + break; + recv_len += len; + } + if (cmd & SWD_CMD_APNDP) { + len = 1 + 1 + 1 + DIV_ROUND_UP(ap_delay_clk, 8); + // 0xA1 + Len + rev + n byte(delay) + if (send_len + len > CH347_MAX_SEND_BUF) + break; + len = 1; // 0xA1 + if ((recv_len + len) > CH347_MAX_RECV_BUF) + break; + } + // swd packet requests + flush = true; + } while (false); + + return flush; +} + +static int ch347_swd_run_queue_inner(void); + +static int ch347_swd_send_idle(uint32_t ap_delay_clk) +{ + bool run_q = false; + struct ch347_swd_io *pswd_io = NULL; + unsigned int max_processing_clk = ch347_swd_context.clk_divisor + ? CH347_MAX_PROCESSING_US / ch347_swd_context.clk_divisor + : CH347_MAX_PROCESSING_US * 5; + bool more_q_runs = + 1 + 1 + 1 + DIV_ROUND_UP(ap_delay_clk, 8) > CH347_MAX_SEND_BUF + && ap_delay_clk > max_processing_clk; + + if (ch347_swd_context.sent_cmd_count) { + unsigned int expected_total_clk = ch347_swd_context.total_swd_clk + ap_delay_clk; + unsigned int expected_send_len = ch347_swd_context.send_len + + 1 + 1 + 1 + DIV_ROUND_UP(ap_delay_clk, 8); + // 0xA1 + Len + rev + n byte(delay) + unsigned int expected_recv_len = ch347_swd_context.need_recv_len + 1; + // 0xA1 + unsigned int expected_time = ch347_swd_context.clk_divisor + ? expected_total_clk * ch347_swd_context.clk_divisor + : expected_total_clk / 5; + if (expected_time > CH347_MAX_PROCESSING_US + || expected_send_len > CH347_MAX_SEND_BUF + || expected_recv_len > CH347_MAX_RECV_BUF) { + int send_room = CH347_MAX_SEND_BUF - ch347_swd_context.send_len - 1 - 1 - 1; + if (more_q_runs + && send_room > 0 + && expected_recv_len <= CH347_MAX_RECV_BUF + && ch347_swd_context.total_swd_clk < max_processing_clk) { + pswd_io = ch347_get_one_swd_io(); + if (pswd_io) { + // fill the rest of queue/time by part of delay + unsigned int this_delay_clk = MIN(ap_delay_clk, 255); + if ((unsigned int)send_room * 8 < this_delay_clk) + this_delay_clk = send_room * 8; + if (max_processing_clk - ch347_swd_context.total_swd_clk < this_delay_clk) + this_delay_clk = max_processing_clk - ch347_swd_context.total_swd_clk; + LOG_DEBUG_IO("partial delay %u clk", this_delay_clk); + ch347_write_spec_seq(NULL, this_delay_clk); + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); + ap_delay_clk -= this_delay_clk; + } + } + run_q = true; + } + } + + do { + if (!run_q) + pswd_io = ch347_get_one_swd_io(); + + if (!pswd_io) { + int retval = ch347_swd_run_queue_inner(); + if (retval != ERROR_OK) + return retval; + + pswd_io = ch347_get_one_swd_io(); + if (!pswd_io) { + LOG_ERROR("ch347 SWD queue not empty after ch347_swd_run_queue"); + ch347_swd_context.queued_retval = ERROR_FAIL; + return ERROR_FAIL; + } + } + + unsigned int send_room = CH347_MAX_SEND_BUF - 1 - 1 - 1; + unsigned int this_delay_clk = MIN(ap_delay_clk, 255); + if (send_room * 8 < this_delay_clk) + this_delay_clk = send_room * 8; + if (max_processing_clk < this_delay_clk) + this_delay_clk = max_processing_clk; + LOG_DEBUG_IO("delay %u clk", this_delay_clk); + ch347_write_spec_seq(NULL, this_delay_clk); + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); + ap_delay_clk -= this_delay_clk; + run_q = true; + pswd_io = NULL; + } while (ap_delay_clk); + return ERROR_OK; +} + +static int ch347_swd_run_queue_inner(void) +{ + LOG_DEBUG_IO("Executing %u queued transactions", ch347_swd_context.sent_cmd_count); + if (ch347_swd_context.queued_retval != ERROR_OK) { + LOG_DEBUG_IO("Skipping due to previous errors: %d", ch347_swd_context.queued_retval); + goto skip; + } + + int retval = ch347_swd_queue_flush(); + if (retval != ERROR_OK) + return retval; + + if (ch347_swd_context.queued_retval != ERROR_OK) { + LOG_ERROR("CH347 usb write/read failed - queued_retval"); + goto skip; + } + uint8_t *recv_buf = ch347_swd_context.recv_buf; + int recv_len = 0; + if (recv_buf[recv_len++] != CH347_CMD_SWD) { // 0XE8 + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed - not CH347_CMD_SWD"); + goto skip; + } + + int cmds_len = le_to_h_u16(&recv_buf[recv_len]); + recv_len += 2; // cmds_len + if ((cmds_len + CH347_CMD_HEADER) > ch347_swd_context.recv_len) { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed - too long"); + goto skip; + } + + struct list_head *tmp; + struct list_head *pos; + struct ch347_swd_io *pswd_io; + + list_for_each_safe(pos, tmp, &ch347_swd_context.send_cmd_head) { + pswd_io = list_entry(pos, struct ch347_swd_io, list_entry); + if (pswd_io->usb_cmd == CH347_CMD_SWD_SEQ_W) { + if (recv_buf[recv_len++] != CH347_CMD_SWD_SEQ_W) { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed - not CH347_CMD_SWD_SEQ_W"); + goto skip; + } + } else { // read/write Reg + uint32_t ack; + bool check_ack; + // read Reg + if (recv_buf[recv_len] == CH347_CMD_SWD_REG_R) { + recv_len++; + ack = buf_get_u32(&recv_buf[recv_len++], 0, 3); + /* Devices do not reply to DP_TARGETSEL write + cmd, ignore received ack */ + check_ack = swd_cmd_returns_ack(pswd_io->cmd); + if (pswd_io->cmd & SWD_CMD_RNW) { + uint32_t data = buf_get_u32(&recv_buf[recv_len], 0, 32); + + LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK) + ? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO, + "%s%s %s read reg %X = %08" PRIx32, + check_ack ? "" : "ack ignored ", + ack == SWD_ACK_OK ? "OK" : + ack == SWD_ACK_WAIT ? "WAIT" : + ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP", + (pswd_io->cmd & SWD_CMD_A32) >> 1, + data); + + if (ack != SWD_ACK_OK && check_ack) { + ch347_swd_context.queued_retval = swd_ack_to_error_code(ack); + goto skip; + } + + uint32_t parity = buf_get_u32(&recv_buf[recv_len], 32, 1); + if (parity != (uint32_t)parity_u32(data)) { + LOG_ERROR("SWD Read data parity mismatch"); + ch347_swd_context.queued_retval = ERROR_FAIL; + goto skip; + } + + if (pswd_io->dst) + *pswd_io->dst = data; + } else { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed - not SWD_CMD_RNW"); + goto skip; + } + recv_len += 5; + } else if (recv_buf[recv_len] == CH347_CMD_SWD_REG_W) { + recv_len++; + ack = buf_get_u32(&recv_buf[recv_len++], 0, 3); + /* Devices do not reply to DP_TARGETSEL write + cmd, ignore received ack */ + check_ack = swd_cmd_returns_ack(pswd_io->cmd); + + LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK) + ? 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", + pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP", + (pswd_io->cmd & SWD_CMD_A32) >> 1, + pswd_io->value); + + if (ack != SWD_ACK_OK && check_ack) { + ch347_swd_context.queued_retval = swd_ack_to_error_code(ack); + goto skip; + } + } else { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed recv_len = %d", recv_len); + goto skip; + } + } + list_del_init(&pswd_io->list_entry); + list_add_tail(&pswd_io->list_entry, + &ch347_swd_context.free_cmd_head); + } + +skip: + if (!list_empty(&ch347_swd_context.send_cmd_head)) { + list_for_each_safe(pos, tmp, &ch347_swd_context.send_cmd_head) { + pswd_io = list_entry(pos, struct ch347_swd_io, list_entry); + list_del_init(&pswd_io->list_entry); + list_add_tail(&pswd_io->list_entry, + &ch347_swd_context.free_cmd_head); + } + } + + // 0xE8 + 2byte len + ch347_swd_context.send_len = CH347_CMD_HEADER; + // 0xE8 + 2byte len + ch347_swd_context.need_recv_len = CH347_CMD_HEADER; + ch347_swd_context.recv_len = 0; + ch347_swd_context.sent_cmd_count = 0; + ch347_swd_context.total_swd_clk = 0; + retval = ch347_swd_context.queued_retval; + ch347_swd_context.queued_retval = ERROR_OK; + return retval; +} + +static int ch347_swd_run_queue(void) +{ + /* A transaction must be followed by another transaction or at least 8 + idle cycles to ensure that data is clocked through the AP. */ + int retval = ch347_swd_send_idle(8); + if (retval != ERROR_OK) + return retval; + + return ch347_swd_run_queue_inner(); +} + +static int ch347_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk) +{ + int retval = ERROR_OK; + bool run_q = false; + if (ch347_swd_context.sent_cmd_count) { + unsigned int expected_total_clk = ch347_swd_context.total_swd_clk + + 46 // SWD transaction + + ap_delay_clk + + 8; // 8 idle cycles at the end of queue + unsigned int expected_time = ch347_swd_context.clk_divisor + ? expected_total_clk * ch347_swd_context.clk_divisor + : expected_total_clk / 5; + if (expected_time > CH347_MAX_PROCESSING_US) { + LOG_DEBUG_IO("Expected queue run %u cycles, with this cmd %u", + ch347_swd_context.total_swd_clk, expected_total_clk); + run_q = true; + } else if (!ch347_chk_buf_size(cmd, ap_delay_clk)) { + run_q = true; + } + } + + struct ch347_swd_io *pswd_io = NULL; + if (!run_q) + pswd_io = ch347_get_one_swd_io(); + + if (!pswd_io) { + retval = ch347_swd_run_queue_inner(); + if (retval != ERROR_OK) + return retval; + + pswd_io = ch347_get_one_swd_io(); + if (!pswd_io) { + LOG_ERROR("ch347 SWD queue not empty after ch347_swd_run_queue"); + ch347_swd_context.queued_retval = ERROR_FAIL; + return ERROR_FAIL; + } + } + + pswd_io->cmd = cmd | SWD_CMD_START | SWD_CMD_PARK; + + if (pswd_io->cmd & SWD_CMD_RNW) { + pswd_io->usb_cmd = CH347_CMD_SWD_REG_R; + pswd_io->dst = dst; + ch347_read_swd_reg(pswd_io->cmd); + } else { + pswd_io->usb_cmd = CH347_CMD_SWD_REG_W; + pswd_io->value = data; + ch347_write_swd_reg(pswd_io->cmd, data); + } + + ch347_swd_context.sent_cmd_count++; + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); + + // Insert idle cycles after AP accesses to avoid WAIT + if (ap_delay_clk) + retval = ch347_swd_send_idle(ap_delay_clk); + + return retval; +} + +static int ch347_swd_switch_seq(enum swd_special_seq seq) +{ + switch (seq) { + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + return ch347_swd_switch_out(seq, swd_seq_line_reset, swd_seq_line_reset_len); + case JTAG_TO_SWD: + LOG_DEBUG("JTAG-to-SWD"); + return ch347_swd_switch_out(seq, swd_seq_jtag_to_swd, swd_seq_jtag_to_swd_len); + case JTAG_TO_DORMANT: + LOG_DEBUG("JTAG-to-DORMANT"); + return ch347_swd_switch_out(seq, swd_seq_jtag_to_dormant, swd_seq_jtag_to_dormant_len); + case SWD_TO_JTAG: + LOG_DEBUG("SWD-to-JTAG"); + return ch347_swd_switch_out(seq, swd_seq_swd_to_jtag, swd_seq_swd_to_jtag_len); + case SWD_TO_DORMANT: + LOG_DEBUG("SWD-to-DORMANT"); + return ch347_swd_switch_out(seq, swd_seq_swd_to_dormant, swd_seq_swd_to_dormant_len); + case DORMANT_TO_SWD: + LOG_DEBUG("DORMANT-to-SWD"); + return ch347_swd_switch_out(seq, swd_seq_dormant_to_swd, swd_seq_dormant_to_swd_len); + case DORMANT_TO_JTAG: + LOG_DEBUG("DORMANT-to-JTAG"); + return ch347_swd_switch_out(seq, swd_seq_dormant_to_jtag, swd_seq_dormant_to_jtag_len); + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; + } +} + +static void ch347_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) +{ + assert(cmd & SWD_CMD_RNW); + int retval = ch347_swd_queue_cmd(cmd, value, 0, ap_delay_clk); + if (retval != ERROR_OK) + ch347_swd_context.queued_retval = retval; +} + +static void ch347_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) +{ + assert(!(cmd & SWD_CMD_RNW)); + int retval = ch347_swd_queue_cmd(cmd, NULL, value, ap_delay_clk); + if (retval != ERROR_OK) + ch347_swd_context.queued_retval = retval; +} + +static const struct swd_driver ch347_swd = { + .init = ch347_swd_init, + .switch_seq = ch347_swd_switch_seq, + .read_reg = ch347_swd_read_reg, + .write_reg = ch347_swd_write_reg, + .run = ch347_swd_run_queue, +}; + +static struct jtag_interface ch347_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = ch347_execute_queue, +}; + +struct adapter_driver ch347_adapter_driver = { + .name = "ch347", + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, + .commands = ch347_command_handlers, + + .init = ch347_init, + .quit = ch347_quit, + .reset = ch347_reset, + .speed = ch347_speed_set, + .khz = ch347_speed_get_index, + .speed_div = ch347_speed_get, + + .jtag_ops = &ch347_interface, + .swd_ops = &ch347_swd, +}; diff --git a/src/jtag/drivers/cklink.c b/src/jtag/drivers/cklink.c new file mode 100644 index 0000000000..0e974fe2ee --- /dev/null +++ b/src/jtag/drivers/cklink.c @@ -0,0 +1,747 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * T-Head CK-Link JTAG adapter driver. * + * * + * Supports the CK-Link Lite V2 wire protocol used by T-Head probes and * + * Bouffalo Lab BL616/BL702 CK-Link clones. USB bulk with a framed * + * command protocol reverse-engineered from T-Head's DebugServer. * + * * + * Copyright (C) 2026 by William Markezana * + * * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include "libusb_helper.h" + +// USB identification. Defaults can be overridden via `adapter usb vid_pid`. +#define CKLINK_VID_BOUFFALO 0x42bf +#define CKLINK_VID_THEAD 0x32bf +#define CKLINK_PID_LITE_V2 0xb210 + +#define CKLINK_USB_INTERFACE 0 +#define CKLINK_EP_OUT 0x02 +#define CKLINK_EP_IN 0x81 +#define CKLINK_USB_TIMEOUT_MS 1000 +#define CKLINK_USB_BUF_SIZE 2048 + +// Wire-protocol framing bytes +#define CKLINK_FRAME_START 0x68 +#define CKLINK_FRAME_END 0x16 + +// Response frame layout: start + status + payload + checksum + end +#define CKLINK_FRAME_OVERHEAD 4 +#define CKLINK_RESP_PAYLOAD_OFFSET 2 + +// Opcodes +#define CKLINK_OP_SELFREG_WRITE 0x06 +#define CKLINK_OP_SELFREG_READ 0x87 +#define CKLINK_OP_JTAG_BATCH 0x88 + +// Self-register indices +#define CKLINK_SR_CSR 0 // clock divider + CDI mode +#define CKLINK_SR_MTCR_WAIT 1 // target-comm wait cycles +#define CKLINK_SR_JTAG_CONFIG 8 // JTAG config word +#define CKLINK_SELFREG_BYTES 4 + +/* + * Init values replayed from a captured DebugServer session. + * sr0 (CSR): byte 0 = clock divider, byte 3 = CDI mode (0x60=5-wire JTAG, + * 0x61=2-wire cJTAG). The 5->2->5 mode toggle at end of init acts as a + * TAP reset: the wire driver re-initializes on each switch. + * sr1 MTCR_WAIT = 1000 cycles. sr8 JTAG_CONFIG: opaque, known-good. + */ +#define CKLINK_SR0_SETUP_CLK_BYTE 0x17 // ~2000 kHz +#define CKLINK_SR0_RUN_CLK_BYTE 0x12 // ~2526 kHz, DebugServer default +#define CKLINK_SR0_MODE_JTAG 0x60 +#define CKLINK_SR0_MODE_CJTAG 0x61 +#define CKLINK_SR1_INIT_VALUE 0x000003e8 +#define CKLINK_SR8_INIT_VALUE 0x00622250 + +// freq_kHz = 48000 / (N + 1); cap at DebugServer-validated 0x12. +#define CKLINK_CLK_SOURCE_KHZ 48000 +#define CKLINK_CLK_DIV_MIN CKLINK_SR0_RUN_CLK_BYTE +#define CKLINK_CLK_DIV_MAX 0xff + +#define CKLINK_CSR(clk, mode) (((uint32_t)(mode) << 24) | (clk)) + +// Batch opcode encodes IR/DR bit-counts in single bytes. +#define CKLINK_MAX_SCAN_BITS 255 +#define CKLINK_MAX_SCAN_BYTES 32 // DIV_ROUND_UP(255, 8) + +// Synthesized IR when a DR scan arrives without a cached IR. +#define CKLINK_PLACEHOLDER_IR_BITS 5 +#define CKLINK_PLACEHOLDER_IR_VALUE 0x01 + +struct cklink_ctx { + struct libusb_device_handle *usb_dev; + uint8_t tx_buf[CKLINK_USB_BUF_SIZE]; + uint8_t rx_buf[CKLINK_USB_BUF_SIZE]; + uint8_t csr_clk; + uint8_t ir_value[CKLINK_MAX_SCAN_BYTES]; + unsigned int ir_bits; + struct jtag_command *pending_ir_cmd; + uint8_t *scan_tdi; + uint8_t *scan_tdo; + size_t scan_buf_size; + bool long_scan_warned; + bool dropped_ir_warned; +}; + +static struct cklink_ctx *cklink_handle; + +// Built-in VID/PID list, used when `adapter usb vid_pid` is not set. +static const uint16_t cklink_default_vids[] = { + CKLINK_VID_BOUFFALO, + CKLINK_VID_THEAD, + 0, +}; +static const uint16_t cklink_default_pids[] = { + CKLINK_PID_LITE_V2, + CKLINK_PID_LITE_V2, + 0, +}; + +// Sum-mod-256. +static uint8_t cklink_checksum(const uint8_t *buf, unsigned int len) +{ + uint8_t sum = 0; + for (unsigned int i = 0; i < len; i++) + sum += buf[i]; + return sum; +} + +/* Send a framed command; NULL rxlen means fire-and-forget (selfreg writes + * are not acknowledged). @p opcode selects the response-checksum rule. */ +static int cklink_usb_xfer(struct cklink_ctx *ck, uint8_t opcode, + unsigned int txlen, unsigned int *rxlen) +{ + int actual = 0; + int ret = jtag_libusb_bulk_write(ck->usb_dev, CKLINK_EP_OUT, + (char *)ck->tx_buf, txlen, + CKLINK_USB_TIMEOUT_MS, &actual); + if (ret != ERROR_OK || (unsigned int)actual != txlen) { + LOG_ERROR("CK-Link bulk write failed (ret=%d, actual=%d/%d)", + ret, actual, txlen); + return ERROR_FAIL; + } + + if (!rxlen) + return ERROR_OK; + + ret = jtag_libusb_bulk_read(ck->usb_dev, CKLINK_EP_IN, + (char *)ck->rx_buf, CKLINK_USB_BUF_SIZE, + CKLINK_USB_TIMEOUT_MS, &actual); + if (ret != ERROR_OK || actual < (int)CKLINK_FRAME_OVERHEAD) { + LOG_ERROR("CK-Link bulk read failed (ret=%d, actual=%d)", + ret, actual); + return ERROR_FAIL; + } + if (ck->rx_buf[0] != CKLINK_FRAME_START) { + LOG_ERROR("CK-Link bad response start byte 0x%02x", + ck->rx_buf[0]); + return ERROR_FAIL; + } + if (ck->rx_buf[actual - 1] != CKLINK_FRAME_END) { + LOG_ERROR("CK-Link bad response end byte 0x%02x", + ck->rx_buf[actual - 1]); + return ERROR_FAIL; + } + /* + * RX checksum is opcode-specific: selfreg reads sum all payload; + * single-entry JTAG batch sums all except the last byte of dr_tdo. + */ + unsigned int csum_end = actual - ((opcode == CKLINK_OP_JTAG_BATCH) ? 3 : 2); + uint8_t computed = cklink_checksum(ck->rx_buf, csum_end); + if (computed != ck->rx_buf[actual - 2]) { + LOG_ERROR("CK-Link response checksum mismatch: op=0x%02x stated=0x%02x computed=0x%02x", + opcode, ck->rx_buf[actual - 2], computed); + return ERROR_FAIL; + } + // Status byte semantics undocumented; log non-zero for traces. + if (ck->rx_buf[1] != 0) { + LOG_DEBUG("CK-Link op=0x%02x returned status=0x%02x", + opcode, ck->rx_buf[1]); + } + *rxlen = (unsigned int)actual; + return ERROR_OK; +} + +static unsigned int cklink_frame_start(struct cklink_ctx *ck, uint8_t opcode) +{ + ck->tx_buf[0] = CKLINK_FRAME_START; + ck->tx_buf[1] = opcode; + return 2; +} + +static unsigned int cklink_frame_end(struct cklink_ctx *ck, unsigned int pos) +{ + assert(pos + 2 <= CKLINK_USB_BUF_SIZE); + ck->tx_buf[pos] = cklink_checksum(ck->tx_buf, pos); + ck->tx_buf[pos + 1] = CKLINK_FRAME_END; + return pos + 2; +} + +static int cklink_selfreg_write(struct cklink_ctx *ck, uint8_t reg, + const uint8_t *value) +{ + unsigned int pos = cklink_frame_start(ck, CKLINK_OP_SELFREG_WRITE); + ck->tx_buf[pos++] = reg; + memcpy(&ck->tx_buf[pos], value, CKLINK_SELFREG_BYTES); + pos += CKLINK_SELFREG_BYTES; + pos = cklink_frame_end(ck, pos); + return cklink_usb_xfer(ck, CKLINK_OP_SELFREG_WRITE, pos, NULL); +} + +static int cklink_selfreg_read(struct cklink_ctx *ck, uint8_t reg, uint8_t *value) +{ + unsigned int pos = cklink_frame_start(ck, CKLINK_OP_SELFREG_READ); + ck->tx_buf[pos++] = reg; + pos = cklink_frame_end(ck, pos); + + unsigned int rxlen = 0; + int ret = cklink_usb_xfer(ck, CKLINK_OP_SELFREG_READ, pos, &rxlen); + if (ret != ERROR_OK) + return ret; + + const unsigned int expected = CKLINK_FRAME_OVERHEAD + CKLINK_SELFREG_BYTES; + if (rxlen < expected) { + LOG_ERROR("CK-Link selfreg read response too short (%u < %u)", + rxlen, expected); + return ERROR_FAIL; + } + memcpy(value, &ck->rx_buf[CKLINK_RESP_PAYLOAD_OFFSET], + CKLINK_SELFREG_BYTES); + return ERROR_OK; +} + +/* Single-entry batch scan. Scans > 255 bits are clamped with a one-time + * warning: chunking across entries breaks Shift-DR continuity, and + * erroring out here breaks OpenOCD's chain probe's -expected-id recovery. */ +static int cklink_jtag_scan(struct cklink_ctx *ck, + unsigned int ir_bits, const uint8_t *ir_tdi, + uint8_t *ir_tdo, + unsigned int dr_bits, const uint8_t *dr_tdi, + uint8_t *dr_tdo) +{ + if ((ir_bits > CKLINK_MAX_SCAN_BITS || dr_bits > CKLINK_MAX_SCAN_BITS) + && !ck->long_scan_warned) { + LOG_WARNING("CK-Link: scan exceeds %u-bit per-entry limit (ir=%u dr=%u); clamping", + CKLINK_MAX_SCAN_BITS, ir_bits, dr_bits); + ck->long_scan_warned = true; + } + if (ir_bits > CKLINK_MAX_SCAN_BITS) + ir_bits = CKLINK_MAX_SCAN_BITS; + if (dr_bits > CKLINK_MAX_SCAN_BITS) + dr_bits = CKLINK_MAX_SCAN_BITS; + + const unsigned int ir_bytes = DIV_ROUND_UP(ir_bits, 8); + const unsigned int dr_bytes = DIV_ROUND_UP(dr_bits, 8); + + unsigned int pos = cklink_frame_start(ck, CKLINK_OP_JTAG_BATCH); + ck->tx_buf[pos++] = 0; // entry_count - 1 + ck->tx_buf[pos++] = (uint8_t)ir_bits; + if (ir_tdi) + memcpy(&ck->tx_buf[pos], ir_tdi, ir_bytes); + else + memset(&ck->tx_buf[pos], 0, ir_bytes); + pos += ir_bytes; + ck->tx_buf[pos++] = (uint8_t)dr_bits; + if (dr_tdi) + memcpy(&ck->tx_buf[pos], dr_tdi, dr_bytes); + else + memset(&ck->tx_buf[pos], 0, dr_bytes); + pos += dr_bytes; + pos = cklink_frame_end(ck, pos); + + unsigned int rxlen = 0; + int ret = cklink_usb_xfer(ck, CKLINK_OP_JTAG_BATCH, pos, &rxlen); + if (ret != ERROR_OK) + return ret; + + // Response: start + status + ir_tdo + dr_echo + dr_tdo + csum + end. + const unsigned int expected = + CKLINK_FRAME_OVERHEAD + ir_bytes + 1 + dr_bytes; + if (rxlen < expected) { + LOG_ERROR("CK-Link scan response truncated: got %u, need %u (ir=%u dr=%u)", + rxlen, expected, ir_bits, dr_bits); + return ERROR_FAIL; + } + + if (ir_tdo && ir_bytes) + memcpy(ir_tdo, &ck->rx_buf[CKLINK_RESP_PAYLOAD_OFFSET], ir_bytes); + + const unsigned int dr_tdo_offset = + CKLINK_RESP_PAYLOAD_OFFSET + ir_bytes + 1; + if (dr_tdo) + memcpy(dr_tdo, &ck->rx_buf[dr_tdo_offset], dr_bytes); + + return ERROR_OK; +} + +// Shift num_bits of idle cycles, chunked to the 255-bit protocol limit. +static int cklink_idle_cycles(struct cklink_ctx *ck, unsigned int num_bits) +{ + static const uint8_t zeros[CKLINK_MAX_SCAN_BYTES] = { 0 }; + + while (num_bits > 0) { + unsigned int chunk = num_bits > CKLINK_MAX_SCAN_BITS + ? CKLINK_MAX_SCAN_BITS : num_bits; + int ret = cklink_jtag_scan(ck, 0, NULL, NULL, + chunk, zeros, NULL); + if (ret != ERROR_OK) + return ret; + num_bits -= chunk; + } + return ERROR_OK; +} + +/* Flush a pending IR with a 1-bit dummy DR so its in_value gets populated + * with real captured IR TDO. Called at end of execute_queue so Capture-IR + * validation sees real hardware data. */ +static int cklink_flush_pending_ir(struct cklink_ctx *ck) +{ + if (!ck || !ck->pending_ir_cmd) + return ERROR_OK; + + uint8_t ir_tdo[CKLINK_MAX_SCAN_BYTES] = { 0 }; + uint8_t dummy_dr = 0; + int ret = cklink_jtag_scan(ck, ck->ir_bits, ck->ir_value, ir_tdo, + 1, &dummy_dr, NULL); + if (ret != ERROR_OK) + return ret; + + struct scan_command *scan = ck->pending_ir_cmd->cmd.scan; + unsigned int off = 0; + for (unsigned int i = 0; i < scan->num_fields; i++) { + struct scan_field *f = &scan->fields[i]; + if (f->in_value) { + buf_set_buf(ir_tdo, off, f->in_value, 0, + f->num_bits); + } + off += f->num_bits; + } + ck->pending_ir_cmd = NULL; + // ir_bits/ir_value stay valid: hardware IR is still what we cached. + return ERROR_OK; +} + +static int cklink_execute_scan(struct cklink_ctx *ck, struct jtag_command *cmd) +{ + struct scan_command *scan = cmd->cmd.scan; + + unsigned int total_bits = 0; + for (unsigned int i = 0; i < scan->num_fields; i++) + total_bits += scan->fields[i].num_bits; + + if (total_bits == 0) + return ERROR_OK; + + const unsigned int total_bytes = DIV_ROUND_UP(total_bits, 8); + if (total_bytes > ck->scan_buf_size) { + uint8_t *ntdi = realloc(ck->scan_tdi, total_bytes); + uint8_t *ntdo = realloc(ck->scan_tdo, total_bytes); + if (!ntdi || !ntdo) { + LOG_ERROR("CK-Link: out of memory for %u-bit scan", + total_bits); + // Partial success is fine; freed in cklink_quit. + if (ntdi) + ck->scan_tdi = ntdi; + if (ntdo) + ck->scan_tdo = ntdo; + return ERROR_FAIL; + } + ck->scan_tdi = ntdi; + ck->scan_tdo = ntdo; + ck->scan_buf_size = total_bytes; + } + memset(ck->scan_tdi, 0, total_bytes); + memset(ck->scan_tdo, 0, total_bytes); + + unsigned int bit_offset = 0; + for (unsigned int i = 0; i < scan->num_fields; i++) { + struct scan_field *field = &scan->fields[i]; + if (field->out_value) { + buf_set_buf(field->out_value, 0, ck->scan_tdi, + bit_offset, field->num_bits); + } + bit_offset += field->num_bits; + } + + if (scan->ir_scan) { + /* + * Defer IR until paired with a DR (batch needs both). + * Back-to-back IR drops the first: mid-queue flush would + * cycle Capture-DR/Update-DR on the previous IR's register + * (e.g. DMI), triggering spurious transactions. + */ + if (total_bytes > sizeof(ck->ir_value)) { + LOG_ERROR("CK-Link: IR scan of %u bits exceeds cache (%zu bytes)", + total_bits, sizeof(ck->ir_value)); + return ERROR_JTAG_QUEUE_FAILED; + } + if (ck->pending_ir_cmd) { + if (!ck->dropped_ir_warned) { + LOG_WARNING("CK-Link: back-to-back IR scan dropped pending IR; multi-TAP chains are not supported"); + ck->dropped_ir_warned = true; + } else { + LOG_DEBUG("CK-Link: dropping pending IR (%u bits) before new IR scan", + ck->ir_bits); + } + } + memcpy(ck->ir_value, ck->scan_tdi, total_bytes); + ck->ir_bits = total_bits; + ck->pending_ir_cmd = cmd; + return ERROR_OK; + } + + // No cached IR yet: inject IDCODE placeholder so chain detection works. + const uint8_t placeholder_ir = CKLINK_PLACEHOLDER_IR_VALUE; + const unsigned int eff_ir_bits = ck->ir_bits ? ck->ir_bits + : CKLINK_PLACEHOLDER_IR_BITS; + const uint8_t *eff_ir_value = ck->ir_bits ? ck->ir_value : &placeholder_ir; + if (!ck->ir_bits) + LOG_DEBUG("CK-Link: DR scan with no cached IR; injecting IDCODE placeholder"); + + uint8_t ir_tdo_buf[CKLINK_MAX_SCAN_BYTES] = { 0 }; + int ret = cklink_jtag_scan(ck, eff_ir_bits, eff_ir_value, ir_tdo_buf, + total_bits, ck->scan_tdi, ck->scan_tdo); + if (ret != ERROR_OK) + return ret; + + // Scatter captured IR TDO back into the deferred IR command's fields. + if (ck->pending_ir_cmd) { + struct scan_command *ir_scan = ck->pending_ir_cmd->cmd.scan; + unsigned int ir_off = 0; + for (unsigned int i = 0; i < ir_scan->num_fields; i++) { + struct scan_field *f = &ir_scan->fields[i]; + if (f->in_value) { + buf_set_buf(ir_tdo_buf, ir_off, + f->in_value, 0, f->num_bits); + } + ir_off += f->num_bits; + } + ck->pending_ir_cmd = NULL; + } + + /* + * For clamped scans, fill un-shifted TDO with caller's TDI (models + * "no more TAPs past the limit" - a bare wire). Gives OpenOCD's + * bypass chain-length probe the expected end-of-chain marker. + */ + if (total_bits > CKLINK_MAX_SCAN_BITS) { + buf_set_buf(ck->scan_tdi, CKLINK_MAX_SCAN_BITS, + ck->scan_tdo, CKLINK_MAX_SCAN_BITS, + total_bits - CKLINK_MAX_SCAN_BITS); + } + + bit_offset = 0; + for (unsigned int i = 0; i < scan->num_fields; i++) { + struct scan_field *field = &scan->fields[i]; + if (field->in_value) { + buf_set_buf(ck->scan_tdo, bit_offset, + field->in_value, 0, field->num_bits); + } + bit_offset += field->num_bits; + } + + return ERROR_OK; +} + +static int cklink_write_csr(struct cklink_ctx *ck, uint8_t clk, uint8_t mode) +{ + uint8_t buf[CKLINK_SELFREG_BYTES]; + h_u32_to_le(buf, CKLINK_CSR(clk, mode)); + return cklink_selfreg_write(ck, CKLINK_SR_CSR, buf); +} + +// khz -> sr0 byte 0 divider, rounded up so we never exceed the request. +static uint8_t cklink_khz_to_div(int khz) +{ + if (khz <= 0) + return CKLINK_CLK_DIV_MAX; + int n = ((CKLINK_CLK_SOURCE_KHZ + khz - 1) / khz) - 1; + if (n < CKLINK_CLK_DIV_MIN) + n = CKLINK_CLK_DIV_MIN; + if (n > CKLINK_CLK_DIV_MAX) + n = CKLINK_CLK_DIV_MAX; + return (uint8_t)n; +} + +static int cklink_execute_tlr_reset(struct cklink_ctx *ck) +{ + // Probe-side reset via 5->2->5 mode toggle; target TAP reset not guaranteed. + int ret; + + ret = cklink_write_csr(ck, ck->csr_clk, CKLINK_SR0_MODE_CJTAG); + if (ret != ERROR_OK) + return ret; + ret = cklink_write_csr(ck, ck->csr_clk, CKLINK_SR0_MODE_CJTAG); + if (ret != ERROR_OK) + return ret; + ret = cklink_write_csr(ck, ck->csr_clk, CKLINK_SR0_MODE_JTAG); + if (ret != ERROR_OK) + return ret; + + ck->ir_bits = 0; + memset(ck->ir_value, 0, sizeof(ck->ir_value)); + ck->pending_ir_cmd = NULL; + tap_set_state(TAP_RESET); + return ERROR_OK; +} + +static int cklink_execute_runtest(struct cklink_ctx *ck, struct jtag_command *cmd) +{ + return cklink_idle_cycles(ck, cmd->cmd.runtest->num_cycles); +} + +static int cklink_execute_stableclocks(struct cklink_ctx *ck, struct jtag_command *cmd) +{ + // TMS=0 shifts only hold state in RTI; other stable states would advance. + return cklink_idle_cycles(ck, cmd->cmd.stableclocks->num_cycles); +} + +static int cklink_execute_tms(struct jtag_command *cmd) +{ + // No TMS-sequence opcode: honoring JTAG_TMS is impossible. + LOG_ERROR("CK-Link: JTAG_TMS (%u bits) is not supported by this probe", + cmd->cmd.tms->num_bits); + return ERROR_JTAG_NOT_IMPLEMENTED; +} + +static int cklink_execute_reset(struct cklink_ctx *ck, struct jtag_command *cmd) +{ + // Only TRST is meaningful here: we have no separate SRST control. + if (cmd->cmd.reset->trst) + return cklink_execute_tlr_reset(ck); + return ERROR_OK; +} + +static int cklink_execute_queue(struct jtag_command *cmd_queue) +{ + struct cklink_ctx *ck = cklink_handle; + if (!ck) + return ERROR_JTAG_INIT_FAILED; + + for (struct jtag_command *cmd = cmd_queue; cmd; cmd = cmd->next) { + int ret; + + switch (cmd->type) { + case JTAG_SCAN: + ret = cklink_execute_scan(ck, cmd); + break; + case JTAG_TLR_RESET: + ret = cklink_execute_tlr_reset(ck); + break; + case JTAG_RUNTEST: + ret = cklink_execute_runtest(ck, cmd); + break; + case JTAG_RESET: + ret = cklink_execute_reset(ck, cmd); + break; + case JTAG_PATHMOVE: + // No TMS-sequence opcode: honoring PATHMOVE is impossible. + LOG_ERROR("CK-Link: JTAG_PATHMOVE is not supported by this probe"); + ret = ERROR_JTAG_NOT_IMPLEMENTED; + break; + case JTAG_STABLECLOCKS: + ret = cklink_execute_stableclocks(ck, cmd); + break; + case JTAG_TMS: + ret = cklink_execute_tms(cmd); + break; + case JTAG_SLEEP: + jtag_sleep(cmd->cmd.sleep->us); + ret = ERROR_OK; + break; + default: + LOG_ERROR("CK-Link: unsupported JTAG command %d", + cmd->type); + return ERROR_JTAG_QUEUE_FAILED; + } + if (ret != ERROR_OK) + return ret; + } + // Flush so any un-paired IR's in_value is populated before OpenOCD reads. + return cklink_flush_pending_ir(ck); +} + +static int cklink_probe_init(struct cklink_ctx *ck) +{ + uint8_t sr1[CKLINK_SELFREG_BYTES]; + uint8_t sr8[CKLINK_SELFREG_BYTES]; + uint8_t readback[CKLINK_SELFREG_BYTES]; + int ret; + + h_u32_to_le(sr1, CKLINK_SR1_INIT_VALUE); + h_u32_to_le(sr8, CKLINK_SR8_INIT_VALUE); + + // Configure at slow clock for cold-boot signal-integrity margin. + ret = cklink_write_csr(ck, CKLINK_SR0_SETUP_CLK_BYTE, + CKLINK_SR0_MODE_JTAG); + if (ret != ERROR_OK) + return ret; + ret = cklink_selfreg_write(ck, CKLINK_SR_MTCR_WAIT, sr1); + if (ret != ERROR_OK) + return ret; + ret = cklink_selfreg_write(ck, CKLINK_SR_JTAG_CONFIG, sr8); + if (ret != ERROR_OK) + return ret; + ret = cklink_write_csr(ck, CKLINK_SR0_RUN_CLK_BYTE, + CKLINK_SR0_MODE_JTAG); + if (ret != ERROR_OK) + return ret; + + ret = cklink_selfreg_read(ck, CKLINK_SR_CSR, readback); + if (ret != ERROR_OK) + return ret; + if (readback[3] != CKLINK_SR0_MODE_JTAG) { + LOG_WARNING("CK-Link: sr0 mode byte is 0x%02x, expected 0x%02x (5-wire JTAG)", + readback[3], CKLINK_SR0_MODE_JTAG); + } + ck->csr_clk = CKLINK_SR0_RUN_CLK_BYTE; + + // Pre-load IR = IDCODE; 1-bit DR is the minimum the batch opcode accepts. + const uint8_t idcode_ir = CKLINK_PLACEHOLDER_IR_VALUE; + const uint8_t dummy_dr = 0; + return cklink_jtag_scan(ck, CKLINK_PLACEHOLDER_IR_BITS, &idcode_ir, NULL, + 1, &dummy_dr, NULL); +} + +static int cklink_init(void) +{ + struct cklink_ctx *ck = calloc(1, sizeof(*ck)); + if (!ck) { + LOG_ERROR("CK-Link: out of memory"); + return ERROR_JTAG_INIT_FAILED; + } + + const uint16_t *vids = adapter_usb_get_vids(); + const uint16_t *pids = adapter_usb_get_pids(); + if (!vids[0] || !pids[0]) { + vids = cklink_default_vids; + pids = cklink_default_pids; + } + + const char *serial = adapter_get_required_serial(); + if (jtag_libusb_open(vids, pids, serial, + &ck->usb_dev, NULL) != ERROR_OK) { + LOG_ERROR("CK-Link probe not found"); + free(ck); + return ERROR_JTAG_INIT_FAILED; + } + + libusb_set_auto_detach_kernel_driver(ck->usb_dev, 1); + + int claim = libusb_claim_interface(ck->usb_dev, CKLINK_USB_INTERFACE); + if (claim != 0) { + LOG_ERROR("CK-Link: failed to claim interface %d: %s", + CKLINK_USB_INTERFACE, libusb_error_name(claim)); + jtag_libusb_close(ck->usb_dev); + free(ck); + return ERROR_JTAG_INIT_FAILED; + } + + if (cklink_probe_init(ck) != ERROR_OK) { + LOG_ERROR("CK-Link: probe initialization failed"); + libusb_release_interface(ck->usb_dev, CKLINK_USB_INTERFACE); + jtag_libusb_close(ck->usb_dev); + free(ck); + return ERROR_JTAG_INIT_FAILED; + } + + cklink_handle = ck; + tap_set_state(TAP_RESET); + LOG_INFO("CK-Link Lite V2 initialized (5-wire JTAG)"); + return ERROR_OK; +} + +static int cklink_quit(void) +{ + if (!cklink_handle) + return ERROR_OK; + + libusb_release_interface(cklink_handle->usb_dev, + CKLINK_USB_INTERFACE); + jtag_libusb_close(cklink_handle->usb_dev); + free(cklink_handle->scan_tdi); + free(cklink_handle->scan_tdo); + free(cklink_handle); + cklink_handle = NULL; + return ERROR_OK; +} + +static int cklink_speed(int speed) +{ + struct cklink_ctx *ck = cklink_handle; + if (!ck) + return ERROR_OK; // called before init + + uint8_t div = cklink_khz_to_div(speed); + if (div == ck->csr_clk) + return ERROR_OK; + int ret = cklink_write_csr(ck, div, CKLINK_SR0_MODE_JTAG); + if (ret != ERROR_OK) + return ret; + ck->csr_clk = div; + int actual = CKLINK_CLK_SOURCE_KHZ / (div + 1); + LOG_DEBUG("CK-Link: adapter speed: requested %d kHz, programmed %d kHz (div=0x%02x)", + speed, actual, div); + return ERROR_OK; +} + +static int cklink_khz(int khz, int *jtag_speed) +{ + if (khz == 0) { + LOG_ERROR("CK-Link: adaptive clocking (RTCK) is not supported"); + return ERROR_JTAG_NOT_IMPLEMENTED; + } + uint8_t div = cklink_khz_to_div(khz); + int achievable = CKLINK_CLK_SOURCE_KHZ / (div + 1); + if (achievable != khz) { + static int last_clamp_khz; + if (khz != last_clamp_khz) { + LOG_WARNING("CK-Link: requested %d kHz clamped to %d kHz (div=0x%02x)", + khz, achievable, div); + last_clamp_khz = khz; + } + } + *jtag_speed = achievable; + return ERROR_OK; +} + +static int cklink_speed_div(int speed, int *khz) +{ + *khz = speed; + return ERROR_OK; +} + +static struct jtag_interface cklink_jtag_interface = { + .execute_queue = cklink_execute_queue, +}; + +struct adapter_driver cklink_adapter_driver = { + .name = "cklink", + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, + + .init = cklink_init, + .quit = cklink_quit, + .speed = cklink_speed, + .khz = cklink_khz, + .speed_div = cklink_speed_div, + + .jtag_ops = &cklink_jtag_interface, +}; diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index 2bfcfcc2b0..759a6738d6 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -37,7 +37,8 @@ #include #include "cmsis_dap.h" -#include "libusb_helper.h" + +#define TIMEOUT_MS 6000 /* Create a dummy backend for 'backend' command if real one does not build */ #if BUILD_CMSIS_DAP_USB == 0 @@ -52,9 +53,16 @@ const struct cmsis_dap_backend cmsis_dap_hid_backend = { }; #endif +#if BUILD_CMSIS_DAP_TCP == 0 +const struct cmsis_dap_backend cmsis_dap_tcp_backend = { + .name = "tcp" +}; +#endif + static const struct cmsis_dap_backend *const cmsis_dap_backends[] = { &cmsis_dap_usb_backend, &cmsis_dap_hid_backend, + &cmsis_dap_tcp_backend, }; /* USB Config */ @@ -70,12 +78,9 @@ static const struct cmsis_dap_backend *const cmsis_dap_backends[] = { * 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; +static bool cmsis_dap_quirk_mode; /* enable expensive workarounds */ /* CMSIS-DAP General Commands */ #define CMD_DAP_INFO 0x00 @@ -274,7 +279,8 @@ static int cmsis_dap_open(void) /* Use forced backend */ backend = cmsis_dap_backends[cmsis_dap_backend]; if (backend->open) - retval = backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, adapter_get_required_serial()); + retval = backend->open(dap, adapter_usb_get_vids(), + adapter_usb_get_pids(), adapter_get_required_serial()); else LOG_ERROR("Requested CMSIS-DAP backend is disabled by configure"); @@ -285,7 +291,7 @@ static int cmsis_dap_open(void) if (!backend->open) continue; - retval = backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, adapter_get_required_serial()); + retval = backend->open(dap, adapter_usb_get_vids(), adapter_usb_get_pids(), adapter_get_required_serial()); if (retval == ERROR_OK) break; } @@ -355,12 +361,12 @@ static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen) } uint8_t current_cmd = dap->command[0]; - int retval = dap->backend->write(dap, txlen, LIBUSB_TIMEOUT_MS); + int retval = dap->backend->write(dap, txlen, TIMEOUT_MS); if (retval < 0) return retval; /* get reply */ - retval = dap->backend->read(dap, LIBUSB_TIMEOUT_MS, CMSIS_DAP_BLOCKING); + retval = dap->backend->read(dap, TIMEOUT_MS, CMSIS_DAP_BLOCKING); if (retval < 0) return retval; @@ -864,13 +870,13 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) } } - int retval = dap->backend->write(dap, idx, LIBUSB_TIMEOUT_MS); + int retval = dap->backend->write(dap, idx, TIMEOUT_MS); if (retval < 0) { queued_retval = retval; goto skip; } - unsigned int packet_count = dap->quirk_mode ? 1 : dap->packet_count; + unsigned int packet_count = cmsis_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) @@ -905,7 +911,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, enum cmsis_dap_blo } /* get reply */ - retval = dap->backend->read(dap, LIBUSB_TIMEOUT_MS, blocking); + retval = dap->backend->read(dap, TIMEOUT_MS, blocking); bool timeout = (retval == ERROR_TIMEOUT_REACHED || retval == 0); if (timeout && blocking == CMSIS_DAP_NON_BLOCKING) return; @@ -990,7 +996,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, enum cmsis_dap_blo skip: block->transfer_count = 0; - if (!dap->quirk_mode && dap->packet_count > 1) + if (!cmsis_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--; } @@ -1086,7 +1092,7 @@ static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) /* 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; + unsigned int packet_count = cmsis_dap_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); } @@ -1230,7 +1236,7 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq) if (swd_mode) queued_retval = cmsis_dap_swd_run_queue(); - if (cmsis_dap_handle->quirk_mode && seq != LINE_RESET && + if (cmsis_dap_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. @@ -1558,38 +1564,38 @@ static void debug_parse_cmsis_buf(const uint8_t *cmd, int cmdlen) 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; + 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"); } - default: - LOG_DEBUG("unknown cmsis-dap command %02x", cmd[1]); - break; + 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 @@ -1930,32 +1936,32 @@ static void cmsis_dap_execute_tms(struct jtag_command *cmd) 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); + 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); } } @@ -2175,36 +2181,6 @@ COMMAND_HANDLER(cmsis_dap_handle_cmd_command) 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 int 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) @@ -2238,11 +2214,13 @@ 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); + if (CMD_ARGC == 1) { + COMMAND_PARSE_ENABLE(CMD_ARGV[0], cmsis_dap_quirk_mode); + return ERROR_OK; + } + + command_print(CMD, "%s", cmsis_dap_quirk_mode ? "enabled" : "disabled"); - command_print(CMD, "CMSIS-DAP quirk workarounds %s", - cmsis_dap_handle->quirk_mode ? "enabled" : "disabled"); return ERROR_OK; } @@ -2261,19 +2239,12 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = { .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)", + .help = "set the communication backend to use (USB bulk or HID, or TCP).", + .usage = "(auto | usb_bulk | hid | tcp)", }, { .name = "quirk", @@ -2290,6 +2261,15 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = { .help = "USB bulk backend-specific commands", .usage = "", }, +#endif +#if BUILD_CMSIS_DAP_TCP + { + .name = "tcp", + .chain = cmsis_dap_tcp_subcommand_handlers, + .mode = COMMAND_ANY, + .help = "TCP backend-specific commands", + .usage = "", + }, #endif COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/cmsis_dap.h b/src/jtag/drivers/cmsis_dap.h index aded0e54a3..4272ab4831 100644 --- a/src/jtag/drivers/cmsis_dap.h +++ b/src/jtag/drivers/cmsis_dap.h @@ -52,7 +52,6 @@ struct cmsis_dap { unsigned int pending_fifo_block_count; uint16_t caps; - bool quirk_mode; /* enable expensive workarounds */ uint32_t swo_buf_sz; bool trace_enabled; @@ -66,7 +65,7 @@ enum cmsis_dap_blocking { struct cmsis_dap_backend { const char *name; - int (*open)(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial); + int (*open)(struct cmsis_dap *dap, const uint16_t vids[], const uint16_t pids[], const char *serial); void (*close)(struct cmsis_dap *dap); int (*read)(struct cmsis_dap *dap, int transfer_timeout_ms, enum cmsis_dap_blocking blocking); @@ -78,7 +77,9 @@ struct cmsis_dap_backend { extern const struct cmsis_dap_backend cmsis_dap_hid_backend; extern const struct cmsis_dap_backend cmsis_dap_usb_backend; +extern const struct cmsis_dap_backend cmsis_dap_tcp_backend; extern const struct command_registration cmsis_dap_usb_subcommand_handlers[]; +extern const struct command_registration cmsis_dap_tcp_subcommand_handlers[]; #define REPORT_ID_SIZE 1 diff --git a/src/jtag/drivers/cmsis_dap_tcp.c b/src/jtag/drivers/cmsis_dap_tcp.c new file mode 100644 index 0000000000..38fa0e8e33 --- /dev/null +++ b/src/jtag/drivers/cmsis_dap_tcp.c @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Provides CMSIS-DAP protocol over a TCP/IP socket. * + * UART and SWO are currently unsupported. * + * * + * Copyright (C) 2025 by Brian Kuschak * + * * + * Adapted from cmsis_dap_usb_hid.c. Copyright (C) 2013-2018 by: * + * Mickaël Thomas * + * Maksym Hilliaka * + * Phillip Pearson * + * Paul Fertser * + * mike brown * + * Spencer Oliver * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif +#include +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef _WIN32 +#include +#include +#endif + +#include "helper/command.h" +#include "helper/log.h" +#include "helper/replacements.h" +#include "helper/system.h" +#include "cmsis_dap.h" + +#define STRINGIFY(x) #x + +// If the protocol changes in the future, the SIGNATURE should also be changed. +#define DAP_PKT_HDR_SIGNATURE 0x00504144 // "DAP" +#define DAP_PKT_TYPE_REQUEST 0x01 +#define DAP_PKT_TYPE_RESPONSE 0x02 + +#define CMSIS_DAP_TCP_PORT 4441 // Default. Can be overridden. +#define CMSIS_DAP_PACKET_SIZE 1024 // Max payload size not including + // header. + +/* When flushing after an error, the CMSIS-DAP driver assumes the pipeline is + * empty if it doesn't get a response after a short 10 msec timeout. While this + * works for USB, it may not work for TCP/IP due to higher network latency. TCP + * response packets may take longer to arrive. We set a lower bound on timeout + * for blocking reads, to give enough time for packets to arrive. + * + * The user may override this default value by setting the parameter + * 'cmsis-dap tcp min_timeout' + */ +#define DEFAULT_MIN_TIMEOUT_MS 150 + +/* CMSIS-DAP requests are variable length. With CMSIS-DAP over USB, the + * transfer sizes are preserved by the USB stack. However, TCP/IP is stream + * oriented so we perform our own packetization to preserve the boundaries + * between each request. This short header is prepended to each CMSIS-DAP + * request and response before being sent over the socket. Little endian format + * is used for multibyte values. + */ +struct __attribute__((packed)) cmsis_dap_tcp_packet_hdr { + uint32_t signature; // "DAP" + uint16_t length; // Not including header length. + uint8_t packet_type; + uint8_t reserved; // Reserved for future use. +}; + +/* Defines for struct cmsis_dap_tcp_packet_hdr requested by reviewer. */ +#define HEADER_SIGNATURE_OFFSET 0 +#define HEADER_LENGTH_OFFSET sizeof(uint32_t) +#define HEADER_PACKET_TYPE_OFFSET (sizeof(uint32_t) + sizeof(uint16_t)) +#define HEADER_RESERVED_OFFSET (sizeof(uint32_t) + sizeof(uint16_t) + \ + sizeof(uint8_t)) +#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint16_t) + \ + 2 * sizeof(uint8_t)) + +struct cmsis_dap_backend_data { + int sockfd; +}; + +static char *cmsis_dap_tcp_host; +static char cmsis_dap_tcp_port_default[] = STRINGIFY(CMSIS_DAP_TCP_PORT); +static char *cmsis_dap_tcp_port = cmsis_dap_tcp_port_default; +static int cmsis_dap_tcp_min_timeout_ms = DEFAULT_MIN_TIMEOUT_MS; + +static void cmsis_dap_tcp_close(struct cmsis_dap *dap); +static int cmsis_dap_tcp_alloc(struct cmsis_dap *dap, unsigned int pkt_sz); +static void cmsis_dap_tcp_free(struct cmsis_dap *dap); + +static int cmsis_dap_tcp_open(struct cmsis_dap *dap, + const uint16_t vids[] __attribute__((unused)), + const uint16_t pids[] __attribute__((unused)), + const char *serial __attribute__((unused))) +{ + // Skip the open if the user has not provided a hostname. + if (!cmsis_dap_tcp_host) { + LOG_ERROR("The hostname or IP address of the CMSIS-DAP adapter must be specified"); + return ERROR_FAIL; + } + + // Ignore vids, pids, serial. We use host and port subcommands instead. + + dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data)); + if (!dap->bdata) { + LOG_ERROR("CMSIS-DAP: unable to allocate memory"); + return ERROR_FAIL; + } + + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM + }; + struct addrinfo *result, *rp; + int fd = 0; + + LOG_INFO("CMSIS-DAP: Connecting to %s:%s using TCP backend", + cmsis_dap_tcp_host, cmsis_dap_tcp_port); + + /* Some of the following code was taken from remote_bitbang.c */ + /* Obtain address(es) matching host/port */ + int s = getaddrinfo(cmsis_dap_tcp_host, cmsis_dap_tcp_port, &hints, + &result); + if (s != 0) { + LOG_ERROR("CMSIS-DAP: getaddrinfo: %s\n", gai_strerror(s)); + free(dap->bdata); + return ERROR_FAIL; + } + + /* getaddrinfo() returns a list of address structures. + Try each address until we successfully connect(2). + If socket(2) (or connect(2)) fails, we (close the socket + and) try the next address. */ + + for (rp = result; rp ; rp = rp->ai_next) { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (fd == -1) + continue; + + if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) { + LOG_DEBUG("Connected."); + break; /* Success */ + } + + close(fd); + } + + freeaddrinfo(result); + + if (!rp) { /* No address succeeded */ + LOG_ERROR("CMSIS-DAP: unable to connect to device %s:%s", + cmsis_dap_tcp_host, cmsis_dap_tcp_port); + log_socket_error("Failed to connect"); + free(dap->bdata); + dap->bdata = NULL; + return ERROR_FAIL; + } + + /* Set NODELAY to minimize latency. */ + int one = 1; + /* On Windows optval has to be a const char *. */ + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one)); + + dap->bdata->sockfd = fd; + + int retval = cmsis_dap_tcp_alloc(dap, CMSIS_DAP_PACKET_SIZE); + if (retval != ERROR_OK) { + cmsis_dap_tcp_close(dap); + return retval; + } + return ERROR_OK; +} + +static void cmsis_dap_tcp_close(struct cmsis_dap *dap) +{ + if (close_socket(dap->bdata->sockfd) != 0) + log_socket_error("close_socket"); + + if (dap->bdata) + free(dap->bdata); + dap->bdata = NULL; + cmsis_dap_tcp_free(dap); +} + +static int socket_bytes_available(int sock, unsigned int *out_avail) +{ +#ifdef _WIN32 + u_long avail = 0; + if (ioctlsocket((SOCKET)sock, FIONREAD, &avail) == SOCKET_ERROR) + return -1; +#else + int avail = 0; + if (ioctl(sock, FIONREAD, &avail) < 0) + return -1; +#endif + *out_avail = avail; + return 0; +} + +static inline int readall_socket(int handle, void *buffer, unsigned int count) +{ + // Return after all count bytes available, or timeout, or error. + return recv(handle, buffer, count, MSG_WAITALL); +} + +static int peekall_socket(int handle, void *buffer, unsigned int count, + enum cmsis_dap_blocking blocking, unsigned int timeout_ms) +{ + /* Windows doesn't support MSG_PEEK in combination with MSG_WAITALL: + * return recv(handle, buffer, count, MSG_PEEK | MSG_WAITALL); + * + * So, use this method instead which should work for Windows and others. + * + * Data remains unread on the socket until recv() is called later without + * the MSG_PEEK flag. Return after all count bytes available, or timeout, + * or error. + */ + + if (count == 0) + return 0; + + while (true) { + int ret; + unsigned int avail; + if (socket_bytes_available(handle, &avail) < 0) + return -1; + + if (avail >= count) { + ret = recv(handle, (char *)buffer, (int)count, MSG_PEEK); + if (ret < 0) { +#ifdef _WIN32 + int err = WSAGetLastError(); + if (err == WSAEINTR) + continue; + if (err == WSAEWOULDBLOCK) + return -1; +#else + if (errno == EINTR) + continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) + return -1; // Timeout or nonblocking. +#endif + } + return ret; // 0: Closed, <0: Other error, >0 Success. + } + + // Not enough data available. + if (blocking == CMSIS_DAP_NON_BLOCKING) { +#ifdef _WIN32 + WSASetLastError(WSAEWOULDBLOCK); +#else + errno = EAGAIN; +#endif + return -1; + } + + // Blocking wait. + fd_set rfds; + FD_ZERO(&rfds); + OCD_FD_SET(handle, &rfds); + + struct timeval tv; + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; + + ret = select(handle + 1, &rfds, NULL, NULL, &tv); + if (ret > 0) + continue; // Readable + + if (ret == 0) { // Timeout +#ifdef _WIN32 + WSASetLastError(WSAEWOULDBLOCK); +#else + errno = EAGAIN; +#endif + return -1; + } + + // Error +#ifndef _WIN32 + if (errno == EINTR) + continue; +#endif + return ret; + } +} + +static int cmsis_dap_tcp_read(struct cmsis_dap *dap, int transfer_timeout_ms, + enum cmsis_dap_blocking blocking) +{ + int wait_ms = (blocking == CMSIS_DAP_NON_BLOCKING) ? 0 : + transfer_timeout_ms; + if (wait_ms) { + LOG_DEBUG_IO("CMSIS-DAP: using tcp timeout %d msec", wait_ms); + + // Don't use very short timeouts with TCP/IP as it may not be as fast + // to respond as USB. User configurable minimum value. + if (wait_ms < cmsis_dap_tcp_min_timeout_ms) { + wait_ms = cmsis_dap_tcp_min_timeout_ms; + LOG_DEBUG_IO("CMSIS-DAP: extending timeout to %d msec", wait_ms); + } + } + socket_recv_timeout(dap->bdata->sockfd, wait_ms); + + if (blocking == CMSIS_DAP_NON_BLOCKING) + socket_nonblock(dap->bdata->sockfd); + else + socket_block(dap->bdata->sockfd); + + // Peek at the header first to find the length. + int retval = peekall_socket(dap->bdata->sockfd, dap->packet_buffer, + HEADER_SIZE, blocking, wait_ms); + LOG_DEBUG_IO("Reading header returned %d", retval); + if (retval == 0) { + LOG_DEBUG_IO("CMSIS-DAP: tcp timeout reached 1"); + return ERROR_TIMEOUT_REACHED; + } else if (retval == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + if (blocking == CMSIS_DAP_NON_BLOCKING) + return ERROR_TIMEOUT_REACHED; + + LOG_DEBUG_IO("CMSIS-DAP: tcp timeout reached 2. timeout = %d msec", + wait_ms); + return ERROR_TIMEOUT_REACHED; + } + + LOG_ERROR("CMSIS-DAP: error reading header"); + log_socket_error("peek_socket"); + return ERROR_FAIL; + } else if (retval != HEADER_SIZE) { + LOG_ERROR("CMSIS-DAP: short header read"); + log_socket_error("peek_socket header short read"); + return ERROR_FAIL; + } + + struct cmsis_dap_tcp_packet_hdr header; + header.signature = le_to_h_u32(dap->packet_buffer + + HEADER_SIGNATURE_OFFSET); + header.length = le_to_h_u16(dap->packet_buffer + HEADER_LENGTH_OFFSET); + header.packet_type = dap->packet_buffer[HEADER_PACKET_TYPE_OFFSET]; + header.reserved = dap->packet_buffer[HEADER_RESERVED_OFFSET]; + + if (header.signature != DAP_PKT_HDR_SIGNATURE) { + LOG_ERROR("CMSIS-DAP: Unrecognized packet signature 0x%08x", + header.signature); + return ERROR_FAIL; + } else if (header.packet_type != DAP_PKT_TYPE_RESPONSE) { + LOG_ERROR("CMSIS-DAP: Unrecognized packet type 0x%02x", + header.packet_type); + return ERROR_FAIL; + } else if (header.length + HEADER_SIZE > dap->packet_buffer_size) { + LOG_ERROR("CMSIS-DAP: Packet length %d too large to fit.", + header.length); + return ERROR_FAIL; + } + + // Read the complete packet. + int read_len = HEADER_SIZE + header.length; + LOG_DEBUG_IO("Reading %d bytes (%d payload)...", read_len, header.length); + retval = readall_socket(dap->bdata->sockfd, dap->packet_buffer, read_len); + + if (retval == 0) { + LOG_DEBUG_IO("CMSIS-DAP: tcp timeout reached 3"); + return ERROR_TIMEOUT_REACHED; + } else if (retval == -1) { + LOG_ERROR("CMSIS-DAP: error reading data"); + log_socket_error("read_socket"); + return ERROR_FAIL; + } else if (retval != read_len) { + LOG_ERROR("CMSIS-DAP: short read. retval = %d. read_len = %d. " + "blocking = %s. wait_ms = %d", retval, read_len, + (blocking == CMSIS_DAP_NON_BLOCKING) ? "yes" : "no", wait_ms); + log_socket_error("read_socket short read"); + return ERROR_FAIL; + } + return retval; +} + +static int cmsis_dap_tcp_write(struct cmsis_dap *dap, int txlen, + int timeout_ms __attribute__((unused))) +{ + const unsigned int len = txlen + HEADER_SIZE; + if (len > dap->packet_buffer_size) { + LOG_ERROR("CMSIS-DAP: Packet length %d exceeds TCP buffer size!", len); + return ERROR_FAIL; + } + + /* Set the header values. */ + h_u32_to_le(dap->packet_buffer + HEADER_SIGNATURE_OFFSET, + DAP_PKT_HDR_SIGNATURE); + h_u16_to_le(dap->packet_buffer + HEADER_LENGTH_OFFSET, txlen); + dap->packet_buffer[HEADER_PACKET_TYPE_OFFSET] = DAP_PKT_TYPE_REQUEST; + dap->packet_buffer[HEADER_RESERVED_OFFSET] = 0; + + /* write data to device */ + LOG_DEBUG_IO("Writing %d bytes (%d payload)", len, txlen); + int retval = write_socket(dap->bdata->sockfd, dap->packet_buffer, len); + if (retval < 0) { + log_socket_error("write_socket"); + return ERROR_FAIL; + } else if (retval != (int)len) { + LOG_ERROR("CMSIS-DAP: error writing data"); + log_socket_error("write_socket short write"); + return ERROR_FAIL; + } + return retval; +} + +static int cmsis_dap_tcp_alloc(struct cmsis_dap *dap, unsigned int pkt_sz) +{ + // Reserve space for the packet header. + unsigned int packet_buffer_size = pkt_sz + HEADER_SIZE; + uint8_t *buf = malloc(packet_buffer_size); + if (!buf) { + LOG_ERROR("CMSIS-DAP: 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 + HEADER_SIZE; + dap->response = dap->packet_buffer + HEADER_SIZE; + return ERROR_OK; +} + +static void cmsis_dap_tcp_free(struct cmsis_dap *dap) +{ + free(dap->packet_buffer); + dap->packet_buffer = NULL; +} + +static void cmsis_dap_tcp_cancel_all(struct cmsis_dap *dap) +{ +} + +COMMAND_HANDLER(cmsis_dap_handle_tcp_port) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (cmsis_dap_tcp_port != cmsis_dap_tcp_port_default) + free(cmsis_dap_tcp_port); + + cmsis_dap_tcp_port = strdup(CMD_ARGV[0]); + if (!cmsis_dap_tcp_port) { + LOG_ERROR("CMSIS-DAP: out of memory"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +COMMAND_HANDLER(cmsis_dap_handle_tcp_host) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(cmsis_dap_tcp_host); + cmsis_dap_tcp_host = strdup(CMD_ARGV[0]); + if (!cmsis_dap_tcp_host) { + LOG_ERROR("CMSIS-DAP: out of memory"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +COMMAND_HANDLER(cmsis_dap_handle_tcp_min_timeout) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cmsis_dap_tcp_min_timeout_ms); + LOG_INFO("CMSIS-DAP: using minimum timeout of %d ms for TCP packets.", + cmsis_dap_tcp_min_timeout_ms); + return ERROR_OK; +} + +const struct command_registration cmsis_dap_tcp_subcommand_handlers[] = { + { + .name = "host", + .handler = &cmsis_dap_handle_tcp_host, + .mode = COMMAND_CONFIG, + .help = "set the host name to use (for TCP backend only)", + .usage = "", + }, + { + .name = "port", + .handler = &cmsis_dap_handle_tcp_port, + .mode = COMMAND_CONFIG, + .help = "set the port number to use for DAP (for TCP backend only)", + .usage = "", + }, + { + .name = "min_timeout", + .handler = &cmsis_dap_handle_tcp_min_timeout, + .mode = COMMAND_CONFIG, + .help = "set the minimum timeout in milliseconds to wait for response " + "packets (for TCP backend only)", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct cmsis_dap_backend cmsis_dap_tcp_backend = { + .name = "tcp", + .open = cmsis_dap_tcp_open, + .close = cmsis_dap_tcp_close, + .read = cmsis_dap_tcp_read, + .write = cmsis_dap_tcp_write, + .packet_buffer_alloc = cmsis_dap_tcp_alloc, + .packet_buffer_free = cmsis_dap_tcp_free, + .cancel_all = cmsis_dap_tcp_cancel_all, +}; diff --git a/src/jtag/drivers/cmsis_dap_usb_bulk.c b/src/jtag/drivers/cmsis_dap_usb_bulk.c index 8fbcb029dd..ac684f49b5 100644 --- a/src/jtag/drivers/cmsis_dap_usb_bulk.c +++ b/src/jtag/drivers/cmsis_dap_usb_bulk.c @@ -63,7 +63,7 @@ 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) +static int cmsis_dap_usb_open(struct cmsis_dap *dap, const uint16_t vids[], const uint16_t pids[], const char *serial) { int err; struct libusb_context *ctx; @@ -414,7 +414,19 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p static void cmsis_dap_usb_close(struct cmsis_dap *dap) { for (unsigned int i = 0; i < MAX_PENDING_REQUESTS; i++) { - libusb_free_transfer(dap->bdata->command_transfers[i].transfer); + if (dap->bdata->command_transfers[i].status == CMSIS_DAP_TRANSFER_PENDING) { + LOG_DEBUG("busy command USB transfer at %u", dap->pending_fifo_put_idx); + struct timeval tv = { + .tv_sec = 1, + .tv_usec = 1000 + }; + /* Complete pending commands */ + int res = libusb_handle_events_timeout_completed(dap->bdata->usb_ctx, &tv, NULL); + if (res == 0) + libusb_free_transfer(dap->bdata->command_transfers[i].transfer); + } else { + libusb_free_transfer(dap->bdata->command_transfers[i].transfer); + } libusb_free_transfer(dap->bdata->response_transfers[i].transfer); } cmsis_dap_usb_free(dap); @@ -647,10 +659,10 @@ static void cmsis_dap_usb_cancel_all(struct cmsis_dap *dap) 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 "); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cmsis_dap_usb_interface); return ERROR_OK; } @@ -661,7 +673,7 @@ const struct command_registration cmsis_dap_usb_subcommand_handlers[] = { .handler = &cmsis_dap_handle_usb_interface_command, .mode = COMMAND_CONFIG, .help = "set the USB interface number to use (for USB bulk backend only)", - .usage = "", + .usage = "", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/cmsis_dap_usb_hid.c b/src/jtag/drivers/cmsis_dap_usb_hid.c index a4058ec803..8d4de68857 100644 --- a/src/jtag/drivers/cmsis_dap_usb_hid.c +++ b/src/jtag/drivers/cmsis_dap_usb_hid.c @@ -68,7 +68,7 @@ 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) +static int cmsis_dap_hid_open(struct cmsis_dap *dap, const uint16_t vids[], const uint16_t pids[], const char *serial) { hid_device *dev = NULL; int i; diff --git a/src/jtag/drivers/dmem.c b/src/jtag/drivers/dmem.c index e50e84aeeb..85f3345526 100644 --- a/src/jtag/drivers/dmem.c +++ b/src/jtag/drivers/dmem.c @@ -93,66 +93,62 @@ static bool dmem_is_emulated_ap(struct adiv5_ap *ap, unsigned int *idx) return false; } -static void dmem_emu_set_ap_reg(uint64_t addr, uint32_t val) +static void dmem_emu_set_ap_reg(uint32_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) +static uint32_t dmem_emu_get_ap_reg(uint32_t addr) { - uint32_t val; - addr &= ~ARM_APB_PADDR31; - val = *(volatile uint32_t *)((uintptr_t)dmem_emu_virt_base_addr + addr); - - return val; + return *(volatile uint32_t *)((uintptr_t)dmem_emu_virt_base_addr + addr); } static int dmem_emu_ap_q_read(unsigned int ap_idx, unsigned int reg, uint32_t *data) { - uint64_t addr; + uint32_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; + 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. */ @@ -164,51 +160,51 @@ static int dmem_emu_ap_q_read(unsigned int ap_idx, unsigned int reg, uint32_t *d static int dmem_emu_ap_q_write(unsigned int ap_idx, unsigned int reg, uint32_t data) { - uint64_t addr; + uint32_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; + 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. */ @@ -242,13 +238,13 @@ static int dmem_dp_q_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *dat return ERROR_OK; switch (reg) { - case DP_CTRL_STAT: - *data = CDBGPWRUPACK | CSYSPWRUPACK; - break; + case DP_CTRL_STAT: + *data = CDBGPWRUPACK | CSYSPWRUPACK; + break; - default: - *data = 0; - break; + default: + *data = 0; + break; } return ERROR_OK; @@ -519,7 +515,7 @@ static int dmem_dap_init(void) MAP_SHARED, dmem_fd, dmem_mapped_start); if (dmem_map_base == MAP_FAILED) { - LOG_ERROR("Mapping address 0x%lx for 0x%lx bytes failed!", + LOG_ERROR("Mapping address 0x%zx for 0x%zx bytes failed!", dmem_mapped_start, dmem_mapped_size); goto error_fail; } @@ -543,7 +539,7 @@ static int dmem_dap_init(void) 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!", + LOG_ERROR("Mapping EMU address 0x%" PRIx64 " for 0x%" PRIx64 " bytes failed!", dmem_emu_base_address, dmem_emu_size); goto error_fail; } diff --git a/src/jtag/drivers/esp_usb_jtag.c b/src/jtag/drivers/esp_usb_jtag.c index a133035110..20794e9ef8 100644 --- a/src/jtag/drivers/esp_usb_jtag.c +++ b/src/jtag/drivers/esp_usb_jtag.c @@ -218,8 +218,6 @@ struct esp_usb_jtag { 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; @@ -476,9 +474,6 @@ 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; @@ -487,7 +482,8 @@ static int esp_usb_jtag_init(void) 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); + int r = jtag_libusb_open(adapter_usb_get_vids(), adapter_usb_get_pids(), + NULL, &priv->usb_device, NULL); if (r != ERROR_OK) { LOG_ERROR("esp_usb_jtag: could not find or open device!"); goto out; @@ -693,18 +689,6 @@ COMMAND_HANDLER(esp_usb_jtag_setio_cmd) 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) @@ -742,13 +726,6 @@ static const struct command_registration esp_usb_jtag_subcommands[] = { .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, diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index f88e4b9408..e668909a5f 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -58,8 +58,10 @@ #define FT232R_BUF_SIZE_EXTRA 4096 -static uint16_t ft232r_vid = 0x0403; /* FTDI */ -static uint16_t ft232r_pid = 0x6001; /* FT232R */ +// Default VID/PID pair for FTDI FT232R. +static uint16_t ft232r_vids[] = {0x0403, 0}; +static uint16_t ft232r_pids[] = {0x6001, 0}; + static struct libusb_device_handle *adapter; static uint8_t *ft232r_output; @@ -244,12 +246,24 @@ static int ft232r_speed(int divisor) static int ft232r_init(void) { - uint16_t avids[] = {ft232r_vid, 0}; - uint16_t apids[] = {ft232r_pid, 0}; - if (jtag_libusb_open(avids, apids, NULL, &adapter, NULL)) { + const uint16_t *vids = ft232r_vids; + const uint16_t *pids = ft232r_pids; + + if (adapter_usb_get_vids()[0] != 0) { + vids = adapter_usb_get_vids(); + pids = adapter_usb_get_pids(); + } + + if (jtag_libusb_open(vids, pids, NULL, &adapter, NULL)) { + char usb_vid_pid_str[256] = {0}; + for (unsigned int i = 0; vids[i] != 0; i++) + snprintf(usb_vid_pid_str + strlen(usb_vid_pid_str), + sizeof(usb_vid_pid_str) - strlen(usb_vid_pid_str), + "%04x:%04x ", vids[i], pids[i]); + const char *ft232r_serial_desc = adapter_get_required_serial(); - LOG_ERROR("ft232r not found: vid=%04x, pid=%04x, serial=%s\n", - ft232r_vid, ft232r_pid, (!ft232r_serial_desc) ? "[any]" : ft232r_serial_desc); + LOG_ERROR("ft232r not found: serial=%s, vid/pid=%s\n", + (!ft232r_serial_desc) ? "[any]" : ft232r_serial_desc, usb_vid_pid_str); return ERROR_JTAG_INIT_FAILED; } @@ -385,22 +399,6 @@ static int ft232r_bit_name_to_number(const char *name) return -1; } -COMMAND_HANDLER(ft232r_handle_vid_pid_command) -{ - if (CMD_ARGC > 2) { - LOG_WARNING("ignoring extra IDs in ft232r_vid_pid " - "(maximum is 1 pair)"); - CMD_ARGC = 2; - } - if (CMD_ARGC == 2) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], ft232r_vid); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], ft232r_pid); - } else - LOG_WARNING("incomplete ft232r_vid_pid configuration"); - - return ERROR_OK; -} - COMMAND_HANDLER(ft232r_handle_jtag_nums_command) { if (CMD_ARGC == 4) { @@ -541,13 +539,6 @@ COMMAND_HANDLER(ft232r_handle_restore_serial_command) } static const struct command_registration ft232r_subcommand_handlers[] = { - { - .name = "vid_pid", - .handler = ft232r_handle_vid_pid_command, - .mode = COMMAND_CONFIG, - .help = "USB VID and PID of the adapter", - .usage = "vid pid", - }, { .name = "jtag_nums", .handler = ft232r_handle_jtag_nums_command, @@ -818,71 +809,71 @@ static int syncbb_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); - if ((cmd->cmd.reset->trst == 1) || + if (cmd->cmd.reset->trst == 1 || (cmd->cmd.reset->srst && - (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) { - tap_set_state(TAP_RESET); - } - ft232r_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %u cycles, end in %s", cmd->cmd.runtest->num_cycles, - tap_state_name(cmd->cmd.runtest->end_state)); - - syncbb_end_state(cmd->cmd.runtest->end_state); - syncbb_runtest(cmd->cmd.runtest->num_cycles); - break; - - case JTAG_STABLECLOCKS: - /* this is only allowed while in a stable state. A check for a stable - * state was done in jtag_add_clocks() - */ - syncbb_stableclocks(cmd->cmd.stableclocks->num_cycles); - break; - - case JTAG_TLR_RESET: /* renamed from JTAG_STATEMOVE */ - LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); - - syncbb_end_state(cmd->cmd.statemove->end_state); - syncbb_state_move(0); - break; - - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %u states, end in %s", cmd->cmd.pathmove->num_states, - tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); - - syncbb_path_move(cmd->cmd.pathmove); - break; - - case JTAG_SCAN: - LOG_DEBUG_IO("%s scan end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", - tap_state_name(cmd->cmd.scan->end_state)); - - syncbb_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - type = jtag_scan_type(cmd->cmd.scan); - syncbb_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); - if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - free(buffer); - break; - - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - - jtag_sleep(cmd->cmd.sleep->us); - break; - - case JTAG_TMS: - retval = syncbb_execute_tms(cmd); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) + tap_set_state(TAP_RESET); + + ft232r_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %u cycles, end in %s", cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + + syncbb_end_state(cmd->cmd.runtest->end_state); + syncbb_runtest(cmd->cmd.runtest->num_cycles); + break; + + case JTAG_STABLECLOCKS: + /* this is only allowed while in a stable state. A check for a stable + * state was done in jtag_add_clocks() + */ + syncbb_stableclocks(cmd->cmd.stableclocks->num_cycles); + break; + + case JTAG_TLR_RESET: /* renamed from JTAG_STATEMOVE */ + LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); + + syncbb_end_state(cmd->cmd.statemove->end_state); + syncbb_state_move(0); + break; + + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %u states, end in %s", cmd->cmd.pathmove->num_states, + tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); + + syncbb_path_move(cmd->cmd.pathmove); + break; + + case JTAG_SCAN: + LOG_DEBUG_IO("%s scan end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", + tap_state_name(cmd->cmd.scan->end_state)); + + syncbb_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + syncbb_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + free(buffer); + break; + + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + + jtag_sleep(cmd->cmd.sleep->us); + break; + + case JTAG_TMS: + retval = syncbb_execute_tms(cmd); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } if (ft232r_output_len > 0) ft232r_send_recv(); diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 2c3339e658..159aa9ecac 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -89,7 +89,6 @@ #define JTAG_MODE_ALT (LSB_FIRST | NEG_EDGE_IN | NEG_EDGE_OUT) #define SWD_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT) -static char *ftdi_device_desc; static uint8_t ftdi_channel; static uint8_t ftdi_jtag_mode = JTAG_MODE; @@ -113,12 +112,12 @@ static void cjtag_reset_online_activate(void); to the two-wire clocking and signaling of OScan1 protocol, if placed into OScan1 mode during initialization. */ -static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, - unsigned in_offset, unsigned length, uint8_t mode); -static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, - unsigned in_offset, unsigned length, bool tdi, uint8_t mode); -static void oscan1_mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, - unsigned length, bool tdi, uint8_t mode); +static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned int out_offset, uint8_t *in, + unsigned int in_offset, unsigned int length, uint8_t mode); +static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned int out_offset, uint8_t *in, + unsigned int in_offset, unsigned int length, bool tdi, uint8_t mode); +static void oscan1_mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned int out_offset, + unsigned int length, bool tdi, uint8_t mode); static bool oscan1_mode; @@ -128,11 +127,6 @@ static bool oscan1_mode; static bool jscan3_mode; #endif -#define MAX_USB_IDS 8 -/* vid = pid = 0 marks the end of the list */ -static uint16_t ftdi_vid[MAX_USB_IDS + 1] = { 0 }; -static uint16_t ftdi_pid[MAX_USB_IDS + 1] = { 0 }; - static struct mpsse_ctx *mpsse_ctx; struct signal { @@ -274,8 +268,8 @@ static int ftdi_get_signal(const struct signal *s, uint16_t *value_out) } #if BUILD_FTDI_CJTAG == 1 -static void clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, - unsigned in_offset, unsigned length, uint8_t mode) +static void clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned int out_offset, uint8_t *in, + unsigned int in_offset, unsigned int length, uint8_t mode) { if (oscan1_mode) oscan1_mpsse_clock_data(ctx, out, out_offset, in, in_offset, length, mode); @@ -283,8 +277,8 @@ static void clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_o mpsse_clock_data(ctx, out, out_offset, in, in_offset, length, mode); } -static void clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, - unsigned in_offset, unsigned length, bool tdi, uint8_t mode) +static void clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned int out_offset, uint8_t *in, + unsigned int in_offset, unsigned int length, bool tdi, uint8_t mode) { if (oscan1_mode) oscan1_mpsse_clock_tms_cs(ctx, out, out_offset, in, in_offset, length, tdi, mode); @@ -292,8 +286,8 @@ static void clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out mpsse_clock_tms_cs(ctx, out, out_offset, in, in_offset, length, tdi, mode); } -static void clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, - unsigned length, bool tdi, uint8_t mode) +static void clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned int out_offset, + unsigned int length, bool tdi, uint8_t mode) { if (oscan1_mode) oscan1_mpsse_clock_tms_cs_out(ctx, out, out_offset, length, tdi, mode); @@ -543,6 +537,10 @@ 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); + + /* 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; DO_CLOCK_TMS_CS(mpsse_ctx, &tms_bits, @@ -666,38 +664,38 @@ static void ftdi_execute_command(struct jtag_command *cmd) { switch (cmd->type) { #if BUILD_FTDI_CJTAG == 1 - case JTAG_RESET: - if (cmd->cmd.reset->trst) - cjtag_reset_online_activate(); /* put the target (back) into selected cJTAG mode */ - break; + case JTAG_RESET: + if (cmd->cmd.reset->trst) + cjtag_reset_online_activate(); /* put the target (back) into selected cJTAG mode */ + break; #endif - case JTAG_RUNTEST: - ftdi_execute_runtest(cmd); - break; - case JTAG_TLR_RESET: + case JTAG_RUNTEST: + ftdi_execute_runtest(cmd); + break; + case JTAG_TLR_RESET: #if BUILD_FTDI_CJTAG == 1 - cjtag_reset_online_activate(); /* put the target (back) into selected cJTAG mode */ + cjtag_reset_online_activate(); /* put the target (back) into selected cJTAG mode */ #endif - ftdi_execute_statemove(cmd); - break; - case JTAG_PATHMOVE: - ftdi_execute_pathmove(cmd); - break; - case JTAG_SCAN: - ftdi_execute_scan(cmd); - break; - case JTAG_SLEEP: - ftdi_execute_sleep(cmd); - break; - case JTAG_STABLECLOCKS: - ftdi_execute_stableclocks(cmd); - break; - case JTAG_TMS: - ftdi_execute_tms(cmd); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered: %d", cmd->type); - break; + ftdi_execute_statemove(cmd); + break; + case JTAG_PATHMOVE: + ftdi_execute_pathmove(cmd); + break; + case JTAG_SCAN: + ftdi_execute_scan(cmd); + break; + case JTAG_SLEEP: + ftdi_execute_sleep(cmd); + break; + case JTAG_STABLECLOCKS: + ftdi_execute_stableclocks(cmd); + break; + case JTAG_TMS: + ftdi_execute_tms(cmd); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered: %d", cmd->type); + break; } } @@ -730,13 +728,14 @@ static int ftdi_initialize(void) else LOG_DEBUG("ftdi interface using shortest path jtag state transitions"); - if (!ftdi_vid[0] && !ftdi_pid[0]) { - LOG_ERROR("Please specify ftdi vid_pid"); + if (!adapter_usb_get_vids()[0] && !adapter_usb_get_pids()[0]) { + LOG_ERROR("Please specify 'adapter usb vid_pid'"); return ERROR_JTAG_INIT_FAILED; } - mpsse_ctx = mpsse_open(ftdi_vid, ftdi_pid, ftdi_device_desc, - adapter_get_required_serial(), adapter_usb_get_location(), ftdi_channel); + mpsse_ctx = mpsse_open(adapter_usb_get_vids(), adapter_usb_get_pids(), + adapter_usb_get_product_name(), adapter_get_required_serial(), + adapter_usb_get_location(), ftdi_channel); if (!mpsse_ctx) return ERROR_JTAG_INIT_FAILED; @@ -760,9 +759,9 @@ static int ftdi_initialize(void) return ERROR_JTAG_INIT_FAILED; } /* A dummy JTAG_SEL would have zero mask */ - if (sig->data_mask) + if (sig->data_mask) { ftdi_set_signal(sig, '0'); - else if (jscan3_mode) { + } else if (jscan3_mode) { LOG_ERROR("In JScan3 mode JTAG_SEL signal cannot be dummy, data mask needed"); return ERROR_JTAG_INIT_FAILED; } @@ -791,25 +790,23 @@ static int ftdi_quit(void) sig = next; } - free(ftdi_device_desc); - free(swd_cmd_queue); return ERROR_OK; } #if BUILD_FTDI_CJTAG == 1 -static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, - unsigned in_offset, unsigned length, uint8_t mode) +static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned int out_offset, uint8_t *in, + unsigned int in_offset, unsigned int length, uint8_t mode) { static const uint8_t zero; static const uint8_t one = 1; struct signal *tmsc_en = find_signal_by_name("TMSC_EN"); - LOG_DEBUG_IO("oscan1_mpsse_clock_data: %sout %d bits", in ? "in" : "", length); + LOG_DEBUG_IO("%sout %d bits", in ? "in" : "", length); - for (unsigned i = 0; i < length; i++) { + for (unsigned int i = 0; i < length; i++) { int bitnum; uint8_t bit; @@ -817,7 +814,7 @@ static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, u /* drive TMSC to the *negation* of the desired TDI value */ bitnum = out_offset + i; - bit = out ? ((out[bitnum/8] >> (bitnum%8)) & 0x1) : 0; + bit = out ? ((out[bitnum / 8] >> (bitnum % 8)) & 0x1) : 0; /* Try optimized case first: if desired TDI bit is 1, then we can fuse what would otherwise be the first two MPSSE commands */ @@ -836,25 +833,24 @@ static void oscan1_mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, u ftdi_set_signal(tmsc_en, '0'); /* put TMSC in high impedance */ /* drive another TCK without driving TMSC (TDO cycle) */ - mpsse_clock_tms_cs(mpsse_ctx, &zero, 0, in, in_offset+i, 1, false, mode); + mpsse_clock_tms_cs(mpsse_ctx, &zero, 0, in, in_offset + i, 1, false, mode); if (tmsc_en) ftdi_set_signal(tmsc_en, '1'); /* drive again TMSC */ } } - -static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, - unsigned in_offset, unsigned length, bool tdi, uint8_t mode) +static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned int out_offset, uint8_t *in, + unsigned int in_offset, unsigned int length, bool tdi, uint8_t mode) { static const uint8_t zero; static const uint8_t one = 1; struct signal *tmsc_en = find_signal_by_name("TMSC_EN"); - LOG_DEBUG_IO("oscan1_mpsse_clock_tms_cs: %sout %d bits, tdi=%d", in ? "in" : "", length, tdi); + LOG_DEBUG_IO("%sout %d bits, tdi=%d", in ? "in" : "", length, tdi); - for (unsigned i = 0; i < length; i++) { + for (unsigned int i = 0; i < length; i++) { int bitnum; uint8_t tmsbit; uint8_t tdibit; @@ -866,7 +862,7 @@ static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, /* drive TMSC to desired TMS value */ bitnum = out_offset + i; - tmsbit = ((out[bitnum/8] >> (bitnum%8)) & 0x1); + tmsbit = ((out[bitnum / 8] >> (bitnum % 8)) & 0x1); if (tdibit == tmsbit) { /* Can squash into a single MPSSE command */ @@ -882,21 +878,19 @@ static void oscan1_mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, ftdi_set_signal(tmsc_en, '0'); /* put TMSC in high impedance */ /* drive another TCK without driving TMSC (TDO cycle) */ - mpsse_clock_tms_cs(mpsse_ctx, &zero, 0, in, in_offset+i, 1, false, mode); + mpsse_clock_tms_cs(mpsse_ctx, &zero, 0, in, in_offset + i, 1, false, mode); if (tmsc_en) ftdi_set_signal(tmsc_en, '1'); /* drive again TMSC */ } } - -static void oscan1_mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, - unsigned length, bool tdi, uint8_t mode) +static void oscan1_mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned int out_offset, + unsigned int length, bool tdi, uint8_t mode) { oscan1_mpsse_clock_tms_cs(ctx, out, out_offset, 0, 0, length, tdi, mode); } - static void cjtag_set_tck_tms_tdi(struct signal *tck, char tckvalue, struct signal *tms, char tmsvalue, struct signal *tdi, char tdivalue) { @@ -1062,7 +1056,7 @@ static void cjtag_reset_online_activate(void) if (jscan3_mode) { /* Update the sequence above to enable JScan3 instead of OScan1 */ sequence[ESCAPE_SEQ_OAC_BIT2].tdi = '0'; - sequence[ESCAPE_SEQ_OAC_BIT2+1].tdi = '0'; + sequence[ESCAPE_SEQ_OAC_BIT2 + 1].tdi = '0'; } /* if defined TMSC_EN, replace tms with it */ @@ -1070,7 +1064,7 @@ static void cjtag_reset_online_activate(void) tms = tmsc_en; /* Send the sequence to the adapter */ - for (size_t i = 0; i < sizeof(sequence)/sizeof(sequence[0]); i++) + for (size_t i = 0; i < ARRAY_SIZE(sequence); i++) cjtag_set_tck_tms_tdi(tck, sequence[i].tck, tms, sequence[i].tms, tdi, sequence[i].tdi); /* If JScan3 mode, configure cJTAG adapter to 4-wire */ @@ -1079,21 +1073,8 @@ static void cjtag_reset_online_activate(void) ftdi_get_signal(tdo, &tdovalue); /* Just to force a flush */ } - #endif /* #if BUILD_FTDI_CJTAG == 1 */ -COMMAND_HANDLER(ftdi_handle_device_desc_command) -{ - if (CMD_ARGC == 1) { - free(ftdi_device_desc); - ftdi_device_desc = strdup(CMD_ARGV[0]); - } else { - LOG_ERROR("expected exactly one argument to ftdi device_desc "); - } - - return ERROR_OK; -} - COMMAND_HANDLER(ftdi_handle_channel_command) { if (CMD_ARGC == 1) @@ -1240,36 +1221,6 @@ COMMAND_HANDLER(ftdi_handle_get_signal_command) return ERROR_OK; } -COMMAND_HANDLER(ftdi_handle_vid_pid_command) -{ - if (CMD_ARGC > MAX_USB_IDS * 2) { - 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"); - if (CMD_ARGC < 2) - return ERROR_COMMAND_SYNTAX_ERROR; - /* remove the incomplete trailing id */ - CMD_ARGC -= 1; - } - - unsigned int i; - for (i = 0; i < CMD_ARGC; i += 2) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], ftdi_vid[i >> 1]); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], ftdi_pid[i >> 1]); - } - - /* - * Explicitly terminate, in case there are multiples instances of - * ftdi vid_pid. - */ - ftdi_vid[i >> 1] = ftdi_pid[i >> 1] = 0; - - return ERROR_OK; -} - COMMAND_HANDLER(ftdi_handle_tdo_sample_edge_command) { const struct nvp *n; @@ -1320,13 +1271,6 @@ COMMAND_HANDLER(ftdi_handle_jscan3_mode_command) #endif static const struct command_registration ftdi_subcommand_handlers[] = { - { - .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 = "channel", .handler = &ftdi_handle_channel_command, @@ -1364,13 +1308,6 @@ static const struct command_registration ftdi_subcommand_handlers[] = { .help = "read the value of a layout-specific signal", .usage = "name", }, - { - .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)*", - }, { .name = "tdo_sample_edge", .handler = &ftdi_handle_tdo_sample_edge_command, diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c index 805065f1f4..f6ae684f77 100644 --- a/src/jtag/drivers/gw16012.c +++ b/src/jtag/drivers/gw16012.c @@ -284,46 +284,46 @@ static int gw16012_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); - if (cmd->cmd.reset->trst == 1) - tap_set_state(TAP_RESET); - gw16012_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); - gw16012_end_state(cmd->cmd.runtest->end_state); - gw16012_runtest(cmd->cmd.runtest->num_cycles); - break; - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - gw16012_end_state(cmd->cmd.statemove->end_state); - gw16012_state_move(); - break; - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - gw16012_path_move(cmd->cmd.pathmove); - break; - case JTAG_SCAN: - gw16012_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - type = jtag_scan_type(cmd->cmd.scan); - LOG_DEBUG_IO("%s scan (%i) %i bit end in %i", (cmd->cmd.scan->ir_scan) ? "ir" : "dr", - type, scan_size, cmd->cmd.scan->end_state); - gw16012_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); - if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - free(buffer); - break; - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - jtag_sleep(cmd->cmd.sleep->us); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); + if (cmd->cmd.reset->trst == 1) + tap_set_state(TAP_RESET); + gw16012_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + gw16012_end_state(cmd->cmd.runtest->end_state); + gw16012_runtest(cmd->cmd.runtest->num_cycles); + break; + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + gw16012_end_state(cmd->cmd.statemove->end_state); + gw16012_state_move(); + break; + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + gw16012_path_move(cmd->cmd.pathmove); + break; + case JTAG_SCAN: + gw16012_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + LOG_DEBUG_IO("%s scan (%i) %i bit end in %i", (cmd->cmd.scan->ir_scan) ? "ir" : "dr", + type, scan_size, cmd->cmd.scan->end_state); + gw16012_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + free(buffer); + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + jtag_sleep(cmd->cmd.sleep->us); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } @@ -461,6 +461,8 @@ static int gw16012_init(void) { uint8_t status_port; + LOG_WARNING("This adapter is deprecated and support will be removed in the next release!"); + if (gw16012_init_device() != ERROR_OK) return ERROR_JTAG_INIT_FAILED; diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 9caf37f6f0..1901e8df14 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -40,8 +41,6 @@ static struct jaylink_connection connlist[JAYLINK_MAX_CONNECTIONS]; static enum jaylink_jtag_version jtag_command_version; static uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE]; -static uint32_t serial_number; -static bool use_serial_number; static bool use_usb_location; static enum jaylink_usb_address usb_address; static bool use_usb_address; @@ -242,7 +241,7 @@ static void jlink_execute_scan(struct jtag_command *cmd) static void jlink_execute_sleep(struct jtag_command *cmd) { - LOG_DEBUG_IO("sleep %" PRIu32 "", cmd->cmd.sleep->us); + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); jlink_flush(); jtag_sleep(cmd->cmd.sleep->us); } @@ -250,27 +249,27 @@ static void jlink_execute_sleep(struct jtag_command *cmd) static int jlink_execute_command(struct jtag_command *cmd) { switch (cmd->type) { - case JTAG_STABLECLOCKS: - jlink_execute_stableclocks(cmd); - break; - case JTAG_RUNTEST: - jlink_execute_runtest(cmd); - break; - case JTAG_TLR_RESET: - jlink_execute_statemove(cmd); - break; - case JTAG_PATHMOVE: - jlink_execute_pathmove(cmd); - break; - case JTAG_SCAN: - jlink_execute_scan(cmd); - break; - case JTAG_SLEEP: - jlink_execute_sleep(cmd); - break; - default: - LOG_ERROR("BUG: Unknown JTAG command type encountered"); - return ERROR_JTAG_QUEUE_FAILED; + case JTAG_STABLECLOCKS: + jlink_execute_stableclocks(cmd); + break; + case JTAG_RUNTEST: + jlink_execute_runtest(cmd); + break; + case JTAG_TLR_RESET: + jlink_execute_statemove(cmd); + break; + case JTAG_PATHMOVE: + jlink_execute_pathmove(cmd); + break; + case JTAG_SCAN: + jlink_execute_scan(cmd); + break; + case JTAG_SLEEP: + jlink_execute_sleep(cmd); + break; + default: + LOG_ERROR("BUG: Unknown JTAG command type encountered"); + return ERROR_JTAG_QUEUE_FAILED; } return ERROR_OK; @@ -505,7 +504,7 @@ static int jaylink_log_handler(const struct jaylink_context *ctx, tmp = LOG_LVL_DEBUG; break; case JAYLINK_LOG_LEVEL_DEBUG_IO: - tmp = LOG_LVL_DEBUG_IO; + tmp = LOG_LVL_DEBUG_USB; break; default: tmp = LOG_LVL_WARNING; @@ -561,8 +560,9 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device) } use_usb_location = !!adapter_usb_get_location(); + const char *adapter_serial = adapter_get_required_serial(); - if (!use_serial_number && !use_usb_address && !use_usb_location && num_devices > 1) { + if (!adapter_serial && !use_usb_address && !use_usb_location && num_devices > 1) { LOG_ERROR("Multiple devices found, specify the desired device"); LOG_INFO("Found devices:"); for (size_t i = 0; devs[i]; i++) { @@ -575,7 +575,12 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device) jaylink_strerror(ret)); continue; } - LOG_INFO("Device %zu serial: %" PRIu32, i, serial); + char name[JAYLINK_NICKNAME_MAX_LENGTH]; + int name_ret = jaylink_device_get_nickname(devs[i], name); + if (name_ret == JAYLINK_OK) + LOG_INFO("Device %zu serial: %" PRIu32 ", nickname %s", i, serial, name); + else + LOG_INFO("Device %zu serial: %" PRIu32, i, serial); } jaylink_free_devices(devs, true); @@ -585,23 +590,39 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device) *found_device = false; + uint32_t serial_number; + ret = jaylink_parse_serial_number(adapter_serial, &serial_number); + if (ret != JAYLINK_OK) + serial_number = 0; + 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", - jaylink_strerror(ret)); - continue; + if (adapter_serial) { + /* + * Treat adapter serial as a nickname first as it can also be numeric. + * If it fails to match (optional) device nickname try to compare + * adapter serial with the actual device serial number. + */ + char nickname[JAYLINK_NICKNAME_MAX_LENGTH]; + ret = jaylink_device_get_nickname(dev, nickname); + if (ret != JAYLINK_OK || strcmp(nickname, adapter_serial) != 0) { + if (!serial_number) + continue; + + 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", + jaylink_strerror(ret)); + continue; + } + + if (serial_number != tmp) + continue; } - - if (serial_number != tmp) - continue; } if (use_usb_address) { @@ -670,29 +691,15 @@ static int jlink_init(void) 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; + if (adapter_get_required_serial()) 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) { + if (!found_device && adapter_get_required_serial()) { ret = jlink_open_device(JAYLINK_HIF_TCP, &found_device); if (ret != ERROR_OK) return ret; @@ -2111,44 +2118,44 @@ static int jlink_swd_switch_seq(enum swd_special_seq seq) unsigned int s_len; 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; + 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; } jlink_queue_data_out(s, s_len); diff --git a/src/jtag/drivers/jtag_dpi.c b/src/jtag/drivers/jtag_dpi.c index d6418d39c7..d5a42b1fb1 100644 --- a/src/jtag/drivers/jtag_dpi.c +++ b/src/jtag/drivers/jtag_dpi.c @@ -16,6 +16,9 @@ #endif #include +#ifdef HAVE_NETDB_H +#include +#endif #ifdef HAVE_ARPA_INET_H #include #endif @@ -31,7 +34,6 @@ 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; @@ -189,7 +191,7 @@ static int jtag_dpi_runtest(unsigned int num_cycles) return ERROR_FAIL; } snprintf(buf, sizeof(buf), "ib %d\n", num_bits); - while (num_cycles > 0) { + for (unsigned int cycle = 0; cycle < num_cycles; cycle += num_bits + 6) { ret = write_sock(buf, strlen(buf)); if (ret != ERROR_OK) { LOG_ERROR("write_sock() fail, file %s, line %d", @@ -208,8 +210,6 @@ static int jtag_dpi_runtest(unsigned int num_cycles) __FILE__, __LINE__); goto out; } - - num_cycles -= num_bits + 6; } out: @@ -266,18 +266,6 @@ static int jtag_dpi_execute_queue(struct jtag_command *cmd_queue) 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) { @@ -287,26 +275,65 @@ static int jtag_dpi_init(void) } } - serv_addr.sin_addr.s_addr = inet_addr(server_address); + const struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM + }; + + char port_str[5 + 1]; + snprintf(port_str, sizeof(port_str), "%" PRIu16, server_port); - if (serv_addr.sin_addr.s_addr == INADDR_NONE) { - LOG_ERROR("inet_addr error occurred"); + struct addrinfo *result; + int ret = getaddrinfo(server_address, port_str, &hints, &result); + + if (ret != 0) { + LOG_ERROR("getaddrinfo: %s", gai_strerror(ret)); return ERROR_FAIL; } - if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + struct addrinfo *rp; + for (rp = result; rp ; rp = rp->ai_next) { + sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sockfd == -1) + continue; + + if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) != -1) + break; + close(sockfd); - LOG_ERROR("Can't connect to %s : %" PRIu16, server_address, server_port); + } + + if (!rp) { + LOG_ERROR("Can't connect to %s : %" PRIu16, server_address, + server_port); + freeaddrinfo(result); return ERROR_FAIL; } - if (serv_addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { + + bool is_loopback = false; + if (rp->ai_family == AF_INET) { + struct sockaddr_in sa; + memcpy(&sa, rp->ai_addr, sizeof(sa)); + is_loopback = (sa.sin_addr.s_addr == htonl(INADDR_LOOPBACK)); + } else if (rp->ai_family == AF_INET6) { + struct sockaddr_in6 sa; + memcpy(&sa, rp->ai_addr, sizeof(sa)); + is_loopback = IN6_IS_ADDR_LOOPBACK(&sa.sin6_addr); + } + + if (is_loopback) { + LOG_DEBUG("Enabling TCP_NODELAY to enhance the speed of local connections"); + /* 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)); + setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, + sizeof(int)); } + freeaddrinfo(result); + LOG_INFO("Connection to %s : %" PRIu16 " succeed", server_address, server_port); return ERROR_OK; @@ -374,7 +401,7 @@ static const struct command_registration jtag_dpi_subcommand_handlers[] = { .name = "set_address", .handler = &jtag_dpi_set_address, .mode = COMMAND_CONFIG, - .help = "set the address of the DPI server", + .help = "set the hostname or IP address of the DPI server", .usage = "[address]", }, COMMAND_REGISTRATION_DONE diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c index fac27b3060..525b4bee58 100644 --- a/src/jtag/drivers/jtag_vpi.c +++ b/src/jtag/drivers/jtag_vpi.c @@ -14,6 +14,9 @@ #endif #include +#ifdef HAVE_NETDB_H +#include +#endif #ifdef HAVE_ARPA_INET_H #include #endif @@ -39,14 +42,13 @@ #define CMD_STOP_SIMU 4 /* jtag_vpi server port and address to connect to */ -static int server_port = DEFAULT_SERVER_PORT; +static uint16_t server_port = DEFAULT_SERVER_PORT; static char *server_address; /* Send CMD_STOP_SIMU to server when OpenOCD exits? */ static bool stop_sim_on_exit; static int sockfd; -static struct sockaddr_in serv_addr; /* One jtag_vpi "packet" as sent over a TCP channel. */ struct vpi_cmd { @@ -384,12 +386,9 @@ static int jtag_vpi_clock_tms(int tms) */ static int jtag_vpi_scan(struct scan_command *cmd) { - int scan_bits; uint8_t *buf = NULL; int retval = ERROR_OK; - scan_bits = jtag_build_buffer(cmd, &buf); - if (cmd->ir_scan) { retval = jtag_vpi_state_move(TAP_IRSHIFT); if (retval != ERROR_OK) @@ -400,14 +399,20 @@ static int jtag_vpi_scan(struct scan_command *cmd) return retval; } + int scan_bits = jtag_build_buffer(cmd, &buf); + if (cmd->end_state == TAP_DRSHIFT) { retval = jtag_vpi_queue_tdi(buf, scan_bits, NO_TAP_SHIFT); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + free(buf); return retval; + } } else { retval = jtag_vpi_queue_tdi(buf, scan_bits, TAP_SHIFT); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + free(buf); return retval; + } } if (cmd->end_state != TAP_DRSHIFT) { @@ -416,8 +421,10 @@ static int jtag_vpi_scan(struct scan_command *cmd) * forward to a stable IRPAUSE or DRPAUSE. */ retval = jtag_vpi_clock_tms(0); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + free(buf); return retval; + } if (cmd->ir_scan) tap_set_state(TAP_IRPAUSE); @@ -426,8 +433,10 @@ static int jtag_vpi_scan(struct scan_command *cmd) } retval = jtag_read_buffer(buf, cmd); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + free(buf); return retval; + } free(buf); @@ -524,43 +533,70 @@ static int jtag_vpi_execute_queue(struct jtag_command *cmd_queue) static int jtag_vpi_init(void) { - int flag = 1; + if (!server_address) + server_address = strdup(DEFAULT_SERVER_ADDRESS); - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd < 0) { - LOG_ERROR("jtag_vpi: Could not create client socket"); + const struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM + }; + + char port_str[5 + 1]; + snprintf(port_str, sizeof(port_str), "%" PRIu16, server_port); + + struct addrinfo *result; + int ret = getaddrinfo(server_address, port_str, &hints, &result); + + if (ret != 0) { + LOG_ERROR("getaddrinfo: %s", gai_strerror(ret)); return ERROR_FAIL; } - memset(&serv_addr, 0, sizeof(serv_addr)); + struct addrinfo *rp; + for (rp = result; rp ; rp = rp->ai_next) { + sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sockfd == -1) + continue; - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(server_port); - - if (!server_address) - server_address = strdup(DEFAULT_SERVER_ADDRESS); + if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) != -1) + break; - serv_addr.sin_addr.s_addr = inet_addr(server_address); + close(sockfd); + } - if (serv_addr.sin_addr.s_addr == INADDR_NONE) { - LOG_ERROR("jtag_vpi: inet_addr error occurred"); + if (!rp) { + LOG_ERROR("jtag_vpi: Can't connect to %s : %" PRIu16, + server_address, server_port); + freeaddrinfo(result); return ERROR_FAIL; } - if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { - close(sockfd); - LOG_ERROR("jtag_vpi: Can't connect to %s : %u", server_address, server_port); - return ERROR_COMMAND_CLOSE_CONNECTION; + bool is_loopback = false; + if (rp->ai_family == AF_INET) { + struct sockaddr_in sa; + memcpy(&sa, rp->ai_addr, sizeof(sa)); + is_loopback = (sa.sin_addr.s_addr == htonl(INADDR_LOOPBACK)); + } else if (rp->ai_family == AF_INET6) { + struct sockaddr_in6 sa; + memcpy(&sa, rp->ai_addr, sizeof(sa)); + is_loopback = IN6_IS_ADDR_LOOPBACK(&sa.sin6_addr); } - if (serv_addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { + if (is_loopback) { /* This increases performance dramatically for local - * connections, which is the most likely arrangement - * for a VPI connection. */ - setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)); + * connections, which is the most likely arrangement + * for a VPI connection. */ + LOG_DEBUG("Enabling TCP_NODELAY to enhance the speed of local connections"); + + int flag = 1; + setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, + sizeof(int)); } - LOG_INFO("jtag_vpi: Connection to %s : %u successful", server_address, server_port); + freeaddrinfo(result); + + LOG_INFO("jtag_vpi: Connection to %s : %" PRIu16 " successful", + server_address, server_port); return ERROR_OK; } @@ -594,8 +630,8 @@ COMMAND_HANDLER(jtag_vpi_set_port) if (CMD_ARGC == 0) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port); - LOG_INFO("jtag_vpi: server port set to %u", server_port); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], server_port); + LOG_INFO("jtag_vpi: server port set to %" PRIu16, server_port); return ERROR_OK; } @@ -634,7 +670,7 @@ static const struct command_registration jtag_vpi_subcommand_handlers[] = { .name = "set_address", .handler = &jtag_vpi_set_address, .mode = COMMAND_CONFIG, - .help = "set the IP address of the jtag_vpi server (default: 127.0.0.1)", + .help = "set the hostname or IP address of the jtag_vpi server (default: 127.0.0.1)", .usage = "ipv4_addr", }, { diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index 88e301cebc..f79e2dca70 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -646,25 +646,24 @@ static void kitprog_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay static int kitprog_swd_switch_seq(enum swd_special_seq seq) { switch (seq) { - case JTAG_TO_SWD: - if (kitprog_handle->supports_jtag_to_swd) { - LOG_DEBUG("JTAG to SWD"); - if (kitprog_swd_seq(SEQUENCE_JTAG_TO_SWD) != ERROR_OK) - return ERROR_FAIL; - break; - } else { - LOG_DEBUG("JTAG to SWD not supported"); - /* Fall through to fix target reset issue */ - } - /* fallthrough */ - case LINE_RESET: - LOG_DEBUG("SWD line reset"); - if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK) + case JTAG_TO_SWD: + if (kitprog_handle->supports_jtag_to_swd) { + LOG_DEBUG("JTAG to SWD"); + if (kitprog_swd_seq(SEQUENCE_JTAG_TO_SWD) != ERROR_OK) return ERROR_FAIL; break; - default: - LOG_ERROR("Sequence %d not supported.", seq); + } + LOG_DEBUG("JTAG to SWD not supported"); + /* Fall through to fix target reset issue */ + /* fallthrough */ + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK) return ERROR_FAIL; + break; + default: + LOG_ERROR("Sequence %d not supported.", seq); + return ERROR_FAIL; } return ERROR_OK; diff --git a/src/jtag/drivers/linuxgpiod.c b/src/jtag/drivers/linuxgpiod.c index 36c7e04934..cc738e9a30 100644 --- a/src/jtag/drivers/linuxgpiod.c +++ b/src/jtag/drivers/linuxgpiod.c @@ -19,8 +19,278 @@ #include #include "bitbang.h" +/* + * In case of libgpiod v1, use as much as possible API from v2 plus + * the dummy wrappers below. + */ +#ifdef HAVE_LIBGPIOD_V1 + +#define GPIOD_LINE_DIRECTION_INPUT GPIOD_LINE_REQUEST_DIRECTION_INPUT +#define GPIOD_LINE_DIRECTION_OUTPUT GPIOD_LINE_REQUEST_DIRECTION_OUTPUT + +#define GPIOD_LINE_VALUE_INACTIVE 0 +#define GPIOD_LINE_VALUE_ACTIVE 1 + +#define GPIOD_LINE_DRIVE_PUSH_PULL 0 +#define GPIOD_LINE_DRIVE_OPEN_DRAIN GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN +#define GPIOD_LINE_DRIVE_OPEN_SOURCE GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE + +#define GPIOD_LINE_BIAS_DISABLED GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE +#define GPIOD_LINE_BIAS_PULL_UP GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP +#define GPIOD_LINE_BIAS_PULL_DOWN GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN + +struct gpiod_line_settings { + int direction; + int value; + int drive; + int bias; + int active_low; +}; + +static struct gpiod_line_settings *gpiod_line_settings_new(void) +{ + struct gpiod_line_settings *rv; + + rv = calloc(sizeof(struct gpiod_line_settings), 1); + if (!rv) { + LOG_ERROR("No memory for gpiod line settings"); + return NULL; + } + + return rv; +} + +static void gpiod_line_settings_free(struct gpiod_line_settings *settings) +{ + free(settings); +} + +static int gpiod_line_settings_set_direction(struct gpiod_line_settings *settings, + int direction) +{ + settings->direction = direction; + + return 0; +} + +static int gpiod_line_settings_set_output_value(struct gpiod_line_settings *settings, + int value) +{ + settings->value = value; + + return 0; +} + +static int gpiod_line_settings_set_drive(struct gpiod_line_settings *settings, int drive) +{ + settings->drive = drive; + + return 0; +} + +static void gpiod_line_settings_set_active_low(struct gpiod_line_settings *settings, + bool active_low) +{ + if (active_low) + settings->active_low = GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; +} + +#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS + +static int gpiod_line_settings_set_bias(struct gpiod_line_settings *settings, int bias) +{ + settings->bias = bias; + + return 0; +} + +#else /* HAVE_LIBGPIOD1_FLAGS_BIAS */ + +static int gpiod_line_settings_set_bias(struct gpiod_line_settings *settings, int bias) +{ + if (bias == GPIOD_LINE_BIAS_DISABLED) + return 0; + + LOG_WARNING("linuxgpiod: ignoring request for pull-%s: not supported by libgpiod v%s", + (bias == GPIOD_LINE_BIAS_PULL_UP) ? "up" : "down", + gpiod_version_string()); + + return 0; +} + +#endif /* HAVE_LIBGPIOD1_FLAGS_BIAS */ + +struct gpiod_line_config { + unsigned int gpio_num; + struct gpiod_line_settings *line_settings; +}; + +static struct gpiod_line_config *gpiod_line_config_new(void) +{ + struct gpiod_line_config *rv; + + rv = calloc(sizeof(struct gpiod_line_config), 1); + if (!rv) { + LOG_ERROR("No memory for gpiod line config"); + return NULL; + } + + return rv; +} + +static void gpiod_line_config_free(struct gpiod_line_config *config) +{ + free(config); +} + +static int gpiod_line_config_add_line_settings(struct gpiod_line_config *config, + const unsigned int *offsets, size_t num_offsets, struct gpiod_line_settings *settings) +{ + assert(num_offsets == 1); + + config->gpio_num = *offsets; + config->line_settings = settings; + + return 0; +} + +struct gpiod_request_config { + const char *consumer; +}; + +static struct gpiod_request_config *gpiod_request_config_new(void) +{ + struct gpiod_request_config *rv; + + rv = calloc(sizeof(struct gpiod_request_config), 1); + if (!rv) { + LOG_ERROR("No memory for gpiod request config"); + return NULL; + } + + return rv; +} + +static void gpiod_request_config_free(struct gpiod_request_config *config) +{ + free(config); +} + +static void gpiod_request_config_set_consumer(struct gpiod_request_config *config, + const char *consumer) +{ + config->consumer = consumer; +} + +struct gpiod_line_request { + struct gpiod_line *gpio_line; + struct gpiod_chip *chip; + struct gpiod_request_config *req_cfg; + struct gpiod_line_config *line_cfg; +}; + +static void gpiod_line_request_release(struct gpiod_line_request *request); + +static struct gpiod_line_request *gpiod_chip_request_lines(struct gpiod_chip *chip, + struct gpiod_request_config *req_cfg, struct gpiod_line_config *line_cfg) +{ + struct gpiod_line_request *line_req; + int rv, flags = 0; + + assert(req_cfg); + + line_req = calloc(sizeof(struct gpiod_line_request), 1); + if (!line_req) { + LOG_ERROR("No memory for gpiod line request"); + return NULL; + } + + line_req->gpio_line = gpiod_chip_get_line(chip, line_cfg->gpio_num); + if (!line_req->gpio_line) { + free(line_req); + return NULL; + } + + /* remember stuff in case we need to reconfigure later */ + line_req->chip = chip; + line_req->req_cfg = gpiod_request_config_new(); + *line_req->req_cfg = *req_cfg; + line_req->line_cfg = line_cfg; + + flags |= line_cfg->line_settings->drive; + flags |= line_cfg->line_settings->bias; + flags |= line_cfg->line_settings->active_low; + + struct gpiod_line_request_config config = { + .consumer = line_req->req_cfg->consumer, + .request_type = line_cfg->line_settings->direction, + .flags = flags, + }; + + rv = gpiod_line_request(line_req->gpio_line, &config, line_cfg->line_settings->value); + if (rv < 0) { + gpiod_line_request_release(line_req); + return NULL; + } + + return line_req; +} + +static int gpiod_line_request_get_value(struct gpiod_line_request *request, + __attribute__((unused)) unsigned int offset) +{ + return gpiod_line_get_value(request->gpio_line); +} + +static int gpiod_line_request_set_value(struct gpiod_line_request *request, + __attribute__((unused)) unsigned int offset, int value) +{ + return gpiod_line_set_value(request->gpio_line, value); +} + +static void gpiod_line_request_release(struct gpiod_line_request *request) +{ + gpiod_request_config_free(request->req_cfg); + gpiod_line_release(request->gpio_line); + free(request); +} + +static int gpiod_line_request_reconfigure_lines(struct gpiod_line_request *request, + struct gpiod_line_config *line_cfg) +{ + int rv, flags = 0; + + /* in libgpiod v1 we have to release the line and re-aquire it */ + gpiod_line_release(request->gpio_line); + request->gpio_line = gpiod_chip_get_line(request->chip, request->line_cfg->gpio_num); + if (!request->gpio_line) + return -1; + + flags |= line_cfg->line_settings->drive; + flags |= line_cfg->line_settings->bias; + flags |= line_cfg->line_settings->active_low; + + struct gpiod_line_request_config config = { + .consumer = request->req_cfg->consumer, + .request_type = line_cfg->line_settings->direction, + .flags = flags, + }; + + rv = gpiod_line_request(request->gpio_line, &config, line_cfg->line_settings->value); + if (rv < 0) + return -1; + + /* remember updated line_cfg */ + request->line_cfg = line_cfg; + return 0; +} + +#endif /* HAVE_LIBGPIOD_V1 */ + static struct gpiod_chip *gpiod_chip[ADAPTER_GPIO_IDX_NUM] = {}; -static struct gpiod_line *gpiod_line[ADAPTER_GPIO_IDX_NUM] = {}; +static struct gpiod_line_settings *gpiod_line_settings[ADAPTER_GPIO_IDX_NUM] = {}; +static struct gpiod_line_config *gpiod_line_config[ADAPTER_GPIO_IDX_NUM] = {}; +static struct gpiod_line_request *gpiod_line_req[ADAPTER_GPIO_IDX_NUM] = {}; static int last_swclk; static int last_swdio; @@ -29,6 +299,20 @@ static bool swdio_input; static const struct adapter_gpio_config *adapter_gpio_config; +/* Helper to get/set a single line */ +static int linuxgpiod_line_get_value(enum adapter_gpio_config_index idx) +{ + return gpiod_line_request_get_value(gpiod_line_req[idx], + adapter_gpio_config[idx].gpio_num); +} + +static int linuxgpiod_line_set_value(enum adapter_gpio_config_index idx, int value) +{ + return gpiod_line_request_set_value(gpiod_line_req[idx], + adapter_gpio_config[idx].gpio_num, + value); +} + /* * Helper function to determine if gpio config is valid * @@ -46,7 +330,7 @@ static enum bb_value linuxgpiod_read(void) { int retval; - retval = gpiod_line_get_value(gpiod_line[ADAPTER_GPIO_IDX_TDO]); + retval = linuxgpiod_line_get_value(ADAPTER_GPIO_IDX_TDO); if (retval < 0) { LOG_WARNING("reading tdo failed"); return 0; @@ -79,20 +363,20 @@ static int linuxgpiod_write(int tck, int tms, int tdi) } if (tdi != last_tdi) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TDI], tdi); + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_TDI, tdi); if (retval < 0) LOG_WARNING("writing tdi failed"); } if (tms != last_tms) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TMS], tms); + retval = linuxgpiod_line_set_value(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_line[ADAPTER_GPIO_IDX_TCK], tck); + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_TCK, tck); if (retval < 0) LOG_WARNING("writing tck failed"); } @@ -108,7 +392,7 @@ static int linuxgpiod_swdio_read(void) { int retval; - retval = gpiod_line_get_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO]); + retval = linuxgpiod_line_get_value(ADAPTER_GPIO_IDX_SWDIO); if (retval < 0) { LOG_WARNING("Fail read swdio"); return 0; @@ -121,30 +405,54 @@ static void linuxgpiod_swdio_drive(bool is_output) { int retval; - /* - * FIXME: change direction requires release and re-require the line - * https://stackoverflow.com/questions/58735140/ - * this would change in future libgpiod - */ - gpiod_line_release(gpiod_line[ADAPTER_GPIO_IDX_SWDIO]); - if (is_output) { - if (gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR]) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR], 1); + if (gpiod_line_req[ADAPTER_GPIO_IDX_SWDIO_DIR]) { + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_SWDIO_DIR, 1); if (retval < 0) - LOG_WARNING("Fail set swdio_dir"); + LOG_WARNING("Failed to set swdio_dir=1"); } - retval = gpiod_line_request_output(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], "OpenOCD", 1); + + retval = gpiod_line_settings_set_direction(gpiod_line_settings[ADAPTER_GPIO_IDX_SWDIO], + GPIOD_LINE_DIRECTION_OUTPUT); + if (retval < 0) + LOG_WARNING("Failed to set new direction of swdio"); + + retval = gpiod_line_settings_set_output_value(gpiod_line_settings[ADAPTER_GPIO_IDX_SWDIO], + GPIOD_LINE_VALUE_ACTIVE); + if (retval < 0) + LOG_WARNING("Failed to set output value of swdio"); + + retval = gpiod_line_config_add_line_settings(gpiod_line_config[ADAPTER_GPIO_IDX_SWDIO], + &adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num, 1, + gpiod_line_settings[ADAPTER_GPIO_IDX_SWDIO]); + if (retval < 0) + LOG_WARNING("Failed to apply output configuration to swdio"); + + retval = gpiod_line_request_reconfigure_lines(gpiod_line_req[ADAPTER_GPIO_IDX_SWDIO], + gpiod_line_config[ADAPTER_GPIO_IDX_SWDIO]); if (retval < 0) - LOG_WARNING("Fail request_output line swdio"); + LOG_WARNING("Failed to switch swdio to output"); } else { - retval = gpiod_line_request_input(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], "OpenOCD"); + retval = gpiod_line_settings_set_direction(gpiod_line_settings[ADAPTER_GPIO_IDX_SWDIO], + GPIOD_LINE_DIRECTION_INPUT); 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); + LOG_WARNING("Failed to switch swdio to output"); + + retval = gpiod_line_config_add_line_settings(gpiod_line_config[ADAPTER_GPIO_IDX_SWDIO], + &adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num, 1, + gpiod_line_settings[ADAPTER_GPIO_IDX_SWDIO]); + if (retval < 0) + LOG_WARNING("Failed to apply input configuration to swdio"); + + retval = gpiod_line_request_reconfigure_lines(gpiod_line_req[ADAPTER_GPIO_IDX_SWDIO], + gpiod_line_config[ADAPTER_GPIO_IDX_SWDIO]); + if (retval < 0) + LOG_WARNING("Failed to switch swdio to input"); + + if (gpiod_line_req[ADAPTER_GPIO_IDX_SWDIO_DIR]) { + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_SWDIO_DIR, 0); if (retval < 0) - LOG_WARNING("Fail set swdio_dir"); + LOG_WARNING("Failed to set swdio_dir=0"); } } @@ -158,7 +466,7 @@ static int linuxgpiod_swd_write(int swclk, int swdio) if (!swdio_input) { if (!last_stored || swdio != last_swdio) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], swdio); + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_SWDIO, swdio); if (retval < 0) LOG_WARNING("Fail set swdio"); } @@ -166,7 +474,7 @@ static int linuxgpiod_swd_write(int swclk, int swdio) /* write swclk last */ if (!last_stored || swclk != last_swclk) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWCLK], swclk); + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_SWCLK, swclk); if (retval < 0) LOG_WARNING("Fail set swclk"); } @@ -185,7 +493,7 @@ static int linuxgpiod_blink(bool on) if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_LED)) return ERROR_OK; - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_LED], on ? 1 : 0); + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_LED, on); if (retval < 0) LOG_WARNING("Fail set led"); return retval; @@ -212,17 +520,17 @@ static int linuxgpiod_reset(int trst, int srst) LOG_DEBUG("linuxgpiod_reset"); /* - * active low behaviour handled by "adaptor gpio" command and + * active low behavior 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 (gpiod_line_req[ADAPTER_GPIO_IDX_SRST]) { + retval1 = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_SRST, srst); if (retval1 < 0) LOG_WARNING("set srst value failed"); } - if (gpiod_line[ADAPTER_GPIO_IDX_TRST]) { - retval2 = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TRST], trst); + if (gpiod_line_req[ADAPTER_GPIO_IDX_TRST]) { + retval2 = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_TRST, trst); if (retval2 < 0) LOG_WARNING("set trst value failed"); } @@ -254,9 +562,17 @@ static bool linuxgpiod_swd_mode_possible(void) static inline void helper_release(enum adapter_gpio_config_index idx) { - if (gpiod_line[idx]) { - gpiod_line_release(gpiod_line[idx]); - gpiod_line[idx] = NULL; + if (gpiod_line_req[idx]) { + gpiod_line_request_release(gpiod_line_req[idx]); + gpiod_line_req[idx] = NULL; + } + if (gpiod_line_config[idx]) { + gpiod_line_config_free(gpiod_line_config[idx]); + gpiod_line_config[idx] = NULL; + } + if (gpiod_line_settings[idx]) { + gpiod_line_settings_free(gpiod_line_settings[idx]); + gpiod_line_settings[idx] = NULL; } if (gpiod_chip[idx]) { gpiod_chip_close(gpiod_chip[idx]); @@ -275,84 +591,103 @@ static int linuxgpiod_quit(void) static int helper_get_line(enum adapter_gpio_config_index idx) { + struct gpiod_request_config *req_cfg = NULL; + char chip_path[24]; + int rv = 0; + if (!is_gpio_config_valid(idx)) return ERROR_OK; - int dir = GPIOD_LINE_REQUEST_DIRECTION_INPUT, flags = 0, val = 0, retval; + snprintf(chip_path, sizeof(chip_path), "/dev/gpiochip%u", adapter_gpio_config[idx].chip_num); + gpiod_chip[idx] = gpiod_chip_open(chip_path); - gpiod_chip[idx] = gpiod_chip_open_by_number(adapter_gpio_config[idx].chip_num); if (!gpiod_chip[idx]) { LOG_ERROR("Cannot open LinuxGPIOD chip %d for %s", adapter_gpio_config[idx].chip_num, adapter_gpio_get_name(idx)); return ERROR_JTAG_INIT_FAILED; } - gpiod_line[idx] = gpiod_chip_get_line(gpiod_chip[idx], adapter_gpio_config[idx].gpio_num); - if (!gpiod_line[idx]) { - LOG_ERROR("Error get line %s", adapter_gpio_get_name(idx)); + gpiod_line_settings[idx] = gpiod_line_settings_new(); + gpiod_line_config[idx] = gpiod_line_config_new(); + req_cfg = gpiod_request_config_new(); + + if (!gpiod_line_settings[idx] || !gpiod_line_config[idx] || !req_cfg) { + LOG_ERROR("Cannot configure LinuxGPIOD line for %s", adapter_gpio_get_name(idx)); + gpiod_request_config_free(req_cfg); return ERROR_JTAG_INIT_FAILED; } + gpiod_request_config_set_consumer(req_cfg, "OpenOCD"); + switch (adapter_gpio_config[idx].init_state) { case ADAPTER_GPIO_INIT_STATE_INPUT: - dir = GPIOD_LINE_REQUEST_DIRECTION_INPUT; + rv = gpiod_line_settings_set_direction(gpiod_line_settings[idx], GPIOD_LINE_DIRECTION_INPUT); break; case ADAPTER_GPIO_INIT_STATE_INACTIVE: - dir = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; - val = 0; + rv = gpiod_line_settings_set_direction(gpiod_line_settings[idx], GPIOD_LINE_DIRECTION_OUTPUT); + rv |= gpiod_line_settings_set_output_value(gpiod_line_settings[idx], GPIOD_LINE_VALUE_INACTIVE); break; case ADAPTER_GPIO_INIT_STATE_ACTIVE: - dir = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; - val = 1; + rv = gpiod_line_settings_set_direction(gpiod_line_settings[idx], GPIOD_LINE_DIRECTION_OUTPUT); + rv |= gpiod_line_settings_set_output_value(gpiod_line_settings[idx], GPIOD_LINE_VALUE_ACTIVE); break; } + if (rv < 0) { + LOG_ERROR("Error while configuring LinuxGPIOD line init state for %s", adapter_gpio_get_name(idx)); + gpiod_request_config_free(req_cfg); + return ERROR_JTAG_INIT_FAILED; + } switch (adapter_gpio_config[idx].drive) { case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: + rv = gpiod_line_settings_set_drive(gpiod_line_settings[idx], GPIOD_LINE_DRIVE_PUSH_PULL); break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN: - flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN; + rv = gpiod_line_settings_set_drive(gpiod_line_settings[idx], GPIOD_LINE_DRIVE_OPEN_DRAIN); break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: - flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE; + rv = gpiod_line_settings_set_drive(gpiod_line_settings[idx], GPIOD_LINE_DRIVE_OPEN_SOURCE); break; } + if (rv < 0) { + LOG_ERROR("Error while configuring LinuxGPIOD line driving for %s", adapter_gpio_get_name(idx)); + gpiod_request_config_free(req_cfg); + return ERROR_JTAG_INIT_FAILED; + } switch (adapter_gpio_config[idx].pull) { case ADAPTER_GPIO_PULL_NONE: -#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS - flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE; -#endif + rv = gpiod_line_settings_set_bias(gpiod_line_settings[idx], GPIOD_LINE_BIAS_DISABLED); 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 + rv = gpiod_line_settings_set_bias(gpiod_line_settings[idx], GPIOD_LINE_BIAS_PULL_UP); 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 + rv = gpiod_line_settings_set_bias(gpiod_line_settings[idx], GPIOD_LINE_BIAS_PULL_DOWN); break; } + if (rv < 0) { + LOG_ERROR("Error while configuring LinuxGPIOD line biasing for %s", adapter_gpio_get_name(idx)); + gpiod_request_config_free(req_cfg); + return ERROR_JTAG_INIT_FAILED; + } - if (adapter_gpio_config[idx].active_low) - flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; + gpiod_line_settings_set_active_low(gpiod_line_settings[idx], adapter_gpio_config[idx].active_low); - struct gpiod_line_request_config config = { - .consumer = "OpenOCD", - .request_type = dir, - .flags = flags, - }; + rv = gpiod_line_config_add_line_settings(gpiod_line_config[idx], + &adapter_gpio_config[idx].gpio_num, 1, + gpiod_line_settings[idx]); + if (rv < 0) { + LOG_ERROR("Error configuring gpio line %s", adapter_gpio_get_name(idx)); + gpiod_request_config_free(req_cfg); + return ERROR_JTAG_INIT_FAILED; + } - retval = gpiod_line_request(gpiod_line[idx], &config, val); - if (retval < 0) { + gpiod_line_req[idx] = gpiod_chip_request_lines(gpiod_chip[idx], req_cfg, gpiod_line_config[idx]); + + gpiod_request_config_free(req_cfg); + + if (!gpiod_line_req[idx]) { LOG_ERROR("Error requesting gpio line %s", adapter_gpio_get_name(idx)); return ERROR_JTAG_INIT_FAILED; } diff --git a/src/jtag/drivers/nulink_usb.c b/src/jtag/drivers/nulink_usb.c index 66cf25a6d1..df140ba58d 100644 --- a/src/jtag/drivers/nulink_usb.c +++ b/src/jtag/drivers/nulink_usb.c @@ -1030,7 +1030,7 @@ static int nulink_usb_open(struct hl_interface_param *param, void **fd) if (param->transport != HL_TRANSPORT_SWD) return TARGET_UNKNOWN; - if (!param->vid[0] && !param->pid[0]) { + if (!adapter_usb_get_vids()[0] && !adapter_usb_get_pids()[0]) { LOG_ERROR("Missing vid/pid"); return ERROR_FAIL; } @@ -1068,8 +1068,9 @@ static int nulink_usb_open(struct hl_interface_param *param, void **fd) while (cur_dev) { bool found = false; - for (unsigned int i = 0; param->vid[i] || param->pid[i]; i++) { - if (param->vid[i] == cur_dev->vendor_id && param->pid[i] == cur_dev->product_id) { + for (unsigned int i = 0; adapter_usb_get_vids()[i] != 0; i++) { + if (cur_dev->vendor_id == adapter_usb_get_vids()[i] && + cur_dev->product_id == adapter_usb_get_pids()[i]) { found = true; break; } diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index 04626cb1e5..17db209035 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -134,10 +134,7 @@ static int opendous_usb_read(struct opendous_jtag *opendous_jtag); /* helper functions */ static int opendous_get_version_info(void); - -#ifdef _DEBUG_USB_COMMS_ static void opendous_debug_buffer(uint8_t *buffer, int length); -#endif static struct opendous_jtag *opendous_jtag_handle; @@ -173,26 +170,26 @@ COMMAND_HANDLER(opendous_handle_opendous_info_command) COMMAND_HANDLER(opendous_handle_opendous_hw_jtag_command) { switch (CMD_ARGC) { - case 0: - command_print(CMD, "opendous hw jtag %i", opendous_hw_jtag_version); - break; - - case 1: { - int request_version = atoi(CMD_ARGV[0]); - switch (request_version) { - case 2: - case 3: - opendous_hw_jtag_version = request_version; - break; - - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } + case 0: + command_print(CMD, "opendous hw jtag %i", opendous_hw_jtag_version); + break; + + case 1: { + int request_version = atoi(CMD_ARGV[0]); + switch (request_version) { + case 2: + case 3: + opendous_hw_jtag_version = request_version; break; - } default: return ERROR_COMMAND_SYNTAX_ERROR; + } + break; + } + + default: + return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; @@ -248,66 +245,65 @@ static int opendous_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); - if (cmd->cmd.runtest->end_state != -1) - opendous_end_state(cmd->cmd.runtest->end_state); - opendous_runtest(cmd->cmd.runtest->num_cycles); - break; + if (cmd->cmd.runtest->end_state != -1) + opendous_end_state(cmd->cmd.runtest->end_state); + opendous_runtest(cmd->cmd.runtest->num_cycles); + break; - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - if (cmd->cmd.statemove->end_state != -1) - opendous_end_state(cmd->cmd.statemove->end_state); - opendous_state_move(); - break; + if (cmd->cmd.statemove->end_state != -1) + opendous_end_state(cmd->cmd.statemove->end_state); + opendous_state_move(); + break; - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %u states, end in %i", - cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %u states, end in %i", + cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - opendous_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); - break; + opendous_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); + break; - case JTAG_SCAN: - LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); + case JTAG_SCAN: + LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); - if (cmd->cmd.scan->end_state != -1) - opendous_end_state(cmd->cmd.scan->end_state); + if (cmd->cmd.scan->end_state != -1) + opendous_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - LOG_DEBUG_IO("scan input, length = %d", scan_size); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + LOG_DEBUG_IO("scan input, length = %d", scan_size); -#ifdef _DEBUG_USB_COMMS_ - opendous_debug_buffer(buffer, (scan_size + 7) / 8); -#endif - type = jtag_scan_type(cmd->cmd.scan); - opendous_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); - break; + opendous_debug_buffer(buffer, (scan_size + 7) / 8); + + type = jtag_scan_type(cmd->cmd.scan); + opendous_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); + break; - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); - opendous_tap_execute(); + opendous_tap_execute(); - if (cmd->cmd.reset->trst == 1) - tap_set_state(TAP_RESET); - opendous_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; + if (cmd->cmd.reset->trst == 1) + tap_set_state(TAP_RESET); + opendous_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - opendous_tap_execute(); - jtag_sleep(cmd->cmd.sleep->us); - break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + opendous_tap_execute(); + jtag_sleep(cmd->cmd.sleep->us); + break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } @@ -604,10 +600,7 @@ int opendous_tap_execute(void) int byte_length; int i, j; int result; - -#ifdef _DEBUG_USB_COMMS_ int byte_length_out; -#endif if (tap_length > 0) { @@ -615,10 +608,8 @@ int opendous_tap_execute(void) /* LOG_INFO("OPENDOUS tap execute %d",tap_length); */ byte_length = (tap_length + 3) / 4; -#ifdef _DEBUG_USB_COMMS_ byte_length_out = (tap_length + 7) / 8; - LOG_DEBUG("opendous is sending %d bytes", byte_length); -#endif + LOG_DEBUG_USB("opendous is sending %d bytes", byte_length); for (j = 0, i = 0; j < byte_length;) { @@ -647,10 +638,8 @@ int opendous_tap_execute(void) j += transmit; } -#ifdef _DEBUG_USB_COMMS_ - LOG_DEBUG("opendous tap result %d", byte_length_out); + LOG_DEBUG_USB("opendous tap result %d", byte_length_out); opendous_debug_buffer(tdo_buffer, byte_length_out); -#endif /* LOG_INFO("eStick tap execute %d",tap_length); */ for (i = 0; i < pending_scan_results_length; i++) { @@ -666,9 +655,7 @@ int opendous_tap_execute(void) LOG_DEBUG_IO("pending scan result, length = %d", length); -#ifdef _DEBUG_USB_COMMS_ opendous_debug_buffer(buffer, byte_length_out); -#endif if (jtag_read_buffer(buffer, command) != ERROR_OK) { opendous_tap_init(); @@ -739,9 +726,8 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length) return -1; } -#ifdef _DEBUG_USB_COMMS_ - LOG_DEBUG("USB write begin"); -#endif + LOG_DEBUG_USB("USB write begin"); + if (opendous_probe->CONTROL_TRANSFER) { result = jtag_libusb_control_transfer(opendous_jtag->usb_handle, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, @@ -754,15 +740,13 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length) jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT, (char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT, &result); } -#ifdef _DEBUG_USB_COMMS_ - LOG_DEBUG("USB write end: %d bytes", result); -#endif + + LOG_DEBUG_USB("USB write end: %d bytes", result); LOG_DEBUG_IO("opendous_usb_write, out_length = %d, result = %d", out_length, result); -#ifdef _DEBUG_USB_COMMS_ opendous_debug_buffer(usb_out_buffer, out_length); -#endif + return result; } @@ -771,9 +755,8 @@ int opendous_usb_read(struct opendous_jtag *opendous_jtag) { int transferred; -#ifdef _DEBUG_USB_COMMS_ - LOG_DEBUG("USB read begin"); -#endif + LOG_DEBUG_USB("USB read begin"); + int result; if (opendous_probe->CONTROL_TRANSFER) { result = jtag_libusb_control_transfer(opendous_jtag->usb_handle, @@ -787,29 +770,29 @@ int opendous_usb_read(struct opendous_jtag *opendous_jtag) jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT, (char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT, &result); } -#ifdef _DEBUG_USB_COMMS_ - LOG_DEBUG("USB read end: %d bytes", result); -#endif + + LOG_DEBUG_USB("USB read end: %d bytes", result); + LOG_DEBUG_IO("opendous_usb_read, result = %d", result); -#ifdef _DEBUG_USB_COMMS_ opendous_debug_buffer(usb_in_buffer, result); -#endif + return result; } -#ifdef _DEBUG_USB_COMMS_ #define BYTES_PER_LINE 16 void opendous_debug_buffer(uint8_t *buffer, int length) { + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG_USB)) + return; + char line[8 + 3 * BYTES_PER_LINE + 1]; 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); + LOG_DEBUG_USB("%s", line); } } -#endif diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 943ad854e8..86b27ac4a1 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -32,6 +32,7 @@ #include "config.h" #endif +#include #include #include #include "libusb_helper.h" @@ -74,10 +75,8 @@ enum openjtag_tap_state { #include "libftdi_helper.h" /* OpenJTAG vid/pid */ -static uint16_t openjtag_vid = 0x0403; -static uint16_t openjtag_pid = 0x6001; - -static char *openjtag_device_desc; +static uint16_t openjtag_vids[] = {0x0403, 0}; +static uint16_t openjtag_pids[] = {0x6001, 0}; static struct ftdi_context ftdic; @@ -119,8 +118,6 @@ static const uint16_t cy7c65215_pids[] = {0x0007, 0}; static unsigned int ep_in, ep_out; -#ifdef _DEBUG_USB_COMMS_ - #define DEBUG_TYPE_READ 0 #define DEBUG_TYPE_WRITE 1 #define DEBUG_TYPE_OCD_READ 2 @@ -129,77 +126,78 @@ static unsigned int ep_in, ep_out; #define LINE_LEN 16 static void openjtag_debug_buffer(uint8_t *buffer, int length, uint8_t type) { + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG_USB)) + return; + char line[128]; char s[4]; int i; int j; switch (type) { + case DEBUG_TYPE_READ: + sprintf(line, "USB READ %d bytes", length); + break; + case DEBUG_TYPE_WRITE: + sprintf(line, "USB WRITE %d bytes", length); + break; + case DEBUG_TYPE_OCD_READ: + sprintf(line, "TO OpenOCD %d bytes", length); + break; + case DEBUG_TYPE_BUFFER: + sprintf(line, "Buffer %d bytes", length); + break; + } + + LOG_DEBUG_USB("%s", line); + + for (i = 0; i < length; i += LINE_LEN) { + switch (type) { case DEBUG_TYPE_READ: - sprintf(line, "USB READ %d bytes", length); + sprintf(line, "USB READ: %04x", i); break; case DEBUG_TYPE_WRITE: - sprintf(line, "USB WRITE %d bytes", length); + sprintf(line, "USB WRITE: %04x", i); break; case DEBUG_TYPE_OCD_READ: - sprintf(line, "TO OpenOCD %d bytes", length); + sprintf(line, "TO OpenOCD: %04x", i); break; case DEBUG_TYPE_BUFFER: - sprintf(line, "Buffer %d bytes", length); + sprintf(line, "BUFFER: %04x", i); break; - } - - LOG_DEBUG("%s", line); - - for (i = 0; i < length; i += LINE_LEN) { - switch (type) { - case DEBUG_TYPE_READ: - sprintf(line, "USB READ: %04x", i); - break; - case DEBUG_TYPE_WRITE: - sprintf(line, "USB WRITE: %04x", i); - break; - case DEBUG_TYPE_OCD_READ: - sprintf(line, "TO OpenOCD: %04x", i); - break; - case DEBUG_TYPE_BUFFER: - sprintf(line, "BUFFER: %04x", i); - break; } for (j = i; j < i + LINE_LEN && j < length; j++) { sprintf(s, " %02x", buffer[j]); strcat(line, s); } - LOG_DEBUG("%s", line); + LOG_DEBUG_USB("%s", line); } } -#endif - static int8_t openjtag_get_tap_state(int8_t state) { switch (state) { - case TAP_DREXIT2: return OPENJTAG_TAP_EXIT2_DR; - case TAP_DREXIT1: return OPENJTAG_TAP_EXIT1_DR; - case TAP_DRSHIFT: return OPENJTAG_TAP_SHIFT_DR; - case TAP_DRPAUSE: return OPENJTAG_TAP_PAUSE_DR; - case TAP_IRSELECT: return OPENJTAG_TAP_SELECT_IR; - case TAP_DRUPDATE: return OPENJTAG_TAP_UPDATE_DR; - case TAP_DRCAPTURE: return OPENJTAG_TAP_CAPTURE_DR; - case TAP_DRSELECT: return OPENJTAG_TAP_SELECT_DR; - case TAP_IREXIT2: return OPENJTAG_TAP_EXIT2_IR; - case TAP_IREXIT1: return OPENJTAG_TAP_EXIT1_IR; - case TAP_IRSHIFT: return OPENJTAG_TAP_SHIFT_IR; - case TAP_IRPAUSE: return OPENJTAG_TAP_PAUSE_IR; - case TAP_IDLE: return OPENJTAG_TAP_IDLE; - case TAP_IRUPDATE: return OPENJTAG_TAP_UPDATE_IR; - case TAP_IRCAPTURE: return OPENJTAG_TAP_CAPURE_IR; - case TAP_RESET: return OPENJTAG_TAP_RESET; - case TAP_INVALID: - default: return OPENJTAG_TAP_INVALID; + case TAP_DREXIT2: return OPENJTAG_TAP_EXIT2_DR; + case TAP_DREXIT1: return OPENJTAG_TAP_EXIT1_DR; + case TAP_DRSHIFT: return OPENJTAG_TAP_SHIFT_DR; + case TAP_DRPAUSE: return OPENJTAG_TAP_PAUSE_DR; + case TAP_IRSELECT: return OPENJTAG_TAP_SELECT_IR; + case TAP_DRUPDATE: return OPENJTAG_TAP_UPDATE_DR; + case TAP_DRCAPTURE: return OPENJTAG_TAP_CAPTURE_DR; + case TAP_DRSELECT: return OPENJTAG_TAP_SELECT_DR; + case TAP_IREXIT2: return OPENJTAG_TAP_EXIT2_IR; + case TAP_IREXIT1: return OPENJTAG_TAP_EXIT1_IR; + case TAP_IRSHIFT: return OPENJTAG_TAP_SHIFT_IR; + case TAP_IRPAUSE: return OPENJTAG_TAP_PAUSE_IR; + case TAP_IDLE: return OPENJTAG_TAP_IDLE; + case TAP_IRUPDATE: return OPENJTAG_TAP_UPDATE_IR; + case TAP_IRCAPTURE: return OPENJTAG_TAP_CAPURE_IR; + case TAP_RESET: return OPENJTAG_TAP_RESET; + case TAP_INVALID: + default: return OPENJTAG_TAP_INVALID; } } @@ -207,9 +205,8 @@ static int openjtag_buf_write_standard( uint8_t *buf, int size, uint32_t *bytes_written) { int retval; -#ifdef _DEBUG_USB_COMMS_ + openjtag_debug_buffer(buf, size, DEBUG_TYPE_WRITE); -#endif retval = ftdi_write_data(&ftdic, buf, size); if (retval < 0) { @@ -228,9 +225,7 @@ static int openjtag_buf_write_cy7c65215( { int ret; -#ifdef _DEBUG_USB_COMMS_ openjtag_debug_buffer(buf, size, DEBUG_TYPE_WRITE); -#endif if (size == 0) { *bytes_written = 0; @@ -287,9 +282,7 @@ static int openjtag_buf_read_standard( *bytes_read += retval; } -#ifdef _DEBUG_USB_COMMS_ openjtag_debug_buffer(buf, *bytes_read, DEBUG_TYPE_READ); -#endif return ERROR_OK; } @@ -320,9 +313,7 @@ static int openjtag_buf_read_cy7c65215( *bytes_read = ret; out: -#ifdef _DEBUG_USB_COMMS_ openjtag_debug_buffer(buf, *bytes_read, DEBUG_TYPE_READ); -#endif return ERROR_OK; } @@ -347,34 +338,34 @@ static int openjtag_speed(int speed) { int clockcmd; switch (speed) { - case 48000: - clockcmd = 0x00; - break; - case 24000: - clockcmd = 0x20; - break; - case 12000: - clockcmd = 0x40; - break; - case 6000: - clockcmd = 0x60; - break; - case 3000: - clockcmd = 0x80; - break; - case 1500: - clockcmd = 0xA0; - break; - case 750: - clockcmd = 0xC0; - break; - case 375: - clockcmd = 0xE0; - break; - default: - clockcmd = 0xE0; - LOG_WARNING("adapter speed not recognized, reverting to 375 kHz"); - break; + case 48000: + clockcmd = 0x00; + break; + case 24000: + clockcmd = 0x20; + break; + case 12000: + clockcmd = 0x40; + break; + case 6000: + clockcmd = 0x60; + break; + case 3000: + clockcmd = 0x80; + break; + case 1500: + clockcmd = 0xA0; + break; + case 750: + clockcmd = 0xC0; + break; + case 375: + clockcmd = 0xE0; + break; + default: + clockcmd = 0xE0; + LOG_WARNING("adapter speed not recognized, reverting to 375 kHz"); + break; } openjtag_sendcommand(clockcmd); @@ -385,20 +376,32 @@ static int openjtag_init_standard(void) { uint8_t latency_timer; + const char *usb_product_name = adapter_usb_get_product_name(); + /* Open by device description */ - if (!openjtag_device_desc) { - LOG_WARNING("no openjtag device description specified, " + if (!usb_product_name) { + LOG_WARNING("no openjtag USB product name specified, " "using default 'Open JTAG Project'"); - openjtag_device_desc = "Open JTAG Project"; + usb_product_name = "Open JTAG Project"; } if (ftdi_init(&ftdic) < 0) return ERROR_JTAG_INIT_FAILED; - /* context, vendor id, product id, description, serial id */ - if (ftdi_usb_open_desc(&ftdic, openjtag_vid, openjtag_pid, openjtag_device_desc, NULL) < 0) { - LOG_ERROR("unable to open ftdi device: %s", ftdic.error_str); - return ERROR_JTAG_INIT_FAILED; + const uint16_t *vids = openjtag_vids; + const uint16_t *pids = openjtag_pids; + + if (adapter_usb_get_vids()[0] != 0) { + vids = adapter_usb_get_vids(); + pids = adapter_usb_get_pids(); + } + + for (unsigned int i = 0; vids[i] != 0; i++) { + /* context, vendor id, product id, description, serial id */ + if (ftdi_usb_open_desc(&ftdic, vids[i], pids[i], usb_product_name, NULL) < 0) { + LOG_ERROR("unable to open ftdi device: %s", ftdic.error_str); + return ERROR_JTAG_INIT_FAILED; + } } if (ftdi_usb_reset(&ftdic) < 0) { @@ -585,10 +588,9 @@ static int openjtag_execute_tap_queue(void) count++; } -#ifdef _DEBUG_USB_COMMS_ openjtag_debug_buffer(buffer, DIV_ROUND_UP(openjtag_scan_result_buffer[res_count].bits, 8), DEBUG_TYPE_OCD_READ); -#endif + jtag_read_buffer(buffer, openjtag_scan_result_buffer[res_count].command); free(openjtag_scan_result_buffer[res_count].buffer); @@ -725,9 +727,8 @@ static void openjtag_execute_scan(struct jtag_command *cmd) tap_set_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); -#ifdef _DEBUG_USB_COMMS_ openjtag_debug_buffer(buffer, (scan_size + 7) / 8, DEBUG_TYPE_BUFFER); -#endif + /* set state */ old_state = tap_get_end_state(); openjtag_set_state(cmd->cmd.scan->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); @@ -849,16 +850,6 @@ static int openjtag_khz(int khz, int *jtag_speed) return ERROR_OK; } -COMMAND_HANDLER(openjtag_handle_device_desc_command) -{ - if (CMD_ARGC == 1) - openjtag_device_desc = strdup(CMD_ARGV[0]); - else - LOG_ERROR("require exactly one argument to " - "openjtag_device_desc "); - return ERROR_OK; -} - COMMAND_HANDLER(openjtag_handle_variant_command) { if (CMD_ARGC == 1) { @@ -878,25 +869,7 @@ COMMAND_HANDLER(openjtag_handle_variant_command) return ERROR_OK; } -COMMAND_HANDLER(openjtag_handle_vid_pid_command) -{ - if (CMD_ARGC != 2) - return ERROR_COMMAND_SYNTAX_ERROR; - - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], openjtag_vid); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], openjtag_pid); - - return ERROR_OK; -} - static const struct command_registration openjtag_subcommand_handlers[] = { - { - .name = "device_desc", - .handler = openjtag_handle_device_desc_command, - .mode = COMMAND_CONFIG, - .help = "set the USB device description of the OpenJTAG", - .usage = "description-string", - }, { .name = "variant", .handler = openjtag_handle_variant_command, @@ -904,13 +877,6 @@ static const struct command_registration openjtag_subcommand_handlers[] = { .help = "set the OpenJTAG variant", .usage = "variant-string", }, - { - .name = "vid_pid", - .handler = openjtag_handle_vid_pid_command, - .mode = COMMAND_CONFIG, - .help = "USB VID and PID of the adapter", - .usage = "vid pid", - }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index 143f3bde1f..794f8296e5 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -20,7 +20,7 @@ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #include -#define ioperm(startport, length, enable)\ +#define ioperm(startport, length, enable) \ i386_set_ioperm((startport), (length), (enable)) #endif /* __FreeBSD__ */ @@ -45,67 +45,17 @@ #include #endif -// Parallel port cable description. -struct cable { - const char *name; - // Status port bit containing current TDO value. - uint8_t tdo_mask; - // Data port bit for TRST. - uint8_t trst_mask; - // Data port bit for TMD. - uint8_t tms_mask; - // Data port bit for TCK. - uint8_t tck_mask; - // Data port bit for TDI. - uint8_t tdi_mask; - // Data port bit for SRST. - uint8_t srst_mask; - // Data port bits that should be inverted. - uint8_t output_invert; - // Status port that should be inverted. - uint8_t input_invert; - // Initialize data port with this value. - uint8_t port_init; - // De-initialize data port with this value. - uint8_t port_exit; - // Data port bit for LED. - uint8_t led_mask; -}; - -static const struct cable cables[] = { - /* name tdo trst tms tck tdi srst o_inv i_inv init exit led */ - { "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 }, - { "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 }, - { "wiggler_ntrst_inverted", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 }, - { "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 }, - { "arm-jtag", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 0x80, 0x80, 0x80, 0x00 }, - { "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, - { "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00 }, - { "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, - { "lattice", 0x40, 0x10, 0x04, 0x02, 0x01, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00 }, - { "flashlink", 0x20, 0x10, 0x02, 0x01, 0x04, 0x20, 0x30, 0x20, 0x00, 0x00, 0x00 }, -/* Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows: - HARD TCK - Target TCK - HARD TMS - Target TMS - HARD TDI - Target TDI - HARD TDO - Target TDO - SOFT TCK - Target TRST - SOFT TDI - Target SRST -*/ - { "altium", 0x10, 0x20, 0x04, 0x02, 0x01, 0x80, 0x00, 0x00, 0x10, 0x00, 0x08 }, - { "aspo", 0x10, 0x01, 0x04, 0x08, 0x02, 0x10, 0x17, 0x00, 0x17, 0x17, 0x00 }, - { NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } -}; +static const struct adapter_gpio_config *adapter_gpio_config; -// Configuration variables. -static char *parport_cable; +#if PARPORT_USE_PPDEV == 0 static uint16_t parport_port; -static bool parport_exit; +#endif +static bool parport_write_exit_state; +static char *parport_device_file; static uint32_t parport_toggling_time_ns = 1000; static int wait_states; // Interface variables. -static const struct cable *cable; static uint8_t dataport_value; #if PARPORT_USE_PPDEV == 1 @@ -115,6 +65,20 @@ static unsigned long dataport; static unsigned long statusport; #endif +// Bitmask map for the input pins. +static struct { + uint8_t mask; +} input_pin_bitmask_map[] = { + [10] = {0x40}, + [11] = {0x80}, + [12] = {0x20}, + [13] = {0x10}, + [15] = {0x08}, +}; + +// Generate an output pin bitmask for an adapter signal. +#define OUTPUT_BITMASK(gpio_index) BIT((adapter_gpio_config[(gpio_index)].gpio_num - 2)) + static enum bb_value parport_read(void) { int data = 0; @@ -125,16 +89,15 @@ static enum bb_value parport_read(void) data = inb(statusport); #endif - if ((data ^ cable->input_invert) & cable->tdo_mask) - return BB_HIGH; - else - return BB_LOW; + const struct adapter_gpio_config *gpio_config = &adapter_gpio_config[ADAPTER_GPIO_IDX_TDO]; + const bool tdo_state = data & input_pin_bitmask_map[gpio_config->gpio_num].mask; + + return (tdo_state ^ gpio_config->active_low) ? BB_HIGH : BB_LOW; } -static inline void parport_write_data(void) +static void parport_write_data(void) { - uint8_t output; - output = dataport_value ^ cable->output_invert; + const uint8_t output = dataport_value; #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPWDATA, &output); @@ -147,26 +110,27 @@ static inline void parport_write_data(void) #endif } -static int parport_write(int tck, int tms, int tdi) +static bool is_gpio_configured(enum adapter_gpio_config_index gpio_index) { - int i = wait_states + 1; - - if (tck) - dataport_value |= cable->tck_mask; - else - dataport_value &= ~cable->tck_mask; + return adapter_gpio_config[gpio_index].gpio_num != ADAPTER_GPIO_NOT_SET; +} - if (tms) - dataport_value |= cable->tms_mask; +static void set_pin_state(enum adapter_gpio_config_index gpio_index, + bool state) +{ + if (state ^ adapter_gpio_config[gpio_index].active_low) + dataport_value |= OUTPUT_BITMASK(gpio_index); else - dataport_value &= ~cable->tms_mask; + dataport_value &= ~OUTPUT_BITMASK(gpio_index); +} - if (tdi) - dataport_value |= cable->tdi_mask; - else - dataport_value &= ~cable->tdi_mask; +static int parport_write(int tck, int tms, int tdi) +{ + set_pin_state(ADAPTER_GPIO_IDX_TCK, tck == 1); + set_pin_state(ADAPTER_GPIO_IDX_TMS, tms == 1); + set_pin_state(ADAPTER_GPIO_IDX_TDI, tdi == 1); - while (i-- > 0) + for (int i = 0; i < wait_states + 1; i++) parport_write_data(); return ERROR_OK; @@ -177,15 +141,11 @@ static int parport_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); - if (trst == 0) - dataport_value |= cable->trst_mask; - else if (trst == 1) - dataport_value &= ~cable->trst_mask; + if (is_gpio_configured(ADAPTER_GPIO_IDX_TRST)) + set_pin_state(ADAPTER_GPIO_IDX_TRST, trst == 0); - if (srst == 0) - dataport_value |= cable->srst_mask; - else if (srst == 1) - dataport_value &= ~cable->srst_mask; + if (is_gpio_configured(ADAPTER_GPIO_IDX_SRST)) + set_pin_state(ADAPTER_GPIO_IDX_SRST, srst == 0); parport_write_data(); @@ -194,11 +154,10 @@ static int parport_reset(int trst, int srst) static int parport_led(bool on) { - if (on) - dataport_value |= cable->led_mask; - else - dataport_value &= ~cable->led_mask; + if (!is_gpio_configured(ADAPTER_GPIO_IDX_LED)) + return ERROR_OK; + set_pin_state(ADAPTER_GPIO_IDX_LED, on); parport_write_data(); return ERROR_OK; @@ -213,11 +172,12 @@ static int parport_speed(int speed) static int parport_khz(int khz, int *jtag_speed) { if (!khz) { - LOG_DEBUG("RCLK not supported"); + LOG_ERROR("RCLK is not supported by the adapter"); return ERROR_FAIL; } *jtag_speed = 499999 / (khz * parport_toggling_time_ns); + return ERROR_OK; } @@ -226,32 +186,35 @@ static int parport_speed_div(int speed, int *khz) uint32_t denominator = (speed + 1) * parport_toggling_time_ns; *khz = (499999 + denominator) / denominator; + return ERROR_OK; } #if PARPORT_USE_GIVEIO == 1 -static int parport_get_giveio_access(void) +static bool parport_get_giveio_access(void) { - HANDLE h; OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof(version); if (!GetVersionEx(&version)) { errno = EINVAL; - return -1; + return false; } + if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) - return 0; + return true; + + HANDLE h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); - h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { errno = ENODEV; - return -1; + return false; } CloseHandle(h); - return 0; + return true; } #endif @@ -261,105 +224,150 @@ static const struct bitbang_interface parport_bitbang = { .blink = &parport_led, }; +static const struct { + enum adapter_gpio_config_index gpio_index; + bool required; +} all_signals[] = { + { ADAPTER_GPIO_IDX_TDO, true }, + { ADAPTER_GPIO_IDX_TDI, true }, + { ADAPTER_GPIO_IDX_TMS, true }, + { ADAPTER_GPIO_IDX_TCK, true }, + { ADAPTER_GPIO_IDX_TRST, false }, + { ADAPTER_GPIO_IDX_SRST, false }, + { ADAPTER_GPIO_IDX_LED, false }, + { ADAPTER_GPIO_IDX_USER0, false }, +}; + static int parport_init(void) { - const struct cable *cur_cable; -#if PARPORT_USE_PPDEV == 1 - char buffer[256]; -#endif + adapter_gpio_config = adapter_gpio_get_config(); - cur_cable = cables; + // Check if all signals are configured properly. + for (size_t i = 0; i < ARRAY_SIZE(all_signals); i++) { + const enum adapter_gpio_config_index gpio_index = all_signals[i].gpio_index; + const struct adapter_gpio_config gpio = adapter_gpio_config[gpio_index]; - if (!parport_cable) { - parport_cable = strdup("wiggler"); - LOG_WARNING("No parport cable specified, using default 'wiggler'"); - } + if (gpio.gpio_num == ADAPTER_GPIO_NOT_SET) { + if (all_signals[i].required) { + LOG_ERROR("The signal '%s' is required and must be configured", + adapter_gpio_get_name(gpio_index)); + return ERROR_FAIL; + } - while (cur_cable->name) { - if (!strcmp(cur_cable->name, parport_cable)) { - cable = cur_cable; - break; + continue; } - cur_cable++; - } - if (!cable) { - LOG_ERROR("No matching cable found for %s", parport_cable); - return ERROR_JTAG_INIT_FAILED; + if (gpio_index == ADAPTER_GPIO_IDX_TDO) { + if (gpio.gpio_num < 10 || gpio.gpio_num > 15 || gpio.gpio_num == 14) { + LOG_ERROR("The '%s' signal pin must be 10, 11, 12, 13, or 15", + adapter_gpio_get_name(gpio_index)); + goto init_fail; + } + } else { + if (gpio.gpio_num < 2 || gpio.gpio_num > 9) { + LOG_ERROR("The '%s' signal pin must be 2, 3, 4, 5, 6, 7, 8, or 9", + adapter_gpio_get_name(gpio_index)); + goto init_fail; + } + } } - dataport_value = cable->port_init; + // Initialize signal pin states. + for (size_t i = 0; i < ARRAY_SIZE(all_signals); i++) { + const enum adapter_gpio_config_index gpio_index = all_signals[i].gpio_index; + const struct adapter_gpio_config gpio = adapter_gpio_config[gpio_index]; + + // The TDO (input) and LED (controlled by the adapter) pins cannot be + // initialized. + if (gpio_index == ADAPTER_GPIO_IDX_TDO || gpio_index == ADAPTER_GPIO_IDX_LED) + continue; + + // Do not initialize unconfigured GPIO pins. + if (gpio.gpio_num == ADAPTER_GPIO_NOT_SET) + continue; + + if (gpio.init_state == ADAPTER_GPIO_INIT_STATE_ACTIVE) + set_pin_state(gpio_index, true); + else if (gpio.init_state == ADAPTER_GPIO_INIT_STATE_INACTIVE) + set_pin_state(gpio_index, false); + } #if PARPORT_USE_PPDEV == 1 if (device_handle > 0) { - LOG_ERROR("device is already opened"); - return ERROR_JTAG_INIT_FAILED; + LOG_ERROR("Parallel port is already open"); + goto init_fail; } + if (!parport_device_file) { #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - LOG_DEBUG("opening /dev/ppi%d...", parport_port); + parport_device_file = strdup("/dev/ppi0"); +#else + parport_device_file = strdup("/dev/parport0"); +#endif + LOG_WARNING("No parallel port specified, using %s", parport_device_file); + LOG_WARNING("DEPRECATED! The lack of a parallel port specification is deprecated and will no longer work in the future"); + } - snprintf(buffer, 256, "/dev/ppi%d", parport_port); - device_handle = open(buffer, O_WRONLY); -#else /* not __FreeBSD__, __FreeBSD_kernel__ */ - LOG_DEBUG("opening /dev/parport%d...", parport_port); + LOG_DEBUG("Using parallel port %s", parport_device_file); - snprintf(buffer, 256, "/dev/parport%d", parport_port); - device_handle = open(buffer, O_WRONLY); -#endif /* __FreeBSD__, __FreeBSD_kernel__ */ + device_handle = open(parport_device_file, O_WRONLY); if (device_handle < 0) { int err = errno; - LOG_ERROR("cannot open device. check it exists and that user read and write rights are set. errno=%d", err); - return ERROR_JTAG_INIT_FAILED; + LOG_ERROR("Failed to open parallel port %s (errno = %d)", + parport_device_file, err); + LOG_ERROR("Check whether the device exists and if you have the required access rights"); + goto init_fail; } - LOG_DEBUG("...open"); - #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) - int i = ioctl(device_handle, PPCLAIM); + int retval = ioctl(device_handle, PPCLAIM); - if (i < 0) { - LOG_ERROR("cannot claim device"); - return ERROR_JTAG_INIT_FAILED; + if (retval < 0) { + LOG_ERROR("Failed to claim parallel port %s", parport_device_file); + goto init_fail; } - i = PARPORT_MODE_COMPAT; - i = ioctl(device_handle, PPSETMODE, &i); - if (i < 0) { - LOG_ERROR(" cannot set compatible mode to device"); - return ERROR_JTAG_INIT_FAILED; + int value = PARPORT_MODE_COMPAT; + retval = ioctl(device_handle, PPSETMODE, &value); + + if (retval < 0) { + LOG_ERROR("Cannot set compatible mode to device"); + goto init_fail; } - i = IEEE1284_MODE_COMPAT; - i = ioctl(device_handle, PPNEGOT, &i); - if (i < 0) { - LOG_ERROR("cannot set compatible 1284 mode to device"); - return ERROR_JTAG_INIT_FAILED; + value = IEEE1284_MODE_COMPAT; + retval = ioctl(device_handle, PPNEGOT, &value); + + if (retval < 0) { + LOG_ERROR("Cannot set compatible 1284 mode to device"); + goto init_fail; } #endif /* not __FreeBSD__, __FreeBSD_kernel__ */ #else /* not PARPORT_USE_PPDEV */ + LOG_WARNING("DEPRECATED: Parallel port access with direct I/O is deprecated and support will be removed in the next release"); + if (!parport_port) { parport_port = 0x378; - LOG_WARNING("No parport port specified, using default '0x378' (LPT1)"); + LOG_WARNING("No parallel port specified, using default 0x378 (LPT1)"); } + LOG_DEBUG("Using parallel port 0x%x", parport_port); + dataport = parport_port; statusport = parport_port + 1; - LOG_DEBUG("requesting privileges for parallel port 0x%lx...", dataport); #if PARPORT_USE_GIVEIO == 1 - if (parport_get_giveio_access() != 0) { + if (!parport_get_giveio_access()) { #else /* PARPORT_USE_GIVEIO */ if (ioperm(dataport, 3, 1) != 0) { #endif /* PARPORT_USE_GIVEIO */ - LOG_ERROR("missing privileges for direct i/o"); - return ERROR_JTAG_INIT_FAILED; + LOG_ERROR("Missing privileges for direct I/O"); + goto init_fail; } - LOG_DEBUG("...privileges granted"); - // Make sure parallel port is in right mode (clear tristate and interrupt. + // Make sure parallel port is in right mode (clear tristate and interrupt). #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(parport_port + 2, 0x0); #else @@ -369,110 +377,153 @@ static int parport_init(void) #endif /* PARPORT_USE_PPDEV */ if (parport_reset(0, 0) != ERROR_OK) - return ERROR_FAIL; + goto init_fail; + if (parport_write(0, 0, 0) != ERROR_OK) - return ERROR_FAIL; + goto init_fail; + if (parport_led(true) != ERROR_OK) - return ERROR_FAIL; + goto init_fail; bitbang_interface = &parport_bitbang; return ERROR_OK; + +init_fail: + free(parport_device_file); + return ERROR_JTAG_INIT_FAILED; } static int parport_quit(void) { - if (parport_led(false) != ERROR_OK) - return ERROR_FAIL; + free(parport_device_file); + + // Deinitialize signal pin states. + for (size_t i = 0; i < ARRAY_SIZE(all_signals); i++) { + const enum adapter_gpio_config_index gpio_index = all_signals[i].gpio_index; + const struct adapter_gpio_config gpio = adapter_gpio_config[gpio_index]; + + // The TDO (input) and LED (controlled by the adapter) pins cannot be + // deinitialized. + if (gpio_index == ADAPTER_GPIO_IDX_TDO || gpio_index == ADAPTER_GPIO_IDX_LED) + continue; + + // Do not deinitialize unconfigured GPIO pins. + if (gpio.gpio_num == ADAPTER_GPIO_NOT_SET) + continue; + + if (gpio.exit_state == ADAPTER_GPIO_EXIT_STATE_ACTIVE) + set_pin_state(gpio_index, true); + else if (gpio.exit_state == ADAPTER_GPIO_EXIT_STATE_INACTIVE) + set_pin_state(gpio_index, false); + } - if (parport_exit) { - dataport_value = cable->port_exit; + if (parport_write_exit_state) parport_write_data(); - } - free(parport_cable); - parport_cable = NULL; + if (parport_led(false) != ERROR_OK) + return ERROR_FAIL; return ERROR_OK; } COMMAND_HANDLER(parport_handle_port_command) { - if (CMD_ARGC == 1) { - // Only if the port wasn't overwritten by cmdline. - if (!parport_port) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port); - } else { - LOG_ERROR("The parport port was already configured!"); - return ERROR_FAIL; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + +#if PARPORT_USE_PPDEV == 1 + if (parport_device_file) { + LOG_ERROR("The parallel port device file is already configured"); + return ERROR_FAIL; } - command_print(CMD, "parport port = 0x%" PRIx16 "", parport_port); + char *tmp; - return ERROR_OK; -} + // We do not use the parse_xxx() or COMMAND_PARSE_xxx() functions here since + // they generate an error message if parsing fails. + char *endptr = NULL; + unsigned long port_number = strtoul(CMD_ARGV[0], &endptr, 0); -COMMAND_HANDLER(parport_handle_cable_command) -{ - if (!CMD_ARGC) - return ERROR_OK; + if (*endptr == '\0' && endptr != CMD_ARGV[0]) { + LOG_WARNING("DEPRECATED! Using a port number is deprecated, use the device file instead"); - // Only if the cable name wasn't overwritten by cmdline. - if (!parport_cable) { - // TODO: 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]); +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + tmp = alloc_printf("/dev/ppi%lu", port_number); +#else + tmp = alloc_printf("/dev/parport%lu", port_number); +#endif + } else { + tmp = strdup(CMD_ARGV[0]); + } + + if (!tmp) { + LOG_ERROR("Failed to allocate memory"); + return ERROR_FAIL; + } + + free(parport_device_file); + parport_device_file = tmp; +#else + if (parport_port > 0) { + command_print(CMD, "The parallel port is already configured"); + return ERROR_FAIL; } - // TODO: REVISIT it's probably worth returning the current value. + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port); +#endif return ERROR_OK; } +// This command is only for backward compatibility and will be removed in the +// future. +COMMAND_HANDLER(parport_handle_cable_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + return command_run_linef(CMD_CTX, "parport_select_cable %s", CMD_ARGV[0]); +} + COMMAND_HANDLER(parport_handle_write_on_exit_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_exit); + LOG_WARNING("DEPRECATED: 'parport write_on_exit' will be removed in the future, use the 'adapter gpio' command to configure the exit state for pins"); + + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_write_exit_state); return ERROR_OK; } COMMAND_HANDLER(parport_handle_toggling_time_command) { - if (CMD_ARGC == 1) { - uint32_t ns; - int retval = parse_u32(CMD_ARGV[0], &ns); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - if (retval != ERROR_OK) - return retval; + uint32_t toggling_time; - if (!ns) { - LOG_ERROR("0 ns is not a valid parport toggling time"); - return ERROR_FAIL; - } + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], toggling_time); - parport_toggling_time_ns = ns; - retval = adapter_get_speed(&wait_states); - if (retval != ERROR_OK) { - /* - * If adapter_get_speed fails then the clock_mode has - * not been configured, this happens if toggling_time is - * called before the adapter speed is set. - */ - LOG_INFO("no parport speed set - defaulting to zero wait states"); - wait_states = 0; - } + if (!toggling_time) { + command_print(CMD, "toggling time must not be 0 ns"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - command_print(CMD, "parport toggling time = %" PRIu32 " ns", - parport_toggling_time_ns); + parport_toggling_time_ns = toggling_time; + int retval = adapter_get_speed(&wait_states); + + if (retval != ERROR_OK) { + /* + * If adapter_get_speed fails then the clock_mode has not been + * configured, this happens if toggling_time is called before the + * adapter speed is set. + */ + LOG_INFO("No parallel port speed set, using zero wait states"); + wait_states = 0; + } return ERROR_OK; } @@ -482,35 +533,30 @@ static const struct command_registration parport_subcommand_handlers[] = { .name = "port", .handler = parport_handle_port_command, .mode = COMMAND_CONFIG, - .help = "Display the address of the I/O port (e.g. 0x378) " - "or the number of the '/dev/parport' device used. " - "If a parameter is provided, first change that port.", - .usage = "[port_number]", + .help = "Specify the device file of the parallel port", + .usage = "file", }, { .name = "cable", .handler = parport_handle_cable_command, .mode = COMMAND_CONFIG, .help = "Set the layout of the parallel port cable " - "used to connect to the target.", - // TODO: REVISIT there's no way to list layouts we know. - .usage = "[layout]", + "used to connect to the target", + .usage = "cable", }, { .name = "write_on_exit", .handler = parport_handle_write_on_exit_command, .mode = COMMAND_CONFIG, - .help = "Configure the parallel driver to write " - "a known value to the parallel interface on exit.", + .help = "Configure the driver to write a value to the parallel port on shutdown", .usage = "('on'|'off')", }, { .name = "toggling_time", .handler = parport_handle_toggling_time_command, .mode = COMMAND_CONFIG, - .help = "Displays or assigns how many nanoseconds it " - "takes for the hardware to toggle TCK.", - .usage = "[nanoseconds]", + .help = "Configure how many nanoseconds it takes for the hardware to toggle TCK", + .usage = "time", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/presto.c b/src/jtag/drivers/presto.c index 84b881cdc8..1519a6d986 100644 --- a/src/jtag/drivers/presto.c +++ b/src/jtag/drivers/presto.c @@ -94,9 +94,8 @@ static int presto_read(uint8_t *buf, uint32_t size) { uint32_t ftbytes = 0; - struct timeval timeout, now; - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 1, 0); /* one second timeout */ + // 1 second timeout + int64_t then = timeval_ms() + 1000; while (ftbytes < size) { presto->retval = ftdi_read_data(&presto->ftdic, buf + ftbytes, size - ftbytes); @@ -106,8 +105,7 @@ static int presto_read(uint8_t *buf, uint32_t size) } ftbytes += presto->retval; - gettimeofday(&now, NULL); - if (timeval_compare(&now, &timeout) > 0) + if (timeval_ms() > then) break; } @@ -451,7 +449,7 @@ static struct bitq_interface presto_bitq = { static int presto_adapter_khz(int khz, int *jtag_speed) { - if (khz < 0) { + if (khz <= 0) { *jtag_speed = 0; return ERROR_COMMAND_SYNTAX_ERROR; } diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index 449c616545..f3a1073125 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -21,9 +21,6 @@ #include #include "bitbang.h" -/* arbitrary limit on host name length: */ -#define REMOTE_BITBANG_HOST_MAX 255 - static char *remote_bitbang_host; static char *remote_bitbang_port; @@ -179,14 +176,14 @@ static int remote_bitbang_quit(void) static enum bb_value char_to_int(int c) { switch (c) { - case '0': - return BB_LOW; - case '1': - return BB_HIGH; - default: - remote_bitbang_quit(); - LOG_ERROR("remote_bitbang: invalid read response: %c(%i)", c, c); - return BB_ERROR; + case '0': + return BB_LOW; + case '1': + return BB_HIGH; + default: + remote_bitbang_quit(); + LOG_ERROR("remote_bitbang: invalid read response: %c(%i)", c, c); + return BB_ERROR; } } diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index a818996255..3be786d7bc 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -321,67 +321,53 @@ static int dtc_load_from_buffer(struct libusb_device_handle *hdev_param, const u } switch (header->type) { - case DTCLOAD_COMMENT: - break; - - case DTCLOAD_ENTRY: - /* store entry addresses somewhere */ - if (!strncmp("download", (char *)buffer + 1, 8)) - dtc_entry_download = buffer[0]; - break; - - case DTCLOAD_LOAD: - /* Send the DTC program to ST7 RAM. */ - usb_err = ep1_memory_write( - hdev_param, - DTC_LOAD_BUFFER, - header->length + 1, buffer - ); - if (usb_err < 0) - return usb_err; - - /* Load it into the DTC. */ - usb_err = ep1_generic_commandl( - hdev_param, 3, - EP1_CMD_DTC_LOAD, - (DTC_LOAD_BUFFER >> 8), - DTC_LOAD_BUFFER - ); - if (usb_err < 0) - return usb_err; - - break; - - case DTCLOAD_RUN: - usb_err = ep1_generic_commandl( - hdev_param, 3, - EP1_CMD_DTC_CALL, - buffer[0], - EP1_CMD_DTC_WAIT - ); - if (usb_err < 0) - return usb_err; - - break; - - case DTCLOAD_LUT_START: - lut_start = buffer[0]; - break; - - case DTCLOAD_LUT: - usb_err = ep1_memory_write( - hdev_param, - ST7_USB_BUF_EP0OUT + lut_start, - header->length + 1, buffer - ); - if (usb_err < 0) - return usb_err; - break; - - default: - LOG_ERROR("Invalid DTC image record type: 0x%02x", header->type); - exit(1); - break; + case DTCLOAD_COMMENT: + break; + + case DTCLOAD_ENTRY: + /* store entry addresses somewhere */ + if (!strncmp("download", (char *)buffer + 1, 8)) + dtc_entry_download = buffer[0]; + break; + + case DTCLOAD_LOAD: + /* Send the DTC program to ST7 RAM. */ + usb_err = ep1_memory_write(hdev_param, DTC_LOAD_BUFFER, + header->length + 1, buffer); + if (usb_err < 0) + return usb_err; + + /* Load it into the DTC. */ + usb_err = ep1_generic_commandl(hdev_param, 3, EP1_CMD_DTC_LOAD, + (DTC_LOAD_BUFFER >> 8), DTC_LOAD_BUFFER); + if (usb_err < 0) + return usb_err; + + break; + + case DTCLOAD_RUN: + usb_err = ep1_generic_commandl(hdev_param, 3, EP1_CMD_DTC_CALL, + buffer[0], EP1_CMD_DTC_WAIT); + if (usb_err < 0) + return usb_err; + + break; + + case DTCLOAD_LUT_START: + lut_start = buffer[0]; + break; + + case DTCLOAD_LUT: + usb_err = ep1_memory_write(hdev_param, + ST7_USB_BUF_EP0OUT + lut_start, header->length + 1, buffer); + if (usb_err < 0) + return usb_err; + break; + + default: + LOG_ERROR("Invalid DTC image record type: 0x%02x", header->type); + exit(1); + break; } buffer += (header->length + 1); @@ -446,14 +432,8 @@ static int dtc_start_download(void) return usb_err; /* wait for completion */ - usb_err = jtag_libusb_bulk_read( - hdev, USB_EP1IN_ADDR, - (char *)&ep2txr, 1, - LIBUSB_TIMEOUT_MS, - &transferred - ); - - return usb_err; + return jtag_libusb_bulk_read(hdev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, + LIBUSB_TIMEOUT_MS, &transferred); } static int dtc_run_download( @@ -821,8 +801,7 @@ static int tap_state_queue_run(void) tap_state_queue.buffer >>= 1; } - retval = tap_state_queue_init(); - return retval; + return tap_state_queue_init(); } static int tap_state_queue_append(uint8_t tms) @@ -1147,15 +1126,15 @@ static int rlink_scan(struct jtag_command *cmd, enum scan_type type, chunk_bytes = chunk_bits / 8; switch (type) { - case SCAN_IN: - x = DTC_CMD_SHIFT_TDO_BYTES(chunk_bytes); - break; - case SCAN_OUT: - x = DTC_CMD_SHIFT_TDI_BYTES(chunk_bytes); - break; - default: - x = DTC_CMD_SHIFT_TDIO_BYTES(chunk_bytes); - break; + case SCAN_IN: + x = DTC_CMD_SHIFT_TDO_BYTES(chunk_bytes); + break; + case SCAN_OUT: + x = DTC_CMD_SHIFT_TDI_BYTES(chunk_bytes); + break; + default: + x = DTC_CMD_SHIFT_TDIO_BYTES(chunk_bytes); + break; } dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; @@ -1281,69 +1260,69 @@ static int rlink_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RUNTEST: - case JTAG_TLR_RESET: - case JTAG_PATHMOVE: - case JTAG_SCAN: - break; - - default: - /* some events, such as resets, need a queue flush to ensure - *consistency */ - tap_state_queue_run(); - dtc_queue_run(); - break; + case JTAG_RUNTEST: + case JTAG_TLR_RESET: + case JTAG_PATHMOVE: + case JTAG_SCAN: + break; + + default: + /* some events, such as resets, need a queue flush to ensure + *consistency */ + tap_state_queue_run(); + dtc_queue_run(); + break; } switch (cmd->type) { - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - if ((cmd->cmd.reset->trst == 1) || - (cmd->cmd.reset->srst && - (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) - tap_set_state(TAP_RESET); - rlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %i", - cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); - if (cmd->cmd.runtest->end_state != -1) - rlink_end_state(cmd->cmd.runtest->end_state); - rlink_runtest(cmd->cmd.runtest->num_cycles); - break; - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - if (cmd->cmd.statemove->end_state != -1) - rlink_end_state(cmd->cmd.statemove->end_state); - rlink_state_move(); - break; - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %u states, end in %i", - cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - rlink_path_move(cmd->cmd.pathmove); - break; - case JTAG_SCAN: - LOG_DEBUG_IO("%s scan end in %i", - (cmd->cmd.scan->ir_scan) ? "IR" : "DR", - cmd->cmd.scan->end_state); - if (cmd->cmd.scan->end_state != -1) - rlink_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - type = jtag_scan_type(cmd->cmd.scan); - if (rlink_scan(cmd, type, buffer, scan_size) != ERROR_OK) - retval = ERROR_FAIL; - break; - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - jtag_sleep(cmd->cmd.sleep->us); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", + cmd->cmd.reset->trst, + cmd->cmd.reset->srst); + if (cmd->cmd.reset->trst == 1 || + (cmd->cmd.reset->srst && + (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) + tap_set_state(TAP_RESET); + rlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %i cycles, end in %i", + cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + if (cmd->cmd.runtest->end_state != -1) + rlink_end_state(cmd->cmd.runtest->end_state); + rlink_runtest(cmd->cmd.runtest->num_cycles); + break; + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + if (cmd->cmd.statemove->end_state != -1) + rlink_end_state(cmd->cmd.statemove->end_state); + rlink_state_move(); + break; + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %u states, end in %i", + cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + rlink_path_move(cmd->cmd.pathmove); + break; + case JTAG_SCAN: + LOG_DEBUG_IO("%s scan end in %i", + (cmd->cmd.scan->ir_scan) ? "IR" : "DR", + cmd->cmd.scan->end_state); + if (cmd->cmd.scan->end_state != -1) + rlink_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + if (rlink_scan(cmd, type, buffer, scan_size) != ERROR_OK) + retval = ERROR_FAIL; + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + jtag_sleep(cmd->cmd.sleep->us); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 5ee1f85261..358765463a 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -608,28 +608,28 @@ static int transfer_error_status(const struct libusb_transfer *transfer) int r = 0; switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - r = 0; - break; - case LIBUSB_TRANSFER_TIMED_OUT: - r = LIBUSB_ERROR_TIMEOUT; - break; - case LIBUSB_TRANSFER_STALL: - r = LIBUSB_ERROR_PIPE; - break; - case LIBUSB_TRANSFER_OVERFLOW: - r = LIBUSB_ERROR_OVERFLOW; - break; - case LIBUSB_TRANSFER_NO_DEVICE: - r = LIBUSB_ERROR_NO_DEVICE; - break; - case LIBUSB_TRANSFER_ERROR: - case LIBUSB_TRANSFER_CANCELLED: - r = LIBUSB_ERROR_IO; - break; - default: - r = LIBUSB_ERROR_OTHER; - break; + case LIBUSB_TRANSFER_COMPLETED: + r = 0; + break; + case LIBUSB_TRANSFER_TIMED_OUT: + r = LIBUSB_ERROR_TIMEOUT; + break; + case LIBUSB_TRANSFER_STALL: + r = LIBUSB_ERROR_PIPE; + break; + case LIBUSB_TRANSFER_OVERFLOW: + r = LIBUSB_ERROR_OVERFLOW; + break; + case LIBUSB_TRANSFER_NO_DEVICE: + r = LIBUSB_ERROR_NO_DEVICE; + break; + case LIBUSB_TRANSFER_ERROR: + case LIBUSB_TRANSFER_CANCELLED: + r = LIBUSB_ERROR_IO; + break; + default: + r = LIBUSB_ERROR_OTHER; + break; } return r; @@ -1058,13 +1058,13 @@ static int stlink_usb_error_check(void *handle) if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { switch (h->databuf[0]) { - case STLINK_SWIM_ERR_OK: - return ERROR_OK; - case STLINK_SWIM_BUSY: - return ERROR_WAIT; - default: - LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]); - return ERROR_FAIL; + case STLINK_SWIM_ERR_OK: + return ERROR_OK; + case STLINK_SWIM_BUSY: + return ERROR_WAIT; + default: + LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]); + return ERROR_FAIL; } } @@ -1073,64 +1073,64 @@ static int stlink_usb_error_check(void *handle) h->databuf[0] = STLINK_DEBUG_ERR_OK; switch (h->databuf[0]) { - case STLINK_DEBUG_ERR_OK: - return ERROR_OK; - case STLINK_DEBUG_ERR_FAULT: - LOG_DEBUG("SWD fault response (0x%x)", STLINK_DEBUG_ERR_FAULT); - return ERROR_FAIL; - case STLINK_SWD_AP_WAIT: - LOG_DEBUG("wait status SWD_AP_WAIT (0x%x)", STLINK_SWD_AP_WAIT); - return ERROR_WAIT; - case STLINK_SWD_DP_WAIT: - LOG_DEBUG("wait status SWD_DP_WAIT (0x%x)", STLINK_SWD_DP_WAIT); - return ERROR_WAIT; - case STLINK_JTAG_GET_IDCODE_ERROR: - LOG_DEBUG("STLINK_JTAG_GET_IDCODE_ERROR"); - return ERROR_FAIL; - case STLINK_JTAG_WRITE_ERROR: - LOG_DEBUG("Write error"); - return ERROR_FAIL; - case STLINK_JTAG_WRITE_VERIF_ERROR: - LOG_DEBUG("Write verify error, ignoring"); - return ERROR_OK; - case STLINK_SWD_AP_FAULT: - /* git://git.ac6.fr/openocd commit 657e3e885b9ee10 - * returns ERROR_OK with the comment: - * Change in error status when reading outside RAM. - * This fix allows CDT plugin to visualize memory. - */ - LOG_DEBUG("STLINK_SWD_AP_FAULT"); - return ERROR_FAIL; - case STLINK_SWD_AP_ERROR: - LOG_DEBUG("STLINK_SWD_AP_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_AP_PARITY_ERROR: - LOG_DEBUG("STLINK_SWD_AP_PARITY_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_DP_FAULT: - LOG_DEBUG("STLINK_SWD_DP_FAULT"); - return ERROR_FAIL; - case STLINK_SWD_DP_ERROR: - LOG_DEBUG("STLINK_SWD_DP_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_DP_PARITY_ERROR: - LOG_DEBUG("STLINK_SWD_DP_PARITY_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_AP_WDATA_ERROR: - LOG_DEBUG("STLINK_SWD_AP_WDATA_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_AP_STICKY_ERROR: - LOG_DEBUG("STLINK_SWD_AP_STICKY_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_AP_STICKYORUN_ERROR: - LOG_DEBUG("STLINK_SWD_AP_STICKYORUN_ERROR"); - return ERROR_FAIL; - case STLINK_BAD_AP_ERROR: - LOG_DEBUG("STLINK_BAD_AP_ERROR"); - return ERROR_FAIL; - default: - LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]); - return ERROR_FAIL; + case STLINK_DEBUG_ERR_OK: + return ERROR_OK; + case STLINK_DEBUG_ERR_FAULT: + LOG_DEBUG("SWD fault response (0x%x)", STLINK_DEBUG_ERR_FAULT); + return ERROR_FAIL; + case STLINK_SWD_AP_WAIT: + LOG_DEBUG("wait status SWD_AP_WAIT (0x%x)", STLINK_SWD_AP_WAIT); + return ERROR_WAIT; + case STLINK_SWD_DP_WAIT: + LOG_DEBUG("wait status SWD_DP_WAIT (0x%x)", STLINK_SWD_DP_WAIT); + return ERROR_WAIT; + case STLINK_JTAG_GET_IDCODE_ERROR: + LOG_DEBUG("STLINK_JTAG_GET_IDCODE_ERROR"); + return ERROR_FAIL; + case STLINK_JTAG_WRITE_ERROR: + LOG_DEBUG("Write error"); + return ERROR_FAIL; + case STLINK_JTAG_WRITE_VERIF_ERROR: + LOG_DEBUG("Write verify error, ignoring"); + return ERROR_OK; + case STLINK_SWD_AP_FAULT: + /* git://git.ac6.fr/openocd commit 657e3e885b9ee10 + * returns ERROR_OK with the comment: + * Change in error status when reading outside RAM. + * This fix allows CDT plugin to visualize memory. + */ + LOG_DEBUG("STLINK_SWD_AP_FAULT"); + return ERROR_FAIL; + case STLINK_SWD_AP_ERROR: + LOG_DEBUG("STLINK_SWD_AP_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_AP_PARITY_ERROR: + LOG_DEBUG("STLINK_SWD_AP_PARITY_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_DP_FAULT: + LOG_DEBUG("STLINK_SWD_DP_FAULT"); + return ERROR_FAIL; + case STLINK_SWD_DP_ERROR: + LOG_DEBUG("STLINK_SWD_DP_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_DP_PARITY_ERROR: + LOG_DEBUG("STLINK_SWD_DP_PARITY_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_AP_WDATA_ERROR: + LOG_DEBUG("STLINK_SWD_AP_WDATA_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_AP_STICKY_ERROR: + LOG_DEBUG("STLINK_SWD_AP_STICKY_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_AP_STICKYORUN_ERROR: + LOG_DEBUG("STLINK_SWD_AP_STICKYORUN_ERROR"); + return ERROR_FAIL; + case STLINK_BAD_AP_ERROR: + LOG_DEBUG("STLINK_BAD_AP_ERROR"); + return ERROR_FAIL; + default: + LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]); + return ERROR_FAIL; } } @@ -1597,31 +1597,31 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type) stlink_usb_init_buffer(handle, h->rx_ep, rx_size); switch (type) { - case STLINK_MODE_DEBUG_JTAG: - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; - if (h->version.jtag_api == STLINK_JTAG_API_V1) - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; - else - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_JTAG_NO_RESET; - break; - case STLINK_MODE_DEBUG_SWD: - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; - if (h->version.jtag_api == STLINK_JTAG_API_V1) - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; - else - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_SWD_NO_RESET; - break; - case STLINK_MODE_DEBUG_SWIM: - h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; - h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER; - /* swim enter does not return any response or status */ - return stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); - case STLINK_MODE_DFU: - case STLINK_MODE_MASS: - default: - return ERROR_FAIL; + case STLINK_MODE_DEBUG_JTAG: + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + if (h->version.jtag_api == STLINK_JTAG_API_V1) + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; + else + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_JTAG_NO_RESET; + break; + case STLINK_MODE_DEBUG_SWD: + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + if (h->version.jtag_api == STLINK_JTAG_API_V1) + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; + else + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_SWD_NO_RESET; + break; + case STLINK_MODE_DEBUG_SWIM: + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER; + /* swim enter does not return any response or status */ + return stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); + case STLINK_MODE_DFU: + case STLINK_MODE_MASS: + default: + return ERROR_FAIL; } return stlink_cmd_allow_retry(handle, h->databuf, rx_size); @@ -1639,22 +1639,22 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type) stlink_usb_init_buffer(handle, h->rx_ep, 0); switch (type) { - case STLINK_MODE_DEBUG_JTAG: - case STLINK_MODE_DEBUG_SWD: - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_EXIT; - break; - case STLINK_MODE_DEBUG_SWIM: - h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; - h->cmdbuf[h->cmdidx++] = STLINK_SWIM_EXIT; - break; - case STLINK_MODE_DFU: - h->cmdbuf[h->cmdidx++] = STLINK_DFU_COMMAND; - h->cmdbuf[h->cmdidx++] = STLINK_DFU_EXIT; - break; - case STLINK_MODE_MASS: - default: - return ERROR_FAIL; + case STLINK_MODE_DEBUG_JTAG: + case STLINK_MODE_DEBUG_SWD: + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_EXIT; + break; + case STLINK_MODE_DEBUG_SWIM: + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_EXIT; + break; + case STLINK_MODE_DFU: + h->cmdbuf[h->cmdidx++] = STLINK_DFU_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DFU_EXIT; + break; + case STLINK_MODE_MASS: + default: + return ERROR_FAIL; } res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); @@ -1697,20 +1697,20 @@ static int stlink_usb_exit_mode(void *handle) /* try to exit current mode */ switch (mode) { - case STLINK_DEV_DFU_MODE: - emode = STLINK_MODE_DFU; - break; - case STLINK_DEV_DEBUG_MODE: - emode = STLINK_MODE_DEBUG_SWD; - break; - case STLINK_DEV_SWIM_MODE: - emode = STLINK_MODE_DEBUG_SWIM; - break; - case STLINK_DEV_BOOTLOADER_MODE: - case STLINK_DEV_MASS_MODE: - default: - emode = STLINK_MODE_UNKNOWN; - break; + case STLINK_DEV_DFU_MODE: + emode = STLINK_MODE_DFU; + break; + case STLINK_DEV_DEBUG_MODE: + emode = STLINK_MODE_DEBUG_SWD; + break; + case STLINK_DEV_SWIM_MODE: + emode = STLINK_MODE_DEBUG_SWIM; + break; + case STLINK_DEV_BOOTLOADER_MODE: + case STLINK_DEV_MASS_MODE: + default: + emode = STLINK_MODE_UNKNOWN; + break; } if (emode != STLINK_MODE_UNKNOWN) @@ -2303,16 +2303,13 @@ static int stlink_usb_reset(void *handle) /** */ static int stlink_usb_run(void *handle) { - int res; struct stlink_usb_handle *h = handle; assert(handle); - if (h->version.jtag_api != STLINK_JTAG_API_V1) { - res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN); - - return res; - } + if (h->version.jtag_api != STLINK_JTAG_API_V1) + return stlink_usb_write_debug_reg(handle, DCB_DHCSR, + DBGKEY | C_DEBUGEN); stlink_usb_init_buffer(handle, h->rx_ep, 2); @@ -2325,16 +2322,13 @@ static int stlink_usb_run(void *handle) /** */ static int stlink_usb_halt(void *handle) { - int res; struct stlink_usb_handle *h = handle; 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); - - return res; - } + if (h->version.jtag_api != STLINK_JTAG_API_V1) + return stlink_usb_write_debug_reg(handle, DCB_DHCSR, + DBGKEY | C_HALT | C_DEBUGEN); stlink_usb_init_buffer(handle, h->rx_ep, 2); @@ -3406,7 +3400,7 @@ static int stlink_usb_usb_open(void *handle, struct hl_interface_param *param) in order to become operational. */ do { - if (jtag_libusb_open(param->vid, param->pid, NULL, + if (jtag_libusb_open(adapter_usb_get_vids(), adapter_usb_get_pids(), NULL, &h->usb_backend_priv.fd, stlink_usb_get_alternate_serial) != ERROR_OK) { LOG_ERROR("open failed"); return ERROR_FAIL; @@ -3430,34 +3424,34 @@ static int stlink_usb_usb_open(void *handle, struct hl_interface_param *param) /* wrap version for first read */ switch (pid) { - case STLINK_V1_PID: - h->version.stlink = 1; - h->tx_ep = STLINK_TX_EP; - break; - case STLINK_V3_USBLOADER_PID: - 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; - break; - case STLINK_V2_1_PID: - case STLINK_V2_1_NO_MSD_PID: - h->version.stlink = 2; - h->tx_ep = STLINK_V2_1_TX_EP; - h->trace_ep = STLINK_V2_1_TRACE_EP; - break; - default: - /* fall through - we assume V2 to be the default version*/ - case STLINK_V2_PID: - h->version.stlink = 2; - h->tx_ep = STLINK_TX_EP; - h->trace_ep = STLINK_TRACE_EP; - break; + case STLINK_V1_PID: + h->version.stlink = 1; + h->tx_ep = STLINK_TX_EP; + break; + case STLINK_V3_USBLOADER_PID: + 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; + break; + case STLINK_V2_1_PID: + case STLINK_V2_1_NO_MSD_PID: + h->version.stlink = 2; + h->tx_ep = STLINK_V2_1_TX_EP; + h->trace_ep = STLINK_V2_1_TRACE_EP; + break; + default: + /* fall through - we assume V2 to be the default version */ + case STLINK_V2_PID: + h->version.stlink = 2; + h->tx_ep = STLINK_TX_EP; + h->trace_ep = STLINK_TRACE_EP; + break; } /* get the device version */ @@ -3642,8 +3636,9 @@ static int stlink_tcp_open(void *handle, struct hl_interface_param *param) 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) { + for (unsigned int i = 0; adapter_usb_get_vids()[i]; i++) { + if (h->vid == adapter_usb_get_vids()[i] && + h->pid == adapter_usb_get_pids()[i]) { stlink_id_matched = true; break; } @@ -3740,9 +3735,9 @@ static int stlink_open(struct hl_interface_param *param, enum stlink_mode mode, h->st_mode = mode; - for (unsigned int i = 0; param->vid[i]; i++) { + for (unsigned int i = 0; adapter_usb_get_vids()[i]; i++) { LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", - h->st_mode, param->vid[i], param->pid[i], + h->st_mode, adapter_usb_get_vids()[i], adapter_usb_get_pids()[i], adapter_get_required_serial() ? adapter_get_required_serial() : ""); } @@ -3758,21 +3753,21 @@ static int stlink_open(struct hl_interface_param *param, enum stlink_mode mode, int err = ERROR_OK; switch (h->st_mode) { - case STLINK_MODE_DEBUG_SWD: - if (h->version.jtag_api == STLINK_JTAG_API_V1) - err = ERROR_FAIL; - /* fall-through */ - case STLINK_MODE_DEBUG_JTAG: - if (h->version.jtag == 0) - err = ERROR_FAIL; - break; - case STLINK_MODE_DEBUG_SWIM: - if (h->version.swim == 0) - err = ERROR_FAIL; - break; - default: + case STLINK_MODE_DEBUG_SWD: + if (h->version.jtag_api == STLINK_JTAG_API_V1) err = ERROR_FAIL; - break; + /* fall-through */ + case STLINK_MODE_DEBUG_JTAG: + if (h->version.jtag == 0) + err = ERROR_FAIL; + break; + case STLINK_MODE_DEBUG_SWIM: + if (h->version.swim == 0) + err = ERROR_FAIL; + break; + default: + err = ERROR_FAIL; + break; } if (err != ERROR_OK) { @@ -4194,7 +4189,7 @@ static int stlink_dap_op_connect(struct adiv5_dap *dap) uint32_t idcode; int retval; - LOG_INFO("stlink_dap_op_connect(%sconnect)", dap->do_reconnect ? "re" : ""); + LOG_DEBUG("%s(%sconnect)", __func__, dap->do_reconnect ? "re" : ""); /* Check if we should reset srst already when connecting, but not if reconnecting. */ if (!dap->do_reconnect) { @@ -4284,8 +4279,6 @@ static int stlink_dap_dp_read(struct adiv5_dap *dap, unsigned int reg, uint32_t /** */ static int stlink_dap_dp_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data) { - int retval; - if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL)) if (reg & 0x000000F0) { LOG_ERROR("Banked DP registers not supported in current STLink FW"); @@ -4302,9 +4295,8 @@ static int stlink_dap_dp_write(struct adiv5_dap *dap, unsigned int reg, uint32_t if (reg == DP_CTRL_STAT) data &= ~CORUNDETECT; - retval = stlink_write_dap_register(stlink_dap_handle, + return stlink_write_dap_register(stlink_dap_handle, STLINK_DEBUG_PORT_ACCESS, reg, data); - return retval; } /** */ @@ -4984,31 +4976,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_vid_pid) -{ - unsigned int i, max_usb_ids = HLA_MAX_USB_IDS; - - if (CMD_ARGC > max_usb_ids * 2) { - LOG_WARNING("ignoring extra IDs in 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 vid_pid configuration directive"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - for (i = 0; i < CMD_ARGC; i += 2) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], stlink_dap_param.vid[i / 2]); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], stlink_dap_param.pid[i / 2]); - } - - /* null termination */ - stlink_dap_param.vid[i / 2] = stlink_dap_param.pid[i / 2] = 0; - - return ERROR_OK; -} - /** */ COMMAND_HANDLER(stlink_dap_backend_command) { @@ -5074,13 +5041,6 @@ COMMAND_HANDLER(stlink_dap_cmd_command) /** */ static const struct command_registration stlink_dap_subcommand_handlers[] = { - { - .name = "vid_pid", - .handler = stlink_dap_vid_pid, - .mode = COMMAND_CONFIG, - .help = "USB VID and PID of the adapter", - .usage = "(vid pid)+", - }, { .name = "backend", .handler = &stlink_dap_backend_command, diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c index 279b35377c..902459c7d1 100644 --- a/src/jtag/drivers/sysfsgpio.c +++ b/src/jtag/drivers/sysfsgpio.c @@ -101,7 +101,6 @@ static void unexport_sysfs_gpio(int gpio) */ static int setup_sysfs_gpio(int gpio, int is_output, int init_high) { - struct timeval timeout, now; char buf[40]; char gpiostr[5]; int ret; @@ -121,16 +120,15 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high) } } - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 0, 500000); + // 500 ms timeout + int64_t then = timeval_ms() + 500; snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio); for (;;) { ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in"); if (ret >= 0 || errno != EACCES) break; - gettimeofday(&now, NULL); - if (timeval_compare(&now, &timeout) >= 0) + if (timeval_ms() >= then) break; jtag_sleep(10000); } @@ -146,8 +144,7 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high) ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC); if (ret >= 0 || errno != EACCES) break; - gettimeofday(&now, NULL); - if (timeval_compare(&now, &timeout) >= 0) + if (timeval_ms() >= then) break; jtag_sleep(10000); } diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index 0e01171ea9..cd740b296d 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -126,17 +126,17 @@ static int icdi_send_packet(void *handle, int len) len += sprintf(&h->write_buffer[len], PACKET_END "%02x", cksum); -#ifdef _DEBUG_USB_COMMS_ - char buffer[50]; - char ch = h->write_buffer[1]; - if (ch == 'x' || ch == 'X') - LOG_DEBUG("writing packet: "); - else { - memcpy(buffer, h->write_buffer, len >= 50 ? 50-1 : len); - buffer[len] = 0; - LOG_DEBUG("writing packet: %s", buffer); + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_USB)) { + char buffer[50]; + char ch = h->write_buffer[1]; + if (ch == 'x' || ch == 'X') { + LOG_DEBUG_USB("writing packet: "); + } else { + memcpy(buffer, h->write_buffer, len >= 50 ? 50 - 1 : len); + buffer[len] = 0; + LOG_DEBUG_USB("writing packet: %s", buffer); + } } -#endif while (1) { @@ -155,9 +155,7 @@ static int icdi_send_packet(void *handle, int len) return ERROR_FAIL; } -#ifdef _DEBUG_USB_COMMS_ - LOG_DEBUG("received reply: '%c' : count %d", h->read_buffer[0], transferred); -#endif + LOG_DEBUG_USB("received reply: '%c' : count %d", h->read_buffer[0], transferred); if (h->read_buffer[0] == '-') { LOG_DEBUG("Resending packet %d", ++retry); @@ -182,9 +180,7 @@ static int icdi_send_packet(void *handle, int len) result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer + h->read_count, h->max_packet - h->read_count, &transferred, ICDI_READ_TIMEOUT); -#ifdef _DEBUG_USB_COMMS_ - LOG_DEBUG("received data: count %d", transferred); -#endif + LOG_DEBUG_USB("received data: count %d", transferred); /* check for errors but retry for timeout */ if (result != 0) { @@ -669,13 +665,14 @@ static int icdi_usb_open(struct hl_interface_param *param, void **fd) return ERROR_FAIL; } - 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() : ""); + for (unsigned int i = 0; adapter_usb_get_vids()[i]; ++i) + LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", + param->transport, adapter_usb_get_vids()[i], adapter_usb_get_pids()[i], + adapter_get_required_serial() ? adapter_get_required_serial() : ""); /* 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); + jtag_libusb_open(adapter_usb_get_vids(), adapter_usb_get_pids(), NULL, &h->usb_dev, NULL); if (!h->usb_dev) { LOG_ERROR("open failed"); @@ -692,14 +689,14 @@ static int icdi_usb_open(struct hl_interface_param *param, void **fd) switch (param->transport) { #if 0 - /* TODO place holder as swd is not currently supported */ - case HL_TRANSPORT_SWD: + /* TODO place holder as swd is not currently supported */ + case HL_TRANSPORT_SWD: #endif - case HL_TRANSPORT_JTAG: - break; - default: - retval = ERROR_FAIL; - break; + case HL_TRANSPORT_JTAG: + break; + default: + retval = ERROR_FAIL; + break; } if (retval != ERROR_OK) { diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 417d560cde..eb4e815e58 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -523,32 +523,30 @@ static int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, } switch (direction) { - case PAYLOAD_DIRECTION_OUT: - if (ulink_cmd->payload_out) { - LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); - free(payload); - return ERROR_FAIL; - } else { - ulink_cmd->payload_out = payload; - ulink_cmd->payload_out_size = size; - } - break; - case PAYLOAD_DIRECTION_IN: - if (ulink_cmd->payload_in_start) { - LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); - free(payload); - return ERROR_FAIL; - } else { - ulink_cmd->payload_in_start = payload; - ulink_cmd->payload_in = payload; - ulink_cmd->payload_in_size = size; - - /* By default, free payload_in_start in ulink_clear_queue(). Commands - * that do not want this behavior (e. g. split scans) must turn it off - * separately! */ - ulink_cmd->free_payload_in_start = true; - } - break; + case PAYLOAD_DIRECTION_OUT: + if (ulink_cmd->payload_out) { + LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); + free(payload); + return ERROR_FAIL; + } + ulink_cmd->payload_out = payload; + ulink_cmd->payload_out_size = size; + break; + case PAYLOAD_DIRECTION_IN: + if (ulink_cmd->payload_in_start) { + LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); + free(payload); + return ERROR_FAIL; + } + ulink_cmd->payload_in_start = payload; + ulink_cmd->payload_in = payload; + ulink_cmd->payload_in_size = size; + + /* By default, free payload_in_start in ulink_clear_queue(). Commands + * that do not want this behavior (e.g. split scans) must turn it off + * separately! */ + ulink_cmd->free_payload_in_start = true; + break; } return ERROR_OK; @@ -572,12 +570,12 @@ static int ulink_get_queue_size(struct ulink *device, 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; + 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; @@ -881,31 +879,31 @@ static int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, /* 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 = ulink_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); - break; - case SCAN_OUT: - if (device->delay_scan_out < 0) - cmd->id = CMD_SCAN_OUT; - else - cmd->id = CMD_SLOW_SCAN_OUT; - ret = ulink_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 = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); - break; - default: - LOG_ERROR("BUG: ulink_append_scan_cmd() encountered an unknown scan type"); - ret = ERROR_FAIL; - break; + case SCAN_IN: + if (device->delay_scan_in < 0) + cmd->id = CMD_SCAN_IN; + else + cmd->id = CMD_SLOW_SCAN_IN; + ret = ulink_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); + break; + case SCAN_OUT: + if (device->delay_scan_out < 0) + cmd->id = CMD_SCAN_OUT; + else + cmd->id = CMD_SLOW_SCAN_OUT; + ret = ulink_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 = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); + break; + default: + LOG_ERROR("BUG: %s() encountered an unknown scan type", __func__); + ret = ERROR_FAIL; + break; } if (ret != ERROR_OK) { @@ -1287,24 +1285,24 @@ static int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay) t = 1.0 / (float)(f); switch (type) { - case DELAY_CLOCK_TCK: - x = (t - (float)(6E-6)) / (float)(4E-6); - break; - case DELAY_CLOCK_TMS: - x = (t - (float)(8.5E-6)) / (float)(4E-6); - break; - case DELAY_SCAN_IN: - x = (t - (float)(8.8308E-6)) / (float)(4E-6); - break; - case DELAY_SCAN_OUT: - x = (t - (float)(1.0527E-5)) / (float)(4E-6); - break; - case DELAY_SCAN_IO: - x = (t - (float)(1.3132E-5)) / (float)(4E-6); - break; - default: - return ERROR_FAIL; - break; + case DELAY_CLOCK_TCK: + x = (t - (float)(6E-6)) / (float)(4E-6); + break; + case DELAY_CLOCK_TMS: + x = (t - (float)(8.5E-6)) / (float)(4E-6); + break; + case DELAY_SCAN_IN: + x = (t - (float)(8.8308E-6)) / (float)(4E-6); + break; + case DELAY_SCAN_OUT: + x = (t - (float)(1.0527E-5)) / (float)(4E-6); + break; + case DELAY_SCAN_IO: + x = (t - (float)(1.3132E-5)) / (float)(4E-6); + break; + default: + return ERROR_FAIL; + break; } /* Check if the delay value is negative. This happens when a frequency is @@ -1347,38 +1345,38 @@ static long ulink_calculate_frequency(enum ulink_delay_type type, int delay) return 0; switch (type) { - case DELAY_CLOCK_TCK: - if (delay < 0) - t = (float)(2.666E-6); - else - t = (float)(4E-6) * (float)(delay) + (float)(6E-6); - break; - case DELAY_CLOCK_TMS: - if (delay < 0) - t = (float)(5.666E-6); - else - t = (float)(4E-6) * (float)(delay) + (float)(8.5E-6); - break; - case DELAY_SCAN_IN: - if (delay < 0) - t = (float)(5.5E-6); - else - t = (float)(4E-6) * (float)(delay) + (float)(8.8308E-6); - break; - case DELAY_SCAN_OUT: - if (delay < 0) - t = (float)(7.0E-6); - else - t = (float)(4E-6) * (float)(delay) + (float)(1.0527E-5); - break; - case DELAY_SCAN_IO: - if (delay < 0) - t = (float)(9.926E-6); - else - t = (float)(4E-6) * (float)(delay) + (float)(1.3132E-5); - break; - default: - return 0; + case DELAY_CLOCK_TCK: + if (delay < 0) + t = (float)(2.666E-6); + else + t = (float)(4E-6) * (float)(delay) + (float)(6E-6); + break; + case DELAY_CLOCK_TMS: + if (delay < 0) + t = (float)(5.666E-6); + else + t = (float)(4E-6) * (float)(delay) + (float)(8.5E-6); + break; + case DELAY_SCAN_IN: + if (delay < 0) + t = (float)(5.5E-6); + else + t = (float)(4E-6) * (float)(delay) + (float)(8.8308E-6); + break; + case DELAY_SCAN_OUT: + if (delay < 0) + t = (float)(7.0E-6); + else + t = (float)(4E-6) * (float)(delay) + (float)(1.0527E-5); + break; + case DELAY_SCAN_IO: + if (delay < 0) + t = (float)(9.926E-6); + else + t = (float)(4E-6) * (float)(delay) + (float)(1.3132E-5); + break; + default: + return 0; } f_float = 1.0 / t; @@ -1823,19 +1821,18 @@ static int ulink_post_process_scan(struct ulink_cmd *ulink_cmd) int ret; switch (jtag_scan_type(cmd->cmd.scan)) { - case SCAN_IN: - case SCAN_IO: - ret = jtag_read_buffer(ulink_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: ulink_post_process_scan() encountered an unknown" - " JTAG scan type"); - ret = ERROR_FAIL; - break; + case SCAN_IN: + case SCAN_IO: + ret = jtag_read_buffer(ulink_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: %s() encountered an unknown JTAG scan type", __func__); + ret = ERROR_FAIL; + break; } return ret; @@ -1863,23 +1860,22 @@ static int ulink_post_process_queue(struct ulink *device) * OpenULINK command */ if (current->needs_postprocessing && openocd_cmd) { switch (openocd_cmd->type) { - case JTAG_SCAN: - ret = ulink_post_process_scan(current); - break; - case JTAG_TLR_RESET: - case JTAG_RUNTEST: - case JTAG_RESET: - 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: ulink_post_process_queue() encountered unknown JTAG " - "command type"); - break; + case JTAG_SCAN: + ret = ulink_post_process_scan(current); + break; + case JTAG_TLR_RESET: + case JTAG_RUNTEST: + case JTAG_RESET: + 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: %s() encountered unknown JTAG command type", __func__); + break; } if (ret != ERROR_OK) @@ -1913,31 +1909,31 @@ static int ulink_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_SCAN: - ret = ulink_queue_scan(ulink_handle, cmd); - break; - case JTAG_TLR_RESET: - ret = ulink_queue_tlr_reset(ulink_handle, cmd); - break; - case JTAG_RUNTEST: - ret = ulink_queue_runtest(ulink_handle, cmd); - break; - case JTAG_RESET: - ret = ulink_queue_reset(ulink_handle, cmd); - break; - case JTAG_PATHMOVE: - ret = ulink_queue_pathmove(ulink_handle, cmd); - break; - case JTAG_SLEEP: - ret = ulink_queue_sleep(ulink_handle, cmd); - break; - case JTAG_STABLECLOCKS: - ret = ulink_queue_stableclocks(ulink_handle, cmd); - break; - default: - ret = ERROR_FAIL; - LOG_ERROR("BUG: encountered unknown JTAG command type"); - break; + case JTAG_SCAN: + ret = ulink_queue_scan(ulink_handle, cmd); + break; + case JTAG_TLR_RESET: + ret = ulink_queue_tlr_reset(ulink_handle, cmd); + break; + case JTAG_RUNTEST: + ret = ulink_queue_runtest(ulink_handle, cmd); + break; + case JTAG_RESET: + ret = ulink_queue_reset(ulink_handle, cmd); + break; + case JTAG_PATHMOVE: + ret = ulink_queue_pathmove(ulink_handle, cmd); + break; + case JTAG_SLEEP: + ret = ulink_queue_sleep(ulink_handle, cmd); + break; + case JTAG_STABLECLOCKS: + ret = ulink_queue_stableclocks(ulink_handle, cmd); + break; + default: + ret = ERROR_FAIL; + LOG_ERROR("BUG: encountered unknown JTAG command type"); + break; } if (ret != ERROR_OK) @@ -2179,12 +2175,10 @@ static int ulink_init(void) ulink_handle = NULL; return ERROR_FAIL; } -#ifdef _DEBUG_USB_COMMS_ else { /* Successfully received Bulk IN packet -> continue */ - LOG_INFO("Recovered from lost Bulk IN packet"); + LOG_DEBUG_USB("Recovered from lost Bulk IN packet"); } -#endif } ulink_clear_queue(ulink_handle); @@ -2226,8 +2220,6 @@ static int ulink_quit(void) */ COMMAND_HANDLER(ulink_download_firmware_handler) { - int ret; - if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -2235,10 +2227,8 @@ COMMAND_HANDLER(ulink_download_firmware_handler) LOG_INFO("Downloading ULINK firmware image %s", CMD_ARGV[0]); /* Download firmware image in CMD_ARGV[0] */ - ret = ulink_load_firmware_and_renumerate(&ulink_handle, CMD_ARGV[0], + return ulink_load_firmware_and_renumerate(&ulink_handle, CMD_ARGV[0], ULINK_RENUMERATION_DELAY); - - return ret; } /*************************** Command Registration **************************/ diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index 81344664e2..b952732779 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -63,6 +63,7 @@ #endif /* project specific includes */ +#include #include #include #include @@ -825,9 +826,9 @@ static int ublast_execute_queue(struct jtag_command *cmd_queue) */ static int ublast_init(void) { - int ret, i; + int ret; - for (i = 0; lowlevel_drivers_map[i].name; i++) { + for (unsigned int i = 0; lowlevel_drivers_map[i].name; i++) { if (info.lowlevel_name) { if (!strcmp(lowlevel_drivers_map[i].name, info.lowlevel_name)) { info.drv = lowlevel_drivers_map[i].drv_register(); @@ -853,6 +854,24 @@ static int ublast_init(void) return ERROR_JTAG_DEVICE_ERROR; } + unsigned int num_vid_pid_pairs = 0; + + for (unsigned int i = 0; adapter_usb_get_vids()[i]; i++) + num_vid_pid_pairs++; + + if (num_vid_pid_pairs > 0) { + info.ublast_vid = adapter_usb_get_vids()[0]; + info.ublast_pid = adapter_usb_get_pids()[0]; + } + + if (num_vid_pid_pairs > 1) { + info.ublast_vid_uninit = adapter_usb_get_vids()[1]; + info.ublast_pid_uninit = adapter_usb_get_pids()[1]; + } + + if (num_vid_pid_pairs > 2) + LOG_WARNING("ignoring extra IDs in adapter usb vid_pid (maximum is 2 pairs)"); + /* * Register the lowlevel driver */ @@ -893,31 +912,6 @@ static int ublast_quit(void) return info.drv->close(info.drv); } -COMMAND_HANDLER(ublast_handle_vid_pid_command) -{ - if (CMD_ARGC > 4) { - LOG_WARNING("ignoring extra IDs in ublast_vid_pid " - "(maximum is 2 pairs)"); - CMD_ARGC = 4; - } - - if (CMD_ARGC >= 2) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], info.ublast_vid); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], info.ublast_pid); - } else { - LOG_WARNING("incomplete ublast_vid_pid configuration"); - } - - if (CMD_ARGC == 4) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[2], info.ublast_vid_uninit); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], info.ublast_pid_uninit); - } else { - LOG_WARNING("incomplete ublast_vid_pid configuration"); - } - - return ERROR_OK; -} - COMMAND_HANDLER(ublast_handle_pin_command) { uint8_t out_value; @@ -1006,15 +1000,6 @@ COMMAND_HANDLER(ublast_firmware_command) static const struct command_registration ublast_subcommand_handlers[] = { - { - .name = "vid_pid", - .handler = ublast_handle_vid_pid_command, - .mode = COMMAND_CONFIG, - .help = "the vendor ID and product ID of the USB-Blaster and " - "vendor ID and product ID of the uninitialized device " - "for USB-Blaster II", - .usage = "vid pid vid_uninit pid_uninit", - }, { .name = "lowlevel_driver", .handler = ublast_handle_lowlevel_drv_command, diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 264b45f721..0762b006cc 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -124,8 +124,10 @@ static int usbprog_execute_queue(struct jtag_command *cmd_queue) scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); usbprog_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); - if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) { + free(buffer); return ERROR_JTAG_QUEUE_FAILED; + } free(buffer); break; case JTAG_SLEEP: @@ -274,18 +276,18 @@ static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int void (*f)(struct usbprog_jtag *usbprog_jtag, char *buffer_local, int size); switch (type) { - case SCAN_OUT: - f = &usbprog_jtag_write_tdi; - break; - case SCAN_IN: - f = &usbprog_jtag_read_tdo; - break; - case SCAN_IO: - f = &usbprog_jtag_write_and_read; - break; - default: - LOG_ERROR("unknown scan type: %i", type); - exit(-1); + case SCAN_OUT: + f = &usbprog_jtag_write_tdi; + break; + case SCAN_IN: + f = &usbprog_jtag_read_tdo; + break; + case SCAN_IO: + f = &usbprog_jtag_write_and_read; + break; + default: + LOG_ERROR("unknown scan type: %i", type); + exit(-1); } f(usbprog_jtag_handle, (char *)buffer, scan_size); diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c index 38685950a8..e1687a5341 100644 --- a/src/jtag/drivers/vdebug.c +++ b/src/jtag/drivers/vdebug.c @@ -47,19 +47,20 @@ #include "jtag/interface.h" #include "jtag/commands.h" #include "transport/transport.h" +#include "target/target.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_VERSION 50 #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_POLL_INTERVAL 1000 #define VD_SCALE_PSTOMS 1000000000 /** @@ -205,6 +206,7 @@ struct vd_client { uint32_t poll_max; uint32_t targ_time; int hsocket; + int64_t poll_ts; char server_name[32]; char bfm_path[128]; char mem_path[VD_MAX_MEMORIES][128]; @@ -839,6 +841,35 @@ static void vdebug_mem_close(int hsock, struct vd_shm *pm, uint8_t ndx) } +/* function gets invoked through a callback every VD_POLL_INTERVAL ms + * if the idle time, measured by VD_POLL_INTERVAL - targ_time is more than poll_min + * the wait function is called and its time measured and wait cycles adjusted. + * The wait allows hardware to advance, when no data activity from the vdebug occurs + */ +static int vdebug_poll(void *priv) +{ + int64_t ts, te; + + ts = timeval_ms(); + if (ts - vdc.poll_ts - vdc.targ_time >= vdc.poll_min) { + vdebug_wait(vdc.hsocket, pbuf, vdc.poll_cycles); + te = timeval_ms(); + LOG_DEBUG("poll after %" PRId64 "ms, busy %" PRIu32 "ms; wait %" PRIu32 " %" PRId64 "ms", + ts - vdc.poll_ts, vdc.targ_time, vdc.poll_cycles, te - ts); + + if (te - ts + vdc.targ_time < vdc.poll_max / 2) + vdc.poll_cycles *= 2; + else if (te - ts + vdc.targ_time > vdc.poll_max) + vdc.poll_cycles /= 2; + } else { + LOG_DEBUG("poll after %" PRId64 "ms, busy %" PRIu32 "ms", ts - vdc.poll_ts, vdc.targ_time); + } + vdc.poll_ts = ts; + vdc.targ_time = 0; /* reset target time counter */ + + return ERROR_OK; +} + static int vdebug_init(void) { vdc.hsocket = vdebug_socket_open(vdc.server_name, vdc.server_port); @@ -858,6 +889,7 @@ static int vdebug_init(void) } vdc.trans_first = 1; vdc.poll_cycles = vdc.poll_max; + vdc.poll_ts = timeval_ms(); uint32_t sig_mask = VD_SIG_RESET; if (transport_is_jtag()) sig_mask |= VD_SIG_TRST | VD_SIG_TCKDIV; @@ -876,6 +908,8 @@ static int vdebug_init(void) LOG_ERROR("0x%x cannot connect to %s", rc, vdc.mem_path[i]); } + target_register_timer_callback(vdebug_poll, VD_POLL_INTERVAL, + TARGET_TIMER_TYPE_PERIODIC, &vdc); LOG_INFO("vdebug %d connected to %s through %s:%" PRIu16, VD_VERSION, vdc.bfm_path, vdc.server_name, vdc.server_port); } @@ -885,6 +919,8 @@ static int vdebug_init(void) static int vdebug_quit(void) { + target_unregister_timer_callback(vdebug_poll, &vdc); + for (uint8_t i = 0; i < vdc.mem_ndx; i++) if (vdc.mem_width[i]) vdebug_mem_close(vdc.hsocket, pbuf, i); @@ -1179,12 +1215,14 @@ static int vdebug_dap_run(struct adiv5_dap *dap) COMMAND_HANDLER(vdebug_set_server) { - if ((CMD_ARGC != 1) || !strchr(CMD_ARGV[0], ':')) + if (CMD_ARGC != 1) 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); + const char *pchar = strchr(CMD_ARGV[0], ':'); + if (!pchar) + return ERROR_COMMAND_SYNTAX_ERROR; + size_t len = MIN((uintptr_t)pchar - (uintptr_t)CMD_ARGV[0], sizeof(vdc.server_name) - 1); + memcpy(vdc.server_name, CMD_ARGV[0], len); + vdc.server_name[len] = '\0'; int port = atoi(++pchar); if (port < 0 || port > UINT16_MAX) { LOG_ERROR("invalid port number %d specified", port); @@ -1299,16 +1337,16 @@ static const struct command_registration vdebug_command_handlers[] = { { .name = "batching", .handler = &vdebug_set_batching, - .mode = COMMAND_CONFIG, + .mode = COMMAND_ANY, .help = "set the transaction batching no|wr|rd [0|1|2]", .usage = "", }, { .name = "polling", .handler = &vdebug_set_polling, - .mode = COMMAND_CONFIG, - .help = "set the polling pause, executing hardware cycles between min and max", - .usage = " ", + .mode = COMMAND_ANY, + .help = "set the min idle time and max wait time in ms", + .usage = " ", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index d1bb705908..497f97f63f 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -373,6 +373,9 @@ static bool usb_connect(void) /* If we fall though to here, we don't want this device */ libusb_close(dev); dev = NULL; + } else { + const char *err_msg = libusb_error_name(result); + LOG_ERROR("libusb_open(): %s", err_msg); } } } @@ -428,7 +431,7 @@ static bool usb_connect(void) /* Log the results */ if (result == 0) - LOG_INFO("XDS110: connected"); + LOG_DEBUG("XDS110: connected"); else LOG_ERROR("XDS110: failed to connect"); @@ -448,7 +451,7 @@ static void usb_disconnect(void) xds110.ctx = NULL; } - LOG_INFO("XDS110: disconnected"); + LOG_DEBUG("XDS110: disconnected"); } static bool usb_read(unsigned char *buffer, int size, int *bytes_read, @@ -654,26 +657,18 @@ static bool xds_execute(uint32_t out_length, uint32_t in_length, static bool xds_connect(void) { - bool success; - xds110.write_payload[0] = XDS_CONNECT; - success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool xds_disconnect(void) { - bool success; - xds110.write_payload[0] = XDS_DISCONNECT; - success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool xds_version(uint32_t *firmware_id, uint16_t *hardware_id) @@ -702,48 +697,36 @@ static bool xds_set_tck_delay(uint32_t delay) { uint8_t *delay_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ - bool success; - xds110.write_payload[0] = XDS_SET_TCK; xds110_set_u32(delay_pntr, delay); - success = xds_execute(XDS_OUT_LEN + 4, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN + 4, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool xds_set_trst(uint8_t trst) { uint8_t *trst_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 8-bits */ - bool success; - xds110.write_payload[0] = XDS_SET_TRST; *trst_pntr = trst; - success = xds_execute(XDS_OUT_LEN + 1, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN + 1, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool xds_cycle_tck(uint32_t count) { uint8_t *count_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ - bool success; - xds110.write_payload[0] = XDS_CYCLE_TCK; xds110_set_u32(count_pntr, count); - success = xds_execute(XDS_OUT_LEN + 4, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN + 4, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool xds_goto_state(uint32_t state) @@ -751,17 +734,13 @@ static bool xds_goto_state(uint32_t state) uint8_t *state_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ uint8_t *transit_pntr = &xds110.write_payload[XDS_OUT_LEN+4]; /* 32-bits */ - bool success; - xds110.write_payload[0] = XDS_GOTO_STATE; xds110_set_u32(state_pntr, state); xds110_set_u32(transit_pntr, XDS_JTAG_TRANSIT_QUICKEST); - success = xds_execute(XDS_OUT_LEN+8, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN + 8, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool xds_jtag_scan(uint32_t shift_state, uint16_t shift_bits, @@ -814,16 +793,12 @@ static bool xds_set_srst(uint8_t srst) { uint8_t *srst_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 8-bits */ - bool success; - xds110.write_payload[0] = XDS_SET_SRST; *srst_pntr = srst; - success = xds_execute(XDS_OUT_LEN + 1, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN + 1, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool cmapi_connect(uint32_t *idcode) @@ -847,38 +822,26 @@ static bool cmapi_connect(uint32_t *idcode) static bool cmapi_disconnect(void) { - bool success; - xds110.write_payload[0] = CMAPI_DISCONNECT; - success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool cmapi_acquire(void) { - bool success; - xds110.write_payload[0] = CMAPI_ACQUIRE; - success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool cmapi_release(void) { - bool success; - xds110.write_payload[0] = CMAPI_RELEASE; - success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool cmapi_read_dap_reg(uint32_t type, uint32_t ap_num, @@ -916,8 +879,6 @@ static bool cmapi_write_dap_reg(uint32_t type, uint32_t ap_num, uint8_t *address_pntr = &xds110.write_payload[XDS_OUT_LEN + 2]; /* 8-bits */ uint8_t *value_pntr = &xds110.write_payload[XDS_OUT_LEN + 3]; /* 32-bits */ - bool success; - if (!value) return false; @@ -928,62 +889,44 @@ static bool cmapi_write_dap_reg(uint32_t type, uint32_t ap_num, *address_pntr = (uint8_t)(address & 0xff); xds110_set_u32(value_pntr, *value); - success = xds_execute(XDS_OUT_LEN + 7, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN + 7, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool swd_connect(void) { - bool success; - xds110.write_payload[0] = SWD_CONNECT; - success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool swd_disconnect(void) { - bool success; - xds110.write_payload[0] = SWD_DISCONNECT; - success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool cjtag_connect(uint32_t format) { uint8_t *format_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ - bool success; - xds110.write_payload[0] = CJTAG_CONNECT; xds110_set_u32(format_pntr, format); - success = xds_execute(XDS_OUT_LEN + 4, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN + 4, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool cjtag_disconnect(void) { - bool success; - xds110.write_payload[0] = CJTAG_DISCONNECT; - success = xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool xds_set_supply(uint32_t voltage) @@ -991,17 +934,13 @@ static bool xds_set_supply(uint32_t voltage) uint8_t *volts_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ uint8_t *source_pntr = &xds110.write_payload[XDS_OUT_LEN + 4]; /* 8-bits */ - bool success; - xds110.write_payload[0] = XDS_SET_SUPPLY; xds110_set_u32(volts_pntr, voltage); *source_pntr = (uint8_t)(voltage != 0 ? 1 : 0); - success = xds_execute(XDS_OUT_LEN + 5, XDS_IN_LEN, DEFAULT_ATTEMPTS, + return xds_execute(XDS_OUT_LEN + 5, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } static bool ocd_dap_request(uint8_t *dap_requests, uint32_t request_size, @@ -1059,8 +998,6 @@ static bool ocd_pathmove(uint32_t num_states, uint8_t *path) uint8_t *num_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */ uint8_t *path_pntr = &xds110.write_payload[XDS_OUT_LEN + 4]; - bool success; - if (!path) return false; @@ -1070,10 +1007,8 @@ static bool ocd_pathmove(uint32_t num_states, uint8_t *path) memcpy((void *)path_pntr, (void *)path, num_states); - success = xds_execute(XDS_OUT_LEN + 4 + num_states, XDS_IN_LEN, + return xds_execute(XDS_OUT_LEN + 4 + num_states, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); - - return success; } /*************************************************************************** @@ -1551,42 +1486,42 @@ static void xds110_flush(void) while (xds110.txn_requests[request] != 0) { command = xds110.txn_requests[request++]; switch (command) { - case CMD_IR_SCAN: - case CMD_DR_SCAN: - if (command == CMD_IR_SCAN) - shift_state = XDS_JTAG_STATE_SHIFT_IR; - else - shift_state = XDS_JTAG_STATE_SHIFT_DR; - end_state = (uint32_t)(xds110.txn_requests[request++]); - bits = (uint32_t)(xds110.txn_requests[request++]) << 0; - bits |= (uint32_t)(xds110.txn_requests[request++]) << 8; - data_out = &xds110.txn_requests[request]; - bytes = DIV_ROUND_UP(bits, 8); - xds110_legacy_scan(shift_state, bits, end_state, data_out, - &data_in[result]); - result += bytes; - request += bytes; - break; - case CMD_RUNTEST: - clocks = (uint32_t)(xds110.txn_requests[request++]) << 0; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 8; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 16; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 24; - end_state = (uint32_t)xds110.txn_requests[request++]; - xds110_legacy_runtest(clocks, end_state); - break; - case CMD_STABLECLOCKS: - clocks = (uint32_t)(xds110.txn_requests[request++]) << 0; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 8; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 16; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 24; - xds110_legacy_stableclocks(clocks); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered", - command); - exit(-1); - break; + case CMD_IR_SCAN: + case CMD_DR_SCAN: + if (command == CMD_IR_SCAN) + shift_state = XDS_JTAG_STATE_SHIFT_IR; + else + shift_state = XDS_JTAG_STATE_SHIFT_DR; + end_state = (uint32_t)(xds110.txn_requests[request++]); + bits = (uint32_t)(xds110.txn_requests[request++]) << 0; + bits |= (uint32_t)(xds110.txn_requests[request++]) << 8; + data_out = &xds110.txn_requests[request]; + bytes = DIV_ROUND_UP(bits, 8); + xds110_legacy_scan(shift_state, bits, end_state, data_out, + &data_in[result]); + result += bytes; + request += bytes; + break; + case CMD_RUNTEST: + clocks = (uint32_t)(xds110.txn_requests[request++]) << 0; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 8; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 16; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 24; + end_state = (uint32_t)xds110.txn_requests[request++]; + xds110_legacy_runtest(clocks, end_state); + break; + case CMD_STABLECLOCKS: + clocks = (uint32_t)(xds110.txn_requests[request++]) << 0; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 8; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 16; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 24; + xds110_legacy_stableclocks(clocks); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered", + command); + exit(-1); + break; } } } @@ -1809,32 +1744,32 @@ static void xds110_queue_stableclocks(struct jtag_command *cmd) static void xds110_execute_command(struct jtag_command *cmd) { switch (cmd->type) { - case JTAG_SLEEP: - xds110_flush(); - xds110_execute_sleep(cmd); - break; - case JTAG_TLR_RESET: - xds110_flush(); - xds110_execute_tlr_reset(cmd); - break; - case JTAG_PATHMOVE: - xds110_flush(); - xds110_execute_pathmove(cmd); - break; - case JTAG_SCAN: - xds110_queue_scan(cmd); - break; - case JTAG_RUNTEST: - xds110_queue_runtest(cmd); - break; - case JTAG_STABLECLOCKS: - xds110_queue_stableclocks(cmd); - break; - case JTAG_TMS: - default: - LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered", - cmd->type); - exit(-1); + case JTAG_SLEEP: + xds110_flush(); + xds110_execute_sleep(cmd); + break; + case JTAG_TLR_RESET: + xds110_flush(); + xds110_execute_tlr_reset(cmd); + break; + case JTAG_PATHMOVE: + xds110_flush(); + xds110_execute_pathmove(cmd); + break; + case JTAG_SCAN: + xds110_queue_scan(cmd); + break; + case JTAG_RUNTEST: + xds110_queue_runtest(cmd); + break; + case JTAG_STABLECLOCKS: + xds110_queue_stableclocks(cmd); + break; + case JTAG_TMS: + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered", + cmd->type); + exit(-1); } } diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-xvc.c similarity index 50% rename from src/jtag/drivers/xlnx-pcie-xvc.c rename to src/jtag/drivers/xlnx-xvc.c index 3baa183d95..f00650671d 100644 --- a/src/jtag/drivers/xlnx-pcie-xvc.c +++ b/src/jtag/drivers/xlnx-xvc.c @@ -1,8 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019 Google, LLC. - * Author: Moritz Fischer + * Copyright (C) 2019 Google, LLC. + * Moritz Fischer + * + * Copyright (C) 2021 Western Digital Corporation or its affiliates + * Jeremy Garff + * + * Copyright (C) 2024 Inria + * Nicolas Derumigny */ #ifdef HAVE_CONFIG_H @@ -11,13 +17,14 @@ #include #include -#include #include #include +#include #include -#include #include +#include +#include #include #include @@ -28,14 +35,24 @@ #define PCIE_EXT_CAP_LST 0x100 -#define XLNX_XVC_EXT_CAP 0x00 -#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_PCIE_XVC_EXT_CAP 0x00 +#define XLNX_PCIE_XVC_VSEC_HDR 0x04 +#define XLNX_PCIE_XVC_LEN_REG 0x0C +#define XLNX_PCIE_XVC_TMS_REG 0x10 +#define XLNX_PCIE_XVC_TDX_REG 0x14 + +#define XLNX_PCIE_XVC_CAP_SIZE 0x20 +#define XLNX_PCIE_XVC_VSEC_ID 0x8 + +#define XLNX_AXI_XVC_LEN_REG 0x00 +#define XLNX_AXI_XVC_TMS_REG 0x04 +#define XLNX_AXI_XVC_TDI_REG 0x08 +#define XLNX_AXI_XVC_TDO_REG 0x0c +#define XLNX_AXI_XVC_CTRL_REG 0x10 +#define XLNX_AXI_XVC_MAX_REG 0x18 + +#define XLNX_AXI_XVC_CTRL_REG_ENABLE_MASK 0x01 -#define XLNX_XVC_CAP_SIZE 0x20 -#define XLNX_XVC_VSEC_ID 0x8 #define XLNX_XVC_MAX_BITS 0x20 #define MASK_ACK(x) (((x) >> 9) & 0x7) @@ -47,8 +64,23 @@ struct xlnx_pcie_xvc { char *device; }; +struct xlnx_axi_xvc { + int fd; + uint32_t *base; + char *device_addr; + // Defaults to `/dev/mem` if NULL + char *device_file; +}; + +enum xlnx_xvc_type_t { + PCIE, + AXI +}; + static struct xlnx_pcie_xvc xlnx_pcie_xvc_state; static struct xlnx_pcie_xvc *xlnx_pcie_xvc = &xlnx_pcie_xvc_state; +static struct xlnx_axi_xvc xlnx_axi_xvc_state; +static struct xlnx_axi_xvc *xlnx_axi_xvc = &xlnx_axi_xvc_state; static int xlnx_pcie_xvc_read_reg(const int offset, uint32_t *val) { @@ -60,9 +92,9 @@ static int xlnx_pcie_xvc_read_reg(const int offset, uint32_t *val) * space accessor functions */ err = pread(xlnx_pcie_xvc->fd, &res, sizeof(res), - xlnx_pcie_xvc->offset + offset); + xlnx_pcie_xvc->offset + offset); if (err != sizeof(res)) { - LOG_ERROR("Failed to read offset %x", offset); + LOG_ERROR("Failed to read offset 0x%x", offset); return ERROR_JTAG_DEVICE_ERROR; } @@ -72,6 +104,19 @@ static int xlnx_pcie_xvc_read_reg(const int offset, uint32_t *val) return ERROR_OK; } +static int xlnx_axi_xvc_read_reg(const int offset, uint32_t *val) +{ + uintptr_t b = ((uintptr_t)xlnx_axi_xvc->base) + offset; + volatile uint32_t *w = (uint32_t *)b; + + if (val) { + __atomic_thread_fence(__ATOMIC_SEQ_CST); + *val = *w; + } + + return ERROR_OK; +} + static int xlnx_pcie_xvc_write_reg(const int offset, const uint32_t val) { int err; @@ -81,9 +126,9 @@ static int xlnx_pcie_xvc_write_reg(const int offset, const uint32_t val) * space accessor functions */ err = pwrite(xlnx_pcie_xvc->fd, &val, sizeof(val), - xlnx_pcie_xvc->offset + offset); + xlnx_pcie_xvc->offset + offset); if (err != sizeof(val)) { - LOG_ERROR("Failed to write offset: %x with value: %" PRIx32, + LOG_ERROR("Failed to write offset: 0x%x with value: %" PRIx32, offset, val); return ERROR_JTAG_DEVICE_ERROR; } @@ -91,37 +136,117 @@ static int xlnx_pcie_xvc_write_reg(const int offset, const uint32_t val) return ERROR_OK; } +static int xlnx_axi_xvc_write_reg(const int offset, const uint32_t val) +{ + uintptr_t b = ((uintptr_t)xlnx_axi_xvc->base) + offset; + volatile uint32_t *w = (uint32_t *)b; + + *w = val; + __atomic_thread_fence(__ATOMIC_SEQ_CST); + + return ERROR_OK; +} + static int xlnx_pcie_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, uint32_t *tdo) { int err; - err = xlnx_pcie_xvc_write_reg(XLNX_XVC_LEN_REG, num_bits); + err = xlnx_pcie_xvc_write_reg(XLNX_PCIE_XVC_LEN_REG, num_bits); if (err != ERROR_OK) return err; - err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TMS_REG, tms); + err = xlnx_pcie_xvc_write_reg(XLNX_PCIE_XVC_TMS_REG, tms); if (err != ERROR_OK) return err; - err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TDX_REG, tdi); + err = xlnx_pcie_xvc_write_reg(XLNX_PCIE_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_PCIE_XVC_TDX_REG, tdo); if (err != ERROR_OK) return err; if (tdo) LOG_DEBUG_IO("Transact num_bits: %zu, tms: %" PRIx32 ", tdi: %" PRIx32 ", tdo: %" PRIx32, - num_bits, tms, tdi, *tdo); + num_bits, tms, tdi, *tdo); else LOG_DEBUG_IO("Transact num_bits: %zu, tms: %" PRIx32 ", tdi: %" PRIx32 ", tdo: ", - num_bits, tms, tdi); + num_bits, tms, tdi); + return ERROR_OK; +} + +static int xlnx_axi_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, + uint32_t *tdo) +{ + uint32_t ctrl; + int done = 0; + int err; + + err = xlnx_axi_xvc_write_reg(XLNX_AXI_XVC_LEN_REG, num_bits); + if (err != ERROR_OK) + return err; + + err = xlnx_axi_xvc_write_reg(XLNX_AXI_XVC_TMS_REG, tms); + if (err != ERROR_OK) + return err; + + err = xlnx_axi_xvc_write_reg(XLNX_AXI_XVC_TDI_REG, tdi); + if (err != ERROR_OK) + return err; + + err = xlnx_axi_xvc_write_reg(XLNX_AXI_XVC_CTRL_REG, XLNX_AXI_XVC_CTRL_REG_ENABLE_MASK); + if (err != ERROR_OK) + return err; + + while (!done) { + err = xlnx_axi_xvc_read_reg(XLNX_AXI_XVC_CTRL_REG, &ctrl); + if (err != ERROR_OK) + return err; + + if (!(ctrl & XLNX_AXI_XVC_CTRL_REG_ENABLE_MASK)) + done = 1; + + /* + There is no delay here intentionally. The usleep() + function doesn't block and burns CPU cycles anyway. + The turnaround time is fast enough at high JTAG rates + that adding the call can slow down the overall + throughput. So we'll just sacrifice the CPU to get + best performance. + + Additionally there is no timeout. The underlying + hardware is guaranteed to unset the enable bit within + 32 JTAG clock cycles. There is no hardware condition + that will keep it set forever. Essentially, the hardware + is also our timeout mechanism. + */ + } + + err = xlnx_axi_xvc_read_reg(XLNX_AXI_XVC_TDO_REG, tdo); + if (err != ERROR_OK) + return err; + + if (tdo) + LOG_DEBUG_IO("Transact num_bits: %zu, tms: 0x%x, tdi: 0x%x, tdo: 0x%x", + num_bits, tms, tdi, *tdo); + else + LOG_DEBUG_IO("Transact num_bits: %zu, tms: 0x%x, tdi: 0x%x, tdo: ", + num_bits, tms, tdi); return ERROR_OK; } -static int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) +static int xlnx_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, + uint32_t *tdo, enum xlnx_xvc_type_t xvc_type) +{ + if (xvc_type == PCIE) + return xlnx_pcie_xvc_transact(num_bits, tms, tdi, tdo); + assert(xvc_type == AXI); + return xlnx_axi_xvc_transact(num_bits, tms, tdi, tdo); +} + +static int xlnx_xvc_execute_stableclocks(struct jtag_command *cmd, enum xlnx_xvc_type_t xvc_type) { int tms = tap_get_state() == TAP_RESET ? 1 : 0; size_t left = cmd->cmd.stableclocks->num_cycles; @@ -132,7 +257,7 @@ static int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); - err = xlnx_pcie_xvc_transact(write, tms, 0, NULL); + err = xlnx_xvc_transact(write, tms, 0, NULL, xvc_type); if (err != ERROR_OK) return err; left -= write; @@ -141,12 +266,12 @@ static int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) return ERROR_OK; } -static int xlnx_pcie_xvc_execute_statemove(size_t skip) +static int xlnx_xvc_execute_statemove(size_t skip, enum xlnx_xvc_type_t xvc_type) { uint8_t tms_scan = tap_get_tms_path(tap_get_state(), - tap_get_end_state()); + tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), - tap_get_end_state()); + tap_get_end_state()); int err; LOG_DEBUG("statemove starting at (skip: %zu) %s end in %s", skip, @@ -154,7 +279,7 @@ static int xlnx_pcie_xvc_execute_statemove(size_t skip) tap_state_name(tap_get_end_state())); - err = xlnx_pcie_xvc_transact(tms_count - skip, tms_scan >> skip, 0, NULL); + err = xlnx_xvc_transact(tms_count - skip, tms_scan >> skip, 0, NULL, xvc_type); if (err != ERROR_OK) return err; @@ -163,7 +288,8 @@ static int xlnx_pcie_xvc_execute_statemove(size_t skip) return ERROR_OK; } -static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) +static int xlnx_xvc_execute_runtest(struct jtag_command *cmd, + enum xlnx_xvc_type_t xvc_type) { int err = ERROR_OK; @@ -175,7 +301,7 @@ static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) if (tap_get_state() != TAP_IDLE) { tap_set_end_state(TAP_IDLE); - err = xlnx_pcie_xvc_execute_statemove(0); + err = xlnx_xvc_execute_statemove(0, xvc_type); if (err != ERROR_OK) return err; }; @@ -185,7 +311,7 @@ static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); - err = xlnx_pcie_xvc_transact(write, 0, 0, NULL); + err = xlnx_xvc_transact(write, 0, 0, NULL, xvc_type); if (err != ERROR_OK) return err; left -= write; @@ -193,12 +319,13 @@ static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) tap_set_end_state(tmp_state); if (tap_get_state() != tap_get_end_state()) - err = xlnx_pcie_xvc_execute_statemove(0); + err = xlnx_xvc_execute_statemove(0, xvc_type); return err; } -static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd) +static int xlnx_xvc_execute_pathmove(struct jtag_command *cmd, + enum xlnx_xvc_type_t xvc_type) { unsigned int num_states = cmd->cmd.pathmove->num_states; enum tap_state *path = cmd->cmd.pathmove->path; @@ -210,9 +337,9 @@ static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd) for (unsigned int i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) { - err = xlnx_pcie_xvc_transact(1, 1, 0, NULL); + err = xlnx_xvc_transact(1, 0, 0, NULL, xvc_type); } else if (path[i] == tap_state_transition(tap_get_state(), true)) { - err = xlnx_pcie_xvc_transact(1, 0, 0, NULL); + err = xlnx_xvc_transact(1, 1, 0, NULL, xvc_type); } else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.", tap_state_name(tap_get_state()), @@ -229,7 +356,8 @@ static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd) return ERROR_OK; } -static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) +static int xlnx_xvc_execute_scan(struct jtag_command *cmd, + enum xlnx_xvc_type_t xvc_type) { enum scan_type type = jtag_scan_type(cmd->cmd.scan); enum tap_state saved_end_state = cmd->cmd.scan->end_state; @@ -253,13 +381,13 @@ static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) */ if (ir_scan && tap_get_state() != TAP_IRSHIFT) { tap_set_end_state(TAP_IRSHIFT); - err = xlnx_pcie_xvc_execute_statemove(0); + err = xlnx_xvc_execute_statemove(0, xvc_type); if (err != ERROR_OK) goto out_err; tap_set_end_state(saved_end_state); } else if (!ir_scan && (tap_get_state() != TAP_DRSHIFT)) { tap_set_end_state(TAP_DRSHIFT); - err = xlnx_pcie_xvc_execute_statemove(0); + err = xlnx_xvc_execute_statemove(0, xvc_type); if (err != ERROR_OK) goto out_err; tap_set_end_state(saved_end_state); @@ -271,8 +399,8 @@ static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) /* the last TMS should be a 1, to leave the state */ tms = left <= XLNX_XVC_MAX_BITS ? BIT(write - 1) : 0; tdi = (type != SCAN_IN) ? buf_get_u32(rd_ptr, 0, write) : 0; - err = xlnx_pcie_xvc_transact(write, tms, tdi, type != SCAN_OUT ? - &tdo : NULL); + err = xlnx_xvc_transact(write, tms, tdi, type != SCAN_OUT ? + &tdo : NULL, xvc_type); if (err != ERROR_OK) goto out_err; left -= write; @@ -285,7 +413,7 @@ static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) free(buf); if (tap_get_state() != tap_get_end_state()) - err = xlnx_pcie_xvc_execute_statemove(1); + err = xlnx_xvc_execute_statemove(1, xvc_type); return err; @@ -294,19 +422,14 @@ static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) return err; } -static void xlnx_pcie_xvc_execute_reset(struct jtag_command *cmd) -{ - LOG_DEBUG("reset trst: %i srst: %i", cmd->cmd.reset->trst, - cmd->cmd.reset->srst); -} - -static void xlnx_pcie_xvc_execute_sleep(struct jtag_command *cmd) +static void xlnx_xvc_execute_sleep(struct jtag_command *cmd) { - LOG_DEBUG("sleep %" PRIu32 "", cmd->cmd.sleep->us); + LOG_DEBUG("sleep %" PRIu32, cmd->cmd.sleep->us); usleep(cmd->cmd.sleep->us); } -static int xlnx_pcie_xvc_execute_tms(struct jtag_command *cmd) +static int xlnx_xvc_execute_tms(struct jtag_command *cmd, + enum xlnx_xvc_type_t xvc_type) { const size_t num_bits = cmd->cmd.tms->num_bits; const uint8_t *bits = cmd->cmd.tms->bits; @@ -320,7 +443,7 @@ static int xlnx_pcie_xvc_execute_tms(struct jtag_command *cmd) while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); tms = buf_get_u32(bits, 0, write); - err = xlnx_pcie_xvc_transact(write, tms, 0, NULL); + err = xlnx_xvc_transact(write, tms, 0, NULL, xvc_type); if (err != ERROR_OK) return err; left -= write; @@ -330,29 +453,30 @@ static int xlnx_pcie_xvc_execute_tms(struct jtag_command *cmd) return ERROR_OK; } -static int xlnx_pcie_xvc_execute_command(struct jtag_command *cmd) +static int xlnx_xvc_execute_command(struct jtag_command *cmd, + enum xlnx_xvc_type_t xvc_type) { LOG_DEBUG("%s: cmd->type: %u", __func__, cmd->type); switch (cmd->type) { case JTAG_STABLECLOCKS: - return xlnx_pcie_xvc_execute_stableclocks(cmd); + return xlnx_xvc_execute_stableclocks(cmd, xvc_type); case JTAG_RUNTEST: - return xlnx_pcie_xvc_execute_runtest(cmd); + return xlnx_xvc_execute_runtest(cmd, xvc_type); case JTAG_TLR_RESET: tap_set_end_state(cmd->cmd.statemove->end_state); - return xlnx_pcie_xvc_execute_statemove(0); + return xlnx_xvc_execute_statemove(0, xvc_type); case JTAG_PATHMOVE: - return xlnx_pcie_xvc_execute_pathmove(cmd); + return xlnx_xvc_execute_pathmove(cmd, xvc_type); case JTAG_SCAN: - return xlnx_pcie_xvc_execute_scan(cmd); + return xlnx_xvc_execute_scan(cmd, xvc_type); case JTAG_RESET: - xlnx_pcie_xvc_execute_reset(cmd); + LOG_INFO("WARN: XVC driver has no reset."); break; case JTAG_SLEEP: - xlnx_pcie_xvc_execute_sleep(cmd); + xlnx_xvc_execute_sleep(cmd); break; case JTAG_TMS: - return xlnx_pcie_xvc_execute_tms(cmd); + return xlnx_xvc_execute_tms(cmd, xvc_type); default: LOG_ERROR("BUG: Unknown JTAG command type encountered."); return ERROR_JTAG_QUEUE_FAILED; @@ -361,13 +485,14 @@ static int xlnx_pcie_xvc_execute_command(struct jtag_command *cmd) return ERROR_OK; } -static int xlnx_pcie_xvc_execute_queue(struct jtag_command *cmd_queue) +static int xlnx_xvc_execute_queue(struct jtag_command *cmd_queue, + enum xlnx_xvc_type_t xvc_type) { struct jtag_command *cmd = cmd_queue; int ret; while (cmd) { - ret = xlnx_pcie_xvc_execute_command(cmd); + ret = xlnx_xvc_execute_command(cmd, xvc_type); if (ret != ERROR_OK) return ret; @@ -378,6 +503,15 @@ static int xlnx_pcie_xvc_execute_queue(struct jtag_command *cmd_queue) return ERROR_OK; } +static int xlnx_pcie_xvc_execute_queue(struct jtag_command *cmd_queue) +{ + return xlnx_xvc_execute_queue(cmd_queue, PCIE); +} + +static int xlnx_axi_xvc_execute_queue(struct jtag_command *cmd_queue) +{ + return xlnx_xvc_execute_queue(cmd_queue, AXI); +} static int xlnx_pcie_xvc_init(void) { @@ -399,8 +533,8 @@ static int xlnx_pcie_xvc_init(void) * vendor specific header */ xlnx_pcie_xvc->offset = PCIE_EXT_CAP_LST; while (xlnx_pcie_xvc->offset <= PCI_CFG_SPACE_EXP_SIZE - sizeof(cap) && - xlnx_pcie_xvc->offset >= PCIE_EXT_CAP_LST) { - err = xlnx_pcie_xvc_read_reg(XLNX_XVC_EXT_CAP, &cap); + xlnx_pcie_xvc->offset >= PCIE_EXT_CAP_LST) { + err = xlnx_pcie_xvc_read_reg(XLNX_PCIE_XVC_EXT_CAP, &cap); if (err != ERROR_OK) return err; LOG_DEBUG("Checking capability at 0x%x; id=0x%04" PRIx32 " version=0x%" PRIx32 " next=0x%" PRIx32, @@ -409,7 +543,7 @@ static int xlnx_pcie_xvc_init(void) PCI_EXT_CAP_VER(cap), PCI_EXT_CAP_NEXT(cap)); if (PCI_EXT_CAP_ID(cap) == PCI_EXT_CAP_ID_VNDR) { - err = xlnx_pcie_xvc_read_reg(XLNX_XVC_VSEC_HDR, &vh); + err = xlnx_pcie_xvc_read_reg(XLNX_PCIE_XVC_VSEC_HDR, &vh); if (err != ERROR_OK) return err; LOG_DEBUG("Checking possible match at 0x%x; id: 0x%" PRIx32 "; rev: 0x%" PRIx32 "; length: 0x%" PRIx32, @@ -417,14 +551,14 @@ static int xlnx_pcie_xvc_init(void) PCI_VNDR_HEADER_ID(vh), PCI_VNDR_HEADER_REV(vh), PCI_VNDR_HEADER_LEN(vh)); - if ((PCI_VNDR_HEADER_ID(vh) == XLNX_XVC_VSEC_ID) && - (PCI_VNDR_HEADER_LEN(vh) == XLNX_XVC_CAP_SIZE)) + if ((PCI_VNDR_HEADER_ID(vh) == XLNX_PCIE_XVC_VSEC_ID) && + (PCI_VNDR_HEADER_LEN(vh) == XLNX_PCIE_XVC_CAP_SIZE)) break; } xlnx_pcie_xvc->offset = PCI_EXT_CAP_NEXT(cap); } - if ((xlnx_pcie_xvc->offset > PCI_CFG_SPACE_EXP_SIZE - XLNX_XVC_CAP_SIZE) || - xlnx_pcie_xvc->offset < PCIE_EXT_CAP_LST) { + if ((xlnx_pcie_xvc->offset > PCI_CFG_SPACE_EXP_SIZE - XLNX_PCIE_XVC_CAP_SIZE) || + xlnx_pcie_xvc->offset < PCIE_EXT_CAP_LST) { close(xlnx_pcie_xvc->fd); return ERROR_JTAG_INIT_FAILED; } @@ -434,6 +568,44 @@ static int xlnx_pcie_xvc_init(void) return ERROR_OK; } +static int xlnx_axi_xvc_init(void) +{ + uint64_t baseaddr; + + if (xlnx_axi_xvc->device_addr) { + baseaddr = strtoul(xlnx_axi_xvc->device_addr, NULL, 0); + } else { + LOG_ERROR("Please set device addr."); + return ERROR_JTAG_INIT_FAILED; + } + + if (xlnx_axi_xvc->device_file) { + LOG_INFO("Opening %s for AXI communication", xlnx_axi_xvc->device_file); + xlnx_axi_xvc->fd = open(xlnx_axi_xvc->device_file, O_RDWR | O_SYNC); + } else { + LOG_INFO("Opening /dev/mem for AXI communication"); + xlnx_axi_xvc->fd = open("/dev/mem", O_RDWR | O_SYNC); + } + + if (xlnx_axi_xvc->fd < 0) { + LOG_ERROR("Failed to open device file, check permissions."); + return ERROR_JTAG_INIT_FAILED; + } + + xlnx_axi_xvc->base = mmap(0, XLNX_AXI_XVC_MAX_REG, PROT_READ | PROT_WRITE, + MAP_SHARED, xlnx_axi_xvc->fd, baseaddr); + if (xlnx_axi_xvc->base == MAP_FAILED) { + LOG_ERROR("mmap() failed, check permissions."); + close(xlnx_axi_xvc->fd); + return ERROR_JTAG_INIT_FAILED; + } + + LOG_INFO("Mapped Xilinx XVC/AXI vaddr %p paddr 0x%" PRIx64, + xlnx_axi_xvc->base, baseaddr); + + return ERROR_OK; +} + static int xlnx_pcie_xvc_quit(void) { int err; @@ -445,21 +617,55 @@ static int xlnx_pcie_xvc_quit(void) return ERROR_OK; } +static int xlnx_axi_xvc_quit(void) +{ + int err; + + munmap(xlnx_axi_xvc->base, XLNX_AXI_XVC_MAX_REG); + free(xlnx_pcie_xvc->device); + free(xlnx_axi_xvc->device_file); + free(xlnx_axi_xvc->device_addr); + + err = close(xlnx_axi_xvc->fd); + if (err) + return err; + + return ERROR_OK; +} + COMMAND_HANDLER(xlnx_pcie_xvc_handle_config_command) { - if (CMD_ARGC < 1) + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - /* we can't really free this in a safe manner, so at least - * limit the memory we're leaking by freeing the old one first - * before allocating a new one ... - */ free(xlnx_pcie_xvc->device); xlnx_pcie_xvc->device = strdup(CMD_ARGV[0]); return ERROR_OK; } +COMMAND_HANDLER(xlnx_axi_xvc_handle_dev_addr_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(xlnx_axi_xvc->device_addr); + + xlnx_axi_xvc->device_addr = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + +COMMAND_HANDLER(xlnx_axi_xvc_handle_dev_file_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(xlnx_axi_xvc->device_file); + + xlnx_axi_xvc->device_file = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + static const struct command_registration xlnx_pcie_xvc_subcommand_handlers[] = { { .name = "config", @@ -482,11 +688,45 @@ static const struct command_registration xlnx_pcie_xvc_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration xlnx_axi_xvc_subcommand_handlers[] = { + { + .name = "dev_addr", + .handler = xlnx_axi_xvc_handle_dev_addr_command, + .mode = COMMAND_CONFIG, + .help = "Configure XVC/AXI JTAG device memory address", + .usage = "addr", + }, + { + .name = "dev_file", + .handler = xlnx_axi_xvc_handle_dev_file_command, + .mode = COMMAND_CONFIG, + .help = "Configure XVC/AXI JTAG device file location", + .usage = "addr", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration xlnx_axi_xvc_command_handlers[] = { + { + .name = "xlnx_axi_xvc", + .mode = COMMAND_ANY, + .help = "perform xlnx_axi_xvc management", + .chain = xlnx_axi_xvc_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static struct jtag_interface xlnx_pcie_xvc_jtag_ops = { .execute_queue = &xlnx_pcie_xvc_execute_queue, }; -static int xlnx_pcie_xvc_swd_sequence(const uint8_t *seq, size_t length) +static struct jtag_interface xlnx_axi_xvc_jtag_ops = { + .execute_queue = &xlnx_axi_xvc_execute_queue, +}; + +static int xlnx_xvc_swd_sequence(const uint8_t *seq, size_t length, + enum xlnx_xvc_type_t xvc_type) { size_t left, write; uint32_t send; @@ -496,7 +736,7 @@ static int xlnx_pcie_xvc_swd_sequence(const uint8_t *seq, size_t length) while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); send = buf_get_u32(seq, 0, write); - err = xlnx_pcie_xvc_transact(write, send, 0, NULL); + err = xlnx_xvc_transact(write, send, 0, NULL, xvc_type); if (err != ERROR_OK) return err; left -= write; @@ -506,21 +746,22 @@ static int xlnx_pcie_xvc_swd_sequence(const uint8_t *seq, size_t length) return ERROR_OK; } -static int xlnx_pcie_xvc_swd_switch_seq(enum swd_special_seq seq) +static int xlnx_xvc_swd_switch_seq(enum swd_special_seq seq, + enum xlnx_xvc_type_t xvc_type) { switch (seq) { case LINE_RESET: LOG_DEBUG("SWD line reset"); - return xlnx_pcie_xvc_swd_sequence(swd_seq_line_reset, - swd_seq_line_reset_len); + return xlnx_xvc_swd_sequence(swd_seq_line_reset, + swd_seq_line_reset_len, xvc_type); case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); - return xlnx_pcie_xvc_swd_sequence(swd_seq_jtag_to_swd, - swd_seq_jtag_to_swd_len); + return xlnx_xvc_swd_sequence(swd_seq_jtag_to_swd, + swd_seq_jtag_to_swd_len, xvc_type); case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); - return xlnx_pcie_xvc_swd_sequence(swd_seq_swd_to_jtag, - swd_seq_swd_to_jtag_len); + return xlnx_xvc_swd_sequence(swd_seq_swd_to_jtag, + swd_seq_swd_to_jtag_len, xvc_type); default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; @@ -529,19 +770,31 @@ static int xlnx_pcie_xvc_swd_switch_seq(enum swd_special_seq seq) return ERROR_OK; } +static int xlnx_pcie_xvc_swd_switch_seq(enum swd_special_seq seq) +{ + return xlnx_xvc_swd_switch_seq(seq, PCIE); +} + +static int xlnx_axi_xvc_swd_switch_seq(enum swd_special_seq seq) +{ + return xlnx_xvc_swd_switch_seq(seq, AXI); +} + static int queued_retval; -static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, - uint32_t ap_delay_clk); +static void xlnx_xvc_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk, + enum xlnx_xvc_type_t xvc_type); -static void swd_clear_sticky_errors(void) +static void swd_clear_sticky_errors(enum xlnx_xvc_type_t xvc_type) { - xlnx_pcie_xvc_swd_write_reg(swd_cmd(false, false, DP_ABORT), - STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); + xlnx_xvc_swd_write_reg(swd_cmd(false, false, DP_ABORT), + STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0, xvc_type); } -static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, - uint32_t ap_delay_clk) +static void xlnx_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, + uint32_t ap_delay_clk, + enum xlnx_xvc_type_t xvc_type) { uint32_t res, ack, rpar; int err; @@ -550,23 +803,23 @@ static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, cmd |= SWD_CMD_START | SWD_CMD_PARK; /* cmd + ack */ - err = xlnx_pcie_xvc_transact(12, cmd, 0, &res); + err = xlnx_xvc_transact(12, cmd, 0, &res, xvc_type); if (err != ERROR_OK) goto err_out; ack = MASK_ACK(res); /* read data */ - err = xlnx_pcie_xvc_transact(32, 0, 0, &res); + err = xlnx_xvc_transact(32, 0, 0, &res, xvc_type); if (err != ERROR_OK) goto err_out; /* parity + trn */ - err = xlnx_pcie_xvc_transact(2, 0, 0, &rpar); + err = xlnx_xvc_transact(2, 0, 0, &rpar, xvc_type); if (err != ERROR_OK) goto err_out; - LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + 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", @@ -583,19 +836,19 @@ static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, if (value) *value = res; if (cmd & SWD_CMD_APNDP) - err = xlnx_pcie_xvc_transact(ap_delay_clk, 0, 0, NULL); + err = xlnx_xvc_transact(ap_delay_clk, 0, 0, NULL, xvc_type); queued_retval = err; return; case SWD_ACK_WAIT: LOG_DEBUG_IO("SWD_ACK_WAIT"); - swd_clear_sticky_errors(); + swd_clear_sticky_errors(xvc_type); return; case SWD_ACK_FAULT: LOG_DEBUG_IO("SWD_ACK_FAULT"); queued_retval = ack; return; default: - LOG_DEBUG_IO("No valid acknowledge: ack=%02"PRIx32, ack); + LOG_DEBUG_IO("No valid acknowledge: ack=%02" PRIx32, ack); queued_retval = ack; return; } @@ -603,8 +856,21 @@ static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, queued_retval = err; } -static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, +static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) +{ + xlnx_xvc_swd_read_reg(cmd, value, ap_delay_clk, PCIE); +} + +static void xlnx_axi_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, + uint32_t ap_delay_clk) +{ + xlnx_xvc_swd_read_reg(cmd, value, ap_delay_clk, AXI); +} + +static void xlnx_xvc_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk, + enum xlnx_xvc_type_t xvc_type) { uint32_t res, ack; int err; @@ -613,23 +879,23 @@ static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, cmd |= SWD_CMD_START | SWD_CMD_PARK; /* cmd + trn + ack */ - err = xlnx_pcie_xvc_transact(13, cmd, 0, &res); + err = xlnx_xvc_transact(13, cmd, 0, &res, xvc_type); if (err != ERROR_OK) goto err_out; ack = MASK_ACK(res); /* write data */ - err = xlnx_pcie_xvc_transact(32, value, 0, NULL); + err = xlnx_xvc_transact(32, value, 0, NULL, xvc_type); if (err != ERROR_OK) goto err_out; /* parity + trn */ - err = xlnx_pcie_xvc_transact(2, parity_u32(value), 0, NULL); + err = xlnx_xvc_transact(2, parity_u32(value), 0, NULL, xvc_type); if (err != ERROR_OK) goto err_out; - LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + 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", @@ -640,19 +906,19 @@ static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, switch (ack) { case SWD_ACK_OK: if (cmd & SWD_CMD_APNDP) - err = xlnx_pcie_xvc_transact(ap_delay_clk, 0, 0, NULL); + err = xlnx_xvc_transact(ap_delay_clk, 0, 0, NULL, xvc_type); queued_retval = err; return; case SWD_ACK_WAIT: LOG_DEBUG_IO("SWD_ACK_WAIT"); - swd_clear_sticky_errors(); + swd_clear_sticky_errors(xvc_type); return; case SWD_ACK_FAULT: LOG_DEBUG_IO("SWD_ACK_FAULT"); queued_retval = ack; return; default: - LOG_DEBUG_IO("No valid acknowledge: ack=%02"PRIx32, ack); + LOG_DEBUG_IO("No valid acknowledge: ack=%02" PRIx32, ack); queued_retval = ack; return; } @@ -661,12 +927,24 @@ static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, queued_retval = err; } -static int xlnx_pcie_xvc_swd_run_queue(void) +static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk) +{ + xlnx_xvc_swd_write_reg(cmd, value, ap_delay_clk, PCIE); +} + +static void xlnx_axi_xvc_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk) +{ + xlnx_xvc_swd_write_reg(cmd, value, ap_delay_clk, AXI); +} + +static int xlnx_xvc_swd_run_queue(enum xlnx_xvc_type_t xvc_type) { int err; /* we want at least 8 idle cycles between each transaction */ - err = xlnx_pcie_xvc_transact(8, 0, 0, NULL); + err = xlnx_xvc_transact(8, 0, 0, NULL, xvc_type); if (err != ERROR_OK) return err; @@ -677,19 +955,37 @@ static int xlnx_pcie_xvc_swd_run_queue(void) return err; } -static int xlnx_pcie_xvc_swd_init(void) +static int xlnx_pcie_xvc_swd_run_queue(void) +{ + return xlnx_xvc_swd_run_queue(PCIE); +} + +static int xlnx_axi_xvc_swd_run_queue(void) +{ + return xlnx_xvc_swd_run_queue(AXI); +} + +static int xlnx_xvc_swd_init(void) { return ERROR_OK; } static const struct swd_driver xlnx_pcie_xvc_swd_ops = { - .init = xlnx_pcie_xvc_swd_init, + .init = xlnx_xvc_swd_init, .switch_seq = xlnx_pcie_xvc_swd_switch_seq, .read_reg = xlnx_pcie_xvc_swd_read_reg, .write_reg = xlnx_pcie_xvc_swd_write_reg, .run = xlnx_pcie_xvc_swd_run_queue, }; +static const struct swd_driver xlnx_axi_xvc_swd_ops = { + .init = xlnx_xvc_swd_init, + .switch_seq = xlnx_axi_xvc_swd_switch_seq, + .read_reg = xlnx_axi_xvc_swd_read_reg, + .write_reg = xlnx_axi_xvc_swd_write_reg, + .run = xlnx_axi_xvc_swd_run_queue, +}; + struct adapter_driver xlnx_pcie_xvc_adapter_driver = { .name = "xlnx_pcie_xvc", .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, @@ -702,3 +998,16 @@ struct adapter_driver xlnx_pcie_xvc_adapter_driver = { .jtag_ops = &xlnx_pcie_xvc_jtag_ops, .swd_ops = &xlnx_pcie_xvc_swd_ops, }; + +struct adapter_driver xlnx_axi_xvc_adapter_driver = { + .name = "xlnx_axi_xvc", + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, + .commands = xlnx_axi_xvc_command_handlers, + + .init = &xlnx_axi_xvc_init, + .quit = &xlnx_axi_xvc_quit, + + .jtag_ops = &xlnx_axi_xvc_jtag_ops, + .swd_ops = &xlnx_axi_xvc_swd_ops, +}; diff --git a/src/jtag/drivers/xvc.c b/src/jtag/drivers/xvc.c new file mode 100644 index 0000000000..6e875e4815 --- /dev/null +++ b/src/jtag/drivers/xvc.c @@ -0,0 +1,747 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*************************************************************************** + * Copyright (C) 2021 by Jose Borja Castillo, DTE-UMA * + * joscassan@uma.es * + * * + * This implementation is XVC protocol 1.0/1.1 compatible. However * + * 1.1 extension instructions are not supported. * + * Protocol specs at: https://github.com/Xilinx/XilinxVirtualCable} * + * Some parts of the code are inspired on both bitbang and jlink * + * by Øyvind Harboe and Paul Fertser, respectively. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef _WIN32 +#include +#include +#include +#else +#include +#endif +#include "helper/bits.h" +#include "helper/replacements.h" +#include +#include +#include "helper/log.h" +#include +#include +#include +#include +#include +#include + +static char *xvc_host; +static char *xvc_port; +static uint32_t xvc_tck; + +static int xvc_fd; +static uint8_t *xvc_tms_buf; +static uint8_t *xvc_tdi_buf; +static uint8_t *xvc_send_buf; +static uint8_t *xvc_tdo_buf; +static uint32_t xvc_used_bits; + +// XVC implementation specifics. +static unsigned int xvc_max_vector_size; +// max_vector_size discounting command header. +static unsigned int xvc_max_usable_vector_size; + +struct shift_result { + // First bit position in TDO to read. + unsigned int first; + // Number of bits to read. + unsigned int length; + // Destination address to store the result + void *buffer; + // Offset in the destination buffer. + unsigned int buffer_offset; +}; +/* MAX_BUF_SIZE holds the maximum size that internal buffers are allowed to + be allocated. This parameter is limited by the size of an unsigned int + of 4 bytes. Unsigned int types are employed by several functions in OpenOCD, + like 'write_socket'. The offset of 11 bytes is set to ensure XVC commands + like 'shift' in deed fit inside the aforementioned buffers. + */ +#define MAX_BUF_SIZE (BIT(31) - 11) +#define MAX_SHIFT_RESULTS 256 +static unsigned int last_used_bits; +static unsigned int pending_shift_results; +static struct shift_result shift_result_buffer[MAX_SHIFT_RESULTS]; + +static int xvc_set_tck(void); +static int xvc_fill_buffer(void); + +static unsigned int xvc_bits_to_bytes(unsigned int bits) +{ + return DIV_ROUND_UP(bits, 8); +} + +static int xvc_speed(int speed) +{ + // Converts TCK speed in kHz to ns. + xvc_tck = 1000000 / speed; + // Changes default speed to adapter speed + return xvc_set_tck(); +} + +static int xvc_speed_div(int speed, int *khz) +{ + *khz = speed; + + return ERROR_OK; +} + +static int xvc_khz(int khz, int *jtag_speed) +{ + *jtag_speed = khz; + + return ERROR_OK; +} + +static int read_frame(int sock_id, unsigned char *ptr, unsigned int size) +{ + unsigned int i = size; + while (i > 0) { + int state = read_socket(sock_id, ptr, i); + if (state == 0) { + LOG_ERROR("No data available in socket at %s", __func__); + return ERROR_FAIL; + } + if (state < 0) { + LOG_ERROR("Reading error in %s", __func__); + return ERROR_FAIL; + } + ptr += state; + i -= state; + } + return ERROR_OK; +} + +static int xvc_flush(void) +{ + if (!xvc_used_bits) { + // Nothing to send, so we don't expect any bit back either. + last_used_bits = 0; + LOG_DEBUG_IO("XVC flush: no bits to flush"); + return ERROR_OK; + } + + // Converts bits to bytes, to reckon how many bytes we should send. + unsigned int number_of_bytes = xvc_bits_to_bytes(xvc_used_bits); + // Creates the header. + const char *shift = "shift:"; + size_t shift_len = strlen(shift); + size_t cp_offset = 0; + // Copies the header. + memcpy(xvc_send_buf + cp_offset, shift, shift_len); + // Updates the offset. + cp_offset += shift_len; + // Copies number of bytes. + h_u32_to_le(xvc_send_buf + cp_offset, xvc_used_bits); + cp_offset += sizeof(xvc_used_bits); + // Copies TMS vector. + memcpy(xvc_send_buf + cp_offset, xvc_tms_buf, number_of_bytes); + cp_offset += number_of_bytes; + // Copies TDI vector. + memcpy(xvc_send_buf + cp_offset, xvc_tdi_buf, number_of_bytes); + cp_offset += number_of_bytes; + // Updates the number of bytes used. + LOG_DEBUG_IO("XVC flush: cp_offset: %zu", cp_offset); + LOG_DEBUG_IO("XVC flush: used_bits: %d", xvc_used_bits); + + int written = write_socket(xvc_fd, xvc_send_buf, cp_offset); + if (written != (int)cp_offset) { + LOG_ERROR("Error writing socket in %s", __func__); + return ERROR_FAIL; + } + + memset(xvc_tms_buf, 0, xvc_max_usable_vector_size / 2); + memset(xvc_tdi_buf, 0, xvc_max_usable_vector_size / 2); + last_used_bits = xvc_used_bits; + xvc_used_bits = 0; + + return ERROR_OK; +} + +static int xvc_queue(const uint8_t *tms, unsigned int tms_offset, const uint8_t *tdi, + unsigned int tdi_offset, uint8_t *tdo, unsigned int tdo_offset, unsigned int length) +{ + do { + unsigned int available_length = + (xvc_max_usable_vector_size / 2) - (xvc_used_bits / 8); + if (!available_length || pending_shift_results >= MAX_SHIFT_RESULTS) { + xvc_flush(); + xvc_fill_buffer(); + } + + struct shift_result *shift_result = + &shift_result_buffer[pending_shift_results]; + unsigned int scan_length = + length > available_length ? available_length : length; + if (tdi) + buf_set_buf(tdi, tdi_offset, xvc_tdi_buf, xvc_used_bits, scan_length); + if (tms) + buf_set_buf(tms, tms_offset, xvc_tms_buf, xvc_used_bits, scan_length); + if (tdo) { + shift_result->buffer = tdo; + shift_result->buffer_offset = tdo_offset; + shift_result->first = xvc_used_bits; + shift_result->length = scan_length; + pending_shift_results++; + } + xvc_used_bits += scan_length; + tdi_offset += scan_length; + tms_offset += scan_length; + tdo_offset += scan_length; + length -= scan_length; + } while (length > 0); + + return ERROR_OK; +} + +static int xvc_getinfo(void) +{ + const char *getinfo = "getinfo:"; + size_t len = strlen(getinfo); + int written = write_socket(xvc_fd, getinfo, len); + + if (written != (int)len) { + LOG_ERROR("%s: write", __func__); + return ERROR_FAIL; + } + /* + Response is: xvcServer_vMajor.Minor: \n + Example: xvcServer_v1.0: 4096\n + Max vector size is in bits and represented in unsigned int (4 bytes). + Thus, maximum representable size is 2^32 -1 = 4294967295 bits. This occupies + 10 characters. + */ + char info_recv_buf[26] = {0}; + // Byte read until '\n' or buffer full. + unsigned long idx = 0; + while (idx < sizeof(info_recv_buf) - 1) { + int ret = read_socket(xvc_fd, &info_recv_buf[idx], 1); + if (ret <= 0) { + LOG_ERROR("%s: read", __func__); + return ERROR_FAIL; + } + if (info_recv_buf[idx] == '\n') + break; + idx++; + } + info_recv_buf[idx] = '\0'; + // Check xvcServer_v1.0: or xvcServer_v1.1: Although 1.1 extensions are not supported. + if (strncmp(info_recv_buf, "xvcServer_v1.0:", 15) != 0 && + strncmp(info_recv_buf, "xvcServer_v1.1:", 15) != 0) { + LOG_ERROR("Unexpected response from XVC server_ %s", info_recv_buf); + return ERROR_FAIL; + } + LOG_INFO("XVC HW server version: %s", info_recv_buf); + xvc_max_usable_vector_size = strtoul(&info_recv_buf[15], NULL, 10); + if (xvc_max_usable_vector_size > MAX_BUF_SIZE) { + LOG_DEBUG("Exceeded maximum vector size, outputting to %lu bytes", + MAX_BUF_SIZE); + xvc_max_usable_vector_size = MAX_BUF_SIZE; + } + xvc_max_vector_size = xvc_max_usable_vector_size + 10; + LOG_DEBUG("Maximum vector size set to: %u", xvc_max_vector_size); + /* Usable size: maximum vector size determined by the server minus the + sizeof the command, 10 bytes in worst-case (6 bytes from shift: and 4 + additional ones for bit_length).*/ + // Updates TX Buffer sizes: + xvc_send_buf = malloc(xvc_max_vector_size * sizeof(uint8_t)); + xvc_tms_buf = malloc(xvc_max_usable_vector_size / 2 * sizeof(uint8_t)); + xvc_tdi_buf = malloc(xvc_max_usable_vector_size / 2 * sizeof(uint8_t)); + xvc_tdo_buf = malloc(xvc_max_usable_vector_size / 2 * sizeof(uint8_t)); + if (!xvc_send_buf || !xvc_tms_buf || !xvc_tdi_buf || !xvc_tdo_buf) { + LOG_ERROR("Out of memory"); + free(xvc_send_buf); + free(xvc_tms_buf); + free(xvc_tdi_buf); + free(xvc_tdo_buf); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int xvc_set_tck(void) +{ + /* Creates the command: + * copies the header and appends the value. + * */ + uint8_t set_tck[12]; + const char *header = "settck:"; + memcpy(set_tck, header, strlen(header)); + h_u32_to_le(set_tck + strlen(header), xvc_tck); + int written = write_socket(xvc_fd, set_tck, 11); + if (written != 11) { + LOG_ERROR("%s: write", __func__); + return ERROR_FAIL; + } + uint32_t tck_recv_buf; + int read = read_socket(xvc_fd, &tck_recv_buf, sizeof(tck_recv_buf)); + if (read < 0) { + LOG_ERROR("%s: read", __func__); + return ERROR_FAIL; + } + // Prints response, regardless of machine endianness. + uint32_t xvc_tck_period_ns; + xvc_tck_period_ns = le_to_h_u32((uint8_t *)&tck_recv_buf); + LOG_INFO("XVC tck period ns: %u", xvc_tck_period_ns); + return ERROR_OK; +} + +static int xvc_fill_buffer(void) +{ + if (read_frame(xvc_fd, xvc_tdo_buf, xvc_bits_to_bytes(last_used_bits)) != ERROR_OK) { + LOG_ERROR("Read_frame"); + return ERROR_FAIL; + } + for (unsigned int i = 0; i < pending_shift_results; i++) { + struct shift_result *shift_result = &shift_result_buffer[i]; + buf_set_buf(xvc_tdo_buf, shift_result->first, shift_result->buffer, + shift_result->buffer_offset, shift_result->length); + } + memset(xvc_tdo_buf, 0, xvc_max_usable_vector_size / 2); + pending_shift_results = 0; + return ERROR_OK; +} + +static int xvc_reset(int trst, int srst) +{ + // XVC does not have dedicated Reset lines. + static bool first_time = true; + if (first_time) { + LOG_WARNING("Adapter has no reset lines. Fix \"reset_config\" command in " + "config file"); + first_time = false; + } + return ERROR_OK; +} + +static int xvc_init_tcp(int *fd) +{ + LOG_INFO("Connecting to %s:%s", xvc_host ? xvc_host : "localhost", xvc_port); + + const struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM + }; + + struct addrinfo *result; + // Obtain address(es) matching host/port. + int s = getaddrinfo(xvc_host, xvc_port, &hints, &result); + if (s != 0) { + LOG_ERROR("getaddrinfo: %s", gai_strerror(s)); + return ERROR_FAIL; + } + + /* getaddrinfo() returns a list of address structures. + Try each address until we successfully connect(2). + If socket(2) (or connect(2)) fails, we (close the socket + and) try the next address. */ + struct addrinfo *rp; + for (rp = result; rp; rp = rp->ai_next) { + *fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); +#ifndef _WIN32 + if (*fd == -1) + continue; +#else + if (*fd == (int)INVALID_SOCKET) + continue; +#endif + if (connect(*fd, rp->ai_addr, rp->ai_addrlen) != -1) + break; + + close_socket(*fd); + } + + freeaddrinfo(result); + + if (!rp) { + LOG_ERROR("Failed to connect"); + return ERROR_FAIL; + } + + /* 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)); + + return ERROR_OK; +} + +static int xvc_init_unix(int *fd) +{ + if (!xvc_host) { + LOG_ERROR("host/socket not specified"); + return ERROR_FAIL; + } + + LOG_INFO("Connecting to unix socket %s", xvc_host); + *fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (*fd < 0) { + LOG_ERROR("socket"); + return ERROR_FAIL; + } + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, xvc_host, sizeof(addr.sun_path)); + addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; + + if (connect(*fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { + LOG_ERROR("connect"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +// COMMAND HANDLERS +COMMAND_HANDLER(xvc_handle_port_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + uint16_t port; + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port); + free(xvc_port); + xvc_port = (port == 0) ? NULL : strdup(CMD_ARGV[0]); + return ERROR_OK; +} + +COMMAND_HANDLER(xvc_handle_host_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + free(xvc_host); + xvc_host = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + +static const struct command_registration xvc_subcommand_handlers[] = { + { + .name = "port", + .handler = xvc_handle_port_command, + .mode = COMMAND_CONFIG, + .help = + "Set the port to use to connect to the XVC remote server.\n" + " If 0 or unset, use unix sockets to connect to the remote server.", + .usage = "port_number", + }, + { + .name = "host", + .handler = xvc_handle_host_command, + .mode = COMMAND_CONFIG, + .help = "Set the host to use or UNIX socket to connect to the remote XVC server.", + .usage = "host_name", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration xvc_command_handlers[] = { + { + .name = "xvc", + .mode = COMMAND_ANY, + .help = "perform XVC driver configuration", + .chain = xvc_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static int xvc_init(void) +{ + xvc_used_bits = 0; + last_used_bits = 0; + pending_shift_results = 0; + // Default clock: 1000 ns period. + xvc_tck = 1000; + + LOG_DEBUG("Initializing XVC driver"); + int ret; + + if (!xvc_port) + ret = xvc_init_unix(&xvc_fd); + else + ret = xvc_init_tcp(&xvc_fd); + + if (ret != ERROR_OK) + return ret; + + ret = xvc_getinfo(); + if (ret != ERROR_OK) + return ret; + + ret = xvc_set_tck(); + if (ret != ERROR_OK) + return ret; + + LOG_DEBUG("XVC driver initialized"); + + return ERROR_OK; +} + +static int xvc_quit(void) +{ + if (close_socket(xvc_fd) != 0) { + LOG_ERROR("close_socket"); + return ERROR_FAIL; + } + free(xvc_port); + free(xvc_host); + free(xvc_tms_buf); + free(xvc_tdi_buf); + free(xvc_send_buf); + free(xvc_tdo_buf); + return ERROR_OK; +} + +// The driver leaves the TCK 0 when in idle. +static void xvc_tap_end_state(enum tap_state state) +{ + assert(tap_is_state_stable(state)); + tap_set_end_state(state); +} + +static int xvc_tap_state_move(int skip) +{ + uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + xvc_queue(&tms_scan, 0, NULL, 0, NULL, 0, tms_count); + + tap_set_state(tap_get_end_state()); + return ERROR_OK; +} + +/* + * Clock a bunch of TMS transitions, to change the JTAG + * state machine. "Legacy enqueue" + */ +static int xvc_tap_execute_tms(struct jtag_command *cmd) +{ + unsigned int num_bits = cmd->cmd.tms->num_bits; + const uint8_t *bits = cmd->cmd.tms->bits; + + LOG_DEBUG_IO("TMS: %d bits", num_bits); + + for (unsigned int i = 0; i < num_bits; i++) { + uint8_t tms = 0; + tms = ((bits[i / 8] >> (i % 8)) & 1); + if (xvc_queue(&tms, 0, NULL, 0, NULL, 0, 1) != ERROR_OK) + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int xvc_tap_path_move(struct pathmove_command *cmd) +{ + unsigned int num_states = cmd->num_states; + unsigned int state_count = 0; + uint8_t tms = 0xff; + + while (num_states) { + if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) { + xvc_queue(NULL, 0, NULL, 0, NULL, 0, 1); + } else if (tap_state_transition(tap_get_state(), true) == + cmd->path[state_count]) { + xvc_queue(&tms, 0, NULL, 0, NULL, 0, 1); + } else { + LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", + tap_state_name(tap_get_state()), + tap_state_name(cmd->path[state_count])); + return ERROR_FAIL; + } + + tap_set_state(cmd->path[state_count]); + state_count++; + num_states--; + } + + tap_set_end_state(tap_get_state()); + return ERROR_OK; +} + +static unsigned int xvc_tap_stableclocks(unsigned int num_cycles) +{ + uint8_t tms = (tap_get_state() == TAP_RESET ? 0xff : 0); + + for (unsigned int i = 0; i < num_cycles; i++) + xvc_queue(&tms, 0, NULL, 0, NULL, 0, 1); + + return ERROR_OK; +} + +static int xvc_tap_runtest(unsigned int num_cycles) +{ + enum tap_state 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) { + xvc_tap_end_state(TAP_IDLE); + if (xvc_tap_state_move(0) != ERROR_OK) + return ERROR_FAIL; + } + + xvc_tap_stableclocks(num_cycles); + + // finish in end_state. + xvc_tap_end_state(saved_end_state); + if (tap_get_state() != tap_get_end_state()) + if (xvc_tap_state_move(0) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static int xvc_tap_scan_write(struct scan_command *cmd) +{ + /* Make sure there are no trailing fields with num_bits == 0, or the logic + * below will fail. */ + while (cmd->num_fields > 0 && cmd->fields[cmd->num_fields - 1].num_bits == 0) { + cmd->num_fields--; + LOG_DEBUG("discarding trailing empty field"); + } + if (cmd->num_fields == 0) { + LOG_DEBUG("empty scan, doing nothing"); + return ERROR_OK; + } + + bool ir_scan = cmd->ir_scan; + if (ir_scan) { + if (tap_get_state() != TAP_IRSHIFT) { + tap_set_end_state(TAP_IRSHIFT); + xvc_tap_state_move(0); + } + } else { + if (tap_get_state() != TAP_DRSHIFT) { + xvc_tap_end_state(TAP_DRSHIFT); + xvc_tap_state_move(0); + } + } + xvc_tap_end_state(cmd->end_state); + + for (unsigned int i = 0; i < cmd->num_fields; i++) { + // Last field + if (i == (cmd->num_fields - 1) && tap_get_state() != tap_get_end_state()) { + // All bits except the last one. + xvc_queue(NULL, 0, cmd->fields[i].out_value, 0, cmd->fields[i].in_value, 0, + cmd->fields[i].num_bits - 1); + // Last bit to copy. + uint8_t last_bit = 0; + if (cmd->fields[i].out_value) + bit_copy(&last_bit, 0, cmd->fields[i].out_value, + cmd->fields[i].num_bits - 1, 1); + // TMS set to 1 to leave the current state. + uint8_t tms_bits = 0x01; + xvc_queue(&tms_bits, 0, &last_bit, 0, cmd->fields[i].in_value, + cmd->fields[i].num_bits - 1, 1); + tap_set_state(tap_state_transition(tap_get_state(), 1)); + xvc_queue(&tms_bits, 1, NULL, 0, NULL, 0, 1); + tap_set_state(tap_state_transition(tap_get_state(), 0)); + } else { + xvc_queue(NULL, 0, cmd->fields[i].out_value, 0, cmd->fields[i].in_value, 0, + cmd->fields[i].num_bits); + } + } + + if (tap_get_state() != tap_get_end_state()) { + /* we *KNOW* the above loop transitioned out of + * the shift state, so we skip the first state + * and move directly to the end state. + */ + + if (xvc_tap_state_move(0) != ERROR_OK) + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int xvc_tap_execute_queue(struct jtag_command *cmd_queue) +{ + struct jtag_command *cmd = cmd_queue; + + while (cmd) { + switch (cmd->type) { + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + xvc_tap_end_state(cmd->cmd.runtest->end_state); + if (xvc_tap_runtest(cmd->cmd.runtest->num_cycles) != ERROR_OK) + return ERROR_FAIL; + break; + case JTAG_STABLECLOCKS: + /* this is only allowed while in a stable state. A check for a stable + * state was done in jtag_add_clocks() + */ + if (xvc_tap_stableclocks(cmd->cmd.stableclocks->num_cycles) != ERROR_OK) + return ERROR_FAIL; + break; + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %s", + tap_state_name(cmd->cmd.statemove->end_state)); + xvc_tap_end_state(cmd->cmd.statemove->end_state); + if (xvc_tap_state_move(0) != ERROR_OK) + return ERROR_FAIL; + break; + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %i states, end in %s", + cmd->cmd.pathmove->num_states, + tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); + if (xvc_tap_path_move(cmd->cmd.pathmove) != ERROR_OK) + return ERROR_FAIL; + break; + case JTAG_SCAN: + if (xvc_tap_scan_write(cmd->cmd.scan) != ERROR_OK) + return ERROR_FAIL; + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIi32, cmd->cmd.sleep->us); + // Flush the cmd FIFO before entering sleep to keep timing. + xvc_flush(); + jtag_sleep(cmd->cmd.sleep->us); + break; + case JTAG_TMS: + if (xvc_tap_execute_tms(cmd) != ERROR_OK) + return ERROR_FAIL; + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + return ERROR_FAIL; + } + cmd = cmd->next; + } + + if (xvc_flush() != ERROR_OK) + return ERROR_FAIL; + if (xvc_fill_buffer() != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static struct jtag_interface xvc_interface = { + .execute_queue = &xvc_tap_execute_queue, + .supported = DEBUG_CAP_TMS_SEQ, +}; + +struct adapter_driver xvc_adapter_driver = { + .name = "xvc", + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, + .commands = xvc_command_handlers, + .init = xvc_init, + .quit = xvc_quit, + .reset = &xvc_reset, + .speed = &xvc_speed, + .khz = &xvc_khz, + .speed_div = &xvc_speed_div, + .jtag_ops = &xvc_interface, +}; diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index a9d196ccec..9fa1df92ca 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -26,8 +26,6 @@ static struct hl_interface hl_if = { .param = { .device_desc = NULL, - .vid = { 0 }, - .pid = { 0 }, .transport = HL_TRANSPORT_UNKNOWN, .connect_under_reset = false, .use_stlink_tcp = false, @@ -248,33 +246,6 @@ COMMAND_HANDLER(hl_interface_handle_layout_command) return ERROR_FAIL; } -COMMAND_HANDLER(hl_interface_handle_vid_pid_command) -{ - if (CMD_ARGC > HLA_MAX_USB_IDS * 2) { - LOG_WARNING("ignoring extra IDs in hla_vid_pid " - "(maximum is %d pairs)", HLA_MAX_USB_IDS); - CMD_ARGC = HLA_MAX_USB_IDS * 2; - } - if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { - LOG_WARNING("incomplete hla_vid_pid configuration directive"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - unsigned int i; - for (i = 0; i < CMD_ARGC; i += 2) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], hl_if.param.vid[i / 2]); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], hl_if.param.pid[i / 2]); - } - - /* - * Explicitly terminate, in case there are multiple instances of - * hla_vid_pid. - */ - hl_if.param.vid[i / 2] = hl_if.param.pid[i / 2] = 0; - - return ERROR_OK; -} - COMMAND_HANDLER(hl_interface_handle_stlink_backend_command) { /* default values */ @@ -330,13 +301,6 @@ static const struct command_registration hl_interface_subcommand_handlers[] = { .help = "set the layout of the adapter", .usage = "layout_name", }, - { - .name = "vid_pid", - .handler = &hl_interface_handle_vid_pid_command, - .mode = COMMAND_CONFIG, - .help = "the vendor and product ID of the adapter", - .usage = "(vid pid)*", - }, { .name = "stlink_backend", .handler = &hl_interface_handle_stlink_backend_command, diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index c0ee05498d..8701c033ab 100644 --- a/src/jtag/hla/hla_interface.h +++ b/src/jtag/hla/hla_interface.h @@ -21,10 +21,6 @@ enum e_hl_transports; struct hl_interface_param { /** */ const char *device_desc; - /** List of recognised VIDs */ - uint16_t vid[HLA_MAX_USB_IDS + 1]; - /** List of recognised PIDs */ - uint16_t pid[HLA_MAX_USB_IDS + 1]; /** */ enum hl_transports transport; /** */ diff --git a/src/jtag/hla/hla_transport.c b/src/jtag/hla/hla_transport.c index d8ece0776b..50d2d3e21b 100644 --- a/src/jtag/hla/hla_transport.c +++ b/src/jtag/hla/hla_transport.c @@ -41,7 +41,7 @@ static const struct command_registration hl_swd_transport_subcommand_handlers[] .help = "declare a new SWD DAP", .usage = "basename dap_type ['-irlen' count] " "['-enable'|'-disable'] " - "['-expected_id' number] " + "['-expected-id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " @@ -71,7 +71,7 @@ static const struct command_registration hl_transport_jtag_subcommand_handlers[] "and appends it to the scan chain.", .usage = "basename tap_type '-irlen' count " "['-enable'|'-disable'] " - "['-expected_id' number] " + "['-expected-id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " diff --git a/src/jtag/interface.c b/src/jtag/interface.c index 92c88ca934..23b5bcf4f1 100644 --- a/src/jtag/interface.c +++ b/src/jtag/interface.c @@ -67,28 +67,28 @@ int tap_move_ndx(enum tap_state astate) int ndx; switch (astate) { - case TAP_RESET: - ndx = 0; - break; - case TAP_IDLE: - ndx = 1; - break; - case TAP_DRSHIFT: - ndx = 2; - break; - case TAP_DRPAUSE: - ndx = 3; - break; - case TAP_IRSHIFT: - ndx = 4; - break; - case TAP_IRPAUSE: - ndx = 5; - break; - default: - LOG_ERROR("FATAL: unstable state \"%s\" in tap_move_ndx()", - tap_state_name(astate)); - exit(1); + case TAP_RESET: + ndx = 0; + break; + case TAP_IDLE: + ndx = 1; + break; + case TAP_DRSHIFT: + ndx = 2; + break; + case TAP_DRPAUSE: + ndx = 3; + break; + case TAP_IRSHIFT: + ndx = 4; + break; + case TAP_IRPAUSE: + ndx = 5; + break; + default: + LOG_ERROR("FATAL: unstable state \"%s\" in %s()", + tap_state_name(astate), __func__); + exit(1); } return ndx; @@ -205,16 +205,16 @@ bool tap_is_state_stable(enum tap_state astate) * (not value dependent like an array), and can also check bounds. */ switch (astate) { - case TAP_RESET: - case TAP_IDLE: - case TAP_DRSHIFT: - case TAP_DRPAUSE: - case TAP_IRSHIFT: - case TAP_IRPAUSE: - is_stable = true; - break; - default: - is_stable = false; + case TAP_RESET: + case TAP_IDLE: + case TAP_DRSHIFT: + case TAP_DRPAUSE: + case TAP_IRSHIFT: + case TAP_IRPAUSE: + is_stable = true; + break; + default: + is_stable = false; } return is_stable; @@ -230,83 +230,83 @@ enum tap_state tap_state_transition(enum tap_state cur_state, bool tms) if (tms) { switch (cur_state) { - case TAP_RESET: - new_state = cur_state; - break; - case TAP_IDLE: - case TAP_DRUPDATE: - case TAP_IRUPDATE: - new_state = TAP_DRSELECT; - break; - case TAP_DRSELECT: - new_state = TAP_IRSELECT; - break; - case TAP_DRCAPTURE: - case TAP_DRSHIFT: - new_state = TAP_DREXIT1; - break; - case TAP_DREXIT1: - case TAP_DREXIT2: - new_state = TAP_DRUPDATE; - break; - case TAP_DRPAUSE: - new_state = TAP_DREXIT2; - break; - case TAP_IRSELECT: - new_state = TAP_RESET; - break; - case TAP_IRCAPTURE: - case TAP_IRSHIFT: - new_state = TAP_IREXIT1; - break; - case TAP_IREXIT1: - case TAP_IREXIT2: - new_state = TAP_IRUPDATE; - break; - case TAP_IRPAUSE: - new_state = TAP_IREXIT2; - break; - default: - LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); - exit(1); - break; + case TAP_RESET: + new_state = cur_state; + break; + case TAP_IDLE: + case TAP_DRUPDATE: + case TAP_IRUPDATE: + new_state = TAP_DRSELECT; + break; + case TAP_DRSELECT: + new_state = TAP_IRSELECT; + break; + case TAP_DRCAPTURE: + case TAP_DRSHIFT: + new_state = TAP_DREXIT1; + break; + case TAP_DREXIT1: + case TAP_DREXIT2: + new_state = TAP_DRUPDATE; + break; + case TAP_DRPAUSE: + new_state = TAP_DREXIT2; + break; + case TAP_IRSELECT: + new_state = TAP_RESET; + break; + case TAP_IRCAPTURE: + case TAP_IRSHIFT: + new_state = TAP_IREXIT1; + break; + case TAP_IREXIT1: + case TAP_IREXIT2: + new_state = TAP_IRUPDATE; + break; + case TAP_IRPAUSE: + new_state = TAP_IREXIT2; + break; + default: + LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); + exit(1); + break; } } else { switch (cur_state) { - case TAP_RESET: - case TAP_IDLE: - case TAP_DRUPDATE: - case TAP_IRUPDATE: - new_state = TAP_IDLE; - break; - case TAP_DRSELECT: - new_state = TAP_DRCAPTURE; - break; - case TAP_DRCAPTURE: - case TAP_DRSHIFT: - case TAP_DREXIT2: - new_state = TAP_DRSHIFT; - break; - case TAP_DREXIT1: - case TAP_DRPAUSE: - new_state = TAP_DRPAUSE; - break; - case TAP_IRSELECT: - new_state = TAP_IRCAPTURE; - break; - case TAP_IRCAPTURE: - case TAP_IRSHIFT: - case TAP_IREXIT2: - new_state = TAP_IRSHIFT; - break; - case TAP_IREXIT1: - case TAP_IRPAUSE: - new_state = TAP_IRPAUSE; - break; - default: - LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); - exit(1); - break; + case TAP_RESET: + case TAP_IDLE: + case TAP_DRUPDATE: + case TAP_IRUPDATE: + new_state = TAP_IDLE; + break; + case TAP_DRSELECT: + new_state = TAP_DRCAPTURE; + break; + case TAP_DRCAPTURE: + case TAP_DRSHIFT: + case TAP_DREXIT2: + new_state = TAP_DRSHIFT; + break; + case TAP_DREXIT1: + case TAP_DRPAUSE: + new_state = TAP_DRPAUSE; + break; + case TAP_IRSELECT: + new_state = TAP_IRCAPTURE; + break; + case TAP_IRCAPTURE: + case TAP_IRSHIFT: + case TAP_IREXIT2: + new_state = TAP_IRSHIFT; + break; + case TAP_IREXIT1: + case TAP_IRPAUSE: + new_state = TAP_IRPAUSE; + break; + default: + LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); + exit(1); + break; } } diff --git a/src/jtag/interface.h b/src/jtag/interface.h index 475dbed36e..d5f6d747f0 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -371,6 +371,7 @@ 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); +// Keep in alphabetic order this list of drivers extern struct adapter_driver am335xgpio_adapter_driver; extern struct adapter_driver amt_jtagaccel_adapter_driver; extern struct adapter_driver angie_adapter_driver; @@ -378,6 +379,8 @@ 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 ch347_adapter_driver; +extern struct adapter_driver cklink_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; @@ -410,6 +413,8 @@ 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_axi_xvc_adapter_driver; extern struct adapter_driver xlnx_pcie_xvc_adapter_driver; +extern struct adapter_driver xvc_adapter_driver; #endif /* OPENOCD_JTAG_INTERFACE_H */ diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index e49bd9e0f3..657b1b310f 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -36,125 +36,138 @@ * drivers that were enabled by the @c configure script. */ struct adapter_driver *adapter_drivers[] = { -#if BUILD_PARPORT == 1 - &parport_adapter_driver, + // Keep in alphabetic order this list of drivers + +#if BUILD_AM335XGPIO == 1 + &am335xgpio_adapter_driver, #endif -#if BUILD_DUMMY == 1 - &dummy_adapter_driver, +#if BUILD_AMTJTAGACCEL == 1 + &amt_jtagaccel_adapter_driver, #endif -#if BUILD_FTDI == 1 - &ftdi_adapter_driver, +#if BUILD_ANGIE == 1 + &angie_adapter_driver, #endif -#if BUILD_USB_BLASTER || BUILD_USB_BLASTER_2 == 1 - &usb_blaster_adapter_driver, +#if BUILD_ARMJTAGEW == 1 + &armjtagew_adapter_driver, #endif -#if BUILD_ESP_USB_JTAG == 1 - &esp_usb_adapter_driver, +#if BUILD_AT91RM9200 == 1 + &at91rm9200_adapter_driver, #endif -#if BUILD_JTAG_VPI == 1 - &jtag_vpi_adapter_driver, +#if BUILD_BCM2835GPIO == 1 + &bcm2835gpio_adapter_driver, #endif -#if BUILD_VDEBUG == 1 - &vdebug_adapter_driver, +#if BUILD_BUS_PIRATE == 1 + &buspirate_adapter_driver, #endif -#if BUILD_JTAG_DPI == 1 - &jtag_dpi_adapter_driver, +#if BUILD_CH347 == 1 + &ch347_adapter_driver, #endif -#if BUILD_FT232R == 1 - &ft232r_adapter_driver, +#if BUILD_CKLINK == 1 + &cklink_adapter_driver, #endif -#if BUILD_AMTJTAGACCEL == 1 - &amt_jtagaccel_adapter_driver, +#if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1 || BUILD_CMSIS_DAP_TCP == 1 + &cmsis_dap_adapter_driver, +#endif +#if BUILD_DMEM == 1 + &dmem_dap_adapter_driver, +#endif +#if BUILD_DUMMY == 1 + &dummy_adapter_driver, #endif #if BUILD_EP93XX == 1 &ep93xx_adapter_driver, #endif -#if BUILD_AT91RM9200 == 1 - &at91rm9200_adapter_driver, +#if BUILD_ESP_USB_JTAG == 1 + &esp_usb_adapter_driver, +#endif +#if BUILD_FT232R == 1 + &ft232r_adapter_driver, +#endif +#if BUILD_FTDI == 1 + &ftdi_adapter_driver, #endif #if BUILD_GW16012 == 1 &gw16012_adapter_driver, #endif -#if BUILD_PRESTO - &presto_adapter_driver, -#endif -#if BUILD_USBPROG == 1 - &usbprog_adapter_driver, +#if BUILD_HLADAPTER == 1 + &hl_adapter_driver, #endif -#if BUILD_OPENJTAG == 1 - &openjtag_adapter_driver, +#if BUILD_IMX_GPIO == 1 + &imx_gpio_adapter_driver, #endif #if BUILD_JLINK == 1 &jlink_adapter_driver, #endif -#if BUILD_VSLLINK == 1 - &vsllink_adapter_driver, +#if BUILD_JTAG_DPI == 1 + &jtag_dpi_adapter_driver, #endif -#if BUILD_RLINK == 1 - &rlink_adapter_driver, +#if BUILD_JTAG_VPI == 1 + &jtag_vpi_adapter_driver, #endif -#if BUILD_ULINK == 1 - &ulink_adapter_driver, +#if BUILD_KITPROG == 1 + &kitprog_adapter_driver, #endif -#if BUILD_ANGIE == 1 - &angie_adapter_driver, +#if BUILD_LINUXGPIOD == 1 + &linuxgpiod_adapter_driver, #endif -#if BUILD_ARMJTAGEW == 1 - &armjtagew_adapter_driver, +#if BUILD_LINUXSPIDEV == 1 + &linuxspidev_adapter_driver, #endif -#if BUILD_BUS_PIRATE == 1 - &buspirate_adapter_driver, +#if BUILD_OPENDOUS == 1 + &opendous_adapter_driver, +#endif +#if BUILD_OPENJTAG == 1 + &openjtag_adapter_driver, +#endif +#if BUILD_OSBDM == 1 + &osbdm_adapter_driver, +#endif +#if BUILD_PARPORT == 1 + &parport_adapter_driver, +#endif +#if BUILD_PRESTO == 1 + &presto_adapter_driver, #endif #if BUILD_REMOTE_BITBANG == 1 &remote_bitbang_adapter_driver, #endif -#if BUILD_HLADAPTER == 1 - &hl_adapter_driver, +#if BUILD_RLINK == 1 + &rlink_adapter_driver, #endif -#if BUILD_OSBDM == 1 - &osbdm_adapter_driver, +#if BUILD_RSHIM == 1 + &rshim_dap_adapter_driver, #endif -#if BUILD_OPENDOUS == 1 - &opendous_adapter_driver, +#if BUILD_HLADAPTER_STLINK == 1 + &stlink_dap_adapter_driver, #endif #if BUILD_SYSFSGPIO == 1 &sysfsgpio_adapter_driver, #endif -#if BUILD_LINUXGPIOD == 1 - &linuxgpiod_adapter_driver, -#endif -#if BUILD_LINUXSPIDEV == 1 - &linuxspidev_adapter_driver, -#endif -#if BUILD_XLNX_PCIE_XVC == 1 - &xlnx_pcie_xvc_adapter_driver, +#if BUILD_ULINK == 1 + &ulink_adapter_driver, #endif -#if BUILD_BCM2835GPIO == 1 - &bcm2835gpio_adapter_driver, +#if BUILD_USB_BLASTER == 1 || BUILD_USB_BLASTER_2 == 1 + &usb_blaster_adapter_driver, #endif -#if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1 - &cmsis_dap_adapter_driver, +#if BUILD_USBPROG == 1 + &usbprog_adapter_driver, #endif -#if BUILD_KITPROG == 1 - &kitprog_adapter_driver, +#if BUILD_VDEBUG == 1 + &vdebug_adapter_driver, #endif -#if BUILD_IMX_GPIO == 1 - &imx_gpio_adapter_driver, +#if BUILD_VSLLINK == 1 + &vsllink_adapter_driver, #endif #if BUILD_XDS110 == 1 &xds110_adapter_driver, #endif -#if BUILD_HLADAPTER_STLINK == 1 - &stlink_dap_adapter_driver, +#if BUILD_XLNX_XVC == 1 + &xlnx_pcie_xvc_adapter_driver, + &xlnx_axi_xvc_adapter_driver, #endif -#if BUILD_RSHIM == 1 - &rshim_dap_adapter_driver, -#endif -#if BUILD_DMEM == 1 - &dmem_dap_adapter_driver, -#endif -#if BUILD_AM335XGPIO == 1 - &am335xgpio_adapter_driver, + +#if BUILD_XVC == 1 + &xvc_adapter_driver, #endif NULL, - }; +}; diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index c04daa835f..664c720cac 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -241,6 +241,13 @@ proc interface_list args { eval adapter list $args } +lappend _telnet_autocomplete_skip "espusbjtag vid_pid" +proc "espusbjtag vid_pid" args { + echo "DEPRECATED! use 'adapter usb vid_pid' not 'espusbjtag vid_pid'" + eval adapter usb vid_pid $args +} + + lappend _telnet_autocomplete_skip ftdi_location proc ftdi_location args { echo "DEPRECATED! use 'adapter usb location' not 'ftdi_location'" @@ -269,10 +276,16 @@ proc "hla newtap" {args} { eval swj_newdap $args } +lappend _telnet_autocomplete_skip "ftdi device_desc" +proc "ftdi device_desc" args { + echo "DEPRECATED! use 'adapter usb product_name' not 'ftdi device_desc'" + eval adapter usb product_name $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 + echo "DEPRECATED! use 'adapter usb product_name' not 'ftdi_device_desc'" + eval adapter usb product_name $args } lappend _telnet_autocomplete_skip ftdi_serial @@ -313,8 +326,14 @@ proc 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 + echo "DEPRECATED! use 'adapter usb vid_pid' not 'ftdi_vid_pid'" + eval adapter usb vid_pid $args +} + +lappend _telnet_autocomplete_skip "ftdi vid_pid" +proc "ftdi vid_pid" args { + echo "DEPRECATED! use 'adapter usb vid_pid' not 'ftdi vid_pid'" + eval adapter usb vid_pid $args } lappend _telnet_autocomplete_skip ftdi_tdo_sample_edge @@ -335,10 +354,16 @@ proc remote_bitbang_port args { eval remote_bitbang port $args } +lappend _telnet_autocomplete_skip openjtag_device_desc +proc "openjtag device_desc" args { + echo "DEPRECATED! use 'adapter usb product_name' not 'openjtag device_desc'" + eval adapter usb product_name $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 + echo "DEPRECATED! use 'adapter usb product_name' not 'openjtag_device_desc'" + eval adapter usb product_name $args } lappend _telnet_autocomplete_skip openjtag_variant @@ -359,6 +384,27 @@ proc parport_cable args { eval parport cable $args } +lappend _telnet_autocomplete_skip parport_select_cable +proc parport_select_cable {cable} { + echo "DEPRECATED! Do not use 'parport cable' but use a cable configuration file in interface/parport" + + switch $cable { + "wiggler" { source [find interface/parport/wiggler.cfg] } + "wiggler2" { source [find interface/parport/wiggler2.cfg] } + "wiggler_ntrst_inverted" { source [find interface/parport/wiggler-ntrst-inverted.cfg] } + "old_amt_wiggler" { source [find interface/parport/amt-wiggler-old.cfg ] } + "arm-jtag" { source [find interface/parport/arm-jtag.cfg] } + "chameleon" { source [find interface/parport/chameleon.cfg] } + "dlc5" { source [find interface/parport/dlc5.cfg] } + "triton" { source [find interface/parport/triton.cfg] } + "lattice" { source [find interface/parport/lattice.cfg] } + "flashlink" { source [find interface/parport/flashlink.cfg] } + "altium" { source [find interface/parport/altium.cfg] } + "aspo" { source [find interface/parport/aspo.cfg] } + default { error "invalid parallel port cable '$cable'" } + } +} + 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'" @@ -413,6 +459,12 @@ proc xlnx_pcie_xvc_config args { eval xlnx_pcie_xvc config $args } +lappend _telnet_autocomplete_skip xlnx_axi_xvc_config +proc xlnx_axi_xvc_config args { + echo "DEPRECATED! use 'xlnx_axi_xvc config' not 'xlnx_axi_xvc_config'" + eval xlnx_axi_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'" @@ -783,8 +835,14 @@ proc 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 + echo "DEPRECATED! use 'adapter usb vid_pid' not 'usb_blaster_vid_pid'" + eval adapter usb vid_pid $args +} + +lappend _telnet_autocomplete_skip "usb_blaster vid_pid" +proc "usb_blaster vid_pid" args { + echo "DEPRECATED! use 'adapter usb vid_pid' not 'usb_blaster vid_pid'" + eval adapter usb vid_pid $args } lappend _telnet_autocomplete_skip usb_blaster_lowlevel_driver @@ -813,8 +871,14 @@ proc ft232r_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 + echo "DEPRECATED! use 'adapter usb vid_pid' not 'ft232r_vid_pid'" + eval adapter usb vid_pid $args +} + +lappend _telnet_autocomplete_skip "ft232r vid_pid" +proc "ft232r vid_pid" args { + echo "DEPRECATED! use 'adapter usb vid_pid' not 'ft232r vid_pid'" + eval adapter usb vid_pid $args } lappend _telnet_autocomplete_skip ft232r_jtag_nums @@ -1116,8 +1180,8 @@ proc "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 + echo "DEPRECATED! use 'adapter usb vid_pid', not 'cmsis_dap_vid_pid'" + eval adapter usb vid_pid $args } lappend _telnet_autocomplete_skip "cmsis_dap_usb" @@ -1140,8 +1204,8 @@ proc "hla_device_desc" {desc} { lappend _telnet_autocomplete_skip "hla_vid_pid" proc "hla_vid_pid" {args} { - echo "DEPRECATED! use 'hla vid_pid', not 'hla_vid_pid'" - eval hla vid_pid $args + echo "DEPRECATED! use 'adapter usb vid_pid', not 'hla_vid_pid'" + eval adapter usb vid_pid $args } lappend _telnet_autocomplete_skip "hla_command" @@ -1156,6 +1220,12 @@ proc "hla_stlink_backend" {args} { eval hla stlink_backend $args } +lappend _telnet_autocomplete_skip "st-link vid_pid" +proc "st-link vid_pid" {args} { + echo "DEPRECATED! use 'adapter usb vid_pid', not 'st-link vid_pid'" + eval adapter usb vid_pid $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'" @@ -1178,7 +1248,7 @@ proc "pld device" {driver tap_name {opt 0}} { lappend _telnet_autocomplete_skip "ipdbg -start" proc "ipdbg -start" {args} { - echo "DEPRECATED! use 'ipdbg create-hub' and 'chip.ipdbghub ipdbg start ...', not 'ipdbg -start ...'" + echo "DEPRECATED! use 'ipdbg create-hub' and 'chip.ipdbghub start ...', not 'ipdbg -start ...'" set tap_name "" set pld_name "" set tool_num "1" @@ -1244,17 +1314,14 @@ proc "ipdbg -start" {args} { 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 + eval $hub_name 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 ...'" + echo "DEPRECATED! use 'chip.ipdbghub stop ...', not 'ipdbg -stop ...'" set tap_name "" set pld_name "" set tool_num "1" @@ -1301,7 +1368,11 @@ proc "ipdbg -stop" {args} { return } - eval $hub_name ipdbg stop -tool $tool_num + eval $hub_name stop -tool $tool_num +} + +proc ipdbg {cmd args} { + tailcall "ipdbg $cmd" {*}$args } #TODO: Deprecate in favor of 'jtag execute scan -ir ...' diff --git a/src/jtag/swd.h b/src/jtag/swd.h index 3fe1365b58..c4b6215abd 100644 --- a/src/jtag/swd.h +++ b/src/jtag/swd.h @@ -270,6 +270,7 @@ struct swd_driver { * @param Where to store value to read from register * @param ap_delay_hint Number of idle cycles that may be * needed after an AP access to avoid WAITs + * or zero in case of DP read. */ void (*read_reg)(uint8_t cmd, uint32_t *value, uint32_t ap_delay_hint); @@ -280,6 +281,7 @@ struct swd_driver { * @param Value to be written to the register * @param ap_delay_hint Number of idle cycles that may be * needed after an AP access to avoid WAITs + * or zero in case of DP write. */ void (*write_reg)(uint8_t cmd, uint32_t value, uint32_t ap_delay_hint); diff --git a/src/jtag/swim.c b/src/jtag/swim.c index 004a9fd4f2..43d655c4c7 100644 --- a/src/jtag/swim.c +++ b/src/jtag/swim.c @@ -12,13 +12,12 @@ #include "config.h" #endif +#include "adapter.h" #include "interface.h" #include "swim.h" #include #include -extern struct adapter_driver *adapter_driver; - int swim_system_reset(void) { assert(adapter_driver->swim_ops); diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index 13adeda6d1..a42d024bb6 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -65,13 +65,13 @@ struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) static bool scan_is_safe(enum tap_state state) { switch (state) { - case TAP_RESET: - case TAP_IDLE: - case TAP_DRPAUSE: - case TAP_IRPAUSE: - return true; - default: - return false; + case TAP_RESET: + case TAP_IDLE: + case TAP_DRPAUSE: + case TAP_IRPAUSE: + return true; + default: + return false; } } @@ -433,7 +433,7 @@ COMMAND_HANDLER(handle_jtag_command_pathmove) for (unsigned int i = 0; i < CMD_ARGC; i++) { states[i] = tap_state_by_name(CMD_ARGV[i]); - if (states[i] < 0) { + if (states[i] == TAP_INVALID) { command_print(CMD, "endstate: %s invalid", CMD_ARGV[i]); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -799,18 +799,18 @@ static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e) } switch (e) { - case JTAG_TAP_EVENT_ENABLE: - case JTAG_TAP_EVENT_DISABLE: - /* NOTE: we currently assume the handlers - * can't fail. Right here is where we should - * really be verifying the scan chains ... - */ - tap->enabled = (e == JTAG_TAP_EVENT_ENABLE); - LOG_INFO("JTAG tap: %s %s", tap->dotted_name, + case JTAG_TAP_EVENT_ENABLE: + case JTAG_TAP_EVENT_DISABLE: + /* NOTE: we currently assume the handlers + * can't fail. Right here is where we should + * really be verifying the scan chains ... + */ + tap->enabled = (e == JTAG_TAP_EVENT_ENABLE); + LOG_INFO("JTAG tap: %s %s", tap->dotted_name, tap->enabled ? "enabled" : "disabled"); - break; - default: - break; + break; + default: + break; } } } @@ -960,7 +960,7 @@ static const struct command_registration jtag_subcommand_handlers[] = { "and appends it to the scan chain.", .usage = "basename tap_type '-irlen' count " "['-enable'|'-disable'] " - "['-expected_id' number] " + "['-expected-id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " diff --git a/src/openocd.c b/src/openocd.c index 3fbece3955..f3e1bee48e 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -75,20 +75,20 @@ static int log_target_callback_event_handler(struct target *target, void *priv) { switch (event) { - case TARGET_EVENT_GDB_START: - target->verbose_halt_msg = false; - break; - case TARGET_EVENT_GDB_END: - target->verbose_halt_msg = true; - break; - case TARGET_EVENT_HALTED: - if (target->verbose_halt_msg) { - /* do not display information when debugger caused the halt */ - target_arch_state(target); - } - break; - default: - break; + case TARGET_EVENT_GDB_START: + target->verbose_halt_msg = false; + break; + case TARGET_EVENT_GDB_END: + target->verbose_halt_msg = true; + break; + case TARGET_EVENT_HALTED: + if (target->verbose_halt_msg) { + /* do not display information when debugger caused the halt */ + target_arch_state(target); + } + break; + default: + break; } return ERROR_OK; @@ -170,7 +170,8 @@ COMMAND_HANDLER(handle_init_command) jtag_poll_unmask(save_poll_mask); /* initialize telnet subsystem */ - gdb_target_add_all(all_targets); + if (gdb_target_add_all(all_targets) != ERROR_OK) + return ERROR_FAIL; target_register_event_callback(log_target_callback_event_handler, CMD_CTX); diff --git a/src/pld/efinix.c b/src/pld/efinix.c index b6e5f9e477..6df24a7b82 100644 --- a/src/pld/efinix.c +++ b/src/pld/efinix.c @@ -82,7 +82,8 @@ static int efinix_read_bit_file(struct raw_bit_file *bit_file, const char *filen return ERROR_PLD_FILE_LOAD_FAILED; } - if (!isxdigit(buffer[0]) || !isxdigit(buffer[1])) { + if (!isxdigit((unsigned char)buffer[0]) || + !isxdigit((unsigned char)buffer[1])) { fclose(input_file); free(bit_file->data); bit_file->data = NULL; @@ -199,9 +200,7 @@ static int efinix_load(struct pld_device *pld_device, const char *filename) /* entering RUN/TEST for 100 cycles */ jtag_add_runtest(RUNTEST_FINISH_CYCLES, TAP_IDLE); - retval = jtag_execute_queue(); - - return retval; + return jtag_execute_queue(); } static int efinix_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) diff --git a/src/pld/gatemate.c b/src/pld/gatemate.c index f35b39ad21..11b6ae76ed 100644 --- a/src/pld/gatemate.c +++ b/src/pld/gatemate.c @@ -57,7 +57,8 @@ static int gatemate_read_cfg_line(struct gatemate_bit_file *bit_file, const char } else if (line_buffer[idx] == 0) { break; } else if (idx + 1 < nread) { - if (isxdigit(line_buffer[idx]) && isxdigit(line_buffer[idx + 1])) { + if (isxdigit((unsigned char)line_buffer[idx]) && + isxdigit((unsigned char)line_buffer[idx + 1])) { uint8_t byte; unhexify(&byte, line_buffer + idx, 2); int retval = gatemate_add_byte_to_bitfile(bit_file, byte); @@ -138,11 +139,11 @@ static int gatemate_read_cfg_file(struct gatemate_bit_file *bit_file, const char 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; + memset(bit_file, 0, sizeof(struct gatemate_bit_file)); + /* check if binary .bit or ascii .cfg */ const char *file_suffix_pos = strrchr(filename, '.'); if (!file_suffix_pos) { diff --git a/src/pld/gowin.c b/src/pld/gowin.c index bbc2fe15f6..9a6709b982 100644 --- a/src/pld/gowin.c +++ b/src/pld/gowin.c @@ -172,11 +172,11 @@ static int gowin_read_fs_file(struct gowin_bit_file *bit_file, const char *filen 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; + memset(bit_file, 0, sizeof(struct gowin_bit_file)); + const char *file_suffix_pos = strrchr(filename, '.'); if (!file_suffix_pos) { LOG_ERROR("Unable to detect filename suffix"); @@ -421,9 +421,7 @@ static int gowin_load_to_sram(struct pld_device *pld_device, const char *filenam if (retval != ERROR_OK) return retval; - retval = jtag_execute_queue(); - - return retval; + return jtag_execute_queue(); } static int gowin_read_register_command(struct pld_device *pld_device, uint32_t cmd, uint32_t *value) diff --git a/src/pld/pld.c b/src/pld/pld.c index edd7796139..8334ff5fba 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -249,11 +249,8 @@ COMMAND_HANDLER(handle_pld_devices_command) COMMAND_HANDLER(handle_pld_load_command) { int retval; - struct timeval start, end, duration; struct pld_device *p; - gettimeofday(&start, NULL); - if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; @@ -279,20 +276,21 @@ COMMAND_HANDLER(handle_pld_load_command) return ERROR_PLD_FILE_LOAD_FAILED; } + struct duration load_time; + duration_start(&load_time); + retval = p->driver->load(p, CMD_ARGV[1]); if (retval != ERROR_OK) { 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 %s in %jis %jius", - CMD_ARGV[1], CMD_ARGV[0], - (intmax_t)duration.tv_sec, (intmax_t)duration.tv_usec); } + duration_measure(&load_time); + + command_print(CMD, "loaded file %s to pld device %s in %f s", + CMD_ARGV[1], CMD_ARGV[0], duration_elapsed(&load_time)); + return ERROR_OK; } diff --git a/src/pld/xilinx_bit.c b/src/pld/xilinx_bit.c index e4cc52ef97..1c04c74906 100644 --- a/src/pld/xilinx_bit.c +++ b/src/pld/xilinx_bit.c @@ -113,7 +113,7 @@ int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename) return ERROR_PLD_FILE_LOAD_FAILED; } - LOG_DEBUG("bit_file: %s %s %s,%s %" PRIu32 "", bit_file->source_file, bit_file->part_name, + 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); fclose(input_file); diff --git a/src/rtos/ecos.c b/src/rtos/ecos.c index a70084b4fb..cadfa4442d 100644 --- a/src/rtos/ecos.c +++ b/src/rtos/ecos.c @@ -510,7 +510,7 @@ static bool ecos_escape_string(const char *raw, char *out, size_t limit) continue; } - char *fidx = strchr(tokens, *raw); + const char *fidx = strchr(tokens, *raw); if (!fidx) { /* Should never happen assuming xmlchars * vector and tokens string match. */ @@ -539,7 +539,7 @@ static int ecos_check_app_info(struct rtos *rtos, struct ecos_params *param) return -1; if (param->flush_common) { - if (debug_level >= LOG_LVL_DEBUG) { + if (LOG_LEVEL_IS(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" : " ", @@ -659,8 +659,6 @@ static int ecos_stack_layout_cortexm(struct rtos *rtos, 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: @@ -695,7 +693,7 @@ static int ecos_stack_layout_arm(struct rtos *rtos, struct ecos_params *param, if (si) *si = param->stacking_info; - return retval; + return ERROR_OK; } /* We see this function called on a new connection, it looks like before and @@ -1004,7 +1002,7 @@ static int ecos_update_threads(struct rtos *rtos) 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); + (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; @@ -1073,7 +1071,7 @@ static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, param->uid_width, (uint8_t *)&id); if (retval != ERROR_OK) { - LOG_ERROR("Error reading unique id from eCos thread 0x%08" PRIX32 "", thread_index); + LOG_ERROR("Error reading unique id from eCos thread 0x%08" PRIX32, thread_index); return retval; } diff --git a/src/rtos/freertos.c b/src/rtos/freertos.c index 02409a5e43..5a9224ec08 100644 --- a/src/rtos/freertos.c +++ b/src/rtos/freertos.c @@ -20,219 +20,63 @@ #include "target/cortex_m.h" #define FREERTOS_MAX_PRIORITIES 63 -#define FREERTOS_THREAD_NAME_STR_SIZE 200 -#define FREERTOS_CURRENT_EXECUTION_ID 1 + +/* 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 { const char *target_name; - int (*stacking)(struct rtos *rtos, const struct rtos_register_stacking **stacking, - target_addr_t stack_ptr); - const struct command_registration *commands; -}; - -struct freertos_thread_entry { - struct list_head list; - threadid_t threadid; - target_addr_t tcb; + const unsigned char thread_count_width; + const unsigned char pointer_width; + const unsigned char list_next_offset; /* offsetof(List_t, xListEnd.pxNext) */ + const unsigned char list_width; /* sizeof(List_t) */ + const unsigned char list_elem_next_offset; /* offsetof(ListItem_t, pxNext) */ + const unsigned char list_elem_content_offset; /* offsetof(ListItem_t, pvOwner) */ + const unsigned char thread_stack_offset; /* offsetof(TCB_t, pxTopOfStack) */ + const unsigned char thread_name_offset; /* offsetof(TCB_t, pcTaskName) */ + 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; }; -struct FreeRTOS { - const struct freertos_params *param; - threadid_t last_threadid; - /* Keep track of which threadid we're using for which TCB. We cannot use a - * 1:1 mapping because TCB's can be 64 bits, and the gdb protocol doesn't - * work well with thread id's that are greater than 32 bits. - */ - struct list_head thread_entry_list; - /* sizeof(UBaseType_t) */ - unsigned ubasetype_size; - /* sizeof(void *) */ - unsigned pointer_size; - /* sizeof(TickType_t) */ - unsigned ticktype_size; - unsigned list_width; - unsigned list_item_width; - unsigned list_elem_next_offset; - unsigned list_elem_next_size; - unsigned list_elem_content_offset; - unsigned list_elem_content_size; - unsigned list_uxNumberOfItems_offset; - unsigned list_uxNumberOfItems_size; - unsigned list_next_offset; - unsigned list_next_size; - unsigned thread_stack_offset; - unsigned thread_stack_size; - unsigned thread_name_offset; -}; - -static int cortex_m_stacking(struct rtos *rtos, const struct rtos_register_stacking **stacking, - target_addr_t stack_ptr) -{ - /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */ - 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) || (armv7m_target->fp_feature == FPV5_SP) || - (armv7m_target->fp_feature == FPV5_DP)) { - /* Found ARM v7m target which includes a FPU */ - uint32_t cpacr; - - int 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 retval; - } - - /* Check if CP10 and CP11 are set to full access. */ - if (cpacr & 0x00F00000) { - /* Found target with enabled FPU */ - cm4_fpu_enabled = 1; - } - } - } - - if (cm4_fpu_enabled == 1) { - /* Read the LR to decide between stacking with or without FPU */ - uint32_t LR_svc = 0; - int retval = target_read_u32(rtos->target, - stack_ptr + 0x20, - &LR_svc); - if (retval != ERROR_OK) { - LOG_OUTPUT("Error reading stack frame from FreeRTOS thread"); - return retval; - } - if ((LR_svc & 0x10) == 0) - *stacking = &rtos_standard_cortex_m4f_fpu_stacking; - else - *stacking = &rtos_standard_cortex_m4f_stacking; - } else { - *stacking = &rtos_standard_cortex_m3_stacking; - } - - return ERROR_OK; -} - -/* take 4 bytes (32 bits) as the default size, - * which is suitable for most 32-bit targets and - * configuration of configUSE_16_BIT_TICKS = 0. */ -static unsigned int freertos_ticktype_size = 4; -COMMAND_HANDLER(handle_freertos_ticktype_size) -{ - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - unsigned int size; - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], size); - switch (size) { - case 2: - case 4: - case 8: - freertos_ticktype_size = size; - break; - default: - LOG_ERROR("Invalid ticktype size. Should be 2, 4 or 8."); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; -} - -static const struct command_registration freertos_commands[] = { - { - .name = "freertos_ticktype_size", - .handler = handle_freertos_ticktype_size, - .mode = COMMAND_ANY, - .usage = "(2|4|8)", - .help = "Pass the size (in bytes) of TickType_t to OpenOCD. To make sure the " - "calculation of offsets and sizes is correct. Defaults to 4." - }, - COMMAND_REGISTRATION_DONE -}; - -static enum { - STACKING_MAINLINE, - STACKING_METAL -} riscv_freertos_stacking; -COMMAND_HANDLER(handle_riscv_freertos_stacking) -{ - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - if (!strcmp(CMD_ARGV[0], "mainline")) { - riscv_freertos_stacking = STACKING_MAINLINE; - } else if (!strcmp(CMD_ARGV[0], "metal")) { - riscv_freertos_stacking = STACKING_METAL; - } else { - LOG_ERROR("Only two arguments are supported: mainline and metal"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - return ERROR_OK; -} - -static const struct command_registration riscv_commands[] = { - { - .name = "riscv_freertos_stacking", - .handler = handle_riscv_freertos_stacking, - .mode = COMMAND_ANY, - .usage = "mainline|metal", - .help = "Select which FreeRTOS branch is being used. OpenOCD needs to " - "know because different branches save thread registers on the stack " - "in different orders. It is likely that this order on both branches will " - "change in the future, so make sure to seek out the very latest OpenOCD if " - "debugging is not working right." - }, - COMMAND_REGISTRATION_DONE -}; - -static int riscv_stacking(struct rtos *rtos, const struct rtos_register_stacking **stacking, - target_addr_t stack_ptr) -{ - struct FreeRTOS *freertos = (struct FreeRTOS *) rtos->rtos_specific_params; - LOG_DEBUG("riscv_freertos_stacking=%d", riscv_freertos_stacking); - switch (riscv_freertos_stacking) { - case STACKING_MAINLINE: - if (freertos->pointer_size == 4) - *stacking = &rtos_standard_rv32_stacking; - else if (freertos->pointer_size == 8) - *stacking = &rtos_standard_rv64_stacking; - break; - case STACKING_METAL: - if (freertos->pointer_size == 4) - *stacking = &rtos_metal_rv32_stacking; - else if (freertos->pointer_size == 8) - *stacking = &rtos_metal_rv64_stacking; - break; - } - return ERROR_OK; -} - static const struct freertos_params freertos_params_list[] = { { - .target_name = "cortex_m", - .stacking = cortex_m_stacking - }, - { - .target_name = "hla_target", - .stacking = cortex_m_stacking + "cortex_m", /* target_name */ + 4, /* thread_count_width; */ + 4, /* pointer_width; */ + 12, /* list_next_offset; */ + 20, /* list_width; */ + 4, /* list_elem_next_offset; */ + 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, }, { - .target_name = "riscv", - .stacking = riscv_stacking, - .commands = riscv_commands, + "hla_target", /* target_name */ + 4, /* thread_count_width; */ + 4, /* pointer_width; */ + 12, /* list_next_offset; */ + 20, /* list_width; */ + 4, /* list_elem_next_offset; */ + 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, }, }; 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, threadid_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); -static int freertos_get_thread_reg_value(struct rtos *rtos, threadid_t thread_id, - uint32_t reg_num, uint32_t *size, uint8_t **value); -static int freertos_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); static int freertos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); const struct rtos_type freertos_rtos = { @@ -242,8 +86,6 @@ const struct rtos_type freertos_rtos = { .create = freertos_create, .update_threads = freertos_update_threads, .get_thread_reg_list = freertos_get_thread_reg_list, - .get_thread_reg_value = freertos_get_thread_reg_value, - .set_reg = freertos_set_reg, .get_symbol_list_to_lookup = freertos_get_symbol_list_to_lookup, }; @@ -288,202 +130,32 @@ 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_read_struct_value( - struct target *target, target_addr_t base_address, unsigned offset, - unsigned size_bytes, uint64_t *value) -{ - uint8_t buf[size_bytes]; - int retval = target_read_buffer(target, base_address + offset, size_bytes, buf); - *value = buf_get_u64(buf, 0, size_bytes * 8); - return retval; -} - -typedef struct { - enum { - TYPE_POINTER, - TYPE_UBASE, - TYPE_TICKTYPE, - TYPE_LIST_ITEM, - TYPE_CHAR_ARRAY - } type; - unsigned offset; - unsigned size; -} type_offset_size_t; - -static unsigned populate_offset_size(struct FreeRTOS *freertos, - type_offset_size_t *info, unsigned count) -{ - unsigned offset = 0; - unsigned largest = 0; - for (unsigned i = 0; i < count; i++) { - unsigned align = 0; - switch (info[i].type) { - case TYPE_UBASE: - info[i].size = freertos->ubasetype_size; - align = freertos->ubasetype_size; - break; - case TYPE_POINTER: - info[i].size = freertos->pointer_size; - align = freertos->pointer_size; - break; - case TYPE_TICKTYPE: - info[i].size = freertos->ticktype_size; - align = freertos->ticktype_size; - break; - case TYPE_LIST_ITEM: - info[i].size = freertos->list_item_width; - align = MAX(freertos->ticktype_size, freertos->pointer_size); - break; - case TYPE_CHAR_ARRAY: - /* size is set by the caller. */ - align = 1; - break; - } - - assert(info[i].size > 0); - assert(align > 0); - - largest = MAX(largest, align); - - if (offset & (align - 1)) { - offset = offset & ~(align - 1); - offset += align; - } - - info[i].offset = offset; - offset += info[i].size; - } - - /* Now align offset to the largest type used, and return that as the width - * of the structure. */ - - if (offset & (largest - 1)) { - offset = offset & ~(largest - 1); - offset += largest; - } - return offset; -} - -static void freertos_compute_offsets(struct rtos *rtos) -{ - struct FreeRTOS *freertos = (struct FreeRTOS *) rtos->rtos_specific_params; - - if (freertos->ticktype_size == freertos_ticktype_size) - return; - - freertos->pointer_size = DIV_ROUND_UP(target_address_bits(rtos->target), 8); - freertos->ubasetype_size = DIV_ROUND_UP(target_data_bits(rtos->target), 8); - freertos->ticktype_size = freertos_ticktype_size; - - /* - * FreeRTOS can be compiled with configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES - * in which case extra data is inserted and OpenOCD won't work right. - */ - - /* struct xLIST */ - type_offset_size_t struct_list_info[] = { - {TYPE_UBASE, 0, 0}, /* uxNumberOfItems */ - {TYPE_POINTER, 0, 0}, /* ListItem_t *pxIndex */ - {TYPE_TICKTYPE, 0, 0}, /* xItemValue */ - {TYPE_POINTER, 0, 0}, /* ListItem_t *pxNext */ - {TYPE_POINTER, 0, 0}, /* ListItem_t *pxPrevious */ - }; - - /* struct xLIST_ITEM */ - type_offset_size_t struct_list_item_info[] = { - {TYPE_TICKTYPE, 0, 0}, /* xItemValue */ - {TYPE_POINTER, 0, 0}, /* ListItem_t *pxNext */ - {TYPE_POINTER, 0, 0}, /* ListItem_t *pxPrevious */ - {TYPE_POINTER, 0, 0}, /* void *pvOwner */ - {TYPE_POINTER, 0, 0}, /* List_t *pvContainer */ - }; - - /* struct tskTaskControlBlock */ - type_offset_size_t task_control_block_info[] = { - {TYPE_POINTER, 0, 0}, /* StackType_t *pxTopOfStack */ - {TYPE_LIST_ITEM, 0, 0}, /* ListItem_t xStateListItem */ - {TYPE_LIST_ITEM, 0, 0}, /* ListItem_t xEventListItem */ - {TYPE_UBASE, 0, 0}, /* uxPriority */ - {TYPE_POINTER, 0, 0}, /* StackType_t *pxStack */ - /* configMAX_TASK_NAME_LEN varies a lot between targets, but luckily the - * name is NULL_terminated and we don't need to read anything else in - * the TCB. */ - {TYPE_CHAR_ARRAY, 0, FREERTOS_THREAD_NAME_STR_SIZE}, /* char pcTaskName[configMAX_TASK_NAME_LEN] */ - /* Lots of more optional stuff, but is is irrelevant to us. */ - }; - - freertos->list_width = populate_offset_size( - freertos, struct_list_info, ARRAY_SIZE(struct_list_info)); - freertos->list_uxNumberOfItems_offset = struct_list_info[0].offset; - freertos->list_uxNumberOfItems_size = struct_list_info[0].size; - freertos->list_next_offset = struct_list_info[3].offset; - freertos->list_next_size = struct_list_info[3].size; - - freertos->list_item_width = populate_offset_size( - freertos, struct_list_item_info, ARRAY_SIZE(struct_list_item_info)); - freertos->list_elem_next_offset = struct_list_item_info[1].offset; - freertos->list_elem_next_size = struct_list_item_info[1].size; - freertos->list_elem_content_offset = struct_list_item_info[3].offset; - freertos->list_elem_content_size = struct_list_item_info[3].size; - - populate_offset_size( - freertos, task_control_block_info, ARRAY_SIZE(task_control_block_info)); - freertos->thread_stack_offset = task_control_block_info[0].offset; - freertos->thread_stack_size = task_control_block_info[0].size; - freertos->thread_name_offset = task_control_block_info[5].offset; -} - -struct freertos_thread_entry *thread_entry_list_find_by_tcb( - struct list_head *list, target_addr_t tcb) -{ - struct freertos_thread_entry *t; - list_for_each_entry(t, list, list) { - if (t->tcb == tcb) - return t; - } - return NULL; -} - -struct freertos_thread_entry *thread_entry_list_find_by_id( - struct list_head *list, threadid_t threadid) -{ - struct freertos_thread_entry *t; - list_for_each_entry(t, list, list) { - if (t->threadid == threadid) - return t; - } - return NULL; -} - static int freertos_update_threads(struct rtos *rtos) { int retval; unsigned int tasks_found = 0; + const struct freertos_params *param; if (!rtos->rtos_specific_params) - return ERROR_FAIL; - - freertos_compute_offsets(rtos); + return -1; - struct FreeRTOS *freertos = (struct FreeRTOS *) rtos->rtos_specific_params; + param = (const struct freertos_params *) rtos->rtos_specific_params; if (!rtos->symbols) { LOG_ERROR("No symbols for FreeRTOS"); - return ERROR_FAIL; + return -3; } if (rtos->symbols[FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS].address == 0) { LOG_ERROR("Don't have the number of threads in FreeRTOS"); - return ERROR_FAIL; + return -2; } - uint64_t thread_list_size; - retval = freertos_read_struct_value(rtos->target, - rtos->symbols[FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS].address, - 0, - freertos->ubasetype_size, - &thread_list_size); - LOG_DEBUG("FreeRTOS: Read uxCurrentNumberOfTasks at 0x%" PRIx64 ", value %" PRIu64, + 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); @@ -496,36 +168,33 @@ static int freertos_update_threads(struct rtos *rtos) rtos_free_threadlist(rtos); /* read the current thread */ - target_addr_t px_current_tcb; - retval = freertos_read_struct_value(rtos->target, - rtos->symbols[FREERTOS_VAL_PX_CURRENT_TCB].address, - 0, - freertos->pointer_size, - &px_current_tcb); + 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; } + 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, - px_current_tcb); + rtos->current_thread); /* read scheduler running */ - uint64_t scheduler_running; - retval = freertos_read_struct_value(rtos->target, - rtos->symbols[FREERTOS_VAL_X_SCHEDULER_RUNNING].address, - 0, - freertos->ubasetype_size, - &scheduler_running); + 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%" PRIx64, + 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 || px_current_tcb == 0 || scheduler_running != 1) { + 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 */ @@ -535,10 +204,10 @@ static int freertos_update_threads(struct rtos *rtos) rtos->thread_details = malloc( sizeof(struct thread_detail) * thread_list_size); if (!rtos->thread_details) { - LOG_ERROR("Error allocating memory for %" PRIu64 " threads", thread_list_size); + LOG_ERROR("Error allocating memory for %d threads", thread_list_size); return ERROR_FAIL; } - rtos->current_thread = FREERTOS_CURRENT_EXECUTION_ID; + rtos->current_thread = 1; rtos->thread_details->threadid = rtos->current_thread; rtos->thread_details->exists = true; rtos->thread_details->extra_info_str = NULL; @@ -554,33 +223,27 @@ static int freertos_update_threads(struct rtos *rtos) rtos->thread_details = malloc( sizeof(struct thread_detail) * thread_list_size); if (!rtos->thread_details) { - LOG_ERROR("Error allocating memory for %" PRId64 " threads", thread_list_size); + LOG_ERROR("Error allocating memory for %d threads", thread_list_size); return ERROR_FAIL; } } /* Find out how many lists are needed to be read from pxReadyTasksLists, */ - uint64_t top_used_priority = 0; if (rtos->symbols[FREERTOS_VAL_UX_TOP_USED_PRIORITY].address == 0) { - LOG_WARNING("FreeRTOS: uxTopUsedPriority is not defined, consult the OpenOCD manual for a work-around"); - /* This is a hack specific to the binary I'm debugging. - * Ideally we get https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/33 - * into our FreeRTOS source. */ - top_used_priority = 6; - } else { - retval = freertos_read_struct_value(rtos->target, - rtos->symbols[FREERTOS_VAL_UX_TOP_USED_PRIORITY].address, - 0, - freertos->ubasetype_size, - &top_used_priority); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRIu64, - rtos->symbols[FREERTOS_VAL_UX_TOP_USED_PRIORITY].address, - top_used_priority); + LOG_ERROR("FreeRTOS: uxTopUsedPriority is not defined, consult the OpenOCD manual for a work-around"); + return ERROR_FAIL; } + 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 %" 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; } @@ -602,7 +265,7 @@ 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_PX_READY_TASKS_LISTS].address + - num_lists * freertos->list_width; + num_lists * param->list_width; 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; @@ -615,87 +278,60 @@ static int freertos_update_threads(struct rtos *rtos) continue; /* Read the number of threads in this list */ - uint64_t list_thread_count = 0; - retval = freertos_read_struct_value(rtos->target, - list_of_lists[i], - freertos->list_uxNumberOfItems_offset, - freertos->list_uxNumberOfItems_size, - &list_thread_count); + uint32_t list_thread_count = 0; + retval = target_read_u32(rtos->target, + list_of_lists[i], + &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 %" PRIu64, - i, list_of_lists[i] + freertos->list_uxNumberOfItems_offset, list_thread_count); + 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 */ - target_addr_t prev_list_elem_ptr = -1; - target_addr_t list_elem_ptr = 0; - retval = freertos_read_struct_value(rtos->target, - list_of_lists[i], - freertos->list_next_offset, - freertos->list_next_size, - &list_elem_ptr); + 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, + &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, - i, list_of_lists[i] + freertos->list_next_offset, list_elem_ptr); + 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; - target_addr_t tcb; - retval = freertos_read_struct_value(rtos->target, - list_elem_ptr, - freertos->list_elem_content_offset, - freertos->list_elem_content_size, - &tcb); + retval = target_read_u32(rtos->target, + list_elem_ptr + param->list_elem_content_offset, + &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; } - - const struct freertos_thread_entry *value = - thread_entry_list_find_by_tcb(&freertos->thread_entry_list, tcb); - - if (!value) { - struct freertos_thread_entry *new_value = calloc(1, sizeof(struct freertos_thread_entry)); - new_value->tcb = tcb; - /* threadid can't be 0. - * plus 1 to avoid duplication with "Current Execution" */ - new_value->threadid = ++freertos->last_threadid + FREERTOS_CURRENT_EXECUTION_ID; - - LOG_DEBUG("FreeRTOS: new thread created, tcb=0x%" PRIx64 ", threadid=0x%" PRIx64, - new_value->tcb, new_value->threadid); - - list_add_tail(&new_value->list, &freertos->thread_entry_list); - value = new_value; - } - - rtos->thread_details[tasks_found].threadid = value->threadid; - - LOG_DEBUG("FreeRTOS: Thread %" PRId64 " has TCB 0x%" TARGET_PRIxADDR - "; read from 0x%" PRIx64, - value->threadid, value->tcb, - list_elem_ptr + freertos->list_elem_content_offset); + 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); /* get thread name */ + #define FREERTOS_THREAD_NAME_STR_SIZE (200) char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE]; /* Read the thread name */ retval = target_read_buffer(rtos->target, - value->tcb + freertos->thread_name_offset, + rtos->thread_details[tasks_found].threadid + param->thread_name_offset, FREERTOS_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { @@ -705,7 +341,7 @@ static int freertos_update_threads(struct rtos *rtos) } tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00'; LOG_DEBUG("FreeRTOS: Read Thread Name at 0x%" PRIx64 ", value '%s'", - value->tcb + freertos->thread_name_offset, + rtos->thread_details[tasks_found].threadid + param->thread_name_offset, tmp_str); if (tmp_str[0] == '\x00') @@ -716,9 +352,8 @@ static int freertos_update_threads(struct rtos *rtos) strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str); rtos->thread_details[tasks_found].exists = true; - if (value->tcb == px_current_tcb && rtos->current_thread != FREERTOS_CURRENT_EXECUTION_ID) { + if (rtos->thread_details[tasks_found].threadid == rtos->current_thread) { char running_str[] = "State: Running"; - rtos->current_thread = value->threadid; rtos->thread_details[tasks_found].extra_info_str = malloc( sizeof(running_str)); strcpy(rtos->thread_details[tasks_found].extra_info_str, @@ -732,20 +367,17 @@ static int freertos_update_threads(struct rtos *rtos) prev_list_elem_ptr = list_elem_ptr; list_elem_ptr = 0; - retval = freertos_read_struct_value(rtos->target, - prev_list_elem_ptr, - freertos->list_elem_next_offset, - freertos->list_elem_next_size, - &list_elem_ptr); + retval = target_read_u32(rtos->target, + prev_list_elem_ptr + param->list_elem_next_offset, + &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 " TARGET_ADDR_FMT - ", value " TARGET_ADDR_FMT, - prev_list_elem_ptr + freertos->list_elem_next_offset, - list_elem_ptr); + 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); } } @@ -753,106 +385,77 @@ static int freertos_update_threads(struct rtos *rtos) return 0; } -static int freertos_get_stacking_info(struct rtos *rtos, threadid_t thread_id, - const struct rtos_register_stacking **stacking_info, - target_addr_t *stack_ptr) +static int freertos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) { - if (!rtos->rtos_specific_params) { - LOG_ERROR("rtos_specific_params is NULL!"); - return ERROR_FAIL; - } + int retval; + const struct freertos_params *param; + int64_t stack_ptr = 0; - freertos_compute_offsets(rtos); + if (!rtos) + return -1; - struct FreeRTOS *freertos = (struct FreeRTOS *) rtos->rtos_specific_params; - const struct freertos_params *param = freertos->param; + if (thread_id == 0) + return -2; - const struct freertos_thread_entry *entry = - thread_entry_list_find_by_id(&freertos->thread_entry_list, thread_id); - if (!entry) { - LOG_ERROR("Unknown thread id: %" PRId64, thread_id); - return ERROR_FAIL; - } + if (!rtos->rtos_specific_params) + return -1; + + param = (const struct freertos_params *) rtos->rtos_specific_params; /* Read the stack pointer */ - int retval = freertos_read_struct_value(rtos->target, - entry->tcb, - freertos->thread_stack_offset, - freertos->thread_stack_size, - stack_ptr); + uint32_t pointer_casts_are_bad; + retval = target_read_u32(rtos->target, + thread_id + param->thread_stack_offset, + &pointer_casts_are_bad); if (retval != ERROR_OK) { - LOG_ERROR("Error reading stack frame from FreeRTOS thread %" PRIx64, thread_id); + LOG_ERROR("Error reading stack frame from FreeRTOS thread"); return retval; } - LOG_DEBUG("[%" PRId64 "] FreeRTOS: Read stack pointer at 0x%" PRIx64 ", value 0x%" PRIx64, - thread_id, entry->tcb + freertos->thread_stack_offset, *stack_ptr); - - if (param->stacking(rtos, stacking_info, *stack_ptr) != ERROR_OK) { - LOG_ERROR("No stacking info found for %s!", param->target_name); - return ERROR_FAIL; - } + 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); - return ERROR_OK; -} - -static int freertos_get_thread_reg_list(struct rtos *rtos, threadid_t thread_id, - struct rtos_reg **reg_list, int *num_regs) -{ - /* Let the caller read registers directly for the current thread. */ - if (thread_id == 0) - return ERROR_FAIL; - - const struct rtos_register_stacking *stacking_info; - target_addr_t stack_ptr; - if (freertos_get_stacking_info(rtos, thread_id, &stacking_info, &stack_ptr) != ERROR_OK) - return ERROR_FAIL; - - return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs); -} - -static int freertos_get_thread_reg_value(struct rtos *rtos, threadid_t thread_id, - uint32_t reg_num, uint32_t *size, uint8_t **value) -{ - LOG_DEBUG("reg_num=%d", reg_num); - /* Let the caller read registers directly for the current thread. */ - if (thread_id == 0) - return ERROR_FAIL; + /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */ + 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) || (armv7m_target->fp_feature == FPV5_SP) || + (armv7m_target->fp_feature == FPV5_DP)) { + /* Found ARM v7m target which includes a FPU */ + uint32_t cpacr; - const struct rtos_register_stacking *stacking_info; - target_addr_t stack_ptr; - if (freertos_get_stacking_info(rtos, thread_id, &stacking_info, &stack_ptr) != ERROR_OK) - return ERROR_FAIL; + 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 rtos_reg reg; - reg.number = reg_num; - int result = rtos_generic_stack_read_reg(rtos->target, stacking_info, - stack_ptr, reg_num, ®); - *size = reg.size; - *value = malloc(DIV_ROUND_UP(reg.size, 8)); - if (!*value) { - LOG_ERROR("Failed to allocate memory for %d-bit register.", reg.size); - return ERROR_FAIL; + /* Check if CP10 and CP11 are set to full access. */ + if (cpacr & 0x00F00000) { + /* Found target with enabled FPU */ + cm4_fpu_enabled = 1; + } + } } - memcpy(*value, reg.value, DIV_ROUND_UP(reg.size, 8)); - return result; -} -static int freertos_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value) -{ - LOG_DEBUG("[%" PRId64 "] reg_num=%" PRId32, rtos->current_threadid, reg_num); - - /* Let the caller write registers directly for the current thread. */ - if (rtos->current_threadid == rtos->current_thread) - return ERROR_FAIL; - - const struct rtos_register_stacking *stacking_info; - target_addr_t stack_ptr; - if (freertos_get_stacking_info(rtos, rtos->current_threadid, - &stacking_info, &stack_ptr) != ERROR_OK) - return ERROR_FAIL; - - return rtos_generic_stack_write_reg(rtos->target, stacking_info, stack_ptr, - reg_num, reg_value); + if (cm4_fpu_enabled == 1) { + /* Read the LR to decide between stacking with or without FPU */ + uint32_t lr_svc = 0; + retval = target_read_u32(rtos->target, + stack_ptr + 0x20, + &lr_svc); + if (retval != ERROR_OK) { + LOG_OUTPUT("Error reading stack frame from FreeRTOS thread"); + return retval; + } + 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); + } else + 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(struct symbol_table_elem *symbol_list[]) @@ -928,32 +531,12 @@ static bool freertos_detect_rtos(struct target *target) static int freertos_create(struct target *target) { - unsigned int i = 0; - while (i < ARRAY_SIZE(freertos_params_list) && - strcmp(freertos_params_list[i].target_name, target_type_name(target)) != 0) { - i++; - } - if (i >= ARRAY_SIZE(freertos_params_list)) { - LOG_ERROR("Could not find target in FreeRTOS compatibility list"); - return ERROR_FAIL; - } - - target->rtos->rtos_specific_params = calloc(1, sizeof(struct FreeRTOS)); - if (!target->rtos->rtos_specific_params) { - LOG_ERROR("calloc failed"); - return ERROR_FAIL; - } - - struct FreeRTOS *freertos = (struct FreeRTOS *) target->rtos->rtos_specific_params; - INIT_LIST_HEAD(&freertos->thread_entry_list); - - freertos->param = &freertos_params_list[i]; - - if (freertos->param->commands) { - if (register_commands(target->rtos->cmd_ctx, NULL, - freertos->param->commands) != ERROR_OK) - return ERROR_FAIL; - } + for (unsigned int i = 0; i < ARRAY_SIZE(freertos_params_list); i++) + if (strcmp(freertos_params_list[i].target_name, target_type_name(target)) == 0) { + target->rtos->rtos_specific_params = (void *)&freertos_params_list[i]; + return ERROR_OK; + } - return register_commands(target->rtos->cmd_ctx, NULL, freertos_commands); + LOG_ERROR("Could not find target in FreeRTOS compatibility list"); + return ERROR_FAIL; } diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index e20339a336..9367f70af4 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -24,11 +24,11 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); static int hwthread_smp_init(struct target *target); static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); -static bool hwthread_needs_fake_step(struct target *target, int64_t thread_id); 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); +static bool hwthread_needs_fake_step(struct target *target, int64_t thread_id); struct target *hwthread_swbp_target(struct rtos *rtos, target_addr_t address, uint32_t length, enum breakpoint_type type); @@ -60,10 +60,10 @@ 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, - .needs_fake_step = hwthread_needs_fake_step, .read_buffer = hwthread_read_buffer, .write_buffer = hwthread_write_buffer, - .swbp_target = hwthread_swbp_target + .needs_fake_step = hwthread_needs_fake_step, + .swbp_target = hwthread_swbp_target, }; struct hwthread_params { @@ -94,12 +94,13 @@ 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 */ + int64_t current_threadid; enum target_debug_reason current_reason = DBG_REASON_UNDEFINED; if (!rtos) - return ERROR_FAIL; + return -1; + current_threadid = rtos->current_threadid; /* thread selected by GDB */ target = rtos->target; /* wipe out previous thread details if any */ @@ -211,8 +212,8 @@ static int hwthread_update_threads(struct rtos *rtos) else rtos->current_thread = threadid_from_target(target); - LOG_TARGET_DEBUG(target, "current_thread=%i, threads_found=%d", - (int)rtos->current_thread, threads_found); + LOG_TARGET_DEBUG(target, "current_thread=%" PRId64 ", threads_found=%d", + rtos->current_thread, threads_found); return 0; } @@ -425,11 +426,6 @@ static int hwthread_create(struct target *target) return ERROR_OK; } -static bool hwthread_needs_fake_step(struct target *target, int64_t thread_id) -{ - return false; -} - static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, uint32_t size, uint8_t *buffer) { @@ -460,6 +456,11 @@ static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, return target_write_buffer(curr, address, size, buffer); } +bool hwthread_needs_fake_step(struct target *target, int64_t thread_id) +{ + return false; +} + struct target *hwthread_swbp_target(struct rtos *rtos, target_addr_t address, uint32_t length, enum breakpoint_type type) { diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 4ca02605ed..92854a4b6a 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -145,14 +145,6 @@ static int fill_buffer(struct target *target, uint32_t addr, 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; - value = target_buffer_get_u32(target, value_ptr); - return value; -} - static int linux_os_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { @@ -271,7 +263,7 @@ int fill_task_pid(struct target *target, struct threads *t) int retval = fill_buffer(target, pid_addr, buffer); if (retval == ERROR_OK) { - uint32_t val = get_buffer(target, buffer); + uint32_t val = target_buffer_get_u32(target, buffer); t->pid = val; } else LOG_ERROR("fill_task_pid: unable to read memory"); @@ -290,7 +282,7 @@ static int fill_task(struct target *target, struct threads *t) retval = fill_buffer(target, t->base_addr, buffer); if (retval == ERROR_OK) { - uint32_t val = get_buffer(target, buffer); + uint32_t val = target_buffer_get_u32(target, buffer); t->state = val; } else LOG_ERROR("fill_task: unable to read memory"); @@ -298,7 +290,7 @@ static int fill_task(struct target *target, struct threads *t) retval = fill_buffer(target, pid_addr, buffer); if (retval == ERROR_OK) { - uint32_t val = get_buffer(target, buffer); + uint32_t val = target_buffer_get_u32(target, buffer); t->pid = val; } else LOG_ERROR("fill task: unable to read memory"); @@ -306,7 +298,7 @@ static int fill_task(struct target *target, struct threads *t) retval = fill_buffer(target, on_cpu, buffer); if (retval == ERROR_OK) { - uint32_t val = get_buffer(target, buffer); + uint32_t val = target_buffer_get_u32(target, buffer); t->oncpu = val; } else LOG_ERROR("fill task: unable to read memory"); @@ -314,14 +306,14 @@ static int fill_task(struct target *target, struct threads *t) retval = fill_buffer(target, mem_addr, buffer); if (retval == ERROR_OK) { - uint32_t val = get_buffer(target, buffer); + uint32_t val = target_buffer_get_u32(target, buffer); if (val != 0) { uint32_t asid_addr = val + MM_CTX; retval = fill_buffer(target, asid_addr, buffer); if (retval == ERROR_OK) { - val = get_buffer(target, buffer); + val = target_buffer_get_u32(target, buffer); t->asid = val; } else LOG_ERROR @@ -415,18 +407,18 @@ static int get_current(struct target *target, int create) reg_list[13]->type->get(reg_list[13]); buf = reg_list[13]->value; - val = get_buffer(target, buf); + val = target_buffer_get_u32(target, buf); ti_addr = (val & 0xffffe000); 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); + uint32_t TS = target_buffer_get_u32(target, buffer); uint32_t cpu, on_cpu = TS + ONCPU; retval = fill_buffer(target, on_cpu, buffer); if (retval == ERROR_OK) { - /*uint32_t cpu = get_buffer(target, buffer);*/ + /*uint32_t cpu = target_buffer_get_u32(target, buffer);*/ struct current_thread *ct = linux_os->current_threads; cpu = head->target->coreid; @@ -495,7 +487,7 @@ static struct cpu_context *cpu_context_read(struct target *target, uint32_t base retval = fill_buffer(target, stack, buffer); if (retval == ERROR_OK) - thread_info_addr = get_buffer(target, buffer); + thread_info_addr = target_buffer_get_u32(target, buffer); else LOG_ERROR("cpu_context: unable to read memory"); @@ -507,7 +499,7 @@ static struct cpu_context *cpu_context_read(struct target *target, uint32_t base retval = fill_buffer(target, preempt_count_addr, buffer); if (retval == ERROR_OK) - context->preempt_count = get_buffer(target, buffer); + context->preempt_count = target_buffer_get_u32(target, buffer); else { if (*thread_info_addr_old != 0xdeadbeef) { LOG_ERROR @@ -571,7 +563,7 @@ static uint32_t next_task(struct target *target, struct threads *t) int retval = fill_buffer(target, next_addr, buffer); if (retval == ERROR_OK) { - uint32_t val = get_buffer(target, buffer); + uint32_t val = target_buffer_get_u32(target, buffer); val = val - NEXT; free(buffer); return val; @@ -1282,86 +1274,77 @@ static int linux_thread_packet(struct connection *connection, char const *packet target->rtos->rtos_specific_params; switch (packet[0]) { - case 'T': /* Is thread alive?*/ - - 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 )*/ - /*LOG_INFO(" H packet received '%s'", packet);*/ - linux_gdb_h_packet(connection, target, packet, packet_size); - break; - case 'q': - - if (strncmp(packet, "qSymbol", 7) == 0) { - if (rtos_qsymbol(connection, packet, packet_size) == 1) { - linux_compute_virt2phys(target, - target->rtos->symbols[INIT_TASK].address); - } - - break; - } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { - if (!linux_os->thread_list) { - retval = linux_gdb_thread_packet(target, - connection, - packet, - packet_size); - break; - } else { - retval = linux_gdb_thread_update(target, - connection, - packet, - packet_size); - break; - } - } else if (strncmp(packet, "qsThreadInfo", 12) == 0) { - gdb_put_packet(connection, "l", 1); - break; - } else if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) { - linux_thread_extra_info(target, connection, packet, + case 'T': /* Is thread alive?*/ + 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 )*/ + /*LOG_INFO(" H packet received '%s'", packet);*/ + linux_gdb_h_packet(connection, target, packet, packet_size); + break; + + case 'q': + if (!strncmp(packet, "qSymbol", 7)) { + if (rtos_qsymbol(connection, packet, packet_size) == 1) { + linux_compute_virt2phys(target, + target->rtos->symbols[INIT_TASK].address); + } + } else if (!strncmp(packet, "qfThreadInfo", 12)) { + if (!linux_os->thread_list) { + retval = linux_gdb_thread_packet(target, + connection, + packet, packet_size); - break; } else { - retval = GDB_THREAD_PACKET_NOT_CONSUMED; - break; + retval = linux_gdb_thread_update(target, + connection, + packet, + packet_size); } - - case 'Q': - /* previously response was : thread not found - * gdb_put_packet(connection, "E01", 3); */ + } else if (!strncmp(packet, "qsThreadInfo", 12)) { + gdb_put_packet(connection, "l", 1); + } else if (!strncmp(packet, "qThreadExtraInfo,", 17)) { + linux_thread_extra_info(target, connection, packet, + packet_size); + } else { retval = GDB_THREAD_PACKET_NOT_CONSUMED; - break; - case 'c': - case 's': { - if (linux_os->threads_lookup == 1) { - ct = linux_os->current_threads; + } + break; - while ((ct) && (ct->core_id) != target->coreid) - ct = ct->next; + case 'Q': + /* previously response was : thread not found + * gdb_put_packet(connection, "E01", 3); */ + retval = GDB_THREAD_PACKET_NOT_CONSUMED; + break; - if ((ct) && (ct->threadid == -1)) { - ct = linux_os->current_threads; + case 'c': + case 's': + if (linux_os->threads_lookup == 1) { + ct = linux_os->current_threads; - while ((ct) && (ct->threadid == -1)) - ct = ct->next; - } + while ((ct) && (ct->core_id) != target->coreid) + ct = ct->next; - if ((ct) && (ct->threadid != - target->rtos->current_threadid) - && (target->rtos->current_threadid != -1)) - LOG_WARNING("WARNING! current GDB thread do not match " - "current thread running. " - "Switch thread in GDB to threadid %d", - (int)ct->threadid); + if ((ct) && (ct->threadid == -1)) { + ct = linux_os->current_threads; - LOG_INFO("threads_needs_update = 1"); - linux_os->threads_needs_update = 1; + while ((ct) && (ct->threadid == -1)) + ct = ct->next; } - } - /* if a packet handler returned an error, exit input loop */ - if (retval != ERROR_OK) - return retval; + if ((ct) && (ct->threadid != + target->rtos->current_threadid) + && (target->rtos->current_threadid != -1)) + LOG_WARNING("WARNING! current GDB thread do not match " + "current thread running. " + "Switch thread in GDB to threadid %d", + (int)ct->threadid); + + LOG_INFO("threads_needs_update = 1"); + linux_os->threads_needs_update = 1; + } + break; } return retval; diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index a2dac67322..cc0e92edff 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -18,20 +18,22 @@ #include "server/gdb_server.h" static const struct rtos_type *rtos_types[] = { - &threadx_rtos, - &freertos_rtos, - &ecos_rtos, - &linux_rtos, + // Keep in alphabetic order this list of rtos, except hwthread &chibios_rtos, &chromium_ec_rtos, + &ecos_rtos, &embkernel_rtos, + &freertos_rtos, + &linux_rtos, &mqx_rtos, - &ucos_iii_rtos, &nuttx_rtos, &riot_rtos, - &zephyr_rtos, &rtkernel_rtos, - /* keep this as last, as it always matches with rtos auto */ + &threadx_rtos, + &ucos_iii_rtos, + &zephyr_rtos, + + // keep this as last, as it always matches with rtos auto &hwthread_rtos, }; @@ -42,9 +44,7 @@ int rtos_smp_init(struct target *target) return ERROR_TARGET_INIT_FAILED; } -static int rtos_target_for_threadid(struct connection *connection, - threadid_t threadid, - struct target **t) +static int rtos_target_for_threadid(struct connection *connection, int64_t threadid, struct target **t) { struct target *curr = get_target_from_connection(connection); if (t) @@ -53,8 +53,7 @@ static int rtos_target_for_threadid(struct connection *connection, return ERROR_OK; } -static int os_alloc(struct target *target, const struct rtos_type *ostype, - struct command_context *cmd_ctx) +static int os_alloc(struct target *target, const struct rtos_type *ostype) { struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos)); @@ -70,7 +69,6 @@ static int os_alloc(struct target *target, const struct rtos_type *ostype, /* RTOS drivers can override the packet handler in _create(). */ os->gdb_thread_packet = rtos_thread_packet; os->gdb_target_for_threadid = rtos_target_for_threadid; - os->cmd_ctx = cmd_ctx; return ERROR_OK; } @@ -86,10 +84,9 @@ static void os_free(struct target *target) target->rtos = NULL; } -static int os_alloc_create(struct target *target, const struct rtos_type *ostype, - struct command_context *cmd_ctx) +static int os_alloc_create(struct target *target, const struct rtos_type *ostype) { - int ret = os_alloc(target, ostype, cmd_ctx); + int ret = os_alloc(target, ostype); if (ret != ERROR_OK) return ret; @@ -117,12 +114,12 @@ int rtos_create(struct command_invocation *cmd, struct target *target, /* rtos_qsymbol() will iterate over all RTOSes. Allocate * target->rtos here, and set it to the first RTOS type. */ - return os_alloc(target, rtos_types[0], CMD_CTX); + return os_alloc(target, rtos_types[0]); } for (size_t x = 0; x < ARRAY_SIZE(rtos_types); x++) if (strcmp(rtos_name, rtos_types[x]->name) == 0) - return os_alloc_create(target, rtos_types[x], CMD_CTX); + return os_alloc_create(target, rtos_types[x]); char *all = NULL; for (size_t x = 0; x < ARRAY_SIZE(rtos_types); x++) { @@ -507,6 +504,26 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa return GDB_THREAD_PACKET_NOT_CONSUMED; } +static int rtos_put_gdb_reg(struct connection *connection, + uint8_t *reg_value, unsigned int reg_size) +{ + unsigned int reg_bytes = DIV_ROUND_UP(reg_size, 8); + unsigned int num_bytes = reg_bytes * 2 + 1; // for '\0' + + char *hex = malloc(num_bytes); + if (!hex) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + size_t len = hexify(hex, reg_value, reg_bytes, num_bytes); + + gdb_put_packet(connection, hex, len); + free(hex); + + return ERROR_OK; +} + static int rtos_put_gdb_reg_list(struct connection *connection, struct rtos_reg *reg_list, int num_regs) { @@ -534,72 +551,57 @@ static int rtos_put_gdb_reg_list(struct connection *connection, int rtos_get_gdb_reg(struct connection *connection, int reg_num) { struct target *target = get_target_from_connection(connection); - threadid_t current_threadid = target->rtos->current_threadid; - if (!target->rtos || - current_threadid == -1 || - current_threadid == 0 || - (current_threadid == target->rtos->current_thread && - !target->smp)) { /* in smp several current thread are possible */ - return ERROR_NOT_IMPLEMENTED; - } + int64_t current_threadid = target->rtos->current_threadid; + if ((target->rtos) && (current_threadid != -1) && + (current_threadid != 0) && + ((current_threadid != target->rtos->current_thread) || + (target->smp))) { /* in smp several current thread are possible */ + struct rtos_reg *reg_list; + int num_regs; - struct rtos_reg *reg_list; - int num_regs; + LOG_DEBUG("getting register %d for thread 0x%" PRIx64 + ", target->rtos->current_thread=0x%" PRIx64, + reg_num, + current_threadid, + target->rtos->current_thread); + + int retval; + if (target->rtos->type->get_thread_reg_value) { + uint32_t reg_size; + uint8_t *reg_value; + retval = target->rtos->type->get_thread_reg_value(target->rtos, + current_threadid, reg_num, ®_size, ®_value); + if (retval != ERROR_OK) { + LOG_ERROR("RTOS: failed to get register %d", reg_num); + return retval; + } - LOG_TARGET_DEBUG(target, "getting register %d for thread 0x%" PRIx64 - ", target->rtos->current_thread=0x%" PRIx64, - reg_num, current_threadid, target->rtos->current_thread); + retval = rtos_put_gdb_reg(connection, reg_value, reg_size); - int retval; - if (target->rtos->type->get_thread_reg_value) { - uint32_t reg_size; - uint8_t *reg_value; - retval = target->rtos->type->get_thread_reg_value(target->rtos, - current_threadid, reg_num, ®_size, ®_value); - if (retval != ERROR_OK) { - LOG_ERROR("RTOS: failed to get register %d", reg_num); + free(reg_value); return retval; } - /* Create a reg_list with one register that can - * accommodate the full size of the one we just got the - * value for. To do that we allocate extra space off the - * end of the struct, relying on the fact that - * rtos_reg.value is the last element in the struct. */ - reg_list = calloc(1, sizeof(*reg_list) + DIV_ROUND_UP(reg_size, 8)); - if (!reg_list) { - free(reg_value); - LOG_ERROR("Failed to allocated reg_list for %d-byte register.", - reg_size); - return ERROR_FAIL; - } - reg_list[0].number = reg_num; - reg_list[0].size = reg_size; - memcpy(®_list[0].value, reg_value, DIV_ROUND_UP(reg_size, 8)); - free(reg_value); - num_regs = 1; - } else { retval = target->rtos->type->get_thread_reg_list(target->rtos, - current_threadid, - ®_list, - &num_regs); + current_threadid, + ®_list, + &num_regs); if (retval != ERROR_OK) { LOG_ERROR("RTOS: failed to get register list"); return retval; } - } - for (int i = 0; i < num_regs; ++i) { - if (reg_list[i].number == (uint32_t)reg_num) { - rtos_put_gdb_reg_list(connection, reg_list + i, 1); - free(reg_list); - return ERROR_OK; + for (int i = 0; i < num_regs; ++i) { + if (reg_list[i].number == (uint32_t)reg_num) { + rtos_put_gdb_reg_list(connection, reg_list + i, 1); + free(reg_list); + return ERROR_OK; + } } - } - - free(reg_list); - return ERROR_FAIL; + free(reg_list); + } + return ERROR_NOT_IMPLEMENTED; } /** Return a list of general registers. */ @@ -614,9 +616,10 @@ int rtos_get_gdb_reg_list(struct connection *connection) struct rtos_reg *reg_list; int num_regs; - LOG_TARGET_DEBUG(target, "RTOS: getting register list for thread 0x%" PRIx64 - ", target->rtos->current_thread=0x%" PRIx64, - current_threadid, target->rtos->current_thread); + LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64 + ", target->rtos->current_thread=0x%" PRIx64 "\r\n", + current_threadid, + target->rtos->current_thread); int retval = target->rtos->type->get_thread_reg_list(target->rtos, current_threadid, @@ -651,7 +654,7 @@ int rtos_set_reg(struct connection *connection, int reg_num, int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, - target_addr_t stack_ptr, + int64_t stack_ptr, struct rtos_reg **reg_list, int *num_regs) { @@ -663,7 +666,7 @@ int rtos_generic_stack_read(struct target *target, } /* Read the stack */ uint8_t *stack_data = malloc(stacking->stack_registers_size); - target_addr_t address = stack_ptr; + uint32_t address = stack_ptr; if (stacking->stack_growth_direction == 1) address -= stacking->stack_registers_size; @@ -676,7 +679,7 @@ int rtos_generic_stack_read(struct target *target, LOG_ERROR("Error reading stack frame from thread"); return retval; } - LOG_DEBUG("RTOS: Read stack frame at " TARGET_ADDR_FMT, address); + LOG_DEBUG("RTOS: Read stack frame at 0x%" PRIx32, address); #if 0 LOG_OUTPUT("Stack Data :"); @@ -706,9 +709,6 @@ int rtos_generic_stack_read(struct target *target, buf_cpy(&new_stack_ptr, (*reg_list)[i].value, (*reg_list)[i].size); else if (offset != -1) buf_cpy(stack_data + offset, (*reg_list)[i].value, (*reg_list)[i].size); - - LOG_DEBUG("register %d has value 0x%" PRIx64, (*reg_list)[i].number, - buf_get_u64((*reg_list)[i].value, 0, 64)); } free(stack_data); @@ -716,113 +716,14 @@ int rtos_generic_stack_read(struct target *target, return ERROR_OK; } -/* Read an individual register from the RTOS stack. */ -int rtos_generic_stack_read_reg(struct target *target, - const struct rtos_register_stacking *stacking, - target_addr_t stack_ptr, - uint32_t reg_num, struct rtos_reg *reg) -{ - LOG_DEBUG("stack_ptr=" TARGET_ADDR_FMT ", reg_num=%d", stack_ptr, reg_num); - unsigned total_count = MAX(stacking->total_register_count, stacking->num_output_registers); - unsigned i; - for (i = 0; i < total_count; i++) { - if (stacking->register_offsets[i].number == reg_num) - break; - } - if (i >= total_count) { - /* This register is not on the stack. Return error so a caller somewhere - * will just read the register directly from the target. */ - return ERROR_FAIL; - } - - const struct stack_register_offset *offsets = &stacking->register_offsets[i]; - reg->size = offsets->width_bits; - - unsigned width_bytes = DIV_ROUND_UP(offsets->width_bits, 8); - if (offsets->offset >= 0) { - target_addr_t address = stack_ptr; - - if (stacking->stack_growth_direction == 1) - address -= stacking->stack_registers_size; - - if (target_read_buffer( - target, address + offsets->offset, - width_bytes, reg->value) != ERROR_OK) - return ERROR_FAIL; - LOG_DEBUG("register %d has value 0x%" PRIx64, reg->number, - buf_get_u64(reg->value, 0, 64)); - } else { - memset(reg->value, 0, width_bytes); - } - - return ERROR_OK; -} - -int rtos_generic_stack_write_reg(struct target *target, - const struct rtos_register_stacking *stacking, - target_addr_t stack_ptr, - uint32_t reg_num, uint8_t *reg_value) -{ - LOG_DEBUG("stack_ptr=" TARGET_ADDR_FMT ", reg_num=%d", stack_ptr, reg_num); - unsigned total_count = MAX(stacking->total_register_count, stacking->num_output_registers); - unsigned i; - for (i = 0; i < total_count; i++) { - if (stacking->register_offsets[i].number == reg_num) - break; - } - if (i >= total_count) { - /* This register is not on the stack. Return error so a caller somewhere - * will just read the register directly from the target. */ - return ERROR_FAIL; - } - - const struct stack_register_offset *offsets = &stacking->register_offsets[i]; - - unsigned width_bytes = DIV_ROUND_UP(offsets->width_bits, 8); - if (offsets->offset >= 0) { - target_addr_t address = stack_ptr; - - if (stacking->stack_growth_direction == 1) - address -= stacking->stack_registers_size; - - LOG_DEBUG("write 0x%" PRIx64 " to register %d", - buf_get_u64(reg_value, 0, offsets->width_bits), reg_num); - if (target_write_buffer( - target, address + offsets->offset, - width_bytes, reg_value) != ERROR_OK) - return ERROR_FAIL; - } else if (offsets->offset == -1) { - /* This register isn't on the stack, but is listed as one of those. We - * read it as 0, and ignore writes. */ - } else if (offsets->offset == -2) { - /* This register requires computation when we "read" it. I'm not sure - * how to handle writes. We can't simply return error here because then - * the higher level code will end up writing the register in the halted - * core, which is definitely not the same as writing it for a thread. */ - LOG_ERROR("Don't know how to write register %d with offset -2 in a thread.", - reg_num); - assert(0); - } else { - LOG_ERROR("Don't know how to handle offset <2."); - assert(0); - } - - return ERROR_OK; -} - -struct rtos *rtos_of_target(struct target *target) +struct rtos *rtos_from_target(struct target *target) { - /* Primarily consider the rtos field of the target itself, secondarily consider - * rtos field SMP leader target, then consider rtos field of any other target in the SMP group. - * Otherwise NULL return means that no associated non-zero rtos field could be found. */ - - struct target_list *pos; - - if ((target->rtos) && (target->rtos->type)) + if (target->rtos && target->rtos->type) return target->rtos; + struct target_list *pos; foreach_smp_target(pos, target->smp_targets) - if ((pos->target->rtos) && (pos->target->rtos->type)) + if (pos->target->rtos && pos->target->rtos->type) return pos->target->rtos; return NULL; @@ -830,7 +731,7 @@ struct rtos *rtos_of_target(struct target *target) int rtos_update_threads(struct target *target) { - struct rtos *rtos = rtos_of_target(target); + struct rtos *rtos = rtos_from_target(target); if (rtos) rtos->type->update_threads(rtos); return ERROR_OK; @@ -854,13 +755,6 @@ void rtos_free_threadlist(struct rtos *rtos) } } -bool rtos_needs_fake_step(struct target *target, int64_t thread_id) -{ - if (target->rtos->type->needs_fake_step) - return target->rtos->type->needs_fake_step(target, thread_id); - return target->rtos->current_thread != thread_id; -} - int rtos_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { @@ -877,6 +771,13 @@ int rtos_write_buffer(struct target *target, target_addr_t address, return ERROR_NOT_IMPLEMENTED; } +bool rtos_needs_fake_step(struct target *target, int64_t thread_id) +{ + if (target->rtos->type->needs_fake_step) + return target->rtos->type->needs_fake_step(target, thread_id); + return target->rtos->current_thread != thread_id; +} + struct target *rtos_swbp_target(struct target *target, target_addr_t address, uint32_t length, enum breakpoint_type type) { diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 3ea9aa61b9..17efccf0e8 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -46,18 +46,14 @@ struct rtos { struct thread_detail *thread_details; int thread_count; int (*gdb_thread_packet)(struct connection *connection, char const *packet, int packet_size); - int (*gdb_target_for_threadid)(struct connection *connection, threadid_t thread_id, struct target **p_target); + int (*gdb_target_for_threadid)(struct connection *connection, int64_t thread_id, struct target **p_target); void *rtos_specific_params; - /* Populated in rtos.c, so that individual RTOSes can register commands. */ - struct command_context *cmd_ctx; }; struct rtos_reg { uint32_t number; uint32_t size; uint8_t value[16]; - /* WARNING: rtos_get_gdb_reg() relies on the fact that value is the last - * element of this struct. Any new fields should be added *before* value. */ }; struct rtos_type { @@ -67,7 +63,7 @@ struct rtos_type { int (*smp_init)(struct target *target); int (*update_threads)(struct rtos *rtos); /** Return a list of general registers, with their values filled out. */ - int (*get_thread_reg_list)(struct rtos *rtos, threadid_t thread_id, + int (*get_thread_reg_list)(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); /** Return the size and value of the specified reg_num. The value is * allocated by the callee and freed by the caller. */ @@ -77,13 +73,6 @@ struct rtos_type { 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); - /** - * Possibly 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. If an RTOS can do this, override - * needs_fake_step(). */ - bool (*needs_fake_step)(struct target *target, threadid_t thread_id); /* Implement these if different threads in the RTOS can see memory * differently (for instance because address translation might be different * for each thread). */ @@ -91,6 +80,13 @@ struct rtos_type { uint8_t *buffer); int (*write_buffer)(struct rtos *rtos, target_addr_t address, uint32_t size, const uint8_t *buffer); + /** + * Possibly 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. If an RTOS can do this, override + * needs_fake_step(). */ + bool (*needs_fake_step)(struct target *target, int64_t thread_id); /* When a software breakpoint is set, it is set on only one target, * because we assume memory is shared across them. By default this is the * first target in the SMP group. Override this function to have @@ -108,9 +104,8 @@ struct stack_register_offset { }; struct rtos_register_stacking { - unsigned stack_registers_size; - int stack_growth_direction; - /* The number of gdb general registers, in order. */ + unsigned char stack_registers_size; + signed char stack_growth_direction; unsigned char num_output_registers; /* Some targets require evaluating the stack to determine the * actual stack pointer for a process. If this field is NULL, @@ -122,11 +117,6 @@ struct rtos_register_stacking { const struct rtos_register_stacking *stacking, target_addr_t stack_ptr); const struct stack_register_offset *register_offsets; - /* Total number of registers on the stack, including the general ones. This - * may be 0 if there are no additional registers on the stack beyond the - * general ones. */ - unsigned int total_register_count; - /* Optional field for targets which may have to implement their own stack read function. * Because stack format can be weird or stack data needed to be edited before passing to the gdb. */ @@ -145,17 +135,9 @@ int rtos_set_reg(struct connection *connection, int reg_num, uint8_t *reg_value); int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, - target_addr_t stack_ptr, + int64_t stack_ptr, struct rtos_reg **reg_list, int *num_regs); -int rtos_generic_stack_read_reg(struct target *target, - const struct rtos_register_stacking *stacking, - target_addr_t stack_ptr, - uint32_t reg_num, struct rtos_reg *reg); -int rtos_generic_stack_write_reg(struct target *target, - const struct rtos_register_stacking *stacking, - target_addr_t stack_ptr, - uint32_t reg_num, uint8_t *reg_value); int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size); int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size); int rtos_get_gdb_reg(struct connection *connection, int reg_num); @@ -165,15 +147,20 @@ 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); -bool rtos_needs_fake_step(struct target *target, threadid_t thread_id); 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); +bool rtos_needs_fake_step(struct target *target, int64_t thread_id); struct target *rtos_swbp_target(struct target *target, target_addr_t address, uint32_t length, enum breakpoint_type type); -struct rtos *rtos_of_target(struct target *target); +/** + * Get the RTOS from the target itself, or from one of the targets in + * the same SMP node, or NULL when no RTOS is set. + */ +struct rtos *rtos_from_target(struct target *target); +// Keep in alphabetic order this list of rtos extern const struct rtos_type chibios_rtos; extern const struct rtos_type chromium_ec_rtos; extern const struct rtos_type ecos_rtos; diff --git a/src/rtos/rtos_standard_stackings.c b/src/rtos/rtos_standard_stackings.c index 360ae9b98e..99cd1540f0 100644 --- a/src/rtos/rtos_standard_stackings.c +++ b/src/rtos/rtos_standard_stackings.c @@ -11,7 +11,6 @@ #include "rtos.h" #include "target/armv7m.h" -#include "target/riscv/riscv.h" #include "rtos_standard_stackings.h" static const struct stack_register_offset rtos_standard_cortex_m3_stack_offsets[ARMV7M_NUM_CORE_REGS] = { @@ -104,181 +103,15 @@ static const struct stack_register_offset rtos_standard_cortex_r4_stack_offsets[ { 26, 0x04, 32 }, /* CSPR */ }; -static const struct stack_register_offset rtos_metal_rv32_stack_offsets[] = { - /* zero isn't on the stack. By making its offset -1 we leave the value at 0 - * inside rtos_generic_stack_read(). */ - { 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, 0x80, 32 }, - /* Registers below are on the stack, but not what gdb expects to return from - * a 'g' packet so are only accessible through get_reg. */ - { GDB_REGNO_MSTATUS, 0x84, 32 }, -}; - -static const struct stack_register_offset rtos_metal_rv64_stack_offsets[] = { - /* zero isn't on the stack. By making its offset -1 we leave the value at 0 - * inside rtos_generic_stack_read(). */ - { GDB_REGNO_ZERO, -1, 64 }, - { GDB_REGNO_RA, 2 * 0x04, 64 }, - { GDB_REGNO_SP, 2 * 0x08, 64 }, - { GDB_REGNO_GP, 2 * 0x0c, 64 }, - { GDB_REGNO_TP, 2 * 0x10, 64 }, - { GDB_REGNO_T0, 2 * 0x14, 64 }, - { GDB_REGNO_T1, 2 * 0x18, 64 }, - { GDB_REGNO_T2, 2 * 0x1c, 64 }, - { GDB_REGNO_FP, 2 * 0x20, 64 }, - { GDB_REGNO_S1, 2 * 0x24, 64 }, - { GDB_REGNO_A0, 2 * 0x28, 64 }, - { GDB_REGNO_A1, 2 * 0x2c, 64 }, - { GDB_REGNO_A2, 2 * 0x30, 64 }, - { GDB_REGNO_A3, 2 * 0x34, 64 }, - { GDB_REGNO_A4, 2 * 0x38, 64 }, - { GDB_REGNO_A5, 2 * 0x3c, 64 }, - { GDB_REGNO_A6, 2 * 0x40, 64 }, - { GDB_REGNO_A7, 2 * 0x44, 64 }, - { GDB_REGNO_S2, 2 * 0x48, 64 }, - { GDB_REGNO_S3, 2 * 0x4c, 64 }, - { GDB_REGNO_S4, 2 * 0x50, 64 }, - { GDB_REGNO_S5, 2 * 0x54, 64 }, - { GDB_REGNO_S6, 2 * 0x58, 64 }, - { GDB_REGNO_S7, 2 * 0x5c, 64 }, - { GDB_REGNO_S8, 2 * 0x60, 64 }, - { GDB_REGNO_S9, 2 * 0x64, 64 }, - { GDB_REGNO_S10, 2 * 0x68, 64 }, - { GDB_REGNO_S11, 2 * 0x6c, 64 }, - { GDB_REGNO_T3, 2 * 0x70, 64 }, - { GDB_REGNO_T4, 2 * 0x74, 64 }, - { GDB_REGNO_T5, 2 * 0x78, 64 }, - { GDB_REGNO_T6, 2 * 0x7c, 64 }, - { GDB_REGNO_PC, 2 * 0x80, 64 }, - /* Registers below are on the stack, but not what gdb expects to return from - * a 'g' packet so are only accessible through get_reg. */ - { GDB_REGNO_MSTATUS, 2 * 0x84, 64 }, -}; - -static const struct stack_register_offset rtos_standard_rv32_stack_offsets[] = { - /* zero isn't on the stack. By making its offset -1 we leave the value at 0 - * inside rtos_generic_stack_read(). */ - { GDB_REGNO_ZERO, -1, 32 }, - { GDB_REGNO_RA, 0x04, 32 }, - { GDB_REGNO_SP, -2, 32 }, - { GDB_REGNO_GP, -2, 32 }, - { GDB_REGNO_TP, -2, 32 }, - { GDB_REGNO_T0, 0x08, 32 }, - { GDB_REGNO_T1, 0x0c, 32 }, - { GDB_REGNO_T2, 0x10, 32 }, - { GDB_REGNO_FP, 0x14, 32 }, - { GDB_REGNO_S1, 0x18, 32 }, - { GDB_REGNO_A0, 0x1c, 32 }, - { GDB_REGNO_A1, 0x20, 32 }, - { GDB_REGNO_A2, 0x24, 32 }, - { GDB_REGNO_A3, 0x28, 32 }, - { GDB_REGNO_A4, 0x2c, 32 }, - { GDB_REGNO_A5, 0x30, 32 }, - { GDB_REGNO_A6, 0x34, 32 }, - { GDB_REGNO_A7, 0x38, 32 }, - { GDB_REGNO_S2, 0x3c, 32 }, - { GDB_REGNO_S3, 0x40, 32 }, - { GDB_REGNO_S4, 0x44, 32 }, - { GDB_REGNO_S5, 0x48, 32 }, - { GDB_REGNO_S6, 0x4c, 32 }, - { GDB_REGNO_S7, 0x50, 32 }, - { GDB_REGNO_S8, 0x54, 32 }, - { GDB_REGNO_S9, 0x58, 32 }, - { GDB_REGNO_S10, 0x5c, 32 }, - { GDB_REGNO_S11, 0x60, 32 }, - { GDB_REGNO_T3, 0x64, 32 }, - { GDB_REGNO_T4, 0x68, 32 }, - { GDB_REGNO_T5, 0x6c, 32 }, - { GDB_REGNO_T6, 0x70, 32 }, - { GDB_REGNO_PC, 0, 32 }, - /* Registers below are on the stack, but not what gdb expects to return from - * a 'g' packet so are only accessible through get_reg. */ - { GDB_REGNO_MSTATUS, 29 * 4, 32 }, -}; - -static const struct stack_register_offset rtos_standard_rv64_stack_offsets[] = { - /* zero isn't on the stack. By making its offset -1 we leave the value at 0 - * inside rtos_generic_stack_read(). */ - { GDB_REGNO_ZERO, -1, 64 }, - { GDB_REGNO_RA, 2 * 0x04, 64 }, - { GDB_REGNO_SP, -2, 64 }, - { GDB_REGNO_GP, -2, 64 }, - { GDB_REGNO_TP, -2, 64 }, - { GDB_REGNO_T0, 2 * 0x08, 64 }, - { GDB_REGNO_T1, 2 * 0x0c, 64 }, - { GDB_REGNO_T2, 2 * 0x10, 64 }, - { GDB_REGNO_FP, 2 * 0x14, 64 }, - { GDB_REGNO_S1, 2 * 0x18, 64 }, - { GDB_REGNO_A0, 2 * 0x1c, 64 }, - { GDB_REGNO_A1, 2 * 0x20, 64 }, - { GDB_REGNO_A2, 2 * 0x24, 64 }, - { GDB_REGNO_A3, 2 * 0x28, 64 }, - { GDB_REGNO_A4, 2 * 0x2c, 64 }, - { GDB_REGNO_A5, 2 * 0x30, 64 }, - { GDB_REGNO_A6, 2 * 0x34, 64 }, - { GDB_REGNO_A7, 2 * 0x38, 64 }, - { GDB_REGNO_S2, 2 * 0x3c, 64 }, - { GDB_REGNO_S3, 2 * 0x40, 64 }, - { GDB_REGNO_S4, 2 * 0x44, 64 }, - { GDB_REGNO_S5, 2 * 0x48, 64 }, - { GDB_REGNO_S6, 2 * 0x4c, 64 }, - { GDB_REGNO_S7, 2 * 0x50, 64 }, - { GDB_REGNO_S8, 2 * 0x54, 64 }, - { GDB_REGNO_S9, 2 * 0x58, 64 }, - { GDB_REGNO_S10, 2 * 0x5c, 64 }, - { GDB_REGNO_S11, 2 * 0x60, 64 }, - { GDB_REGNO_T3, 2 * 0x64, 64 }, - { GDB_REGNO_T4, 2 * 0x68, 64 }, - { GDB_REGNO_T5, 2 * 0x6c, 64 }, - { GDB_REGNO_T6, 2 * 0x70, 64 }, - { GDB_REGNO_PC, 0, 64 }, - /* Registers below are on the stack, but not what gdb expects to return from - * a 'g' packet so are only accessible through get_reg. */ - { GDB_REGNO_MSTATUS, 2 * 29 * 4, 64 }, -}; - static target_addr_t rtos_generic_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr, int align) { - target_addr_t new_stack_ptr = stack_ptr; - if (stacking->stack_growth_direction > 0) - new_stack_ptr -= stacking->stack_registers_size; - else - new_stack_ptr += stacking->stack_registers_size; - target_addr_t aligned_stack_ptr = new_stack_ptr & ~((int64_t)align - 1); - + 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 & ~((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 @@ -395,39 +228,3 @@ const struct rtos_register_stacking rtos_standard_cortex_r4_stacking = { .calculate_process_stack = rtos_generic_stack_align8, .register_offsets = rtos_standard_cortex_r4_stack_offsets }; - -const struct rtos_register_stacking rtos_metal_rv32_stacking = { - .stack_registers_size = (32 + 2) * 4, - .stack_growth_direction = -1, - .num_output_registers = 33, - .calculate_process_stack = rtos_generic_stack_align8, - .register_offsets = rtos_metal_rv32_stack_offsets, - .total_register_count = ARRAY_SIZE(rtos_metal_rv32_stack_offsets) -}; - -const struct rtos_register_stacking rtos_standard_rv32_stacking = { - .stack_registers_size = (32 + 2) * 4, - .stack_growth_direction = -1, - .num_output_registers = 33, - .calculate_process_stack = rtos_generic_stack_align8, - .register_offsets = rtos_standard_rv32_stack_offsets, - .total_register_count = ARRAY_SIZE(rtos_standard_rv32_stack_offsets) -}; - -const struct rtos_register_stacking rtos_metal_rv64_stacking = { - .stack_registers_size = (32 + 2) * 8, - .stack_growth_direction = -1, - .num_output_registers = 33, - .calculate_process_stack = rtos_generic_stack_align8, - .register_offsets = rtos_metal_rv64_stack_offsets, - .total_register_count = ARRAY_SIZE(rtos_metal_rv64_stack_offsets) -}; - -const struct rtos_register_stacking rtos_standard_rv64_stacking = { - .stack_registers_size = (32 + 2) * 8, - .stack_growth_direction = -1, - .num_output_registers = 33, - .calculate_process_stack = rtos_generic_stack_align8, - .register_offsets = rtos_standard_rv64_stack_offsets, - .total_register_count = ARRAY_SIZE(rtos_standard_rv64_stack_offsets) -}; diff --git a/src/rtos/rtos_standard_stackings.h b/src/rtos/rtos_standard_stackings.h index 40a3503a27..99fbe07e48 100644 --- a/src/rtos/rtos_standard_stackings.h +++ b/src/rtos/rtos_standard_stackings.h @@ -21,9 +21,4 @@ target_addr_t rtos_cortex_m_stack_align(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr, size_t xpsr_offset); -extern const struct rtos_register_stacking rtos_standard_rv32_stacking; -extern const struct rtos_register_stacking rtos_standard_rv64_stacking; -extern const struct rtos_register_stacking rtos_metal_rv32_stacking; -extern const struct rtos_register_stacking rtos_metal_rv64_stacking; - #endif /* OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H */ diff --git a/src/rtt/rtt.c b/src/rtt/rtt.c index 15b9a373a5..3c7a966a79 100644 --- a/src/rtt/rtt.c +++ b/src/rtt/rtt.c @@ -288,7 +288,7 @@ int rtt_set_polling_interval(unsigned int interval) int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer, size_t *length) { - if (channel_index >= rtt.ctrl.num_up_channels) { + if (channel_index >= rtt.ctrl.num_down_channels) { LOG_WARNING("rtt: Down-channel %u is not available", channel_index); return ERROR_OK; } diff --git a/src/rtt/rtt.h b/src/rtt/rtt.h index d84fdb40b3..b716dfff9f 100644 --- a/src/rtt/rtt.h +++ b/src/rtt/rtt.h @@ -21,8 +21,11 @@ /* 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 +/* Channel structure size in bytes (32-bit architecture). */ +#define RTT_CHANNEL_SIZE_32 24 + +/* Channel structure size in bytes (64-bit architecture). */ +#define RTT_CHANNEL_SIZE_64 32 /* Minimal channel buffer size in bytes. */ #define RTT_CHANNEL_BUFFER_MIN_SIZE 2 @@ -44,9 +47,9 @@ struct rtt_channel { /** Channel structure address on the target. */ target_addr_t address; /** Channel name address on the target. */ - uint32_t name_addr; + target_addr_t name_addr; /** Buffer address on the target. */ - uint32_t buffer_addr; + target_addr_t buffer_addr; /** Channel buffer size in bytes. */ uint32_t size; /** Write position within the buffer in bytes. */ diff --git a/src/rtt/tcl.c b/src/rtt/tcl.c index bae71b6ce5..beb12d90de 100644 --- a/src/rtt/tcl.c +++ b/src/rtt/tcl.c @@ -117,7 +117,7 @@ COMMAND_HANDLER(handle_rtt_channels_command) ctrl = rtt_get_control(); - command_print(CMD, "Channels: up=%u, down=%u", ctrl->num_up_channels, + command_print(CMD, "Channels: up=%" PRIu32 ", down=%" PRIu32, ctrl->num_up_channels, ctrl->num_down_channels); command_print(CMD, "Up-channels:"); @@ -134,7 +134,7 @@ COMMAND_HANDLER(handle_rtt_channels_command) if (!info.size) continue; - command_print(CMD, "%u: %s %u %u", i, info.name, info.size, + command_print(CMD, "%u: %s %" PRIu32 " %" PRIu32, i, info.name, info.size, info.flags); } @@ -149,7 +149,7 @@ COMMAND_HANDLER(handle_rtt_channels_command) if (!info.size) continue; - command_print(CMD, "%u: %s %u %u", i, info.name, info.size, + command_print(CMD, "%u: %s %" PRIu32 " %" PRIu32, i, info.name, info.size, info.flags); } diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 782a3fc50d..9a9616bfe5 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -50,6 +50,8 @@ * found in most modern embedded processors. */ +#define CTRL(c) ((c) - '@') + enum gdb_output_flag { /* GDB doesn't accept 'O' packets */ GDB_OUTPUT_NO, @@ -172,24 +174,6 @@ struct target *get_available_target_from_connection(struct connection *connectio return target; } -/** Return true iff the given connection includes the given target. */ -static bool gdb_connection_includes_target(struct connection *connection, struct target *target) -{ - struct gdb_service *gdb_service = connection->service->priv; - struct target *service_target = gdb_service->target; - if (service_target->smp) { - struct target_list *tlist; - foreach_smp_target(tlist, service_target->smp_targets) { - struct target *t = tlist->target; - if (t == target) - return true; - } - return false; - } - /* Non-SMP target. */ - return service_target == target; -} - static int gdb_last_signal(struct target *target) { LOG_TARGET_DEBUG(target, "Debug reason is: %s", @@ -236,7 +220,7 @@ static int check_pending(struct connection *connection, } FD_ZERO(&read_fds); - FD_SET(connection->fd, &read_fds); + OCD_FD_SET(connection->fd, &read_fds); tv.tv_sec = timeout_s; tv.tv_usec = 0; @@ -249,7 +233,7 @@ static int check_pending(struct connection *connection, else return ERROR_OK; } - *got_data = FD_ISSET(connection->fd, &read_fds) != 0; + *got_data = OCD_FD_ISSET(connection->fd, &read_fds) != 0; return ERROR_OK; } @@ -442,6 +426,19 @@ static void gdb_log_outgoing_packet(struct connection *connection, const char *p gdb_connection->unique_index, packet_len, packet_buf, checksum); } +static void gdb_log_outgoing_async_notif(struct connection *connection, const char *buf, + unsigned int len) +{ + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) + return; + + struct target *target = get_target_from_connection(connection); + struct gdb_connection *gdb_connection = connection->priv; + + LOG_TARGET_DEBUG(target, "{%d} sending packet: %.*s", + gdb_connection->unique_index, len, buf); +} + static int gdb_put_packet_inner(struct connection *connection, const char *buffer, int len) { @@ -459,8 +456,6 @@ static int gdb_put_packet_inner(struct connection *connection, * At this point we should have nothing in the input queue from GDB, * however sometimes '-' is sent even though we've already received * an ACK (+) for everything we've sent off. - * - * This code appears to sometimes eat a ^C coming from gdb. */ int gotdata; for (;; ) { @@ -477,9 +472,13 @@ static int gdb_put_packet_inner(struct connection *connection, gdb_putback_char(connection, reply); LOG_DEBUG("Unexpected start of new packet"); break; + } else if (reply == CTRL('C')) { + /* do not discard Ctrl-C */ + gdb_putback_char(connection, reply); + break; } - LOG_DEBUG("Discard unexpected char %c", reply); + LOG_WARNING("Discard unexpected char %c", reply); } #endif @@ -488,7 +487,7 @@ static int gdb_put_packet_inner(struct connection *connection, char local_buffer[1024]; local_buffer[0] = '$'; - if ((size_t)len + 4 <= sizeof(local_buffer)) { + if ((size_t)len + 5 <= sizeof(local_buffer)) { /* performance gain on smaller packets by only a single call to gdb_write() */ memcpy(local_buffer + 1, buffer, len++); len += snprintf(local_buffer + len, sizeof(local_buffer) - len, "#%02x", my_checksum); @@ -525,7 +524,7 @@ static int gdb_put_packet_inner(struct connection *connection, gdb_con->output_flag = GDB_OUTPUT_NO; gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); - } else if (reply == 0x3) { + } else if (reply == CTRL('C')) { gdb_con->ctrl_c = true; gdb_log_incoming_packet(connection, ""); retval = gdb_get_char(connection, &reply); @@ -735,7 +734,7 @@ static int gdb_get_packet_inner(struct connection *connection, gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative acknowledgment, but no packet pending"); break; - case 0x3: + case CTRL('C'): gdb_log_incoming_packet(connection, ""); gdb_con->ctrl_c = true; *len = 0; @@ -829,7 +828,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio struct target *ct; struct rtos *rtos; - rtos = rtos_of_target(target); + rtos = rtos_from_target(target); if (rtos) { rtos->current_threadid = rtos->current_thread; rtos->gdb_target_for_threadid(connection, rtos->current_threadid, &ct); @@ -1001,9 +1000,9 @@ static int gdb_target_callback_event_handler(struct target *target, enum target_event event, void *priv) { struct connection *connection = priv; + struct target *gdb_target = get_available_target_from_connection(connection); - /* Propagate this event if it's for any of the targets on this gdb connection. */ - if (!gdb_connection_includes_target(connection, target)) + if (gdb_target != target) return ERROR_OK; switch (event) { @@ -1058,8 +1057,8 @@ static int gdb_new_connection(struct connection *connection) * GDB session could leave dangling breakpoints if e.g. communication * timed out. */ - breakpoint_clear_target(target); - watchpoint_clear_target(target); + breakpoint_remove_all(target); + watchpoint_remove_all(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: @@ -1446,7 +1445,7 @@ static int gdb_get_register_packet(struct connection *connection, 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 gdb_error(connection, ERROR_FAIL); + return ERROR_SERVER_REMOTE_CLOSED; } reg_packet = calloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1, 1); /* plus one for string termination null */ @@ -1559,7 +1558,7 @@ static int gdb_read_memory_packet(struct connection *connection, uint8_t *buffer; char *hex_buffer; - int retval; + int retval = ERROR_OK; /* skip command character */ packet++; @@ -1581,7 +1580,7 @@ static int gdb_read_memory_packet(struct connection *connection, buffer = malloc(len); - LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32, addr, len); retval = ERROR_NOT_IMPLEMENTED; if (target->rtos) @@ -1653,7 +1652,7 @@ static int gdb_write_memory_packet(struct connection *connection, buffer = malloc(len); - LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32, addr, len); if (unhexify(buffer, separator, len) != len) LOG_ERROR("unable to decode memory packet"); @@ -1729,7 +1728,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection, } if (len) { - LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32, addr, len); retval = ERROR_NOT_IMPLEMENTED; if (target->rtos) @@ -1836,10 +1835,12 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, struct target *bp_target = target; if (target->rtos && bp_type == BKPT_SOFT) { bp_target = rtos_swbp_target(target, address, size, bp_type); - if (!bp_target) - return ERROR_FAIL; + if (!bp_target) { + retval = ERROR_FAIL; + break; + } } - retval = breakpoint_add(target, address, size, bp_type); + retval = breakpoint_add(bp_target, address, size, bp_type); } else { assert(packet[0] == 'z'); retval = breakpoint_remove(target, address); @@ -2018,52 +2019,67 @@ static int gdb_memory_map(struct connection *connection, "length=\"" TARGET_ADDR_FMT "\"/>\n", ram_start, p->base - ram_start); - /* Report adjacent groups of same-size sectors. So for - * example top boot CFI flash will list an initial region - * with several large sectors (maybe 128KB) and several - * smaller ones at the end (maybe 32KB). STR7 will have - * regions with 8KB, 32KB, and 64KB sectors; etc. - */ - for (unsigned int j = 0; j < p->num_sectors; j++) { - - /* Maybe start a new group of sectors. */ - if (sector_size == 0) { - if (p->sectors[j].offset + p->sectors[j].size > p->size) { - LOG_WARNING("The flash sector at offset 0x%08" PRIx32 - " overflows the end of %s bank.", - p->sectors[j].offset, p->name); - LOG_WARNING("The rest of bank will not show in gdb memory map."); - break; - } - target_addr_t start; - start = p->base + p->sectors[j].offset; + if (p->read_only) { + xml_printf(&retval, &xml, &pos, &size, + "\n", + p->base, p->size); + } else { + if (p->num_sectors == 0) { xml_printf(&retval, &xml, &pos, &size, "sectors[j].size; - group_len = sector_size; - } else { - group_len += sector_size; /* equal to p->sectors[j].size */ + "start=\"" TARGET_ADDR_FMT "\" " + "length=\"0x%x\">" + "0x%x\n" + "\n", p->base, p->size, p->size); } - /* Does this finish a group of sectors? - * If not, continue an already-started group. + /* Report adjacent groups of same-size sectors. So for + * example top boot CFI flash will list an initial region + * with several large sectors (maybe 128KB) and several + * smaller ones at the end (maybe 32KB). STR7 will have + * regions with 8KB, 32KB, and 64KB sectors; etc. */ - if (j < p->num_sectors - 1 - && p->sectors[j + 1].size == sector_size - && p->sectors[j + 1].offset == p->sectors[j].offset + sector_size - && p->sectors[j + 1].offset + p->sectors[j + 1].size <= p->size) - continue; + for (unsigned int j = 0; j < p->num_sectors; j++) { + // Maybe start a new group of sectors + if (sector_size == 0) { + if (p->sectors[j].offset + p->sectors[j].size > p->size) { + LOG_WARNING("The flash sector at offset 0x%08" PRIx32 + " overflows the end of %s bank.", + p->sectors[j].offset, p->name); + LOG_WARNING("The rest of bank will not show in gdb memory map."); + break; + } + target_addr_t start; + start = p->base + p->sectors[j].offset; + xml_printf(&retval, &xml, &pos, &size, + "sectors[j].size; + group_len = sector_size; + } else { + group_len += sector_size; /* equal to p->sectors[j].size */ + } - xml_printf(&retval, &xml, &pos, &size, - "length=\"0x%x\">\n" - "" - "0x%x\n" - "\n", - group_len, - sector_size); - sector_size = 0; + /* Does this finish a group of sectors? + * If not, continue an already-started group. + */ + if (j < p->num_sectors - 1 + && p->sectors[j + 1].size == sector_size + && p->sectors[j + 1].offset == p->sectors[j].offset + sector_size + && p->sectors[j + 1].offset + p->sectors[j + 1].size <= p->size) + continue; + + xml_printf(&retval, &xml, &pos, &size, + "length=\"0x%x\">\n" + "" + "0x%x\n" + "\n", + group_len, + sector_size); + sector_size = 0; + } } ram_start = p->base + p->size; @@ -2667,7 +2683,6 @@ static int gdb_target_description_supported(struct target *target, bool *support ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) { LOG_ERROR("get register list failed"); - reg_list = NULL; goto error; } @@ -2812,7 +2827,6 @@ static int gdb_query_packet(struct connection *connection, cmd = malloc((packet_size - 6) / 2 + 1); size_t len = unhexify((uint8_t *)cmd, packet + 6, (packet_size - 6) / 2); cmd[len] = 0; - LOG_DEBUG("qRcmd: %s", cmd); /* We want to print all debug output to GDB connection */ gdb_connection->output_flag = GDB_OUTPUT_ALL; @@ -2838,7 +2852,6 @@ static int gdb_query_packet(struct connection *connection, cmd_ctx->current_target_override = saved_target_override; current_gdb_connection = NULL; - target_call_timer_callbacks_now(); gdb_connection->output_flag = GDB_OUTPUT_NO; free(cmd); if (retval == JIM_RETURN) @@ -2852,6 +2865,9 @@ static int gdb_query_packet(struct connection *connection, } else { retmsg = strdup(cretmsg); } + + target_call_timer_callbacks_now(); + if (!retmsg) return ERROR_GDB_BUFFER_TOO_SMALL; @@ -2906,7 +2922,7 @@ static int gdb_query_packet(struct connection *connection, gdb_connection->output_flag = GDB_OUTPUT_NO; if (retval == ERROR_OK) { - snprintf(gdb_reply, 10, "C%8.8" PRIx32 "", checksum); + snprintf(gdb_reply, 10, "C%8.8" PRIx32, checksum); gdb_put_packet(connection, gdb_reply, 9); } else { retval = gdb_error(connection, retval); @@ -3041,7 +3057,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p __attribute__((unused)) int packet_size) { struct gdb_connection *gdb_connection = connection->priv; - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); const char *parse = packet; int retval; @@ -3125,8 +3141,6 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p } if (target->rtos) { - /* FIXME: why is this necessary? rtos state should be up-to-date here already! */ - /* Sometimes this results in picking a different thread than * gdb just requested to step. Then we fake it, and now there's * a different thread selected than gdb expects, so register @@ -3141,8 +3155,8 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p * qXfer:threads:read::0,fff$ * P8=cc060607eb89ca7f$ # write r8 on other thread * g$ - * */ - /* rtos_update_threads(target); */ + */ + /* rtos_update_threads(target); */ target->rtos->gdb_target_for_threadid(connection, thread_id, &ct); @@ -3286,8 +3300,8 @@ static void gdb_restart_inferior(struct connection *connection, const char *pack struct gdb_connection *gdb_con = connection->priv; struct target *target = get_target_from_connection(connection); - breakpoint_clear_target(target); - watchpoint_clear_target(target); + breakpoint_remove_all(target); + watchpoint_remove_all(target); command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", target_name(target)); /* set connection as attached after reset */ @@ -3776,18 +3790,30 @@ 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); + if (strncmp(packet, "jc", 2) == 0) { + /* 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); + } else { + /* ignore unknown packets */ + LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]); + retval = gdb_put_packet(connection, "", 0); + } 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 */ - gdb_write_smp_packet(connection, packet, packet_size); + if (strncmp(packet, "jc", 2) == 0) { + /* 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 */ + gdb_read_smp_packet(connection, packet, packet_size); + } else { + /* ignore unknown packets */ + LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]); + retval = gdb_put_packet(connection, "", 0); + } break; case 'F': @@ -3884,6 +3910,7 @@ static void gdb_async_notif(struct connection *connection) LOG_DEBUG("sending packet '%s'", buf); #endif + gdb_log_outgoing_async_notif(connection, buf, len); gdb_write(connection, buf, len); } @@ -3919,12 +3946,11 @@ static const struct service_driver gdb_service_driver = { 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 (!gdb_service) - return -ENOMEM; + struct gdb_service *gdb_service = malloc(sizeof(struct gdb_service)); + if (!gdb_service) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } LOG_TARGET_INFO(target, "starting gdb server on %s", port); @@ -3933,17 +3959,22 @@ 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_service_driver, port, target->gdb_max_connections, gdb_service); + int retval = add_service(&gdb_service_driver, port, + target->gdb_max_connections, gdb_service); + if (retval != ERROR_OK) { + free(gdb_service); + return retval; + } + /* initialize all targets gdb service with the same pointer */ - { - struct target_list *head; - foreach_smp_target(head, target->smp_targets) { - struct target *curr = head->target; - if (curr != target) - curr->gdb_service = gdb_service; - } + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + if (curr != target) + curr->gdb_service = gdb_service; } - return ret; + + return ERROR_OK; } static int gdb_target_add_one(struct target *target) diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c index 859fdb035e..bc04a571b8 100644 --- a/src/server/ipdbg.c +++ b/src/server/ipdbg.c @@ -381,9 +381,7 @@ static int ipdbg_shift_vir(struct ipdbg_hub *hub) 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; + return jtag_execute_queue(); } static int ipdbg_shift_data(struct ipdbg_hub *hub, uint32_t dn_data, uint32_t *up_data) @@ -885,23 +883,6 @@ COMMAND_HANDLER(handle_ipdbg_stop_command) 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) @@ -944,13 +925,18 @@ COMMAND_HANDLER(handle_ipdbg_cfg_queuing_command) static const struct command_registration ipdbg_hub_subcommand_handlers[] = { { - .name = "ipdbg", + .name = "start", .mode = COMMAND_EXEC, - .help = "IPDBG Hub commands.", - .usage = "", - .chain = ipdbg_hostserver_subcommand_handlers - }, - { + .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" + }, { .name = "queuing", .handler = handle_ipdbg_cfg_queuing_command, .mode = COMMAND_ANY, @@ -1151,7 +1137,6 @@ static const struct command_registration ipdbg_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/server.c b/src/server/server.c index 0649ec942b..9e40d4d002 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -43,10 +43,10 @@ enum shutdown_reason { SHUTDOWN_WITH_ERROR_CODE, /* set by shutdown command; quit with non-zero return code */ SHUTDOWN_WITH_SIGNAL_CODE /* set by sig_handler; exec shutdown then exit with signal as return code */ }; -static enum shutdown_reason shutdown_openocd = CONTINUE_MAIN_LOOP; +static volatile sig_atomic_t shutdown_openocd = CONTINUE_MAIN_LOOP; /* store received signal to exit application by killing ourselves */ -static int last_signal; +static volatile sig_atomic_t last_signal; /* set the polling period to 100ms */ static int polling_period = 100; @@ -161,7 +161,8 @@ static int remove_connection(struct service *service, struct connection *connect /* find connection */ while ((c = *p)) { if (c->fd == connection->fd) { - service->connection_closed(c); + if (service->connection_closed) + service->connection_closed(c); if (service->type == CONNECTION_TCP) close_socket(c->fd); else if (service->type == CONNECTION_PIPE) { @@ -190,8 +191,15 @@ static int remove_connection(struct service *service, struct connection *connect static void free_service(struct service *c) { + if (c->type == CONNECTION_PIPE && c->fd != -1) + close(c->fd); + if (c->type == CONNECTION_TCP && c->fd != -1) + close_socket(c->fd); + if (c->service_dtor) + c->service_dtor(c); free(c->name); free(c->port); + free(c->priv); free(c); } @@ -202,7 +210,11 @@ int add_service(const struct service_driver *driver, const char *port, struct hostent *hp; int so_reuseaddr_option = 1; - c = malloc(sizeof(struct service)); + c = calloc(1, sizeof(*c)); + if (!c) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } c->name = strdup(driver->name); c->port = strdup(port); @@ -214,8 +226,15 @@ int add_service(const struct service_driver *driver, const char *port, c->input = driver->input_handler; c->connection_closed = driver->connection_closed_handler; c->keep_client_alive = driver->keep_client_alive_handler; + c->service_dtor = driver->service_dtor_handler; c->priv = priv; c->next = NULL; + + if (!c->name || !c->port) { + LOG_ERROR("Out of memory"); + goto error; + } + long portnumber; if (strcmp(c->port, "pipe") == 0) c->type = CONNECTION_STDINOUT; @@ -235,8 +254,7 @@ int add_service(const struct service_driver *driver, const char *port, c->fd = socket(AF_INET, SOCK_STREAM, 0); if (c->fd == -1) { LOG_ERROR("error creating socket: %s", strerror(errno)); - free_service(c); - return ERROR_FAIL; + goto error; } setsockopt(c->fd, @@ -257,8 +275,7 @@ int add_service(const struct service_driver *driver, const char *port, if (!hp) { LOG_ERROR("couldn't resolve bindto address: %s", bindto_name); close_socket(c->fd); - free_service(c); - return ERROR_FAIL; + goto error; } memcpy(&c->sin.sin_addr, hp->h_addr_list[0], hp->h_length); } @@ -267,8 +284,7 @@ int add_service(const struct service_driver *driver, const char *port, if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) { 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; + goto error; } #ifndef _WIN32 @@ -287,8 +303,7 @@ int add_service(const struct service_driver *driver, const char *port, if (listen(c->fd, 1) == -1) { LOG_ERROR("couldn't listen on socket: %s", strerror(errno)); close_socket(c->fd); - free_service(c); - return ERROR_FAIL; + goto error; } struct sockaddr_in addr_in; @@ -316,15 +331,13 @@ int add_service(const struct service_driver *driver, const char *port, /* we currently do not support named pipes under win32 * so exit openocd for now */ LOG_ERROR("Named pipes currently not supported under this os"); - free_service(c); - return ERROR_FAIL; + goto error; #else /* Pipe we're reading from */ c->fd = open(c->port, O_RDONLY | O_NONBLOCK); if (c->fd == -1) { LOG_ERROR("could not open %s", c->port); - free_service(c); - return ERROR_FAIL; + goto error; } #endif } @@ -335,6 +348,14 @@ int add_service(const struct service_driver *driver, const char *port, *p = c; return ERROR_OK; + +error: + // Only free() what has been locally allocated + free(c->port); + free(c->name); + free(c); + + return ERROR_FAIL; } static void remove_connections(struct service *service) @@ -371,7 +392,6 @@ int remove_service(const char *name, const char *port) if (tmp->type != CONNECTION_STDINOUT) close_socket(tmp->fd); - free(tmp->priv); free_service(tmp); return ERROR_OK; @@ -390,18 +410,7 @@ static int remove_services(void) struct service *next = c->next; remove_connections(c); - - free(c->name); - - if (c->type == CONNECTION_PIPE) { - if (c->fd != -1) - close(c->fd); - } - free(c->port); - free(c->priv); - /* delete service */ - free(c); - + free_service(c); /* remember the last service for unlinking */ c = next; } @@ -448,7 +457,7 @@ int server_loop(struct command_context *command_context) for (service = services; service; service = service->next) { if (service->fd != -1) { /* listen for new connections */ - FD_SET(service->fd, &read_fds); + OCD_FD_SET(service->fd, &read_fds); if (service->fd > fd_max) fd_max = service->fd; @@ -459,7 +468,7 @@ int server_loop(struct command_context *command_context) for (c = service->connections; c; c = c->next) { /* check for activity on the connection */ - FD_SET(c->fd, &read_fds); + OCD_FD_SET(c->fd, &read_fds); if (c->fd > fd_max) fd_max = c->fd; } @@ -537,7 +546,7 @@ int server_loop(struct command_context *command_context) for (service = services; service; service = service->next) { /* handle new connections on listeners */ if ((service->fd != -1) - && (FD_ISSET(service->fd, &read_fds))) { + && (OCD_FD_ISSET(service->fd, &read_fds))) { if (service->max_connections != 0) add_connection(service, command_context); else { @@ -561,7 +570,7 @@ int server_loop(struct command_context *command_context) struct connection *c; for (c = service->connections; c; ) { - if ((c->fd >= 0 && FD_ISSET(c->fd, &read_fds)) || c->input_pending) { + if ((c->fd >= 0 && OCD_FD_ISSET(c->fd, &read_fds)) || c->input_pending) { retval = service->input(c); if (retval != ERROR_OK) { struct connection *next = c->next; @@ -773,6 +782,23 @@ COMMAND_HANDLER(handle_shutdown_command) return ERROR_COMMAND_CLOSE_CONNECTION; } +COMMAND_HANDLER(handle_exit_command) +{ + if (!tcl_is_from_tcl_session(CMD_CTX) + && !telnet_is_from_telnet_session(CMD_CTX)) { + LOG_WARNING("DEPRECATED: 'exit' should only be used in telnet or Tcl " + "sessions to close the session"); + LOG_WARNING("Did you mean 'shutdown'?"); + return command_run_line(CMD_CTX, "shutdown"); + } + + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* Disconnect telnet / Tcl session */ + return ERROR_COMMAND_CLOSE_CONNECTION; +} + COMMAND_HANDLER(handle_poll_period_command) { if (CMD_ARGC == 0) @@ -809,6 +835,13 @@ static const struct command_registration server_command_handlers[] = { .usage = "", .help = "shut the server down", }, + { + .name = "exit", + .handler = &handle_exit_command, + .mode = COMMAND_ANY, + .usage = "", + .help = "exit (disconnect) telnet or Tcl session", + }, { .name = "poll_period", .handler = &handle_poll_period_command, diff --git a/src/server/server.h b/src/server/server.h index c9d4698af8..8a23e4748a 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -58,6 +58,7 @@ struct service_driver { int (*new_connection_handler)(struct connection *connection); /** callback to handle incoming data */ int (*input_handler)(struct connection *connection); + void (*service_dtor_handler)(struct service *service); /** callback to tear down the connection */ int (*connection_closed_handler)(struct connection *connection); /** called periodically to send keep-alive messages on the connection */ @@ -76,6 +77,7 @@ struct service { int (*new_connection_during_keep_alive)(struct connection *connection); int (*new_connection)(struct connection *connection); int (*input)(struct connection *connection); + void (*service_dtor)(struct service *service); int (*connection_closed)(struct connection *connection); void (*keep_client_alive)(struct connection *connection); void *priv; diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index 16cc55e29b..929fbee0c7 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -230,12 +230,22 @@ static int tcl_input(struct connection *connection) #undef ESTR } else { tclc->tc_line[tclc->tc_lineoffset-1] = '\0'; - command_run_line(connection->cmd_ctx, tclc->tc_line); + retval = command_run_line(connection->cmd_ctx, tclc->tc_line); + + if (retval == ERROR_COMMAND_CLOSE_CONNECTION) { + /* "shutdown" or "exit" executed. + * Send an empty response - just the response termination character. + */ + tcl_output(connection, "\x1a", 1); + return ERROR_SERVER_REMOTE_CLOSED; + } + result = Jim_GetString(Jim_GetResult(interp), &reslen); retval = tcl_output(connection, result, reslen); if (retval != ERROR_OK) return retval; - /* Always output ctrl-z as end of line to allow multiline results */ + + /* Signal the end of response by a termination character (ctrl-z) */ tcl_output(connection, "\x1a", 1); } @@ -284,6 +294,15 @@ int tcl_init(void) return add_service(&tcl_service_driver, tcl_port, CONNECTION_LIMIT_UNLIMITED, NULL); } +bool tcl_is_from_tcl_session(struct command_context *cmd_ctx) +{ + if (!cmd_ctx->output_handler_priv) + return false; + + struct connection *conn = (struct connection *)cmd_ctx->output_handler_priv; + return strcmp(conn->service->name, "tcl") == 0; +} + COMMAND_HANDLER(handle_tcl_port_command) { return CALL_COMMAND_HANDLER(server_pipe_command, &tcl_port); @@ -297,7 +316,7 @@ COMMAND_HANDLER(handle_tcl_notifications_command) if (CMD_CTX->output_handler_priv) connection = CMD_CTX->output_handler_priv; - if (connection && !strcmp(connection->service->name, "tcl")) { + if (connection && tcl_is_from_tcl_session(CMD_CTX)) { tclc = connection->priv; return CALL_COMMAND_HANDLER(handle_command_parse_bool, &tclc->tc_notify, "Target Notification output "); } else { @@ -314,7 +333,7 @@ COMMAND_HANDLER(handle_tcl_trace_command) if (CMD_CTX->output_handler_priv) connection = CMD_CTX->output_handler_priv; - if (connection && !strcmp(connection->service->name, "tcl")) { + if (connection && tcl_is_from_tcl_session(CMD_CTX)) { 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 bee562ce88..f92656f9c3 100644 --- a/src/server/tcl_server.h +++ b/src/server/tcl_server.h @@ -12,5 +12,6 @@ int tcl_init(void); int tcl_register_commands(struct command_context *cmd_ctx); void tcl_service_free(void); +bool tcl_is_from_tcl_session(struct command_context *ctx); #endif /* OPENOCD_SERVER_TCL_SERVER_H */ diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 2c3f769801..52115a529d 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -68,7 +68,7 @@ static int telnet_outputline(struct connection *connection, const char *line) /* process lines in buffer */ while (*line) { - char *line_end = strchr(line, '\n'); + const char *line_end = strchr(line, '\n'); if (line_end) len = line_end-line; @@ -519,6 +519,7 @@ static int telnet_exec_line(struct connection *connection) t_con->prompt_visible = true; if (retval == ERROR_COMMAND_CLOSE_CONNECTION) + /* "shutdown" or "exit" executed. */ return ERROR_SERVER_REMOTE_CLOSED; /* the prompt is always placed at the line beginning */ @@ -601,7 +602,8 @@ static void telnet_auto_complete(struct connection *connection) /* 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])) + while ((usr_cmd_pos < t_con->line_cursor) && + isspace((unsigned char)t_con->line[usr_cmd_pos])) usr_cmd_pos++; /* check user command length */ @@ -615,9 +617,10 @@ static void telnet_auto_complete(struct connection *connection) * 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])) { + if ((i < usr_cmd_len - 1) && isspace((unsigned char)t_con->line[usr_cmd_pos + i]) + && isspace((unsigned char)t_con->line[usr_cmd_pos + i + 1])) { optimized_spaces++; continue; } @@ -671,7 +674,7 @@ static void telnet_auto_complete(struct connection *connection) } else if (jimcmd_is_oocd_command(jim_cmd)) { struct command *cmd = jimcmd_privdata(jim_cmd); - if (cmd && !cmd->handler && !cmd->jim_handler) { + if (cmd && !cmd->handler) { /* Initial part of a multi-word command. Ignore it! */ ignore_cmd = true; } else if (cmd && cmd->mode == COMMAND_CONFIG) { @@ -967,14 +970,14 @@ int telnet_init(char *banner) return ERROR_OK; } -COMMAND_HANDLER(handle_telnet_port_command) +bool telnet_is_from_telnet_session(struct command_context *cmd_ctx) { - return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port); + return cmd_ctx->output_handler == telnet_output; } -COMMAND_HANDLER(handle_exit_command) +COMMAND_HANDLER(handle_telnet_port_command) { - return ERROR_COMMAND_CLOSE_CONNECTION; + return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port); } static const struct command_registration telnet_subcommand_handlers[] = { @@ -991,13 +994,6 @@ static const struct command_registration telnet_subcommand_handlers[] = { }; static const struct command_registration telnet_command_handlers[] = { - { - .name = "exit", - .handler = handle_exit_command, - .mode = COMMAND_ANY, - .usage = "", - .help = "exit telnet session", - }, { .name = "telnet", .chain = telnet_subcommand_handlers, diff --git a/src/server/telnet_server.h b/src/server/telnet_server.h index 313b529f0d..a905b4199e 100644 --- a/src/server/telnet_server.h +++ b/src/server/telnet_server.h @@ -54,5 +54,6 @@ struct telnet_service { int telnet_init(char *banner); int telnet_register_commands(struct command_context *command_context); void telnet_service_free(void); +bool telnet_is_from_telnet_session(struct command_context *cmd_ctx); #endif /* OPENOCD_SERVER_TELNET_SERVER_H */ diff --git a/src/svf/svf.c b/src/svf/svf.c index ce994686f1..7491ad6515 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -702,71 +702,71 @@ static int svf_read_command_from_file(FILE *fd) ch = svf_read_line[0]; while (!cmd_ok && (ch != 0)) { switch (ch) { - case '!': + case '!': + slash = 0; + if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) + return ERROR_FAIL; + svf_line_number++; + i = -1; + break; + case '/': + if (++slash == 2) { slash = 0; - if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) + if (svf_getline(&svf_read_line, &svf_read_line_size, + svf_fd) <= 0) return ERROR_FAIL; svf_line_number++; i = -1; + } + break; + case ';': + slash = 0; + cmd_ok = 1; + break; + case '\n': + svf_line_number++; + if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) + return ERROR_FAIL; + i = -1; + /* fallthrough */ + case '\r': + slash = 0; + /* Don't save '\r' and '\n' if no data is parsed */ + if (!cmd_pos) break; - case '/': - if (++slash == 2) { - slash = 0; - if (svf_getline(&svf_read_line, &svf_read_line_size, - svf_fd) <= 0) - return ERROR_FAIL; - svf_line_number++; - i = -1; - } - break; - case ';': - slash = 0; - cmd_ok = 1; - break; - case '\n': - svf_line_number++; - if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) + /* fallthrough */ + default: + /* The parsing code currently expects a space + * before parentheses -- "TDI (123)". Also a + * space afterwards -- "TDI (123) TDO(456)". + * But such spaces are optional... instead of + * parser updates, cope with that by adding the + * spaces as needed. + * + * Ensure there are 3 bytes available, for: + * - current character + * - added space. + * - terminating NUL ('\0') + */ + 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) { + LOG_ERROR("not enough memory"); return ERROR_FAIL; - i = -1; - /* fallthrough */ - case '\r': - slash = 0; - /* Don't save '\r' and '\n' if no data is parsed */ - if (!cmd_pos) - break; - /* fallthrough */ - default: - /* The parsing code currently expects a space - * before parentheses -- "TDI (123)". Also a - * space afterwards -- "TDI (123) TDO(456)". - * But such spaces are optional... instead of - * parser updates, cope with that by adding the - * spaces as needed. - * - * Ensure there are 3 bytes available, for: - * - current character - * - added space. - * - terminating NUL ('\0') - */ - 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) { - LOG_ERROR("not enough memory"); - return ERROR_FAIL; - } } + } - /* insert a space before '(' */ - if ('(' == ch) - svf_command_buffer[cmd_pos++] = ' '; + /* insert a space before '(' */ + if ('(' == ch) + svf_command_buffer[cmd_pos++] = ' '; - svf_command_buffer[cmd_pos++] = (char)toupper(ch); + svf_command_buffer[cmd_pos++] = (char)toupper(ch); - /* insert a space after ')' */ - if (')' == ch) - svf_command_buffer[cmd_pos++] = ' '; - break; + /* insert a space after ')' */ + if (')' == ch) + svf_command_buffer[cmd_pos++] = ' '; + break; } ch = svf_read_line[++i]; } @@ -780,31 +780,33 @@ static int svf_read_command_from_file(FILE *fd) static int svf_parse_cmd_string(char *str, int len, char **argus, int *num_of_argu) { - int pos = 0, num = 0, space_found = 1, in_bracket = 0; + bool space_found = true, in_bracket = false; + int pos = 0, num = 0; while (pos < len) { switch (str[pos]) { - case '!': - case '/': - LOG_ERROR("fail to parse svf command"); - return ERROR_FAIL; - case '(': - in_bracket = 1; - goto parse_char; - case ')': - in_bracket = 0; - goto parse_char; - default: -parse_char: - if (!in_bracket && isspace((int) str[pos])) { - space_found = 1; - str[pos] = '\0'; - } else if (space_found) { - argus[num++] = &str[pos]; - space_found = 0; - } - break; + case '!': + case '/': + LOG_ERROR("fail to parse svf command"); + return ERROR_FAIL; + case '(': + in_bracket = true; + break; + case ')': + in_bracket = false; + break; + default: + break; + } + + if (!in_bracket && isspace((int)str[pos])) { + space_found = true; + str[pos] = '\0'; + } else if (space_found) { + argus[num++] = &str[pos]; + space_found = false; } + pos++; } @@ -979,10 +981,295 @@ static int svf_execute_tap(void) return ERROR_OK; } +static int svf_xxr_common(char **argus, int num_of_argu, char command, struct svf_xxr_para *xxr_para_tmp) +{ + int i, i_tmp; + uint8_t **pbuffer_tmp; + struct scan_field field; + + /* 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]); + return ERROR_FAIL; + } + i_tmp = xxr_para_tmp->len; + xxr_para_tmp->len = atoi(argus[1]); + /* If we are to enlarge the buffers, all parts of xxr_para_tmp + * need to be freed */ + if (i_tmp < xxr_para_tmp->len) { + free(xxr_para_tmp->tdi); + xxr_para_tmp->tdi = NULL; + free(xxr_para_tmp->tdo); + xxr_para_tmp->tdo = NULL; + free(xxr_para_tmp->mask); + xxr_para_tmp->mask = NULL; + free(xxr_para_tmp->smask); + xxr_para_tmp->smask = NULL; + } + + LOG_DEBUG("\tlength = %d", xxr_para_tmp->len); + xxr_para_tmp->data_mask = 0; + for (i = 2; i < num_of_argu; i += 2) { + if ((strlen(argus[i + 1]) < 3) || (argus[i + 1][0] != '(') || + argus[i + 1][strlen(argus[i + 1]) - 1] != ')') { + LOG_ERROR("data section error"); + return ERROR_FAIL; + } + argus[i + 1][strlen(argus[i + 1]) - 1] = '\0'; + /* TDI, TDO, MASK, SMASK */ + if (!strcmp(argus[i], "TDI")) { + /* TDI */ + pbuffer_tmp = &xxr_para_tmp->tdi; + xxr_para_tmp->data_mask |= XXR_TDI; + } else if (!strcmp(argus[i], "TDO")) { + /* TDO */ + pbuffer_tmp = &xxr_para_tmp->tdo; + xxr_para_tmp->data_mask |= XXR_TDO; + } else if (!strcmp(argus[i], "MASK")) { + /* MASK */ + pbuffer_tmp = &xxr_para_tmp->mask; + xxr_para_tmp->data_mask |= XXR_MASK; + } else if (!strcmp(argus[i], "SMASK")) { + /* SMASK */ + pbuffer_tmp = &xxr_para_tmp->smask; + xxr_para_tmp->data_mask |= XXR_SMASK; + } else { + LOG_ERROR("unknown parameter: %s", argus[i]); + return ERROR_FAIL; + } + if (svf_copy_hexstring_to_binary(&argus[i + 1][1], pbuffer_tmp, i_tmp, + xxr_para_tmp->len) != ERROR_OK) { + LOG_ERROR("fail to parse hex value"); + return ERROR_FAIL; + } + SVF_BUF_LOG(DEBUG, *pbuffer_tmp, xxr_para_tmp->len, argus[i]); + } + /* If a command changes the length of the last scan of the same type and the + * MASK parameter is absent, */ + /* the mask pattern used is all cares */ + if (!(xxr_para_tmp->data_mask & XXR_MASK) && i_tmp != xxr_para_tmp->len) { + /* MASK not defined and length changed */ + if (svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, xxr_para_tmp->len) + != ERROR_OK) { + LOG_ERROR("fail to adjust length of array"); + return ERROR_FAIL; + } + buf_set_ones(xxr_para_tmp->mask, xxr_para_tmp->len); + } + /* If TDO is absent, no comparison is needed, set the mask to 0 */ + if (!(xxr_para_tmp->data_mask & XXR_TDO)) { + if (!xxr_para_tmp->tdo) { + if (svf_adjust_array_length(&xxr_para_tmp->tdo, i_tmp, xxr_para_tmp->len) + != ERROR_OK) { + LOG_ERROR("fail to adjust length of array"); + return ERROR_FAIL; + } + } + if (!xxr_para_tmp->mask) { + if (svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, xxr_para_tmp->len) + != ERROR_OK) { + LOG_ERROR("fail to adjust length of array"); + return ERROR_FAIL; + } + } + memset(xxr_para_tmp->mask, 0, (xxr_para_tmp->len + 7) >> 3); + } + /* do scan if necessary */ + 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; + if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { + /* reallocate buffer */ + if (svf_realloc_buffers(svf_buffer_index + ((i + 7) >> 3)) != ERROR_OK) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + } + + /* assemble dr data */ + i = 0; + buf_set_buf(svf_para.hdr_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.hdr_para.len); + i += svf_para.hdr_para.len; + buf_set_buf(svf_para.sdr_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.sdr_para.len); + i += svf_para.sdr_para.len; + buf_set_buf(svf_para.tdr_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.tdr_para.len); + i += svf_para.tdr_para.len; + + /* add check data */ + if (svf_para.sdr_para.data_mask & XXR_TDO) { + /* assemble dr mask data */ + i = 0; + buf_set_buf(svf_para.hdr_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.hdr_para.len); + i += svf_para.hdr_para.len; + buf_set_buf(svf_para.sdr_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.sdr_para.len); + i += svf_para.sdr_para.len; + buf_set_buf(svf_para.tdr_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.tdr_para.len); + + /* assemble dr check data */ + i = 0; + buf_set_buf(svf_para.hdr_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.hdr_para.len); + i += svf_para.hdr_para.len; + buf_set_buf(svf_para.sdr_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.sdr_para.len); + i += svf_para.sdr_para.len; + buf_set_buf(svf_para.tdr_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.tdr_para.len); + i += svf_para.tdr_para.len; + + svf_add_check_para(1, svf_buffer_index, i); + } else { + svf_add_check_para(0, svf_buffer_index, i); + } + field.num_bits = i; + field.out_value = &svf_tdi_buffer[svf_buffer_index]; + field.in_value = (xxr_para_tmp->data_mask & XXR_TDO) ? &svf_tdi_buffer[svf_buffer_index] : NULL; + if (!svf_nil) { + /* NOTE: doesn't use SVF-specified state paths */ + jtag_add_plain_dr_scan(field.num_bits, + field.out_value, + field.in_value, + svf_para.dr_end_state); + } + + if (svf_addcycles) + jtag_add_clocks(svf_addcycles); + + svf_buffer_index += (i + 7) >> 3; + } else if (command == SIR) { + /* check buffer size first, reallocate if necessary */ + i = svf_para.hir_para.len + svf_para.sir_para.len + + svf_para.tir_para.len; + if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { + if (svf_realloc_buffers(svf_buffer_index + ((i + 7) >> 3)) != ERROR_OK) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + } + + /* assemble ir data */ + i = 0; + buf_set_buf(svf_para.hir_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.hir_para.len); + i += svf_para.hir_para.len; + buf_set_buf(svf_para.sir_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.sir_para.len); + i += svf_para.sir_para.len; + buf_set_buf(svf_para.tir_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.tir_para.len); + i += svf_para.tir_para.len; + + /* add check data */ + if (svf_para.sir_para.data_mask & XXR_TDO) { + /* assemble dr mask data */ + i = 0; + buf_set_buf(svf_para.hir_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.hir_para.len); + i += svf_para.hir_para.len; + buf_set_buf(svf_para.sir_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.sir_para.len); + i += svf_para.sir_para.len; + buf_set_buf(svf_para.tir_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.tir_para.len); + + /* assemble dr check data */ + i = 0; + buf_set_buf(svf_para.hir_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.hir_para.len); + i += svf_para.hir_para.len; + buf_set_buf(svf_para.sir_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.sir_para.len); + i += svf_para.sir_para.len; + buf_set_buf(svf_para.tir_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.tir_para.len); + i += svf_para.tir_para.len; + + svf_add_check_para(1, svf_buffer_index, i); + } else { + svf_add_check_para(0, svf_buffer_index, i); + } + field.num_bits = i; + field.out_value = &svf_tdi_buffer[svf_buffer_index]; + field.in_value = (xxr_para_tmp->data_mask & XXR_TDO) ? &svf_tdi_buffer[svf_buffer_index] : NULL; + if (!svf_nil) { + /* NOTE: doesn't use SVF-specified state paths */ + jtag_add_plain_ir_scan(field.num_bits, + field.out_value, + field.in_value, + svf_para.ir_end_state); + } + + svf_buffer_index += (i + 7) >> 3; + } + + return ERROR_OK; +} + static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) { char *argus[256], command; - int num_of_argu = 0, i; + int num_of_argu = 0, i, retval; /* tmp variable */ int i_tmp; @@ -990,10 +1277,6 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) /* for RUNTEST */ int run_count; float min_time; - /* for XXR */ - struct svf_xxr_para *xxr_para_tmp; - uint8_t **pbuffer_tmp; - struct scan_field field; /* for STATE */ enum tap_state *path = NULL, state; /* flag padding commands skipped due to -tap command */ @@ -1009,594 +1292,327 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) command = svf_find_string_in_array(argus[0], (char **)svf_command_name, ARRAY_SIZE(svf_command_name)); switch (command) { - case ENDDR: - case ENDIR: - if (num_of_argu != 2) { - LOG_ERROR("invalid parameter of %s", argus[0]); - return ERROR_FAIL; - } + case ENDDR: + case ENDIR: + if (num_of_argu != 2) { + LOG_ERROR("invalid parameter of %s", argus[0]); + return ERROR_FAIL; + } - i_tmp = tap_state_by_name(argus[1]); + i_tmp = tap_state_by_name(argus[1]); - if (svf_tap_state_is_stable(i_tmp)) { - if (command == ENDIR) { - svf_para.ir_end_state = i_tmp; - LOG_DEBUG("\tIR end_state = %s", - tap_state_name(i_tmp)); - } else { - svf_para.dr_end_state = i_tmp; - LOG_DEBUG("\tDR end_state = %s", - tap_state_name(i_tmp)); - } + if (svf_tap_state_is_stable(i_tmp)) { + if (command == ENDIR) { + svf_para.ir_end_state = i_tmp; + LOG_DEBUG("\tIR end_state = %s", + tap_state_name(i_tmp)); } else { - LOG_ERROR("%s: %s is not a stable state", - argus[0], argus[1]); - return ERROR_FAIL; + svf_para.dr_end_state = i_tmp; + LOG_DEBUG("\tDR end_state = %s", + tap_state_name(i_tmp)); } - break; - case FREQUENCY: - if ((num_of_argu != 1) && (num_of_argu != 3)) { - LOG_ERROR("invalid parameter of %s", argus[0]); + } else { + LOG_ERROR("%s: %s is not a stable state", + argus[0], argus[1]); + return ERROR_FAIL; + } + break; + case FREQUENCY: + if (num_of_argu != 1 && num_of_argu != 3) { + LOG_ERROR("invalid parameter of %s", argus[0]); + return ERROR_FAIL; + } + if (num_of_argu == 1) { + /* TODO: set jtag speed to full speed */ + svf_para.frequency = 0; + } else { + if (strcmp(argus[2], "HZ")) { + LOG_ERROR("HZ not found in FREQUENCY command"); return ERROR_FAIL; } - if (num_of_argu == 1) { - /* TODO: set jtag speed to full speed */ - svf_para.frequency = 0; - } else { - if (strcmp(argus[2], "HZ")) { - LOG_ERROR("HZ not found in FREQUENCY command"); - return ERROR_FAIL; - } - if (svf_execute_tap() != ERROR_OK) - return ERROR_FAIL; - svf_para.frequency = atof(argus[1]); - /* TODO: set jtag speed to */ - if (svf_para.frequency > 0) { - command_run_linef(cmd_ctx, - "adapter speed %d", - (int)svf_para.frequency / 1000); - LOG_DEBUG("\tfrequency = %f", svf_para.frequency); - } - } - break; - case HDR: - if (svf_tap_is_specified) { - padding_command_skipped = 1; - break; - } - xxr_para_tmp = &svf_para.hdr_para; - 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; - case TDR: - if (svf_tap_is_specified) { - padding_command_skipped = 1; - break; - } - xxr_para_tmp = &svf_para.tdr_para; - 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; - case SDR: - xxr_para_tmp = &svf_para.sdr_para; - goto xxr_common; - case SIR: - xxr_para_tmp = &svf_para.sir_para; - 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]); + if (svf_execute_tap() != ERROR_OK) return ERROR_FAIL; + svf_para.frequency = atof(argus[1]); + /* TODO: set jtag speed to */ + if (svf_para.frequency > 0) { + command_run_linef(cmd_ctx, + "adapter speed %d", + (int)svf_para.frequency / 1000); + LOG_DEBUG("\tfrequency = %f", svf_para.frequency); } - i_tmp = xxr_para_tmp->len; - xxr_para_tmp->len = atoi(argus[1]); - /* If we are to enlarge the buffers, all parts of xxr_para_tmp - * need to be freed */ - if (i_tmp < xxr_para_tmp->len) { - free(xxr_para_tmp->tdi); - xxr_para_tmp->tdi = NULL; - free(xxr_para_tmp->tdo); - xxr_para_tmp->tdo = NULL; - free(xxr_para_tmp->mask); - xxr_para_tmp->mask = NULL; - free(xxr_para_tmp->smask); - xxr_para_tmp->smask = NULL; - } - - LOG_DEBUG("\tlength = %d", xxr_para_tmp->len); - xxr_para_tmp->data_mask = 0; - for (i = 2; i < num_of_argu; i += 2) { - if ((strlen(argus[i + 1]) < 3) || (argus[i + 1][0] != '(') || - (argus[i + 1][strlen(argus[i + 1]) - 1] != ')')) { - LOG_ERROR("data section error"); - return ERROR_FAIL; - } - argus[i + 1][strlen(argus[i + 1]) - 1] = '\0'; - /* TDI, TDO, MASK, SMASK */ - if (!strcmp(argus[i], "TDI")) { - /* TDI */ - pbuffer_tmp = &xxr_para_tmp->tdi; - xxr_para_tmp->data_mask |= XXR_TDI; - } else if (!strcmp(argus[i], "TDO")) { - /* TDO */ - pbuffer_tmp = &xxr_para_tmp->tdo; - xxr_para_tmp->data_mask |= XXR_TDO; - } else if (!strcmp(argus[i], "MASK")) { - /* MASK */ - pbuffer_tmp = &xxr_para_tmp->mask; - xxr_para_tmp->data_mask |= XXR_MASK; - } else if (!strcmp(argus[i], "SMASK")) { - /* SMASK */ - pbuffer_tmp = &xxr_para_tmp->smask; - xxr_para_tmp->data_mask |= XXR_SMASK; - } else { - LOG_ERROR("unknown parameter: %s", argus[i]); - return ERROR_FAIL; - } - if (ERROR_OK != - svf_copy_hexstring_to_binary(&argus[i + 1][1], pbuffer_tmp, i_tmp, - xxr_para_tmp->len)) { - LOG_ERROR("fail to parse hex value"); - return ERROR_FAIL; - } - SVF_BUF_LOG(DEBUG, *pbuffer_tmp, xxr_para_tmp->len, argus[i]); - } - /* If a command changes the length of the last scan of the same type and the - * MASK parameter is absent, */ - /* the mask pattern used is all cares */ - if (!(xxr_para_tmp->data_mask & XXR_MASK) && (i_tmp != xxr_para_tmp->len)) { - /* MASK not defined and length changed */ - if (ERROR_OK != - svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, - xxr_para_tmp->len)) { - LOG_ERROR("fail to adjust length of array"); - return ERROR_FAIL; - } - buf_set_ones(xxr_para_tmp->mask, xxr_para_tmp->len); - } - /* If TDO is absent, no comparison is needed, set the mask to 0 */ - if (!(xxr_para_tmp->data_mask & XXR_TDO)) { - if (!xxr_para_tmp->tdo) { - if (ERROR_OK != - svf_adjust_array_length(&xxr_para_tmp->tdo, i_tmp, - xxr_para_tmp->len)) { - LOG_ERROR("fail to adjust length of array"); - return ERROR_FAIL; - } - } - if (!xxr_para_tmp->mask) { - if (ERROR_OK != - svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, - xxr_para_tmp->len)) { - LOG_ERROR("fail to adjust length of array"); - return ERROR_FAIL; - } - } - memset(xxr_para_tmp->mask, 0, (xxr_para_tmp->len + 7) >> 3); - } - /* do scan if necessary */ - 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; - if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { - /* reallocate buffer */ - if (svf_realloc_buffers(svf_buffer_index + ((i + 7) >> 3)) != ERROR_OK) { - LOG_ERROR("not enough memory"); - return ERROR_FAIL; - } - } - - /* assemble dr data */ - i = 0; - buf_set_buf(svf_para.hdr_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.hdr_para.len); - i += svf_para.hdr_para.len; - buf_set_buf(svf_para.sdr_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.sdr_para.len); - i += svf_para.sdr_para.len; - buf_set_buf(svf_para.tdr_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.tdr_para.len); - i += svf_para.tdr_para.len; - - /* add check data */ - if (svf_para.sdr_para.data_mask & XXR_TDO) { - /* assemble dr mask data */ - i = 0; - buf_set_buf(svf_para.hdr_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.hdr_para.len); - i += svf_para.hdr_para.len; - buf_set_buf(svf_para.sdr_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.sdr_para.len); - i += svf_para.sdr_para.len; - buf_set_buf(svf_para.tdr_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.tdr_para.len); - - /* assemble dr check data */ - i = 0; - buf_set_buf(svf_para.hdr_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.hdr_para.len); - i += svf_para.hdr_para.len; - buf_set_buf(svf_para.sdr_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.sdr_para.len); - i += svf_para.sdr_para.len; - buf_set_buf(svf_para.tdr_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.tdr_para.len); - i += svf_para.tdr_para.len; - - svf_add_check_para(1, svf_buffer_index, i); - } else - svf_add_check_para(0, svf_buffer_index, i); - field.num_bits = i; - field.out_value = &svf_tdi_buffer[svf_buffer_index]; - field.in_value = (xxr_para_tmp->data_mask & XXR_TDO) ? &svf_tdi_buffer[svf_buffer_index] : NULL; - if (!svf_nil) { - /* NOTE: doesn't use SVF-specified state paths */ - jtag_add_plain_dr_scan(field.num_bits, - field.out_value, - field.in_value, - svf_para.dr_end_state); - } - - if (svf_addcycles) - jtag_add_clocks(svf_addcycles); - - svf_buffer_index += (i + 7) >> 3; - } else if (command == SIR) { - /* check buffer size first, reallocate if necessary */ - i = svf_para.hir_para.len + svf_para.sir_para.len + - svf_para.tir_para.len; - if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { - if (svf_realloc_buffers(svf_buffer_index + ((i + 7) >> 3)) != ERROR_OK) { - LOG_ERROR("not enough memory"); - return ERROR_FAIL; - } - } - - /* assemble ir data */ - i = 0; - buf_set_buf(svf_para.hir_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.hir_para.len); - i += svf_para.hir_para.len; - buf_set_buf(svf_para.sir_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.sir_para.len); - i += svf_para.sir_para.len; - buf_set_buf(svf_para.tir_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.tir_para.len); - i += svf_para.tir_para.len; - - /* add check data */ - if (svf_para.sir_para.data_mask & XXR_TDO) { - /* assemble dr mask data */ - i = 0; - buf_set_buf(svf_para.hir_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.hir_para.len); - i += svf_para.hir_para.len; - buf_set_buf(svf_para.sir_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.sir_para.len); - i += svf_para.sir_para.len; - buf_set_buf(svf_para.tir_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.tir_para.len); - - /* assemble dr check data */ - i = 0; - buf_set_buf(svf_para.hir_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.hir_para.len); - i += svf_para.hir_para.len; - buf_set_buf(svf_para.sir_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.sir_para.len); - i += svf_para.sir_para.len; - buf_set_buf(svf_para.tir_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.tir_para.len); - i += svf_para.tir_para.len; - - svf_add_check_para(1, svf_buffer_index, i); - } else - svf_add_check_para(0, svf_buffer_index, i); - field.num_bits = i; - field.out_value = &svf_tdi_buffer[svf_buffer_index]; - field.in_value = (xxr_para_tmp->data_mask & XXR_TDO) ? &svf_tdi_buffer[svf_buffer_index] : NULL; - if (!svf_nil) { - /* NOTE: doesn't use SVF-specified state paths */ - jtag_add_plain_ir_scan(field.num_bits, - field.out_value, - field.in_value, - svf_para.ir_end_state); - } - - svf_buffer_index += (i + 7) >> 3; - } + } + break; + case HDR: + if (svf_tap_is_specified) { + padding_command_skipped = 1; break; - case PIO: - case PIOMAP: - LOG_ERROR("PIO and PIOMAP are not supported"); + } + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.hdr_para); + if (retval != ERROR_OK) + return retval; + break; + case HIR: + if (svf_tap_is_specified) { + padding_command_skipped = 1; + break; + } + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.hir_para); + if (retval != ERROR_OK) + return retval; + break; + case TDR: + if (svf_tap_is_specified) { + padding_command_skipped = 1; + break; + } + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.tdr_para); + if (retval != ERROR_OK) + return retval; + break; + case TIR: + if (svf_tap_is_specified) { + padding_command_skipped = 1; + break; + } + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.tir_para); + if (retval != ERROR_OK) + return retval; + break; + case SDR: + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.sdr_para); + if (retval != ERROR_OK) + return retval; + break; + case SIR: + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.sir_para); + if (retval != ERROR_OK) + return retval; + break; + case PIO: + case PIOMAP: + LOG_ERROR("PIO and PIOMAP are not supported"); + return ERROR_FAIL; + case RUNTEST: + /* RUNTEST [run_state] run_count run_clk [min_time SEC [MAXIMUM max_time + * SEC]] [ENDSTATE end_state] */ + /* RUNTEST [run_state] min_time SEC [MAXIMUM max_time SEC] [ENDSTATE + * end_state] */ + if (num_of_argu < 3 || num_of_argu > 11) { + LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; - case RUNTEST: - /* RUNTEST [run_state] run_count run_clk [min_time SEC [MAXIMUM max_time - * SEC]] [ENDSTATE end_state] */ - /* RUNTEST [run_state] min_time SEC [MAXIMUM max_time SEC] [ENDSTATE - * end_state] */ - if ((num_of_argu < 3) || (num_of_argu > 11)) { - LOG_ERROR("invalid parameter of %s", argus[0]); + } + /* init */ + run_count = 0; + min_time = 0; + i = 1; + + /* run_state */ + i_tmp = tap_state_by_name(argus[i]); + if (i_tmp != TAP_INVALID) { + if (svf_tap_state_is_stable(i_tmp)) { + svf_para.runtest_run_state = i_tmp; + + /* When a run_state is specified, the new + * run_state becomes the default end_state. + */ + svf_para.runtest_end_state = i_tmp; + LOG_DEBUG("\trun_state = %s", tap_state_name(i_tmp)); + i++; + } else { + LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); return ERROR_FAIL; } - /* init */ - run_count = 0; - min_time = 0; - i = 1; - - /* run_state */ - i_tmp = tap_state_by_name(argus[i]); - if (i_tmp != TAP_INVALID) { - if (svf_tap_state_is_stable(i_tmp)) { - svf_para.runtest_run_state = i_tmp; - - /* When a run_state is specified, the new - * run_state becomes the default end_state. - */ - svf_para.runtest_end_state = i_tmp; - LOG_DEBUG("\trun_state = %s", tap_state_name(i_tmp)); - i++; - } else { - LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); - return ERROR_FAIL; - } - } + } - /* run_count run_clk */ - if (((i + 2) <= num_of_argu) && strcmp(argus[i + 1], "SEC")) { - if (!strcmp(argus[i + 1], "TCK")) { - /* clock source is TCK */ - run_count = atoi(argus[i]); - LOG_DEBUG("\trun_count@TCK = %d", run_count); - } else { - LOG_ERROR("%s not supported for clock", argus[i + 1]); - return ERROR_FAIL; - } - i += 2; - } - /* min_time SEC */ - if (((i + 2) <= num_of_argu) && !strcmp(argus[i + 1], "SEC")) { - min_time = atof(argus[i]); - LOG_DEBUG("\tmin_time = %fs", min_time); - i += 2; - } - /* MAXIMUM max_time SEC */ - if (((i + 3) <= num_of_argu) && - !strcmp(argus[i], "MAXIMUM") && !strcmp(argus[i + 2], "SEC")) { - float max_time = 0; - max_time = atof(argus[i + 1]); - LOG_DEBUG("\tmax_time = %fs", max_time); - i += 3; + /* run_count run_clk */ + if (((i + 2) <= num_of_argu) && strcmp(argus[i + 1], "SEC")) { + if (!strcmp(argus[i + 1], "TCK")) { + /* clock source is TCK */ + run_count = atoi(argus[i]); + LOG_DEBUG("\trun_count@TCK = %d", run_count); + } else { + LOG_ERROR("%s not supported for clock", argus[i + 1]); + return ERROR_FAIL; } - /* ENDSTATE end_state */ - if (((i + 2) <= num_of_argu) && !strcmp(argus[i], "ENDSTATE")) { - i_tmp = tap_state_by_name(argus[i + 1]); + i += 2; + } + /* min_time SEC */ + if (((i + 2) <= num_of_argu) && !strcmp(argus[i + 1], "SEC")) { + min_time = atof(argus[i]); + LOG_DEBUG("\tmin_time = %fs", min_time); + i += 2; + } + /* MAXIMUM max_time SEC */ + if (((i + 3) <= num_of_argu) && + !strcmp(argus[i], "MAXIMUM") && !strcmp(argus[i + 2], "SEC")) { + float max_time = 0; + max_time = atof(argus[i + 1]); + LOG_DEBUG("\tmax_time = %fs", max_time); + i += 3; + } + /* ENDSTATE end_state */ + if (((i + 2) <= num_of_argu) && !strcmp(argus[i], "ENDSTATE")) { + i_tmp = tap_state_by_name(argus[i + 1]); - if (svf_tap_state_is_stable(i_tmp)) { - svf_para.runtest_end_state = i_tmp; - LOG_DEBUG("\tend_state = %s", tap_state_name(i_tmp)); - } else { - LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); - return ERROR_FAIL; - } - i += 2; + if (svf_tap_state_is_stable(i_tmp)) { + svf_para.runtest_end_state = i_tmp; + LOG_DEBUG("\tend_state = %s", tap_state_name(i_tmp)); + } else { + LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); + return ERROR_FAIL; } + i += 2; + } - /* all parameter should be parsed */ - if (i == num_of_argu) { + /* all parameter should be parsed */ + if (i == num_of_argu) { #if 1 - /* FIXME handle statemove failures */ - uint32_t min_usec = 1000000 * min_time; + /* FIXME handle statemove failures */ + uint32_t min_usec = 1000000 * min_time; - /* enter into run_state if necessary */ - if (cmd_queue_cur_state != svf_para.runtest_run_state) - svf_add_statemove(svf_para.runtest_run_state); + /* enter into run_state if necessary */ + if (cmd_queue_cur_state != svf_para.runtest_run_state) + svf_add_statemove(svf_para.runtest_run_state); - /* add clocks and/or min wait */ - if (run_count > 0) { - if (!svf_nil) - jtag_add_clocks(run_count); - } + /* add clocks and/or min wait */ + if (run_count > 0) { + if (!svf_nil) + jtag_add_clocks(run_count); + } - if (min_usec > 0) { - if (!svf_nil) - jtag_add_sleep(min_usec); - } + if (min_usec > 0) { + if (!svf_nil) + jtag_add_sleep(min_usec); + } - /* move to end_state if necessary */ - if (svf_para.runtest_end_state != svf_para.runtest_run_state) - svf_add_statemove(svf_para.runtest_end_state); + /* move to end_state if necessary */ + if (svf_para.runtest_end_state != svf_para.runtest_run_state) + svf_add_statemove(svf_para.runtest_end_state); #else - if (svf_para.runtest_run_state != TAP_IDLE) { - LOG_ERROR("cannot runtest in %s state", - tap_state_name(svf_para.runtest_run_state)); - return ERROR_FAIL; - } - - if (!svf_nil) - jtag_add_runtest(run_count, svf_para.runtest_end_state); -#endif - } else { - LOG_ERROR("fail to parse parameter of RUNTEST, %d out of %d is parsed", - i, - num_of_argu); + if (svf_para.runtest_run_state != TAP_IDLE) { + LOG_ERROR("cannot runtest in %s state", + tap_state_name(svf_para.runtest_run_state)); return ERROR_FAIL; } - break; - case STATE: - /* STATE [pathstate1 [pathstate2 ...[pathstaten]]] stable_state */ - if (num_of_argu < 2) { - LOG_ERROR("invalid parameter of %s", argus[0]); + + if (!svf_nil) + jtag_add_runtest(run_count, svf_para.runtest_end_state); +#endif + } else { + LOG_ERROR("fail to parse parameter of RUNTEST, %d out of %d is parsed", + i, + num_of_argu); + return ERROR_FAIL; + } + break; + case STATE: + /* STATE [pathstate1 [pathstate2 ...[pathstaten]]] stable_state */ + if (num_of_argu < 2) { + LOG_ERROR("invalid parameter of %s", argus[0]); + return ERROR_FAIL; + } + if (num_of_argu > 2) { + /* STATE pathstate1 ... stable_state */ + path = malloc((num_of_argu - 1) * sizeof(enum tap_state)); + if (!path) { + LOG_ERROR("not enough memory"); return ERROR_FAIL; } - if (num_of_argu > 2) { - /* STATE pathstate1 ... stable_state */ - path = malloc((num_of_argu - 1) * sizeof(enum tap_state)); - if (!path) { - LOG_ERROR("not enough memory"); + num_of_argu--; /* num of path */ + i_tmp = 1; /* path is from parameter 1 */ + for (i = 0; i < num_of_argu; i++, i_tmp++) { + path[i] = tap_state_by_name(argus[i_tmp]); + if (path[i] == TAP_INVALID) { + LOG_ERROR("%s: %s is not a valid state", argus[0], argus[i_tmp]); + free(path); return ERROR_FAIL; } - num_of_argu--; /* num of path */ - i_tmp = 1; /* path is from parameter 1 */ - for (i = 0; i < num_of_argu; i++, i_tmp++) { - path[i] = tap_state_by_name(argus[i_tmp]); - if (path[i] == TAP_INVALID) { - LOG_ERROR("%s: %s is not a valid state", argus[0], argus[i_tmp]); - free(path); - return ERROR_FAIL; - } - /* OpenOCD refuses paths containing TAP_RESET */ - if (path[i] == TAP_RESET) { - /* FIXME last state MUST be stable! */ - if (i > 0) { - if (!svf_nil) - jtag_add_pathmove(i, path); - } + /* OpenOCD refuses paths containing TAP_RESET */ + if (path[i] == TAP_RESET) { + /* FIXME last state MUST be stable! */ + if (i > 0) { if (!svf_nil) - jtag_add_tlr(); - num_of_argu -= i + 1; - i = -1; - } - } - if (num_of_argu > 0) { - /* execute last path if necessary */ - if (svf_tap_state_is_stable(path[num_of_argu - 1])) { - /* last state MUST be stable state */ - if (!svf_nil) - jtag_add_pathmove(num_of_argu, path); - LOG_DEBUG("\tmove to %s by path_move", - tap_state_name(path[num_of_argu - 1])); - } else { - LOG_ERROR("%s: %s is not a stable state", - argus[0], - tap_state_name(path[num_of_argu - 1])); - free(path); - return ERROR_FAIL; + jtag_add_pathmove(i, path); } + if (!svf_nil) + jtag_add_tlr(); + num_of_argu -= i + 1; + i = -1; } - - free(path); - path = NULL; - } else { - /* STATE stable_state */ - state = tap_state_by_name(argus[1]); - if (svf_tap_state_is_stable(state)) { - LOG_DEBUG("\tmove to %s by svf_add_statemove", - tap_state_name(state)); - /* FIXME handle statemove failures */ - svf_add_statemove(state); + } + if (num_of_argu > 0) { + /* execute last path if necessary */ + if (svf_tap_state_is_stable(path[num_of_argu - 1])) { + /* last state MUST be stable state */ + if (!svf_nil) + jtag_add_pathmove(num_of_argu, path); + LOG_DEBUG("\tmove to %s by path_move", + tap_state_name(path[num_of_argu - 1])); } else { LOG_ERROR("%s: %s is not a stable state", - argus[0], tap_state_name(state)); + argus[0], + tap_state_name(path[num_of_argu - 1])); + free(path); return ERROR_FAIL; } } - break; - case TRST: - /* TRST trst_mode */ - if (num_of_argu != 2) { - LOG_ERROR("invalid parameter of %s", argus[0]); + + free(path); + path = NULL; + } else { + /* STATE stable_state */ + state = tap_state_by_name(argus[1]); + if (svf_tap_state_is_stable(state)) { + LOG_DEBUG("\tmove to %s by svf_add_statemove", + tap_state_name(state)); + /* FIXME handle statemove failures */ + svf_add_statemove(state); + } else { + LOG_ERROR("%s: %s is not a stable state", + argus[0], tap_state_name(state)); return ERROR_FAIL; } - if (svf_para.trst_mode != TRST_ABSENT) { - if (svf_execute_tap() != ERROR_OK) - return ERROR_FAIL; - i_tmp = svf_find_string_in_array(argus[1], - (char **)svf_trst_mode_name, - ARRAY_SIZE(svf_trst_mode_name)); - switch (i_tmp) { - case TRST_ON: - if (!svf_nil) - jtag_add_reset(1, 0); - break; - case TRST_Z: - case TRST_OFF: - if (!svf_nil) - jtag_add_reset(0, 0); - break; - case TRST_ABSENT: - break; - default: - LOG_ERROR("unknown TRST mode: %s", argus[1]); - return ERROR_FAIL; - } - svf_para.trst_mode = i_tmp; - LOG_DEBUG("\ttrst_mode = %s", svf_trst_mode_name[svf_para.trst_mode]); - } else { - LOG_ERROR("can not accept TRST command if trst_mode is ABSENT"); + } + break; + case TRST: + /* TRST trst_mode */ + if (num_of_argu != 2) { + LOG_ERROR("invalid parameter of %s", argus[0]); + return ERROR_FAIL; + } + if (svf_para.trst_mode != TRST_ABSENT) { + if (svf_execute_tap() != ERROR_OK) + return ERROR_FAIL; + i_tmp = svf_find_string_in_array(argus[1], + (char **)svf_trst_mode_name, + ARRAY_SIZE(svf_trst_mode_name)); + switch (i_tmp) { + case TRST_ON: + if (!svf_nil) + jtag_add_reset(1, 0); + break; + case TRST_Z: + case TRST_OFF: + if (!svf_nil) + jtag_add_reset(0, 0); + break; + case TRST_ABSENT: + break; + default: + LOG_ERROR("unknown TRST mode: %s", argus[1]); return ERROR_FAIL; } - break; - default: - LOG_ERROR("invalid svf command: %s", argus[0]); + svf_para.trst_mode = i_tmp; + LOG_DEBUG("\ttrst_mode = %s", svf_trst_mode_name[svf_para.trst_mode]); + } else { + LOG_ERROR("can not accept TRST command if trst_mode is ABSENT"); return ERROR_FAIL; + } + break; + default: + LOG_ERROR("invalid svf command: %s", argus[0]); + return ERROR_FAIL; } if (!svf_quiet) { @@ -1604,7 +1620,7 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) LOG_USER("(Above Padding command skipped, as per -tap argument)"); } - if (debug_level >= LOG_LVL_DEBUG) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { /* for convenient debugging, execute tap if possible */ if ((svf_buffer_index > 0) && (((command != STATE) && (command != RUNTEST)) || diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 1a76864180..3d855ab52f 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -34,6 +34,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la if HAVE_CAPSTONE %C%_libtarget_la_CPPFLAGS += $(CAPSTONE_CFLAGS) %C%_libtarget_la_LIBADD += $(CAPSTONE_LIBS) +%C%_libtarget_la_SOURCES += %D%/oocd_capstone.c endif TARGET_CORE_SRC = \ @@ -75,6 +76,7 @@ ARMV6_SRC = \ ARMV7_SRC = \ %D%/armv7m.c \ + %D%/armv7m_cache.c \ %D%/armv7m_trace.c \ %D%/cortex_m.c \ %D%/armv7a.c \ @@ -87,7 +89,6 @@ ARMV8_SRC = \ %D%/armv8_dpm.c \ %D%/armv8_opcodes.c \ %D%/aarch64.c \ - %D%/a64_disassembler.c \ %D%/armv8.c \ %D%/armv8_cache.c @@ -164,7 +165,6 @@ 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 \ @@ -183,6 +183,7 @@ ARC_SRC = \ %D%/armv4_5_cache.h \ %D%/armv7a.h \ %D%/armv7m.h \ + %D%/armv7m_cache.h \ %D%/armv7m_trace.h \ %D%/armv8.h \ %D%/armv8_dpm.h \ @@ -235,7 +236,8 @@ ARC_SRC = \ %D%/arc_cmd.h \ %D%/arc_jtag.h \ %D%/arc_mem.h \ - %D%/rtt.h + %D%/rtt.h \ + %D%/oocd_capstone.h include %D%/openrisc/Makefile.am include %D%/riscv/Makefile.am diff --git a/src/target/a64_disassembler.c b/src/target/a64_disassembler.c deleted file mode 100644 index ca3d3ea7a9..0000000000 --- a/src/target/a64_disassembler.c +++ /dev/null @@ -1,134 +0,0 @@ -// 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 -#include "target.h" -#include "a64_disassembler.h" - -#if HAVE_CAPSTONE - -#include - -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 deleted file mode 100644 index 28fcf4b331..0000000000 --- a/src/target/a64_disassembler.h +++ /dev/null @@ -1,19 +0,0 @@ -/* 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 101cb14408..f8962cbfd5 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -11,7 +11,6 @@ #include "breakpoints.h" #include "aarch64.h" -#include "a64_disassembler.h" #include "register.h" #include "target_request.h" #include "target_type.h" @@ -39,7 +38,8 @@ struct aarch64_private_config { struct arm_cti *cti; }; -static int aarch64_poll(struct target *target); +static int aarch64_poll_smp(struct target *target, bool smp, + bool postpone_event); static int aarch64_debug_entry(struct target *target); static int aarch64_restore_context(struct target *target, bool bpwp); static int aarch64_set_breakpoint(struct target *target, @@ -50,7 +50,7 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint); static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); -static int aarch64_mmu(struct target *target, int *enabled); +static int aarch64_mmu(struct target *target, bool *enabled); static int aarch64_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys); static int aarch64_read_cpu_memory(struct target *target, @@ -215,9 +215,28 @@ static int aarch64_init_debug_access(struct target *target) struct armv8_common *armv8 = target_to_armv8(target); int retval; uint32_t dummy; + uint32_t lsr; LOG_DEBUG("%s", target_name(target)); + /* while the LAR shouldn't even be visible on the external debugger + * interface, this unlock is needed on at least NXP's LX2160A + */ + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + ARM_CS_LAR, ARM_CS_LAR_UNLOCK_KEY); + if (retval != ERROR_OK) { + LOG_WARNING("debug unit unlock write failed - register may not be implemented"); + } else { + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + ARM_CS_LSR, &lsr); + if (retval != ERROR_OK) + LOG_WARNING("debug unit unlock write OK but status read failed."); + else if ((lsr & (ARM_CS_LSR_SLI | ARM_CS_LSR_SLK)) + == (ARM_CS_LSR_SLI | ARM_CS_LSR_SLK)) + /* try to continue anyway, at least read accesses still work */ + LOG_WARNING("debug unit locked, may cause further failures."); + } + retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_OSLAR, 0); if (retval != ERROR_OK) { @@ -262,12 +281,9 @@ static int aarch64_dap_write_memap_register_u32(struct target *target, target_addr_t address, uint32_t value) { - int retval; struct armv8_common *armv8 = target_to_armv8(target); - retval = mem_ap_write_atomic_u32(armv8->debug_ap, address, value); - - return retval; + return mem_ap_write_atomic_u32(armv8->debug_ap, address, value); } static int aarch64_dpm_setup(struct aarch64_common *a8, uint64_t debug) @@ -469,9 +485,8 @@ static int aarch64_halt_smp(struct target *target, bool exc_target) return retval; } -static int update_halt_gdb(struct target *target, enum target_debug_reason debug_reason) +static int aarch64_update_halt_gdb(struct target *target, enum target_debug_reason debug_reason) { - struct target *gdb_target = NULL; struct target_list *head; struct target *curr; @@ -480,7 +495,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug aarch64_halt_smp(target, true); } - /* poll all targets in the group, but skip the target that serves GDB */ + /* poll all targets in the group */ foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ @@ -491,31 +506,43 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug /* skip targets that were already halted */ if (curr->state == TARGET_HALTED) continue; - /* remember the gdb_service->target */ - if (curr->gdb_service) - gdb_target = curr->gdb_service->target; - /* skip it */ - if (curr == gdb_target) - continue; - /* avoid recursion in aarch64_poll() */ - curr->smp = 0; - aarch64_poll(curr); - curr->smp = 1; + const bool smp = false; + const bool postpone_event = true; + aarch64_poll_smp(curr, smp, postpone_event); } - /* after all targets were updated, poll the gdb serving target */ - if (gdb_target && gdb_target != target) - aarch64_poll(gdb_target); - return ERROR_OK; } +enum postponed_halt_events_op { + POSTPONED_HALT_EVENT_CLEAR, + POSTPONED_HALT_EVENT_EMIT +}; + +static void aarch64_smp_postponed_halt_events(struct list_head *smp_targets, + enum postponed_halt_events_op op) +{ + struct target_list *head; + foreach_smp_target(head, smp_targets) { + struct target *t = head->target; + if (!t->smp_halt_event_postponed) + continue; + + if (op == POSTPONED_HALT_EVENT_EMIT) { + LOG_TARGET_DEBUG(t, "sending postponed target event 'halted'"); + target_call_event_callbacks(t, TARGET_EVENT_HALTED); + } + t->smp_halt_event_postponed = false; + } +} + /* * Aarch64 Run control */ -static int aarch64_poll(struct target *target) +static int aarch64_poll_smp(struct target *target, bool smp, + bool postpone_event) { struct armv8_common *armv8 = target_to_armv8(target); enum target_state prev_target_state; @@ -550,17 +577,25 @@ static int aarch64_poll(struct target *target) if (retval != ERROR_OK) return retval; - if (target->smp) - update_halt_gdb(target, debug_reason); + if (smp) + aarch64_update_halt_gdb(target, debug_reason); + + if (arm_semihosting(target, &retval) != 0) { + if (smp) + aarch64_smp_postponed_halt_events(target->smp_targets, + POSTPONED_HALT_EVENT_CLEAR); - if (arm_semihosting(target, &retval) != 0) return retval; + } switch (prev_target_state) { case TARGET_RUNNING: case TARGET_UNKNOWN: case TARGET_RESET: - target_call_event_callbacks(target, TARGET_EVENT_HALTED); + if (postpone_event) + target->smp_halt_event_postponed = true; + else + target_call_event_callbacks(target, TARGET_EVENT_HALTED); break; case TARGET_DEBUG_RUNNING: target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); @@ -568,6 +603,10 @@ static int aarch64_poll(struct target *target) default: break; } + + if (smp) + aarch64_smp_postponed_halt_events(target->smp_targets, + POSTPONED_HALT_EVENT_EMIT); } } else if (prsr & PRSR_RESET) { target->state = TARGET_RESET; @@ -578,6 +617,12 @@ static int aarch64_poll(struct target *target) return retval; } +static int aarch64_poll(struct target *target) +{ + const bool postpone_event = false; + return aarch64_poll_smp(target, target->smp != 0, postpone_event); +} + static int aarch64_halt(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); @@ -613,22 +658,22 @@ static int aarch64_restore_one(struct target *target, bool current, * kill the return address */ switch (arm->core_state) { - case ARM_STATE_ARM: - resume_pc &= 0xFFFFFFFC; - break; - case ARM_STATE_AARCH64: - resume_pc &= 0xFFFFFFFFFFFFFFFCULL; - break; - case ARM_STATE_THUMB: - case ARM_STATE_THUMB_EE: - /* When the return address is loaded into PC - * bit 0 must be 1 to stay in Thumb state - */ - resume_pc |= 0x1; - break; - case ARM_STATE_JAZELLE: - LOG_ERROR("How do I resume into Jazelle state??"); - return ERROR_FAIL; + case ARM_STATE_ARM: + resume_pc &= 0xFFFFFFFC; + break; + case ARM_STATE_AARCH64: + resume_pc &= 0xFFFFFFFFFFFFFFFCULL; + break; + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + /* When the return address is loaded into PC + * bit 0 must be 1 to stay in Thumb state + */ + resume_pc |= 0x1; + break; + case ARM_STATE_JAZELLE: + LOG_ERROR("How do I resume into Jazelle state??"); + return ERROR_FAIL; } LOG_DEBUG("resume pc = 0x%016" PRIx64, resume_pc); buf_set_u64(arm->pc->value, 0, 64, resume_pc); @@ -861,7 +906,7 @@ static int aarch64_step_restart_smp(struct target *target) retval = aarch64_do_restart_one(curr, RESTART_LAZY); if (retval != ERROR_OK) break; -} + } return retval; } @@ -925,6 +970,8 @@ static int aarch64_resume(struct target *target, bool current, } if (curr->state != TARGET_RUNNING) { + struct armv8_common *curr_armv8 = target_to_armv8(curr); + curr_armv8->last_run_control_op = ARMV8_RUNCONTROL_RESUME; curr->state = TARGET_RUNNING; curr->debug_reason = DBG_REASON_NOTHALTED; target_call_event_callbacks(curr, TARGET_EVENT_RESUMED); @@ -1095,20 +1142,19 @@ static int aarch64_post_debug_entry(struct target *target) 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) { + if (!armv8->armv8_mmu.armv8_cache.info_valid) { armv8_identify_cache(armv8); armv8_read_mpidr(armv8); } if (armv8->is_armv8r) { - armv8->armv8_mmu.mmu_enabled = 0; + armv8->armv8_mmu.mmu_enabled = false; } else { - armv8->armv8_mmu.mmu_enabled = - (aarch64->system_control_reg & 0x1U) ? 1 : 0; + armv8->armv8_mmu.mmu_enabled = aarch64->system_control_reg & 0x1U; } armv8->armv8_mmu.armv8_cache.d_u_cache_enabled = - (aarch64->system_control_reg & 0x4U) ? 1 : 0; + aarch64->system_control_reg & 0x4U; armv8->armv8_mmu.armv8_cache.i_cache_enabled = - (aarch64->system_control_reg & 0x1000U) ? 1 : 0; + aarch64->system_control_reg & 0x1000U; return ERROR_OK; } @@ -2529,7 +2575,7 @@ static int aarch64_read_phys_memory(struct target *target, static int aarch64_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - int mmu_enabled = 0; + bool mmu_enabled = false; int retval; /* determine if MMU was enabled on target stop */ @@ -2566,7 +2612,7 @@ static int aarch64_write_phys_memory(struct target *target, static int aarch64_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - int mmu_enabled = 0; + bool mmu_enabled = false; int retval; /* determine if MMU was enabled on target stop */ @@ -2683,16 +2729,18 @@ static int aarch64_examine_first(struct target *target) retval = mem_ap_read_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_MEMFEATURE0, &tmp0); - retval += mem_ap_read_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_MEMFEATURE0 + 4, &tmp1); + if (retval == ERROR_OK) + retval = mem_ap_read_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_MEMFEATURE0 + 4, &tmp1); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "Memory Model Type"); return retval; } retval = mem_ap_read_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DBGFEATURE0, &tmp2); - retval += mem_ap_read_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_DBGFEATURE0 + 4, &tmp3); + if (retval == ERROR_OK) + retval = mem_ap_read_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DBGFEATURE0 + 4, &tmp3); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "ID_AA64DFR0_EL1"); return retval; @@ -2877,7 +2925,7 @@ static void aarch64_deinit_target(struct target *target) free(aarch64); } -static int aarch64_mmu(struct target *target, int *enabled) +static int aarch64_mmu(struct target *target, bool *enabled) { struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; @@ -2886,7 +2934,7 @@ static int aarch64_mmu(struct target *target, int *enabled) return ERROR_TARGET_NOT_HALTED; } if (armv8->is_armv8r) - *enabled = 0; + *enabled = false; else *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled; return ERROR_OK; @@ -2898,6 +2946,45 @@ static int aarch64_virt2phys(struct target *target, target_addr_t virt, return armv8_mmu_translate_va_pa(target, virt, phys, 1); } +static int aarch64_insn_set(struct command_invocation *cmd, + struct target *target, const char **insn_set) +{ + if (target->state != TARGET_HALTED) { + command_print(cmd, "[%s] not halted", target_name(target)); + return ERROR_TARGET_NOT_HALTED; + } + + struct arm *arm = target_to_arm(target); + + switch (arm->core_state) { + case ARM_STATE_AARCH64: + if (target->endianness == TARGET_BIG_ENDIAN) + *insn_set = "arm64be"; + else + *insn_set = "arm64"; + break; + + case ARM_STATE_ARM: + if (target->endianness == TARGET_BIG_ENDIAN) + *insn_set = "armbe"; + else + *insn_set = "arm"; + break; + + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + *insn_set = "thumb"; + break; + + default: + command_print(cmd, "[%s] unknown core_state %d", target_name(target), + arm->core_state); + return ERROR_FAIL; + } + + return ERROR_OK; +} + /* * private target configuration items */ @@ -3007,39 +3094,6 @@ 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); @@ -3186,13 +3240,6 @@ 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, @@ -3282,6 +3329,8 @@ struct target_type aarch64_target = { .write_phys_memory = aarch64_write_phys_memory, .mmu = aarch64_mmu, .virt2phys = aarch64_virt2phys, + + .insn_set = aarch64_insn_set, }; struct target_type armv8r_target = { @@ -3318,4 +3367,6 @@ struct target_type armv8r_target = { .init_target = aarch64_init_target, .deinit_target = aarch64_deinit_target, .examine = aarch64_examine, + + .insn_set = aarch64_insn_set, }; diff --git a/src/target/aarch64.h b/src/target/aarch64.h index b265e82498..db0bcdc154 100644 --- a/src/target/aarch64.h +++ b/src/target/aarch64.h @@ -16,8 +16,6 @@ #define CPUDBG_TTYPR 0xD0C #define ID_AA64PFR0_EL1 0xD20 #define ID_AA64DFR0_EL1 0xD28 -#define CPUDBG_LOCKACCESS 0xFB0 -#define CPUDBG_LOCKSTATUS 0xFB4 #define BRP_NORMAL 0 #define BRP_CONTEXT 1 diff --git a/src/target/adi_v5_dapdirect.c b/src/target/adi_v5_dapdirect.c index 07ea313d19..12d1a68815 100644 --- a/src/target/adi_v5_dapdirect.c +++ b/src/target/adi_v5_dapdirect.c @@ -62,7 +62,7 @@ static const struct command_registration dapdirect_jtag_subcommand_handlers[] = .help = "declare a new TAP", .usage = "basename tap_type '-irlen' count " "['-enable'|'-disable'] " - "['-expected_id' number] " + "['-expected-id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " @@ -154,7 +154,7 @@ static const struct command_registration dapdirect_swd_subcommand_handlers[] = { .help = "declare a new SWD DAP", .usage = "basename dap_type ['-irlen' count] " "['-enable'|'-disable'] " - "['-expected_id' number] " + "['-expected-id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 2d286136a5..3c27224f5e 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -699,7 +700,7 @@ static const struct command_registration swd_commands[] = { .help = "declare a new SWD DAP", .usage = "basename dap_type ['-irlen' count] " "['-enable'|'-disable'] " - "['-expected_id' number] " + "['-expected-id' number] " "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " @@ -722,8 +723,6 @@ static const struct command_registration swd_handlers[] = { static int swd_select(struct command_context *ctx) { - /* FIXME: only place where global 'adapter_driver' is still needed */ - extern struct adapter_driver *adapter_driver; const struct swd_driver *swd = adapter_driver->swd_ops; int retval; diff --git a/src/target/arc.c b/src/target/arc.c index f2482c25ef..18a53a3a7f 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -748,8 +748,6 @@ static int arc_examine(struct target *target) /* Read BCRs and configure optional registers. */ CHECK_RETVAL(arc_configure(target)); - - target_set_examined(target); } return ERROR_OK; @@ -769,7 +767,7 @@ static int arc_exit_debug(struct target *target) target->state = TARGET_HALTED; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); - if (debug_level >= LOG_LVL_DEBUG) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { LOG_TARGET_DEBUG(target, "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_TARGET_DEBUG(target, "core STATUS32: 0x%08" PRIx32, value); @@ -824,7 +822,7 @@ static int arc_halt(struct target *target) CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); /* some more debug information */ - if (debug_level >= LOG_LVL_DEBUG) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { LOG_TARGET_DEBUG(target, "core stopped (halted) DEGUB-REG: 0x%08" PRIx32, value); CHECK_RETVAL(arc_get_register_value(target, "status32", &value)); LOG_TARGET_DEBUG(target, "core STATUS32: 0x%08" PRIx32, value); @@ -1148,7 +1146,7 @@ static int arc_arch_state(struct target *target) { uint32_t pc_value; - if (debug_level < LOG_LVL_DEBUG) + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return ERROR_OK; CHECK_RETVAL(arc_get_register_value(target, "pc", &pc_value)); @@ -1892,18 +1890,18 @@ static int arc_set_watchpoint(struct target *target, 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_TARGET_ERROR(target, "BUG: watchpoint->rw neither read, write nor access"); - return ERROR_FAIL; + 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_TARGET_ERROR(target, "BUG: watchpoint->rw neither read, write nor access"); + return ERROR_FAIL; } int retval = arc_configure_actionpoint(target, wp_num, diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index bf8a8aa28b..2e42398d28 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -709,29 +709,29 @@ COMMAND_HANDLER(arc_handle_get_reg_field) int retval = arc_reg_get_field(target, reg_name, field_name, &value); switch (retval) { - case ERROR_OK: - break; - case ERROR_ARC_REGISTER_NOT_FOUND: - command_print(CMD, - "Register `%s' has not been found.", reg_name); - return ERROR_COMMAND_ARGUMENT_INVALID; - case ERROR_ARC_REGISTER_IS_NOT_STRUCT: - command_print(CMD, - "Register `%s' must have 'struct' type.", reg_name); - return ERROR_COMMAND_ARGUMENT_INVALID; - case ERROR_ARC_REGISTER_FIELD_NOT_FOUND: - 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: - command_print(CMD, - "Field `%s' is not a 'bitfield' field in a structure.", - field_name); - return ERROR_COMMAND_ARGUMENT_INVALID; - default: - /* Pass through other errors. */ - return retval; + case ERROR_OK: + break; + case ERROR_ARC_REGISTER_NOT_FOUND: + command_print(CMD, + "Register `%s' has not been found.", reg_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + case ERROR_ARC_REGISTER_IS_NOT_STRUCT: + command_print(CMD, + "Register `%s' must have 'struct' type.", reg_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + case ERROR_ARC_REGISTER_FIELD_NOT_FOUND: + 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: + command_print(CMD, + "Field `%s' is not a 'bitfield' field in a structure.", + field_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + default: + /* Pass through other errors. */ + return retval; } command_print(CMD, "0x%" PRIx32, value); diff --git a/src/target/arm.h b/src/target/arm.h index 79ec99d117..020b4912a6 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -108,7 +108,8 @@ enum arm_mode { /* VFPv3 internal register numbers mapping to d0:31 */ enum { - ARM_VFP_V3_D0 = 51, + ARM_VFP_V3_D0 = 53, + // numbering should not overlap with e.g. armv4_5.c arm_core_regs .gdb_index ARM_VFP_V3_D1, ARM_VFP_V3_D2, ARM_VFP_V3_D3, @@ -322,10 +323,14 @@ int armv4_5_run_algorithm_inner(struct target *target, int arm_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int arm_blank_check_memory(struct target *target, - struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); + struct target_memory_check_block *blocks, unsigned int num_blocks, + uint8_t erased_value, unsigned int *checked); void arm_set_cpsr(struct arm *arm, uint32_t cpsr); struct reg *arm_reg_current(struct arm *arm, unsigned int regnum); struct reg *armv8_reg_current(struct arm *arm, unsigned int regnum); +int armv4_5_insn_set(struct command_invocation *cmd, struct target *target, + const char **insn_set); + #endif /* OPENOCD_TARGET_ARM_H */ diff --git a/src/target/arm11.c b/src/target/arm11.c index 583830f948..4524b38d42 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -414,19 +414,19 @@ static uint32_t arm11_nextpc(struct arm11_common *arm11, bool current, * kill the return address */ switch (arm11->arm.core_state) { - case ARM_STATE_ARM: - address &= 0xFFFFFFFC; - break; - case ARM_STATE_THUMB: - /* When the return address is loaded into PC - * bit 0 must be 1 to stay in Thumb state - */ - address |= 0x1; - break; - - /* catch-all for JAZELLE and THUMB_EE */ - default: - break; + case ARM_STATE_ARM: + address &= 0xFFFFFFFC; + break; + case ARM_STATE_THUMB: + /* When the return address is loaded into PC + * bit 0 must be 1 to stay in Thumb state + */ + address |= 0x1; + break; + + /* catch-all for JAZELLE and THUMB_EE */ + default: + break; } buf_set_u32(value, 0, 32, address); @@ -469,7 +469,7 @@ static int arm11_resume(struct target *target, bool current, for (bp = target->breakpoints; bp; bp = bp->next) { if (bp->address == address) { - LOG_DEBUG("must step over %08" TARGET_PRIxADDR "", bp->address); + LOG_DEBUG("must step over %08" TARGET_PRIxADDR, bp->address); arm11_step(target, true, 0, false); break; } @@ -802,7 +802,7 @@ static int arm11_read_memory_inner(struct target *target, return ERROR_TARGET_NOT_HALTED; } - LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32 "", + LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32, address, size, count); @@ -819,46 +819,44 @@ static int arm11_read_memory_inner(struct target *target, return retval; switch (size) { - case 1: - arm11->arm.core_cache->reg_list[1].dirty = true; - - for (size_t i = 0; i < count; i++) { - /* ldrb r1, [r0], #1 */ - /* ldrb r1, [r0] */ - CHECK_RETVAL(arm11_run_instr_no_data1(arm11, - !arm11_config_memrw_no_increment ? 0xe4d01001 : 0xe5d01000)); + case 1: + arm11->arm.core_cache->reg_list[1].dirty = true; - uint32_t res; - /* MCR p14,0,R1,c0,c5,0 */ - CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); + for (size_t i = 0; i < count; i++) { + /* ldrb r1, [r0], #1 */ + /* ldrb r1, [r0] */ + CHECK_RETVAL(arm11_run_instr_no_data1(arm11, + !arm11_config_memrw_no_increment ? 0xe4d01001 : 0xe5d01000)); - *buffer++ = res; - } + uint32_t res; + /* MCR p14,0,R1,c0,c5,0 */ + CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); - break; + *buffer++ = res; + } - case 2: - { - arm11->arm.core_cache->reg_list[1].dirty = true; + break; - for (size_t i = 0; i < count; i++) { - /* ldrh r1, [r0], #2 */ - CHECK_RETVAL(arm11_run_instr_no_data1(arm11, - !arm11_config_memrw_no_increment ? 0xe0d010b2 : 0xe1d010b0)); + case 2: + arm11->arm.core_cache->reg_list[1].dirty = true; - uint32_t res; + for (size_t i = 0; i < count; i++) { + /* ldrh r1, [r0], #2 */ + CHECK_RETVAL(arm11_run_instr_no_data1(arm11, + !arm11_config_memrw_no_increment ? 0xe0d010b2 : 0xe1d010b0)); - /* MCR p14,0,R1,c0,c5,0 */ - CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); + uint32_t res; - uint16_t svalue = res; - memcpy(buffer + i * sizeof(uint16_t), &svalue, sizeof(uint16_t)); - } + /* MCR p14,0,R1,c0,c5,0 */ + CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); - break; + uint16_t svalue = res; + memcpy(buffer + i * sizeof(uint16_t), &svalue, sizeof(uint16_t)); } - case 4: + break; + + case 4: { uint32_t instr = !arm11_config_memrw_no_increment ? 0xecb05e01 : 0xed905e00; /** \todo TODO: buffer cast to uint32_t* causes alignment warnings */ @@ -900,7 +898,7 @@ static int arm11_write_memory_inner(struct target *target, return ERROR_TARGET_NOT_HALTED; } - LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32 "", + LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32, address, size, count); @@ -927,56 +925,53 @@ static int arm11_write_memory_inner(struct target *target, bool burst = arm11->memwrite_burst && (count > 1); switch (size) { - case 1: - { - arm11->arm.core_cache->reg_list[1].dirty = true; - - for (size_t i = 0; i < count; i++) { - /* load r1 from DCC with byte data */ - /* MRC p14,0,r1,c0,c5,0 */ - retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++); - if (retval != ERROR_OK) - return retval; - - /* write r1 to memory */ - /* strb r1, [r0], #1 */ - /* strb r1, [r0] */ - retval = arm11_run_instr_no_data1(arm11, - !no_increment ? 0xe4c01001 : 0xe5c01000); - if (retval != ERROR_OK) - return retval; - } + case 1: + arm11->arm.core_cache->reg_list[1].dirty = true; - break; + for (size_t i = 0; i < count; i++) { + /* load r1 from DCC with byte data */ + /* MRC p14,0,r1,c0,c5,0 */ + retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++); + if (retval != ERROR_OK) + return retval; + + /* write r1 to memory */ + /* strb r1, [r0], #1 */ + /* strb r1, [r0] */ + retval = arm11_run_instr_no_data1(arm11, + !no_increment ? 0xe4c01001 : 0xe5c01000); + if (retval != ERROR_OK) + return retval; } - case 2: - { - arm11->arm.core_cache->reg_list[1].dirty = true; - - for (size_t i = 0; i < count; i++) { - uint16_t value; - memcpy(&value, buffer + i * sizeof(uint16_t), sizeof(uint16_t)); - - /* load r1 from DCC with halfword data */ - /* MRC p14,0,r1,c0,c5,0 */ - retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, value); - if (retval != ERROR_OK) - return retval; - - /* write r1 to memory */ - /* strh r1, [r0], #2 */ - /* strh r1, [r0] */ - retval = arm11_run_instr_no_data1(arm11, - !no_increment ? 0xe0c010b2 : 0xe1c010b0); - if (retval != ERROR_OK) - return retval; - } + break; - break; + case 2: + arm11->arm.core_cache->reg_list[1].dirty = true; + + for (size_t i = 0; i < count; i++) { + uint16_t value; + memcpy(&value, buffer + i * sizeof(uint16_t), sizeof(uint16_t)); + + /* load r1 from DCC with halfword data */ + /* MRC p14,0,r1,c0,c5,0 */ + retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, value); + if (retval != ERROR_OK) + return retval; + + /* write r1 to memory */ + /* strh r1, [r0], #2 */ + /* strh r1, [r0] */ + retval = arm11_run_instr_no_data1(arm11, + !no_increment ? 0xe0c010b2 : 0xe1c010b0); + if (retval != ERROR_OK) + return retval; } - case 4: { + break; + + case 4: + { /* stream word data through DCC directly to memory */ /* increment: STC p14,c5,[R0],#4 */ /* no increment: STC p14,c5,[R0]*/ @@ -1164,34 +1159,34 @@ static int arm11_examine(struct target *target) /* assume the manufacturer id is ok; check the part # */ switch ((device_id >> 12) & 0xFFFF) { - case 0x7B36: - type = "ARM1136"; - break; - case 0x7B37: - type = "ARM11 MPCore"; - break; - case 0x7B56: - type = "ARM1156"; - break; - case 0x7B76: - arm11->arm.core_type = ARM_CORE_TYPE_SEC_EXT; - /* NOTE: could default arm11->hardware_step to true */ - type = "ARM1176"; - break; - default: - LOG_ERROR("unexpected ARM11 ID code"); - return ERROR_FAIL; + case 0x7B36: + type = "ARM1136"; + break; + case 0x7B37: + type = "ARM11 MPCore"; + break; + case 0x7B56: + type = "ARM1156"; + break; + case 0x7B76: + arm11->arm.core_type = ARM_CORE_TYPE_SEC_EXT; + /* NOTE: could default arm11->hardware_step to true */ + type = "ARM1176"; + break; + default: + LOG_ERROR("unexpected ARM11 ID code"); + return ERROR_FAIL; } LOG_INFO("found %s", type); /* unlikely this could ever fail, but ... */ switch ((didr >> 16) & 0x0F) { - case ARM11_DEBUG_V6: - case ARM11_DEBUG_V61: /* supports security extensions */ - break; - default: - LOG_ERROR("Only ARM v6 and v6.1 debug supported."); - return ERROR_FAIL; + case ARM11_DEBUG_V6: + case ARM11_DEBUG_V61: /* supports security extensions */ + break; + default: + LOG_ERROR("Only ARM v6 and v6.1 debug supported."); + return ERROR_FAIL; } arm11->brp = ((didr >> 24) & 0x0F) + 1; @@ -1225,8 +1220,6 @@ static int arm11_examine(struct target *target) CHECK_RETVAL(etm_setup(target)); } - target_set_examined(target); - return ERROR_OK; } @@ -1255,16 +1248,16 @@ COMMAND_HANDLER(arm11_handle_vcr) struct arm11_common *arm11 = target_to_arm11(target); switch (CMD_ARGC) { - case 0: - break; - case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], arm11->vcr); - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 0: + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], arm11->vcr); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } - LOG_INFO("VCR 0x%08" PRIx32 "", arm11->vcr); + LOG_INFO("VCR 0x%08" PRIx32, arm11->vcr); return ERROR_OK; } @@ -1375,4 +1368,6 @@ struct target_type arm11_target = { .init_target = arm11_init_target, .deinit_target = arm11_deinit_target, .examine = arm11_examine, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index 4c7211365b..4c2fedaeb2 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -85,30 +85,30 @@ static const char *arm11_ir_to_string(uint8_t ir) const char *s = "unknown"; switch (ir) { - case ARM11_EXTEST: - s = "EXTEST"; - break; - case ARM11_SCAN_N: - s = "SCAN_N"; - break; - case ARM11_RESTART: - s = "RESTART"; - break; - case ARM11_HALT: - s = "HALT"; - break; - case ARM11_INTEST: - s = "INTEST"; - break; - case ARM11_ITRSEL: - s = "ITRSEL"; - break; - case ARM11_IDCODE: - s = "IDCODE"; - break; - case ARM11_BYPASS: - s = "BYPASS"; - break; + case ARM11_EXTEST: + s = "EXTEST"; + break; + case ARM11_SCAN_N: + s = "SCAN_N"; + break; + case ARM11_RESTART: + s = "RESTART"; + break; + case ARM11_HALT: + s = "HALT"; + break; + case ARM11_INTEST: + s = "INTEST"; + break; + case ARM11_ITRSEL: + s = "ITRSEL"; + break; + case ARM11_IDCODE: + s = "IDCODE"; + break; + case ARM11_BYPASS: + s = "BYPASS"; + break; } return s; } @@ -1061,17 +1061,17 @@ static int arm11_bpwp_enable(struct arm_dpm *dpm, unsigned int index_t, action[1].value = control; switch (index_t) { - case 0 ... 15: - action[0].address = ARM11_SC7_BVR0 + index_t; - action[1].address = ARM11_SC7_BCR0 + index_t; - break; - case 16 ... 32: - index_t -= 16; - action[0].address = ARM11_SC7_WVR0 + index_t; - action[1].address = ARM11_SC7_WCR0 + index_t; - break; - default: - return ERROR_FAIL; + case 0 ... 15: + action[0].address = ARM11_SC7_BVR0 + index_t; + action[1].address = ARM11_SC7_BCR0 + index_t; + break; + case 16 ... 32: + index_t -= 16; + action[0].address = ARM11_SC7_WVR0 + index_t; + action[1].address = ARM11_SC7_WCR0 + index_t; + break; + default: + return ERROR_FAIL; } arm11->bpwp_n += 2; @@ -1090,15 +1090,15 @@ static int arm11_bpwp_disable(struct arm_dpm *dpm, unsigned int index_t) action[0].value = 0; switch (index_t) { - case 0 ... 15: - action[0].address = ARM11_SC7_BCR0 + index_t; - break; - case 16 ... 32: - index_t -= 16; - action[0].address = ARM11_SC7_WCR0 + index_t; - break; - default: - return ERROR_FAIL; + case 0 ... 15: + action[0].address = ARM11_SC7_BCR0 + index_t; + break; + case 16 ... 32: + index_t -= 16; + action[0].address = ARM11_SC7_WCR0 + index_t; + break; + default: + return ERROR_FAIL; } arm11->bpwp_n += 1; diff --git a/src/target/arm720t.c b/src/target/arm720t.c index d1433dde72..c62ebb7bd0 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -14,6 +14,7 @@ #include "arm720t.h" #include +#include #include "target_type.h" #include "register.h" #include "arm_opcodes.h" @@ -156,8 +157,7 @@ static int arm720t_disable_mmu_caches(struct target *target, if (d_u_cache || i_cache) cp15_control &= ~0x4U; - retval = arm720t_write_cp15(target, 0xee010f10, cp15_control); - return retval; + return arm720t_write_cp15(target, 0xee010f10, cp15_control); } static int arm720t_enable_mmu_caches(struct target *target, @@ -180,8 +180,7 @@ static int arm720t_enable_mmu_caches(struct target *target, if (d_u_cache || i_cache) cp15_control |= 0x4U; - retval = arm720t_write_cp15(target, 0xee010f10, cp15_control); - return retval; + return arm720t_write_cp15(target, 0xee010f10, cp15_control); } static int arm720t_post_debug_entry(struct target *target) @@ -196,11 +195,12 @@ static int arm720t_post_debug_entry(struct target *target) retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - LOG_DEBUG("cp15_control_reg: %8.8" PRIx32 "", arm720t->cp15_control_reg); + LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, arm720t->cp15_control_reg); - arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0; - arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0; - arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + arm720t->armv4_5_mmu.mmu_enabled = arm720t->cp15_control_reg & 0x1U; + arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = + arm720t->cp15_control_reg & 0x4U; + arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = false; /* save i/d fault status and address register */ retval = arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr_reg); @@ -209,8 +209,7 @@ static int arm720t_post_debug_entry(struct target *target) retval = arm720t_read_cp15(target, 0xee160f10, &arm720t->far_reg); if (retval != ERROR_OK) return retval; - retval = jtag_execute_queue(); - return retval; + return jtag_execute_queue(); } static void arm720t_pre_restore_context(struct target *target) @@ -226,19 +225,15 @@ static int arm720t_arch_state(struct target *target) { struct arm720t_common *arm720t = target_to_arm720(target); - static const char *state[] = { - "disabled", "enabled" - }; - arm_arch_state(target); LOG_USER("MMU: %s, Cache: %s", - state[arm720t->armv4_5_mmu.mmu_enabled], - state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]); + str_enabled_disabled(arm720t->armv4_5_mmu.mmu_enabled), + str_enabled_disabled(arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)); return ERROR_OK; } -static int arm720_mmu(struct target *target, int *enabled) +static int arm720_mmu(struct target *target, bool *enabled) { if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "not halted"); @@ -325,7 +320,7 @@ static int arm720t_soft_reset_halt(struct target *target) return retval; } else break; - if (debug_level >= 3) + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) alive_sleep(100); else keep_alive(); @@ -354,9 +349,9 @@ static int arm720t_soft_reset_halt(struct target *target) retval = arm720t_disable_mmu_caches(target, 1, 1, 1); if (retval != ERROR_OK) return retval; - arm720t->armv4_5_mmu.mmu_enabled = 0; - arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + arm720t->armv4_5_mmu.mmu_enabled = false; + arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = false; + arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = false; retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED); if (retval != ERROR_OK) @@ -407,7 +402,7 @@ static int arm720t_init_arch_info(struct target *target, arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches; arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches; arm720t->armv4_5_mmu.has_tiny_pages = 0; - arm720t->armv4_5_mmu.mmu_enabled = 0; + arm720t->armv4_5_mmu.mmu_enabled = false; return ERROR_OK; } @@ -501,4 +496,6 @@ struct target_type arm720t_target = { .deinit_target = arm720t_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index 5550fb1e24..9e285b1b00 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -637,13 +637,13 @@ int arm7_9_execute_sys_speed(struct target *target) if ((buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1)) && (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_SYSCOMP, 1))) break; - if (debug_level >= 3) + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) alive_sleep(100); else keep_alive(); } if (timeout) { - LOG_ERROR("timeout waiting for SYSCOMP & DBGACK, last DBG_STATUS: %" PRIx32 "", + LOG_ERROR("timeout waiting for SYSCOMP & DBGACK, last DBG_STATUS: %" PRIx32, buf_get_u32(dbg_stat->value, 0, dbg_stat->size)); return ERROR_TARGET_TIMEOUT; } @@ -1088,7 +1088,7 @@ int arm7_9_soft_reset_halt(struct target *target) retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - if (debug_level >= 3) + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) alive_sleep(100); else keep_alive(); @@ -1332,7 +1332,7 @@ static int arm7_9_debug_entry(struct target *target) for (i = 0; i <= 15; i++) { struct reg *r = arm_reg_current(arm, i); - LOG_DEBUG("r%i: 0x%8.8" PRIx32 "", i, context[i]); + LOG_DEBUG("r%i: 0x%8.8" PRIx32, i, context[i]); buf_set_u32(r->value, 0, 32, context[i]); /* r0 and r15 (pc) have to be restored later */ @@ -1340,7 +1340,7 @@ static int arm7_9_debug_entry(struct target *target) r->valid = true; } - LOG_DEBUG("entered debug state at PC 0x%" PRIx32 "", context[15]); + LOG_DEBUG("entered debug state at PC 0x%" PRIx32, context[15]); /* exceptions other than USR & SYS have a saved program status register */ if (arm->spsr) { @@ -1594,7 +1594,7 @@ static int arm7_9_restore_context(struct target *target) struct arm_reg *reg_arch_info; reg_arch_info = reg->arch_info; if ((reg->dirty) && (reg_arch_info->mode != ARM_MODE_ANY)) { - LOG_DEBUG("writing SPSR of mode %i with value 0x%8.8" PRIx32 "", + LOG_DEBUG("writing SPSR of mode %i with value 0x%8.8" PRIx32, i, buf_get_u32(reg->value, 0, 32)); arm7_9->write_xpsr(target, buf_get_u32(reg->value, 0, 32), 1); @@ -1744,7 +1744,7 @@ int arm7_9_resume(struct target *target, uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( - "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", + "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32, current_opcode); return retval; } @@ -1789,7 +1789,7 @@ int arm7_9_resume(struct target *target, LOG_DEBUG("new PC after step: 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); - LOG_DEBUG("set breakpoint at 0x%8.8" TARGET_PRIxADDR "", breakpoint->address); + LOG_DEBUG("set breakpoint at 0x%8.8" TARGET_PRIxADDR, breakpoint->address); retval = arm7_9_set_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; @@ -1937,7 +1937,7 @@ int arm7_9_step(struct target *target, bool current, target_addr_t address, uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( - "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", + "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32, current_opcode); return retval; } @@ -2116,7 +2116,7 @@ int arm7_9_read_memory(struct target *target, int retval; int last_reg = 0; - LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { @@ -2135,21 +2135,49 @@ int arm7_9_read_memory(struct target *target, reg[0] = address; arm7_9->write_core_regs(target, 0x1, reg); - int j = 0; - switch (size) { - case 4: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + case 4: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + if (last_reg <= thisrun_accesses) + last_reg = thisrun_accesses; + + arm7_9->load_word_regs(target, reg_list); + + /* fast memory reads are only safe when the target is running + * from a sufficiently high clock (32 kHz is usually too slow) + */ + if (arm7_9->fast_memory_access) + retval = arm7_9_execute_fast_sys_speed(target); + else + retval = arm7_9_execute_sys_speed(target); + if (retval != ERROR_OK) + return retval; - if (last_reg <= thisrun_accesses) - last_reg = thisrun_accesses; + arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 4); - arm7_9->load_word_regs(target, reg_list); + /* advance buffer, count number of accesses */ + buffer += thisrun_accesses * 4; + num_accesses += thisrun_accesses; + keep_alive(); + } + break; + case 2: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + for (i = 1; i <= thisrun_accesses; i++) { + if (i > last_reg) + last_reg = i; + arm7_9->load_hword_reg(target, i); /* fast memory reads are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ @@ -2160,81 +2188,48 @@ int arm7_9_read_memory(struct target *target, if (retval != ERROR_OK) return retval; - arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 4); - - /* advance buffer, count number of accesses */ - buffer += thisrun_accesses * 4; - num_accesses += thisrun_accesses; - - if ((j++%1024) == 0) - keep_alive(); } - break; - case 2: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; - - for (i = 1; i <= thisrun_accesses; i++) { - if (i > last_reg) - last_reg = i; - arm7_9->load_hword_reg(target, i); - /* fast memory reads are only safe when the target is running - * from a sufficiently high clock (32 kHz is usually too slow) - */ - if (arm7_9->fast_memory_access) - retval = arm7_9_execute_fast_sys_speed(target); - else - retval = arm7_9_execute_sys_speed(target); - if (retval != ERROR_OK) - return retval; - - } - arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 2); + arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 2); - /* advance buffer, count number of accesses */ - buffer += thisrun_accesses * 2; - num_accesses += thisrun_accesses; + /* advance buffer, count number of accesses */ + buffer += thisrun_accesses * 2; + num_accesses += thisrun_accesses; - if ((j++%1024) == 0) - keep_alive(); + keep_alive(); + } + break; + case 1: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + for (i = 1; i <= thisrun_accesses; i++) { + if (i > last_reg) + last_reg = i; + arm7_9->load_byte_reg(target, i); + /* fast memory reads are only safe when the target is running + * from a sufficiently high clock (32 kHz is usually too slow) + */ + if (arm7_9->fast_memory_access) + retval = arm7_9_execute_fast_sys_speed(target); + else + retval = arm7_9_execute_sys_speed(target); + if (retval != ERROR_OK) + return retval; } - break; - case 1: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; - - for (i = 1; i <= thisrun_accesses; i++) { - if (i > last_reg) - last_reg = i; - arm7_9->load_byte_reg(target, i); - /* fast memory reads are only safe when the target is running - * from a sufficiently high clock (32 kHz is usually too slow) - */ - if (arm7_9->fast_memory_access) - retval = arm7_9_execute_fast_sys_speed(target); - else - retval = arm7_9_execute_sys_speed(target); - if (retval != ERROR_OK) - return retval; - } - arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 1); + arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 1); - /* advance buffer, count number of accesses */ - buffer += thisrun_accesses * 1; - num_accesses += thisrun_accesses; + /* advance buffer, count number of accesses */ + buffer += thisrun_accesses * 1; + num_accesses += thisrun_accesses; - if ((j++%1024) == 0) - keep_alive(); - } - break; + keep_alive(); + } + break; } if (!is_arm_mode(arm->core_mode)) @@ -2313,30 +2308,74 @@ int arm7_9_write_memory(struct target *target, embeddedice_store_reg(dbg_ctrl); switch (size) { - case 4: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; - - for (i = 1; i <= thisrun_accesses; i++) { - if (i > last_reg) - last_reg = i; - reg[i] = target_buffer_get_u32(target, buffer); - buffer += 4; - } + case 4: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + for (i = 1; i <= thisrun_accesses; i++) { + if (i > last_reg) + last_reg = i; + reg[i] = target_buffer_get_u32(target, buffer); + buffer += 4; + } + + arm7_9->write_core_regs(target, reg_list, reg); + + arm7_9->store_word_regs(target, reg_list); + + /* fast memory writes are only safe when the target is running + * from a sufficiently high clock (32 kHz is usually too slow) + */ + if (arm7_9->fast_memory_access) { + retval = arm7_9_execute_fast_sys_speed(target); + } else { + retval = arm7_9_execute_sys_speed(target); + + /* + * if memory writes are made when the clock is running slow + * (i.e. 32 kHz) which is necessary in some scripts to reconfigure + * processor operations after a "reset halt" or "reset init", + * need to immediately stroke the keep alive or will end up with + * gdb "keep alive not sent error message" problem. + */ + + keep_alive(); + } + + if (retval != ERROR_OK) + return retval; + + num_accesses += thisrun_accesses; + } + break; + case 2: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + for (i = 1; i <= thisrun_accesses; i++) { + if (i > last_reg) + last_reg = i; + reg[i] = target_buffer_get_u16(target, buffer) & 0xffff; + buffer += 2; + } - arm7_9->write_core_regs(target, reg_list, reg); + arm7_9->write_core_regs(target, reg_list, reg); - arm7_9->store_word_regs(target, reg_list); + for (i = 1; i <= thisrun_accesses; i++) { + arm7_9->store_hword_reg(target, i); /* fast memory writes are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ - if (arm7_9->fast_memory_access) + if (arm7_9->fast_memory_access) { retval = arm7_9_execute_fast_sys_speed(target); - else { + } else { retval = arm7_9_execute_sys_speed(target); /* @@ -2352,99 +2391,55 @@ int arm7_9_write_memory(struct target *target, if (retval != ERROR_OK) return retval; + } - num_accesses += thisrun_accesses; + num_accesses += thisrun_accesses; + } + break; + case 1: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + for (i = 1; i <= thisrun_accesses; i++) { + if (i > last_reg) + last_reg = i; + reg[i] = *buffer++ & 0xff; } - break; - case 2: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; - - for (i = 1; i <= thisrun_accesses; i++) { - if (i > last_reg) - last_reg = i; - reg[i] = target_buffer_get_u16(target, buffer) & 0xffff; - buffer += 2; - } - arm7_9->write_core_regs(target, reg_list, reg); + arm7_9->write_core_regs(target, reg_list, reg); - for (i = 1; i <= thisrun_accesses; i++) { - arm7_9->store_hword_reg(target, i); + for (i = 1; i <= thisrun_accesses; i++) { + arm7_9->store_byte_reg(target, i); + /* fast memory writes are only safe when the target is running + * from a sufficiently high clock (32 kHz is usually too slow) + */ + if (arm7_9->fast_memory_access) { + retval = arm7_9_execute_fast_sys_speed(target); + } else { + retval = arm7_9_execute_sys_speed(target); - /* fast memory writes are only safe when the target is running - * from a sufficiently high clock (32 kHz is usually too slow) + /* + * if memory writes are made when the clock is running slow + * (i.e. 32 kHz) which is necessary in some scripts to reconfigure + * processor operations after a "reset halt" or "reset init", + * need to immediately stroke the keep alive or will end up with + * gdb "keep alive not sent error message" problem. */ - if (arm7_9->fast_memory_access) - retval = arm7_9_execute_fast_sys_speed(target); - else { - retval = arm7_9_execute_sys_speed(target); - - /* - * if memory writes are made when the clock is running slow - * (i.e. 32 kHz) which is necessary in some scripts to reconfigure - * processor operations after a "reset halt" or "reset init", - * need to immediately stroke the keep alive or will end up with - * gdb "keep alive not sent error message" problem. - */ - - keep_alive(); - } - - if (retval != ERROR_OK) - return retval; - } - num_accesses += thisrun_accesses; - } - break; - case 1: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; - - for (i = 1; i <= thisrun_accesses; i++) { - if (i > last_reg) - last_reg = i; - reg[i] = *buffer++ & 0xff; + keep_alive(); } - arm7_9->write_core_regs(target, reg_list, reg); - - for (i = 1; i <= thisrun_accesses; i++) { - arm7_9->store_byte_reg(target, i); - /* fast memory writes are only safe when the target is running - * from a sufficiently high clock (32 kHz is usually too slow) - */ - if (arm7_9->fast_memory_access) - retval = arm7_9_execute_fast_sys_speed(target); - else { - retval = arm7_9_execute_sys_speed(target); - - /* - * if memory writes are made when the clock is running slow - * (i.e. 32 kHz) which is necessary in some scripts to reconfigure - * processor operations after a "reset halt" or "reset init", - * need to immediately stroke the keep alive or will end up with - * gdb "keep alive not sent error message" problem. - */ - - keep_alive(); - } - - if (retval != ERROR_OK) - return retval; - - } + if (retval != ERROR_OK) + return retval; - num_accesses += thisrun_accesses; } - break; + + num_accesses += thisrun_accesses; + } + break; } /* Re-Set DBGACK */ @@ -2641,7 +2636,7 @@ int arm7_9_bulk_write_memory(struct target *target, uint32_t endaddress = buf_get_u32(reg_params[0].value, 0, 32); if (endaddress != (address + count*4)) { LOG_ERROR( - "DCC write failed, expected end address 0x%08" TARGET_PRIxADDR " got 0x%0" PRIx32 "", + "DCC write failed, expected end address 0x%08" TARGET_PRIxADDR " got 0x%0" PRIx32, (address + count*4), endaddress); retval = ERROR_FAIL; @@ -2677,7 +2672,6 @@ int arm7_9_examine(struct target *target) &arm7_9->jtag_info, arm7_9->arm.etm); - target_set_examined(target); } retval = embeddedice_setup(target); diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c index 2f59254afd..e974d01e6a 100644 --- a/src/target/arm7tdmi.c +++ b/src/target/arm7tdmi.c @@ -327,15 +327,15 @@ static void arm7tdmi_read_core_regs_target_buffer(struct target *target, /* nothing fetched, STM still in EXECUTE (1 + i cycle), read databus */ if (mask & (1 << i)) { switch (size) { - case 4: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; + case 4: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; } } } @@ -719,4 +719,6 @@ struct target_type arm7tdmi_target = { .deinit_target = arm7tdmi_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/arm920t.c b/src/target/arm920t.c index 95cfd7ceb2..dad52e0d37 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -12,6 +12,7 @@ #include "arm920t.h" #include +#include #include "target_type.h" #include "register.h" #include "arm_opcodes.h" @@ -362,8 +363,7 @@ int arm920t_disable_mmu_caches(struct target *target, int mmu, if (i_cache) cp15_control &= ~0x1000U; - retval = arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_control); - return retval; + return arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_control); } /* EXPORTED to FA256 */ @@ -390,8 +390,7 @@ int arm920t_enable_mmu_caches(struct target *target, int mmu, if (i_cache) cp15_control |= 0x1000U; - retval = arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_control); - return retval; + return arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_control); } /* EXPORTED to FA256 */ @@ -425,12 +424,11 @@ int arm920t_post_debug_entry(struct target *target) &arm920t->armv4_5_mmu.armv4_5_cache); } - arm920t->armv4_5_mmu.mmu_enabled = - (arm920t->cp15_control_reg & 0x1U) ? 1 : 0; + arm920t->armv4_5_mmu.mmu_enabled = arm920t->cp15_control_reg & 0x1U; arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = - (arm920t->cp15_control_reg & 0x4U) ? 1 : 0; + arm920t->cp15_control_reg & 0x4U; arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = - (arm920t->cp15_control_reg & 0x1000U) ? 1 : 0; + arm920t->cp15_control_reg & 0x1000U; /* save i/d fault status and address register * FIXME use opcode macros */ @@ -510,10 +508,6 @@ static int arm920t_verify_pointer(struct command_invocation *cmd, /** Logs summary of ARM920 state for a halted target. */ int arm920t_arch_state(struct target *target) { - static const char *state[] = { - "disabled", "enabled" - }; - struct arm920t_common *arm920t = target_to_arm920(target); if (arm920t->common_magic != ARM920T_COMMON_MAGIC) { @@ -523,14 +517,14 @@ int arm920t_arch_state(struct target *target) arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", - state[arm920t->armv4_5_mmu.mmu_enabled], - state[arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], - state[arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); + str_enabled_disabled(arm920t->armv4_5_mmu.mmu_enabled), + str_enabled_disabled(arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled), + str_enabled_disabled(arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled)); return ERROR_OK; } -static int arm920_mmu(struct target *target, int *enabled) +static int arm920_mmu(struct target *target, bool *enabled) { if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "not halted"); @@ -560,11 +554,7 @@ static int arm920_virt2phys(struct target *target, int arm920t_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - int retval; - - retval = arm7_9_read_memory(target, address, size, count, buffer); - - return retval; + return arm7_9_read_memory(target, address, size, count, buffer); } @@ -750,7 +740,7 @@ int arm920t_soft_reset_halt(struct target *target) return retval; } else break; - if (debug_level >= 3) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { /* do not eat all CPU, time out after 1 se*/ alive_sleep(100); } else @@ -778,9 +768,9 @@ int arm920t_soft_reset_halt(struct target *target) arm->pc->valid = true; arm920t_disable_mmu_caches(target, 1, 1, 1); - arm920t->armv4_5_mmu.mmu_enabled = 0; - arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + arm920t->armv4_5_mmu.mmu_enabled = false; + arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = false; + arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = false; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } @@ -819,7 +809,7 @@ static int arm920t_init_arch_info(struct target *target, arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches; arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches; arm920t->armv4_5_mmu.has_tiny_pages = 1; - arm920t->armv4_5_mmu.mmu_enabled = 0; + arm920t->armv4_5_mmu.mmu_enabled = false; /* disabling linefills leads to lockups, so keep them enabled for now * this doesn't affect correctness, but might affect timing issues, if @@ -1635,4 +1625,6 @@ struct target_type arm920t_target = { .deinit_target = arm920t_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index 0531106562..790d84c4e3 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -14,6 +14,7 @@ #include "arm926ejs.h" #include +#include #include "target_type.h" #include "register.h" #include "arm_opcodes.h" @@ -220,88 +221,88 @@ static int arm926ejs_examine_debug_reason(struct target *target) debug_reason = buf_get_u32(dbg_stat->value, 6, 4); switch (debug_reason) { - case 0: - LOG_DEBUG("no *NEW* debug entry (?missed one?)"); - /* ... since last restart or debug reset ... */ - target->debug_reason = DBG_REASON_DBGRQ; - break; - case 1: - LOG_DEBUG("breakpoint from EICE unit 0"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 2: - LOG_DEBUG("breakpoint from EICE unit 1"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 3: - LOG_DEBUG("soft breakpoint (BKPT instruction)"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 4: - LOG_DEBUG("vector catch breakpoint"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 5: - LOG_DEBUG("external breakpoint"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 6: - LOG_DEBUG("watchpoint from EICE unit 0"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 7: - LOG_DEBUG("watchpoint from EICE unit 1"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 8: - LOG_DEBUG("external watchpoint"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 9: - LOG_DEBUG("internal debug request"); - target->debug_reason = DBG_REASON_DBGRQ; - break; - case 10: - LOG_DEBUG("external debug request"); - target->debug_reason = DBG_REASON_DBGRQ; - break; - case 11: - LOG_DEBUG("debug re-entry from system speed access"); - /* This is normal when connecting to something that's - * already halted, or in some related code paths, but - * otherwise is surprising (and presumably wrong). - */ - switch (target->debug_reason) { - case DBG_REASON_DBGRQ: - break; - default: - LOG_ERROR("unexpected -- debug re-entry"); - /* FALLTHROUGH */ - case DBG_REASON_UNDEFINED: - target->debug_reason = DBG_REASON_DBGRQ; - break; - } - break; - case 12: - /* FIX!!!! here be dragons!!! We need to fail here so - * the target will interpreted as halted but we won't - * try to talk to it right now... a resume + halt seems - * to sync things up again. Please send an email to - * openocd development mailing list if you have hardware - * to donate to look into this problem.... - */ - LOG_WARNING("WARNING: mystery debug reason MOE = 0xc. Try issuing a resume + halt."); - target->debug_reason = DBG_REASON_DBGRQ; + case 0: + LOG_DEBUG("no *NEW* debug entry (?missed one?)"); + /* ... since last restart or debug reset ... */ + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 1: + LOG_DEBUG("breakpoint from EICE unit 0"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 2: + LOG_DEBUG("breakpoint from EICE unit 1"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 3: + LOG_DEBUG("soft breakpoint (BKPT instruction)"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 4: + LOG_DEBUG("vector catch breakpoint"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 5: + LOG_DEBUG("external breakpoint"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 6: + LOG_DEBUG("watchpoint from EICE unit 0"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 7: + LOG_DEBUG("watchpoint from EICE unit 1"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 8: + LOG_DEBUG("external watchpoint"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 9: + LOG_DEBUG("internal debug request"); + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 10: + LOG_DEBUG("external debug request"); + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 11: + LOG_DEBUG("debug re-entry from system speed access"); + /* This is normal when connecting to something that's + * already halted, or in some related code paths, but + * otherwise is surprising (and presumably wrong). + */ + switch (target->debug_reason) { + case DBG_REASON_DBGRQ: break; default: - LOG_WARNING("WARNING: unknown debug reason: 0x%x", debug_reason); - /* Oh agony! should we interpret this as a halt request or - * that the target stopped on it's own accord? - */ + LOG_ERROR("unexpected -- debug re-entry"); + /* FALLTHROUGH */ + case DBG_REASON_UNDEFINED: target->debug_reason = DBG_REASON_DBGRQ; - /* if we fail here, we won't talk to the target and it will - * be reported to be in the halted state */ break; + } + break; + case 12: + /* FIX!!!! here be dragons!!! We need to fail here so + * the target will interpreted as halted but we won't + * try to talk to it right now... a resume + halt seems + * to sync things up again. Please send an email to + * openocd development mailing list if you have hardware + * to donate to look into this problem.... + */ + LOG_WARNING("WARNING: mystery debug reason MOE = 0xc. Try issuing a resume + halt."); + target->debug_reason = DBG_REASON_DBGRQ; + break; + default: + LOG_WARNING("WARNING: unknown debug reason: 0x%x", debug_reason); + /* Oh agony! should we interpret this as a halt request or + * that the target stopped on it's own accord? + */ + target->debug_reason = DBG_REASON_DBGRQ; + /* if we fail here, we won't talk to the target and it will + * be reported to be in the halted state */ + break; } return ERROR_OK; @@ -382,8 +383,7 @@ static int arm926ejs_disable_mmu_caches(struct target *target, int mmu, cp15_control &= ~0x1000U; } - retval = arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); - return retval; + return arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); } static int arm926ejs_enable_mmu_caches(struct target *target, int mmu, @@ -410,8 +410,7 @@ static int arm926ejs_enable_mmu_caches(struct target *target, int mmu, if (i_cache) cp15_control |= 0x1000U; - retval = arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); - return retval; + return arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); } static int arm926ejs_post_debug_entry(struct target *target) @@ -426,7 +425,7 @@ static int arm926ejs_post_debug_entry(struct target *target) retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - LOG_DEBUG("cp15_control_reg: %8.8" PRIx32 "", arm926ejs->cp15_control_reg); + LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, arm926ejs->cp15_control_reg); if (arm926ejs->armv4_5_mmu.armv4_5_cache.ctype == -1) { uint32_t cache_type_reg; @@ -440,9 +439,11 @@ static int arm926ejs_post_debug_entry(struct target *target) armv4_5_identify_cache(cache_type_reg, &arm926ejs->armv4_5_mmu.armv4_5_cache); } - arm926ejs->armv4_5_mmu.mmu_enabled = (arm926ejs->cp15_control_reg & 0x1U) ? 1 : 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm926ejs->cp15_control_reg & 0x4U) ? 1 : 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm926ejs->cp15_control_reg & 0x1000U) ? 1 : 0; + arm926ejs->armv4_5_mmu.mmu_enabled = arm926ejs->cp15_control_reg & 0x1U; + arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = + arm926ejs->cp15_control_reg & 0x4U; + arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = + arm926ejs->cp15_control_reg & 0x1000U; /* save i/d fault status and address register */ retval = arm926ejs->read_cp15(target, 0, 0, 5, 0, &arm926ejs->d_fsr); @@ -455,7 +456,7 @@ static int arm926ejs_post_debug_entry(struct target *target) if (retval != ERROR_OK) return retval; - LOG_DEBUG("D FSR: 0x%8.8" PRIx32 ", D FAR: 0x%8.8" PRIx32 ", I FSR: 0x%8.8" PRIx32 "", + LOG_DEBUG("D FSR: 0x%8.8" PRIx32 ", D FAR: 0x%8.8" PRIx32 ", I FSR: 0x%8.8" PRIx32, arm926ejs->d_fsr, arm926ejs->d_far, arm926ejs->i_fsr); uint32_t cache_dbg_ctrl; @@ -466,8 +467,7 @@ static int arm926ejs_post_debug_entry(struct target *target) if (retval != ERROR_OK) return retval; cache_dbg_ctrl |= 0x7; - retval = arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); - return retval; + return arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); } static void arm926ejs_pre_restore_context(struct target *target) @@ -503,10 +503,6 @@ static int arm926ejs_verify_pointer(struct command_invocation *cmd, /** Logs summary of ARM926 state for a halted target. */ int arm926ejs_arch_state(struct target *target) { - static const char *state[] = { - "disabled", "enabled" - }; - struct arm926ejs_common *arm926ejs = target_to_arm926(target); if (arm926ejs->common_magic != ARM926EJS_COMMON_MAGIC) { @@ -516,9 +512,9 @@ int arm926ejs_arch_state(struct target *target) arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", - state[arm926ejs->armv4_5_mmu.mmu_enabled], - state[arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], - state[arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); + str_enabled_disabled(arm926ejs->armv4_5_mmu.mmu_enabled), + str_enabled_disabled(arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled), + str_enabled_disabled(arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled)); return ERROR_OK; } @@ -545,7 +541,7 @@ int arm926ejs_soft_reset_halt(struct target *target) return retval; } else break; - if (debug_level >= 1) { + if (LOG_LEVEL_IS(LOG_LVL_WARNING)) { /* do not eat all CPU, time out after 1 se*/ alive_sleep(100); } else @@ -575,9 +571,9 @@ int arm926ejs_soft_reset_halt(struct target *target) retval = arm926ejs_disable_mmu_caches(target, 1, 1, 1); if (retval != ERROR_OK) return retval; - arm926ejs->armv4_5_mmu.mmu_enabled = 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + arm926ejs->armv4_5_mmu.mmu_enabled = false; + arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = false; + arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = false; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } @@ -689,7 +685,7 @@ int arm926ejs_init_arch_info(struct target *target, struct arm926ejs_common *arm arm926ejs->armv4_5_mmu.disable_mmu_caches = arm926ejs_disable_mmu_caches; arm926ejs->armv4_5_mmu.enable_mmu_caches = arm926ejs_enable_mmu_caches; arm926ejs->armv4_5_mmu.has_tiny_pages = 1; - arm926ejs->armv4_5_mmu.mmu_enabled = 0; + arm926ejs->armv4_5_mmu.mmu_enabled = false; arm7_9->examine_debug_reason = arm926ejs_examine_debug_reason; @@ -749,7 +745,7 @@ static int arm926ejs_virt2phys(struct target *target, target_addr_t virtual, tar return ERROR_OK; } -static int arm926ejs_mmu(struct target *target, int *enabled) +static int arm926ejs_mmu(struct target *target, bool *enabled) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); @@ -830,4 +826,6 @@ struct target_type arm926ejs_target = { .read_phys_memory = arm926ejs_read_phys_memory, .write_phys_memory = arm926ejs_write_phys_memory, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/arm946e.c b/src/target/arm946e.c index 828e70f4bc..ab0ac44e10 100644 --- a/src/target/arm946e.c +++ b/src/target/arm946e.c @@ -778,4 +778,6 @@ struct target_type arm946e_target = { .deinit_target = arm946e_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/arm966e.c b/src/target/arm966e.c index b6bcc8ba97..1203b76880 100644 --- a/src/target/arm966e.c +++ b/src/target/arm966e.c @@ -280,4 +280,6 @@ struct target_type arm966e_target = { .deinit_target = arm966e_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index 8ab12de320..f980d91ca3 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -398,15 +398,15 @@ static void arm9tdmi_read_core_regs_target_buffer(struct target *target, if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ switch (size) { - case 4: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; + case 4: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; } } } @@ -923,4 +923,6 @@ struct target_type arm9tdmi_target = { .deinit_target = arm9tdmi_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index df897b80ed..e64f8ac374 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -50,8 +50,16 @@ /* * Relevant specifications from ARM include: * - * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031F + * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031G + * https://developer.arm.com/documentation/ihi0031/latest/ + * * ARM(tm) Debug Interface v6 Architecture Specification ARM IHI 0074C + * https://developer.arm.com/documentation/ihi0074/latest/ + * + * Note that diagrams B4-1 to B4-7 in both ADI specifications show + * SWCLK signal mostly in wrong polarity. See detailed SWD timing + * https://developer.arm.com/documentation/dui0499/b/arm-dstream-target-interface-connections/swd-timing-requirements + * * CoreSight(tm) v1.0 Architecture Specification ARM IHI 0029B * * CoreSight(tm) DAP-Lite TRM, ARM DDI 0316D @@ -1104,7 +1112,9 @@ bool is_ap_num_valid(struct adiv5_dap *dap, uint64_t ap_num) * 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_get_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_ap **ap_out) +int dap_find_by_types_get_ap(struct adiv5_dap *dap, + const enum ap_type *types_to_find, unsigned int num_types, + struct adiv5_ap **ap_out) { if (is_adiv6(dap)) { /* TODO: scan the ROM table and detect the AP available */ @@ -1112,6 +1122,8 @@ int dap_find_get_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adi return ERROR_FAIL; } + assert(num_types > 0); + /* Maximum AP number is 255 since the SELECT register is 8 bits */ for (unsigned int ap_num = 0; ap_num <= DP_APSEL_MAX; ap_num++) { struct adiv5_ap *ap = dap_get_ap(dap, ap_num); @@ -1132,18 +1144,39 @@ int dap_find_get_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adi /* 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 && (id_val & AP_TYPE_MASK) == type_to_find) { - LOG_DEBUG("Found %s at AP index: %d (IDR=0x%08" PRIX32 ")", - ap_type_to_description(type_to_find), + if (retval == ERROR_OK) { + for (unsigned int i = 0; i < num_types; i++) { + if ((id_val & AP_TYPE_MASK) == types_to_find[i]) { + LOG_DEBUG("Found %s at AP index: %d (IDR=0x%08" PRIX32 ")", + ap_type_to_description(types_to_find[i]), ap_num, id_val); - *ap_out = ap; - return ERROR_OK; + *ap_out = ap; + return ERROR_OK; + } + } } dap_put_ap(ap); } - LOG_DEBUG("No %s found", ap_type_to_description(type_to_find)); + char *types_str = NULL; + for (unsigned int i = 0; i < num_types; i++) { + if (!types_str) { + types_str = strdup(ap_type_to_description(types_to_find[i])); + } else { + char *next_str = alloc_printf("%s, %s", types_str, + ap_type_to_description(types_to_find[i])); + free(types_str); + types_str = next_str; + } + if (!types_str) { + LOG_ERROR("No memory"); + return ERROR_FAIL; + } + } + LOG_DEBUG("No %s found", types_str); + free(types_str); + return ERROR_FAIL; } diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index ebd2752bd8..b7472510b6 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -738,10 +738,21 @@ int adiv6_dap_read_baseptr(struct command_invocation *cmd, struct adiv5_dap *dap /* 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 any type from array. + * Increment AP refcount */ +int dap_find_by_types_get_ap(struct adiv5_dap *dap, + const enum ap_type *types_to_find, + unsigned int num_types, + struct adiv5_ap **ap_out); + /* Probe Access Ports to find a particular type. Increment AP refcount */ -int dap_find_get_ap(struct adiv5_dap *dap, +static inline int dap_find_get_ap(struct adiv5_dap *dap, enum ap_type type_to_find, - struct adiv5_ap **ap_out); + struct adiv5_ap **ap_out) +{ + const enum ap_type types[1] = { type_to_find }; + return dap_find_by_types_get_ap(dap, types, 1, ap_out); +} /* Return AP with specified ap_num. Increment AP refcount */ struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num); diff --git a/src/target/arm_coresight.h b/src/target/arm_coresight.h index 58139dcdbe..656f1b71e7 100644 --- a/src/target/arm_coresight.h +++ b/src/target/arm_coresight.h @@ -25,6 +25,15 @@ #define ARM_CS_PIDR6 (0xFD8) #define ARM_CS_PIDR7 (0xFDC) +/* lock/unlock registers on most(?) CS devices */ +#define ARM_CS_LAR (0xFB0) +#define ARM_CS_LSR (0xFB4) +#define ARM_CS_LSR_SLI BIT(0) +#define ARM_CS_LSR_SLK BIT(1) +#define ARM_CS_AUTHSTATUS (0xFB8) + +#define ARM_CS_LAR_UNLOCK_KEY (0xC5ACCE55) + /* * When PIDR bit JEDEC is zero, only the lowers 7 bits of DESIGNER are valid * and represent a legacy ASCII Identity Code. diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index b2f78eef78..221d0df3fb 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -11,6 +11,7 @@ #include #include +#include "target/arm_coresight.h" #include "target/arm_adi_v5.h" #include "target/arm_cti.h" #include "target/target.h" @@ -52,11 +53,23 @@ struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) return NULL; } +static void arm_cti_unlock(struct arm_cti *self) +{ + /* while the LAR /shouldn't/ affect "accesses that use the external + * debugger interface" according to ARM's docs, it certainly does so, + * at least on NXP's LX2160A + */ + mem_ap_write_atomic_u32(self->ap, self->spot.base + ARM_CS_LAR, + ARM_CS_LAR_UNLOCK_KEY); +} + 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; + arm_cti_unlock(self); + /* Read register */ int retval = mem_ap_read_atomic_u32(ap, self->spot.base + reg, &tmp); if (retval != ERROR_OK) @@ -75,6 +88,8 @@ int arm_cti_enable(struct arm_cti *self, bool enable) { uint32_t val = enable ? 1 : 0; + arm_cti_unlock(self); + return mem_ap_write_atomic_u32(self->ap, self->spot.base + CTI_CTR, val); } @@ -84,6 +99,8 @@ int arm_cti_ack_events(struct arm_cti *self, uint32_t event) int retval; uint32_t tmp; + arm_cti_unlock(self); + retval = mem_ap_write_atomic_u32(ap, self->spot.base + CTI_INACK, event); if (retval == ERROR_OK) { int64_t then = timeval_ms(); @@ -122,6 +139,8 @@ 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) { + arm_cti_unlock(self); + return mem_ap_write_atomic_u32(self->ap, self->spot.base + reg, value); } @@ -190,6 +209,9 @@ static const struct { { CTI_APPPULSE, "APPPULSE" }, { CTI_INACK, "INACK" }, { CTI_DEVCTL, "DEVCTL" }, + { ARM_CS_LAR, "LAR" }, + { ARM_CS_LSR, "LSR" }, + { ARM_CS_AUTHSTATUS, "AUTHSTATUS" }, }; static int cti_find_reg_offset(const char *name) @@ -232,13 +254,13 @@ COMMAND_HANDLER(handle_cti_dump) retval = dap_run(ap->dap); if (retval != ERROR_OK) - return JIM_ERR; + return retval; for (size_t i = 0; i < ARRAY_SIZE(cti_names); i++) command_print(CMD, "%8.8s (0x%04"PRIx32") 0x%08"PRIx32, cti_names[i].label, cti_names[i].offset, values[i]); - return JIM_OK; + return ERROR_OK; } COMMAND_HANDLER(handle_cti_enable) @@ -434,49 +456,47 @@ static int cti_configure(struct jim_getopt_info *goi, struct arm_cti *cti) return JIM_OK; } -static int cti_create(struct jim_getopt_info *goi) +COMMAND_HANDLER(handle_cti_create) { - struct command_context *cmd_ctx; - 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); - - if (goi->argc < 3) { - Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); - return JIM_ERR; - } - /* COMMAND */ - jim_getopt_obj(goi, &new_cmd); - /* does this command exist? */ - 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); - return JIM_ERR; + if (CMD_ARGC < 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* check if the cti name clashes with an existing command name */ + Jim_Cmd *jimcmd = Jim_GetCommand(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], JIM_NONE); + if (jimcmd) { + command_print(CMD, "Command/cti: %s Exists", CMD_ARGV[0]); + return ERROR_FAIL; } /* Create it */ - cti = calloc(1, sizeof(*cti)); - if (!cti) - return JIM_ERR; + struct arm_cti *cti = calloc(1, sizeof(*cti)); + if (!cti) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } adiv5_mem_ap_spot_init(&cti->spot); /* Do the rest as "configure" options */ - goi->is_configure = true; - e = cti_configure(goi, cti); + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - 1, CMD_JIMTCL_ARGV + 1); + goi.is_configure = 1; + int e = cti_configure(&goi, cti); if (e != JIM_OK) { + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); free(cti); - return e; + return ERROR_COMMAND_ARGUMENT_INVALID; } - cp = Jim_GetString(new_cmd, NULL); - cti->name = strdup(cp); + cti->name = strdup(CMD_ARGV[0]); + if (!cti->name) { + LOG_ERROR("Out of memory"); + free(cti); + return ERROR_FAIL; + } /* now - create the new cti name command */ const struct command_registration cti_subcommands[] = { @@ -487,7 +507,7 @@ static int cti_create(struct jim_getopt_info *goi) }; const struct command_registration cti_commands[] = { { - .name = cp, + .name = CMD_ARGV[0], .mode = COMMAND_ANY, .help = "cti instance command group", .usage = "", @@ -495,31 +515,24 @@ static int cti_create(struct jim_getopt_info *goi) }, COMMAND_REGISTRATION_DONE }; - e = register_commands_with_data(cmd_ctx, NULL, cti_commands, cti); - if (e != ERROR_OK) - return JIM_ERR; + int retval = register_commands_with_data(CMD_CTX, NULL, cti_commands, cti); + if (retval != ERROR_OK) { + free(cti->name); + free(cti); + return retval; + } list_add_tail(&cti->lh, &all_cti); cti->ap = dap_get_ap(cti->spot.dap, cti->spot.ap_num); if (!cti->ap) { - Jim_SetResultString(goi->interp, "Cannot get AP", -1); - return JIM_ERR; + command_print(CMD, "Cannot get AP"); + free(cti->name); + free(cti); + return ERROR_FAIL; } - return JIM_OK; -} - -static int jim_cti_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 < 2) { - Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, - " [ ...]"); - return JIM_ERR; - } - return cti_create(&goi); + return ERROR_OK; } COMMAND_HANDLER(cti_handle_names) @@ -539,7 +552,7 @@ static const struct command_registration cti_subcommand_handlers[] = { { .name = "create", .mode = COMMAND_ANY, - .jim_handler = jim_cti_create, + .handler = handle_cti_create, .usage = "name '-chain-position' name [options ...]", .help = "Creates a new CTI object", }, diff --git a/src/target/arm_cti.h b/src/target/arm_cti.h index 1513f0254a..8046ead2c6 100644 --- a/src/target/arm_cti.h +++ b/src/target/arm_cti.h @@ -40,7 +40,6 @@ #define CTI_CHOU_STATUS 0x13C #define CTI_GATE 0x140 #define CTI_DEVCTL 0x150 -#define CTI_UNLOCK 0xFB0 #define CTI_CHNL(x) (1 << x) #define CTI_TRIG_HALT 0 diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index c5bd6ccd4d..07b695623c 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -16,12 +16,11 @@ #include "helper/list.h" #include "helper/command.h" #include "transport/transport.h" +#include "jtag/adapter.h" #include "jtag/interface.h" static OOCD_LIST_HEAD(all_dap); -extern struct adapter_driver *adapter_driver; - /* DAP command support */ struct arm_dap_object { struct list_head lh; @@ -333,61 +332,59 @@ static int dap_check_config(struct adiv5_dap *dap) return ERROR_OK; } -static int dap_create(struct jim_getopt_info *goi) +COMMAND_HANDLER(handle_dap_create) { - struct command_context *cmd_ctx; - static struct arm_dap_object *dap; - Jim_Obj *new_cmd; - Jim_Cmd *cmd; - const char *cp; - int e; + if (CMD_ARGC < 3) + return ERROR_COMMAND_SYNTAX_ERROR; - cmd_ctx = current_command_context(goi->interp); - assert(cmd_ctx); + int retval = ERROR_COMMAND_ARGUMENT_INVALID; - if (goi->argc < 3) { - Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); - return JIM_ERR; - } - /* COMMAND */ - jim_getopt_obj(goi, &new_cmd); - /* does this command exist? */ - 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); - return JIM_ERR; + /* check if the dap name clashes with an existing command name */ + Jim_Cmd *jimcmd = Jim_GetCommand(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], JIM_NONE); + if (jimcmd) { + command_print(CMD, "Command/dap: %s Exists", CMD_ARGV[0]); + return ERROR_FAIL; } /* Create it */ - dap = calloc(1, sizeof(struct arm_dap_object)); - if (!dap) - return JIM_ERR; + struct arm_dap_object *dap = calloc(1, sizeof(struct arm_dap_object)); + if (!dap) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } dap_instance_init(&dap->dap); - cp = Jim_GetString(new_cmd, NULL); - dap->name = strdup(cp); + dap->name = strdup(CMD_ARGV[0]); + if (!dap->name) { + LOG_ERROR("Out of memory"); + free(dap); + return ERROR_FAIL; + } - e = dap_configure(goi, dap); - if (e != JIM_OK) + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - 1, CMD_JIMTCL_ARGV + 1); + int e = dap_configure(&goi, dap); + if (e != JIM_OK) { + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); goto err; + } if (!dap->dap.tap) { - Jim_SetResultString(goi->interp, "-chain-position required when creating DAP", -1); - e = JIM_ERR; + command_print(CMD, "-chain-position required when creating DAP"); goto err; } - e = dap_check_config(&dap->dap); - if (e != ERROR_OK) { - e = JIM_ERR; + retval = dap_check_config(&dap->dap); + if (retval != ERROR_OK) goto err; - } struct command_registration dap_create_commands[] = { { - .name = cp, + .name = CMD_ARGV[0], .mode = COMMAND_ANY, .help = "dap instance command group", .usage = "", @@ -400,32 +397,28 @@ static int dap_create(struct jim_getopt_info *goi) if (transport_is_hla()) dap_create_commands[0].chain = NULL; - e = register_commands_with_data(cmd_ctx, NULL, dap_create_commands, dap); - if (e != ERROR_OK) { - e = JIM_ERR; + retval = register_commands_with_data(CMD_CTX, NULL, dap_create_commands, dap); + if (retval != ERROR_OK) goto err; - } list_add_tail(&dap->lh, &all_dap); - return JIM_OK; + return ERROR_OK; err: free(dap->name); free(dap); - return e; + return retval; } -static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +static struct adiv5_dap *target_to_dap(const struct target *target) { - 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, - " [ ...]"); - return JIM_ERR; - } - return dap_create(&goi); + struct adiv5_private_config *pc = target->private_config; + + if (!target->has_dap || !target->dap_configured || !pc) + return NULL; + + return pc->dap; } COMMAND_HANDLER(handle_dap_names) @@ -448,38 +441,37 @@ COMMAND_HANDLER(handle_dap_init) 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; + struct adiv5_dap *dap = target_to_dap(target); uint64_t apsel; if (!dap) { - LOG_ERROR("DAP instance not available. Probably a HLA target..."); + command_print(CMD, "target %s has no DAP", target_name(target)); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } switch (CMD_ARGC) { - case 0: - apsel = dap->apsel; - break; - case 1: - 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; + case 0: + apsel = dap->apsel; + break; + case 1: + 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; } - COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); - if (!is_ap_num_valid(dap, apsel)) - return ERROR_COMMAND_SYNTAX_ERROR; break; - default: + } + 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; } struct adiv5_ap *ap = dap_get_ap(dap, apsel); @@ -496,7 +488,7 @@ static const struct command_registration dap_subcommand_handlers[] = { { .name = "create", .mode = COMMAND_ANY, - .jim_handler = jim_dap_create, + .handler = handle_dap_create, .usage = "name '-chain-position' name", .help = "Creates a new DAP instance", }, diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 8619f8f82e..0a89db6d73 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -15,10 +15,6 @@ #include "arm_disassembler.h" #include -#if HAVE_CAPSTONE -#include -#endif - /* * This disassembler supports two main functions for OpenOCD: * @@ -248,39 +244,39 @@ static int evaluate_srs(uint32_t opcode, const char *mode = ""; switch ((opcode >> 23) & 0x3) { - case 0: - mode = "DA"; - break; - case 1: - /* "IA" is default */ - break; - case 2: - mode = "DB"; - break; - case 3: - mode = "IB"; - break; + case 0: + mode = "DA"; + break; + case 1: + /* "IA" is default */ + break; + case 2: + mode = "DB"; + break; + case 3: + mode = "IB"; + break; } switch (opcode & 0x0e500000) { - case 0x08400000: - snprintf(instruction->text, 128, "0x%8.8" PRIx32 - "\t0x%8.8" PRIx32 - "\tSRS%s\tSP%s, #%" PRIu32, - address, opcode, - mode, wback, - opcode & 0x1f); - break; - case 0x08100000: - snprintf(instruction->text, 128, "0x%8.8" PRIx32 - "\t0x%8.8" PRIx32 - "\tRFE%s\tr%" PRIu32 "%s", - address, opcode, - mode, - (opcode >> 16) & 0xf, wback); - break; - default: - return evaluate_unknown(opcode, address, instruction); + case 0x08400000: + snprintf(instruction->text, 128, "0x%8.8" PRIx32 + "\t0x%8.8" PRIx32 + "\tSRS%s\tSP%s, #%" PRIu32, + address, opcode, + mode, wback, + opcode & 0x1f); + break; + case 0x08100000: + snprintf(instruction->text, 128, "0x%8.8" PRIx32 + "\t0x%8.8" PRIx32 + "\tRFE%s\tr%" PRIu32 "%s", + address, opcode, + mode, + (opcode >> 16) & 0xf, wback); + break; + default: + return evaluate_unknown(opcode, address, instruction); } return ERROR_OK; } @@ -324,7 +320,7 @@ static int evaluate_blx_imm(uint32_t opcode, snprintf(instruction->text, 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX 0x%8.8" PRIx32 "", + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX 0x%8.8" PRIx32, address, opcode, target_address); @@ -596,7 +592,7 @@ static int evaluate_load_store(uint32_t opcode, if (!i) { /* #+- */ 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", ""); @@ -631,21 +627,21 @@ static int evaluate_load_store(uint32_t opcode, snprintf(offset, 32, ", %sr%i", (u) ? "" : "-", rm); else { /* +-, , # */ switch (shift) { - case 0x0: /* LSL */ - 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); - break; - case 0x2: /* ASR */ - 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); - break; - case 0x4: /* RRX */ - snprintf(offset, 32, ", %sr%i, RRX", (u) ? "" : "-", rm); - break; + case 0x0: /* LSL */ + 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); + break; + case 0x2: /* ASR */ + 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); + break; + case 0x4: /* RRX */ + snprintf(offset, 32, ", %sr%i, RRX", (u) ? "" : "-", rm); + break; } } } @@ -707,33 +703,33 @@ static int evaluate_extend(uint32_t opcode, uint32_t address, char *cp) char *type, *rot; switch ((opcode >> 24) & 0x3) { - case 0: - type = "B16"; - break; - case 1: - sprintf(cp, "UNDEFINED"); - return ARM_UNDEFINED_INSTRUCTION; - case 2: - type = "B"; - break; - default: - type = "H"; - break; + case 0: + type = "B16"; + break; + case 1: + sprintf(cp, "UNDEFINED"); + return ARM_UNDEFINED_INSTRUCTION; + case 2: + type = "B"; + break; + default: + type = "H"; + break; } switch ((opcode >> 10) & 0x3) { - case 0: - rot = ""; - break; - case 1: - rot = ", ROR #8"; - break; - case 2: - rot = ", ROR #16"; - break; - default: - rot = ", ROR #24"; - break; + case 0: + rot = ""; + break; + case 1: + rot = ", ROR #8"; + break; + case 2: + rot = ", ROR #16"; + break; + default: + rot = ", ROR #24"; + break; } if (rn == 0xf) { @@ -758,55 +754,55 @@ static int evaluate_p_add_sub(uint32_t opcode, uint32_t address, char *cp) int type; switch ((opcode >> 20) & 0x7) { - case 1: - prefix = "S"; - break; - case 2: - prefix = "Q"; - break; - case 3: - prefix = "SH"; - break; - case 5: - prefix = "U"; - break; - case 6: - prefix = "UQ"; - break; - case 7: - prefix = "UH"; - break; - default: - goto undef; + case 1: + prefix = "S"; + break; + case 2: + prefix = "Q"; + break; + case 3: + prefix = "SH"; + break; + case 5: + prefix = "U"; + break; + case 6: + prefix = "UQ"; + break; + case 7: + prefix = "UH"; + break; + default: + goto undef; } switch ((opcode >> 5) & 0x7) { - case 0: - op = "ADD16"; - type = ARM_ADD; - break; - case 1: - op = "ADDSUBX"; - type = ARM_ADD; - break; - case 2: - op = "SUBADDX"; - type = ARM_SUB; - break; - case 3: - op = "SUB16"; - type = ARM_SUB; - break; - case 4: - op = "ADD8"; - type = ARM_ADD; - break; - case 7: - op = "SUB8"; - type = ARM_SUB; - break; - default: - goto undef; + case 0: + op = "ADD16"; + type = ARM_ADD; + break; + case 1: + op = "ADDSUBX"; + type = ARM_ADD; + break; + case 2: + op = "SUBADDX"; + type = ARM_SUB; + break; + case 3: + op = "SUB16"; + type = ARM_SUB; + break; + case 4: + op = "ADD8"; + type = ARM_ADD; + break; + case 7: + op = "SUB8"; + type = ARM_SUB; + break; + default: + goto undef; } sprintf(cp, "%s%s%s\tr%d, r%d, r%d", prefix, op, COND(opcode), @@ -928,14 +924,14 @@ static int evaluate_media(uint32_t opcode, uint32_t address, unsigned int rn = (opcode >> 12) & 0xf; switch (opcode & 0xc0) { - case 3: - if (rn == 0xf) - goto undef; - /* FALL THROUGH */ - case 0: - break; - default: + case 3: + if (rn == 0xf) goto undef; + /* FALL THROUGH */ + case 0: + break; + default: + goto undef; } if (rn != 0xf) @@ -959,46 +955,46 @@ static int evaluate_media(uint32_t opcode, uint32_t address, /* simple matches against the remaining decode bits */ switch (opcode & 0x01f000f0) { - case 0x00a00030: - case 0x00e00030: - /* parallel halfword saturate */ - sprintf(cp, "%cSAT16%s\tr%d, #%d, r%d", - (opcode & (1 << 22)) ? 'U' : 'S', - COND(opcode), - (int) (opcode >> 12) & 0xf, - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf); - return ERROR_OK; - case 0x00b00030: - mnemonic = "REV"; - break; - case 0x00b000b0: - mnemonic = "REV16"; - break; - case 0x00f000b0: - mnemonic = "REVSH"; - break; - case 0x008000b0: - /* select bytes */ - sprintf(cp, "SEL%s\tr%d, r%d, r%d", COND(opcode), - (int) (opcode >> 12) & 0xf, - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf); - return ERROR_OK; - case 0x01800010: - /* unsigned sum of absolute differences */ - if (((opcode >> 12) & 0xf) == 0xf) - sprintf(cp, "USAD8%s\tr%d, r%d, r%d", COND(opcode), - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf, - (int) (opcode >> 8) & 0xf); - else - sprintf(cp, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode), - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf, - (int) (opcode >> 8) & 0xf, - (int) (opcode >> 12) & 0xf); - return ERROR_OK; + case 0x00a00030: + case 0x00e00030: + /* parallel halfword saturate */ + sprintf(cp, "%cSAT16%s\tr%d, #%d, r%d", + (opcode & (1 << 22)) ? 'U' : 'S', + COND(opcode), + (int)(opcode >> 12) & 0xf, + (int)(opcode >> 16) & 0xf, + (int)(opcode >> 0) & 0xf); + return ERROR_OK; + case 0x00b00030: + mnemonic = "REV"; + break; + case 0x00b000b0: + mnemonic = "REV16"; + break; + case 0x00f000b0: + mnemonic = "REVSH"; + break; + case 0x008000b0: + /* select bytes */ + sprintf(cp, "SEL%s\tr%d, r%d, r%d", COND(opcode), + (int)(opcode >> 12) & 0xf, + (int)(opcode >> 16) & 0xf, + (int)(opcode >> 0) & 0xf); + return ERROR_OK; + case 0x01800010: + /* unsigned sum of absolute differences */ + if (((opcode >> 12) & 0xf) == 0xf) + sprintf(cp, "USAD8%s\tr%d, r%d, r%d", COND(opcode), + (int)(opcode >> 16) & 0xf, + (int)(opcode >> 0) & 0xf, + (int)(opcode >> 8) & 0xf); + else + sprintf(cp, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode), + (int)(opcode >> 16) & 0xf, + (int)(opcode >> 0) & 0xf, + (int)(opcode >> 8) & 0xf, + (int)(opcode >> 12) & 0xf); + return ERROR_OK; } if (mnemonic) { unsigned int rm = (opcode >> 0) & 0xf; @@ -1079,7 +1075,7 @@ static int evaluate_misc_load_store(uint32_t opcode, if (i) {/* Immediate offset/index (#+-)*/ 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; @@ -1280,22 +1276,22 @@ static int evaluate_mul_and_extra_ld_st(uint32_t opcode, s = (opcode & 0x00100000) >> 20; switch ((opcode & 0x00600000) >> 21) { - case 0x0: - instruction->type = ARM_UMULL; - mnemonic = "UMULL"; - break; - case 0x1: - instruction->type = ARM_UMLAL; - mnemonic = "UMLAL"; - break; - case 0x2: - instruction->type = ARM_SMULL; - mnemonic = "SMULL"; - break; - case 0x3: - instruction->type = ARM_SMLAL; - mnemonic = "SMLAL"; - break; + case 0x0: + instruction->type = ARM_UMULL; + mnemonic = "UMULL"; + break; + case 0x1: + instruction->type = ARM_UMLAL; + mnemonic = "UMLAL"; + break; + case 0x2: + instruction->type = ARM_SMULL; + mnemonic = "SMULL"; + break; + case 0x3: + instruction->type = ARM_SMLAL; + mnemonic = "SMLAL"; + break; } snprintf(instruction->text, @@ -1480,22 +1476,22 @@ static int evaluate_misc_instr(uint32_t opcode, rn = (opcode & 0xf0000) >> 16; switch ((opcode & 0x00600000) >> 21) { - case 0x0: - instruction->type = ARM_QADD; - mnemonic = "QADD"; - break; - case 0x1: - instruction->type = ARM_QSUB; - mnemonic = "QSUB"; - break; - case 0x2: - instruction->type = ARM_QDADD; - mnemonic = "QDADD"; - break; - case 0x3: - instruction->type = ARM_QDSUB; - mnemonic = "QDSUB"; - break; + case 0x0: + instruction->type = ARM_QADD; + mnemonic = "QADD"; + break; + case 0x1: + instruction->type = ARM_QSUB; + mnemonic = "QSUB"; + break; + case 0x2: + instruction->type = ARM_QDADD; + mnemonic = "QDADD"; + break; + case 0x3: + instruction->type = ARM_QDSUB; + mnemonic = "QDSUB"; + break; } snprintf(instruction->text, @@ -1527,26 +1523,26 @@ static int evaluate_misc_instr(uint32_t opcode, char *mnemonic = NULL; switch ((opcode & 0x600000) >> 21) { - case 0x1: - instruction->type = ARM_BKPT; - mnemonic = "BRKT"; - immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf); - break; - case 0x2: - instruction->type = ARM_HVC; - mnemonic = "HVC"; - immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf); - break; - case 0x3: - instruction->type = ARM_SMC; - mnemonic = "SMC"; - immediate = (opcode & 0xf); - break; + case 0x1: + instruction->type = ARM_BKPT; + mnemonic = "BRKT"; + immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf); + break; + case 0x2: + instruction->type = ARM_HVC; + mnemonic = "HVC"; + immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf); + break; + case 0x3: + instruction->type = ARM_SMC; + mnemonic = "SMC"; + immediate = (opcode & 0xf); + break; } snprintf(instruction->text, 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s 0x%4.4" PRIx32 "", + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s 0x%4.4" PRIx32, address, opcode, mnemonic, @@ -1717,70 +1713,70 @@ static int evaluate_data_proc(uint32_t opcode, instruction->info.data_proc.s = s; switch (op) { - case 0x0: - instruction->type = ARM_AND; - mnemonic = "AND"; - break; - case 0x1: - instruction->type = ARM_EOR; - mnemonic = "EOR"; - break; - case 0x2: - instruction->type = ARM_SUB; - mnemonic = "SUB"; - break; - case 0x3: - instruction->type = ARM_RSB; - mnemonic = "RSB"; - break; - case 0x4: - instruction->type = ARM_ADD; - mnemonic = "ADD"; - break; - case 0x5: - instruction->type = ARM_ADC; - mnemonic = "ADC"; - break; - case 0x6: - instruction->type = ARM_SBC; - mnemonic = "SBC"; - break; - case 0x7: - instruction->type = ARM_RSC; - mnemonic = "RSC"; - break; - case 0x8: - instruction->type = ARM_TST; - mnemonic = "TST"; - break; - case 0x9: - instruction->type = ARM_TEQ; - mnemonic = "TEQ"; - break; - case 0xa: - instruction->type = ARM_CMP; - mnemonic = "CMP"; - break; - case 0xb: - instruction->type = ARM_CMN; - mnemonic = "CMN"; - break; - case 0xc: - instruction->type = ARM_ORR; - mnemonic = "ORR"; - break; - case 0xd: - instruction->type = ARM_MOV; - mnemonic = "MOV"; - break; - case 0xe: - instruction->type = ARM_BIC; - mnemonic = "BIC"; - break; - case 0xf: - instruction->type = ARM_MVN; - mnemonic = "MVN"; - break; + case 0x0: + instruction->type = ARM_AND; + mnemonic = "AND"; + break; + case 0x1: + instruction->type = ARM_EOR; + mnemonic = "EOR"; + break; + case 0x2: + instruction->type = ARM_SUB; + mnemonic = "SUB"; + break; + case 0x3: + instruction->type = ARM_RSB; + mnemonic = "RSB"; + break; + case 0x4: + instruction->type = ARM_ADD; + mnemonic = "ADD"; + break; + case 0x5: + instruction->type = ARM_ADC; + mnemonic = "ADC"; + break; + case 0x6: + instruction->type = ARM_SBC; + mnemonic = "SBC"; + break; + case 0x7: + instruction->type = ARM_RSC; + mnemonic = "RSC"; + break; + case 0x8: + instruction->type = ARM_TST; + mnemonic = "TST"; + break; + case 0x9: + instruction->type = ARM_TEQ; + mnemonic = "TEQ"; + break; + case 0xa: + instruction->type = ARM_CMP; + mnemonic = "CMP"; + break; + case 0xb: + instruction->type = ARM_CMN; + mnemonic = "CMN"; + break; + case 0xc: + instruction->type = ARM_ORR; + mnemonic = "ORR"; + break; + case 0xd: + instruction->type = ARM_MOV; + mnemonic = "MOV"; + break; + case 0xe: + instruction->type = ARM_BIC; + mnemonic = "BIC"; + break; + case 0xf: + instruction->type = ARM_MVN; + mnemonic = "MVN"; + break; } if (i) {/* immediate shifter operand (#)*/ @@ -1790,7 +1786,7 @@ static int evaluate_data_proc(uint32_t opcode, immediate = ror(immed_8, rotate_imm * 2); - snprintf(shifter_operand, 32, "#0x%" PRIx32 "", immediate); + snprintf(shifter_operand, 32, "#0x%" PRIx32, immediate); instruction->info.data_proc.variant = 0; instruction->info.data_proc.shifter_operand.immediate.immediate = immediate; @@ -2065,28 +2061,28 @@ static int evaluate_b_bl_blx_thumb(uint16_t opcode, target_address = address + 4 + (offset << 1); switch (opc) { - /* unconditional branch */ - case 0: - instruction->type = ARM_B; - mnemonic = "B"; - break; - /* BLX suffix */ - case 1: - instruction->type = ARM_BLX; - mnemonic = "BLX"; - target_address &= 0xfffffffc; - break; - /* BL/BLX prefix */ - case 2: - instruction->type = ARM_UNKNOWN_INSTRUCTION; - mnemonic = "prefix"; - target_address = offset << 12; - break; - /* BL suffix */ - case 3: - instruction->type = ARM_BL; - mnemonic = "BL"; - break; + /* unconditional branch */ + case 0: + instruction->type = ARM_B; + mnemonic = "B"; + break; + /* BLX suffix */ + case 1: + instruction->type = ARM_BLX; + mnemonic = "BLX"; + target_address &= 0xfffffffc; + break; + /* BL/BLX prefix */ + case 2: + instruction->type = ARM_UNKNOWN_INSTRUCTION; + mnemonic = "prefix"; + target_address = offset << 12; + break; + /* BL suffix */ + case 3: + instruction->type = ARM_BL; + mnemonic = "BL"; + break; } /* TODO: deal correctly with dual opcode (prefixed) BL/BLX; @@ -2158,21 +2154,21 @@ static int evaluate_shift_imm_thumb(uint16_t opcode, char *mnemonic = NULL; switch (opc) { - case 0: - instruction->type = ARM_MOV; - mnemonic = "LSLS"; - instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0; - break; - case 1: - instruction->type = ARM_MOV; - mnemonic = "LSRS"; - instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1; - break; - case 2: - instruction->type = ARM_MOV; - mnemonic = "ASRS"; - instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2; - break; + case 0: + instruction->type = ARM_MOV; + mnemonic = "LSLS"; + instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0; + break; + case 1: + instruction->type = ARM_MOV; + mnemonic = "LSRS"; + instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1; + break; + case 2: + instruction->type = ARM_MOV; + mnemonic = "ASRS"; + instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2; + break; } if ((imm == 0) && (opc != 0)) @@ -2208,24 +2204,24 @@ static int evaluate_data_proc_imm_thumb(uint16_t opcode, instruction->info.data_proc.shifter_operand.immediate.immediate = imm; switch (opc) { - case 0: - instruction->type = ARM_MOV; - mnemonic = "MOVS"; - instruction->info.data_proc.rn = -1; - break; - case 1: - instruction->type = ARM_CMP; - mnemonic = "CMP"; - instruction->info.data_proc.rd = -1; - break; - case 2: - instruction->type = ARM_ADD; - mnemonic = "ADDS"; - break; - case 3: - instruction->type = ARM_SUB; - mnemonic = "SUBS"; - break; + case 0: + instruction->type = ARM_MOV; + mnemonic = "MOVS"; + instruction->info.data_proc.rn = -1; + break; + case 1: + instruction->type = ARM_CMP; + mnemonic = "CMP"; + instruction->info.data_proc.rd = -1; + break; + case 2: + instruction->type = ARM_ADD; + mnemonic = "ADDS"; + break; + case 3: + instruction->type = ARM_SUB; + mnemonic = "SUBS"; + break; } snprintf(instruction->text, 128, @@ -2262,131 +2258,131 @@ static int evaluate_data_proc_thumb(uint16_t opcode, op >>= 2; switch (op) { - case 0x0: - instruction->type = ARM_ADD; - mnemonic = "ADD"; - break; - case 0x1: - instruction->type = ARM_CMP; - mnemonic = "CMP"; - break; - case 0x2: - instruction->type = ARM_MOV; - mnemonic = "MOV"; - if (rd == rm) - nop = true; - break; - case 0x3: - if ((opcode & 0x7) == 0x0) { - 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); - } else { - instruction->type = ARM_BX; - snprintf(instruction->text, 128, - "0x%8.8" PRIx32 - " 0x%4.4x \tBX\tr%i", - address, opcode, rm); - } + case 0x0: + instruction->type = ARM_ADD; + mnemonic = "ADD"; + break; + case 0x1: + instruction->type = ARM_CMP; + mnemonic = "CMP"; + break; + case 0x2: + instruction->type = ARM_MOV; + mnemonic = "MOV"; + if (rd == rm) + nop = true; + break; + case 0x3: + if ((opcode & 0x7) == 0x0) { + 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); } else { - instruction->type = ARM_UNDEFINED_INSTRUCTION; + instruction->type = ARM_BX; snprintf(instruction->text, 128, "0x%8.8" PRIx32 - " 0x%4.4x \t" - "UNDEFINED INSTRUCTION", - address, opcode); + " 0x%4.4x \tBX\tr%i", + address, opcode, rm); } - return ERROR_OK; + } else { + instruction->type = ARM_UNDEFINED_INSTRUCTION; + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 + " 0x%4.4x \t" + "UNDEFINED INSTRUCTION", + address, opcode); + } + return ERROR_OK; } } else { switch (op) { - case 0x0: - instruction->type = ARM_AND; - mnemonic = "ANDS"; - break; - case 0x1: - instruction->type = ARM_EOR; - mnemonic = "EORS"; - break; - case 0x2: - instruction->type = ARM_MOV; - 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; - 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; - 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; - break; - case 0x5: - instruction->type = ARM_ADC; - mnemonic = "ADCS"; - break; - case 0x6: - instruction->type = ARM_SBC; - mnemonic = "SBCS"; - break; - case 0x7: - instruction->type = ARM_MOV; - 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; - break; - case 0x8: - instruction->type = ARM_TST; - mnemonic = "TST"; - break; - case 0x9: - instruction->type = ARM_RSB; - mnemonic = "RSBS"; - instruction->info.data_proc.variant = 0 /*immediate*/; - instruction->info.data_proc.shifter_operand.immediate.immediate = 0; - instruction->info.data_proc.rn = rm; - break; - case 0xA: - instruction->type = ARM_CMP; - mnemonic = "CMP"; - break; - case 0xB: - instruction->type = ARM_CMN; - mnemonic = "CMN"; - break; - case 0xC: - instruction->type = ARM_ORR; - mnemonic = "ORRS"; - break; - case 0xD: - instruction->type = ARM_MUL; - mnemonic = "MULS"; - break; - case 0xE: - instruction->type = ARM_BIC; - mnemonic = "BICS"; - break; - case 0xF: - instruction->type = ARM_MVN; - mnemonic = "MVNS"; - break; + case 0x0: + instruction->type = ARM_AND; + mnemonic = "ANDS"; + break; + case 0x1: + instruction->type = ARM_EOR; + mnemonic = "EORS"; + break; + case 0x2: + instruction->type = ARM_MOV; + 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; + 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; + 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; + break; + case 0x5: + instruction->type = ARM_ADC; + mnemonic = "ADCS"; + break; + case 0x6: + instruction->type = ARM_SBC; + mnemonic = "SBCS"; + break; + case 0x7: + instruction->type = ARM_MOV; + 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; + break; + case 0x8: + instruction->type = ARM_TST; + mnemonic = "TST"; + break; + case 0x9: + instruction->type = ARM_RSB; + mnemonic = "RSBS"; + instruction->info.data_proc.variant = 0 /*immediate*/; + instruction->info.data_proc.shifter_operand.immediate.immediate = 0; + instruction->info.data_proc.rn = rm; + break; + case 0xA: + instruction->type = ARM_CMP; + mnemonic = "CMP"; + break; + case 0xB: + instruction->type = ARM_CMN; + mnemonic = "CMN"; + break; + case 0xC: + instruction->type = ARM_ORR; + mnemonic = "ORRS"; + break; + case 0xD: + instruction->type = ARM_MUL; + mnemonic = "MULS"; + break; + case 0xE: + instruction->type = ARM_BIC; + mnemonic = "BICS"; + break; + case 0xF: + instruction->type = ARM_MVN; + mnemonic = "MVNS"; + break; } } @@ -2444,38 +2440,38 @@ static int evaluate_load_store_reg_thumb(uint16_t opcode, char *mnemonic = NULL; switch (opc) { - case 0: - instruction->type = ARM_STR; - mnemonic = "STR"; - break; - case 1: - instruction->type = ARM_STRH; - mnemonic = "STRH"; - break; - case 2: - instruction->type = ARM_STRB; - mnemonic = "STRB"; - break; - case 3: - instruction->type = ARM_LDRSB; - mnemonic = "LDRSB"; - break; - case 4: - instruction->type = ARM_LDR; - mnemonic = "LDR"; - break; - case 5: - instruction->type = ARM_LDRH; - mnemonic = "LDRH"; - break; - case 6: - instruction->type = ARM_LDRB; - mnemonic = "LDRB"; - break; - case 7: - instruction->type = ARM_LDRSH; - mnemonic = "LDRSH"; - break; + case 0: + instruction->type = ARM_STR; + mnemonic = "STR"; + break; + case 1: + instruction->type = ARM_STRH; + mnemonic = "STRH"; + break; + case 2: + instruction->type = ARM_STRB; + mnemonic = "STRB"; + break; + case 3: + instruction->type = ARM_LDRSB; + mnemonic = "LDRSB"; + break; + case 4: + instruction->type = ARM_LDR; + mnemonic = "LDR"; + break; + case 5: + instruction->type = ARM_LDRH; + mnemonic = "LDRH"; + break; + case 6: + instruction->type = ARM_LDRB; + mnemonic = "LDRB"; + break; + case 7: + instruction->type = ARM_LDRSH; + mnemonic = "LDRSH"; + break; } snprintf(instruction->text, 128, @@ -2628,7 +2624,7 @@ static int evaluate_breakpoint_thumb(uint16_t opcode, instruction->type = ARM_BKPT; snprintf(instruction->text, 128, - "0x%8.8" PRIx32 " 0x%4.4x \tBKPT\t%#2.2" PRIx32 "", + "0x%8.8" PRIx32 " 0x%4.4x \tBKPT\t%#2.2" PRIx32, address, opcode, imm); return ERROR_OK; @@ -2804,15 +2800,15 @@ static int evaluate_byterev_thumb(uint16_t opcode, uint32_t address, /* added in ARMv6 */ switch ((opcode >> 6) & 3) { - case 0: - suffix = ""; - break; - case 1: - suffix = "16"; - break; - default: - suffix = "SH"; - break; + case 0: + suffix = ""; + break; + case 1: + suffix = "16"; + break; + default: + suffix = "SH"; + break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tREV%s\tr%d, r%d", @@ -2828,24 +2824,24 @@ static int evaluate_hint_thumb(uint16_t opcode, uint32_t address, char *hint; switch ((opcode >> 4) & 0x0f) { - case 0: - hint = "NOP"; - break; - case 1: - hint = "YIELD"; - break; - case 2: - hint = "WFE"; - break; - case 3: - hint = "WFI"; - break; - case 4: - hint = "SEV"; - break; - default: - hint = "HINT (UNRECOGNIZED)"; - break; + case 0: + hint = "NOP"; + break; + case 1: + hint = "YIELD"; + break; + case 2: + hint = "WFE"; + break; + case 3: + hint = "WFI"; + break; + case 4: + hint = "SEV"; + break; + default: + hint = "HINT (UNRECOGNIZED)"; + break; } snprintf(instruction->text, 128, @@ -2928,36 +2924,36 @@ int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, struct arm_instruct /* Misc */ if ((opcode & 0xf000) == 0xb000) { switch ((opcode >> 8) & 0x0f) { - case 0x0: - return evaluate_adjust_stack_thumb(opcode, address, instruction); - case 0x1: - case 0x3: - case 0x9: - case 0xb: - return evaluate_cb_thumb(opcode, address, instruction); - case 0x2: - return evaluate_extend_thumb(opcode, address, instruction); - case 0x4: - case 0x5: - case 0xc: - case 0xd: - return evaluate_load_store_multiple_thumb(opcode, address, - instruction); - case 0x6: - return evaluate_cps_thumb(opcode, address, instruction); - case 0xa: - if ((opcode & 0x00c0) == 0x0080) - break; - return evaluate_byterev_thumb(opcode, address, instruction); - case 0xe: - return evaluate_breakpoint_thumb(opcode, address, instruction); - case 0xf: - if (opcode & 0x000f) - return evaluate_ifthen_thumb(opcode, address, - instruction); - else - return evaluate_hint_thumb(opcode, address, - instruction); + case 0x0: + return evaluate_adjust_stack_thumb(opcode, address, instruction); + case 0x1: + case 0x3: + case 0x9: + case 0xb: + return evaluate_cb_thumb(opcode, address, instruction); + case 0x2: + return evaluate_extend_thumb(opcode, address, instruction); + case 0x4: + case 0x5: + case 0xc: + case 0xd: + return evaluate_load_store_multiple_thumb(opcode, address, + instruction); + case 0x6: + return evaluate_cps_thumb(opcode, address, instruction); + case 0xa: + if ((opcode & 0x00c0) == 0x0080) + break; + return evaluate_byterev_thumb(opcode, address, instruction); + case 0xe: + return evaluate_breakpoint_thumb(opcode, address, instruction); + case 0xf: + if (opcode & 0x000f) + return evaluate_ifthen_thumb(opcode, address, + instruction); + else + return evaluate_hint_thumb(opcode, address, + instruction); } instruction->type = ARM_UNDEFINED_INSTRUCTION; @@ -3018,100 +3014,3 @@ int arm_access_size(struct arm_instruction *instruction) return 0; } } - -#if HAVE_CAPSTONE -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%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); - } -} - -int arm_disassemble(struct command_invocation *cmd, struct target *target, - target_addr_t address, size_t count, bool thumb_mode) -{ - csh handle; - int ret; - cs_insn *insn; - cs_mode mode; - - if (!cs_support(CS_ARCH_ARM)) { - LOG_ERROR("ARM architecture not supported by capstone"); - return ERROR_FAIL; - } - - mode = CS_MODE_LITTLE_ENDIAN; - - if (thumb_mode) - mode |= CS_MODE_THUMB; - - ret = cs_open(CS_ARCH_ARM, mode, &handle); - - if (ret != CS_ERR_OK) { - LOG_ERROR("cs_open() failed: %s", cs_strerror(ret)); - return ERROR_FAIL; - } - - ret = cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON); - - if (ret != CS_ERR_OK) { - LOG_ERROR("cs_option() failed: %s", cs_strerror(ret)); - cs_close(&handle); - return ERROR_FAIL; - } - - insn = cs_malloc(handle); - - if (!insn) { - LOG_ERROR("cs_malloc() failed\n"); - 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; -} -#endif /* HAVE_CAPSTONE */ diff --git a/src/target/arm_disassembler.h b/src/target/arm_disassembler.h index 8317da997b..25b4423466 100644 --- a/src/target/arm_disassembler.h +++ b/src/target/arm_disassembler.h @@ -187,10 +187,6 @@ int arm_evaluate_opcode(uint32_t opcode, uint32_t address, int thumb_evaluate_opcode(uint16_t opcode, 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 0b2db77c5c..63c41c5835 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -50,9 +50,8 @@ static int dpm_mrc(struct target *target, int cpnum, if (retval != ERROR_OK) return retval; - LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum, - (int) op1, (int) crn, - (int) crm, (int) op2); + LOG_TARGET_DEBUG(target, "MRC p%d, %" PRId32 ", r0, c%" PRId32 ", c%" PRId32 ", %" PRId32, + cpnum, op1, crn, crm, op2); /* read coprocessor register into R0; return via DCC */ retval = dpm->instr_read_data_r0(dpm, @@ -74,8 +73,8 @@ static int dpm_mrrc(struct target *target, int cpnum, if (retval != ERROR_OK) return retval; - LOG_DEBUG("MRRC p%d, %d, r0, r1, c%d", cpnum, - (int)op, (int)crm); + LOG_TARGET_DEBUG(target, "MRRC p%d, %" PRId32 ", r0, r1, c%" PRId32, + cpnum, op, crm); /* read coprocessor register into R0, R1; return via DCC */ retval = dpm->instr_read_data_r0_r1(dpm, @@ -98,9 +97,8 @@ static int dpm_mcr(struct target *target, int cpnum, if (retval != ERROR_OK) return retval; - LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum, - (int) op1, (int) crn, - (int) crm, (int) op2); + LOG_TARGET_DEBUG(target, "MCR p%d, %" PRId32 ", r0, c%" PRId32 ", c%" PRId32 ", %" PRId32, + cpnum, op1, crn, crm, op2); /* read DCC into r0; then write coprocessor register from R0 */ retval = dpm->instr_write_data_r0(dpm, @@ -122,8 +120,8 @@ static int dpm_mcrr(struct target *target, int cpnum, if (retval != ERROR_OK) return retval; - LOG_DEBUG("MCRR p%d, %d, r0, r1, c%d", cpnum, - (int)op, (int)crm); + LOG_TARGET_DEBUG(target, "MCRR p%d, %" PRId32 ", r0, r1, c%" PRId32, + cpnum, op, crm); /* read DCC into r0, r1; then write coprocessor register from R0, R1 */ retval = dpm->instr_write_data_r0_r1(dpm, @@ -173,24 +171,23 @@ static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned int reg uint32_t value_r0, value_r1; switch (regnum) { - case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: - /* move from double word register to r0:r1: "vmov r0, r1, vm" - * then read r0 via dcc - */ - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), - ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0); - if (retval != ERROR_OK) - break; - - /* read r1 via dcc */ - retval = dpm->instr_read_data_dcc(dpm, - ARMV4_5_MCR(14, 0, 1, 0, 5, 0), - &value_r1); + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + /* move from double word register to r0:r1: "vmov r0, r1, vm" + * then read r0 via dcc + */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), + ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0); + if (retval != ERROR_OK) break; - default: - break; + /* read r1 via dcc */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 1, 0, 5, 0), + &value_r1); + break; + default: + break; } if (retval == ERROR_OK) { @@ -198,7 +195,8 @@ static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned int reg buf_set_u32(r->value + 4, 0, 32, value_r1); r->valid = true; r->dirty = false; - LOG_DEBUG("READ: %s, %8.8" PRIx32 ", %8.8" PRIx32, r->name, value_r0, value_r1); + LOG_TARGET_DEBUG(dpm->arm->target, "READ: %s, %8.8" PRIx32 ", %8.8" PRIx32, + r->name, value_r0, value_r1); } return retval; @@ -211,61 +209,62 @@ int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned int regnum) int retval; switch (regnum) { - case 0 ... 14: - /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ - retval = dpm->instr_read_data_dcc(dpm, - ARMV4_5_MCR(14, 0, regnum, 0, 5, 0), - &value); + case 0 ... 14: + /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, regnum, 0, 5, 0), + &value); + break; + case 15:/* PC + * "MOV r0, pc"; then return via DCC */ + retval = dpm->instr_read_data_r0(dpm, 0xe1a0000f, &value); + + /* NOTE: this seems like a slightly awkward place to update + * this value ... but if the PC gets written (the only way + * to change what we compute), the arch spec says subsequent + * reads return values which are "unpredictable". So this + * is always right except in those broken-by-intent cases. + */ + switch (dpm->arm->core_state) { + case ARM_STATE_ARM: + value -= 8; break; - case 15:/* PC - * "MOV r0, pc"; then return via DCC */ - retval = dpm->instr_read_data_r0(dpm, 0xe1a0000f, &value); - - /* NOTE: this seems like a slightly awkward place to update - * this value ... but if the PC gets written (the only way - * to change what we compute), the arch spec says subsequent - * reads return values which are "unpredictable". So this - * is always right except in those broken-by-intent cases. - */ - switch (dpm->arm->core_state) { - case ARM_STATE_ARM: - value -= 8; - break; - case ARM_STATE_THUMB: - case ARM_STATE_THUMB_EE: - value -= 4; - break; - case ARM_STATE_JAZELLE: - /* core-specific ... ? */ - LOG_WARNING("Jazelle PC adjustment unknown"); - break; - default: - LOG_WARNING("unknown core state"); - break; - } + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + value -= 4; break; - case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: - return dpm_read_reg_u64(dpm, r, regnum); - case ARM_VFP_V3_FPSCR: - /* "VMRS r0, FPSCR"; then return via DCC */ - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_VMRS(0), &value); + case ARM_STATE_JAZELLE: + /* core-specific ... ? */ + LOG_TARGET_WARNING(dpm->arm->target, "Jazelle PC adjustment unknown"); break; default: - /* 16: "MRS r0, CPSR"; then return via DCC - * 17: "MRS r0, SPSR"; then return via DCC - */ - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_MRS(0, regnum & 1), - &value); + LOG_TARGET_WARNING(dpm->arm->target, "unknown core state"); break; + } + break; + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + return dpm_read_reg_u64(dpm, r, regnum); + case ARM_VFP_V3_FPSCR: + /* "VMRS r0, FPSCR"; then return via DCC */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMRS(0), &value); + break; + default: + /* 16: "MRS r0, CPSR"; then return via DCC + * 17: "MRS r0, SPSR"; then return via DCC + */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRS(0, regnum & 1), + &value); + break; } if (retval == ERROR_OK) { buf_set_u32(r->value, 0, 32, value); r->valid = true; r->dirty = false; - LOG_DEBUG("READ: %s, %8.8" PRIx32, r->name, value); + LOG_TARGET_DEBUG(dpm->arm->target, "READ: %s, %8.8" PRIx32, r->name, + value); } return retval; @@ -279,29 +278,29 @@ static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned int re uint32_t value_r1 = buf_get_u32(r->value + 4, 0, 32); switch (regnum) { - case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: - /* write value_r1 to r1 via dcc */ - retval = dpm->instr_write_data_dcc(dpm, - ARMV4_5_MRC(14, 0, 1, 0, 5, 0), - value_r1); - if (retval != ERROR_OK) - break; - - /* 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, ((regnum - ARM_VFP_V3_D0) >> 4), - ((regnum - ARM_VFP_V3_D0) & 0xf)), value_r0); + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + /* write value_r1 to r1 via dcc */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 1, 0, 5, 0), + value_r1); + if (retval != ERROR_OK) break; - default: - break; + /* 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, ((regnum - ARM_VFP_V3_D0) >> 4), + ((regnum - ARM_VFP_V3_D0) & 0xf)), value_r0); + break; + default: + break; } if (retval == ERROR_OK) { r->dirty = false; - LOG_DEBUG("WRITE: %s, %8.8" PRIx32 ", %8.8" PRIx32, r->name, value_r0, value_r1); + LOG_TARGET_DEBUG(dpm->arm->target, "WRITE: %s, %8.8" PRIx32 ", %8.8" PRIx32, + r->name, value_r0, value_r1); } return retval; @@ -314,42 +313,43 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned int regnum uint32_t value = buf_get_u32(r->value, 0, 32); switch (regnum) { - case 0 ... 14: - /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */ - retval = dpm->instr_write_data_dcc(dpm, - ARMV4_5_MRC(14, 0, regnum, 0, 5, 0), - value); - break; - case 15:/* PC - * read r0 from DCC; then "MOV pc, r0" */ - retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value); - break; - case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: - return dpm_write_reg_u64(dpm, r, regnum); - case ARM_VFP_V3_FPSCR: - /* move to r0 from DCC, then "VMSR FPSCR, r0" */ - retval = dpm->instr_write_data_r0(dpm, - ARMV4_5_VMSR(0), value); - break; - default: - /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf" - * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf" - */ - retval = dpm->instr_write_data_r0(dpm, - ARMV4_5_MSR_GP(0, 0xf, regnum & 1), - value); - if (retval != ERROR_OK) - return retval; + case 0 ... 14: + /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, regnum, 0, 5, 0), + value); + break; + case 15:/* PC + * read r0 from DCC; then "MOV pc, r0" */ + retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value); + break; + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + return dpm_write_reg_u64(dpm, r, regnum); + case ARM_VFP_V3_FPSCR: + /* move to r0 from DCC, then "VMSR FPSCR, r0" */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMSR(0), value); + break; + default: + /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf" + * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf" + */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MSR_GP(0, 0xf, regnum & 1), + value); + if (retval != ERROR_OK) + return retval; - if (regnum == 16 && dpm->instr_cpsr_sync) - retval = dpm->instr_cpsr_sync(dpm); + if (regnum == 16 && dpm->instr_cpsr_sync) + retval = dpm->instr_cpsr_sync(dpm); - break; + break; } if (retval == ERROR_OK) { r->dirty = false; - LOG_DEBUG("WRITE: %s, %8.8" PRIx32, r->name, value); + LOG_TARGET_DEBUG(dpm->arm->target, "WRITE: %s, %8.8" PRIx32, r->name, + value); } return retval; @@ -463,9 +463,8 @@ static int dpm_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, xp->address, xp->control); if (retval != ERROR_OK) - LOG_ERROR("%s: can't %s HW %spoint %d", + LOG_TARGET_ERROR(dpm->arm->target, "can't %s HW %spoint %d", disable ? "disable" : "enable", - target_name(dpm->arm->target), (xp->number < 16) ? "break" : "watch", xp->number & 0xf); done: @@ -654,24 +653,24 @@ static enum arm_mode dpm_mapmode(struct arm *arm, return ARM_MODE_ANY; switch (num) { - /* don't switch for non-shadowed registers (r0..r7, r15/pc, cpsr) */ - case 0 ... 7: - case 15: - case 16: - break; - /* r8..r12 aren't shadowed for anything except FIQ */ - case 8 ... 12: - if (mode == ARM_MODE_FIQ) - return mode; - break; - /* r13/sp, and r14/lr are always shadowed */ - case 13: - case 14: - case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR: + /* don't switch for non-shadowed registers (r0..r7, r15/pc, cpsr) */ + case 0 ... 7: + case 15: + case 16: + break; + /* r8..r12 aren't shadowed for anything except FIQ */ + case 8 ... 12: + if (mode == ARM_MODE_FIQ) return mode; - default: - LOG_WARNING("invalid register #%u", num); - break; + break; + /* r13/sp, and r14/lr are always shadowed */ + case 13: + case 14: + case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR: + return mode; + default: + LOG_TARGET_WARNING(arm->target, "invalid register #%u", num); + break; } return ARM_MODE_ANY; } @@ -867,26 +866,26 @@ static int dpm_bpwp_setup(struct arm_dpm *dpm, struct dpm_bpwp *xp, * v7 hardware, unaligned 4-byte ones too. */ switch (length) { - case 1: - control |= (1 << (addr & 3)) << 5; + case 1: + control |= (1 << (addr & 3)) << 5; + break; + case 2: + /* require 2-byte alignment */ + if (!(addr & 1)) { + control |= (3 << (addr & 2)) << 5; break; - case 2: - /* require 2-byte alignment */ - if (!(addr & 1)) { - control |= (3 << (addr & 2)) << 5; - break; - } - /* FALL THROUGH */ - case 4: - /* require 4-byte alignment */ - if (!(addr & 3)) { - control |= 0xf << 5; - break; - } - /* FALL THROUGH */ - default: - LOG_ERROR("unsupported {break,watch}point length/alignment"); - return ERROR_COMMAND_SYNTAX_ERROR; + } + /* FALL THROUGH */ + case 4: + /* require 4-byte alignment */ + if (!(addr & 3)) { + control |= 0xf << 5; + break; + } + /* FALL THROUGH */ + default: + LOG_TARGET_ERROR(dpm->arm->target, "unsupported {break,watch}point length/alignment"); + return ERROR_COMMAND_SYNTAX_ERROR; } /* other shared control bits: @@ -899,7 +898,7 @@ static int dpm_bpwp_setup(struct arm_dpm *dpm, struct dpm_bpwp *xp, xp->control = control; xp->dirty = true; - LOG_DEBUG("BPWP: addr %8.8" PRIx32 ", control %" PRIx32 ", number %d", + LOG_TARGET_DEBUG(dpm->arm->target, "BPWP: addr %8.8" PRIx32 ", control %" PRIx32 ", number %d", xp->address, control, xp->number); /* hardware is updated in write_dirty_registers() */ @@ -919,7 +918,7 @@ static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp) /* FIXME we need a generic solution for software breakpoints. */ if (bp->type == BKPT_SOFT) - LOG_DEBUG("using HW bkpt, not SW..."); + LOG_TARGET_DEBUG(dpm->arm->target, "using HW breakpoint instead of SW"); for (unsigned int i = 0; i < dpm->nbp; i++) { if (!dpm->dbp[i].bp) { @@ -963,7 +962,7 @@ static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned int index_t, /* this hardware doesn't support data value matching or masking */ if (wp->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) { - LOG_DEBUG("watchpoint values and masking not supported"); + LOG_TARGET_ERROR(dpm->arm->target, "watchpoint values and masking not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -973,15 +972,15 @@ static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned int index_t, control = dwp->bpwp.control; switch (wp->rw) { - case WPT_READ: - control |= 1 << 3; - break; - case WPT_WRITE: - control |= 2 << 3; - break; - case WPT_ACCESS: - control |= 3 << 3; - break; + case WPT_READ: + control |= 1 << 3; + break; + case WPT_WRITE: + control |= 2 << 3; + break; + case WPT_ACCESS: + control |= 3 << 3; + break; } dwp->bpwp.control = control; @@ -1031,17 +1030,17 @@ static int dpm_remove_watchpoint(struct target *target, struct watchpoint *wp) void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr) { switch (dpm->arm->core_state) { - case ARM_STATE_ARM: - addr -= 8; - break; - case ARM_STATE_THUMB: - case ARM_STATE_THUMB_EE: - addr -= 4; - break; - case ARM_STATE_JAZELLE: - case ARM_STATE_AARCH64: - /* ?? */ - break; + case ARM_STATE_ARM: + addr -= 8; + break; + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + addr -= 4; + break; + case ARM_STATE_JAZELLE: + case ARM_STATE_AARCH64: + /* ?? */ + break; } dpm->wp_addr = addr; } @@ -1060,21 +1059,22 @@ void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr) /* Examine debug reason */ switch (DSCR_ENTRY(dscr)) { - case DSCR_ENTRY_HALT_REQ: /* HALT request from debugger */ - case DSCR_ENTRY_EXT_DBG_REQ: /* EDBGRQ */ - target->debug_reason = DBG_REASON_DBGRQ; - break; - case DSCR_ENTRY_BREAKPOINT: /* HW breakpoint */ - case DSCR_ENTRY_BKPT_INSTR: /* vector catch */ - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case DSCR_ENTRY_IMPRECISE_WATCHPT: /* asynch watchpoint */ - case DSCR_ENTRY_PRECISE_WATCHPT:/* precise watchpoint */ - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - default: - target->debug_reason = DBG_REASON_UNDEFINED; - break; + case DSCR_ENTRY_HALT_REQ: /* HALT request from debugger */ + case DSCR_ENTRY_EXT_DBG_REQ: /* EDBGRQ */ + target->debug_reason = DBG_REASON_DBGRQ; + break; + case DSCR_ENTRY_BREAKPOINT: /* HW breakpoint */ + case DSCR_ENTRY_BKPT_INSTR: /* SW BKPT */ + case DSCR_ENTRY_VECT_CATCH: /* vector catch */ + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case DSCR_ENTRY_IMPRECISE_WATCHPT: /* asynch watchpoint */ + case DSCR_ENTRY_PRECISE_WATCHPT:/* precise watchpoint */ + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + default: + target->debug_reason = DBG_REASON_UNDEFINED; + break; } } @@ -1143,8 +1143,8 @@ int arm_dpm_setup(struct arm_dpm *dpm) return ERROR_FAIL; } - LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", - target_name(target), dpm->nbp, dpm->nwp); + LOG_TARGET_INFO(target, "hardware has %d breakpoints, %d watchpoints", + dpm->nbp, dpm->nwp); /* REVISIT ... and some of those breakpoints could match * execution context IDs... @@ -1172,8 +1172,7 @@ int arm_dpm_initialize(struct arm_dpm *dpm) (void) dpm->bpwp_disable(dpm, 16 + i); } } else - LOG_WARNING("%s: can't disable breakpoints and watchpoints", - target_name(dpm->arm->target)); + LOG_TARGET_WARNING(dpm->arm->target, "can't disable breakpoints and watchpoints"); return ERROR_OK; } diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index a7c47bf417..ea5f756d6a 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -22,7 +22,11 @@ * facilities on the host computer. The target application must be linked * against a library that forwards operation requests by using the SVC * instruction trapped at the Supervisor Call vector by the debugger. - * Details can be found in chapter 8 of DUI0203I_rvct_developer_guide.pdf + * Details can be found in + * "Semihosting for AArch32 and AArch64, 2025Q1" + * https://github.com/ARM-software/abi-aa/releases/download/2025Q1/semihosting.pdf + * and in + * https://developer.arm.com/documentation/dui0203/latest/semihosting * from ARM Ltd. */ diff --git a/src/target/arm_simulator.c b/src/target/arm_simulator.c index 058e3d38b8..8a87e44125 100644 --- a/src/target/arm_simulator.c +++ b/src/target/arm_simulator.c @@ -27,25 +27,31 @@ static uint32_t arm_shift(uint8_t shift, uint32_t rm, shift_amount &= 0xff; if (shift == 0x0) { /* LSL */ - if ((shift_amount > 0) && (shift_amount <= 32)) { + if (shift_amount > 0 && shift_amount < 32) { return_value = rm << shift_amount; *carry = rm >> (32 - shift_amount); + } else if (shift_amount == 32) { + return_value = 0x0; + *carry = rm & 0x1; } else if (shift_amount > 32) { return_value = 0x0; *carry = 0x0; } else /* (shift_amount == 0) */ return_value = rm; } else if (shift == 0x1) { /* LSR */ - if ((shift_amount > 0) && (shift_amount <= 32)) { + if (shift_amount > 0 && shift_amount < 32) { return_value = rm >> shift_amount; *carry = (rm >> (shift_amount - 1)) & 1; + } else if (shift_amount == 32) { + return_value = 0x0; + *carry = (rm >> 31) & 0x1; } else if (shift_amount > 32) { return_value = 0x0; *carry = 0x0; } else /* (shift_amount == 0) */ return_value = rm; } else if (shift == 0x2) { /* ASR */ - if ((shift_amount > 0) && (shift_amount <= 32)) { + if (shift_amount > 0 && shift_amount < 32) { /* C right shifts of unsigned values are guaranteed to * be logical (shift in zeroes); simulate an arithmetic * shift (shift in signed-bit) by adding the sign bit @@ -54,7 +60,7 @@ static uint32_t arm_shift(uint8_t shift, uint32_t rm, return_value = rm >> shift_amount; if (rm & 0x80000000) return_value |= 0xffffffff << (32 - shift_amount); - } else if (shift_amount > 32) { + } else if (shift_amount >= 32) { if (rm & 0x80000000) { return_value = 0xffffffff; *carry = 0x1; @@ -130,86 +136,85 @@ static uint32_t arm_shifter_operand(struct arm_sim_interface *sim, static int pass_condition(uint32_t cpsr, uint32_t opcode) { switch ((opcode & 0xf0000000) >> 28) { - case 0x0: /* EQ */ - if (cpsr & 0x40000000) - return 1; - else - return 0; - case 0x1: /* NE */ - if (!(cpsr & 0x40000000)) - return 1; - else - return 0; - case 0x2: /* CS */ - if (cpsr & 0x20000000) - return 1; - else - return 0; - case 0x3: /* CC */ - if (!(cpsr & 0x20000000)) - return 1; - else - return 0; - case 0x4: /* MI */ - if (cpsr & 0x80000000) - return 1; - else - return 0; - case 0x5: /* PL */ - if (!(cpsr & 0x80000000)) - return 1; - else - return 0; - case 0x6: /* VS */ - if (cpsr & 0x10000000) - return 1; - else - return 0; - case 0x7: /* VC */ - if (!(cpsr & 0x10000000)) - return 1; - else - return 0; - case 0x8: /* HI */ - if ((cpsr & 0x20000000) && !(cpsr & 0x40000000)) - return 1; - else - return 0; - case 0x9: /* LS */ - if (!(cpsr & 0x20000000) || (cpsr & 0x40000000)) - return 1; - else - return 0; - case 0xa: /* GE */ - if (((cpsr & 0x80000000) && (cpsr & 0x10000000)) - || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000))) - return 1; - else - return 0; - case 0xb: /* LT */ - if (((cpsr & 0x80000000) && !(cpsr & 0x10000000)) - || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) - return 1; - else - return 0; - case 0xc: /* GT */ - if (!(cpsr & 0x40000000) && - (((cpsr & 0x80000000) && (cpsr & 0x10000000)) - || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000)))) - return 1; - else - return 0; - case 0xd: /* LE */ - if ((cpsr & 0x40000000) || - ((cpsr & 0x80000000) && !(cpsr & 0x10000000)) - || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) - return 1; - else - return 0; - case 0xe: - case 0xf: + case 0x0: /* EQ */ + if (cpsr & 0x40000000) return 1; - + else + return 0; + case 0x1: /* NE */ + if (!(cpsr & 0x40000000)) + return 1; + else + return 0; + case 0x2: /* CS */ + if (cpsr & 0x20000000) + return 1; + else + return 0; + case 0x3: /* CC */ + if (!(cpsr & 0x20000000)) + return 1; + else + return 0; + case 0x4: /* MI */ + if (cpsr & 0x80000000) + return 1; + else + return 0; + case 0x5: /* PL */ + if (!(cpsr & 0x80000000)) + return 1; + else + return 0; + case 0x6: /* VS */ + if (cpsr & 0x10000000) + return 1; + else + return 0; + case 0x7: /* VC */ + if (!(cpsr & 0x10000000)) + return 1; + else + return 0; + case 0x8: /* HI */ + if ((cpsr & 0x20000000) && !(cpsr & 0x40000000)) + return 1; + else + return 0; + case 0x9: /* LS */ + if (!(cpsr & 0x20000000) || (cpsr & 0x40000000)) + return 1; + else + return 0; + case 0xa: /* GE */ + if (((cpsr & 0x80000000) && (cpsr & 0x10000000)) + || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000))) + return 1; + else + return 0; + case 0xb: /* LT */ + if (((cpsr & 0x80000000) && !(cpsr & 0x10000000)) + || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) + return 1; + else + return 0; + case 0xc: /* GT */ + if (!(cpsr & 0x40000000) && + (((cpsr & 0x80000000) && (cpsr & 0x10000000)) + || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000)))) + return 1; + else + return 0; + case 0xd: /* LE */ + if ((cpsr & 0x40000000) || + ((cpsr & 0x80000000) && !(cpsr & 0x10000000)) + || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) + return 1; + else + return 0; + case 0xe: + case 0xf: + return 1; } LOG_ERROR("BUG: should never get here"); @@ -510,18 +515,18 @@ static int arm_simulate_step_core(struct target *target, } switch (instruction.info.load_store_multiple.addressing_mode) { - case 0: /* Increment after */ - /* rn = rn; */ - break; - case 1: /* Increment before */ - rn = rn + 4; - break; - case 2: /* Decrement after */ - rn = rn - (bits_set * 4) + 4; - break; - case 3: /* Decrement before */ - rn = rn - (bits_set * 4); - break; + case 0: /* Increment after */ + /* rn = rn; */ + break; + case 1: /* Increment before */ + rn = rn + 4; + break; + case 2: /* Decrement after */ + rn = rn - (bits_set * 4) + 4; + break; + case 3: /* Decrement before */ + rn = rn - (bits_set * 4); + break; } for (i = 0; i < 16; i++) { @@ -590,18 +595,18 @@ static int arm_simulate_step_core(struct target *target, } switch (instruction.info.load_store_multiple.addressing_mode) { - case 0: /* Increment after */ - /* rn = rn; */ - break; - case 1: /* Increment before */ - rn = rn + 4; - break; - case 2: /* Decrement after */ - rn = rn - (bits_set * 4) + 4; - break; - case 3: /* Decrement before */ - rn = rn - (bits_set * 4); - break; + case 0: /* Increment after */ + /* rn = rn; */ + break; + case 1: /* Increment before */ + rn = rn + 4; + break; + case 2: /* Decrement after */ + rn = rn - (bits_set * 4) + 4; + break; + case 3: /* Decrement before */ + rn = rn - (bits_set * 4); + break; } for (i = 0; i < 16; i++) { diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index e20cd59272..715b1c962c 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -554,20 +554,28 @@ static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_s return JIM_ERR; } -static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(handle_arm_tpiu_swo_configure) { - struct command *c = jim_to_command(interp); + struct arm_tpiu_swo_object *obj = CMD_DATA; + + if (!CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC, CMD_JIMTCL_ARGV); + goi.is_configure = !strcmp(CMD_NAME, "configure"); - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - goi.is_configure = !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); + int e = arm_tpiu_swo_configure(&goi, obj); + + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); + + if (e != JIM_OK) + return ERROR_FAIL; + + return ERROR_OK; } static int wrap_write_u32(struct target *target, struct adiv5_ap *tpiu_ap, @@ -731,6 +739,7 @@ COMMAND_HANDLER(handle_arm_tpiu_swo_enable) CONNECTION_LIMIT_UNLIMITED, priv); if (retval != ERROR_OK) { command_print(CMD, "Can't configure trace TCP port %s", &obj->out_filename[1]); + free(priv); return retval; } } else if (strcmp(obj->out_filename, "-")) { @@ -872,14 +881,14 @@ static const struct command_registration arm_tpiu_swo_instance_command_handlers[ { .name = "configure", .mode = COMMAND_ANY, - .jim_handler = jim_arm_tpiu_swo_configure, + .handler = handle_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, + .handler = handle_arm_tpiu_swo_configure, .help = "returns the specified TPIU/SWO attribute", .usage = "attribute", }, @@ -907,56 +916,25 @@ static const struct command_registration arm_tpiu_swo_instance_command_handlers[ COMMAND_REGISTRATION_DONE }; -static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *obj) +COMMAND_HANDLER(handle_arm_tpiu_swo_create) { - struct command_context *cmd_ctx; - Jim_Cmd *cmd; - int e; + int retval = ERROR_FAIL; - cmd_ctx = current_command_context(interp); - assert(cmd_ctx); + if (!CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; /* 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; + Jim_Cmd *jimcmd = Jim_GetCommand(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], JIM_NONE); + if (jimcmd) { + command_print(CMD, "cannot create TPIU object because a command with name '%s' already exists", + CMD_ARGV[0]); + return ERROR_FAIL; } struct arm_tpiu_swo_object *obj = calloc(1, sizeof(struct arm_tpiu_swo_object)); if (!obj) { LOG_ERROR("Out of memory"); - return JIM_ERR; + return ERROR_FAIL; } INIT_LIST_HEAD(&obj->connections); adiv5_mem_ap_spot_init(&obj->spot); @@ -968,36 +946,55 @@ static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const goto err_exit; } - Jim_Obj *n; - jim_getopt_obj(&goi, &n); - obj->name = strdup(Jim_GetString(n, NULL)); + obj->name = strdup(CMD_ARGV[0]); if (!obj->name) { LOG_ERROR("Out of memory"); goto err_exit; } /* Do the rest as "configure" options */ - goi.is_configure = true; + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - 1, CMD_JIMTCL_ARGV + 1); + goi.is_configure = 1; int e = arm_tpiu_swo_configure(&goi, obj); + + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); + 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); + command_print(CMD, "-dap and -ap-num required when creating TPIU"); goto err_exit; } - e = arm_tpiu_swo_create(goi.interp, obj); - if (e != JIM_OK) + /* 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 + }; + retval = register_commands_with_data(CMD_CTX, NULL, obj_commands, obj); + if (retval != ERROR_OK) goto err_exit; - return JIM_OK; + list_add_tail(&obj->lh, &all_tpiu_swo); + + return ERROR_OK; err_exit: free(obj->name); free(obj->out_filename); free(obj); - return JIM_ERR; + return retval; } COMMAND_HANDLER(handle_arm_tpiu_swo_names) @@ -1192,7 +1189,7 @@ static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = { { .name = "create", .mode = COMMAND_ANY, - .jim_handler = jim_arm_tpiu_swo_create, + .handler = handle_arm_tpiu_swo_create, .usage = "name [-dap dap] [-ap-num num] [-baseaddr baseaddr]", .help = "Creates a new TPIU or SWO object", }, diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 597dc8990c..cb55a5a1ff 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -22,7 +22,6 @@ #include "armv4_5.h" #include "arm_jtag.h" #include "breakpoints.h" -#include "arm_disassembler.h" #include #include "algorithm.h" #include "register.h" @@ -192,30 +191,30 @@ bool is_arm_mode(unsigned int psr_mode) int arm_mode_to_number(enum arm_mode mode) { switch (mode) { - case ARM_MODE_ANY: - /* map MODE_ANY to user mode */ - case ARM_MODE_USR: - return 0; - case ARM_MODE_FIQ: - return 1; - case ARM_MODE_IRQ: - return 2; - case ARM_MODE_SVC: - return 3; - case ARM_MODE_ABT: - return 4; - case ARM_MODE_UND: - return 5; - case ARM_MODE_SYS: - return 6; - case ARM_MODE_MON: - case ARM_MODE_1176_MON: - return 7; - case ARM_MODE_HYP: - return 8; - default: - LOG_ERROR("invalid mode value encountered %d", mode); - return -1; + case ARM_MODE_ANY: + /* map MODE_ANY to user mode */ + case ARM_MODE_USR: + return 0; + case ARM_MODE_FIQ: + return 1; + case ARM_MODE_IRQ: + return 2; + case ARM_MODE_SVC: + return 3; + case ARM_MODE_ABT: + return 4; + case ARM_MODE_UND: + return 5; + case ARM_MODE_SYS: + return 6; + case ARM_MODE_MON: + case ARM_MODE_1176_MON: + return 7; + case ARM_MODE_HYP: + return 8; + default: + LOG_ERROR("invalid mode value encountered %d", mode); + return -1; } } @@ -223,27 +222,27 @@ int arm_mode_to_number(enum arm_mode mode) enum arm_mode armv4_5_number_to_mode(int number) { switch (number) { - case 0: - return ARM_MODE_USR; - case 1: - return ARM_MODE_FIQ; - case 2: - return ARM_MODE_IRQ; - case 3: - return ARM_MODE_SVC; - case 4: - return ARM_MODE_ABT; - case 5: - return ARM_MODE_UND; - case 6: - return ARM_MODE_SYS; - case 7: - return ARM_MODE_MON; - case 8: - return ARM_MODE_HYP; - default: - LOG_ERROR("mode index out of bounds %d", number); - return ARM_MODE_ANY; + case 0: + return ARM_MODE_USR; + case 1: + return ARM_MODE_FIQ; + case 2: + return ARM_MODE_IRQ; + case 3: + return ARM_MODE_SVC; + case 4: + return ARM_MODE_ABT; + case 5: + return ARM_MODE_UND; + case 6: + return ARM_MODE_SYS; + case 7: + return ARM_MODE_MON; + case 8: + return ARM_MODE_HYP; + default: + LOG_ERROR("mode index out of bounds %d", number); + return ARM_MODE_ANY; } } @@ -355,6 +354,7 @@ static const struct { /* These exist only when the Virtualization Extensions is present */ [42] = { .name = "sp_hyp", .cookie = 13, .mode = ARM_MODE_HYP, .gdb_index = 51, }, [43] = { .name = "spsr_hyp", .cookie = 16, .mode = ARM_MODE_HYP, .gdb_index = 52, }, + // .gdb_index numbering continues by ARM_VFP_V3_D0 }; static const struct { @@ -437,7 +437,7 @@ const int armv4_5_core_reg_map[9][17] = { static const char *arm_core_state_string(struct arm *arm) { if (arm->core_state > ARRAY_SIZE(arm_state_strings)) { - LOG_ERROR("core_state exceeds table size"); + LOG_TARGET_ERROR(arm->target, "core_state exceeds table size"); return "Unknown"; } @@ -483,20 +483,20 @@ void arm_set_cpsr(struct arm *arm, uint32_t cpsr) if (cpsr & (1 << 5)) { /* T */ if (cpsr & (1 << 24)) { /* J */ - LOG_WARNING("ThumbEE -- incomplete support"); + LOG_TARGET_WARNING(arm->target, "ThumbEE -- incomplete support"); state = ARM_STATE_THUMB_EE; } else state = ARM_STATE_THUMB; } else { if (cpsr & (1 << 24)) { /* J */ - LOG_ERROR("Jazelle state handling is BROKEN!"); + LOG_TARGET_ERROR(arm->target, "Jazelle state handling is broken"); state = ARM_STATE_JAZELLE; } else state = ARM_STATE_ARM; } arm->core_state = state; - LOG_DEBUG("set CPSR %#8.8" PRIx32 ": %s mode, %s state", cpsr, + LOG_TARGET_DEBUG(arm->target, "set CPSR %#8.8" PRIx32 ": %s mode, %s state", cpsr, arm_mode_name(mode), arm_core_state_string(arm)); } @@ -521,7 +521,7 @@ struct reg *arm_reg_current(struct arm *arm, unsigned int regnum) return NULL; if (!arm->map) { - LOG_ERROR("Register map is not available yet, the target is not fully initialised"); + LOG_TARGET_ERROR(arm->target, "Register map is not available yet, the target is not fully initialised"); r = arm->core_cache->reg_list + regnum; } else r = arm->core_cache->reg_list + arm->map[regnum]; @@ -530,7 +530,7 @@ struct reg *arm_reg_current(struct arm *arm, unsigned int regnum) * that doesn't support it... */ if (!r) { - LOG_ERROR("Invalid CPSR mode"); + LOG_TARGET_ERROR(arm->target, "Invalid CPSR mode"); r = arm->core_cache->reg_list + regnum; } @@ -631,7 +631,7 @@ static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf) */ if (armv4_5_target->core_mode != (enum arm_mode)(value & 0x1f)) { - LOG_DEBUG("changing ARM core mode to '%s'", + LOG_TARGET_DEBUG(target, "changing ARM core mode to '%s'", arm_mode_name(value & 0x1f)); value &= ~((1 << 24) | (1 << 5)); uint8_t t[4]; @@ -659,15 +659,14 @@ static const struct reg_arch_type arm_reg_type = { struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) { - int num_regs = ARRAY_SIZE(arm_core_regs); - int num_core_regs = num_regs; + unsigned int num_regs = ARRAY_SIZE(arm_core_regs); + unsigned int num_core_regs = num_regs; if (arm->arm_vfp_version == ARM_VFP_V3) num_regs += ARRAY_SIZE(arm_vfp_v3_regs); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct arm_reg *reg_arch_info = calloc(num_regs, sizeof(struct arm_reg)); - int i; if (!cache || !reg_list || !reg_arch_info) { free(cache); @@ -681,7 +680,7 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) cache->reg_list = reg_list; cache->num_regs = 0; - for (i = 0; i < num_core_regs; i++) { + for (unsigned int i = 0; i < num_core_regs; i++) { /* Skip registers this core doesn't expose */ if (arm_core_regs[i].mode == ARM_MODE_MON && arm->core_type != ARM_CORE_TYPE_SEC_EXT @@ -691,8 +690,6 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; - /* REVISIT handle Cortex-M, which only shadows R13/SP */ - reg_arch_info[i].num = arm_core_regs[i].cookie; reg_arch_info[i].mode = arm_core_regs[i].mode; reg_arch_info[i].target = target; @@ -706,9 +703,6 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) reg_list[i].arch_info = ®_arch_info[i]; reg_list[i].exist = true; - /* This really depends on the calling convention in use */ - reg_list[i].caller_save = false; - /* Registers data type, as used by GDB target description */ reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type)); switch (arm_core_regs[i].cookie) { @@ -729,16 +723,22 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) if (reg_list[i].number <= 15 || reg_list[i].number == 25) { reg_list[i].feature->name = "org.gnu.gdb.arm.core"; reg_list[i].group = "general"; + /* Registers which should be preserved across GDB inferior function calls. + * Avoid saving banked registers as GDB (version 16.2 in time of writing) + * does not take the current mode into account and messes the value + * by restoring both the not banked register and the banked alias of it + * in the current mode. */ + reg_list[i].caller_save = true; } else { reg_list[i].feature->name = "net.sourceforge.openocd.banked"; reg_list[i].group = "banked"; + reg_list[i].caller_save = false; } cache->num_regs++; } - int j; - for (i = num_core_regs, j = 0; i < num_regs; i++, j++) { + for (unsigned int i = num_core_regs, j = 0; i < num_regs; i++, j++) { reg_arch_info[i].num = arm_vfp_v3_regs[j].id; reg_arch_info[i].mode = arm_vfp_v3_regs[j].mode; reg_arch_info[i].target = target; @@ -752,7 +752,8 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) reg_list[i].arch_info = ®_arch_info[i]; reg_list[i].exist = true; - reg_list[i].caller_save = false; + /* Mark d0 - d31 and fpscr as save-restore for GDB */ + reg_list[i].caller_save = true; reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type)); reg_list[i].reg_data_type->type = arm_vfp_v3_regs[j].type; @@ -798,7 +799,7 @@ int arm_arch_state(struct target *target) struct arm *arm = target_to_arm(target); if (arm->common_magic != ARM_COMMON_MAGIC) { - LOG_ERROR("BUG: called for a non-ARM target"); + LOG_TARGET_ERROR(target, "BUG: called for a non-ARM target"); return ERROR_FAIL; } @@ -806,7 +807,7 @@ int arm_arch_state(struct target *target) if (target->semihosting && target->semihosting->hit_fileio) return ERROR_OK; - LOG_USER("target halted in %s state due to %s, current mode: %s\n" + LOG_TARGET_USER(target, "target halted in %s state due to %s, current mode: %s\n" "cpsr: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "%s%s", arm_core_state_string(arm), debug_reason_name(target), @@ -842,7 +843,7 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) } if (!is_arm_mode(arm->core_mode)) { - LOG_ERROR("not a valid arm core mode - communication failure?"); + command_print(CMD, "not a valid arm core mode - communication failure?"); return ERROR_FAIL; } @@ -864,26 +865,26 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) /* label this bank of registers (or shadows) */ switch (arm_mode_data[mode].psr) { - case ARM_MODE_SYS: + case ARM_MODE_SYS: + continue; + case ARM_MODE_USR: + name = "System and User"; + sep = ""; + break; + case ARM_MODE_HYP: + if (arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; - case ARM_MODE_USR: - name = "System and User"; - sep = ""; - break; - case ARM_MODE_HYP: - if (arm->core_type != ARM_CORE_TYPE_VIRT_EXT) - 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; - /* FALLTHROUGH */ - default: - name = arm_mode_data[mode].name; - shadow = "shadow "; - break; + /* 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; + /* FALLTHROUGH */ + default: + name = arm_mode_data[mode].name; + shadow = "shadow "; + break; } command_print(CMD, "%s%s mode %sregisters", sep, name, shadow); @@ -948,61 +949,6 @@ COMMAND_HANDLER(handle_arm_core_state_command) return ret; } -COMMAND_HANDLER(handle_arm_disassemble_command) -{ -#if HAVE_CAPSTONE - struct target *target = get_current_target(CMD_CTX); - - if (!target) { - LOG_ERROR("No target selected"); - return ERROR_FAIL; - } - - struct arm *arm = target_to_arm(target); - target_addr_t address; - unsigned int count = 1; - bool thumb = false; - - 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 is always thumb mode */ - thumb = true; - } - - switch (CMD_ARGC) { - case 3: - if (strcmp(CMD_ARGV[2], "thumb") != 0) - return ERROR_COMMAND_SYNTAX_ERROR; - thumb = true; - /* FALL THROUGH */ - case 2: - 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 = true; - } - address &= ~1; - } - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return arm_disassemble(CMD, target, address, count, thumb); -#else - command_print(CMD, "capstone disassembly framework required"); - return ERROR_FAIL; -#endif -} - COMMAND_HANDLER(handle_armv4_5_mcrmrc) { bool is_mcr = false; @@ -1245,13 +1191,6 @@ const struct command_registration arm_all_profiles_command_handlers[] = { .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, }, @@ -1291,7 +1230,7 @@ int arm_get_gdb_reg_list(struct target *target, unsigned int i; if (!is_arm_mode(arm->core_mode)) { - LOG_ERROR("not a valid arm core mode - communication failure?"); + LOG_TARGET_ERROR(target, "not a valid arm core mode - communication failure?"); return ERROR_FAIL; } @@ -1314,14 +1253,14 @@ int arm_get_gdb_reg_list(struct target *target, case REG_CLASS_ALL: switch (arm->core_type) { - case ARM_CORE_TYPE_SEC_EXT: - *reg_list_size = 51; - break; - case ARM_CORE_TYPE_VIRT_EXT: - *reg_list_size = 53; - break; - default: - *reg_list_size = 48; + case ARM_CORE_TYPE_SEC_EXT: + *reg_list_size = 51; + break; + case ARM_CORE_TYPE_VIRT_EXT: + *reg_list_size = 53; + break; + default: + *reg_list_size = 48; } unsigned int list_size_core = *reg_list_size; if (arm->arm_vfp_version == ARM_VFP_V3) @@ -1362,7 +1301,7 @@ int arm_get_gdb_reg_list(struct target *target, return ERROR_OK; default: - LOG_ERROR("not a valid register class type in query."); + LOG_TARGET_ERROR(target, "not a valid register class type in query"); return ERROR_FAIL; } } @@ -1391,8 +1330,7 @@ static int armv4_5_run_algorithm_completion(struct target *target, /* fast exit: ARMv5+ code can use BKPT */ if (exit_point && buf_get_u32(arm->pc->value, 0, 32) != exit_point) { - LOG_WARNING( - "target reentered debug state, but not at the desired exit point: 0x%4.4" PRIx32 "", + LOG_TARGET_ERROR(target, "reentered debug state, but not at the desired exit point: 0x%4.4" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); return ERROR_TARGET_TIMEOUT; } @@ -1414,13 +1352,12 @@ int armv4_5_run_algorithm_inner(struct target *target, uint32_t context[17]; uint32_t cpsr; int exit_breakpoint_size = 0; - int i; int retval = ERROR_OK; - LOG_DEBUG("Running algorithm"); + LOG_TARGET_DEBUG(target, "Running algorithm"); if (arm_algorithm_info->common_magic != ARM_COMMON_MAGIC) { - LOG_ERROR("current target isn't an ARMV4/5 target"); + LOG_TARGET_ERROR(target, "current target isn't an ARMV4/5 target"); return ERROR_TARGET_INVALID; } @@ -1430,20 +1367,20 @@ int armv4_5_run_algorithm_inner(struct target *target, } if (!is_arm_mode(arm->core_mode)) { - LOG_ERROR("not a valid arm core mode - communication failure?"); + LOG_TARGET_ERROR(target, "not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* armv5 and later can terminate with BKPT instruction; less overhead */ if (!exit_point && arm->arch == ARM_ARCH_V4) { - LOG_ERROR("ARMv4 target needs HW breakpoint location"); + LOG_TARGET_ERROR(target, "ARMv4 target needs HW breakpoint location"); return ERROR_FAIL; } /* save r0..pc, cpsr-or-spsr, and then cpsr-for-sure; * they'll be restored later. */ - for (i = 0; i <= 16; i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(context); i++) { struct reg *r; r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, @@ -1455,7 +1392,7 @@ int armv4_5_run_algorithm_inner(struct target *target, } cpsr = buf_get_u32(arm->cpsr->value, 0, 32); - for (i = 0; i < num_mem_params; i++) { + for (int i = 0; i < num_mem_params; i++) { if (mem_params[i].direction == PARAM_IN) continue; retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, @@ -1464,18 +1401,18 @@ int armv4_5_run_algorithm_inner(struct target *target, return retval; } - for (i = 0; i < num_reg_params; i++) { + for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction == PARAM_IN) continue; 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); + LOG_TARGET_ERROR(target, "BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { - LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", + LOG_TARGET_ERROR(target, "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1491,12 +1428,12 @@ int armv4_5_run_algorithm_inner(struct target *target, else if (arm->core_state == ARM_STATE_THUMB) exit_breakpoint_size = 2; else { - LOG_ERROR("BUG: can't execute algorithms when not in ARM or Thumb state"); + LOG_TARGET_ERROR(target, "BUG: can't execute algorithms when not in ARM or Thumb state"); return ERROR_COMMAND_SYNTAX_ERROR; } if (arm_algorithm_info->core_mode != ARM_MODE_ANY) { - LOG_DEBUG("setting core_mode: 0x%2.2x", + LOG_TARGET_DEBUG(target, "setting core_mode: 0x%2.2x", arm_algorithm_info->core_mode); buf_set_u32(arm->cpsr->value, 0, 5, arm_algorithm_info->core_mode); @@ -1509,7 +1446,7 @@ int armv4_5_run_algorithm_inner(struct target *target, retval = breakpoint_add(target, exit_point, exit_breakpoint_size, BKPT_HARD); if (retval != ERROR_OK) { - LOG_ERROR("can't add HW breakpoint to terminate algorithm"); + LOG_TARGET_ERROR(target, "can't add HW breakpoint to terminate algorithm"); return ERROR_TARGET_FAILURE; } } @@ -1525,7 +1462,7 @@ int armv4_5_run_algorithm_inner(struct target *target, if (retval != ERROR_OK) return retval; - for (i = 0; i < num_mem_params; i++) { + for (int i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { int retvaltemp = target_read_buffer(target, mem_params[i].address, mem_params[i].size, @@ -1535,20 +1472,20 @@ int armv4_5_run_algorithm_inner(struct target *target, } } - for (i = 0; i < num_reg_params; i++) { + for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { 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); + LOG_TARGET_ERROR(target, "BUG: register '%s' not found", reg_params[i].reg_name); retval = ERROR_COMMAND_SYNTAX_ERROR; continue; } if (reg->size != reg_params[i].size) { - LOG_ERROR( + LOG_TARGET_ERROR(target, "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); retval = ERROR_COMMAND_SYNTAX_ERROR; @@ -1560,12 +1497,12 @@ int armv4_5_run_algorithm_inner(struct target *target, } /* restore everything we saved before (17 or 18 registers) */ - for (i = 0; i <= 16; i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(context); i++) { uint32_t regvalue; regvalue = buf_get_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).value, 0, 32); if (regvalue != context[i]) { - LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32 "", + LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).name, context[i]); buf_set_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, @@ -1638,8 +1575,10 @@ int arm_checksum_memory(struct target *target, retval = target_write_u32(target, crc_algorithm->address + i * sizeof(uint32_t), le_to_h_u32(&arm_crc_code_le[i * 4])); - if (retval != ERROR_OK) - goto cleanup; + if (retval != ERROR_OK) { + target_free_working_area(target, crc_algorithm); + return retval; + } } arm_algo.common_magic = ARM_COMMON_MAGIC; @@ -1667,12 +1606,11 @@ int arm_checksum_memory(struct target *target, if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else - LOG_ERROR("error executing ARM crc algorithm"); + LOG_TARGET_ERROR(target, "error executing ARM CRC algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); -cleanup: target_free_working_area(target, crc_algorithm); return retval; @@ -1685,7 +1623,8 @@ int arm_checksum_memory(struct target *target, * */ int arm_blank_check_memory(struct target *target, - struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) + struct target_memory_check_block *blocks, unsigned int num_blocks, + uint8_t erased_value, unsigned int *checked) { struct working_area *check_algorithm; struct reg_param reg_params[3]; @@ -1702,7 +1641,7 @@ int arm_blank_check_memory(struct target *target, assert(sizeof(check_code_le) % 4 == 0); if (erased_value != 0xff) { - LOG_ERROR("Erase value 0x%02" PRIx8 " not yet supported for ARMv4/v5 targets", + LOG_TARGET_ERROR(target, "Erase value 0x%02" PRIx8 " not yet supported for ARMv4/v5 targets", erased_value); return ERROR_FAIL; } @@ -1719,8 +1658,10 @@ int arm_blank_check_memory(struct target *target, check_algorithm->address + i * sizeof(uint32_t), le_to_h_u32(&check_code_le[i * 4])); - if (retval != ERROR_OK) - goto cleanup; + if (retval != ERROR_OK) { + target_free_working_area(target, check_algorithm); + return retval; + } } arm_algo.common_magic = ARM_COMMON_MAGIC; @@ -1745,20 +1686,18 @@ int arm_blank_check_memory(struct target *target, exit_var, 10000, &arm_algo); - if (retval == ERROR_OK) + if (retval == ERROR_OK) { blocks[0].result = buf_get_u32(reg_params[2].value, 0, 32); + *checked = 1; /* only one block has been checked */ + } destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); -cleanup: target_free_working_area(target, check_algorithm); - if (retval != ERROR_OK) - return retval; - - return 1; /* only one block has been checked */ + return retval; } static int arm_full_context(struct target *target) @@ -1781,7 +1720,7 @@ static int arm_default_mrc(struct target *target, int cpnum, uint32_t crn, uint32_t crm, uint32_t *value) { - LOG_ERROR("%s doesn't implement MRC", target_type_name(target)); + LOG_TARGET_ERROR(target, "%s doesn't implement MRC", target_type_name(target)); return ERROR_FAIL; } @@ -1789,7 +1728,7 @@ 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)); + LOG_TARGET_ERROR(target, "%s doesn't implement MRRC", target_type_name(target)); return ERROR_FAIL; } @@ -1798,7 +1737,7 @@ static int arm_default_mcr(struct target *target, int cpnum, uint32_t crn, uint32_t crm, uint32_t value) { - LOG_ERROR("%s doesn't implement MCR", target_type_name(target)); + LOG_TARGET_ERROR(target, "%s doesn't implement MCR", target_type_name(target)); return ERROR_FAIL; } @@ -1806,7 +1745,7 @@ 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)); + LOG_TARGET_ERROR(target, "%s doesn't implement MCRR", target_type_name(target)); return ERROR_FAIL; } @@ -1838,3 +1777,35 @@ int arm_init_arch_info(struct target *target, struct arm *arm) return ERROR_OK; } + +int armv4_5_insn_set(struct command_invocation *cmd, struct target *target, + const char **insn_set) +{ + struct arm *arm = target_to_arm(target); + + if (target->state != TARGET_HALTED) { + command_print(cmd, "[%s] not halted", target_name(target)); + return ERROR_TARGET_NOT_HALTED; + } + + switch (arm->core_state) { + case ARM_STATE_ARM: + if (target->endianness == TARGET_BIG_ENDIAN) + *insn_set = "armbe"; + else + *insn_set = "arm"; + break; + + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + *insn_set = "thumb"; + break; + + default: + command_print(cmd, "[%s] unknown core_state %d", target_name(target), + arm->core_state); + return ERROR_FAIL; + } + + return ERROR_OK; +} diff --git a/src/target/armv4_5_cache.h b/src/target/armv4_5_cache.h index 3659941e52..63fbdff33a 100644 --- a/src/target/armv4_5_cache.h +++ b/src/target/armv4_5_cache.h @@ -24,8 +24,8 @@ struct armv4_5_cache_common { int separate; /* separate caches or unified cache */ struct armv4_5_cachesize d_u_size; /* data cache */ struct armv4_5_cachesize i_size; /* instruction cache */ - int i_cache_enabled; - int d_u_cache_enabled; + bool i_cache_enabled; + bool d_u_cache_enabled; }; int armv4_5_identify_cache(uint32_t cache_type_reg, diff --git a/src/target/armv4_5_mmu.c b/src/target/armv4_5_mmu.c index 0c09cb4ca7..4337bfb8fa 100644 --- a/src/target/armv4_5_mmu.c +++ b/src/target/armv4_5_mmu.c @@ -31,7 +31,7 @@ int armv4_5_mmu_translate_va(struct target *target, return retval; first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&first_lvl_descriptor); - LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor); + LOG_DEBUG("1st lvl desc: %8.8" PRIx32, first_lvl_descriptor); if ((first_lvl_descriptor & 0x3) == 0) { LOG_ERROR("Address translation failure"); @@ -68,7 +68,7 @@ int armv4_5_mmu_translate_va(struct target *target, second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&second_lvl_descriptor); - LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor); + LOG_DEBUG("2nd lvl desc: %8.8" PRIx32, second_lvl_descriptor); if ((second_lvl_descriptor & 0x3) == 0) { LOG_ERROR("Address translation failure"); diff --git a/src/target/armv4_5_mmu.h b/src/target/armv4_5_mmu.h index 774f1056eb..bb30e807f4 100644 --- a/src/target/armv4_5_mmu.h +++ b/src/target/armv4_5_mmu.h @@ -21,7 +21,7 @@ struct armv4_5_mmu_common { int (*enable_mmu_caches)(struct target *target, int mmu, int d_u_cache, int i_cache); struct armv4_5_cache_common armv4_5_cache; int has_tiny_pages; - int mmu_enabled; + bool mmu_enabled; }; int armv4_5_mmu_translate_va(struct target *target, diff --git a/src/target/armv7a.c b/src/target/armv7a.c index 4d353dec65..7336a73402 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -14,10 +14,10 @@ #include "armv7a.h" #include "armv7a_mmu.h" -#include "arm_disassembler.h" #include "register.h" #include +#include #include #include @@ -68,9 +68,9 @@ static void armv7a_show_fault_registers(struct target *target) if (retval != ERROR_OK) goto done; - LOG_USER("Data fault registers DFSR: %8.8" PRIx32 + LOG_TARGET_USER(target, "Data fault registers DFSR: %8.8" PRIx32 ", DFAR: %8.8" PRIx32, dfsr, dfar); - LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32 + LOG_TARGET_USER(target, "Instruction fault registers IFSR: %8.8" PRIx32 ", IFAR: %8.8" PRIx32, ifsr, ifar); done: @@ -134,11 +134,11 @@ int armv7a_read_ttbcr(struct target *target) if (retval != ERROR_OK) goto done; - LOG_DEBUG("ttbcr %" PRIx32, ttbcr); + LOG_TARGET_DEBUG(target, "ttbcr %" PRIx32, ttbcr); ttbcr_n = ttbcr & 0x7; armv7a->armv7a_mmu.ttbcr = ttbcr; - armv7a->armv7a_mmu.cached = 1; + armv7a->armv7a_mmu.cached = true; for (ttbidx = 0; ttbidx < 2; ttbidx++) { /* MRC p15,0,,c2,c0,ttbidx */ @@ -157,7 +157,7 @@ int armv7a_read_ttbcr(struct target *target) armv7a->armv7a_mmu.ttbr_range[1] = 0xffffffff; armv7a->armv7a_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n); armv7a->armv7a_mmu.ttbr_mask[1] = 0xffffffff << 14; - armv7a->armv7a_mmu.cached = 1; + armv7a->armv7a_mmu.cached = true; retval = armv7a_read_midr(target); if (retval != ERROR_OK) @@ -169,7 +169,7 @@ int armv7a_read_ttbcr(struct target *target) armv7a->armv7a_mmu.ttbr_mask[0] = 7 << (32 - ttbcr_n); } - LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32, + LOG_TARGET_DEBUG(target, "ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32, (ttbcr_n != 0) ? "used" : "not used", armv7a->armv7a_mmu.ttbr_mask[0], armv7a->armv7a_mmu.ttbr_mask[1]); @@ -186,7 +186,7 @@ int armv7a_handle_cache_info_command(struct command_invocation *cmd, int cl; - if (armv7a_cache->info == -1) { + if (!armv7a_cache->info_valid) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } @@ -248,14 +248,13 @@ static int armv7a_read_mpidr(struct target *target) /* Is register in Multiprocessing Extensions register format? */ if (mpidr & MPIDR_MP_EXT) { - LOG_DEBUG("%s: MPIDR 0x%" PRIx32, target_name(target), mpidr); + LOG_TARGET_DEBUG(target, "%s: MPIDR 0x%" PRIx32, target_name(target), mpidr); armv7a->multi_processor_system = (mpidr >> 30) & 1; armv7a->multi_threading_processor = (mpidr >> 24) & 1; armv7a->level2_id = (mpidr >> 16) & 0xf; armv7a->cluster_id = (mpidr >> 8) & 0xf; armv7a->cpu_id = mpidr & 0xf; - LOG_INFO("%s: MPIDR level2 %x, cluster %x, core %x, %s, %s", - target_name(target), + LOG_TARGET_INFO(target, "MPIDR level2 %x, cluster %x, core %x, %s, %s", armv7a->level2_id, armv7a->cluster_id, armv7a->cpu_id, @@ -263,7 +262,7 @@ static int armv7a_read_mpidr(struct target *target) armv7a->multi_threading_processor == 1 ? "SMT" : "no SMT"); } else - LOG_ERROR("MPIDR not in multiprocessor format"); + LOG_TARGET_DEBUG(target, "MPIDR not in multiprocessor format"); done: dpm->finish(dpm); @@ -338,7 +337,7 @@ int armv7a_identify_cache(struct target *target) cache->iminline = 4UL << (ctr & 0xf); cache->dminline = 4UL << ((ctr & 0xf0000) >> 16); - LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRIu32 " ctr.dminline %" PRIu32, + LOG_TARGET_DEBUG(target, "ctr %" PRIx32 " ctr.iminline %" PRIu32 " ctr.dminline %" PRIu32, ctr, cache->iminline, cache->dminline); /* retrieve CLIDR @@ -350,7 +349,7 @@ int armv7a_identify_cache(struct target *target) goto done; cache->loc = (clidr & 0x7000000) >> 24; - LOG_DEBUG("Number of cache levels to PoC %" PRId32, cache->loc); + LOG_TARGET_DEBUG(target, "Number of cache levels to PoC %" PRId32, cache->loc); /* retrieve selected cache for later restore * MRC p15, 2,, c0, c0, 0; Read CSSELR */ @@ -378,13 +377,13 @@ int armv7a_identify_cache(struct target *target) goto done; cache->arch[cl].d_u_size = decode_cache_reg(cache_reg); - LOG_DEBUG("data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, + LOG_TARGET_DEBUG(target, "data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, cache->arch[cl].d_u_size.index, cache->arch[cl].d_u_size.index_shift, cache->arch[cl].d_u_size.way, cache->arch[cl].d_u_size.way_shift); - LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", + LOG_TARGET_DEBUG(target, "cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", cache->arch[cl].d_u_size.linelen, cache->arch[cl].d_u_size.cachesize, cache->arch[cl].d_u_size.associativity); @@ -398,13 +397,13 @@ int armv7a_identify_cache(struct target *target) goto done; cache->arch[cl].i_size = decode_cache_reg(cache_reg); - LOG_DEBUG("instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, + LOG_TARGET_DEBUG(target, "instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, cache->arch[cl].i_size.index, cache->arch[cl].i_size.index_shift, cache->arch[cl].i_size.way, cache->arch[cl].i_size.way_shift); - LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", + LOG_TARGET_DEBUG(target, "cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", cache->arch[cl].i_size.linelen, cache->arch[cl].i_size.cachesize, cache->arch[cl].i_size.associativity); @@ -427,7 +426,7 @@ int armv7a_identify_cache(struct target *target) armv7a_cache_flush_all_data; } - armv7a->armv7a_mmu.armv7a_cache.info = 1; + armv7a->armv7a_mmu.armv7a_cache.info_valid = true; done: dpm->finish(dpm); armv7a_read_mpidr(target); @@ -445,7 +444,7 @@ static int armv7a_setup_semihosting(struct target *target, int enable) armv7a->debug_base + CPUDBG_VCR, &vcr); if (ret < 0) { - LOG_ERROR("Failed to read VCR register\n"); + LOG_TARGET_ERROR(target, "Failed to read VCR register"); return ret; } @@ -458,7 +457,7 @@ static int armv7a_setup_semihosting(struct target *target, int enable) armv7a->debug_base + CPUDBG_VCR, vcr); if (ret < 0) - LOG_ERROR("Failed to write VCR register\n"); + LOG_TARGET_ERROR(target, "Failed to write VCR register"); return ret; } @@ -473,7 +472,7 @@ int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a) armv7a->arm.target = target; armv7a->arm.common_magic = ARM_COMMON_MAGIC; armv7a->common_magic = ARMV7_COMMON_MAGIC; - armv7a->armv7a_mmu.armv7a_cache.info = -1; + armv7a->armv7a_mmu.armv7a_cache.info_valid = false; armv7a->armv7a_mmu.armv7a_cache.outer_cache = NULL; armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = NULL; return ERROR_OK; @@ -481,29 +480,25 @@ int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a) int armv7a_arch_state(struct target *target) { - static const char *state[] = { - "disabled", "enabled" - }; - struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; if (armv7a->common_magic != ARMV7_COMMON_MAGIC) { - LOG_ERROR("BUG: called for a non-ARMv7A target"); + LOG_TARGET_ERROR(target, "BUG: called for a non-ARMv7A target"); return ERROR_COMMAND_SYNTAX_ERROR; } arm_arch_state(target); if (armv7a->is_armv7r) { - LOG_USER("D-Cache: %s, I-Cache: %s", - state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled], - state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]); + LOG_TARGET_USER(target, "D-Cache: %s, I-Cache: %s", + str_enabled_disabled(armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled), + str_enabled_disabled(armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled)); } else { - LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", - state[armv7a->armv7a_mmu.mmu_enabled], - state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled], - state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]); + LOG_TARGET_USER(target, "MMU: %s, D-Cache: %s, I-Cache: %s", + str_enabled_disabled(armv7a->armv7a_mmu.mmu_enabled), + str_enabled_disabled(armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled), + str_enabled_disabled(armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled)); } if (arm->core_mode == ARM_MODE_ABT) diff --git a/src/target/armv7a.h b/src/target/armv7a.h index 2706c4629b..188751c823 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -58,13 +58,13 @@ struct armv7a_arch_cache { /* common cache information */ struct armv7a_cache_common { - int info; /* -1 invalid, else valid */ + bool info_valid; int loc; /* level of coherency */ uint32_t dminline; /* minimum d-cache linelen */ uint32_t iminline; /* minimum i-cache linelen */ struct armv7a_arch_cache arch[6]; /* cache info, L1 - L7 */ - int i_cache_enabled; - int d_u_cache_enabled; + bool i_cache_enabled; + bool d_u_cache_enabled; /* outer unified cache if some */ struct armv7a_l2x_cache *outer_cache; int (*flush_all_data_cache)(struct target *target); @@ -72,7 +72,7 @@ struct armv7a_cache_common { struct armv7a_mmu_common { /* following field mmu working way */ - int32_t cached; /* 0: not initialized, 1: initialized */ + bool cached; uint32_t ttbcr; /* cache for ttbcr register */ uint32_t ttbr[2]; uint32_t ttbr_mask[2]; @@ -81,7 +81,7 @@ struct armv7a_mmu_common { int (*read_physical_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); struct armv7a_cache_common armv7a_cache; - uint32_t mmu_enabled; + bool mmu_enabled; }; struct armv7a_common { @@ -163,9 +163,6 @@ static inline bool is_armv7a(struct armv7a_common *armv7a) #define CPUDBG_DSCCR 0x028 #define CPUDBG_DSMCR 0x02C -/* See ARMv7a arch spec section C10.8 */ -#define CPUDBG_AUTHSTATUS 0xFB8 - /* See ARMv7a arch spec DDI 0406C C11.10 */ #define CPUDBG_ID_PFR1 0xD24 diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index f2f1097c5a..12967ea460 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -108,8 +108,7 @@ static int armv7a_l1_d_cache_clean_inval_all(struct target *target) armv7a_l1_d_cache_flush_level(dpm, &cache->arch[cl].d_u_size, cl); } - retval = dpm->finish(dpm); - return retval; + return dpm->finish(dpm); done: LOG_ERROR("clean invalidate failed"); @@ -151,9 +150,8 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; - int retval, i = 0; - retval = armv7a_l1_d_cache_sanity_check(target); + int retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; @@ -185,8 +183,7 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, } while (va_line < va_end) { - if ((i++ & 0x3f) == 0) - keep_alive(); + keep_alive(); /* DCIMVAC - Invalidate data cache line by VA to PoC. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line); @@ -215,9 +212,8 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; - int retval, i = 0; - retval = armv7a_l1_d_cache_sanity_check(target); + int retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; @@ -229,8 +225,7 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, va_end = virt + size; while (va_line < va_end) { - if ((i++ & 0x3f) == 0) - keep_alive(); + keep_alive(); /* DCCMVAC - Data Cache Clean by MVA to PoC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line); @@ -259,9 +254,8 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; - int retval, i = 0; - retval = armv7a_l1_d_cache_sanity_check(target); + int retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; @@ -273,8 +267,7 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, va_end = virt + size; while (va_line < va_end) { - if ((i++ & 0x3f) == 0) - keep_alive(); + keep_alive(); /* DCCIMVAC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line); @@ -341,9 +334,8 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->iminline; uint32_t va_line, va_end; - int retval, i = 0; - retval = armv7a_l1_i_cache_sanity_check(target); + int retval = armv7a_l1_i_cache_sanity_check(target); if (retval != ERROR_OK) return retval; @@ -355,8 +347,7 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, va_end = virt + size; while (va_line < va_end) { - if ((i++ & 0x3f) == 0) - keep_alive(); + keep_alive(); /* ICIMVAU - Invalidate instruction cache by VA to PoU. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line); diff --git a/src/target/armv7a_cache_l2x.c b/src/target/armv7a_cache_l2x.c index bc60e6d193..bdcf8cbbee 100644 --- a/src/target/armv7a_cache_l2x.c +++ b/src/target/armv7a_cache_l2x.c @@ -168,7 +168,7 @@ static int arm7a_handle_l2x_cache_info_command(struct command_invocation *cmd, { struct armv7a_l2x_cache *l2x_cache = armv7a_cache->outer_cache; - if (armv7a_cache->info == -1) { + if (!armv7a_cache->info_valid) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } diff --git a/src/target/armv7a_mmu.c b/src/target/armv7a_mmu.c index 43b5dae8ef..371e646586 100644 --- a/src/target/armv7a_mmu.c +++ b/src/target/armv7a_mmu.c @@ -73,40 +73,40 @@ int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, NS == 1 ? "not" : "", SS == 0 ? "not" : ""); switch (OUTER) { - case 0: - LOG_INFO("outer: Non-Cacheable"); - break; - case 1: - LOG_INFO("outer: Write-Back, Write-Allocate"); - break; - case 2: - LOG_INFO("outer: Write-Through, No Write-Allocate"); - break; - case 3: - LOG_INFO("outer: Write-Back, no Write-Allocate"); - break; + case 0: + LOG_INFO("outer: Non-Cacheable"); + break; + case 1: + LOG_INFO("outer: Write-Back, Write-Allocate"); + break; + case 2: + LOG_INFO("outer: Write-Through, No Write-Allocate"); + break; + case 3: + LOG_INFO("outer: Write-Back, no Write-Allocate"); + break; } switch (INNER) { - case 0: - LOG_INFO("inner: Non-Cacheable"); - break; - case 1: - LOG_INFO("inner: Strongly-ordered"); - break; - case 3: - LOG_INFO("inner: Device"); - break; - case 5: - LOG_INFO("inner: Write-Back, Write-Allocate"); - break; - case 6: - LOG_INFO("inner: Write-Through"); - break; - case 7: - LOG_INFO("inner: Write-Back, no Write-Allocate"); - break; - default: - LOG_INFO("inner: %" PRIx32 " ???", INNER); + case 0: + LOG_INFO("inner: Non-Cacheable"); + break; + case 1: + LOG_INFO("inner: Strongly-ordered"); + break; + case 3: + LOG_INFO("inner: Device"); + break; + case 5: + LOG_INFO("inner: Write-Back, Write-Allocate"); + break; + case 6: + LOG_INFO("inner: Write-Through"); + break; + case 7: + LOG_INFO("inner: Write-Back, no Write-Allocate"); + break; + default: + LOG_INFO("inner: %" PRIx32 " ???", INNER); } } @@ -214,7 +214,7 @@ COMMAND_HANDLER(armv7a_mmu_dump_table) max_pt_idx -= 1; } } else { - if (mmu->cached != 1) { + if (!mmu->cached) { LOG_ERROR("TTB not cached!"); return ERROR_FAIL; } diff --git a/src/target/armv7m.c b/src/target/armv7m.c index dc2d84fe15..6db7355304 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -139,6 +139,9 @@ static const struct { { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system", NULL, }, { ARMV7M_CONTROL, "control", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system", NULL, }, + { ARMV8M_MSPLIM, "msplim", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.m-system", NULL, }, + { ARMV8M_PSPLIM, "psplim", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.m-system", NULL, }, + /* ARMv8-M security extension (TrustZone) specific registers */ { ARMV8M_MSP_NS, "msp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, }, { ARMV8M_PSP_NS, "psp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, }, @@ -240,7 +243,6 @@ const char *armv7m_exception_string(int number) static int armv7m_get_core_reg(struct reg *reg) { - int retval; struct arm_reg *armv7m_reg = reg->arch_info; struct target *target = armv7m_reg->target; struct arm *arm = target_to_arm(target); @@ -248,9 +250,7 @@ static int armv7m_get_core_reg(struct reg *reg) if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - retval = arm->read_core_reg(target, reg, reg->number, arm->core_mode); - - return retval; + return arm->read_core_reg(target, reg, reg->number, arm->core_mode); } static int armv7m_set_core_reg(struct reg *reg, uint8_t *buf) @@ -288,6 +288,12 @@ uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id) case ARMV8M_MSP_NS...ARMV8M_PSPLIM_NS: return arm_reg_id - ARMV8M_MSP_NS + ARMV8M_REGSEL_MSP_NS; + case ARMV8M_PSPLIM: + return ARMV8M_REGSEL_PSPLIM; + + case ARMV8M_MSPLIM: + return ARMV8M_REGSEL_MSPLIM; + case ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S: return ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_S; @@ -642,9 +648,7 @@ int armv7m_start_algorithm(struct target *target, /* save previous core mode */ armv7m_algorithm_info->core_mode = core_mode; - retval = target_resume(target, false, entry_point, true, true); - - return retval; + return target_resume(target, false, entry_point, true, true); } /** Waits for an algorithm in the target. */ @@ -964,7 +968,8 @@ int armv7m_checksum_memory(struct target *target, /** Checks an array of memory regions whether they are erased. */ int armv7m_blank_check_memory(struct target *target, - struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) + struct target_memory_check_block *blocks, unsigned int num_blocks, + uint8_t erased_value, unsigned int *checked) { struct working_area *erase_check_algorithm; struct working_area *erase_check_params; @@ -1000,7 +1005,13 @@ int armv7m_blank_check_memory(struct target *target, }; uint32_t avail = target_get_working_area_avail(target); - int blocks_to_check = avail / sizeof(struct algo_block) - 1; + unsigned int avail_blocks = avail / sizeof(struct algo_block); + if (avail_blocks < 2) { + retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto cleanup1; + } + + unsigned int blocks_to_check = avail_blocks - 1; if (num_blocks < blocks_to_check) blocks_to_check = num_blocks; @@ -1010,7 +1021,7 @@ int armv7m_blank_check_memory(struct target *target, goto cleanup1; } - int i; + unsigned int i; uint32_t total_size = 0; for (i = 0; i < blocks_to_check; i++) { total_size += blocks[i].size; @@ -1080,7 +1091,7 @@ int armv7m_blank_check_memory(struct target *target, LOG_TARGET_INFO(target, "Slow CPU clock: %d blocks checked, %d remain. Continuing...", i, num_blocks - i); - retval = i; /* return number of blocks really checked */ + *checked = i; /* return number of blocks really checked */ cleanup4: destroy_reg_param(®_params[0]); diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 86c45f7f26..14c2da4602 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -15,6 +15,7 @@ #define OPENOCD_TARGET_ARMV7M_H #include "arm.h" +#include "armv7m_cache.h" #include "armv7m_trace.h" struct adiv5_ap; @@ -58,6 +59,8 @@ enum { ARMV8M_REGSEL_PSPLIM_S, ARMV8M_REGSEL_MSPLIM_NS, ARMV8M_REGSEL_PSPLIM_NS, + ARMV8M_REGSEL_MSPLIM = ARMV8M_REGSEL_MSPLIM_NS, + ARMV8M_REGSEL_PSPLIM = ARMV8M_REGSEL_PSPLIM_NS, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL = 0x14, ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_S = 0x22, @@ -149,6 +152,8 @@ enum { /* The end of block of container and contained registers */ /* ARMv8-M specific registers */ + ARMV8M_MSPLIM, + ARMV8M_PSPLIM, ARMV8M_MSP_NS, ARMV8M_PSP_NS, ARMV8M_MSP_S, @@ -206,8 +211,8 @@ enum { ARMV7M_CORE_LAST_REG = ARMV7M_XPSR, ARMV7M_FPU_FIRST_REG = ARMV7M_D0, ARMV7M_FPU_LAST_REG = ARMV8M_VPR, - ARMV8M_FIRST_REG = ARMV8M_MSP_NS, - ARMV8M_LAST_REG = ARMV8M_CONTROL_NS, + ARMV8M_TZ_FIRST_REG = ARMV8M_MSP_NS, + ARMV8M_TZ_LAST_REG = ARMV8M_CONTROL_NS, }; enum { @@ -239,6 +244,8 @@ struct armv7m_common { /* hla_target uses a high level adapter that does not support all functions */ bool is_hla_target; + struct armv7m_cache_common armv7m_cache; + struct armv7m_trace_config trace_config; /* Direct processor core register read and writes */ @@ -346,7 +353,8 @@ bool armv7m_map_reg_packing(unsigned int arm_reg_id, 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, - struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); + struct target_memory_check_block *blocks, unsigned int num_blocks, + uint8_t erased_value, unsigned int *checked); int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found); diff --git a/src/target/armv7m_cache.c b/src/target/armv7m_cache.c new file mode 100644 index 0000000000..7a2d8a4145 --- /dev/null +++ b/src/target/armv7m_cache.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2025 by STMicroelectronics + * Copyright (C) 2025 by Antonio Borneo + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int get_cache_info(struct adiv5_ap *ap, unsigned int cl, + unsigned int ind, uint32_t *ccsidr) +{ + uint32_t csselr = FIELD_PREP(CSSELR_LEVEL_MASK, cl) + | FIELD_PREP(CSSELR_IND_MASK, ind); + + int retval = mem_ap_write_u32(ap, CSSELR, csselr); + if (retval != ERROR_OK) + return retval; + + return mem_ap_read_u32(ap, CCSIDR, ccsidr); +} + +static int get_d_u_cache_info(struct adiv5_ap *ap, unsigned int cl, + uint32_t *ccsidr) +{ + return get_cache_info(ap, cl, CSSELR_IND_DATA_OR_UNIFIED_CACHE, ccsidr); +} + +static int get_i_cache_info(struct adiv5_ap *ap, unsigned int cl, + uint32_t *ccsidr) +{ + return get_cache_info(ap, cl, CSSELR_IND_INSTRUCTION_CACHE, ccsidr); +} + +static struct armv7m_cache_size decode_ccsidr(uint32_t ccsidr) +{ + struct armv7m_cache_size size; + + size.line_len = 16 << FIELD_GET(CCSIDR_LINESIZE_MASK, ccsidr); + size.associativity = FIELD_GET(CCSIDR_ASSOCIATIVITY_MASK, ccsidr) + 1; + size.num_sets = FIELD_GET(CCSIDR_NUMSETS_MASK, ccsidr) + 1; + size.cache_size = size.line_len * size.associativity * size.num_sets / 1024; + + // compute info for set way operation on cache + size.index_shift = FIELD_GET(CCSIDR_LINESIZE_MASK, ccsidr) + 2; + size.index = FIELD_GET(CCSIDR_NUMSETS_MASK, ccsidr); + size.way = FIELD_GET(CCSIDR_ASSOCIATIVITY_MASK, ccsidr); + + unsigned int i = 0; + while (((size.way << i) & 0x80000000) == 0) + i++; + size.way_shift = i; + + return size; +} + +static int armv7m_identify_cache_internal(struct target *target) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_cache_common *cache = &armv7m->armv7m_cache; + + uint32_t clidr; + int retval = mem_ap_read_u32(armv7m->debug_ap, CLIDR, &clidr); + if (retval != ERROR_OK) + return retval; + + uint32_t ctr; + retval = mem_ap_read_u32(armv7m->debug_ap, CTR, &ctr); + if (retval != ERROR_OK) + return retval; + + // retrieve selected cache for later restore + uint32_t csselr; + retval = mem_ap_read_atomic_u32(armv7m->debug_ap, CSSELR, &csselr); + if (retval != ERROR_OK) + return retval; + + if (clidr == 0) { + LOG_TARGET_DEBUG(target, "No cache detected"); + return ERROR_OK; + } + + if (FIELD_GET(CTR_FORMAT_MASK, ctr) != CTR_FORMAT_PROVIDED) { + LOG_ERROR("Wrong value in CTR register"); + return ERROR_FAIL; + } + + cache->i_min_line_len = 4UL << FIELD_GET(CTR_IMINLINE_MASK, ctr); + cache->d_min_line_len = 4UL << FIELD_GET(CTR_DMINLINE_MASK, ctr); + LOG_TARGET_DEBUG(target, + "ctr=0x%" PRIx32 " ctr.i_min_line_len=%" PRIu32 " ctr.d_min_line_len=%" PRIu32, + ctr, cache->i_min_line_len, cache->d_min_line_len); + + cache->loc = FIELD_GET(CLIDR_LOC_MASK, clidr); + LOG_TARGET_DEBUG(target, + "clidr=0x%" PRIx32 " Number of cache levels to PoC=%" PRIu32, + clidr, cache->loc); + + // retrieve all available inner caches + uint32_t d_u_ccsidr[8] = {0}, i_ccsidr[8] = {0}; + for (unsigned int cl = 0; cl < cache->loc; cl++) { + unsigned int ctype = FIELD_GET(CLIDR_CTYPE_MASK(cl + 1), clidr); + + // skip reserved values + if (ctype > CLIDR_CTYPE_UNIFIED_CACHE) + continue; + + cache->arch[cl].ctype = ctype; + + // separate d or unified d/i cache at this level ? + if (ctype & (CLIDR_CTYPE_UNIFIED_CACHE | CLIDR_CTYPE_D_CACHE)) { + // retrieve d-cache info + retval = get_d_u_cache_info(armv7m->debug_ap, cl, &d_u_ccsidr[cl]); + if (retval != ERROR_OK) + break; + } + + if (ctype & CLIDR_CTYPE_I_CACHE) { + // retrieve i-cache info + retval = get_i_cache_info(armv7m->debug_ap, cl, &i_ccsidr[cl]); + if (retval != ERROR_OK) + break; + } + } + + // restore selected cache + int retval1 = mem_ap_write_atomic_u32(armv7m->debug_ap, CSSELR, csselr); + + if (retval != ERROR_OK) + return retval; + if (retval1 != ERROR_OK) + return retval1; + + for (unsigned int cl = 0; cl < cache->loc; cl++) { + unsigned int ctype = cache->arch[cl].ctype; + + // separate d or unified d/i cache at this level ? + if (ctype & (CLIDR_CTYPE_UNIFIED_CACHE | CLIDR_CTYPE_D_CACHE)) { + cache->has_d_u_cache = true; + cache->arch[cl].d_u_size = decode_ccsidr(d_u_ccsidr[cl]); + + LOG_TARGET_DEBUG(target, + "data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, + cache->arch[cl].d_u_size.index, + cache->arch[cl].d_u_size.index_shift, + cache->arch[cl].d_u_size.way, + cache->arch[cl].d_u_size.way_shift); + + LOG_TARGET_DEBUG(target, + "cache line %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", + cache->arch[cl].d_u_size.line_len, + cache->arch[cl].d_u_size.cache_size, + cache->arch[cl].d_u_size.associativity); + } + + if (ctype & CLIDR_CTYPE_I_CACHE) { + cache->has_i_cache = true; + cache->arch[cl].i_size = decode_ccsidr(i_ccsidr[cl]); + + LOG_TARGET_DEBUG(target, + "instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, + cache->arch[cl].i_size.index, + cache->arch[cl].i_size.index_shift, + cache->arch[cl].i_size.way, + cache->arch[cl].i_size.way_shift); + + LOG_TARGET_DEBUG(target, + "cache line %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", + cache->arch[cl].i_size.line_len, + cache->arch[cl].i_size.cache_size, + cache->arch[cl].i_size.associativity); + } + } + + cache->info_valid = true; + + return ERROR_OK; +} + +/* + * On Cortex-M7 and Cortex-M85, when the CPU is kept in reset, several + * registers of the System Control Space (SCS) are not accessible and + * return bus error. + * The list of accessible registers for Cortex-M7 is: + * - 0xE000ED00 + * - 0xE000ED30 + * - 0xE000EDF0 ... 0xE000EEFC + * - 0xE000EF40 ... 0xE000EF48 + * - 0xE000EFD0 ... 0xE000EFFC + * The list of accessible registers for Cortex-M85 is: + * - 0xE000ED00 + * - 0xE000ED30 + * - 0xE000ED40 ... 0xE000ED80 + * - 0xE000EDF0 ... 0xE000EEFC + * - 0xE000EF40 ... 0xE000EF4C + * - 0xE000EFB0 ... 0xE000EFFC + * This makes impossible detecting the cache during the reset. + * Use a deferred mechanism to detect the cache during polling or when the + * CPU halts. + */ +int armv7m_identify_cache(struct target *target) +{ + struct cortex_m_common *cortex_m = target_to_cm(target); + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_cache_common *cache = &armv7m->armv7m_cache; + enum cortex_m_impl_part part = cortex_m->core_info->impl_part; + + if (cache->info_valid) + return ERROR_OK; + + if ((part == CORTEX_M7_PARTNO || part == CORTEX_M85_PARTNO) + && cortex_m->dcb_dhcsr & S_RESET_ST) { + cache->defer_identification = true; + return ERROR_OK; + } + + return armv7m_identify_cache_internal(target); +} + +int armv7m_deferred_identify_cache(struct target *target) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_cache_common *cache = &armv7m->armv7m_cache; + + if (cache->info_valid || !cache->defer_identification) + return ERROR_OK; + + int retval = armv7m_identify_cache_internal(target); + if (retval != ERROR_OK) + return retval; + + cache->defer_identification = false; + + return ERROR_OK; +} + +int armv7m_d_cache_flush(struct target *target, uint32_t address, + unsigned int length) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_cache_common *cache = &armv7m->armv7m_cache; + + if (!cache->info_valid || !cache->has_d_u_cache) + return ERROR_OK; + + uint32_t line_len = cache->d_min_line_len; + uint32_t addr_line = ALIGN_DOWN(address, line_len); + uint32_t addr_end = address + length; + + while (addr_line < addr_end) { + int retval = mem_ap_write_u32(armv7m->debug_ap, DCCIMVAC, addr_line); + if (retval != ERROR_OK) + return retval; + addr_line += line_len; + keep_alive(); + } + + return dap_run(armv7m->debug_ap->dap); +} + +int armv7m_i_cache_inval(struct target *target, uint32_t address, + unsigned int length) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_cache_common *cache = &armv7m->armv7m_cache; + + if (!cache->info_valid || !cache->has_i_cache) + return ERROR_OK; + + uint32_t line_len = cache->i_min_line_len; + uint32_t addr_line = ALIGN_DOWN(address, line_len); + uint32_t addr_end = address + length; + + while (addr_line < addr_end) { + int retval = mem_ap_write_u32(armv7m->debug_ap, ICIMVAU, addr_line); + if (retval != ERROR_OK) + return retval; + addr_line += line_len; + keep_alive(); + } + + return dap_run(armv7m->debug_ap->dap); +} + +int armv7m_handle_cache_info_command(struct command_invocation *cmd, + struct target *target) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_cache_common *cache = &armv7m->armv7m_cache; + + if (!target_was_examined(target)) { + command_print(cmd, "Target not examined yet"); + return ERROR_FAIL; + } + + if (cache->defer_identification) { + command_print(cmd, "Cache not detected yet"); + return ERROR_OK; + } + + if (!cache->info_valid) { + command_print(cmd, "No cache detected"); + return ERROR_OK; + } + + for (unsigned int cl = 0; cl < cache->loc; cl++) { + struct armv7m_arch_cache *arch = &cache->arch[cl]; + + if (arch->ctype & CLIDR_CTYPE_I_CACHE) + command_print(cmd, + "L%d I-Cache: line length %" PRIu32 ", associativity %" PRIu32 + ", num sets %" PRIu32 ", cache size %" PRIu32 " KBytes", + cl + 1, + arch->i_size.line_len, + arch->i_size.associativity, + arch->i_size.num_sets, + arch->i_size.cache_size); + + if (arch->ctype & (CLIDR_CTYPE_UNIFIED_CACHE | CLIDR_CTYPE_D_CACHE)) + command_print(cmd, + "L%d %c-Cache: line length %" PRIu32 ", associativity %" PRIu32 + ", num sets %" PRIu32 ", cache size %" PRIu32 " KBytes", + cl + 1, + (arch->ctype & CLIDR_CTYPE_D_CACHE) ? 'D' : 'U', + arch->d_u_size.line_len, + arch->d_u_size.associativity, + arch->d_u_size.num_sets, + arch->d_u_size.cache_size); + } + + return ERROR_OK; +} diff --git a/src/target/armv7m_cache.h b/src/target/armv7m_cache.h new file mode 100644 index 0000000000..e6d943209c --- /dev/null +++ b/src/target/armv7m_cache.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2025 by STMicroelectronics + * Copyright (C) 2025 by Antonio Borneo + */ + +#ifndef OPENOCD_TARGET_ARMV7M_CACHE_H +#define OPENOCD_TARGET_ARMV7M_CACHE_H + +#include +#include + +#include + +struct target; + +struct armv7m_cache_size { + // cache dimensioning + uint32_t line_len; + uint32_t associativity; + uint32_t num_sets; + uint32_t cache_size; + // info for set way operation on cache + uint32_t index; + uint32_t index_shift; + uint32_t way; + uint32_t way_shift; +}; + +// information about one architecture cache at any level +struct armv7m_arch_cache { + unsigned int ctype; // cache type, CLIDR encoding + struct armv7m_cache_size d_u_size; // data cache + struct armv7m_cache_size i_size; // instruction cache +}; + +// common cache information +struct armv7m_cache_common { + bool info_valid; + bool defer_identification; + bool has_i_cache; + bool has_d_u_cache; + unsigned int loc; // level of coherency + uint32_t d_min_line_len; // minimum d-cache line_len + uint32_t i_min_line_len; // minimum i-cache line_len + struct armv7m_arch_cache arch[6]; // cache info, L1 - L7 +}; + +int armv7m_identify_cache(struct target *target); +int armv7m_deferred_identify_cache(struct target *target); +int armv7m_d_cache_flush(struct target *target, uint32_t address, + unsigned int length); +int armv7m_i_cache_inval(struct target *target, uint32_t address, + unsigned int length); +int armv7m_handle_cache_info_command(struct command_invocation *cmd, + struct target *target); + +#endif /* OPENOCD_TARGET_ARMV7M_CACHE_H */ diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c index 556568d71a..498559cbb1 100644 --- a/src/target/armv7m_trace.c +++ b/src/target/armv7m_trace.c @@ -21,7 +21,7 @@ int armv7m_trace_itm_config(struct target *target) struct armv7m_trace_config *trace_config = &armv7m->trace_config; int retval; - retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY); + retval = target_write_u32(target, ITM_LAR, ARM_CS_LAR_UNLOCK_KEY); if (retval != ERROR_OK) return retval; diff --git a/src/target/armv8.c b/src/target/armv8.c index 40390731e8..88d8eaaf81 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -14,10 +14,10 @@ #include #include "armv8.h" -#include "arm_disassembler.h" #include "register.h" #include +#include #include #include @@ -119,27 +119,27 @@ 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; + 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; } @@ -204,7 +204,9 @@ static int armv8_read_ttbcr(struct target *target) retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_TCR_EL3, 0), &ttbcr); - retval += dpm->instr_read_data_r0_64(dpm, + if (retval != ERROR_OK) + goto done; + retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_TTBR0_EL3, 0), &armv8->ttbr_base); if (retval != ERROR_OK) @@ -217,7 +219,9 @@ static int armv8_read_ttbcr(struct target *target) retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_TCR_EL2, 0), &ttbcr); - retval += dpm->instr_read_data_r0_64(dpm, + if (retval != ERROR_OK) + goto done; + retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_TTBR0_EL2, 0), &armv8->ttbr_base); if (retval != ERROR_OK) @@ -233,12 +237,14 @@ static int armv8_read_ttbcr(struct target *target) retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_TCR_EL1, 0), &ttbcr_64); + if (retval != ERROR_OK) + goto done; 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, + 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) @@ -883,12 +889,27 @@ int armv8_read_mpidr(struct armv8_common *armv8) int retval = ERROR_FAIL; struct arm *arm = &armv8->arm; struct arm_dpm *dpm = armv8->arm.dpm; - uint32_t mpidr; + uint64_t mpidr; + uint8_t multi_processor_system; + uint8_t aff3; + uint8_t aff2; + uint8_t aff1; + uint8_t aff0; + uint8_t mt; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; + /* + * TODO: BUG - routine armv8_dpm_modeswitch() doesn't re-evaluate 'arm->dpm->core_state'. + * If the core is halted in EL0 AArch32 while EL1 is in AArch64, the modeswitch moves the core + * to EL1, but there is no re-evaluation of dpm->arm->core_state. As a result, while the core + * is in AArch64, the code considers the system still in AArch32. The read of MPIDR would + * select the instruction based on the old core_state. The call to 'armv8_dpm_get_core_state()' + * below could also potentially return the incorrect execution state for the current EL. + */ + /* check if we're in an unprivileged mode */ if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) { retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); @@ -896,17 +917,39 @@ int armv8_read_mpidr(struct armv8_common *armv8) return retval; } - retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr); + retval = dpm->instr_read_data_r0_64(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr); if (retval != ERROR_OK) goto done; if (mpidr & 1U<<31) { - armv8->multi_processor_system = (mpidr >> 30) & 1; - armv8->cluster_id = (mpidr >> 8) & 0xf; - armv8->cpu_id = mpidr & 0x3; - LOG_INFO("%s cluster %x core %x %s", target_name(armv8->arm.target), - armv8->cluster_id, - armv8->cpu_id, - armv8->multi_processor_system == 0 ? "multi core" : "single core"); + multi_processor_system = (mpidr >> 30) & 1; + aff3 = (mpidr >> 32) & 0xff; + aff2 = (mpidr >> 16) & 0xff; + aff1 = (mpidr >> 8) & 0xff; + aff0 = mpidr & 0xff; + mt = (mpidr >> 24) & 0x1; + if (armv8_dpm_get_core_state(&armv8->dpm) == ARM_STATE_AARCH64) { + if (mt) + LOG_INFO("%s socket %" PRIu32 " cluster %" PRIu32 " core %" PRIu32 " thread %" PRIu32 " %s", + target_name(armv8->arm.target), + aff3, aff2, aff1, aff0, + multi_processor_system == 0 ? "multi core" : "single core"); + else + LOG_INFO("%s socket %" PRIu32 " cluster %" PRIu32 " core %" PRIu32 " %s", + target_name(armv8->arm.target), + aff3, aff1, aff0, + multi_processor_system == 0 ? "multi core" : "single core"); + } else { + if (mt) + LOG_INFO("%s cluster %" PRIu32 " core %" PRIu32 " thread %" PRIu32 " %s", + target_name(armv8->arm.target), + aff2, aff1, aff0, + multi_processor_system == 0 ? "multi core" : "single core"); + else + LOG_INFO("%s cluster %" PRIu32 " core %" PRIu32 " %s", + target_name(armv8->arm.target), + aff1, aff0, + multi_processor_system == 0 ? "multi core" : "single core"); + } } else LOG_ERROR("mpidr not in multiprocessor format"); @@ -1032,18 +1075,18 @@ static void armv8_decode_cacheability(int attr) return; } switch (attr & 0xC) { - case 0: - LOG_USER_N("Write-Through Transient"); - break; - case 0x4: - LOG_USER_N("Write-Back Transient"); - break; - case 0x8: - LOG_USER_N("Write-Through Non-transient"); - break; - case 0xC: - LOG_USER_N("Write-Back Non-transient"); - break; + case 0: + LOG_USER_N("Write-Through Transient"); + break; + case 0x4: + LOG_USER_N("Write-Back Transient"); + break; + case 0x8: + LOG_USER_N("Write-Through Non-transient"); + break; + case 0xC: + LOG_USER_N("Write-Back Non-transient"); + break; } if (attr & 2) LOG_USER_N(" Read-Allocate"); @@ -1070,18 +1113,18 @@ static void armv8_decode_memory_attr(int attr) "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; + 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"); @@ -1265,7 +1308,7 @@ COMMAND_HANDLER(armv8_pauth_command) int armv8_handle_cache_info_command(struct command_invocation *cmd, struct armv8_cache_common *armv8_cache) { - if (armv8_cache->info == -1) { + if (!armv8_cache->info_valid) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } @@ -1292,7 +1335,7 @@ int armv8_init_arch_info(struct target *target, struct armv8_common *armv8) armv8->common_magic = ARMV8_COMMON_MAGIC; armv8->armv8_mmu.armv8_cache.l2_cache = NULL; - armv8->armv8_mmu.armv8_cache.info = -1; + armv8->armv8_mmu.armv8_cache.info_valid = false; armv8->armv8_mmu.armv8_cache.flush_all_data_cache = NULL; armv8->armv8_mmu.armv8_cache.display_cache_info = NULL; return ERROR_OK; @@ -1322,10 +1365,6 @@ static int armv8_aarch64_state(struct target *target) int armv8_arch_state(struct target *target) { - static const char * const state[] = { - "disabled", "enabled" - }; - struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = &armv8->arm; @@ -1340,9 +1379,9 @@ int armv8_arch_state(struct target *target) arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", - state[armv8->armv8_mmu.mmu_enabled], - state[armv8->armv8_mmu.armv8_cache.d_u_cache_enabled], - state[armv8->armv8_mmu.armv8_cache.i_cache_enabled]); + str_enabled_disabled(armv8->armv8_mmu.mmu_enabled), + str_enabled_disabled(armv8->armv8_mmu.armv8_cache.d_u_cache_enabled), + str_enabled_disabled(armv8->armv8_mmu.armv8_cache.i_cache_enabled)); if (arm->core_mode == ARM_MODE_ABT) armv8_show_fault_registers(target); @@ -1815,7 +1854,12 @@ struct reg_cache *armv8_build_reg_cache(struct target *target) reg_list[i].group = armv8_regs[i].group; reg_list[i].number = i; reg_list[i].exist = true; - reg_list[i].caller_save = true; /* gdb defaults to true */ + + /* Registers which should be preserved across GDB inferior function calls. + * Avoid saving ELx banked registers as a standard function should + * not change them and higher EL registers are not accessible + * in lower EL modes. */ + reg_list[i].caller_save = i < ARMV8_ELR_EL1; feature = calloc(1, sizeof(struct reg_feature)); if (feature) { @@ -1878,13 +1922,10 @@ struct reg_cache *armv8_build_reg_cache(struct target *target) struct reg *armv8_reg_current(struct arm *arm, unsigned int regnum) { - struct reg *r; - if (regnum > (ARMV8_LAST_REG - 1)) return NULL; - r = arm->core_cache->reg_list + regnum; - return r; + return arm->core_cache->reg_list + regnum; } static void armv8_free_cache(struct reg_cache *cache, bool regs32) @@ -2028,7 +2069,6 @@ int armv8_set_dbgreg_bits(struct armv8_common *armv8, unsigned int reg, unsigned tmp |= value & mask; /* write new value */ - retval = mem_ap_write_atomic_u32(armv8->debug_ap, + return mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + reg, tmp); - return retval; } diff --git a/src/target/armv8.h b/src/target/armv8.h index dba12f9666..836528578e 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -151,13 +151,13 @@ struct armv8_arch_cache { }; struct armv8_cache_common { - int info; + bool info_valid; int loc; uint32_t iminline; uint32_t dminline; struct armv8_arch_cache arch[6]; /* cache info, L1 - L7 */ - int i_cache_enabled; - int d_u_cache_enabled; + bool i_cache_enabled; + bool d_u_cache_enabled; /* l2 external unified cache if some */ void *l2_cache; @@ -179,7 +179,7 @@ struct armv8_mmu_common { int (*read_physical_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); struct armv8_cache_common armv8_cache; - uint32_t mmu_enabled; + bool mmu_enabled; }; struct armv8_common { @@ -195,11 +195,6 @@ struct armv8_common { const uint32_t *opcodes; - /* mdir */ - uint8_t multi_processor_system; - uint8_t cluster_id; - uint8_t cpu_id; - /* armv8 aarch64 need below information for page translation */ uint8_t va_size; uint8_t pa_size; @@ -252,9 +247,6 @@ static inline bool is_armv8(struct armv8_common *armv8) #define CPUV8_DBG_DBGFEATURE0 0xD28 #define CPUV8_DBG_MEMFEATURE0 0xD38 -#define CPUV8_DBG_LOCKACCESS 0xFB0 -#define CPUV8_DBG_LOCKSTATUS 0xFB4 - #define CPUV8_DBG_EDESR 0x20 #define CPUV8_DBG_EDECR 0x24 #define CPUV8_DBG_EDWAR0 0x30 @@ -278,8 +270,6 @@ static inline bool is_armv8(struct armv8_common *armv8) #define CPUV8_DBG_OSLAR 0x300 -#define CPUV8_DBG_AUTHSTATUS 0xFB8 - #define PAGE_SIZE_4KB 0x1000 #define PAGE_SIZE_4KB_LEVEL0_BITS 39 #define PAGE_SIZE_4KB_LEVEL1_BITS 30 diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c index 1c251beb99..c6bd779358 100644 --- a/src/target/armv8_cache.c +++ b/src/target/armv8_cache.c @@ -92,8 +92,7 @@ static int armv8_cache_d_inner_clean_inval_all(struct armv8_common *armv8) armv8_cache_d_inner_flush_level(armv8, &cache->arch[cl].d_u_size, cl); } - retval = dpm->finish(dpm); - return retval; + return dpm->finish(dpm); done: LOG_ERROR("clean invalidate failed"); @@ -214,7 +213,7 @@ static int armv8_handle_inner_cache_info_command(struct command_invocation *cmd, { int cl; - if (armv8_cache->info == -1) { + if (!armv8_cache->info_valid) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } @@ -262,7 +261,7 @@ static int armv8_flush_all_data(struct target *target) int retval = ERROR_FAIL; /* check that armv8_cache is correctly identify */ struct armv8_common *armv8 = target_to_armv8(target); - if (armv8->armv8_mmu.armv8_cache.info == -1) { + if (!armv8->armv8_mmu.armv8_cache.info_valid) { LOG_ERROR("trying to flush un-identified cache"); return retval; } @@ -288,7 +287,7 @@ static int armv8_flush_all_instruction(struct target *target) int retval = ERROR_FAIL; /* check that armv8_cache is correctly identify */ struct armv8_common *armv8 = target_to_armv8(target); - if (armv8->armv8_mmu.armv8_cache.info == -1) { + if (!armv8->armv8_mmu.armv8_cache.info_valid) { LOG_ERROR("trying to flush un-identified cache"); return retval; } @@ -459,7 +458,7 @@ int armv8_identify_cache(struct armv8_common *armv8) if (retval != ERROR_OK) goto done; - armv8->armv8_mmu.armv8_cache.info = 1; + armv8->armv8_mmu.armv8_cache.info_valid = true; /* if no l2 cache initialize l1 data cache flush function function */ if (!armv8->armv8_mmu.armv8_cache.flush_all_data_cache) { diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index d1cee8a10c..508ec973e3 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -426,17 +426,17 @@ static int dpmv8_bpwp_enable(struct arm_dpm *dpm, unsigned int index_t, int retval; switch (index_t) { - case 0 ... 15: /* breakpoints */ - vr += CPUV8_DBG_BVR_BASE; - cr += CPUV8_DBG_BCR_BASE; - break; - case 16 ... 31: /* watchpoints */ - vr += CPUV8_DBG_WVR_BASE; - cr += CPUV8_DBG_WCR_BASE; - index_t -= 16; - break; - default: - return ERROR_FAIL; + case 0 ... 15: /* breakpoints */ + vr += CPUV8_DBG_BVR_BASE; + cr += CPUV8_DBG_BCR_BASE; + break; + case 16 ... 31: /* watchpoints */ + vr += CPUV8_DBG_WVR_BASE; + cr += CPUV8_DBG_WCR_BASE; + index_t -= 16; + break; + default: + return ERROR_FAIL; } vr += 16 * index_t; cr += 16 * index_t; @@ -456,15 +456,15 @@ static int dpmv8_bpwp_disable(struct arm_dpm *dpm, unsigned int index_t) uint32_t cr; switch (index_t) { - case 0 ... 15: - cr = armv8->debug_base + CPUV8_DBG_BCR_BASE; - break; - case 16 ... 31: - cr = armv8->debug_base + CPUV8_DBG_WCR_BASE; - index_t -= 16; - break; - default: - return ERROR_FAIL; + case 0 ... 15: + cr = armv8->debug_base + CPUV8_DBG_BCR_BASE; + break; + case 16 ... 31: + cr = armv8->debug_base + CPUV8_DBG_WCR_BASE; + index_t -= 16; + break; + default: + return ERROR_FAIL; } cr += 16 * index_t; @@ -542,6 +542,8 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) unsigned int target_el; enum arm_state core_state; uint32_t cpsr; + uint32_t rw = (dpm->dscr >> 10) & 0xF; + uint32_t ns = (dpm->dscr >> 18) & 0x1; /* restore previous mode */ if (mode == ARM_MODE_ANY) { @@ -564,7 +566,11 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) case ARM_MODE_IRQ: case ARM_MODE_FIQ: case ARM_MODE_SYS: - target_el = 1; + /* For Secure, EL1 if EL3 is aarch64, EL3 if EL3 is aarch32 */ + if (ns || (rw & (1 << 3))) + target_el = 1; + else + target_el = 3; break; /* * TODO: handle ARM_MODE_HYP @@ -598,8 +604,8 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) } else { core_state = armv8_dpm_get_core_state(dpm); if (core_state != ARM_STATE_AARCH64) { - /* cannot do DRPS/ERET when already in EL0 */ - if (dpm->last_el != 0) { + /* cannot do DRPS/ERET when in EL0 or in SYS mode */ + if (dpm->last_el != 0 && dpm->arm->core_mode != ARM_MODE_SYS) { /* load SPSR with the desired mode and execute DRPS */ LOG_DEBUG("SPSR = 0x%08"PRIx32, cpsr); retval = dpm->instr_write_data_r0(dpm, @@ -1121,26 +1127,26 @@ static int dpmv8_bpwp_setup(struct arm_dpm *dpm, struct dpm_bpwp *xp, * v7 hardware, unaligned 4-byte ones too. */ switch (length) { - case 1: - control |= (1 << (addr & 3)) << 5; + case 1: + control |= (1 << (addr & 3)) << 5; + break; + case 2: + /* require 2-byte alignment */ + if (!(addr & 1)) { + control |= (3 << (addr & 2)) << 5; break; - case 2: - /* require 2-byte alignment */ - if (!(addr & 1)) { - control |= (3 << (addr & 2)) << 5; - break; - } - /* FALL THROUGH */ - case 4: - /* require 4-byte alignment */ - if (!(addr & 3)) { - control |= 0xf << 5; - break; - } - /* FALL THROUGH */ - default: - LOG_ERROR("unsupported {break,watch}point length/alignment"); - return ERROR_COMMAND_SYNTAX_ERROR; + } + /* FALL THROUGH */ + case 4: + /* require 4-byte alignment */ + if (!(addr & 3)) { + control |= 0xf << 5; + break; + } + /* FALL THROUGH */ + default: + LOG_ERROR("unsupported {break,watch}point length/alignment"); + return ERROR_COMMAND_SYNTAX_ERROR; } /* other shared control bits: @@ -1227,15 +1233,15 @@ static int dpmv8_watchpoint_setup(struct arm_dpm *dpm, unsigned int index_t, control = dwp->bpwp.control; switch (wp->rw) { - case WPT_READ: - control |= 1 << 3; - break; - case WPT_WRITE: - control |= 2 << 3; - break; - case WPT_ACCESS: - control |= 3 << 3; - break; + case WPT_READ: + control |= 1 << 3; + break; + case WPT_WRITE: + control |= 2 << 3; + break; + case WPT_ACCESS: + control |= 3 << 3; + break; } dwp->bpwp.control = control; @@ -1357,31 +1363,31 @@ void armv8_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr) /* Examine debug reason */ switch (DSCR_ENTRY(dscr)) { - /* FALL THROUGH -- assume a v6 core in abort mode */ - case DSCRV8_ENTRY_EXT_DEBUG: /* EDBGRQ */ - target->debug_reason = DBG_REASON_DBGRQ; - break; - case DSCRV8_ENTRY_HALT_STEP_EXECLU: /* HALT step */ - case DSCRV8_ENTRY_HALT_STEP_NORMAL: /* Halt step*/ - case DSCRV8_ENTRY_HALT_STEP: - target->debug_reason = DBG_REASON_SINGLESTEP; - break; - case DSCRV8_ENTRY_HLT: /* HLT instruction (software breakpoint) */ - case DSCRV8_ENTRY_BKPT: /* SW BKPT (?) */ - case DSCRV8_ENTRY_RESET_CATCH: /* Reset catch */ - case DSCRV8_ENTRY_OS_UNLOCK: /*OS unlock catch*/ - case DSCRV8_ENTRY_SW_ACCESS_DBG: /*SW access dbg register*/ - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case DSCRV8_ENTRY_WATCHPOINT: /* asynch watchpoint */ - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case DSCRV8_ENTRY_EXCEPTION_CATCH: /*exception catch*/ - target->debug_reason = DBG_REASON_EXC_CATCH; - break; - default: - target->debug_reason = DBG_REASON_UNDEFINED; - break; + /* FALL THROUGH -- assume a v6 core in abort mode */ + case DSCRV8_ENTRY_EXT_DEBUG: /* EDBGRQ */ + target->debug_reason = DBG_REASON_DBGRQ; + break; + case DSCRV8_ENTRY_HALT_STEP_EXECLU: /* HALT step */ + case DSCRV8_ENTRY_HALT_STEP_NORMAL: /* Halt step*/ + case DSCRV8_ENTRY_HALT_STEP: + target->debug_reason = DBG_REASON_SINGLESTEP; + break; + case DSCRV8_ENTRY_HLT: /* HLT instruction (software breakpoint) */ + case DSCRV8_ENTRY_BKPT: /* SW BKPT (?) */ + case DSCRV8_ENTRY_RESET_CATCH: /* Reset catch */ + case DSCRV8_ENTRY_OS_UNLOCK: /*OS unlock catch*/ + case DSCRV8_ENTRY_SW_ACCESS_DBG: /*SW access dbg register*/ + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case DSCRV8_ENTRY_WATCHPOINT: /* asynch watchpoint */ + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case DSCRV8_ENTRY_EXCEPTION_CATCH: /*exception catch*/ + target->debug_reason = DBG_REASON_EXC_CATCH; + break; + default: + target->debug_reason = DBG_REASON_UNDEFINED; + break; } } diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index 94962c2055..a016a1ccee 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -117,7 +117,7 @@ static int avr32_write_core_reg(struct target *target, int num) reg_value = buf_get_u32(ap7k->core_cache->reg_list[num].value, 0, 32); ap7k->core_regs[num] = reg_value; - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); + LOG_DEBUG("write core reg %i value 0x%" PRIx32, num, reg_value); ap7k->core_cache->reg_list[num].valid = true; ap7k->core_cache->reg_list[num].dirty = false; @@ -126,16 +126,13 @@ static int avr32_write_core_reg(struct target *target, int num) static int avr32_get_core_reg(struct reg *reg) { - int retval; struct avr32_core_reg *avr32_reg = reg->arch_info; struct target *target = avr32_reg->target; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - retval = avr32_read_core_reg(target, avr32_reg->num); - - return retval; + return avr32_read_core_reg(target, avr32_reg->num); } static int avr32_set_core_reg(struct reg *reg, uint8_t *buf) @@ -337,7 +334,7 @@ static int avr32_ap7k_resume(struct target *target, bool current, /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { - LOG_DEBUG("unset breakpoint at 0x%8.8" TARGET_PRIxADDR "", breakpoint->address); + LOG_DEBUG("unset breakpoint at 0x%8.8" TARGET_PRIxADDR, breakpoint->address); #if 0 avr32_ap7k_unset_breakpoint(target, breakpoint); avr32_ap7k_single_step_core(target); @@ -372,11 +369,11 @@ static int avr32_ap7k_resume(struct target *target, bool current, if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); + 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); + LOG_DEBUG("target debug resumed at 0x%" PRIx32, resume_pc); } return ERROR_OK; @@ -425,7 +422,7 @@ static int avr32_ap7k_read_memory(struct target *target, target_addr_t address, { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); - LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); @@ -443,18 +440,18 @@ static int avr32_ap7k_read_memory(struct target *target, target_addr_t address, return ERROR_TARGET_UNALIGNED_ACCESS; switch (size) { - case 4: - return avr32_jtag_read_memory32(&ap7k->jtag, address, count, - (uint32_t *)(void *)buffer); - break; - case 2: - return avr32_jtag_read_memory16(&ap7k->jtag, address, count, - (uint16_t *)(void *)buffer); - break; - case 1: - return avr32_jtag_read_memory8(&ap7k->jtag, address, count, buffer); - default: - break; + case 4: + return avr32_jtag_read_memory32(&ap7k->jtag, address, count, + (uint32_t *)(void *)buffer); + break; + case 2: + return avr32_jtag_read_memory16(&ap7k->jtag, address, count, + (uint16_t *)(void *)buffer); + break; + case 1: + return avr32_jtag_read_memory8(&ap7k->jtag, address, count, buffer); + default: + break; } return ERROR_OK; @@ -465,7 +462,7 @@ static int avr32_ap7k_write_memory(struct target *target, target_addr_t address, { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); - LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); @@ -483,18 +480,18 @@ static int avr32_ap7k_write_memory(struct target *target, target_addr_t address, return ERROR_TARGET_UNALIGNED_ACCESS; switch (size) { - case 4: - return avr32_jtag_write_memory32(&ap7k->jtag, address, count, - (uint32_t *)(void *)buffer); - break; - case 2: - return avr32_jtag_write_memory16(&ap7k->jtag, address, count, - (uint16_t *)(void *)buffer); - break; - case 1: - return avr32_jtag_write_memory8(&ap7k->jtag, address, count, buffer); - default: - break; + case 4: + return avr32_jtag_write_memory32(&ap7k->jtag, address, count, + (uint32_t *)(void *)buffer); + break; + case 2: + return avr32_jtag_write_memory16(&ap7k->jtag, address, count, + (uint16_t *)(void *)buffer); + break; + case 1: + return avr32_jtag_write_memory8(&ap7k->jtag, address, count, buffer); + default: + break; } return ERROR_OK; @@ -527,7 +524,6 @@ static int avr32_ap7k_examine(struct target *target) struct avr32_ap7k_common *ap7k = target_to_ap7k(target); if (!target_was_examined(target)) { - target_set_examined(target); avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DID, &devid); LOG_INFO("device id: %08" PRIx32, devid); avr32_ocd_setbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBE); @@ -548,7 +544,7 @@ static int avr32_ap7k_arch_state(struct target *target) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); - LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "", + LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32, debug_reason_name(target), ap7k->jtag.dpc); return ERROR_OK; diff --git a/src/target/avr32_regs.c b/src/target/avr32_regs.c index d6fd0e0020..4070e2570f 100644 --- a/src/target/avr32_regs.c +++ b/src/target/avr32_regs.c @@ -31,10 +31,7 @@ static int avr32_jtag_read_reg(struct avr32_jtag *jtag_info, int reg, return retval; } while (!(dcsr & OCDREG_DCSR_CPUD)); - retval = avr32_jtag_nexus_read(jtag_info, - AVR32_OCDREG_DCCPU, val); - - return retval; + return avr32_jtag_nexus_read(jtag_info, AVR32_OCDREG_DCCPU, val); } static int avr32_jtag_write_reg(struct avr32_jtag *jtag_info, int reg, @@ -75,9 +72,7 @@ int avr32_jtag_read_regs(struct avr32_jtag *jtag_info, uint32_t *regs) if (retval != ERROR_OK) return retval; - retval = avr32_jtag_read_reg(jtag_info, 0, regs + AVR32_REG_SR); - - return retval; + return avr32_jtag_read_reg(jtag_info, 0, regs + AVR32_REG_SR); } int avr32_jtag_write_regs(struct avr32_jtag *jtag_info, uint32_t *regs) diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 55f8e0baa5..2c46cd3a65 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -15,8 +15,8 @@ #include "target.h" #include #include "breakpoints.h" -#include "rtos/rtos.h" #include "smp.h" +#include "helper/util.h" enum breakpoint_watchpoint { BREAKPOINT, @@ -55,13 +55,20 @@ static int breakpoint_add_internal(struct target *target, */ LOG_TARGET_ERROR(target, "Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")", address, breakpoint->unique_id); - return ERROR_TARGET_DUPLICATE_BREAKPOINT; + return ERROR_BREAKPOINT_DUPLICATED; + } + if (type == BKPT_SOFT && + is_memory_regions_overlap(address, length, breakpoint->address, breakpoint->length)) { + LOG_TARGET_ERROR(target, "Breakpoint overlaps another one at " TARGET_ADDR_FMT + " of length %u (BP %" PRIu32 ")", breakpoint->address, + breakpoint->length, breakpoint->unique_id); + return ERROR_BREAKPOINT_OVERLAPPED; } breakpoint_p = &breakpoint->next; breakpoint = breakpoint->next; } - (*breakpoint_p) = calloc(1, sizeof(struct breakpoint)); + (*breakpoint_p) = malloc(sizeof(struct breakpoint)); (*breakpoint_p)->address = address; (*breakpoint_p)->asid = 0; (*breakpoint_p)->length = length; @@ -73,22 +80,22 @@ static int breakpoint_add_internal(struct target *target, retval = target_add_breakpoint(target, *breakpoint_p); switch (retval) { - case ERROR_OK: - break; - case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: - reason = "resource not available"; - goto fail; - case ERROR_TARGET_NOT_HALTED: - reason = "target not halted"; - goto fail; - default: - reason = "unknown reason"; + case ERROR_OK: + break; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + reason = "resource not available"; + goto fail; + case ERROR_TARGET_NOT_HALTED: + reason = "target not halted"; + goto fail; + default: + reason = "unknown reason"; fail: - LOG_TARGET_ERROR(target, "can't add breakpoint: %s", reason); - free((*breakpoint_p)->orig_instr); - free(*breakpoint_p); - *breakpoint_p = NULL; - return retval; + LOG_TARGET_ERROR(target, "can't add breakpoint: %s", reason); + free((*breakpoint_p)->orig_instr); + free(*breakpoint_p); + *breakpoint_p = NULL; + return retval; } LOG_TARGET_DEBUG(target, "added %s breakpoint at " TARGET_ADDR_FMT @@ -117,13 +124,13 @@ static int context_breakpoint_add_internal(struct target *target, */ LOG_TARGET_ERROR(target, "Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")", asid, breakpoint->unique_id); - return ERROR_TARGET_DUPLICATE_BREAKPOINT; + return ERROR_BREAKPOINT_DUPLICATED; } breakpoint_p = &breakpoint->next; breakpoint = breakpoint->next; } - (*breakpoint_p) = calloc(1, sizeof(struct breakpoint)); + (*breakpoint_p) = malloc(sizeof(struct breakpoint)); (*breakpoint_p)->address = 0; (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; @@ -167,17 +174,17 @@ static int hybrid_breakpoint_add_internal(struct target *target, */ LOG_TARGET_ERROR(target, "Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")", asid, breakpoint->unique_id); - return ERROR_TARGET_DUPLICATE_BREAKPOINT; + return ERROR_BREAKPOINT_DUPLICATED; } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) { LOG_TARGET_ERROR(target, "Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")", address, breakpoint->unique_id); - return ERROR_TARGET_DUPLICATE_BREAKPOINT; + return ERROR_BREAKPOINT_DUPLICATED; } breakpoint_p = &breakpoint->next; breakpoint = breakpoint->next; } - (*breakpoint_p) = calloc(1, sizeof(struct breakpoint)); + (*breakpoint_p) = malloc(sizeof(struct breakpoint)); (*breakpoint_p)->address = address; (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; @@ -215,8 +222,6 @@ int breakpoint_add(struct target *target, struct target_list *list_node; foreach_smp_target(list_node, target->smp_targets) { struct target *curr = list_node->target; - if (curr->state == TARGET_UNAVAILABLE) - continue; int retval = breakpoint_add_internal(curr, address, length, type); if (retval != ERROR_OK) return retval; @@ -224,8 +229,6 @@ int breakpoint_add(struct target *target, return ERROR_OK; } else { - /* For software breakpoints on SMP targets, only set them on a - * single target. We assume that SMP targets share memory. */ return breakpoint_add_internal(target, address, length, type); } } @@ -240,8 +243,6 @@ int context_breakpoint_add(struct target *target, foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; - if (curr->state == TARGET_UNAVAILABLE) - continue; int retval = context_breakpoint_add_internal(curr, asid, length, type); if (retval != ERROR_OK) return retval; @@ -264,8 +265,6 @@ int hybrid_breakpoint_add(struct target *target, foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; - if (curr->state == TARGET_UNAVAILABLE) - continue; int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); if (retval != ERROR_OK) return retval; @@ -276,17 +275,11 @@ int hybrid_breakpoint_add(struct target *target, return hybrid_breakpoint_add_internal(target, address, asid, length, type); } -/* Free the data structures we use to track a breakpoint on data_target. - * Remove the actual breakpoint from breakpoint_target. - * This separation is useful when a software breakpoint is tracked on a target - * that is currently unavailable, but the breakpoint also affects a target that - * is available. - */ -static int breakpoint_free(struct target *data_target, struct target *breakpoint_target, - struct breakpoint *breakpoint_to_remove) +/* free up a breakpoint */ +static int breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove) { - struct breakpoint *breakpoint = data_target->breakpoints; - struct breakpoint **breakpoint_p = &data_target->breakpoints; + struct breakpoint *breakpoint = target->breakpoints; + struct breakpoint **breakpoint_p = &target->breakpoints; int retval; while (breakpoint) { @@ -297,16 +290,16 @@ static int breakpoint_free(struct target *data_target, struct target *breakpoint } if (!breakpoint) - return ERROR_BREAKPOINT_NOT_FOUND; + return ERROR_OK; - retval = target_remove_breakpoint(breakpoint_target, breakpoint); + retval = target_remove_breakpoint(target, breakpoint); if (retval != ERROR_OK) { - LOG_TARGET_ERROR(breakpoint_target, "could not remove breakpoint, BPID: %" PRIu32, - breakpoint->unique_id); + LOG_TARGET_ERROR(target, "could not remove breakpoint #%d on this target", + breakpoint->number); return retval; } - LOG_TARGET_DEBUG(data_target, "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); @@ -314,6 +307,24 @@ static int breakpoint_free(struct target *data_target, struct target *breakpoint return ERROR_OK; } +static int breakpoint_remove_internal(struct target *target, target_addr_t address) +{ + struct breakpoint *breakpoint = target->breakpoints; + + while (breakpoint) { + if ((breakpoint->address == address) || + (breakpoint->address == 0 && breakpoint->asid == address)) + break; + breakpoint = breakpoint->next; + } + + if (breakpoint) { + return breakpoint_free(target, breakpoint); + } else { + return ERROR_BREAKPOINT_NOT_FOUND; + } +} + static int breakpoint_remove_all_internal(struct target *target) { LOG_TARGET_DEBUG(target, "Delete all breakpoints"); @@ -324,7 +335,7 @@ static int breakpoint_remove_all_internal(struct target *target) while (breakpoint) { struct breakpoint *tmp = breakpoint; breakpoint = breakpoint->next; - int status = breakpoint_free(target, target, tmp); + int status = breakpoint_free(target, tmp); if (status != ERROR_OK) retval = status; } @@ -334,93 +345,41 @@ static int breakpoint_remove_all_internal(struct target *target) int breakpoint_remove(struct target *target, target_addr_t address) { - if (!target->smp) { - struct breakpoint *breakpoint = breakpoint_find(target, address); - if (breakpoint) - return breakpoint_free(target, target, breakpoint); - LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); - return ERROR_BREAKPOINT_NOT_FOUND; - } - int retval = ERROR_OK; - unsigned int found = 0; - struct target_list *head; - /* Target where we found a software breakpoint. */ - struct target *software_breakpoint_target = NULL; - struct breakpoint *software_breakpoint = NULL; - /* Target that is available. */ - struct target *available_target = NULL; - /* Target that is available and halted. */ - struct target *halted_target = NULL; - - foreach_smp_target(head, target->smp_targets) { - struct target *curr = head->target; - - if (!available_target && curr->state != TARGET_UNAVAILABLE) - available_target = curr; - if (!halted_target && curr->state == TARGET_HALTED) - halted_target = curr; - - struct breakpoint *breakpoint = breakpoint_find(curr, address); - if (!breakpoint) - continue; - - found++; - - if (breakpoint->type == BKPT_SOFT) { - /* Software breakpoints are set on only one of the SMP - * targets. We can remove them through any of the SMP - * targets. */ - if (software_breakpoint_target) { - LOG_TARGET_WARNING(curr, "Already found software breakpoint at " - TARGET_ADDR_FMT " on %s.", address, target_name(software_breakpoint_target)); - } else { - assert(!software_breakpoint_target); - software_breakpoint_target = curr; - software_breakpoint = breakpoint; + unsigned int num_found_breakpoints = 0; + if (target->smp) { + struct target_list *head; + + 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; + } } - } else { - int status = breakpoint_free(curr, curr, breakpoint); - if (status != ERROR_OK) - retval = status; } - } - if (!found) { - LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); - return ERROR_BREAKPOINT_NOT_FOUND; - } + } else { + retval = breakpoint_remove_internal(target, address); - if (software_breakpoint) { - struct target *remove_target; - if (software_breakpoint_target->state == TARGET_HALTED) - remove_target = software_breakpoint_target; - else if (halted_target) - remove_target = halted_target; - else - remove_target = available_target; - - if (remove_target) { - LOG_DEBUG("Removing software breakpoint found on %s using %s (address=" - TARGET_ADDR_FMT ").", - target_name(software_breakpoint_target), - target_name(remove_target), - address); - /* Remove the software breakpoint through - * remove_target, but update the breakpoints structure - * of software_breakpoint_target. */ - int status = breakpoint_free(software_breakpoint_target, remove_target, software_breakpoint); - if (status != ERROR_OK) - /* TODO: If there is an error, can we try to remove the - * same breakpoint from a different target? */ - retval = status; - } else { - LOG_WARNING("No halted target found to remove software breakpoint at " - TARGET_ADDR_FMT ".", address); - return ERROR_TARGET_NOT_HALTED; + 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; } @@ -438,11 +397,11 @@ static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_ } if (!watchpoint) - return ERROR_WATCHPOINT_NOT_FOUND; + return ERROR_OK; retval = target_remove_watchpoint(target, watchpoint); if (retval != ERROR_OK) { - LOG_TARGET_ERROR(target, "could not remove watchpoint, WPID: %" PRIu32, - watchpoint->unique_id); + LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target", + watchpoint->number); return retval; } @@ -455,6 +414,8 @@ static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_ static int watchpoint_remove_all_internal(struct target *target) { + LOG_TARGET_DEBUG(target, "Delete all watchpoints"); + struct watchpoint *watchpoint = target->watchpoints; int retval = ERROR_OK; @@ -508,34 +469,12 @@ int watchpoint_remove_all(struct target *target) return breakpoint_watchpoint_remove_all(target, WATCHPOINT); } -int breakpoint_clear_target(struct target *target) -{ - int retval = ERROR_OK; - - if (target->smp) { - struct target_list *head; - - foreach_smp_target(head, target->smp_targets) { - struct target *curr = head->target; - int status = breakpoint_remove_all_internal(curr); - - if (status != ERROR_OK) - retval = status; - } - } else { - retval = breakpoint_remove_all_internal(target); - } - - return retval; -} - struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) { struct breakpoint *breakpoint = target->breakpoints; while (breakpoint) { - if (breakpoint->address == address || - (breakpoint->address == 0 && breakpoint->asid == address)) + if (breakpoint->address == address) return breakpoint; breakpoint = breakpoint->next; } @@ -580,23 +519,23 @@ static int watchpoint_add_internal(struct target *target, target_addr_t address, retval = target_add_watchpoint(target, *watchpoint_p); switch (retval) { - case ERROR_OK: - break; - case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: - reason = "resource not available"; - goto bye; - case ERROR_TARGET_NOT_HALTED: - reason = "target not halted"; - goto bye; - default: - reason = "unrecognized error"; + case ERROR_OK: + break; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + reason = "resource not available"; + goto bye; + case ERROR_TARGET_NOT_HALTED: + reason = "target not halted"; + goto bye; + default: + reason = "unrecognized error"; bye: - 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); - *watchpoint_p = NULL; - return retval; + 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); + *watchpoint_p = NULL; + return retval; } LOG_TARGET_DEBUG(target, "added %s watchpoint at " TARGET_ADDR_FMT @@ -617,8 +556,6 @@ int watchpoint_add(struct target *target, target_addr_t address, foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; - if (curr->state == TARGET_UNAVAILABLE) - continue; int retval = watchpoint_add_internal(curr, address, length, rw, value, mask); if (retval != ERROR_OK) return retval; @@ -687,23 +624,6 @@ int watchpoint_remove(struct target *target, target_addr_t address) return retval; } -int watchpoint_clear_target(struct target *target) -{ - LOG_TARGET_DEBUG(target, "Delete all 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, target_addr_t *address) { @@ -711,6 +631,20 @@ int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, struct watchpoint *hit_watchpoint; retval = target_hit_watchpoint(target, &hit_watchpoint); + if (retval == ERROR_NOT_IMPLEMENTED + && target->debug_reason == DBG_REASON_WATCHPOINT) { + // Handle the trivial case: only one watchpoint is set + unsigned int cnt = 0; + struct watchpoint *wp = target->watchpoints; + while (wp) { + cnt++; + wp = wp->next; + } + if (cnt == 1) { + retval = ERROR_OK; + hit_watchpoint = target->watchpoints; + } + } if (retval != ERROR_OK) return ERROR_FAIL; diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index ac5d7016d2..4f156cb16c 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -47,10 +47,9 @@ struct watchpoint { bool is_set; unsigned int number; struct watchpoint *next; - uint32_t unique_id; + int unique_id; }; -int breakpoint_clear_target(struct target *target); int breakpoint_add(struct target *target, target_addr_t address, unsigned int length, enum breakpoint_type type); int context_breakpoint_add(struct target *target, @@ -69,7 +68,6 @@ static inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int breakpoint->number = hw_number; } -int watchpoint_clear_target(struct target *target); int watchpoint_add(struct target *target, target_addr_t address, unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask); @@ -88,5 +86,7 @@ static inline void watchpoint_set(struct watchpoint *watchpoint, unsigned int nu #define ERROR_BREAKPOINT_NOT_FOUND (-1600) #define ERROR_WATCHPOINT_NOT_FOUND (-1601) +#define ERROR_BREAKPOINT_DUPLICATED (-1602) +#define ERROR_BREAKPOINT_OVERLAPPED (-1603) #endif /* OPENOCD_TARGET_BREAKPOINTS_H */ diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index ee27e1b217..d5dd1fc709 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -32,6 +32,7 @@ * Cortex-A9(tm) TRM, ARM DDI 0407F * * Cortex-A4(tm) TRM, ARM DDI 0363E * * Cortex-A15(tm)TRM, ARM DDI 0438C * + * Architecture Reference Manual, ARMv7-A and ARMv7-R, ARM DDI 0406C.d * * * ***************************************************************************/ @@ -54,6 +55,7 @@ #include #include #include +#include static int cortex_a_poll(struct target *target); static int cortex_a_debug_entry(struct target *target); @@ -68,8 +70,8 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); static int cortex_a_wait_dscr_bits(struct target *target, uint32_t mask, uint32_t value, uint32_t *dscr); -static int cortex_a_mmu(struct target *target, int *enabled); -static int cortex_a_mmu_modify(struct target *target, int enable); +static int cortex_a_mmu(struct target *target, bool *enabled); +static int cortex_a_mmu_modify(struct target *target, bool enable); static int cortex_a_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys); static int cortex_a_read_cpu_memory(struct target *target, @@ -109,17 +111,17 @@ static int cortex_a_restore_cp15_control_reg(struct target *target) * If !phys_access, switch to SVC mode and make sure MMU is on * If phys_access, switch off mmu */ -static int cortex_a_prep_memaccess(struct target *target, int phys_access) +static int cortex_a_prep_memaccess(struct target *target, bool phys_access) { struct armv7a_common *armv7a = target_to_armv7a(target); struct cortex_a_common *cortex_a = target_to_cortex_a(target); - int mmu_enabled = 0; + bool mmu_enabled = false; - if (phys_access == 0) { + if (!phys_access) { arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); cortex_a_mmu(target, &mmu_enabled); if (mmu_enabled) - cortex_a_mmu_modify(target, 1); + cortex_a_mmu_modify(target, true); if (cortex_a->dacrfixup_mode == CORTEX_A_DACRFIXUP_ON) { /* overwrite DACR to all-manager */ armv7a->arm.mcr(target, 15, @@ -129,7 +131,7 @@ static int cortex_a_prep_memaccess(struct target *target, int phys_access) } else { cortex_a_mmu(target, &mmu_enabled); if (mmu_enabled) - cortex_a_mmu_modify(target, 0); + cortex_a_mmu_modify(target, false); } return ERROR_OK; } @@ -139,12 +141,12 @@ static int cortex_a_prep_memaccess(struct target *target, int phys_access) * If !phys_access, switch to previous mode * If phys_access, restore MMU setting */ -static int cortex_a_post_memaccess(struct target *target, int phys_access) +static int cortex_a_post_memaccess(struct target *target, bool phys_access) { struct armv7a_common *armv7a = target_to_armv7a(target); struct cortex_a_common *cortex_a = target_to_cortex_a(target); - if (phys_access == 0) { + if (!phys_access) { if (cortex_a->dacrfixup_mode == CORTEX_A_DACRFIXUP_ON) { /* restore */ armv7a->arm.mcr(target, 15, @@ -153,10 +155,10 @@ static int cortex_a_post_memaccess(struct target *target, int phys_access) } arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); } else { - int mmu_enabled = 0; + bool mmu_enabled = false; cortex_a_mmu(target, &mmu_enabled); if (mmu_enabled) - cortex_a_mmu_modify(target, 1); + cortex_a_mmu_modify(target, true); } return ERROR_OK; } @@ -165,12 +167,12 @@ static int cortex_a_post_memaccess(struct target *target, int phys_access) /* modify cp15_control_reg in order to enable or disable mmu for : * - virt2phys address conversion * - read or write memory in phys or virt address */ -static int cortex_a_mmu_modify(struct target *target, int enable) +static int cortex_a_mmu_modify(struct target *target, bool enable) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); int retval = ERROR_OK; - int need_write = 0; + bool need_write = false; if (enable) { /* if mmu enabled at target stop and mmu not enable */ @@ -180,12 +182,12 @@ static int cortex_a_mmu_modify(struct target *target, int enable) } if ((cortex_a->cp15_control_reg_curr & 0x1U) == 0) { cortex_a->cp15_control_reg_curr |= 0x1U; - need_write = 1; + need_write = true; } } else { if ((cortex_a->cp15_control_reg_curr & 0x1U) == 0x1U) { cortex_a->cp15_control_reg_curr &= ~0x1U; - need_write = 1; + need_write = true; } } @@ -214,7 +216,7 @@ static int cortex_a_init_debug_access(struct target *target) /* lock memory-mapped access to debug registers to prevent * software interference */ retval = mem_ap_write_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_LOCKACCESS, 0); + armv7a->debug_base + ARM_CS_LAR, 0); if (retval != ERROR_OK) return retval; @@ -450,12 +452,8 @@ static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, return retval; /* then the opcode, taking data from R0 */ - retval = cortex_a_exec_opcode( - a->armv7a_common.arm.target, - opcode, - &dscr); - - return retval; + return cortex_a_exec_opcode(a->armv7a_common.arm.target, opcode, + &dscr); } static int cortex_a_instr_write_data_r0_r1(struct arm_dpm *dpm, @@ -474,10 +472,8 @@ static int cortex_a_instr_write_data_r0_r1(struct arm_dpm *dpm, return retval; /* then the opcode, taking data from R0, R1 */ - retval = cortex_a_exec_opcode(a->armv7a_common.arm.target, - opcode, - &dscr); - return retval; + return cortex_a_exec_opcode(a->armv7a_common.arm.target, opcode, + &dscr); } static int cortex_a_instr_cpsr_sync(struct arm_dpm *dpm) @@ -580,17 +576,17 @@ static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned int index_t, int retval; switch (index_t) { - case 0 ... 15: /* breakpoints */ - vr += CPUDBG_BVR_BASE; - cr += CPUDBG_BCR_BASE; - break; - case 16 ... 31: /* watchpoints */ - vr += CPUDBG_WVR_BASE; - cr += CPUDBG_WCR_BASE; - index_t -= 16; - break; - default: - return ERROR_FAIL; + case 0 ... 15: /* breakpoints */ + vr += CPUDBG_BVR_BASE; + cr += CPUDBG_BCR_BASE; + break; + case 16 ... 31: /* watchpoints */ + vr += CPUDBG_WVR_BASE; + cr += CPUDBG_WCR_BASE; + index_t -= 16; + break; + default: + return ERROR_FAIL; } vr += 4 * index_t; cr += 4 * index_t; @@ -601,9 +597,7 @@ static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned int index_t, vr, addr); if (retval != ERROR_OK) return retval; - retval = mem_ap_write_atomic_u32(a->armv7a_common.debug_ap, - cr, control); - return retval; + return mem_ap_write_atomic_u32(a->armv7a_common.debug_ap, cr, control); } static int cortex_a_bpwp_disable(struct arm_dpm *dpm, unsigned int index_t) @@ -612,15 +606,15 @@ static int cortex_a_bpwp_disable(struct arm_dpm *dpm, unsigned int index_t) uint32_t cr; switch (index_t) { - case 0 ... 15: - cr = a->armv7a_common.debug_base + CPUDBG_BCR_BASE; - break; - case 16 ... 31: - cr = a->armv7a_common.debug_base + CPUDBG_WCR_BASE; - index_t -= 16; - break; - default: - return ERROR_FAIL; + case 0 ... 15: + cr = a->armv7a_common.debug_base + CPUDBG_BCR_BASE; + break; + case 16 ... 31: + cr = a->armv7a_common.debug_base + CPUDBG_WCR_BASE; + index_t -= 16; + break; + default: + return ERROR_FAIL; } cr += 4 * index_t; @@ -760,7 +754,7 @@ static int cortex_a_poll(struct target *target) if (DSCR_RUN_MODE(dscr) == (DSCR_CORE_HALTED | DSCR_CORE_RESTARTED)) { if (prev_target_state != TARGET_HALTED) { /* We have a halting debug event */ - LOG_DEBUG("Target halted"); + LOG_TARGET_DEBUG(target, "Target halted"); target->state = TARGET_HALTED; retval = cortex_a_debug_entry(target); @@ -808,7 +802,7 @@ static int cortex_a_halt(struct target *target) retval = cortex_a_wait_dscr_bits(target, DSCR_CORE_HALTED, DSCR_CORE_HALTED, &dscr); if (retval != ERROR_OK) { - LOG_ERROR("Error waiting for halt"); + LOG_TARGET_ERROR(target, "Error waiting for halt"); return retval; } @@ -860,24 +854,24 @@ static int cortex_a_internal_restore(struct target *target, bool current, * kill the return address */ switch (arm->core_state) { - case ARM_STATE_ARM: - resume_pc &= 0xFFFFFFFC; - break; - case ARM_STATE_THUMB: - case ARM_STATE_THUMB_EE: - /* When the return address is loaded into PC - * bit 0 must be 1 to stay in Thumb state - */ - resume_pc |= 0x1; - break; - case ARM_STATE_JAZELLE: - LOG_ERROR("How do I resume into Jazelle state??"); - return ERROR_FAIL; - case ARM_STATE_AARCH64: - LOG_ERROR("Shouldn't be in AARCH64 state"); - return ERROR_FAIL; + case ARM_STATE_ARM: + resume_pc &= 0xFFFFFFFC; + break; + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + /* When the return address is loaded into PC + * bit 0 must be 1 to stay in Thumb state + */ + resume_pc |= 0x1; + break; + case ARM_STATE_JAZELLE: + LOG_TARGET_ERROR(target, "How do I resume into Jazelle state??"); + return ERROR_FAIL; + case ARM_STATE_AARCH64: + LOG_TARGET_ERROR(target, "Shouldn't be in AARCH64 state"); + return ERROR_FAIL; } - LOG_DEBUG("resume pc = 0x%08" PRIx32, resume_pc); + LOG_TARGET_DEBUG(target, "resume pc = 0x%08" PRIx32, resume_pc); buf_set_u32(arm->pc->value, 0, 32, resume_pc); arm->pc->dirty = true; arm->pc->valid = true; @@ -935,7 +929,7 @@ static int cortex_a_internal_restart(struct target *target) return retval; if ((dscr & DSCR_INSTR_COMP) == 0) - LOG_ERROR("DSCR InstrCompl must be set before leaving debug!"); + LOG_TARGET_ERROR(target, "DSCR InstrCompl must be set before leaving debug!"); retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr & ~DSCR_ITR_EN); @@ -952,7 +946,7 @@ static int cortex_a_internal_restart(struct target *target) retval = cortex_a_wait_dscr_bits(target, DSCR_CORE_RESTARTED, DSCR_CORE_RESTARTED, &dscr); if (retval != ERROR_OK) { - LOG_ERROR("Error waiting for resume"); + LOG_TARGET_ERROR(target, "Error waiting for resume"); return retval; } @@ -967,7 +961,7 @@ static int cortex_a_internal_restart(struct target *target) static int cortex_a_restore_smp(struct target *target, bool handle_breakpoints) { - int retval = 0; + int retval = ERROR_OK; struct target_list *head; target_addr_t address; @@ -976,9 +970,17 @@ static int cortex_a_restore_smp(struct target *target, bool handle_breakpoints) if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { /* resume current address , not in step mode */ - retval += cortex_a_internal_restore(curr, true, &address, + int retval2 = cortex_a_internal_restore(curr, true, &address, handle_breakpoints, false); - retval += cortex_a_internal_restart(curr); + + if (retval2 == ERROR_OK) + retval2 = cortex_a_internal_restart(curr); + + if (retval2 == ERROR_OK) + target_call_event_callbacks(curr, TARGET_EVENT_RESUMED); + + if (retval == ERROR_OK) + retval = retval2; // save the first error } } return retval; @@ -1010,11 +1012,11 @@ static int cortex_a_resume(struct target *target, bool current, if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_DEBUG("target resumed at " TARGET_ADDR_FMT, address); + LOG_TARGET_DEBUG(target, "target resumed at " TARGET_ADDR_FMT, address); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - LOG_DEBUG("target debug resumed at " TARGET_ADDR_FMT, address); + LOG_TARGET_DEBUG(target, "target debug resumed at " TARGET_ADDR_FMT, address); } return ERROR_OK; @@ -1028,7 +1030,7 @@ static int cortex_a_debug_entry(struct target *target) struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; - LOG_DEBUG("dscr = 0x%08" PRIx32, cortex_a->cpudbg_dscr); + LOG_TARGET_DEBUG(target, "dscr = 0x%08" PRIx32, cortex_a->cpudbg_dscr); /* REVISIT surely we should not re-read DSCR !! */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, @@ -1051,18 +1053,6 @@ static int cortex_a_debug_entry(struct target *target) /* Examine debug reason */ arm_dpm_report_dscr(&armv7a->dpm, cortex_a->cpudbg_dscr); - /* save address of instruction that triggered the watchpoint? */ - if (target->debug_reason == DBG_REASON_WATCHPOINT) { - uint32_t wfar; - - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_WFAR, - &wfar); - if (retval != ERROR_OK) - return retval; - arm_dpm_report_wfar(&armv7a->dpm, wfar); - } - /* First load register accessible through core debug port */ retval = arm_dpm_read_current_registers(&armv7a->dpm); if (retval != ERROR_OK) @@ -1075,6 +1065,29 @@ static int cortex_a_debug_entry(struct target *target) return retval; } + /* save address of instruction that triggered the watchpoint? */ + if (target->debug_reason == DBG_REASON_WATCHPOINT) { + /* + * On v7.1 Debug architecture or on synchronous (precise) watchpoints, + * WFAR is not used. Take the instruction address from halted PC. + * See ARM DDI 0406C.d chapter C5.2.2 "Effect of entering Debug state + * on CP15 registers and the DBGWFAR". + */ + if (((armv7a->dpm.didr >> 16) & 0xf) > 4 || + DSCR_ENTRY(cortex_a->cpudbg_dscr) == DSCR_ENTRY_PRECISE_WATCHPT) { + armv7a->dpm.wp_addr = buf_get_u32(arm->pc->value, 0, 32); + } else { + uint32_t wfar; + + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_WFAR, + &wfar); + if (retval != ERROR_OK) + return retval; + arm_dpm_report_wfar(&armv7a->dpm, wfar); + } + } + #if 0 /* TODO, Move this */ uint32_t cp15_control_register, cp15_cacr, cp15_nacr; @@ -1112,25 +1125,25 @@ static int cortex_a_post_debug_entry(struct target *target) &cortex_a->cp15_control_reg); if (retval != ERROR_OK) return retval; - LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, cortex_a->cp15_control_reg); + LOG_TARGET_DEBUG(target, "cp15_control_reg: %8.8" PRIx32, + cortex_a->cp15_control_reg); cortex_a->cp15_control_reg_curr = cortex_a->cp15_control_reg; if (!armv7a->is_armv7r) armv7a_read_ttbcr(target); - if (armv7a->armv7a_mmu.armv7a_cache.info == -1) + if (!armv7a->armv7a_mmu.armv7a_cache.info_valid) armv7a_identify_cache(target); if (armv7a->is_armv7r) { - armv7a->armv7a_mmu.mmu_enabled = 0; + armv7a->armv7a_mmu.mmu_enabled = false; } else { - armv7a->armv7a_mmu.mmu_enabled = - (cortex_a->cp15_control_reg & 0x1U) ? 1 : 0; + armv7a->armv7a_mmu.mmu_enabled = cortex_a->cp15_control_reg & 0x1U; } armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled = - (cortex_a->cp15_control_reg & 0x4U) ? 1 : 0; + cortex_a->cp15_control_reg & 0x4U; armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled = - (cortex_a->cp15_control_reg & 0x1000U) ? 1 : 0; + cortex_a->cp15_control_reg & 0x1000U; cortex_a->curr_mode = armv7a->arm.core_mode; /* switch to SVC mode to read DACR */ @@ -1164,11 +1177,33 @@ static int cortex_a_set_dscr_bits(struct target *target, dscr |= value & bit_mask; /* write new DSCR */ - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DSCR, dscr); - return retval; + return mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DSCR, dscr); } +/* + * Single-step on ARMv7a/r is implemented through a HW breakpoint that hits + * every instruction at any address except the address of the current + * instruction. + * Such HW breakpoint is never hit in case of a single instruction that jumps + * on itself (infinite loop), or a WFI or a WFE. In this case, halt the CPU + * after a timeout. + * The jump on itself would be executed several times before the timeout forces + * the halt, but this is not an issue. In ARMv7a/r there are few "pathological" + * instructions, listed below, that jumps on itself and that can have side + * effects if executed more than once; but they are not considered as real use + * cases generated by a compiler. + * Some example: + * - 'pop {pc}' or multi register 'pop' including PC, when the new PC value is + * the same value of current PC. The single step will not stop at the first + * 'pop' and will continue taking values from the stack, modifying SP at each + * iteration. + * - 'rfeda', 'rfedb', 'rfeia', 'rfeib', when the new PC value is the same + * value of current PC. The register provided to the instruction (usually SP) + * will be incremented or decremented at each iteration. + * + * TODO: fix exit in case of error, cleaning HW breakpoints. + */ static int cortex_a_step(struct target *target, bool current, target_addr_t address, bool handle_breakpoints) { @@ -1227,15 +1262,34 @@ static int cortex_a_step(struct target *target, bool current, target_addr_t addr if (retval != ERROR_OK) return retval; - int64_t then = timeval_ms(); + // poll at least once before starting the timeout + retval = cortex_a_poll(target); + if (retval != ERROR_OK) + return retval; + + int64_t then = timeval_ms() + 100; while (target->state != TARGET_HALTED) { + if (timeval_ms() > then) + break; + retval = cortex_a_poll(target); if (retval != ERROR_OK) return retval; - if (target->state == TARGET_HALTED) - break; - if (timeval_ms() > then + 1000) { - LOG_ERROR("timeout waiting for target halt"); + } + + if (target->state != TARGET_HALTED) { + LOG_TARGET_DEBUG(target, "timeout waiting for target halt, try halt"); + + retval = cortex_a_halt(target); + if (retval != ERROR_OK) + return retval; + + retval = cortex_a_poll(target); + if (retval != ERROR_OK) + return retval; + + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "timeout waiting for target halt"); return ERROR_FAIL; } } @@ -1255,9 +1309,6 @@ static int cortex_a_step(struct target *target, bool current, target_addr_t addr if (breakpoint) cortex_a_set_breakpoint(target, breakpoint, 0); - if (target->state != TARGET_HALTED) - LOG_DEBUG("target stepped"); - return ERROR_OK; } @@ -1265,7 +1316,7 @@ static int cortex_a_restore_context(struct target *target, bool bpwp) { struct armv7a_common *armv7a = target_to_armv7a(target); - LOG_DEBUG(" "); + LOG_TARGET_DEBUG(target, " "); if (armv7a->pre_restore_context) armv7a->pre_restore_context(target); @@ -1302,6 +1353,14 @@ static int cortex_a_set_breakpoint(struct target *target, return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint_hw_set(breakpoint, brp_i); + if (breakpoint->length == 3) { + /* Thumb-2 breakpoint: fixup to length 4 if word aligned, + * set byte mask for length 2 if unaligned */ + if (IS_ALIGNED(breakpoint->address, 4)) + breakpoint->length = 4; + else + breakpoint->length = 2; + } if (breakpoint->length == 2) byte_addr_select = (3 << (breakpoint->address & 0x02)); control = ((matchmode & 0x7) << 20) @@ -1341,6 +1400,19 @@ static int cortex_a_set_breakpoint(struct target *target, buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11)); } + /* + * ARMv7-A/R fetches instructions in little-endian on both LE and BE CPUs. + * But Cortex-R4 and Cortex-R5 big-endian require BE instructions. + * https://developer.arm.com/documentation/den0042/a/Coding-for-Cortex-R-Processors/Endianness + * https://developer.arm.com/documentation/den0013/d/Porting/Endianness + */ + if ((((cortex_a->cpuid & CPUDBG_CPUID_MASK) == CPUDBG_CPUID_CORTEX_R4) || + ((cortex_a->cpuid & CPUDBG_CPUID_MASK) == CPUDBG_CPUID_CORTEX_R5)) && + target->endianness == TARGET_BIG_ENDIAN) { + // In place swapping is allowed + buf_bswap32(code, code, 4); + } + retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, @@ -1700,7 +1772,6 @@ static int cortex_a_set_watchpoint(struct target *target, struct watchpoint *wat 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; @@ -1758,6 +1829,22 @@ static int cortex_a_set_watchpoint(struct target *target, struct watchpoint *wat break; } + uint8_t load_store_access_control; + switch (watchpoint->rw) { + case WPT_READ: + load_store_access_control = 1; + break; + case WPT_WRITE: + load_store_access_control = 2; + break; + case WPT_ACCESS: + load_store_access_control = 3; + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + return ERROR_FAIL; + }; + watchpoint_set(watchpoint, wrp_i); control = (address_mask << 24) | (byte_address_select << 5) | @@ -2299,19 +2386,20 @@ static int cortex_a_write_cpu_memory(struct target *target, } else { /* Use slow path. Adjust size for aligned accesses */ switch (address % 4) { - case 1: - case 3: - count *= size; - size = 1; - break; - case 2: - if (size == 4) { - count *= 2; - size = 2; - } - case 0: - default: - break; + case 1: + case 3: + count *= size; + size = 1; + break; + case 2: + if (size == 4) { + count *= 2; + size = 2; + } + break; + case 0: + default: + break; } retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr); } @@ -2616,20 +2704,20 @@ static int cortex_a_read_cpu_memory(struct target *target, } else { /* Use slow path. Adjust size for aligned accesses */ switch (address % 4) { - case 1: - case 3: - count *= size; - size = 1; - break; - case 2: - if (size == 4) { - count *= 2; - size = 2; - } - break; - case 0: - default: - break; + case 1: + case 3: + count *= size; + size = 1; + break; + case 2: + if (size == 4) { + count *= 2; + size = 2; + } + break; + case 0: + default: + break; } retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr); } @@ -2719,9 +2807,9 @@ static int cortex_a_read_phys_memory(struct target *target, address, size, count); /* read memory through the CPU */ - cortex_a_prep_memaccess(target, 1); + cortex_a_prep_memaccess(target, true); retval = cortex_a_read_cpu_memory(target, address, size, count, buffer); - cortex_a_post_memaccess(target, 1); + cortex_a_post_memaccess(target, true); return retval; } @@ -2735,9 +2823,9 @@ static int cortex_a_read_memory(struct target *target, target_addr_t address, LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); - cortex_a_prep_memaccess(target, 0); + cortex_a_prep_memaccess(target, false); retval = cortex_a_read_cpu_memory(target, address, size, count, buffer); - cortex_a_post_memaccess(target, 0); + cortex_a_post_memaccess(target, false); return retval; } @@ -2755,9 +2843,9 @@ static int cortex_a_write_phys_memory(struct target *target, address, size, count); /* write memory through the CPU */ - cortex_a_prep_memaccess(target, 1); + cortex_a_prep_memaccess(target, true); retval = cortex_a_write_cpu_memory(target, address, size, count, buffer); - cortex_a_post_memaccess(target, 1); + cortex_a_post_memaccess(target, true); return retval; } @@ -2771,9 +2859,9 @@ static int cortex_a_write_memory(struct target *target, target_addr_t address, LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); - cortex_a_prep_memaccess(target, 0); + cortex_a_prep_memaccess(target, false); retval = cortex_a_write_cpu_memory(target, address, size, count, buffer); - cortex_a_post_memaccess(target, 0); + cortex_a_post_memaccess(target, false); return retval; } @@ -3198,7 +3286,7 @@ static void cortex_a_deinit_target(struct target *target) free(cortex_a); } -static int cortex_a_mmu(struct target *target, int *enabled) +static int cortex_a_mmu(struct target *target, bool *enabled) { struct armv7a_common *armv7a = target_to_armv7a(target); @@ -3208,7 +3296,7 @@ static int cortex_a_mmu(struct target *target, int *enabled) } if (armv7a->is_armv7r) - *enabled = 0; + *enabled = false; else *enabled = target_to_cortex_a(target)->armv7a_common.armv7a_mmu.mmu_enabled; @@ -3219,7 +3307,7 @@ static int cortex_a_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys) { int retval; - int mmu_enabled = 0; + bool mmu_enabled = false; /* * If the MMU was not enabled at debug entry, there is no @@ -3234,7 +3322,7 @@ static int cortex_a_virt2phys(struct target *target, } /* mmu must be enable in order to get a correct translation */ - retval = cortex_a_mmu_modify(target, 1); + retval = cortex_a_mmu_modify(target, true); if (retval != ERROR_OK) return retval; return armv7a_mmu_translate_va_pa(target, (uint32_t)virt, @@ -3418,6 +3506,8 @@ struct target_type cortexa_target = { .write_phys_memory = cortex_a_write_phys_memory, .mmu = cortex_a_mmu, .virt2phys = cortex_a_virt2phys, + + .insn_set = armv4_5_insn_set, }; static const struct command_registration cortex_r4_exec_command_handlers[] = { @@ -3490,4 +3580,6 @@ struct target_type cortexr4_target = { .init_target = cortex_a_init_target, .examine = cortex_a_examine, .deinit_target = cortex_a_deinit_target, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/cortex_a.h b/src/target/cortex_a.h index 37fba1a885..fe878be1b8 100644 --- a/src/target/cortex_a.h +++ b/src/target/cortex_a.h @@ -30,10 +30,11 @@ #define CORTEX_A_MIDR_PARTNUM_SHIFT 4 #define CPUDBG_CPUID 0xD00 +#define CPUDBG_CPUID_MASK 0xff00fff0 +#define CPUDBG_CPUID_CORTEX_R4 0x4100c140 +#define CPUDBG_CPUID_CORTEX_R5 0x4100c150 #define CPUDBG_CTYPR 0xD04 #define CPUDBG_TTYPR 0xD0C -#define CPUDBG_LOCKACCESS 0xFB0 -#define CPUDBG_LOCKSTATUS 0xFB4 #define CPUDBG_OSLAR_LK_MASK (1 << 1) #define BRP_NORMAL 0 diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index ba9d83d79f..61cddafc11 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -21,15 +21,16 @@ #include "jtag/interface.h" #include "breakpoints.h" #include "cortex_m.h" +#include "armv7m_cache.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 +#include #include #include @@ -472,22 +473,22 @@ static int cortex_m_set_maskints_for_halt(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); switch (cortex_m->isrmasking_mode) { - case CORTEX_M_ISRMASK_AUTO: - /* interrupts taken at resume, whether for step or run -> no mask */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_AUTO: + /* interrupts taken at resume, whether for step or run -> no mask */ + return cortex_m_set_maskints(target, false); - case CORTEX_M_ISRMASK_OFF: - /* interrupts never masked */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_OFF: + /* interrupts never masked */ + return cortex_m_set_maskints(target, false); - case CORTEX_M_ISRMASK_ON: - /* interrupts always masked */ - return cortex_m_set_maskints(target, true); + case CORTEX_M_ISRMASK_ON: + /* interrupts always masked */ + return cortex_m_set_maskints(target, true); - case CORTEX_M_ISRMASK_STEPONLY: - /* interrupts masked for single step only -> mask now if MASKINTS - * erratum, otherwise only mask before stepping */ - return cortex_m_set_maskints(target, cortex_m->maskints_erratum); + case CORTEX_M_ISRMASK_STEPONLY: + /* interrupts masked for single step only -> mask now if MASKINTS + * erratum, otherwise only mask before stepping */ + return cortex_m_set_maskints(target, cortex_m->maskints_erratum); } return ERROR_OK; } @@ -495,21 +496,21 @@ static int cortex_m_set_maskints_for_halt(struct target *target) static int cortex_m_set_maskints_for_run(struct target *target) { switch (target_to_cm(target)->isrmasking_mode) { - case CORTEX_M_ISRMASK_AUTO: - /* interrupts taken at resume, whether for step or run -> no mask */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_AUTO: + /* interrupts taken at resume, whether for step or run -> no mask */ + return cortex_m_set_maskints(target, false); - case CORTEX_M_ISRMASK_OFF: - /* interrupts never masked */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_OFF: + /* interrupts never masked */ + return cortex_m_set_maskints(target, false); - case CORTEX_M_ISRMASK_ON: - /* interrupts always masked */ - return cortex_m_set_maskints(target, true); + case CORTEX_M_ISRMASK_ON: + /* interrupts always masked */ + return cortex_m_set_maskints(target, true); - case CORTEX_M_ISRMASK_STEPONLY: - /* interrupts masked for single step only -> no mask */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_STEPONLY: + /* interrupts masked for single step only -> no mask */ + return cortex_m_set_maskints(target, false); } return ERROR_OK; } @@ -517,21 +518,21 @@ static int cortex_m_set_maskints_for_run(struct target *target) static int cortex_m_set_maskints_for_step(struct target *target) { switch (target_to_cm(target)->isrmasking_mode) { - case CORTEX_M_ISRMASK_AUTO: - /* the auto-interrupt should already be done -> mask */ - return cortex_m_set_maskints(target, true); + case CORTEX_M_ISRMASK_AUTO: + /* the auto-interrupt should already be done -> mask */ + return cortex_m_set_maskints(target, true); - case CORTEX_M_ISRMASK_OFF: - /* interrupts never masked */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_OFF: + /* interrupts never masked */ + return cortex_m_set_maskints(target, false); - case CORTEX_M_ISRMASK_ON: - /* interrupts always masked */ - return cortex_m_set_maskints(target, true); + case CORTEX_M_ISRMASK_ON: + /* interrupts always masked */ + return cortex_m_set_maskints(target, true); - case CORTEX_M_ISRMASK_STEPONLY: - /* interrupts masked for single step only -> mask */ - return cortex_m_set_maskints(target, true); + case CORTEX_M_ISRMASK_STEPONLY: + /* interrupts masked for single step only -> mask */ + return cortex_m_set_maskints(target, true); } return ERROR_OK; } @@ -554,7 +555,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_TARGET_DEBUG(target, "NVIC_DFSR 0x%" PRIx32 "", cortex_m->nvic_dfsr); + LOG_TARGET_DEBUG(target, "NVIC_DFSR 0x%" PRIx32, cortex_m->nvic_dfsr); return ERROR_OK; } @@ -616,7 +617,7 @@ 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_TARGET_DEBUG(target, "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); @@ -739,61 +740,61 @@ static int cortex_m_examine_exception_reason(struct target *target) if (retval != ERROR_OK) return retval; switch (armv7m->exception_number) { - case 2: /* NMI */ - break; - case 3: /* Hard Fault */ - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_HFSR, &except_sr); - if (retval != ERROR_OK) - return retval; - if (except_sr & 0x40000000) { - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &cfsr); - if (retval != ERROR_OK) - return retval; - } - break; - case 4: /* Memory Management */ - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_MMFAR, &except_ar); - if (retval != ERROR_OK) - return retval; - break; - case 5: /* Bus Fault */ - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_BFAR, &except_ar); - if (retval != ERROR_OK) - return retval; - break; - case 6: /* Usage Fault */ - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); - if (retval != ERROR_OK) - return retval; - break; - case 7: /* Secure Fault */ - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFSR, &except_sr); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFAR, &except_ar); - if (retval != ERROR_OK) - return retval; - break; - case 11: /* SVCall */ - break; - case 12: /* Debug Monitor */ - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_DFSR, &except_sr); + case 2: /* NMI */ + break; + case 3: /* Hard Fault */ + retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_HFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + if (except_sr & 0x40000000) { + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &cfsr); if (retval != ERROR_OK) return retval; - break; - case 14: /* PendSV */ - break; - case 15: /* SysTick */ - break; - default: - except_sr = 0; - break; + } + break; + case 4: /* Memory Management */ + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_MMFAR, &except_ar); + if (retval != ERROR_OK) + return retval; + break; + case 5: /* Bus Fault */ + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_BFAR, &except_ar); + if (retval != ERROR_OK) + return retval; + break; + case 6: /* Usage Fault */ + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + break; + case 7: /* Secure Fault */ + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFAR, &except_ar); + if (retval != ERROR_OK) + return retval; + break; + case 11: /* SVCall */ + break; + case 12: /* Debug Monitor */ + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_DFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + break; + case 14: /* PendSV */ + break; + case 15: /* SysTick */ + break; + default: + except_sr = 0; + break; } retval = dap_run(swjdp); if (retval == ERROR_OK) @@ -873,6 +874,18 @@ static int cortex_m_debug_entry(struct target *target) return retval; } + // read caches state + retval = armv7m_deferred_identify_cache(target); + if (retval != ERROR_OK) + return retval; + + uint32_t ccr = 0; + if (armv7m->armv7m_cache.info_valid) { + retval = mem_ap_read_u32(armv7m->debug_ap, CCR, &ccr); + if (retval != ERROR_OK) + return retval; + } + /* Load all registers to arm.core_cache */ if (!cortex_m->slow_register_read) { retval = cortex_m_fast_read_all_regs(target); @@ -926,6 +939,11 @@ static int cortex_m_debug_entry(struct target *target) secure_state ? "Secure" : "Non-Secure", target_state_name(target)); + if (armv7m->armv7m_cache.info_valid) + LOG_TARGET_DEBUG(target, "D-Cache %s, I-Cache %s", + str_enabled_disabled(ccr & CCR_DC_MASK), + str_enabled_disabled(ccr & CCR_IC_MASK)); + /* Errata 3092511 workaround * Cortex-M7 can halt in an incorrect address when breakpoint * and exception occurs simultaneously */ @@ -1003,6 +1021,10 @@ static int cortex_m_poll_one(struct target *target) /* S_RESET_ST was expected (in a reset command). Continue processing * to quickly get out of TARGET_RESET state */ + } else { + retval = armv7m_deferred_identify_cache(target); + if (retval != ERROR_OK) + return retval; } if (target->state == TARGET_RESET) { @@ -1779,6 +1801,7 @@ static int cortex_m_assert_reset(struct target *target) int retval2; retval2 = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); + target->debug_reason = DBG_REASON_DBGRQ; if (retval != ERROR_OK || retval2 != ERROR_OK) LOG_TARGET_INFO(target, "AP write error, reset will not halt"); } @@ -1876,7 +1899,6 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint int retval; 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->is_set) { LOG_TARGET_WARNING(target, "breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id); @@ -1885,6 +1907,12 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint if (breakpoint->type == BKPT_HARD) { uint32_t fpcr_value; + struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; + if (!comparator_list) { + LOG_TARGET_ERROR(target, "No comparator list. Not examined?"); + return ERROR_FAIL; + } + while (comparator_list[fp_num].used && (fp_num < cortex_m->fp_num_code)) fp_num++; if (fp_num >= cortex_m->fp_num_code) { @@ -1910,7 +1938,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint 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_TARGET_DEBUG(target, "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) { @@ -1937,12 +1965,25 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint breakpoint->orig_instr); if (retval != ERROR_OK) return retval; + // make sure data cache is cleaned & invalidated down to PoC + retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; + retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, code); if (retval != ERROR_OK) return retval; + // update i-cache at breakpoint location + retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; + retval = armv7m_i_cache_inval(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; + breakpoint->is_set = true; } @@ -1960,7 +2001,6 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi { int retval; struct cortex_m_common *cortex_m = target_to_cm(target); - struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; if (!breakpoint->is_set) { LOG_TARGET_WARNING(target, "breakpoint not set"); @@ -1980,17 +2020,37 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi LOG_TARGET_DEBUG(target, "Invalid FP Comparator number in breakpoint"); return ERROR_OK; } + + struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; + if (!comparator_list) { + LOG_TARGET_ERROR(target, "No comparator list. Not examined?"); + return ERROR_FAIL; + } + comparator_list[fp_num].used = false; comparator_list[fp_num].fpcr_value = 0; target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); } else { + // make sure data cache is cleaned & invalidated down to PoC + retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; + /* restore original instruction (kept in target endianness) */ retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; + + // update i-cache at breakpoint location + retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; + retval = armv7m_i_cache_inval(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; } breakpoint->is_set = false; @@ -1999,6 +2059,15 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { + /* + * GDB packets Z0 and z0 provide the 'kind' parameter that is target-specific + * and typically indicates the size in bytes of the breakpoint. + * But for 32-bit Thumb mode (Thumb-2) breakpoint, GDB provides 'kind = 3' to + * be used to derive the length information. See: + * https://sourceware.org/gdb/current/onlinedocs/gdb.html/ARM-Breakpoint-Kinds.html + * Since there isn't a four byte Thumb-2 breakpoint instruction, always use + * the two bytes breakpoint instruction. + */ if (breakpoint->length == 3) { LOG_TARGET_DEBUG(target, "Using a two byte breakpoint for 32bit Thumb-2 request"); breakpoint->length = 2; @@ -2238,6 +2307,13 @@ void cortex_m_enable_watchpoints(struct target *target) } } +static bool cortex_m_memory_ready(struct target *target) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + + return armv7m->debug_ap; +} + static int cortex_m_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { @@ -2294,7 +2370,6 @@ 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) { - struct timeval timeout, now; struct armv7m_common *armv7m = target_to_armv7m(target); uint32_t reg_value; int retval; @@ -2309,8 +2384,7 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, return target_profiling_default(target, samples, max_num_samples, num_samples, seconds); } - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, seconds, 0); + int64_t then = timeval_ms() + seconds * 1000LL; LOG_TARGET_INFO(target, "Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can..."); @@ -2346,8 +2420,7 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, } - gettimeofday(&now, NULL); - if (sample_count >= max_num_samples || timeval_compare(&now, &timeout) > 0) { + if (sample_count >= max_num_samples || timeval_ms() > then) { LOG_TARGET_INFO(target, "Profiling completed. %" PRIu32 " samples.", sample_count); break; } @@ -2562,6 +2635,127 @@ static bool cortex_m_has_tz(struct target *target) return (dauthstatus & DAUTHSTATUS_SID_MASK) != 0; } +static bool cortex_m_main_extension(struct target *target, uint32_t cpuid) +{ + /* Inspect architecture to differentiate main extension/baseline */ + unsigned int extension = (cpuid & ARM_CPUID_ARCHITECTURE_MASK) >> ARM_CPUID_ARCHITECTURE_POS; + + if (extension == ARM_CPUID_MAIN_EXTENSION) + return true; + else if (extension == ARM_CPUID_NO_MAIN_EXTENSION) + return false; + + LOG_TARGET_WARNING(target, "Fail to detect target extension"); + + return false; +} + +int cortex_m_set_secure(struct target *target, struct cortex_m_saved_security *ssec) +{ + if (ssec) { + ssec->dscsr_dirty = false; + ssec->sau_ctrl_dirty = false; + ssec->mpu_ctrl_dirty = false; + } + + if (!cortex_m_has_tz(target)) + return ERROR_OK; + + uint32_t dscsr; + int retval = target_read_u32(target, DCB_DSCSR, &dscsr); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: DSCSR read failed"); + return retval; + } + if (!(dscsr & DSCSR_CDS)) { + if (ssec) { + ssec->dscsr_dirty = true; + ssec->dscsr = dscsr; + } + LOG_TARGET_DEBUG(target, "Setting Current Domain Secure in DSCSR"); + retval = target_write_u32(target, DCB_DSCSR, DSCSR_CDS); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: DSCSR write failed"); + return retval; + } + } + + uint32_t sau_ctrl; + retval = target_read_u32(target, SAU_CTRL, &sau_ctrl); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: SAU_CTRL read failed"); + return retval; + } + if (sau_ctrl & SAU_CTRL_ENABLE) { + if (ssec) { + ssec->sau_ctrl_dirty = true; + ssec->sau_ctrl = sau_ctrl; + } + retval = target_write_u32(target, SAU_CTRL, sau_ctrl & ~SAU_CTRL_ENABLE); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: SAU_CTRL write failed"); + return retval; + } + } + + uint32_t mpu_ctrl; + retval = target_read_u32(target, MPU_CTRL, &mpu_ctrl); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: MPU_CTRL read failed"); + return retval; + } + if (mpu_ctrl & MPU_CTRL_ENABLE) { + if (ssec) { + ssec->mpu_ctrl_dirty = true; + ssec->mpu_ctrl = mpu_ctrl; + } + retval = target_write_u32(target, MPU_CTRL, mpu_ctrl & ~MPU_CTRL_ENABLE); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: MPU_CTRL write failed"); + return retval; + } + } + return ERROR_OK; +} + +int cortex_m_security_restore(struct target *target, struct cortex_m_saved_security *ssec) +{ + int retval; + if (!cortex_m_has_tz(target)) + return ERROR_OK; + + if (!ssec) + return ERROR_OK; + + if (ssec->mpu_ctrl_dirty) { + retval = target_write_u32(target, MPU_CTRL, ssec->mpu_ctrl); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M security restore: MPU_CTRL write failed"); + return retval; + } + ssec->mpu_ctrl_dirty = false; + } + + if (ssec->sau_ctrl_dirty) { + retval = target_write_u32(target, SAU_CTRL, ssec->sau_ctrl); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M security restore: SAU_CTRL write failed"); + return retval; + } + ssec->sau_ctrl_dirty = false; + } + + if (ssec->dscsr_dirty) { + LOG_TARGET_DEBUG(target, "Restoring Current Domain Security in DSCSR"); + retval = target_write_u32(target, DCB_DSCSR, ssec->dscsr & ~DSCSR_CDSKEY); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: DSCSR write failed"); + return retval; + } + ssec->dscsr_dirty = false; + } + return ERROR_OK; +} #define MVFR0 0xE000EF40 #define MVFR0_SP_MASK 0x000000F0 @@ -2577,10 +2771,12 @@ static bool cortex_m_has_tz(struct target *target) static int cortex_m_find_mem_ap(struct adiv5_dap *swjdp, struct adiv5_ap **debug_ap) { - if (dap_find_get_ap(swjdp, AP_TYPE_AHB3_AP, debug_ap) == ERROR_OK) - return ERROR_OK; + const enum ap_type types[] = { + AP_TYPE_AHB3_AP, + AP_TYPE_AHB5_AP + }; - return dap_find_get_ap(swjdp, AP_TYPE_AHB5_AP, debug_ap); + return dap_find_by_types_get_ap(swjdp, types, ARRAY_SIZE(types), debug_ap); } int cortex_m_examine(struct target *target) @@ -2619,8 +2815,6 @@ int cortex_m_examine(struct target *target) } if (!target_was_examined(target)) { - target_set_examined(target); - /* Read from Device Identification Registers */ retval = target_read_u32(target, CPUID, &cpuid); if (retval != ERROR_OK) @@ -2666,7 +2860,7 @@ int cortex_m_examine(struct target *target) else LOG_TARGET_INFO(target, "The erratum 3092511 workaround will resume after an incorrect halt"); } - LOG_TARGET_DEBUG(target, "cpuid: 0x%8.8" PRIx32 "", cpuid); + LOG_TARGET_DEBUG(target, "cpuid: 0x%8.8" PRIx32, cpuid); if (cortex_m->core_info->flags & CORTEX_M_F_HAS_FPV4) { uint32_t mvfr0; @@ -2715,10 +2909,60 @@ int cortex_m_examine(struct target *target) if (armv7m->fp_feature != FPV5_MVE_F && armv7m->fp_feature != FPV5_MVE_I) armv7m->arm.core_cache->reg_list[ARMV8M_VPR].exist = false; - if (!cortex_m_has_tz(target)) - for (size_t idx = ARMV8M_FIRST_REG; idx <= ARMV8M_LAST_REG; idx++) + if (armv7m->arm.arch == ARM_ARCH_V8M) { + bool cm_has_tz = cortex_m_has_tz(target); + bool main_ext = cortex_m_main_extension(target, cpuid); + bool baseline = !main_ext; + + if (!cm_has_tz) { + for (size_t idx = ARMV8M_TZ_FIRST_REG; idx <= ARMV8M_TZ_LAST_REG; idx++) + armv7m->arm.core_cache->reg_list[idx].exist = false; + + if (baseline) { + armv7m->arm.core_cache->reg_list[ARMV8M_MSPLIM].exist = false; + armv7m->arm.core_cache->reg_list[ARMV8M_PSPLIM].exist = false; + } + } else { + if (baseline) { + /* ARMV8M without main extension but with the security extension has + only two stack limit registers in Secure state */ + armv7m->arm.core_cache->reg_list[ARMV8M_MSPLIM_NS].exist = false; + armv7m->arm.core_cache->reg_list[ARMV8M_PSPLIM_NS].exist = false; + armv7m->arm.core_cache->reg_list[ARMV8M_MSPLIM].exist = false; + armv7m->arm.core_cache->reg_list[ARMV8M_PSPLIM].exist = false; + + armv7m->arm.core_cache->reg_list[ARMV8M_BASEPRI_S].exist = false; + armv7m->arm.core_cache->reg_list[ARMV8M_FAULTMASK_S].exist = false; + armv7m->arm.core_cache->reg_list[ARMV8M_BASEPRI_NS].exist = false; + armv7m->arm.core_cache->reg_list[ARMV8M_FAULTMASK_NS].exist = false; + } else { + /* There is no separate regsel for msplim/psplim of ARMV8M mainline + with the security extension that would point to correct alias + depending on security state of the processor, thus register marked + as non-existing letting to choose between S/NS alias manually */ + armv7m->arm.core_cache->reg_list[ARMV8M_MSPLIM].exist = false; + armv7m->arm.core_cache->reg_list[ARMV8M_PSPLIM].exist = false; + } + } + + if (baseline) { + armv7m->arm.core_cache->reg_list[ARMV7M_BASEPRI].exist = false; + armv7m->arm.core_cache->reg_list[ARMV7M_FAULTMASK].exist = false; + } + } else { + /* Security extension and stack limit checking introduced in ARMV8M */ + for (size_t idx = ARMV8M_TZ_FIRST_REG; idx <= ARMV8M_TZ_LAST_REG; idx++) armv7m->arm.core_cache->reg_list[idx].exist = false; + armv7m->arm.core_cache->reg_list[ARMV8M_MSPLIM].exist = false; + armv7m->arm.core_cache->reg_list[ARMV8M_PSPLIM].exist = false; + + if (armv7m->arm.arch == ARM_ARCH_V6M) { + armv7m->arm.core_cache->reg_list[ARMV7M_BASEPRI].exist = false; + armv7m->arm.core_cache->reg_list[ARMV7M_FAULTMASK].exist = false; + } + } + 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, @@ -2730,6 +2974,18 @@ int cortex_m_examine(struct target *target) if (retval != ERROR_OK) return retval; + /* + * Use a safe value of sticky S_RESET_ST for cache detection, before + * clearing it below. + */ + if (!armv7m->is_hla_target) { + retval = armv7m_identify_cache(target); + if (retval != ERROR_OK) { + LOG_ERROR("Cannot detect cache"); + 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). @@ -2938,6 +3194,15 @@ static int cortex_m_target_create(struct target *target) return ERROR_OK; } +int cortex_m_insn_set(struct command_invocation *cmd, struct target *target, + const char **insn_set) +{ + // string match in target/oocd_capstone.c + *insn_set = "cortexm"; + + return ERROR_OK; +} + /*--------------------------------------------------------------------------*/ static int cortex_m_verify_pointer(struct command_invocation *cmd, @@ -3087,29 +3352,15 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command) { struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); - int retval; - char *reset_config; - retval = cortex_m_verify_pointer(CMD, cortex_m); + int retval = cortex_m_verify_pointer(CMD, cortex_m); if (retval != ERROR_OK) return retval; - if (CMD_ARGC > 0) { - if (strcmp(*CMD_ARGV, "sysresetreq") == 0) - cortex_m->soft_reset_config = CORTEX_M_RESET_SYSRESETREQ; + if (!CMD_ARGC) { + char *reset_config; - else if (strcmp(*CMD_ARGV, "vectreset") == 0) { - if (target_was_examined(target) - && !cortex_m->vectreset_supported) - LOG_TARGET_WARNING(target, "VECTRESET is not supported on your Cortex-M core!"); - else - cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; - - } else - return ERROR_COMMAND_SYNTAX_ERROR; - } - - switch (cortex_m->soft_reset_config) { + switch (cortex_m->soft_reset_config) { case CORTEX_M_RESET_SYSRESETREQ: reset_config = "sysresetreq"; break; @@ -3121,13 +3372,40 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command) default: reset_config = "unknown"; break; + } + + command_print(CMD, "%s", reset_config); + return ERROR_OK; + } else if (CMD_ARGC != 1) { + return ERROR_COMMAND_SYNTAX_ERROR; } - command_print(CMD, "cortex_m reset_config %s", reset_config); + if (!strcmp(CMD_ARGV[0], "sysresetreq")) { + cortex_m->soft_reset_config = CORTEX_M_RESET_SYSRESETREQ; + } else if (!strcmp(CMD_ARGV[0], "vectreset")) { + if (target_was_examined(target) + && !cortex_m->vectreset_supported) + LOG_TARGET_WARNING(target, "VECTRESET is not supported on your Cortex-M core"); + else + cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; + } else { + command_print(CMD, "invalid reset config '%s'", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } return ERROR_OK; } +COMMAND_HANDLER(handle_cortex_m_cache_info_command) +{ + if (CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + return armv7m_handle_cache_info_command(CMD, target); +} + static const struct command_registration cortex_m_exec_command_handlers[] = { { .name = "maskisr", @@ -3150,6 +3428,13 @@ static const struct command_registration cortex_m_exec_command_handlers[] = { .help = "configure software reset handling", .usage = "['sysresetreq'|'vectreset']", }, + { + .name = "cache_info", + .handler = handle_cortex_m_cache_info_command, + .mode = COMMAND_EXEC, + .help = "display information about target caches", + .usage = "", + }, { .chain = smp_command_handlers, }, @@ -3199,6 +3484,7 @@ struct target_type cortexm_target = { .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = armv7m_get_gdb_reg_list, + .memory_ready = cortex_m_memory_ready, .read_memory = cortex_m_read_memory, .write_memory = cortex_m_write_memory, .checksum_memory = armv7m_checksum_memory, @@ -3222,4 +3508,6 @@ struct target_type cortexm_target = { .deinit_target = cortex_m_deinit_target, .profiling = cortex_m_profiling, + + .insn_set = cortex_m_insn_set, }; diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 144f24560c..d5e3d1395f 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -14,20 +14,22 @@ #ifndef OPENOCD_TARGET_CORTEX_M_H #define OPENOCD_TARGET_CORTEX_M_H +#include "arm_coresight.h" #include "armv7m.h" +#include "helper/bitfield.h" #include "helper/bits.h" #define CORTEX_M_COMMON_MAGIC 0x1A451A45U #define SYSTEM_CONTROL_BASE 0x400FE000 +#define ITM_BASE 0xE0000000 #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 ITM_LAR (ITM_BASE + ARM_CS_LAR) #define CPUID 0xE000ED00 @@ -36,6 +38,11 @@ #define ARM_CPUID_PARTNO_POS 4 #define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS) +#define ARM_CPUID_ARCHITECTURE_POS 16 +#define ARM_CPUID_ARCHITECTURE_MASK (0xF << ARM_CPUID_ARCHITECTURE_POS) +#define ARM_CPUID_MAIN_EXTENSION 0xF +#define ARM_CPUID_NO_MAIN_EXTENSION 0xC + #define ARM_MAKE_CPUID(impl, partno) ((((impl) << ARM_CPUID_IMPLEMENTER_POS) & ARM_CPUID_IMPLEMENTER_MASK) | \ (((partno) << ARM_CPUID_PARTNO_POS) & ARM_CPUID_PARTNO_MASK)) @@ -114,6 +121,45 @@ struct cortex_m_part_info { #define FPU_FPCAR 0xE000EF38 #define FPU_FPDSCR 0xE000EF3C +// Cache +#define CCR 0xE000ED14 +#define CLIDR 0xE000ED78 +#define CTR 0xE000ED7C +#define CCSIDR 0xE000ED80 +#define CSSELR 0xE000ED84 +#define ICIMVAU 0xE000EF58 +#define DCCIMVAC 0xE000EF70 + +#define CCR_IC_MASK BIT(17) +#define CCR_DC_MASK BIT(16) + +#define CLIDR_ICB_MASK GENMASK(31, 30) +#define CLIDR_LOUU_MASK GENMASK(29, 27) +#define CLIDR_LOC_MASK GENMASK(26, 24) +#define CLIDR_LOUIS_MASK GENMASK(23, 21) +#define CLIDR_CTYPE_MASK(i) (GENMASK(2, 0) << (3 * (i) - 3)) + +#define CLIDR_CTYPE_I_CACHE BIT(0) +#define CLIDR_CTYPE_D_CACHE BIT(1) +#define CLIDR_CTYPE_UNIFIED_CACHE BIT(2) + +#define CTR_FORMAT_MASK GENMASK(31, 29) +#define CTR_CWG_MASK GENMASK(27, 24) +#define CTR_ERG_MASK GENMASK(23, 20) +#define CTR_DMINLINE_MASK GENMASK(19, 16) +#define CTR_IMINLINE_MASK GENMASK(3, 0) + +#define CTR_FORMAT_PROVIDED 0x04 + +#define CCSIDR_NUMSETS_MASK GENMASK(27, 13) +#define CCSIDR_ASSOCIATIVITY_MASK GENMASK(12, 3) +#define CCSIDR_LINESIZE_MASK GENMASK(2, 0) + +#define CSSELR_LEVEL_MASK GENMASK(3, 1) +#define CSSELR_IND_MASK BIT(0) +#define CSSELR_IND_DATA_OR_UNIFIED_CACHE 0 +#define CSSELR_IND_INSTRUCTION_CACHE 1 + #define TPIU_SSPSR 0xE0040000 #define TPIU_CSPSR 0xE0040004 #define TPIU_ACPR 0xE0040010 @@ -167,6 +213,8 @@ struct cortex_m_part_info { #define NVIC_DFSR 0xE000ED30 #define NVIC_MMFAR 0xE000ED34 #define NVIC_BFAR 0xE000ED38 +#define MPU_CTRL 0xE000ED94 +#define SAU_CTRL 0xE000EDD0 #define NVIC_SFSR 0xE000EDE4 #define NVIC_SFAR 0xE000EDE8 @@ -184,6 +232,9 @@ struct cortex_m_part_info { #define DFSR_VCATCH 8 #define DFSR_EXTERNAL 16 +#define MPU_CTRL_ENABLE BIT(0) +#define SAU_CTRL_ENABLE BIT(0) + #define FPCR_CODE 0 #define FPCR_LITERAL 1 #define FPCR_REPLACE_REMAP (0ul << 30) @@ -264,6 +315,15 @@ struct cortex_m_common { bool incorrect_halt_erratum; }; +struct cortex_m_saved_security { + bool dscsr_dirty; + uint32_t dscsr; + bool sau_ctrl_dirty; + uint32_t sau_ctrl; + bool mpu_ctrl_dirty; + uint32_t mpu_ctrl; +}; + static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m) { return cortex_m->common_magic == CORTEX_M_COMMON_MAGIC; @@ -340,5 +400,20 @@ void cortex_m_enable_watchpoints(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); +int cortex_m_insn_set(struct command_invocation *cmd, struct target *target, + const char **insn_set); + +/** + * Forces Cortex-M core to the basic secure context with SAU and MPU off + * @param ssec pointer to save previous security state or NULL + * @returns error code or ERROR_OK if secure mode was set or is not applicable + * (not ARMv8M with security extension) + */ +int cortex_m_set_secure(struct target *target, struct cortex_m_saved_security *ssec); + +/** + * Restores saved security context to MPU_CTRL, SAU_CTRL and DSCSR + */ +int cortex_m_security_restore(struct target *target, struct cortex_m_saved_security *ssec); #endif /* OPENOCD_TARGET_CORTEX_M_H */ diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index 8198438230..33d8aa7f30 100644 --- a/src/target/dsp563xx.c +++ b/src/target/dsp563xx.c @@ -741,37 +741,37 @@ static int dsp563xx_read_register(struct target *target, int num, int force) arch_info = dsp563xx->core_cache->reg_list[num].arch_info; switch (arch_info->num) { - case DSP563XX_REG_IDX_SSH: - err = dsp563xx_reg_ssh_read(target); - break; - case DSP563XX_REG_IDX_SSL: - err = dsp563xx_reg_ssl_read(target); - break; - case DSP563XX_REG_IDX_PC: - err = dsp563xx_reg_pc_read(target); - break; - case DSP563XX_REG_IDX_IPRC: - case DSP563XX_REG_IDX_IPRP: - case DSP563XX_REG_IDX_BCR: - case DSP563XX_REG_IDX_DCR: - case DSP563XX_REG_IDX_AAR0: - case DSP563XX_REG_IDX_AAR1: - case DSP563XX_REG_IDX_AAR2: - case DSP563XX_REG_IDX_AAR3: - err = dsp563xx_reg_read_high_io(target, - arch_info->instr_mask, &data); - if (err == ERROR_OK) { - dsp563xx->core_regs[num] = data; - dsp563xx->read_core_reg(target, num); - } - break; - default: - err = dsp563xx_reg_read(target, arch_info->eame, &data); - if (err == ERROR_OK) { - dsp563xx->core_regs[num] = data; - dsp563xx->read_core_reg(target, num); - } - break; + case DSP563XX_REG_IDX_SSH: + err = dsp563xx_reg_ssh_read(target); + break; + case DSP563XX_REG_IDX_SSL: + err = dsp563xx_reg_ssl_read(target); + break; + case DSP563XX_REG_IDX_PC: + err = dsp563xx_reg_pc_read(target); + break; + case DSP563XX_REG_IDX_IPRC: + case DSP563XX_REG_IDX_IPRP: + case DSP563XX_REG_IDX_BCR: + case DSP563XX_REG_IDX_DCR: + case DSP563XX_REG_IDX_AAR0: + case DSP563XX_REG_IDX_AAR1: + case DSP563XX_REG_IDX_AAR2: + case DSP563XX_REG_IDX_AAR3: + err = dsp563xx_reg_read_high_io(target, + arch_info->instr_mask, &data); + if (err == ERROR_OK) { + dsp563xx->core_regs[num] = data; + dsp563xx->read_core_reg(target, num); + } + break; + default: + err = dsp563xx_reg_read(target, arch_info->eame, &data); + if (err == ERROR_OK) { + dsp563xx->core_regs[num] = data; + dsp563xx->read_core_reg(target, num); + } + break; } } @@ -793,37 +793,34 @@ static int dsp563xx_write_register(struct target *target, int num, int force) dsp563xx->write_core_reg(target, num); switch (arch_info->num) { - case DSP563XX_REG_IDX_SSH: - err = dsp563xx_reg_ssh_write(target); - break; - case DSP563XX_REG_IDX_PC: - /* pc is updated on resume, no need to write it here */ - break; - case DSP563XX_REG_IDX_IPRC: - case DSP563XX_REG_IDX_IPRP: - case DSP563XX_REG_IDX_BCR: - case DSP563XX_REG_IDX_DCR: - case DSP563XX_REG_IDX_AAR0: - case DSP563XX_REG_IDX_AAR1: - case DSP563XX_REG_IDX_AAR2: - case DSP563XX_REG_IDX_AAR3: - err = dsp563xx_reg_write_high_io(target, - arch_info->instr_mask, - dsp563xx->core_regs[num]); - break; - default: - err = dsp563xx_reg_write(target, - arch_info->instr_mask, - dsp563xx->core_regs[num]); - - if ((err == ERROR_OK) && (arch_info->num == DSP563XX_REG_IDX_SP)) { - dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSH].valid = - 0; - dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSL].valid = - 0; - } - - break; + case DSP563XX_REG_IDX_SSH: + err = dsp563xx_reg_ssh_write(target); + break; + case DSP563XX_REG_IDX_PC: + /* pc is updated on resume, no need to write it here */ + break; + case DSP563XX_REG_IDX_IPRC: + case DSP563XX_REG_IDX_IPRP: + case DSP563XX_REG_IDX_BCR: + case DSP563XX_REG_IDX_DCR: + case DSP563XX_REG_IDX_AAR0: + case DSP563XX_REG_IDX_AAR1: + case DSP563XX_REG_IDX_AAR2: + case DSP563XX_REG_IDX_AAR3: + err = dsp563xx_reg_write_high_io(target, + arch_info->instr_mask, + dsp563xx->core_regs[num]); + break; + default: + err = dsp563xx_reg_write(target, + arch_info->instr_mask, + dsp563xx->core_regs[num]); + + if (err == ERROR_OK && arch_info->num == DSP563XX_REG_IDX_SP) { + dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSH].valid = 0; + dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSL].valid = 0; + } + break; } } @@ -918,8 +915,6 @@ static int dsp563xx_examine(struct target *target) } if (!target_was_examined(target)) { - target_set_examined(target); - /* examine core and chip derivate number */ chip = (target->tap->idcode>>12) & 0x3ff; /* core number 0 means DSP563XX */ @@ -1490,14 +1485,14 @@ static int dsp563xx_get_default_memory(void) return MEM_P; switch (c[0]) { - case '1': - return MEM_X; - case '2': - return MEM_Y; - case '3': - return MEM_L; - default: - break; + case '1': + return MEM_X; + case '2': + return MEM_Y; + case '3': + return MEM_L; + default: + break; } return MEM_P; @@ -1517,7 +1512,7 @@ static int dsp563xx_read_memory_core(struct target *target, uint8_t *b; LOG_DEBUG( - "memtype: %d address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + "memtype: %d address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, mem_type, address, size, @@ -1529,18 +1524,18 @@ static int dsp563xx_read_memory_core(struct target *target, } switch (mem_type) { - case MEM_X: - /* TODO: mark effected queued registers */ - move_cmd = 0x61d800; - break; - case MEM_Y: - move_cmd = 0x69d800; - break; - case MEM_P: - move_cmd = 0x07d891; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case MEM_X: + /* TODO: mark effected queued registers */ + move_cmd = 0x61d800; + break; + case MEM_Y: + move_cmd = 0x69d800; + break; + case MEM_P: + move_cmd = 0x07d891; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } /* we use r0 to store temporary data */ @@ -1698,7 +1693,7 @@ static int dsp563xx_write_memory_core(struct target *target, const uint8_t *b; LOG_DEBUG( - "memtype: %d address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + "memtype: %d address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, mem_type, address, size, @@ -1710,19 +1705,19 @@ static int dsp563xx_write_memory_core(struct target *target, } switch (mem_type) { - case MEM_X: - /* invalidate affected x registers */ - dsp563xx_invalidate_x_context(target, address, address + count - 1); - move_cmd = 0x615800; - break; - case MEM_Y: - move_cmd = 0x695800; - break; - case MEM_P: - move_cmd = 0x075891; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case MEM_X: + /* invalidate affected x registers */ + dsp563xx_invalidate_x_context(target, address, address + count - 1); + move_cmd = 0x615800; + break; + case MEM_Y: + move_cmd = 0x695800; + break; + case MEM_P: + move_cmd = 0x075891; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } /* we use r0 to store temporary data */ @@ -1896,55 +1891,55 @@ static int dsp563xx_add_custom_watchpoint(struct target *target, uint32_t addres if (err == ERROR_OK) { obcr_value |= OBCR_B0_OR_B1; switch (mem_type) { - case MEM_X: - obcr_value |= OBCR_BP_MEM_X; - break; - case MEM_Y: - obcr_value |= OBCR_BP_MEM_Y; - break; - case MEM_P: - obcr_value |= OBCR_BP_MEM_P; - break; - default: - LOG_ERROR("Unknown mem_type parameter (%" PRIu32 ")", mem_type); - err = ERROR_TARGET_INVALID; + case MEM_X: + obcr_value |= OBCR_BP_MEM_X; + break; + case MEM_Y: + obcr_value |= OBCR_BP_MEM_Y; + break; + case MEM_P: + obcr_value |= OBCR_BP_MEM_P; + break; + default: + LOG_ERROR("Unknown mem_type parameter (%" PRIu32 ")", mem_type); + err = ERROR_TARGET_INVALID; } } if (err == ERROR_OK) { switch (rw) { - case WPT_READ: - obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ); - break; - case WPT_WRITE: - obcr_value |= OBCR_BP_0(OBCR_BP_ON_WRITE); - break; - case WPT_ACCESS: - obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ|OBCR_BP_ON_WRITE); - break; - default: - LOG_ERROR("Unsupported write mode (%d)", rw); - err = ERROR_TARGET_INVALID; + case WPT_READ: + obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ); + break; + case WPT_WRITE: + obcr_value |= OBCR_BP_0(OBCR_BP_ON_WRITE); + break; + case WPT_ACCESS: + obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ | OBCR_BP_ON_WRITE); + break; + default: + LOG_ERROR("Unsupported write mode (%d)", rw); + err = ERROR_TARGET_INVALID; } } if (err == ERROR_OK) { switch (cond) { - case EQUAL: - obcr_value |= OBCR_BP_0(OBCR_BP_CC_EQUAL); - break; - case NOT_EQUAL: - obcr_value |= OBCR_BP_0(OBCR_BP_CC_NOT_EQUAL); - break; - case LESS_THAN: - obcr_value |= OBCR_BP_0(OBCR_BP_CC_LESS_THAN); - break; - case GREATER: - obcr_value |= OBCR_BP_0(OBCR_BP_CC_GREATER_THAN); - break; - default: - LOG_ERROR("Unsupported condition code (%d)", cond); - err = ERROR_TARGET_INVALID; + case EQUAL: + obcr_value |= OBCR_BP_0(OBCR_BP_CC_EQUAL); + break; + case NOT_EQUAL: + obcr_value |= OBCR_BP_0(OBCR_BP_CC_NOT_EQUAL); + break; + case LESS_THAN: + obcr_value |= OBCR_BP_0(OBCR_BP_CC_LESS_THAN); + break; + case GREATER: + obcr_value |= OBCR_BP_0(OBCR_BP_CC_GREATER_THAN); + break; + default: + LOG_ERROR("Unsupported condition code (%d)", cond); + err = ERROR_TARGET_INVALID; } } @@ -2001,22 +1996,21 @@ static int dsp563xx_remove_custom_watchpoint(struct target *target) COMMAND_HANDLER(dsp563xx_add_watchpoint_command) { - int err = ERROR_OK; struct target *target = get_current_target(CMD_CTX); uint32_t mem_type = 0; switch (CMD_NAME[2]) { - case 'x': - mem_type = MEM_X; - break; - case 'y': - mem_type = MEM_Y; - break; - case 'p': - mem_type = MEM_P; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'x': + mem_type = MEM_X; + break; + case 'y': + mem_type = MEM_Y; + break; + case 'p': + mem_type = MEM_P; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC < 2) @@ -2028,40 +2022,38 @@ COMMAND_HANDLER(dsp563xx_add_watchpoint_command) enum watchpoint_condition cond; switch (CMD_ARGV[0][0]) { - case '>': - cond = GREATER; - break; - case '<': - cond = LESS_THAN; - break; - case '=': - cond = EQUAL; - break; - case '!': - cond = NOT_EQUAL; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case '>': + cond = GREATER; + break; + case '<': + cond = LESS_THAN; + break; + case '=': + cond = EQUAL; + break; + case '!': + cond = NOT_EQUAL; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } enum watchpoint_rw rw; switch (CMD_ARGV[1][0]) { - case 'r': - rw = WPT_READ; - break; - case 'w': - rw = WPT_WRITE; - break; - case 'a': - rw = WPT_ACCESS; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'r': + rw = WPT_READ; + break; + case 'w': + rw = WPT_WRITE; + break; + case 'a': + rw = WPT_ACCESS; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } - err = dsp563xx_add_custom_watchpoint(target, address, mem_type, rw, cond); - - return err; + return dsp563xx_add_custom_watchpoint(target, address, mem_type, rw, cond); } /* Adding a breakpoint using the once breakpoint logic. @@ -2097,28 +2089,28 @@ COMMAND_HANDLER(dsp563xx_mem_command) uint8_t *buffer, *b; switch (CMD_NAME[1]) { - case 'w': - read_mem = 0; - break; - case 'd': - read_mem = 1; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'w': + read_mem = 0; + break; + case 'd': + read_mem = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } switch (CMD_NAME[3]) { - case 'x': - mem_type = MEM_X; - break; - case 'y': - mem_type = MEM_Y; - break; - case 'p': - mem_type = MEM_P; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'x': + mem_type = MEM_X; + break; + case 'y': + mem_type = MEM_Y; + break; + case 'p': + mem_type = MEM_P; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC > 0) diff --git a/src/target/dsp5680xx.c b/src/target/dsp5680xx.c index 65efbae324..3dc2e01dc1 100644 --- a/src/target/dsp5680xx.c +++ b/src/target/dsp5680xx.c @@ -19,22 +19,13 @@ 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; } -#define err_check_propagate(retval) if (retval != ERROR_OK) return retval; +#define err_log(c, m) LOG_ERROR(_E, c, __func__, __LINE__, m) #define DEBUG_MSG "Debug mode be enabled to read mem." -#define DEBUG_FAIL { err_check(ERROR_FAIL, DSP5680XX_ERROR_NOT_IN_DEBUG, DEBUG_MSG) } -#define CHECK_DBG if (!dsp5680xx_context.debug_mode_enabled) DEBUG_FAIL #define HALT_MSG "Target must be halted." -#define HALT_FAIL { err_check(ERROR_FAIL, DSP5680XX_ERROR_TARGET_RUNNING, HALT_MSG) } -#define CHECK_HALT(target) if (target->state != TARGET_HALTED) HALT_FAIL -#define check_halt_and_debug(target) { CHECK_HALT(target); CHECK_DBG; } static int dsp5680xx_execute_queue(void) { - int retval; - - retval = jtag_execute_queue(); - return retval; + return jtag_execute_queue(); } /** @@ -42,20 +33,10 @@ static int dsp5680xx_execute_queue(void) */ static int reset_jtag(void) { - int retval; - - enum tap_state states[2]; - - const char *cp = "RESET"; - - states[0] = tap_state_by_name(cp); - retval = jtag_add_statemove(states[0]); - err_check_propagate(retval); - retval = jtag_execute_queue(); - err_check_propagate(retval); - jtag_add_pathmove(0, states + 1); - retval = jtag_execute_queue(); - return retval; + int retval = jtag_add_statemove(TAP_RESET); + if (retval != ERROR_OK) + return retval; + return jtag_execute_queue(); } static int dsp5680xx_drscan(struct target *target, uint8_t *d_in, @@ -72,32 +53,31 @@ static int dsp5680xx_drscan(struct target *target, uint8_t *d_in, * *-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */ - int retval = ERROR_OK; - if (!target->tap) { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_JTAG_INVALID_TAP, - "Invalid tap"); + err_log(DSP5680XX_ERROR_JTAG_INVALID_TAP, "Invalid tap"); + return ERROR_FAIL; } if (len > 32) { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_JTAG_DR_LEN_OVERFLOW, + err_log(DSP5680XX_ERROR_JTAG_DR_LEN_OVERFLOW, "dr_len overflow, maximum is 32"); + return ERROR_FAIL; } /* TODO what values of len are valid for jtag_add_plain_dr_scan? */ /* can i send as many bits as i want? */ /* is the casting necessary? */ jtag_add_plain_dr_scan(len, d_in, d_out, TAP_IDLE); if (dsp5680xx_context.flush) { - retval = dsp5680xx_execute_queue(); - err_check(retval, DSP5680XX_ERROR_JTAG_DRSCAN, - "drscan failed!"); + int retval = dsp5680xx_execute_queue(); + if (retval != ERROR_OK) { + err_log(DSP5680XX_ERROR_JTAG_DRSCAN, "drscan failed!"); + return retval; + } } if (d_out) LOG_DEBUG("Data read (%d bits): 0x%04X", len, *d_out); else LOG_DEBUG("Data read was discarded."); - return retval; + return ERROR_OK; } /** @@ -112,55 +92,49 @@ static int dsp5680xx_drscan(struct target *target, uint8_t *d_in, static int dsp5680xx_irscan(struct target *target, uint32_t *d_in, uint32_t *d_out, uint8_t ir_len) { - int retval = ERROR_OK; - uint16_t tap_ir_len = DSP5680XX_JTAG_MASTER_TAP_IRLEN; - if (!target->tap) { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_JTAG_INVALID_TAP, - "Invalid tap"); + if (!target || !target->tap) { + err_log(DSP5680XX_ERROR_JTAG_INVALID_TAP, "Invalid tap"); + return ERROR_FAIL; } if (ir_len != target->tap->ir_length) { if (target->tap->enabled) { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_INVALID_IR_LEN, - "Invalid irlen"); + err_log(DSP5680XX_ERROR_INVALID_IR_LEN, "Invalid irlen"); + return ERROR_FAIL; } else { struct jtag_tap *t = jtag_tap_by_string("dsp568013.chp"); if ((!t) || ((t->enabled) && (ir_len != tap_ir_len))) { - retval = ERROR_FAIL; - err_check(retval, - DSP5680XX_ERROR_INVALID_IR_LEN, - "Invalid irlen"); + err_log(DSP5680XX_ERROR_INVALID_IR_LEN, "Invalid irlen"); + return ERROR_FAIL; } } } jtag_add_plain_ir_scan(ir_len, (uint8_t *) d_in, (uint8_t *) d_out, TAP_IDLE); if (dsp5680xx_context.flush) { - retval = dsp5680xx_execute_queue(); - err_check(retval, DSP5680XX_ERROR_JTAG_IRSCAN, - "irscan failed!"); + int retval = dsp5680xx_execute_queue(); + if (retval != ERROR_OK) { + err_log(DSP5680XX_ERROR_JTAG_IRSCAN, "irscan failed!"); + return retval; + } } - return retval; + return ERROR_OK; } static int dsp5680xx_jtag_status(struct target *target, uint8_t *status) { uint32_t read_from_ir; - uint32_t instr; - - int retval; + uint32_t instr = JTAG_INSTR_ENABLE_ONCE; - instr = JTAG_INSTR_ENABLE_ONCE; - retval = + int retval = dsp5680xx_irscan(target, &instr, &read_from_ir, DSP5680XX_JTAG_CORE_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if (status) *status = (uint8_t) read_from_ir; return ERROR_OK; @@ -188,15 +162,14 @@ static uint32_t data_read_dummy; static int jtag_data_write(struct target *target, uint32_t instr, int num_bits, uint32_t *data_read) { - int retval; - - retval = + int retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &data_read_dummy, num_bits); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if (data_read) *data_read = data_read_dummy; - return retval; + return ERROR_OK; } #define jtag_data_write8(target, instr, data_read) jtag_data_write(target, instr, 8, data_read) @@ -220,17 +193,16 @@ static int eonce_instruction_exec_single(struct target *target, uint8_t instr, uint8_t rw, uint8_t go, uint8_t ex, uint8_t *eonce_status) { - int retval; - uint32_t dr_out_tmp; uint8_t instr_with_flags = instr | (rw << 7) | (go << 6) | (ex << 5); - retval = jtag_data_write(target, instr_with_flags, 8, &dr_out_tmp); - err_check_propagate(retval); + int retval = jtag_data_write(target, instr_with_flags, 8, &dr_out_tmp); + if (retval != ERROR_OK) + return retval; if (eonce_status) *eonce_status = (uint8_t) dr_out_tmp; - return retval; + return ERROR_OK; } /* wrappers for multi opcode instructions */ @@ -242,51 +214,48 @@ static int eonce_instruction_exec_single(struct target *target, uint8_t instr, /* Executes one word DSP instruction */ static int dsp5680xx_exe1(struct target *target, uint16_t opcode) { - int retval; - - retval = eonce_instruction_exec_single(target, 0x04, 0, 1, 0, NULL); - err_check_propagate(retval); - retval = jtag_data_write16(target, opcode, NULL); - err_check_propagate(retval); - return retval; + int retval = eonce_instruction_exec_single(target, 0x04, 0, 1, 0, NULL); + if (retval != ERROR_OK) + return retval; + return jtag_data_write16(target, opcode, NULL); } /* Executes two word DSP instruction */ static int dsp5680xx_exe2(struct target *target, uint16_t opcode1, uint16_t opcode2) { - int retval; - - retval = eonce_instruction_exec_single(target, 0x04, 0, 0, 0, NULL); - err_check_propagate(retval); + int retval = eonce_instruction_exec_single(target, 0x04, 0, 0, 0, NULL); + if (retval != ERROR_OK) + return retval; retval = jtag_data_write16(target, opcode1, NULL); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = eonce_instruction_exec_single(target, 0x04, 0, 1, 0, NULL); - err_check_propagate(retval); - retval = jtag_data_write16(target, opcode2, NULL); - err_check_propagate(retval); - return retval; + if (retval != ERROR_OK) + return retval; + return jtag_data_write16(target, opcode2, NULL); } /* Executes three word DSP instruction */ static int dsp5680xx_exe3(struct target *target, uint16_t opcode1, uint16_t opcode2, uint16_t opcode3) { - int retval; - - retval = eonce_instruction_exec_single(target, 0x04, 0, 0, 0, NULL); - err_check_propagate(retval); + int retval = eonce_instruction_exec_single(target, 0x04, 0, 0, 0, NULL); + if (retval != ERROR_OK) + return retval; retval = jtag_data_write16(target, opcode1, NULL); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = eonce_instruction_exec_single(target, 0x04, 0, 0, 0, NULL); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = jtag_data_write16(target, opcode2, NULL); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = eonce_instruction_exec_single(target, 0x04, 0, 1, 0, NULL); - err_check_propagate(retval); - retval = jtag_data_write16(target, opcode3, NULL); - err_check_propagate(retval); - return retval; + if (retval != ERROR_OK) + return retval; + return jtag_data_write16(target, opcode3, NULL); } /* @@ -305,15 +274,12 @@ static int dsp5680xx_exe3(struct target *target, uint16_t opcode1, static int core_tx_upper_data(struct target *target, uint16_t data, uint32_t *eonce_status_low) { - int retval; - - retval = + int retval = eonce_instruction_exec_single(target, DSP5680XX_ONCE_ORX1, 0, 0, 0, NULL); - err_check_propagate(retval); - retval = jtag_data_write16(target, data, eonce_status_low); - err_check_propagate(retval); - return retval; + if (retval != ERROR_OK) + return retval; + return jtag_data_write16(target, data, eonce_status_low); } /* writes data into lower ORx register of the target */ @@ -329,15 +295,12 @@ static int core_tx_upper_data(struct target *target, uint16_t data, */ static int core_rx_upper_data(struct target *target, uint8_t *data_read) { - int retval; - - retval = + int retval = eonce_instruction_exec_single(target, DSP5680XX_ONCE_OTX1, 1, 0, 0, NULL); - err_check_propagate(retval); - retval = jtag_data_read16(target, data_read); - err_check_propagate(retval); - return retval; + if (retval != ERROR_OK) + return retval; + return jtag_data_read16(target, data_read); } /** @@ -348,15 +311,12 @@ static int core_rx_upper_data(struct target *target, uint8_t *data_read) */ static int core_rx_lower_data(struct target *target, uint8_t *data_read) { - int retval; - - retval = + int retval = eonce_instruction_exec_single(target, DSP5680XX_ONCE_OTX, 1, 0, 0, NULL); - err_check_propagate(retval); - retval = jtag_data_read16(target, data_read); - err_check_propagate(retval); - return retval; + if (retval != ERROR_OK) + return retval; + return jtag_data_read16(target, data_read); } /* @@ -480,63 +440,54 @@ static int core_rx_lower_data(struct target *target, uint8_t *data_read) static int core_move_value_to_pc(struct target *target, uint32_t value) { - check_halt_and_debug(target); - int retval; + if (target->state != TARGET_HALTED) { + err_log(DSP5680XX_ERROR_TARGET_RUNNING, HALT_MSG); + return ERROR_FAIL; + } + if (!dsp5680xx_context.debug_mode_enabled) { + err_log(DSP5680XX_ERROR_NOT_IN_DEBUG, DEBUG_MSG); + return ERROR_FAIL; + } - retval = - dsp5680xx_exe_generic(target, 3, 0xE71E, value & 0xffff, + return dsp5680xx_exe_generic(target, 3, 0xE71E, value & 0xffff, value >> 16); - err_check_propagate(retval); - return retval; } static int eonce_load_tx_rx_to_r0(struct target *target) { - int retval; - - retval = - core_move_long_to_r0(target, + return core_move_long_to_r0(target, ((MC568013_EONCE_TX_RX_ADDR) + (MC568013_EONCE_OBASE_ADDR << 16))); - return retval; } static int core_load_tx_rx_high_addr_to_r0(struct target *target) { - int retval = 0; - - retval = - core_move_long_to_r0(target, + return core_move_long_to_r0(target, ((MC568013_EONCE_TX1_RX1_HIGH_ADDR) + (MC568013_EONCE_OBASE_ADDR << 16))); - return retval; } static int dsp5680xx_read_core_reg(struct target *target, uint8_t reg_addr, uint16_t *data_read) { /* TODO implement a general version of this which matches what openocd uses. */ - int retval; - uint32_t dummy_data_to_shift_into_dr; - retval = eonce_instruction_exec_single(target, reg_addr, 1, 0, 0, NULL); - err_check_propagate(retval); + int retval = eonce_instruction_exec_single(target, reg_addr, 1, 0, 0, NULL); + if (retval != ERROR_OK) + return retval; retval = dsp5680xx_drscan(target, (uint8_t *) &dummy_data_to_shift_into_dr, (uint8_t *) data_read, 8); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; LOG_DEBUG("Reg. data: 0x%02X.", *data_read); - return retval; + return ERROR_OK; } static int eonce_read_status_reg(struct target *target, uint16_t *data) { - int retval; - - retval = dsp5680xx_read_core_reg(target, DSP5680XX_ONCE_OSR, data); - err_check_propagate(retval); - return retval; + return dsp5680xx_read_core_reg(target, DSP5680XX_ONCE_OSR, data); } /** @@ -549,12 +500,7 @@ static int eonce_read_status_reg(struct target *target, uint16_t *data) */ static int eonce_exit_debug_mode(struct target *target, uint8_t *eonce_status) { - int retval; - - retval = - eonce_instruction_exec_single(target, 0x1F, 0, 0, 1, eonce_status); - err_check_propagate(retval); - return retval; + return eonce_instruction_exec_single(target, 0x1F, 0, 0, 1, eonce_status); } static int switch_tap(struct target *target, struct jtag_tap *master_tap, @@ -569,19 +515,18 @@ static int switch_tap(struct target *target, struct jtag_tap *master_tap, if (!master_tap) { master_tap = jtag_tap_by_string("dsp568013.chp"); if (!master_tap) { - retval = ERROR_FAIL; const char *msg = "Failed to get master tap."; - err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER, - msg); + err_log(DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER, msg); + return ERROR_FAIL; } } if (!core_tap) { core_tap = jtag_tap_by_string("dsp568013.cpu"); if (!core_tap) { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_CORE, + err_log(DSP5680XX_ERROR_JTAG_TAP_FIND_CORE, "Failed to get core tap."); + return ERROR_FAIL; } } @@ -596,12 +541,14 @@ static int switch_tap(struct target *target, struct jtag_tap *master_tap, retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; instr = 0x2; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 4); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; core_tap->enabled = true; master_tap->enabled = false; } else { @@ -609,16 +556,18 @@ static int switch_tap(struct target *target, struct jtag_tap *master_tap, retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; instr = 0x1; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 4); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; core_tap->enabled = false; master_tap->enabled = true; } - return retval; + return ERROR_OK; } /** @@ -638,17 +587,16 @@ static int switch_tap(struct target *target, struct jtag_tap *master_tap, static int eonce_enter_debug_mode_without_reset(struct target *target, uint16_t *eonce_status) { - int retval; - uint32_t instr = JTAG_INSTR_DEBUG_REQUEST; uint32_t ir_out; /* not used, just to make jtag happy.*/ /* Debug request #1 */ - retval = + int retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* Enable EOnCE module */ instr = JTAG_INSTR_ENABLE_ONCE; @@ -656,37 +604,37 @@ static int eonce_enter_debug_mode_without_reset(struct target *target, retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if ((ir_out & JTAG_STATUS_MASK) == JTAG_STATUS_DEBUG) target->state = TARGET_HALTED; else { - retval = ERROR_FAIL; - err_check_propagate(retval); + return ERROR_FAIL; } /* Verify that debug mode is enabled */ uint16_t data_read_from_dr; retval = eonce_read_status_reg(target, &data_read_from_dr); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if ((data_read_from_dr & 0x30) == 0x30) { LOG_DEBUG("EOnCE successfully entered debug mode."); dsp5680xx_context.debug_mode_enabled = true; - retval = ERROR_OK; } else { dsp5680xx_context.debug_mode_enabled = false; - retval = ERROR_TARGET_FAILURE; /** *No error msg here, since there is still hope with full halting sequence */ - err_check_propagate(retval); + return ERROR_TARGET_FAILURE; } if (eonce_status) *eonce_status = data_read_from_dr; - return retval; + return ERROR_OK; } /** @@ -700,8 +648,6 @@ static int eonce_enter_debug_mode_without_reset(struct target *target, static int eonce_enter_debug_mode(struct target *target, uint16_t *eonce_status) { - int retval = ERROR_OK; - uint32_t instr = JTAG_INSTR_DEBUG_REQUEST; uint32_t ir_out; /* not used, just to make jtag happy. */ @@ -711,25 +657,21 @@ static int eonce_enter_debug_mode(struct target *target, uint16_t read_16; /* First try the easy way */ - retval = eonce_enter_debug_mode_without_reset(target, eonce_status); + int retval = eonce_enter_debug_mode_without_reset(target, eonce_status); if (retval == ERROR_OK) return retval; - struct jtag_tap *tap_chp; - - struct jtag_tap *tap_cpu; - - tap_chp = jtag_tap_by_string("dsp568013.chp"); + struct jtag_tap *tap_chp = jtag_tap_by_string("dsp568013.chp"); if (!tap_chp) { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER, + err_log(DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER, "Failed to get master tap."); + return ERROR_FAIL; } - tap_cpu = jtag_tap_by_string("dsp568013.cpu"); + struct jtag_tap *tap_cpu = jtag_tap_by_string("dsp568013.cpu"); if (!tap_cpu) { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_CORE, + err_log(DSP5680XX_ERROR_JTAG_TAP_FIND_CORE, "Failed to get master tap."); + return ERROR_FAIL; } /* Enable master tap */ tap_chp->enabled = true; @@ -739,7 +681,8 @@ static int eonce_enter_debug_mode(struct target *target, retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); /* Enable EOnCE module */ @@ -749,35 +692,41 @@ static int eonce_enter_debug_mode(struct target *target, retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 32); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* ir_out now hold tap idcode */ /* Enable core tap */ tap_chp->enabled = true; retval = switch_tap(target, tap_chp, tap_cpu); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; instr = JTAG_INSTR_ENABLE_ONCE; /* Two rounds of jtag 0x6 (enable eonce) to enable EOnCE. */ retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; instr = JTAG_INSTR_DEBUG_REQUEST; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; instr_16 = 0x1; retval = dsp5680xx_drscan(target, (uint8_t *) &instr_16, (uint8_t *) &read_16, 8); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; instr_16 = 0x20; retval = dsp5680xx_drscan(target, (uint8_t *) &instr_16, (uint8_t *) &read_16, 8); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); @@ -788,14 +737,14 @@ static int eonce_enter_debug_mode(struct target *target, retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; } if ((ir_out & JTAG_STATUS_MASK) == JTAG_STATUS_DEBUG) target->state = TARGET_HALTED; else { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_HALT, - "Failed to halt target."); + err_log(DSP5680XX_ERROR_HALT, "Failed to halt target."); + return ERROR_FAIL; } for (int i = 0; i < 3; i++) { @@ -811,20 +760,20 @@ static int eonce_enter_debug_mode(struct target *target, uint16_t data_read_from_dr; retval = eonce_read_status_reg(target, &data_read_from_dr); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if ((data_read_from_dr & 0x30) == 0x30) { LOG_DEBUG("EOnCE successfully entered debug mode."); dsp5680xx_context.debug_mode_enabled = true; - retval = ERROR_OK; } else { const char *msg = "Failed to set EOnCE module to debug mode"; - retval = ERROR_TARGET_FAILURE; - err_check(retval, DSP5680XX_ERROR_ENTER_DEBUG_MODE, msg); + err_log(DSP5680XX_ERROR_ENTER_DEBUG_MODE, msg); + return ERROR_TARGET_FAILURE; } if (eonce_status) *eonce_status = data_read_from_dr; - return retval; + return ERROR_OK; } /** @@ -838,18 +787,21 @@ static int eonce_pc_store(struct target *target) { uint8_t tmp[2]; - int retval; - - retval = core_move_pc_to_r4(target); - err_check_propagate(retval); + int retval = core_move_pc_to_r4(target); + if (retval != ERROR_OK) + return retval; retval = core_move_r4_to_y(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = eonce_load_tx_rx_to_r0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_y0_at_r0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_rx_lower_data(target, tmp); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; LOG_USER("PC value: 0x%X%X\n", tmp[1], tmp[0]); dsp5680xx_context.stored_pc = (tmp[0] | (tmp[1] << 8)); return ERROR_OK; @@ -895,8 +847,6 @@ static int dsp5680xx_deassert_reset(struct target *target) static int dsp5680xx_halt(struct target *target) { - int retval; - uint16_t eonce_status = 0xbeef; if ((target->state == TARGET_HALTED) @@ -908,33 +858,34 @@ static int dsp5680xx_halt(struct target *target) LOG_USER ("Target already halted, re attempting to enter debug mode."); } - retval = eonce_enter_debug_mode(target, &eonce_status); - err_check_propagate(retval); + int retval = eonce_enter_debug_mode(target, &eonce_status); + if (retval != ERROR_OK) + return retval; retval = eonce_pc_store(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if (dsp5680xx_context.debug_mode_enabled) { retval = eonce_pc_store(target); - err_check_propagate(retval); } return retval; } static int dsp5680xx_poll(struct target *target) { - int retval; - uint8_t jtag_status; uint8_t eonce_status; uint16_t read_tmp; - retval = dsp5680xx_jtag_status(target, &jtag_status); - err_check_propagate(retval); + int retval = dsp5680xx_jtag_status(target, &jtag_status); + if (retval != ERROR_OK) + return retval; if (jtag_status == JTAG_STATUS_DEBUG) if (target->state != TARGET_HALTED) { retval = eonce_enter_debug_mode(target, &read_tmp); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; eonce_status = (uint8_t) read_tmp; if ((eonce_status & EONCE_STAT_MASK) != DSP5680XX_ONCE_OSCR_DEBUG_M) { @@ -950,9 +901,11 @@ static int dsp5680xx_poll(struct target *target) if (jtag_status == JTAG_STATUS_NORMAL) { if (target->state == TARGET_RESET) { retval = dsp5680xx_halt(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = eonce_exit_debug_mode(target, &eonce_status); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if ((eonce_status & EONCE_STAT_MASK) != DSP5680XX_ONCE_OSCR_NORMAL_M) { const char *msg = @@ -966,7 +919,8 @@ static int dsp5680xx_poll(struct target *target) } if (target->state != TARGET_RUNNING) { retval = eonce_read_status_reg(target, &read_tmp); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; eonce_status = (uint8_t) read_tmp; if ((eonce_status & EONCE_STAT_MASK) != DSP5680XX_ONCE_OSCR_NORMAL_M) { @@ -1009,21 +963,23 @@ static int dsp5680xx_resume(struct target *target, bool current, if (dsp5680xx_context.debug_mode_enabled) { if (!current) { retval = core_move_value_to_pc(target, address); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; } int retry = 20; while (retry-- > 1) { retval = eonce_exit_debug_mode(target, &eonce_status); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if (eonce_status == DSP5680XX_ONCE_OSCR_NORMAL_M) break; } if (retry == 0) { - retval = ERROR_TARGET_FAILURE; - err_check(retval, DSP5680XX_ERROR_EXIT_DEBUG_MODE, + err_log(DSP5680XX_ERROR_EXIT_DEBUG_MODE, "Failed to exit debug mode..."); + return ERROR_TARGET_FAILURE; } else { target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; @@ -1039,20 +995,23 @@ static int dsp5680xx_resume(struct target *target, bool current, jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); - err_check(retval, DSP5680XX_ERROR_JTAG_RESET, - "Failed to reset JTAG state machine"); + if (retval != ERROR_OK) { + err_log(DSP5680XX_ERROR_JTAG_RESET, + "Failed to reset JTAG state machine"); + return retval; + } jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); retval = dsp5680xx_jtag_status(target, &jtag_status); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if ((jtag_status & JTAG_STATUS_MASK) == JTAG_STATUS_NORMAL) { target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; } else { - retval = ERROR_TARGET_FAILURE; - err_check(retval, DSP5680XX_ERROR_RESUME, - "Failed to resume target"); + err_log(DSP5680XX_ERROR_RESUME, "Failed to resume target"); + return ERROR_TARGET_FAILURE; } } return ERROR_OK; @@ -1090,25 +1049,28 @@ static int dsp5680xx_read_16_single(struct target *t, uint32_t a, uint32_t address = a; - int retval; - - retval = core_move_long_to_r0(target, address); - err_check_propagate(retval); + int retval = core_move_long_to_r0(target, address); + if (retval != ERROR_OK) + return retval; if (r_pmem) retval = core_move_at_pr0_inc_to_y0(target); else retval = core_move_at_r0_to_y0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = eonce_load_tx_rx_to_r0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_y0_at_r0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* at this point the data i want is at the reg eonce can read */ retval = core_rx_lower_data(target, data_read); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; LOG_DEBUG("%s:Data read from 0x%06" PRIX32 ": 0x%02X%02X", __func__, address, data_read[1], data_read[0]); - return retval; + return ERROR_OK; } static int dsp5680xx_read_32_single(struct target *t, uint32_t a, @@ -1118,37 +1080,42 @@ static int dsp5680xx_read_32_single(struct target *t, uint32_t a, uint32_t address = a; - int retval; - address = (address & 0xFFFFF); /* Get data to an intermediate register */ - retval = core_move_long_to_r0(target, address); - err_check_propagate(retval); + int retval = core_move_long_to_r0(target, address); + if (retval != ERROR_OK) + return retval; if (r_pmem) { retval = core_move_at_pr0_inc_to_y0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_at_pr0_inc_to_y1(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; } else { retval = core_move_at_r0_inc_to_y0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_at_r0_to_y1(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; } /* Get lower part of data to TX/RX */ retval = eonce_load_tx_rx_to_r0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_y0_at_r0_inc(target); /* This also load TX/RX high to r0 */ - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* Get upper part of data to TX/RX */ retval = core_move_y1_at_r0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* at this point the data i want is at the reg eonce can read */ retval = core_rx_lower_data(target, data_read); - err_check_propagate(retval); - retval = core_rx_upper_data(target, data_read + 2); - err_check_propagate(retval); - return retval; + if (retval != ERROR_OK) + return retval; + return core_rx_upper_data(target, data_read + 2); } static int dsp5680xx_read(struct target *t, target_addr_t a, uint32_t size, @@ -1160,14 +1127,20 @@ static int dsp5680xx_read(struct target *t, target_addr_t a, uint32_t size, uint8_t *buffer = buf; - check_halt_and_debug(target); - - int retval = ERROR_OK; + if (target->state != TARGET_HALTED) { + err_log(DSP5680XX_ERROR_TARGET_RUNNING, HALT_MSG); + return ERROR_FAIL; + } + if (!dsp5680xx_context.debug_mode_enabled) { + err_log(DSP5680XX_ERROR_NOT_IN_DEBUG, DEBUG_MSG); + return ERROR_FAIL; + } int pmem = 1; - retval = dsp5680xx_convert_address(&address, &pmem); - err_check_propagate(retval); + int retval = dsp5680xx_convert_address(&address, &pmem); + if (retval != ERROR_OK) + return retval; dsp5680xx_context.flush = 0; int counter = FLUSH_COUNT_READ_WRITE; @@ -1199,15 +1172,13 @@ static int dsp5680xx_read(struct target *t, target_addr_t a, uint32_t size, LOG_USER("%s: Invalid read size.", __func__); break; } - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; - retval = dsp5680xx_execute_queue(); - err_check_propagate(retval); - - return retval; + return dsp5680xx_execute_queue(); } static int dsp5680xx_write_16_single(struct target *t, uint32_t a, @@ -1217,18 +1188,16 @@ static int dsp5680xx_write_16_single(struct target *t, uint32_t a, uint32_t address = a; - int retval = 0; - - retval = core_move_long_to_r0(target, address); - err_check_propagate(retval); + int retval = core_move_long_to_r0(target, address); + if (retval != ERROR_OK) + return retval; if (w_pmem) { retval = core_move_value_to_y0(target, data); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_y0_at_pr0_inc(target); - err_check_propagate(retval); } else { retval = core_move_value_at_r0(target, data); - err_check_propagate(retval); } return retval; } @@ -1240,22 +1209,22 @@ static int dsp5680xx_write_32_single(struct target *t, uint32_t a, uint32_t address = a; - int retval = ERROR_OK; - - retval = core_move_long_to_r0(target, address); - err_check_propagate(retval); + int retval = core_move_long_to_r0(target, address); + if (retval != ERROR_OK) + return retval; retval = core_move_long_to_y(target, data); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if (w_pmem) retval = core_move_y0_at_pr0_inc(target); else retval = core_move_y0_at_r0_inc(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if (w_pmem) retval = core_move_y1_at_pr0_inc(target); else retval = core_move_y1_at_r0_inc(target); - err_check_propagate(retval); return retval; } @@ -1305,7 +1274,8 @@ static int dsp5680xx_write_8(struct target *t, uint32_t a, uint32_t c, retval = dsp5680xx_read(target, address + iter, 1, 1, (uint8_t *) &data_old); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if (count == 1) data_old = (((data_old & 0xff) << 8) | data[0]); /* preserve upper byte */ else @@ -1314,7 +1284,6 @@ static int dsp5680xx_write_8(struct target *t, uint32_t a, uint32_t c, retval = dsp5680xx_write_16_single(target, address + iter, data_old, pmem); - err_check_propagate(retval); } return retval; } @@ -1330,8 +1299,6 @@ static int dsp5680xx_write_16(struct target *t, uint32_t a, uint32_t c, const uint8_t *data = d; - int retval = ERROR_OK; - uint32_t iter; int counter = FLUSH_COUNT_READ_WRITE; @@ -1341,7 +1308,7 @@ static int dsp5680xx_write_16(struct target *t, uint32_t a, uint32_t c, dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_READ_WRITE; } - retval = + int retval = dsp5680xx_write_16_single(target, address + iter, data[iter], pmem); if (retval != ERROR_OK) { @@ -1353,7 +1320,7 @@ static int dsp5680xx_write_16(struct target *t, uint32_t a, uint32_t c, dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; - return retval; + return ERROR_OK; } static int dsp5680xx_write_32(struct target *t, uint32_t a, uint32_t c, @@ -1367,8 +1334,6 @@ static int dsp5680xx_write_32(struct target *t, uint32_t a, uint32_t c, const uint8_t *data = d; - int retval = ERROR_OK; - uint32_t iter; int counter = FLUSH_COUNT_READ_WRITE; @@ -1378,7 +1343,7 @@ static int dsp5680xx_write_32(struct target *t, uint32_t a, uint32_t c, dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_READ_WRITE; } - retval = + int retval = dsp5680xx_write_32_single(target, address + (iter << 1), data[iter], pmem); if (retval != ERROR_OK) { @@ -1390,7 +1355,7 @@ static int dsp5680xx_write_32(struct target *t, uint32_t a, uint32_t c, dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; - return retval; + return ERROR_OK; } /** @@ -1414,14 +1379,20 @@ static int dsp5680xx_write(struct target *target, target_addr_t a, uint32_t size uint8_t const *buffer = b; - check_halt_and_debug(target); - - int retval = 0; + if (target->state != TARGET_HALTED) { + err_log(DSP5680XX_ERROR_TARGET_RUNNING, HALT_MSG); + return ERROR_FAIL; + } + if (!dsp5680xx_context.debug_mode_enabled) { + err_log(DSP5680XX_ERROR_NOT_IN_DEBUG, DEBUG_MSG); + return ERROR_FAIL; + } int p_mem = 1; - retval = dsp5680xx_convert_address(&address, &p_mem); - err_check_propagate(retval); + int retval = dsp5680xx_convert_address(&address, &p_mem); + if (retval != ERROR_OK) + return retval; switch (size) { case 1: @@ -1437,10 +1408,8 @@ static int dsp5680xx_write(struct target *target, target_addr_t a, uint32_t size dsp5680xx_write_32(target, address, count, buffer, p_mem); break; default: - retval = ERROR_TARGET_DATA_ABORT; - err_check(retval, DSP5680XX_ERROR_INVALID_DATA_SIZE_UNIT, - "Invalid data size."); - break; + err_log(DSP5680XX_ERROR_INVALID_DATA_SIZE_UNIT, "Invalid data size."); + return ERROR_TARGET_DATA_ABORT; } return retval; } @@ -1448,7 +1417,14 @@ static int dsp5680xx_write(struct target *target, target_addr_t a, uint32_t size static int dsp5680xx_write_buffer(struct target *t, target_addr_t a, uint32_t size, const uint8_t *b) { - check_halt_and_debug(t); + if (t->state != TARGET_HALTED) { + err_log(DSP5680XX_ERROR_TARGET_RUNNING, HALT_MSG); + return ERROR_FAIL; + } + if (!dsp5680xx_context.debug_mode_enabled) { + err_log(DSP5680XX_ERROR_NOT_IN_DEBUG, DEBUG_MSG); + return ERROR_FAIL; + } return dsp5680xx_write(t, a, 1, size, b); } @@ -1465,7 +1441,15 @@ static int dsp5680xx_write_buffer(struct target *t, target_addr_t a, uint32_t si static int dsp5680xx_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { - check_halt_and_debug(target); + if (target->state != TARGET_HALTED) { + err_log(DSP5680XX_ERROR_TARGET_RUNNING, HALT_MSG); + return ERROR_FAIL; + } + if (!dsp5680xx_context.debug_mode_enabled) { + err_log(DSP5680XX_ERROR_NOT_IN_DEBUG, DEBUG_MSG); + return ERROR_FAIL; + } + /* The "/2" solves the byte/word addressing issue.*/ return dsp5680xx_read(target, address, 2, size / 2, buffer); } @@ -1534,20 +1518,14 @@ static int perl_crc(const uint8_t *buff8, uint32_t word_count) */ static int dsp5680xx_f_sim_reset(struct target *target) { - int retval = ERROR_OK; - uint16_t sim_cmd = SIM_CMD_RESET; - uint32_t sim_addr; - if (strcmp(target->tap->chip, "dsp568013") == 0) { - sim_addr = MC568013_SIM_BASE_ADDR + S_FILE_DATA_OFFSET; - retval = - dsp5680xx_write(target, sim_addr, 1, 2, + uint32_t sim_addr = MC568013_SIM_BASE_ADDR + S_FILE_DATA_OFFSET; + return dsp5680xx_write(target, sim_addr, 1, 2, (const uint8_t *)&sim_cmd); - err_check_propagate(retval); } - return retval; + return ERROR_OK; } /** @@ -1560,31 +1538,30 @@ static int dsp5680xx_f_sim_reset(struct target *target) static int dsp5680xx_soft_reset_halt(struct target *target) { /* TODO is this what this function is expected to do...? */ - int retval; - - retval = dsp5680xx_halt(target); - err_check_propagate(retval); - retval = dsp5680xx_f_sim_reset(target); - err_check_propagate(retval); - return retval; + int retval = dsp5680xx_halt(target); + if (retval != ERROR_OK) + return retval; + return dsp5680xx_f_sim_reset(target); } int dsp5680xx_f_protect_check(struct target *target, uint16_t *protected) { - int retval; - - check_halt_and_debug(target); + if (target->state != TARGET_HALTED) { + err_log(DSP5680XX_ERROR_TARGET_RUNNING, HALT_MSG); + return ERROR_FAIL; + } + if (!dsp5680xx_context.debug_mode_enabled) { + err_log(DSP5680XX_ERROR_NOT_IN_DEBUG, DEBUG_MSG); + return ERROR_FAIL; + } if (!protected) { const char *msg = "NULL pointer not valid."; - err_check(ERROR_FAIL, - DSP5680XX_ERROR_PROTECT_CHECK_INVALID_ARGS, msg); + err_log(DSP5680XX_ERROR_PROTECT_CHECK_INVALID_ARGS, msg); + return ERROR_FAIL; } - retval = - dsp5680xx_read_16_single(target, HFM_BASE_ADDR | HFM_PROT, + return dsp5680xx_read_16_single(target, HFM_BASE_ADDR | HFM_PROT, (uint8_t *) protected, 0); - err_check_propagate(retval); - return retval; } /** @@ -1604,28 +1581,32 @@ static int dsp5680xx_f_ex(struct target *target, uint16_t c, uint32_t address, u uint16_t *hfm_ustat, int pmem) { uint32_t command = c; - int retval; - retval = core_load_tx_rx_high_addr_to_r0(target); - err_check_propagate(retval); + int retval = core_load_tx_rx_high_addr_to_r0(target); + if (retval != ERROR_OK) + return retval; retval = core_move_long_to_r2(target, HFM_BASE_ADDR); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; uint8_t i[2]; int watchdog = 100; do { retval = core_move_at_r2_disp_to_y0(target, HFM_USTAT); /* read HMF_USTAT */ - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_y0_at_r0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_rx_upper_data(target, i); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if ((watchdog--) == 1) { - retval = ERROR_TARGET_FAILURE; const char *msg = "Timed out waiting for FM to finish old command."; - err_check(retval, DSP5680XX_ERROR_FM_BUSY, msg); + err_log(DSP5680XX_ERROR_FM_BUSY, msg); + return ERROR_TARGET_FAILURE; } } while (!(i[0] & 0x40)); /* wait until current command is complete */ @@ -1633,65 +1614,79 @@ static int dsp5680xx_f_ex(struct target *target, uint16_t c, uint32_t address, u /* write to HFM_CNFG (lock=0,select bank) - flash_desc.bank&0x03, 0x01 == 0x00, 0x01 ??? */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_CNFG); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* write to HMF_USTAT, clear PVIOL, ACCERR &BLANK bits */ retval = core_move_value_at_r2_disp(target, 0x04, HFM_USTAT); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* clear only one bit at a time */ retval = core_move_value_at_r2_disp(target, 0x10, HFM_USTAT); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_value_at_r2_disp(target, 0x20, HFM_USTAT); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* write to HMF_PROT, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROT); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* write to HMF_PROTB, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROTB); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_value_to_y0(target, data); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* write to the flash block */ retval = core_move_long_to_r3(target, address); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if (pmem) { retval = core_move_y0_at_pr3_inc(target); - err_check_propagate(retval); } else { retval = core_move_y0_at_r3(target); - err_check_propagate(retval); } + if (retval != ERROR_OK) + return retval; /* write command to the HFM_CMD reg */ retval = core_move_value_at_r2_disp(target, command, HFM_CMD); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* start the command */ retval = core_move_value_at_r2_disp(target, 0x80, HFM_USTAT); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; dsp5680xx_context.flush = 1; retval = dsp5680xx_execute_queue(); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; watchdog = 100; do { /* read HMF_USTAT */ retval = core_move_at_r2_disp_to_y0(target, HFM_USTAT); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_y0_at_r0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_rx_upper_data(target, i); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if ((watchdog--) == 1) { - retval = ERROR_TARGET_FAILURE; - err_check(retval, DSP5680XX_ERROR_FM_CMD_TIMED_OUT, + err_log(DSP5680XX_ERROR_FM_CMD_TIMED_OUT, "FM execution did not finish."); + return ERROR_TARGET_FAILURE; } } while (!(i[0] & 0x40)); /* wait until the command is complete */ *hfm_ustat = ((i[0] << 8) | (i[1])); if (i[0] & HFM_USTAT_MASK_PVIOL_ACCER) { - retval = ERROR_TARGET_FAILURE; const char *msg = "pviol and/or accer bits set. HFM command execution error"; - err_check(retval, DSP5680XX_ERROR_FM_EXEC, msg); + err_log(DSP5680XX_ERROR_FM_EXEC, msg); + return ERROR_TARGET_FAILURE; } return ERROR_OK; } @@ -1712,19 +1707,22 @@ static int set_fm_ck_div(struct target *target) { uint8_t i[2]; - int retval; - - retval = core_move_long_to_r2(target, HFM_BASE_ADDR); - err_check_propagate(retval); + int retval = core_move_long_to_r2(target, HFM_BASE_ADDR); + if (retval != ERROR_OK) + return retval; retval = core_load_tx_rx_high_addr_to_r0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* read HFM_CLKD */ retval = core_move_at_r2_to_y0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_y0_at_r0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_rx_upper_data(target, i); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; unsigned int hfm_at_wrong_value = 0; if ((i[0] & 0x7f) != HFM_CLK_DEFAULT) { @@ -1739,18 +1737,21 @@ static int set_fm_ck_div(struct target *target) } /* write HFM_CLKD */ retval = core_move_value_at_r2(target, HFM_CLK_DEFAULT); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* verify HFM_CLKD */ retval = core_move_at_r2_to_y0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_y0_at_r0(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_rx_upper_data(target, i); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if (i[0] != (0x80 | (HFM_CLK_DEFAULT & 0x7f))) { - retval = ERROR_TARGET_FAILURE; - err_check(retval, DSP5680XX_ERROR_FM_SET_CLK, - "Unable to set HFM CLK divisor."); + err_log(DSP5680XX_ERROR_FM_SET_CLK, "Unable to set HFM CLK divisor."); + return ERROR_TARGET_FAILURE; } if (hfm_at_wrong_value) LOG_DEBUG("HFM CLK divisor set to 0x%02x.", i[0] & 0x7f); @@ -1783,17 +1784,18 @@ static int dsp5680xx_f_signature(struct target *target, uint32_t address, uint32 /* * Generate error here, since it is not done in eonce_enter_debug_mode_without_reset */ - err_check(retval, DSP5680XX_ERROR_HALT, - "Failed to halt target."); + if (retval != ERROR_OK) { + err_log(DSP5680XX_ERROR_HALT, "Failed to halt target."); + return retval; + } } retval = dsp5680xx_f_ex(target, HFM_CALCULATE_DATA_SIGNATURE, address, words, &hfm_ustat, 1); - err_check_propagate(retval); - retval = - dsp5680xx_read_16_single(target, HFM_BASE_ADDR | HFM_DATA, + if (retval != ERROR_OK) + return retval; + return dsp5680xx_read_16_single(target, HFM_BASE_ADDR | HFM_DATA, (uint8_t *) signature, 0); - return retval; } int dsp5680xx_f_erase_check(struct target *target, uint8_t *erased, @@ -1807,20 +1809,23 @@ int dsp5680xx_f_erase_check(struct target *target, uint8_t *erased, if (!dsp5680xx_context.debug_mode_enabled) { retval = dsp5680xx_halt(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; } retval = set_fm_ck_div(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* * Check if chip is already erased. */ tmp = HFM_FLASH_BASE_ADDR + sector * HFM_SECTOR_SIZE / 2; retval = dsp5680xx_f_ex(target, HFM_ERASE_VERIFY, tmp, 0, &hfm_ustat, 1); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if (erased) *erased = (uint8_t) (hfm_ustat & HFM_USTAT_MASK_BLANK); - return retval; + return ERROR_OK; } /** @@ -1834,13 +1839,9 @@ int dsp5680xx_f_erase_check(struct target *target, uint8_t *erased, */ static int erase_sector(struct target *target, int sector, uint16_t *hfm_ustat) { - int retval; - uint32_t tmp = HFM_FLASH_BASE_ADDR + sector * HFM_SECTOR_SIZE / 2; - retval = dsp5680xx_f_ex(target, HFM_PAGE_ERASE, tmp, 0, hfm_ustat, 1); - err_check_propagate(retval); - return retval; + return dsp5680xx_f_ex(target, HFM_PAGE_ERASE, tmp, 0, hfm_ustat, 1); } /** @@ -1853,10 +1854,7 @@ static int erase_sector(struct target *target, int sector, uint16_t *hfm_ustat) */ static int mass_erase(struct target *target, uint16_t *hfm_ustat) { - int retval; - - retval = dsp5680xx_f_ex(target, HFM_MASS_ERASE, 0, 0, hfm_ustat, 1); - return retval; + return dsp5680xx_f_ex(target, HFM_MASS_ERASE, 0, 0, hfm_ustat, 1); } int dsp5680xx_f_erase(struct target *target, int first, int last) @@ -1865,20 +1863,23 @@ int dsp5680xx_f_erase(struct target *target, int first, int last) if (!dsp5680xx_context.debug_mode_enabled) { retval = dsp5680xx_halt(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; } /* * Reset SIM * */ retval = dsp5680xx_f_sim_reset(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* * Set hfmdiv * */ retval = set_fm_ck_div(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; uint16_t hfm_ustat; @@ -1888,11 +1889,13 @@ int dsp5680xx_f_erase(struct target *target, int first, int last) if (do_mass_erase) { /* Mass erase */ retval = mass_erase(target, &hfm_ustat); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; } else { for (int i = first; i <= last; i++) { retval = erase_sector(target, i, &hfm_ustat); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; } } return ERROR_OK; @@ -1966,7 +1969,8 @@ int dsp5680xx_f_wr(struct target *t, const uint8_t *b, uint32_t a, uint32_t coun if (!dsp5680xx_context.debug_mode_enabled) { retval = eonce_enter_debug_mode(target, NULL); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; } /* * Download the pgm that flashes. @@ -1984,16 +1988,19 @@ int dsp5680xx_f_wr(struct target *t, const uint8_t *b, uint32_t a, uint32_t coun retval = dsp5680xx_write(target, ram_addr, 1, len * 2, (uint8_t *) pgm_write_pflash); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = dsp5680xx_execute_queue(); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; } /* * Set hfmdiv * */ retval = set_fm_ck_div(target); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* * Setup registers needed by pgm_write_pflash * @@ -2002,54 +2009,65 @@ int dsp5680xx_f_wr(struct target *t, const uint8_t *b, uint32_t a, uint32_t coun dsp5680xx_context.flush = 0; 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 */ - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; + retval = core_load_tx_rx_high_addr_to_r0(target); /* TX/RX reg address to r0 */ + if (retval != ERROR_OK) + return retval; retval = core_move_long_to_r2(target, HFM_BASE_ADDR); /* FM base address to r2 */ - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* * Run flashing program. * */ /* write to HFM_CNFG (lock=0, select bank) */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_CNFG); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* write to HMF_USTAT, clear PVIOL, ACCERR &BLANK bits */ retval = core_move_value_at_r2_disp(target, 0x04, HFM_USTAT); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* clear only one bit at a time */ retval = core_move_value_at_r2_disp(target, 0x10, HFM_USTAT); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = core_move_value_at_r2_disp(target, 0x20, HFM_USTAT); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* write to HMF_PROT, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROT); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* write to HMF_PROTB, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROTB); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; if (count % 2) { /* TODO implement handling of odd number of words. */ - retval = ERROR_FAIL; const char *msg = "Cannot handle odd number of words."; - err_check(retval, DSP5680XX_ERROR_FLASHING_INVALID_WORD_COUNT, - msg); + err_log(DSP5680XX_ERROR_FLASHING_INVALID_WORD_COUNT, msg); + return ERROR_FAIL; } dsp5680xx_context.flush = 1; retval = dsp5680xx_execute_queue(); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; uint32_t drscan_data; uint16_t tmp = (buffer[0] | (buffer[1] << 8)); retval = core_tx_upper_data(target, tmp, &drscan_data); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; retval = dsp5680xx_resume(target, false, ram_addr, false, false); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; int counter = FLUSH_COUNT_FLASH; @@ -2065,7 +2083,7 @@ int dsp5680xx_f_wr(struct target *t, const uint8_t *b, uint32_t a, uint32_t coun retval = core_tx_upper_data(target, tmp, &drscan_data); if (retval != ERROR_OK) { dsp5680xx_context.flush = 1; - err_check_propagate(retval); + return retval; } dsp5680xx_context.flush = 0; } @@ -2080,13 +2098,14 @@ int dsp5680xx_f_wr(struct target *t, const uint8_t *b, uint32_t a, uint32_t coun uint16_t pc_crc; retval = dsp5680xx_f_signature(target, address, i, &signature); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; pc_crc = perl_crc(buffer, i); if (pc_crc != signature) { - retval = ERROR_FAIL; const char *msg = "Flashed data failed CRC check, flash again!"; - err_check(retval, DSP5680XX_ERROR_FLASHING_CRC, msg); + err_log(DSP5680XX_ERROR_FLASHING_CRC, msg); + return ERROR_FAIL; } } return retval; @@ -2094,32 +2113,24 @@ int dsp5680xx_f_wr(struct target *t, const uint8_t *b, uint32_t a, uint32_t coun int dsp5680xx_f_unlock(struct target *target) { - int retval = ERROR_OK; - uint16_t eonce_status; - uint32_t instr; - uint32_t ir_out; - struct jtag_tap *tap_chp; - - struct jtag_tap *tap_cpu; - - tap_chp = jtag_tap_by_string("dsp568013.chp"); + struct jtag_tap *tap_chp = jtag_tap_by_string("dsp568013.chp"); if (!tap_chp) { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER, + err_log(DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER, "Failed to get master tap."); + return ERROR_FAIL; } - tap_cpu = jtag_tap_by_string("dsp568013.cpu"); + struct jtag_tap *tap_cpu = jtag_tap_by_string("dsp568013.cpu"); if (!tap_cpu) { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE, + err_log(DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE, "Failed to get master tap."); + return ERROR_FAIL; } - retval = eonce_enter_debug_mode_without_reset(target, &eonce_status); + int retval = eonce_enter_debug_mode_without_reset(target, &eonce_status); if (retval == ERROR_OK) LOG_WARNING("Memory was not locked."); @@ -2127,20 +2138,25 @@ int dsp5680xx_f_unlock(struct target *target) jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); - err_check(retval, DSP5680XX_ERROR_JTAG_RESET, - "Failed to reset JTAG state machine"); + if (retval != ERROR_OK) { + err_log(DSP5680XX_ERROR_JTAG_RESET, + "Failed to reset JTAG state machine"); + return retval; + } jtag_add_sleep(150); /* Enable core tap */ tap_chp->enabled = true; retval = switch_tap(target, tap_chp, tap_cpu); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; - instr = JTAG_INSTR_DEBUG_REQUEST; + uint32_t instr = JTAG_INSTR_DEBUG_REQUEST; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); @@ -2148,97 +2164,105 @@ int dsp5680xx_f_unlock(struct target *target) /* Enable master tap */ tap_chp->enabled = false; retval = switch_tap(target, tap_chp, tap_cpu); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* Execute mass erase to unlock */ instr = MASTER_TAP_CMD_FLASH_ERASE; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; instr = HFM_CLK_DEFAULT; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 16); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; jtag_add_sleep(TIME_DIV_FREESCALE * 150 * 1000); jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); - err_check(retval, DSP5680XX_ERROR_JTAG_RESET, - "Failed to reset JTAG state machine"); + if (retval != ERROR_OK) { + err_log(DSP5680XX_ERROR_JTAG_RESET, + "Failed to reset JTAG state machine"); + return retval; + } jtag_add_sleep(150); instr = 0x0606ffff; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 32); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; /* enable core tap */ instr = 0x5; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; instr = 0x2; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 4); - err_check_propagate(retval); + if (retval != ERROR_OK) + return retval; tap_cpu->enabled = true; tap_chp->enabled = false; target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; - return retval; + return ERROR_OK; } int dsp5680xx_f_lock(struct target *target) { - int retval; - - 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); - err_check_propagate(retval); + int retval = dsp5680xx_f_wr(target, (uint8_t *)&lock_word, HFM_LOCK_ADDR_L, 2, 1); + if (retval != ERROR_OK) + return retval; jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); - err_check(retval, DSP5680XX_ERROR_JTAG_RESET, - "Failed to reset JTAG state machine"); + if (retval != ERROR_OK) { + err_log(DSP5680XX_ERROR_JTAG_RESET, + "Failed to reset JTAG state machine"); + return retval; + } jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); - tap_chp = jtag_tap_by_string("dsp568013.chp"); + struct jtag_tap *tap_chp = jtag_tap_by_string("dsp568013.chp"); if (!tap_chp) { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER, + err_log(DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER, "Failed to get master tap."); + return ERROR_FAIL; } - tap_cpu = jtag_tap_by_string("dsp568013.cpu"); + struct jtag_tap *tap_cpu = jtag_tap_by_string("dsp568013.cpu"); if (!tap_cpu) { - retval = ERROR_FAIL; - err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE, + err_log(DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE, "Failed to get master tap."); + return ERROR_FAIL; } target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; tap_cpu->enabled = false; tap_chp->enabled = true; - retval = switch_tap(target, tap_chp, tap_cpu); - return retval; + return switch_tap(target, tap_chp, tap_cpu); } static int dsp5680xx_step(struct target *target, bool current, target_addr_t address, bool handle_breakpoints) { - err_check(ERROR_FAIL, DSP5680XX_ERROR_NOT_IMPLEMENTED_STEP, + err_log(DSP5680XX_ERROR_NOT_IMPLEMENTED_STEP, "Not implemented yet."); + return ERROR_FAIL; } /** Holds methods for dsp5680xx targets. */ diff --git a/src/target/embeddedice.c b/src/target/embeddedice.c index 7aef153b58..890b5f499c 100644 --- a/src/target/embeddedice.c +++ b/src/target/embeddedice.c @@ -219,69 +219,69 @@ struct reg_cache *embeddedice_build_reg_cache(struct target *target, LOG_INFO("Embedded ICE version %d", eice_version); switch (eice_version) { - case 1: - /* ARM7TDMI r3, ARM7TDMI-S r3 - * - * REVISIT docs say ARM7TDMI-S r4 uses version 1 but - * that it has 6-bit CTRL and 5-bit STAT... doc bug? - * ARM7TDMI r4 docs say EICE v4. - */ - reg_list[EICE_DBG_CTRL].size = 3; - reg_list[EICE_DBG_STAT].size = 5; - break; - case 2: - /* ARM9TDMI */ - reg_list[EICE_DBG_CTRL].size = 4; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - break; - case 3: - LOG_ERROR("EmbeddedICE v%d handling might be broken", - eice_version); - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - arm7_9->has_monitor_mode = 1; - break; - case 4: - /* ARM7TDMI r4 */ - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_monitor_mode = 1; - break; - case 5: - /* ARM9E-S rev 1 */ - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - arm7_9->has_monitor_mode = 1; - break; - case 6: - /* ARM7EJ-S, ARM9E-S rev 2, ARM9EJ-S */ - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 10; - /* DBG_STAT has MOE bits */ - arm7_9->has_monitor_mode = 1; - break; - case 7: - LOG_ERROR("EmbeddedICE v%d handling might be broken", - eice_version); - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_monitor_mode = 1; + case 1: + /* ARM7TDMI r3, ARM7TDMI-S r3 + * + * REVISIT docs say ARM7TDMI-S r4 uses version 1 but + * that it has 6-bit CTRL and 5-bit STAT... doc bug? + * ARM7TDMI r4 docs say EICE v4. + */ + reg_list[EICE_DBG_CTRL].size = 3; + reg_list[EICE_DBG_STAT].size = 5; + break; + case 2: + /* ARM9TDMI */ + reg_list[EICE_DBG_CTRL].size = 4; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + break; + case 3: + LOG_ERROR("EmbeddedICE v%d handling might be broken", + eice_version); + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + arm7_9->has_monitor_mode = 1; + break; + case 4: + /* ARM7TDMI r4 */ + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_monitor_mode = 1; + break; + case 5: + /* ARM9E-S rev 1 */ + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + arm7_9->has_monitor_mode = 1; + break; + case 6: + /* ARM7EJ-S, ARM9E-S rev 2, ARM9EJ-S */ + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 10; + /* DBG_STAT has MOE bits */ + arm7_9->has_monitor_mode = 1; + break; + case 7: + LOG_ERROR("EmbeddedICE v%d handling might be broken", + eice_version); + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_monitor_mode = 1; + break; + default: + /* + * The Feroceon implementation has the version number + * in some unusual bits. Let feroceon.c validate it + * and do the appropriate setup itself. + */ + if (strcmp(target_type_name(target), "feroceon") == 0 || + strcmp(target_type_name(target), "dragonite") == 0) break; - default: - /* - * The Feroceon implementation has the version number - * in some unusual bits. Let feroceon.c validate it - * and do the appropriate setup itself. - */ - if (strcmp(target_type_name(target), "feroceon") == 0 || - strcmp(target_type_name(target), "dragonite") == 0) - break; - LOG_ERROR("unknown EmbeddedICE version " - "(comms ctrl: 0x%8.8" PRIx32 ")", - buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32)); + LOG_ERROR("unknown EmbeddedICE version " + "(comms ctrl: 0x%8.8" PRIx32 ")", + buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32)); } /* On Feroceon and Dragonite the second unit is seemingly missing. */ @@ -502,7 +502,7 @@ void embeddedice_write_reg(struct reg *reg, uint32_t value) { struct embeddedice_reg *ice_reg = reg->arch_info; - LOG_DEBUG("%i: 0x%8.8" PRIx32 "", ice_reg->addr, value); + LOG_DEBUG("%i: 0x%8.8" PRIx32, ice_reg->addr, value); arm_jtag_scann(ice_reg->jtag_info, 0x2, TAP_IDLE); @@ -574,7 +574,7 @@ int embeddedice_send(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size) /** * Poll DCC control register until read or write handshake completes. */ -int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeout) +int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeout_ms) { struct scan_field fields[3]; uint8_t field0_in[4]; @@ -582,8 +582,6 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou uint8_t field2_out[1]; int retval; uint32_t hsact; - struct timeval now; - struct timeval timeout_end; if (hsbit == EICE_COMM_CTRL_WBIT) hsact = 1; @@ -616,8 +614,8 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); - gettimeofday(&timeout_end, NULL); - timeval_add_time(&timeout_end, 0, timeout * 1000); + + int64_t then = timeval_ms() + timeout_ms; do { jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); retval = jtag_execute_queue(); @@ -627,8 +625,7 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou if (buf_get_u32(field0_in, hsbit, 1) == hsact) return ERROR_OK; - gettimeofday(&now, NULL); - } while (timeval_compare(&now, &timeout_end) <= 0); + } while (timeval_ms() <= then); LOG_ERROR("embeddedice handshake timeout"); return ERROR_TARGET_TIMEOUT; diff --git a/src/target/esirisc.c b/src/target/esirisc.c index fac5dc72ee..ff11ecdff0 100644 --- a/src/target/esirisc.c +++ b/src/target/esirisc.c @@ -367,24 +367,24 @@ static int esirisc_read_memory(struct target *target, target_addr_t address, void *value_p; switch (size) { - case sizeof(value.word): - value_p = &value.word; - retval = esirisc_jtag_read_word(jtag_info, address, value_p); - break; - - case sizeof(value.hword): - value_p = &value.hword; - retval = esirisc_jtag_read_hword(jtag_info, address, value_p); - break; - - case sizeof(value.byte): - value_p = &value.byte; - retval = esirisc_jtag_read_byte(jtag_info, address, value_p); - break; - - default: - LOG_TARGET_ERROR(target, "unsupported size: %" PRIu32, size); - return ERROR_FAIL; + case sizeof(value.word): + value_p = &value.word; + retval = esirisc_jtag_read_word(jtag_info, address, value_p); + break; + + case sizeof(value.hword): + value_p = &value.hword; + retval = esirisc_jtag_read_hword(jtag_info, address, value_p); + break; + + case sizeof(value.byte): + value_p = &value.byte; + retval = esirisc_jtag_read_byte(jtag_info, address, value_p); + break; + + default: + LOG_TARGET_ERROR(target, "unsupported size: %" PRIu32, size); + return ERROR_FAIL; } if (retval != ERROR_OK) { @@ -415,24 +415,24 @@ static int esirisc_write_memory(struct target *target, target_addr_t address, union esirisc_memory value; switch (size) { - case sizeof(value.word): - value.word = buf_get_u32(buffer, 0, num_bits); - retval = esirisc_jtag_write_word(jtag_info, address, value.word); - break; - - case sizeof(value.hword): - value.hword = buf_get_u32(buffer, 0, num_bits); - retval = esirisc_jtag_write_hword(jtag_info, address, value.hword); - break; - - case sizeof(value.byte): - value.byte = buf_get_u32(buffer, 0, num_bits); - retval = esirisc_jtag_write_byte(jtag_info, address, value.byte); - break; - - default: - LOG_TARGET_ERROR(target, "unsupported size: %" PRIu32, size); - return ERROR_FAIL; + case sizeof(value.word): + value.word = buf_get_u32(buffer, 0, num_bits); + retval = esirisc_jtag_write_word(jtag_info, address, value.word); + break; + + case sizeof(value.hword): + value.hword = buf_get_u32(buffer, 0, num_bits); + retval = esirisc_jtag_write_hword(jtag_info, address, value.hword); + break; + + case sizeof(value.byte): + value.byte = buf_get_u32(buffer, 0, num_bits); + retval = esirisc_jtag_write_byte(jtag_info, address, value.byte); + break; + + default: + LOG_TARGET_ERROR(target, "unsupported size: %" PRIu32, size); + return ERROR_FAIL; } if (retval != ERROR_OK) { @@ -641,25 +641,25 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc uint32_t sn; switch (watchpoint->length) { - case sizeof(uint64_t): - sn = 0x3; - break; - case sizeof(uint32_t): - sn = 0x2; - break; - - case sizeof(uint16_t): - sn = 0x1; - break; - - case sizeof(uint8_t): - sn = 0x0; - break; - - default: - LOG_TARGET_ERROR(target, "unsupported length: %" PRIu32, - watchpoint->length); - return ERROR_FAIL; + case sizeof(uint64_t): + sn = 0x3; + break; + case sizeof(uint32_t): + sn = 0x2; + break; + + case sizeof(uint16_t): + sn = 0x1; + break; + + case sizeof(uint8_t): + sn = 0x0; + break; + + default: + LOG_TARGET_ERROR(target, "unsupported length: %" PRIu32, + watchpoint->length); + return ERROR_FAIL; } dbs |= (sn << (2 * wp_index)); /* DBS.Sn */ @@ -679,21 +679,21 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc uint32_t dn; switch (watchpoint->rw) { - case WPT_READ: - dn = 0x1; - break; + case WPT_READ: + dn = 0x1; + break; - case WPT_WRITE: - dn = 0x2; - break; + case WPT_WRITE: + dn = 0x2; + break; - case WPT_ACCESS: - dn = 0x3; - break; + case WPT_ACCESS: + dn = 0x3; + break; - default: - LOG_TARGET_ERROR(target, "unsupported rw: %" PRId32, watchpoint->rw); - return ERROR_FAIL; + default: + LOG_TARGET_ERROR(target, "unsupported rw: %" PRId32, watchpoint->rw); + return ERROR_FAIL; } dbc |= (dn << (2 * wp_index)); /* DBC.Dn */ @@ -1046,33 +1046,33 @@ static int esirisc_debug_entry(struct target *target) uint32_t eid = buf_get_u32(esirisc->eid->value, 0, esirisc->eid->size); switch (eid) { - /* - * InstBreakpoint exceptions are also raised when a core is - * halted for debugging. The following is required to - * determine if a breakpoint was encountered. - */ - case EID_INST_BREAKPOINT: - breakpoint = breakpoint_find(target, - buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size)); - target->debug_reason = (breakpoint) ? - DBG_REASON_BREAKPOINT : DBG_REASON_DBGRQ; - break; - - /* - * eSi-RISC treats watchpoints similarly to breakpoints, - * however GDB will not request to step over the current - * instruction when a watchpoint fires. The following is - * required to resume the target. - */ - case EID_DATA_BREAKPOINT: - esirisc_remove_watchpoints(target); - esirisc_debug_step(target); - esirisc_add_watchpoints(target); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - - default: - target->debug_reason = DBG_REASON_DBGRQ; + /* + * InstBreakpoint exceptions are also raised when a core is + * halted for debugging. The following is required to + * determine if a breakpoint was encountered. + */ + case EID_INST_BREAKPOINT: + breakpoint = breakpoint_find(target, + buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size)); + target->debug_reason = (breakpoint) ? + DBG_REASON_BREAKPOINT : DBG_REASON_DBGRQ; + break; + + /* + * eSi-RISC treats watchpoints similarly to breakpoints, + * however GDB will not request to step over the current + * instruction when a watchpoint fires. The following is + * required to resume the target. + */ + case EID_DATA_BREAKPOINT: + esirisc_remove_watchpoints(target); + esirisc_debug_step(target); + esirisc_add_watchpoints(target); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + + default: + target->debug_reason = DBG_REASON_DBGRQ; } } @@ -1679,8 +1679,6 @@ static int esirisc_examine(struct target *target) } } - target_set_examined(target); - LOG_TARGET_INFO(target, "%d bit, %d registers, %s%s%s", esirisc->num_bits, esirisc->num_regs, target_endianness(target), diff --git a/src/target/esirisc_trace.c b/src/target/esirisc_trace.c index a1d92d1ca9..42bc37d30e 100644 --- a/src/target/esirisc_trace.c +++ b/src/target/esirisc_trace.c @@ -10,6 +10,7 @@ #endif #include +#include #include #include #include @@ -18,8 +19,6 @@ #include "esirisc.h" -#define BIT_MASK(x) ((1 << (x)) - 1) - /* Control Fields */ #define CONTROL_ST (1<<0) /* Start */ #define CONTROL_SP (1<<1) /* Stop */ @@ -389,84 +388,87 @@ static int esirisc_trace_analyze_full(struct command_invocation *cmd, uint8_t *b goto fail; switch (id) { - case ESIRISC_TRACE_ID_EXECUTE: - case ESIRISC_TRACE_ID_STALL: - case ESIRISC_TRACE_ID_BRANCH: - command_print(cmd, "%s", esirisc_trace_id_strings[id]); + case ESIRISC_TRACE_ID_EXECUTE: + case ESIRISC_TRACE_ID_STALL: + case ESIRISC_TRACE_ID_BRANCH: + command_print(cmd, "%s", esirisc_trace_id_strings[id]); + break; + + case ESIRISC_TRACE_ID_EXTENDED: { + uint32_t ext_id; + + retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 4, &ext_id); + if (retval != ERROR_OK) + goto fail; + + switch (ext_id) { + case ESIRISC_TRACE_EXT_ID_STOP: + case ESIRISC_TRACE_EXT_ID_WAIT: + case ESIRISC_TRACE_EXT_ID_MULTICYCLE: + command_print(cmd, "%s", esirisc_trace_ext_id_strings[ext_id]); break; - case ESIRISC_TRACE_ID_EXTENDED: { - uint32_t ext_id; + case ESIRISC_TRACE_EXT_ID_ERET: + case ESIRISC_TRACE_EXT_ID_PC: + case ESIRISC_TRACE_EXT_ID_INDIRECT: + case ESIRISC_TRACE_EXT_ID_END_PC: { + uint32_t pc; - retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 4, &ext_id); + retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &pc); if (retval != ERROR_OK) goto fail; - switch (ext_id) { - case ESIRISC_TRACE_EXT_ID_STOP: - case ESIRISC_TRACE_EXT_ID_WAIT: - case ESIRISC_TRACE_EXT_ID_MULTICYCLE: - command_print(cmd, "%s", esirisc_trace_ext_id_strings[ext_id]); - break; - - case ESIRISC_TRACE_EXT_ID_ERET: - case ESIRISC_TRACE_EXT_ID_PC: - case ESIRISC_TRACE_EXT_ID_INDIRECT: - case ESIRISC_TRACE_EXT_ID_END_PC: { - uint32_t pc; - - retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &pc); - if (retval != ERROR_OK) - goto fail; - - command_print(cmd, "%s PC: 0x%" PRIx32, - esirisc_trace_ext_id_strings[ext_id], pc); - - if (ext_id == ESIRISC_TRACE_EXT_ID_END_PC) { - command_print(cmd, "--- end of trace ---"); - return ERROR_OK; - } - break; - } - case ESIRISC_TRACE_EXT_ID_EXCEPTION: { - uint32_t eid, epc; - - retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &eid); - if (retval != ERROR_OK) - goto fail; - - retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &epc); - if (retval != ERROR_OK) - goto fail; - - command_print(cmd, "%s EID: 0x%" PRIx32 ", EPC: 0x%" PRIx32, - esirisc_trace_ext_id_strings[ext_id], eid, epc); - break; - } - case ESIRISC_TRACE_EXT_ID_COUNT: { - uint32_t count; - - retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &count); - if (retval != ERROR_OK) - goto fail; - - command_print(cmd, "repeats %" PRIu32 " %s", count, - (count == 1) ? "time" : "times"); - break; - } - case ESIRISC_TRACE_EXT_ID_END: - command_print(cmd, "--- end of trace ---"); - return ERROR_OK; - - default: - command_print(cmd, "invalid extended trace ID: %" PRIu32, ext_id); - return ERROR_FAIL; + command_print(cmd, "%s PC: 0x%" PRIx32, + esirisc_trace_ext_id_strings[ext_id], pc); + + if (ext_id == ESIRISC_TRACE_EXT_ID_END_PC) { + command_print(cmd, "--- end of trace ---"); + return ERROR_OK; } break; } + + case ESIRISC_TRACE_EXT_ID_EXCEPTION: { + uint32_t eid, epc; + + retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &eid); + if (retval != ERROR_OK) + goto fail; + + retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &epc); + if (retval != ERROR_OK) + goto fail; + + command_print(cmd, "%s EID: 0x%" PRIx32 ", EPC: 0x%" PRIx32, + esirisc_trace_ext_id_strings[ext_id], eid, epc); + break; + } + + case ESIRISC_TRACE_EXT_ID_COUNT: { + uint32_t count; + + retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &count); + if (retval != ERROR_OK) + goto fail; + + command_print(cmd, "repeats %" PRIu32 " %s", count, + (count == 1) ? "time" : "times"); + break; + } + + case ESIRISC_TRACE_EXT_ID_END: + command_print(cmd, "--- end of trace ---"); + return ERROR_OK; + default: - command_print(cmd, "invalid trace ID: %" PRIu32, id); + command_print(cmd, "invalid extended trace ID: %" PRIu32, ext_id); return ERROR_FAIL; + } + break; + } + default: + command_print(cmd, "invalid trace ID: %" PRIu32, id); + return ERROR_FAIL; } } @@ -480,7 +482,7 @@ static int esirisc_trace_analyze_simple(struct command_invocation *cmd, uint8_t struct target *target = get_current_target(cmd->ctx); struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; - const uint32_t end_of_trace = BIT_MASK(trace_info->pc_bits) << 1; + const uint32_t end_of_trace = GENMASK(trace_info->pc_bits, 1); const uint32_t num_bits = size * 8; int retval; @@ -511,21 +513,21 @@ static int esirisc_trace_analyze(struct command_invocation *cmd, uint8_t *buffer struct esirisc_trace *trace_info = &esirisc->trace_info; switch (trace_info->format) { - case ESIRISC_TRACE_FORMAT_FULL: - command_print(cmd, "--- full pipeline ---"); - return esirisc_trace_analyze_full(cmd, buffer, size); + case ESIRISC_TRACE_FORMAT_FULL: + command_print(cmd, "--- full pipeline ---"); + return esirisc_trace_analyze_full(cmd, buffer, size); - case ESIRISC_TRACE_FORMAT_BRANCH: - command_print(cmd, "--- branches taken ---"); - return esirisc_trace_analyze_full(cmd, buffer, size); + case ESIRISC_TRACE_FORMAT_BRANCH: + command_print(cmd, "--- branches taken ---"); + return esirisc_trace_analyze_full(cmd, buffer, size); - case ESIRISC_TRACE_FORMAT_ICACHE: - command_print(cmd, "--- icache misses ---"); - return esirisc_trace_analyze_simple(cmd, buffer, size); + case ESIRISC_TRACE_FORMAT_ICACHE: + command_print(cmd, "--- icache misses ---"); + return esirisc_trace_analyze_simple(cmd, buffer, size); - default: - command_print(cmd, "invalid trace format: %i", trace_info->format); - return ERROR_FAIL; + default: + command_print(cmd, "invalid trace format: %i", trace_info->format); + return ERROR_FAIL; } } diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c index 399ba8e7cd..fd6565d6b4 100644 --- a/src/target/espressif/esp32.c +++ b/src/target/espressif/esp32.c @@ -192,8 +192,8 @@ static int esp32_soc_reset(struct target *target) 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); + LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state %s", + target_state_name(target)); get_timeout = true; break; } @@ -457,6 +457,13 @@ static const struct command_registration esp32_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static int esp32_insn_set(struct command_invocation *cmd, + struct target *target, const char **insn_set) +{ + *insn_set = "xtensa"; + return ERROR_OK; +} + /** Holds methods for Xtensa targets. */ struct target_type esp32_target = { .name = "esp32", @@ -501,4 +508,6 @@ struct target_type esp32_target = { .deinit_target = esp_xtensa_target_deinit, .commands = esp32_command_handlers, + .profiling = esp_xtensa_profiling, + .insn_set = esp32_insn_set, }; diff --git a/src/target/espressif/esp32_apptrace.c b/src/target/espressif/esp32_apptrace.c index 307096019a..77201ae90b 100644 --- a/src/target/espressif/esp32_apptrace.c +++ b/src/target/espressif/esp32_apptrace.c @@ -488,7 +488,7 @@ int esp32_apptrace_cmd_ctx_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct c 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) { + if (duration_start(&cmd_ctx->idle_time) != ERROR_OK) { command_print(cmd, "Failed to start idle time measurement!"); esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); return ERROR_FAIL; @@ -905,7 +905,7 @@ static int esp32_apptrace_process_data(struct esp32_apptrace_cmd_ctx *ctx, /* 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) { + if (duration_measure(&ctx->read_time) != ERROR_OK) { LOG_ERROR("Failed to stop trace read time measure!"); return ERROR_FAIL; } @@ -1005,7 +1005,7 @@ static int esp32_apptrace_check_connection(struct esp32_apptrace_cmd_ctx *ctx) } if (ctx->stop_tmo != -1.0) { /* re-start idle time measurement */ - if (duration_start(&ctx->idle_time) != 0) { + if (duration_start(&ctx->idle_time) != ERROR_OK) { LOG_ERROR("Failed to re-start idle time measure!"); return ERROR_FAIL; } @@ -1082,7 +1082,7 @@ static int esp32_apptrace_poll(void *priv) ctx->last_blk_id = max_block_id; } if (ctx->stop_tmo != -1.0) { - if (duration_measure(&ctx->idle_time) != 0) { + if (duration_measure(&ctx->idle_time) != ERROR_OK) { ctx->running = 0; LOG_ERROR("Failed to measure idle time!"); return ERROR_FAIL; @@ -1102,7 +1102,7 @@ static int esp32_apptrace_poll(void *priv) return ERROR_FAIL; } if (ctx->tot_len == 0) { - if (duration_start(&ctx->read_time) != 0) { + if (duration_start(&ctx->read_time) != ERROR_OK) { ctx->running = 0; LOG_ERROR("Failed to start trace read time measurement!"); return ERROR_FAIL; @@ -1116,7 +1116,7 @@ static int esp32_apptrace_poll(void *priv) } if (s_time_stats_enable) { /* read block */ - if (duration_start(&blk_proc_time) != 0) { + if (duration_start(&blk_proc_time) != ERROR_OK) { ctx->running = 0; LOG_ERROR("Failed to start block read time measurement!"); return ERROR_FAIL; @@ -1136,7 +1136,7 @@ static int esp32_apptrace_poll(void *priv) 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) { + if (duration_measure(&blk_proc_time) != ERROR_OK) { ctx->running = 0; LOG_ERROR("Failed to measure block read time!"); return ERROR_FAIL; @@ -1148,7 +1148,7 @@ static int esp32_apptrace_poll(void *priv) if (brt < ctx->stats.min_blk_read_time) ctx->stats.min_blk_read_time = brt; - if (duration_start(&blk_proc_time) != 0) { + if (duration_start(&blk_proc_time) != ERROR_OK) { ctx->running = 0; LOG_ERROR("Failed to start block proc time measurement!"); return ERROR_FAIL; @@ -1194,14 +1194,14 @@ static int esp32_apptrace_poll(void *priv) } if (ctx->stop_tmo != -1.0) { /* start idle time measurement */ - if (duration_start(&ctx->idle_time) != 0) { + if (duration_start(&ctx->idle_time) != ERROR_OK) { 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) { + if (duration_measure(&blk_proc_time) != ERROR_OK) { ctx->running = 0; LOG_ERROR("Failed to stop block proc time measure!"); return ERROR_FAIL; @@ -1223,7 +1223,7 @@ static inline bool is_sysview_mode(int mode) static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx) { - if (duration_measure(&ctx->read_time) != 0) + if (duration_measure(&ctx->read_time) != ERROR_OK) LOG_ERROR("Failed to stop trace read time measurement!"); int res = target_unregister_timer_callback(esp32_apptrace_poll, ctx); if (res != ERROR_OK) @@ -1362,7 +1362,7 @@ static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx) } /* 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) { + if (duration_start(&wait_time) != ERROR_OK) { LOG_ERROR("Failed to start trace stop timeout measurement!"); return ERROR_FAIL; } @@ -1418,7 +1418,7 @@ static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx) old_block_id = target_state[fired_target_num].block_id; } } - if (duration_measure(&wait_time) != 0) { + if (duration_measure(&wait_time) != ERROR_OK) { LOG_ERROR("Failed to start trace stop timeout measurement!"); return ERROR_FAIL; } @@ -1532,7 +1532,7 @@ static int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, 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) + if (s_at_cmd_ctx.running && duration_measure(&s_at_cmd_ctx.read_time) != ERROR_OK) LOG_ERROR("Failed to measure trace read time!"); esp32_apptrace_print_stats(&s_at_cmd_ctx); return ERROR_OK; diff --git a/src/target/espressif/esp32_sysview.c b/src/target/espressif/esp32_sysview.c index 2fe2157780..d8eda07731 100644 --- a/src/target/espressif/esp32_sysview.c +++ b/src/target/espressif/esp32_sysview.c @@ -545,7 +545,7 @@ int esp32_sysview_process_data(struct esp32_apptrace_cmd_ctx *ctx, 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) { + if (duration_measure(&ctx->read_time) != ERROR_OK) { LOG_ERROR("Failed to stop trace read time measure!"); return ERROR_FAIL; } diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c index b86e43e626..4a5bcb0473 100644 --- a/src/target/espressif/esp32s2.c +++ b/src/target/espressif/esp32s2.c @@ -272,8 +272,8 @@ static int esp32s2_soc_reset(struct target *target) 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); + LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state %s", + target_state_name(target)); return ERROR_TARGET_TIMEOUT; } } @@ -494,6 +494,13 @@ static const struct command_registration esp32s2_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static int esp32s2_insn_set(struct command_invocation *cmd, + struct target *target, const char **insn_set) +{ + *insn_set = "xtensa_s2"; + return ERROR_OK; +} + /* Holds methods for Xtensa targets. */ struct target_type esp32s2_target = { .name = "esp32s2", @@ -538,4 +545,6 @@ struct target_type esp32s2_target = { .deinit_target = esp_xtensa_target_deinit, .commands = esp32s2_command_handlers, + .profiling = esp_xtensa_profiling, + .insn_set = esp32s2_insn_set, }; diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c index 82413f77fb..a8e3fff68b 100644 --- a/src/target/espressif/esp32s3.c +++ b/src/target/espressif/esp32s3.c @@ -193,8 +193,8 @@ static int esp32s3_soc_reset(struct target *target) xtensa_poll(target); if (timeval_ms() >= timeout) { LOG_TARGET_ERROR(target, - "Timed out waiting for CPU to be reset, target state=%d", - target->state); + "Timed out waiting for CPU to be reset, target state %s", + target_state_name(target)); get_timeout = true; break; } @@ -378,6 +378,13 @@ static const struct command_registration esp32s3_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static int esp32s3_insn_set(struct command_invocation *cmd, + struct target *target, const char **insn_set) +{ + *insn_set = "xtensa_s2"; + return ERROR_OK; +} + /** Holds methods for Xtensa targets. */ struct target_type esp32s3_target = { .name = "esp32s3", @@ -423,4 +430,5 @@ struct target_type esp32s3_target = { .commands = esp32s3_command_handlers, .profiling = esp_xtensa_profiling, + .insn_set = esp32s3_insn_set, }; diff --git a/src/target/espressif/esp_algorithm.c b/src/target/espressif/esp_algorithm.c index 79f610b922..ddb5575833 100644 --- a/src/target/espressif/esp_algorithm.c +++ b/src/target/espressif/esp_algorithm.c @@ -307,7 +307,7 @@ int esp_algorithm_load_func_image(struct target *target, struct esp_algorithm_ru if (!run || !run->hw) return ERROR_FAIL; - if (duration_start(&algo_time) != 0) { + if (duration_start(&algo_time) != ERROR_OK) { LOG_ERROR("Failed to start algo time measurement!"); return ERROR_FAIL; } @@ -486,7 +486,7 @@ int esp_algorithm_load_func_image(struct target *target, struct esp_algorithm_ru run->stub.stack_addr = run->stub.stack->address + run->stack_size; } - if (duration_measure(&algo_time) != 0) { + if (duration_measure(&algo_time) != ERROR_OK) { LOG_ERROR("Failed to stop algo run measurement!"); retval = ERROR_FAIL; goto _on_error; @@ -536,7 +536,7 @@ int esp_algorithm_load_onboard_func(struct target *target, target_addr_t func_ad if (!run || !run->hw) return ERROR_FAIL; - if (duration_start(&algo_time) != 0) { + if (duration_start(&algo_time) != ERROR_OK) { LOG_ERROR("Failed to start algo time measurement!"); return ERROR_FAIL; } @@ -572,7 +572,7 @@ int esp_algorithm_load_onboard_func(struct target *target, target_addr_t func_ad } } - if (duration_measure(&algo_time) != 0) { + if (duration_measure(&algo_time) != ERROR_OK) { LOG_ERROR("Failed to stop algo run measurement!"); return ERROR_FAIL; } diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c index 4cadcb3301..3575272608 100644 --- a/src/target/espressif/esp_xtensa.c +++ b/src/target/espressif/esp_xtensa.c @@ -183,7 +183,6 @@ int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *break int esp_xtensa_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { - struct timeval timeout, now; struct xtensa *xtensa = target_to_xtensa(target); int retval = ERROR_OK; int res; @@ -192,8 +191,7 @@ int esp_xtensa_profiling(struct target *target, uint32_t *samples, #define MIN_PASS 200 #define MAX_PASS 1000 - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, seconds, 0); + int64_t then = timeval_ms() + seconds * 1000LL; uint8_t buf[sizeof(uint32_t) * MAX_PASS]; @@ -238,8 +236,7 @@ int esp_xtensa_profiling(struct target *target, uint32_t *samples, uint32_t sample32 = buf_get_u32(buf + i * sizeof(uint32_t), 0, 32); samples[sample_count++] = sample32; } - gettimeofday(&now, NULL); - if (sample_count >= max_num_samples || timeval_compare(&now, &timeout) > 0) { + if (sample_count >= max_num_samples || timeval_ms() > then) { LOG_TARGET_INFO(target, "Profiling completed. %" PRIu32 " samples.", sample_count); break; } diff --git a/src/target/etb.c b/src/target/etb.c index fb3112d70a..f88b589371 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -287,7 +287,7 @@ static int etb_write_reg(struct reg *reg, uint32_t value) uint8_t reg_addr = etb_reg->addr & 0x7f; struct scan_field fields[3]; - LOG_DEBUG("%i: 0x%8.8" PRIx32 "", (int)(etb_reg->addr), value); + LOG_DEBUG("%i: 0x%8.8" PRIx32, (int)(etb_reg->addr), value); etb_scann(etb_reg->etb, 0x0); etb_set_instr(etb_reg->etb, 0xc); diff --git a/src/target/etm.c b/src/target/etm.c index d9a3cdc5e5..1a41d1c8bb 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -326,24 +326,24 @@ struct reg_cache *etm_build_reg_cache(struct target *target, } else { switch (config >> 28) { - case 7: - case 5: - case 3: - bcd_vers = 0x13; - break; - case 4: - case 2: - bcd_vers = 0x12; - break; - case 1: - bcd_vers = 0x11; - break; - case 0: - bcd_vers = 0x10; - break; - default: - LOG_WARNING("Bad ETMv1 protocol %d", config >> 28); - goto fail; + case 7: + case 5: + case 3: + bcd_vers = 0x13; + break; + case 4: + case 2: + bcd_vers = 0x12; + break; + case 1: + bcd_vers = 0x11; + break; + case 0: + bcd_vers = 0x10; + break; + default: + LOG_WARNING("Bad ETMv1 protocol %d", config >> 28); + goto fail; } } etm_ctx->bcd_vers = bcd_vers; @@ -584,7 +584,7 @@ static int etm_write_reg(struct reg *reg, uint32_t value) return ERROR_COMMAND_SYNTAX_ERROR; } - LOG_DEBUG("%s (%u): 0x%8.8" PRIx32 "", r->name, reg_addr, value); + LOG_DEBUG("%s (%u): 0x%8.8" PRIx32, r->name, reg_addr, value); retval = arm_jtag_scann(etm_reg->jtag_info, 0x6, TAP_IDLE); if (retval != ERROR_OK) @@ -923,52 +923,48 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio ctx->pipe_index += 2; switch (ctx->last_branch_reason) { - case 0x0: /* normal PC change */ - next_pc = ctx->last_branch; - break; - case 0x1: /* tracing enabled */ - command_print(cmd, - "--- tracing enabled at 0x%8.8" PRIx32 " ---", - ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - break; - case 0x2: /* trace restarted after FIFO overflow */ - command_print(cmd, - "--- trace restarted after FIFO overflow at 0x%8.8" PRIx32 " ---", - ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - break; - case 0x3: /* exit from debug state */ + case 0x0: /* normal PC change */ + next_pc = ctx->last_branch; + break; + case 0x1: /* tracing enabled */ + command_print(cmd, + "--- tracing enabled at 0x%8.8" PRIx32 " ---", + ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + case 0x2: /* trace restarted after FIFO overflow */ + command_print(cmd, + "--- trace restarted after FIFO overflow at 0x%8.8" PRIx32 " ---", + ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + case 0x3: /* exit from debug state */ + command_print(cmd, + "--- exit from debug state at 0x%8.8" PRIx32 " ---", + ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + case 0x4: /* periodic synchronization point */ + next_pc = ctx->last_branch; + /* if we had no valid PC prior to this synchronization point, + * we have to move on with the next trace cycle + */ + if (!current_pc_ok) { command_print(cmd, - "--- exit from debug state at 0x%8.8" PRIx32 " ---", - ctx->last_branch); - ctx->current_pc = ctx->last_branch; + "--- periodic synchronization point at 0x%8.8" PRIx32 " ---", + next_pc); + ctx->current_pc = next_pc; ctx->pipe_index++; continue; - break; - case 0x4: /* periodic synchronization point */ - next_pc = ctx->last_branch; - /* if we had no valid PC prior to this synchronization point, - * we have to move on with the next trace cycle - */ - if (!current_pc_ok) { - command_print(cmd, - "--- periodic synchronization point at 0x%8.8" PRIx32 " ---", - next_pc); - ctx->current_pc = next_pc; - ctx->pipe_index++; - continue; - } - break; - default: /* reserved */ - LOG_ERROR( - "BUG: branch reason code 0x%" PRIx32 " is reserved", - ctx->last_branch_reason); - return ERROR_FAIL; + } + break; + default: /* reserved */ + LOG_ERROR("BUG: branch reason code 0x%" PRIx32 " is reserved", + ctx->last_branch_reason); + return ERROR_FAIL; } /* if we got here the branch was a normal PC change @@ -986,7 +982,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio command_print(cmd, "data abort"); else { command_print(cmd, - "exception vector 0x%2.2" PRIx32 "", + "exception vector 0x%2.2" PRIx32, ctx->last_branch); ctx->current_pc = ctx->last_branch; ctx->pipe_index++; @@ -1044,7 +1040,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio if (ctx->ptr_ok) command_print(cmd, - "address: 0x%8.8" PRIx32 "", + "address: 0x%8.8" PRIx32, ctx->last_ptr); } @@ -1059,7 +1055,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio if (etmv1_data(ctx, 4, &data) != 0) return ERROR_ETM_ANALYSIS_FAILED; command_print(cmd, - "data: 0x%8.8" PRIx32 "", + "data: 0x%8.8" PRIx32, data); } } @@ -1069,7 +1065,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio if (etmv1_data(ctx, arm_access_size(&instruction), &data) != 0) return ERROR_ETM_ANALYSIS_FAILED; - command_print(cmd, "data: 0x%8.8" PRIx32 "", data); + command_print(cmd, "data: 0x%8.8" PRIx32, data); } } @@ -1148,21 +1144,21 @@ static COMMAND_HELPER(handle_etm_tracemode_command_update, uint8_t context_id; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], context_id); switch (context_id) { - case 0: - tracemode |= ETM_CTRL_CONTEXTID_NONE; - break; - case 8: - tracemode |= ETM_CTRL_CONTEXTID_8; - break; - case 16: - tracemode |= ETM_CTRL_CONTEXTID_16; - break; - case 32: - tracemode |= ETM_CTRL_CONTEXTID_32; - break; - default: - command_print(CMD, "invalid option '%s'", CMD_ARGV[1]); - return ERROR_COMMAND_SYNTAX_ERROR; + case 0: + tracemode |= ETM_CTRL_CONTEXTID_NONE; + break; + case 8: + tracemode |= ETM_CTRL_CONTEXTID_8; + break; + case 16: + tracemode |= ETM_CTRL_CONTEXTID_16; + break; + case 32: + tracemode |= ETM_CTRL_CONTEXTID_32; + break; + default: + command_print(CMD, "invalid option '%s'", CMD_ARGV[1]); + return ERROR_COMMAND_SYNTAX_ERROR; } bool etmv1_cycle_accurate; @@ -1205,14 +1201,14 @@ COMMAND_HANDLER(handle_etm_tracemode_command) uint32_t tracemode = etm->control; switch (CMD_ARGC) { - case 0: - break; - case 4: - CALL_COMMAND_HANDLER(handle_etm_tracemode_command_update, - &tracemode); - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 0: + break; + case 4: + CALL_COMMAND_HANDLER(handle_etm_tracemode_command_update, + &tracemode); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } /** @@ -1223,33 +1219,33 @@ COMMAND_HANDLER(handle_etm_tracemode_command) command_print(CMD, "current tracemode configuration:"); switch (tracemode & ETM_CTRL_TRACE_MASK) { - default: - command_print(CMD, "data tracing: none"); - break; - case ETM_CTRL_TRACE_DATA: - command_print(CMD, "data tracing: data only"); - break; - case ETM_CTRL_TRACE_ADDR: - command_print(CMD, "data tracing: address only"); - break; - case ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR: - command_print(CMD, "data tracing: address and data"); - break; + default: + command_print(CMD, "data tracing: none"); + break; + case ETM_CTRL_TRACE_DATA: + command_print(CMD, "data tracing: data only"); + break; + case ETM_CTRL_TRACE_ADDR: + command_print(CMD, "data tracing: address only"); + break; + case ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR: + command_print(CMD, "data tracing: address and data"); + break; } switch (tracemode & ETM_CTRL_CONTEXTID_MASK) { - case ETM_CTRL_CONTEXTID_NONE: - command_print(CMD, "contextid tracing: none"); - break; - case ETM_CTRL_CONTEXTID_8: - command_print(CMD, "contextid tracing: 8 bit"); - break; - case ETM_CTRL_CONTEXTID_16: - command_print(CMD, "contextid tracing: 16 bit"); - break; - case ETM_CTRL_CONTEXTID_32: - command_print(CMD, "contextid tracing: 32 bit"); - break; + case ETM_CTRL_CONTEXTID_NONE: + command_print(CMD, "contextid tracing: none"); + break; + case ETM_CTRL_CONTEXTID_8: + command_print(CMD, "contextid tracing: 8 bit"); + break; + case ETM_CTRL_CONTEXTID_16: + command_print(CMD, "contextid tracing: 16 bit"); + break; + case ETM_CTRL_CONTEXTID_32: + command_print(CMD, "contextid tracing: 32 bit"); + break; } if (tracemode & ETM_CTRL_CYCLE_ACCURATE) @@ -1337,39 +1333,39 @@ COMMAND_HANDLER(handle_etm_config_command) uint8_t port_width; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], port_width); switch (port_width) { - /* before ETMv3.0 */ - case 4: - portmode |= ETM_PORT_4BIT; - break; - case 8: - portmode |= ETM_PORT_8BIT; - break; - case 16: - portmode |= ETM_PORT_16BIT; - break; - /* ETMv3.0 and later*/ - case 24: - portmode |= ETM_PORT_24BIT; - break; - case 32: - portmode |= ETM_PORT_32BIT; - break; - case 48: - portmode |= ETM_PORT_48BIT; - break; - case 64: - portmode |= ETM_PORT_64BIT; - break; - case 1: - portmode |= ETM_PORT_1BIT; - break; - case 2: - portmode |= ETM_PORT_2BIT; - break; - default: - command_print(CMD, - "unsupported ETM port width '%s'", CMD_ARGV[1]); - return ERROR_FAIL; + /* before ETMv3.0 */ + case 4: + portmode |= ETM_PORT_4BIT; + break; + case 8: + portmode |= ETM_PORT_8BIT; + break; + case 16: + portmode |= ETM_PORT_16BIT; + break; + /* ETMv3.0 and later*/ + case 24: + portmode |= ETM_PORT_24BIT; + break; + case 32: + portmode |= ETM_PORT_32BIT; + break; + case 48: + portmode |= ETM_PORT_48BIT; + break; + case 64: + portmode |= ETM_PORT_64BIT; + break; + case 1: + portmode |= ETM_PORT_1BIT; + break; + case 2: + portmode |= ETM_PORT_2BIT; + break; + default: + command_print(CMD, + "unsupported ETM port width '%s'", CMD_ARGV[1]); + return ERROR_FAIL; } if (strcmp("normal", CMD_ARGV[2]) == 0) @@ -1500,38 +1496,38 @@ COMMAND_HANDLER(handle_etm_info_command) if (etm->bcd_vers >= 0x30) max_port_size |= (config >> 6) & 0x08; switch (max_port_size) { - /* before ETMv3.0 */ - case 0: - max_port_size = 4; - break; - case 1: - max_port_size = 8; - break; - case 2: - max_port_size = 16; - break; - /* ETMv3.0 and later*/ - case 3: - max_port_size = 24; - break; - case 4: - max_port_size = 32; - break; - case 5: - max_port_size = 48; - break; - case 6: - max_port_size = 64; - break; - case 8: - max_port_size = 1; - break; - case 9: - max_port_size = 2; - break; - default: - LOG_ERROR("Illegal max_port_size"); - return ERROR_FAIL; + /* before ETMv3.0 */ + case 0: + max_port_size = 4; + break; + case 1: + max_port_size = 8; + break; + case 2: + max_port_size = 16; + break; + /* ETMv3.0 and later*/ + case 3: + max_port_size = 24; + break; + case 4: + max_port_size = 32; + break; + case 5: + max_port_size = 48; + break; + case 6: + max_port_size = 64; + break; + case 8: + max_port_size = 1; + break; + case 9: + max_port_size = 2; + break; + default: + LOG_ERROR("Illegal max_port_size"); + return ERROR_FAIL; } command_print(CMD, "max. port size: %i", max_port_size); @@ -1970,19 +1966,19 @@ COMMAND_HANDLER(handle_etm_analyze_command) if (retval != ERROR_OK) { /* FIX! error should be reported inside etmv1_analyze_trace() */ switch (retval) { - case ERROR_ETM_ANALYSIS_FAILED: - command_print(CMD, - "further analysis failed (corrupted trace data or just end of data"); - break; - case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: - command_print(CMD, - "no instruction for current address available, analysis aborted"); - break; - case ERROR_TRACE_IMAGE_UNAVAILABLE: - command_print(CMD, "no image available for trace analysis"); - break; - default: - command_print(CMD, "unknown error"); + case ERROR_ETM_ANALYSIS_FAILED: + command_print(CMD, + "further analysis failed (corrupted trace data or just end of data"); + break; + case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: + command_print(CMD, + "no instruction for current address available, analysis aborted"); + break; + case ERROR_TRACE_IMAGE_UNAVAILABLE: + command_print(CMD, "no image available for trace analysis"); + break; + default: + command_print(CMD, "unknown error"); } } diff --git a/src/target/fa526.c b/src/target/fa526.c index d832d3e7d1..d56238aca1 100644 --- a/src/target/fa526.c +++ b/src/target/fa526.c @@ -80,15 +80,15 @@ static void fa526_read_core_regs_target_buffer(struct target *target, if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ switch (size) { - case 4: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; + case 4: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; } } } @@ -315,7 +315,7 @@ static int fa526_init_arch_info(struct target *target, arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches; arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches; arm920t->armv4_5_mmu.has_tiny_pages = 1; - arm920t->armv4_5_mmu.mmu_enabled = 0; + arm920t->armv4_5_mmu.mmu_enabled = false; /* disabling linefills leads to lockups, so keep them enabled for now * this doesn't affect correctness, but might affect timing issues, if @@ -385,4 +385,6 @@ struct target_type fa526_target = { .deinit_target = fa526_deinit_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/feroceon.c b/src/target/feroceon.c index cf2c838b7d..da2da1c0cf 100644 --- a/src/target/feroceon.c +++ b/src/target/feroceon.c @@ -191,15 +191,15 @@ static void feroceon_read_core_regs_target_buffer(struct target *target, for (i = 0; i <= 15; i++) { if (mask & (1 << i)) { switch (size) { - case 4: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; + case 4: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; } } } @@ -555,7 +555,7 @@ static int feroceon_bulk_write_memory(struct target *target, if (endaddress != address + count*4) { LOG_ERROR("DCC write failed," " expected end address 0x%08" TARGET_PRIxADDR - " got 0x%0" PRIx32 "", + " got 0x%0" PRIx32, address + count*4, endaddress); retval = ERROR_FAIL; } @@ -725,6 +725,8 @@ struct target_type feroceon_target = { .init_target = feroceon_init_target, .deinit_target = feroceon_deinit_target, .examine = feroceon_examine, + + .insn_set = armv4_5_insn_set, }; struct target_type dragonite_target = { @@ -763,4 +765,6 @@ struct target_type dragonite_target = { .target_create = dragonite_target_create, .init_target = feroceon_init_target, .examine = feroceon_examine, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/hla_target.c b/src/target/hla_target.c index 983cd87394..65103412f8 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -619,6 +619,11 @@ 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 bool adapter_memory_ready(struct target *target) +{ + return true; +} + static const struct command_registration hla_command_handlers[] = { { .chain = arm_command_handlers, @@ -661,6 +666,7 @@ struct target_type hla_target = { .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = armv7m_get_gdb_reg_list, + .memory_ready = adapter_memory_ready, .read_memory = adapter_read_memory, .write_memory = adapter_write_memory, .checksum_memory = armv7m_checksum_memory, @@ -675,4 +681,6 @@ struct target_type hla_target = { .add_watchpoint = cortex_m_add_watchpoint, .remove_watchpoint = cortex_m_remove_watchpoint, .profiling = cortex_m_profiling, + + .insn_set = cortex_m_insn_set, }; diff --git a/src/target/image.c b/src/target/image.c index 44a4b58cdf..388ca37076 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -663,7 +663,7 @@ static int image_elf32_read_section(struct image *image, if (offset < filesz) { /* maximal size present in file for the current segment */ read_size = MIN(size, filesz - offset); - LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", 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); @@ -717,7 +717,7 @@ static int image_elf64_read_section(struct image *image, if (offset < filesz) { /* maximal size present in file for the current segment */ read_size = MIN(size, filesz - offset); - LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size, + 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); @@ -828,36 +828,35 @@ static int image_mot_buffer_complete_inner(struct image *image, } } else if (record_type >= 1 && record_type <= 3) { switch (record_type) { - case 1: - /* S1 - 16 bit address data record */ - sscanf(&lpsz_line[bytes_read], "%4" SCNx32, &address); - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - bytes_read += 4; - count -= 2; - break; - - case 2: - /* S2 - 24 bit address data record */ - 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; - bytes_read += 6; - count -= 3; - break; - - case 3: - /* S3 - 32 bit address data record */ - 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); - cal_checksum += (uint8_t)address; - bytes_read += 8; - count -= 4; - break; - + case 1: + /* S1 - 16 bit address data record */ + sscanf(&lpsz_line[bytes_read], "%4" SCNx32, &address); + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + bytes_read += 4; + count -= 2; + break; + + case 2: + /* S2 - 24 bit address data record */ + 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; + bytes_read += 6; + count -= 3; + break; + + case 3: + /* S3 - 32 bit address data record */ + 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); + cal_checksum += (uint8_t)address; + bytes_read += 8; + count -= 4; + break; } if (full_address != address) { @@ -1101,7 +1100,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" TARGET_PRIxADDR " + 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); diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index c5618c9ccd..3e62e35e92 100644 --- a/src/target/mem_ap.c +++ b/src/target/mem_ap.c @@ -143,7 +143,6 @@ static int mem_ap_examine(struct target *target) return ERROR_FAIL; } } - target_set_examined(target); target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_UNDEFINED; return mem_ap_init(mem_ap->ap); diff --git a/src/target/mips32.c b/src/target/mips32.c index 4527c5fa88..831477471a 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -238,7 +238,6 @@ static const struct { static int mips32_get_core_reg(struct reg *reg) { - int retval; struct mips32_core_reg *mips32_reg = reg->arch_info; struct target *target = mips32_reg->target; struct mips32_common *mips32_target = target_to_mips32(target); @@ -246,9 +245,7 @@ static int mips32_get_core_reg(struct reg *reg) if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - retval = mips32_target->read_core_reg(target, mips32_reg->num); - - return retval; + return mips32_target->read_core_reg(target, mips32_reg->num); } static int mips32_set_core_reg(struct reg *reg, uint8_t *buf) @@ -374,7 +371,7 @@ static int mips32_read_core_reg(struct target *target, unsigned int num) 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); + LOG_DEBUG("read core reg %i value 0x%" PRIx64, num, reg_value); return ERROR_OK; } @@ -419,7 +416,7 @@ static int mips32_write_core_reg(struct target *target, unsigned int num) mips32->core_regs.gpr[cnum] = (uint32_t)reg_value; } - LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, 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; @@ -485,7 +482,7 @@ int mips32_arch_state(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); - LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32 "", + 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_REGLIST_C0_PC_INDEX].value, 0, 32)); @@ -734,8 +731,6 @@ int mips32_examine(struct target *target) struct mips32_common *mips32 = target_to_mips32(target); if (!target_was_examined(target)) { - target_set_examined(target); - /* we will configure later */ mips32->bp_scanned = 0; mips32->num_inst_bpoints = 0; @@ -770,8 +765,7 @@ static int mips32_configure_ibs(struct target *target) (ejtag_info->ejtag_iba_step_size * i); /* clear IBIS reg */ - retval = target_write_u32(target, ejtag_info->ejtag_ibs_addr, 0); - return retval; + return target_write_u32(target, ejtag_info->ejtag_ibs_addr, 0); } static int mips32_configure_dbs(struct target *target) @@ -797,8 +791,7 @@ static int mips32_configure_dbs(struct target *target) (ejtag_info->ejtag_dba_step_size * i); /* clear DBIS reg */ - retval = target_write_u32(target, ejtag_info->ejtag_dbs_addr, 0); - return retval; + return target_write_u32(target, ejtag_info->ejtag_dbs_addr, 0); } int mips32_configure_break_unit(struct target *target) @@ -1310,8 +1303,8 @@ int mips32_checksum_memory(struct target *target, target_addr_t address, /** Checks whether a memory region is erased. */ int mips32_blank_check_memory(struct target *target, - struct target_memory_check_block *blocks, int num_blocks, - uint8_t erased_value) + struct target_memory_check_block *blocks, unsigned int num_blocks, + uint8_t erased_value, unsigned int *checked) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; @@ -1367,8 +1360,10 @@ int mips32_blank_check_memory(struct target *target, retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address, erase_check_algorithm->address + (sizeof(erase_check_code) - 4), 10000, &mips32_info); - if (retval == ERROR_OK) + if (retval == ERROR_OK) { blocks[0].result = buf_get_u32(reg_params[2].value, 0, 32); + *checked = 1; /* only one block has been checked */ + } destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); @@ -1377,10 +1372,7 @@ int mips32_blank_check_memory(struct target *target, cleanup: target_free_working_area(target, erase_check_algorithm); - if (retval != ERROR_OK) - return retval; - - return 1; /* only one block has been checked */ + return retval; } static int mips32_verify_pointer(struct command_invocation *cmd, @@ -1687,26 +1679,25 @@ COMMAND_HANDLER(mips32_handle_cp0_command) } 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; + 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; @@ -2003,20 +1994,20 @@ COMMAND_HANDLER(mips32_handle_cpuinfo_command) uint32_t mmu_type = (config0 >> 7) & 7; /* MMU Type Info */ char *mmu; switch (mmu_type) { - case MIPS32_MMU_TLB: - mmu = "TLB"; + case MIPS32_MMU_TLB: + mmu = "TLB"; break; - case MIPS32_MMU_BAT: - mmu = "BAT"; + case MIPS32_MMU_BAT: + mmu = "BAT"; break; - case MIPS32_MMU_FIXED: - mmu = "FIXED"; + case MIPS32_MMU_FIXED: + mmu = "FIXED"; break; - case MIPS32_MMU_DUAL_VTLB_FTLB: - mmu = "DUAL VAR/FIXED"; + case MIPS32_MMU_DUAL_VTLB_FTLB: + mmu = "DUAL VAR/FIXED"; break; - default: - mmu = "Unknown"; + default: + mmu = "Unknown"; } command_print(CMD, "MMU Type: %s", mmu); @@ -2262,25 +2253,25 @@ COMMAND_HANDLER(mips32_handle_dsp_command) } switch (CMD_ARGC) { - case 0: - retval = mips32_dsp_get_all_regs(CMD, mips32); - break; - case 1: - retval = mips32_dsp_get_register(CMD, mips32); - 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, mips32); - } - break; - default: - command_print(CMD, "Error: invalid argument format, required 0-2, given %d", CMD_ARGC); + case 0: + retval = mips32_dsp_get_all_regs(CMD, mips32); + break; + case 1: + retval = mips32_dsp_get_register(CMD, mips32); + break; + case 2: + tmp = *CMD_ARGV[0]; + if (isdigit(tmp)) { + command_print(CMD, "Error: invalid dsp command format"); retval = ERROR_COMMAND_ARGUMENT_INVALID; - break; + } else { + retval = mips32_dsp_set_register(CMD, mips32); + } + break; + default: + command_print(CMD, "Error: invalid argument format, required 0-2, given %d", CMD_ARGC); + retval = ERROR_COMMAND_ARGUMENT_INVALID; + break; } return retval; } diff --git a/src/target/mips32.h b/src/target/mips32.h index 3d919e7ddb..bd797af516 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -933,7 +933,8 @@ int mips32_get_gdb_reg_list(struct target *target, int mips32_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int mips32_blank_check_memory(struct target *target, - struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); + struct target_memory_check_block *blocks, unsigned int num_blocks, + uint8_t erased_value, unsigned int *checked); bool mips32_cpu_support_sync(struct mips_ejtag *ejtag_info); bool mips32_cpu_support_hazard_barrier(struct mips_ejtag *ejtag_info); diff --git a/src/target/mips32_dmaacc.c b/src/target/mips32_dmaacc.c index beffbf51ee..030a24a5cd 100644 --- a/src/target/mips32_dmaacc.c +++ b/src/target/mips32_dmaacc.c @@ -186,18 +186,18 @@ static int ejtag_dma_read_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint8_ /* Handle the bigendian/littleendian */ switch (addr & 0x3) { - case 0: - *data = v & 0xff; - break; - case 1: - *data = (v >> 8) & 0xff; - break; - case 2: - *data = (v >> 16) & 0xff; - break; - case 3: - *data = (v >> 24) & 0xff; - break; + case 0: + *data = v & 0xff; + break; + case 1: + *data = (v >> 8) & 0xff; + break; + case 2: + *data = (v >> 16) & 0xff; + break; + case 3: + *data = (v >> 24) & 0xff; + break; } return ERROR_OK; @@ -341,12 +341,12 @@ static int ejtag_dma_write_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint3 int mips32_dmaacc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf) { switch (size) { - case 1: - return mips32_dmaacc_read_mem8(ejtag_info, addr, count, (uint8_t *)buf); - case 2: - return mips32_dmaacc_read_mem16(ejtag_info, addr, count, (uint16_t *)buf); - case 4: - return mips32_dmaacc_read_mem32(ejtag_info, addr, count, (uint32_t *)buf); + case 1: + return mips32_dmaacc_read_mem8(ejtag_info, addr, count, (uint8_t *)buf); + case 2: + return mips32_dmaacc_read_mem16(ejtag_info, addr, count, (uint16_t *)buf); + case 4: + return mips32_dmaacc_read_mem32(ejtag_info, addr, count, (uint32_t *)buf); } return ERROR_OK; @@ -397,12 +397,12 @@ static int mips32_dmaacc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int mips32_dmaacc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, const void *buf) { switch (size) { - case 1: - return mips32_dmaacc_write_mem8(ejtag_info, addr, count, buf); - case 2: - return mips32_dmaacc_write_mem16(ejtag_info, addr, count, buf); - case 4: - return mips32_dmaacc_write_mem32(ejtag_info, addr, count, buf); + case 1: + return mips32_dmaacc_write_mem8(ejtag_info, addr, count, buf); + case 2: + return mips32_dmaacc_write_mem16(ejtag_info, addr, count, buf); + case 4: + return mips32_dmaacc_write_mem32(ejtag_info, addr, count, buf); } return ERROR_OK; diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c index ea90d6f83a..9a22a5031e 100644 --- a/src/target/mips32_pracc.c +++ b/src/target/mips32_pracc.c @@ -819,19 +819,19 @@ int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int siz 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; + 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; } /** @@ -1256,19 +1256,19 @@ static int mips32_pracc_fastdata_xfer_synchronize_cache(struct mips_ejtag *ejtag 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; + 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; } /** diff --git a/src/target/mips64.c b/src/target/mips64.c index 3d193a3009..3051f95c4d 100644 --- a/src/target/mips64.c +++ b/src/target/mips64.c @@ -224,7 +224,6 @@ static int reg_type2size(enum reg_type type) static int mips64_get_core_reg(struct reg *reg) { - int retval; struct mips64_core_reg *mips64_reg = reg->arch_info; struct target *target = mips64_reg->target; struct mips64_common *mips64_target = target->arch_info; @@ -232,9 +231,7 @@ static int mips64_get_core_reg(struct reg *reg) if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - retval = mips64_target->read_core_reg(target, mips64_reg->num); - - return retval; + return mips64_target->read_core_reg(target, mips64_reg->num); } static int mips64_set_core_reg(struct reg *reg, uint8_t *buf) @@ -283,7 +280,7 @@ 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); + LOG_DEBUG("write core reg %i value 0x%" PRIx64, num, reg_value); mips64->core_cache->reg_list[num].valid = true; mips64->core_cache->reg_list[num].dirty = false; @@ -361,7 +358,7 @@ int mips64_arch_state(struct target *target) exit(-1); } - LOG_USER("target halted due to %s, pc: 0x%" PRIx64 "", + LOG_USER("target halted due to %s, pc: 0x%" PRIx64, debug_reason_name(target), buf_get_u64(pc->value, 0, 64)); return ERROR_OK; @@ -479,8 +476,6 @@ int mips64_examine(struct target *target) mips64->num_inst_bpoints = 0; mips64->num_inst_bpoints_avail = 0; - target_set_examined(target); - return ERROR_OK; } diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index 2ff4aa926f..750c53eba6 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -245,7 +245,7 @@ int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info) /* break bit will be cleared by hardware */ ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); - LOG_DEBUG("ejtag_ctrl: 0x%8.8" PRIx32 "", ejtag_ctrl); + LOG_DEBUG("ejtag_ctrl: 0x%8.8" PRIx32, ejtag_ctrl); if ((ejtag_ctrl & EJTAG_CTRL_BRKST) == 0) goto error; @@ -342,18 +342,18 @@ void ejtag_main_print_imp(struct mips_ejtag *ejtag_info) EJTAG_IMP_HAS(EJTAG_IMP_MIPS64) ? " MIPS64" : " MIPS32"); switch (ejtag_info->ejtag_version) { - case EJTAG_VERSION_20: - ejtag_v20_print_imp(ejtag_info); - break; - case EJTAG_VERSION_25: - case EJTAG_VERSION_26: - case EJTAG_VERSION_31: - case EJTAG_VERSION_41: - case EJTAG_VERSION_51: - ejtag_v26_print_imp(ejtag_info); - break; - default: - break; + case EJTAG_VERSION_20: + ejtag_v20_print_imp(ejtag_info); + break; + case EJTAG_VERSION_25: + case EJTAG_VERSION_26: + case EJTAG_VERSION_31: + case EJTAG_VERSION_41: + case EJTAG_VERSION_51: + ejtag_v26_print_imp(ejtag_info); + break; + default: + break; } } @@ -369,27 +369,27 @@ int mips_ejtag_init(struct mips_ejtag *ejtag_info) ejtag_info->ejtag_version = ((ejtag_info->impcode >> 29) & 0x07); switch (ejtag_info->ejtag_version) { - case EJTAG_VERSION_20: - LOG_DEBUG("EJTAG: Version 1 or 2.0 Detected"); - break; - case EJTAG_VERSION_25: - LOG_DEBUG("EJTAG: Version 2.5 Detected"); - break; - case EJTAG_VERSION_26: - LOG_DEBUG("EJTAG: Version 2.6 Detected"); - break; - case EJTAG_VERSION_31: - LOG_DEBUG("EJTAG: Version 3.1 Detected"); - break; - case EJTAG_VERSION_41: - LOG_DEBUG("EJTAG: Version 4.1 Detected"); - break; - case EJTAG_VERSION_51: - LOG_DEBUG("EJTAG: Version 5.1 Detected"); - break; - default: - LOG_DEBUG("EJTAG: Unknown Version Detected"); - break; + case EJTAG_VERSION_20: + LOG_DEBUG("EJTAG: Version 1 or 2.0 Detected"); + break; + case EJTAG_VERSION_25: + LOG_DEBUG("EJTAG: Version 2.5 Detected"); + break; + case EJTAG_VERSION_26: + LOG_DEBUG("EJTAG: Version 2.6 Detected"); + break; + case EJTAG_VERSION_31: + LOG_DEBUG("EJTAG: Version 3.1 Detected"); + break; + case EJTAG_VERSION_41: + LOG_DEBUG("EJTAG: Version 4.1 Detected"); + break; + case EJTAG_VERSION_51: + LOG_DEBUG("EJTAG: Version 5.1 Detected"); + break; + default: + LOG_DEBUG("EJTAG: Unknown Version Detected"); + break; } ejtag_main_print_imp(ejtag_info); diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index 4e27914a9d..49658b7353 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -486,11 +486,11 @@ static int mips_m4k_internal_restore(struct target *target, bool current, if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); + 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); + LOG_DEBUG("target debug resumed at 0x%" PRIx32, resume_pc); } return ERROR_OK; @@ -638,7 +638,7 @@ static int mips_m4k_set_breakpoint(struct target *target, ejtag_info->ejtag_ibm_offs, 0x00000000); target_write_u32(target, comparator_list[bp_num].reg_address + ejtag_info->ejtag_ibc_offs, 1); - LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32 "", + LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32, breakpoint->unique_id, bp_num, comparator_list[bp_num].bp_value); } else if (breakpoint->type == BKPT_SOFT) { @@ -893,17 +893,17 @@ static int mips_m4k_set_watchpoint(struct target *target, } switch (watchpoint->rw) { - case WPT_READ: - enable &= ~EJTAG_DBCN_NOLB; - break; - case WPT_WRITE: - enable &= ~EJTAG_DBCN_NOSB; - break; - case WPT_ACCESS: - enable &= ~(EJTAG_DBCN_NOLB | EJTAG_DBCN_NOSB); - break; - default: - LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + case WPT_READ: + enable &= ~EJTAG_DBCN_NOLB; + break; + case WPT_WRITE: + enable &= ~EJTAG_DBCN_NOSB; + break; + case WPT_ACCESS: + enable &= ~(EJTAG_DBCN_NOLB | EJTAG_DBCN_NOSB); + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } watchpoint_set(watchpoint, wp_num); @@ -928,7 +928,7 @@ static int mips_m4k_set_watchpoint(struct target *target, /* TODO: probably this value is ignored on 2.0 */ target_write_u32(target, comparator_list[wp_num].reg_address + ejtag_info->ejtag_dbv_offs, 0); - LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", wp_num, comparator_list[wp_num].bp_value); + LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32, wp_num, comparator_list[wp_num].bp_value); return ERROR_OK; } @@ -1012,7 +1012,7 @@ static int mips_m4k_read_memory(struct target *target, target_addr_t address, struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; - LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { @@ -1077,7 +1077,7 @@ static int mips_m4k_write_memory(struct target *target, target_addr_t address, struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; - LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { @@ -1204,7 +1204,7 @@ static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t addre int retval; int write_t = 1; - LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32, address, count); /* check alignment */ @@ -1270,7 +1270,7 @@ static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t addres int retval; int write_t = 0; - LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32, address, count); /* check alignment */ diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index a181a154ee..eb94399e66 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -473,7 +473,7 @@ static int mips_mips64_set_watchpoint(struct target *target, if (retval != ERROR_OK) return retval; - LOG_DEBUG("wp_num %i bp_value 0x%" PRIx64 "", wp_num, c->bp_value); + LOG_DEBUG("wp_num %i bp_value 0x%" PRIx64, wp_num, c->bp_value); return ERROR_OK; } @@ -642,7 +642,7 @@ static int mips_mips64_resume(struct target *target, bool current, /* Single step past breakpoint at current address */ bp = breakpoint_find(target, (uint64_t) resume_pc); if (bp) { - LOG_DEBUG("unset breakpoint at 0x%16.16" PRIx64 "", + LOG_DEBUG("unset breakpoint at 0x%16.16" PRIx64, bp->address); retval = mips_mips64_unset_breakpoint(target, bp); if (retval != ERROR_OK) @@ -682,7 +682,7 @@ static int mips_mips64_resume(struct target *target, bool current, if (retval != ERROR_OK) return retval; - LOG_DEBUG("target resumed at 0x%" PRIx64 "", resume_pc); + LOG_DEBUG("target resumed at 0x%" PRIx64, resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; retval = target_call_event_callbacks(target, @@ -690,7 +690,7 @@ static int mips_mips64_resume(struct target *target, bool current, if (retval != ERROR_OK) return retval; - LOG_DEBUG("target debug resumed at 0x%" PRIx64 "", resume_pc); + LOG_DEBUG("target debug resumed at 0x%" PRIx64, resume_pc); } return ERROR_OK; @@ -911,7 +911,7 @@ static int mips_mips64_read_memory(struct target *target, uint64_t address, } else t = buffer; - LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); retval = mips64_pracc_read_mem(ejtag_info, address, size, count, (void *)t); @@ -949,7 +949,7 @@ static int mips_mips64_bulk_write_memory(struct target *target, struct working_area *fast_data_area; int retval; - LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32, address, count); if (address & 0x7) @@ -1066,7 +1066,7 @@ static int mips_mips64_write_memory(struct target *target, uint64_t address, buffer = t; } - LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); retval = mips64_pracc_write_mem(ejtag_info, address, size, count, diff --git a/src/target/oocd_capstone.c b/src/target/oocd_capstone.c new file mode 100644 index 0000000000..8135fc77ff --- /dev/null +++ b/src/target/oocd_capstone.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * This file wraps the functions in capstone library. + * It also takes care of API changes across versions. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include +#include + +/* + * Extracted from Capstone tool 'cstool', file 'cstool/cstool.c'. + * Big rework expected for next Capstone v6. + */ +static struct { + const char *name; + cs_arch arch; + cs_mode mode; +} all_archs[] = { + { "arm", CS_ARCH_ARM, CS_MODE_ARM }, + { "armbe", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_BIG_ENDIAN }, + { "cortexm", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB | CS_MODE_MCLASS }, + { "thumb", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB }, + +#if CS_API_MAJOR < 6 + { "arm64", CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN }, + { "arm64be", CS_ARCH_ARM64, CS_MODE_BIG_ENDIAN }, +#if CS_API_MAJOR >= 5 + { "riscv32", CS_ARCH_RISCV, CS_MODE_RISCV32 | CS_MODE_RISCVC }, + { "riscv64", CS_ARCH_RISCV, CS_MODE_RISCV64 | CS_MODE_RISCVC }, +#endif +#endif /* CS_API_MAJOR < 6 */ + +#if CS_API_MAJOR >= 6 + { "arm64", CS_ARCH_AARCH64, CS_MODE_LITTLE_ENDIAN }, + { "arm64be", CS_ARCH_AARCH64, CS_MODE_BIG_ENDIAN }, + { "riscv32", CS_ARCH_RISCV, CS_MODE_RISCV32 | CS_MODE_RISCV_C }, + { "riscv64", CS_ARCH_RISCV, CS_MODE_RISCV64 | CS_MODE_RISCV_C }, + { "xtensa", CS_ARCH_XTENSA, CS_MODE_XTENSA_ESP32 }, + { "xtensa_s2", CS_ARCH_XTENSA, CS_MODE_XTENSA_ESP32S2 }, + { "xtensa_8266", CS_ARCH_XTENSA, CS_MODE_XTENSA_ESP8266 }, + { "arc", CS_ARCH_ARC, CS_MODE_LITTLE_ENDIAN }, +#endif /* CS_API_MAJOR >= 6 */ +}; + +int oocd_cs_list_insn_types(struct command_invocation *cmd) +{ + for (size_t i = 0; i < ARRAY_SIZE(all_archs); i++) + command_print_sameline(cmd, (i == 0) ? "%s" : " %s", + all_archs[i].name); + + return ERROR_OK; +} + +static void print_opcode(struct command_invocation *cmd, const cs_insn *insn) +{ + char opcode[3 * ARRAY_SIZE(insn->bytes) + 1]; + + for (uint16_t i = 0; i < insn->size; i++) + sprintf(&opcode[3 * i], " %02" PRIx8, insn->bytes[i]); + + command_print(cmd, "0x%08" PRIx64 " %s\t%s%s%s", + insn->address, opcode, insn->mnemonic, + insn->op_str[0] ? "\t" : "", insn->op_str); +} + +int oocd_cs_disassemble(struct command_invocation *cmd, struct target *target, + uint64_t address, unsigned int count, const char *insn_set) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(all_archs); i++) + if (!strcmp(insn_set, all_archs[i].name)) + break; + + if (i == ARRAY_SIZE(all_archs)) { + command_print(cmd, "Instruction set \"%s\" not supported by Capstone", insn_set); + return ERROR_FAIL; + } + + csh handle; + cs_err csret = cs_open(all_archs[i].arch, all_archs[i].mode, &handle); + if (csret != CS_ERR_OK) { + command_print(cmd, "Capstone 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) { + command_print(cmd, "Capstone cs_option() failed: %s", cs_strerror(csret)); + cs_close(&handle); + return ERROR_FAIL; + } + + cs_insn *insn = cs_malloc(handle); + if (!insn) { + command_print(cmd, "Capstone cs_malloc() failed: %s", cs_strerror(csret)); + cs_close(&handle); + return ERROR_FAIL; + } + + while (count > 0) { + uint8_t buf[4]; + + int retval = target_read_buffer(target, address, sizeof(buf), buf); + if (retval != ERROR_OK) { + cs_free(insn, 1); + cs_close(&handle); + return retval; + } + + size_t size = sizeof(buf); + const uint8_t *tmp = buf; + bool csbool = cs_disasm_iter(handle, &tmp, &size, &address, insn); + if (!csbool) { + command_print(cmd, "Capstone cs_disasm_iter() failed: %s", cs_strerror(csret)); + 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; +} diff --git a/src/target/oocd_capstone.h b/src/target/oocd_capstone.h new file mode 100644 index 0000000000..7233b68136 --- /dev/null +++ b/src/target/oocd_capstone.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_TARGET_WRAP_CAPSTONE_H +#define OPENOCD_TARGET_WRAP_CAPSTONE_H + +#include + +struct command_invocation; +struct target; + +#ifdef HAVE_CAPSTONE + +int oocd_cs_list_insn_types(struct command_invocation *cmd); +int oocd_cs_disassemble(struct command_invocation *cmd, struct target *target, + uint64_t address, unsigned int count, const char *insn_set); + +#else /* HAVE_CAPSTONE */ + +#include +#include + +static inline +int oocd_cs_list_insn_types(struct command_invocation *cmd) +{ + command_print(cmd, "Capstone library not present"); + return ERROR_NOT_IMPLEMENTED; +} + +static inline +int oocd_cs_disassemble(struct command_invocation *cmd, struct target *target, + uint64_t address, unsigned int count, const char *insn_set) +{ + command_print(cmd, "Capstone library not present"); + return ERROR_NOT_IMPLEMENTED; +} + +#endif /* HAVE_CAPSTONE */ + +#endif /* OPENOCD_TARGET_WRAP_CAPSTONE_H */ diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index 185a506c45..60cbb49834 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -118,50 +118,49 @@ static int jsp_input(struct connection *connection) buf_p = buffer; while (bytes_read) { switch (t_con->state) { - case TELNET_STATE_DATA: - if (*buf_p == 0xff) - t_con->state = TELNET_STATE_IAC; - else { - int out_len = 1; - int in_len; - unsigned char in_buffer[10]; - or1k_adv_jtag_jsp_xfer(jsp_service->jtag_info, - &out_len, buf_p, &in_len, - in_buffer); - if (in_len) - telnet_write(connection, - in_buffer, in_len); - } + case TELNET_STATE_DATA: + if (*buf_p == 0xff) { + t_con->state = TELNET_STATE_IAC; + } else { + int out_len = 1; + int in_len; + unsigned char in_buffer[10]; + or1k_adv_jtag_jsp_xfer(jsp_service->jtag_info, + &out_len, buf_p, &in_len, + in_buffer); + if (in_len) + telnet_write(connection, in_buffer, in_len); + } + break; + case TELNET_STATE_IAC: + switch (*buf_p) { + case 0xfe: + t_con->state = TELNET_STATE_DONT; break; - case TELNET_STATE_IAC: - switch (*buf_p) { - case 0xfe: - t_con->state = TELNET_STATE_DONT; - break; - case 0xfd: - t_con->state = TELNET_STATE_DO; - break; - case 0xfc: - t_con->state = TELNET_STATE_WONT; - break; - case 0xfb: - t_con->state = TELNET_STATE_WILL; - break; - } + case 0xfd: + t_con->state = TELNET_STATE_DO; break; - case TELNET_STATE_SB: + case 0xfc: + t_con->state = TELNET_STATE_WONT; break; - case TELNET_STATE_SE: + case 0xfb: + t_con->state = TELNET_STATE_WILL; break; - case TELNET_STATE_WILL: - case TELNET_STATE_WONT: - case TELNET_STATE_DO: - case TELNET_STATE_DONT: - t_con->state = TELNET_STATE_DATA; - break; - default: - LOG_ERROR("unknown telnet state"); - exit(-1); + } + break; + case TELNET_STATE_SB: + break; + case TELNET_STATE_SE: + break; + case TELNET_STATE_WILL: + case TELNET_STATE_WONT: + case TELNET_STATE_DO: + case TELNET_STATE_DONT: + t_con->state = TELNET_STATE_DATA; + break; + default: + LOG_ERROR("unknown telnet state"); + exit(-1); } bytes_read--; @@ -196,10 +195,19 @@ static const struct service_driver jsp_service_driver = { int jsp_init(struct or1k_jtag *jtag_info, char *banner) { struct jsp_service *jsp_service = malloc(sizeof(struct jsp_service)); + if (!jsp_service) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + jsp_service->banner = banner; jsp_service->jtag_info = jtag_info; - return add_service(&jsp_service_driver, jsp_port, 1, jsp_service); + int retval = add_service(&jsp_service_driver, jsp_port, 1, jsp_service); + if (retval != ERROR_OK) + free(jsp_service); + + return retval; } COMMAND_HANDLER(handle_jsp_port_command) diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index 4aa2bd7347..200a97dfeb 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -1124,8 +1124,6 @@ static int or1k_examine(struct target *target) if (!target_was_examined(target)) { - target_set_examined(target); - int running; int retval = du_core->or1k_is_cpu_running(&or1k->jtag, &running); @@ -1202,13 +1200,11 @@ static int or1k_checksum_memory(struct target *target, target_addr_t address, static int or1k_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { - struct timeval timeout, now; struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); int retval = ERROR_OK; - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, seconds, 0); + int64_t then = timeval_ms() + seconds * 1000LL; LOG_INFO("Starting or1k profiling. Sampling npc as fast as we can..."); @@ -1234,8 +1230,7 @@ static int or1k_profiling(struct target *target, uint32_t *samples, samples[sample_count++] = reg_value; - gettimeofday(&now, NULL); - if ((sample_count >= max_num_samples) || timeval_compare(&now, &timeout) > 0) { + if (sample_count >= max_num_samples || timeval_ms() > then) { LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); break; } diff --git a/src/target/openrisc/or1k_du_adv.c b/src/target/openrisc/or1k_du_adv.c index f401ea9fb5..1b5ce9618d 100644 --- a/src/target/openrisc/or1k_du_adv.c +++ b/src/target/openrisc/or1k_du_adv.c @@ -686,8 +686,7 @@ static int adbg_wb_burst_write(struct or1k_jtag *jtag_info, const uint8_t *data, bus_error_retries++; if (bus_error_retries > MAX_BUS_ERRORS) { LOG_ERROR("Max WB bus errors reached during burst read"); - retval = ERROR_FAIL; - return retval; + return ERROR_FAIL; } /* Don't call retry_do(), a JTAG reset won't help a WB bus error */ diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index ec68b3798f..5acbddaf37 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -172,7 +172,7 @@ static unsigned int decode_dmi(const struct riscv_batch *batch, char *text, for (unsigned int i = 0; i < ARRAY_SIZE(description); i++) { if (riscv_get_dmi_address(batch->target, description[i].address) == address) { - const riscv_debug_reg_ctx_t context = { + const struct riscv_debug_reg_ctx context = { .XLEN = { .value = 0, .is_set = false }, .DXLEN = { .value = 0, .is_set = false }, .abits = { .value = 0, .is_set = false }, @@ -204,7 +204,7 @@ static void log_batch(const struct riscv_batch *batch, size_t start_idx, const struct riscv_scan_delays *delays, bool resets_delays, size_t reset_delays_after) { - if (debug_level < LOG_LVL_DEBUG) + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; const unsigned int abits = riscv_get_dmi_address_bits(batch->target); diff --git a/src/target/riscv/debug_defines.c b/src/target/riscv/debug_defines.c index d514c6e033..0fe43a1619 100644 --- a/src/target/riscv/debug_defines.c +++ b/src/target/riscv/debug_defines.c @@ -1,14 +1,12 @@ -/* - * This file is auto-generated by running 'make debug_defines' in - * https://github.com/riscv/riscv-debug-spec/ (40b9a05) - */ +// SPDX-License-Identifier: BSD-2-Clause OR CC-BY-4.0 +/* This file was auto-generated by running 'make debug_defines' in https://github.com/riscv/riscv-debug-spec/ (22a7576) */ #include "debug_defines.h" #include #include -static riscv_debug_reg_field_list_t dtm_idcode_get_version(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_idcode_get_version(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "Version", .lsb = 0x1c, @@ -20,9 +18,9 @@ static riscv_debug_reg_field_list_t dtm_idcode_get_version(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dtm_idcode_get_partnumber(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_idcode_get_partnumber(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "PartNumber", .lsb = 0xc, @@ -34,9 +32,9 @@ static riscv_debug_reg_field_list_t dtm_idcode_get_partnumber(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t dtm_idcode_get_manufid(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_idcode_get_manufid(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "ManufId", .lsb = 1, @@ -48,9 +46,9 @@ static riscv_debug_reg_field_list_t dtm_idcode_get_manufid(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dtm_idcode_get_1(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_idcode_get_1(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "1", .lsb = 0, @@ -74,9 +72,9 @@ static const char *dtm_dtmcs_version_values[16] = { [1] = "1_0", [15] = "custom" }; -static riscv_debug_reg_field_list_t dtm_dtmcs_get_abits(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_dtmcs_get_abits(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "abits", .lsb = 4, @@ -88,9 +86,9 @@ static riscv_debug_reg_field_list_t dtm_dtmcs_get_abits(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t dtm_dtmcs_get_errinfo(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_dtmcs_get_errinfo(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "errinfo", .lsb = 0x12, @@ -102,9 +100,9 @@ static riscv_debug_reg_field_list_t dtm_dtmcs_get_errinfo(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dtm_dtmcs_get_dtmhardreset(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_dtmcs_get_dtmhardreset(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dtmhardreset", .lsb = 0x11, @@ -116,9 +114,9 @@ static riscv_debug_reg_field_list_t dtm_dtmcs_get_dtmhardreset(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t dtm_dtmcs_get_dmireset(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_dtmcs_get_dmireset(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dmireset", .lsb = 0x10, @@ -130,9 +128,9 @@ static riscv_debug_reg_field_list_t dtm_dtmcs_get_dmireset(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dtm_dtmcs_get_idle(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_dtmcs_get_idle(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "idle", .lsb = 0xc, @@ -144,9 +142,9 @@ static riscv_debug_reg_field_list_t dtm_dtmcs_get_idle(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t dtm_dtmcs_get_dmistat(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_dtmcs_get_dmistat(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dmistat", .lsb = 0xa, @@ -158,9 +156,9 @@ static riscv_debug_reg_field_list_t dtm_dtmcs_get_dmistat(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dtm_dtmcs_get_version(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_dtmcs_get_version(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "version", .lsb = 0, @@ -173,10 +171,10 @@ static riscv_debug_reg_field_list_t dtm_dtmcs_get_version(riscv_debug_reg_ctx_t } static const char *dtm_dmi_op_values[4] = {}; -static riscv_debug_reg_field_list_t dtm_dmi_get_address(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_dmi_get_address(struct riscv_debug_reg_ctx context) { assert(context.abits.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "address", .lsb = 0x22, @@ -188,9 +186,9 @@ static riscv_debug_reg_field_list_t dtm_dmi_get_address(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t dtm_dmi_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_dmi_get_data(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 2, @@ -202,9 +200,9 @@ static riscv_debug_reg_field_list_t dtm_dmi_get_data(riscv_debug_reg_ctx_t conte return result; } -static riscv_debug_reg_field_list_t dtm_dmi_get_op(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dtm_dmi_get_op(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "op", .lsb = 0, @@ -222,6 +220,17 @@ static const char *csr_dcsr_debugver_values[16] = { [4] = "1_0", [15] = "custom" }; +static const char *csr_dcsr_extcause_values[8] = { + [0] = "critical_error" +}; +static const char *csr_dcsr_cetrig_values[2] = { + [0] = "disabled", + [1] = "enabled" +}; +static const char *csr_dcsr_pelp_values[2] = { + [0] = "NO_LP_EXPECTED", + [1] = "LP_EXPECTED" +}; static const char *csr_dcsr_ebreakvs_values[2] = { [0] = "exception", [1] = "debug_mode" @@ -260,15 +269,16 @@ static const char *csr_dcsr_cause_values[8] = { [3] = "haltreq", [4] = "step", [5] = "resethaltreq", - [6] = "group" + [6] = "group", + [7] = "other" }; static const char *csr_dcsr_mprven_values[2] = { [0] = "disabled", [1] = "enabled" }; -static riscv_debug_reg_field_list_t csr_dcsr_get_stoptime(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_stoptime(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "stoptime", .lsb = 9, @@ -280,9 +290,9 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_stoptime(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_cause(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_cause(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "cause", .lsb = 6, @@ -294,9 +304,9 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_cause(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_v(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_v(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "v", .lsb = 5, @@ -308,9 +318,9 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_v(riscv_debug_reg_ctx_t context return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_mprven(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_mprven(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "mprven", .lsb = 4, @@ -322,9 +332,9 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_mprven(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_nmip(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_nmip(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "nmip", .lsb = 3, @@ -336,9 +346,9 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_nmip(riscv_debug_reg_ctx_t cont return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_debugver(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_debugver(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "debugver", .lsb = 0x1c, @@ -350,37 +360,79 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_debugver(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_step(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_extcause(struct riscv_debug_reg_ctx context) +{ + struct riscv_debug_reg_field_list result = { + .field = { + .name = "extcause", + .lsb = 0x18, + .msb = 0x1a, + .values = csr_dcsr_extcause_values + }, + .get_next = csr_dcsr_get_debugver + }; + return result; +} + +static struct riscv_debug_reg_field_list csr_dcsr_get_step(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "step", .lsb = 2, .msb = 2, .values = NULL }, - .get_next = csr_dcsr_get_debugver + .get_next = csr_dcsr_get_extcause + }; + return result; +} + +static struct riscv_debug_reg_field_list csr_dcsr_get_cetrig(struct riscv_debug_reg_ctx context) +{ + struct riscv_debug_reg_field_list result = { + .field = { + .name = "cetrig", + .lsb = 0x13, + .msb = 0x13, + .values = csr_dcsr_cetrig_values + }, + .get_next = csr_dcsr_get_step + }; + return result; +} + +static struct riscv_debug_reg_field_list csr_dcsr_get_pelp(struct riscv_debug_reg_ctx context) +{ + struct riscv_debug_reg_field_list result = { + .field = { + .name = "pelp", + .lsb = 0x12, + .msb = 0x12, + .values = csr_dcsr_pelp_values + }, + .get_next = csr_dcsr_get_cetrig }; return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_ebreakvs(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_ebreakvs(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "ebreakvs", .lsb = 0x11, .msb = 0x11, .values = csr_dcsr_ebreakvs_values }, - .get_next = csr_dcsr_get_step + .get_next = csr_dcsr_get_pelp }; return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_ebreakvu(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_ebreakvu(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "ebreakvu", .lsb = 0x10, @@ -392,9 +444,9 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_ebreakvu(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_ebreakm(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_ebreakm(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "ebreakm", .lsb = 0xf, @@ -406,9 +458,9 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_ebreakm(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_ebreaks(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_ebreaks(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "ebreaks", .lsb = 0xd, @@ -420,9 +472,9 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_ebreaks(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_ebreaku(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_ebreaku(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "ebreaku", .lsb = 0xc, @@ -434,9 +486,9 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_ebreaku(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_stepie(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_stepie(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "stepie", .lsb = 0xb, @@ -448,9 +500,9 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_stepie(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_stopcount(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_stopcount(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "stopcount", .lsb = 0xa, @@ -462,9 +514,9 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_stopcount(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_dcsr_get_prv(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dcsr_get_prv(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "prv", .lsb = 0, @@ -476,10 +528,10 @@ static riscv_debug_reg_field_list_t csr_dcsr_get_prv(riscv_debug_reg_ctx_t conte return result; } -static riscv_debug_reg_field_list_t csr_dpc_get_dpc(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dpc_get_dpc(struct riscv_debug_reg_ctx context) { assert(context.DXLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dpc", .lsb = 0, @@ -491,10 +543,10 @@ static riscv_debug_reg_field_list_t csr_dpc_get_dpc(riscv_debug_reg_ctx_t contex return result; } -static riscv_debug_reg_field_list_t csr_dscratch0_get_dscratch0(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dscratch0_get_dscratch0(struct riscv_debug_reg_ctx context) { assert(context.DXLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dscratch0", .lsb = 0, @@ -506,10 +558,10 @@ static riscv_debug_reg_field_list_t csr_dscratch0_get_dscratch0(riscv_debug_reg_ return result; } -static riscv_debug_reg_field_list_t csr_dscratch1_get_dscratch1(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_dscratch1_get_dscratch1(struct riscv_debug_reg_ctx context) { assert(context.DXLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dscratch1", .lsb = 0, @@ -521,10 +573,10 @@ static riscv_debug_reg_field_list_t csr_dscratch1_get_dscratch1(riscv_debug_reg_ return result; } -static riscv_debug_reg_field_list_t csr_tselect_get_index(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tselect_get_index(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "index", .lsb = 0, @@ -551,10 +603,10 @@ static const char *csr_tdata1_dmode_values[2] = { [0] = "both", [1] = "dmode" }; -static riscv_debug_reg_field_list_t csr_tdata1_get_dmode(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tdata1_get_dmode(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dmode", .lsb = (context.XLEN.value + -5), @@ -566,10 +618,10 @@ static riscv_debug_reg_field_list_t csr_tdata1_get_dmode(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_tdata1_get_type(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tdata1_get_type(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "type", .lsb = (context.XLEN.value + -4), @@ -581,10 +633,10 @@ static riscv_debug_reg_field_list_t csr_tdata1_get_type(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_tdata1_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tdata1_get_data(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 0, @@ -596,10 +648,10 @@ static riscv_debug_reg_field_list_t csr_tdata1_get_data(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_tdata2_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tdata2_get_data(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 0, @@ -611,10 +663,10 @@ static riscv_debug_reg_field_list_t csr_tdata2_get_data(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_tdata3_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tdata3_get_data(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 0, @@ -630,9 +682,9 @@ static const char *csr_tinfo_version_values[256] = { [0] = "0", [1] = "1" }; -static riscv_debug_reg_field_list_t csr_tinfo_get_version(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tinfo_get_version(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "version", .lsb = 0x18, @@ -644,9 +696,9 @@ static riscv_debug_reg_field_list_t csr_tinfo_get_version(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_tinfo_get_info(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tinfo_get_info(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "info", .lsb = 0, @@ -662,9 +714,9 @@ static const char *csr_tcontrol_mte_values[2] = { [0] = "disabled", [1] = "enabled" }; -static riscv_debug_reg_field_list_t csr_tcontrol_get_mpte(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tcontrol_get_mpte(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "mpte", .lsb = 7, @@ -676,9 +728,9 @@ static riscv_debug_reg_field_list_t csr_tcontrol_get_mpte(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_tcontrol_get_mte(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tcontrol_get_mte(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "mte", .lsb = 3, @@ -690,14 +742,13 @@ static riscv_debug_reg_field_list_t csr_tcontrol_get_mte(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_scontext_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_scontext_get_data(struct riscv_debug_reg_ctx context) { - assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 0, - .msb = (context.XLEN.value + -1), + .msb = 0x1f, .values = NULL }, .get_next = NULL @@ -705,14 +756,13 @@ static riscv_debug_reg_field_list_t csr_scontext_get_data(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_mcontext_get_hcontext(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontext_get_hcontext(struct riscv_debug_reg_ctx context) { - assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hcontext", .lsb = 0, - .msb = (context.XLEN.value + -1), + .msb = 0xd, .values = NULL }, .get_next = NULL @@ -754,10 +804,10 @@ static const char *csr_mcontrol_match_values[16] = { [12] = "not_mask_low", [13] = "not_mask_high" }; -static riscv_debug_reg_field_list_t csr_mcontrol_get_dmode(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_dmode(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dmode", .lsb = (context.XLEN.value + -5), @@ -769,10 +819,10 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_dmode(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_type(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_type(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "type", .lsb = (context.XLEN.value + -4), @@ -784,10 +834,10 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_type(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_maskmax(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_maskmax(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "maskmax", .lsb = (context.XLEN.value + -0xb), @@ -799,9 +849,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_maskmax(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_match(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_match(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "match", .lsb = 7, @@ -813,9 +863,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_match(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_m(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_m(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "m", .lsb = 6, @@ -827,9 +877,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_m(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_s(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_s(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "s", .lsb = 4, @@ -841,9 +891,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_s(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_u(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_u(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "u", .lsb = 3, @@ -855,9 +905,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_u(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_sizehi(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_sizehi(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sizehi", .lsb = 0x15, @@ -869,9 +919,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_sizehi(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_hit(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_hit(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hit", .lsb = 0x14, @@ -883,9 +933,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_hit(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_execute(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_execute(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "execute", .lsb = 2, @@ -897,9 +947,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_execute(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_select(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_select(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "select", .lsb = 0x13, @@ -911,9 +961,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_select(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_timing(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_timing(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "timing", .lsb = 0x12, @@ -925,9 +975,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_timing(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_sizelo(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_sizelo(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sizelo", .lsb = 0x10, @@ -939,9 +989,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_sizelo(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_action(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_action(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "action", .lsb = 0xc, @@ -953,9 +1003,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_action(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_chain(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_chain(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "chain", .lsb = 0xb, @@ -967,9 +1017,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_chain(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_store(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_store(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "store", .lsb = 1, @@ -981,9 +1031,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol_get_store(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_mcontrol_get_load(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol_get_load(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "load", .lsb = 0, @@ -1042,10 +1092,10 @@ static const char *csr_mcontrol6_uncertainen_values[2] = { [0] = "disabled", [1] = "enabled" }; -static riscv_debug_reg_field_list_t csr_mcontrol6_get_dmode(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_dmode(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dmode", .lsb = (context.XLEN.value + -5), @@ -1057,10 +1107,10 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_dmode(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_type(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_type(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "type", .lsb = (context.XLEN.value + -4), @@ -1072,9 +1122,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_type(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_match(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_match(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "match", .lsb = 7, @@ -1086,9 +1136,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_match(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_m(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_m(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "m", .lsb = 6, @@ -1100,9 +1150,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_m(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_uncertainen(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_uncertainen(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "uncertainen", .lsb = 5, @@ -1114,9 +1164,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_uncertainen(riscv_debug_re return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_s(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_s(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "s", .lsb = 4, @@ -1128,9 +1178,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_s(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_u(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_u(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "u", .lsb = 3, @@ -1142,9 +1192,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_u(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_uncertain(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_uncertain(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "uncertain", .lsb = 0x1a, @@ -1156,9 +1206,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_uncertain(riscv_debug_reg_ return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_hit1(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_hit1(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hit1", .lsb = 0x19, @@ -1170,9 +1220,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_hit1(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_vs(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_vs(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "vs", .lsb = 0x18, @@ -1184,9 +1234,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_vs(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_vu(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_vu(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "vu", .lsb = 0x17, @@ -1198,9 +1248,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_vu(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_hit0(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_hit0(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hit0", .lsb = 0x16, @@ -1212,9 +1262,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_hit0(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_select(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_select(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "select", .lsb = 0x15, @@ -1226,9 +1276,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_select(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_execute(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_execute(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "execute", .lsb = 2, @@ -1240,9 +1290,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_execute(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_size(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_size(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "size", .lsb = 0x10, @@ -1254,9 +1304,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_size(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_action(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_action(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "action", .lsb = 0xc, @@ -1268,9 +1318,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_action(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_chain(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_chain(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "chain", .lsb = 0xb, @@ -1282,9 +1332,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_chain(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_store(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_store(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "store", .lsb = 1, @@ -1296,9 +1346,9 @@ static riscv_debug_reg_field_list_t csr_mcontrol6_get_store(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t csr_mcontrol6_get_load(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_mcontrol6_get_load(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "load", .lsb = 0, @@ -1319,10 +1369,10 @@ static const char *csr_icount_action_values[64] = { [8] = "external0", [9] = "external1" }; -static riscv_debug_reg_field_list_t csr_icount_get_dmode(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_icount_get_dmode(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dmode", .lsb = (context.XLEN.value + -5), @@ -1334,10 +1384,10 @@ static riscv_debug_reg_field_list_t csr_icount_get_dmode(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_icount_get_type(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_icount_get_type(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "type", .lsb = (context.XLEN.value + -4), @@ -1349,9 +1399,9 @@ static riscv_debug_reg_field_list_t csr_icount_get_type(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_icount_get_m(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_icount_get_m(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "m", .lsb = 9, @@ -1363,9 +1413,9 @@ static riscv_debug_reg_field_list_t csr_icount_get_m(riscv_debug_reg_ctx_t conte return result; } -static riscv_debug_reg_field_list_t csr_icount_get_pending(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_icount_get_pending(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "pending", .lsb = 8, @@ -1377,9 +1427,9 @@ static riscv_debug_reg_field_list_t csr_icount_get_pending(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_icount_get_s(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_icount_get_s(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "s", .lsb = 7, @@ -1391,9 +1441,9 @@ static riscv_debug_reg_field_list_t csr_icount_get_s(riscv_debug_reg_ctx_t conte return result; } -static riscv_debug_reg_field_list_t csr_icount_get_u(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_icount_get_u(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "u", .lsb = 6, @@ -1405,9 +1455,9 @@ static riscv_debug_reg_field_list_t csr_icount_get_u(riscv_debug_reg_ctx_t conte return result; } -static riscv_debug_reg_field_list_t csr_icount_get_vs(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_icount_get_vs(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "vs", .lsb = 0x1a, @@ -1419,9 +1469,9 @@ static riscv_debug_reg_field_list_t csr_icount_get_vs(riscv_debug_reg_ctx_t cont return result; } -static riscv_debug_reg_field_list_t csr_icount_get_vu(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_icount_get_vu(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "vu", .lsb = 0x19, @@ -1433,9 +1483,9 @@ static riscv_debug_reg_field_list_t csr_icount_get_vu(riscv_debug_reg_ctx_t cont return result; } -static riscv_debug_reg_field_list_t csr_icount_get_hit(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_icount_get_hit(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hit", .lsb = 0x18, @@ -1447,9 +1497,9 @@ static riscv_debug_reg_field_list_t csr_icount_get_hit(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t csr_icount_get_count(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_icount_get_count(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "count", .lsb = 0xa, @@ -1461,9 +1511,9 @@ static riscv_debug_reg_field_list_t csr_icount_get_count(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_icount_get_action(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_icount_get_action(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "action", .lsb = 0, @@ -1484,10 +1534,10 @@ static const char *csr_itrigger_action_values[64] = { [8] = "external0", [9] = "external1" }; -static riscv_debug_reg_field_list_t csr_itrigger_get_hit(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_itrigger_get_hit(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hit", .lsb = (context.XLEN.value + -6), @@ -1499,10 +1549,10 @@ static riscv_debug_reg_field_list_t csr_itrigger_get_hit(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_itrigger_get_dmode(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_itrigger_get_dmode(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dmode", .lsb = (context.XLEN.value + -5), @@ -1514,10 +1564,10 @@ static riscv_debug_reg_field_list_t csr_itrigger_get_dmode(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_itrigger_get_type(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_itrigger_get_type(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "type", .lsb = (context.XLEN.value + -4), @@ -1529,9 +1579,9 @@ static riscv_debug_reg_field_list_t csr_itrigger_get_type(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_itrigger_get_m(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_itrigger_get_m(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "m", .lsb = 9, @@ -1543,9 +1593,9 @@ static riscv_debug_reg_field_list_t csr_itrigger_get_m(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t csr_itrigger_get_s(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_itrigger_get_s(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "s", .lsb = 7, @@ -1557,9 +1607,9 @@ static riscv_debug_reg_field_list_t csr_itrigger_get_s(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t csr_itrigger_get_u(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_itrigger_get_u(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "u", .lsb = 6, @@ -1571,9 +1621,9 @@ static riscv_debug_reg_field_list_t csr_itrigger_get_u(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t csr_itrigger_get_vs(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_itrigger_get_vs(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "vs", .lsb = 0xc, @@ -1585,9 +1635,9 @@ static riscv_debug_reg_field_list_t csr_itrigger_get_vs(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_itrigger_get_vu(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_itrigger_get_vu(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "vu", .lsb = 0xb, @@ -1599,9 +1649,9 @@ static riscv_debug_reg_field_list_t csr_itrigger_get_vu(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_itrigger_get_nmi(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_itrigger_get_nmi(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "nmi", .lsb = 0xa, @@ -1613,9 +1663,9 @@ static riscv_debug_reg_field_list_t csr_itrigger_get_nmi(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_itrigger_get_action(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_itrigger_get_action(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "action", .lsb = 0, @@ -1636,10 +1686,10 @@ static const char *csr_etrigger_action_values[64] = { [8] = "external0", [9] = "external1" }; -static riscv_debug_reg_field_list_t csr_etrigger_get_hit(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_etrigger_get_hit(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hit", .lsb = (context.XLEN.value + -6), @@ -1651,10 +1701,10 @@ static riscv_debug_reg_field_list_t csr_etrigger_get_hit(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t csr_etrigger_get_dmode(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_etrigger_get_dmode(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dmode", .lsb = (context.XLEN.value + -5), @@ -1666,10 +1716,10 @@ static riscv_debug_reg_field_list_t csr_etrigger_get_dmode(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_etrigger_get_type(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_etrigger_get_type(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "type", .lsb = (context.XLEN.value + -4), @@ -1681,9 +1731,9 @@ static riscv_debug_reg_field_list_t csr_etrigger_get_type(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t csr_etrigger_get_m(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_etrigger_get_m(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "m", .lsb = 9, @@ -1695,9 +1745,9 @@ static riscv_debug_reg_field_list_t csr_etrigger_get_m(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t csr_etrigger_get_s(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_etrigger_get_s(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "s", .lsb = 7, @@ -1709,9 +1759,9 @@ static riscv_debug_reg_field_list_t csr_etrigger_get_s(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t csr_etrigger_get_u(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_etrigger_get_u(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "u", .lsb = 6, @@ -1723,9 +1773,9 @@ static riscv_debug_reg_field_list_t csr_etrigger_get_u(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t csr_etrigger_get_vs(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_etrigger_get_vs(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "vs", .lsb = 0xc, @@ -1737,9 +1787,9 @@ static riscv_debug_reg_field_list_t csr_etrigger_get_vs(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_etrigger_get_vu(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_etrigger_get_vu(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "vu", .lsb = 0xb, @@ -1751,9 +1801,9 @@ static riscv_debug_reg_field_list_t csr_etrigger_get_vu(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t csr_etrigger_get_action(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_etrigger_get_action(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "action", .lsb = 0, @@ -1774,10 +1824,10 @@ static const char *csr_tmexttrigger_action_values[64] = { [8] = "external0", [9] = "external1" }; -static riscv_debug_reg_field_list_t csr_tmexttrigger_get_hit(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tmexttrigger_get_hit(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hit", .lsb = (context.XLEN.value + -6), @@ -1789,10 +1839,10 @@ static riscv_debug_reg_field_list_t csr_tmexttrigger_get_hit(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t csr_tmexttrigger_get_dmode(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tmexttrigger_get_dmode(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dmode", .lsb = (context.XLEN.value + -5), @@ -1804,10 +1854,10 @@ static riscv_debug_reg_field_list_t csr_tmexttrigger_get_dmode(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t csr_tmexttrigger_get_type(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tmexttrigger_get_type(struct riscv_debug_reg_ctx context) { assert(context.XLEN.is_set); - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "type", .lsb = (context.XLEN.value + -4), @@ -1819,9 +1869,9 @@ static riscv_debug_reg_field_list_t csr_tmexttrigger_get_type(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t csr_tmexttrigger_get_select(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tmexttrigger_get_select(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "select", .lsb = 6, @@ -1833,9 +1883,9 @@ static riscv_debug_reg_field_list_t csr_tmexttrigger_get_select(riscv_debug_reg_ return result; } -static riscv_debug_reg_field_list_t csr_tmexttrigger_get_intctl(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tmexttrigger_get_intctl(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "intctl", .lsb = 0x16, @@ -1847,9 +1897,9 @@ static riscv_debug_reg_field_list_t csr_tmexttrigger_get_intctl(riscv_debug_reg_ return result; } -static riscv_debug_reg_field_list_t csr_tmexttrigger_get_action(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_tmexttrigger_get_action(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "action", .lsb = 0, @@ -1870,9 +1920,9 @@ static const char *csr_textra32_sselect_values[4] = { [1] = "scontext", [2] = "asid" }; -static riscv_debug_reg_field_list_t csr_textra32_get_mhvalue(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_textra32_get_mhvalue(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "mhvalue", .lsb = 0x1a, @@ -1884,9 +1934,9 @@ static riscv_debug_reg_field_list_t csr_textra32_get_mhvalue(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t csr_textra32_get_mhselect(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_textra32_get_mhselect(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "mhselect", .lsb = 0x17, @@ -1898,9 +1948,9 @@ static riscv_debug_reg_field_list_t csr_textra32_get_mhselect(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t csr_textra32_get_svalue(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_textra32_get_svalue(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "svalue", .lsb = 2, @@ -1912,9 +1962,9 @@ static riscv_debug_reg_field_list_t csr_textra32_get_svalue(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t csr_textra32_get_sbytemask(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_textra32_get_sbytemask(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbytemask", .lsb = 0x12, @@ -1926,9 +1976,9 @@ static riscv_debug_reg_field_list_t csr_textra32_get_sbytemask(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t csr_textra32_get_sselect(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_textra32_get_sselect(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sselect", .lsb = 0, @@ -1940,9 +1990,9 @@ static riscv_debug_reg_field_list_t csr_textra32_get_sselect(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t csr_textra64_get_mhvalue(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_textra64_get_mhvalue(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "mhvalue", .lsb = 0x33, @@ -1954,9 +2004,9 @@ static riscv_debug_reg_field_list_t csr_textra64_get_mhvalue(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t csr_textra64_get_mhselect(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_textra64_get_mhselect(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "mhselect", .lsb = 0x30, @@ -1968,13 +2018,13 @@ static riscv_debug_reg_field_list_t csr_textra64_get_mhselect(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t csr_textra64_get_sbytemask(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_textra64_get_sbytemask(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbytemask", .lsb = 0x24, - .msb = 0x28, + .msb = 0x27, .values = NULL }, .get_next = csr_textra64_get_mhselect @@ -1982,13 +2032,13 @@ static riscv_debug_reg_field_list_t csr_textra64_get_sbytemask(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t csr_textra64_get_svalue(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_textra64_get_svalue(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "svalue", .lsb = 2, - .msb = 0x23, + .msb = 0x21, .values = NULL }, .get_next = csr_textra64_get_sbytemask @@ -1996,9 +2046,9 @@ static riscv_debug_reg_field_list_t csr_textra64_get_svalue(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t csr_textra64_get_sselect(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list csr_textra64_get_sselect(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sselect", .lsb = 0, @@ -2037,9 +2087,9 @@ static const char *dm_dmstatus_version_values[16] = { [3] = "1_0", [15] = "custom" }; -static riscv_debug_reg_field_list_t dm_dmstatus_get_allhalted(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_allhalted(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "allhalted", .lsb = 9, @@ -2051,9 +2101,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_allhalted(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_anyhalted(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_anyhalted(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "anyhalted", .lsb = 8, @@ -2065,9 +2115,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_anyhalted(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_authenticated(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_authenticated(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "authenticated", .lsb = 7, @@ -2079,9 +2129,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_authenticated(riscv_debug_re return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_authbusy(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_authbusy(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "authbusy", .lsb = 6, @@ -2093,9 +2143,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_authbusy(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_hasresethaltreq(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_hasresethaltreq(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hasresethaltreq", .lsb = 5, @@ -2107,9 +2157,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_hasresethaltreq(riscv_debug_ return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_confstrptrvalid(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_confstrptrvalid(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "confstrptrvalid", .lsb = 4, @@ -2121,9 +2171,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_confstrptrvalid(riscv_debug_ return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_ndmresetpending(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_ndmresetpending(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "ndmresetpending", .lsb = 0x18, @@ -2135,9 +2185,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_ndmresetpending(riscv_debug_ return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_stickyunavail(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_stickyunavail(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "stickyunavail", .lsb = 0x17, @@ -2149,9 +2199,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_stickyunavail(riscv_debug_re return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_impebreak(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_impebreak(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "impebreak", .lsb = 0x16, @@ -2163,9 +2213,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_impebreak(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_allhavereset(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_allhavereset(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "allhavereset", .lsb = 0x13, @@ -2177,9 +2227,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_allhavereset(riscv_debug_reg return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_anyhavereset(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_anyhavereset(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "anyhavereset", .lsb = 0x12, @@ -2191,9 +2241,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_anyhavereset(riscv_debug_reg return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_allresumeack(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_allresumeack(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "allresumeack", .lsb = 0x11, @@ -2205,9 +2255,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_allresumeack(riscv_debug_reg return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_anyresumeack(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_anyresumeack(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "anyresumeack", .lsb = 0x10, @@ -2219,9 +2269,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_anyresumeack(riscv_debug_reg return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_allnonexistent(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_allnonexistent(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "allnonexistent", .lsb = 0xf, @@ -2233,9 +2283,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_allnonexistent(riscv_debug_r return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_anynonexistent(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_anynonexistent(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "anynonexistent", .lsb = 0xe, @@ -2247,9 +2297,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_anynonexistent(riscv_debug_r return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_allunavail(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_allunavail(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "allunavail", .lsb = 0xd, @@ -2261,9 +2311,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_allunavail(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_anyunavail(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_anyunavail(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "anyunavail", .lsb = 0xc, @@ -2275,9 +2325,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_anyunavail(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_allrunning(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_allrunning(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "allrunning", .lsb = 0xb, @@ -2289,9 +2339,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_allrunning(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_anyrunning(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_anyrunning(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "anyrunning", .lsb = 0xa, @@ -2303,9 +2353,9 @@ static riscv_debug_reg_field_list_t dm_dmstatus_get_anyrunning(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t dm_dmstatus_get_version(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmstatus_get_version(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "version", .lsb = 0, @@ -2333,9 +2383,9 @@ static const char *dm_dmcontrol_dmactive_values[2] = { [0] = "inactive", [1] = "active" }; -static riscv_debug_reg_field_list_t dm_dmcontrol_get_hartselhi(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_hartselhi(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hartselhi", .lsb = 6, @@ -2347,9 +2397,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_hartselhi(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_setkeepalive(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_setkeepalive(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "setkeepalive", .lsb = 5, @@ -2361,9 +2411,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_setkeepalive(riscv_debug_re return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_clrkeepalive(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_clrkeepalive(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "clrkeepalive", .lsb = 4, @@ -2375,9 +2425,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_clrkeepalive(riscv_debug_re return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_haltreq(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_haltreq(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "haltreq", .lsb = 0x1f, @@ -2389,9 +2439,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_haltreq(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_resumereq(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_resumereq(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "resumereq", .lsb = 0x1e, @@ -2403,9 +2453,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_resumereq(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_setresethaltreq(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_setresethaltreq(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "setresethaltreq", .lsb = 3, @@ -2417,9 +2467,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_setresethaltreq(riscv_debug return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_hartreset(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_hartreset(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hartreset", .lsb = 0x1d, @@ -2431,9 +2481,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_hartreset(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_ackhavereset(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_ackhavereset(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "ackhavereset", .lsb = 0x1c, @@ -2445,9 +2495,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_ackhavereset(riscv_debug_re return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_ackunavail(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_ackunavail(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "ackunavail", .lsb = 0x1b, @@ -2459,9 +2509,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_ackunavail(riscv_debug_reg_ return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_hasel(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_hasel(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hasel", .lsb = 0x1a, @@ -2473,9 +2523,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_hasel(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_clrresethaltreq(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_clrresethaltreq(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "clrresethaltreq", .lsb = 2, @@ -2487,9 +2537,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_clrresethaltreq(riscv_debug return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_hartsello(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_hartsello(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hartsello", .lsb = 0x10, @@ -2501,9 +2551,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_hartsello(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_ndmreset(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_ndmreset(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "ndmreset", .lsb = 1, @@ -2515,9 +2565,9 @@ static riscv_debug_reg_field_list_t dm_dmcontrol_get_ndmreset(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t dm_dmcontrol_get_dmactive(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcontrol_get_dmactive(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dmactive", .lsb = 0, @@ -2533,9 +2583,9 @@ static const char *dm_hartinfo_dataaccess_values[2] = { [0] = "csr", [1] = "memory" }; -static riscv_debug_reg_field_list_t dm_hartinfo_get_nscratch(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_hartinfo_get_nscratch(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "nscratch", .lsb = 0x14, @@ -2547,9 +2597,9 @@ static riscv_debug_reg_field_list_t dm_hartinfo_get_nscratch(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t dm_hartinfo_get_dataaccess(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_hartinfo_get_dataaccess(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dataaccess", .lsb = 0x10, @@ -2561,9 +2611,9 @@ static riscv_debug_reg_field_list_t dm_hartinfo_get_dataaccess(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t dm_hartinfo_get_datasize(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_hartinfo_get_datasize(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "datasize", .lsb = 0xc, @@ -2575,9 +2625,9 @@ static riscv_debug_reg_field_list_t dm_hartinfo_get_datasize(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t dm_hartinfo_get_dataaddr(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_hartinfo_get_dataaddr(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dataaddr", .lsb = 0, @@ -2589,9 +2639,9 @@ static riscv_debug_reg_field_list_t dm_hartinfo_get_dataaddr(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t dm_hawindowsel_get_hawindowsel(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_hawindowsel_get_hawindowsel(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hawindowsel", .lsb = 0, @@ -2603,9 +2653,9 @@ static riscv_debug_reg_field_list_t dm_hawindowsel_get_hawindowsel(riscv_debug_r return result; } -static riscv_debug_reg_field_list_t dm_hawindow_get_maskdata(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_hawindow_get_maskdata(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "maskdata", .lsb = 0, @@ -2635,9 +2685,9 @@ static const char *dm_abstractcs_cmderr_values[8] = { [6] = "reserved", [7] = "other" }; -static riscv_debug_reg_field_list_t dm_abstractcs_get_cmderr(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_abstractcs_get_cmderr(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "cmderr", .lsb = 8, @@ -2649,9 +2699,9 @@ static riscv_debug_reg_field_list_t dm_abstractcs_get_cmderr(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t dm_abstractcs_get_progbufsize(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_abstractcs_get_progbufsize(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "progbufsize", .lsb = 0x18, @@ -2663,9 +2713,9 @@ static riscv_debug_reg_field_list_t dm_abstractcs_get_progbufsize(riscv_debug_re return result; } -static riscv_debug_reg_field_list_t dm_abstractcs_get_busy(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_abstractcs_get_busy(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "busy", .lsb = 0xc, @@ -2677,9 +2727,9 @@ static riscv_debug_reg_field_list_t dm_abstractcs_get_busy(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dm_abstractcs_get_relaxedpriv(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_abstractcs_get_relaxedpriv(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "relaxedpriv", .lsb = 0xb, @@ -2691,9 +2741,9 @@ static riscv_debug_reg_field_list_t dm_abstractcs_get_relaxedpriv(riscv_debug_re return result; } -static riscv_debug_reg_field_list_t dm_abstractcs_get_datacount(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_abstractcs_get_datacount(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "datacount", .lsb = 0, @@ -2705,9 +2755,9 @@ static riscv_debug_reg_field_list_t dm_abstractcs_get_datacount(riscv_debug_reg_ return result; } -static riscv_debug_reg_field_list_t dm_command_get_cmdtype(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_command_get_cmdtype(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "cmdtype", .lsb = 0x18, @@ -2719,9 +2769,9 @@ static riscv_debug_reg_field_list_t dm_command_get_cmdtype(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dm_command_get_control(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_command_get_control(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "control", .lsb = 0, @@ -2733,9 +2783,9 @@ static riscv_debug_reg_field_list_t dm_command_get_control(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dm_abstractauto_get_autoexecprogbuf(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_abstractauto_get_autoexecprogbuf(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "autoexecprogbuf", .lsb = 0x10, @@ -2747,9 +2797,9 @@ static riscv_debug_reg_field_list_t dm_abstractauto_get_autoexecprogbuf(riscv_de return result; } -static riscv_debug_reg_field_list_t dm_abstractauto_get_autoexecdata(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_abstractauto_get_autoexecdata(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "autoexecdata", .lsb = 0, @@ -2761,9 +2811,9 @@ static riscv_debug_reg_field_list_t dm_abstractauto_get_autoexecdata(riscv_debug return result; } -static riscv_debug_reg_field_list_t dm_confstrptr0_get_addr(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_confstrptr0_get_addr(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "addr", .lsb = 0, @@ -2775,9 +2825,9 @@ static riscv_debug_reg_field_list_t dm_confstrptr0_get_addr(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t dm_confstrptr1_get_addr(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_confstrptr1_get_addr(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "addr", .lsb = 0, @@ -2789,9 +2839,9 @@ static riscv_debug_reg_field_list_t dm_confstrptr1_get_addr(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t dm_confstrptr2_get_addr(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_confstrptr2_get_addr(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "addr", .lsb = 0, @@ -2803,9 +2853,9 @@ static riscv_debug_reg_field_list_t dm_confstrptr2_get_addr(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t dm_confstrptr3_get_addr(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_confstrptr3_get_addr(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "addr", .lsb = 0, @@ -2817,9 +2867,9 @@ static riscv_debug_reg_field_list_t dm_confstrptr3_get_addr(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t dm_nextdm_get_addr(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_nextdm_get_addr(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "addr", .lsb = 0, @@ -2831,9 +2881,9 @@ static riscv_debug_reg_field_list_t dm_nextdm_get_addr(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t dm_data0_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_data0_get_data(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 0, @@ -2845,9 +2895,9 @@ static riscv_debug_reg_field_list_t dm_data0_get_data(riscv_debug_reg_ctx_t cont return result; } -static riscv_debug_reg_field_list_t dm_progbuf0_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_progbuf0_get_data(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 0, @@ -2859,9 +2909,9 @@ static riscv_debug_reg_field_list_t dm_progbuf0_get_data(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t dm_authdata_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_authdata_get_data(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 0, @@ -2881,9 +2931,9 @@ static const char *dm_dmcs2_hgselect_values[2] = { [0] = "harts", [1] = "triggers" }; -static riscv_debug_reg_field_list_t dm_dmcs2_get_dmexttrigger(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcs2_get_dmexttrigger(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "dmexttrigger", .lsb = 7, @@ -2895,9 +2945,9 @@ static riscv_debug_reg_field_list_t dm_dmcs2_get_dmexttrigger(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t dm_dmcs2_get_group(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcs2_get_group(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "group", .lsb = 2, @@ -2909,9 +2959,9 @@ static riscv_debug_reg_field_list_t dm_dmcs2_get_group(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t dm_dmcs2_get_grouptype(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcs2_get_grouptype(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "grouptype", .lsb = 0xb, @@ -2923,9 +2973,9 @@ static riscv_debug_reg_field_list_t dm_dmcs2_get_grouptype(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dm_dmcs2_get_hgwrite(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcs2_get_hgwrite(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hgwrite", .lsb = 1, @@ -2937,9 +2987,9 @@ static riscv_debug_reg_field_list_t dm_dmcs2_get_hgwrite(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t dm_dmcs2_get_hgselect(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_dmcs2_get_hgselect(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "hgselect", .lsb = 0, @@ -2951,9 +3001,9 @@ static riscv_debug_reg_field_list_t dm_dmcs2_get_hgselect(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dm_haltsum0_get_haltsum0(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_haltsum0_get_haltsum0(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "haltsum0", .lsb = 0, @@ -2965,9 +3015,9 @@ static riscv_debug_reg_field_list_t dm_haltsum0_get_haltsum0(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t dm_haltsum1_get_haltsum1(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_haltsum1_get_haltsum1(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "haltsum1", .lsb = 0, @@ -2979,9 +3029,9 @@ static riscv_debug_reg_field_list_t dm_haltsum1_get_haltsum1(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t dm_haltsum2_get_haltsum2(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_haltsum2_get_haltsum2(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "haltsum2", .lsb = 0, @@ -2993,9 +3043,9 @@ static riscv_debug_reg_field_list_t dm_haltsum2_get_haltsum2(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t dm_haltsum3_get_haltsum3(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_haltsum3_get_haltsum3(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "haltsum3", .lsb = 0, @@ -3026,9 +3076,9 @@ static const char *dm_sbcs_sberror_values[8] = { [4] = "size", [7] = "other" }; -static riscv_debug_reg_field_list_t dm_sbcs_get_sbasize(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbasize(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbasize", .lsb = 5, @@ -3040,9 +3090,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbasize(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess128(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbaccess128(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbaccess128", .lsb = 4, @@ -3054,9 +3104,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess128(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess64(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbaccess64(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbaccess64", .lsb = 3, @@ -3068,9 +3118,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess64(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbversion(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbversion(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbversion", .lsb = 0x1d, @@ -3082,9 +3132,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbversion(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbbusyerror(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbbusyerror(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbbusyerror", .lsb = 0x16, @@ -3096,9 +3146,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbbusyerror(riscv_debug_reg_ctx_ return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbbusy(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbbusy(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbbusy", .lsb = 0x15, @@ -3110,9 +3160,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbbusy(riscv_debug_reg_ctx_t con return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbreadonaddr(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbreadonaddr(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbreadonaddr", .lsb = 0x14, @@ -3124,9 +3174,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbreadonaddr(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess32(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbaccess32(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbaccess32", .lsb = 2, @@ -3138,9 +3188,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess32(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbaccess(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbaccess", .lsb = 0x11, @@ -3152,9 +3202,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess(riscv_debug_reg_ctx_t c return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbautoincrement(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbautoincrement(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbautoincrement", .lsb = 0x10, @@ -3166,9 +3216,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbautoincrement(riscv_debug_reg_ return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbreadondata(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbreadondata(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbreadondata", .lsb = 0xf, @@ -3180,9 +3230,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbreadondata(riscv_debug_reg_ctx return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sberror(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sberror(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sberror", .lsb = 0xc, @@ -3194,9 +3244,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sberror(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess16(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbaccess16(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbaccess16", .lsb = 1, @@ -3208,9 +3258,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess16(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess8(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbcs_get_sbaccess8(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "sbaccess8", .lsb = 0, @@ -3222,9 +3272,9 @@ static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess8(riscv_debug_reg_ctx_t return result; } -static riscv_debug_reg_field_list_t dm_sbaddress0_get_address(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbaddress0_get_address(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "address", .lsb = 0, @@ -3236,9 +3286,9 @@ static riscv_debug_reg_field_list_t dm_sbaddress0_get_address(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t dm_sbaddress1_get_address(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbaddress1_get_address(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "address", .lsb = 0, @@ -3250,9 +3300,9 @@ static riscv_debug_reg_field_list_t dm_sbaddress1_get_address(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t dm_sbaddress2_get_address(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbaddress2_get_address(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "address", .lsb = 0, @@ -3264,9 +3314,9 @@ static riscv_debug_reg_field_list_t dm_sbaddress2_get_address(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t dm_sbaddress3_get_address(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbaddress3_get_address(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "address", .lsb = 0, @@ -3278,9 +3328,9 @@ static riscv_debug_reg_field_list_t dm_sbaddress3_get_address(riscv_debug_reg_ct return result; } -static riscv_debug_reg_field_list_t dm_sbdata0_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbdata0_get_data(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 0, @@ -3292,9 +3342,9 @@ static riscv_debug_reg_field_list_t dm_sbdata0_get_data(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t dm_sbdata1_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbdata1_get_data(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 0, @@ -3306,9 +3356,9 @@ static riscv_debug_reg_field_list_t dm_sbdata1_get_data(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t dm_sbdata2_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbdata2_get_data(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 0, @@ -3320,9 +3370,9 @@ static riscv_debug_reg_field_list_t dm_sbdata2_get_data(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t dm_sbdata3_get_data(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list dm_sbdata3_get_data(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "data", .lsb = 0, @@ -3334,9 +3384,9 @@ static riscv_debug_reg_field_list_t dm_sbdata3_get_data(riscv_debug_reg_ctx_t co return result; } -static riscv_debug_reg_field_list_t shortname_get_field(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list shortname_get_field(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "field", .lsb = 0, @@ -3369,9 +3419,9 @@ static const char *ac_access_register_write_values[2] = { [0] = "arg0", [1] = "register" }; -static riscv_debug_reg_field_list_t ac_access_register_get_cmdtype(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_register_get_cmdtype(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "cmdtype", .lsb = 0x18, @@ -3383,9 +3433,9 @@ static riscv_debug_reg_field_list_t ac_access_register_get_cmdtype(riscv_debug_r return result; } -static riscv_debug_reg_field_list_t ac_access_register_get_aarsize(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_register_get_aarsize(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "aarsize", .lsb = 0x14, @@ -3397,9 +3447,9 @@ static riscv_debug_reg_field_list_t ac_access_register_get_aarsize(riscv_debug_r return result; } -static riscv_debug_reg_field_list_t ac_access_register_get_aarpostincrement(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_register_get_aarpostincrement(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "aarpostincrement", .lsb = 0x13, @@ -3411,9 +3461,9 @@ static riscv_debug_reg_field_list_t ac_access_register_get_aarpostincrement(risc return result; } -static riscv_debug_reg_field_list_t ac_access_register_get_postexec(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_register_get_postexec(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "postexec", .lsb = 0x12, @@ -3425,9 +3475,9 @@ static riscv_debug_reg_field_list_t ac_access_register_get_postexec(riscv_debug_ return result; } -static riscv_debug_reg_field_list_t ac_access_register_get_transfer(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_register_get_transfer(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "transfer", .lsb = 0x11, @@ -3439,9 +3489,9 @@ static riscv_debug_reg_field_list_t ac_access_register_get_transfer(riscv_debug_ return result; } -static riscv_debug_reg_field_list_t ac_access_register_get_write(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_register_get_write(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "write", .lsb = 0x10, @@ -3453,9 +3503,9 @@ static riscv_debug_reg_field_list_t ac_access_register_get_write(riscv_debug_reg return result; } -static riscv_debug_reg_field_list_t ac_access_register_get_regno(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_register_get_regno(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "regno", .lsb = 0, @@ -3467,9 +3517,9 @@ static riscv_debug_reg_field_list_t ac_access_register_get_regno(riscv_debug_reg return result; } -static riscv_debug_reg_field_list_t ac_quick_access_get_cmdtype(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_quick_access_get_cmdtype(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "cmdtype", .lsb = 0x18, @@ -3496,9 +3546,9 @@ static const char *ac_access_memory_write_values[2] = { [0] = "arg0", [1] = "memory" }; -static riscv_debug_reg_field_list_t ac_access_memory_get_cmdtype(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_memory_get_cmdtype(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "cmdtype", .lsb = 0x18, @@ -3510,9 +3560,9 @@ static riscv_debug_reg_field_list_t ac_access_memory_get_cmdtype(riscv_debug_reg return result; } -static riscv_debug_reg_field_list_t ac_access_memory_get_aamvirtual(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_memory_get_aamvirtual(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "aamvirtual", .lsb = 0x17, @@ -3524,9 +3574,9 @@ static riscv_debug_reg_field_list_t ac_access_memory_get_aamvirtual(riscv_debug_ return result; } -static riscv_debug_reg_field_list_t ac_access_memory_get_aamsize(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_memory_get_aamsize(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "aamsize", .lsb = 0x14, @@ -3538,9 +3588,9 @@ static riscv_debug_reg_field_list_t ac_access_memory_get_aamsize(riscv_debug_reg return result; } -static riscv_debug_reg_field_list_t ac_access_memory_get_aampostincrement(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_memory_get_aampostincrement(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "aampostincrement", .lsb = 0x13, @@ -3552,9 +3602,9 @@ static riscv_debug_reg_field_list_t ac_access_memory_get_aampostincrement(riscv_ return result; } -static riscv_debug_reg_field_list_t ac_access_memory_get_write(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_memory_get_write(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "write", .lsb = 0x10, @@ -3566,9 +3616,9 @@ static riscv_debug_reg_field_list_t ac_access_memory_get_write(riscv_debug_reg_c return result; } -static riscv_debug_reg_field_list_t ac_access_memory_get_target_specific(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list ac_access_memory_get_target_specific(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "target-specific", .lsb = 0xe, @@ -3580,9 +3630,9 @@ static riscv_debug_reg_field_list_t ac_access_memory_get_target_specific(riscv_d return result; } -static riscv_debug_reg_field_list_t virt_priv_get_v(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list virt_priv_get_v(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "v", .lsb = 2, @@ -3594,9 +3644,9 @@ static riscv_debug_reg_field_list_t virt_priv_get_v(riscv_debug_reg_ctx_t contex return result; } -static riscv_debug_reg_field_list_t virt_priv_get_prv(riscv_debug_reg_ctx_t context) +static struct riscv_debug_reg_field_list virt_priv_get_prv(struct riscv_debug_reg_ctx context) { - riscv_debug_reg_field_list_t result = { + struct riscv_debug_reg_field_list result = { .field = { .name = "prv", .lsb = 0, @@ -3608,9 +3658,9 @@ static riscv_debug_reg_field_list_t virt_priv_get_prv(riscv_debug_reg_ctx_t cont return result; } -riscv_debug_reg_info_t get_riscv_debug_reg_info(enum riscv_debug_reg_ordinal reg_ordinal) +struct riscv_debug_reg_info get_riscv_debug_reg_info(enum riscv_debug_reg_ordinal reg_ordinal) { - static const riscv_debug_reg_info_t debug_reg_info[] = { + static const struct riscv_debug_reg_info debug_reg_info[] = { [DTM_IDCODE_ORDINAL] = { .name = "idcode", .get_fields_head = dtm_idcode_get_1 diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h index dbe5142a8e..451c2c1fbb 100644 --- a/src/target/riscv/debug_defines.h +++ b/src/target/riscv/debug_defines.h @@ -1,7 +1,5 @@ -/* - * This file is auto-generated by running 'make debug_defines' in - * https://github.com/riscv/riscv-debug-spec/ (40b9a05) - */ +/* SPDX-License-Identifier: BSD-2-Clause OR CC-BY-4.0 */ +/* This file was auto-generated by running 'make debug_defines' in https://github.com/riscv/riscv-debug-spec/ (22a7576) */ #ifndef DEBUG_DEFINES_H #define DEBUG_DEFINES_H @@ -35,8 +33,8 @@ /* * This optional field may provide additional detail about an error * that occurred when communicating with a DM. It is updated whenever - * \FdtmDmiOp is updated by the hardware or when 1 is written to - * \FdtmDtmcsDmireset. + * {dmi-op} is updated by the hardware or when 1 is written to + * {dtmcs-dmireset}. */ #define DTM_DTMCS_ERRINFO_OFFSET 0x12ULL #define DTM_DTMCS_ERRINFO_LENGTH 3ULL @@ -79,7 +77,7 @@ #define DTM_DTMCS_DTMHARDRESET 0x20000ULL /* * Writing 1 to this bit clears the sticky error state and resets - * \FdtmDtmcsErrinfo, but does not affect outstanding DMI transactions. + * {dtmcs-errinfo}, but does not affect outstanding DMI transactions. */ #define DTM_DTMCS_DMIRESET_OFFSET 0x10ULL #define DTM_DTMCS_DMIRESET_LENGTH 1ULL @@ -88,8 +86,8 @@ * 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. + * return code ({dtmcs-dmistat} of 3). A debugger must still + * check {dtmcs-dmistat} when necessary. * * 0: It is not necessary to enter Run-Test/Idle at all. * @@ -103,13 +101,13 @@ #define DTM_DTMCS_IDLE_LENGTH 3ULL #define DTM_DTMCS_IDLE 0x7000ULL /* - * Read-only alias of \FdtmDmiOp. + * Read-only alias of {dmi-op}. */ #define DTM_DTMCS_DMISTAT_OFFSET 0xaULL #define DTM_DTMCS_DMISTAT_LENGTH 2ULL #define DTM_DTMCS_DMISTAT 0xc00ULL /* - * The size of \FdmSbaddressZeroAddress in \RdtmDmi. + * The size of {dmi-address} in {dtm-dmi}. */ #define DTM_DTMCS_ABITS_OFFSET 4ULL #define DTM_DTMCS_ABITS_LENGTH 6ULL @@ -133,7 +131,7 @@ /* * Address used for DMI access. In Update-DR this value is used * to access the DM over the DMI. - * \FdtmDmiOp defines what this register contains after every possible + * {dmi-op} defines what this register contains after every possible * operation. */ #define DTM_DMI_ADDRESS_OFFSET 0x22ULL @@ -153,30 +151,30 @@ #define DTM_DMI_OP_LENGTH 2ULL #define DTM_DMI_OP 3ULL /* - * nop: Ignore \FdmSbdataZeroData and \FdmSbaddressZeroAddress. + * nop: Ignore {sbdata0-data} and {sbaddress0-address}. * * Don't send anything over the DMI during Update-DR. - * This operation should never result in a busy or error response. + * This operation should never affect DMI busy or error status. * The address and data reported in the following Capture-DR * are undefined. * - * This operation leaves the values in \FdtmDmiAddress and \FdtmDmiData - * \unspecified. + * This operation leaves the values in {dmi-address} and {dmi-data} + * UNSPECIFIED. */ #define DTM_DMI_OP_NOP 0 /* - * read: Read from \FdtmDmiAddress. + * read: Read from {dmi-address}. * - * When this operation succeeds, \FdtmDmiAddress contains the address - * that was read from, and \FdtmDmiData contains the value that was + * When this operation succeeds, {dmi-address} contains the address + * that was read from, and {dmi-data} contains the value that was * read. */ #define DTM_DMI_OP_READ 1 /* - * write: Write \FdtmDmiData to \FdtmDmiAddress. + * write: Write {dmi-data} to {dmi-address}. * - * This operation leaves the values in \FdtmDmiAddress and \FdtmDmiData - * \unspecified. + * This operation leaves the values in {dmi-address} and {dmi-data} + * UNSPECIFIED. */ #define DTM_DMI_OP_WRITE 2 /* @@ -193,9 +191,9 @@ * reserved: Reserved. */ /* - * failed: A previous operation failed. The data scanned into \RdtmDmi in + * failed: A previous operation failed. The data scanned into {dtm-dmi} in * this access will be ignored. This status is sticky and can be - * cleared by writing \FdtmDtmcsDmireset in \RdtmDtmcs. + * cleared by writing {dtmcs-dmireset} in {dtm-dtmcs}. * * This indicates that the DM itself or the DMI responded with an error. * There are no specified cases in which the DM would @@ -203,14 +201,14 @@ * returning errors. * * If a debugger sees this status, there might be additional - * information in \FdtmDtmcsErrinfo. + * information in {dtmcs-errinfo}. */ #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 + * busy: A DMI operation was attempted while a prior DMI operation was still in + * progress. The data scanned into {dtm-dmi} 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 + * {dtmcs-dmireset} in {dtm-dtmcs}. 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. @@ -233,16 +231,82 @@ * available version of this spec. */ #define CSR_DCSR_DEBUGVER_CUSTOM 15 +/* + * When {dcsr-cause} is 7, this optional field contains the value of a + * more specific halt reason than "other." Otherwise it contains 0. + */ +#define CSR_DCSR_EXTCAUSE_OFFSET 0x18ULL +#define CSR_DCSR_EXTCAUSE_LENGTH 3ULL +#define CSR_DCSR_EXTCAUSE 0x7000000ULL +/* + * critical error: The hart entered a critical error state, as defined in the + * ((Smdbltrp)) extension. + */ +#define CSR_DCSR_EXTCAUSE_CRITICAL_ERROR 0 +/* + * All other values are reserved for future versions of this spec, or + * for use by other RISC-V extensions. + */ +/* + * This bit is part of ((Smdbltrp)) and only exists when that extension + * is implemented. + */ +#define CSR_DCSR_CETRIG_OFFSET 0x13ULL +#define CSR_DCSR_CETRIG_LENGTH 1ULL +#define CSR_DCSR_CETRIG 0x80000ULL +/* + * disabled: A hart in a critical error state does not enter Debug Mode but + * instead asserts the critical-error signal to the platform. + */ +#define CSR_DCSR_CETRIG_DISABLED 0 +/* + * enabled: A hart in a critical error state enters Debug Mode instead of + * asserting the critical-error signal to the platform. Upon such + * entry into Debug Mode, the cause field is set to 7, and the + * extcause field is set to 0, indicating a critical error + * triggered the Debug Mode entry. This cause has the highest + * priority among all reasons for entering Debug Mode. Resuming + * from Debug Mode following an entry from the critical error state + * returns the hart to the critical error state. + */ +#define CSR_DCSR_CETRIG_ENABLED 1 +/* + * [NOTE] + * ==== + * When {dcsr-cetrig} is 1, resuming from Debug Mode + * following an entry due to a critical error will result in an + * immediate re-entry into Debug Mode due to the critical error. + * The debugger may resume with {dcsr-cetrig} set to 0 to allow the + * platform defined actions on critical-error signal to occur. + * Other possible actions include initiating a hart or platform + * reset using the Debug Module reset control. + * ==== + */ +/* + * This bit is part of ((Zicfilp)) and only exists when that extension + * is implemented. + */ +#define CSR_DCSR_PELP_OFFSET 0x12ULL +#define CSR_DCSR_PELP_LENGTH 1ULL +#define CSR_DCSR_PELP 0x40000ULL +/* + * NO_LP_EXPECTED: No landing pad instruction expected. + */ +#define CSR_DCSR_PELP_NO_LP_EXPECTED 0 +/* + * LP_EXPECTED: A landing pad instruction is expected. + */ +#define CSR_DCSR_PELP_LP_EXPECTED 1 #define CSR_DCSR_EBREAKVS_OFFSET 0x11ULL #define CSR_DCSR_EBREAKVS_LENGTH 1ULL #define CSR_DCSR_EBREAKVS 0x20000ULL /* - * exception: {\tt ebreak} instructions in VS-mode behave as described in the + * exception: `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. + * debug mode: `ebreak` instructions in VS-mode enter Debug Mode. */ #define CSR_DCSR_EBREAKVS_DEBUG_MODE 1 /* @@ -252,12 +316,12 @@ #define CSR_DCSR_EBREAKVU_LENGTH 1ULL #define CSR_DCSR_EBREAKVU 0x10000ULL /* - * exception: {\tt ebreak} instructions in VU-mode behave as described in the + * exception: `ebreak` instructions in VU-mode behave as described in the * Privileged Spec. */ #define CSR_DCSR_EBREAKVU_EXCEPTION 0 /* - * debug mode: {\tt ebreak} instructions in VU-mode enter Debug Mode. + * debug mode: `ebreak` instructions in VU-mode enter Debug Mode. */ #define CSR_DCSR_EBREAKVU_DEBUG_MODE 1 /* @@ -267,24 +331,24 @@ #define CSR_DCSR_EBREAKM_LENGTH 1ULL #define CSR_DCSR_EBREAKM 0x8000ULL /* - * exception: {\tt ebreak} instructions in M-mode behave as described in the + * exception: `ebreak` instructions in M-mode behave as described in the * Privileged Spec. */ #define CSR_DCSR_EBREAKM_EXCEPTION 0 /* - * debug mode: {\tt ebreak} instructions in M-mode enter Debug Mode. + * debug mode: `ebreak` instructions in M-mode enter Debug Mode. */ #define CSR_DCSR_EBREAKM_DEBUG_MODE 1 #define CSR_DCSR_EBREAKS_OFFSET 0xdULL #define CSR_DCSR_EBREAKS_LENGTH 1ULL #define CSR_DCSR_EBREAKS 0x2000ULL /* - * exception: {\tt ebreak} instructions in S-mode behave as described in the + * exception: `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. + * debug mode: `ebreak` instructions in S-mode enter Debug Mode. */ #define CSR_DCSR_EBREAKS_DEBUG_MODE 1 /* @@ -294,12 +358,12 @@ #define CSR_DCSR_EBREAKU_LENGTH 1ULL #define CSR_DCSR_EBREAKU 0x1000ULL /* - * exception: {\tt ebreak} instructions in U-mode behave as described in the + * exception: `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. + * debug mode: `ebreak` instructions in U-mode enter Debug Mode. */ #define CSR_DCSR_EBREAKU_DEBUG_MODE 1 /* @@ -310,13 +374,13 @@ #define CSR_DCSR_STEPIE 0x800ULL /* * interrupts disabled: Interrupts (including NMI) are disabled during single stepping - * with \FcsrDcsrStep set. + * with {dcsr-step} set. * This value should be supported. */ #define CSR_DCSR_STEPIE_INTERRUPTS_DISABLED 0 /* * interrupts enabled: Interrupts (including NMI) are enabled during single stepping - * with \FcsrDcsrStep set. + * with {dcsr-step} set. */ #define CSR_DCSR_STEPIE_INTERRUPTS_ENABLED 1 /* @@ -335,9 +399,9 @@ #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 + * on `ebreak` instructions that cause entry into Debug Mode. + * These counters include the `instret` CSR. On single-hart cores + * `cycle` should be stopped, but on multi-hart cores it must keep * incrementing. */ #define CSR_DCSR_STOPCOUNT_FREEZE 1 @@ -348,16 +412,16 @@ #define CSR_DCSR_STOPTIME_LENGTH 1ULL #define CSR_DCSR_STOPTIME 0x200ULL /* - * normal: \Rtime continues to reflect \Rmtime. + * normal: `time` continues to reflect `mtime`. */ #define CSR_DCSR_STOPTIME_NORMAL 0 /* - * freeze: \Rtime is frozen at the time that Debug Mode was entered. When - * leaving Debug Mode, \Rtime will reflect the latest - * value of \Rmtime again. + * freeze: `time` is frozen at the time that Debug Mode was entered. When + * leaving Debug Mode, `time` will reflect the latest + * value of `mtime` again. * - * While all harts have \FcsrDcsrStoptime=1 and are in Debug Mode, - * \Rmtime is allowed to stop incrementing. + * While all harts have {dcsr-stoptime}=1 and are in Debug Mode, + * `mtime` is allowed to stop incrementing. */ #define CSR_DCSR_STOPTIME_FREEZE 1 /* @@ -367,14 +431,14 @@ * 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. + * cycle, hardware should set {dcsr-cause} to the cause with the highest + * priority. See <> for priorities. */ #define CSR_DCSR_CAUSE_OFFSET 6ULL #define CSR_DCSR_CAUSE_LENGTH 3ULL #define CSR_DCSR_CAUSE 0x1c0ULL /* - * ebreak: An {\tt ebreak} instruction was executed. + * ebreak: An `ebreak` instruction was executed. */ #define CSR_DCSR_CAUSE_EBREAK 1 /* @@ -382,15 +446,15 @@ */ #define CSR_DCSR_CAUSE_TRIGGER 2 /* - * haltreq: The debugger requested entry to Debug Mode using \FdmDmcontrolHaltreq. + * haltreq: The debugger requested entry to Debug Mode using {dmcontrol-haltreq}. */ #define CSR_DCSR_CAUSE_HALTREQ 3 /* - * step: The hart single stepped because \FcsrDcsrStep was set. + * step: The hart single stepped because {dcsr-step} was set. */ #define CSR_DCSR_CAUSE_STEP 4 /* - * resethaltreq: The hart halted directly out of reset due to \Fresethaltreq. It + * resethaltreq: The hart halted directly out of reset due to {resethaltreq} It * is also acceptable to report 3 when this happens. */ #define CSR_DCSR_CAUSE_RESETHALTREQ 5 @@ -400,12 +464,13 @@ */ #define CSR_DCSR_CAUSE_GROUP 6 /* - * Other values are reserved for future use. + * other: The hart halted for a reason other than the ones mentioned above. + * {dcsr-extcause} may contain a more specific reason. */ +#define CSR_DCSR_CAUSE_OTHER 7 /* * 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}. + * in when Debug Mode was entered. The encoding is described in <>. * 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. @@ -417,11 +482,11 @@ #define CSR_DCSR_MPRVEN_LENGTH 1ULL #define CSR_DCSR_MPRVEN 0x10ULL /* - * disabled: \FcsrMstatusMprv in \Rmstatus is ignored in Debug Mode. + * disabled: `mprv` in `mstatus` is ignored in Debug Mode. */ #define CSR_DCSR_MPRVEN_DISABLED 0 /* - * enabled: \FcsrMstatusMprv in \Rmstatus takes effect in Debug Mode. + * enabled: `mprv` in `mstatus` takes effect in Debug Mode. */ #define CSR_DCSR_MPRVEN_ENABLED 1 /* @@ -439,7 +504,7 @@ #define CSR_DCSR_NMIP 8ULL /* * When set and not in Debug Mode, the hart will only execute a single - * instruction and then enter Debug Mode. See Section~\ref{stepBit} + * instruction and then enter Debug Mode. See xref:stepbit[] * for details. * * The debugger must not change the value of this bit while the hart @@ -450,8 +515,7 @@ #define CSR_DCSR_STEP 4ULL /* * Contains the privilege mode the hart was operating in when Debug - * Mode was entered. The encoding is described in Table - * \ref{tab:privmode}. A debugger can change this value to change + * Mode was entered. The encoding is described in <>. 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 @@ -482,7 +546,7 @@ #define CSR_TDATA1_TYPE_LENGTH 4ULL #define CSR_TDATA1_TYPE(XLEN) (0xfULL * (1ULL << ((XLEN) + -4ULL))) /* - * none: There is no trigger at this \RcsrTselect. + * none: There is no trigger at this {csr-tselect}. */ #define CSR_TDATA1_TYPE_NONE 0 /* @@ -492,34 +556,34 @@ #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. + * in this register act as described in {csr-mcontrol}. */ #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. + * in this register act as described in {csr-icount}. */ #define CSR_TDATA1_TYPE_ICOUNT 3 /* * itrigger: The trigger is an interrupt trigger. The remaining bits - * in this register act as described in \RcsrItrigger. + * in this register act as described in {csr-itrigger}. */ #define CSR_TDATA1_TYPE_ITRIGGER 4 /* * etrigger: The trigger is an exception trigger. The remaining bits - * in this register act as described in \RcsrEtrigger. + * in this register act as described in {csr-etrigger}. */ #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 + * in this register act as described in {csr-mcontrol6}. 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. + * remaining bits in this register act as described in {csr-tmexttrigger}. */ #define CSR_TDATA1_TYPE_TMEXTTRIGGER 7 /* @@ -528,10 +592,10 @@ #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 + * disabled: This trigger is disabled. In this state, {csr-tdata2} and + * {csr-tdata3} can be written with any value that is supported for * any of the types this trigger implements. - * The remaining bits in this register, except for \FcsrTdataOneDmode, + * The remaining bits in this register, except for {tdata1-dmode}, * are ignored. */ #define CSR_TDATA1_TYPE_DISABLED 15 @@ -539,19 +603,19 @@ * Other values are reserved for future use. */ /* - * If \FcsrTdataOneType is 0, then this bit is hard-wired to 0. + * If {tdata1-type} is 0, then this bit is hard-wired to 0. */ #define CSR_TDATA1_DMODE_OFFSET(XLEN) ((XLEN) + -5ULL) #define CSR_TDATA1_DMODE_LENGTH 1ULL #define CSR_TDATA1_DMODE(XLEN) (1ULL << ((XLEN) + -5ULL)) /* - * both: Both Debug and M-mode can write the {\tt tdata} registers at the - * selected \RcsrTselect. + * both: Both Debug and M-mode can write the `tdata` registers at the + * selected {csr-tselect}. */ #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. + * dmode: Only Debug Mode can write the `tdata` registers at the + * selected {csr-tselect}. Writes from other modes are ignored. */ #define CSR_TDATA1_DMODE_DMODE 1 /* @@ -559,11 +623,11 @@ * 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 + * (whose location depends on {tdata1-type}) to something other * than 1. */ /* - * If \FcsrTdataOneType is 0, then this field is hard-wired to 0. + * If {tdata1-type} is 0, then this field is hard-wired to 0. * * Trigger-specific data. */ @@ -589,14 +653,12 @@ * 0: Supports triggers as described in this spec at commit 5a5c078, * made on February 2, 2023. * - * \begin{steps}{In these older versions:} - * \item \RcsrMcontrolSix has a timing bit identical to - * \FcsrMcontrolTiming - * \item \FcsrMcontrolSixHitZero behaves just as \FcsrMcontrolHit. - * \item \FcsrMcontrolSixHitOne is read-only 0. - * \item Encodings for \FcsrMcontrolSixSize for access sizes larger - * than 64 bits are different. - * \end{steps} + * In these older versions: + * + * . {csr-mcontrol6} has a timing bit identical to {mcontrol-timing} + * . {mcontrol6-hit0} behaves just as {mcontrol-hit}. + * . {mcontrol6-hit1} is read-only 0. + * . Encodings for {mcontrol6-size} for access sizes larger than 64 bits are different. */ #define CSR_TINFO_VERSION_0 0 /* @@ -605,7 +667,7 @@ */ #define CSR_TINFO_VERSION_1 1 /* - * One bit for each possible \FcsrTdataOneType enumerated in \RcsrTdataOne. Bit N + * One bit for each possible {tdata1-type} enumerated in {csr-tdata1}. Bit N * corresponds to type N. If the bit is set, then that type is * supported by the currently selected trigger. * @@ -619,12 +681,12 @@ /* * M-mode previous trigger enable field. * - * \FcsrTcontrolMpte and \FcsrTcontrolMte provide one solution to a problem + * {tcontrol-mpte} and {tcontrol-mte} 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. + * xref:nativetrigger[] for more details. * - * When any trap into M-mode is taken, \FcsrTcontrolMpte is set to the value of - * \FcsrTcontrolMte. + * When any trap into M-mode is taken, {tcontrol-mpte} is set to the value of + * {tcontrol-mte}. */ #define CSR_TCONTROL_MPTE_OFFSET 7ULL #define CSR_TCONTROL_MPTE_LENGTH 1ULL @@ -644,8 +706,7 @@ */ #define CSR_TCONTROL_MTE_ENABLED 1 /* - * When any trap into M-mode is taken, \FcsrTcontrolMte is set to 0. When {\tt - * mret} is executed, \FcsrTcontrolMte is set to the value of \FcsrTcontrolMpte. + * When any trap into M-mode is taken, {tcontrol-mte} is set to 0. When `mret` is executed, {tcontrol-mte} is set to the value of {tcontrol-mpte}. */ #define CSR_HCONTEXT 0x6a8 #define CSR_SCONTEXT 0x5a8 @@ -655,28 +716,28 @@ * 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. + * 0. It's recommended to implement 16 bits on RV32 and 32 bits on + * RV64. */ #define CSR_SCONTEXT_DATA_OFFSET 0ULL -#define CSR_SCONTEXT_DATA_LENGTH(XLEN) (XLEN) -#define CSR_SCONTEXT_DATA(XLEN) ((1ULL << (XLEN)) + -1ULL) +#define CSR_SCONTEXT_DATA_LENGTH 0x20ULL +#define CSR_SCONTEXT_DATA 0xffffffffULL #define CSR_MCONTEXT 0x7a8 /* - * M-Mode or HS-Mode (using \RcsrHcontext) software can write a context + * M-Mode or HS-Mode (using {csr-hcontext}) 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. + * 6 bits on RV32 and 13 bits on RV64 (as visible through the + * {csr-mcontext} register). If the H extension is implemented, + * it's recommended to implement 7 bits on RV32 + * and 14 bits on RV64. */ #define CSR_MCONTEXT_HCONTEXT_OFFSET 0ULL -#define CSR_MCONTEXT_HCONTEXT_LENGTH(XLEN) (XLEN) -#define CSR_MCONTEXT_HCONTEXT(XLEN) ((1ULL << (XLEN)) + -1ULL) +#define CSR_MCONTEXT_HCONTEXT_LENGTH 0xeULL +#define CSR_MCONTEXT_HCONTEXT 0x3fffULL #define CSR_MSCONTEXT 0x7aa #define CSR_MCONTROL 0x7a1 #define CSR_MCONTROL_TYPE_OFFSET(XLEN) ((XLEN) + -4ULL) @@ -687,11 +748,11 @@ #define CSR_MCONTROL_DMODE(XLEN) (1ULL << ((XLEN) + -5ULL)) /* * Specifies the largest naturally aligned powers-of-two (NAPOT) range - * supported by the hardware when \FcsrMcontrolMatch is 1. The value is the + * supported by the hardware when {mcontrol-match} 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 0 indicates {mcontrol-match} 1 is not supported. * A value of 63 corresponds to the maximum NAPOT range, which is - * $2^{63}$ bytes in size. + * 2^63^ bytes in size. */ #define CSR_MCONTROL_MASKMAX_OFFSET(XLEN) ((XLEN) + -0xbULL) #define CSR_MCONTROL_MASKMAX_LENGTH 6ULL @@ -699,7 +760,7 @@ /* * 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 + * come from {mcontrol-sizelo}. See {mcontrol-sizelo} for how this * is used. */ #define CSR_MCONTROL_SIZEHI_OFFSET 0x15ULL @@ -743,19 +804,19 @@ /* * before: The action for this trigger will be taken just before the * instruction that triggered it is retired, but after all preceding - * instructions are retired. \Rxepc or \RcsrDpc (depending - * on \FcsrMcontrolAction) must be set to the virtual address of the + * instructions are retired. `xepc` or {csr-dpc} (depending + * on {mcontrol-action}) 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 + * If this is combined with {mcontrol-load} and + * {mcontrol-select}=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. * * If an instruction matches this trigger and the instruction performs - * multiple memory accesses, it is \unspecified which memory accesses + * multiple memory accesses, it is UNSPECIFIED which memory accesses * have completed before the trigger fires. */ #define CSR_MCONTROL_TIMING_BEFORE 0 @@ -763,39 +824,39 @@ * after: The action for this trigger will be taken after the instruction * that triggered it is retired. It should be taken before the next * instruction is retired, but it is better to implement triggers imprecisely - * than to not implement them at all. \Rxepc or - * \RcsrDpc (depending on \FcsrMcontrolAction) must be set to + * than to not implement them at all. `xepc` or + * {csr-dpc} (depending on {mcontrol-action}) 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 + * dependent on {mcontrol-select}, {mcontrol-execute}, + * {mcontrol-load}, and {mcontrol-store}. 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 + * Data load triggers with {mcontrol-timing} 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. + * {mcontrol-timing} of 1. * - * If a trigger with \FcsrMcontrolTiming of 0 matches, it is + * If a trigger with {mcontrol-timing} of 0 matches, it is * implementation-dependent whether that prevents a trigger with - * \FcsrMcontrolTiming of 1 matching as well. + * {mcontrol-timing} 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: + * from {mcontrol-sizehi}. The combined value is interpreted as follows: */ #define CSR_MCONTROL_SIZELO_OFFSET 0x10ULL #define CSR_MCONTROL_SIZELO_LENGTH 2ULL #define CSR_MCONTROL_SIZELO 0x30000ULL /* * any: The trigger will attempt to match against an access of any size. - * The behavior is only well-defined if $|select|=0$, or if the access + * The behavior is only well-defined if {mcontrol-select}=0, or if the access * size is XLEN. */ #define CSR_MCONTROL_SIZELO_ANY 0 @@ -842,24 +903,24 @@ /* * 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 + * ({mcontrol-select}=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 + * {csr-tdata2} is of size XLEN, there is a known limitation that + * data value triggers ({mcontrol-select}=1) can only be supported * for access sizes up to XLEN bits. When an implementation supports - * data value triggers (\FcsrMcontrolSelect=1), it is recommended + * data value triggers ({mcontrol-select}=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}. + * in xref:tab:action[]. */ #define CSR_MCONTROL_ACTION_OFFSET 0xcULL #define CSR_MCONTROL_ACTION_LENGTH 4ULL @@ -905,10 +966,10 @@ */ #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 + * 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. @@ -916,83 +977,83 @@ * 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. + * Because {mcontrol-chain} affects the next trigger, hardware must zero it in + * writes to {csr-mcontrol} that set {tdata1-dmode} to 0 if the next trigger has + * {tdata1-dmode} of 1. + * In addition hardware should ignore writes to {csr-mcontrol} that set + * {tdata1-dmode} to 1 if the previous trigger has both {tdata1-dmode} of 0 and + * {mcontrol-chain} of 1. Debuggers must avoid the latter case by checking + * {mcontrol-chain} on the previous trigger if they're writing {csr-mcontrol}. * * 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. + * {mcontrol-chain} in writes to {csr-mcontrol} that would make the chain too long. */ #define CSR_MCONTROL_MATCH_OFFSET 7ULL #define CSR_MCONTROL_MATCH_LENGTH 4ULL #define CSR_MCONTROL_MATCH 0x780ULL /* - * equal: Matches when any compare value equals \RcsrTdataTwo. + * equal: Matches when any compare value equals {csr-tdata2}. */ #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 + * napot: Matches when the top `M` bits of any compare value match the top + * `M` bits of {csr-tdata2}. + * `M` is `XLEN-1` minus the index of the least-significant + * bit containing 0 in {csr-tdata2}. Debuggers should only write values + * to {csr-tdata2} such that `M` + {mcontrol-maskmax} ≥ `XLEN` + * and `M` > 0, 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. + * equal to {csr-tdata2}. */ #define CSR_MCONTROL_MATCH_GE 2 /* * lt: Matches when any compare value is less than (unsigned) - * \RcsrTdataTwo. + * {csr-tdata2}. */ #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. + * mask low: Matches when latexmath:[$\frac{XLEN}{2}-{1:0}] of any compare value + * equals latexmath:[$\frac{XLEN}{2}-{1:0}] of {csr-tdata2} after + * latexmath:[$\frac{XLEN}{2}-{1:0}] of the compare value is ANDed with + * `XLEN-1`:latexmath:[$\frac{XLEN}{2}$] of {csr-tdata2}. */ #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. + * mask high: Matches when `XLEN-1`:latexmath:[$\frac{XLEN}{2}$] of any compare + * value equals latexmath:[$\frac{XLEN}{2}-{1:0}] of {csr-tdata2} after + * `XLEN-1`:latexmath:[$\frac{XLEN}{2}$] of the compare value is ANDed with + * `XLEN-1`:latexmath:[$\frac{XLEN}{2}$] of {csr-tdata2}. */ #define CSR_MCONTROL_MATCH_MASK_HIGH 5 /* - * not equal: Matches when \FcsrMcontrolMatch$=0$ would not match. + * not equal: Matches when {mcontrol-match}=0 would not match. */ #define CSR_MCONTROL_MATCH_NOT_EQUAL 8 /* - * not napot: Matches when \FcsrMcontrolMatch$=1$ would not match. + * not napot: Matches when {mcontrol-match}=1 would not match. */ #define CSR_MCONTROL_MATCH_NOT_NAPOT 9 /* - * not mask low: Matches when \FcsrMcontrolMatch$=4$ would not match. + * not mask low: Matches when {mcontrol-match}=4 would not match. */ #define CSR_MCONTROL_MATCH_NOT_MASK_LOW 12 /* - * not mask high: Matches when \FcsrMcontrolMatch$=5$ would not match. + * not mask high: Matches when {mcontrol-match}=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 + * bits of the compare values and of {csr-tdata2}. + * When {mcontrol-select}=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. + * compare values and of {csr-tdata2}. */ /* * When set, enable this trigger in M-mode. @@ -1082,8 +1143,8 @@ #define CSR_MCONTROL6_VU_LENGTH 1ULL #define CSR_MCONTROL6_VU 0x800000ULL /* - * If they are implemented, \FcsrMcontrolSixHitOne (MSB) and - * \FcsrMcontrolSixHitZero (LSB) combine into a single 2-bit field. + * If they are implemented, {mcontrol6-hit1} (MSB) and + * {mcontrol6-hit0} (LSB) combine into a single 2-bit field. * The TM updates this field when the trigger fires. After the debugger * has seen the update, it will normally write 0 to this field to so it * can see future changes. @@ -1102,16 +1163,16 @@ * before: The trigger fired before the instruction that matched it was * retired, but after all preceding instructions are retired. This * explicitly allows for instructions to be partially executed, as - * described in Section \ref{sec:multistate}. + * described in xref:multistate[]. * - * \Rxepc or \RcsrDpc (depending on \FcsrMcontrolSixAction) must be set + * `xepc` or {csr-dpc} (depending on {mcontrol6-action}) must be set * to the virtual address of the instruction that matched. */ #define CSR_MCONTROL6_HIT0_BEFORE 1 /* * after: The trigger fired after the instruction that triggered and at least * one additional instruction were retired. - * \Rxepc or \RcsrDpc (depending on \FcsrMcontrolSixAction) must be set + * `xepc` or {csr-dpc} (depending on {mcontrol6-action}) must be set * to the virtual address of the next instruction that must be executed * to preserve the program flow. */ @@ -1119,7 +1180,7 @@ /* * immediately after: The trigger fired just after the instruction that triggered it was * retired, but before any subsequent instructions were executed. - * \Rxepc or \RcsrDpc (depending on \FcsrMcontrolSixAction) must be set + * `xepc` or {csr-dpc} (depending on {mcontrol6-action}) must be set * to the virtual address of the next instruction that must be executed * to preserve the program flow. * @@ -1153,8 +1214,8 @@ #define CSR_MCONTROL6_SIZE 0x70000ULL /* * any: The trigger will attempt to match against an access of any size. - * The behavior is only well-defined if $|select|=0$, or if the access - * size is XLEN. + * The behavior is only well-defined if {mcontrol6-select}=0, or if the + * access size is XLEN. */ #define CSR_MCONTROL6_SIZE_ANY 0 /* @@ -1188,24 +1249,24 @@ /* * 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 + * ({mcontrol6-select}=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 + * {csr-tdata2} is of size XLEN, there is a known limitation that + * data value triggers ({mcontrol6-select}=1) can only be supported * for access sizes up to XLEN bits. When an implementation supports - * data value triggers (\FcsrMcontrolSixSelect=1), it is recommended + * data value triggers ({mcontrol6-select}=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}. + * in xref:tab:action[]. */ #define CSR_MCONTROL6_ACTION_OFFSET 0xcULL #define CSR_MCONTROL6_ACTION_LENGTH 4ULL @@ -1251,10 +1312,10 @@ */ #define CSR_MCONTROL6_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 + * 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. @@ -1262,85 +1323,85 @@ * 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. + * Because {mcontrol6-chain} affects the next trigger, hardware must zero it in + * writes to {csr-mcontrol6} that set {tdata1-dmode} to 0 if the next trigger has + * {tdata1-dmode} of 1. + * In addition hardware should ignore writes to {csr-mcontrol6} that set + * {tdata1-dmode} to 1 if the previous trigger has both {tdata1-dmode} of 0 and + * {mcontrol6-chain} of 1. Debuggers must avoid the latter case by checking + * {mcontrol6-chain} on the previous trigger if they're writing {csr-mcontrol6}. * * 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. + * {mcontrol6-chain} in writes to {csr-mcontrol6} that would make the chain too long. */ #define CSR_MCONTROL6_MATCH_OFFSET 7ULL #define CSR_MCONTROL6_MATCH_LENGTH 4ULL #define CSR_MCONTROL6_MATCH 0x780ULL /* - * equal: Matches when any compare value equals \RcsrTdataTwo. + * equal: Matches when any compare value equals {csr-tdata2}. */ #define CSR_MCONTROL6_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. - * \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$. + * napot: Matches when the top `M` bits of any compare value match the top + * `M` bits of {csr-tdata2}. + * `M` is `XLEN-1` minus the index of the least-significant bit + * containing 0 in {csr-tdata2}. + * {csr-tdata2} 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 {csr-tdata2} require M + `maskmax6` ≥ `XLEN` and `M` > 0. * See above for how to determine maskmax6. */ #define CSR_MCONTROL6_MATCH_NAPOT 1 /* * ge: Matches when any compare value is greater than (unsigned) or - * equal to \RcsrTdataTwo. + * equal to {csr-tdata2}. */ #define CSR_MCONTROL6_MATCH_GE 2 /* * lt: Matches when any compare value is less than (unsigned) - * \RcsrTdataTwo. + * {csr-tdata2}. */ #define CSR_MCONTROL6_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. + * mask low: Matches when latexmath:[$\frac{XLEN}{2}-{1:0}] of any compare value + * equals latexmath:[$\frac{XLEN}{2}-{1:0}] of {csr-tdata2} after + * latexmath:[$\frac{XLEN}{2}-{1:0}] of the compare value is ANDed with + * `XLEN-1`:latexmath:[$\frac{XLEN}{2}$] of {csr-tdata2}. */ #define CSR_MCONTROL6_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. + * mask high: Matches when `XLEN-1`:latexmath:[$\frac{XLEN}{2}$] of any compare + * value equals latexmath:[$\frac{XLEN}{2}-{1:0}] of {csr-tdata2} after + * `XLEN-1`:latexmath:[$\frac{XLEN}{2}$] of the compare value is ANDed with + * `XLEN-1`:latexmath:[$\frac{XLEN}{2}$] of {csr-tdata2}. */ #define CSR_MCONTROL6_MATCH_MASK_HIGH 5 /* - * not equal: Matches when \FcsrMcontrolSixMatch$=0$ would not match. + * not equal: Matches when {mcontrol6-match} `=0` would not match. */ #define CSR_MCONTROL6_MATCH_NOT_EQUAL 8 /* - * not napot: Matches when \FcsrMcontrolSixMatch$=1$ would not match. + * not napot: Matches when {mcontrol6-match} `=1` would not match. */ #define CSR_MCONTROL6_MATCH_NOT_NAPOT 9 /* - * not mask low: Matches when \FcsrMcontrolSixMatch$=4$ would not match. + * not mask low: Matches when {mcontrol6-match} `=4` would not match. */ #define CSR_MCONTROL6_MATCH_NOT_MASK_LOW 12 /* - * not mask high: Matches when \FcsrMcontrolSixMatch$=5$ would not match. + * not mask high: Matches when {mcontrol6-match} `=5` would not match. */ #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 + * bits of the compare values and of {csr-tdata2}. + * When {mcontrol-select}=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. + * compare values and of {csr-tdata2}. */ /* * When set, enable this trigger in M-mode. @@ -1433,7 +1494,7 @@ #define CSR_ICOUNT_HIT_LENGTH 1ULL #define CSR_ICOUNT_HIT 0x1000000ULL /* - * The trigger will generally fire after \FcsrIcountCount instructions + * The trigger will generally fire after {icount-count} instructions * in enabled modes have been executed. See above for the precise behavior. */ #define CSR_ICOUNT_COUNT_OFFSET 0xaULL @@ -1446,7 +1507,7 @@ #define CSR_ICOUNT_M_LENGTH 1ULL #define CSR_ICOUNT_M 0x200ULL /* - * This bit becomes set when \FcsrIcountCount is decremented from 1 + * This bit becomes set when {icount-count} 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. */ @@ -1471,7 +1532,7 @@ #define CSR_ICOUNT_U 0x40ULL /* * The action to take when the trigger fires. The values are explained - * in Table~\ref{tab:action}. + * in xref:tab:action[]. */ #define CSR_ICOUNT_ACTION_OFFSET 0ULL #define CSR_ICOUNT_ACTION_LENGTH 6ULL @@ -1573,7 +1634,7 @@ #define CSR_ITRIGGER_U 0x40ULL /* * The action to take when the trigger fires. The values are explained - * in Table~\ref{tab:action}. + * in xref:tab:action[]. */ #define CSR_ITRIGGER_ACTION_OFFSET 0ULL #define CSR_ITRIGGER_ACTION_LENGTH 6ULL @@ -1668,7 +1729,7 @@ #define CSR_ETRIGGER_U 0x40ULL /* * The action to take when the trigger fires. The values are explained - * in Table~\ref{tab:action}. + * in xref:tab:action[]. */ #define CSR_ETRIGGER_ACTION_OFFSET 0ULL #define CSR_ETRIGGER_ACTION_LENGTH 6ULL @@ -1734,7 +1795,7 @@ #define CSR_TMEXTTRIGGER_SELECT 0x3fffc0ULL /* * The action to take when the trigger fires. The values are explained - * in Table~\ref{tab:action}. + * in xref:tab:action[]. */ #define CSR_TMEXTTRIGGER_ACTION_OFFSET 0ULL #define CSR_TMEXTTRIGGER_ACTION_LENGTH 6ULL @@ -1769,7 +1830,7 @@ #define CSR_TMEXTTRIGGER_ACTION_EXTERNAL1 9 #define CSR_TEXTRA32 0x7a3 /* - * Data used together with \FcsrTextraThirtytwoMhselect. + * Data used together with {textra32-mhselect}. */ #define CSR_TEXTRA32_MHVALUE_OFFSET 0x1aULL #define CSR_TEXTRA32_MHVALUE_LENGTH 6ULL @@ -1778,22 +1839,22 @@ #define CSR_TEXTRA32_MHSELECT_LENGTH 3ULL #define CSR_TEXTRA32_MHSELECT 0x3800000ULL /* - * ignore: Ignore \FcsrTextraThirtytwoMhvalue. + * ignore: Ignore {textra32-mhvalue}. */ #define CSR_TEXTRA32_MHSELECT_IGNORE 0 /* * mcontext: This trigger will only match or fire if the low bits of - * \RcsrMcontext/\RcsrHcontext equal \FcsrTextraThirtytwoMhvalue. + * {csr-mcontext}/{csr-hcontext} equal {textra32-mhvalue}. */ #define CSR_TEXTRA32_MHSELECT_MCONTEXT 4 /* - * 1, 5 (mcontext\_select): This trigger will only match or fire if the + * 1, 5 (mcontext_select): This trigger will only match or fire if the * low bits of - * \RcsrMcontext/\RcsrHcontext equal \{\FcsrTextraThirtytwoMhvalue, mhselect[2]\}. + * {csr-mcontext}/{csr-hcontext} equal {{textra32-mhvalue}, mhselect[2]}. * - * 2, 6 (vmid\_select): This trigger will only match or fire if VMID in + * 2, 6 (vmid_select): This trigger will only match or fire if VMID in * hgatp equals the lower VMIDMAX - * (defined in the Privileged Spec) bits of \{\FcsrTextraThirtytwoMhvalue, mhselect[2]\}. + * (defined in the Privileged Spec) bits of {{textra32-mhvalue}, mhselect[2]}. * * 3, 7 (reserved): Reserved. * @@ -1801,15 +1862,15 @@ */ /* * When the least significant bit of this field is 1, it causes bits 7:0 - * in the comparison to be ignored, when \FcsrTextraThirtytwoSselect=1. + * in the comparison to be ignored, when {textra32-sselect}=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. + * to be ignored in the comparison, when {textra32-sselect}=1. */ #define CSR_TEXTRA32_SBYTEMASK_OFFSET 0x12ULL #define CSR_TEXTRA32_SBYTEMASK_LENGTH 2ULL #define CSR_TEXTRA32_SBYTEMASK 0xc0000ULL /* - * Data used together with \FcsrTextraThirtytwoSselect. + * Data used together with {textra32-sselect}. * * This field should be tied to 0 when S-mode is not supported. */ @@ -1820,24 +1881,24 @@ #define CSR_TEXTRA32_SSELECT_LENGTH 2ULL #define CSR_TEXTRA32_SSELECT 3ULL /* - * ignore: Ignore \FcsrTextraThirtytwoSvalue. + * ignore: Ignore {textra32-svalue}. */ #define CSR_TEXTRA32_SSELECT_IGNORE 0 /* * scontext: This trigger will only match or fire if the low bits of - * \RcsrScontext equal \FcsrTextraThirtytwoSvalue. + * {csr-scontext} equal {textra32-svalue}. */ #define CSR_TEXTRA32_SSELECT_SCONTEXT 1 /* * asid: This trigger will only match or fire if: - * \begin{itemize}[noitemsep,nolistsep] - * \item the mode is VS-mode or VU-mode and ASID in \Rvsatp + * + * * the mode is VS-mode or VU-mode and ASID in `vsatp` * equals the lower ASIDMAX (defined in the Privileged Spec) bits - * of \FcsrTextraThirtytwoSvalue. - * \item in all other modes, ASID in \Rsatp equals the lower + * of {textra32-svalue}. + * + * * in all other modes, ASID in `satp` equals the lower * ASIDMAX (defined in the Privileged Spec) bits of - * \FcsrTextraThirtytwoSvalue. - * \end{itemize} + * {textra32-svalue}. */ #define CSR_TEXTRA32_SSELECT_ASID 2 /* @@ -1852,18 +1913,17 @@ #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. + * in the comparison to be ignored, when {textra64-sselect}=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. + * and fourth bit controls the comparison of bits 31:24. */ #define CSR_TEXTRA64_SBYTEMASK_OFFSET 0x24ULL -#define CSR_TEXTRA64_SBYTEMASK_LENGTH 5ULL -#define CSR_TEXTRA64_SBYTEMASK 0x1f000000000ULL +#define CSR_TEXTRA64_SBYTEMASK_LENGTH 4ULL +#define CSR_TEXTRA64_SBYTEMASK 0xf000000000ULL #define CSR_TEXTRA64_SVALUE_OFFSET 2ULL -#define CSR_TEXTRA64_SVALUE_LENGTH 0x22ULL -#define CSR_TEXTRA64_SVALUE 0xffffffffcULL +#define CSR_TEXTRA64_SVALUE_LENGTH 0x20ULL +#define CSR_TEXTRA64_SVALUE 0x3fffffffcULL #define CSR_TEXTRA64_SSELECT_OFFSET 0ULL #define CSR_TEXTRA64_SSELECT_LENGTH 2ULL #define CSR_TEXTRA64_SSELECT 3ULL @@ -1872,33 +1932,33 @@ #define DM_DMSTATUS_NDMRESETPENDING_LENGTH 1ULL #define DM_DMSTATUS_NDMRESETPENDING 0x1000000ULL /* - * false: Unimplemented, or \FdmDmcontrolNdmreset is zero and no ndmreset is currently + * false: Unimplemented, or {dmcontrol-ndmreset} 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. + * true: {dmcontrol-ndmreset} is currently nonzero, or there is an ndmreset in progress. */ #define DM_DMSTATUS_NDMRESETPENDING_TRUE 1 #define DM_DMSTATUS_STICKYUNAVAIL_OFFSET 0x17ULL #define DM_DMSTATUS_STICKYUNAVAIL_LENGTH 1ULL #define DM_DMSTATUS_STICKYUNAVAIL 0x800000ULL /* - * current: The per-hart {\tt unavail} bits reflect the current state of the hart. + * current: The per-hart `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. + * sticky: The per-hart `unavail` bits are sticky. Once they are set, they will + * not clear until the debugger acknowledges them using {dmcontrol-ackunavail}. */ #define DM_DMSTATUS_STICKYUNAVAIL_STICKY 1 /* - * If 1, then there is an implicit {\tt ebreak} instruction at the + * If 1, then there is an implicit `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 + * the debugger from having to write the `ebreak` itself, and * allows the Program Buffer to be one word smaller. * - * This must be 1 when \FdmAbstractcsProgbufsize is 1. + * This must be 1 when {abstractcs-progbufsize} is 1. */ #define DM_DMSTATUS_IMPEBREAK_OFFSET 0x16ULL #define DM_DMSTATUS_IMPEBREAK_LENGTH 1ULL @@ -1919,14 +1979,14 @@ #define DM_DMSTATUS_ANYHAVERESET 0x40000ULL /* * This field is 1 when all currently selected harts have their - * resume ack bit\index{resume ack bit} set. + * ((resume ack bit)) set. */ #define DM_DMSTATUS_ALLRESUMEACK_OFFSET 0x11ULL #define DM_DMSTATUS_ALLRESUMEACK_LENGTH 1ULL #define DM_DMSTATUS_ALLRESUMEACK 0x20000ULL /* * This field is 1 when any currently selected hart has its - * resume ack bit\index{resume ack bit} set. + * ((resume ack bit)) set. */ #define DM_DMSTATUS_ANYRESUMEACK_OFFSET 0x10ULL #define DM_DMSTATUS_ANYRESUMEACK_LENGTH 1ULL @@ -1947,7 +2007,7 @@ #define DM_DMSTATUS_ANYNONEXISTENT 0x4000ULL /* * This field is 1 when all currently selected harts are - * unavailable, or (if \FdmDmstatusStickyunavail is 1) were + * unavailable, or (if {dmstatus-stickyunavail} is 1) were * unavailable without that being acknowledged. */ #define DM_DMSTATUS_ALLUNAVAIL_OFFSET 0xdULL @@ -1955,7 +2015,7 @@ #define DM_DMSTATUS_ALLUNAVAIL 0x2000ULL /* * This field is 1 when any currently selected hart is unavailable, - * or (if \FdmDmstatusStickyunavail is 1) was unavailable without + * or (if {dmstatus-stickyunavail} is 1) was unavailable without * that being acknowledged. */ #define DM_DMSTATUS_ANYUNAVAIL_OFFSET 0xcULL @@ -2005,21 +2065,21 @@ #define DM_DMSTATUS_AUTHBUSY 0x40ULL /* * ready: The authentication module is ready to process the next - * read/write to \RdmAuthdata. + * read/write to {dm-authdata}. */ #define DM_DMSTATUS_AUTHBUSY_READY 0 /* - * busy: The authentication module is busy. Accessing \RdmAuthdata results + * busy: The authentication module is busy. Accessing {dm-authdata} results * in unspecified behavior. */ #define DM_DMSTATUS_AUTHBUSY_BUSY 1 /* - * \FdmDmstatusAuthbusy only becomes set in immediate response to an access to - * \RdmAuthdata. + * {dmstatus-authbusy} only becomes set in immediate response to an access to + * {dm-authdata}. */ /* * 1 if this Debug Module supports halt-on-reset functionality - * controllable by the \FdmDmcontrolSetresethaltreq and \FdmDmcontrolClrresethaltreq bits. + * controllable by the {dmcontrol-setresethaltreq} and {dmcontrol-clrresethaltreq} bits. * 0 otherwise. */ #define DM_DMSTATUS_HASRESETHALTREQ_OFFSET 5ULL @@ -2029,12 +2089,12 @@ #define DM_DMSTATUS_CONFSTRPTRVALID_LENGTH 1ULL #define DM_DMSTATUS_CONFSTRPTRVALID 0x10ULL /* - * invalid: \RdmConfstrptrZero--\RdmConfstrptrThree hold information which + * invalid: {dm-confstrptr0}--{dm-confstrptr3} hold information which * is not relevant to the configuration structure. */ #define DM_DMSTATUS_CONFSTRPTRVALID_INVALID 0 /* - * valid: \RdmConfstrptrZero--\RdmConfstrptrThree hold the address of the + * valid: {dm-confstrptr0}--{dm-confstrptr3} hold the address of the * configuration structure. */ #define DM_DMSTATUS_CONFSTRPTRVALID_VALID 1 @@ -2074,7 +2134,10 @@ * harts. Running harts will halt whenever their halt request bit is * set. * - * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. + * Writes apply to the new value of {hartsel} and {dmcontrol-hasel}. + * + * Writes to this bit should be ignored while an abstract command is + * executing. */ #define DM_DMCONTROL_HALTREQ_OFFSET 0x1fULL #define DM_DMCONTROL_HALTREQ_LENGTH 1ULL @@ -2084,9 +2147,12 @@ * they are halted when the write occurs. It also clears the resume * ack bit for those harts. * - * \FdmDmcontrolResumereq is ignored if \FdmDmcontrolHaltreq is set. + * {dmcontrol-resumereq} is ignored if {dmcontrol-haltreq} is set. * - * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. + * Writes apply to the new value of {hartsel} and {dmcontrol-hasel}. + * + * Writes to this bit should be ignored while an abstract command is + * executing. */ #define DM_DMCONTROL_RESUMEREQ_OFFSET 0x1eULL #define DM_DMCONTROL_RESUMEREQ_LENGTH 1ULL @@ -2103,7 +2169,7 @@ * 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. + * Writes apply to the new value of {hartsel} and {dmcontrol-hasel}. */ #define DM_DMCONTROL_HARTRESET_OFFSET 0x1dULL #define DM_DMCONTROL_HARTRESET_LENGTH 1ULL @@ -2116,11 +2182,14 @@ */ #define DM_DMCONTROL_ACKHAVERESET_NOP 0 /* - * ack: Clears {\tt havereset} for any selected harts. + * ack: Clears `havereset` for any selected harts. */ #define DM_DMCONTROL_ACKHAVERESET_ACK 1 /* - * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. + * Writes apply to the new value of {hartsel} and {dmcontrol-hasel}. + * + * Writes to this bit should be ignored while an abstract command is + * executing. */ #define DM_DMCONTROL_ACKUNAVAIL_OFFSET 0x1bULL #define DM_DMCONTROL_ACKUNAVAIL_LENGTH 1ULL @@ -2130,11 +2199,11 @@ */ #define DM_DMCONTROL_ACKUNAVAIL_NOP 0 /* - * ack: Clears {\tt unavail} for any selected harts that are currently available. + * ack: Clears `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. + * Writes apply to the new value of {hartsel} and {dmcontrol-hasel}. */ /* * Selects the definition of currently selected harts. @@ -2143,12 +2212,12 @@ #define DM_DMCONTROL_HASEL_LENGTH 1ULL #define DM_DMCONTROL_HASEL 0x4000000ULL /* - * single: There is a single currently selected hart, that is selected by \Fhartsel. + * single: There is a single currently selected hart, that is selected by {hartsel}. */ #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 + * selected by {hartsel}, plus those selected by the hart array mask * register. */ #define DM_DMCONTROL_HASEL_MULTIPLE 1 @@ -2159,49 +2228,52 @@ * is supported. */ /* - * The low 10 bits of \Fhartsel: the DM-specific index of the hart to + * The low 10 bits of {hartsel}: the DM-specific index of the hart to * select. This hart is always part of the currently selected harts. */ #define DM_DMCONTROL_HARTSELLO_OFFSET 0x10ULL #define DM_DMCONTROL_HARTSELLO_LENGTH 0xaULL #define DM_DMCONTROL_HARTSELLO 0x3ff0000ULL /* - * The high 10 bits of \Fhartsel: the DM-specific index of the hart to + * The high 10 bits of {hartsel}: the DM-specific index of the hart to * select. This hart is always part of the currently selected harts. */ #define DM_DMCONTROL_HARTSELHI_OFFSET 6ULL #define DM_DMCONTROL_HARTSELHI_LENGTH 0xaULL #define DM_DMCONTROL_HARTSELHI 0xffc0ULL /* - * This optional field sets \Fkeepalive for all currently selected - * harts, unless \FdmDmcontrolClrkeepalive is simultaneously set to + * This optional field sets {keepalive} for all currently selected + * harts, unless {dmcontrol-clrkeepalive} is simultaneously set to * 1. * - * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. + * Writes apply to the new value of {hartsel} and {dmcontrol-hasel}. */ #define DM_DMCONTROL_SETKEEPALIVE_OFFSET 5ULL #define DM_DMCONTROL_SETKEEPALIVE_LENGTH 1ULL #define DM_DMCONTROL_SETKEEPALIVE 0x20ULL /* - * This optional field clears \Fkeepalive for all currently selected + * This optional field clears {keepalive} for all currently selected * harts. * - * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. + * Writes apply to the new value of {hartsel} and {dmcontrol-hasel}. */ #define DM_DMCONTROL_CLRKEEPALIVE_OFFSET 4ULL #define DM_DMCONTROL_CLRKEEPALIVE_LENGTH 1ULL #define DM_DMCONTROL_CLRKEEPALIVE 0x10ULL /* * This optional field writes the halt-on-reset request bit for all - * currently selected harts, unless \FdmDmcontrolClrresethaltreq is + * currently selected harts, unless {dmcontrol-clrresethaltreq} 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. + * cleared. The debugger must write to {dmcontrol-clrresethaltreq} to clear it. + * + * Writes apply to the new value of {hartsel} and {dmcontrol-hasel}. * - * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. + * If {dmstatus-hasresethaltreq} is 0, this field is not implemented. * - * If \FdmDmstatusHasresethaltreq is 0, this field is not implemented. + * Writes to this bit should be ignored while an abstract command is + * executing. */ #define DM_DMCONTROL_SETRESETHALTREQ_OFFSET 3ULL #define DM_DMCONTROL_SETRESETHALTREQ_LENGTH 1ULL @@ -2210,7 +2282,10 @@ * 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. + * Writes apply to the new value of {hartsel} and {dmcontrol-hasel}. + * + * Writes to this bit should be ignored while an abstract command is + * executing. */ #define DM_DMCONTROL_CLRRESETHALTREQ_OFFSET 2ULL #define DM_DMCONTROL_CLRRESETHALTREQ_LENGTH 1ULL @@ -2230,21 +2305,25 @@ /* * 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 + * {dm-dmcontrol} until {dmcontrol-dmactive} has taken the requested value + * before performing any action that assumes the requested {dmcontrol-dmactive} * 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. + * indicate completion by setting {dmcontrol-dmactive} to the requested value. + * During this time, the DM may ignore any register writes. */ #define DM_DMCONTROL_DMACTIVE_OFFSET 0ULL #define DM_DMCONTROL_DMACTIVE_LENGTH 1ULL #define DM_DMCONTROL_DMACTIVE 1ULL /* * inactive: The module's state, including authentication mechanism, - * takes its reset values (the \FdmDmcontrolDmactive bit is the only bit which can + * takes its reset values (the {dmcontrol-dmactive} 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 + * to the module may fail. Specifically, {dmstatus-version} might not return * correct data. + * + * When this value is written, the DM may ignore any other bits written + * to {dmcontrol} in the same write. */ #define DM_DMCONTROL_DMACTIVE_INACTIVE 0 /* @@ -2255,9 +2334,9 @@ * 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. + * To place the Debug Module into a known state, a debugger should write 0 to {dmcontrol-dmactive}, + * poll until {dmcontrol-dmactive} is observed 0, write 1 to {dmcontrol-dmactive}, and + * poll until {dmcontrol-dmactive} is observed 1. * * Implementations may pay attention to this bit to further aid * debugging, for example by preventing the Debug Module from being @@ -2265,8 +2344,8 @@ */ #define DM_HARTINFO 0x12 /* - * Number of {\tt dscratch} registers available for the debugger - * to use during program buffer execution, starting from \RcsrDscratchZero. + * Number of `dscratch` registers available for the debugger + * to use during program buffer execution, starting from {csr-dscratch0}. * The debugger can make no assumptions about the contents of these * registers between commands. */ @@ -2277,37 +2356,37 @@ #define DM_HARTINFO_DATAACCESS_LENGTH 1ULL #define DM_HARTINFO_DATAACCESS 0x10000ULL /* - * csr: The {\tt data} registers are shadowed in the hart by CSRs. + * csr: The `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}. + * to a single argument, per <>. */ #define DM_HARTINFO_DATAACCESS_CSR 0 /* - * memory: The {\tt data} registers are shadowed in the hart's memory map. + * memory: The `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 {hartinfo-dataaccess} is 0: Number of CSRs dedicated to + * shadowing the `data` registers. * - * If \FdmHartinfoDataaccess is 1: Number of 32-bit words in the memory map - * dedicated to shadowing the {\tt data} registers. + * If {hartinfo-dataaccess} is 1: Number of 32-bit words in the memory map + * dedicated to shadowing the `data` registers. * - * Since there are at most 12 {\tt data} registers, the value in this + * Since there are at most 12 `data` registers, the value in this * register must be 12 or smaller. */ #define DM_HARTINFO_DATASIZE_OFFSET 0xcULL #define DM_HARTINFO_DATASIZE_LENGTH 4ULL #define DM_HARTINFO_DATASIZE 0xf000ULL /* - * If \FdmHartinfoDataaccess is 0: The number of the first CSR dedicated to - * shadowing the {\tt data} registers. + * If {hartinfo-dataaccess} is 0: The number of the first CSR dedicated to + * shadowing the `data` registers. * - * If \FdmHartinfoDataaccess is 1: Address of RAM where the data + * If {hartinfo-dataaccess} 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. + * `x0` as the address register. */ #define DM_HARTINFO_DATAADDR_OFFSET 0ULL #define DM_HARTINFO_DATAADDR_LENGTH 0xcULL @@ -2315,7 +2394,7 @@ #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 + * 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 0ULL @@ -2344,7 +2423,7 @@ */ #define DM_ABSTRACTCS_BUSY_BUSY 1 /* - * This bit is set as soon as \RdmCommand is written, and is + * This bit is set as soon as {dm-command} is written, and is * not cleared until that command has completed. */ /* @@ -2371,7 +2450,7 @@ * 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. + * This field only contains a valid value if {abstractcs-busy} is 0. */ #define DM_ABSTRACTCS_CMDERR_OFFSET 8ULL #define DM_ABSTRACTCS_CMDERR_LENGTH 3ULL @@ -2381,14 +2460,14 @@ */ #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. + * busy: An abstract command was executing while {dm-command}, + * {dm-abstractcs}, or {dm-abstractauto} was written, or when one + * of the `data` or `progbuf` registers was read or written. + * This status is only written if {abstractcs-cmderr} contains 0. */ #define DM_ABSTRACTCS_CMDERR_BUSY 1 /* - * not supported: The command in \RdmCommand is not supported. It + * not supported: The command in {dm-command} 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. @@ -2396,7 +2475,7 @@ #define DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED 2 /* * exception: An exception occurred while executing the command - * (e.g.\ while executing the Program Buffer). + * (e.g. while executing the Program Buffer). */ #define DM_ABSTRACTCS_CMDERR_EXCEPTION 3 /* @@ -2405,7 +2484,7 @@ */ #define DM_ABSTRACTCS_CMDERR_HALT_RESUME 4 /* - * bus: The abstract command failed due to a bus error (e.g.\ + * bus: The abstract command failed due to a bus error (e.g. * alignment, access size, or timeout). */ #define DM_ABSTRACTCS_CMDERR_BUS 5 @@ -2418,7 +2497,7 @@ */ #define DM_ABSTRACTCS_CMDERR_OTHER 7 /* - * Number of {\tt data} registers that are implemented as part of the + * Number of `data` registers that are implemented as part of the * abstract command interface. Valid sizes are 1 -- 12. */ #define DM_ABSTRACTCS_DATACOUNT_OFFSET 0ULL @@ -2442,18 +2521,18 @@ #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. + * corresponding `progbuf` word cause the DM to act as if the + * current value in {dm-command} was written there again after the + * access to `progbuf` completes. */ #define DM_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET 0x10ULL #define DM_ABSTRACTAUTO_AUTOEXECPROGBUF_LENGTH 0x10ULL #define DM_ABSTRACTAUTO_AUTOEXECPROGBUF 0xffff0000ULL /* * When a bit in this field is 1, read or write accesses to the - * corresponding {\tt data} word cause the DM to act as if the current - * value in \RdmCommand was written there again after the - * access to {\tt data} completes. + * corresponding `data` word cause the DM to act as if the current + * value in {dm-command} was written there again after the + * access to `data` completes. */ #define DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET 0ULL #define DM_ABSTRACTAUTO_AUTOEXECDATA_LENGTH 0xcULL @@ -2538,13 +2617,13 @@ #define DM_DMCS2_DMEXTTRIGGER_LENGTH 4ULL #define DM_DMCS2_DMEXTTRIGGER 0x780ULL /* - * When \FdmDmcsTwoHgselect is 0, contains the group of the hart - * specified by \Fhartsel. + * When {dmcs2-hgselect} is 0, contains the group of the hart + * specified by {hartsel}. * - * When \FdmDmcsTwoHgselect is 1, contains the group of the DM external - * trigger selected by \FdmDmcsTwoDmexttrigger. + * When {dmcs2-hgselect} is 1, contains the group of the DM external + * trigger selected by {dmcs2-dmexttrigger}. * - * The value written to this field is ignored unless \FdmDmcsTwoHgwrite + * The value written to this field is ignored unless {dmcs2-hgwrite} * is also written 1. * * Group numbers are contiguous starting at 0, with the highest number @@ -2558,16 +2637,16 @@ #define DM_DMCS2_GROUP_LENGTH 5ULL #define DM_DMCS2_GROUP 0x7cULL /* - * When 1 is written and \FdmDmcsTwoHgselect is 0, for every selected - * hart the DM will change its group to the value written to \FdmDmcsTwoGroup, + * When 1 is written and {dmcs2-hgselect} is 0, for every selected + * hart the DM will change its group to the value written to {dmcs2-group}, * 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 + * When 1 is written and {dmcs2-hgselect} is 1, the DM will change + * the group of the DM external trigger selected by {dmcs2-dmexttrigger} + * to the value written to {dmcs2-group}, if the hardware supports * that group for that trigger. * * Writing 0 has no effect. @@ -2624,7 +2703,7 @@ /* * 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 + * already in progress (while {sbcs-sbbusy} 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 @@ -2639,15 +2718,15 @@ * 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. + * Writes to {dm-sbcs} while {sbcs-sbbusy} is high result in undefined + * behavior. A debugger must not write to {dm-sbcs} until it reads + * {sbcs-sbbusy} as 0. */ #define DM_SBCS_SBBUSY_OFFSET 0x15ULL #define DM_SBCS_SBBUSY_LENGTH 1ULL #define DM_SBCS_SBBUSY 0x200000ULL /* - * When 1, every write to \RdmSbaddressZero automatically triggers a + * When 1, every write to {dm-sbaddress0} automatically triggers a * system bus read at the new address. */ #define DM_SBCS_SBREADONADDR_OFFSET 0x14ULL @@ -2680,18 +2759,18 @@ */ #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. + * If {sbcs-sbaccess} has an unsupported value when the DM starts a bus + * access, the access is not performed and {sbcs-sberror} is set to 4. */ /* - * When 1, {\tt sbaddress} is incremented by the access size (in - * bytes) selected in \FdmSbcsSbaccess after every system bus access. + * When 1, `sbaddress` is incremented by the access size (in + * bytes) selected in {sbcs-sbaccess} after every system bus access. */ #define DM_SBCS_SBAUTOINCREMENT_OFFSET 0x10ULL #define DM_SBCS_SBAUTOINCREMENT_LENGTH 1ULL #define DM_SBCS_SBAUTOINCREMENT 0x10000ULL /* - * When 1, every read from \RdmSbdataZero automatically triggers a + * When 1, every read from {dm-sbdata0} automatically triggers a * system bus read at the (possibly auto-incremented) address. */ #define DM_SBCS_SBREADONDATA_OFFSET 0xfULL @@ -2772,14 +2851,14 @@ #define DM_SBCS_SBACCESS8 1ULL #define DM_SBADDRESS0 0x39 /* - * Accesses bits 31:0 of the physical address in {\tt sbaddress}. + * Accesses bits 31:0 of the physical address in `sbaddress`. */ #define DM_SBADDRESS0_ADDRESS_OFFSET 0ULL #define DM_SBADDRESS0_ADDRESS_LENGTH 0x20ULL #define DM_SBADDRESS0_ADDRESS 0xffffffffULL #define DM_SBADDRESS1 0x3a /* - * Accesses bits 63:32 of the physical address in {\tt sbaddress} (if + * Accesses bits 63:32 of the physical address in `sbaddress` (if * the system address bus is that wide). */ #define DM_SBADDRESS1_ADDRESS_OFFSET 0ULL @@ -2787,7 +2866,7 @@ #define DM_SBADDRESS1_ADDRESS 0xffffffffULL #define DM_SBADDRESS2 0x3b /* - * Accesses bits 95:64 of the physical address in {\tt sbaddress} (if + * Accesses bits 95:64 of the physical address in `sbaddress` (if * the system address bus is that wide). */ #define DM_SBADDRESS2_ADDRESS_OFFSET 0ULL @@ -2795,7 +2874,7 @@ #define DM_SBADDRESS2_ADDRESS 0xffffffffULL #define DM_SBADDRESS3 0x37 /* - * Accesses bits 127:96 of the physical address in {\tt sbaddress} (if + * Accesses bits 127:96 of the physical address in `sbaddress` (if * the system address bus is that wide). */ #define DM_SBADDRESS3_ADDRESS_OFFSET 0ULL @@ -2803,14 +2882,14 @@ #define DM_SBADDRESS3_ADDRESS 0xffffffffULL #define DM_SBDATA0 0x3c /* - * Accesses bits 31:0 of {\tt sbdata}. + * Accesses bits 31:0 of `sbdata`. */ #define DM_SBDATA0_DATA_OFFSET 0ULL #define DM_SBDATA0_DATA_LENGTH 0x20ULL #define DM_SBDATA0_DATA 0xffffffffULL #define DM_SBDATA1 0x3d /* - * Accesses bits 63:32 of {\tt sbdata} (if the system bus is that + * Accesses bits 63:32 of `sbdata` (if the system bus is that * wide). */ #define DM_SBDATA1_DATA_OFFSET 0ULL @@ -2818,7 +2897,7 @@ #define DM_SBDATA1_DATA 0xffffffffULL #define DM_SBDATA2 0x3e /* - * Accesses bits 95:64 of {\tt sbdata} (if the system bus is that + * Accesses bits 95:64 of `sbdata` (if the system bus is that * wide). */ #define DM_SBDATA2_DATA_OFFSET 0ULL @@ -2826,7 +2905,7 @@ #define DM_SBDATA2_DATA 0xffffffffULL #define DM_SBDATA3 0x3f /* - * Accesses bits 127:96 of {\tt sbdata} (if the system bus is that + * Accesses bits 127:96 of `sbdata` (if the system bus is that * wide). */ #define DM_SBDATA3_DATA_OFFSET 0ULL @@ -2878,14 +2957,14 @@ */ #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 + * If {accessregister-aarsize} specifies a size larger than the register's actual size, + * then the access must fail. If a register is accessible, then reads of {accessregister-aarsize} * 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. + * happens to the high bits in that case is UNSPECIFIED. * * This field controls the Argument Width as referenced in - * Table~\ref{tab:datareg}. + * xref:tab:datareg[]. */ #define AC_ACCESS_REGISTER_AARPOSTINCREMENT_OFFSET 0x13ULL #define AC_ACCESS_REGISTER_AARPOSTINCREMENT_LENGTH 1ULL @@ -2895,11 +2974,11 @@ */ #define AC_ACCESS_REGISTER_AARPOSTINCREMENT_DISABLED 0 /* - * enabled: After a successful register access, \FacAccessregisterRegno is + * enabled: After a successful register access, {accessregister-regno} is * incremented. Incrementing past the highest supported value - * causes \FacAccessregisterRegno to become \unspecified. Supporting + * causes {accessregister-regno} to become UNSPECIFIED. Supporting * this variant is optional. It is undefined whether the increment - * happens when \FacAccessregisterTransfer is 0. + * happens when {accessregister-transfer} is 0. */ #define AC_ACCESS_REGISTER_AARPOSTINCREMENT_ENABLED 1 #define AC_ACCESS_REGISTER_POSTEXEC_OFFSET 0x12ULL @@ -2907,7 +2986,7 @@ #define AC_ACCESS_REGISTER_POSTEXEC 0x40000ULL /* * disabled: No effect. This variant must be supported, and is the only - * supported one if \FdmAbstractcsProgbufsize is 0. + * supported one if {abstractcs-progbufsize} is 0. */ #define AC_ACCESS_REGISTER_POSTEXEC_DISABLED 0 /* @@ -2920,37 +2999,37 @@ #define AC_ACCESS_REGISTER_TRANSFER_LENGTH 1ULL #define AC_ACCESS_REGISTER_TRANSFER 0x20000ULL /* - * disabled: Don't do the operation specified by \FacAccessregisterWrite. + * disabled: Don't do the operation specified by {accessregister-write}. */ #define AC_ACCESS_REGISTER_TRANSFER_DISABLED 0 /* - * enabled: Do the operation specified by \FacAccessregisterWrite. + * enabled: Do the operation specified by {accessregister-write}. */ #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. + * having to worry about placing valid values into {accessregister-aarsize} or {accessregister-regno}. */ /* - * When \FacAccessregisterTransfer is set: + * When {accessregister-transfer} is set: */ #define AC_ACCESS_REGISTER_WRITE_OFFSET 0x10ULL #define AC_ACCESS_REGISTER_WRITE_LENGTH 1ULL #define AC_ACCESS_REGISTER_WRITE 0x10000ULL /* - * arg0: Copy data from the specified register into {\tt arg0} portion - * of {\tt data}. + * arg0: Copy data from the specified register into `arg0` portion + * of `data`. */ #define AC_ACCESS_REGISTER_WRITE_ARG0 0 /* - * register: Copy data from {\tt arg0} portion of {\tt data} into the + * register: Copy data from `arg0` portion of `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 + * xref:tab:regno[]. + * {csr-dpc} may be used as an alias for PC if this command is * supported on a non-halted hart. */ #define AC_ACCESS_REGISTER_REGNO_OFFSET 0ULL @@ -2982,13 +3061,13 @@ #define AC_ACCESS_MEMORY_AAMVIRTUAL_PHYSICAL 0 /* * virtual: Addresses are virtual, and translated the way they would be from - * M-mode, with \FcsrMstatusMprv set. + * M-mode, with `MPRV` 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. + * may optionally allow {accessmemory-aamvirtual} set to 1, which would produce the same result as + * that same abstract command with {accessmemory-aamvirtual} cleared. */ #define AC_ACCESS_MEMORY_AAMSIZE_OFFSET 0x14ULL #define AC_ACCESS_MEMORY_AAMSIZE_LENGTH 3ULL @@ -3015,8 +3094,8 @@ #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. + * `arg1` (which contains the address used) by the number of bytes + * encoded in {accessmemory-aamsize}. * * Supporting this variant is optional, but highly recommended for * performance reasons. @@ -3028,14 +3107,14 @@ #define AC_ACCESS_MEMORY_WRITE_LENGTH 1ULL #define AC_ACCESS_MEMORY_WRITE 0x10000ULL /* - * arg0: Copy data from the memory location specified in {\tt arg1} into - * the low bits of {\tt arg0}. The value of the remaining bits of - * {\tt arg0} are \unspecified. + * arg0: Copy data from the memory location specified in `arg1` into + * the low bits of `arg0`. The value of the remaining bits of + * `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}. + * memory: Copy data from the low bits of `arg0` into the memory + * location specified in `arg1`. */ #define AC_ACCESS_MEMORY_WRITE_MEMORY 1 /* @@ -3047,7 +3126,7 @@ #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}, + * Mode was entered. The encoding is described in <>, * 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. @@ -3057,8 +3136,7 @@ #define VIRT_PRIV_V 4ULL /* * Contains the privilege mode the hart was operating in when Debug - * Mode was entered. The encoding is described in Table - * \ref{tab:privmode}, and matches the privilege mode encoding from + * Mode was entered. The encoding is described in <>, 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. */ @@ -3126,7 +3204,7 @@ enum riscv_debug_reg_ordinal { AC_ACCESS_MEMORY_ORDINAL, VIRT_PRIV_ORDINAL }; -typedef struct { +struct riscv_debug_reg_ctx { struct { unsigned int value; int is_set; } DXLEN; @@ -3136,21 +3214,21 @@ typedef struct { struct { unsigned int value; int is_set; } abits; -} riscv_debug_reg_ctx_t; +}; -typedef struct { +struct riscv_debug_reg_field_info { const char *name; unsigned int lsb; // inclusive unsigned int msb; // inclusive const char **values; // If non-NULL, array of human-readable string for each possible value -} riscv_debug_reg_field_info_t; -typedef struct riscv_debug_reg_field_list_t { - riscv_debug_reg_field_info_t field; - struct riscv_debug_reg_field_list_t (*get_next)(riscv_debug_reg_ctx_t context); -} riscv_debug_reg_field_list_t; -typedef struct { +}; +struct riscv_debug_reg_field_list { + struct riscv_debug_reg_field_info field; + struct riscv_debug_reg_field_list (*get_next)(struct riscv_debug_reg_ctx context); +}; +struct riscv_debug_reg_info { const char *name; - struct riscv_debug_reg_field_list_t (* const get_fields_head)(riscv_debug_reg_ctx_t context); -} riscv_debug_reg_info_t; -riscv_debug_reg_info_t get_riscv_debug_reg_info(enum riscv_debug_reg_ordinal reg_ordinal); + struct riscv_debug_reg_field_list (* const get_fields_head)(struct riscv_debug_reg_ctx context); +}; +struct riscv_debug_reg_info get_riscv_debug_reg_info(enum riscv_debug_reg_ordinal reg_ordinal); #endif diff --git a/src/target/riscv/debug_reg_printer.c b/src/target/riscv/debug_reg_printer.c index fc7dabd265..da4d09f788 100644 --- a/src/target/riscv/debug_reg_printer.c +++ b/src/target/riscv/debug_reg_printer.c @@ -43,7 +43,7 @@ static unsigned int riscv_debug_reg_field_value_to_s(char *buf, unsigned int off } static unsigned int riscv_debug_reg_field_to_s(char *buf, unsigned int offset, - riscv_debug_reg_field_info_t field, riscv_debug_reg_ctx_t context, + struct riscv_debug_reg_field_info field, struct riscv_debug_reg_ctx context, uint64_t field_value) { const unsigned int name_len = get_len_or_sprintf(buf, offset, "%s=", field.name); @@ -52,7 +52,7 @@ static unsigned int riscv_debug_reg_field_to_s(char *buf, unsigned int offset, field.values, field_value); } -static uint64_t riscv_debug_reg_field_value(riscv_debug_reg_field_info_t field, uint64_t value) +static uint64_t riscv_debug_reg_field_value(struct riscv_debug_reg_field_info field, uint64_t value) { assert(field.msb < 64); assert(field.msb >= field.lsb); @@ -61,14 +61,14 @@ static uint64_t riscv_debug_reg_field_value(riscv_debug_reg_field_info_t field, } static unsigned int riscv_debug_reg_fields_to_s(char *buf, unsigned int offset, - struct riscv_debug_reg_field_list_t (*get_next)(riscv_debug_reg_ctx_t contex), - riscv_debug_reg_ctx_t context, uint64_t value, + struct riscv_debug_reg_field_list (*get_next)(struct riscv_debug_reg_ctx contex), + struct riscv_debug_reg_ctx context, uint64_t value, enum riscv_debug_reg_show show) { unsigned int curr = offset; curr += get_len_or_sprintf(buf, curr, " {"); char *separator = ""; - for (struct riscv_debug_reg_field_list_t list; get_next; get_next = list.get_next) { + for (struct riscv_debug_reg_field_list list; get_next; get_next = list.get_next) { list = get_next(context); uint64_t field_value = riscv_debug_reg_field_value(list.field, value); @@ -89,12 +89,12 @@ static unsigned int riscv_debug_reg_fields_to_s(char *buf, unsigned int offset, } unsigned int riscv_debug_reg_to_s(char *buf, enum riscv_debug_reg_ordinal reg_ordinal, - riscv_debug_reg_ctx_t context, uint64_t value, + struct riscv_debug_reg_ctx context, uint64_t value, enum riscv_debug_reg_show show) { unsigned int length = 0; - riscv_debug_reg_info_t reg = get_riscv_debug_reg_info(reg_ordinal); + struct riscv_debug_reg_info reg = get_riscv_debug_reg_info(reg_ordinal); length += get_len_or_sprintf(buf, length, "%s=", reg.name); length += print_number(buf, length, value); diff --git a/src/target/riscv/debug_reg_printer.h b/src/target/riscv/debug_reg_printer.h index 5089ff8fab..7b8b4f1f3b 100644 --- a/src/target/riscv/debug_reg_printer.h +++ b/src/target/riscv/debug_reg_printer.h @@ -27,14 +27,14 @@ enum riscv_debug_reg_show { * (excluding '\0'). * * Example: - * const struct riscv_debug_reg_ctx_t context = { + * const struct struct riscv_debug_reg_ctx context = { * .abits = { .value = , .is_set = true } * }; * char buf[riscv_debug_reg_to_s(NULL, DTM_DMI_ORDINAL, context, ) + 1] * riscv_debug_reg_to_s(buf, DTM_DMI_ORDINAL, context, ); */ unsigned int riscv_debug_reg_to_s(char *buf, enum riscv_debug_reg_ordinal reg_ordinal, - riscv_debug_reg_ctx_t context, uint64_t value, + struct riscv_debug_reg_ctx context, uint64_t value, enum riscv_debug_reg_show show); #endif /* OPENOCD_TARGET_RISCV_DEBUG_REG_PRINTER_H */ diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h index 0d0392912e..79c24367f4 100644 --- a/src/target/riscv/gdb_regs.h +++ b/src/target/riscv/gdb_regs.h @@ -99,6 +99,7 @@ enum gdb_regno { GDB_REGNO_DPC = CSR_DPC + GDB_REGNO_CSR0, GDB_REGNO_DCSR = CSR_DCSR + GDB_REGNO_CSR0, GDB_REGNO_DSCRATCH0 = CSR_DSCRATCH0 + GDB_REGNO_CSR0, + GDB_REGNO_DSCRATCH1 = CSR_DSCRATCH1 + 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, diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index ba44abaf19..d4b9b970b8 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -7,13 +7,13 @@ #define RISCV013_MAX_PROGBUF_SIZE 16 -typedef enum { +enum riscv_progbuf_exec_result { RISCV_PROGBUF_EXEC_RESULT_NOT_EXECUTED, RISCV_PROGBUF_EXEC_RESULT_UNKNOWN, RISCV_PROGBUF_EXEC_RESULT_EXCEPTION, RISCV_PROGBUF_EXEC_RESULT_UNKNOWN_ERROR, RISCV_PROGBUF_EXEC_RESULT_SUCCESS -} riscv_progbuf_exec_result_t; +}; /* The various RISC-V debug specifications all revolve around setting up * program buffers and executing them on the target. This structure contains a @@ -28,7 +28,7 @@ struct riscv_program { /* execution result of the program */ /* TODO: remove this field. We should make it a parameter to riscv_program_exec */ - riscv_progbuf_exec_result_t execution_result; + enum riscv_progbuf_exec_result execution_result; }; /* Initializes a program with the header. */ diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 54de6a10db..717a9cb577 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -7,7 +7,6 @@ #include #include -#include #ifdef HAVE_CONFIG_H #include "config.h" @@ -230,19 +229,25 @@ static unsigned int slot_offset(const struct target *target, slot_t slot) { riscv011_info_t *info = get_info(target); switch (riscv_xlen(target)) { - case 32: - switch (slot) { - case SLOT0: return 4; - case SLOT1: return 5; - case SLOT_LAST: return info->dramsize-1; - } - break; - case 64: - switch (slot) { - case SLOT0: return 4; - case SLOT1: return 6; - case SLOT_LAST: return info->dramsize-2; - } + case 32: + switch (slot) { + case SLOT0: + return 4; + case SLOT1: + return 5; + case SLOT_LAST: + return info->dramsize - 1; + } + break; + case 64: + switch (slot) { + case SLOT0: + return 4; + case SLOT1: + return 6; + case SLOT_LAST: + return info->dramsize - 2; + } } LOG_ERROR("slot_offset called with xlen=%d, slot=%d", riscv_xlen(target), slot); @@ -254,10 +259,10 @@ static uint32_t load(const struct target *target, unsigned int rd, unsigned int base, int16_t offset) { switch (riscv_xlen(target)) { - case 32: - return lw(rd, base, offset); - case 64: - return ld(rd, base, offset); + case 32: + return lw(rd, base, offset); + case 64: + return ld(rd, base, offset); } assert(0); return 0; /* Silence -Werror=return-type */ @@ -267,10 +272,10 @@ static uint32_t store(const struct target *target, unsigned int src, unsigned int base, int16_t offset) { switch (riscv_xlen(target)) { - case 32: - return sw(src, base, offset); - case 64: - return sd(src, base, offset); + case 32: + return sw(src, base, offset); + case 64: + return sd(src, base, offset); } assert(0); return 0; /* Silence -Werror=return-type */ @@ -385,7 +390,7 @@ static void dump_field(const struct scan_field *field) static const char * const op_string[] = {"nop", "r", "w", "?"}; static const char * const status_string[] = {"+", "?", "F", "b"}; - if (debug_level < LOG_LVL_DEBUG) + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits); @@ -641,13 +646,13 @@ static void scans_add_read(scans_t *scans, slot_t slot, bool set_interrupt) { const struct target *target = scans->target; switch (riscv_xlen(target)) { - case 32: - scans_add_read32(scans, slot_offset(target, slot), set_interrupt); - break; - case 64: - scans_add_read32(scans, slot_offset(target, slot), false); - scans_add_read32(scans, slot_offset(target, slot) + 1, set_interrupt); - break; + case 32: + scans_add_read32(scans, slot_offset(target, slot), set_interrupt); + break; + case 64: + scans_add_read32(scans, slot_offset(target, slot), false); + scans_add_read32(scans, slot_offset(target, slot) + 1, set_interrupt); + break; } } @@ -718,7 +723,7 @@ static int read_bits(struct target *target, bits_t *result) static int wait_for_debugint_clear(struct target *target, bool ignore_first) { - time_t start = time(NULL); + int64_t then = timeval_ms() + 1000 * riscv_get_command_timeout_sec(); if (ignore_first) { /* Throw away the results of the first read, since they'll contain the * result of the read that happened just before debugint was set. @@ -736,7 +741,7 @@ static int wait_for_debugint_clear(struct target *target, bool ignore_first) if (!bits.interrupt) return ERROR_OK; - if (time(NULL) - start > riscv_get_command_timeout_sec()) { + if (timeval_ms() > then) { LOG_ERROR("Timed out waiting for debug int to clear." "Increase timeout with riscv set_command_timeout_sec."); return ERROR_FAIL; @@ -906,19 +911,19 @@ static int cache_write(struct target *target, unsigned int address, bool run) dbus_status_t status = scans_get_u32(scans, i, DBUS_OP_START, DBUS_OP_SIZE); switch (status) { - case DBUS_STATUS_SUCCESS: - break; - case DBUS_STATUS_FAILED: - LOG_ERROR("Debug RAM write failed. Hardware error?"); - scans_delete(scans); - return ERROR_FAIL; - case DBUS_STATUS_BUSY: - errors++; - break; - default: - LOG_ERROR("Got invalid bus access status: %d", status); - scans_delete(scans); - return ERROR_FAIL; + case DBUS_STATUS_SUCCESS: + break; + case DBUS_STATUS_FAILED: + LOG_ERROR("Debug RAM write failed. Hardware error?"); + scans_delete(scans); + return ERROR_FAIL; + case DBUS_STATUS_BUSY: + errors++; + break; + default: + LOG_ERROR("Got invalid bus access status: %d", status); + scans_delete(scans); + return ERROR_FAIL; } } @@ -1016,14 +1021,14 @@ static void dram_write_jump(struct target *target, unsigned int index, static int wait_for_state(struct target *target, enum target_state state) { - time_t start = time(NULL); + int64_t then = timeval_ms() + 1000 * riscv_get_command_timeout_sec(); while (1) { int result = riscv011_poll(target); if (result != ERROR_OK) return result; if (target->state == state) return ERROR_OK; - if (time(NULL) - start > riscv_get_command_timeout_sec()) { + if (timeval_ms() > then) { LOG_ERROR("Timed out waiting for state %d. " "Increase timeout with riscv set_command_timeout_sec.", state); return ERROR_FAIL; @@ -1183,14 +1188,14 @@ static int full_step(struct target *target, bool announce) int result = execute_resume(target, true); if (result != ERROR_OK) return result; - time_t start = time(NULL); + int64_t then = timeval_ms() + 1000 * riscv_get_command_timeout_sec(); while (1) { result = poll_target(target, announce); if (result != ERROR_OK) return result; if (target->state != TARGET_DEBUG_RUNNING) break; - if (time(NULL) - start > riscv_get_command_timeout_sec()) { + if (timeval_ms() > then) { LOG_ERROR("Timed out waiting for step to complete." "Increase timeout with riscv set_command_timeout_sec"); return ERROR_FAIL; @@ -1680,17 +1685,17 @@ static riscv_error_t handle_halt_routine(struct target *target) uint32_t address = scans_get_u32(scans, i, DBUS_ADDRESS_START, info->addrbits); switch (status) { - case DBUS_STATUS_SUCCESS: - break; - case DBUS_STATUS_FAILED: - LOG_ERROR("Debug access failed. Hardware error?"); - goto error; - case DBUS_STATUS_BUSY: - dbus_busy++; - break; - default: - LOG_ERROR("Got invalid bus access status: %d", status); - goto error; + case DBUS_STATUS_SUCCESS: + break; + case DBUS_STATUS_FAILED: + LOG_ERROR("Debug access failed. Hardware error?"); + goto error; + case DBUS_STATUS_BUSY: + dbus_busy++; + break; + default: + LOG_ERROR("Got invalid bus access status: %d", status); + goto error; } if (data & DMCONTROL_INTERRUPT) { interrupt_set++; @@ -1699,111 +1704,111 @@ static riscv_error_t handle_halt_routine(struct target *target) if (address == 4 || address == 5) { unsigned int reg; switch (result) { - case 0: - reg = 1; - break; - case 1: - reg = 2; - break; - case 2: - reg = 3; - break; - case 3: - reg = 4; - break; - case 4: - reg = 5; - break; - case 5: - reg = 6; - break; - case 6: - reg = 7; - break; - /* S0 */ - /* S1 */ - case 7: - reg = 10; - break; - case 8: - reg = 11; - break; - case 9: - reg = 12; - break; - case 10: - reg = 13; - break; - case 11: - reg = 14; - break; - case 12: - reg = 15; - break; - case 13: - reg = 16; - break; - case 14: - reg = 17; - break; - case 15: - reg = 18; - break; - case 16: - reg = 19; - break; - case 17: - reg = 20; - break; - case 18: - reg = 21; - break; - case 19: - reg = 22; - break; - case 20: - reg = 23; - break; - case 21: - reg = 24; - break; - case 22: - reg = 25; - break; - case 23: - reg = 26; - break; - case 24: - reg = 27; - break; - case 25: - reg = 28; - break; - case 26: - reg = 29; - break; - case 27: - reg = 30; - break; - case 28: - reg = 31; - break; - case 29: - reg = S1; - break; - case 30: - reg = S0; - break; - case 31: - reg = GDB_REGNO_DPC; - break; - case 32: - reg = GDB_REGNO_DCSR; - break; - default: - assert(0); - LOG_ERROR("Got invalid register result %d", result); - goto error; + case 0: + reg = 1; + break; + case 1: + reg = 2; + break; + case 2: + reg = 3; + break; + case 3: + reg = 4; + break; + case 4: + reg = 5; + break; + case 5: + reg = 6; + break; + case 6: + reg = 7; + break; + /* S0 */ + /* S1 */ + case 7: + reg = 10; + break; + case 8: + reg = 11; + break; + case 9: + reg = 12; + break; + case 10: + reg = 13; + break; + case 11: + reg = 14; + break; + case 12: + reg = 15; + break; + case 13: + reg = 16; + break; + case 14: + reg = 17; + break; + case 15: + reg = 18; + break; + case 16: + reg = 19; + break; + case 17: + reg = 20; + break; + case 18: + reg = 21; + break; + case 19: + reg = 22; + break; + case 20: + reg = 23; + break; + case 21: + reg = 24; + break; + case 22: + reg = 25; + break; + case 23: + reg = 26; + break; + case 24: + reg = 27; + break; + case 25: + reg = 28; + break; + case 26: + reg = 29; + break; + case 27: + reg = 30; + break; + case 28: + reg = 31; + break; + case 29: + reg = S1; + break; + case 30: + reg = S0; + break; + case 31: + reg = GDB_REGNO_DPC; + break; + case 32: + reg = GDB_REGNO_DCSR; + break; + default: + assert(0); + LOG_ERROR("Got invalid register result %d", result); + goto error; } if (riscv_xlen(target) == 32) { reg_cache_set(target, reg, data & 0xffffffff); @@ -1860,22 +1865,22 @@ static int handle_halt(struct target *target, bool announce) int cause = get_field(info->dcsr, DCSR_CAUSE); switch (cause) { - case DCSR_CAUSE_SWBP: - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case DCSR_CAUSE_HWBP: - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case DCSR_CAUSE_DEBUGINT: - target->debug_reason = DBG_REASON_DBGRQ; - break; - case DCSR_CAUSE_STEP: - target->debug_reason = DBG_REASON_SINGLESTEP; - break; - case DCSR_CAUSE_HALT: - default: - LOG_ERROR("Invalid halt cause %d in DCSR (0x%" PRIx64 ")", - cause, info->dcsr); + case DCSR_CAUSE_SWBP: + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case DCSR_CAUSE_HWBP: + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case DCSR_CAUSE_DEBUGINT: + target->debug_reason = DBG_REASON_DBGRQ; + break; + case DCSR_CAUSE_STEP: + target->debug_reason = DBG_REASON_SINGLESTEP; + break; + case DCSR_CAUSE_HALT: + default: + LOG_ERROR("Invalid halt cause %d in DCSR (0x%" PRIx64 ")", + cause, info->dcsr); } if (info->never_halted) { @@ -1925,11 +1930,6 @@ static int poll_target(struct target *target, bool announce) { jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); - /* Inhibit debug logging during poll(), which isn't usually interesting and - * just fills up the screen/logs with clutter. */ - int old_debug_level = debug_level; - if (debug_level >= LOG_LVL_DEBUG) - debug_level = LOG_LVL_INFO; bits_t bits = { .haltnot = 0, .interrupt = 0 @@ -1937,8 +1937,6 @@ static int poll_target(struct target *target, bool announce) if (read_bits(target, &bits) != ERROR_OK) return ERROR_FAIL; - debug_level = old_debug_level; - if (bits.haltnot && bits.interrupt) { target->state = TARGET_DEBUG_RUNNING; LOG_DEBUG("debug running"); @@ -2013,7 +2011,7 @@ static int deassert_reset(struct target *target) return wait_for_state(target, TARGET_RUNNING); } -static int read_memory(struct target *target, const riscv_mem_access_args_t args) +static int read_memory(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_read(args)); @@ -2032,21 +2030,21 @@ static int read_memory(struct target *target, const riscv_mem_access_args_t args cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16)); switch (size) { - case 1: - cache_set32(target, 1, lb(S1, S0, 0)); - cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); - break; - case 2: - cache_set32(target, 1, lh(S1, S0, 0)); - cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); - break; - case 4: - cache_set32(target, 1, lw(S1, S0, 0)); - cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); - break; - default: - LOG_ERROR("Unsupported size: %d", size); - return ERROR_FAIL; + case 1: + cache_set32(target, 1, lb(S1, S0, 0)); + cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); + break; + case 2: + cache_set32(target, 1, lh(S1, S0, 0)); + cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); + break; + case 4: + cache_set32(target, 1, lw(S1, S0, 0)); + cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START + 16)); + break; + default: + LOG_ERROR("Unsupported size: %d", size); + return ERROR_FAIL; } cache_set_jump(target, 3); cache_write(target, CACHE_NO_READ, false); @@ -2089,17 +2087,17 @@ static int read_memory(struct target *target, const riscv_mem_access_args_t args dbus_status_t status = scans_get_u32(scans, j, DBUS_OP_START, DBUS_OP_SIZE); switch (status) { - case DBUS_STATUS_SUCCESS: - break; - case DBUS_STATUS_FAILED: - LOG_ERROR("Debug RAM write failed. Hardware error?"); - goto error; - case DBUS_STATUS_BUSY: - dbus_busy++; - break; - default: - LOG_ERROR("Got invalid bus access status: %d", status); - return ERROR_FAIL; + case DBUS_STATUS_SUCCESS: + break; + case DBUS_STATUS_FAILED: + LOG_ERROR("Debug RAM write failed. Hardware error?"); + goto error; + case DBUS_STATUS_BUSY: + dbus_busy++; + break; + default: + LOG_ERROR("Got invalid bus access status: %d", status); + return ERROR_FAIL; } uint64_t data = scans_get_u64(scans, j, DBUS_DATA_START, DBUS_DATA_SIZE); @@ -2110,19 +2108,19 @@ static int read_memory(struct target *target, const riscv_mem_access_args_t args } else if (i + j > 1) { uint32_t offset = size * (i + j - 2); switch (size) { - case 1: - buffer[offset] = data; - break; - case 2: - buffer[offset] = data; - buffer[offset+1] = data >> 8; - break; - case 4: - buffer[offset] = data; - buffer[offset+1] = data >> 8; - buffer[offset+2] = data >> 16; - buffer[offset+3] = data >> 24; - break; + case 1: + buffer[offset] = data; + break; + case 2: + buffer[offset] = data; + buffer[offset + 1] = data >> 8; + break; + case 4: + buffer[offset] = data; + buffer[offset + 1] = data >> 8; + buffer[offset + 2] = data >> 16; + buffer[offset + 3] = data >> 24; + break; } } LOG_DEBUG("j=%d status=%d data=%09" PRIx64, j, status, data); @@ -2167,21 +2165,21 @@ static int read_memory(struct target *target, const riscv_mem_access_args_t args static int setup_write_memory(struct target *target, uint32_t size) { switch (size) { - case 1: - cache_set32(target, 0, lb(S0, ZERO, DEBUG_RAM_START + 16)); - cache_set32(target, 1, sb(S0, T0, 0)); - break; - case 2: - cache_set32(target, 0, lh(S0, ZERO, DEBUG_RAM_START + 16)); - cache_set32(target, 1, sh(S0, T0, 0)); - break; - case 4: - cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16)); - cache_set32(target, 1, sw(S0, T0, 0)); - break; - default: - LOG_ERROR("Unsupported size: %d", size); - return ERROR_FAIL; + case 1: + cache_set32(target, 0, lb(S0, ZERO, DEBUG_RAM_START + 16)); + cache_set32(target, 1, sb(S0, T0, 0)); + break; + case 2: + cache_set32(target, 0, lh(S0, ZERO, DEBUG_RAM_START + 16)); + cache_set32(target, 1, sh(S0, T0, 0)); + break; + case 4: + cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16)); + cache_set32(target, 1, sw(S0, T0, 0)); + break; + default: + LOG_ERROR("Unsupported size: %d", size); + return ERROR_FAIL; } cache_set32(target, 2, addi(T0, T0, size)); cache_set_jump(target, 3); @@ -2190,7 +2188,7 @@ static int setup_write_memory(struct target *target, uint32_t size) return ERROR_OK; } -static int write_memory(struct target *target, const riscv_mem_access_args_t args) +static int write_memory(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_write(args)); @@ -2241,21 +2239,21 @@ static int write_memory(struct target *target, const riscv_mem_access_args_t arg uint32_t value; uint32_t offset = size * (i + j); switch (size) { - case 1: - value = buffer[offset]; - break; - case 2: - value = buffer[offset] | - (buffer[offset+1] << 8); - break; - case 4: - value = buffer[offset] | - ((uint32_t) buffer[offset+1] << 8) | - ((uint32_t) buffer[offset+2] << 16) | - ((uint32_t) buffer[offset+3] << 24); - break; - default: - goto error; + case 1: + value = buffer[offset]; + break; + case 2: + value = buffer[offset] | + (buffer[offset + 1] << 8); + break; + case 4: + value = buffer[offset] | + ((uint32_t)buffer[offset + 1] << 8) | + ((uint32_t)buffer[offset + 2] << 16) | + ((uint32_t)buffer[offset + 3] << 24); + break; + default: + goto error; } scans_add_write32(scans, 4, value, true); @@ -2274,17 +2272,17 @@ static int write_memory(struct target *target, const riscv_mem_access_args_t arg dbus_status_t status = scans_get_u32(scans, j, DBUS_OP_START, DBUS_OP_SIZE); switch (status) { - case DBUS_STATUS_SUCCESS: - break; - case DBUS_STATUS_FAILED: - LOG_ERROR("Debug RAM write failed. Hardware error?"); - goto error; - case DBUS_STATUS_BUSY: - dbus_busy++; - break; - default: - LOG_ERROR("Got invalid bus access status: %d", status); - return ERROR_FAIL; + case DBUS_STATUS_SUCCESS: + break; + case DBUS_STATUS_FAILED: + LOG_ERROR("Debug RAM write failed. Hardware error?"); + goto error; + case DBUS_STATUS_BUSY: + dbus_busy++; + break; + default: + LOG_ERROR("Got invalid bus access status: %d", status); + return ERROR_FAIL; } int interrupt = scans_get_u32(scans, j, DBUS_DATA_START + 33, 1); if (interrupt) @@ -2339,7 +2337,7 @@ static int write_memory(struct target *target, const riscv_mem_access_args_t arg return ERROR_FAIL; } -static int access_memory(struct target *target, const riscv_mem_access_args_t args) +static int access_memory(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_valid(args)); const bool is_write = riscv_mem_access_is_write(args); @@ -2348,11 +2346,6 @@ static int access_memory(struct target *target, const riscv_mem_access_args_t ar return read_memory(target, args); } -static int arch_state(struct target *target) -{ - return ERROR_OK; -} - static COMMAND_HELPER(riscv011_print_info, struct target *target) { /* Abstract description. */ @@ -2375,12 +2368,12 @@ static COMMAND_HELPER(riscv011_print_info, struct target *target) static int wait_for_authbusy(struct target *target) { - time_t start = time(NULL); + int64_t then = timeval_ms() + 1000 * riscv_get_command_timeout_sec(); while (1) { uint32_t dminfo = dbus_read(target, DMINFO); if (!get_field(dminfo, DMINFO_AUTHBUSY)) break; - if (time(NULL) - start > riscv_get_command_timeout_sec()) { + if (timeval_ms() > then) { 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_get_command_timeout_sec(), @@ -2473,6 +2466,4 @@ struct target_type riscv011_target = { .assert_reset = assert_reset, .deassert_reset = deassert_reset, - - .arch_state = arch_state, }; diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 1170d663a8..a72c6270b5 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -8,7 +8,6 @@ #include #include #include -#include #ifdef HAVE_CONFIG_H #include "config.h" @@ -64,16 +63,16 @@ static int register_read_direct(struct target *target, riscv_reg_t *value, enum gdb_regno number); static int register_write_direct(struct target *target, enum gdb_regno number, riscv_reg_t value); -static int riscv013_access_memory(struct target *target, const riscv_mem_access_args_t args); +static int riscv013_access_memory(struct target *target, const struct riscv_mem_access_args args); static bool riscv013_get_impebreak(const struct target *target); static unsigned int riscv013_get_progbufsize(const struct target *target); -typedef enum { +enum grouptype { HALT_GROUP, RESUME_GROUP -} grouptype_t; +}; static int set_group(struct target *target, bool *supported, unsigned int group, - grouptype_t grouptype); + enum grouptype grouptype); /** * Since almost everything can be accomplish by scanning the dbus register, all @@ -222,7 +221,7 @@ typedef struct { /* We cache the read-only bits of sbcs here. */ uint32_t sbcs; - yes_no_maybe_t progbuf_writable; + enum yes_no_maybe progbuf_writable; /* We only need the address so that we know the alignment of the buffer. */ riscv_addr_t progbuf_address; @@ -351,15 +350,15 @@ static void riscv013_dm_free(struct target *target) info->dm = NULL; } -static riscv_debug_reg_ctx_t get_riscv_debug_reg_ctx(const struct target *target) +static struct riscv_debug_reg_ctx get_riscv_debug_reg_ctx(const struct target *target) { if (!target_was_examined(target)) { - const riscv_debug_reg_ctx_t default_context = {0}; + const struct riscv_debug_reg_ctx default_context = {0}; return default_context; } RISCV013_INFO(info); - const riscv_debug_reg_ctx_t context = { + const struct riscv_debug_reg_ctx context = { .XLEN = { .value = riscv_xlen(target), .is_set = true }, .DXLEN = { .value = riscv_xlen(target), .is_set = true }, .abits = { .value = info->abits, .is_set = true }, @@ -370,9 +369,9 @@ static riscv_debug_reg_ctx_t get_riscv_debug_reg_ctx(const struct target *target static void log_debug_reg(struct target *target, enum riscv_debug_reg_ordinal reg, riscv_reg_t value, const char *file, unsigned int line, const char *func) { - if (debug_level < LOG_LVL_DEBUG) + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; - const riscv_debug_reg_ctx_t context = get_riscv_debug_reg_ctx(target); + const struct riscv_debug_reg_ctx context = get_riscv_debug_reg_ctx(target); char * const buf = malloc(riscv_debug_reg_to_s(NULL, reg, context, value, RISCV_DEBUG_REG_HIDE_UNNAMED_0) + 1); if (!buf) { LOG_ERROR("Unable to allocate memory."); @@ -449,9 +448,7 @@ static int increase_dmi_busy_delay(struct target *target) if (res != ERROR_OK) return res; - res = riscv_scan_increase_delay(&info->learned_delays, - RISCV_DELAY_BASE); - return res; + return riscv_scan_increase_delay(&info->learned_delays, RISCV_DELAY_BASE); } static void reset_learned_delays(struct target *target) @@ -536,7 +533,32 @@ static int dm_write(struct target *target, uint32_t address, uint32_t value) return dmi_write(target, riscv013_get_dmi_address(target, address), value); } -static bool check_dbgbase_exists(struct target *target) +static int activate_dm(struct target *target, uint32_t dm_base_addr) +{ + LOG_TARGET_DEBUG(target, "Activating the DM with DMI base address (dbgbase) = 0x%x", dm_base_addr); + if (dmi_write(target, DM_DMCONTROL + dm_base_addr, DM_DMCONTROL_DMACTIVE) != ERROR_OK) + return ERROR_FAIL; + + int64_t then = timeval_ms() + 1000 * riscv_get_command_timeout_sec(); + LOG_TARGET_DEBUG(target, "Waiting for the DM to become active"); + while (1) { + uint32_t dmcontrol; + if (dmi_read(target, &dmcontrol, DM_DMCONTROL + dm_base_addr) != ERROR_OK) + return ERROR_FAIL; + if (get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE)) + break; + if (timeval_ms() > then) { + LOG_TARGET_ERROR(target, "Debug Module (at address dbgbase=0x%" PRIx32 ") did not become active in %d s. " + "Increase the timeout with 'riscv set_command_timeout_sec'", + dm_base_addr, riscv_get_command_timeout_sec()); + return ERROR_TIMEOUT_REACHED; + } + } + LOG_TARGET_DEBUG(target, "DM has become active"); + return ERROR_OK; +} + +static int check_dbgbase_exists(struct target *target) { uint32_t next_dm = 0; unsigned int count = 1; @@ -546,7 +568,14 @@ static bool check_dbgbase_exists(struct target *target) while (1) { uint32_t current_dm = next_dm; if (current_dm == target->dbgbase) - return true; + return ERROR_OK; + + uint32_t dmcontrol; + if (dmi_read(target, &dmcontrol, DM_DMCONTROL + current_dm) != ERROR_OK) + break; + if (!get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE) && activate_dm(target, current_dm) != ERROR_OK) + break; + if (dmi_read(target, &next_dm, DM_NEXTDM + current_dm) != ERROR_OK) break; LOG_TARGET_DEBUG(target, "dm @ 0x%x --> nextdm=0x%x", current_dm, next_dm); @@ -567,7 +596,7 @@ static bool check_dbgbase_exists(struct target *target) break; } } - return false; + return ERROR_FAIL; } static int dmstatus_read(struct target *target, uint32_t *dmstatus, @@ -602,15 +631,15 @@ static int increase_ac_busy_delay(struct target *target) static uint32_t __attribute__((unused)) abstract_register_size(unsigned int width) { switch (width) { - case 32: - return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 2); - case 64: - return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 3); - case 128: - return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 4); - default: - LOG_ERROR("Unsupported register width: %d", width); - return 0; + case 32: + return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 2); + case 64: + return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 3); + case 128: + return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 4); + default: + LOG_ERROR("Unsupported register width: %d", width); + return 0; } } @@ -627,7 +656,7 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) return ERROR_FAIL; } - time_t start = time(NULL); + int64_t then = timeval_ms() + 1000 * riscv_get_command_timeout_sec(); do { if (dm_read(target, abstractcs, DM_ABSTRACTCS) != ERROR_OK) { /* We couldn't read abstractcs. For safety, overwrite the output value to @@ -642,7 +671,7 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) dm->abstract_cmd_maybe_busy = false; return ERROR_OK; } - } while ((time(NULL) - start) < riscv_get_command_timeout_sec()); + } while (timeval_ms() < then); LOG_TARGET_ERROR(target, "Timed out after %ds waiting for busy to go low (abstractcs=0x%" PRIx32 "). " @@ -745,14 +774,14 @@ int riscv013_execute_abstract_command(struct target *target, uint32_t command, { assert(cmderr); *cmderr = CMDERR_NONE; - if (debug_level >= LOG_LVL_DEBUG) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { switch (get_field(command, DM_COMMAND_CMDTYPE)) { - case 0: - LOG_DEBUG_REG(target, AC_ACCESS_REGISTER, command); - break; - default: - LOG_TARGET_DEBUG(target, "command=0x%x", command); - break; + case 0: + LOG_DEBUG_REG(target, AC_ACCESS_REGISTER, command); + break; + default: + LOG_TARGET_DEBUG(target, "command=0x%x", command); + break; } } @@ -864,14 +893,14 @@ static int write_abstract_arg(struct target *target, unsigned int index, { unsigned int offset = index * size_bits / 32; switch (size_bits) { - default: - LOG_TARGET_ERROR(target, "Unsupported size: %d bits", size_bits); - return ERROR_FAIL; - case 64: - dm_write(target, DM_DATA0 + offset + 1, (uint32_t)(value >> 32)); - /* falls through */ - case 32: - dm_write(target, DM_DATA0 + offset, (uint32_t)value); + default: + LOG_TARGET_ERROR(target, "Unsupported size: %d bits", size_bits); + return ERROR_FAIL; + case 64: + dm_write(target, DM_DATA0 + offset + 1, (uint32_t)(value >> 32)); + /* falls through */ + case 32: + dm_write(target, DM_DATA0 + offset, (uint32_t)value); } return ERROR_OK; } @@ -884,16 +913,16 @@ uint32_t riscv013_access_register_command(struct target *target, uint32_t number { uint32_t command = set_field(0, DM_COMMAND_CMDTYPE, 0); switch (size) { - case 32: - command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 2); - break; - case 64: - command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 3); - break; - default: - LOG_TARGET_ERROR(target, "%d-bit register %s not supported.", - size, riscv_reg_gdb_regno_name(target, number)); - assert(0); + case 32: + command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 2); + break; + case 64: + command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 3); + break; + default: + LOG_TARGET_ERROR(target, "%d-bit register %s not supported.", + size, riscv_reg_gdb_regno_name(target, number)); + assert(0); } if (number <= GDB_REGNO_XPR31) { @@ -1013,19 +1042,19 @@ static int register_write_abstract(struct target *target, enum gdb_regno number, static uint32_t abstract_memory_size(unsigned int 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; + 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; } } @@ -1260,38 +1289,38 @@ static int scratch_read64(struct target *target, scratch_mem_t *scratch, { uint32_t v; switch (scratch->memory_space) { - case SPACE_DM_DATA: - if (dm_read(target, &v, DM_DATA0 + scratch->debug_address) != ERROR_OK) - return ERROR_FAIL; - *value = v; - if (dm_read(target, &v, DM_DATA1 + scratch->debug_address) != ERROR_OK) - return ERROR_FAIL; - *value |= ((uint64_t) v) << 32; - break; - case SPACE_DMI_PROGBUF: - if (dm_read(target, &v, DM_PROGBUF0 + scratch->debug_address) != ERROR_OK) - return ERROR_FAIL; - *value = v; - if (dm_read(target, &v, DM_PROGBUF1 + scratch->debug_address) != ERROR_OK) + case SPACE_DM_DATA: + if (dm_read(target, &v, DM_DATA0 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value = v; + if (dm_read(target, &v, DM_DATA1 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value |= ((uint64_t)v) << 32; + break; + case SPACE_DMI_PROGBUF: + if (dm_read(target, &v, DM_PROGBUF0 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value = v; + if (dm_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] = {0}; + const struct riscv_mem_access_args args = { + .address = scratch->debug_address, + .read_buffer = buffer, + .size = 4, + .count = 2, + .increment = 4, + }; + if (riscv013_access_memory(target, args) != ERROR_OK) return ERROR_FAIL; - *value |= ((uint64_t) v) << 32; - break; - case SPACE_DMI_RAM: - { - uint8_t buffer[8] = {0}; - const riscv_mem_access_args_t args = { - .address = scratch->debug_address, - .read_buffer = buffer, - .size = 4, - .count = 2, - .increment = 4, - }; - if (riscv013_access_memory(target, args) != ERROR_OK) - return ERROR_FAIL; - *value = buf_get_u64(buffer, - /* first = */ 0, /* bit_num = */ 64); - } - break; + *value = buf_get_u64(buffer, + /* first = */ 0, /* bit_num = */ 64); + } + break; } return ERROR_OK; } @@ -1300,38 +1329,38 @@ static int scratch_write64(struct target *target, scratch_mem_t *scratch, uint64_t value) { switch (scratch->memory_space) { - case SPACE_DM_DATA: - dm_write(target, DM_DATA0 + scratch->debug_address, (uint32_t)value); - dm_write(target, DM_DATA1 + scratch->debug_address, (uint32_t)(value >> 32)); - break; - case SPACE_DMI_PROGBUF: - dm_write(target, DM_PROGBUF0 + scratch->debug_address, (uint32_t)value); - dm_write(target, DM_PROGBUF1 + scratch->debug_address, (uint32_t)(value >> 32)); - riscv013_invalidate_cached_progbuf(target); - break; - case SPACE_DMI_RAM: - { - uint8_t buffer[8] = { - value, - value >> 8, - value >> 16, - value >> 24, - value >> 32, - value >> 40, - value >> 48, - value >> 56 - }; - const riscv_mem_access_args_t args = { - .address = scratch->debug_address, - .write_buffer = buffer, - .size = 4, - .count = 2, - .increment = 4, - }; - if (riscv013_access_memory(target, args) != ERROR_OK) - return ERROR_FAIL; - } - break; + case SPACE_DM_DATA: + dm_write(target, DM_DATA0 + scratch->debug_address, (uint32_t)value); + dm_write(target, DM_DATA1 + scratch->debug_address, (uint32_t)(value >> 32)); + break; + case SPACE_DMI_PROGBUF: + dm_write(target, DM_PROGBUF0 + scratch->debug_address, (uint32_t)value); + dm_write(target, DM_PROGBUF1 + scratch->debug_address, (uint32_t)(value >> 32)); + riscv013_invalidate_cached_progbuf(target); + break; + case SPACE_DMI_RAM: + { + uint8_t buffer[8] = { + value, + value >> 8, + value >> 16, + value >> 24, + value >> 32, + value >> 40, + value >> 48, + value >> 56 + }; + const struct riscv_mem_access_args args = { + .address = scratch->debug_address, + .write_buffer = buffer, + .size = 4, + .count = 2, + .increment = 4, + }; + if (riscv013_access_memory(target, args) != ERROR_OK) + return ERROR_FAIL; + } + break; } return ERROR_OK; } @@ -1443,13 +1472,31 @@ static int register_read_progbuf(struct target *target, uint64_t *value, { assert(target->state == TARGET_HALTED); - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) - return fpr_read_progbuf(target, value, number); - else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) - return csr_read_progbuf(target, value, number); + int res; + uint64_t new_value; + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + res = fpr_read_progbuf(target, &new_value, number); + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + res = csr_read_progbuf(target, &new_value, number); + } else { + LOG_TARGET_ERROR(target, "Unexpected read of %s via program buffer.", + riscv_reg_gdb_regno_name(target, number)); + return ERROR_FAIL; + } + if (res != ERROR_OK) + return res; - LOG_TARGET_ERROR(target, "Unexpected read of %s via program buffer.", - riscv_reg_gdb_regno_name(target, number)); + unsigned int size_bits = register_size(target, number); + unsigned int value_bits = sizeof(*value) * CHAR_BIT; + assert(size_bits <= value_bits); + if (size_bits == value_bits || new_value >> size_bits == 0) { + *value = new_value; + return ERROR_OK; + } + LOG_TARGET_ERROR(target, "Value 0x%" PRIx64 " read from register %s" + " exceeds the size of the register (%u bits). This is a HW bug." + " Discarding the value", new_value, + riscv_reg_gdb_regno_name(target, number), size_bits); return ERROR_FAIL; } @@ -1662,7 +1709,7 @@ static int register_read_direct(struct target *target, riscv_reg_t *value, static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) { - time_t start = time(NULL); + int64_t then = timeval_ms() + 1000 * riscv_get_command_timeout_sec(); while (1) { uint32_t value; if (dmstatus_read(target, &value, false) != ERROR_OK) @@ -1671,7 +1718,7 @@ static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) *dmstatus = value; if (!get_field(value, DM_DMSTATUS_AUTHBUSY)) break; - if (time(NULL) - start > riscv_get_command_timeout_sec()) { + if (timeval_ms() > then) { LOG_TARGET_ERROR(target, "Timed out after %ds waiting for authbusy to go low (dmstatus=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", riscv_get_command_timeout_sec(), @@ -1794,7 +1841,7 @@ static void deinit_target(struct target *target) } static int set_group(struct target *target, bool *supported, unsigned int group, - grouptype_t grouptype) + enum grouptype grouptype) { uint32_t write_val = DM_DMCS2_HGWRITE; assert(group <= 31); @@ -1861,14 +1908,14 @@ static int reset_dm(struct target *target) if (result != ERROR_OK) return result; - const time_t start = time(NULL); + int64_t then = timeval_ms() + 1000 * riscv_get_command_timeout_sec(); LOG_TARGET_DEBUG(target, "Waiting for the DM to acknowledge reset."); do { result = dm_read(target, &dmcontrol, DM_DMCONTROL); if (result != ERROR_OK) return result; - if (time(NULL) - start > riscv_get_command_timeout_sec()) { + if (timeval_ms() > then) { LOG_TARGET_ERROR(target, "DM didn't acknowledge reset in %d s. " "Increase the timeout with 'riscv set_command_timeout_sec'.", riscv_get_command_timeout_sec()); @@ -1877,27 +1924,13 @@ static int reset_dm(struct target *target) } while (get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE)); LOG_TARGET_DEBUG(target, "DM reset initiated."); } + /* TODO: Move the code above into `deactivate_dm()` function + * (a logical counterpart to activate_dm()). */ - LOG_TARGET_DEBUG(target, "Activating the DM."); - result = dm_write(target, DM_DMCONTROL, DM_DMCONTROL_DMACTIVE); + result = activate_dm(target, dm->base); if (result != ERROR_OK) return result; - const time_t start = time(NULL); - LOG_TARGET_DEBUG(target, "Waiting for the DM to come out of reset."); - do { - result = dm_read(target, &dmcontrol, DM_DMCONTROL); - if (result != ERROR_OK) - return result; - - if (time(NULL) - start > riscv_get_command_timeout_sec()) { - LOG_TARGET_ERROR(target, "Debug Module did not become active in %d s. " - "Increase the timeout with 'riscv set_command_timeout_sec'.", - riscv_get_command_timeout_sec()); - return ERROR_TIMEOUT_REACHED; - } - } while (!get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE)); - LOG_TARGET_DEBUG(target, "DM successfully reset."); dm->was_reset = true; return ERROR_OK; @@ -2052,7 +2085,7 @@ static int examine(struct target *target) info->abits, RISCV013_DTMCS_ABITS_MIN); } - if (!check_dbgbase_exists(target)) { + if (check_dbgbase_exists(target) != ERROR_OK) { LOG_TARGET_ERROR(target, "Could not find debug module with DMI base address (dbgbase) = 0x%x", target->dbgbase); return ERROR_FAIL; } @@ -2118,6 +2151,12 @@ static int examine(struct target *target) if (riscv_get_hart_state(target, &state_at_examine_start) != ERROR_OK) return ERROR_FAIL; + if (state_at_examine_start == RISCV_STATE_UNAVAILABLE) { + target->state = TARGET_UNAVAILABLE; + LOG_TARGET_INFO(target, "unavailable."); + return ERROR_FAIL; + } + RISCV_INFO(r); const bool hart_halted_at_examine_start = state_at_examine_start == RISCV_STATE_HALTED; if (!hart_halted_at_examine_start) { @@ -2221,7 +2260,7 @@ static unsigned int riscv013_data_bits(struct target *target) RISCV_INFO(r); for (unsigned int i = 0; i < r->num_enabled_mem_access_methods; i++) { - riscv_mem_access_method_t method = r->mem_access_methods[i]; + enum riscv_mem_access_method method = r->mem_access_methods[i]; if (method == RISCV_MEM_ACCESS_PROGBUF) { if (has_sufficient_progbuf(target, 3)) @@ -2327,7 +2366,7 @@ static int prep_for_vector_access(struct target *target, if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "Unable to access vector register: target not halted"); - return ERROR_FAIL; + return ERROR_TARGET_NOT_HALTED; } if (prep_for_register_access(target, orig_mstatus, GDB_REGNO_VL) != ERROR_OK) return ERROR_FAIL; @@ -2460,16 +2499,16 @@ int riscv013_set_register_buf(struct target *target, enum gdb_regno regno, 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); + 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; @@ -2544,7 +2583,7 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch) riscv_batch_add_nop(batch); size_t finished_scans = 0; - const time_t start = time(NULL); + int64_t then = timeval_ms() + 1000 * riscv_get_command_timeout_sec(); const unsigned int old_base_delay = riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_BASE); int result; @@ -2567,7 +2606,7 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch) result = increase_dmi_busy_delay(target); if (result != ERROR_OK) return result; - } while (time(NULL) - start < riscv_get_command_timeout_sec()); + } while (timeval_ms() < then); assert(result == ERROR_OK); assert(riscv_batch_was_batch_busy(batch)); @@ -2590,18 +2629,18 @@ 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; + 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; } } @@ -2987,14 +3026,14 @@ static int deassert_reset(struct target *target) uint32_t dmstatus; const unsigned int orig_base_delay = riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_BASE); - time_t start = time(NULL); + int64_t then = timeval_ms() + 1000 * riscv_get_command_timeout_sec(); LOG_TARGET_DEBUG(target, "Waiting for hart to come out of reset."); do { result = dmstatus_read(target, &dmstatus, true); if (result != ERROR_OK) return result; - if (time(NULL) - start > riscv_get_command_timeout_sec()) { + if (timeval_ms() > then) { LOG_TARGET_ERROR(target, "Hart didn't leave reset in %ds; " "dmstatus=0x%x (allunavail=%s, allhavereset=%s); " "Increase the timeout with riscv set_command_timeout_sec.", @@ -3003,15 +3042,7 @@ static int deassert_reset(struct target *target) get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET) ? "true" : "false"); return ERROR_TIMEOUT_REACHED; } - /* Certain debug modules, like the one in GD32VF103 - * MCUs, violate the specification's requirement that - * each hart is in "exactly one of four states" and, - * during reset, report harts as both unavailable and - * halted/running. To work around this, we check for - * the absence of the unavailable state rather than - * the presence of any other state. */ - } while (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) && - !get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)); + } while (!get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)); riscv_scan_set_delay(&info->learned_delays, RISCV_DELAY_BASE, orig_base_delay); @@ -3103,7 +3134,7 @@ static int execute_autofence(struct target *target) static void log_memory_access128(target_addr_t address, uint64_t value_h, uint64_t value_l, bool is_read) { - if (debug_level < LOG_LVL_DEBUG) + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; char fmt[80]; @@ -3115,26 +3146,26 @@ static void log_memory_access128(target_addr_t address, uint64_t value_h, static void log_memory_access64(target_addr_t address, uint64_t value, unsigned int size_bytes, bool is_read) { - if (debug_level < LOG_LVL_DEBUG) + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; char fmt[80]; sprintf(fmt, "M[0x%" TARGET_PRIxADDR "] %ss 0x%%0%d" PRIx64, address, is_read ? "read" : "write", size_bytes * 2); switch (size_bytes) { - case 1: - value &= 0xff; - break; - case 2: - value &= 0xffff; - break; - case 4: - value &= 0xffffffffUL; - break; - case 8: - break; - default: - assert(false); + 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); } @@ -3188,13 +3219,13 @@ static target_addr_t sb_read_address(struct target *target) static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) { - time_t start = time(NULL); + int64_t then = timeval_ms() + 1000 * riscv_get_command_timeout_sec(); while (1) { if (dm_read(target, sbcs, DM_SBCS) != ERROR_OK) return ERROR_FAIL; if (!get_field(*sbcs, DM_SBCS_SBBUSY)) return ERROR_OK; - if (time(NULL) - start > riscv_get_command_timeout_sec()) { + if (timeval_ms() > then) { LOG_TARGET_ERROR(target, "Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", riscv_get_command_timeout_sec(), *sbcs); @@ -3269,7 +3300,7 @@ static int restore_privilege_from_virt2phys_mode(struct target *target, riscv_re return ERROR_OK; } -static int read_memory_bus_v0(struct target *target, const riscv_mem_access_args_t args) +static int read_memory_bus_v0(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_read(args)); @@ -3359,7 +3390,7 @@ static int read_memory_bus_v0(struct target *target, const riscv_mem_access_args /** * Read the requested memory using the system bus interface. */ -static int read_memory_bus_v1(struct target *target, const riscv_mem_access_args_t args) +static int read_memory_bus_v1(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_read(args)); @@ -3505,7 +3536,8 @@ static int read_memory_bus_v1(struct target *target, const riscv_mem_access_args return ERROR_OK; } -static void log_mem_access_result(struct target *target, bool success, riscv_mem_access_method_t method, bool is_read) +static void log_mem_access_result(struct target *target, bool success, + enum riscv_mem_access_method method, bool is_read) { RISCV_INFO(r); bool warn = false; @@ -3676,7 +3708,7 @@ static struct mem_access_result mem_access_result(enum mem_access_result_enum va } static struct mem_access_result mem_should_skip_progbuf(struct target *target, - const riscv_mem_access_args_t args) + const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_valid(args)); const char *const access_type = @@ -3719,7 +3751,7 @@ static struct mem_access_result mem_should_skip_progbuf(struct target *target, } static struct mem_access_result -mem_should_skip_sysbus(struct target *target, const riscv_mem_access_args_t args) +mem_should_skip_sysbus(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_valid(args)); @@ -3752,7 +3784,7 @@ mem_should_skip_sysbus(struct target *target, const riscv_mem_access_args_t args } static struct mem_access_result -mem_should_skip_abstract(struct target *target, const riscv_mem_access_args_t args) +mem_should_skip_abstract(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_valid(args)); @@ -3787,7 +3819,7 @@ mem_should_skip_abstract(struct target *target, const riscv_mem_access_args_t ar * aamsize fields in the memory access abstract command. */ static struct mem_access_result -read_memory_abstract(struct target *target, const riscv_mem_access_args_t args) +read_memory_abstract(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_read(args)); @@ -3864,7 +3896,7 @@ read_memory_abstract(struct target *target, const riscv_mem_access_args_t args) * byte aamsize fields in the memory access abstract command. */ static struct mem_access_result -write_memory_abstract(struct target *target, const riscv_mem_access_args_t args) +write_memory_abstract(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_write(args)); @@ -4015,7 +4047,7 @@ static int read_memory_progbuf_inner_startup(struct target *target, */ static int read_memory_progbuf_inner_on_ac_busy(struct target *target, uint32_t start_index, uint32_t *elements_read, - const riscv_mem_access_args_t args) + const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_read(args)); @@ -4074,7 +4106,7 @@ static int read_memory_progbuf_inner_on_ac_busy(struct target *target, */ static int read_memory_progbuf_inner_on_dmi_busy(struct target *target, uint32_t start_index, uint32_t next_start_index, - const riscv_mem_access_args_t args) + const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_read(args)); @@ -4095,7 +4127,7 @@ static int read_memory_progbuf_inner_on_dmi_busy(struct target *target, static int read_memory_progbuf_inner_extract_batch_data(struct target *target, const struct riscv_batch *batch, uint32_t start_index, uint32_t elements_to_read, uint32_t *elements_read, - const riscv_mem_access_args_t args) + const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_read(args)); @@ -4152,7 +4184,7 @@ static int read_memory_progbuf_inner_extract_batch_data(struct target *target, * - DM_ABSTRACTAUTO_AUTOEXECDATA is set. */ static int read_memory_progbuf_inner_run_and_process_batch(struct target *target, - struct riscv_batch *batch, const riscv_mem_access_args_t args, + struct riscv_batch *batch, const struct riscv_mem_access_args args, uint32_t start_index, uint32_t elements_to_read, uint32_t *elements_read) { assert(riscv_mem_access_is_read(args)); @@ -4223,7 +4255,7 @@ static uint32_t read_memory_progbuf_inner_fill_batch(struct riscv_batch *batch, } static int read_memory_progbuf_inner_try_to_read(struct target *target, - const riscv_mem_access_args_t args, uint32_t *elements_read, + const struct riscv_mem_access_args args, uint32_t *elements_read, uint32_t index, uint32_t loop_count) { assert(riscv_mem_access_is_read(args)); @@ -4246,7 +4278,7 @@ static int read_memory_progbuf_inner_try_to_read(struct target *target, * with the address argument equal to curr_target_address. */ static int read_memory_progbuf_inner_ensure_forward_progress(struct target *target, - const riscv_mem_access_args_t args, uint32_t start_index) + const struct riscv_mem_access_args args, uint32_t start_index) { assert(riscv_mem_access_is_read(args)); @@ -4257,7 +4289,7 @@ static int read_memory_progbuf_inner_ensure_forward_progress(struct target *targ start_index * args.increment; uint8_t * const curr_buffer_address = args.read_buffer + start_index * args.size; - const riscv_mem_access_args_t curr_access = { + const struct riscv_mem_access_args curr_access = { .read_buffer = curr_buffer_address, .address = curr_target_address, .size = args.size, @@ -4279,7 +4311,7 @@ static int read_memory_progbuf_inner_ensure_forward_progress(struct target *targ return ERROR_OK; } -static void set_buffer_and_log_read(const riscv_mem_access_args_t args, +static void set_buffer_and_log_read(const struct riscv_mem_access_args args, uint32_t index, uint64_t value) { assert(riscv_mem_access_is_read(args)); @@ -4296,7 +4328,7 @@ static void set_buffer_and_log_read(const riscv_mem_access_args_t args, } static int read_word_from_dm_data_regs(struct target *target, - const riscv_mem_access_args_t args, uint32_t index) + const struct riscv_mem_access_args args, uint32_t index) { assert(args.size <= 8); uint64_t value; @@ -4308,7 +4340,7 @@ static int read_word_from_dm_data_regs(struct target *target, } static struct mem_access_result read_word_from_s1(struct target *target, - const riscv_mem_access_args_t args, uint32_t index) + const struct riscv_mem_access_args args, uint32_t index) { assert(riscv_mem_access_is_read(args)); @@ -4361,7 +4393,7 @@ static int read_memory_progbuf_inner_fill_progbuf(struct target *target, * is encountered in the process. */ static struct mem_access_result -read_memory_progbuf_inner(struct target *target, const riscv_mem_access_args_t args) +read_memory_progbuf_inner(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_read(args)); assert(args.count > 1 && "If count == 1, read_memory_progbuf_inner_one must be called"); @@ -4419,7 +4451,7 @@ read_memory_progbuf_inner(struct target *target, const riscv_mem_access_args_t a * program doesn't need to increment. */ static struct mem_access_result -read_memory_progbuf_inner_one(struct target *target, const riscv_mem_access_args_t args) +read_memory_progbuf_inner_one(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_read(args)); @@ -4455,7 +4487,7 @@ read_memory_progbuf_inner_one(struct target *target, const riscv_mem_access_args * Read the requested memory, silently handling memory access errors. */ static struct mem_access_result -read_memory_progbuf(struct target *target, const riscv_mem_access_args_t args) +read_memory_progbuf(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_read(args)); @@ -4471,10 +4503,10 @@ read_memory_progbuf(struct target *target, const riscv_mem_access_args_t args) } static struct mem_access_result -write_memory_progbuf(struct target *target, const riscv_mem_access_args_t args); +write_memory_progbuf(struct target *target, const struct riscv_mem_access_args args); static struct mem_access_result -access_memory_progbuf(struct target *target, const riscv_mem_access_args_t args) +access_memory_progbuf(struct target *target, const struct riscv_mem_access_args args) { struct mem_access_result skip_reason = mem_should_skip_progbuf(target, args); if (!is_mem_access_ok(skip_reason)) @@ -4509,12 +4541,12 @@ access_memory_progbuf(struct target *target, const riscv_mem_access_args_t args) } static int -write_memory_bus_v0(struct target *target, const riscv_mem_access_args_t args); +write_memory_bus_v0(struct target *target, const struct riscv_mem_access_args args); static int -write_memory_bus_v1(struct target *target, const riscv_mem_access_args_t args); +write_memory_bus_v1(struct target *target, const struct riscv_mem_access_args args); static struct mem_access_result -access_memory_sysbus(struct target *target, const riscv_mem_access_args_t args) +access_memory_sysbus(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_valid(args)); @@ -4542,7 +4574,7 @@ access_memory_sysbus(struct target *target, const riscv_mem_access_args_t args) } static struct mem_access_result -access_memory_abstract(struct target *target, const riscv_mem_access_args_t args) +access_memory_abstract(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_valid(args)); @@ -4561,7 +4593,7 @@ access_memory_abstract(struct target *target, const riscv_mem_access_args_t args } static int -riscv013_access_memory(struct target *target, const riscv_mem_access_args_t args) +riscv013_access_memory(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_valid(args)); @@ -4586,21 +4618,21 @@ riscv013_access_memory(struct target *target, const riscv_mem_access_args_t args RISCV_INFO(r); for (unsigned int i = 0; i < r->num_enabled_mem_access_methods; ++i) { - riscv_mem_access_method_t method = r->mem_access_methods[i]; + enum riscv_mem_access_method method = r->mem_access_methods[i]; switch (method) { - case RISCV_MEM_ACCESS_PROGBUF: - skip_reason[method] = access_memory_progbuf(target, args); - break; - case RISCV_MEM_ACCESS_SYSBUS: - skip_reason[method] = access_memory_sysbus(target, args); - break; - case RISCV_MEM_ACCESS_ABSTRACT: - skip_reason[method] = access_memory_abstract(target, args); - break; - default: - LOG_TARGET_ERROR(target, "Unknown memory access method: %d", method); - assert(false && "Unknown memory access method"); - goto failure; + case RISCV_MEM_ACCESS_PROGBUF: + skip_reason[method] = access_memory_progbuf(target, args); + break; + case RISCV_MEM_ACCESS_SYSBUS: + skip_reason[method] = access_memory_sysbus(target, args); + break; + case RISCV_MEM_ACCESS_ABSTRACT: + skip_reason[method] = access_memory_abstract(target, args); + break; + default: + LOG_TARGET_ERROR(target, "Unknown memory access method: %d", method); + assert(false && "Unknown memory access method"); + goto failure; } if (is_mem_access_failed(skip_reason[method])) @@ -4621,7 +4653,7 @@ riscv013_access_memory(struct target *target, const riscv_mem_access_args_t args return ERROR_FAIL; } -static int write_memory_bus_v0(struct target *target, const riscv_mem_access_args_t args) +static int write_memory_bus_v0(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_write(args)); @@ -4675,7 +4707,7 @@ static int write_memory_bus_v0(struct target *target, const riscv_mem_access_arg return ERROR_OK; } -static int write_memory_bus_v1(struct target *target, const riscv_mem_access_args_t args) +static int write_memory_bus_v1(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_write(args)); @@ -4876,7 +4908,8 @@ static int write_memory_progbuf_teardown(struct target *target) * failed write. */ static int write_memory_progbuf_handle_busy(struct target *target, - target_addr_t *address_p, uint32_t size, const uint8_t *buffer) + target_addr_t *address_p, target_addr_t end_address, uint32_t size, + const uint8_t *buffer) { int res = riscv013_clear_abstract_error(target); if (res != ERROR_OK) @@ -4892,8 +4925,12 @@ static int write_memory_progbuf_handle_busy(struct target *target, if (register_read_direct(target, &address_on_target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; const uint8_t * const curr_buff = buffer + (address_on_target - *address_p); - LOG_TARGET_DEBUG(target, "Restarting from 0x%" TARGET_PRIxADDR, *address_p); *address_p = address_on_target; + if (*address_p == end_address) { + LOG_TARGET_DEBUG(target, "Got busy while reading after reading the last element"); + return ERROR_OK; + } + LOG_TARGET_DEBUG(target, "Restarting from 0x%" TARGET_PRIxADDR, *address_p); /* This restores the pipeline and ensures one item gets reliably written */ return write_memory_progbuf_startup(target, address_p, curr_buff, size); } @@ -4971,7 +5008,8 @@ static int write_memory_progbuf_run_batch(struct target *target, struct riscv_ba /* TODO: If dmi busy is encountered, the address of the last * successful write can be deduced by analysing the batch. */ - return write_memory_progbuf_handle_busy(target, address_p, size, buffer); + return write_memory_progbuf_handle_busy(target, address_p, end_address, + size, buffer); } LOG_TARGET_ERROR(target, "Error when writing memory, abstractcs=0x%" PRIx32, abstractcs); @@ -5020,7 +5058,7 @@ static int write_memory_progbuf_fill_progbuf(struct target *target, uint32_t siz static struct mem_access_result write_memory_progbuf_inner(struct target *target, - const riscv_mem_access_args_t args) + const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_write(args)); @@ -5055,7 +5093,7 @@ write_memory_progbuf_inner(struct target *target, } static struct mem_access_result -write_memory_progbuf(struct target *target, const riscv_mem_access_args_t args) +write_memory_progbuf(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_write(args)); @@ -5079,10 +5117,6 @@ static unsigned int riscv013_get_progbufsize(const struct target *target) return r->progbufsize; } -static int arch_state(struct target *target) -{ - return ERROR_OK; -} struct target_type riscv013_target = { .name = "riscv", @@ -5097,8 +5131,6 @@ struct target_type riscv013_target = { .assert_reset = assert_reset, .deassert_reset = deassert_reset, - - .arch_state = arch_state }; /*** 0.13-specific implementations of various RISC-V helper functions. ***/ @@ -5425,6 +5457,8 @@ static int riscv013_invalidate_cached_progbuf(struct target *target) static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr) { + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; uint32_t run_program = 0; run_program = set_field(run_program, AC_ACCESS_REGISTER_AARSIZE, 2); run_program = set_field(run_program, AC_ACCESS_REGISTER_POSTEXEC, 1); @@ -5484,7 +5518,7 @@ static int riscv013_step_or_resume_current_hart(struct target *target, { if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "Hart is not halted!"); - return ERROR_FAIL; + return ERROR_TARGET_NOT_HALTED; } LOG_TARGET_DEBUG(target, "resuming (operation=%s)", diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index c6f1ef0546..dbe6e68f14 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -155,7 +155,7 @@ bool riscv_virt2phys_mode_is_sw(const struct target *target) return r->virt2phys_mode == RISCV_VIRT2PHYS_MODE_SW; } -const char *riscv_virt2phys_mode_to_str(riscv_virt2phys_mode_t mode) +const char *riscv_virt2phys_mode_to_str(enum riscv_virt2phys_mode mode) { assert(mode == RISCV_VIRT2PHYS_MODE_OFF || mode == RISCV_VIRT2PHYS_MODE_SW @@ -462,16 +462,16 @@ static struct target_type *get_target_type(struct target *target) RISCV_INFO(info); switch (info->dtm_version) { - case DTM_DTMCS_VERSION_0_11: - return &riscv011_target; - case DTM_DTMCS_VERSION_1_0: - return &riscv013_target; - default: - /* TODO: once we have proper support for non-examined targets - * we should have an assert here */ - LOG_TARGET_ERROR(target, "Unsupported DTM version: %d", - info->dtm_version); - return NULL; + case DTM_DTMCS_VERSION_0_11: + return &riscv011_target; + case DTM_DTMCS_VERSION_1_0: + return &riscv013_target; + default: + /* TODO: once we have proper support for non-examined targets + * we should have an assert here */ + LOG_TARGET_ERROR(target, "Unsupported DTM version: %d", + info->dtm_version); + return NULL; } } @@ -1788,16 +1788,16 @@ int riscv_remove_watchpoint(struct target *target, return ERROR_OK; } -typedef enum { +enum mctrl6hitstatus { M6_HIT_ERROR, M6_HIT_NOT_SUPPORTED, M6_NOT_HIT, M6_HIT_BEFORE, M6_HIT_AFTER, M6_HIT_IMM_AFTER -} mctrl6hitstatus; +}; -static mctrl6hitstatus check_mcontrol6_hit_status(struct target *target, +static enum mctrl6hitstatus check_mcontrol6_hit_status(struct target *target, riscv_reg_t tdata1, uint64_t hit_mask) { const uint32_t hit0 = get_field(tdata1, CSR_MCONTROL6_HIT0); @@ -1877,39 +1877,39 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_ uint64_t hit_mask = 0; switch (type) { - case CSR_TDATA1_TYPE_LEGACY: - /* Doesn't support hit bit. */ - break; - case CSR_TDATA1_TYPE_MCONTROL: - hit_mask = CSR_MCONTROL_HIT; + case CSR_TDATA1_TYPE_LEGACY: + /* Doesn't support hit bit. */ + break; + case CSR_TDATA1_TYPE_MCONTROL: + hit_mask = CSR_MCONTROL_HIT; + *need_single_step = true; + break; + case CSR_TDATA1_TYPE_MCONTROL6: + hit_mask = CSR_MCONTROL6_HIT0 | CSR_MCONTROL6_HIT1; + if (r->tinfo_version == CSR_TINFO_VERSION_0) { *need_single_step = true; - break; - case CSR_TDATA1_TYPE_MCONTROL6: - hit_mask = CSR_MCONTROL6_HIT0 | CSR_MCONTROL6_HIT1; - if (r->tinfo_version == CSR_TINFO_VERSION_0) { + } else if (r->tinfo_version == RISCV_TINFO_VERSION_UNKNOWN + || r->tinfo_version == CSR_TINFO_VERSION_1) { + enum mctrl6hitstatus hits_status = check_mcontrol6_hit_status(target, + tdata1, hit_mask); + if (hits_status == M6_HIT_ERROR) + return ERROR_FAIL; + if (hits_status == M6_HIT_BEFORE || hits_status == M6_HIT_NOT_SUPPORTED) *need_single_step = true; - } else if (r->tinfo_version == RISCV_TINFO_VERSION_UNKNOWN - || r->tinfo_version == CSR_TINFO_VERSION_1) { - mctrl6hitstatus hits_status = check_mcontrol6_hit_status(target, - tdata1, hit_mask); - if (hits_status == M6_HIT_ERROR) - return ERROR_FAIL; - if (hits_status == M6_HIT_BEFORE || hits_status == M6_HIT_NOT_SUPPORTED) - *need_single_step = true; - } - break; - case CSR_TDATA1_TYPE_ICOUNT: - hit_mask = CSR_ICOUNT_HIT; - break; - case CSR_TDATA1_TYPE_ITRIGGER: - hit_mask = CSR_ITRIGGER_HIT(riscv_xlen(target)); - break; - case CSR_TDATA1_TYPE_ETRIGGER: - hit_mask = CSR_ETRIGGER_HIT(riscv_xlen(target)); - break; - default: - LOG_TARGET_DEBUG(target, "Trigger %u has unknown type %d", i, type); - continue; + } + break; + case CSR_TDATA1_TYPE_ICOUNT: + hit_mask = CSR_ICOUNT_HIT; + break; + case CSR_TDATA1_TYPE_ITRIGGER: + hit_mask = CSR_ITRIGGER_HIT(riscv_xlen(target)); + break; + case CSR_TDATA1_TYPE_ETRIGGER: + hit_mask = CSR_ETRIGGER_HIT(riscv_xlen(target)); + break; + default: + LOG_TARGET_DEBUG(target, "Trigger %u has unknown type %d", i, type); + continue; } /* FIXME: this logic needs to be changed to ignore triggers that are not @@ -2098,7 +2098,7 @@ static int get_loadstore_memoffset(struct target *target, const riscv_insn_t instruction, int16_t *memoffset) { uint32_t opcode = get_opcode(instruction); - int16_t offset; + int16_t offset = 0; switch (opcode) { case MATCH_LB: @@ -2499,28 +2499,36 @@ int riscv_examine(struct target *target) LOG_TARGET_ERROR(target, "Could not read dtmcontrol. Check JTAG connectivity/board power."); return ERROR_FAIL; } - LOG_TARGET_DEBUG(target, "dtmcontrol=0x%x", dtmcontrol); - info->dtm_version = get_field(dtmcontrol, DTMCONTROL_VERSION); - LOG_TARGET_DEBUG(target, "version=0x%x", info->dtm_version); + LOG_TARGET_DEBUG(target, "dtmcontrol=0x%" PRIx32, dtmcontrol); + uint32_t dtm_version = get_field(dtmcontrol, DTMCONTROL_VERSION); + LOG_TARGET_DEBUG(target, "version=0x%" PRIx32, dtm_version); - int examine_status = ERROR_FAIL; - struct target_type *tt = get_target_type(target); - if (!tt) - goto examine_fail; - - examine_status = tt->init_target(info->cmd_ctx, target); - if (examine_status != ERROR_OK) - goto examine_fail; - - examine_status = tt->examine(target); - if (examine_status != ERROR_OK) - goto examine_fail; + struct target_type *tt; + if (info->dtm_version == DTM_DTMCS_VERSION_UNKNOWN) { + info->dtm_version = dtm_version; + tt = get_target_type(target); + if (!tt) { + info->dtm_version = DTM_DTMCS_VERSION_UNKNOWN; + return ERROR_FAIL; + } - return ERROR_OK; + int retval = tt->init_target(info->cmd_ctx, target); + if (retval != ERROR_OK) { + info->dtm_version = DTM_DTMCS_VERSION_UNKNOWN; + return retval; + } + } else { + if (info->dtm_version != dtm_version) { + // REVISIT: could we deinit_target, change version and init_target again? + LOG_TARGET_ERROR(target, "dtmcs.version changed to 0x%" PRIx32, dtm_version); + return ERROR_FAIL; + } + tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; + } -examine_fail: - info->dtm_version = DTM_DTMCS_VERSION_UNKNOWN; - return examine_status; + return tt->examine(target); } static int oldriscv_poll(struct target *target) @@ -2576,71 +2584,71 @@ static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_r r->trigger_hit = -1; r->need_single_step = false; switch (halt_reason) { - case RISCV_HALT_EBREAK: - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case RISCV_HALT_TRIGGER: - target->debug_reason = DBG_REASON_UNDEFINED; - if (riscv_trigger_detect_hit_bits(target, &r->trigger_hit, - &r->need_single_step) != ERROR_OK) - return ERROR_FAIL; - // FIXME: handle multiple hit bits - if (r->trigger_hit != RISCV_TRIGGER_HIT_NOT_FOUND) { - /* We scan for breakpoints first. If no breakpoints are found we still - * assume that debug reason is DBG_REASON_BREAKPOINT, unless - * there is a watchpoint match - This is to take - * ETrigger/ITrigger/ICount into account - */ - LOG_TARGET_DEBUG(target, - "Active hit bit is detected, trying to find trigger owner."); - for (struct breakpoint *bp = target->breakpoints; bp; bp = bp->next) { - if (bp->unique_id == r->trigger_hit) { - target->debug_reason = DBG_REASON_BREAKPOINT; - LOG_TARGET_DEBUG(target, - "Breakpoint with unique_id = %" PRIu32 " owns the trigger.", - bp->unique_id); - } - } - if (target->debug_reason == DBG_REASON_UNDEFINED) { - // by default we report all triggers as breakpoints + case RISCV_HALT_EBREAK: + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case RISCV_HALT_TRIGGER: + target->debug_reason = DBG_REASON_UNDEFINED; + if (riscv_trigger_detect_hit_bits(target, &r->trigger_hit, + &r->need_single_step) != ERROR_OK) + return ERROR_FAIL; + // FIXME: handle multiple hit bits + if (r->trigger_hit != RISCV_TRIGGER_HIT_NOT_FOUND) { + /* We scan for breakpoints first. If no breakpoints are found we still + * assume that debug reason is DBG_REASON_BREAKPOINT, unless + * there is a watchpoint match - This is to take + * ETrigger/ITrigger/ICount into account + */ + LOG_TARGET_DEBUG(target, + "Active hit bit is detected, trying to find trigger owner."); + for (struct breakpoint *bp = target->breakpoints; bp; bp = bp->next) { + if (bp->unique_id == r->trigger_hit) { target->debug_reason = DBG_REASON_BREAKPOINT; - for (struct watchpoint *wp = target->watchpoints; wp; wp = wp->next) { - if (wp->unique_id == r->trigger_hit) { - target->debug_reason = DBG_REASON_WATCHPOINT; - LOG_TARGET_DEBUG(target, - "Watchpoint with unique_id = %" PRIu32 " owns the trigger.", - wp->unique_id); - } + LOG_TARGET_DEBUG(target, + "Breakpoint with unique_id = %" PRIu32 " owns the trigger.", + bp->unique_id); + } + } + if (target->debug_reason == DBG_REASON_UNDEFINED) { + // by default we report all triggers as breakpoints + target->debug_reason = DBG_REASON_BREAKPOINT; + for (struct watchpoint *wp = target->watchpoints; wp; wp = wp->next) { + if (wp->unique_id == r->trigger_hit) { + target->debug_reason = DBG_REASON_WATCHPOINT; + LOG_TARGET_DEBUG(target, + "Watchpoint with unique_id = %" PRIu32 " owns the trigger.", + wp->unique_id); } } - } else { - LOG_TARGET_DEBUG(target, - "No trigger hit found, deriving debug reason without it."); - riscv_reg_t dpc; - if (riscv_reg_get(target, &dpc, GDB_REGNO_DPC) != ERROR_OK) - return ERROR_FAIL; - /* Here we don't have the hit bit set (likely, HW does not support it). - * We are trying to guess the state. But here comes the problem: - * if we have etrigger/itrigger/icount raised - we can't really - * distinguish it from the breakpoint or watchpoint. There is not - * much we can do here, except for checking current PC against pending - * breakpoints and hope for the best) - */ - target->debug_reason = derive_debug_reason_without_hitbit(target, dpc); } - break; - case RISCV_HALT_INTERRUPT: - case RISCV_HALT_GROUP: - target->debug_reason = DBG_REASON_DBGRQ; - break; - case RISCV_HALT_SINGLESTEP: - target->debug_reason = DBG_REASON_SINGLESTEP; - break; - case RISCV_HALT_UNKNOWN: - target->debug_reason = DBG_REASON_UNDEFINED; - break; - case RISCV_HALT_ERROR: - return ERROR_FAIL; + } else { + LOG_TARGET_DEBUG(target, + "No trigger hit found, deriving debug reason without it."); + riscv_reg_t dpc; + if (riscv_reg_get(target, &dpc, GDB_REGNO_DPC) != ERROR_OK) + return ERROR_FAIL; + /* Here we don't have the hit bit set (likely, HW does not support it). + * We are trying to guess the state. But here comes the problem: + * if we have etrigger/itrigger/icount raised - we can't really + * distinguish it from the breakpoint or watchpoint. There is not + * much we can do here, except for checking current PC against pending + * breakpoints and hope for the best) + */ + target->debug_reason = derive_debug_reason_without_hitbit(target, dpc); + } + break; + case RISCV_HALT_INTERRUPT: + case RISCV_HALT_GROUP: + target->debug_reason = DBG_REASON_DBGRQ; + break; + case RISCV_HALT_SINGLESTEP: + target->debug_reason = DBG_REASON_SINGLESTEP; + break; + case RISCV_HALT_UNKNOWN: + target->debug_reason = DBG_REASON_UNDEFINED; + break; + case RISCV_HALT_ERROR: + return ERROR_FAIL; } LOG_TARGET_DEBUG(target, "debug_reason=%d", target->debug_reason); @@ -2925,8 +2933,7 @@ static int resume_finish(struct target *target, bool debug_execution) * @par single_hart When true, only resume a single hart even if SMP is * configured. This is used to run algorithms on just one hart. */ -static int riscv_resume( - struct target *target, +static int riscv_resume(struct target *target, bool current, target_addr_t address, bool handle_breakpoints, @@ -3027,9 +3034,9 @@ static int riscv_effective_privilege_mode(struct target *target, int *v_mode, in return ERROR_OK; } -int riscv_mmu(struct target *target, int *enabled) +int riscv_mmu(struct target *target, bool *enabled) { - *enabled = 0; + *enabled = false; if (!riscv_virt2phys_mode_is_sw(target)) return ERROR_OK; @@ -3060,7 +3067,7 @@ int riscv_mmu(struct target *target, int *enabled) /* vsatp is identical to satp, so we can use the satp macros. */ if (get_field(vsatp, RISCV_SATP_MODE(xlen)) != SATP_MODE_OFF) { LOG_TARGET_DEBUG(target, "VS-stage translation is enabled."); - *enabled = 1; + *enabled = true; return ERROR_OK; } @@ -3072,7 +3079,7 @@ int riscv_mmu(struct target *target, int *enabled) } if (get_field(hgatp, RISCV_HGATP_MODE(xlen)) != HGATP_MODE_OFF) { LOG_TARGET_DEBUG(target, "G-stage address translation is enabled."); - *enabled = 1; + *enabled = true; } else { LOG_TARGET_DEBUG(target, "No V-mode address translation enabled."); } @@ -3097,7 +3104,7 @@ int riscv_mmu(struct target *target, int *enabled) LOG_TARGET_DEBUG(target, "MMU is disabled."); } else { LOG_TARGET_DEBUG(target, "MMU is enabled."); - *enabled = 1; + *enabled = true; } return ERROR_OK; @@ -3144,7 +3151,7 @@ static int riscv_address_translate(struct target *target, uint8_t buffer[8]; assert(info->pte_shift <= 3); - const riscv_mem_access_args_t args = { + const struct riscv_mem_access_args args = { .address = pte_address, .read_buffer = buffer, .size = 4, @@ -3223,55 +3230,55 @@ static int riscv_virt2phys_v(struct target *target, target_addr_t virtual, targe const virt2phys_info_t *vsatp_info; /* VS-stage address translation. */ switch (vsatp_mode) { - case SATP_MODE_SV32: - vsatp_info = &sv32; - break; - case SATP_MODE_SV39: - vsatp_info = &sv39; - break; - case SATP_MODE_SV48: - vsatp_info = &sv48; - break; - case SATP_MODE_SV57: - vsatp_info = &sv57; - break; - case SATP_MODE_OFF: - vsatp_info = NULL; - LOG_TARGET_DEBUG(target, "vsatp mode is %d. No VS-stage translation. (vsatp: 0x%" PRIx64 ")", - vsatp_mode, vsatp); - break; - default: - LOG_TARGET_ERROR(target, - "vsatp mode %d is not supported. (vsatp: 0x%" PRIx64 ")", - vsatp_mode, vsatp); - return ERROR_FAIL; + case SATP_MODE_SV32: + vsatp_info = &sv32; + break; + case SATP_MODE_SV39: + vsatp_info = &sv39; + break; + case SATP_MODE_SV48: + vsatp_info = &sv48; + break; + case SATP_MODE_SV57: + vsatp_info = &sv57; + break; + case SATP_MODE_OFF: + vsatp_info = NULL; + LOG_TARGET_DEBUG(target, "vsatp mode is %d. No VS-stage translation. (vsatp: 0x%" PRIx64 ")", + vsatp_mode, vsatp); + break; + default: + LOG_TARGET_ERROR(target, + "vsatp mode %d is not supported. (vsatp: 0x%" PRIx64 ")", + vsatp_mode, vsatp); + return ERROR_FAIL; } const virt2phys_info_t *hgatp_info; /* G-stage address translation. */ switch (hgatp_mode) { - case HGATP_MODE_SV32X4: - hgatp_info = &sv32x4; - break; - case HGATP_MODE_SV39X4: - hgatp_info = &sv39x4; - break; - case HGATP_MODE_SV48X4: - hgatp_info = &sv48x4; - break; - case HGATP_MODE_SV57X4: - hgatp_info = &sv57x4; - break; - case HGATP_MODE_OFF: - hgatp_info = NULL; - LOG_TARGET_DEBUG(target, "hgatp mode is %d. No G-stage translation. (hgatp: 0x%" PRIx64 ")", - hgatp_mode, hgatp); - break; - default: - LOG_TARGET_ERROR(target, - "hgatp mode %d is not supported. (hgatp: 0x%" PRIx64 ")", - hgatp_mode, hgatp); - return ERROR_FAIL; + case HGATP_MODE_SV32X4: + hgatp_info = &sv32x4; + break; + case HGATP_MODE_SV39X4: + hgatp_info = &sv39x4; + break; + case HGATP_MODE_SV48X4: + hgatp_info = &sv48x4; + break; + case HGATP_MODE_SV57X4: + hgatp_info = &sv57x4; + break; + case HGATP_MODE_OFF: + hgatp_info = NULL; + LOG_TARGET_DEBUG(target, "hgatp mode is %d. No G-stage translation. (hgatp: 0x%" PRIx64 ")", + hgatp_mode, hgatp); + break; + default: + LOG_TARGET_ERROR(target, + "hgatp mode %d is not supported. (hgatp: 0x%" PRIx64 ")", + hgatp_mode, hgatp); + return ERROR_FAIL; } /* For any virtual memory access, the original virtual address is @@ -3313,7 +3320,7 @@ static int riscv_virt2phys_v(struct target *target, target_addr_t virtual, targe int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { - int enabled; + bool enabled; if (riscv_mmu(target, &enabled) != ERROR_OK) return ERROR_FAIL; if (!enabled) { @@ -3341,26 +3348,26 @@ int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t int satp_mode = get_field(satp_value, RISCV_SATP_MODE(xlen)); const virt2phys_info_t *satp_info; switch (satp_mode) { - case SATP_MODE_SV32: - satp_info = &sv32; - break; - case SATP_MODE_SV39: - satp_info = &sv39; - break; - case SATP_MODE_SV48: - satp_info = &sv48; - break; - case SATP_MODE_SV57: - satp_info = &sv57; - break; - case SATP_MODE_OFF: - LOG_TARGET_ERROR(target, "No translation or protection." - " (satp: 0x%" PRIx64 ")", satp_value); - return ERROR_FAIL; - default: - LOG_TARGET_ERROR(target, "The translation mode is not supported." - " (satp: 0x%" PRIx64 ")", satp_value); - return ERROR_FAIL; + case SATP_MODE_SV32: + satp_info = &sv32; + break; + case SATP_MODE_SV39: + satp_info = &sv39; + break; + case SATP_MODE_SV48: + satp_info = &sv48; + break; + case SATP_MODE_SV57: + satp_info = &sv57; + break; + case SATP_MODE_OFF: + LOG_TARGET_ERROR(target, "No translation or protection." + " (satp: 0x%" PRIx64 ")", satp_value); + return ERROR_FAIL; + default: + LOG_TARGET_ERROR(target, "The translation mode is not supported." + " (satp: 0x%" PRIx64 ")", satp_value); + return ERROR_FAIL; } return riscv_address_translate(target, @@ -3387,7 +3394,7 @@ static int check_virt_memory_access(struct target *target, target_addr_t address int riscv_read_phys_memory(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer) { - const riscv_mem_access_args_t args = { + const struct riscv_mem_access_args args = { .address = phys_address, .read_buffer = buffer, .size = size, @@ -3401,7 +3408,7 @@ int riscv_read_phys_memory(struct target *target, target_addr_t phys_address, int riscv_write_phys_memory(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer) { - const riscv_mem_access_args_t args = { + const struct riscv_mem_access_args args = { .address = phys_address, .write_buffer = buffer, .size = size, @@ -3413,7 +3420,7 @@ int riscv_write_phys_memory(struct target *target, target_addr_t phys_address, return r->access_memory(target, args); } -static int riscv_rw_memory(struct target *target, const riscv_mem_access_args_t args) +static int riscv_rw_memory(struct target *target, const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_valid(args)); @@ -3424,7 +3431,7 @@ static int riscv_rw_memory(struct target *target, const riscv_mem_access_args_t return ERROR_OK; } - int mmu_enabled; + bool mmu_enabled; int result = riscv_mmu(target, &mmu_enabled); if (result != ERROR_OK) return result; @@ -3455,7 +3462,7 @@ static int riscv_rw_memory(struct target *target, const riscv_mem_access_args_t (RISCV_PGSIZE - RISCV_PGOFFSET(current_address)) / args.size); - riscv_mem_access_args_t current_access = args; + struct riscv_mem_access_args current_access = args; current_access.address = physical_addr; current_access.count = chunk_count; if (is_write) @@ -3476,7 +3483,7 @@ static int riscv_rw_memory(struct target *target, const riscv_mem_access_args_t int riscv_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - const riscv_mem_access_args_t args = { + const struct riscv_mem_access_args args = { .address = address, .read_buffer = buffer, .size = size, @@ -3490,7 +3497,7 @@ int riscv_read_memory(struct target *target, target_addr_t address, int riscv_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - const riscv_mem_access_args_t args = { + const struct riscv_mem_access_args args = { .address = address, .write_buffer = buffer, .size = size, @@ -3504,10 +3511,10 @@ int riscv_write_memory(struct target *target, target_addr_t address, const char *riscv_get_gdb_arch(const struct target *target) { switch (riscv_xlen(target)) { - case 32: - return "riscv:rv32"; - case 64: - return "riscv:rv64"; + case 32: + return "riscv:rv32"; + case 64: + return "riscv:rv64"; } LOG_TARGET_ERROR(target, "Unsupported xlen: %d", riscv_xlen(target)); return NULL; @@ -3525,15 +3532,15 @@ static int riscv_get_gdb_reg_list_internal(struct target *target, } switch (reg_class) { - case REG_CLASS_GENERAL: - *reg_list_size = 33; - break; - case REG_CLASS_ALL: - *reg_list_size = target->reg_cache->num_regs; - break; - default: - LOG_TARGET_ERROR(target, "Unsupported reg_class: %d", reg_class); - return ERROR_FAIL; + case REG_CLASS_GENERAL: + *reg_list_size = 33; + break; + case REG_CLASS_ALL: + *reg_list_size = target->reg_cache->num_regs; + break; + default: + LOG_TARGET_ERROR(target, "Unsupported reg_class: %d", reg_class); + return ERROR_FAIL; } *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); @@ -3547,8 +3554,7 @@ static int riscv_get_gdb_reg_list_internal(struct target *target, if (is_read && target->reg_cache->reg_list[i].exist && !target->reg_cache->reg_list[i].valid) { - if (target->reg_cache->reg_list[i].type->get( - &target->reg_cache->reg_list[i]) != ERROR_OK) + if (target->reg_cache->reg_list[i].type->get(&target->reg_cache->reg_list[i]) != ERROR_OK) return ERROR_FAIL; } } @@ -3581,11 +3587,7 @@ int riscv_arch_state(struct target *target) target_name(target), debug_reason_name(target), semihosting_active ? " Semihosting is active." : ""); - struct target_type *tt = get_target_type(target); - if (!tt) - return ERROR_FAIL; - assert(tt->arch_state); - return tt->arch_state(target); + return ERROR_OK; } /* Algorithm must end with a software breakpoint instruction. */ @@ -3861,25 +3863,25 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a enum riscv_hart_state previous_riscv_state = 0; enum target_state previous_target_state = target->state; switch (target->state) { - case TARGET_UNKNOWN: - /* Special case, handled further down. */ - previous_riscv_state = RISCV_STATE_UNAVAILABLE; /* Need to assign something. */ - break; - case TARGET_RUNNING: - previous_riscv_state = RISCV_STATE_RUNNING; - break; - case TARGET_HALTED: - previous_riscv_state = RISCV_STATE_HALTED; - break; - case TARGET_RESET: - previous_riscv_state = RISCV_STATE_HALTED; - break; - case TARGET_DEBUG_RUNNING: - previous_riscv_state = RISCV_STATE_RUNNING; - break; - case TARGET_UNAVAILABLE: - previous_riscv_state = RISCV_STATE_UNAVAILABLE; - break; + case TARGET_UNKNOWN: + /* Special case, handled further down. */ + previous_riscv_state = RISCV_STATE_UNAVAILABLE; /* Need to assign something. */ + break; + case TARGET_RUNNING: + previous_riscv_state = RISCV_STATE_RUNNING; + break; + case TARGET_HALTED: + previous_riscv_state = RISCV_STATE_HALTED; + break; + case TARGET_RESET: + previous_riscv_state = RISCV_STATE_HALTED; + break; + case TARGET_DEBUG_RUNNING: + previous_riscv_state = RISCV_STATE_RUNNING; + break; + case TARGET_UNAVAILABLE: + previous_riscv_state = RISCV_STATE_UNAVAILABLE; + break; } /* If OpenOCD thinks we're running but this hart is halted then it's time @@ -3902,79 +3904,79 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a if (target->state == TARGET_UNKNOWN || state != previous_riscv_state) { switch (state) { - case RISCV_STATE_HALTED: - if (previous_riscv_state == RISCV_STATE_UNAVAILABLE) - LOG_TARGET_INFO(target, "became available (halted)"); - - LOG_TARGET_DEBUG(target, " triggered a halt; previous_target_state=%d", - previous_target_state); - target->state = TARGET_HALTED; - enum riscv_halt_reason halt_reason = riscv_halt_reason(target); - if (set_debug_reason(target, halt_reason) != ERROR_OK) - return ERROR_FAIL; + case RISCV_STATE_HALTED: + if (previous_riscv_state == RISCV_STATE_UNAVAILABLE) + LOG_TARGET_INFO(target, "became available (halted)"); - if (halt_reason == RISCV_HALT_EBREAK) { - int retval; - /* Detect if this EBREAK is a semihosting request. If so, handle it. */ - switch (riscv_semihosting(target, &retval)) { - case SEMIHOSTING_NONE: - break; - case SEMIHOSTING_WAITING: - /* This hart should remain halted. */ - *next_action = RPH_REMAIN_HALTED; - break; - case SEMIHOSTING_HANDLED: - /* This hart should be resumed, along with any other - * harts that halted due to haltgroups. */ - *next_action = RPH_RESUME; - return ERROR_OK; - case SEMIHOSTING_ERROR: - return retval; - } + LOG_TARGET_DEBUG(target, " triggered a halt; previous_target_state=%d", + previous_target_state); + target->state = TARGET_HALTED; + enum riscv_halt_reason halt_reason = riscv_halt_reason(target); + if (set_debug_reason(target, halt_reason) != ERROR_OK) + return ERROR_FAIL; + + if (halt_reason == RISCV_HALT_EBREAK) { + int retval; + /* Detect if this EBREAK is a semihosting request. If so, handle it. */ + switch (riscv_semihosting(target, &retval)) { + case SEMIHOSTING_NONE: + break; + case SEMIHOSTING_WAITING: + /* This hart should remain halted. */ + *next_action = RPH_REMAIN_HALTED; + break; + case SEMIHOSTING_HANDLED: + /* This hart should be resumed, along with any other + * harts that halted due to haltgroups. */ + *next_action = RPH_RESUME; + return ERROR_OK; + case SEMIHOSTING_ERROR: + return retval; } + } - if (r->handle_became_halted && - r->handle_became_halted(target, previous_riscv_state) != ERROR_OK) - return ERROR_FAIL; + if (r->handle_became_halted && + r->handle_became_halted(target, previous_riscv_state) != ERROR_OK) + return ERROR_FAIL; - /* We shouldn't do the callbacks yet. What if - * there are multiple harts that halted at the - * same time? We need to set debug reason on each - * of them before calling a callback, which is - * going to figure out the "current thread". */ + /* We shouldn't do the callbacks yet. What if + * there are multiple harts that halted at the + * same time? We need to set debug reason on each + * of them before calling a callback, which is + * going to figure out the "current thread". */ - r->halted_needs_event_callback = true; - if (previous_target_state == TARGET_DEBUG_RUNNING) - r->halted_callback_event = TARGET_EVENT_DEBUG_HALTED; - else - r->halted_callback_event = TARGET_EVENT_HALTED; - break; - - case RISCV_STATE_RUNNING: - if (previous_riscv_state == RISCV_STATE_UNAVAILABLE) - LOG_TARGET_INFO(target, "became available (running)"); - - LOG_TARGET_DEBUG(target, " triggered running"); - target->state = TARGET_RUNNING; - target->debug_reason = DBG_REASON_NOTHALTED; - if (r->handle_became_running && - r->handle_became_running(target, previous_riscv_state) != ERROR_OK) - return ERROR_FAIL; - break; - - case RISCV_STATE_UNAVAILABLE: - LOG_TARGET_DEBUG(target, " became unavailable"); - LOG_TARGET_INFO(target, "became unavailable."); - target->state = TARGET_UNAVAILABLE; - if (r->handle_became_unavailable && - r->handle_became_unavailable(target, previous_riscv_state) != ERROR_OK) - return ERROR_FAIL; - break; + r->halted_needs_event_callback = true; + if (previous_target_state == TARGET_DEBUG_RUNNING) + r->halted_callback_event = TARGET_EVENT_DEBUG_HALTED; + else + r->halted_callback_event = TARGET_EVENT_HALTED; + break; + + case RISCV_STATE_RUNNING: + if (previous_riscv_state == RISCV_STATE_UNAVAILABLE) + LOG_TARGET_INFO(target, "became available (running)"); + + LOG_TARGET_DEBUG(target, " triggered running"); + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + if (r->handle_became_running && + r->handle_became_running(target, previous_riscv_state) != ERROR_OK) + return ERROR_FAIL; + break; + + case RISCV_STATE_UNAVAILABLE: + LOG_TARGET_DEBUG(target, " became unavailable"); + LOG_TARGET_INFO(target, "became unavailable."); + target->state = TARGET_UNAVAILABLE; + if (r->handle_became_unavailable && + r->handle_became_unavailable(target, previous_riscv_state) != ERROR_OK) + return ERROR_FAIL; + break; - case RISCV_STATE_NON_EXISTENT: - LOG_TARGET_ERROR(target, "Hart is non-existent!"); - target->state = TARGET_UNAVAILABLE; - break; + case RISCV_STATE_NON_EXISTENT: + LOG_TARGET_ERROR(target, "Hart is non-existent!"); + target->state = TARGET_UNAVAILABLE; + break; } } @@ -4007,8 +4009,8 @@ static int sample_memory(struct target *target) 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, + 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) @@ -4074,19 +4076,19 @@ int riscv_openocd_poll(struct target *target) return ERROR_FAIL; switch (next_action) { - case RPH_NONE: - if (t->state == TARGET_HALTED) - halted++; - if (t->state == TARGET_RUNNING || - t->state == TARGET_DEBUG_RUNNING) - running++; - break; - case RPH_REMAIN_HALTED: - should_remain_halted++; - break; - case RPH_RESUME: - should_resume++; - break; + case RPH_NONE: + if (t->state == TARGET_HALTED) + halted++; + if (t->state == TARGET_RUNNING || + t->state == TARGET_DEBUG_RUNNING) + running++; + break; + case RPH_REMAIN_HALTED: + should_remain_halted++; + break; + case RPH_RESUME: + should_resume++; + break; } } @@ -4226,9 +4228,15 @@ static int riscv_openocd_step_impl(struct target *target, bool current, RISCV_INFO(r); bool *wps_to_enable = calloc(r->trigger_count, sizeof(*wps_to_enable)); + if (!wps_to_enable) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + if (disable_watchpoints(target, wps_to_enable) != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to temporarily disable " "watchpoints before single-step."); + free(wps_to_enable); return ERROR_FAIL; } @@ -4273,6 +4281,8 @@ static int riscv_openocd_step_impl(struct target *target, bool current, "after single-step."); } + free(wps_to_enable); + if (breakpoint && (riscv_add_breakpoint(target, breakpoint) != ERROR_OK)) { success = false; LOG_TARGET_ERROR(target, "Unable to restore the disabled breakpoint."); @@ -4388,7 +4398,7 @@ static bool parse_csr_address(const char *reg_address_str, unsigned int *reg_add { *reg_addr = -1; /* skip initial spaces */ - while (isspace(reg_address_str[0])) + while (isspace((unsigned char)reg_address_str[0])) ++reg_address_str; /* try to detect if string starts with 0x or 0X */ bool is_hex_address = strncmp(reg_address_str, "0x", 2) == 0 || @@ -4481,7 +4491,6 @@ static int parse_reg_ranges_impl(struct list_head *ranges, char *args, } } else { LOG_ERROR("Invalid argument '%s'.", arg); - free(args); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -4496,7 +4505,7 @@ static int parse_reg_ranges_impl(struct list_head *ranges, char *args, /* Check for overlap, name uniqueness. */ range_list_t *entry; list_for_each_entry(entry, ranges, list) { - if ((entry->low <= high) && (low <= entry->high)) { + 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); @@ -4623,10 +4632,10 @@ COMMAND_HANDLER(riscv_authdata_read) return ERROR_FAIL; command_print_sameline(CMD, "0x%08" PRIx32, value); return ERROR_OK; - } else { - LOG_TARGET_ERROR(target, "authdata_read is not implemented for this target."); - return ERROR_FAIL; } + + LOG_TARGET_ERROR(target, "authdata_read is not implemented for this target."); + return ERROR_FAIL; } COMMAND_HANDLER(riscv_authdata_write) @@ -4827,7 +4836,7 @@ COMMAND_HANDLER(riscv_set_ir) COMMAND_HANDLER(riscv_resume_order) { - if (CMD_ARGC > 1) + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!strcmp(CMD_ARGV[0], "normal")) { @@ -5016,6 +5025,11 @@ COMMAND_HANDLER(riscv_itrigger) struct target *target = get_current_target(CMD_CTX); const int ITRIGGER_UNIQUE_ID = -CSR_TDATA1_TYPE_ITRIGGER; + if (!target_was_examined(target)) { + LOG_TARGET_ERROR(target, "not examined"); + return ERROR_TARGET_NOT_EXAMINED; + } + if (riscv_enumerate_triggers(target) != ERROR_OK) return ERROR_FAIL; @@ -5081,6 +5095,11 @@ COMMAND_HANDLER(riscv_icount) struct target *target = get_current_target(CMD_CTX); const int ICOUNT_UNIQUE_ID = -CSR_TDATA1_TYPE_ICOUNT; + if (!target_was_examined(target)) { + LOG_TARGET_ERROR(target, "not examined"); + return ERROR_TARGET_NOT_EXAMINED; + } + if (riscv_enumerate_triggers(target) != ERROR_OK) return ERROR_FAIL; @@ -5146,6 +5165,11 @@ COMMAND_HANDLER(riscv_etrigger) struct target *target = get_current_target(CMD_CTX); const int ETRIGGER_UNIQUE_ID = -CSR_TDATA1_TYPE_ETRIGGER; + if (!target_was_examined(target)) { + LOG_TARGET_ERROR(target, "not examined"); + return ERROR_TARGET_NOT_EXAMINED; + } + if (riscv_enumerate_triggers(target) != ERROR_OK) return ERROR_FAIL; @@ -5203,6 +5227,11 @@ COMMAND_HANDLER(riscv_etrigger) COMMAND_HANDLER(handle_repeat_read) { struct target *target = get_current_target(CMD_CTX); + if (!target_was_examined(target)) { + LOG_TARGET_ERROR(target, "not examined"); + return ERROR_TARGET_NOT_EXAMINED; + } + RISCV_INFO(r); if (CMD_ARGC < 2 || CMD_ARGC > 3) @@ -5224,7 +5253,7 @@ COMMAND_HANDLER(handle_repeat_read) LOG_ERROR("malloc failed"); return ERROR_FAIL; } - const riscv_mem_access_args_t args = { + const struct riscv_mem_access_args args = { .address = address, .read_buffer = buffer, .size = size, @@ -5232,10 +5261,8 @@ COMMAND_HANDLER(handle_repeat_read) .increment = 0, }; int result = r->access_memory(target, args); - if (result == ERROR_OK) { - target_handle_md_output(cmd, target, address, size, count, buffer, - false); - } + if (result == ERROR_OK) + target_handle_md_output(cmd, target, address, size, count, buffer, false); free(buffer); return result; } @@ -5419,6 +5446,11 @@ COMMAND_HANDLER(riscv_exec_progbuf) struct target *target = get_current_target(CMD_CTX); + if (!target_was_examined(target)) { + LOG_TARGET_ERROR(target, "not examined"); + return ERROR_TARGET_NOT_EXAMINED; + } + RISCV_INFO(r); if (r->dtm_version != DTM_DTMCS_VERSION_1_0) { LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer is " @@ -5429,7 +5461,7 @@ COMMAND_HANDLER(riscv_exec_progbuf) if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "exec_progbuf: Can't execute " "program buffer, target not halted."); - return ERROR_FAIL; + return ERROR_TARGET_NOT_HALTED; } if (riscv_progbuf_size(target) == 0) { @@ -5538,6 +5570,11 @@ static COMMAND_HELPER(report_reserved_triggers, struct target *target) COMMAND_HANDLER(handle_reserve_trigger) { struct target *target = get_current_target(CMD_CTX); + if (!target_was_examined(target)) { + command_print(CMD, "Error: Target not examined"); + return ERROR_TARGET_NOT_EXAMINED; + } + if (CMD_ARGC == 0) return CALL_COMMAND_HANDLER(report_reserved_triggers, target); @@ -5574,7 +5611,7 @@ COMMAND_HANDLER(handle_riscv_virt2phys_mode) { struct riscv_info *info = riscv_info(get_current_target(CMD_CTX)); if (CMD_ARGC == 0) { - riscv_virt2phys_mode_t mode = info->virt2phys_mode; + enum riscv_virt2phys_mode mode = info->virt2phys_mode; command_print(CMD, "%s", riscv_virt2phys_mode_to_str(mode)); return ERROR_OK; } @@ -5869,6 +5906,9 @@ static const struct command_registration riscv_exec_command_handlers[] = { "When off, users need to take care of memory coherency themselves, for example by using " "`riscv exec_progbuf` to execute fence or CMO instructions." }, + { + .chain = smp_command_handlers + }, COMMAND_REGISTRATION_DONE }; @@ -5901,9 +5941,6 @@ const struct command_registration riscv_command_handlers[] = { .usage = "", .chain = semihosting_common_handlers }, - { - .chain = smp_command_handlers - }, COMMAND_REGISTRATION_DONE }; @@ -5920,6 +5957,31 @@ unsigned int riscv_data_bits(struct target *target) return riscv_xlen(target); } +static int riscv_insn_set(struct command_invocation *cmd, + struct target *target, const char **insn_set) +{ + if (!target_was_examined(target)) { + command_print(cmd, "[%s] target not examined yet", target_name(target)); + return ERROR_TARGET_NOT_EXAMINED; + } + + switch (riscv_xlen(target)) { + case 32: + *insn_set = "riscv32"; + break; + + case 64: + *insn_set = "riscv64"; + break; + + default: + command_print(cmd, "[%s] unsupported instruction set", target_name(target)); + return ERROR_FAIL; + } + + return ERROR_OK; +} + struct target_type riscv_target = { .name = "riscv", @@ -5967,7 +6029,9 @@ struct target_type riscv_target = { .commands = riscv_command_handlers, .address_bits = riscv_xlen_nonconst, - .data_bits = riscv_data_bits + .data_bits = riscv_data_bits, + + .insn_set = riscv_insn_set, }; /*** RISC-V Interface ***/ @@ -6063,7 +6127,7 @@ static int riscv_step_rtos_hart(struct target *target) if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "Hart isn't halted before single step!"); - return ERROR_FAIL; + return ERROR_TARGET_NOT_HALTED; } r->on_step(target); if (r->step_current_hart(target) != ERROR_OK) @@ -6210,26 +6274,26 @@ static int disable_trigger_if_dmode(struct target *target, riscv_reg_t tdata1) { bool dmode_is_set = false; switch (get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)))) { - case CSR_TDATA1_TYPE_LEGACY: - /* On these older cores we don't support software using - * triggers. */ - dmode_is_set = true; - break; - case CSR_TDATA1_TYPE_MCONTROL: - dmode_is_set = tdata1 & CSR_MCONTROL_DMODE(riscv_xlen(target)); - break; - case CSR_TDATA1_TYPE_MCONTROL6: - dmode_is_set = tdata1 & CSR_MCONTROL6_DMODE(riscv_xlen(target)); - break; - case CSR_TDATA1_TYPE_ICOUNT: - dmode_is_set = tdata1 & CSR_ICOUNT_DMODE(riscv_xlen(target)); - break; - case CSR_TDATA1_TYPE_ITRIGGER: - dmode_is_set = tdata1 & CSR_ITRIGGER_DMODE(riscv_xlen(target)); - break; - case CSR_TDATA1_TYPE_ETRIGGER: - dmode_is_set = tdata1 & CSR_ETRIGGER_DMODE(riscv_xlen(target)); - break; + case CSR_TDATA1_TYPE_LEGACY: + /* On these older cores we don't support software using + * triggers. */ + dmode_is_set = true; + break; + case CSR_TDATA1_TYPE_MCONTROL: + dmode_is_set = tdata1 & CSR_MCONTROL_DMODE(riscv_xlen(target)); + break; + case CSR_TDATA1_TYPE_MCONTROL6: + dmode_is_set = tdata1 & CSR_MCONTROL6_DMODE(riscv_xlen(target)); + break; + case CSR_TDATA1_TYPE_ICOUNT: + dmode_is_set = tdata1 & CSR_ICOUNT_DMODE(riscv_xlen(target)); + break; + case CSR_TDATA1_TYPE_ITRIGGER: + dmode_is_set = tdata1 & CSR_ITRIGGER_DMODE(riscv_xlen(target)); + break; + case CSR_TDATA1_TYPE_ETRIGGER: + dmode_is_set = tdata1 & CSR_ETRIGGER_DMODE(riscv_xlen(target)); + break; } if (!dmode_is_set) /* Nothing to do */ @@ -6253,7 +6317,7 @@ int riscv_enumerate_triggers(struct target *target) if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "Unable to enumerate triggers: target not halted."); - return ERROR_FAIL; + return ERROR_TARGET_NOT_HALTED; } riscv_reg_t orig_tselect; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 3b0d8ed6d4..1ff9580f4b 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -47,26 +47,26 @@ typedef uint64_t riscv_reg_t; typedef uint32_t riscv_insn_t; typedef uint64_t riscv_addr_t; -typedef enum { +enum yes_no_maybe { YNM_MAYBE, YNM_YES, YNM_NO -} yes_no_maybe_t; +}; -typedef enum riscv_mem_access_method { +enum riscv_mem_access_method { RISCV_MEM_ACCESS_PROGBUF, RISCV_MEM_ACCESS_SYSBUS, RISCV_MEM_ACCESS_ABSTRACT, RISCV_MEM_ACCESS_MAX_METHODS_NUM -} riscv_mem_access_method_t; +}; -typedef enum riscv_virt2phys_mode { +enum riscv_virt2phys_mode { RISCV_VIRT2PHYS_MODE_HW, RISCV_VIRT2PHYS_MODE_SW, RISCV_VIRT2PHYS_MODE_OFF -} riscv_virt2phys_mode_t; +}; -const char *riscv_virt2phys_mode_to_str(riscv_virt2phys_mode_t mode); +const char *riscv_virt2phys_mode_to_str(enum riscv_virt2phys_mode mode); enum riscv_halt_reason { RISCV_HALT_INTERRUPT, @@ -133,7 +133,7 @@ struct reg_name_table { char **reg_names; }; -typedef struct riscv_mem_access_args { +struct riscv_mem_access_args { target_addr_t address; const uint8_t *write_buffer; @@ -142,23 +142,23 @@ typedef struct riscv_mem_access_args { uint32_t size; uint32_t count; uint32_t increment; -} riscv_mem_access_args_t; +}; static inline bool -riscv_mem_access_is_valid(const riscv_mem_access_args_t args) +riscv_mem_access_is_valid(const struct riscv_mem_access_args args) { return !args.read_buffer != !args.write_buffer; } static inline bool -riscv_mem_access_is_read(const riscv_mem_access_args_t args) +riscv_mem_access_is_read(const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_valid(args)); return !args.write_buffer && args.read_buffer; } static inline bool -riscv_mem_access_is_write(const riscv_mem_access_args_t args) +riscv_mem_access_is_write(const struct riscv_mem_access_args args) { assert(riscv_mem_access_is_valid(args)); return !args.read_buffer && args.write_buffer; @@ -223,7 +223,7 @@ struct riscv_info { int64_t trigger_hit; /* The configured approach to translate virtual addresses to physical */ - riscv_virt2phys_mode_t virt2phys_mode; + enum riscv_virt2phys_mode virt2phys_mode; bool triggers_enumerated; @@ -303,7 +303,7 @@ struct riscv_info { riscv_sample_config_t *config, int64_t until_ms); - int (*access_memory)(struct target *target, const riscv_mem_access_args_t args); + int (*access_memory)(struct target *target, const struct riscv_mem_access_args args); unsigned int (*data_bits)(struct target *target); @@ -330,7 +330,7 @@ struct riscv_info { bool *reserved_triggers; /* Memory access methods to use, ordered by priority, highest to lowest. */ - riscv_mem_access_method_t mem_access_methods[RISCV_MEM_ACCESS_MAX_METHODS_NUM]; + enum riscv_mem_access_method mem_access_methods[RISCV_MEM_ACCESS_MAX_METHODS_NUM]; unsigned int num_enabled_mem_access_methods; @@ -356,7 +356,7 @@ struct riscv_info { /* Track when we were last asked to do something substantial. */ int64_t last_activity; - yes_no_maybe_t vsew64_supported; + enum yes_no_maybe vsew64_supported; bool range_trigger_fallback_encountered; @@ -480,7 +480,7 @@ int riscv_read_phys_memory(struct target *target, target_addr_t phys_address, int riscv_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); -int riscv_mmu(struct target *target, int *enabled); +int riscv_mmu(struct target *target, bool *enabled); int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical); const char *riscv_get_gdb_arch(const struct target *target); int riscv_get_gdb_reg_list_noread(struct target *target, diff --git a/src/target/riscv/riscv_reg.c b/src/target/riscv/riscv_reg.c index f1b1c5b7ad..09a2ad0231 100644 --- a/src/target/riscv/riscv_reg.c +++ b/src/target/riscv/riscv_reg.c @@ -325,17 +325,17 @@ uint32_t gdb_regno_size(const struct target *target, uint32_t regno) if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { const unsigned int csr_number = regno - GDB_REGNO_CSR0; switch (csr_number) { - case CSR_DCSR: - case CSR_MVENDORID: - case CSR_MCOUNTINHIBIT: + case CSR_DCSR: + case CSR_MVENDORID: + case CSR_MCOUNTINHIBIT: - case CSR_FFLAGS: - case CSR_FRM: - case CSR_FCSR: + case CSR_FFLAGS: + case CSR_FRM: + case CSR_FCSR: - case CSR_SCOUNTEREN: - case CSR_MCOUNTEREN: - return 32; + case CSR_SCOUNTEREN: + case CSR_MCOUNTEREN: + return 32; } } return riscv_xlen(target); @@ -393,154 +393,154 @@ bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno) assert(regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095); const unsigned int csr_number = regno - GDB_REGNO_CSR0; switch (csr_number) { - case CSR_FFLAGS: - case CSR_FRM: - case CSR_FCSR: - return riscv_supports_extension(target, 'F'); - case CSR_VSTART: - case CSR_VXSAT: - case CSR_VXRM: - case CSR_VL: - case CSR_VCSR: - case CSR_VTYPE: - return vlenb_exists(target); - case CSR_SCOUNTEREN: - case CSR_SSTATUS: - case CSR_STVEC: - case CSR_SIP: - case CSR_SIE: - case CSR_SSCRATCH: - case CSR_SEPC: - case CSR_SCAUSE: - case CSR_STVAL: - case CSR_SATP: - return riscv_supports_extension(target, 'S'); - 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." */ - return riscv_supports_extension(target, 'S') || - riscv_supports_extension(target, 'N'); - - case CSR_PMPCFG1: - case CSR_PMPCFG3: - case CSR_CYCLEH: - case CSR_TIMEH: - case CSR_INSTRETH: - case CSR_HPMCOUNTER3H: - case CSR_HPMCOUNTER4H: - case CSR_HPMCOUNTER5H: - case CSR_HPMCOUNTER6H: - case CSR_HPMCOUNTER7H: - case CSR_HPMCOUNTER8H: - case CSR_HPMCOUNTER9H: - case CSR_HPMCOUNTER10H: - case CSR_HPMCOUNTER11H: - case CSR_HPMCOUNTER12H: - case CSR_HPMCOUNTER13H: - case CSR_HPMCOUNTER14H: - case CSR_HPMCOUNTER15H: - case CSR_HPMCOUNTER16H: - case CSR_HPMCOUNTER17H: - case CSR_HPMCOUNTER18H: - case CSR_HPMCOUNTER19H: - case CSR_HPMCOUNTER20H: - case CSR_HPMCOUNTER21H: - case CSR_HPMCOUNTER22H: - case CSR_HPMCOUNTER23H: - case CSR_HPMCOUNTER24H: - case CSR_HPMCOUNTER25H: - case CSR_HPMCOUNTER26H: - case CSR_HPMCOUNTER27H: - case CSR_HPMCOUNTER28H: - case CSR_HPMCOUNTER29H: - case CSR_HPMCOUNTER30H: - case CSR_HPMCOUNTER31H: - case CSR_MCYCLEH: - case CSR_MINSTRETH: - case CSR_MHPMCOUNTER4H: - case CSR_MHPMCOUNTER5H: - case CSR_MHPMCOUNTER6H: - case CSR_MHPMCOUNTER7H: - case CSR_MHPMCOUNTER8H: - case CSR_MHPMCOUNTER9H: - case CSR_MHPMCOUNTER10H: - case CSR_MHPMCOUNTER11H: - case CSR_MHPMCOUNTER12H: - case CSR_MHPMCOUNTER13H: - case CSR_MHPMCOUNTER14H: - case CSR_MHPMCOUNTER15H: - case CSR_MHPMCOUNTER16H: - case CSR_MHPMCOUNTER17H: - case CSR_MHPMCOUNTER18H: - case CSR_MHPMCOUNTER19H: - case CSR_MHPMCOUNTER20H: - case CSR_MHPMCOUNTER21H: - case CSR_MHPMCOUNTER22H: - case CSR_MHPMCOUNTER23H: - case CSR_MHPMCOUNTER24H: - case CSR_MHPMCOUNTER25H: - case CSR_MHPMCOUNTER26H: - case CSR_MHPMCOUNTER27H: - case CSR_MHPMCOUNTER28H: - case CSR_MHPMCOUNTER29H: - case CSR_MHPMCOUNTER30H: - case CSR_MHPMCOUNTER31H: - return riscv_xlen(target) == 32; - case CSR_MCOUNTEREN: - return riscv_supports_extension(target, 'U'); - /* Interrupts M-Mode CSRs. */ - case CSR_MISELECT: - case CSR_MIREG: - case CSR_MVIEN: - case CSR_MVIP: - case CSR_MIEH: - case CSR_MIPH: - return reg_exists(target, GDB_REGNO_MTOPI); - case CSR_MIDELEGH: - case CSR_MVIENH: - case CSR_MVIPH: - return reg_exists(target, GDB_REGNO_MTOPI) && - riscv_xlen(target) == 32 && - riscv_supports_extension(target, 'S'); - /* Interrupts S-Mode CSRs. */ - case CSR_SISELECT: - case CSR_SIREG: - case CSR_STOPI: - return reg_exists(target, GDB_REGNO_MTOPI) && - riscv_supports_extension(target, 'S'); - case CSR_STOPEI: - return reg_exists(target, GDB_REGNO_MTOPEI) && - riscv_supports_extension(target, 'S'); - case CSR_SIEH: - case CSR_SIPH: - return reg_exists(target, GDB_REGNO_MTOPI) && - riscv_xlen(target) == 32 && - riscv_supports_extension(target, 'S'); - /* Interrupts Hypervisor and VS CSRs. */ - case CSR_HVIEN: - case CSR_HVICTL: - case CSR_HVIPRIO1: - case CSR_HVIPRIO2: - case CSR_VSISELECT: - case CSR_VSIREG: - case CSR_VSTOPI: - return reg_exists(target, GDB_REGNO_MTOPI) && - riscv_supports_extension(target, 'H'); - case CSR_VSTOPEI: - return reg_exists(target, GDB_REGNO_MTOPEI) && - riscv_supports_extension(target, 'H'); - case CSR_HIDELEGH: - case CSR_HVIENH: - case CSR_HVIPH: - case CSR_HVIPRIO1H: - case CSR_HVIPRIO2H: - case CSR_VSIEH: - case CSR_VSIPH: - return reg_exists(target, GDB_REGNO_MTOPI) && - riscv_xlen(target) == 32 && - riscv_supports_extension(target, 'H'); + case CSR_FFLAGS: + case CSR_FRM: + case CSR_FCSR: + return riscv_supports_extension(target, 'F'); + case CSR_VSTART: + case CSR_VXSAT: + case CSR_VXRM: + case CSR_VL: + case CSR_VCSR: + case CSR_VTYPE: + return vlenb_exists(target); + case CSR_SCOUNTEREN: + case CSR_SSTATUS: + case CSR_STVEC: + case CSR_SIP: + case CSR_SIE: + case CSR_SSCRATCH: + case CSR_SEPC: + case CSR_SCAUSE: + case CSR_STVAL: + case CSR_SATP: + return riscv_supports_extension(target, 'S'); + 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." */ + return riscv_supports_extension(target, 'S') || + riscv_supports_extension(target, 'N'); + + case CSR_PMPCFG1: + case CSR_PMPCFG3: + case CSR_CYCLEH: + case CSR_TIMEH: + case CSR_INSTRETH: + case CSR_HPMCOUNTER3H: + case CSR_HPMCOUNTER4H: + case CSR_HPMCOUNTER5H: + case CSR_HPMCOUNTER6H: + case CSR_HPMCOUNTER7H: + case CSR_HPMCOUNTER8H: + case CSR_HPMCOUNTER9H: + case CSR_HPMCOUNTER10H: + case CSR_HPMCOUNTER11H: + case CSR_HPMCOUNTER12H: + case CSR_HPMCOUNTER13H: + case CSR_HPMCOUNTER14H: + case CSR_HPMCOUNTER15H: + case CSR_HPMCOUNTER16H: + case CSR_HPMCOUNTER17H: + case CSR_HPMCOUNTER18H: + case CSR_HPMCOUNTER19H: + case CSR_HPMCOUNTER20H: + case CSR_HPMCOUNTER21H: + case CSR_HPMCOUNTER22H: + case CSR_HPMCOUNTER23H: + case CSR_HPMCOUNTER24H: + case CSR_HPMCOUNTER25H: + case CSR_HPMCOUNTER26H: + case CSR_HPMCOUNTER27H: + case CSR_HPMCOUNTER28H: + case CSR_HPMCOUNTER29H: + case CSR_HPMCOUNTER30H: + case CSR_HPMCOUNTER31H: + case CSR_MCYCLEH: + case CSR_MINSTRETH: + case CSR_MHPMCOUNTER4H: + case CSR_MHPMCOUNTER5H: + case CSR_MHPMCOUNTER6H: + case CSR_MHPMCOUNTER7H: + case CSR_MHPMCOUNTER8H: + case CSR_MHPMCOUNTER9H: + case CSR_MHPMCOUNTER10H: + case CSR_MHPMCOUNTER11H: + case CSR_MHPMCOUNTER12H: + case CSR_MHPMCOUNTER13H: + case CSR_MHPMCOUNTER14H: + case CSR_MHPMCOUNTER15H: + case CSR_MHPMCOUNTER16H: + case CSR_MHPMCOUNTER17H: + case CSR_MHPMCOUNTER18H: + case CSR_MHPMCOUNTER19H: + case CSR_MHPMCOUNTER20H: + case CSR_MHPMCOUNTER21H: + case CSR_MHPMCOUNTER22H: + case CSR_MHPMCOUNTER23H: + case CSR_MHPMCOUNTER24H: + case CSR_MHPMCOUNTER25H: + case CSR_MHPMCOUNTER26H: + case CSR_MHPMCOUNTER27H: + case CSR_MHPMCOUNTER28H: + case CSR_MHPMCOUNTER29H: + case CSR_MHPMCOUNTER30H: + case CSR_MHPMCOUNTER31H: + return riscv_xlen(target) == 32; + case CSR_MCOUNTEREN: + return riscv_supports_extension(target, 'U'); + /* Interrupts M-Mode CSRs. */ + case CSR_MISELECT: + case CSR_MIREG: + case CSR_MVIEN: + case CSR_MVIP: + case CSR_MIEH: + case CSR_MIPH: + return reg_exists(target, GDB_REGNO_MTOPI); + case CSR_MIDELEGH: + case CSR_MVIENH: + case CSR_MVIPH: + return reg_exists(target, GDB_REGNO_MTOPI) && + riscv_xlen(target) == 32 && + riscv_supports_extension(target, 'S'); + /* Interrupts S-Mode CSRs. */ + case CSR_SISELECT: + case CSR_SIREG: + case CSR_STOPI: + return reg_exists(target, GDB_REGNO_MTOPI) && + riscv_supports_extension(target, 'S'); + case CSR_STOPEI: + return reg_exists(target, GDB_REGNO_MTOPEI) && + riscv_supports_extension(target, 'S'); + case CSR_SIEH: + case CSR_SIPH: + return reg_exists(target, GDB_REGNO_MTOPI) && + riscv_xlen(target) == 32 && + riscv_supports_extension(target, 'S'); + /* Interrupts Hypervisor and VS CSRs. */ + case CSR_HVIEN: + case CSR_HVICTL: + case CSR_HVIPRIO1: + case CSR_HVIPRIO2: + case CSR_VSISELECT: + case CSR_VSIREG: + case CSR_VSTOPI: + return reg_exists(target, GDB_REGNO_MTOPI) && + riscv_supports_extension(target, 'H'); + case CSR_VSTOPEI: + return reg_exists(target, GDB_REGNO_MTOPEI) && + riscv_supports_extension(target, 'H'); + case CSR_HIDELEGH: + case CSR_HVIENH: + case CSR_HVIPH: + case CSR_HVIPRIO1H: + case CSR_HVIPRIO2H: + case CSR_VSIEH: + case CSR_VSIPH: + return reg_exists(target, GDB_REGNO_MTOPI) && + riscv_xlen(target) == 32 && + riscv_supports_extension(target, 'H'); } return is_known_standard_csr(csr_number); } diff --git a/src/target/riscv/riscv_reg_impl.h b/src/target/riscv/riscv_reg_impl.h index 67d746c0ba..d38d4146ed 100644 --- a/src/target/riscv/riscv_reg_impl.h +++ b/src/target/riscv/riscv_reg_impl.h @@ -194,30 +194,31 @@ static inline bool riscv_reg_impl_gdb_regno_cacheable(enum gdb_regno regno, /* Most CSRs won't change value on us, but we can't assume it about arbitrary * CSRs. */ switch (regno) { - case GDB_REGNO_DPC: - case GDB_REGNO_VLENB: - case GDB_REGNO_MISA: - case GDB_REGNO_DCSR: - case GDB_REGNO_DSCRATCH0: - case GDB_REGNO_MEPC: - 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 !is_write; - - case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */ - case GDB_REGNO_TDATA1: /* Changes value when tselect is changed. */ - case GDB_REGNO_TDATA2: /* Changes value when tselect is changed. */ - case GDB_REGNO_VSTART: /* Changes value when vtype is changed. */ - case GDB_REGNO_VL: /* Changes value when vtype is changed. */ - case GDB_REGNO_VTYPE: /* Writes to vtype have side effects, so we don't cache it. */ - case GDB_REGNO_VXSAT: /* Changes value when vcsr is changed. */ - case GDB_REGNO_VXRM: /* Changes value when vcsr is changed. */ - case GDB_REGNO_VCSR: /* Changes when vxrm or vxsat are changed. */ - default: - return false; + case GDB_REGNO_DPC: + case GDB_REGNO_VLENB: + case GDB_REGNO_MISA: + case GDB_REGNO_DCSR: + case GDB_REGNO_MEPC: + 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 !is_write; + + case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */ + case GDB_REGNO_TDATA1: /* Changes value when tselect is changed. */ + case GDB_REGNO_TDATA2: /* Changes value when tselect is changed. */ + case GDB_REGNO_DSCRATCH0: /* Dscratch* need not retain value between abstract commands. */ + case GDB_REGNO_DSCRATCH1: + case GDB_REGNO_VSTART: /* Changes value when vtype is changed. */ + case GDB_REGNO_VL: /* Changes value when vtype is changed. */ + case GDB_REGNO_VTYPE: /* Writes to vtype have side effects, so we don't cache it. */ + case GDB_REGNO_VXSAT: /* Changes value when vcsr is changed. */ + case GDB_REGNO_VXRM: /* Changes value when vcsr is changed. */ + case GDB_REGNO_VCSR: /* Changes when vxrm or vxsat are changed. */ + default: + return false; } } #endif /* OPENOCD_TARGET_RISCV_RISCV_REG_IMPL_H */ diff --git a/src/target/riscv/scr5.c b/src/target/riscv/scr5.c index 15946053a7..f52b9533df 100644 --- a/src/target/riscv/scr5.c +++ b/src/target/riscv/scr5.c @@ -281,7 +281,7 @@ static int scr5_virt2phys(struct target *target, target_addr_t virt_addr, return riscv_virt2phys(target, virt_addr, phys_addr); } - int mmu_enabled; + bool mmu_enabled; int res = riscv_mmu(target, &mmu_enabled); if (res != ERROR_OK) return res; diff --git a/src/target/rtt.c b/src/target/rtt.c index 5ce049ae18..0dd82f5c7d 100644 --- a/src/target/rtt.c +++ b/src/target/rtt.c @@ -18,32 +18,74 @@ #include "target.h" +// Offsets for RTT control block parameters. +struct rtt_control_params { + unsigned int channel_size; + unsigned int buffer_addr_offset; + unsigned int size_offset; + unsigned int write_pos_offset; + unsigned int read_pos_offset; + unsigned int flags_offset; +}; + +// Offsets for 32-bit architecture. +static const struct rtt_control_params rtt_params_32 = { + .channel_size = RTT_CHANNEL_SIZE_32, + .buffer_addr_offset = 4, + .size_offset = 8, + .write_pos_offset = 12, + .read_pos_offset = 16, + .flags_offset = 20 +}; + +// Offsets for 64-bit architecture. +static const struct rtt_control_params rtt_params_64 = { + .channel_size = RTT_CHANNEL_SIZE_64, + .buffer_addr_offset = 8, + .size_offset = 16, + .write_pos_offset = 20, + .read_pos_offset = 24, + .flags_offset = 28 +}; + +static const struct rtt_control_params *get_rtt_params(struct target *target) +{ + if (target_address_bits(target) == 64) + return &rtt_params_64; + return &rtt_params_32; +} + 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]; + uint8_t buf[RTT_CHANNEL_SIZE_64]; target_addr_t address; + const struct rtt_control_params *params = get_rtt_params(target); - address = ctrl->address + RTT_CB_SIZE + (channel_index * RTT_CHANNEL_SIZE); + address = ctrl->address + RTT_CB_SIZE + (channel_index * params->channel_size); if (type == RTT_CHANNEL_TYPE_DOWN) - address += ctrl->num_up_channels * RTT_CHANNEL_SIZE; + address += ctrl->num_up_channels * params->channel_size; - ret = target_read_buffer(target, address, RTT_CHANNEL_SIZE, buf); + ret = target_read_buffer(target, address, params->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); - + if (target_address_bits(target) == 64) { + channel->name_addr = target_buffer_get_u64(target, buf + 0); + channel->buffer_addr = target_buffer_get_u64(target, buf + params->buffer_addr_offset); + } else { + channel->name_addr = target_buffer_get_u32(target, buf + 0); + channel->buffer_addr = target_buffer_get_u32(target, buf + params->buffer_addr_offset); + } + channel->size = target_buffer_get_u32(target, buf + params->size_offset); + channel->write_pos = target_buffer_get_u32(target, buf + params->write_pos_offset); + channel->read_pos = target_buffer_get_u32(target, buf + params->read_pos_offset); + channel->flags = target_buffer_get_u32(target, buf + params->flags_offset); return ERROR_OK; } @@ -157,7 +199,8 @@ static int write_to_channel(struct target *target, return ret; } - ret = target_write_u32(target, channel->address + 12, + const struct rtt_control_params *params = get_rtt_params(target); + ret = target_write_u32(target, channel->address + params->write_pos_offset, (channel->write_pos + len) % channel->size); if (ret != ERROR_OK) @@ -230,10 +273,8 @@ int target_rtt_read_control_block(struct target *target, 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); + ctrl->num_up_channels = target_buffer_get_u32(target, buf + RTT_CB_MAX_ID_LENGTH + 0); + ctrl->num_down_channels = target_buffer_get_u32(target, buf + RTT_CB_MAX_ID_LENGTH + 4); return ERROR_OK; } @@ -298,15 +339,18 @@ int target_rtt_read_channel_info(struct target *target, return ret; } + info->size = channel.size; + info->flags = channel.flags; + + if (!channel_is_active(&channel)) + return ERROR_OK; + 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; } @@ -351,7 +395,8 @@ static int read_from_channel(struct target *target, } if (len > 0) { - ret = target_write_u32(target, channel->address + 16, + const struct rtt_control_params *params = get_rtt_params(target); + ret = target_write_u32(target, channel->address + params->read_pos_offset, (channel->read_pos + len) % channel->size); if (ret != ERROR_OK) diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index ffcd3aafde..bcf37b6ad3 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -24,8 +24,10 @@ * instruction trapped by the debugger. * * Details can be found in - * "Semihosting for AArch32 and AArch64, Release 2.0" - * https://static.docs.arm.com/100863/0200/semihosting.pdf + * "Semihosting for AArch32 and AArch64, 2025Q1" + * https://github.com/ARM-software/abi-aa/releases/download/2025Q1/semihosting.pdf + * and in + * https://developer.arm.com/documentation/dui0203/latest/semihosting * from ARM Ltd. */ @@ -308,60 +310,60 @@ static char *semihosting_user_op_params; static 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 ""; + 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 ""; } } @@ -399,1244 +401,1239 @@ int semihosting_common(struct target *target) semihosting->param); switch (semihosting->op) { + case SEMIHOSTING_SYS_CLOCK: /* 0x10 */ + /* + * Returns the number of centiseconds (hundredths of a second) + * since the execution started. + * + * Values returned can be of limited use for some benchmarking + * purposes because of communication overhead or other + * agent-specific factors. For example, with a debug hardware + * unit the request is passed back to the host for execution. + * This can lead to unpredictable delays in transmission and + * process scheduling. + * + * Use this function to calculate time intervals, by calculating + * differences between intervals with and without the code + * sequence to be timed. + * + * Entry + * The PARAMETER REGISTER must contain 0. There are no other + * parameters. + * + * Return + * On exit, the RETURN REGISTER contains: + * - The number of centiseconds since some arbitrary start + * point, if the call is successful. + * - –1 if the call is not successful. For example, because + * of a communications error. + */ + { + clock_t delta = clock() - semihosting->setup_time; - case SEMIHOSTING_SYS_CLOCK: /* 0x10 */ - /* - * Returns the number of centiseconds (hundredths of a second) - * since the execution started. - * - * Values returned can be of limited use for some benchmarking - * purposes because of communication overhead or other - * agent-specific factors. For example, with a debug hardware - * unit the request is passed back to the host for execution. - * This can lead to unpredictable delays in transmission and - * process scheduling. - * - * Use this function to calculate time intervals, by calculating - * differences between intervals with and without the code - * sequence to be timed. - * - * Entry - * The PARAMETER REGISTER must contain 0. There are no other - * parameters. - * - * Return - * On exit, the RETURN REGISTER contains: - * - The number of centiseconds since some arbitrary start - * point, if the call is successful. - * - –1 if the call is not successful. For example, because - * of a communications error. - */ - { - clock_t delta = clock() - semihosting->setup_time; + semihosting->result = delta / (CLOCKS_PER_SEC / 100); + } + break; + + case SEMIHOSTING_SYS_CLOSE: /* 0x02 */ + /* + * Closes a file on the host system. The handle must reference + * a file that was opened with SYS_OPEN. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field argument block: + * - field 1 Contains a handle for an open file. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the call is successful + * - –1 if the call is not successful. + */ + retval = semihosting_read_fields(target, 1, fields); + if (retval != ERROR_OK) + return retval; - semihosting->result = delta / (CLOCKS_PER_SEC / 100); + { + 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) { + semihosting->hit_fileio = true; + fileio_info->identifier = "close"; + fileio_info->param_1 = fd; + } else { + semihosting->result = close(fd); + if (semihosting->result == -1) + semihosting->sys_errno = errno; + LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result); + } } break; - case SEMIHOSTING_SYS_CLOSE: /* 0x02 */ - /* - * Closes a file on the host system. The handle must reference - * a file that was opened with SYS_OPEN. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * one-field argument block: - * - field 1 Contains a handle for an open file. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the call is successful - * - –1 if the call is not successful. - */ - retval = semihosting_read_fields(target, 1, fields); + case SEMIHOSTING_SYS_ERRNO: /* 0x13 */ + /* + * Returns the value of the C library errno variable that is + * associated with the semihosting implementation. The errno + * variable can be set by a number of C library semihosted + * functions, including: + * - SYS_REMOVE + * - SYS_OPEN + * - SYS_CLOSE + * - SYS_READ + * - SYS_WRITE + * - SYS_SEEK. + * + * Whether errno is set or not, and to what value, is entirely + * host-specific, except where the ISO C standard defines the + * behavior. + * + * Entry + * There are no parameters. The PARAMETER REGISTER must be 0. + * + * Return + * On exit, the RETURN REGISTER contains the value of the C + * library errno variable. + */ + semihosting->result = semihosting->sys_errno; + break; + + case SEMIHOSTING_SYS_EXIT: /* 0x18 */ + /* + * Note: SYS_EXIT was called angel_SWIreason_ReportException in + * previous versions of the documentation. + * + * An application calls this operation to report an exception + * to the debugger directly. The most common use is to report + * that execution has completed, using ADP_Stopped_ApplicationExit. + * + * Note: This semihosting operation provides no means for 32-bit + * callers to indicate an application exit with a specified exit + * code. Semihosting callers may prefer to check for the presence + * of the SH_EXT_EXTENDED_REPORT_EXCEPTION extension and use + * the SYS_REPORT_EXCEPTION_EXTENDED operation instead, if it + * is available. + * + * Entry (32-bit) + * On entry, the PARAMETER register is set to a reason code + * describing the cause of the trap. Not all semihosting client + * implementations will necessarily trap every corresponding + * event. Important reason codes are: + * + * - ADP_Stopped_ApplicationExit 0x20026 + * - ADP_Stopped_RunTimeErrorUnknown 0x20023 + * + * Entry (64-bit) + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 The exception type, which is one of the set of + * reason codes in the above tables. + * - field 2 A subcode, whose meaning depends on the reason + * code in field 1. + * In particular, if field 1 is ADP_Stopped_ApplicationExit + * then field 2 is an exit status code, as passed to the C + * standard library exit() function. A simulator receiving + * this request must notify a connected debugger, if present, + * and then exit with the specified status. + * + * Return + * No return is expected from these calls. However, it is + * possible for the debugger to request that the application + * continues by performing an RDI_Execute request or equivalent. + * In this case, execution continues with the registers as they + * were on entry to the operation, or as subsequently modified + * by the debugger. + */ + if (semihosting->word_size_bytes == 8) { + retval = semihosting_read_fields(target, 2, fields); if (retval != ERROR_OK) 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) { - semihosting->hit_fileio = true; - fileio_info->identifier = "close"; - fileio_info->param_1 = fd; - } else { - semihosting->result = close(fd); - if (semihosting->result == -1) - semihosting->sys_errno = errno; - LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result); - } - } - break; - case SEMIHOSTING_SYS_ERRNO: /* 0x13 */ - /* - * Returns the value of the C library errno variable that is - * associated with the semihosting implementation. The errno - * variable can be set by a number of C library semihosted - * functions, including: - * - SYS_REMOVE - * - SYS_OPEN - * - SYS_CLOSE - * - SYS_READ - * - SYS_WRITE - * - SYS_SEEK. - * - * Whether errno is set or not, and to what value, is entirely - * host-specific, except where the ISO C standard defines the - * behavior. - * - * Entry - * There are no parameters. The PARAMETER REGISTER must be 0. - * - * Return - * On exit, the RETURN REGISTER contains the value of the C - * library errno variable. - */ - semihosting->result = semihosting->sys_errno; - break; + int type = semihosting_get_field(target, 0, fields); + int code = semihosting_get_field(target, 1, fields); - case SEMIHOSTING_SYS_EXIT: /* 0x18 */ - /* - * Note: SYS_EXIT was called angel_SWIreason_ReportException in - * previous versions of the documentation. - * - * An application calls this operation to report an exception - * to the debugger directly. The most common use is to report - * that execution has completed, using ADP_Stopped_ApplicationExit. - * - * Note: This semihosting operation provides no means for 32-bit - * callers to indicate an application exit with a specified exit - * code. Semihosting callers may prefer to check for the presence - * of the SH_EXT_EXTENDED_REPORT_EXCEPTION extension and use - * the SYS_REPORT_EXCEPTION_EXTENDED operation instead, if it - * is available. - * - * Entry (32-bit) - * On entry, the PARAMETER register is set to a reason code - * describing the cause of the trap. Not all semihosting client - * implementations will necessarily trap every corresponding - * event. Important reason codes are: - * - * - ADP_Stopped_ApplicationExit 0x20026 - * - ADP_Stopped_RunTimeErrorUnknown 0x20023 - * - * Entry (64-bit) - * On entry, the PARAMETER REGISTER contains a pointer to a - * two-field argument block: - * - field 1 The exception type, which is one of the set of - * reason codes in the above tables. - * - field 2 A subcode, whose meaning depends on the reason - * code in field 1. - * In particular, if field 1 is ADP_Stopped_ApplicationExit - * then field 2 is an exit status code, as passed to the C - * standard library exit() function. A simulator receiving - * this request must notify a connected debugger, if present, - * and then exit with the specified status. - * - * Return - * No return is expected from these calls. However, it is - * possible for the debugger to request that the application - * continues by performing an RDI_Execute request or equivalent. - * In this case, execution continues with the registers as they - * were on entry to the operation, or as subsequently modified - * by the debugger. - */ - if (semihosting->word_size_bytes == 8) { - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - int type = semihosting_get_field(target, 0, fields); - int code = semihosting_get_field(target, 1, fields); - - if (type == ADP_STOPPED_APPLICATION_EXIT) { - if (!gdb_get_actual_connections()) - exit(code); - else { - fprintf(stderr, - "semihosting: *** application exited with %d ***\n", - code); - } - } else { - fprintf(stderr, - "semihosting: application exception %#x\n", - type); - } - } + if (type == ADP_STOPPED_APPLICATION_EXIT) { + if (!gdb_get_actual_connections()) + exit(code); + + fprintf(stderr, + "semihosting: *** application exited with %d ***\n", + code); } else { - if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) { - if (!gdb_get_actual_connections()) - exit(0); - else { - fprintf(stderr, - "semihosting: *** application exited normally ***\n"); - } - } 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_get_actual_connections()) - exit(1); - else { - fprintf(stderr, - "semihosting: *** application exited with error ***\n"); - } - } else { - if (!gdb_get_actual_connections()) - exit(1); - else { - fprintf(stderr, - "semihosting: application exception %#x\n", - (unsigned) semihosting->param); - } - } - } - if (!semihosting->has_resumable_exit) { - semihosting->is_resumable = false; - return target_call_event_callbacks(target, TARGET_EVENT_HALTED); + fprintf(stderr, + "semihosting: application exception %#x\n", type); } - break; + } else { + if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) { + if (!gdb_get_actual_connections()) + exit(0); + + fprintf(stderr, + "semihosting: *** application exited normally ***\n"); + } 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_get_actual_connections()) + exit(1); + + fprintf(stderr, + "semihosting: *** application exited with error ***\n"); + } else { + if (!gdb_get_actual_connections()) + exit(1); - case SEMIHOSTING_SYS_EXIT_EXTENDED: /* 0x20 */ - /* - * This operation is only supported if the semihosting extension - * SH_EXT_EXIT_EXTENDED is implemented. SH_EXT_EXIT_EXTENDED is - * reported using feature byte 0, bit 0. If this extension is - * supported, then the implementation provides a means to - * report a normal exit with a nonzero exit status in both 32-bit - * and 64-bit semihosting APIs. - * - * The implementation must provide the semihosting call - * SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs. - * - * SYS_EXIT_EXTENDED is used by an application to report an - * exception or exit to the debugger directly. The most common - * use is to report that execution has completed, using - * ADP_Stopped_ApplicationExit. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * two-field argument block: - * - field 1 The exception type, which should be one of the set - * of reason codes that are documented for the SYS_EXIT - * (0x18) call. For example, ADP_Stopped_ApplicationExit. - * - field 2 A subcode, whose meaning depends on the reason - * code in field 1. In particular, if field 1 is - * ADP_Stopped_ApplicationExit then field 2 is an exit status - * code, as passed to the C standard library exit() function. - * A simulator receiving this request must notify a connected - * debugger, if present, and then exit with the specified status. - * - * Return - * No return is expected from these calls. - * - * For the A64 API, this call is identical to the behavior of - * the mandatory SYS_EXIT (0x18) call. If this extension is - * supported, then both calls must be implemented. - */ - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - int type = semihosting_get_field(target, 0, fields); - int code = semihosting_get_field(target, 1, fields); - - if (type == ADP_STOPPED_APPLICATION_EXIT) { - if (!gdb_get_actual_connections()) - exit(code); - else { - fprintf(stderr, - "semihosting: *** application exited with %d ***\n", - code); - } - } else { - fprintf(stderr, "semihosting: exception %#x\n", - type); - } + fprintf(stderr, + "semihosting: application exception %#x\n", + (unsigned int)semihosting->param); } - if (!semihosting->has_resumable_exit) { - semihosting->is_resumable = false; - return target_call_event_callbacks(target, TARGET_EVENT_HALTED); - } - break; + } + if (!semihosting->has_resumable_exit) { + semihosting->is_resumable = false; + return target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + break; - case SEMIHOSTING_SYS_FLEN: /* 0x0C */ - /* - * Returns the length of a specified file. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * one-field argument block: - * - field 1 A handle for a previously opened, seekable file - * object. - * - * Return - * On exit, the RETURN REGISTER contains: - * - The current length of the file object, if the call is - * successful. - * - –1 if an error occurs. - */ - if (semihosting->is_fileio) { - semihosting->result = -1; - semihosting->sys_errno = EINVAL; + case SEMIHOSTING_SYS_EXIT_EXTENDED: /* 0x20 */ + /* + * This operation is only supported if the semihosting extension + * SH_EXT_EXIT_EXTENDED is implemented. SH_EXT_EXIT_EXTENDED is + * reported using feature byte 0, bit 0. If this extension is + * supported, then the implementation provides a means to + * report a normal exit with a nonzero exit status in both 32-bit + * and 64-bit semihosting APIs. + * + * The implementation must provide the semihosting call + * SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs. + * + * SYS_EXIT_EXTENDED is used by an application to report an + * exception or exit to the debugger directly. The most common + * use is to report that execution has completed, using + * ADP_Stopped_ApplicationExit. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 The exception type, which should be one of the set + * of reason codes that are documented for the SYS_EXIT + * (0x18) call. For example, ADP_Stopped_ApplicationExit. + * - field 2 A subcode, whose meaning depends on the reason + * code in field 1. In particular, if field 1 is + * ADP_Stopped_ApplicationExit then field 2 is an exit status + * code, as passed to the C standard library exit() function. + * A simulator receiving this request must notify a connected + * debugger, if present, and then exit with the specified status. + * + * Return + * No return is expected from these calls. + * + * For the A64 API, this call is identical to the behavior of + * the mandatory SYS_EXIT (0x18) call. If this extension is + * supported, then both calls must be implemented. + */ + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) + return retval; + + { + int type = semihosting_get_field(target, 0, fields); + int code = semihosting_get_field(target, 1, fields); + + if (type == ADP_STOPPED_APPLICATION_EXIT) { + if (!gdb_get_actual_connections()) + exit(code); + + fprintf(stderr, + "semihosting: *** application exited with %d ***\n", + code); + } else { + fprintf(stderr, "semihosting: exception %#x\n", type); } - retval = semihosting_read_fields(target, 1, fields); - if (retval != ERROR_OK) - return retval; - else { - int fd = semihosting_get_field(target, 0, fields); - struct stat buf; - semihosting->result = fstat(fd, &buf); - if (semihosting->result == -1) { - semihosting->sys_errno = errno; - LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result); - break; - } + } + if (!semihosting->has_resumable_exit) { + semihosting->is_resumable = false; + return target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + break; + + case SEMIHOSTING_SYS_FLEN: /* 0x0C */ + /* + * Returns the length of a specified file. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field argument block: + * - field 1 A handle for a previously opened, seekable file + * object. + * + * Return + * On exit, the RETURN REGISTER contains: + * - The current length of the file object, if the call is + * successful. + * - –1 if an error occurs. + */ + if (semihosting->is_fileio) { + semihosting->result = -1; + semihosting->sys_errno = EINVAL; + } + retval = semihosting_read_fields(target, 1, fields); + if (retval != ERROR_OK) + return retval; + + { + int fd = semihosting_get_field(target, 0, fields); + struct stat buf; + semihosting->result = fstat(fd, &buf); + if (semihosting->result == -1) { + semihosting->sys_errno = errno; LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result); - semihosting->result = buf.st_size; + break; } - break; + LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result); + semihosting->result = buf.st_size; + } + break; - case SEMIHOSTING_SYS_GET_CMDLINE: /* 0x15 */ - /* - * Returns the command line that is used for the call to the - * executable, that is, argc and argv. - * - * Entry - * On entry, the PARAMETER REGISTER points to a two-field data - * block to be used for returning the command string and its length: - * - field 1 A pointer to a buffer of at least the size that is - * specified in field 2. - * - field 2 The length of the buffer in bytes. - * - * Return - * On exit: - * If the call is successful, then the RETURN REGISTER contains 0, - * the PARAMETER REGISTER is unchanged, and the data block is - * updated as follows: - * - field 1 A pointer to a null-terminated string of the command - * line. - * - field 2 The length of the string in bytes. - * If the call is not successful, then the RETURN REGISTER - * contains -1. - * - * Note: The semihosting implementation might impose limits on - * the maximum length of the string that can be transferred. - * However, the implementation must be able to support a - * command-line length of at least 80 bytes. - */ - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - uint64_t addr = semihosting_get_field(target, 0, fields); - size_t size = semihosting_get_field(target, 1, fields); - - char *arg = semihosting->cmdline ? - semihosting->cmdline : ""; - uint32_t len = strlen(arg) + 1; - if (len > size) - semihosting->result = -1; - else { - semihosting_set_field(target, len, 1, fields); - retval = target_write_buffer(target, addr, len, - (uint8_t *)arg); - if (retval != ERROR_OK) - return retval; - semihosting->result = 0; + case SEMIHOSTING_SYS_GET_CMDLINE: /* 0x15 */ + /* + * Returns the command line that is used for the call to the + * executable, that is, argc and argv. + * + * Entry + * On entry, the PARAMETER REGISTER points to a two-field data + * block to be used for returning the command string and its length: + * - field 1 A pointer to a buffer of at least the size that is + * specified in field 2. + * - field 2 The length of the buffer in bytes. + * + * Return + * On exit: + * If the call is successful, then the RETURN REGISTER contains 0, + * the PARAMETER REGISTER is unchanged, and the data block is + * updated as follows: + * - field 1 A pointer to a null-terminated string of the command + * line. + * - field 2 The length of the string in bytes. + * If the call is not successful, then the RETURN REGISTER + * contains -1. + * + * Note: The semihosting implementation might impose limits on + * the maximum length of the string that can be transferred. + * However, the implementation must be able to support a + * command-line length of at least 80 bytes. + */ + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) + return retval; - retval = semihosting_write_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - } - LOG_DEBUG("SYS_GET_CMDLINE=[%s], %" PRId64, arg, semihosting->result); - } - break; + { + uint64_t addr = semihosting_get_field(target, 0, fields); + size_t size = semihosting_get_field(target, 1, fields); - case SEMIHOSTING_SYS_HEAPINFO: /* 0x16 */ - /* - * Returns the system stack and heap parameters. - * - * Entry - * On entry, the PARAMETER REGISTER contains the address of a - * pointer to a four-field data block. The contents of the data - * block are filled by the function. The following C-like - * pseudocode describes the layout of the block: - * struct block { - * void* heap_base; - * void* heap_limit; - * void* stack_base; - * void* stack_limit; - * }; - * - * Return - * On exit, the PARAMETER REGISTER is unchanged and the data - * block has been updated. - */ - retval = semihosting_read_fields(target, 1, fields); - if (retval != ERROR_OK) - return retval; - else { - uint64_t addr = semihosting_get_field(target, 0, fields); - /* tell the remote we have no idea */ - memset(fields, 0, 4 * semihosting->word_size_bytes); - retval = target_write_memory(target, addr, 4, - semihosting->word_size_bytes, - fields); + char *arg = semihosting->cmdline ? semihosting->cmdline : ""; + uint32_t len = strlen(arg) + 1; + if (len > size) { + semihosting->result = -1; + } else { + semihosting_set_field(target, len, 1, fields); + retval = target_write_buffer(target, addr, len, + (uint8_t *)arg); if (retval != ERROR_OK) return retval; semihosting->result = 0; - } - break; - case SEMIHOSTING_SYS_ISERROR: /* 0x08 */ - /* - * Determines whether the return code from another semihosting - * call is an error status or not. - * - * This call is passed a parameter block containing the error - * code to examine. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * one-field data block: - * - field 1 The required status word to check. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the status field is not an error indication - * - A nonzero value if the status field is an error indication. - */ - retval = semihosting_read_fields(target, 1, fields); - if (retval != ERROR_OK) - return retval; - - uint64_t code = semihosting_get_field(target, 0, fields); - semihosting->result = (code != 0); - break; - - case SEMIHOSTING_SYS_ISTTY: /* 0x09 */ - /* - * Checks whether a file is connected to an interactive device. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * one-field argument block: - * field 1 A handle for a previously opened file object. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 1 if the handle identifies an interactive device. - * - 0 if the handle identifies a file. - * - A value other than 1 or 0 if an error occurs. - */ - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "isatty"; - fileio_info->param_1 = semihosting->param; - } else { - retval = semihosting_read_fields(target, 1, fields); + retval = semihosting_write_fields(target, 2, fields); if (retval != ERROR_OK) return retval; - int fd = semihosting_get_field(target, 0, fields); - // 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; + LOG_DEBUG("SYS_GET_CMDLINE=[%s], %" PRId64, arg, semihosting->result); + } + break; + + case SEMIHOSTING_SYS_HEAPINFO: /* 0x16 */ + /* + * Returns the system stack and heap parameters. + * + * Entry + * On entry, the PARAMETER REGISTER contains the address of a + * pointer to a four-field data block. The contents of the data + * block are filled by the function. The following C-like + * pseudocode describes the layout of the block: + * struct block { + * void* heap_base; + * void* heap_limit; + * void* stack_base; + * void* stack_limit; + * }; + * + * Return + * On exit, the PARAMETER REGISTER is unchanged and the data + * block has been updated. + */ + retval = semihosting_read_fields(target, 1, fields); + if (retval != ERROR_OK) + return retval; - case SEMIHOSTING_SYS_OPEN: /* 0x01 */ - /* - * Opens a file on the host system. - * - * The file path is specified either as relative to the current - * directory of the host process, or absolute, using the path - * conventions of the host operating system. - * - * Semihosting implementations must support opening the special - * path name :semihosting-features as part of the semihosting - * extensions reporting mechanism. - * - * ARM targets interpret the special path name :tt as meaning - * the console input stream, for an open-read or the console - * output stream, for an open-write. Opening these streams is - * performed as part of the standard startup code for those - * applications that reference the C stdio streams. The - * semihosting extension SH_EXT_STDOUT_STDERR allows the - * semihosting caller to open separate output streams - * corresponding to stdout and stderr. This extension is - * reported using feature byte 0, bit 1. Use SYS_OPEN with - * the special path name :semihosting-features to access the - * feature bits. - * - * If this extension is supported, the implementation must - * support the following additional semantics to SYS_OPEN: - * - If the special path name :tt is opened with an fopen - * mode requesting write access (w, wb, w+, or w+b), then - * this is a request to open stdout. - * - If the special path name :tt is opened with a mode - * requesting append access (a, ab, a+, or a+b), then this is - * a request to open stderr. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * three-field argument block: - * - field 1 A pointer to a null-terminated string containing - * a file or device name. - * - field 2 An integer that specifies the file opening mode. - * - field 3 An integer that gives the length of the string - * pointed to by field 1. - * - * The length does not include the terminating null character - * that must be present. - * - * Return - * On exit, the RETURN REGISTER contains: - * - A nonzero handle if the call is successful. - * - –1 if the call is not successful. - */ - retval = semihosting_read_fields(target, 3, fields); + { + uint64_t addr = semihosting_get_field(target, 0, fields); + /* tell the remote we have no idea */ + memset(fields, 0, 4 * semihosting->word_size_bytes); + retval = target_write_memory(target, addr, 4, + semihosting->word_size_bytes, + fields); if (retval != ERROR_OK) return retval; - else { - uint64_t addr = semihosting_get_field(target, 0, fields); - uint32_t mode = semihosting_get_field(target, 1, fields); - size_t len = semihosting_get_field(target, 2, fields); + semihosting->result = 0; + } + break; - if (mode > 11) { - semihosting->result = -1; - semihosting->sys_errno = EINVAL; - break; - } - 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 { - 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[basedir_len + len] = 0; - /* TODO: implement the :semihosting-features special file. - * */ - if (semihosting->is_fileio) { - if (strcmp((char *)fn, ":semihosting-features") == 0) { - semihosting->result = -1; - semihosting->sys_errno = EINVAL; - } else if (strcmp((char *)fn, ":tt") == 0) { - if (mode == 0) { - semihosting->result = 0; - } else if (mode == 4) { - semihosting->result = 1; - } else if (mode == 8) { - semihosting->result = 2; - } 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_gdb_modeflags[mode]; - fileio_info->param_4 = 0644; - } - } else { - if (strcmp((char *)fn, ":tt") == 0) { - /* Mode is: - * - 0-3 ("r") for stdin, - * - 4-7 ("w") for stdout, - * - 8-11 ("a") for stderr */ - int fd; - if (mode < 4) { - fd = dup(STDIN_FILENO); - semihosting->stdin_fd = fd; - LOG_DEBUG("dup(STDIN)=%d", fd); - } else if (mode < 8) { - fd = dup(STDOUT_FILENO); - semihosting->stdout_fd = fd; - LOG_DEBUG("dup(STDOUT)=%d", fd); - } else { - 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_host_modeflags[mode], - 0644); - if (semihosting->result == -1) - semihosting->sys_errno = errno; - LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result); - } - } - free(fn); - } - } - break; + case SEMIHOSTING_SYS_ISERROR: /* 0x08 */ + /* + * Determines whether the return code from another semihosting + * call is an error status or not. + * + * This call is passed a parameter block containing the error + * code to examine. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field data block: + * - field 1 The required status word to check. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the status field is not an error indication + * - A nonzero value if the status field is an error indication. + */ + retval = semihosting_read_fields(target, 1, fields); + if (retval != ERROR_OK) + return retval; - case SEMIHOSTING_SYS_READ: /* 0x06 */ - /* - * Reads the contents of a file into a buffer. The file position - * is specified either: - * - Explicitly by a SYS_SEEK. - * - Implicitly one byte beyond the previous SYS_READ or - * SYS_WRITE request. - * - * The file position is at the start of the file when it is - * opened, and is lost when the file is closed. Perform the - * file operation as a single action whenever possible. For - * example, do not split a read of 16KB into four 4KB chunks - * unless there is no alternative. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * three-field data block: - * - field 1 Contains a handle for a file previously opened - * with SYS_OPEN. - * - field 2 Points to a buffer. - * - field 3 Contains the number of bytes to read to the buffer - * from the file. - * - * Return - * On exit, the RETURN REGISTER contains the number of bytes not - * filled in the buffer (buffer_length - bytes_read) as follows: - * - If the RETURN REGISTER is 0, the entire buffer was - * successfully filled. - * - If the RETURN REGISTER is the same as field 3, no bytes - * were read (EOF can be assumed). - * - If the RETURN REGISTER contains a value smaller than - * field 3, the read succeeded but the buffer was only partly - * filled. For interactive devices, this is the most common - * return value. - */ - retval = semihosting_read_fields(target, 3, fields); + uint64_t code = semihosting_get_field(target, 0, fields); + semihosting->result = (code != 0); + break; + + case SEMIHOSTING_SYS_ISTTY: /* 0x09 */ + /* + * Checks whether a file is connected to an interactive device. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field argument block: + * field 1 A handle for a previously opened file object. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 1 if the handle identifies an interactive device. + * - 0 if the handle identifies a file. + * - A value other than 1 or 0 if an error occurs. + */ + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "isatty"; + fileio_info->param_1 = semihosting->param; + } else { + retval = semihosting_read_fields(target, 1, fields); if (retval != ERROR_OK) return retval; - else { - int fd = semihosting_get_field(target, 0, fields); - uint64_t addr = semihosting_get_field(target, 1, fields); - size_t len = semihosting_get_field(target, 2, fields); - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "read"; - fileio_info->param_1 = fd; - fileio_info->param_2 = addr; - fileio_info->param_3 = len; - } else { - uint8_t *buf = malloc(len); - if (!buf) { - semihosting->result = -1; - semihosting->sys_errno = ENOMEM; - } else { - semihosting->result = semihosting_read(semihosting, fd, buf, len); - LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%" PRId64, - fd, - addr, - len, - semihosting->result); - if (semihosting->result >= 0) { - retval = target_write_buffer(target, addr, - semihosting->result, - buf); - if (retval != ERROR_OK) { - free(buf); - return retval; - } - /* the number of bytes NOT filled in */ - semihosting->result = len - - semihosting->result; - } - free(buf); - } - } - } - break; + int fd = semihosting_get_field(target, 0, fields); + // 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; - case SEMIHOSTING_SYS_READC: /* 0x07 */ - /* - * Reads a byte from the console. - * - * Entry - * The PARAMETER REGISTER must contain 0. There are no other - * parameters or values possible. - * - * Return - * On exit, the RETURN REGISTER contains the byte read from - * the console. - */ - if (semihosting->is_fileio) { - LOG_ERROR("SYS_READC not supported by semihosting fileio"); - return ERROR_FAIL; - } - semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd); - LOG_DEBUG("getchar()=%" PRId64, semihosting->result); - break; + case SEMIHOSTING_SYS_OPEN: /* 0x01 */ + /* + * Opens a file on the host system. + * + * The file path is specified either as relative to the current + * directory of the host process, or absolute, using the path + * conventions of the host operating system. + * + * Semihosting implementations must support opening the special + * path name :semihosting-features as part of the semihosting + * extensions reporting mechanism. + * + * ARM targets interpret the special path name :tt as meaning + * the console input stream, for an open-read or the console + * output stream, for an open-write. Opening these streams is + * performed as part of the standard startup code for those + * applications that reference the C stdio streams. The + * semihosting extension SH_EXT_STDOUT_STDERR allows the + * semihosting caller to open separate output streams + * corresponding to stdout and stderr. This extension is + * reported using feature byte 0, bit 1. Use SYS_OPEN with + * the special path name :semihosting-features to access the + * feature bits. + * + * If this extension is supported, the implementation must + * support the following additional semantics to SYS_OPEN: + * - If the special path name :tt is opened with an fopen + * mode requesting write access (w, wb, w+, or w+b), then + * this is a request to open stdout. + * - If the special path name :tt is opened with a mode + * requesting append access (a, ab, a+, or a+b), then this is + * a request to open stderr. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-field argument block: + * - field 1 A pointer to a null-terminated string containing + * a file or device name. + * - field 2 An integer that specifies the file opening mode. + * - field 3 An integer that gives the length of the string + * pointed to by field 1. + * + * The length does not include the terminating null character + * that must be present. + * + * Return + * On exit, the RETURN REGISTER contains: + * - A nonzero handle if the call is successful. + * - –1 if the call is not successful. + */ + retval = semihosting_read_fields(target, 3, fields); + if (retval != ERROR_OK) + return retval; - case SEMIHOSTING_SYS_REMOVE: /* 0x0E */ - /* - * Deletes a specified file on the host filing system. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * two-field argument block: - * - field 1 Points to a null-terminated string that gives the - * path name of the file to be deleted. - * - field 2 The length of the string. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the delete is successful - * - A nonzero, host-specific error code if the delete fails. - */ - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - uint64_t addr = semihosting_get_field(target, 0, fields); - size_t len = semihosting_get_field(target, 1, fields); - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "unlink"; - fileio_info->param_1 = addr; - fileio_info->param_2 = len; - } else { - uint8_t *fn = malloc(len+1); - if (!fn) { - semihosting->result = -1; - semihosting->sys_errno = ENOMEM; - } else { - retval = - target_read_memory(target, addr, 1, len, - fn); - if (retval != ERROR_OK) { - free(fn); - return retval; - } - fn[len] = 0; - semihosting->result = remove((char *)fn); - if (semihosting->result == -1) - semihosting->sys_errno = errno; - LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result); + { + uint64_t addr = semihosting_get_field(target, 0, fields); + uint32_t mode = semihosting_get_field(target, 1, fields); + size_t len = semihosting_get_field(target, 2, fields); - free(fn); - } - } + if (mode > 11) { + semihosting->result = -1; + semihosting->sys_errno = EINVAL; + break; } - break; - - case SEMIHOSTING_SYS_RENAME: /* 0x0F */ - /* - * Renames a specified file. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * four-field data block: - * - field 1 A pointer to the name of the old file. - * - field 2 The length of the old filename. - * - field 3 A pointer to the new filename. - * - field 4 The length of the new filename. Both strings are - * null-terminated. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the rename is successful. - * - A nonzero, host-specific error code if the rename fails. - */ - retval = semihosting_read_fields(target, 4, fields); - if (retval != ERROR_OK) - return retval; - else { - uint64_t addr1 = semihosting_get_field(target, 0, fields); - size_t len1 = semihosting_get_field(target, 1, fields); - uint64_t addr2 = semihosting_get_field(target, 2, fields); - size_t len2 = semihosting_get_field(target, 3, fields); - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "rename"; - fileio_info->param_1 = addr1; - fileio_info->param_2 = len1; - fileio_info->param_3 = addr2; - fileio_info->param_4 = len2; - } else { - uint8_t *fn1 = malloc(len1+1); - uint8_t *fn2 = malloc(len2+1); - if (!fn1 || !fn2) { - free(fn1); - free(fn2); - semihosting->result = -1; - semihosting->sys_errno = ENOMEM; - } else { - retval = target_read_memory(target, addr1, 1, len1, - fn1); - if (retval != ERROR_OK) { - free(fn1); - free(fn2); - return retval; - } - retval = target_read_memory(target, addr2, 1, len2, - fn2); - if (retval != ERROR_OK) { - free(fn1); - free(fn2); - return retval; - } - fn1[len1] = 0; - fn2[len2] = 0; - semihosting->result = rename((char *)fn1, - (char *)fn2); - // 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); - } + 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 { + if (basedir_len > 0) { + strcpy((char *)fn, semihosting->basedir); + if (fn[basedir_len - 1] != '/') + fn[basedir_len++] = '/'; } - } - break; - - case SEMIHOSTING_SYS_SEEK: /* 0x0A */ - /* - * Seeks to a specified position in a file using an offset - * specified from the start of the file. The file is assumed - * to be a byte array and the offset is given in bytes. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * two-field data block: - * - field 1 A handle for a seekable file object. - * - field 2 The absolute byte position to seek to. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the request is successful. - * - A negative value if the request is not successful. - * Use SYS_ERRNO to read the value of the host errno variable - * describing the error. - * - * Note: The effect of seeking outside the current extent of - * the file object is undefined. - */ - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - int fd = semihosting_get_field(target, 0, fields); - off_t pos = semihosting_get_field(target, 1, fields); - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "lseek"; - fileio_info->param_1 = fd; - fileio_info->param_2 = pos; - fileio_info->param_3 = SEEK_SET; - } else { - semihosting->result = lseek(fd, pos, SEEK_SET); - 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; + retval = target_read_memory(target, addr, 1, len, fn + basedir_len); + if (retval != ERROR_OK) { + free(fn); + return retval; } - } - break; - - case SEMIHOSTING_SYS_SYSTEM: /* 0x12 */ - /* - * Passes a command to the host command-line interpreter. - * This enables you to execute a system command such as dir, - * ls, or pwd. The terminal I/O is on the host, and is not - * visible to the target. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * two-field argument block: - * - field 1 Points to a string to be passed to the host - * command-line interpreter. - * - field 2 The length of the string. - * - * Return - * On exit, the RETURN REGISTER contains the return status. - */ - - /* Provide SYS_SYSTEM functionality. Uses the - * libc system command, there may be a reason *NOT* - * to use this, but as I can't think of one, I - * implemented it this way. - */ - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - uint64_t addr = semihosting_get_field(target, 0, fields); - size_t len = semihosting_get_field(target, 1, fields); + fn[basedir_len + len] = 0; + /* TODO: implement the :semihosting-features special file. + * */ if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "system"; - fileio_info->param_1 = addr; - fileio_info->param_2 = len; - } else { - uint8_t *cmd = malloc(len+1); - if (!cmd) { + if (strcmp((char *)fn, ":semihosting-features") == 0) { semihosting->result = -1; - semihosting->sys_errno = ENOMEM; + semihosting->sys_errno = EINVAL; + } else if (strcmp((char *)fn, ":tt") == 0) { + if (mode == 0) { + semihosting->result = 0; + } else if (mode == 4) { + semihosting->result = 1; + } else if (mode == 8) { + semihosting->result = 2; + } else { + semihosting->result = -1; + semihosting->sys_errno = EINVAL; + } } else { - retval = target_read_memory(target, - addr, - 1, - len, - cmd); - if (retval != ERROR_OK) { - free(cmd); - return retval; + semihosting->hit_fileio = true; + fileio_info->identifier = "open"; + fileio_info->param_1 = addr; + fileio_info->param_2 = len; + fileio_info->param_3 = open_gdb_modeflags[mode]; + fileio_info->param_4 = 0644; + } + } else { + if (strcmp((char *)fn, ":tt") == 0) { + /* Mode is: + * - 0-3 ("r") for stdin, + * - 4-7 ("w") for stdout, + * - 8-11 ("a") for stderr */ + int fd; + if (mode < 4) { + fd = dup(STDIN_FILENO); + semihosting->stdin_fd = fd; + LOG_DEBUG("dup(STDIN)=%d", fd); + } else if (mode < 8) { + fd = dup(STDOUT_FILENO); + semihosting->stdout_fd = fd; + LOG_DEBUG("dup(STDOUT)=%d", fd); } else { - cmd[len] = 0; - semihosting->result = system( - (const char *)cmd); - LOG_DEBUG("system('%s')=%" PRId64, cmd, semihosting->result); + fd = dup(STDERR_FILENO); + semihosting->stderr_fd = fd; + LOG_DEBUG("dup(STDERR)=%d", fd); } - - free(cmd); + 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_host_modeflags[mode], + 0644); + if (semihosting->result == -1) + semihosting->sys_errno = errno; + LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result); } } + free(fn); } - break; + } + break; - case SEMIHOSTING_SYS_TIME: /* 0x11 */ - /* - * Returns the number of seconds since 00:00 January 1, 1970. - * This value is real-world time, regardless of any debug agent - * configuration. - * - * Entry - * There are no parameters. - * - * Return - * On exit, the RETURN REGISTER contains the number of seconds. - */ - semihosting->result = time(NULL); - break; + case SEMIHOSTING_SYS_READ: /* 0x06 */ + /* + * Reads the contents of a file into a buffer. The file position + * is specified either: + * - Explicitly by a SYS_SEEK. + * - Implicitly one byte beyond the previous SYS_READ or + * SYS_WRITE request. + * + * The file position is at the start of the file when it is + * opened, and is lost when the file is closed. Perform the + * file operation as a single action whenever possible. For + * example, do not split a read of 16KB into four 4KB chunks + * unless there is no alternative. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-field data block: + * - field 1 Contains a handle for a file previously opened + * with SYS_OPEN. + * - field 2 Points to a buffer. + * - field 3 Contains the number of bytes to read to the buffer + * from the file. + * + * Return + * On exit, the RETURN REGISTER contains the number of bytes not + * filled in the buffer (buffer_length - bytes_read) as follows: + * - If the RETURN REGISTER is 0, the entire buffer was + * successfully filled. + * - If the RETURN REGISTER is the same as field 3, no bytes + * were read (EOF can be assumed). + * - If the RETURN REGISTER contains a value smaller than + * field 3, the read succeeded but the buffer was only partly + * filled. For interactive devices, this is the most common + * return value. + */ + retval = semihosting_read_fields(target, 3, fields); + if (retval != ERROR_OK) + return retval; - case SEMIHOSTING_SYS_WRITE: /* 0x05 */ - /* - * Writes the contents of a buffer to a specified file at the - * current file position. The file position is specified either: - * - Explicitly, by a SYS_SEEK. - * - Implicitly as one byte beyond the previous SYS_READ or - * SYS_WRITE request. - * - * The file position is at the start of the file when the file - * is opened, and is lost when the file is closed. - * - * Perform the file operation as a single action whenever - * possible. For example, do not split a write of 16KB into - * four 4KB chunks unless there is no alternative. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * three-field data block: - * - field 1 Contains a handle for a file previously opened - * with SYS_OPEN. - * - field 2 Points to the memory containing the data to be written. - * - field 3 Contains the number of bytes to be written from - * the buffer to the file. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the call is successful. - * - The number of bytes that are not written, if there is an error. - */ - retval = semihosting_read_fields(target, 3, fields); - if (retval != ERROR_OK) - return retval; - else { - int fd = semihosting_get_field(target, 0, fields); - uint64_t addr = semihosting_get_field(target, 1, fields); - size_t len = semihosting_get_field(target, 2, fields); - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "write"; - fileio_info->param_1 = fd; - fileio_info->param_2 = addr; - fileio_info->param_3 = len; + { + int fd = semihosting_get_field(target, 0, fields); + uint64_t addr = semihosting_get_field(target, 1, fields); + size_t len = semihosting_get_field(target, 2, fields); + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "read"; + fileio_info->param_1 = fd; + fileio_info->param_2 = addr; + fileio_info->param_3 = len; + } else { + uint8_t *buf = malloc(len); + if (!buf) { + semihosting->result = -1; + semihosting->sys_errno = ENOMEM; } else { - uint8_t *buf = malloc(len); - if (!buf) { - semihosting->result = -1; - semihosting->sys_errno = ENOMEM; - } else { - retval = target_read_buffer(target, addr, len, buf); + semihosting->result = semihosting_read(semihosting, fd, buf, len); + LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%" PRId64, + fd, + addr, + len, + semihosting->result); + if (semihosting->result >= 0) { + retval = target_write_buffer(target, addr, + semihosting->result, + buf); if (retval != ERROR_OK) { free(buf); return retval; } - semihosting->result = semihosting_write(semihosting, fd, buf, len); - LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64, - fd, - addr, - len, - semihosting->result); - if (semihosting->result >= 0) { - /* The number of bytes that are NOT written. - * */ - semihosting->result = len - - semihosting->result; - } - - free(buf); + /* the number of bytes NOT filled in */ + semihosting->result = len - + semihosting->result; } + free(buf); } } - break; + } + break; + + case SEMIHOSTING_SYS_READC: /* 0x07 */ + /* + * Reads a byte from the console. + * + * Entry + * The PARAMETER REGISTER must contain 0. There are no other + * parameters or values possible. + * + * Return + * On exit, the RETURN REGISTER contains the byte read from + * the console. + */ + if (semihosting->is_fileio) { + LOG_ERROR("SYS_READC not supported by semihosting fileio"); + return ERROR_FAIL; + } + semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd); + LOG_DEBUG("getchar()=%" PRId64, semihosting->result); + break; + + case SEMIHOSTING_SYS_REMOVE: /* 0x0E */ + /* + * Deletes a specified file on the host filing system. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 Points to a null-terminated string that gives the + * path name of the file to be deleted. + * - field 2 The length of the string. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the delete is successful + * - A nonzero, host-specific error code if the delete fails. + */ + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) + return retval; - case SEMIHOSTING_SYS_WRITEC: /* 0x03 */ - /* - * Writes a character byte, pointed to by the PARAMETER REGISTER, - * to the debug channel. When executed under a semihosting - * debugger, the character appears on the host debugger console. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to the - * character. - * - * Return - * None. The RETURN REGISTER is corrupted. - */ + { + uint64_t addr = semihosting_get_field(target, 0, fields); + size_t len = semihosting_get_field(target, 1, fields); if (semihosting->is_fileio) { semihosting->hit_fileio = true; - fileio_info->identifier = "write"; - fileio_info->param_1 = 1; - fileio_info->param_2 = semihosting->param; - fileio_info->param_3 = 1; + fileio_info->identifier = "unlink"; + fileio_info->param_1 = addr; + fileio_info->param_2 = len; } else { - uint64_t addr = semihosting->param; - unsigned char c; - retval = target_read_memory(target, addr, 1, 1, &c); - if (retval != ERROR_OK) - return retval; - semihosting_putchar(semihosting, semihosting->stdout_fd, c); - semihosting->result = 0; + uint8_t *fn = malloc(len + 1); + if (!fn) { + semihosting->result = -1; + semihosting->sys_errno = ENOMEM; + } else { + retval = target_read_memory(target, addr, 1, len, fn); + if (retval != ERROR_OK) { + free(fn); + return retval; + } + fn[len] = 0; + semihosting->result = remove((char *)fn); + if (semihosting->result == -1) + semihosting->sys_errno = errno; + LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result); + + free(fn); + } } - break; + } + break; + + case SEMIHOSTING_SYS_RENAME: /* 0x0F */ + /* + * Renames a specified file. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * four-field data block: + * - field 1 A pointer to the name of the old file. + * - field 2 The length of the old filename. + * - field 3 A pointer to the new filename. + * - field 4 The length of the new filename. Both strings are + * null-terminated. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the rename is successful. + * - A nonzero, host-specific error code if the rename fails. + */ + retval = semihosting_read_fields(target, 4, fields); + if (retval != ERROR_OK) + return retval; - case SEMIHOSTING_SYS_WRITE0: /* 0x04 */ - /* - * Writes a null-terminated string to the debug channel. - * When executed under a semihosting debugger, the characters - * appear on the host debugger console. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to the - * first byte of the string. - * - * Return - * None. The RETURN REGISTER is corrupted. - */ + { + uint64_t addr1 = semihosting_get_field(target, 0, fields); + size_t len1 = semihosting_get_field(target, 1, fields); + uint64_t addr2 = semihosting_get_field(target, 2, fields); + size_t len2 = semihosting_get_field(target, 3, fields); if (semihosting->is_fileio) { - size_t count = 0; - uint64_t addr = semihosting->param; - for (;; addr++) { - unsigned char c; - retval = target_read_memory(target, addr, 1, 1, &c); - if (retval != ERROR_OK) - return retval; - if (c == '\0') - break; - count++; - } semihosting->hit_fileio = true; - fileio_info->identifier = "write"; - fileio_info->param_1 = 1; - fileio_info->param_2 = semihosting->param; - fileio_info->param_3 = count; + fileio_info->identifier = "rename"; + fileio_info->param_1 = addr1; + fileio_info->param_2 = len1; + fileio_info->param_3 = addr2; + fileio_info->param_4 = len2; } else { - uint64_t addr = semihosting->param; - do { - unsigned char c; - retval = target_read_memory(target, addr++, 1, 1, &c); - if (retval != ERROR_OK) + uint8_t *fn1 = malloc(len1 + 1); + uint8_t *fn2 = malloc(len2 + 1); + if (!fn1 || !fn2) { + free(fn1); + free(fn2); + semihosting->result = -1; + semihosting->sys_errno = ENOMEM; + } else { + retval = target_read_memory(target, addr1, 1, len1, fn1); + if (retval != ERROR_OK) { + free(fn1); + free(fn2); return retval; - if (!c) - break; - semihosting_putchar(semihosting, semihosting->stdout_fd, c); - } while (1); - semihosting->result = 0; + } + retval = target_read_memory(target, addr2, 1, len2, fn2); + if (retval != ERROR_OK) { + free(fn1); + free(fn2); + return retval; + } + fn1[len1] = 0; + fn2[len2] = 0; + semihosting->result = rename((char *)fn1, (char *)fn2); + // 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); + } } - break; + } + 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 */ - } + case SEMIHOSTING_SYS_SEEK: /* 0x0A */ + /* + * Seeks to a specified position in a file using an offset + * specified from the start of the file. The file is assumed + * to be a byte array and the offset is given in bytes. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field data block: + * - field 1 A handle for a seekable file object. + * - field 2 The absolute byte position to seek to. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the request is successful. + * - A negative value if the request is not successful. + * Use SYS_ERRNO to read the value of the host errno variable + * describing the error. + * + * Note: The effect of seeking outside the current extent of + * the file object is undefined. + */ + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) + return retval; - 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; + { + int fd = semihosting_get_field(target, 0, fields); + off_t pos = semihosting_get_field(target, 1, fields); + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "lseek"; + fileio_info->param_1 = fd; + fileio_info->param_2 = pos; + fileio_info->param_3 = SEEK_SET; + } else { + semihosting->result = lseek(fd, pos, SEEK_SET); + 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; } + } + break; - uint64_t addr = semihosting_get_field(target, 0, fields); + case SEMIHOSTING_SYS_SYSTEM: /* 0x12 */ + /* + * Passes a command to the host command-line interpreter. + * This enables you to execute a system command such as dir, + * ls, or pwd. The terminal I/O is on the host, and is not + * visible to the target. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 Points to a string to be passed to the host + * command-line interpreter. + * - field 2 The length of the string. + * + * Return + * On exit, the RETURN REGISTER contains the return status. + */ + /* Provide SYS_SYSTEM functionality. Uses the + * libc system command, there may be a reason *NOT* + * to use this, but as I can't think of one, I + * implemented it this way. + */ + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) + 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; - } + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "system"; + fileio_info->param_1 = addr; + fileio_info->param_2 = len; + } else { + uint8_t *cmd = malloc(len + 1); + if (!cmd) { + semihosting->result = -1; + semihosting->sys_errno = ENOMEM; + } else { + retval = target_read_memory(target, + addr, + 1, + len, + cmd); + if (retval != ERROR_OK) { + free(cmd); + return retval; + } + cmd[len] = 0; + semihosting->result = system((const char *)cmd); + LOG_DEBUG("system('%s')=%" PRId64, cmd, semihosting->result); - 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; + free(cmd); + } } + } + break; - target_handle_event(target, semihosting->op); - free(semihosting_user_op_params); - semihosting_user_op_params = NULL; - semihosting->result = 0; - break; + case SEMIHOSTING_SYS_TIME: /* 0x11 */ + /* + * Returns the number of seconds since 00:00 January 1, 1970. + * This value is real-world time, regardless of any debug agent + * configuration. + * + * Entry + * There are no parameters. + * + * Return + * On exit, the RETURN REGISTER contains the number of seconds. + */ + semihosting->result = time(NULL); + break; - case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */ + case SEMIHOSTING_SYS_WRITE: /* 0x05 */ /* - * Returns the number of elapsed target ticks since execution - * started. - * Use SYS_TICKFREQ to determine the tick frequency. + * Writes the contents of a buffer to a specified file at the + * current file position. The file position is specified either: + * - Explicitly, by a SYS_SEEK. + * - Implicitly as one byte beyond the previous SYS_READ or + * SYS_WRITE request. * - * Entry (32-bit) - * On entry, the PARAMETER REGISTER points to a two-field data - * block to be used for returning the number of elapsed ticks: - * - field 1 The least significant field and is at the low address. - * - field 2 The most significant field and is at the high address. + * The file position is at the start of the file when the file + * is opened, and is lost when the file is closed. * - * Entry (64-bit) - * On entry the PARAMETER REGISTER points to a one-field data - * block to be used for returning the number of elapsed ticks: - * - field 1 The number of elapsed ticks as a 64-bit value. + * Perform the file operation as a single action whenever + * possible. For example, do not split a write of 16KB into + * four 4KB chunks unless there is no alternative. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-field data block: + * - field 1 Contains a handle for a file previously opened + * with SYS_OPEN. + * - field 2 Points to the memory containing the data to be written. + * - field 3 Contains the number of bytes to be written from + * the buffer to the file. * * Return - * On exit: - * - On success, the RETURN REGISTER contains 0, the PARAMETER - * REGISTER is unchanged, and the data block pointed to by the - * PARAMETER REGISTER is filled in with the number of elapsed - * ticks. - * - On failure, the RETURN REGISTER contains -1, and the - * PARAMETER REGISTER contains -1. - * - * Note: Some semihosting implementations might not support this - * semihosting operation, and they always return -1 in the - * RETURN REGISTER. + * On exit, the RETURN REGISTER contains: + * - 0 if the call is successful. + * - The number of bytes that are not written, if there is an error. */ + retval = semihosting_read_fields(target, 3, fields); + if (retval != ERROR_OK) + return retval; + + { + int fd = semihosting_get_field(target, 0, fields); + uint64_t addr = semihosting_get_field(target, 1, fields); + size_t len = semihosting_get_field(target, 2, fields); + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "write"; + fileio_info->param_1 = fd; + fileio_info->param_2 = addr; + fileio_info->param_3 = len; + } else { + uint8_t *buf = malloc(len); + if (!buf) { + semihosting->result = -1; + semihosting->sys_errno = ENOMEM; + } else { + retval = target_read_buffer(target, addr, len, buf); + if (retval != ERROR_OK) { + free(buf); + return retval; + } + semihosting->result = semihosting_write(semihosting, fd, buf, len); + LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64, + fd, + addr, + len, + semihosting->result); + if (semihosting->result >= 0) { + /* The number of bytes that are NOT written. + * */ + semihosting->result = len - + semihosting->result; + } + + free(buf); + } + } + } + break; - case SEMIHOSTING_SYS_TICKFREQ: /* 0x31 */ + case SEMIHOSTING_SYS_WRITEC: /* 0x03 */ /* - * Returns the tick frequency. + * Writes a character byte, pointed to by the PARAMETER REGISTER, + * to the debug channel. When executed under a semihosting + * debugger, the character appears on the host debugger console. * * Entry - * The PARAMETER REGISTER must contain 0 on entry to this routine. + * On entry, the PARAMETER REGISTER contains a pointer to the + * character. * * Return - * On exit, the RETURN REGISTER contains either: - * - The number of ticks per second. - * - –1 if the target does not know the value of one tick. - * - * Note: Some semihosting implementations might not support - * this semihosting operation, and they always return -1 in the - * RETURN REGISTER. + * None. The RETURN REGISTER is corrupted. */ + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "write"; + fileio_info->param_1 = 1; + fileio_info->param_2 = semihosting->param; + fileio_info->param_3 = 1; + } else { + uint64_t addr = semihosting->param; + unsigned char c; + retval = target_read_memory(target, addr, 1, 1, &c); + if (retval != ERROR_OK) + return retval; + semihosting_putchar(semihosting, semihosting->stdout_fd, c); + semihosting->result = 0; + } + break; - case SEMIHOSTING_SYS_TMPNAM: /* 0x0D */ + case SEMIHOSTING_SYS_WRITE0: /* 0x04 */ /* - * Returns a temporary name for a file identified by a system - * file identifier. + * Writes a null-terminated string to the debug channel. + * When executed under a semihosting debugger, the characters + * appear on the host debugger console. * * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * three-word argument block: - * - field 1 A pointer to a buffer. - * - field 2 A target identifier for this filename. Its value - * must be an integer in the range 0-255. - * - field 3 Contains the length of the buffer. The length must - * be at least the value of L_tmpnam on the host system. + * On entry, the PARAMETER REGISTER contains a pointer to the + * first byte of the string. * * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the call is successful. - * - –1 if an error occurs. + * None. The RETURN REGISTER is corrupted. + */ + if (semihosting->is_fileio) { + size_t count = 0; + uint64_t addr = semihosting->param; + for (;; addr++) { + unsigned char c; + retval = target_read_memory(target, addr, 1, 1, &c); + if (retval != ERROR_OK) + return retval; + if (c == '\0') + break; + count++; + } + semihosting->hit_fileio = true; + fileio_info->identifier = "write"; + fileio_info->param_1 = 1; + fileio_info->param_2 = semihosting->param; + fileio_info->param_3 = count; + } else { + uint64_t addr = semihosting->param; + do { + unsigned char c; + retval = target_read_memory(target, addr++, 1, 1, &c); + if (retval != ERROR_OK) + return retval; + if (!c) + break; + 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). * - * The buffer pointed to by the PARAMETER REGISTER contains - * the filename, prefixed with a suitable directory name. - * If you use the same target identifier again, the same - * filename is returned. + * 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 * - * Note: The returned string must be null-terminated. + * 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 */ + } - default: - fprintf(stderr, "semihosting: unsupported call %#x\n", - (unsigned) semihosting->op); - semihosting->result = -1; - semihosting->sys_errno = ENOTSUP; + 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 + * started. + * Use SYS_TICKFREQ to determine the tick frequency. + * + * Entry (32-bit) + * On entry, the PARAMETER REGISTER points to a two-field data + * block to be used for returning the number of elapsed ticks: + * - field 1 The least significant field and is at the low address. + * - field 2 The most significant field and is at the high address. + * + * Entry (64-bit) + * On entry the PARAMETER REGISTER points to a one-field data + * block to be used for returning the number of elapsed ticks: + * - field 1 The number of elapsed ticks as a 64-bit value. + * + * Return + * On exit: + * - On success, the RETURN REGISTER contains 0, the PARAMETER + * REGISTER is unchanged, and the data block pointed to by the + * PARAMETER REGISTER is filled in with the number of elapsed + * ticks. + * - On failure, the RETURN REGISTER contains -1, and the + * PARAMETER REGISTER contains -1. + * + * Note: Some semihosting implementations might not support this + * semihosting operation, and they always return -1 in the + * RETURN REGISTER. + */ + + case SEMIHOSTING_SYS_TICKFREQ: /* 0x31 */ + /* + * Returns the tick frequency. + * + * Entry + * The PARAMETER REGISTER must contain 0 on entry to this routine. + * + * Return + * On exit, the RETURN REGISTER contains either: + * - The number of ticks per second. + * - –1 if the target does not know the value of one tick. + * + * Note: Some semihosting implementations might not support + * this semihosting operation, and they always return -1 in the + * RETURN REGISTER. + */ + + case SEMIHOSTING_SYS_TMPNAM: /* 0x0D */ + /* + * Returns a temporary name for a file identified by a system + * file identifier. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-word argument block: + * - field 1 A pointer to a buffer. + * - field 2 A target identifier for this filename. Its value + * must be an integer in the range 0-255. + * - field 3 Contains the length of the buffer. The length must + * be at least the value of L_tmpnam on the host system. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the call is successful. + * - –1 if an error occurs. + * + * The buffer pointed to by the PARAMETER REGISTER contains + * the filename, prefixed with a suitable directory name. + * If you use the same target identifier again, the same + * filename is returned. + * + * Note: The returned string must be null-terminated. + */ + + default: + fprintf(stderr, "semihosting: unsupported call %#x\n", + (unsigned int)semihosting->op); + semihosting->result = -1; + semihosting->sys_errno = ENOTSUP; } if (!semihosting->hit_fileio) { @@ -1690,18 +1687,18 @@ static int semihosting_common_fileio_end(struct target *target, int result, * below: */ switch (semihosting->op) { - case SEMIHOSTING_SYS_WRITE: /* 0x05 */ - case SEMIHOSTING_SYS_READ: /* 0x06 */ - if (result < 0) - semihosting->result = fileio_info->param_3; /* Zero bytes read/written. */ - else - semihosting->result = (int64_t)fileio_info->param_3 - result; - break; + case SEMIHOSTING_SYS_WRITE: /* 0x05 */ + case SEMIHOSTING_SYS_READ: /* 0x06 */ + if (result < 0) + semihosting->result = fileio_info->param_3; /* Zero bytes read/written. */ + else + semihosting->result = (int64_t)fileio_info->param_3 - result; + break; - case SEMIHOSTING_SYS_SEEK: /* 0x0a */ - if (result > 0) - semihosting->result = 0; - break; + case SEMIHOSTING_SYS_SEEK: /* 0x0a */ + if (result > 0) + semihosting->result = 0; + break; } bool fileio_failed = false; @@ -1803,13 +1800,12 @@ static int semihosting_service_input_handler(struct connection *connection) return ERROR_OK; } -static int semihosting_service_connection_closed_handler(struct connection *connection) +static void semihosting_service_dtor_handler(struct service *service) { - struct semihosting_tcp_service *service = connection->service->priv; - if (service) - free(service->name); + struct semihosting_tcp_service *service_priv = service->priv; + if (service_priv) + free(service_priv->name); - return ERROR_OK; } static void semihosting_tcp_close_cnx(struct semihosting *semihosting) @@ -1828,7 +1824,8 @@ static const struct service_driver semihosting_service_driver = { .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, + .service_dtor_handler = semihosting_service_dtor_handler, + .connection_closed_handler = NULL, .keep_client_alive_handler = NULL, }; @@ -1860,7 +1857,7 @@ COMMAND_HANDLER(handle_common_semihosting_command) return ERROR_FAIL; } - if (semihosting && semihosting->setup(target, is_active) != ERROR_OK) { + if (semihosting->setup(target, is_active) != ERROR_OK) { LOG_ERROR("Failed to Configure semihosting"); return ERROR_FAIL; } diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h index 1821ca4e2e..ecf38d62a1 100644 --- a/src/target/semihosting_common.h +++ b/src/target/semihosting_common.h @@ -19,8 +19,10 @@ /* * According to: - * "Semihosting for AArch32 and AArch64, Release 2.0" - * https://static.docs.arm.com/100863/0200/semihosting.pdf + * "Semihosting for AArch32 and AArch64, 2025Q1" + * https://github.com/ARM-software/abi-aa/releases/download/2025Q1/semihosting.pdf + * and to: + * https://developer.arm.com/documentation/dui0203/latest/semihosting/about-semihosting/the-semihosting-interface * from ARM Ltd. * * The available semihosting operation numbers passed in R0 are allocated diff --git a/src/target/smp.c b/src/target/smp.c index 41ca880d43..8a9dd2d9d7 100644 --- a/src/target/smp.c +++ b/src/target/smp.c @@ -54,16 +54,13 @@ int gdb_read_smp_packet(struct connection *connection, LOG_WARNING(DEPRECATED_MSG); if (target->smp) { - if (strncmp(packet, "jc", 2) == 0) { - const uint32_t len = sizeof(target->gdb_service->core[0]); - char hex_buffer[len * 2 + 1]; - uint8_t buffer[len]; - buf_set_u32(buffer, 0, len * 8, target->gdb_service->core[0]); - size_t pkt_len = hexify(hex_buffer, buffer, sizeof(buffer), - sizeof(hex_buffer)); - - retval = gdb_put_packet(connection, hex_buffer, pkt_len); - } + const uint32_t len = sizeof(target->gdb_service->core[0]); + char hex_buffer[len * 2 + 1]; + uint8_t buffer[len]; + buf_set_u32(buffer, 0, len * 8, target->gdb_service->core[0]); + size_t pkt_len = hexify(hex_buffer, buffer, sizeof(buffer), + sizeof(hex_buffer)); + retval = gdb_put_packet(connection, hex_buffer, pkt_len); } else retval = gdb_put_packet(connection, "E01", 3); return retval; diff --git a/src/target/startup.tcl b/src/target/startup.tcl index 1cc9bb7fda..8a05614c91 100644 --- a/src/target/startup.tcl +++ b/src/target/startup.tcl @@ -295,6 +295,18 @@ proc "mips_m4k smp_off" {args} { eval mips_m4k smp off $args } +lappend _telnet_autocomplete_skip "arm disassemble" +proc "arm disassemble" {args} { + echo "DEPRECATED! use 'disassemble $args'" + eval disassemble $args +} + +lappend _telnet_autocomplete_skip "aarch64 disassemble" +proc "aarch64 disassemble" {args} { + echo "DEPRECATED! use 'disassemble $args' not 'aarch64 disassemble $args'" + eval disassemble $args +} + lappend _telnet_autocomplete_skip _post_init_target_cortex_a_cache_auto proc _post_init_target_cortex_a_cache_auto {} { set cortex_a_found 0 diff --git a/src/target/stm8.c b/src/target/stm8.c index 81c41f2b2a..6f261c9cdb 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -13,6 +13,7 @@ #include #include "target.h" #include "target_type.h" +#include "jtag/adapter.h" #include "jtag/interface.h" #include "jtag/jtag.h" #include "jtag/swim.h" @@ -33,7 +34,6 @@ static void stm8_enable_watchpoints(struct target *target); static int stm8_unset_watchpoint(struct target *target, struct watchpoint *watchpoint); static int (*adapter_speed)(int speed); -extern struct adapter_driver *adapter_driver; static const struct { unsigned int id; @@ -584,7 +584,6 @@ static int stm8_write_regs(struct target *target, uint32_t regs[]) 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_to_stm8(target); @@ -592,9 +591,7 @@ static int stm8_get_core_reg(struct reg *reg) if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - retval = stm8->read_core_reg(target, stm8_reg->num); - - return retval; + return stm8->read_core_reg(target, stm8_reg->num); } static int stm8_set_core_reg(struct reg *reg, uint8_t *buf) @@ -704,19 +701,19 @@ static int stm8_write_flash(struct target *target, enum mem_type type, int res; switch (type) { - case (FLASH): - stm8_unlock_flash(target); - break; - case (EEPROM): - stm8_unlock_eeprom(target); - break; - case (OPTION): - stm8_unlock_eeprom(target); - opt = OPT; - break; - default: - LOG_ERROR("BUG: wrong mem_type %d", type); - assert(0); + case FLASH: + stm8_unlock_flash(target); + break; + case EEPROM: + stm8_unlock_eeprom(target); + break; + case OPTION: + stm8_unlock_eeprom(target); + opt = OPT; + break; + default: + LOG_ERROR("BUG: wrong mem_type %d", type); + assert(0); } if (size == 2) { @@ -870,7 +867,7 @@ static int stm8_poll(struct target *target) uint8_t csr1, csr2; #ifdef LOG_STM8 - LOG_DEBUG("target->state=%d", target->state); + LOG_DEBUG("target->state %s", target_state_name(target)); #endif /* read dm_csrx control regs */ @@ -1094,11 +1091,11 @@ static int stm8_resume(struct target *target, bool current, if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); + 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); + LOG_DEBUG("target debug resumed at 0x%" PRIx32, resume_pc); } return ERROR_OK; @@ -1173,7 +1170,7 @@ static int stm8_read_core_reg(struct target *target, unsigned int num) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = stm8->core_regs[num]; - LOG_DEBUG("read core reg %i value 0x%" PRIx32 "", num, reg_value); + LOG_DEBUG("read core reg %i value 0x%" PRIx32, num, reg_value); buf_set_u32(stm8->core_cache->reg_list[num].value, 0, 32, reg_value); stm8->core_cache->reg_list[num].valid = true; stm8->core_cache->reg_list[num].dirty = false; @@ -1193,7 +1190,7 @@ static int stm8_write_core_reg(struct target *target, unsigned int num) reg_value = buf_get_u32(stm8->core_cache->reg_list[num].value, 0, 32); stm8->core_regs[num] = reg_value; - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); + LOG_DEBUG("write core reg %i value 0x%" PRIx32, num, reg_value); stm8->core_cache->reg_list[num].valid = true; stm8->core_cache->reg_list[num].dirty = false; @@ -1327,7 +1324,7 @@ static int stm8_arch_state(struct target *target) { struct stm8_common *stm8 = target_to_stm8(target); - LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "", + LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32, debug_reason_name(target), buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32)); @@ -1438,7 +1435,7 @@ static int stm8_set_breakpoint(struct target *target, if (retval != ERROR_OK) return retval; - LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32 "", + LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32, breakpoint->unique_id, bp_num, comparator_list[bp_num].bp_value); } else if (breakpoint->type == BKPT_SOFT) { @@ -1601,17 +1598,17 @@ static int stm8_set_watchpoint(struct target *target, enum hw_break_type enable = 0; switch (watchpoint->rw) { - case WPT_READ: - enable = HWBRK_RD; - break; - case WPT_WRITE: - enable = HWBRK_WR; - break; - case WPT_ACCESS: - enable = HWBRK_ACC; - break; - default: - LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + case WPT_READ: + enable = HWBRK_RD; + break; + case WPT_WRITE: + enable = HWBRK_WR; + break; + case WPT_ACCESS: + enable = HWBRK_ACC; + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } comparator_list[wp_num].used = true; @@ -1626,7 +1623,7 @@ static int stm8_set_watchpoint(struct target *target, watchpoint_set(watchpoint, wp_num); - LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", + LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32, wp_num, comparator_list[wp_num].bp_value); @@ -1747,8 +1744,6 @@ static int stm8_examine(struct target *target) } } - target_set_examined(target); - return ERROR_OK; } @@ -1757,7 +1752,8 @@ static int stm8_examine(struct target *target) /** Checks whether a memory region is erased. */ static int stm8_blank_check_memory(struct target *target, - struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) + struct target_memory_check_block *blocks, unsigned int num_blocks, + uint8_t erased_value, unsigned int *checked) { struct working_area *erase_check_algorithm; struct reg_param reg_params[2]; @@ -1801,8 +1797,10 @@ static int stm8_blank_check_memory(struct target *target, erase_check_algorithm->address + (sizeof(stm8_erase_check_code) - 1), 10000, &stm8_info); - if (retval == ERROR_OK) + if (retval == ERROR_OK) { blocks[0].result = (*(reg_params[0].value) == 0xff); + *checked = 1; /* only one block has been checked */ + } destroy_mem_param(&mem_params[0]); destroy_mem_param(&mem_params[1]); @@ -1811,10 +1809,7 @@ static int stm8_blank_check_memory(struct target *target, target_free_working_area(target, erase_check_algorithm); - if (retval != ERROR_OK) - return retval; - - return 1; /* only one block has been checked */ + return retval; } static int stm8_checksum_memory(struct target *target, target_addr_t address, diff --git a/src/target/target.c b/src/target/target.c index 392abc9dee..ed84b3e2e1 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -30,12 +30,14 @@ #include "config.h" #endif +#include #include #include #include #include #include #include +#include #include "target.h" #include "target_type.h" @@ -71,46 +73,45 @@ static int target_gdb_fileio_end_default(struct target *target, int retcode, int fileio_errno, bool ctrl_c); static struct target_type *target_types[] = { + // Keep in alphabetic order this list of targets + &aarch64_target, + &arcv2_target, + &arm11_target, + &arm720t_target, &arm7tdmi_target, - &arm9tdmi_target, &arm920t_target, - &arm720t_target, - &arm966e_target, - &arm946e_target, &arm926ejs_target, - &fa526_target, - &feroceon_target, - &dragonite_target, - &xscale_target, - &xtensa_chip_target, - &cortexm_target, + &arm946e_target, + &arm966e_target, + &arm9tdmi_target, + &armv8r_target, + &avr32_ap7k_target, + &avr_target, &cortexa_target, + &cortexm_target, &cortexr4_target, - &arm11_target, - &ls1_sap_target, - &mips_m4k_target, - &avr_target, + &dragonite_target, &dsp563xx_target, &dsp5680xx_target, - &testee_target, - &avr32_ap7k_target, - &hla_target, - &esp32_target, + &esirisc_target, &esp32s2_target, &esp32s3_target, + &esp32_target, + &fa526_target, + &feroceon_target, + &hla_target, + &ls1_sap_target, + &mem_ap_target, + &mips_m4k_target, + &mips_mips64_target, &or1k_target, - &quark_x10xx_target, &quark_d20xx_target, - &stm8_target, + &quark_x10xx_target, &riscv_target, - &scr5_target, - &mem_ap_target, - &esirisc_target, - &arcv2_target, - &aarch64_target, - &armv8r_target, - &mips_mips64_target, - NULL, + &stm8_target, + &testee_target, + &xscale_target, + &xtensa_chip_target, }; struct target *all_targets; @@ -119,7 +120,7 @@ static struct target_timer_callback *target_timer_callbacks; static int64_t target_timer_next_event_value; static OOCD_LIST_HEAD(target_reset_callback_list); static OOCD_LIST_HEAD(target_trace_callback_list); -static const unsigned int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; +static unsigned int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; static OOCD_LIST_HEAD(empty_smp_targets); enum nvp_assert { @@ -491,7 +492,7 @@ int target_poll(struct target *target) /* We can't poll until after examine */ if (!target_was_examined(target)) { /* Fail silently lest we pollute the log */ - return ERROR_FAIL; + return ERROR_TARGET_NOT_EXAMINED; } retval = target->type->poll(target); @@ -517,10 +518,10 @@ int target_poll(struct target *target) int target_halt(struct target *target) { int retval; - /* We can't poll until after examine */ + if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; + LOG_TARGET_ERROR(target, "not examined"); + return ERROR_TARGET_NOT_EXAMINED; } retval = target->type->halt(target); @@ -568,10 +569,9 @@ int target_resume(struct target *target, bool current, target_addr_t address, { int retval; - /* We can't poll until after examine */ if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; + LOG_TARGET_ERROR(target, "not examined"); + return ERROR_TARGET_NOT_EXAMINED; } target_call_event_callbacks(target, TARGET_EVENT_RESUME_START); @@ -651,15 +651,19 @@ static int identity_virt2phys(struct target *target, return ERROR_OK; } -static int no_mmu(struct target *target, int *enabled) +static int no_mmu(struct target *target, bool *enabled) { - *enabled = 0; + *enabled = false; return ERROR_OK; } +static inline void target_reset_active_polled(struct target *target) +{ + target->active_polled = false; +} + static int default_examine(struct target *target) { - target_set_examined(target); return ERROR_OK; } @@ -686,7 +690,6 @@ int target_examine_one(struct target *target) return retval; } - LOG_USER("[%s] Target successfully examined.", target_name(target)); target_set_examined(target); target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); @@ -706,12 +709,6 @@ static int jtag_enable_callback(enum jtag_event event, void *priv) return target_examine_one(target); } -/* When this is true, it's OK to call examine() again in the hopes that this time - * it will work. Earlier than that there is probably other initialization that - * needs to happen (like scanning the JTAG chain) before examine should be - * called. */ -static bool examine_attempted; - /* Targets that correctly implement init + examine, i.e. * no communication with target during init: * @@ -722,8 +719,6 @@ int target_examine(void) int retval = ERROR_OK; struct target *target; - examine_attempted = true; - for (target = all_targets; target; target = target->next) { /* defer examination, but don't skip it */ if (!target->tap->enabled) { @@ -752,8 +747,8 @@ const char *target_type_name(const struct target *target) static int target_soft_reset_halt(struct target *target) { if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; + LOG_TARGET_ERROR(target, "not examined"); + return ERROR_TARGET_NOT_EXAMINED; } if (!target->type->soft_reset_halt) { LOG_ERROR("Target %s does not support soft_reset_halt", @@ -790,7 +785,8 @@ int target_run_algorithm(struct target *target, int retval = ERROR_FAIL; if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + LOG_TARGET_ERROR(target, "not examined"); + retval = ERROR_TARGET_NOT_EXAMINED; goto done; } if (!target->type->run_algorithm) { @@ -831,7 +827,8 @@ int target_start_algorithm(struct target *target, int retval = ERROR_FAIL; if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + LOG_TARGET_ERROR(target, "not examined"); + retval = ERROR_TARGET_NOT_EXAMINED; goto done; } if (!target->type->start_algorithm) { @@ -1241,15 +1238,23 @@ int target_run_read_async_algorithm(struct target *target, return retval; } +bool target_memory_ready(struct target *target) +{ + if (target->type->memory_ready) + return target->type->memory_ready(target); + + return target_was_examined(target); +} + int target_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + if (!target_memory_ready(target)) { + LOG_TARGET_ERROR(target, "Memory not ready"); return ERROR_FAIL; } if (!target->type->read_memory) { - LOG_ERROR("Target %s doesn't support read_memory", target_name(target)); + LOG_TARGET_ERROR(target, "doesn't support read_memory"); return ERROR_FAIL; } int result = target->type->read_memory(target, address, size, count, buffer); @@ -1261,12 +1266,12 @@ int target_read_memory(struct target *target, int target_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + if (!target_memory_ready(target)) { + LOG_TARGET_ERROR(target, "Memory not ready"); return ERROR_FAIL; } if (!target->type->read_phys_memory) { - LOG_ERROR("Target %s doesn't support read_phys_memory", target_name(target)); + LOG_TARGET_ERROR(target, "doesn't support read_phys_memory"); return ERROR_FAIL; } int result = target->type->read_phys_memory(target, address, size, count, buffer); @@ -1278,12 +1283,12 @@ int target_read_phys_memory(struct target *target, int target_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + if (!target_memory_ready(target)) { + LOG_TARGET_ERROR(target, "Memory not ready"); return ERROR_FAIL; } if (!target->type->write_memory) { - LOG_ERROR("Target %s doesn't support write_memory", target_name(target)); + LOG_TARGET_ERROR(target, "doesn't support write_memory"); return ERROR_FAIL; } int result = target->type->write_memory(target, address, size, count, buffer); @@ -1295,12 +1300,12 @@ int target_write_memory(struct target *target, int target_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + if (!target_memory_ready(target)) { + LOG_TARGET_ERROR(target, "Memory not ready"); return ERROR_FAIL; } if (!target->type->write_phys_memory) { - LOG_ERROR("Target %s doesn't support write_phys_memory", target_name(target)); + LOG_TARGET_ERROR(target, "doesn't support write_phys_memory"); return ERROR_FAIL; } int result = target->type->write_phys_memory(target, address, size, count, buffer); @@ -1369,9 +1374,9 @@ int target_hit_watchpoint(struct target *target, 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 + * return error such that gdb_server will not take the nonsense * information. */ - return ERROR_FAIL; + return ERROR_NOT_IMPLEMENTED; } return target->type->hit_watchpoint(target, hit_watchpoint); @@ -1391,7 +1396,8 @@ int target_get_gdb_reg_list(struct target *target, int result = ERROR_FAIL; if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + LOG_TARGET_ERROR(target, "not examined"); + result = ERROR_TARGET_NOT_EXAMINED; goto done; } @@ -1431,6 +1437,11 @@ int target_step(struct target *target, { int retval; + if (!target_was_examined(target)) { + LOG_TARGET_ERROR(target, "not examined"); + return ERROR_TARGET_NOT_EXAMINED; + } + target_call_event_callbacks(target, TARGET_EVENT_STEP_START); retval = target->type->step(target, current, address, handle_breakpoints); @@ -1496,6 +1507,7 @@ static int target_init_one(struct command_context *cmd_ctx, struct target *target) { target_reset_examined(target); + target_reset_active_polled(target); struct target_type *type = target->type; if (!type->examine) @@ -1674,6 +1686,18 @@ int target_register_trace_callback(int (*callback)(struct target *target, return ERROR_OK; } +static int target_timer_callback_set_period(struct target_timer_callback *cb, unsigned int time_ms) +{ + if (!cb) + return ERROR_FAIL; + + cb->time_ms = time_ms; + cb->when = timeval_ms() + time_ms; + target_timer_next_event_value = MIN(target_timer_next_event_value, cb->when); + + return ERROR_OK; +} + int target_register_timer_callback(int (*callback)(void *priv), unsigned int time_ms, enum target_timer_type type, void *priv) { @@ -1691,16 +1715,12 @@ int target_register_timer_callback(int (*callback)(void *priv), (*callbacks_p) = malloc(sizeof(struct target_timer_callback)); (*callbacks_p)->callback = callback; (*callbacks_p)->type = type; - (*callbacks_p)->time_ms = time_ms; (*callbacks_p)->removed = false; - (*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; - return ERROR_OK; + return target_timer_callback_set_period(*callbacks_p, time_ms); } int target_unregister_event_callback(int (*callback)(struct target *target, @@ -1764,17 +1784,30 @@ int target_unregister_trace_callback(int (*callback)(struct target *target, return ERROR_OK; } -int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) +static struct target_timer_callback *target_find_timer_callback(int (*callback)(void *priv), + void *priv) { if (!callback) - return ERROR_COMMAND_SYNTAX_ERROR; + return NULL; for (struct target_timer_callback *c = target_timer_callbacks; c; c = c->next) { - if ((c->callback == callback) && (c->priv == priv)) { - c->removed = true; - return ERROR_OK; - } + if (c->callback == callback && c->priv == priv) + return c; + } + + return NULL; +} + +int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) +{ + if (!callback) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target_timer_callback *cb = target_find_timer_callback(callback, priv); + if (cb) { + cb->removed = true; + return ERROR_OK; } return ERROR_FAIL; @@ -1987,7 +2020,7 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w /* Reevaluate working area address based on MMU state*/ if (!target->working_areas) { int retval; - int enabled; + bool enabled; retval = target->type->mmu(target, &enabled); if (retval != ERROR_OK) @@ -2199,6 +2232,22 @@ uint32_t target_get_working_area_avail(struct target *target) return max_size; } +static void free_smp_target_list(struct list_head *smp_targets) +{ + assert(smp_targets); + if (smp_targets == &empty_smp_targets) + return; + + struct target_list *head, *tmp; + list_for_each_entry_safe(head, tmp, smp_targets, lh) { + list_del(&head->lh); + head->target->smp = 0; + head->target->smp_targets = &empty_smp_targets; + free(head); + } + free(smp_targets); +} + static void target_destroy(struct target *target) { breakpoint_remove_all(target); @@ -2222,19 +2271,7 @@ static void target_destroy(struct target *target) target_free_all_working_areas(target); - /* release the targets SMP list */ - if (target->smp) { - 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); - } - if (target->smp_targets != &empty_smp_targets) - free(target->smp_targets); - target->smp = 0; - } + free_smp_target_list(target->smp_targets); rtos_destroy(target); @@ -2277,7 +2314,6 @@ void target_quit(void) int target_arch_state(struct target *target) { - int retval; if (!target) { LOG_WARNING("No target has been configured"); return ERROR_OK; @@ -2286,8 +2322,7 @@ int target_arch_state(struct target *target) if (target->state != TARGET_HALTED) return ERROR_OK; - retval = target->type->arch_state(target); - return retval; + return target->type->arch_state(target); } static int target_get_gdb_fileio_info_default(struct target *target, @@ -2309,10 +2344,7 @@ static int target_gdb_fileio_end_default(struct target *target, 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; - - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, seconds, 0); + int64_t then = timeval_ms() + seconds * 1000LL; LOG_INFO("Starting profiling. Halting and resuming the" " target as often as we can..."); @@ -2343,8 +2375,7 @@ int target_profiling_default(struct target *target, uint32_t *samples, if (retval != ERROR_OK) break; - gettimeofday(&now, NULL); - if ((sample_count >= max_num_samples) || timeval_compare(&now, &timeout) >= 0) { + if (sample_count >= max_num_samples || timeval_ms() >= then) { LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); break; } @@ -2354,6 +2385,20 @@ int target_profiling_default(struct target *target, uint32_t *samples, return retval; } +static int target_insn_set(struct command_invocation *cmd, struct target *target, + const char **insn_set) +{ + if (target->type->insn_set) + return target->type->insn_set(cmd, target, insn_set); + + command_print(cmd, "Instruction-set detection not implemented on target %s", + target_name(target)); + command_print(cmd, "Change target or specify one of the instruction set:"); + oocd_cs_list_insn_types(cmd); + + return ERROR_NOT_IMPLEMENTED; +} + /* Single aligned words are guaranteed to use 16 or 32 bit access * mode respectively, otherwise data is handled as quickly as * possible @@ -2363,8 +2408,8 @@ int target_write_buffer(struct target *target, target_addr_t address, uint32_t s LOG_DEBUG("writing buffer of %" PRIu32 " byte at " TARGET_ADDR_FMT, size, address); - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + if (!target_memory_ready(target)) { + LOG_TARGET_ERROR(target, "Memory not ready"); return ERROR_FAIL; } @@ -2428,8 +2473,8 @@ int target_read_buffer(struct target *target, target_addr_t address, uint32_t si LOG_DEBUG("reading buffer of %" PRIu32 " byte at " TARGET_ADDR_FMT, size, address); - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + if (!target_memory_ready(target)) { + LOG_TARGET_ERROR(target, "Memory not ready"); return ERROR_FAIL; } @@ -2488,8 +2533,8 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_ assert(target); assert(crc); if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; + LOG_TARGET_ERROR(target, "not examined"); + return ERROR_TARGET_NOT_EXAMINED; } if (!target->type->checksum_memory) { LOG_ERROR("Target %s doesn't support checksum_memory", target_name(target)); @@ -2511,8 +2556,8 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_ uint8_t *buffer = malloc(size); if (!buffer) { - LOG_ERROR("error allocating buffer of %" PRIu32 " bytes", size); - return ERROR_COMMAND_SYNTAX_ERROR; + LOG_ERROR("error allocating buffer for section (%" PRIu32 " bytes)", size); + return ERROR_FAIL; } int retval = target_read_buffer(target, address, size, buffer); @@ -2521,14 +2566,6 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_ return retval; } - /* convert to target endianness */ - /* FIXME: we should handle cases when size is not multiple of sizeof(uint32_t) */ - for (uint32_t i = 0; i < (size / sizeof(uint32_t)); i++) { - uint32_t target_data; - target_data = target_buffer_get_u32(target, &buffer[i * sizeof(uint32_t)]); - target_buffer_set_u32(target, &buffer[i * sizeof(uint32_t)], target_data); - } - retval = image_calculate_checksum(buffer, size, crc); free(buffer); @@ -2536,33 +2573,30 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_ } int target_blank_check_memory(struct target *target, - struct target_memory_check_block *blocks, int num_blocks, - uint8_t erased_value) + struct target_memory_check_block *blocks, unsigned int num_blocks, + uint8_t erased_value, unsigned int *checked) { if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; + LOG_TARGET_ERROR(target, "not examined"); + return ERROR_TARGET_NOT_EXAMINED; } if (!target->type->blank_check_memory) return ERROR_NOT_IMPLEMENTED; - return target->type->blank_check_memory(target, blocks, num_blocks, erased_value); + return target->type->blank_check_memory(target, blocks, num_blocks, + erased_value, checked); } int target_read_u64(struct target *target, target_addr_t address, uint64_t *value) { uint8_t value_buf[8]; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } int retval = target_read_memory(target, address, 8, 1, value_buf); if (retval == ERROR_OK) { *value = target_buffer_get_u64(target, value_buf); - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64, address, *value); } else { @@ -2577,16 +2611,12 @@ int target_read_u64(struct target *target, target_addr_t address, uint64_t *valu int target_read_u32(struct target *target, target_addr_t address, uint32_t *value) { uint8_t value_buf[4]; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } int retval = target_read_memory(target, address, 4, 1, value_buf); if (retval == ERROR_OK) { *value = target_buffer_get_u32(target, value_buf); - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32, address, *value); } else { @@ -2601,10 +2631,6 @@ int target_read_u32(struct target *target, target_addr_t address, uint32_t *valu int target_read_u16(struct target *target, target_addr_t address, uint16_t *value) { uint8_t value_buf[2]; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } int retval = target_read_memory(target, address, 2, 1, value_buf); @@ -2624,11 +2650,6 @@ int target_read_u16(struct target *target, target_addr_t address, uint16_t *valu int target_read_u8(struct target *target, target_addr_t address, uint8_t *value) { - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } - int retval = target_read_memory(target, address, 1, 1, value); if (retval == ERROR_OK) { @@ -2648,12 +2669,8 @@ int target_write_u64(struct target *target, target_addr_t address, uint64_t valu { int retval; uint8_t value_buf[8]; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64, address, value); @@ -2669,12 +2686,8 @@ int target_write_u32(struct target *target, target_addr_t address, uint32_t valu { int retval; uint8_t value_buf[4]; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32, address, value); @@ -2690,10 +2703,6 @@ int target_write_u16(struct target *target, target_addr_t address, uint16_t valu { int retval; uint8_t value_buf[2]; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx16, address, @@ -2710,10 +2719,6 @@ int target_write_u16(struct target *target, target_addr_t address, uint16_t valu int target_write_u8(struct target *target, target_addr_t address, uint8_t value) { int retval; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%2.2" PRIx8, address, value); @@ -2729,12 +2734,8 @@ int target_write_phys_u64(struct target *target, target_addr_t address, uint64_t { int retval; uint8_t value_buf[8]; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64, address, value); @@ -2750,12 +2751,8 @@ int target_write_phys_u32(struct target *target, target_addr_t address, uint32_t { int retval; uint8_t value_buf[4]; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32, address, value); @@ -2771,10 +2768,6 @@ int target_write_phys_u16(struct target *target, target_addr_t address, uint16_t { int retval; uint8_t value_buf[2]; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx16, address, @@ -2791,10 +2784,6 @@ int target_write_phys_u16(struct target *target, target_addr_t address, uint16_t int target_write_phys_u8(struct target *target, target_addr_t address, uint8_t value) { int retval; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%2.2" PRIx8, address, value); @@ -2869,10 +2858,10 @@ COMMAND_HANDLER(handle_targets_command) return retval; } -/* every 300ms we check for reset & powerdropout and issue a "reset halt" if so. */ +/* every polling_interval we check for reset & powerdropout */ -static int power_dropout; -static int srst_asserted; +static int sensed_power_dropout; +static int sensed_srst_asserted; static int run_power_restore; static int run_power_dropout; @@ -2884,29 +2873,29 @@ static int sense_handler(void) static int prev_srst_asserted; static int prev_power_dropout; - int retval = jtag_power_dropout(&power_dropout); + int retval = jtag_power_dropout(&sensed_power_dropout); if (retval != ERROR_OK) return retval; int power_restored; - power_restored = prev_power_dropout && !power_dropout; + power_restored = prev_power_dropout && !sensed_power_dropout; if (power_restored) run_power_restore = 1; int64_t current = timeval_ms(); static int64_t last_power; bool wait_more = last_power + 2000 > current; - if (power_dropout && !wait_more) { + if (sensed_power_dropout && !wait_more) { run_power_dropout = 1; last_power = current; } - retval = jtag_srst_asserted(&srst_asserted); + retval = jtag_srst_asserted(&sensed_srst_asserted); if (retval != ERROR_OK) return retval; int srst_deasserted; - srst_deasserted = prev_srst_asserted && !srst_asserted; + srst_deasserted = prev_srst_asserted && !sensed_srst_asserted; static int64_t last_srst; wait_more = last_srst + 2000 > current; @@ -2915,11 +2904,11 @@ static int sense_handler(void) last_srst = current; } - if (!prev_srst_asserted && srst_asserted) + if (!prev_srst_asserted && sensed_srst_asserted) run_srst_asserted = 1; - prev_srst_asserted = srst_asserted; - prev_power_dropout = power_dropout; + prev_srst_asserted = sensed_srst_asserted; + prev_power_dropout = sensed_power_dropout; if (srst_deasserted || power_restored) { /* Other than logging the event we can't do anything here. @@ -2931,11 +2920,24 @@ static int sense_handler(void) return ERROR_OK; } +static int handle_one_target(struct target *target) +{ + if (!target_active_polled(target) || !target->tap->enabled) + return ERROR_OK; + + int res = target_poll(target); + if (res == ERROR_OK) + return res; + + LOG_TARGET_ERROR(target, "Polling failed, trying to reexamine"); + target_reset_examined(target); + return target_examine_one(target); +} + /* process target state changes */ static int handle_target(void *priv) { Jim_Interp *interp = (Jim_Interp *)priv; - int retval = ERROR_OK; if (!is_jtag_poll_safe()) { /* polling is disabled currently */ @@ -2986,50 +2988,36 @@ static int handle_target(void *priv) recursive = 0; } + /* FIXME: sensed SRST state should be treated similarly as + * active SRST control and honour reset config RESET_SRST_NO_GATING */ + if (sensed_power_dropout || sensed_srst_asserted) + return ERROR_OK; + + int retval = ERROR_OK; /* Poll targets for state changes unless that's globally disabled. * Skip targets that are currently disabled. */ for (struct target *target = all_targets; is_jtag_poll_safe() && target; target = target->next) { - /* This function only gets called every polling_interval, so * allow some slack in the time comparison. Otherwise, if we * schedule for now+polling_interval, the next poll won't * actually happen until a polling_interval later. */ - bool poll_needed = timeval_ms() + polling_interval / 2 >= target->backoff.next_attempt; - if (!target->tap->enabled || power_dropout || srst_asserted || !poll_needed) + if (timeval_ms() + polling_interval / 2 < target->backoff.next_attempt) continue; - /* polling may fail silently until the target has been examined */ - retval = target_poll(target); - if (retval == ERROR_OK) { - /* Polling succeeded, reset the back-off interval */ - target->backoff.interval = polling_interval; - } else { - /* Increase interval between polling up to 5000ms */ + int tgt_res = handle_one_target(target); + if (tgt_res != ERROR_OK) { + retval = tgt_res; target->backoff.interval = MAX(polling_interval, - MIN(target->backoff.interval * 2 + 1, 5000)); - /* Do *not* tell gdb the target halted. This might just - * be a hiccup. We have no reason to believe the target - * is halted, and if it is running while gdb thinks it's - * halted things just get unnecessarily confused. gdb - * users can hit ^C if the need to interact with the - * target. */ + MIN(target->backoff.interval * 2u + 1u, TARGET_MAX_POLLING_INTERVAL_MS)); + } else { + target->backoff.interval = polling_interval; } target->backoff.next_attempt = timeval_ms() + target->backoff.interval; - LOG_TARGET_DEBUG(target, "target_poll() -> %d, next attempt in %dms", - retval, target->backoff.interval); - - if (retval != ERROR_OK && examine_attempted) { - target_reset_examined(target); - retval = target_examine_one(target); - if (retval != ERROR_OK) { - LOG_TARGET_DEBUG(target, "Examination failed. Polling again in %dms", - target->backoff.interval); - return retval; - } - } + LOG_TARGET_DEBUG_IO(target, "target_poll() -> %d, next attempt in %ums", + tgt_res, target->backoff.interval); } return retval; @@ -3041,7 +3029,7 @@ COMMAND_HANDLER(handle_reg_command) struct target *target = get_current_target(CMD_CTX); if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + command_print(CMD, "Error: [%s] not examined", target_name(target)); return ERROR_TARGET_NOT_EXAMINED; } struct reg *reg = NULL; @@ -3070,13 +3058,13 @@ COMMAND_HANDLER(handle_reg_command) count, reg->name, reg->size, value, reg->dirty - ? " (dirty)" - : ""); + ? " (dirty)" + : ""); free(value); } else { command_print(CMD, "(%i) %s (/%" PRIu32 ")", - count, reg->name, - reg->size); + count, reg->name, + reg->size); } } cache = cache->next; @@ -3220,6 +3208,36 @@ COMMAND_HANDLER(handle_poll_command) return retval; } +COMMAND_HANDLER(handle_poll_interval_command) +{ + int retval; + unsigned int ms; + + switch (CMD_ARGC) { + case 0: + command_print(CMD, "%d", polling_interval); + break; + case 1: + retval = parse_uint(CMD_ARGV[0], &ms); + if (retval != ERROR_OK) + return ERROR_COMMAND_ARGUMENT_INVALID; + + /* If the timer callback has been registered, update the timer callback period */ + struct target_timer_callback *cb = target_find_timer_callback(&handle_target, CMD_CTX->interp); + if (cb) { + retval = target_timer_callback_set_period(cb, ms); + if (retval != ERROR_OK) + return retval; + } + polling_interval = ms; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return ERROR_OK; +} + COMMAND_HANDLER(handle_wait_halt_command) { if (CMD_ARGC > 1) @@ -3372,7 +3390,7 @@ COMMAND_HANDLER(handle_step_command) } void target_handle_md_output(struct command_invocation *cmd, - struct target *target, target_addr_t address, unsigned size, + struct target *target, target_addr_t address, unsigned int size, unsigned int count, const uint8_t *buffer, bool include_address) { const unsigned int line_bytecnt = 32; @@ -3401,8 +3419,8 @@ void target_handle_md_output(struct command_invocation *cmd, return; } - for (unsigned i = 0; i < count; i++) { - if (include_address && (i % line_modulo == 0)) { + for (unsigned int i = 0; i < count; i++) { + if (include_address && i % line_modulo == 0) { output_len += snprintf(output + output_len, sizeof(output) - output_len, TARGET_ADDR_FMT ": ", @@ -3486,8 +3504,7 @@ COMMAND_HANDLER(handle_md_command) struct target *target = get_current_target(CMD_CTX); int retval = fn(target, address, size, count, buffer); if (retval == ERROR_OK) - target_handle_md_output(CMD, target, address, size, count, buffer, - true); + target_handle_md_output(CMD, target, address, size, count, buffer, true); free(buffer); @@ -3581,20 +3598,20 @@ COMMAND_HANDLER(handle_mw_command) struct target *target = get_current_target(CMD_CTX); unsigned int wordsize; switch (CMD_NAME[2]) { - case 'd': - wordsize = 8; - break; - case 'w': - wordsize = 4; - break; - case 'h': - wordsize = 2; - break; - case 'b': - wordsize = 1; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'd': + wordsize = 8; + break; + case 'w': + wordsize = 4; + break; + case 'h': + wordsize = 2; + break; + case 'b': + wordsize = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } return target_fill_mem(target, address, fn, wordsize, value, count); @@ -3704,7 +3721,7 @@ COMMAND_HANDLER(handle_load_image_command) free(buffer); } - if ((retval == ERROR_OK) && (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)); @@ -3761,7 +3778,7 @@ COMMAND_HANDLER(handle_dump_image_command) free(buffer); - if ((retval == ERROR_OK) && (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) @@ -3906,7 +3923,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver done: if (diffs > 0) retval = ERROR_FAIL; - if ((retval == ERROR_OK) && (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)); @@ -3987,7 +4004,7 @@ static int handle_bp_command_set(struct command_invocation *cmd, retval = context_breakpoint_add(target, asid, length, hw); /* error is always logged in context_breakpoint_add(), do not print it again */ if (retval == ERROR_OK) - command_print(cmd, "Context breakpoint set at 0x%8.8" PRIx32 "", asid); + command_print(cmd, "Context breakpoint set at 0x%8.8" PRIx32, asid); } else { if (!target->type->add_hybrid_breakpoint) { @@ -3997,7 +4014,7 @@ static int handle_bp_command_set(struct command_invocation *cmd, retval = hybrid_breakpoint_add(target, addr, asid, length, hw); /* error is always logged in hybrid_breakpoint_add(), do not print it again */ if (retval == ERROR_OK) - command_print(cmd, "Hybrid breakpoint set at 0x%8.8" PRIx32 "", asid); + command_print(cmd, "Hybrid breakpoint set at 0x%8.8" PRIx32, asid); } return retval; } @@ -4010,39 +4027,39 @@ COMMAND_HANDLER(handle_bp_command) int hw = BKPT_SOFT; switch (CMD_ARGC) { - case 0: - return handle_bp_command_list(CMD); + case 0: + return handle_bp_command_list(CMD); - case 2: - asid = 0; + case 2: + asid = 0; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); + return handle_bp_command_set(CMD, addr, asid, length, hw); + + case 3: + if (strcmp(CMD_ARGV[2], "hw") == 0) { + hw = BKPT_HARD; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); + asid = 0; return handle_bp_command_set(CMD, addr, asid, length, hw); - - case 3: - if (strcmp(CMD_ARGV[2], "hw") == 0) { - hw = BKPT_HARD; - COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); - asid = 0; - return handle_bp_command_set(CMD, addr, asid, length, hw); - } else if (strcmp(CMD_ARGV[2], "hw_ctx") == 0) { - hw = BKPT_HARD; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], asid); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); - addr = 0; - return handle_bp_command_set(CMD, addr, asid, length, hw); - } - /* fallthrough */ - case 4: + } else if (strcmp(CMD_ARGV[2], "hw_ctx") == 0) { hw = BKPT_HARD; - COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], asid); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], length); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], asid); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); + addr = 0; return handle_bp_command_set(CMD, addr, asid, length, hw); + } + /* fallthrough */ + case 4: + hw = BKPT_HARD; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], asid); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], length); + return handle_bp_command_set(CMD, addr, asid, length, hw); - default: - return ERROR_COMMAND_SYNTAX_ERROR; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } } @@ -4222,112 +4239,100 @@ static void write_string(FILE *f, char *s) typedef unsigned char UNIT[2]; /* unit of profiling */ -/* Dump a gmon.out histogram file. */ -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) +static void write_gmon_hist(FILE *f, const uint32_t *samples, uint32_t sample_num, + float sample_rate, struct target *target) { - uint32_t i; - FILE *f = fopen(filename, "wb"); - if (!f) - return; - 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 */ - write_data(f, &zero, 1); + uint32_t min = samples[0]; + uint32_t max = samples[sample_num - 1]; - /* figure out bucket size */ - uint32_t min; - uint32_t max; - if (with_range) { - min = start_address; - max = end_address; - } else { - min = samples[0]; - max = samples[0]; - for (i = 0; i < sample_num; i++) { - if (min > samples[i]) - min = samples[i]; - if (max < samples[i]) - max = samples[i]; - } - - /* max should be (largest sample + 1) - * Refer to binutils/gprof/hist.c (find_histogram_for_pc) */ - if (max < UINT32_MAX) - max++; - - /* gprof requires (max - min) >= 2 */ - while ((max - min) < 2) { - if (max < UINT32_MAX) - max++; - else - min--; - } - } + /* max should be (largest sample + 1) + * Refer to binutils/gprof/hist.c (find_histogram_for_pc) */ + max++; + /* The ratio ((double)((max - min) / 2) / num_buckets) must match across + * all histograms in this file. To avoid trunction in the /2, we must have + * an even length address space for compatibility with binutils <=2.44. + * Refer to binutils/gprof/hist.c (calculation of n_hist_scale)*/ + if ((max - min) % 2) + max++; 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 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) * 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 = num_buckets; - long long c = address_space; - int index_t = (a * b) / c; /* danger!!!! int32 overflows */ - buckets[index_t]++; - } + uint8_t zero = 0; /* GMON_TAG_TIME_HIST */ + write_data(f, &zero, 1); /* append binary memory gmon.out &profile_hist_hdr ((char*)&profile_hist_hdr + sizeof(struct gmon_hist_hdr)) */ 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, address_space / sizeof(UNIT), target); /* # of buckets */ write_long(f, sample_rate, target); write_string(f, "seconds"); - for (i = 0; i < (15-strlen("seconds")); i++) + for (size_t i = strlen("seconds"); i < 15; i++) 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 * num_buckets); - if (data) { - for (i = 0; i < num_buckets; i++) { - int val; - val = buckets[i]; - if (val > 65535) - val = 65535; - data[i * 2] = val&0xff; - data[i * 2 + 1] = (val >> 8) & 0xff; + bool saturated_once = false; + for (uint32_t i = 0, bidx = 0; bidx < address_space; bidx += sizeof(UNIT)) { + uint32_t val = i; + uint32_t bmax = min + bidx + sizeof(UNIT); + while (i < sample_num && samples[i] < bmax) + ++i; + val = i - val; + + if (val > UINT16_MAX) { + val = UINT16_MAX; + if (!saturated_once) + LOG_WARNING("profiler bucket saturated, will read as 65535"); + saturated_once = true; } - free(buckets); - write_data(f, data, num_buckets * 2); - free(data); - } else - free(buckets); + + uint8_t data[2]; + h_u16_to_le(data, val); + write_data(f, data, 2); + } +} + +/* Dump a gmon.out histogram file. */ +static void write_gmon(const uint32_t *samples, uint32_t sample_num, const char *filename, + struct target *target, uint32_t duration_ms) +{ + float sample_rate = sample_num / (duration_ms / 1000.0); + FILE *f = fopen(filename, "wb"); + if (!f) + return; + 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 */ + + while (sample_num) { + /* if address gap exceeds this, make another histogram */ + const uint32_t MAX_GAP = 32; + + /* figure out bucket size */ + uint32_t max = samples[0]; + uint32_t this_pass = 1; + while (this_pass < sample_num && samples[this_pass] - max < MAX_GAP) + max = samples[this_pass++]; + + write_gmon_hist(f, samples, this_pass, sample_rate, target); + + samples += this_pass; + sample_num -= this_pass; + } fclose(f); } +// comparison function for qsort(). Returns -1, 0 or +1 +static int compare_pc32(const void *p1, const void *p2) +{ + uint32_t lhs = *(const uint32_t *)p1; + uint32_t rhs = *(const uint32_t *)p2; + return (lhs > rhs) - (lhs < rhs); +} + /* profiling samples the CPU PC as quickly as OpenOCD is able, * which will be used as a random sampling of PC */ COMMAND_HANDLER(handle_profile_command) @@ -4376,7 +4381,7 @@ COMMAND_HANDLER(handle_profile_command) free(samples); return retval; } - uint32_t duration_ms = timeval_ms() - timestart_ms; + uint64_t duration_ms = timeval_ms() - timestart_ms; assert(num_of_samples <= MAX_PROFILE_SAMPLE_NUM); @@ -4410,12 +4415,38 @@ COMMAND_HANDLER(handle_profile_command) return retval; } - write_gmon(samples, num_of_samples, CMD_ARGV[1], - with_range, start_address, end_address, target, duration_ms); + if (!num_of_samples) { + command_print(CMD, "Wrote no samples"); + free(samples); + return ERROR_OK; + } + + if (with_range) { + uint32_t num_filtered_samples = 0; + for (uint32_t in = 0; in < num_of_samples; ++in) { + uint32_t sample = samples[in]; + if (sample >= start_address && sample < end_address) + samples[num_filtered_samples++] = sample; + } + duration_ms = (duration_ms * num_filtered_samples + num_of_samples / 2) / num_of_samples; + if (duration_ms < 1) + duration_ms = 0; + num_of_samples = num_filtered_samples; + + if (!num_of_samples) { + command_print(CMD, "Wrote no samples in the requested range"); + free(samples); + return ERROR_OK; + } + } + + qsort(samples, num_of_samples, sizeof(samples[0]), compare_pc32); + + write_gmon(samples, num_of_samples, CMD_ARGV[1], target, duration_ms); command_print(CMD, "Wrote %s", CMD_ARGV[1]); free(samples); - return retval; + return ERROR_OK; } COMMAND_HANDLER(handle_target_read_memory) @@ -4677,11 +4708,18 @@ COMMAND_HANDLER(handle_target_write_memory) */ void target_handle_event(struct target *target, enum target_event e) { - struct target_event_action *teap; + struct target_event_action *teap, *tmp; int retval; - list_for_each_entry(teap, &target->events_action, list) { + list_for_each_entry_safe(teap, tmp, &target->events_action, list) { if (teap->event == e) { + /* + * The event can be destroyed by its own handler. + * Make a local copy and use it in place of the original. + */ + struct target_event_action local_teap = *teap; + teap = &local_teap; + LOG_DEBUG("target: %s (%s) event: %d (%s) action: %s", target_name(target), target_type_name(target), @@ -4697,7 +4735,13 @@ void target_handle_event(struct target *target, enum target_event e) struct target *saved_target_override = cmd_ctx->current_target_override; cmd_ctx->current_target_override = target; + /* + * The event can be destroyed by its own handler. + * Prevent the body to get deallocated by Jim. + */ + Jim_IncrRefCount(teap->body); retval = Jim_EvalObj(teap->interp, teap->body); + Jim_DecrRefCount(teap->interp, teap->body); cmd_ctx->current_target_override = saved_target_override; @@ -4740,13 +4784,17 @@ COMMAND_HANDLER(handle_target_get_reg) const int length = Jim_ListLength(CMD_CTX->interp, next_argv); const struct target *target = get_current_target(CMD_CTX); + if (target->state != TARGET_HALTED) { + command_print(CMD, "Error: [%s] not halted", target_name(target)); + return ERROR_TARGET_NOT_HALTED; + } for (int i = 0; i < length; i++) { Jim_Obj *elem = Jim_ListGetIndex(CMD_CTX->interp, next_argv, i); const char *reg_name = Jim_String(elem); - struct reg *reg = register_get_by_name(target->reg_cache, reg_name, false); + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, true); if (!reg || !reg->exist) { command_print(CMD, "unknown register '%s'", reg_name); @@ -4800,11 +4848,16 @@ COMMAND_HANDLER(handle_set_reg_command) const struct target *target = get_current_target(CMD_CTX); assert(target); + if (target->state != TARGET_HALTED) { + command_print(CMD, "Error: [%s] not halted", target_name(target)); + return ERROR_TARGET_NOT_HALTED; + } + 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); + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, true); if (!reg || !reg->exist) { command_print(CMD, "unknown register '%s'", reg_name); @@ -4937,7 +4990,8 @@ static COMMAND_HELPER(target_configure, struct target *target, unsigned int inde case TCFG_EVENT: if (index == CMD_ARGC) { - command_print(CMD, "missing event-name"); + command_print(CMD, "expecting %s event-name event-body", + CMD_ARGV[index - 1]); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -4950,7 +5004,8 @@ static COMMAND_HELPER(target_configure, struct target *target, unsigned int inde if (is_configure) { if (index == CMD_ARGC) { - command_print(CMD, "missing event-body"); + command_print(CMD, "expecting %s %s event-body", + CMD_ARGV[index - 2], CMD_ARGV[index - 1]); return ERROR_COMMAND_ARGUMENT_INVALID; } } @@ -5401,8 +5456,10 @@ COMMAND_HANDLER(handle_target_reset) /* do the assert */ if (n->value == NVP_ASSERT) { int retval = target->type->assert_reset(target); - if (target->defer_examine) + if (target->defer_examine) { target_reset_examined(target); + target_reset_active_polled(target); + } return retval; } @@ -5526,6 +5583,36 @@ COMMAND_HANDLER(handle_target_invoke_event) return ERROR_OK; } +COMMAND_HANDLER(handle_target_disassemble) +{ + struct target *target = get_current_target(CMD_CTX); + + if (CMD_ARGC < 1 || CMD_ARGC > 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (CMD_ARGC == 1 && !strcmp("list", CMD_ARGV[0])) + return oocd_cs_list_insn_types(CMD); + + target_addr_t address; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); + + unsigned int count = 1; + if (CMD_ARGC > 1) + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count); + + const char *insn_set; + if (CMD_ARGC > 2) { + insn_set = CMD_ARGV[2]; + } else { + int retval = target_insn_set(CMD, target, &insn_set); + if (retval != ERROR_OK) + return retval; + LOG_TARGET_DEBUG(target, "instruction set \"%s\"", insn_set); + } + + return oocd_cs_disassemble(CMD, target, address, count, insn_set); +} + static const struct command_registration target_instance_command_handlers[] = { { .name = "configure", @@ -5709,15 +5796,21 @@ static const struct command_registration target_instance_command_handlers[] = { .help = "invoke handler for specified event", .usage = "event_name", }, + { + .name = "disassemble", + .mode = COMMAND_EXEC, + .handler = handle_target_disassemble, + .help = "disassemble instructions", + .usage = "list | address [count [instruction_set]]", + }, COMMAND_REGISTRATION_DONE }; COMMAND_HANDLER(handle_target_create) { int retval = ERROR_OK; - int x; - if (CMD_ARGC < 4) + if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* check if the target name clashes with an existing command name */ @@ -5739,15 +5832,16 @@ COMMAND_HANDLER(handle_target_create) LOG_INFO("The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD"); } /* now does target type exist */ - for (x = 0 ; target_types[x] ; x++) { + size_t x; + for (x = 0 ; x < ARRAY_SIZE(target_types) ; x++) { if (strcmp(cp, target_types[x]->name) == 0) { /* found */ break; } } - if (!target_types[x]) { + if (x == ARRAY_SIZE(target_types)) { char *all = NULL; - for (x = 0 ; target_types[x] ; x++) { + for (x = 0 ; x < ARRAY_SIZE(target_types) ; x++) { char *prev = all; if (all) all = alloc_printf("%s, %s", all, target_types[x]->name); @@ -5949,7 +6043,7 @@ COMMAND_HANDLER(handle_target_types) if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; - for (unsigned int x = 0; target_types[x]; x++) + for (size_t x = 0; x < ARRAY_SIZE(target_types); x++) command_print(CMD, "%s", target_types[x]->name); return ERROR_OK; @@ -6033,8 +6127,11 @@ COMMAND_HANDLER(handle_target_smp) 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; + free_smp_target_list(target->smp_targets); + } foreach_smp_target(curr, lh) { struct target *target = curr->target; target->smp = smp_group; @@ -6047,6 +6144,9 @@ COMMAND_HANDLER(handle_target_smp) if (retval == ERROR_OK && rtos_target) retval = rtos_smp_init(rtos_target); + if (retval != ERROR_OK) + free_smp_target_list(lh); + return retval; } @@ -6062,7 +6162,7 @@ static const struct command_registration target_subcommand_handlers[] = { .name = "create", .mode = COMMAND_CONFIG, .handler = handle_target_create, - .usage = "name type '-chain-position' name [options ...]", + .usage = "name type [options ...]", .help = "Creates and selects a new target", }, { @@ -6202,7 +6302,7 @@ COMMAND_HANDLER(handle_fast_load_image_command) free(buffer); } - if ((retval == ERROR_OK) && (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)); @@ -6265,6 +6365,13 @@ static const struct command_registration target_command_handlers[] = { .chain = target_subcommand_handlers, .usage = "", }, + { + .name = "poll_interval", + .handler = handle_poll_interval_command, + .mode = COMMAND_ANY, + .help = "print or set the target state polling interval", + .usage = "[milliseconds]", + }, COMMAND_REGISTRATION_DONE }; @@ -6763,6 +6870,13 @@ static const struct command_registration target_exec_command_handlers[] = { .help = "Test the target's memory access functions", .usage = "size", }, + { + .name = "disassemble", + .mode = COMMAND_EXEC, + .handler = handle_target_disassemble, + .help = "disassemble instructions", + .usage = "list | address [count [instruction_set]]", + }, COMMAND_REGISTRATION_DONE }; @@ -6784,25 +6898,25 @@ static int target_register_user_commands(struct command_context *cmd_ctx) 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!"; + 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 fd5bc4fde6..5db14db56a 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -126,12 +126,19 @@ struct target { bool defer_examine; /** - * Indicates whether this target has been examined. + * Indicates whether this target has been examined, + * remembers the last result of examine call. * * Do @b not access this field directly, use target_was_examined() * or target_set_examined(). */ bool examined; + /** + * The flag is set after a successful examine call. + * It remains set forever or in the case of defer examine + * gets reset by reset command. + */ + bool active_polled; /** * true if the target is currently running a downloaded @@ -431,16 +438,28 @@ const char *target_type_name(const struct target *target); */ int target_examine_one(struct target *target); -/** @returns @c true if target_set_examined() has been called. */ +/** @returns @c true if target_set_examined() has been called. + * The returned value reflects the last examination result. */ static inline bool target_was_examined(const struct target *target) { return target->examined; } -/** Sets the @c examined flag for the given target. */ -/** Use in target->type->examine() after one-time setup is done. */ +/** @returns @c true if target_set_examined() has been called. + * The flag remains set forever or in the case of defer examine + * gets reset by reset command */ +static inline bool target_active_polled(const struct target *target) +{ + return target->active_polled; +} + +/** Sets the @c examined and @c active_polled flags for the given target. + * Not necessary to call it in target->type->examine() methods, + * the target infrastructure calls it after successful return + * from this method. */ static inline void target_set_examined(struct target *target) { + target->active_polled = true; target->examined = true; } @@ -602,6 +621,15 @@ int target_run_read_async_algorithm(struct target *target, uint32_t entry_point, uint32_t exit_point, void *arch_info); +/** + * Returns true if target memory is ready to read/write. + * + * This routine is a wrapper for target->type->memory_ready. + * If the target specific check is not implemented, + * returns target_was_examined() + */ +bool target_memory_ready(struct target *target); + /** * Read @a count items of @a size bytes from the memory of @a target at * the @a address given. @@ -665,8 +693,8 @@ int target_read_buffer(struct target *target, int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t *crc); int target_blank_check_memory(struct target *target, - struct target_memory_check_block *blocks, int num_blocks, - uint8_t erased_value); + struct target_memory_check_block *blocks, unsigned int num_blocks, + uint8_t erased_value, unsigned int *checked); int target_wait_state(struct target *target, enum target_state state, unsigned int ms); /** @@ -786,7 +814,7 @@ int target_arch_state(struct target *target); void target_handle_event(struct target *t, enum target_event e); void target_handle_md_output(struct command_invocation *cmd, - struct target *target, target_addr_t address, unsigned size, + struct target *target, target_addr_t address, unsigned int size, unsigned int count, const uint8_t *buffer, bool include_address); int target_profiling_default(struct target *target, uint32_t *samples, uint32_t @@ -803,15 +831,15 @@ int target_profiling_default(struct target *target, uint32_t *samples, uint32_t #define ERROR_TARGET_TRANSLATION_FAULT (-309) #define ERROR_TARGET_NOT_RUNNING (-310) #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) -#define ERROR_TARGET_HALTED_DO_RESUME (-316) /* used to workaround incorrect debug halt */ +#define ERROR_TARGET_ALGO_EXIT (-312) +#define ERROR_TARGET_SIZE_NOT_SUPPORTED (-313) +#define ERROR_TARGET_PACKING_NOT_SUPPORTED (-314) +#define ERROR_TARGET_HALTED_DO_RESUME (-315) /* used to workaround incorrect debug halt */ extern bool get_target_reset_nag(void); -#define TARGET_DEFAULT_POLLING_INTERVAL 100 +#define TARGET_DEFAULT_POLLING_INTERVAL 100u +#define TARGET_MAX_POLLING_INTERVAL_MS 5000u const char *target_debug_reason_str(enum target_debug_reason reason); diff --git a/src/target/target_request.c b/src/target/target_request.c index 8d51dc3d60..11586a696f 100644 --- a/src/target/target_request.c +++ b/src/target/target_request.c @@ -74,15 +74,15 @@ static int target_hexmsg(struct target *target, int size, uint32_t length) line_len = 0; for (i = 0; i < length; i++) { switch (size) { - case 4: - line_len += snprintf(line + line_len, 128 - line_len, "%8.8" PRIx32 " ", le_to_h_u32(data + (4*i))); - break; - case 2: - line_len += snprintf(line + line_len, 128 - line_len, "%4.4x ", le_to_h_u16(data + (2*i))); - break; - case 1: - line_len += snprintf(line + line_len, 128 - line_len, "%2.2x ", data[i]); - break; + case 4: + line_len += snprintf(line + line_len, 128 - line_len, "%8.8" PRIx32 " ", le_to_h_u32(data + (4 * i))); + break; + case 2: + line_len += snprintf(line + line_len, 128 - line_len, "%4.4x ", le_to_h_u16(data + (2 * i))); + break; + case 1: + line_len += snprintf(line + line_len, 128 - line_len, "%2.2x ", data[i]); + break; } if ((i%8 == 7) || (i == length - 1)) { @@ -120,24 +120,24 @@ int target_request(struct target *target, uint32_t request) } switch (target_req_cmd) { - case TARGET_REQ_TRACEMSG: - trace_point(target, (request & 0xffffff00) >> 8); - break; - case TARGET_REQ_DEBUGMSG: - if (((request & 0xff00) >> 8) == 0) - target_asciimsg(target, (request & 0xffff0000) >> 16); - else - target_hexmsg(target, (request & 0xff00) >> 8, (request & 0xffff0000) >> 16); - break; - case TARGET_REQ_DEBUGCHAR: - target_charmsg(target, (request & 0x00ff0000) >> 16); - break; -/* case TARGET_REQ_SEMIHOSTING: - * break; + case TARGET_REQ_TRACEMSG: + trace_point(target, (request & 0xffffff00) >> 8); + break; + case TARGET_REQ_DEBUGMSG: + if (((request & 0xff00) >> 8) == 0) + target_asciimsg(target, (request & 0xffff0000) >> 16); + else + target_hexmsg(target, (request & 0xff00) >> 8, (request & 0xffff0000) >> 16); + break; + case TARGET_REQ_DEBUGCHAR: + target_charmsg(target, (request & 0x00ff0000) >> 16); + break; +/* case TARGET_REQ_SEMIHOSTING: + * break; */ - default: - LOG_ERROR("unknown target request: %2.2x", target_req_cmd); - break; + default: + LOG_ERROR("unknown target request: %2.2x", target_req_cmd); + break; } return ERROR_OK; diff --git a/src/target/target_type.h b/src/target/target_type.h index 2fb89ca43f..3ad917b87d 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -16,6 +16,7 @@ #include +struct command_invocation; struct target; /** @@ -111,6 +112,12 @@ struct target_type { * count: number of items of */ + /** + * Returns true if target memory is read to read/write. + * Do @b not call this function + * directly, use target_memory_ready() instead. + */ + bool (*memory_ready)(struct target *target); /** * Target memory read callback. Do @b not call this function * directly, use target_read_memory() instead. @@ -135,8 +142,8 @@ struct target_type { int (*checksum_memory)(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int (*blank_check_memory)(struct target *target, - struct target_memory_check_block *blocks, int num_blocks, - uint8_t erased_value); + struct target_memory_check_block *blocks, unsigned int num_blocks, + uint8_t erased_value, unsigned int *checked); /* * target break-/watchpoint control @@ -201,10 +208,6 @@ struct target_type { /* otherwise: JIM_OK, or JIM_ERR, */ 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, struct jim_getopt_info *goi); - /** * This method is used to perform target setup that requires * JTAG access. @@ -268,7 +271,7 @@ struct target_type { int (*write_phys_memory)(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer); - int (*mmu)(struct target *target, int *enabled); + int (*mmu)(struct target *target, bool *enabled); /* after reset is complete, the target can check if things are properly set up. * @@ -309,8 +312,20 @@ struct target_type { * 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); + + /* + * Reports the instruction set in execution on the CPU. + * The returned string should be statically allocated, no free() required. + * The strings should be the same used by Capstone 'cstool' command line + * parameter . + * Returns ERROR_OK or an error code if the current instruction set cannot + * be determined. + */ + int (*insn_set)(struct command_invocation *cmd, struct target *target, + const char **insn_set); }; +// Keep in alphabetic order this list of targets extern struct target_type aarch64_target; extern struct target_type arcv2_target; extern struct target_type arm11_target; diff --git a/src/target/testee.c b/src/target/testee.c index 687565271d..68fa882f27 100644 --- a/src/target/testee.c +++ b/src/target/testee.c @@ -10,6 +10,7 @@ #include +#include "smp.h" #include "target.h" #include "target_type.h" #include "hello.h" @@ -22,6 +23,9 @@ static const struct command_registration testee_command_handlers[] = { .chain = hello_command_handlers, .usage = "", }, + { + .chain = smp_command_handlers, + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/trace.c b/src/target/trace.c index 333a787f92..a92fd27bf4 100644 --- a/src/target/trace.c +++ b/src/target/trace.c @@ -115,7 +115,7 @@ COMMAND_HANDLER(handle_trace_history_command) if (trace->trace_history[i % trace->trace_history_size] < trace->num_trace_points) { uint32_t address; address = trace->trace_points[trace->trace_history[i % trace->trace_history_size]].address; - command_print(CMD, "trace point %i: 0x%8.8" PRIx32 "", + command_print(CMD, "trace point %i: 0x%8.8" PRIx32, (int)(trace->trace_history[i % trace->trace_history_size]), address); } else diff --git a/src/target/x86_32_common.c b/src/target/x86_32_common.c index 8cca9a5e91..8ad9d00fec 100644 --- a/src/target/x86_32_common.c +++ b/src/target/x86_32_common.c @@ -96,7 +96,7 @@ int x86_32_common_init_arch_info(struct target *t, struct x86_32_common *x86_32) return ERROR_OK; } -int x86_32_common_mmu(struct target *t, int *enabled) +int x86_32_common_mmu(struct target *t, bool *enabled) { *enabled = true; return ERROR_OK; @@ -331,27 +331,27 @@ static int read_mem(struct target *t, uint32_t size, } switch (size) { - case BYTE: - if (use32) - retval = x86_32->submit_instruction(t, MEMRDB32); - else - retval = x86_32->submit_instruction(t, MEMRDB16); - break; - case WORD: - if (use32) - retval = x86_32->submit_instruction(t, MEMRDH32); - else - retval = x86_32->submit_instruction(t, MEMRDH16); - break; - case DWORD: - if (use32) - retval = x86_32->submit_instruction(t, MEMRDW32); - else - retval = x86_32->submit_instruction(t, MEMRDW16); - break; - default: - LOG_ERROR("%s invalid read mem size", __func__); - break; + case BYTE: + if (use32) + retval = x86_32->submit_instruction(t, MEMRDB32); + else + retval = x86_32->submit_instruction(t, MEMRDB16); + break; + case WORD: + if (use32) + retval = x86_32->submit_instruction(t, MEMRDH32); + else + retval = x86_32->submit_instruction(t, MEMRDH16); + break; + case DWORD: + if (use32) + retval = x86_32->submit_instruction(t, MEMRDW32); + else + retval = x86_32->submit_instruction(t, MEMRDW16); + break; + default: + LOG_ERROR("%s invalid read mem size", __func__); + break; } if (retval != ERROR_OK) @@ -407,27 +407,27 @@ static int write_mem(struct target *t, uint32_t size, return retval; } switch (size) { - case BYTE: - if (use32) - retval = x86_32->submit_instruction(t, MEMWRB32); - else - retval = x86_32->submit_instruction(t, MEMWRB16); - break; - case WORD: - if (use32) - retval = x86_32->submit_instruction(t, MEMWRH32); - else - retval = x86_32->submit_instruction(t, MEMWRH16); - break; - case DWORD: - if (use32) - retval = x86_32->submit_instruction(t, MEMWRW32); - else - retval = x86_32->submit_instruction(t, MEMWRW16); - break; - default: - LOG_ERROR("%s invalid write mem size", __func__); - return ERROR_FAIL; + case BYTE: + if (use32) + retval = x86_32->submit_instruction(t, MEMWRB32); + else + retval = x86_32->submit_instruction(t, MEMWRB16); + break; + case WORD: + if (use32) + retval = x86_32->submit_instruction(t, MEMWRH32); + else + retval = x86_32->submit_instruction(t, MEMWRH16); + break; + case DWORD: + if (use32) + retval = x86_32->submit_instruction(t, MEMWRW32); + else + retval = x86_32->submit_instruction(t, MEMWRW16); + break; + default: + LOG_ERROR("%s invalid write mem size", __func__); + return ERROR_FAIL; } if (retval != ERROR_OK) @@ -706,27 +706,27 @@ static int x86_32_common_read_io(struct target *t, uint32_t addr, pg_disabled = true; } switch (size) { - case BYTE: - if (use32) - retval = x86_32->submit_instruction(t, IORDB32); - else - retval = x86_32->submit_instruction(t, IORDB16); - break; - case WORD: - if (use32) - retval = x86_32->submit_instruction(t, IORDH32); - else - retval = x86_32->submit_instruction(t, IORDH16); - break; - case DWORD: - if (use32) - retval = x86_32->submit_instruction(t, IORDW32); - else - retval = x86_32->submit_instruction(t, IORDW16); - break; - default: - LOG_ERROR("%s invalid read io size", __func__); - return ERROR_FAIL; + case BYTE: + if (use32) + retval = x86_32->submit_instruction(t, IORDB32); + else + retval = x86_32->submit_instruction(t, IORDB16); + break; + case WORD: + if (use32) + retval = x86_32->submit_instruction(t, IORDH32); + else + retval = x86_32->submit_instruction(t, IORDH16); + break; + case DWORD: + if (use32) + retval = x86_32->submit_instruction(t, IORDW32); + else + retval = x86_32->submit_instruction(t, IORDW16); + break; + default: + LOG_ERROR("%s invalid read io size", __func__); + return ERROR_FAIL; } /* restore CR0.PG bit if needed */ @@ -795,27 +795,27 @@ int x86_32_common_write_io(struct target *t, uint32_t addr, pg_disabled = true; } switch (size) { - case BYTE: - if (use32) - retval = x86_32->submit_instruction(t, IOWRB32); - else - retval = x86_32->submit_instruction(t, IOWRB16); - break; - case WORD: - if (use32) - retval = x86_32->submit_instruction(t, IOWRH32); - else - retval = x86_32->submit_instruction(t, IOWRH16); - break; - case DWORD: - if (use32) - retval = x86_32->submit_instruction(t, IOWRW32); - else - retval = x86_32->submit_instruction(t, IOWRW16); - break; - default: - LOG_ERROR("%s invalid write io size", __func__); - return ERROR_FAIL; + case BYTE: + if (use32) + retval = x86_32->submit_instruction(t, IOWRB32); + else + retval = x86_32->submit_instruction(t, IOWRB16); + break; + case WORD: + if (use32) + retval = x86_32->submit_instruction(t, IOWRH32); + else + retval = x86_32->submit_instruction(t, IOWRH16); + break; + case DWORD: + if (use32) + retval = x86_32->submit_instruction(t, IOWRW32); + else + retval = x86_32->submit_instruction(t, IOWRW16); + break; + default: + LOG_ERROR("%s invalid write io size", __func__); + return ERROR_FAIL; } /* restore CR0.PG bit if needed */ @@ -899,29 +899,29 @@ static int set_debug_regs(struct target *t, uint32_t address, } switch (bp_type) { - case 0: - /* 00 - only on instruction execution */ - DR7_SET_EXE(dr7, bp_num); - DR7_SET_LENGTH(dr7, bp_num, bp_length); - break; - case 1: - /* 01 - only on data writes */ - DR7_SET_WRITE(dr7, bp_num); - DR7_SET_LENGTH(dr7, bp_num, bp_length); - break; - case 2: - /* 10 UNSUPPORTED - an I/O read and I/O write */ - LOG_ERROR("%s unsupported feature bp_type=%d", __func__, bp_type); - return ERROR_FAIL; - break; - case 3: - /* on data read or data write */ - DR7_SET_ACCESS(dr7, bp_num); - DR7_SET_LENGTH(dr7, bp_num, bp_length); - break; - default: - LOG_ERROR("%s invalid request [only 0-3] bp_type=%d", __func__, bp_type); - return ERROR_FAIL; + case 0: + /* 00 - only on instruction execution */ + DR7_SET_EXE(dr7, bp_num); + DR7_SET_LENGTH(dr7, bp_num, bp_length); + break; + case 1: + /* 01 - only on data writes */ + DR7_SET_WRITE(dr7, bp_num); + DR7_SET_LENGTH(dr7, bp_num, bp_length); + break; + case 2: + /* 10 UNSUPPORTED - an I/O read and I/O write */ + LOG_ERROR("%s unsupported feature bp_type=%d", __func__, bp_type); + return ERROR_FAIL; + break; + case 3: + /* on data read or data write */ + DR7_SET_ACCESS(dr7, bp_num); + DR7_SET_LENGTH(dr7, bp_num, bp_length); + break; + default: + LOG_ERROR("%s invalid request [only 0-3] bp_type=%d", __func__, bp_type); + return ERROR_FAIL; } /* update regs in the reg cache ready to be written to hardware @@ -1027,7 +1027,7 @@ static int set_swbp(struct target *t, struct breakpoint *bp) if (read_phys_mem(t, physaddr, 1, 1, bp->orig_instr)) return ERROR_FAIL; - LOG_DEBUG("set software breakpoint - orig byte=0x%02" PRIx8 "", *bp->orig_instr); + LOG_DEBUG("set software breakpoint - orig byte=0x%02" PRIx8, *bp->orig_instr); /* just write the instruction trap byte */ if (write_phys_mem(t, physaddr, 1, 1, &opcode)) @@ -1040,7 +1040,7 @@ static int set_swbp(struct target *t, struct breakpoint *bp) if (readback != SW_BP_OPCODE) { LOG_ERROR("%s software breakpoint error at " TARGET_ADDR_FMT ", check memory", __func__, bp->address); - LOG_ERROR("%s readback=0x%02" PRIx8 " orig=0x%02" PRIx8 "", + LOG_ERROR("%s readback=0x%02" PRIx8 " orig=0x%02" PRIx8, __func__, readback, *bp->orig_instr); return ERROR_FAIL; } @@ -1089,7 +1089,7 @@ static int unset_swbp(struct target *t, struct breakpoint *bp) } else { LOG_ERROR("%s software breakpoint remove error at " TARGET_ADDR_FMT ", check memory", __func__, bp->address); - LOG_ERROR("%s current=0x%02" PRIx8 " orig=0x%02" PRIx8 "", + LOG_ERROR("%s current=0x%02" PRIx8 " orig=0x%02" PRIx8, __func__, current_instr, *bp->orig_instr); return ERROR_FAIL; } @@ -1206,21 +1206,19 @@ static int set_watchpoint(struct target *t, struct watchpoint *wp) } switch (wp->rw) { - case WPT_WRITE: - if (set_debug_regs(t, wp->address, wp_num, - DR7_BP_WRITE, wp->length) != ERROR_OK) { - return ERROR_FAIL; - } - break; - case WPT_ACCESS: - if (set_debug_regs(t, wp->address, wp_num, DR7_BP_READWRITE, - wp->length) != ERROR_OK) { - return ERROR_FAIL; - } - break; - default: - LOG_ERROR("%s only 'access' or 'write' watchpoints are supported", __func__); - break; + case WPT_WRITE: + if (set_debug_regs(t, wp->address, wp_num, + DR7_BP_WRITE, wp->length) != ERROR_OK) + return ERROR_FAIL; + break; + case WPT_ACCESS: + if (set_debug_regs(t, wp->address, wp_num, DR7_BP_READWRITE, + wp->length) != ERROR_OK) + return ERROR_FAIL; + break; + default: + LOG_ERROR("%s only 'access' or 'write' watchpoints are supported", __func__); + break; } watchpoint_set(wp, wp_num); debug_reg_list[wp_num].used = 1; @@ -1460,17 +1458,17 @@ COMMAND_HANDLER(handle_iow_command) unsigned int wordsize; switch (CMD_NAME[2]) { - case 'w': - wordsize = 4; - break; - case 'h': - wordsize = 2; - break; - case 'b': - wordsize = 1; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'w': + wordsize = 4; + break; + case 'h': + wordsize = 2; + break; + case 'b': + wordsize = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } return target_fill_io(target, address, wordsize, value); } diff --git a/src/target/x86_32_common.h b/src/target/x86_32_common.h index e232747697..7e8672ea00 100644 --- a/src/target/x86_32_common.h +++ b/src/target/x86_32_common.h @@ -299,7 +299,7 @@ int x86_32_get_gdb_reg_list(struct target *t, enum target_register_class reg_class); int x86_32_common_init_arch_info(struct target *target, struct x86_32_common *x86_32); -int x86_32_common_mmu(struct target *t, int *enabled); +int x86_32_common_mmu(struct target *t, bool *enabled); int x86_32_common_virt2phys(struct target *t, target_addr_t address, target_addr_t *physical); int x86_32_common_read_phys_mem(struct target *t, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer); diff --git a/src/target/xscale.c b/src/target/xscale.c index 84318a905f..6dc4e43082 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -22,6 +22,7 @@ #include "arm_simulator.h" #include "arm_disassembler.h" #include +#include #include "register.h" #include "image.h" #include "arm_opcodes.h" @@ -333,7 +334,6 @@ static int xscale_read_tx(struct target *target, int consume) enum tap_state path[3]; enum tap_state noconsume_path[6]; int retval; - struct timeval timeout, now; struct scan_field fields[3]; uint8_t field0_in = 0x0; uint8_t field0_check_value = 0x2; @@ -368,8 +368,8 @@ static int xscale_read_tx(struct target *target, int consume) uint8_t tmp; fields[2].in_value = &tmp; - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 1, 0); + // 1 second timeout + int64_t then = timeval_ms() + 1000; for (;; ) { /* if we want to consume the register content (i.e. clear TX_READY), @@ -392,14 +392,13 @@ static int xscale_read_tx(struct target *target, int consume) return ERROR_TARGET_TIMEOUT; } - gettimeofday(&now, NULL); - if (timeval_compare(&now, &timeout) > 0) { + if (timeval_ms() > then) { LOG_ERROR("time out reading TX register"); return ERROR_TARGET_TIMEOUT; } if (!((!(field0_in & 1)) && consume)) goto done; - if (debug_level >= 3) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { LOG_DEBUG("waiting 100ms"); alive_sleep(100); /* avoid flooding the logs */ } else @@ -417,7 +416,6 @@ static int xscale_write_rx(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); int retval; - struct timeval timeout, now; struct scan_field fields[3]; uint8_t field0_out = 0x0; uint8_t field0_in = 0x0; @@ -445,8 +443,8 @@ static int xscale_write_rx(struct target *target) uint8_t tmp; fields[2].in_value = &tmp; - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 1, 0); + // 1 second timeout + int64_t then = timeval_ms() + 1000; /* poll until rx_read is low */ LOG_DEBUG("polling RX"); @@ -462,15 +460,13 @@ static int xscale_write_rx(struct target *target) return retval; } - gettimeofday(&now, NULL); - if ((now.tv_sec > timeout.tv_sec) || - ((now.tv_sec == timeout.tv_sec) && (now.tv_usec > timeout.tv_usec))) { + if (timeval_ms() > then) { LOG_ERROR("time out writing RX register"); return ERROR_TARGET_TIMEOUT; } if (!(field0_in & 1)) goto done; - if (debug_level >= 3) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { LOG_DEBUG("waiting 100ms"); alive_sleep(100); /* avoid flooding the logs */ } else @@ -516,24 +512,24 @@ static int xscale_send(struct target *target, const uint8_t *buffer, int count, uint32_t t; switch (size) { - case 4: - if (endianness == TARGET_LITTLE_ENDIAN) - t = le_to_h_u32(buffer); - else - t = be_to_h_u32(buffer); - break; - case 2: - if (endianness == TARGET_LITTLE_ENDIAN) - t = le_to_h_u16(buffer); - else - t = be_to_h_u16(buffer); - break; - case 1: - t = buffer[0]; - break; - default: - LOG_ERROR("BUG: size neither 4, 2 nor 1"); - return ERROR_COMMAND_SYNTAX_ERROR; + case 4: + if (endianness == TARGET_LITTLE_ENDIAN) + t = le_to_h_u32(buffer); + else + t = be_to_h_u32(buffer); + break; + case 2: + if (endianness == TARGET_LITTLE_ENDIAN) + t = le_to_h_u16(buffer); + else + t = be_to_h_u16(buffer); + break; + case 1: + t = buffer[0]; + break; + default: + LOG_ERROR("BUG: size neither 4, 2 nor 1"); + return ERROR_COMMAND_SYNTAX_ERROR; } buf_set_u32(t1, 0, 32, t); @@ -639,7 +635,7 @@ static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8] int word; struct scan_field fields[2]; - LOG_DEBUG("loading miniIC at 0x%8.8" PRIx32 "", va); + LOG_DEBUG("loading miniIC at 0x%8.8" PRIx32, va); /* LDIC into IR */ xscale_jtag_set_instr(target->tap, @@ -774,10 +770,6 @@ static int xscale_arch_state(struct target *target) struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; - static const char *state[] = { - "disabled", "enabled" - }; - static const char *arch_dbg_reason[] = { "", "\n(processor reset)", "\n(trace buffer full)" }; @@ -789,9 +781,9 @@ static int xscale_arch_state(struct target *target) arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s%s", - state[xscale->armv4_5_mmu.mmu_enabled], - state[xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], - state[xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled], + str_enabled_disabled(xscale->armv4_5_mmu.mmu_enabled), + str_enabled_disabled(xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled), + str_enabled_disabled(xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled), arch_dbg_reason[xscale->arch_debug_reason]); return ERROR_OK; @@ -859,24 +851,24 @@ static int xscale_debug_entry(struct target *target) buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, buffer[0]); arm->core_cache->reg_list[0].dirty = true; arm->core_cache->reg_list[0].valid = true; - LOG_DEBUG("r0: 0x%8.8" PRIx32 "", buffer[0]); + LOG_DEBUG("r0: 0x%8.8" PRIx32, buffer[0]); /* move pc from buffer to register cache */ buf_set_u32(arm->pc->value, 0, 32, buffer[1]); arm->pc->dirty = true; arm->pc->valid = true; - LOG_DEBUG("pc: 0x%8.8" PRIx32 "", buffer[1]); + LOG_DEBUG("pc: 0x%8.8" PRIx32, buffer[1]); /* move data from buffer to register cache */ for (i = 1; i <= 7; i++) { buf_set_u32(arm->core_cache->reg_list[i].value, 0, 32, buffer[1 + i]); arm->core_cache->reg_list[i].dirty = true; arm->core_cache->reg_list[i].valid = true; - LOG_DEBUG("r%i: 0x%8.8" PRIx32 "", i, buffer[i + 1]); + LOG_DEBUG("r%i: 0x%8.8" PRIx32, i, buffer[i + 1]); } arm_set_cpsr(arm, buffer[9]); - LOG_DEBUG("cpsr: 0x%8.8" PRIx32 "", buffer[9]); + LOG_DEBUG("cpsr: 0x%8.8" PRIx32, buffer[9]); if (!is_arm_mode(arm->core_mode)) { target->state = TARGET_UNKNOWN; @@ -919,46 +911,46 @@ static int xscale_debug_entry(struct target *target) pc = buf_get_u32(arm->pc->value, 0, 32); switch (moe) { - case 0x0: /* Processor reset */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET; - pc -= 4; - break; - case 0x1: /* Instruction breakpoint hit */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x2: /* Data breakpoint hit */ - target->debug_reason = DBG_REASON_WATCHPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x3: /* BKPT instruction executed */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x4: /* Ext. debug event */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x5: /* Vector trap occurred */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x6: /* Trace buffer full break */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL; - pc -= 4; - break; - case 0x7: /* Reserved (may flag Hot-Debug support) */ - default: - LOG_ERROR("Method of Entry is 'Reserved'"); - exit(-1); - break; + case 0x0: /* Processor reset */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET; + pc -= 4; + break; + case 0x1: /* Instruction breakpoint hit */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x2: /* Data breakpoint hit */ + target->debug_reason = DBG_REASON_WATCHPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x3: /* BKPT instruction executed */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x4: /* Ext. debug event */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x5: /* Vector trap occurred */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x6: /* Trace buffer full break */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL; + pc -= 4; + break; + case 0x7: /* Reserved (may flag Hot-Debug support) */ + default: + LOG_ERROR("Method of Entry is 'Reserved'"); + exit(-1); + break; } /* apply PC fixup */ @@ -982,11 +974,11 @@ static int xscale_debug_entry(struct target *target) xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); xscale->cp15_control_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); - xscale->armv4_5_mmu.mmu_enabled = (xscale->cp15_control_reg & 0x1U) ? 1 : 0; + xscale->armv4_5_mmu.mmu_enabled = xscale->cp15_control_reg & 0x1U; xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = - (xscale->cp15_control_reg & 0x4U) ? 1 : 0; + xscale->cp15_control_reg & 0x4U; xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = - (xscale->cp15_control_reg & 0x1000U) ? 1 : 0; + xscale->cp15_control_reg & 0x1000U; /* tracing enabled, read collected trace data */ if (xscale->trace.mode != XSCALE_TRACE_DISABLED) { @@ -1162,7 +1154,7 @@ static int xscale_resume(struct target *target, bool current, uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( - "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", + "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32, current_opcode); } @@ -1187,7 +1179,7 @@ static int xscale_resume(struct target *target, bool current, /* send register */ xscale_send_u32(target, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); - LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", + LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32, i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } @@ -1251,7 +1243,7 @@ static int xscale_resume(struct target *target, bool current, for (i = 7; i >= 0; i--) { /* send register */ xscale_send_u32(target, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); - LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", + LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32, i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } @@ -1296,7 +1288,7 @@ static int xscale_step_inner(struct target *target, bool current, target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( - "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", + "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32, current_opcode); return retval; } @@ -1340,7 +1332,7 @@ static int xscale_step_inner(struct target *target, bool current, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); if (retval != ERROR_OK) return retval; - LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", i, + LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32, i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } @@ -1818,20 +1810,20 @@ static int xscale_read_memory(struct target *target, target_addr_t address, /* extract data from host-endian buffer into byte stream */ for (i = 0; i < count; i++) { switch (size) { - case 4: - target_buffer_set_u32(target, buffer, buf32[i]); - buffer += 4; - break; - case 2: - target_buffer_set_u16(target, buffer, buf32[i] & 0xffff); - buffer += 2; - break; - case 1: - *buffer++ = buf32[i] & 0xff; - break; - default: - LOG_ERROR("invalid read size"); - return ERROR_COMMAND_SYNTAX_ERROR; + case 4: + target_buffer_set_u32(target, buffer, buf32[i]); + buffer += 4; + break; + case 2: + target_buffer_set_u16(target, buffer, buf32[i] & 0xffff); + buffer += 2; + break; + case 1: + *buffer++ = buf32[i] & 0xff; + break; + default: + LOG_ERROR("invalid read size"); + return ERROR_COMMAND_SYNTAX_ERROR; } } @@ -1910,24 +1902,24 @@ static int xscale_write_memory(struct target *target, target_addr_t address, #if 0 for (i = 0; i < count; i++) { switch (size) { - case 4: - value = target_buffer_get_u32(target, buffer); - xscale_send_u32(target, value); - buffer += 4; - break; - case 2: - value = target_buffer_get_u16(target, buffer); - xscale_send_u32(target, value); - buffer += 2; - break; - case 1: - value = *buffer; - xscale_send_u32(target, value); - buffer += 1; - break; - default: - LOG_ERROR("should never get here"); - exit(-1); + case 4: + value = target_buffer_get_u32(target, buffer); + xscale_send_u32(target, value); + buffer += 4; + break; + case 2: + value = target_buffer_get_u16(target, buffer); + xscale_send_u32(target, value); + buffer += 2; + break; + case 1: + value = *buffer; + xscale_send_u32(target, value); + buffer += 1; + break; + default: + LOG_ERROR("should never get here"); + exit(-1); } } #endif @@ -2030,8 +2022,7 @@ static int xscale_disable_mmu_caches(struct target *target, int mmu, return retval; /* execute cpwait to ensure outstanding operations complete */ - retval = xscale_send_u32(target, 0x53); - return retval; + return xscale_send_u32(target, 0x53); } static int xscale_enable_mmu_caches(struct target *target, int mmu, @@ -2062,8 +2053,7 @@ static int xscale_enable_mmu_caches(struct target *target, int mmu, return retval; /* execute cpwait to ensure outstanding operations complete */ - retval = xscale_send_u32(target, 0x53); - return retval; + return xscale_send_u32(target, 0x53); } static int xscale_set_breakpoint(struct target *target, @@ -2237,17 +2227,17 @@ static int xscale_set_watchpoint(struct target *target, } switch (watchpoint->rw) { - case WPT_READ: - enable = 0x3; - break; - case WPT_ACCESS: - enable = 0x2; - break; - case WPT_WRITE: - enable = 0x1; - break; - default: - LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + case WPT_READ: + enable = 0x3; + break; + case WPT_ACCESS: + enable = 0x2; + break; + case WPT_WRITE: + enable = 0x1; + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } /* For watchpoint across more than one word, both DBR registers must @@ -2688,61 +2678,60 @@ static int xscale_analyze_trace(struct target *target, struct command_invocation continue; switch (trace_msg_type) { - case 0: /* Exceptions */ - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - exception = (trace_data->entries[i].data & 0x70) >> 4; - - /* FIXME: vector table may be at ffff0000 */ - branch_target = (trace_data->entries[i].data & 0xf0) >> 2; - break; - - case 8: /* Direct Branch */ - break; - - case 9: /* Indirect Branch */ - xscale_branch_address(trace_data, i, &branch_target); - break; - - case 13: /* Checkpointed Indirect Branch */ - xscale_branch_address(trace_data, i, &branch_target); - if ((trace_data->num_checkpoints == 2) && (chkpt == 0)) - chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is - *oldest */ - else - chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and - *newest */ - - chkpt++; - break; - - case 12: /* Checkpointed Direct Branch */ - if ((trace_data->num_checkpoints == 2) && (chkpt == 0)) - chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is - *oldest */ - else - chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and - *newest */ - - /* if no current_pc, checkpoint will be starting point */ - if (current_pc == 0) - branch_target = chkpt_reg; + case 0: /* Exceptions */ + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + exception = (trace_data->entries[i].data & 0x70) >> 4; + + /* FIXME: vector table may be at ffff0000 */ + branch_target = (trace_data->entries[i].data & 0xf0) >> 2; + break; - chkpt++; - break; + case 8: /* Direct Branch */ + break; - case 15:/* Roll-over */ - break; + case 9: /* Indirect Branch */ + xscale_branch_address(trace_data, i, &branch_target); + break; - default:/* Reserved */ - LOG_WARNING("trace is suspect: invalid trace message byte"); - continue; + case 13: /* Checkpointed Indirect Branch */ + xscale_branch_address(trace_data, i, &branch_target); + if (trace_data->num_checkpoints == 2 && chkpt == 0) + chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is + *oldest */ + else + chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and + *newest */ + + chkpt++; + break; + case 12: /* Checkpointed Direct Branch */ + if (trace_data->num_checkpoints == 2 && chkpt == 0) + chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is + *oldest */ + else + chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and + *newest */ + + /* if no current_pc, checkpoint will be starting point */ + if (current_pc == 0) + branch_target = chkpt_reg; + + chkpt++; + break; + + case 15:/* Roll-over */ + break; + + default:/* Reserved */ + LOG_WARNING("trace is suspect: invalid trace message byte"); + continue; } /* If we don't have the current_pc yet, but we did get the branch target @@ -3007,7 +2996,7 @@ static int xscale_init_arch_info(struct target *target, xscale->armv4_5_mmu.disable_mmu_caches = xscale_disable_mmu_caches; xscale->armv4_5_mmu.enable_mmu_caches = xscale_enable_mmu_caches; xscale->armv4_5_mmu.has_tiny_pages = 1; - xscale->armv4_5_mmu.mmu_enabled = 0; + xscale->armv4_5_mmu.mmu_enabled = false; return ERROR_OK; } @@ -3126,7 +3115,7 @@ static int xscale_virt2phys(struct target *target, return ERROR_OK; } -static int xscale_mmu(struct target *target, int *enabled) +static int xscale_mmu(struct target *target, bool *enabled) { struct xscale_common *xscale = target_to_xscale(target); @@ -3523,33 +3512,33 @@ COMMAND_HANDLER(xscale_handle_cp15) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg_no); /*translate from xscale cp15 register no to openocd register*/ switch (reg_no) { - case 0: - reg_no = XSCALE_MAINID; - break; - case 1: - reg_no = XSCALE_CTRL; - break; - case 2: - reg_no = XSCALE_TTB; - break; - case 3: - reg_no = XSCALE_DAC; - break; - case 5: - reg_no = XSCALE_FSR; - break; - case 6: - reg_no = XSCALE_FAR; - break; - case 13: - reg_no = XSCALE_PID; - break; - case 15: - reg_no = XSCALE_CPACCESS; - break; - default: - command_print(CMD, "invalid register number"); - return ERROR_COMMAND_SYNTAX_ERROR; + case 0: + reg_no = XSCALE_MAINID; + break; + case 1: + reg_no = XSCALE_CTRL; + break; + case 2: + reg_no = XSCALE_TTB; + break; + case 3: + reg_no = XSCALE_DAC; + break; + case 5: + reg_no = XSCALE_FSR; + break; + case 6: + reg_no = XSCALE_FAR; + break; + case 13: + reg_no = XSCALE_PID; + break; + case 15: + reg_no = XSCALE_CPACCESS; + break; + default: + command_print(CMD, "invalid register number"); + return ERROR_COMMAND_SYNTAX_ERROR; } reg = &xscale->reg_cache->reg_list[reg_no]; @@ -3560,7 +3549,7 @@ COMMAND_HANDLER(xscale_handle_cp15) /* read cp15 control register */ xscale_get_reg(reg); value = buf_get_u32(reg->value, 0, 32); - command_print(CMD, "%s (/%i): 0x%" PRIx32 "", reg->name, (int)(reg->size), + command_print(CMD, "%s (/%i): 0x%" PRIx32, reg->name, (int)(reg->size), value); } else if (CMD_ARGC == 2) { uint32_t value; @@ -3740,5 +3729,7 @@ struct target_type xscale_target = { .deinit_target = xscale_deinit_target, .virt2phys = xscale_virt2phys, - .mmu = xscale_mmu + .mmu = xscale_mmu, + + .insn_set = armv4_5_insn_set, }; diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index 3a877edfa6..d1a08c3bd3 100644 --- a/src/target/xtensa/xtensa.c +++ b/src/target/xtensa/xtensa.c @@ -907,7 +907,6 @@ int xtensa_examine(struct target *target) 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; } @@ -949,7 +948,8 @@ int xtensa_smpbreak_set(struct target *target, uint32_t set) 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); + LOG_TARGET_DEBUG(target, "set smpbreak=%" PRIx32 ", state %s", set, + target_state_name(target)); return res; } @@ -1555,7 +1555,7 @@ int xtensa_get_gdb_reg_list(struct target *target, return ERROR_OK; } -int xtensa_mmu_is_enabled(struct target *target, int *enabled) +int xtensa_mmu_is_enabled(struct target *target, bool *enabled) { struct xtensa *xtensa = target_to_xtensa(target); *enabled = xtensa->core_config->mmu.itlb_entries_count > 0 || @@ -2076,17 +2076,16 @@ int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t si /* 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; + res = xtensa_read_memory(target, address, size, count, buffer); } else { LOG_TARGET_WARNING(target, "Failed reading %d bytes at address "TARGET_ADDR_FMT, count * size, address); } + } else { + if (bswap) + buf_bswap32(albuff, albuff, addrend_al - addrstart_al); + memcpy(buffer, albuff + (address & 3), (size * count)); } - - if (bswap) - buf_bswap32(albuff, albuff, addrend_al - addrstart_al); - memcpy(buffer, albuff + (address & 3), (size * count)); free(albuff); return res; } @@ -3493,6 +3492,10 @@ static void xtensa_free_reg_cache(struct target *target) free(xtensa->optregs); } xtensa->optregs = NULL; + free(xtensa->contiguous_regs_desc); + xtensa->contiguous_regs_desc = NULL; + free(xtensa->contiguous_regs_list); + xtensa->contiguous_regs_list = NULL; } void xtensa_target_deinit(struct target *target) @@ -3896,6 +3899,10 @@ COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa) xtensa->total_regs_num = numregs; xtensa->core_regs_num = 0; xtensa->num_optregs = 0; + /* Prevent memory leak in case xtregs is called twice */ + free(xtensa->optregs); + free(xtensa->contiguous_regs_desc); + xtensa->contiguous_regs_desc = NULL; /* 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) { diff --git a/src/target/xtensa/xtensa.h b/src/target/xtensa/xtensa.h index a920f77cdf..daa88b10d1 100644 --- a/src/target/xtensa/xtensa.h +++ b/src/target/xtensa/xtensa.h @@ -392,7 +392,7 @@ int xtensa_step(struct target *target, bool current, target_addr_t address, bool handle_breakpoints); int xtensa_do_step(struct target *target, bool current, target_addr_t address, bool handle_breakpoints); -int xtensa_mmu_is_enabled(struct target *target, int *enabled); +int xtensa_mmu_is_enabled(struct target *target, bool *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, diff --git a/src/transport/transport.c b/src/transport/transport.c index 5323a7ca0a..bb7df408ca 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -352,7 +352,7 @@ COMMAND_HANDLER(handle_transport_select) transport_single_is_autoselected = false; return ERROR_OK; } - LOG_WARNING("Transport \"%s\" was already selected", CMD_ARGV[0]); + LOG_DEBUG("Transport \"%s\" was already selected", CMD_ARGV[0]); return ERROR_OK; } command_print(CMD, "Can't change session's transport after the initial selection was made"); diff --git a/src/xsvf/xsvf.c b/src/xsvf/xsvf.c index 617c2f423e..5f5bf8d094 100644 --- a/src/xsvf/xsvf.c +++ b/src/xsvf/xsvf.c @@ -117,57 +117,57 @@ static enum tap_state xsvf_to_tap(int xsvf_state) enum tap_state ret; switch (xsvf_state) { - case XSV_RESET: - ret = TAP_RESET; - break; - case XSV_IDLE: - ret = TAP_IDLE; - break; - case XSV_DRSELECT: - ret = TAP_DRSELECT; - break; - case XSV_DRCAPTURE: - ret = TAP_DRCAPTURE; - break; - case XSV_DRSHIFT: - ret = TAP_DRSHIFT; - break; - case XSV_DREXIT1: - ret = TAP_DREXIT1; - break; - case XSV_DRPAUSE: - ret = TAP_DRPAUSE; - break; - case XSV_DREXIT2: - ret = TAP_DREXIT2; - break; - case XSV_DRUPDATE: - ret = TAP_DRUPDATE; - break; - case XSV_IRSELECT: - ret = TAP_IRSELECT; - break; - case XSV_IRCAPTURE: - ret = TAP_IRCAPTURE; - break; - case XSV_IRSHIFT: - ret = TAP_IRSHIFT; - break; - case XSV_IREXIT1: - ret = TAP_IREXIT1; - break; - case XSV_IRPAUSE: - ret = TAP_IRPAUSE; - break; - case XSV_IREXIT2: - ret = TAP_IREXIT2; - break; - case XSV_IRUPDATE: - ret = TAP_IRUPDATE; - break; - default: - LOG_ERROR("UNKNOWN XSVF STATE 0x%02X", xsvf_state); - exit(1); + case XSV_RESET: + ret = TAP_RESET; + break; + case XSV_IDLE: + ret = TAP_IDLE; + break; + case XSV_DRSELECT: + ret = TAP_DRSELECT; + break; + case XSV_DRCAPTURE: + ret = TAP_DRCAPTURE; + break; + case XSV_DRSHIFT: + ret = TAP_DRSHIFT; + break; + case XSV_DREXIT1: + ret = TAP_DREXIT1; + break; + case XSV_DRPAUSE: + ret = TAP_DRPAUSE; + break; + case XSV_DREXIT2: + ret = TAP_DREXIT2; + break; + case XSV_DRUPDATE: + ret = TAP_DRUPDATE; + break; + case XSV_IRSELECT: + ret = TAP_IRSELECT; + break; + case XSV_IRCAPTURE: + ret = TAP_IRCAPTURE; + break; + case XSV_IRSHIFT: + ret = TAP_IRSHIFT; + break; + case XSV_IREXIT1: + ret = TAP_IREXIT1; + break; + case XSV_IRPAUSE: + ret = TAP_IRPAUSE; + break; + case XSV_IREXIT2: + ret = TAP_IREXIT2; + break; + case XSV_IRUPDATE: + ret = TAP_IRUPDATE; + break; + default: + LOG_ERROR("UNKNOWN XSVF STATE 0x%02X", xsvf_state); + exit(1); } return ret; @@ -275,94 +275,91 @@ COMMAND_HANDLER(handle_xsvf_command) enum tap_state mystate; switch (opcode) { - case XCOMMENT: - /* ignore/show comments between XSTATE ops */ + case XCOMMENT: + /* ignore/show comments between XSTATE ops */ + break; + case XSTATE: + /* try to collect another transition */ + if (pathlen == XSTATE_MAX_PATH) { + LOG_ERROR("XSVF: path too long"); + do_abort = 1; break; - case XSTATE: - /* try to collect another transition */ - if (pathlen == XSTATE_MAX_PATH) { - LOG_ERROR("XSVF: path too long"); - do_abort = 1; - break; - } - - if (read(xsvf_fd, &uc, 1) < 0) { - do_abort = 1; - break; - } + } - mystate = xsvf_to_tap(uc); - path[pathlen++] = mystate; - - LOG_DEBUG("XSTATE 0x%02X %s", uc, - tap_state_name(mystate)); - - /* If path is incomplete, collect more */ - if (!svf_tap_state_is_stable(mystate)) - continue; - - /* Else execute the path transitions we've - * collected so far. - * - * NOTE: Punting on the saved path is not - * strictly correct, but we must to do this - * unless jtag_add_pathmove() stops rejecting - * paths containing RESET. This is probably - * harmless, since there aren't many options - * for going from a stable state to reset; - * at the worst, we may issue extra clocks - * once we get to RESET. - */ - if (mystate == TAP_RESET) { - LOG_WARNING("XSVF: dodgey RESET"); - path[0] = mystate; - } + if (read(xsvf_fd, &uc, 1) < 0) { + do_abort = 1; + break; + } - /* FALL THROUGH */ - default: - /* Execute the path we collected - * - * NOTE: OpenOCD requires something that XSVF - * doesn't: the last TAP state in the path - * must be stable. In practice, tools that - * create XSVF seem to follow that rule too. - */ - collecting_path = false; + mystate = xsvf_to_tap(uc); + path[pathlen++] = mystate; - if (path[0] == TAP_RESET) - jtag_add_tlr(); - else - jtag_add_pathmove(pathlen, path); + LOG_DEBUG("XSTATE 0x%02X %s", uc, + tap_state_name(mystate)); - result = jtag_execute_queue(); - if (result != ERROR_OK) { - LOG_ERROR("XSVF: pathmove error %d", result); - do_abort = 1; - break; - } + /* If path is incomplete, collect more */ + if (!svf_tap_state_is_stable(mystate)) continue; - } - } - switch (opcode) { - case XCOMPLETE: - LOG_DEBUG("XCOMPLETE"); + /* Else execute the path transitions we've + * collected so far. + * + * NOTE: Punting on the saved path is not + * strictly correct, but we must to do this + * unless jtag_add_pathmove() stops rejecting + * paths containing RESET. This is probably + * harmless, since there aren't many options + * for going from a stable state to reset; + * at the worst, we may issue extra clocks + * once we get to RESET. + */ + if (mystate == TAP_RESET) { + LOG_WARNING("XSVF: dodgey RESET"); + path[0] = mystate; + } + + /* FALL THROUGH */ + default: + /* Execute the path we collected + * + * NOTE: OpenOCD requires something that XSVF + * doesn't: the last TAP state in the path + * must be stable. In practice, tools that + * create XSVF seem to follow that rule too. + */ + collecting_path = false; + + if (path[0] == TAP_RESET) + jtag_add_tlr(); + else + jtag_add_pathmove(pathlen, path); result = jtag_execute_queue(); if (result != ERROR_OK) { - tdo_mismatch = 1; + LOG_ERROR("XSVF: pathmove error %d", result); + do_abort = 1; break; } - break; + continue; + } + } - case XTDOMASK: - LOG_DEBUG("XTDOMASK"); - if (dr_in_mask && - (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_mask) != ERROR_OK)) - do_abort = 1; - break; + switch (opcode) { + case XCOMPLETE: + LOG_DEBUG("XCOMPLETE"); + result = jtag_execute_queue(); + if (result != ERROR_OK) + tdo_mismatch = 1; + break; + + case XTDOMASK: + LOG_DEBUG("XTDOMASK"); + if (dr_in_mask && + (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_mask) != ERROR_OK)) + do_abort = 1; + break; - case XRUNTEST: + case XRUNTEST: { uint8_t xruntest_buf[4]; @@ -376,20 +373,20 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XREPEAT: + case XREPEAT: { uint8_t myrepeat; - if (read(xsvf_fd, &myrepeat, 1) < 0) + if (read(xsvf_fd, &myrepeat, 1) < 0) { do_abort = 1; - else { + } else { xrepeat = myrepeat; LOG_DEBUG("XREPEAT %d", xrepeat); } } break; - case XSDRSIZE: + case XSDRSIZE: { uint8_t xsdrsize_buf[4]; @@ -411,8 +408,8 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XSDR: /* these two are identical except for the dr_in_buf */ - case XSDRTDO: + case XSDR: /* these two are identical except for the dr_in_buf */ + case XSDRTDO: { int limit = xrepeat; int matched = 0; @@ -521,47 +518,47 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XSETSDRMASKS: - LOG_ERROR("unsupported XSETSDRMASKS"); - unsupported = 1; - break; + case XSETSDRMASKS: + LOG_ERROR("unsupported XSETSDRMASKS"); + unsupported = 1; + break; - case XSDRINC: - LOG_ERROR("unsupported XSDRINC"); - unsupported = 1; - break; + case XSDRINC: + LOG_ERROR("unsupported XSDRINC"); + unsupported = 1; + break; - case XSDRB: - LOG_ERROR("unsupported XSDRB"); - unsupported = 1; - break; + case XSDRB: + LOG_ERROR("unsupported XSDRB"); + unsupported = 1; + break; - case XSDRC: - LOG_ERROR("unsupported XSDRC"); - unsupported = 1; - break; + case XSDRC: + LOG_ERROR("unsupported XSDRC"); + unsupported = 1; + break; - case XSDRE: - LOG_ERROR("unsupported XSDRE"); - unsupported = 1; - break; + case XSDRE: + LOG_ERROR("unsupported XSDRE"); + unsupported = 1; + break; - case XSDRTDOB: - LOG_ERROR("unsupported XSDRTDOB"); - unsupported = 1; - break; + case XSDRTDOB: + LOG_ERROR("unsupported XSDRTDOB"); + unsupported = 1; + break; - case XSDRTDOC: - LOG_ERROR("unsupported XSDRTDOC"); - unsupported = 1; - break; + case XSDRTDOC: + LOG_ERROR("unsupported XSDRTDOC"); + unsupported = 1; + break; - case XSDRTDOE: - LOG_ERROR("unsupported XSDRTDOE"); - unsupported = 1; - break; + case XSDRTDOE: + LOG_ERROR("unsupported XSDRTDOE"); + unsupported = 1; + break; - case XSTATE: + case XSTATE: { enum tap_state mystate; @@ -606,50 +603,48 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XENDIR: - - if (read(xsvf_fd, &uc, 1) < 0) { - do_abort = 1; - break; - } - - /* see page 22 of XSVF spec */ - if (uc == 0) - xendir = TAP_IDLE; - else if (uc == 1) - xendir = TAP_IRPAUSE; - else { - LOG_ERROR("illegial XENDIR argument: 0x%02X", uc); - unsupported = 1; - break; - } - - LOG_DEBUG("XENDIR 0x%02X %s", uc, tap_state_name(xendir)); + case XENDIR: + if (read(xsvf_fd, &uc, 1) < 0) { + do_abort = 1; break; + } - case XENDDR: + /* see page 22 of XSVF spec */ + if (uc == 0) { + xendir = TAP_IDLE; + } else if (uc == 1) { + xendir = TAP_IRPAUSE; + } else { + LOG_ERROR("illegial XENDIR argument: 0x%02X", uc); + unsupported = 1; + break; + } - if (read(xsvf_fd, &uc, 1) < 0) { - do_abort = 1; - break; - } + LOG_DEBUG("XENDIR 0x%02X %s", uc, tap_state_name(xendir)); + break; - /* see page 22 of XSVF spec */ - if (uc == 0) - xenddr = TAP_IDLE; - else if (uc == 1) - xenddr = TAP_DRPAUSE; - else { - LOG_ERROR("illegial XENDDR argument: 0x%02X", uc); - unsupported = 1; - break; - } + case XENDDR: + if (read(xsvf_fd, &uc, 1) < 0) { + do_abort = 1; + break; + } - LOG_DEBUG("XENDDR %02X %s", uc, tap_state_name(xenddr)); + /* see page 22 of XSVF spec */ + if (uc == 0) { + xenddr = TAP_IDLE; + } else if (uc == 1) { + xenddr = TAP_DRPAUSE; + } else { + LOG_ERROR("illegial XENDDR argument: 0x%02X", uc); + unsupported = 1; break; + } + + LOG_DEBUG("XENDDR %02X %s", uc, tap_state_name(xenddr)); + break; - case XSIR: - case XSIR2: + case XSIR: + case XSIR2: { uint8_t short_buf[2]; uint8_t *ir_buf; @@ -675,9 +670,9 @@ COMMAND_HANDLER(handle_xsvf_command) ir_buf = malloc((bitcount + 7) / 8); - if (xsvf_read_buffer(bitcount, xsvf_fd, ir_buf) != ERROR_OK) + if (xsvf_read_buffer(bitcount, xsvf_fd, ir_buf) != ERROR_OK) { do_abort = 1; - else { + } else { struct scan_field field; field.num_bits = bitcount; @@ -712,7 +707,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XCOMMENT: + case XCOMMENT: { unsigned int ndx = 0; char comment[128]; @@ -734,7 +729,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XWAIT: + case XWAIT: { /* expected in stream: XWAIT @@ -762,9 +757,9 @@ COMMAND_HANDLER(handle_xsvf_command) LOG_DEBUG("XWAIT %s %s usecs:%d", tap_state_name( wait_state), tap_state_name(end_state), delay); - if (runtest_requires_tck && wait_state == TAP_IDLE) + if (runtest_requires_tck && wait_state == TAP_IDLE) { jtag_add_runtest(delay, end_state); - else { + } else { /* FIXME handle statemove errors ... */ result = svf_add_statemove(wait_state); if (result != ERROR_OK) @@ -777,7 +772,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XWAITSTATE: + case XWAITSTATE: { /* expected in stream: * XWAITSTATE @@ -838,7 +833,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case LCOUNT: + case LCOUNT: { /* expected in stream: * LCOUNT @@ -855,7 +850,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case LDELAY: + case LDELAY: { /* expected in stream: * LDELAY @@ -881,10 +876,10 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - /* LSDR is more like XSDRTDO than it is like XSDR. It uses LDELAY which - * comes with clocks !AND! sleep requirements. - */ - case LSDR: + /* LSDR is more like XSDRTDO than it is like XSDR. It uses LDELAY which + * comes with clocks !AND! sleep requirements. + */ + case LSDR: { int limit = loop_count; int matched = 0; @@ -948,7 +943,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XTRST: + case XTRST: { uint8_t trst_mode; @@ -974,9 +969,9 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - default: - LOG_ERROR("unknown xsvf command (0x%02X)", uc); - unsupported = 1; + default: + LOG_ERROR("unknown xsvf command (0x%02X)", uc); + unsupported = 1; } if (do_abort || unsupported || tdo_mismatch) { diff --git a/tcl/board/altera_sockit.cfg b/tcl/board/altera_sockit.cfg index bbd87d6466..3df6f87429 100644 --- a/tcl/board/altera_sockit.cfg +++ b/tcl/board/altera_sockit.cfg @@ -14,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 0x09fb 0x6810 +#adapter usb vid_pid 0x09fb 0x6810 #usb_blaster device_desc "USB-Blaster II" adapter speed 100 diff --git a/tcl/board/ti_beagleboard_xm.cfg b/tcl/board/beagle/beagleboard-xm.cfg similarity index 88% rename from tcl/board/ti_beagleboard_xm.cfg rename to tcl/board/beagle/beagleboard-xm.cfg index fd176a0016..cd9a53c5f8 100644 --- a/tcl/board/ti_beagleboard_xm.cfg +++ b/tcl/board/beagle/beagleboard-xm.cfg @@ -4,7 +4,7 @@ # http://beagleboard.org set CHIPTYPE "dm37x" -source [find target/amdm37x.cfg] +source [find target/ti/amdm37x.cfg] # The TI-14 JTAG connector does not have srst. CPU reset is handled in # hardware. diff --git a/tcl/board/ti_beagleboard.cfg b/tcl/board/beagle/beagleboard.cfg similarity index 86% rename from tcl/board/ti_beagleboard.cfg rename to tcl/board/beagle/beagleboard.cfg index 6767bd6df1..735708e80c 100644 --- a/tcl/board/ti_beagleboard.cfg +++ b/tcl/board/beagle/beagleboard.cfg @@ -6,7 +6,7 @@ # Fall back to 6MHz if RTCK is not supported jtag_rclk 6000 -source [find target/omap3530.cfg] +source [find target/ti/omap3530.cfg] # TI-14 JTAG connector reset_config trst_only diff --git a/tcl/board/ti_beaglebone-base.cfg b/tcl/board/beagle/beaglebone-base.cfg similarity index 77% rename from tcl/board/ti_beaglebone-base.cfg rename to tcl/board/beagle/beaglebone-base.cfg index 566f0a4b30..db8432f4c9 100644 --- a/tcl/board/ti_beaglebone-base.cfg +++ b/tcl/board/beagle/beaglebone-base.cfg @@ -3,4 +3,4 @@ # AM335x Beaglebone family base configuration # http://beagleboard.org/bone -source [find target/am335x.cfg] +source [find target/ti/am335x.cfg] diff --git a/tcl/board/ti_beaglebone_black.cfg b/tcl/board/beagle/beaglebone-black.cfg similarity index 76% rename from tcl/board/ti_beaglebone_black.cfg rename to tcl/board/beagle/beaglebone-black.cfg index d72bf09dd6..89928d76f1 100644 --- a/tcl/board/ti_beaglebone_black.cfg +++ b/tcl/board/beagle/beaglebone-black.cfg @@ -7,4 +7,4 @@ adapter speed 1000 reset_config trst_and_srst -source [find board/ti_beaglebone-base.cfg] +source [find board/beagle/beaglebone-base.cfg] diff --git a/tcl/board/ti_beaglebone.cfg b/tcl/board/beagle/beaglebone.cfg similarity index 83% rename from tcl/board/ti_beaglebone.cfg rename to tcl/board/beagle/beaglebone.cfg index d96e45f6ad..f09b51e866 100644 --- a/tcl/board/ti_beaglebone.cfg +++ b/tcl/board/beagle/beaglebone.cfg @@ -10,4 +10,4 @@ adapter speed 16000 reset_config trst_and_srst -source [find board/ti_beaglebone-base.cfg] +source [find board/beagle/beaglebone-base.cfg] diff --git a/tcl/board/bemicro_cycloneiii.cfg b/tcl/board/bemicro_cycloneiii.cfg index 3c92b500c1..0ae75693b6 100644 --- a/tcl/board/bemicro_cycloneiii.cfg +++ b/tcl/board/bemicro_cycloneiii.cfg @@ -6,7 +6,7 @@ adapter driver ftdi ftdi channel 0 ftdi layout_init 0x0008 0x008b -ftdi vid_pid 0x0403 0xa4a0 +adapter usb vid_pid 0x0403 0xa4a0 reset_config none transport select jtag @@ -18,7 +18,7 @@ source [find fpga/altera-cycloneiii.cfg] #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" +# "cycloneiii.ipdbghub start -tool 0 -port 5555" set JTAGSPI_CHAIN_ID cycloneiii.pld diff --git a/tcl/board/calao-usb-a9260.cfg b/tcl/board/calao-usb-a9260.cfg index 52fede0fa5..662db345c4 100644 --- a/tcl/board/calao-usb-a9260.cfg +++ b/tcl/board/calao-usb-a9260.cfg @@ -3,8 +3,8 @@ # CALAO Systems USB-A9260 (C01 and C02) adapter driver ftdi -ftdi device_desc "USB-A9260" -ftdi vid_pid 0x0403 0x6001 0x0403 0x6010 +adapter usb product_name "USB-A9260" +adapter usb 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 diff --git a/tcl/board/calao-usb-a9g20-c01.cfg b/tcl/board/calao-usb-a9g20-c01.cfg index d2017864a9..214f93b47b 100644 --- a/tcl/board/calao-usb-a9g20-c01.cfg +++ b/tcl/board/calao-usb-a9g20-c01.cfg @@ -4,8 +4,8 @@ # Authors: Gregory Hermant, Jean-Christophe PLAGNIOL-VILLARD, Wolfram Sang adapter driver ftdi -ftdi device_desc "USB-A9G20" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "USB-A9G20" +adapter usb 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 diff --git a/tcl/board/certuspro_evaluation.cfg b/tcl/board/certuspro_evaluation.cfg index ba2f17c221..b46695b543 100644 --- a/tcl/board/certuspro_evaluation.cfg +++ b/tcl/board/certuspro_evaluation.cfg @@ -3,7 +3,7 @@ # https://www.latticesemi.com/products/developmentboardsandkits/certuspro-nx-versa-board adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 +adapter usb vid_pid 0x0403 0x6010 ftdi channel 0 ftdi layout_init 0x0008 0x008b diff --git a/tcl/board/digilent_analog_discovery.cfg b/tcl/board/digilent_analog_discovery.cfg index 1bc239b632..453a9dd7d0 100644 --- a/tcl/board/digilent_analog_discovery.cfg +++ b/tcl/board/digilent_analog_discovery.cfg @@ -10,8 +10,8 @@ # adapter driver ftdi -ftdi device_desc "Digilent USB Device" -ftdi vid_pid 0x0403 0x6014 +adapter usb product_name "Digilent USB Device" +adapter usb vid_pid 0x0403 0x6014 ftdi layout_init 0x8008 0x800b diff --git a/tcl/board/digilent_anvyl.cfg b/tcl/board/digilent_anvyl.cfg index e820028779..cd4be2a61d 100644 --- a/tcl/board/digilent_anvyl.cfg +++ b/tcl/board/digilent_anvyl.cfg @@ -7,8 +7,8 @@ adapter driver ftdi adapter speed 30000 -ftdi device_desc "Digilent USB Device" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Digilent USB Device" +adapter usb vid_pid 0x0403 0x6010 # channel 0 is the JTAG channel # channel 1 is a user serial channel to pins on the FPGA diff --git a/tcl/board/digilent_cmod_s7.cfg b/tcl/board/digilent_cmod_s7.cfg index 4fa45a17a7..9d94545953 100644 --- a/tcl/board/digilent_cmod_s7.cfg +++ b/tcl/board/digilent_cmod_s7.cfg @@ -7,7 +7,7 @@ adapter driver ftdi ftdi channel 0 ftdi layout_init 0x0008 0x008b -ftdi vid_pid 0x0403 0x6010 +adapter usb vid_pid 0x0403 0x6010 reset_config none transport select jtag @@ -16,7 +16,7 @@ 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" +# "xc7.ipdbghub 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 diff --git a/tcl/board/digilent_nexys_video.cfg b/tcl/board/digilent_nexys_video.cfg index b60ec912fc..dd84b89bd3 100644 --- a/tcl/board/digilent_nexys_video.cfg +++ b/tcl/board/digilent_nexys_video.cfg @@ -6,8 +6,8 @@ adapter driver ftdi adapter speed 30000 -ftdi device_desc "Digilent USB Device" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Digilent USB Device" +adapter usb vid_pid 0x0403 0x6010 # channel 0 is dedicated for Digilent's DPTI Interface # channel 1 is used for JTAG diff --git a/tcl/board/digilent_zybo.cfg b/tcl/board/digilent_zybo.cfg new file mode 100644 index 0000000000..ed990dc4a5 --- /dev/null +++ b/tcl/board/digilent_zybo.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Digilent Zybo +# https://digilent.com/reference/programmable-logic/zybo/start + +# Tested with the Zybo board from Digilent (older). +# Not tested with the Zybo Z7 board from Digilent (newer). + + +adapter driver ftdi +ftdi channel 0 +#adapter usb product_name "Digilent Adept USB Device" +adapter usb vid_pid 0x0403 0x6010 +ftdi layout_init 0x3088 0x1f8b +ftdi layout_signal nSRST -data 0x3000 -oe 0x1000 +ftdi layout_signal LED -data 0x0010 +reset_config srst_pulls_trst +transport select jtag + +source [find target/zynq_7000.cfg] + +adapter speed 10000 + +# "ipdbg create-hub zynq.ipdbghub -pld zynq_pl.pld" -c init -c "zynq.ipdbghub ipdbg start -tool 0 -port 5555" diff --git a/tcl/board/dk-tm4c129.cfg b/tcl/board/dk-tm4c129.cfg index 27bd432ce5..2c5b5b151e 100644 --- a/tcl/board/dk-tm4c129.cfg +++ b/tcl/board/dk-tm4c129.cfg @@ -1,5 +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" +echo "WARNING: board/dk-tm4c129.cfg is deprecated, please switch to board/ti/dk-tm4c129.cfg" -source [find board/ti_dk-tm4c129.cfg] +source [find board/ti/dk-tm4c129.cfg] diff --git a/tcl/board/easydevkits/esp32-wrover-e-ftdi-jtag-devkit.cfg b/tcl/board/easydevkits/esp32-wrover-e-ftdi-jtag-devkit.cfg new file mode 100644 index 0000000000..8992e2bbb8 --- /dev/null +++ b/tcl/board/easydevkits/esp32-wrover-e-ftdi-jtag-devkit.cfg @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for the EasyDevKits ESP32-WROVER-E FTDI JTAG DevKit. +# +# For example, OpenOCD can be started for ESP32 debugging on +# +# openocd -f board/esp32-wrover-e-ftdi-jtag-devkit.cfg +# + +# Select the FTDI JTAG driver +adapter driver ftdi + +# Identify the device +adapter usb product_name "EasyDevKit" +adapter usb vid_pid 0x0403 0x6010 +# interface 0 is JTAG; interface 1 is the uart +ftdi channel 0 + +# TCK, TDI, TDO, TMS: ADBUS0-3 +# activity LED: ADBUS4 +ftdi layout_init 0x0008 0x001b +ftdi layout_signal LED -data 0x0010 + +# Source the ESP32 configuration file +source [find target/esp32.cfg] + +# --------------------------------------------------------------------------- +# JTAG speed (in kHz) +# +# If you encounter DSR/DIR errors that are not caused by OpenOCD +# attempting to read unmapped memory regions, try lowering this value. +# +# Recommended settings for EasyDevKits: +# - Do not exceed 20 MHz. +# - Best results are typically achieved at 20 MHz. +# --------------------------------------------------------------------------- +adapter speed 20000 diff --git a/tcl/board/easydevkits/esp32-wrover-e-wch-jtag-devkit.cfg b/tcl/board/easydevkits/esp32-wrover-e-wch-jtag-devkit.cfg new file mode 100644 index 0000000000..491fe533d1 --- /dev/null +++ b/tcl/board/easydevkits/esp32-wrover-e-wch-jtag-devkit.cfg @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for the EasyDevKits ESP32-WROVER-E WCH JTAG DevKit. +# +# For example, OpenOCD can be started for ESP32 debugging on +# +# openocd -f board/esp32-wrover-e-wch-jtag-devkit.cfg +# + +# Select the CH347 JTAG driver +adapter driver ch347 + +# Identify the device +adapter usb vid_pid 0x1a86 0x55dd +adapter usb product_name "EasyDevKit" + +# Configure activity LED +# Note: The LED is active-low on GPIO4. +adapter gpio led 4 -active-low + +# Source the ESP32 configuration file +source [find target/esp32.cfg] + +# --------------------------------------------------------------------------- +# JTAG speed (in kHz) +# +# If you encounter DSR/DIR errors that are not caused by OpenOCD +# attempting to read unmapped memory regions, try lowering this value. +# +# Recommended settings for EasyDevKits: +# - Do not exceed 30 MHz. +# - Best results are typically achieved at 15 MHz. +# +# Supported frequencies (kHz): +# 469, 938, 1875, 3750, 7500, 15000, 30000, 60000 +# --------------------------------------------------------------------------- +adapter speed 15000 diff --git a/tcl/board/ecp5_evaluation.cfg b/tcl/board/ecp5_evaluation.cfg index 71769f6074..4e794e26a8 100644 --- a/tcl/board/ecp5_evaluation.cfg +++ b/tcl/board/ecp5_evaluation.cfg @@ -5,7 +5,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 +adapter usb vid_pid 0x0403 0x6010 ftdi channel 0 ftdi layout_init 0x0008 0x008b @@ -17,7 +17,7 @@ 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 +#ecp5.ipdbghub start -tool 0 -port 5555 set JTAGSPI_CHAIN_ID ecp5.pld source [find cpld/jtagspi.cfg] diff --git a/tcl/board/ek-tm4c123gxl.cfg b/tcl/board/ek-tm4c123gxl.cfg index d569e58cd9..b808731a6f 100644 --- a/tcl/board/ek-tm4c123gxl.cfg +++ b/tcl/board/ek-tm4c123gxl.cfg @@ -1,5 +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" +echo "WARNING: board/ek-tm4c123gxl.cfg is deprecated, please switch to board/ti/ek-tm4c123gxl.cfg" -source [find 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 5c1167451e..0e8837c4ed 100644 --- a/tcl/board/ek-tm4c1294xl.cfg +++ b/tcl/board/ek-tm4c1294xl.cfg @@ -1,5 +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" +echo "WARNING: board/ek-tm4c1294xl.cfg is deprecated, please switch to board/ti/ek-tm4c1294xl.cfg" -source [find board/ti_ek-tm4c1294xl.cfg] +source [find board/ti/ek-tm4c1294xl.cfg] diff --git a/tcl/board/esp32h2-builtin.cfg b/tcl/board/esp32h2-builtin.cfg index 1ce596104a..4455f99990 100644 --- a/tcl/board/esp32h2-builtin.cfg +++ b/tcl/board/esp32h2-builtin.cfg @@ -1,15 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-or-later # -# Example OpenOCD configuration file for ESP32-C3 connected via builtin USB-JTAG adapter. +# Example OpenOCD configuration file for ESP32-H2 connected via builtin USB-JTAG adapter. # -# For example, OpenOCD can be started for ESP32-C3 debugging on +# For example, OpenOCD can be started for ESP32-H2 debugging on # -# openocd -f board/esp32c3-builtin.cfg +# openocd -f board/esp32h2-builtin.cfg # # Source the JTAG interface configuration file source [find interface/esp_usb_jtag.cfg] -# Source the ESP32-C3 configuration file +# Source the ESP32-H2 configuration file source [find target/esp32h2.cfg] adapter speed 40000 diff --git a/tcl/board/gatemate_eval.cfg b/tcl/board/gatemate_eval.cfg index c4d3f3dfda..cbb9ff291e 100644 --- a/tcl/board/gatemate_eval.cfg +++ b/tcl/board/gatemate_eval.cfg @@ -5,7 +5,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 +adapter usb vid_pid 0x0403 0x6010 ftdi channel 0 ftdi layout_init 0x0014 0x011b diff --git a/tcl/board/gowin_runber.cfg b/tcl/board/gowin_runber.cfg index 6cb07362b9..5e0addf6ad 100644 --- a/tcl/board/gowin_runber.cfg +++ b/tcl/board/gowin_runber.cfg @@ -4,7 +4,7 @@ # https://www.seeedstudio.com/Gowin-RUNBER-Development-Board-p-4779.html adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 +adapter usb vid_pid 0x0403 0x6010 ftdi channel 0 ftdi layout_init 0x0008 0x008b @@ -17,4 +17,4 @@ 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 +#gw1n.ipdbghub start -tool 0 -port 5555 diff --git a/tcl/board/gumstix-aerocore.cfg b/tcl/board/gumstix-aerocore.cfg index ddadc88c0b..e6591c4192 100644 --- a/tcl/board/gumstix-aerocore.cfg +++ b/tcl/board/gumstix-aerocore.cfg @@ -3,7 +3,7 @@ # 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 +adapter usb vid_pid 0x0403 0x6011 ftdi layout_init 0x0000 0x001b ftdi layout_signal nTRST -data 0x0010 diff --git a/tcl/board/hpmicro/hpm5300evk.cfg b/tcl/board/hpmicro/hpm5300evk.cfg new file mode 100644 index 0000000000..70eacd36a5 --- /dev/null +++ b/tcl/board/hpmicro/hpm5300evk.cfg @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 HPMicro + +adapter speed 10000 +source [find interface/hpmicro/hpmicro_evk.cfg] +source [find target/hpmicro/hpm5300.cfg] +# openocd flash driver argument: +# - option0: +# [31:28] Flash probe type +# 0 - SFDP SDR / 1 - SFDP DDR +# 2 - 1-4-4 Read (0xEB, 24-bit address) / 3 - 1-2-2 Read(0xBB, 24-bit address) +# 4 - HyperFLASH 1.8V / 5 - HyperFLASH 3V +# 6 - OctaBus DDR (SPI -> OPI DDR) +# 8 - Xccela DDR (SPI -> OPI DDR) +# 10 - EcoXiP DDR (SPI -> OPI DDR) +# [27:24] Command Pads after Power-on Reset +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [23:20] Command Pads after Configuring FLASH +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [19:16] Quad Enable Sequence (for the device support SFDP 1.0 only) +# 0 - Not needed +# 1 - QE bit is at bit6 in Status Register 1 +# 2 - QE bit is at bit1 in Status Register 2 +# 3 - QE bit is at bit7 in Status Register 2 +# 4 - QE bit is at bit1 in Status Register 2 and should be programmed by 0x31 +# [15:8] Dummy cycles +# 0 - Auto-probed / detected / default value +# Others - User specified value, for DDR read, the dummy cycles should be 2 * cycles on FLASH datasheet +# [7:4] Misc. +# 0 - Not used +# 1 - SPI mode +# 2 - Internal loopback +# 3 - External DQS +# [3:0] Frequency option +# 1 - 30MHz / 2 - 50MHz / 3 - 66MHz / 4 - 80MHz / 5 - 100MHz / 6 - 120MHz / 7 - 133MHz / 8 - 166MHz +# - option1: +# [31:20] Reserved +# [19:16] IO voltage +# 0 - 3V / 1 - 1.8V +# [15:12] Pin group +# 0 - 1st group / 1 - 2nd group +# [11:8] Connection selection +# 0 - CA_CS0 / 1 - CB_CS0 / 2 - CA_CS0 + CB_CS0 (Two FLASH connected to CA and CB respectively) +# [7:0] Drive Strength +# 0 - Default value + +# xpi0 configs +# - flash driver: hpm_xpi +# - flash ctrl index: 0xF3000000 +# - base address: 0x80000000 +# - flash size: 0x2000000 +# - flash option0: 0x5 +# - flash option1: 0x1000 +flash bank xpi0 hpm_xpi 0x80000000 0x2000000 0 0 $_TARGET0 0xF3000000 0x5 0x1000 + +proc init_clock {} { + mww 0xF4000800 0xFFFFFFFF + mww 0xF4000810 0xFFFFFFFF + mww 0xF4000820 0xFFFFFFFF + mww 0xF4000830 0xFFFFFFFF + echo "clocks has been enabled!" +} + +$_TARGET0 configure -event reset-init { + init_clock +} diff --git a/tcl/board/hpmicro/hpm5301evklite.cfg b/tcl/board/hpmicro/hpm5301evklite.cfg new file mode 100644 index 0000000000..effa506012 --- /dev/null +++ b/tcl/board/hpmicro/hpm5301evklite.cfg @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 HPMicro + +adapter speed 10000 +source [find interface/hpmicro/hpmicro_evk.cfg] +source [find target/hpmicro/hpm5300.cfg] +# openocd flash driver argument: +# - option0: +# [31:28] Flash probe type +# 0 - SFDP SDR / 1 - SFDP DDR +# 2 - 1-4-4 Read (0xEB, 24-bit address) / 3 - 1-2-2 Read(0xBB, 24-bit address) +# 4 - HyperFLASH 1.8V / 5 - HyperFLASH 3V +# 6 - OctaBus DDR (SPI -> OPI DDR) +# 8 - Xccela DDR (SPI -> OPI DDR) +# 10 - EcoXiP DDR (SPI -> OPI DDR) +# [27:24] Command Pads after Power-on Reset +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [23:20] Command Pads after Configuring FLASH +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [19:16] Quad Enable Sequence (for the device support SFDP 1.0 only) +# 0 - Not needed +# 1 - QE bit is at bit6 in Status Register 1 +# 2 - QE bit is at bit1 in Status Register 2 +# 3 - QE bit is at bit7 in Status Register 2 +# 4 - QE bit is at bit1 in Status Register 2 and should be programmed by 0x31 +# [15:8] Dummy cycles +# 0 - Auto-probed / detected / default value +# Others - User specified value, for DDR read, the dummy cycles should be 2 * cycles on FLASH datasheet +# [7:4] Misc. +# 0 - Not used +# 1 - SPI mode +# 2 - Internal loopback +# 3 - External DQS +# [3:0] Frequency option +# 1 - 30MHz / 2 - 50MHz / 3 - 66MHz / 4 - 80MHz / 5 - 100MHz / 6 - 120MHz / 7 - 133MHz / 8 - 166MHz +# - option1: +# [31:20] Reserved +# [19:16] IO voltage +# 0 - 3V / 1 - 1.8V +# [15:12] Pin group +# 0 - 1st group / 1 - 2nd group +# [11:8] Connection selection +# 0 - CA_CS0 / 1 - CB_CS0 / 2 - CA_CS0 + CB_CS0 (Two FLASH connected to CA and CB respectively) +# [7:0] Drive Strength +# 0 - Default value + +# xpi0 configs +# - flash driver: hpm_xpi +# - flash ctrl index: 0xF3000000 +# - base address: 0x80000000 +# - flash size: 0x2000000 +# - flash option0: 0x5 +# - flash option1: 0x1000 +flash bank xpi0 hpm_xpi 0x80000000 0x2000000 1 1 $_TARGET0 0xF3000000 0x5 0x1000 + +proc init_clock {} { + mww 0xF4000800 0xFFFFFFFF + mww 0xF4000810 0xFFFFFFFF + mww 0xF4000820 0xFFFFFFFF + mww 0xF4000830 0xFFFFFFFF + echo "clocks has been enabled!" +} + +$_TARGET0 configure -event reset-init { + init_clock +} diff --git a/tcl/board/hpmicro/hpm6200evk.cfg b/tcl/board/hpmicro/hpm6200evk.cfg new file mode 100644 index 0000000000..67cda4fedb --- /dev/null +++ b/tcl/board/hpmicro/hpm6200evk.cfg @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 HPMicro + +adapter speed 10000 +source [find interface/hpmicro/hpmicro_evk.cfg] +source [find target/hpmicro/hpm6280-single-core.cfg] +# openocd flash driver argument: +# - option0: +# [31:28] Flash probe type +# 0 - SFDP SDR / 1 - SFDP DDR +# 2 - 1-4-4 Read (0xEB, 24-bit address) / 3 - 1-2-2 Read(0xBB, 24-bit address) +# 4 - HyperFLASH 1.8V / 5 - HyperFLASH 3V +# 6 - OctaBus DDR (SPI -> OPI DDR) +# 8 - Xccela DDR (SPI -> OPI DDR) +# 10 - EcoXiP DDR (SPI -> OPI DDR) +# [27:24] Command Pads after Power-on Reset +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [23:20] Command Pads after Configuring FLASH +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [19:16] Quad Enable Sequence (for the device support SFDP 1.0 only) +# 0 - Not needed +# 1 - QE bit is at bit6 in Status Register 1 +# 2 - QE bit is at bit1 in Status Register 2 +# 3 - QE bit is at bit7 in Status Register 2 +# 4 - QE bit is at bit1 in Status Register 2 and should be programmed by 0x31 +# [15:8] Dummy cycles +# 0 - Auto-probed / detected / default value +# Others - User specified value, for DDR read, the dummy cycles should be 2 * cycles on FLASH datasheet +# [7:4] Misc. +# 0 - Not used +# 1 - SPI mode +# 2 - Internal loopback +# 3 - External DQS +# [3:0] Frequency option +# 1 - 30MHz / 2 - 50MHz / 3 - 66MHz / 4 - 80MHz / 5 - 100MHz / 6 - 120MHz / 7 - 133MHz / 8 - 166MHz +# - option1: +# [31:20] Reserved +# [19:16] IO voltage +# 0 - 3V / 1 - 1.8V +# [15:12] Pin group +# 0 - 1st group / 1 - 2nd group +# [11:8] Connection selection +# 0 - CA_CS0 / 1 - CB_CS0 / 2 - CA_CS0 + CB_CS0 (Two FLASH connected to CA and CB respectively) +# [7:0] Drive Strength +# 0 - Default value + +# xpi0 configs +# - flash driver: hpm_xpi +# - flash ctrl index: 0xF3040000 +# - base address: 0x80000000 +# - flash size: 0x1000000 +flash bank xpi0 hpm_xpi 0x80000000 0x1000000 0 0 $_TARGET0 0xF3040000 + +proc init_clock {} { + mww 0xF4000800 0xFFFFFFFF + mww 0xF4000810 0xFFFFFFFF + mww 0xF4000820 0xFFFFFFFF + mww 0xF4000830 0xFFFFFFFF + echo "clocks has been enabled!" +} + +$_TARGET0 configure -event reset-init { + init_clock +} diff --git a/tcl/board/hpmicro/hpm6300evk.cfg b/tcl/board/hpmicro/hpm6300evk.cfg new file mode 100644 index 0000000000..5d0a711898 --- /dev/null +++ b/tcl/board/hpmicro/hpm6300evk.cfg @@ -0,0 +1,217 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2021 HPMicro + +adapter speed 10000 +source [find interface/hpmicro/hpmicro_evk.cfg] +source [find target/hpmicro/hpm6360.cfg] +# openocd flash driver argument: +# - option0: +# [31:28] Flash probe type +# 0 - SFDP SDR / 1 - SFDP DDR +# 2 - 1-4-4 Read (0xEB, 24-bit address) / 3 - 1-2-2 Read(0xBB, 24-bit address) +# 4 - HyperFLASH 1.8V / 5 - HyperFLASH 3V +# 6 - OctaBus DDR (SPI -> OPI DDR) +# 8 - Xccela DDR (SPI -> OPI DDR) +# 10 - EcoXiP DDR (SPI -> OPI DDR) +# [27:24] Command Pads after Power-on Reset +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [23:20] Command Pads after Configuring FLASH +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [19:16] Quad Enable Sequence (for the device support SFDP 1.0 only) +# 0 - Not needed +# 1 - QE bit is at bit6 in Status Register 1 +# 2 - QE bit is at bit1 in Status Register 2 +# 3 - QE bit is at bit7 in Status Register 2 +# 4 - QE bit is at bit1 in Status Register 2 and should be programmed by 0x31 +# openocd flash driver argument: +# - option0: +# [31:28] Flash probe type +# 0 - SFDP SDR / 1 - SFDP DDR +# 2 - 1-4-4 Read (0xEB, 24-bit address) / 3 - 1-2-2 Read(0xBB, 24-bit address) +# 4 - HyperFLASH 1.8V / 5 - HyperFLASH 3V +# 6 - OctaBus DDR (SPI -> OPI DDR) +# 8 - Xccela DDR (SPI -> OPI DDR) +# 10 - EcoXiP DDR (SPI -> OPI DDR) +# [27:24] Command Pads after Power-on Reset +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [23:20] Command Pads after Configuring FLASH +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [19:16] Quad Enable Sequence (for the device support SFDP 1.0 only) +# 0 - Not needed +# 1 - QE bit is at bit6 in Status Register 1 +# 2 - QE bit is at bit1 in Status Register 2 +# 3 - QE bit is at bit7 in Status Register 2 +# 4 - QE bit is at bit1 in Status Register 2 and should be programmed by 0x31 +# [15:8] Dummy cycles +# 0 - Auto-probed / detected / default value +# Others - User specified value, for DDR read, the dummy cycles should be 2 * cycles on FLASH datasheet +# [7:4] Misc. +# 0 - Not used +# 1 - SPI mode +# 2 - Internal loopback +# 3 - External DQS +# [3:0] Frequency option +# 1 - 30MHz / 2 - 50MHz / 3 - 66MHz / 4 - 80MHz / 5 - 100MHz / 6 - 120MHz / 7 - 133MHz / 8 - 166MHz +# - option1: +# [31:20] Reserved +# [19:16] IO voltage +# 0 - 3V / 1 - 1.8V +# [15:12] Pin group +# 0 - 1st group / 1 - 2nd group +# [11:8] Connection selection +# 0 - CA_CS0 / 1 - CB_CS0 / 2 - CA_CS0 + CB_CS0 (Two FLASH connected to CA and CB respectively) +# [7:0] Drive Strength +# 0 - Default value + +# xpi0 configs +# - flash driver: hpm_xpi +# - flash ctrl index: 0xF3040000 +# - base address: 0x80000000 +# - flash size: 0x1000000 +flash bank xpi0 hpm_xpi 0x80000000 0x1000000 0 0 $_TARGET0 0xF3040000 + +proc init_clock {} { + mww 0xF4000800 0xFFFFFFFF + mww 0xF4000810 0xFFFFFFFF + mww 0xF4000820 0xFFFFFFFF + mww 0xF4000830 0xFFFFFFFF + echo "clocks has been enabled!" +} + +proc init_sdram { } { +# configure femc frequency +# 166Mhz pll0_clk1: 333Mhz divide by 2 + mww 0xF4001808 0x201 + + # PA25 + mww 0xF40400C8 0xC + # PA26 + mww 0xF40400D0 0xC + # PA27 + mww 0xF40400D8 0xC + # PA28 + mww 0xF40400E0 0xC + # PA29 + mww 0xF40400E8 0xC + # PA30 + mww 0xF40400F0 0xC + # PA31 + mww 0xF40400F8 0xC + # PB00 + mww 0xF4040100 0xC + # PB01 + mww 0xF4040108 0xC + # PB02 + mww 0xF4040110 0xC + # PB03 + mww 0xF4040118 0xC + # PB04 + mww 0xF4040120 0xC + # PB05 + mww 0xF4040128 0xC + # PB06 + mww 0xF4040130 0xC + # PB07 + mww 0xF4040138 0xC + # PB08 + mww 0xF4040140 0xC + + # PB09 + mww 0xF4040148 0xC + # PB10 + mww 0xF4040150 0xC + # PB11 + mww 0xF4040158 0xC + # PB12 + mww 0xF4040160 0xC + # PB13 + mww 0xF4040168 0xC + # PB14 + mww 0xF4040170 0xC + # PB15 + mww 0xF4040178 0xC + # PB16 + mww 0xF4040180 0xC + # PB17 + mww 0xF4040188 0xC + # PB18 + mww 0xF4040190 0xC + # PB19 + mww 0xF4040198 0xC + # PB20 + mww 0xF40401A0 0xC + + # PB21 + mww 0xF40401A8 0xC + # PB22 + mww 0xF40401B0 0xC + # PB23 + mww 0xF40401B8 0xC + # PB24 + mww 0xF40401C0 0xC + # PB25 + mww 0xF40401C8 0xC + # PB26 + mww 0xF40401D0 0xC + # PB27 + mww 0xF40401D8 0xC + # PB28 + mww 0xF40401E0 0xC + # PB29 + mww 0xF40401E8 0xC + # PB30 + mww 0xF40401F0 0xC + # PB31 + mww 0xF40401F8 0xC + + # femc configuration + mww 0xF3050000 0x1 + sleep 10 + mww 0xF3050000 0x2 + mww 0xF3050008 0x30524 + mww 0xF305000C 0x6030524 + mww 0xF3050000 0x10000004 + + # 32MB + mww 0xF3050010 0x4000001b + mww 0xF3050014 0 + # 16-bit + mww 0xF3050040 0xf31 + + # 166Mhz configuration + mww 0xF3050044 0x884e33 + mww 0xF3050048 0x1020d0d + mww 0xF3050048 0x1020d0d + mww 0xF305004C 0x2020300 + + # config delay cell + mww 0xF3050150 0x2000 + mww 0xF3050094 0 + mww 0xF3050098 0 + + # precharge all + mww 0xF3050090 0x40000000 + mww 0xF305009C 0xA55A000F + sleep 500 + mww 0xF305003C 0x3 + # auto refresh + mww 0xF305009C 0xA55A000C + sleep 500 + mww 0xF305003C 0x3 + mww 0xF305009C 0xA55A000C + sleep 500 + mww 0xF305003C 0x3 + + # set mode + mww 0xF30500A0 0x33 + mww 0xF305009C 0xA55A000A + sleep 500 + mww 0xF305003C 0x3 + mww 0xF305004C 0x2020301 + echo "SDRAM has been initialized" +} + +$_TARGET0 configure -event reset-init { + init_clock + init_sdram +} diff --git a/tcl/board/hpmicro/hpm6750evk.cfg b/tcl/board/hpmicro/hpm6750evk.cfg new file mode 100644 index 0000000000..7cabef6dc7 --- /dev/null +++ b/tcl/board/hpmicro/hpm6750evk.cfg @@ -0,0 +1,239 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2021 HPMicro + +adapter speed 10000 +source [find interface/hpmicro/hpmicro_evk.cfg] +source [find target/hpmicro/hpm6750-single-core.cfg] +# openocd flash driver argument: +# - option0: +# [31:28] Flash probe type +# 0 - SFDP SDR / 1 - SFDP DDR +# 2 - 1-4-4 Read (0xEB, 24-bit address) / 3 - 1-2-2 Read(0xBB, 24-bit address) +# 4 - HyperFLASH 1.8V / 5 - HyperFLASH 3V +# 6 - OctaBus DDR (SPI -> OPI DDR) +# 8 - Xccela DDR (SPI -> OPI DDR) +# 10 - EcoXiP DDR (SPI -> OPI DDR) +# [27:24] Command Pads after Power-on Reset +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [23:20] Command Pads after Configuring FLASH +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [19:16] Quad Enable Sequence (for the device support SFDP 1.0 only) +# 0 - Not needed +# 1 - QE bit is at bit6 in Status Register 1 +# 2 - QE bit is at bit1 in Status Register 2 +# 3 - QE bit is at bit7 in Status Register 2 +# 4 - QE bit is at bit1 in Status Register 2 and should be programmed by 0x31 +# [15:8] Dummy cycles +# 0 - Auto-probed / detected / default value +# Others - User specified value, for DDR read, the dummy cycles should be 2 * cycles on FLASH datasheet +# [7:4] Misc. +# 0 - Not used +# 1 - SPI mode +# 2 - Internal loopback +# 3 - External DQS +# [3:0] Frequency option +# 1 - 30MHz / 2 - 50MHz / 3 - 66MHz / 4 - 80MHz / 5 - 100MHz / 6 - 120MHz / 7 - 133MHz / 8 - 166MHz +# - option1: +# [31:20] Reserved +# [19:16] IO voltage +# 0 - 3V / 1 - 1.8V +# [15:12] Pin group +# 0 - 1st group / 1 - 2nd group +# [11:8] Connection selection +# 0 - CA_CS0 / 1 - CB_CS0 / 2 - CA_CS0 + CB_CS0 (Two FLASH connected to CA and CB respectively) +# [7:0] Drive Strength +# 0 - Default value + +# xpi0 configs +# - flash driver: hpm_xpi +# - flash ctrl index: 0xF3040000 +# - base address: 0x80000000 +# - flash size: 0x2000000 +# - flash option0: 0x7 +flash bank xpi0 hpm_xpi 0x80000000 0x2000000 0 0 $_TARGET0 0xF3040000 0x7 + +proc init_clock {} { + mww 0xF4000800 0xFFFFFFFF + mww 0xF4000810 0xFFFFFFFF + mww 0xF4000820 0xFFFFFFFF + mww 0xF4000830 0xFFFFFFFF + echo "clocks has been enabled!" +} + +proc init_sdram { } { +# configure femc frequency +# 133Mhz pll1_clk0: 266Mhz divide by 2 + #mww 0xF4001820 0x201 +# 166Mhz pll2_clk0: 333Mhz divide by 2 + mww 0xF4001820 0x401 + # PC01 + mww 0xF4040208 0xC + # PC00 + mww 0xF4040200 0xC + # PB31 + mww 0xF40401F8 0xC + # PB30 + mww 0xF40401F0 0xC + # PB29 + mww 0xF40401E8 0xC + # PB28 + mww 0xF40401E0 0xC + # PB27 + mww 0xF40401D8 0xC + # PB26 + mww 0xF40401D0 0xC + # PB25 + mww 0xF40401C8 0xC + # PB24 + mww 0xF40401C0 0xC + # PB23 + mww 0xF40401B8 0xC + # PB22 + mww 0xF40401B0 0xC + # PB21 + mww 0xF40401A8 0xC + # PB20 + mww 0xF40401A0 0xC + # PB19 + mww 0xF4040198 0xC + # PB18 + mww 0xF4040190 0xC + + # PD13 + mww 0xF4040368 0xC + # PD12 + mww 0xF4040360 0xC + # PD10 + mww 0xF4040350 0xC + # PD09 + mww 0xF4040348 0xC + # PD08 + mww 0xF4040340 0xC + # PD07 + mww 0xF4040338 0xC + # PD06 + mww 0xF4040330 0xC + # PD05 + mww 0xF4040328 0xC + # PD04 + mww 0xF4040320 0xC + # PD03 + mww 0xF4040318 0xC + # PD02 + mww 0xF4040310 0xC + # PD01 + mww 0xF4040308 0xC + # PD00 + mww 0xF4040300 0xC + # PC29 + mww 0xF40402E8 0xC + # PC28 + mww 0xF40402E0 0xC + # PC27 + mww 0xF40402D8 0xC + + # PC22 + mww 0xF40402B0 0xC + # PC21 + mww 0xF40402A8 0xC + # PC17 + mww 0xF4040288 0xC + # PC15 + mww 0xF4040278 0xC + # PC12 + mww 0xF4040260 0xC + # PC11 + mww 0xF4040258 0xC + # PC10 + mww 0xF4040250 0xC + # PC09 + mww 0xF4040248 0xC + # PC08 + mww 0xF4040240 0xC + # PC07 + mww 0xF4040238 0xC + # PC06 + mww 0xF4040230 0xC + # PC05 + mww 0xF4040228 0xC + # PC04 + mww 0xF4040220 0xC + + # PC14 + mww 0xF4040270 0xC + # PC13 + mww 0xF4040268 0xC + # PC16 + # mww 0xF4040280 0x1000C + # PC26 + mww 0xF40402D0 0xC + # PC25 + mww 0xF40402C8 0xC + # PC19 + mww 0xF4040298 0xC + # PC18 + mww 0xF4040290 0xC + # PC23 + mww 0xF40402B8 0xC + # PC24 + mww 0xF40402C0 0xC + # PC30 + mww 0xF40402F0 0xC + # PC31 + mww 0xF40402F8 0xC + # PC02 + mww 0xF4040210 0xC + # PC03 + mww 0xF4040218 0xC + + # femc configuration + mww 0xF3050000 0x1 + sleep 10 + mww 0xF3050000 0x2 + mww 0xF3050008 0x30524 + mww 0xF305000C 0x6030524 + mww 0xF3050000 0x10000000 + mww 0xF3050010 0x4000001b + mww 0xF3050014 0 + mww 0xF3050040 0xf32 + + # 133Mhz configuration + #mww 0xF3050044 0x884e22 + # 166Mhz configuration + mww 0xF3050044 0x884e33 + mww 0xF3050048 0x1020d0d + mww 0xF3050048 0x1020d0d + mww 0xF305004C 0x2020300 + + # config delay cell + mww 0xF3050150 0x3b + mww 0xF3050150 0x203b + mww 0xF3050094 0 + mww 0xF3050098 0 + + # precharge all + mww 0xF3050090 0x40000000 + mww 0xF305009C 0xA55A000F + sleep 500 + mww 0xF305003C 0x3 + # auto refresh + mww 0xF305009C 0xA55A000C + sleep 500 + mww 0xF305003C 0x3 + mww 0xF305009C 0xA55A000C + sleep 500 + mww 0xF305003C 0x3 + + # set mode + mww 0xF30500A0 0x33 + mww 0xF305009C 0xA55A000A + sleep 500 + mww 0xF305003C 0x3 + mww 0xF305004C 0x2020301 + echo "SDRAM has been initialized" +} + +$_TARGET0 configure -event reset-init { + init_clock + init_sdram +} diff --git a/tcl/board/hpmicro/hpm6750evk2.cfg b/tcl/board/hpmicro/hpm6750evk2.cfg new file mode 100644 index 0000000000..35fca3c37a --- /dev/null +++ b/tcl/board/hpmicro/hpm6750evk2.cfg @@ -0,0 +1,239 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2022 HPMicro + +adapter speed 10000 +source [find interface/hpmicro/hpmicro_evk.cfg] +source [find target/hpmicro/hpm6750-single-core.cfg] +# openocd flash driver argument: +# - option0: +# [31:28] Flash probe type +# 0 - SFDP SDR / 1 - SFDP DDR +# 2 - 1-4-4 Read (0xEB, 24-bit address) / 3 - 1-2-2 Read(0xBB, 24-bit address) +# 4 - HyperFLASH 1.8V / 5 - HyperFLASH 3V +# 6 - OctaBus DDR (SPI -> OPI DDR) +# 8 - Xccela DDR (SPI -> OPI DDR) +# 10 - EcoXiP DDR (SPI -> OPI DDR) +# [27:24] Command Pads after Power-on Reset +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [23:20] Command Pads after Configuring FLASH +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [19:16] Quad Enable Sequence (for the device support SFDP 1.0 only) +# 0 - Not needed +# 1 - QE bit is at bit6 in Status Register 1 +# 2 - QE bit is at bit1 in Status Register 2 +# 3 - QE bit is at bit7 in Status Register 2 +# 4 - QE bit is at bit1 in Status Register 2 and should be programmed by 0x31 +# [15:8] Dummy cycles +# 0 - Auto-probed / detected / default value +# Others - User specified value, for DDR read, the dummy cycles should be 2 * cycles on FLASH datasheet +# [7:4] Misc. +# 0 - Not used +# 1 - SPI mode +# 2 - Internal loopback +# 3 - External DQS +# [3:0] Frequency option +# 1 - 30MHz / 2 - 50MHz / 3 - 66MHz / 4 - 80MHz / 5 - 100MHz / 6 - 120MHz / 7 - 133MHz / 8 - 166MHz +# - option1: +# [31:20] Reserved +# [19:16] IO voltage +# 0 - 3V / 1 - 1.8V +# [15:12] Pin group +# 0 - 1st group / 1 - 2nd group +# [11:8] Connection selection +# 0 - CA_CS0 / 1 - CB_CS0 / 2 - CA_CS0 + CB_CS0 (Two FLASH connected to CA and CB respectively) +# [7:0] Drive Strength +# 0 - Default value + +# xpi0 configs +# - flash driver: hpm_xpi +# - flash ctrl index: 0xF3040000 +# - base address: 0x80000000 +# - flash size: 0x2000000 +# - flash option0: 0x7 +flash bank xpi0 hpm_xpi 0x80000000 0x2000000 1 1 $_TARGET0 0xF3040000 0x7 + +proc init_clock {} { + mww 0xF4000800 0xFFFFFFFF + mww 0xF4000810 0xFFFFFFFF + mww 0xF4000820 0xFFFFFFFF + mww 0xF4000830 0xFFFFFFFF + echo "clocks has been enabled!" +} + +proc init_sdram { } { +# configure femc frequency +# 133Mhz pll1_clk0: 266Mhz divide by 2 + #mww 0xF4001820 0x201 +# 166Mhz pll2_clk0: 333Mhz divide by 2 + mww 0xF4001820 0x401 + # PC01 + mww 0xF4040208 0xC + # PC00 + mww 0xF4040200 0xC + # PB31 + mww 0xF40401F8 0xC + # PB30 + mww 0xF40401F0 0xC + # PB29 + mww 0xF40401E8 0xC + # PB28 + mww 0xF40401E0 0xC + # PB27 + mww 0xF40401D8 0xC + # PB26 + mww 0xF40401D0 0xC + # PB25 + mww 0xF40401C8 0xC + # PB24 + mww 0xF40401C0 0xC + # PB23 + mww 0xF40401B8 0xC + # PB22 + mww 0xF40401B0 0xC + # PB21 + mww 0xF40401A8 0xC + # PB20 + mww 0xF40401A0 0xC + # PB19 + mww 0xF4040198 0xC + # PB18 + mww 0xF4040190 0xC + + # PD13 + mww 0xF4040368 0xC + # PD12 + mww 0xF4040360 0xC + # PD10 + mww 0xF4040350 0xC + # PD09 + mww 0xF4040348 0xC + # PD08 + mww 0xF4040340 0xC + # PD07 + mww 0xF4040338 0xC + # PD06 + mww 0xF4040330 0xC + # PD05 + mww 0xF4040328 0xC + # PD04 + mww 0xF4040320 0xC + # PD03 + mww 0xF4040318 0xC + # PD02 + mww 0xF4040310 0xC + # PD01 + mww 0xF4040308 0xC + # PD00 + mww 0xF4040300 0xC + # PC29 + mww 0xF40402E8 0xC + # PC28 + mww 0xF40402E0 0xC + # PC27 + mww 0xF40402D8 0xC + + # PC22 + mww 0xF40402B0 0xC + # PC21 + mww 0xF40402A8 0xC + # PC17 + mww 0xF4040288 0xC + # PC15 + mww 0xF4040278 0xC + # PC12 + mww 0xF4040260 0xC + # PC11 + mww 0xF4040258 0xC + # PC10 + mww 0xF4040250 0xC + # PC09 + mww 0xF4040248 0xC + # PC08 + mww 0xF4040240 0xC + # PC07 + mww 0xF4040238 0xC + # PC06 + mww 0xF4040230 0xC + # PC05 + mww 0xF4040228 0xC + # PC04 + mww 0xF4040220 0xC + + # PC14 + mww 0xF4040270 0xC + # PC13 + mww 0xF4040268 0xC + # PC16 + #mww 0xF4040280 0x1000C + # PC26 + mww 0xF40402D0 0xC + # PC25 + mww 0xF40402C8 0xC + # PC19 + mww 0xF4040298 0xC + # PC18 + mww 0xF4040290 0xC + # PC23 + mww 0xF40402B8 0xC + # PC24 + mww 0xF40402C0 0xC + # PC30 + mww 0xF40402F0 0xC + # PC31 + mww 0xF40402F8 0xC + # PC02 + mww 0xF4040210 0xC + # PC03 + mww 0xF4040218 0xC + + # femc configuration + mww 0xF3050000 0x1 + sleep 10 + mww 0xF3050000 0x2 + mww 0xF3050008 0x30524 + mww 0xF305000C 0x6030524 + mww 0xF3050000 0x10000000 + mww 0xF3050010 0x4000001b + mww 0xF3050014 0 + mww 0xF3050040 0xf32 + + # 133Mhz configuration + #mww 0xF3050044 0x884e22 + # 166Mhz configuration + mww 0xF3050044 0x884e33 + mww 0xF3050048 0x1020d0d + mww 0xF3050048 0x1020d0d + mww 0xF305004C 0x2020300 + + # config delay cell + mww 0xF3050150 0x3b + mww 0xF3050150 0x203b + mww 0xF3050094 0 + mww 0xF3050098 0 + + # precharge all + mww 0xF3050090 0x40000000 + mww 0xF305009C 0xA55A000F + sleep 500 + mww 0xF305003C 0x3 + # auto refresh + mww 0xF305009C 0xA55A000C + sleep 500 + mww 0xF305003C 0x3 + mww 0xF305009C 0xA55A000C + sleep 500 + mww 0xF305003C 0x3 + + # set mode + mww 0xF30500A0 0x33 + mww 0xF305009C 0xA55A000A + sleep 500 + mww 0xF305003C 0x3 + mww 0xF305004C 0x2020301 + echo "SDRAM has been initialized" +} + +$_TARGET0 configure -event reset-init { + init_clock + init_sdram +} diff --git a/tcl/board/hpmicro/hpm6750evkmini.cfg b/tcl/board/hpmicro/hpm6750evkmini.cfg new file mode 100644 index 0000000000..37b1ef83ed --- /dev/null +++ b/tcl/board/hpmicro/hpm6750evkmini.cfg @@ -0,0 +1,210 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2021 HPMicro + +adapter speed 10000 +source [find interface/hpmicro/hpmicro_evk.cfg] +source [find target/hpmicro/hpm6750-single-core.cfg] +# openocd flash driver argument: +# - ARG7: +# [31:28] Flash probe type +# 0 - SFDP SDR / 1 - SFDP DDR +# 2 - 1-4-4 Read (0xEB, 24-bit address) / 3 - 1-2-2 Read(0xBB, 24-bit address) +# 4 - HyperFLASH 1.8V / 5 - HyperFLASH 3V +# 6 - OctaBus DDR (SPI -> OPI DDR) +# 8 - Xccela DDR (SPI -> OPI DDR) +# 10 - EcoXiP DDR (SPI -> OPI DDR) +# [27:24] Command Pads after Power-on Reset +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [23:20] Command Pads after Configuring FLASH +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [19:16] Quad Enable Sequence (for the device support SFDP 1.0 only) +# 0 - Not needed +# 1 - QE bit is at bit6 in Status Register 1 +# 2 - QE bit is at bit1 in Status Register 2 +# 3 - QE bit is at bit7 in Status Register 2 +# 4 - QE bit is at bit1 in Status Register 2 and should be programmed by 0x31 +# [15:8] Dummy cycles +# 0 - Auto-probed / detected / default value +# Others - User specified value, for DDR read, the dummy cycles should be 2 * cycles on FLASH datasheet +# [7:4] Misc. +# 0 - Not used +# 1 - SPI mode +# 2 - Internal loopback +# 3 - External DQS +# [3:0] Frequency option +# 1 - 30MHz / 2 - 50MHz / 3 - 66MHz / 4 - 80MHz / 5 - 100MHz / 6 - 120MHz / 7 - 133MHz / 8 - 166MHz +# - ARG8: +# [31:20] Reserved +# [19:16] IO voltage +# 0 - 3V / 1 - 1.8V +# [15:12] Pin group +# 0 - 1st group / 1 - 2nd group +# [11:8] Connection selection +# 0 - CA_CS0 / 1 - CB_CS0 / 2 - CA_CS0 + CB_CS0 (Two FLASH connected to CA and CB respectively) +# [7:0] Drive Strength +# 0 - Default value + +# xpi0 configs +# - flash driver: hpm_xpi +# - flash ctrl index: 0xF3040000 +# - base address: 0x80000000 +# - flash size: 0x1000000 +# - flash option0: 0x7 +flash bank xpi0 hpm_xpi 0x80000000 0x1000000 1 1 $_TARGET0 0xF3040000 0x7 + +proc init_clock {} { + mww 0xF4000800 0xFFFFFFFF + mww 0xF4000810 0xFFFFFFFF + mww 0xF4000820 0xFFFFFFFF + mww 0xF4000830 0xFFFFFFFF + echo "clocks has been enabled!" +} + +proc init_sdram { } { +# configure femc frequency +# 133Mhz pll1_clk0: 266Mhz divide by 2 + #mww 0xF4001820 0x201 +# 166Mhz pll2_clk0: 333Mhz divide by 2 + mww 0xF4001820 0x401 + + # PD13 + mww 0xF4040368 0xC + # PD12 + mww 0xF4040360 0xC + # PD10 + mww 0xF4040350 0xC + # PD09 + mww 0xF4040348 0xC + # PD08 + mww 0xF4040340 0xC + # PD07 + mww 0xF4040338 0xC + # PD06 + mww 0xF4040330 0xC + # PD05 + mww 0xF4040328 0xC + # PD04 + mww 0xF4040320 0xC + # PD03 + mww 0xF4040318 0xC + # PD02 + mww 0xF4040310 0xC + # PD01 + mww 0xF4040308 0xC + # PD00 + mww 0xF4040300 0xC + # PC29 + mww 0xF40402E8 0xC + # PC28 + mww 0xF40402E0 0xC + # PC27 + mww 0xF40402D8 0xC + + # PC22 + mww 0xF40402B0 0xC + # PC21 + mww 0xF40402A8 0xC + # PC17 + mww 0xF4040288 0xC + # PC15 + mww 0xF4040278 0xC + # PC12 + mww 0xF4040260 0xC + # PC11 + mww 0xF4040258 0xC + # PC10 + mww 0xF4040250 0xC + # PC09 + mww 0xF4040248 0xC + # PC08 + mww 0xF4040240 0xC + # PC07 + mww 0xF4040238 0xC + # PC06 + mww 0xF4040230 0xC + # PC05 + mww 0xF4040228 0xC + # PC04 + mww 0xF4040220 0xC + + # PC14 + mww 0xF4040270 0xC + # PC13 + mww 0xF4040268 0xC + # PC16 + #mww 0xF4040280 0x1000C + # PC26 + mww 0xF40402D0 0xC + # PC25 + mww 0xF40402C8 0xC + # PC19 + mww 0xF4040298 0xC + # PC18 + mww 0xF4040290 0xC + # PC23 + mww 0xF40402B8 0xC + # PC24 + mww 0xF40402C0 0xC + # PC30 + mww 0xF40402F0 0xC + # PC31 + mww 0xF40402F8 0xC + # PC02 + mww 0xF4040210 0xC + # PC03 + mww 0xF4040218 0xC + + # femc configuration + mww 0xF3050000 0x1 + sleep 10 + mww 0xF3050000 0x2 + mww 0xF3050008 0x30524 + mww 0xF305000C 0x6030524 + mww 0xF3050000 0x10000000 + + # 16MB + mww 0xF3050010 0x40000019 + mww 0xF3050014 0 + # 16-bit + mww 0xF3050040 0xf31 + + # 133Mhz configuration + #mww 0xF3050044 0x884e22 + # 166Mhz configuration + mww 0xF3050044 0x884e33 + mww 0xF3050048 0x1020d0d + mww 0xF3050048 0x1020d0d + mww 0xF305004C 0x2020300 + + # config delay cell + mww 0xF3050150 0x3b + mww 0xF3050150 0x203b + mww 0xF3050094 0 + mww 0xF3050098 0 + + # precharge all + mww 0xF3050090 0x40000000 + mww 0xF305009C 0xA55A000F + sleep 500 + mww 0xF305003C 0x3 + # auto refresh + mww 0xF305009C 0xA55A000C + sleep 500 + mww 0xF305003C 0x3 + mww 0xF305009C 0xA55A000C + sleep 500 + mww 0xF305003C 0x3 + + # set mode + mww 0xF30500A0 0x33 + mww 0xF305009C 0xA55A000A + sleep 500 + mww 0xF305003C 0x3 + mww 0xF305004C 0x2020301 + echo "SDRAM has been initialized" +} + +$_TARGET0 configure -event reset-init { + init_clock + init_sdram +} diff --git a/tcl/board/hpmicro/hpm6800evk.cfg b/tcl/board/hpmicro/hpm6800evk.cfg new file mode 100644 index 0000000000..86b674f771 --- /dev/null +++ b/tcl/board/hpmicro/hpm6800evk.cfg @@ -0,0 +1,157 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 HPMicro + +adapter speed 10000 +source [find interface/hpmicro/hpmicro_evk.cfg] +source [find target/hpmicro/hpm6880.cfg] +# openocd flash driver argument: +# - option0: +# [31:28] Flash probe type +# 0 - SFDP SDR / 1 - SFDP DDR +# 2 - 1-4-4 Read (0xEB, 24-bit address) / 3 - 1-2-2 Read(0xBB, 24-bit address) +# 4 - HyperFLASH 1.8V / 5 - HyperFLASH 3V +# 6 - OctaBus DDR (SPI -> OPI DDR) +# 8 - Xccela DDR (SPI -> OPI DDR) +# 10 - EcoXiP DDR (SPI -> OPI DDR) +# [27:24] Command Pads after Power-on Reset +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [23:20] Command Pads after Configuring FLASH +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [19:16] Quad Enable Sequence (for the device support SFDP 1.0 only) +# 0 - Not needed +# 1 - QE bit is at bit6 in Status Register 1 +# 2 - QE bit is at bit1 in Status Register 2 +# 3 - QE bit is at bit7 in Status Register 2 +# 4 - QE bit is at bit1 in Status Register 2 and should be programmed by 0x31 +# [15:8] Dummy cycles +# 0 - Auto-probed / detected / default value +# Others - User specified value, for DDR read, the dummy cycles should be 2 * cycles on FLASH datasheet +# [7:4] Misc. +# 0 - Not used +# 1 - SPI mode +# 2 - Internal loopback +# 3 - External DQS +# [3:0] Frequency option +# 1 - 30MHz / 2 - 50MHz / 3 - 66MHz / 4 - 80MHz / 5 - 100MHz / 6 - 120MHz / 7 - 133MHz / 8 - 166MHz +# - option1: +# [31:20] Reserved +# [19:16] IO voltage +# 0 - 3V / 1 - 1.8V +# [15:12] Pin group +# 0 - 1st group / 1 - 2nd group +# [11:8] Connection selection +# 0 - CA_CS0 / 1 - CB_CS0 / 2 - CA_CS0 + CB_CS0 (Two FLASH connected to CA and CB respectively) +# [7:0] Drive Strength +# 0 - Default value + +# xpi0 configs +# - flash driver: hpm_xpi +# - flash ctrl index: 0xF3000000 +# - base address: 0x80000000 +# - flash size: 0x2000000 +# - flash option0: 0x7 +flash bank xpi0 hpm_xpi 0x80000000 0x2000000 0 0 $_TARGET0 0xF3000000 0x7 + +proc init_clock {} { + mww 0xF4000800 0xFFFFFFFF + mww 0xF4000810 0xFFFFFFFF + mww 0xF4000820 0xFFFFFFFF + mww 0xF4000830 0xFFFFFFFF + echo "clocks has been enabled!" +} + +proc init_ddr3 {} { +# ddr dcdc setup + mww 0xF4104080 0x10578 + +# ddr3 setup + mww 0xF40C0180 0x30000019 + mww 0xF400180C 0x09100401 + mww 0xF4153000 0xF0000010 + mww 0xF30101B0 0 + mww 0xF4150040 0xf004641f + mww 0xF4153000 0xf0000011 + mww 0xF3013000 0xf4000000 + mww 0xF3010490 1 + mww 0xF3010000 0x1040001 + mww 0xF30100D0 0x4002004e + mww 0xF3010110 0x05010407 + mww 0xF3010190 0x07040102 + mww 0xF3010194 0x20404 + mww 0xF30101A4 0x20008 + mww 0xF3010240 0x06000600 + mww 0xF3010200 0x1F1F1F + mww 0xF3010204 0x121212 + mww 0xF3010208 0 + mww 0xF301020C 0 + mww 0xF3010210 0x1F1F + mww 0xF3010214 0x06030303 + mww 0xF3010218 0x0F060606 + mww 0xF3013000 0xFC000000 + mww 0xF4150054 0xc70 + mww 0xF4150058 0x6 + mww 0xF415005c 0x18 + mww 0xF4150048 0x919c8866 + mww 0xF415004c 0x1a838360 + mww 0xF415008c 0xf06d50 + mww 0xF4150050 0x3002d200 + mww 0xF30101b0 1 + sleep 100 + mww 0xF4150068 0x930035C7 + mww 0xF4150004 0xFF81 + sleep 200 + echo "ddr3 has been enabled!" +} + +proc init_dram {} { +# ddr dcdc setup + mww 0xF4104080 0x10708 + +# pll1 setup + mww 0xF40c0180 0xb0000016 + mww 0xF40c0184 0 + mww 0xF40c0188 0xe4e1c00 + +#ddr setup + mww 0xF3010000 0x3040000 + mww 0xF30101B0 0 + mww 0xF4150044 0x40a + mww 0xF4150040 0xf004641f + mww 0xF4153000 0xf0000011 + mww 0xF3013000 0xf4000000 + mww 0xF3010490 1 + mww 0xF3010000 0x1040000 + mww 0xF3010190 0x07010101 + mww 0xF3010194 0x20404 + mww 0xF30101A4 0x20008 + mww 0xF3010240 0x6000600 + mww 0xF3010200 0x1f1f1f + mww 0xF3010204 0x70707 + mww 0xF3010208 0 + mww 0xF301020c 0 + mww 0xF3010210 0x1f1f + mww 0xF3010214 0x6060606 + mww 0xF3010218 0xf0f0606 + mww 0xF3013000 0xfc000000 + mww 0xF4150020 0x3000100 + mww 0xF4150028 0x18002356 + mww 0xF415002c 0x0aac4156 + mww 0xF4150054 0xe73 + mww 0xF4150058 0x5 + mww 0xF415005c 0 + mww 0xF4150048 0xf2adfe53 + mww 0xF415004c 0x22820362 + mww 0xF4150050 0x30020100 + mww 0xF415008c 0xf06d50 + mww 0xF30101b0 1 + sleep 100 + mww 0xF4150068 0x91003587 + mww 0xF4150004 0xF501 + sleep 200 + echo "ddr has been enabled!" +} + +$_TARGET0 configure -event reset-init { + init_clock + init_ddr3 +} diff --git a/tcl/board/hpmicro/hpm6e00evk.cfg b/tcl/board/hpmicro/hpm6e00evk.cfg new file mode 100644 index 0000000000..982db1d3c3 --- /dev/null +++ b/tcl/board/hpmicro/hpm6e00evk.cfg @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2024 HPMicro + +adapter speed 10000 +source [find interface/hpmicro/hpmicro_evk.cfg] +source [find target/hpmicro/hpm6e80-single-core.cfg] +# openocd flash driver argument: +# - option0: +# [31:28] Flash probe type +# 0 - SFDP SDR / 1 - SFDP DDR +# 2 - 1-4-4 Read (0xEB, 24-bit address) / 3 - 1-2-2 Read(0xBB, 24-bit address) +# 4 - HyperFLASH 1.8V / 5 - HyperFLASH 3V +# 6 - OctaBus DDR (SPI -> OPI DDR) +# 8 - Xccela DDR (SPI -> OPI DDR) +# 10 - EcoXiP DDR (SPI -> OPI DDR) +# [27:24] Command Pads after Power-on Reset +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [23:20] Command Pads after Configuring FLASH +# 0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI +# [19:16] Quad Enable Sequence (for the device support SFDP 1.0 only) +# 0 - Not needed +# 1 - QE bit is at bit6 in Status Register 1 +# 2 - QE bit is at bit1 in Status Register 2 +# 3 - QE bit is at bit7 in Status Register 2 +# 4 - QE bit is at bit1 in Status Register 2 and should be programmed by 0x31 +# [15:8] Dummy cycles +# 0 - Auto-probed / detected / default value +# Others - User specified value, for DDR read, the dummy cycles should be 2 * cycles on FLASH datasheet +# [7:4] Misc. +# 0 - Not used +# 1 - SPI mode +# 2 - Internal loopback +# 3 - External DQS +# [3:0] Frequency option +# 1 - 30MHz / 2 - 50MHz / 3 - 66MHz / 4 - 80MHz / 5 - 100MHz / 6 - 120MHz / 7 - 133MHz / 8 - 166MHz +# - option1: +# [31:20] Reserved +# [19:16] IO voltage +# 0 - 3V / 1 - 1.8V +# [15:12] Pin group +# 0 - 1st group / 1 - 2nd group +# [11:8] Connection selection +# 0 - CA_CS0 / 1 - CB_CS0 / 2 - CA_CS0 + CB_CS0 (Two FLASH connected to CA and CB respectively) +# [7:0] Drive Strength +# 0 - Default value + +# xpi0 configs +# - flash driver: hpm_xpi +# - flash ctrl index: 0xF3000000 +# - base address: 0x80000000 +# - flash size: 0x2000000 +# - flash option0: 0x7 +flash bank xpi0 hpm_xpi 0x80000000 0x2000000 0 0 $_TARGET0 0xF3000000 0x7 + +proc init_clock {} { + mww 0xF4000800 0xFFFFFFFF + mww 0xF4000810 0xFFFFFFFF + mww 0xF4000820 0xFFFFFFFF + mww 0xF4000830 0xFFFFFFFF + echo "clocks has been enabled!" +} + +$_TARGET0 configure -event reset-init { + init_clock +} diff --git a/tcl/board/kasli.cfg b/tcl/board/kasli.cfg index d85e1ca152..3c331b1706 100644 --- a/tcl/board/kasli.cfg +++ b/tcl/board/kasli.cfg @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-or-later adapter driver ftdi -ftdi device_desc "Quad RS232-HS" -ftdi vid_pid 0x0403 0x6011 +adapter usb product_name "Quad RS232-HS" +adapter usb vid_pid 0x0403 0x6011 ftdi channel 0 ftdi layout_init 0x0008 0x000b # adapter usb location 1:8 diff --git a/tcl/board/linksys-wag200g.cfg b/tcl/board/linksys-wag200g.cfg index 26900a7d7a..2150baf893 100644 --- a/tcl/board/linksys-wag200g.cfg +++ b/tcl/board/linksys-wag200g.cfg @@ -22,7 +22,7 @@ set partition_list { adam2env { "Adam2 environment" 0x903f0000 0x00010000 } } -source [find target/ti-ar7.cfg] +source [find target/ti/ar7.cfg] # External 4MB MXIC 29LV320MBTC Flash (Manufacturer/Device: 0x00c2 0x227e) set _FLASHNAME $_CHIPNAME.flash diff --git a/tcl/board/microchip/pic64gx-curiosity-kit.cfg b/tcl/board/microchip/pic64gx-curiosity-kit.cfg new file mode 100644 index 0000000000..e7e67ea4bd --- /dev/null +++ b/tcl/board/microchip/pic64gx-curiosity-kit.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip RISC-V board +# +# https://www.microchip.com/en-us/products/microprocessors/64-bit-mpus/pic64gx +# +adapter speed 6000 + +source [find interface/microchip/embedded_flashpro5.cfg] +source [find target/microchip/pic64gx.cfg] diff --git a/tcl/board/microchip/sama7d65-curiosity.cfg b/tcl/board/microchip/sama7d65-curiosity.cfg new file mode 100644 index 0000000000..2f32daf154 --- /dev/null +++ b/tcl/board/microchip/sama7d65-curiosity.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip SAMA7D65 Curiosity Board (EV63J76A) +# https://www.microchip.com/en-us/development-tool/EV63J76A +# +# SAMA7D65 Cortex-A7, DDR SDRAM, 128 KB SRAM +# +# External JTAG/SWD probe connects to J38. +# +# JTAG is disabled by ROM code during boot. +# On blank boards, ROM enters SAM-BA Monitor which enables JTAG. +# Remove JP9, JP10 and SD card to force SAM-BA entry. +# +# Two-stage boot for debug: +# 1. Load AT91Bootstrap to SRAM (0x00100000) - initializes DDR +# 2. Load application to DDR (0x60000000) +# + +source [find target/microchip/sama7d6.cfg] + +# Conservative initial speed - increases after reset-init +adapter speed 1000 diff --git a/tcl/board/microchip/sama7g54-ek.cfg b/tcl/board/microchip/sama7g54-ek.cfg new file mode 100644 index 0000000000..e6e07b9feb --- /dev/null +++ b/tcl/board/microchip/sama7g54-ek.cfg @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip SAMA7G54-EK evaluation kit (EV21H18A) +# https://www.microchip.com/en-us/development-tool/EV21H18A +# +# SAMA7G54 Cortex-A7 @ 1 GHz, 512 MB DDR3L, 128 KB SRAM +# +# Debug interface selection: +# By default, uses on-board J-Link-OB (USB J24, J26 must be open). +# Could specify external adapter by: +# openocd -f interface/jlink.cfg -c "transport select jtag" \ +# -f board/microchip/sama7g54-ek.cfg +# otherwise use on-board J-Link-OB by default. +# +# JTAG is disabled by ROM code during boot. +# On blank boards, ROM enters SAM-BA Monitor which enables JTAG. +# Press SW4 or close J22 to force SAM-BA entry. +# +# Two-stage boot for debug: +# 1. Load AT91Bootstrap to SRAM (0x00100000) - initializes DDR +# 2. Load application to DDR (0x60000000) +# +if { [adapter name] eq "undefined" } { + # Use on-board J-Link-OB adapter (JTAG) + echo "Info : use on-board J-Link-OB adapter" + source [find interface/jlink.cfg] + transport select jtag +} else { + # External adapter specified on command line + # User must select transport via: -c "transport select jtag" or "swd" + echo "Info : use external [adapter name] adapter" +} +source [find target/microchip/sama7g5.cfg] +# Conservative initial speed - increases after reset-init +adapter speed 1000 diff --git a/tcl/board/mikroe/clicker4-stm32f745vg.cfg b/tcl/board/mikroe/clicker4-stm32f745vg.cfg new file mode 100644 index 0000000000..9ccd948801 --- /dev/null +++ b/tcl/board/mikroe/clicker4-stm32f745vg.cfg @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is a MikroElektronika Click 4 board with a single STM32F745VG chip +# and an on-board CODEGRIP debugger. +# https://www.mikroe.com/clicker-4-for-stm32f745vgt6 + +source [find interface/cmsis-dap.cfg] +transport select jtag +adapter speed 4000 + +source [find target/stm32f7x.cfg] diff --git a/tcl/board/nds32_corvettef1.cfg b/tcl/board/nds32_corvettef1.cfg index 7300ce04a2..195977e434 100644 --- a/tcl/board/nds32_corvettef1.cfg +++ b/tcl/board/nds32_corvettef1.cfg @@ -7,8 +7,8 @@ adapter speed 10000 adapter driver ftdi -ftdi device_desc "Dual RS232-HS" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Dual RS232-HS" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 diff --git a/tcl/board/netgear-dg834v3.cfg b/tcl/board/netgear-dg834v3.cfg index a9938889c6..4292ac4065 100644 --- a/tcl/board/netgear-dg834v3.cfg +++ b/tcl/board/netgear-dg834v3.cfg @@ -12,7 +12,7 @@ set partition_list { config { "Bootloader config space" 0x903f0000 0x00010000 } } -source [find target/ti-ar7.cfg] +source [find target/ti/ar7.cfg] # External 16MB SDRAM - disabled as we use internal sram #$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x00001000 diff --git a/tcl/board/nordic_nrf51_dk.cfg b/tcl/board/nordic/nrf51-dk.cfg similarity index 72% rename from tcl/board/nordic_nrf51_dk.cfg rename to tcl/board/nordic/nrf51-dk.cfg index 7ddae2d438..dee63cc7ff 100644 --- a/tcl/board/nordic_nrf51_dk.cfg +++ b/tcl/board/nordic/nrf51-dk.cfg @@ -5,7 +5,4 @@ # source [find interface/jlink.cfg] - -transport select swd - -source [find target/nrf51.cfg] +source [find target/nordic/nrf51.cfg] diff --git a/tcl/board/nordic_nrf51822_mkit.cfg b/tcl/board/nordic/nrf51822-mkit.cfg similarity index 79% rename from tcl/board/nordic_nrf51822_mkit.cfg rename to tcl/board/nordic/nrf51822-mkit.cfg index 266d710704..fd32271789 100644 --- a/tcl/board/nordic_nrf51822_mkit.cfg +++ b/tcl/board/nordic/nrf51822-mkit.cfg @@ -5,4 +5,4 @@ # source [find interface/cmsis-dap.cfg] -source [find target/nrf51.cfg] +source [find target/nordic/nrf51.cfg] diff --git a/tcl/board/nordic_nrf52_dk.cfg b/tcl/board/nordic/nrf52-dk.cfg similarity index 72% rename from tcl/board/nordic_nrf52_dk.cfg rename to tcl/board/nordic/nrf52-dk.cfg index 7366bf94af..c35d5c7c6b 100644 --- a/tcl/board/nordic_nrf52_dk.cfg +++ b/tcl/board/nordic/nrf52-dk.cfg @@ -5,7 +5,4 @@ # source [find interface/jlink.cfg] - -transport select swd - -source [find target/nrf52.cfg] +source [find target/nordic/nrf52.cfg] diff --git a/tcl/board/nordic/nrf5340-dk.cfg b/tcl/board/nordic/nrf5340-dk.cfg new file mode 100644 index 0000000000..8d5c111013 --- /dev/null +++ b/tcl/board/nordic/nrf5340-dk.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Nordic Semiconductor nRF5340 Development Kit +# https://www.nordicsemi.com/Products/Development-hardware/nRF5340-DK +# + +source [find interface/jlink.cfg] +source [find target/nordic/nrf53.cfg] diff --git a/tcl/board/nordic/nrf9160-dk.cfg b/tcl/board/nordic/nrf9160-dk.cfg new file mode 100644 index 0000000000..b3deedaa81 --- /dev/null +++ b/tcl/board/nordic/nrf9160-dk.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Nordic Semiconductor nRF9160 Development Kit +# https://www.nordicsemi.com/Products/Development-hardware/nRF9160-DK +# + +source [find interface/jlink.cfg] +source [find target/nordic/nrf91.cfg] diff --git a/tcl/board/nordic_nrf52_ftx232.cfg b/tcl/board/nordic_nrf52_ftx232.cfg index c3c69a89a5..772d176d6f 100644 --- a/tcl/board/nordic_nrf52_ftx232.cfg +++ b/tcl/board/nordic_nrf52_ftx232.cfg @@ -5,9 +5,11 @@ # or any FT232H/FT2232H/FT4232H based board/module # +echo "WARNING: 'board/nordic_nrf52_ftx232.cfg' is deprecated, use '-f interface/ftdi/ft232h-module-swd.cfg -f target/nordic/nrf52.cfg' instead" + source [find interface/ftdi/ft232h-module-swd.cfg] #source [find interface/ftdi/minimodule-swd.cfg] transport select swd -source [find target/nrf52.cfg] +source [find target/nordic/nrf52.cfg] diff --git a/tcl/board/numato_mimas_a7.cfg b/tcl/board/numato_mimas_a7.cfg index 82d6a561b2..0a357a64f8 100644 --- a/tcl/board/numato_mimas_a7.cfg +++ b/tcl/board/numato_mimas_a7.cfg @@ -10,8 +10,8 @@ # Therefore, prefer external power supply. adapter driver ftdi -ftdi device_desc "Mimas Artix 7 FPGA Module" -ftdi vid_pid 0x2a19 0x1009 +adapter usb product_name "Mimas Artix 7 FPGA Module" +adapter usb 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) diff --git a/tcl/board/orange_pi_zero_3.cfg b/tcl/board/orange_pi_zero_3.cfg new file mode 100644 index 0000000000..2af983c650 --- /dev/null +++ b/tcl/board/orange_pi_zero_3.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Orange Pi Zero 3 board with Allwinner H618 chip +# http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-Zero-3.html +# +# Accessing JTAG signals on Orange Pi Zero 3 board requires connection to pins +# on the microSD card slot. +# 1 - DAT2 - TCK +# 2 - CD/DAT3 - NC +# 3 - CMD - TDO +# 4 - VDD - NC +# 5 - CLK - NC +# 6 - VSS - NC +# 7 - DAT0 - TDI +# 8 - DAT1 - TMS +# +# PF Configure Register 0 at address 0x0300b0b4 must be set 0x07373733 to set +# the JTAG function on these pins (which is what the factory installed image on +# the SPI flash does when the board is powered without a microSD inserted). + +source [find target/allwinner_h618.cfg] + +# To this contributor's knowledge, the board neither exposes TRST nor SRST. +reset_config none diff --git a/tcl/board/phone_se_j100i.cfg b/tcl/board/phone_se_j100i.cfg index 70387ee154..09ea703c84 100644 --- a/tcl/board/phone_se_j100i.cfg +++ b/tcl/board/phone_se_j100i.cfg @@ -6,7 +6,7 @@ # more information can be found on # http://bb.osmocom.org/trac/wiki/SonyEricssonJ100i # -source [find target/ti_calypso.cfg] +source [find target/ti/calypso.cfg] # external flash diff --git a/tcl/board/pico-debug.cfg b/tcl/board/pico-debug.cfg index ba59f860a3..8139663f23 100644 --- a/tcl/board/pico-debug.cfg +++ b/tcl/board/pico-debug.cfg @@ -6,5 +6,5 @@ source [find interface/cmsis-dap.cfg] adapter speed 4000 -set CHIPNAME rp2040 -source [find target/rp2040-core0.cfg] +set USE_CORE 0 +source [find target/rp2040.cfg] diff --git a/tcl/board/pico2-debug.cfg b/tcl/board/pico2-debug.cfg new file mode 100644 index 0000000000..d0a4c6af5a --- /dev/null +++ b/tcl/board/pico2-debug.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# pico2-debug is a virtual CMSIS-DAP debug adapter +# it runs on the very same RP2350 target being debugged without additional hardware +# https://github.com/majbthrd/pico2-debug + +source [find interface/cmsis-dap.cfg] +adapter speed 4000 + +set USE_CORE 0 +source [find target/rp2350.cfg] diff --git a/tcl/board/quark_d2000_refboard.cfg b/tcl/board/quark_d2000_refboard.cfg index 3af5735a8b..7887d06c1d 100644 --- a/tcl/board/quark_d2000_refboard.cfg +++ b/tcl/board/quark_d2000_refboard.cfg @@ -4,7 +4,7 @@ # the board has an onboard FTDI FT232H chip adapter driver ftdi -ftdi vid_pid 0x0403 0x6014 +adapter usb vid_pid 0x0403 0x6014 ftdi channel 0 ftdi layout_init 0x0000 0x030b diff --git a/tcl/board/rpi3.cfg b/tcl/board/rpi3.cfg index fd93a9d9d8..a08bfeb12e 100644 --- a/tcl/board/rpi3.cfg +++ b/tcl/board/rpi3.cfg @@ -1,10 +1,10 @@ # 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 +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2837 # # Enable JTAG GPIO on Raspberry Pi boards -# https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md +# https://www.raspberrypi.com/documentation/computers/legacy_config_txt.html#enable_jtag_gpio source [find target/bcm2837.cfg] transport select jtag diff --git a/tcl/board/rpi4b.cfg b/tcl/board/rpi4b.cfg index 5b046af7b5..7d937e8c05 100644 --- a/tcl/board/rpi4b.cfg +++ b/tcl/board/rpi4b.cfg @@ -1,10 +1,10 @@ # 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 +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2711 # # Enable JTAG GPIO on Raspberry Pi boards -# https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md +# https://www.raspberrypi.com/documentation/computers/legacy_config_txt.html#enable_jtag_gpio source [find target/bcm2711.cfg] transport select jtag diff --git a/tcl/board/sayma_amc.cfg b/tcl/board/sayma_amc.cfg index b714609221..665bd3153f 100644 --- a/tcl/board/sayma_amc.cfg +++ b/tcl/board/sayma_amc.cfg @@ -13,8 +13,8 @@ # which features an Artix 7 FPGA. adapter driver ftdi -ftdi device_desc "Quad RS232-HS" -ftdi vid_pid 0x0403 0x6011 +adapter usb product_name "Quad RS232-HS" +adapter usb vid_pid 0x0403 0x6011 ftdi channel 0 # Use this to distinguish multiple boards by topology #adapter usb location 5:1 diff --git a/tcl/board/sifive-e31arty-cjtag.cfg b/tcl/board/sifive-e31arty-cjtag.cfg deleted file mode 100644 index 58ba23a509..0000000000 --- a/tcl/board/sifive-e31arty-cjtag.cfg +++ /dev/null @@ -1,23 +0,0 @@ -# -# Be sure you include the speed and interface before this file -# Example: -# -c "adapter_khz 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e31arty-cjtag.cfg" - -set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000913 - - -set _TARGETNAME $_CHIPNAME.cpu - -target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME -$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 - -flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 -init -if {[ info exists pulse_srst]} { - oscan1_ftdi_set_signal nSRST 0 - oscan1_ftdi_set_signal nSRST z -} -halt -flash protect 0 64 last off -echo "Ready for Remote Connections" diff --git a/tcl/board/sifive-e31arty-onboard-ftdi.cfg b/tcl/board/sifive-e31arty-onboard-ftdi.cfg deleted file mode 100644 index 3d40cfa04c..0000000000 --- a/tcl/board/sifive-e31arty-onboard-ftdi.cfg +++ /dev/null @@ -1,25 +0,0 @@ -# -# Be sure you include the speed and interface before this file -# Example: -# -c "adapter_khz 5000" -f "interface/ftdi/arty-onboard-ftdi.cfg" -f "board/sifive-e31arty-onboard-ftdi.cfg" - -set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 6; # -expected-id 0x0362d093 - -set _TARGETNAME $_CHIPNAME.cpu - -target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME -$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 -riscv use_bscan_tunnel 5 - -# Uncomment if hardware has flash -# 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 -} -halt -# Uncomment if hardware has flash -# flash protect 0 64 last off -echo "Ready for Remote Connections" diff --git a/tcl/board/sifive-e31arty.cfg b/tcl/board/sifive/e31-arty.cfg similarity index 94% rename from tcl/board/sifive-e31arty.cfg rename to tcl/board/sifive/e31-arty.cfg index b3e980f408..bdf79dae61 100644 --- a/tcl/board/sifive-e31arty.cfg +++ b/tcl/board/sifive/e31-arty.cfg @@ -3,7 +3,7 @@ # # Be sure you include the speed and interface before this file # Example: -# -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e31arty.cfg" +# -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive/e31-arty.cfg" set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 diff --git a/tcl/board/sifive-e51arty.cfg b/tcl/board/sifive/e51-arty.cfg similarity index 94% rename from tcl/board/sifive-e51arty.cfg rename to tcl/board/sifive/e51-arty.cfg index 3133c39023..1476d503e2 100644 --- a/tcl/board/sifive-e51arty.cfg +++ b/tcl/board/sifive/e51-arty.cfg @@ -3,7 +3,7 @@ # # Be sure you include the speed and interface before this file # Example: -# -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e51arty.cfg" +# -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive/e51-arty.cfg" set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 diff --git a/tcl/board/sifive-hifive1-revb.cfg b/tcl/board/sifive/hifive1-rev-b.cfg similarity index 89% rename from tcl/board/sifive-hifive1-revb.cfg rename to tcl/board/sifive/hifive1-rev-b.cfg index 7fcab0c63a..e5fe104ac8 100644 --- a/tcl/board/sifive-hifive1-revb.cfg +++ b/tcl/board/sifive/hifive1-rev-b.cfg @@ -12,9 +12,6 @@ set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME $_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 0x4000 -work-area-backup 0 -riscv set_enable_virt2phys off -riscv set_enable_virtual off - flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME.0 init diff --git a/tcl/board/sifive-hifive1.cfg b/tcl/board/sifive/hifive1.cfg similarity index 92% rename from tcl/board/sifive-hifive1.cfg rename to tcl/board/sifive/hifive1.cfg index f69dc4fcc0..fbe0961790 100644 --- a/tcl/board/sifive-hifive1.cfg +++ b/tcl/board/sifive/hifive1.cfg @@ -3,8 +3,8 @@ adapter speed 10000 adapter driver ftdi -ftdi device_desc "Dual RS232-HS" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Dual RS232-HS" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x001b ftdi layout_signal nSRST -oe 0x0020 -data 0x0020 diff --git a/tcl/board/silabs/fg23-dk2600a.cfg b/tcl/board/silabs/fg23-dk2600a.cfg new file mode 100644 index 0000000000..572756c9cc --- /dev/null +++ b/tcl/board/silabs/fg23-dk2600a.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# EFR32FG23 868-915 MHz +14 dBm Dev Kit +# https://www.silabs.com/development-tools/wireless/proprietary/efr32fg23-868-915-mhz-14-dbm-dev-kit + +source [find interface/jlink.cfg] + +transport select swd + +source [find target/silabs/xg23.cfg] diff --git a/tcl/board/silabs/pg23-pk2504a.cfg b/tcl/board/silabs/pg23-pk2504a.cfg new file mode 100644 index 0000000000..240ab5de55 --- /dev/null +++ b/tcl/board/silabs/pg23-pk2504a.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# EFM32PG23 Pro Kit +# https://www.silabs.com/development-tools/mcu/32-bit/efm32pg23-pro-kit + +source [find interface/jlink.cfg] + +transport select swd + +source [find target/silabs/xg23.cfg] diff --git a/tcl/board/silabs/pg28-pk2506a.cfg b/tcl/board/silabs/pg28-pk2506a.cfg new file mode 100644 index 0000000000..13f6f767da --- /dev/null +++ b/tcl/board/silabs/pg28-pk2506a.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# EFM32PG28 Pro Kit +# https://www.silabs.com/development-tools/mcu/32-bit/efm32pg28-pro-kit + +source [find interface/jlink.cfg] + +transport select swd + +source [find target/silabs/xg28.cfg] diff --git a/tcl/board/silabs/xg24-ek2703a.cfg b/tcl/board/silabs/xg24-ek2703a.cfg new file mode 100644 index 0000000000..16260c808a --- /dev/null +++ b/tcl/board/silabs/xg24-ek2703a.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# EFR32xG24 Explorer Kit +# https://www.silabs.com/development-tools/wireless/efr32xg24-explorer-kit + +source [find interface/jlink.cfg] + +transport select swd + +source [find target/silabs/xg24.cfg] diff --git a/tcl/board/st_nucleo_l5.cfg b/tcl/board/st/nucleo-l552ze-q.cfg similarity index 65% rename from tcl/board/st_nucleo_l5.cfg rename to tcl/board/st/nucleo-l552ze-q.cfg index f3cb680c25..de5ce173f4 100644 --- a/tcl/board/st_nucleo_l5.cfg +++ b/tcl/board/st/nucleo-l552ze-q.cfg @@ -1,7 +1,7 @@ # 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 +# NUCLEO-L552ZE-Q +# https://www.st.com/en/evaluation-tools/nucleo-l552ze-q.html source [find interface/stlink.cfg] diff --git a/tcl/board/st/nucleo-u083rc.cfg b/tcl/board/st/nucleo-u083rc.cfg index 03e9569305..eff0cf28a6 100644 --- a/tcl/board/st/nucleo-u083rc.cfg +++ b/tcl/board/st/nucleo-u083rc.cfg @@ -5,8 +5,6 @@ source [find interface/stlink.cfg] -transport select swd - source [find target/stm32u0x.cfg] reset_config srst_only diff --git a/tcl/board/st/nucleo-u3c5zi-q.cfg b/tcl/board/st/nucleo-u3c5zi-q.cfg new file mode 100644 index 0000000000..21b8439c1a --- /dev/null +++ b/tcl/board/st/nucleo-u3c5zi-q.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# NUCLEO-U3C5ZI-Q +# https://www.st.com/en/evaluation-tools/nucleo-u3c5zi-q.html + +source [find interface/stlink.cfg] + +transport select swd + +source [find target/stm32u3x.cfg] + +reset_config srst_only diff --git a/tcl/board/st/nucleo-u575zi-q.cfg b/tcl/board/st/nucleo-u575zi-q.cfg new file mode 100644 index 0000000000..acc548a2a6 --- /dev/null +++ b/tcl/board/st/nucleo-u575zi-q.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# NUCLEO-U575ZI-Q +# https://www.st.com/en/evaluation-tools/nucleo-u575zi-q.html + +source [find interface/stlink.cfg] + +transport select swd + +source [find target/stm32u5x.cfg] + +reset_config srst_only diff --git a/tcl/board/stm32mp13x_dk.cfg b/tcl/board/st/stm32mp135f-dk.cfg similarity index 83% rename from tcl/board/stm32mp13x_dk.cfg rename to tcl/board/st/stm32mp135f-dk.cfg index 8ece24844c..2259e0425b 100644 --- a/tcl/board/stm32mp13x_dk.cfg +++ b/tcl/board/st/stm32mp135f-dk.cfg @@ -7,6 +7,6 @@ source [find interface/stlink.cfg] transport select swd -source [find target/stm32mp13x.cfg] +source [find target/st/stm32mp13x.cfg] reset_config srst_only diff --git a/tcl/board/stm32mp15x_dk2.cfg b/tcl/board/st/stm32mp157f-dk2.cfg similarity index 72% rename from tcl/board/stm32mp15x_dk2.cfg rename to tcl/board/st/stm32mp157f-dk2.cfg index ba1c7f78a6..b193ae3a0c 100644 --- a/tcl/board/stm32mp15x_dk2.cfg +++ b/tcl/board/st/stm32mp157f-dk2.cfg @@ -3,11 +3,12 @@ # board MB1272B # http://www.st.com/en/evaluation-tools/stm32mp157a-dk1.html # http://www.st.com/en/evaluation-tools/stm32mp157c-dk2.html +# http://www.st.com/en/evaluation-tools/stm32mp157f-dk2.html source [find interface/stlink.cfg] transport select swd -source [find target/stm32mp15x.cfg] +source [find target/st/stm32mp15x.cfg] reset_config srst_only diff --git a/tcl/board/st/stm32mp235f-dk.cfg b/tcl/board/st/stm32mp235f-dk.cfg new file mode 100644 index 0000000000..1f660f19ed --- /dev/null +++ b/tcl/board/st/stm32mp235f-dk.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# MB1605 with stm32mp23x +# https://www.st.com/en/evaluation-tools/stm32mp257f-dk.html + +source [find interface/stlink.cfg] + +transport select swd + +source [find target/st/stm32mp23x.cfg] + +reset_config srst_only diff --git a/tcl/board/st/stm32mp257f-dk.cfg b/tcl/board/st/stm32mp257f-dk.cfg new file mode 100644 index 0000000000..182f1d00ce --- /dev/null +++ b/tcl/board/st/stm32mp257f-dk.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# MB1605 +# https://www.st.com/en/evaluation-tools/stm32mp257f-dk.html + +source [find interface/stlink.cfg] + +transport select swd + +source [find target/st/stm32mp25x.cfg] + +reset_config srst_only diff --git a/tcl/board/st_nucleo_c0.cfg b/tcl/board/st_nucleo_c0.cfg index 845b7b50e9..a4c0c4f423 100644 --- a/tcl/board/st_nucleo_c0.cfg +++ b/tcl/board/st_nucleo_c0.cfg @@ -2,8 +2,6 @@ source [find interface/stlink.cfg] -transport select swd - source [find target/stm32c0x.cfg] reset_config srst_only diff --git a/tcl/board/st_nucleo_f0.cfg b/tcl/board/st_nucleo_f0.cfg index 4d80711275..975ea34a9f 100644 --- a/tcl/board/st_nucleo_f0.cfg +++ b/tcl/board/st_nucleo_f0.cfg @@ -10,8 +10,6 @@ source [find interface/stlink.cfg] -transport select swd - source [find target/stm32f0x.cfg] reset_config srst_only diff --git a/tcl/board/st_nucleo_g0.cfg b/tcl/board/st_nucleo_g0.cfg index c68d3d0e5a..39036271ed 100644 --- a/tcl/board/st_nucleo_g0.cfg +++ b/tcl/board/st_nucleo_g0.cfg @@ -12,8 +12,6 @@ source [find interface/stlink.cfg] -transport select swd - source [find target/stm32g0x.cfg] reset_config srst_only diff --git a/tcl/board/stm320518_eval_stlink.cfg b/tcl/board/stm320518_eval_stlink.cfg index 8f4652eff9..d97ecaa114 100644 --- a/tcl/board/stm320518_eval_stlink.cfg +++ b/tcl/board/stm320518_eval_stlink.cfg @@ -8,8 +8,6 @@ source [find interface/stlink.cfg] -transport select swd - # increase working area to 8KB set WORKAREASIZE 0x2000 diff --git a/tcl/board/stm32f0discovery.cfg b/tcl/board/stm32f0discovery.cfg index 9a8e921538..e58ab156ec 100644 --- a/tcl/board/stm32f0discovery.cfg +++ b/tcl/board/stm32f0discovery.cfg @@ -5,8 +5,6 @@ source [find interface/stlink.cfg] -transport select swd - set WORKAREASIZE 0x2000 source [find target/stm32f0x.cfg] diff --git a/tcl/board/stm32l0discovery.cfg b/tcl/board/stm32l0discovery.cfg index 06d02ed024..2708fc3aea 100644 --- a/tcl/board/stm32l0discovery.cfg +++ b/tcl/board/stm32l0discovery.cfg @@ -5,8 +5,6 @@ source [find interface/stlink.cfg] -transport select swd - set WORKAREASIZE 0x2000 source [find target/stm32l0.cfg] diff --git a/tcl/board/ti_am243_launchpad.cfg b/tcl/board/ti/am243-launchpad.cfg similarity index 94% rename from tcl/board/ti_am243_launchpad.cfg rename to tcl/board/ti/am243-launchpad.cfg index aa75dda888..6833cdd677 100644 --- a/tcl/board/ti_am243_launchpad.cfg +++ b/tcl/board/ti/am243-launchpad.cfg @@ -20,6 +20,6 @@ if { ![info exists SOC] } { set SOC am243 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 250 diff --git a/tcl/board/ti_am261_launchpad.cfg b/tcl/board/ti/am261-launchpad.cfg similarity index 94% rename from tcl/board/ti_am261_launchpad.cfg rename to tcl/board/ti/am261-launchpad.cfg index c6c4609ed1..0a99d8b1ec 100644 --- a/tcl/board/ti_am261_launchpad.cfg +++ b/tcl/board/ti/am261-launchpad.cfg @@ -20,6 +20,6 @@ if { ![info exists SOC] } { set SOC am261 } -source [find target/ti_k3.cfg] +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 similarity index 94% rename from tcl/board/ti_am263_launchpad.cfg rename to tcl/board/ti/am263-launchpad.cfg index a07a21b3d5..7d603d386a 100644 --- a/tcl/board/ti_am263_launchpad.cfg +++ b/tcl/board/ti/am263-launchpad.cfg @@ -20,6 +20,6 @@ if { ![info exists SOC] } { set SOC am263 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 250 diff --git a/tcl/board/ti_am263p_launchpad.cfg b/tcl/board/ti/am263p-launchpad.cfg similarity index 94% rename from tcl/board/ti_am263p_launchpad.cfg rename to tcl/board/ti/am263p-launchpad.cfg index 96e06fab6b..25ae80d63b 100644 --- a/tcl/board/ti_am263p_launchpad.cfg +++ b/tcl/board/ti/am263p-launchpad.cfg @@ -20,6 +20,6 @@ if { ![info exists SOC] } { set SOC am263p } -source [find target/ti_k3.cfg] +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 similarity index 94% rename from tcl/board/ti_am273_launchpad.cfg rename to tcl/board/ti/am273-launchpad.cfg index c17170bf13..6f10b6b624 100644 --- a/tcl/board/ti_am273_launchpad.cfg +++ b/tcl/board/ti/am273-launchpad.cfg @@ -20,6 +20,6 @@ if { ![info exists SOC] } { set SOC am273 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 250 diff --git a/tcl/board/ti_am335xevm.cfg b/tcl/board/ti/am335xevm.cfg similarity index 84% rename from tcl/board/ti_am335xevm.cfg rename to tcl/board/ti/am335xevm.cfg index af058ecf70..cc64d5877b 100644 --- a/tcl/board/ti_am335xevm.cfg +++ b/tcl/board/ti/am335xevm.cfg @@ -7,6 +7,6 @@ # jtag_rclk 6000 -source [find target/am335x.cfg] +source [find target/ti/am335x.cfg] reset_config trst_and_srst diff --git a/tcl/board/am3517evm.cfg b/tcl/board/ti/am3517evm.cfg similarity index 94% rename from tcl/board/am3517evm.cfg rename to tcl/board/ti/am3517evm.cfg index 0b19be68bc..c76516608c 100644 --- a/tcl/board/am3517evm.cfg +++ b/tcl/board/ti/am3517evm.cfg @@ -13,7 +13,7 @@ # http://processors.wiki.ti.com/index.php?title=How_to_Find_the_Silicon_Revision_of_your_OMAP35x set CHIPTYPE "am35x" -source [find target/amdm37x.cfg] +source [find target/ti/amdm37x.cfg] # The TI-14 JTAG connector does not have srst. CPU reset is handled in # hardware. diff --git a/tcl/board/ti_am437x_idk.cfg b/tcl/board/ti/am437x-idk.cfg similarity index 90% rename from tcl/board/ti_am437x_idk.cfg rename to tcl/board/ti/am437x-idk.cfg index b4277628ee..30f2580f62 100644 --- a/tcl/board/ti_am437x_idk.cfg +++ b/tcl/board/ti/am437x-idk.cfg @@ -8,7 +8,7 @@ source [find interface/ftdi/xds100v2.cfg] transport select jtag adapter speed 30000 -source [find target/am437x.cfg] +source [find target/ti/am437x.cfg] $_TARGETNAME configure -event reset-init { init_platform 0x61a11b32 } reset_config trst_and_srst diff --git a/tcl/board/ti_am43xx_evm.cfg b/tcl/board/ti/am43xx-evm.cfg similarity index 82% rename from tcl/board/ti_am43xx_evm.cfg rename to tcl/board/ti/am43xx-evm.cfg index 005421f423..1c39618203 100644 --- a/tcl/board/ti_am43xx_evm.cfg +++ b/tcl/board/ti/am43xx-evm.cfg @@ -4,6 +4,6 @@ transport select jtag adapter speed 16000 -source [find target/am437x.cfg] +source [find target/ti/am437x.cfg] reset_config trst_and_srst diff --git a/tcl/board/ti_am625_swd_native.cfg b/tcl/board/ti/am625-self-hosted.cfg similarity index 92% rename from tcl/board/ti_am625_swd_native.cfg rename to tcl/board/ti/am625-self-hosted.cfg index dc4b20579d..8891e021a9 100644 --- a/tcl/board/ti_am625_swd_native.cfg +++ b/tcl/board/ti/am625-self-hosted.cfg @@ -14,9 +14,10 @@ # We are using dmem, which uses dapdirect_swd transport adapter driver dmem +transport select swd if { ![info exists SOC] } { set SOC am625 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] diff --git a/tcl/board/ti_am625evm.cfg b/tcl/board/ti/am625evm.cfg similarity index 94% rename from tcl/board/ti_am625evm.cfg rename to tcl/board/ti/am625evm.cfg index 4906fd0967..2df13cdae1 100644 --- a/tcl/board/ti_am625evm.cfg +++ b/tcl/board/ti/am625evm.cfg @@ -20,6 +20,6 @@ if { ![info exists SOC] } { set SOC am625 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 2500 diff --git a/tcl/board/ti_am62a7_swd_native.cfg b/tcl/board/ti/am62a7-self-hosted.cfg similarity index 92% rename from tcl/board/ti_am62a7_swd_native.cfg rename to tcl/board/ti/am62a7-self-hosted.cfg index 99fc0b0b38..4d5512688e 100644 --- a/tcl/board/ti_am62a7_swd_native.cfg +++ b/tcl/board/ti/am62a7-self-hosted.cfg @@ -14,9 +14,10 @@ # We are using dmem, which uses dapdirect_swd transport adapter driver dmem +transport select swd if { ![info exists SOC] } { set SOC am62a7 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] diff --git a/tcl/board/ti_am62a7evm.cfg b/tcl/board/ti/am62a7evm.cfg similarity index 94% rename from tcl/board/ti_am62a7evm.cfg rename to tcl/board/ti/am62a7evm.cfg index e40790950b..1c90be8b16 100644 --- a/tcl/board/ti_am62a7evm.cfg +++ b/tcl/board/ti/am62a7evm.cfg @@ -20,6 +20,6 @@ if { ![info exists SOC] } { set SOC am62a7 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 2500 diff --git a/tcl/board/ti_am62levm.cfg b/tcl/board/ti/am62levm.cfg similarity index 94% rename from tcl/board/ti_am62levm.cfg rename to tcl/board/ti/am62levm.cfg index 6debdd49f4..53ac7a5a07 100644 --- a/tcl/board/ti_am62levm.cfg +++ b/tcl/board/ti/am62levm.cfg @@ -20,6 +20,6 @@ if { ![info exists SOC] } { set SOC am62l } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 2500 diff --git a/tcl/board/ti_am62p_swd_native.cfg b/tcl/board/ti/am62p-self-hosted.cfg similarity index 92% rename from tcl/board/ti_am62p_swd_native.cfg rename to tcl/board/ti/am62p-self-hosted.cfg index fa549f3585..55e6ea3d75 100644 --- a/tcl/board/ti_am62p_swd_native.cfg +++ b/tcl/board/ti/am62p-self-hosted.cfg @@ -14,9 +14,10 @@ # We are using dmem, which uses dapdirect_swd transport adapter driver dmem +transport select swd if { ![info exists SOC] } { set SOC am62p } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] diff --git a/tcl/board/ti_am62pevm.cfg b/tcl/board/ti/am62pevm.cfg similarity index 94% rename from tcl/board/ti_am62pevm.cfg rename to tcl/board/ti/am62pevm.cfg index 2322b3d943..6c7f99a33c 100644 --- a/tcl/board/ti_am62pevm.cfg +++ b/tcl/board/ti/am62pevm.cfg @@ -19,6 +19,6 @@ if { ![info exists SOC] } { set SOC am62p } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 2500 diff --git a/tcl/board/ti_am642evm.cfg b/tcl/board/ti/am642evm.cfg similarity index 93% rename from tcl/board/ti_am642evm.cfg rename to tcl/board/ti/am642evm.cfg index e97fdcf138..a6cfacd805 100644 --- a/tcl/board/ti_am642evm.cfg +++ b/tcl/board/ti/am642evm.cfg @@ -19,6 +19,6 @@ if { ![info exists SOC] } { set SOC am642 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 250 diff --git a/tcl/board/ti/am64xx-self-hosted.cfg b/tcl/board/ti/am64xx-self-hosted.cfg new file mode 100644 index 0000000000..65e9e7c56e --- /dev/null +++ b/tcl/board/ti/am64xx-self-hosted.cfg @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2022-2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments am642 +# Link: https://www.ti.com/product/AM642 +# +# This configuration file is used as a self hosted debug configuration that +# works on every AM642 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 +transport select swd + +if { ![info exists SOC] } { + set SOC am642 +} + +source [find target/ti/k3.cfg] diff --git a/tcl/board/ti_am654evm.cfg b/tcl/board/ti/am654evm.cfg similarity index 93% rename from tcl/board/ti_am654evm.cfg rename to tcl/board/ti/am654evm.cfg index a661f6068f..e812feb6cb 100644 --- a/tcl/board/ti_am654evm.cfg +++ b/tcl/board/ti/am654evm.cfg @@ -19,6 +19,6 @@ if { ![info exists SOC] } { set SOC am654 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 2500 diff --git a/tcl/board/ti_blaze.cfg b/tcl/board/ti/blaze.cfg similarity index 70% rename from tcl/board/ti_blaze.cfg rename to tcl/board/ti/blaze.cfg index e28b05b83a..e549035279 100644 --- a/tcl/board/ti_blaze.cfg +++ b/tcl/board/ti/blaze.cfg @@ -2,6 +2,6 @@ jtag_rclk 6000 -source [find target/omap4430.cfg] +source [find target/ti/omap4430.cfg] reset_config trst_and_srst diff --git a/tcl/board/ti_cc13x0_launchpad.cfg b/tcl/board/ti/cc13x0-launchpad.cfg similarity index 82% rename from tcl/board/ti_cc13x0_launchpad.cfg rename to tcl/board/ti/cc13x0-launchpad.cfg index f6dfbcda3d..e6904456c1 100644 --- a/tcl/board/ti_cc13x0_launchpad.cfg +++ b/tcl/board/ti/cc13x0-launchpad.cfg @@ -6,4 +6,4 @@ source [find interface/xds110.cfg] transport select jtag adapter speed 5500 -source [find target/ti_cc13x0.cfg] +source [find target/ti/cc13x0.cfg] diff --git a/tcl/board/ti_cc13x2_launchpad.cfg b/tcl/board/ti/cc13x2-launchpad.cfg similarity index 82% rename from tcl/board/ti_cc13x2_launchpad.cfg rename to tcl/board/ti/cc13x2-launchpad.cfg index 900842a2fd..1653224d1f 100644 --- a/tcl/board/ti_cc13x2_launchpad.cfg +++ b/tcl/board/ti/cc13x2-launchpad.cfg @@ -6,4 +6,4 @@ source [find interface/xds110.cfg] adapter speed 5500 transport select jtag -source [find target/ti_cc13x2.cfg] +source [find target/ti/cc13x2.cfg] diff --git a/tcl/board/ti_cc26x0_launchpad.cfg b/tcl/board/ti/cc26x0-launchpad.cfg similarity index 82% rename from tcl/board/ti_cc26x0_launchpad.cfg rename to tcl/board/ti/cc26x0-launchpad.cfg index 431383db1c..8e57cf2a43 100644 --- a/tcl/board/ti_cc26x0_launchpad.cfg +++ b/tcl/board/ti/cc26x0-launchpad.cfg @@ -6,4 +6,4 @@ source [find interface/xds110.cfg] adapter speed 5500 transport select jtag -source [find target/ti_cc26x0.cfg] +source [find target/ti/cc26x0.cfg] diff --git a/tcl/board/ti_cc26x2_launchpad.cfg b/tcl/board/ti/cc26x2-launchpad.cfg similarity index 82% rename from tcl/board/ti_cc26x2_launchpad.cfg rename to tcl/board/ti/cc26x2-launchpad.cfg index 133f57e07f..931270e21d 100644 --- a/tcl/board/ti_cc26x2_launchpad.cfg +++ b/tcl/board/ti/cc26x2-launchpad.cfg @@ -6,4 +6,4 @@ source [find interface/xds110.cfg] adapter speed 5500 transport select jtag -source [find target/ti_cc26x2.cfg] +source [find target/ti/cc26x2.cfg] diff --git a/tcl/board/ti_cc26x2x7_launchpad.cfg b/tcl/board/ti/cc26x2x7-launchpad.cfg similarity index 81% rename from tcl/board/ti_cc26x2x7_launchpad.cfg rename to tcl/board/ti/cc26x2x7-launchpad.cfg index 9e6e72e89c..c1b6e059a0 100644 --- a/tcl/board/ti_cc26x2x7_launchpad.cfg +++ b/tcl/board/ti/cc26x2x7-launchpad.cfg @@ -6,4 +6,4 @@ source [find interface/xds110.cfg] adapter speed 5500 transport select jtag -source [find target/ti_cc26x2x7.cfg] +source [find target/ti/cc26x2x7.cfg] diff --git a/tcl/board/ti_cc3200_launchxl.cfg b/tcl/board/ti/cc3200-launchxl.cfg similarity index 91% rename from tcl/board/ti_cc3200_launchxl.cfg rename to tcl/board/ti/cc3200-launchxl.cfg index 5f39b8a83f..ca78cd19e6 100644 --- a/tcl/board/ti_cc3200_launchxl.cfg +++ b/tcl/board/ti/cc3200-launchxl.cfg @@ -17,7 +17,7 @@ if { [info exists TRANSPORT] } { adapter speed 2500 set WORKAREASIZE 0x40000 -source [find target/ti_cc32xx.cfg] +source [find target/ti/cc32xx.cfg] reset_config srst_only adapter srst delay 1100 diff --git a/tcl/board/ti_cc3220sf_launchpad.cfg b/tcl/board/ti/cc3220sf-launchpad.cfg similarity index 82% rename from tcl/board/ti_cc3220sf_launchpad.cfg rename to tcl/board/ti/cc3220sf-launchpad.cfg index fe34554dfc..560e3ee259 100644 --- a/tcl/board/ti_cc3220sf_launchpad.cfg +++ b/tcl/board/ti/cc3220sf-launchpad.cfg @@ -6,4 +6,4 @@ source [find interface/xds110.cfg] adapter speed 8500 transport select swd -source [find target/ti_cc3220sf.cfg] +source [find target/ti/cc3220sf.cfg] diff --git a/tcl/board/ti_cc32xx_launchpad.cfg b/tcl/board/ti/cc32xx-launchpad.cfg similarity index 86% rename from tcl/board/ti_cc32xx_launchpad.cfg rename to tcl/board/ti/cc32xx-launchpad.cfg index 343da485d3..41da72c3cc 100644 --- a/tcl/board/ti_cc32xx_launchpad.cfg +++ b/tcl/board/ti/cc32xx-launchpad.cfg @@ -6,7 +6,7 @@ source [find interface/xds110.cfg] adapter speed 8500 transport select swd -source [find target/ti_cc32xx.cfg] +source [find target/ti/cc32xx.cfg] reset_config srst_only adapter srst delay 1100 diff --git a/tcl/board/da850evm.cfg b/tcl/board/ti/da850evm.cfg similarity index 78% rename from tcl/board/da850evm.cfg rename to tcl/board/ti/da850evm.cfg index 12de3a7e38..eff7cf4e8f 100644 --- a/tcl/board/da850evm.cfg +++ b/tcl/board/ti/da850evm.cfg @@ -4,9 +4,9 @@ # 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 -source [find target/omapl138.cfg] +source [find target/ti/omapl138.cfg] reset_config trst_and_srst separate #currently any pinmux/timing must be setup by UBL before openocd can do debug -#TODO: implement pinmux/timing on reset like in board/dm365evm.cfg +#TODO: implement pinmux/timing on reset like in board/ti/dm365evm.cfg diff --git a/tcl/board/ti_dk-tm4c129.cfg b/tcl/board/ti/dk-tm4c129.cfg similarity index 86% rename from tcl/board/ti_dk-tm4c129.cfg rename to tcl/board/ti/dk-tm4c129.cfg index e0574fa870..d01b559668 100644 --- a/tcl/board/ti_dk-tm4c129.cfg +++ b/tcl/board/ti/dk-tm4c129.cfg @@ -13,4 +13,4 @@ transport select jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c129xnczad -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/dm355evm.cfg b/tcl/board/ti/dm355evm.cfg similarity index 99% rename from tcl/board/dm355evm.cfg rename to tcl/board/ti/dm355evm.cfg index 0dbffa8395..d7102b372e 100644 --- a/tcl/board/dm355evm.cfg +++ b/tcl/board/ti/dm355evm.cfg @@ -4,7 +4,7 @@ # http://focus.ti.com/docs/toolsw/folders/print/tmdsevm355.html # http://c6000.spectrumdigital.com/evmdm355/ -source [find target/ti_dm355.cfg] +source [find target/ti/dm355.cfg] reset_config trst_and_srst separate diff --git a/tcl/board/dm365evm.cfg b/tcl/board/ti/dm365evm.cfg similarity index 99% rename from tcl/board/dm365evm.cfg rename to tcl/board/ti/dm365evm.cfg index 15db24c204..113a4a3d1a 100644 --- a/tcl/board/dm365evm.cfg +++ b/tcl/board/ti/dm365evm.cfg @@ -4,7 +4,7 @@ # http://focus.ti.com/docs/toolsw/folders/print/tmdxevm365.html # http://support.spectrumdigital.com/boards/evmdm365 -source [find target/ti_dm365.cfg] +source [find target/ti/dm365.cfg] # NOTE: in Rev C boards, the CPLD ignores SRST from the ARM-20 JTAG # connector, so it doesn't affect generation of the reset signal. diff --git a/tcl/board/dm6446evm.cfg b/tcl/board/ti/dm6446evm.cfg similarity index 98% rename from tcl/board/dm6446evm.cfg rename to tcl/board/ti/dm6446evm.cfg index 1236b86228..7f1b5b0522 100644 --- a/tcl/board/dm6446evm.cfg +++ b/tcl/board/ti/dm6446evm.cfg @@ -6,7 +6,7 @@ # EVM is just the board; buy that at Spectrum. # The "kit" from TI also has: video camera, LCD video monitor, more. -source [find target/ti_dm6446.cfg] +source [find target/ti/dm6446.cfg] # J4 controls what CS2 hooks up to, usually NOR or NAND flash. # S3.1/S3.2 controls boot mode, which may force J4 and S3.3 settings. diff --git a/tcl/board/ek-lm3s1968.cfg b/tcl/board/ti/ek-lm3s1968.cfg similarity index 93% rename from tcl/board/ek-lm3s1968.cfg rename to tcl/board/ti/ek-lm3s1968.cfg index c794a17a01..3828653400 100644 --- a/tcl/board/ek-lm3s1968.cfg +++ b/tcl/board/ti/ek-lm3s1968.cfg @@ -18,4 +18,4 @@ source [find interface/ftdi/luminary.cfg] # include the target config set WORKAREASIZE 0x2000 set CHIPNAME lm3s1968 -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ek-lm3s3748.cfg b/tcl/board/ti/ek-lm3s3748.cfg similarity index 90% rename from tcl/board/ek-lm3s3748.cfg rename to tcl/board/ti/ek-lm3s3748.cfg index 705cb64ce0..c72af120f6 100644 --- a/tcl/board/ek-lm3s3748.cfg +++ b/tcl/board/ti/ek-lm3s3748.cfg @@ -13,4 +13,4 @@ source [find interface/ftdi/luminary.cfg] # 20k working area set WORKAREASIZE 0x4000 set CHIPNAME lm3s3748 -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ek-lm3s6965.cfg b/tcl/board/ti/ek-lm3s6965.cfg similarity index 91% rename from tcl/board/ek-lm3s6965.cfg rename to tcl/board/ti/ek-lm3s6965.cfg index ee4e15f8a8..3ce2c5167b 100644 --- a/tcl/board/ek-lm3s6965.cfg +++ b/tcl/board/ti/ek-lm3s6965.cfg @@ -14,4 +14,4 @@ source [find interface/ftdi/luminary.cfg] set WORKAREASIZE 0x5000 set CHIPNAME lm3s6965 # include the target config -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ek-lm3s811-revb.cfg b/tcl/board/ti/ek-lm3s811-revb.cfg similarity index 83% rename from tcl/board/ek-lm3s811-revb.cfg rename to tcl/board/ti/ek-lm3s811-revb.cfg index f968eece5f..baa4d63ab8 100644 --- a/tcl/board/ek-lm3s811-revb.cfg +++ b/tcl/board/ti/ek-lm3s811-revb.cfg @@ -7,10 +7,10 @@ # # NOTE: newer 811-EK boards (rev C and above) shouldn't use this. -# use board/ek-lm3s811.cfg +# use board/ti/ek-lm3s811.cfg source [find interface/ftdi/luminary-lm3s811.cfg] # include the target config set WORKAREASIZE 0x2000 set CHIPNAME lm3s811 -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ek-lm3s811.cfg b/tcl/board/ti/ek-lm3s811.cfg similarity index 91% rename from tcl/board/ek-lm3s811.cfg rename to tcl/board/ti/ek-lm3s811.cfg index 0cf36c2843..9a36221ea1 100644 --- a/tcl/board/ek-lm3s811.cfg +++ b/tcl/board/ti/ek-lm3s811.cfg @@ -14,4 +14,4 @@ source [find interface/ftdi/luminary.cfg] # include the target config set WORKAREASIZE 0x2000 set CHIPNAME lm3s811 -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ek-lm3s8962.cfg b/tcl/board/ti/ek-lm3s8962.cfg similarity index 91% rename from tcl/board/ek-lm3s8962.cfg rename to tcl/board/ti/ek-lm3s8962.cfg index 71a1b1090c..f58147edde 100644 --- a/tcl/board/ek-lm3s8962.cfg +++ b/tcl/board/ti/ek-lm3s8962.cfg @@ -14,4 +14,4 @@ source [find interface/ftdi/luminary.cfg] set WORKAREASIZE 0x10000 set CHIPNAME lm3s8962 # include the target config -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ek-lm3s9b9x.cfg b/tcl/board/ti/ek-lm3s9b9x.cfg similarity index 90% rename from tcl/board/ek-lm3s9b9x.cfg rename to tcl/board/ti/ek-lm3s9b9x.cfg index 289a2cc091..b823b56cdd 100644 --- a/tcl/board/ek-lm3s9b9x.cfg +++ b/tcl/board/ti/ek-lm3s9b9x.cfg @@ -13,4 +13,4 @@ source [find interface/ftdi/luminary-icdi.cfg] set WORKAREASIZE 0x4000 set CHIPNAME lm3s9b9x -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ek-lm3s9d92.cfg b/tcl/board/ti/ek-lm3s9d92.cfg similarity index 90% rename from tcl/board/ek-lm3s9d92.cfg rename to tcl/board/ti/ek-lm3s9d92.cfg index 08bbbdb586..9f4dcaa35c 100644 --- a/tcl/board/ek-lm3s9d92.cfg +++ b/tcl/board/ti/ek-lm3s9d92.cfg @@ -13,4 +13,4 @@ source [find interface/ftdi/luminary-icdi.cfg] # 64k working area set WORKAREASIZE 0x10000 set CHIPNAME lm3s9d92 -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ek-lm4f120xl.cfg b/tcl/board/ti/ek-lm4f120xl.cfg similarity index 90% rename from tcl/board/ek-lm4f120xl.cfg rename to tcl/board/ti/ek-lm4f120xl.cfg index 44b1b1ea12..b1ab986680 100644 --- a/tcl/board/ek-lm4f120xl.cfg +++ b/tcl/board/ti/ek-lm4f120xl.cfg @@ -16,4 +16,4 @@ transport select jtag set WORKAREASIZE 0x8000 set CHIPNAME lm4f120h5qr -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ek-lm4f232.cfg b/tcl/board/ti/ek-lm4f232.cfg similarity index 90% rename from tcl/board/ek-lm4f232.cfg rename to tcl/board/ti/ek-lm4f232.cfg index bb7f9ea5b0..1fd05bb753 100644 --- a/tcl/board/ek-lm4f232.cfg +++ b/tcl/board/ti/ek-lm4f232.cfg @@ -16,4 +16,4 @@ transport select jtag set WORKAREASIZE 0x8000 set CHIPNAME lm4f23x -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ti_ek-tm4c123gxl.cfg b/tcl/board/ti/ek-tm4c123gxl.cfg similarity index 87% rename from tcl/board/ti_ek-tm4c123gxl.cfg rename to tcl/board/ti/ek-tm4c123gxl.cfg index 7b8fc267f5..2d1c1a7712 100644 --- a/tcl/board/ti_ek-tm4c123gxl.cfg +++ b/tcl/board/ti/ek-tm4c123gxl.cfg @@ -12,4 +12,4 @@ transport select jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c123gh6pm -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ti_ek-tm4c1294xl.cfg b/tcl/board/ti/ek-tm4c1294xl.cfg similarity index 87% rename from tcl/board/ti_ek-tm4c1294xl.cfg rename to tcl/board/ti/ek-tm4c1294xl.cfg index 8cceb49c96..38e8f023b0 100644 --- a/tcl/board/ti_ek-tm4c1294xl.cfg +++ b/tcl/board/ti/ek-tm4c1294xl.cfg @@ -13,4 +13,4 @@ transport select jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c1294ncpdt -source [find target/stellaris.cfg] +source [find target/ti/stellaris.cfg] diff --git a/tcl/board/ti_j7200evm.cfg b/tcl/board/ti/j7200evm.cfg similarity index 93% rename from tcl/board/ti_j7200evm.cfg rename to tcl/board/ti/j7200evm.cfg index cc70056fb4..7edeb36785 100644 --- a/tcl/board/ti_j7200evm.cfg +++ b/tcl/board/ti/j7200evm.cfg @@ -19,6 +19,6 @@ if { ![info exists SOC] } { set SOC j7200 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 2500 diff --git a/tcl/board/ti_j721e_swd_native.cfg b/tcl/board/ti/j721e-self-hosted.cfg similarity index 93% rename from tcl/board/ti_j721e_swd_native.cfg rename to tcl/board/ti/j721e-self-hosted.cfg index 3041c3c345..7b3f6060f1 100644 --- a/tcl/board/ti_j721e_swd_native.cfg +++ b/tcl/board/ti/j721e-self-hosted.cfg @@ -14,8 +14,9 @@ # We are using dmem, which uses dapdirect_swd transport adapter driver dmem +transport select swd if { ![info exists SOC] } { set SOC j721e } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] diff --git a/tcl/board/ti_j721evm.cfg b/tcl/board/ti/j721evm.cfg similarity index 93% rename from tcl/board/ti_j721evm.cfg rename to tcl/board/ti/j721evm.cfg index d0c4b74965..92e88234ee 100644 --- a/tcl/board/ti_j721evm.cfg +++ b/tcl/board/ti/j721evm.cfg @@ -19,6 +19,6 @@ if { ![info exists SOC] } { set SOC j721e } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 2500 diff --git a/tcl/board/ti_j721s2evm.cfg b/tcl/board/ti/j721s2evm.cfg similarity index 94% rename from tcl/board/ti_j721s2evm.cfg rename to tcl/board/ti/j721s2evm.cfg index 72418b57b6..f8e12b8753 100644 --- a/tcl/board/ti_j721s2evm.cfg +++ b/tcl/board/ti/j721s2evm.cfg @@ -20,6 +20,6 @@ if { ![info exists SOC] } { set SOC j721s2 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 2500 diff --git a/tcl/board/ti_j722s_swd_native.cfg b/tcl/board/ti/j722s-self-hosted.cfg similarity index 93% rename from tcl/board/ti_j722s_swd_native.cfg rename to tcl/board/ti/j722s-self-hosted.cfg index bbe0d508c8..1bc60968c0 100644 --- a/tcl/board/ti_j722s_swd_native.cfg +++ b/tcl/board/ti/j722s-self-hosted.cfg @@ -15,9 +15,10 @@ # We are using dmem, which uses dapdirect_swd transport adapter driver dmem +transport select swd if { ![info exists SOC] } { set SOC j722s } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] diff --git a/tcl/board/ti_j722sevm.cfg b/tcl/board/ti/j722sevm.cfg similarity index 94% rename from tcl/board/ti_j722sevm.cfg rename to tcl/board/ti/j722sevm.cfg index 6a5c2d9cd9..c43e7abe5d 100644 --- a/tcl/board/ti_j722sevm.cfg +++ b/tcl/board/ti/j722sevm.cfg @@ -19,6 +19,6 @@ if { ![info exists SOC] } { set SOC j722s } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 2500 diff --git a/tcl/board/ti/j784s4-self-hosted.cfg b/tcl/board/ti/j784s4-self-hosted.cfg new file mode 100644 index 0000000000..dd534248f6 --- /dev/null +++ b/tcl/board/ti/j784s4-self-hosted.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 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 +transport select swd + +if { ![info exists SOC] } { + set SOC j784s4 +} +source [find target/ti/k3.cfg] diff --git a/tcl/board/ti_j784s4evm.cfg b/tcl/board/ti/j784s4evm.cfg similarity index 94% rename from tcl/board/ti_j784s4evm.cfg rename to tcl/board/ti/j784s4evm.cfg index d23dc8ce67..a8a5af2e0f 100644 --- a/tcl/board/ti_j784s4evm.cfg +++ b/tcl/board/ti/j784s4evm.cfg @@ -20,6 +20,6 @@ if { ![info exists SOC] } { set SOC j784s4 } -source [find target/ti_k3.cfg] +source [find target/ti/k3.cfg] adapter speed 2500 diff --git a/tcl/board/ti/launchxl2-tms57012.cfg b/tcl/board/ti/launchxl2-tms57012.cfg new file mode 100644 index 0000000000..ba305f6914 --- /dev/null +++ b/tcl/board/ti/launchxl2-tms57012.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Hercules TMS570LS12x LaunchPad Development Kit +# https://www.ti.com/tool/LAUNCHXL2-TMS57012 + +source [find interface/xds110.cfg] + +transport select jtag + +source [find target/ti/tms570ls1x.cfg] diff --git a/tcl/board/ti_msp432_launchpad.cfg b/tcl/board/ti/msp432-launchpad.cfg similarity index 82% rename from tcl/board/ti_msp432_launchpad.cfg rename to tcl/board/ti/msp432-launchpad.cfg index 4832b837b0..455d5a362e 100644 --- a/tcl/board/ti_msp432_launchpad.cfg +++ b/tcl/board/ti/msp432-launchpad.cfg @@ -6,4 +6,4 @@ source [find interface/xds110.cfg] adapter speed 10000 transport select swd -source [find target/ti_msp432.cfg] +source [find target/ti/msp432.cfg] diff --git a/tcl/board/ti_mspm0_launchpad.cfg b/tcl/board/ti/mspm0-launchpad.cfg similarity index 92% rename from tcl/board/ti_mspm0_launchpad.cfg rename to tcl/board/ti/mspm0-launchpad.cfg index 132fdc2a30..30632f2b5c 100644 --- a/tcl/board/ti_mspm0_launchpad.cfg +++ b/tcl/board/ti/mspm0-launchpad.cfg @@ -11,4 +11,4 @@ source [find interface/xds110.cfg] adapter speed 10000 -source [find target/ti_mspm0.cfg] +source [find target/ti/mspm0.cfg] diff --git a/tcl/board/omap2420_h4.cfg b/tcl/board/ti/omap2420-h4.cfg similarity index 92% rename from tcl/board/omap2420_h4.cfg rename to tcl/board/ti/omap2420-h4.cfg index ec169654fa..b3e9d7daba 100644 --- a/tcl/board/omap2420_h4.cfg +++ b/tcl/board/ti/omap2420-h4.cfg @@ -2,7 +2,7 @@ # OMAP2420 SDP board ("H4") -source [find target/omap2420.cfg] +source [find target/ti/omap2420.cfg] # NOTE: this assumes you're *NOT* using a TI-14 connector. reset_config trst_and_srst separate diff --git a/tcl/board/osk5912.cfg b/tcl/board/ti/osk5912.cfg similarity index 96% rename from tcl/board/osk5912.cfg rename to tcl/board/ti/osk5912.cfg index 0759a27ac0..1f94c67a28 100644 --- a/tcl/board/osk5912.cfg +++ b/tcl/board/ti/osk5912.cfg @@ -2,7 +2,7 @@ # http://omap.spectrumdigital.com/osk5912/ -source [find target/omap5912.cfg] +source [find target/ti/omap5912.cfg] # NOTE: this assumes you're using the ARM 20-pin ("Multi-ICE") # JTAG connector, and accordingly have J1 connecting pins 1 & 2. diff --git a/tcl/board/ti_pandaboard.cfg b/tcl/board/ti/pandaboard-es.cfg similarity index 69% rename from tcl/board/ti_pandaboard.cfg rename to tcl/board/ti/pandaboard-es.cfg index 45092e067d..cd8a2f80bb 100644 --- a/tcl/board/ti_pandaboard.cfg +++ b/tcl/board/ti/pandaboard-es.cfg @@ -2,6 +2,6 @@ jtag_rclk 6000 -source [find target/omap4430.cfg] +source [find target/ti/omap4460.cfg] reset_config trst_only diff --git a/tcl/board/ti_pandaboard_es.cfg b/tcl/board/ti/pandaboard.cfg similarity index 69% rename from tcl/board/ti_pandaboard_es.cfg rename to tcl/board/ti/pandaboard.cfg index f83735844d..7e15f07bdf 100644 --- a/tcl/board/ti_pandaboard_es.cfg +++ b/tcl/board/ti/pandaboard.cfg @@ -2,6 +2,6 @@ jtag_rclk 6000 -source [find target/omap4460.cfg] +source [find target/ti/omap4430.cfg] reset_config trst_only diff --git a/tcl/board/ti_tmdx570ls20susb.cfg b/tcl/board/ti/tmdx570ls20susb.cfg similarity index 91% rename from tcl/board/ti_tmdx570ls20susb.cfg rename to tcl/board/ti/tmdx570ls20susb.cfg index 9c5ef74eaa..ccf649d8fd 100644 --- a/tcl/board/ti_tmdx570ls20susb.cfg +++ b/tcl/board/ti/tmdx570ls20susb.cfg @@ -8,7 +8,7 @@ source [find interface/ftdi/xds100v2.cfg] # Processor is TMS570LS20216 -source [find target/ti_tms570ls20xxx.cfg] +source [find target/ti/tms570ls20xxx.cfg] reset_config trst_only diff --git a/tcl/board/ti_tmdx570ls31usb.cfg b/tcl/board/ti/tmdx570ls31usb.cfg similarity index 78% rename from tcl/board/ti_tmdx570ls31usb.cfg rename to tcl/board/ti/tmdx570ls31usb.cfg index 324f003d38..b2d5d8119a 100644 --- a/tcl/board/ti_tmdx570ls31usb.cfg +++ b/tcl/board/ti/tmdx570ls31usb.cfg @@ -3,6 +3,6 @@ adapter speed 1500 source [find interface/ftdi/xds100v2.cfg] -source [find target/ti_tms570.cfg] +source [find target/ti/tms570.cfg] reset_config trst_only diff --git a/tcl/board/trion_t20_bga256.cfg b/tcl/board/trion_t20_bga256.cfg index ca44f0b8ce..ee6b484cd7 100644 --- a/tcl/board/trion_t20_bga256.cfg +++ b/tcl/board/trion_t20_bga256.cfg @@ -9,7 +9,7 @@ # CRESET_N and SS_N pins in addition to the standard JTAG pins. adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 +adapter usb vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0008 0x008b @@ -21,7 +21,7 @@ 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 +#trion.ipdbghub start -tool 0 -port 5555 set JTAGSPI_CHAIN_ID trion.pld source [find cpld/jtagspi.cfg] diff --git a/tcl/board/vd_a75x4_jtag.cfg b/tcl/board/vd_a75x4_jtag.cfg index c94a71972d..a91f8b8cfc 100644 --- a/tcl/board/vd_a75x4_jtag.cfg +++ b/tcl/board/vd_a75x4_jtag.cfg @@ -17,7 +17,7 @@ set CPUTAPID 0x4ba06477 transport select jtag # JTAG reset config, frequency and reset delay -reset_config trst_and_srst +reset_config trst_only adapter speed 1500000 adapter srst delay 5 diff --git a/tcl/board/vd_pulpissimo_jtag.cfg b/tcl/board/vd_pulpissimo_jtag.cfg index a3f5a84886..5a6725fd62 100644 --- a/tcl/board/vd_pulpissimo_jtag.cfg +++ b/tcl/board/vd_pulpissimo_jtag.cfg @@ -4,9 +4,9 @@ source [find interface/vdebug.cfg] -set _CHIPNAME ibex -set _HARTID 0x20 -set _CPUTAPID 0x249511c3 +set CHIPNAME ibex +set HARTID 0x20 +set CPUTAPID 0x249511c3 # vdebug select transport transport select jtag @@ -25,7 +25,7 @@ vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[1\].sram_i.mem_ar 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 newtap $CHIPNAME cpu -irlen 5 -ircapture 0x05 -irmask 0x1f -expected-id $CPUTAPID jtag arp_init-reset diff --git a/tcl/file_renaming.cfg b/tcl/file_renaming.cfg new file mode 100644 index 0000000000..844899f724 --- /dev/null +++ b/tcl/file_renaming.cfg @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This file is used to remap configuration files that has been +# renamed, except simple renames that are taken care automatically +# like: +# .../file.cfg ==> .../${vendor}/file.cfg +# .../vendor-file.cfg ==> .../vendor/file.cfg +# .../vendor_file.cfg ==> .../vendor/file.cfg +# +# The formatting below is a TCL dict, so pairs of key-value +# in a simple TCL list, using for each line +# old_name new_name +# including in each name one of the prefix folder between +# board, chip, cpld, cpu, fpga, interface, target, test, tools + +set _file_renaming { + board/omap2420_h4.cfg board/ti/omap2420-h4.cfg + board/stm32mp13x_dk.cfg board/st/stm32mp135f-dk.cfg + board/stm32mp15x_dk2.cfg board/st/stm32mp157f-dk2.cfg + board/st_nucleo_l5.cfg board/st/nucleo-l552ze-q.cfg + board/sifive-hifive1-revb.cfg board/sifive/hifive1-rev-b.cfg + board/ti_beagleboard.cfg board/beagle/beagleboard.cfg + board/ti_beagleboard_xm.cfg board/beagle/beagleboard-xm.cfg + board/ti_beaglebone-base.cfg board/beagle/beaglebone-base.cfg + board/ti_beaglebone_black.cfg board/beagle/beaglebone-black.cfg + board/ti_beaglebone.cfg board/beagle/beaglebone.cfg + interface/chameleon.cfg interface/parport/chameleon.cfg + interface/flashlink.cfg interface/parport/flashlink.cfg +} diff --git a/tcl/interface/altera-usb-blaster.cfg b/tcl/interface/altera-usb-blaster.cfg index cc6057b510..c9a56b268a 100644 --- a/tcl/interface/altera-usb-blaster.cfg +++ b/tcl/interface/altera-usb-blaster.cfg @@ -9,5 +9,5 @@ adapter driver usb_blaster usb_blaster lowlevel_driver ftdi # These are already the defaults. -# usb_blaster vid_pid 0x09FB 0x6001 +# adapter usb 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 93f9809b03..95927676bb 100644 --- a/tcl/interface/altera-usb-blaster2.cfg +++ b/tcl/interface/altera-usb-blaster2.cfg @@ -5,6 +5,6 @@ # adapter driver usb_blaster -usb_blaster vid_pid 0x09fb 0x6010 0x09fb 0x6810 +adapter usb 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/chameleon.cfg b/tcl/interface/chameleon.cfg deleted file mode 100644 index b73d129f02..0000000000 --- a/tcl/interface/chameleon.cfg +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later - -# -# Amontec Chameleon POD -# -# http://www.amontec.com/chameleon.shtml -# - -adapter driver parport -parport cable chameleon diff --git a/tcl/interface/cklink.cfg b/tcl/interface/cklink.cfg new file mode 100644 index 0000000000..fb017aa056 --- /dev/null +++ b/tcl/interface/cklink.cfg @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# T-Head CK-Link JTAG adapter (including Bouffalo BL616/BL702 clones) +# + +adapter driver cklink diff --git a/tcl/interface/cmsis-dap-tcp.cfg b/tcl/interface/cmsis-dap-tcp.cfg new file mode 100644 index 0000000000..7889fb9444 --- /dev/null +++ b/tcl/interface/cmsis-dap-tcp.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# cmsis-dap-tcp - CMSIS-DAP protocol over TCP/IP. +# + +adapter driver cmsis-dap +cmsis-dap backend tcp + +# Specify the hostname or IP address of your programmer. +# cmsis-dap tcp host 192.168.1.4 + +# Optionally specify a port number. Default port is 4441. +# cmsis-dap tcp port 4441 + +# Optionally set a lower bound on packet timeouts (milliseconds), if using a +# slow network. +# cmsis-dap tcp min_timeout 300 diff --git a/tcl/interface/esp_usb_bridge.cfg b/tcl/interface/esp_usb_bridge.cfg index 9342239e77..9354855bad 100644 --- a/tcl/interface/esp_usb_bridge.cfg +++ b/tcl/interface/esp_usb_bridge.cfg @@ -5,5 +5,5 @@ adapter driver esp_usb_jtag -espusbjtag vid_pid 0x303a 0x1002 +adapter usb 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 index 40427d0e3e..eff1224a85 100644 --- a/tcl/interface/esp_usb_jtag.cfg +++ b/tcl/interface/esp_usb_jtag.cfg @@ -5,5 +5,7 @@ adapter driver esp_usb_jtag -espusbjtag vid_pid 0x303a 0x1001 +adapter usb vid_pid 0x303a 0x1001 espusbjtag caps_descriptor 0x2000 + +transport select jtag diff --git a/tcl/interface/flashlink.cfg b/tcl/interface/flashlink.cfg deleted file mode 100644 index d552c50a6b..0000000000 --- a/tcl/interface/flashlink.cfg +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later - -# -# ST FlashLINK JTAG parallel cable -# -# http://www.st.com/internet/evalboard/product/94023.jsp -# http://www.st.com/stonline/products/literature/um/7889.pdf -# - -if { [info exists PARPORTADDR] } { - set _PARPORTADDR $PARPORTADDR -} else { - set _PARPORTADDR 0 -} - -adapter driver parport -parport port $_PARPORTADDR -parport cable flashlink diff --git a/tcl/interface/ft232r/radiona_ulx3s.cfg b/tcl/interface/ft232r/radiona_ulx3s.cfg index 3fc3d7105e..54a82f1590 100644 --- a/tcl/interface/ft232r/radiona_ulx3s.cfg +++ b/tcl/interface/ft232r/radiona_ulx3s.cfg @@ -7,7 +7,7 @@ adapter driver ft232r adapter speed 1000 -ft232r vid_pid 0x0403 0x6015 +adapter usb vid_pid 0x0403 0x6015 ft232r tck_num DSR ft232r tms_num DCD ft232r tdi_num RI diff --git a/tcl/interface/ftdi/100ask-openjtag.cfg b/tcl/interface/ftdi/100ask-openjtag.cfg index 5ab9252c69..452b4585f1 100644 --- a/tcl/interface/ftdi/100ask-openjtag.cfg +++ b/tcl/interface/ftdi/100ask-openjtag.cfg @@ -10,8 +10,8 @@ # adapter driver ftdi -ftdi device_desc "USB<=>JTAG&RS232" -ftdi vid_pid 0x1457 0x5118 +adapter usb product_name "USB<=>JTAG&RS232" +adapter usb vid_pid 0x1457 0x5118 ftdi layout_init 0x0f08 0x0f1b ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 diff --git a/tcl/interface/ftdi/arty-onboard-ftdi.cfg b/tcl/interface/ftdi/arty-onboard-ftdi.cfg deleted file mode 100644 index 0edc615e4c..0000000000 --- a/tcl/interface/ftdi/arty-onboard-ftdi.cfg +++ /dev/null @@ -1,7 +0,0 @@ -interface ftdi -# ftdi_device_desc "Arty On-board FTDI interface" -ftdi vid_pid 0x0403 0x6010 -ftdi channel 0 -ftdi layout_init 0x0088 0x008b -reset_config none - diff --git a/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg b/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg index 6256aa0c2b..f175897321 100644 --- a/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg +++ b/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg @@ -6,8 +6,8 @@ # adapter driver ftdi -ftdi device_desc "Opella-LD Debug Probe" -ftdi vid_pid 0x0B6B 0x0040 +adapter usb product_name "Opella-LD Debug Probe" +adapter usb vid_pid 0x0B6B 0x0040 ftdi tdo_sample_edge falling ftdi layout_init 0x0A68 0xFF7B ftdi channel 0 diff --git a/tcl/interface/ftdi/ashling-opella-ld-swd.cfg b/tcl/interface/ftdi/ashling-opella-ld-swd.cfg index 4a4e4e0680..1d960efc04 100644 --- a/tcl/interface/ftdi/ashling-opella-ld-swd.cfg +++ b/tcl/interface/ftdi/ashling-opella-ld-swd.cfg @@ -6,8 +6,8 @@ # adapter driver ftdi -ftdi device_desc "Opella-LD Debug Probe" -ftdi vid_pid 0x0B6B 0x0040 +adapter usb product_name "Opella-LD Debug Probe" +adapter usb vid_pid 0x0B6B 0x0040 ftdi layout_init 0x0860 0x0b7b ftdi channel 0 ftdi layout_signal JTAGOE -data 0x0010 diff --git a/tcl/interface/ftdi/axm0432.cfg b/tcl/interface/ftdi/axm0432.cfg index 50083996c3..e0a99ba63e 100644 --- a/tcl/interface/ftdi/axm0432.cfg +++ b/tcl/interface/ftdi/axm0432.cfg @@ -12,8 +12,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 device_desc "Symphony SoundBite" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Symphony SoundBite" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0c2b ftdi layout_signal nTRST -data 0x0800 diff --git a/tcl/interface/ftdi/c232hm.cfg b/tcl/interface/ftdi/c232hm.cfg index 23c8f3af23..fc78895fc0 100644 --- a/tcl/interface/ftdi/c232hm.cfg +++ b/tcl/interface/ftdi/c232hm.cfg @@ -16,11 +16,11 @@ # 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" +#adapter usb product_name "C232HM-DDHSL-0" +#adapter usb product_name "C232HM-EDHSL-0" # Common PID for FT232H -ftdi vid_pid 0x0403 0x6014 +adapter usb vid_pid 0x0403 0x6014 # Layout # High data byte 0x40 configures red LED on ACBUS6 initially high (unlit, since active-low) diff --git a/tcl/interface/ftdi/cortino.cfg b/tcl/interface/ftdi/cortino.cfg index 8bc8d6e4cc..1c28e2a64b 100644 --- a/tcl/interface/ftdi/cortino.cfg +++ b/tcl/interface/ftdi/cortino.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Cortino" -ftdi vid_pid 0x0640 0x0032 +adapter usb product_name "Cortino" +adapter usb vid_pid 0x0640 0x0032 ftdi layout_init 0x0108 0x010b ftdi layout_signal nTRST -data 0x0100 diff --git a/tcl/interface/ftdi/digilent-hs1.cfg b/tcl/interface/ftdi/digilent-hs1.cfg index 6a632ed268..e3021701ce 100644 --- a/tcl/interface/ftdi/digilent-hs1.cfg +++ b/tcl/interface/ftdi/digilent-hs1.cfg @@ -4,8 +4,8 @@ # (the later being the OEM on-board version) adapter driver ftdi -ftdi device_desc "Digilent Adept USB Device" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Digilent Adept USB Device" +adapter usb vid_pid 0x0403 0x6010 # channel 1 does not have any functionality ftdi channel 0 # just TCK TDI TDO TMS, no reset diff --git a/tcl/interface/ftdi/digilent-hs2-cjtag.cfg b/tcl/interface/ftdi/digilent-hs2-cjtag.cfg deleted file mode 100644 index 3daf46185d..0000000000 --- a/tcl/interface/ftdi/digilent-hs2-cjtag.cfg +++ /dev/null @@ -1,17 +0,0 @@ -adapter driver ftdi -ftdi device_desc "Digilent Adept USB Device" -ftdi vid_pid 0x0403 0x6014 - -ftdi channel 0 -ftdi layout_init 0x60e8 0x60eb - -reset_config none - -# These signals are used for cJTAG escape sequence on initialization only -ftdi layout_signal TCK -data 0x0001 -ftdi layout_signal TDI -data 0x0002 -ftdi layout_signal TDO -input 0x0004 -ftdi layout_signal TMS -data 0x0008 -ftdi layout_signal JTAG_SEL -ndata 0x6000 -oe 0x6000 - -ftdi layout_signal TMSC_EN -data 0x0020 -oe 0x0020 diff --git a/tcl/interface/ftdi/digilent-hs2.cfg b/tcl/interface/ftdi/digilent-hs2.cfg index 89c9e4b6c4..83f1a74461 100644 --- a/tcl/interface/ftdi/digilent-hs2.cfg +++ b/tcl/interface/ftdi/digilent-hs2.cfg @@ -7,8 +7,8 @@ # 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 +adapter usb product_name "Digilent Adept USB Device" +adapter usb vid_pid 0x0403 0x6014 ftdi channel 0 ftdi layout_init 0x00e8 0x60eb diff --git a/tcl/interface/ftdi/digilent_jtag_hs3.cfg b/tcl/interface/ftdi/digilent_jtag_hs3.cfg index 78a233feb5..9834c6ae57 100644 --- a/tcl/interface/ftdi/digilent_jtag_hs3.cfg +++ b/tcl/interface/ftdi/digilent_jtag_hs3.cfg @@ -5,8 +5,8 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6014 -ftdi device_desc "Digilent USB Device" +adapter usb vid_pid 0x0403 0x6014 +adapter usb product_name "Digilent USB Device" # From Digilent support: # The SRST pin is [...] 0x20 and 0x10 is the /OE (active low output enable) diff --git a/tcl/interface/ftdi/digilent_jtag_smt2.cfg b/tcl/interface/ftdi/digilent_jtag_smt2.cfg index ac623a796d..8c723c060d 100644 --- a/tcl/interface/ftdi/digilent_jtag_smt2.cfg +++ b/tcl/interface/ftdi/digilent_jtag_smt2.cfg @@ -10,7 +10,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6014 +adapter usb vid_pid 0x0403 0x6014 ftdi layout_init 0x20e8 0x3feb ftdi layout_signal nSRST -data 0x2000 diff --git a/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg b/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg index 38236bc107..439fe41d51 100644 --- a/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg +++ b/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg @@ -10,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 adapter usb product_name from digilent_hs2 is wrong. adapter driver ftdi -ftdi device_desc "Digilent USB Device" -ftdi vid_pid 0x0403 0x6014 +adapter usb product_name "Digilent USB Device" +adapter usb 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 67fee6b0f5..96802af3a2 100644 --- a/tcl/interface/ftdi/dlp-usb1232h.cfg +++ b/tcl/interface/ftdi/dlp-usb1232h.cfg @@ -15,8 +15,8 @@ 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 +adapter usb product_name "Dual RS232-HS" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 diff --git a/tcl/interface/ftdi/dp_busblaster.cfg b/tcl/interface/ftdi/dp_busblaster.cfg index 373e122c46..7269f31fb0 100644 --- a/tcl/interface/ftdi/dp_busblaster.cfg +++ b/tcl/interface/ftdi/dp_busblaster.cfg @@ -14,8 +14,8 @@ 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 +adapter usb product_name "Dual RS232-HS" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 diff --git a/tcl/interface/ftdi/dp_busblaster_kt-link.cfg b/tcl/interface/ftdi/dp_busblaster_kt-link.cfg index 222ca3810b..cbe2b1f2d7 100644 --- a/tcl/interface/ftdi/dp_busblaster_kt-link.cfg +++ b/tcl/interface/ftdi/dp_busblaster_kt-link.cfg @@ -12,8 +12,8 @@ # adapter driver ftdi -ftdi device_desc "Dual RS232-HS" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Dual RS232-HS" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x8c28 0xff3b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 diff --git a/tcl/interface/ftdi/esp32_devkitj_v1.cfg b/tcl/interface/ftdi/esp32_devkitj_v1.cfg index 1b455a9ac8..c3139894fe 100644 --- a/tcl/interface/ftdi/esp32_devkitj_v1.cfg +++ b/tcl/interface/ftdi/esp32_devkitj_v1.cfg @@ -5,7 +5,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 0x0403 0x6014 +adapter usb vid_pid 0x0403 0x6010 0x0403 0x6014 # interface 1 is the uart ftdi channel 0 @@ -23,3 +23,5 @@ ftdi layout_signal LED4 -data 0x8000 # 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 + +transport select jtag diff --git a/tcl/interface/ftdi/esp32s2_kaluga_v1.cfg b/tcl/interface/ftdi/esp32s2_kaluga_v1.cfg index 1880bcbc5f..ae1b20564d 100644 --- a/tcl/interface/ftdi/esp32s2_kaluga_v1.cfg +++ b/tcl/interface/ftdi/esp32s2_kaluga_v1.cfg @@ -8,7 +8,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 0x0403 0x6014 +adapter usb vid_pid 0x0403 0x6010 0x0403 0x6014 # interface 1 is the uart ftdi channel 0 @@ -27,3 +27,5 @@ ftdi layout_signal LED2 -ndata 0x1000 # commented out: # ftdi layout_signal nSRST -oe 0x0020 # reset_config srst_only + +transport select jtag diff --git a/tcl/interface/ftdi/flossjtag-noeeprom.cfg b/tcl/interface/ftdi/flossjtag-noeeprom.cfg index 1008e1ae68..e98c9e1cb6 100644 --- a/tcl/interface/ftdi/flossjtag-noeeprom.cfg +++ b/tcl/interface/ftdi/flossjtag-noeeprom.cfg @@ -20,8 +20,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 device_desc "Dual RS232-HS" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Dual RS232-HS" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 diff --git a/tcl/interface/ftdi/flossjtag.cfg b/tcl/interface/ftdi/flossjtag.cfg index 90ba63a4cd..f67d1e825f 100644 --- a/tcl/interface/ftdi/flossjtag.cfg +++ b/tcl/interface/ftdi/flossjtag.cfg @@ -20,8 +20,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 device_desc "FLOSS-JTAG" +adapter usb vid_pid 0x0403 0x6010 +adapter usb product_name "FLOSS-JTAG" # adapter serial "FJ000001" ftdi layout_init 0x0008 0x180b diff --git a/tcl/interface/ftdi/flyswatter.cfg b/tcl/interface/ftdi/flyswatter.cfg index 8bce00dbbf..4cbca3e39c 100644 --- a/tcl/interface/ftdi/flyswatter.cfg +++ b/tcl/interface/ftdi/flyswatter.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Flyswatter" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Flyswatter" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0818 0x0cfb ftdi layout_signal nTRST -data 0x0010 diff --git a/tcl/interface/ftdi/flyswatter2.cfg b/tcl/interface/ftdi/flyswatter2.cfg index ebc00fe601..fc0a35757f 100644 --- a/tcl/interface/ftdi/flyswatter2.cfg +++ b/tcl/interface/ftdi/flyswatter2.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Flyswatter2" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Flyswatter2" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0538 0x057b ftdi layout_signal LED -ndata 0x0400 diff --git a/tcl/interface/ftdi/ft232h-module-swd.cfg b/tcl/interface/ftdi/ft232h-module-swd.cfg index d09ccf16d4..e7fe463a7e 100644 --- a/tcl/interface/ftdi/ft232h-module-swd.cfg +++ b/tcl/interface/ftdi/ft232h-module-swd.cfg @@ -10,7 +10,7 @@ adapter driver ftdi -ftdi vid_pid 0x0403 0x6014 +adapter usb vid_pid 0x0403 0x6014 # data MSB..LSB direction (1:out) MSB..LSB # 0000'0000'0011'0000 0000'0000'0011'1011 diff --git a/tcl/interface/ftdi/gw16042.cfg b/tcl/interface/ftdi/gw16042.cfg index 326a88fa02..b2b8fc5fbc 100644 --- a/tcl/interface/ftdi/gw16042.cfg +++ b/tcl/interface/ftdi/gw16042.cfg @@ -20,8 +20,8 @@ # adapter driver ftdi -ftdi device_desc "USB-JTAG" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "USB-JTAG" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0058 0x007b ftdi layout_signal nTRST -data 0x0010 diff --git a/tcl/interface/ftdi/hie-jtag.cfg b/tcl/interface/ftdi/hie-jtag.cfg index 6694df0484..b85200664c 100644 --- a/tcl/interface/ftdi/hie-jtag.cfg +++ b/tcl/interface/ftdi/hie-jtag.cfg @@ -7,8 +7,8 @@ adapter driver ftdi ftdi channel 0 -ftdi vid_pid 0x0403 0x6014 -ftdi device_desc "HIE JTAG Debugger" +adapter usb vid_pid 0x0403 0x6014 +adapter usb product_name "HIE JTAG Debugger" ftdi layout_init 0x0c08 0x4f1b diff --git a/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg index d5d24e5fc5..bd3d43b8ce 100644 --- a/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg @@ -12,8 +12,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 device_desc "NXHX 10-ETM" -ftdi vid_pid 0x0640 0x0028 +adapter usb product_name "NXHX 10-ETM" +adapter usb vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 diff --git a/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg index 003b9df6b3..0367c2349a 100644 --- a/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg @@ -12,8 +12,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 device_desc "NXHX 500-ETM" -ftdi vid_pid 0x0640 0x0028 +adapter usb product_name "NXHX 500-ETM" +adapter usb vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 diff --git a/tcl/interface/ftdi/hilscher_nxhx500_re.cfg b/tcl/interface/ftdi/hilscher_nxhx500_re.cfg index 97ad38075d..1f76d6fa58 100644 --- a/tcl/interface/ftdi/hilscher_nxhx500_re.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx500_re.cfg @@ -12,8 +12,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 device_desc "NXHX 500-RE" -ftdi vid_pid 0x0640 0x0028 +adapter usb product_name "NXHX 500-RE" +adapter usb vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 diff --git a/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg index 06280c1ffd..5116f2e2ce 100644 --- a/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg @@ -12,8 +12,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 device_desc "NXHX 50-ETM" -ftdi vid_pid 0x0640 0x0028 +adapter usb product_name "NXHX 50-ETM" +adapter usb vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 diff --git a/tcl/interface/ftdi/hilscher_nxhx50_re.cfg b/tcl/interface/ftdi/hilscher_nxhx50_re.cfg index f14be626b0..ad45e623be 100644 --- a/tcl/interface/ftdi/hilscher_nxhx50_re.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx50_re.cfg @@ -12,8 +12,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 device_desc "NXHX50-RE" -ftdi vid_pid 0x0640 0x0028 +adapter usb product_name "NXHX50-RE" +adapter usb vid_pid 0x0640 0x0028 ftdi layout_init 0x0308 0x030b ftdi layout_signal nTRST -data 0x0100 diff --git a/tcl/interface/ftdi/hitex_lpc1768stick.cfg b/tcl/interface/ftdi/hitex_lpc1768stick.cfg index 91bd5a8423..31c3a70173 100644 --- a/tcl/interface/ftdi/hitex_lpc1768stick.cfg +++ b/tcl/interface/ftdi/hitex_lpc1768stick.cfg @@ -8,8 +8,8 @@ adapter driver ftdi -ftdi device_desc "LPC1768-Stick" -ftdi vid_pid 0x0640 0x0026 +adapter usb product_name "LPC1768-Stick" +adapter usb vid_pid 0x0640 0x0026 ftdi layout_init 0x0388 0x038b ftdi layout_signal nTRST -data 0x0100 diff --git a/tcl/interface/ftdi/hitex_str9-comstick.cfg b/tcl/interface/ftdi/hitex_str9-comstick.cfg index f698677a63..0f16a116b9 100644 --- a/tcl/interface/ftdi/hitex_str9-comstick.cfg +++ b/tcl/interface/ftdi/hitex_str9-comstick.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "STR9-comStick" -ftdi vid_pid 0x0640 0x002c +adapter usb product_name "STR9-comStick" +adapter usb vid_pid 0x0640 0x002c ftdi layout_init 0x0108 0x010b ftdi layout_signal nTRST -data 0x0100 diff --git a/tcl/interface/ftdi/icebear.cfg b/tcl/interface/ftdi/icebear.cfg index 4a763994b5..c7c95f1be6 100644 --- a/tcl/interface/ftdi/icebear.cfg +++ b/tcl/interface/ftdi/icebear.cfg @@ -12,8 +12,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 device_desc "ICEbear JTAG adapter" -ftdi vid_pid 0x0403 0xc140 +adapter usb product_name "ICEbear JTAG adapter" +adapter usb vid_pid 0x0403 0xc140 ftdi layout_init 0x0028 0x002b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 diff --git a/tcl/interface/ftdi/imx8mp-evk.cfg b/tcl/interface/ftdi/imx8mp-evk.cfg index 02564dc99e..b53c4b6c09 100644 --- a/tcl/interface/ftdi/imx8mp-evk.cfg +++ b/tcl/interface/ftdi/imx8mp-evk.cfg @@ -13,7 +13,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6011 +adapter usb vid_pid 0x0403 0x6011 ftdi channel 0 ftdi layout_init 0x00f8 0x000b diff --git a/tcl/interface/ftdi/incircuit-icprog.cfg b/tcl/interface/ftdi/incircuit-icprog.cfg index 81f2872205..f46b0a902e 100644 --- a/tcl/interface/ftdi/incircuit-icprog.cfg +++ b/tcl/interface/ftdi/incircuit-icprog.cfg @@ -9,7 +9,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nSRST -noe 0x0400 -data 0x0800 diff --git a/tcl/interface/ftdi/iotlab-usb.cfg b/tcl/interface/ftdi/iotlab-usb.cfg index b7a004e848..c607548678 100644 --- a/tcl/interface/ftdi/iotlab-usb.cfg +++ b/tcl/interface/ftdi/iotlab-usb.cfg @@ -6,7 +6,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 diff --git a/tcl/interface/ftdi/isodebug.cfg b/tcl/interface/ftdi/isodebug.cfg index 0a6e0807ec..4b9a406dde 100644 --- a/tcl/interface/ftdi/isodebug.cfg +++ b/tcl/interface/ftdi/isodebug.cfg @@ -4,7 +4,7 @@ # 5 kV isolated JTAG/SWD + UART adapter by Unjo AB adapter driver ftdi -ftdi vid_pid 0x22b7 0x150d +adapter usb vid_pid 0x22b7 0x150d ftdi layout_init 0x0ff8 0xfffb diff --git a/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg b/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg index ea60dcfc39..f955e817ae 100644 --- a/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg +++ b/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "JTAG-lock-pick Tiny 2" -ftdi vid_pid 0x0403 0x8220 +adapter usb product_name "JTAG-lock-pick Tiny 2" +adapter usb vid_pid 0x0403 0x8220 ftdi layout_init 0x8c28 0xff3b ftdi layout_signal SWD_EN -ndata 0x0020 -oe 0x2000 diff --git a/tcl/interface/ftdi/jtagkey.cfg b/tcl/interface/ftdi/jtagkey.cfg index 1c1c09d3fd..25b64466e1 100644 --- a/tcl/interface/ftdi/jtagkey.cfg +++ b/tcl/interface/ftdi/jtagkey.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Amontec JTAGkey" -ftdi vid_pid 0x0403 0xcff8 +adapter usb product_name "Amontec JTAGkey" +adapter usb vid_pid 0x0403 0xcff8 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 diff --git a/tcl/interface/ftdi/jtagkey2.cfg b/tcl/interface/ftdi/jtagkey2.cfg index 80df347c38..36da3d38d1 100644 --- a/tcl/interface/ftdi/jtagkey2.cfg +++ b/tcl/interface/ftdi/jtagkey2.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Amontec JTAGkey-2" -ftdi vid_pid 0x0403 0xcff8 +adapter usb product_name "Amontec JTAGkey-2" +adapter usb vid_pid 0x0403 0xcff8 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 diff --git a/tcl/interface/ftdi/jtagkey2p.cfg b/tcl/interface/ftdi/jtagkey2p.cfg index 3a76bd085a..3a661a1d4a 100644 --- a/tcl/interface/ftdi/jtagkey2p.cfg +++ b/tcl/interface/ftdi/jtagkey2p.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Amontec JTAGkey-2P" -ftdi vid_pid 0x0403 0xcff8 +adapter usb product_name "Amontec JTAGkey-2P" +adapter usb vid_pid 0x0403 0xcff8 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 diff --git a/tcl/interface/ftdi/kt-link.cfg b/tcl/interface/ftdi/kt-link.cfg index 61c6b831b7..4787724cfc 100644 --- a/tcl/interface/ftdi/kt-link.cfg +++ b/tcl/interface/ftdi/kt-link.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "KT-LINK" -ftdi vid_pid 0x0403 0xbbe2 +adapter usb product_name "KT-LINK" +adapter usb vid_pid 0x0403 0xbbe2 ftdi layout_init 0x8c28 0xff3b ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 diff --git a/tcl/interface/ftdi/lambdaconcept_ecpix-5.cfg b/tcl/interface/ftdi/lambdaconcept_ecpix-5.cfg index df4955f8a1..2976b0f2a0 100644 --- a/tcl/interface/ftdi/lambdaconcept_ecpix-5.cfg +++ b/tcl/interface/ftdi/lambdaconcept_ecpix-5.cfg @@ -7,8 +7,8 @@ adapter driver ftdi adapter speed 10000 -ftdi device_desc "Dual RS232-HS" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Dual RS232-HS" +adapter usb 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 75c5cbe7fd..f90fb7152e 100644 --- a/tcl/interface/ftdi/lisa-l.cfg +++ b/tcl/interface/ftdi/lisa-l.cfg @@ -12,8 +12,8 @@ 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 +adapter usb product_name "Lisa/L" +adapter usb vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0008 0x180b diff --git a/tcl/interface/ftdi/luminary-icdi.cfg b/tcl/interface/ftdi/luminary-icdi.cfg index 9142503dd0..238adf57f0 100644 --- a/tcl/interface/ftdi/luminary-icdi.cfg +++ b/tcl/interface/ftdi/luminary-icdi.cfg @@ -18,8 +18,8 @@ # adapter driver ftdi -ftdi device_desc "Luminary Micro ICDI Board" -ftdi vid_pid 0x0403 0xbcda +adapter usb product_name "Luminary Micro ICDI Board" +adapter usb vid_pid 0x0403 0xbcda ftdi layout_init 0x00a8 0x00eb ftdi layout_signal nSRST -noe 0x0020 diff --git a/tcl/interface/ftdi/luminary-lm3s811.cfg b/tcl/interface/ftdi/luminary-lm3s811.cfg index 98be166fd6..dcbc0cdfe9 100644 --- a/tcl/interface/ftdi/luminary-lm3s811.cfg +++ b/tcl/interface/ftdi/luminary-lm3s811.cfg @@ -14,8 +14,8 @@ # adapter driver ftdi -ftdi device_desc "LM3S811 Evaluation Board" -ftdi vid_pid 0x0403 0xbcd9 +adapter usb product_name "LM3S811 Evaluation Board" +adapter usb vid_pid 0x0403 0xbcd9 ftdi layout_init 0x0088 0x008b ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 diff --git a/tcl/interface/ftdi/luminary.cfg b/tcl/interface/ftdi/luminary.cfg index 27d9a9da05..fd5403476d 100644 --- a/tcl/interface/ftdi/luminary.cfg +++ b/tcl/interface/ftdi/luminary.cfg @@ -27,8 +27,8 @@ # adapter driver ftdi -ftdi device_desc "Stellaris Evaluation Board" -ftdi vid_pid 0x0403 0xbcd9 +adapter usb product_name "Stellaris Evaluation Board" +adapter usb vid_pid 0x0403 0xbcd9 ftdi layout_init 0x00a8 0x00eb ftdi layout_signal nSRST -noe 0x0020 diff --git a/tcl/interface/ftdi/m53evk.cfg b/tcl/interface/ftdi/m53evk.cfg index 2d9c30448b..cb2542faa7 100644 --- a/tcl/interface/ftdi/m53evk.cfg +++ b/tcl/interface/ftdi/m53evk.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Dual RS232-HS" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Dual RS232-HS" +adapter usb vid_pid 0x0403 0x6010 ftdi channel 0 ftdi layout_init 0x0008 0x000b diff --git a/tcl/interface/ftdi/mbftdi.cfg b/tcl/interface/ftdi/mbftdi.cfg index 09cec9ffb3..1bdebb4e59 100644 --- a/tcl/interface/ftdi/mbftdi.cfg +++ b/tcl/interface/ftdi/mbftdi.cfg @@ -12,7 +12,7 @@ # adapter driver ftdi -ftdi device_desc "Dual RS232-HS" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Dual RS232-HS" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x000b diff --git a/tcl/interface/ftdi/minimodule-swd.cfg b/tcl/interface/ftdi/minimodule-swd.cfg index 3eb2f53278..aca361a912 100644 --- a/tcl/interface/ftdi/minimodule-swd.cfg +++ b/tcl/interface/ftdi/minimodule-swd.cfg @@ -40,12 +40,12 @@ adapter driver ftdi #Select your module type and channel -#ftdi device_desc "FT2232H MiniModule" -ftdi vid_pid 0x0403 0x6010 +#adapter usb product_name "FT2232H MiniModule" +adapter usb vid_pid 0x0403 0x6010 #ftdi channel 1 -#ftdi device_desc "FT4232H MiniModule" -#ftdi vid_pid 0x0403 0x6011 +#adapter usb product_name "FT4232H MiniModule" +#adapter usb vid_pid 0x0403 0x6011 #ftdi channel 1 ftdi layout_init 0x0000 0x000b diff --git a/tcl/interface/ftdi/minimodule.cfg b/tcl/interface/ftdi/minimodule.cfg index 825d7c1dc8..cfd18af7ac 100644 --- a/tcl/interface/ftdi/minimodule.cfg +++ b/tcl/interface/ftdi/minimodule.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "FT2232H MiniModule" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "FT2232H MiniModule" +adapter usb vid_pid 0x0403 0x6010 # Every pin set as high impedance except TCK, TDI, TDO and TMS ftdi layout_init 0x0008 0x000b diff --git a/tcl/interface/ftdi/minispartan6.cfg b/tcl/interface/ftdi/minispartan6.cfg index f12bae621c..74b13bfb21 100644 --- a/tcl/interface/ftdi/minispartan6.cfg +++ b/tcl/interface/ftdi/minispartan6.cfg @@ -5,8 +5,8 @@ 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 +#adapter usb product_name "Dual RS232-HS" +adapter usb vid_pid 0x0403 0x6010 # interface 1 is the uart ftdi channel 0 # just TCK TDI TDO TMS, no reset diff --git a/tcl/interface/ftdi/miniwiggler.cfg b/tcl/interface/ftdi/miniwiggler.cfg index ebaa97920b..a10ec49d32 100644 --- a/tcl/interface/ftdi/miniwiggler.cfg +++ b/tcl/interface/ftdi/miniwiggler.cfg @@ -25,8 +25,8 @@ # adapter driver ftdi -ftdi device_desc "DAS JDS miniWiggler V3.1" -ftdi vid_pid 0x058b 0x0043 +adapter usb product_name "DAS JDS miniWiggler V3.1" +adapter usb vid_pid 0x058b 0x0043 ftdi channel 0 ftdi layout_init 0x0008 0x001b diff --git a/tcl/interface/ftdi/neodb.cfg b/tcl/interface/ftdi/neodb.cfg index d3b35412fb..9b90823a37 100644 --- a/tcl/interface/ftdi/neodb.cfg +++ b/tcl/interface/ftdi/neodb.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Debug Board for Neo1973" -ftdi vid_pid 0x1457 0x5118 +adapter usb product_name "Debug Board for Neo1973" +adapter usb vid_pid 0x1457 0x5118 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 diff --git a/tcl/interface/ftdi/ngxtech.cfg b/tcl/interface/ftdi/ngxtech.cfg index 635333fb97..a5825c83fb 100644 --- a/tcl/interface/ftdi/ngxtech.cfg +++ b/tcl/interface/ftdi/ngxtech.cfg @@ -13,8 +13,8 @@ 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 +adapter usb product_name "NGX JTAG" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 diff --git a/tcl/interface/ftdi/olimex-arm-jtag-cjtag.cfg b/tcl/interface/ftdi/olimex-arm-jtag-cjtag.cfg index 6939d00267..c782ec3b96 100644 --- a/tcl/interface/ftdi/olimex-arm-jtag-cjtag.cfg +++ b/tcl/interface/ftdi/olimex-arm-jtag-cjtag.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/ @@ -11,8 +13,8 @@ interface ftdi ftdi oscan1_mode on -ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" -ftdi vid_pid 0x15ba 0x002a +adapter usb product_name "Olimex OpenOCD JTAG ARM-USB-TINY-H" +adapter usb vid_pid 0x15ba 0x002a ftdi layout_init 0x0808 0x0a1b ftdi layout_signal nSRST -oe 0x0200 diff --git a/tcl/interface/ftdi/olimex-arm-usb-ocd-h-cjtag.cfg b/tcl/interface/ftdi/olimex-arm-usb-ocd-h-cjtag.cfg index 36ac587620..657fb85f5c 100644 --- a/tcl/interface/ftdi/olimex-arm-usb-ocd-h-cjtag.cfg +++ b/tcl/interface/ftdi/olimex-arm-usb-ocd-h-cjtag.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Olimex ARM-USB-OCD-H (using cJTAG) # @@ -6,8 +8,8 @@ interface ftdi ftdi oscan1_mode on -ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-OCD-H" -ftdi vid_pid 0x15ba 0x002b +adapter usb product_name "Olimex OpenOCD JTAG ARM-USB-OCD-H" +adapter usb vid_pid 0x15ba 0x002b ftdi layout_init 0x0808 0x0a1b ftdi layout_signal nSRST -oe 0x0200 diff --git a/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg b/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg index cd11ad8e11..dd67b6d570 100644 --- a/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg +++ b/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-OCD-H" -ftdi vid_pid 0x15ba 0x002b +adapter usb product_name "Olimex OpenOCD JTAG ARM-USB-OCD-H" +adapter usb vid_pid 0x15ba 0x002b ftdi layout_init 0x0908 0x0b1b ftdi layout_signal nSRST -oe 0x0200 diff --git a/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg b/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg index d2261e2b77..9d0b0091c7 100644 --- a/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg +++ b/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Olimex OpenOCD JTAG" -ftdi vid_pid 0x15ba 0x0003 +adapter usb product_name "Olimex OpenOCD JTAG" +adapter usb vid_pid 0x15ba 0x0003 ftdi layout_init 0x0c08 0x0f1b ftdi layout_signal nSRST -oe 0x0200 diff --git a/tcl/interface/ftdi/olimex-arm-usb-tiny-h-cjtag.cfg b/tcl/interface/ftdi/olimex-arm-usb-tiny-h-cjtag.cfg index 13378b394a..62ca02c4de 100644 --- a/tcl/interface/ftdi/olimex-arm-usb-tiny-h-cjtag.cfg +++ b/tcl/interface/ftdi/olimex-arm-usb-tiny-h-cjtag.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/ @@ -11,8 +13,8 @@ interface ftdi ftdi oscan1_mode on -ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" -ftdi vid_pid 0x15ba 0x002a +adapter usb product_name "Olimex OpenOCD JTAG ARM-USB-TINY-H" +adapter usb vid_pid 0x15ba 0x002a ftdi layout_init 0x0808 0x0a1b ftdi layout_signal nSRST -oe 0x0200 diff --git a/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg b/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg index a2b3e3edfc..e771348482 100644 --- a/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg +++ b/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" -ftdi vid_pid 0x15ba 0x002a +adapter usb product_name "Olimex OpenOCD JTAG ARM-USB-TINY-H" +adapter usb vid_pid 0x15ba 0x002a ftdi layout_init 0x0808 0x0a1b ftdi layout_signal nSRST -oe 0x0200 diff --git a/tcl/interface/ftdi/olimex-jtag-tiny.cfg b/tcl/interface/ftdi/olimex-jtag-tiny.cfg index 7d8e81da3c..889b4e08bb 100644 --- a/tcl/interface/ftdi/olimex-jtag-tiny.cfg +++ b/tcl/interface/ftdi/olimex-jtag-tiny.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Olimex OpenOCD JTAG TINY" -ftdi vid_pid 0x15ba 0x0004 +adapter usb product_name "Olimex OpenOCD JTAG TINY" +adapter usb vid_pid 0x15ba 0x0004 ftdi layout_init 0x0808 0x0a1b ftdi layout_signal nSRST -oe 0x0200 diff --git a/tcl/interface/ftdi/oocdlink.cfg b/tcl/interface/ftdi/oocdlink.cfg index 0e99b67a4d..88f799a1ec 100644 --- a/tcl/interface/ftdi/oocdlink.cfg +++ b/tcl/interface/ftdi/oocdlink.cfg @@ -13,8 +13,8 @@ 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 +adapter usb product_name "OOCDLink" +adapter usb vid_pid 0x0403 0xbaf8 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 diff --git a/tcl/interface/ftdi/opendous_ftdi.cfg b/tcl/interface/ftdi/opendous_ftdi.cfg index 5d6f5aee1a..faa3952f6b 100644 --- a/tcl/interface/ftdi/opendous_ftdi.cfg +++ b/tcl/interface/ftdi/opendous_ftdi.cfg @@ -10,8 +10,8 @@ # adapter driver ftdi -ftdi device_desc "Dual RS232-HS" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Dual RS232-HS" +adapter usb vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0c08 0x0f1b diff --git a/tcl/interface/ftdi/openocd-usb-hs.cfg b/tcl/interface/ftdi/openocd-usb-hs.cfg index af1f61c33d..4f1ab058d1 100644 --- a/tcl/interface/ftdi/openocd-usb-hs.cfg +++ b/tcl/interface/ftdi/openocd-usb-hs.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Dual RS232-HS" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Dual RS232-HS" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 diff --git a/tcl/interface/ftdi/openocd-usb.cfg b/tcl/interface/ftdi/openocd-usb.cfg index c333d65ca9..da39d3660b 100644 --- a/tcl/interface/ftdi/openocd-usb.cfg +++ b/tcl/interface/ftdi/openocd-usb.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Dual RS232" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Dual RS232" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 diff --git a/tcl/interface/ftdi/openrd.cfg b/tcl/interface/ftdi/openrd.cfg index b6b2d1d93e..19da745cea 100644 --- a/tcl/interface/ftdi/openrd.cfg +++ b/tcl/interface/ftdi/openrd.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "OpenRD JTAGKey FT2232D B" -ftdi vid_pid 0x0403 0x9e90 +adapter usb product_name "OpenRD JTAGKey FT2232D B" +adapter usb vid_pid 0x0403 0x9e90 ftdi channel 0 ftdi layout_init 0x0608 0x0f1b diff --git a/tcl/interface/ftdi/pipistrello.cfg b/tcl/interface/ftdi/pipistrello.cfg index 29ecd12292..c76112ddfc 100644 --- a/tcl/interface/ftdi/pipistrello.cfg +++ b/tcl/interface/ftdi/pipistrello.cfg @@ -3,8 +3,8 @@ # 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 +adapter usb product_name "Pipistrello LX45" +adapter usb vid_pid 0x0403 0x6010 # interface 1 is the uart ftdi channel 0 # just TCK TDI TDO TMS, no reset diff --git a/tcl/interface/ftdi/pls_spc5.cfg b/tcl/interface/ftdi/pls_spc5.cfg index 3b3c2d6475..5be8e25e0f 100644 --- a/tcl/interface/ftdi/pls_spc5.cfg +++ b/tcl/interface/ftdi/pls_spc5.cfg @@ -27,8 +27,8 @@ # adapter driver ftdi -ftdi device_desc "PLS USB/JTAG Adapter for SPC5xxx" -ftdi vid_pid 0x263d 0x4001 +adapter usb product_name "PLS USB/JTAG Adapter for SPC5xxx" +adapter usb vid_pid 0x263d 0x4001 ftdi channel 0 ftdi layout_init 0x0008 0x000b diff --git a/tcl/interface/ftdi/redbee-econotag.cfg b/tcl/interface/ftdi/redbee-econotag.cfg index d0d3d833e1..2491ea0eb9 100644 --- a/tcl/interface/ftdi/redbee-econotag.cfg +++ b/tcl/interface/ftdi/redbee-econotag.cfg @@ -16,7 +16,7 @@ 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 +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0c08 0x0c2b ftdi layout_signal nTRST -data 0x0800 diff --git a/tcl/interface/ftdi/redbee-usb.cfg b/tcl/interface/ftdi/redbee-usb.cfg index 98805536d2..880c5d53eb 100644 --- a/tcl/interface/ftdi/redbee-usb.cfg +++ b/tcl/interface/ftdi/redbee-usb.cfg @@ -16,7 +16,7 @@ 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 +adapter usb vid_pid 0x0403 0x6010 ftdi channel 1 ftdi layout_init 0x0c08 0x0c2b diff --git a/tcl/interface/ftdi/sheevaplug.cfg b/tcl/interface/ftdi/sheevaplug.cfg index 29c8688091..24c9ee77f3 100644 --- a/tcl/interface/ftdi/sheevaplug.cfg +++ b/tcl/interface/ftdi/sheevaplug.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "SheevaPlug JTAGKey FT2232D B" -ftdi vid_pid 0x9e88 0x9e8f +adapter usb product_name "SheevaPlug JTAGKey FT2232D B" +adapter usb vid_pid 0x9e88 0x9e8f ftdi channel 0 ftdi layout_init 0x0608 0x0f1b diff --git a/tcl/interface/ftdi/signalyzer-lite.cfg b/tcl/interface/ftdi/signalyzer-lite.cfg index e6c3839c98..85459ed49c 100644 --- a/tcl/interface/ftdi/signalyzer-lite.cfg +++ b/tcl/interface/ftdi/signalyzer-lite.cfg @@ -12,8 +12,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 device_desc "Signalyzer LITE" -ftdi vid_pid 0x0403 0xbca1 +adapter usb product_name "Signalyzer LITE" +adapter usb vid_pid 0x0403 0xbca1 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 diff --git a/tcl/interface/ftdi/signalyzer.cfg b/tcl/interface/ftdi/signalyzer.cfg index fa7a7edc1e..5c055d3307 100644 --- a/tcl/interface/ftdi/signalyzer.cfg +++ b/tcl/interface/ftdi/signalyzer.cfg @@ -12,8 +12,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 device_desc "Signalyzer" -ftdi vid_pid 0x0403 0xbca0 +adapter usb product_name "Signalyzer" +adapter usb vid_pid 0x0403 0xbca0 ftdi layout_init 0x0008 0x000b ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 diff --git a/tcl/interface/ftdi/sipeed-rv-debugger.cfg b/tcl/interface/ftdi/sipeed-rv-debugger.cfg index ca65398c6e..cc8f4f0367 100644 --- a/tcl/interface/ftdi/sipeed-rv-debugger.cfg +++ b/tcl/interface/ftdi/sipeed-rv-debugger.cfg @@ -7,7 +7,7 @@ adapter driver ftdi adapter speed 6000 -ftdi device_desc "JTAG Debugger" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "JTAG Debugger" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0008 0x001b ftdi layout_signal nSRST -oe 0x0020 -data 0x0020 diff --git a/tcl/interface/ftdi/sipeed-usb-jtag-debugger.cfg b/tcl/interface/ftdi/sipeed-usb-jtag-debugger.cfg index 8a804eca67..cc6455e1a6 100644 --- a/tcl/interface/ftdi/sipeed-usb-jtag-debugger.cfg +++ b/tcl/interface/ftdi/sipeed-usb-jtag-debugger.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Dual RS232" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Dual RS232" +adapter usb vid_pid 0x0403 0x6010 ftdi channel 0 # Every pin set as high impedance except TCK, TDI, TDO, TMS and RST diff --git a/tcl/interface/ftdi/snps_sdp.cfg b/tcl/interface/ftdi/snps_sdp.cfg index eb2aecc87a..242c238c28 100644 --- a/tcl/interface/ftdi/snps_sdp.cfg +++ b/tcl/interface/ftdi/snps_sdp.cfg @@ -11,7 +11,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 +adapter usb 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 index f84efe61ed..28b302eeb6 100644 --- a/tcl/interface/ftdi/steppenprobe.cfg +++ b/tcl/interface/ftdi/steppenprobe.cfg @@ -6,7 +6,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 +adapter usb vid_pid 0x0403 0x6010 # Initial Layout ftdi layout_init 0x0058 0x99fb diff --git a/tcl/interface/ftdi/stm32-stick.cfg b/tcl/interface/ftdi/stm32-stick.cfg index 1d72d20e35..cbf0a723dd 100644 --- a/tcl/interface/ftdi/stm32-stick.cfg +++ b/tcl/interface/ftdi/stm32-stick.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "STM32-PerformanceStick" -ftdi vid_pid 0x0640 0x002d +adapter usb product_name "STM32-PerformanceStick" +adapter usb vid_pid 0x0640 0x002d ftdi layout_init 0x0388 0x038b ftdi layout_signal nTRST -data 0x0100 diff --git a/tcl/interface/ftdi/ti-icdi.cfg b/tcl/interface/ftdi/ti-icdi.cfg index 964de76e6a..75b7152aca 100644 --- a/tcl/interface/ftdi/ti-icdi.cfg +++ b/tcl/interface/ftdi/ti-icdi.cfg @@ -9,7 +9,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0451 0xc32a +adapter usb vid_pid 0x0451 0xc32a ftdi layout_init 0x00a8 0x00eb ftdi layout_signal nSRST -noe 0x0020 diff --git a/tcl/interface/ftdi/tigard.cfg b/tcl/interface/ftdi/tigard.cfg index 43ce0ad1d1..7a14c16881 100644 --- a/tcl/interface/ftdi/tigard.cfg +++ b/tcl/interface/ftdi/tigard.cfg @@ -5,8 +5,8 @@ adapter driver ftdi -ftdi device_desc "Tigard V1.1" -ftdi vid_pid 0x0403 0x6010 +adapter usb product_name "Tigard V1.1" +adapter usb vid_pid 0x0403 0x6010 ftdi channel 1 diff --git a/tcl/interface/ftdi/tumpa-lite.cfg b/tcl/interface/ftdi/tumpa-lite.cfg index e3f12e3b12..1184146dca 100644 --- a/tcl/interface/ftdi/tumpa-lite.cfg +++ b/tcl/interface/ftdi/tumpa-lite.cfg @@ -7,7 +7,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x8a99 +adapter usb vid_pid 0x0403 0x8a99 ftdi layout_init 0x0038 0x087b ftdi layout_signal nTRST -data 0x0020 -oe 0x0020 diff --git a/tcl/interface/ftdi/tumpa.cfg b/tcl/interface/ftdi/tumpa.cfg index db4311bfe1..b28abe3432 100644 --- a/tcl/interface/ftdi/tumpa.cfg +++ b/tcl/interface/ftdi/tumpa.cfg @@ -7,7 +7,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x8a98 0x0403 0x6010 +adapter usb vid_pid 0x0403 0x8a98 0x0403 0x6010 ftdi layout_init 0x0038 0x087b ftdi layout_signal nTRST -data 0x0020 diff --git a/tcl/interface/ftdi/turtelizer2-revB.cfg b/tcl/interface/ftdi/turtelizer2-revB.cfg index f90fc58c1b..29655e6b03 100644 --- a/tcl/interface/ftdi/turtelizer2-revB.cfg +++ b/tcl/interface/ftdi/turtelizer2-revB.cfg @@ -12,8 +12,8 @@ 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 +adapter usb product_name "Turtelizer JTAG/RS232 Adapter" +adapter usb vid_pid 0x0403 0xbdc8 ftdi layout_init 0x0008 0x0c5b ftdi layout_signal nSRST -oe 0x0040 diff --git a/tcl/interface/ftdi/turtelizer2-revC.cfg b/tcl/interface/ftdi/turtelizer2-revC.cfg index 94617a1dd1..858ff6ff84 100644 --- a/tcl/interface/ftdi/turtelizer2-revC.cfg +++ b/tcl/interface/ftdi/turtelizer2-revC.cfg @@ -7,8 +7,8 @@ # adapter driver ftdi -ftdi device_desc "Turtelizer JTAG/RS232 Adapter" -ftdi vid_pid 0x0403 0xbdc8 +adapter usb product_name "Turtelizer JTAG/RS232 Adapter" +adapter usb vid_pid 0x0403 0xbdc8 ftdi layout_init 0x0008 0x0c7b ftdi layout_signal nTRST -oe 0x0020 diff --git a/tcl/interface/ftdi/um232h.cfg b/tcl/interface/ftdi/um232h.cfg index 6be08b59cb..1e7f7faa4d 100644 --- a/tcl/interface/ftdi/um232h.cfg +++ b/tcl/interface/ftdi/um232h.cfg @@ -10,8 +10,8 @@ # adapter driver ftdi -#ftdi device_desc "UM232H" -ftdi vid_pid 0x0403 0x6014 +#adapter usb product_name "UM232H" +adapter usb vid_pid 0x0403 0x6014 ftdi layout_init 0xfff8 0xfffb ftdi layout_signal nTRST -data 0x0100 -oe 0x0100 diff --git a/tcl/interface/ftdi/vpaclink.cfg b/tcl/interface/ftdi/vpaclink.cfg index ff508f2dcd..a7807ab0be 100644 --- a/tcl/interface/ftdi/vpaclink.cfg +++ b/tcl/interface/ftdi/vpaclink.cfg @@ -13,8 +13,8 @@ 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 +adapter usb product_name "VPACLink" +adapter usb vid_pid 0x0403 0x6010 ftdi layout_init 0x0508 0x0f1b ftdi layout_signal nTRST -data 0x0200 -noe 0x0100 diff --git a/tcl/interface/ftdi/xds100v2.cfg b/tcl/interface/ftdi/xds100v2.cfg index 373df4f49b..eed552a6db 100644 --- a/tcl/interface/ftdi/xds100v2.cfg +++ b/tcl/interface/ftdi/xds100v2.cfg @@ -10,7 +10,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0xa6d0 0x0403 0x6010 +adapter usb vid_pid 0x0403 0xa6d0 0x0403 0x6010 ftdi layout_init 0x0038 0x597b diff --git a/tcl/interface/ftdi/xds100v3.cfg b/tcl/interface/ftdi/xds100v3.cfg index dc722336f1..86852510d2 100644 --- a/tcl/interface/ftdi/xds100v3.cfg +++ b/tcl/interface/ftdi/xds100v3.cfg @@ -10,4 +10,4 @@ source [find interface/ftdi/xds100v2.cfg] # The USB ids are different. -ftdi vid_pid 0x0403 0xa6d1 +adapter usb vid_pid 0x0403 0xa6d1 diff --git a/tcl/interface/ftdi/xt_kc705_ml605.cfg b/tcl/interface/ftdi/xt_kc705_ml605.cfg index dda8c0a2b6..13b0e85c96 100644 --- a/tcl/interface/ftdi/xt_kc705_ml605.cfg +++ b/tcl/interface/ftdi/xt_kc705_ml605.cfg @@ -3,7 +3,7 @@ # adapter driver ftdi -ftdi vid_pid 0x0403 0x6010 +adapter usb vid_pid 0x0403 0x6010 # Specify "adapter serial " here as needed ftdi layout_init 0x0010 0x007b diff --git a/tcl/interface/hpmicro/hpmicro_evk.cfg b/tcl/interface/hpmicro/hpmicro_evk.cfg new file mode 100644 index 0000000000..c106505ac4 --- /dev/null +++ b/tcl/interface/hpmicro/hpmicro_evk.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2021 HPMicro + +adapter driver ftdi +adapter usb vid_pid 0x0403 0x6010 + +ftdi_layout_init 0x0208 0x020b +ftdi_layout_signal nTRST -data 0x0200 -noe 0x0400 +ftdi_layout_signal nSRST -data 0x0100 -noe 0x0800 diff --git a/tcl/interface/microchip/dv22s07a.cfg b/tcl/interface/microchip/dv22s07a.cfg new file mode 100644 index 0000000000..aceb0c89b7 --- /dev/null +++ b/tcl/interface/microchip/dv22s07a.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip DV22S07A OpenOCD Debug Probe +# +# https://www.microchip.com/en-us/development-tool/DV22S07A +# +# FT4232HQ-based JTAG debug probe. +# Channel A is dedicated to JTAG (2x10 IDC connector J2). +# 3.3V JTAG logic only (no level shifters). +# +# On Windows, the FT4232HQ Channel A interface requires a +# libusb-compatible driver (WinUSB, libusbK) to be used with +# OpenOCD. See the product page for installation instructions: +# https://www.microchip.com/en-us/development-tool/DV22S07A +# + +adapter driver ftdi +adapter usb vid_pid 0x0403 0x6011 +ftdi channel 0 +ftdi layout_init 0x0038 0x003b +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 +ftdi layout_signal nSRST -data 0x0020 -oe 0x0020 diff --git a/tcl/interface/microchip/embedded_flashpro5.cfg b/tcl/interface/microchip/embedded_flashpro5.cfg new file mode 100644 index 0000000000..a3adf94746 --- /dev/null +++ b/tcl/interface/microchip/embedded_flashpro5.cfg @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Embedded FlashPro5 +# +# https://www.microchip.com/en-us/development-tool/flashpro5 +# + +adapter driver ftdi + +# vidpid 1514:2008 = embedded flashpro5 +# vidpid 1514:200a = pic64gx +adapter usb vid_pid 0x1514 0x2008 0x1514 0x200a + +# That FTDI has 4 channels (channel 0 and 1 are MPSSE-capable, 2 and 3 are bitbang +ftdi channel 0 + +# Initial Layout - data[0..15] direction[0..15] +ftdi layout_init 0x0018 0xfdfb +# Signal Data Direction Notes +# AD0 TCK 0 1 (out) Port A TCK +# AD1 TDI 0 1 (out) Port A TDI +# AD2 TDO 0 0 (in) PORT A TDO +# AD3 TMS 1 1 (out) Port A TMS +# AD4 GPIOL0 1 1 (out) Port A TRST +# AD5 GPIOL1 0 1 (out) (unused) +# AD6 GPIOL2 0 1 (out) (unused) +# AD7 GPIOL3 0 1 (out) (unused) + +# BD0 TCK 0 1 (out) FTDI_UART_B_TXD +# BD1 TDI 0 0 (in) FTDI_UART_B_RXD +# BD2 TDO 0 1 (out) (unused) +# BD3 TMS 0 1 (out) (unused) +# BD4 GPIOL0 0 1 (out) (unused) +# BD5 GPIOL1 0 1 (out) (unused) +# BD6 GPIOL2 0 1 (out) (unused) +# BD7 GPIOL2 0 1 (out) (unused) + +# Signals definition +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 diff --git a/tcl/interface/nulink.cfg b/tcl/interface/nulink.cfg index be68347e73..86b0a421af 100644 --- a/tcl/interface/nulink.cfg +++ b/tcl/interface/nulink.cfg @@ -7,7 +7,7 @@ adapter driver hla hla layout nulink hla device_desc "Nu-Link" -hla vid_pid 0x0416 0x511b 0x0416 0x511c 0x0416 0x511d 0x0416 0x5200 0x0416 0x5201 +adapter usb vid_pid 0x0416 0x511b 0x0416 0x511c 0x0416 0x511d 0x0416 0x5200 0x0416 0x5201 # Only swd is supported transport select swd diff --git a/tcl/interface/openjtag.cfg b/tcl/interface/openjtag.cfg index 1602352db8..3ba5c44722 100644 --- a/tcl/interface/openjtag.cfg +++ b/tcl/interface/openjtag.cfg @@ -7,4 +7,4 @@ # adapter driver openjtag -openjtag device_desc "Open JTAG Project" +adapter usb product_name "Open JTAG Project" diff --git a/tcl/interface/parport/altium.cfg b/tcl/interface/parport/altium.cfg new file mode 100644 index 0000000000..9389d47ef1 --- /dev/null +++ b/tcl/interface/parport/altium.cfg @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows: +# +# HARD TCK - Target TCK +# HARD TMS - Target TMS +# HARD TDI - Target TDI +# HARD TDO - Target TDO +# SOFT TCK - Target TRST +# SOFT TDI - Target SRST + +adapter driver parport + +adapter gpio tdo 13 -exit-inactive +adapter gpio trst 7 -active-high -exit-inactive +adapter gpio tms 4 -exit-inactive +adapter gpio tck 3 -exit-inactive +adapter gpio tdi 2 -exit-inactive +adapter gpio srst 9 -active-high -exit-inactive +adapter gpio led 5 -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 6 -init-active -exit-inactive + +transport select jtag diff --git a/tcl/interface/parport/amt-wiggler-old.cfg b/tcl/interface/parport/amt-wiggler-old.cfg new file mode 100644 index 0000000000..bba30c8b21 --- /dev/null +++ b/tcl/interface/parport/amt-wiggler-old.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 2 -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 4 -exit-inactive +adapter gpio tdi 5 -exit-inactive +adapter gpio srst 6 -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 9 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/arm-jtag.cfg b/tcl/interface/parport/arm-jtag.cfg new file mode 100644 index 0000000000..3b2a10daac --- /dev/null +++ b/tcl/interface/parport/arm-jtag.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 2 -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 4 -exit-inactive +adapter gpio tdi 5 -exit-inactive +adapter gpio srst 6 -active-high -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 9 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/aspo.cfg b/tcl/interface/parport/aspo.cfg new file mode 100644 index 0000000000..0d14719dba --- /dev/null +++ b/tcl/interface/parport/aspo.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 13 -exit-inactive +adapter gpio trst 2 -init-active -exit-active +adapter gpio tms 4 -active-low -exit-active +adapter gpio tck 5 -exit-inactive +adapter gpio tdi 3 -active-low -init-active -exit-active +adapter gpio srst 6 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/chameleon.cfg b/tcl/interface/parport/chameleon.cfg new file mode 100644 index 0000000000..f0ebcdd50c --- /dev/null +++ b/tcl/interface/parport/chameleon.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio tms 4 -exit-inactive +adapter gpio tck 2 -exit-inactive +adapter gpio tdi 3 -exit-inactive + +transport select jtag diff --git a/tcl/interface/parport/dlc5.cfg b/tcl/interface/parport/dlc5.cfg index 24acea7a95..fb84943213 100644 --- a/tcl/interface/parport/dlc5.cfg +++ b/tcl/interface/parport/dlc5.cfg @@ -1,17 +1,16 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# # Xilinx Parallel Cable III 'DLC 5' (and various clones) -# -# http://www.xilinx.com/itp/xilinx4/data/docs/pac/appendixb.html -# - -if { [info exists PARPORTADDR] } { - set _PARPORTADDR $PARPORTADDR -} else { - set _PARPORTADDR 0 -} adapter driver parport -parport port $_PARPORTADDR -parport cable dlc5 + +adapter gpio tdo 13 -exit-inactive +adapter gpio tms 4 -exit-inactive +adapter gpio tck 3 -exit-inactive +adapter gpio tdi 2 -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 6 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/flashlink.cfg b/tcl/interface/parport/flashlink.cfg new file mode 100644 index 0000000000..b1a261d0bb --- /dev/null +++ b/tcl/interface/parport/flashlink.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 12 -active-low -exit-inactive +adapter gpio trst 6 -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 2 -exit-inactive +adapter gpio tdi 4 -exit-inactive +adapter gpio srst 7 -exit-inactive + +transport select jtag diff --git a/tcl/interface/parport/lattice.cfg b/tcl/interface/parport/lattice.cfg new file mode 100644 index 0000000000..aa7322812d --- /dev/null +++ b/tcl/interface/parport/lattice.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 10 -exit-inactive +adapter gpio trst 6 -active-high -init-active -exit-active +adapter gpio tms 4 -exit-inactive +adapter gpio tck 3 -exit-inactive +adapter gpio tdi 2 -exit-inactive +adapter gpio srst 5 -active-high -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/triton.cfg b/tcl/interface/parport/triton.cfg new file mode 100644 index 0000000000..b24d223a91 --- /dev/null +++ b/tcl/interface/parport/triton.cfg @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 5 -active-high -exit-inactive +adapter gpio tms 4 -exit-inactive +adapter gpio tck 2 -exit-inactive +adapter gpio tdi 3 -exit-inactive + +transport select jtag diff --git a/tcl/interface/parport/wiggler-ntrst-inverted.cfg b/tcl/interface/parport/wiggler-ntrst-inverted.cfg new file mode 100644 index 0000000000..3b2fc0f289 --- /dev/null +++ b/tcl/interface/parport/wiggler-ntrst-inverted.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 6 -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 4 -exit-inactive +adapter gpio tdi 5 -exit-inactive +adapter gpio srst 2 -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 9 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/wiggler.cfg b/tcl/interface/parport/wiggler.cfg index b9fceeb852..84c1c83026 100644 --- a/tcl/interface/parport/wiggler.cfg +++ b/tcl/interface/parport/wiggler.cfg @@ -1,21 +1,16 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# -# Parallel port wiggler (many clones available) on port 0x378 -# -# Addresses: 0x378/LPT1 or 0x278/LPT2 ... -# +adapter driver parport -if { [info exists PARPORTADDR] } { - set _PARPORTADDR $PARPORTADDR -} else { - if {$tcl_platform(platform) eq "windows"} { - set _PARPORTADDR 0x378 - } { - set _PARPORTADDR 0 - } -} +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 6 -active-high -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 4 -exit-inactive +adapter gpio tdi 5 -exit-inactive +adapter gpio srst 2 -exit-inactive -adapter driver parport -parport port $_PARPORTADDR -parport cable wiggler +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 9 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/wiggler2.cfg b/tcl/interface/parport/wiggler2.cfg new file mode 100644 index 0000000000..839e7f9b46 --- /dev/null +++ b/tcl/interface/parport/wiggler2.cfg @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 6 -active-high -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 4 -exit-inactive +adapter gpio tdi 5 -exit-inactive +adapter gpio srst 2 -exit-inactive +adapter gpio led 7 -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 9 -init-active -exit-inactive + +transport select jtag diff --git a/tcl/interface/raspberrypi-native.cfg b/tcl/interface/raspberrypi-native.cfg index c80f90a146..1eb9761eea 100644 --- a/tcl/interface/raspberrypi-native.cfg +++ b/tcl/interface/raspberrypi-native.cfg @@ -50,12 +50,12 @@ 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 + set speed_offset 31 } elseif {[string match *bcm2836* $compat] || [string match *bcm2709* $compat]} { - set speed_offset 36 + set speed_offset 25 } elseif {[string match *bcm2835* $compat] || [string match *bcm2708* $compat]} { set clocks_per_timing_loop 6 - set speed_offset 32 + set speed_offset 23 } elseif {[string match *bcm2712* $compat]} { echo "Error: Raspberrypi Pi 5 has moved GPIOs to PCIe connected RP1 chip." echo "Error: Native GPIO handling is not supported, use 'raspberrypi5-gpiod.cfg'" diff --git a/tcl/interface/stlink-hla.cfg b/tcl/interface/stlink-hla.cfg index 5c4adb8973..adbfda8e20 100644 --- a/tcl/interface/stlink-hla.cfg +++ b/tcl/interface/stlink-hla.cfg @@ -11,7 +11,9 @@ echo "Consider updating your ST-Link firmware to a version >= V2J24 (2015)" adapter driver hla hla layout stlink hla device_desc "ST-LINK" -hla vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 +adapter usb vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d \ + 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 \ + 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 # Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 # devices seem to have serial numbers with unreadable characters. ST-LINK/V2 diff --git a/tcl/interface/stlink.cfg b/tcl/interface/stlink.cfg index 48c5656615..972a51690b 100644 --- a/tcl/interface/stlink.cfg +++ b/tcl/interface/stlink.cfg @@ -17,7 +17,9 @@ if { [adapter name] == "hla" } { } adapter driver st-link -st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 +adapter usb 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 jtag # transport select swd diff --git a/tcl/interface/ti-icdi.cfg b/tcl/interface/ti-icdi.cfg index c13d27e8b1..fdd879a7e9 100644 --- a/tcl/interface/ti-icdi.cfg +++ b/tcl/interface/ti-icdi.cfg @@ -11,7 +11,7 @@ adapter driver hla hla layout ti-icdi -hla vid_pid 0x1cbe 0x00fd +adapter usb 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 diff --git a/tcl/interface/usb-jtag.cfg b/tcl/interface/usb-jtag.cfg index 039c748b37..c7f3d60c24 100644 --- a/tcl/interface/usb-jtag.cfg +++ b/tcl/interface/usb-jtag.cfg @@ -32,7 +32,7 @@ # driver but ixo-usb-jtag requires the ftdi driver. adapter driver usb_blaster -usb_blaster vid_pid 0x16C0 0x06AD +adapter usb 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. diff --git a/tcl/interface/vdebug.cfg b/tcl/interface/vdebug.cfg index 63a5955067..27a8aafd7b 100644 --- a/tcl/interface/vdebug.cfg +++ b/tcl/interface/vdebug.cfg @@ -30,4 +30,4 @@ tcl port disabled vdebug batching 1 # Polling values -vdebug polling 100 1000 +vdebug polling 100 500 diff --git a/tcl/target/1986Be1T.cfg "b/tcl/target/1986\320\262\320\2651\321\202.cfg" similarity index 100% rename from tcl/target/1986Be1T.cfg rename to "tcl/target/1986\320\262\320\2651\321\202.cfg" diff --git a/tcl/target/allwinner_h618.cfg b/tcl/target/allwinner_h618.cfg new file mode 100644 index 0000000000..98d3ace0de --- /dev/null +++ b/tcl/target/allwinner_h618.cfg @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Allwinner H618 chip. It is an updated version of the Allwinner H616. + +# Information is available on linux-sunxi.org: +# Datasheet: https://linux-sunxi.org/images/b/b9/H616_Datasheet_V1.0_cleaned.pdf +# Manual: https://linux-sunxi.org/images/2/24/H616_User_Manual_V1.0_cleaned.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME h618 +} + +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 0x5ba00477 +} + +set _cores 4 +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 1 + +# these addresses are obtained from the ROM table via 'dap info 1' command +set _DBGBASE {0x81410000 0x81510000 0x81610000 0x81710000} +set _CTIBASE {0x81420000 0x81520000 0x81620000 0x81720000} + +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 1 -baseaddr [lindex $_CTIBASE $_core] + target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 1 -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/altera_fpgasoc.cfg b/tcl/target/altera_fpgasoc.cfg index a98b346c6c..00ebb37263 100644 --- a/tcl/target/altera_fpgasoc.cfg +++ b/tcl/target/altera_fpgasoc.cfg @@ -48,7 +48,6 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_TARGETNAME1 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80110000 -$_TARGETNAME1 configure -event reset-start { adapter speed 1000 } $_TARGETNAME1 configure -event reset-assert-post "cycv_dbginit $_TARGETNAME1" @@ -56,7 +55,6 @@ $_TARGETNAME1 configure -event reset-assert-post "cycv_dbginit $_TARGETNAME1" #target create $_TARGETNAME2 cortex_a -dap $_CHIPNAME.dap \ # -coreid 1 -dbgbase 0x80112000 -#$_TARGETNAME2 configure -event reset-start { adapter speed 1000 } #$_TARGETNAME2 configure -event reset-assert-post "cycv_dbginit $_TARGETNAME2" proc cycv_dbginit {target} { diff --git a/tcl/target/artery/at32f4x.cfg b/tcl/target/artery/at32f4x.cfg new file mode 100644 index 0000000000..c299aa9040 --- /dev/null +++ b/tcl/target/artery/at32f4x.cfg @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Configuration file for Artery AT32F4x family. +# +# https://www.arterychip.com/en/product/ +# + +# AT32F4x devices support JTAG and SWD transport. +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME at32f4x +} + +# 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 0x1ba01477 + } +} + +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 little -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME artery 0x08000000 0 0 0 $_TARGETNAME + +adapter speed 1000 + +if {![using_hla]} { + cortex_m reset_config sysresetreq +} diff --git a/tcl/target/at91samdXX.cfg b/tcl/target/at91samdXX.cfg index 5132109ba8..893854309f 100644 --- a/tcl/target/at91samdXX.cfg +++ b/tcl/target/at91samdXX.cfg @@ -7,7 +7,7 @@ # # samdXX devices only support SWD transports. # -source [find target/swj-dp.tcl] +transport select swd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -15,12 +15,6 @@ if { [info exists CHIPNAME] } { set _CHIPNAME at91samd } -if { [info exists ENDIAN] } { - set _ENDIAN $ENDIAN -} else { - set _ENDIAN little -} - # Work-area is a space in RAM used for flash programming # By default use 2kB if { [info exists WORKAREASIZE] } { @@ -35,11 +29,11 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x4ba00477 } -swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -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 +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/atsame5x.cfg b/tcl/target/atsame5x.cfg index 5093d41b09..0f759a242c 100644 --- a/tcl/target/atsame5x.cfg +++ b/tcl/target/atsame5x.cfg @@ -8,7 +8,7 @@ # # Devices only support SWD transports. # -source [find target/swj-dp.tcl] +transport select swd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -16,12 +16,6 @@ if { [info exists CHIPNAME] } { set _CHIPNAME atsame5 } -if { [info exists ENDIAN] } { - set _ENDIAN $ENDIAN -} else { - set _ENDIAN little -} - # Work-area is a space in RAM used for flash programming # By default use 32kB (the smallest RAM size is 128kB) if { [info exists WORKAREASIZE] } { @@ -36,11 +30,11 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x4ba00477 } -swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -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 +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/atsamv.cfg b/tcl/target/atsamv.cfg index 7e9f6c57ef..9fd89795b6 100644 --- a/tcl/target/atsamv.cfg +++ b/tcl/target/atsamv.cfg @@ -41,6 +41,11 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20400000 -work-area-size $_WORKAREASIZE -work-area-backup 0 +$_TARGETNAME configure -event reset-init { + # WDT_MR = WDDIS (disable watchdog) + mww 0x400E1854 0x8000 +} + adapter speed 1800 if {![using_hla]} { @@ -58,4 +63,6 @@ if {![using_hla]} { } set _FLASHNAME $_CHIPNAME.flash +set _SIGNATURENAME $_CHIPNAME.usersignature flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME +flash bank $_SIGNATURENAME atsamv 0x100000000 0 0 0 $_TARGETNAME diff --git a/tcl/target/bcm2711.cfg b/tcl/target/bcm2711.cfg index f8d2b3a65b..9704daf812 100644 --- a/tcl/target/bcm2711.cfg +++ b/tcl/target/bcm2711.cfg @@ -3,8 +3,8 @@ # 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/ +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2711 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/bcm2835.cfg b/tcl/target/bcm2835.cfg index 32a03666c4..645588730d 100644 --- a/tcl/target/bcm2835.cfg +++ b/tcl/target/bcm2835.cfg @@ -3,8 +3,8 @@ # 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 +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2835 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/bcm2836.cfg b/tcl/target/bcm2836.cfg index 04921315ed..695426e7a8 100644 --- a/tcl/target/bcm2836.cfg +++ b/tcl/target/bcm2836.cfg @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# The Broadcom chip used in the Raspberry Pi 2 Model B +# The Broadcom chip used in the Raspberry Pi 2 Model B v1.1 -# Partial information is available in raspberry pi website: -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836 +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2836 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/bcm2837.cfg b/tcl/target/bcm2837.cfg index 749de31037..d41892c431 100644 --- a/tcl/target/bcm2837.cfg +++ b/tcl/target/bcm2837.cfg @@ -3,9 +3,9 @@ # 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 +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2837 +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2837b0 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/bl602.cfg b/tcl/target/bl602.cfg index d110d3e3bd..97c16a6628 100644 --- a/tcl/target/bl602.cfg +++ b/tcl/target/bl602.cfg @@ -24,6 +24,8 @@ set CPUTAPID 0x20000c05 set WORKAREAADDR 0x42014000 set WORKAREASIZE 0xC000 +set FLASH_CHIP_TYPE bl602 + source [find target/bl602_common.cfg] # JTAG reset is broken. Read comment of bl602_sw_reset_hbn_wait function for more information diff --git a/tcl/target/bl602_common.cfg b/tcl/target/bl602_common.cfg index cf4bc3947c..da687d291f 100644 --- a/tcl/target/bl602_common.cfg +++ b/tcl/target/bl602_common.cfg @@ -37,15 +37,24 @@ set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME riscv set_mem_access sysbus -riscv set_enable_virt2phys off +riscv virt2phys_mode off $_TARGETNAME configure -work-area-phys $_WORKAREAADDR -work-area-size $_WORKAREASIZE -work-area-backup 1 # Internal RC ticks on 32 MHz, so this speed should be safe to use. adapter speed 8000 -# Useful functions +if { [info exists FLASH_CHIP_TYPE] } { + set _FLASHNAME $_CHIPNAME.flash + flash bank $_FLASHNAME bl602 0x23000000 0 0 0 $_TARGETNAME $FLASH_CHIP_TYPE + $_TARGETNAME configure -event reset-init { + # Probing of Flash is required to initialize SFlash from unknown state. + flash probe 0 + } +} + +# Useful functions set dmcontrol 0x10 set dmcontrol_dmactive [expr {1 << 0}] set dmcontrol_ndmreset [expr {1 << 1}] diff --git a/tcl/target/bl616.cfg b/tcl/target/bl616.cfg new file mode 100644 index 0000000000..6f00c05464 --- /dev/null +++ b/tcl/target/bl616.cfg @@ -0,0 +1,145 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Author: Marek Kraus + +# +# Bouffalo Labs BL616 and BL618 target +# +# Default JTAG pins: (if not changed by eFuse configuration) +# TMS - GPIO0 +# TCK - GPIO1 +# TDO - GPIO2 +# TDI - GPIO3 +# + +source [find mem_helper.tcl] + +transport select jtag + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bl616 +} + +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10000b6f + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME riscv -chain-position $_TARGETNAME + +riscv set_mem_access progbuf +riscv virt2phys_mode off + +$_TARGETNAME configure -work-area-phys 0x40000000 -work-area-size 0x10000 -work-area-backup 1 + +adapter speed 4000 + +# Useful functions +set dmcontrol 0x10 +set dmcontrol_dmactive [expr {1 << 0}] +set dmcontrol_haltreq [expr {1 << 31}] + +# By spec, ndmreset should reset whole chip. This implementation resets only few parts of the chip. +# CTRL_PWRON_RESET register in GLB core triggers full "power-on like" reset, so we use it instead +# for full software reset. +$_TARGETNAME configure -event reset-assert { + halt + + # To stay in BootROM until JTAG re-attaches, we are using BootROM functionality + # to force ISP mode, so BootROM looks out for external ISP communication. + + # In HBN_RSV2, set HBN_RELEASE_CORE to HBN_RELEASE_CORE_FLAG (4) + # and HBN_USER_BOOT_SEL to 1 (ISP) + mww 0x2000f108 0x44000000 + + # Switch clock to internal RC32M + # In HBN_GLB, set ROOT_CLK_SEL = 0 + mmw 0x2000f030 0x0 0x00000002 + + # In GLB_SYS_CFG0, set REG_BCLK_DIV and REG_HCLK_DIV = 0 + mmw 0x20000090 0x0 0x00FFFF00 + + # Trigger BCLK ACT pulse + # In GLB_SYS_CFG1, set BCLK_DIV_ACT_PULSE = 1 + mmw 0x20000094 0x1 0x00000001 + # In GLB_SYS_CFG1, wait for GLB_STS_BCLK_PROT_DONE to become 1 + while { [expr {[mrw 0x20000094] & 4}] == 0 } { sleep 1 } + + # In GLB_SWRST_CFG2, clear CTRL_PWRON_RESET + mmw 0x20000548 0x0 0x00000001 + + # This Software reset method resets everything, so CPU as well. + # It does that in not much good way, resulting in Debug Module being reset as well. + # This also means, that right after CPU and Debug Module are turned on, we need to + # enable Debug Module and halt CPU if needed. Additionally, we trigger this SW reset + # through program buffer access directly with DMI commands, to avoid errors printed by + # OpenOCD about unsuccessful register write. + + # In GLB_SWRST_CFG2, set CTRL_PWRON_RESET to 1 + set_reg {fp 0x20000548 s1 0x01} + riscv dmi_write 0x20 0x00942023 + riscv dmi_write 0x17 0x40000 + + # We need to wait for chip to finish reset and execute BootROM + sleep 10 + + # JTAG Debug Transport Module is reset as well, so we need to get into RUN/IDLE state + runtest 10 + + # We need to enable Debug Module and halt the CPU, so we can reset Program Counter + # and to do additional clean-ups. If reset was called without halt, resume is handled + # by reset-deassert-post event handler. + + # In Debug Module Control (dmcontrol), set dmactive to 1 and then haltreq to 1 + riscv dmi_write $::dmcontrol $::dmcontrol_dmactive + riscv dmi_write $::dmcontrol [ expr {$::dmcontrol_dmactive | $::dmcontrol_haltreq} ] +} + +$_TARGETNAME configure -event reset-deassert-post { + # Set Program Counter to start of BootROM and execute one instruction + step 0x90000000 + + # When using default JTAG pinout, BOOT pin is the same as JTAG TDO pin. + # Since after reset we set PC to start of the BootROM, + # BootROM will execute also check of BOOT pin, which will disable TDO pin, + # to check the BOOT pin state. This leads to temporary loss of JTAG access + # and causes (recoverable) errors in OpenOCD. We can bypass the BOOT pin check + # function, by forcing booting from Media/SPI Flash. + + # In HBN_RSV2, set HBN_RELEASE_CORE to HBN_RELEASE_CORE_FLAG (4) + # and HBN_USER_BOOT_SEL to 2 (Media/SPI Flash) + mww 0x2000f108 0x48000000 + + # Resume the processor if reset was triggered without halt request + if {$halt == 0} { + resume + } +} + +# According to JTAG spec (IEEE 1149.1), when chip enters "Test-Logic-Reset" state, +# the IR instruction should be set to "IDCODE" or "BYPASS" (when chip does not have IDCODE). +# This is done so automatic chain scan can detect all the chips within JTAG chain without knowing IDCODE. +# JTAG Debug Transport Module (DTM) used in this chip, developed by T-Head (formerly C-Sky) +# does not implement this, so OpenOCD can't detect the chip anymore after the IR instruction is changed. +# This workaround gets chip into known state, and manually set IR instruction to IDCODE, +# which is 0x01, standardized by RISC-V Debug Specification. +proc init_reset { mode } { + if {[using_jtag]} { + # Get JTAG SM to known state + runtest 10 + # Set IR to IDCODE + irscan $::_CHIPNAME.cpu 0x01 + jtag arp_init-reset + } +} + +proc jtag_init {} { + # Get JTAG SM to known state + runtest 10 + # Set IR to IDCODE + irscan $::_CHIPNAME.cpu 0x01 + + if {[catch {jtag arp_init} err]!=0} { + # try resetting additionally + init_reset startup + } +} diff --git a/tcl/target/bl702.cfg b/tcl/target/bl702.cfg index 8caf06ebe1..39d95cb7b5 100644 --- a/tcl/target/bl702.cfg +++ b/tcl/target/bl702.cfg @@ -24,6 +24,8 @@ set CPUTAPID 0x20000e05 set WORKAREAADDR 0x22014000 set WORKAREASIZE 0xC000 +set FLASH_CHIP_TYPE bl702 + source [find target/bl602_common.cfg] # JTAG reset is broken. Read comment of bl602_sw_reset_hbn_wait function for more information diff --git a/tcl/target/bl702l.cfg b/tcl/target/bl702l.cfg index 467dd8ce6b..357636a110 100644 --- a/tcl/target/bl702l.cfg +++ b/tcl/target/bl702l.cfg @@ -25,6 +25,8 @@ set CPUTAPID 0x20000e05 set WORKAREAADDR 0x42020000 set WORKAREASIZE 0x10000 +set FLASH_CHIP_TYPE bl702l + source [find target/bl602_common.cfg] # JTAG reset is broken. Read comment of bl602_sw_reset function for more information diff --git a/tcl/target/bluenrg-x.cfg b/tcl/target/bluenrg-x.cfg index afa1b513b2..ad6f1c43fb 100644 --- a/tcl/target/bluenrg-x.cfg +++ b/tcl/target/bluenrg-x.cfg @@ -20,7 +20,7 @@ set _ENDIAN little if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x5F00 + set _WORKAREASIZE 0x3C00 } adapter speed 4000 diff --git a/tcl/target/efm32.cfg b/tcl/target/efm32.cfg index 2187c0aca4..fe793d0f59 100644 --- a/tcl/target/efm32.cfg +++ b/tcl/target/efm32.cfg @@ -1,55 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-or-later +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026 Silicon Laboratories Inc. -# -# Silicon Labs (formerly Energy Micro) EFM32 target -# -# Note: All EFM32 chips have SWD support, but only newer series 1 -# chips have JTAG support. -# - -source [find target/swj-dp.tcl] - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME efm32 -} - -# Work-area is a space in RAM used for flash programming -# By default use 2kB -if { [info exists WORKAREASIZE] } { - set _WORKAREASIZE $WORKAREASIZE -} else { - set _WORKAREASIZE 0x800 -} - -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - if { [using_jtag] } { - set _CPUTAPID 0x4ba00477 - } { - set _CPUTAPID 0x2ba01477 - } -} - -swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID -dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu - -adapter speed 1000 - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap - -$_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 - -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 - # perform a soft reset - cortex_m reset_config sysresetreq -} +source [find target/silabs/series0.cfg] diff --git a/tcl/target/esp32.cfg b/tcl/target/esp32.cfg index b30a170247..0803296127 100644 --- a/tcl/target/esp32.cfg +++ b/tcl/target/esp32.cfg @@ -5,14 +5,14 @@ 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 +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 diff --git a/tcl/target/esp32c2.cfg b/tcl/target/esp32c2.cfg index 51de1d1a30..a22fe7088c 100644 --- a/tcl/target/esp32c2.cfg +++ b/tcl/target/esp32c2.cfg @@ -5,61 +5,68 @@ source [find target/esp_common.cfg] # Target specific global variables -set _CHIPNAME "esp32c2" -set _CPUTAPID 0x0000cc25 -set _ESP_ARCH "riscv" -set _ONLYCPU 1 -set _ESP_SMP_TARGET 0 -set _ESP_SMP_BREAK 0 -set _ESP_EFUSE_MAC_ADDR_REG 0x60008840 +set _CHIPNAME "esp32c2" +set _CPUTAPID "0x0000cc25" +set _ESP_ARCH "riscv" +set _ONLYCPU 1 +set _ESP_SMP_TARGET 0 +set _ESP_SMP_BREAK 0 +set _ESP_EFUSE_MAC_ADDR_REG 0x60008840 # Target specific functions should be implemented for each riscv chips. proc esp32c2_wdt_disable { } { - # Halt event can occur during config phase (before "init" is done). - # Ignore it since mww commands don't work at that time. - if { [string compare [command mode] config] == 0 } { - return - } - - # Timer Group 0 WDT - mww 0x6001f064 0x50D83AA1 - mww 0x6001F048 0 - # RTC WDT - mww 0x6000809C 0x50D83AA1 - mww 0x60008084 0 - # SWD - mww 0x600080A4 0x8F1D312A - mww 0x600080A0 0x84B00000 + # Halt event can occur during config phase (before "init" is done). + # Ignore it since mww commands don't work at that time. + if { [string compare [command mode] config] == 0 } { + return + } + + # Disable Timer Group 0 WDT + mww 0x6001f064 0x50D83AA1 + mww 0x6001F048 0 + # Clear TG0 wdt interrupt state + mww 0x6001F07C 0x2 + + # Disable RTC WDT + mww 0x6000809C 0x50D83AA1 + mww 0x60008084 0 + + # Disable Super WDT + mww 0x600080A4 0x8F1D312A + mww 0x600080A0 0x84B00000 + + # Clear RTC and Super wdt interrupt states + mww 0x60008044 0x8008 } proc esp32c2_soc_reset { } { global _RISCV_DMCONTROL - # This procedure does "digital system reset", i.e. resets - # all the peripherals except for the RTC block. - # It is called from reset-assert-post target event callback, - # after assert_reset procedure was called. - # Since we need the hart to to execute a write to RTC_CNTL_SW_SYS_RST, - # temporarily take it out of reset. Save the dmcontrol state before - # doing so. - riscv dmi_write $_RISCV_DMCONTROL 0x80000001 - # Trigger the reset - mww 0x60008000 0x9c00a000 - # Workaround for stuck in cpu start during calibration. - # By writing zero to TIMG_RTCCALICFG_REG, we are disabling calibration - mww 0x6001F068 0 - # Wait for the reset to happen - sleep 10 - poll - # Disable the watchdogs again - esp32c2_wdt_disable - - # Here debugger reads allresumeack and allhalted bits as set (0x330a2) - # We will clean allhalted state by resuming the core. - riscv dmi_write $_RISCV_DMCONTROL 0x40000001 - - # Put the hart back into reset state. Note that we need to keep haltreq set. - riscv dmi_write $_RISCV_DMCONTROL 0x80000003 + # This procedure does "digital system reset", i.e. resets + # all the peripherals except for the RTC block. + # It is called from reset-assert-post target event callback, + # after assert_reset procedure was called. + # Since we need the hart to execute a write to RTC_CNTL_SW_SYS_RST, + # temporarily take it out of reset. Save the dmcontrol state before + # doing so. + riscv dmi_write $_RISCV_DMCONTROL 0x80000001 + # Trigger the reset + mww 0x60008000 0x9c00a000 + # Workaround for stuck in cpu start during calibration. + # By writing zero to TIMG_RTCCALICFG_REG, we are disabling calibration + mww 0x6001F068 0 + # Wait for the reset to happen + sleep 10 + poll + # Disable the watchdogs again + esp32c2_wdt_disable + + # Here debugger reads allresumeack and allhalted bits as set (0x330a2) + # We will clean allhalted state by resuming the core. + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 + + # Put the hart back into reset state. Note that we need to keep haltreq set. + riscv dmi_write $_RISCV_DMCONTROL 0x80000003 } proc esp32c2_memprot_is_enabled { } { @@ -87,26 +94,26 @@ proc esp32c2_memprot_is_enabled { } { riscv dmi_write $_RISCV_ABS_CMD 0x2203b3 set pmpaddr3 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] - set IRAM_LOW 0x40380000 - set IRAM_HIGH 0x403C0000 - set DRAM_LOW 0x3FCA0000 - set DRAM_HIGH 0x3FCE0000 + set IRAM_LOW 0x40380000 + set IRAM_HIGH 0x403C0000 + set DRAM_LOW 0x3FCA0000 + set DRAM_HIGH 0x3FCE0000 set PMP_RWX 0x07 - set PMP_RW 0x03 + set PMP_RW 0x03 # The lock bit remains unset during the execution of the 2nd stage bootloader. # Thus we do not perform a lock bit check for IRAM and DRAM regions. # Check OpenOCD can write and execute from IRAM. if {$pmpaddr0 >= $IRAM_LOW && $pmpaddr1 <= $IRAM_HIGH} { - if {($pmp0cfg & $PMP_RWX) != 0 || ($pmp1cfg & $PMP_RWX) != $PMP_RWX} { + if {($pmp0cfg & $PMP_RWX) != 0 || ($pmp1cfg & $PMP_RWX) != $PMP_RWX} { return 1 } } # Check OpenOCD can read/write entire DRAM region. if {$pmpaddr2 >= $DRAM_LOW && $pmpaddr3 <= $DRAM_HIGH} { - if {($pmp2cfg & $PMP_RW) != 0 && ($pmp3cfg & $PMP_RW) != $PMP_RW} { + if {($pmp2cfg & $PMP_RW) != 0 && ($pmp3cfg & $PMP_RW) != $PMP_RW} { return 1 } } diff --git a/tcl/target/esp32c3.cfg b/tcl/target/esp32c3.cfg index 4dca6533c8..fea14d7c71 100644 --- a/tcl/target/esp32c3.cfg +++ b/tcl/target/esp32c3.cfg @@ -5,33 +5,44 @@ source [find target/esp_common.cfg] # Target specific global variables -set _CHIPNAME "esp32c3" -set _CPUTAPID 0x00005c25 -set _ESP_ARCH "riscv" -set _ONLYCPU 1 -set _ESP_SMP_TARGET 0 -set _ESP_SMP_BREAK 0 -set _ESP_EFUSE_MAC_ADDR_REG 0x60008844 +set _CHIPNAME "esp32c3" +set _CPUTAPID "0x00005c25" +set _ESP_ARCH "riscv" +set _ONLYCPU 1 +set _ESP_SMP_TARGET 0 +set _ESP_SMP_BREAK 0 +set _ESP_EFUSE_MAC_ADDR_REG 0x60008844 # Target specific functions should be implemented for each riscv chips. proc esp32c3_wdt_disable { } { - # Halt event can occur during config phase (before "init" is done). - # Ignore it since mww commands don't work at that time. - if { [string compare [command mode] config] == 0 } { - return - } + # Halt event can occur during config phase (before "init" is done). + # Ignore it since mww commands don't work at that time. + if { [string compare [command mode] config] == 0 } { + return + } - # Timer Group 0 & 1 WDTs - mww 0x6001f064 0x50D83AA1 - mww 0x6001F048 0 - mww 0x60020064 0x50D83AA1 - mww 0x60020048 0 - # RTC WDT - mww 0x600080a8 0x50D83AA1 - mww 0x60008090 0 - # SWD - mww 0x600080b0 0x8F1D312A - mww 0x600080ac 0x84B00000 + # Disable Timer Group 0 WDT + mww 0x6001f064 0x50D83AA1 + mww 0x6001F048 0 + # Clear TG0 wdt interrupt state + mww 0x6001F07C 0x2 + + # Disable Timer Group 1 WDT + mww 0x60020064 0x50D83AA1 + mww 0x60020048 0 + # Clear TG1 wdt interrupt state + mww 0x6002007C 0x2 + + # Disable RTC WDT + mww 0x600080a8 0x50D83AA1 + mww 0x60008090 0 + + # Disable Super WDT + mww 0x600080b0 0x8F1D312A + mww 0x600080ac 0x84B00000 + + # Clear RTC and Super wdt interrupt states + mww 0x6000804C 0x8008 } # This is almost identical with the esp32c2_soc_reset. @@ -39,43 +50,43 @@ proc esp32c3_wdt_disable { } { proc esp32c3_soc_reset { } { global _RISCV_DMCONTROL - # This procedure does "digital system reset", i.e. resets - # all the peripherals except for the RTC block. - # It is called from reset-assert-post target event callback, - # after assert_reset procedure was called. - # Since we need the hart to to execute a write to RTC_CNTL_SW_SYS_RST, - # temporarily take it out of reset. Save the dmcontrol state before - # doing so. - riscv dmi_write $_RISCV_DMCONTROL 0x80000001 - # Trigger the reset - mww 0x60008000 0x9c00a000 - # Workaround for stuck in cpu start during calibration. - # By writing zero to TIMG_RTCCALICFG_REG, we are disabling calibration - mww 0x6001F068 0 - # Wait for the reset to happen - sleep 10 - poll - # Disable the watchdogs again - esp32c3_wdt_disable + # This procedure does "digital system reset", i.e. resets + # all the peripherals except for the RTC block. + # It is called from reset-assert-post target event callback, + # after assert_reset procedure was called. + # Since we need the hart to execute a write to RTC_CNTL_SW_SYS_RST, + # temporarily take it out of reset. Save the dmcontrol state before + # doing so. + riscv dmi_write $_RISCV_DMCONTROL 0x80000001 + # Trigger the reset + mww 0x60008000 0x9c00a000 + # Workaround for stuck in cpu start during calibration. + # By writing zero to TIMG_RTCCALICFG_REG, we are disabling calibration + mww 0x6001F068 0 + # Wait for the reset to happen + sleep 10 + poll + # Disable the watchdogs again + esp32c3_wdt_disable - # Here debugger reads allresumeack and allhalted bits as set (0x330a2) - # We will clean allhalted state by resuming the core. - riscv dmi_write $_RISCV_DMCONTROL 0x40000001 + # Here debugger reads allresumeack and allhalted bits as set (0x330a2) + # We will clean allhalted state by resuming the core. + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 - # Put the hart back into reset state. Note that we need to keep haltreq set. - riscv dmi_write $_RISCV_DMCONTROL 0x80000003 + # Put the hart back into reset state. Note that we need to keep haltreq set. + riscv dmi_write $_RISCV_DMCONTROL 0x80000003 } proc esp32c3_memprot_is_enabled { } { - # IRAM0 PMS lock, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG - if { [get_mmr_bit 0x600C10A8 0] != 0 } { - return 1 - } - # DRAM0 PMS lock, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG - if { [get_mmr_bit 0x600C10C0 0] != 0 } { - return 1 - } - return 0 + # IRAM0 PMS lock, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG + if { [get_mmr_bit 0x600C10A8 0] != 0 } { + return 1 + } + # DRAM0 PMS lock, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG + if { [get_mmr_bit 0x600C10C0 0] != 0 } { + return 1 + } + return 0 } create_esp_target $_ESP_ARCH diff --git a/tcl/target/esp32c6.cfg b/tcl/target/esp32c6.cfg index 14b6a9190c..4299a0b551 100644 --- a/tcl/target/esp32c6.cfg +++ b/tcl/target/esp32c6.cfg @@ -5,75 +5,85 @@ source [find target/esp_common.cfg] # Target specific global variables -set _CHIPNAME "esp32c6" -set _CPUTAPID 0x0000dc25 -set _ESP_ARCH "riscv" -set _ONLYCPU 1 -set _ESP_SMP_TARGET 0 -set _ESP_SMP_BREAK 0 -set _ESP_EFUSE_MAC_ADDR_REG 0x600B0844 +set _CHIPNAME "esp32c6" +set _CPUTAPID 0x0000dc25 +set _ESP_ARCH "riscv" +set _ONLYCPU 1 +set _ESP_SMP_TARGET 0 +set _ESP_SMP_BREAK 0 +set _ESP_EFUSE_MAC_ADDR_REG 0x600B0844 # Target specific functions should be implemented for each riscv chips. proc esp32c6_wdt_disable { } { - # Halt event can occur during config phase (before "init" is done). - # Ignore it since mww commands don't work at that time. - if { [string compare [command mode] config] == 0 } { - return - } - - # Timer Group 0 & 1 WDTs - mww 0x60008064 0x50D83AA1 - mww 0x60008048 0 - mww 0x60009064 0x50D83AA1 - mww 0x60009048 0 - # LP_WDT_RTC - mww 0x600b1c18 0x50D83AA1 - mww 0x600B1C00 0 - # LP_WDT_SWD - mww 0x600b1c20 0x50D83AA1 - mww 0x600b1c1c 0x40000000 + # Halt event can occur during config phase (before "init" is done). + # Ignore it since mww commands don't work at that time. + if { [string compare [command mode] config] == 0 } { + return + } + + # Disable Timer Group 0 WDT + mww 0x60008064 0x50D83AA1 + mww 0x60008048 0 + # Clear TG0 wdt interrupt state + mww 0x6000807C 0x2 + + # Disable Timer Group 1 WDT + mww 0x60009064 0x50D83AA1 + mww 0x60009048 0 + # Clear TG1 wdt interrupt state + mww 0x6000907C 0x2 + + # Disable LP_WDT_RTC + mww 0x600b1c18 0x50D83AA1 + mww 0x600B1c00 0 + # Disable LP_WDT_SWD + mww 0x600b1c20 0x50D83AA1 + mww 0x600b1c1c 0x40000000 + + # Clear LP_WDT_RTC and LP_WDT_SWD interrupt states + mww 0x600B1c30 0xC0000000 } proc esp32c6_soc_reset { } { global _RISCV_DMCONTROL _RISCV_SB_CS _RISCV_SB_ADDR0 _RISCV_SB_DATA0 - riscv dmi_write $_RISCV_DMCONTROL 0x80000001 - riscv dmi_write $_RISCV_SB_CS 0x48000 - riscv dmi_write $_RISCV_SB_ADDR0 0x600b1034 - riscv dmi_write $_RISCV_SB_DATA0 0x80000000 - # clear dmactive to clear sbbusy otherwise debug module gets stuck - riscv dmi_write $_RISCV_DMCONTROL 0 + riscv dmi_write $_RISCV_DMCONTROL 0x80000001 + riscv dmi_write $_RISCV_SB_CS 0x48000 + riscv dmi_write $_RISCV_SB_ADDR0 0x600b1034 + riscv dmi_write $_RISCV_SB_DATA0 0x80000000 + # clear dmactive to clear sbbusy otherwise debug module gets stuck + riscv dmi_write $_RISCV_DMCONTROL 0 - riscv dmi_write $_RISCV_SB_CS 0x48000 - riscv dmi_write $_RISCV_SB_ADDR0 0x600b1038 - riscv dmi_write $_RISCV_SB_DATA0 0x10000000 + riscv dmi_write $_RISCV_SB_CS 0x48000 + riscv dmi_write $_RISCV_SB_ADDR0 0x600b1038 + riscv dmi_write $_RISCV_SB_DATA0 0x10000000 - # clear dmactive to clear sbbusy otherwise debug module gets stuck - riscv dmi_write $_RISCV_DMCONTROL 0 - riscv dmi_write $_RISCV_DMCONTROL 0x40000001 - # Here debugger reads dmstatus as 0xc03a2 + # clear dmactive to clear sbbusy otherwise debug module gets stuck + riscv dmi_write $_RISCV_DMCONTROL 0 + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 + # Here debugger reads dmstatus as 0xc03a2 - # Wait for the reset to happen - sleep 10 - poll - # Here debugger reads dmstatus as 0x3a2 + # Wait for the reset to happen + sleep 10 + poll + # Here debugger reads dmstatus as 0x3a2 - # Disable the watchdogs again - esp32c6_wdt_disable + # Disable the watchdogs again + esp32c6_wdt_disable - # Here debugger reads anyhalted and allhalted bits as set (0x3a2) - # We will clean allhalted state by resuming the core. - riscv dmi_write $_RISCV_DMCONTROL 0x40000001 + # Here debugger reads anyhalted and allhalted bits as set (0x3a2) + # We will clean allhalted state by resuming the core. + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 - # Put the hart back into reset state. Note that we need to keep haltreq set. - riscv dmi_write $_RISCV_DMCONTROL 0x80000003 + # Put the hart back into reset state. Note that we need to keep haltreq set. + riscv dmi_write $_RISCV_DMCONTROL 0x80000003 } proc esp32c6_memprot_is_enabled { } { global _RISCV_ABS_CMD _RISCV_ABS_DATA0 # If IRAM/DRAM split is enabled TOR address match mode is used. - # If IRAM/DRAM split is disabled NAPOT mode is used. + # If IRAM/DRAM split is disabled NAPOT mode is used. # In order to determine if the IRAM/DRAM regions are protected against RWX/RW, # it is necessary to first read the mode and then apply the appropriate method for checking. # We can understand the mode reading pmp5cfg in pmpcfg1 register. @@ -87,13 +97,13 @@ proc esp32c6_memprot_is_enabled { } { set pmp6cfg [expr {($pmpcfg1 >> (8 * 2)) & 0xFF}] set pmp7cfg [expr {($pmpcfg1 >> (8 * 3)) & 0xFF}] - set IRAM_LOW 0x40800000 - set IRAM_HIGH 0x40880000 - set DRAM_LOW 0x40800000 - set DRAM_HIGH 0x40880000 + set IRAM_LOW 0x40800000 + set IRAM_HIGH 0x40880000 + set DRAM_LOW 0x40800000 + set DRAM_HIGH 0x40880000 set PMP_RWX 0x07 - set PMP_RW 0x03 - set PMP_A [expr {($pmp5cfg >> 3) & 0x03}] + set PMP_RW 0x03 + set PMP_A [expr {($pmp5cfg >> 3) & 0x03}] if {$PMP_A == 0} { # TOR mode used to protect valid address space. diff --git a/tcl/target/esp32h2.cfg b/tcl/target/esp32h2.cfg index b9c4f56adf..4d3e9350b1 100644 --- a/tcl/target/esp32h2.cfg +++ b/tcl/target/esp32h2.cfg @@ -5,73 +5,75 @@ source [find target/esp_common.cfg] # Target specific global variables -set _CHIPNAME "esp32h2" -set _CPUTAPID 0x00010c25 -set _ESP_ARCH "riscv" -set _ONLYCPU 1 -set _ESP_SMP_TARGET 0 -set _ESP_SMP_BREAK 0 -set _ESP_EFUSE_MAC_ADDR_REG 0x600B0844 +set _CHIPNAME "esp32h2" +set _CPUTAPID 0x00010c25 +set _ESP_ARCH "riscv" +set _ONLYCPU 1 +set _ESP_SMP_TARGET 0 +set _ESP_SMP_BREAK 0 +set _ESP_EFUSE_MAC_ADDR_REG 0x600B0844 # Target specific functions should be implemented for each riscv chips. proc esp32h2_wdt_disable { } { - # Halt event can occur during config phase (before "init" is done). - # Ignore it since mww commands don't work at that time. - if { [string compare [command mode] config] == 0 } { - return - } - - # Timer Group 0 & 1 WDTs - mww 0x60009064 0x50D83AA1 - mww 0x60009048 0 - mww 0x6000A064 0x50D83AA1 - mww 0x6000A048 0 - # WDT_RTC - #mww 0x600b1c18 0x50D83AA1 - #mww 0x600B1C00 0 - # WDT_SWD - #mww 0x600b1c20 0x8F1D312A - #mww 0x600b1c1c 0x84B00000 + # Halt event can occur during config phase (before "init" is done). + # Ignore it since mww commands don't work at that time. + if { [string compare [command mode] config] == 0 } { + return + } + + # Disable Timer Group 0 WDT + mww 0x60009064 0x50D83AA1 + mww 0x60009048 0 + # Clear TG0 wdt interrupt state + mww 0x6000907C 0x2 + + # Disable Timer Group 1 WDT + mww 0x6000A064 0x50D83AA1 + mww 0x6000A048 0 + # Clear TG1 wdt interrupt state + mww 0x6000A07C 0x2 } proc esp32h2_soc_reset { } { global _RISCV_DMCONTROL _RISCV_SB_CS _RISCV_SB_ADDR0 _RISCV_SB_DATA0 - riscv dmi_write $_RISCV_DMCONTROL 0x80000001 - riscv dmi_write $_RISCV_SB_CS 0x48000 - riscv dmi_write $_RISCV_SB_ADDR0 0x600b1034 - riscv dmi_write $_RISCV_SB_DATA0 0x80000000 - # clear dmactive to clear sbbusy otherwise debug module gets stuck - riscv dmi_write $_RISCV_DMCONTROL 0 + riscv dmi_write $_RISCV_DMCONTROL 0x80000001 + riscv dmi_write $_RISCV_SB_CS 0x48000 + riscv dmi_write $_RISCV_SB_ADDR0 0x600b1034 + riscv dmi_write $_RISCV_SB_DATA0 0x80000000 + # clear dmactive to clear sbbusy otherwise debug module gets stuck + riscv dmi_write $_RISCV_DMCONTROL 0 - riscv dmi_write $_RISCV_SB_CS 0x48000 - riscv dmi_write $_RISCV_SB_ADDR0 0x600b1038 - riscv dmi_write $_RISCV_SB_DATA0 0x10000000 + riscv dmi_write $_RISCV_SB_CS 0x48000 + riscv dmi_write $_RISCV_SB_ADDR0 0x600b1038 + riscv dmi_write $_RISCV_SB_DATA0 0x10000000 - # clear dmactive to clear sbbusy otherwise debug module gets stuck - riscv dmi_write $_RISCV_DMCONTROL 0 - riscv dmi_write $_RISCV_DMCONTROL 0x40000001 - # Here debugger reads dmstatus as 0xc03a2 + # clear dmactive to clear sbbusy otherwise debug module gets stuck + riscv dmi_write $_RISCV_DMCONTROL 0 + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 + # Here debugger reads dmstatus as 0xc03a2 - # Wait for the reset to happen - sleep 10 - poll - # Here debugger reads dmstatus as 0x3a2 + # Wait for the reset to happen + sleep 10 + poll + # Here debugger reads dmstatus as 0x3a2 - # Disable the watchdogs again - esp32h2_wdt_disable + # Disable the watchdogs again + esp32h2_wdt_disable - # Here debugger reads anyhalted and allhalted bits as set (0x3a2) - # We will clean allhalted state by resuming the core. - riscv dmi_write $_RISCV_DMCONTROL 0x40000001 + # Here debugger reads anyhalted and allhalted bits as set (0x3a2) + # We will clean allhalted state by resuming the core. + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 - # Put the hart back into reset state. Note that we need to keep haltreq set. - riscv dmi_write $_RISCV_DMCONTROL 0x80000003 + # Put the hart back into reset state. Note that we need to keep haltreq set. + riscv dmi_write $_RISCV_DMCONTROL 0x80000003 } proc esp32h2_memprot_is_enabled { } { global _RISCV_ABS_CMD _RISCV_ABS_DATA0 - # If IRAM/DRAM split is enabled, PMPADDR 5-6 will cover valid IRAM region and PMPADDR 7 will cover valid DRAM region + # If IRAM/DRAM split is enabled; + # PMPADDR 5-6 will cover valid IRAM region; + # PMPADDR 7 will cover valid DRAM region; # Only TOR mode is used for IRAM and DRAM protections. # Read pmpcfg1 and extract into 8-bit variables. @@ -90,13 +92,13 @@ proc esp32h2_memprot_is_enabled { } { riscv dmi_write $_RISCV_ABS_CMD 0x2203b7 set pmpaddr7 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] - set IRAM_LOW 0x40800000 - set IRAM_HIGH 0x40850000 - set DRAM_LOW 0x40800000 - set DRAM_HIGH 0x40850000 + set IRAM_LOW 0x40800000 + set IRAM_HIGH 0x40850000 + set DRAM_LOW 0x40800000 + set DRAM_HIGH 0x40850000 set PMP_RWX 0x07 - set PMP_RW 0x03 + set PMP_RW 0x03 # The lock bit remains unset during the execution of the 2nd stage bootloader. # Thus, we do not perform a lock bit check for IRAM and DRAM regions. diff --git a/tcl/target/esp32s2.cfg b/tcl/target/esp32s2.cfg index 4c1362a346..05b4b29f9b 100644 --- a/tcl/target/esp32s2.cfg +++ b/tcl/target/esp32s2.cfg @@ -5,13 +5,13 @@ 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 +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 diff --git a/tcl/target/esp32s3.cfg b/tcl/target/esp32s3.cfg index 12c166c463..53a9742d63 100644 --- a/tcl/target/esp32s3.cfg +++ b/tcl/target/esp32s3.cfg @@ -5,13 +5,13 @@ 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 +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 diff --git a/tcl/target/esp_common.cfg b/tcl/target/esp_common.cfg index 7914865687..f0aafa8058 100644 --- a/tcl/target/esp_common.cfg +++ b/tcl/target/esp_common.cfg @@ -33,31 +33,31 @@ 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 - global _TARGET_TYPE _ESP_ARCH + global _TARGET_TYPE _ESP_ARCH # 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 + 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 _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" - if {$_ESP_ARCH == "riscv"} { set _TARGET_TYPE $_ESP_ARCH } else { set _TARGET_TYPE $_CHIPNAME } + + 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 { } { @@ -190,7 +190,7 @@ proc configure_openocd_events { ARCH } { } proc configure_esp_riscv_default_settings { } { - gdb_breakpoint_override hard + gdb breakpoint_override hard riscv set_reset_timeout_sec 2 riscv set_command_timeout_sec 5 riscv set_mem_access sysbus progbuf abstract diff --git a/tcl/target/gd32vf103.cfg b/tcl/target/gd32vf103.cfg deleted file mode 100644 index 77fdff7a23..0000000000 --- a/tcl/target/gd32vf103.cfg +++ /dev/null @@ -1,187 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later - -# -# GigaDevice GD32VF103 target -# -# https://www.gigadevice.com/products/microcontrollers/gd32/risc-v/ -# - -adapter speed 1000 -source [find mem_helper.tcl] - -transport select jtag - -reset_config srst_nogate - -# The smallest RAM size 6kB (GD32VF103C4/T4/R4) -if { [info exists WORKAREASIZE] } { - set _WORKAREASIZE $WORKAREASIZE -} else { - set _WORKAREASIZE 0x1800 -} - -set _CHIPNAME gd32vf103 -# The vendor's configuration expects an ID of 0x1e200a6d, but this one is what -# I have on my board (Sipeed Longan Nano, GD32VF103CBT6). -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d -jtag newtap $_CHIPNAME bs -irlen 5 -expected-id 0x790007a3 - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME riscv -chain-position $_TARGETNAME -$_TARGETNAME riscv set_enable_virt2phys off - -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 - -# Address 0 is only aliased to main flash when the chip is not running its -# built-in bootloader. When it is, it's instead aliased to a read only section -# of flash at 0x1fffb000. However, we can't detect or dynamically switch this, -# so just pretend it's always aliased to main flash. We need to tell OpenOCD -# about this alias because otherwise we'll try to use software breakpoints on -# code in flash, which don't work because flash mappings are read-only. -flash bank $_CHIPNAME.flashalias virtual 0x0 0 0 0 $_TARGETNAME $_FLASHNAME - -# 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_haltreq [expr 1 << 31] - - global _RESETMODE - global _TARGETNAME - - # 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, - # and psoc6.cfg already uses the same trick. (reset_deassert(), which - # does run, also does this, but at that point it may be too late: the - # reset has already been triggered, so there's a race between it and - # the haltreq write.) - # - # 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] - } - $_TARGETNAME riscv dmi_write $dmcontrol $val - - # Unlock 0xe0042008 so that the next write triggers a reset - $_TARGETNAME 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! - $_TARGETNAME 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 - } -} - -# 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/gd32e23x.cfg b/tcl/target/gigadevice/gd32e23x.cfg similarity index 100% rename from tcl/target/gd32e23x.cfg rename to tcl/target/gigadevice/gd32e23x.cfg diff --git a/tcl/target/gigadevice/gd32vf103.cfg b/tcl/target/gigadevice/gd32vf103.cfg new file mode 100644 index 0000000000..c064554498 --- /dev/null +++ b/tcl/target/gigadevice/gd32vf103.cfg @@ -0,0 +1,137 @@ +# 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] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME gd32vf103 +} + +# The smallest RAM size 6kB (GD32VF103C4/T4/R4) +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1800 +} + +# Example OpenOCD configurations from GigaDevice/Nuclei expect a cpu IDCODE of +# 0x1e200a6d instead. It's unclear if any units with that IDCODE exist in the +# wild. Please report a bug if you have such a unit. +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d +jtag newtap $_CHIPNAME bs -irlen 5 -expected-id 0x790007a3 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME riscv -chain-position $_TARGETNAME + +# Disable virtual address translation since we don't have an MMU. Nothing will +# break without this line, but OpenOCD will do a few unnecessary register reads +# to figure it out on its own. +$_TARGETNAME riscv virt2phys_mode off + +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 +} + +set dmcontrol 0x10 +set dmcontrol_dmactive [expr {1 << 0}] +set dmcontrol_clrresethaltreq [expr {1 << 2}] +set dmcontrol_setresethaltreq [expr {1 << 3}] +set dmcontrol_ackhavereset [expr {1 << 28}] +set dmstatus 0x11 +set dmstatus_allunavail [expr {1 << 12}] +set dmstatus_allhavereset [expr {1 << 19}] + +$_TARGETNAME configure -event reset-start { + if {$halt} { + set ctrl [expr {$::dmcontrol_dmactive | $::dmcontrol_setresethaltreq}] + } else { + set ctrl [expr {$::dmcontrol_dmactive | $::dmcontrol_clrresethaltreq}] + } + riscv dmi_write $::dmcontrol $ctrl +} + +# 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 reset_config_options [reset_config] + # If hardware NRST signal is connected and configured, reset has been + # triggered. Avoid second reset and return early + if {[string match {srst_only *} $reset_config_options] + || [string match {srst_and_trst *} $reset_config_options]} { + return + } + + # Halt the core so that we can write to memory. We do this first so + # that it doesn't clobber our dmcontrol configuration. + halt + + echo "gd32vf103 reset workaround halt=$halt" + + # 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 +} + +# On GD32VF103 the specification's requirement that each hart is in "exactly +# one of four states" is violated and, during reset, report harts as both +# unavailable and halted/running. To work around this, after the havereset is +# lowered in the main deassert_reset procedure, we wait for the absence of the +# unavailable state. +$_TARGETNAME configure -event reset-deassert-post { + set timeout_ms 100 + set start [clock milliseconds] + while {1} { + set status [riscv dmi_read $::dmstatus] + if {!($status & $::dmstatus_allunavail)} { + break + } + if {[clock milliseconds] - $start > $timeout_ms} { + error {Timed out waiting for the hart to become available after a reset} + } + } + + set ctrl [expr {$::dmcontrol_dmactive | $::dmcontrol_clrresethaltreq}] + if {$status & $::dmstatus_allhavereset} { + set ctrl [expr {$ctrl | $::dmcontrol_ackhavereset}] + } + riscv dmi_write $::dmcontrol $ctrl +} diff --git a/tcl/target/hpmicro/hpm5300.cfg b/tcl/target/hpmicro/hpm5300.cfg new file mode 100644 index 0000000000..310c788bde --- /dev/null +++ b/tcl/target/hpmicro/hpm5300.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2021 HPMicro +# +# datasheet: https://www.hpmicro.com/Public/Uploads/uploadfile/files/20251126/HPM5300DSV012.pdf + +if { [info exists CHIPNAME] } { + set _CHIP $CHIPNAME +} else { + set _CHIP hpm5361 +} +set _CPUTAPID 0x1000563D +jtag newtap $_CHIP cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGET0 $_CHIP.cpu0 +target create $_TARGET0 riscv -chain-position $_CHIP.cpu -coreid 0 + +$_TARGET0 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common.cfg] +source [find target/hpmicro/hpm_common_csr_lite.cfg] + +proc reset_soc {} { + sba_write_mem 0xF410001C 24000000 +} diff --git a/tcl/target/hpmicro/hpm6280-dual-core.cfg b/tcl/target/hpmicro/hpm6280-dual-core.cfg new file mode 100644 index 0000000000..a8cc33f5f1 --- /dev/null +++ b/tcl/target/hpmicro/hpm6280-dual-core.cfg @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2021 HPMicro +# +# datasheet: https://www.hpmicro.com/Public/Uploads/uploadfile/files/20251124/HPM6200DSV26.pdf + +if { [info exists CHIPNAME] } { + set _CHIP $CHIPNAME +} else { + set _CHIP hpm6280 +} +set _CPUTAPID 0x1000563D +jtag newtap $_CHIP cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGET0 $_CHIP.cpu0 +target create $_TARGET0 riscv -chain-position $_CHIP.cpu -coreid 0 + +$_TARGET0 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common.cfg] +source [find target/hpmicro/hpm_common_csr.cfg] + +proc release_core1 {} { + sba_write_mem 0xF4002C00 0x1000 +} + +set _TARGET1 $_CHIP.cpu1 +target create $_TARGET1 riscv -chain-position $_CHIP.cpu -coreid 1 +$_TARGET1 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common_csr.cfg] + +$_TARGET1 configure -event examine-start { + release_core1 +} + +$_TARGET1 configure -event reset-deassert-pre { + $::_TARGET0 arp_poll + release_core1 +} + +proc reset_soc {} { + sba_write_mem 0xF40C001C 24000000 +} diff --git a/tcl/target/hpmicro/hpm6280-single-core.cfg b/tcl/target/hpmicro/hpm6280-single-core.cfg new file mode 100644 index 0000000000..0e12c03af9 --- /dev/null +++ b/tcl/target/hpmicro/hpm6280-single-core.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2021 HPMicro +# +# datasheet: https://www.hpmicro.com/Public/Uploads/uploadfile/files/20251124/HPM6200DSV26.pdf + +if { [info exists CHIPNAME] } { + set _CHIP $CHIPNAME +} else { + set _CHIP hpm6280 +} +set _CPUTAPID 0x1000563D +jtag newtap $_CHIP cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGET0 $_CHIP.cpu0 +target create $_TARGET0 riscv -chain-position $_CHIP.cpu -coreid 0 + +$_TARGET0 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common.cfg] +source [find target/hpmicro/hpm_common_csr.cfg] + +proc reset_soc {} { + sba_write_mem 0xF40C001C 24000000 +} diff --git a/tcl/target/hpmicro/hpm6360.cfg b/tcl/target/hpmicro/hpm6360.cfg new file mode 100644 index 0000000000..abb6d9dbb7 --- /dev/null +++ b/tcl/target/hpmicro/hpm6360.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2021 HPMicro +# +# datasheet: https://www.hpmicro.com/Public/Uploads/uploadfile/files/20251124/HPM6300DSV28-779.pdf:w + +if { [info exists CHIPNAME] } { + set _CHIP $CHIPNAME +} else { + set _CHIP hpm6360 +} +set _CPUTAPID 0x1000563D +jtag newtap $_CHIP cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGET0 $_CHIP.cpu0 +target create $_TARGET0 riscv -chain-position $_CHIP.cpu -coreid 0 + +$_TARGET0 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common.cfg] +source [find target/hpmicro/hpm_common_csr.cfg] + +proc reset_soc {} { + sba_write_mem 0xF40C001C 24000000 +} diff --git a/tcl/target/hpmicro/hpm6750-dual-core.cfg b/tcl/target/hpmicro/hpm6750-dual-core.cfg new file mode 100644 index 0000000000..6beae150d4 --- /dev/null +++ b/tcl/target/hpmicro/hpm6750-dual-core.cfg @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2021 HPMicro +# +# datasheet: https://www.hpmicro.com/Public/Uploads/uploadfile/files/20251124/HPM67006400DSV27.pdf + +if { [info exists CHIPNAME] } { + set _CHIP $CHIPNAME +} else { + set _CHIP hpm6750 +} +set _CPUTAPID 0x1000563D +jtag newtap $_CHIP cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGET0 $_CHIP.cpu0 +target create $_TARGET0 riscv -chain-position $_CHIP.cpu -coreid 0 + +$_TARGET0 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common.cfg] +source [find target/hpmicro/hpm_common_csr.cfg] + +proc release_core1 {} { + set chip_rev [sba_read_mem 0x2001FF00] + if {$chip_rev != 0x56010100 } { + # set start point for core1 + sba_write_mem 0xF4002C08 0x20016284 + } else { + sba_write_mem 0xF4002C08 0x2001660c + } + + # set boot flag for core1 + sba_write_mem 0xF4002C0C 0xC1BEF1A9 + + # release core1 + sba_write_mem 0xF4002C00 0x1000 +} + +set _TARGET1 $_CHIP.cpu1 +target create $_TARGET1 riscv -chain-position $_CHIP.cpu -coreid 1 +$_TARGET1 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common_csr.cfg] + +$_TARGET1 configure -event examine-start { + release_core1 +} + +$_TARGET1 configure -event reset-deassert-pre { + $::_TARGET0 arp_poll + release_core1 +} + +proc reset_soc {} { + sba_write_mem 0xF40C001C 24000000 +} diff --git a/tcl/target/hpmicro/hpm6750-single-core.cfg b/tcl/target/hpmicro/hpm6750-single-core.cfg new file mode 100644 index 0000000000..2566c84154 --- /dev/null +++ b/tcl/target/hpmicro/hpm6750-single-core.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2021 HPMicro +# +# datasheet: https://www.hpmicro.com/Public/Uploads/uploadfile/files/20251124/HPM67006400DSV27.pdf + +if { [info exists CHIPNAME] } { + set _CHIP $CHIPNAME +} else { + set _CHIP hpm6750 +} +set _CPUTAPID 0x1000563D +jtag newtap $_CHIP cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGET0 $_CHIP.cpu0 +target create $_TARGET0 riscv -chain-position $_CHIP.cpu -coreid 0 + +$_TARGET0 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common.cfg] +source [find target/hpmicro/hpm_common_csr.cfg] + +proc reset_soc {} { + sba_write_mem 0xF40C001C 24000000 +} diff --git a/tcl/target/hpmicro/hpm6880.cfg b/tcl/target/hpmicro/hpm6880.cfg new file mode 100644 index 0000000000..591388f924 --- /dev/null +++ b/tcl/target/hpmicro/hpm6880.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 HPMicro +# +# datasheet: https://www.hpmicro.com/Public/Uploads/uploadfile/files/20251128/HPM6800DSV12.pdf + +if { [info exists CHIPNAME] } { + set _CHIP $CHIPNAME +} else { + set _CHIP hpm6880 +} +set _CPUTAPID 0x1000563D +jtag newtap $_CHIP cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGET0 $_CHIP.cpu0 +target create $_TARGET0 riscv -chain-position $_CHIP.cpu -coreid 0 + +$_TARGET0 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common.cfg] +source [find target/hpmicro/hpm_common_csr.cfg] + +proc reset_soc {} { + sba_write_mem 0xF410001C 24000000 +} diff --git a/tcl/target/hpmicro/hpm6e80-dual-core.cfg b/tcl/target/hpmicro/hpm6e80-dual-core.cfg new file mode 100644 index 0000000000..759cfd06a5 --- /dev/null +++ b/tcl/target/hpmicro/hpm6e80-dual-core.cfg @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2024 HPMicro +# +# datasheet: https://www.hpmicro.com/Public/Uploads/uploadfile/files/20251124/HPM6E00DSV011.pdf + +if { [info exists CHIPNAME] } { + set _CHIP $CHIPNAME +} else { + set _CHIP hpm6e00 +} +set _CPUTAPID 0x1000563D +jtag newtap $_CHIP cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGET0 $_CHIP.cpu0 +target create $_TARGET0 riscv -chain-position $_CHIP.cpu -coreid 0 + +$_TARGET0 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common.cfg] +source [find target/hpmicro/hpm_common_csr.cfg] + +proc release_core1 {} { + sba_write_mem 0xF4002C00 0x1000 +} + +set _TARGET1 $_CHIP.cpu1 +target create $_TARGET1 riscv -chain-position $_CHIP.cpu -coreid 1 +$_TARGET1 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common_csr.cfg] + +$_TARGET1 configure -event examine-start { + release_core1 +} + +$_TARGET1 configure -event reset-deassert-pre { + $::_TARGET0 arp_poll + release_core1 +} + +$_TARGET0 configure -event reset-end { + sba_write_mem 0xF4002010 0x2 +} + +proc reset_soc {} { + sba_write_mem 0xF410001C 24000000 +} diff --git a/tcl/target/hpmicro/hpm6e80-single-core.cfg b/tcl/target/hpmicro/hpm6e80-single-core.cfg new file mode 100644 index 0000000000..7d62070fce --- /dev/null +++ b/tcl/target/hpmicro/hpm6e80-single-core.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2024 HPMicro +# +# datasheet: https://www.hpmicro.com/Public/Uploads/uploadfile/files/20251124/HPM6E00DSV011.pdf + +if { [info exists CHIPNAME] } { + set _CHIP $CHIPNAME +} else { + set _CHIP hpm6e00 +} +set _CPUTAPID 0x1000563D +jtag newtap $_CHIP cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGET0 $_CHIP.cpu0 +target create $_TARGET0 riscv -chain-position $_CHIP.cpu -coreid 0 + +$_TARGET0 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0 + +source [find target/hpmicro/hpm_common.cfg] +source [find target/hpmicro/hpm_common_csr.cfg] + +proc reset_soc {} { + sba_write_mem 0xF410001C 24000000 +} diff --git a/tcl/target/hpmicro/hpm_common.cfg b/tcl/target/hpmicro/hpm_common.cfg new file mode 100644 index 0000000000..5f627cf65c --- /dev/null +++ b/tcl/target/hpmicro/hpm_common.cfg @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2025 HPMicro + +source [find target/hpmicro/hpm_reset.cfg] + +set dmsbcs 0x38 +set dmsbaddress0 0x39 +set dmsbdata0 0x3C + +proc target0_dmi_write_reg {reg value} { + $::_TARGET0 riscv dmi_write ${reg} ${value} +} + +proc target0_dmi_read_reg {reg} { + set v [$::_TARGET0 riscv dmi_read ${reg} $::dmsbdata0] + return ${v} +} +proc sba_write_mem {addr value} { + target0_dmi_write_reg $::dmsbaddress0 ${addr} + target0_dmi_write_reg $::dmsbdata0 ${value} +} + +proc sba_read_mem {addr} { + set sbcs [expr { 0x100000 | [target0_dmi_read_reg $::dmsbcs] }] + target0_dmi_write_reg $::dmsbcs ${sbcs} + target0_dmi_write_reg $::dmsbaddress0 ${addr} + set value [target0_dmi_read_reg $::dmsbdata0] + return ${value} +} diff --git a/tcl/target/hpmicro/hpm_common_csr.cfg b/tcl/target/hpmicro/hpm_common_csr.cfg new file mode 100644 index 0000000000..5cf02305cd --- /dev/null +++ b/tcl/target/hpmicro/hpm_common_csr.cfg @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2024 HPMicro + +# expose non-standard csr registers +# scounteren +riscv expose_csrs 262 +# mcountinhibit +riscv expose_csrs 800 +# milmb +riscv expose_csrs 1984 +# mdlmb +riscv expose_csrs 1985 +# mecc_code +riscv expose_csrs 1986 +# mnvec +riscv expose_csrs 1987 +# mxstatus +riscv expose_csrs 1988 +# mpft_ctl +riscv expose_csrs 1989 +# mhsp_ctl +riscv expose_csrs 1990 +# msp_bound +riscv expose_csrs 1991 +# msp_base +riscv expose_csrs 1992 +# mdcause +riscv expose_csrs 1993 +# mcache_ctl +riscv expose_csrs 1994 +# mcctlbeginaddr +riscv expose_csrs 1995 +# mcctlcommand +riscv expose_csrs 1996 +# mcctldata +riscv expose_csrs 1997 +# mcounterwen +riscv expose_csrs 1998 +# mcounterinten +riscv expose_csrs 1999 +# mmisc_ctl +riscv expose_csrs 2000 +# mcountermask_m +riscv expose_csrs 2001 +# mcountermask_s +riscv expose_csrs 2002 +# mcountermask_u +riscv expose_csrs 2003 +# mcounterovf +riscv expose_csrs 2004 +# mslideleg +riscv expose_csrs 2005 +# mclk_ctl +riscv expose_csrs 2015 +# dexc2dbg +riscv expose_csrs 2016 +# ddcause +riscv expose_csrs 2017 +# uitb +riscv expose_csrs 2048 +# ucode +riscv expose_csrs 2049 +# udcause +riscv expose_csrs 2057 +# ucctlbeginaddr +riscv expose_csrs 2059 +# ucctlcommand +riscv expose_csrs 2060 +# slie +riscv expose_csrs 2500 +# slip +riscv expose_csrs 2501 +# sdcause +riscv expose_csrs 2505 +# scctldata +riscv expose_csrs 2509 +# scounterinten +riscv expose_csrs 2511 +# scountermask_m +riscv expose_csrs 2513 +# scountermask_s +riscv expose_csrs 2514 +# scountermask_u +riscv expose_csrs 2515 +# scounterovf +riscv expose_csrs 2516 +# scountinhibit +riscv expose_csrs 2528 +# shpmevent3 +riscv expose_csrs 2531 +# shpmevent4 +riscv expose_csrs 2532 +# shpmevent5 +riscv expose_csrs 2533 +# shpmevent6 +riscv expose_csrs 2534 +# micm_cfg +riscv expose_csrs 4032 +# mdcm_cfg +riscv expose_csrs 4033 +# mmsc_cfg +riscv expose_csrs 4034 +# mmsc_cfg2 +riscv expose_csrs 4035 diff --git a/tcl/target/hpmicro/hpm_common_csr_lite.cfg b/tcl/target/hpmicro/hpm_common_csr_lite.cfg new file mode 100644 index 0000000000..c0921f8f6a --- /dev/null +++ b/tcl/target/hpmicro/hpm_common_csr_lite.cfg @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2024 HPMicro + +# expose non-standard csr registers +# mcountinhibit +riscv expose_csrs 800 +# milmb +riscv expose_csrs 1984 +# mdlmb +riscv expose_csrs 1985 +# mecc_code +riscv expose_csrs 1986 +# mnvec +riscv expose_csrs 1987 +# mxstatus +riscv expose_csrs 1988 +# mpft_ctl +riscv expose_csrs 1989 +# mhsp_ctl +riscv expose_csrs 1990 +# msp_bound +riscv expose_csrs 1991 +# msp_base +riscv expose_csrs 1992 +# mdcause +riscv expose_csrs 1993 +# mcache_ctl +riscv expose_csrs 1994 +# mcctlbeginaddr +riscv expose_csrs 1995 +# mcctlcommand +riscv expose_csrs 1996 +# mcctldata +riscv expose_csrs 1997 +# mcounterwen +riscv expose_csrs 1998 +# mcounterinten +riscv expose_csrs 1999 +# mmisc_ctl +riscv expose_csrs 2000 +# mcountermask_m +riscv expose_csrs 2001 +# mcountermask_s +riscv expose_csrs 2002 +# mcountermask_u +riscv expose_csrs 2003 +# mcounterovf +riscv expose_csrs 2004 +# dexc2dbg +riscv expose_csrs 2016 +# ddcause +riscv expose_csrs 2017 +# uitb +riscv expose_csrs 2048 +# ucode +riscv expose_csrs 2049 +# udcause +riscv expose_csrs 2057 +# ucctlbeginaddr +riscv expose_csrs 2059 +# ucctlcommand +riscv expose_csrs 2060 +# micm_cfg +riscv expose_csrs 4032 +# mdcm_cfg +riscv expose_csrs 4033 +# mmsc_cfg +riscv expose_csrs 4034 +# mmsc_cfg2 +riscv expose_csrs 4035 diff --git a/tcl/target/hpmicro/hpm_reset.cfg b/tcl/target/hpmicro/hpm_reset.cfg new file mode 100644 index 0000000000..0a0106a987 --- /dev/null +++ b/tcl/target/hpmicro/hpm_reset.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2025 HPMicro + +# As debug access needs to be released by bootrom after reset, +# and halt request set along with reset will be ignored, it needs +# a short period of time for bootrom to release the access, +# so we request halt again in reset-deassert-pre event. +$_TARGET0 configure -event reset-deassert-pre { + sleep 1 + if {$halt} { + $::_TARGET0 arp_halt + } +} diff --git a/tcl/target/imx6.cfg b/tcl/target/imx6.cfg index c9b6acf79d..ed83d65fc2 100644 --- a/tcl/target/imx6.cfg +++ b/tcl/target/imx6.cfg @@ -78,6 +78,5 @@ proc imx6_dbginit {target} { # Slow speed to be sure it will work adapter speed 1000 -$_TARGETNAME configure -event reset-start { adapter speed 1000 } $_TARGETNAME configure -event reset-assert-post "imx6_dbginit $_TARGETNAME" diff --git a/tcl/target/ke0x.cfg b/tcl/target/ke0x.cfg index b357767191..761a0a6974 100644 --- a/tcl/target/ke0x.cfg +++ b/tcl/target/ke0x.cfg @@ -3,8 +3,8 @@ # # Freescale Kinetis KE0x and KEAx series devices # - -source [find target/swj-dp.tcl] +# Devices support SWD transport only +transport select swd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -26,7 +26,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x0bc11477 } -swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/klx.cfg b/tcl/target/klx.cfg index cd236b3395..b4014ba5b6 100644 --- a/tcl/target/klx.cfg +++ b/tcl/target/klx.cfg @@ -4,8 +4,8 @@ # NXP (former Freescale) Kinetis KL series devices # Also used for Cortex-M0+ equipped members of KVx and KE1xZ series # - -source [find target/swj-dp.tcl] +# Devices support SWD transport only +transport select swd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -27,7 +27,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x0bc11477 } -swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/lpc8nxx.cfg b/tcl/target/lpc8nxx.cfg index 859e99b6a3..6f1f88df41 100644 --- a/tcl/target/lpc8nxx.cfg +++ b/tcl/target/lpc8nxx.cfg @@ -5,8 +5,8 @@ # Based on NXP proposal https://community.nxp.com/message/1011149 # Many thanks to Dries Moors from NXP support. # SWD only transport +transport select swd -source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { @@ -15,7 +15,7 @@ if { [info exists CHIPNAME] } { set _CHIPNAME lpc8nxx } -swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id 0 +swd newdap $_CHIPNAME cpu -expected-id 0 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/lsch3_common.cfg b/tcl/target/lsch3_common.cfg index f48d59b9d8..ad88b2e1b3 100644 --- a/tcl/target/lsch3_common.cfg +++ b/tcl/target/lsch3_common.cfg @@ -51,8 +51,8 @@ proc release_cpu {cpu} { } # Release the cpu; it will start executing something bogus - mem2array regs 32 $RST_BRRL 1 - mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}] + set reg [read_memory $RST_BRRL 32 1] + mww $RST_BRRL [expr {$reg | 1 << $cpu}] if {$not_halted} { resume diff --git a/tcl/target/max32620.cfg b/tcl/target/max32620.cfg index f3a9f84c88..0ea8d15c2b 100644 --- a/tcl/target/max32620.cfg +++ b/tcl/target/max32620.cfg @@ -1,32 +1,19 @@ # SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32620 - Arm Cortex-M4F @ 96MHz -# Maxim Integrated MAX32620 OpenOCD target configuration file -# www.maximintegrated.com - -# adapter speed -adapter speed 4000 - -# reset pin configuration +# Set the reset pin configuration reset_config srst_only +adapter srst delay 200 -if {[using_jtag]} { - jtag newtap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version - jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -ignore-version -} else { - swd newdap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version -} - -dap create max32620.dap -chain-position max32620.cpu +# Set flash parameters +set FLASH_BASE 0x0 +set FLASH_SIZE 0x200000 +set FLC_BASE 0x40002000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x00 -# target configuration -target create max32620.cpu cortex_m -dap max32620.dap -max32620.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 +# Setup the reserved TAP +set RSV_TAP 1 -# Config Command: flash bank name driver base size chip_width bus_width target [driver_options] -# flash bank max32xxx 0 0 -# max32620 flash base address 0x00000000 -# max32620 flash size 0x200000 (2MB) -# max32620 FLC base address 0x40002000 -# max32620 sector (page) size 0x2000 (8kB) -# max32620 clock speed 96 (MHz) -flash bank max32620.flash max32xxx 0x00000000 0x200000 0 0 max32620.cpu 0x40002000 0x2000 96 +source [find target/max32xxx_common.cfg] diff --git a/tcl/target/max32625.cfg b/tcl/target/max32625.cfg index 90eb392668..0f97010c8c 100644 --- a/tcl/target/max32625.cfg +++ b/tcl/target/max32625.cfg @@ -1,32 +1,17 @@ # SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32625 - Arm Cortex-M4F @ 96MHz -# Maxim Integrated MAX32625 OpenOCD target configuration file -# www.maximintegrated.com +# Note: reset_config srst_only causes reset halt to time out -# adapter speed -adapter speed 4000 +# Set flash parameters +set FLASH_BASE 0x0 +set FLASH_SIZE 0x80000 +set FLC_BASE 0x40002000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x00 -# reset pin configuration -reset_config srst_only +# Setup the reserved TAP +set RSV_TAP 1 -if {[using_jtag]} { - jtag newtap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version - jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f71197 -ignore-version -} else { - 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 -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] -# flash bank max32xxx 0 0 -# max32625 flash base address 0x00000000 -# max32625 flash size 0x80000 (512k) -# max32625 FLC base address 0x40002000 -# max32625 sector (page) size 0x2000 (8kB) -# max32625 clock speed 96 (MHz) -flash bank max32625.flash max32xxx 0x00000000 0x80000 0 0 max32625.cpu 0x40002000 0x2000 96 +source [find target/max32xxx_common.cfg] diff --git a/tcl/target/max3263x.cfg b/tcl/target/max3263x.cfg index 852e04af1e..c8d99466ca 100644 --- a/tcl/target/max3263x.cfg +++ b/tcl/target/max3263x.cfg @@ -1,32 +1,39 @@ # SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX3263x - Arm Cortex-M4F @ 96MHz -# Maxim Integrated MAX3263X OpenOCD target configuration file -# www.maximintegrated.com +# Set the reset pin configuration +reset_config none -# adapter speed -adapter speed 4000 +# Set flash parameters +set FLASH_BASE 0x0 +set FLASH_SIZE 0x200000 +set FLC_BASE 0x40002000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x00 -# reset pin configuration -reset_config srst_only +# Setup the reserved TAP +set RSV_TAP 1 -if {[using_jtag]} { - jtag newtap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version - jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f76197 -ignore-version -} else { - swd newdap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version -} +source [find target/max32xxx_common.cfg] + +# Create custom reset sequence +$_CHIPNAME.cpu configure -event reset-init { + + # Reset the peripherals + mww 0x40000848 0xFFFFFFFF + mww 0x4000084C 0xFFFFFFFF -dap create max3263x.dap -chain-position max3263x.cpu + sleep 10 -# target configuration -target create max3263x.cpu cortex_m -dap max3263x.dap -max3263x.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 + mww 0x40000848 0x0 + mww 0x4000084C 0x0 -# Config Command: flash bank name driver base size chip_width bus_width target [driver_options] -# flash bank max32xxx 0 0 -# max3263x flash base address 0x00000000 -# max3263x flash size 0x200000 (2MB) -# max3263x FLC base address 0x40002000 -# max3263x sector (page) size 0x2000 (8kB) -# max3263x clock speed 96 (MHz) -flash bank max3263x.flash max32xxx 0x00000000 0x200000 0 0 max3263x.cpu 0x40002000 0x2000 96 + # Reset the SP + set SP_ADDR [mrw 0x0] + reg sp $SP_ADDR + + # Reset the PC to the Reset_Handler + set RESET_HANDLER_ADDR [mrw 0x4] + reg pc $RESET_HANDLER_ADDR +} diff --git a/tcl/target/max32650.cfg b/tcl/target/max32650.cfg new file mode 100644 index 0000000000..3ca3787091 --- /dev/null +++ b/tcl/target/max32650.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32650 - Arm Cortex-M4F @ 120MHz + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x300000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx_common.cfg] + +if {![using_hla]} { + # The chip supports standard ARM/Cortex-M4 SYSRESETREQ signal + cortex_m reset_config sysresetreq +} diff --git a/tcl/target/max32655.cfg b/tcl/target/max32655.cfg new file mode 100644 index 0000000000..4151fe19d5 --- /dev/null +++ b/tcl/target/max32655.cfg @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32655 - Arm Cortex-M4F @ 100MHz + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x80000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 100 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx_common.cfg] + +if {![using_hla]} { + # The chip supports standard ARM/Cortex-M4 SYSRESETREQ signal + cortex_m reset_config sysresetreq +} diff --git a/tcl/target/max32660.cfg b/tcl/target/max32660.cfg new file mode 100644 index 0000000000..89f5741de1 --- /dev/null +++ b/tcl/target/max32660.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32660 - Arm Cortex-M4F @ 96MHz + +# Set the reset pin configuration +reset_config srst_only + +# Set flash parameters +set FLASH_BASE 0x0 +set FLASH_SIZE 0x40000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x00 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx_common.cfg] diff --git a/tcl/target/max32662.cfg b/tcl/target/max32662.cfg new file mode 100644 index 0000000000..70f486318a --- /dev/null +++ b/tcl/target/max32662.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32662 - Arm Cortex-M4F @ 100MHz + +# Set the reset pin configuration +reset_config srst_only + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x40000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx_common.cfg] diff --git a/tcl/target/max32670.cfg b/tcl/target/max32670.cfg new file mode 100644 index 0000000000..92dc6e12f3 --- /dev/null +++ b/tcl/target/max32670.cfg @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32670 - Arm Cortex-M4F @ 100MHz + +# Set the reset pin configuration +reset_config none + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x60000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx_common.cfg] + +# Early revisions of the MAX32670 will disable SWD upon reset. There are reserved address locations +# in the ROM code that can be used to insert breakpoints. +# This workaround will enable SWD for affected revisions. +$_CHIPNAME.cpu configure -event reset-assert-pre { + if {$halt} {catch {bp 0x00002174 2 hw}} +} + +$_CHIPNAME.cpu configure -event reset-deassert-post { + if {$halt} { + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_halt + rbp 0x00002174 + } +} diff --git a/tcl/target/max32672.cfg b/tcl/target/max32672.cfg new file mode 100644 index 0000000000..9709b699fe --- /dev/null +++ b/tcl/target/max32672.cfg @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32672 - Arm Cortex-M4F @ 100MHz + +# Set the reset pin configuration +reset_config none +adapter srst pulse_width 200 + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x80000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx_common.cfg] + +# Add additional flash bank +set FLASH_BASE 0x10080000 +set FLC_BASE 0x40029400 + +flash bank $_CHIPNAME.flash1 max32xxx $FLASH_BASE $FLASH_SIZE 0 0 $_CHIPNAME.cpu \ +$FLC_BASE $FLASH_SECTOR $FLASH_CLK $FLASH_OPTIONS diff --git a/tcl/target/max32675.cfg b/tcl/target/max32675.cfg new file mode 100644 index 0000000000..ade025db04 --- /dev/null +++ b/tcl/target/max32675.cfg @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32675 - Arm Cortex-M4F @ 100MHz + +# Set the reset pin configuration +reset_config none +adapter srst pulse_width 200 + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x60000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx_common.cfg] + +# Early revisions of the MAX32675 will disable SWD upon reset. There are reserved address locations +# in the ROM code that can be used to insert breakpoints. +# This workaround will enable SWD for affected revisions. +$_CHIPNAME.cpu configure -event reset-assert-pre { + if {$halt} {catch {bp 0x00002174 2 hw}} +} + +$_CHIPNAME.cpu configure -event reset-deassert-post { + if {$halt} { + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_halt + rbp 0x00002174 + } +} diff --git a/tcl/target/max32680.cfg b/tcl/target/max32680.cfg new file mode 100644 index 0000000000..ebb2e341d6 --- /dev/null +++ b/tcl/target/max32680.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32680 - Arm Cortex-M4F @ 100MHz + +# Set the reset pin configuration +reset_config srst_only +adapter srst pulse_width 2 + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x80000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 100 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx_common.cfg] diff --git a/tcl/target/max32690.cfg b/tcl/target/max32690.cfg new file mode 100644 index 0000000000..de9d233bea --- /dev/null +++ b/tcl/target/max32690.cfg @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32690 - Arm Cortex-M4F @ 120MHz + +# Set the reset pin configuration +reset_config srst_only +adapter srst pulse_width 2 + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x300000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x4000 +set FLASH_CLK 60 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx_common.cfg] + +# Add additional flash bank +set FLASH_BASE 0x10300000 +set FLASH_SIZE 0x40000 +set FLC_BASE 0x40029400 +set FLASH_SECTOR 0x2000 + +flash bank $_CHIPNAME.flash1 max32xxx $FLASH_BASE $FLASH_SIZE 0 0 $_CHIPNAME.cpu \ +$FLC_BASE $FLASH_SECTOR $FLASH_CLK $FLASH_OPTIONS + +# Early revisions of the MAX32690 will disable SWD upon reset. There are reserved address locations +# in the ROM code that can be used to insert breakpoints. +# This workaround will enable SWD for affected revisions. +$_CHIPNAME.cpu configure -event reset-assert-pre { + if {$halt} { + catch {bp 0x0000FFF4 2 hw} + } +} + +$_CHIPNAME.cpu configure -event reset-deassert-post { + if {$halt} { + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_halt + rbp 0x0000FFF4 + } +} diff --git a/tcl/target/max32xxx_common.cfg b/tcl/target/max32xxx_common.cfg new file mode 100644 index 0000000000..e8e2dd4289 --- /dev/null +++ b/tcl/target/max32xxx_common.cfg @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated max32xxx OpenOCD driver configuration file. +# Contains common settings for max32xxx devices. + +source [find mem_helper.tcl] +source [find target/swj-dp.tcl] + +# Target configuration +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME max32xxx +} + +# Add reserved TAP +if { [using_jtag] && [info exists RSV_TAP] } { + jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -ignore-version + jtag newtap rsvtap tap -irlen 4 -irmask 0xf -ircapture 0x1 -ignore-version +} else { + swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -ignore-version +} + + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_CHIPNAME.cpu cortex_m -dap $_CHIPNAME.dap + +# Enable thread-aware debugging +$_CHIPNAME.cpu configure -rtos hwthread + +# Setup working area +if { [info exists WORK_START] } { + set _WORK_START $WORK_START +} else { + set _WORK_START 0x20005000 +} + +if { [info exists WORK_SIZE] } { + set _WORK_SIZE $WORK_SIZE +} else { + set _WORK_SIZE 0x8000 +} + +$_CHIPNAME.cpu configure -work-area-phys $_WORK_START -work-area-size $_WORK_SIZE + +# Configure flash driver +if { [info exists FLASH_BASE] } { + set _FLASH_BASE $FLASH_BASE +} else { + set _FLASH_BASE 0x10000000 +} + +if { [info exists FLASH_SIZE] } { + set _FLASH_SIZE $FLASH_SIZE +} else { + set _FLASH_SIZE 0x10000 +} + +if { [info exists FLC_BASE] } { + set _FLC_BASE $FLC_BASE +} else { + set _FLC_BASE 0x40029000 +} + +if { [info exists FLASH_SECTOR] } { + set _FLASH_SECTOR $FLASH_SECTOR +} else { + set _FLASH_SECTOR 0x2000 +} + +if { [info exists FLASH_CLK] } { + set _FLASH_CLK $FLASH_CLK +} else { + set _FLASH_CLK 96 +} + +# OPTIONS_128 0x01 /* Perform 128 bit flash writes */ +# OPTIONS_ENC 0x02 /* Encrypt the flash contents */ +# OPTIONS_AUTH 0x04 /* Authenticate the flash contents */ +# OPTIONS_COUNT 0x08 /* Add counter values to authentication */ +# OPTIONS_INTER 0x10 /* Interleave the authentication and count values*/ +# OPTIONS_RELATIVE_XOR 0x20 /* Only XOR the offset of the address when encrypting */ +# OPTIONS_KEYSIZE 0x40 /* Use a 256 bit KEY */ + +if { [info exists FLASH_OPTIONS] } { + set _FLASH_OPTIONS $FLASH_OPTIONS +} else { + set _FLASH_OPTIONS 0 +} + +flash bank $_CHIPNAME.flash max32xxx $_FLASH_BASE $_FLASH_SIZE 0 0 $_CHIPNAME.cpu \ +$_FLC_BASE $_FLASH_SECTOR $_FLASH_CLK $_FLASH_OPTIONS + +# call allow_low_pwr_dbg to set this to 1 +set ALLOW_LOW_PWR_DBG 0 + +proc allow_low_pwr_dbg {} { + global ALLOW_LOW_PWR_DBG + + # set our low-power debug flag + set ALLOW_LOW_PWR_DBG 1 +} + +# enable debug in case of low-power mode +proc enable_debug {} { + set DBGKEY 0xA05F0000 + set C_DEBUGEN 0x00000001 + set C_HALT 0x00000002 + + echo "Enable debug to connect in low-power mode" + + # enable debug + mww 0xE000EDF0 [expr {$DBGKEY | $C_HALT | $C_DEBUGEN}] + + # allow for time waking up + sleep 500 +} + +$_CHIPNAME.cpu configure -event reset-deassert-post { + global ALLOW_LOW_PWR_DBG + + if { $ALLOW_LOW_PWR_DBG == 1 } { + enable_debug + } +} diff --git a/tcl/target/microchip/mpfs.cfg b/tcl/target/microchip/mpfs.cfg new file mode 100644 index 0000000000..3a63e3d3b4 --- /dev/null +++ b/tcl/target/microchip/mpfs.cfg @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Target: MPFS PolarFire SoC-series processors by Microchip Technologies +# +# https://www.microchip.com/en-us/products/fpgas-and-plds/system-on-chip-fpgas/polarfire-soc-fpgas +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME mpfs +} + +# Process COREID variable +if { ![exists COREID] } { + set COREID -1 +} + +transport select jtag + +# PolarFire SoC (MPFS) hart id to name lookup table +array set hart_names { + 0 e51 + 1 u54_1 + 2 u54_2 + 3 u54_3 + 4 u54_4 +} + +# MPFS devices table +set mpfs_cpu_tap_info { + MPFS025 0x0f8531cf + MPFS095 0x0f8181cf + MPFS160 0x0f8191cf + MPFS250 0x0f81a1cf + MPFS460 0x0f81b1cf + RTPFS160 0x0f8991cf + RTPFS460 0x0f89b1cf +} + +proc expected_ids {tap_list} { + set str "" + dict for {key value} $tap_list { + append str "-expected-id" " " $value " " + } + + return $str +} + +set irlen 8 +set expected_ids [expected_ids $mpfs_cpu_tap_info] +eval jtag newtap $_CHIPNAME cpu -irlen $irlen $expected_ids -ignore-version + +if {$COREID == -1} { + # Single debug connection to all HART's + set _TARGETNAME_0 $_CHIPNAME.$hart_names(0) + set _TARGETNAME_1 $_CHIPNAME.$hart_names(1) + set _TARGETNAME_2 $_CHIPNAME.$hart_names(2) + set _TARGETNAME_3 $_CHIPNAME.$hart_names(3) + set _TARGETNAME_4 $_CHIPNAME.$hart_names(4) + + target create $_TARGETNAME_0 riscv -chain-position $_CHIPNAME.cpu -coreid 0 -rtos hwthread + target create $_TARGETNAME_1 riscv -chain-position $_CHIPNAME.cpu -coreid 1 -rtos hwthread + target create $_TARGETNAME_2 riscv -chain-position $_CHIPNAME.cpu -coreid 2 -rtos hwthread + target create $_TARGETNAME_3 riscv -chain-position $_CHIPNAME.cpu -coreid 3 -rtos hwthread + target create $_TARGETNAME_4 riscv -chain-position $_CHIPNAME.cpu -coreid 4 -rtos hwthread + target smp $_TARGETNAME_0 $_TARGETNAME_1 $_TARGETNAME_2 $_TARGETNAME_3 $_TARGETNAME_4 +} else { + # Debug connection to a specific hart + set _TARGETNAME_0 $_CHIPNAME.$hart_names($COREID) + target create $_TARGETNAME_0 riscv -chain-position $_CHIPNAME.cpu -coreid $COREID +} + +# Only TRSTn supported +reset_config trst_only diff --git a/tcl/target/microchip/pic64gx.cfg b/tcl/target/microchip/pic64gx.cfg new file mode 100644 index 0000000000..25cef6b237 --- /dev/null +++ b/tcl/target/microchip/pic64gx.cfg @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Target: Pic64gx processor by Microchip Technologies +# +# https://www.microchip.com/en-us/products/microprocessors/64-bit-mpus/pic64gx +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME pic64gx +} + +# Process COREID variable +if {![exists COREID]} { + set COREID -1 +} + +transport select jtag + +# PIC64GX hart id to name lookup table +array set hart_names { + 0 e51 + 1 u54_1 + 2 u54_2 + 3 u54_3 + 4 u54_4 +} + +# PIC64GX table +set pic64gx_tap_info { + PIC64GX1000 0x0f8531cf +} + +proc expected_ids {tap_list} { + set str "" + dict for {key value} $tap_list { + append str "-expected-id" " " $value " " + } + + return $str +} + +set irlen 8 +set expected_ids [expected_ids $pic64gx_tap_info] +eval jtag newtap $_CHIPNAME cpu -irlen $irlen $expected_ids -ignore-version + +if {$COREID == -1} { + # Single debug connection to all harts + set _TARGETNAME_0 $_CHIPNAME.$hart_names(0) + set _TARGETNAME_1 $_CHIPNAME.$hart_names(1) + set _TARGETNAME_2 $_CHIPNAME.$hart_names(2) + set _TARGETNAME_3 $_CHIPNAME.$hart_names(3) + set _TARGETNAME_4 $_CHIPNAME.$hart_names(4) + + target create $_TARGETNAME_0 riscv -chain-position $_CHIPNAME.cpu -coreid 0 -rtos hwthread + target create $_TARGETNAME_1 riscv -chain-position $_CHIPNAME.cpu -coreid 1 -rtos hwthread + target create $_TARGETNAME_2 riscv -chain-position $_CHIPNAME.cpu -coreid 2 -rtos hwthread + target create $_TARGETNAME_3 riscv -chain-position $_CHIPNAME.cpu -coreid 3 -rtos hwthread + target create $_TARGETNAME_4 riscv -chain-position $_CHIPNAME.cpu -coreid 4 -rtos hwthread + target smp $_TARGETNAME_0 $_TARGETNAME_1 $_TARGETNAME_2 $_TARGETNAME_3 $_TARGETNAME_4 +} else { + # Debug connection to a specific hart + set _TARGETNAME_0 $_CHIPNAME.$hart_names($COREID) + target create $_TARGETNAME_0 riscv -chain-position $_CHIPNAME.cpu -coreid $COREID +} + +# Only TRSTn supported +reset_config trst_only diff --git a/tcl/target/microchip/sama7d6.cfg b/tcl/target/microchip/sama7d6.cfg new file mode 100644 index 0000000000..750634055b --- /dev/null +++ b/tcl/target/microchip/sama7d6.cfg @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip SAMA7D6 series: SAMA7D65 +# Cortex-A7 MPU, JTAG and SWD +# +# https://www.microchip.com/en-us/product/sama7d65 +# DS60001851 +# +# JTAG-DP IDCODE: 0x6BA00477 +# SW-DP DPIDR: 0x6BA02477 +# +# JTAG access is disabled by ROM code during boot. +# It is enabled after AT91Bootstrap runs or SAM-BA Monitor entry. +# Transient DAP errors before bootstrap are caused by the watchdog. +# + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME sama7d6 +} + +if { [info exists ENDIAN] } { + set _ENDIAN $ENDIAN +} else { + set _ENDIAN little +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x6ba00477 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x6ba02477 +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID -expected-id $_DAP_TAPID -irlen 4 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu.0 +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -endian $_ENDIAN -ap-num 0 -dbgbase 0x80030000 + +# SRAM 128KB - shared with ROM code and AT91Bootstrap +$_TARGETNAME configure -work-area-phys 0x00100000 -work-area-size 0x20000 -work-area-backup 0 + +$_TARGETNAME configure -event examine-start { + adapter speed 1000 +} + +$_TARGETNAME configure -event examine-end { + if { [catch { $_TARGETNAME arp_halt }] } { + echo "Warning: Could not halt target - JTAG may not be enabled yet" + } + catch { $_TARGETNAME arp_waitstate halted 1000 } +} + +$_TARGETNAME configure -event reset-start { + adapter speed 1000 +} + +$_TARGETNAME configure -event reset-init { + adapter speed 4000 +} diff --git a/tcl/target/microchip/sama7g5.cfg b/tcl/target/microchip/sama7g5.cfg new file mode 100644 index 0000000000..ec4cedaf3c --- /dev/null +++ b/tcl/target/microchip/sama7g5.cfg @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip SAMA7G5 series: SAMA7G54 +# Cortex-A7 MPU, JTAG and SWD +# +# https://www.microchip.com/en-us/product/sama7g54 +# DS60001765 +# +# JTAG-DP IDCODE: 0x6BA00477 +# SW-DP DPIDR: 0x6BA02477 +# +# JTAG access is disabled by ROM code during boot. +# It is enabled after AT91Bootstrap runs or SAM-BA Monitor entry. +# Transient DAP errors before bootstrap are caused by the watchdog. +# + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME sama7g5 +} + +if { [info exists ENDIAN] } { + set _ENDIAN $ENDIAN +} else { + set _ENDIAN little +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x6ba00477 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x6ba02477 +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID -expected-id $_DAP_TAPID -irlen 4 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu.0 +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -endian $_ENDIAN -ap-num 0 -dbgbase 0x80030000 + +# SRAM 128KB - shared with ROM code and AT91Bootstrap +$_TARGETNAME configure -work-area-phys 0x00100000 -work-area-size 0x20000 -work-area-backup 0 + +$_TARGETNAME configure -event examine-start { + adapter speed 1000 +} + +$_TARGETNAME configure -event examine-end { + if { [catch { $_TARGETNAME arp_halt }] } { + echo "Warning: Could not halt target - JTAG may not be enabled yet" + } + catch { $_TARGETNAME arp_waitstate halted 1000 } +} + +$_TARGETNAME configure -event reset-start { + adapter speed 1000 +} + +$_TARGETNAME configure -event reset-init { + adapter speed 4000 +} diff --git a/tcl/target/ngultra.cfg b/tcl/target/ngultra.cfg index 9f9814fd75..99dcef81a5 100644 --- a/tcl/target/ngultra.cfg +++ b/tcl/target/ngultra.cfg @@ -48,3 +48,14 @@ for { set _core 0 } { $_core < $_cores } { incr _core } { # 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 + +lappend post_init_commands { + foreach t [target names] { + set dap [$t cget -dap] + set ap [$t cget -ap-num] + $dap apsel $ap + # speed up firmware upload by reducing nb of RUNTEST cycles + echo "NGUltra post-init: $dap AP.$ap set memaccess to 5" + $dap memaccess 5 + } +} diff --git a/tcl/target/nrf_common.cfg b/tcl/target/nordic/common.cfg similarity index 100% rename from tcl/target/nrf_common.cfg rename to tcl/target/nordic/common.cfg diff --git a/tcl/target/nrf51.cfg b/tcl/target/nordic/nrf51.cfg similarity index 89% rename from tcl/target/nrf51.cfg rename to tcl/target/nordic/nrf51.cfg index 3781eccb50..959ee432fd 100644 --- a/tcl/target/nrf51.cfg +++ b/tcl/target/nordic/nrf51.cfg @@ -3,8 +3,8 @@ # # script for Nordic nRF51 series, a Cortex-M0 chip # - -source [find target/swj-dp.tcl] +# Devices support SWD transport only +transport select swd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -12,12 +12,6 @@ if { [info exists CHIPNAME] } { set _CHIPNAME nrf51 } -if { [info exists ENDIAN] } { - set _ENDIAN $ENDIAN -} else { - set _ENDIAN little -} - # Work-area is a space in RAM used for flash programming # By default use 16kB if { [info exists WORKAREASIZE] } { @@ -32,7 +26,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x0bb11477 } -swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/nrf52.cfg b/tcl/target/nordic/nrf52.cfg similarity index 97% rename from tcl/target/nrf52.cfg rename to tcl/target/nordic/nrf52.cfg index 0703b18862..c151283dad 100644 --- a/tcl/target/nrf52.cfg +++ b/tcl/target/nordic/nrf52.cfg @@ -3,8 +3,9 @@ # # Nordic nRF52 series: ARM Cortex-M4 @ 64 MHz # +# Devices support SWD transport only +transport select swd -source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { @@ -27,7 +28,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x2ba01477 } -swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/nrf53.cfg b/tcl/target/nordic/nrf53.cfg similarity index 92% rename from tcl/target/nrf53.cfg rename to tcl/target/nordic/nrf53.cfg index 307df902c2..137897c577 100644 --- a/tcl/target/nrf53.cfg +++ b/tcl/target/nordic/nrf53.cfg @@ -3,8 +3,9 @@ # # Nordic nRF53 series: dual ARM Cortex-M33, multidrop SWD # +# Devices support SWD transport only +transport select swd -source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { @@ -34,7 +35,7 @@ if { [info exists SWD_INSTANCE_ID] } { set _SWD_INSTANCE_ID 0 } -swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID if { [info exists SWD_MULTIDROP] } { dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -dp-id 0x0070289 -instance-id $_SWD_INSTANCE_ID @@ -60,7 +61,7 @@ if { ![using_hla] } { # Keep adapter speed less or equal 2000 kHz or flash programming fails! adapter speed 1000 -source [find target/nrf_common.cfg] +source [find target/nordic/common.cfg] flash bank $_CHIPNAME.app.flash nrf5 0x00000000 0 0 0 $_TARGETNAME_APP flash bank $_CHIPNAME.app.uicr nrf5 0x00FF8000 0 0 0 $_TARGETNAME_APP @@ -71,9 +72,11 @@ if { ![using_hla] } { flash bank $_CHIPNAME.net.uicr nrf5 0x01FF8000 0 0 0 $_TARGETNAME_NET # System reset sets NETWORK.FORCEOFF which keeps the network core in reset - # Don't touch network core during reset - $_TARGETNAME_NET configure -event reset-assert {} - # and start it after application core reset is finished to make all flash accessible + # Don't touch network core during reset - the event handler is + # intentionally empty and prevents native processing + $_TARGETNAME_NET configure -event reset-assert {;} + # and start it after application core reset is finished to make + # all flash accessible $_TARGETNAME_APP configure -event reset-init "nrf53_cpunet_release $_CHIPNAME" $_TARGETNAME_APP cortex_m reset_config sysresetreq diff --git a/tcl/target/nrf91.cfg b/tcl/target/nordic/nrf91.cfg similarity index 91% rename from tcl/target/nrf91.cfg rename to tcl/target/nordic/nrf91.cfg index e0ff4e5460..826d627763 100644 --- a/tcl/target/nrf91.cfg +++ b/tcl/target/nordic/nrf91.cfg @@ -3,8 +3,9 @@ # # Nordic nRF91 series: ARM Cortex-M33, SWD only # +# Devices support SWD transport only +transport select swd -source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { @@ -27,7 +28,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x6ba02477 } -swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID # Contrary to the product specification at least nRF9161 supports multidrop SWD. # The instance ID is fixed, no more than one nRF91 can be connected to one SWD bus. @@ -45,7 +46,7 @@ adapter speed 1000 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -source [find target/nrf_common.cfg] +source [find target/nordic/common.cfg] flash bank $_CHIPNAME.flash nrf5 0x00000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.uicr nrf5 0x00FF8000 0 0 0 $_TARGETNAME diff --git a/tcl/target/npcx.cfg b/tcl/target/npcx.cfg index 84bb0b7a53..8ca9f14980 100644 --- a/tcl/target/npcx.cfg +++ b/tcl/target/npcx.cfg @@ -46,9 +46,6 @@ $_TARGETNAME configure -work-area-phys 0x200c0000 -work-area-size $_WORKAREASIZE # 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 diff --git a/tcl/target/numicro.cfg b/tcl/target/numicro.cfg index 29077f39f8..e492fa1601 100644 --- a/tcl/target/numicro.cfg +++ b/tcl/target/numicro.cfg @@ -2,8 +2,7 @@ # script for Nuvoton MuMicro Cortex-M0 Series -# Adapt based on what transport is active. -source [find target/swj-dp.tcl] +transport select swd # Set Chipname if { [info exists CHIPNAME] } { @@ -29,7 +28,7 @@ if { [info exists WORKAREASIZE] } { # Debug Adapter Target Settings -swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUDAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap diff --git a/tcl/target/numicro_m4.cfg b/tcl/target/numicro_m4.cfg index 1302515d34..ac242c417d 100644 --- a/tcl/target/numicro_m4.cfg +++ b/tcl/target/numicro_m4.cfg @@ -2,7 +2,7 @@ # script for Nuvoton MuMicro Cortex-M4 Series -source [find target/swj-dp.tcl] +transport select swd # Set Chipname if { [info exists CHIPNAME] } { @@ -28,7 +28,7 @@ if { [info exists WORKAREASIZE] } { # Debug Adapter Target Settings -swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUDAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap diff --git a/tcl/target/nxp/lx2160a.cfg b/tcl/target/nxp/lx2160a.cfg new file mode 100644 index 0000000000..40f2d4a420 --- /dev/null +++ b/tcl/target/nxp/lx2160a.cfg @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# NXP LX2160A - 16-core Arm Cortex-A72 QorIQ Layerscape SoC +# +# https://www.nxp.com/products/LX2160A +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME lx2160a +} + +if { [info exists NUMCORES] } { + set _NUMCORES $NUMCORES +} else { + set _NUMCORES 16 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x6ba00477 +} + +jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap + +set _TARGETNAME $_CHIPNAME.cpu +set _smp "target smp" + +# implementation has 2 cores in each core complex +for {set cc 0} {$cc < $_NUMCORES / 2} {incr cc} { + set core0 [format %x [expr {$cc * 2 + 0}]] + set core1 [format %x [expr {$cc * 2 + 1}]] + + cti create $_CHIPNAME.cti.$core0 \ + -dap $_CHIPNAME.dap -ap-num 0 \ + -baseaddr [expr {0x1020000 + $cc * 0x400000}] + target create $_CHIPNAME.cpu.$core0 aarch64 \ + -dap $_CHIPNAME.dap -ap-num 0 \ + -dbgbase [expr {0x1010000 + $cc * 0x400000}] \ + -cti $_CHIPNAME.cti.$core0 + cti create $_CHIPNAME.cti.$core1 \ + -dap $_CHIPNAME.dap -ap-num 0 \ + -baseaddr [expr {0x1120000 + $cc * 0x400000}] + target create $_CHIPNAME.cpu.$core1 aarch64 \ + -dap $_CHIPNAME.dap -ap-num 0 \ + -dbgbase [expr {0x1110000 + $cc * 0x400000}] \ + -cti $_CHIPNAME.cti.$core1 + + set _smp "$_smp $_CHIPNAME.cpu.$core0 $_CHIPNAME.cpu.$core1" + + unset core0 + unset core1 +} + +eval $_smp +targets lx2160a.cpu.0 + +# datasheet value, tested @ 15MHz +adapter speed 25000 diff --git a/tcl/target/psoc4.cfg b/tcl/target/psoc4.cfg index baa2c83f41..f9673638e8 100644 --- a/tcl/target/psoc4.cfg +++ b/tcl/target/psoc4.cfg @@ -5,7 +5,7 @@ # # PSoC 4 devices support SWD transports only. # -source [find target/swj-dp.tcl] +transport select swd if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -27,7 +27,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x0bb11477 } -swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/pxa255.cfg b/tcl/target/pxa255.cfg index 14ee13c372..a9cfc63d54 100644 --- a/tcl/target/pxa255.cfg +++ b/tcl/target/pxa255.cfg @@ -31,7 +31,6 @@ target create $_TARGETNAME xscale -endian $_ENDIAN \ # Until the PLL kicks in, keep the JTAG clock slow enough # that we get no errors. adapter speed 300 -$_TARGETNAME configure -event "reset-start" { adapter speed 300 } # both TRST and SRST are *required* for debug # DCSR is often accessed with SRST active diff --git a/tcl/target/qualcomm/qcs6490.cfg b/tcl/target/qualcomm/qcs6490.cfg new file mode 100644 index 0000000000..d12708c8a2 --- /dev/null +++ b/tcl/target/qualcomm/qcs6490.cfg @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# The QCS6490/QCM6490 is a 6nm processor designed for enterprise and Internet of Things (IOT) applications, +# featuring global 5G and Wi-Fi 6E support +# +# Product Page: +# https://www.qualcomm.com/products/internet-of-things/industrial/building-enterprise/qcs6490 +# https://www.qualcomm.com/products/internet-of-things/industrial/building-enterprise/qcm6490 + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME QCS6490 +} + +if { [info exists ENDIAN] } { + set _ENDIAN $ENDIAN +} else { + set _ENDIAN little +} + +adapter speed 500 +reset_config trst_and_srst + +# Set CUP TAP ID based on protocol selection +if { [using_jtag] } { + set _CPUTAPID 0x5ba00477 +} else { + set _CPUTAPID 0x5ba02477 +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID -irlen 4 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -ignore-syspwrupack + +cti create $_CHIPNAME.cti -dap $_CHIPNAME.dap -baseaddr 0x87020000 -ap-num 1 + +target create $_CHIPNAME.cpu0 aarch64 -endian $_ENDIAN -dap $_CHIPNAME.dap -coreid 0 \ + -dbgbase 0x87010000 -cti $_CHIPNAME.cti -event reset-assert-post { dap init } + +$_CHIPNAME.cpu0 configure -event examine-end { + eval $_CHIPNAME.cpu0 arp_halt +} + +# Default breakpoints to hardware breakpoints +gdb_breakpoint_override hard diff --git a/tcl/target/rk3588.cfg b/tcl/target/rk3588.cfg new file mode 100644 index 0000000000..7b470268a1 --- /dev/null +++ b/tcl/target/rk3588.cfg @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Rockchip RK3588 Target +# https://www.rock-chips.com/a/en/products/RK35_Series/2022/0926/1660.html +# Andreas Dannenberg + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME rk3588 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x2ba01477 +} + +adapter speed 4000 + +transport select swd + +# Declare the one SWD tap to access the DAP +swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID + +# Create the DAP +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# Create target to allow accessing system memory directly +target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 + +# Declare the 8 main application cores (4 little cores + 4 big cores) + +# Little cluster (cores 0..3) +set _TARGETNAME $_CHIPNAME.lcore +set $_TARGETNAME.base(0) 0x81004000 +set $_TARGETNAME.base(1) 0x81005000 +set $_TARGETNAME.base(2) 0x81006000 +set $_TARGETNAME.base(3) 0x81007000 +set $_TARGETNAME.cti(0) 0x81014000 +set $_TARGETNAME.cti(1) 0x81015000 +set $_TARGETNAME.cti(2) 0x81016000 +set $_TARGETNAME.cti(3) 0x81017000 + +# Big cluster (cores 4..7) +set _TARGETNAME $_CHIPNAME.bcore +set $_TARGETNAME.base(4) 0x81024000 +set $_TARGETNAME.base(5) 0x81025000 +set $_TARGETNAME.base(6) 0x81026000 +set $_TARGETNAME.base(7) 0x81027000 +set $_TARGETNAME.cti(4) 0x81034000 +set $_TARGETNAME.cti(5) 0x81035000 +set $_TARGETNAME.cti(6) 0x81036000 +set $_TARGETNAME.cti(7) 0x81037000 + +# Build string used to enable SMP mode +set _smp_command "target smp" + +set _cores 8 +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 0 + + target create ${_TARGETNAME}$_core aarch64 \ + -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core \ + -dbgbase [set $_TARGETNAME.base($_core)] + + if { $_core != 0 } { + # non-boot core examination may fail + ${_TARGETNAME}$_core configure -defer-examine + } else { + # uncomment to use hardware threads pseudo rtos + # ${_TARGETNAME}$_core configure -rtos hwthread + } + + set _smp_command "$_smp_command ${_TARGETNAME}$_core" +} + +eval $_smp_command + +# Set default target to boot core +targets $_CHIPNAME.lcore0 diff --git a/tcl/target/rp2040.cfg b/tcl/target/rp2040.cfg index f64d4322b1..e60892ebd2 100644 --- a/tcl/target/rp2040.cfg +++ b/tcl/target/rp2040.cfg @@ -1,13 +1,11 @@ # 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 +# https://www.raspberrypi.com/documentation/microcontrollers/silicon.html#rp2040 # The device requires multidrop SWD for debug. transport select swd -source [find target/swj-dp.tcl] - if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { @@ -50,7 +48,7 @@ if { [info exists USE_CORE] } { } set _BOTH_CORES [expr { $_USE_CORE != 0 && $_USE_CORE != 1 }] -swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +swd 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 @@ -83,9 +81,9 @@ if { $_USE_CORE != 1 } { # srst does not exist; use SYSRESETREQ to perform a soft reset $_TARGETNAME_0 cortex_m reset_config sysresetreq - # After a rescue reset and fi BOOTSEL is halted connect the flash to enable + # After a rescue reset or if halted in BOOTSEL connect the flash to enable # reads from the XIP cached mapping area - $_TARGETNAME_0 configure -event reset-init { rp2xxx rom_api_call 0 CX } + $_TARGETNAME_0 configure -event reset-init { rp2xxx rom_api_call CX } } # core 1 diff --git a/tcl/target/rp2350.cfg b/tcl/target/rp2350.cfg index b7617acd4c..afa16261c4 100644 --- a/tcl/target/rp2350.cfg +++ b/tcl/target/rp2350.cfg @@ -1,12 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-or-later # RP2350 is a microcontroller with dual Cortex-M33 cores or dual Hazard3 RISC-V cores. -# https://www.raspberrypi.com/documentation/microcontrollers/rp2350.html +# https://www.raspberrypi.com/documentation/microcontrollers/silicon.html#rp2350 transport select swd -source [find target/swj-dp.tcl] - if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { @@ -51,7 +49,7 @@ if { [info exists USE_CORE] } { set _USE_CORE { cm0 cm1 } } -swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID if { [info exists SWD_MULTIDROP] } { dap create $_CHIPNAME.dap -adiv6 -chain-position $_CHIPNAME.cpu -dp-id 0x0040927 -instance-id 0 @@ -100,7 +98,7 @@ if { [info exists _TARGETNAME_CM0] } { if { [info exists _TARGETNAME_RV0] } { target create $_TARGETNAME_RV0 riscv -dap $_CHIPNAME.dap -ap-num 0xa000 -coreid 0 - $_TARGETNAME_RV0 riscv set_enable_virt2phys off + $_TARGETNAME_RV0 riscv virt2phys_mode off $_TARGETNAME_RV0 configure -event reset-init "_rv_reset_init" @@ -117,7 +115,7 @@ if { [info exists _TARGETNAME_CM1] } { if { [info exists _TARGETNAME_RV1] } { target create $_TARGETNAME_RV1 riscv -dap $_CHIPNAME.dap -ap-num 0xa000 -coreid 1 - $_TARGETNAME_RV1 riscv set_enable_virt2phys off + $_TARGETNAME_RV1 riscv virt2phys_mode off } if { [info exists USE_SMP] } { diff --git a/tcl/target/silabs/series0.cfg b/tcl/target/silabs/series0.cfg new file mode 100644 index 0000000000..c0cfcb2a1c --- /dev/null +++ b/tcl/target/silabs/series0.cfg @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Silicon Labs (formerly Energy Micro) EFM32 target +# +# Note: All EFM32 chips have SWD support, but only newer series 1 +# chips have JTAG support. +# + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME efm32 +} + +# Work-area is a space in RAM used for flash programming +# By default use 2kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x800 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x4ba00477 + } { + set _CPUTAPID 0x2ba01477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +adapter speed 1000 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +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 + # perform a soft reset + cortex_m reset_config sysresetreq +} diff --git a/tcl/target/silabs/series1.cfg b/tcl/target/silabs/series1.cfg new file mode 100644 index 0000000000..fe793d0f59 --- /dev/null +++ b/tcl/target/silabs/series1.cfg @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026 Silicon Laboratories Inc. + +source [find target/silabs/series0.cfg] diff --git a/tcl/target/silabs/series2.cfg b/tcl/target/silabs/series2.cfg new file mode 100644 index 0000000000..f3182a5029 --- /dev/null +++ b/tcl/target/silabs/series2.cfg @@ -0,0 +1,241 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026 Silicon Laboratories Inc. +# +# Silicon Labs Series 2 targets. These target are usually branded as EFM32PG2x +# or EFR32xG2x (eg. EFM32PG28, EFR32MG27, ...). + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME efm32 +} + +# Work-area is a space in RAM used for flash programming. By default use 2kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x800 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + # Cortex-M33 TAP IDs for Series 2 + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } { + set _CPUTAPID 0x6ba02477 + } +} + +# Family group xg21 and xg22 has flash base address 0x00000000. The others has +# flash base address 0x08000000 +if { [info exists FLASHBASE] } { + set _FLASHBASE $FLASHBASE +} else { + set _FLASHBASE 0x08000000 +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +adapter speed 1000 + +# DCI (Debug Control Interface) is accessible via MEM-AP 1 +set _DCINAME $_CHIPNAME.dci +target create $_DCINAME mem_ap -dap $_CHIPNAME.dap -ap-num 1 + +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.flash +flash bank $_FLASHNAME efm32 $_FLASHBASE 0 0 0 $_TARGETNAME +flash bank userdata.flash efm32 0x0FE00000 0 0 0 $_TARGETNAME + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to perform a soft reset + cortex_m reset_config sysresetreq + + $_TARGETNAME configure -event examine-fail { + if [catch silabs_s2_dci_read_se_status errstr] { + echo $errstr + } + } +} + +# Debug Challenge Interface registers. See +# https://docs.silabs.com/iot-security/1.2.2/series2-secure-debug/ +# https://docs.silabs.com/iot-security/1.2.2/efr32-dci-swd-programming/ +set _DCI_REG_WDATA 0x1000 +set _DCI_REG_RDATA 0x1004 +set _DCI_REG_STATUS 0x1008 +set _DCI_REG_ID 0x10FC + +proc silabs_s2_dci_connect {} { + global _DCINAME _DCI_REG_ID + + if [catch {$_DCINAME read_memory $_DCI_REG_ID 32 1} dciid] { + return -code error "Failed to read DCIID" + } + if {$dciid != 0xdc11d} { + return -code error "Failed to read correct DCIID (got $dciid)" + } + echo "Successfully connected to DCI" +} + +proc silabs_s2_dci_read_status {} { + global _DCINAME _DCI_REG_STATUS + + return [$_DCINAME read_memory $_DCI_REG_STATUS 32 1] +} + +proc silabs_s2_dci_write_cmd {dci_write_word} { + global _DCINAME _DCI_REG_WDATA + + for {set i 0} {$i < 100} {incr i} { + set dcistatus [silabs_s2_dci_read_status] + + if {$dcistatus & 1} { + echo "DCI WPENDING bit set, retrying" + sleep 10 + continue + } + + if {$dcistatus & 0x100} { + echo "DCI RDATAVALID is set, can't write to DCIWRITE" + return -1 + } + + $_DCINAME write_memory $_DCI_REG_WDATA 32 $dci_write_word + return 0 + } + + echo "DCI write timeout" + return -1 +} + +proc silabs_s2_dci_read_response {} { + global _DCINAME _DCI_REG_RDATA + + for {set i 0} {$i < 100} {incr i} { + set dcistatus [silabs_s2_dci_read_status] + + if {$dcistatus & 0x100} { + return [$_DCINAME read_memory $_DCI_REG_RDATA 32 1] + } + + echo "DCI RDATAVALID is not set, retrying" + sleep 10 + } + + echo "DCI read timeout" + return -1 +} + +proc silabs_s2_dci_device_erase {} { + silabs_s2_dci_connect + poll off + + silabs_s2_dci_write_cmd 8 + silabs_s2_dci_write_cmd 0x430F0000 + + sleep 2000 + echo "Device erase command sent. Device should now be erased and debug should be available again after a reset" + poll on +} + +proc silabs_s2_dci_device_lock {} { + echo "Attempting to activate debug lock..." + + silabs_s2_dci_connect + poll off + + silabs_s2_dci_write_cmd 8 + silabs_s2_dci_write_cmd 0x430C0000 + + set recvlen [silabs_s2_dci_read_response] + + if {$recvlen & 0xFFFF0000} { + echo "command response was not OK, got $recvlen as command response. Can't continue." + poll on + return + } + + sleep 100 + + silabs_s2_dci_read_se_status + poll on +} + +proc silabs_s2_dci_read_se_status {} { + silabs_s2_dci_connect + poll off + + # Write len + silabs_s2_dci_write_cmd 8 + + # Write cmd + silabs_s2_dci_write_cmd 0xFE010000 + + set recvlen [silabs_s2_dci_read_response] + + if {$recvlen & 0xFFFF0000} { + echo "command response was not OK, got $recvlen as command response. Can't continue." + poll on + return + } + + set debuglock_idx 3 + + if {$recvlen == 0x28} { + set debuglock_idx 7 + } + + incr recvlen -4 + + for {set i 0} {$recvlen > 0} {incr i} { + set recvlen [expr {$recvlen - 4}] + set sestatusarray($i) [silabs_s2_dci_read_response] + } + + poll on + + echo "DCI SESTATUS response:" + + set debuglock $sestatusarray($debuglock_idx) + + if {$debuglock & 0x01} { + echo "Debug lock (config): Enabled" + } else { + echo "Debug lock (config): Disabled" + } + + if {$debuglock & 0x02} { + echo "Device erase: Enabled" + } else { + echo "Device erase: Disabled" + } + + if {$debuglock & 0x04} { + echo "Secure debug: Enabled" + } else { + echo "Secure debug: Disabled" + } + + if {$debuglock & 0x20} { + poll off + echo "Debug lock (hw status): Enabled" + echo "" + echo " * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *" + echo " You will not be able to communicate with this device" + echo " unless you perform a device erase (if available, indicated above)!" + echo " Try silabs_s2_dci_device_erase to attempt erase." + echo " * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *" + } else { + echo "Debug lock (hw status): Disabled" + } +} diff --git a/tcl/target/silabs/xg21.cfg b/tcl/target/silabs/xg21.cfg new file mode 100644 index 0000000000..bc6e50ceae --- /dev/null +++ b/tcl/target/silabs/xg21.cfg @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026 Silicon Laboratories Inc. +# +# Silicon Labs EFM32PG21/EFR32xG21 target + +set FLASHBASE 0x00000000 +source [find target/silabs/series2.cfg] diff --git a/tcl/target/silabs/xg23.cfg b/tcl/target/silabs/xg23.cfg new file mode 100644 index 0000000000..c166f2fc42 --- /dev/null +++ b/tcl/target/silabs/xg23.cfg @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026 Silicon Laboratories Inc. +# +# Silicon Labs EFM32PG23/EFR32xG23 target + +set FLASHBASE 0x08000000 +source [find target/silabs/series2.cfg] diff --git a/tcl/target/silabs/xg24.cfg b/tcl/target/silabs/xg24.cfg new file mode 100644 index 0000000000..ad40c597eb --- /dev/null +++ b/tcl/target/silabs/xg24.cfg @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026 Silicon Laboratories Inc. +# +# Silicon Labs EFM32PG24/EFR32xG24 target + +set FLASHBASE 0x08000000 +source [find target/silabs/series2.cfg] diff --git a/tcl/target/silabs/xg25.cfg b/tcl/target/silabs/xg25.cfg new file mode 100644 index 0000000000..e238755be0 --- /dev/null +++ b/tcl/target/silabs/xg25.cfg @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026 Silicon Laboratories Inc. +# +# Silicon Labs EFM32PG25/EFR32xG25 target + +set FLASHBASE 0x08000000 +source [find target/silabs/series2.cfg] diff --git a/tcl/target/silabs/xg26.cfg b/tcl/target/silabs/xg26.cfg new file mode 100644 index 0000000000..8aa0c7af17 --- /dev/null +++ b/tcl/target/silabs/xg26.cfg @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026 Silicon Laboratories Inc. +# +# Silicon Labs EFM32PG26/EFR32xG26 target + +set FLASHBASE 0x08000000 +source [find target/silabs/series2.cfg] diff --git a/tcl/target/silabs/xg28.cfg b/tcl/target/silabs/xg28.cfg new file mode 100644 index 0000000000..15705c486e --- /dev/null +++ b/tcl/target/silabs/xg28.cfg @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026 Silicon Laboratories Inc. +# +# Silicon Labs EFM32PG28/EFR32xG28 target + +set FLASHBASE 0x08000000 +source [find target/silabs/series2.cfg] diff --git a/tcl/target/silabs/xg29.cfg b/tcl/target/silabs/xg29.cfg new file mode 100644 index 0000000000..224b516fb4 --- /dev/null +++ b/tcl/target/silabs/xg29.cfg @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026 Silicon Laboratories Inc. +# +# Silicon Labs EFM32PG29/EFR32xG29 target + +set FLASHBASE 0x08000000 +source [find target/silabs/series2.cfg] diff --git a/tcl/target/stm32mp13x.cfg b/tcl/target/st/stm32mp13x.cfg similarity index 63% rename from tcl/target/stm32mp13x.cfg rename to tcl/target/st/stm32mp13x.cfg index bcf25c9049..adf2ef8d05 100644 --- a/tcl/target/stm32mp13x.cfg +++ b/tcl/target/st/stm32mp13x.cfg @@ -40,13 +40,17 @@ if { [using_jtag] } { jtag newtap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 } -dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack +if { [info exists SWD_MULTIDROP] } { + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack -dp-id 0x05010041 -instance-id 0 +} else { + 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 +target create $_CHIPNAME.cpu cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 -defer-examine $_CHIPNAME.cpu cortex_a maskisr on $_CHIPNAME.cpu cortex_a dacrfixup on @@ -76,27 +80,61 @@ proc axi_nsecure {} { axi_secure -proc dbgmcu_enable_debug {} { +# mmw with target selection +proc target_mmw {target reg setbits clearbits} { + set val [eval $target read_memory $reg 32 1] + set val [expr {($val & ~$clearbits) | $setbits}] + eval $target mww $reg $val +} + +lappend _telnet_autocomplete_skip _enable_debug +# Uses AP1 +proc _enable_debug {} { # keep clock enabled in low-power - ## catch {$::_CHIPNAME.ap1 mww 0xe0081004 0x00000004} + 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 +lappend _telnet_autocomplete_skip _handshake_with_wrapper +# Uses AP1 +proc _handshake_with_wrapper { halt } { + set dbgmcu_cr 0 + catch {set dbgmcu_cr [eval $::_CHIPNAME.ap1 read_memory 0xe0081004 32 1]} + if {[expr {($dbgmcu_cr & 0x07) == 0x00}]} { + echo "\nWARNING: FSBL wrapper not detected. Board in dev boot mode?\n" + return + } + + if { $halt } { + $::_CHIPNAME.ap1 arp_halt + $::_CHIPNAME.ap1 mww 0xe00d0300 0 + target_mmw $::_CHIPNAME.ap1 0xe00d0088 0x00004000 0 + } + + $::_CHIPNAME.ap1 mww 0xe0081004 0x7 } # FIXME: most of handlers below will be removed once reset framework get merged +$_CHIPNAME.ap1 configure -event reset-assert-post { + adapter assert srst +} + $_CHIPNAME.ap1 configure -event reset-deassert-pre { adapter deassert srst deassert trst catch {dap init} catch {$::_CHIPNAME.dap apid 1} + $::_CHIPNAME.ap1 arp_examine + _handshake_with_wrapper $halt + _enable_debug + $::_CHIPNAME.cpu arp_examine + if { $halt } { + $::_CHIPNAME.cpu arp_halt + } +} + +$_CHIPNAME.ap1 configure -event examine-end { + _enable_debug + $::_CHIPNAME.cpu arp_examine } -$_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/st/stm32mp15x.cfg similarity index 56% rename from tcl/target/stm32mp15x.cfg rename to tcl/target/st/stm32mp15x.cfg index bcdda73e90..b83f89b4be 100644 --- a/tcl/target/stm32mp15x.cfg +++ b/tcl/target/st/stm32mp15x.cfg @@ -18,6 +18,17 @@ if { [info exists CHIPNAME] } { set _CHIPNAME stm32mp15x } +# Set to 0 to prevent CPU examine. Default examine them +if { ! [info exists EN_CA7_0] } { + set EN_CA7_0 1 +} +if { ! [info exists EN_CA7_1] } { + set EN_CA7_1 1 +} +if { ! [info exists EN_CM4] } { + set EN_CM4 1 +} + if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { @@ -40,22 +51,27 @@ if { [using_jtag] } { jtag newtap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 } -dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack +if { [info exists SWD_MULTIDROP] } { + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack -dp-id 0x05000041 -instance-id 0 +} else { + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack +} -# FIXME: Cortex-M code requires target accessible during reset, but this is not possible in STM32MP1 -# so defer-examine it until the reset framework get merged # 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.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 -target create $_CHIPNAME.cpu0 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 -target create $_CHIPNAME.cpu1 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 1 -dbgbase 0xE00D2000 +target create $_CHIPNAME.cpu0 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 -defer-examine +target create $_CHIPNAME.cpu1 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 1 -dbgbase 0xE00D2000 -defer-examine target create $_CHIPNAME.cm4 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine targets $_CHIPNAME.cpu0 target smp $_CHIPNAME.cpu0 $_CHIPNAME.cpu1 +$_CHIPNAME.cpu0 configure -rtos hwthread +$_CHIPNAME.cpu1 configure -rtos hwthread + $_CHIPNAME.cpu0 cortex_a maskisr on $_CHIPNAME.cpu1 cortex_a maskisr on $_CHIPNAME.cpu0 cortex_a dacrfixup on @@ -96,7 +112,16 @@ proc axi_nsecure {} { axi_secure -proc dbgmcu_enable_debug {} { +# mmw with target selection +proc target_mmw {target reg setbits clearbits} { + set val [eval $target read_memory $reg 32 1] + set val [expr {($val & ~$clearbits) | $setbits}] + eval $target mww $reg $val +} + +lappend _telnet_autocomplete_skip _enable_debug +# Uses AP1 +proc _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 @@ -104,30 +129,99 @@ proc dbgmcu_enable_debug {} { catch {$::_CHIPNAME.ap1 mww 0xe008104c 0x00000008} } -proc toggle_cpu0_dbg_claim0 {} { - # toggle CPU0 DBG_CLAIM[0] - $::_CHIPNAME.ap1 mww 0xe00d0fa0 1 - $::_CHIPNAME.ap1 mww 0xe00d0fa4 1 +lappend _telnet_autocomplete_skip _handshake_with_wrapper +# Uses AP1 +proc _handshake_with_wrapper { halt } { + set dbgmcu_cr 0 + catch {set dbgmcu_cr [eval $::_CHIPNAME.ap1 read_memory 0xe0081004 32 1]} + if {[expr {($dbgmcu_cr & 0x07) == 0x00}]} { + echo "\nWARNING: FSBL wrapper not detected. Board in dev boot mode?\n" + return + } + + if { $halt } { + $::_CHIPNAME.ap1 arp_halt + if { $::EN_CA7_0 } { + $::_CHIPNAME.ap1 arp_halt + $::_CHIPNAME.ap1 mww 0xe00d0300 0 + target_mmw $::_CHIPNAME.ap1 0xe00d0088 0x00004000 0 + } + } + + $::_CHIPNAME.ap1 mww 0xe0081004 0x7 } -proc detect_cpu1 {} { +lappend _telnet_autocomplete_skip _detect_cpu1 +# Uses AP1 +proc _detect_cpu1 {} { + if { !$::EN_CA7_1 } { + return + } + 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} + if { !$dual_core } { + set ::EN_CA7_1 0 + } } -proc rcc_enable_traceclk {} { +lappend _telnet_autocomplete_skip _rcc_enable_traceclk +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;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} -$_CHIPNAME.cm4 configure -event reset-deassert-post {$::_CHIPNAME.cm4 arp_examine;if {[$::_CHIPNAME.ap2 curstate] == "halted"} {$::_CHIPNAME.cm4 arp_poll;$::_CHIPNAME.cm4 arp_poll;$::_CHIPNAME.cm4 arp_halt}} -$_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 {rcc_enable_traceclk;$::_CHIPNAME.cm4 arp_examine} +$_CHIPNAME.cm4 configure -event reset-assert { } + +$_CHIPNAME.ap1 configure -event reset-assert-post { + adapter assert srst +} + +$_CHIPNAME.ap1 configure -event reset-deassert-pre { + adapter deassert srst deassert trst + catch {dap init} + catch {$::_CHIPNAME.dap apid 1} + $::_CHIPNAME.ap1 arp_examine + _handshake_with_wrapper $halt + if { $::EN_CA7_0 } { + $::_CHIPNAME.cpu0 arp_examine + if { $halt } { + $::_CHIPNAME.cpu0 arp_halt + } + } + if { $::EN_CA7_1 } { + $::_CHIPNAME.cpu1 arp_examine + if { $halt } { + $::_CHIPNAME.cpu1 arp_halt + } + } + _enable_debug +} + +$_CHIPNAME.ap2 configure -event reset-deassert-pre { + _rcc_enable_traceclk + if { $::EN_CM4 } { + $::_CHIPNAME.cm4 arp_examine + if { $halt } { + $::_CHIPNAME.cm4 arp_halt + } + } +} + +$_CHIPNAME.ap1 configure -event examine-end { + _enable_debug + _detect_cpu1 + if { $::EN_CA7_0 } { + $::_CHIPNAME.cpu0 arp_examine + } + if { $::EN_CA7_1 } { + $::_CHIPNAME.cpu1 arp_examine + } +} + +$_CHIPNAME.ap2 configure -event examine-end { + _rcc_enable_traceclk + if { $::EN_CM4 } { + $::_CHIPNAME.cm4 arp_examine + } +} diff --git a/tcl/target/st/stm32mp21x.cfg b/tcl/target/st/stm32mp21x.cfg new file mode 100644 index 0000000000..2cc37738bd --- /dev/null +++ b/tcl/target/st/stm32mp21x.cfg @@ -0,0 +1,232 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# STMicroelectronics STM32MP21x +# STM32MP21x devices support both JTAG and SWD transports. + +# HLA does not support multi-cores nor custom CSW nor AP other than 0 +if { [using_hla] } { + echo "ERROR: HLA transport cannot work with this target." + shutdown +} + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32mp21x +} + +# Set to 0 to prevent CPU examine. Default examine them +if { ! [info exists EN_CA35] } { + set EN_CA35 1 +} +if { ! [info exists EN_CM33] } { + set EN_CM33 1 +} + +set _ENDIAN little + +# jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } { + set _CPUTAPID 0x6ba02477 + } +} + +# Chip Level TAP Controller, only in jtag mode +if { [info exists CLCTAPID] } { + set _CLCTAPID $CLCTAPID +} else { + set _CLCTAPID 0x16503041 +} + +swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 -ircapture 0x01 -irmask 0x0f +if { [using_jtag] } { + swj_newdap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 +} + +if { [info exists SWD_MULTIDROP] } { + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -dp-id 0x05030041 -instance-id 0 +} else { + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap +} + +# define AXI & APB Memory Access Ports +# NOTE: do not change the order of target create +target create $_CHIPNAME.ap0 mem_ap -dap $_CHIPNAME.dap -ap-num 0 +target create $_CHIPNAME.ap1 mem_ap -dap $_CHIPNAME.dap -ap-num 1 +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 2 +target create $_CHIPNAME.ap3 mem_ap -dap $_CHIPNAME.dap -ap-num 3 -defer-examine + +# define the Cortex-A35 +cti create $_CHIPNAME.cti.a35 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80220000 +target create $_CHIPNAME.a35 aarch64 -dap $_CHIPNAME.dap -ap-num 1 -dbgbase 0x80210000 \ + -cti $_CHIPNAME.cti.a35 -defer-examine + +# define the Cortex-M33 +target create $_CHIPNAME.m33 cortex_m -dap $_CHIPNAME.dap -ap-num 3 -defer-examine +cti create $_CHIPNAME.cti.m33 -dap $_CHIPNAME.dap -ap-num 3 -baseaddr 0xe0042000 + +# define the system CTIs +cti create $_CHIPNAME.cti.sys0 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80080000 +cti create $_CHIPNAME.cti.sys1 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80090000 + +swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x800A0000 +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80040000 + +targets $_CHIPNAME.a35 + +reset_config srst_pulls_trst + +adapter speed 5000 +adapter srst pulse_width 200 +# wait 1 seconds for bootrom +adapter srst delay 1000 + +# set CSW for AXI +$_CHIPNAME.dap apsel 2 +$_CHIPNAME.dap apcsw 0x12800000 + +# set CSW for Cortex-M33 D-Cache +$_CHIPNAME.dap apsel 3 +$_CHIPNAME.dap apcsw 0x1a000000 + +# mmw with target selection +proc target_mmw {target reg setbits clearbits} { + set val [eval $target read_memory $reg 32 1] + set val [expr {($val & ~$clearbits) | $setbits}] + eval $target mww $reg $val +} + +lappend _telnet_autocomplete_skip _enable_debug +# Uses AP0 and AXI +proc _enable_debug {} { + # Enable DBGMCU clock in RC + $::_CHIPNAME.axi mww 0x44200520 0x500 + + # set debug enable bits in DBGMCU_CR to get ap3/cm33 visible + $::_CHIPNAME.ap0 mww 0x80001004 0x7 + + # Freeze watchdogs on CPU halt + $::_CHIPNAME.axi mww 0x440a003c 0x00000026 + $::_CHIPNAME.axi mww 0x440a0040 0x00000038 +} + +lappend _telnet_autocomplete_skip _rcc_enable_traceclk +# Uses AXI +proc _rcc_enable_traceclk {} { + # set bit TRACEEN in RCC_DBGCFGR to clock TPIU + target_mmw $::_CHIPNAME.axi 0x44200520 0x200 0 +} + +lappend _telnet_autocomplete_skip _handshake_with_wrapper +# Uses AP0, AP1 and AP3 +proc _handshake_with_wrapper { halt } { + set dbgmcu_cr 0 + catch {set dbgmcu_cr [eval $::_CHIPNAME.ap0 read_memory 0x80001004 32 1]} + if {[expr {($dbgmcu_cr & 0x07) == 0x00}]} { + echo "\nWARNING: FSBL wrapper not detected. Board in dev boot mode?\n" + return + } + + if { $halt } { + if { $::EN_CA35 } { + $::_CHIPNAME.ap1 arp_examine + $::_CHIPNAME.ap1 arp_halt + $::_CHIPNAME.ap1 mww 0x80210300 0 + target_mmw $::_CHIPNAME.ap1 0x80210088 0x00004000 0 + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap3 arp_examine + $::_CHIPNAME.ap3 arp_halt + $::_CHIPNAME.ap3 mww 0xe000edf0 0xa05f0001 + } + } + + # alert wrapper that debugger is ready + $::_CHIPNAME.ap0 mww 0x80001004 0x07 +} + +lappend _telnet_autocomplete_skip _enable_dbgmcu_on_devboot +# In DEV BOOT the BootROM does not completes the sequence to enable the +# visibility of DBGMCU on AP0. +# Write a value in DBGMCU_DBG_AUTH_DEV from CID1. +# Returns 1 if DEV BOOT is detected +# Uses AP2 (AXI bus) +proc _enable_dbgmcu_on_devboot {} { + $::_CHIPNAME.axi mww 0x44230004 0 + set boot_pins [expr {[$::_CHIPNAME.axi read_memory 0x44230000 32 1] & 0xf}] + if {$boot_pins != 0x3 && $boot_pins != 0xc} { + return 0 + } + + set rifsc_rimc_cr [$::_CHIPNAME.axi read_memory 0x42080c00 32 1] + if {$rifsc_rimc_cr != 0x00008710} { + echo "RIFSC_RIMC_CR modified, skip activation of DBGMCU" + return 1 + } + + # Enable DBGMCU clock in RC + $::_CHIPNAME.axi mww 0x44200520 0x500 + + # Change DAP (AXI) CID, write in DBGMCU, set back DAP CID + $::_CHIPNAME.axi mww 0x42080c00 0x00008110 + $::_CHIPNAME.axi mww 0x440A0104 1 + $::_CHIPNAME.axi mww 0x42080c00 0x00008710 + return 1 +} + +$_CHIPNAME.m33 configure -event reset-assert { } + +$_CHIPNAME.axi configure -event reset-assert-post { + adapter assert srst +} + +$_CHIPNAME.axi configure -event reset-deassert-pre { + adapter deassert srst deassert trst + catch {dap init} + catch {$::_CHIPNAME.dap apid 0} + $::_CHIPNAME.axi arp_examine + set is_dev_boot [_enable_dbgmcu_on_devboot] + if { !$is_dev_boot } { + _handshake_with_wrapper $halt + } + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35 } { + $::_CHIPNAME.a35 arp_examine + if { $halt } { + $::_CHIPNAME.a35 arp_halt + } + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap3 arp_examine + $::_CHIPNAME.m33 arp_examine + if { $halt } { + $::_CHIPNAME.ap3 arp_halt + $::_CHIPNAME.m33 arp_halt + } + } +} + +$_CHIPNAME.axi configure -event examine-end { + set is_dev_boot [_enable_dbgmcu_on_devboot] + if { $is_dev_boot } { + echo "Dev boot detected" + } + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35 } { + $::_CHIPNAME.a35 arp_examine + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap3 arp_examine + $::_CHIPNAME.m33 arp_examine + } +} diff --git a/tcl/target/st/stm32mp23x.cfg b/tcl/target/st/stm32mp23x.cfg new file mode 100644 index 0000000000..4cba8400f1 --- /dev/null +++ b/tcl/target/st/stm32mp23x.cfg @@ -0,0 +1,220 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# STMicroelectronics STM32MP23x +# STM32MP23x devices support both JTAG and SWD transports. + +# HLA does not support multi-cores nor custom CSW nor AP other than 0 +if { [using_hla] } { + echo "ERROR: HLA transport cannot work with this target." + shutdown +} + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32mp23x +} + +# Set to 0 to prevent CPU examine. Default examine them +if { ! [info exists EN_CA35_0] } { + set EN_CA35_0 1 +} +if { ! [info exists EN_CA35_1] } { + set EN_CA35_1 1 +} +if { ! [info exists EN_CM33] } { + set EN_CM33 1 +} + +set _ENDIAN little + +# jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } { + set _CPUTAPID 0x6ba02477 + } +} + +# Chip Level TAP Controller, only in jtag mode +if { [info exists CLCTAPID] } { + set _CLCTAPID $CLCTAPID +} else { + set _CLCTAPID 0x16505041 +} + +swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 -ircapture 0x01 -irmask 0x0f +if { [using_jtag] } { + swj_newdap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 +} + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap + +# define AXI & APB Memory Access Ports +# NOTE: do not change the order of target create +target create $_CHIPNAME.ap0 mem_ap -dap $_CHIPNAME.dap -ap-num 0 +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 4 +target create $_CHIPNAME.ap8 mem_ap -dap $_CHIPNAME.dap -ap-num 8 -defer-examine + +# define the first Cortex-A35 +cti create $_CHIPNAME.cti.a35_0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80220000 +target create $_CHIPNAME.a35_0 aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80210000 \ + -cti $_CHIPNAME.cti.a35_0 -defer-examine + +# define the second Cortex-A35 +cti create $_CHIPNAME.cti.a35_1 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80320000 +target create $_CHIPNAME.a35_1 aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80310000 \ + -cti $_CHIPNAME.cti.a35_1 -defer-examine + +# define the Cortex-M33 +target create $_CHIPNAME.m33 cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine +cti create $_CHIPNAME.cti.m33 -dap $_CHIPNAME.dap -ap-num 8 -baseaddr 0xe0042000 + +# define the system CTIs +cti create $_CHIPNAME.cti.sys0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80090000 +cti create $_CHIPNAME.cti.sys1 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x800a0000 + +swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x800b0000 +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80050000 + +targets $_CHIPNAME.a35_0 + +target smp $_CHIPNAME.a35_0 $_CHIPNAME.a35_1 +$_CHIPNAME.a35_0 configure -rtos hwthread +$_CHIPNAME.a35_1 configure -rtos hwthread + +reset_config srst_gates_jtag srst_pulls_trst + +adapter speed 5000 +adapter srst pulse_width 200 +# wait 1 seconds for bootrom +adapter srst delay 1000 + +# set CSW for AXI +$_CHIPNAME.dap apsel 4 +$_CHIPNAME.dap apcsw 0x12800000 + +# set CSW for Cortex-M33 D-Cache +$_CHIPNAME.dap apsel 8 +$_CHIPNAME.dap apcsw 0x1a000000 + +# mmw with target selection +proc target_mmw {target reg setbits clearbits} { + set val [eval $target read_memory $reg 32 1] + set val [expr {($val & ~$clearbits) | $setbits}] + eval $target mww $reg $val +} + +lappend _telnet_autocomplete_skip _enable_debug +# Uses AP0 and AXI +proc _enable_debug {} { + # set debug enable bits in DBGMCU_CR to get ap8/cm33 visible + $::_CHIPNAME.ap0 mww 0x80010004 0x17 + + # Freeze watchdogs on CPU halt + $::_CHIPNAME.axi mww 0x4a010008 0x00000000 + $::_CHIPNAME.axi mww 0x4a01003c 0x00000026 + $::_CHIPNAME.axi mww 0x4a010040 0x00000038 + $::_CHIPNAME.axi mww 0x4a010044 0x00000400 + $::_CHIPNAME.axi mww 0x4a010048 0x00000400 + $::_CHIPNAME.axi mww 0x4a01004c 0x00000600 +} + +lappend _telnet_autocomplete_skip _rcc_enable_traceclk +# Uses AXI +proc _rcc_enable_traceclk {} { + # set bit TRACEEN in RCC_DBGCFGR to clock TPIU + target_mmw $::_CHIPNAME.axi 0x44200520 0x200 0 +} + +lappend _telnet_autocomplete_skip _handshake_with_wrapper +# Uses AP0 +proc _handshake_with_wrapper { halt } { + set dbgmcu_cr 0 + catch {set dbgmcu_cr [eval $::_CHIPNAME.ap0 read_memory 0x80010004 32 1]} + if {[expr {($dbgmcu_cr & 0x07) == 0x00}]} { + echo "\nWARNING: FSBL wrapper not detected. Board in dev boot mode?\n" + return; + } + + if { $halt } { + if { $::EN_CA35_0 || $::EN_CA35_1 } { + $::_CHIPNAME.ap0 arp_examine + $::_CHIPNAME.ap0 arp_halt + } + if { $::EN_CA35_0 } { + $::_CHIPNAME.ap0 mww 0x80210300 0 + target_mmw $::_CHIPNAME.ap0 0x80210088 0x00004000 0 + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.ap0 mww 0x80310300 0 + target_mmw $::_CHIPNAME.ap0 0x80310088 0x00004000 0 + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.ap8 arp_halt + $::_CHIPNAME.ap8 mww 0xe000edf0 0xa05f0001 + } + } + + # alert wrapper that debugger is ready + $::_CHIPNAME.ap0 mww 0x80010004 0x17 +} + +$_CHIPNAME.m33 configure -event reset-assert { } + +$_CHIPNAME.axi configure -event reset-assert-post { + adapter assert srst +} + +$_CHIPNAME.axi configure -event reset-deassert-pre { + adapter deassert srst deassert trst + catch {dap init} + catch {$::_CHIPNAME.dap apid 0} + $::_CHIPNAME.ap0 arp_examine + _handshake_with_wrapper $halt + + $::_CHIPNAME.axi arp_examine + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35_0 } { + $::_CHIPNAME.a35_0 arp_examine + if { $halt } { + $::_CHIPNAME.a35_0 arp_halt + } + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.a35_1 arp_examine + if { $halt } { + $::_CHIPNAME.a35_1 arp_halt + } + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.m33 arp_examine + if { $halt } { + $::_CHIPNAME.m33 arp_halt + } + } +} + +$_CHIPNAME.axi configure -event examine-end { + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35_0 } { + $::_CHIPNAME.a35_0 arp_examine + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.a35_1 arp_examine + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.m33 arp_examine + } +} diff --git a/tcl/target/st/stm32mp25x.cfg b/tcl/target/st/stm32mp25x.cfg new file mode 100644 index 0000000000..556b43ff7f --- /dev/null +++ b/tcl/target/st/stm32mp25x.cfg @@ -0,0 +1,256 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# STMicroelectronics STM32MP25x +# STM32MP25x devices support both JTAG and SWD transports. + +# HLA does not support multi-cores nor custom CSW nor AP other than 0 +if { [using_hla] } { + echo "ERROR: HLA transport cannot work with this target." + shutdown +} + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32mp25x +} + +# Set to 0 to prevent CPU examine. Default examine them +if { ! [info exists EN_CA35_0] } { + set EN_CA35_0 1 +} +if { ! [info exists EN_CA35_1] } { + set EN_CA35_1 1 +} +if { ! [info exists EN_CM33] } { + set EN_CM33 1 +} +if { ! [info exists EN_CM0P] } { + set EN_CM0P 1 +} + +set _ENDIAN little + +# jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } { + set _CPUTAPID 0x6ba02477 + } +} + +# Chip Level TAP Controller, only in jtag mode +if { [info exists CLCTAPID] } { + set _CLCTAPID $CLCTAPID +} else { + set _CLCTAPID 0x16505041 +} + +swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 -ircapture 0x01 -irmask 0x0f +if { [using_jtag] } { + swj_newdap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 +} + +if { [info exists SWD_MULTIDROP] } { + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -dp-id 0x05050041 -instance-id 0 +} else { + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap +} + +# define AXI & APB Memory Access Ports +# NOTE: do not change the order of target create +target create $_CHIPNAME.ap0 mem_ap -dap $_CHIPNAME.dap -ap-num 0 +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 4 +target create $_CHIPNAME.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 -defer-examine +target create $_CHIPNAME.ap8 mem_ap -dap $_CHIPNAME.dap -ap-num 8 -defer-examine + +# define the first Cortex-A35 +cti create $_CHIPNAME.cti.a35_0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80220000 +target create $_CHIPNAME.a35_0 aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80210000 \ + -cti $_CHIPNAME.cti.a35_0 -defer-examine + +# define the second Cortex-A35 +cti create $_CHIPNAME.cti.a35_1 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80320000 +target create $_CHIPNAME.a35_1 aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80310000 \ + -cti $_CHIPNAME.cti.a35_1 -defer-examine + +# define the Cortex-M33 +target create $_CHIPNAME.m33 cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine +cti create $_CHIPNAME.cti.m33 -dap $_CHIPNAME.dap -ap-num 8 -baseaddr 0xe0042000 + +# define the Cortex-M0+ +target create $_CHIPNAME.m0p cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine +cti create $_CHIPNAME.cti.m0p -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xf0000000 + +# define the system CTIs +cti create $_CHIPNAME.cti.sys0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80090000 +cti create $_CHIPNAME.cti.sys1 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x800a0000 + +swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x800b0000 +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80050000 + +targets $_CHIPNAME.a35_0 + +target smp $_CHIPNAME.a35_0 $_CHIPNAME.a35_1 +$_CHIPNAME.a35_0 configure -rtos hwthread +$_CHIPNAME.a35_1 configure -rtos hwthread + +reset_config srst_gates_jtag srst_pulls_trst + +adapter speed 5000 +adapter srst pulse_width 200 +# wait 1 seconds for bootrom +adapter srst delay 1000 + +# set CSW for AXI +$_CHIPNAME.dap apsel 4 +$_CHIPNAME.dap apcsw 0x12800000 + +# set CSW for Cortex-M33 D-Cache +$_CHIPNAME.dap apsel 8 +$_CHIPNAME.dap apcsw 0x1a000000 + +# mmw with target selection +proc target_mmw {target reg setbits clearbits} { + set val [eval $target read_memory $reg 32 1] + set val [expr {($val & ~$clearbits) | $setbits}] + eval $target mww $reg $val +} + +lappend _telnet_autocomplete_skip _enable_ap2_cm0p +proc _enable_ap2_cm0p {} { + # set bits C3LPEN and C3EN in RCC_C3CFGR to enable AP2 and CM0+ clock + target_mmw $::_CHIPNAME.axi 0x54200490 6 0 +} + +lappend _telnet_autocomplete_skip _enable_debug +# Uses AP0 and AXI +proc _enable_debug {} { + # set debug enable bits in DBGMCU_CR to get ap2/cm0+ and ap8/cm33 visible + # set DBG_SWD_SEL_N bit in DBGMCU_CR to get ap2/cm0+ on main debug interface + $::_CHIPNAME.ap0 mww 0x80010004 0x17 + + if { $::EN_CM0P } { + _enable_ap2_cm0p + } + + # Freeze watchdogs on CPU halt + $::_CHIPNAME.axi mww 0x4a010008 0x00000000 + $::_CHIPNAME.axi mww 0x4a01003c 0x00000026 + $::_CHIPNAME.axi mww 0x4a010040 0x00000038 + $::_CHIPNAME.axi mww 0x4a010044 0x00000400 + $::_CHIPNAME.axi mww 0x4a010048 0x00000400 + $::_CHIPNAME.axi mww 0x4a01004c 0x00000600 +} + +lappend _telnet_autocomplete_skip _rcc_enable_traceclk +# Uses AXI +proc _rcc_enable_traceclk {} { + # set bit TRACEEN in RCC_DBGCFGR to clock TPIU + target_mmw $::_CHIPNAME.axi 0x44200520 0x200 0 +} + +lappend _telnet_autocomplete_skip _handshake_with_wrapper +# Uses AP0 +proc _handshake_with_wrapper { halt } { + set dbgmcu_cr 0 + catch {set dbgmcu_cr [eval $::_CHIPNAME.ap0 read_memory 0x80010004 32 1]} + if {[expr {($dbgmcu_cr & 0x07) == 0x00}]} { + echo "\nWARNING: FSBL wrapper not detected. Board in dev boot mode?\n" + return; + } + + if { $halt } { + if { $::EN_CA35_0 || $::EN_CA35_1 } { + $::_CHIPNAME.ap0 arp_examine + $::_CHIPNAME.ap0 arp_halt + } + if { $::EN_CA35_0 } { + $::_CHIPNAME.ap0 mww 0x80210300 0 + target_mmw $::_CHIPNAME.ap0 0x80210088 0x00004000 0 + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.ap0 mww 0x80310300 0 + target_mmw $::_CHIPNAME.ap0 0x80310088 0x00004000 0 + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.ap8 arp_halt + $::_CHIPNAME.ap8 mww 0xe000edf0 0xa05f0001 + } + } + + # alert wrapper that debugger is ready + $::_CHIPNAME.ap0 mww 0x80010004 0x17 +} + +$_CHIPNAME.m33 configure -event reset-assert { } +$_CHIPNAME.m0p configure -event reset-assert { } + +$_CHIPNAME.axi configure -event reset-assert-post { + adapter assert srst +} + +$_CHIPNAME.axi configure -event reset-deassert-pre { + adapter deassert srst deassert trst + catch {dap init} + catch {$::_CHIPNAME.dap apid 0} + $::_CHIPNAME.ap0 arp_examine + _handshake_with_wrapper $halt + + $::_CHIPNAME.axi arp_examine + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35_0 } { + $::_CHIPNAME.a35_0 arp_examine + if { $halt } { + $::_CHIPNAME.a35_0 arp_halt + } + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.a35_1 arp_examine + if { $halt } { + $::_CHIPNAME.a35_1 arp_halt + } + } + if { $::EN_CM0P } { + $::_CHIPNAME.ap2 arp_examine + $::_CHIPNAME.m0p arp_examine + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.m33 arp_examine + if { $halt } { + $::_CHIPNAME.m33 arp_halt + } + } +} + +$_CHIPNAME.m0p configure -event examine-start { + _enable_ap2_cm0p +} + +$_CHIPNAME.axi configure -event examine-end { + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35_0 } { + $::_CHIPNAME.a35_0 arp_examine + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.a35_1 arp_examine + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.m33 arp_examine + } + if { $::EN_CM0P } { + $::_CHIPNAME.ap2 arp_examine + $::_CHIPNAME.m0p arp_examine + } +} diff --git a/tcl/target/stm32c0x.cfg b/tcl/target/stm32c0x.cfg index d015120319..35c0c5dc46 100644 --- a/tcl/target/stm32c0x.cfg +++ b/tcl/target/stm32c0x.cfg @@ -4,8 +4,8 @@ # # stm32c0 devices support SWD transports only. # +transport select swd -source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { @@ -32,7 +32,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x0bc11477 } -swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/stm32f0x.cfg b/tcl/target/stm32f0x.cfg index 5b8954eb21..06c8fa5591 100644 --- a/tcl/target/stm32f0x.cfg +++ b/tcl/target/stm32f0x.cfg @@ -5,7 +5,8 @@ # # stm32 devices support SWD transports only. # -source [find target/swj-dp.tcl] +transport select swd + source [find mem_helper.tcl] if { [info exists CHIPNAME] } { @@ -41,7 +42,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x0bb11477 } -swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/stm32f3x.cfg b/tcl/target/stm32f3x.cfg index aa978d9c84..840ddff3f4 100644 --- a/tcl/target/stm32f3x.cfg +++ b/tcl/target/stm32f3x.cfg @@ -17,11 +17,11 @@ if { [info exists CHIPNAME] } { set _ENDIAN little # Work-area is a space in RAM used for flash programming -# By default use 16kB +# By default use 12kB if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x4000 + set _WORKAREASIZE 0x3000 } # Allow overriding the Flash bank size diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index 35d8275b55..a77527c46d 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -98,6 +98,9 @@ proc _proc_pre_enable_$_CHIPNAME.tpiu {_chipname} { targets $_chipname.cpu if { [$_chipname.tpiu cget -protocol] eq "sync" } { + # Enable the GPIOE clock. + mmw 0x40023830 0x00000010 0x00000010 + switch [$_chipname.tpiu cget -port-width] { 1 { # Set TRACE_IOEN; TRACE_MODE to sync 1 bit; GPIOE[2-3] to AF0 diff --git a/tcl/target/stm32g0x.cfg b/tcl/target/stm32g0x.cfg index b6d9a22a2c..2a63f689a1 100644 --- a/tcl/target/stm32g0x.cfg +++ b/tcl/target/stm32g0x.cfg @@ -5,7 +5,8 @@ # # stm32g0 devices support SWD transports only. # -source [find target/swj-dp.tcl] +transport select swd + source [find mem_helper.tcl] if { [info exists CHIPNAME] } { @@ -32,7 +33,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x0bc11477 } -swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/stm32g4x.cfg b/tcl/target/stm32g4x.cfg index 39ed1e3818..54b20eee5e 100644 --- a/tcl/target/stm32g4x.cfg +++ b/tcl/target/stm32g4x.cfg @@ -83,11 +83,6 @@ $_TARGETNAME configure -event reset-init { mmw 0x40021008 0x00000001 0x00000002 ;# RCC_CFGR: SW=HSI16 } -$_TARGETNAME configure -event reset-start { - # Reset clock is HSI (16 MHz) - adapter speed 2000 -} - $_TARGETNAME configure -event examine-end { # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP mmw 0xE0042004 0x00000007 0 diff --git a/tcl/target/stm32h7rsx.cfg b/tcl/target/stm32h7rsx.cfg new file mode 100644 index 0000000000..a51982bb2f --- /dev/null +++ b/tcl/target/stm32h7rsx.cfg @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32h7rsx family + +# +# stm32h7rs 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 stm32h7rsx +} + +# Issue an error when hla is used +if { [using_hla] } { + echo "Error : hla does not support STM32H7RS devices" +} + +set _ENDIAN little + +# 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 + } { + 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 +} + +target create $_CHIPNAME.ap0 mem_ap -dap $_CHIPNAME.dap -ap-num 0 +target create $_CHIPNAME.cpu0 cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap -ap-num 1 +# test ram area +$_CHIPNAME.cpu0 configure -work-area-phys 0x24000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +flash bank $_CHIPNAME.flash stm32h7x 0x08000000 0 0 0 $_CHIPNAME.cpu0 + +# Make sure that cpu0 is selected +targets $_CHIPNAME.cpu0 + +# Clock after reset is HSI at 64 MHz, no need of PLL +adapter speed 4000 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +# use hardware reset +# +# The STM32H7RS does not support connect_assert_srst mode because the AXI is +# unavailable while SRST is asserted, and that is used to access the DBGMCU +# component at 0x5C001000 in the examine-end event handler. +# +reset_config srst_gates_jtag + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + $_CHIPNAME.cpu0 cortex_m reset_config sysresetreq + + # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal + # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3 + # makes the data access cacheable. This allows reading and writing data in the + # CPU cache from the debugger, which is far more useful than going straight to + # RAM when operating on typical variables, and is generally no worse when + # operating on special memory locations. + $_CHIPNAME.dap apcsw 0x08000000 0x08000000 +} + +$_CHIPNAME.cpu0 configure -event examine-end { + # Enable debug during low power modes (uses more power) + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP + mmw 0x5C001004 0x00000007 0 + + # Enable clock for tracing + # DBGMCU_CR |= TRACECLKEN + mmw 0x5C001004 0x00100000 0 +} diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index 5aae938619..a364e0682b 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -126,7 +126,7 @@ if { [info exists QUADSPI] && $QUADSPI } { } # Clock after reset is HSI at 64 MHz, no need of PLL -adapter speed 1800 +adapter speed 4000 adapter srst delay 100 if {[using_jtag]} { @@ -198,11 +198,6 @@ $_CHIPNAME.cpu0 configure -event examine-end { stm32h7x_dbgmcu_mmw 0x3000 0x00000003 0 } -$_CHIPNAME.cpu0 configure -event reset-init { - # Clock after reset is HSI at 64 MHz, no need of PLL - adapter speed 4000 -} - # get _CHIPNAME from current target proc stm32h7x_get_chipname {} { set t [target current] diff --git a/tcl/target/stm32l0.cfg b/tcl/target/stm32l0.cfg index b4bdb18a4d..1324902944 100644 --- a/tcl/target/stm32l0.cfg +++ b/tcl/target/stm32l0.cfg @@ -1,11 +1,10 @@ # 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 +# stm32l0x devices support SWD transports only. # +transport select swd -source [find target/swj-dp.tcl] source [find mem_helper.tcl] if { [info exists CHIPNAME] } { @@ -38,7 +37,7 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x0bc11477 } -swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +swd newdap $_CHIPNAME cpu -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index 9a696736cd..1666b25498 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -143,8 +143,8 @@ $_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 + mmw 0x40022000 0x00000103 0x00000007 ;# FLASH_ACR = PRFTBE | 3(Latency) + mmw 0x40021000 0x00000099 0x000000F0 ;# RCC_CR = MSI_ON | MSIRGSEL | MSI Range 9 # Boost JTAG frequency adapter speed 4000 diff --git a/tcl/target/stm32n6x.cfg b/tcl/target/stm32n6x.cfg new file mode 100644 index 0000000000..6b13cf75a0 --- /dev/null +++ b/tcl/target/stm32n6x.cfg @@ -0,0 +1,167 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32n6x family +# stm32n6 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 stm32n6x +} + +# 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 + } { + set _CPUTAPID 0x6ba02477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +set _TARGETNAME $_CHIPNAME.cpu + +dap create $_CHIPNAME.dap -chain-position $_TARGETNAME + +target create $_CHIPNAME.ap0 mem_ap -endian little -dap $_CHIPNAME.dap -ap-num 0 + +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap -ap-num 1 + +# use secure RAM by default +$_TARGETNAME configure -work-area-phys 0x34000000 -work-area-size $_WORKAREASIZE -work-area-backup 1 + +if { ![using_hla] } { + swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE008A000 + tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0084000 +} + +adapter speed 8000 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +if { [using_hla] } { + echo "Warn : The selected adapter does not support debugging this device in secure mode" +} else { + # Use SYSRESETREQ to perform a soft reset if SRST is not fitted. + cortex_m reset_config sysresetreq +} + +proc stm32n6x_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 stm32n6x_ahb_ap_non_secure_access {} { + [[target current] cget -dap] apsel 1 + # SPROT=1=Non Secure access, Priv=1 + [[target current] cget -dap] apcsw 0x4B000000 0x4F000000 +} + +proc stm32n6x_ahb_ap_secure_access {} { + [[target current] cget -dap] apsel 1 + # SPROT=0=Secure access, Priv=1 + [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 +} + +# get _CHIPNAME from current target +proc stm32n6x_get_chipname {} { + return [regsub {\.[^.]*$} [target current] {}] +} + +# like mrw, but with target selection +proc stm32n6x_mrw {used_target reg} { + return [$used_target read_memory $reg 32 1] +} + +# like mmw, but with target selection +proc stm32n6x_mmw {used_target reg setbits clearbits} { + set old [stm32n6x_mrw $used_target $reg] + set new [expr {($old & ~$clearbits) | $setbits}] + $used_target mww $reg $new +} + +proc stm32n6x_enter_debug {} { + set _CHIPNAME [stm32n6x_get_chipname] + + # check security status + set secure [stm32n6x_is_secure] + + if {$secure} { + stm32n6x_ahb_ap_secure_access + } else { + stm32n6x_ahb_ap_non_secure_access + } + + # print the secure state only when it changes + global $_CHIPNAME.secure + + if {![info exists $_CHIPNAME.secure] || $secure != [set $_CHIPNAME.secure]} { + # update saved security state + set $_CHIPNAME.secure $secure + set secure_str [expr {$secure ? "Secure" : "Non-Secure"}] + echo "$_CHIPNAME.cpu in $secure_str state" + } + + # use secure workarea only when TrustZone is enabled + set use_secure_workarea 1 + set workarea_addr [$_CHIPNAME.cpu cget -work-area-phys] + + if {$use_secure_workarea} { + set workarea_addr [expr {$workarea_addr | 0x10000000}] + } else { + set workarea_addr [expr {$workarea_addr & ~0x10000000}] + } + + $_CHIPNAME.cpu configure -work-area-phys $workarea_addr + + global $_CHIPNAME.workarea_size + if {![info exists $_CHIPNAME.workarea_size]} { + set $_CHIPNAME.workarea_size [$_CHIPNAME.cpu cget -work-area-size] + } + + set workarea_size [set $_CHIPNAME.workarea_size] + $_CHIPNAME.cpu configure -work-area-size $workarea_size +} + +$_CHIPNAME.ap0 configure -event examine-end { + set _CHIPNAME [stm32n6x_get_chipname] + # Enable Trace Port and DBG Clock (uses more power) + # DBGMCU_CR |= DBGCLK_EN | TRACECLK_EN + stm32n6x_mmw $_CHIPNAME.ap0 0x44001004 0x00300000 0 +} + +$_TARGETNAME configure -event examine-end { + stm32n6x_enter_debug + set _CHIPNAME [stm32n6x_get_chipname] + + # Enable debug during low power modes (uses more power) + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP + stm32n6x_mmw $_CHIPNAME.ap0 0x44001004 0x00000007 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1LFZ |= DBG_WWDG_STOP + stm32n6x_mmw $_CHIPNAME.ap0 0x44001010 0x00000800 0 + # DBGMCU_APB4FZ |= DBG_IWDG_STOP + stm32n6x_mmw $_CHIPNAME.ap0 0x4400101C 0x00040000 0 +} + +$_TARGETNAME configure -event halted { + stm32n6x_enter_debug +} diff --git a/tcl/target/stm32u0x.cfg b/tcl/target/stm32u0x.cfg index d3aaed3cbb..7bce8f6d76 100644 --- a/tcl/target/stm32u0x.cfg +++ b/tcl/target/stm32u0x.cfg @@ -4,6 +4,7 @@ # # STM32U0 devices support only SWD transport. # +transport select swd source [find mem_helper.tcl] diff --git a/tcl/target/stm32u3x.cfg b/tcl/target/stm32u3x.cfg new file mode 100644 index 0000000000..47c68935ec --- /dev/null +++ b/tcl/target/stm32u3x.cfg @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32u3x family +# stm32u3x 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 stm32u3x +} + +source [find target/stm32x5x_common.cfg] + +# In order to allow the flash program and erase operations, +# we need to set the voltage scale to range 1 + +proc config_voltage_range {} { + set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] + # PWR voltage scaling register + set PWR_VOSR [expr {0x4003080C + $offset}] + # PWR supply voltage monitoring control register + set PWR_SVMCR [expr {0x40030810 + $offset}] + # RCC AHB1 peripheral clock enable register 2 + # RCC_AHB1ENR2 = PWREN + mww [expr {0x40030C94 + $offset}] 0x4 + if {(([mrw $PWR_VOSR] & 0x10001) != 0x10001)} { + # PWR_SVMCR = IO2SV + mmw $PWR_SVMCR 0x20000000 0 + # PWR_VOSR : R1EN: Voltage scaling range 1 + mmw $PWR_VOSR 1 3 + # while !(PWR_VOSR & R1RDY) + while {([mrw $PWR_VOSR] & 0x10001) != 0x10001} {} + # Enable EPOD Booster + mmw $PWR_VOSR 0x00000100 0 + # while !(PWR_VOSR & BOOSTRDY) + while {([mrw $PWR_VOSR] & 0x1000000) != 0} {} + } +} + +$_TARGETNAME configure -event reset-init { + config_voltage_range +} + +$_TARGETNAME configure -event gdb-flash-erase-start { + stm32x5x_gdb_flash_erase_start + config_voltage_range +} diff --git a/tcl/target/stm32wba2x.cfg b/tcl/target/stm32wba2x.cfg new file mode 100644 index 0000000000..88349bafbb --- /dev/null +++ b/tcl/target/stm32wba2x.cfg @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32wba2x family + +# +# stm32wba2x 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 stm32wba2x +} + +# 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 0x0be11477 + } else { + # 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 -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 0x0bf8d000 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 0x46020C00 0x00000100 0x00000000 ;# RCC_CR |= HSION + mmw 0x46020C1C 0x00000000 0x00000003 ;# 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_SCR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP + mmw 0xE0044004 0x00000007 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1LFZR |= DBG_IWDG_STOP + mmw 0xE0044008 0x00001000 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/stm32wbax.cfg b/tcl/target/stm32wba5x.cfg similarity index 87% rename from tcl/target/stm32wbax.cfg rename to tcl/target/stm32wba5x.cfg index 129940720b..9eadd24037 100644 --- a/tcl/target/stm32wbax.cfg +++ b/tcl/target/stm32wba5x.cfg @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# script for stm32wbax family +# script for stm32wba5x family # -# stm32wba devices support both JTAG and SWD transports. +# stm32wba5x devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] @@ -11,7 +11,7 @@ source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { - set _CHIPNAME stm32wbax + set _CHIPNAME stm32wba5x } # Work-area is a space in RAM used for flash programming @@ -22,7 +22,7 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x10000 } -#jtag scan chain +# jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { @@ -47,7 +47,7 @@ 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 +flash bank $_CHIPNAME.otp stm32l4x 0x0bf90000 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 @@ -76,7 +76,7 @@ $_TARGETNAME configure -event reset-init { # 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 + mmw 0x56020C1C 0x00000000 0x00000003 ;# RCC_CFGR1: SW=HSI16 # Boost JTAG frequency adapter speed 4000 } @@ -88,12 +88,12 @@ $_TARGETNAME configure -event reset-start { $_TARGETNAME configure -event examine-end { # Enable debug during low power modes (uses more power) - # DBGMCU_CR |= DBG_STANDBY | DBG_STOP - mmw 0xE0042004 0x00000006 0 + # DBGMCU_SCR |= DBG_STANDBY | DBG_STOP + mmw 0xE0044004 0x00000006 0 # Stop watchdog counters during halt # DBGMCU_APB1LFZR |= DBG_IWDG_STOP | DBG_WWDG_STOP - mmw 0xE0042008 0x00001800 0 + mmw 0xE0044008 0x00001800 0 } tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 diff --git a/tcl/target/stm32wba6x.cfg b/tcl/target/stm32wba6x.cfg new file mode 100644 index 0000000000..4f29ca9414 --- /dev/null +++ b/tcl/target/stm32wba6x.cfg @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32wba6x family + +# +# stm32wba6x 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 stm32wba6x +} + +# 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 0x0bfa0000 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 0x00000003 ;# 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_SCR |= DBG_STANDBY | DBG_STOP + mmw 0xE0044004 0x00000006 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1LFZR |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE0044008 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 737b1447c0..d11c5fb8ca 100644 --- a/tcl/target/stm32wbx.cfg +++ b/tcl/target/stm32wbx.cfg @@ -76,8 +76,8 @@ $_TARGETNAME 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. - mmw 0x58004000 0x00000102 0 ;# FLASH_ACR |= PRFTBE | 2(Latency) - mmw 0x58000000 0x00000091 0 ;# RCC_CR = MSI_ON | MSI Range 24 MHz + mmw 0x58004000 0x00000102 0x00000007 ;# FLASH_ACR |= PRFTBE | 2(Latency) + mmw 0x58000000 0x00000091 0x000000F0 ;# RCC_CR = MSI_ON | MSI Range 24 MHz # Boost JTAG frequency adapter speed 4000 } diff --git a/tcl/target/stm32wlx.cfg b/tcl/target/stm32wlx.cfg index 39c897fc5d..ddf760d45b 100644 --- a/tcl/target/stm32wlx.cfg +++ b/tcl/target/stm32wlx.cfg @@ -91,8 +91,8 @@ $_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. - mmw 0x58004000 0x00000102 0 ;# FLASH_ACR |= PRFTEN | 2(Latency) - mmw 0x58000000 0x00000091 0 ;# RCC_CR = MSI_ON | MSI Range 24 MHz + mmw 0x58004000 0x00000102 0x00000007 ;# FLASH_ACR |= PRFTEN | 2(Latency) + mmw 0x58000000 0x00000099 0x000000F0 ;# RCC_CR = MSI_ON | MSI Range 24 MHz | MSIRGSEL # Boost JTAG frequency adapter speed 4000 } diff --git a/tcl/target/stm32x5x_common.cfg b/tcl/target/stm32x5x_common.cfg index fb3aeb18c1..61ef35d6dc 100644 --- a/tcl/target/stm32x5x_common.cfg +++ b/tcl/target/stm32x5x_common.cfg @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# common script for stm32l5x and stm32u5x families +# common script for stm32l5x, stm32u3x and stm32u5x families # Work-area is a space in RAM used for flash programming # By default use 64kB @@ -16,6 +16,7 @@ if { [info exists CPUTAPID] } { } else { if { [using_jtag] } { # STM32L5x: RM0438 Rev5, Section 52.2.8 JTAG debug port - Table 425. JTAG-DP data registers + # STM32U3x: RM0487 Rev1, Section 53.3.1 JTAG debug port - Table 569. 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 @@ -87,6 +88,38 @@ proc stm32x5x_ahb_ap_secure_access {} { } } +proc stm32x5x_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 +} + +$_TARGETNAME configure -event gdb-flash-erase-start stm32x5x_gdb_flash_erase_start + $_TARGETNAME configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 480 @@ -123,36 +156,6 @@ $_TARGETNAME configure -event halted { } } -$_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 diff --git a/tcl/target/am335x.cfg b/tcl/target/ti/am335x.cfg similarity index 97% rename from tcl/target/am335x.cfg rename to tcl/target/ti/am335x.cfg index 208ebf5610..9388f76fb5 100644 --- a/tcl/target/am335x.cfg +++ b/tcl/target/ti/am335x.cfg @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -84,7 +84,7 @@ $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x4000 # when putting the target into 'reset halt', we need to disable the watchdog as # it would otherwise trigger while we're in JTAG -# FIXME: unify with target/am437x.cfg +# FIXME: unify with target/ti/am437x.cfg source [find mem_helper.tcl] set WDT1_BASE_ADDR 0x44e35000 set WDT1_W_PEND_WSPR [expr {$WDT1_BASE_ADDR + 0x0034}] diff --git a/tcl/target/am437x.cfg b/tcl/target/ti/am437x.cfg similarity index 99% rename from tcl/target/am437x.cfg rename to tcl/target/ti/am437x.cfg index 5350927583..5470f164b5 100644 --- a/tcl/target/am437x.cfg +++ b/tcl/target/ti/am437x.cfg @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] source [find mem_helper.tcl] ############################################################################### diff --git a/tcl/target/amdm37x.cfg b/tcl/target/ti/amdm37x.cfg similarity index 99% rename from tcl/target/amdm37x.cfg rename to tcl/target/ti/amdm37x.cfg index d9adae9047..635d94c1c3 100644 --- a/tcl/target/amdm37x.cfg +++ b/tcl/target/ti/amdm37x.cfg @@ -59,7 +59,7 @@ adapter speed 10 # can be read about this module in sprugn4r in chapter 27: "Debug and # Emulation". The module is used to route the JTAG chain to the various # subsystems in the chip. -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] # The TAP order should be described from the TDO connection in OpenOCD to the # TDI pin. The OpenOCD FAQ describes this in more detail: diff --git a/tcl/target/ti-ar7.cfg b/tcl/target/ti/ar7.cfg similarity index 100% rename from tcl/target/ti-ar7.cfg rename to tcl/target/ti/ar7.cfg diff --git a/tcl/target/ti_calypso.cfg b/tcl/target/ti/calypso.cfg similarity index 100% rename from tcl/target/ti_calypso.cfg rename to tcl/target/ti/calypso.cfg diff --git a/tcl/target/ti_cc13x0.cfg b/tcl/target/ti/cc13x0.cfg similarity index 84% rename from tcl/target/ti_cc13x0.cfg rename to tcl/target/ti/cc13x0.cfg index f1c43a6899..7f33edb804 100644 --- a/tcl/target/ti_cc13x0.cfg +++ b/tcl/target/ti/cc13x0.cfg @@ -10,4 +10,4 @@ set CHIPNAME cc13x0 set JRC_TAPID 0x0B9BE02F set WORKAREASIZE 0x4000 -source [find target/ti_cc26x0.cfg] +source [find target/ti/cc26x0.cfg] diff --git a/tcl/target/ti_cc13x2.cfg b/tcl/target/ti/cc13x2.cfg similarity index 84% rename from tcl/target/ti_cc13x2.cfg rename to tcl/target/ti/cc13x2.cfg index c850816851..2dadb9ce0b 100644 --- a/tcl/target/ti_cc13x2.cfg +++ b/tcl/target/ti/cc13x2.cfg @@ -10,4 +10,4 @@ set CHIPNAME cc13x2 set JRC_TAPID 0x0BB4102F set WORKAREASIZE 0x7000 -source [find target/ti_cc26x0.cfg] +source [find target/ti/cc26x0.cfg] diff --git a/tcl/target/cc2538.cfg b/tcl/target/ti/cc2538.cfg similarity index 94% rename from tcl/target/cc2538.cfg rename to tcl/target/ti/cc2538.cfg index e4fb02ad4d..f0fd34b054 100644 --- a/tcl/target/cc2538.cfg +++ b/tcl/target/ti/cc2538.cfg @@ -5,8 +5,8 @@ adapter speed 100 -source [find target/icepick.cfg] -source [find target/ti-cjtag.cfg] +source [find target/ti/icepick.cfg] +source [find target/ti/cjtag.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/ti_cc26x0.cfg b/tcl/target/ti/cc26x0.cfg similarity index 95% rename from tcl/target/ti_cc26x0.cfg rename to tcl/target/ti/cc26x0.cfg index b9ccf31232..246c1fd979 100644 --- a/tcl/target/ti_cc26x0.cfg +++ b/tcl/target/ti/cc26x0.cfg @@ -6,8 +6,8 @@ # http://www.ti.com # -source [find target/icepick.cfg] -source [find target/ti-cjtag.cfg] +source [find target/ti/icepick.cfg] +source [find target/ti/cjtag.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/ti_cc26x2.cfg b/tcl/target/ti/cc26x2.cfg similarity index 84% rename from tcl/target/ti_cc26x2.cfg rename to tcl/target/ti/cc26x2.cfg index 62c91c3395..14b5869219 100644 --- a/tcl/target/ti_cc26x2.cfg +++ b/tcl/target/ti/cc26x2.cfg @@ -10,4 +10,4 @@ set CHIPNAME cc26x2 set JRC_TAPID 0x0BB4102F set WORKAREASIZE 0x7000 -source [find target/ti_cc26x0.cfg] +source [find target/ti/cc26x0.cfg] diff --git a/tcl/target/ti_cc26x2x7.cfg b/tcl/target/ti/cc26x2x7.cfg similarity index 84% rename from tcl/target/ti_cc26x2x7.cfg rename to tcl/target/ti/cc26x2x7.cfg index 91c1a80596..80ecdd450a 100644 --- a/tcl/target/ti_cc26x2x7.cfg +++ b/tcl/target/ti/cc26x2x7.cfg @@ -10,4 +10,4 @@ set CHIPNAME cc26x2x7 set JRC_TAPID 0x1BB7702F set WORKAREASIZE 0x7000 -source [find target/ti_cc26x0.cfg] +source [find target/ti/cc26x0.cfg] diff --git a/tcl/target/ti_cc3220sf.cfg b/tcl/target/ti/cc3220sf.cfg similarity index 93% rename from tcl/target/ti_cc3220sf.cfg rename to tcl/target/ti/cc3220sf.cfg index cf43363768..7b242ab8a5 100644 --- a/tcl/target/ti_cc3220sf.cfg +++ b/tcl/target/ti/cc3220sf.cfg @@ -7,8 +7,8 @@ # source [find target/swj-dp.tcl] -source [find target/icepick.cfg] -source [find target/ti_cc32xx.cfg] +source [find target/ti/icepick.cfg] +source [find target/ti/cc32xx.cfg] set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME diff --git a/tcl/target/ti_cc32xx.cfg b/tcl/target/ti/cc32xx.cfg similarity index 97% rename from tcl/target/ti_cc32xx.cfg rename to tcl/target/ti/cc32xx.cfg index 9eb03eb2f4..d081360bd4 100644 --- a/tcl/target/ti_cc32xx.cfg +++ b/tcl/target/ti/cc32xx.cfg @@ -8,7 +8,7 @@ # source [find target/swj-dp.tcl] -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/ti-cjtag.cfg b/tcl/target/ti/cjtag.cfg similarity index 100% rename from tcl/target/ti-cjtag.cfg rename to tcl/target/ti/cjtag.cfg diff --git a/tcl/target/davinci.cfg b/tcl/target/ti/davinci.cfg similarity index 100% rename from tcl/target/davinci.cfg rename to tcl/target/ti/davinci.cfg diff --git a/tcl/target/ti_dm355.cfg b/tcl/target/ti/dm355.cfg similarity index 97% rename from tcl/target/ti_dm355.cfg rename to tcl/target/ti/dm355.cfg index 42923733ea..198d1eb504 100644 --- a/tcl/target/ti_dm355.cfg +++ b/tcl/target/ti/dm355.cfg @@ -17,7 +17,7 @@ set EMU01 "-disable" # needing any ICEpick interaction. #set EMU01 "-enable" -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] # # Also note: when running without RTCK before the PLLs are set up, you @@ -80,7 +80,7 @@ dict set dm355 uart0 0x01c20000 dict set dm355 uart1 0x01c20400 dict set dm355 uart2 0x01e06000 -source [find target/davinci.cfg] +source [find target/ti/davinci.cfg] ################ # GDB target: the ARM, using SRAM1 for scratch. SRAM0 (also 16K) diff --git a/tcl/target/ti_dm365.cfg b/tcl/target/ti/dm365.cfg similarity index 97% rename from tcl/target/ti_dm365.cfg rename to tcl/target/ti/dm365.cfg index e19efd7ee4..8f4510e3bb 100644 --- a/tcl/target/ti_dm365.cfg +++ b/tcl/target/ti/dm365.cfg @@ -17,7 +17,7 @@ set EMU01 "-disable" # needing any ICEpick interaction. #set EMU01 "-enable" -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { @@ -72,7 +72,7 @@ dict set dm365 a_emif_cs1 0x04000000 dict set dm365 ddr_emif 0x20000000 dict set dm365 ddr 0x80000000 -source [find target/davinci.cfg] +source [find target/ti/davinci.cfg] ################ # GDB target: the ARM, using SRAM1 for scratch. SRAM0 (also 16K) diff --git a/tcl/target/ti_dm6446.cfg b/tcl/target/ti/dm6446.cfg similarity index 98% rename from tcl/target/ti_dm6446.cfg rename to tcl/target/ti/dm6446.cfg index 8938234c30..23218c4ab3 100644 --- a/tcl/target/ti_dm6446.cfg +++ b/tcl/target/ti/dm6446.cfg @@ -17,7 +17,7 @@ set EMU01 "-disable" # needing any ICEpick interaction. #set EMU01 "-enable" -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] # Subsidiary TAP: unknown ... must enable via ICEpick jtag newtap $_CHIPNAME unknown -irlen 8 -disable diff --git a/tcl/target/icepick.cfg b/tcl/target/ti/icepick.cfg similarity index 100% rename from tcl/target/icepick.cfg rename to tcl/target/ti/icepick.cfg diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti/k3.cfg similarity index 95% rename from tcl/target/ti_k3.cfg rename to tcl/target/ti/k3.cfg index 0dee74e5ee..6b0ac2e52f 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti/k3.cfg @@ -176,6 +176,16 @@ switch $_soc { # Uses the same JTAG ID set _armv8_cores 0 } + + # 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 } am625 { set _K3_DAP_TAPID 0x0bb7e02f @@ -333,7 +343,7 @@ switch $_soc { set ARMV8_CTIBASE {0x90420000 0x90520000 0x90620000 0x90720000 0x90820000 0x90920000 0x90a20000 0x90b20000} - # J721s2 has 4 clusters of 2 R5 cores each. + # J784s4 has 4 clusters of 2 R5 cores each. set _r5_cores 8 set R5_DBGBASE {0x9d010000 0x9d012000 0x9d410000 0x9d412000 @@ -348,6 +358,16 @@ switch $_soc { main1_r5.0 main1_r5.1 main2_r5.0 main2_r5.1} + # 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 + # sysctrl CTI base set CM3_CTIBASE {0x20001000} # Sysctrl power-ap unlock offsets diff --git a/tcl/target/ti_msp432.cfg b/tcl/target/ti/msp432.cfg similarity index 100% rename from tcl/target/ti_msp432.cfg rename to tcl/target/ti/msp432.cfg diff --git a/tcl/target/ti_mspm0.cfg b/tcl/target/ti/mspm0.cfg similarity index 85% rename from tcl/target/ti_mspm0.cfg rename to tcl/target/ti/mspm0.cfg index 4e9b89c1f5..199b764bc9 100644 --- a/tcl/target/ti_mspm0.cfg +++ b/tcl/target/ti/mspm0.cfg @@ -14,26 +14,17 @@ if { [info exists CHIPNAME] } { set _CHIPNAME mspm0x } -if { [info exists CPUTAPID] } { - set _DAP_TAPID $CPUTAPID -} else { - set _DAP_TAPID 0x4ba00477 -} - +# Note, some targets use "CPUTAPID" variable for this purpose. if { [info exists DAP_SWD_ID] } { set _DAP_SWD_ID $DAP_SWD_ID } else { set _DAP_SWD_ID 0x2ba01477 } -source [find target/swj-dp.tcl] - -# MSPM0 only supports swd, so set it here and save a line for custom boards +# MSPM0 only supports swd transport select swd -set _DAP_ID $_DAP_SWD_ID - -swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_DAP_ID +swd newdap $_CHIPNAME cpu -expected-id $_DAP_SWD_ID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu @@ -162,16 +153,33 @@ add_help_text mspm0_start_bootloader "Ask explicitly for bootloader startup" # However this cannot be the default configuration as this # prevents reset init reset halt to function properly # since the Debug Subsystem (debugss) logic or coresight -# seems impacted by nRST. +# seems impacted by nRST. srst_nogate is used to skip the +# automatic DAP re-init in cortex_m_deassert_reset since +# the MSPM0 DebugSS needs time (depends on device frequency) +# to recover after nRST before the DAP is accessible. +# We manually poll arp_examine with a timeout instead of +# relying on a fixed sleep. +# # This can be overridden in board file as required. # # mspm0_board_reset: Board level reset proc mspm0_board_reset {} { set user_reset_config [reset_config] - reset_config srst_only - set errno [catch {reset}] + reset_config srst_only srst_nogate + set errno [catch {reset} errmsg] eval reset_config $user_reset_config - if {$errno} {error} + if {$errno} {error "board reset failed with error: $errmsg ($errno)"} + # Poll until DebugSS is ready, up to 2000ms + set timeout 2000 + set step 100 + while {$timeout > 0} { + if {![catch {$::_TARGETNAME arp_examine}]} { + return + } + sleep $step + set timeout [expr {$timeout - $step}] + } + error "board reset: DebugSS failed to come up within timeout" } add_help_text mspm0_board_reset "Request a board level reset" diff --git a/tcl/target/omap2420.cfg b/tcl/target/ti/omap2420.cfg similarity index 100% rename from tcl/target/omap2420.cfg rename to tcl/target/ti/omap2420.cfg diff --git a/tcl/target/omap3530.cfg b/tcl/target/ti/omap3530.cfg similarity index 96% rename from tcl/target/omap3530.cfg rename to tcl/target/ti/omap3530.cfg index bd8b111a0b..5ae003b398 100644 --- a/tcl/target/omap3530.cfg +++ b/tcl/target/ti/omap3530.cfg @@ -11,7 +11,7 @@ if { [info exists CHIPNAME] } { } # ICEpick-C ... used to route Cortex, DSP, and more not shown here -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] # Subsidiary TAP: C64x+ DSP ... must enable via ICEpick jtag newtap $_CHIPNAME dsp -irlen 38 -ircapture 0x25 -irmask 0x3f -disable @@ -66,7 +66,6 @@ proc omap3_dbginit {target} { # 16.8MHz/2 = 8.4MHz core clock, even before a bootloader kicks in. # OK to speed up *after* PLL and clock tree setup. adapter speed 1000 -$_TARGETNAME configure -event "reset-start" { adapter speed 1000 } # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset # ourselves using PRM_RSTCTRL. RST_GS (2) is a warm reset, like ICEpick diff --git a/tcl/target/omap4430.cfg b/tcl/target/ti/omap4430.cfg similarity index 98% rename from tcl/target/omap4430.cfg rename to tcl/target/ti/omap4430.cfg index 4bc7fe1bf7..f1b87f147a 100644 --- a/tcl/target/omap4430.cfg +++ b/tcl/target/ti/omap4430.cfg @@ -12,7 +12,7 @@ if { [info exists CHIPNAME] } { # Although the OMAP4430 supposedly has an ICEpick-D, only the # ICEpick-C router commands seem to work. # See http://processors.wiki.ti.com/index.php/ICEPICK -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] # diff --git a/tcl/target/omap4460.cfg b/tcl/target/ti/omap4460.cfg similarity index 98% rename from tcl/target/omap4460.cfg rename to tcl/target/ti/omap4460.cfg index 85ba96c51f..b9e4140618 100644 --- a/tcl/target/omap4460.cfg +++ b/tcl/target/ti/omap4460.cfg @@ -12,7 +12,7 @@ if { [info exists CHIPNAME] } { # Although the OMAP4430 supposedly has an ICEpick-D, only the # ICEpick-C router commands seem to work. # See http://processors.wiki.ti.com/index.php/ICEPICK -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] # diff --git a/tcl/target/omap5912.cfg b/tcl/target/ti/omap5912.cfg similarity index 100% rename from tcl/target/omap5912.cfg rename to tcl/target/ti/omap5912.cfg diff --git a/tcl/target/omapl138.cfg b/tcl/target/ti/omapl138.cfg similarity index 95% rename from tcl/target/omapl138.cfg rename to tcl/target/ti/omapl138.cfg index 78c456d5c0..166317f1d2 100644 --- a/tcl/target/omapl138.cfg +++ b/tcl/target/ti/omapl138.cfg @@ -9,7 +9,7 @@ if { [info exists CHIPNAME] } { set _CHIPNAME omapl138 } -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] # Subsidiary TAP: ARM ETB11, with scan chain for 4K of ETM trace buffer if { [info exists ETB_TAPID] } { @@ -55,7 +55,6 @@ $_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x2000 # CLKIN = 20 MHz (best case: 30 MHz) even when no bootloader turns # on the PLL and starts using it. OK to speed up after clock setup. adapter speed 1500 -$_TARGETNAME configure -event "reset-start" { adapter speed 1500 } arm7_9 fast_memory_access enable arm7_9 dcc_downloads enable diff --git a/tcl/target/ti_rm4x.cfg b/tcl/target/ti/rm4x.cfg similarity index 56% rename from tcl/target/ti_rm4x.cfg rename to tcl/target/ti/rm4x.cfg index 715aa5b705..9103d44621 100644 --- a/tcl/target/ti_rm4x.cfg +++ b/tcl/target/ti/rm4x.cfg @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-or-later -source [find target/ti_tms570.cfg] +source [find target/ti/tms570.cfg] diff --git a/tcl/target/stellaris.cfg b/tcl/target/ti/stellaris.cfg similarity index 100% rename from tcl/target/stellaris.cfg rename to tcl/target/ti/stellaris.cfg diff --git a/tcl/target/ti_tms570.cfg b/tcl/target/ti/tms570.cfg similarity index 97% rename from tcl/target/ti_tms570.cfg rename to tcl/target/ti/tms570.cfg index 18e0d82941..3b0639b5d6 100644 --- a/tcl/target/ti_tms570.cfg +++ b/tcl/target/ti/tms570.cfg @@ -15,7 +15,7 @@ if { [info exists ENDIAN] } { } # TMS570 has an ICEpick-C on which we need the router commands. -source [find target/icepick.cfg] +source [find target/ti/icepick.cfg] # Main DAP # DAP_TAPID should be set before source-ing this file diff --git a/tcl/target/ti_tms570lc43xx.cfg b/tcl/target/ti/tms570lc43xx.cfg similarity index 73% rename from tcl/target/ti_tms570lc43xx.cfg rename to tcl/target/ti/tms570lc43xx.cfg index ffda989f97..677132a89e 100644 --- a/tcl/target/ti_tms570lc43xx.cfg +++ b/tcl/target/ti/tms570lc43xx.cfg @@ -3,4 +3,4 @@ set DAP_TAPID 0x0B95A02F set JRC_TAPID 0x0B95A02F -source [find target/ti_tms570.cfg] +source [find target/ti/tms570.cfg] diff --git a/tcl/target/ti/tms570ls1x.cfg b/tcl/target/ti/tms570ls1x.cfg new file mode 100644 index 0000000000..8eace9c524 --- /dev/null +++ b/tcl/target/ti/tms570ls1x.cfg @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# TMS570LS1114, TMS570LS1115 +# TMS570LS1224, TMS570LS1225, TMS570LS1227 +set DAP_TAPID 0x0B95502F +set JRC_TAPID 0x0B95502F + +source [find target/ti/tms570.cfg] diff --git a/tcl/target/ti_tms570ls20xxx.cfg b/tcl/target/ti/tms570ls20xxx.cfg similarity index 84% rename from tcl/target/ti_tms570ls20xxx.cfg rename to tcl/target/ti/tms570ls20xxx.cfg index cc2bbd6904..4581dbf304 100644 --- a/tcl/target/ti_tms570ls20xxx.cfg +++ b/tcl/target/ti/tms570ls20xxx.cfg @@ -5,4 +5,4 @@ set DAP_TAPID 0x0B7B302F set JRC_TAPID 0x0B7B302F -source [find target/ti_tms570.cfg] +source [find target/ti/tms570.cfg] diff --git a/tcl/target/ti_tms570ls3137.cfg b/tcl/target/ti/tms570ls3137.cfg similarity index 76% rename from tcl/target/ti_tms570ls3137.cfg rename to tcl/target/ti/tms570ls3137.cfg index ebe2cfc652..2cbbde84fe 100644 --- a/tcl/target/ti_tms570ls3137.cfg +++ b/tcl/target/ti/tms570ls3137.cfg @@ -4,4 +4,4 @@ set DAP_TAPID 0x0B8A002F set JRC_TAPID 0x0B8A002F -source [find target/ti_tms570.cfg] +source [find target/ti/tms570.cfg] diff --git a/tcl/target/vd_riscv.cfg b/tcl/target/vd_riscv.cfg index f08cb1ac8b..44a80524a6 100644 --- a/tcl/target/vd_riscv.cfg +++ b/tcl/target/vd_riscv.cfg @@ -2,15 +2,15 @@ # Cadence virtual debug interface # RISCV core -if {![info exists _HARTID]} { - set _HARTID 0x00 +if {![info exists HARTID]} { + set HARTID 0x00 } -if {![info exists _CHIPNAME]} { - set _CHIPNAME riscv +if {![info exists CHIPNAME]} { + set CHIPNAME riscv } -set _TARGETNAME $_CHIPNAME.cpu +set _TARGETNAME $CHIPNAME.cpu -target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $_HARTID +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $HARTID riscv set_reset_timeout_sec 120 riscv set_command_timeout_sec 120 diff --git a/tcl/target/K1879x61R.cfg "b/tcl/target/\320\2721879x\320\2611\321\217.cfg" similarity index 100% rename from tcl/target/K1879x61R.cfg rename to "tcl/target/\320\2721879x\320\2611\321\217.cfg" diff --git a/testing/tcl_commands/Makefile.am b/testing/tcl_commands/Makefile.am index 4f9e37ecda..b331491137 100644 --- a/testing/tcl_commands/Makefile.am +++ b/testing/tcl_commands/Makefile.am @@ -4,9 +4,12 @@ TESTS = if DUMMY TESTS += \ + test-target-create-command.cfg \ + test-target-configure-cget-command.cfg \ test-jtag-execute-command.cfg \ test-irscan-command.cfg \ - test-drscan-command.cfg + test-drscan-command.cfg \ + test-target-smp-command.cfg endif EXTRA_DIST = utils.tcl $(TESTS) diff --git a/testing/tcl_commands/test-target-configure-cget-command.cfg b/testing/tcl_commands/test-target-configure-cget-command.cfg new file mode 100644 index 0000000000..2d546c83da --- /dev/null +++ b/testing/tcl_commands/test-target-configure-cget-command.cfg @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +namespace import testing_helpers::* +namespace import configure_testing::* + +adapter driver dummy +jtag newtap tap cpu -irlen 5 + +{*}[target_create_first_args] {*}[simple_configure_options] + +set target_name [lindex [target names] 0] + +check_matches testee {$target_name cget -type} + +foreach {opt arg} [simple_configure_options] { + check_syntax_err {$target_name cget $opt extra_arg} + check_matches [dict get [simple_configure_options] $opt] \ + {$target_name cget $opt} +} + +check_error_matches .*-event.* {$target_name cget -event} +$target_name cget -event examine-start +check_syntax_err {$target_name cget -event examine-start extra_arg} + +check_syntax_err {$target_name configure} + +foreach {opt arg} [simple_configure_options] { + $target_name configure $opt [$target_name cget $opt] +} + +shutdown diff --git a/testing/tcl_commands/test-target-create-command.cfg b/testing/tcl_commands/test-target-create-command.cfg new file mode 100644 index 0000000000..11264316c3 --- /dev/null +++ b/testing/tcl_commands/test-target-create-command.cfg @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +namespace import testing_helpers::* +namespace import configure_testing::* + +adapter driver dummy +jtag newtap tap cpu -irlen 5 + +check_syntax_err {target create} +check_syntax_err {target create} +check_syntax_err {target create test.target} +check_error_matches -chain-position {target create test.target testee} + +{*}[target_create_first_args] {*}[simple_configure_options] + +foreach {opt arg} [simple_configure_options] { + check_error_matches ".*${opt}.*" {{*}[target_create_first_args] $opt} +} + +foreach {opt1 arg1} [simple_configure_options] { + foreach {opt2 arg2} [simple_configure_options] { + check_error_matches ".*${opt2}.*" \ + {{*}[target_create_first_args] $opt1 $arg1 $opt2} + check_error_matches {} \ + {{*}[target_create_first_args] $opt1 $opt2 $arg2} + } +} + +check_error_matches ".*-type.*" \ + {{*}[target_create_first_args] -type} + +check_error_matches ".*-type.*" \ + {{*}[target_create_first_args] {*}[simple_configure_options] -type} + +check_error_matches {.*-event [^ ]+ .*} \ + {{*}[target_create_first_args] -event} + +check_error_matches {.*not-an-event.*} \ + {{*}[target_create_first_args] -event not-an-event} + +check_error_matches {.*-event examine-start [^ ]+.*} \ + {{*}[target_create_first_args] -event examine-start} + +{*}[target_create_first_args] {*}[simple_configure_options] \ + -event examine-start body +{*}[target_create_first_args] {*}[simple_configure_options] \ + -event examine-start body \ + -event examine-end another-body \ + -event examine-start new-body +{*}[target_create_first_args] -event examine-start body {*}[simple_configure_options] + +{*}[target_create_first_args] {*}[simple_configure_options] -defer-examine + +shutdown diff --git a/testing/tcl_commands/test-target-smp-command.cfg b/testing/tcl_commands/test-target-smp-command.cfg new file mode 100644 index 0000000000..ff4ab02e09 --- /dev/null +++ b/testing/tcl_commands/test-target-smp-command.cfg @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +namespace import testing_helpers::* + +adapter driver dummy +jtag newtap tap0 cpu -irlen 2 +jtag newtap tap1 cpu -irlen 2 +target create tgt0 testee -chain-position tap0.cpu +target create tgt1 testee -chain-position tap1.cpu + +init + +target smp tgt0 tgt1 +check_matches on {tgt0 smp} +check_matches on {tgt1 smp} + +target smp not_a_target +check_matches on {tgt0 smp} +check_matches on {tgt1 smp} + +target smp tgt0 +check_matches on {tgt0 smp} +check_matches off {tgt1 smp} + +target smp tgt0 not_a_target +check_matches on {tgt0 smp} +check_matches off {tgt1 smp} + +target smp tgt0 +check_matches on {tgt0 smp} +check_matches off {tgt1 smp} + +target smp tgt0 tgt0 +check_matches on {tgt0 smp} +check_matches off {tgt1 smp} + +target smp tgt1 +check_matches on {tgt0 smp} +check_matches on {tgt1 smp} + +target smp tgt0 tgt1 +check_matches on {tgt0 smp} +check_matches on {tgt1 smp} + +target smp tgt1 +check_matches off {tgt0 smp} +check_matches on {tgt1 smp} + +target smp tgt0 tgt1 +check_matches on {tgt0 smp} +check_matches on {tgt1 smp} + +target smp tgt0 tgt1 +check_matches on {tgt0 smp} +check_matches on {tgt1 smp} + +shutdown diff --git a/testing/tcl_commands/utils.tcl b/testing/tcl_commands/utils.tcl index c18f875cf9..09ae79c85f 100644 --- a/testing/tcl_commands/utils.tcl +++ b/testing/tcl_commands/utils.tcl @@ -8,20 +8,26 @@ namespace eval testing_helpers { } proc check_for_error {expctd_code msg_ptrn script} { - set code [catch {uplevel 1 $script} msg] - if {!$code} { + set ::errorCode NONE + set code [catch {uplevel $script} msg] + set expanded_script [uplevel subst \"$script\"] + if {$code == 0} { test_failure \ - "'$script' finished successfully. \ + "'$expanded_script' finished successfully. \ Was expecting an error." } - if {$expctd_code ne "" && $code != $expctd_code} { + if {$code != 1} { test_failure \ - "'$script' returned unexpected error code $code. \ - Was expecting $expctd_code. Error message: '$msg'" + "'$expanded_script' returned unexpected error code $code" } - if {$msg_ptrn ne "" && ![regexp $msg_ptrn $msg]} { + if {$expctd_code ne "" && ([lindex $::errorCode 0] ne "OpenOCD" || [lindex $::errorCode 1] != $expctd_code)} { test_failure \ - "'$script' returned unexpected error message '$msg'. \ + "'$expanded_script' returned unexpected error code '$::errorCode'. \ + Was expecting 'OpenOCD $expctd_code'. Error message: '$msg'" + } + if {$msg_ptrn ne "" && ![regexp -- $msg_ptrn $msg]} { + test_failure \ + "'$expanded_script' returned unexpected error message '$msg'. \ Was expecting '$msg_ptrn'. Error code: $code" } } @@ -34,6 +40,10 @@ namespace eval testing_helpers { tailcall check_for_error -603 {} $script } + proc check_error_matches {pattern script} { + tailcall check_for_error {} $pattern $script + } + proc check_syntax_err script { tailcall check_for_error -601 {} $script } @@ -55,7 +65,8 @@ namespace eval testing_helpers { } namespace export check_generic_error check_invalid_arg check_syntax_err \ - check_overflow_err check_underflow_err check_matches + check_overflow_err check_underflow_err check_matches check_error_matches \ + check_syntax_err } namespace eval jtag_dummy_testing { @@ -106,3 +117,36 @@ namespace eval jtag_dummy_testing { namespace export setup } + +namespace eval configure_testing { + + variable target_idx 0 + + proc unique_tgt_name {} { + variable target_idx + incr target_idx + return test_target$target_idx + } + + proc target_create_first_args {} { + return "target create [unique_tgt_name] testee" + } + + proc simple_configure_options {} { + return { + -work-area-virt 0 + -work-area-phys 0 + -work-area-size 1 + -work-area-backup 0 + -endian little + -coreid 1 + -chain-position tap.cpu + -dbgbase 0 + -rtos hwthread + -gdb-port 0 + -gdb-max-connections 1 + } + } + + namespace export target_create_first_args simple_configure_options +} diff --git a/tools/filter_openocd_log.py b/tools/filter_openocd_log.py deleted file mode 100755 index 666e166ddb..0000000000 --- a/tools/filter_openocd_log.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import re - -# This function is the only OpenOCD-specific part of this script. -def make_canonical(line): - # Remove the line number and time stamp. - m = re.match(r"(Debug|Error|Info |User |Warn ): \d+ \d+ (.*)", line) - if m: - return "%s: - - %s\n" % (m.group(1), m.group(2)) - else: - return line - -def buf_startswith(buf, sequence): - if len(buf) < len(sequence): - return False - for i, entry in enumerate(sequence): - if entry[1] != buf[i][1]: - return False - return True - -def shorten_buffer(outfd, buf, current_repetition): - """Do something to the buffer to make it shorter. If we can't compress - anything, then print out the first line and remove it.""" - length_before = len(buf) - - if current_repetition: - while buf_startswith(buf, current_repetition[0]): - del buf[:len(current_repetition[0])] - current_repetition[1] += 1 - if len(buf) < length_before: - return current_repetition - outfd.write("## The following %d lines repeat %d times:\n" % ( - len(current_repetition[0]), current_repetition[1])) - for entry in current_repetition[0]: - outfd.write("# %s" % entry[1]) - - # Look for repeated sequences... - repetitions = [] - for length in range(1, int(len(buf)/2)): - # Is there a repeating sequence of `length` lines? - matched_lines = 0 - for i, entry in enumerate(buf[length:]): - if entry[1] == buf[i % length][1]: - matched_lines += 1 - else: - break - if matched_lines >= length: - repetitions.append((matched_lines + length, length)) - - if repetitions: - repetitions.sort(key=lambda entry: -entry[1]) - matched_lines, length = repetitions[-1] - repeated = int(matched_lines / length) - if repeated * length >= 3: - sequence = buf[:length] - del buf[:repeated * length] - - if matched_lines == length_before: - # Could be continued... - return [sequence, repeated] - - else: - outfd.write("## The following %d lines repeat %d times:\n" % - (length, repeated)) - for entry in sequence: - outfd.write("# %s" % entry[1]) - return None - - if len(buf) >= length_before: - line, _ = buf[0] - outfd.write(line) - buf.pop(0) - - if length_before <= len(buf): - print("Buffer:") - for entry in buf: - print("%r" % entry[0]) - assert False - - return None - -def compress_log(infd, outfd, window): - """Compress log by finding repeated runs of lines. Runs in O(lines * - window**2), which can probably be improved.""" - # Contains line, canonical tuples - buf = [] - current_repetition = None - - for line in infd: - buf.append((line, make_canonical(line))) - if len(buf) > window: - current_repetition = shorten_buffer(outfd, buf, current_repetition) - - while len(buf) > 0: - current_repetition = shorten_buffer(outfd, buf, current_repetition) - -def main(args): - import argparse - parser = argparse.ArgumentParser( - description='Combine repeated OpenOCD debug output lines. This is ' - 'very helpful when looking at verbose log files where e.g. target ' - 'polling is repeated over and over.', - epilog='If no files are specified, read standard input.', - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument('file', nargs='*', help='input file') - parser.add_argument('-o', '--output', help='output file', default=sys.stdout) - parser.add_argument('-w', '--window', type=int, default=400, - help='number of lines to consider when looking for repetitions') - args = parser.parse_args(args) - - if args.file: - for f in args.file: - compress_log(open(f, "r"), args.output, args.window) - else: - compress_log(sys.stdin, args.output, args.window) - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) diff --git a/tools/scripts/camelcase.txt b/tools/scripts/camelcase.txt index 6c6c28daa5..ee690f64d9 100644 --- a/tools/scripts/camelcase.txt +++ b/tools/scripts/camelcase.txt @@ -87,20 +87,14 @@ 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 @@ -113,46 +107,34 @@ 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_Length 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_SetGlobalVariableStr 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 @@ -179,7 +161,6 @@ CreateFile CloseHandle FormatMessage GetModuleFileName -GetSystemTimeAsFileTime GetTickCount GetVersionEx HighPart @@ -188,14 +169,15 @@ MsgWaitForMultipleObjects PeekMessage PeekNamedPipe QuadPart +QueryPerformanceCounter +QueryPerformanceFrequency SetConsoleCtrlHandler Sleep WaitForSingleObject WSACleanup WSAGetLastError +WSASetLastError WSAStartup -dwHighDateTime -dwLowDateTime dwPlatformId dwOSVersionInfoSize diff --git a/tools/scripts/checkpatch.pl b/tools/scripts/checkpatch.pl index 1011b33055..f77f364d1c 100755 --- a/tools/scripts/checkpatch.pl +++ b/tools/scripts/checkpatch.pl @@ -92,6 +92,12 @@ my $tabsize = 8; my ${CONFIG_} = "CONFIG_"; +# OpenOCD specific: Begin: check markdown with pymarkdownlnt +# Remember which Markdown (*.md) files were already linted. +my %md_checked; +my $md_linter_not_found; +# OpenOCD specific: End + sub help { my ($exitcode) = @_; @@ -1417,14 +1423,14 @@ sub top_of_kernel_tree { if (!$OpenOCD) { my @tree_check = ( "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile", - "README", "Documentation", "arch", "include", "drivers", + "README.md", "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", + "README.md", "contrib", "doc", "src", "tcl", "testing", "tools", ); # OpenOCD specific: End @@ -2435,6 +2441,44 @@ sub report_dump { our @report; } +# OpenOCD specific: Begin: check markdown with pymarkdownlnt +sub run_md_linter { + my ($file) = @_; + my $md_linter = "pymarkdownlnt"; + + return if !$file || !-f $file; + + if (!defined($md_linter_not_found)) { + $md_linter_not_found = (which($md_linter) eq ""); + } + + if ($md_linter_not_found) { + return; + } + + my @cmd = ($md_linter, "scan", $file); + + my @out = qx{@cmd 2>&1}; + my $rc = $? >> 8; + + foreach my $line (@out) { + chomp $line; + next if $line eq ""; + + if ($line =~ m/^(.*?):(\d+):(\d+):\s*([A-Z0-9]+):\s*(.*)$/) { + my ($path, $ln, $col, $code, $msg) = ($1, $2, $3, $4, $5); + WARN("MARKDOWN_LINT", "$file:$ln:$col: $code: $msg\n"); + } else { + WARN("MARKDOWN_LINT: Failed to parse output: $line\n"); + } + } + + if ($rc != 0 && !@out) { + WARN("MARKDOWN_LINT", "Markdown linter exited with status $rc for $file\n"); + } +} +# OpenOCD specific: End + sub fixup_current_range { my ($lineRef, $offset, $length) = @_; @@ -2965,6 +3009,15 @@ sub process { } } + # OpenOCD specific: Begin: check markdown with pymarkdownlnt + # Lint Markdown files. + if ($realfile =~ /\.md$/ && !$md_checked{$realfile}) { + my $fullpath = $root ? "$root/$realfile" : $realfile; + run_md_linter($fullpath); + $md_checked{$realfile} = 1; + } + # OpenOCD specific: End + next; } @@ -3879,6 +3932,12 @@ sub process { # more than $tabsize must use tabs. if ($rawline =~ /^\+\s* \t\s*\S/ || $rawline =~ /^\+\s* \s*/) { + # OpenOCD specific: Begin: fix check on $tabsize + # Do nothing in this default upstream case + } + if ($rawline =~ /^\+\s* \t\s*\S/ || + $rawline =~ /^\+\s* {$tabsize}\s*/) { + # OpenOCD specific: End my $herevet = "$here\n" . cat_vet($rawline) . "\n"; $rpt_cleaners = 1; if (ERROR("CODE_INDENT", @@ -4040,6 +4099,7 @@ sub process { } } +if (!$OpenOCD) { # check for missing blank lines after struct/union declarations # with exceptions for various attributes and macros if ($prevline =~ /^[\+ ]};?\s*$/ && @@ -4059,6 +4119,7 @@ sub process { fix_insert_line($fixlinenr, "\+"); } } +} # !$OpenOCD # check for multiple consecutive blank lines if ($prevline =~ /^[\+ ]\s*$/ && @@ -4073,6 +4134,7 @@ sub process { $last_blank_line = $linenr; } +if (!$OpenOCD) { # 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/) { @@ -4118,6 +4180,7 @@ sub process { } } } +} # !$OpenOCD # check for spaces at the beginning of a line. # Exceptions: diff --git a/tools/scripts/spdxcheck.py b/tools/scripts/spdxcheck.py index f882943790..9180f61fa6 100755 --- a/tools/scripts/spdxcheck.py +++ b/tools/scripts/spdxcheck.py @@ -50,7 +50,7 @@ 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" ] + license_dirs = [ "preferred", "dual", "exceptions", "stand-alone" ] # OpenOCD specific: End lictree = repo.head.commit.tree['LICENSES'] diff --git a/tools/scripts/typedefs.txt b/tools/scripts/typedefs.txt index 97f330d9dc..57da94056a 100644 --- a/tools/scripts/typedefs.txt +++ b/tools/scripts/typedefs.txt @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later fd_set +FILE Jim_Cmd Jim_CmdProc Jim_DelCmdProc