--- trunk/src/cpu_mips_coproc.c 2007/10/08 16:18:11 6 +++ trunk/src/cpu_mips_coproc.c 2007/10/08 16:18:27 10 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_mips_coproc.c,v 1.18 2005/05/07 02:13:22 debug Exp $ + * $Id: cpu_mips_coproc.c,v 1.23 2005/06/26 11:36:27 debug Exp $ * * Emulation of MIPS coprocessors. */ @@ -88,7 +88,7 @@ #else const int m16 = 0; #endif - int IB, DB, SB, IC, DC, SC; + int cpu_type, IB, DB, SB, IC, DC, SC; /* Default values: */ c->reg[COP0_CONFIG] = @@ -111,7 +111,13 @@ (TODO) */ ; - switch (cpu->cd.mips.cpu_type.rev) { + cpu_type = cpu->cd.mips.cpu_type.rev & 0xff; + + /* AU1x00 are treated as 4Kc (MIPS32 cores): */ + if ((cpu->cd.mips.cpu_type.rev & 0xffff) == 0x0301) + cpu_type = MIPS_4Kc; + + switch (cpu_type) { case MIPS_R4000: /* according to the R4000 manual */ case MIPS_R4600: IB = cpu->machine->cache_picache_linesize - 4; @@ -298,23 +304,44 @@ break; case MIPS_4Kc: case MIPS_5Kc: - /* According to the MIPS64 5K User's Manual: */ - /* TODO: How good does this work with 4K? */ + /* According to the MIPS64 (5K) User's Manual: */ c->reg[COP0_CONFIG] = ( (uint32_t)1 << 31)/* Config 1 present bit */ | ( 0 << 20) /* ISD: instruction scheduling disable (=1) */ | ( 0 << 17) /* DID: dual issue disable */ | ( 0 << 16) /* BM: burst mode */ - | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15) + | ((cpu->byte_order == EMUL_BIG_ENDIAN? 1 : 0) << 15) /* endian mode */ - | ((cpu->cd.mips.cpu_type.rev==MIPS_5Kc?2:1) << 13) - /* 1=32-bit only, 2=32/64 */ + | ((cpu_type == MIPS_5Kc? 2 : 0) << 13) + /* 0=MIPS32, 1=64S, 2=64 */ | ( 0 << 10) /* Architecture revision */ | ( 1 << 7) /* MMU type: 1=TLB, 3=FMT */ | ( 2 << 0) /* kseg0 cache coherency algorithm */ ; - /* TODO: Config select 1: caches and such */ + /* Config select 1: caches etc. TODO: Associativity? */ + IB = cpu->machine->cache_picache_linesize - 1; + IB = IB < 0? 0 : (IB > 7? 7 : IB); + DB = cpu->machine->cache_pdcache_linesize - 1; + DB = DB < 0? 0 : (DB > 7? 7 : DB); + IC = cpu->machine->cache_picache - + cpu->machine->cache_picache_linesize - 7; + DC = cpu->machine->cache_pdcache - + cpu->machine->cache_pdcache_linesize - 7; + cpu->cd.mips.cop0_config_select1 = + ((cpu->cd.mips.cpu_type.nr_of_tlb_entries - 1) << 25) + | (IC << 22) /* IS: I-cache sets per way */ + | (IB << 19) /* IL: I-cache line-size */ + | (1 << 16) /* IA: I-cache assoc. (ways-1) */ + | (DC << 13) /* DS: D-cache sets per way */ + | (DB << 10) /* DL: D-cache line-size */ + | (1 << 7) /* DA: D-cache assoc. (ways-1) */ + | (16 * 0) /* Existance of PerformanceCounters */ + | ( 8 * 0) /* Existance of Watch Registers */ + | ( 4 * m16) /* Existance of MIPS16 */ + | ( 2 * 0) /* Existance of EJTAG */ + | ( 1 * 1) /* Existance of FPU */ + ; break; default: ; @@ -505,16 +532,16 @@ } +#ifdef BINTRANS /* * old_update_translation_table(): */ static void old_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page) { -#ifdef BINTRANS int a, b; struct vth32_table *tbl1; - void *p; + void *p_r, *p_w; uint32_t p_paddr; /* This table stuff only works for 32-bit mode: */ @@ -555,11 +582,12 @@ exit(1); } } - p = tbl1->haddr_entry[b]; + p_r = tbl1->haddr_entry[b*2]; + p_w = tbl1->haddr_entry[b*2+1]; p_paddr = tbl1->paddr_entry[b]; - /* printf(" p = %p\n", p); */ - if (p == NULL && p_paddr == 0 && - (host_page!=NULL || paddr_page!=0)) { + /* printf(" p_r=%p p_w=%p\n", p_r, p_w); */ + if (p_r == NULL && p_paddr == 0 && + (host_page != NULL || paddr_page != 0)) { tbl1->refcount ++; /* printf("ADDING %08x -> %p wf=%i (refcount is " "now %i)\n", (int)vaddr_page, host_page, @@ -567,21 +595,25 @@ } if (writeflag == -1) { /* Forced downgrade to read-only: */ - tbl1->haddr_entry[b] = (void *) - ((size_t)tbl1->haddr_entry[b] & ~1); - } else if (writeflag==0 && (size_t)p&1 && host_page != NULL) { + tbl1->haddr_entry[b*2 + 1] = NULL; + } else if (writeflag==0 && p_w != NULL && host_page != NULL) { /* Don't degrade a page from writable to readonly. */ } else { - if (host_page != NULL) - tbl1->haddr_entry[b] = (void *) - ((size_t)host_page + (writeflag?1:0)); - else - tbl1->haddr_entry[b] = NULL; + if (host_page != NULL) { + tbl1->haddr_entry[b*2] = host_page; + if (writeflag) + tbl1->haddr_entry[b*2+1] = host_page; + else + tbl1->haddr_entry[b*2+1] = NULL; + } else { + tbl1->haddr_entry[b*2] = NULL; + tbl1->haddr_entry[b*2+1] = NULL; + } tbl1->paddr_entry[b] = paddr_page; } tbl1->bintrans_chunks[b] = NULL; -#endif } +#endif /* @@ -617,7 +649,7 @@ { int a, b; struct vth32_table *tbl1; - void *p; + void *p_r, *p_w; uint32_t p_paddr; if (!cpu->machine->old_bintrans_enable) { @@ -647,14 +679,16 @@ tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; /* printf("tbl1 = %p\n", tbl1); */ - p = tbl1->haddr_entry[b]; + p_r = tbl1->haddr_entry[b*2]; + p_w = tbl1->haddr_entry[b*2+1]; p_paddr = tbl1->paddr_entry[b]; tbl1->bintrans_chunks[b] = NULL; - /* printf(" p = %p\n", p); */ - if (p != NULL || p_paddr != 0) { + /* printf("B: p_r=%p p_w=%p\n", p_r,p_w); */ + if (p_r != NULL || p_paddr != 0) { /* printf("Found a mapping, " "vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b); */ - tbl1->haddr_entry[b] = NULL; + tbl1->haddr_entry[b*2] = NULL; + tbl1->haddr_entry[b*2+1] = NULL; tbl1->paddr_entry[b] = 0; tbl1->refcount --; if (tbl1->refcount == 0) { @@ -685,7 +719,8 @@ tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; if (tbl1 != cpu->cd.mips.vaddr_to_hostaddr_nulltable) { for (b=0; b<0x400; b++) { - tbl1->haddr_entry[b] = NULL; + tbl1->haddr_entry[b*2] = NULL; + tbl1->haddr_entry[b*2+1] = NULL; tbl1->paddr_entry[b] = 0; tbl1->bintrans_chunks[b] = NULL; } @@ -940,7 +975,7 @@ * Read a value from a MIPS coprocessor register. */ void coproc_register_read(struct cpu *cpu, - struct mips_coproc *cp, int reg_nr, uint64_t *ptr) + struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int select) { int unimpl = 1; @@ -982,7 +1017,19 @@ if (cp->coproc_nr==0 && reg_nr==COP0_CAUSE) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_EPC) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_PRID) unimpl = 0; - if (cp->coproc_nr==0 && reg_nr==COP0_CONFIG) unimpl = 0; + if (cp->coproc_nr==0 && reg_nr==COP0_CONFIG) { + if (select > 0) { + switch (select) { + case 1: *ptr = cpu->cd.mips.cop0_config_select1; + break; + default:fatal("coproc_register_read(): unimplemented" + " config register select %i\n", select); + exit(1); + } + return; + } + unimpl = 0; + } if (cp->coproc_nr==0 && reg_nr==COP0_LLADDR) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_WATCHLO) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_WATCHHI) unimpl = 0; @@ -1022,7 +1069,8 @@ * Write a value to a MIPS coprocessor register. */ void coproc_register_write(struct cpu *cpu, - struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int flag64) + struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int flag64, + int select) { int unimpl = 1; int readonly = 0; @@ -1188,6 +1236,18 @@ readonly = 1; break; case COP0_CONFIG: + if (select > 0) { + switch (select) { + case 1: cpu->cd.mips.cop0_config_select1 = tmp; + break; + default:fatal("coproc_register_write(): unimpl" + "emented config register select " + "%i\n", select); + exit(1); + } + return; + } + /* fatal("COP0_CONFIG: modifying K0 bits: " "0x%08x => ", cp->reg[reg_nr]); */ tmp = *ptr; @@ -2515,13 +2575,16 @@ if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MFCz << 21)) || ((function & 0x03e007f8) == (COPz_DMFCz << 21)))) { if (unassemble_only) { - debug("%s%i\t%s,%s\n", + debug("%s%i\t%s,%s", copz==COPz_DMFCz? "dmfc" : "mfc", cpnr, regnames[rt], cop0_names[rd]); + if (function & 7) + debug(",%i", (int)(function & 7)); + debug("\n"); return; } coproc_register_read(cpu, cpu->cd.mips.coproc[cpnr], - rd, &tmpvalue); + rd, &tmpvalue, function & 7); cpu->cd.mips.gpr[rt] = tmpvalue; if (copz == COPz_MFCz) { /* Sign-extend: */ @@ -2535,9 +2598,12 @@ if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MTCz << 21)) || ((function & 0x03e007f8) == (COPz_DMTCz << 21)))) { if (unassemble_only) { - debug("%s%i\t%s,%s\n", + debug("%s%i\t%s,%s", copz==COPz_DMTCz? "dmtc" : "mtc", cpnr, regnames[rt], cop0_names[rd]); + if (function & 7) + debug(",%i", (int)(function & 7)); + debug("\n"); return; } tmpvalue = cpu->cd.mips.gpr[rt]; @@ -2548,7 +2614,7 @@ tmpvalue |= 0xffffffff00000000ULL; } coproc_register_write(cpu, cpu->cd.mips.coproc[cpnr], rd, - &tmpvalue, copz == COPz_DMTCz); + &tmpvalue, copz == COPz_DMTCz, function & 7); return; }