- split fileio handling into fileio part and image handling
authordrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Tue, 29 May 2007 11:23:42 +0000 (11:23 +0000)
committerdrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Tue, 29 May 2007 11:23:42 +0000 (11:23 +0000)
- reworked etm/etb into a generic etm part with trace capture drivers (currently only etb supported)
- added XScale debug handler binary to repository
- added Thumb disassembling (thanks to Vincent Palatin for this patch)
- added support for non-CFI compatible flashes to cfi driver (currently only SST39VFxxx devices supported)
This checkin is experimental, not suitable for general use

git-svn-id: svn://svn.berlios.de/openocd/trunk@155 b42882b7-edfa-0310-969c-e2dbd0fdcd60

26 files changed:
src/flash/Makefile.am
src/flash/cfi.c
src/flash/cfi.h
src/flash/flash.c
src/flash/nand.c
src/flash/non_cfi.c [new file with mode: 0644]
src/flash/non_cfi.h [new file with mode: 0644]
src/helper/fileio.c
src/helper/fileio.h
src/jtag/jtag.c
src/openocd.c
src/target/Makefile.am
src/target/arm7_9_common.c
src/target/arm7_9_common.h
src/target/arm7tdmi.c
src/target/arm9tdmi.c
src/target/arm_disassembler.c
src/target/arm_disassembler.h
src/target/arm_simulator.c
src/target/armv4_5.h
src/target/etb.c
src/target/etb.h
src/target/etm.c
src/target/etm.h
src/target/target.c
src/target/xscale/debug_handler.bin [new file with mode: 0755]

index 6368f626ea2f91f5b0d79ed63698bbc5400f5d9f..8f99e05e98119f31d8472f7c22dc3526be260e05 100644 (file)
@@ -1,5 +1,5 @@
 INCLUDES = -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target $(all_includes)
 METASOURCES = AUTO
 noinst_LIBRARIES = libflash.a
-libflash_a_SOURCES = flash.c lpc2000.c cfi.c at91sam7.c str7x.c str9x.c nand.c lpc3180_nand_controller.c
-noinst_HEADERS = flash.h lpc2000.h cfi.h at91sam7.h str7x.h str9x.h nand.h lpc3180_nand_controller.h
+libflash_a_SOURCES = flash.c lpc2000.c cfi.c non_cfi.c at91sam7.c str7x.c str9x.c nand.c lpc3180_nand_controller.c
+noinst_HEADERS = flash.h lpc2000.h cfi.h non_cfi.h at91sam7.h str7x.h str9x.h nand.h lpc3180_nand_controller.h
index 83a8120a4d897bce69b16a9727fca3e7517811d2..69494b5f94b339ec7c3694c81bec4100dcd4a4dc 100644 (file)
@@ -66,17 +66,33 @@ flash_driver_t cfi_flash =
        .info = cfi_info
 };
 
+cfi_unlock_addresses_t cfi_unlock_addresses[] =
+{
+       [CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa },
+       [CFI_UNLOCK_5555_2AAA] = { .unlock1 = 0x5555, .unlock2 = 0x2aaa },
+};
+
 /* CFI fixups foward declarations */
+void cfi_fixup_non_cfi(flash_bank_t *flash, void *param);
 void cfi_fixup_0002_erase_regions(flash_bank_t *flash, void *param);
+void cfi_fixup_0002_unlock_addresses(flash_bank_t *flash, void *param);
 void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *flash, void *param);
 
 /* fixup after identifying JEDEC manufactuer and ID */
 cfi_fixup_t cfi_jedec_fixups[] = {
+       {CFI_MFR_SST, 0x00D4, cfi_fixup_non_cfi, NULL},
+       {CFI_MFR_SST, 0x00D5, cfi_fixup_non_cfi, NULL},
+       {CFI_MFR_SST, 0x00D6, cfi_fixup_non_cfi, NULL},
+       {CFI_MFR_SST, 0x00D7, cfi_fixup_non_cfi, NULL},
        {0, 0, NULL, NULL}
 };
 
 /* fixup after reading cmdset 0002 primary query table */
 cfi_fixup_t cfi_0002_fixups[] = {
+       {CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+       {CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+       {CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+       {CFI_MFR_SST, 0x00D7, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
        {CFI_MFR_ATMEL, 0x00C8, cfi_fixup_atmel_reversed_erase_regions, NULL},
        {CFI_MFR_ANY, CFI_ID_ANY, cfi_fixup_0002_erase_regions, NULL},
        {0, 0, NULL, NULL}
@@ -421,6 +437,11 @@ int cfi_read_spansion_pri_ext(flash_bank_t *bank)
        
        DEBUG("WP# protection 0x%x", pri_ext->TopBottom);
        
+       /* default values for implementation specific workarounds */
+       pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1;
+       pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2;
+       pri_ext->_reversed_geometry = 0;
+       
        return ERROR_OK;
 }
 
@@ -594,7 +615,9 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **
        cfi_info = malloc(sizeof(cfi_flash_bank_t));
        bank->driver_priv = cfi_info;
        
-       cfi_info->x16_as_x8 = 1;
+       cfi_info->x16_as_x8 = 0;
+       cfi_info->jedec_probe = 0;
+       cfi_info->not_cfi = 0;
        
        cfi_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
        if (!cfi_info->target)
@@ -605,9 +628,13 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **
 
        for (i = 6; i < argc; i++)
        {
-               if (strcmp(args[i], "x16_as_x8") != 0)
+               if (strcmp(args[i], "x16_as_x8") == 0)
                {
-                       cfi_info->x16_as_x8 = 0;
+                       cfi_info->x16_as_x8 = 1;
+               }
+               else if (strcmp(args[i], "jedec_probe") == 0)
+               {
+                       cfi_info->jedec_probe = 1;
                }
        }
                
@@ -665,19 +692,19 @@ int cfi_spansion_erase(struct flash_bank_s *bank, int first, int last)
        for (i = first; i <= last; i++)
        {
                cfi_command(bank, 0xaa, command);
-               target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command);
+               target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
                        
                cfi_command(bank, 0x55, command);
-               target->type->write_memory(target, flash_address(bank, 0, 0x2aa), bank->bus_width, 1, command);
+               target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command);
                
                cfi_command(bank, 0x80, command);
-               target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command);
+               target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
 
                cfi_command(bank, 0xaa, command);
-               target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command);
+               target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
                        
                cfi_command(bank, 0x55, command);
-               target->type->write_memory(target, flash_address(bank, 0, 0x2aa), bank->bus_width, 1, command);
+               target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command);
                
                cfi_command(bank, 0x30, command);
                target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
@@ -891,9 +918,10 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
        armv4_5_algorithm_t armv4_5_info;
        working_area_t *source;
        u32 buffer_size = 32768;
-       u8 write_command[CFI_MAX_BUS_WIDTH];
-       u8 busy_pattern[CFI_MAX_BUS_WIDTH];
-       u8 error_pattern[CFI_MAX_BUS_WIDTH];
+       u8 write_command_buf[CFI_MAX_BUS_WIDTH];
+       u8 busy_pattern_buf[CFI_MAX_BUS_WIDTH];
+       u8 error_pattern_buf[CFI_MAX_BUS_WIDTH];
+       u32 write_command_val, busy_pattern_val, error_pattern_val;
        int retval;
 
        /* algorithm register usage:
@@ -906,7 +934,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
         * r6: error test pattern
         */
         
-       u32 word_32_code[] = {
+       static const u32 word_32_code[] = {
                0xe4904004,   /* loop:  ldr r4, [r0], #4 */
                0xe5813000,   /*                str r3, [r1] */
                0xe5814000,   /*                str r4, [r1] */
@@ -923,7 +951,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
                0xeafffffe,   /* done:  b -2 */
        };
        
-       u32 word_16_code[] = {
+       static const u32 word_16_code[] = {
                0xe0d040b2,   /* loop:  ldrh r4, [r0], #2 */
                0xe1c130b0,   /*                strh r3, [r1] */
                0xe1c140b0,   /*                strh r4, [r1] */
@@ -940,7 +968,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
                0xeafffffe,   /* done:  b -2 */
        };
        
-       u32 word_8_code[] = {
+       static const u32 word_8_code[] = {
                0xe4d04001,   /* loop:  ldrb r4, [r0], #1 */
                0xe5c13000,   /*                strb r3, [r1] */
                0xe5c14000,   /*                strb r4, [r1] */
@@ -966,29 +994,37 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
        /* flash write code */
        if (!cfi_info->write_algorithm)
        {
+               u8 write_code_buf[14 * 4];
+               int i;
+                       
                if (target_alloc_working_area(target, 4 * 14, &cfi_info->write_algorithm) != ERROR_OK)
                {
                        WARNING("no working area available, can't do block memory writes");
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                };
-                       
+               
                /* write algorithm code to working area */
                if (bank->bus_width == 1)
                {
-                       target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_8_code);
+                       for (i = 0; i < 14; i++)
+                               target_buffer_set_u32(target, write_code_buf + (i*4), word_8_code[i]);
                }
                else if (bank->bus_width == 2)
                {
-                       target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_16_code);
+                       for (i = 0; i < 14; i++)
+                               target_buffer_set_u32(target, write_code_buf + (i*4), word_16_code[i]);
                }       
                else if (bank->bus_width == 4)
                {
-                       target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_32_code);
+                       for (i = 0; i < 14; i++)
+                               target_buffer_set_u32(target, write_code_buf + (i*4), word_32_code[i]);
                }
                else
                {
                        return ERROR_FLASH_OPERATION_FAILED;
                }
+
+               target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, write_code_buf);
        }
        
        while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
@@ -1013,10 +1049,30 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
        init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);
        init_reg_param(&reg_params[6], "r6", 32, PARAM_OUT);
 
-       cfi_command(bank, 0x40, write_command);
-       cfi_command(bank, 0x80, busy_pattern);
-       cfi_command(bank, 0x7e, error_pattern);
-
+       /* prepare command and status register patterns */
+       cfi_command(bank, 0x40, write_command_buf);
+       cfi_command(bank, 0x80, busy_pattern_buf);
+       cfi_command(bank, 0x7e, error_pattern_buf);
+       
+       if (bank->bus_width == 1)
+       {
+               write_command_val = write_command_buf[0];
+               busy_pattern_val = busy_pattern_buf[0];
+               error_pattern_val = error_pattern_buf[0];
+       }
+       else if (bank->bus_width == 2)
+       {
+               write_command_val = target_buffer_get_u16(target, write_command_buf);
+               busy_pattern_val = target_buffer_get_u16(target, busy_pattern_buf);
+               error_pattern_val = target_buffer_get_u16(target, error_pattern_buf);
+       }
+       else if (bank->bus_width == 4)
+       {
+               write_command_val = target_buffer_get_u32(target, write_command_buf);
+               busy_pattern_val = target_buffer_get_u32(target, busy_pattern_buf);
+               error_pattern_val = target_buffer_get_u32(target, error_pattern_buf);
+       }
+       
        while (count > 0)
        {
                u32 thisrun_count = (count > buffer_size) ? buffer_size : count;
@@ -1026,11 +1082,9 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
                buf_set_u32(reg_params[0].value, 0, 32, source->address);
                buf_set_u32(reg_params[1].value, 0, 32, address);
                buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
-               buf_set_u32(reg_params[3].value, 0, 32, target_buffer_get_u32(target, write_command));
-               buf_set_u32(reg_params[5].value, 0, 32, target_buffer_get_u32(target, busy_pattern));
-               buf_set_u32(reg_params[6].value, 0, 32, target_buffer_get_u32(target, error_pattern));
-               buf_set_u32(reg_params[5].value, 0, 32, buf_get_u32(busy_pattern, 0, 32));
-               buf_set_u32(reg_params[6].value, 0, 32, buf_get_u32(error_pattern, 0, 32));
+               buf_set_u32(reg_params[3].value, 0, 32, write_command_val);
+               buf_set_u32(reg_params[5].value, 0, 32, busy_pattern_val);
+               buf_set_u32(reg_params[6].value, 0, 32, error_pattern_val);
        
                if ((retval = target->type->run_algorithm(target, 0, NULL, 7, reg_params, cfi_info->write_algorithm->address, cfi_info->write_algorithm->address + (13 * 4), 10000, &armv4_5_info)) != ERROR_OK)
                {
@@ -1038,7 +1092,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
                        return ERROR_FLASH_OPERATION_FAILED;
                }
        
-               if (buf_get_u32(reg_params[4].value, 0, 32) & target_buffer_get_u32(target, error_pattern))
+               if (buf_get_u32(reg_params[4].value, 0, 32) & error_pattern_val)
                {
                        /* read status register (outputs debug inforation) */
                        cfi_intel_wait_status_busy(bank, 100);
@@ -1078,8 +1132,6 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
        int i;
        int retval;
        int exit_code = ERROR_OK;
-       int code_size;
-       void *code_p;
 
        /* input parameters - */
        /*      R0 = source address */
@@ -1095,8 +1147,8 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
        /* unlock registers - */
        /*  R8 = unlock1_addr */
        /*  R9 = unlock1_cmd */
-       /*  R10 = unlock1_addr */
-       /*  R11 = unlock1_cmd */
+       /*  R10 = unlock2_addr */
+       /*  R11 = unlock2_cmd */
 
        u32 word_32_code[] = {
                                                /* 00008100 <sp_32_code>:               */
@@ -1207,36 +1259,47 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
        /* flash write code */
        if (!cfi_info->write_algorithm)
        {
-               /* write algorithm code to working area */
+               u8 *code_p;
+
+               /* convert bus-width dependent algorithm code to correct endiannes */
                if (bank->bus_width == 1)
                {
-                       code_size = sizeof(word_8_code);
-                       code_p = word_8_code;
+                       code_p = malloc(24 * 4);
+                       
+                       for (i = 0; i < 24; i++)
+                               target_buffer_set_u32(target, code_p + (i*4), word_8_code[i]);
                }
                else if (bank->bus_width == 2)
                {
-                       code_size = sizeof(word_16_code);
-                       code_p = word_16_code;
-               }
+                       code_p = malloc(24 * 4);
+                       
+                       for (i = 0; i < 24; i++)
+                               target_buffer_set_u32(target, code_p + (i*4), word_16_code[i]);
+               }       
                else if (bank->bus_width == 4)
                {
-                       code_size = sizeof(word_32_code);
-                       code_p = word_32_code;
+                       code_p = malloc(24 * 4);
+                       
+                       for (i = 0; i < 24; i++)
+                               target_buffer_set_u32(target, code_p + (i*4), word_32_code[i]);
                }
                else
                {
                        return ERROR_FLASH_OPERATION_FAILED;
                }
-
-               if (target_alloc_working_area(target, code_size,
-                                                     &cfi_info->write_algorithm) != ERROR_OK)
+               
+               /* allocate working area */
+               if (target_alloc_working_area(target, 24 * 4,
+                       &cfi_info->write_algorithm) != ERROR_OK)
                {
                        WARNING("no working area available, can't do block memory writes");
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
-                       
-               target_write_buffer(target, cfi_info->write_algorithm->address, 
-                                   code_size, code_p);
+               
+               /* write algorithm code to working area */
+               target_write_buffer(target, cfi_info->write_algorithm->address, 24 * 4, code_p);
+               
+               free(code_p);
        }
        
        while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
@@ -1277,14 +1340,14 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
                buf_set_u32(reg_params[3].value, 0, 32, buf_get_u32(write_command, 0, 32));
                cfi_command(bank, 0x80, write_command);
                buf_set_u32(reg_params[4].value, 0, 32, buf_get_u32(write_command, 0, 32));
-               buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, 0x555));
+               buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1));
                buf_set_u32(reg_params[7].value, 0, 32, 0xaa);
-               buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, 0xaaa));
+               buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2));
                buf_set_u32(reg_params[9].value, 0, 32, 0x55);
        
                retval = target->type->run_algorithm(target, 0, NULL, 10, reg_params, 
                                                     cfi_info->write_algorithm->address, 
-                                                    cfi_info->write_algorithm->address + (code_size - 4), 
+                                                    cfi_info->write_algorithm->address + ((24 * 4) - 4), 
                                                     10000, &armv4_5_info);
 
                status = buf_get_u32(reg_params[5].value, 0, 32);
@@ -1301,6 +1364,8 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
                count -= thisrun_count;
        }
        
+       target_free_working_area(target, source);
+       
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
        destroy_reg_param(&reg_params[2]);
@@ -1347,13 +1412,13 @@ int cfi_spansion_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
        u8 command[8];
        
        cfi_command(bank, 0xaa, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command);
+       target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
        
        cfi_command(bank, 0x55, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x2aa), bank->bus_width, 1, command);
+       target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command);
        
        cfi_command(bank, 0xa0, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command);
+       target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
 
        target->type->write_memory(target, address, bank->bus_width, 1, word);
        
@@ -1554,6 +1619,16 @@ void cfi_fixup_0002_erase_regions(flash_bank_t *bank, void *param)
        }
 }
 
+void cfi_fixup_0002_unlock_addresses(flash_bank_t *bank, void *param)
+{
+       cfi_flash_bank_t *cfi_info = bank->driver_priv;
+       cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
+       cfi_unlock_addresses_t *unlock_addresses = param;
+       
+       pri_ext->_unlock1 = unlock_addresses->unlock1;
+       pri_ext->_unlock2 = unlock_addresses->unlock2;
+}
+
 int cfi_probe(struct flash_bank_s *bank)
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
@@ -1563,14 +1638,25 @@ int cfi_probe(struct flash_bank_s *bank)
        int i;
        int sector = 0;
        u32 offset = 0;
-               
+       u32 unlock1 = 0x555;
+       u32 unlock2 = 0x2aa;
+       
+       /* JEDEC standard JESD21C uses 0x5555 and 0x2aaa as unlock addresses,
+        * while CFI compatible AMD/Spansion flashes use 0x555 and 0x2aa
+        */
+       if (cfi_info->jedec_probe)
+       {
+               unlock1 = 0x5555;
+               unlock2 = 0x2aaa;
+       }
+       
        /* switch to read identifier codes mode ("AUTOSELECT") */
        cfi_command(bank, 0xaa, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command);
+       target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command);
        cfi_command(bank, 0x55, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x2aa), bank->bus_width, 1, command);
+       target->type->write_memory(target, flash_address(bank, 0, unlock2), bank->bus_width, 1, command);
        cfi_command(bank, 0x90, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command);
+       target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command);
 
        if (bank->chip_width == 1)
        {
@@ -1594,105 +1680,132 @@ int cfi_probe(struct flash_bank_s *bank)
 
        cfi_fixup(bank, cfi_jedec_fixups);
 
-       /* enter CFI query mode
-        * according to JEDEC Standard No. 68.01,
-        * a single bus sequence with address = 0x55, data = 0x98 should put
-        * the device into CFI query mode.
-        * 
-        * SST flashes clearly violate this, and we will consider them incompatbile for now
+       /* query only if this is a CFI compatible flash,
+        * otherwise the relevant info has already been filled in
         */
-       cfi_command(bank, 0x98, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
-       
-       cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
-       cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
-       cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
-       
-       DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]);
-       
-       if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
+       if (cfi_info->not_cfi == 0)
        {
+               /* enter CFI query mode
+                * according to JEDEC Standard No. 68.01,
+                * a single bus sequence with address = 0x55, data = 0x98 should put
+                * the device into CFI query mode.
+                * 
+                * SST flashes clearly violate this, and we will consider them incompatbile for now
+                */
+               cfi_command(bank, 0x98, command);
+               target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
+               
+               cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
+               cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
+               cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
+               
+               DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]);
+               
+               if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
+               {
+                       cfi_command(bank, 0xf0, command);
+                       target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+                       cfi_command(bank, 0xff, command);
+                       target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+                       return ERROR_FLASH_BANK_INVALID;
+               }
+               
+               cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13);
+               cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);
+               cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17);
+               cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19);
+               
+               DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
+               
+               cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b);
+               cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c);
+               cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d);
+               cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e);
+               cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f);
+               cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20);
+               cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21);
+               cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22);
+               cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23);
+               cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24);
+               cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25);
+               cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26);
+               
+               DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x",
+                       (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
+                       (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
+                       (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
+                       (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
+               DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
+                       1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
+               DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
+                       (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
+                       (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
+                       (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
+               
+               cfi_info->dev_size = cfi_query_u8(bank, 0, 0x27);
+               cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28);
+               cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a);
+               cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c);
+               
+               DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size));
+               
+               if (((1 << cfi_info->dev_size) * bank->bus_width / bank->chip_width) != bank->size)
+               {
+                       WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size);
+               }
+               
+               if (cfi_info->num_erase_regions)
+               {
+                       cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions);
+                       for (i = 0; i < cfi_info->num_erase_regions; i++)
+                       {
+                               cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i));
+                               DEBUG("erase region[%i]: %i blocks of size 0x%x", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256);
+                       }
+               }
+               else
+               {
+                       cfi_info->erase_region_info = NULL;
+               }
+                       
+               /* We need to read the primary algorithm extended query table before calculating
+                * the sector layout to be able to apply fixups
+                */     
+               switch(cfi_info->pri_id)
+               {
+                       /* Intel command set (standard and extended) */
+                       case 0x0001:
+                       case 0x0003:
+                               cfi_read_intel_pri_ext(bank);
+                               break;
+                       /* AMD/Spansion, Atmel, ... command set */
+                       case 0x0002:
+                               cfi_read_0002_pri_ext(bank);
+                               break;
+                       default:
+                               ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+                               break;
+               }
+               
+               /* return to read array mode
+                * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command
+                */
                cfi_command(bank, 0xf0, command);
                target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
                cfi_command(bank, 0xff, command);
                target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-               return ERROR_FLASH_BANK_INVALID;
-       }
-       
-       cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13);
-       cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);
-       cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17);
-       cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19);
-       
-       DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
-       
-       cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b);
-       cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c);
-       cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d);
-       cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e);
-       cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f);
-       cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20);
-       cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21);
-       cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22);
-       cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23);
-       cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24);
-       cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25);
-       cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26);
-       
-       DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x",
-               (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
-               (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
-               (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
-               (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
-       DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
-               1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
-       DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
-               (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
-               (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
-               (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
-       
-       cfi_info->dev_size = cfi_query_u8(bank, 0, 0x27);
-       cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28);
-       cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a);
-       cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c);
-       
-       DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size));
-       
-       if (((1 << cfi_info->dev_size) * bank->bus_width / bank->chip_width) != bank->size)
-       {
-               WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size);
        }
        
-       if (cfi_info->num_erase_regions)
-       {
-               cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions);
-               for (i = 0; i < cfi_info->num_erase_regions; i++)
-               {
-                       cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i));
-                       DEBUG("erase region[%i]: %i blocks of size 0x%x", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256);
-                       
-                       num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
-               }
-       }
-       else
-       {
-               cfi_info->erase_region_info = NULL;
-       }
-               
-       /* We need to read the primary algorithm extended query table before calculating
-        * the sector layout to be able to apply fixups
-        */     
+       /* apply fixups depending on the primary command set */
        switch(cfi_info->pri_id)
        {
                /* Intel command set (standard and extended) */
                case 0x0001:
                case 0x0003:
-                       cfi_read_intel_pri_ext(bank);
                        cfi_fixup(bank, cfi_0001_fixups);
                        break;
                /* AMD/Spansion, Atmel, ... command set */
-        case 0x0002:
-                       cfi_read_0002_pri_ext(bank);
+               case 0x0002:
                        cfi_fixup(bank, cfi_0002_fixups);
                        break;
                default:
@@ -1713,6 +1826,11 @@ int cfi_probe(struct flash_bank_s *bank)
        }
        else
        {
+               for (i = 0; i < cfi_info->num_erase_regions; i++)
+               {
+                       num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
+               }
+               
                bank->num_sectors = num_sectors;
                bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
                
@@ -1731,14 +1849,6 @@ int cfi_probe(struct flash_bank_s *bank)
                }
        }
        
-       /* return to read array mode
-        * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command
-        */
-       cfi_command(bank, 0xf0, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-       cfi_command(bank, 0xff, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-       
        return ERROR_OK;
 }
 
@@ -1893,13 +2003,13 @@ int cfi_spansion_protect_check(struct flash_bank_s *bank)
        int i;
        
        cfi_command(bank, 0xaa, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command);
+       target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
        
        cfi_command(bank, 0x55, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x2aa), bank->bus_width, 1, command);
+       target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command);
        
        cfi_command(bank, 0x90, command);
-       target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command);
+       target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
 
        for (i = 0; i < bank->num_sectors; i++)
        {
index fa53f0d81dfe2b77c5f2bfd78344c5e4c7369bee..b4e3ab226c8ebdf7bc2d634e55f115260872e809 100644 (file)
@@ -30,10 +30,12 @@ typedef struct cfi_flash_bank_s
        working_area_t *erase_check_algorithm;
        
        int x16_as_x8;
+       int jedec_probe;
+       int not_cfi;
        
        u16 manufacturer;
        u16 device_id;
-               
+       
        char qry[3];
        
        /* identification string */
@@ -108,6 +110,8 @@ typedef struct cfi_spansion_pri_ext_s
        u8  VppMax;
        u8  TopBottom;
        int _reversed_geometry;
+       u32 _unlock1;
+       u32 _unlock2;
 } cfi_spansion_pri_ext_t;
 
 /* Atmel primary extended query table as defined for and used by
@@ -124,6 +128,17 @@ typedef struct cfi_atmel_pri_ext_s
        u8 page_mode;
 } cfi_atmel_pri_ext_t;
 
+enum {
+       CFI_UNLOCK_555_2AA,
+       CFI_UNLOCK_5555_2AAA,
+};
+
+typedef struct cfi_unlock_addresses_s
+{
+       u32 unlock1;
+       u32 unlock2;
+} cfi_unlock_addresses_t;
+
 typedef struct cfi_fixup_s
 {
        u16 mfr;
@@ -135,6 +150,7 @@ typedef struct cfi_fixup_s
 #define CFI_MFR_AMD            0x0001
 #define CFI_MFR_ATMEL  0x001F
 #define CFI_MFR_ST             0x0020  /* STMicroelectronics */
+#define CFI_MFR_SST            0x00BF
 
 #define CFI_MFR_ANY            0xffff
 #define CFI_ID_ANY             0xffff
index f5c83f80c43ffdc43cdd8e6cd60758f1af0a63ab..6af29825ca293b17b85e9c1a465551e54df720b1 100644 (file)
@@ -35,6 +35,7 @@
 #include <errno.h>
 
 #include <fileio.h>
+#include <image.h>
 
 /* command handlers */
 int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -493,9 +494,7 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
        u8 *buffer;
        u32 buf_cnt;
 
-       fileio_t file;
-       fileio_image_t image_info;
-       enum fileio_sec_type sec_type;
+       image_t image;
        
        duration_t duration;
        char *duration_text;
@@ -511,7 +510,12 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
        
        duration_start_measure(&duration);
        
-       fileio_identify_image_type(&sec_type, (argc == 4) ? args[3] : NULL);
+       identify_image_type(&image.type, (argc == 4) ? args[3] : NULL);
+
+       image.base_address_set = 1;
+       image.base_address = strtoul(args[1], NULL, 0);
+       
+       image.start_address_set = 0;
        
        offset = strtoul(args[2], NULL, 0);
        p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
@@ -521,20 +525,16 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
                return ERROR_OK;
        }
        
-       image_info.base_address = strtoul(args[2], NULL, 0);
-       image_info.has_start_address = 0;
-
-       if (fileio_open(&file, args[1], FILEIO_READ, 
-               FILEIO_IMAGE, &image_info, sec_type) != ERROR_OK)
+       if (image_open(&image, args[1], FILEIO_READ) != ERROR_OK)
        {
-               command_print(cmd_ctx, "flash write error: %s", file.error_str);
+               command_print(cmd_ctx, "flash write error: %s", image.error_str);
                return ERROR_OK;
        }
        
-       binary_size = file.size;
+       binary_size = image.size;
        buffer = malloc(binary_size);
 
-       fileio_read(&file, binary_size, buffer, &buf_cnt);
+       image_read(&image, binary_size, buffer, &buf_cnt);
        
        if ((retval = p->driver->write(p, buffer, offset, buf_cnt)) != ERROR_OK)
        {
@@ -571,12 +571,12 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
        {
                duration_stop_measure(&duration, &duration_text);
                command_print(cmd_ctx, "wrote file %s to flash bank %i at offset 0x%8.8x in %s",
-                       file.url, strtoul(args[0], NULL, 0), offset, duration_text);
+                       args[1], strtoul(args[0], NULL, 0), offset, duration_text);
                free(duration_text);
        }
        
        free(buffer);
-       fileio_close(&file);
+       image_close(&image);
        
        return ERROR_OK;
 }
index e0dfa22ff9afb0d86bf1b031711f019a95f259b8..38a70749a4f2553662df8a352cdcc53b30e04026 100644 (file)
@@ -38,6 +38,7 @@
 #include "flash.h"
 #include "time_support.h"
 #include "fileio.h"
+#include "image.h"
 
 int nand_register_commands(struct command_context_s *cmd_ctx);
 int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -1163,10 +1164,8 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
        u32 buf_cnt;
        enum oob_formats oob_format = NAND_OOB_NONE;
        
-       fileio_t file;
-       fileio_image_t image_info;
-       int sec_type_identified = 0;
-       enum fileio_sec_type sec_type;
+       image_t image;
+       int image_type_identified = 0;
        
        duration_t duration;
        char *duration_text;
@@ -1201,9 +1200,9 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
                                        oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
                                else
                                {
-                                       if (fileio_identify_image_type(&sec_type, args[i]) == ERROR_OK)
+                                       if (identify_image_type(&image.type, args[i]) == ERROR_OK)
                                        {
-                                               sec_type_identified = 1;
+                                               image_type_identified = 1;
                                        }
                                        else
                                        {
@@ -1214,27 +1213,27 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
                }
                
                /* if no image type option was encountered, set the default */
-               if (!sec_type_identified)
+               if (!image_type_identified)
                {
                        
-                       fileio_identify_image_type(&sec_type, NULL);
-                       sec_type_identified = 1;
+                       identify_image_type(&image.type, NULL);
+                       image_type_identified = 1;
                }
 
-               image_info.base_address = strtoul(args[2], NULL, 0);
-               image_info.has_start_address = 0;
+               image.base_address_set = 1;
+               image.base_address = strtoul(args[2], NULL, 0);
+               image.start_address_set = 0;
        
-               if (fileio_open(&file, args[1], FILEIO_READ, 
-                       FILEIO_IMAGE, &image_info, sec_type) != ERROR_OK)
+               if (image_open(&image, args[1], FILEIO_READ) != ERROR_OK)
                {
-                       command_print(cmd_ctx, "flash write error: %s", file.error_str);
+                       command_print(cmd_ctx, "flash write error: %s", image.error_str);
                        return ERROR_OK;
                }
        
                /* the offset might have been overwritten by the image base address */
-               offset = image_info.base_address;
+               offset = image.base_address;
                
-               buf_cnt = binary_size = file.size;
+               buf_cnt = binary_size = image.size;
                
                if (!(oob_format & NAND_OOB_ONLY))
                {
@@ -1263,7 +1262,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
                        
                        if (page)
                        {
-                               fileio_read(&file, page_size, page, &size_read);
+                               image_read(&image, page_size, page, &size_read);
                                buf_cnt -= size_read;
                                if (size_read < page_size)
                                {
@@ -1273,7 +1272,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
                                
                        if (oob)
                        {
-                               fileio_read(&file, oob_size, oob, &size_read);
+                               image_read(&image, oob_size, oob, &size_read);
                                buf_cnt -= size_read;
                                if (size_read < oob_size)
                                {
@@ -1284,7 +1283,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
                        if (nand_write_page(p, offset / p->page_size, page, page_size, oob, oob_size) != ERROR_OK)
                        {
                                command_print(cmd_ctx, "failed writing file %s to NAND flash %s at offset 0x%8.8x",
-                                       file.url, args[0], offset);
+                                       args[1], args[0], offset);
                                return ERROR_OK;
                        }
                        offset += page_size;
@@ -1292,7 +1291,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
 
                duration_stop_measure(&duration, &duration_text);
                command_print(cmd_ctx, "wrote file %s to NAND flash %s at offset 0x%8.8x in %s",
-                       file.url, args[0], image_info.base_address, duration_text);
+                       args[1], args[0], image.base_address, duration_text);
                free(duration_text);
        }
        else
@@ -1318,8 +1317,7 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
        {
                if (p->device)
                {
-                       fileio_t file;
-                       fileio_image_t image_info;
+                       fileio_t fileio;
                        duration_t duration;
                        char *duration_text;
                        int retval;
@@ -1367,14 +1365,10 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
                                        oob_size = 64;
                                oob = malloc(oob_size);
                        }
-
-                       image_info.base_address = address;
-                       image_info.has_start_address = 0;
                        
-                       if (fileio_open(&file, args[1], FILEIO_WRITE, 
-                               FILEIO_IMAGE, &image_info, FILEIO_PLAIN) != ERROR_OK)
+                       if (fileio_open(&fileio, args[1], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
                        {
-                               command_print(cmd_ctx, "dump_image error: %s", file.error_str);
+                               command_print(cmd_ctx, "dump_image error: %s", fileio.error_str);
                                return ERROR_OK;
                        }
        
@@ -1391,13 +1385,13 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
                                
                                if (page)
                                {
-                                       fileio_write(&file, page_size, page, &size_written);
+                                       fileio_write(&fileio, page_size, page, &size_written);
                                        bytes_done += page_size;
                                }
                                        
                                if (oob)
                                {
-                                       fileio_write(&file, oob_size, oob, &size_written);
+                                       fileio_write(&fileio, oob_size, oob, &size_written);
                                        bytes_done += oob_size;
                                }
                                        
@@ -1411,10 +1405,10 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
                        if (oob)
                                free(oob);
                        
-                       fileio_close(&file);
+                       fileio_close(&fileio);
 
                        duration_stop_measure(&duration, &duration_text);
-                       command_print(cmd_ctx, "dumped %lli byte in %s", file.size, duration_text);
+                       command_print(cmd_ctx, "dumped %lli byte in %s", fileio.size, duration_text);
                        free(duration_text);
                }
                else
diff --git a/src/flash/non_cfi.c b/src/flash/non_cfi.c
new file mode 100644 (file)
index 0000000..3a74ff9
--- /dev/null
@@ -0,0 +1,175 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "log.h"
+
+#include "flash.h"
+#include "cfi.h"
+#include "non_cfi.h"
+
+/* non-CFI compatible flashes */
+non_cfi_t non_cfi_flashes[] = {
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0xd4,
+               .pri_id = 0x02,
+               .dev_size = 0x10,
+               .interface_desc = 0x0,
+               .max_buf_write_size = 0x0,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       0x0010000f,
+                       0x00000000
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0xd5,
+               .pri_id = 0x02,
+               .dev_size = 0x11,
+               .interface_desc = 0x0,
+               .max_buf_write_size = 0x0,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       0x0010001f,
+                       0x00000000
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0xd6,
+               .pri_id = 0x02,
+               .dev_size = 0x12,
+               .interface_desc = 0x0,
+               .max_buf_write_size = 0x0,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       0x0010003f,
+                       0x00000000
+               }
+       },
+       {
+               .mfr = CFI_MFR_SST,
+               .id = 0xd7,
+               .pri_id = 0x02,
+               .dev_size = 0x13,
+               .interface_desc = 0x0,
+               .max_buf_write_size = 0x0,
+               .num_erase_regions = 1,
+               .erase_region_info =
+               {
+                       0x0010007f,
+                       0x00000000
+               }
+       },
+       {
+               .mfr = 0,
+               .id = 0,
+       }
+};
+
+void cfi_fixup_non_cfi(flash_bank_t *bank, void *param)
+{
+       cfi_flash_bank_t *cfi_info = bank->driver_priv;
+       non_cfi_t *non_cfi = non_cfi_flashes;
+       
+       while (non_cfi->mfr)
+       {
+               if ((cfi_info->manufacturer == non_cfi->mfr)
+                       && (cfi_info->device_id == non_cfi->id))
+               {
+                       break;
+               }
+               non_cfi++;
+       }
+       
+       cfi_info->not_cfi = 1;
+       
+       /* fill in defaults for non-critical data */
+       cfi_info->vcc_min = 0x0;
+       cfi_info->vcc_max = 0x0;
+       cfi_info->vpp_min = 0x0;
+       cfi_info->vpp_max = 0x0;
+       cfi_info->word_write_timeout_typ = 0x0;
+       cfi_info->buf_write_timeout_typ = 0x0;
+       cfi_info->block_erase_timeout_typ = 0x0;
+       cfi_info->chip_erase_timeout_typ = 0x0;
+       cfi_info->word_write_timeout_max = 0x0;
+       cfi_info->buf_write_timeout_max = 0x0;
+       cfi_info->block_erase_timeout_max = 0x0;
+       cfi_info->chip_erase_timeout_max = 0x0;
+       
+       cfi_info->qry[0] = 'Q';
+       cfi_info->qry[1] = 'R';
+       cfi_info->qry[2] = 'Y';
+       
+       cfi_info->pri_id = non_cfi->pri_id;
+       cfi_info->pri_addr = 0x0;
+       cfi_info->alt_id = 0x0;
+       cfi_info->alt_addr = 0x0;
+       cfi_info->alt_ext = NULL;
+       
+       cfi_info->interface_desc = non_cfi->interface_desc;
+       cfi_info->max_buf_write_size = non_cfi->max_buf_write_size;
+       cfi_info->num_erase_regions = non_cfi->num_erase_regions;
+       cfi_info->erase_region_info = non_cfi->erase_region_info;
+       
+       if (cfi_info->pri_id == 0x2)
+       {
+               cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t));
+
+               pri_ext->pri[0] = 'P';
+               pri_ext->pri[1] = 'R';
+               pri_ext->pri[2] = 'I';
+               
+               pri_ext->major_version = '1';
+               pri_ext->minor_version = '0';
+               
+               pri_ext->SiliconRevision = 0x0;
+               pri_ext->EraseSuspend = 0x0;
+               pri_ext->EraseSuspend = 0x0;
+               pri_ext->BlkProt = 0x0;
+               pri_ext->TmpBlkUnprotect = 0x0;
+               pri_ext->BlkProtUnprot = 0x0;
+               pri_ext->SimultaneousOps = 0x0;
+               pri_ext->BurstMode = 0x0;
+               pri_ext->PageMode = 0x0;
+               pri_ext->VppMin = 0x0;
+               pri_ext->VppMax = 0x0;
+               pri_ext->TopBottom = 0x0;
+       
+               pri_ext->_reversed_geometry = 0;
+               
+               cfi_info->pri_ext = pri_ext;
+       } else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3))
+       {
+               ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported");
+               exit(-1);
+       }
+}
+
diff --git a/src/flash/non_cfi.h b/src/flash/non_cfi.h
new file mode 100644 (file)
index 0000000..e91b209
--- /dev/null
@@ -0,0 +1,41 @@
+/***************************************************************************
+ *   Copyright (C) 2007 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifndef NON_CFI_H
+#define NON_CFI_H
+
+#include "types.h"
+
+typedef struct non_cfi_s
+{
+       u16 mfr;
+       u16 id;
+       u16 pri_id;
+       u8 dev_size;
+       u16 interface_desc;
+       u16 max_buf_write_size;
+       u8 num_erase_regions;
+       u32 erase_region_info[6];
+} non_cfi_t;
+
+extern non_cfi_t non_cfi_flashes[];
+extern void cfi_fixup_non_cfi(flash_bank_t *bank, void *param);
+
+#endif /* NON_CFI_H */
+
index 648f18794c9e17a4fc2940364f52927fe954f2d7..3a760cd82f8ba042c51e931fd35d9ed6a52a9d8c 100644 (file)
@@ -98,7 +98,7 @@ int fileio_open_local(fileio_t *fileio)
                }
        }
        
-       if (fileio->pri_type == FILEIO_IMAGE)
+       if (fileio->type == FILEIO_BINARY)
                strcat(access, "b");
        
        if (!(fileio_local->file = fopen(fileio->url, access)))
@@ -120,126 +120,7 @@ int fileio_open_local(fileio_t *fileio)
        return ERROR_OK;
 }
 
-//#ifdef FILEIO_BUFFER_COMPLETE_IHEX
-int fileio_ihex_buffer_complete(fileio_t *fileio)
-{
-       fileio_image_t *image = fileio->pri_type_private;
-       fileio_ihex_t *ihex = fileio->sec_type_private;
-       u32 raw_bytes_read, raw_bytes;
-       int retval;
-       u32 full_address = image->base_address;
-       char *buffer = malloc(ihex->raw_size);
-       u32 cooked_bytes = 0x0;
-       
-       ihex->raw_size = fileio->size;
-       ihex->buffer = malloc(ihex->raw_size >> 1);
-       
-       if ((retval = fileio_dispatch_read(fileio, ihex->raw_size, (u8*)buffer, &raw_bytes_read)) != ERROR_OK)
-       {
-               free(buffer);
-               ERROR("failed buffering IHEX file, read failed");
-               return ERROR_FILEIO_OPERATION_FAILED;
-       }
-       
-       if (raw_bytes_read != ihex->raw_size)
-       {
-               free(buffer);
-               ERROR("failed buffering complete IHEX file, only partially read");
-               return ERROR_FILEIO_OPERATION_FAILED;
-       }
-       
-       raw_bytes = 0x0;
-       while (raw_bytes < raw_bytes_read)
-       {
-               u32 count;
-               u32 address;
-               u32 record_type;
-               u32 checksum;
-               
-               if (sscanf(&buffer[raw_bytes], ":%2x%4x%2x", &count, &address, &record_type) != 3)
-               {
-                       snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "invalid IHEX record");
-                       return ERROR_FILEIO_OPERATION_FAILED;
-               }
-               raw_bytes += 9;
-               
-               if (record_type == 0)
-               {
-                       if ((full_address & 0xffff) != address)
-                       {
-                               free(buffer);
-                               ERROR("can't handle non-linear IHEX file");
-                               snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't handle non-linear IHEX file");
-                               return ERROR_FILEIO_OPERATION_FAILED;
-                       }
-                       
-                       while (count-- > 0)
-                       {
-                               sscanf(&buffer[raw_bytes], "%2hhx", &ihex->buffer[cooked_bytes]);
-                               raw_bytes += 2;
-                               cooked_bytes += 1;
-                               full_address++;
-                       }
-               }
-               else if (record_type == 1)
-               {
-                       free(buffer);
-                       fileio->size = cooked_bytes;
-                       return ERROR_OK;
-               }
-               else if (record_type == 4)
-               {
-                       u16 upper_address;
-                       
-                       sscanf(&buffer[raw_bytes], "%4hx", &upper_address);
-                       raw_bytes += 4;
-                       
-                       if ((full_address >> 16) != upper_address)
-                       {
-                               free(buffer);
-                               ERROR("can't handle non-linear IHEX file");
-                               snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't handle non-linear IHEX file");
-                               return ERROR_FILEIO_OPERATION_FAILED;
-                       }
-               }
-               else if (record_type == 5)
-               {
-                       u32 start_address;
-                       
-                       sscanf(&buffer[raw_bytes], "%8x", &start_address);
-                       raw_bytes += 8;
-                       
-                       image->has_start_address = 1;
-                       image->start_address = be_to_h_u32((u8*)&start_address);
-               }
-               else
-               {
-                       free(buffer);
-                       ERROR("unhandled IHEX record type: %i", record_type);
-                       snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "unhandled IHEX record type: %i", record_type);
-                       return ERROR_FILEIO_OPERATION_FAILED;
-               }
-               
-               sscanf(&buffer[raw_bytes], "%2x", &checksum);
-               raw_bytes += 2;
-               
-               /* consume new-line character(s) */
-               if ((buffer[raw_bytes] == '\n') || (buffer[raw_bytes] == '\r'))
-                       raw_bytes++;
-
-               if ((buffer[raw_bytes] == '\n') || (buffer[raw_bytes] == '\r'))
-                       raw_bytes++;
-       }
-
-       free(buffer);
-       ERROR("premature end of IHEX file, no end-of-file record found");
-       snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "premature end of IHEX file, no end-of-file record found");
-       return ERROR_FILEIO_OPERATION_FAILED;   
-}
-//#endif
-
-int fileio_open(fileio_t *fileio, char *url, enum fileio_access access,
-       enum fileio_pri_type pri_type, void *pri_info, enum fileio_sec_type sec_type)
+int fileio_open(fileio_t *fileio, char *url, enum fileio_access access,        enum fileio_type type)
 {
        int retval = ERROR_OK;
        char *resource_identifier = NULL;
@@ -261,9 +142,8 @@ int fileio_open(fileio_t *fileio, char *url, enum fileio_access access,
                fileio->location = FILEIO_LOCAL;
        }
        
+       fileio->type = type;
        fileio->access = access;
-       fileio->pri_type = pri_type;
-       fileio->sec_type = sec_type;
        fileio->url = strdup(url);
        
        switch (fileio->location)
@@ -279,50 +159,6 @@ int fileio_open(fileio_t *fileio, char *url, enum fileio_access access,
        if (retval != ERROR_OK)
                return retval;
        
-       if (fileio->pri_type == FILEIO_TEXT)
-       {
-               /* do nothing for now */
-               return ERROR_OK;
-       }
-       else if (fileio->pri_type == FILEIO_IMAGE)
-       {
-               fileio_image_t *image = malloc(sizeof(fileio_image_t));
-               fileio_image_t *image_info = pri_info;
-               
-               fileio->pri_type_private = image;
-               *image = *image_info; 
-               
-               if (fileio->sec_type == FILEIO_PLAIN)
-               {
-                       fileio->sec_type_private = NULL;
-               }
-               else if (fileio->sec_type == FILEIO_IHEX)
-               {
-                       fileio_ihex_t *fileio_ihex;
-                       
-                       if (fileio->access != FILEIO_READ)
-                       {
-                               ERROR("can't write/append to a IHEX file");
-                               snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't write/append to a IHEX file");
-                               fileio_close(fileio);
-                               return ERROR_FILEIO_OPERATION_FAILED;
-                       }
-                       
-                       fileio_ihex = malloc(sizeof(fileio_ihex_t));
-                       fileio->sec_type_private = fileio_ihex;
-                       
-                       fileio_ihex->position = 0;
-                       fileio_ihex->raw_size = fileio->size;
-#ifdef FILEIO_BUFFER_COMPLETE_IHEX
-                       if (fileio_ihex_buffer_complete(fileio) != ERROR_OK)
-                       {
-                               fileio_close(fileio);
-                               return ERROR_FILEIO_OPERATION_FAILED;
-                       }
-#endif
-               }
-       }
-       
        return ERROR_OK;
 }
 
@@ -369,29 +205,6 @@ int fileio_close(fileio_t *fileio)
        
        free(fileio->url);
        
-       if (fileio->pri_type == FILEIO_TEXT)
-       {
-               /* do nothing for now */
-       }
-       else if (fileio->pri_type == FILEIO_IMAGE)
-       {
-               if (fileio->sec_type == FILEIO_PLAIN)
-               {
-                       /* nothing special to do for plain binary */
-               }
-               else if (fileio->sec_type == FILEIO_IHEX)
-               {
-                       fileio_ihex_t *fileio_ihex = fileio->sec_type_private;
-       
-                       if (fileio_ihex->buffer)
-                               free(fileio_ihex->buffer);
-                       
-                       free(fileio->sec_type_private);
-               }
-               
-               free(fileio->pri_type_private);
-       }
-       
        return ERROR_OK;
 }
 
@@ -432,7 +245,7 @@ int fileio_local_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
        return ERROR_OK;
 }
 
-int fileio_dispatch_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
+int fileio_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
 {
        switch (fileio->location)
        {
@@ -445,38 +258,6 @@ int fileio_dispatch_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
        }
 }
 
-int fileio_read_ihex(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
-{
-       fileio_ihex_t *fileio_ihex = fileio->sec_type_private;
-
-       if ((fileio_ihex->position + size) > fileio->size)
-       {
-               /* don't read past the end of the file */
-               size = (fileio->size - fileio_ihex->position);
-       }
-       
-#ifdef FILEIO_BUFFER_COMPLETE_IHEX
-       memcpy(buffer, fileio_ihex->buffer + fileio_ihex->position, size);
-       *size_read = size;
-#endif
-
-       return ERROR_OK;
-}
-
-int fileio_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
-{
-       if (fileio->sec_type == FILEIO_PLAIN)
-       {
-               return fileio_dispatch_read(fileio, size, buffer, size_read);
-       }
-       else if (fileio->sec_type == FILEIO_IHEX)
-       {
-               return fileio_read_ihex(fileio, size, buffer, size_read);
-       }
-       
-       return ERROR_OK;
-}
-
 int fileio_local_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
 {
        fileio_local_t *fileio_local = fileio->location_private;
@@ -486,7 +267,7 @@ int fileio_local_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written
        return ERROR_OK;
 }
 
-int fileio_dispatch_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
+int fileio_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
 {
        switch (fileio->location)
        {
@@ -499,48 +280,3 @@ int fileio_dispatch_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_writ
        
        return ERROR_OK;
 }
-
-int fileio_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
-{
-       int retval = ERROR_FILEIO_OPERATION_NOT_SUPPORTED;
-       if (fileio->sec_type == FILEIO_PLAIN)
-       {
-               retval = fileio_dispatch_write(fileio, size, buffer, size_written);
-       }
-       else if (fileio->sec_type == FILEIO_IHEX)
-       {
-               return ERROR_FILEIO_OPERATION_NOT_SUPPORTED;
-       }
-       
-       if (retval != ERROR_OK)
-               return retval;
-               
-       fileio->size += size;
-       
-       return ERROR_OK;
-}
-
-int fileio_identify_image_type(enum fileio_sec_type *sec_type, char *type_string)
-{
-       if (type_string)
-       {
-               if (!strcmp(type_string, "bin"))
-               {
-                       *sec_type = FILEIO_PLAIN;
-               }
-               else if (!strcmp(type_string, "ihex"))
-               {
-                       *sec_type = FILEIO_IHEX;
-               }
-               else
-               {
-                       return ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN;
-               }
-       }
-       else
-       {
-               *sec_type = FILEIO_PLAIN;
-       }
-       
-       return ERROR_OK;
-}
index c047cb87aa029183dd9e78457fb4cdd5f2ef7eeb..55e6f32313aa1504517bc7d2feae0a2ff00dc202 100644 (file)
 
 #define FILEIO_MAX_ERROR_STRING                (128)
 
-/* make buffering of complete intel-hex format files optional
- * to account for resource-limited hosts
- */
-#define FILEIO_BUFFER_COMPLETE_IHEX
+#include "types.h"
 
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
 #include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
 
-enum fileio_pri_type
-{
-       FILEIO_TEXT = 0x1,
-       FILEIO_IMAGE = 0x2,
-};
-
-enum fileio_sec_type
+enum fileio_type
 {
-       FILEIO_PLAIN = 0x10,
-       FILEIO_IHEX = 0x20,
-/*
- * Possible future enhancements:
- * FILEIO_ELF,
- * FILEIO_SRECORD,
- */
+       FILEIO_TEXT,
+       FILEIO_BINARY,
 };
 
 enum fileio_location
@@ -73,48 +65,23 @@ typedef struct fileio_s
        char *url;
        char error_str[FILEIO_MAX_ERROR_STRING];
        long long size;
-       enum fileio_pri_type pri_type;
-       enum fileio_sec_type sec_type;
+       enum fileio_type type;
        enum fileio_location location;
        enum fileio_access access;
        void *location_private;
-       void *pri_type_private;
-       void *sec_type_private;
 } fileio_t;
 
-typedef struct fileio_text_s
-{
-} fileio_text_t;
-
-typedef struct fileio_image_s
-{
-       u32 base_address;
-       int has_start_address;
-       u32 start_address;
-} fileio_image_t;
-
 typedef struct fileio_local_s
 {
        FILE *file;
        struct stat file_stat;
 } fileio_local_t;
 
-typedef struct fileio_ihex_s
-{
-       u32 position;
-       u32 raw_size;
-#ifdef FILEIO_BUFFER_COMPLETE_IHEX
-       u8 *buffer;
-#endif
-} fileio_ihex_t;
-
-extern int fileio_identify_image_type(enum fileio_sec_type *sec_type, char *type_string);
 extern int fileio_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written);
 extern int fileio_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read);
 extern int fileio_seek(fileio_t *fileio, u32 position);
 extern int fileio_close(fileio_t *fileio);
-extern int fileio_open(fileio_t *fileio, char *url, enum fileio_access access,
-       enum fileio_pri_type pri_type, void *pri_info, enum fileio_sec_type sec_type);
+extern int fileio_open(fileio_t *fileio, char *url, enum fileio_access access, enum fileio_type type);
        
 #define ERROR_FILEIO_LOCATION_UNKNOWN  (-1200)
 #define ERROR_FILEIO_NOT_FOUND                 (-1201)
index 073ce1f4553a429ef605301f5bddf7ca02fe6692..6dfde760112f3b9fc66b9d472319949e0d5236f7 100644 (file)
@@ -1282,6 +1282,7 @@ int jtag_examine_chain()
        {
                ERROR("number of discovered devices in JTAG chain (%i) doesn't match configuration (%i)", 
                        device_count, jtag_num_devices);
+               ERROR("check the config file and ensure proper JTAG communication (connections, speed, ...)");
                exit(-1);
        }
        
index 3abdda63168f0b5f8d7566a41ab29c4a25c60017..10a4cfd28e4eb889c4422266cd93c21209f1c29f 100644 (file)
@@ -18,7 +18,7 @@
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#define OPENOCD_VERSION "Open On-Chip Debugger (2007-04-26 16:40 CEST)"
+#define OPENOCD_VERSION "Open On-Chip Debugger (2007-05-29 13:15 CEST)"
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
index cf1955a05c59945873ae4a7013ee7de2f57776b8..b1e6f91924640f6730d2c8a9e0047585f100ea53 100644 (file)
@@ -3,7 +3,7 @@ METASOURCES = AUTO
 noinst_LIBRARIES = libtarget.a
 libtarget_a_SOURCES = target.c register.c breakpoints.c armv4_5.c embeddedice.c etm.c arm7tdmi.c arm9tdmi.c \
        arm_jtag.c arm7_9_common.c algorithm.c arm920t.c arm720t.c armv4_5_mmu.c armv4_5_cache.c arm_disassembler.c \
-       arm966e.c arm926ejs.c etb.c xscale.c arm_simulator.c
+       arm966e.c arm926ejs.c etb.c xscale.c arm_simulator.c image.c
 noinst_HEADERS = target.h register.h armv4_5.h embeddedice.h etm.h arm7tdmi.h arm9tdmi.h \
                arm_jtag.h arm7_9_common.h arm920t.h arm720t.h armv4_5_mmu.h armv4_5_cache.h breakpoints.h algorithm.h \
-               arm_disassembler.h arm966e.h arm926ejs.h etb.h xscale.h arm_simulator.h
+               arm_disassembler.h arm966e.h arm926ejs.h etb.h xscale.h arm_simulator.h image.h
index 2c82c91e705946dbe404216d7ed9c8354f30f4c4..77a43feebb265a845b4a8e423da7f5079e2908e4 100644 (file)
@@ -2096,8 +2096,6 @@ int arm7_9_register_commands(struct command_context_s *cmd_ctx)
        
        arm7_9_cmd = register_command(cmd_ctx, NULL, "arm7_9", NULL, COMMAND_ANY, "arm7/9 specific commands");
 
-       register_command(cmd_ctx, arm7_9_cmd, "etm", handle_arm7_9_etm_command, COMMAND_CONFIG, NULL);
-       
        register_command(cmd_ctx, arm7_9_cmd, "write_xpsr", handle_arm7_9_write_xpsr_command, COMMAND_EXEC, "write program status register <value> <not cpsr|spsr>");
        register_command(cmd_ctx, arm7_9_cmd, "write_xpsr_im8", handle_arm7_9_write_xpsr_im8_command, COMMAND_EXEC, "write program status register <8bit immediate> <rotate> <not cpsr|spsr>");
        
@@ -2115,7 +2113,8 @@ int arm7_9_register_commands(struct command_context_s *cmd_ctx)
                COMMAND_ANY, "use DCC downloads for larger memory writes <enable|disable>");
 
        armv4_5_register_commands(cmd_ctx);
-       etb_register_commands(cmd_ctx, arm7_9_cmd);
+       
+       etm_register_commands(cmd_ctx);
        
        return ERROR_OK;
 }
@@ -2425,83 +2424,6 @@ int handle_arm7_9_dcc_downloads_command(struct command_context_s *cmd_ctx, char
        return ERROR_OK;
 }
 
-int handle_arm7_9_etm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       target_t *target;
-       armv4_5_common_t *armv4_5;
-       arm7_9_common_t *arm7_9;
-       
-       if (argc != 1)
-       {
-               ERROR("incomplete 'arm7_9 etm <target>' command");
-               exit(-1);
-       }
-       
-       target = get_target_by_num(strtoul(args[0], NULL, 0));
-       
-       if (!target)
-       {
-               ERROR("target number '%s' not defined", args[0]);
-               exit(-1);
-       }
-       
-       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
-       {
-               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
-               return ERROR_OK;
-       }
-       
-       arm7_9->has_etm = 1;
-       
-       return ERROR_OK;
-}
-
-int handle_arm7_9_etb_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       target_t *target;
-       jtag_device_t *jtag_device;
-       armv4_5_common_t *armv4_5;
-       arm7_9_common_t *arm7_9;
-       
-       if (argc != 2)
-       {
-               ERROR("incomplete 'arm7_9 etb <target> <chain_pos>' command");
-               exit(-1);
-       }
-       
-       target = get_target_by_num(strtoul(args[0], NULL, 0));
-       
-       if (!target)
-       {
-               ERROR("target number '%s' not defined", args[0]);
-               exit(-1);
-       }
-       
-       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
-       {
-               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
-               return ERROR_OK;
-       }
-       
-       jtag_device = jtag_get_device(strtoul(args[1], NULL, 0));
-       
-       if (!jtag_device)
-       {
-               ERROR("jtag device number '%s' not defined", args[1]);
-               exit(-1);
-       }
-
-       arm7_9->etb = malloc(sizeof(etb_t));
-       
-       arm7_9->etb->chain_pos = strtoul(args[1], NULL, 0);
-       arm7_9->etb->cur_scan_chain = -1;
-       arm7_9->etb->reg_cache = NULL;
-       arm7_9->etb->RAM_width = 0;
-       arm7_9->etb->RAM_depth = 0;
-
-       return ERROR_OK;
-}
-
 int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9)
 {
        armv4_5_common_t *armv4_5 = &arm7_9->armv4_5_common;
@@ -2515,8 +2437,7 @@ int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9)
        arm7_9->force_hw_bkpts = 0;
        arm7_9->use_dbgrq = 0;
        
-       arm7_9->has_etm = 0;
-       arm7_9->etb = NULL;
+       arm7_9->etm_ctx = NULL;
        arm7_9->has_single_step = 0;
        arm7_9->has_monitor_mode = 0;
        arm7_9->has_vector_catch = 0;
index e77bedac0190da377837d8944b2f206ea9cded30..fbcb920dc51ae162bf88be00c5f25c97effaf512 100644 (file)
@@ -25,7 +25,7 @@
 #include "breakpoints.h"
 #include "target.h"
 
-#include "etb.h"
+#include "etm.h"
 
 #define        ARM7_9_COMMON_MAGIC 0x0a790a79
 
@@ -35,7 +35,6 @@ typedef struct arm7_9_common_s
        
        arm_jtag_t jtag_info;
        reg_cache_t *eice_cache;
-       reg_cache_t *etm_cache;
        
        u32 arm_bkpt;
        u16 thumb_bkpt;
@@ -48,8 +47,8 @@ typedef struct arm7_9_common_s
        int dbgreq_adjust_pc;
        int use_dbgrq;
        
-       int has_etm;
-       etb_t *etb;
+       etm_context_t *etm_ctx;
+       
        int has_single_step;
        int has_monitor_mode;
        int has_vector_catch;
index 5684dcfa12f1572075ecae5d0773138080c6200c..7c6b937f09e288a3767324dd494d8c0ec80b1715 100644 (file)
@@ -744,10 +744,10 @@ void arm7tdmi_build_reg_cache(target_t *target)
        (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9);
        arm7_9->eice_cache = (*cache_p)->next;
        
-       if (arm7_9->has_etm)
+       if (arm7_9->etm_ctx)
        {
-               (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0);
-               arm7_9->etm_cache = (*cache_p)->next->next;
+               (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx);
+               arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next;
        }
 }
 
index 112926d16ea4960873f4663c7434771c34ca4742..7ecd1f0d58463a638578cd5ed0a182e1d9b8d23c 100644 (file)
@@ -874,16 +874,10 @@ void arm9tdmi_build_reg_cache(target_t *target)
        (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9);
        arm7_9->eice_cache = (*cache_p)->next;
 
-       if (arm7_9->has_etm)
+       if (arm7_9->etm_ctx)
        {
-               (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0);
-               arm7_9->etm_cache = (*cache_p)->next->next;
-       }
-       
-       if (arm7_9->etb)
-       {
-               (*cache_p)->next->next->next = etb_build_reg_cache(arm7_9->etb);
-               arm7_9->etb->reg_cache = (*cache_p)->next->next->next;
+               (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx);
+               arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next;
        }
 }
 
index dd77928252fd41131eac1b197d08f357f52f1b14..1c275f54645a897e70c4cbede7f8806264838e94 100644 (file)
@@ -343,7 +343,10 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
        if (!I) /* #+-<offset_12> */
        {
                u32 offset_12 = (opcode & 0xfff);
-               snprintf(offset, 32, "#%s0x%x", (U) ? "" : "-", offset_12);
+               if (offset_12)
+                       snprintf(offset, 32, ", #%s0x%x", (U) ? "" : "-", offset_12);
+               else
+                       snprintf(offset, 32, "");
                
                instruction->info.load_store.offset_mode = 0;
                instruction->info.load_store.offset.offset = offset_12;
@@ -376,26 +379,26 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
 
                if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */
                {
-                       snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
+                       snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
                }
                else /* +-<Rm>, <Shift>, #<shift_imm> */
                {
                        switch (shift)
                        {
                                case 0x0: /* LSL */
-                                       snprintf(offset, 32, "%sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm);
+                                       snprintf(offset, 32, "%sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm);
                                        break;
                                case 0x1: /* LSR */
-                                       snprintf(offset, 32, "%sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm);
+                                       snprintf(offset, 32, "%sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm);
                                        break;
                                case 0x2: /* ASR */
-                                       snprintf(offset, 32, "%sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm);
+                                       snprintf(offset, 32, "%sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm);
                                        break;
                                case 0x3: /* ROR */
-                                       snprintf(offset, 32, "%sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm);
+                                       snprintf(offset, 32, "%sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm);
                                        break;
                                case 0x4: /* RRX */
-                                       snprintf(offset, 32, "%sr%i, RRX", (U) ? "" : "-", Rm);
+                                       snprintf(offset, 32, "%sr%i, RRX", (U) ? "" : "-", Rm);
                                        break;
                        }
                }
@@ -405,7 +408,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
        {
                if (W == 0) /* offset */
                {
-                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]",
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]",
                                         address, opcode, operation, COND(opcode), suffix,
                                         Rd, Rn, offset);
                        
@@ -413,7 +416,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
                }
                else /* pre-indexed */
                {
-                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]!",
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]!",
                                         address, opcode, operation, COND(opcode), suffix,
                                         Rd, Rn, offset);
                        
@@ -422,7 +425,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
        }
        else /* post-indexed */
        {
-               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i]%s",
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i]%s",
                                 address, opcode, operation, COND(opcode), suffix,
                                 Rd, Rn, offset);
                
@@ -1157,7 +1160,10 @@ int evaluate_data_proc(u32 opcode, u32 address, arm_instruction_t *instruction)
        }
        else if ((op == 0xd) || (op == 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
        {
-               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s",
+               if (opcode==0xe1a00000) /* print MOV r0,r0 as NOP */
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tNOP",address, opcode);
+               else
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s",
                                 address, opcode, mnemonic, COND(opcode),
                                 (S) ? "S" : "", Rd, shifter_operand);
        }
@@ -1315,3 +1321,762 @@ int arm_evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction)
        return -1;
 }
 
+int evaluate_b_bl_blx_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u32 offset = opcode & 0x7ff;
+       u32 opc = (opcode >> 11) & 0x3;
+       u32 target_address;
+       char *mnemonic = NULL;
+       
+       /* sign extend 11-bit offset */
+       if (((opc==0) || (opc==2)) && (offset & 0x00000400))
+               offset = 0xfffff800 | offset;
+       
+       target_address = address + 4 + (offset<<1);
+
+       switch(opc)
+       {
+               /* unconditional branch */
+               case 0:
+                       instruction->type = ARM_B;
+                       mnemonic = "B";
+                       break;
+               /* BLX suffix */
+               case 1:
+                       instruction->type = ARM_BLX;
+                       mnemonic = "BLX";
+                       break;
+               /* BL/BLX prefix */
+               case 2:
+                       instruction->type = ARM_UNKNOWN_INSTUCTION;
+                       mnemonic = "prefix";
+                       target_address = offset<<12;
+                       break;
+               /* BL suffix */
+               case 3:
+                       instruction->type = ARM_BL;
+                       mnemonic = "BL";
+                       break;
+       }
+       /* TODO: deals correctly with dual opcodes BL/BLX ... */
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s 0x%8.8x", address, opcode,mnemonic, target_address);
+       
+       instruction->info.b_bl_bx_blx.reg_operand = -1;
+       instruction->info.b_bl_bx_blx.target_address = target_address;
+
+       return ERROR_OK;
+}
+
+int evaluate_add_sub_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u8 Rd = (opcode >> 0) & 0x7;
+       u8 Rn = (opcode >> 3) & 0x7;
+       u8 Rm_imm = (opcode >> 6) & 0x7;
+       u32 opc = opcode & (1<<9);
+       u32 reg_imm  = opcode & (1<<10);
+       char *mnemonic;
+       
+       if (opc)
+       {
+               instruction->type = ARM_SUB;
+               mnemonic = "SUBS";
+       }
+       else
+       {
+               instruction->type = ARM_ADD;
+               mnemonic = "ADDS";
+       }
+       
+       instruction->info.data_proc.Rd = Rd;
+       instruction->info.data_proc.Rn = Rn;
+       instruction->info.data_proc.S = 1;
+
+       if (reg_imm)
+       {
+               instruction->info.data_proc.variant = 0; /*immediate*/
+               instruction->info.data_proc.shifter_operand.immediate.immediate = Rm_imm;
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #%d",
+                                address, opcode, mnemonic, Rd, Rn, Rm_imm);
+       }
+       else
+       {
+               instruction->info.data_proc.variant = 1; /*immediate shift*/
+               instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm_imm;
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, r%i",
+                                address, opcode, mnemonic, Rd, Rn, Rm_imm);
+       }
+
+       return ERROR_OK;
+}
+
+int evaluate_shift_imm_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u8 Rd = (opcode >> 0) & 0x7;
+       u8 Rm = (opcode >> 3) & 0x7;
+       u8 imm = (opcode >> 6) & 0x1f;
+       u8 opc = (opcode >> 11) & 0x3;
+       char *mnemonic = NULL;
+       
+       switch(opc)
+       {
+               case 0:
+                       instruction->type = ARM_MOV;
+                       mnemonic = "LSLS";
+                       instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0;
+                       break;
+               case 1:
+                       instruction->type = ARM_MOV;
+                       mnemonic = "LSRS";
+                       instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1;
+                       break;
+               case 2:
+                       instruction->type = ARM_MOV;
+                       mnemonic = "ASRS";
+                       instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2;
+                       break;
+       }
+
+       if ((imm==0) && (opc!=0))
+               imm = 32;
+
+       instruction->info.data_proc.Rd = Rd;
+       instruction->info.data_proc.Rn = -1;
+       instruction->info.data_proc.S = 1;
+
+       instruction->info.data_proc.variant = 1; /*immediate_shift*/
+       instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
+       instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = imm;
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #0x%02x",
+                                address, opcode, mnemonic, Rd, Rm, imm);
+
+       return ERROR_OK;
+}
+
+int evaluate_data_proc_imm_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u8 imm = opcode & 0xff;
+       u8 Rd = (opcode >> 8) & 0x7;
+       u32 opc = (opcode >> 11) & 0x3;
+       char *mnemonic = NULL;
+       
+       instruction->info.data_proc.Rd = Rd;
+       instruction->info.data_proc.Rn = Rd;
+       instruction->info.data_proc.S = 1;
+       instruction->info.data_proc.variant = 0; /*immediate*/
+       instruction->info.data_proc.shifter_operand.immediate.immediate = imm;
+       
+       switch(opc)
+       {
+               case 0:
+                       instruction->type = ARM_MOV;
+                       mnemonic = "MOVS";
+                       instruction->info.data_proc.Rn = -1;
+                       break;
+               case 1:
+                       instruction->type = ARM_CMP;
+                       mnemonic = "CMP";
+                       instruction->info.data_proc.Rd = -1;
+                       break;
+               case 2:
+                       instruction->type = ARM_ADD;
+                       mnemonic = "ADDS";
+                       break;
+               case 3:
+                       instruction->type = ARM_SUB;
+                       mnemonic = "SUBS";
+                       break;
+       }
+       
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, #0x%02x",
+                                address, opcode, mnemonic, Rd, imm);
+
+       return ERROR_OK;
+}
+
+int evaluate_data_proc_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u8 high_reg, op, Rm, Rd,H1,H2;
+       char *mnemonic = NULL;
+       
+       high_reg = (opcode & 0x0400) >> 10;
+       op = (opcode & 0x03C0) >> 6;
+       
+       Rd = (opcode & 0x0007);
+       Rm = (opcode & 0x0038) >> 3;
+       H1 = (opcode & 0x0080) >> 7;
+       H2 = (opcode & 0x0040) >> 6;
+       
+       instruction->info.data_proc.Rd = Rd;
+       instruction->info.data_proc.Rn = Rd;
+       instruction->info.data_proc.S = (!high_reg || (instruction->type == ARM_CMP));
+       instruction->info.data_proc.variant = 1 /*immediate shift*/;
+       instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
+
+       if (high_reg)
+       {
+               Rd |= H1 << 3;
+               Rm |= H2 << 3;
+               op >>= 2;
+       
+               switch (op)
+               {
+                       case 0x0:
+                               instruction->type = ARM_ADD;
+                               mnemonic = "ADD";
+                               break;
+                       case 0x1:
+                               instruction->type = ARM_CMP;
+                               mnemonic = "CMP";
+                               break;
+                       case 0x2:
+                               instruction->type = ARM_MOV;
+                               mnemonic = "MOV";
+                               break;
+                       case 0x3:
+                               if ((opcode & 0x7) == 0x0)
+                               {
+                                       instruction->info.b_bl_bx_blx.reg_operand = Rm;
+                                       if (H1)
+                                       {
+                                               instruction->type = ARM_BLX;
+                                               snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tBLX r%i", address, opcode, Rm);
+                                       }
+                                       else
+                                       {
+                                               instruction->type = ARM_BX;
+                                               snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tBX r%i", address, opcode, Rm);
+                                       }
+                               }
+                               else
+                               {
+                                       instruction->type = ARM_UNDEFINED_INSTRUCTION;
+                                       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address, opcode);
+                               }
+                               return ERROR_OK;        
+                               break;
+               }
+       }
+       else
+       {
+               switch (op)
+               {
+                       case 0x0:
+                               instruction->type = ARM_AND;
+                               mnemonic = "ANDS";
+                               break;
+                       case 0x1:
+                               instruction->type = ARM_EOR;
+                               mnemonic = "EORS";
+                               break;
+                       case 0x2:
+                               instruction->type = ARM_MOV;
+                               mnemonic = "LSLS";
+                               instruction->info.data_proc.variant = 2 /*register shift*/;
+                               instruction->info.data_proc.shifter_operand.register_shift.shift = 0;
+                               instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
+                               instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
+                               break;
+                       case 0x3:
+                               instruction->type = ARM_MOV;
+                               mnemonic = "LSRS";
+                               instruction->info.data_proc.variant = 2 /*register shift*/;
+                               instruction->info.data_proc.shifter_operand.register_shift.shift = 1;
+                               instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
+                               instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
+                               break;
+                       case 0x4:
+                               instruction->type = ARM_MOV;
+                               mnemonic = "ASRS";
+                               instruction->info.data_proc.variant = 2 /*register shift*/;
+                               instruction->info.data_proc.shifter_operand.register_shift.shift = 2;
+                               instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
+                               instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
+                               break;
+                       case 0x5:
+                               instruction->type = ARM_ADC;
+                               mnemonic = "ADCS";
+                               break;
+                       case 0x6:
+                               instruction->type = ARM_SBC;
+                               mnemonic = "SBCS";
+                               break;
+                       case 0x7:
+                               instruction->type = ARM_MOV;
+                               mnemonic = "RORS";
+                               instruction->info.data_proc.variant = 2 /*register shift*/;
+                               instruction->info.data_proc.shifter_operand.register_shift.shift = 3;
+                               instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
+                               instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
+                               break;
+                       case 0x8:
+                               instruction->type = ARM_TST;
+                               mnemonic = "TST";
+                               break;
+                       case 0x9:
+                               instruction->type = ARM_RSB;
+                               mnemonic = "NEGS";
+                               instruction->info.data_proc.variant = 0 /*immediate*/;
+                               instruction->info.data_proc.shifter_operand.immediate.immediate = 0;
+                               instruction->info.data_proc.Rn = Rm;
+                               break;
+                       case 0xA:
+                               instruction->type = ARM_CMP;
+                               mnemonic = "CMP";
+                               break;
+                       case 0xB:
+                               instruction->type = ARM_CMN;
+                               mnemonic = "CMN";
+                               break;
+                       case 0xC:
+                               instruction->type = ARM_ORR;
+                               mnemonic = "ORRS";
+                               break;
+                       case 0xD:
+                               instruction->type = ARM_MUL;
+                               mnemonic = "MULS";
+                               break;
+                       case 0xE:
+                               instruction->type = ARM_BIC;
+                               mnemonic = "BICS";
+                               break;
+                       case 0xF:
+                               instruction->type = ARM_MVN;
+                               mnemonic = "MVNS";
+                               break;
+               }
+       }
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i",
+                                address, opcode, mnemonic, Rd, Rm);
+
+       return ERROR_OK;
+}
+
+int evaluate_load_literal_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u32 immediate;
+       u8 Rd = (opcode >> 8) & 0x7; 
+
+       instruction->type = ARM_LDR;
+       immediate = opcode & 0x000000ff;
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tLDR r%i, [PC, #0x%x]", address, opcode, Rd, immediate*4);
+
+       instruction->info.load_store.Rd = Rd;
+       instruction->info.load_store.Rn = 15 /*PC*/;
+       instruction->info.load_store.index_mode = 0; /*offset*/
+       instruction->info.load_store.offset_mode = 0; /*immediate*/
+       instruction->info.load_store.offset.offset = immediate*4;
+
+       return ERROR_OK;
+}
+
+int evaluate_load_store_reg_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u8 Rd = (opcode >> 0) & 0x7; 
+       u8 Rn = (opcode >> 3) & 0x7; 
+       u8 Rm = (opcode >> 6) & 0x7; 
+       u8 opc = (opcode >> 9) & 0x7; 
+       char *mnemonic = NULL;
+
+       switch(opc)
+       {
+               case 0:
+                       instruction->type = ARM_STR;
+                       mnemonic = "STR";
+                       break;
+               case 1:
+                       instruction->type = ARM_STRH;
+                       mnemonic = "STRH";
+                       break;
+               case 2:
+                       instruction->type = ARM_STRB;
+                       mnemonic = "STRB";
+                       break;
+               case 3:
+                       instruction->type = ARM_LDRSB;
+                       mnemonic = "LDRSB";
+                       break;
+               case 4:
+                       instruction->type = ARM_LDR;
+                       mnemonic = "LDR";
+                       break;
+               case 5:
+                       instruction->type = ARM_LDRH;
+                       mnemonic = "LDRH";
+                       break;
+               case 6:
+                       instruction->type = ARM_LDRB;
+                       mnemonic = "LDRB";
+                       break;
+               case 7:
+                       instruction->type = ARM_LDRSH;
+                       mnemonic = "LDRSH";
+                       break;
+       }
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [r%i, r%i]", address, opcode, mnemonic, Rd, Rn, Rm);
+       
+       instruction->info.load_store.Rd = Rd;
+       instruction->info.load_store.Rn = Rn;
+       instruction->info.load_store.index_mode = 0; /*offset*/
+       instruction->info.load_store.offset_mode = 1; /*register*/
+       instruction->info.load_store.offset.reg.Rm = Rm;
+
+       return ERROR_OK;
+}
+
+int evaluate_load_store_imm_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u32 offset = (opcode >> 6) & 0x1f;
+       u8 Rd = (opcode >> 0) & 0x7; 
+       u8 Rn = (opcode >> 3) & 0x7; 
+       u32 L = opcode & (1<<11);
+       u32 B = opcode & (1<<12);
+       char *mnemonic;
+       char suffix = ' ';
+       u32 shift = 2;
+
+       if (L)
+       {
+               instruction->type = ARM_LDR;
+               mnemonic = "LDR";
+       }
+       else
+       {
+               instruction->type = ARM_STR;
+               mnemonic = "STR";
+       }
+
+       if ((opcode&0xF000)==0x8000)
+       {
+               suffix = 'H';
+               shift = 1;
+       }
+       else if (B)
+       {
+               suffix = 'B';
+               shift = 0;
+       }
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s%c r%i, [r%i, #0x%x]", address, opcode, mnemonic, suffix, Rd, Rn, offset<<shift);
+       
+       instruction->info.load_store.Rd = Rd;
+       instruction->info.load_store.Rn = Rn;
+       instruction->info.load_store.index_mode = 0; /*offset*/
+       instruction->info.load_store.offset_mode = 0; /*immediate*/
+       instruction->info.load_store.offset.offset = offset<<shift;
+
+       return ERROR_OK;
+}
+
+int evaluate_load_store_stack_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u32 offset = opcode  & 0xff;
+       u8 Rd = (opcode >> 8) & 0x7; 
+       u32 L = opcode & (1<<11);
+       char *mnemonic;
+
+       if (L)
+       {
+               instruction->type = ARM_LDR;
+               mnemonic = "LDR";
+       }
+       else
+       {
+               instruction->type = ARM_STR;
+               mnemonic = "STR";
+       }
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [SP, #0x%x]", address, opcode, mnemonic, Rd, offset*4);
+       
+       instruction->info.load_store.Rd = Rd;
+       instruction->info.load_store.Rn = 13 /*SP*/;
+       instruction->info.load_store.index_mode = 0; /*offset*/
+       instruction->info.load_store.offset_mode = 0; /*immediate*/
+       instruction->info.load_store.offset.offset = offset*4;
+
+       return ERROR_OK;
+}
+
+int evaluate_add_sp_pc_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u32 imm = opcode  & 0xff;
+       u8 Rd = (opcode >> 8) & 0x7; 
+       u8 Rn;
+       u32 SP = opcode & (1<<11);
+       char *reg_name;
+
+       instruction->type = ARM_ADD;
+       
+       if (SP)
+       {
+               reg_name = "SP";
+               Rn = 13;
+       }
+       else
+       {
+               reg_name = "PC";
+               Rn = 15;
+       }
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tADD r%i, %s, #0x%x", address, opcode, Rd,reg_name, imm*4);
+
+       instruction->info.data_proc.variant = 0 /* immediate */;
+       instruction->info.data_proc.Rd = Rd;
+       instruction->info.data_proc.Rn = Rn;
+       instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4;
+
+       return ERROR_OK;
+}
+
+int evaluate_adjust_stack_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u32 imm = opcode  & 0x7f;
+       u8 opc = opcode & (1<<7);
+       char *mnemonic;
+
+       
+       if (opc)
+       {
+               instruction->type = ARM_SUB;
+               mnemonic = "SUB";
+       }
+       else
+       {
+               instruction->type = ARM_ADD;
+               mnemonic = "ADD";
+       }
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s SP, #0x%x", address, opcode, mnemonic, imm*4);
+
+       instruction->info.data_proc.variant = 0 /* immediate */;
+       instruction->info.data_proc.Rd = 13 /*SP*/;
+       instruction->info.data_proc.Rn = 13 /*SP*/;
+       instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4;
+
+       return ERROR_OK;
+}
+
+int evaluate_breakpoint_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u32 imm = opcode  & 0xff;
+       
+       instruction->type = ARM_BKPT;
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tBKPT 0x%02x", address, opcode, imm);
+
+       return ERROR_OK;
+}
+
+int evaluate_load_store_multiple_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u32 reg_list = opcode  & 0xff;
+       u32 L = opcode & (1<<11);
+       u32 R = opcode & (1<<8);
+       u8 Rn = (opcode >> 8) & 7;
+       u8 addr_mode = 0 /* IA */;
+       char reg_names[40];
+       char *reg_names_p;
+       char *mnemonic;
+       char ptr_name[7] = "";
+       int i;  
+
+       if ((opcode & 0xf000) == 0xc000)
+       { /* generic load/store multiple */
+               if (L)
+               {
+                       instruction->type = ARM_LDM;
+                       mnemonic = "LDMIA";
+               }
+               else
+               {
+                       instruction->type = ARM_STM;
+                       mnemonic = "STMIA";
+               }
+               snprintf(ptr_name,7,"r%i!, ",Rn);
+       }
+       else
+       { /* push/pop */
+               Rn = 13; /* SP */
+               if (L)
+               {
+                       instruction->type = ARM_LDM;
+                       mnemonic = "POP";
+                       if (R)
+                               reg_list |= (1<<15) /*PC*/;
+               }
+               else
+               {
+                       instruction->type = ARM_STM;
+                       mnemonic = "PUSH";
+                       addr_mode = 3; /*DB*/
+                       if (R)
+                               reg_list |= (1<<14) /*LR*/;
+               }
+       }
+
+       reg_names_p = reg_names;
+       for (i = 0; i <= 15; i++)
+       {
+               if (reg_list & (1<<i))
+                       reg_names_p += snprintf(reg_names_p, (reg_names + 40 - reg_names_p), "r%i, ", i);
+       }
+       if (reg_names_p>reg_names)
+               reg_names_p[-2] = '\0';
+       else /* invalid op : no registers */
+               reg_names[0] = '\0';
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s %s{%s}", address, opcode, mnemonic, ptr_name,reg_names);
+
+       instruction->info.load_store_multiple.register_list = reg_list;
+       instruction->info.load_store_multiple.Rn = Rn;
+       instruction->info.load_store_multiple.addressing_mode = addr_mode;
+
+       return ERROR_OK;
+}
+
+int evaluate_cond_branch_thumb(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u32 offset = opcode  & 0xff;
+       u8 cond = (opcode >> 8) & 0xf;
+       u32 target_address;
+
+       if (cond == 0xf)
+       {
+               instruction->type = ARM_SWI;
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tSWI 0x%02x", address, opcode, offset);
+               return ERROR_OK;
+       }
+       else if (cond == 0xe)
+       {
+               instruction->type = ARM_UNDEFINED_INSTRUCTION;
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address, opcode);
+               return ERROR_OK;
+       }
+
+       /* sign extend 8-bit offset */
+       if (offset & 0x00000080)
+               offset = 0xffffff00 | offset;
+       
+       target_address = address + 4 + (offset<<1);
+
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tB%s 0x%8.8x", address, opcode,
+                        arm_condition_strings[cond], target_address);
+       
+       instruction->type = ARM_B;
+       instruction->info.b_bl_bx_blx.reg_operand = -1;
+       instruction->info.b_bl_bx_blx.target_address = target_address;
+
+       return ERROR_OK;
+}
+
+int thumb_evaluate_opcode(u16 opcode, u32 address, arm_instruction_t *instruction)
+{
+       /* clear fields, to avoid confusion */
+       memset(instruction, 0, sizeof(arm_instruction_t));
+       instruction->opcode = opcode;
+       
+       if ((opcode & 0xe000) == 0x0000)
+       {
+               /* add/substract register or immediate */
+               if ((opcode & 0x1800) == 0x1800)
+                       return evaluate_add_sub_thumb(opcode, address, instruction);
+               /* shift by immediate */
+               else
+                       return evaluate_shift_imm_thumb(opcode, address, instruction);
+       }
+       
+       /* Add/substract/compare/move immediate */
+       if ((opcode & 0xe000) == 0x2000)
+       {
+               return evaluate_data_proc_imm_thumb(opcode, address, instruction);
+       }
+       
+       /* Data processing instructions */
+       if ((opcode & 0xf800) == 0x4000)
+       {
+               return evaluate_data_proc_thumb(opcode, address, instruction);
+       }
+       
+       /* Load from literal pool */
+       if ((opcode & 0xf800) == 0x4800)
+       {
+               return evaluate_load_literal_thumb(opcode, address, instruction);
+       }
+
+       /* Load/Store register offset */
+       if ((opcode & 0xf000) == 0x5000)
+       {
+               return evaluate_load_store_reg_thumb(opcode, address, instruction);
+       }
+
+       /* Load/Store immediate offset */
+       if (((opcode & 0xe000) == 0x6000)
+               ||((opcode & 0xf000) == 0x8000))
+       {
+               return evaluate_load_store_imm_thumb(opcode, address, instruction);
+       }
+       
+       /* Load/Store from/to stack */
+       if ((opcode & 0xf000) == 0x9000)
+       {
+               return evaluate_load_store_stack_thumb(opcode, address, instruction);
+       }
+
+       /* Add to SP/PC */
+       if ((opcode & 0xf000) == 0xa000)
+       {
+               return evaluate_add_sp_pc_thumb(opcode, address, instruction);
+       }
+
+       /* Misc */
+       if ((opcode & 0xf000) == 0xb000)
+       {
+               if ((opcode & 0x0f00) == 0x0000)
+                       return evaluate_adjust_stack_thumb(opcode, address, instruction);
+               else if ((opcode & 0x0f00) == 0x0e00)
+                       return evaluate_breakpoint_thumb(opcode, address, instruction);
+               else if ((opcode & 0x0600) == 0x0400) /* push pop */
+                       return evaluate_load_store_multiple_thumb(opcode, address, instruction);
+               else
+               {
+                       instruction->type = ARM_UNDEFINED_INSTRUCTION;
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address, opcode);
+                       return ERROR_OK;
+               }
+       }
+
+       /* Load/Store multiple */
+       if ((opcode & 0xf000) == 0xc000)
+       {
+               return evaluate_load_store_multiple_thumb(opcode, address, instruction);
+       }
+
+       /* Conditional branch + SWI */
+       if ((opcode & 0xf000) == 0xd000)
+       {
+               return evaluate_cond_branch_thumb(opcode, address, instruction);
+       }
+       
+       if ((opcode & 0xe000) == 0xe000)
+       {
+               /* Undefined instructions */
+               if ((opcode & 0xf801) == 0xe801)
+               {
+                       instruction->type = ARM_UNDEFINED_INSTRUCTION;
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
+                       return ERROR_OK;
+               }
+               else
+               { /* Branch to offset */
+                       return evaluate_b_bl_blx_thumb(opcode, address, instruction);
+               }
+       }
+
+       ERROR("should never reach this point (opcode=%04x)",opcode);
+       return -1;
+}
+
index b55c885507bae16611fdeb489a868f5cc27a9c90..bdab113ddaa6e855a26a19aa0453dc8e7affaf49 100644 (file)
@@ -133,7 +133,7 @@ union arm_shifter_operand
        } immediate;
        struct {
                u8 Rm;
-               u8 shift;
+               u8 shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */
                u8 shift_imm;
        } immediate_shift;
        struct {
@@ -164,7 +164,7 @@ typedef struct arm_load_store_instr_s
                u32 offset;
                struct {
                        u8 Rm;
-                       u8 shift;
+                       u8 shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */
                        u8 shift_imm;
                } reg;
        } offset;
@@ -195,6 +195,7 @@ typedef struct arm_instruction_s
 } arm_instruction_t;
 
 extern int arm_evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction);
+extern int thumb_evaluate_opcode(u16 opcode, u32 address, arm_instruction_t *instruction);
 
 #define COND(opcode) (arm_condition_strings[(opcode & 0xf0000000)>>28])
 
index fd0b309cec7338cfd0740df58f021d9dd22ae456..561b14f8f2c71bbbadf7738a0dcbae2cb0fdff95 100644 (file)
@@ -257,6 +257,11 @@ int pass_condition(u32 cpsr, u32 opcode)
        return 0;
 }
 
+int thumb_pass_branch_condition(u32 cpsr, u16 opcode)
+{
+       return pass_condition(cpsr, (opcode & 0x0f00) << 20); 
+}
+
 /* simulate a single step (if possible)
  * if the dry_run_pc argument is provided, no state is changed,
  * but the new pc is stored in the variable pointed at by the argument
@@ -275,26 +280,43 @@ int arm_simulate_step(target_t *target, u32 *dry_run_pc)
                target_read_u32(target, current_pc, &opcode);
                arm_evaluate_opcode(opcode, current_pc, &instruction);
                instruction_size = 4;
+               
+               /* check condition code (for all instructions) */
+               if (!pass_condition(buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), opcode))
+               {
+                       if (dry_run_pc)
+                       {
+                               *dry_run_pc = current_pc + instruction_size;
+                       }
+                       else
+                       {
+                               buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
+                       }
+                       
+                       return ERROR_OK;
+               }
        }
        else
        {
-               /* TODO: add support for Thumb instruction set */
+               target_read_u32(target, current_pc, &opcode);
+               arm_evaluate_opcode(opcode, current_pc, &instruction);
                instruction_size = 2;
-       }
-       
-       /* check condition code */
-       if (!pass_condition(buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), opcode))
-       {
-               if (dry_run_pc)
-               {
-                       *dry_run_pc = current_pc + instruction_size;
-               }
-               else
+               
+               /* check condition code (only for branch instructions) */
+               if ((!thumb_pass_branch_condition(buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), opcode)) &&
+                       (instruction.type == ARM_B))
                {
-                       buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
+                       if (dry_run_pc)
+                       {
+                               *dry_run_pc = current_pc + instruction_size;
+                       }
+                       else
+                       {
+                               buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, current_pc + instruction_size);
+                       }
+                       
+                       return ERROR_OK;
                }
-               
-               return ERROR_OK;
        }
        
        /* examine instruction type */
index 0ba94ff7cbe5c79932ff1f4c6d55e7b5b47a0c97..36264f3583bcb5c29b4f20bfa6a0da71207352f2 100644 (file)
@@ -23,7 +23,7 @@
 #include "register.h"
 #include "target.h"
 
-enum armv4_5_mode
+typedef enum armv4_5_mode
 {
        ARMV4_5_MODE_USR = 16, 
        ARMV4_5_MODE_FIQ = 17, 
@@ -33,16 +33,16 @@ enum armv4_5_mode
        ARMV4_5_MODE_UND = 27,
        ARMV4_5_MODE_SYS = 31,
        ARMV4_5_MODE_ANY = -1
-};
+} armv4_5_mode_t;
 
 extern char* armv4_5_mode_strings[];
 
-enum armv4_5_state
+typedef enum armv4_5_state
 {
        ARMV4_5_STATE_ARM,
        ARMV4_5_STATE_THUMB,
        ARMV4_5_STATE_JAZELLE,
-};
+} armv4_5_state_t;
 
 extern char* armv4_5_state_strings[];
 
index 21f250aa7f3e3b34c419e236eaeacfd8b0e0e023..257c4b182a27c334b93f801415762c571ddfd55a 100644 (file)
 #include "config.h"
 #endif
 
+#include <string.h>
+
 #include "arm7_9_common.h"
 #include "etb.h"
+#include "etm.h"
 
 #include "log.h"
 #include "types.h"
@@ -55,16 +58,7 @@ int etb_set_reg_w_exec(reg_t *reg, u8 *buf);
 int etb_write_reg(reg_t *reg, u32 value);
 int etb_read_reg(reg_t *reg);
 
-int handle_arm7_9_etb_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_arm7_9_etb_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-char *etmv1_branch_reason_string[] =
-{
-       "normal pc change", "tracing enabled", "restart after FIFO overflow",
-       "exit from debug state", "peridoic synchronization point",
-       "reserved", "reserved", "reserved"
-};
-
+int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
 int etb_set_instr(etb_t *etb, u32 new_instr)
 {
@@ -180,6 +174,74 @@ int etb_get_reg(reg_t *reg)
        return ERROR_OK;
 }
 
+int etb_read_ram(etb_t *etb, u32 *data, int num_frames)
+{
+       scan_field_t fields[3];
+       int i;
+       
+       jtag_add_end_state(TAP_RTI);
+       etb_scann(etb, 0x0);
+       etb_set_instr(etb, 0xc);
+       
+       fields[0].device = etb->chain_pos;
+       fields[0].num_bits = 32;
+       fields[0].out_value = NULL;
+       fields[0].out_mask = NULL;
+       fields[0].in_value = NULL;
+       fields[0].in_check_value = NULL;
+       fields[0].in_check_mask = NULL;
+       fields[0].in_handler = NULL;
+       fields[0].in_handler_priv = NULL;
+       
+       fields[1].device = etb->chain_pos;
+       fields[1].num_bits = 7;
+       fields[1].out_value = malloc(1);
+       buf_set_u32(fields[1].out_value, 0, 7, 4);
+       fields[1].out_mask = NULL;
+       fields[1].in_value = NULL;
+       fields[1].in_check_value = NULL;
+       fields[1].in_check_mask = NULL;
+       fields[1].in_handler = NULL;
+       fields[1].in_handler_priv = NULL;
+
+       fields[2].device = etb->chain_pos;
+       fields[2].num_bits = 1;
+       fields[2].out_value = malloc(1);
+       buf_set_u32(fields[2].out_value, 0, 1, 0);
+       fields[2].out_mask = NULL;
+       fields[2].in_value = NULL;
+       fields[2].in_check_value = NULL;
+       fields[2].in_check_mask = NULL;
+       fields[2].in_handler = NULL;
+       fields[2].in_handler_priv = NULL;
+       
+       jtag_add_dr_scan(3, fields, -1, NULL);
+
+       fields[0].in_handler = buf_to_u32_handler;
+       
+       for (i = 0; i < num_frames; i++)
+       {
+               /* ensure nR/W reamins set to read */
+               buf_set_u32(fields[2].out_value, 0, 1, 0);
+               
+               /* address remains set to 0x4 (RAM data) until we read the last frame */
+               if (i < num_frames - 1)
+                       buf_set_u32(fields[1].out_value, 0, 7, 4);
+               else
+                       buf_set_u32(fields[1].out_value, 0, 7, 0);
+               
+               fields[0].in_handler_priv = &data[i];
+               jtag_add_dr_scan(3, fields, -1, NULL);
+       }
+       
+       jtag_execute_queue();
+       
+       free(fields[1].out_value);
+       free(fields[2].out_value);
+       
+       return ERROR_OK;
+}
+
 int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask)
 {
        etb_reg_t *etb_reg = reg->arch_info;
@@ -333,293 +395,266 @@ int etb_store_reg(reg_t *reg)
        return etb_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
 }
 
-int etb_register_commands(struct command_context_s *cmd_ctx, command_t *arm7_9_cmd)
+int etb_register_commands(struct command_context_s *cmd_ctx)
 {
-       register_command(cmd_ctx, arm7_9_cmd, "etb", handle_arm7_9_etb_command, COMMAND_CONFIG, NULL);
+       command_t *etb_cmd;
+       
+       etb_cmd = register_command(cmd_ctx, NULL, "etb", NULL, COMMAND_ANY, "Embedded Trace Buffer");
+       
+       register_command(cmd_ctx, etb_cmd, "config", handle_etb_config_command, COMMAND_CONFIG, NULL);
+
+       return ERROR_OK;
+}
 
-       register_command(cmd_ctx, arm7_9_cmd, "etb_dump", handle_arm7_9_etb_dump_command, COMMAND_EXEC, "dump current ETB content");
+int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target;
+       jtag_device_t *jtag_device;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       
+       if (argc != 2)
+       {
+               ERROR("incomplete 'etb config <target> <chain_pos>' command");
+               exit(-1);
+       }
+       
+       target = get_target_by_num(strtoul(args[0], NULL, 0));
+       
+       if (!target)
+       {
+               ERROR("target number '%s' not defined", args[0]);
+               exit(-1);
+       }
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       jtag_device = jtag_get_device(strtoul(args[1], NULL, 0));
+       
+       if (!jtag_device)
+       {
+               ERROR("jtag device number '%s' not defined", args[1]);
+               exit(-1);
+       }
+       
+       if (arm7_9->etm_ctx)
+       {
+               etb_t *etb = malloc(sizeof(etb_t));
+               
+               arm7_9->etm_ctx->capture_driver_priv = etb;
+               
+               etb->chain_pos = strtoul(args[1], NULL, 0);
+               etb->cur_scan_chain = -1;
+               etb->reg_cache = NULL;
+               etb->ram_width = 0;
+               etb->ram_depth = 0;
+       }
+       else
+       {
+               ERROR("target has no ETM defined, ETB left unconfigured");
+       }
 
        return ERROR_OK;
 }
 
-#define PIPESTAT(x) ((x) & 0x7)
-#define TRACEPKT(x) (((x) & 0x7fff8) >> 3)
-#define TRACESYNC(x) (((x) & 0x80000) >> 19)
+int etb_init(etm_context_t *etm_ctx)
+{
+       etb_t *etb = etm_ctx->capture_driver_priv;
+       
+       etb->etm_ctx = etm_ctx;
+       
+       /* identify ETB RAM depth and width */
+       etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]);
+       etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]);
+       jtag_execute_queue();
+
+       etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32);
+       etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32);
+       
+       return ERROR_OK;
+}
 
-int etmv1_next_packet(int trace_depth, u32 *trace_data, int frame, int *port_half, int apo, u8 *packet)
+trace_status_t etb_status(etm_context_t *etm_ctx)
 {
-       while (frame < trace_depth)
+       etb_t *etb = etm_ctx->capture_driver_priv;
+       
+       etb->etm_ctx = etm_ctx;
+       
+       /* if tracing is currently idle, return this information */
+       if (etm_ctx->capture_status == TRACE_IDLE)
        {
-               if (apo > 0)
-               {
-                       if (TRACESYNC(trace_data[frame]))
-                               apo--;
-               }
-               else
+               return etm_ctx->capture_status;
+       }
+       else if (etm_ctx->capture_status & TRACE_RUNNING)
+       {
+               reg_t *etb_status_reg = &etb->reg_cache->reg_list[ETB_STATUS];
+               int etb_timeout = 100;
+               
+               /* trace is running, check the ETB status flags */
+               etb_get_reg(etb_status_reg);
+       
+               /* check Full bit to identify an overflow */
+               if (buf_get_u32(etb_status_reg->value, 0, 1) == 1)
+                       etm_ctx->capture_status |= TRACE_OVERFLOWED;
+
+               /* check Triggered bit to identify trigger condition */
+               if (buf_get_u32(etb_status_reg->value, 1, 1) == 1)
+                       etm_ctx->capture_status |= TRACE_TRIGGERED;
+
+               /* check AcqComp to identify trace completion */
+               if (buf_get_u32(etb_status_reg->value, 2, 1) == 1)
                {
-                       /* we're looking for a branch address, skip if TRACESYNC isn't set */
-                       if ((apo == 0) && (!TRACESYNC(trace_data[frame])))
+                       while (etb_timeout-- && (buf_get_u32(etb_status_reg->value, 3, 1) == 0))
                        {
-                               frame++;
-                               continue;
+                               /* wait for data formatter idle */
+                               etb_get_reg(etb_status_reg);
                        }
-                               
-                       /* TRACEPKT is valid if this isn't a TD nor a TRIGGER cycle */
-                       if (((PIPESTAT(trace_data[frame]) != 0x7) && (PIPESTAT(trace_data[frame]) != 0x6))
-                               && !((apo == 0) && (!TRACESYNC(trace_data[frame]))))
+                       
+                       if (etb_timeout == 0)
+                       {
+                               ERROR("AcqComp set but DFEmpty won't go high, ETB status: 0x%x",
+                                       buf_get_u32(etb_status_reg->value, 0, etb_status_reg->size));
+                       }
+                       
+                       if (!(etm_ctx->capture_status && TRACE_TRIGGERED))
                        {
-                               if (*port_half == 0)
-                               {
-                                       *packet = TRACEPKT(trace_data[frame]) & 0xff;
-                                       *port_half = 1;
-                               }
-                               else
-                               {
-                                       *packet = (TRACEPKT(trace_data[frame]) & 0xff00) >> 8;
-                                       *port_half = 0;
-                                       frame++;
-                               }
-                               return frame;
+                               ERROR("trace completed, but no trigger condition detected");
                        }
+                       
+                       etm_ctx->capture_status &= ~TRACE_RUNNING;
+                       etm_ctx->capture_status |= TRACE_COMPLETED;
                }
-               frame++;
        }
        
-       /* we reached the end of the trace without finding the packet we're looking for
-        * tracing is finished
-        */
-       return -1;
+       return etm_ctx->capture_status;
 }
 
-int handle_arm7_9_etb_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+int etb_read_trace(etm_context_t *etm_ctx)
 {
-       int retval;
-       target_t *target = get_current_target(cmd_ctx);
-       armv4_5_common_t *armv4_5;
-       arm7_9_common_t *arm7_9;
-       int i, j, k;
+       etb_t *etb = etm_ctx->capture_driver_priv;
        int first_frame = 0;
-       int last_frame;
-       int addressbits_valid = 0;
-       u32 address = 0x0;
-       u32 *trace_data;
-       int port_half = 0;
-       int last_instruction = -1;
-       u8 branch_reason;
-       u8 packet;
-       char trace_output[256];
-       int trace_output_len;
-       u8 apo;
-
-       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
-       {
-               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
-               return ERROR_OK;
-       }
+       int num_frames = etb->ram_depth;
+       u32 *trace_data = NULL;
+       int i, j;
+       
+       etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]);
+       etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]);
+       jtag_execute_queue();
        
-       if (!arm7_9->etb)
+       /* check if we overflowed, and adjust first frame of the trace accordingly
+        * if we didn't overflow, read only up to the frame that would be written next,
+        * i.e. don't read invalid entries
+        */
+       if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1))
        {
-               command_print(cmd_ctx, "no ETB configured for current target");
-               return ERROR_OK;
+               first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32);
        }
-       
-       if (!(arm7_9->etb->RAM_depth && arm7_9->etb->RAM_width))
+       else
        {
-               /* identify ETB RAM depth and width */
-               etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_DEPTH]);
-               etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_WIDTH]);
-               jtag_execute_queue();
-       
-               arm7_9->etb->RAM_depth = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32);
-               arm7_9->etb->RAM_width = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32);
+               num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32);
        }
        
-       trace_data = malloc(sizeof(u32) * arm7_9->etb->RAM_depth);
-       
-       etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_STATUS]);
-       etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]);
-       jtag_execute_queue();
-       
-       /* check if we overflowed, and adjust first and last frame of the trace accordingly */
-       if (buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_STATUS].value, 1, 1))
+       etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame);
+
+       /* read data into temporary array for unpacking */      
+       trace_data = malloc(sizeof(u32) * num_frames);
+       etb_read_ram(etb, trace_data, num_frames);
+
+       if (etm_ctx->trace_depth > 0)
        {
-               first_frame = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32);
+               free(etm_ctx->trace_data);
        }
        
-       last_frame = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32) - 1;
-       
-       etb_write_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame);
+       if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED)
+               etm_ctx->trace_depth = num_frames * 2;
+       else
+               etm_ctx->trace_depth = num_frames;
 
-       /* read trace data from ETB */
-       i = first_frame;
-       j = 0;
-       do {
-               etb_read_reg(&arm7_9->etb->reg_cache->reg_list[ETB_RAM_DATA]);
-               jtag_execute_queue();
-               trace_data[j++] = buf_get_u32(arm7_9->etb->reg_cache->reg_list[ETB_RAM_DATA].value, 0, 32);
-               i++;
-       } while ((i % arm7_9->etb->RAM_depth) != (first_frame % arm7_9->etb->RAM_depth));
+       etm_ctx->trace_data= malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth);
        
-       for (i = 0, j = 0; i < arm7_9->etb->RAM_depth; i++)
+       for (i = 0, j = 0; i < num_frames; i++)
        {
-               int trigger = 0;
-               
-               trace_output_len = 0;
-               
-               /* catch trigger, actual PIPESTAT is encoded in TRACEPKT[2:0] */
-               if (PIPESTAT(trace_data[i]) == 0x6)
+               if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED)
                {
-                       trigger = 1;
-                       trace_data[i] &= ~0x7;
-                       trace_data[i] |= TRACEPKT(trace_data[i]) & 0x7;
-               }
-       
-               if (addressbits_valid == 32)
-               {
-                       trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                               "%i: 0x%8.8x %s", i, address, (trigger) ? "(TRIGGER) " : "");
-               }
-               else if (addressbits_valid != 0)
-               {
-                       trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                               "%i: 0x...%x %s", i, address, (trigger) ? "(TRIGGER) " : "");
+                       etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
+                       etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3;
+                       etm_ctx->trace_data[j].tracesync = (trace_data[i] & 0x800) >> 11;
+
+                       etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x7000) >> 12;
+                       etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7f8000) >> 15;
+                       etm_ctx->trace_data[j+1].tracesync = (trace_data[i] & 0x800000) >> 23;
+                       
+                       j += 2;
                }
                else
                {
-                       trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                               "%i: 0xUNK %s", i, (trigger) ? "(TRIGGER) " : "");
-               }
-               
-               switch (PIPESTAT(trace_data[i]))
-               {
-                       case 0x0:
-                               trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                                       "IE");
-                               break;
-                       case 0x1:
-                               trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                                       "ID");
-                               break;
-                       case 0x2:
-                               /* Instruction exectued - TRACEPKT might be valid, but belongs to another cycle */
-                               trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                                       "IN");
-                               break;
-                       case 0x3:
-                               /* WAIT cycle - TRACEPKT is valid, but belongs to another cycle */
-                               trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                                       "WT");
-                               break;
-                       case 0x4:
-                               /* following a branch two APO cycles are output on PIPESTAT[1:0]
-                                * but another BE/BD could overwrite the current branch,
-                                * or a trigger could cause the APO to be output on TRACEPKT[1:0]
-                                */
-                               if ((PIPESTAT(trace_data[i + 1]) == 0x4)
-                                       || (PIPESTAT(trace_data[i + 1]) == 0x5))
-                               {
-                                       /* another branch occured, we ignore this one */
-                                       j = (j < i + 1) ? i + 1 : j;
-                                       break;
-                               }
-                               else if (PIPESTAT(trace_data[i + 1]) == 0x6)
-                               {
-                                       apo = TRACEPKT(trace_data[i + 1]) & 0x3;
-                               }
-                               else
-                               {
-                                       apo = PIPESTAT(trace_data[i + 1]) & 0x3;
-                               }
-
-                               if ((PIPESTAT(trace_data[i + 2]) == 0x4)
-                                       || (PIPESTAT(trace_data[i + 2]) == 0x5))
-                               {
-                                       j = (j < i + 2) ? i + 1 : j;
-                                       i = i + 1;
-                                       break;
-                               }
-                               else if (PIPESTAT(trace_data[i + 2]) == 0x6)
-                               {
-                                       apo |= (TRACEPKT(trace_data[i + 2]) & 0x3) << 2;
-                               }
-                               else
-                               {
-                                       apo = (PIPESTAT(trace_data[i + 1]) & 0x3) << 2;
-                               }
-                               
-                               branch_reason = -1;
-                               k = 0;
-                               do
-                               {
-                                       if ((j = etmv1_next_packet(arm7_9->etb->RAM_depth, trace_data, j, &port_half, apo, &packet)) != -1)
-                                       {
-                                               address &= ~(0x7f << (k * 7));
-                                               address |= (packet & 0x7f) << (k * 7);
-                                       }
-                                       else
-                                       {
-                                               break;
-                                       }
-                                       k++;
-                               } while ((k < 5) && (packet & 0x80));
-                               
-                               if (addressbits_valid < ((k * 7 > 32) ? 32 : k * 7))
-                                       addressbits_valid = (k * 7 > 32) ? 32 : k * 7;
-                               
-                               if (k == 5)
-                               {
-                                       branch_reason = (packet & 0x7) >> 4;
-                                       trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                                               "BE 0x%x (/%i) (%s)", address, addressbits_valid, etmv1_branch_reason_string[branch_reason]);
-                               }
-                               else
-                               {
-                                       trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                                               "BE 0x%x (/%i)", address, addressbits_valid);
-                               }
-                               
-                               break;
-                       case 0x5:
-                               trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                                       "BD");
-                               break;
-                       case 0x6:
-                               /* We catch the trigger event before we get here */
-                               ERROR("TR pipestat should have been caught earlier");
-                               trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                                       "--");
-                               break;
-                       case 0x7:
-                               /* TRACE disabled - TRACEPKT = invalid */
-                               trace_output_len += snprintf(trace_output + trace_output_len, 256 - trace_output_len,
-                                       "TD");
-                               break;
-               }
-               
-               /* PIPESTAT other than WT (b011) and TD (b111) mean we executed an instruction */
-               if ((PIPESTAT(trace_data[i]) & 0x3) != 0x3)
-               {
-                       last_instruction = i;
-                       address += 4;
+                       etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
+                       etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3;
+                       etm_ctx->trace_data[j].tracesync = (trace_data[i] & 0x80000) >> 19;
+                       
+                       j += 1;
                }
+       }
+       
+       free(trace_data);
+       
+       return ERROR_OK;
+}
 
-               /* The group of packets for a particular instruction cannot start on or before any
-                * previous functional PIPESTAT (IE, IN, ID, BE, or BD)
-                */
-               if (j < last_instruction)
-               {
-                       j = last_instruction + 1;
-               }
+int etb_start_capture(etm_context_t *etm_ctx)
+{
+       etb_t *etb = etm_ctx->capture_driver_priv;
+       u32 etb_ctrl_value = 0x1;
 
-               /* restore trigger PIPESTAT to ensure TRACEPKT is ignored */            
-               if (trigger == 1)
+       if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED)
+       {
+               if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT)
                {
-                       trace_data[i] &= ~0x7;
-                       trace_data[i] |= 0x6;   
+                       DEBUG("ETB can't run in demultiplexed mode with a 16-bit port");
+                       return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
                }
-               
-               command_print(cmd_ctx, "%s (raw: 0x%8.8x)", trace_output, trace_data[i]);
+               etb_ctrl_value |= 0x2;
        }
        
+       if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED)
+               return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
+       
+       etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], 0x600);
+       etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0);
+       etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value);
+       jtag_execute_queue();
+       
+       /* we're starting a new trace, initialize capture status */
+       etm_ctx->capture_status = TRACE_RUNNING;
+       
+       return ERROR_OK; 
+}
+
+int etb_stop_capture(etm_context_t *etm_ctx)
+{
+       etb_t *etb = etm_ctx->capture_driver_priv;
+       reg_t *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL];
+
+       etb_write_reg(etb_ctrl_reg, 0x0);
+       jtag_execute_queue();
+       
+       /* trace stopped, just clear running flag, but preserve others */ 
+       etm_ctx->capture_status &= ~TRACE_RUNNING;
+       
        return ERROR_OK;
 }
+
+etm_capture_driver_t etb_capture_driver =
+{
+       .name = "etb",
+       .register_commands = etb_register_commands,
+       .init = etb_init,
+       .status = etb_status,
+       .start_capture = etb_start_capture,
+       .stop_capture = etb_stop_capture,
+       .read_trace = etb_read_trace,
+};
index 12e613ffc3659f658690b0b01d21a05f41aceb08..1a579cb39d7954e733652867810792b3dd139eef 100644 (file)
@@ -25,6 +25,9 @@
 #include "register.h"\r
 #include "arm_jtag.h"\r
 \r
+#include "etb.h"\r
+#include "etm.h"\r
+\r
 /* ETB registers */\r
 enum\r
 {\r
@@ -41,13 +44,14 @@ enum
 \r
 typedef struct etb_s\r
 {\r
+       etm_context_t *etm_ctx;\r
        int chain_pos;\r
        int cur_scan_chain;\r
        reg_cache_t *reg_cache;\r
        \r
        /* ETB parameters */\r
-       int RAM_depth;\r
-       int RAM_width;\r
+       int ram_depth;\r
+       int ram_width;\r
 } etb_t;\r
 \r
 typedef struct etb_reg_s\r
@@ -56,6 +60,8 @@ typedef struct etb_reg_s
        etb_t *etb;\r
 } etb_reg_t;\r
 \r
+extern etm_capture_driver_t etb_capture_driver;\r
+\r
 extern reg_cache_t* etb_build_reg_cache(etb_t *etb);\r
 extern int etb_read_reg(reg_t *reg);\r
 extern int etb_write_reg(reg_t *reg, u32 value);\r
@@ -64,6 +70,6 @@ extern int etb_store_reg(reg_t *reg);
 extern int etb_set_reg(reg_t *reg, u32 value);\r
 extern int etb_set_reg_w_exec(reg_t *reg, u8 *buf);\r
 \r
-extern int etb_register_commands(struct command_context_s *cmd_ctx, command_t *arm7_9_cmd);\r
+extern int etb_register_commands(struct command_context_s *cmd_ctx);\r
 \r
 #endif /* ETB_H */\r
index 016130d5db871a3cd01b95f525b0966d955d7fa4..02c33104a35c08285944102fc03669018ba6a4d1 100644 (file)
 #include "config.h"
 #endif
 
+#include <string.h>
+
 #include "etm.h"
+#include "etb.h"
 
 #include "armv4_5.h"
 #include "arm7_9_common.h"
 #include "target.h"
 #include "register.h"
 #include "jtag.h"
+#include "fileio.h"
 
 #include <stdlib.h>
 
+/* ETM register access functionality 
+ * 
+ */
+
 bitfield_desc_t etm_comms_ctrl_bitfield_desc[] = 
 {
        {"R", 1},
@@ -204,13 +212,16 @@ int etm_set_reg_w_exec(reg_t *reg, u8 *buf);
 int etm_write_reg(reg_t *reg, u32 value);
 int etm_read_reg(reg_t *reg);
 
-reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg)
+command_t *etm_cmd = NULL;
+
+reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx)
 {
        reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t));
        reg_t *reg_list = NULL;
        etm_reg_t *arch_info = NULL;
        int num_regs = sizeof(etm_reg_arch_info)/sizeof(int);
        int i;
+       u32 etm_ctrl_value;
        
        /* register a register arch-type for etm registers only once */
        if (etm_reg_arch_type == -1)
@@ -242,6 +253,44 @@ reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int ex
                arch_info[i].addr = etm_reg_arch_info[i];
                arch_info[i].jtag_info = jtag_info;
        }
+
+       /* initialize some ETM control register settings */     
+       etm_get_reg(&reg_list[ETM_CTRL]);
+       etm_ctrl_value = buf_get_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size);
+       
+       /* clear the ETM powerdown bit (0) */
+       etm_ctrl_value &= ~0x1;
+               
+       /* configure port width (6:4), mode (17:16) and clocking (13) */
+       etm_ctrl_value = (etm_ctrl_value & 
+               ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK)
+               | etm_ctx->portmode;
+       
+       buf_set_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size, etm_ctrl_value);
+       etm_store_reg(&reg_list[ETM_CTRL]);
+       
+       /* the ETM might have an ETB connected */
+       if (strcmp(etm_ctx->capture_driver->name, "etb") == 0)
+       {
+               etb_t *etb = etm_ctx->capture_driver_priv;
+               
+               if (!etb)
+               {
+                       ERROR("etb selected as etm capture driver, but no ETB configured");
+                       return ERROR_OK;
+               }
+               
+               reg_cache->next = etb_build_reg_cache(etb);
+               
+               etb->reg_cache = reg_cache->next;
+               
+               if (etm_ctx->capture_driver->init(etm_ctx) != ERROR_OK)
+               {
+                       ERROR("ETM capture driver initialization failed");
+                       exit(-1);
+               }
+       }
+       
        return reg_cache;
 }
 
@@ -410,3 +459,638 @@ int etm_store_reg(reg_t *reg)
        return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
 }
 
+/* ETM trace analysis functionality
+ * 
+ */
+extern etm_capture_driver_t etb_capture_driver;
+
+etm_capture_driver_t *etm_capture_drivers[] = 
+{
+       &etb_capture_driver,
+       NULL
+};
+
+char *etmv1v1_branch_reason_strings[] =
+{
+       "normal PC change",
+       "tracing enabled",
+       "trace restarted after overflow",
+       "exit from debug",
+       "periodic synchronization",
+       "reserved",
+       "reserved",
+       "reserved",
+};
+
+int etmv1_next_packet(etm_context_t *ctx, u8 *packet)
+{
+       
+       
+       return ERROR_OK;
+}
+
+int etmv1_analyse_trace(etm_context_t *ctx)
+{
+       ctx->pipe_index = 0;
+       ctx->data_index = 0;
+       
+       while (ctx->pipe_index < ctx->trace_depth)
+       {
+               switch (ctx->trace_data[ctx->pipe_index].pipestat)
+               {
+                       case STAT_IE:
+                       case STAT_ID:
+                               break;
+                       case STAT_IN:
+                               DEBUG("IN");
+                               break;
+                       case STAT_WT:
+                               DEBUG("WT");
+                               break;
+                       case STAT_BE:
+                       case STAT_BD:
+                               break;
+                       case STAT_TD:
+                               /* TODO: in cycle accurate trace, we have to count cycles */
+                               DEBUG("TD");
+                               break;
+               }
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       etmv1_tracemode_t tracemode;
+       
+       target = get_current_target(cmd_ctx);
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       if (!arm7_9->etm_ctx)
+       {
+               command_print(cmd_ctx, "current target doesn't have an ETM configured");
+               return ERROR_OK;
+       }
+       
+       tracemode = arm7_9->etm_ctx->tracemode;
+
+       if (argc == 3)
+       {
+               if (strcmp(args[0], "none") == 0)
+               {
+                       tracemode = ETMV1_TRACE_NONE;
+               }
+               else if (strcmp(args[0], "data") == 0)
+               {
+                       tracemode = ETMV1_TRACE_DATA;
+               }
+               else if (strcmp(args[0], "address") == 0)
+               {
+                       tracemode = ETMV1_TRACE_ADDR;
+               }
+               else if (strcmp(args[0], "all") == 0)
+               {
+                       tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR;
+               }
+               else
+               {
+                       command_print(cmd_ctx, "invalid option '%s'", args[0]);
+                       return ERROR_OK;
+               }
+               
+               switch (strtol(args[1], NULL, 0))
+               {
+                       case 0:
+                               tracemode |= ETMV1_CONTEXTID_NONE;
+                               break;
+                       case 8:
+                               tracemode |= ETMV1_CONTEXTID_8;
+                               break;
+                       case 16:
+                               tracemode |= ETMV1_CONTEXTID_16;
+                               break;
+                       case 32:
+                               tracemode |= ETMV1_CONTEXTID_32;
+                               break;
+                       default:
+                               command_print(cmd_ctx, "invalid option '%s'", args[1]);
+                               return ERROR_OK;
+               }
+               
+               if (strcmp(args[2], "enable") == 0)
+               {
+                       tracemode |= ETMV1_CYCLE_ACCURATE;
+               }
+               else if (strcmp(args[2], "disable") == 0)
+               {
+                       tracemode |= 0;
+               }
+               else
+               {
+                       command_print(cmd_ctx, "invalid option '%s'", args[2]);
+                       return ERROR_OK;
+               }
+       }
+       else if (argc != 0)
+       {
+               command_print(cmd_ctx, "usage: configure trace mode <none|data|address|all> <context id bits> <enable|disable cycle accurate>");
+               return ERROR_OK;
+       }
+       
+       command_print(cmd_ctx, "current tracemode configuration:");
+       
+       switch (tracemode & ETMV1_TRACE_MASK)
+       {
+               case ETMV1_TRACE_NONE:
+                       command_print(cmd_ctx, "data tracing: none");
+                       break;
+               case ETMV1_TRACE_DATA:
+                       command_print(cmd_ctx, "data tracing: data only");
+                       break;
+               case ETMV1_TRACE_ADDR:
+                       command_print(cmd_ctx, "data tracing: address only");
+                       break;
+               case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR:
+                       command_print(cmd_ctx, "data tracing: address and data");
+                       break;
+       }
+       
+       switch (tracemode & ETMV1_CONTEXTID_MASK)
+       {
+               case ETMV1_CONTEXTID_NONE:
+                       command_print(cmd_ctx, "contextid tracing: none");
+                       break;
+               case ETMV1_CONTEXTID_8:
+                       command_print(cmd_ctx, "contextid tracing: 8 bit");
+                       break;
+               case ETMV1_CONTEXTID_16:
+                       command_print(cmd_ctx, "contextid tracing: 16 bit");
+                       break;
+               case ETMV1_CONTEXTID_32:
+                       command_print(cmd_ctx, "contextid tracing: 32 bit");
+                       break;
+       }
+       
+       if (tracemode & ETMV1_CYCLE_ACCURATE)
+       {
+               command_print(cmd_ctx, "cycle-accurate tracing enabled");
+       }
+       else
+       {
+               command_print(cmd_ctx, "cycle-accurate tracing disabled");
+       }
+       
+       /* only update ETM_CTRL register if tracemode changed */
+       if (arm7_9->etm_ctx->tracemode != tracemode)
+       {
+               reg_t *etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL];
+               
+               etm_get_reg(etm_ctrl_reg);
+               
+               buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK);
+               buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4);
+               buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8);
+               
+               etm_store_reg(etm_ctrl_reg);
+               
+               arm7_9->etm_ctx->tracemode = tracemode;
+               
+               /* invalidate old trace data */
+               arm7_9->etm_ctx->capture_status = TRACE_IDLE;
+               if (arm7_9->etm_ctx->trace_depth > 0)
+               {
+                       free(arm7_9->etm_ctx->trace_data);
+               }
+               arm7_9->etm_ctx->trace_depth = 0;
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       etm_portmode_t portmode = 0x0;
+       etm_context_t *etm_ctx = malloc(sizeof(etm_context_t));
+       int i;
+       
+       if (argc != 5)
+       {
+               ERROR("incomplete 'etm config <target> <port_width> <port_mode> <clocking> <capture_driver>' command");
+               exit(-1);
+       }
+       
+       target = get_target_by_num(strtoul(args[0], NULL, 0));
+       
+       if (!target)
+       {
+               ERROR("target number '%s' not defined", args[0]);
+               exit(-1);
+       }
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       switch (strtoul(args[1], NULL, 0))
+       {
+               case 4:
+                       portmode |= ETM_PORT_4BIT;
+                       break;
+               case 8:
+                       portmode |= ETM_PORT_8BIT;
+                       break;
+               case 16:
+                       portmode |= ETM_PORT_16BIT;
+                       break;
+               default:
+                       command_print(cmd_ctx, "unsupported ETM port width '%s', must be 4, 8 or 16", args[1]);
+                       return ERROR_OK;
+       }
+       
+       if (strcmp("normal", args[2]) == 0)
+       {
+               portmode |= ETM_PORT_NORMAL;
+       }
+       else if (strcmp("multiplexed", args[2]) == 0)
+       {
+               portmode |= ETM_PORT_MUXED;
+       }
+       else if (strcmp("demultiplexed", args[2]) == 0)
+       {
+               portmode |= ETM_PORT_DEMUXED;
+       }
+       else
+       {
+               command_print(cmd_ctx, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", args[2]);
+               return ERROR_OK;
+       }
+       
+       if (strcmp("half", args[3]) == 0)
+       {
+               portmode |= ETM_PORT_HALF_CLOCK;
+       }
+       else if (strcmp("full", args[3]) == 0)
+       {
+               portmode |= ETM_PORT_FULL_CLOCK;
+       }
+       else
+       {
+               command_print(cmd_ctx, "unsupported ETM port clocking '%s', must be 'full' or 'half'", args[3]);
+               return ERROR_OK;
+       }
+       
+       for (i=0; etm_capture_drivers[i]; i++)
+       {
+               if (strcmp(args[4], etm_capture_drivers[i]->name) == 0)
+               {
+                       if (etm_capture_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)
+                       {
+                               free(etm_ctx);
+                               exit(-1);
+                       }
+               
+                       etm_ctx->capture_driver = etm_capture_drivers[i];
+
+                       break;
+               }
+       }
+       
+       etm_ctx->trace_data = NULL;
+       etm_ctx->trace_depth = 0;
+       etm_ctx->portmode = portmode;
+       etm_ctx->tracemode = 0x0;
+       etm_ctx->core_state = ARMV4_5_STATE_ARM;
+       etm_ctx->pipe_index = 0;
+       etm_ctx->data_index = 0;
+       etm_ctx->current_pc = 0x0;
+       etm_ctx->pc_ok = 0;
+       etm_ctx->last_branch = 0x0;
+       etm_ctx->last_ptr = 0x0;
+       etm_ctx->context_id = 0x0;
+       
+       arm7_9->etm_ctx = etm_ctx;
+       
+       etm_register_user_commands(cmd_ctx);
+       
+       return ERROR_OK;
+}
+
+int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       trace_status_t trace_status;
+       
+       target = get_current_target(cmd_ctx);
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       if (!arm7_9->etm_ctx)
+       {
+               command_print(cmd_ctx, "current target doesn't have an ETM configured");
+               return ERROR_OK;
+       }
+       
+       trace_status = arm7_9->etm_ctx->capture_driver->status(arm7_9->etm_ctx);
+       
+       if (trace_status == TRACE_IDLE)
+       {
+               command_print(cmd_ctx, "tracing is idle");
+       }
+       else
+       {
+               static char *completed = " completed";
+               static char *running = " is running";
+               static char *overflowed = ", trace overflowed";
+               static char *triggered = ", trace triggered";
+               
+               command_print(cmd_ctx, "trace collection%s%s%s", 
+                       (trace_status & TRACE_RUNNING) ? running : completed,
+                       (trace_status & TRACE_OVERFLOWED) ? overflowed : "",
+                       (trace_status & TRACE_TRIGGERED) ? triggered : "");
+               
+               if (arm7_9->etm_ctx->trace_depth > 0)
+               {
+                       command_print(cmd_ctx, "%i frames of trace data read", arm7_9->etm_ctx->trace_depth);
+               }
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_etm_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       fileio_t file;
+       target_t *target;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       etm_context_t *etm_ctx;
+       u32 size_written;
+       
+       if (argc != 1)
+       {
+               command_print(cmd_ctx, "usage: etm dump <file>");
+               return ERROR_OK;
+       }
+       
+       target = get_current_target(cmd_ctx);
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       if (!(etm_ctx = arm7_9->etm_ctx))
+       {
+               command_print(cmd_ctx, "current target doesn't have an ETM configured");
+               return ERROR_OK;
+       }
+       
+       if (etm_ctx->capture_driver->status == TRACE_IDLE)
+       {
+               command_print(cmd_ctx, "trace capture wasn't enabled, no trace data captured");
+               return ERROR_OK;
+       }
+
+       if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING)
+       {
+               /* TODO: if on-the-fly capture is to be supported, this needs to be changed */
+               command_print(cmd_ctx, "trace capture not completed");
+               return ERROR_OK;
+       }
+       
+       /* read the trace data if it wasn't read already */
+       if (etm_ctx->trace_depth == 0)
+               etm_ctx->capture_driver->read_trace(etm_ctx);
+       
+       if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "file open error: %s", file.error_str);
+               return ERROR_OK;
+       }
+       
+       //fileio_write(&file, etm_ctx->trace_depth * 4, (u8*)etm_ctx->trace_data, &size_written);
+       
+       fileio_close(&file);
+       
+       return ERROR_OK;        
+}
+
+int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       fileio_t file;
+       target_t *target;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       etm_context_t *etm_ctx;
+       u32 size_read;
+       
+       if (argc != 1)
+       {
+               command_print(cmd_ctx, "usage: etm load <file>");
+               return ERROR_OK;
+       }
+       
+       target = get_current_target(cmd_ctx);
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       if (!(etm_ctx = arm7_9->etm_ctx))
+       {
+               command_print(cmd_ctx, "current target doesn't have an ETM configured");
+               return ERROR_OK;
+       }
+       
+       if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING)
+       {
+               command_print(cmd_ctx, "trace capture running, stop first");
+               return ERROR_OK;
+       }
+       
+       if (fileio_open(&file, args[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "file open error: %s", file.error_str);
+               return ERROR_OK;
+       }
+       
+       if (file.size % 4)
+       {
+               command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data");
+               return ERROR_OK;
+       }
+       
+       if (etm_ctx->trace_depth > 0)
+       {
+               free(etm_ctx->trace_data);
+       }
+       
+       //fileio_read(&file, file.size, (u8*)etm_ctx->trace_data, &size_read);
+       etm_ctx->trace_depth = file.size / 4;
+       etm_ctx->capture_status = TRACE_COMPLETED;
+       
+       fileio_close(&file);
+       
+       return ERROR_OK;        
+}
+
+int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       etm_context_t *etm_ctx;
+       reg_t *etm_ctrl_reg;
+
+       target = get_current_target(cmd_ctx);
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       if (!(etm_ctx = arm7_9->etm_ctx))
+       {
+               command_print(cmd_ctx, "current target doesn't have an ETM configured");
+               return ERROR_OK;
+       }
+       
+       /* invalidate old tracing data */
+       arm7_9->etm_ctx->capture_status = TRACE_IDLE;
+       if (arm7_9->etm_ctx->trace_depth > 0)
+       {
+               free(arm7_9->etm_ctx->trace_data);
+       }
+       arm7_9->etm_ctx->trace_depth = 0;
+               
+       etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL];
+       etm_get_reg(etm_ctrl_reg);
+               
+       /* Clear programming bit (10), set port selection bit (11) */
+       buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2);
+
+       etm_store_reg(etm_ctrl_reg);
+       jtag_execute_queue();
+
+       etm_ctx->capture_driver->start_capture(etm_ctx);
+
+       return ERROR_OK;
+}
+
+int handle_etm_stop_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       etm_context_t *etm_ctx;
+       reg_t *etm_ctrl_reg;
+
+       target = get_current_target(cmd_ctx);
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       if (!(etm_ctx = arm7_9->etm_ctx))
+       {
+               command_print(cmd_ctx, "current target doesn't have an ETM configured");
+               return ERROR_OK;
+       }
+       
+       etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL];
+       etm_get_reg(etm_ctrl_reg);
+               
+       /* Set programming bit (10), clear port selection bit (11) */
+       buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1);
+
+       etm_store_reg(etm_ctrl_reg);    
+       jtag_execute_queue();
+       
+       etm_ctx->capture_driver->stop_capture(etm_ctx);
+       
+       return ERROR_OK;
+}
+
+int handle_etm_analyse_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target;
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       etm_context_t *etm_ctx;
+
+       target = get_current_target(cmd_ctx);
+       
+       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       {
+               command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+               return ERROR_OK;
+       }
+       
+       if (!(etm_ctx = arm7_9->etm_ctx))
+       {
+               command_print(cmd_ctx, "current target doesn't have an ETM configured");
+               return ERROR_OK;
+       }
+       
+       etmv1_analyse_trace(etm_ctx);
+       
+       return ERROR_OK;
+}
+
+int etm_register_commands(struct command_context_s *cmd_ctx)
+{
+       etm_cmd = register_command(cmd_ctx, NULL, "etm", NULL, COMMAND_ANY, "Embedded Trace Macrocell");
+
+       register_command(cmd_ctx, etm_cmd, "config", handle_etm_config_command, COMMAND_CONFIG, NULL);
+
+       return ERROR_OK;
+}
+
+int etm_register_user_commands(struct command_context_s *cmd_ctx)
+{
+       register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command,
+               COMMAND_EXEC, "configure trace mode <none|data|address|all> <context id bits> <enable|disable cycle accurate>");
+
+       register_command(cmd_ctx, etm_cmd, "status", handle_etm_status_command,
+               COMMAND_EXEC, "display current target's ETM status");
+       register_command(cmd_ctx, etm_cmd, "start", handle_etm_start_command,
+               COMMAND_EXEC, "start ETM trace collection");
+       register_command(cmd_ctx, etm_cmd, "stop", handle_etm_stop_command,
+               COMMAND_EXEC, "stop ETM trace collection");
+
+       register_command(cmd_ctx, etm_cmd, "analyze", handle_etm_stop_command,
+               COMMAND_EXEC, "anaylze collected ETM trace");
+
+       register_command(cmd_ctx, etm_cmd, "dump", handle_etm_dump_command,
+               COMMAND_EXEC, "dump captured trace data <file>");
+       register_command(cmd_ctx, etm_cmd, "load", handle_etm_load_command,
+               COMMAND_EXEC, "load trace data for analysis <file>");
+
+       return ERROR_OK;
+}
index 4b24e5c8800bc390d3b3cb70bb4f34ffee5ef884..595917885a56dcd93518a42dc81def870c62a410 100644 (file)
@@ -1,7 +1,10 @@
 /***************************************************************************\r
- *   Copyright (C) 2005 by Dominic Rath                                    *\r
+ *   Copyright (C) 2005, 2007 by Dominic Rath                              *\r
  *   Dominic.Rath@gmx.de                                                   *\r
  *                                                                         *\r
+ *   Copyright (C) 2007 by Vincent Palatin                                 *\r
+ *   vincent.palatin_openocd@m4x.org                                       *\r
+ *                                                                         *\r
  *   This program is free software; you can redistribute it and/or modify  *\r
  *   it under the terms of the GNU General Public License as published by  *\r
  *   the Free Software Foundation; either version 2 of the License, or     *\r
 #ifndef ETM_H\r
 #define ETM_H\r
 \r
+#include "trace.h"\r
 #include "target.h"\r
 #include "register.h"\r
 #include "arm_jtag.h"\r
 \r
-// ETM registers (V1.2 protocol)\r
+#include "armv4_5.h"\r
+\r
+/* ETM registers (V1.3 protocol) */\r
 enum\r
 {\r
        ETM_CTRL = 0x00,\r
@@ -58,14 +64,123 @@ enum
        ETM_CONTEXTID_COMPARATOR_MASK = 0x6f,   \r
 };\r
 \r
-\r
 typedef struct etm_reg_s\r
 {\r
        int addr;\r
        arm_jtag_t *jtag_info;\r
 } etm_reg_t;\r
 \r
-extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, int extra_reg);\r
+typedef enum\r
+{\r
+       /* Port width */\r
+       ETM_PORT_4BIT           = 0x00,\r
+       ETM_PORT_8BIT           = 0x10,\r
+       ETM_PORT_16BIT          = 0x20,\r
+       ETM_PORT_WIDTH_MASK     = 0x70, \r
+       /* Port modes */\r
+       ETM_PORT_NORMAL    = 0x00000,\r
+       ETM_PORT_MUXED     = 0x10000,\r
+       ETM_PORT_DEMUXED   = 0x20000,\r
+       ETM_PORT_MODE_MASK = 0x30000,\r
+       /* Clocking modes */\r
+       ETM_PORT_FULL_CLOCK = 0x0000,\r
+       ETM_PORT_HALF_CLOCK = 0x1000,\r
+       ETM_PORT_CLOCK_MASK = 0x1000,\r
+} etm_portmode_t;\r
+\r
+typedef enum\r
+{\r
+       /* Data trace */\r
+       ETMV1_TRACE_NONE         = 0x00,\r
+       ETMV1_TRACE_DATA     = 0x01,\r
+       ETMV1_TRACE_ADDR     = 0x02,\r
+       ETMV1_TRACE_MASK     = 0x03,\r
+       /* ContextID */\r
+       ETMV1_CONTEXTID_NONE = 0x00,\r
+       ETMV1_CONTEXTID_8    = 0x10,\r
+       ETMV1_CONTEXTID_16   = 0x20,\r
+       ETMV1_CONTEXTID_32   = 0x30,\r
+       ETMV1_CONTEXTID_MASK = 0x30,\r
+       /* Misc */\r
+       ETMV1_CYCLE_ACCURATE = 0x100\r
+} etmv1_tracemode_t;\r
+\r
+/* forward-declare ETM context */\r
+struct etm_context_s;\r
+\r
+typedef struct etm_capture_driver_s\r
+{\r
+       char *name;\r
+       int (*register_commands)(struct command_context_s *cmd_ctx);\r
+       int (*init)(struct etm_context_s *etm_ctx);\r
+       trace_status_t (*status)(struct etm_context_s *etm_ctx);\r
+       int (*read_trace)(struct etm_context_s *etm_ctx);\r
+       int (*start_capture)(struct etm_context_s *etm_ctx);\r
+       int (*stop_capture)(struct etm_context_s *etm_ctx);\r
+} etm_capture_driver_t;\r
+\r
+typedef struct etmv1_trace_data_s\r
+{\r
+       u8 pipestat;    /* pipeline cycle this packet belongs to */\r
+       u16 packet;     /* packet data (4, 8 or 16 bit) */\r
+       int tracesync;  /* 1 if tracesync was set on this packet */\r
+} etmv1_trace_data_t;\r
+\r
+/* describe a trace context\r
+ * if support for ETMv2 or ETMv3 is to be implemented,\r
+ * this will have to be split into version independent elements\r
+ * and a version specific part\r
+ */\r
+typedef struct etm_context_s\r
+{\r
+       reg_cache_t *reg_cache;                 /* ETM register cache */\r
+       etm_capture_driver_t *capture_driver;   /* driver used to access ETM data */\r
+       void *capture_driver_priv;              /* capture driver private data */\r
+       trace_status_t capture_status;  /* current state of capture run */ \r
+       etmv1_trace_data_t *trace_data; /* trace data */\r
+       u32 trace_depth;                                /* number of trace cycles to be analyzed, 0 if no trace data available */\r
+       etm_portmode_t portmode;                /* normal, multiplexed or demultiplexed */\r
+       etmv1_tracemode_t tracemode;    /* type of information the trace contains (data, addres, contextID, ...) */ \r
+       armv4_5_state_t core_state;             /* current core state (ARM, Thumb, Jazelle) */\r
+//     trace_image_provider_t image_provider;  /* source for target opcodes */\r
+       u32 pipe_index;                                 /* current trace cycle */\r
+       u32 data_index;                                 /* cycle holding next data packet */\r
+       u32 current_pc;                                 /* current program counter */\r
+       u32 pc_ok;                                              /* full PC has been acquired */\r
+       u32 last_branch;                                /* last branch address output */ \r
+       u32 last_ptr;                                   /* address of the last data access */\r
+       u32 context_id;                                 /* context ID of the code being traced */\r
+} etm_context_t;\r
+\r
+/* PIPESTAT values */\r
+typedef enum\r
+{\r
+       STAT_IE = 0x0,\r
+       STAT_ID = 0x1,\r
+       STAT_IN = 0x2,\r
+       STAT_WT = 0x3,\r
+       STAT_BE = 0x4,\r
+       STAT_BD = 0x5,\r
+       STAT_TR = 0x6,\r
+       STAT_TD = 0x7\r
+} etmv1_pipestat_t;\r
+\r
+/* branch reason values */\r
+typedef enum\r
+{\r
+       BR_NORMAL  = 0x0, /* Normal PC change : periodic synchro (ETMv1.1) */\r
+       BR_ENABLE  = 0x1, /* Trace has been enabled */\r
+       BR_RESTART = 0x2, /* Trace restarted after a FIFO overflow */\r
+       BR_NODEBUG = 0x3, /* ARM has exited for debug state */\r
+       BR_PERIOD  = 0x4, /* Peridioc synchronization point (ETM>=v1.2)*/\r
+       BR_RSVD5   = 0x5, /* reserved */\r
+       BR_RSVD6   = 0x6, /* reserved */\r
+       BR_RSVD7   = 0x7, /* reserved */\r
+} etmv1_branch_reason_t;\r
+\r
+extern char *etmv1v1_branch_reason_strings[];\r
+\r
+extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx);\r
 extern int etm_read_reg(reg_t *reg);\r
 extern int etm_write_reg(reg_t *reg, u32 value);\r
 extern int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask);\r
@@ -73,4 +188,12 @@ extern int etm_store_reg(reg_t *reg);
 extern int etm_set_reg(reg_t *reg, u32 value);\r
 extern int etm_set_reg_w_exec(reg_t *reg, u8 *buf);\r
 \r
+int etm_register_commands(struct command_context_s *cmd_ctx);\r
+int etm_register_user_commands(struct command_context_s *cmd_ctx);\r
+extern etm_context_t* etm_create_context(etm_portmode_t portmode, char *capture_driver_name);\r
+\r
+#define ERROR_ETM_INVALID_DRIVER       (-1300)\r
+#define ERROR_ETM_PORTMODE_NOT_SUPPORTED       (-1301)\r
+#define ERROR_ETM_CAPTURE_INIT_FAILED  (-1302)\r
+\r
 #endif /* ETM_H */\r
index 050a523e712d964024ccdf57e2652ee1547f3643..e980ae4a147239143ccd80b1473ab4c0fb6127ca 100644 (file)
@@ -43,6 +43,7 @@
 #include <time_support.h>
 
 #include <fileio.h>
+#include <image.h>
 
 int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv);
 
@@ -1656,12 +1657,9 @@ int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char
        u32 address;
        u8 *buffer;
        u32 buf_cnt;
-       u32 binary_size;
-       
-       fileio_t file;
-       enum fileio_pri_type pri_type = FILEIO_IMAGE;
-       fileio_image_t image_info;
-       enum fileio_sec_type sec_type;
+       u32 image_size;
+
+       image_t image;  
        
        duration_t duration;
        char *duration_text;
@@ -1674,40 +1672,41 @@ int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char
                return ERROR_OK;
        }
        
-       memset(&file, 0, sizeof(fileio_t));
-       fileio_identify_image_type(&sec_type, (argc == 3) ? args[2] : NULL);
+       identify_image_type(&image.type, (argc == 3) ? args[2] : NULL);
 
-       image_info.base_address = strtoul(args[1], NULL, 0);
-       image_info.has_start_address = 0;
+       image.base_address_set = 1;
+       image.base_address = strtoul(args[1], NULL, 0);
+       
+       image.start_address_set = 0;
        
        buffer = malloc(128 * 1024);
 
        duration_start_measure(&duration);
        
-       if (fileio_open(&file, args[0], FILEIO_READ, 
-               pri_type, &image_info, sec_type) != ERROR_OK)
+       if (image_open(&image, args[0], FILEIO_READ) != ERROR_OK)
        {
-               command_print(cmd_ctx, "load_image error: %s", file.error_str);
+               command_print(cmd_ctx, "load_image error: %s", image.error_str);
                return ERROR_OK;
        }
        
-       binary_size = file.size;
-       address = image_info.base_address;
-       while ((binary_size > 0) &&
-               (fileio_read(&file, 128 * 1024, buffer, &buf_cnt) == ERROR_OK))
+       image_size = image.size;
+       address = image.base_address;
+       
+       while ((image_size > 0) &&
+               (image_read(&image, 128 * 1024, buffer, &buf_cnt) == ERROR_OK))
        {
                target_write_buffer(target, address, buf_cnt, buffer);
                address += buf_cnt;
-               binary_size -= buf_cnt;
+               image_size -= buf_cnt;
        }
 
        free(buffer);
        
        duration_stop_measure(&duration, &duration_text);
-       command_print(cmd_ctx, "downloaded %lli byte in %s", file.size, duration_text);
+       command_print(cmd_ctx, "downloaded %u byte in %s", image.size, duration_text);
        free(duration_text);
        
-       fileio_close(&file);
+       image_close(&image);
 
        return ERROR_OK;
 
@@ -1715,8 +1714,7 @@ int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char
 
 int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       fileio_t file;
-       fileio_image_t image_info;
+       fileio_t fileio;
        
        u32 address;
        u32 size;
@@ -1742,13 +1740,9 @@ int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char
                return ERROR_OK;
        }
        
-       image_info.base_address = address;
-       image_info.has_start_address = 0;
-       
-       if (fileio_open(&file, args[0], FILEIO_WRITE, 
-               FILEIO_IMAGE, &image_info, FILEIO_PLAIN) != ERROR_OK)
+       if (fileio_open(&fileio, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
        {
-               command_print(cmd_ctx, "dump_image error: %s", file.error_str);
+               command_print(cmd_ctx, "dump_image error: %s", fileio.error_str);
                return ERROR_OK;
        }
        
@@ -1760,16 +1754,16 @@ int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char
                u32 this_run_size = (size > 560) ? 560 : size;
                
                target->type->read_memory(target, address, 4, this_run_size / 4, buffer);
-               fileio_write(&file, this_run_size, buffer, &size_written);
+               fileio_write(&fileio, this_run_size, buffer, &size_written);
                
                size -= this_run_size;
                address += this_run_size;
        }
 
-       fileio_close(&file);
+       fileio_close(&fileio);
 
        duration_stop_measure(&duration, &duration_text);
-       command_print(cmd_ctx, "dumped %lli byte in %s", file.size, duration_text);
+       command_print(cmd_ctx, "dumped %lli byte in %s", fileio.size, duration_text);
        free(duration_text);
        
        return ERROR_OK;
diff --git a/src/target/xscale/debug_handler.bin b/src/target/xscale/debug_handler.bin
new file mode 100755 (executable)
index 0000000..2dde185
Binary files /dev/null and b/src/target/xscale/debug_handler.bin differ

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)