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