📄 c4011.c
字号:
/************************************************************* * File: lib/c4011.c * Purpose: Part of C runtime library * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 970516 Created from c4010.c * 970910 Added ifndef around re_sonic for BE builds * 970910 Added call to sw2kseg1 before CCC writes * 971115 Added code to set re_sonic * 980615 Renamed re_sonic re_ether * 980616 Added addDevice call for iceport. * 980616 Added "case 8" devinit. * 980730 Added F_MIPS for Crossview. * 980730 Fixed the HI reg #. * 980826 Added diag prints to setbp same as c4101. * 980826 Added hwdbReq(). * 980827 Fixed brkRemove ram bpt. Needed outw not write_target(). * 981107 Fixed typo for build when CLKFREQ is defined * 981214 Moved build of dcs value from setbp_target to brkInstall */#ifndef LR4010#define LR4010#endif#include "mips.h"#include <termio.h>#include <terms.h>#include <pmon.h>#define VALID_BIT (1<<1)#define inb(a) (*((volatile Uchar *)(a)))#define outb(a,v) (*((volatile Uchar *)(a))=(v))#define outw(a,v) (*((volatile Ulong *)(a))=(v))#define inw(a) (*((volatile Ulong *)(a)))/* UART 16-bit timer 4.34us/tick */#ifdef MIPSEB#define BASE_2681 0xbe000003#else#define BASE_2681 0xbe000000#endif#define SRA_2681 ((1*4)+BASE_2681)#define THRA_2681 ((3*4)+BASE_2681)#define ACR_2681 ((4*4)+BASE_2681)#define ISR_2681 ((5*4)+BASE_2681)#define CTU_2681 ((6*4)+BASE_2681)#define CTL_2681 ((7*4)+BASE_2681)#define START_2681 ((14*4)+BASE_2681)#define STOP_2681 ((15*4)+BASE_2681)#define TMRRDY_2681 0x08#define TXEMT_2681 0x08#define TXRDY_2681 0x04#define DELAY 184 /* 800us */static measureFreq();static c4011exception();static Ulong mXccc();int a4011exception();Ulong saved_scbus_ea_4011;static char *c0_regs[] = { "C0_INX", "C0_RAND", "C0_TLBLO", "C0_BPC", "C0_CTEXT", "C0_PAGEMASK", "C0_WIRED", "C0_DCS", "C0_BADADDR", "C0_COUNT", "C0_TLBHI", "C0_COMPARE", "C0_SR", "C0_CAUSE", "C0_EPC", "C0_PRID", "C0_CONFIG", "C0_LLADR", "C0_BPC", "C0_BDA", "C0_BPCM", "C0_BDAM", "$22", "C0_ROTATE", "C0_CMASK", "$25", "$26", "$27", "$28", "$29", "C0_ERREPC", "$31" };static RegSpec CCCreg[] = { {1,25,"EVI",2,0,0}, {1,24,"CMP",2,0,0}, {1,23,"IIE",2,0,0}, {1,22,"DIE",2,0,0}, {1,21,"MUL",2,0,0}, {1,20,"MAD",2,0,0}, {1,19,"TMR",2,0,0}, {1,18,"BGE",2,0,0}, {1,17,"IE0",2,0,0}, {1,16,"IE1",2,0,0}, {2,14,"IS",10,0,0}, {1,13,"DE0",2,0,0}, {1,12,"DE1",2,0,0}, {2,10,"DS",10,0,0}, {1,9,"IPWE",2,0,0}, {2,7,"IPWS",10,0,0}, {1,6,"TE",2,0,0}, {1,5,"WB",2,0,0}, {1,4,"SR0",2,0,0}, {1,3,"SR1",2,0,0}, {1,2,"ISC",2,0,0}, {1,1,"TAG",2,0,0}, {1,0,"INV",2,0,0}, {0}};static RegSpec DCSreg[] = { {1,31,"TR",2,0,0}, {1,30,"UD",2,0,0}, {1,29,"KD",2,0,0}, {1,28,"TE",2,0,0}, {1,27,"DW",2,0,0}, {1,26,"DR",2,0,0}, {1,25,"DAE",2,0,0}, {1,24,"PCE",2,0,0}, {1,23,"DE",2,0,0}, {1,5,"T",2,0,0}, {1,4,"W",2,0,0}, {1,3,"R",2,0,0}, {1,2,"DA",2,0,0}, {1,1,"PC",2,0,0}, {1,0,"DB",2,0,0}, {0}};static RegSpec SCerreg[] = { {1,1,"BEDE",2,0,0}, {1,0,"BERR",2,0,0}, {0}};static RegSpec EVintreg[] = { {1,1,"HEVI",2,0,0}, {1,0,"SEVI",2,0,0}, {0}};static RegRec reglist[] = { {mXpc,0,"PC","pc",14,(F_MIPS|F_CPU)}, {mXgpr,0,"HI","HI",32,(F_CPU|F_MIPS)}, {mXgpr,0,"LO","LO",33,(F_CPU|F_MIPS)}, /* ========== cp0 ========== */ {mXc0,mips_sr_def,"C0_SR","SR",12,(F_CP0|F_MIPS)}, {mXc0,mips_cause_def,"C0_CAUSE","CAUSE",13,(F_CP0|F_MIPS)}, {mXc0,mips_prid_def,"C0_PRID","PRID",15,(F_CP0|F_RO|F_MIPS)}, {mXc0,0,"C0_EPC","EPC",14,(F_CP0|F_MIPS)}, {mXc0,0,"C0_BADVA","BADVA",8,(F_CP0|F_MIPS)},/*--------- end of basic MIPS stuff ------------------------*/ {mXccc,CCCreg,"C0_CCC","CCC",C0_CCC,0}, {mXc0,DCSreg,"C0_DCS","DCS",C0_DCS,0}, {mXmem,SCerreg,"M_SCBUS_ST","SCBUS_ST",M_SCBUS_ST,0}, {mXmem,0,"M_SCBUS_EA","SCBUS_EA",M_SCBUS_EA,F_RO}, {mXmem,EVintreg,"M_EXVI","EXVI",M_EXVI,0}, {mXc0,0,"C0_INDEX","INDEX",C0_INDEX,0}, {mXc0,0,"C0_RANDOM","RANDOM",C0_RANDOM,0}, {mXc0,0,"C0_ENTRYLO","ENTRYLO",C0_ENTRYLO,0}, {mXc0,0,"C0_CONTEXT","CONTEXT",C0_CONTEXT,0}, {mXc0,0,"C0_PAGEMASK","PAGEMASK",C0_PAGEMASK,0}, {mXc0,0,"C0_WIRED","WIRED",C0_WIRED,0}, {mXc0,0,"C0_COUNT","COUNT",C0_COUNT,0}, {mXc0,0,"C0_ENTRYHI","ENTRYHI",C0_ENTRYHI,0}, {mXc0,0,"C0_COMPARE","COMPARE",C0_COMPARE,0}, {mXc0,0,"C0_LLADR","LLADR",C0_LLADR,0}, {mXc0,0,"C0_BPC","BPC",18,0}, {mXc0,0,"C0_BDA","BDA",19,0}, {mXc0,0,"C0_BPCM","BPCM",20,0}, {mXc0,0,"C0_BDAM","BDAM",21,0}, {mXc0,0,"C0_ROTATE","ROTATE",C0_ROTATE,0}, {mXc0,0,"C0_CMASK","CMASK",C0_CMASK,0}, {mXc0,0,"C0_ERREPC","ERREPC",C0_ERREPC,0}, {0}};int do_cache401x();extern Optdesc cache_opts401x[];static CmdRec cmds[] = { {"cache",cache_opts401x,do_cache401x}, {0}};static int setbp_target(),brkInstall(),brkRemove();static int hwibReq(),hwdbReq();extern int iflush_needed,dflush_needed;extern int icache_size,dcache_size,cache_line_size;extern fFunc *clkinit_ptr;Func *clkinit_2681();extern void *_clkinfo;int iceport();static struct iceportinfo iceportdat = {0xb0ff0000};int p2681();static struct p2681info tty1dat = {0xbe000000,3,4};/************************************************************** c4011init(type)*/c4011init(type)int type;{int cf,i;switch (type) { case 0 : /* hostInit(0) */ break; case 1 : /* */ break; case 2 : /* cpuInit(2) */ c0regNames = c0_regs; for (i=0;reglist[i].func;i++) addRegRec(®list[i]); for (i=0;cmds[i].name;i++) addCmdRec(&cmds[i]); icache_size = 8*1024; dcache_size = 8*1024; cache_line_size = 32; brkInstall_ptr = brkInstall; brkRemove_ptr = brkRemove; setbp_target_ptr = setbp_target; if ((cf=measureFreq())==0) cf = 80; /* default */ setdMonEnv("clkfreq",cf); clkinit_ptr = clkinit_2681; _clkinfo = &tty1dat; break; case 3 : /* hostInit(3) extra memory */ break; case 4 : /* hostInit(4) */#ifdef NVRAM nvInfo.start = 0xbfc00000; nvInfo.width = 1; nvInfo.gap = 1; nvInfo.nvbase = 0; #endif break; case 5 : /* hostInit(5) */#if defined(ETHERNET) && defined(MIPSEB) re_ether = 1;#endif sscanf(getMonEnv("clkfreq"),"%d",&cf); outw(M_DRAM_REFRESH,(cf/10)*156); saved_scbus_ea_4011 = -1;#if 1 asm_exception_ptr = a4011exception; c_exception_ptr = c4011exception;#endif break; case 6 : /* 980616 If the iceport has no clock (no txrdy) the "init -c" command won't work. */ if (inw(0xb0ff0008)&1) addDevice((Addr)&iceportdat,0,iceport,1024,B9600); break; case 7 : /* hostInit(7) */#ifdef NVRAM nvInfo.start = 0xbfd00000;#endif break; case 8 : addDevice((Addr)&tty1dat,0,p2681,1024,DEFBAUD); addDevice((Addr)&tty1dat,1,p2681,1024,DEFBAUD);#ifdef ETHERNET ether_driver_ptr = sonic_driver;#endif break; }}/************************************************************** static c4011exception()*/static c4011exception(){if (saved_scbus_ea_4011 != -1) { printf("\nSCBUS error ea=%08x\n",saved_scbus_ea_4011); saved_scbus_ea_4011 = -1; stop(0); }}/************************************************************** measureFreq()** The scheme I use is to the number of cpu cycles that were* executed while waiting for a fixed time to elapse.* * To wait a fixed time I program the 2681 Timer to delay 800us. I poll* the ISR in the UART waiting for it to reach zero. This is reliable * because we always use the same speed crystal for the DUART.* * To measure the cpu clocks, I use whatever timer is available inside the* cpu.*/static measureFreq(){static measure_4011();Ulong cpu;#ifdef CLKFREQreturn CLKFREQ; /* 981107 */#endifcpu = measure_4011();cpu += measure_4011();return ((cpu/16)+126)/100;}/**************************************************************/static measure_4011(){Ulong cpu,dummy,tmode;/* preload timers */outb(ACR_2681,0x30); /* counter mode */dummy = inb(STOP_2681);outb(CTU_2681,DELAY>>8);outb(CTL_2681,DELAY&0xff);/* start timers */dummy = inb(START_2681);mtc0(C0_COUNT,0);/* wait for 2681 to reach zero */while (!(inb(ISR_2681)&TMRRDY_2681)) ;/* read CPU timer */cpu = mfc0(C0_COUNT);dummy = inb(STOP_2681);outb(ACR_2681,0x70); /* timer mode */return(cpu);}/************************************************************** Ulong mXccc(write,reg,size,value)* must copy-back the dcache before changing CCC_WB bit. * For simplicity I do it for all writes to the CCC reg.*/static Ulong mXccc(write,reg,size,value)int write,reg,size,value;{if (write == 0) /* read */ return(read_target(XT_CP0,reg,0));else { flush_target(DCACHE); sw2kseg1(); write_target(XT_CP0,reg,value); }}/************************************************************** static int setbp_target(n,type,addr,addr2,value)* type: 1=bpc 2=bda 3=itemp 4=sstep 5=nonrt* returns bp number, or -1 on error.* addr2 and value are only used for BPTYPE_DATA.* In the case of BPTYPE_DATA the access type (r/w) is encoded* in the 2nd nibble of 'type';*/static int setbp_target(n,type,addr,addr2,value)int n,type;Ulong addr,addr2,value;{int i,method,atype,code;Ulong info;long mask; /* must be signed */ #if 0printf("setbp_target(%d,%d,%08x,%08x,%08x)\n",n,type,addr,addr2,value);#endifatype = type>>4;type &= 0xf;code = 0;if (type == BPTYPE_NONRT) { printf("Warning: This breakpoint requires non real-time execution.\n"); }else if (type == BPTYPE_PC || type == BPTYPE_ITMP || type == BPTYPE_TRACE) { if (is_writeable_target(addr)) { if (verbose) fprintf(dfp,"is writeable\n"); method = BRK_METHOD_RAM; } else if (IS_K0SEG(addr) && ilockReq401x(addr)) { if (verbose) fprintf(dfp,"ilock avail\n"); method = BRK_METHOD_ROM; } else if (hwibReq(addr)) { if (verbose) fprintf(dfp,"hwib avail\n"); method = BRK_METHOD_HW; mask = 0xffffffff; } else { printf("%08x: can't set bpt\n",addr); return(0-BP_E_ERR); } }else if (type == BPTYPE_DATA) { if (!hwdbReq(addr)) { printf("%08x: can't set bpt\n",addr); return(0-BP_E_ERR); } method = BRK_METHOD_HW; info = 0; if (atype&1) info |= 2; if (atype&2) info |= 1; if (atype&4) return(0-BP_E_VAL); if (addr2) { /* compute mask */ for (mask=0x80000000;(addr&mask) == (addr2&mask);mask>>=1) ; mask <<= 1; /* oops! one step too many */ code |= BP_W_MSK; } else mask = 0xffffffff; /* all-enable */ }else printf("setbp_target: %x: bad type\n",type);if (n == -1) { for (i=0;i<MAX_BPT;i++) if (brkList[i].type == 0) break; if (i >= MAX_BPT) { printf("Fatal error: out of bpts\n"); return(0-BP_E_ERR); } n = i; }if (n < 0 || n >= MAX_BPT) { printf("%d: bad bpt number\n",n); return(0-BP_E_ERR); }brkList[n].type = type;brkList[n].addr = addr;brkList[n].method = method;brkList[n].mask = mask;brkList[n].aux[0] = info;brkList[n].isset = 0;return((code<<16)|n);}/************************************************************** static brkInstall(type)* type=1 install regular+temp bpts* type=2 install trace bpts*/static brkInstall(type)int type;{int i,flag;Ulong dcs,tag,vmask,addr;if (verbose) fprintf(dfp,"\nbrkInstall(%d)\n",type);flag = 0;for (i=0;i<MAX_BPT;i++) { /* first discard the entries we aren't going to handle */ if (brkList[i].type==0) continue; if (type == 1 && brkList[i].type == BPTYPE_TRACE) continue; if (type == 2 && brkList[i].type != BPTYPE_TRACE) continue; addr = brkList[i].addr; switch (brkList[i].method) { case BRK_METHOD_RAM : if (verbose) fprintf(dfp,"installing ram bpt at %08x\n",addr); brkList[i].val = read_target(XT_MEM,addr,4); outw(addr,BPT_CODE); iflush_needed = dflush_needed = 1; flush_target(ICACHE); flush_target(DCACHE); brkList[i].isset = 1; break; case BRK_METHOD_ROM : if (verbose) fprintf(dfp,"installing rom bpt at %08x\n",addr); if (!flag) flush_target(ICACHE); flag = 1; if (!(readCache401x(1,ICACHETAG,addr)&VALID_BIT)) initIsp401x(addr); wrIsp401x(addr,BPT_CODE); brkList[i].isset = 1; break; case BRK_METHOD_HW : dcs = read_target(XT_DBX,DBX_DCS,0); if (brkList[i].type == BPTYPE_DATA) { if (verbose) fprintf(dfp,"installing hwdb bpt at %08x\n",addr); write_target(XT_CP0,DBX_BDA,addr); write_target(XT_CP0,DBX_BDAM,brkList[i].mask); dcs |= DCS_TR|DCS_UD|DCS_KD|DCS_DE|DCS_DAE; if (brkList[i].aux[0]&2) dcs |= DCS_DR; if (brkList[i].aux[0]&1) dcs |= DCS_DW; } else { if (verbose) fprintf(dfp,"installing hwib bpt at %08x\n",addr); write_target(XT_CP0,DBX_BPC,addr); write_target(XT_CP0,DBX_BPCM,brkList[i].mask); dcs |= DCS_TR|DCS_UD|DCS_KD|DCS_DE|DCS_PCE; } write_target(XT_DBX,DBX_DCS,dcs); brkList[i].isset = 1; break; default : printf("%d: error bad method\n",brkList[i].method); return(-1); } }}/************************************************************** static int brkRemove(epc)* returns type: 0=none 1=bpc 2=bda 3=itemp 4=sstep*/static int brkRemove(epc)Ulong epc;{int i,type,flag;Ulong ccc;if (verbose) fprintf(dfp,"brkRemove(%08x)\n",epc);type = flag = 0;for (i=0;i<MAX_BPT;i++) { /* first discard the entries we aren't going to handle */ if (brkList[i].type==0) continue; if (brkList[i].isset==0) continue; if (epc == brkList[i].addr) type = brkList[i].type; switch (brkList[i].method) { case BRK_METHOD_RAM : outw(brkList[i].addr,brkList[i].val); iflush_needed = dflush_needed = 1; flush_target(ICACHE); flush_target(DCACHE); break; case BRK_METHOD_ROM : if (!flag) { ccc = read_target(XT_CP0,C0_CCC,0); write_target(XT_CP0,C0_CCC,ccc&~CCC_ISR1); iflush_needed=1; flush_target(ICACHE); flag = 1; } break; case BRK_METHOD_HW : write_target(XT_CP0,DBX_DCS,0); break; } if (brkList[i].type == BPTYPE_ITMP) brkList[i].type = 0; if (brkList[i].type == BPTYPE_TRACE) brkList[i].type = 0; }return(type);}/************************************************************** static int hwibReq(addr)* verify that other hw ibpts don't conflict with this one.* i.e. More than one.*/static int hwibReq(addr)Ulong addr;{int i,n;n = 0;for (i=0;i<MAX_BPT;i++) { if (brkList[i].type==0) continue; if (brkList[i].method != BRK_METHOD_HW) continue; if (brkList[i].type == BPTYPE_DATA) continue; n++; } if (n > 0) return(0);return(1);}/************************************************************** static int hwdbReq(addr)* verify that other hw dbpts don't conflict with this one.* i.e. More than one.*/static int hwdbReq(addr)Ulong addr;{int i,n;n = 0;for (i=0;i<MAX_BPT;i++) { if (brkList[i].type==0) continue; if (brkList[i].method != BRK_METHOD_HW) continue; if (brkList[i].type != BPTYPE_DATA) continue; n++; } if (n > 0) return(0);return(1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -