1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2008 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
8 * Copyright (C) 2010 by Drasko DRASKOVIC *
9 * drasko.draskovic@gmail.com *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
25 ***************************************************************************/
32 #include "target_type.h"
33 #include "arm_opcodes.h"
35 #include "breakpoints.h"
38 #define _DEBUG_INSTRUCTION_EXECUTION_
41 #define NB_CACHE_WAYS 4
47 * flag to give info about cache manipulation during debug :
48 * "0" - cache lines are invalidated "on the fly", for affected addresses.
49 * This is prefered from performance point of view.
50 * "1" - cache is invalidated and switched off on debug_entry, and switched back on on restore.
51 * It is kept off during debugging.
53 static uint8_t arm946e_preserve_cache
;
55 int arm946e_post_debug_entry(struct target
*target
);
56 void arm946e_pre_restore_context(struct target
*target
);
57 static int arm946e_read_cp15(struct target
*target
, int reg_addr
, uint32_t *value
);
59 int arm946e_init_arch_info(struct target
*target
,
60 struct arm946e_common
*arm946e
,
63 struct arm7_9_common
*arm7_9
= &arm946e
->arm7_9_common
;
65 /* initialize arm7/arm9 specific info (including armv4_5) */
66 arm9tdmi_init_arch_info(target
, arm7_9
, tap
);
68 arm946e
->common_magic
= ARM946E_COMMON_MAGIC
;
71 * The ARM946E-S implements the ARMv5TE architecture which
72 * has the BKPT instruction, so we don't have to use a watchpoint comparator
74 arm7_9
->arm_bkpt
= ARMV5_BKPT(0x0);
75 arm7_9
->thumb_bkpt
= ARMV5_T_BKPT(0x0) & 0xffff;
78 arm7_9
->post_debug_entry
= arm946e_post_debug_entry
;
79 arm7_9
->pre_restore_context
= arm946e_pre_restore_context
;
82 * disabling linefills leads to lockups, so keep them enabled for now
83 * this doesn't affect correctness, but might affect timing issues, if
84 * important data is evicted from the cache during the debug session
86 arm946e_preserve_cache
= 0;
88 /* override hw single-step capability from ARM9TDMI */
89 /* arm7_9->has_single_step = 1; */
94 static int arm946e_target_create(struct target
*target
, Jim_Interp
*interp
)
96 struct arm946e_common
*arm946e
= calloc(1, sizeof(struct arm946e_common
));
98 arm946e_init_arch_info(target
, arm946e
, target
->tap
);
103 static int arm946e_verify_pointer(struct command_context
*cmd_ctx
,
104 struct arm946e_common
*arm946e
)
106 if (arm946e
->common_magic
!= ARM946E_COMMON_MAGIC
) {
107 command_print(cmd_ctx
, "target is not an ARM946");
108 return ERROR_TARGET_INVALID
;
114 * REVISIT: The "read_cp15" and "write_cp15" commands could hook up
115 * to eventual mrc() and mcr() routines ... the reg_addr values being
116 * constructed (for CP15 only) from Opcode_1, Opcode_2, and CRn values.
117 * See section 7.3 of the ARM946E-S TRM.
119 static int arm946e_read_cp15(struct target
*target
, int reg_addr
, uint32_t *value
)
121 int retval
= ERROR_OK
;
122 struct arm7_9_common
*arm7_9
= target_to_arm7_9(target
);
123 struct arm_jtag
*jtag_info
= &arm7_9
->jtag_info
;
124 struct scan_field fields
[3];
125 uint8_t reg_addr_buf
= reg_addr
& 0x3f;
126 uint8_t nr_w_buf
= 0;
128 retval
= arm_jtag_scann(jtag_info
, 0xf, TAP_IDLE
);
129 if (retval
!= ERROR_OK
)
131 retval
= arm_jtag_set_instr(jtag_info
, jtag_info
->intest_instr
, NULL
, TAP_IDLE
);
132 if (retval
!= ERROR_OK
)
135 fields
[0].num_bits
= 32;
136 /* REVISIT: table 7-2 shows that bits 31-31 need to be
137 * specified for accessing BIST registers ...
139 fields
[0].out_value
= NULL
;
140 fields
[0].in_value
= NULL
;
142 fields
[1].num_bits
= 6;
143 fields
[1].out_value
= ®_addr_buf
;
144 fields
[1].in_value
= NULL
;
146 fields
[2].num_bits
= 1;
147 fields
[2].out_value
= &nr_w_buf
;
148 fields
[2].in_value
= NULL
;
150 jtag_add_dr_scan(jtag_info
->tap
, 3, fields
, TAP_IDLE
);
152 fields
[0].in_value
= (uint8_t *)value
;
153 jtag_add_dr_scan(jtag_info
->tap
, 3, fields
, TAP_IDLE
);
155 jtag_add_callback(arm_le_to_h_u32
, (jtag_callback_data_t
)value
);
157 #ifdef _DEBUG_INSTRUCTION_EXECUTION_
158 LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr
, *value
);
161 retval
= jtag_execute_queue();
162 if (retval
!= ERROR_OK
)
168 int arm946e_write_cp15(struct target
*target
, int reg_addr
, uint32_t value
)
170 int retval
= ERROR_OK
;
171 struct arm7_9_common
*arm7_9
= target_to_arm7_9(target
);
172 struct arm_jtag
*jtag_info
= &arm7_9
->jtag_info
;
173 struct scan_field fields
[3];
174 uint8_t reg_addr_buf
= reg_addr
& 0x3f;
175 uint8_t nr_w_buf
= 1;
176 uint8_t value_buf
[4];
178 buf_set_u32(value_buf
, 0, 32, value
);
180 retval
= arm_jtag_scann(jtag_info
, 0xf, TAP_IDLE
);
181 if (retval
!= ERROR_OK
)
183 retval
= arm_jtag_set_instr(jtag_info
, jtag_info
->intest_instr
, NULL
, TAP_IDLE
);
184 if (retval
!= ERROR_OK
)
187 fields
[0].num_bits
= 32;
188 fields
[0].out_value
= value_buf
;
189 fields
[0].in_value
= NULL
;
191 fields
[1].num_bits
= 6;
192 fields
[1].out_value
= ®_addr_buf
;
193 fields
[1].in_value
= NULL
;
195 fields
[2].num_bits
= 1;
196 fields
[2].out_value
= &nr_w_buf
;
197 fields
[2].in_value
= NULL
;
199 jtag_add_dr_scan(jtag_info
->tap
, 3, fields
, TAP_IDLE
);
201 #ifdef _DEBUG_INSTRUCTION_EXECUTION_
202 LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr
, value
);
205 retval
= jtag_execute_queue();
206 if (retval
!= ERROR_OK
)
212 uint32_t arm946e_invalidate_whole_dcache(struct target
*target
)
217 uint32_t cp15_idx
, seg
, dtag
;
222 arm946e_read_cp15(target
, 0x01, (uint32_t *) &csize
);
224 csize
= (csize
>> 18) & 0x0F;
229 shift
= csize
- 0x3; /* Now 0 = 4KB, 1 = 8KB, ... */
231 /* Cache size, given in bytes */
232 csize
= 1 << (12 + shift
);
233 /* One line (index) is 32 bytes (8 words) long */
234 nb_idx
= (csize
/ 32); /* gives nb of lines (indexes) in the cache */
236 /* Loop for all segmentde (i.e. ways) */
237 for (seg
= 0; seg
< NB_CACHE_WAYS
; seg
++) {
238 /* Loop for all indexes */
239 for (idx
= 0; idx
< nb_idx
; idx
++) {
240 /* Form and write cp15 index (segment + line idx) */
241 cp15_idx
= seg
<< 30 | idx
<< 5;
242 retval
= arm946e_write_cp15(target
, 0x3a, cp15_idx
);
243 if (retval
!= ERROR_OK
) {
244 LOG_DEBUG("ERROR writing index");
249 arm946e_read_cp15(target
, 0x16, (uint32_t *) &dtag
);
251 /* Check cache line VALID bit */
252 if (!(dtag
>> 4 & 0x1))
255 /* Clean data cache line */
256 retval
= arm946e_write_cp15(target
, 0x35, 0x1);
257 if (retval
!= ERROR_OK
) {
258 LOG_DEBUG("ERROR cleaning cache line");
262 /* Flush data cache line */
263 retval
= arm946e_write_cp15(target
, 0x1a, 0x1);
264 if (retval
!= ERROR_OK
) {
265 LOG_DEBUG("ERROR flushing cache line");
274 uint32_t arm946e_invalidate_whole_icache(struct target
*target
)
278 LOG_DEBUG("FLUSHING I$");
281 * Invalidate (flush) I$
282 * mcr 15, 0, r0, cr7, cr5, {0}
284 retval
= arm946e_write_cp15(target
, 0x0f, 0x1);
285 if (retval
!= ERROR_OK
) {
286 LOG_DEBUG("ERROR flushing I$");
293 int arm946e_post_debug_entry(struct target
*target
)
295 uint32_t ctr_reg
= 0x0;
296 uint32_t retval
= ERROR_OK
;
298 /* See if CACHES are enabled, and save that info
299 * in the global vars, so that arm946e_pre_restore_context() can use them */
300 arm946e_read_cp15(target
, 0x02, (uint32_t *) &ctr_reg
);
301 dc
= (ctr_reg
>> 2) & 0x01;
302 ic
= (ctr_reg
>> 12) & 0x01;
304 if (arm946e_preserve_cache
) {
306 /* Clean and flush D$ */
307 arm946e_invalidate_whole_dcache(target
);
310 ctr_reg
&= ~(1 << 2);
315 arm946e_invalidate_whole_icache(target
);
318 ctr_reg
&= ~(1 << 12);
321 /* Write the new configuration */
322 retval
= arm946e_write_cp15(target
, 0x02, ctr_reg
);
323 if (retval
!= ERROR_OK
) {
324 LOG_DEBUG("ERROR disabling cache");
327 } /* if preserve_cache */
332 void arm946e_pre_restore_context(struct target
*target
)
334 uint32_t ctr_reg
= 0x0;
337 if (arm946e_preserve_cache
) {
338 /* Get the contents of the CTR reg */
339 arm946e_read_cp15(target
, 0x02, (uint32_t *) &ctr_reg
);
342 * Read-modify-write CP15 test state register
343 * to reenable I/D-cache linefills
355 /* Write the new configuration */
356 retval
= arm946e_write_cp15(target
, 0x02, ctr_reg
);
357 if (retval
!= ERROR_OK
)
358 LOG_DEBUG("ERROR enabling cache");
359 } /* if preserve_cache */
362 uint32_t arm946e_invalidate_dcache(struct target
*target
, uint32_t address
,
363 uint32_t size
, uint32_t count
)
365 uint32_t csize
= 0x0;
367 uint32_t cur_addr
= 0x0;
368 uint32_t cp15_idx
, set
, way
, dtag
;
372 for (i
= 0; i
< count
*size
; i
++) {
373 cur_addr
= address
+ i
;
376 arm946e_read_cp15(target
, 0x01, (uint32_t *) &csize
);
378 /* Conclude cache size to find number of lines */
379 csize
= (csize
>> 18) & 0x0F;
384 shift
= csize
- 0x3; /* Now 0 = 4KB, 1 = 8KB, ... */
386 csize
= 1 << (12 + shift
);
388 set
= (cur_addr
>> 5) & 0xff; /* set field is 8 bits long */
390 for (way
= 0; way
< NB_CACHE_WAYS
; way
++) {
392 * Find if the affected address is kept in the cache.
393 * Because JTAG Scan Chain 15 offers limited approach,
394 * we have to loop through all cache ways (segments) and
395 * read cache tags, then compare them with with address.
398 /* Form and write cp15 index (segment + line idx) */
399 cp15_idx
= way
<< 30 | set
<< 5;
400 retval
= arm946e_write_cp15(target
, 0x3a, cp15_idx
);
401 if (retval
!= ERROR_OK
) {
402 LOG_DEBUG("ERROR writing index");
407 arm946e_read_cp15(target
, 0x16, (uint32_t *) &dtag
);
409 /* Check cache line VALID bit */
410 if (!(dtag
>> 4 & 0x1))
413 /* If line is valid and corresponds to affected address - invalidate it */
414 if (dtag
>> 5 == cur_addr
>> 5) {
415 /* Clean data cache line */
416 retval
= arm946e_write_cp15(target
, 0x35, 0x1);
417 if (retval
!= ERROR_OK
) {
418 LOG_DEBUG("ERROR cleaning cache line");
422 /* Flush data cache line */
423 retval
= arm946e_write_cp15(target
, 0x1c, 0x1);
424 if (retval
!= ERROR_OK
) {
425 LOG_DEBUG("ERROR flushing cache line");
431 } /* loop through all 4 ways */
432 } /* loop through all addresses */
437 uint32_t arm946e_invalidate_icache(struct target
*target
, uint32_t address
,
438 uint32_t size
, uint32_t count
)
440 uint32_t cur_addr
= 0x0;
441 uint32_t cp15_idx
, set
, way
, itag
;
445 for (i
= 0; i
< count
*size
; i
++) {
446 cur_addr
= address
+ i
;
448 set
= (cur_addr
>> 5) & 0xff; /* set field is 8 bits long */
450 for (way
= 0; way
< NB_CACHE_WAYS
; way
++) {
451 /* Form and write cp15 index (segment + line idx) */
452 cp15_idx
= way
<< 30 | set
<< 5;
453 retval
= arm946e_write_cp15(target
, 0x3a, cp15_idx
);
454 if (retval
!= ERROR_OK
) {
455 LOG_DEBUG("ERROR writing index");
460 arm946e_read_cp15(target
, 0x17, (uint32_t *) &itag
);
462 /* Check cache line VALID bit */
463 if (!(itag
>> 4 & 0x1))
466 /* If line is valid and corresponds to affected address - invalidate it */
467 if (itag
>> 5 == cur_addr
>> 5) {
469 retval
= arm946e_write_cp15(target
, 0x1d, 0x0);
470 if (retval
!= ERROR_OK
) {
471 LOG_DEBUG("ERROR flushing cache line");
483 /** Writes a buffer, in the specified word size, with current MMU settings. */
484 int arm946e_write_memory(struct target
*target
, uint32_t address
,
485 uint32_t size
, uint32_t count
, const uint8_t *buffer
)
491 /* Invalidate D$ if it is ON */
492 if (!arm946e_preserve_cache
&& dc
== 1)
493 arm946e_invalidate_dcache(target
, address
, size
, count
);
498 retval
= arm7_9_write_memory(target
, address
, size
, count
, buffer
);
499 if (retval
!= ERROR_OK
)
503 * Invalidate I$ if it is ON.
505 * D$ has been cleaned and flushed before mem write thus forcing it to behave like write-through,
506 * because arm7_9_write_memory() has seen non-valid bit in D$
507 * and wrote data into physical RAM (without touching or allocating the cache line).
508 * From ARM946ES Technical Reference Manual we can see that it uses "allocate on read-miss"
509 * policy for both I$ and D$ (Chapter 3.2 and 3.3)
512 * "ARM system developer's guide: designing and optimizing system software" by
513 * Andrew N. Sloss, Dominic Symes and Chris Wright,
514 * Chapter 12.3.3 Allocating Policy on a Cache Miss :
515 * A read allocate on cache miss policy allocates a cache line only during a read from main memory.
516 * If the victim cache line contains valid data, then it is written to main memory before the cache line
517 * is filled with new data.
518 * Under this strategy, a write of new data to memory does not update the contents of the cache memory
519 * unless a cache line was allocated on a previous read from main memory.
520 * If the cache line contains valid data, then the write updates the cache and may update the main memory if
521 * the cache write policy is write-through.
522 * If the data is not in the cache, the controller writes to main memory only.
524 if (!arm946e_preserve_cache
&& ic
== 1)
525 arm946e_invalidate_icache(target
, address
, size
, count
);
531 int arm946e_read_memory(struct target
*target
, uint32_t address
,
532 uint32_t size
, uint32_t count
, uint8_t *buffer
)
538 retval
= arm7_9_read_memory(target
, address
, size
, count
, buffer
);
539 if (retval
!= ERROR_OK
)
546 COMMAND_HANDLER(arm946e_handle_cp15_command
)
549 struct target
*target
= get_current_target(CMD_CTX
);
550 struct arm946e_common
*arm946e
= target_to_arm946(target
);
552 retval
= arm946e_verify_pointer(CMD_CTX
, arm946e
);
553 if (retval
!= ERROR_OK
)
556 if (target
->state
!= TARGET_HALTED
) {
557 command_print(CMD_CTX
, "target must be stopped for \"%s\" command", CMD_NAME
);
561 /* one or more argument, access a single register (write if second argument is given */
564 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], address
);
568 retval
= arm946e_read_cp15(target
, address
, &value
);
569 if (retval
!= ERROR_OK
) {
570 command_print(CMD_CTX
, "couldn't access reg %" PRIi32
, address
);
573 retval
= jtag_execute_queue();
574 if (retval
!= ERROR_OK
)
577 command_print(CMD_CTX
, "%" PRIi32
": %8.8" PRIx32
, address
, value
);
578 } else if (CMD_ARGC
== 2) {
580 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], value
);
581 retval
= arm946e_write_cp15(target
, address
, value
);
582 if (retval
!= ERROR_OK
) {
583 command_print(CMD_CTX
, "couldn't access reg %" PRIi32
, address
);
586 command_print(CMD_CTX
, "%" PRIi32
": %8.8" PRIx32
, address
, value
);
593 static const struct command_registration arm946e_exec_command_handlers
[] = {
596 .handler
= arm946e_handle_cp15_command
,
597 .mode
= COMMAND_EXEC
,
598 .usage
= "regnum [value]",
599 .help
= "display/modify cp15 register",
601 COMMAND_REGISTRATION_DONE
604 const struct command_registration arm946e_command_handlers
[] = {
606 .chain
= arm9tdmi_command_handlers
,
611 .help
= "arm946e command group",
613 .chain
= arm946e_exec_command_handlers
,
615 COMMAND_REGISTRATION_DONE
618 /** Holds methods for ARM946 targets. */
619 struct target_type arm946e_target
= {
623 .arch_state
= arm_arch_state
,
625 .target_request_data
= arm7_9_target_request_data
,
628 .resume
= arm7_9_resume
,
631 .assert_reset
= arm7_9_assert_reset
,
632 .deassert_reset
= arm7_9_deassert_reset
,
633 .soft_reset_halt
= arm7_9_soft_reset_halt
,
635 .get_gdb_reg_list
= arm_get_gdb_reg_list
,
637 /* .read_memory = arm7_9_read_memory, */
638 /* .write_memory = arm7_9_write_memory, */
639 .read_memory
= arm946e_read_memory
,
640 .write_memory
= arm946e_write_memory
,
642 .bulk_write_memory
= arm7_9_bulk_write_memory
,
644 .checksum_memory
= arm_checksum_memory
,
645 .blank_check_memory
= arm_blank_check_memory
,
647 .run_algorithm
= armv4_5_run_algorithm
,
649 .add_breakpoint
= arm7_9_add_breakpoint
,
650 .remove_breakpoint
= arm7_9_remove_breakpoint
,
651 /* .add_breakpoint = arm946e_add_breakpoint, */
652 /* .remove_breakpoint = arm946e_remove_breakpoint, */
654 .add_watchpoint
= arm7_9_add_watchpoint
,
655 .remove_watchpoint
= arm7_9_remove_watchpoint
,
657 .commands
= arm946e_command_handlers
,
658 .target_create
= arm946e_target_create
,
659 .init_target
= arm9tdmi_init_target
,
660 .examine
= arm7_9_examine
,
661 .check_reset
= arm7_9_check_reset
,
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)