1 /* cpu.c tr3200 cpu description file */
2 /* (c) in 2014 by Luis Panadero Guardeno */
3 
4 #include "vasm.h"
5 
6 /*#define CPU_DEBUG (1)*/
7 #ifdef CPU_DEBUG
8 #define OPERAND_DEBUG (1)
9 #define INSTR_DEBUG (1)
10 #endif
11 
12 char *cpu_copyright="vasm TR3200 cpu module v0.1.2 by Luis Panadero Guardeno";
13 
14 char *cpuname="tr3200";
15 int bitsperbyte=8;
16 int bytespertaddr=4;
17 
18 mnemonic mnemonics[]={
19 #include "opcodes.h"
20 };
21 
22 int mnemonic_cnt=sizeof(mnemonics)/sizeof(mnemonics[0]);
23 
24 
25 static taddr opsize(operand *p, unsigned char num_operands, section *sec, taddr pc);
26 
27 /* parse instruction */
parse_instruction(char * s,int * inst_len,char ** ext,int * ext_len,int * ext_cnt)28 char *parse_instruction(char *s, int *inst_len, char **ext, int *ext_len,
29                         int *ext_cnt)
30 {
31   char* inst = s;
32 #ifdef CPU_DEBUG
33     fprintf(stderr, "parse_inst : \"%.*s\"\n", *inst_len, s);
34 #endif
35 /*
36   while (*s && !isspace((unsigned char)*s))
37     s++;
38   *inst_len = s - inst; */
39   return s;
40 }
41 
42 /* Sets op if is a valid register */
parse_reg(char ** p,int len,operand * op)43 static int parse_reg(char **p, int len, operand *op)
44 {
45   char *rp = skip(*p);
46   int reg = -1;
47 
48   if (len < 2) {
49     return 0;
50   }
51 
52   if (*rp != '%') {
53     return 0;
54   }
55   rp++;
56 
57   if (tolower((unsigned char)rp[0]) != 'r') {
58     /* Could be y, bp, sp, ia or flags */
59     if (len == 2 && tolower((unsigned char)rp[0]) == 'y') {
60       rp++;
61       *p = skip(rp);
62       op->type = OP_GPR;
63       op->reg = 11;
64 
65       return 1;
66     } else if ( len == 3 && (tolower((unsigned char)rp[0]) == 'b')
67         && (tolower((unsigned char)rp[1]) == 'p')  ) {
68       rp++; rp++;
69       *p = skip(rp);
70       op->type = OP_GPR;
71       op->reg = 12;
72 
73       return 1;
74     } else if ( len == 3 && (tolower((unsigned char)rp[0]) == 's')
75         && (tolower((unsigned char)rp[1]) == 'p')  ) {
76       rp++; rp++;
77       *p = skip(rp);
78       op->type = OP_GPR;
79       op->reg = 13;
80 
81       return 1;
82     } else if ( len == 3 && (tolower((unsigned char)rp[0]) == 'i')
83         && (tolower((unsigned char)rp[1]) == 'a')  ) {
84       rp++; rp++;
85       *p = skip(rp);
86       op->type = OP_GPR;
87       op->reg = 14;
88 
89       return 1;
90     } else if ( len == 6
91         && (tolower((unsigned char)rp[0]) == 'f')
92         && (tolower((unsigned char)rp[1]) == 'l')
93         && (tolower((unsigned char)rp[2]) == 'a')
94         && (tolower((unsigned char)rp[3]) == 'g')
95         && (tolower((unsigned char)rp[4]) == 's')
96         ) {
97       rp += 5;
98       *p = skip(rp);
99       op->type = OP_GPR;
100       op->reg = 14;
101 
102       return 1;
103     }
104     /* It's not a register */
105     return 0;
106   }
107 
108   rp++;
109   /* Get number */
110   if (len < 2 || sscanf(rp, "%u", &reg) != 1) {
111     return 0;
112   }
113 
114   /* "%r0 .. %r15" are valid */
115   if (reg < 0 || reg > 15) {
116     return 0;
117   }
118 
119   /* skip digits and return new pointer together with register number */
120   while ( isdigit((unsigned char)*rp) ) {
121     rp++;
122   }
123 
124   *p = skip(rp);
125   op->type = OP_GPR;
126   op->reg = reg;
127   return 1;
128 }
129 
130 /* Parses operands and reads expressions
131  * *p string
132  * len string length
133  * *op operand
134  * requires Type of operand expected
135  */
parse_operand(char * p,int len,operand * op,int requires)136 int parse_operand(char *p, int len, operand *op, int requires)
137 {
138   op->type = NO_OP;
139 #ifdef OPERAND_DEBUG
140     fprintf(stderr, "parse_operand (reqs=%02x): \"%.*s\"\t",
141            (unsigned)requires, len, p);
142 #endif
143 
144   /* Try to grab the register */
145   if (1 != parse_reg(&p, len, op) ) {
146 #ifdef OPERAND_DEBUG
147     fprintf(stderr, "imm\t");
148 #endif
149     /* Its not a register, should be a immediate value or a expression */
150     if(p[0]=='#') { /* Immediate value */
151       expr *tree;
152 #ifdef OPERAND_DEBUG
153     fprintf(stderr, "# ");
154 #endif
155       op->type = OP_IMM;
156       p=skip(p+1);
157       tree = parse_expr(&p);
158       if (!tree) { /* It's not a valid expresion */
159         return PO_NOMATCH;
160       }
161       op->value = tree;
162     } else { /* expresion that would be a immediate value */
163 #ifdef OPERAND_DEBUG
164     fprintf(stderr, "expr\t");
165 #endif
166       op->type = OP_IMM;
167 
168       int parent=0;
169       expr *tree;
170 
171       /*
172       if (*p=='(') {
173         parent=1;
174         p=skip(p+1);
175       }
176       */
177 
178       tree = parse_expr(&p);
179       if (!tree) { /* It's not a valid expresion */
180         return PO_NOMATCH ;
181       }
182 
183       /* Inside of a ( ) */
184       /*
185       p=skip(p);
186       if(parent) {
187         if(*p!=')'){
188           cpu_error(0);
189           return 0;
190         } else
191         p=skip(p+1);
192       }
193       */
194 
195       op->value=tree;
196     }
197   }
198 
199 #ifdef OPERAND_DEBUG
200     fprintf(stderr, "(type=%02x)\n", (unsigned) op->type);
201 #endif
202 
203   if(requires == op->type) { /* Matched type */
204     return PO_MATCH;
205   }
206 
207   return PO_NOMATCH; /* Ops! Not match */
208 }
209 
210 /* Convert an instruction into a DATA atom including relocations,
211    if necessary. */
eval_instruction(instruction * p,section * sec,taddr pc)212 dblock *eval_instruction (instruction *p, section *sec, taddr pc)
213 {
214   /* Calc instruction size */
215   size_t size = instruction_size(p, sec, pc);
216   dblock *db = new_dblock();
217   mnemonic m = mnemonics[p->code];
218   unsigned char *opcode, *d; /* Data */
219   taddr val;
220   unsigned char ml_bits = 0;
221   unsigned char num_operands = 0;
222   unsigned char srn = 0; /* Size of Rn */
223   operand* rn = NULL;
224   symbol *base = NULL;
225   int btype;
226 
227 #ifdef INSTR_DEBUG
228   fprintf(stderr, "eval_instruction code \"%s\" ", m.name);
229 #endif
230 
231   num_operands += (m.operand_type[0] != NO_OP)? 1 : 0;
232   num_operands += (m.operand_type[1] != NO_OP)? 1 : 0;
233   num_operands += (m.operand_type[2] != NO_OP)? 1 : 0;
234   if (num_operands > 0) {
235     rn = p->op[m.ext.rn_pos];
236   }
237 
238 #ifdef INSTR_DEBUG
239   fprintf(stderr, "P%d ", num_operands);
240   if (num_operands > 0)
241     fprintf(stderr, "rn type=%02x ", (unsigned) rn->type);
242 #endif
243 
244   /* See if Rn is an immediate to set ML bits*/
245   if (rn != NULL && rn->type == OP_IMM) {
246     srn = opsize(rn, num_operands, sec, pc);
247     ml_bits = 2 | (srn == 4);
248   }
249   ml_bits = ml_bits << 6; /* Emplace ML bits */
250 #ifdef INSTR_DEBUG
251   fprintf(stderr, "IMM=%d ", srn);
252   fprintf(stderr, "ml %02x ", ml_bits);
253 #endif
254 
255   db->size=size;
256   db->data = mymalloc(size); /* allocate for the data block */
257   memset(db->data, 0, db->size);
258   /* Here to write data ! */
259   d = db->data;
260   d[3] = m.ext.opcode; /* Common part */
261   d[2] = ml_bits;
262 
263   switch (num_operands) {
264     case 3: /* format P3 */
265       /* Rn is always at the LSBytes side */
266       if( rn->type == OP_GPR) { /* Is a register */
267         d[0] = (rn->reg) & 0xF;
268       } else if (ml_bits == 0x80 ) { /* ML are 10 -> immediate */
269         eval_expr(rn->value, &val, sec, pc);
270 #ifdef INSTR_DEBUG
271     fprintf(stderr, "val %04x ", val);
272 #endif
273         d[1] = (val >>8)  & 0x3F;
274         d[0] = (val )     & 0xFF;
275       } else { /* 32 bit immediate */
276         eval_expr(rn->value, &val, sec, pc);
277 #ifdef INSTR_DEBUG
278     fprintf(stderr, "val %08x ", val);
279 #endif
280         d[7] = (val >>24) & 0xFF;
281         d[6] = (val >>16) & 0xFF;
282         d[5] = (val >>8 ) & 0xFF;
283         d[4] = (val )     & 0xFF;
284       }
285 
286       if (m.ext.rn_pos == 1) { /* Special case of STORE */
287         d[1] |= (p->op[0]->reg & 0xF) << 6;
288         d[2] |= (p->op[0]->reg & 0xF) >> 2;
289         d[2] |= (p->op[2]->reg) << 2; /* rd */
290       } else {
291         d[1] |= (p->op[1]->reg & 0xF) << 6;
292         d[2] |= (p->op[1]->reg & 0xF) >> 2;
293         d[2] |= (p->op[0]->reg) << 2; /* rd */
294       }
295 
296       break;
297 
298     case 2: /* format P2 */
299       if( rn->type == OP_GPR) { /* Is a register */
300         d[0] = (rn->reg) & 0xF;
301       } else if (ml_bits == 0x80 ) { /* ML are 10 -> immediate */
302         eval_expr(rn->value, &val, sec, pc);
303         /* CALL/JUMP stuff */
304         if (m.ext.opcode == 0x4B || m.ext.opcode == 0x4C ) {
305           val = val >> 2; /* CALL/JMP does a left shift of two bits */
306         }
307 #ifdef INSTR_DEBUG
308     fprintf(stderr, "val %06x ", val);
309 #endif
310         d[2] |= (val >>16)  & 0x03;
311         d[1] =  (val >>8)  & 0xFF;
312         d[0] =  (val )     & 0xFF;
313 
314       } else { /* 32 bit immediate */
315         eval_expr(rn->value, &val, sec, pc);
316 #ifdef INSTR_DEBUG
317     fprintf(stderr, "val %08x ", val);
318 #endif
319         d[7] = (val >>24) & 0xFF;
320         d[6] = (val >>16) & 0xFF;
321         d[5] = (val >>8 ) & 0xFF;
322         d[4] = (val )     & 0xFF;
323       }
324 
325       if (m.ext.rn_pos == 0) { /* Special case of STORE */
326         d[2] |= (p->op[1]->reg) << 2;
327       } else {
328         d[2] |= (p->op[0]->reg) << 2;
329       }
330       break;
331 
332     case 1: /* format P1 */
333       if( rn->type == OP_GPR) { /* Is a register */
334         d[0] = (rn->reg) & 0xF;
335       } else if (ml_bits == 0x80 ) { /* ML are 10 -> immediate */
336         if (!eval_expr(rn->value, &val, sec, pc))
337           btype = find_base(rn->value, &base, sec, pc);
338         /* CALL/JUMP stuff */
339         if (m.ext.opcode >= 0x27 && m.ext.opcode <= 0x28 ) {
340           if (base != NULL && btype == BASE_OK) {
341             if (is_pc_reloc(base, sec))
342               add_extnreloc_masked(&db->relocs, base, val-4, REL_PC,
343                                    0, 22, 0, 0xfffffc);
344             else if (LOCREF(base))
345               val = val - pc - 4; /* Relative jump/call (%pc has been increased) */
346             base = NULL;
347           }
348           else
349             val = val - pc - 4; /* Relative jump/call (%pc has been increased) */
350           val = val >> 2; /* CALL/JMP does a left shift of two bits */
351         } else if (m.ext.opcode >= 0x25 && m.ext.opcode <= 0x26 ) {
352           if (base != NULL && btype != BASE_ILLEGAL) {
353             add_extnreloc_masked(&db->relocs, base, val,
354                                  btype == BASE_PCREL ? REL_PC : REL_ABS,
355                                  0, 22, 0, 0xfffffc);
356             base = NULL;
357           }
358           val = val >> 2; /* CALL/JMP does a left shift of two bits */
359         }
360 
361 #ifdef INSTR_DEBUG
362     fprintf(stderr, "val %06x ", val);
363 #endif
364         d[2] |= (val >>16)  & 0x3F;
365         d[1] =  (val >>8)  & 0xFF;
366         d[0] =  (val )     & 0xFF;
367 
368       } else { /* 32 bit immediate */
369         eval_expr(rn->value, &val, sec, pc);
370         /* CALL/JUMP stuff */
371         if (m.ext.opcode >= 0x27 && m.ext.opcode <= 0x28 ) {
372           val = val - pc - 4; /* Relative jump/call */
373         }
374 #ifdef INSTR_DEBUG
375     fprintf(stderr, "val %08x ", val);
376 #endif
377         d[7] = (val >>24) & 0xFF;
378         d[6] = (val >>16) & 0xFF;
379         d[5] = (val >>8 ) & 0xFF;
380         d[4] = (val )     & 0xFF;
381       }
382 
383       break;
384 
385     case 0: /* format NP */
386 #ifdef INSTR_DEBUG
387     fprintf(stderr, "NP ");
388 #endif
389     default:
390     ;
391   }
392 #ifdef INSTR_DEBUG
393   {
394     int i;
395     for(i= db->size -1; i >= 0; i-- ) {
396       fprintf(stderr, "%02X ", d[i]);
397     }
398   }
399   fprintf(stderr, "\n");
400 #endif
401 
402   return db;
403 }
404 
405 /* Create a dblock (with relocs, if necessary) for size bits of data. */
eval_data(operand * op,size_t bitsize,section * sec,taddr pc)406 dblock *eval_data(operand *op, size_t bitsize, section *sec, taddr pc)
407 {
408   dblock *new=new_dblock();
409   taddr val;
410   new->size = bitsize >> 3;
411   new->data = mymalloc(new->size);
412 #ifdef CPU_DEBUG
413     fprintf(stderr, "eval_data ");
414 #endif
415   if(op->type != OP_IMM) { /* ??? */
416 #ifdef CPU_DEBUG
417     fprintf(stderr, "!= OP_IMM\n");
418 #endif
419     ierror(0);
420   }
421 
422   if(bitsize!=8 && bitsize!=16 && bitsize!=32) {
423 #ifdef CPU_DEBUG
424     fprintf(stderr, "bad data size\n");
425 #endif
426     cpu_error(2); /* Invalid data size */
427   }
428 
429   if(!eval_expr(op->value, &val, sec, pc) ) {
430     symbol *base;
431     int btype;
432 
433     btype = find_base(op->value, &base, sec, pc);
434     if (base)
435       add_extnreloc(&new->relocs, base, val,
436                     btype==BASE_PCREL ? REL_PC : REL_ABS, 0, bitsize, 0);
437     else if (btype != BASE_NONE)
438       general_error(38);  /* illegal relocation */
439   }
440 
441   if(bitsize == 8){
442     new->data[0] = val & 0xFF;
443 
444   } else if (bitsize == 16){
445     new->data[1] = (val>>8)  & 0xFF;
446     new->data[0] = val       & 0xFF;
447 
448   } else if (bitsize == 32){
449     new->data[3] = (val>>24) & 0xFF;
450     new->data[2] = (val>>16) & 0xFF;
451     new->data[1] = (val>>8)  & 0xFF;
452     new->data[0] = val       & 0xFF;
453   }
454   return new;
455 }
456 
457 /* Size of a operand
458  * *p operand
459  * num_operand Total number of operands
460  * */
opsize(operand * p,unsigned char num_operands,section * sec,taddr pc)461 static taddr opsize(operand *p, unsigned char num_operands, section *sec, taddr pc)
462 {
463   taddr val = 0;
464   if(!p) {
465     return 0;
466 
467   } else if (p->type == OP_IMM ) {
468     eval_expr(p->value, &val, sec, pc);
469     if (num_operands == 3
470         && (val < -8192 || val > 8191) ) {          /* 14 bits */
471       return 4; /* 32 bit immediate */
472     } else if (num_operands == 2
473         && (val < -131072 || val > 131071) ) {  /* 18 bits */
474       return 4; /* 32 bit immediate */
475     } else if (num_operands == 1
476         && (val < -2097152 || val > 2097151) ) { /* 22 bits */
477       return 4; /* 32 bit immediate */
478     }
479   }
480   return 0;
481 }
482 
483 /* Calculate the size of the current instruction; must be identical
484    to the data created by eval_instruction. */
instruction_size(instruction * p,section * sec,taddr pc)485 size_t instruction_size (instruction *p, section *sec, taddr pc)
486 {
487   size_t size = 4; /* four bytes */
488   unsigned char num_operands = 0;
489   num_operands += (p->op[0] != 0)? 1 : 0;
490   num_operands += (p->op[1] != 0)? 1 : 0;
491   num_operands += (p->op[2] != 0)? 1 : 0;
492 
493   size += opsize(p->op[0], num_operands, sec, pc);
494   size += opsize(p->op[1], num_operands, sec, pc);
495   size += opsize(p->op[2], num_operands, sec, pc);
496 
497   return size;
498 }
499 
new_operand()500 operand *new_operand()
501 {
502   operand *new = mymalloc(sizeof(*new));
503   new->type=-1;
504   return new;
505 }
506 
507 /* return true, if initialization was successfull */
init_cpu()508 int init_cpu()
509 {
510   return 1;
511 }
512 
513 /* return true, if the passed argument is understood */
cpu_args(char * p)514 int cpu_args(char *p)
515 {
516   /* no args */
517   return 0;
518 }
519 
520 /* parse cpu-specific directives; return pointer to end of
521    cpu-specific text */
parse_cpu_special(char * s)522 char *parse_cpu_special(char *s)
523 {
524   /* no specials */
525   return s;
526 }
527