@@ -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,27 @@ static int abstract_cmd_batch_check_and_clear_cmderr(struct target *target,
651700 return res ;
652701}
653702
703+ enum riscv_debug_reg_ordinal get_cmdtype (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+ return val2cmdtype [get_field (command , DM_COMMAND_CMDTYPE )];
713+ }
714+
715+ static void mark_command_as_unsupported (struct target * target , uint32_t command )
716+ {
717+ LOG_TARGET_DEBUG (target , "Caching the abstract "
718+ "command 0x%" PRIx32 " as not supported" , command );
719+ log_debug_reg (target , get_cmdtype (command ),
720+ command , __FILE__ , __LINE__ , __func__ );
721+ ac_cache_insert (& get_info (target )-> ac_not_supported_cache , command );
722+ }
723+
654724int riscv013_execute_abstract_command (struct target * target , uint32_t command ,
655725 uint32_t * cmderr )
656726{
@@ -684,6 +754,9 @@ int riscv013_execute_abstract_command(struct target *target, uint32_t command,
684754
685755 res = abstract_cmd_batch_check_and_clear_cmderr (target , batch ,
686756 abstractcs_read_key , cmderr );
757+ if (res != ERROR_OK && * cmderr == CMDERR_NOT_SUPPORTED )
758+ mark_command_as_unsupported (target , command );
759+
687760cleanup :
688761 riscv_batch_free (batch );
689762 return res ;
@@ -829,38 +902,35 @@ uint32_t riscv013_access_register_command(struct target *target, uint32_t number
829902 return command ;
830903}
831904
905+ static bool is_command_unsupported (struct target * target , uint32_t command )
906+ {
907+ bool supported = !ac_cache_contains (& get_info (target )-> ac_not_supported_cache , command );
908+ if (supported )
909+ return false;
910+
911+ LOG_TARGET_DEBUG (target , "Abstract command 0x%"
912+ PRIx32 " is cached as not supported" , command );
913+ log_debug_reg (target , get_cmdtype (command ),
914+ command , __FILE__ , __LINE__ , __func__ );
915+ return supported ;
916+ }
917+
832918static int register_read_abstract_with_size (struct target * target ,
833919 riscv_reg_t * value , enum gdb_regno number , unsigned int size )
834920{
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 ;
843921 /* The spec doesn't define abstract register numbers for vector registers. */
844922 if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31 )
845923 return ERROR_FAIL ;
846924
847925 uint32_t command = riscv013_access_register_command (target , number , size ,
848926 AC_ACCESS_REGISTER_TRANSFER );
927+ if (is_command_unsupported (target , command ))
928+ return ERROR_FAIL ;
849929
850930 uint32_t cmderr ;
851931 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- }
932+ if (result != ERROR_OK )
862933 return result ;
863- }
864934
865935 if (value )
866936 return read_abstract_arg (target , value , 0 , size );
@@ -879,23 +949,17 @@ static int register_read_abstract(struct target *target, riscv_reg_t *value,
879949static int register_write_abstract (struct target * target , enum gdb_regno number ,
880950 riscv_reg_t value )
881951{
882- RISCV013_INFO (info );
883-
884952 dm013_info_t * dm = get_dm (target );
885953 if (!dm )
886954 return ERROR_FAIL ;
887955
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-
895956 const unsigned int size_bits = register_size (target , number );
896957 const uint32_t command = riscv013_access_register_command (target , number , size_bits ,
897958 AC_ACCESS_REGISTER_TRANSFER |
898959 AC_ACCESS_REGISTER_WRITE );
960+ if (is_command_unsupported (target , command ))
961+ return ERROR_FAIL ;
962+
899963 LOG_DEBUG_REG (target , AC_ACCESS_REGISTER , command );
900964 assert (size_bits % 32 == 0 );
901965 const unsigned int size_in_words = size_bits / 32 ;
@@ -915,18 +979,9 @@ static int register_write_abstract(struct target *target, enum gdb_regno number,
915979 uint32_t cmderr ;
916980 res = abstract_cmd_batch_check_and_clear_cmderr (target , batch ,
917981 abstractcs_read_key , & cmderr );
982+ if (res != ERROR_OK && cmderr == CMDERR_NOT_SUPPORTED )
983+ mark_command_as_unsupported (target , command );
918984
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- }
930985cleanup :
931986 riscv_batch_free (batch );
932987 return res ;
@@ -1709,6 +1764,10 @@ static void deinit_target(struct target *target)
17091764 if (!info )
17101765 return ;
17111766
1767+ riscv013_info_t * vsinfo = info -> version_specific ;
1768+ if (vsinfo )
1769+ ac_cache_free (& vsinfo -> ac_not_supported_cache );
1770+
17121771 riscv013_dm_free (target );
17131772
17141773 free (info -> version_specific );
@@ -2819,17 +2878,7 @@ static int init_target(struct command_context *cmd_ctx,
28192878 info -> progbufsize = -1 ;
28202879 reset_learned_delays (target );
28212880
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 ;
2881+ info -> ac_not_supported_cache = ac_cache_construct ();
28332882
28342883 return ERROR_OK ;
28352884}
@@ -3719,16 +3768,17 @@ read_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
37193768{
37203769 assert (riscv_mem_access_is_read (args ));
37213770
3722- RISCV013_INFO (info );
3723- bool use_aampostincrement = info -> has_aampostincrement != YNM_NO ;
3724-
37253771 memset (args .read_buffer , 0 , args .count * args .size );
37263772
37273773 /* Convert the size (bytes) to width (bits) */
37283774 unsigned int width = args .size << 3 ;
37293775
37303776 /* Create the command (physical address, postincrement, read) */
3731- uint32_t command = access_memory_command (target , false, width , use_aampostincrement , false);
3777+ uint32_t command = access_memory_command (target , false, width ,
3778+ /* postincrement = */ true, /* is_write= */ false);
3779+ bool use_aampostincrement = !is_command_unsupported (target , command );
3780+ command = access_memory_command (target , false, width ,
3781+ /* postincrement = */ use_aampostincrement , /* is_write = */ false);
37323782
37333783 /* Execute the reads */
37343784 uint8_t * p = args .read_buffer ;
@@ -3749,33 +3799,15 @@ read_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
37493799 /* Execute the command */
37503800 uint32_t cmderr ;
37513801 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- }
3802+ if (use_aampostincrement && result != ERROR_OK &&
3803+ cmderr == CMDERR_NOT_SUPPORTED ) {
3804+ LOG_TARGET_DEBUG (target , "Trying the same abstract memory "
3805+ "write command, but without aampostincrement" );
3806+ use_aampostincrement = false;
3807+
3808+ /* Try the same access but with postincrement disabled. */
3809+ command = access_memory_command (target , false, width , false, false);
3810+ result = riscv013_execute_abstract_command (target , command , & cmderr );
37793811 }
37803812
37813813 /* TODO:
@@ -3791,7 +3823,7 @@ read_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
37913823 return mem_access_result (MEM_ACCESS_FAILED_DM_ACCESS_FAILED );
37923824 buf_set_u64 (p , 0 , 8 * args .size , value );
37933825
3794- if (info -> has_aampostincrement == YNM_YES )
3826+ if (use_aampostincrement )
37953827 updateaddr = false;
37963828 p += args .size ;
37973829 }
@@ -3809,15 +3841,17 @@ write_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
38093841{
38103842 assert (riscv_mem_access_is_write (args ));
38113843
3812- RISCV013_INFO (info );
38133844 int result = ERROR_OK ;
3814- bool use_aampostincrement = info -> has_aampostincrement != YNM_NO ;
38153845
38163846 /* Convert the size (bytes) to width (bits) */
38173847 unsigned int width = args .size << 3 ;
38183848
38193849 /* Create the command (physical address, postincrement, write) */
3820- uint32_t command = access_memory_command (target , false, width , use_aampostincrement , true);
3850+ uint32_t command = access_memory_command (target , false, width ,
3851+ /* postincrement = */ true, /* is_write = */ true);
3852+ bool use_aampostincrement = !is_command_unsupported (target , command );
3853+ command = access_memory_command (target , false, width ,
3854+ /* postincrement = */ use_aampostincrement , /* is_write = */ true);
38213855
38223856 /* Execute the writes */
38233857 const uint8_t * p = args .write_buffer ;
@@ -3844,33 +3878,15 @@ write_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
38443878 /* Execute the command */
38453879 uint32_t cmderr ;
38463880 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- }
3881+ if (use_aampostincrement && result != ERROR_OK &&
3882+ cmderr == CMDERR_NOT_SUPPORTED ) {
3883+ LOG_TARGET_DEBUG (target , "Trying the same abstract memory "
3884+ "write command, but without aampostincrement" );
3885+ use_aampostincrement = false;
3886+
3887+ /* Try the same access but with postincrement disabled. */
3888+ command = access_memory_command (target , false, width , false, true);
3889+ result = riscv013_execute_abstract_command (target , command , & cmderr );
38743890 }
38753891
38763892 /* TODO:
@@ -3879,7 +3895,7 @@ write_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
38793895 if (result != ERROR_OK )
38803896 return mem_access_result (MEM_ACCESS_SKIPPED_ABSTRACT_ACCESS_CMDERR );
38813897
3882- if (info -> has_aampostincrement == YNM_YES )
3898+ if (use_aampostincrement )
38833899 updateaddr = false;
38843900 p += args .size ;
38853901 }
0 commit comments