This is an automated email from Gerrit.

Salvador Arroyo (sarroyof...@yahoo.es) just uploaded a new patch set to Gerrit, 
which you can find at http://openocd.zylin.com/1961

-- gerrit

commit 5095e72bf0a773093b42794290055eba30681b71
Author: Salvador Arroyo <sarroyof...@yahoo.es>
Date:   Thu Feb 20 17:49:45 2014 +0100

    mips32: pracc code for cache initialization
    
    This patch provides the necessary code to initialize or reinitialize mips32
    primary caches.
    After power up the state of the caches are unknown and probably after
    running a program that use caches. Resets does not modify cache
    state.
    Basically it writes 0 to every tag in the tag array, thus invalidating
    and unlocking every cache line.
    The code can also synchronize the entire caches. This is useful after
    loading code with fast data transfer.
    A handler is provided. Calling "mips32 cache number ( 0 - 7) " performs
    cache initialization and sets the cache coherency attribute. If called
    "mips32 cache s" synchronize the entire caches.
    pracc_cache_loop() implements the basic pracc code to source the
    needed addresses or indexes in the caches. EHB instructions has
    been added to make the code work in queued mode for a 24k core.
    Without ending the code with an EHB instruction, a cp0 read at
    register 28 select 0, just after executing the cache code, may take a
    delay of 10 instructions. This makes fail also current version of
    legacy code, silently or not depending on the function called next.
    Two additional EHB instruction are needed in this case to make the
    code work is queued mode.
    This was only tested in an ar7421, for other cores may be different.
    EHB defaults to a variant of SSNOP in release 1.
    Compared with existing cache code this code makes no assumption
    about the presence of any cache or the line size of the caches and
    only required encodings are used.
    For cache initialization it can be called at any time and without a working
    memory controller and D cache can be used if cca = 3 accessing Kse0.
    Again, only tested on ar7421!
    
    Change-Id: Ifd36e60bc40619c6057414f7c2d59f7012df550e
    Signed-off-by: Salvador Arroyo <sarroyof...@yahoo.es>

diff --git a/src/target/mips32.c b/src/target/mips32.c
index 188e88b..2b009d0 100644
--- a/src/target/mips32.c
+++ b/src/target/mips32.c
@@ -841,6 +841,49 @@ COMMAND_HANDLER(mips32_handle_scan_delay_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(mips32_handle_cache_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct mips32_common *mips32 = target_to_mips32(target);
+       struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+
+       int retval = mips32_verify_pointer(CMD_CTX, mips32);
+       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;
+       }
+
+       uint32_t kseg0cca;
+       if (CMD_ARGC == 1)
+               if (*CMD_ARGV[0] == 's')
+                       kseg0cca = 8;
+               else {
+                       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], kseg0cca);
+                       if (kseg0cca > 7) {
+                               command_print(CMD_CTX, "valid values 0 to 7 or 
s");
+                               return ERROR_OK;
+                       }
+               }
+       else
+               if (CMD_ARGC == 0 || CMD_ARGC > 1)
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if (kseg0cca <= 7) {
+               retval = mips32_pracc_cache_op_index(ejtag_info, 1, kseg0cca);
+               if (retval != ERROR_OK)
+                       command_print(CMD_CTX, "couldn't initialize cache");
+       } else {
+               retval = mips32_pracc_cache_op_index(ejtag_info, 0, 0);
+               if (retval != ERROR_OK)
+                       command_print(CMD_CTX, "couldn't sync cache");
+       }
+
+       return ERROR_OK;
+}
+
 static const struct command_registration mips32_exec_command_handlers[] = {
        {
                .name = "cp0",
@@ -856,6 +899,13 @@ static const struct command_registration 
mips32_exec_command_handlers[] = {
                .help = "display/set scan delay in nano seconds",
                .usage = "[value]",
        },
+               {
+               .name = "cache",
+               .handler = mips32_handle_cache_command,
+               .mode = COMMAND_EXEC,
+               .help = "init/sync mips32 primary caches, initialize with cca = 
value (0 to 7), if s sync entire cache",
+               .usage = "[value]",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
diff --git a/src/target/mips32.h b/src/target/mips32.h
index 951b2ed..1ecc39a 100644
--- a/src/target/mips32.h
+++ b/src/target/mips32.h
@@ -44,7 +44,7 @@
 /** Returns the kernel segment base of a given address */
 #define KSEGX(a)               ((a) & 0xe0000000)
 
-/** CP0 CONFIG regites fields */
+/** CP0 CONFIG register fields */
 #define MIPS32_CONFIG0_KU_SHIFT 25
 #define MIPS32_CONFIG0_KU_MASK (0x7 << MIPS32_CONFIG0_KU_SHIFT)
 
@@ -57,9 +57,24 @@
 #define MIPS32_CONFIG0_AR_SHIFT 10
 #define MIPS32_CONFIG0_AR_MASK (0x7 << MIPS32_CONFIG0_AR_SHIFT)
 
-#define MIPS32_CONFIG1_DL_SHIFT 10
+#define MIPS32_CONFIG1_DL_SHIFT 10     /* D cache line size */
 #define MIPS32_CONFIG1_DL_MASK (0x7 << MIPS32_CONFIG1_DL_SHIFT)
 
+#define MIPS32_CONFIG1_IL_SHIFT 19     /* I cache line size */
+#define MIPS32_CONFIG1_IL_MASK (0x7 << MIPS32_CONFIG1_IL_SHIFT)
+
+#define MIPS32_CONFIG1_DS_SHIFT 13     /* D cache sets per way */
+#define MIPS32_CONFIG1_DS_MASK (0x7 << MIPS32_CONFIG1_DS_SHIFT)
+
+#define MIPS32_CONFIG1_IS_SHIFT 22     /* I cache sets per way */
+#define MIPS32_CONFIG1_IS_MASK (0x7 << MIPS32_CONFIG1_IS_SHIFT)
+
+#define MIPS32_CONFIG1_DA_SHIFT 7      /* D cache associativity */
+#define MIPS32_CONFIG1_DA_MASK (0x7 << MIPS32_CONFIG1_DA_SHIFT)
+
+#define MIPS32_CONFIG1_IA_SHIFT 16     /* I cache associativity */
+#define MIPS32_CONFIG1_IA_MASK (0x7 << MIPS32_CONFIG1_IA_SHIFT)
+
 #define MIPS32_ARCH_REL1 0x0
 #define MIPS32_ARCH_REL2 0x1
 
@@ -201,8 +216,11 @@ struct mips32_algorithm {
 
 #define MIPS32_SYNC                    0xF
 #define MIPS32_SYNCI_STEP      0x1     /* reg num od address step size to be 
used with synci instruction */
+/* EHB execution hazard barrier in release 2,defaults to SSNOP variant in 
release 1 */
+#define MIPS32_EHB              0xC0
 
 /**
+
  * Cache operations definietions
  * Operation field is 5 bits long :
  * 1) bits 1..0 hold cache type
@@ -211,6 +229,14 @@ struct mips32_algorithm {
 #define MIPS32_CACHE_D_HIT_WRITEBACK ((0x1 << 0) | (0x6 << 2))
 #define MIPS32_CACHE_I_HIT_INVALIDATE ((0x0 << 0) | (0x4 << 2))
 
+/* required encodings to synchronize entire caches */
+#define MIPS32_DCACHE_WBACK_INV_BY_INDEX               ((0x1 << 0) | (0x0 << 
2))
+#define MIPS32_ICACHE_INVALIDATE_BY_INDEX              ((0x0 << 0) | (0x0 << 
2))
+
+/* required encodings for cache initialization */
+#define MIPS32_DCACHE_INDEX_STORE_TAG                  ((0x1 << 0) | (0x2 << 
2))
+#define MIPS32_ICACHE_INDEX_STORE_TAG                  ((0x0 << 0) | (0x2 << 
2))
+
 /* ejtag specific instructions */
 #define MIPS32_DRET                                    0x4200001F
 #define MIPS32_SDBBP                           0x7000003F      /* 
MIPS32_J_INST(MIPS32_OP_SPECIAL2, MIPS32_OP_SDBBP) */
diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c
index da9a2b7..4171455 100644
--- a/src/target/mips32_pracc.c
+++ b/src/target/mips32_pracc.c
@@ -730,6 +730,136 @@ static int mips32_pracc_clean_invalidate_cache(struct 
mips_ejtag *ejtag_info,
        return retval;
 }
 
+static int pracc_cache_loop(struct mips_ejtag *ejtag_info,
+                                       uint32_t cbaddr,                /* base 
or start  address for cache operation */
+                                       unsigned clcount,               /* line 
count */
+                                       unsigned clsiz,                 /* line 
size */
+                                       uint32_t caopcode,              /* 
cache encoding */
+                                       bool use_synci)                 /* use 
SYNCI instruction, caopcode ignored */
+{
+       struct pracc_queue_info ctx = {.max_code = 512 + 9};            /* 
alloc memory for the worst case */
+       pracc_queue_init(&ctx);
+       if (ctx.retval != ERROR_OK)
+               goto exit;
+
+       while (clcount > 0) {
+               ctx.code_count = 0;
+               uint32_t last_upper_base_addr = UPPER16((cbaddr + 0x8000));
+               pracc_add(&ctx, 0, MIPS32_MTC0(15, 31, 0));
+               pracc_add(&ctx, 0, MIPS32_LUI(15, last_upper_base_addr));       
        /* load $15 with memory base address */
+
+               int this_round_count = (clcount > 512) ? 512 : clcount;
+               for (int i = 0; i != this_round_count; i++, cbaddr += clsiz) {
+
+                       uint32_t upper_base_addr = UPPER16((cbaddr + 0x8000));
+                       if (last_upper_base_addr != upper_base_addr) {
+                               pracc_add(&ctx, 0, MIPS32_LUI(15, 
upper_base_addr));    /* if needed, change upper address in $15*/
+                               last_upper_base_addr = upper_base_addr;
+                       }
+                       if (use_synci)
+                               pracc_add(&ctx, 0, 
MIPS32_SYNCI(LOWER16(cbaddr), 15));
+                       else
+                               pracc_add(&ctx, 0, MIPS32_CACHE(caopcode, 
LOWER16(cbaddr), 15));
+               }
+               clcount -= this_round_count;
+               if (clcount == 0) {                             /* after 
sourcing by address or index */
+                       pracc_add(&ctx, 0, MIPS32_SYNC);        /* recommended 
secuence to avoid hazards, see docs */
+                       pracc_add(&ctx, 0, MIPS32_EHB);         /* execution 
hazard barrier, SSNOP variant in release 1 */
+                       pracc_add(&ctx, 0, MIPS32_EHB);         /* additional 
code for 24k */
+                       pracc_add(&ctx, 0, MIPS32_EHB);         /* some 24k 
core needs this to work in queued mode */
+               }
+               pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1)));        
                /* jump to start */
+               pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0));                     
                /* restore reg15 from DeSave */
+               ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL);
+               if (ctx.retval != ERROR_OK)
+                       goto exit;
+       }
+exit:
+       pracc_queue_free(&ctx);
+       return ctx.retval;
+}
+
+/**    pracc cache code with index opcodes to operate over entire
+       primary caches: initialization or synchronization
+*/
+int mips32_pracc_cache_op_index(struct mips_ejtag *ejtag_info, bool init,  
uint32_t kseg0cca)
+{
+       /* get cache info */
+       uint32_t cp0config1;
+       int retval = mips32_cp0_read(ejtag_info, &cp0config1, 16, 1);
+       if (retval != ERROR_OK)
+               return retval;
+       /* cp0 config1 encoding: 0 => no cache, 1 => 4 bytes, 2 => 8 bytes,... 
max 6 => 128 bytes cache line size */
+       unsigned ilshift = (cp0config1 & MIPS32_CONFIG1_IL_MASK) >> 
MIPS32_CONFIG1_IL_SHIFT;
+       unsigned dlshift = (cp0config1 & MIPS32_CONFIG1_DL_MASK) >> 
MIPS32_CONFIG1_DL_SHIFT;
+
+       if (dlshift == 0 && ilshift == 0) {
+               LOG_INFO("No cache present");
+               return ERROR_OK;
+       }
+
+       if (init)
+               /* initialize TagLo and TagHi to 0 in cp0 28 and 29 registers, 
select 0 and 2 */
+               for (int reg = 28; reg <= 29; reg++)
+                       for (int sel = 0; sel <= 2; sel += 2) {
+                               retval = mips32_cp0_write(ejtag_info, 0, reg, 
sel);
+                               if (retval != ERROR_OK)
+                                       return retval;
+                       }
+       /* read cacheability and coherency attribute for Kseg0, change value if 
needed */
+       uint32_t cp0config;
+       retval = mips32_cp0_read(ejtag_info, &cp0config, 16, 0);
+       if (retval != ERROR_OK)
+               return retval;
+       uint32_t cca = cp0config & MIPS32_CONFIG0_K0_MASK;
+       kseg0cca &= MIPS32_CONFIG0_K0_MASK;
+       if (init && (cca != kseg0cca)) {
+               retval = mips32_cp0_write(ejtag_info, (cp0config & 
~MIPS32_CONFIG0_K0_MASK) | kseg0cca, 16, 0);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+       /* Cache lines = sets per_way * ways (or associativity), see docs for 
encoding */
+       unsigned setspw = (cp0config1 & MIPS32_CONFIG1_IS_MASK) >> 
MIPS32_CONFIG1_IS_SHIFT;
+       setspw = 32 << ((1 + setspw) & 0x7);
+       unsigned ways = 1 + ((cp0config1 & MIPS32_CONFIG1_IA_MASK) >> 
MIPS32_CONFIG1_IA_SHIFT);
+
+       unsigned ilcount = setspw * ways;
+       unsigned ilsize = 2 << ilshift;
+       if (init)
+               LOG_INFO("Icache size: %d bytes   Sets per way: %d   Ways: %d   
Line size: %d bytes",
+                                               ilsize * ilcount, setspw, ways, 
ilsize);
+
+       setspw = (cp0config1 & MIPS32_CONFIG1_DS_MASK) >> 
MIPS32_CONFIG1_DS_SHIFT;
+       setspw = 32 << ((1 + setspw) & 0x7);
+       ways = 1 + ((cp0config1 & MIPS32_CONFIG1_DA_MASK) >> 
MIPS32_CONFIG1_DA_SHIFT);
+
+       unsigned dlcount = setspw * ways;
+       unsigned dlsize = 2 << dlshift;
+       if (init)
+               LOG_INFO("Dcache size: %d bytes   Sets per way: %d   Ways: %d   
Line size: %d bytes",
+                                                 dlsize * dlcount, setspw, 
ways, dlsize);
+
+       uint32_t base_addr = UPPER16(KSEG0);    /* use unmapped base address to 
avoid TLB related exceptions, see docs */
+
+       if (dlshift && (init || cca == 3)) {            /* if data cache is 
present... */
+               uint32_t dcaopcode = init ? MIPS32_DCACHE_INDEX_STORE_TAG : 
MIPS32_DCACHE_WBACK_INV_BY_INDEX;
+
+               retval = pracc_cache_loop(ejtag_info, base_addr, dlcount, 
dlsize, dcaopcode, 0);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       if (ilshift) {                  /* if instruction cache is present */
+               uint32_t icaopcode = init ?  MIPS32_ICACHE_INDEX_STORE_TAG : 
MIPS32_ICACHE_INVALIDATE_BY_INDEX;
+
+               retval = pracc_cache_loop(ejtag_info, base_addr, ilcount, 
ilsize, icaopcode, 0);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return retval;
+}
+
 static int mips32_pracc_write_mem_generic(struct mips_ejtag *ejtag_info,
                uint32_t addr, int size, int count, const void *buf)
 {
diff --git a/src/target/mips32_pracc.h b/src/target/mips32_pracc.h
index 4dc0bbe..fe882fc 100644
--- a/src/target/mips32_pracc.h
+++ b/src/target/mips32_pracc.h
@@ -58,6 +58,7 @@ struct pracc_queue_info {
        int store_count;
        uint32_t *pracc_list;   /* Code and store addresses */
 };
+int mips32_pracc_cache_op_index(struct mips_ejtag *ejtag_info, bool init, 
uint32_t kseg0cca);
 void pracc_queue_init(struct pracc_queue_info *ctx);
 void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr);
 void pracc_queue_free(struct pracc_queue_info *ctx);

-- 

------------------------------------------------------------------------------
Managing the Performance of Cloud-Based Applications
Take advantage of what the Cloud has to offer - Avoid Common Pitfalls.
Read the Whitepaper.
http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk
_______________________________________________
OpenOCD-devel mailing list
OpenOCD-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to