Compare commits
40 Commits
Author | SHA1 | Date |
---|---|---|
liangkangnan | 0463f8d773 | |
liangkangnan | 916fcb01cb | |
liangkangnan | 9bbbaf9bad | |
liangkangnan | e5a97681ea | |
liangkangnan | 76b7bb357b | |
liangkangnan | 26b7b3c917 | |
liangkangnan | 66f480322a | |
liangkangnan | e2b555e287 | |
liangkangnan | a610f377c9 | |
liangkangnan | 65ff1f1dd2 | |
Blue Liang | c94bf74155 | |
Blue Liang | 3cc6fe00af | |
liangkangnan | eefff456ca | |
Tim Newsome | 97fb3f4bd4 | |
Tommy Murphy | 95a8cd9b5d | |
Tim Newsome | 4f9e2d7171 | |
Tim Newsome | 1524487a13 | |
Alistair Francis | 62af8d3c10 | |
Tim Newsome | fcdb5d64ec | |
Tim Newsome | 0c3e50a06a | |
Tim Newsome | 55dd7e83ca | |
Tim Newsome | e6e281197f | |
Tim Newsome | 2e9aad8914 | |
Tim Newsome | 464407cfd2 | |
Tim Newsome | cbb15587dc | |
Tim Newsome | 3967f48843 | |
Tim Newsome | 60eccb2967 | |
Tim Newsome | 5b2426a4b2 | |
Jonathan Tinkham | 548790fefc | |
Tim Newsome | f6f30fb148 | |
Tim Newsome | 54e5d2533c | |
Tim Newsome | 1ae21b3874 | |
Tim Newsome | 1449af5bdb | |
Tim Newsome | 95462a8a35 | |
Tim Newsome | 7cb8843794 | |
Tim Newsome | 2f456abd55 | |
Tim Newsome | 69e6891434 | |
Jan Matyas | fcea4f79ba | |
Tim Newsome | 8b8db033ee | |
Hsiangkai | 2c3f099b73 |
|
@ -99,3 +99,5 @@ TAGS
|
||||||
|
|
||||||
# ctags tag files
|
# ctags tag files
|
||||||
tags
|
tags
|
||||||
|
|
||||||
|
release/
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[submodule "jimtcl"]
|
[submodule "jimtcl"]
|
||||||
path = jimtcl
|
path = jimtcl
|
||||||
url = https://github.com/msteveb/jimtcl
|
url = https://gitee.com/liangkangnan/jimtcl
|
||||||
|
|
2
README
2
README
|
@ -118,7 +118,7 @@ Debug targets
|
||||||
|
|
||||||
ARM11, ARM7, ARM9, AVR32, Cortex-A, Cortex-R, Cortex-M, LS102x-SAP,
|
ARM11, ARM7, ARM9, AVR32, Cortex-A, Cortex-R, Cortex-M, LS102x-SAP,
|
||||||
Feroceon/Dragonite, DSP563xx, DSP5680xx, EnSilica eSi-RISC, FA526, MIPS
|
Feroceon/Dragonite, DSP563xx, DSP5680xx, EnSilica eSi-RISC, FA526, MIPS
|
||||||
EJTAG, NDS32, XScale, Intel Quark.
|
EJTAG, NDS32, RISC-V, XScale, Intel Quark.
|
||||||
|
|
||||||
Flash drivers
|
Flash drivers
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -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可执行文件。
|
|
@ -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}=="1016", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
||||||
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", 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}=="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
|
# Raisonance RLink
|
||||||
ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
||||||
|
|
|
@ -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,
|
|
@ -9468,20 +9468,20 @@ This is used to access 64-bit floating point registers on 32-bit targets.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn Command {riscv set_prefer_sba} on|off
|
@deffn Command {riscv set_prefer_sba} on|off
|
||||||
When on, prefer to use System Bus Access to access memory. When off, prefer to
|
When on, prefer to use System Bus Access to access memory. When off (default),
|
||||||
use the Program Buffer to access memory.
|
prefer to use the Program Buffer to access memory.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn Command {riscv set_enable_virtual} on|off
|
@deffn Command {riscv set_enable_virtual} on|off
|
||||||
When on, memory accesses are performed on physical or virtual memory depending
|
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.
|
on physical memory.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn Command {riscv set_enable_virt2phys} on|off
|
@deffn Command {riscv set_enable_virt2phys} on|off
|
||||||
When on, memory accesses are performed on physical or virtual memory depending
|
When on (default), memory accesses are performed on physical or virtual memory
|
||||||
on the current satp configuration. When off, all memory accessses are performed
|
depending on the current satp configuration. When off, all memory accessses are
|
||||||
on physical memory.
|
performed on physical memory.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn Command {riscv resume_order} normal|reversed
|
@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.
|
the DM transport TAP's instruction register to enable. Supply a value of 0 to disable.
|
||||||
@end deffn
|
@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
|
@subsection RISC-V Authentication Commands
|
||||||
|
|
||||||
The following commands can be used to authenticate to a RISC-V system. Eg. a
|
The following commands can be used to authenticate to a RISC-V system. Eg. a
|
||||||
|
|
|
@ -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}
|
|
@ -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
|
|
@ -136,7 +136,8 @@ struct fespi_target {
|
||||||
/* TODO !!! What is the right naming convention here? */
|
/* TODO !!! What is the right naming convention here? */
|
||||||
static const struct fespi_target target_devices[] = {
|
static const struct fespi_target target_devices[] = {
|
||||||
/* name, tap_idcode, ctrl_base */
|
/* 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 }
|
{ 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 target *target = bank->target;
|
||||||
struct fespi_flash_bank *fespi_info = bank->driver_priv;
|
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 sector;
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
|
@ -547,21 +548,22 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
algorithm_wa->address, retval);
|
algorithm_wa->address, retval);
|
||||||
target_free_working_area(target, algorithm_wa);
|
target_free_working_area(target, algorithm_wa);
|
||||||
algorithm_wa = NULL;
|
algorithm_wa = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
data_wa_size = MIN(target->working_area_size - algorithm_wa->size, count);
|
} else {
|
||||||
while (1) {
|
data_wa_size = MIN(target->working_area_size - algorithm_wa->size, count);
|
||||||
if (data_wa_size < 128) {
|
while (1) {
|
||||||
LOG_WARNING("Couldn't allocate data working area.");
|
if (data_wa_size < 128) {
|
||||||
target_free_working_area(target, algorithm_wa);
|
LOG_WARNING("Couldn't allocate data working area.");
|
||||||
algorithm_wa = NULL;
|
target_free_working_area(target, algorithm_wa);
|
||||||
}
|
algorithm_wa = NULL;
|
||||||
if (target_alloc_working_area_try(target, data_wa_size, &data_wa) ==
|
}
|
||||||
ERROR_OK) {
|
if (target_alloc_working_area_try(target, data_wa_size, &data_wa) ==
|
||||||
break;
|
ERROR_OK) {
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
data_wa_size = data_wa_size * 3 / 4;
|
data_wa_size = data_wa_size * 3 / 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_WARNING("Couldn't allocate %zd-byte working area.", bin_size);
|
LOG_WARNING("Couldn't allocate %zd-byte working area.", bin_size);
|
||||||
|
@ -620,7 +622,6 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
page_offset = 0;
|
|
||||||
buffer += cur_count;
|
buffer += cur_count;
|
||||||
offset += cur_count;
|
offset += cur_count;
|
||||||
count -= 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)
|
if (retval != ERROR_OK)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
page_offset = offset % page_size;
|
uint32_t page_offset = offset % page_size;
|
||||||
/* central part, aligned words */
|
/* central part, aligned words */
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
/* clip block at page boundary */
|
/* clip block at page boundary */
|
||||||
|
|
|
@ -1309,7 +1309,7 @@
|
||||||
[10][0x34 - 1] = "Xiamen Kingblaze Technology Co Ltd",
|
[10][0x34 - 1] = "Xiamen Kingblaze Technology Co Ltd",
|
||||||
[10][0x35 - 1] = "Shenzhen Lomica Technology Co Ltd",
|
[10][0x35 - 1] = "Shenzhen Lomica Technology Co Ltd",
|
||||||
[10][0x36 - 1] = "Nuclei System 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][0x38 - 1] = "Shenzhen Ingacom Semiconductor Ltd",
|
||||||
[10][0x39 - 1] = "Zotac Technology Ltd",
|
[10][0x39 - 1] = "Zotac Technology Ltd",
|
||||||
[10][0x3a - 1] = "Foxline",
|
[10][0x3a - 1] = "Foxline",
|
||||||
|
|
|
@ -151,6 +151,7 @@ extern int debug_level;
|
||||||
#define ERROR_WAIT (-5)
|
#define ERROR_WAIT (-5)
|
||||||
/* ERROR_TIMEOUT is already taken by winerror.h. */
|
/* ERROR_TIMEOUT is already taken by winerror.h. */
|
||||||
#define ERROR_TIMEOUT_REACHED (-6)
|
#define ERROR_TIMEOUT_REACHED (-6)
|
||||||
|
#define ERROR_NOT_IMPLEMENTED (-7)
|
||||||
|
|
||||||
|
|
||||||
#endif /* OPENOCD_HELPER_LOG_H */
|
#endif /* OPENOCD_HELPER_LOG_H */
|
||||||
|
|
|
@ -34,9 +34,12 @@
|
||||||
#if IS_DARWIN
|
#if IS_DARWIN
|
||||||
#include <libproc.h>
|
#include <libproc.h>
|
||||||
#endif
|
#endif
|
||||||
|
/* sys/sysctl.h is deprecated on Linux from glibc 2.30 */
|
||||||
|
#ifndef __linux__
|
||||||
#ifdef HAVE_SYS_SYSCTL_H
|
#ifdef HAVE_SYS_SYSCTL_H
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
#if IS_WIN32 && !IS_CYGWIN
|
#if IS_WIN32 && !IS_CYGWIN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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}=="1016", MODE="664", GROUP="plugdev"
|
||||||
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1017", 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}=="1018", MODE="664", GROUP="plugdev"
|
||||||
|
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1051", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
LABEL="libjaylink_end_rules"
|
LABEL="libjaylink_end_rules"
|
||||||
|
|
|
@ -59,7 +59,9 @@ static const uint16_t pids[][2] = {
|
||||||
{0x1015, 0},
|
{0x1015, 0},
|
||||||
{0x1016, 0},
|
{0x1016, 0},
|
||||||
{0x1017, 0},
|
{0x1017, 0},
|
||||||
{0x1018, 0}
|
{0x1018, 0},
|
||||||
|
{0x1051, 0},
|
||||||
|
{0x1061, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Maximum length of the USB string descriptor for the serial number. */
|
/** Maximum length of the USB string descriptor for the serial number. */
|
||||||
|
|
|
@ -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);
|
static int hwthread_smp_init(struct target *target);
|
||||||
int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
|
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);
|
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)
|
#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,
|
.get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup,
|
||||||
.smp_init = hwthread_smp_init,
|
.smp_init = hwthread_smp_init,
|
||||||
.set_reg = hwthread_set_reg,
|
.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 {
|
struct hwthread_params {
|
||||||
|
@ -393,3 +399,33 @@ bool hwthread_needs_fake_step(struct target *target, int64_t thread_id)
|
||||||
{
|
{
|
||||||
return false;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -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) {
|
if (sscanf(packet_stttrr, "vCont;s:%d;c", &threadid) == 1) {
|
||||||
riscv_set_rtos_hartid(target, threadid - 1);
|
riscv_set_rtos_hartid(target, threadid - 1);
|
||||||
riscv_step_rtos_hart(target);
|
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);
|
gdb_put_packet(connection, "S05", 3);
|
||||||
return JIM_OK;
|
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_GDB_START);
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_RESUME_START);
|
target_call_event_callbacks(target, TARGET_EVENT_RESUME_START);
|
||||||
riscv_set_all_rtos_harts(target);
|
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;
|
target->state = TARGET_RUNNING;
|
||||||
gdb_set_frontend_state_running(connection);
|
gdb_set_frontend_state_running(connection);
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
|
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_RESUME_END);
|
target_call_event_callbacks(target, TARGET_EVENT_RESUME_END);
|
||||||
return JIM_OK;
|
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");
|
LOG_ERROR("Got unknown vCont-type packet");
|
||||||
|
}
|
||||||
|
|
||||||
return GDB_THREAD_PACKET_NOT_CONSUMED;
|
return GDB_THREAD_PACKET_NOT_CONSUMED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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->type->needs_fake_step(target, thread_id);
|
||||||
return target->rtos->current_thread != 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;
|
||||||
|
}
|
||||||
|
|
|
@ -90,6 +90,13 @@ struct rtos_type {
|
||||||
* target running a multi-threading OS. If an RTOS can do this, override
|
* target running a multi-threading OS. If an RTOS can do this, override
|
||||||
* needs_fake_step(). */
|
* needs_fake_step(). */
|
||||||
bool (*needs_fake_step)(struct target *target, int64_t thread_id);
|
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 {
|
struct stack_register_offset {
|
||||||
|
@ -136,5 +143,9 @@ int rtos_smp_init(struct target *target);
|
||||||
/* function for handling symbol access */
|
/* function for handling symbol access */
|
||||||
int rtos_qsymbol(struct connection *connection, char const *packet, int packet_size);
|
int rtos_qsymbol(struct connection *connection, char const *packet, int packet_size);
|
||||||
bool rtos_needs_fake_step(struct target *target, int64_t thread_id);
|
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 */
|
#endif /* OPENOCD_RTOS_RTOS_H */
|
||||||
|
|
|
@ -1425,7 +1425,7 @@ static int gdb_read_memory_packet(struct connection *connection,
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
char *hex_buffer;
|
char *hex_buffer;
|
||||||
|
|
||||||
int retval = ERROR_OK;
|
int retval;
|
||||||
|
|
||||||
/* skip command character */
|
/* skip command character */
|
||||||
packet++;
|
packet++;
|
||||||
|
@ -1449,7 +1449,11 @@ static int gdb_read_memory_packet(struct connection *connection,
|
||||||
|
|
||||||
LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
|
LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
|
||||||
|
|
||||||
retval = target_read_buffer(target, addr, len, buffer);
|
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) {
|
if ((retval != ERROR_OK) && !gdb_report_data_abort) {
|
||||||
/* TODO : Here we have to lie and send back all zero's lest stack traces won't work.
|
/* TODO : Here we have to lie and send back all zero's lest stack traces won't work.
|
||||||
|
@ -1520,7 +1524,11 @@ static int gdb_write_memory_packet(struct connection *connection,
|
||||||
if (unhexify(buffer, separator, len) != len)
|
if (unhexify(buffer, separator, len) != len)
|
||||||
LOG_ERROR("unable to decode memory packet");
|
LOG_ERROR("unable to decode memory packet");
|
||||||
|
|
||||||
retval = target_write_buffer(target, addr, len, buffer);
|
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)
|
if (retval == ERROR_OK)
|
||||||
gdb_put_packet(connection, "OK", 2);
|
gdb_put_packet(connection, "OK", 2);
|
||||||
|
@ -1589,7 +1597,12 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
|
||||||
if (len) {
|
if (len) {
|
||||||
LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
|
LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
|
||||||
|
|
||||||
retval = target_write_buffer(target, addr, len, (uint8_t *)separator);
|
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)
|
if (retval != ERROR_OK)
|
||||||
gdb_connection->mem_write_error = true;
|
gdb_connection->mem_write_error = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,14 +162,13 @@ void dump_field(int idle, const struct scan_field *field)
|
||||||
|
|
||||||
log_printf_lf(LOG_LVL_DEBUG,
|
log_printf_lf(LOG_LVL_DEBUG,
|
||||||
__FILE__, __LINE__, __PRETTY_FUNCTION__,
|
__FILE__, __LINE__, __PRETTY_FUNCTION__,
|
||||||
"%db %di %s %08x @%02x -> %s %08x @%02x",
|
"%db %s %08x @%02x -> %s %08x @%02x; %di",
|
||||||
field->num_bits, idle,
|
field->num_bits, op_string[out_op], out_data, out_address,
|
||||||
op_string[out_op], out_data, out_address,
|
status_string[in_op], in_data, in_address, idle);
|
||||||
status_string[in_op], in_data, in_address);
|
|
||||||
} else {
|
} else {
|
||||||
log_printf_lf(LOG_LVL_DEBUG,
|
log_printf_lf(LOG_LVL_DEBUG,
|
||||||
__FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %di %s %08x @%02x -> ?",
|
__FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?; %di",
|
||||||
field->num_bits, idle, op_string[out_op], out_data, out_address);
|
field->num_bits, op_string[out_op], out_data, out_address, idle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -76,6 +76,12 @@ enum gdb_regno {
|
||||||
GDB_REGNO_FT11,
|
GDB_REGNO_FT11,
|
||||||
GDB_REGNO_FPR31 = GDB_REGNO_FT11,
|
GDB_REGNO_FPR31 = GDB_REGNO_FT11,
|
||||||
GDB_REGNO_CSR0 = 65,
|
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_TSELECT = CSR_TSELECT + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_TDATA1 = CSR_TDATA1 + GDB_REGNO_CSR0,
|
GDB_REGNO_TDATA1 = CSR_TDATA1 + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_TDATA2 = CSR_TDATA2 + 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_SATP = CSR_SATP + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_CSR4095 = GDB_REGNO_CSR0 + 4095,
|
GDB_REGNO_CSR4095 = GDB_REGNO_CSR0 + 4095,
|
||||||
GDB_REGNO_PRIV = 4161,
|
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
|
GDB_REGNO_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -323,3 +323,33 @@ static uint32_t auipc(unsigned int dest)
|
||||||
{
|
{
|
||||||
return MATCH_AUIPC | (dest << 7);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -56,7 +56,8 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
|
||||||
if (riscv_program_ebreak(p) != ERROR_OK) {
|
if (riscv_program_ebreak(p) != ERROR_OK) {
|
||||||
LOG_ERROR("Unable to write ebreak");
|
LOG_ERROR("Unable to write ebreak");
|
||||||
for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
|
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;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
info->dcsr &= ~DCSR_HALT;
|
||||||
|
|
||||||
if (step)
|
if (step)
|
||||||
|
@ -1946,8 +1949,11 @@ static int assert_reset(struct target *target)
|
||||||
|
|
||||||
/* Not sure what we should do when there are multiple cores.
|
/* Not sure what we should do when there are multiple cores.
|
||||||
* Here just reset the single hart we're talking to. */
|
* Here just reset the single hart we're talking to. */
|
||||||
info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS |
|
info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
|
||||||
DCSR_EBREAKU | DCSR_HALT;
|
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)
|
if (target->reset_halt)
|
||||||
info->dcsr |= DCSR_NDRESET;
|
info->dcsr |= DCSR_NDRESET;
|
||||||
else
|
else
|
||||||
|
|
|
@ -92,6 +92,7 @@ static int riscv013_test_compliance(struct target *target);
|
||||||
#define CSR_DCSR_CAUSE_DEBUGINT 3
|
#define CSR_DCSR_CAUSE_DEBUGINT 3
|
||||||
#define CSR_DCSR_CAUSE_STEP 4
|
#define CSR_DCSR_CAUSE_STEP 4
|
||||||
#define CSR_DCSR_CAUSE_HALT 5
|
#define CSR_DCSR_CAUSE_HALT 5
|
||||||
|
#define CSR_DCSR_CAUSE_GROUP 6
|
||||||
|
|
||||||
#define RISCV013_INFO(r) riscv013_info_t *r = get_info(target)
|
#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,
|
log_printf_lf(LOG_LVL_DEBUG,
|
||||||
__FILE__, __LINE__, "scan",
|
__FILE__, __LINE__, "scan",
|
||||||
"%db %di %s %08x @%02x -> %s %08x @%02x",
|
"%db %s %08x @%02x -> %s %08x @%02x; %di",
|
||||||
field->num_bits, idle,
|
field->num_bits, op_string[out_op], out_data, out_address,
|
||||||
op_string[out_op], out_data, out_address,
|
status_string[in_op], in_data, in_address, idle);
|
||||||
status_string[in_op], in_data, in_address);
|
|
||||||
|
|
||||||
char out_text[500];
|
char out_text[500];
|
||||||
char in_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();
|
int retval = jtag_execute_queue();
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
LOG_ERROR("dmi_scan failed jtag scan");
|
LOG_ERROR("dmi_scan failed jtag scan");
|
||||||
|
if (data_in)
|
||||||
|
*data_in = ~0;
|
||||||
return DMI_STATUS_FAILED;
|
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);
|
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,
|
static int dmi_op_timeout(struct target *target, uint32_t *data_in,
|
||||||
bool *dmi_busy_encountered, int dmi_op, uint32_t address,
|
bool *dmi_busy_encountered, int dmi_op, uint32_t address,
|
||||||
uint32_t data_out, int timeout_sec, bool exec, bool ensure_success)
|
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);
|
false);
|
||||||
if (status == DMI_STATUS_BUSY) {
|
if (status == DMI_STATUS_BUSY) {
|
||||||
increase_dmi_busy_delay(target);
|
increase_dmi_busy_delay(target);
|
||||||
|
if (dmi_busy_encountered)
|
||||||
|
*dmi_busy_encountered = true;
|
||||||
} else if (status == DMI_STATUS_SUCCESS) {
|
} else if (status == DMI_STATUS_SUCCESS) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("failed %s (NOP) at 0x%x, status=%d", op_name, address,
|
if (data_in) {
|
||||||
status);
|
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;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
if (time(NULL) - start > timeout_sec)
|
if (time(NULL) - start > timeout_sec)
|
||||||
return ERROR_TIMEOUT_REACHED;
|
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;
|
return ERROR_OK;
|
||||||
|
@ -676,7 +686,12 @@ int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus,
|
||||||
DMI_DMSTATUS, 0, timeout_sec, false, true);
|
DMI_DMSTATUS, 0, timeout_sec, false, true);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return result;
|
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. "
|
LOG_ERROR("Debugger is not authenticated to target Debug Module. "
|
||||||
"(dmstatus=0x%x). Use `riscv authdata_read` and "
|
"(dmstatus=0x%x). Use `riscv authdata_read` and "
|
||||||
"`riscv authdata_write` commands to authenticate.", *dmstatus);
|
"`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);
|
command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 3);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
LOG_ERROR("%d-bit register %s not supported.", size,
|
||||||
|
gdb_regno_name(number));
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,6 +882,8 @@ static uint32_t access_register_command(struct target *target, uint32_t number,
|
||||||
assert(reg_info);
|
assert(reg_info);
|
||||||
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
|
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
|
||||||
0xc000 + reg_info->custom_number);
|
0xc000 + reg_info->custom_number);
|
||||||
|
} else {
|
||||||
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
command |= flags;
|
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 &&
|
if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 &&
|
||||||
!info->abstract_read_csr_supported)
|
!info->abstract_read_csr_supported)
|
||||||
return ERROR_FAIL;
|
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,
|
uint32_t command = access_register_command(target, number, size,
|
||||||
AC_ACCESS_REGISTER_TRANSFER);
|
AC_ACCESS_REGISTER_TRANSFER);
|
||||||
|
@ -1041,6 +1063,56 @@ static int examine_progbuf(struct target *target)
|
||||||
return ERROR_OK;
|
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 {
|
typedef enum {
|
||||||
SPACE_DMI_DATA,
|
SPACE_DMI_DATA,
|
||||||
SPACE_DMI_PROGBUF,
|
SPACE_DMI_PROGBUF,
|
||||||
|
@ -1153,7 +1225,7 @@ static int scratch_read64(struct target *target, scratch_mem_t *scratch,
|
||||||
break;
|
break;
|
||||||
case SPACE_DMI_RAM:
|
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)
|
if (read_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
*value = buffer[0] |
|
*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)
|
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
uint64_t mstatus;
|
||||||
|
if (prep_for_register_access(target, &mstatus, number) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
scratch_mem_t scratch;
|
scratch_mem_t scratch;
|
||||||
bool use_scratch = false;
|
bool use_scratch = false;
|
||||||
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 &&
|
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;
|
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 {
|
} else {
|
||||||
if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK)
|
if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
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));
|
riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0));
|
||||||
else
|
else
|
||||||
riscv_program_insert(&program, fmv_w_x(number - GDB_REGNO_FPR0, S0));
|
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) {
|
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
|
||||||
riscv_program_csrw(&program, S0, number);
|
riscv_program_csrw(&program, S0, number);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1290,6 +1379,9 @@ static int register_write_direct(struct target *target, unsigned number,
|
||||||
if (use_scratch)
|
if (use_scratch)
|
||||||
scratch_release(target, &scratch);
|
scratch_release(target, &scratch);
|
||||||
|
|
||||||
|
if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
/* Restore S0. */
|
/* Restore S0. */
|
||||||
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
|
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -1314,14 +1406,6 @@ static int register_read(struct target *target, uint64_t *value, uint32_t number
|
||||||
return ERROR_OK;
|
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. */
|
/** Actually read registers from the target right now. */
|
||||||
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
|
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;
|
scratch_mem_t scratch;
|
||||||
bool use_scratch = false;
|
bool use_scratch = false;
|
||||||
|
|
||||||
uint64_t s0;
|
riscv_reg_t s0;
|
||||||
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
|
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
/* Write program to move data into s0. */
|
/* Write program to move data into s0. */
|
||||||
|
|
||||||
uint64_t mstatus;
|
uint64_t mstatus;
|
||||||
if (is_fpu_reg(number)) {
|
if (prep_for_register_access(target, &mstatus, number) != ERROR_OK)
|
||||||
if (register_read(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK)
|
return ERROR_FAIL;
|
||||||
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 (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
||||||
if (riscv_supports_extension(target, riscv_current_hartid(target), 'D')
|
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) {
|
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
|
||||||
riscv_program_csrr(&program, S0, number);
|
riscv_program_csrr(&program, S0, number);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number);
|
LOG_ERROR("Unsupported register: %s", gdb_regno_name(number));
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1401,9 +1479,8 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_fpu_reg(number) && (mstatus & MSTATUS_FS) == 0)
|
if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK)
|
||||||
if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus) != ERROR_OK)
|
return ERROR_FAIL;
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
/* Restore S0. */
|
/* Restore S0. */
|
||||||
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
|
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
|
||||||
|
@ -1464,6 +1541,24 @@ static int set_haltgroup(struct target *target, bool *supported)
|
||||||
return ERROR_OK;
|
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)
|
static int examine(struct target *target)
|
||||||
{
|
{
|
||||||
/* Don't need to select dbus, since the first thing we do is read dtmcontrol. */
|
/* 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;
|
return ERROR_FAIL;
|
||||||
LOG_DEBUG("dmstatus: 0x%08x", dmstatus);
|
LOG_DEBUG("dmstatus: 0x%08x", dmstatus);
|
||||||
if (get_field(dmstatus, DMI_DMSTATUS_VERSION) != 2) {
|
if (get_field(dmstatus, DMI_DMSTATUS_VERSION) != 2) {
|
||||||
LOG_ERROR("OpenOCD only supports Debug Module version 2, not %d "
|
/* Error was already printed out in dmstatus_read(). */
|
||||||
"(dmstatus=0x%x)", get_field(dmstatus, DMI_DMSTATUS_VERSION), dmstatus);
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1643,6 +1737,11 @@ static int examine(struct target *target)
|
||||||
return ERROR_FAIL;
|
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. */
|
/* Now init registers based on what we discovered. */
|
||||||
if (riscv_init_registers(target) != ERROR_OK)
|
if (riscv_init_registers(target) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -1750,6 +1849,153 @@ static unsigned riscv013_data_bits(struct target *target)
|
||||||
return riscv_xlen(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,
|
static int init_target(struct command_context *cmd_ctx,
|
||||||
struct target *target)
|
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->get_register = &riscv013_get_register;
|
||||||
generic_info->set_register = &riscv013_set_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->select_current_hart = &riscv013_select_current_hart;
|
||||||
generic_info->is_halted = &riscv013_is_halted;
|
generic_info->is_halted = &riscv013_is_halted;
|
||||||
generic_info->resume_go = &riscv013_resume_go;
|
generic_info->resume_go = &riscv013_resume_go;
|
||||||
|
@ -2010,6 +2258,10 @@ static int execute_fence(struct target *target)
|
||||||
if (!riscv_hart_enabled(target, i))
|
if (!riscv_hart_enabled(target, i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (i == old_hartid)
|
||||||
|
/* Fence already executed for this hart */
|
||||||
|
continue;
|
||||||
|
|
||||||
riscv_set_current_hartid(target, i);
|
riscv_set_current_hartid(target, i);
|
||||||
|
|
||||||
struct riscv_program program;
|
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 size, uint8_t *buffer)
|
||||||
{
|
{
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
if (size > 12) {
|
int result;
|
||||||
if (dmi_read(target, &value, DMI_SBDATA3) != ERROR_OK)
|
static int sbdata[4] = { DMI_SBDATA0, DMI_SBDATA1, DMI_SBDATA2, DMI_SBDATA3 };
|
||||||
return ERROR_FAIL;
|
assert(size <= 16);
|
||||||
write_to_buf(buffer + 12, value, 4);
|
for (int i = (size-1) / 4; i >= 0; i--) {
|
||||||
log_memory_access(address + 12, value, 4, true);
|
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;
|
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++) {
|
for (uint32_t i = (next_address - address) / size; i < count - 1; i++) {
|
||||||
if (read_memory_bus_word(target, address + i * size, size,
|
for (int j = (size - 1) / 4; j >= 0; j--) {
|
||||||
buffer + i * size) != ERROR_OK)
|
uint32_t value;
|
||||||
return ERROR_FAIL;
|
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;
|
uint32_t sbcs_read = 0;
|
||||||
if (count > 1) {
|
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.
|
/* "Writes to sbcs while sbbusy is high result in undefined behavior.
|
||||||
* A debugger must not write to sbcs until it reads sbbusy as 0." */
|
* A debugger must not write to sbcs until it reads sbbusy as 0." */
|
||||||
if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK)
|
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;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read the last word, after we disabled sbreadondata if necessary. */
|
||||||
if (!get_field(sbcs_read, DMI_SBCS_SBERROR) &&
|
if (!get_field(sbcs_read, DMI_SBCS_SBERROR) &&
|
||||||
!get_field(sbcs_read, DMI_SBCS_SBBUSYERROR)) {
|
!get_field(sbcs_read, DMI_SBCS_SBBUSYERROR)) {
|
||||||
if (read_memory_bus_word(target, address + (count - 1) * size, size,
|
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;
|
int result = ERROR_OK;
|
||||||
|
|
||||||
/* Write address to S0, and execute buffer. */
|
/* Write address to S0. */
|
||||||
result = register_write_direct(target, GDB_REGNO_S0, address);
|
result = register_write_direct(target, GDB_REGNO_S0, address);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
goto error;
|
return result;
|
||||||
uint32_t command = access_register_command(target, GDB_REGNO_S1,
|
uint32_t command = access_register_command(target, GDB_REGNO_S1,
|
||||||
riscv_xlen(target),
|
riscv_xlen(target),
|
||||||
AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC);
|
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;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
/* First read has just triggered. Result is in s1. */
|
/* First read has just triggered. Result is in s1. */
|
||||||
|
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK)
|
if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK)
|
||||||
|
@ -3083,11 +3369,12 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address,
|
||||||
|
|
||||||
bool dmi_busy_encountered;
|
bool dmi_busy_encountered;
|
||||||
if (dmi_op(target, &sbcs, &dmi_busy_encountered, DMI_OP_READ,
|
if (dmi_op(target, &sbcs, &dmi_busy_encountered, DMI_OP_READ,
|
||||||
DMI_SBCS, 0, false, false) != ERROR_OK)
|
DMI_SBCS, 0, false, false) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
time_t start = time(NULL);
|
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) {
|
if (time(NULL) - start > riscv_command_timeout_sec) {
|
||||||
LOG_ERROR("Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). "
|
LOG_ERROR("Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). "
|
||||||
"Increase the timeout with riscv set_command_timeout_sec.",
|
"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;
|
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;
|
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. */
|
/* We wrote while the target was busy. Slow down and try again. */
|
||||||
dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR);
|
dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR);
|
||||||
info->bus_master_write_delay += info->bus_master_write_delay / 10 + 1;
|
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);
|
next_address = sb_read_address(target);
|
||||||
if (next_address < address) {
|
if (next_address < address) {
|
||||||
/* This should never happen, probably buggy hardware. */
|
/* 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;
|
uint32_t abstractcs;
|
||||||
bool dmi_busy_encountered;
|
bool dmi_busy_encountered;
|
||||||
if (dmi_op(target, &abstractcs, &dmi_busy_encountered, DMI_OP_READ,
|
result = dmi_op(target, &abstractcs, &dmi_busy_encountered,
|
||||||
DMI_ABSTRACTCS, 0, false, true) != ERROR_OK)
|
DMI_OP_READ, DMI_ABSTRACTCS, 0, false, true);
|
||||||
|
if (result != ERROR_OK)
|
||||||
goto error;
|
goto error;
|
||||||
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
|
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
|
||||||
if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK)
|
if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK)
|
||||||
|
@ -3354,7 +3645,6 @@ struct target_type riscv013_target = {
|
||||||
|
|
||||||
.poll = &riscv_openocd_poll,
|
.poll = &riscv_openocd_poll,
|
||||||
.halt = &riscv_halt,
|
.halt = &riscv_halt,
|
||||||
.resume = &riscv_resume,
|
|
||||||
.step = &riscv_openocd_step,
|
.step = &riscv_openocd_step,
|
||||||
|
|
||||||
.assert_reset = assert_reset,
|
.assert_reset = assert_reset,
|
||||||
|
@ -3377,10 +3667,12 @@ static int riscv013_get_register(struct target *target,
|
||||||
|
|
||||||
int result = ERROR_OK;
|
int result = ERROR_OK;
|
||||||
if (rid == GDB_REGNO_PC) {
|
if (rid == GDB_REGNO_PC) {
|
||||||
|
/* TODO: move this into riscv.c. */
|
||||||
result = register_read(target, value, GDB_REGNO_DPC);
|
result = register_read(target, value, GDB_REGNO_DPC);
|
||||||
LOG_DEBUG("[%d] read PC from DPC: 0x%" PRIx64, target->coreid, *value);
|
LOG_DEBUG("[%d] read PC from DPC: 0x%" PRIx64, target->coreid, *value);
|
||||||
} else if (rid == GDB_REGNO_PRIV) {
|
} else if (rid == GDB_REGNO_PRIV) {
|
||||||
uint64_t dcsr;
|
uint64_t dcsr;
|
||||||
|
/* TODO: move this into riscv.c. */
|
||||||
result = register_read(target, &dcsr, GDB_REGNO_DCSR);
|
result = register_read(target, &dcsr, GDB_REGNO_DCSR);
|
||||||
*value = get_field(dcsr, CSR_DCSR_PRV);
|
*value = get_field(dcsr, CSR_DCSR_PRV);
|
||||||
} else {
|
} 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_DEBUGINT:
|
||||||
case CSR_DCSR_CAUSE_HALT:
|
case CSR_DCSR_CAUSE_HALT:
|
||||||
return RISCV_HALT_INTERRUPT;
|
return RISCV_HALT_INTERRUPT;
|
||||||
|
case CSR_DCSR_CAUSE_GROUP:
|
||||||
|
return RISCV_HALT_GROUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_ERROR("Unknown DCSR cause field: %x", (int)get_field(dcsr, CSR_DCSR_CAUSE));
|
LOG_ERROR("Unknown DCSR cause field: %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)
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
dcsr = set_field(dcsr, CSR_DCSR_STEP, step);
|
dcsr = set_field(dcsr, CSR_DCSR_STEP, step);
|
||||||
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, 1);
|
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, riscv_ebreakm);
|
||||||
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, 1);
|
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, riscv_ebreaks);
|
||||||
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, 1);
|
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, riscv_ebreaku);
|
||||||
return riscv_set_register(target, GDB_REGNO_DCSR, dcsr);
|
return riscv_set_register(target, GDB_REGNO_DCSR, dcsr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4244,7 +4538,7 @@ int riscv013_test_compliance(struct target *target)
|
||||||
|
|
||||||
/* resumereq */
|
/* resumereq */
|
||||||
/* This bit is not actually readable according to the spec, so nothing to check.*/
|
/* 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.*/
|
/* Halt all harts again so the test can continue.*/
|
||||||
COMPLIANCE_MUST_PASS(riscv_halt(target));
|
COMPLIANCE_MUST_PASS(riscv_halt(target));
|
||||||
|
|
|
@ -252,6 +252,9 @@ int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC;
|
||||||
|
|
||||||
bool riscv_prefer_sba;
|
bool riscv_prefer_sba;
|
||||||
bool riscv_enable_virt2phys = true;
|
bool riscv_enable_virt2phys = true;
|
||||||
|
bool riscv_ebreakm = true;
|
||||||
|
bool riscv_ebreaks = true;
|
||||||
|
bool riscv_ebreaku = true;
|
||||||
|
|
||||||
bool riscv_enable_virtual;
|
bool riscv_enable_virtual;
|
||||||
|
|
||||||
|
@ -273,6 +276,8 @@ static enum {
|
||||||
} resume_order;
|
} resume_order;
|
||||||
|
|
||||||
virt2phys_info_t sv32 = {
|
virt2phys_info_t sv32 = {
|
||||||
|
.name = "Sv32",
|
||||||
|
.va_bits = 32,
|
||||||
.level = 2,
|
.level = 2,
|
||||||
.pte_shift = 2,
|
.pte_shift = 2,
|
||||||
.vpn_shift = {12, 22},
|
.vpn_shift = {12, 22},
|
||||||
|
@ -284,6 +289,8 @@ virt2phys_info_t sv32 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
virt2phys_info_t sv39 = {
|
virt2phys_info_t sv39 = {
|
||||||
|
.name = "Sv39",
|
||||||
|
.va_bits = 39,
|
||||||
.level = 3,
|
.level = 3,
|
||||||
.pte_shift = 3,
|
.pte_shift = 3,
|
||||||
.vpn_shift = {12, 21, 30},
|
.vpn_shift = {12, 21, 30},
|
||||||
|
@ -295,6 +302,8 @@ virt2phys_info_t sv39 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
virt2phys_info_t sv48 = {
|
virt2phys_info_t sv48 = {
|
||||||
|
.name = "Sv48",
|
||||||
|
.va_bits = 48,
|
||||||
.level = 4,
|
.level = 4,
|
||||||
.pte_shift = 3,
|
.pte_shift = 3,
|
||||||
.vpn_shift = {12, 21, 30, 39},
|
.vpn_shift = {12, 21, 30, 39},
|
||||||
|
@ -1050,11 +1059,13 @@ int halt_prep(struct target *target)
|
||||||
if (!riscv_hart_enabled(target, i))
|
if (!riscv_hart_enabled(target, i))
|
||||||
continue;
|
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)
|
if (riscv_set_current_hartid(target, i) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if (riscv_is_halted(target)) {
|
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 {
|
} else {
|
||||||
if (r->halt_prep(target) != ERROR_OK)
|
if (r->halt_prep(target) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
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
|
* @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.
|
* configured. This is used to run algorithms on just one hart.
|
||||||
*/
|
*/
|
||||||
int riscv_resume_internal(
|
int riscv_resume(
|
||||||
struct target *target,
|
struct target *target,
|
||||||
int current,
|
int current,
|
||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
|
@ -1344,10 +1355,10 @@ int riscv_resume_internal(
|
||||||
return result;
|
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)
|
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);
|
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)
|
static int riscv_mmu(struct target *target, int *enabled)
|
||||||
{
|
{
|
||||||
|
if (!riscv_enable_virt2phys) {
|
||||||
|
*enabled = 0;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (riscv_rtos_enabled(target))
|
if (riscv_rtos_enabled(target))
|
||||||
riscv_set_current_hartid(target, target->rtos->current_thread - 1);
|
riscv_set_current_hartid(target, target->rtos->current_thread - 1);
|
||||||
|
|
||||||
riscv_reg_t value;
|
/* Don't use MMU in explicit or effective M (machine) mode */
|
||||||
int result = riscv_get_register(target, &value, GDB_REGNO_SATP);
|
riscv_reg_t priv;
|
||||||
if (result != ERROR_OK) {
|
if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) {
|
||||||
LOG_DEBUG("Couldn't read SATP.");
|
LOG_ERROR("Failed to read priv register.");
|
||||||
return result;
|
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.");
|
LOG_DEBUG("MMU is disabled.");
|
||||||
*enabled = 0;
|
*enabled = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1404,18 +1440,16 @@ static int riscv_address_translate(struct target *target,
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return result;
|
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) {
|
switch (mode) {
|
||||||
case SATP_MODE_SV32:
|
case SATP_MODE_SV32:
|
||||||
LOG_DEBUG("Translation mode: SV32");
|
|
||||||
info = &sv32;
|
info = &sv32;
|
||||||
break;
|
break;
|
||||||
case SATP_MODE_SV39:
|
case SATP_MODE_SV39:
|
||||||
LOG_DEBUG("Translation mode: SV39");
|
|
||||||
info = &sv39;
|
info = &sv39;
|
||||||
break;
|
break;
|
||||||
case SATP_MODE_SV48:
|
case SATP_MODE_SV48:
|
||||||
LOG_DEBUG("Translation mode: SV48");
|
|
||||||
info = &sv48;
|
info = &sv48;
|
||||||
break;
|
break;
|
||||||
case SATP_MODE_OFF:
|
case SATP_MODE_OFF:
|
||||||
|
@ -1427,8 +1461,18 @@ static int riscv_address_translate(struct target *target,
|
||||||
" (satp: 0x%" PRIx64")", satp_value);
|
" (satp: 0x%" PRIx64")", satp_value);
|
||||||
return ERROR_FAIL;
|
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;
|
table_address = ppn_value << RISCV_PGSHIFT;
|
||||||
i = info->level - 1;
|
i = info->level - 1;
|
||||||
while (i >= 0) {
|
while (i >= 0) {
|
||||||
|
@ -1448,6 +1492,9 @@ static int riscv_address_translate(struct target *target,
|
||||||
else
|
else
|
||||||
pte = buf_get_u64(buffer, 0, 64);
|
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)))
|
if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W)))
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
@ -1466,26 +1513,25 @@ static int riscv_address_translate(struct target *target,
|
||||||
return ERROR_FAIL;
|
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) {
|
while (i < info->level) {
|
||||||
ppn_value = pte >> info->pte_ppn_shift[i];
|
ppn_value = pte >> info->pte_ppn_shift[i];
|
||||||
ppn_value &= info->pte_ppn_mask[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]);
|
*physical |= (ppn_value << info->pa_ppn_shift[i]);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
LOG_DEBUG("Virtual address: 0x%" TARGET_PRIxADDR, virtual);
|
LOG_DEBUG("0x%" TARGET_PRIxADDR " -> 0x%" TARGET_PRIxADDR, virtual,
|
||||||
LOG_DEBUG("Physical address: 0x%" TARGET_PRIxADDR, *physical);
|
*physical);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical)
|
static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical)
|
||||||
{
|
{
|
||||||
if (!riscv_enable_virt2phys)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
int enabled;
|
int enabled;
|
||||||
if (riscv_mmu(target, &enabled) == ERROR_OK) {
|
if (riscv_mmu(target, &enabled) == ERROR_OK) {
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
|
@ -1693,7 +1739,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
||||||
|
|
||||||
/* Run algorithm */
|
/* Run algorithm */
|
||||||
LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point);
|
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;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
int64_t start = timeval_ms();
|
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;
|
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:
|
case RISCV_HALT_BREAKPOINT:
|
||||||
target->debug_reason = DBG_REASON_BREAKPOINT;
|
target->debug_reason = DBG_REASON_BREAKPOINT;
|
||||||
break;
|
break;
|
||||||
|
@ -1906,6 +1952,7 @@ int set_debug_reason(struct target *target, int hartid)
|
||||||
target->debug_reason = DBG_REASON_WATCHPOINT;
|
target->debug_reason = DBG_REASON_WATCHPOINT;
|
||||||
break;
|
break;
|
||||||
case RISCV_HALT_INTERRUPT:
|
case RISCV_HALT_INTERRUPT:
|
||||||
|
case RISCV_HALT_GROUP:
|
||||||
target->debug_reason = DBG_REASON_DBGRQ;
|
target->debug_reason = DBG_REASON_DBGRQ;
|
||||||
break;
|
break;
|
||||||
case RISCV_HALT_SINGLESTEP:
|
case RISCV_HALT_SINGLESTEP:
|
||||||
|
@ -1917,6 +1964,7 @@ int set_debug_reason(struct target *target, int hartid)
|
||||||
case RISCV_HALT_ERROR:
|
case RISCV_HALT_ERROR:
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
LOG_DEBUG("[%s] debug_reason=%d", target_name(target), target->debug_reason);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1947,7 +1995,8 @@ int riscv_openocd_poll(struct target *target)
|
||||||
LOG_DEBUG(" hart %d halted", halted_hart);
|
LOG_DEBUG(" hart %d halted", halted_hart);
|
||||||
|
|
||||||
target->state = TARGET_HALTED;
|
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;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
target->rtos->current_threadid = halted_hart + 1;
|
target->rtos->current_threadid = halted_hart + 1;
|
||||||
|
@ -1963,45 +2012,75 @@ int riscv_openocd_poll(struct target *target)
|
||||||
riscv_halt(target);
|
riscv_halt(target);
|
||||||
|
|
||||||
} else if (target->smp) {
|
} else if (target->smp) {
|
||||||
bool halt_discovered = false;
|
unsigned halts_discovered = 0;
|
||||||
|
unsigned total_targets = 0;
|
||||||
bool newly_halted[128] = {0};
|
bool newly_halted[128] = {0};
|
||||||
|
unsigned should_remain_halted = 0;
|
||||||
|
unsigned should_resume = 0;
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
for (struct target_list *list = target->head; list != NULL;
|
for (struct target_list *list = target->head; list != NULL;
|
||||||
list = list->next, i++) {
|
list = list->next, i++) {
|
||||||
|
total_targets++;
|
||||||
struct target *t = list->target;
|
struct target *t = list->target;
|
||||||
riscv_info_t *r = riscv_info(t);
|
riscv_info_t *r = riscv_info(t);
|
||||||
assert(i < DIM(newly_halted));
|
assert(i < DIM(newly_halted));
|
||||||
enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid);
|
enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid);
|
||||||
switch (out) {
|
switch (out) {
|
||||||
case RPH_NO_CHANGE:
|
case RPH_NO_CHANGE:
|
||||||
break;
|
if (t->state == TARGET_HALTED)
|
||||||
case RPH_DISCOVERED_RUNNING:
|
should_remain_halted++;
|
||||||
t->state = TARGET_RUNNING;
|
break;
|
||||||
t->debug_reason = DBG_REASON_NOTHALTED;
|
case RPH_DISCOVERED_RUNNING:
|
||||||
break;
|
t->state = TARGET_RUNNING;
|
||||||
case RPH_DISCOVERED_HALTED:
|
t->debug_reason = DBG_REASON_NOTHALTED;
|
||||||
halt_discovered = true;
|
break;
|
||||||
newly_halted[i] = true;
|
case RPH_DISCOVERED_HALTED:
|
||||||
t->state = TARGET_HALTED;
|
halts_discovered++;
|
||||||
if (set_debug_reason(t, r->current_hartid) != ERROR_OK)
|
newly_halted[i] = true;
|
||||||
return ERROR_FAIL;
|
t->state = TARGET_HALTED;
|
||||||
break;
|
enum riscv_halt_reason halt_reason =
|
||||||
case RPH_ERROR:
|
riscv_halt_reason(t, r->current_hartid);
|
||||||
|
if (set_debug_reason(t, halt_reason) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
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) {
|
LOG_DEBUG("should_remain_halted=%d, should_resume=%d",
|
||||||
i = 0;
|
should_remain_halted, should_resume);
|
||||||
for (struct target_list *list = target->head; list != NULL;
|
if (should_remain_halted && should_resume) {
|
||||||
list = list->next, i++) {
|
LOG_WARNING("%d harts should remain halted, and %d should resume.",
|
||||||
struct target *t = list->target;
|
should_remain_halted, should_resume);
|
||||||
if (newly_halted[i])
|
}
|
||||||
target_call_event_callbacks(t, TARGET_EVENT_HALTED);
|
if (should_remain_halted) {
|
||||||
}
|
LOG_DEBUG("halt all");
|
||||||
|
|
||||||
LOG_DEBUG("Halt other targets in this SMP group.");
|
|
||||||
riscv_halt(target);
|
riscv_halt(target);
|
||||||
|
} else if (should_resume) {
|
||||||
|
LOG_DEBUG("resume all");
|
||||||
|
riscv_resume(target, true, 0, 0, 0, false);
|
||||||
}
|
}
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
|
@ -2016,18 +2095,30 @@ int riscv_openocd_poll(struct target *target)
|
||||||
halted_hart = riscv_current_hartid(target);
|
halted_hart = riscv_current_hartid(target);
|
||||||
LOG_DEBUG(" hart %d halted", halted_hart);
|
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;
|
return ERROR_FAIL;
|
||||||
target->state = TARGET_HALTED;
|
target->state = TARGET_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target->debug_reason == DBG_REASON_BREAKPOINT) {
|
if (target->debug_reason == DBG_REASON_BREAKPOINT) {
|
||||||
int retval;
|
int retval;
|
||||||
if (riscv_semihosting(target, &retval) != 0)
|
switch (riscv_semihosting(target, &retval)) {
|
||||||
return 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2459,6 +2550,36 @@ COMMAND_HANDLER(riscv_set_enable_virt2phys)
|
||||||
return ERROR_OK;
|
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[] = {
|
static const struct command_registration riscv_exec_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "test_compliance",
|
.name = "test_compliance",
|
||||||
|
@ -2487,7 +2608,7 @@ static const struct command_registration riscv_exec_command_handlers[] = {
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.usage = "riscv set_prefer_sba on|off",
|
.usage = "riscv set_prefer_sba on|off",
|
||||||
.help = "When on, prefer to use System Bus Access to access memory. "
|
.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",
|
.name = "set_enable_virtual",
|
||||||
|
@ -2496,7 +2617,7 @@ static const struct command_registration riscv_exec_command_handlers[] = {
|
||||||
.usage = "riscv set_enable_virtual on|off",
|
.usage = "riscv set_enable_virtual on|off",
|
||||||
.help = "When on, memory accesses are performed on physical or virtual "
|
.help = "When on, memory accesses are performed on physical or virtual "
|
||||||
"memory depending on the current system configuration. "
|
"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",
|
.name = "expose_csrs",
|
||||||
|
@ -2599,7 +2720,32 @@ static const struct command_registration riscv_exec_command_handlers[] = {
|
||||||
.handler = riscv_set_enable_virt2phys,
|
.handler = riscv_set_enable_virt2phys,
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.usage = "riscv set_enable_virt2phys on|off",
|
.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
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
@ -2696,7 +2842,7 @@ struct target_type riscv_target = {
|
||||||
.poll = old_or_new_riscv_poll,
|
.poll = old_or_new_riscv_poll,
|
||||||
|
|
||||||
.halt = riscv_halt,
|
.halt = riscv_halt,
|
||||||
.resume = riscv_resume,
|
.resume = riscv_target_resume,
|
||||||
.step = old_or_new_riscv_step,
|
.step = old_or_new_riscv_step,
|
||||||
|
|
||||||
.assert_reset = riscv_assert_reset,
|
.assert_reset = riscv_assert_reset,
|
||||||
|
@ -2921,6 +3067,55 @@ bool riscv_has_register(struct target *target, int hartid, int regid)
|
||||||
return 1;
|
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
|
* 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
|
* 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'))
|
riscv_supports_extension(target, hartid, 'E'))
|
||||||
return ERROR_OK;
|
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,
|
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);
|
RISCV_INFO(r);
|
||||||
|
|
||||||
struct reg *reg = &target->reg_cache->reg_list[regid];
|
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)) {
|
if (reg && reg->valid && hartid == riscv_current_hartid(target)) {
|
||||||
*value = buf_get_u64(reg->value, 0, reg->size);
|
*value = buf_get_u64(reg->value, 0, reg->size);
|
||||||
|
LOG_DEBUG("{%d} %s: %" PRIx64 " (cached)", hartid,
|
||||||
|
gdb_regno_name(regid), *value);
|
||||||
return ERROR_OK;
|
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);
|
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);
|
LOG_DEBUG("{%d} %s: %" PRIx64, hartid, gdb_regno_name(regid), *value);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -3223,6 +3438,74 @@ const char *gdb_regno_name(enum gdb_regno regno)
|
||||||
return "priv";
|
return "priv";
|
||||||
case GDB_REGNO_SATP:
|
case GDB_REGNO_SATP:
|
||||||
return "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:
|
default:
|
||||||
if (regno <= GDB_REGNO_XPR31)
|
if (regno <= GDB_REGNO_XPR31)
|
||||||
sprintf(buf, "x%d", regno - GDB_REGNO_ZERO);
|
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;
|
riscv_reg_info_t *reg_info = reg->arch_info;
|
||||||
struct target *target = reg_info->target;
|
struct target *target = reg_info->target;
|
||||||
uint64_t value;
|
RISCV_INFO(r);
|
||||||
int result = riscv_get_register(target, &value, reg->number);
|
|
||||||
if (result != ERROR_OK)
|
if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
|
||||||
return result;
|
if (!r->get_register_buf) {
|
||||||
buf_set_u64(reg->value, 0, reg->size, value);
|
LOG_ERROR("Reading register %s not supported on this RISC-V target.",
|
||||||
/* CSRs (and possibly other extension) registers may change value at any
|
gdb_regno_name(reg->number));
|
||||||
* time. */
|
return ERROR_FAIL;
|
||||||
if (reg->number <= GDB_REGNO_XPR31 ||
|
}
|
||||||
(reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) ||
|
|
||||||
reg->number == GDB_REGNO_PC)
|
if (r->get_register_buf(target, reg->value, reg->number) != ERROR_OK)
|
||||||
reg->valid = true;
|
return ERROR_FAIL;
|
||||||
LOG_DEBUG("[%d]{%d} read 0x%" PRIx64 " from %s (valid=%d)",
|
} else {
|
||||||
target->coreid, riscv_current_hartid(target), value, reg->name,
|
uint64_t value;
|
||||||
reg->valid);
|
int result = riscv_get_register(target, &value, reg->number);
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
buf_set_u64(reg->value, 0, reg->size, value);
|
||||||
|
}
|
||||||
|
reg->valid = gdb_regno_cacheable(reg->number, false);
|
||||||
|
char *str = buf_to_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;
|
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;
|
riscv_reg_info_t *reg_info = reg->arch_info;
|
||||||
struct target *target = reg_info->target;
|
struct target *target = reg_info->target;
|
||||||
|
RISCV_INFO(r);
|
||||||
|
|
||||||
uint64_t value = buf_get_u64(buf, 0, reg->size);
|
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);
|
||||||
|
|
||||||
LOG_DEBUG("[%d]{%d} write 0x%" PRIx64 " to %s (valid=%d)",
|
memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8));
|
||||||
target->coreid, riscv_current_hartid(target), value, reg->name,
|
reg->valid = gdb_regno_cacheable(reg->number, true);
|
||||||
reg->valid);
|
|
||||||
struct reg *r = &target->reg_cache->reg_list[reg->number];
|
if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
|
||||||
/* CSRs (and possibly other extension) registers may change value at any
|
if (!r->set_register_buf) {
|
||||||
* time. */
|
LOG_ERROR("Writing register %s not supported on this RISC-V target.",
|
||||||
if (reg->number <= GDB_REGNO_XPR31 ||
|
gdb_regno_name(reg->number));
|
||||||
(reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) ||
|
return ERROR_FAIL;
|
||||||
reg->number == GDB_REGNO_PC)
|
}
|
||||||
r->valid = true;
|
|
||||||
memcpy(r->value, buf, (r->size + 7) / 8);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
riscv_set_register(target, reg->number, value);
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3327,6 +3628,8 @@ int riscv_init_registers(struct target *target)
|
||||||
calloc(target->reg_cache->num_regs, max_reg_name_len);
|
calloc(target->reg_cache->num_regs, max_reg_name_len);
|
||||||
char *reg_name = info->reg_names;
|
char *reg_name = info->reg_names;
|
||||||
|
|
||||||
|
int hartid = riscv_current_hartid(target);
|
||||||
|
|
||||||
static struct reg_feature feature_cpu = {
|
static struct reg_feature feature_cpu = {
|
||||||
.name = "org.gnu.gdb.riscv.cpu"
|
.name = "org.gnu.gdb.riscv.cpu"
|
||||||
};
|
};
|
||||||
|
@ -3336,6 +3639,9 @@ int riscv_init_registers(struct target *target)
|
||||||
static struct reg_feature feature_csr = {
|
static struct reg_feature feature_csr = {
|
||||||
.name = "org.gnu.gdb.riscv.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 = {
|
static struct reg_feature feature_virtual = {
|
||||||
.name = "org.gnu.gdb.riscv.virtual"
|
.name = "org.gnu.gdb.riscv.virtual"
|
||||||
};
|
};
|
||||||
|
@ -3343,14 +3649,117 @@ int riscv_init_registers(struct target *target)
|
||||||
.name = "org.gnu.gdb.riscv.custom"
|
.name = "org.gnu.gdb.riscv.custom"
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct reg_data_type type_ieee_single = {
|
/* These types are built into gdb. */
|
||||||
.type = REG_TYPE_IEEE_SINGLE,
|
static struct reg_data_type type_ieee_single = { .type = REG_TYPE_IEEE_SINGLE, .id = "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 = {
|
static struct reg_data_type_union single_double_union = {
|
||||||
.type = REG_TYPE_IEEE_DOUBLE,
|
.fields = single_double_fields
|
||||||
.id = "ieee_double"
|
|
||||||
};
|
};
|
||||||
|
static struct reg_data_type type_ieee_single_double = {
|
||||||
|
.type = REG_TYPE_ARCH_DEFINED,
|
||||||
|
.id = "FPU_FD",
|
||||||
|
.type_class = REG_TYPE_CLASS_UNION,
|
||||||
|
.reg_type_union = &single_double_union
|
||||||
|
};
|
||||||
|
static struct reg_data_type type_uint8 = { .type = REG_TYPE_UINT8, .id = "uint8" };
|
||||||
|
static struct reg_data_type type_uint16 = { .type = REG_TYPE_UINT16, .id = "uint16" };
|
||||||
|
static struct reg_data_type type_uint32 = { .type = REG_TYPE_UINT32, .id = "uint32" };
|
||||||
|
static struct reg_data_type type_uint64 = { .type = REG_TYPE_UINT64, .id = "uint64" };
|
||||||
|
static struct reg_data_type type_uint128 = { .type = REG_TYPE_UINT128, .id = "uint128" };
|
||||||
|
|
||||||
|
/* This is roughly the XML we want:
|
||||||
|
* <vector id="bytes" type="uint8" count="16"/>
|
||||||
|
* <vector id="shorts" type="uint16" count="8"/>
|
||||||
|
* <vector id="words" type="uint32" count="4"/>
|
||||||
|
* <vector id="longs" type="uint64" count="2"/>
|
||||||
|
* <vector id="quads" type="uint128" count="1"/>
|
||||||
|
* <union id="riscv_vector_type">
|
||||||
|
* <field name="b" type="bytes"/>
|
||||||
|
* <field name="s" type="shorts"/>
|
||||||
|
* <field name="w" type="words"/>
|
||||||
|
* <field name="l" type="longs"/>
|
||||||
|
* <field name="q" type="quads"/>
|
||||||
|
* </union>
|
||||||
|
*/
|
||||||
|
|
||||||
|
info->vector_uint8.type = &type_uint8;
|
||||||
|
info->vector_uint8.count = info->vlenb[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[] = {
|
struct csr_info csr_info[] = {
|
||||||
#define DECLARE_CSR(name, number) { number, #name },
|
#define DECLARE_CSR(name, number) { number, #name },
|
||||||
#include "encoding.h"
|
#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));
|
riscv_reg_info_t *shared_reg_info = calloc(1, sizeof(riscv_reg_info_t));
|
||||||
shared_reg_info->target = target;
|
shared_reg_info->target = target;
|
||||||
|
|
||||||
int hartid = riscv_current_hartid(target);
|
|
||||||
|
|
||||||
/* When gdb requests register N, gdb_get_register_packet() assumes that this
|
/* 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
|
* 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
|
* 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) {
|
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
||||||
r->caller_save = true;
|
r->caller_save = true;
|
||||||
if (riscv_supports_extension(target, hartid, 'D')) {
|
if (riscv_supports_extension(target, hartid, 'D')) {
|
||||||
r->reg_data_type = &type_ieee_double;
|
|
||||||
r->size = 64;
|
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')) {
|
} else if (riscv_supports_extension(target, hartid, 'F')) {
|
||||||
r->reg_data_type = &type_ieee_single;
|
r->reg_data_type = &type_ieee_single;
|
||||||
r->size = 32;
|
r->size = 32;
|
||||||
|
@ -3725,6 +4135,15 @@ int riscv_init_registers(struct target *target)
|
||||||
case CSR_MHPMCOUNTER31H:
|
case CSR_MHPMCOUNTER31H:
|
||||||
r->exist = riscv_xlen(target) == 32;
|
r->exist = riscv_xlen(target) == 32;
|
||||||
break;
|
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) {
|
if (!r->exist && expose_csr) {
|
||||||
|
@ -3743,6 +4162,15 @@ int riscv_init_registers(struct target *target)
|
||||||
r->feature = &feature_virtual;
|
r->feature = &feature_virtual;
|
||||||
r->size = 8;
|
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) {
|
} else if (number >= GDB_REGNO_COUNT) {
|
||||||
/* Custom registers. */
|
/* Custom registers. */
|
||||||
assert(expose_custom);
|
assert(expose_custom);
|
||||||
|
|
|
@ -7,6 +7,7 @@ struct riscv_program;
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
#include "gdb_regs.h"
|
#include "gdb_regs.h"
|
||||||
#include "jtag/jtag.h"
|
#include "jtag/jtag.h"
|
||||||
|
#include "target/register.h"
|
||||||
|
|
||||||
/* The register cache is statically allocated. */
|
/* The register cache is statically allocated. */
|
||||||
#define RISCV_MAX_HARTS 1024
|
#define RISCV_MAX_HARTS 1024
|
||||||
|
@ -39,6 +40,7 @@ enum riscv_halt_reason {
|
||||||
RISCV_HALT_SINGLESTEP,
|
RISCV_HALT_SINGLESTEP,
|
||||||
RISCV_HALT_TRIGGER,
|
RISCV_HALT_TRIGGER,
|
||||||
RISCV_HALT_UNKNOWN,
|
RISCV_HALT_UNKNOWN,
|
||||||
|
RISCV_HALT_GROUP,
|
||||||
RISCV_HALT_ERROR
|
RISCV_HALT_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,6 +76,8 @@ typedef struct {
|
||||||
/* It's possible that each core has a different supported ISA set. */
|
/* It's possible that each core has a different supported ISA set. */
|
||||||
int xlen[RISCV_MAX_HARTS];
|
int xlen[RISCV_MAX_HARTS];
|
||||||
riscv_reg_t misa[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. */
|
/* The number of triggers per hart. */
|
||||||
unsigned trigger_count[RISCV_MAX_HARTS];
|
unsigned trigger_count[RISCV_MAX_HARTS];
|
||||||
|
@ -110,6 +114,9 @@ typedef struct {
|
||||||
riscv_reg_t *value, int hid, int rid);
|
riscv_reg_t *value, int hid, int rid);
|
||||||
int (*set_register)(struct target *, int hartid, int regid,
|
int (*set_register)(struct target *, int hartid, int regid,
|
||||||
uint64_t value);
|
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 *);
|
int (*select_current_hart)(struct target *);
|
||||||
bool (*is_halted)(struct target *target);
|
bool (*is_halted)(struct target *target);
|
||||||
/* Resume this target, as well as every other prepped target that can be
|
/* 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? */
|
/* How many harts are attached to the DM that this target is attached to? */
|
||||||
int (*hart_count)(struct target *target);
|
int (*hart_count)(struct target *target);
|
||||||
unsigned (*data_bits)(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;
|
} riscv_info_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -156,7 +178,9 @@ typedef struct {
|
||||||
} riscv_bscan_tunneled_scan_context_t;
|
} riscv_bscan_tunneled_scan_context_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
int level;
|
int level;
|
||||||
|
unsigned va_bits;
|
||||||
unsigned pte_shift;
|
unsigned pte_shift;
|
||||||
unsigned vpn_shift[PG_MAX_LEVEL];
|
unsigned vpn_shift[PG_MAX_LEVEL];
|
||||||
unsigned vpn_mask[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_prefer_sba;
|
||||||
|
|
||||||
extern bool riscv_enable_virtual;
|
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
|
/* Everything needs the RISC-V specific info structure, so here's a nice macro
|
||||||
* that provides that. */
|
* that provides that. */
|
||||||
|
@ -212,7 +239,8 @@ int riscv_resume(
|
||||||
int current,
|
int current,
|
||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
int handle_breakpoints,
|
int handle_breakpoints,
|
||||||
int debug_execution
|
int debug_execution,
|
||||||
|
bool single_hart
|
||||||
);
|
);
|
||||||
|
|
||||||
int riscv_openocd_step(
|
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. */
|
/* Returns TRUE if the target has the given register on the given hart. */
|
||||||
bool riscv_has_register(struct target *target, int hartid, int regid);
|
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
|
/** Set register, updating the cache. */
|
||||||
* are zero extended to 64 bits. */
|
|
||||||
int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v);
|
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);
|
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,
|
int riscv_get_register(struct target *target, riscv_reg_t *value,
|
||||||
enum gdb_regno r);
|
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 riscv_get_register_on_hart(struct target *target, riscv_reg_t *value,
|
||||||
int hartid, enum gdb_regno regid);
|
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);
|
int riscv_init_registers(struct target *target);
|
||||||
|
|
||||||
void riscv_semihosting_init(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,
|
void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field,
|
||||||
riscv_bscan_tunneled_scan_context_t *ctxt);
|
riscv_bscan_tunneled_scan_context_t *ctxt);
|
||||||
|
|
|
@ -60,35 +60,35 @@ void riscv_semihosting_init(struct target *target)
|
||||||
/**
|
/**
|
||||||
* Check for and process a semihosting request using the ARM protocol). This
|
* 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.
|
* 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 target Pointer to the target to process.
|
||||||
* @param retval Pointer to a location where the return code will be stored
|
* @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
|
* @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;
|
struct semihosting *semihosting = target->semihosting;
|
||||||
if (!semihosting)
|
if (!semihosting) {
|
||||||
return 0;
|
LOG_DEBUG(" -> NONE (!semihosting)");
|
||||||
|
return SEMI_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!semihosting->is_active)
|
if (!semihosting->is_active) {
|
||||||
return 0;
|
LOG_DEBUG(" -> NONE (!semihosting->is_active)");
|
||||||
|
return SEMI_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
riscv_reg_t dpc;
|
riscv_reg_t pc;
|
||||||
int result = riscv_get_register(target, &dpc, GDB_REGNO_DPC);
|
int result = riscv_get_register(target, &pc, GDB_REGNO_PC);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return 0;
|
return SEMI_ERROR;
|
||||||
|
|
||||||
uint8_t tmp[12];
|
uint8_t tmp[12];
|
||||||
|
|
||||||
/* Read the current instruction, including the bracketing */
|
/* 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)
|
if (*retval != ERROR_OK)
|
||||||
return 0;
|
return SEMI_ERROR;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The instructions that trigger a semihosting call,
|
* 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 pre = target_buffer_get_u32(target, tmp);
|
||||||
uint32_t ebreak = target_buffer_get_u32(target, tmp + 4);
|
uint32_t ebreak = target_buffer_get_u32(target, tmp + 4);
|
||||||
uint32_t post = target_buffer_get_u32(target, tmp + 8);
|
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) {
|
if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) {
|
||||||
|
|
||||||
/* Not the magic sequence defining semihosting. */
|
/* 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.
|
* operation to complete.
|
||||||
*/
|
*/
|
||||||
if (!semihosting->hit_fileio) {
|
if (!semihosting->hit_fileio) {
|
||||||
|
|
||||||
/* RISC-V uses A0 and A1 to pass function arguments */
|
/* RISC-V uses A0 and A1 to pass function arguments */
|
||||||
riscv_reg_t r0;
|
riscv_reg_t r0;
|
||||||
riscv_reg_t r1;
|
riscv_reg_t r1;
|
||||||
|
|
||||||
result = riscv_get_register(target, &r0, GDB_REGNO_A0);
|
result = riscv_get_register(target, &r0, GDB_REGNO_A0);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK) {
|
||||||
return 0;
|
LOG_DEBUG(" -> ERROR (couldn't read a0)");
|
||||||
|
return SEMI_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
result = riscv_get_register(target, &r1, GDB_REGNO_A1);
|
result = riscv_get_register(target, &r1, GDB_REGNO_A1);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK) {
|
||||||
return 0;
|
LOG_DEBUG(" -> ERROR (couldn't read a1)");
|
||||||
|
return SEMI_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
semihosting->op = r0;
|
semihosting->op = r0;
|
||||||
semihosting->param = r1;
|
semihosting->param = r1;
|
||||||
|
@ -136,11 +139,12 @@ int riscv_semihosting(struct target *target, int *retval)
|
||||||
*retval = semihosting_common(target);
|
*retval = semihosting_common(target);
|
||||||
if (*retval != ERROR_OK) {
|
if (*retval != ERROR_OK) {
|
||||||
LOG_ERROR("Failed semihosting operation");
|
LOG_ERROR("Failed semihosting operation");
|
||||||
return 0;
|
return SEMI_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Unknown operation number, not a semihosting call. */
|
/* 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) {
|
if (semihosting->is_resumable && !semihosting->hit_fileio) {
|
||||||
/* Resume right after the EBREAK 4 bytes instruction. */
|
/* Resume right after the EBREAK 4 bytes instruction. */
|
||||||
*retval = target_resume(target, 0, dpc+4, 0, 0);
|
*retval = riscv_set_register(target, GDB_REGNO_PC, pc + 4);
|
||||||
if (*retval != ERROR_OK) {
|
if (*retval != ERROR_OK)
|
||||||
LOG_ERROR("Failed to resume target");
|
return SEMI_ERROR;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
LOG_DEBUG(" -> HANDLED");
|
||||||
|
return SEMI_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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;
|
struct semihosting *semihosting = target->semihosting;
|
||||||
if (semihosting)
|
if (semihosting)
|
||||||
|
|
|
@ -41,7 +41,9 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
#include <helper/time_support.h>
|
#include <helper/time_support.h>
|
||||||
|
#include <helper/fileio.h>
|
||||||
#include <jtag/jtag.h>
|
#include <jtag/jtag.h>
|
||||||
#include <flash/nor/core.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);
|
int fileio_errno, bool ctrl_c);
|
||||||
static int target_profiling_default(struct target *target, uint32_t *samples,
|
static int target_profiling_default(struct target *target, uint32_t *samples,
|
||||||
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds);
|
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds);
|
||||||
|
static int halt_mcu(struct target *target);
|
||||||
|
|
||||||
/* targets */
|
/* targets */
|
||||||
extern struct target_type arm7tdmi_target;
|
extern struct target_type arm7tdmi_target;
|
||||||
|
@ -2853,6 +2856,12 @@ COMMAND_HANDLER(handle_reg_command)
|
||||||
|
|
||||||
target = get_current_target(CMD_CTX);
|
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 */
|
/* list all available registers for the current target */
|
||||||
if (CMD_ARGC == 0) {
|
if (CMD_ARGC == 0) {
|
||||||
struct reg_cache *cache = target->reg_cache;
|
struct reg_cache *cache = target->reg_cache;
|
||||||
|
@ -3127,6 +3136,10 @@ COMMAND_HANDLER(handle_resume_command)
|
||||||
|
|
||||||
struct target *target = get_current_target(CMD_CTX);
|
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 no CMD_ARGV, resume from current pc, addr = 0,
|
||||||
* with one arguments, addr = CMD_ARGV[0],
|
* with one arguments, addr = CMD_ARGV[0],
|
||||||
* handle breakpoints, not debugging */
|
* handle breakpoints, not debugging */
|
||||||
|
@ -4206,7 +4219,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
|
||||||
long l;
|
long l;
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
int len;
|
int len;
|
||||||
uint32_t addr;
|
target_addr_t addr;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
uint32_t v;
|
uint32_t v;
|
||||||
const char *varname;
|
const char *varname;
|
||||||
|
@ -4233,8 +4246,9 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
|
||||||
if (e != JIM_OK)
|
if (e != JIM_OK)
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
e = Jim_GetLong(interp, argv[2], &l);
|
jim_wide w;
|
||||||
addr = l;
|
e = Jim_GetWide(interp, argv[2], &w);
|
||||||
|
addr = w;
|
||||||
if (e != JIM_OK)
|
if (e != JIM_OK)
|
||||||
return e;
|
return e;
|
||||||
e = Jim_GetLong(interp, argv[3], &l);
|
e = Jim_GetLong(interp, argv[3], &l);
|
||||||
|
@ -4288,7 +4302,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
|
||||||
} else {
|
} else {
|
||||||
char buf[100];
|
char buf[100];
|
||||||
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
|
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,
|
addr,
|
||||||
width);
|
width);
|
||||||
Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL);
|
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);
|
retval = target_read_memory(target, addr, width, count, buffer);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
/* BOO !*/
|
/* 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,
|
addr,
|
||||||
width,
|
width,
|
||||||
count);
|
count);
|
||||||
|
@ -6180,6 +6194,385 @@ nextw:
|
||||||
return retval;
|
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[] = {
|
static const struct command_registration target_exec_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "fast_load_image",
|
.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",
|
.help = "Test the target's memory access functions",
|
||||||
.usage = "size",
|
.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
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
|
@ -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"
|
Loading…
Reference in New Issue