Skip to content

Commit 91300da

Browse files
committed
Implement abstract memory read/write command in Spike
This commit implements the abstract memory read/write commands in the debug module. The changes include: - Added support for abstract memory access commands (cmdtype 2) in perform_abstract_command() - Implemented perform_abstract_memory_access() method to handle memory operations Signed-off-by: Farid Khaydari <[email protected]>
1 parent 11ee6d0 commit 91300da

File tree

2 files changed

+234
-121
lines changed

2 files changed

+234
-121
lines changed

riscv/debug_module.cc

Lines changed: 221 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -697,11 +697,26 @@ bool debug_module_t::perform_abstract_command()
697697
return true;
698698
}
699699

700-
if ((command >> 24) == 0) {
701-
// register access
702-
unsigned size = get_field(command, AC_ACCESS_REGISTER_AARSIZE);
703-
bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
704-
unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
700+
auto cmdtype = get_field(command, DM_COMMAND_CMDTYPE);
701+
constexpr decltype(cmdtype) CMDTYPE_ACCESS_REGISTER = 0ULL;
702+
constexpr decltype(cmdtype) CMDTYPE_ACCESS_MEMORY = 2ULL;
703+
704+
if (cmdtype == CMDTYPE_ACCESS_REGISTER)
705+
return perform_abstract_register_access();
706+
707+
if (cmdtype == CMDTYPE_ACCESS_MEMORY)
708+
return perform_abstract_memory_access();
709+
710+
abstractcs.cmderr = CMDERR_NOTSUP;
711+
return true;
712+
}
713+
714+
bool debug_module_t::perform_abstract_register_access()
715+
{
716+
// register access
717+
unsigned size = get_field(command, AC_ACCESS_REGISTER_AARSIZE);
718+
bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
719+
unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
705720

706721
if (!selected_hart_state().halted) {
707722
abstractcs.cmderr = CMDERR_HALTRESUME;
@@ -715,120 +730,120 @@ bool debug_module_t::perform_abstract_command()
715730
return true;
716731
}
717732

718-
unsigned i = 0;
719-
if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
733+
unsigned i = 0;
734+
if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
735+
736+
if (is_fpu_reg(regno)) {
737+
// Save S0
738+
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0));
739+
// Save mstatus
740+
write32(debug_abstract, i++, csrr(S0, CSR_MSTATUS));
741+
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH1));
742+
// Set mstatus.fs
743+
assert((MSTATUS_FS & 0xfff) == 0);
744+
write32(debug_abstract, i++, lui(S0, MSTATUS_FS >> 12));
745+
write32(debug_abstract, i++, csrrs(ZERO, S0, CSR_MSTATUS));
746+
}
720747

721-
if (is_fpu_reg(regno)) {
722-
// Save S0
748+
if (regno < 0x1000 && config.support_abstract_csr_access) {
749+
if (!is_fpu_reg(regno)) {
723750
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0));
724-
// Save mstatus
725-
write32(debug_abstract, i++, csrr(S0, CSR_MSTATUS));
726-
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH1));
727-
// Set mstatus.fs
728-
assert((MSTATUS_FS & 0xfff) == 0);
729-
write32(debug_abstract, i++, lui(S0, MSTATUS_FS >> 12));
730-
write32(debug_abstract, i++, csrrs(ZERO, S0, CSR_MSTATUS));
731751
}
732752

733-
if (regno < 0x1000 && config.support_abstract_csr_access) {
734-
if (!is_fpu_reg(regno)) {
735-
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0));
736-
}
737-
738-
if (write) {
739-
switch (size) {
740-
case 2:
741-
write32(debug_abstract, i++, lw(S0, ZERO, debug_data_start));
742-
break;
743-
case 3:
744-
write32(debug_abstract, i++, ld(S0, ZERO, debug_data_start));
745-
break;
746-
default:
747-
abstractcs.cmderr = CMDERR_NOTSUP;
748-
return true;
749-
}
750-
write32(debug_abstract, i++, csrw(S0, regno));
751-
752-
} else {
753-
write32(debug_abstract, i++, csrr(S0, regno));
754-
switch (size) {
755-
case 2:
756-
write32(debug_abstract, i++, sw(S0, ZERO, debug_data_start));
757-
break;
758-
case 3:
759-
write32(debug_abstract, i++, sd(S0, ZERO, debug_data_start));
760-
break;
761-
default:
762-
abstractcs.cmderr = CMDERR_NOTSUP;
763-
return true;
764-
}
765-
}
766-
if (!is_fpu_reg(regno)) {
767-
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0));
753+
if (write) {
754+
switch (size) {
755+
case 2:
756+
write32(debug_abstract, i++, lw(S0, ZERO, debug_data_start));
757+
break;
758+
case 3:
759+
write32(debug_abstract, i++, ld(S0, ZERO, debug_data_start));
760+
break;
761+
default:
762+
abstractcs.cmderr = CMDERR_NOTSUP;
763+
return true;
768764
}
765+
write32(debug_abstract, i++, csrw(S0, regno));
769766

770-
} else if (regno >= 0x1000 && regno < 0x1020) {
771-
unsigned regnum = regno - 0x1000;
772-
767+
} else {
768+
write32(debug_abstract, i++, csrr(S0, regno));
773769
switch (size) {
774770
case 2:
775-
if (write)
776-
write32(debug_abstract, i++, lw(regnum, ZERO, debug_data_start));
777-
else
778-
write32(debug_abstract, i++, sw(regnum, ZERO, debug_data_start));
771+
write32(debug_abstract, i++, sw(S0, ZERO, debug_data_start));
779772
break;
780773
case 3:
781-
if (write)
782-
write32(debug_abstract, i++, ld(regnum, ZERO, debug_data_start));
783-
else
784-
write32(debug_abstract, i++, sd(regnum, ZERO, debug_data_start));
774+
write32(debug_abstract, i++, sd(S0, ZERO, debug_data_start));
785775
break;
786776
default:
787777
abstractcs.cmderr = CMDERR_NOTSUP;
788778
return true;
789779
}
780+
}
781+
if (!is_fpu_reg(regno)) {
782+
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0));
783+
}
790784

791-
if (regno == 0x1000 + S0 && write) {
792-
/*
793-
* The exception handler starts out be restoring dscratch to s0,
794-
* which was saved before executing the abstract memory region. Since
795-
* we just wrote s0, also make sure to write that same value to
796-
* dscratch in case an exception occurs in a program buffer that
797-
* might be executed later.
798-
*/
799-
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0));
800-
}
785+
} else if (regno >= 0x1000 && regno < 0x1020) {
786+
unsigned regnum = regno - 0x1000;
801787

802-
} else if (regno >= 0x1020 && regno < 0x1040 && config.support_abstract_fpr_access) {
803-
unsigned fprnum = regno - 0x1020;
788+
switch (size) {
789+
case 2:
790+
if (write)
791+
write32(debug_abstract, i++, lw(regnum, ZERO, debug_data_start));
792+
else
793+
write32(debug_abstract, i++, sw(regnum, ZERO, debug_data_start));
794+
break;
795+
case 3:
796+
if (write)
797+
write32(debug_abstract, i++, ld(regnum, ZERO, debug_data_start));
798+
else
799+
write32(debug_abstract, i++, sd(regnum, ZERO, debug_data_start));
800+
break;
801+
default:
802+
abstractcs.cmderr = CMDERR_NOTSUP;
803+
return true;
804+
}
804805

805-
if (write) {
806-
switch (size) {
807-
case 2:
808-
write32(debug_abstract, i++, flw(fprnum, ZERO, debug_data_start));
809-
break;
810-
case 3:
811-
write32(debug_abstract, i++, fld(fprnum, ZERO, debug_data_start));
812-
break;
813-
default:
814-
abstractcs.cmderr = CMDERR_NOTSUP;
815-
return true;
816-
}
806+
if (regno == 0x1000 + S0 && write) {
807+
/*
808+
* The exception handler starts out be restoring dscratch to s0,
809+
* which was saved before executing the abstract memory region. Since
810+
* we just wrote s0, also make sure to write that same value to
811+
* dscratch in case an exception occurs in a program buffer that
812+
* might be executed later.
813+
*/
814+
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0));
815+
}
817816

818-
} else {
819-
switch (size) {
820-
case 2:
821-
write32(debug_abstract, i++, fsw(fprnum, ZERO, debug_data_start));
822-
break;
823-
case 3:
824-
write32(debug_abstract, i++, fsd(fprnum, ZERO, debug_data_start));
825-
break;
826-
default:
827-
abstractcs.cmderr = CMDERR_NOTSUP;
828-
return true;
829-
}
817+
} else if (regno >= 0x1020 && regno < 0x1040 && config.support_abstract_fpr_access) {
818+
unsigned fprnum = regno - 0x1020;
819+
820+
if (write) {
821+
switch (size) {
822+
case 2:
823+
write32(debug_abstract, i++, flw(fprnum, ZERO, debug_data_start));
824+
break;
825+
case 3:
826+
write32(debug_abstract, i++, fld(fprnum, ZERO, debug_data_start));
827+
break;
828+
default:
829+
abstractcs.cmderr = CMDERR_NOTSUP;
830+
return true;
830831
}
831832

833+
} else {
834+
switch (size) {
835+
case 2:
836+
write32(debug_abstract, i++, fsw(fprnum, ZERO, debug_data_start));
837+
break;
838+
case 3:
839+
write32(debug_abstract, i++, fsd(fprnum, ZERO, debug_data_start));
840+
break;
841+
default:
842+
abstractcs.cmderr = CMDERR_NOTSUP;
843+
return true;
844+
}
845+
}
846+
832847
} else if (regno >= 0xc000 && (regno & 1) == 1) {
833848
// Support odd-numbered custom registers, to allow for debugger testing.
834849
unsigned custom_number = regno - 0xc000;
@@ -844,39 +859,124 @@ bool debug_module_t::perform_abstract_command()
844859
}
845860
return true;
846861

847-
} else {
848-
abstractcs.cmderr = CMDERR_NOTSUP;
849-
return true;
850-
}
851-
852-
if (is_fpu_reg(regno)) {
853-
// restore mstatus
854-
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH1));
855-
write32(debug_abstract, i++, csrw(S0, CSR_MSTATUS));
856-
// restore s0
857-
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0));
858-
}
859-
}
860-
861-
if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
862-
write32(debug_abstract, i,
863-
jal(ZERO, debug_progbuf_start - debug_abstract_start - 4 * i));
864-
i++;
865862
} else {
866-
write32(debug_abstract, i++, ebreak());
863+
abstractcs.cmderr = CMDERR_NOTSUP;
864+
return true;
867865
}
868866

869-
debug_rom_flags[selected_hart_id()] |= 1 << DEBUG_ROM_FLAG_GO;
870-
rti_remaining = config.abstract_rti;
871-
abstract_command_completed = false;
867+
if (is_fpu_reg(regno)) {
868+
// restore mstatus
869+
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH1));
870+
write32(debug_abstract, i++, csrw(S0, CSR_MSTATUS));
871+
// restore s0
872+
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0));
873+
}
874+
}
872875

873-
abstractcs.busy = true;
876+
if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
877+
write32(debug_abstract, i,
878+
jal(ZERO, debug_progbuf_start - debug_abstract_start - 4 * i));
879+
i++;
874880
} else {
881+
write32(debug_abstract, i++, ebreak());
882+
}
883+
884+
debug_rom_flags[selected_hart_id()] |= 1 << DEBUG_ROM_FLAG_GO;
885+
rti_remaining = config.abstract_rti;
886+
abstract_command_completed = false;
887+
888+
abstractcs.busy = true;
889+
return true;
890+
}
891+
892+
static unsigned idx(unsigned xlen)
893+
{
894+
return field_width(xlen) - 3U;
895+
}
896+
897+
bool debug_module_t::perform_abstract_memory_access() {
898+
unsigned aamsize = get_field(command, AC_ACCESS_MEMORY_AAMSIZE);
899+
bool aampostincrement = get_field(command, AC_ACCESS_MEMORY_AAMPOSTINCREMENT);
900+
bool aamvirtual = get_field(command, AC_ACCESS_MEMORY_AAMVIRTUAL);
901+
bool is_write = get_field(command, AC_ACCESS_MEMORY_WRITE);
902+
auto xlen = sim->get_harts().at(selected_hart_id())->get_xlen();
903+
904+
if (!selected_hart_state().halted) {
905+
abstractcs.cmderr = CMDERR_HALTRESUME;
906+
return true;
907+
}
908+
909+
if (aamvirtual || aamsize > 3 || aamsize > idx(xlen)) {
875910
abstractcs.cmderr = CMDERR_NOTSUP;
911+
return true;
876912
}
913+
914+
unsigned offset = 0;
915+
generate_initial_sequence(offset);
916+
is_write ? handle_memory_write(xlen, aamsize, offset)
917+
: handle_memory_read(xlen, aamsize, offset);
918+
919+
if (aampostincrement)
920+
handle_post_increment(xlen, aamsize, offset);
921+
922+
generate_termination_sequence(offset);
923+
start_command_execution();
924+
925+
abstractcs.cmderr = CMDERR_NONE;
877926
return true;
878927
}
879928

929+
using handle_memory_func = uint32_t (*)(unsigned rd_src, unsigned base, uint16_t offset);
930+
static constexpr std::array<handle_memory_func, 4> lx = {&lb, &lh, &lw, &ld};
931+
static constexpr std::array<handle_memory_func, 4> sx = {&sb, &sh, &sw, &sd};
932+
933+
unsigned debug_module_t::arg(unsigned xlen, unsigned idx)
934+
{
935+
return debug_data_start + idx * xlen / 8;
936+
}
937+
938+
void debug_module_t::handle_memory_read(size_t xlen, unsigned aamsize, unsigned &offset)
939+
{
940+
write32(debug_abstract, offset++, lx[idx(xlen)](S0, ZERO, arg(xlen, 1)));
941+
write32(debug_abstract, offset++, lx[aamsize](S0, S0, 0));
942+
write32(debug_abstract, offset++, sx[idx(xlen)](S0, ZERO, arg(xlen, 0)));
943+
}
944+
945+
void debug_module_t::handle_memory_write(size_t xlen, unsigned aamsize, unsigned &offset)
946+
{
947+
write32(debug_abstract, offset++, lx[idx(xlen)](S0, ZERO, arg(xlen, 0)));
948+
write32(debug_abstract, offset++, lx[idx(xlen)](S1, ZERO, arg(xlen, 1)));
949+
write32(debug_abstract, offset++, sx[aamsize](S0, S1, 0));
950+
}
951+
952+
void debug_module_t::handle_post_increment(size_t xlen, unsigned aamsize, unsigned &offset)
953+
{
954+
write32(debug_abstract, offset++, lx[idx(xlen)](S1, ZERO, arg(xlen, 1)));
955+
write32(debug_abstract, offset++, addi(S1, S1, 1U << aamsize));
956+
write32(debug_abstract, offset++, sx[idx(xlen)](S1, ZERO, arg(xlen, 1)));
957+
}
958+
959+
void debug_module_t::generate_initial_sequence(unsigned &offset)
960+
{
961+
write32(debug_abstract, offset++, csrw(S0, CSR_DSCRATCH0));
962+
write32(debug_abstract, offset++, csrw(S1, CSR_DSCRATCH1));
963+
}
964+
965+
void debug_module_t::generate_termination_sequence(unsigned &offset)
966+
{
967+
write32(debug_abstract, offset++, csrr(S0, CSR_DSCRATCH0));
968+
write32(debug_abstract, offset++, csrr(S1, CSR_DSCRATCH1));
969+
write32(debug_abstract, offset++, ebreak());
970+
}
971+
972+
void debug_module_t::start_command_execution()
973+
{
974+
debug_rom_flags[selected_hart_id()] |= 1 << DEBUG_ROM_FLAG_GO;
975+
rti_remaining = config.abstract_rti;
976+
abstract_command_completed = false;
977+
abstractcs.busy = true;
978+
}
979+
880980
bool debug_module_t::dmi_write(unsigned address, uint32_t value)
881981
{
882982
D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));

0 commit comments

Comments
 (0)