├── LICENSE ├── Makefile ├── README.md ├── bin ├── flasher-gap └── plpbridge ├── include └── debug_bridge │ ├── debug_bridge.h │ └── proxy.hpp ├── python └── bridge │ ├── chips │ ├── arnold.py │ ├── fulmine.py │ ├── gap.py │ ├── gap8_revc.py │ ├── gap_rev1.py │ ├── pulp.py │ ├── pulpissimo.py │ ├── pulpissimo_v2.py │ ├── usoc_v1.py │ ├── vega.py │ ├── vivosoc3.py │ └── wolfe.py │ ├── debug_bridge.py │ ├── default_debug_bridge.py │ └── jtag.py └── src ├── cable.hpp ├── cables ├── adv_dbg_itf │ ├── adv_dbg_itf.cpp │ └── adv_dbg_itf.hpp ├── ftdi │ ├── ftdi.cpp │ └── ftdi.hpp ├── jtag-proxy │ ├── jtag-proxy.cpp │ └── jtag-proxy.hpp ├── jtag.cpp └── log.h ├── gdb-server ├── breakpoints.cpp ├── gdb-server.cpp ├── gdb-server.h ├── gdb-server.hpp ├── rsp.cpp └── target.cpp ├── python_wrapper.cpp └── reqloop.cpp /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | INSTALL_DIR ?= $(CURDIR)/install 2 | TARGET_INSTALL_DIR ?= $(CURDIR)/install 3 | BUILD_DIR ?= $(CURDIR)/build 4 | 5 | 6 | 7 | HEADER_FILES += $(shell find include -name *.hpp) 8 | TARGET_HEADER_FILES += $(shell find include -name *.h) 9 | HEADER_FILES += $(shell find include -name *.h) 10 | HEADER_FILES += $(shell find bin -type f) 11 | 12 | define declareInstallFile 13 | $(INSTALL_DIR)/$(1): $(1) 14 | install -D $(1) $$@ 15 | INSTALL_HEADERS += $(INSTALL_DIR)/$(1) 16 | endef 17 | 18 | define declareTargetInstallFile 19 | $(TARGET_INSTALL_DIR)/$(1): $(1) 20 | install -D $(1) $$@ 21 | INSTALL_HEADERS += $(TARGET_INSTALL_DIR)/$(1) 22 | endef 23 | 24 | define declareJsonInstallFile 25 | $(INSTALL_DIR)/$(1): json-tools/$(1) 26 | install -D json-tools/$(1) $$@ 27 | INSTALL_HEADERS += $(INSTALL_DIR)/$(1) 28 | endef 29 | 30 | HEADER_FILES += $(shell find python -name *.py) 31 | 32 | 33 | 34 | FTDI_CFLAGS = $(shell libftdi1-config --cflags) 35 | FTDI_LDFLAGS = $(shell libftdi1-config --libs) 36 | 37 | ifeq '$(FTDI_CFLAGS)$(FTDI_LDFLAGS)' '' 38 | FTDI_CFLAGS = $(shell libftdi-config --cflags) 39 | FTDI_LDFLAGS = $(shell libftdi-config --libs) 40 | endif 41 | 42 | ifneq '$(FTDI_CFLAGS)$(FTDI_LDFLAGS)' '' 43 | USE_FTDI=1 44 | endif 45 | 46 | FTDI_1_4=$(shell pkg-config --exists libftdi1 --atleast-version=1.4 || echo FAILED) 47 | 48 | ifeq '$(FTDI_1_4)' '' 49 | FTDI_CFLAGS += -DFTDI_1_4 50 | endif 51 | 52 | 53 | SDL_CFLAGS = $(shell sdl2-config --cflags) 54 | SDL_LDFLAGS = $(shell sdl2-config --libs) 55 | 56 | ifneq '$(SDL_CFLAGS)$(SDL_LDFLAGS)' '' 57 | USE_SDL=1 58 | endif 59 | 60 | 61 | 62 | CFLAGS += -O3 -g -fPIC -std=gnu++11 -MMD -MP -Isrc -Iinclude -I$(INSTALL_DIR)/include $(FTDI_CFLAGS) $(SDL_CFLAGS) 63 | LDFLAGS += -O3 -g -shared $(FTDI_LDFLAGS) $(SDL_LDFLAGS) 64 | 65 | SRCS = src/python_wrapper.cpp src/cables/jtag.cpp src/reqloop.cpp \ 66 | src/cables/adv_dbg_itf/adv_dbg_itf.cpp src/gdb-server/gdb-server.cpp \ 67 | src/gdb-server/rsp.cpp src/gdb-server/target.cpp src/gdb-server/breakpoints.cpp 68 | 69 | LDFLAGS += -L$(INSTALL_DIR)/lib 70 | LDFLAGS += -ljson 71 | 72 | ifneq '$(USE_FTDI)' '' 73 | CFLAGS += -D__USE_FTDI__ 74 | SRCS += src/cables/ftdi/ftdi.cpp 75 | endif 76 | 77 | ifneq '$(USE_SDL)' '' 78 | CFLAGS += -D__USE_SDL__ 79 | endif 80 | 81 | SRCS += src/cables/jtag-proxy/jtag-proxy.cpp 82 | 83 | OBJS = $(patsubst %.cpp,$(BUILD_DIR)/%.o,$(SRCS)) 84 | 85 | $(foreach file, $(HEADER_FILES), $(eval $(call declareInstallFile,$(file)))) 86 | $(foreach file, $(TARGET_HEADER_FILES), $(eval $(call declareTargetInstallFile,$(file)))) 87 | 88 | 89 | all: build 90 | 91 | install: 92 | 93 | -include $(OBJS:.o=.d) 94 | 95 | $(BUILD_DIR)/%.o: %.cpp 96 | @mkdir -p $(basename $@) 97 | $(CXX) $(CFLAGS) -o $@ -c $< 98 | 99 | $(BUILD_DIR)/libpulpdebugbridge.so: $(OBJS) 100 | $(CXX) -o $@ $^ $(LDFLAGS) 101 | 102 | $(INSTALL_DIR)/lib/libpulpdebugbridge.so: $(BUILD_DIR)/libpulpdebugbridge.so 103 | install -D $< $@ 104 | 105 | build: $(INSTALL_HEADERS) $(INSTALL_DIR)/lib/libpulpdebugbridge.so 106 | 107 | clean: 108 | rm -rf $(BUILD_DIR) 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pulp debug bridge 2 | 3 | This is a tool which can be used to interact with a pulp target, like doing read and write or loading a binary. 4 | It also provide an RSP server so that it can be used to interface GDB with pulp targets. 5 | 6 | ### Getting the sources 7 | 8 | You can get the sources with this command: 9 | 10 | $ git clone https://github.com/pulp-platform/pulp-debug-bridge.git 11 | 12 | ### Prerequisites 13 | 14 | In case the FTDI cables are needed, the libftdi must be installed. Here is the command on Ubuntu to install it: 15 | 16 | $ sudo apt-get install libftdi1-dev 17 | 18 | Once the FTDI lib is installed, USB access rights must be updated. 19 | Most of the time a rule like the following must be added under /etc/udev/rules.d/, for example in /etc/udev/rules.d/10-ftdi.rules: 20 | 21 | ATTR{idVendor}=="15ba", ATTR{idProduct}=="002b", MODE="0666", GROUP="dialout" 22 | 23 | The following command can be used to restart udev after the rule has been added: 24 | 25 | sudo udevadm control --reload-rules && sudo udevadm trigger 26 | 27 | The user should also need to be in the *dialout* group. 28 | 29 | The following python package is also needed: 30 | 31 | $ sudo pip3 install pyelftools 32 | 33 | 34 | ### Installation 35 | 36 | To build this tool, you have to clone the following repository: 37 | 38 | $ git clone git@github.com:pulp-platform/pulp-builder.git --recursive 39 | 40 | Then go inside pulp-builder and execute the following command: 41 | 42 | $ ./scripts/build-debug-bridge 43 | 44 | This will checkout all sources inluding other modules needed by the bridge, build everything and install that under the `install` directory. 45 | 46 | All what is needed to use the tool is then inside the directory `install`. You can define the following paths in order to use it: 47 | 48 | export PATH=$PWD/install/ws/bin:$PATH 49 | export PYTHONPATH=$PWD/install/ws/python:$PYTHONPATH 50 | export LD_LIBRARY_PATH=$PWD/install/ws/lib:$LD_LIBRARY_PATH 51 | export PULP_CONFIGS_PATH=$PWD/install/ws/configs 52 | 53 | 54 | ### Usage 55 | 56 | You can execute the following to display the help: 57 | 58 | $ plpbridge --help 59 | 60 | You need at least to configure the cable and the target with these options: 61 | 62 | # plpbridge --chip=pulpissimo --cable=ftdi 63 | 64 | You can for example read from the target with this command: 65 | 66 | # plpbridge --chip=pulpissimo --cable=ftdi read --addr=0x1c000000 --size=32 67 | 68 | Or write: 69 | 70 | # plpbridge --chip=pulpissimo --cable=ftdi write --addr=0x1c000000 --size=32 --value=0x12345678 71 | 72 | A binary can also be loaded with this command: 73 | 74 | # plpbridge --chip=pulpissimo --cable=ftdi load --binary= 75 | 76 | The RSP server for the GDB connection can be started with this command: 77 | 78 | # plpbridge --chip=pulpissimo --cable=ftdi gdb wait --rsp-port=1234 79 | 80 | ### Supported cables 81 | 82 | 2 FTDI cables are supported: --cable=ftdi@olimex and --cable=ftdi@digilent. 83 | However the bridge may need few modifications depending on the ftdi chip which is used. 84 | 85 | It is also possible to connect the bridge to a remote server, like an RTL platform (using a DPI model): --cable=jtag-proxy. 86 | More information for this cable will be provided soon. 87 | 88 | ### Supported targets 89 | 90 | Only pulp and pulpissimo are supported for now. 91 | 92 | ### Customizing existing targets 93 | 94 | The bridge is getting architecture information about the selected chip using a JSON description of the architecture. 95 | Such descriptions can be found under install/configs/systems (once the bridge is built). For example if the selected chip is pulpissimo, the bridge will get the description from install/configs/systems/pulpissimo.json. These configs comes from the pulp-configs module which is downloaded as a dependency and are found by the bridge using the environment variable PULP_CONFIGS_PATH. 96 | 97 | The configs contains a lot of hardware details and are generated from high-level descriptions that can be found under install/configs/templates/chips. The idea is that this high-level config describes the most important architecture properties, which are then used by generator scripts to generate the final detailed description. 98 | 99 | If the targetted architecture is slightly different from an existing one, it is possible to take one of these templates and customize it to reflect the differences, and then use the generated configuration to configure the bridge. 100 | 101 | For that first copy and modify an existing template: 102 | 103 | $ cp install/configs/templates/chips/pulpissimo.json my_template.json 104 | 105 | The memory map can for example be modified and will be taken into account by the generators. 106 | Then generate the configuration from your template: 107 | 108 | $ pulp_config_gen --template=$PWD/my_template.json --output=my_config.json 109 | 110 | Then instead of specifying a chip, you can specify your configuration on the bridge command-line like this: 111 | 112 | $ plpbridge --config=my_config.json --cable=ftdi load --binary= 113 | -------------------------------------------------------------------------------- /bin/flasher-gap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pulp-platform/pulp-debug-bridge/a86ed5a887585daf85bb07bb6c5c515a1587122c/bin/flasher-gap -------------------------------------------------------------------------------- /bin/plpbridge: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # Copyright (C) 2018 ETH Zurich and University of Bologna 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 20 | 21 | 22 | import bridge.debug_bridge as db 23 | import argparse 24 | import code 25 | from importlib.machinery import SourceFileLoader 26 | import os.path 27 | import sys 28 | import pulp_config as plpconf 29 | 30 | try: 31 | import plptree 32 | except: 33 | pass 34 | 35 | import json_tools as js 36 | 37 | try: 38 | from IPython import embed 39 | except: 40 | pass 41 | 42 | 43 | 44 | class bcolors: 45 | HEADER = '\033[95m' 46 | OKBLUE = '\033[94m' 47 | OKGREEN = '\033[92m' 48 | WARNING = '\033[93m' 49 | FAIL = '\033[91m' 50 | ENDC = '\033[0m' 51 | BOLD = '\033[1m' 52 | UNDERLINE = '\033[4m' 53 | 54 | 55 | def fatal_error(error): 56 | print (bcolors.FAIL + 'FATAL ERROR: ' + error + bcolors.ENDC) 57 | 58 | 59 | def read(bridge): 60 | if args.addr == None: 61 | raise Exception('Access address must be given through option --addr when using command "read"') 62 | 63 | addr = int(args.addr, 0) 64 | size = int(args.size, 0) 65 | width = args.width 66 | 67 | if args.verbose >= 4: 68 | print ('Read access command (addr: 0x%x, size: 0x%x)' % (addr, size)) 69 | 70 | data = bridge.read(addr=addr, size=size) 71 | 72 | while size > 0: 73 | line = '%8.8x: ' % addr 74 | for i in range(0, 16, width): 75 | 76 | line += '%*.*x ' % (width*2, width*2, int.from_bytes(b''.join(data[0:width]), byteorder='little')) 77 | size -= width 78 | addr += width 79 | data = data[width:] 80 | if size <= 0: 81 | break 82 | print (line) 83 | 84 | return 0 85 | 86 | 87 | 88 | def write(bridge): 89 | if args.addr == None: 90 | raise Exception('Access address must be given through option --addr when using command "write"') 91 | 92 | if args.value == None: 93 | raise Exception('Access value must be given through option --value when using command "write"') 94 | 95 | addr = int(args.addr, 0) 96 | size = int(args.size, 0) 97 | value = int(args.value, 0) 98 | 99 | if args.verbose >= 4: 100 | print ('Write access command (addr: 0x%x, size: 0x%x, value: 0x%x)' % (addr, size, value)) 101 | 102 | bridge.write(addr=addr, size=size, buffer=value.to_bytes(size, byteorder='little')) 103 | 104 | return 0 105 | 106 | def efuse_write(bridge): 107 | addr = int(args.addr, 0) 108 | value = int(args.value, 0) 109 | mask = int(args.mask, 0) 110 | 111 | bridge.efuse_access(args.flasher_init, True, addr, value, mask) 112 | 113 | return 0 114 | 115 | def eeprom_write(bridge): 116 | addr = int(args.addr, 0) 117 | 118 | return bridge.eeprom_access(args.flasher_init, 0, 0, True, addr, args.file) 119 | 120 | 121 | def get_flash_id(): 122 | if args.flash_type == 'hyperflash': 123 | return 1 124 | elif args.flash_type == 'mram': 125 | return 2 126 | else: 127 | return 0 128 | 129 | 130 | def flash_write(bridge): 131 | addr = int(args.addr, 0) 132 | 133 | return bridge.flash_access(args.flasher_init, get_flash_id(), 0, 0, True, addr, 0, args.file) 134 | 135 | 136 | def flash_read(bridge): 137 | addr = int(args.addr, 0) 138 | size = int(args.size, 0) 139 | 140 | return bridge.flash_access(args.flasher_init, get_flash_id(), 0, 0, False, addr, size, args.file) 141 | 142 | 143 | def flash_erase(bridge): 144 | addr = int(args.addr, 0) 145 | size = int(args.size, 0) 146 | 147 | return bridge.flash_erase(args.flasher_init, get_flash_id(), 0, 0, addr, size) 148 | 149 | 150 | def flash_erase_sector(bridge): 151 | addr = int(args.addr, 0) 152 | 153 | return bridge.flash_erase_sector(args.flasher_init, get_flash_id(), 0, 0, addr) 154 | 155 | 156 | def flash_erase_chip(bridge): 157 | return bridge.flash_erase_chip(args.flasher_init, get_flash_id(), 0, 0) 158 | 159 | 160 | def load(bridge): 161 | 162 | if args.verbose >= 4: 163 | binaries = [] 164 | binaries_conf = bridge.config.get('**/runner/binaries') 165 | if binaries_conf is not None: 166 | binaries = binaries_conf.get_dict() 167 | print ('Loading ELF binaries (path: %s)' % ' '.join(binaries)) 168 | 169 | return bridge.load() 170 | 171 | 172 | def ioloop(bridge): 173 | if args.verbose >= 4: 174 | print ('Lauching IO loop') 175 | 176 | return bridge.ioloop() 177 | 178 | 179 | def reqloop(bridge): 180 | if args.verbose >= 4: 181 | print ('Lauching req loop') 182 | 183 | return bridge.reqloop() 184 | 185 | 186 | def gdb(bridge): 187 | if args.verbose >= 4: 188 | print ('Lauching GDB server') 189 | 190 | return bridge.gdb(int(args.rsp_port)) 191 | 192 | 193 | def start(bridge): 194 | if args.verbose >= 4: 195 | print ('Starting execution') 196 | 197 | return bridge.start() 198 | 199 | 200 | def stop(bridge): 201 | if args.verbose >= 4: 202 | print ('Stopping execution') 203 | 204 | return bridge.stop() 205 | 206 | 207 | def wait(bridge): 208 | if args.verbose >= 4: 209 | print ('Waiting termination') 210 | 211 | return bridge.wait() 212 | 213 | def flash(bridge): 214 | # When using the flasher, the binaries should be the flasher 215 | bridge.binaries= [os.environ["INSTALL_DIR"] + "/bin/flasher"] 216 | if args.verbose >=4: 217 | print("Flashing the flash image") 218 | 219 | load(bridge) 220 | ioloop(bridge) 221 | start(bridge) 222 | return bridge.flash(args.fimages) 223 | 224 | 225 | def reset(bridge): 226 | if args.verbose >= 4: 227 | print ('Chip reset') 228 | 229 | return bridge.reset() 230 | 231 | 232 | def script(bridge): 233 | 234 | for script in args.scripts: 235 | if args.verbose >= 4: 236 | print ('Executing script: ' + script) 237 | 238 | if script.find('@') == -1: 239 | script_name = script 240 | script_entry = "debug_bridge_entry" 241 | else: 242 | script_entry, script_name = script.split('@') 243 | 244 | module = SourceFileLoader("user_script", script_name).load_module() 245 | 246 | entry = getattr(module, script_entry) 247 | if entry(bridge): 248 | return -1 249 | 250 | return 0 251 | 252 | 253 | 254 | commands = { 255 | 'read' : ['Read data from the target', read], 256 | 'write' : ['Write data to the target', write], 257 | 'load' : ['Load a binary into the target', load], 258 | 'ioloop' : ['Activate IO loop', ioloop], 259 | 'reqloop' : ['Activate request loop', reqloop], 260 | 'gdb' : ['Open RSP server for GDB connection',gdb], 261 | 'start' : ['Start execution', start], 262 | 'stop' : ['Stop execution', stop], 263 | 'flash' : ['Flash the flash image', flash], 264 | 'wait' : ['Wait termination', wait], 265 | 'reset' : ['Chip reset', reset], 266 | 'script' : ['Execute user scripts', script], 267 | 'efuse_write' : ['Write to efuse', efuse_write], 268 | 'eeprom_write': ['Write to eeprom', eeprom_write], 269 | 'flash_write' : ['Write to flash', flash_write], 270 | 'flash_read' : ['Read from flash', flash_read], 271 | 'flash_erase_sector' : ['Erase flash sector', flash_erase_sector], 272 | 'flash_erase' : ['Erase flash area', flash_erase], 273 | 'flash_erase_chip' : ['Erase flash', flash_erase_chip], 274 | } 275 | 276 | 277 | command_help = """Available commands: 278 | """ 279 | 280 | for name, cmd in commands.items(): 281 | command_help += ' %-10s %s\n' % (name, cmd[0]) 282 | 283 | parser = argparse.ArgumentParser(description='Control a pulp target', 284 | epilog=command_help, formatter_class=argparse.RawDescriptionHelpFormatter, add_help=False 285 | ) 286 | 287 | parser.add_argument('command', metavar='CMD', type=str, nargs='*', 288 | help='a command to be executed (see the command help afterwards)') 289 | 290 | parser.add_argument("--script", dest="scripts", default=[], action="append", help="Specify a script to be executed with the script command") 291 | parser.add_argument("--config", dest="config", default=None, help="Specify the system configuration") 292 | parser.add_argument("--config-path", dest="config_path", default=None, help="Specify the system configuration") 293 | parser.add_argument("--ipython", dest="ipython", action="store_true", help="Enter ipython shell") 294 | parser.add_argument("--shell", dest="shell", action="store_true", help="Enter python shell") 295 | parser.add_argument("--port", dest="port", type=int, default=None, help="Specify port for proxy mode") 296 | parser.add_argument("--debug", dest="debug", action='store_true', default=False, help="Activate debug mode for this script") 297 | parser.add_argument("--verbose", dest="verbose", type=int, default=3, help="Verbose mode") 298 | parser.add_argument("--help", dest="help", action='store_true', default=False, help="Dump help") 299 | parser.add_argument("--cable", dest="cable", default=None, help="Specify cable") 300 | parser.add_argument("--chip", dest="chip", default=None, help="Specify target chip") 301 | parser.add_argument("--binary", dest="binaries", default=[], action="append", help="Specify a binary to be loaded by the load command") 302 | parser.add_argument("--flash-image", dest="fimages", default=[], action="append", help="Specify a flash image to be flashed") 303 | parser.add_argument("--flash-type", dest="flash_type", default="hyperflash", help="Specify flash type") 304 | parser.add_argument("--config-opt", dest="configOpt", default=[], action="append", help='specify configuration option') 305 | 306 | [args, otherArgs] = parser.parse_known_args() 307 | 308 | if 'read' in args.command or 'write' in args.command: 309 | parser.add_argument("--addr", dest="addr", default=None, help="Specify the address of the access for read and write commands") 310 | parser.add_argument("--size", dest="size", default="4", help="Specify the size of the access for read and write commands") 311 | 312 | opt_flasher_init = False 313 | 314 | if 'efuse_write' in args.command: 315 | opt_flasher_init = True 316 | parser.add_argument("--addr", dest="addr", default=None, help="Specify the address of the access for read and write commands") 317 | parser.add_argument("--value", dest="value", default=None, help="Specify the value to be written for write command") 318 | parser.add_argument("--mask", dest="mask", default="0xffffffff", help="Specify the mask used to select which bit is written") 319 | 320 | if 'read' in args.command: 321 | parser.add_argument("--width", dest="width", default=1, type=int, help="Specify the word size in bytes used to display numbers for read commands") 322 | 323 | if 'write' in args.command: 324 | parser.add_argument("--value", dest="value", default=None, help="Specify the value to be written for write command") 325 | 326 | if 'eeprom_write' in args.command or 'flash_write' in args.command or 'flash_read' in args.command: 327 | parser.add_argument("--file", dest="file", default=None, help="The file to be written for eeprom_write command") 328 | parser.add_argument("--addr", dest="addr", default=None, help="Specify the address of the access for read and write commands") 329 | opt_flasher_init = True 330 | 331 | if 'flash_read' in args.command or 'flash_erase' in args.command: 332 | parser.add_argument("--size", dest="size", default="4", help="Specify the size of the access for read and write commands") 333 | 334 | if 'flash_erase_sector' in args.command or 'flash_erase' in args.command: 335 | parser.add_argument("--addr", dest="addr", default=None, help="Specify the address of the access for read and write commands") 336 | opt_flasher_init = True 337 | 338 | if 'flash_erase_chip' in args.command: 339 | opt_flasher_init = True 340 | 341 | if 'gdb' in args.command: 342 | parser.add_argument("--rsp-port", dest="rsp_port", default=1234, help="Specify the port number that the RSP will use to open a socket for GDB connection") 343 | 344 | if opt_flasher_init: 345 | parser.add_argument("--flasher-init", dest="flasher_init", action="store_true", default=True, help="Initialize flasher") 346 | parser.add_argument("--no-flasher-init", dest="flasher_init", action="store_false", default=True, help="Initialize flasher") 347 | 348 | 349 | parser.add_argument("--boot-mode", dest="boot_mode", default=None, help="Specify the boot mode") 350 | 351 | args = parser.parse_args() 352 | 353 | if args.help: 354 | parser.print_help() 355 | exit(0) 356 | 357 | 358 | 359 | config_path = args.config_path 360 | config_name = args.config 361 | 362 | 363 | if config_name is not None: 364 | config_path = os.path.join( 365 | os.path.dirname(os.path.dirname(sys.argv[0])), 366 | 'configs', 'config', '%s.json' % config_name 367 | ) 368 | 369 | elif args.chip is not None: 370 | config_path = os.path.join( 371 | os.path.dirname(os.path.dirname(sys.argv[0])), 372 | 'configs', 'chips', args.chip, '%s.json' % args.chip 373 | ) 374 | 375 | if not os.path.exists(config_path): 376 | print ("ERROR, didn't find any configuration for specified chip (chip: %s, config: %s)" % (args.chip, config_path)) 377 | exit(-1) 378 | 379 | elif config_path is None: 380 | raise Exception('A chip or a config file must be specified') 381 | 382 | config = plpconf.get_config(config_path, config_opts=args.configOpt, interpret=True) 383 | 384 | 385 | # And overloads it with the specified options 386 | if args.boot_mode is not None: 387 | if config.get('**/debug_bridge') is None: 388 | config.set('debug_bridge', {}) 389 | 390 | config.get('**/debug_bridge').set('boot-mode', args.boot_mode) 391 | 392 | cable = os.environ.get('PLPBRIDGE_CABLE') 393 | if cable is not None and args.cable is not None: 394 | print ('Overwriting --cable option with PLPBRIDGE_CABLE: %s' % cable) 395 | args.cable = cable 396 | 397 | if args.cable is not None: 398 | if config.get('**/debug_bridge') is None: 399 | config.set('debug_bridge', {}) 400 | 401 | config.get('**/debug_bridge').set('cable/type', args.cable) 402 | 403 | if args.port is not None: 404 | if config.get('**/debug_bridge') is None: 405 | config.set('debug_bridge', {}) 406 | 407 | if config.get('**/debug_bridge/cable') is None: 408 | config.get('**/debug_bridge').set('cable', {}) 409 | 410 | if config.get('**/debug_bridge/cable/jtag-proxy') is None: 411 | config.get('**/debug_bridge/cable').set('jtag-proxy', {}) 412 | 413 | config.get('**/debug_bridge/cable/jtag-proxy').set('port', args.port) 414 | 415 | for binary in args.binaries: 416 | if config.get('**/runner') is None: 417 | config.set('runner', {}) 418 | 419 | if config.get('**/runner/binaries') is None: 420 | config.get('**/runner').set('binaries', []) 421 | 422 | config.get('**/runner').set('binaries', binary) 423 | 424 | 425 | 426 | 427 | if len(args.command) == 0: 428 | json_commands = config.get('**/debug_bridge/commands') 429 | if json_commands is not None: 430 | args.command = json_commands.get().split() 431 | 432 | 433 | binaries = [] 434 | binaries_conf = config.get('**/runner/binaries') 435 | if binaries_conf is not None: 436 | binaries = binaries_conf.get_dict() 437 | 438 | bridge = db.get_bridge(config=config, verbose=args.verbose, binaries=binaries) 439 | 440 | if args.ipython: 441 | embed() 442 | 443 | if args.shell: 444 | code.interact(local=locals()) 445 | 446 | #bridge.exec_config() 447 | 448 | 449 | 450 | 451 | 452 | def handle_commands(bridge): 453 | if len(args.command) == 0: 454 | parser.print_help() 455 | exit(0) 456 | 457 | else: 458 | for cmd in args.command: 459 | 460 | if commands.get(cmd) is None: 461 | fatal_error('Unknown command: ' + cmd) 462 | exit(1) 463 | else: 464 | try: 465 | if commands.get(cmd)[1](bridge) != 0: 466 | print () 467 | fatal_error('the command \'%s\' has failed' % (cmd)) 468 | exit(1) 469 | except Exception as e: 470 | fatal_error('the command \'%s\' has failed with an exception: %s' % (cmd, e)) 471 | if args.debug: 472 | raise 473 | exit(1) 474 | 475 | 476 | 477 | 478 | 479 | handle_commands(bridge) 480 | -------------------------------------------------------------------------------- /include/debug_bridge/debug_bridge.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 19 | */ 20 | 21 | #ifndef __DEBUG_BRIDGE_DEBUG_BRIDGE_H__ 22 | #define __DEBUG_BRIDGE_DEBUG_BRIDGE_H__ 23 | 24 | #define PROTOCOL_VERSION_0 0 // Initial version 25 | #define PROTOCOL_VERSION_1 1 // Added runtime / bridge state synchronization 26 | #define PROTOCOL_VERSION_2 2 // Added bridge to runtime requests 27 | #define PROTOCOL_VERSION_3 3 // Added field "connected" in target state to allow bridge to reconnect several times 28 | #define PROTOCOL_VERSION_4 4 // Added field "bridge_to_target" in requests as they are now released by the target 29 | 30 | #define HAL_PRINTF_BUF_SIZE 128 31 | 32 | typedef enum { 33 | HAL_BRIDGE_REQ_CONNECT = 0, 34 | HAL_BRIDGE_REQ_DISCONNECT = 1, 35 | HAL_BRIDGE_REQ_OPEN = 2, 36 | HAL_BRIDGE_REQ_READ = 3, 37 | HAL_BRIDGE_REQ_WRITE = 4, 38 | HAL_BRIDGE_REQ_CLOSE = 5, 39 | HAL_BRIDGE_REQ_FB_OPEN = 6, 40 | HAL_BRIDGE_REQ_FB_UPDATE = 7, 41 | HAL_BRIDGE_REQ_TARGET_STATUS_SYNC = 8, 42 | HAL_BRIDGE_REQ_REPLY = 9, 43 | HAL_BRIDGE_TARGET_REQ_EFUSE_ACCESS = 10, 44 | HAL_BRIDGE_TARGET_REQ_EEPROM_ACCESS = 11, 45 | HAL_BRIDGE_TARGET_REQ_BUFFER_ALLOC = 12, 46 | HAL_BRIDGE_TARGET_REQ_BUFFER_FREE = 13, 47 | HAL_BRIDGE_TARGET_REQ_FLASH_ACCESS = 14, 48 | HAL_BRIDGE_TARGET_REQ_FLASH_ERASE_CHIP = 15, 49 | HAL_BRIDGE_TARGET_REQ_FLASH_ERASE_SECTOR = 16, 50 | HAL_BRIDGE_TARGET_REQ_FLASH_ERASE = 17, 51 | HAL_BRIDGE_REQ_FIRST_USER = 18 52 | } hal_bridge_req_e; 53 | 54 | typedef enum { 55 | HAL_BRIDGE_REQ_FB_FORMAT_GRAY = 1, 56 | HAL_BRIDGE_REQ_FB_FORMAT_RGB = 2, 57 | HAL_BRIDGE_REQ_FB_FORMAT_RAW = 3 58 | } hal_bridge_fb_format_e; 59 | 60 | typedef struct hal_bridge_req_s { 61 | uint64_t bridge_data; 62 | uint32_t next; 63 | uint32_t size; 64 | uint32_t type; 65 | uint32_t done; 66 | uint32_t popped; 67 | uint32_t bridge_to_target; 68 | union { 69 | struct { 70 | uint32_t name_len; 71 | uint32_t name; 72 | uint32_t flags; 73 | uint32_t mode; 74 | uint32_t retval; 75 | } open; 76 | struct { 77 | uint32_t file; 78 | uint32_t retval; 79 | } close; 80 | struct { 81 | uint32_t file; 82 | uint32_t ptr; 83 | uint32_t len; 84 | uint32_t retval; 85 | } read; 86 | struct { 87 | uint32_t file; 88 | uint32_t ptr; 89 | uint32_t len; 90 | uint32_t retval; 91 | } write; 92 | struct { 93 | uint64_t screen; 94 | uint32_t name_len; 95 | uint32_t name; 96 | uint32_t width; 97 | uint32_t height; 98 | uint32_t format; 99 | } fb_open; 100 | struct { 101 | uint64_t screen; 102 | uint32_t addr; 103 | uint32_t posx; 104 | uint32_t posy; 105 | uint32_t width; 106 | uint32_t height; 107 | } fb_update; 108 | struct { 109 | uint32_t is_write; 110 | uint32_t index; 111 | uint32_t value; 112 | uint32_t mask; 113 | } efuse_access; 114 | struct { 115 | uint8_t itf; 116 | uint8_t cs; 117 | uint8_t is_write; 118 | uint8_t padding; 119 | uint32_t addr; 120 | uint32_t buffer; 121 | uint32_t size; 122 | uint32_t retval; 123 | } eeprom_access; 124 | struct { 125 | uint8_t type; 126 | uint8_t itf; 127 | uint8_t cs; 128 | uint8_t is_write; 129 | uint32_t addr; 130 | uint32_t buffer; 131 | uint32_t size; 132 | uint32_t retval; 133 | } flash_access; 134 | struct { 135 | uint8_t type; 136 | uint8_t itf; 137 | uint8_t cs; 138 | uint8_t padding; 139 | uint32_t retval; 140 | } flash_erase_chip; 141 | struct { 142 | uint8_t type; 143 | uint8_t itf; 144 | uint8_t cs; 145 | uint8_t padding; 146 | uint32_t addr; 147 | uint32_t retval; 148 | } flash_erase_sector; 149 | struct { 150 | uint8_t type; 151 | uint8_t itf; 152 | uint8_t cs; 153 | uint8_t padding; 154 | uint32_t addr; 155 | uint32_t size; 156 | uint32_t retval; 157 | } flash_erase; 158 | struct { 159 | uint32_t size; 160 | uint32_t buffer; 161 | } buffer_alloc; 162 | struct { 163 | uint32_t size; 164 | uint32_t buffer; 165 | } buffer_free; 166 | struct { 167 | } target_status_sync; 168 | }; 169 | } hal_bridge_req_t; 170 | 171 | typedef struct { 172 | volatile int32_t connected; 173 | } __attribute__((packed)) hal_target_state_t; 174 | 175 | typedef struct { 176 | // The bridge will set it to one when it finds the debug struct to notify 177 | // the target that the bridge is present. 178 | volatile int32_t connected; 179 | } __attribute__((packed)) hal_bridge_state_t; 180 | 181 | // This structure can be used to interact with the host loader 182 | typedef struct { 183 | 184 | uint32_t protocol_version; 185 | 186 | hal_target_state_t target; 187 | 188 | hal_bridge_state_t bridge; 189 | 190 | // Used by external debug bridge to get exit status when using the board 191 | uint32_t exit_status; 192 | 193 | // Printf 194 | uint32_t use_internal_printf; 195 | uint32_t pending_putchar; 196 | uint32_t putc_current; 197 | uint8_t putc_buffer[HAL_PRINTF_BUF_SIZE]; 198 | 199 | // Debug step, used for showing progress to host loader 200 | uint32_t debug_step; 201 | uint32_t debug_step_pending; 202 | 203 | // Requests 204 | uint32_t first_req; 205 | uint32_t last_req; 206 | uint32_t first_bridge_req; 207 | uint32_t first_bridge_free_req; 208 | uint32_t target_req; 209 | 210 | uint32_t notif_req_addr; 211 | uint32_t notif_req_value; 212 | 213 | } __attribute__((packed)) hal_debug_struct_t; 214 | 215 | #endif -------------------------------------------------------------------------------- /include/debug_bridge/proxy.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 19 | */ 20 | 21 | #ifndef __DEBUG_BRIDGE_PROXY_HPP__ 22 | #define __DEBUG_BRIDGE_PROXY_HPP__ 23 | 24 | #include 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | typedef enum { 31 | DEBUG_BRIDGE_JTAG_REQ = 0, 32 | DEBUG_BRIDGE_RESET_REQ = 1, 33 | DEBUG_BRIDGE_CONFIG_REQ = 2 34 | } proxy_req_type_e; 35 | 36 | typedef enum { 37 | DEBUG_BRIDGE_JTAG_TDI = 0, 38 | DEBUG_BRIDGE_JTAG_TMS = 1, 39 | DEBUG_BRIDGE_JTAG_TRST = 2 40 | } proxy_req_jtag_cycle_e; 41 | 42 | typedef struct { 43 | int32_t type; 44 | 45 | union { 46 | struct { 47 | int32_t bits; 48 | int8_t tdo; 49 | } jtag; 50 | struct { 51 | int32_t active; 52 | int32_t duration; 53 | } reset; 54 | struct { 55 | int32_t value; 56 | } config; 57 | }; 58 | 59 | } proxy_req_t; 60 | 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | 66 | #endif -------------------------------------------------------------------------------- /python/bridge/chips/arnold.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | import time 21 | 22 | JTAG_SOC_AXIREG = 4 23 | 24 | JTAG_SOC_CONFREG = 7 25 | JTAG_SOC_CONFREG_WIDTH = 9 26 | 27 | BOOT_MODE_JTAG = 1 28 | BOOT_MODE_JTAG_HYPER = 11 29 | CONFREG_BOOT_WAIT = 1 30 | CONFREG_PGM_LOADED = 1 31 | CONFREG_INIT = 0 32 | 33 | class arnold_debug_bridge(debug_bridge): 34 | 35 | def __init__(self, config, binaries=[], verbose=False, fimages=[]): 36 | super(arnold_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 37 | 38 | self.fimages = fimages 39 | self.start_cores = False 40 | 41 | def stop(self): 42 | 43 | # Reset the chip and tell him we want to load via jtag 44 | # We keep the reset active until the end so that it sees 45 | # the boot mode as soon as it boots from rom 46 | if self.verbose: 47 | print ("Notifying to boot code that we are doing a JTAG boot") 48 | self.get_cable().jtag_reset(True) 49 | self.get_cable().jtag_reset(False) 50 | self.get_cable().chip_reset(True) 51 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (BOOT_MODE_JTAG << 1) | 1) 52 | self.get_cable().chip_reset(False) 53 | 54 | 55 | # Now wait until the boot code tells us we can load the code 56 | if self.verbose: 57 | print ("Waiting for notification from boot code") 58 | while True: 59 | reg_value = self.get_cable().jtag_get_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (BOOT_MODE_JTAG << 1) | 1) 60 | if reg_value == CONFREG_BOOT_WAIT: 61 | break 62 | print ("Received for notification from boot code") 63 | 64 | # Stall the FC 65 | self.write(0x1A110000, 4, [0, 0, 1, 0]) 66 | 67 | print ("Stopped core") 68 | 69 | return 0 70 | 71 | def reset(self): 72 | self.stop() 73 | return 0 74 | 75 | 76 | def load_jtag(self, binaries): 77 | 78 | if self.verbose: 79 | print ('Loading binary through jtag') 80 | 81 | if self.stop() != 0: 82 | return -1 83 | 84 | # Load the binary through jtag 85 | if self.verbose: 86 | print ("Loading binaries") 87 | for binary in binaries: 88 | if self.load_elf(binary=binary): 89 | return 1 90 | 91 | # Be careful to set the new PC only after the code is loaded as the prefetch 92 | # buffer is immediately fetching instructions and would get wrong instructions 93 | self.write(0x1A112000, 4, [0x80, 0x80, 0x00, 0x1c]) 94 | 95 | self.start_cores = True 96 | 97 | return 0 98 | 99 | 100 | def start(self): 101 | 102 | if self.start_cores: 103 | print ('Starting execution') 104 | 105 | # Unstall the FC so that it starts fetching instructions from the loaded binary 106 | self.write(0x1A110000, 4, [0, 0, 0, 0]) 107 | 108 | return 0 109 | -------------------------------------------------------------------------------- /python/bridge/chips/fulmine.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | 21 | 22 | class fulmine_debug_bridge(debug_bridge): 23 | 24 | def __init__(self, config, binaries=[], verbose=False): 25 | super(fulmine_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 26 | 27 | # We have to use the soc tap on fulmine 28 | if config.get('**/debug_bridge/cable/tap') is not None: 29 | config.get('**/debug_bridge/cable').set('tap', 1) 30 | 31 | def start(self): 32 | self.write_32(0x10200008, 0x1) 33 | return 0 34 | -------------------------------------------------------------------------------- /python/bridge/chips/gap.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | import time 21 | 22 | JTAG_SOC_AXIREG = 4 23 | 24 | JTAG_SOC_CONFREG = 7 25 | JTAG_SOC_CONFREG_WIDTH = 4 26 | 27 | BOOT_MODE_JTAG = 4 28 | BOOT_MODE_JTAG_HYPER = 11 29 | CONFREG_BOOT_WAIT = 1 30 | CONFREG_PGM_LOADED = 1 31 | CONFREG_INIT = 0 32 | 33 | class gap_debug_bridge(debug_bridge): 34 | 35 | def __init__(self, config, binaries=[], verbose=False, fimages=[]): 36 | super(gap_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 37 | 38 | self.fimages = fimages 39 | self.start_cores = False 40 | 41 | def stop(self): 42 | 43 | 44 | # Reset the chip and tell him we want to load via jtag 45 | # We keep the reset active until the end so that it sees 46 | # the boot mode as soon as it boots from rom 47 | if self.verbose: 48 | print ("Notifying to boot code that we are doing a JTAG boot") 49 | self.get_cable().chip_reset(True) 50 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, BOOT_MODE_JTAG) 51 | self.get_cable().chip_reset(False) 52 | 53 | # Removed synchronization with boot code due to HW bug, it is better 54 | # to stop fc as soon as possible 55 | 56 | # # Now wait until the boot code tells us we can load the code 57 | # if self.verbose: 58 | # print ("Waiting for notification from boot code") 59 | # while True: 60 | # reg_value = self.get_cable().jtag_get_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, BOOT_MODE_JTAG) 61 | # if reg_value == CONFREG_BOOT_WAIT: 62 | # break 63 | # print ("Received for notification from boot code") 64 | 65 | # Stall the FC 66 | self.write(0x1B300000, 4, [0, 0, 1, 0]) 67 | 68 | # Configure FLL with no lock to avoid the HW bug with fll 69 | #self.write_32(0x1a100004, 0x840005f5) 70 | #self.write_32(0x1a100008, 0x8100410b) 71 | 72 | return 0 73 | 74 | 75 | def load_jtag(self, binaries): 76 | 77 | if self.verbose: 78 | print ('Loading binary through jtag') 79 | 80 | if self.stop() != 0: 81 | return -1 82 | 83 | # Load the binary through jtag 84 | if self.verbose: 85 | print ("Loading binaries") 86 | for binary in binaries: 87 | if self.load_elf(binary=binary): 88 | return 1 89 | 90 | with open(binaries[0], 'rb') as file: 91 | entry = ELFFile(file).header['e_entry'] 92 | # Be careful to set the new PC only after the code is loaded as the prefetch 93 | # buffer is immediately fetching instructions and would get wrong instructions 94 | self.write_32(0x1B302000, entry) 95 | 96 | self.start_cores = True 97 | 98 | return 0 99 | 100 | 101 | def start(self): 102 | 103 | if self.start_cores: 104 | print ('Starting execution') 105 | 106 | # Unstall the FC so that it starts fetching instructions from the loaded binary 107 | self.write(0x1B300000, 4, [0, 0, 0, 0]) 108 | 109 | return 0 110 | 111 | 112 | def load_jtag_hyper(self, binaries): 113 | 114 | if self.verbose: 115 | print ('Loading binary through jtag_hyper') 116 | 117 | # Reset the chip and tell him we want to load from hyper 118 | # We keep the reset active until the end so that it sees 119 | # the boot mode as soon as it boots from rom 120 | if self.verbose: 121 | print ("Notifying to boot code that we are doing a JTAG boot from hyperflash") 122 | self.get_cable().chip_reset(True) 123 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, BOOT_MODE_JTAG_HYPER) 124 | self.get_cable().chip_reset(False) 125 | 126 | return 0 127 | 128 | 129 | def flash(self, fimages): 130 | MAX_BUFF_SIZE = (350*1024) 131 | f_path = fimages[0] 132 | addrHeader = self._get_binary_symbol_addr('flasherHeader') 133 | addrImgRdy = addrHeader 134 | addrFlasherRdy = addrHeader + 4 135 | addrFlashAddr = addrHeader + 8 136 | addrIterTime = addrHeader + 12 137 | addrBufSize = addrHeader + 16 138 | # open the file in read binary mode 139 | f_img = open(f_path, 'rb') 140 | f_size = os.path.getsize(f_path) 141 | lastSize = f_size % MAX_BUFF_SIZE; 142 | if(lastSize): 143 | n_iter = f_size // MAX_BUFF_SIZE + 1; 144 | else: 145 | n_iter = f_size // MAX_BUFF_SIZE 146 | 147 | flasher_ready = self.read_32(addrFlasherRdy) 148 | while(flasher_ready == 0): 149 | flasher_ready = self.read_32(addrFlasherRdy) 150 | flasher_ready = 0; 151 | addrBuffer = self.read_32((addrHeader+20)) 152 | indexAddr = 0 153 | self.write_32(addrFlashAddr, 0) 154 | self.write_32(addrIterTime, n_iter) 155 | for i in range(n_iter): 156 | if (lastSize and i == (n_iter-1)): 157 | buff_data = f_img.read(lastSize) 158 | self.write(addrBuffer, lastSize, buff_data) 159 | self.write_32(addrBufSize, ((lastSize + 3) & ~3)) 160 | else: 161 | buff_data = f_img.read(MAX_BUFF_SIZE) 162 | self.write(addrBuffer, MAX_BUFF_SIZE, buff_data) 163 | self.write_32(addrBufSize, MAX_BUFF_SIZE) 164 | self.write_32(addrImgRdy, 1) 165 | self.write_32(addrFlasherRdy, 0) 166 | if (i!=(n_iter-1)): 167 | flasher_ready = self.read_32(addrFlasherRdy) 168 | while(flasher_ready == 0): 169 | flasher_ready = self.read_32(addrFlasherRdy) 170 | f_img.close() 171 | return 0 172 | 173 | 174 | def load_jtag_old(self): 175 | 176 | if self.verbose: 177 | print ('Loading binary through jtag') 178 | 179 | # Reset the chip and tell him we want to load via jtag 180 | # We keep the reset active until the end so that it sees 181 | # the boot mode as soon as it boots from rom 182 | if self.verbose: 183 | print ("Notifying to boot code that we are doing a JTAG boot") 184 | self.get_cable().chip_reset(True) 185 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, BOOT_MODE_JTAG) 186 | self.get_cable().chip_reset(False) 187 | 188 | # Now wait until the boot code tells us we can load the code 189 | if self.verbose: 190 | print ("Waiting for notification from boot code") 191 | while True: 192 | reg_value = self.get_cable().jtag_get_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, BOOT_MODE_JTAG) 193 | if reg_value == CONFREG_BOOT_WAIT: 194 | break 195 | print ("Received for notification from boot code") 196 | 197 | 198 | # Load the binary through jtag 199 | if self.verbose: 200 | print ("Loading binaries") 201 | for binary in self.binaries: 202 | if self.load_elf(binary=binary): 203 | return 1 204 | 205 | return 0 206 | 207 | 208 | def start_old(self): 209 | 210 | # And notify the boot code that the binary is ready 211 | if self.verbose: 212 | print ("Notifying to boot code that the binary is loaded") 213 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, CONFREG_PGM_LOADED) 214 | 215 | return 0 216 | 217 | 218 | -------------------------------------------------------------------------------- /python/bridge/chips/gap8_revc.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | import time 21 | 22 | JTAG_SOC_AXIREG = 4 23 | 24 | JTAG_SOC_CONFREG = 7 25 | JTAG_SOC_CONFREG_WIDTH = 4 26 | 27 | BOOT_MODE_JTAG = 1 28 | BOOT_MODE_JTAG_HYPER = 11 29 | CONFREG_BOOT_WAIT = 1 30 | CONFREG_PGM_LOADED = 1 31 | CONFREG_INIT = 0 32 | 33 | class gap_debug_bridge(debug_bridge): 34 | 35 | def __init__(self, config, binaries=[], verbose=False, fimages=[]): 36 | super(gap_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 37 | 38 | self.fimages = fimages 39 | self.start_cores = False 40 | self.boot_mode = None 41 | self.stopped = False 42 | 43 | def reset(self, jtag_boot=True): 44 | self.get_cable().jtag_reset(True) 45 | self.get_cable().jtag_reset(False) 46 | self.get_cable().chip_reset(True) 47 | if jtag_boot: 48 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (BOOT_MODE_JTAG << 1) | 1) 49 | self.get_cable().chip_reset(False) 50 | return 0 51 | 52 | def set_boot_mode(self, boot_mode, reset=True): 53 | if self.verbose: 54 | print ("Notifying to boot code new boot mode (mode: %d)" % boot_mode) 55 | if reset: 56 | self.get_cable().chip_reset(True) 57 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (boot_mode << 1) | 1) 58 | 59 | if reset: 60 | self.get_cable().chip_reset(False) 61 | self.boot_mode = boot_mode 62 | 63 | def wait_available(self): 64 | if self.verbose: 65 | print ("Waiting for target to be available") 66 | 67 | boot_mode = 0 68 | if self.boot_mode is not None: 69 | boot_mode = (self.boot_mode << 1) | 1 70 | 71 | # Loop until we see bit 0 becoming 1, this will indicate that the 72 | # target is ready to accept bridge requests 73 | while True: 74 | reg_value = self.get_cable().jtag_get_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, boot_mode) 75 | 76 | rt_req = (reg_value >> 1) & 0x7 77 | 78 | if rt_req == 4 or rt_req == 1: 79 | break 80 | 81 | if self.verbose: 82 | print ("Target is available") 83 | 84 | 85 | def wait_ready(self, boot_mode=None): 86 | if boot_mode is None: 87 | boot_mode = self.boot_mode 88 | 89 | if boot_mode is None: 90 | print ('Can not wait for boot code if the boot mode is unknown') 91 | return -1 92 | 93 | if self.verbose: 94 | print ("Waiting for notification from boot code") 95 | while True: 96 | reg_value = self.get_cable().jtag_get_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (boot_mode << 1) | 1) 97 | 98 | if reg_value == CONFREG_BOOT_WAIT: 99 | break 100 | print ("Received for notification from boot code") 101 | 102 | return 0 103 | 104 | def stop(self): 105 | # Reset the chip and tell him we want to load via jtag 106 | # We keep the reset active until the end so that it sees 107 | # the boot mode as soon as it boots from rom 108 | self.set_boot_mode(BOOT_MODE_JTAG) 109 | 110 | # Now wait until the boot code tells us we can load the code 111 | if self.wait_ready() != 0: 112 | return -1 113 | 114 | # Stall the FC 115 | self.write(0x1B300000, 4, [0, 0, 1, 0]) 116 | 117 | self.stopped = True 118 | 119 | return 0 120 | 121 | def pause_for_conf(self): 122 | self.set_boot_mode(4) 123 | if self.wait_ready() != 0: 124 | return -1 125 | return 0 126 | 127 | def resume_after_conf(self, boot_mode): 128 | self.set_boot_mode(5, reset=False) 129 | while True: 130 | reg_value = self.get_cable().jtag_get_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (5 << 1) | 1) 131 | if (reg_value & 1) == 0: 132 | break 133 | 134 | self.set_boot_mode(boot_mode, reset=False) 135 | 136 | return 0 137 | 138 | def clear(self): 139 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, 0) 140 | self.boot_mode = None 141 | 142 | 143 | def load_jtag(self, binaries): 144 | 145 | if self.verbose: 146 | print ('Loading binary through jtag') 147 | 148 | if self.stop() != 0: 149 | return -1 150 | 151 | # Load the binary through jtag 152 | if self.verbose: 153 | print ("Loading binaries") 154 | for binary in binaries: 155 | if self.load_elf(binary=binary): 156 | return 1 157 | 158 | # Be careful to set the new PC only after the code is loaded as the prefetch 159 | # buffer is immediately fetching instructions and would get wrong instructions 160 | self.write(0x1B302000, 4, [0x80, 0x00, 0x00, 0x1c]) 161 | 162 | self.start_cores = True 163 | 164 | return 0 165 | 166 | 167 | def start(self): 168 | 169 | if self.start_cores: 170 | print ('Starting execution') 171 | 172 | # Unstall the FC so that it starts fetching instructions from the loaded binary 173 | self.write(0x1B300000, 4, [0, 0, 0, 0]) 174 | 175 | return 0 176 | 177 | 178 | def load_jtag_hyper(self, binaries): 179 | 180 | if self.verbose: 181 | print ('Loading binary through jtag_hyper') 182 | 183 | # Reset the chip and tell him we want to load from hyper 184 | # We keep the reset active until the end so that it sees 185 | # the boot mode as soon as it boots from rom 186 | if self.verbose: 187 | print ("Notifying to boot code that we are doing a JTAG boot from hyperflash") 188 | self.get_cable().chip_reset(True) 189 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, BOOT_MODE_JTAG_HYPER) 190 | self.get_cable().chip_reset(False) 191 | 192 | return 0 193 | 194 | 195 | def flash(self, fimages): 196 | MAX_BUFF_SIZE = (350*1024) 197 | f_path = fimages[0] 198 | addrHeader = self._get_binary_symbol_addr('flasherHeader') 199 | addrImgRdy = addrHeader 200 | addrFlasherRdy = addrHeader + 4 201 | addrFlashAddr = addrHeader + 8 202 | addrIterTime = addrHeader + 12 203 | addrBufSize = addrHeader + 16 204 | # open the file in read binary mode 205 | f_img = open(f_path, 'rb') 206 | f_size = os.path.getsize(f_path) 207 | lastSize = f_size % MAX_BUFF_SIZE; 208 | if(lastSize): 209 | n_iter = f_size // MAX_BUFF_SIZE + 1; 210 | else: 211 | n_iter = f_size // MAX_BUFF_SIZE 212 | 213 | flasher_ready = self.read_32(addrFlasherRdy) 214 | while(flasher_ready == 0): 215 | flasher_ready = self.read_32(addrFlasherRdy) 216 | flasher_ready = 0; 217 | addrBuffer = self.read_32((addrHeader+20)) 218 | indexAddr = 0 219 | self.write_32(addrFlashAddr, 0) 220 | self.write_32(addrIterTime, n_iter) 221 | for i in range(n_iter): 222 | if (lastSize and i == (n_iter-1)): 223 | buff_data = f_img.read(lastSize) 224 | self.write(addrBuffer, lastSize, buff_data) 225 | self.write_32(addrBufSize, ((lastSize + 3) & ~3)) 226 | else: 227 | buff_data = f_img.read(MAX_BUFF_SIZE) 228 | self.write(addrBuffer, MAX_BUFF_SIZE, buff_data) 229 | self.write_32(addrBufSize, MAX_BUFF_SIZE) 230 | self.write_32(addrImgRdy, 1) 231 | self.write_32(addrFlasherRdy, 0) 232 | if (i!=(n_iter-1)): 233 | flasher_ready = self.read_32(addrFlasherRdy) 234 | while(flasher_ready == 0): 235 | flasher_ready = self.read_32(addrFlasherRdy) 236 | f_img.close() 237 | return 0 238 | -------------------------------------------------------------------------------- /python/bridge/chips/gap_rev1.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | import time 21 | 22 | JTAG_SOC_AXIREG = 4 23 | 24 | JTAG_SOC_CONFREG = 7 25 | JTAG_SOC_CONFREG_WIDTH = 4 26 | 27 | BOOT_MODE_JTAG = 1 28 | BOOT_MODE_JTAG_HYPER = 11 29 | CONFREG_BOOT_WAIT = 1 30 | CONFREG_PGM_LOADED = 1 31 | CONFREG_INIT = 0 32 | 33 | class gap_debug_bridge(debug_bridge): 34 | 35 | def __init__(self, config, binaries=[], verbose=False, fimages=[]): 36 | super(gap_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 37 | 38 | self.fimages = fimages 39 | self.start_cores = False 40 | self.boot_mode = None 41 | self.stopped = False 42 | 43 | def reset(self, jtag_boot=True): 44 | self.get_cable().jtag_reset(True) 45 | self.get_cable().jtag_reset(False) 46 | self.get_cable().chip_reset(True) 47 | if jtag_boot: 48 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (BOOT_MODE_JTAG << 1) | 1) 49 | self.get_cable().chip_reset(False) 50 | return 0 51 | 52 | def set_boot_mode(self, boot_mode, reset=True): 53 | if self.verbose: 54 | print ("Notifying to boot code new boot mode (mode: %d)" % boot_mode) 55 | if reset: 56 | self.get_cable().chip_reset(True) 57 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (boot_mode << 1) | 1) 58 | 59 | if reset: 60 | self.get_cable().chip_reset(False) 61 | self.boot_mode = boot_mode 62 | 63 | def wait_available(self): 64 | if self.verbose: 65 | print ("Waiting for target to be available") 66 | 67 | boot_mode = 0 68 | if self.boot_mode is not None: 69 | boot_mode = (self.boot_mode << 1) | 1 70 | 71 | # Loop until we see bit 0 becoming 1, this will indicate that the 72 | # target is ready to accept bridge requests 73 | while True: 74 | reg_value = self.get_cable().jtag_get_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, boot_mode) 75 | 76 | rt_req = (reg_value >> 1) & 0x7 77 | 78 | if rt_req == 4 or rt_req == 1: 79 | break 80 | 81 | if self.verbose: 82 | print ("Target is available") 83 | 84 | 85 | def wait_ready(self, boot_mode=None): 86 | if boot_mode is None: 87 | boot_mode = self.boot_mode 88 | 89 | if boot_mode is None: 90 | print ('Can not wait for boot code if the boot mode is unknown') 91 | return -1 92 | 93 | if self.verbose: 94 | print ("Waiting for notification from boot code") 95 | while True: 96 | reg_value = self.get_cable().jtag_get_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (boot_mode << 1) | 1) 97 | 98 | if reg_value == CONFREG_BOOT_WAIT: 99 | break 100 | print ("Received for notification from boot code") 101 | 102 | return 0 103 | 104 | def stop(self): 105 | # Reset the chip and tell him we want to load via jtag 106 | # We keep the reset active until the end so that it sees 107 | # the boot mode as soon as it boots from rom 108 | self.set_boot_mode(BOOT_MODE_JTAG) 109 | 110 | # Now wait until the boot code tells us we can load the code 111 | if self.wait_ready() != 0: 112 | return -1 113 | 114 | # Stall the FC 115 | self.write(0x1B300000, 4, [0, 0, 1, 0]) 116 | 117 | self.stopped = True 118 | 119 | return 0 120 | 121 | def pause_for_conf(self): 122 | self.set_boot_mode(4) 123 | if self.wait_ready() != 0: 124 | return -1 125 | return 0 126 | 127 | def resume_after_conf(self, boot_mode): 128 | self.set_boot_mode(5, reset=False) 129 | while True: 130 | reg_value = self.get_cable().jtag_get_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (5 << 1) | 1) 131 | if (reg_value & 1) == 0: 132 | break 133 | 134 | self.set_boot_mode(boot_mode, reset=False) 135 | 136 | return 0 137 | 138 | def clear(self): 139 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, 0) 140 | self.boot_mode = None 141 | 142 | 143 | def load_jtag(self, binaries): 144 | 145 | if self.verbose: 146 | print ('Loading binary through jtag') 147 | 148 | if self.stop() != 0: 149 | return -1 150 | 151 | # Load the binary through jtag 152 | if self.verbose: 153 | print ("Loading binaries") 154 | for binary in binaries: 155 | if self.load_elf(binary=binary): 156 | return 1 157 | 158 | # Be careful to set the new PC only after the code is loaded as the prefetch 159 | # buffer is immediately fetching instructions and would get wrong instructions 160 | self.write(0x1B302000, 4, [0x80, 0x00, 0x00, 0x1c]) 161 | 162 | self.start_cores = True 163 | 164 | return 0 165 | 166 | 167 | def start(self): 168 | 169 | if self.start_cores: 170 | print ('Starting execution') 171 | 172 | # Unstall the FC so that it starts fetching instructions from the loaded binary 173 | self.write(0x1B300000, 4, [0, 0, 0, 0]) 174 | 175 | return 0 176 | 177 | 178 | def load_jtag_hyper(self, binaries): 179 | 180 | if self.verbose: 181 | print ('Loading binary through jtag_hyper') 182 | 183 | # Reset the chip and tell him we want to load from hyper 184 | # We keep the reset active until the end so that it sees 185 | # the boot mode as soon as it boots from rom 186 | if self.verbose: 187 | print ("Notifying to boot code that we are doing a JTAG boot from hyperflash") 188 | self.get_cable().chip_reset(True) 189 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, BOOT_MODE_JTAG_HYPER) 190 | self.get_cable().chip_reset(False) 191 | 192 | return 0 193 | 194 | 195 | def flash(self, fimages): 196 | MAX_BUFF_SIZE = (350*1024) 197 | f_path = fimages[0] 198 | addrHeader = self._get_binary_symbol_addr('flasherHeader') 199 | addrImgRdy = addrHeader 200 | addrFlasherRdy = addrHeader + 4 201 | addrFlashAddr = addrHeader + 8 202 | addrIterTime = addrHeader + 12 203 | addrBufSize = addrHeader + 16 204 | # open the file in read binary mode 205 | f_img = open(f_path, 'rb') 206 | f_size = os.path.getsize(f_path) 207 | lastSize = f_size % MAX_BUFF_SIZE; 208 | if(lastSize): 209 | n_iter = f_size // MAX_BUFF_SIZE + 1; 210 | else: 211 | n_iter = f_size // MAX_BUFF_SIZE 212 | 213 | flasher_ready = self.read_32(addrFlasherRdy) 214 | while(flasher_ready == 0): 215 | flasher_ready = self.read_32(addrFlasherRdy) 216 | flasher_ready = 0; 217 | addrBuffer = self.read_32((addrHeader+20)) 218 | indexAddr = 0 219 | self.write_32(addrFlashAddr, 0) 220 | self.write_32(addrIterTime, n_iter) 221 | for i in range(n_iter): 222 | if (lastSize and i == (n_iter-1)): 223 | buff_data = f_img.read(lastSize) 224 | self.write(addrBuffer, lastSize, buff_data) 225 | self.write_32(addrBufSize, ((lastSize + 3) & ~3)) 226 | else: 227 | buff_data = f_img.read(MAX_BUFF_SIZE) 228 | self.write(addrBuffer, MAX_BUFF_SIZE, buff_data) 229 | self.write_32(addrBufSize, MAX_BUFF_SIZE) 230 | self.write_32(addrImgRdy, 1) 231 | self.write_32(addrFlasherRdy, 0) 232 | if (i!=(n_iter-1)): 233 | flasher_ready = self.read_32(addrFlasherRdy) 234 | while(flasher_ready == 0): 235 | flasher_ready = self.read_32(addrFlasherRdy) 236 | f_img.close() 237 | return 0 238 | -------------------------------------------------------------------------------- /python/bridge/chips/pulp.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | import time 21 | 22 | JTAG_RISCV_IRLEN = 5 23 | JTAG_RISCV_BYPASS = 0x1f 24 | 25 | JTAG_SOC_CONFREG_ID = 6 26 | JTAG_SOC_CONFREG = (JTAG_SOC_CONFREG_ID << 0) | (JTAG_RISCV_BYPASS << 4) 27 | JTAG_SOC_CONFREG_WIDTH = 8 + 1 28 | JTAG_SOC_IRLEN = 4 29 | 30 | JTAG_IRLEN = JTAG_SOC_IRLEN + JTAG_RISCV_IRLEN 31 | 32 | class pulp_debug_bridge(debug_bridge): 33 | 34 | def __init__(self, config, binaries=[], verbose=False): 35 | 36 | super(pulp_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 37 | 38 | def load_jtag(self, binaries): 39 | 40 | if self.verbose: 41 | print ('Loading binary through jtag') 42 | 43 | #if self.stop(): 44 | # return -1 45 | 46 | # Load the binary through jtag 47 | if self.verbose: 48 | print ("Loading binaries") 49 | for binary in binaries: 50 | if self.load_elf(binary=binary): 51 | return 1 52 | 53 | return 0 54 | 55 | 56 | def start(self): 57 | # First stall the core 58 | self.write_dmi(0x10, 0x00000001) # DMACTIVE 59 | 60 | self.write_dmi(0x10, 0x03E00001) # HART SEL 61 | self.write_dmi(0x10, 0x83E00001) # HALT REQ 62 | 63 | # Wait until it is halted 64 | while True: 65 | status = self.read_dmi(0x11) 66 | 67 | if ((status >> 9) & 1) == 1: 68 | break 69 | 70 | # Set PC 71 | self.write_dmi(0x04, 0x1c008080) # PC into DATA0 72 | self.write_dmi(0x17, 0x00230000 | 0x7b1) # Abstract cmd to set DPC 73 | 74 | # Resume the core 75 | self.write_dmi(0x10, 0x43E00001) 76 | 77 | return 0 78 | 79 | def write_dmi(self, reg, value): 80 | self.write_reg_int(reg, value, 4, 1) # DMACTIVE 81 | 82 | 83 | 84 | def read_dmi(self, reg): 85 | return self.read_reg_int(reg, 4, 1) # DMACTIVE 86 | -------------------------------------------------------------------------------- /python/bridge/chips/pulpissimo.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | import time 21 | 22 | JTAG_RISCV_IRLEN = 5 23 | JTAG_RISCV_BYPASS = 0x1f 24 | 25 | JTAG_SOC_CONFREG_ID = 6 26 | JTAG_SOC_CONFREG = (JTAG_SOC_CONFREG_ID << 0) | (JTAG_RISCV_BYPASS << 4) 27 | JTAG_SOC_CONFREG_WIDTH = 8 + 1 28 | JTAG_SOC_IRLEN = 4 29 | 30 | JTAG_IRLEN = JTAG_SOC_IRLEN + JTAG_RISCV_IRLEN 31 | 32 | class pulpissimo_debug_bridge(debug_bridge): 33 | 34 | def __init__(self, config, binaries=[], verbose=False): 35 | 36 | super(pulpissimo_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 37 | 38 | def load_jtag(self, binaries): 39 | 40 | if self.verbose: 41 | print ('Loading binary through jtag') 42 | 43 | #if self.stop(): 44 | # return -1 45 | 46 | # Load the binary through jtag 47 | if self.verbose: 48 | print ("Loading binaries") 49 | for binary in binaries: 50 | if self.load_elf(binary=binary): 51 | return 1 52 | 53 | return 0 54 | 55 | 56 | def start(self): 57 | # First stall the core 58 | self.write_dmi(0x10, 0x00000001) # DMACTIVE 59 | 60 | self.write_dmi(0x10, 0x03E00001) # HART SEL 61 | self.write_dmi(0x10, 0x83E00001) # HALT REQ 62 | 63 | # Wait until it is halted 64 | while True: 65 | status = self.read_dmi(0x11) 66 | 67 | if ((status >> 9) & 1) == 1: 68 | break 69 | 70 | # Set PC 71 | self.write_dmi(0x04, 0x1c008080) # PC into DATA0 72 | self.write_dmi(0x17, 0x00230000 | 0x7b1) # Abstract cmd to set DPC 73 | 74 | # Resume the core 75 | self.write_dmi(0x10, 0x43E00001) 76 | 77 | return 0 78 | 79 | def write_dmi(self, reg, value): 80 | self.write_reg_int(reg, value, 4, 1) # DMACTIVE 81 | 82 | 83 | 84 | def read_dmi(self, reg): 85 | return self.read_reg_int(reg, 4, 1) # DMACTIVE 86 | -------------------------------------------------------------------------------- /python/bridge/chips/pulpissimo_v2.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | import time 21 | 22 | JTAG_SOC_AXIREG = 4 23 | 24 | JTAG_SOC_CONFREG = 7 25 | JTAG_SOC_CONFREG_WIDTH = 9 26 | 27 | BOOT_MODE_JTAG = 1 28 | BOOT_MODE_JTAG_HYPER = 11 29 | CONFREG_BOOT_WAIT = 1 30 | CONFREG_PGM_LOADED = 1 31 | CONFREG_INIT = 0 32 | 33 | class pulpissimo_v2_debug_bridge(debug_bridge): 34 | 35 | def __init__(self, config, binaries=[], verbose=False, fimages=[]): 36 | super(pulpissimo_v2_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 37 | 38 | self.fimages = fimages 39 | self.start_cores = False 40 | 41 | def stop(self): 42 | 43 | # Reset the chip and tell him we want to load via jtag 44 | # We keep the reset active until the end so that it sees 45 | # the boot mode as soon as it boots from rom 46 | if self.verbose: 47 | print ("Notifying to boot code that we are doing a JTAG boot") 48 | self.get_cable().jtag_reset(True) 49 | self.get_cable().jtag_reset(False) 50 | self.get_cable().chip_reset(True) 51 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (BOOT_MODE_JTAG << 1) | 1) 52 | self.get_cable().chip_reset(False) 53 | 54 | 55 | # Now wait until the boot code tells us we can load the code 56 | if self.verbose: 57 | print ("Waiting for notification from boot code") 58 | while True: 59 | reg_value = self.get_cable().jtag_get_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, (BOOT_MODE_JTAG << 1) | 1) 60 | if reg_value == CONFREG_BOOT_WAIT: 61 | break 62 | print ("Received for notification from boot code") 63 | 64 | # Stall the FC 65 | self.write(0x1A110000, 4, [0, 0, 1, 0]) 66 | 67 | print ("Stopped core") 68 | 69 | return 0 70 | 71 | def reset(self): 72 | self.stop() 73 | return 0 74 | 75 | 76 | def load_jtag(self, binaries): 77 | 78 | if self.verbose: 79 | print ('Loading binary through jtag') 80 | 81 | if self.stop() != 0: 82 | return -1 83 | 84 | # Load the binary through jtag 85 | if self.verbose: 86 | print ("Loading binaries") 87 | for binary in binaries: 88 | if self.load_elf(binary=binary): 89 | return 1 90 | 91 | # Be careful to set the new PC only after the code is loaded as the prefetch 92 | # buffer is immediately fetching instructions and would get wrong instructions 93 | self.write(0x1A112000, 4, [0x80, 0x80, 0x00, 0x1c]) 94 | 95 | self.start_cores = True 96 | 97 | return 0 98 | 99 | 100 | def start(self): 101 | 102 | if self.start_cores: 103 | print ('Starting execution') 104 | 105 | # Unstall the FC so that it starts fetching instructions from the loaded binary 106 | self.write(0x1A110000, 4, [0, 0, 0, 0]) 107 | 108 | return 0 109 | -------------------------------------------------------------------------------- /python/bridge/chips/usoc_v1.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | import time 21 | 22 | class usoc_v1_debug_bridge(debug_bridge): 23 | 24 | def __init__(self, config, binaries=[], verbose=False): 25 | 26 | super(usoc_v1_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 27 | 28 | self.start_cores = False 29 | 30 | 31 | def load_jtag(self, binaries): 32 | 33 | if self.verbose: 34 | print ('Loading binary through jtag') 35 | 36 | if self.stop(): 37 | return -1 38 | 39 | # Load the binary through jtag 40 | if self.verbose: 41 | print ("Loading binaries") 42 | for binary in binaries: 43 | if self.load_elf(binary=binary): 44 | return 1 45 | 46 | # Be careful to set the new PC only after the code is loaded as the prefetch 47 | # buffer is immediately fetching instructions and would get wrong instructions 48 | self.write(0x1A112000, 4, [0x80, 0x80, 0x00, 0x1c]) 49 | 50 | self.start_cores = True 51 | 52 | return 0 53 | 54 | 55 | def start(self): 56 | 57 | if self.start_cores: 58 | # Unstall the FC so that it starts fetching instructions from the loaded binary 59 | self.write(0x1A110000, 4, [0, 0, 0, 0]) 60 | 61 | return 0 62 | 63 | def stop(self): 64 | 65 | # Reset the chip and tell him we want to load via jtag 66 | # We keep the reset active until the end so that it sees 67 | # the boot mode as soon as it boots from rom 68 | if self.verbose: 69 | print ("Stalling the FC") 70 | 71 | self.get_cable().chip_reset(True) 72 | self.get_cable().chip_reset(False) 73 | 74 | # Stall the FC as when the reset is released it just tries to load from flash 75 | while True: 76 | # on usoc_v1, the core will start only after a while when the reset 77 | # is released, so the first accesses we do may not have any effect. 78 | # As a aworkaround we have to try stopping it several time. 79 | # Another issue on RTL simulation is that the core is not 80 | # functional anymore if we let him execute a branch with X 81 | # which happens if we let it run too long before we stop it. 82 | # Due to that we cannot read the stall status before we stop it. 83 | for i in range(0, 10): 84 | self.write(0x1A110000, 4, [0, 0, 1, 0]) 85 | 86 | value = self.read_32(0x1A110000) 87 | if (value >> 16) & 1 == 1: 88 | break 89 | 90 | return 0 91 | -------------------------------------------------------------------------------- /python/bridge/chips/vega.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | import time 21 | 22 | JTAG_RISCV_IRLEN = 5 23 | JTAG_RISCV_BYPASS = 0x1f 24 | 25 | JTAG_SOC_CONFREG_ID = 6 26 | JTAG_SOC_CONFREG = (JTAG_SOC_CONFREG_ID << 5) | (JTAG_RISCV_BYPASS << 0) 27 | JTAG_SOC_CONFREG_WIDTH = 8 + 1 28 | JTAG_SOC_IRLEN = 4 29 | 30 | JTAG_IRLEN = JTAG_SOC_IRLEN + JTAG_RISCV_IRLEN 31 | 32 | class vega_debug_bridge(debug_bridge): 33 | 34 | def __init__(self, config, binaries=[], verbose=False): 35 | 36 | super(vega_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 37 | 38 | self.start_cores = False 39 | self.first_reset = True 40 | self.boot_mode = None 41 | 42 | 43 | def reset(self, stop=True): 44 | 45 | 46 | 47 | 48 | if self.first_reset: 49 | # The first time, we need to wait enough time to let the voltage 50 | # regulator converge 51 | self.get_cable().chip_reset(True, 5000000) 52 | self.first_reset = False 53 | 54 | # Reset the chip and tell him we want to load via jtag 55 | # We keep the reset active until the end so that it sees 56 | # the boot mode as soon as it boots from rom 57 | 58 | # Use bootsel pad to tell boot code to stop 59 | if stop: 60 | self.get_cable().chip_config(1) 61 | 62 | # Due to voltage convergence and so on we need to wait 63 | # 200ms when the reset is low 64 | #self.get_cable().chip_reset(True, 200000000) 65 | self.get_cable().chip_reset(True, 100000000) 66 | # It also takes some time before the JTAG is ready 67 | self.get_cable().chip_reset(False, 4000000) 68 | 69 | #self.get_cable().jtag_reset(True) 70 | self.get_cable().jtag_reset(False) 71 | 72 | return 0 73 | 74 | 75 | def wait_eoc(self): 76 | 77 | while True: 78 | value = self.read_32(0x1a1040a0) 79 | 80 | if (value >> 31) == 1: 81 | return value & 0x7fffffff 82 | 83 | time.sleep(0.1) 84 | 85 | 86 | def jtag_hyper_boot(self): 87 | 88 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, ((((2 << 0) | (1<<3)) << 1) | 1) << 1, JTAG_IRLEN) 89 | 90 | 91 | def jtag_mram_boot(self): 92 | 93 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, ((((2 << 0) | (2<<3)) << 1) | 1) << 1, JTAG_IRLEN) 94 | 95 | 96 | def jtag_spim_boot(self): 97 | 98 | self.get_cable().jtag_set_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, ((((2 << 0) | (0<<3)) << 1) | 1) << 1, JTAG_IRLEN) 99 | 100 | 101 | def load_jtag(self, binaries): 102 | 103 | if self.verbose: 104 | print ('Loading binary through jtag') 105 | 106 | #if self.stop(): 107 | # return -1 108 | 109 | # Load the binary through jtag 110 | if self.verbose: 111 | print ("Loading binaries") 112 | for binary in binaries: 113 | if self.load_elf(binary=binary): 114 | return 1 115 | 116 | return 0 117 | 118 | 119 | def start(self): 120 | # First stall the core 121 | self.write_dmi(0x10, 0x00000001) # DMACTIVE 122 | 123 | self.write_dmi(0x10, 0x03E00001) # HART SEL 124 | self.write_dmi(0x10, 0x83E00001) # HALT REQ 125 | 126 | # Wait until it is halted 127 | while True: 128 | status = self.read_dmi(0x11) 129 | 130 | if ((status >> 9) & 1) == 1: 131 | break 132 | 133 | # Set PC 134 | self.write_dmi(0x04, 0x1c008080) # PC into DATA0 135 | self.write_dmi(0x17, 0x00230000 | 0x7b1) # Abstract cmd to set DPC 136 | 137 | # Resume the core 138 | self.write_dmi(0x10, 0x43E00001) 139 | 140 | return 0 141 | 142 | 143 | 144 | def clear(self): 145 | self.get_cable().chip_config(0) 146 | 147 | 148 | 149 | def wait_available(self): 150 | 151 | boot_mode = 0 152 | if self.boot_mode is not None: 153 | boot_mode = (self.boot_mode << 1) | 1 154 | 155 | # Loop until we see bit 0 becoming 1, this will indicate that the 156 | # target is ready to accept bridge requests 157 | while True: 158 | reg_value = self.get_cable().jtag_get_reg(JTAG_SOC_CONFREG, JTAG_SOC_CONFREG_WIDTH, boot_mode, JTAG_IRLEN) >> 1 159 | 160 | rt_req = (reg_value >> 1) & 0x7 161 | 162 | if rt_req == 4 or rt_req == 1: 163 | break 164 | 165 | if self.verbose: 166 | print ("Target is available") 167 | 168 | 169 | 170 | def write_dmi(self, reg, value): 171 | self.write_reg_int(reg, value, 4, 0) # DMACTIVE 172 | 173 | 174 | 175 | def read_dmi(self, reg): 176 | return self.read_reg_int(reg, 4, 0) # DMACTIVE 177 | 178 | 179 | 180 | def stop(self): 181 | 182 | return 0 -------------------------------------------------------------------------------- /python/bridge/chips/vivosoc3.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | 21 | class vivosoc3_debug_bridge(debug_bridge): 22 | 23 | def __init__(self, config, binaries=[], verbose=False): 24 | 25 | super(vivosoc3_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 26 | 27 | 28 | def reset(self, stop=True): 29 | 30 | self.get_cable().chip_config(1) 31 | 32 | self.get_cable().chip_reset(True, 1000000) 33 | 34 | self.get_cable().chip_reset(False) 35 | 36 | return 0 37 | -------------------------------------------------------------------------------- /python/bridge/chips/wolfe.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | import time 21 | 22 | class wolfe_debug_bridge(debug_bridge): 23 | 24 | def __init__(self, config, binaries=[], verbose=False): 25 | 26 | super(wolfe_debug_bridge, self).__init__(config=config, binaries=binaries, verbose=verbose) 27 | 28 | self.start_cores = False 29 | 30 | 31 | def load_jtag(self, binaries): 32 | 33 | if self.verbose: 34 | print ('Loading binary through jtag') 35 | 36 | if self.stop(): 37 | return -1 38 | 39 | # Load the binary through jtag 40 | if self.verbose: 41 | print ("Loading binaries") 42 | for binary in binaries: 43 | if self.load_elf(binary=binary): 44 | return 1 45 | 46 | # Be careful to set the new PC only after the code is loaded as the prefetch 47 | # buffer is immediately fetching instructions and would get wrong instructions 48 | self.write(0x1A112000, 4, [0x80, 0x80, 0x00, 0x1c]) 49 | 50 | self.start_cores = True 51 | 52 | return 0 53 | 54 | 55 | def start(self): 56 | 57 | if self.start_cores: 58 | # Unstall the FC so that it starts fetching instructions from the loaded binary 59 | self.write(0x1A110000, 4, [0, 0, 0, 0]) 60 | 61 | return 0 62 | 63 | def stop(self): 64 | 65 | # Reset the chip and tell him we want to load via jtag 66 | # We keep the reset active until the end so that it sees 67 | # the boot mode as soon as it boots from rom 68 | if self.verbose: 69 | print ("Stalling the FC") 70 | 71 | self.get_cable().chip_reset(True) 72 | self.get_cable().chip_reset(False) 73 | 74 | # Stall the FC as when the reset is released it just tries to load from flash 75 | while True: 76 | # on Wolfe, the core will start only after a while when the reset 77 | # is released, so the first accesses we do may not have any effect. 78 | # As a aworkaround we have to try stopping it several time. 79 | # Another issue on RTL simulation is that the core is not 80 | # functional anymore if we let him execute a branch with X 81 | # which happens if we let it run too long before we stop it. 82 | # Due to that we cannot read the stall status before we stop it. 83 | for i in range(0, 10): 84 | self.write(0x1A110000, 4, [0, 0, 1, 0]) 85 | 86 | value = self.read_32(0x1A110000) 87 | if (value >> 16) & 1 == 1: 88 | break 89 | 90 | return 0 91 | -------------------------------------------------------------------------------- /python/bridge/debug_bridge.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | from bridge.default_debug_bridge import * 20 | import bridge.chips.gap as gap 21 | import bridge.chips.gap_rev1 as gap_rev1 22 | import bridge.chips.gap8_revc as gap8_revc 23 | import bridge.chips.wolfe as wolfe 24 | import bridge.chips.usoc_v1 as usoc_v1 25 | import bridge.chips.vega as vega 26 | import bridge.chips.arnold as arnold 27 | import bridge.chips.fulmine as fulmine 28 | import bridge.chips.pulpissimo as pulpissimo 29 | import bridge.chips.pulp as pulp 30 | import bridge.chips.vivosoc3 as vivosoc3 31 | 32 | 33 | def get_bridge(config, binaries=[], verbose=False): 34 | 35 | chip_config = config.get('**/board/chip') 36 | if chip_config is None: 37 | raise Exception('Wrong JSON configuration, do not contain any chip information') 38 | 39 | chip = config.get('**/board/chip').get('name').get() 40 | 41 | if chip == 'gap': 42 | bridge_class = gap.gap_debug_bridge 43 | elif chip == 'gap_rev1': 44 | bridge_class = gap_rev1.gap_debug_bridge 45 | elif chip == 'gap8_revc': 46 | bridge_class = gap8_revc.gap_debug_bridge 47 | elif chip == 'fulmine' or chip == 'vivosoc2' or chip == 'vivosoc2_1': 48 | bridge_class = fulmine.fulmine_debug_bridge 49 | elif chip == 'wolfe': 50 | bridge_class = wolfe.wolfe_debug_bridge 51 | elif chip == 'usoc_v1': 52 | bridge_class = usoc_v1.usoc_v1_debug_bridge 53 | elif chip == 'vega': 54 | bridge_class = vega.vega_debug_bridge 55 | elif chip == 'arnold': 56 | bridge_class = arnold.arnold_debug_bridge 57 | elif chip == 'pulp': 58 | bridge_class = pulp.pulp_debug_bridge 59 | elif chip == 'pulpissimo': 60 | bridge_class = pulpissimo.pulpissimo_debug_bridge 61 | elif chip == 'vivosoc3': 62 | bridge_class = vivosoc3.vivosoc3_debug_bridge 63 | else: 64 | bridge_class = debug_bridge 65 | 66 | return bridge_class(config=config, binaries=binaries, verbose=verbose) 67 | -------------------------------------------------------------------------------- /python/bridge/default_debug_bridge.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | import ctypes 20 | import os 21 | import os.path 22 | import json_tools as js 23 | from elftools.elf.elffile import ELFFile 24 | import time 25 | 26 | 27 | class Ctype_cable(object): 28 | 29 | def __init__(self, module, config, system_config): 30 | 31 | self.module = module 32 | self.gdb_handle = None 33 | 34 | # Register entry points with appropriate arguments 35 | self.module.cable_new.argtypes = [ctypes.c_char_p, ctypes.c_char_p] 36 | self.module.cable_new.restype = ctypes.c_void_p 37 | 38 | self.module.cable_write.argtypes = \ 39 | [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_char_p] 40 | 41 | self.module.cable_read.argtypes = \ 42 | [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_char_p] 43 | 44 | self.module.cable_reg_write.argtypes = \ 45 | [ctypes.c_void_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_int] 46 | 47 | self.module.cable_reg_read.argtypes = \ 48 | [ctypes.c_void_p, ctypes.c_int, ctypes.c_char_p] 49 | 50 | self.module.chip_reset.argtypes = \ 51 | [ctypes.c_void_p, ctypes.c_bool, ctypes.c_int] 52 | 53 | self.module.chip_config.argtypes = \ 54 | [ctypes.c_void_p, ctypes.c_int] 55 | 56 | self.module.jtag_reset.argtypes = \ 57 | [ctypes.c_void_p, ctypes.c_bool] 58 | 59 | self.module.jtag_soft_reset.argtypes = \ 60 | [ctypes.c_void_p] 61 | 62 | self.module.cable_jtag_set_reg.argtypes = \ 63 | [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_uint, ctypes.c_int] 64 | self.module.cable_jtag_set_reg.restype = ctypes.c_bool 65 | 66 | self.module.cable_jtag_get_reg.argtypes = \ 67 | [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.c_int] 68 | self.module.cable_jtag_get_reg.restype = ctypes.c_bool 69 | 70 | self.module.cable_lock.argtypes = \ 71 | [ctypes.c_void_p] 72 | 73 | self.module.cable_unlock.argtypes = \ 74 | [ctypes.c_void_p] 75 | 76 | self.module.bridge_get_error.argtypes = [] 77 | self.module.bridge_get_error.restype = ctypes.c_char_p 78 | 79 | self.module.bridge_init.argtypes = [ctypes.c_char_p, ctypes.c_int] 80 | 81 | self.module.gdb_server_open.argtypes = [ctypes.c_void_p, ctypes.c_int] 82 | self.module.gdb_server_open.restype = ctypes.c_void_p 83 | 84 | self.module.gdb_server_close.argtypes = [ctypes.c_void_p, ctypes.c_int] 85 | 86 | config_string = None 87 | 88 | if config is not None: 89 | config_string = config.dump_to_string().encode('utf-8') 90 | 91 | self.instance = self.module.cable_new(config_string, system_config.dump_to_string().encode('utf-8')) 92 | 93 | if self.instance == None: 94 | raise Exception('Failed to initialize cable with error: ' + self.module.bridge_get_error().decode('utf-8')) 95 | 96 | def get_instance(self): 97 | return self.instance 98 | 99 | def write(self, addr, size, buffer): 100 | data = (ctypes.c_char * size).from_buffer(bytearray(buffer)) 101 | self.module.cable_write(self.instance, addr, size, data) 102 | 103 | def reg_write(self, addr, size, buffer, device=-1): 104 | data = (ctypes.c_char * size).from_buffer(bytearray(buffer)) 105 | self.module.cable_reg_write(self.instance, addr, data, device) 106 | 107 | def read(self, addr, size): 108 | data = (ctypes.c_char * size)() 109 | self.module.cable_read(self.instance, addr, size, data) 110 | 111 | result = [] 112 | for elem in data: 113 | result.append(elem) 114 | 115 | return result 116 | 117 | def reg_read(self, addr, size, device=-1): 118 | data = (ctypes.c_char * size)() 119 | self.module.cable_reg_read(self.instance, addr, data, device) 120 | 121 | result = [] 122 | for elem in data: 123 | result.append(elem) 124 | 125 | return result 126 | 127 | def chip_reset(self, value, duration=1000000): 128 | self.module.chip_reset(self.instance, value, duration) 129 | 130 | def chip_config(self, value): 131 | self.module.chip_config(self.instance, value) 132 | 133 | def jtag_reset(self, value): 134 | self.module.jtag_reset(self.instance, value) 135 | 136 | def jtag_soft_reset(self): 137 | self.module.jtag_soft_reset(self.instance) 138 | 139 | def jtag_set_reg(self, reg, width, value, ir_len=-1): 140 | self.module.cable_jtag_set_reg(self.instance, reg, width, value, ir_len) 141 | 142 | def jtag_get_reg(self, reg, width, value, ir_len=-1): 143 | out_value = ctypes.c_int() 144 | self.module.cable_jtag_get_reg(self.instance, reg, width, ctypes.byref(out_value), value, ir_len) 145 | return out_value.value 146 | 147 | def lock(self): 148 | self.module.cable_lock(self.instance) 149 | 150 | def unlock(self): 151 | self.module.cable_unlock(self.instance) 152 | 153 | 154 | 155 | 156 | class debug_bridge(object): 157 | 158 | def __init__(self, config, binaries=[], verbose=False): 159 | self.config = config 160 | self.cable = None 161 | self.cable_name = config.get_child_str('**/debug_bridge/cable/type') 162 | if self.cable_name is None: 163 | self.cable_name = 'ftdi' 164 | self.binaries = binaries 165 | self.reqloop_handle = None 166 | self.verbose = verbose 167 | self.gdb_handle = None 168 | self.cable_config = config.get('**/debug_bridge/cable') 169 | 170 | 171 | 172 | # Load the library which provides generic services through 173 | # python / C++ bindings 174 | lib_path=os.path.join('libpulpdebugbridge.so') 175 | self.module = ctypes.CDLL(lib_path) 176 | 177 | self.module.bridge_reqloop_open.argtypes = [ctypes.c_void_p, ctypes.c_uint] 178 | self.module.bridge_reqloop_open.restype = ctypes.c_void_p 179 | 180 | self.module.bridge_reqloop_buffer_alloc.argtypes = [ctypes.c_void_p, ctypes.c_int] 181 | self.module.bridge_reqloop_buffer_alloc.restype = ctypes.c_uint 182 | 183 | self.module.bridge_reqloop_buffer_free.argtypes = [ctypes.c_void_p, ctypes.c_uint, ctypes.c_int] 184 | 185 | self.module.bridge_reqloop_efuse_access.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_uint, ctypes.c_uint] 186 | 187 | self.module.bridge_reqloop_eeprom_access.argtypes = [ctypes.c_void_p, ctypes.c_uint, ctypes.c_uint, ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint] 188 | self.module.bridge_reqloop_eeprom_access.restype = ctypes.c_int 189 | 190 | self.module.bridge_reqloop_flash_access.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint] 191 | self.module.bridge_reqloop_flash_access.restype = ctypes.c_int 192 | 193 | self.module.bridge_reqloop_flash_erase.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint, ctypes.c_int] 194 | self.module.bridge_reqloop_flash_erase.restype = ctypes.c_int 195 | 196 | self.module.bridge_reqloop_flash_erase_sector.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint] 197 | self.module.bridge_reqloop_flash_erase_sector.restype = ctypes.c_int 198 | 199 | self.module.bridge_reqloop_flash_erase_chip.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_uint, ctypes.c_uint] 200 | self.module.bridge_reqloop_flash_erase_chip.restype = ctypes.c_int 201 | 202 | self.module.bridge_reqloop_close.argtypes = [ctypes.c_void_p, ctypes.c_int] 203 | 204 | self.module.bridge_init(config.dump_to_string().encode('utf-8'), verbose) 205 | 206 | #self.module.jtag_shift.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(ctypes.c_char_p), ctypes.POINTER(ctypes.c_char_p)] 207 | 208 | def __mount_cable(self): 209 | if self.cable_name is None: 210 | raise Exception("Trying to mount cable while no cable was specified") 211 | 212 | if self.cable_name.split('@')[0] in ['ftdi', 'jtag-proxy']: 213 | self.__mount_ctype_cable() 214 | pass 215 | else: 216 | raise Exception('Unknown cable: ' + self.cable_name) 217 | 218 | def __mount_ctype_cable(self): 219 | 220 | self.cable = Ctype_cable( 221 | module = self.module, 222 | config = self.cable_config, 223 | system_config = self.config 224 | ) 225 | 226 | def get_cable(self): 227 | if self.cable is None: 228 | self.__mount_cable() 229 | 230 | return self.cable 231 | 232 | def load_jtag(self, binaries): 233 | return self.load_default(binaries) 234 | 235 | def load_jtag_hyper(self, binaries): 236 | raise Exception('JTAG boot is not supported on this target') 237 | 238 | def load_elf(self, binary): 239 | if self.verbose: 240 | print ('Loading %s' % binary) 241 | 242 | with open(binary, 'rb') as file: 243 | elffile = ELFFile(file) 244 | 245 | for segment in elffile.iter_segments(): 246 | 247 | if segment['p_type'] == 'PT_LOAD': 248 | 249 | data = segment.data() 250 | addr = segment['p_paddr'] 251 | size = len(data) 252 | 253 | if self.verbose: 254 | print ('Loading section (base: 0x%x, size: 0x%x)' % (addr, size)) 255 | 256 | self.write(addr, size, data) 257 | 258 | if segment['p_filesz'] < segment['p_memsz']: 259 | addr = segment['p_paddr'] + segment['p_filesz'] 260 | size = segment['p_memsz'] - segment['p_filesz'] 261 | print ('Init section to 0 (base: 0x%x, size: 0x%x)' % (addr, size)) 262 | self.write( 263 | addr, 264 | size, 265 | [0] * size 266 | ) 267 | 268 | 269 | set_pc_addr_config = self.config.get('**/debug_bridge/set_pc_addr') 270 | 271 | if set_pc_addr_config is not None: 272 | set_pc_offset_config = self.config.get('**/debug_bridge/set_pc_offset') 273 | entry = elffile.header['e_entry'] 274 | 275 | if set_pc_offset_config is not None: 276 | entry += set_pc_offset_config.get_int() 277 | 278 | if self.verbose: 279 | print ('Setting PC (base: 0x%x, value: 0x%x)' % (set_pc_addr_config.get_int(), entry)) 280 | 281 | return self.write_32(set_pc_addr_config.get_int(), entry) 282 | 283 | return 0 284 | 285 | def load(self, binaries=None): 286 | if binaries is None: 287 | binaries = self.binaries 288 | 289 | mode = self.config.get_child_str('**/debug_bridge/boot-mode') 290 | if mode is None: 291 | mode = 'jtag' 292 | 293 | if mode == 'jtag': 294 | return self.load_jtag(binaries) 295 | elif mode == 'jtag_hyper': 296 | return self.load_jtag_hyper(binaries) 297 | else: 298 | return self.load_default(binaries) 299 | 300 | def load_default(self, binaries): 301 | for binary in binaries: 302 | if self.load_elf(binary=binary): 303 | return 1 304 | 305 | return 0 306 | 307 | def start(self): 308 | start_addr_config = self.config.get('**/debug_bridge/start_addr') 309 | if start_addr_config is not None: 310 | if self.verbose: 311 | print ('Starting (base: 0x%x, value: 0x%x)' % (start_addr_config.get_int(), self.config.get('**/debug_bridge/start_value').get_int())) 312 | 313 | self.write_32(start_addr_config.get_int(), self.config.get('**/debug_bridge/start_value').get_int()) 314 | return 0 315 | 316 | def stop(self): 317 | stop_addr_config = self.config.get('**/debug_bridge/stop_addr') 318 | if stop_addr_config is not None: 319 | self.write_32(stop_addr_config.get_int(), self.config.get('**/debug_bridge/stop_value').get_int()) != 0 320 | return 0 321 | 322 | def read(self, addr, size): 323 | return self.get_cable().read(addr, size) 324 | 325 | def write(self, addr, size, buffer): 326 | return self.get_cable().write(addr, size, buffer) 327 | 328 | def write_int(self, addr, value, size): 329 | return self.write(addr, size, value.to_bytes(size, byteorder='little')) 330 | 331 | def write_reg_int(self, addr, value, size, device=-1): 332 | return self.get_cable().reg_write(addr, size, value.to_bytes(size, byteorder='little'), device) 333 | 334 | def write_32(self, addr, value): 335 | return self.write_int(addr, value, 4) 336 | 337 | def write_16(self, addr, value): 338 | return self.write_int(addr, value, 2) 339 | 340 | def write_8(self, addr, value): 341 | return self.write_int(addr, value, 1) 342 | 343 | def read_int(self, addr, size): 344 | byte_array = None 345 | for byte in self.read(addr, size): 346 | if byte_array == None: 347 | byte_array = byte 348 | else: 349 | byte_array += byte 350 | return int.from_bytes(byte_array, byteorder='little') 351 | 352 | def read_reg_int(self, addr, size, device=-1): 353 | byte_array = None 354 | for byte in self.get_cable().reg_read(addr, size, device): 355 | if byte_array == None: 356 | byte_array = byte 357 | else: 358 | byte_array += byte 359 | return int.from_bytes(byte_array, byteorder='little') 360 | 361 | def read_32(self, addr): 362 | return self.read_int(addr, 4) 363 | 364 | def read_16(self, addr): 365 | return self.read_int(addr, 2) 366 | 367 | def read_8(self, addr): 368 | return self.read_int(addr, 1) 369 | 370 | def _get_binary_symbol_addr(self, name, binaries=[]): 371 | 372 | binaries = binaries + self.binaries 373 | 374 | for binary in binaries: 375 | with open(binary, 'rb') as file: 376 | elf = ELFFile(file) 377 | for section in elf.iter_sections(): 378 | if section.header['sh_type'] == 'SHT_SYMTAB': 379 | for symbol in section.iter_symbols(): 380 | if symbol.name == name: 381 | t_section=symbol.entry['st_shndx'] 382 | t_vaddr=symbol.entry['st_value'] 383 | return t_vaddr 384 | return 0 385 | 386 | def reset(self): 387 | self.get_cable().jtag_reset(True) 388 | self.get_cable().jtag_reset(False) 389 | self.get_cable().chip_reset(True) 390 | self.get_cable().chip_reset(False) 391 | return 0 392 | 393 | def ioloop(self): 394 | 395 | return 0 396 | 397 | def reqloop(self, binaries=[]): 398 | 399 | # First get address of the structure used to communicate between 400 | # the bridge and the runtime 401 | addr = self._get_binary_symbol_addr('__rt_debug_struct_ptr', binaries) 402 | if addr == 0: 403 | addr = self._get_binary_symbol_addr('debugStruct_ptr', binaries) 404 | 405 | self.reqloop_handle = self.module.bridge_reqloop_open( 406 | self.get_cable().get_instance(), addr) 407 | 408 | return 0 409 | 410 | def reqloop_close(self, force=False): 411 | if self.reqloop_handle is not None: 412 | return self.module.bridge_reqloop_close(self.reqloop_handle, force) 413 | return 0 414 | 415 | 416 | def __flasher_init(self, flasher_init): 417 | chip = self.config.get('**/board/chip').get('name').get() 418 | flasher_name = 'flasher-%s' % chip 419 | flasher_path = os.path.join(os.environ.get('PULP_SDK_INSTALL'), 'bin', flasher_name) 420 | 421 | if flasher_init: 422 | self.stop() 423 | # TODO this breaks boot test using bridge, why this is needed ? 424 | self.load([flasher_path]) 425 | 426 | self.reqloop([flasher_path]) 427 | 428 | if flasher_init: 429 | self.start() 430 | 431 | 432 | 433 | def __flasher_deinit(self): 434 | self.reqloop_close(force=True) 435 | 436 | 437 | 438 | def efuse_access(self, flasher_init, is_write, index, value, mask): 439 | 440 | self.__flasher_init(flasher_init) 441 | 442 | print ('efuse access') 443 | self.module.bridge_reqloop_efuse_access(self.reqloop_handle, is_write, index, value, mask) 444 | print ('efuse access done') 445 | 446 | self.__flasher_deinit() 447 | 448 | 449 | 450 | def __alloc_buffer(self, size): 451 | 452 | return self.module.bridge_reqloop_buffer_alloc(self.reqloop_handle, size) 453 | 454 | 455 | 456 | def eeprom_access(self, flasher_init, itf, cs, is_write,eeprom_addr, filepath): 457 | self.__flasher_init(flasher_init) 458 | 459 | addr = self.__alloc_buffer(1024) 460 | 461 | with open(filepath, 'rb') as file: 462 | while True: 463 | buff = file.read(1024) 464 | if buff: 465 | self.write(addr, len(buff), buff) 466 | if self.module.bridge_reqloop_eeprom_access(self.reqloop_handle, itf, cs, True, eeprom_addr, addr, len(buff)): 467 | return -1 468 | eeprom_addr += 1024 469 | else: 470 | break 471 | 472 | self.__flasher_deinit() 473 | 474 | return 0 475 | 476 | 477 | 478 | def flash_access(self, flasher_init, type, itf, cs, is_write,flash_addr, size, filepath): 479 | self.__flasher_init(flasher_init) 480 | 481 | addr = self.__alloc_buffer(1024) 482 | 483 | if is_write: 484 | with open(filepath, 'rb') as file: 485 | while True: 486 | buff = file.read(1024) 487 | if buff: 488 | self.write(addr, len(buff), buff) 489 | 490 | buff_size = len(buff) 491 | buff_size = (buff_size + 7) & ~0x7 492 | 493 | if self.module.bridge_reqloop_flash_access(self.reqloop_handle, type, itf, cs, True, flash_addr, addr, buff_size): 494 | return -1 495 | flash_addr += 1024 496 | else: 497 | break 498 | else: 499 | with open(filepath, 'wb') as file: 500 | while size > 0: 501 | iter_size = 1024 502 | if iter_size > size: 503 | iter_size = size 504 | if self.module.bridge_reqloop_flash_access(self.reqloop_handle, type, itf, cs, False, flash_addr, addr, iter_size): 505 | return -1 506 | buff = self.read(addr, iter_size) 507 | for elem in buff: 508 | file.write(elem) 509 | size -= iter_size 510 | flash_addr += iter_size 511 | 512 | self.__flasher_deinit() 513 | 514 | return 0 515 | 516 | 517 | 518 | 519 | def flash_erase_sector(self, flasher_init, type, itf, cs, flash_addr): 520 | self.__flasher_init(flasher_init) 521 | 522 | if self.module.bridge_reqloop_flash_erase_sector(self.reqloop_handle, type, itf, cs, flash_addr): 523 | return -1 524 | 525 | self.__flasher_deinit() 526 | 527 | return 0 528 | 529 | 530 | 531 | 532 | def flash_erase_chip(self, flasher_init, type, itf, cs): 533 | self.__flasher_init(flasher_init) 534 | 535 | if self.module.bridge_reqloop_flash_erase_chip(self.reqloop_handle, type, itf, cs): 536 | return -1 537 | 538 | self.__flasher_deinit() 539 | 540 | return 0 541 | 542 | 543 | def flash_erase(self, flasher_init, type, itf, cs, flash_addr, size): 544 | self.__flasher_init(flasher_init) 545 | 546 | if self.module.bridge_reqloop_flash_erase(self.reqloop_handle, type, itf, cs, flash_addr, size): 547 | return -1 548 | 549 | self.__flasher_deinit() 550 | 551 | return 0 552 | 553 | 554 | def flash(self): 555 | raise Exception('Flash is not supported on this target') 556 | 557 | def gdb(self, port): 558 | self.gdb_handle = self.module.gdb_server_open(self.get_cable().get_instance(), port) 559 | return 0 560 | 561 | def wait(self): 562 | if self.gdb_handle is not None: 563 | self.module.gdb_server_close(self.gdb_handle, 0) 564 | 565 | # The wait function returns in case reqloop has been launched 566 | # as it will check for end of application. 567 | if self.reqloop_handle is not None: 568 | return self.module.bridge_reqloop_close(self.reqloop_handle, 0) 569 | 570 | return 0 571 | 572 | def lock(self): 573 | self.get_cable().lock() 574 | 575 | def unlock(self): 576 | self.get_cable().unlock() 577 | -------------------------------------------------------------------------------- /python/bridge/jtag.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018 ETH Zurich and University of Bologna 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 18 | 19 | import ctypes 20 | import os 21 | import os.path 22 | from elftools.elf.elffile import ELFFile 23 | import time 24 | import sys 25 | import json_tools as js 26 | 27 | BOOT_MODE_DEFAULT = 0 28 | BOOT_MODE_JTAG = 1 29 | BOOT_MODE_ROM_HYPER = 2 30 | 31 | JTAG_SOC_INSTR_WIDTH = 0x4 32 | JTAG_SOC_IDCODE = 0x2 33 | JTAG_SOC_AXIREG = 0x4 34 | JTAG_SOC_BBMUXREG = 0x5 35 | JTAG_SOC_CLKGATEREG = 0x6 36 | JTAG_SOC_CONFREG = 0x7 37 | JTAG_SOC_TESTMODEREG = 0x8 38 | JTAG_SOC_BISTREG = 0x9 39 | JTAG_SOC_BYPASS = 0xf 40 | JTAG_SOC_IDCODE_WIDTH = 32 41 | JTAG_SOC_AXIREG_WIDTH = 96 42 | JTAG_SOC_BBMUXREG_WIDTH = 21 43 | JTAG_SOC_CLKGATEREG_WIDTH = 11 44 | JTAG_SOC_CONFREG_WIDTH = 4 45 | JTAG_SOC_TESTMODEREG_WIDTH = 4 46 | JTAG_SOC_BISTREG_WIDTH = 20 47 | 48 | JTAG_CLUSTER_INSTR_WIDTH = 4 49 | JTAG_CLUSTER_IDCODE = 2 50 | JTAG_CLUSTER_SAMPLE_PRELOAD = 1 51 | JTAG_CLUSTER_EXTEST = 0 52 | JTAG_CLUSTER_DEBUG = 8 53 | JTAG_CLUSTER_MBIST = 9 54 | JTAG_CLUSTER_BYPASS = 0xf 55 | JTAG_CLUSTER_IDCODE_WIDTH = 32 56 | 57 | JTAG_IDCODE_WIDTH = JTAG_CLUSTER_IDCODE_WIDTH + JTAG_SOC_IDCODE_WIDTH 58 | JTAG_INSTR_WIDTH = JTAG_CLUSTER_INSTR_WIDTH + JTAG_SOC_INSTR_WIDTH 59 | 60 | 61 | ADV_DBG_AXI4_MODULE = 0x20 62 | ADV_DBG_CPU_MODULE = 0x21 63 | 64 | ADV_DBG_AXI4_NOP = 0x0 65 | ADV_DBG_AXI4_WRITE8 = 0x1 66 | ADV_DBG_AXI4_WRITE16 = 0x2 67 | ADV_DBG_AXI4_WRITE32 = 0x3 68 | ADV_DBG_AXI4_WRITE64 = 0x4 69 | ADV_DBG_AXI4_READ8 = 0x5 70 | ADV_DBG_AXI4_READ16 = 0x6 71 | ADV_DBG_AXI4_READ32 = 0x7 72 | ADV_DBG_AXI4_READ64 = 0x8 73 | ADV_DBG_AXI4_WREG = 0x9 74 | ADV_DBG_AXI4_SELREG = 0xD 75 | 76 | ADV_DBG_CPU_NOP = 0x0 77 | ADV_DBG_CPU_WRITE = 0x3 78 | ADV_DBG_CPU_READ = 0x7 79 | ADV_DBG_CPU_WREG = 0x9 80 | ADV_DBG_CPU_SELREG = 0xD 81 | 82 | ADV_DBG_CPU_REG_STATUS = 0x0 83 | 84 | class debug_bridge(object): 85 | """ Debug bridge doc. """ 86 | 87 | def __init__(self, config_path, cable_option=None): 88 | self.config = js.import_config_from_file(config_path) 89 | path = os.path.join(os.environ.get('PULP_SDK_HOME'), 'install', 'ws', 'lib', 'libdebugbridge.so') 90 | self.module = ctypes.CDLL(path) 91 | self.module.bridge_new.argtypes = [ctypes.c_char_p, ctypes.c_char_p] 92 | self.module.jtag_write.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_char_p] 93 | #self.module.jtag_shift.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(ctypes.c_char_p), ctypes.POINTER(ctypes.c_char_p)] 94 | with open(config_path, 'r') as config: 95 | self.instance = self.module.bridge_new(config.read().encode('utf-8'), cable_option.encode('utf-8')) 96 | 97 | def reset(self, active): 98 | """ Debug bridge reset. 99 | :param active: Reset target 100 | """ 101 | self.module.reset(self.instance, active) 102 | 103 | def exit(self, status): 104 | self.module.plt_exit(self.instance, status) 105 | 106 | def jtag_write(self, addr, size, buffer): 107 | data = (ctypes.c_char * size).from_buffer(bytearray(buffer)) 108 | self.module.jtag_write(self.instance, addr, size, data) 109 | 110 | def jtag_read(self, addr, size): 111 | data = (ctypes.c_ubyte * size)() 112 | self.module.jtag_read(self.instance, addr, size, data) 113 | 114 | result = [] 115 | for elem in data: 116 | result.append(elem) 117 | 118 | return result 119 | 120 | def jtag_read32(self, addr): 121 | data = self.jtag_read(addr, 4) 122 | return int.from_bytes(bytearray(data), 'little') 123 | 124 | def jtag_reset(self): 125 | self.module.jtag_reset(self.instance) 126 | 127 | def jtag_idle(self): 128 | self.module.jtag_idle(self.instance) 129 | 130 | def jtag_shift_ir(self): 131 | self.module.jtag_shift_ir(self.instance) 132 | 133 | def jtag_shift_dr(self): 134 | self.module.jtag_shift_dr(self.instance) 135 | 136 | def jtag_shift_common(self, width, bufferin, noex): 137 | size = int((width + 7) / 8) 138 | if bufferin is not None: 139 | datain = (ctypes.c_char * size).from_buffer(bytearray(bufferin)) 140 | else: 141 | datain = (ctypes.c_char * size)() 142 | dataout = (ctypes.c_ubyte * size)() 143 | self.module.jtag_shift(self.instance, width, datain, dataout, noex) 144 | 145 | result = [] 146 | for elem in dataout: 147 | result.append(elem) 148 | 149 | return bytearray(result) 150 | 151 | def jtag_shift_noex(self, width, bufferin): 152 | return self.jtag_shift_common(width, bufferin, 1) 153 | 154 | def jtag_shift(self, width, bufferin): 155 | return self.jtag_shift_common(width, bufferin, 0) 156 | 157 | def jtag_set_reg(self, reg, value): 158 | # Set TAP in confreg mode 159 | self.jtag_shift_ir() 160 | self.jtag_shift(JTAG_SOC_INSTR_WIDTH, [reg]) 161 | self.jtag_idle() 162 | 163 | # And push the new value 164 | self.jtag_shift_dr() 165 | self.jtag_shift(9, [value, 0]) 166 | self.jtag_idle() 167 | 168 | def jtag_get_reg(self, reg, value): 169 | # Set TAP in confreg mode 170 | #self.jtag_shift_ir() 171 | #self.jtag_shift(JTAG_SOC_INSTR_WIDTH, [reg]) 172 | #self.jtag_idle() 173 | #print (binascii.hexlify(bytearray(data))) 174 | 175 | # And push the new value 176 | self.jtag_shift_dr() 177 | result = self.jtag_shift(9, [value, 0]) 178 | self.jtag_idle() 179 | 180 | return result 181 | 182 | def jtag_set_dbg_mode_soc(self): 183 | 184 | self.jtag_shift_ir() 185 | self.jtag_shift_noex(JTAG_CLUSTER_INSTR_WIDTH, [JTAG_SOC_BYPASS]) 186 | self.jtag_shift(JTAG_SOC_INSTR_WIDTH, [JTAG_SOC_AXIREG]) 187 | self.jtag_idle() 188 | 189 | def wait_exit(self): 190 | self.jtag_set_dbg_mode_soc() 191 | 192 | while True: 193 | value = self.jtag_read32(0x1a1040a0) 194 | 195 | if (value >> 31) & 1: 196 | return value & 0x7fffffff 197 | 198 | time.sleep(0.5) 199 | 200 | def wait_exit_and_stop(self): 201 | status = self.wait_exit() 202 | self.exit(status) 203 | 204 | def load(self, binary): 205 | 206 | print ('Loading ELF file (path: %s)' % binary) 207 | 208 | self.jtag_set_dbg_mode_soc() 209 | 210 | with open(binary, 'rb') as file: 211 | elffile = ELFFile(file) 212 | 213 | for segment in elffile.iter_segments(): 214 | if segment['p_type'] == 'PT_LOAD': 215 | 216 | data = segment.data() 217 | addr = segment['p_paddr'] 218 | size = len(data) 219 | 220 | print ('Loading section (base: 0x%x, size: 0x%x)' % (addr, size)) 221 | 222 | self.jtag_write(addr, size, data) 223 | 224 | def wait_and_exit(self): 225 | 226 | status = self.wait_exit_and_stop() 227 | sys.exit(status) 228 | 229 | 230 | def rom_boot(self): 231 | 232 | # This is the default mode so just let the core boot and behave in the 233 | # default mode 234 | self.jtag_reset() 235 | self.reset(False) 236 | 237 | 238 | def rom_hyper_boot(self, binary): 239 | 240 | self.jtag_reset() 241 | 242 | # Reset the chip and tell him we want to load via jtag 243 | # We keep the reset active until the end so that it sees 244 | # the boot mode as soon as it boots from rom 245 | self.reset(True) 246 | self.jtag_set_reg(JTAG_SOC_CONFREG, BOOT_MODE_ROM_HYPER << 1) 247 | self.reset(False) 248 | 249 | # We don't have anything else to do as it reads the boot mode 250 | # and does everything with the flash 251 | 252 | 253 | def jtag_boot(self, binary): 254 | 255 | self.jtag_reset() 256 | 257 | # Reset the chip and tell him we want to load via jtag 258 | # We keep the reset active until the end so that it sees 259 | # the boot mode as soon as it boots from rom 260 | self.reset(True) 261 | self.jtag_set_reg(JTAG_SOC_CONFREG, BOOT_MODE_JTAG << 1) 262 | self.reset(False) 263 | 264 | # Load the binary through jtag 265 | self.load(binary) 266 | 267 | # And notify the boot code that the binary is ready 268 | self.jtag_set_reg(JTAG_SOC_CONFREG, (BOOT_MODE_JTAG << 1) | 1) 269 | 270 | def exec_config(self): 271 | 272 | mode = self.config.get('runner/boot-mode').get() 273 | 274 | if mode == 'rom': 275 | self.rom_boot() 276 | elif mode == 'rom_hyper': 277 | self.rom_hyper_boot() 278 | elif mode == 'jtag': 279 | self.jtag_boot(self.config.get('loader/binaries').get_elem(0).get()) 280 | else: 281 | raise Exception("Unsupported mode: " + mode) 282 | 283 | self.wait_and_exit() 284 | -------------------------------------------------------------------------------- /src/cable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 19 | */ 20 | 21 | #ifndef __CABLES_CABLE_HPP__ 22 | #define __CABLES_CABLE_HPP__ 23 | 24 | #include "json.hpp" 25 | #include "cables/log.h" 26 | 27 | 28 | class Cable_jtag_itf 29 | { 30 | public: 31 | 32 | virtual bool bit_inout(char* inbit, char outbit, bool last) { printf ("i am bit_inout virtual fct in cable class\n"); return false; } 33 | 34 | virtual bool stream_inout(char* instream, char* outstream, unsigned int n_bits, bool last) { printf ("i am stream_inout virtual fct in cable class\n"); return false; } 35 | 36 | virtual int flush() { return -1; } 37 | virtual bool jtag_reset(bool active) { printf("JTAG\n"); return false; } 38 | 39 | virtual void device_select(unsigned int i) {} 40 | 41 | bool jtag_soft_reset(); 42 | bool jtag_write_tms(int val); 43 | bool jtag_shift_ir(); 44 | bool jtag_shift_dr(); 45 | bool jtag_idle(); 46 | bool jtag_shift(int width, char *bits); 47 | bool jtag_shift_ir(unsigned int ir, int ir_len=-1); 48 | bool jtag_set_reg(unsigned int reg, int width, unsigned int value, int ir_len=-1); 49 | bool jtag_get_reg(unsigned int reg, int width, unsigned int *out_value, unsigned int value, int ir_len=-1); 50 | }; 51 | 52 | 53 | 54 | class Cable_io_itf 55 | { 56 | public: 57 | virtual bool access(bool write, unsigned int addr, int size, char* buffer, int device=-1) { return false; } 58 | virtual bool reg_access(bool write, unsigned int addr, char* buffer, int device=-1) { return false; } 59 | }; 60 | 61 | 62 | 63 | class Cable_ctrl_itf 64 | { 65 | public: 66 | virtual bool chip_reset(bool active, int duration) { return false; } 67 | virtual bool chip_config(uint32_t config) { return false; } 68 | }; 69 | 70 | 71 | 72 | class Cable : public Cable_io_itf, public Cable_jtag_itf, public Cable_ctrl_itf 73 | { 74 | public: 75 | Cable(js::config *config) : config(config) {} 76 | 77 | virtual bool connect(js::config *config) { return true; } 78 | 79 | virtual void lock() { } 80 | 81 | virtual void unlock() { } 82 | 83 | js::config *get_config() { return this->config; } 84 | 85 | protected: 86 | js::config *config; 87 | 88 | }; 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /src/cables/adv_dbg_itf/adv_dbg_itf.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | /* 16 | * Authors: Andreas Traber 17 | */ 18 | 19 | #ifndef __CABLES_ADV_DBG_ITF_ADV_DBG_ITF_HPP__ 20 | #define __CABLES_ADV_DBG_ITF_ADV_DBG_ITF_HPP__ 21 | 22 | #include 23 | #include 24 | 25 | #include "cables/log.h" 26 | #include "cable.hpp" 27 | 28 | class FTDILL; 29 | 30 | #define DEV_PROTOCOL_PULP 0 31 | #define DEV_PROTOCOL_RISCV 1 32 | 33 | struct jtag_device { 34 | uint32_t id; 35 | unsigned int index; 36 | unsigned int ir_len; 37 | bool is_in_debug; 38 | int protocol; 39 | }; 40 | 41 | class Adv_dbg_itf : public Cable { 42 | public: 43 | Adv_dbg_itf(js::config *system_config, js::config *config, Log* log, Cable *itf); 44 | virtual ~Adv_dbg_itf(); 45 | 46 | bool connect(); 47 | void lock(); 48 | void unlock(); 49 | 50 | 51 | bool access(bool write, unsigned int addr, int size, char* buffer, int device=-1); 52 | bool reg_access(bool write, unsigned int addr, char* buffer, int device=-1); 53 | 54 | void device_select(unsigned int i); 55 | 56 | void add_device(int ir_len, int protocol=DEV_PROTOCOL_PULP); 57 | 58 | 59 | bool chip_reset(bool active, int duration); 60 | bool chip_config(uint32_t config); 61 | bool jtag_reset(bool active); 62 | bool jtag_soft_reset(); 63 | 64 | 65 | bool bit_inout(char* inbit, char outbit, bool last); 66 | bool stream_inout(char* instream, char* outstream, unsigned int n_bits, bool last); 67 | 68 | int flush(); 69 | 70 | 71 | private: 72 | enum ADBG_OPCODES { 73 | AXI_WRITE8 = 0x1, 74 | AXI_WRITE16 = 0x2, 75 | AXI_WRITE32 = 0x3, 76 | AXI_WRITE64 = 0x4, 77 | AXI_READ8 = 0x5, 78 | AXI_READ16 = 0x6, 79 | AXI_READ32 = 0x7, 80 | AXI_READ64 = 0x8 81 | }; 82 | 83 | Cable* m_dev; 84 | Log* log; 85 | 86 | bool cable_connected = false; 87 | bool connected = false; 88 | 89 | pthread_mutex_t mutex; 90 | unsigned int debug_ir; 91 | int retry_count; 92 | int check_errors; 93 | int access_timeout; 94 | 95 | 96 | std::vector m_jtag_devices; 97 | unsigned int m_jtag_device_sel = 0; 98 | unsigned int m_jtag_device_default = 0; 99 | 100 | bool m_tms_on_last; 101 | 102 | js::config *bridge_config; 103 | 104 | bool reg_access_pulp(bool write, unsigned int addr, char* buffer); 105 | 106 | bool reg_access_riscv(bool write, unsigned int addr, char* buffer); 107 | bool reg_access_read_riscv(bool write, unsigned int addr, char* buffer); 108 | bool reg_access_write_riscv(bool write, unsigned int addr, char* buffer); 109 | 110 | bool write(unsigned int addr, int size, char* buffer); 111 | bool write_internal(int bitwidth, unsigned int addr, int size, char* buffer); 112 | bool write_internal_pulp(int bitwidth, unsigned int addr, int size, char* buffer); 113 | bool write_internal_riscv(int bitwidth, unsigned int addr, int size, char* buffer); 114 | 115 | bool read(unsigned int addr, int size, char* buffer); 116 | bool read_internal(int bitwidth, unsigned int addr, int size, char* buffer); 117 | bool read_internal_pulp(int bitwidth, unsigned int addr, int size, char* buffer); 118 | bool read_internal_riscv(int bitwidth, unsigned int addr, int size, char* buffer); 119 | 120 | bool read_error_reg(uint32_t *addr, bool *error); 121 | bool clear_error_reg(); 122 | 123 | bool jtag_pad_before(); 124 | bool jtag_pad_after(bool tms); 125 | 126 | bool jtag_debug(); 127 | 128 | int ir_len_detect(); 129 | int dr_len_detect(); 130 | 131 | bool jtag_axi_select(); 132 | bool jtag_auto_discovery(); 133 | bool jtag_idle(); 134 | bool jtag_set_selected_ir(char ir); 135 | 136 | bool check_connection(); 137 | bool check_cable(); 138 | 139 | bool jtag_dmi_select(); 140 | 141 | uint32_t crc_compute(uint32_t crc, char* data_in, int length_bits); 142 | }; 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /src/cables/ftdi/ftdi.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | /* 16 | * Authors: Andreas Traber 17 | */ 18 | 19 | /* 20 | * Olimex ARM-USB-OCD, ARM-USB-OCD-H, ARM-USB-TINY and ARM-USB-TINY-H pinout 21 | * 22 | * GPIO Function Comment 23 | * 0 TCK Set as output but do not drive manually 24 | * 1 TDI Set as output but do not drive manually 25 | * 2 TDO Set as input, should not be driven 26 | * 3 TMS Set as output but do not drive manually 27 | * 4 ?? GPIOL0 of FT2232H, set as output 28 | * 5 ?? GPIOL1 of FT2232H, set as input, should not be driven 29 | * 6 ?? GPIOL2 of FT2232H, set as input, should not be driven 30 | * 7 RTCK GPIOL3 of FT2232H, set as input, should not be driven 31 | * 8 TRST*) Set as output 32 | * 9 SRST**) Set as output 33 | * 10 ?? GPIOH2 of FT2232H, set as output 34 | * 11 Red LED Set as output 35 | * 12 ?? GPIOH4 of FT2232H, set as input, should not be driven 36 | * 13 ?? GPIOH5 of FT2232H, set as input, should not be driven 37 | * 14 ?? GPIOH6 of FT2232H, set as input, should not be driven 38 | * 15 ?? GPIOH7 of FT2232H, set as input, should not be driven 39 | * 40 | * *) Pin is driven by Olimex in an active-high way, i.e. 0: driven to GND by Olimex 41 | * 1: driven to VRef by Olimex 42 | * **) Pin is driven by Olimex in an active-low way, i.e. 0: not driven by Olimex -> needs to be driven to high from DUT side (V_reset) 43 | * 1: driven to GND by Olimex 44 | * 45 | * Use command SET_BITS_LOW for GPIO 0 - 7 (byte0: value, byte1: direction) 46 | * Use command SET_BITS_HIGH for GPIO 8 - 15 (byte0: value, byte1: direction) 47 | */ 48 | 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | #include "ftdi.hpp" 56 | #include "cables/log.h" 57 | 58 | 59 | #ifndef min 60 | #define min(X,Y) ((X) < (Y) ? (X) : (Y)) 61 | #endif 62 | 63 | //----------------------------------------------------------------------------- 64 | 65 | Ftdi::Ftdi(js::config *config, Log* log, FTDIDeviceID id) : Cable(config), log (log), m_id (id) 66 | { 67 | if (config->get("**/vendor") != NULL && config->get("**/product") != NULL) 68 | { 69 | m_descriptors.push_back((struct device_desc){(unsigned int)config->get_child_int("**/vendor"), (unsigned int)config->get_child_int("**/product")}); 70 | } 71 | else 72 | { 73 | // add all our known devices to the map 74 | m_descriptors.push_back((struct device_desc){0x15ba, 0x002a}); 75 | m_descriptors.push_back((struct device_desc){0x15ba, 0x002b}); 76 | 77 | m_descriptors.push_back((struct device_desc){0x0403, 0x6010}); // ftdi2232 Gapuino 78 | m_descriptors.push_back((struct device_desc){0x1d6b, 0x0002}); // ftdi2232 Gapuino 79 | } 80 | } 81 | 82 | Ftdi::~Ftdi() 83 | { 84 | ftdi_usb_close(&m_ftdic); 85 | ftdi_deinit(&m_ftdic); 86 | 87 | if (m_params.send_buf) free(m_params.send_buf); 88 | if (m_params.recv_buf) free(m_params.recv_buf); 89 | } 90 | 91 | bool 92 | Ftdi::connect(js::config *config) 93 | { 94 | char buf[256]; 95 | std::list dev_desc = m_descriptors; 96 | int error; 97 | bool result; 98 | int err; 99 | const char *description = NULL; 100 | js::config *user_gpios = config->get("user_gpios"); 101 | 102 | if (config && config->get("description") != NULL) 103 | { 104 | description = config->get("description")->get_str().c_str(); 105 | } 106 | 107 | m_params.send_buf_len = FTDX_MAXSEND; 108 | m_params.send_buffered = 0; 109 | m_params.send_buf = (char*)malloc(m_params.send_buf_len); 110 | m_params.recv_buf_len = FTDI_MAXRECV; 111 | m_params.to_recv = 0; 112 | m_params.recv_write_idx = 0; 113 | m_params.recv_read_idx = 0; 114 | m_params.recv_buf = (char*)malloc(m_params.recv_buf_len); 115 | 116 | if (!m_params.send_buf || !m_params.recv_buf) { 117 | log->error("ftdi2232: Can't allocate memory for ftdi context structures\n"); 118 | goto fail; 119 | } 120 | 121 | ftdi_init(&m_ftdic); 122 | 123 | if (config->get("bus") != NULL) 124 | { 125 | #ifdef FTDI_1_4 126 | if (ftdi_usb_open_bus_addr(&m_ftdic, config->get_child_int("**/bus"), config->get_child_int("**/device"))) 127 | { 128 | error = 1; 129 | } 130 | #else 131 | log->error("Specifying device through USB address is only supported with at least version 1.4 of libftdi\n"); 132 | goto fail; 133 | #endif 134 | } 135 | else 136 | { 137 | //--------------------------------------------------------------------------- 138 | // Device Selection 139 | if (description == NULL) { 140 | std::list dev_available; 141 | struct device_desc dev; 142 | 143 | for (std::list::iterator it = dev_desc.begin(); 144 | it != dev_desc.end(); it++) { 145 | struct ftdi_device_list* devlist; 146 | int n = ftdi_usb_find_all(&m_ftdic, &devlist, it->vid, it->pid); 147 | 148 | if (n > 0) { 149 | for(int i = 0; i < n; ++i) { 150 | if (dev_try_open(it->vid, it->pid, i)) { 151 | log->user("Found ftdi device i:0x%X:0x%X:%d\n", 152 | it->vid, it->pid, i); 153 | dev_available.push_back({.vid = it->vid, .pid = it->pid, .index = (unsigned int)i}); 154 | break; 155 | } 156 | } 157 | } 158 | 159 | ftdi_list_free2(devlist); 160 | } 161 | 162 | if (dev_available.size() == 0) { 163 | log->error("ft2232: Connection failed\n"); 164 | goto fail; 165 | } 166 | 167 | dev = dev_available.front(); 168 | log->user("Connecting to ftdi device i:0x%X:0x%X:%d\n", 169 | dev.vid, dev.pid, dev.index); 170 | error = ftdi_usb_open_desc_index(&m_ftdic, dev.vid, dev.pid, NULL, NULL, dev.index); 171 | } else { 172 | log->user("Connecting to ftdi device %s\n", description); 173 | error = ftdi_usb_open_string(&m_ftdic, description); 174 | } 175 | } 176 | 177 | if (error != 0) { 178 | if (error == -1) log->debug("usb_find_busses() failed\n"); 179 | else if (error == -2) log->debug("usb_find_devices() failed\n"); 180 | else if (error == -3) log->debug("usb device not found\n"); 181 | else if (error == -4) log->debug("unable to open device\n"); 182 | else if (error == -5) log->debug("unable to claim device\n"); 183 | else if (error == -6) log->debug("reset failed\n"); 184 | else if (error == -7) log->debug("set baudrate failed\n"); 185 | else if (error == -8) log->debug("get product description failed\n"); 186 | else if (error == -9) log->debug("get serial number failed\n"); 187 | else if (error == -10) log->debug("unable to close device\n"); 188 | else if (error == -11) log->debug("ftdi context invalid\n"); 189 | else if (error == -12) log->debug("libusb_get_device_list() failed\n"); 190 | else if (error == -13) log->debug("libusb_get_device_descriptor() failed\n"); 191 | 192 | log->warning("ft2232: Connection failed\n"); 193 | 194 | goto fail; 195 | } 196 | 197 | if(!ft2232_mpsse_open()) { 198 | log->error("ft2232: Open MPSSE mode failed\n"); 199 | goto fail; 200 | } 201 | 202 | log->debug("Connected to libftdi driver.\n"); 203 | 204 | //--------------------------------------------------------------------------- 205 | // Setup layout for different devices 206 | 207 | int buf_len; 208 | this->reverse_reset = config->get_child_bool("reverse_reset"); 209 | bits_value = 0; 210 | bits_direction = 0x1b; 211 | 212 | if (user_gpios != NULL) 213 | { 214 | for (auto x:user_gpios->get_elems()) 215 | { 216 | this->user_gpios.push_back(x->get_int()); 217 | set_bit_direction(x->get_int(), 1); 218 | } 219 | } 220 | 221 | if (config->get("system_reset_gpio") != NULL) 222 | { 223 | this->system_reset_gpio = config->get_int("system_reset_gpio"); 224 | set_bit_direction(this->system_reset_gpio, 1); 225 | if (reverse_reset) 226 | bits_value |= 1<system_reset_gpio; 227 | } 228 | 229 | if (config->get("jtag_reset_gpio") != NULL) 230 | { 231 | this->jtag_reset_gpio = config->get_int("jtag_reset_gpio"); 232 | set_bit_direction(this->jtag_reset_gpio, 1); 233 | bits_value |= 1<jtag_reset_gpio; 234 | } 235 | 236 | 237 | buf[0] = SET_BITS_LOW; // Set value & direction of ADBUS lines 238 | buf[1] = bits_value & 0xff; // values 239 | buf[2] = 0x1b; // direction (1 == output) 240 | //buf[3] = 0x8a; // Activate this command to disabled the default divider by 5, otherwise by default we can just go up to 6MHz instead of 30MHz 241 | buf[3] = TCK_DIVISOR; 242 | buf[4] = 0x02; // The divisor has been put to 2 as is not reliable on silicon with less 243 | // than that 244 | buf[5] = 0x00; 245 | buf[6] = SEND_IMMEDIATE; 246 | 247 | buf_len = 7; 248 | 249 | if(ft2232_write(buf, buf_len, 0) != buf_len) { 250 | log->error("ft2232: Initial write failed\n"); 251 | goto fail; 252 | } 253 | 254 | flush(); 255 | 256 | return true; 257 | 258 | fail: 259 | if (m_params.send_buf) free(m_params.send_buf); 260 | if (m_params.recv_buf) free(m_params.recv_buf); 261 | 262 | return false; 263 | } 264 | 265 | 266 | bool Ftdi::chip_config(uint32_t config) 267 | { 268 | for (auto x:this->user_gpios) 269 | { 270 | this->set_bit_value(x, config & 1); 271 | config >>= 1; 272 | } 273 | 274 | } 275 | 276 | bool Ftdi::chip_reset(bool active, int duration) 277 | { 278 | if (this->system_reset_gpio != -1) 279 | { 280 | if (this->reverse_reset) 281 | active = !active; 282 | 283 | if (!set_bit_value(this->system_reset_gpio, active)) 284 | return false; 285 | } 286 | 287 | if (duration > 0) 288 | usleep(duration / 1000); 289 | 290 | return true; 291 | } 292 | 293 | int 294 | Ftdi::ft2232_seq_purge(int purge_rx, int purge_tx) { 295 | int ret = 0; 296 | unsigned char buf; 297 | 298 | ret = ftdi_usb_purge_buffers(&m_ftdic); 299 | if (ret < 0) { 300 | log->warning("ft2232: ftdi_usb_purge_buffers() failed\n"); 301 | return -1; 302 | } 303 | 304 | ret = ftdi_read_data(&m_ftdic, &buf, 1); 305 | if (ret < 0) { 306 | log->warning("ft2232: ftdi_read_data() failed\n"); 307 | return -1; 308 | } 309 | 310 | return 0; 311 | } 312 | 313 | int 314 | Ftdi::ft2232_seq_reset() { 315 | if (ftdi_usb_reset(&m_ftdic) < 0) { 316 | log->warning("ft2232: ftdi_usb_reset() failed\n"); 317 | return -1; 318 | } 319 | 320 | if(ft2232_seq_purge(1, 1) < 0) { 321 | log->warning("ft2232: Could not purge\n"); 322 | return -1; 323 | } 324 | 325 | return 0; 326 | } 327 | 328 | int 329 | Ftdi::flush() { 330 | unsigned int xferred; 331 | unsigned int recvd = 0; 332 | 333 | if (m_params.send_buffered == 0) 334 | return 0; 335 | 336 | if ((xferred = ftdi_write_data(&m_ftdic, (uint8_t*)m_params.send_buf, m_params.send_buffered)) < 0) { 337 | log->warning("ft2232: ftdi_write_data() failed\n"); 338 | return -1; 339 | } 340 | 341 | if (xferred < m_params.send_buffered) { 342 | log->warning("Written fewer bytes than requested.\n"); 343 | return -1; 344 | } 345 | 346 | m_params.send_buffered = 0; 347 | 348 | /* now read all scheduled receive bytes */ 349 | if (m_params.to_recv) { 350 | if (m_params.recv_write_idx + m_params.to_recv > m_params.recv_buf_len) { 351 | /* extend receive buffer */ 352 | m_params.recv_buf_len = m_params.recv_write_idx + m_params.to_recv; 353 | if (m_params.recv_buf) 354 | m_params.recv_buf = (char*)realloc(m_params.recv_buf, m_params.recv_buf_len); 355 | } 356 | 357 | assert(m_params.recv_buf != NULL); 358 | 359 | while (recvd == 0) { 360 | recvd = ftdi_read_data(&m_ftdic, (uint8_t*)&(m_params.recv_buf[m_params.recv_write_idx]), m_params.to_recv); 361 | if (recvd < 0) 362 | log->warning("Error from ftdi_read_data()\n"); 363 | } 364 | 365 | if (recvd < m_params.to_recv) 366 | log->warning("Received less bytes than requested.\n"); 367 | 368 | m_params.to_recv -= recvd; 369 | m_params.recv_write_idx += recvd; 370 | } 371 | 372 | return xferred < 0 ? -1 : xferred; 373 | } 374 | 375 | int 376 | Ftdi::ft2232_read(char* buf, int len) { 377 | int cpy_len; 378 | int recvd = 0; 379 | 380 | /* flush send buffer to get all scheduled receive bytes */ 381 | if (flush() < 0) { 382 | log->warning("ft2232: Could not read any data after a flush\n"); 383 | return -1; 384 | } 385 | 386 | if (len == 0) { 387 | log->warning("ft2232: Please don't read 0 bits\n"); 388 | return 0; 389 | } 390 | 391 | /* check for number of remaining bytes in receive buffer */ 392 | cpy_len = m_params.recv_write_idx - m_params.recv_read_idx; 393 | 394 | if (cpy_len > len) 395 | cpy_len = len; 396 | 397 | len -= cpy_len; 398 | 399 | if (cpy_len > 0) { 400 | // get data from the receive buffer 401 | memcpy(buf, &(m_params.recv_buf[m_params.recv_read_idx]), cpy_len); 402 | m_params.recv_read_idx += cpy_len; 403 | 404 | if (m_params.recv_read_idx == m_params.recv_write_idx) 405 | m_params.recv_read_idx = m_params.recv_write_idx = 0; 406 | } 407 | 408 | if (len > 0) { 409 | /* need to get more data directly from the device */ 410 | while (recvd == 0) { 411 | recvd = ftdi_read_data(&m_ftdic, (uint8_t*)&(buf[cpy_len]), len); 412 | if (recvd < 0) 413 | log->warning("ft2232: Error from ftdi_read_data()\n"); 414 | } 415 | } 416 | 417 | return recvd < 0 ? -1 : (cpy_len + len); 418 | } 419 | 420 | int Ftdi::ft2232_write(char *buf, int len, int recv) 421 | { 422 | int xferred = 0; 423 | 424 | // this write function will try to buffer write data 425 | // buffering will be ceased and a flush triggered in two cases. 426 | 427 | // Case A: max number of scheduled receive bytes will be exceeded 428 | // with this write 429 | // Case B: max number of scheduled send bytes has been reached 430 | if ((m_params.to_recv + recv > FTDI_MAXRECV) || ((m_params.send_buffered > FTDX_MAXSEND) && (m_params.to_recv == 0))) 431 | xferred = flush(); 432 | 433 | if (xferred < 0) { 434 | log->warning("ft2232: Flush before write failed\n"); 435 | return -1; 436 | } 437 | 438 | // now buffer this write 439 | if (m_params.send_buffered + len > m_params.send_buf_len) { 440 | m_params.send_buf_len = m_params.send_buffered + len; 441 | 442 | if (m_params.send_buf) 443 | m_params.send_buf = (char*)realloc(m_params.send_buf, m_params.send_buf_len); 444 | } 445 | 446 | assert(m_params.send_buf); 447 | 448 | memcpy( &(m_params.send_buf[m_params.send_buffered]), buf, len); 449 | m_params.send_buffered += len; 450 | if (recv > 0) 451 | m_params.to_recv += recv; 452 | 453 | if (recv < 0) { 454 | // immediate write requested, so flush the buffered data 455 | xferred = flush(); 456 | } 457 | 458 | return xferred < 0 ? -1 : len; 459 | } 460 | 461 | bool Ftdi::ft2232_mpsse_open() 462 | { 463 | char buf[3]; 464 | int ret; 465 | 466 | // This sequence might seem weird and containing superfluous stuff. 467 | // However, it's built after the description of JTAG_InitDevice 468 | // Ref. FTCJTAGPG10.pdf 469 | // Intermittent problems will occur when certain steps are skipped. 470 | 471 | ret = ft2232_seq_reset(); 472 | if (ret < 0) 473 | goto fail; 474 | 475 | ret = ft2232_seq_purge(1, 0); 476 | if (ret < 0) 477 | goto fail; 478 | 479 | ret = ftdi_write_data_set_chunksize(&m_ftdic, FTDX_MAXSEND_MPSSE); 480 | if (ret < 0) { 481 | log->warning("ft2232: Got error %s\n", ftdi_get_error_string(&m_ftdic)); 482 | goto fail; 483 | } 484 | 485 | ret = ftdi_read_data_set_chunksize(&m_ftdic, FTDX_MAXSEND_MPSSE); 486 | if (ret < 0) { 487 | log->warning("ft2232: Got error %s\n", ftdi_get_error_string(&m_ftdic)); 488 | goto fail; 489 | } 490 | 491 | /* set a reasonable latency timer value 492 | if this value is too low then the chip will send intermediate result data 493 | in short packets (suboptimal performance) */ 494 | ret = ftdi_set_latency_timer(&m_ftdic, 1); 495 | if (ret < 0) { 496 | log->warning("ft2232: ftdi_set_latency_timer() failed\n"); 497 | goto fail; 498 | } 499 | 500 | ret = ftdi_set_bitmode(&m_ftdic, 0x0b, BITMODE_MPSSE); 501 | if (ret < 0) { 502 | log->warning("ft2232: ftdi_set_bitmode() failed\n"); 503 | goto fail; 504 | } 505 | 506 | ret = ftdi_usb_reset(&m_ftdic); 507 | if (ret < 0) { 508 | log->warning("ft2232: ftdi_usb_reset() failed\n"); 509 | goto fail; 510 | } 511 | 512 | ret = ft2232_seq_purge(1, 0); 513 | if (ret < 0) { 514 | log->warning("ft2232: Could not purge\n"); 515 | goto fail; 516 | } 517 | 518 | // set TCK Divisor 519 | buf[0] = TCK_DIVISOR; 520 | buf[1] = 0x2; 521 | buf[2] = 0x0; 522 | ret = ft2232_write(buf, 3, 0 ); 523 | if (ret < 0) { 524 | log->warning("ft2232: Failed to set TCK divisor\n"); 525 | goto fail; 526 | } 527 | 528 | // switch off loopback 529 | buf[0] = LOOPBACK_END; 530 | ret = ft2232_write(buf, 1, 0); 531 | if (ret < 0) { 532 | log->warning("ft2232: Failed to switch off loopback\n"); 533 | goto fail; 534 | } 535 | 536 | ret = flush(); 537 | if (ret < 0) { 538 | goto fail; 539 | } 540 | 541 | ret = ftdi_usb_reset(&m_ftdic); 542 | if (ret < 0) { 543 | log->warning("ft2232: ftdi_usb_reset() failed\n"); 544 | goto fail; 545 | } 546 | 547 | ret = ft2232_seq_purge(1, 0); 548 | if (ret < 0) { 549 | log->warning("ft2232: Could not purge\n"); 550 | goto fail; 551 | } 552 | 553 | return true; 554 | 555 | fail: 556 | log->warning("ft2232: Opening device in mpsse mode failed\n"); 557 | 558 | ftdi_usb_close(&m_ftdic); 559 | ftdi_deinit(&m_ftdic); 560 | 561 | return false; 562 | } 563 | 564 | bool Ftdi::dev_try_open(unsigned int vid, unsigned int pid, unsigned int index) const 565 | { 566 | struct ftdi_context ftdic; 567 | int error; 568 | 569 | ftdi_init(&ftdic); 570 | 571 | error = ftdi_usb_open_desc_index(&ftdic, vid, pid, NULL, NULL, index); 572 | if (error != 0) { 573 | ftdi_deinit(&ftdic); 574 | return false; 575 | } 576 | 577 | ftdi_usb_close(&ftdic); 578 | ftdi_deinit(&ftdic); 579 | 580 | return true; 581 | } 582 | 583 | bool Ftdi::bit_out(char outbit, bool last) 584 | { 585 | return stream_out_internal(&outbit, 1, false, last); 586 | } 587 | 588 | bool Ftdi::bit_inout(char* inbit, char outbit, bool last) 589 | { 590 | return stream_inout(inbit, &outbit, 1, last); 591 | } 592 | 593 | bool Ftdi::stream_out(char* outstream, unsigned int n_bits, bool last) 594 | { 595 | return stream_out_internal(outstream, n_bits, false, last); 596 | } 597 | 598 | bool Ftdi::stream_out_internal(char* outstream, unsigned int n_bits, bool postread, bool last) 599 | { 600 | unsigned int len_bytes; 601 | unsigned int len_bits; 602 | unsigned int len_tms_bits; 603 | char buf; 604 | 605 | len_tms_bits = last ? 1 : 0; 606 | len_bytes = (n_bits - len_tms_bits) / 8; 607 | len_bits = (n_bits - len_tms_bits) % 8; 608 | 609 | if(len_bytes > 0) { 610 | if (ft2232_write_bytes(outstream, len_bytes, postread) < 0) { 611 | log->warning("ft2232: ftdi_stream_out has failed\n"); 612 | return false; 613 | } 614 | } 615 | 616 | if(len_bits > 0) { 617 | if (ft2232_write_bits(&(outstream[len_bytes]), len_bits, postread, 0) < 0) { 618 | log->warning("ft2232: ftdi_stream_out has failed\n"); 619 | return false; 620 | } 621 | } 622 | 623 | if(len_tms_bits > 0) { 624 | buf = outstream[len_bytes] >> len_bits; 625 | if (ft2232_write_bits(&buf, 1, postread, 1) < 0) { 626 | log->warning("ft2232: ftdi_stream_out has failed\n"); 627 | return false; 628 | } 629 | } 630 | 631 | return true; 632 | } 633 | 634 | bool Ftdi::stream_in(char* instream, unsigned int n_bits, bool last) 635 | { 636 | int len_bytes; 637 | int len_bits; 638 | int len_tms_bits; 639 | 640 | len_tms_bits = last ? 1 : 0; 641 | len_bytes = (n_bits - len_tms_bits) / 8; 642 | len_bits = (n_bits - len_tms_bits) % 8; 643 | 644 | if(len_bytes > 0) { 645 | if (ft2232_read_packed_bits(instream, len_bytes, 8, 0) < 0) { 646 | log->warning("ft2232: fdti_stream_in has failed\n"); 647 | return false; 648 | } 649 | } 650 | 651 | if(len_bits > 0) { 652 | if (ft2232_read_packed_bits(instream, 1, len_bits, len_bytes * 8) < 0) { 653 | log->warning("ft2232: fdti_stream_in has failed\n"); 654 | return false; 655 | } 656 | } 657 | 658 | if(len_tms_bits > 0) { 659 | if (ft2232_read_packed_bits(instream, 1, 1, (len_bits + (len_bytes * 8))) < 0) { 660 | log->warning("ft2232: fdti_stream_in has failed\n"); 661 | return false; 662 | } 663 | } 664 | 665 | return true; 666 | } 667 | 668 | bool Ftdi::stream_inout(char* instream, char* outstream, unsigned int n_bits, bool last) 669 | { 670 | if (outstream) 671 | { 672 | if (!stream_out_internal(outstream, n_bits, instream != NULL, last)) { 673 | log->warning("ft2232: ftdi_stream_inout has failed\n"); 674 | return false; 675 | } 676 | } 677 | else 678 | { 679 | int bytes = (n_bits + 7) / 8; 680 | char buffer[bytes]; 681 | ::memset(buffer, 0, bytes); 682 | if (!stream_out_internal(buffer, n_bits, instream != NULL, last)) { 683 | log->warning("ft2232: ftdi_stream_inout has failed\n"); 684 | return false; 685 | } 686 | } 687 | 688 | if (instream && !stream_in(instream, n_bits, last)) { 689 | log->warning("ft2232: ftdi_stream_inout has failed\n"); 690 | return false; 691 | } 692 | 693 | return true; 694 | } 695 | 696 | int Ftdi::ft2232_write_bytes(char *buf, int len, bool postread) 697 | { 698 | int cur_command_size; 699 | int max_command_size; 700 | int cur_chunk_len; 701 | int recv; 702 | int xferred; 703 | char *mybuf; 704 | 705 | if(len == 0) 706 | return 0; 707 | 708 | recv = 0; 709 | max_command_size = min(len, 65536)+3; 710 | mybuf = (char*) malloc(max_command_size); 711 | 712 | /// Command OPCODE: write bytes 713 | mybuf[0] = MPSSE_DO_WRITE | MPSSE_LSB | MPSSE_WRITE_NEG; 714 | if(postread) // if postread is enabled it will buffer incoming bytes 715 | mybuf[0] = mybuf[0] | MPSSE_DO_READ; 716 | 717 | // We divide the transmitting stream of bytes in chunks with a maximun length of 65536 bytes each. 718 | while(len > 0) { 719 | cur_chunk_len = min(len, 65536); 720 | len = len - cur_chunk_len; 721 | cur_command_size = cur_chunk_len + 3; 722 | 723 | /// Low and High bytes of the length field 724 | mybuf[1] = (unsigned char) ( cur_chunk_len - 1); 725 | mybuf[2] = (unsigned char) ((cur_chunk_len - 1) >> 8); 726 | 727 | /// The rest of the command is filled with the bytes that will be transferred 728 | memcpy(&(mybuf[3]), buf, cur_chunk_len ); 729 | buf = buf + cur_chunk_len; 730 | 731 | /// Finally we can transmit the command 732 | xferred = ft2232_write(mybuf, cur_command_size, (postread ? cur_chunk_len : 0) ); 733 | if(xferred != cur_command_size) { 734 | log->warning("ft2232: could not transmit command\n"); 735 | free(mybuf); 736 | return -1; 737 | } 738 | 739 | // If OK, the update the number of incoming bytes that are being buffered for a posterior read 740 | if(postread) 741 | recv = recv + cur_chunk_len; 742 | } 743 | 744 | free(mybuf); 745 | 746 | // Returns the number of buffered incoming bytes 747 | return recv; 748 | } 749 | 750 | int Ftdi::ft2232_write_bits(char *buf, int len, bool postread, bool with_tms) 751 | { 752 | int max_command_size; 753 | int max_chunk_len; 754 | int cur_chunk_len; 755 | int recv; 756 | int xferred; 757 | int i; 758 | char mybuf[3]; 759 | 760 | if(len == 0) 761 | return 0; 762 | 763 | max_command_size = 3; 764 | 765 | if(!with_tms) { 766 | /// Command OPCODE: write bits (can write up to 8 bits in a single command) 767 | max_chunk_len = 8; 768 | mybuf[0] = MPSSE_DO_WRITE | MPSSE_LSB | MPSSE_WRITE_NEG | MPSSE_BITMODE; 769 | } 770 | else { 771 | /// Command OPCODE: 0x4B write bit with tms (can write up to 1 bits in a single command) 772 | max_chunk_len = 1; 773 | mybuf[0] = MPSSE_WRITE_TMS|MPSSE_LSB|MPSSE_BITMODE|MPSSE_WRITE_NEG; 774 | } 775 | 776 | if(postread) // (OPCODE += 0x20) if postread is enabled it will buffer incoming bits 777 | mybuf[0] = mybuf[0] | MPSSE_DO_READ; 778 | 779 | // We divide the transmitting stream of bytes in chunks with a maximun length of max_chunk_len bits each. 780 | i = 0; 781 | recv = 0; 782 | while(len > 0) { 783 | cur_chunk_len = min(len, max_chunk_len); 784 | len = len - cur_chunk_len; 785 | 786 | // Bit length field 787 | mybuf[1] = (char) (cur_chunk_len - 1); 788 | 789 | 790 | if(!with_tms) { 791 | /// The last byte of the command is filled with the bits that will be transferred 792 | mybuf[2] = buf[i/8]; 793 | i += 8; 794 | } 795 | else { 796 | mybuf[2] = 0x01 | ((buf[(i/8)] >> (i%8)) << 7); 797 | i++; 798 | } 799 | 800 | // Finally we can transmit the command 801 | xferred = ft2232_write(mybuf, max_command_size, (postread ? 1 : 0) ); 802 | if(xferred != max_command_size) { 803 | log->warning("ft2232: ftdi write has failed\n"); 804 | return -1; 805 | } 806 | 807 | // If OK, the update the number of incoming bytes that are being buffered for a posterior read 808 | if(postread) 809 | recv = recv + 1; 810 | } 811 | 812 | if (flush() < 0) 813 | return -1; 814 | 815 | return recv; 816 | } 817 | 818 | int Ftdi::ft2232_read_packed_bits(char *buf, int packet_len, int bits_per_packet, int offset) 819 | { 820 | char *mybuf; 821 | unsigned char dst_mask; 822 | unsigned char src_mask; 823 | int row_offset; 824 | int dst_row; 825 | int dst_col; 826 | int src_row; 827 | int src_col; 828 | int i; 829 | 830 | if(packet_len == 0 || bits_per_packet == 0) 831 | return 0; 832 | 833 | if (offset == 0 && bits_per_packet == 8) 834 | { 835 | if(ft2232_read(buf, packet_len) < 0) { 836 | log->warning("Read failed\n"); 837 | return -1; 838 | } 839 | } 840 | else 841 | { 842 | mybuf = (char*) malloc(packet_len); 843 | if(ft2232_read(mybuf, packet_len) < 0) { 844 | log->warning("Read failed\n"); 845 | free(mybuf); 846 | return -1; 847 | } 848 | 849 | if(bits_per_packet < 8) { 850 | for(i=0; i < packet_len; i++) { // rotate bits to the left side 851 | mybuf[i] = (mybuf[i] >> (8-bits_per_packet)); 852 | } 853 | 854 | for(i = offset; i < (packet_len*bits_per_packet+offset); i++) { 855 | dst_row = i / 8; 856 | dst_col = i % 8; 857 | src_row = (i-offset) / bits_per_packet; 858 | src_col = (i-offset) % bits_per_packet; 859 | dst_mask = ~(1 << dst_col); 860 | src_mask = (1 << src_col); 861 | buf[dst_row] = (buf[dst_row] & dst_mask) | ((mybuf[src_row] & src_mask) >> (dst_col - src_col)); 862 | } 863 | } else if(bits_per_packet == 8) { 864 | row_offset = offset / 8; 865 | memcpy( &(buf[row_offset]), mybuf, packet_len); 866 | } else { 867 | free(mybuf); 868 | return -1; 869 | } 870 | 871 | free(mybuf); 872 | } 873 | 874 | return 0; 875 | } 876 | 877 | bool Ftdi::set_bit_value(int bit, int value) 878 | { 879 | 880 | char buf[4]; 881 | 882 | bits_value = (bits_value & ~(1<= 8) 884 | { 885 | buf[0] = SET_BITS_HIGH; 886 | buf[1] = bits_value >> 8; 887 | buf[2] = bits_direction >> 8; 888 | buf[3] = SEND_IMMEDIATE; 889 | } 890 | else 891 | { 892 | buf[0] = SET_BITS_LOW; 893 | buf[1] = bits_value; 894 | buf[2] = bits_direction; 895 | buf[3] = SEND_IMMEDIATE; 896 | } 897 | 898 | if (ft2232_write(buf, 4, 0) != 4) return false; 899 | flush(); 900 | return true; 901 | } 902 | 903 | bool Ftdi::set_bit_value_del(int bit, int value, int del) 904 | { 905 | 906 | char buf[4]; 907 | 908 | bits_value = (bits_value & ~(1<= 8) 910 | { 911 | buf[0] = SET_BITS_HIGH; 912 | buf[1] = bits_value >> 8; 913 | buf[2] = bits_direction >> 8; 914 | buf[3] = SEND_IMMEDIATE; 915 | } 916 | else 917 | { 918 | buf[0] = SET_BITS_LOW; 919 | buf[1] = bits_value; 920 | buf[2] = bits_direction; 921 | buf[3] = SEND_IMMEDIATE; 922 | } 923 | 924 | if (ft2232_write(buf, 4, 0) != 4) return false; 925 | usleep(del); 926 | flush(); 927 | return true; 928 | } 929 | 930 | bool Ftdi::set_bit_direction(int bit, int isout) 931 | { 932 | bits_direction = (bits_direction & ~(1<jtag_reset_gpio != -1) 938 | return set_bit_value(this->jtag_reset_gpio, !active); 939 | return true; 940 | } 941 | 942 | -------------------------------------------------------------------------------- /src/cables/ftdi/ftdi.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | /* 16 | * Authors: Andreas Traber 17 | */ 18 | 19 | #ifndef MEM_FTDI_LL_H 20 | #define MEM_FTDI_LL_H 21 | 22 | #include "cables/adv_dbg_itf/adv_dbg_itf.hpp" 23 | #include "cable.hpp" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | extern "C" { 30 | #include 31 | } 32 | 33 | #define FTDX_MAXSEND 4096 34 | #define FTDX_MAXSEND_MPSSE (64 * 1024) 35 | #define FTDI_MAXRECV ( 4 * 64) 36 | 37 | struct ftdi_param { 38 | uint32_t send_buf_len; 39 | uint32_t send_buffered; 40 | char *send_buf; 41 | uint32_t recv_buf_len; 42 | uint32_t to_recv; 43 | uint32_t recv_write_idx; 44 | uint32_t recv_read_idx; 45 | char *recv_buf; 46 | }; 47 | 48 | class Log; 49 | 50 | class Ftdi : public Cable { 51 | public: 52 | 53 | enum FTDIDeviceID { 54 | Olimex, 55 | Digilent, 56 | Generic, 57 | }; 58 | 59 | Ftdi(js::config *config, Log* log, FTDIDeviceID id); 60 | ~Ftdi(); 61 | 62 | bool connect(js::config *config); 63 | 64 | bool bit_inout(char* inbit, char outbit, bool last); 65 | 66 | bool stream_inout(char* instream, char* outstream, unsigned int n_bits, bool last); 67 | 68 | bool jtag_reset(bool active); 69 | 70 | int flush(); 71 | 72 | 73 | 74 | bool chip_reset(bool active, int duration); 75 | bool chip_config(uint32_t config); 76 | 77 | private: 78 | struct device_desc { 79 | unsigned int vid; 80 | unsigned int pid; 81 | unsigned int index; 82 | }; 83 | 84 | bool set_bit_value(int bit, int value); 85 | bool set_bit_value_del(int bit, int value, int del); 86 | bool set_bit_direction(int bit, int isout); 87 | 88 | bool bit_out(char outbit, bool tms); 89 | 90 | bool stream_out(char* outstream, unsigned int n_bits, bool last); 91 | bool stream_in(char* instream, unsigned int n_bits, bool last); 92 | 93 | void state_trans_tms(int tms); 94 | 95 | bool stream_out_internal(char* outstream, unsigned int n_bits, bool postread, bool last); 96 | 97 | int ft2232_write_bytes(char *buf, int len, bool postread); 98 | int ft2232_write_bits(char *buf, int len, bool postread, bool with_tms); 99 | int ft2232_read_packed_bits(char *buf, int packet_len, int bits_per_packet, int offset); 100 | 101 | bool ft2232_common_open(); 102 | bool ft2232_mpsse_open(); 103 | int ft2232_seq_purge(int purge_rx, int purge_tx); 104 | int ft2232_seq_reset(); 105 | int ft2232_read(char* buf, int len); 106 | int ft2232_write(char *buf, int len, int recv); 107 | bool dev_try_open(unsigned int vid, unsigned int pid, unsigned int index) const; 108 | 109 | std::list m_descriptors; 110 | std::vector user_gpios; 111 | 112 | Log* log; 113 | FTDIDeviceID m_id; 114 | struct ftdi_param m_params; 115 | struct ftdi_context m_ftdic; 116 | unsigned int bits_value; 117 | unsigned int bits_direction; 118 | int system_reset_gpio = -1; 119 | int jtag_reset_gpio = -1; 120 | bool reverse_reset = false; 121 | 122 | }; 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /src/cables/jtag-proxy/jtag-proxy.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "cables/log.h" 35 | #include "jtag-proxy.hpp" 36 | #include "debug_bridge/proxy.hpp" 37 | 38 | Jtag_proxy::Jtag_proxy(Log* log) : Cable(NULL) 39 | { 40 | } 41 | 42 | bool Jtag_proxy::connect(js::config *config) 43 | { 44 | struct sockaddr_in addr; 45 | struct hostent *he; 46 | 47 | js::config *proxy_config = config->get("jtag-proxy"); 48 | 49 | if (proxy_config == NULL || proxy_config->get("port") == NULL) 50 | { 51 | fprintf(stderr, "Didn't find any information for JTAG proxy\n"); 52 | return false; 53 | } 54 | 55 | int m_port = proxy_config->get("port")->get_int(); 56 | char *m_server = (char *)"localhost"; 57 | 58 | if((m_socket = socket(PF_INET, SOCK_STREAM, 0)) < 0) { 59 | fprintf(stderr, "Unable to create socket (%s)\n", strerror(errno)); 60 | return false; 61 | } 62 | 63 | if((he = gethostbyname(m_server)) == NULL) { 64 | perror("gethostbyname"); 65 | return false; 66 | } 67 | 68 | addr.sin_family = AF_INET; 69 | addr.sin_port = htons(m_port); 70 | addr.sin_addr = *((struct in_addr *)he->h_addr_list[0]); 71 | memset(addr.sin_zero, '\0', sizeof(addr.sin_zero)); 72 | 73 | if(::connect(m_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) { 74 | fprintf(stderr, "Unable to connect to %s port %d (%s)\n", m_server, m_port, 75 | strerror(errno)); 76 | return false; 77 | } 78 | return true; 79 | } 80 | 81 | bool Jtag_proxy::bit_inout(char* inbit, char outbit, bool last) 82 | { 83 | return stream_inout(inbit, &outbit, 1, last); 84 | } 85 | 86 | bool Jtag_proxy::proxy_stream(char* instream, char* outstream, unsigned int n_bits, bool last, int bit) 87 | { 88 | proxy_req_t req = { .type=DEBUG_BRIDGE_JTAG_REQ }; 89 | req.jtag.bits = n_bits; 90 | req.jtag.tdo = instream != NULL; 91 | 92 | if (n_bits >= (1<<16)) return false; 93 | 94 | uint8_t buffer[n_bits]; 95 | uint8_t value; 96 | if (outstream) 97 | { 98 | for (int i=0; i>= 1; 111 | } 112 | } 113 | else 114 | { 115 | ::memset(buffer, 0, n_bits); 116 | } 117 | 118 | if (last) 119 | { 120 | buffer[n_bits-1] |= 1 << DEBUG_BRIDGE_JTAG_TMS; 121 | } 122 | 123 | ::send(m_socket, (void *)&req, sizeof(req), 0); 124 | ::send(m_socket, (void *)buffer, n_bits, 0); 125 | if (instream != NULL) 126 | { 127 | 128 | ::memset((void *)instream, 0, (n_bits + 7) / 8); 129 | if (::recv(m_socket, (void *)instream, (n_bits + 7) / 8, 0) != (n_bits + 7) / 8) return false; 130 | 131 | } 132 | return true; 133 | } 134 | 135 | bool Jtag_proxy::stream_inout(char* instream, char* outstream, unsigned int n_bits, bool last) 136 | { 137 | return proxy_stream(instream, outstream, n_bits, last, DEBUG_BRIDGE_JTAG_TDI); 138 | } 139 | 140 | bool Jtag_proxy::jtag_reset(bool active) 141 | { 142 | int value = !active; 143 | return proxy_stream(NULL, (char *)&value, 1, 0, DEBUG_BRIDGE_JTAG_TRST); 144 | } 145 | 146 | int Jtag_proxy::flush() 147 | { 148 | return true; 149 | } 150 | 151 | bool Jtag_proxy::chip_reset(bool active, int duration) 152 | { 153 | proxy_req_t req = { .type=DEBUG_BRIDGE_RESET_REQ }; 154 | req.reset.active = active; 155 | req.reset.duration = duration; 156 | ::send(m_socket, (void *)&req, sizeof(req), 0); 157 | 158 | return true; 159 | } 160 | 161 | bool Jtag_proxy::chip_config(uint32_t config) 162 | { 163 | proxy_req_t req = { .type=DEBUG_BRIDGE_CONFIG_REQ }; 164 | req.config.value = config; 165 | ::send(m_socket, (void *)&req, sizeof(req), 0); 166 | return true; 167 | } 168 | -------------------------------------------------------------------------------- /src/cables/jtag-proxy/jtag-proxy.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 19 | */ 20 | 21 | 22 | #include "cables/adv_dbg_itf/adv_dbg_itf.hpp" 23 | #include "cable.hpp" 24 | 25 | #include 26 | 27 | class Jtag_proxy : public Cable { 28 | public: 29 | 30 | Jtag_proxy(Log* log); 31 | 32 | bool connect(js::config *config); 33 | 34 | bool bit_inout(char* inbit, char outbit, bool last); 35 | 36 | bool stream_inout(char* instream, char* outstream, unsigned int n_bits, bool last); 37 | 38 | bool jtag_reset(bool active); 39 | 40 | int flush(); 41 | 42 | 43 | 44 | bool chip_reset(bool active, int duration); 45 | bool chip_config(uint32_t config); 46 | 47 | private: 48 | 49 | int m_socket; 50 | 51 | bool proxy_stream(char* instream, char* outstream, unsigned int n_bits, bool last, int bit); 52 | 53 | }; -------------------------------------------------------------------------------- /src/cables/jtag.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 19 | */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "cable.hpp" 26 | 27 | 28 | #define JTAG_SOC_INSTR_WIDTH 0x4 29 | #define JTAG_SOC_IDCODE 0x2 30 | #define JTAG_SOC_AXIREG 0x4 31 | #define JTAG_SOC_BBMUXREG 0x5 32 | #define JTAG_SOC_CLKGATEREG 0x6 33 | #define JTAG_SOC_CONFREG 0x7 34 | #define JTAG_SOC_TESTMODEREG 0x8 35 | #define JTAG_SOC_BISTREG 0x9 36 | #define JTAG_SOC_BYPASS 0xf 37 | #define JTAG_SOC_IDCODE_WIDTH 32 38 | #define JTAG_SOC_AXIREG_WIDTH 96 39 | #define JTAG_SOC_BBMUXREG_WIDTH 21 40 | #define JTAG_SOC_CLKGATEREG_WIDTH 11 41 | #define JTAG_SOC_CONFREG_WIDTH 4 42 | #define JTAG_SOC_TESTMODEREG_WIDTH 4 43 | #define JTAG_SOC_BISTREG_WIDTH 20 44 | 45 | #define JTAG_CLUSTER_INSTR_WIDTH 4 46 | #define JTAG_CLUSTER_IDCODE 2 47 | #define JTAG_CLUSTER_SAMPLE_PRELOAD 1 48 | #define JTAG_CLUSTER_EXTEST 0 49 | #define JTAG_CLUSTER_DEBUG 8 50 | #define JTAG_CLUSTER_MBIST 9 51 | #define JTAG_CLUSTER_BYPASS 0xf 52 | #define JTAG_CLUSTER_IDCODE_WIDTH 32 53 | 54 | #define JTAG_IDCODE_WIDTH JTAG_CLUSTER_IDCODE_WIDTH + JTAG_SOC_IDCODE_WIDTH 55 | #define JTAG_INSTR_WIDTH JTAG_CLUSTER_INSTR_WIDTH + JTAG_SOC_INSTR_WIDTH 56 | 57 | 58 | bool Cable_jtag_itf::jtag_soft_reset() { 59 | for (int i = 0; i < 10; i++) 60 | jtag_write_tms(1); 61 | 62 | jtag_write_tms(0); 63 | 64 | return true; 65 | } 66 | 67 | bool Cable_jtag_itf::jtag_write_tms(int val) 68 | { 69 | return bit_inout(NULL, 0x0, val != 0); 70 | } 71 | 72 | bool Cable_jtag_itf::jtag_shift_ir() 73 | { 74 | if (!jtag_write_tms(1)) return false; 75 | if (!jtag_write_tms(1)) return false; 76 | if (!jtag_write_tms(0)) return false; 77 | if (!jtag_write_tms(0)) return false; 78 | return true; 79 | } 80 | 81 | bool Cable_jtag_itf::jtag_shift_dr() 82 | { 83 | if (!jtag_write_tms(1)) return false; 84 | if (!jtag_write_tms(0)) return false; 85 | if (!jtag_write_tms(0)) return false; 86 | return true; 87 | } 88 | 89 | bool Cable_jtag_itf::jtag_idle() 90 | { 91 | if (!jtag_write_tms(1)) return false; 92 | if (!jtag_write_tms(0)) return false; 93 | return true; 94 | } 95 | 96 | bool Cable_jtag_itf::jtag_shift(int width, char *bits) 97 | { 98 | return stream_inout(NULL, bits, width, 1); 99 | } 100 | 101 | bool Cable_jtag_itf::jtag_shift_ir(unsigned int ir, int ir_len) 102 | { 103 | if (ir_len == -1) 104 | ir_len = JTAG_SOC_INSTR_WIDTH; 105 | 106 | if (!jtag_shift_ir()) return false; 107 | if (!jtag_shift(ir_len, (char *)&ir)) return false; 108 | if (!jtag_idle()) return false; 109 | return true; 110 | } 111 | 112 | bool Cable_jtag_itf::jtag_set_reg(unsigned int reg, int width, unsigned int value, int ir_len) 113 | { 114 | if (!jtag_shift_ir(reg, ir_len)) return false; 115 | if (!jtag_shift_dr()) return false; 116 | if (!jtag_shift(width, (char *)&value)) return false; 117 | if (!jtag_idle()) return false; 118 | return true; 119 | } 120 | 121 | bool Cable_jtag_itf::jtag_get_reg(unsigned int reg, int width, unsigned int *out_value, unsigned int value, int ir_len) 122 | { 123 | if (!jtag_shift_ir(reg, ir_len)) return false; 124 | if (!jtag_shift_dr()) return false; 125 | if (!stream_inout((char *)out_value, (char *)&value, width, 1)) return false; 126 | if (!jtag_idle()) return false; 127 | return true; 128 | } 129 | -------------------------------------------------------------------------------- /src/cables/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 19 | */ 20 | 21 | #ifndef LOG_H 22 | #define LOG_H 23 | 24 | typedef enum 25 | { 26 | LOG_ERROR = 0, 27 | LOG_WARNING = 1, 28 | LOG_INFO = 2, 29 | LOG_DEBUG = 3 30 | } log_level_e; 31 | 32 | class Log { 33 | public: 34 | void print(log_level_e, const char *str, ...); 35 | void error(const char *str, ...) ; 36 | void warning(const char *str, ...) ; 37 | void user(const char *str, ...) ; 38 | void debug(const char *str, ...) ; 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/gdb-server/breakpoints.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Andreas Traber 19 | */ 20 | 21 | 22 | #include "gdb-server.hpp" 23 | 24 | #include 25 | #include 26 | 27 | #define INSN_IS_COMPRESSED(instr) ((instr & 0x3) != 0x3) 28 | #define INSN_BP_COMPRESSED 0x9002 29 | #define INSN_BP 0x00100073 30 | 31 | Breakpoints::Breakpoints(Gdb_server *top) 32 | : top(top) { 33 | } 34 | 35 | bool 36 | Breakpoints::insert(unsigned int addr) { 37 | bool retval; 38 | uint32_t data_bp; 39 | struct bp_insn bp; 40 | 41 | bp.addr = addr; 42 | retval = top->cable->access(false, addr, 4, (char*)&bp.insn_orig); 43 | bp.is_compressed = INSN_IS_COMPRESSED(bp.insn_orig); 44 | 45 | breakpoints.push_back(bp); 46 | 47 | if (bp.is_compressed) { 48 | data_bp = INSN_BP_COMPRESSED; 49 | retval = retval && top->cable->access(true, addr, 2, (char*)&data_bp); 50 | } else { 51 | data_bp = INSN_BP; 52 | retval = retval && top->cable->access(true, addr, 4, (char*)&data_bp); 53 | } 54 | 55 | this->top->target->flush(); 56 | 57 | return retval; 58 | } 59 | 60 | bool 61 | Breakpoints::remove(unsigned int addr) { 62 | 63 | bool retval; 64 | bool is_compressed; 65 | uint32_t data; 66 | for (std::list::iterator it = breakpoints.begin(); it != breakpoints.end(); it++) { 67 | if (it->addr == addr) { 68 | data = it->insn_orig; 69 | is_compressed = it->is_compressed; 70 | 71 | breakpoints.erase(it); 72 | 73 | if (is_compressed) 74 | retval = top->cable->access(true, addr, 2, (char*)&data); 75 | else 76 | retval = top->cable->access(true, addr, 4, (char*)&data); 77 | 78 | this->top->target->flush(); 79 | 80 | return retval; 81 | } 82 | } 83 | 84 | return false; 85 | } 86 | 87 | bool 88 | Breakpoints::clear() { 89 | 90 | bool retval = this->disable_all(); 91 | 92 | breakpoints.clear(); 93 | 94 | return retval; 95 | } 96 | 97 | 98 | bool 99 | Breakpoints::at_addr(unsigned int addr) { 100 | for (std::list::iterator it = breakpoints.begin(); it != breakpoints.end(); it++) { 101 | if (it->addr == addr) { 102 | // we found our bp 103 | return true; 104 | } 105 | } 106 | 107 | return false; 108 | } 109 | 110 | bool 111 | Breakpoints::enable(unsigned int addr) { 112 | bool retval; 113 | uint32_t data; 114 | 115 | for (std::list::iterator it = breakpoints.begin(); it != breakpoints.end(); it++) { 116 | if (it->addr == addr) { 117 | if (it->is_compressed) { 118 | data = INSN_BP_COMPRESSED; 119 | retval = top->cable->access(1, addr, 2, (char*)&data); 120 | } else { 121 | data = INSN_BP; 122 | retval = top->cable->access(1, addr, 4, (char*)&data); 123 | } 124 | 125 | return true; 126 | //return retval && m_cache->flush(); 127 | } 128 | } 129 | 130 | fprintf(stderr, "bp_enable: Did not find any bp at addr %08X\n", addr); 131 | 132 | return false; 133 | } 134 | 135 | bool 136 | Breakpoints::disable(unsigned int addr) { 137 | bool retval; 138 | 139 | for (std::list::iterator it = breakpoints.begin(); it != breakpoints.end(); it++) { 140 | if (it->addr == addr) { 141 | if (it->is_compressed) 142 | retval = top->cable->access(1, addr, 2, (char*)&it->insn_orig); 143 | else 144 | retval = top->cable->access(1, addr, 4, (char*)&it->insn_orig); 145 | 146 | return true; 147 | //return retval && m_cache->flush(); 148 | } 149 | } 150 | 151 | fprintf(stderr, "bp_enable: Did not find any bp at addr %08X\n", addr); 152 | 153 | return false; 154 | } 155 | 156 | bool 157 | Breakpoints::enable_all() { 158 | bool retval = true; 159 | 160 | for (std::list::iterator it = breakpoints.begin(); it != breakpoints.end(); it++) { 161 | retval = retval && this->enable(it->addr); 162 | } 163 | 164 | return retval; 165 | } 166 | 167 | bool 168 | Breakpoints::disable_all() { 169 | bool retval = true; 170 | 171 | for (std::list::iterator it = breakpoints.begin(); it != breakpoints.end(); it++) { 172 | retval = retval && this->disable(it->addr); 173 | } 174 | 175 | return retval; 176 | } 177 | -------------------------------------------------------------------------------- /src/gdb-server/gdb-server.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Andreas Traber 19 | */ 20 | 21 | #include "cable.hpp" 22 | #include "gdb-server/gdb-server.hpp" 23 | #include 24 | 25 | 26 | Gdb_server::Gdb_server(Log *log, Cable *cable, js::config *config, int socket_port) 27 | : log(log), cable(cable), config(config) 28 | { 29 | target = new Target(this); 30 | 31 | bkp = new Breakpoints(this); 32 | 33 | rsp = new Rsp(this, socket_port); 34 | 35 | if (!rsp->open()) throw std::logic_error("Unable to open RSP server"); 36 | } 37 | 38 | int Gdb_server::stop(bool kill) 39 | { 40 | if (rsp != NULL) 41 | { 42 | rsp->close(kill); 43 | rsp = NULL; 44 | } 45 | } 46 | 47 | void Gdb_server::print(const char *format, ...) 48 | { 49 | va_list ap; 50 | va_start(ap, format); 51 | vprintf(format, ap); 52 | va_end(ap); 53 | } 54 | -------------------------------------------------------------------------------- /src/gdb-server/gdb-server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Andreas Traber 19 | */ 20 | 21 | #ifndef __GDB_SERVER_GDB_SERVER_H__ 22 | #define __GDB_SERVER_GDB_SERVER_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | 37 | class Rsp { 38 | public: 39 | Rsp(int socket_ptr); 40 | //Rsp(int socket_port, MemIF* mem, LogIF *log, std::list list_dbgif, std::list list_dbg_cluster_if, BreakPoints* bp, DbgIF *main_if); 41 | 42 | private: 43 | bool open(); 44 | void close(); 45 | 46 | bool wait_client(); 47 | bool loop(); 48 | 49 | bool decode(char* data, size_t len); 50 | 51 | bool multithread(char* data, size_t len); 52 | 53 | bool cont(char* data, size_t len); // continue, reserved keyword, thus not used as function name 54 | bool step(char* data, size_t len); 55 | 56 | bool query(char* data, size_t len); 57 | bool v_packet(char* data, size_t len); 58 | 59 | bool regs_send(); 60 | bool reg_read(char* data, size_t len); 61 | bool reg_write(char* data, size_t len); 62 | 63 | bool get_packet(char* data, size_t* len); 64 | 65 | bool signal(); 66 | 67 | bool send(const char* data, size_t len); 68 | bool send_str(const char* data); 69 | 70 | 71 | // internal helper functions 72 | bool pc_read(unsigned int* pc); 73 | 74 | bool waitStop(DbgIF* dbgif); 75 | bool resume(bool step); 76 | bool resume(int tid, bool step); 77 | void resumeCoresPrepare(DbgIF *dbgif, bool step); 78 | void resumeCores(); 79 | 80 | bool mem_read(char* data, size_t len); 81 | bool mem_write_ascii(char* data, size_t len); 82 | bool mem_write(char* data, size_t len); 83 | 84 | bool bp_insert(char* data, size_t len); 85 | bool bp_remove(char* data, size_t len); 86 | 87 | DbgIF* get_dbgif(int thread_id); 88 | 89 | int m_socket_port; 90 | int m_socket_in; 91 | int m_socket_client; 92 | 93 | int m_thread_sel; 94 | int m_thread_init; 95 | MemIF* m_mem; 96 | LogIF *log; 97 | BreakPoints* m_bp; 98 | std::list m_dbgifs; 99 | std::list m_dbg_cluster_ifs; 100 | }; 101 | 102 | #endif -------------------------------------------------------------------------------- /src/gdb-server/gdb-server.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Andreas Traber 19 | */ 20 | 21 | #ifndef __GDB_SERVER_GDB_SERVER_H__ 22 | #define __GDB_SERVER_GDB_SERVER_H__ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "cable.hpp" 38 | #include "json.hpp" 39 | 40 | #define DBG_CTRL_REG 0x0 41 | #define DBG_HIT_REG 0x4 42 | #define DBG_IE_REG 0x8 43 | #define DBG_CAUSE_REG 0xC 44 | #define DBG_NPC_REG 0x2000 45 | #define DBG_PPC_REG 0x2004 46 | 47 | #define DBG_CAUSE_BP 0x3 48 | 49 | 50 | class Rsp; 51 | class Breakpoints; 52 | class Target; 53 | class Target_cluster_common; 54 | class Target_cluster; 55 | class Target_core; 56 | 57 | static int first_free_thread_id = 0; 58 | 59 | class Gdb_server 60 | { 61 | public: 62 | Gdb_server(Log *log, Cable *cable, js::config *config, int socket_port); 63 | int stop(bool kill); 64 | void print(const char *format, ...); 65 | 66 | Rsp *rsp; 67 | Log *log; 68 | Cable *cable; 69 | Target *target; 70 | Breakpoints *bkp; 71 | 72 | js::config *config; 73 | }; 74 | 75 | 76 | 77 | 78 | class Target_core 79 | { 80 | public: 81 | Target_core(Gdb_server *top, uint32_t dbg_unit_addr, int cluster_id, int core_id); 82 | void set_power(bool is_on); 83 | bool read(uint32_t addr, uint32_t* rdata); 84 | bool write(uint32_t addr, uint32_t wdata); 85 | bool csr_read(unsigned int i, uint32_t *data); 86 | int get_thread_id() { return thread_id; } 87 | void get_name(char* str, size_t len) { 88 | snprintf(str, len, "Cluster %02d - Core %01d", this->cluster_id, this->core_id); 89 | } 90 | bool is_stopped(); 91 | void read_ppc(uint32_t *ppc); 92 | 93 | bool stop(); 94 | bool halt(); 95 | void prepare_resume(bool step=false); 96 | void commit_resume(); 97 | void set_step_mode(bool new_step); 98 | void commit_step_mode(); 99 | void resume(); 100 | void flush(); 101 | 102 | bool gpr_read_all(uint32_t *data); 103 | bool gpr_read(unsigned int i, uint32_t *data); 104 | bool gpr_write(unsigned int i, uint32_t data); 105 | 106 | private: 107 | Gdb_server *top; 108 | bool is_on = false; 109 | uint32_t dbg_unit_addr; 110 | uint32_t hartid; 111 | int cluster_id; 112 | int core_id; 113 | int thread_id; 114 | bool ppc_is_cached = false; 115 | uint32_t ppc_cached; 116 | bool stopped = false; 117 | bool step = false; 118 | bool commit_step = false; 119 | }; 120 | 121 | 122 | 123 | class Target { 124 | public: 125 | Target(Gdb_server *top); 126 | 127 | inline int get_nb_threads() { return cores.size(); } 128 | 129 | 130 | void halt(); 131 | void resume(bool step=false, int tid=-1); 132 | void resume_all(); 133 | bool wait(int socket_client); 134 | void flush(); 135 | 136 | void update_power(); 137 | 138 | std::vector get_threads() { return cores; } 139 | Target_core *get_thread(int thread_id) { return cores_from_threadid[thread_id]; } 140 | Target_core *get_thread_from_id(int id) { return cores[id]; } 141 | 142 | 143 | private: 144 | Gdb_server *top; 145 | std::vector clusters; 146 | std::vector cores; 147 | std::map cores_from_threadid; 148 | }; 149 | 150 | 151 | 152 | struct bp_insn { 153 | uint32_t addr; 154 | uint32_t insn_orig; 155 | bool is_compressed; 156 | }; 157 | 158 | 159 | 160 | class Breakpoints { 161 | public: 162 | Breakpoints(Gdb_server *top); 163 | 164 | bool insert(unsigned int addr); 165 | bool remove(unsigned int addr); 166 | 167 | bool clear(); 168 | 169 | bool at_addr(unsigned int addr); 170 | 171 | bool enable_all(); 172 | bool disable_all(); 173 | 174 | bool disable(unsigned int addr); 175 | bool enable(unsigned int addr); 176 | 177 | private: 178 | std::list breakpoints; 179 | Gdb_server *top; 180 | }; 181 | 182 | class Rsp { 183 | public: 184 | Rsp(Gdb_server *top, int socket_port); 185 | //Rsp(int socket_port, MemIF* mem, LogIF *log, std::list list_dbgif, std::list list_dbg_cluster_if, BreakPoints* bp, DbgIF *main_if); 186 | 187 | bool open(); 188 | void close(int kill); 189 | 190 | 191 | private: 192 | 193 | bool decode(int socket_client, char* data, size_t len); 194 | bool get_packet(int socket_client, char* data, size_t* len); 195 | 196 | void client_routine(int socket_client); 197 | void listener_routine(); 198 | 199 | 200 | bool regs_send(int socket_client); 201 | bool signal(int socket_client); 202 | 203 | bool multithread(int socket_client, char* data, size_t len); 204 | 205 | bool v_packet(int socket_client, char* data, size_t len); 206 | 207 | bool query(int socket_client, char* data, size_t len); 208 | 209 | bool send(int socket_client, const char* data, size_t len); 210 | bool send_str(int socket_client, const char* data); 211 | 212 | bool cont(int socket_client, char* data, size_t len); // continue, reserved keyword, thus not used as function name 213 | bool resume(int socket_client, bool step); 214 | bool resume(int socket_client, int tid, bool step); 215 | bool wait(int socket_client, Target_core *core=NULL); 216 | bool step(int socket_client, char* data, size_t len); 217 | 218 | // internal helper functions 219 | bool pc_read(int socket_client, unsigned int* pc); 220 | 221 | bool reg_read(int socket_client, char* data, size_t len); 222 | bool reg_write(int socket_client, char* data, size_t len); 223 | 224 | bool mem_read(int socket_client, char* data, size_t len); 225 | bool mem_write_ascii(int socket_client, char* data, size_t len); 226 | bool mem_write(int socket_client, char* data, size_t len); 227 | 228 | bool bp_insert(int socket_client, char* data, size_t len); 229 | bool bp_remove(int socket_client, char* data, size_t len); 230 | 231 | Gdb_server *top; 232 | int socket_port; 233 | int socket_in; 234 | std::thread *listener_thread; 235 | 236 | int thread_sel; 237 | Target_core *main_core = NULL; 238 | 239 | 240 | 241 | bool wait_client(); 242 | bool loop(); 243 | 244 | 245 | 246 | //void resumeCoresPrepare(DbgIF *dbgif, bool step); 247 | void resumeCores(); 248 | 249 | //DbgIF* get_dbgif(int thread_id); 250 | 251 | 252 | int m_thread_init; 253 | //MemIF* m_mem; 254 | //LogIF *log; 255 | //BreakPoints* m_bp; 256 | //std::list m_dbgifs; 257 | //std::list m_dbg_cluster_ifs; 258 | }; 259 | 260 | #endif -------------------------------------------------------------------------------- /src/gdb-server/target.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 19 | */ 20 | 21 | #include "gdb-server/gdb-server.hpp" 22 | #include 23 | 24 | 25 | class Target_cache 26 | { 27 | public: 28 | virtual void flush() { } 29 | }; 30 | 31 | class Target_cluster_cache : public Target_cache 32 | { 33 | public: 34 | Target_cluster_cache(Gdb_server *top, uint32_t addr); 35 | void flush(); 36 | private: 37 | Gdb_server *top; 38 | uint32_t addr; 39 | }; 40 | 41 | 42 | 43 | class Target_fc_cache : public Target_cache 44 | { 45 | public: 46 | Target_fc_cache(Gdb_server *top, uint32_t addr); 47 | void flush(); 48 | private: 49 | Gdb_server *top; 50 | uint32_t addr; 51 | }; 52 | 53 | 54 | 55 | 56 | 57 | class Target_cluster_power 58 | { 59 | public: 60 | virtual bool is_on() { return true; } 61 | }; 62 | 63 | 64 | 65 | class Target_cluster_power_bypass : public Target_cluster_power 66 | { 67 | public: 68 | Target_cluster_power_bypass(Gdb_server *top, uint32_t reg_addr, int bit); 69 | bool is_on(); 70 | 71 | private: 72 | Gdb_server *top; 73 | uint32_t reg_addr; 74 | int bit; 75 | }; 76 | 77 | 78 | 79 | 80 | class Target_cluster_ctrl 81 | { 82 | public: 83 | virtual bool init() {} 84 | }; 85 | 86 | 87 | 88 | class Target_cluster_ctrl_xtrigger : public Target_cluster_ctrl 89 | { 90 | public: 91 | Target_cluster_ctrl_xtrigger(Gdb_server *top, uint32_t cluster_ctrl_addr); 92 | bool init(); 93 | 94 | private: 95 | Gdb_server *top; 96 | uint32_t cluster_ctrl_addr; 97 | }; 98 | 99 | 100 | Target_cluster_cache::Target_cluster_cache(Gdb_server *top, uint32_t addr) 101 | : top(top), addr(addr) 102 | { 103 | 104 | } 105 | 106 | void Target_cluster_cache::flush() 107 | { 108 | this->top->log->debug("Flushing cluster cache (addr: 0x%x)\n", addr); 109 | 110 | uint32_t data = 0xFFFFFFFF; 111 | top->cable->access(true, addr + 0x04, 4, (char*)&data); 112 | } 113 | 114 | 115 | 116 | Target_fc_cache::Target_fc_cache(Gdb_server *top, uint32_t addr) 117 | : top(top), addr(addr) 118 | { 119 | 120 | } 121 | 122 | void Target_fc_cache::flush() 123 | { 124 | this->top->log->debug("Flushing FC cache (addr: 0x%x)\n", addr); 125 | 126 | uint32_t data = 0xFFFFFFFF; 127 | top->cable->access(true, addr + 0x04, 4, (char*)&data); 128 | } 129 | 130 | 131 | Target_cluster_ctrl_xtrigger::Target_cluster_ctrl_xtrigger(Gdb_server *top, uint32_t cluster_ctrl_addr) 132 | : top(top), cluster_ctrl_addr(cluster_ctrl_addr) 133 | { 134 | 135 | } 136 | 137 | 138 | 139 | bool Target_cluster_ctrl_xtrigger::init() 140 | { 141 | uint32_t info; 142 | // set all-stop mode, so that all cores go to debug when one enters debug mode 143 | info = 0xFFFFFFFF; 144 | top->cable->access(true, cluster_ctrl_addr + 0x000038, 4, (char*)&info); 145 | } 146 | 147 | 148 | 149 | Target_cluster_power_bypass::Target_cluster_power_bypass(Gdb_server *top, uint32_t reg_addr, int bit) 150 | : top(top), reg_addr(reg_addr), bit(bit) 151 | { 152 | } 153 | 154 | bool Target_cluster_power_bypass::is_on() 155 | { 156 | uint32_t info; 157 | top->cable->access(false, reg_addr, 4, (char*)&info); 158 | return (info >> bit) & 1; 159 | } 160 | 161 | 162 | class Target_cluster_common 163 | { 164 | friend class Target_cluster; 165 | friend class Target_fc; 166 | 167 | public: 168 | Target_cluster_common(js::config *config, Gdb_server *top, uint32_t cluster_addr, uint32_t xtrigger_addr, int cluster_id); 169 | int get_nb_core() { return nb_core; } 170 | Target_core *get_core(int i) { return cores[i]; } 171 | void update_power(); 172 | void set_power(bool is_on); 173 | void resume(); 174 | void halt(); 175 | void flush(); 176 | 177 | protected: 178 | Gdb_server *top; 179 | std::vector cores; 180 | bool is_on = false; 181 | Target_cluster_power *power; 182 | Target_cluster_ctrl *ctrl; 183 | int nb_on_cores = 0; 184 | int nb_core = 0; 185 | int cluster_id; 186 | uint32_t cluster_addr; 187 | uint32_t xtrigger_addr; 188 | Target_cache *cache = NULL; 189 | }; 190 | 191 | class Target_cluster : public Target_cluster_common 192 | { 193 | public: 194 | Target_cluster(js::config *system_config, js::config *config, Gdb_server *top, uint32_t cluster_base, uint32_t xtrigger_base, int cluster_id); 195 | }; 196 | 197 | class Target_fc : public Target_cluster_common 198 | { 199 | public: 200 | Target_fc(js::config *config, Gdb_server *top, uint32_t fc_dbg_base, uint32_t fc_cache_base, int cluster_id); 201 | }; 202 | 203 | 204 | 205 | Target_core::Target_core(Gdb_server *top, uint32_t dbg_unit_addr, int cluster_id, int core_id) 206 | : top(top), dbg_unit_addr(dbg_unit_addr), cluster_id(cluster_id), core_id(core_id) 207 | { 208 | top->log->print(LOG_DEBUG, "Instantiated core\n"); 209 | this->thread_id = first_free_thread_id++; 210 | } 211 | 212 | 213 | 214 | void Target_core::flush() 215 | { 216 | this->top->log->debug("Flushing core cache (cluster: %d, core: %d)\n", cluster_id, core_id); 217 | 218 | // Write back the value of NPC so that it triggers a flush of the prefetch buffer 219 | uint32_t npc; 220 | this->read(DBG_NPC_REG, &npc); 221 | this->write(DBG_NPC_REG, npc); 222 | } 223 | 224 | 225 | 226 | void Target_core::read_ppc(uint32_t *ppc) 227 | { 228 | if (!ppc_is_cached) { 229 | read(DBG_PPC_REG, &ppc_cached); 230 | ppc_is_cached = true; 231 | } 232 | *ppc = ppc_cached; 233 | } 234 | 235 | 236 | 237 | bool Target_core::gpr_read_all(uint32_t *data) 238 | { 239 | if (!is_on) return false; 240 | this->top->log->debug("Reading all registers (cluster: %d, core: %d)\n", cluster_id, core_id); 241 | 242 | // Write back the valu 243 | return top->cable->access(false, dbg_unit_addr + 0x0400, 32 * 4, (char*)data); 244 | } 245 | 246 | 247 | 248 | bool Target_core::gpr_read(unsigned int i, uint32_t *data) 249 | { 250 | if (!is_on) return false; 251 | return this->read(0x0400 + i * 4, data); 252 | } 253 | 254 | 255 | 256 | bool Target_core::gpr_write(unsigned int i, uint32_t data) 257 | { 258 | if (!is_on) return false; 259 | return this->write(0x0400 + i * 4, data); 260 | } 261 | 262 | 263 | 264 | void Target_core::commit_resume() 265 | { 266 | this->stopped = false; 267 | 268 | if (!this->is_on) return; 269 | 270 | this->ppc_is_cached = false; 271 | this->commit_step_mode(); 272 | this->write(DBG_HIT_REG, 0); 273 | } 274 | 275 | 276 | 277 | void Target_core::set_power(bool is_on) 278 | { 279 | if (is_on != this->is_on) 280 | { 281 | this->is_on = is_on; 282 | if (is_on) { 283 | top->log->print(LOG_DEBUG, "Setting-on core\n"); 284 | is_on = true; 285 | // let's discover core id and cluster id 286 | this->stop(); 287 | csr_read(0xF14, &hartid); 288 | 289 | cluster_id = hartid >> 5; 290 | core_id = hartid & 0x1f; 291 | 292 | top->log->print(LOG_DEBUG, "Found a core with id %X (cluster: %d, core: %d)\n", hartid, cluster_id, core_id); 293 | this->write(DBG_IE_REG, 1<<3); 294 | if (!stopped) resume(); 295 | } else { 296 | top->log->print(LOG_DEBUG, "Setting-off core (cluster: %d, core: %d)\n", cluster_id, core_id); 297 | is_on = false; 298 | } 299 | } 300 | } 301 | 302 | bool Target_core::read(uint32_t addr, uint32_t* rdata) 303 | { 304 | if (!is_on) return false; 305 | top->log->print(LOG_DEBUG, "Reading register (addr: 0x%x)\n", dbg_unit_addr + addr); 306 | return top->cable->access(false, dbg_unit_addr + addr, 4, (char*)rdata); 307 | } 308 | 309 | 310 | 311 | bool Target_core::write(uint32_t addr, uint32_t wdata) 312 | { 313 | if (!is_on) return false; 314 | top->log->print(LOG_DEBUG, "Writing register (addr: 0x%x, value: 0x%x)\n", dbg_unit_addr + addr, wdata); 315 | return top->cable->access(true, dbg_unit_addr + addr, 4, (char*)&wdata); 316 | } 317 | 318 | 319 | 320 | bool Target_core::csr_read(unsigned int i, uint32_t *data) 321 | { 322 | if (!is_on) return false; 323 | return this->read(0x4000 + i * 4, data); 324 | } 325 | 326 | 327 | 328 | bool Target_core::is_stopped() { 329 | if (!is_on) return false; 330 | 331 | uint32_t data; 332 | if (!this->read(DBG_CTRL_REG, &data)) { 333 | fprintf(stderr, "debug_is_stopped: Reading from CTRL reg failed\n"); 334 | return false; 335 | } 336 | 337 | this->stopped = data & 0x10000; 338 | 339 | top->log->debug("Checking core status (cluster: %d, core: %d, stopped: %d)\n", cluster_id, core_id, this->stopped); 340 | 341 | return this->stopped; 342 | } 343 | 344 | 345 | bool Target_core::stop() 346 | { 347 | if (!is_on) return false; 348 | if (this->stopped) return false; 349 | 350 | this->top->log->debug("Halting core (cluster: %d, core: %d, is_on: %d)\n", cluster_id, core_id, is_on); 351 | uint32_t data; 352 | if (!this->read(DBG_CTRL_REG, &data)) { 353 | fprintf(stderr, "debug_is_stopped: Reading from CTRL reg failed\n"); 354 | return false; 355 | } 356 | 357 | data |= 0x1 << 16; 358 | return this->write(DBG_CTRL_REG, data); 359 | } 360 | 361 | 362 | 363 | bool Target_core::halt() 364 | { 365 | //stopped = true; 366 | return stop(); 367 | } 368 | 369 | 370 | 371 | void Target_core::set_step_mode(bool new_step) 372 | { 373 | this->top->log->debug("Setting step mode (cluster: %d, core: %d, step: %d, new_step: %d)\n", cluster_id, core_id, step, new_step); 374 | 375 | if (new_step != step) { 376 | this->step = new_step; 377 | this->commit_step = true; 378 | } 379 | } 380 | 381 | 382 | void Target_core::commit_step_mode() 383 | { 384 | if (!is_on) return; 385 | 386 | if (commit_step) { 387 | this->top->log->debug("Committing step mode (cluster: %d, core: %d, step: %d)\n", cluster_id, core_id, step); 388 | this->write(DBG_CTRL_REG, (1<<16) | step); 389 | this->commit_step = false; 390 | } 391 | } 392 | 393 | 394 | 395 | void Target_core::prepare_resume(bool step) 396 | { 397 | 398 | if (!is_on) return; 399 | 400 | top->log->debug("Preparing core to resume (step: %d)\n", step); 401 | 402 | // now let's handle software breakpoints 403 | uint32_t ppc; 404 | this->read_ppc(&ppc); 405 | 406 | // if there is a breakpoint at this address, let's remove it and single-step over it 407 | bool has_stepped = false; 408 | 409 | if (this->top->bkp->at_addr(ppc)) { 410 | 411 | top->log->debug("Core is stopped on a breakpoint, stepping to go over (addr: 0x%x)\n", ppc); 412 | 413 | this->top->bkp->disable(ppc); 414 | this->write(DBG_NPC_REG, ppc); // re-execute this instruction 415 | this->write(DBG_CTRL_REG, 0x1); // single-step 416 | while (1) { 417 | uint32_t value; 418 | this->read(DBG_CTRL_REG, &value); 419 | if ((value >> 16) & 1) break; 420 | } 421 | this->top->bkp->enable(ppc); 422 | has_stepped = true; 423 | } 424 | 425 | this->set_step_mode(step && !has_stepped); 426 | } 427 | 428 | 429 | 430 | void Target_core::resume() 431 | { 432 | this->stopped = false; 433 | 434 | if (!is_on) return; 435 | 436 | this->top->log->debug("Resuming core and committing step mode (cluster: %d, core: %d, step: %d)\n", cluster_id, core_id, step); 437 | 438 | // clear hit register, has to be done before CTRL 439 | this->write(DBG_HIT_REG, 0); 440 | 441 | this->write(DBG_CTRL_REG, step); 442 | 443 | this->commit_step = false; 444 | this->ppc_is_cached = false; 445 | } 446 | 447 | 448 | 449 | Target_cluster_common::Target_cluster_common(js::config *config, Gdb_server *top, uint32_t cluster_addr, uint32_t xtrigger_addr, int cluster_id) 450 | : top(top), cluster_id(cluster_id), cluster_addr(cluster_addr), xtrigger_addr(xtrigger_addr) 451 | { 452 | } 453 | 454 | 455 | 456 | Target_cluster::Target_cluster(js::config *system_config, js::config *config, Gdb_server *top, uint32_t cluster_base, uint32_t xtrigger_addr, int cluster_id) 457 | : Target_cluster_common(config, top, cluster_base, xtrigger_addr, cluster_id) 458 | { 459 | int nb_pe = config->get("nb_pe")->get_int(); 460 | for (int i=0; iget("**/apb_soc_ctrl/regmap/power/bypass"); 469 | if (bypass_config) 470 | { 471 | uint32_t addr = system_config->get("**/apb_soc_ctrl/base")->get_int() + 472 | bypass_config->get("offset")->get_int(); 473 | int bit = bypass_config->get("content/dbg1/bit")->get_int(); 474 | 475 | // Case where there is an apb soc ctrl register which tells if the cluster is on 476 | power = new Target_cluster_power_bypass(top, addr, bit); 477 | } 478 | else 479 | { 480 | // Otherwise, the cluster will always be on 481 | power = new Target_cluster_power(); 482 | } 483 | 484 | ctrl = new Target_cluster_ctrl_xtrigger(top, cluster_base + 0x00200000); 485 | 486 | cache = new Target_cluster_cache(top, cluster_base + 0x00201400); 487 | 488 | this->update_power(); 489 | } 490 | 491 | 492 | 493 | Target_fc::Target_fc(js::config *config, Gdb_server *top, uint32_t fc_dbg_base, uint32_t fc_cache_base, int cluster_id) 494 | : Target_cluster_common(config, top, fc_dbg_base, -1, cluster_id) 495 | { 496 | Target_core *core = new Target_core(top, fc_dbg_base, cluster_id, 0); 497 | cores.push_back(core); 498 | nb_core++; 499 | 500 | // the FC will always be on 501 | power = new Target_cluster_power(); 502 | 503 | ctrl = new Target_cluster_ctrl(); 504 | 505 | if (fc_cache_base != -1) 506 | cache = new Target_fc_cache(top, fc_cache_base); 507 | 508 | this->update_power(); 509 | } 510 | 511 | 512 | 513 | void Target_cluster_common::flush() 514 | { 515 | if (!is_on) return; 516 | 517 | this->top->log->debug("Flushing cluster caches (cluster: %d)\n", cluster_id); 518 | 519 | if (this->cache) 520 | this->cache->flush(); 521 | 522 | for (auto &core: cores) 523 | { 524 | core->flush(); 525 | } 526 | } 527 | 528 | 529 | 530 | void Target_cluster_common::resume() 531 | { 532 | this->top->log->debug("Resuming cluster (cluster: %d)\n", cluster_id); 533 | 534 | if (xtrigger_addr != -1) { 535 | 536 | // This cluster is a one with the cross-trigger matrix, use it to resume all cores 537 | // As the step mode is cached and committed when writing to the individual core 538 | // debug register, we have to commit it now before resuming the core through the 539 | // global register 540 | for (auto &core: cores) { 541 | core->commit_resume(); 542 | } 543 | 544 | if (is_on) { 545 | this->top->log->debug("Resuming cluster through global register (cluster: %d)\n", cluster_id); 546 | uint32_t info = 0xFFFFFFFF; 547 | this->top->cable->access(true, xtrigger_addr + 0x00200000 + 0x28, 4, (char*)&info); 548 | } 549 | } else { 550 | // Otherwise, just resume them individually 551 | for (auto &core: cores) { 552 | core->resume(); 553 | } 554 | } 555 | } 556 | 557 | 558 | 559 | void Target_cluster_common::update_power() 560 | { 561 | set_power(power->is_on()); 562 | } 563 | 564 | 565 | void Target_cluster_common::set_power(bool is_on) 566 | { 567 | this->top->log->debug("Set cluster power (cluster: %d, is_on: %d)\n", cluster_id, is_on); 568 | 569 | if (is_on != this->is_on) { 570 | this->is_on = is_on; 571 | 572 | ctrl->init(); 573 | } 574 | 575 | if (is_on && nb_on_cores != nb_core) 576 | { 577 | for(auto const& core: cores) 578 | { 579 | core->set_power(is_on); 580 | } 581 | } else { 582 | nb_on_cores = 0; 583 | } 584 | } 585 | 586 | 587 | 588 | void Target_cluster_common::halt() 589 | { 590 | this->top->log->debug("Halting cluster (cluster: %d)\n", cluster_id); 591 | // Either the core is alone (FC) or the cluster is using a cross-trigger matrix to stop all cores 592 | // thus only stop the first one 593 | cores.front()->halt(); 594 | } 595 | 596 | 597 | #if 0 598 | void Target_cluster::set_power(bool is_on) 599 | { 600 | if (is_on != this->is_on) { 601 | this->is_on = is_on; 602 | 603 | if (is_on && base_addr != -1) { 604 | uint32_t info; 605 | // set all-stop mode, so that all cores go to debug when one enters debug mode 606 | info = 0xFFFFFFFF; 607 | m_mem->access(1, base_addr + 0x000038, 4, (char*)&info); 608 | } 609 | } 610 | 611 | if (is_on && nb_on_cores != itfs.size()) { 612 | uint32_t info = -1; 613 | if (base_addr != -1) { 614 | m_mem->access(0, base_addr + 0x000008, 4, (char*)&info); 615 | } 616 | int i = 0; 617 | for (std::list::iterator it = itfs.begin(); it != itfs.end(); it++, i++) { 618 | if ((info >> i) & 1) { 619 | (*it)->set_power(is_on); 620 | } 621 | } 622 | } else { 623 | nb_on_cores = 0; 624 | } 625 | } 626 | #endif 627 | 628 | 629 | 630 | Target::Target(Gdb_server *top) 631 | : top(top) 632 | { 633 | js::config *config = top->config; 634 | 635 | js::config *fc_config = config->get("**/soc/fc"); 636 | if (fc_config != NULL) 637 | { 638 | unsigned int fc_dbg_addr = config->get("**/fc_dbg_unit/base")->get_int(); 639 | js::config *cache_config = config->get("**/fc_icache/base"); 640 | unsigned int fc_icache_addr = -1; 641 | if (cache_config) 642 | fc_icache_addr = cache_config->get_int(); 643 | 644 | Target_fc *cluster = new Target_fc(fc_config, top, fc_dbg_addr, fc_icache_addr, fc_config->get("cluster_id")->get_int()); 645 | 646 | clusters.push_back(cluster); 647 | Target_core *core = cluster->get_core(0); 648 | cores.push_back(core); 649 | cores_from_threadid[core->get_thread_id()] = core; 650 | } 651 | 652 | js::config *cluster_config = config->get("**/soc/cluster"); 653 | if (cluster_config != NULL) 654 | { 655 | int nb_clusters = config->get("**/nb_cluster")->get_int(); 656 | for (int i=0; iget("**/cluster/base"); 660 | if (base_config != NULL) 661 | cluster_base = base_config->get_int(); 662 | 663 | Target_cluster *cluster = new Target_cluster(config, cluster_config, top, cluster_base + 0x400000 * i, cluster_base + 0x400000 * i, i); 664 | 665 | clusters.push_back(cluster); 666 | for (int j=0; jget_nb_core(); j++) 667 | { 668 | Target_core *core = cluster->get_core(j); 669 | cores.push_back(core); 670 | cores_from_threadid[core->get_thread_id()] = core; 671 | } 672 | } 673 | } 674 | } 675 | 676 | 677 | 678 | void Target::flush() 679 | { 680 | for (auto &cluster : this->clusters) 681 | { 682 | cluster->flush(); 683 | } 684 | } 685 | 686 | 687 | 688 | void Target::resume_all() 689 | { 690 | for (auto &cluster : this->clusters) 691 | { 692 | cluster->resume(); 693 | } 694 | } 695 | 696 | 697 | 698 | void Target::resume(bool step, int tid) 699 | { 700 | if (tid == -1) 701 | { 702 | for (auto &thread : this->get_threads()) 703 | { 704 | thread->prepare_resume(step); 705 | this->resume_all(); 706 | } 707 | } 708 | else 709 | { 710 | auto *thread = this->get_thread(tid); 711 | thread->prepare_resume(step); 712 | thread->resume(); 713 | } 714 | 715 | } 716 | 717 | bool Target::wait(int socket_client) 718 | { 719 | printf("UNIMPLEMENTED AT %s %d\n", __FILE__, __LINE__); 720 | exit(1); 721 | return true; 722 | } 723 | 724 | 725 | 726 | void Target::update_power() 727 | { 728 | for (auto &cluster: clusters) { 729 | cluster->update_power(); 730 | } 731 | } 732 | 733 | 734 | 735 | void Target::halt() 736 | { 737 | for (auto &cluster: this->clusters) 738 | { 739 | cluster->halt(); 740 | } 741 | } -------------------------------------------------------------------------------- /src/python_wrapper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 ETH Zurich and University of Bologna 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Authors: Germain Haugou, ETH (germain.haugou@iis.ee.ethz.ch) 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "json.hpp" 27 | #include "cables/log.h" 28 | #include "cables/adv_dbg_itf/adv_dbg_itf.hpp" 29 | #include "cables/jtag-proxy/jtag-proxy.hpp" 30 | #ifdef __USE_FTDI__ 31 | #include "cables/ftdi/ftdi.hpp" 32 | #endif 33 | #include "gdb-server/gdb-server.hpp" 34 | 35 | using namespace std; 36 | 37 | 38 | static int bridge_verbose = 0; 39 | static const char *bridge_error = NULL; 40 | static js::config *system_config = NULL; 41 | 42 | void Log::print(log_level_e level, const char *str, ...) 43 | { 44 | if (bridge_verbose <= level) return; 45 | va_list va; 46 | va_start(va, str); 47 | vprintf(str, va); 48 | va_end(va); 49 | } 50 | 51 | 52 | void Log::user(const char *str, ...) 53 | { 54 | if (bridge_verbose <= LOG_INFO) return; 55 | va_list va; 56 | va_start(va, str); 57 | vprintf(str, va); 58 | va_end(va); 59 | } 60 | 61 | void Log::debug(const char *str, ...) 62 | { 63 | if (bridge_verbose <= LOG_DEBUG) return; 64 | va_list va; 65 | va_start(va, str); 66 | vprintf(str, va); 67 | va_end(va); 68 | } 69 | 70 | void Log::warning(const char *str, ...) 71 | { 72 | if (bridge_verbose <= LOG_WARNING) return; 73 | va_list va; 74 | va_start(va, str); 75 | vprintf(str, va); 76 | va_end(va); 77 | } 78 | 79 | void Log::error(const char *str, ...) 80 | { 81 | char buff[1024]; 82 | va_list va; 83 | va_start(va, str); 84 | vsnprintf(buff, 1024, str, va); 85 | va_end(va); 86 | bridge_error = strdup(buff); 87 | 88 | if (bridge_verbose <= LOG_ERROR) return; 89 | va_start(va, str); 90 | vprintf(str, va); 91 | va_end(va); 92 | } 93 | 94 | extern "C" void *cable_new(const char *config_string, const char *system_config_string) 95 | { 96 | const char *cable_name = NULL; 97 | js::config *config = NULL; 98 | js::config *system_config = js::import_config_from_string(std::string(system_config_string)); 99 | 100 | if (config_string != NULL) 101 | { 102 | config = js::import_config_from_string(std::string(config_string)); 103 | js::config *type_config = config->get("type"); 104 | if (type_config != NULL) 105 | { 106 | cable_name = type_config->get_str().c_str(); 107 | } 108 | } 109 | 110 | if (cable_name == NULL) { 111 | bridge_error = "No cable name specified"; 112 | return NULL; 113 | } 114 | 115 | if (strncmp(cable_name, "ftdi", 4) == 0) 116 | { 117 | #ifdef __USE_FTDI__ 118 | Log *log = new Log(); 119 | Ftdi::FTDIDeviceID id = Ftdi::Olimex; 120 | if (strcmp(cable_name, "ftdi@digilent") == 0) id = Ftdi::Digilent; 121 | if (strcmp(cable_name, "ftdi@generic") == 0) id = Ftdi::Generic; 122 | Adv_dbg_itf *adu = new Adv_dbg_itf(system_config, config, log, new Ftdi(system_config, log, id)); 123 | return (void *)static_cast(adu); 124 | #else 125 | fprintf(stderr, "Debug bridge has not been compiled with FTDI support\n"); 126 | return NULL; 127 | #endif 128 | } 129 | else if (strcmp(cable_name, "jtag-proxy") == 0) 130 | { 131 | Log *log = new Log(); 132 | Adv_dbg_itf *adu = new Adv_dbg_itf(system_config, config, log, new Jtag_proxy(log)); 133 | return (void *)static_cast(adu); 134 | } 135 | else 136 | { 137 | fprintf(stderr, "Unknown cable: %s\n", cable_name); 138 | return NULL; 139 | } 140 | 141 | return NULL; 142 | } 143 | 144 | extern "C" void cable_write(void *cable, unsigned int addr, int size, const char *data) 145 | { 146 | Adv_dbg_itf *adu = (Adv_dbg_itf *)cable; 147 | adu->access(true, addr, size, (char *)data); 148 | } 149 | 150 | extern "C" void cable_read(void *cable, unsigned int addr, int size, const char *data) 151 | { 152 | Adv_dbg_itf *adu = (Adv_dbg_itf *)cable; 153 | adu->access(false, addr, size, (char *)data); 154 | } 155 | 156 | extern "C" void cable_reg_write(void *cable, unsigned int addr, const char *data, int device) 157 | { 158 | Adv_dbg_itf *adu = (Adv_dbg_itf *)cable; 159 | adu->reg_access(true, addr, (char *)data, device); 160 | } 161 | 162 | extern "C" void cable_reg_read(void *cable, unsigned int addr, const char *data, int device) 163 | { 164 | Adv_dbg_itf *adu = (Adv_dbg_itf *)cable; 165 | adu->reg_access(false, addr, (char *)data, device); 166 | } 167 | 168 | extern "C" void chip_reset(void *handler, bool active, int duration) 169 | { 170 | Adv_dbg_itf *cable = (Adv_dbg_itf *)handler; 171 | cable->chip_reset(active, duration); 172 | } 173 | 174 | extern "C" void chip_config(void *handler, uint32_t value) 175 | { 176 | Adv_dbg_itf *cable = (Adv_dbg_itf *)handler; 177 | cable->chip_config(value); 178 | } 179 | 180 | extern "C" void jtag_reset(void *handler, bool active) 181 | { 182 | Adv_dbg_itf *cable = (Adv_dbg_itf *)handler; 183 | cable->jtag_reset(active); 184 | } 185 | 186 | extern "C" void jtag_soft_reset(void *handler) 187 | { 188 | Adv_dbg_itf *cable = (Adv_dbg_itf *)handler; 189 | cable->jtag_soft_reset(); 190 | } 191 | 192 | 193 | extern "C" bool cable_jtag_set_reg(void *handler, unsigned int reg, int width, unsigned int value, int ir_len) 194 | { 195 | Cable *cable = (Cable *)handler; 196 | return cable->jtag_set_reg(reg, width, value, ir_len); 197 | } 198 | 199 | extern "C" bool cable_jtag_get_reg(void *handler, unsigned int reg, int width, unsigned int *out_value, unsigned int value, int ir_len) 200 | { 201 | Cable *cable = (Cable *)handler; 202 | return cable->jtag_get_reg(reg, width, out_value, value, ir_len); 203 | } 204 | 205 | extern "C" void cable_lock(void *handler) 206 | { 207 | Cable *cable = (Cable *)handler; 208 | cable->lock(); 209 | } 210 | 211 | extern "C" void cable_unlock(void *handler) 212 | { 213 | Cable *cable = (Cable *)handler; 214 | cable->unlock(); 215 | } 216 | 217 | 218 | 219 | 220 | static void init_sigint_handler(int s) { 221 | raise(SIGTERM); 222 | } 223 | 224 | extern "C" char * bridge_get_error() 225 | { 226 | if (bridge_error == NULL) return strdup("unknown error"); 227 | return strdup(bridge_error); 228 | } 229 | 230 | extern "C" void bridge_init(const char *config_string, int verbose) 231 | { 232 | system_config = js::import_config_from_string(std::string(config_string)); 233 | bridge_verbose = verbose; 234 | 235 | // This should be the first C method called by python. 236 | // As python is not catching SIGINT where we are in C world, we have to 237 | // setup a sigint handler to exit in case control+C is hit. 238 | signal (SIGINT, init_sigint_handler); 239 | 240 | } 241 | 242 | 243 | extern "C" void *gdb_server_open(void *cable, int socket_port) 244 | { 245 | return (void *)new Gdb_server(new Log(), (Cable *)cable, system_config, socket_port); 246 | } 247 | 248 | extern "C" void gdb_server_close(void *arg, int kill) 249 | { 250 | Gdb_server *server = (Gdb_server *)arg; 251 | server->stop(kill); 252 | } 253 | 254 | 255 | 256 | 257 | #if 0 258 | 259 | extern "C" void plt_exit(void *_bridge, bool status) 260 | { 261 | Bridge *bridge = (Bridge *)_bridge; 262 | bridge->getMemIF()->exit(status); 263 | } 264 | 265 | extern "C" bool jtag_reset(void *_bridge) 266 | { 267 | Bridge *bridge = (Bridge *)_bridge; 268 | bridge->getJtagIF()->jtag_reset(); 269 | } 270 | 271 | extern "C" bool jtag_idle(void *_bridge) 272 | { 273 | Bridge *bridge = (Bridge *)_bridge; 274 | bridge->getJtagIF()->jtag_idle(); 275 | } 276 | 277 | extern "C" bool jtag_shift_ir(void *_bridge) 278 | { 279 | Bridge *bridge = (Bridge *)_bridge; 280 | bridge->getJtagIF()->jtag_shift_ir(); 281 | } 282 | 283 | extern "C" bool jtag_shift_dr(void *_bridge) 284 | { 285 | Bridge *bridge = (Bridge *)_bridge; 286 | bridge->getJtagIF()->jtag_shift_dr(); 287 | } 288 | 289 | extern "C" void jtag_shift(void *_bridge, int width, const char *datain, const char *dataout, int noex) 290 | { 291 | Bridge *bridge = (Bridge *)_bridge; 292 | bridge->getJtagIF()->jtag_shift(width, (unsigned char *)datain, (unsigned char *)dataout, noex); 293 | } 294 | 295 | #endif 296 | --------------------------------------------------------------------------------