@@ -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+
880980bool 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