3a69b3ac |
1 | /* m68k.c All the m68020 specific stuff in one convenient, huge, |
2 | slow to compile, easy to find file. |
3 | Copyright (C) 1987, 1991 Free Software Foundation, Inc. |
4 | |
5 | This file is part of GAS, the GNU Assembler. |
6 | |
7 | GAS is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 1, or (at your option) |
10 | any later version. |
11 | |
12 | GAS is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GAS; see the file COPYING. If not, write to |
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
20 | |
21 | #include <ctype.h> |
22 | |
23 | #include "as.h" |
24 | |
25 | #include "obstack.h" |
26 | |
27 | /* note that this file includes real declarations and thus can only be included by one source file per executable. */ |
28 | #include "m68k-opcode.h" |
29 | |
30 | /* This array holds the chars that always start a comment. If the |
31 | pre-processor is disabled, these aren't very useful */ |
32 | const char comment_chars[] = "|"; |
33 | |
34 | /* This array holds the chars that only start a comment at the beginning of |
35 | a line. If the line seems to have the form '# 123 filename' |
36 | .line and .file directives will appear in the pre-processed output */ |
37 | /* Note that input_file.c hand checks for '#' at the beginning of the |
38 | first line of the input file. This is because the compiler outputs |
39 | #NO_APP at the beginning of its output. */ |
40 | /* Also note that comments like this one will always work. */ |
41 | const char line_comment_chars[] = "#"; |
42 | |
43 | /* Chars that can be used to separate mant from exp in floating point nums */ |
44 | const char EXP_CHARS[] = "eE"; |
45 | |
46 | /* Chars that mean this number is a floating point constant */ |
47 | /* As in 0f12.456 */ |
48 | /* or 0d1.2345e12 */ |
49 | |
50 | const char FLT_CHARS[] = "rRsSfFdDxXeEpP"; |
51 | |
52 | /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be |
53 | changed in read.c . Ideally it shouldn't have to know about it at all, |
54 | but nothing is ideal around here. |
55 | */ |
56 | |
57 | int md_reloc_size = 8; /* Size of relocation record */ |
58 | |
59 | /* Its an arbitrary name: This means I don't approve of it */ |
60 | /* See flames below */ |
61 | static struct obstack robyn; |
62 | |
63 | #define TAB(x,y) (((x)<<2)+(y)) |
64 | #define TABTYPE(xy) ((xy) >> 2) |
65 | #define BYTE 0 |
66 | #define SHORT 1 |
67 | #define LONG 2 |
68 | #define SZ_UNDEF 3 |
69 | |
70 | #define BRANCH 1 |
71 | #define FBRANCH 2 |
72 | #define PCREL 3 |
73 | #define BCC68000 4 |
74 | #define DBCC 5 |
75 | #define PCLEA 6 |
76 | |
77 | struct m68k_exp { |
78 | char *e_beg; |
79 | char *e_end; |
80 | expressionS e_exp; |
81 | short e_siz; /* 0== default 1==short/byte 2==word 3==long */ |
82 | }; |
83 | |
84 | /* Internal form of an operand. */ |
85 | struct m68k_op { |
86 | char *error; /* Couldn't parse it */ |
87 | int mode; /* What mode this instruction is in. */ |
88 | unsigned long reg; /* Base register */ |
89 | struct m68k_exp *con1; |
90 | int ireg; /* Index register */ |
91 | int isiz; /* 0==unspec 1==byte(?) 2==short 3==long */ |
92 | int imul; /* Multipy ireg by this (1,2,4,or 8) */ |
93 | struct m68k_exp *con2; |
94 | }; |
95 | |
96 | /* internal form of a 68020 instruction */ |
97 | struct m68_it { |
98 | char *error; |
99 | char *args; /* list of opcode info */ |
100 | int numargs; |
101 | |
102 | int numo; /* Number of shorts in opcode */ |
103 | short opcode[11]; |
104 | |
105 | struct m68k_op operands[6]; |
106 | |
107 | int nexp; /* number of exprs in use */ |
108 | struct m68k_exp exprs[4]; |
109 | |
110 | int nfrag; /* Number of frags we have to produce */ |
111 | struct { |
112 | int fragoff; /* Where in the current opcode[] the frag ends */ |
113 | symbolS *fadd; |
114 | long foff; |
115 | int fragty; |
116 | } fragb[4]; |
117 | |
118 | int nrel; /* Num of reloc strucs in use */ |
119 | struct { |
120 | int n; |
121 | symbolS *add, |
122 | *sub; |
123 | long off; |
124 | char wid; |
125 | char pcrel; |
126 | } reloc[5]; /* Five is enough??? */ |
127 | }; |
128 | |
129 | struct m68_it the_ins; /* the instruction being assembled */ |
130 | |
131 | |
132 | /* Macros for adding things to the m68_it struct */ |
133 | |
134 | #define addword(w) the_ins.opcode[the_ins.numo++]=(w) |
135 | |
136 | /* Like addword, but goes BEFORE general operands */ |
137 | #define insop(w) {int z;\ |
138 | for(z=the_ins.numo;z>opcode->m_codenum;--z)\ |
139 | the_ins.opcode[z]=the_ins.opcode[z-1];\ |
140 | for(z=0;z<the_ins.nrel;z++)\ |
141 | the_ins.reloc[z].n+=2;\ |
142 | the_ins.opcode[opcode->m_codenum]=w;\ |
143 | the_ins.numo++;\ |
144 | } |
145 | |
146 | |
147 | #define add_exp(beg,end) (\ |
148 | the_ins.exprs[the_ins.nexp].e_beg=beg,\ |
149 | the_ins.exprs[the_ins.nexp].e_end=end,\ |
150 | &the_ins.exprs[the_ins.nexp++]\ |
151 | ) |
152 | |
153 | |
154 | /* The numo+1 kludge is so we can hit the low order byte of the prev word. Blecch*/ |
155 | #define add_fix(width,exp,pc_rel) {\ |
156 | the_ins.reloc[the_ins.nrel].n= ((width)=='B') ? (the_ins.numo*2-1) : \ |
157 | (((width)=='b') ? ((the_ins.numo-1)*2) : (the_ins.numo*2));\ |
158 | the_ins.reloc[the_ins.nrel].add=adds((exp));\ |
159 | the_ins.reloc[the_ins.nrel].sub=subs((exp));\ |
160 | the_ins.reloc[the_ins.nrel].off=offs((exp));\ |
161 | the_ins.reloc[the_ins.nrel].wid=width;\ |
162 | the_ins.reloc[the_ins.nrel++].pcrel=pc_rel;\ |
163 | } |
164 | |
165 | #define add_frag(add,off,type) {\ |
166 | the_ins.fragb[the_ins.nfrag].fragoff=the_ins.numo;\ |
167 | the_ins.fragb[the_ins.nfrag].fadd=add;\ |
168 | the_ins.fragb[the_ins.nfrag].foff=off;\ |
169 | the_ins.fragb[the_ins.nfrag++].fragty=type;\ |
170 | } |
171 | |
172 | #define isvar(exp) ((exp) && (adds(exp) || subs(exp))) |
173 | |
174 | #define seg(exp) ((exp)->e_exp.X_seg) |
175 | #define adds(exp) ((exp)->e_exp.X_add_symbol) |
176 | #define subs(exp) ((exp)->e_exp.X_subtract_symbol) |
177 | #define offs(exp) ((exp)->e_exp.X_add_number) |
178 | |
179 | |
180 | struct m68_incant { |
181 | char *m_operands; |
182 | unsigned long m_opcode; |
183 | short m_opnum; |
184 | short m_codenum; |
185 | struct m68_incant *m_next; |
186 | }; |
187 | |
188 | #define getone(x) ((((x)->m_opcode)>>16)&0xffff) |
189 | #define gettwo(x) (((x)->m_opcode)&0xffff) |
190 | |
191 | |
192 | #ifdef __STDC__ |
193 | |
194 | static char *crack_operand(char *str, struct m68k_op *opP); |
195 | static int get_num(struct m68k_exp *exp, int ok); |
196 | static int get_regs(int i, char *str, struct m68k_op *opP); |
197 | static int reverse_16_bits(int in); |
198 | static int reverse_8_bits(int in); |
199 | static int try_index(char **s, struct m68k_op *opP); |
200 | static void install_gen_operand(int mode, int val); |
201 | static void install_operand(int mode, int val); |
202 | static void s_bss(void); |
203 | static void s_data1(void); |
204 | static void s_data2(void); |
205 | static void s_even(void); |
206 | static void s_proc(void); |
207 | |
208 | #else /* __STDC__ */ |
209 | |
210 | static char *crack_operand(); |
211 | static int get_num(); |
212 | static int get_regs(); |
213 | static int reverse_16_bits(); |
214 | static int reverse_8_bits(); |
215 | static int try_index(); |
216 | static void install_gen_operand(); |
217 | static void install_operand(); |
218 | static void s_bss(); |
219 | static void s_data1(); |
220 | static void s_data2(); |
221 | static void s_even(); |
222 | static void s_proc(); |
223 | |
224 | #endif /* __STDC__ */ |
225 | |
226 | /* BCC68000 is for patching in an extra jmp instruction for long offsets |
227 | on the 68000. The 68000 doesn't support long branches with branchs */ |
228 | |
229 | /* This table desribes how you change sizes for the various types of variable |
230 | size expressions. This version only supports two kinds. */ |
231 | |
232 | /* Note that calls to frag_var need to specify the maximum expansion needed */ |
233 | /* This is currently 10 bytes for DBCC */ |
234 | |
235 | /* The fields are: |
236 | How far Forward this mode will reach: |
237 | How far Backward this mode will reach: |
238 | How many bytes this mode will add to the size of the frag |
239 | Which mode to go to if the offset won't fit in this one |
240 | */ |
241 | const relax_typeS |
242 | md_relax_table[] = { |
243 | { 1, 1, 0, 0 }, /* First entries aren't used */ |
244 | { 1, 1, 0, 0 }, /* For no good reason except */ |
245 | { 1, 1, 0, 0 }, /* that the VAX doesn't either */ |
246 | { 1, 1, 0, 0 }, |
247 | |
248 | { (127), (-128), 0, TAB(BRANCH,SHORT)}, |
249 | { (32767), (-32768), 2, TAB(BRANCH,LONG) }, |
250 | { 0, 0, 4, 0 }, |
251 | { 1, 1, 0, 0 }, |
252 | |
253 | { 1, 1, 0, 0 }, /* FBRANCH doesn't come BYTE */ |
254 | { (32767), (-32768), 2, TAB(FBRANCH,LONG)}, |
255 | { 0, 0, 4, 0 }, |
256 | { 1, 1, 0, 0 }, |
257 | |
258 | { 1, 1, 0, 0 }, /* PCREL doesn't come BYTE */ |
259 | { (32767), (-32768), 2, TAB(PCREL,LONG)}, |
260 | { 0, 0, 4, 0 }, |
261 | { 1, 1, 0, 0 }, |
262 | |
263 | { (127), (-128), 0, TAB(BCC68000,SHORT)}, |
264 | { (32767), (-32768), 2, TAB(BCC68000,LONG) }, |
265 | { 0, 0, 6, 0 }, /* jmp long space */ |
266 | { 1, 1, 0, 0 }, |
267 | |
268 | { 1, 1, 0, 0 }, /* DBCC doesn't come BYTE */ |
269 | { (32767), (-32768), 2, TAB(DBCC,LONG) }, |
270 | { 0, 0, 10, 0 }, /* bra/jmp long space */ |
271 | { 1, 1, 0, 0 }, |
272 | |
273 | { 1, 1, 0, 0 }, /* PCLEA doesn't come BYTE */ |
274 | { 32767, -32768, 2, TAB(PCLEA,LONG) }, |
275 | { 0, 0, 6, 0 }, |
276 | { 1, 1, 0, 0 }, |
277 | |
278 | }; |
279 | |
280 | /* These are the machine dependent pseudo-ops. These are included so |
281 | the assembler can work on the output from the SUN C compiler, which |
282 | generates these. |
283 | */ |
284 | |
285 | /* This table describes all the machine specific pseudo-ops the assembler |
286 | has to support. The fields are: |
287 | pseudo-op name without dot |
288 | function to call to execute this pseudo-op |
289 | Integer arg to pass to the function |
290 | */ |
291 | const pseudo_typeS md_pseudo_table[] = { |
292 | { "data1", s_data1, 0 }, |
293 | { "data2", s_data2, 0 }, |
294 | { "bss", s_bss, 0 }, |
295 | { "even", s_even, 0 }, |
296 | { "skip", s_space, 0 }, |
297 | { "proc", s_proc, 0 }, |
298 | { 0, 0, 0 } |
299 | }; |
300 | |
301 | |
302 | /* #define isbyte(x) ((x)>=-128 && (x)<=127) */ |
303 | /* #define isword(x) ((x)>=-32768 && (x)<=32767) */ |
304 | |
305 | #define issbyte(x) ((x)>=-128 && (x)<=127) |
306 | #define isubyte(x) ((x)>=0 && (x)<=255) |
307 | #define issword(x) ((x)>=-32768 && (x)<=32767) |
308 | #define isuword(x) ((x)>=0 && (x)<=65535) |
309 | |
310 | #define isbyte(x) ((x)>=-128 && (x)<=255) |
311 | #define isword(x) ((x)>=-32768 && (x)<=65535) |
312 | #define islong(x) (1) |
313 | |
314 | extern char *input_line_pointer; |
315 | |
316 | /* Operands we can parse: (And associated modes) |
317 | |
318 | numb: 8 bit num |
319 | numw: 16 bit num |
320 | numl: 32 bit num |
321 | dreg: data reg 0-7 |
322 | reg: address or data register |
323 | areg: address register |
324 | apc: address register, PC, ZPC or empty string |
325 | num: 16 or 32 bit num |
326 | num2: like num |
327 | sz: w or l if omitted, l assumed |
328 | scale: 1 2 4 or 8 if omitted, 1 assumed |
329 | |
330 | 7.4 IMMED #num --> NUM |
331 | 0.? DREG dreg --> dreg |
332 | 1.? AREG areg --> areg |
333 | 2.? AINDR areg@ --> *(areg) |
334 | 3.? AINC areg@+ --> *(areg++) |
335 | 4.? ADEC areg@- --> *(--areg) |
336 | 5.? AOFF apc@(numw) --> *(apc+numw) -- empty string and ZPC not allowed here |
337 | 6.? AINDX apc@(num,reg:sz:scale) --> *(apc+num+reg*scale) |
338 | 6.? AINDX apc@(reg:sz:scale) --> same, with num=0 |
339 | 6.? APODX apc@(num)@(num2,reg:sz:scale) --> *(*(apc+num)+num2+reg*scale) |
340 | 6.? APODX apc@(num)@(reg:sz:scale) --> same, with num2=0 |
341 | 6.? AMIND apc@(num)@(num2) --> *(*(apc+num)+num2) (previous mode without an index reg) |
342 | 6.? APRDX apc@(num,reg:sz:scale)@(num2) --> *(*(apc+num+reg*scale)+num2) |
343 | 6.? APRDX apc@(reg:sz:scale)@(num2) --> same, with num=0 |
344 | 7.0 ABSL num:sz --> *(num) |
345 | num --> *(num) (sz L assumed) |
346 | *** MSCR otherreg --> Magic |
347 | With -l option |
348 | 5.? AOFF apc@(num) --> *(apc+num) -- empty string and ZPC not allowed here still |
349 | |
350 | examples: |
351 | #foo #0x35 #12 |
352 | d2 |
353 | a4 |
354 | a3@ |
355 | a5@+ |
356 | a6@- |
357 | a2@(12) pc@(14) |
358 | a1@(5,d2:w:1) @(45,d6:l:4) |
359 | pc@(a2) @(d4) |
360 | etc . . . |
361 | |
362 | |
363 | #name@(numw) -->turn into PC rel mode |
364 | apc@(num8,reg:sz:scale) --> *(apc+num8+reg*scale) |
365 | |
366 | */ |
367 | |
368 | #define IMMED 1 |
369 | #define DREG 2 |
370 | #define AREG 3 |
371 | #define AINDR 4 |
372 | #define ADEC 5 |
373 | #define AINC 6 |
374 | #define AOFF 7 |
375 | #define AINDX 8 |
376 | #define APODX 9 |
377 | #define AMIND 10 |
378 | #define APRDX 11 |
379 | #define ABSL 12 |
380 | #define MSCR 13 |
381 | #define REGLST 14 |
382 | |
383 | #define FAIL 0 |
384 | #define OK 1 |
385 | |
386 | /* DATA and ADDR have to be contiguous, so that reg-DATA gives 0-7==data reg, |
387 | 8-15==addr reg for operands that take both types */ |
388 | #define DATA 1 /* 1- 8 == data registers 0-7 */ |
389 | #define ADDR (DATA+8) /* 9-16 == address regs 0-7 */ |
390 | #define FPREG (ADDR+8) /* 17-24 Eight FP registers */ |
391 | #define COPNUM (FPREG+8) /* 25-32 Co-processor #1-#8 */ |
392 | |
393 | #define PC (COPNUM+8) /* 33 Program counter */ |
394 | #define ZPC (PC+1) /* 34 Hack for Program space, but 0 addressing */ |
395 | #define SR (ZPC+1) /* 35 Status Reg */ |
396 | #define CCR (SR+1) /* 36 Condition code Reg */ |
397 | |
398 | /* These have to be in order for the movec instruction to work. */ |
399 | #define USP (CCR+1) /* 37 User Stack Pointer */ |
400 | #define ISP (USP+1) /* 38 Interrupt stack pointer */ |
401 | #define SFC (ISP+1) /* 39 */ |
402 | #define DFC (SFC+1) /* 40 */ |
403 | #define CACR (DFC+1) /* 41 */ |
404 | #define VBR (CACR+1) /* 42 */ |
405 | #define CAAR (VBR+1) /* 43 */ |
406 | #define MSP (CAAR+1) /* 44 */ |
407 | |
408 | #define FPI (MSP+1) /* 45 */ |
409 | #define FPS (FPI+1) /* 46 */ |
410 | #define FPC (FPS+1) /* 47 */ |
411 | /* |
412 | * these defines should be in m68k.c but |
413 | * i put them here to keep all the m68851 stuff |
414 | * together -rab |
415 | * JF--Make sure these #s don't clash with the ones in m68k.c |
416 | * That would be BAD. |
417 | */ |
418 | #define TC (FPC+1) /* 48 */ |
419 | #define DRP (TC+1) /* 49 */ |
420 | #define SRP (DRP+1) /* 50 */ |
421 | #define CRP (SRP+1) /* 51 */ |
422 | #define CAL (CRP+1) /* 52 */ |
423 | #define VAL (CAL+1) /* 53 */ |
424 | #define SCC (VAL+1) /* 54 */ |
425 | #define AC (SCC+1) /* 55 */ |
426 | #define BAD (AC+1) /* 56,57,58,59, 60,61,62,63 */ |
427 | #define BAC (BAD+8) /* 64,65,66,67, 68,69,70,71 */ |
428 | #define PSR (BAC+8) /* 72 */ |
429 | #define PCSR (PSR+1) /* 73 */ |
430 | |
431 | |
432 | /* Note that COPNUM==processor #1 -- COPNUM+7==#8, which stores as 000 */ |
433 | /* I think. . . */ |
434 | |
435 | #define SP ADDR+7 |
436 | |
437 | /* JF these tables here are for speed at the expense of size */ |
438 | /* You can replace them with the #if 0 versions if you really |
439 | need space and don't mind it running a bit slower */ |
440 | |
441 | static char mklower_table[256]; |
442 | #define mklower(c) (mklower_table[(unsigned char)(c)]) |
443 | static char notend_table[256]; |
444 | static char alt_notend_table[256]; |
445 | #define notend(s) ( !(notend_table[(unsigned char)(*s)] || (*s==':' &&\ |
446 | alt_notend_table[(unsigned char)(s[1])]))) |
447 | |
448 | #if 0 |
449 | #define mklower(c) (isupper(c) ? tolower(c) : c) |
450 | #endif |
451 | |
452 | |
453 | /* JF modified this to handle cases where the first part of a symbol name |
454 | looks like a register */ |
455 | |
456 | int |
457 | m68k_reg_parse(ccp) |
458 | register char **ccp; |
459 | { |
460 | register char c1, |
461 | c2, |
462 | c3, |
463 | c4; |
464 | register int n = 0, |
465 | ret = FAIL; |
466 | |
467 | c1=mklower(ccp[0][0]); |
468 | #ifdef REGISTER_PREFIX |
469 | if(c1!=REGISTER_PREFIX) |
470 | return FAIL; |
471 | c1=mklower(ccp[0][1]); |
472 | c2=mklower(ccp[0][2]); |
473 | c3=mklower(ccp[0][3]); |
474 | c4=mklower(ccp[0][4]); |
475 | #else |
476 | c2=mklower(ccp[0][1]); |
477 | c3=mklower(ccp[0][2]); |
478 | c4=mklower(ccp[0][3]); |
479 | #endif |
480 | switch(c1) { |
481 | case 'a': |
482 | if(c2>='0' && c2<='7') { |
483 | n=2; |
484 | ret=ADDR+c2-'0'; |
485 | } |
486 | #ifdef m68851 |
487 | else if (c2 == 'c') { |
488 | n = 2; |
489 | ret = AC; |
490 | } |
491 | #endif |
492 | break; |
493 | #ifdef m68851 |
494 | case 'b': |
495 | if (c2 == 'a') { |
496 | if (c3 == 'd') { |
497 | if (c4 >= '0' && c4 <= '7') { |
498 | n = 4; |
499 | ret = BAD + c4 - '0'; |
500 | } |
501 | } |
502 | if (c3 == 'c') { |
503 | if (c4 >= '0' && c4 <= '7') { |
504 | n = 4; |
505 | ret = BAC + c4 - '0'; |
506 | } |
507 | } |
508 | } |
509 | break; |
510 | #endif |
511 | case 'c': |
512 | #ifdef m68851 |
513 | if (c2 == 'a' && c3 == 'l') { |
514 | n = 3; |
515 | ret = CAL; |
516 | } else |
517 | #endif |
518 | /* This supports both CCR and CC as the ccr reg. */ |
519 | if(c2=='c' && c3=='r') { |
520 | n=3; |
521 | ret = CCR; |
522 | } else if(c2=='c') { |
523 | n=2; |
524 | ret = CCR; |
525 | } else if(c2=='a' && (c3=='a' || c3=='c') && c4=='r') { |
526 | n=4; |
527 | ret = c3=='a' ? CAAR : CACR; |
528 | } |
529 | #ifdef m68851 |
530 | else if (c2 == 'r' && c3 == 'p') { |
531 | n = 3; |
532 | ret = (CRP); |
533 | } |
534 | #endif |
535 | break; |
536 | case 'd': |
537 | if(c2>='0' && c2<='7') { |
538 | n=2; |
539 | ret = DATA+c2-'0'; |
540 | } else if(c2=='f' && c3=='c') { |
541 | n=3; |
542 | ret = DFC; |
543 | } |
544 | #ifdef m68851 |
545 | else if (c2 == 'r' && c3 == 'p') { |
546 | n = 3; |
547 | ret = (DRP); |
548 | } |
549 | #endif |
550 | break; |
551 | case 'f': |
552 | if(c2=='p') { |
553 | if(c3>='0' && c3<='7') { |
554 | n=3; |
555 | ret = FPREG+c3-'0'; |
556 | if(c4==':') |
557 | ccp[0][3]=','; |
558 | } else if(c3=='i') { |
559 | n=3; |
560 | ret = FPI; |
561 | } else if(c3=='s') { |
562 | n= (c4 == 'r' ? 4 : 3); |
563 | ret = FPS; |
564 | } else if(c3=='c') { |
565 | n= (c4 == 'r' ? 4 : 3); |
566 | ret = FPC; |
567 | } |
568 | } |
569 | break; |
570 | case 'i': |
571 | if(c2=='s' && c3=='p') { |
572 | n=3; |
573 | ret = ISP; |
574 | } |
575 | break; |
576 | case 'm': |
577 | if(c2=='s' && c3=='p') { |
578 | n=3; |
579 | ret = MSP; |
580 | } |
581 | break; |
582 | case 'p': |
583 | if(c2=='c') { |
584 | #ifdef m68851 |
585 | if(c3 == 's' && c4=='r') { |
586 | n=4; |
587 | ret = (PCSR); |
588 | } else |
589 | #endif |
590 | { |
591 | n=2; |
592 | ret = PC; |
593 | } |
594 | } |
595 | #ifdef m68851 |
596 | else if (c2 == 's' && c3 == 'r') { |
597 | n = 3; |
598 | ret = (PSR); |
599 | } |
600 | #endif |
601 | break; |
602 | case 's': |
603 | #ifdef m68851 |
604 | if (c2 == 'c' && c3 == 'c') { |
605 | n = 3; |
606 | ret = (SCC); |
607 | } else if (c2 == 'r' && c3 == 'p') { |
608 | n = 3; |
609 | ret = (SRP); |
610 | } else |
611 | #endif |
612 | if(c2=='r') { |
613 | n=2; |
614 | ret = SR; |
615 | } else if(c2=='p') { |
616 | n=2; |
617 | ret = ADDR+7; |
618 | } else if(c2=='f' && c3=='c') { |
619 | n=3; |
620 | ret = SFC; |
621 | } |
622 | break; |
623 | #ifdef m68851 |
624 | case 't': |
625 | if(c2 == 'c') { |
626 | n=2; |
627 | ret=TC; |
628 | } |
629 | break; |
630 | #endif |
631 | case 'u': |
632 | if(c2=='s' && c3=='p') { |
633 | n=3; |
634 | ret = USP; |
635 | } |
636 | break; |
637 | case 'v': |
638 | #ifdef m68851 |
639 | if (c2 == 'a' && c3 == 'l') { |
640 | n = 3; |
641 | ret = (VAL); |
642 | } else |
643 | #endif |
644 | if(c2=='b' && c3=='r') { |
645 | n=3; |
646 | ret = VBR; |
647 | } |
648 | break; |
649 | case 'z': |
650 | if(c2=='p' && c3=='c') { |
651 | n=3; |
652 | ret = ZPC; |
653 | } |
654 | break; |
655 | default: |
656 | break; |
657 | } |
658 | if(n) { |
659 | #ifdef REGISTER_PREFIX |
660 | n++; |
661 | #endif |
662 | if(isalnum(ccp[0][n]) || ccp[0][n]=='_') |
663 | ret=FAIL; |
664 | else |
665 | ccp[0]+=n; |
666 | } else |
667 | ret = FAIL; |
668 | return ret; |
669 | } |
670 | |
671 | #define SKIP_WHITE() { str++; if(*str==' ') str++;} |
672 | |
673 | int |
674 | m68k_ip_op(str,opP) |
675 | char *str; |
676 | register struct m68k_op *opP; |
677 | { |
678 | char *strend; |
679 | long i; |
680 | |
681 | if(*str==' ') |
682 | str++; |
683 | /* Find the end of the string */ |
684 | if(!*str) { |
685 | /* Out of gas */ |
686 | opP->error="Missing operand"; |
687 | return FAIL; |
688 | } |
689 | for(strend=str;*strend;strend++) |
690 | ; |
691 | --strend; |
692 | |
693 | /* Guess what: A constant. Shar and enjoy */ |
694 | if(*str=='#') { |
695 | str++; |
696 | opP->con1=add_exp(str,strend); |
697 | opP->mode=IMMED; |
698 | return OK; |
699 | } |
700 | i=m68k_reg_parse(&str); |
701 | if((i==FAIL || *str!='\0') && *str!='@') { |
702 | char *stmp; |
703 | |
704 | if(i!=FAIL && (*str=='/' || *str=='-')) { |
705 | opP->mode=REGLST; |
706 | return get_regs(i,str,opP); |
707 | } |
708 | if((stmp=strchr(str,'@')) != '\0') { |
709 | opP->con1=add_exp(str,stmp-1); |
710 | if(stmp==strend) { |
711 | opP->mode=AINDX; |
712 | return OK; |
713 | } |
714 | stmp++; |
715 | if(*stmp++!='(' || *strend--!=')') { |
716 | opP->error="Malformed operand"; |
717 | return FAIL; |
718 | } |
719 | i=try_index(&stmp,opP); |
720 | opP->con2=add_exp(stmp,strend); |
721 | if(i==FAIL) opP->mode=AMIND; |
722 | else opP->mode=APODX; |
723 | return OK; |
724 | } |
725 | opP->mode=ABSL; |
726 | opP->con1=add_exp(str,strend); |
727 | return OK; |
728 | } |
729 | opP->reg=i; |
730 | if(*str=='\0') { |
731 | if(i>=DATA+0 && i<=DATA+7) |
732 | opP->mode=DREG; |
733 | else if(i>=ADDR+0 && i<=ADDR+7) |
734 | opP->mode=AREG; |
735 | else |
736 | opP->mode=MSCR; |
737 | return OK; |
738 | } |
739 | if((i<ADDR+0 || i>ADDR+7) && i!=PC && i!=ZPC && i!=FAIL) { /* Can't indirect off non address regs */ |
740 | opP->error="Invalid indirect register"; |
741 | return FAIL; |
742 | } |
743 | if(*str!='@') |
744 | abort(); |
745 | str++; |
746 | switch(*str) { |
747 | case '\0': |
748 | opP->mode=AINDR; |
749 | return OK; |
750 | case '-': |
751 | opP->mode=ADEC; |
752 | return OK; |
753 | case '+': |
754 | opP->mode=AINC; |
755 | return OK; |
756 | case '(': |
757 | str++; |
758 | break; |
759 | default: |
760 | opP->error="Junk after indirect"; |
761 | return FAIL; |
762 | } |
763 | /* Some kind of indexing involved. Lets find out how bad it is */ |
764 | i=try_index(&str,opP); |
765 | /* Didn't start with an index reg, maybe its offset or offset,reg */ |
766 | if(i==FAIL) { |
767 | char *beg_str; |
768 | |
769 | beg_str=str; |
770 | for(i=1;i;) { |
771 | switch(*str++) { |
772 | case '\0': |
773 | opP->error="Missing )"; |
774 | return FAIL; |
775 | case ',': i=0; break; |
776 | case '(': i++; break; |
777 | case ')': --i; break; |
778 | } |
779 | } |
780 | /* if(str[-3]==':') { |
781 | int siz; |
782 | |
783 | switch(str[-2]) { |
784 | case 'b': |
785 | case 'B': |
786 | siz=1; |
787 | break; |
788 | case 'w': |
789 | case 'W': |
790 | siz=2; |
791 | break; |
792 | case 'l': |
793 | case 'L': |
794 | siz=3; |
795 | break; |
796 | default: |
797 | opP->error="Specified size isn't :w or :l"; |
798 | return FAIL; |
799 | } |
800 | opP->con1=add_exp(beg_str,str-4); |
801 | opP->con1->e_siz=siz; |
802 | } else */ |
803 | opP->con1=add_exp(beg_str,str-2); |
804 | /* Should be offset,reg */ |
805 | if(str[-1]==',') { |
806 | i=try_index(&str,opP); |
807 | if(i==FAIL) { |
808 | opP->error="Malformed index reg"; |
809 | return FAIL; |
810 | } |
811 | } |
812 | } |
813 | /* We've now got offset) offset,reg) or reg) */ |
814 | |
815 | if(*str=='\0') { |
816 | /* Th-the-thats all folks */ |
817 | if(opP->reg==FAIL) opP->mode=AINDX; /* Other form of indirect */ |
818 | else if(opP->ireg==FAIL) opP->mode=AOFF; |
819 | else opP->mode=AINDX; |
820 | return OK; |
821 | } |
822 | /* Next thing had better be another @ */ |
823 | if(*str!='@' || str[1]!='(') { |
824 | opP->error="junk after indirect"; |
825 | return FAIL; |
826 | } |
827 | str+=2; |
828 | if(opP->ireg!=FAIL) { |
829 | opP->mode=APRDX; |
830 | i=try_index(&str,opP); |
831 | if(i!=FAIL) { |
832 | opP->error="Two index registers! not allowed!"; |
833 | return FAIL; |
834 | } |
835 | } else |
836 | i=try_index(&str,opP); |
837 | if(i==FAIL) { |
838 | char *beg_str; |
839 | |
840 | beg_str=str; |
841 | for(i=1;i;) { |
842 | switch(*str++) { |
843 | case '\0': |
844 | opP->error="Missing )"; |
845 | return FAIL; |
846 | case ',': i=0; break; |
847 | case '(': i++; break; |
848 | case ')': --i; break; |
849 | } |
850 | } |
851 | opP->con2=add_exp(beg_str,str-2); |
852 | if(str[-1]==',') { |
853 | if(opP->ireg!=FAIL) { |
854 | opP->error="Can't have two index regs"; |
855 | return FAIL; |
856 | } |
857 | i=try_index(&str,opP); |
858 | if(i==FAIL) { |
859 | opP->error="malformed index reg"; |
860 | return FAIL; |
861 | } |
862 | opP->mode=APODX; |
863 | } else if(opP->ireg!=FAIL) |
864 | opP->mode=APRDX; |
865 | else |
866 | opP->mode=AMIND; |
867 | } else |
868 | opP->mode=APODX; |
869 | if(*str!='\0') { |
870 | opP->error="Junk after indirect"; |
871 | return FAIL; |
872 | } |
873 | return OK; |
874 | } |
875 | |
876 | static int try_index(s,opP) |
877 | char **s; |
878 | struct m68k_op *opP; |
879 | { |
880 | register int i; |
881 | char *ss; |
882 | #define SKIP_W() { ss++; if(*ss==' ') ss++;} |
883 | |
884 | ss= *s; |
885 | /* SKIP_W(); */ |
886 | i=m68k_reg_parse(&ss); |
887 | if(!(i>=DATA+0 && i<=ADDR+7)) { /* if i is not DATA or ADDR reg */ |
888 | *s=ss; |
889 | return FAIL; |
890 | } |
891 | opP->ireg=i; |
892 | /* SKIP_W(); */ |
893 | if(*ss==')') { |
894 | opP->isiz=0; |
895 | opP->imul=1; |
896 | SKIP_W(); |
897 | *s=ss; |
898 | return OK; |
899 | } |
900 | if(*ss!=':') { |
901 | opP->error="Missing : in index register"; |
902 | *s=ss; |
903 | return FAIL; |
904 | } |
905 | SKIP_W(); |
906 | switch(*ss) { |
907 | case 'w': |
908 | case 'W': |
909 | opP->isiz=2; |
910 | break; |
911 | case 'l': |
912 | case 'L': |
913 | opP->isiz=3; |
914 | break; |
915 | default: |
916 | opP->error="Index register size spec not :w or :l"; |
917 | *s=ss; |
918 | return FAIL; |
919 | } |
920 | SKIP_W(); |
921 | if(*ss==':') { |
922 | SKIP_W(); |
923 | switch(*ss) { |
924 | case '1': |
925 | case '2': |
926 | case '4': |
927 | case '8': |
928 | opP->imul= *ss-'0'; |
929 | break; |
930 | default: |
931 | opP->error="index multiplier not 1, 2, 4 or 8"; |
932 | *s=ss; |
933 | return FAIL; |
934 | } |
935 | SKIP_W(); |
936 | } else opP->imul=1; |
937 | if(*ss!=')') { |
938 | opP->error="Missing )"; |
939 | *s=ss; |
940 | return FAIL; |
941 | } |
942 | SKIP_W(); |
943 | *s=ss; |
944 | return OK; |
945 | } /* try_index() */ |
946 | |
947 | #ifdef TEST1 /* TEST1 tests m68k_ip_op(), which parses operands */ |
948 | main() |
949 | { |
950 | char buf[128]; |
951 | struct m68k_op thark; |
952 | |
953 | for(;;) { |
954 | if(!gets(buf)) |
955 | break; |
956 | bzero(&thark,sizeof(thark)); |
957 | if(!m68k_ip_op(buf,&thark)) printf("FAIL:"); |
958 | if(thark.error) |
959 | printf("op1 error %s in %s\n",thark.error,buf); |
960 | printf("mode %d, reg %d, ",thark.mode,thark.reg); |
961 | if(thark.b_const) |
962 | printf("Constant: '%.*s',",1+thark.e_const-thark.b_const,thark.b_const); |
963 | printf("ireg %d, isiz %d, imul %d ",thark.ireg,thark.isiz,thark.imul); |
964 | if(thark.b_iadd) |
965 | printf("Iadd: '%.*s'",1+thark.e_iadd-thark.b_iadd,thark.b_iadd); |
966 | printf("\n"); |
967 | } |
968 | exit(0); |
969 | } |
970 | |
971 | #endif |
972 | |
973 | |
974 | static struct hash_control* op_hash = NULL; /* handle of the OPCODE hash table |
975 | NULL means any use before m68_ip_begin() |
976 | will crash */ |
977 | |
978 | \f |
979 | /* |
980 | * m 6 8 _ i p ( ) |
981 | * |
982 | * This converts a string into a 68k instruction. |
983 | * The string must be a bare single instruction in sun format |
984 | * with RMS-style 68020 indirects |
985 | * (example: ) |
986 | * |
987 | * It provides some error messages: at most one fatal error message (which |
988 | * stops the scan) and at most one warning message for each operand. |
989 | * The 68k instruction is returned in exploded form, since we have no |
990 | * knowledge of how you parse (or evaluate) your expressions. |
991 | * We do however strip off and decode addressing modes and operation |
992 | * mnemonic. |
993 | * |
994 | * This function's value is a string. If it is not "" then an internal |
995 | * logic error was found: read this code to assign meaning to the string. |
996 | * No argument string should generate such an error string: |
997 | * it means a bug in our code, not in the user's text. |
998 | * |
999 | * You MUST have called m86_ip_begin() once and m86_ip_end() never before using |
1000 | * this function. |
1001 | */ |
1002 | |
1003 | /* JF this function no longer returns a useful value. Sorry */ |
1004 | void |
1005 | m68_ip (instring) |
1006 | char *instring; |
1007 | { |
1008 | register char *p; |
1009 | register struct m68k_op *opP; |
1010 | register struct m68_incant *opcode; |
1011 | register char *s; |
1012 | register int tmpreg, |
1013 | baseo, |
1014 | outro, |
1015 | nextword; |
1016 | int siz1, |
1017 | siz2; |
1018 | char c; |
1019 | int losing; |
1020 | int opsfound; |
1021 | LITTLENUM_TYPE words[6]; |
1022 | LITTLENUM_TYPE *wordp; |
1023 | |
1024 | if (*instring == ' ') |
1025 | instring++; /* skip leading whitespace */ |
1026 | |
1027 | /* Scan up to end of operation-code, which MUST end in end-of-string |
1028 | or exactly 1 space. */ |
1029 | for (p = instring; *p != '\0'; p++) |
1030 | if (*p == ' ') |
1031 | break; |
1032 | |
1033 | |
1034 | if (p == instring) { |
1035 | the_ins.error = "No operator"; |
1036 | the_ins.opcode[0] = (short) NULL; |
1037 | /* the_ins.numo=1; */ |
1038 | return; |
1039 | } |
1040 | |
1041 | /* p now points to the end of the opcode name, probably whitespace. |
1042 | make sure the name is null terminated by clobbering the whitespace, |
1043 | look it up in the hash table, then fix it back. */ |
1044 | c = *p; |
1045 | *p = '\0'; |
1046 | opcode = (struct m68_incant *)hash_find (op_hash, instring); |
1047 | *p = c; |
1048 | |
1049 | if (opcode == NULL) { |
1050 | the_ins.error = "Unknown operator"; |
1051 | the_ins.opcode[0] = (short) NULL; |
1052 | /* the_ins.numo=1; */ |
1053 | return; |
1054 | } |
1055 | |
1056 | /* found a legitimate opcode, start matching operands */ |
1057 | for(opP= &the_ins.operands[0];*p;opP++) { |
1058 | p = crack_operand (p, opP); |
1059 | if(opP->error) { |
1060 | the_ins.error=opP->error; |
1061 | return; |
1062 | } |
1063 | } |
1064 | |
1065 | opsfound=opP- &the_ins.operands[0]; |
1066 | /* This ugly hack is to support the floating pt opcodes in their standard form */ |
1067 | /* Essentially, we fake a first enty of type COP#1 */ |
1068 | if(opcode->m_operands[0]=='I') { |
1069 | int n; |
1070 | |
1071 | for(n=opsfound;n>0;--n) |
1072 | the_ins.operands[n]=the_ins.operands[n-1]; |
1073 | |
1074 | /* bcopy((char *)(&the_ins.operands[0]),(char *)(&the_ins.operands[1]),opsfound*sizeof(the_ins.operands[0])); */ |
1075 | bzero((char *)(&the_ins.operands[0]),sizeof(the_ins.operands[0])); |
1076 | the_ins.operands[0].mode=MSCR; |
1077 | the_ins.operands[0].reg=COPNUM; /* COP #1 */ |
1078 | opsfound++; |
1079 | } |
1080 | /* We've got the operands. Find an opcode that'll |
1081 | accept them */ |
1082 | for(losing=0;;) { |
1083 | if(opsfound!=opcode->m_opnum) |
1084 | losing++; |
1085 | else for(s=opcode->m_operands,opP= &the_ins.operands[0];*s && !losing;s+=2,opP++) { |
1086 | /* Warning: this switch is huge! */ |
1087 | /* I've tried to organize the cases into this order: |
1088 | non-alpha first, then alpha by letter. lower-case goes directly |
1089 | before uppercase counterpart. */ |
1090 | /* Code with multiple case ...: gets sorted by the lowest case ... |
1091 | it belongs to. I hope this makes sense. */ |
1092 | switch(*s) { |
1093 | case '!': |
1094 | if(opP->mode==MSCR || opP->mode==IMMED || |
1095 | opP->mode==DREG || opP->mode==AREG || opP->mode==AINC || opP->mode==ADEC || opP->mode==REGLST) |
1096 | losing++; |
1097 | break; |
1098 | |
1099 | case '#': |
1100 | if(opP->mode!=IMMED) |
1101 | losing++; |
1102 | else { |
1103 | long t; |
1104 | |
1105 | t=get_num(opP->con1,80); |
1106 | if(s[1]=='b' && !isbyte(t)) |
1107 | losing++; |
1108 | else if(s[1]=='w' && !isword(t)) |
1109 | losing++; |
1110 | } |
1111 | break; |
1112 | |
1113 | case '^': |
1114 | case 'T': |
1115 | if(opP->mode!=IMMED) |
1116 | losing++; |
1117 | break; |
1118 | |
1119 | case '$': |
1120 | if(opP->mode==MSCR || opP->mode==AREG || |
1121 | opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST) |
1122 | losing++; |
1123 | break; |
1124 | |
1125 | case '%': |
1126 | if(opP->mode==MSCR || opP->reg==PC || |
1127 | opP->reg==ZPC || opP->mode==REGLST) |
1128 | losing++; |
1129 | break; |
1130 | |
1131 | |
1132 | case '&': |
1133 | if(opP->mode==MSCR || opP->mode==DREG || |
1134 | opP->mode==AREG || opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || |
1135 | opP->mode==AINC || opP->mode==ADEC || opP->mode==REGLST) |
1136 | losing++; |
1137 | break; |
1138 | |
1139 | case '*': |
1140 | if(opP->mode==MSCR || opP->mode==REGLST) |
1141 | losing++; |
1142 | break; |
1143 | |
1144 | case '+': |
1145 | if(opP->mode!=AINC) |
1146 | losing++; |
1147 | break; |
1148 | |
1149 | case '-': |
1150 | if(opP->mode!=ADEC) |
1151 | losing++; |
1152 | break; |
1153 | |
1154 | case '/': |
1155 | if(opP->mode==MSCR || opP->mode==AREG || |
1156 | opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->mode==REGLST) |
1157 | losing++; |
1158 | break; |
1159 | |
1160 | case ';': |
1161 | if(opP->mode==MSCR || opP->mode==AREG || opP->mode==REGLST) |
1162 | losing++; |
1163 | break; |
1164 | |
1165 | case '?': |
1166 | if(opP->mode==MSCR || opP->mode==AREG || |
1167 | opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->reg==PC || |
1168 | opP->reg==ZPC || opP->mode==REGLST) |
1169 | losing++; |
1170 | break; |
1171 | |
1172 | case '@': |
1173 | if(opP->mode==MSCR || opP->mode==AREG || |
1174 | opP->mode==IMMED || opP->mode==REGLST) |
1175 | losing++; |
1176 | break; |
1177 | |
1178 | case '~': /* For now! (JF FOO is this right?) */ |
1179 | if(opP->mode==MSCR || opP->mode==DREG || |
1180 | opP->mode==AREG || opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST) |
1181 | losing++; |
1182 | break; |
1183 | |
1184 | case 'A': |
1185 | if(opP->mode!=AREG) |
1186 | losing++; |
1187 | break; |
1188 | |
1189 | case 'B': /* FOO */ |
1190 | if(opP->mode!=ABSL) |
1191 | losing++; |
1192 | break; |
1193 | |
1194 | case 'C': |
1195 | if(opP->mode!=MSCR || opP->reg!=CCR) |
1196 | losing++; |
1197 | break; |
1198 | |
1199 | case 'd': /* FOO This mode is a KLUDGE!! */ |
1200 | if(opP->mode!=AOFF && (opP->mode!=ABSL || |
1201 | opP->con1->e_beg[0]!='(' || opP->con1->e_end[0]!=')')) |
1202 | losing++; |
1203 | break; |
1204 | |
1205 | case 'D': |
1206 | if(opP->mode!=DREG) |
1207 | losing++; |
1208 | break; |
1209 | |
1210 | case 'F': |
1211 | if(opP->mode!=MSCR || opP->reg<(FPREG+0) || opP->reg>(FPREG+7)) |
1212 | losing++; |
1213 | break; |
1214 | |
1215 | case 'I': |
1216 | if(opP->mode!=MSCR || opP->reg<COPNUM || |
1217 | opP->reg>=COPNUM+7) |
1218 | losing++; |
1219 | break; |
1220 | |
1221 | case 'J': |
1222 | if(opP->mode!=MSCR || opP->reg<USP || opP->reg>MSP) |
1223 | losing++; |
1224 | break; |
1225 | |
1226 | case 'k': |
1227 | if(opP->mode!=IMMED) |
1228 | losing++; |
1229 | break; |
1230 | |
1231 | case 'l': |
1232 | case 'L': |
1233 | if(opP->mode==DREG || opP->mode==AREG || opP->mode==FPREG) { |
1234 | if(s[1]=='8') |
1235 | losing++; |
1236 | else { |
1237 | opP->mode=REGLST; |
1238 | opP->reg=1<<(opP->reg-DATA); |
1239 | } |
1240 | } else if(opP->mode!=REGLST) { |
1241 | losing++; |
1242 | } else if(s[1]=='8' && opP->reg&0x0FFffFF) |
1243 | losing++; |
1244 | else if(s[1]=='3' && opP->reg&0x7000000) |
1245 | losing++; |
1246 | break; |
1247 | |
1248 | case 'M': |
1249 | if(opP->mode!=IMMED) |
1250 | losing++; |
1251 | else { |
1252 | long t; |
1253 | |
1254 | t=get_num(opP->con1,80); |
1255 | if(!issbyte(t) || isvar(opP->con1)) |
1256 | losing++; |
1257 | } |
1258 | break; |
1259 | |
1260 | case 'O': |
1261 | if(opP->mode!=DREG && opP->mode!=IMMED) |
1262 | losing++; |
1263 | break; |
1264 | |
1265 | case 'Q': |
1266 | if(opP->mode!=IMMED) |
1267 | losing++; |
1268 | else { |
1269 | long t; |
1270 | |
1271 | t=get_num(opP->con1,80); |
1272 | if(t<1 || t>8 || isvar(opP->con1)) |
1273 | losing++; |
1274 | } |
1275 | break; |
1276 | |
1277 | case 'R': |
1278 | if(opP->mode!=DREG && opP->mode!=AREG) |
1279 | losing++; |
1280 | break; |
1281 | |
1282 | case 's': |
1283 | if(opP->mode!=MSCR || !(opP->reg==FPI || opP->reg==FPS || opP->reg==FPC)) |
1284 | losing++; |
1285 | break; |
1286 | |
1287 | case 'S': |
1288 | if(opP->mode!=MSCR || opP->reg!=SR) |
1289 | losing++; |
1290 | break; |
1291 | |
1292 | case 'U': |
1293 | if(opP->mode!=MSCR || opP->reg!=USP) |
1294 | losing++; |
1295 | break; |
1296 | |
1297 | /* JF these are out of order. We could put them |
1298 | in order if we were willing to put up with |
1299 | bunches of #ifdef m68851s in the code */ |
1300 | #ifdef m68851 |
1301 | /* Memory addressing mode used by pflushr */ |
1302 | case '|': |
1303 | if(opP->mode==MSCR || opP->mode==DREG || |
1304 | opP->mode==AREG || opP->mode==REGLST) |
1305 | losing++; |
1306 | break; |
1307 | |
1308 | case 'f': |
1309 | if (opP->mode != MSCR || (opP->reg != SFC && opP->reg != DFC)) |
1310 | losing++; |
1311 | break; |
1312 | |
1313 | case 'P': |
1314 | if (opP->mode != MSCR || (opP->reg != TC && opP->reg != CAL && |
1315 | opP->reg != VAL && opP->reg != SCC && opP->reg != AC)) |
1316 | losing++; |
1317 | break; |
1318 | |
1319 | case 'V': |
1320 | if (opP->reg != VAL) |
1321 | losing++; |
1322 | break; |
1323 | |
1324 | case 'W': |
1325 | if (opP->mode != MSCR || (opP->reg != DRP && opP->reg != SRP && |
1326 | opP->reg != CRP)) |
1327 | losing++; |
1328 | break; |
1329 | |
1330 | case 'X': |
1331 | if (opP->mode != MSCR || |
1332 | (!(opP->reg >= BAD && opP->reg <= BAD+7) && |
1333 | !(opP->reg >= BAC && opP->reg <= BAC+7))) |
1334 | losing++; |
1335 | break; |
1336 | |
1337 | case 'Y': |
1338 | if (opP->reg != PSR) |
1339 | losing++; |
1340 | break; |
1341 | |
1342 | case 'Z': |
1343 | if (opP->reg != PCSR) |
1344 | losing++; |
1345 | break; |
1346 | #endif |
1347 | default: |
1348 | as_fatal("Internal error: Operand mode %c unknown in line %s of file \"%s\"", |
1349 | *s, __LINE__, __FILE__); |
1350 | } |
1351 | } |
1352 | if(!losing) |
1353 | break; |
1354 | opcode=opcode->m_next; |
1355 | if(!opcode) { /* Fell off the end */ |
1356 | the_ins.error="instruction/operands mismatch"; |
1357 | return; |
1358 | } |
1359 | losing=0; |
1360 | } |
1361 | the_ins.args=opcode->m_operands; |
1362 | the_ins.numargs=opcode->m_opnum; |
1363 | the_ins.numo=opcode->m_codenum; |
1364 | the_ins.opcode[0]=getone(opcode); |
1365 | the_ins.opcode[1]=gettwo(opcode); |
1366 | |
1367 | for(s=the_ins.args,opP= &the_ins.operands[0];*s;s+=2,opP++) { |
1368 | /* This switch is a doozy. |
1369 | What the first step; its a big one! */ |
1370 | switch(s[0]) { |
1371 | |
1372 | case '*': |
1373 | case '~': |
1374 | case '%': |
1375 | case ';': |
1376 | case '@': |
1377 | case '!': |
1378 | case '&': |
1379 | case '$': |
1380 | case '?': |
1381 | case '/': |
1382 | #ifdef m68851 |
1383 | case '|': |
1384 | #endif |
1385 | switch(opP->mode) { |
1386 | case IMMED: |
1387 | tmpreg=0x3c; /* 7.4 */ |
1388 | if(strchr("bwl",s[1])) nextword=get_num(opP->con1,80); |
1389 | else nextword=nextword=get_num(opP->con1,0); |
1390 | if(isvar(opP->con1)) |
1391 | add_fix(s[1],opP->con1,0); |
1392 | switch(s[1]) { |
1393 | case 'b': |
1394 | if(!isbyte(nextword)) |
1395 | opP->error="operand out of range"; |
1396 | addword(nextword); |
1397 | baseo=0; |
1398 | break; |
1399 | case 'w': |
1400 | if(!isword(nextword)) |
1401 | opP->error="operand out of range"; |
1402 | addword(nextword); |
1403 | baseo=0; |
1404 | break; |
1405 | case 'l': |
1406 | addword(nextword>>16); |
1407 | addword(nextword); |
1408 | baseo=0; |
1409 | break; |
1410 | |
1411 | case 'f': |
1412 | baseo=2; |
1413 | outro=8; |
1414 | break; |
1415 | case 'F': |
1416 | baseo=4; |
1417 | outro=11; |
1418 | break; |
1419 | case 'x': |
1420 | baseo=6; |
1421 | outro=15; |
1422 | break; |
1423 | case 'p': |
1424 | baseo=6; |
1425 | outro= -1; |
1426 | break; |
1427 | default: |
1428 | as_fatal("Internal error: Can't decode %c%c in line %s of file \"%s\"", |
1429 | *s, s[1], __LINE__, __FILE__); |
1430 | } |
1431 | if(!baseo) |
1432 | break; |
1433 | |
1434 | /* We gotta put out some float */ |
1435 | if(seg(opP->con1)!=SEG_BIG) { |
1436 | int_to_gen(nextword); |
1437 | gen_to_words(words,baseo,(long)outro); |
1438 | for(wordp=words;baseo--;wordp++) |
1439 | addword(*wordp); |
1440 | break; |
1441 | } /* Its BIG */ |
1442 | if(offs(opP->con1)>0) { |
1443 | as_warn("Bignum assumed to be binary bit-pattern"); |
1444 | if(offs(opP->con1)>baseo) { |
1445 | as_bad("Bignum too big for %c format; truncated",s[1]); |
1446 | offs(opP->con1)=baseo; |
1447 | } |
1448 | baseo-=offs(opP->con1); |
1449 | for(wordp=generic_bignum+offs(opP->con1)-1;offs(opP->con1)--;--wordp) |
1450 | addword(*wordp); |
1451 | while(baseo--) |
1452 | addword(0); |
1453 | break; |
1454 | } |
1455 | gen_to_words(words,baseo,(long)outro); |
1456 | for(wordp=words;baseo--;wordp++) |
1457 | addword(*wordp); |
1458 | break; |
1459 | case DREG: |
1460 | tmpreg=opP->reg-DATA; /* 0.dreg */ |
1461 | break; |
1462 | case AREG: |
1463 | tmpreg=0x08+opP->reg-ADDR; /* 1.areg */ |
1464 | break; |
1465 | case AINDR: |
1466 | tmpreg=0x10+opP->reg-ADDR; /* 2.areg */ |
1467 | break; |
1468 | case ADEC: |
1469 | tmpreg=0x20+opP->reg-ADDR; /* 4.areg */ |
1470 | break; |
1471 | case AINC: |
1472 | tmpreg=0x18+opP->reg-ADDR; /* 3.areg */ |
1473 | break; |
1474 | case AOFF: |
1475 | |
1476 | nextword=get_num(opP->con1,80); |
1477 | /* Force into index mode. Hope this works */ |
1478 | |
1479 | /* We do the first bit for 32-bit displacements, |
1480 | and the second bit for 16 bit ones. It is |
1481 | possible that we should make the default be |
1482 | WORD instead of LONG, but I think that'd |
1483 | break GCC, so we put up with a little |
1484 | inefficiency for the sake of working output. |
1485 | */ |
1486 | |
1487 | if( !issword(nextword) |
1488 | || ( isvar(opP->con1) |
1489 | && ( ( opP->con1->e_siz==0 |
1490 | && flagseen['l']==0) |
1491 | || opP->con1->e_siz==3))) { |
1492 | |
1493 | if(opP->reg==PC) |
1494 | tmpreg=0x3B; /* 7.3 */ |
1495 | else |
1496 | tmpreg=0x30+opP->reg-ADDR; /* 6.areg */ |
1497 | if(isvar(opP->con1)) { |
1498 | if(opP->reg==PC) { |
1499 | add_frag(adds(opP->con1), |
1500 | offs(opP->con1), |
1501 | TAB(PCLEA,SZ_UNDEF)); |
1502 | break; |
1503 | } else { |
1504 | addword(0x0170); |
1505 | add_fix('l',opP->con1,1); |
1506 | } |
1507 | } else |
1508 | addword(0x0170); |
1509 | addword(nextword>>16); |
1510 | } else { |
1511 | if(opP->reg==PC) |
1512 | tmpreg=0x3A; /* 7.2 */ |
1513 | else |
1514 | tmpreg=0x28+opP->reg-ADDR; /* 5.areg */ |
1515 | |
1516 | if(isvar(opP->con1)) { |
1517 | if(opP->reg==PC) { |
1518 | add_fix('w',opP->con1,1); |
1519 | } else |
1520 | add_fix('w',opP->con1,0); |
1521 | } |
1522 | } |
1523 | addword(nextword); |
1524 | break; |
1525 | case AINDX: |
1526 | case APODX: |
1527 | case AMIND: |
1528 | case APRDX: |
1529 | nextword=0; |
1530 | baseo=get_num(opP->con1,80); |
1531 | outro=get_num(opP->con2,80); |
1532 | /* Figure out the 'addressing mode' */ |
1533 | /* Also turn on the BASE_DISABLE bit, if needed */ |
1534 | if(opP->reg==PC || opP->reg==ZPC) { |
1535 | tmpreg=0x3b; /* 7.3 */ |
1536 | if(opP->reg==ZPC) |
1537 | nextword|=0x80; |
1538 | } else if(opP->reg==FAIL) { |
1539 | nextword|=0x80; |
1540 | tmpreg=0x30; /* 6.garbage */ |
1541 | } else tmpreg=0x30+opP->reg-ADDR; /* 6.areg */ |
1542 | |
1543 | siz1= (opP->con1) ? opP->con1->e_siz : 0; |
1544 | siz2= (opP->con2) ? opP->con2->e_siz : 0; |
1545 | |
1546 | /* Index register stuff */ |
1547 | if(opP->ireg>=DATA+0 && opP->ireg<=ADDR+7) { |
1548 | nextword|=(opP->ireg-DATA)<<12; |
1549 | |
1550 | if(opP->isiz==0 || opP->isiz==3) |
1551 | nextword|=0x800; |
1552 | switch(opP->imul) { |
1553 | case 1: break; |
1554 | case 2: nextword|=0x200; break; |
1555 | case 4: nextword|=0x400; break; |
1556 | case 8: nextword|=0x600; break; |
1557 | default: abort(); |
1558 | } |
1559 | /* IF its simple, |
1560 | GET US OUT OF HERE! */ |
1561 | |
1562 | /* Must be INDEX, with an index |
1563 | register. Address register |
1564 | cannot be ZERO-PC, and either |
1565 | :b was forced, or we know |
1566 | it will fit */ |
1567 | if( opP->mode==AINDX |
1568 | && opP->reg!=FAIL |
1569 | && opP->reg!=ZPC |
1570 | && ( siz1==1 |
1571 | || ( issbyte(baseo) |
1572 | && !isvar(opP->con1)))) { |
1573 | nextword +=baseo&0xff; |
1574 | addword(nextword); |
1575 | if(isvar(opP->con1)) |
1576 | add_fix('B',opP->con1,0); |
1577 | break; |
1578 | } |
1579 | } else |
1580 | nextword|=0x40; /* No index reg */ |
1581 | |
1582 | /* It aint simple */ |
1583 | nextword|=0x100; |
1584 | /* If the guy specified a width, we assume that |
1585 | it is wide enough. Maybe it isn't. Ifso, we lose |
1586 | */ |
1587 | switch(siz1) { |
1588 | case 0: |
1589 | if(isvar(opP->con1) || !issword(baseo)) { |
1590 | siz1=3; |
1591 | nextword|=0x30; |
1592 | } else if(baseo==0) |
1593 | nextword|=0x10; |
1594 | else { |
1595 | nextword|=0x20; |
1596 | siz1=2; |
1597 | } |
1598 | break; |
1599 | case 1: |
1600 | as_warn("Byte dispacement won't work. Defaulting to :w"); |
1601 | case 2: |
1602 | nextword|=0x20; |
1603 | break; |
1604 | case 3: |
1605 | nextword|=0x30; |
1606 | break; |
1607 | } |
1608 | |
1609 | /* Figure out innner displacement stuff */ |
1610 | if(opP->mode!=AINDX) { |
1611 | switch(siz2) { |
1612 | case 0: |
1613 | if(isvar(opP->con2) || !issword(outro)) { |
1614 | siz2=3; |
1615 | nextword|=0x3; |
1616 | } else if(outro==0) |
1617 | nextword|=0x1; |
1618 | else { |
1619 | nextword|=0x2; |
1620 | siz2=2; |
1621 | } |
1622 | break; |
1623 | case 1: |
1624 | as_warn("Byte dispacement won't work. Defaulting to :w"); |
1625 | case 2: |
1626 | nextword|=0x2; |
1627 | break; |
1628 | case 3: |
1629 | nextword|=0x3; |
1630 | break; |
1631 | } |
1632 | if(opP->mode==APODX) nextword|=0x04; |
1633 | else if(opP->mode==AMIND) nextword|=0x40; |
1634 | } |
1635 | addword(nextword); |
1636 | |
1637 | if(isvar(opP->con1)) { |
1638 | if(opP->reg==PC || opP->reg==ZPC) { |
1639 | add_fix(siz1==3 ? 'l' : 'w',opP->con1,1); |
1640 | opP->con1->e_exp.X_add_number+=6; |
1641 | } else |
1642 | add_fix(siz1==3 ? 'l' : 'w',opP->con1,0); |
1643 | } |
1644 | if(siz1==3) |
1645 | addword(baseo>>16); |
1646 | if(siz1) |
1647 | addword(baseo); |
1648 | |
1649 | if(isvar(opP->con2)) { |
1650 | if(opP->reg==PC || opP->reg==ZPC) { |
1651 | add_fix(siz2==3 ? 'l' : 'w',opP->con2,1); |
1652 | opP->con1->e_exp.X_add_number+=6; |
1653 | } else |
1654 | add_fix(siz2==3 ? 'l' : 'w',opP->con2,0); |
1655 | } |
1656 | if(siz2==3) |
1657 | addword(outro>>16); |
1658 | if(siz2) |
1659 | addword(outro); |
1660 | |
1661 | break; |
1662 | |
1663 | case ABSL: |
1664 | nextword=get_num(opP->con1,80); |
1665 | switch(opP->con1->e_siz) { |
1666 | default: |
1667 | as_bad("Unknown size for absolute reference"); |
1668 | case 0: |
1669 | if(!isvar(opP->con1) && issword(offs(opP->con1))) { |
1670 | tmpreg=0x38; /* 7.0 */ |
1671 | addword(nextword); |
1672 | break; |
1673 | } |
1674 | if(isvar(opP->con1) && |
1675 | !subs(opP->con1) && |
1676 | !strchr("~%&$?", s[0])) { |
1677 | tmpreg=0x3A; /* 7.2 */ |
1678 | add_frag(adds(opP->con1), |
1679 | offs(opP->con1), |
1680 | TAB(PCREL,SZ_UNDEF)); |
1681 | break; |
1682 | } |
1683 | case 3: /* Fall through into long */ |
1684 | if(isvar(opP->con1)) |
1685 | add_fix('l',opP->con1,0); |
1686 | |
1687 | tmpreg=0x39; /* 7.1 mode */ |
1688 | addword(nextword>>16); |
1689 | addword(nextword); |
1690 | break; |
1691 | |
1692 | case 2: /* Word */ |
1693 | if(isvar(opP->con1)) |
1694 | add_fix('w',opP->con1,0); |
1695 | |
1696 | tmpreg=0x38; /* 7.0 mode */ |
1697 | addword(nextword); |
1698 | break; |
1699 | } |
1700 | break; |
1701 | case MSCR: |
1702 | default: |
1703 | as_bad("unknown/incorrect operand"); |
1704 | /* abort(); */ |
1705 | } |
1706 | install_gen_operand(s[1],tmpreg); |
1707 | break; |
1708 | |
1709 | case '#': |
1710 | case '^': |
1711 | switch(s[1]) { /* JF: I hate floating point! */ |
1712 | case 'j': |
1713 | tmpreg=70; |
1714 | break; |
1715 | case '8': |
1716 | tmpreg=20; |
1717 | break; |
1718 | case 'C': |
1719 | tmpreg=50; |
1720 | break; |
1721 | case '3': |
1722 | default: |
1723 | tmpreg=80; |
1724 | break; |
1725 | } |
1726 | tmpreg=get_num(opP->con1,tmpreg); |
1727 | if(isvar(opP->con1)) |
1728 | add_fix(s[1],opP->con1,0); |
1729 | switch(s[1]) { |
1730 | case 'b': /* Danger: These do no check for |
1731 | certain types of overflow. |
1732 | user beware! */ |
1733 | if(!isbyte(tmpreg)) |
1734 | opP->error="out of range"; |
1735 | insop(tmpreg); |
1736 | if(isvar(opP->con1)) |
1737 | the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2; |
1738 | break; |
1739 | case 'w': |
1740 | if(!isword(tmpreg)) |
1741 | opP->error="out of range"; |
1742 | insop(tmpreg); |
1743 | if(isvar(opP->con1)) |
1744 | the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2; |
1745 | break; |
1746 | case 'l': |
1747 | insop(tmpreg); /* Because of the way insop works, we put these two out backwards */ |
1748 | insop(tmpreg>>16); |
1749 | if(isvar(opP->con1)) |
1750 | the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2; |
1751 | break; |
1752 | case '3': |
1753 | tmpreg&=0xFF; |
1754 | case '8': |
1755 | case 'C': |
1756 | install_operand(s[1],tmpreg); |
1757 | break; |
1758 | default: |
1759 | as_fatal("Internal error: Unknown mode #%c in line %s of file \"%s\"", s[1], __LINE__, __FILE__); |
1760 | } |
1761 | break; |
1762 | |
1763 | case '+': |
1764 | case '-': |
1765 | case 'A': |
1766 | install_operand(s[1],opP->reg-ADDR); |
1767 | break; |
1768 | |
1769 | case 'B': |
1770 | tmpreg=get_num(opP->con1,80); |
1771 | switch(s[1]) { |
1772 | case 'g': |
1773 | if(opP->con1->e_siz) { /* Deal with fixed size stuff by hand */ |
1774 | switch(opP->con1->e_siz) { |
1775 | case 1: |
1776 | add_fix('b',opP->con1,1); |
1777 | break; |
1778 | case 2: |
1779 | add_fix('w',opP->con1,1); |
1780 | addword(0); |
1781 | break; |
1782 | case 3: |
1783 | add_fix('l',opP->con1,1); |
1784 | addword(0); |
1785 | addword(0); |
1786 | break; |
1787 | default: |
1788 | as_bad("Bad size for expression %d", opP->con1->e_siz); |
1789 | } |
1790 | } else if(subs(opP->con1)) { |
1791 | /* We can't relax it */ |
1792 | the_ins.opcode[the_ins.numo-1]|=0xff; |
1793 | add_fix('l',opP->con1,1); |
1794 | addword(0); |
1795 | addword(0); |
1796 | } else if(adds(opP->con1)) { |
1797 | if (flagseen['m'] && |
1798 | (the_ins.opcode[0] >= 0x6200) && |
1799 | (the_ins.opcode[0] <= 0x6f00)) { |
1800 | add_frag(adds(opP->con1),offs(opP->con1),TAB(BCC68000,SZ_UNDEF)); |
1801 | } else { |
1802 | add_frag(adds(opP->con1),offs(opP->con1),TAB(BRANCH,SZ_UNDEF)); |
1803 | } |
1804 | } else { |
1805 | /* JF: This is the WRONG thing to do |
1806 | add_frag((symbolS *)0,offs(opP->con1),TAB(BRANCH,BYTE)); */ |
1807 | the_ins.opcode[the_ins.numo-1]|=0xff; |
1808 | offs(opP->con1)+=4; |
1809 | add_fix('l',opP->con1,1); |
1810 | addword(0); |
1811 | addword(0); |
1812 | } |
1813 | break; |
1814 | case 'w': |
1815 | if(isvar(opP->con1)) { |
1816 | /* check for DBcc instruction */ |
1817 | if ((the_ins.opcode[0] & 0xf0f8) ==0x50c8) { |
1818 | /* size varies if patch */ |
1819 | /* needed for long form */ |
1820 | add_frag(adds(opP->con1),offs(opP->con1),TAB(DBCC,SZ_UNDEF)); |
1821 | break; |
1822 | } |
1823 | |
1824 | /* Don't ask! */ |
1825 | opP->con1->e_exp.X_add_number+=2; |
1826 | add_fix('w',opP->con1,1); |
1827 | } |
1828 | addword(0); |
1829 | break; |
1830 | case 'c': |
1831 | if(opP->con1->e_siz) { |
1832 | switch(opP->con1->e_siz) { |
1833 | case 2: |
1834 | add_fix('w',opP->con1,1) |
1835 | addword(0); |
1836 | break; |
1837 | case 3: |
1838 | the_ins.opcode[the_ins.numo-1]|=0x40; |
1839 | add_fix('l',opP->con1,1); |
1840 | addword(0); |
1841 | addword(0); |
1842 | break; |
1843 | default: |
1844 | as_bad("Bad size for offset, must be word or long"); |
1845 | break; |
1846 | } |
1847 | } else if(subs(opP->con1)) { |
1848 | add_fix('l',opP->con1,1); |
1849 | add_frag((symbolS *)0,(long)0,TAB(FBRANCH,LONG)); |
1850 | } else if(adds(opP->con1)) { |
1851 | add_frag(adds(opP->con1),offs(opP->con1),TAB(FBRANCH,SZ_UNDEF)); |
1852 | } else { |
1853 | /* add_frag((symbolS *)0,offs(opP->con1),TAB(FBRANCH,SHORT)); */ |
1854 | the_ins.opcode[the_ins.numo-1]|=0x40; |
1855 | add_fix('l',opP->con1,1); |
1856 | addword(0); |
1857 | addword(4); |
1858 | } |
1859 | break; |
1860 | default: |
1861 | as_fatal("Internal error: operand type B%c unknown in line %s of file \"%s\"", |
1862 | s[1], __LINE__, __FILE__); |
1863 | } |
1864 | break; |
1865 | |
1866 | case 'C': /* Ignore it */ |
1867 | break; |
1868 | |
1869 | case 'd': /* JF this is a kludge */ |
1870 | if(opP->mode==AOFF) { |
1871 | install_operand('s',opP->reg-ADDR); |
1872 | } else { |
1873 | char *tmpP; |
1874 | |
1875 | tmpP=opP->con1->e_end-2; |
1876 | opP->con1->e_beg++; |
1877 | opP->con1->e_end-=4; /* point to the , */ |
1878 | baseo=m68k_reg_parse(&tmpP); |
1879 | if(baseo<ADDR+0 || baseo>ADDR+7) { |
1880 | as_bad("Unknown address reg, using A0"); |
1881 | baseo=0; |
1882 | } else baseo-=ADDR; |
1883 | install_operand('s',baseo); |
1884 | } |
1885 | tmpreg=get_num(opP->con1,80); |
1886 | if(!issword(tmpreg)) { |
1887 | as_bad("Expression out of range, using 0"); |
1888 | tmpreg=0; |
1889 | } |
1890 | addword(tmpreg); |
1891 | break; |
1892 | |
1893 | case 'D': |
1894 | install_operand(s[1],opP->reg-DATA); |
1895 | break; |
1896 | |
1897 | case 'F': |
1898 | install_operand(s[1],opP->reg-FPREG); |
1899 | break; |
1900 | |
1901 | case 'I': |
1902 | tmpreg=1+opP->reg-COPNUM; |
1903 | if(tmpreg==8) |
1904 | tmpreg=0; |
1905 | install_operand(s[1],tmpreg); |
1906 | break; |
1907 | |
1908 | case 'J': /* JF foo */ |
1909 | switch(opP->reg) { |
1910 | case SFC: |
1911 | tmpreg=0; |
1912 | break; |
1913 | case DFC: |
1914 | tmpreg=0x001; |
1915 | break; |
1916 | case CACR: |
1917 | tmpreg=0x002; |
1918 | break; |
1919 | case USP: |
1920 | tmpreg=0x800; |
1921 | break; |
1922 | case VBR: |
1923 | tmpreg=0x801; |
1924 | break; |
1925 | case CAAR: |
1926 | tmpreg=0x802; |
1927 | break; |
1928 | case MSP: |
1929 | tmpreg=0x803; |
1930 | break; |
1931 | case ISP: |
1932 | tmpreg=0x804; |
1933 | break; |
1934 | default: |
1935 | abort(); |
1936 | } |
1937 | install_operand(s[1],tmpreg); |
1938 | break; |
1939 | |
1940 | case 'k': |
1941 | tmpreg=get_num(opP->con1,55); |
1942 | install_operand(s[1],tmpreg&0x7f); |
1943 | break; |
1944 | |
1945 | case 'l': |
1946 | tmpreg=opP->reg; |
1947 | if(s[1]=='w') { |
1948 | if(tmpreg&0x7FF0000) |
1949 | as_bad("Floating point register in register list"); |
1950 | insop(reverse_16_bits(tmpreg)); |
1951 | } else { |
1952 | if(tmpreg&0x700FFFF) |
1953 | as_bad("Wrong register in floating-point reglist"); |
1954 | install_operand(s[1],reverse_8_bits(tmpreg>>16)); |
1955 | } |
1956 | break; |
1957 | |
1958 | case 'L': |
1959 | tmpreg=opP->reg; |
1960 | if(s[1]=='w') { |
1961 | if(tmpreg&0x7FF0000) |
1962 | as_bad("Floating point register in register list"); |
1963 | insop(tmpreg); |
1964 | } else if(s[1]=='8') { |
1965 | if(tmpreg&0x0FFFFFF) |
1966 | as_bad("incorrect register in reglist"); |
1967 | install_operand(s[1],tmpreg>>24); |
1968 | } else { |
1969 | if(tmpreg&0x700FFFF) |
1970 | as_bad("wrong register in floating-point reglist"); |
1971 | else |
1972 | install_operand(s[1],tmpreg>>16); |
1973 | } |
1974 | break; |
1975 | |
1976 | case 'M': |
1977 | install_operand(s[1],get_num(opP->con1,60)); |
1978 | break; |
1979 | |
1980 | case 'O': |
1981 | tmpreg= (opP->mode==DREG) |
1982 | ? 0x20+opP->reg-DATA |
1983 | : (get_num(opP->con1,40)&0x1F); |
1984 | install_operand(s[1],tmpreg); |
1985 | break; |
1986 | |
1987 | case 'Q': |
1988 | tmpreg=get_num(opP->con1,10); |
1989 | if(tmpreg==8) |
1990 | tmpreg=0; |
1991 | install_operand(s[1],tmpreg); |
1992 | break; |
1993 | |
1994 | case 'R': |
1995 | /* This depends on the fact that ADDR registers are |
1996 | eight more than their corresponding DATA regs, so |
1997 | the result will have the ADDR_REG bit set */ |
1998 | install_operand(s[1],opP->reg-DATA); |
1999 | break; |
2000 | |
2001 | case 's': |
2002 | if(opP->reg==FPI) tmpreg=0x1; |
2003 | else if(opP->reg==FPS) tmpreg=0x2; |
2004 | else if(opP->reg==FPC) tmpreg=0x4; |
2005 | else abort(); |
2006 | install_operand(s[1],tmpreg); |
2007 | break; |
2008 | |
2009 | case 'S': /* Ignore it */ |
2010 | break; |
2011 | |
2012 | case 'T': |
2013 | install_operand(s[1],get_num(opP->con1,30)); |
2014 | break; |
2015 | |
2016 | case 'U': /* Ignore it */ |
2017 | break; |
2018 | |
2019 | #ifdef m68851 |
2020 | /* JF: These are out of order, I fear. */ |
2021 | case 'f': |
2022 | switch (opP->reg) { |
2023 | case SFC: |
2024 | tmpreg=0; |
2025 | break; |
2026 | case DFC: |
2027 | tmpreg=1; |
2028 | break; |
2029 | default: |
2030 | abort(); |
2031 | } |
2032 | install_operand(s[1],tmpreg); |
2033 | break; |
2034 | |
2035 | case 'P': |
2036 | switch(opP->reg) { |
2037 | case TC: |
2038 | tmpreg=0; |
2039 | break; |
2040 | case CAL: |
2041 | tmpreg=4; |
2042 | break; |
2043 | case VAL: |
2044 | tmpreg=5; |
2045 | break; |
2046 | case SCC: |
2047 | tmpreg=6; |
2048 | break; |
2049 | case AC: |
2050 | tmpreg=7; |
2051 | break; |
2052 | default: |
2053 | abort(); |
2054 | } |
2055 | install_operand(s[1],tmpreg); |
2056 | break; |
2057 | |
2058 | case 'V': |
2059 | if (opP->reg == VAL) |
2060 | break; |
2061 | abort(); |
2062 | |
2063 | case 'W': |
2064 | switch(opP->reg) { |
2065 | |
2066 | case DRP: |
2067 | tmpreg=1; |
2068 | break; |
2069 | case SRP: |
2070 | tmpreg=2; |
2071 | break; |
2072 | case CRP: |
2073 | tmpreg=3; |
2074 | break; |
2075 | default: |
2076 | abort(); |
2077 | } |
2078 | install_operand(s[1],tmpreg); |
2079 | break; |
2080 | |
2081 | case 'X': |
2082 | switch (opP->reg) { |
2083 | case BAD: case BAD+1: case BAD+2: case BAD+3: |
2084 | case BAD+4: case BAD+5: case BAD+6: case BAD+7: |
2085 | tmpreg = (4 << 10) | ((opP->reg - BAD) << 2); |
2086 | break; |
2087 | |
2088 | case BAC: case BAC+1: case BAC+2: case BAC+3: |
2089 | case BAC+4: case BAC+5: case BAC+6: case BAC+7: |
2090 | tmpreg = (5 << 10) | ((opP->reg - BAC) << 2); |
2091 | break; |
2092 | |
2093 | default: |
2094 | abort(); |
2095 | } |
2096 | install_operand(s[1], tmpreg); |
2097 | break; |
2098 | case 'Y': |
2099 | if (opP->reg == PSR) |
2100 | break; |
2101 | abort(); |
2102 | |
2103 | case 'Z': |
2104 | if (opP->reg == PCSR) |
2105 | break; |
2106 | abort(); |
2107 | #endif /* m68851 */ |
2108 | default: |
2109 | as_fatal("Internal error: Operand type %c unknown in line %s of file \"%s\"", s[0], __LINE__, __FILE__); |
2110 | } |
2111 | } |
2112 | /* By the time whe get here (FINALLY) the_ins contains the complete |
2113 | instruction, ready to be emitted. . . */ |
2114 | } |
2115 | |
2116 | static int get_regs(i,str,opP) |
2117 | int i; |
2118 | struct m68k_op *opP; |
2119 | char *str; |
2120 | { |
2121 | /* 26, 25, 24, 23-16, 15-8, 0-7 */ |
2122 | /* Low order 24 bits encoded fpc,fps,fpi,fp7-fp0,a7-a0,d7-d0 */ |
2123 | unsigned long cur_regs = 0; |
2124 | int reg1, |
2125 | reg2; |
2126 | |
2127 | #define ADD_REG(x) { if(x==FPI) cur_regs|=(1<<24);\ |
2128 | else if(x==FPS) cur_regs|=(1<<25);\ |
2129 | else if(x==FPC) cur_regs|=(1<<26);\ |
2130 | else cur_regs|=(1<<(x-1)); } |
2131 | |
2132 | reg1=i; |
2133 | for(;;) { |
2134 | if(*str=='/') { |
2135 | ADD_REG(reg1); |
2136 | str++; |
2137 | } else if(*str=='-') { |
2138 | str++; |
2139 | reg2=m68k_reg_parse(&str); |
2140 | if(reg2<DATA || reg2>=FPREG+8 || reg1==FPI || reg1==FPS || reg1==FPC) { |
2141 | opP->error="unknown register in register list"; |
2142 | return FAIL; |
2143 | } |
2144 | while(reg1<=reg2) { |
2145 | ADD_REG(reg1); |
2146 | reg1++; |
2147 | } |
2148 | if(*str=='\0') |
2149 | break; |
2150 | } else if(*str=='\0') { |
2151 | ADD_REG(reg1); |
2152 | break; |
2153 | } else { |
2154 | opP->error="unknow character in register list"; |
2155 | return FAIL; |
2156 | } |
2157 | /* DJA -- Bug Fix. Did't handle d1-d2/a1 until the following instruction was added */ |
2158 | if (*str=='/') |
2159 | str ++; |
2160 | reg1=m68k_reg_parse(&str); |
2161 | if((reg1<DATA || reg1>=FPREG+8) && !(reg1==FPI || reg1==FPS || reg1==FPC)) { |
2162 | opP->error="unknown register in register list"; |
2163 | return FAIL; |
2164 | } |
2165 | } |
2166 | opP->reg=cur_regs; |
2167 | return OK; |
2168 | } /* get_regs() */ |
2169 | |
2170 | static int reverse_16_bits(in) |
2171 | int in; |
2172 | { |
2173 | int out=0; |
2174 | int n; |
2175 | |
2176 | static int mask[16] = { |
2177 | 0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080, |
2178 | 0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000 |
2179 | }; |
2180 | for(n=0;n<16;n++) { |
2181 | if(in&mask[n]) |
2182 | out|=mask[15-n]; |
2183 | } |
2184 | return out; |
2185 | } /* reverse_16_bits() */ |
2186 | |
2187 | static int reverse_8_bits(in) |
2188 | int in; |
2189 | { |
2190 | int out=0; |
2191 | int n; |
2192 | |
2193 | static int mask[8] = { |
2194 | 0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080, |
2195 | }; |
2196 | |
2197 | for(n=0;n<8;n++) { |
2198 | if(in&mask[n]) |
2199 | out|=mask[7-n]; |
2200 | } |
2201 | return out; |
2202 | } /* reverse_8_bits() */ |
2203 | |
2204 | static void install_operand(mode,val) |
2205 | int mode; |
2206 | int val; |
2207 | { |
2208 | switch(mode) { |
2209 | case 's': |
2210 | the_ins.opcode[0]|=val & 0xFF; /* JF FF is for M kludge */ |
2211 | break; |
2212 | case 'd': |
2213 | the_ins.opcode[0]|=val<<9; |
2214 | break; |
2215 | case '1': |
2216 | the_ins.opcode[1]|=val<<12; |
2217 | break; |
2218 | case '2': |
2219 | the_ins.opcode[1]|=val<<6; |
2220 | break; |
2221 | case '3': |
2222 | the_ins.opcode[1]|=val; |
2223 | break; |
2224 | case '4': |
2225 | the_ins.opcode[2]|=val<<12; |
2226 | break; |
2227 | case '5': |
2228 | the_ins.opcode[2]|=val<<6; |
2229 | break; |
2230 | case '6': |
2231 | /* DANGER! This is a hack to force cas2l and cas2w cmds |
2232 | to be three words long! */ |
2233 | the_ins.numo++; |
2234 | the_ins.opcode[2]|=val; |
2235 | break; |
2236 | case '7': |
2237 | the_ins.opcode[1]|=val<<7; |
2238 | break; |
2239 | case '8': |
2240 | the_ins.opcode[1]|=val<<10; |
2241 | break; |
2242 | #ifdef m68851 |
2243 | case '9': |
2244 | the_ins.opcode[1]|=val<<5; |
2245 | break; |
2246 | #endif |
2247 | |
2248 | case 't': |
2249 | the_ins.opcode[1]|=(val<<10)|(val<<7); |
2250 | break; |
2251 | case 'D': |
2252 | the_ins.opcode[1]|=(val<<12)|val; |
2253 | break; |
2254 | case 'g': |
2255 | the_ins.opcode[0]|=val=0xff; |
2256 | break; |
2257 | case 'i': |
2258 | the_ins.opcode[0]|=val<<9; |
2259 | break; |
2260 | case 'C': |
2261 | the_ins.opcode[1]|=val; |
2262 | break; |
2263 | case 'j': |
2264 | the_ins.opcode[1]|=val; |
2265 | the_ins.numo++; /* What a hack */ |
2266 | break; |
2267 | case 'k': |
2268 | the_ins.opcode[1]|=val<<4; |
2269 | break; |
2270 | case 'b': |
2271 | case 'w': |
2272 | case 'l': |
2273 | break; |
2274 | case 'c': |
2275 | default: |
2276 | abort(); |
2277 | } |
2278 | } /* install_operand() */ |
2279 | |
2280 | static void install_gen_operand(mode,val) |
2281 | int mode; |
2282 | int val; |
2283 | { |
2284 | switch(mode) { |
2285 | case 's': |
2286 | the_ins.opcode[0]|=val; |
2287 | break; |
2288 | case 'd': |
2289 | /* This is a kludge!!! */ |
2290 | the_ins.opcode[0]|=(val&0x07)<<9|(val&0x38)<<3; |
2291 | break; |
2292 | case 'b': |
2293 | case 'w': |
2294 | case 'l': |
2295 | case 'f': |
2296 | case 'F': |
2297 | case 'x': |
2298 | case 'p': |
2299 | the_ins.opcode[0]|=val; |
2300 | break; |
2301 | /* more stuff goes here */ |
2302 | default: |
2303 | abort(); |
2304 | } |
2305 | } /* install_gen_operand() */ |
2306 | |
2307 | static char *crack_operand(str,opP) |
2308 | register char *str; |
2309 | register struct m68k_op *opP; |
2310 | { |
2311 | register int parens; |
2312 | register int c; |
2313 | register char *beg_str; |
2314 | |
2315 | if(!str) { |
2316 | return str; |
2317 | } |
2318 | beg_str=str; |
2319 | for(parens=0;*str && (parens>0 || notend(str));str++) { |
2320 | if(*str=='(') parens++; |
2321 | else if(*str==')') { |
2322 | if(!parens) { /* ERROR */ |
2323 | opP->error="Extra )"; |
2324 | return str; |
2325 | } |
2326 | --parens; |
2327 | } |
2328 | } |
2329 | if(!*str && parens) { /* ERROR */ |
2330 | opP->error="Missing )"; |
2331 | return str; |
2332 | } |
2333 | c= *str; |
2334 | *str='\0'; |
2335 | if(m68k_ip_op(beg_str,opP)==FAIL) { |
2336 | *str=c; |
2337 | return str; |
2338 | } |
2339 | *str=c; |
2340 | if(c=='}') |
2341 | c= *++str; /* JF bitfield hack */ |
2342 | if(c) { |
2343 | c= *++str; |
2344 | if(!c) |
2345 | as_bad("Missing operand"); |
2346 | } |
2347 | return str; |
2348 | } |
2349 | |
2350 | /* See the comment up above where the #define notend(... is */ |
2351 | #if 0 |
2352 | notend(s) |
2353 | char *s; |
2354 | { |
2355 | if(*s==',') return 0; |
2356 | if(*s=='{' || *s=='}') |
2357 | return 0; |
2358 | if(*s!=':') return 1; |
2359 | /* This kludge here is for the division cmd, which is a kludge */ |
2360 | if(strchr("aAdD#",s[1])) return 0; |
2361 | return 1; |
2362 | } |
2363 | #endif |
2364 | |
2365 | /* This is the guts of the machine-dependent assembler. STR points to a |
2366 | machine dependent instruction. This funciton is supposed to emit |
2367 | the frags/bytes it assembles to. |
2368 | */ |
2369 | void |
2370 | md_assemble(str) |
2371 | char *str; |
2372 | { |
2373 | char *er; |
2374 | short *fromP; |
2375 | char *toP; |
2376 | int m,n; |
2377 | char *to_beg_P; |
2378 | int shorts_this_frag; |
2379 | |
2380 | bzero((char *)(&the_ins),sizeof(the_ins)); /* JF for paranoia sake */ |
2381 | m68_ip(str); |
2382 | er=the_ins.error; |
2383 | if(!er) { |
2384 | for(n=the_ins.numargs;n;--n) |
2385 | if(the_ins.operands[n].error) { |
2386 | er=the_ins.operands[n].error; |
2387 | break; |
2388 | } |
2389 | } |
2390 | if(er) { |
2391 | as_bad("\"%s\" -- Statement '%s' ignored",er,str); |
2392 | return; |
2393 | } |
2394 | |
2395 | if(the_ins.nfrag==0) { /* No frag hacking involved; just put it out */ |
2396 | toP=frag_more(2*the_ins.numo); |
2397 | fromP= &the_ins.opcode[0]; |
2398 | for(m=the_ins.numo;m;--m) { |
2399 | md_number_to_chars(toP,(long)(*fromP),2); |
2400 | toP+=2; |
2401 | fromP++; |
2402 | } |
2403 | /* put out symbol-dependent info */ |
2404 | for(m=0;m<the_ins.nrel;m++) { |
2405 | switch(the_ins.reloc[m].wid) { |
2406 | case 'B': |
2407 | n=1; |
2408 | break; |
2409 | case 'b': |
2410 | n=1; |
2411 | break; |
2412 | case '3': |
2413 | n=2; |
2414 | break; |
2415 | case 'w': |
2416 | n=2; |
2417 | break; |
2418 | case 'l': |
2419 | n=4; |
2420 | break; |
2421 | default: |
2422 | as_fatal("Don't know how to figure width of %c in md_assemble()",the_ins.reloc[m].wid); |
2423 | } |
2424 | |
2425 | fix_new(frag_now, |
2426 | (toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n, |
2427 | n, |
2428 | the_ins.reloc[m].add, |
2429 | the_ins.reloc[m].sub, |
2430 | the_ins.reloc[m].off, |
2431 | the_ins.reloc[m].pcrel, |
2432 | NO_RELOC); |
2433 | } |
2434 | return; |
2435 | } |
2436 | |
2437 | /* There's some frag hacking */ |
2438 | for(n=0,fromP= &the_ins.opcode[0];n<the_ins.nfrag;n++) { |
2439 | int wid; |
2440 | |
2441 | if(n==0) wid=2*the_ins.fragb[n].fragoff; |
2442 | else wid=2*(the_ins.numo-the_ins.fragb[n-1].fragoff); |
2443 | toP=frag_more(wid); |
2444 | to_beg_P=toP; |
2445 | shorts_this_frag=0; |
2446 | for(m=wid/2;m;--m) { |
2447 | md_number_to_chars(toP,(long)(*fromP),2); |
2448 | toP+=2; |
2449 | fromP++; |
2450 | shorts_this_frag++; |
2451 | } |
2452 | for(m=0;m<the_ins.nrel;m++) { |
2453 | if((the_ins.reloc[m].n)>= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */) { |
2454 | the_ins.reloc[m].n-= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */; |
2455 | break; |
2456 | } |
2457 | wid=the_ins.reloc[m].wid; |
2458 | if(wid==0) |
2459 | continue; |
2460 | the_ins.reloc[m].wid=0; |
2461 | wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000; |
2462 | |
2463 | fix_new(frag_now, |
2464 | (toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n, |
2465 | wid, |
2466 | the_ins.reloc[m].add, |
2467 | the_ins.reloc[m].sub, |
2468 | the_ins.reloc[m].off, |
2469 | the_ins.reloc[m].pcrel, |
2470 | NO_RELOC); |
2471 | } |
2472 | know(the_ins.fragb[n].fadd); |
2473 | (void)frag_var(rs_machine_dependent,10,0,(relax_substateT)(the_ins.fragb[n].fragty), |
2474 | the_ins.fragb[n].fadd,the_ins.fragb[n].foff,to_beg_P); |
2475 | } |
2476 | n=(the_ins.numo-the_ins.fragb[n-1].fragoff); |
2477 | shorts_this_frag=0; |
2478 | if(n) { |
2479 | toP=frag_more(n*sizeof(short)); |
2480 | while(n--) { |
2481 | md_number_to_chars(toP,(long)(*fromP),2); |
2482 | toP+=2; |
2483 | fromP++; |
2484 | shorts_this_frag++; |
2485 | } |
2486 | } |
2487 | for(m=0;m<the_ins.nrel;m++) { |
2488 | int wid; |
2489 | |
2490 | wid=the_ins.reloc[m].wid; |
2491 | if(wid==0) |
2492 | continue; |
2493 | the_ins.reloc[m].wid=0; |
2494 | wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000; |
2495 | |
2496 | fix_new(frag_now, |
2497 | (the_ins.reloc[m].n + toP-frag_now->fr_literal)-/* the_ins.numo */ shorts_this_frag*2, |
2498 | wid, |
2499 | the_ins.reloc[m].add, |
2500 | the_ins.reloc[m].sub, |
2501 | the_ins.reloc[m].off, |
2502 | the_ins.reloc[m].pcrel, |
2503 | NO_RELOC); |
2504 | } |
2505 | } |
2506 | |
2507 | /* This function is called once, at assembler startup time. This should |
2508 | set up all the tables, etc that the MD part of the assembler needs |
2509 | */ |
2510 | void |
2511 | md_begin() |
2512 | { |
2513 | /* |
2514 | * md_begin -- set up hash tables with 68000 instructions. |
2515 | * similar to what the vax assembler does. ---phr |
2516 | */ |
2517 | /* RMS claims the thing to do is take the m68k-opcode.h table, and make |
2518 | a copy of it at runtime, adding in the information we want but isn't |
2519 | there. I think it'd be better to have an awk script hack the table |
2520 | at compile time. Or even just xstr the table and use it as-is. But |
2521 | my lord ghod hath spoken, so we do it this way. Excuse the ugly var |
2522 | names. */ |
2523 | |
2524 | register const struct m68k_opcode *ins; |
2525 | register struct m68_incant *hack, |
2526 | *slak; |
2527 | register char *retval = 0; /* empty string, or error msg text */ |
2528 | register unsigned int i; |
2529 | register char c; |
2530 | |
2531 | if ((op_hash = hash_new()) == NULL) |
2532 | as_fatal("Virtual memory exhausted"); |
2533 | |
2534 | obstack_begin(&robyn,4000); |
2535 | for (ins = m68k_opcodes; ins < endop; ins++) { |
2536 | hack=slak=(struct m68_incant *)obstack_alloc(&robyn,sizeof(struct m68_incant)); |
2537 | do { |
2538 | slak->m_operands=ins->args; |
2539 | slak->m_opnum=strlen(slak->m_operands)/2; |
2540 | slak->m_opcode=ins->opcode; |
2541 | /* This is kludgey */ |
2542 | slak->m_codenum=((ins->match)&0xffffL) ? 2 : 1; |
2543 | if((ins+1)!=endop && !strcmp(ins->name,(ins+1)->name)) { |
2544 | slak->m_next=(struct m68_incant *) |
2545 | obstack_alloc(&robyn,sizeof(struct m68_incant)); |
2546 | ins++; |
2547 | } else |
2548 | slak->m_next=0; |
2549 | slak=slak->m_next; |
2550 | } while(slak); |
2551 | |
2552 | retval = hash_insert (op_hash, ins->name,(char *)hack); |
2553 | /* Didn't his mommy tell him about null pointers? */ |
2554 | if(retval && *retval) |
2555 | as_fatal("Internal Error: Can't hash %s: %s", ins->name,retval); |
2556 | } |
2557 | |
2558 | for (i = 0; i < sizeof(mklower_table) ; i++) |
2559 | mklower_table[i] = (isupper(c = (char) i)) ? tolower(c) : c; |
2560 | |
2561 | for (i = 0 ; i < sizeof(notend_table) ; i++) { |
2562 | notend_table[i] = 0; |
2563 | alt_notend_table[i] = 0; |
2564 | } |
2565 | notend_table[','] = 1; |
2566 | notend_table['{'] = 1; |
2567 | notend_table['}'] = 1; |
2568 | alt_notend_table['a'] = 1; |
2569 | alt_notend_table['A'] = 1; |
2570 | alt_notend_table['d'] = 1; |
2571 | alt_notend_table['D'] = 1; |
2572 | alt_notend_table['#'] = 1; |
2573 | alt_notend_table['f'] = 1; |
2574 | alt_notend_table['F'] = 1; |
2575 | #ifdef REGISTER_PREFIX |
2576 | alt_notend_table[REGISTER_PREFIX] = 1; |
2577 | #endif |
2578 | } |
2579 | |
2580 | #if 0 |
2581 | #define notend(s) ((*s == ',' || *s == '}' || *s == '{' \ |
2582 | || (*s == ':' && strchr("aAdD#", s[1]))) \ |
2583 | ? 0 : 1) |
2584 | #endif |
2585 | |
2586 | /* This funciton is called once, before the assembler exits. It is |
2587 | supposed to do any final cleanup for this part of the assembler. |
2588 | */ |
2589 | void |
2590 | md_end() |
2591 | { |
2592 | } |
2593 | |
2594 | /* Equal to MAX_PRECISION in atof-ieee.c */ |
2595 | #define MAX_LITTLENUMS 6 |
2596 | |
2597 | /* Turn a string in input_line_pointer into a floating point constant of type |
2598 | type, and store the appropriate bytes in *litP. The number of LITTLENUMS |
2599 | emitted is stored in *sizeP . An error message is returned, or NULL on OK. |
2600 | */ |
2601 | char * |
2602 | md_atof(type,litP,sizeP) |
2603 | char type; |
2604 | char *litP; |
2605 | int *sizeP; |
2606 | { |
2607 | int prec; |
2608 | LITTLENUM_TYPE words[MAX_LITTLENUMS]; |
2609 | LITTLENUM_TYPE *wordP; |
2610 | char *t; |
2611 | |
2612 | switch(type) { |
2613 | case 'f': |
2614 | case 'F': |
2615 | case 's': |
2616 | case 'S': |
2617 | prec = 2; |
2618 | break; |
2619 | |
2620 | case 'd': |
2621 | case 'D': |
2622 | case 'r': |
2623 | case 'R': |
2624 | prec = 4; |
2625 | break; |
2626 | |
2627 | case 'x': |
2628 | case 'X': |
2629 | prec = 6; |
2630 | break; |
2631 | |
2632 | case 'p': |
2633 | case 'P': |
2634 | prec = 6; |
2635 | break; |
2636 | |
2637 | default: |
2638 | *sizeP=0; |
2639 | return "Bad call to MD_ATOF()"; |
2640 | } |
2641 | t=atof_ieee(input_line_pointer,type,words); |
2642 | if(t) |
2643 | input_line_pointer=t; |
2644 | |
2645 | *sizeP=prec * sizeof(LITTLENUM_TYPE); |
2646 | for(wordP=words;prec--;) { |
2647 | md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE)); |
2648 | litP+=sizeof(LITTLENUM_TYPE); |
2649 | } |
2650 | return ""; /* Someone should teach Dean about null pointers */ |
2651 | } |
2652 | |
2653 | /* Turn an integer of n bytes (in val) into a stream of bytes appropriate |
2654 | for use in the a.out file, and stores them in the array pointed to by buf. |
2655 | This knows about the endian-ness of the target machine and does |
2656 | THE RIGHT THING, whatever it is. Possible values for n are 1 (byte) |
2657 | 2 (short) and 4 (long) Floating numbers are put out as a series of |
2658 | LITTLENUMS (shorts, here at least) |
2659 | */ |
2660 | void |
2661 | md_number_to_chars(buf,val,n) |
2662 | char *buf; |
2663 | long val; |
2664 | int n; |
2665 | { |
2666 | switch(n) { |
2667 | case 1: |
2668 | *buf++=val; |
2669 | break; |
2670 | case 2: |
2671 | *buf++=(val>>8); |
2672 | *buf++=val; |
2673 | break; |
2674 | case 4: |
2675 | *buf++=(val>>24); |
2676 | *buf++=(val>>16); |
2677 | *buf++=(val>>8); |
2678 | *buf++=val; |
2679 | break; |
2680 | default: |
2681 | abort(); |
2682 | } |
2683 | } |
2684 | |
2685 | void |
2686 | md_apply_fix(fixP, val) |
2687 | fixS *fixP; |
2688 | long val; |
2689 | { |
2690 | char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; |
2691 | |
2692 | switch(fixP->fx_size) { |
2693 | case 1: |
2694 | *buf++=val; |
2695 | break; |
2696 | case 2: |
2697 | *buf++=(val>>8); |
2698 | *buf++=val; |
2699 | break; |
2700 | case 4: |
2701 | *buf++=(val>>24); |
2702 | *buf++=(val>>16); |
2703 | *buf++=(val>>8); |
2704 | *buf++=val; |
2705 | break; |
2706 | default: |
2707 | BAD_CASE (fixP->fx_size); |
2708 | } |
2709 | } |
2710 | |
2711 | |
2712 | /* *fragP has been relaxed to its final size, and now needs to have |
2713 | the bytes inside it modified to conform to the new size There is UGLY |
2714 | MAGIC here. .. |
2715 | */ |
2716 | void |
2717 | md_convert_frag(fragP) |
2718 | register fragS *fragP; |
2719 | { |
2720 | long disp; |
2721 | long ext; |
2722 | |
2723 | /* Address in gas core of the place to store the displacement. */ |
2724 | register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal; |
2725 | /* Address in object code of the displacement. */ |
2726 | register int object_address = fragP -> fr_fix + fragP -> fr_address; |
2727 | |
2728 | know(fragP->fr_symbol); |
2729 | |
2730 | /* The displacement of the address, from current location. */ |
2731 | disp = (S_GET_VALUE(fragP->fr_symbol) + fragP->fr_offset) - object_address; |
2732 | |
2733 | switch(fragP->fr_subtype) { |
2734 | case TAB(BCC68000,BYTE): |
2735 | case TAB(BRANCH,BYTE): |
2736 | know(issbyte(disp)); |
2737 | if(disp==0) |
2738 | as_bad("short branch with zero offset: use :w"); |
2739 | fragP->fr_opcode[1]=disp; |
2740 | ext=0; |
2741 | break; |
2742 | case TAB(DBCC,SHORT): |
2743 | know(issword(disp)); |
2744 | ext=2; |
2745 | break; |
2746 | case TAB(BCC68000,SHORT): |
2747 | case TAB(BRANCH,SHORT): |
2748 | know(issword(disp)); |
2749 | fragP->fr_opcode[1]=0x00; |
2750 | ext=2; |
2751 | break; |
2752 | case TAB(BRANCH,LONG): |
2753 | if(flagseen['m']) { |
2754 | if(fragP->fr_opcode[0]==0x61) { |
2755 | fragP->fr_opcode[0]= 0x4E; |
2756 | fragP->fr_opcode[1]= 0xB9; /* JSR with ABSL LONG offset */ |
2757 | subseg_change(SEG_TEXT, 0); |
2758 | |
2759 | fix_new(fragP, |
2760 | fragP->fr_fix, |
2761 | 4, |
2762 | fragP->fr_symbol, |
2763 | 0, |
2764 | fragP->fr_offset, |
2765 | 0, |
2766 | NO_RELOC); |
2767 | |
2768 | fragP->fr_fix+=4; |
2769 | ext=0; |
2770 | } else if(fragP->fr_opcode[0]==0x60) { |
2771 | fragP->fr_opcode[0]= 0x4E; |
2772 | fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */ |
2773 | subseg_change(SEG_TEXT, 0); |
2774 | fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0, |
2775 | NO_RELOC); |
2776 | fragP->fr_fix+=4; |
2777 | ext=0; |
2778 | }else { |
2779 | as_bad("Long branch offset not supported."); |
2780 | } |
2781 | } else { |
2782 | fragP->fr_opcode[1]=0xff; |
2783 | ext=4; |
2784 | } |
2785 | break; |
2786 | case TAB(BCC68000,LONG): |
2787 | /* only Bcc 68000 instructions can come here */ |
2788 | /* change bcc into b!cc/jmp absl long */ |
2789 | fragP->fr_opcode[0] ^= 0x01; /* invert bcc */ |
2790 | fragP->fr_opcode[1] = 0x6; /* branch offset = 6 */ |
2791 | |
2792 | /* JF: these used to be fr_opcode[2,3], but they may be in a |
2793 | different frag, in which case refering to them is a no-no. |
2794 | Only fr_opcode[0,1] are guaranteed to work. */ |
2795 | *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */ |
2796 | *buffer_address++ = 0xf9; |
2797 | fragP->fr_fix += 2; /* account for jmp instruction */ |
2798 | subseg_change(SEG_TEXT,0); |
2799 | fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, |
2800 | fragP->fr_offset,0, |
2801 | NO_RELOC); |
2802 | fragP->fr_fix += 4; |
2803 | ext=0; |
2804 | break; |
2805 | case TAB(DBCC,LONG): |
2806 | /* only DBcc 68000 instructions can come here */ |
2807 | /* change dbcc into dbcc/jmp absl long */ |
2808 | /* JF: these used to be fr_opcode[2-7], but that's wrong */ |
2809 | *buffer_address++ = 0x00; /* branch offset = 4 */ |
2810 | *buffer_address++ = 0x04; |
2811 | *buffer_address++ = 0x60; /* put in bra pc+6 */ |
2812 | *buffer_address++ = 0x06; |
2813 | *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */ |
2814 | *buffer_address++ = 0xf9; |
2815 | |
2816 | fragP->fr_fix += 6; /* account for bra/jmp instructions */ |
2817 | subseg_change(SEG_TEXT,0); |
2818 | fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, |
2819 | fragP->fr_offset,0, |
2820 | NO_RELOC); |
2821 | fragP->fr_fix += 4; |
2822 | ext=0; |
2823 | break; |
2824 | case TAB(FBRANCH,SHORT): |
2825 | know((fragP->fr_opcode[1]&0x40)==0); |
2826 | ext=2; |
2827 | break; |
2828 | case TAB(FBRANCH,LONG): |
2829 | fragP->fr_opcode[1]|=0x40; /* Turn on LONG bit */ |
2830 | ext=4; |
2831 | break; |
2832 | case TAB(PCREL,SHORT): |
2833 | ext=2; |
2834 | break; |
2835 | case TAB(PCREL,LONG): |
2836 | /* FIXME-SOMEDAY, this should allow pcrel-long to be generated if -pic is on. |
2837 | Else we can't handle position independent code. Pcrel-long costs an |
2838 | extra index word though. Doing it requires more relax tables and |
2839 | stuff elsewhere in this module though. */ |
2840 | /* The thing to do here is force it to ABSOLUTE LONG, since |
2841 | PCREL is really trying to shorten an ABSOLUTE address anyway */ |
2842 | subseg_change(SEG_TEXT,0); |
2843 | fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0, |
2844 | NO_RELOC); |
2845 | if((fragP->fr_opcode[1] & 0x3F) != 0x3A) |
2846 | as_bad("Internal error (long PC-relative operand) for insn 0x%04lx at 0x%lx", |
2847 | fragP->fr_opcode[0],fragP->fr_address); |
2848 | fragP->fr_opcode[1]&= ~0x3F; |
2849 | fragP->fr_opcode[1]|=0x39; /* Mode 7.1 */ |
2850 | fragP->fr_fix+=4; |
2851 | ext=0; |
2852 | break; |
2853 | case TAB(PCLEA,SHORT): |
2854 | subseg_change(SEG_TEXT,0); |
2855 | fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset,1, |
2856 | NO_RELOC); |
2857 | fragP->fr_opcode[1] &= ~0x3F; |
2858 | fragP->fr_opcode[1] |= 0x3A; |
2859 | ext=2; |
2860 | break; |
2861 | case TAB(PCLEA,LONG): |
2862 | subseg_change(SEG_TEXT,0); |
2863 | fix_new(fragP,(int)(fragP->fr_fix)+2,4,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset+2,1, |
2864 | NO_RELOC); |
2865 | *buffer_address++ = 0x01; |
2866 | *buffer_address++ = 0x70; |
2867 | fragP->fr_fix+=2; |
2868 | /* buffer_address+=2; */ |
2869 | ext=4; |
2870 | break; |
2871 | |
2872 | } |
2873 | if(ext) { |
2874 | md_number_to_chars(buffer_address,(long)disp,(int)ext); |
2875 | fragP->fr_fix+=ext; |
2876 | } |
2877 | } |
2878 | |
2879 | /* Force truly undefined symbols to their maximum size, and generally set up |
2880 | the frag list to be relaxed |
2881 | */ |
2882 | int md_estimate_size_before_relax(fragP, segment) |
2883 | register fragS *fragP; |
2884 | segT segment; |
2885 | { |
2886 | int old_fix; |
2887 | register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal; |
2888 | |
2889 | old_fix=fragP->fr_fix; |
2890 | |
2891 | /* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */ |
2892 | switch(fragP->fr_subtype) { |
2893 | case TAB(BRANCH,SZ_UNDEF): |
2894 | if(S_GET_SEGMENT(fragP->fr_symbol) == segment) { |
2895 | /* Symbol now defined; start at byte-size. */ |
2896 | fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),BYTE); |
2897 | break; |
2898 | } else if(!flagseen['p'] || (!flagseen['l'] && flagseen['m'])) { |
2899 | /* Symbol in another segment, or undef. |
2900 | If we don't care about position independent code, |
2901 | or if we're using long displacements on a 68000, |
2902 | rewrite to short or long absolute. */ |
2903 | if(fragP->fr_opcode[0]==0x61) { |
2904 | if(flagseen['l']) { |
2905 | fragP->fr_opcode[0]= 0x4E; |
2906 | fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL WORD offset */ |
2907 | subseg_change(SEG_TEXT, 0); |
2908 | fix_new(fragP, fragP->fr_fix, 2, |
2909 | fragP->fr_symbol, 0, fragP->fr_offset, 0, |
2910 | NO_RELOC); |
2911 | fragP->fr_fix+=2; |
2912 | } else { |
2913 | fragP->fr_opcode[0]= 0x4E; |
2914 | fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL LONG offset */ |
2915 | subseg_change(SEG_TEXT, 0); |
2916 | fix_new(fragP, fragP->fr_fix, 4, |
2917 | fragP->fr_symbol, 0, fragP->fr_offset, 0, |
2918 | NO_RELOC); |
2919 | fragP->fr_fix+=4; |
2920 | } |
2921 | frag_wane(fragP); |
2922 | } else if(fragP->fr_opcode[0]==0x60) { |
2923 | if(flagseen['l']) { |
2924 | fragP->fr_opcode[0]= 0x4E; |
2925 | fragP->fr_opcode[1]= 0xF8; /* JMP with ABSL WORD offset */ |
2926 | subseg_change(SEG_TEXT, 0); |
2927 | fix_new(fragP, fragP->fr_fix, 2, |
2928 | fragP->fr_symbol, 0, fragP->fr_offset, 0, |
2929 | NO_RELOC); |
2930 | fragP->fr_fix+=2; |
2931 | } else { |
2932 | fragP->fr_opcode[0]= 0x4E; |
2933 | fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */ |
2934 | subseg_change(SEG_TEXT, 0); |
2935 | fix_new(fragP, fragP->fr_fix, 4, |
2936 | fragP->fr_symbol, 0, fragP->fr_offset, 0, |
2937 | NO_RELOC); |
2938 | fragP->fr_fix+=4; |
2939 | } |
2940 | frag_wane(fragP); |
2941 | } else { |
2942 | as_bad("Long branch offset to extern symbol not supported."); |
2943 | } |
2944 | } else if(flagseen['l']) { |
2945 | /* Symbol in other seg or undefined, and user |
2946 | wants short pcrel offsets (-l). Set size to 2, fix |
2947 | pcrel displacement after relax. */ |
2948 | fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol, |
2949 | (symbolS *)0,fragP->fr_offset+2,1, |
2950 | NO_RELOC); |
2951 | fragP->fr_fix+=2; |
2952 | fragP->fr_opcode[1]=0x00; |
2953 | frag_wane(fragP); |
2954 | } else { |
2955 | /* Symbol in other seg or undefined, and user |
2956 | wants long pcrel offsets. Set size to 4, and fix |
2957 | pcrel displacement after relax. */ |
2958 | fix_new(fragP,(int)(fragP->fr_fix),4,fragP->fr_symbol, |
2959 | (symbolS *)0,fragP->fr_offset + 4,1, |
2960 | NO_RELOC); |
2961 | fragP->fr_fix+=4; |
2962 | fragP->fr_opcode[1]=0xff; |
2963 | frag_wane(fragP); |
2964 | break; |
2965 | } |
2966 | break; |
2967 | |
2968 | case TAB(FBRANCH,SZ_UNDEF): |
2969 | if(S_GET_SEGMENT(fragP->fr_symbol) == segment |
2970 | || flagseen['l']) { |
2971 | fragP->fr_subtype=TAB(FBRANCH,SHORT); |
2972 | fragP->fr_var+=2; |
2973 | } else { |
2974 | fragP->fr_subtype=TAB(FBRANCH,LONG); |
2975 | fragP->fr_var+=4; |
2976 | } |
2977 | break; |
2978 | |
2979 | case TAB(PCREL,SZ_UNDEF): |
2980 | if(S_GET_SEGMENT(fragP->fr_symbol) == segment |
2981 | || flagseen['l']) { |
2982 | fragP->fr_subtype=TAB(PCREL,SHORT); |
2983 | fragP->fr_var+=2; |
2984 | } else { |
2985 | fragP->fr_subtype=TAB(PCREL,LONG); |
2986 | fragP->fr_var+=4; |
2987 | } |
2988 | break; |
2989 | |
2990 | case TAB(BCC68000,SZ_UNDEF): |
2991 | if(S_GET_SEGMENT(fragP->fr_symbol) == segment) { |
2992 | fragP->fr_subtype=TAB(BCC68000,BYTE); |
2993 | break; |
2994 | } |
2995 | /* only Bcc 68000 instructions can come here */ |
2996 | /* change bcc into b!cc/jmp absl long */ |
2997 | fragP->fr_opcode[0] ^= 0x01; /* invert bcc */ |
2998 | if(flagseen['l']) { |
2999 | fragP->fr_opcode[1] = 0x04; /* branch offset = 6 */ |
3000 | /* JF: these were fr_opcode[2,3] */ |
3001 | buffer_address[0] = 0x4e; /* put in jmp long (0x4ef9) */ |
3002 | buffer_address[1] = 0xf8; |
3003 | fragP->fr_fix += 2; /* account for jmp instruction */ |
3004 | subseg_change(SEG_TEXT,0); |
3005 | fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0, |
3006 | fragP->fr_offset,0, |
3007 | NO_RELOC); |
3008 | fragP->fr_fix += 2; |
3009 | } else { |
3010 | fragP->fr_opcode[1] = 0x06; /* branch offset = 6 */ |
3011 | /* JF: these were fr_opcode[2,3] */ |
3012 | buffer_address[2] = 0x4e; /* put in jmp long (0x4ef9) */ |
3013 | buffer_address[3] = 0xf9; |
3014 | fragP->fr_fix += 2; /* account for jmp instruction */ |
3015 | subseg_change(SEG_TEXT,0); |
3016 | fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, |
3017 | fragP->fr_offset,0, |
3018 | NO_RELOC); |
3019 | fragP->fr_fix += 4; |
3020 | } |
3021 | frag_wane(fragP); |
3022 | break; |
3023 | |
3024 | case TAB(DBCC,SZ_UNDEF): |
3025 | if(S_GET_SEGMENT(fragP->fr_symbol) == segment) { |
3026 | fragP->fr_subtype=TAB(DBCC,SHORT); |
3027 | fragP->fr_var+=2; |
3028 | break; |
3029 | } |
3030 | /* only DBcc 68000 instructions can come here */ |
3031 | /* change dbcc into dbcc/jmp absl long */ |
3032 | /* JF: these used to be fr_opcode[2-4], which is wrong. */ |
3033 | buffer_address[0] = 0x00; /* branch offset = 4 */ |
3034 | buffer_address[1] = 0x04; |
3035 | buffer_address[2] = 0x60; /* put in bra pc + ... */ |
3036 | if(flagseen['l']) { |
3037 | /* JF: these were fr_opcode[5-7] */ |
3038 | buffer_address[3] = 0x04; /* plus 4 */ |
3039 | buffer_address[4] = 0x4e;/* Put in Jump Word */ |
3040 | buffer_address[5] = 0xf8; |
3041 | fragP->fr_fix += 6; /* account for bra/jmp instruction */ |
3042 | subseg_change(SEG_TEXT,0); |
3043 | fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0, |
3044 | fragP->fr_offset,0, |
3045 | NO_RELOC); |
3046 | fragP->fr_fix+=2; |
3047 | } else { |
3048 | /* JF: these were fr_opcode[5-7] */ |
3049 | buffer_address[3] = 0x06; /* Plus 6 */ |
3050 | buffer_address[4] = 0x4e; /* put in jmp long (0x4ef9) */ |
3051 | buffer_address[5] = 0xf9; |
3052 | fragP->fr_fix += 6; /* account for bra/jmp instruction */ |
3053 | subseg_change(SEG_TEXT,0); |
3054 | fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, |
3055 | fragP->fr_offset,0, |
3056 | NO_RELOC); |
3057 | fragP->fr_fix += 4; |
3058 | } |
3059 | frag_wane(fragP); |
3060 | break; |
3061 | |
3062 | case TAB(PCLEA,SZ_UNDEF): |
3063 | if((S_GET_SEGMENT(fragP->fr_symbol))==segment || flagseen['l']) { |
3064 | fragP->fr_subtype=TAB(PCLEA,SHORT); |
3065 | fragP->fr_var+=2; |
3066 | } else { |
3067 | fragP->fr_subtype=TAB(PCLEA,LONG); |
3068 | fragP->fr_var+=6; |
3069 | } |
3070 | break; |
3071 | |
3072 | default: |
3073 | break; |
3074 | } |
3075 | |
3076 | /* now that SZ_UNDEF are taken care of, check others */ |
3077 | switch(fragP->fr_subtype) { |
3078 | case TAB(BCC68000,BYTE): |
3079 | case TAB(BRANCH,BYTE): |
3080 | /* We can't do a short jump to the next instruction, |
3081 | so we force word mode. */ |
3082 | if(fragP->fr_symbol && S_GET_VALUE(fragP->fr_symbol)==0 && |
3083 | fragP->fr_symbol->sy_frag==fragP->fr_next) { |
3084 | fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),SHORT); |
3085 | fragP->fr_var+=2; |
3086 | } |
3087 | break; |
3088 | default: |
3089 | break; |
3090 | } |
3091 | return fragP->fr_var + fragP->fr_fix - old_fix; |
3092 | } |
3093 | |
3094 | #if defined(OBJ_AOUT) | defined(OBJ_BOUT) |
3095 | /* the bit-field entries in the relocation_info struct plays hell |
3096 | with the byte-order problems of cross-assembly. So as a hack, |
3097 | I added this mach. dependent ri twiddler. Ugly, but it gets |
3098 | you there. -KWK */ |
3099 | /* on m68k: first 4 bytes are normal unsigned long, next three bytes |
3100 | are symbolnum, most sig. byte first. Last byte is broken up with |
3101 | bit 7 as pcrel, bits 6 & 5 as length, bit 4 as pcrel, and the lower |
3102 | nibble as nuthin. (on Sun 3 at least) */ |
3103 | /* Translate the internal relocation information into target-specific |
3104 | format. */ |
3105 | void |
3106 | md_ri_to_chars(the_bytes, ri) |
3107 | char *the_bytes; |
3108 | struct reloc_info_generic *ri; |
3109 | { |
3110 | /* this is easy */ |
3111 | md_number_to_chars(the_bytes, ri->r_address, 4); |
3112 | /* now the fun stuff */ |
3113 | the_bytes[4] = (ri->r_symbolnum >> 16) & 0x0ff; |
3114 | the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff; |
3115 | the_bytes[6] = ri->r_symbolnum & 0x0ff; |
3116 | the_bytes[7] = (((ri->r_pcrel << 7) & 0x80) | ((ri->r_length << 5) & 0x60) | |
3117 | ((ri->r_extern << 4) & 0x10)); |
3118 | } |
3119 | #endif /* OBJ_AOUT or OBJ_BOUT */ |
3120 | |
3121 | #ifndef WORKING_DOT_WORD |
3122 | const int md_short_jump_size = 4; |
3123 | const int md_long_jump_size = 6; |
3124 | |
3125 | void |
3126 | md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol) |
3127 | char *ptr; |
3128 | long from_addr, |
3129 | to_addr; |
3130 | fragS *frag; |
3131 | symbolS *to_symbol; |
3132 | { |
3133 | long offset; |
3134 | |
3135 | offset = to_addr - (from_addr+2); |
3136 | |
3137 | md_number_to_chars(ptr ,(long)0x6000,2); |
3138 | md_number_to_chars(ptr+2,(long)offset,2); |
3139 | } |
3140 | |
3141 | void |
3142 | md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol) |
3143 | char *ptr; |
3144 | long from_addr, |
3145 | to_addr; |
3146 | fragS *frag; |
3147 | symbolS *to_symbol; |
3148 | { |
3149 | long offset; |
3150 | |
3151 | if(flagseen['m']) { |
3152 | offset=to_addr-S_GET_VALUE(to_symbol); |
3153 | md_number_to_chars(ptr ,(long)0x4EF9,2); |
3154 | md_number_to_chars(ptr+2,(long)offset,4); |
3155 | fix_new(frag,(ptr+2)-frag->fr_literal,4,to_symbol,(symbolS *)0,(long)0,0, |
3156 | NO_RELOC); |
3157 | } else { |
3158 | offset=to_addr - (from_addr+2); |
3159 | md_number_to_chars(ptr ,(long)0x60ff,2); |
3160 | md_number_to_chars(ptr+2,(long)offset,4); |
3161 | } |
3162 | } |
3163 | |
3164 | #endif |
3165 | /* Different values of OK tell what its OK to return. Things that aren't OK are an error (what a shock, no?) |
3166 | |
3167 | 0: Everything is OK |
3168 | 10: Absolute 1:8 only |
3169 | 20: Absolute 0:7 only |
3170 | 30: absolute 0:15 only |
3171 | 40: Absolute 0:31 only |
3172 | 50: absolute 0:127 only |
3173 | 55: absolute -64:63 only |
3174 | 60: absolute -128:127 only |
3175 | 70: absolute 0:4095 only |
3176 | 80: No bignums |
3177 | |
3178 | */ |
3179 | |
3180 | static int get_num(exp,ok) |
3181 | struct m68k_exp *exp; |
3182 | int ok; |
3183 | { |
3184 | #ifdef TEST2 |
3185 | long l = 0; |
3186 | |
3187 | if(!exp->e_beg) |
3188 | return 0; |
3189 | if(*exp->e_beg=='0') { |
3190 | if(exp->e_beg[1]=='x') |
3191 | sscanf(exp->e_beg+2,"%x",&l); |
3192 | else |
3193 | sscanf(exp->e_beg+1,"%O",&l); |
3194 | return l; |
3195 | } |
3196 | return atol(exp->e_beg); |
3197 | #else |
3198 | char *save_in; |
3199 | char c_save; |
3200 | |
3201 | if(!exp) { |
3202 | /* Can't do anything */ |
3203 | return 0; |
3204 | } |
3205 | if(!exp->e_beg || !exp->e_end) { |
3206 | seg(exp)=SEG_ABSOLUTE; |
3207 | adds(exp)=0; |
3208 | subs(exp)=0; |
3209 | offs(exp)= (ok==10) ? 1 : 0; |
3210 | as_bad("Null expression defaults to %ld", offs(exp)); |
3211 | return 0; |
3212 | } |
3213 | |
3214 | exp->e_siz=0; |
3215 | if(/* ok!=80 && */exp->e_end[-1]==':' && (exp->e_end-exp->e_beg)>=2) { |
3216 | switch(exp->e_end[0]) { |
3217 | case 's': |
3218 | case 'S': |
3219 | case 'b': |
3220 | case 'B': |
3221 | exp->e_siz=1; |
3222 | break; |
3223 | case 'w': |
3224 | case 'W': |
3225 | exp->e_siz=2; |
3226 | break; |
3227 | case 'l': |
3228 | case 'L': |
3229 | exp->e_siz=3; |
3230 | break; |
3231 | default: |
3232 | as_bad("Unknown size for expression \"%c\"", exp->e_end[0]); |
3233 | } |
3234 | exp->e_end-=2; |
3235 | } |
3236 | c_save=exp->e_end[1]; |
3237 | exp->e_end[1]='\0'; |
3238 | save_in=input_line_pointer; |
3239 | input_line_pointer=exp->e_beg; |
3240 | switch(expression(&(exp->e_exp))) { |
3241 | case SEG_PASS1: |
3242 | seg(exp)=SEG_ABSOLUTE; |
3243 | adds(exp)=0; |
3244 | subs(exp)=0; |
3245 | offs(exp)= (ok==10) ? 1 : 0; |
3246 | as_bad("Unknown expression: '%s' defaulting to %d",exp->e_beg,offs(exp)); |
3247 | break; |
3248 | |
3249 | case SEG_ABSENT: |
3250 | /* Do the same thing the VAX asm does */ |
3251 | seg(exp)=SEG_ABSOLUTE; |
3252 | adds(exp)=0; |
3253 | subs(exp)=0; |
3254 | offs(exp)=0; |
3255 | if(ok==10) { |
3256 | as_bad("expression out of range: defaulting to 1"); |
3257 | offs(exp)=1; |
3258 | } |
3259 | break; |
3260 | case SEG_ABSOLUTE: |
3261 | switch(ok) { |
3262 | case 10: |
3263 | if(offs(exp)<1 || offs(exp)>8) { |
3264 | as_bad("expression out of range: defaulting to 1"); |
3265 | offs(exp)=1; |
3266 | } |
3267 | break; |
3268 | case 20: |
3269 | if(offs(exp)<0 || offs(exp)>7) |
3270 | goto outrange; |
3271 | break; |
3272 | case 30: |
3273 | if(offs(exp)<0 || offs(exp)>15) |
3274 | goto outrange; |
3275 | break; |
3276 | case 40: |
3277 | if(offs(exp)<0 || offs(exp)>32) |
3278 | goto outrange; |
3279 | break; |
3280 | case 50: |
3281 | if(offs(exp)<0 || offs(exp)>127) |
3282 | goto outrange; |
3283 | break; |
3284 | case 55: |
3285 | if(offs(exp)<-64 || offs(exp)>63) |
3286 | goto outrange; |
3287 | break; |
3288 | case 60: |
3289 | if(offs(exp)<-128 || offs(exp)>127) |
3290 | goto outrange; |
3291 | break; |
3292 | case 70: |
3293 | if(offs(exp)<0 || offs(exp)>4095) { |
3294 | outrange: |
3295 | as_bad("expression out of range: defaulting to 0"); |
3296 | offs(exp)=0; |
3297 | } |
3298 | break; |
3299 | default: |
3300 | break; |
3301 | } |
3302 | break; |
3303 | case SEG_TEXT: |
3304 | case SEG_DATA: |
3305 | case SEG_BSS: |
3306 | case SEG_UNKNOWN: |
3307 | case SEG_DIFFERENCE: |
3308 | if(ok>=10 && ok<=70) { |
3309 | seg(exp)=SEG_ABSOLUTE; |
3310 | adds(exp)=0; |
3311 | subs(exp)=0; |
3312 | offs(exp)= (ok==10) ? 1 : 0; |
3313 | as_bad("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp)); |
3314 | } |
3315 | break; |
3316 | case SEG_BIG: |
3317 | if(ok==80 && offs(exp)<0) { /* HACK! Turn it into a long */ |
3318 | LITTLENUM_TYPE words[6]; |
3319 | |
3320 | gen_to_words(words,2,8L);/* These numbers are magic! */ |
3321 | seg(exp)=SEG_ABSOLUTE; |
3322 | adds(exp)=0; |
3323 | subs(exp)=0; |
3324 | offs(exp)=words[1]|(words[0]<<16); |
3325 | } else if(ok!=0) { |
3326 | seg(exp)=SEG_ABSOLUTE; |
3327 | adds(exp)=0; |
3328 | subs(exp)=0; |
3329 | offs(exp)= (ok==10) ? 1 : 0; |
3330 | as_bad("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp)); |
3331 | } |
3332 | break; |
3333 | default: |
3334 | abort(); |
3335 | } |
3336 | if(input_line_pointer!=exp->e_end+1) |
3337 | as_bad("Ignoring junk after expression"); |
3338 | exp->e_end[1]=c_save; |
3339 | input_line_pointer=save_in; |
3340 | if(exp->e_siz) { |
3341 | switch(exp->e_siz) { |
3342 | case 1: |
3343 | if(!isbyte(offs(exp))) |
3344 | as_bad("expression doesn't fit in BYTE"); |
3345 | break; |
3346 | case 2: |
3347 | if(!isword(offs(exp))) |
3348 | as_bad("expression doesn't fit in WORD"); |
3349 | break; |
3350 | } |
3351 | } |
3352 | return offs(exp); |
3353 | #endif |
3354 | } /* get_num() */ |
3355 | |
3356 | /* These are the back-ends for the various machine dependent pseudo-ops. */ |
3357 | |
3358 | static void s_data1() { |
3359 | subseg_new(SEG_DATA,1); |
3360 | demand_empty_rest_of_line(); |
3361 | } /* s_data1() */ |
3362 | |
3363 | static void s_data2() { |
3364 | subseg_new(SEG_DATA,2); |
3365 | demand_empty_rest_of_line(); |
3366 | } /* s_data2() */ |
3367 | |
3368 | static void s_bss() { |
3369 | /* We don't support putting frags in the BSS segment, but we |
3370 | can put them into initialized data for now... */ |
3371 | subseg_new(SEG_DATA,255); /* FIXME-SOON */ |
3372 | demand_empty_rest_of_line(); |
3373 | } /* s_bss() */ |
3374 | |
3375 | static void s_even() { |
3376 | register int temp; |
3377 | register long temp_fill; |
3378 | |
3379 | temp = 1; /* JF should be 2? */ |
3380 | temp_fill = get_absolute_expression (); |
3381 | if ( ! need_pass_2 ) /* Never make frag if expect extra pass. */ |
3382 | frag_align (temp, (int)temp_fill); |
3383 | demand_empty_rest_of_line(); |
3384 | } /* s_even() */ |
3385 | |
3386 | static void s_proc() { |
3387 | demand_empty_rest_of_line(); |
3388 | } /* s_proc() */ |
3389 | |
3390 | /* s_space is defined in read.c .skip is simply an alias to it. */ |
3391 | |
3392 | int |
3393 | md_parse_option(argP,cntP,vecP) |
3394 | char **argP; |
3395 | int *cntP; |
3396 | char ***vecP; |
3397 | { |
3398 | switch(**argP) { |
3399 | case 'l': /* -l means keep externals to 2 byte branch offsets |
3400 | rather than 4 byte branch offsets */ |
3401 | break; |
3402 | |
3403 | case 'm': |
3404 | /* Gas almost ignores this option! */ |
3405 | (*argP)++; |
3406 | if(**argP=='c') |
3407 | (*argP)++; |
3408 | if(!strcmp(*argP,"68000")) |
3409 | flagseen['m']=2; |
3410 | else if(!strcmp(*argP,"68010")) { |
3411 | #ifdef TE_SUN |
3412 | magic_number_for_object_file = 1<<16|OMAGIC; |
3413 | #endif |
3414 | flagseen['m']=1; |
3415 | } else if(!strcmp(*argP,"68020")) |
3416 | flagseen['m']=0; |
3417 | else |
3418 | as_warn("Unknown -m option ignored"); |
3419 | while(**argP) |
3420 | (*argP)++; |
3421 | break; |
3422 | |
3423 | case 'p': |
3424 | if (!strcmp(*argP,"pic")) { |
3425 | (*argP) += 3; |
3426 | break; /* -pic, Position Independent Code */ |
3427 | } |
3428 | else |
3429 | return 0; |
3430 | default: |
3431 | return 0; |
3432 | } |
3433 | return 1; |
3434 | } |
3435 | |
3436 | |
3437 | #ifdef TEST2 |
3438 | |
3439 | /* TEST2: Test md_assemble() */ |
3440 | /* Warning, this routine probably doesn't work anymore */ |
3441 | |
3442 | main() |
3443 | { |
3444 | struct m68_it the_ins; |
3445 | char buf[120]; |
3446 | char *cp; |
3447 | int n; |
3448 | |
3449 | m68_ip_begin(); |
3450 | for(;;) { |
3451 | if(!gets(buf) || !*buf) |
3452 | break; |
3453 | if(buf[0]=='|' || buf[1]=='.') |
3454 | continue; |
3455 | for(cp=buf;*cp;cp++) |
3456 | if(*cp=='\t') |
3457 | *cp=' '; |
3458 | if(is_label(buf)) |
3459 | continue; |
3460 | bzero(&the_ins,sizeof(the_ins)); |
3461 | m68_ip(&the_ins,buf); |
3462 | if(the_ins.error) { |
3463 | printf("Error %s in %s\n",the_ins.error,buf); |
3464 | } else { |
3465 | printf("Opcode(%d.%s): ",the_ins.numo,the_ins.args); |
3466 | for(n=0;n<the_ins.numo;n++) |
3467 | printf(" 0x%x",the_ins.opcode[n]&0xffff); |
3468 | printf(" "); |
3469 | print_the_insn(&the_ins.opcode[0],stdout); |
3470 | (void)putchar('\n'); |
3471 | } |
3472 | for(n=0;n<strlen(the_ins.args)/2;n++) { |
3473 | if(the_ins.operands[n].error) { |
3474 | printf("op%d Error %s in %s\n",n,the_ins.operands[n].error,buf); |
3475 | continue; |
3476 | } |
3477 | printf("mode %d, reg %d, ",the_ins.operands[n].mode,the_ins.operands[n].reg); |
3478 | if(the_ins.operands[n].b_const) |
3479 | printf("Constant: '%.*s', ",1+the_ins.operands[n].e_const-the_ins.operands[n].b_const,the_ins.operands[n].b_const); |
3480 | printf("ireg %d, isiz %d, imul %d, ",the_ins.operands[n].ireg,the_ins.operands[n].isiz,the_ins.operands[n].imul); |
3481 | if(the_ins.operands[n].b_iadd) |
3482 | printf("Iadd: '%.*s',",1+the_ins.operands[n].e_iadd-the_ins.operands[n].b_iadd,the_ins.operands[n].b_iadd); |
3483 | (void)putchar('\n'); |
3484 | } |
3485 | } |
3486 | m68_ip_end(); |
3487 | return 0; |
3488 | } |
3489 | |
3490 | is_label(str) |
3491 | char *str; |
3492 | { |
3493 | while(*str==' ') |
3494 | str++; |
3495 | while(*str && *str!=' ') |
3496 | str++; |
3497 | if(str[-1]==':' || str[1]=='=') |
3498 | return 1; |
3499 | return 0; |
3500 | } |
3501 | |
3502 | #endif |
3503 | |
3504 | /* Possible states for relaxation: |
3505 | |
3506 | 0 0 branch offset byte (bra, etc) |
3507 | 0 1 word |
3508 | 0 2 long |
3509 | |
3510 | 1 0 indexed offsets byte a0@(32,d4:w:1) etc |
3511 | 1 1 word |
3512 | 1 2 long |
3513 | |
3514 | 2 0 two-offset index word-word a0@(32,d4)@(45) etc |
3515 | 2 1 word-long |
3516 | 2 2 long-word |
3517 | 2 3 long-long |
3518 | |
3519 | */ |
3520 | |
3521 | |
3522 | |
3523 | #ifdef DONTDEF |
3524 | abort() |
3525 | { |
3526 | printf("ABORT!\n"); |
3527 | exit(12); |
3528 | } |
3529 | |
3530 | char *index(s,c) |
3531 | char *s; |
3532 | { |
3533 | while(*s!=c) { |
3534 | if(!*s) return 0; |
3535 | s++; |
3536 | } |
3537 | return s; |
3538 | } |
3539 | |
3540 | bzero(s,n) |
3541 | char *s; |
3542 | { |
3543 | while(n--) |
3544 | *s++=0; |
3545 | } |
3546 | |
3547 | print_frags() |
3548 | { |
3549 | fragS *fragP; |
3550 | extern fragS *text_frag_root; |
3551 | |
3552 | for(fragP=text_frag_root;fragP;fragP=fragP->fr_next) { |
3553 | printf("addr %lu next 0x%x fix %ld var %ld symbol 0x%x offset %ld\n", |
3554 | fragP->fr_address,fragP->fr_next,fragP->fr_fix,fragP->fr_var,fragP->fr_symbol,fragP->fr_offset); |
3555 | printf("opcode 0x%x type %d subtype %d\n\n",fragP->fr_opcode,fragP->fr_type,fragP->fr_subtype); |
3556 | } |
3557 | fflush(stdout); |
3558 | return 0; |
3559 | } |
3560 | #endif |
3561 | |
3562 | #ifdef DONTDEF |
3563 | /*VARARGS1*/ |
3564 | panic(format,args) |
3565 | char *format; |
3566 | { |
3567 | fputs("Internal error:",stderr); |
3568 | _doprnt(format,&args,stderr); |
3569 | (void)putc('\n',stderr); |
3570 | as_where(); |
3571 | abort(); |
3572 | } |
3573 | #endif |
3574 | |
3575 | /* We have no need to default values of symbols. */ |
3576 | |
3577 | /* ARGSUSED */ |
3578 | symbolS * |
3579 | md_undefined_symbol (name) |
3580 | char *name; |
3581 | { |
3582 | return 0; |
3583 | } |
3584 | |
3585 | /* Parse an operand that is machine-specific. |
3586 | We just return without modifying the expression if we have nothing |
3587 | to do. */ |
3588 | |
3589 | /* ARGSUSED */ |
3590 | void |
3591 | md_operand (expressionP) |
3592 | expressionS *expressionP; |
3593 | { |
3594 | } |
3595 | |
3596 | /* Round up a section size to the appropriate boundary. */ |
3597 | long |
3598 | md_section_align (segment, size) |
3599 | segT segment; |
3600 | long size; |
3601 | { |
3602 | return size; /* Byte alignment is fine */ |
3603 | } |
3604 | |
3605 | /* Exactly what point is a PC-relative offset relative TO? |
3606 | On the 68k, they're relative to the address of the offset, plus |
3607 | its size. (??? Is this right? FIXME-SOON!) */ |
3608 | long |
3609 | md_pcrel_from (fixP) |
3610 | fixS *fixP; |
3611 | { |
3612 | return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; |
3613 | } |
3614 | |
3615 | /* Opcode table for m68000/m68020 and m68881. |
3616 | Copyright (C) 1989, Free Software Foundation. |
3617 | |
3618 | This file is part of GDB, the GNU Debugger and GAS, the GNU Assembler. |
3619 | |
3620 | Both GDB and GAS are free software; you can redistribute and/or modify |
3621 | it under the terms of the GNU General Public License as published by |
3622 | the Free Software Foundation; either version 1, or (at your option) |
3623 | any later version. |
3624 | |
3625 | GDB and GAS are distributed in the hope that it will be useful, |
3626 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
3627 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3628 | GNU General Public License for more details. |
3629 | |
3630 | You should have received a copy of the GNU General Public License |
3631 | along with GDB or GAS; see the file COPYING. If not, write to |
3632 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
3633 | |
3634 | /* We store four bytes of opcode for all opcodes because that |
3635 | is the most any of them need. The actual length of an instruction |
3636 | is always at least 2 bytes, and is as much longer as necessary to |
3637 | hold the operands it has. |
3638 | |
3639 | The match component is a mask saying which bits must match |
3640 | particular opcode in order for an instruction to be an instance |
3641 | of that opcode. |
3642 | |
3643 | The args component is a string containing two characters |
3644 | for each operand of the instruction. The first specifies |
3645 | the kind of operand; the second, the place it is stored. */ |
3646 | |
3647 | /* Kinds of operands: |
3648 | D data register only. Stored as 3 bits. |
3649 | A address register only. Stored as 3 bits. |
3650 | R either kind of register. Stored as 4 bits. |
3651 | F floating point coprocessor register only. Stored as 3 bits. |
3652 | O an offset (or width): immediate data 0-31 or data register. |
3653 | Stored as 6 bits in special format for BF... insns. |
3654 | + autoincrement only. Stored as 3 bits (number of the address register). |
3655 | - autodecrement only. Stored as 3 bits (number of the address register). |
3656 | Q quick immediate data. Stored as 3 bits. |
3657 | This matches an immediate operand only when value is in range 1 .. 8. |
3658 | M moveq immediate data. Stored as 8 bits. |
3659 | This matches an immediate operand only when value is in range -128..127 |
3660 | T trap vector immediate data. Stored as 4 bits. |
3661 | |
3662 | k K-factor for fmove.p instruction. Stored as a 7-bit constant or |
3663 | a three bit register offset, depending on the field type. |
3664 | |
3665 | # immediate data. Stored in special places (b, w or l) |
3666 | which say how many bits to store. |
3667 | ^ immediate data for floating point instructions. Special places |
3668 | are offset by 2 bytes from '#'... |
3669 | B pc-relative address, converted to an offset |
3670 | that is treated as immediate data. |
3671 | d displacement and register. Stores the register as 3 bits |
3672 | and stores the displacement in the entire second word. |
3673 | |
3674 | C the CCR. No need to store it; this is just for filtering validity. |
3675 | S the SR. No need to store, just as with CCR. |
3676 | U the USP. No need to store, just as with CCR. |
3677 | |
3678 | I Coprocessor ID. Not printed if 1. The Coprocessor ID is always |
3679 | extracted from the 'd' field of word one, which means that an extended |
3680 | coprocessor opcode can be skipped using the 'i' place, if needed. |
3681 | |
3682 | s System Control register for the floating point coprocessor. |
3683 | S List of system control registers for floating point coprocessor. |
3684 | |
3685 | J Misc register for movec instruction, stored in 'j' format. |
3686 | Possible values: |
3687 | 000 SFC Source Function Code reg |
3688 | 001 DFC Data Function Code reg |
3689 | 002 CACR Cache Control Register |
3690 | 800 USP User Stack Pointer |
3691 | 801 VBR Vector Base reg |
3692 | 802 CAAR Cache Address Register |
3693 | 803 MSP Master Stack Pointer |
3694 | 804 ISP Interrupt Stack Pointer |
3695 | |
3696 | L Register list of the type d0-d7/a0-a7 etc. |
3697 | (New! Improved! Can also hold fp0-fp7, as well!) |
3698 | The assembler tries to see if the registers match the insn by |
3699 | looking at where the insn wants them stored. |
3700 | |
3701 | l Register list like L, but with all the bits reversed. |
3702 | Used for going the other way. . . |
3703 | |
3704 | They are all stored as 6 bits using an address mode and a register number; |
3705 | they differ in which addressing modes they match. |
3706 | |
3707 | * all (modes 0-6,7.*) |
3708 | ~ alterable memory (modes 2-6,7.0,7.1)(not 0,1,7.~) |
3709 | % alterable (modes 0-6,7.0,7.1)(not 7.~) |
3710 | ; data (modes 0,2-6,7.*)(not 1) |
3711 | @ data, but not immediate (modes 0,2-6,7.? ? ?)(not 1,7.?) This may really be ;, the 68020 book says it is |
3712 | ! control (modes 2,5,6,7.*-)(not 0,1,3,4,7.4) |
3713 | & alterable control (modes 2,5,6,7.0,7.1)(not 0,1,7.? ? ?) |
3714 | $ alterable data (modes 0,2-6,7.0,7.1)(not 1,7.~) |
3715 | ? alterable control, or data register (modes 0,2,5,6,7.0,7.1)(not 1,3,4,7.~) |
3716 | / control, or data register (modes 0,2,5,6,7.0,7.1,7.2,7.3)(not 1,3,4,7.4) |
3717 | */ |
3718 | |
3719 | /* JF: for the 68851 */ |
3720 | /* |
3721 | I didn't use much imagination in choosing the |
3722 | following codes, so many of them aren't very |
3723 | mnemonic. -rab |
3724 | |
3725 | P pmmu register |
3726 | Possible values: |
3727 | 000 TC Translation Control reg |
3728 | 100 CAL Current Access Level |
3729 | 101 VAL Validate Access Level |
3730 | 110 SCC Stack Change Control |
3731 | 111 AC Access Control |
3732 | |
3733 | W wide pmmu registers |
3734 | Possible values: |
3735 | 001 DRP Dma Root Pointer |
3736 | 010 SRP Supervisor Root Pointer |
3737 | 011 CRP Cpu Root Pointer |
3738 | |
3739 | f function code register |
3740 | 0 SFC |
3741 | 1 DFC |
3742 | |
3743 | V VAL register only |
3744 | |
3745 | X BADx, BACx |
3746 | 100 BAD Breakpoint Acknowledge Data |
3747 | 101 BAC Breakpoint Acknowledge Control |
3748 | |
3749 | Y PSR |
3750 | Z PCSR |
3751 | |
3752 | | memory (modes 2-6, 7.*) |
3753 | |
3754 | */ |
3755 | |
3756 | /* Places to put an operand, for non-general operands: |
3757 | s source, low bits of first word. |
3758 | d dest, shifted 9 in first word |
3759 | 1 second word, shifted 12 |
3760 | 2 second word, shifted 6 |
3761 | 3 second word, shifted 0 |
3762 | 4 third word, shifted 12 |
3763 | 5 third word, shifted 6 |
3764 | 6 third word, shifted 0 |
3765 | 7 second word, shifted 7 |
3766 | 8 second word, shifted 10 |
3767 | D store in both place 1 and place 3; for divul and divsl. |
3768 | b second word, low byte |
3769 | w second word (entire) |
3770 | l second and third word (entire) |
3771 | g branch offset for bra and similar instructions. |
3772 | The place to store depends on the magnitude of offset. |
3773 | t store in both place 7 and place 8; for floating point operations |
3774 | c branch offset for cpBcc operations. |
3775 | The place to store is word two if bit six of word one is zero, |
3776 | and words two and three if bit six of word one is one. |
3777 | i Increment by two, to skip over coprocessor extended operands. Only |
3778 | works with the 'I' format. |
3779 | k Dynamic K-factor field. Bits 6-4 of word 2, used as a register number. |
3780 | Also used for dynamic fmovem instruction. |
3781 | C floating point coprocessor constant - 7 bits. Also used for static |
3782 | K-factors... |
3783 | j Movec register #, stored in 12 low bits of second word. |
3784 | |
3785 | Places to put operand, for general operands: |
3786 | d destination, shifted 6 bits in first word |
3787 | b source, at low bit of first word, and immediate uses one byte |
3788 | w source, at low bit of first word, and immediate uses two bytes |
3789 | l source, at low bit of first word, and immediate uses four bytes |
3790 | s source, at low bit of first word. |
3791 | Used sometimes in contexts where immediate is not allowed anyway. |
3792 | f single precision float, low bit of 1st word, immediate uses 4 bytes |
3793 | F double precision float, low bit of 1st word, immediate uses 8 bytes |
3794 | x extended precision float, low bit of 1st word, immediate uses 12 bytes |
3795 | p packed float, low bit of 1st word, immediate uses 12 bytes |
3796 | */ |
3797 | |
3798 | #define one(x) ((x) << 16) |
3799 | #define two(x, y) (((x) << 16) + y) |
3800 | |
3801 | /* |
3802 | * Local Variables: |
3803 | * comment-column: 0 |
3804 | * fill-column: 131 |
3805 | * End: |
3806 | */ |
3807 | |
3808 | /* end of tc-m68k.c */ |