Commit | Line | Data |
---|---|---|
163107a1 SC |
1 | /* tc-z8k.c -- Assemble code for the Zilog Z800N |
2 | Copyright (C) 1992 Free Software Foundation. | |
3 | ||
4 | This file is part of GAS, the GNU Assembler. | |
5 | ||
6 | GAS is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GAS is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GAS; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | ||
20 | ||
21 | /* | |
22 | Written By Steve Chamberlain | |
23 | sac@cygnus.com | |
24 | */ | |
25 | ||
26 | #include <stdio.h> | |
27 | #define DEFINE_TABLE | |
cfb48ce5 | 28 | #include "../opcodes/z8k-opc.h" |
163107a1 SC |
29 | |
30 | #include "as.h" | |
587c4264 | 31 | #include "read.h" |
163107a1 SC |
32 | #include "bfd.h" |
33 | #include <ctype.h> | |
34 | #include "listing.h" | |
35 | ||
587c4264 ILT |
36 | const char comment_chars[] = { '!',0 }; |
37 | const char line_separator_chars[] = { ';' ,0}; | |
38 | const char line_comment_chars[] = ""; | |
163107a1 SC |
39 | |
40 | extern int machine; | |
41 | extern int coff_flags; | |
42 | int segmented_mode; | |
43 | int md_reloc_size ; | |
44 | ||
45 | /* This table describes all the machine specific pseudo-ops the assembler | |
46 | has to support. The fields are: | |
47 | pseudo-op name without dot | |
48 | function to call to execute this pseudo-op | |
49 | Integer arg to pass to the function | |
50 | */ | |
51 | ||
52 | void cons(); | |
53 | ||
54 | ||
55 | void s_segm() | |
56 | { | |
57 | segmented_mode = 1; | |
58 | machine = bfd_mach_z8001; | |
59 | coff_flags = F_Z8001; | |
60 | } | |
61 | ||
62 | void s_unseg() | |
63 | { | |
64 | segmented_mode = 0; | |
65 | machine = bfd_mach_z8002; | |
66 | coff_flags = F_Z8002; | |
67 | } | |
68 | const pseudo_typeS md_pseudo_table[] = | |
69 | { | |
70 | { "int", cons, 2 }, | |
71 | { "data.b", cons, 1 }, | |
72 | { "data.w", cons, 2 }, | |
73 | { "data.l", cons, 4 }, | |
74 | { "form", listing_psize, 0 }, | |
75 | { "heading", listing_title, 0}, | |
76 | { "import", s_ignore, 0}, | |
77 | { "page", listing_eject, 0}, | |
78 | { "program", s_ignore, 0}, | |
587c4264 ILT |
79 | { "z8001", s_segm, 0}, |
80 | { "z8002", s_unseg, 0}, | |
163107a1 SC |
81 | { 0,0,0 } |
82 | }; | |
83 | ||
84 | ||
85 | const char EXP_CHARS[] = "eE"; | |
86 | ||
87 | /* Chars that mean this number is a floating point constant */ | |
88 | /* As in 0f12.456 */ | |
89 | /* or 0d1.2345e12 */ | |
587c4264 | 90 | const char FLT_CHARS[] = "rRsSfFdDxXpP"; |
163107a1 SC |
91 | |
92 | ||
93 | const relax_typeS md_relax_table[1]; | |
94 | ||
95 | ||
96 | static struct hash_control *opcode_hash_control; /* Opcode mnemonics */ | |
97 | ||
98 | ||
99 | ||
100 | void md_begin () | |
101 | { | |
102 | opcode_entry_type *opcode; | |
103 | char *prev_name= ""; | |
104 | int idx = 0; | |
105 | ||
106 | opcode_hash_control = hash_new(); | |
107 | ||
108 | ||
109 | for (opcode = z8k_table; opcode->name; opcode++) | |
110 | { | |
111 | /* Only enter unique codes into the table */ | |
112 | char *src= opcode->name; | |
113 | ||
114 | if (strcmp(opcode->name, prev_name)) | |
115 | { | |
116 | hash_insert(opcode_hash_control, opcode->name, (char *)opcode); | |
117 | idx++; | |
118 | } | |
119 | opcode->idx = idx; | |
120 | prev_name = opcode->name; | |
121 | } | |
122 | ||
123 | } | |
124 | ||
125 | ||
126 | struct z8k_exp { | |
127 | char *e_beg; | |
128 | char *e_end; | |
129 | expressionS e_exp; | |
130 | }; | |
131 | typedef struct z8k_op | |
132 | { | |
133 | char regsize; /* 'b','w','r','q' */ | |
134 | unsigned int reg; /* 0..15 */ | |
135 | ||
136 | int mode; | |
137 | ||
138 | unsigned int x_reg;/* any other register associated with the mode */ | |
139 | expressionS exp; /* any expression */ | |
140 | } op_type; | |
141 | ||
142 | ||
143 | ||
587c4264 ILT |
144 | static expressionS *da_operand; |
145 | static expressionS *imm_operand; | |
163107a1 | 146 | |
587c4264 ILT |
147 | |
148 | int reg[16]; | |
163107a1 SC |
149 | int the_cc; |
150 | ||
151 | char * | |
152 | DEFUN(whatreg,(reg, src), | |
153 | int *reg AND | |
154 | char *src) | |
155 | { | |
156 | if (isdigit(src[1])) | |
157 | { | |
158 | *reg = (src[0] - '0') * 10 +src[1] - '0'; | |
159 | return src+2; | |
160 | } | |
161 | else | |
162 | { | |
163 | *reg = (src[0] - '0'); | |
164 | return src+1; | |
165 | } | |
166 | return 0; | |
167 | } | |
168 | ||
169 | /* | |
170 | parse operands | |
171 | ||
172 | rh0-rh7, rl0-rl7 | |
173 | r0-r15 | |
174 | rr0-rr14 | |
175 | rq0--rq12 | |
176 | WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp | |
177 | r0l,r0h,..r7l,r7h | |
178 | @WREG | |
179 | @WREG+ | |
180 | @-WREG | |
181 | #const | |
182 | ||
183 | */ | |
184 | ||
185 | ||
186 | /* try and parse a reg name, returns number of chars consumed */ | |
187 | char* | |
188 | DEFUN(parse_reg,(src, mode, reg), | |
189 | char *src AND | |
190 | int * mode AND | |
191 | unsigned int *reg) | |
192 | { | |
193 | char *res = 0; | |
587c4264 | 194 | if (src[0] == 'r') |
163107a1 | 195 | { |
587c4264 | 196 | if (src[1] == 'r') |
163107a1 SC |
197 | { |
198 | *mode = CLASS_REG_LONG; | |
199 | res = whatreg(reg, src+2); | |
200 | } | |
587c4264 | 201 | else if (src[1] == 'h') |
163107a1 SC |
202 | { |
203 | *mode = CLASS_REG_BYTE; | |
204 | res = whatreg(reg, src+2); | |
205 | } | |
587c4264 | 206 | else if (src[1] == 'l') |
163107a1 SC |
207 | { |
208 | *mode = CLASS_REG_BYTE; | |
209 | res = whatreg(reg, src+2); | |
210 | } | |
587c4264 | 211 | else if (src[1] == 'q') |
163107a1 SC |
212 | { |
213 | * mode = CLASS_REG_QUAD; | |
214 | res = whatreg(reg, src+2); | |
215 | } | |
216 | else | |
217 | { | |
218 | *mode = CLASS_REG_WORD; | |
219 | res = whatreg(reg, src+1); | |
220 | } | |
221 | } | |
222 | return res; | |
223 | ||
224 | ||
225 | } | |
226 | ||
227 | char * | |
228 | DEFUN(parse_exp,(s, op), | |
229 | char *s AND | |
230 | expressionS *op) | |
231 | { | |
232 | char *save = input_line_pointer; | |
233 | char *new; | |
234 | segT seg; | |
235 | input_line_pointer = s; | |
236 | seg = expr(0,op); | |
237 | new = input_line_pointer; | |
238 | input_line_pointer = save; | |
239 | if (SEG_NORMAL(seg)) | |
240 | return new; | |
241 | switch (seg) { | |
242 | case SEG_ABSOLUTE: | |
243 | case SEG_UNKNOWN: | |
244 | case SEG_DIFFERENCE: | |
245 | case SEG_BIG: | |
246 | case SEG_REGISTER: | |
247 | return new; | |
248 | case SEG_ABSENT: | |
249 | as_bad("Missing operand"); | |
250 | return new; | |
251 | default: | |
252 | as_bad("Don't understand operand of type %s", segment_name (seg)); | |
253 | return new; | |
254 | } | |
255 | } | |
256 | ||
257 | ||
258 | /* The many forms of operand: | |
259 | ||
260 | <rb> | |
261 | <r> | |
262 | <rr> | |
263 | <rq> | |
264 | @r | |
265 | #exp | |
266 | exp | |
267 | exp(r) | |
268 | r(#exp) | |
269 | r(r) | |
270 | ||
271 | ||
272 | ||
273 | */ | |
274 | ||
275 | static | |
276 | char * | |
277 | DEFUN(checkfor,(ptr, what), | |
278 | char *ptr AND | |
279 | char what) | |
280 | { | |
281 | if (*ptr == what) ptr++; | |
282 | else { | |
283 | as_bad("expected %c", what); | |
284 | } | |
285 | return ptr; | |
286 | } | |
287 | ||
288 | /* Make sure the mode supplied is the size of a word */ | |
289 | static void | |
290 | DEFUN(regword,(mode, string), | |
291 | int mode AND | |
292 | char *string) | |
293 | { | |
294 | int ok; | |
295 | ok = CLASS_REG_WORD; | |
296 | if (ok != mode) | |
297 | { | |
298 | as_bad("register is wrong size for a word %s", string); | |
299 | } | |
300 | } | |
301 | ||
302 | /* Make sure the mode supplied is the size of an address */ | |
303 | static void | |
304 | DEFUN(regaddr,(mode, string), | |
305 | int mode AND | |
306 | char *string) | |
307 | { | |
308 | int ok; | |
309 | ok = segmented_mode ? CLASS_REG_LONG : CLASS_REG_WORD; | |
310 | if (ok != mode) | |
311 | { | |
312 | as_bad("register is wrong size for address %s", string); | |
313 | } | |
314 | } | |
315 | ||
316 | struct cc_names { | |
317 | int value; | |
318 | char *name; | |
319 | ||
320 | ||
321 | }; | |
322 | ||
323 | struct cc_names table[] = | |
324 | { | |
587c4264 ILT |
325 | 0x0,"f", |
326 | 0x1,"lt", | |
327 | 0x2,"le", | |
328 | 0x3,"ule", | |
329 | 0x4,"ov", | |
330 | 0x4,"pe", | |
331 | 0x5,"mi", | |
332 | 0x6,"eq", | |
333 | 0x6,"z", | |
334 | 0x7,"c", | |
335 | 0x7,"ult", | |
336 | 0x8,"t", | |
337 | 0x9,"ge", | |
338 | 0xa,"gt", | |
339 | 0xb,"ugt", | |
340 | 0xc,"nov", | |
341 | 0xc,"po", | |
342 | 0xd,"pl", | |
343 | 0xe,"ne", | |
344 | 0xe,"nz", | |
345 | 0xf,"nc", | |
346 | 0xf,"uge", | |
163107a1 SC |
347 | 0,0 |
348 | }; | |
349 | ||
350 | static void | |
351 | DEFUN(get_cc_operand,(ptr, mode, dst), | |
352 | char **ptr AND | |
353 | struct z8k_op *mode AND | |
354 | unsigned int dst) | |
355 | { | |
356 | char *src = *ptr; | |
357 | int r; | |
358 | int i; | |
587c4264 ILT |
359 | while (*src== ' ') |
360 | src++; | |
361 | ||
163107a1 SC |
362 | mode->mode = CLASS_CC; |
363 | for (i = 0; table[i].name; i++) | |
364 | { | |
365 | int j; | |
366 | for (j = 0; table[i].name[j]; j++) | |
367 | { | |
368 | if (table[i].name[j] != src[j]) | |
369 | goto fail; | |
370 | } | |
587c4264 | 371 | the_cc = table[i].value; |
163107a1 SC |
372 | *ptr = src + j; |
373 | return; | |
374 | fail:; | |
375 | } | |
587c4264 | 376 | the_cc = 0x8; |
163107a1 SC |
377 | return ; |
378 | } | |
379 | ||
380 | static void | |
381 | DEFUN(get_operand,(ptr, mode, dst), | |
382 | char **ptr AND | |
383 | struct z8k_op *mode AND | |
384 | unsigned int dst) | |
385 | { | |
386 | char *src = *ptr; | |
387 | char *end; | |
388 | unsigned int num; | |
389 | unsigned int len; | |
390 | unsigned int size; | |
391 | mode->mode = 0; | |
392 | ||
587c4264 ILT |
393 | |
394 | while (*src == ' ') | |
395 | src++; | |
163107a1 SC |
396 | if (*src == '#') |
397 | { | |
398 | mode->mode = CLASS_IMM; | |
587c4264 | 399 | imm_operand = &(mode->exp); |
163107a1 SC |
400 | src = parse_exp(src+1, &(mode->exp)); |
401 | } | |
402 | else if (*src == '@') { | |
403 | int d; | |
404 | mode->mode = CLASS_IR; | |
405 | src= parse_reg(src+1, &d, &mode->reg); | |
406 | } | |
407 | else | |
408 | { | |
587c4264 ILT |
409 | int regn; |
410 | end = parse_reg(src, &mode->mode, ®n); | |
163107a1 SC |
411 | |
412 | if (end) | |
413 | { | |
414 | int nw, nr; | |
415 | src = end; | |
416 | if (*src == '(') | |
417 | { | |
418 | src++; | |
419 | end = parse_reg(src, &nw, &nr); | |
420 | if (end) | |
421 | { | |
422 | /* Got Ra(Rb) */ | |
423 | src = end; | |
424 | ||
425 | if (*src != ')') | |
426 | { | |
427 | as_bad("Missing ) in ra(rb)"); | |
428 | } | |
429 | else | |
430 | { | |
431 | src++; | |
432 | } | |
433 | ||
434 | regaddr(mode->mode,"ra(rb) ra"); | |
435 | regword(mode->mode,"ra(rb) rb"); | |
436 | mode->mode = CLASS_BX; | |
587c4264 | 437 | mode->reg = regn; |
163107a1 | 438 | mode->x_reg = nr; |
587c4264 | 439 | reg[ARG_RX] = nr; |
163107a1 SC |
440 | } |
441 | else | |
442 | { | |
443 | /* Got Ra(disp) */ | |
444 | if (*src == '#') | |
445 | src++; | |
446 | src = parse_exp(src, &(mode->exp)); | |
447 | src = checkfor(src, ')'); | |
448 | mode->mode = CLASS_BA; | |
587c4264 | 449 | mode->reg = regn; |
163107a1 | 450 | mode->x_reg = 0; |
587c4264 | 451 | da_operand = &(mode->exp); |
163107a1 SC |
452 | } |
453 | } | |
454 | else | |
455 | { | |
587c4264 | 456 | mode->reg = regn; |
163107a1 SC |
457 | mode->x_reg = 0; |
458 | } | |
459 | } | |
460 | else | |
461 | { | |
462 | /* No initial reg */ | |
463 | src = parse_exp(src, &(mode->exp)); | |
464 | if (*src == '(') | |
465 | { | |
466 | src++; | |
587c4264 | 467 | end = parse_reg(src, &(mode->mode), ®n); |
163107a1 SC |
468 | regword(mode->mode,"addr(Ra) ra"); |
469 | mode->mode = CLASS_X; | |
587c4264 | 470 | mode->reg = regn; |
163107a1 | 471 | mode->x_reg =0; |
587c4264 | 472 | da_operand = &(mode->exp); |
163107a1 SC |
473 | src = checkfor(end, ')'); |
474 | } | |
475 | else | |
476 | { | |
477 | /* Just an address */ | |
478 | mode->mode = CLASS_DA; | |
479 | mode->reg = 0; | |
480 | mode->x_reg = 0; | |
587c4264 | 481 | da_operand = &(mode->exp); |
163107a1 SC |
482 | } |
483 | } | |
484 | } | |
485 | *ptr = src; | |
486 | } | |
487 | ||
488 | static | |
489 | char * | |
cfb48ce5 SC |
490 | DEFUN(get_operands,(opcode, op_end, operand), |
491 | opcode_entry_type *opcode AND | |
492 | char *op_end AND | |
493 | op_type *operand) | |
163107a1 SC |
494 | { |
495 | char *ptr = op_end; | |
496 | switch (opcode->noperands) | |
497 | { | |
498 | case 0: | |
499 | operand[0].mode = 0; | |
500 | operand[1].mode = 0; | |
501 | break; | |
502 | ||
587c4264 | 503 | case 1: |
163107a1 | 504 | ptr++; |
587c4264 ILT |
505 | if (opcode->arg_info[0] == CLASS_CC) |
506 | { | |
507 | get_cc_operand(&ptr, operand+0,0); | |
508 | } | |
509 | else | |
510 | { | |
511 | ||
512 | get_operand(& ptr, operand +0,0); | |
513 | } | |
163107a1 SC |
514 | operand[1].mode =0; |
515 | break; | |
516 | ||
517 | case 2: | |
518 | ptr++; | |
519 | if (opcode->arg_info[0] == CLASS_CC) | |
520 | { | |
521 | get_cc_operand(&ptr, operand+0,0); | |
522 | } | |
523 | else | |
524 | { | |
587c4264 | 525 | |
163107a1 SC |
526 | get_operand(& ptr, operand +0,0); |
527 | } | |
528 | if (*ptr == ',') ptr++; | |
529 | get_operand(& ptr, operand +1, 1); | |
530 | break; | |
587c4264 ILT |
531 | |
532 | case 3: | |
533 | ptr++; | |
534 | get_operand(& ptr, operand +0,0); | |
535 | if (*ptr == ',') ptr++; | |
536 | get_operand(& ptr, operand +1, 1); | |
537 | if (*ptr == ',') ptr++; | |
538 | get_operand(& ptr, operand +2, 2); | |
539 | break; | |
163107a1 SC |
540 | |
541 | default: | |
542 | abort(); | |
543 | } | |
544 | ||
545 | ||
546 | return ptr; | |
547 | } | |
548 | ||
549 | /* Passed a pointer to a list of opcodes which use different | |
550 | addressing modes, return the opcode which matches the opcodes | |
551 | provided | |
552 | */ | |
553 | ||
587c4264 ILT |
554 | |
555 | ||
163107a1 SC |
556 | |
557 | static | |
558 | opcode_entry_type * | |
559 | DEFUN(get_specific,(opcode, operands), | |
560 | opcode_entry_type *opcode AND | |
561 | op_type *operands) | |
562 | ||
563 | { | |
564 | opcode_entry_type *this_try = opcode ; | |
565 | int found = 0; | |
566 | unsigned int noperands = opcode->noperands; | |
567 | ||
568 | unsigned int dispreg; | |
569 | unsigned int this_index = opcode->idx; | |
570 | ||
571 | while (this_index == opcode->idx && !found) | |
572 | { | |
573 | unsigned int i; | |
574 | ||
575 | this_try = opcode ++; | |
576 | for (i = 0; i < noperands; i++) | |
577 | { | |
578 | int mode = operands[i].mode; | |
579 | ||
587c4264 ILT |
580 | if ((mode&CLASS_MASK) != (this_try->arg_info[i] & CLASS_MASK)) |
581 | { | |
582 | /* it could be an pc rel operand, if this is a da mode and | |
583 | we like disps, then insert it */ | |
584 | ||
585 | if (mode == CLASS_DA && this_try->arg_info[i] == CLASS_DISP) | |
586 | { | |
587 | /* This is the case */ | |
588 | operands[i].mode = CLASS_DISP; | |
589 | } | |
590 | else { | |
591 | /* Can't think of a way to turn what we've been given into | |
592 | something that's ok */ | |
593 | goto fail; | |
594 | } | |
595 | } | |
596 | switch (mode & CLASS_MASK) { | |
597 | default: | |
598 | break; | |
599 | case CLASS_X: | |
600 | case CLASS_IR: | |
601 | case CLASS_BA: | |
602 | case CLASS_BX: | |
603 | case CLASS_DISP: | |
604 | case CLASS_REG: | |
605 | reg[this_try->arg_info[i] & ARG_MASK] = operands[i].reg; | |
606 | break; | |
607 | } | |
163107a1 SC |
608 | } |
609 | ||
610 | found =1; | |
611 | fail: ; | |
612 | } | |
613 | if (found) | |
614 | return this_try; | |
615 | else | |
616 | return 0; | |
617 | } | |
618 | ||
619 | static void | |
620 | DEFUN(check_operand,(operand, width, string), | |
621 | struct z8k_op *operand AND | |
622 | unsigned int width AND | |
623 | char *string) | |
624 | { | |
625 | if (operand->exp.X_add_symbol == 0 | |
626 | && operand->exp.X_subtract_symbol == 0) | |
627 | { | |
628 | ||
629 | /* No symbol involved, let's look at offset, it's dangerous if any of | |
630 | the high bits are not 0 or ff's, find out by oring or anding with | |
631 | the width and seeing if the answer is 0 or all fs*/ | |
632 | if ((operand->exp.X_add_number & ~width) != 0 && | |
633 | (operand->exp.X_add_number | width)!= (~0)) | |
634 | { | |
635 | as_warn("operand %s0x%x out of range.", string, operand->exp.X_add_number); | |
636 | } | |
637 | } | |
638 | ||
639 | } | |
640 | ||
641 | static void | |
642 | DEFUN(newfix,(ptr, type, operand), | |
cfb48ce5 | 643 | int ptr AND |
163107a1 | 644 | int type AND |
587c4264 | 645 | expressionS *operand) |
163107a1 | 646 | { |
587c4264 ILT |
647 | if (operand->X_add_symbol |
648 | || operand->X_subtract_symbol | |
649 | || operand->X_add_number) { | |
650 | fix_new(frag_now, | |
651 | ptr, | |
652 | 1, | |
653 | operand->X_add_symbol, | |
654 | operand->X_subtract_symbol, | |
655 | operand->X_add_number, | |
656 | 0, | |
657 | type); | |
658 | } | |
163107a1 SC |
659 | } |
660 | ||
661 | ||
662 | /* Now we know what sort of opcodes it is, lets build the bytes - | |
663 | */ | |
664 | static void | |
665 | DEFUN (build_bytes,(this_try, operand), | |
666 | opcode_entry_type *this_try AND | |
667 | struct z8k_op *operand) | |
668 | { | |
669 | unsigned int i; | |
670 | char buffer[20]; | |
671 | int length; | |
672 | char *output; | |
673 | char *output_ptr = buffer; | |
674 | char part; | |
675 | int c; | |
676 | char high; | |
677 | int nib; | |
678 | int nibble; | |
679 | unsigned short *class_ptr; | |
587c4264 | 680 | memset(buffer, 20, 0); |
163107a1 SC |
681 | class_ptr = this_try->byte_info; |
682 | top: ; | |
683 | ||
684 | for (nibble = 0; c = *class_ptr++; nibble++) | |
685 | { | |
686 | ||
687 | switch (c & CLASS_MASK) | |
688 | { | |
689 | default: | |
587c4264 | 690 | |
163107a1 SC |
691 | abort(); |
692 | case CLASS_ADDRESS: | |
693 | /* Direct address, we don't cope with the SS mode right now */ | |
694 | if (segmented_mode) { | |
587c4264 ILT |
695 | newfix((output_ptr-buffer)/2, R_DA | R_SEG, da_operand); |
696 | *output_ptr++ = 0; | |
697 | *output_ptr++ = 0; | |
698 | *output_ptr++ = 0; | |
699 | *output_ptr++ = 0; | |
700 | *output_ptr++ = 0; | |
701 | *output_ptr++ = 0; | |
702 | *output_ptr++ = 0; | |
703 | *output_ptr++ = 0; | |
163107a1 SC |
704 | } |
705 | else { | |
587c4264 ILT |
706 | newfix((output_ptr-buffer)/2, R_DA, da_operand); |
707 | *output_ptr++ = 0; | |
708 | *output_ptr++ = 0; | |
709 | *output_ptr++ = 0; | |
710 | *output_ptr++ = 0; | |
163107a1 | 711 | } |
587c4264 | 712 | da_operand = 0; |
163107a1 | 713 | break; |
587c4264 ILT |
714 | case CLASS_DISP8: |
715 | /* pc rel 8 bit */ | |
716 | newfix((output_ptr-buffer)/2, R_JR, da_operand); | |
717 | da_operand = 0; | |
718 | *output_ptr++ = 0; | |
719 | *output_ptr++ = 0; | |
720 | break; | |
721 | ||
163107a1 SC |
722 | case CLASS_CC: |
723 | *output_ptr++ = the_cc; | |
724 | break; | |
725 | case CLASS_BIT: | |
726 | *output_ptr++ = c & 0xf; | |
727 | break; | |
728 | case CLASS_REGN0: | |
729 | if (reg[c&0xf] == 0) | |
730 | { | |
731 | as_bad("can't use R0 here"); | |
732 | } | |
733 | case CLASS_REG: | |
734 | case CLASS_REG_BYTE: | |
735 | case CLASS_REG_WORD: | |
736 | case CLASS_REG_LONG: | |
737 | case CLASS_REG_QUAD: | |
738 | /* Insert bit mattern of | |
739 | right reg */ | |
740 | *output_ptr++ = reg[c & 0xf]; | |
741 | break; | |
587c4264 ILT |
742 | case CLASS_DISP: |
743 | newfix((output_ptr-buffer)/2, R_DA, da_operand); | |
744 | da_operand= 0; | |
745 | output_ptr += 4; | |
746 | break; | |
163107a1 SC |
747 | case CLASS_IMM: |
748 | { | |
749 | nib = 0; | |
750 | switch (c & ARG_MASK) | |
751 | { | |
752 | case ARG_IMM4: | |
587c4264 ILT |
753 | *output_ptr ++ = imm_operand->X_add_number; |
754 | imm_operand->X_add_number = 0; | |
755 | newfix((output_ptr-buffer)/2, R_IMM4L, imm_operand); | |
756 | break; | |
757 | case ARG_IMMNMINUS1: | |
758 | imm_operand->X_add_number --; | |
cfb48ce5 | 759 | newfix((output_ptr-buffer)/2, R_IMM4L, imm_operand); |
163107a1 SC |
760 | *output_ptr++ = 0; |
761 | break; | |
163107a1 | 762 | case ARG_IMM8: |
cfb48ce5 | 763 | newfix((output_ptr-buffer)/2, R_IMM8, imm_operand); |
163107a1 SC |
764 | *output_ptr++ = 0; |
765 | *output_ptr++ = 0; | |
766 | ||
587c4264 ILT |
767 | case ARG_NIM16: |
768 | imm_operand->X_add_number = - imm_operand->X_add_number; | |
769 | newfix((output_ptr-buffer)/2, R_DA, imm_operand); | |
163107a1 SC |
770 | *output_ptr++ = 0; |
771 | *output_ptr++ = 0; | |
772 | *output_ptr++ = 0; | |
773 | *output_ptr++ = 0; | |
774 | break; | |
775 | ||
587c4264 ILT |
776 | case ARG_IMM16: |
777 | { | |
778 | int n = imm_operand->X_add_number ; | |
779 | imm_operand->X_add_number = 0; | |
780 | newfix((output_ptr-buffer)/2, R_DA, imm_operand); | |
781 | *output_ptr++ = n>>24; | |
782 | *output_ptr++ = n>>16; | |
783 | *output_ptr++ = n>>8; | |
784 | *output_ptr++ = n; | |
785 | } | |
786 | ||
787 | break; | |
788 | ||
163107a1 | 789 | case ARG_IMM32: |
cfb48ce5 | 790 | newfix((output_ptr-buffer)/2, R_IMM32, imm_operand); |
163107a1 SC |
791 | *output_ptr++ = 0; |
792 | *output_ptr++ = 0; | |
793 | *output_ptr++ = 0; | |
794 | *output_ptr++ = 0; | |
795 | ||
796 | *output_ptr++ = 0; | |
797 | *output_ptr++ = 0; | |
798 | *output_ptr++ = 0; | |
799 | *output_ptr++ = 0; | |
800 | ||
163107a1 SC |
801 | break; |
802 | ||
803 | default: | |
804 | abort(); | |
805 | ||
806 | ||
807 | } | |
808 | } | |
809 | } | |
810 | } | |
811 | ||
812 | /* Copy from the nibble buffer into the frag */ | |
813 | ||
814 | { | |
587c4264 | 815 | int length = (output_ptr - buffer) / 2 ; |
163107a1 | 816 | char *src = buffer; |
587c4264 ILT |
817 | char *fragp = frag_more(length); |
818 | frag_wane(frag_now); | |
819 | frag_new(0); | |
163107a1 SC |
820 | while (src < output_ptr) |
821 | { | |
822 | *fragp = (src[0] << 4) | src[1]; | |
823 | src+=2; | |
824 | fragp++; | |
825 | } | |
826 | ||
827 | ||
828 | } | |
829 | ||
830 | } | |
831 | ||
832 | /* This is the guts of the machine-dependent assembler. STR points to a | |
833 | machine dependent instruction. This funciton is supposed to emit | |
834 | the frags/bytes it assembles to. | |
835 | */ | |
836 | ||
837 | ||
838 | ||
839 | void | |
840 | DEFUN(md_assemble,(str), | |
841 | char *str) | |
842 | { | |
843 | char *op_start; | |
844 | char *op_end; | |
845 | unsigned int i; | |
587c4264 | 846 | struct z8k_op operand[3]; |
163107a1 SC |
847 | opcode_entry_type *opcode; |
848 | opcode_entry_type * prev_opcode; | |
849 | ||
850 | char *dot = 0; | |
851 | char c; | |
852 | /* Drop leading whitespace */ | |
853 | while (*str == ' ') | |
854 | str++; | |
855 | ||
856 | /* find the op code end */ | |
857 | for (op_start = op_end = str; | |
858 | *op_end != 0 && *op_end != ' '; | |
859 | op_end ++) | |
860 | { | |
861 | } | |
862 | ||
863 | ; | |
864 | ||
865 | if (op_end == op_start) | |
866 | { | |
867 | as_bad("can't find opcode "); | |
868 | } | |
869 | c = *op_end; | |
870 | ||
871 | *op_end = 0; | |
872 | ||
873 | opcode = (opcode_entry_type *) hash_find(opcode_hash_control, | |
874 | op_start); | |
875 | ||
876 | if (opcode == NULL) | |
877 | { | |
878 | as_bad("unknown opcode"); | |
879 | return; | |
880 | } | |
881 | ||
882 | ||
883 | input_line_pointer = get_operands(opcode, op_end, | |
884 | operand); | |
885 | *op_end = c; | |
886 | prev_opcode = opcode; | |
887 | ||
888 | opcode = get_specific(opcode, operand); | |
889 | ||
890 | if (opcode == 0) | |
891 | { | |
892 | /* Couldn't find an opcode which matched the operands */ | |
893 | char *where =frag_more(2); | |
894 | where[0] = 0x0; | |
895 | where[1] = 0x0; | |
896 | ||
cfb48ce5 | 897 | as_bad("Can't find opcode to match operands"); |
163107a1 SC |
898 | return; |
899 | } | |
900 | ||
901 | build_bytes(opcode, operand); | |
902 | } | |
903 | ||
904 | ||
905 | void | |
906 | DEFUN(tc_crawl_symbol_chain, (headers), | |
907 | object_headers *headers) | |
908 | { | |
909 | printf("call to tc_crawl_symbol_chain \n"); | |
910 | } | |
911 | ||
912 | symbolS *DEFUN(md_undefined_symbol,(name), | |
913 | char *name) | |
914 | { | |
915 | return 0; | |
916 | } | |
917 | ||
918 | void | |
919 | DEFUN(tc_headers_hook,(headers), | |
920 | object_headers *headers) | |
921 | { | |
922 | printf("call to tc_headers_hook \n"); | |
923 | } | |
924 | void | |
925 | DEFUN_VOID(md_end) | |
926 | { | |
927 | } | |
928 | ||
929 | /* Various routines to kill one day */ | |
930 | /* Equal to MAX_PRECISION in atof-ieee.c */ | |
931 | #define MAX_LITTLENUMS 6 | |
932 | ||
933 | /* Turn a string in input_line_pointer into a floating point constant of type | |
934 | type, and store the appropriate bytes in *litP. The number of LITTLENUMS | |
935 | emitted is stored in *sizeP . An error message is returned, or NULL on OK. | |
936 | */ | |
937 | char * | |
938 | md_atof(type,litP,sizeP) | |
939 | char type; | |
940 | char *litP; | |
941 | int *sizeP; | |
942 | { | |
943 | int prec; | |
944 | LITTLENUM_TYPE words[MAX_LITTLENUMS]; | |
945 | LITTLENUM_TYPE *wordP; | |
946 | char *t; | |
947 | char *atof_ieee(); | |
948 | ||
949 | switch(type) { | |
950 | case 'f': | |
951 | case 'F': | |
952 | case 's': | |
953 | case 'S': | |
954 | prec = 2; | |
955 | break; | |
956 | ||
957 | case 'd': | |
958 | case 'D': | |
959 | case 'r': | |
960 | case 'R': | |
961 | prec = 4; | |
962 | break; | |
963 | ||
964 | case 'x': | |
965 | case 'X': | |
966 | prec = 6; | |
967 | break; | |
968 | ||
969 | case 'p': | |
970 | case 'P': | |
971 | prec = 6; | |
972 | break; | |
973 | ||
974 | default: | |
975 | *sizeP=0; | |
976 | return "Bad call to MD_ATOF()"; | |
977 | } | |
978 | t=atof_ieee(input_line_pointer,type,words); | |
979 | if(t) | |
980 | input_line_pointer=t; | |
981 | ||
982 | *sizeP=prec * sizeof(LITTLENUM_TYPE); | |
983 | for(wordP=words;prec--;) { | |
984 | md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE)); | |
985 | litP+=sizeof(LITTLENUM_TYPE); | |
986 | } | |
987 | return ""; /* Someone should teach Dean about null pointers */ | |
988 | } | |
989 | ||
990 | int | |
991 | md_parse_option(argP, cntP, vecP) | |
992 | char **argP; | |
993 | int *cntP; | |
994 | char ***vecP; | |
995 | ||
996 | { | |
997 | return 0; | |
998 | ||
999 | } | |
1000 | ||
1001 | int md_short_jump_size; | |
1002 | ||
1003 | void tc_aout_fix_to_chars () { printf("call to tc_aout_fix_to_chars \n"); | |
1004 | abort(); } | |
1005 | void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol) | |
1006 | char *ptr; | |
1007 | long from_addr; | |
1008 | long to_addr; | |
1009 | fragS *frag; | |
1010 | symbolS *to_symbol; | |
1011 | { | |
1012 | as_fatal("failed sanity check."); | |
1013 | } | |
1014 | ||
1015 | void | |
1016 | md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol) | |
1017 | char *ptr; | |
1018 | long from_addr, to_addr; | |
1019 | fragS *frag; | |
1020 | symbolS *to_symbol; | |
1021 | { | |
1022 | as_fatal("failed sanity check."); | |
1023 | } | |
1024 | ||
1025 | void | |
1026 | md_convert_frag(headers, fragP) | |
1027 | object_headers *headers; | |
1028 | fragS * fragP; | |
1029 | ||
1030 | { printf("call to md_convert_frag \n"); abort(); } | |
1031 | ||
1032 | long | |
1033 | DEFUN(md_section_align,(seg, size), | |
1034 | segT seg AND | |
1035 | long size) | |
1036 | { | |
1037 | return((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg])); | |
1038 | ||
1039 | } | |
1040 | ||
1041 | void | |
1042 | md_apply_fix(fixP, val) | |
1043 | fixS *fixP; | |
1044 | long val; | |
1045 | { | |
1046 | char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; | |
1047 | ||
cfb48ce5 SC |
1048 | switch(fixP->fx_r_type) { |
1049 | case R_IMM4L: | |
1050 | buf[0] = (buf[0] & 0xf0) | ((buf[0] + val) & 0xf); | |
163107a1 | 1051 | break; |
cfb48ce5 | 1052 | |
587c4264 ILT |
1053 | case R_JR: |
1054 | ||
1055 | *buf++= val; | |
1056 | /* if (val != 0) abort();*/ | |
1057 | break; | |
1058 | ||
1059 | ||
cfb48ce5 SC |
1060 | case R_IMM8: |
1061 | buf[0] += val; | |
1062 | break; | |
587c4264 | 1063 | break; |
cfb48ce5 | 1064 | case R_DA: |
163107a1 SC |
1065 | *buf++=(val>>8); |
1066 | *buf++=val; | |
1067 | break; | |
cfb48ce5 | 1068 | case R_IMM32: |
163107a1 SC |
1069 | *buf++=(val>>24); |
1070 | *buf++=(val>>16); | |
1071 | *buf++=(val>>8); | |
1072 | *buf++=val; | |
1073 | break; | |
cfb48ce5 SC |
1074 | case R_DA | R_SEG: |
1075 | *buf++ = (val>>16); | |
1076 | *buf++ = 0x00; | |
1077 | *buf++ = (val>>8); | |
1078 | *buf++ = val; | |
1079 | break; | |
163107a1 SC |
1080 | default: |
1081 | abort(); | |
1082 | ||
1083 | } | |
1084 | } | |
1085 | ||
1086 | void DEFUN(md_operand, (expressionP),expressionS *expressionP) | |
1087 | { } | |
1088 | ||
1089 | int md_long_jump_size; | |
1090 | int | |
1091 | md_estimate_size_before_relax(fragP, segment_type) | |
1092 | register fragS *fragP; | |
1093 | register segT segment_type; | |
1094 | { | |
1095 | printf("call tomd_estimate_size_before_relax \n"); abort(); } | |
1096 | /* Put number into target byte order */ | |
1097 | ||
1098 | void DEFUN(md_number_to_chars,(ptr, use, nbytes), | |
1099 | char *ptr AND | |
1100 | long use AND | |
1101 | int nbytes) | |
1102 | { | |
1103 | switch (nbytes) { | |
1104 | case 4: *ptr++ = (use >> 24) & 0xff; | |
1105 | case 3: *ptr++ = (use >> 16) & 0xff; | |
1106 | case 2: *ptr++ = (use >> 8) & 0xff; | |
1107 | case 1: *ptr++ = (use >> 0) & 0xff; | |
1108 | break; | |
1109 | default: | |
1110 | abort(); | |
1111 | } | |
1112 | } | |
1113 | long md_pcrel_from(fixP) | |
1114 | fixS *fixP; { abort(); } | |
1115 | ||
1116 | void tc_coff_symbol_emit_hook() { } | |
1117 | ||
1118 | ||
1119 | void tc_reloc_mangle(fix_ptr, intr, base) | |
1120 | fixS *fix_ptr; | |
1121 | struct internal_reloc *intr; | |
1122 | bfd_vma base; | |
1123 | ||
1124 | { | |
1125 | symbolS *symbol_ptr; | |
1126 | ||
1127 | symbol_ptr = fix_ptr->fx_addsy; | |
1128 | ||
1129 | /* If this relocation is attached to a symbol then it's ok | |
1130 | to output it */ | |
1131 | if (fix_ptr->fx_r_type == RELOC_32) { | |
1132 | /* cons likes to create reloc32's whatever the size of the reloc.. | |
1133 | */ | |
1134 | switch (fix_ptr->fx_size) | |
1135 | { | |
1136 | ||
1137 | case 2: | |
587c4264 | 1138 | intr->r_type = R_DA; |
163107a1 SC |
1139 | break; |
1140 | case 1: | |
1141 | intr->r_type = R_IMM8; | |
1142 | break; | |
1143 | default: | |
1144 | abort(); | |
1145 | ||
1146 | } | |
1147 | ||
1148 | } | |
1149 | else { | |
1150 | intr->r_type = fix_ptr->fx_r_type; | |
1151 | } | |
1152 | ||
1153 | intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where +base; | |
1154 | intr->r_offset = fix_ptr->fx_offset; | |
1155 | ||
1156 | if (symbol_ptr) | |
1157 | intr->r_symndx = symbol_ptr->sy_number; | |
1158 | else | |
1159 | intr->r_symndx = -1; | |
1160 | ||
1161 | ||
1162 | } | |
1163 | ||
1164 |