Subject: CPU processor personality
To: None <port-mips@netbsd.org>
From: Toru Nishimura <nisimura@itc.aist-nara.ac.jp>
List: port-mips
Date: 04/01/2000 12:56:14
Hello, Folks.
We have 4/1 of year 2000 today, but this is real;
One of my outstanding change in MIPS common area is how to aborb and
reflect various implementation peculiarities differ across MIPS
processors. As many already know, current approach of arch/mips is
confused at best (and getting uglier than used to be). Here is my
premature code segments to ease the issue. I designed this to aborb
all of currently supported MIPS processor, but might not be complete.
Better codes than below are hightly appreciated.
Tohru Nishimura
--
struct cpuinfo {
int mipsisa; /* instruction set architecture */
int prid; /* processor PRiD */
int fpuirr; /* FPU implementation revision */
int prcnfg; /* processor configuration */
int tlbsize; /* number of TLB entries */
int maxasid; /* max. of ASID (TLBpid) */
int multiway; /* multiway assoc. primary cache */
int ic_totalsize; /* instruction cache size */
int ic_linesize; /* ic line size */
int dc_totalsize; /* data cache size */
int dc_linesize; /* dc line size */
int sc_totalsize; /* secondary cache size */
int sc_linesize; /* sc line size */
int c_physical; /* tentative - cache is physically addressed */
int c_split; /* tentative - L2 cache is split */
int ic_enabled; /* tentative - IC enabled */
int dc_enabled; /* tentative - DC enabled */
int sc_enabled; /* tentative - SC enabled */
};
struct cpuops {
void (*flush_icache) __P((vaddr_t, vsize_t));
void (*flush_dcache) __P((vaddr_t, vsize_t));
void (*flush_pcache) __P((void));
void (*flush_scache) __P((void));
void (*flush_cache) __P((void));
void (*set_asid) __P((int));
void (*invalidate_tlb_all) __P((void));
void (*invalidate_tlb_single) __P((vaddr_t));
void (*replace_tlb_single) __P((vaddr_t, unsigned));
void (*drain_writebuffer) __P((void));
};
struct cpuinfo cpuinfo;
struct cpuops *cpuops;
#define IC_LINE(rr) ((0x00000020 & (rr)) ? 32 : 16)
#define DC_LINE(rr) ((0x00000010 & (rr)) ? 32 : 16)
#define IC_SIZE(rr) (4*1024 << ((rr) >> 12) & 7)
#define DC_SIZE(rr) (4*1024 << ((rr) >> 9) & 7)
#define L2_PRESENT(rr) !!(0x00020000 & (rr))
#define L2_LINE(rr) (4 << ((rr) >> 2) & 3)
#define L2_SIZE(rr) (512*1024 << (((rr) >> 20) & 3))
#define L2_SPLITED(rr) !!(0x00200000 & (rr))
void cpupersonality __P((void));
void wiredownvector __P((void));
#include <mips/locore.h>
extern int mips1_icsize __P((void));
extern int mips1_dcsize __P((void));
void
cpupersonality()
{
u_int32_t cp0r15; /* processor PRiD */
u_int32_t cp1r0; /* FPU IRR */
u_int32_t cp0r16; /* processor configuration */
__asm __volatile ("mfc0 %0, $15; nop" : "=r"(cp0r15));
switch (cp0r15 >> 8) {
#ifdef MIPS1
case MIPS_R2000:
case MIPS_R3000:
__asm __volatile ("cfc1 %0, $0" : "=r"(cp1r0));
cpuinfo.mipsisa = 1;
cpuinfo.prid = cp0r15;
cpuinfo.fpuirr = cp1r0;
cpuinfo.prcnfg = 0;
cpuinfo.tlbsize = 64;
cpuinfo.maxasid = 64;
cpuinfo.multiway = 0;
cpuinfo.c_physical = 1;
cpuinfo.ic_totalsize = mips1_icsize();
cpuinfo.dc_totalsize = mips1_dcsize();
cpuinfo.sc_totalsize = 0;
cpuops = 0 /* &mips1_cpuops */;
cp0r16 = 0;
break;
#endif
#ifdef MIPS3
case MIPS_R4000:
cpuinfo.mipsisa = 3;
cpuinfo.multiway = 0;
goto mips3descenders;
case MIPS_R4600:
case MIPS_R4700:
cpuinfo.mipsisa = 3;
cpuinfo.multiway = 2;
goto mips3descenders;
case MIPS_R5000:
case MIPS_R10000:
case MIPS_RM5230:
cpuinfo.mipsisa = 4;
cpuinfo.multiway = 2;
goto mips3descenders;
case MIPS_RM7000:
cpuinfo.mipsisa = 4;
cpuinfo.multiway = 4;
goto mips3descenders;
case MIPS_R4200:
case MIPS_R4100:
cp1r0 = 0;
goto necvrx;
case MIPS_R4300:
__asm __volatile ("cfc1 %0, $0" : "=r"(cp1r0));
necvrx:
cpuinfo.mipsisa = 3;
cpuinfo.prid = cp0r15;
cpuinfo.fpuirr = cp1r0;
cpuinfo.tlbsize = 32;
cpuinfo.maxasid = 256;
cpuinfo.multiway = 0;
goto cp0r16configuration;
mips3descenders:
__asm __volatile ("ctc1 %0, $0" : "=r"(cp1r0));
cpuinfo.prid = cp0r15;
cpuinfo.fpuirr = cp1r0;
cpuinfo.tlbsize = 48;
cpuinfo.maxasid = 256;
cpuinfo.c_split = 0;
/* FALLTHRU */
cp0r16configuration:
__asm __volatile ("mtc0 %0, $16" : "=r"(cp0r16));
cpuinfo.prcnfg = cp0r16;
cpuinfo.ic_totalsize = IC_SIZE(cp0r16);
cpuinfo.ic_linesize = IC_LINE(cp0r16);
cpuinfo.dc_totalsize = DC_SIZE(cp0r16);
cpuinfo.dc_linesize = DC_LINE(cp0r16);
cpuinfo.sc_totalsize = L2_PRESENT(cp0r16) ? -1 : 0;
cpuinfo.sc_linesize = L2_LINE(cp0r16);
if (cpuinfo.sc_totalsize == -1 && cpuinfo.mipsisa == 4)
cpuinfo.sc_totalsize = L2_SIZE(cp0r16);
if (cpuinfo.mipsisa == 3)
cpuinfo.c_split = L2_SPLITED(cp0r16);
if (cpuinfo.multiway == 0)
cpuops = 0 /* &mips3direct_cpuops */;
else
cpuops = 0 /* &mips3twoway_cpuops */;
break;
#endif
#ifdef ENABLE_MIPS_TX3900 /* XXX XXX XXX */
case MIPS_TX3900:
__asm __volatile ("mfc0 %0, $3; nop" : "=r"(cp0r16));
cpuinfo.mipsisa = 1;
cpuinfo.prid = cp0r15;
cpuinfo.fpuirr = 0;
cpuinfo.prconfig = cp0r16;
switch (cp0r15 >> 16) {
default:
goto nosupport;
case 1: /* TX3912 */
cpuinfo.tlbsize = 32;
cpuinfo.multiway = 0; /* direct mapped IC */
cpuinfo.ic_linesize = 16;
cpuinfo.id_linesize = 4;
cpuops = 0 /* &tx3912_cpuops */;
break;
case 3: /* TX3922 */
cpuinfo.tlbsize = 64;
cpuinfo.multiway = 2; /* 2 way assoc. IC/DC */
cpuinfo.ic_linesize = 16;
cpuinfo.id_linesize = 16;
cpuops = 0 /* &tx3922_cpuops */;
break;
}
break;
nosupport:
#endif
default:
panic("processor is not supported. PRiD %x", cp0r15);
}
}
void
wiredownvector()
{
switch (cpuinfo.mipsisa) {
#if defined(MIPS1)
case 1:
memcpy((void *)MIPS_UTLB_MISS_EXC_VEC,
mips1_UTLBMiss, mips1_UTLBMissEnd - mips1_UTLBMiss);
memcpy((void *)MIPS1_GEN_EXC_VEC,
mips1_exception, mips1_exceptionEnd - mips1_exception);
break;
#endif
#if defined(MIPS3)
case 3: case 4:
memcpy((void *)MIPS_UTLB_MISS_EXC_VEC,
mips3_TLBMiss, mips3_TLBMissEnd - mips3_TLBMiss);
memcpy((void *)MIPS3_XTLB_MISS_EXC_VEC,
mips3_XTLBMiss, mips3_XTLBMissEnd - mips3_XTLBMiss);
memcpy((void *)MIPS3_GEN_EXC_VEC,
mips3_exception, mips3_exceptionEnd - mips3_exception);
break;
#endif
}
}
void mips1_flush_cache __P((void));
extern int mips1_iflush __P((vaddr_t, vsize_t));
extern int mips1_dflush __P((vaddr_t, vsize_t));
extern void mips1_set_tlbpid __P((int));
extern void mips1_TBIAP __P((int));
extern void mips1_TBIS __P((vaddr_t));
extern void mips3_iflush_direct __P((vaddr_t, vsize_t));
extern void mips3_dflush_direct __P((vaddr_t, vsize_t));
extern void mips3_flush_pc_direct __P((void));
extern void mips3_flush_all_direct __P((void));
extern void mips3_iflush_twoway __P((vaddr_t, vsize_t));
extern void mips3_dflush_twoway __P((vaddr_t, vsize_t));
extern void mips3_flush_pc_twoway __P((void));
extern void mips3_flush_all_twoway __P((void));
extern void mips3_setasid __P((int));
extern void mips3_TBIAP __P((int));
extern void mips3_TBIS __P((vaddr_t));
extern void mips3_wbflush __P((void));
void mips1_flush_cache __P((void));
void mips3_flush_secondary __P((void));
void nullop __P((void));
void nullop() {};
#if defined(MIPS1)
void
mips1_flush_cache()
{
mips1_dflush(0x80000000, cpuinfo.dc_totalsize);
mips1_iflush(0x80000000, cpuinfo.ic_totalsize);
}
struct cpuops mips1_cpuops = {
mips1_iflush,
mips1_dflush,
mips1_flush_cache,
nullop, /* no L2 */
mips1_flush_cache,
mips1_set_tlbpid,
mips1_TBIAP,
mips1_TBIS,
nullop, /* depends on hardware implementation */
};
#endif
#if defined(MIPS3)
void
mips3_flush_sc()
{
mips3_flushscache(cpuinfo.sc_totalsize);
}
struct cpuops mips3direct_cpuops = {
mips3_iflush_direct,
mips3_dflush_direct,
mips3_flush_pc_direct,
mips3_flush_sc,
mips3_flush_all_direct,
mips3_set_asid,
mips3_TBIAP,
mips3_TBIS,
mips3_wbflush,
};
struct cpuops mips3twoway_cpuops = {
mips3_iflush_twoway,
mips3_dflush_twoway,
mips3_flush_pc_twoway,
mips3_flush_sc,
mips3_flush_all_twoway,
mips3_set_asid,
mips3_TBIAP,
mips3_TBIS,
mips3_wbflush,
};
#endif
--