205 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
 | 
						|
 *	The President and Fellows of Harvard College.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 * 3. Neither the name of the University nor the names of its contributors
 | 
						|
 *    may be used to endorse or promote products derived from this software
 | 
						|
 *    without specific prior written permission.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
 | 
						|
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
 | 
						|
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
						|
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
						|
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
						|
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
						|
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
						|
 * SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
#include <kern/mips/regdefs.h>
 | 
						|
#include <mips/specialreg.h>
 | 
						|
 | 
						|
/*
 | 
						|
 * TLB handling for the MIPS-161.
 | 
						|
 *
 | 
						|
 * The MIPS-161 uses the simpler MIPS-1 (r2000/r3000) TLB rather
 | 
						|
 * than the paired-page TLB of later MIPS models.
 | 
						|
 *
 | 
						|
 * However, we handle MIPS32 pipeline hazards. If you want to run on
 | 
						|
 * a real MIPS-1, change the ssnops to plain nops and check where and
 | 
						|
 * how many you need in the matching processor docs.
 | 
						|
 *
 | 
						|
 * (ssnop means "superscalar nop"; it exists because the pipeline
 | 
						|
 * hazards require a fixed number of cycles, and a superscalar CPU can
 | 
						|
 * potentially issue arbitrarily many nops in one cycle.)
 | 
						|
 */
 | 
						|
 | 
						|
   .text
 | 
						|
   .set noreorder
 | 
						|
   .set mips32 /* so we can use ssnop */
 | 
						|
 | 
						|
   /*
 | 
						|
    * tlb_random: use the "tlbwr" instruction to write a TLB entry
 | 
						|
    * into a (very pseudo-) random slot in the TLB.
 | 
						|
    *
 | 
						|
    * Pipeline hazard: must wait between setting entryhi/lo and
 | 
						|
    * doing the tlbwr. Use two cycles; some processors may vary.
 | 
						|
    */
 | 
						|
   .globl tlb_random
 | 
						|
   .type tlb_random,@function
 | 
						|
   .ent tlb_random
 | 
						|
tlb_random:
 | 
						|
   mtc0 a0, c0_entryhi	/* store the passed entry into the */
 | 
						|
   mtc0 a1, c0_entrylo	/*   tlb entry registers */
 | 
						|
   ssnop		/* wait for pipeline hazard */
 | 
						|
   ssnop
 | 
						|
   tlbwr		/* do it */
 | 
						|
   j ra
 | 
						|
   nop
 | 
						|
   .end tlb_random
 | 
						|
 | 
						|
   /*
 | 
						|
    * tlb_write: use the "tlbwi" instruction to write a TLB entry
 | 
						|
    * into a selected slot in the TLB.
 | 
						|
    *
 | 
						|
    * Pipeline hazard: must wait between setting entryhi/lo and
 | 
						|
    * doing the tlbwi. Use two cycles; some processors may vary.
 | 
						|
    */
 | 
						|
   .text
 | 
						|
   .globl tlb_write
 | 
						|
   .type tlb_write,@function
 | 
						|
   .ent tlb_write
 | 
						|
tlb_write:
 | 
						|
   mtc0 a0, c0_entryhi	/* store the passed entry into the */
 | 
						|
   mtc0 a1, c0_entrylo	/*   tlb entry registers */
 | 
						|
   sll  t0, a2, CIN_INDEXSHIFT  /* shift the passed index into place */
 | 
						|
   mtc0 t0, c0_index	/* store the shifted index into the index register */
 | 
						|
   ssnop		/* wait for pipeline hazard */
 | 
						|
   ssnop
 | 
						|
   tlbwi		/* do it */
 | 
						|
   j ra
 | 
						|
   nop
 | 
						|
   .end tlb_write
 | 
						|
 | 
						|
   /*
 | 
						|
    * tlb_read: use the "tlbr" instruction to read a TLB entry
 | 
						|
    * from a selected slot in the TLB.
 | 
						|
    *
 | 
						|
    * Pipeline hazard: must wait between setting c0_index and
 | 
						|
    * doing the tlbr. Use two cycles; some processors may vary.
 | 
						|
    * Similarly, three more cycles before reading c0_entryhi/lo.
 | 
						|
    */
 | 
						|
   .text
 | 
						|
   .globl tlb_read
 | 
						|
   .type tlb_read,@function
 | 
						|
   .ent tlb_read
 | 
						|
tlb_read:
 | 
						|
   sll  t0, a2, CIN_INDEXSHIFT  /* shift the passed index into place */
 | 
						|
   mtc0 t0, c0_index	/* store the shifted index into the index register */
 | 
						|
   ssnop		/* wait for pipeline hazard */
 | 
						|
   ssnop
 | 
						|
   tlbr			/* do it */
 | 
						|
   ssnop		/* wait for pipeline hazard */
 | 
						|
   ssnop
 | 
						|
   ssnop
 | 
						|
   mfc0 t0, c0_entryhi	/* get the tlb entry out of the */
 | 
						|
   mfc0 t1, c0_entrylo	/*   tlb entry registers */
 | 
						|
   sw t0, 0(a0)		/* store through the passed pointer */
 | 
						|
   j ra
 | 
						|
   sw t1, 0(a1)		/* store (in delay slot) */
 | 
						|
   .end tlb_read
 | 
						|
 | 
						|
   /*
 | 
						|
    * tlb_probe: use the "tlbp" instruction to find the index in the
 | 
						|
    * TLB of a TLB entry matching the relevant parts of the one supplied.
 | 
						|
    *
 | 
						|
    * Pipeline hazard: must wait between setting c0_entryhi/lo and
 | 
						|
    * doing the tlbp. Use two cycles; some processors may vary.
 | 
						|
    * Similarly, two more cycles before reading c0_index.
 | 
						|
    */
 | 
						|
   .text
 | 
						|
   .globl tlb_probe
 | 
						|
   .type tlb_probe,@function
 | 
						|
   .ent tlb_probe
 | 
						|
tlb_probe:
 | 
						|
   mtc0 a0, c0_entryhi	/* store the passed entry into the */
 | 
						|
   mtc0 a1, c0_entrylo	/*   tlb entry registers */
 | 
						|
   ssnop		/* wait for pipeline hazard */
 | 
						|
   ssnop
 | 
						|
   tlbp			/* do it */
 | 
						|
   ssnop		/* wait for pipeline hazard */
 | 
						|
   ssnop
 | 
						|
   mfc0 t0, c0_index	/* fetch the index back in t0 */
 | 
						|
 | 
						|
   /*
 | 
						|
    * If the high bit (CIN_P) of c0_index is set, the probe failed.
 | 
						|
    * The high bit is not set <--> c0_index (now in t0) >= 0.
 | 
						|
    */
 | 
						|
 | 
						|
   bgez t0, 1f		/* did probe succeed? if so, skip forward */
 | 
						|
   nop			/* delay slot */
 | 
						|
   addi v0, z0, -1	/* set return value to -1 to indicate failure */
 | 
						|
   j ra			/* done */
 | 
						|
   nop			/* delay slot */
 | 
						|
 | 
						|
1:
 | 
						|
   /* succeeded - get the index field from the index register value */
 | 
						|
   andi t1, t0, CIN_INDEX       /* mask off the field */
 | 
						|
   j ra				/* done */
 | 
						|
   sra  v0, t1, CIN_INDEXSHIFT  /* shift it (in delay slot) */
 | 
						|
   .end tlb_probe
 | 
						|
 | 
						|
 | 
						|
   /*
 | 
						|
    * tlb_reset
 | 
						|
    *
 | 
						|
    * Initialize the TLB. At processor startup, the TLB state is completely
 | 
						|
    * undefined. So be sure to avoid creating any duplicates. Also make sure
 | 
						|
    * that the initialization entries don't duplicate the INVALID entries
 | 
						|
    * defined in tlb.h. (This way you can write the invalid entries in
 | 
						|
    * without having to use tlbp to find out if they're going to cause dups.)
 | 
						|
    *
 | 
						|
    * This function is not defined in tlb.h because it's only called from
 | 
						|
    * start.S.
 | 
						|
    *
 | 
						|
    * Pipeline hazards are as above.
 | 
						|
    */
 | 
						|
   .text
 | 
						|
   .globl tlb_reset
 | 
						|
   .type tlb_reset,@function
 | 
						|
   .ent tlb_reset
 | 
						|
tlb_reset:
 | 
						|
   li t0, 0			/* t0 <- tlb index number (shifted) */
 | 
						|
   li t1, 0x81000000		/* t1 <- tlb reset vaddr */
 | 
						|
1:
 | 
						|
   mtc0 $0, c0_entrylo 		/* set up proposed tlb entry for reset */
 | 
						|
   mtc0 t1, c0_entryhi
 | 
						|
   ssnop			/* wait for pipeline hazard */
 | 
						|
   ssnop
 | 
						|
   tlbp				/* check if it already exists */
 | 
						|
   ssnop			/* wait for pipeline hazard */
 | 
						|
   ssnop
 | 
						|
   mfc0 t2, c0_index
 | 
						|
   bgez t2, 1b			/* if it does, loop back */
 | 
						|
   addiu t1, t1, 0x1000		/* next vaddr (in delay slot) */
 | 
						|
   mtc0 t0, c0_index		/* doesn't exist, set index to write to */
 | 
						|
   ssnop			/* wait for pipeline hazard */
 | 
						|
   ssnop
 | 
						|
   addiu t0, t0, 0x100		/* next tlb index (shifted) */
 | 
						|
   bne t0, 0x4000, 1b		/* if it's not the last tlb index, loop */
 | 
						|
   tlbwi			/* write tlb entry (in delay slot) */
 | 
						|
   j ra				/* done */
 | 
						|
   nop				/* delay slot */
 | 
						|
   .end tlb_reset
 |