diff --git a/mips.h b/mips.h index 6369301..c7dbb58 100644 --- a/mips.h +++ b/mips.h @@ -49,6 +49,7 @@ #define MIPS_OP_ORI 0x0D #define MIPS_OP_XOR 0x26 #define MIPS_OP_SRL 0x03 +#define MIPS_OP_CACHE 0x2f #define MIPS_COP0_MF 0x00 #define MIPS_COP0_MT 0x04 @@ -86,6 +87,7 @@ #define MIPS_SW(reg, off, base) MIPS_I_INST(MIPS_OP_SW, base, reg, off) #define MIPS_XOR(reg, val1, val2) MIPS_R_INST(0, val1, val2, reg, 0, MIPS_OP_XOR) #define MIPS_SRL(reg, src, off) MIPS_R_INST(0, 0, src, reg, off, MIPS_OP_SRL) +#define MIPS_CACHE(op, off, base) MIPS_I_INST(MIPS_OP_CACHE, base, op, off) #define MIPS_DRET 0x4200001F #define MIPS_BREAK 0x0000000D diff --git a/proxy-mips.c b/proxy-mips.c index 2f8e7bb..248934e 100644 --- a/proxy-mips.c +++ b/proxy-mips.c @@ -612,18 +612,22 @@ static int mips_write_mem(uint64_t addr, } unsigned offset = (addr & 3); - if (offset == 0 && write_size == 4 && - target_is_rom_address (target.device, addr)) - { - /* Software breakpoint: use hardware breakpoint instead. */ - unsigned opcode = *(uint32_t*) buf; - - if ((opcode & MIPS_BREAK_MASK) == MIPS_BREAK) - target_add_break (target.device, addr, 'b'); - else - target_remove_break (target.device, addr); - return RP_VAL_TARGETRET_OK; + unsigned need_cache_flush = 0, cache_flush_addr = 0; + if (offset == 0 && write_size == 4) { + if (target_is_rom_address (target.device, addr)) { + unsigned opcode = *(uint32_t*) buf; + + /* Software breakpoint in read only memory: use hardware breakpoint instead. */ + if ((opcode & MIPS_BREAK_MASK) == MIPS_BREAK) + target_add_break (target.device, addr, 'b'); + else + target_remove_break (target.device, addr); + return RP_VAL_TARGETRET_OK; + } + need_cache_flush = 1; + cache_flush_addr = addr; } + if (offset != 0) { /* Nonaligned address. * Read a word and construct the value. */ @@ -681,6 +685,12 @@ static int mips_write_mem(uint64_t addr, memcpy ((unsigned char*) &data, buf, write_size); target_write_word (target.device, addr, data); } +#if 1 + // Experimental: Flush cache after writing a software break opcode. + if (need_cache_flush) { + target_cache_flush (target.device, cache_flush_addr); + } +#endif return RP_VAL_TARGETRET_OK; } diff --git a/target-ejtag.c b/target-ejtag.c index 9beddfd..3d52c2e 100644 --- a/target-ejtag.c +++ b/target-ejtag.c @@ -952,6 +952,38 @@ void target_write_word (target_t *t, unsigned addr, unsigned word) } } +/* + * Flush the D-cache and invalidate I-cache on a given address. + */ +void target_cache_flush (target_t *t, unsigned addr) +{ + static const unsigned code[] = { /* start: */ + MIPS_MTC0 (15, 31, 0), /* move $15 to COP0 DeSave */ + MIPS_LUI (15, UPPER16(PRACC_STACK)), /* $15 = PRACC_STACK */ + MIPS_ORI (15, 15, LOWER16(PRACC_STACK)), + MIPS_SW (9, 0, 15), /* sw $9,($15) */ + + MIPS_LW (9, NEG16(PRACC_STACK - PRACC_PARAM_IN), 15), /* load R9 @ param_in[0] = address */ + + MIPS_CACHE (8+6, 0, 9), /* cache 8+6,0($9) - writeback D cache */ + MIPS_CACHE (0+4, 0, 9), /* cache 0+4,0($9) - invalidate I cache */ + + MIPS_LW (9, 0, 15), /* lw $9,($15) */ + MIPS_B (NEG16(9)), /* b start */ + MIPS_MFC0 (15, 31, 0), /* move COP0 DeSave to $15 */ + MIPS_NOP, + MIPS_NOP, + }; + unsigned param_in [1]; + + param_in[0] = addr; + if (! t->adapter->exec (t->adapter, 1, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, 0)) + { + fprintf (stderr, "ERROR: cannot flush cache at address %08x\n", addr); + } +} + /* * Write chunk of data to memory. */ diff --git a/target.h b/target.h index d5050ac..29f6def 100644 --- a/target.h +++ b/target.h @@ -41,6 +41,7 @@ void target_read_block (target_t *t, unsigned addr, void target_write_word (target_t *t, unsigned addr, unsigned word); void target_write_block (target_t *t, unsigned addr, unsigned nwords, unsigned *data); +void target_cache_flush (target_t *t, unsigned addr); void target_stop (target_t *t); void target_step (target_t *t);