@@ -145,6 +145,60 @@ typedef struct {
145145 struct target * target ;
146146} target_list_t ;
147147
148+ struct ac_cache {
149+ uint32_t * commands ;
150+ size_t size ;
151+ };
152+
153+ static int ac_cache_elem_comparator (const void * lhs , const void * rhs )
154+ {
155+ return * (const uint32_t * )rhs - * (const uint32_t * )lhs ;
156+ }
157+
158+ static struct ac_cache ac_cache_construct (void )
159+ {
160+ struct ac_cache cache = {
161+ cache .commands = NULL ,
162+ cache .size = 0 ,
163+ };
164+ return cache ;
165+ }
166+
167+ static void ac_cache_free (struct ac_cache * cache )
168+ {
169+ free (cache -> commands );
170+ cache -> commands = NULL ;
171+ cache -> size = 0 ;
172+ }
173+
174+ static void ac_cache_insert (struct ac_cache * cache , uint32_t command )
175+ {
176+ assert (cache );
177+
178+ size_t old_size = cache -> size ;
179+ size_t new_size = old_size + 1 ;
180+ size_t entry_size = sizeof (* cache -> commands );
181+
182+ uint32_t * commands = realloc (cache -> commands , new_size * entry_size );
183+ if (!commands ) {
184+ LOG_ERROR ("Reallocation to %zu bytes failed" , new_size );
185+ return ;
186+ }
187+
188+ commands [old_size ] = command ;
189+ cache -> commands = commands ;
190+ cache -> size = new_size ;
191+
192+ qsort (cache -> commands , cache -> size , entry_size ,
193+ ac_cache_elem_comparator );
194+ }
195+
196+ static bool ac_cache_contains (const struct ac_cache * cache , uint32_t command )
197+ {
198+ return bsearch (& command , cache -> commands , cache -> size ,
199+ sizeof (* cache -> commands ), ac_cache_elem_comparator );
200+ }
201+
148202typedef struct {
149203 /* The indexed used to address this hart in its DM. */
150204 unsigned int index ;
@@ -175,12 +229,7 @@ typedef struct {
175229 */
176230 struct riscv_scan_delays learned_delays ;
177231
178- bool abstract_read_csr_supported ;
179- bool abstract_write_csr_supported ;
180- bool abstract_read_fpr_supported ;
181- bool abstract_write_fpr_supported ;
182-
183- yes_no_maybe_t has_aampostincrement ;
232+ struct ac_cache ac_not_supported_cache ;
184233
185234 /* Some fields from hartinfo. */
186235 uint8_t datasize ;
@@ -651,6 +700,24 @@ static int abstract_cmd_batch_check_and_clear_cmderr(struct target *target,
651700 return res ;
652701}
653702
703+ static void mark_command_as_unsupported (struct target * target , uint32_t command )
704+ {
705+ enum riscv_debug_reg_ordinal val2cmdtype [4 ] = {
706+ AC_ACCESS_REGISTER_ORDINAL ,
707+ AC_QUICK_ACCESS_ORDINAL ,
708+ AC_ACCESS_MEMORY_ORDINAL ,
709+ 0 ,
710+ };
711+
712+ enum riscv_debug_reg_ordinal cmdtype =
713+ val2cmdtype [get_field (command , DM_COMMAND_CMDTYPE )];
714+
715+ LOG_TARGET_DEBUG (target , "Caching the abstract "
716+ "command 0x%" PRIx32 " as not supported" , command );
717+ log_debug_reg (target , cmdtype , command , __FILE__ , __LINE__ , __func__ );
718+ ac_cache_insert (& get_info (target )-> ac_not_supported_cache , command );
719+ }
720+
654721int riscv013_execute_abstract_command (struct target * target , uint32_t command ,
655722 uint32_t * cmderr )
656723{
@@ -684,6 +751,9 @@ int riscv013_execute_abstract_command(struct target *target, uint32_t command,
684751
685752 res = abstract_cmd_batch_check_and_clear_cmderr (target , batch ,
686753 abstractcs_read_key , cmderr );
754+ if (res != ERROR_OK && * cmderr == CMDERR_NOT_SUPPORTED )
755+ mark_command_as_unsupported (target , command );
756+
687757cleanup :
688758 riscv_batch_free (batch );
689759 return res ;
@@ -829,38 +899,40 @@ uint32_t riscv013_access_register_command(struct target *target, uint32_t number
829899 return command ;
830900}
831901
902+ static bool is_command_unsupported (struct target * target , uint32_t command )
903+ {
904+ enum riscv_debug_reg_ordinal val2cmdtype [4 ] = {
905+ AC_ACCESS_REGISTER_ORDINAL ,
906+ AC_QUICK_ACCESS_ORDINAL ,
907+ AC_ACCESS_MEMORY_ORDINAL ,
908+ 0 ,
909+ };
910+
911+ enum riscv_debug_reg_ordinal cmdtype =
912+ val2cmdtype [get_field (command , DM_COMMAND_CMDTYPE )];
913+
914+ LOG_TARGET_DEBUG (target , "Abstract command 0x%"
915+ PRIx32 " is cached as not supported" , command );
916+ log_debug_reg (target , cmdtype , command , __FILE__ , __LINE__ , __func__ );
917+ return ac_cache_contains (& get_info (target )-> ac_not_supported_cache , command );
918+ }
919+
832920static int register_read_abstract_with_size (struct target * target ,
833921 riscv_reg_t * value , enum gdb_regno number , unsigned int size )
834922{
835- RISCV013_INFO (info );
836-
837- if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 &&
838- !info -> abstract_read_fpr_supported )
839- return ERROR_FAIL ;
840- if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 &&
841- !info -> abstract_read_csr_supported )
842- return ERROR_FAIL ;
843923 /* The spec doesn't define abstract register numbers for vector registers. */
844924 if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31 )
845925 return ERROR_FAIL ;
846926
847927 uint32_t command = riscv013_access_register_command (target , number , size ,
848928 AC_ACCESS_REGISTER_TRANSFER );
929+ if (is_command_unsupported (target , command ))
930+ return ERROR_FAIL ;
849931
850932 uint32_t cmderr ;
851933 int result = riscv013_execute_abstract_command (target , command , & cmderr );
852- if (result != ERROR_OK ) {
853- if (cmderr == CMDERR_NOT_SUPPORTED ) {
854- if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 ) {
855- info -> abstract_read_fpr_supported = false;
856- LOG_TARGET_INFO (target , "Disabling abstract command reads from FPRs." );
857- } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 ) {
858- info -> abstract_read_csr_supported = false;
859- LOG_TARGET_INFO (target , "Disabling abstract command reads from CSRs." );
860- }
861- }
934+ if (result != ERROR_OK )
862935 return result ;
863- }
864936
865937 if (value )
866938 return read_abstract_arg (target , value , 0 , size );
@@ -879,23 +951,17 @@ static int register_read_abstract(struct target *target, riscv_reg_t *value,
879951static int register_write_abstract (struct target * target , enum gdb_regno number ,
880952 riscv_reg_t value )
881953{
882- RISCV013_INFO (info );
883-
884954 dm013_info_t * dm = get_dm (target );
885955 if (!dm )
886956 return ERROR_FAIL ;
887957
888- if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 &&
889- !info -> abstract_write_fpr_supported )
890- return ERROR_FAIL ;
891- if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 &&
892- !info -> abstract_write_csr_supported )
893- return ERROR_FAIL ;
894-
895958 const unsigned int size_bits = register_size (target , number );
896959 const uint32_t command = riscv013_access_register_command (target , number , size_bits ,
897960 AC_ACCESS_REGISTER_TRANSFER |
898961 AC_ACCESS_REGISTER_WRITE );
962+ if (is_command_unsupported (target , command ))
963+ return ERROR_FAIL ;
964+
899965 LOG_DEBUG_REG (target , AC_ACCESS_REGISTER , command );
900966 assert (size_bits % 32 == 0 );
901967 const unsigned int size_in_words = size_bits / 32 ;
@@ -915,18 +981,9 @@ static int register_write_abstract(struct target *target, enum gdb_regno number,
915981 uint32_t cmderr ;
916982 res = abstract_cmd_batch_check_and_clear_cmderr (target , batch ,
917983 abstractcs_read_key , & cmderr );
984+ if (res != ERROR_OK && cmderr == CMDERR_NOT_SUPPORTED )
985+ mark_command_as_unsupported (target , command );
918986
919- if (res != ERROR_OK ) {
920- if (cmderr == CMDERR_NOT_SUPPORTED ) {
921- if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 ) {
922- info -> abstract_write_fpr_supported = false;
923- LOG_TARGET_INFO (target , "Disabling abstract command writes to FPRs." );
924- } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 ) {
925- info -> abstract_write_csr_supported = false;
926- LOG_TARGET_INFO (target , "Disabling abstract command writes to CSRs." );
927- }
928- }
929- }
930987cleanup :
931988 riscv_batch_free (batch );
932989 return res ;
@@ -1709,6 +1766,10 @@ static void deinit_target(struct target *target)
17091766 if (!info )
17101767 return ;
17111768
1769+ riscv013_info_t * vsinfo = info -> version_specific ;
1770+ if (vsinfo )
1771+ ac_cache_free (& vsinfo -> ac_not_supported_cache );
1772+
17121773 riscv013_dm_free (target );
17131774
17141775 free (info -> version_specific );
@@ -2819,17 +2880,7 @@ static int init_target(struct command_context *cmd_ctx,
28192880 info -> progbufsize = -1 ;
28202881 reset_learned_delays (target );
28212882
2822- /* Assume all these abstract commands are supported until we learn
2823- * otherwise.
2824- * TODO: The spec allows eg. one CSR to be able to be accessed abstractly
2825- * while another one isn't. We don't track that this closely here, but in
2826- * the future we probably should. */
2827- info -> abstract_read_csr_supported = true;
2828- info -> abstract_write_csr_supported = true;
2829- info -> abstract_read_fpr_supported = true;
2830- info -> abstract_write_fpr_supported = true;
2831-
2832- info -> has_aampostincrement = YNM_MAYBE ;
2883+ info -> ac_not_supported_cache = ac_cache_construct ();
28332884
28342885 return ERROR_OK ;
28352886}
@@ -3719,16 +3770,17 @@ read_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
37193770{
37203771 assert (riscv_mem_access_is_read (args ));
37213772
3722- RISCV013_INFO (info );
3723- bool use_aampostincrement = info -> has_aampostincrement != YNM_NO ;
3724-
37253773 memset (args .read_buffer , 0 , args .count * args .size );
37263774
37273775 /* Convert the size (bytes) to width (bits) */
37283776 unsigned int width = args .size << 3 ;
37293777
37303778 /* Create the command (physical address, postincrement, read) */
3731- uint32_t command = access_memory_command (target , false, width , use_aampostincrement , false);
3779+ uint32_t command = access_memory_command (target , false, width ,
3780+ /* postincrement = */ true, /* is_write= */ false);
3781+ bool use_aampostincrement = !is_command_unsupported (target , command );
3782+ command = access_memory_command (target , false, width ,
3783+ /* postincrement = */ use_aampostincrement , /* is_write = */ false);
37323784
37333785 /* Execute the reads */
37343786 uint8_t * p = args .read_buffer ;
@@ -3749,33 +3801,15 @@ read_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
37493801 /* Execute the command */
37503802 uint32_t cmderr ;
37513803 result = riscv013_execute_abstract_command (target , command , & cmderr );
3752-
3753- /* TODO: we need to modify error handling here. */
3754- /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */
3755- if (info -> has_aampostincrement == YNM_MAYBE ) {
3756- if (result == ERROR_OK ) {
3757- /* Safety: double-check that the address was really auto-incremented */
3758- riscv_reg_t new_address ;
3759- result = read_abstract_arg (target , & new_address , 1 , riscv_xlen (target ));
3760- if (result != ERROR_OK )
3761- return mem_access_result (MEM_ACCESS_FAILED_DM_ACCESS_FAILED );
3762-
3763- if (new_address == args .address + args .size ) {
3764- LOG_TARGET_DEBUG (target , "aampostincrement is supported on this target." );
3765- info -> has_aampostincrement = YNM_YES ;
3766- } else {
3767- LOG_TARGET_WARNING (target , "Buggy aampostincrement! Address not incremented correctly." );
3768- info -> has_aampostincrement = YNM_NO ;
3769- }
3770- } else {
3771- /* Try the same access but with postincrement disabled. */
3772- command = access_memory_command (target , false, width , false, false);
3773- result = riscv013_execute_abstract_command (target , command , & cmderr );
3774- if (result == ERROR_OK ) {
3775- LOG_TARGET_DEBUG (target , "aampostincrement is not supported on this target." );
3776- info -> has_aampostincrement = YNM_NO ;
3777- }
3778- }
3804+ if (use_aampostincrement && result != ERROR_OK &&
3805+ cmderr == CMDERR_NOT_SUPPORTED ) {
3806+ LOG_TARGET_DEBUG (target , "Trying the same abstract memory "
3807+ "write command, but without aampostincrement" );
3808+ use_aampostincrement = false;
3809+
3810+ /* Try the same access but with postincrement disabled. */
3811+ command = access_memory_command (target , false, width , false, false);
3812+ result = riscv013_execute_abstract_command (target , command , & cmderr );
37793813 }
37803814
37813815 /* TODO:
@@ -3791,7 +3825,7 @@ read_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
37913825 return mem_access_result (MEM_ACCESS_FAILED_DM_ACCESS_FAILED );
37923826 buf_set_u64 (p , 0 , 8 * args .size , value );
37933827
3794- if (info -> has_aampostincrement == YNM_YES )
3828+ if (use_aampostincrement )
37953829 updateaddr = false;
37963830 p += args .size ;
37973831 }
@@ -3809,15 +3843,17 @@ write_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
38093843{
38103844 assert (riscv_mem_access_is_write (args ));
38113845
3812- RISCV013_INFO (info );
38133846 int result = ERROR_OK ;
3814- bool use_aampostincrement = info -> has_aampostincrement != YNM_NO ;
38153847
38163848 /* Convert the size (bytes) to width (bits) */
38173849 unsigned int width = args .size << 3 ;
38183850
38193851 /* Create the command (physical address, postincrement, write) */
3820- uint32_t command = access_memory_command (target , false, width , use_aampostincrement , true);
3852+ uint32_t command = access_memory_command (target , false, width ,
3853+ /* postincrement = */ true, /* is_write = */ true);
3854+ bool use_aampostincrement = !is_command_unsupported (target , command );
3855+ command = access_memory_command (target , false, width ,
3856+ /* postincrement = */ use_aampostincrement , /* is_write = */ true);
38213857
38223858 /* Execute the writes */
38233859 const uint8_t * p = args .write_buffer ;
@@ -3844,33 +3880,15 @@ write_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
38443880 /* Execute the command */
38453881 uint32_t cmderr ;
38463882 result = riscv013_execute_abstract_command (target , command , & cmderr );
3847-
3848- /* TODO: we need to modify error handling here. */
3849- /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */
3850- if (info -> has_aampostincrement == YNM_MAYBE ) {
3851- if (result == ERROR_OK ) {
3852- /* Safety: double-check that the address was really auto-incremented */
3853- riscv_reg_t new_address ;
3854- result = read_abstract_arg (target , & new_address , 1 , riscv_xlen (target ));
3855- if (result != ERROR_OK )
3856- return mem_access_result (MEM_ACCESS_FAILED_DM_ACCESS_FAILED );
3857-
3858- if (new_address == args .address + args .size ) {
3859- LOG_TARGET_DEBUG (target , "aampostincrement is supported on this target." );
3860- info -> has_aampostincrement = YNM_YES ;
3861- } else {
3862- LOG_TARGET_WARNING (target , "Buggy aampostincrement! Address not incremented correctly." );
3863- info -> has_aampostincrement = YNM_NO ;
3864- }
3865- } else {
3866- /* Try the same access but with postincrement disabled. */
3867- command = access_memory_command (target , false, width , false, true);
3868- result = riscv013_execute_abstract_command (target , command , & cmderr );
3869- if (result == ERROR_OK ) {
3870- LOG_TARGET_DEBUG (target , "aampostincrement is not supported on this target." );
3871- info -> has_aampostincrement = YNM_NO ;
3872- }
3873- }
3883+ if (use_aampostincrement && result != ERROR_OK &&
3884+ cmderr == CMDERR_NOT_SUPPORTED ) {
3885+ LOG_TARGET_DEBUG (target , "Trying the same abstract memory "
3886+ "write command, but without aampostincrement" );
3887+ use_aampostincrement = false;
3888+
3889+ /* Try the same access but with postincrement disabled. */
3890+ command = access_memory_command (target , false, width , false, true);
3891+ result = riscv013_execute_abstract_command (target , command , & cmderr );
38743892 }
38753893
38763894 /* TODO:
@@ -3879,7 +3897,7 @@ write_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
38793897 if (result != ERROR_OK )
38803898 return mem_access_result (MEM_ACCESS_SKIPPED_ABSTRACT_ACCESS_CMDERR );
38813899
3882- if (info -> has_aampostincrement == YNM_YES )
3900+ if (use_aampostincrement )
38833901 updateaddr = false;
38843902 p += args .size ;
38853903 }
0 commit comments