Compare commits

...

40 Commits

Author SHA1 Message Date
liangkangnan 0463f8d773 README: add linux build steps
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-11 09:56:11 +08:00
liangkangnan 916fcb01cb loader: add tinyriscv
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-11 09:55:02 +08:00
liangkangnan 9bbbaf9bad add tinyriscv_program command
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-11-11 09:54:00 +08:00
liangkangnan e5a97681ea target: add load_bin command
Signed-off-by: liangkangnan <liangkangnan@163.com>
2021-05-31 11:48:54 +08:00
liangkangnan 76b7bb357b add README.md
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-06-13 13:29:05 +08:00
liangkangnan 26b7b3c917 README: update
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-06-13 13:23:26 +08:00
liangkangnan 66f480322a add tinyriscv manu code
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-06-13 13:14:10 +08:00
liangkangnan e2b555e287 git ignore release dir
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-06-13 13:13:19 +08:00
liangkangnan a610f377c9 add release.sh
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-06-13 13:12:30 +08:00
liangkangnan 65ff1f1dd2 add rebuild.sh
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-06-13 13:11:44 +08:00
Blue Liang c94bf74155 README: update
Signed-off-by: Blue Liang <liangkangnan@163.com>
2020-06-12 19:06:22 +08:00
Blue Liang 3cc6fe00af README: add build steps
Signed-off-by: Blue Liang <liangkangnan@163.com>
2020-06-12 19:01:20 +08:00
liangkangnan eefff456ca submodule: use gitee jimtcl repo
Signed-off-by: liangkangnan <liangkangnan@163.com>
2020-06-11 23:31:41 +08:00
Tim Newsome 97fb3f4bd4
Add RISC-V to README. (#482)
Change-Id: Ie70833a8b357c4f3ec6ae4472a77bfc409a448bf
2020-06-09 12:49:37 -07:00
Tommy Murphy 95a8cd9b5d
Don't use MMU in M mode - https://github.com/riscv/riscv-openocd/issu… (#479)
* Don't use MMU in M mode - https://github.com/riscv/riscv-openocd/issues/474

* Updated code based on feedback from @timsifive
2020-05-26 10:33:30 -07:00
Tim Newsome 4f9e2d7171
Fix semihosting for multicore targets (#478)
* WIP making semihosting work with -rtos hwthread.

Change-Id: Icb46f3eeedc1391e8fdc73c3ad8036f20267eb2e

* More WIP.

Change-Id: I670a6e1ba2a13a6ef2ae303a99559a16fdd1bbfb

* Fix halting due to a trigger.

Change-Id: Ie7caa8dde9518bcd5440e34cf31ed0d30ebf29ad

* Fix multicore semihosting without halt groups.

Change-Id: I53587e5234308ed2cc30a7132c86e4c94eb176c4

* WIP

Change-Id: I40630543b08d8b533726cb3f63aa60a62be8ef40

* Fix single core semihosting.

This was the last bug!

Change-Id: I593abac027fa9707f48b7f58163d7089574a0e28

* Fix whitespace.

Change-Id: I285c152970b87864c63803fae61312e5b79dfe6d
2020-05-19 10:34:36 -07:00
Tim Newsome 1524487a13
Speed up SBA block reads roughly 2x. (#477)
* Speed up SBA block reads roughly 2x.

Change-Id: I4e4f5530d4abae7470fd00308361e727904367d2

* Fix whitespace.

Change-Id: I28a1269c489d051560a2455973f9a8574f35f487
2020-05-18 14:43:41 -07:00
Alistair Francis 62af8d3c10
Improvements for the HiFive1 revB (#476)
* libjaylink: discovery/usb: Add product ID (PID) 0x1061

Add the 0x1061 ID used with some HiFive1 revB boards.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

* boards: sifive-hifive1-revb: Fix flash range

Fix the flash protect range to avoid errors.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

* contrib: Add HiFive1 revB to udev rules

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2020-05-15 11:31:32 -07:00
Tim Newsome fcdb5d64ec
Make mem2array work with 64-bit addresses. (#475)
Change-Id: I805389dc9934db5affe3c8059d9630acede956c1
2020-05-14 10:19:24 -07:00
Tim Newsome 0c3e50a06a
Don't cache PC, but do cache DPC. (#473)
This fixes a bug where we read PC and marked it cached without actually
updating the cached value. The DPC value was correctly marked as valid
and updated.

Change-Id: Id6d3e94a96b981688b06f7f4a998019f2c02f6f5
2020-05-06 08:43:59 -07:00
Tim Newsome 55dd7e83ca
Add awareness of halt group cause. (#472)
Change-Id: I7f7b967ccaa3d1ff05a7e7d0c2a7ba4fa7d68ac0
2020-05-06 08:42:38 -07:00
Tim Newsome e6e281197f
Cache accesses through riscv_[sg]et_register. (#467)
* Cache accesses through riscv_[sg]et_register.

This helps a lot with the address translation code, which checks satp
over and over again. Now satp is only read once per halt. It should also
help in a few other cases (but I don't have a good test setup to really
measure the impact).

Change-Id: I90392cc60d2145a70cf6c003d6a956dc9f3c0cc4

* Fix whitespace.

Change-Id: I05c5342d8a461cd8c618a3f60296925e9e84643f

* Don't read registers that we know don't exist.

Change-Id: Ie5c6226b3d4ecb6cf8f0d8954a52fda88e6e5bdd
2020-04-21 14:58:59 -07:00
Tim Newsome 2e9aad8914
Don't propagate failure to read satp in riscv_mmu() (#466)
If we return failure, then the caller will think something's wrong. But
it could very well be that the hardware doesn't have SATP, in which case
we should just report that the MMU is disabled.

This fixes a bug where flashing wasn't using the target algorithm
because allocating a work area failed.

Change-Id: I16e8e660036d3f8584c0b17e842c4ec8961a8410
2020-04-13 12:53:26 -07:00
Tim Newsome 464407cfd2
Expose FPRs as single and double for F and D. (#465)
If a hart support both F and D, then expose the FPRs as a union of float
and double. Fixes #336.

Change-Id: I3d4503bbf9281d6380c51259388cd01d399b94d6
2020-04-10 13:32:12 -07:00
Tim Newsome cbb15587dc
Document default values for some config options. (#461)
Change-Id: I4373b9487ea11664d3a6ea7ea10e99ea6d337232
2020-03-27 11:21:02 -07:00
Tim Newsome 3967f48843
Fix some clang static checker complaints. (#464)
The OpenOCD project looks at this, so once in a while I go through and
make sure our code is OK.

Change-Id: I50032c847f30e93604d83d6366cfad85918d6e66
2020-03-27 11:20:48 -07:00
Tim Newsome 60eccb2967
Use the correct thread for memory accesses. (#459)
* Deal with vlenb being unreadable.

Instead of exiting during examine(), spit out a warning, and don't
expose the vector data registers. We do provide access to the vector
CSRs, because maybe they do work? It's just that we have no idea what
the size of the data registers is.

Change-Id: I6e9ffeb242e2e22fc62cb1b50782c2efb4ace0bd

* WIP

Change-Id: I46292eefe537aeaf72bdd44e4aa58298b5120b00

* Use the correct thread for memory accesses.

Previously, OpenOCD would perform RTOS memory accesses through the first
thread in the RTOS. This doesn't work if different threads have a
different memory view. For instance if `-rtos hwthread` is used, each
configured core could have address translation configured differently.

Change-Id: I61328c8f50065ecba5ce1797dbeaee482812f799
2020-03-26 09:46:32 -07:00
Tim Newsome 5b2426a4b2
Deal with vlenb being unreadable. (#458)
Instead of exiting during examine(), spit out a warning, and don't
expose the vector data registers. We do provide access to the vector
CSRs, because maybe they do work? It's just that we have no idea what
the size of the data registers is.

Change-Id: I6e9ffeb242e2e22fc62cb1b50782c2efb4ace0bd
2020-03-26 09:08:56 -07:00
Jonathan Tinkham 548790fefc
Add support for HiFive1 RevB board (#456)
Adds new PID (0x1051) used on board to libjaylink, and add config
and flash entry for RevB board and FE310-G002 respectively.
2020-03-19 09:31:05 -07:00
Tim Newsome f6f30fb148
Update to 1.11 privileged spec. (#455)
Change-Id: I25029f7e83819464e71528fb4225b4761787793f
2020-03-18 12:24:22 -07:00
Tim Newsome 54e5d2533c
helper: skip including sys/sysctl.h on Linux (#450)
Starting from glibc 2.30, the header file sys/sysctl.h gets
deprecated on Linux, after the commit 744e82963716 ("Linux:
Deprecate <sys/sysctl.h> and sysctl")
	https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=744e82963716

The associated NEWS reports
	The Linux-specific <sys/sysctl.h> header and the sysctl
	function have been deprecated and will be removed from a
	future version of glibc.

Latest automake 1.16.1 still does not handle this case.
Current OpenOCD build fails with warning and requires configure
with "--disable-werror" to build.

Prevent including sys/sysctl.h on Linux build.

Change-Id: I5310976573352a96e5aef123352f73475f0c35fe
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/5317
Tested-by: jenkins
Reviewed-by: Moritz Fischer <moritz.fischer.private@gmail.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>

Co-authored-by: Antonio Borneo <borneo.antonio@gmail.com>
2020-03-05 12:13:33 -08:00
Tim Newsome 1ae21b3874
Fix address translation when high bits are set. (#453)
Fixes #452.
Also check that the high bits match the MSB of the virtual address.

Change-Id: Ib1d3d04db9ad9327ef71ea3736d5cf5d3b65b9c4
2020-03-05 11:33:51 -08:00
Tim Newsome 1449af5bdb
Give control over dcsr.ebreak[msu] bits. (#451)
This allows a user to debug code that uses software breakpoints itself.

Change-Id: If40cb626354e11703017cdf8c5919a31e83ebc3f
2020-02-20 13:58:15 -08:00
Tim Newsome 95462a8a35
Add support for vector register access (#448)
* WIP

Change-Id: I0264a73b7f7d2ce89cc0b80692dbf81d9cdcc2fd

* Reading v* registers appears to work.

Can't really test it though, because gdb doesn't print them right.

Change-Id: I8d66339371c564a493d32f15c3d114b738a455c5

* Total hack to communicate registers to gdb.

Change-Id: Id06c819675f2a5bcaf751e322d95a7d71c633765

* Implement writing vector registers.

Fixed reading vector registers.

Change-Id: I8f06aa5ee5020b3213a4f68644c205c9d6b9d214

* Show gdb the actual size of the vector registers.

This length may be different per hart.

Change-Id: I92e95383da82ee7a5c995822a53d51b1ea933493

* Remove outdated todo comment.

Change-Id: Ic9158b002858f0d15a6452773b095aa5f4501128

* Removed TODO comment.

Filed #449 to track this.

Change-Id: I5277b19e545df2024f34cda39158ddf7d0d89d47

* Nicely handle some errors reading/writing V regs.

Change-Id: Ia7bb63a5f9433d9f7b46496b2c0994864cfc4a09
2020-02-14 14:54:05 -08:00
Tim Newsome 7cb8843794
Update the current thread when gdb requests a step. (#444)
Evidently this is what gdb expects.

Change-Id: I634cdbcbcfab149c1b916e3744ff4915a8f8669b
2020-01-31 12:56:46 -08:00
Tim Newsome 2f456abd55
Complain about debug version before authentication. (#441)
Change-Id: I769af8323545c2c18e4253a1543e9202f0bdfabc
2020-01-27 16:07:08 -08:00
Tim Newsome 69e6891434
Handle DMI busy in sba write. (#437)
* Handle DMI busy in sba write.

If we encounter DMI busy on the NOP after a read, we'll never get the
value out because DMI busy is sticky. The read must be retried, but we
don't know whether it was ever issued. Since the read has side effects
(incrementing of the address) this retry must be handled at a higher
layer. So now dmi_op_timeout can be told to retry or not, and if retry
is disabled it'll return an error when busy.

Also actually properly do the retry in dmi_op_timeout(). Previously the
code would not reissue the command and end up returning a garbage value.

Change-Id: I3b52ebd51ebbbedd6e425676ac861b57fbe711b1

* Fix whitespace.

Change-Id: Icb76d964e681b22346368d224d1930c9342343f3

* Handle a few more DMI busy cases.

Change-Id: I8503a44e4bf935c0ebfff0d598fe4c322fda702a

* Explain when to use dmi_op_timeout(retry).

Change-Id: I1a5c6d76ac41a84472a8f79faecb2f48105191ff

* dmi_reset does not affect the current transaction.

That means the retry scheme we had been using works fine. This does
contain some minor tweaks, and now we pass my tests which hammer the DMI
busy case harder.

Change-Id: I13eee384dbba82bc5a5b1d387c75c547afe557b5

* Remove unnecessary changes to make the PR readable

Change-Id: I87079876e6965563cf590e3936b3595aeab8715d

* Move idle to end of line...

... because we go through run-test/idle after the scan.

Change-Id: I21a8cff22471f0b895d8cd8d25373dced9bf1ca9

* Remove unused code.

Change-Id: I07a7cdd2d64ca40a4fe181111a34cf55ff1928d1
2020-01-13 15:10:43 -08:00
Jan Matyas fcea4f79ba Don't issue extra FENCE+FENCE.i for the current hart. (#439)
The original OpenOCD code issued FENCE & FENCE.i twice for the current
hart (which is harmless, but takes time).

Avoiding this extra FENCE is a slight performance improvement. Per my rough
measurements, this improves performance of certain debugger actions
(single-stepping) by approx. 20% in single-hart systems.
2020-01-10 12:29:10 -08:00
Tim Newsome 8b8db033ee
Upcast mask value to work with 64-bit physical (#436)
Change-Id: I00f0d2a3c79a431e1aa49c7478fa6c17e2fa5256
2020-01-06 16:57:15 -08:00
Hsiangkai 2c3f099b73 Fix bugs. Do not touch SATP if there is no MMU. (#435)
* riscv: Fix bugs. Do not touch SATP if there is no MMU.

In some platform, there is no SATP register at all.
OpenOCD will report unexpected errors if SATP is unreadable.
So, use 'riscv_enable_virtual' to guard SATP access.

* riscv: fix format typo.
2019-12-31 11:27:22 -08:00
32 changed files with 3325 additions and 502 deletions

2
.gitignore vendored
View File

@ -99,3 +99,5 @@ TAGS
# ctags tag files
tags
release/

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "jimtcl"]
path = jimtcl
url = https://github.com/msteveb/jimtcl
url = https://gitee.com/liangkangnan/jimtcl

2
README
View File

@ -118,7 +118,7 @@ Debug targets
ARM11, ARM7, ARM9, AVR32, Cortex-A, Cortex-R, Cortex-M, LS102x-SAP,
Feroceon/Dragonite, DSP563xx, DSP5680xx, EnSilica eSi-RISC, FA526, MIPS
EJTAG, NDS32, XScale, Intel Quark.
EJTAG, NDS32, RISC-V, XScale, Intel Quark.
Flash drivers
-------------

55
README.md Normal file
View File

@ -0,0 +1,55 @@
# 编译Windows版本
## 1.安装msys2
到[msys2官网](https://www.msys2.org/)下载安装最新的64位版本安装完成后打开mingw-32bit窗口执行以下命令安装依赖
`pacman -S autoconf automake pkg-config libtool binutils gcc git make mingw-w64-i686-toolchain mingw-w64-i686-libusb mingw-w64-i686-hidapi mingw-w64-i686-libftdi`
## 2.下载源码
下载本项目的所有代码到msys2的某个目录下
`git clone --recursive https://gitee.com/liangkangnan/tinyriscv-openocd.git`
## 3.编译源码
### 3.1第一次编译或者重新编译
在项目的根目录下,执行以下命令:
`./rebuild.sh`
### 3.2打包openocd.exe
编译完成后就可以打包了,执行以下命令进行打包:
`./release.sh`
打包后的文件在根目录下的release目录里可以把整个release目录拷贝到电脑的其他目录下使用。
### 3.3修改源码后编译
修改源码后只需要执行make命令即可编译。
`make`
编译完可以按照步骤3.2进行打包。
# 编译Linux版本
以ubuntu系统为例。
## 1.安装依赖
`sudo apt-get install autoconf automake pkg-config libtool libusb-dev libusb-1.0-0-dev libhidapi-dev`
## 2.编译
```
./bootstrap
./configure --enable-remote-bitbang --enable-cmsis-dap --enable-ftdi
make
```
编译完成后会在src/目录下生成openocd可执行文件。

View File

@ -109,6 +109,8 @@ ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", MODE="660", GROUP="plugdev",
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1016", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1018", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1051", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1061", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Raisonance RLink
ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="660", GROUP="plugdev", TAG+="uaccess"

View File

@ -0,0 +1,70 @@
/* Autogenerated with ./bin2char.sh */
0x97,0x21,0x00,0x00,0x93,0x81,0x01,0x80,0x13,0x81,0x01,0xc0,0x17,0x05,0x00,0x00,
0x13,0x05,0x45,0x44,0x97,0x15,0x00,0x00,0x93,0x85,0xc5,0xfe,0x17,0x16,0x00,0x00,
0x13,0x06,0x46,0xfe,0x63,0xfc,0xc5,0x00,0x83,0x22,0x05,0x00,0x23,0xa0,0x55,0x00,
0x13,0x05,0x45,0x00,0x93,0x85,0x45,0x00,0xe3,0xe8,0xc5,0xfe,0x17,0x15,0x00,0x00,
0x13,0x05,0x45,0xfc,0x93,0x85,0x81,0x81,0x63,0x78,0xb5,0x00,0x23,0x20,0x05,0x00,
0x13,0x05,0x45,0x00,0xe3,0x6c,0xb5,0xfe,0x13,0x05,0x00,0x00,0x93,0x05,0x00,0x00,
0xef,0x00,0x80,0x00,0x6f,0x00,0x00,0x00,0x13,0x01,0x01,0xff,0x23,0x26,0x11,0x00,
0x23,0x24,0x81,0x00,0x13,0x04,0x01,0x01,0xb7,0x17,0x00,0x20,0x37,0x17,0x00,0x20,
0x13,0x07,0x07,0x50,0x23,0xa0,0xe7,0x00,0xb7,0x17,0x00,0x20,0x37,0x17,0x00,0x20,
0x13,0x07,0xc7,0x40,0x23,0xa2,0xe7,0x00,0xb7,0x17,0x00,0x20,0x93,0x87,0x07,0x40,
0x03,0xa7,0x07,0x00,0x23,0xa4,0xe1,0x80,0xb7,0x17,0x00,0x20,0x93,0x87,0x47,0x40,
0x03,0xa7,0x07,0x00,0x23,0xa6,0xe1,0x80,0xb7,0x17,0x00,0x20,0x93,0x87,0x87,0x40,
0x03,0xa7,0x07,0x00,0x23,0xa8,0xe1,0x80,0xb7,0x17,0x00,0x20,0x83,0xa7,0x47,0x00,
0x23,0xa0,0x07,0x00,0xef,0x00,0x80,0x08,0x83,0xa7,0x01,0x81,0x63,0x80,0x07,0x02,
0x83,0xa7,0xc1,0x80,0x13,0x85,0x07,0x00,0xef,0x00,0x00,0x2c,0x93,0x07,0x05,0x00,
0x13,0x87,0x07,0x00,0x23,0x8a,0xe1,0x80,0x6f,0x00,0x00,0x03,0x03,0xa7,0xc1,0x80,
0xb7,0x17,0x00,0x20,0x83,0xa6,0x07,0x00,0x83,0xa7,0x81,0x80,0x13,0x86,0x07,0x00,
0x93,0x85,0x06,0x00,0x13,0x05,0x07,0x00,0xef,0x00,0x40,0x10,0x93,0x07,0x05,0x00,
0x13,0x87,0x07,0x00,0x23,0x8a,0xe1,0x80,0xef,0x00,0x40,0x06,0x83,0xc7,0x41,0x81,
0x63,0x8c,0x07,0x00,0xb7,0x17,0x00,0x20,0x83,0xa7,0x47,0x00,0x13,0x07,0x30,0x00,
0x23,0xa0,0xe7,0x00,0x6f,0x00,0x40,0x01,0xb7,0x17,0x00,0x20,0x83,0xa7,0x47,0x00,
0x13,0x07,0x10,0x00,0x23,0xa0,0xe7,0x00,0x6f,0x00,0x00,0x00,0x13,0x01,0x01,0xff,
0x23,0x26,0x81,0x00,0x13,0x04,0x01,0x01,0xb7,0x07,0x00,0x0e,0x03,0xa7,0x07,0x00,
0xb7,0x07,0x00,0x0e,0x13,0x67,0x87,0x00,0x23,0xa0,0xe7,0x00,0x13,0x00,0x00,0x00,
0x03,0x24,0xc1,0x00,0x13,0x01,0x01,0x01,0x67,0x80,0x00,0x00,0x13,0x01,0x01,0xff,
0x23,0x26,0x81,0x00,0x13,0x04,0x01,0x01,0xb7,0x07,0x00,0x0e,0x03,0xa7,0x07,0x00,
0xb7,0x07,0x00,0x0e,0x13,0x77,0x77,0xff,0x23,0xa0,0xe7,0x00,0x13,0x00,0x00,0x00,
0x03,0x24,0xc1,0x00,0x13,0x01,0x01,0x01,0x67,0x80,0x00,0x00,0x13,0x01,0x01,0xff,
0x23,0x26,0x81,0x00,0x13,0x04,0x01,0x01,0xb7,0x07,0x00,0x0e,0x03,0xa7,0x07,0x00,
0xb7,0x07,0x00,0x0e,0x13,0x67,0x07,0x01,0x23,0xa0,0xe7,0x00,0x13,0x00,0x00,0x00,
0x03,0x24,0xc1,0x00,0x13,0x01,0x01,0x01,0x67,0x80,0x00,0x00,0x13,0x01,0x01,0xff,
0x23,0x26,0x81,0x00,0x13,0x04,0x01,0x01,0xb7,0x07,0x00,0x0e,0x03,0xa7,0x07,0x00,
0xb7,0x07,0x00,0x0e,0x13,0x77,0xf7,0xfe,0x23,0xa0,0xe7,0x00,0x13,0x00,0x00,0x00,
0x03,0x24,0xc1,0x00,0x13,0x01,0x01,0x01,0x67,0x80,0x00,0x00,0x13,0x01,0x01,0xfd,
0x23,0x26,0x11,0x02,0x23,0x24,0x81,0x02,0x13,0x04,0x01,0x03,0x23,0x2e,0xa4,0xfc,
0x23,0x2c,0xb4,0xfc,0x23,0x2a,0xc4,0xfc,0xb7,0x07,0x00,0x0e,0x03,0xa7,0x07,0x00,
0xb7,0x07,0x00,0x0e,0x13,0x77,0x97,0xff,0x23,0xa0,0xe7,0x00,0xb7,0x07,0x00,0x0e,
0x03,0xa7,0x07,0x00,0xb7,0x07,0x00,0x0e,0x13,0x67,0x27,0x00,0x23,0xa0,0xe7,0x00,
0xb7,0x07,0x00,0x0e,0x93,0x87,0x47,0x00,0x83,0x26,0xc4,0xfd,0x37,0x07,0x80,0x00,
0x13,0x07,0xf7,0xff,0x33,0xf7,0xe6,0x00,0x23,0xa0,0xe7,0x00,0x03,0x27,0x44,0xfd,
0x93,0x07,0x40,0x00,0x63,0xf4,0xe7,0x00,0xef,0xf0,0x5f,0xf3,0x83,0x27,0x44,0xfd,
0x23,0x20,0xf4,0xfe,0x23,0x24,0x04,0xfe,0x6f,0x00,0x40,0x0b,0x03,0x27,0x04,0xfe,
0x93,0x07,0x00,0x02,0x63,0xf8,0xe7,0x00,0x93,0x07,0x00,0x02,0x23,0x22,0xf4,0xfe,
0x6f,0x00,0xc0,0x00,0x83,0x27,0x04,0xfe,0x23,0x22,0xf4,0xfe,0x03,0x27,0x04,0xfe,
0x83,0x27,0x44,0xfe,0xb3,0x07,0xf7,0x40,0x23,0x20,0xf4,0xfe,0x83,0x27,0x44,0xfe,
0x93,0xd7,0x27,0x00,0x23,0x22,0xf4,0xfe,0x23,0x26,0x04,0xfe,0x6f,0x00,0x40,0x06,
0x83,0x27,0x84,0xfe,0x93,0x97,0x27,0x00,0x03,0x27,0x84,0xfd,0x33,0x07,0xf7,0x00,
0xb7,0x07,0x00,0x0e,0x93,0x87,0x87,0x00,0x03,0x27,0x07,0x00,0x23,0xa0,0xe7,0x00,
0xb7,0x07,0x00,0x0e,0x03,0xa7,0x07,0x00,0xb7,0x07,0x00,0x0e,0x13,0x67,0x17,0x00,
0x23,0xa0,0xe7,0x00,0x13,0x00,0x00,0x00,0xb7,0x07,0x00,0x0e,0x83,0xa7,0x07,0x00,
0x93,0xf7,0x17,0x00,0xe3,0x9a,0x07,0xfe,0x83,0x27,0x84,0xfe,0x93,0x87,0x17,0x00,
0x23,0x24,0xf4,0xfe,0x83,0x27,0xc4,0xfe,0x93,0x87,0x17,0x00,0x23,0x26,0xf4,0xfe,
0x03,0x27,0xc4,0xfe,0x83,0x27,0x44,0xfe,0xe3,0x6c,0xf7,0xf8,0x83,0x27,0x04,0xfe,
0xe3,0x96,0x07,0xf4,0x03,0x27,0x44,0xfd,0x93,0x07,0x40,0x00,0x63,0xfe,0xe7,0x00,
0xef,0xf0,0xdf,0xe8,0x13,0x00,0x00,0x00,0xb7,0x07,0x00,0x0e,0x83,0xa7,0x07,0x00,
0x93,0xf7,0x17,0x00,0xe3,0x9a,0x07,0xfe,0xb7,0x07,0x00,0x0e,0x83,0xa7,0x07,0x00,
0x93,0xf7,0x07,0x02,0x63,0x86,0x07,0x00,0x93,0x07,0x00,0x00,0x6f,0x00,0x80,0x00,
0x93,0x07,0x10,0x00,0x13,0x85,0x07,0x00,0x83,0x20,0xc1,0x02,0x03,0x24,0x81,0x02,
0x13,0x01,0x01,0x03,0x67,0x80,0x00,0x00,0x13,0x01,0x01,0xfe,0x23,0x2e,0x81,0x00,
0x13,0x04,0x01,0x02,0x23,0x26,0xa4,0xfe,0xb7,0x07,0x00,0x0e,0x03,0xa7,0x07,0x00,
0xb7,0x07,0x00,0x0e,0x13,0x77,0x97,0xff,0x23,0xa0,0xe7,0x00,0xb7,0x07,0x00,0x0e,
0x03,0xa7,0x07,0x00,0xb7,0x07,0x00,0x0e,0x13,0x67,0x47,0x00,0x23,0xa0,0xe7,0x00,
0xb7,0x07,0x00,0x0e,0x93,0x87,0x47,0x00,0x83,0x26,0xc4,0xfe,0x37,0x07,0x80,0x00,
0x13,0x07,0xf7,0xff,0x33,0xf7,0xe6,0x00,0x23,0xa0,0xe7,0x00,0xb7,0x07,0x00,0x0e,
0x03,0xa7,0x07,0x00,0xb7,0x07,0x00,0x0e,0x13,0x67,0x17,0x00,0x23,0xa0,0xe7,0x00,
0x13,0x00,0x00,0x00,0xb7,0x07,0x00,0x0e,0x83,0xa7,0x07,0x00,0x93,0xf7,0x17,0x00,
0xe3,0x9a,0x07,0xfe,0xb7,0x07,0x00,0x0e,0x83,0xa7,0x07,0x00,0x93,0xf7,0x07,0x02,
0x63,0x86,0x07,0x00,0x93,0x07,0x00,0x00,0x6f,0x00,0x80,0x00,0x93,0x07,0x10,0x00,
0x13,0x85,0x07,0x00,0x03,0x24,0xc1,0x01,0x13,0x01,0x01,0x02,0x67,0x80,0x00,0x00,

View File

@ -9468,20 +9468,20 @@ This is used to access 64-bit floating point registers on 32-bit targets.
@end deffn
@deffn Command {riscv set_prefer_sba} on|off
When on, prefer to use System Bus Access to access memory. When off, prefer to
use the Program Buffer to access memory.
When on, prefer to use System Bus Access to access memory. When off (default),
prefer to use the Program Buffer to access memory.
@end deffn
@deffn Command {riscv set_enable_virtual} on|off
When on, memory accesses are performed on physical or virtual memory depending
on the current system configuration. When off, all memory accessses are performed
on the current system configuration. When off (default), all memory accessses are performed
on physical memory.
@end deffn
@deffn Command {riscv set_enable_virt2phys} on|off
When on, memory accesses are performed on physical or virtual memory depending
on the current satp configuration. When off, all memory accessses are performed
on physical memory.
When on (default), memory accesses are performed on physical or virtual memory
depending on the current satp configuration. When off, all memory accessses are
performed on physical memory.
@end deffn
@deffn Command {riscv resume_order} normal|reversed
@ -9511,6 +9511,21 @@ Enable or disable use of a BSCAN tunnel to reach DM. Supply the width of
the DM transport TAP's instruction register to enable. Supply a value of 0 to disable.
@end deffn
@deffn Command {riscv set_ebreakm} on|off
Control dcsr.ebreakm. When on (default), M-mode ebreak instructions trap to
OpenOCD. When off, they generate a breakpoint exception handled internally.
@end deffn
@deffn Command {riscv set_ebreaks} on|off
Control dcsr.ebreaks. When on (default), S-mode ebreak instructions trap to
OpenOCD. When off, they generate a breakpoint exception handled internally.
@end deffn
@deffn Command {riscv set_ebreaku} on|off
Control dcsr.ebreaku. When on (default), U-mode ebreak instructions trap to
OpenOCD. When off, they generate a breakpoint exception handled internally.
@end deffn
@subsection RISC-V Authentication Commands
The following commands can be used to authenticate to a RISC-V system. Eg. a

19
rebuild.sh Normal file
View File

@ -0,0 +1,19 @@
#!/bin/bash
set -e
BASE=`pwd`
NPROC=${NPROC:-$((`nproc`*2))}
PARALLEL=${PARALLEL:--j${NPROC}}
echo "building openocd......"
./bootstrap
./configure --build=i686-w64-mingw32 --host=i686-w64-mingw32 --disable-gccwarnings CFLAGS="-O2"
sed -i '$d' ./src/jtag/drivers/libjaylink/config.h
sed -i '$d' ./src/jtag/drivers/libjaylink/config.h
sed -i '$d' ./src/jtag/drivers/libjaylink/config.h
make ${PARALLEL}

25
release.sh Normal file
View File

@ -0,0 +1,25 @@
#!/bin/bash
set -e
BASE=`pwd`
NPROC=${NPROC:-$((`nproc`*2))}
PARALLEL=${PARALLEL:--j${NPROC}}
echo "relase openocd......"
rm -rf release
mkdir -p release
cp ./src/openocd.exe ./release
cp /mingw32/bin/libconfuse-2.dll ./release
cp /mingw32/bin/libftdi1.dll ./release
cp /mingw32/bin/libftdipp1.dll ./release
cp /mingw32/bin/libgcc_s_dw2-1.dll ./release
cp /mingw32/bin/libhidapi-0.dll ./release
cp /mingw32/bin/libiconv-2.dll ./release
cp /mingw32/bin/libintl-8.dll ./release
cp /mingw32/bin/libstdc++-6.dll ./release
cp /mingw32/bin/libusb-1.0.dll ./release
cp /mingw32/bin/libwinpthread-1.dll ./release

View File

@ -136,7 +136,8 @@ struct fespi_target {
/* TODO !!! What is the right naming convention here? */
static const struct fespi_target target_devices[] = {
/* name, tap_idcode, ctrl_base */
{ "Freedom E300 SPI Flash", 0x10e31913 , 0x10014000 },
{ "Freedom E310-G000 SPI Flash", 0x10e31913 , 0x10014000 },
{ "Freedom E310-G002 SPI Flash", 0x20000913 , 0x10014000 },
{ NULL, 0, 0 }
};
@ -495,7 +496,7 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
{
struct target *target = bank->target;
struct fespi_flash_bank *fespi_info = bank->driver_priv;
uint32_t cur_count, page_size, page_offset;
uint32_t cur_count, page_size;
int sector;
int retval = ERROR_OK;
@ -547,8 +548,8 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
algorithm_wa->address, retval);
target_free_working_area(target, algorithm_wa);
algorithm_wa = NULL;
}
} else {
data_wa_size = MIN(target->working_area_size - algorithm_wa->size, count);
while (1) {
if (data_wa_size < 128) {
@ -563,6 +564,7 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
data_wa_size = data_wa_size * 3 / 4;
}
}
} else {
LOG_WARNING("Couldn't allocate %zd-byte working area.", bin_size);
algorithm_wa = NULL;
@ -620,7 +622,6 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
goto err;
}
page_offset = 0;
buffer += cur_count;
offset += cur_count;
count -= cur_count;
@ -641,7 +642,7 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
if (retval != ERROR_OK)
goto err;
page_offset = offset % page_size;
uint32_t page_offset = offset % page_size;
/* central part, aligned words */
while (count > 0) {
/* clip block at page boundary */

View File

@ -1309,7 +1309,7 @@
[10][0x34 - 1] = "Xiamen Kingblaze Technology Co Ltd",
[10][0x35 - 1] = "Shenzhen Lomica Technology Co Ltd",
[10][0x36 - 1] = "Nuclei System Technology Co Ltd",
[10][0x37 - 1] = "Wuhan Xun Zhan Electronic Technology",
[10][0x37 - 1] = "LiangKangNan",
[10][0x38 - 1] = "Shenzhen Ingacom Semiconductor Ltd",
[10][0x39 - 1] = "Zotac Technology Ltd",
[10][0x3a - 1] = "Foxline",

View File

@ -151,6 +151,7 @@ extern int debug_level;
#define ERROR_WAIT (-5)
/* ERROR_TIMEOUT is already taken by winerror.h. */
#define ERROR_TIMEOUT_REACHED (-6)
#define ERROR_NOT_IMPLEMENTED (-7)
#endif /* OPENOCD_HELPER_LOG_H */

View File

@ -34,9 +34,12 @@
#if IS_DARWIN
#include <libproc.h>
#endif
/* sys/sysctl.h is deprecated on Linux from glibc 2.30 */
#ifndef __linux__
#ifdef HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
#endif
#endif
#if IS_WIN32 && !IS_CYGWIN
#include <windows.h>
#endif

View File

@ -37,5 +37,6 @@ ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1016", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1018", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1051", MODE="664", GROUP="plugdev"
LABEL="libjaylink_end_rules"

View File

@ -59,7 +59,9 @@ static const uint16_t pids[][2] = {
{0x1015, 0},
{0x1016, 0},
{0x1017, 0},
{0x1018, 0}
{0x1018, 0},
{0x1051, 0},
{0x1061, 0}
};
/** Maximum length of the USB string descriptor for the serial number. */

View File

@ -39,6 +39,10 @@ static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]
static int hwthread_smp_init(struct target *target);
int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
bool hwthread_needs_fake_step(struct target *target, int64_t thread_id);
int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
uint32_t size, uint8_t *buffer);
int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
uint32_t size, const uint8_t *buffer);
#define HW_THREAD_NAME_STR_SIZE (32)
@ -59,7 +63,9 @@ const struct rtos_type hwthread_rtos = {
.get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup,
.smp_init = hwthread_smp_init,
.set_reg = hwthread_set_reg,
.needs_fake_step = hwthread_needs_fake_step
.needs_fake_step = hwthread_needs_fake_step,
.read_buffer = hwthread_read_buffer,
.write_buffer = hwthread_write_buffer,
};
struct hwthread_params {
@ -393,3 +399,33 @@ bool hwthread_needs_fake_step(struct target *target, int64_t thread_id)
{
return false;
}
int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
uint32_t size, uint8_t *buffer)
{
if (rtos == NULL)
return ERROR_FAIL;
struct target *target = rtos->target;
struct target *curr = find_thread(target, rtos->current_thread);
if (curr == NULL)
return ERROR_FAIL;
return target_read_buffer(curr, address, size, buffer);
}
int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
uint32_t size, const uint8_t *buffer)
{
if (rtos == NULL)
return ERROR_FAIL;
struct target *target = rtos->target;
struct target *curr = find_thread(target, rtos->current_thread);
if (curr == NULL)
return ERROR_FAIL;
return target_write_buffer(curr, address, size, buffer);
}

View File

@ -257,25 +257,26 @@ static int riscv_gdb_v_packet(struct connection *connection, const char *packet,
if (sscanf(packet_stttrr, "vCont;s:%d;c", &threadid) == 1) {
riscv_set_rtos_hartid(target, threadid - 1);
riscv_step_rtos_hart(target);
/* Stepping changes the current thread to whichever thread was stepped. */
target->rtos->current_threadid = threadid;
gdb_put_packet(connection, "S05", 3);
return JIM_OK;
}
if (strcmp(packet_stttrr, "vCont;c") == 0) {
} else if (strcmp(packet_stttrr, "vCont;c") == 0) {
target_call_event_callbacks(target, TARGET_EVENT_GDB_START);
target_call_event_callbacks(target, TARGET_EVENT_RESUME_START);
riscv_set_all_rtos_harts(target);
riscv_resume(target, 1, 0, 0, 0);
riscv_resume(target, 1, 0, 0, 0, false);
target->state = TARGET_RUNNING;
gdb_set_frontend_state_running(connection);
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
target_call_event_callbacks(target, TARGET_EVENT_RESUME_END);
return JIM_OK;
}
if (strncmp(packet_stttrr, "vCont", 5) == 0)
} else if (strncmp(packet_stttrr, "vCont", 5) == 0) {
LOG_ERROR("Got unknown vCont-type packet");
}
return GDB_THREAD_PACKET_NOT_CONSUMED;
}

View File

@ -680,3 +680,19 @@ bool rtos_needs_fake_step(struct target *target, int64_t thread_id)
return target->rtos->type->needs_fake_step(target, thread_id);
return target->rtos->current_thread != thread_id;
}
int rtos_read_buffer(struct target *target, target_addr_t address,
uint32_t size, uint8_t *buffer)
{
if (target->rtos->type->read_buffer)
return target->rtos->type->read_buffer(target->rtos, address, size, buffer);
return ERROR_NOT_IMPLEMENTED;
}
int rtos_write_buffer(struct target *target, target_addr_t address,
uint32_t size, const uint8_t *buffer)
{
if (target->rtos->type->write_buffer)
return target->rtos->type->write_buffer(target->rtos, address, size, buffer);
return ERROR_NOT_IMPLEMENTED;
}

View File

@ -90,6 +90,13 @@ struct rtos_type {
* target running a multi-threading OS. If an RTOS can do this, override
* needs_fake_step(). */
bool (*needs_fake_step)(struct target *target, int64_t thread_id);
/* Implement these if different threads in the RTOS can see memory
* differently (for instance because address translation might be different
* for each thread). */
int (*read_buffer)(struct rtos *rtos, target_addr_t address, uint32_t size,
uint8_t *buffer);
int (*write_buffer)(struct rtos *rtos, target_addr_t address, uint32_t size,
const uint8_t *buffer);
};
struct stack_register_offset {
@ -136,5 +143,9 @@ int rtos_smp_init(struct target *target);
/* function for handling symbol access */
int rtos_qsymbol(struct connection *connection, char const *packet, int packet_size);
bool rtos_needs_fake_step(struct target *target, int64_t thread_id);
int rtos_read_buffer(struct target *target, target_addr_t address,
uint32_t size, uint8_t *buffer);
int rtos_write_buffer(struct target *target, target_addr_t address,
uint32_t size, const uint8_t *buffer);
#endif /* OPENOCD_RTOS_RTOS_H */

View File

@ -1425,7 +1425,7 @@ static int gdb_read_memory_packet(struct connection *connection,
uint8_t *buffer;
char *hex_buffer;
int retval = ERROR_OK;
int retval;
/* skip command character */
packet++;
@ -1449,6 +1449,10 @@ static int gdb_read_memory_packet(struct connection *connection,
LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
retval = ERROR_NOT_IMPLEMENTED;
if (target->rtos != NULL)
retval = rtos_read_buffer(target, addr, len, buffer);
if (retval == ERROR_NOT_IMPLEMENTED)
retval = target_read_buffer(target, addr, len, buffer);
if ((retval != ERROR_OK) && !gdb_report_data_abort) {
@ -1520,6 +1524,10 @@ static int gdb_write_memory_packet(struct connection *connection,
if (unhexify(buffer, separator, len) != len)
LOG_ERROR("unable to decode memory packet");
retval = ERROR_NOT_IMPLEMENTED;
if (target->rtos != NULL)
retval = rtos_write_buffer(target, addr, len, buffer);
if (retval == ERROR_NOT_IMPLEMENTED)
retval = target_write_buffer(target, addr, len, buffer);
if (retval == ERROR_OK)
@ -1589,7 +1597,12 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
if (len) {
LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
retval = ERROR_NOT_IMPLEMENTED;
if (target->rtos != NULL)
retval = rtos_write_buffer(target, addr, len, (uint8_t *)separator);
if (retval == ERROR_NOT_IMPLEMENTED)
retval = target_write_buffer(target, addr, len, (uint8_t *)separator);
if (retval != ERROR_OK)
gdb_connection->mem_write_error = true;
}

View File

@ -162,14 +162,13 @@ void dump_field(int idle, const struct scan_field *field)
log_printf_lf(LOG_LVL_DEBUG,
__FILE__, __LINE__, __PRETTY_FUNCTION__,
"%db %di %s %08x @%02x -> %s %08x @%02x",
field->num_bits, idle,
op_string[out_op], out_data, out_address,
status_string[in_op], in_data, in_address);
"%db %s %08x @%02x -> %s %08x @%02x; %di",
field->num_bits, op_string[out_op], out_data, out_address,
status_string[in_op], in_data, in_address, idle);
} else {
log_printf_lf(LOG_LVL_DEBUG,
__FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %di %s %08x @%02x -> ?",
field->num_bits, idle, op_string[out_op], out_data, out_address);
__FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?; %di",
field->num_bits, op_string[out_op], out_data, out_address, idle);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -76,6 +76,12 @@ enum gdb_regno {
GDB_REGNO_FT11,
GDB_REGNO_FPR31 = GDB_REGNO_FT11,
GDB_REGNO_CSR0 = 65,
GDB_REGNO_VSTART = CSR_VSTART + GDB_REGNO_CSR0,
GDB_REGNO_VXSAT = CSR_VXSAT + GDB_REGNO_CSR0,
GDB_REGNO_VXRM = CSR_VXRM + GDB_REGNO_CSR0,
GDB_REGNO_VLENB = CSR_VLENB + GDB_REGNO_CSR0,
GDB_REGNO_VL = CSR_VL + GDB_REGNO_CSR0,
GDB_REGNO_VTYPE = CSR_VTYPE + GDB_REGNO_CSR0,
GDB_REGNO_TSELECT = CSR_TSELECT + GDB_REGNO_CSR0,
GDB_REGNO_TDATA1 = CSR_TDATA1 + GDB_REGNO_CSR0,
GDB_REGNO_TDATA2 = CSR_TDATA2 + GDB_REGNO_CSR0,
@ -89,6 +95,18 @@ enum gdb_regno {
GDB_REGNO_SATP = CSR_SATP + GDB_REGNO_CSR0,
GDB_REGNO_CSR4095 = GDB_REGNO_CSR0 + 4095,
GDB_REGNO_PRIV = 4161,
/* It's still undecided what register numbers GDB will actually use for
* these. See
* https://groups.google.com/a/groups.riscv.org/d/msg/sw-dev/7lQYiTUN9Ms/gTxGhzaYBQAJ
*/
GDB_REGNO_V0, GDB_REGNO_V1, GDB_REGNO_V2, GDB_REGNO_V3,
GDB_REGNO_V4, GDB_REGNO_V5, GDB_REGNO_V6, GDB_REGNO_V7,
GDB_REGNO_V8, GDB_REGNO_V9, GDB_REGNO_V10, GDB_REGNO_V11,
GDB_REGNO_V12, GDB_REGNO_V13, GDB_REGNO_V14, GDB_REGNO_V15,
GDB_REGNO_V16, GDB_REGNO_V17, GDB_REGNO_V18, GDB_REGNO_V19,
GDB_REGNO_V20, GDB_REGNO_V21, GDB_REGNO_V22, GDB_REGNO_V23,
GDB_REGNO_V24, GDB_REGNO_V25, GDB_REGNO_V26, GDB_REGNO_V27,
GDB_REGNO_V28, GDB_REGNO_V29, GDB_REGNO_V30, GDB_REGNO_V31,
GDB_REGNO_COUNT
};

View File

@ -323,3 +323,33 @@ static uint32_t auipc(unsigned int dest)
{
return MATCH_AUIPC | (dest << 7);
}
static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm) __attribute__((unused));
static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm)
{
return (bits(imm, 10, 0) << 20) |
(src << 15) |
(dest << 7) |
MATCH_VSETVLI;
}
static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2) __attribute__((unused));
static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2)
{
return (vs2 << 20) | (rd << 7) | MATCH_VMV_X_S;
}
static uint32_t vmv_s_x(unsigned int vd, unsigned int vs2) __attribute__((unused));
static uint32_t vmv_s_x(unsigned int vd, unsigned int rs1)
{
return (rs1 << 15) | (vd << 7) | MATCH_VMV_S_X;
}
static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
unsigned int rs1, unsigned int vm) __attribute__((unused));
static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
unsigned int rs1, unsigned int vm)
{
return (vm << 25) | (vs2 << 20) | (rs1 << 15) | (vd << 7) |
MATCH_VSLIDE1DOWN_VX;
}

View File

@ -56,7 +56,8 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
if (riscv_program_ebreak(p) != ERROR_OK) {
LOG_ERROR("Unable to write ebreak");
for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
LOG_ERROR("ram[%02x]: DASM(0x%08lx) [0x%08lx]", (int)i, (long)p->debug_buffer[i], (long)p->debug_buffer[i]);
LOG_ERROR("ram[%02x]: DASM(0x%08lx) [0x%08lx]", (int)i,
(long)p->debug_buffer[i], (long)p->debug_buffer[i]);
return ERROR_FAIL;
}

View File

@ -1114,7 +1114,10 @@ static int execute_resume(struct target *target, bool step)
}
}
info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU;
info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
info->dcsr &= ~DCSR_HALT;
if (step)
@ -1946,8 +1949,11 @@ static int assert_reset(struct target *target)
/* Not sure what we should do when there are multiple cores.
* Here just reset the single hart we're talking to. */
info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS |
DCSR_EBREAKU | DCSR_HALT;
info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
info->dcsr |= DCSR_HALT;
if (target->reset_halt)
info->dcsr |= DCSR_NDRESET;
else

View File

@ -92,6 +92,7 @@ static int riscv013_test_compliance(struct target *target);
#define CSR_DCSR_CAUSE_DEBUGINT 3
#define CSR_DCSR_CAUSE_STEP 4
#define CSR_DCSR_CAUSE_HALT 5
#define CSR_DCSR_CAUSE_GROUP 6
#define RISCV013_INFO(r) riscv013_info_t *r = get_info(target)
@ -395,10 +396,9 @@ static void dump_field(int idle, const struct scan_field *field)
log_printf_lf(LOG_LVL_DEBUG,
__FILE__, __LINE__, "scan",
"%db %di %s %08x @%02x -> %s %08x @%02x",
field->num_bits, idle,
op_string[out_op], out_data, out_address,
status_string[in_op], in_data, in_address);
"%db %s %08x @%02x -> %s %08x @%02x; %di",
field->num_bits, op_string[out_op], out_data, out_address,
status_string[in_op], in_data, in_address, idle);
char out_text[500];
char in_text[500];
@ -525,6 +525,8 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
int retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("dmi_scan failed jtag scan");
if (data_in)
*data_in = ~0;
return DMI_STATUS_FAILED;
}
@ -542,8 +544,20 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
}
/* If dmi_busy_encountered is non-NULL, this function will use it to tell the
* caller whether DMI was ever busy during this call. */
/**
* @param data_in The data we received from the target.
* @param dmi_op The operation to perform (read/write/nop).
* @param dmi_busy_encountered
* If non-NULL, will be updated to reflect whether DMI busy was
* encountered while executing this operation or not.
* @param address The address argument to that operation.
* @param data_out The data to send to the target.
* @param exec When true, this scan will execute something, so extra RTI
* cycles may be added.
* @param ensure_success
* Scan a nop after the requested operation, ensuring the
* DMI operation succeeded.
*/
static int dmi_op_timeout(struct target *target, uint32_t *data_in,
bool *dmi_busy_encountered, int dmi_op, uint32_t address,
uint32_t data_out, int timeout_sec, bool exec, bool ensure_success)
@ -606,27 +620,23 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in,
false);
if (status == DMI_STATUS_BUSY) {
increase_dmi_busy_delay(target);
if (dmi_busy_encountered)
*dmi_busy_encountered = true;
} else if (status == DMI_STATUS_SUCCESS) {
break;
} else {
LOG_ERROR("failed %s (NOP) at 0x%x, status=%d", op_name, address,
if (data_in) {
LOG_ERROR("Failed %s (NOP) at 0x%x; value=0x%x, status=%d",
op_name, address, *data_in, status);
} else {
LOG_ERROR("Failed %s (NOP) at 0x%x; status=%d", op_name, address,
status);
}
return ERROR_FAIL;
}
if (time(NULL) - start > timeout_sec)
return ERROR_TIMEOUT_REACHED;
}
if (status != DMI_STATUS_SUCCESS) {
if (status == DMI_STATUS_FAILED || !data_in) {
LOG_ERROR("Failed %s (NOP) at 0x%x; status=%d", op_name, address,
status);
} else {
LOG_ERROR("Failed %s (NOP) at 0x%x; value=0x%x, status=%d",
op_name, address, *data_in, status);
}
return ERROR_FAIL;
}
}
return ERROR_OK;
@ -676,7 +686,12 @@ int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus,
DMI_DMSTATUS, 0, timeout_sec, false, true);
if (result != ERROR_OK)
return result;
if (authenticated && !get_field(*dmstatus, DMI_DMSTATUS_AUTHENTICATED)) {
if (get_field(*dmstatus, DMI_DMSTATUS_VERSION) != 2) {
LOG_ERROR("OpenOCD only supports Debug Module version 2 (0.13), not "
"%d (dmstatus=0x%x). This error might be caused by a JTAG "
"signal issue. Try reducing the JTAG clock speed.",
get_field(*dmstatus, DMI_DMSTATUS_VERSION), *dmstatus);
} else if (authenticated && !get_field(*dmstatus, DMI_DMSTATUS_AUTHENTICATED)) {
LOG_ERROR("Debugger is not authenticated to target Debug Module. "
"(dmstatus=0x%x). Use `riscv authdata_read` and "
"`riscv authdata_write` commands to authenticate.", *dmstatus);
@ -846,6 +861,8 @@ static uint32_t access_register_command(struct target *target, uint32_t number,
command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 3);
break;
default:
LOG_ERROR("%d-bit register %s not supported.", size,
gdb_regno_name(number));
assert(0);
}
@ -865,6 +882,8 @@ static uint32_t access_register_command(struct target *target, uint32_t number,
assert(reg_info);
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
0xc000 + reg_info->custom_number);
} else {
assert(0);
}
command |= flags;
@ -883,6 +902,9 @@ static int register_read_abstract(struct target *target, uint64_t *value,
if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 &&
!info->abstract_read_csr_supported)
return ERROR_FAIL;
/* The spec doesn't define abstract register numbers for vector registers. */
if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31)
return ERROR_FAIL;
uint32_t command = access_register_command(target, number, size,
AC_ACCESS_REGISTER_TRANSFER);
@ -1041,6 +1063,56 @@ static int examine_progbuf(struct target *target)
return ERROR_OK;
}
static int is_fpu_reg(uint32_t gdb_regno)
{
return (gdb_regno >= GDB_REGNO_FPR0 && gdb_regno <= GDB_REGNO_FPR31) ||
(gdb_regno == GDB_REGNO_CSR0 + CSR_FFLAGS) ||
(gdb_regno == GDB_REGNO_CSR0 + CSR_FRM) ||
(gdb_regno == GDB_REGNO_CSR0 + CSR_FCSR);
}
static int is_vector_reg(uint32_t gdb_regno)
{
return (gdb_regno >= GDB_REGNO_V0 && gdb_regno <= GDB_REGNO_V31) ||
gdb_regno == GDB_REGNO_VSTART ||
gdb_regno == GDB_REGNO_VXSAT ||
gdb_regno == GDB_REGNO_VXRM ||
gdb_regno == GDB_REGNO_VL ||
gdb_regno == GDB_REGNO_VTYPE ||
gdb_regno == GDB_REGNO_VLENB;
}
static int prep_for_register_access(struct target *target, uint64_t *mstatus,
int regno)
{
if (is_fpu_reg(regno) || is_vector_reg(regno)) {
if (register_read(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK)
return ERROR_FAIL;
if (is_fpu_reg(regno) && (*mstatus & MSTATUS_FS) == 0) {
if (register_write_direct(target, GDB_REGNO_MSTATUS,
set_field(*mstatus, MSTATUS_FS, 1)) != ERROR_OK)
return ERROR_FAIL;
} else if (is_vector_reg(regno) && (*mstatus & MSTATUS_VS) == 0) {
if (register_write_direct(target, GDB_REGNO_MSTATUS,
set_field(*mstatus, MSTATUS_VS, 1)) != ERROR_OK)
return ERROR_FAIL;
}
} else {
*mstatus = 0;
}
return ERROR_OK;
}
static int cleanup_after_register_access(struct target *target,
uint64_t mstatus, int regno)
{
if ((is_fpu_reg(regno) && (mstatus & MSTATUS_FS) == 0) ||
(is_vector_reg(regno) && (mstatus & MSTATUS_VS) == 0))
if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}
typedef enum {
SPACE_DMI_DATA,
SPACE_DMI_PROGBUF,
@ -1153,7 +1225,7 @@ static int scratch_read64(struct target *target, scratch_mem_t *scratch,
break;
case SPACE_DMI_RAM:
{
uint8_t buffer[8];
uint8_t buffer[8] = {0};
if (read_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK)
return ERROR_FAIL;
*value = buffer[0] |
@ -1239,6 +1311,10 @@ static int register_write_direct(struct target *target, unsigned number,
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
uint64_t mstatus;
if (prep_for_register_access(target, &mstatus, number) != ERROR_OK)
return ERROR_FAIL;
scratch_mem_t scratch;
bool use_scratch = false;
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 &&
@ -1263,6 +1339,10 @@ static int register_write_direct(struct target *target, unsigned number,
return ERROR_FAIL;
}
} else if (number == GDB_REGNO_VTYPE) {
riscv_program_insert(&program, csrr(S0, CSR_VL));
riscv_program_insert(&program, vsetvli(ZERO, S0, value));
} else {
if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK)
return ERROR_FAIL;
@ -1272,6 +1352,15 @@ static int register_write_direct(struct target *target, unsigned number,
riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0));
else
riscv_program_insert(&program, fmv_w_x(number - GDB_REGNO_FPR0, S0));
} else if (number == GDB_REGNO_VL) {
/* "The XLEN-bit-wide read-only vl CSR can only be updated by the
* vsetvli and vsetvl instructions, and the fault-only-rst vector
* load instruction variants." */
riscv_reg_t vtype;
if (register_read(target, &vtype, GDB_REGNO_VTYPE) != ERROR_OK)
return ERROR_FAIL;
if (riscv_program_insert(&program, vsetvli(ZERO, S0, vtype)) != ERROR_OK)
return ERROR_FAIL;
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
riscv_program_csrw(&program, S0, number);
} else {
@ -1290,6 +1379,9 @@ static int register_write_direct(struct target *target, unsigned number,
if (use_scratch)
scratch_release(target, &scratch);
if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK)
return ERROR_FAIL;
/* Restore S0. */
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
return ERROR_FAIL;
@ -1314,14 +1406,6 @@ static int register_read(struct target *target, uint64_t *value, uint32_t number
return ERROR_OK;
}
static int is_fpu_reg(uint32_t gdb_regno)
{
return (gdb_regno >= GDB_REGNO_FPR0 && gdb_regno <= GDB_REGNO_FPR31) ||
(gdb_regno == GDB_REGNO_CSR0 + CSR_FFLAGS) ||
(gdb_regno == GDB_REGNO_CSR0 + CSR_FRM) ||
(gdb_regno == GDB_REGNO_CSR0 + CSR_FCSR);
}
/** Actually read registers from the target right now. */
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
{
@ -1340,21 +1424,15 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
scratch_mem_t scratch;
bool use_scratch = false;
uint64_t s0;
riscv_reg_t s0;
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
/* Write program to move data into s0. */
uint64_t mstatus;
if (is_fpu_reg(number)) {
if (register_read(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK)
if (prep_for_register_access(target, &mstatus, number) != ERROR_OK)
return ERROR_FAIL;
if ((mstatus & MSTATUS_FS) == 0)
if (register_write_direct(target, GDB_REGNO_MSTATUS,
set_field(mstatus, MSTATUS_FS, 1)) != ERROR_OK)
return ERROR_FAIL;
}
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
if (riscv_supports_extension(target, riscv_current_hartid(target), 'D')
@ -1382,7 +1460,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
riscv_program_csrr(&program, S0, number);
} else {
LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number);
LOG_ERROR("Unsupported register: %s", gdb_regno_name(number));
return ERROR_FAIL;
}
@ -1401,8 +1479,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
return ERROR_FAIL;
}
if (is_fpu_reg(number) && (mstatus & MSTATUS_FS) == 0)
if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus) != ERROR_OK)
if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK)
return ERROR_FAIL;
/* Restore S0. */
@ -1464,6 +1541,24 @@ static int set_haltgroup(struct target *target, bool *supported)
return ERROR_OK;
}
static int discover_vlenb(struct target *target, int hartid)
{
RISCV_INFO(r);
riscv_reg_t vlenb;
if (register_read(target, &vlenb, GDB_REGNO_VLENB) != ERROR_OK) {
LOG_WARNING("Couldn't read vlenb for %s; vector register access won't "
"work.", target_name(target));
r->vlenb[hartid] = 0;
return ERROR_OK;
}
r->vlenb[hartid] = vlenb;
LOG_INFO("hart %d: Vector support with vlenb=%d", hartid, r->vlenb[hartid]);
return ERROR_OK;
}
static int examine(struct target *target)
{
/* Don't need to select dbus, since the first thing we do is read dtmcontrol. */
@ -1519,8 +1614,7 @@ static int examine(struct target *target)
return ERROR_FAIL;
LOG_DEBUG("dmstatus: 0x%08x", dmstatus);
if (get_field(dmstatus, DMI_DMSTATUS_VERSION) != 2) {
LOG_ERROR("OpenOCD only supports Debug Module version 2, not %d "
"(dmstatus=0x%x)", get_field(dmstatus, DMI_DMSTATUS_VERSION), dmstatus);
/* Error was already printed out in dmstatus_read(). */
return ERROR_FAIL;
}
@ -1643,6 +1737,11 @@ static int examine(struct target *target)
return ERROR_FAIL;
}
if (riscv_supports_extension(target, i, 'V')) {
if (discover_vlenb(target, i) != ERROR_OK)
return ERROR_FAIL;
}
/* Now init registers based on what we discovered. */
if (riscv_init_registers(target) != ERROR_OK)
return ERROR_FAIL;
@ -1750,6 +1849,153 @@ static unsigned riscv013_data_bits(struct target *target)
return riscv_xlen(target);
}
static int prep_for_vector_access(struct target *target, uint64_t *vtype,
uint64_t *vl, unsigned *debug_vl)
{
RISCV_INFO(r);
/* TODO: this continuous save/restore is terrible for performance. */
/* Write vtype and vl. */
unsigned encoded_vsew;
switch (riscv_xlen(target)) {
case 32:
encoded_vsew = 2;
break;
case 64:
encoded_vsew = 3;
break;
default:
LOG_ERROR("Unsupported xlen: %d", riscv_xlen(target));
return ERROR_FAIL;
}
/* Save vtype and vl. */
if (register_read(target, vtype, GDB_REGNO_VTYPE) != ERROR_OK)
return ERROR_FAIL;
if (register_read(target, vl, GDB_REGNO_VL) != ERROR_OK)
return ERROR_FAIL;
if (register_write_direct(target, GDB_REGNO_VTYPE, encoded_vsew << 2) != ERROR_OK)
return ERROR_FAIL;
*debug_vl = DIV_ROUND_UP(r->vlenb[r->current_hartid] * 8,
riscv_xlen(target));
if (register_write_direct(target, GDB_REGNO_VL, *debug_vl) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}
static int cleanup_after_vector_access(struct target *target, uint64_t vtype,
uint64_t vl)
{
/* Restore vtype and vl. */
if (register_write_direct(target, GDB_REGNO_VTYPE, vtype) != ERROR_OK)
return ERROR_FAIL;
if (register_write_direct(target, GDB_REGNO_VL, vl) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}
static int riscv013_get_register_buf(struct target *target,
uint8_t *value, int regno)
{
assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31);
riscv_reg_t s0;
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
uint64_t mstatus;
if (prep_for_register_access(target, &mstatus, regno) != ERROR_OK)
return ERROR_FAIL;
uint64_t vtype, vl;
unsigned debug_vl;
if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != ERROR_OK)
return ERROR_FAIL;
unsigned vnum = regno - GDB_REGNO_V0;
unsigned xlen = riscv_xlen(target);
struct riscv_program program;
riscv_program_init(&program, target);
riscv_program_insert(&program, vmv_x_s(S0, vnum));
riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true));
int result = ERROR_OK;
for (unsigned i = 0; i < debug_vl; i++) {
/* Executing the program might result in an exception if there is some
* issue with the vector implementation/instructions we're using. If that
* happens, attempt to restore as usual. We may have clobbered the
* vector register we tried to read already.
* For other failures, we just return error because things are probably
* so messed up that attempting to restore isn't going to help. */
result = riscv_program_exec(&program, target);
if (result == ERROR_OK) {
uint64_t v;
if (register_read_direct(target, &v, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
buf_set_u64(value, xlen * i, xlen, v);
} else {
break;
}
}
if (cleanup_after_vector_access(target, vtype, vl) != ERROR_OK)
return ERROR_FAIL;
if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK)
return ERROR_FAIL;
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
return ERROR_FAIL;
return result;
}
static int riscv013_set_register_buf(struct target *target,
int regno, const uint8_t *value)
{
assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31);
riscv_reg_t s0;
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
uint64_t mstatus;
if (prep_for_register_access(target, &mstatus, regno) != ERROR_OK)
return ERROR_FAIL;
uint64_t vtype, vl;
unsigned debug_vl;
if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != ERROR_OK)
return ERROR_FAIL;
unsigned vnum = regno - GDB_REGNO_V0;
unsigned xlen = riscv_xlen(target);
struct riscv_program program;
riscv_program_init(&program, target);
riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true));
int result = ERROR_OK;
for (unsigned i = 0; i < debug_vl; i++) {
if (register_write_direct(target, GDB_REGNO_S0,
buf_get_u64(value, xlen * i, xlen)) != ERROR_OK)
return ERROR_FAIL;
result = riscv_program_exec(&program, target);
if (result != ERROR_OK)
break;
}
if (cleanup_after_vector_access(target, vtype, vl) != ERROR_OK)
return ERROR_FAIL;
if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK)
return ERROR_FAIL;
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
return ERROR_FAIL;
return result;
}
static int init_target(struct command_context *cmd_ctx,
struct target *target)
{
@ -1758,6 +2004,8 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->get_register = &riscv013_get_register;
generic_info->set_register = &riscv013_set_register;
generic_info->get_register_buf = &riscv013_get_register_buf;
generic_info->set_register_buf = &riscv013_set_register_buf;
generic_info->select_current_hart = &riscv013_select_current_hart;
generic_info->is_halted = &riscv013_is_halted;
generic_info->resume_go = &riscv013_resume_go;
@ -2010,6 +2258,10 @@ static int execute_fence(struct target *target)
if (!riscv_hart_enabled(target, i))
continue;
if (i == old_hartid)
/* Fence already executed for this hart */
continue;
riscv_set_current_hartid(target, i);
struct riscv_program program;
@ -2059,28 +2311,16 @@ static int read_memory_bus_word(struct target *target, target_addr_t address,
uint32_t size, uint8_t *buffer)
{
uint32_t value;
if (size > 12) {
if (dmi_read(target, &value, DMI_SBDATA3) != ERROR_OK)
return ERROR_FAIL;
write_to_buf(buffer + 12, value, 4);
log_memory_access(address + 12, value, 4, true);
int result;
static int sbdata[4] = { DMI_SBDATA0, DMI_SBDATA1, DMI_SBDATA2, DMI_SBDATA3 };
assert(size <= 16);
for (int i = (size-1) / 4; i >= 0; i--) {
result = dmi_op(target, &value, NULL, DMI_OP_READ, sbdata[i], 0, false, true);
if (result != ERROR_OK)
return result;
write_to_buf(buffer + i * 4, value, MIN(size, 4));
log_memory_access(address + i * 4, value, MIN(size, 4), true);
}
if (size > 8) {
if (dmi_read(target, &value, DMI_SBDATA2) != ERROR_OK)
return ERROR_FAIL;
write_to_buf(buffer + 8, value, 4);
log_memory_access(address + 8, value, 4, true);
}
if (size > 4) {
if (dmi_read(target, &value, DMI_SBDATA1) != ERROR_OK)
return ERROR_FAIL;
write_to_buf(buffer + 4, value, 4);
log_memory_access(address + 4, value, 4, true);
}
if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK)
return ERROR_FAIL;
write_to_buf(buffer, value, MIN(size, 4));
log_memory_access(address, value, MIN(size, 4), true);
return ERROR_OK;
}
@ -2296,14 +2536,60 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
}
}
/* First value has been read, and is waiting for us to issue a DMI read
* to get it. */
static int sbdata[4] = {DMI_SBDATA0, DMI_SBDATA1, DMI_SBDATA2, DMI_SBDATA3};
assert(size <= 16);
target_addr_t next_read = address - 1;
for (uint32_t i = (next_address - address) / size; i < count - 1; i++) {
if (read_memory_bus_word(target, address + i * size, size,
buffer + i * size) != ERROR_OK)
for (int j = (size - 1) / 4; j >= 0; j--) {
uint32_t value;
unsigned attempt = 0;
while (1) {
if (attempt++ > 100) {
LOG_ERROR("DMI keeps being busy in while reading memory just past " TARGET_ADDR_FMT,
next_read);
return ERROR_FAIL;
}
dmi_status_t status = dmi_scan(target, NULL, &value,
DMI_OP_READ, sbdata[j], 0, false);
if (status == DMI_STATUS_BUSY)
increase_dmi_busy_delay(target);
else if (status == DMI_STATUS_SUCCESS)
break;
else
return ERROR_FAIL;
}
if (next_read != address - 1) {
write_to_buf(buffer + next_read - address, value, MIN(size, 4));
log_memory_access(next_read, value, MIN(size, 4), true);
}
next_read = address + i * size + j * 4;
}
}
uint32_t sbcs_read = 0;
if (count > 1) {
uint32_t value;
unsigned attempt = 0;
while (1) {
if (attempt++ > 100) {
LOG_ERROR("DMI keeps being busy in while reading memory just past " TARGET_ADDR_FMT,
next_read);
return ERROR_FAIL;
}
dmi_status_t status = dmi_scan(target, NULL, &value, DMI_OP_NOP, 0, 0, false);
if (status == DMI_STATUS_BUSY)
increase_dmi_busy_delay(target);
else if (status == DMI_STATUS_SUCCESS)
break;
else
return ERROR_FAIL;
}
write_to_buf(buffer + next_read - address, value, MIN(size, 4));
log_memory_access(next_read, value, MIN(size, 4), true);
/* "Writes to sbcs while sbbusy is high result in undefined behavior.
* A debugger must not write to sbcs until it reads sbbusy as 0." */
if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK)
@ -2314,6 +2600,7 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
return ERROR_FAIL;
}
/* Read the last word, after we disabled sbreadondata if necessary. */
if (!get_field(sbcs_read, DMI_SBCS_SBERROR) &&
!get_field(sbcs_read, DMI_SBCS_SBBUSYERROR)) {
if (read_memory_bus_word(target, address + (count - 1) * size, size,
@ -2495,10 +2782,10 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
int result = ERROR_OK;
/* Write address to S0, and execute buffer. */
/* Write address to S0. */
result = register_write_direct(target, GDB_REGNO_S0, address);
if (result != ERROR_OK)
goto error;
return result;
uint32_t command = access_register_command(target, GDB_REGNO_S1,
riscv_xlen(target),
AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC);
@ -2506,7 +2793,6 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
return ERROR_FAIL;
/* First read has just triggered. Result is in s1. */
if (count == 1) {
uint64_t value;
if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK)
@ -3087,7 +3373,8 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address,
return ERROR_FAIL;
time_t start = time(NULL);
while (get_field(sbcs, DMI_SBCS_SBBUSY)) {
bool dmi_busy = dmi_busy_encountered;
while (get_field(sbcs, DMI_SBCS_SBBUSY) || dmi_busy) {
if (time(NULL) - start > riscv_command_timeout_sec) {
LOG_ERROR("Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
@ -3095,15 +3382,18 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address,
return ERROR_FAIL;
}
if (dmi_read(target, &sbcs, DMI_SBCS) != ERROR_OK)
if (dmi_op(target, &sbcs, &dmi_busy, DMI_OP_READ,
DMI_SBCS, 0, false, true) != ERROR_OK)
return ERROR_FAIL;
}
if (get_field(sbcs, DMI_SBCS_SBBUSYERROR) || dmi_busy_encountered) {
if (get_field(sbcs, DMI_SBCS_SBBUSYERROR)) {
/* We wrote while the target was busy. Slow down and try again. */
dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR);
info->bus_master_write_delay += info->bus_master_write_delay / 10 + 1;
}
if (get_field(sbcs, DMI_SBCS_SBBUSYERROR) || dmi_busy_encountered) {
next_address = sb_read_address(target);
if (next_address < address) {
/* This should never happen, probably buggy hardware. */
@ -3267,8 +3557,9 @@ static int write_memory_progbuf(struct target *target, target_addr_t address,
uint32_t abstractcs;
bool dmi_busy_encountered;
if (dmi_op(target, &abstractcs, &dmi_busy_encountered, DMI_OP_READ,
DMI_ABSTRACTCS, 0, false, true) != ERROR_OK)
result = dmi_op(target, &abstractcs, &dmi_busy_encountered,
DMI_OP_READ, DMI_ABSTRACTCS, 0, false, true);
if (result != ERROR_OK)
goto error;
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK)
@ -3354,7 +3645,6 @@ struct target_type riscv013_target = {
.poll = &riscv_openocd_poll,
.halt = &riscv_halt,
.resume = &riscv_resume,
.step = &riscv_openocd_step,
.assert_reset = assert_reset,
@ -3377,10 +3667,12 @@ static int riscv013_get_register(struct target *target,
int result = ERROR_OK;
if (rid == GDB_REGNO_PC) {
/* TODO: move this into riscv.c. */
result = register_read(target, value, GDB_REGNO_DPC);
LOG_DEBUG("[%d] read PC from DPC: 0x%" PRIx64, target->coreid, *value);
} else if (rid == GDB_REGNO_PRIV) {
uint64_t dcsr;
/* TODO: move this into riscv.c. */
result = register_read(target, &dcsr, GDB_REGNO_DCSR);
*value = get_field(dcsr, CSR_DCSR_PRV);
} else {
@ -3632,6 +3924,8 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target)
case CSR_DCSR_CAUSE_DEBUGINT:
case CSR_DCSR_CAUSE_HALT:
return RISCV_HALT_INTERRUPT;
case CSR_DCSR_CAUSE_GROUP:
return RISCV_HALT_GROUP;
}
LOG_ERROR("Unknown DCSR cause field: %x", (int)get_field(dcsr, CSR_DCSR_CAUSE));
@ -4072,9 +4366,9 @@ static int riscv013_on_step_or_resume(struct target *target, bool step)
if (result != ERROR_OK)
return result;
dcsr = set_field(dcsr, CSR_DCSR_STEP, step);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, 1);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, 1);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, 1);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, riscv_ebreakm);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, riscv_ebreaks);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, riscv_ebreaku);
return riscv_set_register(target, GDB_REGNO_DCSR, dcsr);
}
@ -4244,7 +4538,7 @@ int riscv013_test_compliance(struct target *target)
/* resumereq */
/* This bit is not actually readable according to the spec, so nothing to check.*/
COMPLIANCE_MUST_PASS(riscv_resume(target, true, 0, false, false));
COMPLIANCE_MUST_PASS(riscv_resume(target, true, 0, false, false, false));
/* Halt all harts again so the test can continue.*/
COMPLIANCE_MUST_PASS(riscv_halt(target));

View File

@ -252,6 +252,9 @@ int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC;
bool riscv_prefer_sba;
bool riscv_enable_virt2phys = true;
bool riscv_ebreakm = true;
bool riscv_ebreaks = true;
bool riscv_ebreaku = true;
bool riscv_enable_virtual;
@ -273,6 +276,8 @@ static enum {
} resume_order;
virt2phys_info_t sv32 = {
.name = "Sv32",
.va_bits = 32,
.level = 2,
.pte_shift = 2,
.vpn_shift = {12, 22},
@ -284,6 +289,8 @@ virt2phys_info_t sv32 = {
};
virt2phys_info_t sv39 = {
.name = "Sv39",
.va_bits = 39,
.level = 3,
.pte_shift = 3,
.vpn_shift = {12, 21, 30},
@ -295,6 +302,8 @@ virt2phys_info_t sv39 = {
};
virt2phys_info_t sv48 = {
.name = "Sv48",
.va_bits = 48,
.level = 4,
.pte_shift = 3,
.vpn_shift = {12, 21, 30, 39},
@ -1050,11 +1059,13 @@ int halt_prep(struct target *target)
if (!riscv_hart_enabled(target, i))
continue;
LOG_DEBUG("prep hart %d", i);
LOG_DEBUG("[%s] prep hart, debug_reason=%d", target_name(target),
target->debug_reason);
if (riscv_set_current_hartid(target, i) != ERROR_OK)
return ERROR_FAIL;
if (riscv_is_halted(target)) {
LOG_DEBUG("Hart %d is already halted.", i);
LOG_DEBUG("Hart %d is already halted (reason=%d).", i,
target->debug_reason);
} else {
if (r->halt_prep(target) != ERROR_OK)
return ERROR_FAIL;
@ -1296,7 +1307,7 @@ static int resume_finish(struct target *target)
* @par single_hart When true, only resume a single hart even if SMP is
* configured. This is used to run algorithms on just one hart.
*/
int riscv_resume_internal(
int riscv_resume(
struct target *target,
int current,
target_addr_t address,
@ -1344,10 +1355,10 @@ int riscv_resume_internal(
return result;
}
int riscv_resume(struct target *target, int current, target_addr_t address,
static int riscv_target_resume(struct target *target, int current, target_addr_t address,
int handle_breakpoints, int debug_execution)
{
return riscv_resume_internal(target, current, address, handle_breakpoints,
return riscv_resume(target, current, address, handle_breakpoints,
debug_execution, false);
}
@ -1364,17 +1375,42 @@ static int riscv_select_current_hart(struct target *target)
static int riscv_mmu(struct target *target, int *enabled)
{
if (!riscv_enable_virt2phys) {
*enabled = 0;
return ERROR_OK;
}
if (riscv_rtos_enabled(target))
riscv_set_current_hartid(target, target->rtos->current_thread - 1);
riscv_reg_t value;
int result = riscv_get_register(target, &value, GDB_REGNO_SATP);
if (result != ERROR_OK) {
LOG_DEBUG("Couldn't read SATP.");
return result;
/* Don't use MMU in explicit or effective M (machine) mode */
riscv_reg_t priv;
if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) {
LOG_ERROR("Failed to read priv register.");
return ERROR_FAIL;
}
if (get_field(value, RISCV_SATP_MODE(riscv_xlen(target))) == SATP_MODE_OFF) {
riscv_reg_t mstatus;
if (riscv_get_register(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) {
LOG_ERROR("Failed to read mstatus register.");
return ERROR_FAIL;
}
if ((get_field(mstatus, MSTATUS_MPRV) ? get_field(mstatus, MSTATUS_MPP) : priv) == PRV_M) {
LOG_DEBUG("SATP/MMU ignored in Machine mode (mstatus=0x%" PRIx64 ").", mstatus);
*enabled = 0;
return ERROR_OK;
}
riscv_reg_t satp;
if (riscv_get_register(target, &satp, GDB_REGNO_SATP) != ERROR_OK) {
LOG_DEBUG("Couldn't read SATP.");
/* If we can't read SATP, then there must not be an MMU. */
*enabled = 0;
return ERROR_OK;
}
if (get_field(satp, RISCV_SATP_MODE(riscv_xlen(target))) == SATP_MODE_OFF) {
LOG_DEBUG("MMU is disabled.");
*enabled = 0;
} else {
@ -1404,18 +1440,16 @@ static int riscv_address_translate(struct target *target,
if (result != ERROR_OK)
return result;
mode = get_field(satp_value, RISCV_SATP_MODE(riscv_xlen(target)));
unsigned xlen = riscv_xlen(target);
mode = get_field(satp_value, RISCV_SATP_MODE(xlen));
switch (mode) {
case SATP_MODE_SV32:
LOG_DEBUG("Translation mode: SV32");
info = &sv32;
break;
case SATP_MODE_SV39:
LOG_DEBUG("Translation mode: SV39");
info = &sv39;
break;
case SATP_MODE_SV48:
LOG_DEBUG("Translation mode: SV48");
info = &sv48;
break;
case SATP_MODE_OFF:
@ -1427,8 +1461,18 @@ static int riscv_address_translate(struct target *target,
" (satp: 0x%" PRIx64")", satp_value);
return ERROR_FAIL;
}
LOG_DEBUG("virtual=0x%" TARGET_PRIxADDR "; mode=%s", virtual, info->name);
ppn_value = get_field(satp_value, RISCV_SATP_PPN(riscv_xlen(target)));
/* verify bits xlen-1:va_bits-1 are all equal */
target_addr_t mask = ((target_addr_t) 1 << (xlen - (info->va_bits-1))) - 1;
target_addr_t masked_msbs = (virtual >> (info->va_bits-1)) & mask;
if (masked_msbs != 0 && masked_msbs != mask) {
LOG_ERROR("Virtual address 0x%" TARGET_PRIxADDR " is not sign-extended "
"for %s mode.", virtual, info->name);
return ERROR_FAIL;
}
ppn_value = get_field(satp_value, RISCV_SATP_PPN(xlen));
table_address = ppn_value << RISCV_PGSHIFT;
i = info->level - 1;
while (i >= 0) {
@ -1448,6 +1492,9 @@ static int riscv_address_translate(struct target *target,
else
pte = buf_get_u64(buffer, 0, 64);
LOG_DEBUG("i=%d; PTE @0x%" TARGET_PRIxADDR " = 0x%" PRIx64, i,
pte_address, pte);
if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W)))
return ERROR_FAIL;
@ -1466,26 +1513,25 @@ static int riscv_address_translate(struct target *target,
return ERROR_FAIL;
}
*physical = virtual;
/* Make sure to clear out the high bits that may be set. */
*physical = virtual & (((target_addr_t) 1 << info->va_bits) - 1);
while (i < info->level) {
ppn_value = pte >> info->pte_ppn_shift[i];
ppn_value &= info->pte_ppn_mask[i];
*physical &= ~(info->pa_ppn_mask[i] << info->pa_ppn_shift[i]);
*physical &= ~(((target_addr_t) info->pa_ppn_mask[i]) <<
info->pa_ppn_shift[i]);
*physical |= (ppn_value << info->pa_ppn_shift[i]);
i++;
}
LOG_DEBUG("Virtual address: 0x%" TARGET_PRIxADDR, virtual);
LOG_DEBUG("Physical address: 0x%" TARGET_PRIxADDR, *physical);
LOG_DEBUG("0x%" TARGET_PRIxADDR " -> 0x%" TARGET_PRIxADDR, virtual,
*physical);
return ERROR_OK;
}
static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical)
{
if (!riscv_enable_virt2phys)
return ERROR_FAIL;
int enabled;
if (riscv_mmu(target, &enabled) == ERROR_OK) {
if (!enabled)
@ -1693,7 +1739,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
/* Run algorithm */
LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point);
if (riscv_resume_internal(target, 0, entry_point, 0, 0, true) != ERROR_OK)
if (riscv_resume(target, 0, entry_point, 0, 0, true) != ERROR_OK)
return ERROR_FAIL;
int64_t start = timeval_ms();
@ -1896,9 +1942,9 @@ static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid)
return RPH_NO_CHANGE;
}
int set_debug_reason(struct target *target, int hartid)
int set_debug_reason(struct target *target, enum riscv_halt_reason halt_reason)
{
switch (riscv_halt_reason(target, hartid)) {
switch (halt_reason) {
case RISCV_HALT_BREAKPOINT:
target->debug_reason = DBG_REASON_BREAKPOINT;
break;
@ -1906,6 +1952,7 @@ int set_debug_reason(struct target *target, int hartid)
target->debug_reason = DBG_REASON_WATCHPOINT;
break;
case RISCV_HALT_INTERRUPT:
case RISCV_HALT_GROUP:
target->debug_reason = DBG_REASON_DBGRQ;
break;
case RISCV_HALT_SINGLESTEP:
@ -1917,6 +1964,7 @@ int set_debug_reason(struct target *target, int hartid)
case RISCV_HALT_ERROR:
return ERROR_FAIL;
}
LOG_DEBUG("[%s] debug_reason=%d", target_name(target), target->debug_reason);
return ERROR_OK;
}
@ -1947,7 +1995,8 @@ int riscv_openocd_poll(struct target *target)
LOG_DEBUG(" hart %d halted", halted_hart);
target->state = TARGET_HALTED;
if (set_debug_reason(target, halted_hart) != ERROR_OK)
enum riscv_halt_reason halt_reason = riscv_halt_reason(target, halted_hart);
if (set_debug_reason(target, halt_reason) != ERROR_OK)
return ERROR_FAIL;
target->rtos->current_threadid = halted_hart + 1;
@ -1963,45 +2012,75 @@ int riscv_openocd_poll(struct target *target)
riscv_halt(target);
} else if (target->smp) {
bool halt_discovered = false;
unsigned halts_discovered = 0;
unsigned total_targets = 0;
bool newly_halted[128] = {0};
unsigned should_remain_halted = 0;
unsigned should_resume = 0;
unsigned i = 0;
for (struct target_list *list = target->head; list != NULL;
list = list->next, i++) {
total_targets++;
struct target *t = list->target;
riscv_info_t *r = riscv_info(t);
assert(i < DIM(newly_halted));
enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid);
switch (out) {
case RPH_NO_CHANGE:
if (t->state == TARGET_HALTED)
should_remain_halted++;
break;
case RPH_DISCOVERED_RUNNING:
t->state = TARGET_RUNNING;
t->debug_reason = DBG_REASON_NOTHALTED;
break;
case RPH_DISCOVERED_HALTED:
halt_discovered = true;
halts_discovered++;
newly_halted[i] = true;
t->state = TARGET_HALTED;
if (set_debug_reason(t, r->current_hartid) != ERROR_OK)
enum riscv_halt_reason halt_reason =
riscv_halt_reason(t, r->current_hartid);
if (set_debug_reason(t, halt_reason) != ERROR_OK)
return ERROR_FAIL;
if (halt_reason == RISCV_HALT_BREAKPOINT) {
int retval;
switch (riscv_semihosting(t, &retval)) {
case SEMI_NONE:
case SEMI_WAITING:
/* This hart should remain halted. */
should_remain_halted++;
break;
case SEMI_HANDLED:
/* This hart should be resumed, along with any other
* harts that halted due to haltgroups. */
should_resume++;
break;
case SEMI_ERROR:
return retval;
}
} else if (halt_reason != RISCV_HALT_GROUP) {
should_remain_halted++;
}
break;
case RPH_ERROR:
return ERROR_FAIL;
}
}
if (halt_discovered) {
i = 0;
for (struct target_list *list = target->head; list != NULL;
list = list->next, i++) {
struct target *t = list->target;
if (newly_halted[i])
target_call_event_callbacks(t, TARGET_EVENT_HALTED);
LOG_DEBUG("should_remain_halted=%d, should_resume=%d",
should_remain_halted, should_resume);
if (should_remain_halted && should_resume) {
LOG_WARNING("%d harts should remain halted, and %d should resume.",
should_remain_halted, should_resume);
}
LOG_DEBUG("Halt other targets in this SMP group.");
if (should_remain_halted) {
LOG_DEBUG("halt all");
riscv_halt(target);
} else if (should_resume) {
LOG_DEBUG("resume all");
riscv_resume(target, true, 0, 0, 0, false);
}
return ERROR_OK;
@ -2016,18 +2095,30 @@ int riscv_openocd_poll(struct target *target)
halted_hart = riscv_current_hartid(target);
LOG_DEBUG(" hart %d halted", halted_hart);
if (set_debug_reason(target, halted_hart) != ERROR_OK)
enum riscv_halt_reason halt_reason = riscv_halt_reason(target, halted_hart);
if (set_debug_reason(target, halt_reason) != ERROR_OK)
return ERROR_FAIL;
target->state = TARGET_HALTED;
}
if (target->debug_reason == DBG_REASON_BREAKPOINT) {
int retval;
if (riscv_semihosting(target, &retval) != 0)
switch (riscv_semihosting(target, &retval)) {
case SEMI_NONE:
case SEMI_WAITING:
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
break;
case SEMI_HANDLED:
if (riscv_resume(target, true, 0, 0, 0, false) != ERROR_OK)
return ERROR_FAIL;
break;
case SEMI_ERROR:
return retval;
}
} else {
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}
return ERROR_OK;
}
@ -2459,6 +2550,36 @@ COMMAND_HANDLER(riscv_set_enable_virt2phys)
return ERROR_OK;
}
COMMAND_HANDLER(riscv_set_ebreakm)
{
if (CMD_ARGC != 1) {
LOG_ERROR("Command takes exactly 1 parameter");
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreakm);
return ERROR_OK;
}
COMMAND_HANDLER(riscv_set_ebreaks)
{
if (CMD_ARGC != 1) {
LOG_ERROR("Command takes exactly 1 parameter");
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaks);
return ERROR_OK;
}
COMMAND_HANDLER(riscv_set_ebreaku)
{
if (CMD_ARGC != 1) {
LOG_ERROR("Command takes exactly 1 parameter");
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaku);
return ERROR_OK;
}
static const struct command_registration riscv_exec_command_handlers[] = {
{
.name = "test_compliance",
@ -2487,7 +2608,7 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.mode = COMMAND_ANY,
.usage = "riscv set_prefer_sba on|off",
.help = "When on, prefer to use System Bus Access to access memory. "
"When off, prefer to use the Program Buffer to access memory."
"When off (default), prefer to use the Program Buffer to access memory."
},
{
.name = "set_enable_virtual",
@ -2496,7 +2617,7 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.usage = "riscv set_enable_virtual on|off",
.help = "When on, memory accesses are performed on physical or virtual "
"memory depending on the current system configuration. "
"When off, all memory accessses are performed on physical memory."
"When off (default), all memory accessses are performed on physical memory."
},
{
.name = "expose_csrs",
@ -2599,7 +2720,32 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.handler = riscv_set_enable_virt2phys,
.mode = COMMAND_ANY,
.usage = "riscv set_enable_virt2phys on|off",
.help = "Enable translation from virtual address to physical address."
.help = "When on (default), enable translation from virtual address to "
"physical address."
},
{
.name = "set_ebreakm",
.handler = riscv_set_ebreakm,
.mode = COMMAND_ANY,
.usage = "riscv set_ebreakm on|off",
.help = "Control dcsr.ebreakm. When off, M-mode ebreak instructions "
"don't trap to OpenOCD. Defaults to on."
},
{
.name = "set_ebreaks",
.handler = riscv_set_ebreaks,
.mode = COMMAND_ANY,
.usage = "riscv set_ebreaks on|off",
.help = "Control dcsr.ebreaks. When off, S-mode ebreak instructions "
"don't trap to OpenOCD. Defaults to on."
},
{
.name = "set_ebreaku",
.handler = riscv_set_ebreaku,
.mode = COMMAND_ANY,
.usage = "riscv set_ebreaku on|off",
.help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions "
"don't trap to OpenOCD. Defaults to on."
},
COMMAND_REGISTRATION_DONE
};
@ -2696,7 +2842,7 @@ struct target_type riscv_target = {
.poll = old_or_new_riscv_poll,
.halt = riscv_halt,
.resume = riscv_resume,
.resume = riscv_target_resume,
.step = old_or_new_riscv_step,
.assert_reset = riscv_assert_reset,
@ -2921,6 +3067,55 @@ bool riscv_has_register(struct target *target, int hartid, int regid)
return 1;
}
/**
* If write is true:
* return true iff we are guaranteed that the register will contain exactly
* the value we just wrote when it's read.
* If write is false:
* return true iff we are guaranteed that the register will read the same
* value in the future as the value we just read.
*/
static bool gdb_regno_cacheable(enum gdb_regno regno, bool write)
{
/* GPRs, FPRs, vector registers are just normal data stores. */
if (regno <= GDB_REGNO_XPR31 ||
(regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) ||
(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31))
return true;
/* Most CSRs won't change value on us, but we can't assume it about rbitrary
* CSRs. */
switch (regno) {
case GDB_REGNO_DPC:
return true;
case GDB_REGNO_VSTART:
case GDB_REGNO_VXSAT:
case GDB_REGNO_VXRM:
case GDB_REGNO_VLENB:
case GDB_REGNO_VL:
case GDB_REGNO_VTYPE:
case GDB_REGNO_MISA:
case GDB_REGNO_DCSR:
case GDB_REGNO_DSCRATCH:
case GDB_REGNO_MSTATUS:
case GDB_REGNO_MEPC:
case GDB_REGNO_MCAUSE:
case GDB_REGNO_SATP:
/*
* WARL registers might not contain the value we just wrote, but
* these ones won't spontaneously change their value either. *
*/
return !write;
case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */
case GDB_REGNO_TDATA1: /* Changes value when tselect is changed. */
case GDB_REGNO_TDATA2: /* Changse value when tselect is changed. */
default:
return false;
}
}
/**
* This function is called when the debug user wants to change the value of a
* register. The new value may be cached, and may not be written until the hart
@ -2942,7 +3137,17 @@ int riscv_set_register_on_hart(struct target *target, int hartid,
riscv_supports_extension(target, hartid, 'E'))
return ERROR_OK;
return r->set_register(target, hartid, regid, value);
struct reg *reg = &target->reg_cache->reg_list[regid];
buf_set_u64(reg->value, 0, reg->size, value);
int result = r->set_register(target, hartid, regid, value);
if (result == ERROR_OK)
reg->valid = gdb_regno_cacheable(regid, true);
else
reg->valid = false;
LOG_DEBUG("[%s]{%d} wrote 0x%" PRIx64 " to %s valid=%d",
target_name(target), hartid, value, reg->name, reg->valid);
return result;
}
int riscv_get_register(struct target *target, riscv_reg_t *value,
@ -2958,9 +3163,16 @@ int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value,
RISCV_INFO(r);
struct reg *reg = &target->reg_cache->reg_list[regid];
if (!reg->exist) {
LOG_DEBUG("[%s]{%d} %s does not exist.",
target_name(target), hartid, gdb_regno_name(regid));
return ERROR_FAIL;
}
if (reg && reg->valid && hartid == riscv_current_hartid(target)) {
*value = buf_get_u64(reg->value, 0, reg->size);
LOG_DEBUG("{%d} %s: %" PRIx64 " (cached)", hartid,
gdb_regno_name(regid), *value);
return ERROR_OK;
}
@ -2973,6 +3185,9 @@ int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value,
int result = r->get_register(target, value, hartid, regid);
if (result == ERROR_OK)
reg->valid = gdb_regno_cacheable(regid, false);
LOG_DEBUG("{%d} %s: %" PRIx64, hartid, gdb_regno_name(regid), *value);
return result;
}
@ -3223,6 +3438,74 @@ const char *gdb_regno_name(enum gdb_regno regno)
return "priv";
case GDB_REGNO_SATP:
return "satp";
case GDB_REGNO_VTYPE:
return "vtype";
case GDB_REGNO_VL:
return "vl";
case GDB_REGNO_V0:
return "v0";
case GDB_REGNO_V1:
return "v1";
case GDB_REGNO_V2:
return "v2";
case GDB_REGNO_V3:
return "v3";
case GDB_REGNO_V4:
return "v4";
case GDB_REGNO_V5:
return "v5";
case GDB_REGNO_V6:
return "v6";
case GDB_REGNO_V7:
return "v7";
case GDB_REGNO_V8:
return "v8";
case GDB_REGNO_V9:
return "v9";
case GDB_REGNO_V10:
return "v10";
case GDB_REGNO_V11:
return "v11";
case GDB_REGNO_V12:
return "v12";
case GDB_REGNO_V13:
return "v13";
case GDB_REGNO_V14:
return "v14";
case GDB_REGNO_V15:
return "v15";
case GDB_REGNO_V16:
return "v16";
case GDB_REGNO_V17:
return "v17";
case GDB_REGNO_V18:
return "v18";
case GDB_REGNO_V19:
return "v19";
case GDB_REGNO_V20:
return "v20";
case GDB_REGNO_V21:
return "v21";
case GDB_REGNO_V22:
return "v22";
case GDB_REGNO_V23:
return "v23";
case GDB_REGNO_V24:
return "v24";
case GDB_REGNO_V25:
return "v25";
case GDB_REGNO_V26:
return "v26";
case GDB_REGNO_V27:
return "v27";
case GDB_REGNO_V28:
return "v28";
case GDB_REGNO_V29:
return "v29";
case GDB_REGNO_V30:
return "v30";
case GDB_REGNO_V31:
return "v31";
default:
if (regno <= GDB_REGNO_XPR31)
sprintf(buf, "x%d", regno - GDB_REGNO_ZERO);
@ -3240,20 +3523,29 @@ static int register_get(struct reg *reg)
{
riscv_reg_info_t *reg_info = reg->arch_info;
struct target *target = reg_info->target;
RISCV_INFO(r);
if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
if (!r->get_register_buf) {
LOG_ERROR("Reading register %s not supported on this RISC-V target.",
gdb_regno_name(reg->number));
return ERROR_FAIL;
}
if (r->get_register_buf(target, reg->value, reg->number) != ERROR_OK)
return ERROR_FAIL;
} else {
uint64_t value;
int result = riscv_get_register(target, &value, reg->number);
if (result != ERROR_OK)
return result;
buf_set_u64(reg->value, 0, reg->size, value);
/* CSRs (and possibly other extension) registers may change value at any
* time. */
if (reg->number <= GDB_REGNO_XPR31 ||
(reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) ||
reg->number == GDB_REGNO_PC)
reg->valid = true;
LOG_DEBUG("[%d]{%d} read 0x%" PRIx64 " from %s (valid=%d)",
target->coreid, riscv_current_hartid(target), value, reg->name,
reg->valid);
}
reg->valid = gdb_regno_cacheable(reg->number, false);
char *str = buf_to_str(reg->value, reg->size, 16);
LOG_DEBUG("[%d]{%d} read 0x%s from %s (valid=%d)", target->coreid,
riscv_current_hartid(target), str, reg->name, reg->valid);
free(str);
return ERROR_OK;
}
@ -3261,22 +3553,31 @@ static int register_set(struct reg *reg, uint8_t *buf)
{
riscv_reg_info_t *reg_info = reg->arch_info;
struct target *target = reg_info->target;
RISCV_INFO(r);
char *str = buf_to_str(buf, reg->size, 16);
LOG_DEBUG("[%d]{%d} write 0x%s to %s (valid=%d)", target->coreid,
riscv_current_hartid(target), str, reg->name, reg->valid);
free(str);
memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8));
reg->valid = gdb_regno_cacheable(reg->number, true);
if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
if (!r->set_register_buf) {
LOG_ERROR("Writing register %s not supported on this RISC-V target.",
gdb_regno_name(reg->number));
return ERROR_FAIL;
}
if (r->set_register_buf(target, reg->number, reg->value) != ERROR_OK)
return ERROR_FAIL;
} else {
uint64_t value = buf_get_u64(buf, 0, reg->size);
if (riscv_set_register(target, reg->number, value) != ERROR_OK)
return ERROR_FAIL;
}
LOG_DEBUG("[%d]{%d} write 0x%" PRIx64 " to %s (valid=%d)",
target->coreid, riscv_current_hartid(target), value, reg->name,
reg->valid);
struct reg *r = &target->reg_cache->reg_list[reg->number];
/* CSRs (and possibly other extension) registers may change value at any
* time. */
if (reg->number <= GDB_REGNO_XPR31 ||
(reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) ||
reg->number == GDB_REGNO_PC)
r->valid = true;
memcpy(r->value, buf, (r->size + 7) / 8);
riscv_set_register(target, reg->number, value);
return ERROR_OK;
}
@ -3327,6 +3628,8 @@ int riscv_init_registers(struct target *target)
calloc(target->reg_cache->num_regs, max_reg_name_len);
char *reg_name = info->reg_names;
int hartid = riscv_current_hartid(target);
static struct reg_feature feature_cpu = {
.name = "org.gnu.gdb.riscv.cpu"
};
@ -3336,6 +3639,9 @@ int riscv_init_registers(struct target *target)
static struct reg_feature feature_csr = {
.name = "org.gnu.gdb.riscv.csr"
};
static struct reg_feature feature_vector = {
.name = "org.gnu.gdb.riscv.vector"
};
static struct reg_feature feature_virtual = {
.name = "org.gnu.gdb.riscv.virtual"
};
@ -3343,14 +3649,117 @@ int riscv_init_registers(struct target *target)
.name = "org.gnu.gdb.riscv.custom"
};
static struct reg_data_type type_ieee_single = {
.type = REG_TYPE_IEEE_SINGLE,
.id = "ieee_single"
/* These types are built into gdb. */
static struct reg_data_type type_ieee_single = { .type = REG_TYPE_IEEE_SINGLE, .id = "ieee_single" };
static struct reg_data_type type_ieee_double = { .type = REG_TYPE_IEEE_DOUBLE, .id = "ieee_double" };
static struct reg_data_type_union_field single_double_fields[] = {
{"float", &type_ieee_single, single_double_fields + 1},
{"double", &type_ieee_double, NULL},
};
static struct reg_data_type type_ieee_double = {
.type = REG_TYPE_IEEE_DOUBLE,
.id = "ieee_double"
static struct reg_data_type_union single_double_union = {
.fields = single_double_fields
};
static struct reg_data_type type_ieee_single_double = {
.type = REG_TYPE_ARCH_DEFINED,
.id = "FPU_FD",
.type_class = REG_TYPE_CLASS_UNION,
.reg_type_union = &single_double_union
};
static struct reg_data_type type_uint8 = { .type = REG_TYPE_UINT8, .id = "uint8" };
static struct reg_data_type type_uint16 = { .type = REG_TYPE_UINT16, .id = "uint16" };
static struct reg_data_type type_uint32 = { .type = REG_TYPE_UINT32, .id = "uint32" };
static struct reg_data_type type_uint64 = { .type = REG_TYPE_UINT64, .id = "uint64" };
static struct reg_data_type type_uint128 = { .type = REG_TYPE_UINT128, .id = "uint128" };
/* This is roughly the XML we want:
* <vector id="bytes" type="uint8" count="16"/>
* <vector id="shorts" type="uint16" count="8"/>
* <vector id="words" type="uint32" count="4"/>
* <vector id="longs" type="uint64" count="2"/>
* <vector id="quads" type="uint128" count="1"/>
* <union id="riscv_vector_type">
* <field name="b" type="bytes"/>
* <field name="s" type="shorts"/>
* <field name="w" type="words"/>
* <field name="l" type="longs"/>
* <field name="q" type="quads"/>
* </union>
*/
info->vector_uint8.type = &type_uint8;
info->vector_uint8.count = info->vlenb[hartid];
info->type_uint8_vector.type = REG_TYPE_ARCH_DEFINED;
info->type_uint8_vector.id = "bytes";
info->type_uint8_vector.type_class = REG_TYPE_CLASS_VECTOR;
info->type_uint8_vector.reg_type_vector = &info->vector_uint8;
info->vector_uint16.type = &type_uint16;
info->vector_uint16.count = info->vlenb[hartid] / 2;
info->type_uint16_vector.type = REG_TYPE_ARCH_DEFINED;
info->type_uint16_vector.id = "shorts";
info->type_uint16_vector.type_class = REG_TYPE_CLASS_VECTOR;
info->type_uint16_vector.reg_type_vector = &info->vector_uint16;
info->vector_uint32.type = &type_uint32;
info->vector_uint32.count = info->vlenb[hartid] / 4;
info->type_uint32_vector.type = REG_TYPE_ARCH_DEFINED;
info->type_uint32_vector.id = "words";
info->type_uint32_vector.type_class = REG_TYPE_CLASS_VECTOR;
info->type_uint32_vector.reg_type_vector = &info->vector_uint32;
info->vector_uint64.type = &type_uint64;
info->vector_uint64.count = info->vlenb[hartid] / 8;
info->type_uint64_vector.type = REG_TYPE_ARCH_DEFINED;
info->type_uint64_vector.id = "longs";
info->type_uint64_vector.type_class = REG_TYPE_CLASS_VECTOR;
info->type_uint64_vector.reg_type_vector = &info->vector_uint64;
info->vector_uint128.type = &type_uint128;
info->vector_uint128.count = info->vlenb[hartid] / 16;
info->type_uint128_vector.type = REG_TYPE_ARCH_DEFINED;
info->type_uint128_vector.id = "quads";
info->type_uint128_vector.type_class = REG_TYPE_CLASS_VECTOR;
info->type_uint128_vector.reg_type_vector = &info->vector_uint128;
info->vector_fields[0].name = "b";
info->vector_fields[0].type = &info->type_uint8_vector;
if (info->vlenb[hartid] >= 2) {
info->vector_fields[0].next = info->vector_fields + 1;
info->vector_fields[1].name = "s";
info->vector_fields[1].type = &info->type_uint16_vector;
} else {
info->vector_fields[0].next = NULL;
}
if (info->vlenb[hartid] >= 4) {
info->vector_fields[1].next = info->vector_fields + 2;
info->vector_fields[2].name = "w";
info->vector_fields[2].type = &info->type_uint32_vector;
} else {
info->vector_fields[1].next = NULL;
}
if (info->vlenb[hartid] >= 8) {
info->vector_fields[2].next = info->vector_fields + 3;
info->vector_fields[3].name = "l";
info->vector_fields[3].type = &info->type_uint64_vector;
} else {
info->vector_fields[2].next = NULL;
}
if (info->vlenb[hartid] >= 16) {
info->vector_fields[3].next = info->vector_fields + 4;
info->vector_fields[4].name = "q";
info->vector_fields[4].type = &info->type_uint128_vector;
} else {
info->vector_fields[3].next = NULL;
}
info->vector_fields[4].next = NULL;
info->vector_union.fields = info->vector_fields;
info->type_vector.type = REG_TYPE_ARCH_DEFINED;
info->type_vector.id = "riscv_vector";
info->type_vector.type_class = REG_TYPE_CLASS_UNION;
info->type_vector.reg_type_union = &info->vector_union;
struct csr_info csr_info[] = {
#define DECLARE_CSR(name, number) { number, #name },
#include "encoding.h"
@ -3366,8 +3775,6 @@ int riscv_init_registers(struct target *target)
riscv_reg_info_t *shared_reg_info = calloc(1, sizeof(riscv_reg_info_t));
shared_reg_info->target = target;
int hartid = riscv_current_hartid(target);
/* When gdb requests register N, gdb_get_register_packet() assumes that this
* is register at index N in reg_list. So if there are certain registers
* that don't exist, we need to leave holes in the list (or renumber, but
@ -3500,8 +3907,11 @@ int riscv_init_registers(struct target *target)
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
r->caller_save = true;
if (riscv_supports_extension(target, hartid, 'D')) {
r->reg_data_type = &type_ieee_double;
r->size = 64;
if (riscv_supports_extension(target, hartid, 'F'))
r->reg_data_type = &type_ieee_single_double;
else
r->reg_data_type = &type_ieee_double;
} else if (riscv_supports_extension(target, hartid, 'F')) {
r->reg_data_type = &type_ieee_single;
r->size = 32;
@ -3725,6 +4135,15 @@ int riscv_init_registers(struct target *target)
case CSR_MHPMCOUNTER31H:
r->exist = riscv_xlen(target) == 32;
break;
case CSR_VSTART:
case CSR_VXSAT:
case CSR_VXRM:
case CSR_VL:
case CSR_VTYPE:
case CSR_VLENB:
r->exist = riscv_supports_extension(target, hartid, 'V');
break;
}
if (!r->exist && expose_csr) {
@ -3743,6 +4162,15 @@ int riscv_init_registers(struct target *target)
r->feature = &feature_virtual;
r->size = 8;
} else if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) {
r->caller_save = false;
r->exist = riscv_supports_extension(target, hartid, 'V') && info->vlenb[hartid];
r->size = info->vlenb[hartid] * 8;
sprintf(reg_name, "v%d", number - GDB_REGNO_V0);
r->group = "vector";
r->feature = &feature_vector;
r->reg_data_type = &info->type_vector;
} else if (number >= GDB_REGNO_COUNT) {
/* Custom registers. */
assert(expose_custom);

View File

@ -7,6 +7,7 @@ struct riscv_program;
#include "opcodes.h"
#include "gdb_regs.h"
#include "jtag/jtag.h"
#include "target/register.h"
/* The register cache is statically allocated. */
#define RISCV_MAX_HARTS 1024
@ -39,6 +40,7 @@ enum riscv_halt_reason {
RISCV_HALT_SINGLESTEP,
RISCV_HALT_TRIGGER,
RISCV_HALT_UNKNOWN,
RISCV_HALT_GROUP,
RISCV_HALT_ERROR
};
@ -74,6 +76,8 @@ typedef struct {
/* It's possible that each core has a different supported ISA set. */
int xlen[RISCV_MAX_HARTS];
riscv_reg_t misa[RISCV_MAX_HARTS];
/* Cached value of vlenb. 0 if vlenb is not readable for some reason. */
unsigned vlenb[RISCV_MAX_HARTS];
/* The number of triggers per hart. */
unsigned trigger_count[RISCV_MAX_HARTS];
@ -110,6 +114,9 @@ typedef struct {
riscv_reg_t *value, int hid, int rid);
int (*set_register)(struct target *, int hartid, int regid,
uint64_t value);
int (*get_register_buf)(struct target *target, uint8_t *buf, int regno);
int (*set_register_buf)(struct target *target, int regno,
const uint8_t *buf);
int (*select_current_hart)(struct target *);
bool (*is_halted)(struct target *target);
/* Resume this target, as well as every other prepped target that can be
@ -148,6 +155,21 @@ typedef struct {
/* How many harts are attached to the DM that this target is attached to? */
int (*hart_count)(struct target *target);
unsigned (*data_bits)(struct target *target);
/* Storage for vector register types. */
struct reg_data_type_vector vector_uint8;
struct reg_data_type_vector vector_uint16;
struct reg_data_type_vector vector_uint32;
struct reg_data_type_vector vector_uint64;
struct reg_data_type_vector vector_uint128;
struct reg_data_type type_uint8_vector;
struct reg_data_type type_uint16_vector;
struct reg_data_type type_uint32_vector;
struct reg_data_type type_uint64_vector;
struct reg_data_type type_uint128_vector;
struct reg_data_type_union_field vector_fields[5];
struct reg_data_type_union vector_union;
struct reg_data_type type_vector;
} riscv_info_t;
typedef struct {
@ -156,7 +178,9 @@ typedef struct {
} riscv_bscan_tunneled_scan_context_t;
typedef struct {
const char *name;
int level;
unsigned va_bits;
unsigned pte_shift;
unsigned vpn_shift[PG_MAX_LEVEL];
unsigned vpn_mask[PG_MAX_LEVEL];
@ -175,6 +199,9 @@ extern int riscv_reset_timeout_sec;
extern bool riscv_prefer_sba;
extern bool riscv_enable_virtual;
extern bool riscv_ebreakm;
extern bool riscv_ebreaks;
extern bool riscv_ebreaku;
/* Everything needs the RISC-V specific info structure, so here's a nice macro
* that provides that. */
@ -212,7 +239,8 @@ int riscv_resume(
int current,
target_addr_t address,
int handle_breakpoints,
int debug_execution
int debug_execution,
bool single_hart
);
int riscv_openocd_step(
@ -262,12 +290,14 @@ int riscv_count_harts(struct target *target);
/* Returns TRUE if the target has the given register on the given hart. */
bool riscv_has_register(struct target *target, int hartid, int regid);
/* Returns the value of the given register on the given hart. 32-bit registers
* are zero extended to 64 bits. */
/** Set register, updating the cache. */
int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v);
/** Set register, updating the cache. */
int riscv_set_register_on_hart(struct target *target, int hid, enum gdb_regno rid, uint64_t v);
/** Get register, from the cache if it's in there. */
int riscv_get_register(struct target *target, riscv_reg_t *value,
enum gdb_regno r);
/** Get register, from the cache if it's in there. */
int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value,
int hartid, enum gdb_regno regid);
@ -308,7 +338,13 @@ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_wp_addre
int riscv_init_registers(struct target *target);
void riscv_semihosting_init(struct target *target);
int riscv_semihosting(struct target *target, int *retval);
typedef enum {
SEMI_NONE, /* Not halted for a semihosting call. */
SEMI_HANDLED, /* Call handled, and target was resumed. */
SEMI_WAITING, /* Call handled, target is halted waiting until we can resume. */
SEMI_ERROR /* Something went wrong. */
} semihosting_result_t;
semihosting_result_t riscv_semihosting(struct target *target, int *retval);
void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field,
riscv_bscan_tunneled_scan_context_t *ctxt);

View File

@ -60,35 +60,35 @@ void riscv_semihosting_init(struct target *target)
/**
* Check for and process a semihosting request using the ARM protocol). This
* is meant to be called when the target is stopped due to a debug mode entry.
* If the value 0 is returned then there was nothing to process. A non-zero
* return value signifies that a request was processed and the target resumed,
* or an error was encountered, in which case the caller must return
* immediately.
*
* @param target Pointer to the target to process.
* @param retval Pointer to a location where the return code will be stored
* @return non-zero value if a request was processed or an error encountered
*/
int riscv_semihosting(struct target *target, int *retval)
semihosting_result_t riscv_semihosting(struct target *target, int *retval)
{
struct semihosting *semihosting = target->semihosting;
if (!semihosting)
return 0;
if (!semihosting) {
LOG_DEBUG(" -> NONE (!semihosting)");
return SEMI_NONE;
}
if (!semihosting->is_active)
return 0;
if (!semihosting->is_active) {
LOG_DEBUG(" -> NONE (!semihosting->is_active)");
return SEMI_NONE;
}
riscv_reg_t dpc;
int result = riscv_get_register(target, &dpc, GDB_REGNO_DPC);
riscv_reg_t pc;
int result = riscv_get_register(target, &pc, GDB_REGNO_PC);
if (result != ERROR_OK)
return 0;
return SEMI_ERROR;
uint8_t tmp[12];
/* Read the current instruction, including the bracketing */
*retval = target_read_memory(target, dpc - 4, 2, 6, tmp);
*retval = target_read_memory(target, pc - 4, 2, 6, tmp);
if (*retval != ERROR_OK)
return 0;
return SEMI_ERROR;
/*
* The instructions that trigger a semihosting call,
@ -101,12 +101,12 @@ int riscv_semihosting(struct target *target, int *retval)
uint32_t pre = target_buffer_get_u32(target, tmp);
uint32_t ebreak = target_buffer_get_u32(target, tmp + 4);
uint32_t post = target_buffer_get_u32(target, tmp + 8);
LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, dpc);
LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, pc);
if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) {
/* Not the magic sequence defining semihosting. */
return 0;
LOG_DEBUG(" -> NONE (no magic)");
return SEMI_NONE;
}
/*
@ -114,18 +114,21 @@ int riscv_semihosting(struct target *target, int *retval)
* operation to complete.
*/
if (!semihosting->hit_fileio) {
/* RISC-V uses A0 and A1 to pass function arguments */
riscv_reg_t r0;
riscv_reg_t r1;
result = riscv_get_register(target, &r0, GDB_REGNO_A0);
if (result != ERROR_OK)
return 0;
if (result != ERROR_OK) {
LOG_DEBUG(" -> ERROR (couldn't read a0)");
return SEMI_ERROR;
}
result = riscv_get_register(target, &r1, GDB_REGNO_A1);
if (result != ERROR_OK)
return 0;
if (result != ERROR_OK) {
LOG_DEBUG(" -> ERROR (couldn't read a1)");
return SEMI_ERROR;
}
semihosting->op = r0;
semihosting->param = r1;
@ -136,11 +139,12 @@ int riscv_semihosting(struct target *target, int *retval)
*retval = semihosting_common(target);
if (*retval != ERROR_OK) {
LOG_ERROR("Failed semihosting operation");
return 0;
return SEMI_ERROR;
}
} else {
/* Unknown operation number, not a semihosting call. */
return 0;
LOG_DEBUG(" -> NONE (unknown operation number)");
return SEMI_NONE;
}
}
@ -150,16 +154,16 @@ int riscv_semihosting(struct target *target, int *retval)
*/
if (semihosting->is_resumable && !semihosting->hit_fileio) {
/* Resume right after the EBREAK 4 bytes instruction. */
*retval = target_resume(target, 0, dpc+4, 0, 0);
if (*retval != ERROR_OK) {
LOG_ERROR("Failed to resume target");
return 0;
*retval = riscv_set_register(target, GDB_REGNO_PC, pc + 4);
if (*retval != ERROR_OK)
return SEMI_ERROR;
LOG_DEBUG(" -> HANDLED");
return SEMI_HANDLED;
}
return 1;
}
return 0;
LOG_DEBUG(" -> WAITING");
return SEMI_WAITING;
}
/* -------------------------------------------------------------------------
@ -171,7 +175,7 @@ int riscv_semihosting(struct target *target, int *retval)
*/
static int riscv_semihosting_setup(struct target *target, int enable)
{
LOG_DEBUG("enable=%d", enable);
LOG_DEBUG("[%s] enable=%d", target_name(target), enable);
struct semihosting *semihosting = target->semihosting;
if (semihosting)

View File

@ -41,7 +41,9 @@
#include "config.h"
#endif
#include <sys/time.h>
#include <helper/time_support.h>
#include <helper/fileio.h>
#include <jtag/jtag.h>
#include <flash/nor/core.h>
@ -74,6 +76,7 @@ static int target_gdb_fileio_end_default(struct target *target, int retcode,
int fileio_errno, bool ctrl_c);
static int target_profiling_default(struct target *target, uint32_t *samples,
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds);
static int halt_mcu(struct target *target);
/* targets */
extern struct target_type arm7tdmi_target;
@ -2853,6 +2856,12 @@ COMMAND_HANDLER(handle_reg_command)
target = get_current_target(CMD_CTX);
if (target->state != TARGET_HALTED) {
LOG_INFO("Please halt the target first");
retval = !ERROR_OK;
return retval;
}
/* list all available registers for the current target */
if (CMD_ARGC == 0) {
struct reg_cache *cache = target->reg_cache;
@ -3127,6 +3136,10 @@ COMMAND_HANDLER(handle_resume_command)
struct target *target = get_current_target(CMD_CTX);
if (target->state != TARGET_HALTED) {
halt_mcu(target);
}
/* with no CMD_ARGV, resume from current pc, addr = 0,
* with one arguments, addr = CMD_ARGV[0],
* handle breakpoints, not debugging */
@ -4206,7 +4219,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
long l;
uint32_t width;
int len;
uint32_t addr;
target_addr_t addr;
uint32_t count;
uint32_t v;
const char *varname;
@ -4233,8 +4246,9 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
if (e != JIM_OK)
return e;
e = Jim_GetLong(interp, argv[2], &l);
addr = l;
jim_wide w;
e = Jim_GetWide(interp, argv[2], &w);
addr = w;
if (e != JIM_OK)
return e;
e = Jim_GetLong(interp, argv[3], &l);
@ -4288,7 +4302,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
} else {
char buf[100];
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
sprintf(buf, "mem2array address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads",
sprintf(buf, "mem2array address: " TARGET_ADDR_FMT " is not aligned for %" PRId32 " byte reads",
addr,
width);
Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL);
@ -4320,7 +4334,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
retval = target_read_memory(target, addr, width, count, buffer);
if (retval != ERROR_OK) {
/* BOO !*/
LOG_ERROR("mem2array: Read @ 0x%08" PRIx32 ", w=%" PRId32 ", cnt=%" PRId32 ", failed",
LOG_ERROR("mem2array: Read @ " TARGET_ADDR_FMT ", w=%" PRId32 ", cnt=%" PRId32 ", failed",
addr,
width,
count);
@ -6180,6 +6194,385 @@ nextw:
return retval;
}
COMMAND_HANDLER(handle_load_bin_command)
{
struct image image;
target_addr_t addr;
int retval;
int i;
uint8_t *write_buffer = NULL;
uint8_t *read_buffer = NULL;
size_t buf_cnt;
uint32_t image_size;
if (CMD_ARGC != 3)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr);
unsigned verify = 1;
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], verify);
image.base_address = addr;
image.base_address_set = 1;
image.start_address_set = 0;
if (image_open(&image, CMD_ARGV[0], "bin") != ERROR_OK)
return ERROR_FAIL;
retval = ERROR_OK;
image_size = 0;
struct target *target = get_current_target(CMD_CTX);
struct duration bench;
duration_start(&bench);
for (i = 0; i < image.num_sections; i++) {
write_buffer = malloc(image.sections[i].size);
if (write_buffer == NULL) {
command_print(CMD,
"error allocating write buffer for section (%d bytes)",
(int)(image.sections[i].size));
retval = ERROR_FAIL;
break;
}
if (verify) {
read_buffer = malloc(image.sections[i].size);
if (read_buffer == NULL) {
command_print(CMD,
"error allocating read buffer for section (%d bytes)",
(int)(image.sections[i].size));
retval = ERROR_FAIL;
free(write_buffer);
break;
}
}
retval = image_read_section(&image, i, 0x0, image.sections[i].size, write_buffer, &buf_cnt);
if (retval != ERROR_OK) {
free(write_buffer);
break;
}
retval = target_write_buffer(target, image.sections[i].base_address, buf_cnt, write_buffer);
if (retval != ERROR_OK) {
free(write_buffer);
break;
}
if (verify) {
retval = target_read_buffer(target, image.sections[i].base_address, buf_cnt, read_buffer);
if (retval != ERROR_OK) {
free(write_buffer);
if (read_buffer != NULL)
free(read_buffer);
break;
}
size_t k;
for (k = 0; k < buf_cnt; k++) {
if (write_buffer[k] != read_buffer[k]) {
command_print(CMD, "write failed at address " TARGET_ADDR_FMT "",
image.sections[i].base_address);
free(write_buffer);
if (read_buffer != NULL)
free(read_buffer);
retval = ERROR_FAIL;
goto end;
}
}
}
image_size += buf_cnt;
command_print(CMD, "%u bytes written at address " TARGET_ADDR_FMT "",
(unsigned int)buf_cnt,
image.sections[i].base_address);
free(write_buffer);
if (verify && (read_buffer != NULL))
free(read_buffer);
}
if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
command_print(CMD, "downloaded %" PRIu32 " bytes "
"in %fs (%0.3f KiB/s)", image_size,
duration_elapsed(&bench), duration_kbps(&bench, image_size));
}
end:
image_close(&image);
return retval;
}
// 烧写数据地址4K + 1K + 256
#define DATA_ADDR (0x20001500)
// 烧写数据长度
#define DATA_LEN (0x20001400)
// 烧写(擦除)地址
#define PROGRAM_ADDR (0x20001404)
// 擦除标志
// 0: 不擦除1擦除
#define ERASE_FLAG (0x20001408)
// 烧写状态标志
// bit0为烧写结束标志0未烧写完成1烧写完成。
// bit1为烧写结果标志0烧写失败1烧写成功
#define RESULT_FLAG (0x2000140C)
// loader地址
#define LOADER_ADDR (0x20000000)
// 每次烧写最大长度
#define EACH_BURN_LEN (256)
// 扇区大小
#define FLASH_SECTOR_SIZE (4096)
static int program_result(struct target *target)
{
int retval;
int data;
int timeout = 0;
wait:
usleep(200000);
// 读烧写结束标记
retval = target_read_buffer(target, RESULT_FLAG, 4, (uint8_t *)(&data));
if (retval != ERROR_OK) {
goto end;
}
// 烧写结束
if (data & 0x1) {
// 烧写失败
if (!(data & 0x2)) {
retval = !ERROR_OK;
// 烧写成功
} else {
retval = ERROR_OK;
}
// 还没烧写结束
} else {
timeout++;
if (timeout >= 20) {
retval = !ERROR_OK;
goto end;
}
goto wait;
}
end:
return retval;
}
static int halt_mcu(struct target *target)
{
int retval;
target->verbose_halt_msg = true;
// halt住MCU
retval = target_halt(target);
if (retval != ERROR_OK) {
return retval;
}
// 等待halt成功
retval = target_wait_state(target, TARGET_HALTED, DEFAULT_HALT_TIMEOUT);
if (retval != ERROR_OK) {
return retval;
}
return retval;
}
COMMAND_HANDLER(handle_tinyriscv_program_command)
{
struct fileio *file;
target_addr_t addr;
int retval;
size_t i;
uint8_t *data_buffer;
size_t count;
size_t file_size;
size_t num;
int data;
struct target *target;
static const uint8_t tinyriscv_flash_write_code[] = {
#include "../../contrib/loaders/flash/tinyriscv/tinyriscv.inc"
};
target = get_current_target(CMD_CTX);
// 参数检查
if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;
// 烧写地址
COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr);
struct duration bench;
duration_start(&bench);
// halt住MCU
retval = halt_mcu(target);
if (retval != ERROR_OK) {
goto end2;
}
LOG_INFO("flash loader downloading...");
// 先下载loader到内存
retval = target_write_buffer(target, LOADER_ADDR, sizeof(tinyriscv_flash_write_code),
tinyriscv_flash_write_code);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to download flash loader into ram");
goto end2;
}
// 打开要烧写的文件
if (fileio_open(&file, CMD_ARGV[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) {
LOG_ERROR("fail to open %s", CMD_ARGV[0]);
retval = ERROR_FAIL;
goto end2;
}
// 文件大小
fileio_size(file, &file_size);
//LOG_INFO("bin file size: %d(bytes)", (int)(file_size));
LOG_INFO("erasing...");
// 要擦除多少个扇区
num = (file_size / FLASH_SECTOR_SIZE) + 1;
for (i = 0; i < num; i++) {
data = 0x1;
// 擦除标记
retval = target_write_buffer(target, ERASE_FLAG, 4, (uint8_t *)(&data));
if (retval != ERROR_OK) {
LOG_ERROR("write erase_flag failed!!!");
goto end1;
}
data = addr + (i * FLASH_SECTOR_SIZE);
LOG_INFO("erase addr: 0x%x", data);
// 擦除地址
retval = target_write_buffer(target, PROGRAM_ADDR, 4, (uint8_t *)(&data));
if (retval != ERROR_OK) {
LOG_ERROR("write erase_addr failed!!!");
goto end1;
}
// halt住MCU
retval = halt_mcu(target);
if (retval != ERROR_OK) {
goto end1;
}
// 开始烧写
retval = target_resume(target, 0, LOADER_ADDR, 1, 0);
if (retval != ERROR_OK) {
LOG_ERROR("resume failed!!!");
goto end1;
}
// 获取烧写结果
retval = program_result(target);
if (retval != ERROR_OK) {
LOG_ERROR("erase failed!!!");
goto end1;
}
}
// 清擦除标志
data = 0;
retval = target_write_buffer(target, ERASE_FLAG, 4, (uint8_t *)(&data));
if (retval != ERROR_OK) {
goto end1;
}
// 分配内存
data_buffer = malloc(EACH_BURN_LEN);
if (data_buffer == NULL) {
LOG_ERROR("error allocating data buffer (%d bytes)",
EACH_BURN_LEN);
retval = ERROR_FAIL;
goto end1;
}
retval = ERROR_OK;
LOG_INFO("programming...");
num = file_size;
while (num > 0) {
fileio_read(file, EACH_BURN_LEN, data_buffer, &count);
if (count > 0) {
// 下载数据
retval = target_write_buffer(target, DATA_ADDR, count, data_buffer);
if (retval != ERROR_OK) {
LOG_ERROR("write data failed!!!");
break;
}
data = addr;
LOG_INFO("program addr: 0x%x", data);
// 烧写地址
retval = target_write_buffer(target, PROGRAM_ADDR, 4, (uint8_t *)(&data));
if (retval != ERROR_OK) {
LOG_ERROR("write program addr failed!!!");
break;
}
data = count;
// 烧写长度
retval = target_write_buffer(target, DATA_LEN, 4, (uint8_t *)(&data));
if (retval != ERROR_OK) {
LOG_ERROR("write data len failed!!!");
break;
}
// halt住MCU
retval = halt_mcu(target);
if (retval != ERROR_OK) {
goto end1;
}
// 开始烧写
retval = target_resume(target, 0, LOADER_ADDR, 1, 0);
if (retval != ERROR_OK) {
LOG_ERROR("resume failed!!!");
break;
}
// 获取烧写结果
retval = program_result(target);
if (retval != ERROR_OK) {
LOG_ERROR("program failed!!!");
break;
}
addr += count;
}
num -= count;
}
if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
LOG_INFO("program %" PRIu32 " bytes "
"in %fs (%0.3f KiB/s)", (uint32_t)(file_size),
duration_elapsed(&bench), duration_kbps(&bench, file_size));
}
free(data_buffer);
end1:
fileio_close(file);
end2:
if (retval == ERROR_OK) {
LOG_INFO("End, program succ");
} else {
LOG_ERROR("End, program failed!!!");
}
return retval;
}
static const struct command_registration target_exec_command_handlers[] = {
{
.name = "fast_load_image",
@ -6426,6 +6819,20 @@ static const struct command_registration target_exec_command_handlers[] = {
.help = "Test the target's memory access functions",
.usage = "size",
},
{
.name = "load_bin",
.handler = handle_load_bin_command,
.mode = COMMAND_EXEC,
.help = "Download bin file into memory and verify it",
.usage = "filename address verify",
},
{
.name = "tinyriscv_program",
.handler = handle_tinyriscv_program_command,
.mode = COMMAND_EXEC,
.help = "Program file into external flash",
.usage = "filename address",
},
COMMAND_REGISTRATION_DONE
};

View File

@ -0,0 +1,24 @@
adapter_khz 4000
interface jlink
transport select jtag
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000913
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME
$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 0x4000 -work-area-backup 0
riscv set_enable_virt2phys off
riscv set_enable_virtual off
flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME.0
init
jlink jtag 3
halt
flash protect 0 1 last off
echo "Ready for Remote Connections"