Conform to OpenOCD style guide.
Change-Id: I2b23ac79639ed40e9d59db5c52ea2196df0349bc
This commit is contained in:
parent
19d9e3e32a
commit
d942bce996
|
@ -28,7 +28,7 @@ matrix:
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
env:
|
env:
|
||||||
- BUILD=i686-linux-gnu
|
- BUILD=i686-linux-gnu
|
||||||
- CFLAGS=-m32
|
- CFLAGS=-m32
|
||||||
- EXECUTABLE=openocd
|
- EXECUTABLE=openocd
|
||||||
compiler: clang
|
compiler: clang
|
||||||
|
@ -38,7 +38,7 @@ matrix:
|
||||||
- gcc-multilib
|
- gcc-multilib
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
env:
|
env:
|
||||||
- BUILD=i686-w64-mingw
|
- BUILD=i686-w64-mingw
|
||||||
- CONFIGURE_ARGS="--build=i686-unknown-linux-gnu --host=i686-w64-mingw32"
|
- CONFIGURE_ARGS="--build=i686-unknown-linux-gnu --host=i686-w64-mingw32"
|
||||||
- EXECUTABLE=openocd.exe
|
- EXECUTABLE=openocd.exe
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> *
|
* Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> *
|
||||||
* Modified by Megan Wachs <megan@sifive.com> from the original stmsmi.c *
|
* Modified by Megan Wachs <megan@sifive.com> from the original stmsmi.c *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General Public License as published by *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
/* The Freedom E SPI controller is a SPI bus controller
|
/* The Freedom E SPI controller is a SPI bus controller
|
||||||
* specifically designed for SPI Flash Memories on Freedom E platforms.
|
* specifically designed for SPI Flash Memories on Freedom E platforms.
|
||||||
*
|
*
|
||||||
* Two working modes are available:
|
* Two working modes are available:
|
||||||
* - SW mode: the SPI is controlled by SW. Any custom commands can be sent
|
* - SW mode: the SPI is controlled by SW. Any custom commands can be sent
|
||||||
* on the bus. Writes are only possible in this mode.
|
* on the bus. Writes are only possible in this mode.
|
||||||
|
@ -127,7 +127,7 @@
|
||||||
int __a; \
|
int __a; \
|
||||||
uint32_t __v; \
|
uint32_t __v; \
|
||||||
\
|
\
|
||||||
__a = target_read_u32(target, ctrl_base + (a), &__v); \
|
__a = target_read_u32(target, ctrl_base + (a), &__v); \
|
||||||
if (__a != ERROR_OK) { \
|
if (__a != ERROR_OK) { \
|
||||||
LOG_ERROR("FESPI_READ_REG error"); \
|
LOG_ERROR("FESPI_READ_REG error"); \
|
||||||
return __a; \
|
return __a; \
|
||||||
|
@ -139,7 +139,7 @@
|
||||||
{ \
|
{ \
|
||||||
int __r; \
|
int __r; \
|
||||||
\
|
\
|
||||||
__r = target_write_u32(target, ctrl_base + (a), (v)); \
|
__r = target_write_u32(target, ctrl_base + (a), (v)); \
|
||||||
if (__r != ERROR_OK) { \
|
if (__r != ERROR_OK) { \
|
||||||
LOG_ERROR("FESPI_WRITE_REG error"); \
|
LOG_ERROR("FESPI_WRITE_REG error"); \
|
||||||
return __r; \
|
return __r; \
|
||||||
|
@ -163,7 +163,7 @@ struct fespi_target {
|
||||||
uint32_t ctrl_base;
|
uint32_t ctrl_base;
|
||||||
};
|
};
|
||||||
|
|
||||||
//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 E300 SPI Flash", 0x10e31913 , 0x10014000 },
|
||||||
|
@ -189,16 +189,17 @@ FLASH_BANK_COMMAND_HANDLER(fespi_flash_bank_command)
|
||||||
fespi_info->probed = 0;
|
fespi_info->probed = 0;
|
||||||
fespi_info->ctrl_base = 0;
|
fespi_info->ctrl_base = 0;
|
||||||
if (CMD_ARGC >= 7) {
|
if (CMD_ARGC >= 7) {
|
||||||
int temp;
|
int temp;
|
||||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[6], temp);
|
COMMAND_PARSE_NUMBER(int, CMD_ARGV[6], temp);
|
||||||
fespi_info->ctrl_base = (uint32_t) temp;
|
fespi_info->ctrl_base = (uint32_t) temp;
|
||||||
LOG_DEBUG("ASSUMING FESPI device at ctrl_base = 0x%x", fespi_info->ctrl_base);
|
LOG_DEBUG("ASSUMING FESPI device at ctrl_base = 0x%x", fespi_info->ctrl_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fespi_set_dir (struct flash_bank * bank, bool dir) {
|
static int fespi_set_dir(struct flash_bank *bank, bool dir)
|
||||||
|
{
|
||||||
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 ctrl_base = fespi_info->ctrl_base;
|
uint32_t ctrl_base = fespi_info->ctrl_base;
|
||||||
|
@ -211,7 +212,8 @@ static int fespi_set_dir (struct flash_bank * bank, bool dir) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fespi_txwm_wait(struct flash_bank *bank) {
|
static int fespi_txwm_wait(struct flash_bank *bank)
|
||||||
|
{
|
||||||
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 ctrl_base = fespi_info->ctrl_base;
|
uint32_t ctrl_base = fespi_info->ctrl_base;
|
||||||
|
@ -219,9 +221,8 @@ static int fespi_txwm_wait(struct flash_bank *bank) {
|
||||||
int64_t start = timeval_ms();
|
int64_t start = timeval_ms();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (FESPI_READ_REG(FESPI_REG_IP) & FESPI_IP_TXWM) {
|
if (FESPI_READ_REG(FESPI_REG_IP) & FESPI_IP_TXWM)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
int64_t now = timeval_ms();
|
int64_t now = timeval_ms();
|
||||||
if (now - start > 1000) {
|
if (now - start > 1000) {
|
||||||
LOG_ERROR("ip.txwm didn't get set.");
|
LOG_ERROR("ip.txwm didn't get set.");
|
||||||
|
@ -233,7 +234,8 @@ static int fespi_txwm_wait(struct flash_bank *bank) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fespi_tx(struct flash_bank *bank, uint8_t in){
|
static int fespi_tx(struct flash_bank *bank, uint8_t in)
|
||||||
|
{
|
||||||
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 ctrl_base = fespi_info->ctrl_base;
|
uint32_t ctrl_base = fespi_info->ctrl_base;
|
||||||
|
@ -241,9 +243,8 @@ static int fespi_tx(struct flash_bank *bank, uint8_t in){
|
||||||
int64_t start = timeval_ms();
|
int64_t start = timeval_ms();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if ((int32_t) FESPI_READ_REG(FESPI_REG_TXFIFO) >= 0) {
|
if ((int32_t) FESPI_READ_REG(FESPI_REG_TXFIFO) >= 0)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
int64_t now = timeval_ms();
|
int64_t now = timeval_ms();
|
||||||
if (now - start > 1000) {
|
if (now - start > 1000) {
|
||||||
LOG_ERROR("txfifo stayed negative.");
|
LOG_ERROR("txfifo stayed negative.");
|
||||||
|
@ -276,14 +277,14 @@ static int fespi_rx(struct flash_bank *bank, uint8_t *out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out) {
|
if (out)
|
||||||
*out = value & 0xff;
|
*out = value & 0xff;
|
||||||
}
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO!!! Why don't we need to call this after writing?
|
/* TODO!!! Why don't we need to call this after writing? */
|
||||||
static int fespi_wip (struct flash_bank * bank, int timeout)
|
static int fespi_wip(struct flash_bank *bank, int timeout)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
@ -326,26 +327,34 @@ static int fespi_erase_sector(struct flash_bank *bank, int sector)
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
retval = fespi_tx(bank, SPIFLASH_WRITE_ENABLE);
|
retval = fespi_tx(bank, SPIFLASH_WRITE_ENABLE);
|
||||||
if (retval != ERROR_OK) {return retval;}
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
retval = fespi_txwm_wait(bank);
|
retval = fespi_txwm_wait(bank);
|
||||||
if (retval != ERROR_OK) {return retval;}
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
|
FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
|
||||||
retval = fespi_tx(bank, fespi_info->dev->erase_cmd);
|
retval = fespi_tx(bank, fespi_info->dev->erase_cmd);
|
||||||
if (retval != ERROR_OK) {return retval;}
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
sector = bank->sectors[sector].offset;
|
sector = bank->sectors[sector].offset;
|
||||||
retval = fespi_tx(bank, sector >> 16);
|
retval = fespi_tx(bank, sector >> 16);
|
||||||
if (retval != ERROR_OK) {return retval;}
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
retval = fespi_tx(bank, sector >> 8);
|
retval = fespi_tx(bank, sector >> 8);
|
||||||
if (retval != ERROR_OK) {return retval;}
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
retval = fespi_tx(bank, sector);
|
retval = fespi_tx(bank, sector);
|
||||||
if (retval != ERROR_OK) {return retval;}
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
retval = fespi_txwm_wait(bank);
|
retval = fespi_txwm_wait(bank);
|
||||||
if (retval != ERROR_OK) {return retval;}
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
|
FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
|
||||||
|
|
||||||
retval = fespi_wip(bank, FESPI_MAX_TIMEOUT);
|
retval = fespi_wip(bank, FESPI_MAX_TIMEOUT);
|
||||||
if (retval != ERROR_OK){return retval;}
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -384,9 +393,9 @@ static int fespi_erase(struct flash_bank *bank, int first, int last)
|
||||||
|
|
||||||
FESPI_WRITE_REG(FESPI_REG_TXCTRL, FESPI_TXWM(1));
|
FESPI_WRITE_REG(FESPI_REG_TXCTRL, FESPI_TXWM(1));
|
||||||
retval = fespi_txwm_wait(bank);
|
retval = fespi_txwm_wait(bank);
|
||||||
if (retval != ERROR_OK){
|
if (retval != ERROR_OK) {
|
||||||
LOG_ERROR("WM Didn't go high before attempting.");
|
LOG_ERROR("WM Didn't go high before attempting.");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable Hardware accesses*/
|
/* Disable Hardware accesses*/
|
||||||
|
@ -394,7 +403,7 @@ static int fespi_erase(struct flash_bank *bank, int first, int last)
|
||||||
|
|
||||||
/* poll WIP */
|
/* poll WIP */
|
||||||
retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT);
|
retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
for (sector = first; sector <= last; sector++) {
|
for (sector = first; sector <= last; sector++) {
|
||||||
|
@ -427,7 +436,7 @@ static int slow_fespi_write_buffer(struct flash_bank *bank,
|
||||||
uint32_t ctrl_base = fespi_info->ctrl_base;
|
uint32_t ctrl_base = fespi_info->ctrl_base;
|
||||||
uint32_t ii;
|
uint32_t ii;
|
||||||
|
|
||||||
//TODO!!! assert that len < page size
|
/* TODO!!! assert that len < page size */
|
||||||
|
|
||||||
fespi_tx(bank, SPIFLASH_WRITE_ENABLE);
|
fespi_tx(bank, SPIFLASH_WRITE_ENABLE);
|
||||||
fespi_txwm_wait(bank);
|
fespi_txwm_wait(bank);
|
||||||
|
@ -440,9 +449,8 @@ static int slow_fespi_write_buffer(struct flash_bank *bank,
|
||||||
fespi_tx(bank, offset >> 8);
|
fespi_tx(bank, offset >> 8);
|
||||||
fespi_tx(bank, offset);
|
fespi_tx(bank, offset);
|
||||||
|
|
||||||
for (ii = 0; ii < len; ii++) {
|
for (ii = 0; ii < len; ii++)
|
||||||
fespi_tx(bank, buffer[ii]);
|
fespi_tx(bank, buffer[ii]);
|
||||||
}
|
|
||||||
|
|
||||||
fespi_txwm_wait(bank);
|
fespi_txwm_wait(bank);
|
||||||
|
|
||||||
|
@ -487,67 +495,67 @@ static int slow_fespi_write_buffer(struct flash_bank *bank,
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
command_table:
|
command_table:
|
||||||
j main // 0
|
j main // 0
|
||||||
ebreak // 4
|
ebreak // 4
|
||||||
j tx // 8
|
j tx // 8
|
||||||
j txwm_wait // 12
|
j txwm_wait // 12
|
||||||
j write_reg // 16
|
j write_reg // 16
|
||||||
j wip_wait // 20
|
j wip_wait // 20
|
||||||
j set_dir // 24
|
j set_dir // 24
|
||||||
|
|
||||||
// Execute the program.
|
// Execute the program.
|
||||||
main:
|
main:
|
||||||
lbu t0, 0(a1)
|
lbu t0, 0(a1)
|
||||||
addi a1, a1, 1
|
addi a1, a1, 1
|
||||||
la t1, command_table
|
la t1, command_table
|
||||||
add t0, t0, t1
|
add t0, t0, t1
|
||||||
jr t0
|
jr t0
|
||||||
|
|
||||||
// Read 1 byte the contains the number of bytes to transmit. Then read those
|
// Read 1 byte the contains the number of bytes to transmit. Then read those
|
||||||
// bytes from the program and transmit them one by one.
|
// bytes from the program and transmit them one by one.
|
||||||
tx:
|
tx:
|
||||||
lbu t1, 0(a1) // read number of bytes to transmit
|
lbu t1, 0(a1) // read number of bytes to transmit
|
||||||
addi a1, a1, 1
|
addi a1, a1, 1
|
||||||
1: lw t0, FESPI_REG_TXFIFO(a0) // wait for FIFO clear
|
1: lw t0, FESPI_REG_TXFIFO(a0) // wait for FIFO clear
|
||||||
bltz t0, 1b
|
bltz t0, 1b
|
||||||
lbu t0, 0(a1) // Load byte to write
|
lbu t0, 0(a1) // Load byte to write
|
||||||
sw t0, FESPI_REG_TXFIFO(a0)
|
sw t0, FESPI_REG_TXFIFO(a0)
|
||||||
addi a1, a1, 1
|
addi a1, a1, 1
|
||||||
addi t1, t1, -1
|
addi t1, t1, -1
|
||||||
bgtz t1, 1b
|
bgtz t1, 1b
|
||||||
j main
|
j main
|
||||||
|
|
||||||
// Wait until TXWM is set.
|
// Wait until TXWM is set.
|
||||||
txwm_wait:
|
txwm_wait:
|
||||||
1: lw t0, FESPI_REG_IP(a0)
|
1: lw t0, FESPI_REG_IP(a0)
|
||||||
andi t0, t0, FESPI_IP_TXWM
|
andi t0, t0, FESPI_IP_TXWM
|
||||||
beqz t0, 1b
|
beqz t0, 1b
|
||||||
j main
|
j main
|
||||||
|
|
||||||
// Read 1 byte that contains the offset of the register to write, and 1 byte
|
// Read 1 byte that contains the offset of the register to write, and 1 byte
|
||||||
// that contains the data to write.
|
// that contains the data to write.
|
||||||
write_reg:
|
write_reg:
|
||||||
lbu t0, 0(a1) // read register to write
|
lbu t0, 0(a1) // read register to write
|
||||||
add t0, t0, a0
|
add t0, t0, a0
|
||||||
lbu t1, 1(a1) // read value to write
|
lbu t1, 1(a1) // read value to write
|
||||||
addi a1, a1, 2
|
addi a1, a1, 2
|
||||||
sw t1, 0(t0)
|
sw t1, 0(t0)
|
||||||
j main
|
j main
|
||||||
|
|
||||||
wip_wait:
|
wip_wait:
|
||||||
li a2, SPIFLASH_READ_STATUS
|
li a2, SPIFLASH_READ_STATUS
|
||||||
jal txrx_byte
|
jal txrx_byte
|
||||||
// discard first result
|
// discard first result
|
||||||
1: li a2, 0
|
1: li a2, 0
|
||||||
jal txrx_byte
|
jal txrx_byte
|
||||||
andi t0, a2, SPIFLASH_BSY_BIT
|
andi t0, a2, SPIFLASH_BSY_BIT
|
||||||
bnez t0, 1b
|
bnez t0, 1b
|
||||||
j main
|
j main
|
||||||
|
|
||||||
txrx_byte: // transmit the byte in a2, receive a bit into a2
|
txrx_byte: // transmit the byte in a2, receive a bit into a2
|
||||||
lw t0, FESPI_REG_TXFIFO(a0) // wait for FIFO clear
|
lw t0, FESPI_REG_TXFIFO(a0) // wait for FIFO clear
|
||||||
bltz t0, txrx_byte
|
bltz t0, txrx_byte
|
||||||
sw a2, FESPI_REG_TXFIFO(a0)
|
sw a2, FESPI_REG_TXFIFO(a0)
|
||||||
1: lw a2, FESPI_REG_RXFIFO(a0)
|
1: lw a2, FESPI_REG_RXFIFO(a0)
|
||||||
bltz a2, 1b
|
bltz a2, 1b
|
||||||
ret
|
ret
|
||||||
|
@ -556,8 +564,8 @@ set_dir:
|
||||||
lw t0, FESPI_REG_FMT(a0)
|
lw t0, FESPI_REG_FMT(a0)
|
||||||
li t1, ~(FESPI_FMT_DIR(0xFFFFFFFF))
|
li t1, ~(FESPI_FMT_DIR(0xFFFFFFFF))
|
||||||
and t0, t0, t1
|
and t0, t0, t1
|
||||||
lbu t1, 0(a1) // read value to OR in
|
lbu t1, 0(a1) // read value to OR in
|
||||||
addi a1, a1, 1
|
addi a1, a1, 1
|
||||||
or t0, t0, t1
|
or t0, t0, t1
|
||||||
sw t0, FESPI_REG_FMT(a0)
|
sw t0, FESPI_REG_FMT(a0)
|
||||||
j main
|
j main
|
||||||
|
@ -565,24 +573,24 @@ set_dir:
|
||||||
// ALGO_END
|
// ALGO_END
|
||||||
*/
|
*/
|
||||||
static const uint8_t algorithm_bin[] = {
|
static const uint8_t algorithm_bin[] = {
|
||||||
0x6f, 0x00, 0xc0, 0x01, 0x73, 0x00, 0x10, 0x00, 0x6f, 0x00, 0xc0, 0x02,
|
0x6f, 0x00, 0xc0, 0x01, 0x73, 0x00, 0x10, 0x00, 0x6f, 0x00, 0xc0, 0x02,
|
||||||
0x6f, 0x00, 0x00, 0x05, 0x6f, 0x00, 0xc0, 0x05, 0x6f, 0x00, 0x00, 0x07,
|
0x6f, 0x00, 0x00, 0x05, 0x6f, 0x00, 0xc0, 0x05, 0x6f, 0x00, 0x00, 0x07,
|
||||||
0x6f, 0x00, 0x00, 0x0a, 0x83, 0xc2, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00,
|
0x6f, 0x00, 0x00, 0x0a, 0x83, 0xc2, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00,
|
||||||
0x17, 0x03, 0x00, 0x00, 0x13, 0x03, 0xc3, 0xfd, 0xb3, 0x82, 0x62, 0x00,
|
0x17, 0x03, 0x00, 0x00, 0x13, 0x03, 0xc3, 0xfd, 0xb3, 0x82, 0x62, 0x00,
|
||||||
0x67, 0x80, 0x02, 0x00, 0x03, 0xc3, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00,
|
0x67, 0x80, 0x02, 0x00, 0x03, 0xc3, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00,
|
||||||
0x83, 0x22, 0x85, 0x04, 0xe3, 0xce, 0x02, 0xfe, 0x83, 0xc2, 0x05, 0x00,
|
0x83, 0x22, 0x85, 0x04, 0xe3, 0xce, 0x02, 0xfe, 0x83, 0xc2, 0x05, 0x00,
|
||||||
0x23, 0x24, 0x55, 0x04, 0x93, 0x85, 0x15, 0x00, 0x13, 0x03, 0xf3, 0xff,
|
0x23, 0x24, 0x55, 0x04, 0x93, 0x85, 0x15, 0x00, 0x13, 0x03, 0xf3, 0xff,
|
||||||
0xe3, 0x44, 0x60, 0xfe, 0x6f, 0xf0, 0x5f, 0xfc, 0x83, 0x22, 0x45, 0x07,
|
0xe3, 0x44, 0x60, 0xfe, 0x6f, 0xf0, 0x5f, 0xfc, 0x83, 0x22, 0x45, 0x07,
|
||||||
0x93, 0xf2, 0x12, 0x00, 0xe3, 0x8c, 0x02, 0xfe, 0x6f, 0xf0, 0x5f, 0xfb,
|
0x93, 0xf2, 0x12, 0x00, 0xe3, 0x8c, 0x02, 0xfe, 0x6f, 0xf0, 0x5f, 0xfb,
|
||||||
0x83, 0xc2, 0x05, 0x00, 0xb3, 0x82, 0xa2, 0x00, 0x03, 0xc3, 0x15, 0x00,
|
0x83, 0xc2, 0x05, 0x00, 0xb3, 0x82, 0xa2, 0x00, 0x03, 0xc3, 0x15, 0x00,
|
||||||
0x93, 0x85, 0x25, 0x00, 0x23, 0xa0, 0x62, 0x00, 0x6f, 0xf0, 0xdf, 0xf9,
|
0x93, 0x85, 0x25, 0x00, 0x23, 0xa0, 0x62, 0x00, 0x6f, 0xf0, 0xdf, 0xf9,
|
||||||
0x13, 0x06, 0x50, 0x00, 0xef, 0x00, 0x80, 0x01, 0x13, 0x06, 0x00, 0x00,
|
0x13, 0x06, 0x50, 0x00, 0xef, 0x00, 0x80, 0x01, 0x13, 0x06, 0x00, 0x00,
|
||||||
0xef, 0x00, 0x00, 0x01, 0x93, 0x72, 0x16, 0x00, 0xe3, 0x9a, 0x02, 0xfe,
|
0xef, 0x00, 0x00, 0x01, 0x93, 0x72, 0x16, 0x00, 0xe3, 0x9a, 0x02, 0xfe,
|
||||||
0x6f, 0xf0, 0x1f, 0xf8, 0x83, 0x22, 0x85, 0x04, 0xe3, 0xce, 0x02, 0xfe,
|
0x6f, 0xf0, 0x1f, 0xf8, 0x83, 0x22, 0x85, 0x04, 0xe3, 0xce, 0x02, 0xfe,
|
||||||
0x23, 0x24, 0xc5, 0x04, 0x03, 0x26, 0xc5, 0x04, 0xe3, 0x4e, 0x06, 0xfe,
|
0x23, 0x24, 0xc5, 0x04, 0x03, 0x26, 0xc5, 0x04, 0xe3, 0x4e, 0x06, 0xfe,
|
||||||
0x67, 0x80, 0x00, 0x00, 0x83, 0x22, 0x05, 0x04, 0x13, 0x03, 0x70, 0xff,
|
0x67, 0x80, 0x00, 0x00, 0x83, 0x22, 0x05, 0x04, 0x13, 0x03, 0x70, 0xff,
|
||||||
0xb3, 0xf2, 0x62, 0x00, 0x03, 0xc3, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00,
|
0xb3, 0xf2, 0x62, 0x00, 0x03, 0xc3, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00,
|
||||||
0xb3, 0xe2, 0x62, 0x00, 0x23, 0x20, 0x55, 0x04, 0x6f, 0xf0, 0x9f, 0xf4
|
0xb3, 0xe2, 0x62, 0x00, 0x23, 0x20, 0x55, 0x04, 0x6f, 0xf0, 0x9f, 0xf4
|
||||||
};
|
};
|
||||||
#define STEP_EXIT 4
|
#define STEP_EXIT 4
|
||||||
#define STEP_TX 8
|
#define STEP_TX 8
|
||||||
|
@ -625,7 +633,7 @@ static int as_empty(struct algorithm_steps *as)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return size of compiled program.
|
/* Return size of compiled program. */
|
||||||
static unsigned as_compile(struct algorithm_steps *as, uint8_t *target,
|
static unsigned as_compile(struct algorithm_steps *as, uint8_t *target,
|
||||||
unsigned target_size)
|
unsigned target_size)
|
||||||
{
|
{
|
||||||
|
@ -684,9 +692,8 @@ static unsigned as_compile(struct algorithm_steps *as, uint8_t *target,
|
||||||
LOG_DEBUG("%d-byte program:", offset);
|
LOG_DEBUG("%d-byte program:", offset);
|
||||||
for (unsigned i = 0; i < offset;) {
|
for (unsigned i = 0; i < offset;) {
|
||||||
char buf[80];
|
char buf[80];
|
||||||
for (unsigned x = 0; i < offset && x < 16; x++, i++) {
|
for (unsigned x = 0; i < offset && x < 16; x++, i++)
|
||||||
sprintf(buf + x*3, "%02x ", target[i]);
|
sprintf(buf + x*3, "%02x ", target[i]);
|
||||||
}
|
|
||||||
LOG_DEBUG("%s", buf);
|
LOG_DEBUG("%s", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,7 +778,7 @@ static int steps_add_buffer_write(struct algorithm_steps *as,
|
||||||
as_add_txwm_wait(as);
|
as_add_txwm_wait(as);
|
||||||
as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
|
as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
|
||||||
|
|
||||||
// fespi_wip()
|
/* fespi_wip() */
|
||||||
as_add_set_dir(as, FESPI_DIR_RX);
|
as_add_set_dir(as, FESPI_DIR_RX);
|
||||||
as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
|
as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
|
||||||
as_add_wip_wait(as);
|
as_add_wip_wait(as);
|
||||||
|
@ -908,11 +915,10 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
cur_count = 4 - (offset & 3);
|
cur_count = 4 - (offset & 3);
|
||||||
if (cur_count > count)
|
if (cur_count > count)
|
||||||
cur_count = count;
|
cur_count = count;
|
||||||
if (algorithm_wa) {
|
if (algorithm_wa)
|
||||||
retval = steps_add_buffer_write(as, buffer, offset, cur_count);
|
retval = steps_add_buffer_write(as, buffer, offset, cur_count);
|
||||||
} else {
|
else
|
||||||
retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count);
|
retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count);
|
||||||
}
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto err;
|
goto err;
|
||||||
offset += cur_count;
|
offset += cur_count;
|
||||||
|
@ -929,11 +935,10 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
else
|
else
|
||||||
cur_count = count & ~3;
|
cur_count = count & ~3;
|
||||||
|
|
||||||
if (algorithm_wa) {
|
if (algorithm_wa)
|
||||||
retval = steps_add_buffer_write(as, buffer, offset, cur_count);
|
retval = steps_add_buffer_write(as, buffer, offset, cur_count);
|
||||||
} else {
|
else
|
||||||
retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count);
|
retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count);
|
||||||
}
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -945,18 +950,16 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
|
|
||||||
/* buffer tail */
|
/* buffer tail */
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
if (algorithm_wa) {
|
if (algorithm_wa)
|
||||||
retval = steps_add_buffer_write(as, buffer, offset, count);
|
retval = steps_add_buffer_write(as, buffer, offset, count);
|
||||||
} else {
|
else
|
||||||
retval = slow_fespi_write_buffer(bank, buffer, offset, count);
|
retval = slow_fespi_write_buffer(bank, buffer, offset, count);
|
||||||
}
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (algorithm_wa) {
|
if (algorithm_wa)
|
||||||
retval = steps_execute(as, bank, algorithm_wa, data_wa);
|
retval = steps_execute(as, bank, algorithm_wa, data_wa);
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (algorithm_wa) {
|
if (algorithm_wa) {
|
||||||
|
@ -1043,27 +1046,27 @@ static int fespi_probe(struct flash_bank *bank)
|
||||||
fespi_info->probed = 0;
|
fespi_info->probed = 0;
|
||||||
|
|
||||||
if (fespi_info->ctrl_base == 0) {
|
if (fespi_info->ctrl_base == 0) {
|
||||||
for (target_device = target_devices ; target_device->name ; ++target_device)
|
for (target_device = target_devices ; target_device->name ; ++target_device)
|
||||||
if (target_device->tap_idcode == target->tap->idcode)
|
if (target_device->tap_idcode == target->tap->idcode)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!target_device->name) {
|
if (!target_device->name) {
|
||||||
LOG_ERROR("Device ID 0x%" PRIx32 " is not known as FESPI capable",
|
LOG_ERROR("Device ID 0x%" PRIx32 " is not known as FESPI capable",
|
||||||
target->tap->idcode);
|
target->tap->idcode);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fespi_info->ctrl_base = target_device->ctrl_base;
|
fespi_info->ctrl_base = target_device->ctrl_base;
|
||||||
|
|
||||||
LOG_DEBUG("Valid FESPI on device %s at address 0x%" PRIx32,
|
LOG_DEBUG("Valid FESPI on device %s at address 0x%" PRIx32,
|
||||||
target_device->name, bank->base);
|
target_device->name, bank->base);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG("Assuming FESPI as specified at address 0x%x with ctrl at 0x%x",
|
LOG_DEBUG("Assuming FESPI as specified at address 0x%x with ctrl at 0x%x",
|
||||||
fespi_info->ctrl_base,
|
fespi_info->ctrl_base,
|
||||||
bank->base);
|
bank->base);
|
||||||
}
|
}
|
||||||
ctrl_base = fespi_info->ctrl_base;
|
ctrl_base = fespi_info->ctrl_base;
|
||||||
|
|
||||||
/* read and decode flash ID; returns in SW mode */
|
/* read and decode flash ID; returns in SW mode */
|
||||||
FESPI_WRITE_REG(FESPI_REG_TXCTRL, FESPI_TXWM(1));
|
FESPI_WRITE_REG(FESPI_REG_TXCTRL, FESPI_TXWM(1));
|
||||||
|
|
|
@ -76,10 +76,8 @@ static void remote_bitbang_fill_buf(void)
|
||||||
contiguous_available_space);
|
contiguous_available_space);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
remote_bitbang_end += count;
|
remote_bitbang_end += count;
|
||||||
// TODO: check for overflow.
|
if (remote_bitbang_end == sizeof(remote_bitbang_buf))
|
||||||
if (remote_bitbang_end == sizeof(remote_bitbang_buf)) {
|
|
||||||
remote_bitbang_end = 0;
|
remote_bitbang_end = 0;
|
||||||
}
|
|
||||||
} else if (count == 0) {
|
} else if (count == 0) {
|
||||||
return;
|
return;
|
||||||
} else if (count < 0) {
|
} else if (count < 0) {
|
||||||
|
@ -171,7 +169,7 @@ static int remote_bitbang_read_sample(void)
|
||||||
{
|
{
|
||||||
if (remote_bitbang_start != remote_bitbang_end) {
|
if (remote_bitbang_start != remote_bitbang_end) {
|
||||||
int c = remote_bitbang_buf[remote_bitbang_start];
|
int c = remote_bitbang_buf[remote_bitbang_start];
|
||||||
remote_bitbang_start =
|
remote_bitbang_start =
|
||||||
(remote_bitbang_start + 1) % sizeof(remote_bitbang_buf);
|
(remote_bitbang_start + 1) % sizeof(remote_bitbang_buf);
|
||||||
return char_to_int(c);
|
return char_to_int(c);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ static int riscv_gdb_thread_packet(struct connection *connection, const char *pa
|
||||||
if (strncmp(packet, "qfThreadInfo", 12) == 0) {
|
if (strncmp(packet, "qfThreadInfo", 12) == 0) {
|
||||||
riscv_update_threads(target->rtos);
|
riscv_update_threads(target->rtos);
|
||||||
r->qs_thread_info_offset = 1;
|
r->qs_thread_info_offset = 1;
|
||||||
|
|
||||||
char m[16];
|
char m[16];
|
||||||
snprintf(m, 16, "m%08x", (int)rtos->thread_details[0].threadid);
|
snprintf(m, 16, "m%08x", (int)rtos->thread_details[0].threadid);
|
||||||
gdb_put_packet(connection, m, strlen(m));
|
gdb_put_packet(connection, m, strlen(m));
|
||||||
|
@ -305,8 +305,7 @@ static int riscv_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct rtos_type riscv_rtos =
|
const struct rtos_type riscv_rtos = {
|
||||||
{
|
|
||||||
.name = "riscv",
|
.name = "riscv",
|
||||||
.detect_rtos = riscv_detect_rtos,
|
.detect_rtos = riscv_detect_rtos,
|
||||||
.create = riscv_create_rtos,
|
.create = riscv_create_rtos,
|
||||||
|
|
|
@ -1286,10 +1286,10 @@ static int gdb_get_register_packet(struct connection *connection,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reg_list[reg_num]->valid) {
|
if (!reg_list[reg_num]->valid) {
|
||||||
retval = reg_list[reg_num]->type->get(reg_list[reg_num]);
|
retval = reg_list[reg_num]->type->get(reg_list[reg_num]);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name);
|
LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name);
|
||||||
free (reg_list);
|
free(reg_list);
|
||||||
return gdb_error(connection, retval);
|
return gdb_error(connection, retval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1347,7 +1347,7 @@ static int gdb_set_register_packet(struct connection *connection,
|
||||||
gdb_target_to_reg(target, separator + 1, chars, bin_buf);
|
gdb_target_to_reg(target, separator + 1, chars, bin_buf);
|
||||||
|
|
||||||
retval = reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf);
|
retval = reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf);
|
||||||
if (retval != ERROR_OK){
|
if (retval != ERROR_OK) {
|
||||||
LOG_DEBUG("Couldn't set register %s.", reg_list[reg_num]->name);
|
LOG_DEBUG("Couldn't set register %s.", reg_list[reg_num]->name);
|
||||||
free(bin_buf);
|
free(bin_buf);
|
||||||
free(reg_list);
|
free(reg_list);
|
||||||
|
|
|
@ -17,7 +17,7 @@ static uint32_t load(const struct target *target, unsigned int rd,
|
||||||
return ld(rd, base, offset);
|
return ld(rd, base, offset);
|
||||||
}
|
}
|
||||||
assert(0);
|
assert(0);
|
||||||
return 0; // Silence -Werror=return-type
|
return 0; /* Silence -Werror=return-type */
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t store(const struct target *target, unsigned int src,
|
static uint32_t store(const struct target *target, unsigned int src,
|
||||||
|
@ -32,7 +32,7 @@ static uint32_t store(const struct target *target, unsigned int src,
|
||||||
return sd(src, base, offset);
|
return sd(src, base, offset);
|
||||||
}
|
}
|
||||||
assert(0);
|
assert(0);
|
||||||
return 0; // Silence -Werror=return-type
|
return 0; /* Silence -Werror=return-type */
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -138,8 +138,8 @@ void riscv_batch_add_nop(struct riscv_batch *batch)
|
||||||
|
|
||||||
void dump_field(const struct scan_field *field)
|
void dump_field(const struct scan_field *field)
|
||||||
{
|
{
|
||||||
static const char *op_string[] = {"-", "r", "w", "?"};
|
static const char * const op_string[] = {"-", "r", "w", "?"};
|
||||||
static const char *status_string[] = {"+", "?", "F", "b"};
|
static const char * const status_string[] = {"+", "?", "F", "b"};
|
||||||
|
|
||||||
if (debug_level < LOG_LVL_DEBUG)
|
if (debug_level < LOG_LVL_DEBUG)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -295,7 +295,7 @@
|
||||||
*
|
*
|
||||||
* Other values are reserved for future use.
|
* Other values are reserved for future use.
|
||||||
*/
|
*/
|
||||||
#define CSR_TDATA1_TYPE_OFFSET XLEN-4
|
#define CSR_TDATA1_TYPE_OFFSET (XLEN-4)
|
||||||
#define CSR_TDATA1_TYPE_LENGTH 4
|
#define CSR_TDATA1_TYPE_LENGTH 4
|
||||||
#define CSR_TDATA1_TYPE (0xfULL << CSR_TDATA1_TYPE_OFFSET)
|
#define CSR_TDATA1_TYPE (0xfULL << CSR_TDATA1_TYPE_OFFSET)
|
||||||
/*
|
/*
|
||||||
|
@ -307,14 +307,14 @@
|
||||||
*
|
*
|
||||||
* This bit is only writable from Debug Mode.
|
* This bit is only writable from Debug Mode.
|
||||||
*/
|
*/
|
||||||
#define CSR_TDATA1_DMODE_OFFSET XLEN-5
|
#define CSR_TDATA1_DMODE_OFFSET (XLEN-5)
|
||||||
#define CSR_TDATA1_DMODE_LENGTH 1
|
#define CSR_TDATA1_DMODE_LENGTH 1
|
||||||
#define CSR_TDATA1_DMODE (0x1ULL << CSR_TDATA1_DMODE_OFFSET)
|
#define CSR_TDATA1_DMODE (0x1ULL << CSR_TDATA1_DMODE_OFFSET)
|
||||||
/*
|
/*
|
||||||
* Trigger-specific data.
|
* Trigger-specific data.
|
||||||
*/
|
*/
|
||||||
#define CSR_TDATA1_DATA_OFFSET 0
|
#define CSR_TDATA1_DATA_OFFSET 0
|
||||||
#define CSR_TDATA1_DATA_LENGTH XLEN - 5
|
#define CSR_TDATA1_DATA_LENGTH (XLEN - 5)
|
||||||
#define CSR_TDATA1_DATA (((1L<<XLEN - 5)-1) << CSR_TDATA1_DATA_OFFSET)
|
#define CSR_TDATA1_DATA (((1L<<XLEN - 5)-1) << CSR_TDATA1_DATA_OFFSET)
|
||||||
#define CSR_TDATA2 0x7a2
|
#define CSR_TDATA2 0x7a2
|
||||||
#define CSR_TDATA2_DATA_OFFSET 0
|
#define CSR_TDATA2_DATA_OFFSET 0
|
||||||
|
@ -325,10 +325,10 @@
|
||||||
#define CSR_TDATA3_DATA_LENGTH XLEN
|
#define CSR_TDATA3_DATA_LENGTH XLEN
|
||||||
#define CSR_TDATA3_DATA (((1L<<XLEN)-1) << CSR_TDATA3_DATA_OFFSET)
|
#define CSR_TDATA3_DATA (((1L<<XLEN)-1) << CSR_TDATA3_DATA_OFFSET)
|
||||||
#define CSR_MCONTROL 0x7a1
|
#define CSR_MCONTROL 0x7a1
|
||||||
#define CSR_MCONTROL_TYPE_OFFSET XLEN-4
|
#define CSR_MCONTROL_TYPE_OFFSET (XLEN-4)
|
||||||
#define CSR_MCONTROL_TYPE_LENGTH 4
|
#define CSR_MCONTROL_TYPE_LENGTH 4
|
||||||
#define CSR_MCONTROL_TYPE (0xfULL << CSR_MCONTROL_TYPE_OFFSET)
|
#define CSR_MCONTROL_TYPE (0xfULL << CSR_MCONTROL_TYPE_OFFSET)
|
||||||
#define CSR_MCONTROL_DMODE_OFFSET XLEN-5
|
#define CSR_MCONTROL_DMODE_OFFSET (XLEN-5)
|
||||||
#define CSR_MCONTROL_DMODE_LENGTH 1
|
#define CSR_MCONTROL_DMODE_LENGTH 1
|
||||||
#define CSR_MCONTROL_DMODE (0x1ULL << CSR_MCONTROL_DMODE_OFFSET)
|
#define CSR_MCONTROL_DMODE (0x1ULL << CSR_MCONTROL_DMODE_OFFSET)
|
||||||
/*
|
/*
|
||||||
|
@ -339,7 +339,7 @@
|
||||||
* corresponds to the maximum NAPOT range, which is $2^{63}$ bytes in
|
* corresponds to the maximum NAPOT range, which is $2^{63}$ bytes in
|
||||||
* size.
|
* size.
|
||||||
*/
|
*/
|
||||||
#define CSR_MCONTROL_MASKMAX_OFFSET XLEN-11
|
#define CSR_MCONTROL_MASKMAX_OFFSET (XLEN-11)
|
||||||
#define CSR_MCONTROL_MASKMAX_LENGTH 6
|
#define CSR_MCONTROL_MASKMAX_LENGTH 6
|
||||||
#define CSR_MCONTROL_MASKMAX (0x3fULL << CSR_MCONTROL_MASKMAX_OFFSET)
|
#define CSR_MCONTROL_MASKMAX (0x3fULL << CSR_MCONTROL_MASKMAX_OFFSET)
|
||||||
/*
|
/*
|
||||||
|
@ -478,10 +478,10 @@
|
||||||
#define CSR_MCONTROL_LOAD_LENGTH 1
|
#define CSR_MCONTROL_LOAD_LENGTH 1
|
||||||
#define CSR_MCONTROL_LOAD (0x1ULL << CSR_MCONTROL_LOAD_OFFSET)
|
#define CSR_MCONTROL_LOAD (0x1ULL << CSR_MCONTROL_LOAD_OFFSET)
|
||||||
#define CSR_ICOUNT 0x7a1
|
#define CSR_ICOUNT 0x7a1
|
||||||
#define CSR_ICOUNT_TYPE_OFFSET XLEN-4
|
#define CSR_ICOUNT_TYPE_OFFSET (XLEN-4)
|
||||||
#define CSR_ICOUNT_TYPE_LENGTH 4
|
#define CSR_ICOUNT_TYPE_LENGTH 4
|
||||||
#define CSR_ICOUNT_TYPE (0xfULL << CSR_ICOUNT_TYPE_OFFSET)
|
#define CSR_ICOUNT_TYPE (0xfULL << CSR_ICOUNT_TYPE_OFFSET)
|
||||||
#define CSR_ICOUNT_DMODE_OFFSET XLEN-5
|
#define CSR_ICOUNT_DMODE_OFFSET (XLEN-5)
|
||||||
#define CSR_ICOUNT_DMODE_LENGTH 1
|
#define CSR_ICOUNT_DMODE_LENGTH 1
|
||||||
#define CSR_ICOUNT_DMODE (0x1ULL << CSR_ICOUNT_DMODE_OFFSET)
|
#define CSR_ICOUNT_DMODE (0x1ULL << CSR_ICOUNT_DMODE_OFFSET)
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#ifndef TARGET__RISCV__GDB_REGS_H
|
#ifndef TARGET__RISCV__GDB_REGS_H
|
||||||
#define TARGET__RISCV__GDB_REGS_H
|
#define TARGET__RISCV__GDB_REGS_H
|
||||||
|
|
||||||
// gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in
|
/* gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in
|
||||||
// its source tree. We must interpret the numbers the same here.
|
* its source tree. We must interpret the numbers the same here. */
|
||||||
enum gdb_regno {
|
enum gdb_regno {
|
||||||
GDB_REGNO_ZERO = 0, /* Read-only register, always 0. */
|
GDB_REGNO_ZERO = 0, /* Read-only register, always 0. */
|
||||||
GDB_REGNO_RA = 1, /* Return Address. */
|
GDB_REGNO_RA = 1, /* Return Address. */
|
||||||
|
|
|
@ -5,16 +5,19 @@
|
||||||
#define S0 8
|
#define S0 8
|
||||||
#define S1 9
|
#define S1 9
|
||||||
|
|
||||||
static uint32_t bits(uint32_t value, unsigned int hi, unsigned int lo) {
|
static uint32_t bits(uint32_t value, unsigned int hi, unsigned int lo)
|
||||||
|
{
|
||||||
return (value >> lo) & ((1 << (hi+1-lo)) - 1);
|
return (value >> lo) & ((1 << (hi+1-lo)) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t bit(uint32_t value, unsigned int b) {
|
static uint32_t bit(uint32_t value, unsigned int b)
|
||||||
|
{
|
||||||
return (value >> b) & 1;
|
return (value >> b) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused));
|
static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused));
|
||||||
static uint32_t jal(unsigned int rd, uint32_t imm) {
|
static uint32_t jal(unsigned int rd, uint32_t imm)
|
||||||
|
{
|
||||||
return (bit(imm, 20) << 31) |
|
return (bit(imm, 20) << 31) |
|
||||||
(bits(imm, 10, 1) << 21) |
|
(bits(imm, 10, 1) << 21) |
|
||||||
(bit(imm, 11) << 20) |
|
(bit(imm, 11) << 20) |
|
||||||
|
@ -24,7 +27,8 @@ static uint32_t jal(unsigned int rd, uint32_t imm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused));
|
static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused));
|
||||||
static uint32_t csrsi(unsigned int csr, uint16_t imm) {
|
static uint32_t csrsi(unsigned int csr, uint16_t imm)
|
||||||
|
{
|
||||||
return (csr << 20) |
|
return (csr << 20) |
|
||||||
(bits(imm, 4, 0) << 15) |
|
(bits(imm, 4, 0) << 15) |
|
||||||
MATCH_CSRRSI;
|
MATCH_CSRRSI;
|
||||||
|
@ -107,7 +111,8 @@ static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused));
|
static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused));
|
||||||
static uint32_t csrw(unsigned int source, unsigned int csr) {
|
static uint32_t csrw(unsigned int source, unsigned int csr)
|
||||||
|
{
|
||||||
return (csr << 20) | (source << 15) | MATCH_CSRRW;
|
return (csr << 20) | (source << 15) | MATCH_CSRRW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,17 +126,20 @@ static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm)
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused));
|
static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused));
|
||||||
static uint32_t csrr(unsigned int rd, unsigned int csr) {
|
static uint32_t csrr(unsigned int rd, unsigned int csr)
|
||||||
|
{
|
||||||
return (csr << 20) | (rd << 7) | MATCH_CSRRS;
|
return (csr << 20) | (rd << 7) | MATCH_CSRRS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
|
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
|
||||||
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) {
|
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr)
|
||||||
|
{
|
||||||
return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRS;
|
return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
|
static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
|
||||||
static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) {
|
static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr)
|
||||||
|
{
|
||||||
return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRW;
|
return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,9 +214,15 @@ static uint32_t fmv_d_x(unsigned dest, unsigned src)
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t ebreak(void) __attribute__ ((unused));
|
static uint32_t ebreak(void) __attribute__ ((unused));
|
||||||
static uint32_t ebreak(void) { return MATCH_EBREAK; }
|
static uint32_t ebreak(void)
|
||||||
|
{
|
||||||
|
return MATCH_EBREAK;
|
||||||
|
}
|
||||||
static uint32_t ebreak_c(void) __attribute__ ((unused));
|
static uint32_t ebreak_c(void) __attribute__ ((unused));
|
||||||
static uint32_t ebreak_c(void) { return MATCH_C_EBREAK; }
|
static uint32_t ebreak_c(void)
|
||||||
|
{
|
||||||
|
return MATCH_C_EBREAK;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t fence_i(void) __attribute__ ((unused));
|
static uint32_t fence_i(void) __attribute__ ((unused));
|
||||||
static uint32_t fence_i(void)
|
static uint32_t fence_i(void)
|
||||||
|
@ -226,7 +240,8 @@ static uint32_t lui(unsigned int dest, uint32_t imm)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused));
|
static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused));
|
||||||
static uint32_t csrci(unsigned int csr, uint16_t imm) {
|
static uint32_t csrci(unsigned int csr, uint16_t imm)
|
||||||
|
{
|
||||||
return (csr << 20) |
|
return (csr << 20) |
|
||||||
(bits(imm, 4, 0) << 15) |
|
(bits(imm, 4, 0) << 15) |
|
||||||
MATCH_CSRRCI;
|
MATCH_CSRRCI;
|
||||||
|
|
|
@ -18,11 +18,10 @@ int riscv_program_init(struct riscv_program *p, struct target *target)
|
||||||
p->target = target;
|
p->target = target;
|
||||||
p->instruction_count = 0;
|
p->instruction_count = 0;
|
||||||
p->target_xlen = riscv_xlen(target);
|
p->target_xlen = riscv_xlen(target);
|
||||||
for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) {
|
for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i)
|
||||||
p->writes_xreg[i] = 0;
|
p->writes_xreg[i] = 0;
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i)
|
for (size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i)
|
||||||
p->debug_buffer[i] = -1;
|
p->debug_buffer[i] = -1;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -54,7 +53,7 @@ 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]);
|
||||||
abort();
|
abort();
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -150,20 +150,20 @@ typedef struct {
|
||||||
/* We only need the address so that we know the alignment of the buffer. */
|
/* We only need the address so that we know the alignment of the buffer. */
|
||||||
riscv_addr_t progbuf_address;
|
riscv_addr_t progbuf_address;
|
||||||
|
|
||||||
// Number of run-test/idle cycles the target requests we do after each dbus
|
/* Number of run-test/idle cycles the target requests we do after each dbus
|
||||||
// access.
|
* access. */
|
||||||
unsigned int dtmcontrol_idle;
|
unsigned int dtmcontrol_idle;
|
||||||
|
|
||||||
// This value is incremented every time a dbus access comes back as "busy".
|
/* This value is incremented every time a dbus access comes back as "busy".
|
||||||
// It's used to determine how many run-test/idle cycles to feed the target
|
* It's used to determine how many run-test/idle cycles to feed the target
|
||||||
// in between accesses.
|
* in between accesses. */
|
||||||
unsigned int dmi_busy_delay;
|
unsigned int dmi_busy_delay;
|
||||||
|
|
||||||
// This value is increased every time we tried to execute two commands
|
/* This value is increased every time we tried to execute two commands
|
||||||
// consecutively, and the second one failed because the previous hadn't
|
* consecutively, and the second one failed because the previous hadn't
|
||||||
// completed yet. It's used to add extra run-test/idle cycles after
|
* completed yet. It's used to add extra run-test/idle cycles after
|
||||||
// starting a command, so we don't have to waste time checking for busy to
|
* starting a command, so we don't have to waste time checking for busy to
|
||||||
// go low.
|
* go low. */
|
||||||
unsigned int ac_busy_delay;
|
unsigned int ac_busy_delay;
|
||||||
|
|
||||||
bool need_strict_step;
|
bool need_strict_step;
|
||||||
|
@ -173,12 +173,12 @@ typedef struct {
|
||||||
bool abstract_read_fpr_supported;
|
bool abstract_read_fpr_supported;
|
||||||
bool abstract_write_fpr_supported;
|
bool abstract_write_fpr_supported;
|
||||||
|
|
||||||
// When a function returns some error due to a failure indicated by the
|
/* When a function returns some error due to a failure indicated by the
|
||||||
// target in cmderr, the caller can look here to see what that error was.
|
* target in cmderr, the caller can look here to see what that error was.
|
||||||
// (Compare with errno.)
|
* (Compare with errno.) */
|
||||||
uint8_t cmderr;
|
uint8_t cmderr;
|
||||||
|
|
||||||
// Some fields from hartinfo.
|
/* Some fields from hartinfo. */
|
||||||
uint8_t datasize;
|
uint8_t datasize;
|
||||||
uint8_t dataaccess;
|
uint8_t dataaccess;
|
||||||
int16_t dataaddr;
|
int16_t dataaddr;
|
||||||
|
@ -232,7 +232,7 @@ static void decode_dmi(char *text, unsigned address, unsigned data)
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
*(text++) = ' ';
|
*(text++) = ' ';
|
||||||
if (mask & (mask >> 1)) {
|
if (mask & (mask >> 1)) {
|
||||||
// If the field is more than 1 bit wide.
|
/* If the field is more than 1 bit wide. */
|
||||||
sprintf(text, "%s=%d", description[i].name, value);
|
sprintf(text, "%s=%d", description[i].name, value);
|
||||||
} else {
|
} else {
|
||||||
strcpy(text, description[i].name);
|
strcpy(text, description[i].name);
|
||||||
|
@ -245,8 +245,8 @@ static void decode_dmi(char *text, unsigned address, unsigned data)
|
||||||
|
|
||||||
static void dump_field(const struct scan_field *field)
|
static void dump_field(const struct scan_field *field)
|
||||||
{
|
{
|
||||||
static const char *op_string[] = {"-", "r", "w", "?"};
|
static const char * const op_string[] = {"-", "r", "w", "?"};
|
||||||
static const char *status_string[] = {"+", "?", "F", "b"};
|
static const char * const status_string[] = {"+", "?", "F", "b"};
|
||||||
|
|
||||||
if (debug_level < LOG_LVL_DEBUG)
|
if (debug_level < LOG_LVL_DEBUG)
|
||||||
return;
|
return;
|
||||||
|
@ -371,9 +371,8 @@ static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in,
|
||||||
if (exec)
|
if (exec)
|
||||||
idle_count += info->ac_busy_delay;
|
idle_count += info->ac_busy_delay;
|
||||||
|
|
||||||
if (idle_count) {
|
if (idle_count)
|
||||||
jtag_add_runtest(idle_count, TAP_IDLE);
|
jtag_add_runtest(idle_count, TAP_IDLE);
|
||||||
}
|
|
||||||
|
|
||||||
int retval = jtag_execute_queue();
|
int retval = jtag_execute_queue();
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
@ -381,13 +380,11 @@ static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in,
|
||||||
return DMI_STATUS_FAILED;
|
return DMI_STATUS_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_in) {
|
if (data_in)
|
||||||
*data_in = buf_get_u64(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
|
*data_in = buf_get_u64(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
|
||||||
}
|
|
||||||
|
|
||||||
if (address_in) {
|
if (address_in)
|
||||||
*address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits);
|
*address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits);
|
||||||
}
|
|
||||||
|
|
||||||
dump_field(&field);
|
dump_field(&field);
|
||||||
|
|
||||||
|
@ -403,9 +400,9 @@ static uint64_t dmi_read(struct target *target, uint16_t address)
|
||||||
|
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
|
|
||||||
// This first loop ensures that the read request was actually sent
|
/* This first loop ensures that the read request was actually sent
|
||||||
// to the target. Note that if for some reason this stays busy,
|
* to the target. Note that if for some reason this stays busy,
|
||||||
// it is actually due to the previous dmi_read or dmi_write.
|
* it is actually due to the previous dmi_read or dmi_write. */
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
status = dmi_scan(target, NULL, NULL, DMI_OP_READ, address, 0,
|
status = dmi_scan(target, NULL, NULL, DMI_OP_READ, address, 0,
|
||||||
false);
|
false);
|
||||||
|
@ -424,9 +421,9 @@ static uint64_t dmi_read(struct target *target, uint16_t address)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This second loop ensures that we got the read
|
/* This second loop ensures that we got the read
|
||||||
// data back. Note that NOP can result in a 'busy' result as well, but
|
* data back. Note that NOP can result in a 'busy' result as well, but
|
||||||
// that would be noticed on the next DMI access we do.
|
* that would be noticed on the next DMI access we do. */
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
status = dmi_scan(target, &address_in, &value, DMI_OP_NOP, address, 0,
|
status = dmi_scan(target, &address_in, &value, DMI_OP_NOP, address, 0,
|
||||||
|
@ -456,7 +453,7 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value)
|
||||||
dmi_status_t status = DMI_STATUS_BUSY;
|
dmi_status_t status = DMI_STATUS_BUSY;
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
|
|
||||||
// The first loop ensures that we successfully sent the write request.
|
/* The first loop ensures that we successfully sent the write request. */
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
status = dmi_scan(target, NULL, NULL, DMI_OP_WRITE, address, value,
|
status = dmi_scan(target, NULL, NULL, DMI_OP_WRITE, address, value,
|
||||||
address == DMI_COMMAND);
|
address == DMI_COMMAND);
|
||||||
|
@ -476,8 +473,9 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The second loop isn't strictly necessary, but would ensure that
|
/* The second loop isn't strictly necessary, but would ensure that the
|
||||||
// the write is complete/ has no non-busy errors before returning from this function.
|
* write is complete/ has no non-busy errors before returning from this
|
||||||
|
* function. */
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
status = dmi_scan(target, NULL, NULL, DMI_OP_NOP, address, 0,
|
status = dmi_scan(target, NULL, NULL, DMI_OP_NOP, address, 0,
|
||||||
false);
|
false);
|
||||||
|
@ -529,9 +527,8 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs)
|
||||||
while (1) {
|
while (1) {
|
||||||
*abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
*abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
|
|
||||||
if (get_field(*abstractcs, DMI_ABSTRACTCS_BUSY) == 0) {
|
if (get_field(*abstractcs, DMI_ABSTRACTCS_BUSY) == 0)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
|
||||||
|
|
||||||
if (time(NULL) - start > riscv_command_timeout_sec) {
|
if (time(NULL) - start > riscv_command_timeout_sec) {
|
||||||
info->cmderr = get_field(*abstractcs, DMI_ABSTRACTCS_CMDERR);
|
info->cmderr = get_field(*abstractcs, DMI_ABSTRACTCS_CMDERR);
|
||||||
|
@ -551,9 +548,9 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs)
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_ERROR("Timed out after %ds waiting for busy to go low (abstractcs=0x%x). "
|
LOG_ERROR("Timed out after %ds waiting for busy to go low (abstractcs=0x%x). "
|
||||||
"Increase the timeout with riscv set_command_timeout_sec.",
|
"Increase the timeout with riscv set_command_timeout_sec.",
|
||||||
riscv_command_timeout_sec,
|
riscv_command_timeout_sec,
|
||||||
*abstractcs);
|
*abstractcs);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -574,7 +571,7 @@ static int execute_abstract_command(struct target *target, uint32_t command)
|
||||||
info->cmderr = get_field(cs, DMI_ABSTRACTCS_CMDERR);
|
info->cmderr = get_field(cs, DMI_ABSTRACTCS_CMDERR);
|
||||||
if (info->cmderr != 0) {
|
if (info->cmderr != 0) {
|
||||||
LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, cs);
|
LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, cs);
|
||||||
// Clear the error.
|
/* Clear the error. */
|
||||||
dmi_write(target, DMI_ABSTRACTCS, set_field(0, DMI_ABSTRACTCS_CMDERR,
|
dmi_write(target, DMI_ABSTRACTCS, set_field(0, DMI_ABSTRACTCS_CMDERR,
|
||||||
info->cmderr));
|
info->cmderr));
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -704,9 +701,8 @@ static int register_write_abstract(struct target *target, uint32_t number,
|
||||||
AC_ACCESS_REGISTER_TRANSFER |
|
AC_ACCESS_REGISTER_TRANSFER |
|
||||||
AC_ACCESS_REGISTER_WRITE);
|
AC_ACCESS_REGISTER_WRITE);
|
||||||
|
|
||||||
if (write_abstract_arg(target, 0, value) != ERROR_OK) {
|
if (write_abstract_arg(target, 0, value) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
int result = execute_abstract_command(target, command);
|
int result = execute_abstract_command(target, command);
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK) {
|
||||||
|
@ -732,7 +728,7 @@ static int examine_progbuf(struct target *target)
|
||||||
if (info->progbuf_writable != YNM_MAYBE)
|
if (info->progbuf_writable != YNM_MAYBE)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
// Figure out if progbuf is writable.
|
/* Figure out if progbuf is writable. */
|
||||||
|
|
||||||
if (info->progbufsize < 1) {
|
if (info->progbufsize < 1) {
|
||||||
info->progbuf_writable = YNM_NO;
|
info->progbuf_writable = YNM_NO;
|
||||||
|
@ -761,8 +757,8 @@ static int examine_progbuf(struct target *target)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK) {
|
||||||
// This program might have failed if the program buffer is not
|
/* This program might have failed if the program buffer is not
|
||||||
// writable.
|
* writable. */
|
||||||
info->progbuf_writable = YNM_NO;
|
info->progbuf_writable = YNM_NO;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -789,11 +785,11 @@ typedef enum {
|
||||||
} memory_space_t;
|
} memory_space_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// How can the debugger access this memory?
|
/* How can the debugger access this memory? */
|
||||||
memory_space_t memory_space;
|
memory_space_t memory_space;
|
||||||
// Memory address to access the scratch memory from the hart.
|
/* Memory address to access the scratch memory from the hart. */
|
||||||
riscv_addr_t hart_address;
|
riscv_addr_t hart_address;
|
||||||
// Memory address to access the scratch memory from the debugger.
|
/* Memory address to access the scratch memory from the debugger. */
|
||||||
riscv_addr_t debug_address;
|
riscv_addr_t debug_address;
|
||||||
} scratch_mem_t;
|
} scratch_mem_t;
|
||||||
|
|
||||||
|
@ -812,12 +808,11 @@ static int scratch_find(struct target *target,
|
||||||
alignment *= 2;
|
alignment *= 2;
|
||||||
|
|
||||||
if (info->dataaccess == 1) {
|
if (info->dataaccess == 1) {
|
||||||
// Sign extend dataaddr.
|
/* Sign extend dataaddr. */
|
||||||
scratch->hart_address = info->dataaddr;
|
scratch->hart_address = info->dataaddr;
|
||||||
if (info->dataaddr & (1<<11)) {
|
if (info->dataaddr & (1<<11))
|
||||||
scratch->hart_address |= 0xfffffffffffff000ULL;
|
scratch->hart_address |= 0xfffffffffffff000ULL;
|
||||||
}
|
/* Align. */
|
||||||
// Align.
|
|
||||||
scratch->hart_address = (scratch->hart_address + alignment - 1) & ~(alignment - 1);
|
scratch->hart_address = (scratch->hart_address + alignment - 1) & ~(alignment - 1);
|
||||||
|
|
||||||
if ((size_bytes + scratch->hart_address - info->dataaddr + 3) / 4 >=
|
if ((size_bytes + scratch->hart_address - info->dataaddr + 3) / 4 >=
|
||||||
|
@ -831,8 +826,8 @@ static int scratch_find(struct target *target,
|
||||||
if (examine_progbuf(target) != ERROR_OK)
|
if (examine_progbuf(target) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
// Allow for ebreak at the end of the program.
|
/* Allow for ebreak at the end of the program. */
|
||||||
unsigned program_size = (program->instruction_count + 1 ) * 4;
|
unsigned program_size = (program->instruction_count + 1) * 4;
|
||||||
scratch->hart_address = (info->progbuf_address + program_size + alignment - 1) &
|
scratch->hart_address = (info->progbuf_address + program_size + alignment - 1) &
|
||||||
~(alignment - 1);
|
~(alignment - 1);
|
||||||
if ((size_bytes + scratch->hart_address - info->progbuf_address + 3) / 4 >=
|
if ((size_bytes + scratch->hart_address - info->progbuf_address + 3) / 4 >=
|
||||||
|
@ -961,11 +956,10 @@ static int register_write_direct(struct target *target, unsigned number,
|
||||||
return ERROR_FAIL;
|
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, 'D')) {
|
if (riscv_supports_extension(target, 'D'))
|
||||||
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_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 {
|
||||||
|
@ -976,7 +970,7 @@ static int register_write_direct(struct target *target, unsigned number,
|
||||||
|
|
||||||
int exec_out = riscv_program_exec(&program, target);
|
int exec_out = riscv_program_exec(&program, target);
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
|
@ -1004,10 +998,10 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
|
||||||
if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK)
|
if (register_read_direct(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. */
|
||||||
|
|
||||||
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
||||||
// TODO: Possibly set F in mstatus.
|
/* TODO: Possibly set F in mstatus. */
|
||||||
if (riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) {
|
if (riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) {
|
||||||
/* There are no instructions to move all the bits from a
|
/* There are no instructions to move all the bits from a
|
||||||
* register, so we need to use some scratch RAM. */
|
* register, so we need to use some scratch RAM. */
|
||||||
|
@ -1033,19 +1027,19 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute program.
|
/* Execute program. */
|
||||||
result = riscv_program_exec(&program, target);
|
result = riscv_program_exec(&program, target);
|
||||||
|
|
||||||
if (use_scratch) {
|
if (use_scratch) {
|
||||||
if (scratch_read64(target, &scratch, value) != ERROR_OK)
|
if (scratch_read64(target, &scratch, value) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
} else {
|
} else {
|
||||||
// Read S0
|
/* Read S0 */
|
||||||
if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK)
|
if (register_read_direct(target, value, GDB_REGNO_S0) != 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)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -1094,11 +1088,11 @@ static int init_target(struct command_context *cmd_ctx,
|
||||||
info->dmi_busy_delay = 0;
|
info->dmi_busy_delay = 0;
|
||||||
info->ac_busy_delay = 0;
|
info->ac_busy_delay = 0;
|
||||||
|
|
||||||
// Assume all these abstract commands are supported until we learn
|
/* Assume all these abstract commands are supported until we learn
|
||||||
// otherwise.
|
* otherwise.
|
||||||
// TODO: The spec allows eg. one CSR to be able to be accessed abstractly
|
* TODO: The spec allows eg. one CSR to be able to be accessed abstractly
|
||||||
// while another one isn't. We don't track that this closely here, but in
|
* while another one isn't. We don't track that this closely here, but in
|
||||||
// the future we probably should.
|
* the future we probably should. */
|
||||||
info->abstract_read_csr_supported = true;
|
info->abstract_read_csr_supported = true;
|
||||||
info->abstract_write_csr_supported = true;
|
info->abstract_write_csr_supported = true;
|
||||||
info->abstract_read_fpr_supported = true;
|
info->abstract_read_fpr_supported = true;
|
||||||
|
@ -1117,7 +1111,7 @@ static void deinit_target(struct target *target)
|
||||||
|
|
||||||
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. */
|
||||||
|
|
||||||
uint32_t dtmcontrol = dtmcontrol_scan(target, 0);
|
uint32_t dtmcontrol = dtmcontrol_scan(target, 0);
|
||||||
LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol);
|
LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol);
|
||||||
|
@ -1147,7 +1141,7 @@ static int examine(struct target *target)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the Debug Module.
|
/* Reset the Debug Module. */
|
||||||
dmi_write(target, DMI_DMCONTROL, 0);
|
dmi_write(target, DMI_DMCONTROL, 0);
|
||||||
dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
|
dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
|
||||||
uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL);
|
uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL);
|
||||||
|
@ -1184,7 +1178,7 @@ static int examine(struct target *target)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that abstract data registers are accessible.
|
/* Check that abstract data registers are accessible. */
|
||||||
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT);
|
info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT);
|
||||||
info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE);
|
info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE);
|
||||||
|
@ -1193,8 +1187,8 @@ static int examine(struct target *target)
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK);
|
r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK);
|
||||||
|
|
||||||
// Don't call any riscv_* functions until after we've counted the number of
|
/* Don't call any riscv_* functions until after we've counted the number of
|
||||||
// cores and initialized registers.
|
* cores and initialized registers. */
|
||||||
for (int i = 0; i < RISCV_MAX_HARTS; ++i) {
|
for (int i = 0; i < RISCV_MAX_HARTS; ++i) {
|
||||||
if (!riscv_rtos_enabled(target) && i != target->coreid)
|
if (!riscv_rtos_enabled(target) && i != target->coreid)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1203,29 +1197,26 @@ static int examine(struct target *target)
|
||||||
riscv013_select_current_hart(target);
|
riscv013_select_current_hart(target);
|
||||||
|
|
||||||
uint32_t s = dmi_read(target, DMI_DMSTATUS);
|
uint32_t s = dmi_read(target, DMI_DMSTATUS);
|
||||||
if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) {
|
if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT))
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
r->hart_count = i + 1;
|
r->hart_count = i + 1;
|
||||||
|
|
||||||
if (!riscv_is_halted(target)) {
|
if (!riscv_is_halted(target))
|
||||||
riscv013_halt_current_hart(target);
|
riscv013_halt_current_hart(target);
|
||||||
}
|
|
||||||
|
|
||||||
/* Without knowing anything else we can at least mess with the
|
/* Without knowing anything else we can at least mess with the
|
||||||
* program buffer. */
|
* program buffer. */
|
||||||
r->debug_buffer_size[i] = info->progbufsize;
|
r->debug_buffer_size[i] = info->progbufsize;
|
||||||
|
|
||||||
int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64);
|
int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64);
|
||||||
if (result == ERROR_OK) {
|
if (result == ERROR_OK)
|
||||||
r->xlen[i] = 64;
|
r->xlen[i] = 64;
|
||||||
} else {
|
else
|
||||||
r->xlen[i] = 32;
|
r->xlen[i] = 32;
|
||||||
}
|
|
||||||
|
|
||||||
register_read_direct(target, &r->misa, GDB_REGNO_MISA);
|
register_read_direct(target, &r->misa, GDB_REGNO_MISA);
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
|
@ -1241,19 +1232,18 @@ static int examine(struct target *target)
|
||||||
riscv_enumerate_triggers(target);
|
riscv_enumerate_triggers(target);
|
||||||
|
|
||||||
/* Resumes all the harts, so the debugger can later pause them. */
|
/* Resumes all the harts, so the debugger can later pause them. */
|
||||||
// TODO: Only do this if the harts were halted to start with.
|
/* TODO: Only do this if the harts were halted to start with. */
|
||||||
riscv_resume_all_harts(target);
|
riscv_resume_all_harts(target);
|
||||||
target->state = TARGET_RUNNING;
|
target->state = TARGET_RUNNING;
|
||||||
|
|
||||||
target_set_examined(target);
|
target_set_examined(target);
|
||||||
|
|
||||||
if (target->rtos) {
|
if (target->rtos)
|
||||||
riscv_update_threads(target->rtos);
|
riscv_update_threads(target->rtos);
|
||||||
}
|
|
||||||
|
|
||||||
// Some regression suites rely on seeing 'Examined RISC-V core' to know
|
/* Some regression suites rely on seeing 'Examined RISC-V core' to know
|
||||||
// when they can connect with gdb/telnet.
|
* when they can connect with gdb/telnet.
|
||||||
// We will need to update those suites if we want to change that text.
|
* We will need to update those suites if we want to change that text. */
|
||||||
LOG_INFO("Examined RISC-V core; found %d harts",
|
LOG_INFO("Examined RISC-V core; found %d harts",
|
||||||
riscv_count_harts(target));
|
riscv_count_harts(target));
|
||||||
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
||||||
|
@ -1276,12 +1266,12 @@ static int assert_reset(struct target *target)
|
||||||
uint32_t control_base = set_field(0, DMI_DMCONTROL_DMACTIVE, 1);
|
uint32_t control_base = set_field(0, DMI_DMCONTROL_DMACTIVE, 1);
|
||||||
|
|
||||||
if (target->rtos) {
|
if (target->rtos) {
|
||||||
// There's only one target, and OpenOCD thinks each hart is a thread.
|
/* There's only one target, and OpenOCD thinks each hart is a thread.
|
||||||
// We must reset them all.
|
* We must reset them all. */
|
||||||
|
|
||||||
// TODO: Try to use hasel in dmcontrol
|
/* TODO: Try to use hasel in dmcontrol */
|
||||||
|
|
||||||
// Set haltreq/resumereq for each hart.
|
/* Set haltreq/resumereq for each hart. */
|
||||||
uint32_t control = control_base;
|
uint32_t control = control_base;
|
||||||
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
||||||
if (!riscv_hart_enabled(target, i))
|
if (!riscv_hart_enabled(target, i))
|
||||||
|
@ -1292,12 +1282,12 @@ static int assert_reset(struct target *target)
|
||||||
target->reset_halt ? 1 : 0);
|
target->reset_halt ? 1 : 0);
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
dmi_write(target, DMI_DMCONTROL, control);
|
||||||
}
|
}
|
||||||
// Assert ndmreset
|
/* Assert ndmreset */
|
||||||
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
|
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
dmi_write(target, DMI_DMCONTROL, control);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Reset just this hart.
|
/* Reset just this hart. */
|
||||||
uint32_t control = set_field(control_base, DMI_DMCONTROL_HARTSEL,
|
uint32_t control = set_field(control_base, DMI_DMCONTROL_HARTSEL,
|
||||||
r->current_hartid);
|
r->current_hartid);
|
||||||
control = set_field(control, DMI_DMCONTROL_HALTREQ,
|
control = set_field(control, DMI_DMCONTROL_HALTREQ,
|
||||||
|
@ -1305,11 +1295,11 @@ static int assert_reset(struct target *target)
|
||||||
control = set_field(control, DMI_DMCONTROL_HARTRESET, 1);
|
control = set_field(control, DMI_DMCONTROL_HARTRESET, 1);
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
dmi_write(target, DMI_DMCONTROL, control);
|
||||||
|
|
||||||
// Read back to check if hartreset is supported.
|
/* Read back to check if hartreset is supported. */
|
||||||
uint32_t rb = dmi_read(target, DMI_DMCONTROL);
|
uint32_t rb = dmi_read(target, DMI_DMCONTROL);
|
||||||
if (!get_field(rb, DMI_DMCONTROL_HARTRESET)) {
|
if (!get_field(rb, DMI_DMCONTROL_HARTRESET)) {
|
||||||
// Use ndmreset instead. That will reset the entire device, but
|
/* Use ndmreset instead. That will reset the entire device, but
|
||||||
// that's probably what OpenOCD wants anyway.
|
* that's probably what OpenOCD wants anyway. */
|
||||||
control = set_field(control, DMI_DMCONTROL_HARTRESET, 0);
|
control = set_field(control, DMI_DMCONTROL_HARTRESET, 0);
|
||||||
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
|
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
dmi_write(target, DMI_DMCONTROL, control);
|
||||||
|
@ -1329,7 +1319,7 @@ static int deassert_reset(struct target *target)
|
||||||
|
|
||||||
LOG_DEBUG("%d", r->current_hartid);
|
LOG_DEBUG("%d", r->current_hartid);
|
||||||
|
|
||||||
// Clear the reset, but make sure haltreq is still set
|
/* Clear the reset, but make sure haltreq is still set */
|
||||||
uint32_t control = 0;
|
uint32_t control = 0;
|
||||||
control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
|
control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
|
||||||
control = set_field(control, DMI_DMCONTROL_HARTSEL, r->current_hartid);
|
control = set_field(control, DMI_DMCONTROL_HARTSEL, r->current_hartid);
|
||||||
|
@ -1405,7 +1395,8 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int execute_fence(struct target *target) {
|
static int execute_fence(struct target *target)
|
||||||
|
{
|
||||||
struct riscv_program program;
|
struct riscv_program program;
|
||||||
riscv_program_init(&program, target);
|
riscv_program_init(&program, target);
|
||||||
riscv_program_fence(&program);
|
riscv_program_fence(&program);
|
||||||
|
@ -1441,7 +1432,7 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
if (execute_fence(target) != ERROR_OK)
|
if (execute_fence(target) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
// Write the program (load, increment)
|
/* Write the program (load, increment) */
|
||||||
struct riscv_program program;
|
struct riscv_program program;
|
||||||
riscv_program_init(&program, target);
|
riscv_program_init(&program, target);
|
||||||
switch (size) {
|
switch (size) {
|
||||||
|
@ -1464,7 +1455,7 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
riscv_program_write(&program);
|
riscv_program_write(&program);
|
||||||
|
|
||||||
// Write address to S0, and execute buffer.
|
/* Write address to S0, and execute buffer. */
|
||||||
if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK)
|
if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
uint32_t command = access_register_command(GDB_REGNO_S1, riscv_xlen(target),
|
uint32_t command = access_register_command(GDB_REGNO_S1, riscv_xlen(target),
|
||||||
|
@ -1473,27 +1464,27 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
if (execute_abstract_command(target, command) != ERROR_OK)
|
if (execute_abstract_command(target, command) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
// First read has just triggered. Result is in s1.
|
/* First read has just triggered. Result is in s1. */
|
||||||
|
|
||||||
dmi_write(target, DMI_ABSTRACTAUTO,
|
dmi_write(target, DMI_ABSTRACTAUTO,
|
||||||
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
|
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
|
||||||
|
|
||||||
// read_addr is the next address that the hart will read from, which is the
|
/* read_addr is the next address that the hart will read from, which is the
|
||||||
// value in s0.
|
* value in s0. */
|
||||||
riscv_addr_t read_addr = address + size;
|
riscv_addr_t read_addr = address + size;
|
||||||
// The next address that we need to receive data for.
|
/* The next address that we need to receive data for. */
|
||||||
riscv_addr_t receive_addr = address;
|
riscv_addr_t receive_addr = address;
|
||||||
riscv_addr_t fin_addr = address + (count * size);
|
riscv_addr_t fin_addr = address + (count * size);
|
||||||
unsigned skip = 1;
|
unsigned skip = 1;
|
||||||
while (read_addr < fin_addr) {
|
while (read_addr < fin_addr) {
|
||||||
LOG_DEBUG("read_addr=0x%" PRIx64 ", receive_addr=0x%" PRIx64
|
LOG_DEBUG("read_addr=0x%" PRIx64 ", receive_addr=0x%" PRIx64
|
||||||
", fin_addr=0x%" PRIx64, read_addr, receive_addr, fin_addr);
|
", fin_addr=0x%" PRIx64, read_addr, receive_addr, fin_addr);
|
||||||
// The pipeline looks like this:
|
/* The pipeline looks like this:
|
||||||
// memory -> s1 -> dm_data0 -> debugger
|
* memory -> s1 -> dm_data0 -> debugger
|
||||||
// It advances every time the debugger reads dmdata0.
|
* It advances every time the debugger reads dmdata0.
|
||||||
// So at any time the debugger has just read mem[s0 - 3*size],
|
* So at any time the debugger has just read mem[s0 - 3*size],
|
||||||
// dm_data0 contains mem[s0 - 2*size]
|
* dm_data0 contains mem[s0 - 2*size]
|
||||||
// s1 contains mem[s0-size]
|
* s1 contains mem[s0-size] */
|
||||||
|
|
||||||
LOG_DEBUG("creating burst to read from 0x%" TARGET_PRIxADDR
|
LOG_DEBUG("creating burst to read from 0x%" TARGET_PRIxADDR
|
||||||
" up to 0x%" TARGET_PRIxADDR, read_addr, fin_addr);
|
" up to 0x%" TARGET_PRIxADDR, read_addr, fin_addr);
|
||||||
|
@ -1512,8 +1503,8 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
|
|
||||||
riscv_batch_run(batch);
|
riscv_batch_run(batch);
|
||||||
|
|
||||||
// Wait for the target to finish performing the last abstract command,
|
/* Wait for the target to finish performing the last abstract command,
|
||||||
// and update our copy of cmderr.
|
* and update our copy of cmderr. */
|
||||||
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
|
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
|
||||||
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
|
@ -1538,7 +1529,7 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
+#include <unistd.h>
|
+#include <unistd.h>
|
||||||
+
|
+
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include "debug_module.h"
|
#include "debug_module.h"
|
||||||
@@ -398,6 +400,15 @@ bool debug_module_t::perform_abstract_command()
|
@@ -398,6 +400,15 @@ bool debug_module_t::perform_abstract_command()
|
||||||
// Since the next instruction is what we will use, just use nother NOP
|
// Since the next instruction is what we will use, just use nother NOP
|
||||||
|
@ -1562,17 +1553,17 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
|
|
||||||
dmi_write(target, DMI_ABSTRACTAUTO, 0);
|
dmi_write(target, DMI_ABSTRACTAUTO, 0);
|
||||||
|
|
||||||
// This is definitely a good version of the value that we
|
/* This is definitely a good version of the value that we
|
||||||
// attempted to read when we discovered that the target was
|
* attempted to read when we discovered that the target was
|
||||||
// busy.
|
* busy. */
|
||||||
dmi_data0 = dmi_read(target, DMI_DATA0);
|
dmi_data0 = dmi_read(target, DMI_DATA0);
|
||||||
|
|
||||||
// Clobbers DMI_DATA0.
|
/* Clobbers DMI_DATA0. */
|
||||||
if (register_read_direct(target, &next_read_addr, GDB_REGNO_S0) != ERROR_OK)
|
if (register_read_direct(target, &next_read_addr, GDB_REGNO_S0) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
// Restore the command, and execute it.
|
/* Restore the command, and execute it.
|
||||||
// Now DMI_DATA0 contains the next value just as it would if no
|
* Now DMI_DATA0 contains the next value just as it would if no
|
||||||
// error had occurred.
|
* error had occurred. */
|
||||||
dmi_write(target, DMI_COMMAND, command);
|
dmi_write(target, DMI_COMMAND, command);
|
||||||
|
|
||||||
dmi_write(target, DMI_ABSTRACTAUTO,
|
dmi_write(target, DMI_ABSTRACTAUTO,
|
||||||
|
@ -1588,11 +1579,10 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now read whatever we got out of the batch.
|
/* Now read whatever we got out of the batch. */
|
||||||
for (size_t i = 0; i < reads; i++) {
|
for (size_t i = 0; i < reads; i++) {
|
||||||
if (read_addr >= next_read_addr) {
|
if (read_addr >= next_read_addr)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
read_addr += size;
|
read_addr += size;
|
||||||
|
|
||||||
|
@ -1625,14 +1615,14 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
dmi_write(target, DMI_ABSTRACTAUTO, 0);
|
dmi_write(target, DMI_ABSTRACTAUTO, 0);
|
||||||
|
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
// Read the penultimate word.
|
/* Read the penultimate word. */
|
||||||
uint64_t value = dmi_read(target, DMI_DATA0);
|
uint64_t value = dmi_read(target, DMI_DATA0);
|
||||||
write_to_buf(buffer + receive_addr - address, value, size);
|
write_to_buf(buffer + receive_addr - address, value, size);
|
||||||
LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, receive_addr, value);
|
LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, receive_addr, value);
|
||||||
receive_addr += size;
|
receive_addr += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the last word.
|
/* Read the last word. */
|
||||||
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)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -1664,7 +1654,7 @@ static int write_memory(struct target *target, target_addr_t address,
|
||||||
if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK)
|
if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
// Write the program (store, increment)
|
/* Write the program (store, increment) */
|
||||||
struct riscv_program program;
|
struct riscv_program program;
|
||||||
riscv_program_init(&program, target);
|
riscv_program_init(&program, target);
|
||||||
|
|
||||||
|
@ -1736,12 +1726,12 @@ static int write_memory(struct target *target, target_addr_t address,
|
||||||
address + offset) != ERROR_OK)
|
address + offset) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
// Write value.
|
/* Write value. */
|
||||||
dmi_write(target, DMI_DATA0, value);
|
dmi_write(target, DMI_DATA0, value);
|
||||||
|
|
||||||
// Write and execute command that moves value into S1 and
|
/* Write and execute command that moves value into S1 and
|
||||||
// executes program buffer.
|
* executes program buffer. */
|
||||||
uint32_t command = access_register_command(GDB_REGNO_S1, 32,
|
uint32_t command = access_register_command(GDB_REGNO_S1, 32,
|
||||||
AC_ACCESS_REGISTER_POSTEXEC |
|
AC_ACCESS_REGISTER_POSTEXEC |
|
||||||
AC_ACCESS_REGISTER_TRANSFER |
|
AC_ACCESS_REGISTER_TRANSFER |
|
||||||
AC_ACCESS_REGISTER_WRITE);
|
AC_ACCESS_REGISTER_WRITE);
|
||||||
|
@ -1749,7 +1739,7 @@ static int write_memory(struct target *target, target_addr_t address,
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
// Turn on autoexec
|
/* Turn on autoexec */
|
||||||
dmi_write(target, DMI_ABSTRACTAUTO,
|
dmi_write(target, DMI_ABSTRACTAUTO,
|
||||||
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
|
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
|
||||||
|
|
||||||
|
@ -1764,9 +1754,9 @@ static int write_memory(struct target *target, target_addr_t address,
|
||||||
riscv_batch_run(batch);
|
riscv_batch_run(batch);
|
||||||
riscv_batch_free(batch);
|
riscv_batch_free(batch);
|
||||||
|
|
||||||
// Note that if the scan resulted in a Busy DMI response, it
|
/* Note that if the scan resulted in a Busy DMI response, it
|
||||||
// is this read to abstractcs that will cause the dmi_busy_delay
|
* is this read to abstractcs that will cause the dmi_busy_delay
|
||||||
// to be incremented if necessary.
|
* to be incremented if necessary. */
|
||||||
|
|
||||||
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
|
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
|
||||||
|
@ -1815,8 +1805,7 @@ static int arch_state(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct target_type riscv013_target =
|
struct target_type riscv013_target = {
|
||||||
{
|
|
||||||
.name = "riscv",
|
.name = "riscv",
|
||||||
|
|
||||||
.init_target = init_target,
|
.init_target = init_target,
|
||||||
|
@ -2102,7 +2091,7 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste
|
||||||
|
|
||||||
void riscv013_clear_abstract_error(struct target *target)
|
void riscv013_clear_abstract_error(struct target *target)
|
||||||
{
|
{
|
||||||
// Wait for busy to go away.
|
/* Wait for busy to go away. */
|
||||||
time_t start = time(NULL);
|
time_t start = time(NULL);
|
||||||
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) {
|
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) {
|
||||||
|
@ -2117,6 +2106,6 @@ void riscv013_clear_abstract_error(struct target *target)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Clear the error status.
|
/* Clear the error status. */
|
||||||
dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR);
|
dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR);
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
|
|
||||||
#define DIM(x) (sizeof(x)/sizeof(*x))
|
#define DIM(x) (sizeof(x)/sizeof(*x))
|
||||||
|
|
||||||
// Constants for legacy SiFive hardware breakpoints.
|
/* Constants for legacy SiFive hardware breakpoints. */
|
||||||
#define CSR_BPCONTROL_X (1<<0)
|
#define CSR_BPCONTROL_X (1<<0)
|
||||||
#define CSR_BPCONTROL_W (1<<1)
|
#define CSR_BPCONTROL_W (1<<1)
|
||||||
#define CSR_BPCONTROL_R (1<<2)
|
#define CSR_BPCONTROL_R (1<<2)
|
||||||
|
@ -185,8 +185,8 @@ int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC;
|
||||||
/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
|
/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
|
||||||
int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC;
|
int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC;
|
||||||
|
|
||||||
bool riscv_use_scratch_ram = false;
|
bool riscv_use_scratch_ram;
|
||||||
uint64_t riscv_scratch_ram_address = 0;
|
uint64_t riscv_scratch_ram_address;
|
||||||
|
|
||||||
/* In addition to the ones in the standard spec, we'll also expose additional
|
/* In addition to the ones in the standard spec, we'll also expose additional
|
||||||
* CSRs in this list.
|
* CSRs in this list.
|
||||||
|
@ -284,7 +284,7 @@ static void trigger_from_breakpoint(struct trigger *trigger,
|
||||||
trigger->read = false;
|
trigger->read = false;
|
||||||
trigger->write = false;
|
trigger->write = false;
|
||||||
trigger->execute = true;
|
trigger->execute = true;
|
||||||
// unique_id is unique across both breakpoints and watchpoints.
|
/* unique_id is unique across both breakpoints and watchpoints. */
|
||||||
trigger->unique_id = breakpoint->unique_id;
|
trigger->unique_id = breakpoint->unique_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@ static int maybe_add_trigger_t1(struct target *target, unsigned hartid,
|
||||||
const uint32_t bpcontrol_bpaction = 0xff << 11;
|
const uint32_t bpcontrol_bpaction = 0xff << 11;
|
||||||
|
|
||||||
if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) {
|
if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) {
|
||||||
// Trigger is already in use, presumably by user code.
|
/* Trigger is already in use, presumably by user code. */
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,8 +315,8 @@ static int maybe_add_trigger_t1(struct target *target, unsigned hartid,
|
||||||
tdata1 = set_field(tdata1, bpcontrol_s, !!(r->misa & (1 << ('S' - 'A'))));
|
tdata1 = set_field(tdata1, bpcontrol_s, !!(r->misa & (1 << ('S' - 'A'))));
|
||||||
tdata1 = set_field(tdata1, bpcontrol_h, !!(r->misa & (1 << ('H' - 'A'))));
|
tdata1 = set_field(tdata1, bpcontrol_h, !!(r->misa & (1 << ('H' - 'A'))));
|
||||||
tdata1 |= bpcontrol_m;
|
tdata1 |= bpcontrol_m;
|
||||||
tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); // exact match
|
tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */
|
||||||
tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); // cause bp exception
|
tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */
|
||||||
|
|
||||||
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, tdata1);
|
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, tdata1);
|
||||||
|
|
||||||
|
@ -342,13 +342,13 @@ static int maybe_add_trigger_t2(struct target *target, unsigned hartid,
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
|
|
||||||
// tselect is already set
|
/* tselect is already set */
|
||||||
if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) {
|
if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) {
|
||||||
// Trigger is already in use, presumably by user code.
|
/* Trigger is already in use, presumably by user code. */
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// address/data match trigger
|
/* address/data match trigger */
|
||||||
tdata1 |= MCONTROL_DMODE(riscv_xlen(target));
|
tdata1 |= MCONTROL_DMODE(riscv_xlen(target));
|
||||||
tdata1 = set_field(tdata1, MCONTROL_ACTION,
|
tdata1 = set_field(tdata1, MCONTROL_ACTION,
|
||||||
MCONTROL_ACTION_DEBUG_MODE);
|
MCONTROL_ACTION_DEBUG_MODE);
|
||||||
|
@ -390,12 +390,12 @@ static int add_trigger(struct target *target, struct trigger *trigger)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
|
|
||||||
// In RTOS mode, we need to set the same trigger in the same slot on every
|
/* In RTOS mode, we need to set the same trigger in the same slot on every
|
||||||
// hart, to keep up the illusion that each hart is a thread running on the
|
* hart, to keep up the illusion that each hart is a thread running on the
|
||||||
// same core.
|
* same core. */
|
||||||
|
|
||||||
// Otherwise, we just set the trigger on the one hart this target deals
|
/* Otherwise, we just set the trigger on the one hart this target deals
|
||||||
// with.
|
* with. */
|
||||||
|
|
||||||
riscv_reg_t tselect[RISCV_MAX_HARTS];
|
riscv_reg_t tselect[RISCV_MAX_HARTS];
|
||||||
|
|
||||||
|
@ -412,9 +412,8 @@ static int add_trigger(struct target *target, struct trigger *trigger)
|
||||||
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < r->trigger_count[first_hart]; i++) {
|
for (i = 0; i < r->trigger_count[first_hart]; i++) {
|
||||||
if (r->trigger_unique_id[i] != -1) {
|
if (r->trigger_unique_id[i] != -1)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
riscv_set_register_on_hart(target, first_hart, GDB_REGNO_TSELECT, i);
|
riscv_set_register_on_hart(target, first_hart, GDB_REGNO_TSELECT, i);
|
||||||
|
|
||||||
|
@ -425,9 +424,8 @@ static int add_trigger(struct target *target, struct trigger *trigger)
|
||||||
for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) {
|
for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) {
|
||||||
if (!riscv_hart_enabled(target, hartid))
|
if (!riscv_hart_enabled(target, hartid))
|
||||||
continue;
|
continue;
|
||||||
if (hartid > first_hart) {
|
if (hartid > first_hart)
|
||||||
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, i);
|
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, i);
|
||||||
}
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 1:
|
case 1:
|
||||||
result = maybe_add_trigger_t1(target, hartid, trigger, tdata1);
|
result = maybe_add_trigger_t1(target, hartid, trigger, tdata1);
|
||||||
|
@ -440,14 +438,12 @@ static int add_trigger(struct target *target, struct trigger *trigger)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG("Using trigger %d (type %d) for bp %d", i, type,
|
LOG_DEBUG("Using trigger %d (type %d) for bp %d", i, type,
|
||||||
trigger->unique_id);
|
trigger->unique_id);
|
||||||
|
@ -481,11 +477,10 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
int retval;
|
int retval;
|
||||||
if (breakpoint->length == 4) {
|
if (breakpoint->length == 4)
|
||||||
retval = target_write_u32(target, breakpoint->address, ebreak());
|
retval = target_write_u32(target, breakpoint->address, ebreak());
|
||||||
} else {
|
else
|
||||||
retval = target_write_u16(target, breakpoint->address, ebreak_c());
|
retval = target_write_u16(target, breakpoint->address, ebreak_c());
|
||||||
}
|
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%"
|
LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%"
|
||||||
TARGET_PRIxADDR, breakpoint->length, breakpoint->address);
|
TARGET_PRIxADDR, breakpoint->length, breakpoint->address);
|
||||||
|
@ -496,9 +491,8 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
|
||||||
struct trigger trigger;
|
struct trigger trigger;
|
||||||
trigger_from_breakpoint(&trigger, breakpoint);
|
trigger_from_breakpoint(&trigger, breakpoint);
|
||||||
int result = add_trigger(target, &trigger);
|
int result = add_trigger(target, &trigger);
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("OpenOCD only supports hardware and software breakpoints.");
|
LOG_INFO("OpenOCD only supports hardware and software breakpoints.");
|
||||||
|
@ -527,9 +521,8 @@ static int remove_trigger(struct target *target, struct trigger *trigger)
|
||||||
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < r->trigger_count[first_hart]; i++) {
|
for (i = 0; i < r->trigger_count[first_hart]; i++) {
|
||||||
if (r->trigger_unique_id[i] == trigger->unique_id) {
|
if (r->trigger_unique_id[i] == trigger->unique_id)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (i >= r->trigger_count[first_hart]) {
|
if (i >= r->trigger_count[first_hart]) {
|
||||||
LOG_ERROR("Couldn't find the hardware resources used by hardware "
|
LOG_ERROR("Couldn't find the hardware resources used by hardware "
|
||||||
|
@ -565,9 +558,8 @@ int riscv_remove_breakpoint(struct target *target,
|
||||||
struct trigger trigger;
|
struct trigger trigger;
|
||||||
trigger_from_breakpoint(&trigger, breakpoint);
|
trigger_from_breakpoint(&trigger, breakpoint);
|
||||||
int result = remove_trigger(target, &trigger);
|
int result = remove_trigger(target, &trigger);
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("OpenOCD only supports hardware and software breakpoints.");
|
LOG_INFO("OpenOCD only supports hardware and software breakpoints.");
|
||||||
|
@ -589,7 +581,7 @@ static void trigger_from_watchpoint(struct trigger *trigger,
|
||||||
trigger->read = (watchpoint->rw == WPT_READ || watchpoint->rw == WPT_ACCESS);
|
trigger->read = (watchpoint->rw == WPT_READ || watchpoint->rw == WPT_ACCESS);
|
||||||
trigger->write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == WPT_ACCESS);
|
trigger->write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == WPT_ACCESS);
|
||||||
trigger->execute = false;
|
trigger->execute = false;
|
||||||
// unique_id is unique across both breakpoints and watchpoints.
|
/* unique_id is unique across both breakpoints and watchpoints. */
|
||||||
trigger->unique_id = watchpoint->unique_id;
|
trigger->unique_id = watchpoint->unique_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,9 +591,8 @@ int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
|
||||||
trigger_from_watchpoint(&trigger, watchpoint);
|
trigger_from_watchpoint(&trigger, watchpoint);
|
||||||
|
|
||||||
int result = add_trigger(target, &trigger);
|
int result = add_trigger(target, &trigger);
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
watchpoint->set = true;
|
watchpoint->set = true;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -614,9 +605,8 @@ int riscv_remove_watchpoint(struct target *target,
|
||||||
trigger_from_watchpoint(&trigger, watchpoint);
|
trigger_from_watchpoint(&trigger, watchpoint);
|
||||||
|
|
||||||
int result = remove_trigger(target, &trigger);
|
int result = remove_trigger(target, &trigger);
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
watchpoint->set = false;
|
watchpoint->set = false;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -651,7 +641,7 @@ static int riscv_examine(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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. */
|
||||||
|
|
||||||
riscv_info_t *info = (riscv_info_t *) target->arch_info;
|
riscv_info_t *info = (riscv_info_t *) target->arch_info;
|
||||||
uint32_t dtmcontrol = dtmcontrol_scan(target, 0);
|
uint32_t dtmcontrol = dtmcontrol_scan(target, 0);
|
||||||
|
@ -775,9 +765,8 @@ static int riscv_get_gdb_reg_list(struct target *target,
|
||||||
}
|
}
|
||||||
|
|
||||||
*reg_list = calloc(*reg_list_size, sizeof(struct reg *));
|
*reg_list = calloc(*reg_list_size, sizeof(struct reg *));
|
||||||
if (!*reg_list) {
|
if (!*reg_list)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < *reg_list_size; i++) {
|
for (int i = 0; i < *reg_list_size; i++) {
|
||||||
assert(!target->reg_cache->reg_list[i].valid ||
|
assert(!target->reg_cache->reg_list[i].valid ||
|
||||||
|
@ -794,7 +783,7 @@ static int riscv_arch_state(struct target *target)
|
||||||
return tt->arch_state(target);
|
return tt->arch_state(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Algorithm must end with a software breakpoint instruction.
|
/* Algorithm must end with a software breakpoint instruction. */
|
||||||
static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
||||||
struct mem_param *mem_params, int num_reg_params,
|
struct mem_param *mem_params, int num_reg_params,
|
||||||
struct reg_param *reg_params, target_addr_t entry_point,
|
struct reg_param *reg_params, target_addr_t entry_point,
|
||||||
|
@ -812,11 +801,10 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Save registers
|
/* Save registers */
|
||||||
struct reg *reg_pc = register_get_by_name(target->reg_cache, "pc", 1);
|
struct reg *reg_pc = register_get_by_name(target->reg_cache, "pc", 1);
|
||||||
if (!reg_pc || reg_pc->type->get(reg_pc) != ERROR_OK) {
|
if (!reg_pc || reg_pc->type->get(reg_pc) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
uint64_t saved_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size);
|
uint64_t saved_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size);
|
||||||
|
|
||||||
uint64_t saved_regs[32];
|
uint64_t saved_regs[32];
|
||||||
|
@ -839,17 +827,15 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->type->get(r) != ERROR_OK) {
|
if (r->type->get(r) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
saved_regs[r->number] = buf_get_u64(r->value, 0, r->size);
|
saved_regs[r->number] = buf_get_u64(r->value, 0, r->size);
|
||||||
if (r->type->set(r, reg_params[i].value) != ERROR_OK) {
|
if (r->type->set(r, reg_params[i].value) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Disable Interrupts before attempting to run the algorithm.
|
/* Disable Interrupts before attempting to run the algorithm. */
|
||||||
uint64_t current_mstatus;
|
uint64_t current_mstatus;
|
||||||
uint8_t mstatus_bytes[8];
|
uint8_t mstatus_bytes[8];
|
||||||
|
|
||||||
|
@ -869,11 +855,10 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
||||||
|
|
||||||
reg_mstatus->type->set(reg_mstatus, mstatus_bytes);
|
reg_mstatus->type->set(reg_mstatus, mstatus_bytes);
|
||||||
|
|
||||||
/// Run algorithm
|
/* Run algorithm */
|
||||||
LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point);
|
LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point);
|
||||||
if (oldriscv_resume(target, 0, entry_point, 0, 0) != ERROR_OK) {
|
if (oldriscv_resume(target, 0, entry_point, 0, 0) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
int64_t start = timeval_ms();
|
int64_t start = timeval_ms();
|
||||||
while (target->state != TARGET_HALTED) {
|
while (target->state != TARGET_HALTED) {
|
||||||
|
@ -889,14 +874,12 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = old_or_new_riscv_poll(target);
|
int result = old_or_new_riscv_poll(target);
|
||||||
if (result != ERROR_OK) {
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reg_pc->type->get(reg_pc) != ERROR_OK) {
|
if (reg_pc->type->get(reg_pc) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
uint64_t final_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size);
|
uint64_t final_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size);
|
||||||
if (final_pc != exit_point) {
|
if (final_pc != exit_point) {
|
||||||
LOG_ERROR("PC ended up at 0x%" PRIx64 " instead of 0x%"
|
LOG_ERROR("PC ended up at 0x%" PRIx64 " instead of 0x%"
|
||||||
|
@ -904,37 +887,35 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore Interrupts
|
/* Restore Interrupts */
|
||||||
LOG_DEBUG("Restoring Interrupts");
|
LOG_DEBUG("Restoring Interrupts");
|
||||||
buf_set_u64(mstatus_bytes, 0, info->xlen[0], current_mstatus);
|
buf_set_u64(mstatus_bytes, 0, info->xlen[0], current_mstatus);
|
||||||
reg_mstatus->type->set(reg_mstatus, mstatus_bytes);
|
reg_mstatus->type->set(reg_mstatus, mstatus_bytes);
|
||||||
|
|
||||||
/// Restore registers
|
/* Restore registers */
|
||||||
uint8_t buf[8];
|
uint8_t buf[8];
|
||||||
buf_set_u64(buf, 0, info->xlen[0], saved_pc);
|
buf_set_u64(buf, 0, info->xlen[0], saved_pc);
|
||||||
if (reg_pc->type->set(reg_pc, buf) != ERROR_OK) {
|
if (reg_pc->type->set(reg_pc, buf) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < num_reg_params; i++) {
|
for (int i = 0; i < num_reg_params; i++) {
|
||||||
LOG_DEBUG("restore %s", reg_params[i].reg_name);
|
LOG_DEBUG("restore %s", reg_params[i].reg_name);
|
||||||
struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0);
|
struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0);
|
||||||
buf_set_u64(buf, 0, info->xlen[0], saved_regs[r->number]);
|
buf_set_u64(buf, 0, info->xlen[0], saved_regs[r->number]);
|
||||||
if (r->type->set(r, buf) != ERROR_OK) {
|
if (r->type->set(r, buf) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Should run code on the target to perform CRC of
|
/* Should run code on the target to perform CRC of
|
||||||
memory. Not yet implemented.
|
memory. Not yet implemented.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int riscv_checksum_memory(struct target *target,
|
static int riscv_checksum_memory(struct target *target,
|
||||||
target_addr_t address, uint32_t count,
|
target_addr_t address, uint32_t count,
|
||||||
uint32_t* checksum)
|
uint32_t *checksum)
|
||||||
{
|
{
|
||||||
*checksum = 0xFFFFFFFF;
|
*checksum = 0xFFFFFFFF;
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
|
@ -945,10 +926,10 @@ block holds all-ones (because this is generally called on
|
||||||
NOR flash which is 1 when "blank")
|
NOR flash which is 1 when "blank")
|
||||||
Not yet implemented.
|
Not yet implemented.
|
||||||
*/
|
*/
|
||||||
int riscv_blank_check_memory(struct target * target,
|
int riscv_blank_check_memory(struct target *target,
|
||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
uint32_t * blank,
|
uint32_t *blank,
|
||||||
uint8_t erased_value)
|
uint8_t erased_value)
|
||||||
{
|
{
|
||||||
*blank = 0;
|
*blank = 0;
|
||||||
|
@ -1031,7 +1012,7 @@ int riscv_openocd_poll(struct target *target)
|
||||||
target->debug_reason = DBG_REASON_SINGLESTEP;
|
target->debug_reason = DBG_REASON_SINGLESTEP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (riscv_rtos_enabled(target)) {
|
if (riscv_rtos_enabled(target)) {
|
||||||
target->rtos->current_threadid = triggered_hart + 1;
|
target->rtos->current_threadid = triggered_hart + 1;
|
||||||
target->rtos->current_thread = triggered_hart + 1;
|
target->rtos->current_thread = triggered_hart + 1;
|
||||||
|
@ -1075,9 +1056,8 @@ int riscv_openocd_resume(
|
||||||
) {
|
) {
|
||||||
LOG_DEBUG("resuming all harts");
|
LOG_DEBUG("resuming all harts");
|
||||||
|
|
||||||
if (!current) {
|
if (!current)
|
||||||
riscv_set_register(target, GDB_REGNO_PC, address);
|
riscv_set_register(target, GDB_REGNO_PC, address);
|
||||||
}
|
|
||||||
|
|
||||||
int out = riscv_resume_all_harts(target);
|
int out = riscv_resume_all_harts(target);
|
||||||
if (out != ERROR_OK) {
|
if (out != ERROR_OK) {
|
||||||
|
@ -1099,9 +1079,8 @@ int riscv_openocd_step(
|
||||||
) {
|
) {
|
||||||
LOG_DEBUG("stepping rtos hart");
|
LOG_DEBUG("stepping rtos hart");
|
||||||
|
|
||||||
if (!current) {
|
if (!current)
|
||||||
riscv_set_register(target, GDB_REGNO_PC, address);
|
riscv_set_register(target, GDB_REGNO_PC, address);
|
||||||
}
|
|
||||||
|
|
||||||
int out = riscv_step_rtos_hart(target);
|
int out = riscv_step_rtos_hart(target);
|
||||||
if (out != ERROR_OK) {
|
if (out != ERROR_OK) {
|
||||||
|
@ -1126,7 +1105,7 @@ COMMAND_HANDLER(riscv_set_command_timeout_sec)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
int timeout = atoi(CMD_ARGV[0]);
|
int timeout = atoi(CMD_ARGV[0]);
|
||||||
if (timeout <= 0){
|
if (timeout <= 0) {
|
||||||
LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]);
|
LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -1143,7 +1122,7 @@ COMMAND_HANDLER(riscv_set_reset_timeout_sec)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
int timeout = atoi(CMD_ARGV[0]);
|
int timeout = atoi(CMD_ARGV[0]);
|
||||||
if (timeout <= 0){
|
if (timeout <= 0) {
|
||||||
LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]);
|
LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -1204,7 +1183,7 @@ COMMAND_HANDLER(riscv_set_expose_csrs)
|
||||||
for (unsigned i = 0; i == 0 || CMD_ARGV[0][i-1]; i++) {
|
for (unsigned i = 0; i == 0 || CMD_ARGV[0][i-1]; i++) {
|
||||||
char c = CMD_ARGV[0][i];
|
char c = CMD_ARGV[0][i];
|
||||||
if (isspace(c)) {
|
if (isspace(c)) {
|
||||||
// Ignore whitespace.
|
/* Ignore whitespace. */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1303,8 +1282,7 @@ const struct command_registration riscv_command_handlers[] = {
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct target_type riscv_target =
|
struct target_type riscv_target = {
|
||||||
{
|
|
||||||
.name = "riscv",
|
.name = "riscv",
|
||||||
|
|
||||||
.init_target = riscv_init_target,
|
.init_target = riscv_init_target,
|
||||||
|
@ -1443,13 +1421,12 @@ bool riscv_supports_extension(struct target *target, char letter)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
unsigned num;
|
unsigned num;
|
||||||
if (letter >= 'a' && letter <= 'z') {
|
if (letter >= 'a' && letter <= 'z')
|
||||||
num = letter - 'a';
|
num = letter - 'a';
|
||||||
} else if (letter >= 'A' && letter <= 'Z') {
|
else if (letter >= 'A' && letter <= 'Z')
|
||||||
num = letter - 'A';
|
num = letter - 'A';
|
||||||
} else {
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
return r->misa & (1 << num);
|
return r->misa & (1 << num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1533,9 +1510,11 @@ void riscv_set_rtos_hartid(struct target *target, int hartid)
|
||||||
|
|
||||||
int riscv_count_harts(struct target *target)
|
int riscv_count_harts(struct target *target)
|
||||||
{
|
{
|
||||||
if (target == NULL) return 1;
|
if (target == NULL)
|
||||||
|
return 1;
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
if (r == NULL) return 1;
|
if (r == NULL)
|
||||||
|
return 1;
|
||||||
return r->hart_count;
|
return r->hart_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1546,7 +1525,7 @@ bool riscv_has_register(struct target *target, int hartid, int regid)
|
||||||
|
|
||||||
void riscv_set_register(struct target *target, enum gdb_regno r, riscv_reg_t v)
|
void riscv_set_register(struct target *target, enum gdb_regno r, riscv_reg_t v)
|
||||||
{
|
{
|
||||||
// TODO: propagate errors
|
/* TODO: propagate errors */
|
||||||
return riscv_set_register_on_hart(target, riscv_current_hartid(target), r, v);
|
return riscv_set_register_on_hart(target, riscv_current_hartid(target), r, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1697,8 +1676,8 @@ int riscv_enumerate_triggers(struct target *target)
|
||||||
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, t);
|
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, t);
|
||||||
uint64_t tselect_rb = riscv_get_register_on_hart(target, hartid,
|
uint64_t tselect_rb = riscv_get_register_on_hart(target, hartid,
|
||||||
GDB_REGNO_TSELECT);
|
GDB_REGNO_TSELECT);
|
||||||
// Mask off the top bit, which is used as tdrmode in old
|
/* Mask off the top bit, which is used as tdrmode in old
|
||||||
// implementations.
|
* implementations. */
|
||||||
tselect_rb &= ~(1ULL << (riscv_xlen(target)-1));
|
tselect_rb &= ~(1ULL << (riscv_xlen(target)-1));
|
||||||
if (tselect_rb != t)
|
if (tselect_rb != t)
|
||||||
break;
|
break;
|
||||||
|
@ -1707,14 +1686,13 @@ int riscv_enumerate_triggers(struct target *target)
|
||||||
int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target)));
|
int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target)));
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 1:
|
case 1:
|
||||||
// On these older cores we don't support software using
|
/* On these older cores we don't support software using
|
||||||
// triggers.
|
* triggers. */
|
||||||
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0);
|
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) {
|
if (tdata1 & MCONTROL_DMODE(riscv_xlen(target)))
|
||||||
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0);
|
riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1765,15 +1743,14 @@ const char *gdb_regno_name(enum gdb_regno regno)
|
||||||
case GDB_REGNO_PRIV:
|
case GDB_REGNO_PRIV:
|
||||||
return "priv";
|
return "priv";
|
||||||
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);
|
||||||
} else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) {
|
else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095)
|
||||||
sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0);
|
sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0);
|
||||||
} else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) {
|
else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31)
|
||||||
sprintf(buf, "f%d", regno - GDB_REGNO_FPR0);
|
sprintf(buf, "f%d", regno - GDB_REGNO_FPR0);
|
||||||
} else {
|
else
|
||||||
sprintf(buf, "gdb_regno_%d", regno);
|
sprintf(buf, "gdb_regno_%d", regno);
|
||||||
}
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1864,15 +1841,15 @@ int riscv_init_registers(struct target *target)
|
||||||
#include "encoding.h"
|
#include "encoding.h"
|
||||||
#undef DECLARE_CSR
|
#undef DECLARE_CSR
|
||||||
};
|
};
|
||||||
// encoding.h does not contain the registers in sorted order.
|
/* encoding.h does not contain the registers in sorted order. */
|
||||||
qsort(csr_info, DIM(csr_info), sizeof(*csr_info), cmp_csr_info);
|
qsort(csr_info, DIM(csr_info), sizeof(*csr_info), cmp_csr_info);
|
||||||
unsigned csr_info_index = 0;
|
unsigned csr_info_index = 0;
|
||||||
|
|
||||||
// When gdb request register N, gdb_get_register_packet() assumes that this
|
/* When gdb request 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
|
||||||
// it would be nice not to have yet another set of numbers to translate
|
* it would be nice not to have yet another set of numbers to translate
|
||||||
// between).
|
* between). */
|
||||||
for (uint32_t number = 0; number < GDB_REGNO_COUNT; number++) {
|
for (uint32_t number = 0; number < GDB_REGNO_COUNT; number++) {
|
||||||
struct reg *r = &target->reg_cache->reg_list[number];
|
struct reg *r = &target->reg_cache->reg_list[number];
|
||||||
r->caller_save = true;
|
r->caller_save = true;
|
||||||
|
@ -1883,43 +1860,107 @@ int riscv_init_registers(struct target *target)
|
||||||
r->arch_info = target;
|
r->arch_info = target;
|
||||||
r->number = number;
|
r->number = number;
|
||||||
r->size = riscv_xlen(target);
|
r->size = riscv_xlen(target);
|
||||||
// r->size is set in riscv_invalidate_register_cache, maybe because the
|
/* r->size is set in riscv_invalidate_register_cache, maybe because the
|
||||||
// target is in theory allowed to change XLEN on us. But I expect a lot
|
* target is in theory allowed to change XLEN on us. But I expect a lot
|
||||||
// of other things to break in that case as well.
|
* of other things to break in that case as well. */
|
||||||
if (number <= GDB_REGNO_XPR31) {
|
if (number <= GDB_REGNO_XPR31) {
|
||||||
switch (number) {
|
switch (number) {
|
||||||
case GDB_REGNO_ZERO: r->name = "zero"; break;
|
case GDB_REGNO_ZERO:
|
||||||
case GDB_REGNO_RA: r->name = "ra"; break;
|
r->name = "zero";
|
||||||
case GDB_REGNO_SP: r->name = "sp"; break;
|
break;
|
||||||
case GDB_REGNO_GP: r->name = "gp"; break;
|
case GDB_REGNO_RA:
|
||||||
case GDB_REGNO_TP: r->name = "tp"; break;
|
r->name = "ra";
|
||||||
case GDB_REGNO_T0: r->name = "t0"; break;
|
break;
|
||||||
case GDB_REGNO_T1: r->name = "t1"; break;
|
case GDB_REGNO_SP:
|
||||||
case GDB_REGNO_T2: r->name = "t2"; break;
|
r->name = "sp";
|
||||||
case GDB_REGNO_FP: r->name = "fp"; break;
|
break;
|
||||||
case GDB_REGNO_S1: r->name = "s1"; break;
|
case GDB_REGNO_GP:
|
||||||
case GDB_REGNO_A0: r->name = "a0"; break;
|
r->name = "gp";
|
||||||
case GDB_REGNO_A1: r->name = "a1"; break;
|
break;
|
||||||
case GDB_REGNO_A2: r->name = "a2"; break;
|
case GDB_REGNO_TP:
|
||||||
case GDB_REGNO_A3: r->name = "a3"; break;
|
r->name = "tp";
|
||||||
case GDB_REGNO_A4: r->name = "a4"; break;
|
break;
|
||||||
case GDB_REGNO_A5: r->name = "a5"; break;
|
case GDB_REGNO_T0:
|
||||||
case GDB_REGNO_A6: r->name = "a6"; break;
|
r->name = "t0";
|
||||||
case GDB_REGNO_A7: r->name = "a7"; break;
|
break;
|
||||||
case GDB_REGNO_S2: r->name = "s2"; break;
|
case GDB_REGNO_T1:
|
||||||
case GDB_REGNO_S3: r->name = "s3"; break;
|
r->name = "t1";
|
||||||
case GDB_REGNO_S4: r->name = "s4"; break;
|
break;
|
||||||
case GDB_REGNO_S5: r->name = "s5"; break;
|
case GDB_REGNO_T2:
|
||||||
case GDB_REGNO_S6: r->name = "s6"; break;
|
r->name = "t2";
|
||||||
case GDB_REGNO_S7: r->name = "s7"; break;
|
break;
|
||||||
case GDB_REGNO_S8: r->name = "s8"; break;
|
case GDB_REGNO_FP:
|
||||||
case GDB_REGNO_S9: r->name = "s9"; break;
|
r->name = "fp";
|
||||||
case GDB_REGNO_S10: r->name = "s10"; break;
|
break;
|
||||||
case GDB_REGNO_S11: r->name = "s11"; break;
|
case GDB_REGNO_S1:
|
||||||
case GDB_REGNO_T3: r->name = "t3"; break;
|
r->name = "s1";
|
||||||
case GDB_REGNO_T4: r->name = "t4"; break;
|
break;
|
||||||
case GDB_REGNO_T5: r->name = "t5"; break;
|
case GDB_REGNO_A0:
|
||||||
case GDB_REGNO_T6: r->name = "t6"; break;
|
r->name = "a0";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_A1:
|
||||||
|
r->name = "a1";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_A2:
|
||||||
|
r->name = "a2";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_A3:
|
||||||
|
r->name = "a3";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_A4:
|
||||||
|
r->name = "a4";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_A5:
|
||||||
|
r->name = "a5";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_A6:
|
||||||
|
r->name = "a6";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_A7:
|
||||||
|
r->name = "a7";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_S2:
|
||||||
|
r->name = "s2";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_S3:
|
||||||
|
r->name = "s3";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_S4:
|
||||||
|
r->name = "s4";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_S5:
|
||||||
|
r->name = "s5";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_S6:
|
||||||
|
r->name = "s6";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_S7:
|
||||||
|
r->name = "s7";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_S8:
|
||||||
|
r->name = "s8";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_S9:
|
||||||
|
r->name = "s9";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_S10:
|
||||||
|
r->name = "s10";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_S11:
|
||||||
|
r->name = "s11";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_T3:
|
||||||
|
r->name = "t3";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_T4:
|
||||||
|
r->name = "t4";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_T5:
|
||||||
|
r->name = "t5";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_T6:
|
||||||
|
r->name = "t6";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
r->group = "general";
|
r->group = "general";
|
||||||
r->feature = &feature_cpu;
|
r->feature = &feature_cpu;
|
||||||
|
@ -1938,38 +1979,102 @@ int riscv_init_registers(struct target *target)
|
||||||
r->exist = false;
|
r->exist = false;
|
||||||
}
|
}
|
||||||
switch (number) {
|
switch (number) {
|
||||||
case GDB_REGNO_FT0: r->name = "ft0"; break;
|
case GDB_REGNO_FT0:
|
||||||
case GDB_REGNO_FT1: r->name = "ft1"; break;
|
r->name = "ft0";
|
||||||
case GDB_REGNO_FT2: r->name = "ft2"; break;
|
break;
|
||||||
case GDB_REGNO_FT3: r->name = "ft3"; break;
|
case GDB_REGNO_FT1:
|
||||||
case GDB_REGNO_FT4: r->name = "ft4"; break;
|
r->name = "ft1";
|
||||||
case GDB_REGNO_FT5: r->name = "ft5"; break;
|
break;
|
||||||
case GDB_REGNO_FT6: r->name = "ft6"; break;
|
case GDB_REGNO_FT2:
|
||||||
case GDB_REGNO_FT7: r->name = "ft7"; break;
|
r->name = "ft2";
|
||||||
case GDB_REGNO_FS0: r->name = "fs0"; break;
|
break;
|
||||||
case GDB_REGNO_FS1: r->name = "fs1"; break;
|
case GDB_REGNO_FT3:
|
||||||
case GDB_REGNO_FA0: r->name = "fa0"; break;
|
r->name = "ft3";
|
||||||
case GDB_REGNO_FA1: r->name = "fa1"; break;
|
break;
|
||||||
case GDB_REGNO_FA2: r->name = "fa2"; break;
|
case GDB_REGNO_FT4:
|
||||||
case GDB_REGNO_FA3: r->name = "fa3"; break;
|
r->name = "ft4";
|
||||||
case GDB_REGNO_FA4: r->name = "fa4"; break;
|
break;
|
||||||
case GDB_REGNO_FA5: r->name = "fa5"; break;
|
case GDB_REGNO_FT5:
|
||||||
case GDB_REGNO_FA6: r->name = "fa6"; break;
|
r->name = "ft5";
|
||||||
case GDB_REGNO_FA7: r->name = "fa7"; break;
|
break;
|
||||||
case GDB_REGNO_FS2: r->name = "fs2"; break;
|
case GDB_REGNO_FT6:
|
||||||
case GDB_REGNO_FS3: r->name = "fs3"; break;
|
r->name = "ft6";
|
||||||
case GDB_REGNO_FS4: r->name = "fs4"; break;
|
break;
|
||||||
case GDB_REGNO_FS5: r->name = "fs5"; break;
|
case GDB_REGNO_FT7:
|
||||||
case GDB_REGNO_FS6: r->name = "fs6"; break;
|
r->name = "ft7";
|
||||||
case GDB_REGNO_FS7: r->name = "fs7"; break;
|
break;
|
||||||
case GDB_REGNO_FS8: r->name = "fs8"; break;
|
case GDB_REGNO_FS0:
|
||||||
case GDB_REGNO_FS9: r->name = "fs9"; break;
|
r->name = "fs0";
|
||||||
case GDB_REGNO_FS10: r->name = "fs10"; break;
|
break;
|
||||||
case GDB_REGNO_FS11: r->name = "fs11"; break;
|
case GDB_REGNO_FS1:
|
||||||
case GDB_REGNO_FT8: r->name = "ft8"; break;
|
r->name = "fs1";
|
||||||
case GDB_REGNO_FT9: r->name = "ft9"; break;
|
break;
|
||||||
case GDB_REGNO_FT10: r->name = "ft10"; break;
|
case GDB_REGNO_FA0:
|
||||||
case GDB_REGNO_FT11: r->name = "ft11"; break;
|
r->name = "fa0";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FA1:
|
||||||
|
r->name = "fa1";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FA2:
|
||||||
|
r->name = "fa2";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FA3:
|
||||||
|
r->name = "fa3";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FA4:
|
||||||
|
r->name = "fa4";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FA5:
|
||||||
|
r->name = "fa5";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FA6:
|
||||||
|
r->name = "fa6";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FA7:
|
||||||
|
r->name = "fa7";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FS2:
|
||||||
|
r->name = "fs2";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FS3:
|
||||||
|
r->name = "fs3";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FS4:
|
||||||
|
r->name = "fs4";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FS5:
|
||||||
|
r->name = "fs5";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FS6:
|
||||||
|
r->name = "fs6";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FS7:
|
||||||
|
r->name = "fs7";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FS8:
|
||||||
|
r->name = "fs8";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FS9:
|
||||||
|
r->name = "fs9";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FS10:
|
||||||
|
r->name = "fs10";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FS11:
|
||||||
|
r->name = "fs11";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FT8:
|
||||||
|
r->name = "ft8";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FT9:
|
||||||
|
r->name = "ft9";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FT10:
|
||||||
|
r->name = "ft10";
|
||||||
|
break;
|
||||||
|
case GDB_REGNO_FT11:
|
||||||
|
r->name = "ft11";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
r->group = "float";
|
r->group = "float";
|
||||||
r->feature = &feature_fpu;
|
r->feature = &feature_fpu;
|
||||||
|
@ -1986,11 +2091,11 @@ int riscv_init_registers(struct target *target)
|
||||||
r->name = csr_info[csr_info_index].name;
|
r->name = csr_info[csr_info_index].name;
|
||||||
} else {
|
} else {
|
||||||
sprintf(reg_name, "csr%d", csr_number);
|
sprintf(reg_name, "csr%d", csr_number);
|
||||||
// Assume unnamed registers don't exist, unless we have some
|
/* Assume unnamed registers don't exist, unless we have some
|
||||||
// configuration that tells us otherwise. That's important
|
* configuration that tells us otherwise. That's important
|
||||||
// because eg. Eclipse crashes if a target has too many
|
* because eg. Eclipse crashes if a target has too many
|
||||||
// registers, and apparently has no way of only showing a
|
* registers, and apparently has no way of only showing a
|
||||||
// subset of registers in any case.
|
* subset of registers in any case. */
|
||||||
r->exist = false;
|
r->exist = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2032,9 +2137,8 @@ int riscv_init_registers(struct target *target)
|
||||||
r->feature = &feature_virtual;
|
r->feature = &feature_virtual;
|
||||||
r->size = 8;
|
r->size = 8;
|
||||||
}
|
}
|
||||||
if (reg_name[0]) {
|
if (reg_name[0])
|
||||||
r->name = reg_name;
|
r->name = reg_name;
|
||||||
}
|
|
||||||
reg_name += strlen(reg_name) + 1;
|
reg_name += strlen(reg_name) + 1;
|
||||||
assert(reg_name < info->reg_names + GDB_REGNO_COUNT * max_reg_name_len);
|
assert(reg_name < info->reg_names + GDB_REGNO_COUNT * max_reg_name_len);
|
||||||
r->value = &info->reg_cache_values[number];
|
r->value = &info->reg_cache_values[number];
|
||||||
|
|
|
@ -141,7 +141,7 @@ int riscv_openocd_resume(
|
||||||
struct target *target,
|
struct target *target,
|
||||||
int current,
|
int current,
|
||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
int handle_breakpoints,
|
int handle_breakpoints,
|
||||||
int debug_execution
|
int debug_execution
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -2830,8 +2830,8 @@ COMMAND_HANDLER(handle_reg_command)
|
||||||
|
|
||||||
retval = reg->type->set(reg, buf);
|
retval = reg->type->set(reg, buf);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
LOG_DEBUG("Couldn't set register %s.", reg->name);
|
LOG_DEBUG("Couldn't set register %s.", reg->name);
|
||||||
free (buf);
|
free(buf);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue