/* cpu.c example cpu-description file */ /* (c) in 2013 by Volker Barthelmann */ #include "vasm.h" char *cpu_copyright="VideoCore IV cpu backend 0.1 (c) in 2013 Volker Barthelmann"; char *cpuname="vidcore"; mnemonic mnemonics[]={ #include "opcodes.h" }; int mnemonic_cnt=sizeof(mnemonics)/sizeof(mnemonics[0]); int bitsperbyte=8; int bytespertaddr=4; static char *ccs[]={"eq","ne","cs","cc","mi","pl","vs","vc", "hi","ls","ge","lt","gt","le","???","f"}; static char *vflags[]={"all","none","ifz","ifnz","ifn","ifnn","ifc","ifnc"}; static char *accs[]={ "???", "sub", "wba", "???", "clra", "???", "???", "???", "sign", "???", "???", "???", "???", "???", "???", "???", "high", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "uadd", "usub", "uacc", "udec", "???", "???", "???", "???", "sadd", "ssub", "sacc", "sdec", "???", "???", "???", "???", "uaddh", "usubh", "uacch", "udech", "???", "???", "???", "???", "saddh", "ssubh", "sacch", "sdech", "???", "???", "???", "???"}; static char *sru[]={ "sumu", "sums", "???", "imin", "???", "imax", "???", "max"}; static size_t oplen(int op) { if(op<=EN_MEMDISP16) return 2; else if(op<=EN_ARITHI32) return 4; else if(op<=EN_VARITHI48) return 6; else if(op<=EN_ADDCMPB64) return 8; else if(op<=EN_VARITHI80) return 10; ierror(0); } static char *skip_reg(char *s,int *reg) { int r=-1; char* orig=s; if(s[0]=='p'&&s[1]=='c'){ *reg=31; return s+2; } if(s[0]=='s'&&s[1]=='r'){ *reg=30; return s+2; } if(s[0]=='l'&&s[1]=='r'){ *reg=26; return s+2; } if(s[0]=='s'&&s[1]=='p'){ *reg=25; return s+2; } if(*s!='r'){ return s; } s++; if(*s<'0'||*s>'9'){ return orig; } r=*s++-'0'; if(*s>='0'&&*s<='9') r=10*r+*s++-'0'; if(isalnum(*s)||*s=='_'){ return orig; } *reg=r; return s; } int parse_operand(char *p,int len,operand *op,int req) { int r; char *s,*start=p; op->type=-1; p=skip(p); if(req>=OP_REG&&req<=OP_LR){ int reg; s=skip_reg(p,&r); if(s!=p){ if((req==OP_REG&&r<=31)|| (req==OP_SREG&&r<=15)|| (req==OP_PC&&r==31)|| (req==OP_LR&&r==26)|| (req==OP_MREG&&(r==0||r==6||r==16||r==24))){ op->type=OP_REG; op->reg=r; }else return 0; }else return 0; p=skip(s); }else if(req==OP_MREG){ int first; s=skip_reg(p,&r); if(s==p) return 0; if(r==0) op->dreg=0; else if(r==6) op->dreg=1; else if(r==16) op->dreg=2; else if(r==24) op->dreg=3; else return 0; s=skip(s); if(*s!='-') return 0; p=skip(s+1); first=r; s=skip_reg(p,&r); if(s==p) return 0; p=skip(s); op->reg=(r-first)&31; }else if(req==OP_IND){ p=skip(p); if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&r); if(s==p) return 0; if(r>15) return 0; p=skip(s); op->reg=r; if(*p!=')') return 0; p=skip(p+1); op->type=OP_IND; }else if(req==OP_VIND){ int nodisp=0; p=skip(p); if(*p=='('){ char *m; m=s=skip(p+1); s=skip_reg(s,&r); if((m!=s)||(*s=='0')) nodisp=1; } if(!nodisp){ op->offset=parse_expr(&p); if(!op->offset) return 0; }else op->offset=0; if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&r); if (s==p){ /* Special case: Allow '0' instead of a register */ if (*p=='0'){ p=skip(p+1); op->reg=15; } else return 0; }else{ if(r>14) return 0; p=skip(s); op->reg=r; } op->dreg=15; if(*p=='+'&&p[1]=='='){ p=skip(p+2); s=skip_reg(p,&r); if(s==p) return 0; if(r>14) return 0; p=skip(s); op->dreg=r; } if(*p!=')') return 0; p=skip(p+1); op->type=OP_IND; }else if(req==OP_PREDEC){ p=skip(p); if(p[0]!='-'||p[1]!='-') return 0; p=skip(p+2); if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&r); if(s==p) return 0; p=skip(s); if(*p!=')') return 0; p=skip(p+1); op->reg=r; op->type=OP_PREDEC; }else if(req==OP_POSTINC){ p=skip(p); if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&r); if(s==p) return 0; p=skip(s); if(*p!=')') return 0; p=skip(p+1); if(*p++!='+') return 0; if(*p!='+') return 0; p=skip(p+1); op->reg=r; op->type=OP_POSTINC; }else if(req==OP_REGIND){ p=skip(p); if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&op->reg); if(s==p) return 0; p=skip(s); if(*p!=',') return 0; p=skip(p+1); s=skip_reg(p,&op->dreg); if(s==p) return 0; p=skip(s); if(*p!=')') return 0; op->type=OP_REGIND; p=skip(p+1); }else if(req==OP_IMMIND|| req==OP_IMMINDSP|| req==OP_IMMINDSD|| req==OP_IMMINDR0|| req==OP_IMMINDS|| req==OP_IMMINDPC){ op->offset=0; if(*p=='('){ char *p2; p2=skip(p+1); s=skip_reg(p2,&r); if(s!=p2){ p=skip(s); if(*p==')'){ p=skip(p+1); op->offset=number_expr(0); } } } if(!op->offset){ op->offset=parse_expr(&p); if(!op->offset) return 0; p=skip(p); if(*p!='(') return 0; p=skip(p+1); s=skip_reg(p,&r); if(s==p) return 0; p=skip(s); if(*p!=')') return 0; } if(req==OP_IMMINDSP&&r!=25) return 0; if(req==OP_IMMINDPC&&r!=31) return 0; if(req==OP_IMMINDSD&&r!=24) return 0; if(req==OP_IMMINDR0&&r!=0) return 0; if(req==OP_IMMINDS&&r>15) return 0; op->reg=r; op->type=OP_IMMIND; p=skip(p+1); }else if(req>=OP_IMM4&&req<=OP_IMM32&&skip_reg(p,&r)==p){ op->type=OP_IMM32; op->offset=parse_expr(&p); simplify_expr(op->offset); p=skip(p); }else if((req==OP_ABS||req==OP_REL)&&skip_reg(p,&r)==p){ op->type=req; op->offset=parse_expr(&p); simplify_expr(op->offset); p=skip(p); }else if(req==OP_VREG||req==OP_VREGM||req==OP_VREGMM||req==OP_VREGA80){ s=skip_reg(p,&r); op->offset=0; if(s!=p){ if (*s=='+'||*s=='-'){ if(req==OP_VREG) return 0; op->offset=parse_expr(&s); } p=skip(s); op->type=OP_VREG; if(req==OP_VREG){ op->reg=(0xE<<6)|r; op->dreg=0x3c; }else{ op->reg=(0xE<<6); op->dreg=r<<2; } }else if(*p=='-'){ p=skip(p+1); op->type=OP_VREG; op->reg=(0xF<<6); op->dreg=0x3c; }else{ int size,vert,x,y,inc=15<<2; expr *e; if(*p=='H'||*p=='h') vert=0; // Disable vertical registers in 48-bit instructions for now else if((req!=OP_VREG)&&(*p=='V'||*p=='v')) vert=1; else return 0; p=skip(p+1); if(*p=='X'||*p=='x'){ size=2; p=skip(p+1); }else if(*p=='1'&&p[1]=='6'){ size=2; p=skip(p+2); }else if(*p=='Y'||*p=='y'){ size=4; p=skip(p+1); }else if(*p=='3'&&p[1]=='2'){ size=4; p=skip(p+2); }else if(*p=='8'){ size=1; p=skip(p+1); }else{ size=1; p=skip(p); } if(*p!='(') return 0; p=skip(p+1); e=parse_expr(&p); if(e->type!=NUM) return 0; y=e->c.val; p=skip(p); #if 1 if(req!=OP_VREG&&*p=='+'){ p++; if(*p!='+') return 0; if(vert) { cpu_error(4); return 0; } p=skip(p+1); inc|=2; } #endif if(*p!=',') return 0; p=skip(p+1); if((*p=='c')||(*p=='C')) { p++; if (*p!='b'&&*p!='B') return 0; p++; if (*p!='+') return 0; inc|=1; } e=parse_expr(&p); if(e->type!=NUM) return 0; x=e->c.val; p=skip(p); #if 1 if(req!=OP_VREG&&*p=='+'){ p++; if(*p!='+') return 0; if(!vert) { cpu_error(4); return 0; } p=skip(p+1); inc|=2; } #endif if(*p!=')') return 0; p=skip(p+1); if(req!=OP_VREG&&*p=='*'){ p=skip(p+1); inc|=1; } if(req!=OP_VREG&&*p=='+'){ p=skip(p+1); s=skip_reg(p,&r); if(s==p) return 0; p=skip(s); inc&=~0x3c; inc|=(r<<2); } if(req==OP_VREGA80){ if(size==1){ op->reg=(vert<<6)|((x&48)<<3); }else if(size==2){ if(x&16) return 0; op->reg=(vert<<6)|(8<<6)|((x&32)<<2); }else{ if(x&48) return 0; op->reg=(vert<<6)|(12<<6); } if(y<0||y>63) return 0; op->reg|=y&63; inc|=(x&15)<<6; }else{ if(vert){ if(size==1){ op->reg=(1<<6)|((x&48)<<3); }else if(size==2){ if(x&16) return 0; op->reg=(9<<6)|((x&32)<<2); }else{ if(x&48) return 0; op->reg=13<<6; } if(y<0||y>63||(y&15)) return 0; op->reg|=(y&48)|(x&15); } else{ if(size==1){ if(x&15) return 0; op->reg=(x&48)<<3; }else if(size==2){ if(x&31) return 0; op->reg=(8<<6)|((x&32)<<2); }else{ if(x) return 0; op->reg=12<<6; } if(y<0||y>63) return 0; op->reg|=y&63; } } op->dreg=inc; op->type=OP_VREG; } }else return 0; if(req==OP_VREGMM||req==OP_IMM32M||req==OP_VIND){ int vecmod=0,i; while(1){ if(!strncasecmp(p,"rep",3)&&isspace((unsigned char)p[3])){ expr *e; taddr x; p=skip(p+3); if((*p=='r')&&(p[1]=='0')&&!isdigit(p[2])){ p=skip(p+2); vecmod|=7<<16; i=0; }else{ e=parse_expr(&p); if(e->type!=NUM) return 0; x=e->c.val; for(i=0;i<8;i++){ if((1<=8) return 0; p=skip(p); continue; } for(i=0;i7)) return 0; vecmod|=(1<<6)|(i<<3)|r; continue; } } for (i=0;ivecmod=vecmod; } if(p>=start+len) return 1; else return 0; } static taddr dooffset(int rel,expr *tree,section *sec,taddr pc,rlist **relocs,int roffset,int size,taddr mask) { taddr val; if(!eval_expr(tree,&val,sec,pc)){ taddr addend=val; symbol *base; if(find_base(tree,&base,sec,pc)!=BASE_OK){ general_error(38); return val; } if(rel==REL_PC){ val-=pc; addend+=roffset/8; } if(rel!=REL_PC||!LOCREF(base)||base->sec!=sec){ add_nreloc_masked(relocs,base,addend,rel,size,roffset,mask); return 0; } } #if 0 if(val<-(1<<(size-1))||val>((1<<(size-1))-1)) cpu_error(1,size); #endif return val&mask; } static taddr reloffset(expr *tree,section *sec,taddr pc,rlist **relocs,int roffset,int size,taddr mask) { /* taddr mask=size==32?0xffffffff:((((taddr)1)<=(1<=(1<<(bits-1))) cpu_error(1,bits); } return val&((1<=(1<=(1<<(bits-1))) return 0; } return 1; } /* replace instruction by one with encoding enc */ static int replace(int c,int enc) { int i=c+1; while(!strcmp(mnemonics[c].name,mnemonics[i].name)){ if(mnemonics[i].ext.encoding==enc){ c=i; break; } i++; } if(c!=i) ierror(0); return c; } static int translate(instruction *p,section *sec,taddr pc) { int c=p->code,e=mnemonics[c].ext.encoding; taddr val; if(p->qualifiers[0]){ /* extend to larger variants if ccs are required */ if(e==EN_MEMDISP16) c=replace(c,EN_MEMDISP32); if(e==EN_ARITHR16) c=replace(c,EN_ARITHR32); if(e==EN_ARITHI16) c=replace(c,EN_ARITHI32); } if(e==EN_ARITHI32){ if(p->op[2]){ if(!chkval(p->op[2]->offset,sec,pc,6,1)&&(!strcmp("add",mnemonics[c].name)||!strcmp("sub",mnemonics[c].name))) c=replace(c,EN_ADD48); }else{ if((mnemonics[c].ext.code<32)&&(!chkval(p->op[1]->offset,sec,pc,6,1))) c=replace(c,EN_ARITHI48); } } if(e==EN_ARITHI16){ if(!chkval(p->op[1]->offset,sec,pc,5,0)) c=replace(c,EN_ARITHI48); } if(e==EN_RBRANCH16){ symbol *base; if(find_base(p->op[0]->offset,&base,sec,pc)!=BASE_OK||!LOCREF(base)||base->sec!=sec) c=replace(c,EN_RBRANCH32); else{ int i; i=eval_expr(p->op[0]->offset,&val,sec,pc); val-=pc; if(val>126||val<-128) c=replace(c,EN_RBRANCH32); } } if(e==EN_ADDCMPB32){ int i; i=eval_expr(p->op[3]->offset,&val,sec,pc); val-=pc; if(val>1022||val<-1024) c+=4; else if(p->op[2]->type!=OP_REG&&(val>254||val<-256)) c+=4; } if((e==EN_MEMDISP16||e==EN_MEMDISP32||e==EN_MEM12DISP32||e==EN_MEM16DISP32)){ if(!eval_expr(p->op[1]->offset,&val,sec,pc)){ c=replace(c,EN_MEM48); }else{ if(e==EN_MEMDISP16&&(val<0||val>54||(val&3))){ if(val<=4095&&val>=-4096) c=replace(c,EN_MEM12DISP32); else c=replace(c,EN_MEM48); } } } /* todo */ return c; } /* Convert an instruction into a DATA atom including relocations, if necessary. */ dblock *eval_instruction(instruction *p,section *sec,taddr pc) { dblock *db=new_dblock(); int c,sz,enc,cc,ww,m=0; unsigned long code,code2,code3; rlist *relocs=0; if(p->qualifiers[0]){ int i; for(i=0;i<15;i++){ if(!strcmp(p->qualifiers[0],ccs[i])){ cc=i; break; } } if(i>15) ierror(0); }else cc=14; c=translate(p,sec,pc); enc=mnemonics[c].ext.encoding; db->size=sz=oplen(enc); db->data=mymalloc(db->size); code=mnemonics[c].ext.code; switch(enc){ case EN_ARITHR16: if(cc!=14) cpu_error(3); code=0x40000000|(code<<24); code|=(p->op[0]->reg<<16)|(p->op[1]->reg<<20); break; case EN_ARITHI16: if(cc!=14) cpu_error(3); code=0x60000000|((code>>1)<<25); code|=(p->op[0]->reg<<16)|(absval(p->op[1]->offset,sec,pc,5,0)<<20); break; case EN_FIX16: if(cc!=14) cpu_error(3); break; case EN_IBRANCH16: if(cc!=14) cpu_error(3); code|=(p->op[0]->reg<<16); break; case EN_RBRANCH16: code=0x18000000; code|=cc<<23; code|=((reloffset(p->op[0]->offset,sec,pc,&relocs,0,7,0xfe)>>1)&127)<<16; break; case EN_MREG16: if(cc!=14) cpu_error(3); code|=(p->op[0]->dreg<<21)|(p->op[0]->reg<<16); break; case EN_RBRANCH32: if(code==0x90000000) code|=cc<<24; else code|=((reloffset(p->op[0]->offset,sec,pc,&relocs,8,4,0xF000000)>>24)&0xf)<<24; code|=((reloffset(p->op[0]->offset,sec,pc,&relocs,16,16,0x1fffe)>>1)&0x7fffff); code|=((reloffset(p->op[0]->offset,sec,pc,&relocs,0,7,0xfe0000)>>17)&0x7f)<<16; break; case EN_FUNARY32: code=0xC0000040|(code<<21); code|=p->op[0]->reg<<16; code|=p->op[1]->reg<<11; code|=cc<<7; break; case EN_ARITHR32: code=0xC0000000|(code<<21); code|=p->op[0]->reg<<16; if(p->op[2]){ code|=p->op[1]->reg<<11; code|=p->op[2]->reg; }else{ code|=p->op[0]->reg<<11; code|=p->op[1]->reg; } code|=cc<<7; break; case EN_ARITHI32: code=0xC0000040|(code<<21); code|=p->op[0]->reg<<16; if(p->op[2]){ code|=p->op[1]->reg<<11; code|=absval(p->op[2]->offset,sec,pc,6,1); }else{ code|=p->op[0]->reg<<11; code|=absval(p->op[1]->offset,sec,pc,6,1); } code|=cc<<7; break; case EN_ADDCMPB64: // Large offset: invert CC, place a long branch after // so we really generate the following: // addcmpb<~cc> d, a, b, skip // b // skip: // m=1; if(cc&1) cc--; else cc++; case EN_ADDCMPB32: code=0x80000000|(code<<14); code|=cc<<24; code|=p->op[0]->reg<<16; if(code&0x4000){ code|=absval(p->op[1]->offset,sec,pc,4,1)<<20; }else{ code|=p->op[1]->reg<<20; } if(code&0x8000){ code|=absval(p->op[2]->offset,sec,pc,6,0)<<8; if(m) code|=4; else code|=((reloffset(p->op[3]->offset,sec,pc,&relocs,16,9,0x1ff)>>1)&0xff); }else{ code|=p->op[2]->reg<<10; if(m) code|=4; else code|=((reloffset(p->op[3]->offset,sec,pc,&relocs,16,11,0x7ff)>>1)&0x3ff); } if(m){ code2=0x90000000|(14<<24); code2|=((reloffset(p->op[3]->offset,sec,pc+4,&relocs,48,16,0x1fffe)>>1)&0x7fffff); code2|=((reloffset(p->op[3]->offset,sec,pc+4,&relocs,32,7,0xfe0000)>>17)&0x7f)<<16; } break; case EN_ARITHI48: if(cc!=14) cpu_error(3); code=0xE8000000|(code<<21); code|=p->op[0]->reg<<16; code2=absoffset(p->op[1]->offset,sec,pc,&relocs,16,32); break; case EN_ADD48: if(cc!=14) cpu_error(3); if(p->op[2]) code2=absoffset(p->op[2]->offset,sec,pc,&relocs,16,32); else code2=absoffset(p->op[1]->offset,sec,pc,&relocs,16,32); /* pseudo sub */ if(code==6) code2=-code2; code=0xEC000000; code|=p->op[0]->reg<<16; if(p->op[2]) code|=p->op[1]->reg<<21; else code|=p->op[0]->reg<<21; break; case EN_MEMREG16: if(cc!=14) cpu_error(3); code=0x08000000|(code<<24); code|=p->op[0]->reg<<16; code|=p->op[1]->reg<<20; ww=0; /*FIXME*/ code|=ww<<25; break; case EN_MEMSTACK16: if(cc!=14) cpu_error(3); code=0x04000000|(code<<25); code|=p->op[0]->reg<<16; code|=(absval(p->op[1]->offset,sec,pc,7,1)>>2)<<20; break; case EN_MEMDISP16: if(cc!=14) cpu_error(3); code=0x20000000|(code<<28); code|=p->op[0]->reg<<16; code|=(absval(p->op[1]->offset,sec,pc,6,0)>>2)<<24; code|=p->op[1]->reg<<20; break; case EN_LEA16: if(cc!=14) cpu_error(3); code=0x10000000; code|=p->op[0]->reg<<16; code|=(absval(p->op[1]->offset,sec,pc,8,1)>>2)<<21; break; case EN_LEA48: if(cc!=14) cpu_error(3); code=0xE5000000|(p->op[0]->reg<<16); code2=reloffset(p->op[1]->offset,sec,pc,&relocs,16,32,0xffffffff); break; case EN_MEM48: if(cc!=14) cpu_error(3); code=0xE6000000|(code<<21); code|=p->op[0]->reg<<16; if(p->op[1]->reg==31) code2=reloffset(p->op[1]->offset,sec,pc,&relocs,16,27,0xffffffff)&0x7ffffff; else /* TODO: other relocs */ code2=absoffset(p->op[1]->offset,sec,pc,&relocs,16,27)&0x7ffffff; code2|=p->op[1]->reg<<27; break; case EN_MEMREG32: code=0xA0000000|(code<<21); code|=p->op[0]->reg<<16; code|=p->op[1]->reg<<11; code|=p->op[1]->dreg; code|=cc<<7; break; case EN_MEMDISP32: code=0xA0000040|(code<<21); code|=p->op[0]->reg<<16; code|=p->op[1]->reg<<11; code|=absval(p->op[1]->offset,sec,pc,5,1); code|=cc<<7; break; case EN_MEMPREDEC: case EN_MEMPOSTINC: code<<=21; if(p->op[1]->type==OP_POSTINC) code|=0xA5000000; else code|=0xA4000000; code|=p->op[0]->reg<<16; code|=p->op[1]->reg<<11; code|=cc<<7; break; case EN_MEM12DISP32: if(cc!=14) cpu_error(3); code=0xA2000000|(code<<21); code|=p->op[0]->reg<<16; code|=p->op[1]->reg<<11; code|=absval(p->op[1]->offset,sec,pc,12,1)&0x7ff; code|=(absval(p->op[1]->offset,sec,pc,12,1)&0x800)<<13; break; case EN_MEM16DISP32: if(cc!=14) cpu_error(3); code|=p->op[0]->reg<<16; if((code&0xff000000)==0xaa000000) code|=reloffset(p->op[1]->offset,sec,pc,&relocs,16,16,0xffff)&0xffff; else code|=absval(p->op[1]->offset,sec,pc,16,1); break; case EN_VLOAD48: code=0xF0000000|(code<<19); code2=(p->op[0]->reg<<22)|(7<<7)|p->op[1]->reg; break; case EN_VSTORE48: code=0xF0000000|(code<<19); code2=(p->op[0]->reg<<12)|(7<<7)|p->op[1]->reg; break; case EN_VREAD48: code=0xF0000000|(code<<19); code2=(p->op[0]->reg<<22)|p->op[1]->reg; break; case EN_VWRITE48: code=0xF0000000|(code<<19); code2=(p->op[0]->reg<<12)|p->op[1]->reg; break; case EN_VREADI48: code=0xF0000000|(code<<19); code2=(p->op[0]->reg<<22)|absval(p->op[1]->offset,sec,pc,6,0)|(1<<10); break; case EN_VWRITEI48: code=0xF0000000|(code<<19); code2=(p->op[0]->reg<<12)|absval(p->op[1]->offset,sec,pc,6,0)|(1<<10); break; case EN_VARITHR48: if(code<48) code|=64; code=0xF4000000|(code<<19); if(p->op[2]){ code2=(p->op[0]->reg<<22)|(p->op[1]->reg<<12)|p->op[2]->reg; }else{ code2=(p->op[0]->reg<<22)|p->op[1]->reg; } break; case EN_VARITHI48: if(code<48) code|=64; code=0xF4000000|(code<<19); if(p->op[2]){ code2=(p->op[0]->reg<<22)|(p->op[1]->reg<<12)|absval(p->op[2]->offset,sec,pc,6,0)|(1<<10); }else{ code2=(p->op[0]->reg<<22)|absval(p->op[1]->offset,sec,pc,6,0)|(1<<10); } break; // TODO: Check these! case EN_VLOAD80: code=0xF8000000|(code<<19)|(p->op[1]->vecmod&0x70000); code2=(p->op[0]->reg<<22); code3=(p->op[1]->reg<<2)|(p->op[0]->dreg<<26)|((p->op[1]->dreg)<<22); if(p->op[1]->offset){ code2|=(absval(p->op[1]->offset,sec,pc,16,1)&0x7f); code3|=(absval(p->op[1]->offset,sec,pc,16,1)>>7)&3; code3|=((absval(p->op[1]->offset,sec,pc,16,1)>>9)&0x7f)<<6; } break; case EN_VSTORE80: code=0xF8000000|(code<<19)|(p->op[1]->vecmod&0x70000); code2=(p->op[0]->reg<<12); code3=(p->op[1]->reg<<2)|(p->op[0]->dreg<<20)|((p->op[1]->dreg)<<28); if(p->op[1]->offset){ code2|=(absval(p->op[1]->offset,sec,pc,16,1)&0x7f); code3|=(absval(p->op[1]->offset,sec,pc,16,1)>>7)&3; code3|=((absval(p->op[1]->offset,sec,pc,16,1)>>9)&0x7f)<<6; } break; case EN_VREAD80: if(p->op[1]->offset){ p->op[1]->reg|=(absval(p->op[1]->offset,sec,pc,9,1)&0x7f); p->op[1]->dreg|=(absval(p->op[1]->offset,sec,pc,9,1)>>7)&3; } code=0xF8000000|(code<<19)|(p->op[1]->vecmod&0x70000); code2=(p->op[0]->reg<<22)|(p->op[1]->reg); if(p->op[1]->vecmod&(1<<20)) code2|=(1<<11); code3=(p->op[0]->dreg<<26)|(p->op[1]->dreg); code3|=(p->op[1]->vecmod&0x3fff)<<6; break; case EN_VWRITE80: if(p->op[1]->offset){ p->op[1]->reg|=(absval(p->op[1]->offset,sec,pc,9,1)&0x7f); p->op[1]->dreg|=(absval(p->op[1]->offset,sec,pc,9,1)>>7)&3; } code=0xF8000000|(code<<19)|(p->op[1]->vecmod&0x70000); code2=(p->op[0]->reg<<12)|(p->op[1]->reg); if(p->op[1]->vecmod&(1<<20)) code2|=(1<<11); code3=((p->op[0]->dreg&0x3f)<<20)|((p->op[0]->dreg&0x3c0)<<10)|(p->op[1]->dreg); code3|=(p->op[1]->vecmod&0x3fff)<<6; break; case EN_VREADI80: if(p->op[1]->offset){ p->op[1]->reg|=(absval(p->op[1]->offset,sec,pc,9,1)&0x7f); p->op[1]->dreg|=(absval(p->op[1]->offset,sec,pc,9,1)>>7)&3; } code=0xF8000000|(code<<19)|(p->op[1]->vecmod&0x70000); if(p->op[1]->vecmod&(1<<20)) code2|=(1<<11); code2=(p->op[0]->reg<<22)|(1<<10)|(absval(p->op[1]->offset,sec,pc,16,0)&0x3ff); code3=(p->op[0]->dreg<<26)|((absval(p->op[1]->offset,sec,pc,16,0)>>10)&0x3f); code3|=(p->op[1]->vecmod&0x3fff)<<6; break; case EN_VWRITEI80: if(p->op[1]->offset){ p->op[1]->reg|=(absval(p->op[1]->offset,sec,pc,9,1)&0x7f); p->op[1]->dreg|=(absval(p->op[1]->offset,sec,pc,9,1)>>7)&3; } code=0xF8000000|(code<<19)|(p->op[1]->vecmod&0x70000); if(p->op[1]->vecmod&(1<<20)) code2|=(1<<11); code2=(p->op[0]->reg<<12)|(1<<10)|(absval(p->op[1]->offset,sec,pc,16,0)&0x3ff); code3=((p->op[0]->dreg&0x3f)<<20)|((p->op[0]->dreg&0x3c0)<<10)|((absval(p->op[1]->offset,sec,pc,16,0)>>10)&0x3f); code3|=(p->op[1]->vecmod&0x3fff)<<6; break; case EN_VARITHR80: if(code<48) code|=64; if(p->op[2]){ if(p->op[2]->offset){ p->op[2]->reg|=(absval(p->op[2]->offset,sec,pc,9,1)&0x7f); p->op[2]->dreg|=(absval(p->op[2]->offset,sec,pc,9,1)>>7)&3; } code=0xFC000000|(code<<19)|(p->op[2]->vecmod&0x70000); code2=(p->op[0]->reg<<22)|(p->op[1]->reg<<12)|(p->op[2]->reg); if(p->op[2]->vecmod&(1<<20)) code2|=(1<<11); code3=(p->op[0]->dreg<<26)|((p->op[1]->dreg&0x3f)<<20)|((p->op[1]->dreg&0x3c0)<<10)|(p->op[2]->dreg); code3|=(p->op[2]->vecmod&0x3fff)<<6; }else{ if(p->op[1]->offset){ p->op[1]->reg|=(absval(p->op[1]->offset,sec,pc,9,1)&0x7f); p->op[1]->dreg|=(absval(p->op[1]->offset,sec,pc,9,1)>>7)&3; } code=0xFC000000|(code<<19)|(p->op[1]->vecmod&0x70000); code2=(p->op[0]->reg<<22)|(p->op[1]->reg); if(p->op[1]->vecmod&(1<<20)) code2|=(1<<11); code3=(p->op[0]->dreg<<26)|(p->op[1]->dreg); code3|=(p->op[1]->vecmod&0x3fff)<<6; } break; case EN_VARITHI80: if(code<48) code|=64; if(p->op[2]){ if(p->op[2]->offset){ p->op[2]->reg|=(absval(p->op[2]->offset,sec,pc,9,1)&0x7f); p->op[2]->dreg|=(absval(p->op[2]->offset,sec,pc,9,1)>>7); } code=0xFC000000|(code<<19)|(p->op[2]->vecmod&0x70000); if(p->op[2]->vecmod&(1<<20)) code2|=(1<<11); code2=(p->op[0]->reg<<22)|(p->op[1]->reg<<12)|(1<<10)|(absval(p->op[2]->offset,sec,pc,16,0)&0x3ff); code3=(p->op[0]->dreg<<26)|((p->op[1]->dreg&0x3f)<<20)|((p->op[1]->dreg&0x3c0)<<10)|((absval(p->op[2]->offset,sec,pc,16,0)>>10)&0x3f); code3|=(p->op[2]->vecmod&0x3fff)<<6; }else{ if(p->op[1]->offset){ p->op[1]->reg|=(absval(p->op[1]->offset,sec,pc,9,1)&0x7f); p->op[1]->dreg|=(absval(p->op[1]->offset,sec,pc,9,1)>>7); } code=0xFC000000|(code<<19)|(p->op[1]->vecmod&0x70000); if(p->op[1]->vecmod&(1<<20)) code2|=(1<<11); code2=(p->op[0]->reg<<22)|(1<<10)|(absval(p->op[1]->offset,sec,pc,16,0)&0x3ff); code3=(p->op[0]->dreg<<26)|((absval(p->op[1]->offset,sec,pc,16,0)>>10)&0x3f); code3|=(p->op[1]->vecmod&0x3fff)<<6; } break; default: ierror(0); } if(enc>=EN_VLOAD48&&enc<=EN_VARITHI48){ db->data[0]=(code>>16)&0xff; db->data[1]=(code>>24)&0xff; db->data[3]=(code2>>24)&0xff; db->data[2]=(code2>>16)&0xff; db->data[5]=(code2>>8)&0xff; db->data[4]=(code2>>0)&0xff; }else if(sz==2){ db->data[0]=(code>>16)&0xff; db->data[1]=(code>>24)&0xff; }else if(sz==4){ db->data[1]=(code>>24)&0xff; db->data[0]=(code>>16)&0xff; db->data[3]=(code>>8)&0xff; db->data[2]=(code)&0xff; }else if(sz==6){ db->data[0]=(code>>16)&0xff; db->data[1]=(code>>24)&0xff; db->data[5]=(code2>>24)&0xff; db->data[4]=(code2>>16)&0xff; db->data[3]=(code2>>8)&0xff; db->data[2]=(code2>>0)&0xff; } else if(sz==8){ db->data[1]=(code>>24)&0xff; db->data[0]=(code>>16)&0xff; db->data[3]=(code>>8)&0xff; db->data[2]=(code)&0xff; db->data[5]=(code2>>24)&0xff; db->data[4]=(code2>>16)&0xff; db->data[7]=(code2>>8)&0xff; db->data[6]=(code2)&0xff; }else if(sz==10){ db->data[0]=(code>>16)&0xff; db->data[1]=(code>>24)&0xff; db->data[3]=(code2>>24)&0xff; db->data[2]=(code2>>16)&0xff; db->data[5]=(code2>>8)&0xff; db->data[4]=(code2>>0)&0xff; db->data[7]=(code3>>24)&0xff; db->data[6]=(code3>>16)&0xff; db->data[9]=(code3>>8)&0xff; db->data[8]=(code3>>0)&0xff; } db->relocs=relocs; return db; } /* Create a dblock (with relocs, if necessary) for size bits of data. */ dblock *eval_data(operand *op,size_t bitsize,section *sec,taddr pc) { dblock *new=new_dblock(); taddr val; new->size=(bitsize+7)/8; new->data=mymalloc(new->size); if(op->type!=OP_ABS) ierror(0); if(bitsize!=8&&bitsize!=16&&bitsize!=32) cpu_error(2); val=absoffset(op->offset,sec,pc,&new->relocs,0,bitsize); if(bitsize==32){ new->data[3]=val>>24; new->data[2]=val>>16; new->data[1]=val>>8; new->data[0]=val; }else if(bitsize==16){ new->data[1]=val>>8; new->data[0]=val; }else new->data[0]=val; return new; } /* Calculate the size of the current instruction; must be identical to the data created by eval_instruction. */ size_t instruction_size(instruction *p,section *sec,taddr pc) { int c; c=translate(p,sec,pc); return oplen(mnemonics[c].ext.encoding); } operand *new_operand() { operand *new=mymalloc(sizeof(*new)); new->type=-1; return new; } /* return true, if initialization was successfull */ int init_cpu() { return 1; } /* return true, if the passed argument is understood */ int cpu_args(char *p) { return 0; } /* parse cpu-specific directives; return pointer to end of cpu-specific text */ char *parse_cpu_special(char *s) { char *name=s,*merk=s; return merk; } int set_default_qualifiers(char **q,int *q_len) /* fill in pointers to default qualifiers, return number of qualifiers */ { q[0]="u32"; q_len[0]=3; q[1]=""; q_len[1]=0; return 2; } char *parse_instruction(char *s,int *inst_len,char **ext,int *ext_len, int *ext_cnt) /* parse instruction and save extension locations */ { char *inst = s, l, i; int cnt = 0; while (*s && *s!='.' && !isspace((unsigned char)*s)) s++; l = s - inst; if(strncasecmp("divs",inst,l)&&strncmp("vreadacc",inst,l)&& strncasecmp("vcmpge",inst,l)){ for(i=0;i<16;i++){ int cl=strlen(ccs[i]); if(l>cl&&!strncasecmp(s-cl,ccs[i],cl)){ ext[0]=s-cl; ext_len[0]=cl; cnt=1; l-=cl; break; } } } *ext_cnt = cnt; *inst_len=l; return s; }