Skip to content
This repository was archived by the owner on Mar 7, 2026. It is now read-only.

Commit 85fa83e

Browse files
perigosorg-silva
authored andcommitted
!experimental! riscv32: add hacky fallback memory access using the progbuf when sysbus and abstract memory access is not available
1 parent a3cce45 commit 85fa83e

3 files changed

Lines changed: 171 additions & 15 deletions

File tree

src/target/riscv32.c

Lines changed: 152 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ static ssize_t riscv32_reg_read(target_s *target, uint32_t c, void *data, size_t
7272
static ssize_t riscv32_reg_write(target_s *target, uint32_t c, const void *data, size_t max);
7373
static void riscv32_regs_read(target_s *target, void *data);
7474
static void riscv32_regs_write(target_s *target, const void *data);
75+
static void riscv32_mem_read(target_s *target, void *dest, target_addr_t src, size_t len);
76+
static void riscv32_mem_write(target_s *target, target_addr_t dest, const void *src, size_t len);
7577

7678
static int riscv32_breakwatch_set(target_s *target, breakwatch_s *breakwatch);
7779
static int riscv32_breakwatch_clear(target_s *target, breakwatch_s *breakwatch);
@@ -548,7 +550,139 @@ static void riscv32_sysbus_mem_write(
548550
riscv32_sysbus_mem_adjusted_write(hart, address, data, remainder, native_access_width, native_access_length);
549551
}
550552

551-
void riscv32_mem_read(target_s *const target, void *const dest, const target_addr_t src, const size_t len)
553+
static void riscv32_abstract_progbuf_mem_read(
554+
riscv_hart_s *const hart, void *const dest, const target_addr_t src, const size_t len)
555+
{
556+
if (!(hart->extensions & RV_ISA_EXT_COMPRESSED)) {
557+
DEBUG_ERROR("This target does not implement the compressed ISA extension\n");
558+
return;
559+
}
560+
561+
/* Figure out the maximal width of access to perform, up to the bitness of the target */
562+
const uint8_t access_width = riscv_mem_access_width(hart, src, len);
563+
// const uint8_t access_length = 1U << access_width;
564+
// /* Build the access command */
565+
// const uint32_t command = RV_DM_ABST_CMD_ACCESS_MEM | RV_ABST_READ | (access_width << RV_ABST_MEM_ACCESS_SHIFT) |
566+
// (access_length < len ? RV_ABST_MEM_ADDR_POST_INC : 0U);
567+
// /* Write the address to read to arg1 */
568+
// if (!riscv_dm_write(hart->dbg_module, RV_DM_DATA1, src))
569+
// return;
570+
// uint8_t *const data = (uint8_t *)dest;
571+
// for (size_t offset = 0; offset < len; offset += access_length) {
572+
// /* Execute the read */
573+
// if (!riscv_dm_write(hart->dbg_module, RV_DM_ABST_COMMAND, command) || !riscv_command_wait_complete(hart))
574+
// return;
575+
// /* Extract back the data from arg0 */
576+
// uint32_t value = 0;
577+
// if (!riscv_dm_read(hart->dbg_module, RV_DM_DATA0, &value))
578+
// return;
579+
// riscv32_unpack_data(data + offset, value, access_width);
580+
// }
581+
582+
/* Disable auto-exec */
583+
// if (!riscv_dm_write(hart->dbg_module, RV_DM_ABST_AUTO, 0))
584+
// return;
585+
586+
/*
587+
* progbuf 0
588+
* c.lw x8,0(x11) // Pull the address from DATA1
589+
* c.lw x9,0(x8) // Read the data at that location
590+
*/
591+
if (!riscv_dm_write(hart->dbg_module, RV_DM_PROGBUF0, 0x40044180U))
592+
return;
593+
594+
/*
595+
* progbuf 1
596+
* c.nop // alternately, `c.addi x8, 4` , for auto-increment (0xc1040411)
597+
* c.sw x9, 0(x10) // Write back to DATA0
598+
*/
599+
if (!riscv_dm_write(hart->dbg_module, RV_DM_PROGBUF1, 0xc1040001U))
600+
return;
601+
602+
/*
603+
* progbuf 2
604+
* c.sw x8, 0(x11) // Write addy to DATA1
605+
* c.ebreak
606+
*/
607+
if (!riscv_dm_write(hart->dbg_module, RV_DM_PROGBUF2, 0x9002c180U))
608+
return;
609+
610+
/* StaticUpdatePROGBUFRegs */
611+
uint32_t rr;
612+
if (!riscv_dm_read(hart->dbg_module, 0x12U, &rr)) {
613+
DEBUG_ERROR("Could not get hart info\n");
614+
return;
615+
}
616+
DEBUG_INFO("rr: %08" PRIx32 "\n", rr);
617+
const uint32_t data0_offset = 0xe0000000U | (rr & 0x7ffU);
618+
if (!riscv_dm_write(hart->dbg_module, RV_DM_DATA0, data0_offset)) // DATA0's location in memory.
619+
return;
620+
if (!riscv_dm_write(hart->dbg_module, RV_DM_ABST_COMMAND, 0x0023100aU)) // Copy data to x10
621+
return;
622+
if (!riscv_dm_write(hart->dbg_module, RV_DM_DATA0, data0_offset + 4U)) // DATA1's location in memory.
623+
return;
624+
if (!riscv_dm_write(hart->dbg_module, RV_DM_ABST_COMMAND, 0x0023100bU)) // Copy data to x11
625+
return;
626+
// if (!riscv_dm_write(hart->dbg_module, RV_DM_DATA0, 0x40022010U)) // FLASH->CTLR
627+
// return;
628+
// if (!riscv_dm_write(hart->dbg_module, RV_DM_ABST_COMMAND, 0x0023100cU)) // Copy data to x12
629+
// return;
630+
// #define CR_PAGE_PG ((uint32_t)0x00010000)
631+
// #define CR_BUF_LOAD ((uint32_t)0x00040000)
632+
// if (!riscv_dm_write(hart->dbg_module, RV_DM_DATA0, CR_PAGE_PG | CR_BUF_LOAD))
633+
// return;
634+
// if (!riscv_dm_write(hart->dbg_module, RV_DM_ABST_COMMAND, 0x0023100dU)) // Copy data to x13
635+
// return;
636+
637+
/* Enable auto-exec */
638+
// if (!riscv_dm_write(hart->dbg_module, RV_DM_ABST_AUTO, 1U))
639+
// return;
640+
641+
if (!riscv_dm_write(hart->dbg_module, RV_DM_DATA1, src))
642+
return;
643+
if (!riscv_dm_write(hart->dbg_module, RV_DM_ABST_COMMAND, 0x00241000U) || !riscv_command_wait_complete(hart))
644+
return;
645+
646+
/* Extract back the data from arg0 */
647+
uint32_t value = 0;
648+
if (!riscv_dm_read(hart->dbg_module, RV_DM_DATA0, &value))
649+
return;
650+
651+
riscv32_unpack_data(dest, value, access_width);
652+
}
653+
654+
static void riscv32_abstract_progbuf_mem_write(
655+
riscv_hart_s *const hart, const target_addr_t dest, const void *const src, const size_t len)
656+
{
657+
DEBUG_TARGET("Performing %zu byte write of %08" PRIx32 " using PROGBUF\n", len, dest);
658+
659+
(void)hart;
660+
(void)dest;
661+
(void)src;
662+
(void)len;
663+
664+
// /* Figure out the maximal width of access to perform, up to the bitness of the target */
665+
// const uint8_t access_width = riscv_mem_access_width(hart, dest, len);
666+
// const uint8_t access_length = 1U << access_width;
667+
// /* Build the access command */
668+
// const uint32_t command = RV_DM_ABST_CMD_ACCESS_MEM | RV_ABST_WRITE | (access_width << RV_ABST_MEM_ACCESS_SHIFT) |
669+
// (access_length < len ? RV_ABST_MEM_ADDR_POST_INC : 0U);
670+
// /* Write the address to write to arg1 */
671+
// if (!riscv_dm_write(hart->dbg_module, RV_DM_DATA1, dest))
672+
// return;
673+
// const uint8_t *const data = (const uint8_t *)src;
674+
// for (size_t offset = 0; offset < len; offset += access_length) {
675+
// /* Pack the data to write into arg0 */
676+
// uint32_t value = riscv32_pack_data(data + offset, access_width);
677+
// if (!riscv_dm_write(hart->dbg_module, RV_DM_DATA0, value))
678+
// return;
679+
// /* Execute the write */
680+
// if (!riscv_dm_write(hart->dbg_module, RV_DM_ABST_COMMAND, command) || !riscv_command_wait_complete(hart))
681+
// return;
682+
// }
683+
}
684+
685+
static void riscv32_mem_read(target_s *const target, void *const dest, const target_addr_t src, const size_t len)
552686
{
553687
/* If we're asked to do a 0-byte read, do nothing */
554688
if (!len) {
@@ -559,8 +693,15 @@ void riscv32_mem_read(target_s *const target, void *const dest, const target_add
559693
riscv_hart_s *const hart = riscv_hart_struct(target);
560694
if (hart->flags & RV_HART_FLAG_MEMORY_SYSBUS)
561695
riscv32_sysbus_mem_read(hart, dest, src, len);
562-
else
696+
else if (hart->flags & RV_HART_FLAG_MEMORY_ABSTRACT) {
563697
riscv32_abstract_mem_read(hart, dest, src, len);
698+
if (hart->status == RISCV_HART_NOT_SUPP) {
699+
DEBUG_WARN("Abstract memory access not supported, falling back to prog buffer\n");
700+
hart->flags &= (uint8_t)~RV_HART_FLAG_MEMORY_ABSTRACT;
701+
riscv32_abstract_progbuf_mem_read(hart, dest, src, len);
702+
}
703+
} else
704+
riscv32_abstract_progbuf_mem_read(hart, dest, src, len);
564705

565706
#if ENABLE_DEBUG
566707
DEBUG_PROTO("%s: @ %08" PRIx32 " len %zu:", __func__, src, len);
@@ -578,7 +719,7 @@ void riscv32_mem_read(target_s *const target, void *const dest, const target_add
578719
#endif
579720
}
580721

581-
void riscv32_mem_write(target_s *const target, const target_addr_t dest, const void *const src, const size_t len)
722+
static void riscv32_mem_write(target_s *const target, const target_addr_t dest, const void *const src, const size_t len)
582723
{
583724
#if ENABLE_DEBUG
584725
DEBUG_PROTO("%s: @ %" PRIx32 " len %zu:", __func__, dest, len);
@@ -601,8 +742,15 @@ void riscv32_mem_write(target_s *const target, const target_addr_t dest, const v
601742
riscv_hart_s *const hart = riscv_hart_struct(target);
602743
if (hart->flags & RV_HART_FLAG_MEMORY_SYSBUS)
603744
riscv32_sysbus_mem_write(hart, dest, src, len);
604-
else
745+
else if (hart->flags & RV_HART_FLAG_MEMORY_ABSTRACT) {
605746
riscv32_abstract_mem_write(hart, dest, src, len);
747+
if (hart->status == RISCV_HART_NOT_SUPP) {
748+
DEBUG_WARN("Abstract memory access not supported, falling back to prog buffer\n");
749+
hart->flags &= (uint8_t)~RV_HART_FLAG_MEMORY_ABSTRACT;
750+
riscv32_abstract_progbuf_mem_write(hart, dest, src, len);
751+
}
752+
} else
753+
riscv32_abstract_progbuf_mem_write(hart, dest, src, len);
606754
}
607755

608756
/*

src/target/riscv_debug.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -780,17 +780,23 @@ static void riscv_hart_discover_triggers(riscv_hart_s *const hart)
780780

781781
static void riscv_hart_memory_access_type(riscv_hart_s *const hart)
782782
{
783-
uint32_t sysbus_status;
784-
hart->flags &= (uint8_t)~RV_HART_FLAG_MEMORY_SYSBUS;
783+
hart->flags &= (uint8_t)~RV_HART_FLAG_MEMORY_MASK;
785784
/*
786785
* Try reading the system bus access control and status register.
787786
* Check if the value read back is non-zero for the sbasize field
788787
*/
789-
if (!riscv_dm_read(hart->dbg_module, RV_DM_SYSBUS_CTRLSTATUS, &sysbus_status) ||
790-
!(sysbus_status & RV_DM_SYSBUS_STATUS_ADDR_WIDTH_MASK))
791-
return;
792-
/* If all the checks passed, we now have a valid system bus so can proceed with using it for memory access */
793-
hart->flags = RV_HART_FLAG_MEMORY_SYSBUS | (sysbus_status & RV_HART_FLAG_ACCESS_WIDTH_MASK);
788+
uint32_t sysbus_status;
789+
if (riscv_dm_read(hart->dbg_module, RV_DM_SYSBUS_CTRLSTATUS, &sysbus_status) &&
790+
sysbus_status & RV_DM_SYSBUS_STATUS_ADDR_WIDTH_MASK) {
791+
/* If all the checks passed, we now have a valid system bus so can proceed with using it for memory access */
792+
hart->flags = RV_HART_FLAG_MEMORY_SYSBUS | (sysbus_status & RV_HART_FLAG_ACCESS_WIDTH_MASK);
793+
} else {
794+
/*
795+
* If the system bus is not valid, we need to fall back to using abstract commands
796+
* Later, if the memory access fails, we'll clear the flag and fall back to use the prog buffer
797+
*/
798+
hart->flags = RV_HART_FLAG_MEMORY_ABSTRACT;
799+
}
794800
/* Make sure the system bus is not in any kind of error state */
795801
(void)riscv_dm_write(hart->dbg_module, RV_DM_SYSBUS_CTRLSTATUS, 0x00407000U);
796802
}

src/target/riscv_debug.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,9 @@ typedef enum riscv_match_size {
8585
} riscv_match_size_e;
8686

8787
/* These defines specify Hart-specific information such as which memory access style to use */
88-
#define RV_HART_FLAG_MEMORY_ABSTRACT 0x00U
88+
#define RV_HART_FLAG_MEMORY_MASK 0x30U
8989
#define RV_HART_FLAG_MEMORY_SYSBUS 0x10U
90+
#define RV_HART_FLAG_MEMORY_ABSTRACT 0x20U
9091
#define RV_HART_FLAG_ACCESS_WIDTH_MASK 0x0fU
9192
#define RV_HART_FLAG_ACCESS_WIDTH_8BIT 0x01U
9293
#define RV_HART_FLAG_ACCESS_WIDTH_16BIT 0x02U
@@ -161,6 +162,10 @@ typedef struct riscv_hart {
161162
#define RV_DM_DATA3 0x07U
162163
#define RV_DM_ABST_CTRLSTATUS 0x16U
163164
#define RV_DM_ABST_COMMAND 0x17U
165+
#define RV_DM_ABST_AUTO 0x18U
166+
#define RV_DM_PROGBUF0 0x20U
167+
#define RV_DM_PROGBUF1 0x21U
168+
#define RV_DM_PROGBUF2 0x22U
164169
#define RV_DM_SYSBUS_CTRLSTATUS 0x38U
165170
#define RV_DM_SYSBUS_ADDR0 0x39U
166171
#define RV_DM_SYSBUS_ADDR1 0x3aU
@@ -271,7 +276,4 @@ uint8_t riscv_mem_access_width(const riscv_hart_s *hart, target_addr_t address,
271276
void riscv32_unpack_data(void *dest, uint32_t data, uint8_t access_width);
272277
uint32_t riscv32_pack_data(const void *src, uint8_t access_width);
273278

274-
void riscv32_mem_read(target_s *target, void *dest, target_addr_t src, size_t len);
275-
void riscv32_mem_write(target_s *target, target_addr_t dest, const void *src, size_t len);
276-
277279
#endif /*TARGET_RISCV_DEBUG_H*/

0 commit comments

Comments
 (0)