Merge pull request #131 from riscv/small_progbuf
Support program buffers that are just 2 instructions largemacbuild
commit
e50ee46a6f
|
@ -49,13 +49,12 @@ void riscv_batch_run(struct riscv_batch *batch)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
keep_alive();
|
keep_alive();
|
||||||
|
|
||||||
LOG_DEBUG("running a batch of %ld scans", (long)batch->used_scans);
|
LOG_DEBUG("running a batch of %ld scans", (long)batch->used_scans);
|
||||||
riscv_batch_add_nop(batch);
|
riscv_batch_add_nop(batch);
|
||||||
|
|
||||||
for (size_t i = 0; i < batch->used_scans; ++i) {
|
for (size_t i = 0; i < batch->used_scans; ++i) {
|
||||||
dump_field(batch->fields + i);
|
|
||||||
jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE);
|
jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE);
|
||||||
if (batch->idle_count > 0)
|
if (batch->idle_count > 0)
|
||||||
jtag_add_runtest(batch->idle_count, TAP_IDLE);
|
jtag_add_runtest(batch->idle_count, TAP_IDLE);
|
||||||
|
|
|
@ -173,12 +173,6 @@
|
||||||
#define CSR_DCSR_EBREAKM_LENGTH 1
|
#define CSR_DCSR_EBREAKM_LENGTH 1
|
||||||
#define CSR_DCSR_EBREAKM (0x1U << CSR_DCSR_EBREAKM_OFFSET)
|
#define CSR_DCSR_EBREAKM (0x1U << CSR_DCSR_EBREAKM_OFFSET)
|
||||||
/*
|
/*
|
||||||
* When 1, {\tt ebreak} instructions in Hypervisor Mode enter Debug Mode.
|
|
||||||
*/
|
|
||||||
#define CSR_DCSR_EBREAKH_OFFSET 14
|
|
||||||
#define CSR_DCSR_EBREAKH_LENGTH 1
|
|
||||||
#define CSR_DCSR_EBREAKH (0x1U << CSR_DCSR_EBREAKH_OFFSET)
|
|
||||||
/*
|
|
||||||
* When 1, {\tt ebreak} instructions in Supervisor Mode enter Debug Mode.
|
* When 1, {\tt ebreak} instructions in Supervisor Mode enter Debug Mode.
|
||||||
*/
|
*/
|
||||||
#define CSR_DCSR_EBREAKS_OFFSET 13
|
#define CSR_DCSR_EBREAKS_OFFSET 13
|
||||||
|
@ -207,9 +201,10 @@
|
||||||
/*
|
/*
|
||||||
* 0: Increment counters as usual.
|
* 0: Increment counters as usual.
|
||||||
*
|
*
|
||||||
* 1: Don't increment any counters while in Debug Mode. This includes
|
* 1: Don't increment any counters while in Debug Mode or on {\tt
|
||||||
* the {\tt cycle} and {\tt instret} CSRs. This is preferred for most
|
* ebreak} instructions that cause entry into Debug Mode. These
|
||||||
* debugging scenarios.
|
* counters include the {\tt cycle} and {\tt instret} CSRs. This is
|
||||||
|
* preferred for most debugging scenarios.
|
||||||
*
|
*
|
||||||
* An implementation may choose not to support writing to this bit.
|
* An implementation may choose not to support writing to this bit.
|
||||||
* The debugger must read back the value it writes to check whether
|
* The debugger must read back the value it writes to check whether
|
||||||
|
@ -312,9 +307,9 @@
|
||||||
*
|
*
|
||||||
* This bit is only writable from Debug Mode.
|
* This bit is only writable from Debug Mode.
|
||||||
*/
|
*/
|
||||||
#define CSR_TDATA1_HMODE_OFFSET XLEN-5
|
#define CSR_TDATA1_DMODE_OFFSET XLEN-5
|
||||||
#define CSR_TDATA1_HMODE_LENGTH 1
|
#define CSR_TDATA1_DMODE_LENGTH 1
|
||||||
#define CSR_TDATA1_HMODE (0x1ULL << CSR_TDATA1_HMODE_OFFSET)
|
#define CSR_TDATA1_DMODE (0x1ULL << CSR_TDATA1_DMODE_OFFSET)
|
||||||
/*
|
/*
|
||||||
* Trigger-specific data.
|
* Trigger-specific data.
|
||||||
*/
|
*/
|
||||||
|
@ -390,7 +385,7 @@
|
||||||
* 0: Raise a breakpoint exception. (Used when software wants to use
|
* 0: Raise a breakpoint exception. (Used when software wants to use
|
||||||
* the trigger module without an external debugger attached.)
|
* the trigger module without an external debugger attached.)
|
||||||
*
|
*
|
||||||
* 1: Enter Debug Mode. (Only supported when \Fhmode is 1.)
|
* 1: Enter Debug Mode. (Only supported when \Fdmode is 1.)
|
||||||
*
|
*
|
||||||
* 2: Start tracing.
|
* 2: Start tracing.
|
||||||
*
|
*
|
||||||
|
@ -532,7 +527,7 @@
|
||||||
* 0: Raise a breakpoint exception. (Used when software wants to use the
|
* 0: Raise a breakpoint exception. (Used when software wants to use the
|
||||||
* trigger module without an external debugger attached.)
|
* trigger module without an external debugger attached.)
|
||||||
*
|
*
|
||||||
* 1: Enter Debug Mode. (Only supported when \Fhmode is 1.)
|
* 1: Enter Debug Mode. (Only supported when \Fdmode is 1.)
|
||||||
*
|
*
|
||||||
* 2: Start tracing.
|
* 2: Start tracing.
|
||||||
*
|
*
|
||||||
|
@ -549,6 +544,30 @@
|
||||||
#define CSR_ICOUNT_ACTION (0x3fULL << CSR_ICOUNT_ACTION_OFFSET)
|
#define CSR_ICOUNT_ACTION (0x3fULL << CSR_ICOUNT_ACTION_OFFSET)
|
||||||
#define DMI_DMSTATUS 0x11
|
#define DMI_DMSTATUS 0x11
|
||||||
/*
|
/*
|
||||||
|
* If 1, then there is an implicit {\tt ebreak} instruction at the
|
||||||
|
* non-existent word immediately after the Program Buffer. This saves
|
||||||
|
* the debugger from having to write the {\tt ebreak} itself, and
|
||||||
|
* allows the Program Buffer to be one word smaller.
|
||||||
|
*
|
||||||
|
* This must be 1 when \Fprogbufsize is 1.
|
||||||
|
*/
|
||||||
|
#define DMI_DMSTATUS_IMPEBREAK_OFFSET 22
|
||||||
|
#define DMI_DMSTATUS_IMPEBREAK_LENGTH 1
|
||||||
|
#define DMI_DMSTATUS_IMPEBREAK (0x1U << DMI_DMSTATUS_IMPEBREAK_OFFSET)
|
||||||
|
/*
|
||||||
|
* Gets set if the Debug Module was accessed incorrectly.
|
||||||
|
*
|
||||||
|
* 0 (none): No error.
|
||||||
|
*
|
||||||
|
* 1 (badaddr): There was an access to an unimplemented Debug Module
|
||||||
|
* address.
|
||||||
|
*
|
||||||
|
* 7 (other): An access failed for another reason.
|
||||||
|
*/
|
||||||
|
#define DMI_DMSTATUS_DMERR_OFFSET 18
|
||||||
|
#define DMI_DMSTATUS_DMERR_LENGTH 3
|
||||||
|
#define DMI_DMSTATUS_DMERR (0x7U << DMI_DMSTATUS_DMERR_OFFSET)
|
||||||
|
/*
|
||||||
* This field is 1 when all currently selected harts have acknowledged the previous \Fresumereq.
|
* This field is 1 when all currently selected harts have acknowledged the previous \Fresumereq.
|
||||||
*/
|
*/
|
||||||
#define DMI_DMSTATUS_ALLRESUMEACK_OFFSET 17
|
#define DMI_DMSTATUS_ALLRESUMEACK_OFFSET 17
|
||||||
|
@ -629,6 +648,13 @@
|
||||||
#define DMI_DMSTATUS_AUTHBUSY_OFFSET 6
|
#define DMI_DMSTATUS_AUTHBUSY_OFFSET 6
|
||||||
#define DMI_DMSTATUS_AUTHBUSY_LENGTH 1
|
#define DMI_DMSTATUS_AUTHBUSY_LENGTH 1
|
||||||
#define DMI_DMSTATUS_AUTHBUSY (0x1U << DMI_DMSTATUS_AUTHBUSY_OFFSET)
|
#define DMI_DMSTATUS_AUTHBUSY (0x1U << DMI_DMSTATUS_AUTHBUSY_OFFSET)
|
||||||
|
/*
|
||||||
|
* 0: \Rdevtreeaddrzero--\Rdevtreeaddrthree hold information which
|
||||||
|
* is not relevant to the Device Tree.
|
||||||
|
*
|
||||||
|
* 1: \Rdevtreeaddrzero--\Rdevtreeaddrthree registers hold the address of the
|
||||||
|
* Device Tree.
|
||||||
|
*/
|
||||||
#define DMI_DMSTATUS_DEVTREEVALID_OFFSET 4
|
#define DMI_DMSTATUS_DEVTREEVALID_OFFSET 4
|
||||||
#define DMI_DMSTATUS_DEVTREEVALID_LENGTH 1
|
#define DMI_DMSTATUS_DEVTREEVALID_LENGTH 1
|
||||||
#define DMI_DMSTATUS_DEVTREEVALID (0x1U << DMI_DMSTATUS_DEVTREEVALID_OFFSET)
|
#define DMI_DMSTATUS_DEVTREEVALID (0x1U << DMI_DMSTATUS_DEVTREEVALID_OFFSET)
|
||||||
|
@ -654,7 +680,6 @@
|
||||||
*
|
*
|
||||||
* Writing 1 or 0 has no effect on a hart which is already halted, but
|
* Writing 1 or 0 has no effect on a hart which is already halted, but
|
||||||
* the bit should be cleared to 0 before the hart is resumed.
|
* the bit should be cleared to 0 before the hart is resumed.
|
||||||
* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior.
|
|
||||||
*
|
*
|
||||||
* Writes apply to the new value of \Fhartsel and \Fhasel.
|
* Writes apply to the new value of \Fhartsel and \Fhasel.
|
||||||
*/
|
*/
|
||||||
|
@ -664,7 +689,8 @@
|
||||||
/*
|
/*
|
||||||
* Resume request signal for all currently selected harts. When set to 1,
|
* Resume request signal for all currently selected harts. When set to 1,
|
||||||
* each selected hart will resume if it is currently halted.
|
* each selected hart will resume if it is currently halted.
|
||||||
* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior.
|
*
|
||||||
|
* This bit is ignored while \Fhaltreq is set.
|
||||||
*
|
*
|
||||||
* Writes apply to the new value of \Fhartsel and \Fhasel.
|
* Writes apply to the new value of \Fhartsel and \Fhasel.
|
||||||
*/
|
*/
|
||||||
|
@ -710,11 +736,12 @@
|
||||||
#define DMI_DMCONTROL_HARTSEL (0x3ffU << DMI_DMCONTROL_HARTSEL_OFFSET)
|
#define DMI_DMCONTROL_HARTSEL (0x3ffU << DMI_DMCONTROL_HARTSEL_OFFSET)
|
||||||
/*
|
/*
|
||||||
* This bit controls the reset signal from the DM to the rest of the
|
* This bit controls the reset signal from the DM to the rest of the
|
||||||
* system. To perform a system reset the debugger writes 1,
|
* system. The signal should reset every part of the system, including
|
||||||
|
* every hart, except for the DM and any logic required to access the
|
||||||
|
* DM.
|
||||||
|
* To perform a system reset the debugger writes 1,
|
||||||
* and then writes 0
|
* and then writes 0
|
||||||
* to deassert the reset. This bit must not reset the Debug Module
|
* to deassert the reset.
|
||||||
* registers. What it does reset is platform-specific (it may
|
|
||||||
* reset nothing).
|
|
||||||
*/
|
*/
|
||||||
#define DMI_DMCONTROL_NDMRESET_OFFSET 1
|
#define DMI_DMCONTROL_NDMRESET_OFFSET 1
|
||||||
#define DMI_DMCONTROL_NDMRESET_LENGTH 1
|
#define DMI_DMCONTROL_NDMRESET_LENGTH 1
|
||||||
|
@ -778,7 +805,7 @@
|
||||||
* shadowing the {\tt data} registers.
|
* shadowing the {\tt data} registers.
|
||||||
*
|
*
|
||||||
* If \Fdataaccess is 1: Signed address of RAM where the {\tt data}
|
* If \Fdataaccess is 1: Signed address of RAM where the {\tt data}
|
||||||
* registers are shadowed.
|
* registers are shadowed, to be used to access relative to \Rzero.
|
||||||
*/
|
*/
|
||||||
#define DMI_HARTINFO_DATAADDR_OFFSET 0
|
#define DMI_HARTINFO_DATAADDR_OFFSET 0
|
||||||
#define DMI_HARTINFO_DATAADDR_LENGTH 12
|
#define DMI_HARTINFO_DATAADDR_LENGTH 12
|
||||||
|
@ -891,13 +918,10 @@
|
||||||
#define DMI_ABSTRACTCS 0x16
|
#define DMI_ABSTRACTCS 0x16
|
||||||
/*
|
/*
|
||||||
* Size of the Program Buffer, in 32-bit words. Valid sizes are 0 - 16.
|
* Size of the Program Buffer, in 32-bit words. Valid sizes are 0 - 16.
|
||||||
*
|
|
||||||
* TODO: Explain what can be done with each size of the buffer, to suggest
|
|
||||||
* why you would want more or less words.
|
|
||||||
*/
|
*/
|
||||||
#define DMI_ABSTRACTCS_PROGSIZE_OFFSET 24
|
#define DMI_ABSTRACTCS_PROGBUFSIZE_OFFSET 24
|
||||||
#define DMI_ABSTRACTCS_PROGSIZE_LENGTH 5
|
#define DMI_ABSTRACTCS_PROGBUFSIZE_LENGTH 5
|
||||||
#define DMI_ABSTRACTCS_PROGSIZE (0x1fU << DMI_ABSTRACTCS_PROGSIZE_OFFSET)
|
#define DMI_ABSTRACTCS_PROGBUFSIZE (0x1fU << DMI_ABSTRACTCS_PROGBUFSIZE_OFFSET)
|
||||||
/*
|
/*
|
||||||
* 1: An abstract command is currently being executed.
|
* 1: An abstract command is currently being executed.
|
||||||
*
|
*
|
||||||
|
@ -1013,24 +1037,22 @@
|
||||||
*
|
*
|
||||||
* 4: 128-bit
|
* 4: 128-bit
|
||||||
*
|
*
|
||||||
* If an unsupported system bus access size is written here,
|
* If an unsupported system bus access size is written here, the DM
|
||||||
* the DM may not perform the access, or may perform the access
|
* does not perform the access and sberror is set to 3.
|
||||||
* with any access size.
|
|
||||||
*/
|
*/
|
||||||
#define DMI_SBCS_SBACCESS_OFFSET 17
|
#define DMI_SBCS_SBACCESS_OFFSET 17
|
||||||
#define DMI_SBCS_SBACCESS_LENGTH 3
|
#define DMI_SBCS_SBACCESS_LENGTH 3
|
||||||
#define DMI_SBCS_SBACCESS (0x7U << DMI_SBCS_SBACCESS_OFFSET)
|
#define DMI_SBCS_SBACCESS (0x7U << DMI_SBCS_SBACCESS_OFFSET)
|
||||||
/*
|
/*
|
||||||
* When 1, the internal address value (used by the system bus master)
|
* When 1, {\tt sbaddress} is incremented by the access size (in
|
||||||
* is incremented by the access size (in bytes) selected in \Fsbaccess
|
* bytes) selected in \Fsbaccess after every system bus access.
|
||||||
* after every system bus access.
|
|
||||||
*/
|
*/
|
||||||
#define DMI_SBCS_SBAUTOINCREMENT_OFFSET 16
|
#define DMI_SBCS_SBAUTOINCREMENT_OFFSET 16
|
||||||
#define DMI_SBCS_SBAUTOINCREMENT_LENGTH 1
|
#define DMI_SBCS_SBAUTOINCREMENT_LENGTH 1
|
||||||
#define DMI_SBCS_SBAUTOINCREMENT (0x1U << DMI_SBCS_SBAUTOINCREMENT_OFFSET)
|
#define DMI_SBCS_SBAUTOINCREMENT (0x1U << DMI_SBCS_SBAUTOINCREMENT_OFFSET)
|
||||||
/*
|
/*
|
||||||
* When 1, every read from \Rsbdatazero automatically triggers a system
|
* When 1, every read from \Rsbdatazero automatically triggers a
|
||||||
* bus read at the new address.
|
* system bus read at the (possibly auto-incremented) address.
|
||||||
*/
|
*/
|
||||||
#define DMI_SBCS_SBAUTOREAD_OFFSET 15
|
#define DMI_SBCS_SBAUTOREAD_OFFSET 15
|
||||||
#define DMI_SBCS_SBAUTOREAD_LENGTH 1
|
#define DMI_SBCS_SBAUTOREAD_LENGTH 1
|
||||||
|
@ -1052,8 +1074,7 @@
|
||||||
*
|
*
|
||||||
* 4: The system bus master was busy when one of the
|
* 4: The system bus master was busy when one of the
|
||||||
* {\tt sbaddress} or {\tt sbdata} registers was written,
|
* {\tt sbaddress} or {\tt sbdata} registers was written,
|
||||||
* or the {\tt sbdata} register was read when it had
|
* or \Rsbdatazero was read when it had stale data.
|
||||||
* stale data.
|
|
||||||
*/
|
*/
|
||||||
#define DMI_SBCS_SBERROR_OFFSET 12
|
#define DMI_SBCS_SBERROR_OFFSET 12
|
||||||
#define DMI_SBCS_SBERROR_LENGTH 3
|
#define DMI_SBCS_SBERROR_LENGTH 3
|
||||||
|
@ -1097,54 +1118,54 @@
|
||||||
#define DMI_SBCS_SBACCESS8 (0x1U << DMI_SBCS_SBACCESS8_OFFSET)
|
#define DMI_SBCS_SBACCESS8 (0x1U << DMI_SBCS_SBACCESS8_OFFSET)
|
||||||
#define DMI_SBADDRESS0 0x39
|
#define DMI_SBADDRESS0 0x39
|
||||||
/*
|
/*
|
||||||
* Accesses bits 31:0 of the internal address.
|
* Accesses bits 31:0 of the physical address in {\tt sbaddress}.
|
||||||
*/
|
*/
|
||||||
#define DMI_SBADDRESS0_ADDRESS_OFFSET 0
|
#define DMI_SBADDRESS0_ADDRESS_OFFSET 0
|
||||||
#define DMI_SBADDRESS0_ADDRESS_LENGTH 32
|
#define DMI_SBADDRESS0_ADDRESS_LENGTH 32
|
||||||
#define DMI_SBADDRESS0_ADDRESS (0xffffffffU << DMI_SBADDRESS0_ADDRESS_OFFSET)
|
#define DMI_SBADDRESS0_ADDRESS (0xffffffffU << DMI_SBADDRESS0_ADDRESS_OFFSET)
|
||||||
#define DMI_SBADDRESS1 0x3a
|
#define DMI_SBADDRESS1 0x3a
|
||||||
/*
|
/*
|
||||||
* Accesses bits 63:32 of the internal address (if the system address
|
* Accesses bits 63:32 of the physical address in {\tt sbaddress} (if
|
||||||
* bus is that wide).
|
* the system address bus is that wide).
|
||||||
*/
|
*/
|
||||||
#define DMI_SBADDRESS1_ADDRESS_OFFSET 0
|
#define DMI_SBADDRESS1_ADDRESS_OFFSET 0
|
||||||
#define DMI_SBADDRESS1_ADDRESS_LENGTH 32
|
#define DMI_SBADDRESS1_ADDRESS_LENGTH 32
|
||||||
#define DMI_SBADDRESS1_ADDRESS (0xffffffffU << DMI_SBADDRESS1_ADDRESS_OFFSET)
|
#define DMI_SBADDRESS1_ADDRESS (0xffffffffU << DMI_SBADDRESS1_ADDRESS_OFFSET)
|
||||||
#define DMI_SBADDRESS2 0x3b
|
#define DMI_SBADDRESS2 0x3b
|
||||||
/*
|
/*
|
||||||
* Accesses bits 95:64 of the internal address (if the system address
|
* Accesses bits 95:64 of the physical address in {\tt sbaddress} (if
|
||||||
* bus is that wide).
|
* the system address bus is that wide).
|
||||||
*/
|
*/
|
||||||
#define DMI_SBADDRESS2_ADDRESS_OFFSET 0
|
#define DMI_SBADDRESS2_ADDRESS_OFFSET 0
|
||||||
#define DMI_SBADDRESS2_ADDRESS_LENGTH 32
|
#define DMI_SBADDRESS2_ADDRESS_LENGTH 32
|
||||||
#define DMI_SBADDRESS2_ADDRESS (0xffffffffU << DMI_SBADDRESS2_ADDRESS_OFFSET)
|
#define DMI_SBADDRESS2_ADDRESS (0xffffffffU << DMI_SBADDRESS2_ADDRESS_OFFSET)
|
||||||
#define DMI_SBDATA0 0x3c
|
#define DMI_SBDATA0 0x3c
|
||||||
/*
|
/*
|
||||||
* Accesses bits 31:0 of the internal data.
|
* Accesses bits 31:0 of {\tt sbdata}.
|
||||||
*/
|
*/
|
||||||
#define DMI_SBDATA0_DATA_OFFSET 0
|
#define DMI_SBDATA0_DATA_OFFSET 0
|
||||||
#define DMI_SBDATA0_DATA_LENGTH 32
|
#define DMI_SBDATA0_DATA_LENGTH 32
|
||||||
#define DMI_SBDATA0_DATA (0xffffffffU << DMI_SBDATA0_DATA_OFFSET)
|
#define DMI_SBDATA0_DATA (0xffffffffU << DMI_SBDATA0_DATA_OFFSET)
|
||||||
#define DMI_SBDATA1 0x3d
|
#define DMI_SBDATA1 0x3d
|
||||||
/*
|
/*
|
||||||
* Accesses bits 63:32 of the internal data (if the system bus is
|
* Accesses bits 63:32 of {\tt sbdata} (if the system bus is that
|
||||||
* that wide).
|
* wide).
|
||||||
*/
|
*/
|
||||||
#define DMI_SBDATA1_DATA_OFFSET 0
|
#define DMI_SBDATA1_DATA_OFFSET 0
|
||||||
#define DMI_SBDATA1_DATA_LENGTH 32
|
#define DMI_SBDATA1_DATA_LENGTH 32
|
||||||
#define DMI_SBDATA1_DATA (0xffffffffU << DMI_SBDATA1_DATA_OFFSET)
|
#define DMI_SBDATA1_DATA (0xffffffffU << DMI_SBDATA1_DATA_OFFSET)
|
||||||
#define DMI_SBDATA2 0x3e
|
#define DMI_SBDATA2 0x3e
|
||||||
/*
|
/*
|
||||||
* Accesses bits 95:64 of the internal data (if the system bus is
|
* Accesses bits 95:64 of {\tt sbdata} (if the system bus is that
|
||||||
* that wide).
|
* wide).
|
||||||
*/
|
*/
|
||||||
#define DMI_SBDATA2_DATA_OFFSET 0
|
#define DMI_SBDATA2_DATA_OFFSET 0
|
||||||
#define DMI_SBDATA2_DATA_LENGTH 32
|
#define DMI_SBDATA2_DATA_LENGTH 32
|
||||||
#define DMI_SBDATA2_DATA (0xffffffffU << DMI_SBDATA2_DATA_OFFSET)
|
#define DMI_SBDATA2_DATA (0xffffffffU << DMI_SBDATA2_DATA_OFFSET)
|
||||||
#define DMI_SBDATA3 0x3f
|
#define DMI_SBDATA3 0x3f
|
||||||
/*
|
/*
|
||||||
* Accesses bits 127:96 of the internal data (if the system bus is
|
* Accesses bits 127:96 of {\tt sbdata} (if the system bus is that
|
||||||
* that wide).
|
* wide).
|
||||||
*/
|
*/
|
||||||
#define DMI_SBDATA3_DATA_OFFSET 0
|
#define DMI_SBDATA3_DATA_OFFSET 0
|
||||||
#define DMI_SBDATA3_DATA_LENGTH 32
|
#define DMI_SBDATA3_DATA_LENGTH 32
|
||||||
|
@ -1188,6 +1209,9 @@
|
||||||
* 0: Don't do the operation specified by \Fwrite.
|
* 0: Don't do the operation specified by \Fwrite.
|
||||||
*
|
*
|
||||||
* 1: Do the operation specified by \Fwrite.
|
* 1: Do the operation specified by \Fwrite.
|
||||||
|
*
|
||||||
|
* This bit can be used to just execute the Program Buffer without
|
||||||
|
* having to worry about placing valid values into \Fsize or \Fregno.
|
||||||
*/
|
*/
|
||||||
#define AC_ACCESS_REGISTER_TRANSFER_OFFSET 17
|
#define AC_ACCESS_REGISTER_TRANSFER_OFFSET 17
|
||||||
#define AC_ACCESS_REGISTER_TRANSFER_LENGTH 1
|
#define AC_ACCESS_REGISTER_TRANSFER_LENGTH 1
|
||||||
|
@ -1223,8 +1247,9 @@
|
||||||
/*
|
/*
|
||||||
* Contains the privilege level the hart was operating in when Debug
|
* Contains the privilege level the hart was operating in when Debug
|
||||||
* Mode was entered. The encoding is described in Table
|
* Mode was entered. The encoding is described in Table
|
||||||
* \ref{tab:privlevel}. A user can write this value to change the
|
* \ref{tab:privlevel}, and matches the privilege level encoding from
|
||||||
* hart's privilege level when exiting Debug Mode.
|
* the RISC-V Privileged ISA Specification. A user can write this
|
||||||
|
* value to change the hart's privilege level when exiting Debug Mode.
|
||||||
*/
|
*/
|
||||||
#define VIRT_PRIV_PRV_OFFSET 0
|
#define VIRT_PRIV_PRV_OFFSET 0
|
||||||
#define VIRT_PRIV_PRV_LENGTH 2
|
#define VIRT_PRIV_PRV_LENGTH 2
|
||||||
|
|
|
@ -11,44 +11,39 @@
|
||||||
#include "asm.h"
|
#include "asm.h"
|
||||||
#include "encoding.h"
|
#include "encoding.h"
|
||||||
|
|
||||||
riscv_addr_t riscv_program_gal(struct riscv_program *p, riscv_addr_t addr);
|
|
||||||
int riscv_program_lah(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr);
|
|
||||||
int riscv_program_lal(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr);
|
|
||||||
|
|
||||||
/* Program interface. */
|
/* Program interface. */
|
||||||
int riscv_program_init(struct riscv_program *p, struct target *target)
|
int riscv_program_init(struct riscv_program *p, struct target *target)
|
||||||
{
|
{
|
||||||
memset(p, 0, sizeof(*p));
|
memset(p, 0, sizeof(*p));
|
||||||
p->target = target;
|
p->target = target;
|
||||||
p->instruction_count = 0;
|
p->instruction_count = 0;
|
||||||
p->data_count = 0;
|
|
||||||
p->writes_memory = 0;
|
|
||||||
p->target_xlen = riscv_xlen(target);
|
p->target_xlen = riscv_xlen(target);
|
||||||
for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) {
|
for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) {
|
||||||
p->writes_xreg[i] = 0;
|
p->writes_xreg[i] = 0;
|
||||||
p->in_use[i] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i)
|
for(size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i)
|
||||||
p->debug_buffer[i] = -1;
|
p->debug_buffer[i] = -1;
|
||||||
|
|
||||||
if (riscv_debug_buffer_enter(target, p) != ERROR_OK) {
|
|
||||||
LOG_ERROR("unable to write progam buffer enter code");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int riscv_program_write(struct riscv_program *program)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < program->instruction_count; ++i) {
|
||||||
|
LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", program, i, program->debug_buffer[i]);
|
||||||
|
if (riscv_write_debug_buffer(program->target, i,
|
||||||
|
program->debug_buffer[i]) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add ebreak and execute the program. */
|
||||||
int riscv_program_exec(struct riscv_program *p, struct target *t)
|
int riscv_program_exec(struct riscv_program *p, struct target *t)
|
||||||
{
|
{
|
||||||
keep_alive();
|
keep_alive();
|
||||||
|
|
||||||
if (riscv_debug_buffer_leave(t, p) != ERROR_OK) {
|
|
||||||
LOG_ERROR("unable to write program buffer exit code");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1];
|
riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1];
|
||||||
for (size_t i = GDB_REGNO_XPR0 + 1; i <= GDB_REGNO_XPR31; ++i) {
|
for (size_t i = GDB_REGNO_XPR0 + 1; i <= GDB_REGNO_XPR31; ++i) {
|
||||||
if (p->writes_xreg[i]) {
|
if (p->writes_xreg[i]) {
|
||||||
|
@ -57,14 +52,6 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->writes_memory && (riscv_program_fence(p) != ERROR_OK)) {
|
|
||||||
LOG_ERROR("Unable to write fence");
|
|
||||||
for(size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
|
|
||||||
LOG_ERROR("ram[%02x]: DASM(0x%08lx) [0x%08lx]", (int)i, (long)p->debug_buffer[i], (long)p->debug_buffer[i]);
|
|
||||||
abort();
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (riscv_program_ebreak(p) != ERROR_OK) {
|
if (riscv_program_ebreak(p) != ERROR_OK) {
|
||||||
LOG_ERROR("Unable to write ebreak");
|
LOG_ERROR("Unable to write ebreak");
|
||||||
for(size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
|
for(size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
|
||||||
|
@ -73,16 +60,8 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < riscv_debug_buffer_size(p->target); ++i) {
|
if (riscv_program_write(p) != ERROR_OK)
|
||||||
if (i < p->instruction_count) {
|
return ERROR_FAIL;
|
||||||
LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", p, i, p->debug_buffer[i]);
|
|
||||||
riscv_write_debug_buffer(t, i, p->debug_buffer[i]);
|
|
||||||
}
|
|
||||||
if (i >= riscv_debug_buffer_size(p->target) - p->data_count) {
|
|
||||||
LOG_DEBUG("%p: debug_buffer[%02x] = 0x%08x", p, i, p->debug_buffer[i]);
|
|
||||||
riscv_write_debug_buffer(t, i, p->debug_buffer[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (riscv_execute_debug_buffer(t) != ERROR_OK) {
|
if (riscv_execute_debug_buffer(t) != ERROR_OK) {
|
||||||
LOG_ERROR("Unable to execute program %p", p);
|
LOG_ERROR("Unable to execute program %p", p);
|
||||||
|
@ -90,7 +69,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
|
for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
|
||||||
if (i >= riscv_debug_buffer_size(p->target) - p->data_count)
|
if (i >= riscv_debug_buffer_size(p->target))
|
||||||
p->debug_buffer[i] = riscv_read_debug_buffer(t, i);
|
p->debug_buffer[i] = riscv_read_debug_buffer(t, i);
|
||||||
|
|
||||||
for (size_t i = GDB_REGNO_XPR0; i <= GDB_REGNO_XPR31; ++i)
|
for (size_t i = GDB_REGNO_XPR0; i <= GDB_REGNO_XPR31; ++i)
|
||||||
|
@ -100,236 +79,39 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv_addr_t riscv_program_alloc_data(struct riscv_program *p, size_t bytes)
|
|
||||||
{
|
|
||||||
riscv_addr_t addr =
|
|
||||||
riscv_debug_buffer_addr(p->target)
|
|
||||||
+ riscv_debug_buffer_size(p->target) * sizeof(p->debug_buffer[0])
|
|
||||||
- p->data_count * sizeof(p->debug_buffer[0])
|
|
||||||
- bytes;
|
|
||||||
while (addr % bytes != 0) addr--;
|
|
||||||
|
|
||||||
riscv_addr_t ptop =
|
|
||||||
riscv_debug_buffer_addr(p->target)
|
|
||||||
+ p->instruction_count * sizeof(p->debug_buffer[0]);
|
|
||||||
|
|
||||||
if (addr <= ptop) {
|
|
||||||
LOG_ERROR("unable to allocate %d bytes", (int)bytes);
|
|
||||||
return RISCV_PROGRAM_ALLOC_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
p->data_count =
|
|
||||||
+ riscv_debug_buffer_size(p->target)
|
|
||||||
- (addr - riscv_debug_buffer_addr(p->target)) / sizeof(p->debug_buffer[0]);
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_addr_t riscv_program_alloc_x(struct riscv_program *p)
|
|
||||||
{
|
|
||||||
return riscv_program_alloc_data(p, p->target_xlen / 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_addr_t riscv_program_alloc_d(struct riscv_program *p)
|
|
||||||
{
|
|
||||||
return riscv_program_alloc_data(p, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_addr_t riscv_program_alloc_w(struct riscv_program *p)
|
|
||||||
{
|
|
||||||
return riscv_program_alloc_data(p, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_addr_t riscv_program_alloc_h(struct riscv_program *p)
|
|
||||||
{
|
|
||||||
return riscv_program_alloc_data(p, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_addr_t riscv_program_alloc_b(struct riscv_program *p)
|
|
||||||
{
|
|
||||||
return riscv_program_alloc_data(p, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_insn_t riscv_program_read_ram(struct riscv_program *p, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
if (addr < riscv_debug_buffer_addr(p->target))
|
|
||||||
return -1;
|
|
||||||
if ((size_t)addr > riscv_debug_buffer_addr(p->target) + (riscv_debug_buffer_size(p->target) * sizeof(p->debug_buffer[0])))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int off = (addr - riscv_debug_buffer_addr(p->target)) / sizeof(p->debug_buffer[0]);
|
|
||||||
return p->debug_buffer[off];
|
|
||||||
}
|
|
||||||
|
|
||||||
void riscv_program_write_ram(struct riscv_program *p, riscv_addr_t addr, uint64_t d)
|
|
||||||
{
|
|
||||||
if (addr < riscv_debug_buffer_addr(p->target))
|
|
||||||
return;
|
|
||||||
if ((size_t)addr > riscv_debug_buffer_addr(p->target) + (riscv_debug_buffer_size(p->target) * sizeof(p->debug_buffer[0])))
|
|
||||||
return;
|
|
||||||
|
|
||||||
int off = (addr - riscv_debug_buffer_addr(p->target)) / sizeof(p->debug_buffer[0]);
|
|
||||||
p->debug_buffer[off] = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
||||||
{
|
{
|
||||||
p->writes_memory = 1;
|
|
||||||
return riscv_program_insert(p, sw(d, b, offset));
|
return riscv_program_insert(p, sw(d, b, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_program_shr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
int riscv_program_shr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
||||||
{
|
{
|
||||||
p->writes_memory = 1;
|
|
||||||
return riscv_program_insert(p, sh(d, b, offset));
|
return riscv_program_insert(p, sh(d, b, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_program_sbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
int riscv_program_sbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
||||||
{
|
{
|
||||||
p->writes_memory = 1;
|
|
||||||
return riscv_program_insert(p, sb(d, b, offset));
|
return riscv_program_insert(p, sb(d, b, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
||||||
{
|
{
|
||||||
p->writes_memory = 1;
|
|
||||||
return riscv_program_insert(p, lw(d, b, offset));
|
return riscv_program_insert(p, lw(d, b, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
||||||
{
|
{
|
||||||
p->writes_memory = 1;
|
|
||||||
return riscv_program_insert(p, lh(d, b, offset));
|
return riscv_program_insert(p, lh(d, b, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
||||||
{
|
{
|
||||||
p->writes_memory = 1;
|
|
||||||
return riscv_program_insert(p, lb(d, b, offset));
|
return riscv_program_insert(p, lb(d, b, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_program_lx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
switch (p->target_xlen) {
|
|
||||||
case 64: return riscv_program_ld(p, d, addr);
|
|
||||||
case 32: return riscv_program_lw(p, d, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR("unknown xlen %d", p->target_xlen);
|
|
||||||
abort();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_ld(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d;
|
|
||||||
if (riscv_program_lah(p, d, addr) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (riscv_program_insert(p, ld(d, t, riscv_program_gal(p, addr))) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_lw(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d;
|
|
||||||
if (riscv_program_lah(p, d, addr) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (riscv_program_insert(p, lw(d, t, riscv_program_gal(p, addr))) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_lh(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d;
|
|
||||||
if (riscv_program_lah(p, d, addr) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (riscv_program_insert(p, lh(d, t, riscv_program_gal(p, addr))) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_lb(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d;
|
|
||||||
if (riscv_program_lah(p, t, addr) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (riscv_program_insert(p, lb(d, t, riscv_program_gal(p, addr))) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_sx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
switch (p->target_xlen) {
|
|
||||||
case 64: return riscv_program_sd(p, d, addr);
|
|
||||||
case 32: return riscv_program_sw(p, d, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR("unknown xlen %d", p->target_xlen);
|
|
||||||
abort();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_sd(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
enum gdb_regno t = riscv_program_gah(p, addr) == 0
|
|
||||||
? GDB_REGNO_X0
|
|
||||||
: riscv_program_gettemp(p);
|
|
||||||
if (riscv_program_lah(p, t, addr) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (riscv_program_insert(p, sd(d, t, riscv_program_gal(p, addr))) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
riscv_program_puttemp(p, t);
|
|
||||||
p->writes_memory = true;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_sw(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
enum gdb_regno t = riscv_program_gah(p, addr) == 0
|
|
||||||
? GDB_REGNO_X0
|
|
||||||
: riscv_program_gettemp(p);
|
|
||||||
if (riscv_program_lah(p, t, addr) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (riscv_program_insert(p, sw(d, t, riscv_program_gal(p, addr))) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
riscv_program_puttemp(p, t);
|
|
||||||
p->writes_memory = true;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_sh(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
enum gdb_regno t = riscv_program_gah(p, addr) == 0
|
|
||||||
? GDB_REGNO_X0
|
|
||||||
: riscv_program_gettemp(p);
|
|
||||||
if (riscv_program_lah(p, t, addr) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (riscv_program_insert(p, sh(d, t, riscv_program_gal(p, addr))) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
riscv_program_puttemp(p, t);
|
|
||||||
p->writes_memory = true;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_sb(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
enum gdb_regno t = riscv_program_gah(p, addr) == 0
|
|
||||||
? GDB_REGNO_X0
|
|
||||||
: riscv_program_gettemp(p);
|
|
||||||
if (riscv_program_lah(p, t, addr) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (riscv_program_insert(p, sb(d, t, riscv_program_gal(p, addr))) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
riscv_program_puttemp(p, t);
|
|
||||||
p->writes_memory = true;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr)
|
int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr)
|
||||||
{
|
{
|
||||||
assert(csr >= GDB_REGNO_CSR0);
|
assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095);
|
||||||
return riscv_program_insert(p, csrrs(d, GDB_REGNO_X0, csr - GDB_REGNO_CSR0));
|
return riscv_program_insert(p, csrrs(d, GDB_REGNO_X0, csr - GDB_REGNO_CSR0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,12 +121,6 @@ int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno
|
||||||
return riscv_program_insert(p, csrrw(GDB_REGNO_X0, s, csr - GDB_REGNO_CSR0));
|
return riscv_program_insert(p, csrrw(GDB_REGNO_X0, s, csr - GDB_REGNO_CSR0));
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_program_csrrw(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, enum gdb_regno csr)
|
|
||||||
{
|
|
||||||
assert(csr >= GDB_REGNO_CSR0);
|
|
||||||
return riscv_program_insert(p, csrrw(d, s, csr - GDB_REGNO_CSR0));
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_fence_i(struct riscv_program *p)
|
int riscv_program_fence_i(struct riscv_program *p)
|
||||||
{
|
{
|
||||||
return riscv_program_insert(p, fence_i());
|
return riscv_program_insert(p, fence_i());
|
||||||
|
@ -357,158 +133,27 @@ int riscv_program_fence(struct riscv_program *p)
|
||||||
|
|
||||||
int riscv_program_ebreak(struct riscv_program *p)
|
int riscv_program_ebreak(struct riscv_program *p)
|
||||||
{
|
{
|
||||||
|
struct target *target = p->target;
|
||||||
|
RISCV_INFO(r);
|
||||||
|
if (p->instruction_count == riscv_debug_buffer_size(p->target) &&
|
||||||
|
r->impebreak) {
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
return riscv_program_insert(p, ebreak());
|
return riscv_program_insert(p, ebreak());
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_program_lui(struct riscv_program *p, enum gdb_regno d, int32_t u)
|
|
||||||
{
|
|
||||||
return riscv_program_insert(p, lui(d, u));
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t u)
|
int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t u)
|
||||||
{
|
{
|
||||||
return riscv_program_insert(p, addi(d, s, u));
|
return riscv_program_insert(p, addi(d, s, u));
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_program_fsx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
assert(d >= GDB_REGNO_FPR0);
|
|
||||||
assert(d <= GDB_REGNO_FPR31);
|
|
||||||
enum gdb_regno t = riscv_program_gah(p, addr) == 0
|
|
||||||
? GDB_REGNO_X0
|
|
||||||
: riscv_program_gettemp(p);
|
|
||||||
if (riscv_program_lah(p, t, addr) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
uint32_t instruction;
|
|
||||||
switch (p->target->reg_cache->reg_list[GDB_REGNO_FPR0].size) {
|
|
||||||
case 64:
|
|
||||||
instruction = fsd(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr));
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
instruction = fsw(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
if (riscv_program_insert(p, instruction) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
riscv_program_puttemp(p, t);
|
|
||||||
p->writes_memory = true;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_flx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
assert(d >= GDB_REGNO_FPR0);
|
|
||||||
assert(d <= GDB_REGNO_FPR31);
|
|
||||||
enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d;
|
|
||||||
if (riscv_program_lah(p, t, addr) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
uint32_t instruction;
|
|
||||||
switch (p->target->reg_cache->reg_list[GDB_REGNO_FPR0].size) {
|
|
||||||
case 64:
|
|
||||||
instruction = fld(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr));
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
instruction = flw(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
if (riscv_program_insert(p, instruction) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c)
|
|
||||||
{
|
|
||||||
if (riscv_program_lui(p, d, c >> 12) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (riscv_program_addi(p, d, d, c & 0xFFF) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_dont_restore_register(struct riscv_program *p, enum gdb_regno r)
|
|
||||||
{
|
|
||||||
assert(r < RISCV_REGISTER_COUNT);
|
|
||||||
p->writes_xreg[r] = 0;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_do_restore_register(struct riscv_program *p, enum gdb_regno r)
|
|
||||||
{
|
|
||||||
assert(r < RISCV_REGISTER_COUNT);
|
|
||||||
p->writes_xreg[r] = 1;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void riscv_program_reserve_register(struct riscv_program *p, enum gdb_regno r)
|
|
||||||
{
|
|
||||||
assert(r < RISCV_REGISTER_COUNT);
|
|
||||||
assert(p->in_use[r] == 0);
|
|
||||||
p->in_use[r] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum gdb_regno riscv_program_gettemp(struct riscv_program *p)
|
|
||||||
{
|
|
||||||
for (size_t i = GDB_REGNO_S0; i <= GDB_REGNO_XPR31; ++i) {
|
|
||||||
if (p->in_use[i]) continue;
|
|
||||||
|
|
||||||
riscv_program_do_restore_register(p, i);
|
|
||||||
p->in_use[i] = 1;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR("You've run out of temporary registers. This is impossible.");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void riscv_program_puttemp(struct riscv_program *p, enum gdb_regno r)
|
|
||||||
{
|
|
||||||
assert(r < RISCV_REGISTER_COUNT);
|
|
||||||
p->in_use[r] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Helper functions. */
|
|
||||||
riscv_addr_t riscv_program_gah(struct riscv_program *p, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
return addr >> 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_addr_t riscv_program_gal(struct riscv_program *p, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
if (addr > 0) {
|
|
||||||
return (addr & 0x7FF);
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_lah(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
riscv_addr_t ah = riscv_program_gah(p, addr);
|
|
||||||
if (ah == 0)
|
|
||||||
return ERROR_OK;
|
|
||||||
return riscv_program_lui(p, d, ah);
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_lal(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr)
|
|
||||||
{
|
|
||||||
riscv_addr_t al = riscv_program_gal(p, addr);
|
|
||||||
if (al == 0)
|
|
||||||
return ERROR_OK;
|
|
||||||
return riscv_program_addi(p, d, d, al);
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_program_insert(struct riscv_program *p, riscv_insn_t i)
|
int riscv_program_insert(struct riscv_program *p, riscv_insn_t i)
|
||||||
{
|
{
|
||||||
if (p->instruction_count + p->data_count + 1 > riscv_debug_buffer_size(p->target)) {
|
if (p->instruction_count >= riscv_debug_buffer_size(p->target)) {
|
||||||
LOG_ERROR("Unable to insert instruction:");
|
LOG_ERROR("Unable to insert instruction:");
|
||||||
LOG_ERROR(" instruction_count=%d", (int)p->instruction_count);
|
LOG_ERROR(" instruction_count=%d", (int)p->instruction_count);
|
||||||
LOG_ERROR(" data_count =%d", (int)p->data_count);
|
|
||||||
LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target));
|
LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target));
|
||||||
return ERROR_FAIL;
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
p->debug_buffer[p->instruction_count] = i;
|
p->debug_buffer[p->instruction_count] = i;
|
||||||
|
|
|
@ -15,23 +15,12 @@ struct riscv_program {
|
||||||
|
|
||||||
uint32_t debug_buffer[RISCV_MAX_DEBUG_BUFFER_SIZE];
|
uint32_t debug_buffer[RISCV_MAX_DEBUG_BUFFER_SIZE];
|
||||||
|
|
||||||
/* The debug buffer is allocated in two directions: instructions go at
|
/* Number of 32-bit instructions in the program. */
|
||||||
* the start, while data goes at the end. When they meet in the middle
|
|
||||||
* this blows up. */
|
|
||||||
size_t instruction_count;
|
size_t instruction_count;
|
||||||
size_t data_count;
|
|
||||||
|
|
||||||
/* Side effects of executing this program. These must be accounted for
|
/* Side effects of executing this program. These must be accounted for
|
||||||
* in order to maintain correct executing of the target system. */
|
* in order to maintain correct executing of the target system. */
|
||||||
bool writes_xreg[RISCV_REGISTER_COUNT];
|
bool writes_xreg[RISCV_REGISTER_COUNT];
|
||||||
bool writes_memory;
|
|
||||||
|
|
||||||
/* When a register is used it will be set in this array. */
|
|
||||||
bool in_use[RISCV_REGISTER_COUNT];
|
|
||||||
|
|
||||||
/* Remembers the registers that have been saved into dscratch
|
|
||||||
* registers. These are restored */
|
|
||||||
enum gdb_regno dscratch_saved[RISCV_DSCRATCH_COUNT];
|
|
||||||
|
|
||||||
/* XLEN on the target. */
|
/* XLEN on the target. */
|
||||||
int target_xlen;
|
int target_xlen;
|
||||||
|
@ -40,6 +29,9 @@ struct riscv_program {
|
||||||
/* Initializes a program with the header. */
|
/* Initializes a program with the header. */
|
||||||
int riscv_program_init(struct riscv_program *p, struct target *t);
|
int riscv_program_init(struct riscv_program *p, struct target *t);
|
||||||
|
|
||||||
|
/* Write the program to the program buffer. */
|
||||||
|
int riscv_program_write(struct riscv_program *program);
|
||||||
|
|
||||||
/* Executes a program, returning 0 if the program successfully executed. Note
|
/* Executes a program, returning 0 if the program successfully executed. Note
|
||||||
* that this may cause registers to be saved or restored, which could result to
|
* that this may cause registers to be saved or restored, which could result to
|
||||||
* calls to things like riscv_save_register which itself could require a
|
* calls to things like riscv_save_register which itself could require a
|
||||||
|
@ -60,83 +52,24 @@ int riscv_program_insert(struct riscv_program *p, riscv_insn_t i);
|
||||||
* memory. */
|
* memory. */
|
||||||
int riscv_program_save_to_dscratch(struct riscv_program *p, enum gdb_regno to_save);
|
int riscv_program_save_to_dscratch(struct riscv_program *p, enum gdb_regno to_save);
|
||||||
|
|
||||||
/* Allocates data of various sizes. Either returns the absolute physical
|
|
||||||
* address or RISCV_PROGRAM_ALLOC_FAIL on failure. */
|
|
||||||
riscv_addr_t riscv_program_alloc_data(struct riscv_program *p, size_t bytes);
|
|
||||||
riscv_addr_t riscv_program_alloc_x(struct riscv_program *p);
|
|
||||||
riscv_addr_t riscv_program_alloc_d(struct riscv_program *p);
|
|
||||||
riscv_addr_t riscv_program_alloc_w(struct riscv_program *p);
|
|
||||||
riscv_addr_t riscv_program_alloc_h(struct riscv_program *p);
|
|
||||||
riscv_addr_t riscv_program_alloc_b(struct riscv_program *p);
|
|
||||||
#define RISCV_PROGRAM_ALLOC_FAIL ((riscv_addr_t)(-1))
|
|
||||||
|
|
||||||
/* Reads a word of memory from this program's internal view of the debug RAM.
|
|
||||||
* This is what you want to use to get data back from the program after it
|
|
||||||
* executes. */
|
|
||||||
riscv_insn_t riscv_program_read_ram(struct riscv_program *p, riscv_addr_t addr);
|
|
||||||
void riscv_program_write_ram(struct riscv_program *p, riscv_addr_t a, uint64_t d);
|
|
||||||
|
|
||||||
/* Helpers to assembly various instructions. Return 0 on success. These might
|
/* Helpers to assembly various instructions. Return 0 on success. These might
|
||||||
* assembly into a multi-instruction sequence that overwrites some other
|
* assembly into a multi-instruction sequence that overwrites some other
|
||||||
* register, but those will be properly saved and restored. */
|
* register, but those will be properly saved and restored. */
|
||||||
int riscv_program_lx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr);
|
|
||||||
int riscv_program_ld(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr);
|
|
||||||
int riscv_program_lw(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr);
|
|
||||||
int riscv_program_lh(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr);
|
|
||||||
int riscv_program_lb(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr);
|
|
||||||
|
|
||||||
int riscv_program_sx(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr);
|
|
||||||
int riscv_program_sd(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr);
|
|
||||||
int riscv_program_sw(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr);
|
|
||||||
int riscv_program_sh(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr);
|
|
||||||
int riscv_program_sb(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr);
|
|
||||||
|
|
||||||
int riscv_program_lxr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
|
||||||
int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
|
||||||
int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
||||||
int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
||||||
int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
||||||
|
|
||||||
int riscv_program_sxr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
|
||||||
int riscv_program_sdr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
|
||||||
int riscv_program_swr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
int riscv_program_swr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
||||||
int riscv_program_shr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
int riscv_program_shr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
||||||
int riscv_program_sbr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
int riscv_program_sbr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
||||||
|
|
||||||
int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr);
|
int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr);
|
||||||
int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr);
|
int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr);
|
||||||
int riscv_program_csrrw(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, enum gdb_regno csr);
|
|
||||||
|
|
||||||
int riscv_program_fence_i(struct riscv_program *p);
|
int riscv_program_fence_i(struct riscv_program *p);
|
||||||
int riscv_program_fence(struct riscv_program *p);
|
int riscv_program_fence(struct riscv_program *p);
|
||||||
int riscv_program_ebreak(struct riscv_program *p);
|
int riscv_program_ebreak(struct riscv_program *p);
|
||||||
|
|
||||||
int riscv_program_lui(struct riscv_program *p, enum gdb_regno d, int32_t u);
|
|
||||||
int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i);
|
int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i);
|
||||||
|
|
||||||
int riscv_program_fsx(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr);
|
|
||||||
int riscv_program_flx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr);
|
|
||||||
|
|
||||||
/* Assembler macros. */
|
|
||||||
int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c);
|
|
||||||
int riscv_program_la(struct riscv_program *p, enum gdb_regno d, riscv_addr_t a);
|
|
||||||
|
|
||||||
/* Register allocation. The user is expected to have obtained temporary
|
|
||||||
* registers using these fuctions. Additionally, there is an interface for
|
|
||||||
* reserving registers -- it's expected that this has been called as the first
|
|
||||||
* thing in the program's execution to reserve registers that can't be touched
|
|
||||||
* by the program's execution. */
|
|
||||||
void riscv_program_reserve_register(struct riscv_program *p, enum gdb_regno r);
|
|
||||||
enum gdb_regno riscv_program_gettemp(struct riscv_program *p);
|
|
||||||
void riscv_program_puttemp(struct riscv_program *p, enum gdb_regno r);
|
|
||||||
|
|
||||||
/* Executing a program usually causes the registers that get overwritten to be
|
|
||||||
* saved and restored. Calling this prevents the given register from actually
|
|
||||||
* being restored as a result of all activity in this program. */
|
|
||||||
int riscv_program_dont_restore_register(struct riscv_program *p, enum gdb_regno r);
|
|
||||||
int riscv_program_do_restore_register(struct riscv_program *p, enum gdb_regno r);
|
|
||||||
|
|
||||||
/* Addressing functions. */
|
|
||||||
riscv_addr_t riscv_program_gah(struct riscv_program *p, riscv_addr_t addr);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -200,6 +200,9 @@ int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC;
|
||||||
/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
|
/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
|
||||||
int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC;
|
int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC;
|
||||||
|
|
||||||
|
bool riscv_use_scratch_ram = false;
|
||||||
|
uint64_t riscv_scratch_ram_address = 0;
|
||||||
|
|
||||||
static uint32_t dtmcontrol_scan(struct target *target, uint32_t out)
|
static uint32_t dtmcontrol_scan(struct target *target, uint32_t out)
|
||||||
{
|
{
|
||||||
struct scan_field field;
|
struct scan_field field;
|
||||||
|
@ -1120,8 +1123,8 @@ int riscv_openocd_step(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Command Handlers */
|
/* Command Handlers */
|
||||||
COMMAND_HANDLER(riscv_set_command_timeout_sec) {
|
COMMAND_HANDLER(riscv_set_command_timeout_sec)
|
||||||
|
{
|
||||||
if (CMD_ARGC != 1) {
|
if (CMD_ARGC != 1) {
|
||||||
LOG_ERROR("Command takes exactly 1 parameter");
|
LOG_ERROR("Command takes exactly 1 parameter");
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
@ -1137,11 +1140,11 @@ COMMAND_HANDLER(riscv_set_command_timeout_sec) {
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(riscv_set_reset_timeout_sec) {
|
COMMAND_HANDLER(riscv_set_reset_timeout_sec)
|
||||||
|
{
|
||||||
if (CMD_ARGC != 1) {
|
if (CMD_ARGC != 1) {
|
||||||
LOG_ERROR("Command takes exactly 1 parameter");
|
LOG_ERROR("Command takes exactly 1 parameter");
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
int timeout = atoi(CMD_ARGV[0]);
|
int timeout = atoi(CMD_ARGV[0]);
|
||||||
if (timeout <= 0){
|
if (timeout <= 0){
|
||||||
|
@ -1153,6 +1156,29 @@ COMMAND_HANDLER(riscv_set_reset_timeout_sec) {
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(riscv_set_scratch_ram)
|
||||||
|
{
|
||||||
|
if (CMD_ARGC != 1) {
|
||||||
|
LOG_ERROR("Command takes exactly 1 parameter");
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
}
|
||||||
|
if (!strcmp(CMD_ARGV[0], "none")) {
|
||||||
|
riscv_use_scratch_ram = false;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long unsigned int address;
|
||||||
|
int result = sscanf(CMD_ARGV[0], "%Lx", &address);
|
||||||
|
if (result != (int) strlen(CMD_ARGV[0])) {
|
||||||
|
LOG_ERROR("%s is not a valid address for command.", CMD_ARGV[0]);
|
||||||
|
riscv_use_scratch_ram = false;
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
riscv_scratch_ram_address = address;
|
||||||
|
riscv_use_scratch_ram = true;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct command_registration riscv_exec_command_handlers[] = {
|
static const struct command_registration riscv_exec_command_handlers[] = {
|
||||||
{
|
{
|
||||||
|
@ -1161,14 +1187,21 @@ static const struct command_registration riscv_exec_command_handlers[] = {
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.usage = "riscv set_command_timeout_sec [sec]",
|
.usage = "riscv set_command_timeout_sec [sec]",
|
||||||
.help = "Set the wall-clock timeout (in seconds) for individual commands"
|
.help = "Set the wall-clock timeout (in seconds) for individual commands"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "set_reset_timeout_sec",
|
.name = "set_reset_timeout_sec",
|
||||||
.handler = riscv_set_reset_timeout_sec,
|
.handler = riscv_set_reset_timeout_sec,
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.usage = "riscv set_reset_timeout_sec [sec]",
|
.usage = "riscv set_reset_timeout_sec [sec]",
|
||||||
.help = "Set the wall-clock timeout (in seconds) after reset is deasserted"
|
.help = "Set the wall-clock timeout (in seconds) after reset is deasserted"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "set_scratch_ram",
|
||||||
|
.handler = riscv_set_scratch_ram,
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.usage = "riscv set_scratch_ram none|[address]",
|
||||||
|
.help = "Set address of 16 bytes of scratch RAM the debugger can use, or 'none'."
|
||||||
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1235,7 +1268,6 @@ void riscv_info_init(struct target *target, riscv_info_t *r)
|
||||||
|
|
||||||
for (size_t h = 0; h < RISCV_MAX_HARTS; ++h) {
|
for (size_t h = 0; h < RISCV_MAX_HARTS; ++h) {
|
||||||
r->xlen[h] = -1;
|
r->xlen[h] = -1;
|
||||||
r->debug_buffer_addr[h] = -1;
|
|
||||||
|
|
||||||
for (size_t e = 0; e < RISCV_MAX_REGISTERS; ++e)
|
for (size_t e = 0; e < RISCV_MAX_REGISTERS; ++e)
|
||||||
r->valid_saved_registers[h][e] = false;
|
r->valid_saved_registers[h][e] = false;
|
||||||
|
@ -1483,28 +1515,6 @@ size_t riscv_debug_buffer_size(struct target *target)
|
||||||
return r->debug_buffer_size[riscv_current_hartid(target)];
|
return r->debug_buffer_size[riscv_current_hartid(target)];
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv_addr_t riscv_debug_buffer_addr(struct target *target)
|
|
||||||
{
|
|
||||||
RISCV_INFO(r);
|
|
||||||
riscv_addr_t out = r->debug_buffer_addr[riscv_current_hartid(target)];
|
|
||||||
assert((out & 3) == 0);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program)
|
|
||||||
{
|
|
||||||
RISCV_INFO(r);
|
|
||||||
r->debug_buffer_enter(target, program);
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_debug_buffer_leave(struct target *target, struct riscv_program *program)
|
|
||||||
{
|
|
||||||
RISCV_INFO(r);
|
|
||||||
r->debug_buffer_leave(target, program);
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn)
|
int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
|
|
|
@ -72,15 +72,15 @@ typedef struct {
|
||||||
* target controls, while otherwise only a single hart is controlled. */
|
* target controls, while otherwise only a single hart is controlled. */
|
||||||
int trigger_unique_id[RISCV_MAX_HWBPS];
|
int trigger_unique_id[RISCV_MAX_HWBPS];
|
||||||
|
|
||||||
/* The address of the debug RAM buffer. */
|
|
||||||
riscv_addr_t debug_buffer_addr[RISCV_MAX_HARTS];
|
|
||||||
|
|
||||||
/* The number of entries in the debug buffer. */
|
/* The number of entries in the debug buffer. */
|
||||||
int debug_buffer_size[RISCV_MAX_HARTS];
|
int debug_buffer_size[RISCV_MAX_HARTS];
|
||||||
|
|
||||||
/* This avoids invalidating the register cache too often. */
|
/* This avoids invalidating the register cache too often. */
|
||||||
bool registers_initialized;
|
bool registers_initialized;
|
||||||
|
|
||||||
|
/* This hart contains an implicit ebreak at the end of the program buffer. */
|
||||||
|
bool impebreak;
|
||||||
|
|
||||||
/* Helper functions that target the various RISC-V debug spec
|
/* Helper functions that target the various RISC-V debug spec
|
||||||
* implementations. */
|
* implementations. */
|
||||||
riscv_reg_t (*get_register)(struct target *, int hartid, int regid);
|
riscv_reg_t (*get_register)(struct target *, int hartid, int regid);
|
||||||
|
@ -95,8 +95,6 @@ typedef struct {
|
||||||
void (*on_resume)(struct target *target);
|
void (*on_resume)(struct target *target);
|
||||||
void (*on_step)(struct target *target);
|
void (*on_step)(struct target *target);
|
||||||
enum riscv_halt_reason (*halt_reason)(struct target *target);
|
enum riscv_halt_reason (*halt_reason)(struct target *target);
|
||||||
void (*debug_buffer_enter)(struct target *target, struct riscv_program *program);
|
|
||||||
void (*debug_buffer_leave)(struct target *target, struct riscv_program *program);
|
|
||||||
void (*write_debug_buffer)(struct target *target, unsigned index,
|
void (*write_debug_buffer)(struct target *target, unsigned index,
|
||||||
riscv_insn_t d);
|
riscv_insn_t d);
|
||||||
riscv_insn_t (*read_debug_buffer)(struct target *target, unsigned index);
|
riscv_insn_t (*read_debug_buffer)(struct target *target, unsigned index);
|
||||||
|
@ -113,6 +111,9 @@ extern int riscv_command_timeout_sec;
|
||||||
/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
|
/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
|
||||||
extern int riscv_reset_timeout_sec;
|
extern int riscv_reset_timeout_sec;
|
||||||
|
|
||||||
|
extern bool riscv_use_scratch_ram;
|
||||||
|
extern uint64_t riscv_scratch_ram_address;
|
||||||
|
|
||||||
/* Everything needs the RISC-V specific info structure, so here's a nice macro
|
/* Everything needs the RISC-V specific info structure, so here's a nice macro
|
||||||
* that provides that. */
|
* that provides that. */
|
||||||
static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused));
|
static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused));
|
||||||
|
@ -213,10 +214,6 @@ int riscv_count_triggers_of_hart(struct target *target, int hartid);
|
||||||
/* These helper functions let the generic program interface get target-specific
|
/* These helper functions let the generic program interface get target-specific
|
||||||
* information. */
|
* information. */
|
||||||
size_t riscv_debug_buffer_size(struct target *target);
|
size_t riscv_debug_buffer_size(struct target *target);
|
||||||
riscv_addr_t riscv_debug_buffer_addr(struct target *target);
|
|
||||||
|
|
||||||
int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program);
|
|
||||||
int riscv_debug_buffer_leave(struct target *target, struct riscv_program *program);
|
|
||||||
|
|
||||||
riscv_insn_t riscv_read_debug_buffer(struct target *target, int index);
|
riscv_insn_t riscv_read_debug_buffer(struct target *target, int index);
|
||||||
riscv_addr_t riscv_read_debug_buffer_x(struct target *target, int index);
|
riscv_addr_t riscv_read_debug_buffer_x(struct target *target, int index);
|
||||||
|
|
Loading…
Reference in New Issue