Revision 29e179bc target-sh4/helper.c

b/target-sh4/helper.c
282 282
    return match;
283 283
}
284 284

  
285
static int same_tlb_entry_exists(const tlb_t * haystack, uint8_t nbtlb,
286
				 const tlb_t * needle)
287
{
288
    int i;
289
    for (i = 0; i < nbtlb; i++)
290
        if (!memcmp(&haystack[i], needle, sizeof(tlb_t)))
291
	    return 1;
292
    return 0;
293
}
294

  
295
static void increment_urc(CPUState * env)
296
{
297
    uint8_t urb, urc;
298

  
299
    /* Increment URC */
300
    urb = ((env->mmucr) >> 18) & 0x3f;
301
    urc = ((env->mmucr) >> 10) & 0x3f;
302
    urc++;
303
    if (urc == urb || urc == UTLB_SIZE - 1)
304
	urc = 0;
305
    env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
306
}
307

  
285 308
/* Find itlb entry - update itlb from utlb if necessary and asked for
286 309
   Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE
287 310
   Update the itlb from utlb if update is not 0
......
313 336
   Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */
314 337
int find_utlb_entry(CPUState * env, target_ulong address, int use_asid)
315 338
{
316
    uint8_t urb, urc;
317

  
318
    /* Increment URC */
319
    urb = ((env->mmucr) >> 18) & 0x3f;
320
    urc = ((env->mmucr) >> 10) & 0x3f;
321
    urc++;
322
    if (urc == urb || urc == UTLB_SIZE - 1)
323
	urc = 0;
324
    env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
339
    /* per utlb access */
340
    increment_urc(env);
325 341

  
326 342
    /* Return entry */
327 343
    return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
......
407 423
	    return (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE :
408 424
		MMU_DTLB_MISS_READ;
409 425
	}
410
	/* Mask upper 3 bits */
411
	*physical = address & 0x1FFFFFFF;
426
	if (address >= 0x80000000 && address < 0xc0000000) {
427
	    /* Mask upper 3 bits for P1 and P2 areas */
428
	    *physical = address & 0x1fffffff;
429
	} else if (address >= 0xfc000000) {
430
	    /*
431
	     * Mask upper 3 bits for control registers in P4 area,
432
	     * to unify access to control registers via P0-P3 area.
433
	     * The addresses for cache store queue, TLB address array
434
	     * are not masked.
435
	     */
436
	*physical = address & 0x1fffffff;
437
	} else {
438
	    /* access to cache store queue, or TLB address array. */
439
	    *physical = address;
440
	}
412 441
	*prot = PAGE_READ | PAGE_WRITE;
413 442
	return MMU_OK;
414 443
    }
......
543 572
    entry->tc   = (uint8_t)cpu_ptea_tc(env->ptea);
544 573
}
545 574

  
575
void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
576
				    uint32_t mem_value)
577
{
578
    int associate = addr & 0x0000080;
579
    uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
580
    uint8_t d = (uint8_t)((mem_value & 0x00000200) >> 9);
581
    uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
582
    uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
583

  
584
    if (associate) {
585
        int i;
586
	tlb_t * utlb_match_entry = NULL;
587
	int needs_tlb_flush = 0;
588

  
589
	/* search UTLB */
590
	for (i = 0; i < UTLB_SIZE; i++) {
591
            tlb_t * entry = &s->utlb[i];
592
            if (!entry->v)
593
	        continue;
594

  
595
            if (entry->vpn == vpn && entry->asid == asid) {
596
	        if (utlb_match_entry) {
597
		    /* Multiple TLB Exception */
598
		    s->exception_index = 0x140;
599
		    s->tea = addr;
600
		    break;
601
	        }
602
		if (entry->v && !v)
603
		    needs_tlb_flush = 1;
604
		entry->v = v;
605
		entry->d = d;
606
	        utlb_match_entry = entry;
607
	    }
608
	    increment_urc(s); /* per utlb access */
609
	}
610

  
611
	/* search ITLB */
612
	for (i = 0; i < ITLB_SIZE; i++) {
613
            tlb_t * entry = &s->itlb[i];
614
            if (entry->vpn == vpn && entry->asid == asid) {
615
	        if (entry->v && !v)
616
		    needs_tlb_flush = 1;
617
	        if (utlb_match_entry)
618
		    *entry = *utlb_match_entry;
619
	        else
620
		    entry->v = v;
621
		break;
622
	    }
623
	}
624

  
625
	if (needs_tlb_flush)
626
	    tlb_flush_page(s, vpn << 10);
627
        
628
    } else {
629
        int index = (addr & 0x00003f00) >> 8;
630
        tlb_t * entry = &s->utlb[index];
631
	if (entry->v) {
632
	    /* Overwriting valid entry in utlb. */
633
            target_ulong address = entry->vpn << 10;
634
	    if (!same_tlb_entry_exists(s->itlb, ITLB_SIZE, entry)) {
635
	        tlb_flush_page(s, address);
636
	    }
637
	}
638
	entry->asid = asid;
639
	entry->vpn = vpn;
640
	entry->d = d;
641
	entry->v = v;
642
	increment_urc(s);
643
    }
644
}
645

  
546 646
#endif

Also available in: Unified diff