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", ®) != 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