Merge up to a35e254c53 from upstream

Checkpatch-ignore: MACRO_ARG_REUSE, MACRO_ARG_PRECEDENCE
Change-Id: Icd10f44d162054f8f32019a579ccbdda2cee7a91
This commit is contained in:
Evgeniy Naydanov 2024-03-28 12:06:34 +03:00
commit 46e7507e48
32 changed files with 1765 additions and 1283 deletions

View File

@ -7348,10 +7348,6 @@ works only for chips that do not have factory pre-programmed region 0
code.
@end deffn
@deffn {Command} {nrf5 info}
Decodes and shows information from FICR and UICR registers.
@end deffn
@end deffn
@deffn {Flash Driver} {ocl}
@ -11103,6 +11099,11 @@ EJTAG Register Specification could be found in MIPS Document MD00047F, for
core specific EJTAG Register definition, please check Core Specific SUM manual.
@end deffn
@deffn {Command} {mips32 dsp} [[register_name] [value]]
Displays all DSP registers' contents or get/set value by register name. Will display
an error if current CPU does not support DSP.
@end deffn
@section RISC-V Architecture
@uref{http://riscv.org/, RISC-V} is a free and open ISA. OpenOCD supports JTAG
@ -12353,59 +12354,102 @@ waveform generator. These are synthesize-able hardware descriptions of
logic circuits in addition to software for control, visualization and further analysis.
In a session using JTAG for its transport protocol, OpenOCD supports the function
of a JTAG-Host. The JTAG-Host is needed to connect the circuit over JTAG to the
control-software. For more details see @url{http://ipdbg.org}.
control-software. The JTAG-Hub is the circuit which transfers the data from JTAG to the
different tools connected to the Hub. Hub implementations for most major FPGA vendors/families
are provided. For more details see @url{http://ipdbg.org}.
@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-tap @var{tapname}} @option{-hub @var{ir_value} [@var{dr_length}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] [@option{-port @var{number}}] [@option{-tool @var{number}}]
Starts or stops a IPDBG JTAG-Host server. Arguments can be specified in any order.
@deffn {Command} {ipdbg create-hub} @var{hub_name} @option{-tap @var{tapname}} @option{-ir @var{ir_value} [@var{dr_length}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}]
@deffnx {Command} {ipdbg create-hub} @var{hub_name} @option{-pld @var{pld_name} [@var{user}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}]
Creates a IPDBG JTAG Hub. The created hub is later used to start, stop and configure IPDBG JTAG Host servers.
The first argument @var{hub_name} is the name of the created hub. It can be used later as a reference.
The pld drivers are able to provide the tap and ir_value for the IPDBG JTAG-Host server. This will be used with the second variant with option @option{-pld}.
Command options:
@itemize @bullet
@item @option{-start|-stop} starts or stops a IPDBG JTAG-Host server (default: start).
@item @var{hub_name} the name of the IPDBG hub.
This name is also used to create the object's command, referred to here
as @command{$hub_name}, and in other places where the Hub needs to be identified.
@item @option{-tap @var{tapname}} targeting the TAP @var{tapname}.
@item @option{-hub @var{ir_value}} states that the JTAG hub is
reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}.
@item @option{-port @var{number}} tcp port number where the JTAG-Host will listen. The default is 4242 which is used when the option is not given.
@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given.
@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} On some devices, the user data-register is reachable if there is a
specific value in a second dr. This second dr is called vir (virtual ir). With this parameter given, the IPDBG satisfies this condition prior an
@item @option{-ir @var{ir_value}} states that the JTAG hub is
reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}. Also known as @verb{|USERx|} instructions.
The optional @var{dr_length} is the length of the dr.
Current JTAG-Hub implementation only supports dr_length=13, which is also the default value.
@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} To support more Hubs than USER registers in a single FPGA it is possible to
use a mechanism known as virtual-ir where the user data-register is reachable if there is a specific value in a second dr.
This second dr is called vir (virtual ir). With this parameter given, the IPDBG satisfies this condition prior an
access to the IPDBG-Hub. The value shifted into the vir is given by the first parameter @var{vir_value} (default: 0x11). The second
parameter @var{length} is the length of the vir data register (default: 5). With the @var{instr_code} (default: 0x00e) parameter the ir value to
shift data through vir can be configured.
@item @option{-pld @var{pld_name} [@var{user}]} The defined driver for the pld @var{pld_name} is used to get the tap and user instruction.
The pld devices names can be shown by the command @command{pld devices}. With [@var{user}] one can select a different @verb{|USERx|}-Instruction.
If the IPDBG JTAG-Hub is used without modification the default value of 1 which selects the first @verb{|USERx|} instruction is adequate.
The @verb{|USERx|} instructions are vendor specific and don't change between families of the same vendor.
So if there's a pld driver for your vendor it should work with your FPGA even when the driver is not compatible with your device for the remaining features.
If your device/vendor is not supported you have to use the first variant.
@end itemize
@end deffn
@deffn {Command} {$hub_name ipdbg start} @option{-tool @var{number}} @option{-port @var{number}}
Starts a IPDBG JTAG-Host server. The remaining arguments can be specified in any order.
Command options:
@itemize @bullet
@item @option{-port @var{number}} tcp port number where the JTAG-Host will listen. The default is 4242 which is used when the option is not given.
@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given.
@end itemize
@end deffn
or
@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-pld @var{name} [@var{user}]} [@option{-port @var{number}}] [@option{-tool @var{number}}]
Also starts or stops a IPDBG JTAG-Host server. The pld drivers are able to provide the tap and hub/IR for the IPDBG JTAG-Host server.
With the @option{-pld @var{name} [@var{user}]} the information from the pld-driver is used and the options @option{-tap} and @option{-hub} are not required.
The defined driver for the pld @var{name} gets selected. (The pld devices names can be shown by the command @command{pld devices}).
The @verb{|USERx|} instructions are vendor specific and don't change between families of the same vendor.
So if there's a pld driver for your vendor it should work with your FPGA even when the driver is not compatible with your device for the remaining features. If your device/vendor is not supported you have to use the previous command.
With [@var{user}] one can select a different @verb{|USERx|}-Instruction. If the IPDBG JTAG-Hub is used without modification the default value of 1 which selects the first @verb{|USERx|} instruction is adequate.
The remaining options are described in the previous command.
@deffn {Command} {$hub_name ipdbg stop} @option{-tool @var{number}}
Stops a IPDBG JTAG-Host server.
Command options:
@itemize @bullet
@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given.
@end itemize
@end deffn
Examples:
@example
ipdbg -start -tap xc6s.tap -hub 0x02 -port 4242 -tool 4
ipdbg create-hub xc6s.ipdbghub -tap xc6s.tap -hub 0x02
xc6s.ipdbghub ipdbg start -port 4242 -tool 4
@end example
Starts a server listening on tcp-port 4242 which connects to tool 4.
Creates a IPDBG Hub and starts a server listening on tcp-port 4242 which connects to tool 4.
The connection is through the TAP of a Xilinx Spartan 6 on USER1 instruction (tested with a papillion pro board).
@example
ipdbg -start -tap 10m50.tap -hub 0x00C -vir -port 60000 -tool 1
ipdbg create-hub max10m50.ipdbghub -tap max10m50.tap -hub 0x00C -vir
max10m50.ipdbghub ipdbg start -tool 1 -port 60000
@end example
Starts a server listening on tcp-port 60000 which connects to tool 1 (data_up_1/data_down_1).
The connection is through the TAP of a Intel MAX10 virtual jtag component (sld_instance_index is 0; sld_ir_width is smaller than 5).
@example
ipdbg -start -pld xc7.pld -port 5555 -tool 0
ipdbg create-hub xc7.ipdbghub -pld xc7.pld
xc7.ipdbghub ipdbg start -port 5555 -tool 0
@end example
Starts a server listening on tcp-port 5555 which connects to tool 0 (data_up_0/data_down_0).
The TAP and ir value used to reach the JTAG Hub is given by the pld driver.
@deffn {Command} {$hub_name queuing} @option{-size @var{size}}
Configure the queuing between IPDBG JTAG-Host and Hub.
The maximum possible queue size is 1024 which is also the default.
@itemize @bullet
@item @option{-size @var{size}} max number of transfers in the queue.
@end itemize
@end deffn
@example
bitbang.ibdbghub queuing -size 32
@end example
Send a maximum of 32 transfers to the queue before executing them.
@node Utility Commands
@chapter Utility Commands

View File

@ -17,6 +17,7 @@
#include <target/armv7m.h>
#include <helper/types.h>
#include <helper/time_support.h>
#include <helper/bits.h>
/* Both those values are constant across the current spectrum ofr nRF5 devices */
#define WATCHDOG_REFRESH_REGISTER 0x40010600
@ -42,32 +43,9 @@ enum nrf5_ficr_registers {
NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040),
NRF51_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044),
/* CONFIGID is documented on nRF51 series only.
* On nRF52 is present but not documented */
NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C),
NRF5_FICR_DEVICEID0 = NRF5_FICR_REG(0x060),
NRF5_FICR_DEVICEID1 = NRF5_FICR_REG(0x064),
NRF5_FICR_ER0 = NRF5_FICR_REG(0x080),
NRF5_FICR_ER1 = NRF5_FICR_REG(0x084),
NRF5_FICR_ER2 = NRF5_FICR_REG(0x088),
NRF5_FICR_ER3 = NRF5_FICR_REG(0x08C),
NRF5_FICR_IR0 = NRF5_FICR_REG(0x090),
NRF5_FICR_IR1 = NRF5_FICR_REG(0x094),
NRF5_FICR_IR2 = NRF5_FICR_REG(0x098),
NRF5_FICR_IR3 = NRF5_FICR_REG(0x09C),
NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG(0x0A0),
NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG(0x0A4),
NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG(0x0A8),
NRF51_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC),
NRF51_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0),
NRF51_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4),
NRF51_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8),
NRF51_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC),
NRF51_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0),
NRF51_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC),
NRF51_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0),
NRF51_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4),
NRF51_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8),
NRF51_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC),
/* Following registers are available on nRF52 and on nRF51 since rev 3 */
NRF5_FICR_INFO_PART = NRF5_FICR_REG(0x100),
@ -84,9 +62,6 @@ enum nrf5_uicr_registers {
#define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset)
NRF51_UICR_CLENR0 = NRF5_UICR_REG(0x000),
NRF51_UICR_RBPCONF = NRF5_UICR_REG(0x004),
NRF51_UICR_XTALFREQ = NRF5_UICR_REG(0x008),
NRF51_UICR_FWID = NRF5_UICR_REG(0x010),
};
enum nrf5_nvmc_registers {
@ -120,10 +95,10 @@ struct nrf52_ficr_info {
};
enum nrf5_features {
NRF5_FEATURE_SERIES_51 = 1 << 0,
NRF5_FEATURE_SERIES_52 = 1 << 1,
NRF5_FEATURE_BPROT = 1 << 2,
NRF5_FEATURE_ACL_PROT = 1 << 3,
NRF5_FEATURE_SERIES_51 = BIT(0),
NRF5_FEATURE_SERIES_52 = BIT(1),
NRF5_FEATURE_BPROT = BIT(2),
NRF5_FEATURE_ACL_PROT = BIT(3),
};
struct nrf5_device_spec {
@ -164,26 +139,20 @@ struct nrf5_info {
.features = NRF5_FEATURE_SERIES_51, \
}
#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize, features) \
{ \
.hwid = (id), \
.part = pt, \
.variant = var, \
.build_code = bcode, \
.flash_size_kb = (fsize), \
.features = features, \
}
/* The known devices table below is derived from the "nRF5x series
* compatibility matrix" documents, which can be found in the "DocLib" of
* nordic:
/*
* The table maps known HWIDs to the part numbers, variant
* build code and some other info. For nRF51 rev 1 and 2 devices
* this is the only way how to get the part number and variant.
*
* https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51422_ic_revision_overview
* https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51822_ic_revision_overview
* https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51824_ic_revision_overview
* https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52810/latest/COMP/nrf52810/nRF52810_ic_revision_overview
* https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52832/latest/COMP/nrf52832/ic_revision_overview
* https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52840/latest/COMP/nrf52840/nRF52840_ic_revision_overview
* All tested nRF51 rev 3 devices have FICR INFO fields
* but the fields are not documented in RM so we keep HWIDs in
* this table.
*
* nRF52 and newer devices have FICR INFO documented, the autodetection
* can rely on it and HWIDs table is not used.
*
* The known devices table below is derived from the "nRF5x series
* compatibility matrix" documents.
*
* Up to date with Matrix v2.0, plus some additional HWIDs.
*
@ -248,19 +217,6 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = {
/* The driver fully autodetects nRF52 series devices by FICR INFO,
* no need for nRF52xxx HWIDs in this table */
#if 0
/* nRF52810 Devices */
NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
/* nRF52832 Devices */
NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT),
/* nRF52840 Devices */
NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_ACL_PROT),
#endif
};
struct nrf5_device_package {
@ -270,11 +226,16 @@ struct nrf5_device_package {
/* Newer devices have FICR INFO.PACKAGE.
* This table converts its value to two character code */
static const struct nrf5_device_package nrf5_packages_table[] = {
static const struct nrf5_device_package nrf52_packages_table[] = {
{ 0x2000, "QF" },
{ 0x2001, "CH" },
{ 0x2002, "CI" },
{ 0x2003, "QC" },
{ 0x2004, "QI/CA" }, /* differs nRF52805, 810, 811: CA, nRF52833, 840: QI */
{ 0x2005, "CK" },
{ 0x2007, "QD" },
{ 0x2008, "CJ" },
{ 0x2009, "CF" },
};
const struct flash_driver nrf5_flash, nrf51_flash;
@ -282,28 +243,10 @@ const struct flash_driver nrf5_flash, nrf51_flash;
static bool nrf5_bank_is_probed(const struct flash_bank *bank)
{
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
return nbank->probed;
}
static int nrf5_probe(struct flash_bank *bank);
static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_info **chip)
{
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
struct nrf5_bank *nbank = bank->driver_priv;
*chip = nbank->chip;
if (nrf5_bank_is_probed(bank))
return ERROR_OK;
return nrf5_probe(bank);
}
static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
{
@ -431,9 +374,10 @@ static int nrf5_protect_check_clenr0(struct flash_bank *bank)
{
int res;
uint32_t clenr0;
struct nrf5_bank *nbank = bank->driver_priv;
struct nrf5_info *chip = nbank->chip;
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
assert(chip);
res = target_read_u32(chip->target, NRF51_FICR_CLENR0,
@ -462,8 +406,8 @@ static int nrf5_protect_check_clenr0(struct flash_bank *bank)
static int nrf5_protect_check_bprot(struct flash_bank *bank)
{
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
assert(chip);
static uint32_t nrf5_bprot_offsets[4] = { 0x600, 0x604, 0x610, 0x614 };
@ -493,8 +437,8 @@ static int nrf5_protect_check(struct flash_bank *bank)
return ERROR_OK;
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
assert(chip);
if (chip->features & NRF5_FEATURE_BPROT)
@ -512,8 +456,11 @@ static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int fi
{
int res;
uint32_t clenr0, ppfc;
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
assert(chip);
if (first != 0) {
LOG_ERROR("Code region 0 must start at the beginning of the bank");
@ -570,18 +517,21 @@ error:
static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first,
unsigned int last)
{
int res;
struct nrf5_info *chip;
/* UICR cannot be write protected so just bail out early */
if (bank->base == NRF5_UICR_BASE) {
LOG_ERROR("UICR page does not support protection");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
res = nrf5_get_probed_chip_if_halted(bank, &chip);
if (res != ERROR_OK)
return res;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
assert(chip);
if (chip->features & NRF5_FEATURE_SERIES_51)
return nrf5_protect_clenr0(bank, set, first, last);
@ -607,9 +557,9 @@ static bool nrf5_info_variant_to_str(uint32_t variant, char *bf)
static const char *nrf5_decode_info_package(uint32_t package)
{
for (size_t i = 0; i < ARRAY_SIZE(nrf5_packages_table); i++) {
if (nrf5_packages_table[i].package == package)
return nrf5_packages_table[i].code;
for (size_t i = 0; i < ARRAY_SIZE(nrf52_packages_table); i++) {
if (nrf52_packages_table[i].package == package)
return nrf52_packages_table[i].code;
}
return "xx";
}
@ -642,7 +592,9 @@ static int get_nrf5_chip_type_str(const struct nrf5_info *chip, char *buf, unsig
static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd)
{
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
assert(chip);
char chip_type_str[256];
if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK)
@ -676,11 +628,15 @@ static int nrf5_read_ficr_info(struct nrf5_info *chip)
chip->features = NRF5_FEATURE_SERIES_52;
switch (chip->ficr_info.part) {
case 0x52805:
case 0x52810:
case 0x52811:
case 0x52832:
chip->features |= NRF5_FEATURE_BPROT;
break;
case 0x52820:
case 0x52833:
case 0x52840:
chip->features |= NRF5_FEATURE_ACL_PROT;
break;
@ -755,8 +711,11 @@ static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size)
static int nrf5_probe(struct flash_bank *bank)
{
int res;
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
assert(chip);
struct target *target = chip->target;
uint32_t configid;
@ -1024,11 +983,17 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u
static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct nrf5_info *chip;
int res;
int res = nrf5_get_probed_chip_if_halted(bank, &chip);
if (res != ERROR_OK)
return res;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
assert(chip);
assert(offset % 4 == 0);
assert(count % 4 == 0);
@ -1081,11 +1046,16 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first,
unsigned int last)
{
int res;
struct nrf5_info *chip;
res = nrf5_get_probed_chip_if_halted(bank, &chip);
if (res != ERROR_OK)
return res;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
assert(chip);
/* UICR CLENR0 based protection used on nRF51 prevents erase
* absolutely silently. NVMC has no flag to indicate the protection
@ -1101,7 +1071,7 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first,
}
/* For each sector to be erased */
for (unsigned int s = first; s <= last && res == ERROR_OK; s++) {
for (unsigned int s = first; s <= last; s++) {
if (chip->features & NRF5_FEATURE_SERIES_51
&& bank->sectors[s].is_protected == 1) {
@ -1122,6 +1092,7 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first,
static void nrf5_free_driver_priv(struct flash_bank *bank)
{
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
if (!chip)
return;
@ -1160,6 +1131,9 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
struct nrf5_info *chip;
struct nrf5_bank *nbank = NULL;
if (bank->driver == &nrf51_flash)
LOG_WARNING("Flash driver 'nrf51' is deprecated! Use 'nrf5' instead.");
switch (bank->base) {
case NRF5_FLASH_BASE:
case NRF5_UICR_BASE:
@ -1210,11 +1184,15 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
assert(bank);
struct nrf5_info *chip;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
res = nrf5_get_probed_chip_if_halted(bank, &chip);
if (res != ERROR_OK)
return res;
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
assert(chip);
if (chip->features & NRF5_FEATURE_SERIES_51) {
uint32_t ppfc;
@ -1245,137 +1223,6 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
return res;
}
COMMAND_HANDLER(nrf5_handle_info_command)
{
int res;
struct flash_bank *bank = NULL;
struct target *target = get_current_target(CMD_CTX);
res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank);
if (res != ERROR_OK)
return res;
assert(bank);
struct nrf5_info *chip;
res = nrf5_get_probed_chip_if_halted(bank, &chip);
if (res != ERROR_OK)
return res;
static struct {
const uint32_t address;
uint32_t value;
} ficr[] = {
{ .address = NRF5_FICR_CODEPAGESIZE },
{ .address = NRF5_FICR_CODESIZE },
{ .address = NRF51_FICR_CLENR0 },
{ .address = NRF51_FICR_PPFC },
{ .address = NRF51_FICR_NUMRAMBLOCK },
{ .address = NRF51_FICR_SIZERAMBLOCK0 },
{ .address = NRF51_FICR_SIZERAMBLOCK1 },
{ .address = NRF51_FICR_SIZERAMBLOCK2 },
{ .address = NRF51_FICR_SIZERAMBLOCK3 },
{ .address = NRF5_FICR_CONFIGID },
{ .address = NRF5_FICR_DEVICEID0 },
{ .address = NRF5_FICR_DEVICEID1 },
{ .address = NRF5_FICR_ER0 },
{ .address = NRF5_FICR_ER1 },
{ .address = NRF5_FICR_ER2 },
{ .address = NRF5_FICR_ER3 },
{ .address = NRF5_FICR_IR0 },
{ .address = NRF5_FICR_IR1 },
{ .address = NRF5_FICR_IR2 },
{ .address = NRF5_FICR_IR3 },
{ .address = NRF5_FICR_DEVICEADDRTYPE },
{ .address = NRF5_FICR_DEVICEADDR0 },
{ .address = NRF5_FICR_DEVICEADDR1 },
{ .address = NRF51_FICR_OVERRIDEN },
{ .address = NRF51_FICR_NRF_1MBIT0 },
{ .address = NRF51_FICR_NRF_1MBIT1 },
{ .address = NRF51_FICR_NRF_1MBIT2 },
{ .address = NRF51_FICR_NRF_1MBIT3 },
{ .address = NRF51_FICR_NRF_1MBIT4 },
{ .address = NRF51_FICR_BLE_1MBIT0 },
{ .address = NRF51_FICR_BLE_1MBIT1 },
{ .address = NRF51_FICR_BLE_1MBIT2 },
{ .address = NRF51_FICR_BLE_1MBIT3 },
{ .address = NRF51_FICR_BLE_1MBIT4 },
}, uicr[] = {
{ .address = NRF51_UICR_CLENR0, },
{ .address = NRF51_UICR_RBPCONF },
{ .address = NRF51_UICR_XTALFREQ },
{ .address = NRF51_UICR_FWID },
};
for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) {
res = target_read_u32(chip->target, ficr[i].address,
&ficr[i].value);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read %" PRIx32, ficr[i].address);
return res;
}
}
for (size_t i = 0; i < ARRAY_SIZE(uicr); i++) {
res = target_read_u32(chip->target, uicr[i].address,
&uicr[i].value);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read %" PRIx32, uicr[i].address);
return res;
}
}
command_print(CMD,
"\n[factory information control block]\n\n"
"code page size: %"PRIu32"B\n"
"code memory size: %"PRIu32"kB\n"
"code region 0 size: %"PRIu32"kB\n"
"pre-programmed code: %s\n"
"number of ram blocks: %"PRIu32"\n"
"ram block 0 size: %"PRIu32"B\n"
"ram block 1 size: %"PRIu32"B\n"
"ram block 2 size: %"PRIu32"B\n"
"ram block 3 size: %"PRIu32 "B\n"
"config id: %" PRIx32 "\n"
"device id: 0x%"PRIx32"%08"PRIx32"\n"
"encryption root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n"
"identity root: 0x%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"\n"
"device address type: 0x%"PRIx32"\n"
"device address: 0x%"PRIx32"%08"PRIx32"\n"
"override enable: %"PRIx32"\n"
"NRF_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n"
"BLE_1MBIT values: %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n"
"\n[user information control block]\n\n"
"code region 0 size: %"PRIu32"kB\n"
"read back protection configuration: %"PRIx32"\n"
"reset value for XTALFREQ: %"PRIx32"\n"
"firmware id: 0x%04"PRIx32,
ficr[0].value,
(ficr[1].value * ficr[0].value) / 1024,
(ficr[2].value == 0xFFFFFFFF) ? 0 : ficr[2].value / 1024,
((ficr[3].value & 0xFF) == 0x00) ? "present" : "not present",
ficr[4].value,
ficr[5].value,
(ficr[6].value == 0xFFFFFFFF) ? 0 : ficr[6].value,
(ficr[7].value == 0xFFFFFFFF) ? 0 : ficr[7].value,
(ficr[8].value == 0xFFFFFFFF) ? 0 : ficr[8].value,
ficr[9].value,
ficr[10].value, ficr[11].value,
ficr[12].value, ficr[13].value, ficr[14].value, ficr[15].value,
ficr[16].value, ficr[17].value, ficr[18].value, ficr[19].value,
ficr[20].value,
ficr[21].value, ficr[22].value,
ficr[23].value,
ficr[24].value, ficr[25].value, ficr[26].value, ficr[27].value, ficr[28].value,
ficr[29].value, ficr[30].value, ficr[31].value, ficr[32].value, ficr[33].value,
(uicr[0].value == 0xFFFFFFFF) ? 0 : uicr[0].value / 1024,
uicr[1].value & 0xFFFF,
uicr[2].value & 0xFF,
uicr[3].value & 0xFFFF);
return ERROR_OK;
}
static const struct command_registration nrf5_exec_command_handlers[] = {
{
@ -1385,13 +1232,6 @@ static const struct command_registration nrf5_exec_command_handlers[] = {
.help = "Erase all flash contents of the chip.",
.usage = "",
},
{
.name = "info",
.handler = nrf5_handle_info_command,
.mode = COMMAND_EXEC,
.help = "Show FICR and UICR info.",
.usage = "",
},
COMMAND_REGISTRATION_DONE
};

View File

@ -11,7 +11,8 @@
#ifndef OPENOCD_HELPER_BINARYBUFFER_H
#define OPENOCD_HELPER_BINARYBUFFER_H
#include "list.h"
#include <helper/list.h>
#include <helper/types.h>
/** @file
* Support functions to access arbitrary bits in a byte array

File diff suppressed because it is too large Load Diff

View File

@ -114,6 +114,15 @@ extern int debug_level;
expr); \
} while (0)
#define LOG_CUSTOM_LEVEL(level, expr ...) \
do { \
enum log_levels _level = level; \
if (debug_level >= _level) \
log_printf_lf(_level, \
__FILE__, __LINE__, __func__, \
expr); \
} while (0)
#define LOG_INFO(expr ...) \
log_printf_lf(LOG_LVL_INFO, __FILE__, __LINE__, __func__, expr)

View File

@ -341,6 +341,10 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
exit(0);
}
/* dump full command line */
for (int i = 0; i < argc; i++)
LOG_DEBUG("ARGV[%d] = \"%s\"", i, argv[i]);
/* paths specified on the command line take precedence over these
* built-in paths
*/

View File

@ -20,6 +20,11 @@
#include <jtag/interface.h>
#include <jtag/commands.h>
#include <helper/time_support.h>
/* Timeout for retrying on SWD WAIT in msec */
#define SWD_WAIT_TIMEOUT 500
/**
* Function bitbang_stableclocks
* issues a number of clock cycles while staying in a stable state.
@ -474,7 +479,8 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay
return;
}
for (;;) {
int64_t timeout = timeval_ms() + SWD_WAIT_TIMEOUT;
for (unsigned int retry = 0;; retry++) {
uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)];
cmd |= SWD_CMD_START | SWD_CMD_PARK;
@ -488,16 +494,25 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay
uint32_t data = buf_get_u32(trn_ack_data_parity_trn, 1 + 3, 32);
int parity = buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 32, 1);
LOG_DEBUG_IO("%s %s read reg %X = %08" PRIx32,
LOG_CUSTOM_LEVEL((ack != SWD_ACK_OK && (retry == 0 || ack != SWD_ACK_WAIT))
? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO,
"%s %s read reg %X = %08" PRIx32,
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
cmd & SWD_CMD_APNDP ? "AP" : "DP",
(cmd & SWD_CMD_A32) >> 1,
data);
if (ack == SWD_ACK_WAIT) {
if (ack == SWD_ACK_WAIT && timeval_ms() <= timeout) {
swd_clear_sticky_errors();
if (retry > 20)
alive_sleep(1);
continue;
} else if (ack != SWD_ACK_OK) {
}
if (retry > 1)
LOG_DEBUG("SWD WAIT: retried %u times", retry);
if (ack != SWD_ACK_OK) {
queued_retval = swd_ack_to_error_code(ack);
return;
}
@ -524,12 +539,14 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay
return;
}
int64_t timeout = timeval_ms() + SWD_WAIT_TIMEOUT;
/* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
bool check_ack = swd_cmd_returns_ack(cmd);
/* init the array to silence scan-build */
uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)] = {0};
for (;;) {
for (unsigned int retry = 0;; retry++) {
buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32, value);
buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1 + 32, 1, parity_u32(value));
@ -554,23 +571,30 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay
bitbang_swd_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 32 + 1);
int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3);
LOG_DEBUG_IO("%s%s %s write reg %X = %08" PRIx32,
LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK && (retry == 0 || ack != SWD_ACK_WAIT))
? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO,
"%s%s %s write reg %X = %08" PRIx32,
check_ack ? "" : "ack ignored ",
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
cmd & SWD_CMD_APNDP ? "AP" : "DP",
(cmd & SWD_CMD_A32) >> 1,
buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32));
if (check_ack) {
if (ack == SWD_ACK_WAIT) {
if (check_ack && ack == SWD_ACK_WAIT && timeval_ms() <= timeout) {
swd_clear_sticky_errors();
if (retry > 20)
alive_sleep(1);
continue;
} else if (ack != SWD_ACK_OK) {
}
if (retry > 1)
LOG_DEBUG("SWD WAIT: retried %u times", retry);
if (check_ack && ack != SWD_ACK_OK) {
queued_retval = swd_ack_to_error_code(ack);
return;
}
}
if (cmd & SWD_CMD_APNDP)
bitbang_swd_exchange(true, NULL, 0, ap_delay_clk);

View File

@ -944,7 +944,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, enum cmsis_dap_blo
if (ack != SWD_ACK_OK) {
LOG_DEBUG("SWD ack not OK @ %d %s", transfer_count,
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
queued_retval = swd_ack_to_error_code(ack);
/* TODO: use results of transfers completed before the error occurred? */
goto skip;
}

View File

@ -1506,7 +1506,8 @@ static int ftdi_swd_run_queue(void)
/* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
bool check_ack = swd_cmd_returns_ack(swd_cmd_queue[i].cmd);
LOG_DEBUG_IO("%s%s %s %s reg %X = %08"PRIx32,
LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK) ? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO,
"%s%s %s %s reg %X = %08" PRIx32,
check_ack ? "" : "ack ignored ",
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
swd_cmd_queue[i].cmd & SWD_CMD_APNDP ? "AP" : "DP",

View File

@ -782,7 +782,7 @@ static int kitprog_swd_run_queue(void)
if (ack != SWD_ACK_OK || (buffer[read_index] & 0x08)) {
LOG_DEBUG("SWD ack not OK: %d %s", i,
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
queued_retval = swd_ack_to_error_code(ack);
break;
}
read_index++;

View File

@ -1146,4 +1146,132 @@ proc "pld device" {driver tap_name {opt 0}} {
}
}
lappend _telnet_autocomplete_skip "ipdbg -start"
proc "ipdbg -start" {args} {
echo "DEPRECATED! use 'ipdbg create-hub' and 'chip.ipdbghub ipdbg start ...', not 'ipdbg -start ...'"
set tap_name ""
set pld_name ""
set tool_num "1"
set port_num "4242"
set idx 0
set num_args [llength $args]
while {$idx < $num_args} {
set arg [lindex $args $idx]
switch -- $arg {
"-tap" {
incr idx
if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} {
echo "no TAP name given"
return
}
set tap_name [lindex $args $idx]
}
"-pld" {
incr idx
if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} {
echo "no PLD name given"
return
}
set pld_name [lindex $args $idx]
}
"-tool" {
if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} {
set tool_num [lindex $args [expr {$idx + 1}]]
set args [lreplace $args [expr {$idx + 1}] [expr {$idx + 1}]]
incr num_args -1
}
set args [lreplace $args $idx $idx]
incr num_args -1
incr idx -1
}
"-port" {
if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} {
set port_num [lindex $args [expr {$idx + 1}]]
set args [lreplace $args [expr {$idx + 1}] [expr {$idx + 1}]]
incr num_args -1
}
set args [lreplace $args $idx $idx]
incr num_args -1
incr idx -1
}
"-hub" {
set args [lreplace $args $idx $idx "-ir" ]
}
default {
# don't touch remaining arguments
}
}
incr idx
}
set hub_name ""
if {$tap_name != ""} {
set hub_name [lindex [split $tap_name .] 0].ipdbghub
} elseif {$pld_name != ""} {
set hub_name [lindex [split $pld_name .] 0].ipdbghub
} else {
echo "parsing arguments failed: no tap and no pld given."
return
}
echo "name: $hub_name"
echo "ipdbg create-hub $hub_name $args"
catch {eval ipdbg create-hub $hub_name $args}
eval $hub_name ipdbg start -tool $tool_num -port $port_num
}
lappend _telnet_autocomplete_skip "ipdbg -stop"
proc "ipdbg -stop" {args} {
echo "DEPRECATED! use 'chip.ipdbghub ipdbg stop ...', not 'ipdbg -stop ...'"
set tap_name ""
set pld_name ""
set tool_num "1"
set idx 0
set num_args [llength $args]
while {$idx < $num_args} {
set arg [lindex $args $idx]
switch -- $arg {
"-tap" {
incr idx
if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} {
echo "no TAP name given"
return
}
set tap_name [lindex $args $idx]
}
"-pld" {
incr idx
if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} {
echo "no PLD name given"
return
}
set pld_name [lindex $args $idx]
}
"-tool" {
if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} {
set tool_num [lindex $args [expr {$idx + 1}]]
}
}
default {
# don't touch remaining arguments
}
}
incr idx
}
set hub_name ""
if {$tap_name != ""} {
set hub_name [lindex [split $tap_name .] 0].ipdbghub
} elseif {$pld_name != ""} {
set hub_name [lindex [split $pld_name .] 0].ipdbghub
} else {
echo "parsing arguments failed: no tap and no pld given."
return
}
eval $hub_name ipdbg stop -tool $tool_num
}
# END MIGRATION AIDS

View File

@ -53,6 +53,8 @@
enum gdb_output_flag {
/* GDB doesn't accept 'O' packets */
GDB_OUTPUT_NO,
/* GDB doesn't accept 'O' packets but accepts notifications */
GDB_OUTPUT_NOTIF,
/* GDB accepts 'O' packets */
GDB_OUTPUT_ALL,
};
@ -71,6 +73,8 @@ struct gdb_connection {
enum target_state frontend_state;
struct image *vflash_image;
bool closed;
/* set to prevent re-entrance from log messages during gdb_get_packet()
* and gdb_put_packet(). */
bool busy;
int noack_mode;
/* set flag to true if you want the next stepi to return immediately.
@ -1537,9 +1541,6 @@ static int gdb_error(struct connection *connection, int retval)
return ERROR_OK;
}
/* We don't have to worry about the default 2 second timeout for GDB packets,
* because GDB breaks up large memory reads into smaller reads.
*/
static int gdb_read_memory_packet(struct connection *connection,
char const *packet, int packet_size)
{
@ -3470,6 +3471,13 @@ static int gdb_v_packet(struct connection *connection,
if (strncmp(packet, "vFlashDone", 10) == 0) {
uint32_t written;
/* GDB command 'flash-erase' does not send a vFlashWrite,
* so nothing to write here. */
if (!gdb_connection->vflash_image) {
gdb_put_packet(connection, "OK", 2);
return ERROR_OK;
}
/* process the flashing buffer. No need to erase as GDB
* always issues a vFlashErase first. */
target_call_event_callbacks(target,
@ -3564,7 +3572,7 @@ static void gdb_log_callback(void *priv, const char *file, unsigned line,
struct connection *connection = priv;
struct gdb_connection *gdb_con = connection->priv;
if (gdb_con->output_flag == GDB_OUTPUT_NO)
if (gdb_con->output_flag != GDB_OUTPUT_ALL)
/* No out allowed */
return;
@ -3649,10 +3657,14 @@ static int gdb_input_inner(struct connection *connection)
retval = gdb_set_register_packet(connection, packet, packet_size);
break;
case 'm':
gdb_con->output_flag = GDB_OUTPUT_NOTIF;
retval = gdb_read_memory_packet(connection, packet, packet_size);
gdb_con->output_flag = GDB_OUTPUT_NO;
break;
case 'M':
gdb_con->output_flag = GDB_OUTPUT_NOTIF;
retval = gdb_write_memory_packet(connection, packet, packet_size);
gdb_con->output_flag = GDB_OUTPUT_NO;
break;
case 'z':
case 'Z':
@ -3743,9 +3755,9 @@ static int gdb_input_inner(struct connection *connection)
retval = gdb_detach(connection);
break;
case 'X':
gdb_con->output_flag = GDB_OUTPUT_NOTIF;
retval = gdb_write_memory_binary_packet(connection, packet, packet_size);
if (retval != ERROR_OK)
return retval;
gdb_con->output_flag = GDB_OUTPUT_NO;
break;
case 'k':
if (gdb_con->extended_protocol) {
@ -3843,19 +3855,51 @@ static int gdb_input(struct connection *connection)
return ERROR_OK;
}
/*
* Send custom notification packet as keep-alive during memory read/write.
*
* From gdb 7.0 (released 2009-10-06) an unknown notification received during
* memory read/write would be silently dropped.
* Before gdb 7.0 any character, with exclusion of "+-$", would be considered
* as junk and ignored.
* In both cases the reception will reset the timeout counter in gdb, thus
* working as a keep-alive.
* Check putpkt_binary() and getpkt_sane() in gdb commit
* 74531fed1f2d662debc2c209b8b3faddceb55960
*
* Enable remote debug in gdb with 'set debug remote 1' to either dump the junk
* characters in gdb pre-7.0 and the notification from gdb 7.0.
*/
static void gdb_async_notif(struct connection *connection)
{
static unsigned char count;
unsigned char checksum = 0;
char buf[22];
int len = sprintf(buf, "%%oocd_keepalive:%2.2x", count++);
for (int i = 1; i < len; i++)
checksum += buf[i];
len += sprintf(buf + len, "#%2.2x", checksum);
#ifdef _DEBUG_GDB_IO_
LOG_DEBUG("sending packet '%s'", buf);
#endif
gdb_write(connection, buf, len);
}
static void gdb_keep_client_alive(struct connection *connection)
{
struct gdb_connection *gdb_con = connection->priv;
if (gdb_con->busy) {
/* do not send packets, retry asap */
return;
}
switch (gdb_con->output_flag) {
case GDB_OUTPUT_NO:
/* no need for keep-alive */
break;
case GDB_OUTPUT_NOTIF:
/* send asynchronous notification */
gdb_async_notif(connection);
break;
case GDB_OUTPUT_ALL:
/* send an empty O packet */
gdb_output_con(connection, "");

View File

@ -15,22 +15,15 @@
#include "ipdbg.h"
#define IPDBG_BUFFER_SIZE 16384
#define IPDBG_MIN_NUM_OF_OPTIONS 2
#define IPDBG_MAX_NUM_OF_OPTIONS 14
#define IPDBG_MIN_NUM_OF_CREATE_OPTIONS 3
#define IPDBG_MAX_NUM_OF_CREATE_OPTIONS 10
#define IPDBG_NUM_OF_START_OPTIONS 4
#define IPDBG_NUM_OF_STOP_OPTIONS 2
#define IPDBG_NUM_OF_QUEUE_OPTIONS 2
#define IPDBG_MIN_DR_LENGTH 11
#define IPDBG_MAX_DR_LENGTH 13
#define IPDBG_TCP_PORT_STR_MAX_LENGTH 6
#define IPDBG_SCRATCH_MEMORY_SIZE 1024
#define IPDBG_EMPTY_DOWN_TRANSFERS 1024
#define IPDBG_CONSECUTIVE_UP_TRANSFERS 1024
#if IPDBG_SCRATCH_MEMORY_SIZE < IPDBG_EMPTY_DOWN_TRANSFERS
#error "scratch Memory must be at least IPDBG_EMPTY_DOWN_TRANSFERS"
#endif
#if IPDBG_SCRATCH_MEMORY_SIZE < IPDBG_CONSECUTIVE_UP_TRANSFERS
#error "scratch Memory must be at least IPDBG_CONSECUTIVE_UP_TRANSFERS"
#endif
/* private connection data for IPDBG */
struct ipdbg_fifo {
@ -75,6 +68,8 @@ struct ipdbg_hub {
uint32_t xoff_mask;
uint32_t tool_mask;
uint32_t last_dn_tool;
char *name;
size_t using_queue_size;
struct ipdbg_hub *next;
struct jtag_tap *tap;
struct connection **connections;
@ -247,73 +242,9 @@ static void ipdbg_add_hub(struct ipdbg_hub *hub)
for (ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next)
;
ihub->next = hub;
} else
} else {
ipdbg_first_hub = hub;
}
static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length,
struct ipdbg_virtual_ir_info *virtual_ir, struct ipdbg_hub **hub)
{
*hub = NULL;
struct ipdbg_hub *new_hub = calloc(1, sizeof(struct ipdbg_hub));
if (!new_hub)
goto mem_err_hub;
const size_t dreg_buffer_size = DIV_ROUND_UP(data_register_length, 8);
new_hub->max_tools = ipdbg_max_tools_from_data_register_length(data_register_length);
new_hub->scratch_memory.dr_out_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size);
new_hub->scratch_memory.dr_in_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size);
new_hub->scratch_memory.fields = calloc(IPDBG_SCRATCH_MEMORY_SIZE, sizeof(struct scan_field));
new_hub->connections = calloc(new_hub->max_tools, sizeof(struct connection *));
if (virtual_ir)
new_hub->scratch_memory.vir_out_val = calloc(1, DIV_ROUND_UP(virtual_ir->length, 8));
if (!new_hub->scratch_memory.dr_out_vals || !new_hub->scratch_memory.dr_in_vals ||
!new_hub->scratch_memory.fields || (virtual_ir && !new_hub->scratch_memory.vir_out_val) ||
!new_hub->connections)
goto mem_err2;
if (virtual_ir)
buf_set_u32(new_hub->scratch_memory.vir_out_val, 0, virtual_ir->length, virtual_ir->value);
new_hub->tap = tap;
new_hub->user_instruction = user_instruction;
new_hub->data_register_length = data_register_length;
new_hub->valid_mask = BIT(data_register_length - 1);
new_hub->xoff_mask = BIT(data_register_length - 2);
new_hub->tool_mask = (new_hub->xoff_mask - 1) >> 8;
new_hub->last_dn_tool = new_hub->tool_mask;
new_hub->virtual_ir = virtual_ir;
*hub = new_hub;
return ERROR_OK;
mem_err2:
free(new_hub->scratch_memory.vir_out_val);
free(new_hub->connections);
free(new_hub->scratch_memory.fields);
free(new_hub->scratch_memory.dr_in_vals);
free(new_hub->scratch_memory.dr_out_vals);
free(new_hub);
mem_err_hub:
free(virtual_ir);
LOG_ERROR("Out of memory");
return ERROR_FAIL;
}
static void ipdbg_free_hub(struct ipdbg_hub *hub)
{
if (!hub)
return;
free(hub->connections);
free(hub->virtual_ir);
free(hub->scratch_memory.dr_out_vals);
free(hub->scratch_memory.dr_in_vals);
free(hub->scratch_memory.fields);
free(hub->scratch_memory.vir_out_val);
free(hub);
}
}
static int ipdbg_remove_hub(struct ipdbg_hub *hub)
@ -335,6 +266,58 @@ static int ipdbg_remove_hub(struct ipdbg_hub *hub)
return ERROR_FAIL;
}
static void ipdbg_free_hub(struct ipdbg_hub *hub)
{
if (!hub)
return;
free(hub->connections);
free(hub->virtual_ir);
free(hub->name);
free(hub->scratch_memory.dr_out_vals);
free(hub->scratch_memory.dr_in_vals);
free(hub->scratch_memory.fields);
free(hub->scratch_memory.vir_out_val);
free(hub);
}
static struct ipdbg_hub *ipdbg_allocate_hub(uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir,
const char *name)
{
struct ipdbg_hub *new_hub = calloc(1, sizeof(struct ipdbg_hub));
if (!new_hub) {
LOG_ERROR("Out of memory");
return NULL;
}
new_hub->name = strdup(name);
if (!new_hub->name) {
free(new_hub);
LOG_ERROR("Out of memory");
return NULL;
}
const size_t dreg_buffer_size = DIV_ROUND_UP(data_register_length, 8);
uint32_t max_tools = ipdbg_max_tools_from_data_register_length(data_register_length);
new_hub->scratch_memory.dr_out_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size);
new_hub->scratch_memory.dr_in_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size);
new_hub->scratch_memory.fields = calloc(IPDBG_SCRATCH_MEMORY_SIZE, sizeof(struct scan_field));
new_hub->connections = calloc(max_tools, sizeof(struct connection *));
if (virtual_ir)
new_hub->scratch_memory.vir_out_val = calloc(1, DIV_ROUND_UP(virtual_ir->length, 8));
if (!new_hub->scratch_memory.dr_out_vals || !new_hub->scratch_memory.dr_in_vals ||
!new_hub->scratch_memory.fields || (virtual_ir && !new_hub->scratch_memory.vir_out_val) ||
!new_hub->connections) {
ipdbg_free_hub(new_hub);
LOG_ERROR("Out of memory");
return NULL;
}
return new_hub;
}
static void ipdbg_init_scan_field(struct scan_field *fields, uint8_t *in_value, int num_bits, const uint8_t *out_value)
{
fields->check_mask = NULL;
@ -470,7 +453,7 @@ static int ipdbg_shift_empty_data(struct ipdbg_hub *hub)
const size_t dreg_buffer_size = DIV_ROUND_UP(hub->data_register_length, 8);
memset(hub->scratch_memory.dr_out_vals, 0, dreg_buffer_size);
for (size_t i = 0; i < IPDBG_EMPTY_DOWN_TRANSFERS; ++i) {
for (size_t i = 0; i < hub->using_queue_size; ++i) {
ipdbg_init_scan_field(hub->scratch_memory.fields + i,
hub->scratch_memory.dr_in_vals + i * dreg_buffer_size,
hub->data_register_length,
@ -482,7 +465,7 @@ static int ipdbg_shift_empty_data(struct ipdbg_hub *hub)
if (retval == ERROR_OK) {
uint32_t up_data;
for (size_t i = 0; i < IPDBG_EMPTY_DOWN_TRANSFERS; ++i) {
for (size_t i = 0; i < hub->using_queue_size; ++i) {
up_data = buf_get_u32(hub->scratch_memory.dr_in_vals +
i * dreg_buffer_size, 0,
hub->data_register_length);
@ -531,8 +514,8 @@ static int ipdbg_jtag_transfer_bytes(struct ipdbg_hub *hub,
return ERROR_FAIL;
const size_t dreg_buffer_size = DIV_ROUND_UP(hub->data_register_length, 8);
size_t num_tx = (connection->dn_fifo.count < IPDBG_CONSECUTIVE_UP_TRANSFERS) ?
connection->dn_fifo.count : IPDBG_CONSECUTIVE_UP_TRANSFERS;
size_t num_tx = (connection->dn_fifo.count < hub->using_queue_size) ?
connection->dn_fifo.count : hub->using_queue_size;
for (size_t i = 0; i < num_tx; ++i) {
uint32_t dn_data = hub->valid_mask | ((tool & hub->tool_mask) << 8) |
@ -760,62 +743,18 @@ static const struct service_driver ipdbg_service_driver = {
.keep_client_alive_handler = NULL,
};
static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instruction,
uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool)
static struct ipdbg_hub *ipdbg_get_hub_by_name(const char *name)
{
LOG_INFO("starting ipdbg service on port %d for tool %d", port, tool);
struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir);
if (hub) {
free(virtual_ir);
if (hub->data_register_length != data_register_length) {
LOG_DEBUG("hub must have the same data_register_length for all tools");
return ERROR_FAIL;
}
} else {
int retval = ipdbg_create_hub(tap, user_instruction, data_register_length, virtual_ir, &hub);
if (retval != ERROR_OK)
return retval;
struct ipdbg_hub *hub = NULL;
for (hub = ipdbg_first_hub; hub; hub = hub->next) {
if (strcmp(hub->name, name) == 0)
break;
}
return hub;
};
struct ipdbg_service *service = NULL;
int retval = ipdbg_create_service(hub, tool, &service, port);
if (retval != ERROR_OK || !service) {
if (hub->active_services == 0 && hub->active_connections == 0)
ipdbg_free_hub(hub);
return ERROR_FAIL;
}
char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH];
snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", port);
retval = add_service(&ipdbg_service_driver, port_str_buffer, 1, service);
if (retval == ERROR_OK) {
ipdbg_add_service(service);
if (hub->active_services == 0 && hub->active_connections == 0)
ipdbg_add_hub(hub);
hub->active_services++;
} else {
if (hub->active_services == 0 && hub->active_connections == 0)
ipdbg_free_hub(hub);
free(service);
}
return retval;
}
static int ipdbg_stop(struct jtag_tap *tap, uint32_t user_instruction,
struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool)
static int ipdbg_stop_service(struct ipdbg_service *service)
{
struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir);
free(virtual_ir);
if (!hub)
return ERROR_FAIL;
struct ipdbg_service *service = ipdbg_find_service(hub, tool);
if (!service)
return ERROR_FAIL;
int retval = ipdbg_remove_service(service);
if (retval != ERROR_OK) {
LOG_ERROR("BUG: ipdbg_remove_service failed");
@ -831,41 +770,271 @@ static int ipdbg_stop(struct jtag_tap *tap, uint32_t user_instruction,
LOG_ERROR("BUG: remove_service failed");
return retval;
}
hub->active_services--;
if (hub->active_connections == 0 && hub->active_services == 0) {
retval = ipdbg_remove_hub(hub);
if (retval != ERROR_OK) {
LOG_ERROR("BUG: ipdbg_remove_hub failed");
return retval;
}
ipdbg_free_hub(hub);
}
return ERROR_OK;
}
COMMAND_HANDLER(handle_ipdbg_command)
int ipdbg_server_free(void)
{
struct jtag_tap *tap = NULL;
int retval = ERROR_OK;
for (struct ipdbg_hub *hub = ipdbg_first_hub; hub;) {
for (uint8_t tool = 0; tool < hub->max_tools; ++tool) {
struct ipdbg_service *service = ipdbg_find_service(hub, tool);
if (service) {
int new_retval = ipdbg_stop_service(service);
if (new_retval != ERROR_OK)
retval = new_retval;
hub->active_services--;
}
}
struct ipdbg_hub *next_hub = hub->next;
int new_retval = ipdbg_remove_hub(hub);
if (new_retval != ERROR_OK)
retval = new_retval;
ipdbg_free_hub(hub);
hub = next_hub;
}
return retval;
}
static int ipdbg_start(struct ipdbg_hub *hub, uint16_t port, uint8_t tool)
{
LOG_INFO("starting ipdbg service on port %d for tool %d", port, tool);
struct ipdbg_service *service = NULL;
int retval = ipdbg_create_service(hub, tool, &service, port);
if (retval != ERROR_OK || !service) {
if (hub->active_services == 0 && hub->active_connections == 0)
ipdbg_free_hub(hub);
return ERROR_FAIL;
}
char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH];
snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", port);
retval = add_service(&ipdbg_service_driver, port_str_buffer, 1, service);
if (retval != ERROR_OK) {
free(service);
return retval;
}
ipdbg_add_service(service);
hub->active_services++;
return ERROR_OK;
}
COMMAND_HANDLER(handle_ipdbg_start_command)
{
struct ipdbg_hub *hub = CMD_DATA;
uint16_t port = 4242;
uint8_t tool = 1;
if (CMD_ARGC > IPDBG_NUM_OF_START_OPTIONS)
return ERROR_COMMAND_SYNTAX_ERROR;
for (unsigned int i = 0; i < CMD_ARGC; ++i) {
if (strcmp(CMD_ARGV[i], "-port") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u16, i, port, "port number");
} else if (strcmp(CMD_ARGV[i], "-tool") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool");
} else {
command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]);
return ERROR_FAIL;
}
}
return ipdbg_start(hub, port, tool);
}
static int ipdbg_stop(struct ipdbg_hub *hub, uint8_t tool)
{
struct ipdbg_service *service = ipdbg_find_service(hub, tool);
if (!service) {
LOG_ERROR("No service for hub '%s'/tool %d found", hub->name, tool);
return ERROR_FAIL;
}
int retval = ipdbg_stop_service(service);
hub->active_services--;
LOG_INFO("stopped ipdbg service for tool %d", tool);
return retval;
}
COMMAND_HANDLER(handle_ipdbg_stop_command)
{
struct ipdbg_hub *hub = CMD_DATA;
uint8_t tool = 1;
if (CMD_ARGC > IPDBG_NUM_OF_STOP_OPTIONS)
return ERROR_COMMAND_SYNTAX_ERROR;
for (unsigned int i = 0; i < CMD_ARGC; ++i) {
if (strcmp(CMD_ARGV[i], "-tool") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool");
} else {
command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]);
return ERROR_FAIL;
}
}
return ipdbg_stop(hub, tool);
}
static const struct command_registration ipdbg_hostserver_subcommand_handlers[] = {
{
.name = "start",
.mode = COMMAND_EXEC,
.handler = handle_ipdbg_start_command,
.help = "Starts a IPDBG Host server.",
.usage = "-tool number -port port"
}, {
.name = "stop",
.mode = COMMAND_EXEC,
.handler = handle_ipdbg_stop_command,
.help = "Stops a IPDBG Host server.",
.usage = "-tool number"
},
COMMAND_REGISTRATION_DONE
};
static COMMAND_HELPER(ipdbg_config_queuing, struct ipdbg_hub *hub, unsigned int size)
{
if (!hub)
return ERROR_FAIL;
if (hub->active_connections) {
command_print(CMD, "Configuration change not allowed when hub has active connections");
return ERROR_FAIL;
}
if (size == 0 || size > IPDBG_SCRATCH_MEMORY_SIZE) {
command_print(CMD, "queuing size out of range! Must be 0 < size <= %d", IPDBG_SCRATCH_MEMORY_SIZE);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
hub->using_queue_size = size;
return ERROR_OK;
}
COMMAND_HANDLER(handle_ipdbg_cfg_queuing_command)
{
struct ipdbg_hub *hub = CMD_DATA;
unsigned int size;
if (CMD_ARGC != IPDBG_NUM_OF_QUEUE_OPTIONS)
return ERROR_COMMAND_SYNTAX_ERROR;
for (unsigned int i = 0; i < CMD_ARGC; ++i) {
if (strcmp(CMD_ARGV[i], "-size") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(uint, i, size, "size");
} else {
command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]);
return ERROR_FAIL;
}
}
return CALL_COMMAND_HANDLER(ipdbg_config_queuing, hub, size);
}
static const struct command_registration ipdbg_hub_subcommand_handlers[] = {
{
.name = "ipdbg",
.mode = COMMAND_EXEC,
.help = "IPDBG Hub commands.",
.usage = "",
.chain = ipdbg_hostserver_subcommand_handlers
},
{
.name = "queuing",
.handler = handle_ipdbg_cfg_queuing_command,
.mode = COMMAND_ANY,
.help = "configures queuing between IPDBG Host and Hub.",
.usage = "-size size",
},
COMMAND_REGISTRATION_DONE
};
static int ipdbg_register_hub_command(struct ipdbg_hub *hub, struct command_invocation *cmd)
{
Jim_Interp *interp = CMD_CTX->interp;
/* does this command exist? */
Jim_Cmd *jcmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, hub->name, -1), JIM_NONE);
if (jcmd) {
LOG_ERROR("cannot create Hub because a command with name '%s' already exists", hub->name);
return ERROR_FAIL;
}
const struct command_registration obj_commands[] = {
{
.name = hub->name,
.mode = COMMAND_EXEC,
.help = "IPDBG Hub command group.",
.usage = "",
.chain = ipdbg_hub_subcommand_handlers
},
COMMAND_REGISTRATION_DONE
};
return register_commands_with_data(CMD_CTX, NULL, obj_commands, hub);
}
static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length,
struct ipdbg_virtual_ir_info *virtual_ir, const char *name, struct command_invocation *cmd)
{
struct ipdbg_hub *new_hub = ipdbg_allocate_hub(data_register_length, virtual_ir, name);
if (!new_hub)
return ERROR_FAIL;
if (virtual_ir)
buf_set_u32(new_hub->scratch_memory.vir_out_val, 0, virtual_ir->length, virtual_ir->value);
new_hub->tap = tap;
new_hub->user_instruction = user_instruction;
new_hub->data_register_length = data_register_length;
new_hub->valid_mask = BIT(data_register_length - 1);
new_hub->xoff_mask = BIT(data_register_length - 2);
new_hub->tool_mask = (new_hub->xoff_mask - 1) >> 8;
new_hub->last_dn_tool = new_hub->tool_mask;
new_hub->virtual_ir = virtual_ir;
new_hub->max_tools = ipdbg_max_tools_from_data_register_length(data_register_length);
new_hub->using_queue_size = IPDBG_SCRATCH_MEMORY_SIZE;
int retval = ipdbg_register_hub_command(new_hub, cmd);
if (retval != ERROR_OK) {
LOG_ERROR("Creating hub failed");
ipdbg_free_hub(new_hub);
return ERROR_FAIL;
}
ipdbg_add_hub(new_hub);
return ERROR_OK;
}
COMMAND_HANDLER(handle_ipdbg_create_hub_command)
{
struct jtag_tap *tap = NULL;
uint32_t user_instruction = 0x00;
uint8_t data_register_length = IPDBG_MAX_DR_LENGTH;
bool start = true;
bool hub_configured = false;
bool has_virtual_ir = false;
uint32_t virtual_ir_instruction = 0x00e;
uint32_t virtual_ir_length = 5;
uint32_t virtual_ir_value = 0x11;
struct ipdbg_virtual_ir_info *virtual_ir = NULL;
int user_num = 1;
bool hub_configured = false;
if ((CMD_ARGC < IPDBG_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > IPDBG_MAX_NUM_OF_OPTIONS))
if (CMD_ARGC < IPDBG_MIN_NUM_OF_CREATE_OPTIONS || CMD_ARGC > IPDBG_MAX_NUM_OF_CREATE_OPTIONS)
return ERROR_COMMAND_SYNTAX_ERROR;
for (unsigned int i = 0; i < CMD_ARGC; ++i) {
const char *hub_name = CMD_ARGV[0];
for (unsigned int i = 1; i < CMD_ARGC; ++i) {
if (strcmp(CMD_ARGV[i], "-tap") == 0) {
if (i + 1 >= CMD_ARGC || CMD_ARGV[i + 1][0] == '-') {
command_print(CMD, "no TAP given");
command_print(CMD, "no TAP name given");
return ERROR_FAIL;
}
tap = jtag_tap_by_string(CMD_ARGV[i + 1]);
@ -874,7 +1043,7 @@ COMMAND_HANDLER(handle_ipdbg_command)
return ERROR_FAIL;
}
++i;
} else if (strcmp(CMD_ARGV[i], "-hub") == 0) {
} else if (strcmp(CMD_ARGV[i], "-ir") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u32, i, user_instruction, "ir_value to select hub");
hub_configured = true;
COMMAND_PARSE_OPTIONAL_NUMBER(u8, i, data_register_length);
@ -917,20 +1086,11 @@ COMMAND_HANDLER(handle_ipdbg_command)
COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_length);
COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_instruction);
has_virtual_ir = true;
} else if (strcmp(CMD_ARGV[i], "-port") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u16, i, port, "port number");
} else if (strcmp(CMD_ARGV[i], "-tool") == 0) {
COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool");
} else if (strcmp(CMD_ARGV[i], "-stop") == 0) {
start = false;
} else if (strcmp(CMD_ARGV[i], "-start") == 0) {
start = true;
} else {
command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]);
return ERROR_FAIL;
}
}
if (!tap) {
command_print(CMD, "no valid tap selected");
return ERROR_FAIL;
@ -941,8 +1101,8 @@ COMMAND_HANDLER(handle_ipdbg_command)
return ERROR_FAIL;
}
if (tool >= ipdbg_max_tools_from_data_register_length(data_register_length)) {
command_print(CMD, "Tool: %d is invalid", tool);
if (ipdbg_get_hub_by_name(hub_name)) {
LOG_ERROR("IPDBG hub with name '%s' already exists", hub_name);
return ERROR_FAIL;
}
@ -957,20 +1117,38 @@ COMMAND_HANDLER(handle_ipdbg_command)
virtual_ir->value = virtual_ir_value;
}
if (start)
return ipdbg_start(port, tap, user_instruction, data_register_length, virtual_ir, tool);
else
return ipdbg_stop(tap, user_instruction, virtual_ir, tool);
if (ipdbg_find_hub(tap, user_instruction, virtual_ir)) {
LOG_ERROR("IPDBG hub for given TAP and user-instruction already exists");
free(virtual_ir);
return ERROR_FAIL;
}
int retval = ipdbg_create_hub(tap, user_instruction, data_register_length, virtual_ir, hub_name, cmd);
if (retval != ERROR_OK)
free(virtual_ir);
return retval;
}
static const struct command_registration ipdbg_config_command_handlers[] = {
{
.name = "create-hub",
.mode = COMMAND_ANY,
.handler = handle_ipdbg_create_hub_command,
.help = "create a IPDBG Hub",
.usage = "name.ipdbghub (-tap device.tap -ir ir_value [dr_length] |"
" -pld name.pld [user]) [-vir [vir_value [length [instr_code]]]]",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration ipdbg_command_handlers[] = {
{
.name = "ipdbg",
.handler = handle_ipdbg_command,
.mode = COMMAND_EXEC,
.help = "Starts or stops an IPDBG JTAG-Host server.",
.usage = "[-start|-stop] -tap device.tap -hub ir_value [dr_length]"
" [-port number] [-tool number] [-vir [vir_value [length [instr_code]]]]",
.mode = COMMAND_ANY,
.help = "IPDBG Hub/Host commands.",
.usage = "",
.chain = ipdbg_config_command_handlers,
},
COMMAND_REGISTRATION_DONE
};

View File

@ -7,5 +7,6 @@
#include <helper/command.h>
int ipdbg_register_commands(struct command_context *cmd_ctx);
int ipdbg_server_free(void);
#endif /* OPENOCD_IPDBG_IPDBG_H */

View File

@ -23,6 +23,7 @@
#include "openocd.h"
#include "tcl_server.h"
#include "telnet_server.h"
#include "ipdbg.h"
#include <signal.h>
@ -714,6 +715,7 @@ void server_free(void)
tcl_service_free();
telnet_service_free();
jsp_service_free();
ipdbg_server_free();
free(bindto_name);
}

View File

@ -93,6 +93,7 @@ static int aarch64_restore_system_control_reg(struct target *target)
case ARM_MODE_HYP:
case ARM_MODE_UND:
case ARM_MODE_SYS:
case ARM_MODE_MON:
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
break;
@ -172,6 +173,7 @@ static int aarch64_mmu_modify(struct target *target, int enable)
case ARM_MODE_HYP:
case ARM_MODE_UND:
case ARM_MODE_SYS:
case ARM_MODE_MON:
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
break;
@ -1043,6 +1045,7 @@ static int aarch64_post_debug_entry(struct target *target)
case ARM_MODE_HYP:
case ARM_MODE_UND:
case ARM_MODE_SYS:
case ARM_MODE_MON:
instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0);
break;
@ -2891,13 +2894,8 @@ static int aarch64_jim_configure(struct target *target, struct jim_getopt_info *
* options, JIM_OK if it correctly parsed the topmost option
* and JIM_ERR if an error occurred during parameter evaluation.
* For JIM_CONTINUE, we check our own params.
*
* adiv5_jim_configure() assumes 'private_config' to point to
* 'struct adiv5_private_config'. Override 'private_config'!
*/
target->private_config = &pc->adiv5_config;
e = adiv5_jim_configure(target, goi);
target->private_config = pc;
e = adiv5_jim_configure_ext(target, goi, &pc->adiv5_config, ADI_CONFIGURE_DAP_COMPULSORY);
if (e != JIM_CONTINUE)
return e;

View File

@ -84,16 +84,8 @@ static void swd_clear_sticky_errors(struct adiv5_dap *dap)
static int swd_run_inner(struct adiv5_dap *dap)
{
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
int retval;
retval = swd->run();
if (retval != ERROR_OK) {
/* fault response */
dap->do_reconnect = true;
}
return retval;
return swd->run();
}
static inline int check_sync(struct adiv5_dap *dap)
@ -105,14 +97,13 @@ static inline int check_sync(struct adiv5_dap *dap)
static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned int reg)
{
/* Only register address 0 (ADIv6 only) and 4 are banked. */
if ((reg & 0xf) > 4)
if (is_adiv6(dap) ? (reg & 0xf) > 4 : (reg & 0xf) != 4)
return ERROR_OK;
uint32_t sel = (reg >> 4) & DP_SELECT_DPBANK;
/* DP register 0 is not mapped according to ADIv5
* whereas ADIv6 ensures DPBANKSEL = 0 after line reset */
if ((dap->select_valid || ((reg & 0xf) == 0 && dap->select_dpbanksel_valid))
/* ADIv6 ensures DPBANKSEL = 0 after line reset */
if ((dap->select_valid || (is_adiv6(dap) && dap->select_dpbanksel_valid))
&& (sel == (dap->select & DP_SELECT_DPBANK)))
return ERROR_OK;
@ -146,7 +137,7 @@ static int swd_queue_dp_read_inner(struct adiv5_dap *dap, unsigned int reg,
static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg,
uint32_t data)
{
int retval;
int retval = ERROR_OK;
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
assert(swd);
@ -167,7 +158,11 @@ static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg,
if (reg == DP_SELECT1)
dap->select = ((uint64_t)data << 32) | (dap->select & 0xffffffffull);
/* DP_ABORT write is not banked.
* Prevent writing DP_SELECT before as it would fail on locked up DP */
if (reg != DP_ABORT)
retval = swd_queue_dp_bankselect(dap, reg);
if (retval == ERROR_OK) {
swd->write_reg(swd_cmd(false, false, reg), data, 0);
@ -285,15 +280,15 @@ static int swd_multidrop_select(struct adiv5_dap *dap)
swd_multidrop_selected_dap = NULL;
if (retry > 3) {
LOG_ERROR("Failed to select multidrop %s", adiv5_dap_name(dap));
dap->do_reconnect = true;
return retval;
}
LOG_DEBUG("Failed to select multidrop %s, retrying...",
adiv5_dap_name(dap));
/* we going to retry localy, do not ask for full reconnect */
dap->do_reconnect = false;
}
dap->do_reconnect = false;
return retval;
}
@ -632,7 +627,13 @@ static int swd_run(struct adiv5_dap *dap)
swd_finish_read(dap);
return swd_run_inner(dap);
retval = swd_run_inner(dap);
if (retval != ERROR_OK) {
/* fault response */
dap->do_reconnect = true;
}
return retval;
}
/** Put the SWJ-DP back to JTAG mode */

View File

@ -2424,11 +2424,12 @@ err_no_param:
return JIM_ERR;
}
int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi)
int adiv5_jim_configure_ext(struct target *target, struct jim_getopt_info *goi,
struct adiv5_private_config *pc, enum adiv5_configure_dap_optional optional)
{
struct adiv5_private_config *pc;
int e;
if (!pc) {
pc = (struct adiv5_private_config *)target->private_config;
if (!pc) {
pc = calloc(1, sizeof(struct adiv5_private_config));
@ -2439,7 +2440,9 @@ int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi)
pc->ap_num = DP_APSEL_INVALID;
target->private_config = pc;
}
}
if (optional == ADI_CONFIGURE_DAP_COMPULSORY)
target->has_dap = true;
e = adiv5_jim_spot_configure(goi, &pc->dap, &pc->ap_num, NULL);
@ -2455,11 +2458,17 @@ int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi)
}
target->tap = pc->dap->tap;
target->dap_configured = true;
target->has_dap = true;
}
return JIM_OK;
}
int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi)
{
return adiv5_jim_configure_ext(target, goi, NULL, ADI_CONFIGURE_DAP_COMPULSORY);
}
int adiv5_verify_config(struct adiv5_private_config *pc)
{
if (!pc)

View File

@ -788,6 +788,15 @@ struct adiv5_private_config {
};
extern int adiv5_verify_config(struct adiv5_private_config *pc);
enum adiv5_configure_dap_optional {
ADI_CONFIGURE_DAP_COMPULSORY = false,
ADI_CONFIGURE_DAP_OPTIONAL = true
};
extern int adiv5_jim_configure_ext(struct target *target, struct jim_getopt_info *goi,
struct adiv5_private_config *pc,
enum adiv5_configure_dap_optional optional);
extern int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi);
struct adiv5_mem_ap_spot {

View File

@ -194,11 +194,11 @@ static const char *mem_ap_get_gdb_arch(const struct target *target)
* reg[24]: 32 bits, fps
* reg[25]: 32 bits, cpsr
*
* Set 'exist' only to reg[0..15], so initial response to GDB is correct
* GDB requires only reg[0..15]
*/
#define NUM_REGS 26
#define NUM_GDB_REGS 16
#define MAX_REG_SIZE 96
#define REG_EXIST(n) ((n) < 16)
#define REG_SIZE(n) ((((n) >= 16) && ((n) < 24)) ? 96 : 32)
struct mem_ap_alloc_reg_list {
@ -218,14 +218,14 @@ static int mem_ap_get_gdb_reg_list(struct target *target, struct reg **reg_list[
}
*reg_list = mem_ap_alloc->reg_list;
*reg_list_size = NUM_REGS;
*reg_list_size = (reg_class == REG_CLASS_ALL) ? NUM_REGS : NUM_GDB_REGS;
struct reg *regs = mem_ap_alloc->regs;
for (int i = 0; i < NUM_REGS; i++) {
regs[i].number = i;
regs[i].value = mem_ap_alloc->regs_value;
regs[i].size = REG_SIZE(i);
regs[i].exist = REG_EXIST(i);
regs[i].exist = true;
regs[i].type = &mem_ap_reg_arch_type;
(*reg_list)[i] = &regs[i];
}

View File

@ -161,6 +161,67 @@ static const struct {
#define MIPS32_NUM_REGS ARRAY_SIZE(mips32_regs)
#define zero 0
#define AT 1
#define v0 2
#define v1 3
#define a0 4
#define a1 5
#define a2 6
#define a3 7
#define t0 8
#define t1 9
#define t2 10
#define t3 11
#define t4 12
#define t5 13
#define t6 14
#define t7 15
#define ta0 12 /* alias for $t4 */
#define ta1 13 /* alias for $t5 */
#define ta2 14 /* alias for $t6 */
#define ta3 15 /* alias for $t7 */
#define s0 16
#define s1 17
#define s2 18
#define s3 19
#define s4 20
#define s5 21
#define s6 22
#define s7 23
#define s8 30 /* == fp */
#define t8 24
#define t9 25
#define k0 26
#define k1 27
#define gp 28
#define sp 29
#define fp 30
#define ra 31
static const struct {
const char *name;
} mips32_dsp_regs[MIPS32NUMDSPREGS] = {
{ "hi0"},
{ "hi1"},
{ "hi2"},
{ "hi3"},
{ "lo0"},
{ "lo1"},
{ "lo2"},
{ "lo3"},
{ "control"},
};
static int mips32_get_core_reg(struct reg *reg)
{
int retval;
@ -201,6 +262,61 @@ static int mips32_set_core_reg(struct reg *reg, uint8_t *buf)
return ERROR_OK;
}
/**
* mips32_set_all_fpr_width - Set the width of all floating-point registers
* @param[in] mips32: MIPS32 common structure
* @param[in] fp64: Flag indicating whether to set the width to 64 bits (double precision)
*
* @brief Sets the width of all floating-point registers based on the specified flag.
*/
static void mips32_set_all_fpr_width(struct mips32_common *mips32, bool fp64)
{
struct reg_cache *cache = mips32->core_cache;
struct reg *reg_list = cache->reg_list;
int i;
for (i = MIPS32_REGLIST_FP_INDEX; i < (MIPS32_REGLIST_FP_INDEX + MIPS32_REG_FP_COUNT); i++) {
reg_list[i].size = fp64 ? 64 : 32;
reg_list[i].reg_data_type->type = fp64 ? REG_TYPE_IEEE_DOUBLE : REG_TYPE_IEEE_SINGLE;
}
}
/**
* mips32_detect_fpr_mode_change - Detect changes in floating-point register mode
* @param[in] mips32: MIPS32 common structure
* @param[in] cp0_status: Value of the CP0 status register
*
* @brief Detects changes in the floating-point register mode based on the CP0 status register.
* If changes are detected, it updates the internal state
* and logs a warning message indicating the mode change.
*/
static void mips32_detect_fpr_mode_change(struct mips32_common *mips32, uint32_t cp0_status)
{
if (!mips32->fp_imp)
return;
/* CP0.Status.FR indicates the working mode of floating-point register.
* When FP = 0, fpr can contain any 32bit data type,
* 64bit data types are stored in even-odd register pairs.
* When FP = 1, fpr can contain any data types.*/
bool fpu_in_64bit = ((cp0_status & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0);
/* CP0.Status.CU1 indicated whether CoProcessor1(which is FPU) is present. */
bool fp_enabled = ((cp0_status & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0);
if (mips32->fpu_in_64bit != fpu_in_64bit) {
mips32->fpu_in_64bit = fpu_in_64bit;
mips32_set_all_fpr_width(mips32, fpu_in_64bit);
LOG_WARNING("** FP mode changed to %sbit, you must reconnect GDB **", fpu_in_64bit ? "64" : "32");
}
if (mips32->fpu_enabled != fp_enabled) {
mips32->fpu_enabled = fp_enabled;
const char *s = fp_enabled ? "enabled" : "disabled";
LOG_WARNING("** FP is %s, register update %s **", s, s);
}
}
static int mips32_read_core_reg(struct target *target, unsigned int num)
{
unsigned int cnum;
@ -217,6 +333,8 @@ static int mips32_read_core_reg(struct target *target, unsigned int num)
cnum = num - MIPS32_REGLIST_C0_INDEX;
reg_value = mips32->core_regs.cp0[cnum];
buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value);
if (cnum == MIPS32_REG_C0_STATUS_INDEX)
mips32_detect_fpr_mode_change(mips32, reg_value);
} else if (num >= MIPS32_REGLIST_FPC_INDEX) {
/* FPCR */
cnum = num - MIPS32_REGLIST_FPC_INDEX;
@ -258,6 +376,8 @@ static int mips32_write_core_reg(struct target *target, unsigned int num)
cnum = num - MIPS32_REGLIST_C0_INDEX;
reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32);
mips32->core_regs.cp0[cnum] = (uint32_t)reg_value;
if (cnum == MIPS32_REG_C0_STATUS_INDEX)
mips32_detect_fpr_mode_change(mips32, reg_value);
} else if (num >= MIPS32_REGLIST_FPC_INDEX) {
/* FPCR */
cnum = num - MIPS32_REGLIST_FPC_INDEX;
@ -926,8 +1046,8 @@ static int mips32_read_config_fpu(struct mips32_common *mips32, struct mips_ejta
mips32->fp_imp = MIPS32_FP_IMP_NONE;
return ERROR_OK;
}
uint32_t status_value;
bool status_fr, status_cu1;
uint32_t fir_value, status_value;
bool fpu_in_64bit, fp_enabled;
retval = mips32_cp0_read(ejtag_info, &status_value, MIPS32_C0_STATUS, 0);
if (retval != ERROR_OK) {
@ -935,20 +1055,34 @@ static int mips32_read_config_fpu(struct mips32_common *mips32, struct mips_ejta
return retval;
}
status_fr = (status_value >> MIPS32_CP0_STATUS_FR_SHIFT) & 0x1;
status_cu1 = (status_value >> MIPS32_CP0_STATUS_CU1_SHIFT) & 0x1;
if (status_cu1) {
/* TODO: read fpu(cp1) config register for current operating mode.
* Now its set to 32 bits by default. */
snprintf(buf, sizeof(buf), "yes");
fp_imp = MIPS32_FP_IMP_32;
fpu_in_64bit = (status_value & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0;
fp_enabled = (status_value & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0;
if (fp_enabled) {
retval = mips32_cp1_control_read(ejtag_info, &fir_value, 0);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to read cp1 FIR register");
return retval;
}
if ((fir_value >> MIPS32_CP1_FIR_F64_SHIFT) & 0x1)
fp_imp++;
} else {
/* This is the only condition that writes to buf */
snprintf(buf, sizeof(buf), "yes, disabled");
fp_imp = MIPS32_FP_IMP_UNKNOWN;
}
mips32->fpu_in_64bit = status_fr;
mips32->fpu_enabled = status_cu1;
mips32->fpu_in_64bit = fpu_in_64bit;
mips32->fpu_enabled = fp_enabled;
mips32_set_all_fpr_width(mips32, fpu_in_64bit);
/* If fpu is not disabled, print out more information */
if (!buf[0])
snprintf(buf, sizeof(buf), "yes, %sbit (%s, working in %sbit)",
fp_imp == MIPS32_FP_IMP_64 ? "64" : "32",
fp_enabled ? "enabled" : "disabled",
fpu_in_64bit ? "64" : "32");
LOG_USER("FPU implemented: %s", buf);
mips32->fp_imp = fp_imp;
@ -1544,6 +1678,204 @@ COMMAND_HANDLER(mips32_handle_cp0_command)
return retval;
}
/**
* mips32_dsp_enable - Enable access to DSP registers
* @param[in] ctx: Context information for the pracc queue
* @param[in] isa: Instruction Set Architecture identifier
*
* @brief Enables access to DSP registers by modifying the status register.
*
* This function adds instructions to the context queue for enabling
* access to DSP registers by modifying the status register.
*/
static void mips32_dsp_enable(struct pracc_queue_info *ctx, int isa)
{
/* Save Status Register */
/* move status to $9 (t1) 2*/
pracc_add(ctx, 0, MIPS32_MFC0(isa, 9, 12, 0));
/* Read it again in order to modify it */
/* move status to $0 (t0) 3*/
pracc_add(ctx, 0, MIPS32_MFC0(isa, 8, 12, 0));
/* Enable access to DSP registers by setting MX bit in status register */
/* $15 = MIPS32_PRACC_STACK 4/5/6*/
pracc_add(ctx, 0, MIPS32_LUI(isa, 15, UPPER16(MIPS32_DSP_ENABLE)));
pracc_add(ctx, 0, MIPS32_ORI(isa, 15, 15, LOWER16(MIPS32_DSP_ENABLE)));
pracc_add(ctx, 0, MIPS32_ISA_OR(8, 8, 15));
/* Enable DSP - update status registers 7*/
pracc_add(ctx, 0, MIPS32_MTC0(isa, 8, 12, 0));
}
/**
* mips32_dsp_restore - Restore DSP status registers to the previous setting
* @param[in] ctx: Context information pracc queue
* @param[in] isa: isa identifier
*
* @brief Restores the DSP status registers to their previous setting.
*
* This function adds instructions to the context queue for restoring the DSP
* status registers to their values before the operation.
*/
static void mips32_dsp_restore(struct pracc_queue_info *ctx, int isa)
{
pracc_add(ctx, 0, MIPS32_MTC0(isa, 9, 12, 0)); /* Restore status registers to previous setting */
pracc_add(ctx, 0, MIPS32_NOP); /* nop */
}
/**
* mips32_pracc_read_dsp_reg - Read a value from a MIPS32 DSP register
* @param[in] ejtag_info: EJTAG information structure
* @param[out] val: Pointer to store the read value
* @param[in] reg: Index of the DSP register to read
*
* @brief Reads the value from the specified MIPS32 DSP register using EJTAG access.
*
* This function initiates a sequence of instructions to read the value from the
* specified DSP register. It will enable dsp module if its not enabled
* and restoring the status registers after the read operation.
*
* @return ERROR_OK on success; error code on failure.
*/
static int mips32_pracc_read_dsp_reg(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t reg)
{
int isa = 0;
struct pracc_queue_info ctx = {
.max_code = 48,
.ejtag_info = ejtag_info
};
uint32_t dsp_read_code[] = {
MIPS32_MFHI(isa, t0), /* mfhi t0 ($ac0) - OPCODE - 0x00004010 */
MIPS32_DSP_MFHI(t0, 1), /* mfhi t0,$ac1 - OPCODE - 0x00204010 */
MIPS32_DSP_MFHI(t0, 2), /* mfhi t0,$ac2 - OPCODE - 0x00404010 */
MIPS32_DSP_MFHI(t0, 3), /* mfhi t0,$ac3 - OPCODE - 0x00604010*/
MIPS32_MFLO(isa, t0), /* mflo t0 ($ac0) - OPCODE - 0x00004012 */
MIPS32_DSP_MFLO(t0, 1), /* mflo t0,$ac1 - OPCODE - 0x00204012 */
MIPS32_DSP_MFLO(t0, 2), /* mflo t0,$ac2 - OPCODE - 0x00404012 */
MIPS32_DSP_MFLO(t0, 3), /* mflo t0,$ac3 - OPCODE - 0x00604012 */
MIPS32_DSP_RDDSP(t0, 0x3F), /* rddsp t0, 0x3f (DSPCtl) - OPCODE - 0x7c3f44b8 */
};
/* Check status register to determine if dsp register access is enabled */
/* Get status register so it can be restored later */
ctx.pracc_list = NULL;
/* Init context queue */
pracc_queue_init(&ctx);
if (ctx.retval != ERROR_OK)
goto exit;
/* Enables DSP whether its already enabled or not */
mips32_dsp_enable(&ctx, isa);
/* move AC or Control to $8 (t0) 8*/
pracc_add(&ctx, 0, dsp_read_code[reg]);
/* Restore status registers to previous setting */
mips32_dsp_restore(&ctx, isa);
/* $15 = MIPS32_PRACC_BASE_ADDR 1*/
pracc_add(&ctx, 0, MIPS32_LUI(isa, 15, PRACC_UPPER_BASE_ADDR));
/* store $8 to pracc_out 10*/
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, MIPS32_SW(isa, 8, PRACC_OUT_OFFSET, 15));
/* move COP0 DeSave to $15 11*/
pracc_add(&ctx, 0, MIPS32_MFC0(isa, 15, 31, 0));
/* restore upper 16 of $8 12*/
pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(ejtag_info->reg8)));
/* restore lower 16 of $8 13*/
pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(ejtag_info->reg8)));
/* restore upper 16 of $9 14*/
pracc_add(&ctx, 0, MIPS32_LUI(isa, 9, UPPER16(ejtag_info->reg9)));
pracc_add(&ctx, 0, MIPS32_SYNC(isa));
/* jump to start 18*/
pracc_add(&ctx, 0, MIPS32_B(isa, NEG16(ctx.code_count + 1)));
/* restore lower 16 of $9 15*/
pracc_add(&ctx, 0, MIPS32_ORI(isa, 9, 9, LOWER16(ejtag_info->reg9)));
ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1);
exit:
pracc_queue_free(&ctx);
return ctx.retval;
}
/**
* mips32_pracc_write_dsp_reg - Write a value to a MIPS32 DSP register
* @param[in] ejtag_info: EJTAG information structure
* @param[in] val: Value to be written to the register
* @param[in] reg: Index of the DSP register to write
*
* @brief Writes the specified value to the specified MIPS32 DSP register.
*
* This function initiates a sequence of instructions to write the given value to the
* specified DSP register.
*
* @return ERROR_OK on success; error code on failure.
*/
static int mips32_pracc_write_dsp_reg(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t reg)
{
int isa = 0;
struct pracc_queue_info ctx = {
.max_code = 48,
.ejtag_info = ejtag_info
};
uint32_t dsp_write_code[] = {
MIPS32_MTHI(isa, t0), /* mthi t0 ($ac0) - OPCODE - 0x01000011 */
MIPS32_DSP_MTHI(t0, 1), /* mthi t0, $ac1 - OPCODE - 0x01000811 */
MIPS32_DSP_MTHI(t0, 2), /* mthi t0, $ac2 - OPCODE - 0x01001011 */
MIPS32_DSP_MTHI(t0, 3), /* mthi t0, $ac3 - OPCODE - 0x01001811 */
MIPS32_MTLO(isa, t0), /* mtlo t0 ($ac0) - OPCODE - 0x01000013 */
MIPS32_DSP_MTLO(t0, 1), /* mtlo t0, $ac1 - OPCODE - 0x01000813 */
MIPS32_DSP_MTLO(t0, 2), /* mtlo t0, $ac2 - OPCODE - 0x01001013 */
MIPS32_DSP_MTLO(t0, 3), /* mtlo t0, $ac3 - OPCODE - 0x01001813 */
MIPS32_DSP_WRDSP(t0, 0x1F), /* wrdsp t0, 0x1f (DSPCtl) - OPCODE - 0x7d00fcf8*/
};
/* Init context queue */
pracc_queue_init(&ctx);
if (ctx.retval != ERROR_OK)
goto exit;
/* Enables DSP whether its already enabled or not */
mips32_dsp_enable(&ctx, isa);
/* Load val to $8 (t0) */
pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(val)));
pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(val)));
/* move AC or Control to $8 (t0) */
pracc_add(&ctx, 0, dsp_write_code[reg]);
/* nop, delay in order to ensure write */
pracc_add(&ctx, 0, MIPS32_NOP);
/* Restore status registers to previous setting */
mips32_dsp_restore(&ctx, isa);
/* move COP0 DeSave to $15 */
pracc_add(&ctx, 0, MIPS32_MFC0(isa, 15, 31, 0));
/* restore $8 */
pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(ejtag_info->reg8)));
pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(ejtag_info->reg8)));
/* restore upper 16 of $9 */
pracc_add(&ctx, 0, MIPS32_LUI(isa, 9, UPPER16(ejtag_info->reg9)));
/* jump to start */
pracc_add(&ctx, 0, MIPS32_B(isa, NEG16(ctx.code_count + 1)));
/* restore lower 16 of $9 */
pracc_add(&ctx, 0, MIPS32_ORI(isa, 9, 9, LOWER16(ejtag_info->reg9)));
ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
exit:
pracc_queue_free(&ctx);
return ctx.retval;
}
/**
* mips32_handle_cpuinfo_command - Handles the 'cpuinfo' command.
* @param[in] cmd: Command invocation context.
@ -1746,6 +2078,167 @@ COMMAND_HANDLER(mips32_handle_cpuinfo_command)
return ERROR_OK;
}
/**
* mips32_dsp_find_register_by_name - Find DSP register index by name
* @param[in] reg_name: Name of the DSP register to find
*
* @brief Searches for a DSP register by name and returns its index.
* If no match is found, it returns MIPS32NUMDSPREGS.
*
* @return Index of the found register or MIPS32NUMDSPREGS if not found.
*/
static int mips32_dsp_find_register_by_name(const char *reg_name)
{
if (reg_name)
for (int i = 0; i < MIPS32NUMDSPREGS; i++) {
if (strcmp(mips32_dsp_regs[i].name, reg_name) == 0)
return i;
}
return MIPS32NUMDSPREGS;
}
/**
* mips32_dsp_get_all_regs - Get values of all MIPS32 DSP registers
* @param[in] cmd: Command invocation context
* @param[in] ejtag_info: EJTAG information structure
*
* @brief This function iterates through all DSP registers, reads their values,
* and prints each register name along with its corresponding value.
*
* @return ERROR_OK on success; error code on failure.
*/
static int mips32_dsp_get_all_regs(struct command_invocation *cmd, struct mips_ejtag *ejtag_info)
{
uint32_t value;
for (int i = 0; i < MIPS32NUMDSPREGS; i++) {
int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, i);
if (retval != ERROR_OK) {
command_print(CMD, "couldn't access reg %s", mips32_dsp_regs[i].name);
return retval;
}
command_print(CMD, "%*s: 0x%8.8x", 7, mips32_dsp_regs[i].name, value);
}
return ERROR_OK;
}
/**
* mips32_dsp_get_register - Get the value of a MIPS32 DSP register
* @param[in] cmd: Command invocation context
* @param[in] ejtag_info: EJTAG information structure
*
* @brief Retrieves the value of a specified MIPS32 DSP register.
* If the register is found, it reads the register value and prints the result.
* If the register is not found, it prints an error message.
*
* @return ERROR_OK on success; error code on failure.
*/
static int mips32_dsp_get_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info)
{
uint32_t value;
int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]);
if (index == MIPS32NUMDSPREGS) {
command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]);
return ERROR_COMMAND_SYNTAX_ERROR;
}
int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, index);
if (retval != ERROR_OK)
command_print(CMD, "ERROR: Could not access dsp register %s", CMD_ARGV[0]);
else
command_print(CMD, "0x%8.8x", value);
return retval;
}
/**
* mips32_dsp_set_register - Set the value of a MIPS32 DSP register
* @param[in] cmd: Command invocation context
* @param[in] ejtag_info: EJTAG information structure
*
* @brief Sets the value of a specified MIPS32 DSP register.
* If the register is found, it writes provided value to the register.
* If the register is not found or there is an error in writing the value,
* it prints an error message.
*
* @return ERROR_OK on success; error code on failure.
*/
static int mips32_dsp_set_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info)
{
uint32_t value;
int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]);
if (index == MIPS32NUMDSPREGS) {
command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]);
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
int retval = mips32_pracc_write_dsp_reg(ejtag_info, value, index);
if (retval != ERROR_OK)
command_print(CMD, "Error: could not write to dsp register %s", CMD_ARGV[0]);
return retval;
}
/**
* mips32_handle_dsp_command - Handles mips dsp related command
* @param[in] cmd: Command invocation context
*
* @brief Reads or sets the content of each dsp register.
*
* @return ERROR_OK on success; error code on failure.
*/
COMMAND_HANDLER(mips32_handle_dsp_command)
{
int retval, tmp;
struct target *target = get_current_target(CMD_CTX);
struct mips32_common *mips32 = target_to_mips32(target);
struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
retval = mips32_verify_pointer(CMD, mips32);
if (retval != ERROR_OK)
return retval;
if (target->state != TARGET_HALTED) {
command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME);
return ERROR_OK;
}
/* Check for too many command args */
if (CMD_ARGC >= 3)
return ERROR_COMMAND_SYNTAX_ERROR;
/* Check if DSP access supported or not */
if (!mips32->dsp_imp) {
/* Issue Error Message */
command_print(CMD, "DSP not implemented by this processor");
return ERROR_OK;
}
switch (CMD_ARGC) {
case 0:
retval = mips32_dsp_get_all_regs(CMD, ejtag_info);
break;
case 1:
retval = mips32_dsp_get_register(CMD, ejtag_info);
break;
case 2:
tmp = *CMD_ARGV[0];
if (isdigit(tmp)) {
command_print(CMD, "Error: invalid dsp command format");
retval = ERROR_COMMAND_ARGUMENT_INVALID;
} else {
retval = mips32_dsp_set_register(CMD, ejtag_info);
}
break;
default:
command_print(CMD, "Error: invalid argument format, required 0-2, given %d", CMD_ARGC);
retval = ERROR_COMMAND_ARGUMENT_INVALID;
break;
}
return retval;
}
/**
* mips32_handle_ejtag_reg_command - Handler commands related to EJTAG
* @param[in] cmd: Command invocation context
@ -1847,6 +2340,14 @@ static const struct command_registration mips32_exec_command_handlers[] = {
.help = "display CPU information",
.usage = "",
},
{
.name = "dsp",
.handler = mips32_handle_dsp_command,
.mode = COMMAND_EXEC,
.help = "display or set DSP register; "
"with no arguments, displays all registers and their values",
.usage = "[[register_name] [value]]",
},
{
.name = "scan_delay",
.handler = mips32_handle_scan_delay_command,

View File

@ -69,7 +69,7 @@
#define MIPS32_SCAN_DELAY_LEGACY_MODE 2000000
#define MIPS32_NUM_DSPREGS 9
#define MIPS32NUMDSPREGS 9
/* Bit Mask indicating CP0 register supported by this core */
#define MIPS_CP0_MK4 0x0001
@ -459,10 +459,13 @@ struct mips32_algorithm {
#define MIPS32_OP_AND 0x24u
#define MIPS32_OP_CACHE 0x2Fu
#define MIPS32_OP_COP0 0x10u
#define MIPS32_OP_COP1 0x11u
#define MIPS32_OP_J 0x02u
#define MIPS32_OP_JR 0x08u
#define MIPS32_OP_LUI 0x0Fu
#define MIPS32_OP_LW 0x23u
#define MIPS32_OP_LWC1 0x31u
#define MIPS32_OP_LDC1 0x35u
#define MIPS32_OP_LB 0x20u
#define MIPS32_OP_LBU 0x24u
#define MIPS32_OP_LHU 0x25u
@ -470,6 +473,7 @@ struct mips32_algorithm {
#define MIPS32_OP_MTHI 0x11u
#define MIPS32_OP_MFLO 0x12u
#define MIPS32_OP_MTLO 0x13u
#define MIPS32_OP_MUL 0x02u
#define MIPS32_OP_RDHWR 0x3Bu
#define MIPS32_OP_SB 0x28u
#define MIPS32_OP_SH 0x29u
@ -485,6 +489,8 @@ struct mips32_algorithm {
#define MIPS32_OP_SLLV 0x04u
#define MIPS32_OP_SLTI 0x0Au
#define MIPS32_OP_MOVN 0x0Bu
#define MIPS32_OP_SWC1 0x39u
#define MIPS32_OP_SDC1 0x3Du
#define MIPS32_OP_REGIMM 0x01u
#define MIPS32_OP_SDBBP 0x3Fu
@ -517,6 +523,7 @@ struct mips32_algorithm {
#define MIPS32_ISA_BGTZ(reg, off) MIPS32_I_INST(MIPS32_OP_BGTZ, reg, 0, off)
#define MIPS32_ISA_BNE(src, tar, off) MIPS32_I_INST(MIPS32_OP_BNE, src, tar, off)
#define MIPS32_ISA_CACHE(op, off, base) MIPS32_I_INST(MIPS32_OP_CACHE, base, op, off)
#define MIPS32_ISA_CFC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_CF, gpr, cpr, 0, 0)
#define MIPS32_ISA_J(tar) MIPS32_J_INST(MIPS32_OP_J, (0x0FFFFFFFu & (tar)) >> 2)
#define MIPS32_ISA_JR(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_JR)
#define MIPS32_ISA_JRHB(reg) MIPS32_R_INST(0, reg, 0, 0, 0x10, MIPS32_OP_JR)
@ -526,9 +533,15 @@ struct mips32_algorithm {
#define MIPS32_ISA_LHU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LHU, base, reg, off)
#define MIPS32_ISA_LUI(reg, val) MIPS32_I_INST(MIPS32_OP_LUI, 0, reg, val)
#define MIPS32_ISA_LW(reg, off, base) MIPS32_I_INST(MIPS32_OP_LW, base, reg, off)
#define MIPS32_ISA_LWC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_LWC1, base, reg, off)
#define MIPS32_ISA_LDC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_LDC1, base, reg, off)
#define MIPS32_ISA_MFC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP_MF, gpr, cpr, 0, sel)
#define MIPS32_ISA_MTC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP_MT, gpr, cpr, 0, sel)
#define MIPS32_ISA_MFC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MF, gpr, cpr, 0, 0)
#define MIPS32_ISA_MFHC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MFH, gpr, cpr, 0, 0)
#define MIPS32_ISA_MTC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MT, gpr, cpr, 0, 0)
#define MIPS32_ISA_MTHC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MTH, gpr, cpr, 0, 0)
#define MIPS32_ISA_MFLO(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFLO)
#define MIPS32_ISA_MFHI(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFHI)
#define MIPS32_ISA_MTLO(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTLO)
@ -542,6 +555,8 @@ struct mips32_algorithm {
#define MIPS32_ISA_SB(reg, off, base) MIPS32_I_INST(MIPS32_OP_SB, base, reg, off)
#define MIPS32_ISA_SH(reg, off, base) MIPS32_I_INST(MIPS32_OP_SH, base, reg, off)
#define MIPS32_ISA_SW(reg, off, base) MIPS32_I_INST(MIPS32_OP_SW, base, reg, off)
#define MIPS32_ISA_SWC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_SWC1, base, reg, off)
#define MIPS32_ISA_SDC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_SDC1, base, reg, off)
#define MIPS32_ISA_SLL(dst, src, sa) MIPS32_R_INST(MIPS32_OP_SPECIAL, 0, src, dst, sa, MIPS32_OP_SLL)
#define MIPS32_ISA_SLLV(dst, src, sa) MIPS32_R_INST(MIPS32_OP_SPECIAL, 0, src, dst, sa, MIPS32_OP_SLLV)
@ -588,6 +603,7 @@ struct mips32_algorithm {
#define MMIPS32_OP_BGTZ 0x06u
#define MMIPS32_OP_BNE 0x2Du
#define MMIPS32_OP_CACHE 0x06u
#define MMIPS32_OP_CFC1 0x40u
#define MMIPS32_OP_J 0x35u
#define MMIPS32_OP_JALR 0x03Cu
#define MMIPS32_OP_JALRHB 0x07Cu
@ -596,8 +612,14 @@ struct mips32_algorithm {
#define MMIPS32_OP_LHU 0x0Du
#define MMIPS32_OP_LUI 0x0Du
#define MMIPS32_OP_LW 0x3Fu
#define MMIPS32_OP_LWC1 0x27u
#define MMIPS32_OP_LDC1 0x2Fu
#define MMIPS32_OP_MFC0 0x03u
#define MMIPS32_OP_MFC1 0x80u
#define MMIPS32_OP_MFHC1 0xC0u
#define MMIPS32_OP_MTC0 0x0Bu
#define MMIPS32_OP_MTC1 0xA0u
#define MMIPS32_OP_MTHC1 0xE0u
#define MMIPS32_OP_MFLO 0x075u
#define MMIPS32_OP_MFHI 0x035u
#define MMIPS32_OP_MTLO 0x0F5u
@ -608,6 +630,8 @@ struct mips32_algorithm {
#define MMIPS32_OP_SB 0x06u
#define MMIPS32_OP_SH 0x0Eu
#define MMIPS32_OP_SW 0x3Eu
#define MMIPS32_OP_SWC1 0x26u
#define MMIPS32_OP_SDC1 0x2Eu
#define MMIPS32_OP_SLTU 0x390u
#define MMIPS32_OP_SLL 0x000u
#define MMIPS32_OP_SLTI 0x24u
@ -627,6 +651,7 @@ struct mips32_algorithm {
#define MMIPS32_BGTZ(reg, off) MIPS32_I_INST(MMIPS32_POOL32I, MMIPS32_OP_BGTZ, reg, off)
#define MMIPS32_BNE(src, tar, off) MIPS32_I_INST(MMIPS32_OP_BNE, tar, src, off)
#define MMIPS32_CACHE(op, off, base) MIPS32_R_INST(MMIPS32_POOL32B, op, base, MMIPS32_OP_CACHE << 1, 0, off)
#define MMIPS32_CFC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_CFC1, MMIPS32_POOL32FXF)
#define MMIPS32_J(tar) MIPS32_J_INST(MMIPS32_OP_J, ((0x07FFFFFFu & ((tar) >> 1))))
#define MMIPS32_JR(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_JALR, MMIPS32_POOL32AXF)
@ -636,13 +661,19 @@ struct mips32_algorithm {
#define MMIPS32_LHU(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LHU, reg, base, off)
#define MMIPS32_LUI(reg, val) MIPS32_I_INST(MMIPS32_POOL32I, MMIPS32_OP_LUI, reg, val)
#define MMIPS32_LW(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LW, reg, base, off)
#define MMIPS32_LWC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LWC1, reg, base, off)
#define MMIPS32_LDC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LDC1, reg, base, off)
#define MMIPS32_MFC0(gpr, cpr, sel) MIPS32_R_INST(MMIPS32_POOL32A, gpr, cpr, sel,\
MMIPS32_OP_MFC0, MMIPS32_POOL32AXF)
#define MMIPS32_MFC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MFC1, MMIPS32_POOL32FXF)
#define MMIPS32_MFHC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MFHC1, MMIPS32_POOL32FXF)
#define MMIPS32_MFLO(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MFLO, MMIPS32_POOL32AXF)
#define MMIPS32_MFHI(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MFHI, MMIPS32_POOL32AXF)
#define MMIPS32_MTC0(gpr, cpr, sel) MIPS32_R_INST(MMIPS32_POOL32A, gpr, cpr, sel,\
MMIPS32_OP_MTC0, MMIPS32_POOL32AXF)
#define MMIPS32_MTC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MTC1, MMIPS32_POOL32FXF)
#define MMIPS32_MTHC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MTHC1, MMIPS32_POOL32FXF)
#define MMIPS32_MTLO(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MTLO, MMIPS32_POOL32AXF)
#define MMIPS32_MTHI(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MTHI, MMIPS32_POOL32AXF)
@ -653,6 +684,8 @@ struct mips32_algorithm {
#define MMIPS32_SB(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SB, reg, base, off)
#define MMIPS32_SH(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SH, reg, base, off)
#define MMIPS32_SW(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SW, reg, base, off)
#define MMIPS32_SWC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SWC1, reg, base, off)
#define MMIPS32_SDC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SDC1, reg, base, off)
#define MMIPS32_SRL(reg, src, off) MIPS32_R_INST(MMIPS32_POOL32A, reg, src, off, 0, MMIPS32_OP_SRL)
#define MMIPS32_SLTU(dst, src, tar) MIPS32_R_INST(MMIPS32_POOL32A, tar, src, dst, 0, MMIPS32_OP_SLTU)
@ -686,6 +719,7 @@ struct mips32_algorithm {
#define MIPS32_BGTZ(isa, reg, off) (isa ? MMIPS32_BGTZ(reg, off) : MIPS32_ISA_BGTZ(reg, off))
#define MIPS32_BNE(isa, src, tar, off) (isa ? MMIPS32_BNE(src, tar, off) : MIPS32_ISA_BNE(src, tar, off))
#define MIPS32_CACHE(isa, op, off, base) (isa ? MMIPS32_CACHE(op, off, base) : MIPS32_ISA_CACHE(op, off, base))
#define MIPS32_CFC1(isa, gpr, cpr) (isa ? MMIPS32_CFC1(gpr, cpr) : MIPS32_ISA_CFC1(gpr, cpr))
#define MIPS32_J(isa, tar) (isa ? MMIPS32_J(tar) : MIPS32_ISA_J(tar))
#define MIPS32_JR(isa, reg) (isa ? MMIPS32_JR(reg) : MIPS32_ISA_JR(reg))
@ -694,10 +728,15 @@ struct mips32_algorithm {
#define MIPS32_LBU(isa, reg, off, base) (isa ? MMIPS32_LBU(reg, off, base) : MIPS32_ISA_LBU(reg, off, base))
#define MIPS32_LHU(isa, reg, off, base) (isa ? MMIPS32_LHU(reg, off, base) : MIPS32_ISA_LHU(reg, off, base))
#define MIPS32_LW(isa, reg, off, base) (isa ? MMIPS32_LW(reg, off, base) : MIPS32_ISA_LW(reg, off, base))
#define MIPS32_LWC1(isa, reg, off, base) (isa ? MMIPS32_LWC1(reg, off, base) : MIPS32_ISA_LWC1(reg, off, base))
#define MIPS32_LUI(isa, reg, val) (isa ? MMIPS32_LUI(reg, val) : MIPS32_ISA_LUI(reg, val))
#define MIPS32_MFC0(isa, gpr, cpr, sel) (isa ? MMIPS32_MFC0(gpr, cpr, sel) : MIPS32_ISA_MFC0(gpr, cpr, sel))
#define MIPS32_MTC0(isa, gpr, cpr, sel) (isa ? MMIPS32_MTC0(gpr, cpr, sel) : MIPS32_ISA_MTC0(gpr, cpr, sel))
#define MIPS32_MFC1(isa, gpr, cpr) (isa ? MMIPS32_MFC1(gpr, cpr) : MIPS32_ISA_MFC1(gpr, cpr))
#define MIPS32_MFHC1(isa, gpr, cpr) (isa ? MMIPS32_MFHC1(gpr, cpr) : MIPS32_ISA_MFHC1(gpr, cpr))
#define MIPS32_MTC1(isa, gpr, cpr) (isa ? MMIPS32_MTC1(gpr, cpr) : MIPS32_ISA_MTC1(gpr, cpr))
#define MIPS32_MTHC1(isa, gpr, cpr) (isa ? MMIPS32_MTHC1(gpr, cpr) : MIPS32_ISA_MTHC1(gpr, cpr))
#define MIPS32_MFLO(isa, reg) (isa ? MMIPS32_MFLO(reg) : MIPS32_ISA_MFLO(reg))
#define MIPS32_MFHI(isa, reg) (isa ? MMIPS32_MFHI(reg) : MIPS32_ISA_MFHI(reg))
#define MIPS32_MTLO(isa, reg) (isa ? MMIPS32_MTLO(reg) : MIPS32_ISA_MTLO(reg))
@ -710,6 +749,8 @@ struct mips32_algorithm {
#define MIPS32_SB(isa, reg, off, base) (isa ? MMIPS32_SB(reg, off, base) : MIPS32_ISA_SB(reg, off, base))
#define MIPS32_SH(isa, reg, off, base) (isa ? MMIPS32_SH(reg, off, base) : MIPS32_ISA_SH(reg, off, base))
#define MIPS32_SW(isa, reg, off, base) (isa ? MMIPS32_SW(reg, off, base) : MIPS32_ISA_SW(reg, off, base))
#define MIPS32_SWC1(isa, reg, off, base) (isa ? MMIPS32_SWC1(reg, off, base) : MIPS32_ISA_SWC1(reg, off, base))
#define MIPS32_SDC1(isa, reg, off, base) (isa ? MMIPS32_SDC1(reg, off, base) : MIPS32_ISA_SDC1(reg, off, base))
#define MIPS32_SLL(isa, dst, src, sa) (isa ? MMIPS32_SLL(dst, src, sa) : MIPS32_ISA_SLL(dst, src, sa))
#define MIPS32_EHB(isa) (isa ? MMIPS32_SLL(0, 0, 3) : MIPS32_ISA_SLL(0, 0, 3))
@ -734,6 +775,24 @@ struct mips32_algorithm {
/* ejtag specific instructions */
#define MICRO_MIPS32_SDBBP 0x000046C0
#define MICRO_MIPS_SDBBP 0x46C0
#define MIPS32_DSP_ENABLE 0x1000000
#define MIPS32_S_INST(rs, rac, opcode) \
(((rs) << 21) | ((rac) << 11) | (opcode))
#define MIPS32_DSP_R_INST(rt, immd, opcode, extrw) \
((0x1F << 26) | ((immd) << 16) | ((rt) << 11) | ((opcode) << 6) | (extrw))
#define MIPS32_DSP_W_INST(rs, immd, opcode, extrw) \
((0x1F << 26) | ((rs) << 21) | ((immd) << 11) | ((opcode) << 6) | (extrw))
#define MIPS32_DSP_MFHI(reg, ac) MIPS32_R_INST(0, ac, 0, reg, 0, MIPS32_OP_MFHI)
#define MIPS32_DSP_MFLO(reg, ac) MIPS32_R_INST(0, ac, 0, reg, 0, MIPS32_OP_MFLO)
#define MIPS32_DSP_MTLO(reg, ac) MIPS32_S_INST(reg, ac, MIPS32_OP_MTLO)
#define MIPS32_DSP_MTHI(reg, ac) MIPS32_S_INST(reg, ac, MIPS32_OP_MTHI)
#define MIPS32_DSP_RDDSP(rt, mask) MIPS32_DSP_R_INST(rt, mask, 0x12, 0x38)
#define MIPS32_DSP_WRDSP(rs, mask) MIPS32_DSP_W_INST(rs, mask, 0x13, 0x38)
/*
* MIPS32 Config1 Register (CP0 Register 16, Select 1)
*/

View File

@ -588,6 +588,26 @@ int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_r
return ctx.retval;
}
int mips32_cp1_control_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp1_c_reg)
{
struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
pracc_queue_init(&ctx);
pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */
pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa));
pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, cp1_c_reg)); /* move cp1c reg to $8 */
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT,
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */
pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */
pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */
pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */
pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */
ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1);
pracc_queue_free(&ctx);
return ctx.retval;
}
/**
* \b mips32_pracc_sync_cache
*
@ -856,6 +876,9 @@ int mips32_pracc_write_regs(struct mips32_common *mips32)
struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
uint32_t *gprs = mips32->core_regs.gpr;
uint32_t *c0rs = mips32->core_regs.cp0;
bool fpu_in_64bit = ((c0rs[0] & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0);
bool fp_enabled = ((c0rs[0] & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0);
uint32_t rel = (ejtag_info->config[0] & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT;
pracc_queue_init(&ctx);
@ -895,6 +918,31 @@ int mips32_pracc_write_regs(struct mips32_common *mips32)
if (mips32_cpu_support_hazard_barrier(ejtag_info))
pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa));
/* store FPRs */
if (mips32->fp_imp && fp_enabled) {
uint64_t *fprs = mips32->core_regs.fpr;
if (fpu_in_64bit) {
for (int i = 0; i != MIPS32_REG_FP_COUNT; i++) {
uint32_t fp_lo = fprs[i] & 0xffffffff;
uint32_t fp_hi = (fprs[i] >> 32) & 0xffffffff;
pracc_add_li32(&ctx, 2, fp_lo, 0);
pracc_add_li32(&ctx, 3, fp_hi, 0);
pracc_add(&ctx, 0, MIPS32_MTC1(ctx.isa, 2, i));
pracc_add(&ctx, 0, MIPS32_MTHC1(ctx.isa, 3, i));
}
} else {
for (int i = 0; i != MIPS32_REG_FP_COUNT; i++) {
uint32_t fp_lo = fprs[i] & 0xffffffff;
pracc_add_li32(&ctx, 2, fp_lo, 0);
pracc_add(&ctx, 0, MIPS32_MTC1(ctx.isa, 2, i));
}
}
if (rel > MIPS32_RELEASE_1)
pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa));
}
/* load registers 2 to 31 with li32, optimize */
for (int i = 2; i < 32; i++)
pracc_add_li32(&ctx, i, gprs[i], 1);
@ -1014,6 +1062,9 @@ int mips32_pracc_read_regs(struct mips32_common *mips32)
struct mips32_core_regs *core_regs = &mips32->core_regs;
unsigned int offset_gpr = ((uint8_t *)&core_regs->gpr[0]) - (uint8_t *)core_regs;
unsigned int offset_cp0 = ((uint8_t *)&core_regs->cp0[0]) - (uint8_t *)core_regs;
unsigned int offset_fpr = ((uint8_t *)&core_regs->fpr[0]) - (uint8_t *)core_regs;
unsigned int offset_fpcr = ((uint8_t *)&core_regs->fpcr[0]) - (uint8_t *)core_regs;
bool fp_enabled;
/*
* This procedure has to be in 2 distinctive steps, because we can
@ -1040,11 +1091,64 @@ int mips32_pracc_read_regs(struct mips32_common *mips32)
ejtag_info->reg8 = mips32->core_regs.gpr[8];
ejtag_info->reg9 = mips32->core_regs.gpr[9];
if (ctx.retval != ERROR_OK)
return ctx.retval;
/* we only care if FP is actually impl'd and if cp1 is enabled */
/* since we already read cp0 in the prev step */
/* now we know what's in cp0.status */
/* TODO: Read FPRs */
fp_enabled = (mips32->core_regs.cp0[0] & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0;
if (mips32->fp_imp && fp_enabled) {
pracc_queue_init(&ctx);
mips32_pracc_store_regs_set_base_addr(&ctx);
/* FCSR */
pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, 31));
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset_fpcr,
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset_fpcr, 1));
/* FIR */
pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, 0));
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset_fpcr + 4,
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset_fpcr + 4, 1));
/* f0 to f31 */
if (mips32->fpu_in_64bit) {
for (int i = 0; i != 32; i++) {
size_t offset = offset_fpr + (i * 8);
/* current pracc implementation (or EJTAG itself) only supports 32b access */
/* so there is no way to use SDC1 */
/* lower half */
pracc_add(&ctx, 0, MIPS32_MFC1(ctx.isa, 8, i));
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset,
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset, 1));
/* upper half */
pracc_add(&ctx, 0, MIPS32_MFHC1(ctx.isa, 8, i));
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset + 4,
MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset + 4, 1));
}
} else {
for (int i = 0; i != 32; i++) {
size_t offset = offset_fpr + (i * 8);
pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset,
MIPS32_SWC1(ctx.isa, i, PRACC_OUT_OFFSET + offset, 1));
}
}
mips32_pracc_store_regs_restore(&ctx);
/* jump to start */
pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa)));
/* load $15 in DeSave */
pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0));
ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, (uint32_t *)&mips32->core_regs, 1);
pracc_queue_free(&ctx);
}
return ctx.retval;
}

View File

@ -103,6 +103,21 @@ int mips32_cp0_read(struct mips_ejtag *ejtag_info,
int mips32_cp0_write(struct mips_ejtag *ejtag_info,
uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel);
/**
* mips32_cp1_control_read
*
* @brief Simulates cfc1 ASM instruction (Move Control Word From Floating Point),
* i.e. implements copro C1 Control Register read.
*
* @param[in] ejtag_info
* @param[in] val Storage to hold read value
* @param[in] cp1_c_reg Number of copro C1 control register we want to read
*
* @return ERROR_OK on Success, ERROR_FAIL otherwise
*/
int mips32_cp1_control_read(struct mips_ejtag *ejtag_info,
uint32_t *val, uint32_t cp1_c_reg);
static inline void pracc_swap16_array(struct mips_ejtag *ejtag_info, uint32_t *buf, int count)
{
if (ejtag_info->isa && ejtag_info->endianness)

View File

@ -23,6 +23,7 @@
#include <helper/list.h>
#include "helper/replacements.h"
#include "helper/system.h"
#include <helper/types.h>
#include <jim.h>
struct reg;

View File

@ -144,17 +144,7 @@ static int xtensa_chip_examine(struct target *target)
static int xtensa_chip_jim_configure(struct target *target, struct jim_getopt_info *goi)
{
static bool dap_configured;
int ret = adiv5_jim_configure(target, goi);
if (ret == JIM_OK) {
LOG_DEBUG("xtensa '-dap' target option found");
dap_configured = true;
}
if (!dap_configured) {
LOG_DEBUG("xtensa '-dap' target option not yet found, assuming JTAG...");
target->has_dap = false;
}
return ret;
return adiv5_jim_configure_ext(target, goi, NULL, ADI_CONFIGURE_DAP_OPTIONAL);
}
/** Methods for generic example of Xtensa-based chip-level targets. */

View File

@ -17,7 +17,8 @@ source [find fpga/altera-cycloneiii.cfg]
#quartus_cpf --option=bitstream_compression=off -c output_files\cycloneiii_blinker.sof cycloneiii_blinker.rbf
#openocd -f board/bemicro_cycloneiii.cfg -c "init" -c "pld load cycloneiii.pld cycloneiii_blinker.rbf"
# "ipdbg -start -tap cycloneiii.tap -hub 0x00e -tool 0 -port 5555"
# "ipdbg create-hub cycloneiii.ipdbghub -tap cycloneiii.tap -ir 0x00e"
# "cycloneiii.ipdbghub ipdbg start -tool 0 -port 5555"
set JTAGSPI_CHAIN_ID cycloneiii.pld

View File

@ -15,7 +15,8 @@ adapter speed 10000
source [find cpld/xilinx-xc7.cfg]
# "ipdbg -start -tap xc7.tap -hub 0x02 -tool 0 -port 5555"
# "ipdbg create-hub xc7.ipdbghub -tap xc7.tap -ir 0x02"
# "xc7.ipdbghub ipdbg start -tool 0 -port 5555"
#openocd -f board/digilent_cmod_s7.cfg -c "init" -c "pld load xc7.pld shared_folder/cmod_s7_fast.bit"
set JTAGSPI_CHAIN_ID xc7.pld

View File

@ -16,7 +16,8 @@ adapter speed 6000
source [find fpga/lattice_ecp5.cfg]
#openocd -f board/ecp5_evaluation.cfg -c "init" -c "pld load ecp5.pld shared_folder/ecp5_blinker_impl1.bit"
#ipdbg -start -tap ecp5.tap -hub 0x32 -port 5555 -tool 0
#ipdbg create-hub ecp5.ipdbghub -tap ecp5.tap -ir 0x32
#ecp5.ipdbghub ipdbg start -tool 0 -port 5555
set JTAGSPI_CHAIN_ID ecp5.pld
source [find cpld/jtagspi.cfg]

View File

@ -16,4 +16,5 @@ source [find fpga/gowin_gw1n.cfg]
#openocd -f board/gowin_runber.cfg -c "init" -c "pld load 0 impl/pnr/gw1n_blinker.fs"
#ipdbg -start -tap gw1n.tap -hub 0x42 -port 5555 -tool 0
#ipdbg create-hub gw1n.ipdbghub -tap gw1n.tap -ir 0x42
#gw1n.ipdbghubipdbg start -tool 0 -port 5555

View File

@ -20,7 +20,8 @@ adapter speed 6000
source [find fpga/efinix_trion.cfg]
#openocd -f board/trion_t20_bga256.cfg -c "init" -c "pld load trion.pld outflow/trion_blinker.bit"
#ipdbg -start -tap trion.tap -hub 0x8 -port 5555 -tool 0
#ipdbg create-hub trion.ipdbghub -tap trion.tap -ir 0x8
#trion.ipdbghub ipdbg start -tool 0 -port 5555
set JTAGSPI_CHAIN_ID trion.pld
source [find cpld/jtagspi.cfg]

View File

@ -45,13 +45,11 @@ if {![using_hla]} {
cortex_m reset_config sysresetreq
}
flash bank $_CHIPNAME.flash nrf51 0x00000000 0 1 1 $_TARGETNAME
flash bank $_CHIPNAME.uicr nrf51 0x10001000 0 1 1 $_TARGETNAME
flash bank $_CHIPNAME.flash nrf5 0x00000000 0 0 0 $_TARGETNAME
flash bank $_CHIPNAME.uicr nrf5 0x10001000 0 0 0 $_TARGETNAME
#
# The chip should start up from internal 16Mhz RC, so setting adapter
# clock to 1Mhz should be OK
#
adapter speed 1000
proc enable_all_ram {} {
@ -60,4 +58,4 @@ proc enable_all_ram {} {
# resetting we enable all banks via the RAMON register
mww 0x40000524 0xF
}
$_TARGETNAME configure -event reset-end { enable_all_ram }
$_TARGETNAME configure -event reset-init { enable_all_ram }