/************************************************************* * File: mon/go.c * Purpose: code for execution control * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 970216 Changed type name Cmd to CmdRec. * 970227 setTrigger: Added cleanup code on setbp error. * 970331 Used BPTYPE_ codes for setbp_target * 970822 Added clrhndlrs() to go. * 980802 Added count=0 to constReduc(). * 981023 cont() updated to support -w for imon95. */ #include #include #include #include #include #define PREGS /* enable pseudo regs */ char clientcmd[LINESZ]; extern int clkdat; int bptTmpId = -1; Bps Bpt[MAX_BPT]; /* user break points */ int bptCount; #define PCHISTSZ 200 unsigned long pchist_d[PCHISTSZ+1]; int pchist_ip,pchist_op; WhenRec *when_list,*when_ptr; char *oprs[] = {"&&","||","==","!=",">=","<=",">","<", "+","-","*","/","&","|",0}; Optdesc g_opts[] = { {"[-st] [adr [bptadr]] [-c args]","start execution (go)"}, {"-s","don't set client sp"}, {"-t","time execution"}, {"","start address"}, {"","temporary breakpoint"}, {"-c ","args to be passed to client"}, {0}}; Optdesc t_opts[] = { {"[-v] [cnt]","trace (single-step)"}, {"-v","verbose, list each step"}, {"","execute instructions"}, {0}}; Optdesc to_opts[] = { {"[-v] [cnt]","trace over (single-step)"}, {"-v","verbose, list each step"}, {"","execute instructions"}, {0}}; Optdesc b_opts[] = { {"[[-s cmdstr]brkadr]..","set breakpoint at address"}, {"-s ","execute command string when bpt is encountered"}, {"","stop when PC is "}, {"-d","display detailed break info"}, {"-T","TinyRISC address"}, {0}}; Optdesc w_opts[] = { {" ","complex breakpoint"}, {"","expression defining condition"}, {"","a command string defining the action"}, {0}}; Optdesc db_opts[] = { {"[numb|*]..","delete breakpoint"}, {0}}; /************************************************************* * go(ac,av,info), the 'g' command */ go(ac,av,info) int ac; char *av[]; CmdRec *info; { ADDR adr; int i,j,n,flags,tbpt; char *p,tmp[16]; U64 rv; n = flags = 0; bptTmpId = -1; strcpy(clientcmd,av[0]); strcat(clientcmd," "); if (!regChain) { printf("Target Description Driver not loaded\n"); return(1); } for (i=1;iname,info->opts); return(1); } } } else { if (n == 0) { n++; if(!get_rsa(&rv,av[i])) return(1); adr = rv.lo; if (adr != getPc()) putPc(adr); } else if (n == 1) { n++; if(!get_rsa(&rv,av[i])) return(1); adr = rv.lo; tbpt = setbp_target(-1,BPTYPE_ITMP,adr,0,0); if (tbpt < 0) { printf("error: unable to set bpt\n"); return(1); } tbpt &= 0xff; /* 970520 mask out warnings */ } else { if (tbpt != -1) clrbp_target(tbpt); printf("Too many arguments.\n"); printf("usage: %s %s\n",info->name,info->opts); return(1); } } } clrhndlrs(); /* 970822 */ swlst(2); /* switch to clilst */ run_target(0,flags,(int)clientcmd); } Optdesc c_opts[] = { {"[-w][bptadr]","continue execution"}, {"bptadr","a temporary breakpoint"}, {"-w","Don't wait (imon95 and imon only)"}, {0}}; /************************************************************* * cont(ac,av,info) * The continue command * 981023 Updated to support -w for imon95. */ cont(ac,av,info) int ac; char *av[]; CmdRec *info; { ADDR adr; char *p,tmp[16]; int i,n,tbpt,flags; U64 rv; if (!regChain) { printf("Target Description Driver not loaded\n"); return(1); } n = flags = 0; for (i=1;iname,info->opts); return(1); } } bptTmpId = -1; if (n == 1) { tbpt = setbp_target(-1,BPTYPE_ITMP,adr,0,0); if (tbpt < 0) { printf("error: unable to set bpt\n"); return(1); } tbpt &= 0xff; /* 970520 mask out warnings */ } swlst(2); /* switch to clilst */ run_target(1,flags,0); } /************************************************************* * setTrigger(char *cond,char *action) * This function sets up a trigger event. * It converts cond from a string to an RPN expression. * It does this by calling parseCond(). parseCond() is * called twice, once to set the when_ptr which indicates * the amount of storage required, and once to generate the actual * expression. The expression is placed in the array pointed * to be when_list. when_list and when_ptr are then saved in the * cond and csz members of a Bps structure. The string that * describes the condition is saved in the member cstr. * The action string (if specified) is placed in the member * cmdstr. The function setbp_target() is called in order to * set the actual breakpoint. Only this target dependent routine * 'knows' how this might best be achieved for a given set of * hardware. * 970227 Added cleanup code on setbp error. */ int setTrigger(char *cond,char *action) { char *p; int j,r; Ulong v; /* find an empty slot */ for(j=0;j < MAX_BPT && Bpt[j].cond;j++) ; if(j >= MAX_BPT) { printf("too many breakpoints\n"); return(-1); } when_list = when_ptr = 0; p = strdup(cond); parseCond(p); strcpy(p,cond); when_list = (WhenRec *)malloc((unsigned int)when_ptr); when_ptr = when_list; parseCond(p); free(p); constReduc(); Bpt[j].cond = when_list; Bpt[j].csz = when_ptr; Bpt[j].cstr = strdup(cond); if (action) Bpt[j].cmdstr = strdup(action); else Bpt[j].cmdstr = 0; bptCount++; if ((v=pcBpt(Bpt[j].cond,Bpt[j].csz)) != -1) { /* @pc CONST == bpc */ /* @pc CONST == ......... && bpc */ r = setbp_target(j,BPTYPE_PC,v,0,0); /* instr */ } else if ((v=singleDref(Bpt[j].cond,Bpt[j].csz)) != -1) { /* ADDR CONST OPR bda */ /* ADDR CONST OPR ........... && bda */ r = setbp_target(j,0x20|BPTYPE_DATA,v,0,0); /* data */ /* 0x20 is brk on write only */ } else { /* ...................... || nonrt */ r = setbp_target(j,BPTYPE_NONRT,0,0,0); /* nonrt execution */ } if (r >= 0) return(j); /* all ok */ /* 970227 error case */ Bpt[j].cond = 0; free(Bpt[j].cstr); if (Bpt[j].cmdstr) free(Bpt[j].cmdstr); if (when_list) free(when_list); return(-1); } #if 1 /************************************************************* */ setHwdbpt(int atype,ADDR addr,Ulong mask) { char *p,buf[100]; int j; char *cmd = "(@cause&0x3c)==0x1c"; /* look for a DBE exception */ /* find an empty slot */ for(j=0;j < MAX_BPT && Bpt[j].cond;j++) ; if(j >= MAX_BPT) { printf("too many breakpoints\n"); return(-1); } when_list = when_ptr = 0; p = strdup(cmd); parseCond(p); strcpy(p,cmd); when_list = (WhenRec *)malloc((unsigned int)when_ptr); when_ptr = when_list; parseCond(p); free(p); constReduc(); Bpt[j].cond = when_list; Bpt[j].csz = when_ptr; sprintf(buf,"ab -%s%s %08x %08x", (atype&1)?"r":"", (atype&2)?"w":"", addr,mask); Bpt[j].cstr = strdup(buf); Bpt[j].cmdstr = strdup("stop"); bptCount++; atype |= 8; /* indicate that addr2 is a mask value */ atype <<= 4; if (setbp_target(j,atype|BPTYPE_DATA,addr,mask,0) >= 0) { printf("Bpt%d has been set (%s)\n",j,Bpt[j].cstr); return(j); /* ok */ } /* 970227 error case */ printf("Unable to set Bpt%d\n",j); Bpt[j].cond = 0; free(Bpt[j].cstr); if (Bpt[j].cmdstr) free(Bpt[j].cmdstr); if (when_list) free(when_list); return(-1); } Optdesc ab_opts[] = { {"[-rw] addr1 [mask]","set access (data) bpt"}, {"addr1","start address"}, {"mask","address mask"}, {"-r","break on read operations only"}, {"-w","break on write operations only"}, {0}}; /************************************************************* */ int ab_cmd(int ac,char *av[]) { int got_addr1,got_mask,mode; ADDR addr1; Ulong mask; int i,j,rtn,n; char *cstr; U64 rv; got_addr1 = got_mask = mode = 0; for (i=1;iname,"PC") && cond[1].tag == WHEN_CONST && cond[2].tag == WHEN_OPR && cond[2].val == WHEN_OPR_EQ) { if (csz-cond == 3) return(cond[1].val); else if (csz[-1].tag == WHEN_OPR && csz[-1].val == WHEN_OPR_LAND) return(cond[1].val); } return(-1); } /************************************************************* * singleDref(cond,csz) * If this a singleDref breakpoint, return the bpt addr; else return -1. */ singleDref(cond,csz) WhenRec *cond,*csz; { if (cond[0].tag == WHEN_CONST && cond[1].tag == WHEN_MEM && cond[2].tag == WHEN_CONST && cond[3].tag == WHEN_OPR) { if (csz-cond == 4) return(cond[0].val); else if (csz[-1].tag == WHEN_OPR && csz[-1].val == WHEN_OPR_LAND) return(cond[0].val); } return(-1); } /************************************************************* * when(ac,av,info) * The 'when' (set trigger event) command. */ when(ac,av,info) int ac; char *av[]; CmdRec *info; { int j; char tmp[LINESZ]; if (!regChain) { printf("Target Description Driver not loaded\n"); return(1); } if (ac != 3) { printf("usage: %s %s\n",info->name,info->opts); return(1); } strnspc(av[1]); /* remove whitespace */ j = setTrigger(av[1],av[2]); if (j != -1) { sprintf(prnbuf,"Bpt %2d: when '%s' ",j,Bpt[j].cstr); if (Bpt[j].cmdstr) { sprintf(tmp," \"%s\"",Bpt[j].cmdstr); strcat(prnbuf,tmp); } printf("%s\n",prnbuf); } else printf("Unable to set specified breakpoint.\n"); } /************************************************************* * trace(ac,av) * The 't' and 'to' (single-step) commands */ trace(int ac,char *av[]) { int i,j,n,flags,count; U64 rv; if (!regChain) { printf("Target Description Driver not loaded\n"); return(1); } flags = 0; if (strequ(av[0],"to")) flags |= T_O; n = 0; count = 1; for (i=1;i= ac) { printf("bad arg count\n"); return(1); } str = av[i]; } else if (av[i][1] == 'T') Tflag = 1; else if (av[i][1] == 'd') { for (j=0;j 1){ for(i = j = 0; j < ac - 1; j++){ if (strequ(av[1+j],"*")) { clrbpt(-1); continue; } if (!atob(&i,av[1+j],10)) { printf("%s: decimal number expected\n",av[1+j]); continue; } clrbpt(i); } } else dspbpts(); return(0); } /************************************************************* * void clrbpt(i) * Clear specified breakpoint. If i==-1 clear all bpts. */ void clrbpt(i) int i; { if (i == -1) { for (i=0;i= a1 && adr <= a2) return(1); } return(0); } /************************************************************* * addpchist(adr) */ addpchist(adr) unsigned long adr; { pchist_d[pchist_ip] = adr; pchist_ip = incmod(pchist_ip,PCHISTSZ); if (pchist_ip == pchist_op) pchist_op = incmod(pchist_op,PCHISTSZ); } /************************************************************* * clrpchist() */ clrpchist() { pchist_ip = pchist_op = 0; } /************************************************************* * unsigned long getpchist(n) */ unsigned long getpchist(n) int n; { int i; i = pchist_ip-n-1; if (i < 0) i += PCHISTSZ+1; if (incmod(i,PCHISTSZ) == pchist_op) return(0); return(pchist_d[i]); } char *strrpstr(); /************************************************************* * constReduc() * optimize by performing constant reduction. * eg. change 80023450 00000018 + to 80023468 * It would be better to integrate this with parseCond(). */ constReduc() { WhenRec *p,*q; int count; Ulong v1,v2; count = 0; for (p=when_list;ptag) { case WHEN_CONST : count++; break; case WHEN_OPR : if (count < 2) { count = 0; /* 980802 */ break; } v1 = (p-2)->val; v2 = (p-1)->val; /* printf("opt: %08x %08x %s\n",v1,v2,oprs[p->val]); */ switch (p->val) { case WHEN_OPR_LAND : /* logical AND */ if (v1 && v2) (p-2)->val = ~0; else (p-2)->val = 0; break; case WHEN_OPR_LOR : if (v1 || v2) (p-2)->val = ~0; else (p-2)->val = 0; break; case WHEN_OPR_EQ : if (v1 == v2) (p-2)->val = ~0; else (p-2)->val = 0; break; case WHEN_OPR_NE : if (v1 != v2) (p-2)->val = ~0; else (p-2)->val = 0; break; case WHEN_OPR_GE : if (v1 >= v2) (p-2)->val = ~0; else (p-2)->val = 0; break; case WHEN_OPR_LE : if (v1 <= v2) (p-2)->val = ~0; else (p-2)->val = 0; break; case WHEN_OPR_GT : if (v1 > v2) (p-2)->val = ~0; else (p-2)->val = 0; break; case WHEN_OPR_LT : if (v1 < v2) (p-2)->val = 1; else (p-2)->val = 0; break; case WHEN_OPR_ADD : (p-2)->val = v1 + v2; break; case WHEN_OPR_SUB : (p-2)->val = v1 - v2; break; case WHEN_OPR_MUL : (p-2)->val = v1 * v2; break; case WHEN_OPR_DIV : (p-2)->val = v1 / v2; break; case WHEN_OPR_BAND : /* Bitwise AND */ (p-2)->val = (v1 & v2); break; case WHEN_OPR_BOR : (p-2)->val = (v1 | v2); break; default : count = 0; } if (count==2) { for (q=p+1;q >= < <= == !=. In addition it also permits * the '^' operator to dereference any address. */ int parseCond(char *p) { int r,inbase,inalpha,i; char *q,subexpr[LINESZ]; extern char *badhexsym; Ulong val; /* strip enclosing parens */ while (*p == '(' && strbalp(p) == p+strlen(p)-1) { strdchr(p); p[strlen(p)-1] = 0; } for (i=0;oprs[i];i++) { if (q=strrpstr(p,oprs[i])) { strNcpy(subexpr,p,q-p); r = parseCond(subexpr); if (r == 0) return(r); r = parseCond(q+strlen(oprs[i])); if (r == 0) return(r); if (when_list) { when_ptr->tag = WHEN_OPR; when_ptr->val = i; } when_ptr++; return(1); } } /* * having taken care of all the usual stuff, we handle the unary * operators and special cases. */ if (*p == '^') { r = parseCond(p+1); if (r == 0) return(r); if (when_list) { when_ptr->tag = WHEN_MEM; when_ptr->val = 0; } when_ptr++; return(1); } if (*p == '!') { r = parseCond(p+1); if (r == 0) return(r); if (when_list) { when_ptr->tag = WHEN_NOT; when_ptr->val = 0; } when_ptr++; return(1); } if (*p == '~') { r = parseCond(p+1); if (r == 0) return(r); if (when_list) { when_ptr->tag = WHEN_INV; when_ptr->val = 0; } when_ptr++; return(1); } if (*p == '@') { #ifdef PREGS if (ispreg(&p[1])) { val = (Ulong)(p[1]-'a'); if (when_list) { when_ptr->tag = WHEN_PREG; when_ptr->val = val; } when_ptr++; r = 1; } else { val = (Ulong)findRegRec(&p[1],0); if (val) { if (when_list) { when_ptr->tag = WHEN_REG; when_ptr->val = val; } when_ptr++; r = 1; } else printf("%s: reg not found\n",&p[1]); } #else val = (Ulong)findRegRec(&p[1],0); if (val) { if (when_list) { when_ptr->tag = WHEN_REG; when_ptr->val = val; } when_ptr++; r = 1; } else printf("%s: reg not found\n",&p[1]); #endif } else if (strequ(p,".")) { if (when_list) { when_ptr->tag = WHEN_REG; when_ptr->val = (Ulong)findRegRec("pc",0); } when_ptr++; r = 1; } else if (isdigit(*p)) { inbase = matchenv("inbase"); if (inbase == IB_TEN) r = atob((unsigned int *)&val,p,10); else if (inbase == IB_SIXTEEN) r = atob((unsigned int *)&val,p,16); else if (inbase == IB_EIGHT) r = atob((unsigned int *)&val,p,8); else if (inbase == IB_AUTO) r = atob((unsigned int *)&val,p,0); else { printf("%s: bad inbase value\n",getMonEnv("inbase")); return(0); } if (r == 0) { r = atob((unsigned int *)&val,p,0); if (r == 0) printf("%s: bad base %s value\n", p,getMonEnv("inbase")); } if (r) { if (when_list) { when_ptr->tag = WHEN_CONST; when_ptr->val = val; } when_ptr++; } } else if (isxdigit(*p)) { r = sym2adr(&val,p); if (r == 0) { r = atob((unsigned int *)&val,p,16); if (r == 0) printf(badhexsym,p); } if (r) { if (when_list) { when_ptr->tag = WHEN_CONST; when_ptr->val = val; } when_ptr++; } } else { r = sym2adr(&val,p); if (r == 0) { if (*p == '(') printf("unbalanced parens\n"); else printf("%s: bad symbol name\n",p); } if (r) { if (when_list) { when_ptr->tag = WHEN_CONST; when_ptr->val = val; } when_ptr++; } } return(r); } Ulong when_evalstk[8]; Ulong *when_evalptr; /************************************************************* * evalBpt(p,e) */ evalBpt(s,e) WhenRec *s,*e; { WhenRec *p; Ulong *t,v; when_evalptr = when_evalstk; for (p=s;ptag) { case WHEN_CONST : *when_evalptr++ = p->val; break; case WHEN_MEM : v1 = *--when_evalptr; *when_evalptr++ = read_target32(v1); break; case WHEN_REG : *when_evalptr++ = getU6432((RegRec *)p->val); break; #ifdef PREGS case WHEN_PREG : *when_evalptr++ = getPreg(p->val); break; #endif case WHEN_NOT : v1 = *--when_evalptr; if (v1) *when_evalptr++ = 0; else *when_evalptr = 1; break; case WHEN_INV : v1 = *--when_evalptr; *when_evalptr++ = ~v1; break; case WHEN_OPR : switch (p->val) { case WHEN_OPR_LAND : v1 = *--when_evalptr; v2 = *--when_evalptr; if (v1 && v2) *when_evalptr++ = ~0; else *when_evalptr++ = 0; break; case WHEN_OPR_LOR : v1 = *--when_evalptr; v2 = *--when_evalptr; if (v1 || v2) *when_evalptr++ = ~0; else *when_evalptr++ = 0; break; case WHEN_OPR_EQ : v1 = *--when_evalptr; v2 = *--when_evalptr; if (v1 == v2) *when_evalptr++ = ~0; else *when_evalptr++ = 0; break; case WHEN_OPR_NE : v1 = *--when_evalptr; v2 = *--when_evalptr; if (v1 != v2) *when_evalptr++ = ~0; else *when_evalptr++ = 0; break; case WHEN_OPR_GE : v2 = *--when_evalptr; v1 = *--when_evalptr; if (v1 >= v2) *when_evalptr++ = ~0; else *when_evalptr++ = 0; break; case WHEN_OPR_LE : v2 = *--when_evalptr; v1 = *--when_evalptr; if (v1 <= v2) *when_evalptr++ = ~0; else *when_evalptr++ = 0; break; case WHEN_OPR_GT : v2 = *--when_evalptr; v1 = *--when_evalptr; if (v1 > v2) *when_evalptr++ = ~0; else *when_evalptr++ = 0; break; case WHEN_OPR_LT : v2 = *--when_evalptr; v1 = *--when_evalptr; if (v1 < v2) *when_evalptr++ = 1; else *when_evalptr++ = 0; break; case WHEN_OPR_ADD : v1 = *--when_evalptr; v2 = *--when_evalptr; *when_evalptr++ = v1 + v2; break; case WHEN_OPR_SUB : v2 = *--when_evalptr; v1 = *--when_evalptr; *when_evalptr++ = v1 - v2; break; case WHEN_OPR_MUL : v1 = *--when_evalptr; v2 = *--when_evalptr; *when_evalptr++ = v1 * v2; break; case WHEN_OPR_DIV : v2 = *--when_evalptr; v1 = *--when_evalptr; *when_evalptr++ = v1 / v2; break; case WHEN_OPR_BAND : v1 = *--when_evalptr; v2 = *--when_evalptr; *when_evalptr++ = (v1 & v2); break; case WHEN_OPR_BOR : v1 = *--when_evalptr; v2 = *--when_evalptr; *when_evalptr++ = (v1 | v2); break; default : printf("%d: bad opr\n",p->val); } break; default : printf("%d: bad tag\n",p->tag); } } /************************************************************* * printOps(cond,csz) */ printOps(cond,csz) WhenRec *cond,*csz; { WhenRec *p; for (p=cond;ptag) { case WHEN_OPR : printf("opr %s\n",oprs[p->val]); break; case WHEN_CONST : printf("const %08x\n",p->val); break; case WHEN_MEM : printf("memref\n"); break; #ifdef PREGS case WHEN_PREG : printf("preg %c\n",p->val+'a'); break; #endif case WHEN_REG : printf("reg %s\n",((RegRec *)p->val)->name); break; case WHEN_NOT : printf("NOT\n"); break; case WHEN_INV : printf("INV\n"); break; default : printf("bad tag: %08x %s\n",p->val,p->tag); } } }