1 /* cpu.c example cpu-description file */
2 /* (c) in 2002 by Volker Barthelmann */
3 
4 #include "vasm.h"
5 
6 char *cpu_copyright="vasm test cpu backend (c) in 2002 Volker Barthelmann";
7 
8 /* example machine.
9    valid Registers: R0-R3
10    valid extensions: .b/.w (default .w)
11 
12    Instruction format:
13    XCCCCCCC 11112222 [32bit op1] [32bit op2]
14 
15    X:   set if byte-extension
16    C:   instruction code
17    1/2: operand 1/2 type
18         0-3  register
19         4-7  register indirect (32bit offset follows)
20         8    absolute (32bit value follows)
21         9    immediate (32bit value follows)
22         Special case for addq: 1111: immediate 0-15
23         Special case for bra: 11112222: 0-255 relative offset
24 */
25 
26 char *cpuname="test";
27 int bitsperbyte=8;
28 int bytespertaddr=4;
29 
30 mnemonic mnemonics[]={
31   "move",{OP_ALL,OP_REG},{CPU_ALL,0x0},
32   "move",{OP_REG,OP_ALL_DEST},{CPU_ALL,0x1},
33   "add",{OP_ALL,OP_REG},{CPU_ALL,0x2},
34   "add",{OP_REG,OP_ALL_DEST},{CPU_ALL,0x3},
35   "add",{OP_IMM32,OP_MEM},{CPU_ALL,0x4},
36   "addq",{OP_IMM32,OP_ALL_DEST},{CPU_ALL,0x5},
37   "jmp",{OP_ABS,0},{CPU_ALL,0x6},
38   "bra",{OP_ABS,0},{CPU_ALL,0x7},
39 };
40 
41 int mnemonic_cnt=sizeof(mnemonics)/sizeof(mnemonics[0]);
42 
43 
parse_instruction(char * s,int * inst_len,char ** ext,int * ext_len,int * ext_cnt)44 char *parse_instruction(char *s,int *inst_len,char **ext,int *ext_len,
45                         int *ext_cnt)
46 /* parse instruction and save extension locations */
47 {
48   char *inst = s;
49 
50   while (*s && *s!='.' && !isspace((unsigned char)*s))
51     s++;
52   *inst_len = s - inst;
53   if (*s =='.') {
54     /* extension present */
55     ext[*ext_cnt] = ++s;
56     while (*s && *s!='.' && !isspace((unsigned char)*s))
57       s++;
58     ext_len[*ext_cnt] = s - ext[*ext_cnt];
59     *ext_cnt += 1;
60   }
61   return s;
62 }
63 
set_default_qualifiers(char ** q,int * q_len)64 int set_default_qualifiers(char **q,int *q_len)
65 /* fill in pointers to default qualifiers, return number of qualifiers */
66 {
67   q[0] = "w";
68   q_len[0] = 1;
69   return 1;
70 }
71 
72 /* Does not do much useful parsing yet. */
parse_operand(char * p,int len,operand * op,int requires)73 int parse_operand(char *p,int len,operand *op,int requires)
74 {
75   p=skip(p);
76   if(len==2&&(p[0]=='r'||p[0]=='R')&&p[1]>='0'&&p[1]<='3'){
77     op->type=OP_REG;
78     op->basereg=p[1]-'0';
79   }else if(p[0]=='#'){
80     op->type=OP_IMM32;
81     p=skip(p+1);
82     op->offset=parse_expr(&p);
83   }else{
84     int parent=0;
85     expr *tree;
86     op->type=-1;
87     if(*p=='('){
88       parent=1;
89       p=skip(p+1);
90     }
91     tree=parse_expr(&p);
92     if(!tree)
93       return 0;
94     p=skip(p);
95     if(parent){
96       if(*p==','){
97 	p=skip(p+1);
98 	if((*p!='r'&&*p!='R')||p[1]<'0'||p[1]>'3'){
99 	  cpu_error(0);
100 	  return 0;
101 	}
102 	op->type=OP_REGIND;
103 	op->basereg=p[1]-'0';
104 	p=skip(p+2);
105       }
106       if(*p!=')'){
107 	cpu_error(0);
108 	return 0;
109       }else
110 	p=skip(p+1);
111     }
112     if(op->type!=OP_REGIND)
113       op->type=OP_ABS;
114     op->offset=tree;
115   }
116   if(requires==op->type)
117     return 1;
118   if(requires==OP_ALL_DEST&&op->type!=OP_IMM32)
119     return 1;
120   if(requires==OP_MEM&&OP_ISMEM(op->type))
121     return 1;
122   if(requires==OP_ALL)
123     return 1;
124   return 0;
125 }
126 
127 /* Return new instruction code, if instruction can be optimized
128    to another one. */
opt_inst(instruction * p,section * sec,taddr pc)129 static int opt_inst(instruction *p,section *sec,taddr pc)
130 {
131   /* Ganz simples Beispiel. */
132 
133   /* add->addq */
134   if((p->code==2||p->code==4)&&p->op[0]->type==OP_IMM32){
135     taddr val;
136     if(eval_expr(p->op[0]->offset,&val,sec,pc)&&val<16)
137       return 5;
138   }
139   /* jmp->bra */
140   if(p->code==6){
141     expr *tree=p->op[0]->offset;
142     if(tree->type==SYM&&tree->c.sym->sec==sec&&LOCREF(tree->c.sym)&&
143        tree->c.sym->pc-pc>=-128&&tree->c.sym->pc-pc<=127)
144       return 7;
145   }
146   return p->code;
147 }
148 
operand_code(operand * p)149 static int operand_code(operand *p)
150 {
151   if(!p)
152     return 0;
153   if(p->type==OP_REG)
154     return p->basereg;
155   if(p->type==OP_REGIND)
156     return 4+p->basereg;
157   if(p->type==OP_ABS)
158     return 8;
159   if(p->type==OP_IMM32)
160     return 9;
161   ierror(0);
162 }
fill_operand(operand * p,section * sec,taddr pc,char * d,rlist ** relocs,int roffset)163 static char *fill_operand(operand *p,section *sec,taddr pc,char *d,rlist **relocs,int roffset)
164 {
165   taddr val;
166   if(!p||p->type==OP_REG)
167     return d;
168   /* FIXME: Test for valid operand, create reloc */
169   if(!eval_expr(p->offset,&val,sec,pc)){
170     symbol *base;
171     if (find_base(p->offset,&base,sec,pc)!=BASE_OK)
172       general_error(38);
173     else
174       add_nreloc(relocs,base,0,REL_ABS,16,roffset*8);
175   }
176   *d++=val>>24;
177   *d++=val>>16;
178   *d++=val>>8;
179   *d++=val;
180   return d;
181 }
182 
183 /* Convert an instruction into a DATA atom including relocations,
184    if necessary. */
eval_instruction(instruction * p,section * sec,taddr pc)185 dblock *eval_instruction(instruction *p,section *sec,taddr pc)
186 {
187   /* Auch simpel. Fehlerchecks fehlen. */
188   size_t size=instruction_size(p,sec,pc);
189   dblock *db=new_dblock();
190   int c=opt_inst(p,sec,pc);
191   unsigned char *d;
192   taddr val;
193   db->size=size;
194   d=db->data=mymalloc(size);
195   *d=c;
196   if(p->qualifiers[0]){
197     if(c>5)
198       cpu_error(1,p->qualifiers[0]);
199     else if(!strcmp(p->qualifiers[0],"b"))
200       *d|=128;
201     else if(strcmp(p->qualifiers[0],"w"))
202       cpu_error(1,p->qualifiers[0]);
203   }
204   d++;
205   if(c==5){
206     /* addq */
207     taddr val;
208     if(!eval_expr(p->op[0]->offset,&val,sec,pc)||val>15)
209       cpu_error(0);
210     *d=((val<<4)|operand_code(p->op[1]));
211     return db;
212   }
213   if(c==7){
214     expr *tree=p->op[0]->offset;
215     if(!(tree->type==SYM&&tree->c.sym->sec==sec&&LOCREF(tree->c.sym)&&
216 	 tree->c.sym->pc-pc>=-128&&tree->c.sym->pc-pc<=127))
217       cpu_error(0);
218     else
219       *d=tree->c.sym->pc-pc;
220     return db;
221   }
222 
223   *d=((operand_code(p->op[0])<<4)|operand_code(p->op[1]));
224   d++;
225   d=fill_operand(p->op[0],sec,pc,d,&db->relocs,d-db->data);
226   d=fill_operand(p->op[1],sec,pc,d,&db->relocs,d-db->data);
227   return db;
228 }
229 
230 /* Create a dblock (with relocs, if necessary) for size bits of data. */
eval_data(operand * op,size_t bitsize,section * sec,taddr pc)231 dblock *eval_data(operand *op,size_t bitsize,section *sec,taddr pc)
232 {
233   dblock *new=new_dblock();
234   taddr val;
235   new->size=(bitsize+7)/8;
236   new->data=mymalloc(new->size);
237   if(op->type!=OP_ABS)
238     ierror(0);
239   if(bitsize!=8&&bitsize!=16&&bitsize!=32)
240     cpu_error(2);
241   if(!eval_expr(op->offset,&val,sec,pc)&&bitsize!=32)
242     general_error(38);
243   if(bitsize==8){
244     new->data[0]=val;
245   }else if(bitsize==16){
246     new->data[0]=val>>8;
247     new->data[1]=val;
248   }else if(bitsize==32){
249     fill_operand(op,sec,pc,new->data,&new->relocs,0);
250   }
251   return new;
252 }
253 
opsize(operand * p)254 static taddr opsize(operand *p)
255 {
256   if(!p)
257     return 0;
258   if(p->type!=OP_REG)
259     return 4;
260   else
261     return 0;
262 }
263 
264 /* Calculate the size of the current instruction; must be identical
265    to the data created by eval_instruction. */
instruction_size(instruction * p,section * sec,taddr pc)266 size_t instruction_size(instruction *p,section *sec,taddr pc)
267 {
268   int c;
269   size_t size=2;
270   size+=opsize(p->op[0]);
271   size+=opsize(p->op[1]);
272   c=opt_inst(p,sec,pc);
273   if(c==5||c==7){
274     /* addq/bra */
275     size-=4;
276   }
277   return size;
278 }
279 
new_operand()280 operand *new_operand()
281 {
282   operand *new=mymalloc(sizeof(*new));
283   new->type=-1;
284   return new;
285 }
286 
287 /* return true, if initialization was successfull */
init_cpu()288 int init_cpu()
289 {
290   return 1;
291 }
292 
293 /* return true, if the passed argument is understood */
cpu_args(char * p)294 int cpu_args(char *p)
295 {
296   /* no args */
297   return 0;
298 }
299 
300 /* parse cpu-specific directives; return pointer to end of
301    cpu-specific text */
parse_cpu_special(char * s)302 char *parse_cpu_special(char *s)
303 {
304   /* no specials */
305   return s;
306 }
307