- 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