/************************************************************* * File: mon/regs.c * Purpose: Part of core Monitor * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 970304 Start of revision history * 971002 Added "modified" for Crossview * 980918 Made some 64-bit changes */ #include #include #include #include #define BADREG "error: arg2 [%s] bad register name\n" #define BADFIELD "error: arg3: [%s] bad field name\n" #define BADBASE "error: arg%d: [%s] base %d value expected\n" #define BADVALUE "error: arg%d: [%s] max value %d expected\n" #define BADSVALUE "error: arg4: [%s] bad symbolic value\n" #define REG_RO "Register is readonly\n" Optdesc r_opts[] = { {"[reg* [val|field val]]","display/set register"}, {"*","display all registers"}, {"t*","display all registers starting with t"}, {"reg value","set specified register"}, {"reg field value","set specified field"}, {"f*","display all fp registers"}, {0}}; RegRec gpreglist[] = { {mXgpr,0,"zero","0",0,(F_ALL|F_ANAME|F_GPR|F_RO|F_MIPS)}, {mXgpr,0,"at","1",1,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"v0","2",2,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"v1","3",3,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"a0","4",4,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"a1","5",5,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"a2","6",6,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"a3","7",7,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"t0","8",8,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"t1","9",9,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"t2","10",10,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"t3","11",11,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"t4","12",12,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"t5","13",13,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"t6","14",14,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"t7","15",15,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"s0","16",16,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"s1","17",17,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"s2","18",18,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"s3","19",19,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"s4","20",20,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"s5","21",21,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"s6","22",22,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"s7","23",23,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"t8","24",24,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"t9","25",25,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"k0","26",26,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"k1","27",27,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"gp","28",28,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"sp","29",29,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"s8","30",30,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {mXgpr,0,"ra","31",31,(F_ALL|F_ANAME|F_GPR|F_MIPS)}, {0}}; char *rmvalues[] = {"RN","RZ","RP","RM",0}; RegSpec cp1_csr[] = { {1,23,"C",2,0,0}, {1,17,"EE",2,0,0}, {1,16,"EV",2,0,0}, {1,15,"EZ",2,0,0}, {1,14,"EO",2,0,0}, {1,13,"EU",2,0,0}, {1,12,"EI",2,0,0}, {1,11,"TV",2,0,0}, {1,10,"TZ",2,0,0}, {1, 9,"TO",2,0,0}, {1, 8,"TU",2,0,0}, {1, 7,"TI",2,0,0}, {1, 6,"SV",2,0,0}, {1, 5,"SZ",2,0,0}, {1, 4,"SO",2,0,0}, {1, 3,"SU",2,0,0}, {1, 2,"SI",2,0,0}, {1, 0,"RM",0,rmvalues,0}, {0}}; RegRec fpreglist[] = { {mXc1,0,"$f0","f0",0,(F_ANAME|F_FPR)}, {mXc1,0,"$f1","f1",1,(F_ANAME|F_FPR)}, {mXc1,0,"$f2","f2",2,(F_ANAME|F_FPR)}, {mXc1,0,"$f3","f3",3,(F_ANAME|F_FPR)}, {mXc1,0,"$f4","f4",4,(F_ANAME|F_FPR)}, {mXc1,0,"$f5","f5",5,(F_ANAME|F_FPR)}, {mXc1,0,"$f6","f6",6,(F_ANAME|F_FPR)}, {mXc1,0,"$f7","f7",7,(F_ANAME|F_FPR)}, {mXc1,0,"$f8","f8",8,(F_ANAME|F_FPR)}, {mXc1,0,"$f9","f9",9,(F_ANAME|F_FPR)}, {mXc1,0,"$f10","f10",10,(F_ANAME|F_FPR)}, {mXc1,0,"$f11","f11",11,(F_ANAME|F_FPR)}, {mXc1,0,"$f12","f12",12,(F_ANAME|F_FPR)}, {mXc1,0,"$f13","f13",13,(F_ANAME|F_FPR)}, {mXc1,0,"$f14","f14",14,(F_ANAME|F_FPR)}, {mXc1,0,"$f15","f15",15,(F_ANAME|F_FPR)}, {mXc1,0,"$f16","f16",16,(F_ANAME|F_FPR)}, {mXc1,0,"$f17","f17",17,(F_ANAME|F_FPR)}, {mXc1,0,"$f18","f18",18,(F_ANAME|F_FPR)}, {mXc1,0,"$f19","f19",19,(F_ANAME|F_FPR)}, {mXc1,0,"$f20","f20",20,(F_ANAME|F_FPR)}, {mXc1,0,"$f21","f21",21,(F_ANAME|F_FPR)}, {mXc1,0,"$f22","f22",22,(F_ANAME|F_FPR)}, {mXc1,0,"$f23","f23",23,(F_ANAME|F_FPR)}, {mXc1,0,"$f24","f24",24,(F_ANAME|F_FPR)}, {mXc1,0,"$f25","f25",25,(F_ANAME|F_FPR)}, {mXc1,0,"$f26","f26",26,(F_ANAME|F_FPR)}, {mXc1,0,"$f27","f27",27,(F_ANAME|F_FPR)}, {mXc1,0,"$f28","f28",28,(F_ANAME|F_FPR)}, {mXc1,0,"$f29","f29",29,(F_ANAME|F_FPR)}, {mXc1,0,"$f30","f30",30,(F_ANAME|F_FPR)}, {mXc1,0,"$f31","f31",31,(F_ANAME|F_FPR)}, {cXc1,0,"C1_FRID","FRID",0,F_RO}, {cXc1,cp1_csr,"C1_CSR","CSR",31,0}, {0}}; /* a linked list of register description structs */ RegRec *regChain; /* storage for pseudo registers */ Ulong pregs[26]; char preg_valid[26]; /************************************************************* * int registers(int ac,char *av[]) DEF * the 'r' (display registers) command */ int registers(int ac,char *av[]) { int i,j,len,lmargin[2],flag,wild,l,siz; unsigned int n; U64 w,rv; RegSpec *q; RegRec *p; char buf[80],tmp1[20],tmp2[20]; Ulong *pr,val; if (!regChain) { printf("Target Description Driver not loaded\n"); return(1); } if (ac > 1 && (!strncmp(av[1],"f$",2) || !strncmp(av[1],"F$",2) || !strncmp(av[1],"f*",2) || !strncmp(av[1],"F*",2))) { disp_Fprs(ac,av); return(0); } prnbuf[0] = 0; if (!atob(&siz,getMonEnv("moresz"),10)) { printf("%s: bad moresz value\n",getMonEnv("moresz")); return(1); } l = siz; ioctl_cbreak(0L); lmargin[0] = lmargin[1] = 0; for (p=0;p=findRegRec("*",p);) { len = strlen(p->name); if (p->spec) { if (len > lmargin[1]) lmargin[1] = len; } else { if (len > lmargin[0]) lmargin[0] = len; } } switch (ac) { case 1 : /* displ GP registers */ disp_Gprs(1); break; case 2 : /* displ selected register(s) */ if (strequ(av[1],"*")) { /* all regs */ disp_Gprs(0); l -= 4; for (p=0;p=findRegRec("*",p);) { if (p->flags&F_GPR) continue; if (dispReg(p,lmargin,&l,siz)) break; } for (j= -1;;) { if ((j=nxtPreg(j+1))== -1) break; sprintf(prnbuf,"%c = %08x",j+'a',getPreg(j)); more(prnbuf,&l,siz); } if (strlen(prnbuf)) more(prnbuf,&l,siz); } else if (strequ(av[1],"?")) { /* all pregs */ for (j= -1;;) { if ((j=nxtPreg(j+1))== -1) break; sprintf(prnbuf,"%c = %08x",j+'a',getPreg(j)); more(prnbuf,&l,siz); } } else { /* display reg(s) by name */ if (ispreg(av[1])) { printf("%c = %08x\n",av[1][0], getPreg(av[1][0]-'a')); break; } flag = 0; for (p=0;p=findRegRec(av[1],p);) { if (dispReg(p,lmargin,&l, siz)) break; flag = 1; } if (strlen(prnbuf)) more(prnbuf,&l,siz); if (flag == 0) printf(BADREG,av[1]); } break; case 3 : /* set entire register */ if (!get_rsa(&rv,av[2])) break; if (ispreg(av[1])) { putPreg(av[1][0]-'a',rv.lo); break; } flag = 0; for (p=0;p=findRegRec(av[1],p);) { if (p->flags&F_RO) printf(REG_RO); else { (* p->func)(1,p->regnum,p->size,rv); p->modified = 1; /* 971002 */ } flag = 1; } if (flag == 0) printf(BADREG,av[1]); break; case 4 : /* set register field */ p = findRegRec(av[1],0); if (p == 0) { printf(BADREG,av[1]); break; } /* found the reg, now find the field */ q = p->spec; if (!q) { printf(BADFIELD,av[2]); break; } for (i=0;q[i].name;i++) { if (striequ(av[2],q[i].name)) break; } if (q[i].name == 0) { printf(BADFIELD,av[2]); break; } /* found the field, now find the value */ if (q[i].ro) { printf(REG_RO); break; } /* first check to see if should be symbolic */ if (q[i].base == 0) { /* symbolic */ for (n=0;q[i].values[n];n++) { if (striequ(av[3],q[i].values[n])) break; } if (q[i].values[n] == 0) { printf(BADSVALUE,av[3]); break; } } else { /* numeric */ if (!atobRV(&rv,av[3],q[i].base)) { printf(BADBASE,4,av[3],q[i].base); break; } if (rv.lo >= (1<func)(0,p->regnum,p->size); setfield(&w.lo,q[i].size,q[i].lsb,rv.lo); (* p->func)(1,p->regnum,p->size,w); break; } return(0); } /************************************************************* * int dispReg(RegRec *rr,int *lmargin,int *ln,int siz) DEF */ int dispReg(RegRec *rr,int *lmargin,int *ln,int siz) { char tmp[80],*fmt; int state,flag; U64 value; if (rr->flags&F_WO) { if (lmargin[0]+strlen(prnbuf)+10 > 79) if (more(prnbuf,ln,siz)) return(1); sprintf(tmp,"%*s=WRTEONLY ",lmargin[0],rr->name); strcat(prnbuf,tmp); return(0); } value = (* rr->func)(0,rr->regnum,rr->size); if (rr->spec) { if (strlen(prnbuf)) if (more(prnbuf,ln,siz)) return(1); state = 0; while (disp_reg(prnbuf,rr,lmargin[1],value,state++)) { if (more(prnbuf,ln,siz)) return(1); } } else if (rr->flags&F_GPR) { if (lmargin[0]+strlen(prnbuf)+10 > 79) if (more(prnbuf,ln,siz)) return(1); sprintf(tmp,"%*s=%s=%s ",lmargin[0]-3,rr->aname, rr->name,rvtostr(value)); strcat(prnbuf,tmp); } else { if (lmargin[0]+strlen(prnbuf)+10 > 79) if (more(prnbuf,ln,siz)) return(1); flag = 0; switch (rr->size) { case 8 : fmt = "%*s=%02x "; break; case 16 : fmt = "%*s=%04x "; break; case 32 : fmt = "%*s=%08x "; break; case 64 : default : fmt = "%*s=%s "; flag=1; } if (flag) sprintf(tmp,fmt,lmargin[0], rr->name,rvtostr(value)); else sprintf(tmp,fmt,lmargin[0], rr->name,value.lo); strcat(prnbuf,tmp); } return(0); } /************************************************************* * int disp_reg(char *pb,RegRec *q,int lmargin,U64 value,int state) DEF */ int disp_reg(char *pb,RegRec *q,int lmargin,U64 value,int state) { int i,val,len,width,col,n; char buf[80],tmp[80]; RegSpec *p; static int posn; if (lmargin == 0) lmargin = strlen(q->name); if (q->spec == 0) { printf("disp_reg: spec==0\n"); return(1); } if (state == 0) posn = 0; p = q->spec; if (p[posn].size == 0) return(0); *pb = 0; if ((state&1) == 0) { /* print field names */ sprintf(pb,"%*s: ",lmargin,q->name); col = lmargin+2; for (i=posn;p[i].size != 0;i++) { if (p[i].name == 0) continue; width = fieldsz(&p[i]); if (col+width+1 > 76) break; sprintf(buf,"%~*s ",width,p[i].name); strcat(pb,buf); col += width+1; } } else { /* print field values */ for (n=lmargin+2;n>0;n--) strcat(pb," "); /* +2 for ": " */ col = lmargin+2; for (i=posn;p[i].size != 0;i++) { if (p[i].name) len = strlen(p[i].name); else len = 0; width = fieldsz(&p[i]); if (col+width+1 > 76) break; val = getfield(value.lo,p[i].size,p[i].lsb); if (p[i].base == 0) strcpy(buf,p[i].values[val]); else { btoa(buf,val,p[i].base); if (p[i].base != 10) str_fmt(buf,p[i].size,FMT_RJUST0); } sprintf(tmp,"%~*s ",width,buf); strcat(pb,tmp); col += width+1; } posn = i; } return(1); } /************************************************************* * int fieldsz(RegSpec *p) DEF */ int fieldsz(RegSpec *p) { int width,nmsz,valsz,len; char **q; nmsz = strlen(p->name); switch (p->base) { case 0 : valsz = 0; for (q=p->values;*q;q++) { len = strlen(*q); if (len > valsz) valsz = len; } break; case 2 : valsz = p->size; break; case 10 : if (p->size > 3) valsz = 2; else valsz = 1; break; case 16 : valsz = 1; break; } if (nmsz > valsz) width = nmsz; else width = valsz; return(width); } /************************************************************* * void setfield(Ulong *dstp,int size,int lsb,int value) DEF */ void setfield(Ulong *dstp,int size,int lsb,int value) { Ulong msk,v; msk = ((1<name,name) || striequ(p->aname,name)) { if (p->spec) { state = 0; while (disp_reg(prnbuf,p,0,rv,state++)) printf("%s\n",prnbuf); } else { if (p->flags&F_ANAME) printf("$%s-%s-%08x\n",p->aname, p->name,value); else printf("%s: %08x\n",p->name,value); } return(1); } } return(0); } /************************************************************* * int getreg(U64 *vp,char *name) DEF * get value from named register * return 0 if register not found. */ int getreg(U64 *vp,char *name) { RegRec *p; p = findRegRec(name,0); if (!p) return(0); *vp = getU64(p); return(1); } /************************************************************* * U64 getU64(RegRec *p) DEF * get register value using a RegRec ptr */ U64 getU64(RegRec *p) { return (* p->func)(0,p->regnum,p->size); } /************************************************************* * int putU64(RegRec *p,U64 v) DEF * put register value using a RegRec ptr */ int putU64(RegRec *p,U64 v) { if (!p->func) return(0); (* p->func)(1,p->regnum,p->size,v); return(1); } /************************************************************* * char *getexcname(int n) DEF */ char *getexcname(int n) { return(excodes[n>>2]); } /************************************************************* * Ulong getPreg(int reg) DEF * return the contents of a specified pseudo register */ Ulong getPreg(int reg) { if (!preg_valid[reg]) { preg_valid[reg] = 1; pregs[reg] = 0; } return(pregs[reg]); } /************************************************************* * void putPreg(int reg,Ulong v) DEF * write to a specified pseudo register */ void putPreg(int reg,Ulong v) { preg_valid[reg] = 1; pregs[reg] = v; } /************************************************************* * int nxtPreg(int reg) DEF * get the number of the next valid pseudo register */ int nxtPreg(int reg) { for (;reg < 26;reg++) { if (preg_valid[reg]) return(reg); } return(-1); } /************************************************************* * int ispreg(char *name) DEF * return 1 if name is a pseudo register */ int ispreg(char *name) { if (strlen(name) != 1) return(0); if (name[0] >= 'a' && name[0] <= 'z') return(1); return(0); } /************************************************************* * void addRegRec(RegRec *p) DEF * add a RegRec to the regChain */ void addRegRec(RegRec *p) { RegRec *q; p->next = 0; if (!regChain) { /* empty */ regChain = p; } else { for (q=regChain;q->next;q=q->next) ; /* find end of chain */ q->next = p; } } /************************************************************* * void addFpRegs(void) DEF */ void addFpRegs(void) { int i; for (i=0;fpreglist[i].func;i++) addRegRec(&fpreglist[i]); } /************************************************************* * void addGpRegs(void) DEF */ void addGpRegs(void) { int i; for (i=0;gpreglist[i].func;i++) addRegRec(&gpreglist[i]); } /************************************************************* * RegRec *findRegRec(char *name,RegRec *rec) DEF * Searches the regChain and returns the address of the * struct that describes the first register whose name matches. * * name = ptr to the register name (may contain wildcards) * rec = ptr to last record matched. Or zero. * returns: ptr to RegRec matching, or zero if not found. * * usage: * p = findRegRec(name,0); * or: * for (p=0;p=findRegRec(name,p);) { * printf("match %s\n",p->name); * } */ RegRec *findRegRec(char *name,RegRec *rec) { int wild; RegRec *p; char tmp[40]; if (strchr(name,'*') || strchr(name,'?')) wild = 1; else wild = 0; strtoupper(name); for (p=(rec)?rec->next:regChain;p;p=p->next) { #if 0 /* I was having probs w 'p' getting trashed (it seems) */ if (!p || ((Ulong)p) < 0x80000000 || ((Ulong)p)&3) { printf("findRegRec: p=%08x\n",p); break; } #endif if (wild) { strcpy(tmp,p->name); strtoupper(tmp); if (strpat(tmp,name)) return(p); } else { if (striequ(name,p->name)) return(p); if (striequ(name,p->aname)) return(p); } } return(0); }