787 lines
20 KiB
C
787 lines
20 KiB
C
|
/* cpu.c example cpu-description file */
|
||
|
/* (c) in 2002 by Volker Barthelmann */
|
||
|
|
||
|
#include "vasm.h"
|
||
|
|
||
|
char *cpu_copyright="vasm c16x/st10 cpu backend 0.2c (c) in 2002-2005 Volker Barthelmann";
|
||
|
char *cpuname="c16x";
|
||
|
|
||
|
mnemonic mnemonics[]={
|
||
|
#include "opcodes.h"
|
||
|
};
|
||
|
|
||
|
int mnemonic_cnt=sizeof(mnemonics)/sizeof(mnemonics[0]);
|
||
|
|
||
|
int bitsperbyte=8;
|
||
|
int bytespertaddr=4;
|
||
|
|
||
|
static int JMPA,JMPR,JMPS,JNB,JB,JBC,JNBS,JMP;
|
||
|
static int notrans,tojmpa;
|
||
|
|
||
|
#define JMPCONV 256
|
||
|
#define INVCC(c) (((c)&1)?(c)-1:(c)+1)
|
||
|
|
||
|
#define ISBIT 1
|
||
|
|
||
|
typedef struct sfr {
|
||
|
struct sfr *next;
|
||
|
int flags;
|
||
|
unsigned int laddr,saddr,boffset;
|
||
|
} sfr;
|
||
|
|
||
|
|
||
|
sfr *first_sfr;
|
||
|
#define SFRHTSIZE 1024
|
||
|
hashtable *sfrhash;
|
||
|
|
||
|
static char *skip_reg(char *s,int *reg)
|
||
|
{
|
||
|
int r=-1;
|
||
|
if(*s!='r'&&*s!='R'){
|
||
|
cpu_error(1);
|
||
|
return s;
|
||
|
}
|
||
|
s++;
|
||
|
if(*s<'0'||*s>'9'){
|
||
|
cpu_error(1);
|
||
|
return s;
|
||
|
}
|
||
|
r=*s++-'0';
|
||
|
if(*s>='0'&&*s<='5')
|
||
|
r=10*r+*s++-'0';
|
||
|
*reg=r;
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
int parse_operand(char *p,int len,operand *op,int requires)
|
||
|
{
|
||
|
op->type=-1;
|
||
|
op->mod=-1;
|
||
|
p=skip(p);
|
||
|
if(requires==OP_REL){
|
||
|
char *s=p;
|
||
|
op->type=OP_REL;
|
||
|
op->offset=parse_expr(&s);
|
||
|
simplify_expr(op->offset);
|
||
|
if(s==p)
|
||
|
return 0;
|
||
|
else
|
||
|
return 1;
|
||
|
}
|
||
|
if(requires==OP_CC){
|
||
|
op->type=OP_CC;
|
||
|
if(len<4||len>6||p[0]!='c'||p[1]!='c'||p[2]!='_')
|
||
|
return 0;
|
||
|
if(len==4){
|
||
|
if(p[3]=='z')
|
||
|
op->cc=2;
|
||
|
else if(p[3]=='v')
|
||
|
op->cc=4;
|
||
|
else if(p[3]=='n')
|
||
|
op->cc=6;
|
||
|
else if(p[3]=='c')
|
||
|
op->cc=8;
|
||
|
else
|
||
|
return 0;
|
||
|
}else if(len==5){
|
||
|
if(p[3]=='u'&&p[4]=='c')
|
||
|
op->cc=0;
|
||
|
else if(p[3]=='n'&&p[4]=='z')
|
||
|
op->cc=3;
|
||
|
else if(p[3]=='n'&&p[4]=='v')
|
||
|
op->cc=5;
|
||
|
else if(p[3]=='n'&&p[4]=='n')
|
||
|
op->cc=7;
|
||
|
else if(p[3]=='n'&&p[4]=='c')
|
||
|
op->cc=0;
|
||
|
else if(p[3]=='e'&&p[4]=='q')
|
||
|
op->cc=2;
|
||
|
else if(p[3]=='n'&&p[4]=='e')
|
||
|
op->cc=3;
|
||
|
else
|
||
|
return 0;
|
||
|
}else if(len==6){
|
||
|
if(!strncmp(p+3,"ult",3))
|
||
|
op->cc=8;
|
||
|
else if(!strncmp(p+3,"ule",3))
|
||
|
op->cc=0xf;
|
||
|
else if(!strncmp(p+3,"uge",3))
|
||
|
op->cc=0x9;
|
||
|
else if(!strncmp(p+3,"ugt",3))
|
||
|
op->cc=0xe;
|
||
|
else if(!strncmp(p+3,"slt",3))
|
||
|
op->cc=0xc;
|
||
|
else if(!strncmp(p+3,"sle",3))
|
||
|
op->cc=0xb;
|
||
|
else if(!strncmp(p+3,"sge",3))
|
||
|
op->cc=0xd;
|
||
|
else if(!strncmp(p+3,"sgt",3))
|
||
|
op->cc=0xa;
|
||
|
else if(!strncmp(p+3,"net",3))
|
||
|
op->cc=0x1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
if((p[0]=='r'||p[0]=='R')&&p[1]>='0'&&p[1]<='9'&&(len==2||p[2]=='.')){
|
||
|
op->type=OP_GPR;
|
||
|
op->reg=p[1]-'0';
|
||
|
op->regsfr=op->reg+0xf0;
|
||
|
if(len>2){
|
||
|
op->type=OP_BADDR;
|
||
|
if(requires==OP_BADDR){
|
||
|
p=skip(p+3);
|
||
|
op->boffset=parse_expr(&p);
|
||
|
op->offset=number_expr(op->regsfr);
|
||
|
}
|
||
|
}
|
||
|
}else if((p[0]=='r'||p[0]=='R')&&p[1]=='1'&&p[2]>='0'&&p[2]<='5'&&(len==3||p[3]=='.')){
|
||
|
op->type=OP_GPR;
|
||
|
op->reg=(p[1]-'0')*10+p[2]-'0';
|
||
|
op->regsfr=op->reg+0xf0;
|
||
|
if(len>3){
|
||
|
op->type=OP_BADDR;
|
||
|
if(requires==OP_BADDR){
|
||
|
p=skip(p+4);
|
||
|
op->boffset=parse_expr(&p);
|
||
|
op->offset=number_expr(op->regsfr);
|
||
|
}
|
||
|
}
|
||
|
}else if(len==3&&(p[0]=='r'||p[0]=='R')&&(p[1]=='l'||p[1]=='L')&&p[2]>='0'&&p[2]<='7'){
|
||
|
op->type=OP_BGPR;
|
||
|
op->reg=(p[2]-'0')*2;
|
||
|
op->regsfr=op->reg+0xf0;
|
||
|
}else if(len==3&&(p[0]=='r'||p[0]=='R')&&(p[1]=='h'||p[1]=='H')&&p[2]>='0'&&p[2]<='7'){
|
||
|
op->type=OP_BGPR;
|
||
|
op->reg=(p[2]-'0')*2+1;
|
||
|
op->regsfr=op->reg+0xf0;
|
||
|
}else if(p[0]=='#'){
|
||
|
op->type=OP_IMM16;
|
||
|
p=skip(p+1);
|
||
|
if((!strncmp("SOF",p,3)||!strncmp("sof",p,3))&&isspace((unsigned char)p[3])){op->mod=MOD_SOF;p=skip(p+3);}
|
||
|
if((!strncmp("SEG",p,3)||!strncmp("seg",p,3))&&isspace((unsigned char)p[3])){op->mod=MOD_SEG;p=skip(p+3);}
|
||
|
if((!strncmp("DPP0:",p,5)||!strncmp("dpp0:",p,5))){op->mod=MOD_DPP0;p=skip(p+5);}
|
||
|
if((!strncmp("DPP1:",p,5)||!strncmp("dpp1:",p,5))){op->mod=MOD_DPP1;p=skip(p+5);}
|
||
|
if((!strncmp("DPP2:",p,5)||!strncmp("dpp2:",p,5))){op->mod=MOD_DPP2;p=skip(p+5);}
|
||
|
if((!strncmp("DPP3:",p,5)||!strncmp("dpp3:",p,5))){op->mod=MOD_DPP3;p=skip(p+5);}
|
||
|
if((!strncmp("DPPX:",p,5)||!strncmp("dppx:",p,5))){op->mod=MOD_DPPX;p=skip(p+5);}
|
||
|
op->offset=parse_expr(&p);
|
||
|
simplify_expr(op->offset);
|
||
|
#if 0
|
||
|
if(op->offset->type==NUM){
|
||
|
taddr val=op->offset->c.val;
|
||
|
if(val>=0&&val<=7)
|
||
|
op->type=OP_IMM3;
|
||
|
else if(val>=0&&val<=15)
|
||
|
op->type=OP_IMM4;
|
||
|
else if(val>=0&&val<=127)
|
||
|
op->type=OP_IMM7;
|
||
|
else if(val>=0&&val<=255)
|
||
|
op->type=OP_IMM8;
|
||
|
}
|
||
|
#endif
|
||
|
}else if(*p=='['){
|
||
|
p=skip(p+1);
|
||
|
if(*p=='-'){
|
||
|
p=skip(p+1);
|
||
|
p=skip_reg(p,&op->reg);
|
||
|
p=skip(p);
|
||
|
if(*p!=']')
|
||
|
cpu_error(0);
|
||
|
if(op->reg<=3)
|
||
|
op->type=OP_PREDEC03;
|
||
|
else
|
||
|
op->type=OP_PREDEC;
|
||
|
}else{
|
||
|
p=skip_reg(p,&op->reg);
|
||
|
p=skip(p);
|
||
|
if(*p=='+'){
|
||
|
p=skip(p+1);
|
||
|
if(*p==']'){
|
||
|
if(op->reg<=3)
|
||
|
op->type=OP_POSTINC03;
|
||
|
else
|
||
|
op->type=OP_POSTINC;
|
||
|
}else{
|
||
|
if(*p!='#')
|
||
|
cpu_error(0);
|
||
|
p=skip(p+1);
|
||
|
op->offset=parse_expr(&p);
|
||
|
p=skip(p);
|
||
|
op->type=OP_REGDISP;
|
||
|
}
|
||
|
}else{
|
||
|
if(op->reg<=3)
|
||
|
op->type=OP_REG03IND;
|
||
|
else
|
||
|
op->type=OP_REGIND;
|
||
|
}
|
||
|
if(*p!=']')
|
||
|
cpu_error(0);
|
||
|
}
|
||
|
}else{
|
||
|
if(ISIDSTART(*p)){
|
||
|
char *name=p;
|
||
|
hashdata data;
|
||
|
while((p==name||ISIDCHAR(*p))&&*p!='.')
|
||
|
p++;
|
||
|
if(find_namelen(sfrhash,name,p-name,&data)){
|
||
|
sfr *sfr;
|
||
|
sfr=data.ptr;
|
||
|
if(sfr->flags&ISBIT){
|
||
|
op->offset=number_expr(sfr->saddr);
|
||
|
op->type=OP_BADDR;
|
||
|
op->boffset=number_expr(sfr->boffset);
|
||
|
}else{
|
||
|
if(requires==OP_SFR||requires==OP_BSFR||requires==OP_BWORD){
|
||
|
op->offset=number_expr(sfr->saddr);
|
||
|
op->type=requires;
|
||
|
}else if(requires==OP_BADDR&&*p=='.'){
|
||
|
op->offset=number_expr(sfr->saddr);
|
||
|
p=skip(p+1);
|
||
|
op->boffset=parse_expr(&p);
|
||
|
op->type=OP_BADDR;
|
||
|
}else if(requires==OP_ABS||requires==OP_BABS){
|
||
|
op->type=requires;
|
||
|
op->offset=number_expr((2*sfr->saddr)+(sfr->laddr<<8));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if(op->type==-1)
|
||
|
p=name;
|
||
|
}
|
||
|
if(op->type==-1){
|
||
|
if((!strncmp("SOF",p,3)||!strncmp("sof",p,3))&&isspace((unsigned char)p[3])){op->mod=MOD_SOF;p=skip(p+3);}
|
||
|
if((!strncmp("SEG",p,3)||!strncmp("seg",p,3))&&isspace((unsigned char)p[3])){op->mod=MOD_SEG;p=skip(p+3);}
|
||
|
if((!strncmp("DPP0:",p,5)||!strncmp("dpp0:",p,5))){op->mod=MOD_DPP0;p=skip(p+5);}
|
||
|
if((!strncmp("DPP1:",p,5)||!strncmp("dpp1:",p,5))){op->mod=MOD_DPP1;p=skip(p+5);}
|
||
|
if((!strncmp("DPP2:",p,5)||!strncmp("dpp2:",p,5))){op->mod=MOD_DPP2;p=skip(p+5);}
|
||
|
if((!strncmp("DPP3:",p,5)||!strncmp("dpp3:",p,5))){op->mod=MOD_DPP3;p=skip(p+5);}
|
||
|
if((!strncmp("DPPX:",p,5)||!strncmp("dppx:",p,5))){op->mod=MOD_DPPX;p=skip(p+5);}
|
||
|
op->offset=parse_expr(&p);
|
||
|
op->type=OP_ABS;
|
||
|
}
|
||
|
}
|
||
|
if(requires==op->type)
|
||
|
return 1;
|
||
|
if(requires==OP_BWORD&&op->type==OP_SFR)
|
||
|
return 1;
|
||
|
if(op->type==OP_IMM16&&(requires>=OP_IMM2&&requires<=OP_IMM16))
|
||
|
return 1;
|
||
|
if(op->type==OP_PREDEC03&&requires==OP_PREDEC)
|
||
|
return 1;
|
||
|
if(op->type==OP_POSTINC03&&requires==OP_POSTINC)
|
||
|
return 1;
|
||
|
if(op->type==OP_REG03IND&&requires==OP_REGIND)
|
||
|
return 1;
|
||
|
if((requires==OP_SFR&&op->type==OP_GPR)||
|
||
|
(requires==OP_BWORD&&op->type==OP_GPR)||
|
||
|
(requires==OP_BWORD&&op->type==OP_BGPR)||
|
||
|
(requires==OP_BSFR&&op->type==OP_BGPR)){
|
||
|
op->offset=number_expr(op->regsfr);
|
||
|
return 1;
|
||
|
}
|
||
|
if(requires==OP_BSFR&&op->type==OP_BGPR)
|
||
|
return 1;
|
||
|
if(requires==OP_JADDR&&op->type==OP_ABS)
|
||
|
return 1;
|
||
|
if(requires==OP_BABS&&op->type==OP_ABS)
|
||
|
return 1;
|
||
|
/*FIXME*/
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static taddr reloffset(expr *tree,section *sec,taddr pc)
|
||
|
{
|
||
|
symbol *sym;
|
||
|
int btype;
|
||
|
taddr val;
|
||
|
simplify_expr(tree);
|
||
|
if(tree->type==NUM){
|
||
|
/* should we do it like this?? */
|
||
|
val=tree->c.val;
|
||
|
}else{
|
||
|
btype=find_base(tree,&sym,sec,pc);
|
||
|
if(btype!=BASE_OK||!LOCREF(sym)||sym->sec!=sec)
|
||
|
val=0xffff;
|
||
|
else{
|
||
|
eval_expr(tree,&val,sec,pc);
|
||
|
val=val-pc;
|
||
|
}
|
||
|
}
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
static taddr absoffset2(expr *tree,int mod,section *sec,taddr pc,rlist **relocs,int roffset,int size,taddr mask)
|
||
|
{
|
||
|
taddr val;
|
||
|
if(mod==MOD_SOF){
|
||
|
if(mask!=0xffffffff&&mask!=0xffff) cpu_error(5);
|
||
|
mask=0xffff;
|
||
|
}
|
||
|
if(mod==MOD_SEG){
|
||
|
if(mask!=0xff&&mask!=0xffff&&mask!=0xffffffff) cpu_error(6);
|
||
|
mask<<=16;
|
||
|
}
|
||
|
if(mod==MOD_DPP0||mod==MOD_DPP1||mod==MOD_DPP2||mod==MOD_DPP3||mod==MOD_DPPX){
|
||
|
if(mask!=0xffffffff&&mask!=0xffff) cpu_error(7);
|
||
|
mask=0x3fff;
|
||
|
}
|
||
|
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(mod==MOD_DPP1) val|=0x4000;
|
||
|
if(mod==MOD_DPP2) val|=0x8000;
|
||
|
if(mod==MOD_DPP3) val|=0xc000;
|
||
|
if(mod==MOD_DPPX){
|
||
|
static int dpplen;
|
||
|
static char *dppname;
|
||
|
char *id=base->name;
|
||
|
symbol *dppsym;
|
||
|
size-=2;
|
||
|
if(strlen(id)+9>dpplen){
|
||
|
myfree(dppname);
|
||
|
dppname=mymalloc(dpplen=strlen(id)+9);
|
||
|
}
|
||
|
strcpy(dppname,"___DPP_");
|
||
|
strcat(dppname,id);
|
||
|
dppsym=new_import(dppname);
|
||
|
if(dppsym->type==EXPRESSION){
|
||
|
if(!eval_expr(dppsym->expr,&val,0,0))
|
||
|
ierror(0);
|
||
|
val<<=14;
|
||
|
}else{
|
||
|
add_nreloc_masked(relocs,dppsym,0,REL_ABS,2,roffset+14,0x3);
|
||
|
}
|
||
|
}
|
||
|
add_nreloc_masked(relocs,base,addend,REL_ABS,size,roffset,mask);
|
||
|
return val;
|
||
|
}
|
||
|
val&=mask;
|
||
|
if(mod==MOD_DPPX) cpu_error(7);
|
||
|
if(mod==MOD_DPP1) val|=0x4000;
|
||
|
if(mod==MOD_DPP2) val|=0x8000;
|
||
|
if(mod==MOD_DPP3) val|=0xc000;
|
||
|
if(mod==MOD_SEG) val>>=16;
|
||
|
/*FIXME: range check */
|
||
|
#if 1
|
||
|
if(size==16)
|
||
|
return val&0xffff;
|
||
|
else
|
||
|
return val&((1<<size)-1);
|
||
|
#else
|
||
|
return val;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static taddr absoffset(expr *tree,int mod,section *sec,taddr pc,rlist **relocs,int roffset,int size)
|
||
|
{
|
||
|
/* taddr mask=size==32?0xffffffff:((((taddr)1)<<size)-1);*/
|
||
|
return absoffset2(tree,mod,sec,pc,relocs,roffset,size,0xffffffff);
|
||
|
}
|
||
|
|
||
|
static taddr absval(expr *tree,section *sec,taddr pc,int bits)
|
||
|
{
|
||
|
taddr val;
|
||
|
if(!eval_expr(tree,&val,sec,pc))
|
||
|
cpu_error(0);
|
||
|
if(bits==2){
|
||
|
/* ext instructions */
|
||
|
if(val<1||val>4)
|
||
|
cpu_error(3,2);
|
||
|
return val;
|
||
|
}else if(val<0||val>=(1<<bits))
|
||
|
cpu_error(3,bits);
|
||
|
return val&((1<<bits)-1);
|
||
|
}
|
||
|
|
||
|
static int translate(instruction *p,section *sec,taddr pc)
|
||
|
{
|
||
|
int c=p->code;
|
||
|
taddr val;
|
||
|
/* choose one of jmpr/jmpa */
|
||
|
if(c==JMP||(!notrans&&(c==JMPA||c==JMPR||c==JB||c==JNB))){
|
||
|
val=reloffset(p->op[1]->offset,sec,pc);
|
||
|
if(val<-256||val>254||val%2){
|
||
|
if(c==JB) return JNB|JMPCONV;
|
||
|
if(c==JNB) return JB|JMPCONV;
|
||
|
if(c==JMPA) return JMPA;
|
||
|
if(tojmpa) return JMPA;
|
||
|
if(p->op[0]->cc==0)
|
||
|
return JMPS;
|
||
|
else
|
||
|
return JMPR|JMPCONV;
|
||
|
}else{
|
||
|
if(c==JB||c==JNB)
|
||
|
return c;
|
||
|
return JMPR;
|
||
|
}
|
||
|
}
|
||
|
/* choose between gpr,#imm3 and reg,#imm16 */
|
||
|
if(mnemonics[c].operand_type[1]==OP_IMM3){
|
||
|
if(!eval_expr(p->op[1]->offset,&val,sec,pc)||val<0||val>7){
|
||
|
if(!strcmp(mnemonics[c].name,mnemonics[c+1].name))
|
||
|
return c+1;
|
||
|
}
|
||
|
}
|
||
|
/* choose between gpr,#imm4 and reg,#imm16 */
|
||
|
if(mnemonics[c].operand_type[1]==OP_IMM4){
|
||
|
if(!eval_expr(p->op[1]->offset,&val,sec,pc)||val<0||val>7){
|
||
|
if(!strcmp(mnemonics[c].name,mnemonics[c+1].name))
|
||
|
return c+1;
|
||
|
}
|
||
|
}
|
||
|
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 opcode,c,jmpconv=0,osize;
|
||
|
unsigned long code;
|
||
|
char *d;
|
||
|
taddr val;
|
||
|
rlist *relocs=0;
|
||
|
operand *jmpaddr;
|
||
|
|
||
|
c=translate(p,sec,pc);
|
||
|
if(c&JMPCONV){ jmpconv=1;c&=~JMPCONV;}
|
||
|
if((mnemonics[p->code].operand_type[0]==OP_GPR&&mnemonics[c].operand_type[0]==OP_SFR)||
|
||
|
(mnemonics[p->code].operand_type[0]==OP_BGPR&&mnemonics[c].operand_type[0]==OP_BSFR))
|
||
|
p->op[0]->offset=number_expr(p->op[0]->regsfr);
|
||
|
|
||
|
|
||
|
db->size=osize=mnemonics[c].ext.len*2;
|
||
|
if(jmpconv) db->size+=4;
|
||
|
db->data=mymalloc(db->size);
|
||
|
|
||
|
opcode=mnemonics[c].ext.opcode;
|
||
|
switch(mnemonics[c].ext.encoding){
|
||
|
case 0:
|
||
|
code=opcode<<16|(opcode>>8)<<8|opcode>>8;
|
||
|
break;
|
||
|
case 1:
|
||
|
code=opcode;
|
||
|
break;
|
||
|
case 2:
|
||
|
code=opcode|p->op[0]->reg<<4|p->op[1]->reg;
|
||
|
break;
|
||
|
case 3:
|
||
|
code=opcode|p->op[0]->reg|p->op[1]->reg<<4;
|
||
|
break;
|
||
|
case 4:
|
||
|
code=opcode|p->op[0]->reg<<4|p->op[1]->reg|8;
|
||
|
break;
|
||
|
case 5:
|
||
|
code=opcode|p->op[0]->reg<<4|p->op[1]->reg|12;
|
||
|
break;
|
||
|
case 6:
|
||
|
code=opcode|p->op[0]->reg<<4|absval(p->op[1]->offset,sec,pc,3);
|
||
|
break;
|
||
|
case 7:
|
||
|
/* fall through */
|
||
|
case 8:
|
||
|
code=opcode<<16|absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,20,8)<<16|absoffset(p->op[1]->offset,p->op[1]->mod,sec,pc,&relocs,16,16);
|
||
|
break;
|
||
|
case 9:
|
||
|
code=opcode|p->op[0]->reg|absval(p->op[1]->offset,sec,pc,4)<<4;
|
||
|
break;
|
||
|
case 10:
|
||
|
/* rfi: reorder bmov operands */
|
||
|
code=opcode<<16|
|
||
|
absoffset(p->op[1]->offset,p->op[1]->mod,sec,pc,&relocs,8,8)<<16|
|
||
|
absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,16,8)<<0|
|
||
|
absoffset(p->op[1]->boffset,0,sec,pc,&relocs,24,4)<<12|
|
||
|
absoffset(p->op[0]->boffset,0,sec,pc,&relocs,28,4)<<8;
|
||
|
break;
|
||
|
case 11:
|
||
|
code=opcode|absoffset(p->op[0]->boffset,0,sec,pc,&relocs,0,4)<<12|absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,8,8);
|
||
|
break;
|
||
|
case 12:
|
||
|
code=opcode<<16|
|
||
|
absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,8,8)<<16|
|
||
|
absoffset(p->op[2]->offset,p->op[2]->mod,sec,pc,&relocs,16,8)<<8|
|
||
|
absoffset(p->op[1]->offset,p->op[1]->mod,sec,pc,&relocs,24,8);
|
||
|
break;
|
||
|
case 13:
|
||
|
code=opcode<<16|
|
||
|
absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,8,8)<<16|
|
||
|
absoffset(p->op[1]->offset,p->op[1]->mod,sec,pc,&relocs,16,8)<<8|
|
||
|
absoffset(p->op[2]->offset,p->op[2]->mod,sec,pc,&relocs,24,8);
|
||
|
break;
|
||
|
case 14:
|
||
|
code=opcode<<16|p->op[0]->cc<<20|absoffset(p->op[1]->offset,p->op[1]->mod,sec,pc,&relocs,16,16);
|
||
|
break;
|
||
|
case 15:
|
||
|
code=opcode|p->op[0]->cc<<4|p->op[1]->reg;
|
||
|
break;
|
||
|
case 16:
|
||
|
val=((reloffset(p->op[0]->offset,sec,pc)-2)>>1)&255;
|
||
|
code=opcode|val;
|
||
|
break;
|
||
|
case 17:
|
||
|
if(p->op[0]->type==OP_CC){
|
||
|
/* jmp cc_uc was converted to jmps */
|
||
|
code=opcode<<16|absoffset2(p->op[1]->offset,0,sec,pc,&relocs,8,8,0xffff0000)<<16|absoffset2(p->op[1]->offset,0,sec,pc,&relocs,16,16,0xffff);
|
||
|
}else{
|
||
|
code=opcode<<16|absoffset2(p->op[0]->offset,0,sec,pc,&relocs,8,8,0xffff0000)<<16|absoffset2(p->op[0]->offset,0,sec,pc,&relocs,16,16,0xffff);
|
||
|
}
|
||
|
break;
|
||
|
case 18:
|
||
|
/* fall through */
|
||
|
case 19:
|
||
|
code=opcode<<16|0xf<<20|p->op[0]->reg<<16|absoffset(p->op[1]->offset,p->op[1]->mod,sec,pc,&relocs,16,16);
|
||
|
break;
|
||
|
case 20:
|
||
|
code=opcode|p->op[0]->reg<<4;
|
||
|
break;
|
||
|
case 21:
|
||
|
code=opcode|p->op[0]->reg<<4|p->op[0]->reg;
|
||
|
break;
|
||
|
case 22:
|
||
|
if(!jmpconv){
|
||
|
val=((reloffset(p->op[1]->offset,sec,pc)-4)>>1)&255;
|
||
|
code=opcode<<16|
|
||
|
absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,8,8)<<16|
|
||
|
absoffset(p->op[0]->boffset,0,sec,pc,&relocs,24,4)<<12|
|
||
|
val;
|
||
|
}else{
|
||
|
code=opcode<<16|
|
||
|
absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,8,8)<<16|
|
||
|
absoffset(p->op[0]->boffset,0,sec,pc,&relocs,24,4)<<12|
|
||
|
2;
|
||
|
jmpaddr=p->op[1];
|
||
|
}
|
||
|
break;
|
||
|
case 23:
|
||
|
if(!jmpconv){
|
||
|
val=((reloffset(p->op[1]->offset,sec,pc)-2)>>1)&255;
|
||
|
code=opcode|p->op[0]->cc<<12|val;
|
||
|
}else{
|
||
|
code=opcode|INVCC(p->op[0]->cc)<<12|2;
|
||
|
jmpaddr=p->op[1];
|
||
|
}
|
||
|
break;
|
||
|
case 24:
|
||
|
code=opcode<<16|p->op[0]->reg<<20|p->op[1]->reg<<16|absoffset(p->op[1]->offset,p->op[1]->mod,sec,pc,&relocs,16,16);
|
||
|
break;
|
||
|
case 25:
|
||
|
code=opcode<<16|p->op[0]->reg<<16|absoffset(p->op[1]->offset,p->op[1]->mod,sec,pc,&relocs,16,16);
|
||
|
break;
|
||
|
case 26:
|
||
|
code=opcode|absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,8,8);
|
||
|
break;
|
||
|
case 27:
|
||
|
code=opcode|absval(p->op[0]->offset,sec,pc,7)<<1;
|
||
|
break;
|
||
|
case 28:
|
||
|
code=opcode<<16|p->op[0]->reg<<16|p->op[1]->reg<<20|absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,16,16);
|
||
|
break;
|
||
|
case 29:
|
||
|
code=opcode<<16|absoffset(p->op[1]->offset,p->op[1]->mod,sec,pc,&relocs,8,8)<<16|absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,16,16);
|
||
|
break;
|
||
|
case 30:
|
||
|
code=opcode<<16|p->op[1]->reg<<16|absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,16,16);
|
||
|
break;
|
||
|
case 31:
|
||
|
code=opcode|((absval(p->op[0]->offset,sec,pc,2)-1)<<4);
|
||
|
break;
|
||
|
case 32:
|
||
|
code=opcode|p->op[0]->reg|((absval(p->op[1]->offset,sec,pc,2)-1)<<4);
|
||
|
break;
|
||
|
case 34:
|
||
|
code=opcode<<16|((absval(p->op[1]->offset,sec,pc,2)-1)<<20)|absoffset(p->op[0]->offset,p->op[0]->mod,sec,pc,&relocs,16,8);
|
||
|
break;
|
||
|
case 33:
|
||
|
default:
|
||
|
ierror(mnemonics[c].ext.encoding);
|
||
|
}
|
||
|
|
||
|
d=db->data;
|
||
|
if(osize==4){
|
||
|
*d++=code>>24;
|
||
|
*d++=code>>16;
|
||
|
*d++=code;
|
||
|
*d++=code>>8;
|
||
|
}else{
|
||
|
*d++=code>>8;
|
||
|
*d++=code;
|
||
|
}
|
||
|
if(jmpconv){
|
||
|
*d++=0xfa;
|
||
|
*d++=absoffset2(jmpaddr->offset,0,sec,pc,&relocs,8+8*osize,8,0xffff0000);
|
||
|
val=absoffset2(jmpaddr->offset,0,sec,pc,&relocs,16+8*osize,16,0xffff);
|
||
|
*d++=val>>8;
|
||
|
*d++=val;
|
||
|
}
|
||
|
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(4);
|
||
|
val=absoffset(op->offset,op->mod,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=translate(p,sec,pc),add=0;
|
||
|
if(c&JMPCONV){ add=4;c&=~JMPCONV;}
|
||
|
return mnemonics[c].ext.len*2+add;
|
||
|
}
|
||
|
|
||
|
operand *new_operand()
|
||
|
{
|
||
|
operand *new=mymalloc(sizeof(*new));
|
||
|
new->type=-1;
|
||
|
return new;
|
||
|
}
|
||
|
|
||
|
/* return true, if initialization was successfull */
|
||
|
int init_cpu()
|
||
|
{
|
||
|
int i;
|
||
|
for(i=0;i<mnemonic_cnt;i++){
|
||
|
if(!strcmp(mnemonics[i].name,"jmp"))
|
||
|
JMP=i;
|
||
|
if(!strcmp(mnemonics[i].name,"jmpr"))
|
||
|
JMPR=i;
|
||
|
if(!strcmp(mnemonics[i].name,"jmpa"))
|
||
|
JMPA=i;
|
||
|
if(!strcmp(mnemonics[i].name,"jmps"))
|
||
|
JMPS=i;
|
||
|
if(!strcmp(mnemonics[i].name,"jb"))
|
||
|
JB=i;
|
||
|
if(!strcmp(mnemonics[i].name,"jbc"))
|
||
|
JBC=i;
|
||
|
if(!strcmp(mnemonics[i].name,"jnb"))
|
||
|
JNB=i;
|
||
|
if(!strcmp(mnemonics[i].name,"jnbs"))
|
||
|
JNBS=i;
|
||
|
}
|
||
|
sfrhash=new_hashtable(SFRHTSIZE);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* return true, if the passed argument is understood */
|
||
|
int cpu_args(char *p)
|
||
|
{
|
||
|
if(!strcmp(p,"-no-translations")){
|
||
|
notrans=1;
|
||
|
return 1;
|
||
|
}
|
||
|
if(!strcmp(p,"-jmpa")){
|
||
|
tojmpa=1;
|
||
|
return 1;
|
||
|
}
|
||
|
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;
|
||
|
if(ISIDSTART(*s)){
|
||
|
s++;
|
||
|
while(ISIDCHAR(*s))
|
||
|
s++;
|
||
|
if(s-name==4&&!strncmp(name,".sfr",4)){
|
||
|
sfr *new;
|
||
|
hashdata data;
|
||
|
expr *tree;
|
||
|
s=skip(s);
|
||
|
if(!ISIDSTART(*s))
|
||
|
cpu_error(0);
|
||
|
name=s++;
|
||
|
while(ISIDCHAR(*s))
|
||
|
s++;
|
||
|
if(find_namelen(sfrhash,name,s-name,&data))
|
||
|
new=data.ptr;
|
||
|
else{
|
||
|
data.ptr=new=mymalloc(sizeof(*new));
|
||
|
add_hashentry(sfrhash,cnvstr(name,s-name),data);
|
||
|
new->next=first_sfr;
|
||
|
first_sfr=new;
|
||
|
}
|
||
|
new->flags=new->laddr=new->saddr=0;
|
||
|
new->boffset=0;
|
||
|
s=skip(s);
|
||
|
if(*s!=',')
|
||
|
cpu_error(0);
|
||
|
else
|
||
|
s=skip(s+1);
|
||
|
tree=parse_expr(&s);
|
||
|
simplify_expr(tree);
|
||
|
if(!tree||tree->type!=NUM)
|
||
|
cpu_error(0);
|
||
|
else
|
||
|
new->laddr=tree->c.val;
|
||
|
s=skip(s);
|
||
|
if(tree->c.val==0xfe||tree->c.val==0xf0){
|
||
|
if(*s!=',')
|
||
|
cpu_error(0);
|
||
|
else
|
||
|
s=skip(s+1);
|
||
|
free_expr(tree);
|
||
|
tree=parse_expr(&s);
|
||
|
simplify_expr(tree);
|
||
|
if(!tree||tree->type!=NUM)
|
||
|
cpu_error(0);
|
||
|
else
|
||
|
new->saddr=tree->c.val;
|
||
|
free_expr(tree);
|
||
|
s=skip(s);
|
||
|
}else{
|
||
|
if(tree->c.val>=0xfe00)
|
||
|
new->laddr=0xfe;
|
||
|
else
|
||
|
new->laddr=0xf0;
|
||
|
new->saddr=(tree->c.val-(new->laddr<<8))/2;
|
||
|
if((new->laddr<<8)+2*new->saddr!=tree->c.val) ierror(0);
|
||
|
free_expr(tree);
|
||
|
}
|
||
|
if(*s==','){
|
||
|
s=skip(s+1);
|
||
|
tree=parse_expr(&s);
|
||
|
simplify_expr(tree);
|
||
|
new->boffset=tree->c.val;
|
||
|
new->flags|=ISBIT;
|
||
|
free_expr(tree);
|
||
|
}
|
||
|
return skip(s);
|
||
|
}
|
||
|
}
|
||
|
return merk;
|
||
|
}
|