Merge up to a35e254c53
from upstream
Checkpatch-ignore: MACRO_ARG_REUSE, MACRO_ARG_PRECEDENCE Change-Id: Icd10f44d162054f8f32019a579ccbdda2cee7a91
This commit is contained in:
commit
46e7507e48
102
doc/openocd.texi
102
doc/openocd.texi
|
@ -7348,10 +7348,6 @@ works only for chips that do not have factory pre-programmed region 0
|
||||||
code.
|
code.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {nrf5 info}
|
|
||||||
Decodes and shows information from FICR and UICR registers.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Flash Driver} {ocl}
|
@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.
|
core specific EJTAG Register definition, please check Core Specific SUM manual.
|
||||||
@end deffn
|
@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
|
@section RISC-V Architecture
|
||||||
|
|
||||||
@uref{http://riscv.org/, RISC-V} is a free and open ISA. OpenOCD supports JTAG
|
@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.
|
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
|
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
|
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}}]
|
@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}]]]}]
|
||||||
Starts or stops a IPDBG JTAG-Host server. Arguments can be specified in any order.
|
@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:
|
Command options:
|
||||||
@itemize @bullet
|
@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{-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{-ir @var{ir_value}} states that the JTAG hub is
|
||||||
@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.
|
reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}. Also known as @verb{|USERx|} instructions.
|
||||||
@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.
|
The optional @var{dr_length} is the length of the dr.
|
||||||
@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} On some devices, the user data-register is reachable if there is a
|
Current JTAG-Hub implementation only supports dr_length=13, which is also the default value.
|
||||||
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{-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
|
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
|
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.
|
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 itemize
|
||||||
@end deffn
|
@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.
|
@deffn {Command} {$hub_name ipdbg stop} @option{-tool @var{number}}
|
||||||
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.
|
Stops a IPDBG JTAG-Host server.
|
||||||
|
Command options:
|
||||||
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.
|
@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.
|
||||||
The remaining options are described in the previous command.
|
@end itemize
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
@example
|
@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
|
@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).
|
The connection is through the TAP of a Xilinx Spartan 6 on USER1 instruction (tested with a papillion pro board).
|
||||||
|
|
||||||
@example
|
@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
|
@end example
|
||||||
Starts a server listening on tcp-port 60000 which connects to tool 1 (data_up_1/data_down_1).
|
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).
|
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
|
@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
|
@end example
|
||||||
Starts a server listening on tcp-port 5555 which connects to tool 0 (data_up_0/data_down_0).
|
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.
|
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
|
@node Utility Commands
|
||||||
@chapter Utility Commands
|
@chapter Utility Commands
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <target/armv7m.h>
|
#include <target/armv7m.h>
|
||||||
#include <helper/types.h>
|
#include <helper/types.h>
|
||||||
#include <helper/time_support.h>
|
#include <helper/time_support.h>
|
||||||
|
#include <helper/bits.h>
|
||||||
|
|
||||||
/* Both those values are constant across the current spectrum ofr nRF5 devices */
|
/* Both those values are constant across the current spectrum ofr nRF5 devices */
|
||||||
#define WATCHDOG_REFRESH_REGISTER 0x40010600
|
#define WATCHDOG_REFRESH_REGISTER 0x40010600
|
||||||
|
@ -42,32 +43,9 @@ enum nrf5_ficr_registers {
|
||||||
NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040),
|
NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040),
|
||||||
NRF51_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044),
|
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_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 */
|
/* Following registers are available on nRF52 and on nRF51 since rev 3 */
|
||||||
NRF5_FICR_INFO_PART = NRF5_FICR_REG(0x100),
|
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)
|
#define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset)
|
||||||
|
|
||||||
NRF51_UICR_CLENR0 = NRF5_UICR_REG(0x000),
|
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 {
|
enum nrf5_nvmc_registers {
|
||||||
|
@ -120,10 +95,10 @@ struct nrf52_ficr_info {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum nrf5_features {
|
enum nrf5_features {
|
||||||
NRF5_FEATURE_SERIES_51 = 1 << 0,
|
NRF5_FEATURE_SERIES_51 = BIT(0),
|
||||||
NRF5_FEATURE_SERIES_52 = 1 << 1,
|
NRF5_FEATURE_SERIES_52 = BIT(1),
|
||||||
NRF5_FEATURE_BPROT = 1 << 2,
|
NRF5_FEATURE_BPROT = BIT(2),
|
||||||
NRF5_FEATURE_ACL_PROT = 1 << 3,
|
NRF5_FEATURE_ACL_PROT = BIT(3),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nrf5_device_spec {
|
struct nrf5_device_spec {
|
||||||
|
@ -164,26 +139,20 @@ struct nrf5_info {
|
||||||
.features = NRF5_FEATURE_SERIES_51, \
|
.features = NRF5_FEATURE_SERIES_51, \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize, features) \
|
/*
|
||||||
{ \
|
* The table maps known HWIDs to the part numbers, variant
|
||||||
.hwid = (id), \
|
* build code and some other info. For nRF51 rev 1 and 2 devices
|
||||||
.part = pt, \
|
* this is the only way how to get the part number and variant.
|
||||||
.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:
|
|
||||||
*
|
*
|
||||||
* https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51422_ic_revision_overview
|
* All tested nRF51 rev 3 devices have FICR INFO fields
|
||||||
* https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51822_ic_revision_overview
|
* but the fields are not documented in RM so we keep HWIDs in
|
||||||
* https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51824_ic_revision_overview
|
* this table.
|
||||||
* 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
|
* nRF52 and newer devices have FICR INFO documented, the autodetection
|
||||||
* https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52840/latest/COMP/nrf52840/nRF52840_ic_revision_overview
|
* 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.
|
* 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,
|
/* The driver fully autodetects nRF52 series devices by FICR INFO,
|
||||||
* no need for nRF52xxx HWIDs in this table */
|
* 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 {
|
struct nrf5_device_package {
|
||||||
|
@ -270,11 +226,16 @@ struct nrf5_device_package {
|
||||||
|
|
||||||
/* Newer devices have FICR INFO.PACKAGE.
|
/* Newer devices have FICR INFO.PACKAGE.
|
||||||
* This table converts its value to two character code */
|
* 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" },
|
{ 0x2000, "QF" },
|
||||||
{ 0x2001, "CH" },
|
{ 0x2001, "CH" },
|
||||||
{ 0x2002, "CI" },
|
{ 0x2002, "CI" },
|
||||||
|
{ 0x2003, "QC" },
|
||||||
|
{ 0x2004, "QI/CA" }, /* differs nRF52805, 810, 811: CA, nRF52833, 840: QI */
|
||||||
{ 0x2005, "CK" },
|
{ 0x2005, "CK" },
|
||||||
|
{ 0x2007, "QD" },
|
||||||
|
{ 0x2008, "CJ" },
|
||||||
|
{ 0x2009, "CF" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct flash_driver nrf5_flash, nrf51_flash;
|
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)
|
static bool nrf5_bank_is_probed(const struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct nrf5_bank *nbank = bank->driver_priv;
|
struct nrf5_bank *nbank = bank->driver_priv;
|
||||||
|
|
||||||
assert(nbank);
|
assert(nbank);
|
||||||
|
|
||||||
return nbank->probed;
|
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)
|
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;
|
int res;
|
||||||
uint32_t clenr0;
|
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);
|
assert(chip);
|
||||||
|
|
||||||
res = target_read_u32(chip->target, NRF51_FICR_CLENR0,
|
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)
|
static int nrf5_protect_check_bprot(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct nrf5_bank *nbank = bank->driver_priv;
|
struct nrf5_bank *nbank = bank->driver_priv;
|
||||||
|
assert(nbank);
|
||||||
struct nrf5_info *chip = nbank->chip;
|
struct nrf5_info *chip = nbank->chip;
|
||||||
|
|
||||||
assert(chip);
|
assert(chip);
|
||||||
|
|
||||||
static uint32_t nrf5_bprot_offsets[4] = { 0x600, 0x604, 0x610, 0x614 };
|
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;
|
return ERROR_OK;
|
||||||
|
|
||||||
struct nrf5_bank *nbank = bank->driver_priv;
|
struct nrf5_bank *nbank = bank->driver_priv;
|
||||||
|
assert(nbank);
|
||||||
struct nrf5_info *chip = nbank->chip;
|
struct nrf5_info *chip = nbank->chip;
|
||||||
|
|
||||||
assert(chip);
|
assert(chip);
|
||||||
|
|
||||||
if (chip->features & NRF5_FEATURE_BPROT)
|
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;
|
int res;
|
||||||
uint32_t clenr0, ppfc;
|
uint32_t clenr0, ppfc;
|
||||||
|
|
||||||
struct nrf5_bank *nbank = bank->driver_priv;
|
struct nrf5_bank *nbank = bank->driver_priv;
|
||||||
|
assert(nbank);
|
||||||
struct nrf5_info *chip = nbank->chip;
|
struct nrf5_info *chip = nbank->chip;
|
||||||
|
assert(chip);
|
||||||
|
|
||||||
if (first != 0) {
|
if (first != 0) {
|
||||||
LOG_ERROR("Code region 0 must start at the beginning of the bank");
|
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,
|
static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first,
|
||||||
unsigned int last)
|
unsigned int last)
|
||||||
{
|
{
|
||||||
int res;
|
|
||||||
struct nrf5_info *chip;
|
|
||||||
|
|
||||||
/* UICR cannot be write protected so just bail out early */
|
/* UICR cannot be write protected so just bail out early */
|
||||||
if (bank->base == NRF5_UICR_BASE) {
|
if (bank->base == NRF5_UICR_BASE) {
|
||||||
LOG_ERROR("UICR page does not support protection");
|
LOG_ERROR("UICR page does not support protection");
|
||||||
return ERROR_FLASH_OPER_UNSUPPORTED;
|
return ERROR_FLASH_OPER_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = nrf5_get_probed_chip_if_halted(bank, &chip);
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
if (res != ERROR_OK)
|
LOG_ERROR("Target not halted");
|
||||||
return res;
|
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)
|
if (chip->features & NRF5_FEATURE_SERIES_51)
|
||||||
return nrf5_protect_clenr0(bank, set, first, last);
|
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)
|
static const char *nrf5_decode_info_package(uint32_t package)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(nrf5_packages_table); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE(nrf52_packages_table); i++) {
|
||||||
if (nrf5_packages_table[i].package == package)
|
if (nrf52_packages_table[i].package == package)
|
||||||
return nrf5_packages_table[i].code;
|
return nrf52_packages_table[i].code;
|
||||||
}
|
}
|
||||||
return "xx";
|
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)
|
static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd)
|
||||||
{
|
{
|
||||||
struct nrf5_bank *nbank = bank->driver_priv;
|
struct nrf5_bank *nbank = bank->driver_priv;
|
||||||
|
assert(nbank);
|
||||||
struct nrf5_info *chip = nbank->chip;
|
struct nrf5_info *chip = nbank->chip;
|
||||||
|
assert(chip);
|
||||||
|
|
||||||
char chip_type_str[256];
|
char chip_type_str[256];
|
||||||
if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK)
|
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;
|
chip->features = NRF5_FEATURE_SERIES_52;
|
||||||
|
|
||||||
switch (chip->ficr_info.part) {
|
switch (chip->ficr_info.part) {
|
||||||
|
case 0x52805:
|
||||||
case 0x52810:
|
case 0x52810:
|
||||||
|
case 0x52811:
|
||||||
case 0x52832:
|
case 0x52832:
|
||||||
chip->features |= NRF5_FEATURE_BPROT;
|
chip->features |= NRF5_FEATURE_BPROT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x52820:
|
||||||
|
case 0x52833:
|
||||||
case 0x52840:
|
case 0x52840:
|
||||||
chip->features |= NRF5_FEATURE_ACL_PROT;
|
chip->features |= NRF5_FEATURE_ACL_PROT;
|
||||||
break;
|
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)
|
static int nrf5_probe(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
struct nrf5_bank *nbank = bank->driver_priv;
|
struct nrf5_bank *nbank = bank->driver_priv;
|
||||||
|
assert(nbank);
|
||||||
struct nrf5_info *chip = nbank->chip;
|
struct nrf5_info *chip = nbank->chip;
|
||||||
|
assert(chip);
|
||||||
struct target *target = chip->target;
|
struct target *target = chip->target;
|
||||||
|
|
||||||
uint32_t configid;
|
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,
|
static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
uint32_t offset, uint32_t count)
|
uint32_t offset, uint32_t count)
|
||||||
{
|
{
|
||||||
struct nrf5_info *chip;
|
int res;
|
||||||
|
|
||||||
int res = nrf5_get_probed_chip_if_halted(bank, &chip);
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
if (res != ERROR_OK)
|
LOG_ERROR("Target not halted");
|
||||||
return res;
|
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(offset % 4 == 0);
|
||||||
assert(count % 4 == 0);
|
assert(count % 4 == 0);
|
||||||
|
@ -1081,11 +1046,16 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first,
|
||||||
unsigned int last)
|
unsigned int last)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct nrf5_info *chip;
|
|
||||||
|
|
||||||
res = nrf5_get_probed_chip_if_halted(bank, &chip);
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
if (res != ERROR_OK)
|
LOG_ERROR("Target not halted");
|
||||||
return res;
|
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
|
/* UICR CLENR0 based protection used on nRF51 prevents erase
|
||||||
* absolutely silently. NVMC has no flag to indicate the protection
|
* 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 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
|
if (chip->features & NRF5_FEATURE_SERIES_51
|
||||||
&& bank->sectors[s].is_protected == 1) {
|
&& 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)
|
static void nrf5_free_driver_priv(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct nrf5_bank *nbank = bank->driver_priv;
|
struct nrf5_bank *nbank = bank->driver_priv;
|
||||||
|
assert(nbank);
|
||||||
struct nrf5_info *chip = nbank->chip;
|
struct nrf5_info *chip = nbank->chip;
|
||||||
if (!chip)
|
if (!chip)
|
||||||
return;
|
return;
|
||||||
|
@ -1160,6 +1131,9 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
|
||||||
struct nrf5_info *chip;
|
struct nrf5_info *chip;
|
||||||
struct nrf5_bank *nbank = NULL;
|
struct nrf5_bank *nbank = NULL;
|
||||||
|
|
||||||
|
if (bank->driver == &nrf51_flash)
|
||||||
|
LOG_WARNING("Flash driver 'nrf51' is deprecated! Use 'nrf5' instead.");
|
||||||
|
|
||||||
switch (bank->base) {
|
switch (bank->base) {
|
||||||
case NRF5_FLASH_BASE:
|
case NRF5_FLASH_BASE:
|
||||||
case NRF5_UICR_BASE:
|
case NRF5_UICR_BASE:
|
||||||
|
@ -1210,11 +1184,15 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
|
||||||
|
|
||||||
assert(bank);
|
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);
|
struct nrf5_bank *nbank = bank->driver_priv;
|
||||||
if (res != ERROR_OK)
|
assert(nbank);
|
||||||
return res;
|
struct nrf5_info *chip = nbank->chip;
|
||||||
|
assert(chip);
|
||||||
|
|
||||||
if (chip->features & NRF5_FEATURE_SERIES_51) {
|
if (chip->features & NRF5_FEATURE_SERIES_51) {
|
||||||
uint32_t ppfc;
|
uint32_t ppfc;
|
||||||
|
@ -1245,137 +1223,6 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
|
||||||
return res;
|
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[] = {
|
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.",
|
.help = "Erase all flash contents of the chip.",
|
||||||
.usage = "",
|
.usage = "",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = "info",
|
|
||||||
.handler = nrf5_handle_info_command,
|
|
||||||
.mode = COMMAND_EXEC,
|
|
||||||
.help = "Show FICR and UICR info.",
|
|
||||||
.usage = "",
|
|
||||||
},
|
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
#ifndef OPENOCD_HELPER_BINARYBUFFER_H
|
#ifndef OPENOCD_HELPER_BINARYBUFFER_H
|
||||||
#define OPENOCD_HELPER_BINARYBUFFER_H
|
#define OPENOCD_HELPER_BINARYBUFFER_H
|
||||||
|
|
||||||
#include "list.h"
|
#include <helper/list.h>
|
||||||
|
#include <helper/types.h>
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
* Support functions to access arbitrary bits in a byte array
|
* Support functions to access arbitrary bits in a byte array
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -114,6 +114,15 @@ extern int debug_level;
|
||||||
expr); \
|
expr); \
|
||||||
} while (0)
|
} 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 ...) \
|
#define LOG_INFO(expr ...) \
|
||||||
log_printf_lf(LOG_LVL_INFO, __FILE__, __LINE__, __func__, expr)
|
log_printf_lf(LOG_LVL_INFO, __FILE__, __LINE__, __func__, expr)
|
||||||
|
|
||||||
|
|
|
@ -341,6 +341,10 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
|
||||||
exit(0);
|
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
|
/* paths specified on the command line take precedence over these
|
||||||
* built-in paths
|
* built-in paths
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -20,6 +20,11 @@
|
||||||
#include <jtag/interface.h>
|
#include <jtag/interface.h>
|
||||||
#include <jtag/commands.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
|
* Function bitbang_stableclocks
|
||||||
* issues a number of clock cycles while staying in a stable state.
|
* 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;
|
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)];
|
uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)];
|
||||||
|
|
||||||
cmd |= SWD_CMD_START | SWD_CMD_PARK;
|
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);
|
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);
|
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",
|
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_APNDP ? "AP" : "DP",
|
||||||
(cmd & SWD_CMD_A32) >> 1,
|
(cmd & SWD_CMD_A32) >> 1,
|
||||||
data);
|
data);
|
||||||
|
|
||||||
if (ack == SWD_ACK_WAIT) {
|
if (ack == SWD_ACK_WAIT && timeval_ms() <= timeout) {
|
||||||
swd_clear_sticky_errors();
|
swd_clear_sticky_errors();
|
||||||
|
if (retry > 20)
|
||||||
|
alive_sleep(1);
|
||||||
|
|
||||||
continue;
|
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);
|
queued_retval = swd_ack_to_error_code(ack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -524,12 +539,14 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t timeout = timeval_ms() + SWD_WAIT_TIMEOUT;
|
||||||
|
|
||||||
/* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
|
/* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
|
||||||
bool check_ack = swd_cmd_returns_ack(cmd);
|
bool check_ack = swd_cmd_returns_ack(cmd);
|
||||||
|
|
||||||
/* init the array to silence scan-build */
|
/* init the array to silence scan-build */
|
||||||
uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)] = {0};
|
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, value);
|
||||||
buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1 + 32, 1, parity_u32(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);
|
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);
|
int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3);
|
||||||
|
LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK && (retry == 0 || ack != SWD_ACK_WAIT))
|
||||||
LOG_DEBUG_IO("%s%s %s write reg %X = %08" PRIx32,
|
? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO,
|
||||||
|
"%s%s %s write reg %X = %08" PRIx32,
|
||||||
check_ack ? "" : "ack ignored ",
|
check_ack ? "" : "ack ignored ",
|
||||||
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
|
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_APNDP ? "AP" : "DP",
|
||||||
(cmd & SWD_CMD_A32) >> 1,
|
(cmd & SWD_CMD_A32) >> 1,
|
||||||
buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32));
|
buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32));
|
||||||
|
|
||||||
if (check_ack) {
|
if (check_ack && ack == SWD_ACK_WAIT && timeval_ms() <= timeout) {
|
||||||
if (ack == SWD_ACK_WAIT) {
|
|
||||||
swd_clear_sticky_errors();
|
swd_clear_sticky_errors();
|
||||||
|
if (retry > 20)
|
||||||
|
alive_sleep(1);
|
||||||
|
|
||||||
continue;
|
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);
|
queued_retval = swd_ack_to_error_code(ack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd & SWD_CMD_APNDP)
|
if (cmd & SWD_CMD_APNDP)
|
||||||
bitbang_swd_exchange(true, NULL, 0, ap_delay_clk);
|
bitbang_swd_exchange(true, NULL, 0, ap_delay_clk);
|
||||||
|
|
|
@ -944,7 +944,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, enum cmsis_dap_blo
|
||||||
if (ack != SWD_ACK_OK) {
|
if (ack != SWD_ACK_OK) {
|
||||||
LOG_DEBUG("SWD ack not OK @ %d %s", transfer_count,
|
LOG_DEBUG("SWD ack not OK @ %d %s", transfer_count,
|
||||||
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
|
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? */
|
/* TODO: use results of transfers completed before the error occurred? */
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1506,7 +1506,8 @@ static int ftdi_swd_run_queue(void)
|
||||||
/* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
|
/* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
|
||||||
bool check_ack = swd_cmd_returns_ack(swd_cmd_queue[i].cmd);
|
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 ",
|
check_ack ? "" : "ack ignored ",
|
||||||
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
|
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",
|
swd_cmd_queue[i].cmd & SWD_CMD_APNDP ? "AP" : "DP",
|
||||||
|
|
|
@ -782,7 +782,7 @@ static int kitprog_swd_run_queue(void)
|
||||||
if (ack != SWD_ACK_OK || (buffer[read_index] & 0x08)) {
|
if (ack != SWD_ACK_OK || (buffer[read_index] & 0x08)) {
|
||||||
LOG_DEBUG("SWD ack not OK: %d %s", i,
|
LOG_DEBUG("SWD ack not OK: %d %s", i,
|
||||||
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
|
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;
|
break;
|
||||||
}
|
}
|
||||||
read_index++;
|
read_index++;
|
||||||
|
|
|
@ -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
|
# END MIGRATION AIDS
|
||||||
|
|
|
@ -53,6 +53,8 @@
|
||||||
enum gdb_output_flag {
|
enum gdb_output_flag {
|
||||||
/* GDB doesn't accept 'O' packets */
|
/* GDB doesn't accept 'O' packets */
|
||||||
GDB_OUTPUT_NO,
|
GDB_OUTPUT_NO,
|
||||||
|
/* GDB doesn't accept 'O' packets but accepts notifications */
|
||||||
|
GDB_OUTPUT_NOTIF,
|
||||||
/* GDB accepts 'O' packets */
|
/* GDB accepts 'O' packets */
|
||||||
GDB_OUTPUT_ALL,
|
GDB_OUTPUT_ALL,
|
||||||
};
|
};
|
||||||
|
@ -71,6 +73,8 @@ struct gdb_connection {
|
||||||
enum target_state frontend_state;
|
enum target_state frontend_state;
|
||||||
struct image *vflash_image;
|
struct image *vflash_image;
|
||||||
bool closed;
|
bool closed;
|
||||||
|
/* set to prevent re-entrance from log messages during gdb_get_packet()
|
||||||
|
* and gdb_put_packet(). */
|
||||||
bool busy;
|
bool busy;
|
||||||
int noack_mode;
|
int noack_mode;
|
||||||
/* set flag to true if you want the next stepi to return immediately.
|
/* 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;
|
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,
|
static int gdb_read_memory_packet(struct connection *connection,
|
||||||
char const *packet, int packet_size)
|
char const *packet, int packet_size)
|
||||||
{
|
{
|
||||||
|
@ -3470,6 +3471,13 @@ static int gdb_v_packet(struct connection *connection,
|
||||||
if (strncmp(packet, "vFlashDone", 10) == 0) {
|
if (strncmp(packet, "vFlashDone", 10) == 0) {
|
||||||
uint32_t written;
|
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
|
/* process the flashing buffer. No need to erase as GDB
|
||||||
* always issues a vFlashErase first. */
|
* always issues a vFlashErase first. */
|
||||||
target_call_event_callbacks(target,
|
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 connection *connection = priv;
|
||||||
struct gdb_connection *gdb_con = 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 */
|
/* No out allowed */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -3649,10 +3657,14 @@ static int gdb_input_inner(struct connection *connection)
|
||||||
retval = gdb_set_register_packet(connection, packet, packet_size);
|
retval = gdb_set_register_packet(connection, packet, packet_size);
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
|
gdb_con->output_flag = GDB_OUTPUT_NOTIF;
|
||||||
retval = gdb_read_memory_packet(connection, packet, packet_size);
|
retval = gdb_read_memory_packet(connection, packet, packet_size);
|
||||||
|
gdb_con->output_flag = GDB_OUTPUT_NO;
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
|
gdb_con->output_flag = GDB_OUTPUT_NOTIF;
|
||||||
retval = gdb_write_memory_packet(connection, packet, packet_size);
|
retval = gdb_write_memory_packet(connection, packet, packet_size);
|
||||||
|
gdb_con->output_flag = GDB_OUTPUT_NO;
|
||||||
break;
|
break;
|
||||||
case 'z':
|
case 'z':
|
||||||
case 'Z':
|
case 'Z':
|
||||||
|
@ -3743,9 +3755,9 @@ static int gdb_input_inner(struct connection *connection)
|
||||||
retval = gdb_detach(connection);
|
retval = gdb_detach(connection);
|
||||||
break;
|
break;
|
||||||
case 'X':
|
case 'X':
|
||||||
|
gdb_con->output_flag = GDB_OUTPUT_NOTIF;
|
||||||
retval = gdb_write_memory_binary_packet(connection, packet, packet_size);
|
retval = gdb_write_memory_binary_packet(connection, packet, packet_size);
|
||||||
if (retval != ERROR_OK)
|
gdb_con->output_flag = GDB_OUTPUT_NO;
|
||||||
return retval;
|
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
if (gdb_con->extended_protocol) {
|
if (gdb_con->extended_protocol) {
|
||||||
|
@ -3843,19 +3855,51 @@ static int gdb_input(struct connection *connection)
|
||||||
return ERROR_OK;
|
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)
|
static void gdb_keep_client_alive(struct connection *connection)
|
||||||
{
|
{
|
||||||
struct gdb_connection *gdb_con = connection->priv;
|
struct gdb_connection *gdb_con = connection->priv;
|
||||||
|
|
||||||
if (gdb_con->busy) {
|
|
||||||
/* do not send packets, retry asap */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (gdb_con->output_flag) {
|
switch (gdb_con->output_flag) {
|
||||||
case GDB_OUTPUT_NO:
|
case GDB_OUTPUT_NO:
|
||||||
/* no need for keep-alive */
|
/* no need for keep-alive */
|
||||||
break;
|
break;
|
||||||
|
case GDB_OUTPUT_NOTIF:
|
||||||
|
/* send asynchronous notification */
|
||||||
|
gdb_async_notif(connection);
|
||||||
|
break;
|
||||||
case GDB_OUTPUT_ALL:
|
case GDB_OUTPUT_ALL:
|
||||||
/* send an empty O packet */
|
/* send an empty O packet */
|
||||||
gdb_output_con(connection, "");
|
gdb_output_con(connection, "");
|
||||||
|
|
|
@ -15,22 +15,15 @@
|
||||||
#include "ipdbg.h"
|
#include "ipdbg.h"
|
||||||
|
|
||||||
#define IPDBG_BUFFER_SIZE 16384
|
#define IPDBG_BUFFER_SIZE 16384
|
||||||
#define IPDBG_MIN_NUM_OF_OPTIONS 2
|
#define IPDBG_MIN_NUM_OF_CREATE_OPTIONS 3
|
||||||
#define IPDBG_MAX_NUM_OF_OPTIONS 14
|
#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_MIN_DR_LENGTH 11
|
||||||
#define IPDBG_MAX_DR_LENGTH 13
|
#define IPDBG_MAX_DR_LENGTH 13
|
||||||
#define IPDBG_TCP_PORT_STR_MAX_LENGTH 6
|
#define IPDBG_TCP_PORT_STR_MAX_LENGTH 6
|
||||||
#define IPDBG_SCRATCH_MEMORY_SIZE 1024
|
#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 */
|
/* private connection data for IPDBG */
|
||||||
struct ipdbg_fifo {
|
struct ipdbg_fifo {
|
||||||
|
@ -75,6 +68,8 @@ struct ipdbg_hub {
|
||||||
uint32_t xoff_mask;
|
uint32_t xoff_mask;
|
||||||
uint32_t tool_mask;
|
uint32_t tool_mask;
|
||||||
uint32_t last_dn_tool;
|
uint32_t last_dn_tool;
|
||||||
|
char *name;
|
||||||
|
size_t using_queue_size;
|
||||||
struct ipdbg_hub *next;
|
struct ipdbg_hub *next;
|
||||||
struct jtag_tap *tap;
|
struct jtag_tap *tap;
|
||||||
struct connection **connections;
|
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)
|
for (ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next)
|
||||||
;
|
;
|
||||||
ihub->next = hub;
|
ihub->next = hub;
|
||||||
} else
|
} else {
|
||||||
ipdbg_first_hub = hub;
|
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)
|
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;
|
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)
|
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;
|
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);
|
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);
|
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,
|
ipdbg_init_scan_field(hub->scratch_memory.fields + i,
|
||||||
hub->scratch_memory.dr_in_vals + i * dreg_buffer_size,
|
hub->scratch_memory.dr_in_vals + i * dreg_buffer_size,
|
||||||
hub->data_register_length,
|
hub->data_register_length,
|
||||||
|
@ -482,7 +465,7 @@ static int ipdbg_shift_empty_data(struct ipdbg_hub *hub)
|
||||||
|
|
||||||
if (retval == ERROR_OK) {
|
if (retval == ERROR_OK) {
|
||||||
uint32_t up_data;
|
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 +
|
up_data = buf_get_u32(hub->scratch_memory.dr_in_vals +
|
||||||
i * dreg_buffer_size, 0,
|
i * dreg_buffer_size, 0,
|
||||||
hub->data_register_length);
|
hub->data_register_length);
|
||||||
|
@ -531,8 +514,8 @@ static int ipdbg_jtag_transfer_bytes(struct ipdbg_hub *hub,
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
const size_t dreg_buffer_size = DIV_ROUND_UP(hub->data_register_length, 8);
|
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) ?
|
size_t num_tx = (connection->dn_fifo.count < hub->using_queue_size) ?
|
||||||
connection->dn_fifo.count : IPDBG_CONSECUTIVE_UP_TRANSFERS;
|
connection->dn_fifo.count : hub->using_queue_size;
|
||||||
|
|
||||||
for (size_t i = 0; i < num_tx; ++i) {
|
for (size_t i = 0; i < num_tx; ++i) {
|
||||||
uint32_t dn_data = hub->valid_mask | ((tool & hub->tool_mask) << 8) |
|
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,
|
.keep_client_alive_handler = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instruction,
|
static struct ipdbg_hub *ipdbg_get_hub_by_name(const char *name)
|
||||||
uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool)
|
|
||||||
{
|
{
|
||||||
LOG_INFO("starting ipdbg service on port %d for tool %d", port, tool);
|
struct ipdbg_hub *hub = NULL;
|
||||||
|
for (hub = ipdbg_first_hub; hub; hub = hub->next) {
|
||||||
struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir);
|
if (strcmp(hub->name, name) == 0)
|
||||||
if (hub) {
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
return hub;
|
||||||
|
};
|
||||||
|
|
||||||
struct ipdbg_service *service = NULL;
|
static int ipdbg_stop_service(struct ipdbg_service *service)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
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);
|
int retval = ipdbg_remove_service(service);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
LOG_ERROR("BUG: ipdbg_remove_service failed");
|
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");
|
LOG_ERROR("BUG: remove_service failed");
|
||||||
return retval;
|
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;
|
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;
|
uint16_t port = 4242;
|
||||||
uint8_t tool = 1;
|
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;
|
uint32_t user_instruction = 0x00;
|
||||||
uint8_t data_register_length = IPDBG_MAX_DR_LENGTH;
|
uint8_t data_register_length = IPDBG_MAX_DR_LENGTH;
|
||||||
bool start = true;
|
|
||||||
bool hub_configured = false;
|
|
||||||
bool has_virtual_ir = false;
|
bool has_virtual_ir = false;
|
||||||
uint32_t virtual_ir_instruction = 0x00e;
|
uint32_t virtual_ir_instruction = 0x00e;
|
||||||
uint32_t virtual_ir_length = 5;
|
uint32_t virtual_ir_length = 5;
|
||||||
uint32_t virtual_ir_value = 0x11;
|
uint32_t virtual_ir_value = 0x11;
|
||||||
struct ipdbg_virtual_ir_info *virtual_ir = NULL;
|
struct ipdbg_virtual_ir_info *virtual_ir = NULL;
|
||||||
int user_num = 1;
|
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;
|
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 (strcmp(CMD_ARGV[i], "-tap") == 0) {
|
||||||
if (i + 1 >= CMD_ARGC || CMD_ARGV[i + 1][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;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
tap = jtag_tap_by_string(CMD_ARGV[i + 1]);
|
tap = jtag_tap_by_string(CMD_ARGV[i + 1]);
|
||||||
|
@ -874,7 +1043,7 @@ COMMAND_HANDLER(handle_ipdbg_command)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
++i;
|
++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");
|
COMMAND_PARSE_ADDITIONAL_NUMBER(u32, i, user_instruction, "ir_value to select hub");
|
||||||
hub_configured = true;
|
hub_configured = true;
|
||||||
COMMAND_PARSE_OPTIONAL_NUMBER(u8, i, data_register_length);
|
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_length);
|
||||||
COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_instruction);
|
COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_instruction);
|
||||||
has_virtual_ir = true;
|
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 {
|
} else {
|
||||||
command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]);
|
command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tap) {
|
if (!tap) {
|
||||||
command_print(CMD, "no valid tap selected");
|
command_print(CMD, "no valid tap selected");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -941,8 +1101,8 @@ COMMAND_HANDLER(handle_ipdbg_command)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tool >= ipdbg_max_tools_from_data_register_length(data_register_length)) {
|
if (ipdbg_get_hub_by_name(hub_name)) {
|
||||||
command_print(CMD, "Tool: %d is invalid", tool);
|
LOG_ERROR("IPDBG hub with name '%s' already exists", hub_name);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -957,20 +1117,38 @@ COMMAND_HANDLER(handle_ipdbg_command)
|
||||||
virtual_ir->value = virtual_ir_value;
|
virtual_ir->value = virtual_ir_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start)
|
if (ipdbg_find_hub(tap, user_instruction, virtual_ir)) {
|
||||||
return ipdbg_start(port, tap, user_instruction, data_register_length, virtual_ir, tool);
|
LOG_ERROR("IPDBG hub for given TAP and user-instruction already exists");
|
||||||
else
|
free(virtual_ir);
|
||||||
return ipdbg_stop(tap, user_instruction, virtual_ir, tool);
|
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[] = {
|
static const struct command_registration ipdbg_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "ipdbg",
|
.name = "ipdbg",
|
||||||
.handler = handle_ipdbg_command,
|
.mode = COMMAND_ANY,
|
||||||
.mode = COMMAND_EXEC,
|
.help = "IPDBG Hub/Host commands.",
|
||||||
.help = "Starts or stops an IPDBG JTAG-Host server.",
|
.usage = "",
|
||||||
.usage = "[-start|-stop] -tap device.tap -hub ir_value [dr_length]"
|
.chain = ipdbg_config_command_handlers,
|
||||||
" [-port number] [-tool number] [-vir [vir_value [length [instr_code]]]]",
|
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,5 +7,6 @@
|
||||||
#include <helper/command.h>
|
#include <helper/command.h>
|
||||||
|
|
||||||
int ipdbg_register_commands(struct command_context *cmd_ctx);
|
int ipdbg_register_commands(struct command_context *cmd_ctx);
|
||||||
|
int ipdbg_server_free(void);
|
||||||
|
|
||||||
#endif /* OPENOCD_IPDBG_IPDBG_H */
|
#endif /* OPENOCD_IPDBG_IPDBG_H */
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "openocd.h"
|
#include "openocd.h"
|
||||||
#include "tcl_server.h"
|
#include "tcl_server.h"
|
||||||
#include "telnet_server.h"
|
#include "telnet_server.h"
|
||||||
|
#include "ipdbg.h"
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
@ -714,6 +715,7 @@ void server_free(void)
|
||||||
tcl_service_free();
|
tcl_service_free();
|
||||||
telnet_service_free();
|
telnet_service_free();
|
||||||
jsp_service_free();
|
jsp_service_free();
|
||||||
|
ipdbg_server_free();
|
||||||
|
|
||||||
free(bindto_name);
|
free(bindto_name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@ static int aarch64_restore_system_control_reg(struct target *target)
|
||||||
case ARM_MODE_HYP:
|
case ARM_MODE_HYP:
|
||||||
case ARM_MODE_UND:
|
case ARM_MODE_UND:
|
||||||
case ARM_MODE_SYS:
|
case ARM_MODE_SYS:
|
||||||
|
case ARM_MODE_MON:
|
||||||
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
|
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -172,6 +173,7 @@ static int aarch64_mmu_modify(struct target *target, int enable)
|
||||||
case ARM_MODE_HYP:
|
case ARM_MODE_HYP:
|
||||||
case ARM_MODE_UND:
|
case ARM_MODE_UND:
|
||||||
case ARM_MODE_SYS:
|
case ARM_MODE_SYS:
|
||||||
|
case ARM_MODE_MON:
|
||||||
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
|
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1043,6 +1045,7 @@ static int aarch64_post_debug_entry(struct target *target)
|
||||||
case ARM_MODE_HYP:
|
case ARM_MODE_HYP:
|
||||||
case ARM_MODE_UND:
|
case ARM_MODE_UND:
|
||||||
case ARM_MODE_SYS:
|
case ARM_MODE_SYS:
|
||||||
|
case ARM_MODE_MON:
|
||||||
instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0);
|
instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0);
|
||||||
break;
|
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
|
* options, JIM_OK if it correctly parsed the topmost option
|
||||||
* and JIM_ERR if an error occurred during parameter evaluation.
|
* and JIM_ERR if an error occurred during parameter evaluation.
|
||||||
* For JIM_CONTINUE, we check our own params.
|
* 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_ext(target, goi, &pc->adiv5_config, ADI_CONFIGURE_DAP_COMPULSORY);
|
||||||
e = adiv5_jim_configure(target, goi);
|
|
||||||
target->private_config = pc;
|
|
||||||
if (e != JIM_CONTINUE)
|
if (e != JIM_CONTINUE)
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
|
|
|
@ -84,16 +84,8 @@ static void swd_clear_sticky_errors(struct adiv5_dap *dap)
|
||||||
static int swd_run_inner(struct adiv5_dap *dap)
|
static int swd_run_inner(struct adiv5_dap *dap)
|
||||||
{
|
{
|
||||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = swd->run();
|
return swd->run();
|
||||||
|
|
||||||
if (retval != ERROR_OK) {
|
|
||||||
/* fault response */
|
|
||||||
dap->do_reconnect = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int check_sync(struct adiv5_dap *dap)
|
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)
|
static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned int reg)
|
||||||
{
|
{
|
||||||
/* Only register address 0 (ADIv6 only) and 4 are banked. */
|
/* 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;
|
return ERROR_OK;
|
||||||
|
|
||||||
uint32_t sel = (reg >> 4) & DP_SELECT_DPBANK;
|
uint32_t sel = (reg >> 4) & DP_SELECT_DPBANK;
|
||||||
|
|
||||||
/* DP register 0 is not mapped according to ADIv5
|
/* ADIv6 ensures DPBANKSEL = 0 after line reset */
|
||||||
* whereas ADIv6 ensures DPBANKSEL = 0 after line reset */
|
if ((dap->select_valid || (is_adiv6(dap) && dap->select_dpbanksel_valid))
|
||||||
if ((dap->select_valid || ((reg & 0xf) == 0 && dap->select_dpbanksel_valid))
|
|
||||||
&& (sel == (dap->select & DP_SELECT_DPBANK)))
|
&& (sel == (dap->select & DP_SELECT_DPBANK)))
|
||||||
return ERROR_OK;
|
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,
|
static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg,
|
||||||
uint32_t data)
|
uint32_t data)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval = ERROR_OK;
|
||||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||||
assert(swd);
|
assert(swd);
|
||||||
|
|
||||||
|
@ -167,7 +158,11 @@ static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg,
|
||||||
if (reg == DP_SELECT1)
|
if (reg == DP_SELECT1)
|
||||||
dap->select = ((uint64_t)data << 32) | (dap->select & 0xffffffffull);
|
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);
|
retval = swd_queue_dp_bankselect(dap, reg);
|
||||||
|
|
||||||
if (retval == ERROR_OK) {
|
if (retval == ERROR_OK) {
|
||||||
swd->write_reg(swd_cmd(false, false, reg), data, 0);
|
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;
|
swd_multidrop_selected_dap = NULL;
|
||||||
if (retry > 3) {
|
if (retry > 3) {
|
||||||
LOG_ERROR("Failed to select multidrop %s", adiv5_dap_name(dap));
|
LOG_ERROR("Failed to select multidrop %s", adiv5_dap_name(dap));
|
||||||
|
dap->do_reconnect = true;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Failed to select multidrop %s, retrying...",
|
LOG_DEBUG("Failed to select multidrop %s, retrying...",
|
||||||
adiv5_dap_name(dap));
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,7 +627,13 @@ static int swd_run(struct adiv5_dap *dap)
|
||||||
|
|
||||||
swd_finish_read(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 */
|
/** Put the SWJ-DP back to JTAG mode */
|
||||||
|
|
|
@ -2424,11 +2424,12 @@ err_no_param:
|
||||||
return JIM_ERR;
|
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;
|
int e;
|
||||||
|
|
||||||
|
if (!pc) {
|
||||||
pc = (struct adiv5_private_config *)target->private_config;
|
pc = (struct adiv5_private_config *)target->private_config;
|
||||||
if (!pc) {
|
if (!pc) {
|
||||||
pc = calloc(1, sizeof(struct adiv5_private_config));
|
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;
|
pc->ap_num = DP_APSEL_INVALID;
|
||||||
target->private_config = pc;
|
target->private_config = pc;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optional == ADI_CONFIGURE_DAP_COMPULSORY)
|
||||||
target->has_dap = true;
|
target->has_dap = true;
|
||||||
|
|
||||||
e = adiv5_jim_spot_configure(goi, &pc->dap, &pc->ap_num, NULL);
|
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->tap = pc->dap->tap;
|
||||||
target->dap_configured = true;
|
target->dap_configured = true;
|
||||||
|
target->has_dap = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return JIM_OK;
|
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)
|
int adiv5_verify_config(struct adiv5_private_config *pc)
|
||||||
{
|
{
|
||||||
if (!pc)
|
if (!pc)
|
||||||
|
|
|
@ -788,6 +788,15 @@ struct adiv5_private_config {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int adiv5_verify_config(struct adiv5_private_config *pc);
|
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);
|
extern int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi);
|
||||||
|
|
||||||
struct adiv5_mem_ap_spot {
|
struct adiv5_mem_ap_spot {
|
||||||
|
|
|
@ -194,11 +194,11 @@ static const char *mem_ap_get_gdb_arch(const struct target *target)
|
||||||
* reg[24]: 32 bits, fps
|
* reg[24]: 32 bits, fps
|
||||||
* reg[25]: 32 bits, cpsr
|
* 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_REGS 26
|
||||||
|
#define NUM_GDB_REGS 16
|
||||||
#define MAX_REG_SIZE 96
|
#define MAX_REG_SIZE 96
|
||||||
#define REG_EXIST(n) ((n) < 16)
|
|
||||||
#define REG_SIZE(n) ((((n) >= 16) && ((n) < 24)) ? 96 : 32)
|
#define REG_SIZE(n) ((((n) >= 16) && ((n) < 24)) ? 96 : 32)
|
||||||
|
|
||||||
struct mem_ap_alloc_reg_list {
|
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 = 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;
|
struct reg *regs = mem_ap_alloc->regs;
|
||||||
|
|
||||||
for (int i = 0; i < NUM_REGS; i++) {
|
for (int i = 0; i < NUM_REGS; i++) {
|
||||||
regs[i].number = i;
|
regs[i].number = i;
|
||||||
regs[i].value = mem_ap_alloc->regs_value;
|
regs[i].value = mem_ap_alloc->regs_value;
|
||||||
regs[i].size = REG_SIZE(i);
|
regs[i].size = REG_SIZE(i);
|
||||||
regs[i].exist = REG_EXIST(i);
|
regs[i].exist = true;
|
||||||
regs[i].type = &mem_ap_reg_arch_type;
|
regs[i].type = &mem_ap_reg_arch_type;
|
||||||
(*reg_list)[i] = ®s[i];
|
(*reg_list)[i] = ®s[i];
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,6 +161,67 @@ static const struct {
|
||||||
#define MIPS32_NUM_REGS ARRAY_SIZE(mips32_regs)
|
#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)
|
static int mips32_get_core_reg(struct reg *reg)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -201,6 +262,61 @@ static int mips32_set_core_reg(struct reg *reg, uint8_t *buf)
|
||||||
return ERROR_OK;
|
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)
|
static int mips32_read_core_reg(struct target *target, unsigned int num)
|
||||||
{
|
{
|
||||||
unsigned int cnum;
|
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;
|
cnum = num - MIPS32_REGLIST_C0_INDEX;
|
||||||
reg_value = mips32->core_regs.cp0[cnum];
|
reg_value = mips32->core_regs.cp0[cnum];
|
||||||
buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value);
|
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) {
|
} else if (num >= MIPS32_REGLIST_FPC_INDEX) {
|
||||||
/* FPCR */
|
/* FPCR */
|
||||||
cnum = num - MIPS32_REGLIST_FPC_INDEX;
|
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;
|
cnum = num - MIPS32_REGLIST_C0_INDEX;
|
||||||
reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32);
|
reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32);
|
||||||
mips32->core_regs.cp0[cnum] = (uint32_t)reg_value;
|
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) {
|
} else if (num >= MIPS32_REGLIST_FPC_INDEX) {
|
||||||
/* FPCR */
|
/* FPCR */
|
||||||
cnum = num - MIPS32_REGLIST_FPC_INDEX;
|
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;
|
mips32->fp_imp = MIPS32_FP_IMP_NONE;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
uint32_t status_value;
|
uint32_t fir_value, status_value;
|
||||||
bool status_fr, status_cu1;
|
bool fpu_in_64bit, fp_enabled;
|
||||||
|
|
||||||
retval = mips32_cp0_read(ejtag_info, &status_value, MIPS32_C0_STATUS, 0);
|
retval = mips32_cp0_read(ejtag_info, &status_value, MIPS32_C0_STATUS, 0);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
@ -935,20 +1055,34 @@ static int mips32_read_config_fpu(struct mips32_common *mips32, struct mips_ejta
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_fr = (status_value >> MIPS32_CP0_STATUS_FR_SHIFT) & 0x1;
|
fpu_in_64bit = (status_value & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0;
|
||||||
status_cu1 = (status_value >> MIPS32_CP0_STATUS_CU1_SHIFT) & 0x1;
|
fp_enabled = (status_value & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0;
|
||||||
if (status_cu1) {
|
if (fp_enabled) {
|
||||||
/* TODO: read fpu(cp1) config register for current operating mode.
|
retval = mips32_cp1_control_read(ejtag_info, &fir_value, 0);
|
||||||
* Now its set to 32 bits by default. */
|
if (retval != ERROR_OK) {
|
||||||
snprintf(buf, sizeof(buf), "yes");
|
LOG_ERROR("Failed to read cp1 FIR register");
|
||||||
fp_imp = MIPS32_FP_IMP_32;
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fir_value >> MIPS32_CP1_FIR_F64_SHIFT) & 0x1)
|
||||||
|
fp_imp++;
|
||||||
} else {
|
} else {
|
||||||
|
/* This is the only condition that writes to buf */
|
||||||
snprintf(buf, sizeof(buf), "yes, disabled");
|
snprintf(buf, sizeof(buf), "yes, disabled");
|
||||||
fp_imp = MIPS32_FP_IMP_UNKNOWN;
|
fp_imp = MIPS32_FP_IMP_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
mips32->fpu_in_64bit = status_fr;
|
mips32->fpu_in_64bit = fpu_in_64bit;
|
||||||
mips32->fpu_enabled = status_cu1;
|
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);
|
LOG_USER("FPU implemented: %s", buf);
|
||||||
mips32->fp_imp = fp_imp;
|
mips32->fp_imp = fp_imp;
|
||||||
|
@ -1544,6 +1678,204 @@ COMMAND_HANDLER(mips32_handle_cp0_command)
|
||||||
return retval;
|
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.
|
* mips32_handle_cpuinfo_command - Handles the 'cpuinfo' command.
|
||||||
* @param[in] cmd: Command invocation context.
|
* @param[in] cmd: Command invocation context.
|
||||||
|
@ -1746,6 +2078,167 @@ COMMAND_HANDLER(mips32_handle_cpuinfo_command)
|
||||||
return ERROR_OK;
|
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
|
* mips32_handle_ejtag_reg_command - Handler commands related to EJTAG
|
||||||
* @param[in] cmd: Command invocation context
|
* @param[in] cmd: Command invocation context
|
||||||
|
@ -1847,6 +2340,14 @@ static const struct command_registration mips32_exec_command_handlers[] = {
|
||||||
.help = "display CPU information",
|
.help = "display CPU information",
|
||||||
.usage = "",
|
.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",
|
.name = "scan_delay",
|
||||||
.handler = mips32_handle_scan_delay_command,
|
.handler = mips32_handle_scan_delay_command,
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
|
|
||||||
#define MIPS32_SCAN_DELAY_LEGACY_MODE 2000000
|
#define MIPS32_SCAN_DELAY_LEGACY_MODE 2000000
|
||||||
|
|
||||||
#define MIPS32_NUM_DSPREGS 9
|
#define MIPS32NUMDSPREGS 9
|
||||||
|
|
||||||
/* Bit Mask indicating CP0 register supported by this core */
|
/* Bit Mask indicating CP0 register supported by this core */
|
||||||
#define MIPS_CP0_MK4 0x0001
|
#define MIPS_CP0_MK4 0x0001
|
||||||
|
@ -459,10 +459,13 @@ struct mips32_algorithm {
|
||||||
#define MIPS32_OP_AND 0x24u
|
#define MIPS32_OP_AND 0x24u
|
||||||
#define MIPS32_OP_CACHE 0x2Fu
|
#define MIPS32_OP_CACHE 0x2Fu
|
||||||
#define MIPS32_OP_COP0 0x10u
|
#define MIPS32_OP_COP0 0x10u
|
||||||
|
#define MIPS32_OP_COP1 0x11u
|
||||||
#define MIPS32_OP_J 0x02u
|
#define MIPS32_OP_J 0x02u
|
||||||
#define MIPS32_OP_JR 0x08u
|
#define MIPS32_OP_JR 0x08u
|
||||||
#define MIPS32_OP_LUI 0x0Fu
|
#define MIPS32_OP_LUI 0x0Fu
|
||||||
#define MIPS32_OP_LW 0x23u
|
#define MIPS32_OP_LW 0x23u
|
||||||
|
#define MIPS32_OP_LWC1 0x31u
|
||||||
|
#define MIPS32_OP_LDC1 0x35u
|
||||||
#define MIPS32_OP_LB 0x20u
|
#define MIPS32_OP_LB 0x20u
|
||||||
#define MIPS32_OP_LBU 0x24u
|
#define MIPS32_OP_LBU 0x24u
|
||||||
#define MIPS32_OP_LHU 0x25u
|
#define MIPS32_OP_LHU 0x25u
|
||||||
|
@ -470,6 +473,7 @@ struct mips32_algorithm {
|
||||||
#define MIPS32_OP_MTHI 0x11u
|
#define MIPS32_OP_MTHI 0x11u
|
||||||
#define MIPS32_OP_MFLO 0x12u
|
#define MIPS32_OP_MFLO 0x12u
|
||||||
#define MIPS32_OP_MTLO 0x13u
|
#define MIPS32_OP_MTLO 0x13u
|
||||||
|
#define MIPS32_OP_MUL 0x02u
|
||||||
#define MIPS32_OP_RDHWR 0x3Bu
|
#define MIPS32_OP_RDHWR 0x3Bu
|
||||||
#define MIPS32_OP_SB 0x28u
|
#define MIPS32_OP_SB 0x28u
|
||||||
#define MIPS32_OP_SH 0x29u
|
#define MIPS32_OP_SH 0x29u
|
||||||
|
@ -485,6 +489,8 @@ struct mips32_algorithm {
|
||||||
#define MIPS32_OP_SLLV 0x04u
|
#define MIPS32_OP_SLLV 0x04u
|
||||||
#define MIPS32_OP_SLTI 0x0Au
|
#define MIPS32_OP_SLTI 0x0Au
|
||||||
#define MIPS32_OP_MOVN 0x0Bu
|
#define MIPS32_OP_MOVN 0x0Bu
|
||||||
|
#define MIPS32_OP_SWC1 0x39u
|
||||||
|
#define MIPS32_OP_SDC1 0x3Du
|
||||||
|
|
||||||
#define MIPS32_OP_REGIMM 0x01u
|
#define MIPS32_OP_REGIMM 0x01u
|
||||||
#define MIPS32_OP_SDBBP 0x3Fu
|
#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_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_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_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_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_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)
|
#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_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_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_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_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_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_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_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)
|
#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_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_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_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_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)
|
#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_BGTZ 0x06u
|
||||||
#define MMIPS32_OP_BNE 0x2Du
|
#define MMIPS32_OP_BNE 0x2Du
|
||||||
#define MMIPS32_OP_CACHE 0x06u
|
#define MMIPS32_OP_CACHE 0x06u
|
||||||
|
#define MMIPS32_OP_CFC1 0x40u
|
||||||
#define MMIPS32_OP_J 0x35u
|
#define MMIPS32_OP_J 0x35u
|
||||||
#define MMIPS32_OP_JALR 0x03Cu
|
#define MMIPS32_OP_JALR 0x03Cu
|
||||||
#define MMIPS32_OP_JALRHB 0x07Cu
|
#define MMIPS32_OP_JALRHB 0x07Cu
|
||||||
|
@ -596,8 +612,14 @@ struct mips32_algorithm {
|
||||||
#define MMIPS32_OP_LHU 0x0Du
|
#define MMIPS32_OP_LHU 0x0Du
|
||||||
#define MMIPS32_OP_LUI 0x0Du
|
#define MMIPS32_OP_LUI 0x0Du
|
||||||
#define MMIPS32_OP_LW 0x3Fu
|
#define MMIPS32_OP_LW 0x3Fu
|
||||||
|
#define MMIPS32_OP_LWC1 0x27u
|
||||||
|
#define MMIPS32_OP_LDC1 0x2Fu
|
||||||
#define MMIPS32_OP_MFC0 0x03u
|
#define MMIPS32_OP_MFC0 0x03u
|
||||||
|
#define MMIPS32_OP_MFC1 0x80u
|
||||||
|
#define MMIPS32_OP_MFHC1 0xC0u
|
||||||
#define MMIPS32_OP_MTC0 0x0Bu
|
#define MMIPS32_OP_MTC0 0x0Bu
|
||||||
|
#define MMIPS32_OP_MTC1 0xA0u
|
||||||
|
#define MMIPS32_OP_MTHC1 0xE0u
|
||||||
#define MMIPS32_OP_MFLO 0x075u
|
#define MMIPS32_OP_MFLO 0x075u
|
||||||
#define MMIPS32_OP_MFHI 0x035u
|
#define MMIPS32_OP_MFHI 0x035u
|
||||||
#define MMIPS32_OP_MTLO 0x0F5u
|
#define MMIPS32_OP_MTLO 0x0F5u
|
||||||
|
@ -608,6 +630,8 @@ struct mips32_algorithm {
|
||||||
#define MMIPS32_OP_SB 0x06u
|
#define MMIPS32_OP_SB 0x06u
|
||||||
#define MMIPS32_OP_SH 0x0Eu
|
#define MMIPS32_OP_SH 0x0Eu
|
||||||
#define MMIPS32_OP_SW 0x3Eu
|
#define MMIPS32_OP_SW 0x3Eu
|
||||||
|
#define MMIPS32_OP_SWC1 0x26u
|
||||||
|
#define MMIPS32_OP_SDC1 0x2Eu
|
||||||
#define MMIPS32_OP_SLTU 0x390u
|
#define MMIPS32_OP_SLTU 0x390u
|
||||||
#define MMIPS32_OP_SLL 0x000u
|
#define MMIPS32_OP_SLL 0x000u
|
||||||
#define MMIPS32_OP_SLTI 0x24u
|
#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_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_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_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_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)
|
#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_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_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_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,\
|
#define MMIPS32_MFC0(gpr, cpr, sel) MIPS32_R_INST(MMIPS32_POOL32A, gpr, cpr, sel,\
|
||||||
MMIPS32_OP_MFC0, MMIPS32_POOL32AXF)
|
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_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_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,\
|
#define MMIPS32_MTC0(gpr, cpr, sel) MIPS32_R_INST(MMIPS32_POOL32A, gpr, cpr, sel,\
|
||||||
MMIPS32_OP_MTC0, MMIPS32_POOL32AXF)
|
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_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)
|
#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_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_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_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_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)
|
#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_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_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_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_J(isa, tar) (isa ? MMIPS32_J(tar) : MIPS32_ISA_J(tar))
|
||||||
#define MIPS32_JR(isa, reg) (isa ? MMIPS32_JR(reg) : MIPS32_ISA_JR(reg))
|
#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_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_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_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_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_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_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_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_MFHI(isa, reg) (isa ? MMIPS32_MFHI(reg) : MIPS32_ISA_MFHI(reg))
|
||||||
#define MIPS32_MTLO(isa, reg) (isa ? MMIPS32_MTLO(reg) : MIPS32_ISA_MTLO(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_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_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_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_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))
|
#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 */
|
/* ejtag specific instructions */
|
||||||
#define MICRO_MIPS32_SDBBP 0x000046C0
|
#define MICRO_MIPS32_SDBBP 0x000046C0
|
||||||
#define MICRO_MIPS_SDBBP 0x46C0
|
#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)
|
* MIPS32 Config1 Register (CP0 Register 16, Select 1)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -588,6 +588,26 @@ int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_r
|
||||||
return ctx.retval;
|
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
|
* \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};
|
struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
|
||||||
uint32_t *gprs = mips32->core_regs.gpr;
|
uint32_t *gprs = mips32->core_regs.gpr;
|
||||||
uint32_t *c0rs = mips32->core_regs.cp0;
|
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);
|
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))
|
if (mips32_cpu_support_hazard_barrier(ejtag_info))
|
||||||
pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa));
|
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 */
|
/* load registers 2 to 31 with li32, optimize */
|
||||||
for (int i = 2; i < 32; i++)
|
for (int i = 2; i < 32; i++)
|
||||||
pracc_add_li32(&ctx, i, gprs[i], 1);
|
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;
|
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_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_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
|
* 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->reg8 = mips32->core_regs.gpr[8];
|
||||||
ejtag_info->reg9 = mips32->core_regs.gpr[9];
|
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 */
|
/* we only care if FP is actually impl'd and if cp1 is enabled */
|
||||||
/* since we already read cp0 in the prev step */
|
/* since we already read cp0 in the prev step */
|
||||||
/* now we know what's in cp0.status */
|
/* 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;
|
return ctx.retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,21 @@ int mips32_cp0_read(struct mips_ejtag *ejtag_info,
|
||||||
int mips32_cp0_write(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);
|
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)
|
static inline void pracc_swap16_array(struct mips_ejtag *ejtag_info, uint32_t *buf, int count)
|
||||||
{
|
{
|
||||||
if (ejtag_info->isa && ejtag_info->endianness)
|
if (ejtag_info->isa && ejtag_info->endianness)
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <helper/list.h>
|
#include <helper/list.h>
|
||||||
#include "helper/replacements.h"
|
#include "helper/replacements.h"
|
||||||
#include "helper/system.h"
|
#include "helper/system.h"
|
||||||
|
#include <helper/types.h>
|
||||||
#include <jim.h>
|
#include <jim.h>
|
||||||
|
|
||||||
struct reg;
|
struct reg;
|
||||||
|
|
|
@ -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 int xtensa_chip_jim_configure(struct target *target, struct jim_getopt_info *goi)
|
||||||
{
|
{
|
||||||
static bool dap_configured;
|
return adiv5_jim_configure_ext(target, goi, NULL, ADI_CONFIGURE_DAP_OPTIONAL);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Methods for generic example of Xtensa-based chip-level targets. */
|
/** Methods for generic example of Xtensa-based chip-level targets. */
|
||||||
|
|
|
@ -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
|
#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"
|
#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
|
set JTAGSPI_CHAIN_ID cycloneiii.pld
|
||||||
|
|
|
@ -15,7 +15,8 @@ adapter speed 10000
|
||||||
|
|
||||||
source [find cpld/xilinx-xc7.cfg]
|
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"
|
#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
|
set JTAGSPI_CHAIN_ID xc7.pld
|
||||||
|
|
|
@ -16,7 +16,8 @@ adapter speed 6000
|
||||||
source [find fpga/lattice_ecp5.cfg]
|
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"
|
#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
|
set JTAGSPI_CHAIN_ID ecp5.pld
|
||||||
source [find cpld/jtagspi.cfg]
|
source [find cpld/jtagspi.cfg]
|
||||||
|
|
|
@ -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"
|
#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
|
||||||
|
|
|
@ -20,7 +20,8 @@ adapter speed 6000
|
||||||
source [find fpga/efinix_trion.cfg]
|
source [find fpga/efinix_trion.cfg]
|
||||||
|
|
||||||
#openocd -f board/trion_t20_bga256.cfg -c "init" -c "pld load trion.pld outflow/trion_blinker.bit"
|
#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
|
set JTAGSPI_CHAIN_ID trion.pld
|
||||||
source [find cpld/jtagspi.cfg]
|
source [find cpld/jtagspi.cfg]
|
||||||
|
|
|
@ -45,13 +45,11 @@ if {![using_hla]} {
|
||||||
cortex_m reset_config sysresetreq
|
cortex_m reset_config sysresetreq
|
||||||
}
|
}
|
||||||
|
|
||||||
flash bank $_CHIPNAME.flash nrf51 0x00000000 0 1 1 $_TARGETNAME
|
flash bank $_CHIPNAME.flash nrf5 0x00000000 0 0 0 $_TARGETNAME
|
||||||
flash bank $_CHIPNAME.uicr nrf51 0x10001000 0 1 1 $_TARGETNAME
|
flash bank $_CHIPNAME.uicr nrf5 0x10001000 0 0 0 $_TARGETNAME
|
||||||
|
|
||||||
#
|
|
||||||
# The chip should start up from internal 16Mhz RC, so setting adapter
|
# The chip should start up from internal 16Mhz RC, so setting adapter
|
||||||
# clock to 1Mhz should be OK
|
# clock to 1Mhz should be OK
|
||||||
#
|
|
||||||
adapter speed 1000
|
adapter speed 1000
|
||||||
|
|
||||||
proc enable_all_ram {} {
|
proc enable_all_ram {} {
|
||||||
|
@ -60,4 +58,4 @@ proc enable_all_ram {} {
|
||||||
# resetting we enable all banks via the RAMON register
|
# resetting we enable all banks via the RAMON register
|
||||||
mww 0x40000524 0xF
|
mww 0x40000524 0xF
|
||||||
}
|
}
|
||||||
$_TARGETNAME configure -event reset-end { enable_all_ram }
|
$_TARGETNAME configure -event reset-init { enable_all_ram }
|
||||||
|
|
Loading…
Reference in New Issue