cortex_a hybrid & context breakpoints
[fw/openocd] / src / target / mips_m4k.c
index 0508c35f80d7ab7dc99c9c5a113cfcb07eb42f15..7be96a4979aa4c8f193c5b828b9c9393da60426a 100644 (file)
@@ -6,6 +6,9 @@
  *                                                                         *
  *   Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com>          *
  *                                                                         *
+ *   Copyright (C) 2011 by Drasko DRASKOVIC                                *
+ *   drasko.draskovic@gmail.com                                            *
+ *                                                                         *
  *   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     *
@@ -120,7 +123,9 @@ static int mips_m4k_poll(struct target *target)
 
        /* read ejtag control reg */
        mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
-       mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
+       retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
+       if (retval != ERROR_OK)
+               return retval;
 
        /* clear this bit before handling polling
         * as after reset registers will read zero */
@@ -131,7 +136,9 @@ static int mips_m4k_poll(struct target *target)
                ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_ROCC;
 
                mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
-               mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
+               retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
+               if (retval != ERROR_OK)
+                       return retval;
                LOG_DEBUG("Reset Detected");
        }
 
@@ -254,18 +261,14 @@ static int mips_m4k_assert_reset(struct target *target)
        {
                if (mips_m4k->is_pic32mx)
                {
-                       uint32_t mchip_cmd;
-
                        LOG_DEBUG("Using MTAP reset to reset processor...");
 
                        /* use microchip specific MTAP reset */
                        mips_ejtag_set_instr(ejtag_info, MTAP_SW_MTAP);
                        mips_ejtag_set_instr(ejtag_info, MTAP_COMMAND);
 
-                       mchip_cmd = MCHP_ASERT_RST;
-                       mips_ejtag_drscan_8(ejtag_info, &mchip_cmd);
-                       mchip_cmd = MCHP_DE_ASSERT_RST;
-                       mips_ejtag_drscan_8(ejtag_info, &mchip_cmd);
+                       mips_ejtag_drscan_8_out(ejtag_info, MCHP_ASERT_RST);
+                       mips_ejtag_drscan_8_out(ejtag_info, MCHP_DE_ASSERT_RST);
                        mips_ejtag_set_instr(ejtag_info, MTAP_SW_ETAP);
                }
                else
@@ -274,7 +277,7 @@ static int mips_m4k_assert_reset(struct target *target)
                        uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl | EJTAG_CTRL_PRRST | EJTAG_CTRL_PERRST;
                        LOG_DEBUG("Using EJTAG reset (PRRST) to reset processor...");
                        mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
-                       mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
+                       mips_ejtag_drscan_32_out(ejtag_info, ejtag_ctrl);
                }
        }
 
@@ -616,6 +619,14 @@ static int mips_m4k_unset_breakpoint(struct target *target,
                        {
                                return retval;
                        }
+
+                       /**
+                        * target_read_memory() gets us data in _target_ endianess.
+                        * If we want to use this data on the host for comparisons with some macros
+                        * we must first transform it to _host_ endianess using target_buffer_get_u32().
+                        */
+                       current_instr = target_buffer_get_u32(target, (uint8_t *)&current_instr);
+
                        if (current_instr == MIPS32_SDBBP)
                        {
                                if ((retval = target_write_memory(target, breakpoint->address, 4, 1,
@@ -635,7 +646,7 @@ static int mips_m4k_unset_breakpoint(struct target *target,
                        {
                                return retval;
                        }
-
+                       current_instr = target_buffer_get_u16(target, (uint8_t *)&current_instr);
                        if (current_instr == MIPS16_SDBBP)
                        {
                                if ((retval = target_write_memory(target, breakpoint->address, 2, 1,
@@ -859,20 +870,53 @@ static int mips_m4k_read_memory(struct target *target, uint32_t address,
        if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
                return ERROR_TARGET_UNALIGNED_ACCESS;
 
+       /* since we don't know if buffer is aligned, we allocate new mem that is always aligned */
+       void *t = NULL;
+
+       if (size > 1)
+       {
+               t = malloc(count * size * sizeof(uint8_t));
+               if (t == NULL)
+               {
+                       LOG_ERROR("Out of memory");
+                       return ERROR_FAIL;
+               }
+       }
+       else
+       {
+               t = buffer;
+       }
+
        /* if noDMA off, use DMAACC mode for memory read */
        int retval;
        if (ejtag_info->impcode & EJTAG_IMP_NODMA)
-               retval = mips32_pracc_read_mem(ejtag_info, address, size, count, (void *)buffer);
+               retval = mips32_pracc_read_mem(ejtag_info, address, size, count, t);
        else
-               retval = mips32_dmaacc_read_mem(ejtag_info, address, size, count, (void *)buffer);
-       if (ERROR_OK != retval)
-               return retval;
+               retval = mips32_dmaacc_read_mem(ejtag_info, address, size, count, t);
 
-       return ERROR_OK;
+       /* mips32_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */
+       /* endianness, but byte array should represent target endianness       */
+       if (ERROR_OK == retval)
+       {
+               switch(size)
+               {
+               case 4:
+                       target_buffer_set_u32_array(target,buffer,count,t);
+                       break;
+               case 2:
+                       target_buffer_set_u16_array(target,buffer,count,t);
+                       break;
+               }
+       }
+
+       if ((size > 1) && (t != NULL))
+               free(t);
+
+       return retval;
 }
 
 static int mips_m4k_write_memory(struct target *target, uint32_t address,
-               uint32_t size, uint32_t count, uint8_t *buffer)
+               uint32_t size, uint32_t count, const uint8_t *buffer)
 {
        struct mips32_common *mips32 = target_to_mips32(target);
        struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
@@ -893,11 +937,45 @@ static int mips_m4k_write_memory(struct target *target, uint32_t address,
        if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
                return ERROR_TARGET_UNALIGNED_ACCESS;
 
+       /** correct endianess if we have word or hword access */
+       void *t = NULL;
+       if (size > 1)
+       {
+               /* mips32_..._write_mem with size 4/2 requires uint32_t/uint16_t in host */
+               /* endianness, but byte array represents target endianness               */
+               t = malloc(count * size * sizeof(uint8_t));
+               if (t == NULL)
+               {
+                       LOG_ERROR("Out of memory");
+                       return ERROR_FAIL;
+               }
+
+               switch(size)
+               {
+               case 4:
+                       target_buffer_get_u32_array(target,buffer,count,(uint32_t*)t);
+                       break;
+               case 2:
+                       target_buffer_get_u16_array(target,buffer,count,(uint16_t*)t);
+                       break;
+               }
+               buffer = t;
+       }
+
        /* if noDMA off, use DMAACC mode for memory write */
+       int retval;
        if (ejtag_info->impcode & EJTAG_IMP_NODMA)
-               return mips32_pracc_write_mem(ejtag_info, address, size, count, (void *)buffer);
+               retval = mips32_pracc_write_mem(ejtag_info, address, size, count, (void *)buffer);
        else
-               return mips32_dmaacc_write_mem(ejtag_info, address, size, count, (void *)buffer);
+               retval = mips32_dmaacc_write_mem(ejtag_info, address, size, count, (void *)buffer);
+
+       if (t != NULL)
+               free(t);
+
+       if (ERROR_OK != retval)
+               return retval;
+
+       return ERROR_OK;
 }
 
 static int mips_m4k_init_target(struct command_context *cmd_ctx,
@@ -966,7 +1044,7 @@ static int mips_m4k_examine(struct target *target)
 }
 
 static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address,
-               uint32_t count, uint8_t *buffer)
+               uint32_t count, const uint8_t *buffer)
 {
        struct mips32_common *mips32 = target_to_mips32(target);
        struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
@@ -1004,19 +1082,24 @@ static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address,
                ejtag_info->fast_access_save = -1;
        }
 
-       /* TAP data register is loaded LSB first (little endian) */
-       if (target->endianness == TARGET_BIG_ENDIAN)
+       /* mips32_pracc_fastdata_xfer requires uint32_t in host endianness, */
+       /* but byte array represents target endianness                      */
+       uint32_t *t = NULL;
+       t = malloc(count * sizeof(uint32_t));
+       if (t == NULL)
        {
-               uint32_t i, t32;
-               for(i = 0; i < (count * 4); i += 4)
-               {
-                       t32 = be_to_h_u32((uint8_t *) &buffer[i]);
-                       h_u32_to_le(&buffer[i], t32);
-               }
+               LOG_ERROR("Out of memory");
+               return ERROR_FAIL;
        }
 
+       target_buffer_get_u32_array(target,buffer,count,t);
+
        retval = mips32_pracc_fastdata_xfer(ejtag_info, mips32->fast_data_area, write_t, address,
-                       count, (uint32_t*) (void *)buffer);
+                       count, t);
+
+       if (t != NULL)
+               free(t);
+
        if (retval != ERROR_OK)
        {
                /* FASTDATA access failed, try normal memory write */
@@ -1027,6 +1110,106 @@ static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address,
        return retval;
 }
 
+static int mips_m4k_verify_pointer(struct command_context *cmd_ctx,
+               struct mips_m4k_common *mips_m4k)
+{
+       if (mips_m4k->common_magic != MIPSM4K_COMMON_MAGIC) {
+               command_print(cmd_ctx, "target is not an MIPS_M4K");
+               return ERROR_TARGET_INVALID;
+       }
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(mips_m4k_handle_cp0_command)
+{
+       int retval;
+       struct target *target = get_current_target(CMD_CTX);
+       struct mips_m4k_common *mips_m4k = target_to_m4k(target);
+       struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info;
+
+       retval = mips_m4k_verify_pointer(CMD_CTX, mips_m4k);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (target->state != TARGET_HALTED)
+       {
+               command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
+               return ERROR_OK;
+       }
+
+       /* two or more argument, access a single register/select (write if third argument is given) */
+       if (CMD_ARGC < 2)
+       {
+               command_print(CMD_CTX, "command requires more arguments.");
+       }
+       else
+       {
+               uint32_t cp0_reg, cp0_sel;
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg);
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel);
+
+               if (CMD_ARGC == 2)
+               {
+                       uint32_t value;
+
+                       if ((retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel)) != ERROR_OK)
+                       {
+                               command_print(CMD_CTX,
+                                               "couldn't access reg %" PRIi32,
+                                               cp0_reg);
+                               return ERROR_OK;
+                       }
+                       if ((retval = jtag_execute_queue()) != ERROR_OK)
+                       {
+                               return retval;
+                       }
+
+                       command_print(CMD_CTX, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32,
+                                       cp0_reg, cp0_sel, value);
+               }
+               else if (CMD_ARGC == 3)
+               {
+                       uint32_t value;
+                       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
+                       if ((retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel)) != ERROR_OK)
+                       {
+                               command_print(CMD_CTX,
+                                               "couldn't access cp0 reg %" PRIi32 ", select %" PRIi32,
+                                               cp0_reg,  cp0_sel);
+                               return ERROR_OK;
+                       }
+                       command_print(CMD_CTX, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32,
+                                       cp0_reg, cp0_sel, value);
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static const struct command_registration mips_m4k_exec_command_handlers[] = {
+       {
+               .name = "cp0",
+               .handler = mips_m4k_handle_cp0_command,
+               .mode = COMMAND_EXEC,
+               .usage = "regnum [value]",
+               .help = "display/modify cp0 register",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration mips_m4k_command_handlers[] = {
+       {
+               .chain = mips32_command_handlers,
+       },
+       {
+               .name = "mips_m4k",
+               .mode = COMMAND_ANY,
+               .help = "mips_m4k command group",
+               .chain = mips_m4k_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
 struct target_type mips_m4k_target =
 {
        .name = "mips_m4k",
@@ -1059,6 +1242,7 @@ struct target_type mips_m4k_target =
        .add_watchpoint = mips_m4k_add_watchpoint,
        .remove_watchpoint = mips_m4k_remove_watchpoint,
 
+       .commands = mips_m4k_command_handlers,
        .target_create = mips_m4k_target_create,
        .init_target = mips_m4k_init_target,
        .examine = mips_m4k_examine,