]>
Commit | Line | Data |
---|---|---|
fecd2382 RP |
1 | /* ns32k.c -- Assemble on the National Semiconductor 32k series |
2 | Copyright (C) 1987 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of GAS, the GNU Assembler. | |
5 | ||
6 | GAS is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 1, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GAS is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GAS; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | ||
20 | /*#define SHOW_NUM 1*/ /* uncomment for debugging */ | |
21 | ||
22 | #include <stdio.h> | |
23 | #include <ctype.h> | |
24 | #ifdef USG | |
25 | #include <string.h> | |
26 | #else | |
27 | #include <strings.h> | |
28 | #endif | |
29 | #include "ns32k-opcode.h" | |
30 | ||
31 | #include "as.h" | |
32 | ||
33 | #include "obstack.h" | |
34 | ||
35 | /* Macros */ | |
36 | #define IIF_ENTRIES 13 /* number of entries in iif */ | |
37 | #define PRIVATE_SIZE 256 /* size of my garbage memory */ | |
38 | #define MAX_ARGS 4 | |
39 | #define DEFAULT -1 /* addr_mode returns this value when plain constant or label is encountered */ | |
40 | ||
41 | #define IIF(ptr,a1,c1,e1,g1,i1,k1,m1,o1,q1,s1,u1) \ | |
42 | iif.iifP[ptr].type= a1; \ | |
43 | iif.iifP[ptr].size= c1; \ | |
44 | iif.iifP[ptr].object= e1; \ | |
45 | iif.iifP[ptr].object_adjust= g1; \ | |
46 | iif.iifP[ptr].pcrel= i1; \ | |
47 | iif.iifP[ptr].pcrel_adjust= k1; \ | |
48 | iif.iifP[ptr].im_disp= m1; \ | |
49 | iif.iifP[ptr].relax_substate= o1; \ | |
50 | iif.iifP[ptr].bit_fixP= q1; \ | |
51 | iif.iifP[ptr].addr_mode= s1; \ | |
52 | iif.iifP[ptr].bsr= u1; | |
53 | ||
54 | #ifdef SEQUENT_COMPATABILITY | |
55 | #define LINE_COMMENT_CHARS "|" | |
56 | #define ABSOLUTE_PREFIX '@' | |
57 | #define IMMEDIATE_PREFIX '#' | |
58 | #endif | |
59 | ||
60 | #ifndef LINE_COMMENT_CHARS | |
61 | #define LINE_COMMENT_CHARS "#" | |
62 | #endif | |
63 | ||
64 | char comment_chars[] = "#"; | |
65 | char line_comment_chars[] = LINE_COMMENT_CHARS; | |
66 | #if !defined(ABSOLUTE_PREFIX) && !defined(IMMEDIATE_PREFIX) | |
67 | #define ABSOLUTE_PREFIX '@' /* One or the other MUST be defined */ | |
68 | #endif | |
69 | ||
70 | struct addr_mode { | |
71 | char mode; /* addressing mode of operand (0-31) */ | |
72 | char scaled_mode; /* mode combined with scaled mode */ | |
73 | char scaled_reg; /* register used in scaled+1 (1-8) */ | |
74 | char float_flag; /* set if R0..R7 was F0..F7 ie a floating-point-register */ | |
75 | char am_size; /* estimated max size of general addr-mode parts*/ | |
76 | char im_disp; /* if im_disp==1 we have a displacement */ | |
77 | char pcrel; /* 1 if pcrel, this is really redundant info */ | |
78 | char disp_suffix[2]; /* length of displacement(s), 0=undefined */ | |
79 | char *disp[2]; /* pointer(s) at displacement(s) | |
80 | or immediates(s) (ascii) */ | |
81 | char index_byte; /* index byte */ | |
82 | }; | |
83 | typedef struct addr_mode addr_modeS; | |
84 | ||
85 | ||
86 | char *freeptr,*freeptr_static; /* points at some number of free bytes */ | |
87 | struct hash_control *inst_hash_handle; | |
88 | ||
89 | struct ns32k_opcode *desc; /* pointer at description of instruction */ | |
90 | addr_modeS addr_modeP; | |
91 | char EXP_CHARS[] = "eE"; | |
92 | char FLT_CHARS[] = "fd"; /* we don't want to support lowercase, do we */ | |
93 | ||
94 | /* UPPERCASE denotes live names | |
95 | * when an instruction is built, IIF is used as an intermidiate form to store | |
96 | * the actual parts of the instruction. A ns32k machine instruction can | |
97 | * be divided into a couple of sub PARTs. When an instruction is assembled | |
98 | * the appropriate PART get an assignment. When an IIF has been completed it's | |
99 | * converted to a FRAGment as specified in AS.H */ | |
100 | ||
101 | /* internal structs */ | |
102 | struct option { | |
103 | char *pattern; | |
104 | unsigned long or; | |
105 | unsigned long and; | |
106 | }; | |
107 | ||
108 | typedef struct { | |
109 | int type; /* how to interpret object */ | |
110 | int size; /* Estimated max size of object */ | |
111 | unsigned long object; /* binary data */ | |
112 | int object_adjust; /* number added to object */ | |
113 | int pcrel; /* True if object is pcrel */ | |
114 | int pcrel_adjust; /* It's value reflects the length in bytes from the instruction start to the displacement */ | |
115 | int im_disp; /* True if the object is a displacement */ | |
116 | relax_substateT relax_substate; /* Initial relaxsubstate */ | |
117 | bit_fixS *bit_fixP; /* Pointer at bit_fix struct */ | |
118 | int addr_mode; /* What addrmode do we associate with this iif-entry */ | |
119 | char bsr; /* Sequent hack */ | |
120 | }iif_entryT; /* Internal Instruction Format */ | |
121 | struct int_ins_form { | |
122 | int instr_size; /* Max size of instruction in bytes. */ | |
123 | iif_entryT iifP[IIF_ENTRIES+1]; | |
124 | }; | |
125 | struct int_ins_form iif; | |
126 | expressionS exprP; | |
127 | char *input_line_pointer; | |
128 | /* description of the PARTs in IIF | |
129 | *object[n]: | |
130 | * 0 total length in bytes of entries in iif | |
131 | * 1 opcode | |
132 | * 2 index_byte_a | |
133 | * 3 index_byte_b | |
134 | * 4 disp_a_1 | |
135 | * 5 disp_a_2 | |
136 | * 6 disp_b_1 | |
137 | * 7 disp_b_2 | |
138 | * 8 imm_a | |
139 | * 9 imm_b | |
140 | * 10 implied1 | |
141 | * 11 implied2 | |
142 | * | |
143 | * For every entry there is a datalength in bytes. This is stored in size[n]. | |
144 | * 0, the objectlength is not explicitly given by the instruction | |
145 | * and the operand is undefined. This is a case for relaxation. | |
146 | * Reserve 4 bytes for the final object. | |
147 | * | |
148 | * 1, the entry contains one byte | |
149 | * 2, the entry contains two bytes | |
150 | * 3, the entry contains three bytes | |
151 | * 4, the entry contains four bytes | |
152 | * etc | |
153 | * | |
154 | * Furthermore, every entry has a data type identifier in type[n]. | |
155 | * | |
156 | * 0, the entry is void, ignore it. | |
157 | * 1, the entry is a binary number. | |
158 | * 2, the entry is a pointer at an expression. | |
159 | * Where expression may be as simple as a single '1', | |
160 | * and as complicated as foo-bar+12, | |
161 | * foo and bar may be undefined but suffixed by :{b|w|d} to | |
162 | * control the length of the object. | |
163 | * | |
164 | * 3, the entry is a pointer at a bignum struct | |
165 | * | |
166 | * | |
167 | * The low-order-byte coresponds to low physical memory. | |
168 | * Obviously a FRAGment must be created for each valid disp in PART whose | |
169 | * datalength is undefined (to bad) . | |
170 | * The case where just the expression is undefined is less severe and is | |
171 | * handled by fix. Here the number of bytes in the objectfile is known. | |
172 | * With this representation we simplify the assembly and separates the | |
173 | * machine dependent/independent parts in a more clean way (said OE) | |
174 | */ | |
175 | \f | |
176 | struct option opt1[]= /* restore, exit */ | |
177 | { | |
178 | { "r0", 0x80, 0xff }, | |
179 | { "r1", 0x40, 0xff }, | |
180 | { "r2", 0x20, 0xff }, | |
181 | { "r3", 0x10, 0xff }, | |
182 | { "r4", 0x08, 0xff }, | |
183 | { "r5", 0x04, 0xff }, | |
184 | { "r6", 0x02, 0xff }, | |
185 | { "r7", 0x01, 0xff }, | |
186 | { 0 , 0x00, 0xff } | |
187 | }; | |
188 | struct option opt2[]= /* save, enter */ | |
189 | { | |
190 | { "r0", 0x01, 0xff }, | |
191 | { "r1", 0x02, 0xff }, | |
192 | { "r2", 0x04, 0xff }, | |
193 | { "r3", 0x08, 0xff }, | |
194 | { "r4", 0x10, 0xff }, | |
195 | { "r5", 0x20, 0xff }, | |
196 | { "r6", 0x40, 0xff }, | |
197 | { "r7", 0x80, 0xff }, | |
198 | { 0 , 0x00, 0xff } | |
199 | }; | |
200 | struct option opt3[]= /* setcfg */ | |
201 | { | |
202 | { "c", 0x8, 0xff }, | |
203 | { "m", 0x4, 0xff }, | |
204 | { "f", 0x2, 0xff }, | |
205 | { "i", 0x1, 0xff }, | |
206 | { 0 , 0x0, 0xff } | |
207 | }; | |
208 | struct option opt4[]= /* cinv */ | |
209 | { | |
210 | { "a", 0x4, 0xff }, | |
211 | { "i", 0x2, 0xff }, | |
212 | { "d", 0x1, 0xff }, | |
213 | { 0 , 0x0, 0xff } | |
214 | }; | |
215 | struct option opt5[]= /* string inst */ | |
216 | { | |
217 | { "b", 0x2, 0xff }, | |
218 | { "u", 0xc, 0xff }, | |
219 | { "w", 0x4, 0xff }, | |
220 | { 0 , 0x0, 0xff } | |
221 | }; | |
222 | struct option opt6[]= /* plain reg ext,cvtp etc */ | |
223 | { | |
224 | { "r0", 0x00, 0xff }, | |
225 | { "r1", 0x01, 0xff }, | |
226 | { "r2", 0x02, 0xff }, | |
227 | { "r3", 0x03, 0xff }, | |
228 | { "r4", 0x04, 0xff }, | |
229 | { "r5", 0x05, 0xff }, | |
230 | { "r6", 0x06, 0xff }, | |
231 | { "r7", 0x07, 0xff }, | |
232 | { 0 , 0x00, 0xff } | |
233 | }; | |
234 | ||
235 | #if !defined(NS32032) && !defined(NS32532) | |
236 | #define NS32032 | |
237 | #endif | |
238 | ||
239 | struct option cpureg_532[]= /* lpr spr */ | |
240 | { | |
241 | { "us", 0x0, 0xff }, | |
242 | { "dcr", 0x1, 0xff }, | |
243 | { "bpc", 0x2, 0xff }, | |
244 | { "dsr", 0x3, 0xff }, | |
245 | { "car", 0x4, 0xff }, | |
246 | { "fp", 0x8, 0xff }, | |
247 | { "sp", 0x9, 0xff }, | |
248 | { "sb", 0xa, 0xff }, | |
249 | { "usp", 0xb, 0xff }, | |
250 | { "cfg", 0xc, 0xff }, | |
251 | { "psr", 0xd, 0xff }, | |
252 | { "intbase", 0xe, 0xff }, | |
253 | { "mod", 0xf, 0xff }, | |
254 | { 0 , 0x00, 0xff } | |
255 | }; | |
256 | struct option mmureg_532[]= /* lmr smr */ | |
257 | { | |
258 | { "mcr", 0x9, 0xff }, | |
259 | { "msr", 0xa, 0xff }, | |
260 | { "tear", 0xb, 0xff }, | |
261 | { "ptb0", 0xc, 0xff }, | |
262 | { "ptb1", 0xd, 0xff }, | |
263 | { "ivar0", 0xe, 0xff }, | |
264 | { "ivar1", 0xf, 0xff }, | |
265 | { 0 , 0x0, 0xff } | |
266 | }; | |
267 | ||
268 | struct option cpureg_032[]= /* lpr spr */ | |
269 | { | |
270 | { "upsr", 0x0, 0xff }, | |
271 | { "fp", 0x8, 0xff }, | |
272 | { "sp", 0x9, 0xff }, | |
273 | { "sb", 0xa, 0xff }, | |
274 | { "psr", 0xd, 0xff }, | |
275 | { "intbase", 0xe, 0xff }, | |
276 | { "mod", 0xf, 0xff }, | |
277 | { 0 , 0x0, 0xff } | |
278 | }; | |
279 | struct option mmureg_032[]= /* lmr smr */ | |
280 | { | |
281 | { "bpr0", 0x0, 0xff }, | |
282 | { "bpr1", 0x1, 0xff }, | |
283 | { "pf0", 0x4, 0xff }, | |
284 | { "pf1", 0x5, 0xff }, | |
285 | { "sc", 0x8, 0xff }, | |
286 | { "msr", 0xa, 0xff }, | |
287 | { "bcnt", 0xb, 0xff }, | |
288 | { "ptb0", 0xc, 0xff }, | |
289 | { "ptb1", 0xd, 0xff }, | |
290 | { "eia", 0xf, 0xff }, | |
291 | { 0 , 0x0, 0xff } | |
292 | }; | |
293 | ||
294 | #if defined(NS32532) | |
295 | struct option *cpureg = cpureg_532; | |
296 | struct option *mmureg = mmureg_532; | |
297 | #else | |
298 | struct option *cpureg = cpureg_032; | |
299 | struct option *mmureg = mmureg_032; | |
300 | #endif | |
301 | \f | |
302 | ||
303 | const pseudo_typeS md_pseudo_table[]={ /* so far empty */ | |
304 | { 0, 0, 0 } | |
305 | }; | |
306 | ||
307 | #define IND(x,y) (((x)<<2)+(y)) | |
308 | ||
309 | /* those are index's to relax groups in md_relax_table | |
310 | ie it must be multiplied by 4 to point at a group start. Viz IND(x,y) | |
311 | Se function relax_segment in write.c for more info */ | |
312 | ||
313 | #define BRANCH 1 | |
314 | #define PCREL 2 | |
315 | ||
316 | /* those are index's to entries in a relax group */ | |
317 | ||
318 | #define BYTE 0 | |
319 | #define WORD 1 | |
320 | #define DOUBLE 2 | |
321 | #define UNDEF 3 | |
322 | /* Those limits are calculated from the displacement start in memory. | |
323 | The ns32k uses the begining of the instruction as displacement base. | |
324 | This type of displacements could be handled here by moving the limit window | |
325 | up or down. I choose to use an internal displacement base-adjust as there | |
326 | are other routines that must consider this. Also, as we have two various | |
327 | offset-adjusts in the ns32k (acb versus br/brs/jsr/bcond), two set of limits | |
328 | would have had to be used. | |
329 | Now we dont have to think about that. */ | |
330 | ||
331 | ||
332 | const relax_typeS md_relax_table[]={ | |
333 | { 1, 1, 0, 0 }, | |
334 | { 1, 1, 0, 0 }, | |
335 | { 1, 1, 0, 0 }, | |
336 | { 1, 1, 0, 0 }, | |
337 | ||
338 | { (63), (-64), 1, IND(BRANCH,WORD) }, | |
339 | { (8192), (-8192), 2, IND(BRANCH,DOUBLE) }, | |
340 | { 0, 0, 4, 0 }, | |
341 | { 1, 1, 0, 0 } | |
342 | }; | |
343 | ||
344 | /* Array used to test if mode contains displacements. | |
345 | Value is true if mode contains displacement. */ | |
346 | ||
347 | char disp_test[]={ 0,0,0,0,0,0,0,0, | |
348 | 1,1,1,1,1,1,1,1, | |
349 | 1,1,1,0,0,1,1,0, | |
350 | 1,1,1,1,1,1,1,1 }; | |
351 | ||
352 | /* Array used to calculate max size of displacements */ | |
353 | ||
354 | char disp_size[]={ 4,1,2,0,4 }; | |
355 | \f | |
356 | ||
357 | #ifdef __STDC__ | |
358 | ||
359 | static segT evaluate_expr(expressionS *resultP, char *ptr); | |
360 | static void md_number_to_disp(char *buf, long val, int n); | |
361 | static void md_number_to_imm(char *buf, long val, int n); | |
362 | ||
363 | #else /* __STDC__ */ | |
364 | ||
365 | static segT evaluate_expr(); | |
366 | static void md_number_to_disp(); | |
367 | static void md_number_to_imm(); | |
368 | ||
369 | #endif /* __STDC__ */ | |
370 | ||
371 | /* Parses a general operand into an addressingmode struct | |
372 | ||
373 | in: pointer at operand in ascii form | |
374 | pointer at addr_mode struct for result | |
375 | the level of recursion. (always 0 or 1) | |
376 | ||
377 | out: data in addr_mode struct | |
378 | */ | |
379 | int addr_mode(operand,addr_modeP,recursive_level) | |
380 | char *operand; | |
381 | register addr_modeS *addr_modeP; | |
382 | int recursive_level; | |
383 | { | |
384 | register char *str; | |
385 | register int i; | |
386 | register int strl; | |
387 | register int mode; | |
388 | int j; | |
389 | mode = DEFAULT; /* default */ | |
390 | addr_modeP->scaled_mode=0; /* why not */ | |
391 | addr_modeP->scaled_reg=0; /* if 0, not scaled index */ | |
392 | addr_modeP->float_flag=0; | |
393 | addr_modeP->am_size=0; | |
394 | addr_modeP->im_disp=0; | |
395 | addr_modeP->pcrel=0; /* not set in this function */ | |
396 | addr_modeP->disp_suffix[0]=0; | |
397 | addr_modeP->disp_suffix[1]=0; | |
398 | addr_modeP->disp[0]=NULL; | |
399 | addr_modeP->disp[1]=NULL; | |
400 | str=operand; | |
401 | if (str[0]==0) {return (0);} /* we don't want this */ | |
402 | strl=strlen(str); | |
403 | switch (str[0]) { | |
404 | /* the following three case statements controls the mode-chars | |
405 | this is the place to ed if you want to change them */ | |
406 | #ifdef ABSOLUTE_PREFIX | |
407 | case ABSOLUTE_PREFIX: | |
408 | if (str[strl-1]==']') break; | |
409 | addr_modeP->mode=21; /* absolute */ | |
410 | addr_modeP->disp[0]=str+1; | |
411 | return (-1); | |
412 | #endif | |
413 | #ifdef IMMEDIATE_PREFIX | |
414 | case IMMEDIATE_PREFIX: | |
415 | if (str[strl-1]==']') break; | |
416 | addr_modeP->mode=20; /* immediate */ | |
417 | addr_modeP->disp[0]=str+1; | |
418 | return (-1); | |
419 | #endif | |
420 | case '.': | |
421 | if (str[strl-1]!=']') { | |
422 | switch (str[1]) { | |
423 | case'-':case'+': | |
424 | if (str[2]!='\000') { | |
425 | addr_modeP->mode=27; /* pc-relativ */ | |
426 | addr_modeP->disp[0]=str+2; | |
427 | return (-1); | |
428 | } | |
429 | default: | |
430 | as_warn("Invalid syntax in PC-relative addressing mode"); | |
431 | return(0); | |
432 | } | |
433 | } | |
434 | break; | |
435 | case'e': | |
436 | if (str[strl-1]!=']') { | |
437 | if((!strncmp(str,"ext(",4)) && strl>7) { /* external */ | |
438 | addr_modeP->disp[0]=str+4; | |
439 | i=0; | |
440 | j=2; | |
441 | do { /* disp[0]'s termination point */ | |
442 | j+=1; | |
443 | if (str[j]=='(') i++; | |
444 | if (str[j]==')') i--; | |
445 | } while (j<strl && i!=0); | |
446 | if (i!=0 || !(str[j+1]=='-' || str[j+1]=='+') ) { | |
447 | as_warn("Invalid syntax in External addressing mode"); | |
448 | return(0); | |
449 | } | |
450 | str[j]='\000'; /* null terminate disp[0] */ | |
451 | addr_modeP->disp[1]=str+j+2; | |
452 | addr_modeP->mode=22; | |
453 | return (-1); | |
454 | } | |
455 | } | |
456 | break; | |
457 | default:; | |
458 | } | |
459 | strl=strlen(str); | |
460 | switch(strl) { | |
461 | case 2: | |
462 | switch (str[0]) { | |
463 | case'f':addr_modeP->float_flag=1; | |
464 | case'r': | |
465 | if (str[1]>='0' && str[1]<'8') { | |
466 | addr_modeP->mode=str[1]-'0'; | |
467 | return (-1); | |
468 | } | |
469 | } | |
470 | case 3: | |
471 | if (!strncmp(str,"tos",3)) { | |
472 | addr_modeP->mode=23; /* TopOfStack */ | |
473 | return (-1); | |
474 | } | |
475 | default:; | |
476 | } | |
477 | if (strl>4) { | |
478 | if (str[strl-1]==')') { | |
479 | if (str[strl-2]==')') { | |
480 | if (!strncmp(&str[strl-5],"(fp",3)) { | |
481 | mode=16; /* Memory Relative */ | |
482 | } | |
483 | if (!strncmp(&str[strl-5],"(sp",3)) { | |
484 | mode=17; | |
485 | } | |
486 | if (!strncmp(&str[strl-5],"(sb",3)) { | |
487 | mode=18; | |
488 | } | |
489 | if (mode!=DEFAULT) { /* memory relative */ | |
490 | addr_modeP->mode=mode; | |
491 | j=strl-5; /* temp for end of disp[0] */ | |
492 | i=0; | |
493 | do { | |
494 | strl-=1; | |
495 | if (str[strl]==')') i++; | |
496 | if (str[strl]=='(') i--; | |
497 | } while (strl>-1 && i!=0); | |
498 | if (i!=0) { | |
499 | as_warn("Invalid syntax in Memory Relative addressing mode"); | |
500 | return(0); | |
501 | } | |
502 | addr_modeP->disp[1]=str; | |
503 | addr_modeP->disp[0]=str+strl+1; | |
504 | str[j]='\000'; /* null terminate disp[0] */ | |
505 | str[strl]='\000'; /* null terminate disp[1] */ | |
506 | return (-1); | |
507 | } | |
508 | } | |
509 | switch (str[strl-3]) { | |
510 | case'r':case'R': | |
511 | if (str[strl-2]>='0' && str[strl-2]<'8' && str[strl-4]=='(') { | |
512 | addr_modeP->mode=str[strl-2]-'0'+8; | |
513 | addr_modeP->disp[0]=str; | |
514 | str[strl-4]=0; | |
515 | return (-1); /* reg rel */ | |
516 | } | |
517 | default: | |
518 | if (!strncmp(&str[strl-4],"(fp",3)) { | |
519 | mode=24; | |
520 | } | |
521 | if (!strncmp(&str[strl-4],"(sp",3)) { | |
522 | mode=25; | |
523 | } | |
524 | if (!strncmp(&str[strl-4],"(sb",3)) { | |
525 | mode=26; | |
526 | } | |
527 | if (!strncmp(&str[strl-4],"(pc",3)) { | |
528 | mode=27; | |
529 | } | |
530 | if (mode!=DEFAULT) { | |
531 | addr_modeP->mode=mode; | |
532 | addr_modeP->disp[0]=str; | |
533 | str[strl-4]='\0'; | |
534 | return (-1); /* memory space */ | |
535 | } | |
536 | } | |
537 | } | |
538 | /* no trailing ')' do we have a ']' ? */ | |
539 | if (str[strl-1]==']') { | |
540 | switch (str[strl-2]) { | |
541 | case'b':mode=28;break; | |
542 | case'w':mode=29;break; | |
543 | case'd':mode=30;break; | |
544 | case'q':mode=31;break; | |
545 | default:; | |
546 | as_warn("Invalid scaled-indexed mode, use (b,w,d,q)"); | |
547 | if (str[strl-3]!=':' || str[strl-6]!='[' || | |
548 | str[strl-5]=='r' || str[strl-4]<'0' || str[strl-4]>'7') { | |
549 | as_warn("Syntax in scaled-indexed mode, use [Rn:m] where n=[0..7] m={b,w,d,q}"); | |
550 | } | |
551 | } /* scaled index */ | |
552 | { | |
553 | if (recursive_level>0) { | |
554 | as_warn("Scaled-indexed addressing mode combined with scaled-index"); | |
555 | return(0); | |
556 | } | |
557 | addr_modeP->am_size+=1; /* scaled index byte */ | |
558 | j=str[strl-4]-'0'; /* store temporary */ | |
559 | str[strl-6]='\000'; /* nullterminate for recursive call */ | |
560 | i=addr_mode(str,addr_modeP,1); | |
561 | if (!i || addr_modeP->mode==20) { | |
562 | as_warn("Invalid or illegal addressing mode combined with scaled-index"); | |
563 | return(0); | |
564 | } | |
565 | addr_modeP->scaled_mode=addr_modeP->mode; /* store the inferior mode */ | |
566 | addr_modeP->mode=mode; | |
567 | addr_modeP->scaled_reg=j+1; | |
568 | return (-1); | |
569 | } | |
570 | } | |
571 | } | |
572 | addr_modeP->mode = DEFAULT; /* default to whatever */ | |
573 | addr_modeP->disp[0]=str; | |
574 | return (-1); | |
575 | } | |
576 | \f | |
577 | /* ptr points at string | |
578 | addr_modeP points at struct with result | |
579 | This routine calls addr_mode to determine the general addr.mode of | |
580 | the operand. When this is ready it parses the displacements for size | |
581 | specifying suffixes and determines size of immediate mode via ns32k-opcode. | |
582 | Also builds index bytes if needed. | |
583 | */ | |
584 | int get_addr_mode(ptr,addr_modeP) | |
585 | char *ptr; | |
586 | addr_modeS *addr_modeP; | |
587 | { | |
588 | int tmp; | |
589 | addr_mode(ptr,addr_modeP,0); | |
590 | if (addr_modeP->mode == DEFAULT || addr_modeP->scaled_mode == -1) { | |
591 | /* resolve ambigious operands, this shouldn't | |
592 | be necessary if one uses standard NSC operand | |
593 | syntax. But the sequent compiler doesn't!!! | |
594 | This finds a proper addressinging mode if it | |
595 | is implicitly stated. See ns32k-opcode.h */ | |
596 | (void)evaluate_expr(&exprP,ptr); /* this call takes time Sigh! */ | |
597 | if (addr_modeP->mode == DEFAULT) { | |
598 | if (exprP.X_add_symbol || exprP.X_subtract_symbol) { | |
599 | addr_modeP->mode=desc->default_model; /* we have a label */ | |
600 | } else { | |
601 | addr_modeP->mode=desc->default_modec; /* we have a constant */ | |
602 | } | |
603 | } else { | |
604 | if (exprP.X_add_symbol || exprP.X_subtract_symbol) { | |
605 | addr_modeP->scaled_mode=desc->default_model; | |
606 | } else { | |
607 | addr_modeP->scaled_mode=desc->default_modec; | |
608 | } | |
609 | } | |
610 | /* must put this mess down in addr_mode to handle the scaled case better */ | |
611 | } | |
612 | /* It appears as the sequent compiler wants an absolute when we have a | |
613 | label without @. Constants becomes immediates besides the addr case. | |
614 | Think it does so with local labels too, not optimum, pcrel is better. | |
615 | When I have time I will make gas check this and select pcrel when possible | |
616 | Actually that is trivial. | |
617 | */ | |
618 | if (tmp=addr_modeP->scaled_reg) { /* build indexbyte */ | |
619 | tmp--; /* remember regnumber comes incremented for flagpurpose */ | |
620 | tmp|=addr_modeP->scaled_mode<<3; | |
621 | addr_modeP->index_byte=(char)tmp; | |
622 | addr_modeP->am_size+=1; | |
623 | } | |
624 | if (disp_test[addr_modeP->mode]) { /* there was a displacement, probe for length specifying suffix*/ | |
625 | { | |
626 | register char c; | |
627 | register char suffix; | |
628 | register char suffix_sub; | |
629 | register int i; | |
630 | register char *toP; | |
631 | register char *fromP; | |
632 | ||
633 | addr_modeP->pcrel=0; | |
634 | if (disp_test[addr_modeP->mode]) { /* there is a displacement */ | |
635 | if (addr_modeP->mode==27 || addr_modeP->scaled_mode==27) { /* do we have pcrel. mode */ | |
636 | addr_modeP->pcrel=1; | |
637 | } | |
638 | addr_modeP->im_disp=1; | |
639 | for(i=0;i<2;i++) { | |
640 | suffix_sub=suffix=0; | |
641 | if (toP=addr_modeP->disp[i]) { /* suffix of expression, the largest size rules */ | |
642 | fromP=toP; | |
643 | while (c = *fromP++) { | |
644 | *toP++=c; | |
645 | if (c==':') { | |
646 | switch (*fromP) { | |
647 | case '\0': | |
648 | as_warn("Premature end of suffix--Defaulting to d"); | |
649 | suffix=4; | |
650 | continue; | |
651 | case 'b':suffix_sub=1;break; | |
652 | case 'w':suffix_sub=2;break; | |
653 | case 'd':suffix_sub=4;break; | |
654 | default: | |
655 | as_warn("Bad suffix after ':' use {b|w|d} Defaulting to d"); | |
656 | suffix=4; | |
657 | } | |
658 | fromP++; | |
659 | toP--; /* So we write over the ':' */ | |
660 | if (suffix<suffix_sub) suffix=suffix_sub; | |
661 | } | |
662 | } | |
663 | *toP='\0'; /* terminate properly */ | |
664 | addr_modeP->disp_suffix[i]=suffix; | |
665 | addr_modeP->am_size+=suffix ? suffix : 4; | |
666 | } | |
667 | } | |
668 | } | |
669 | } | |
670 | } else { | |
671 | if (addr_modeP->mode==20) { /* look in ns32k_opcode for size */ | |
672 | addr_modeP->disp_suffix[0]=addr_modeP->am_size=desc->im_size; | |
673 | addr_modeP->im_disp=0; | |
674 | } | |
675 | } | |
676 | return addr_modeP->mode; | |
677 | } | |
678 | ||
679 | ||
680 | /* read an optionlist */ | |
681 | void optlist(str,optionP,default_map) | |
682 | char *str; /* the string to extract options from */ | |
683 | struct option *optionP; /* how to search the string */ | |
684 | unsigned long *default_map; /* default pattern and output */ | |
685 | { | |
686 | register int i,j,k,strlen1,strlen2; | |
687 | register char *patternP,*strP; | |
688 | strlen1=strlen(str); | |
689 | if (strlen1<1) { | |
690 | as_fatal("Very short instr to option, ie you can't do it on a NULLstr"); | |
691 | } | |
692 | for (i=0;optionP[i].pattern!=0;i++) { | |
693 | strlen2=strlen(optionP[i].pattern); | |
694 | for (j=0;j<strlen1;j++) { | |
695 | patternP=optionP[i].pattern; | |
696 | strP = &str[j]; | |
697 | for (k=0;k<strlen2;k++) { | |
698 | if (*(strP++)!=*(patternP++)) break; | |
699 | } | |
700 | if (k==strlen2) { /* match */ | |
701 | *default_map|=optionP[i].or; | |
702 | *default_map&=optionP[i].and; | |
703 | } | |
704 | } | |
705 | } | |
706 | } | |
707 | /* search struct for symbols | |
708 | This function is used to get the short integer form of reg names | |
709 | in the instructions lmr, smr, lpr, spr | |
710 | return true if str is found in list */ | |
711 | ||
712 | int list_search(str,optionP,default_map) | |
713 | char *str; /* the string to match */ | |
714 | struct option *optionP; /* list to search */ | |
715 | unsigned long *default_map; /* default pattern and output */ | |
716 | { | |
717 | register int i; | |
718 | for (i=0;optionP[i].pattern!=0;i++) { | |
719 | if (!strncmp(optionP[i].pattern,str,20)) { /* use strncmp to be safe */ | |
720 | *default_map|=optionP[i].or; | |
721 | *default_map&=optionP[i].and; | |
722 | return -1; | |
723 | } | |
724 | } | |
725 | as_warn("No such entry in list. (cpu/mmu register)"); | |
726 | return 0; | |
727 | } | |
728 | static segT evaluate_expr(resultP,ptr) | |
729 | expressionS *resultP; | |
730 | char *ptr; | |
731 | { | |
732 | register char *tmp_line; | |
733 | register segT segment; | |
734 | tmp_line=input_line_pointer; | |
735 | input_line_pointer=ptr; | |
736 | segment=expression(&exprP); | |
737 | input_line_pointer=tmp_line; | |
738 | return (segment); | |
739 | } | |
740 | \f | |
741 | /* Convert operands to iif-format and adds bitfields to the opcode. | |
742 | Operands are parsed in such an order that the opcode is updated from | |
743 | its most significant bit, that is when the operand need to alter the | |
744 | opcode. | |
745 | Be carefull not to put to objects in the same iif-slot. | |
746 | */ | |
747 | ||
748 | void encode_operand(argc,argv,operandsP,suffixP,im_size,opcode_bit_ptr) | |
749 | int argc; | |
750 | char **argv; | |
751 | char *operandsP; | |
752 | char *suffixP; | |
753 | char im_size; | |
754 | char opcode_bit_ptr; | |
755 | { | |
756 | register int i,j; | |
757 | int pcrel,tmp,b,loop,pcrel_adjust; | |
758 | for(loop=0;loop<argc;loop++) { | |
759 | i=operandsP[loop<<1]-'1'; /* what operand are we supposed to work on */ | |
760 | if (i>3) as_fatal("Internal consistency error. check ns32k-opcode.h"); | |
761 | pcrel=0; | |
762 | pcrel_adjust=0; | |
763 | tmp=0; | |
764 | switch (operandsP[(loop<<1)+1]) { | |
765 | case 'f': /* operand of sfsr turns out to be a nasty specialcase */ | |
766 | opcode_bit_ptr-=5; | |
767 | case 'F': /* 32 bit float general form */ | |
768 | case 'L': /* 64 bit float */ | |
769 | case 'Q': /* quad-word */ | |
770 | case 'B': /* byte */ | |
771 | case 'W': /* word */ | |
772 | case 'D': /* double-word */ | |
773 | case 'A': /* double-word gen-address-form ie no regs allowed */ | |
774 | get_addr_mode(argv[i],&addr_modeP); | |
775 | iif.instr_size+=addr_modeP.am_size; | |
776 | if (opcode_bit_ptr==desc->opcode_size) b=4; else b=6; | |
777 | for (j=b;j<(b+2);j++) { | |
778 | if (addr_modeP.disp[j-b]) { | |
779 | IIF(j, | |
780 | 2, | |
781 | addr_modeP.disp_suffix[j-b], | |
782 | (unsigned long)addr_modeP.disp[j-b], | |
783 | 0, | |
784 | addr_modeP.pcrel, | |
785 | iif.instr_size-addr_modeP.am_size, /* this aint used (now) */ | |
786 | addr_modeP.im_disp, | |
787 | IND(BRANCH,BYTE), | |
788 | NULL, | |
789 | addr_modeP.scaled_reg ? addr_modeP.scaled_mode:addr_modeP.mode, | |
790 | 0); | |
791 | } | |
792 | } | |
793 | opcode_bit_ptr-=5; | |
794 | iif.iifP[1].object|=((long)addr_modeP.mode)<<opcode_bit_ptr; | |
795 | if (addr_modeP.scaled_reg) { | |
796 | j=b/2; | |
797 | IIF(j,1,1, (unsigned long)addr_modeP.index_byte,0,0,0,0,0, NULL,-1,0); | |
798 | } | |
799 | break; | |
800 | case 'b': /* multiple instruction disp */ | |
801 | freeptr++; /* OVE:this is an useful hack */ | |
802 | tmp=(int)sprintf(freeptr,"((%s-1)*%d)\000",argv[i],desc->im_size); | |
803 | argv[i]=freeptr; | |
804 | freeptr=(char*)tmp; | |
805 | pcrel-=1; /* make pcrel 0 inspite of what case 'p': wants */ | |
806 | /* fall thru */ | |
807 | case 'p': /* displacement - pc relative addressing */ | |
808 | pcrel+=1; | |
809 | /* fall thru */ | |
810 | case 'd': /* displacement */ | |
811 | iif.instr_size+=suffixP[i] ? suffixP[i] : 4; | |
812 | IIF(12, 2, suffixP[i], (unsigned long)argv[i], 0, | |
813 | pcrel, pcrel_adjust, 1, IND(BRANCH,BYTE), NULL,-1,0); | |
814 | break; | |
815 | case 'H': /* sequent-hack: the linker wants a bit set when bsr */ | |
816 | pcrel=1; | |
817 | iif.instr_size+=suffixP[i] ? suffixP[i] : 4; | |
818 | IIF(12, 2, suffixP[i], (unsigned long)argv[i], 0, | |
819 | pcrel, pcrel_adjust, 1, IND(BRANCH,BYTE), NULL,-1,1);break; | |
820 | case 'q': /* quick */ | |
821 | opcode_bit_ptr-=4; | |
822 | IIF(11,2,42,(unsigned long)argv[i],0,0,0,0,0, | |
823 | bit_fix_new(4,opcode_bit_ptr,-8,7,0,1,0),-1,0); | |
824 | break; | |
825 | case 'r': /* register number (3 bits) */ | |
826 | list_search(argv[i],opt6,&tmp); | |
827 | opcode_bit_ptr-=3; | |
828 | iif.iifP[1].object|=tmp<<opcode_bit_ptr; | |
829 | break; | |
830 | case 'O': /* setcfg instruction optionslist */ | |
831 | optlist(argv[i],opt3,&tmp); | |
832 | opcode_bit_ptr-=4; | |
833 | iif.iifP[1].object|=tmp<<15; | |
834 | break; | |
835 | case 'C': /* cinv instruction optionslist */ | |
836 | optlist(argv[i],opt4,&tmp); | |
837 | opcode_bit_ptr-=4; | |
838 | iif.iifP[1].object|=tmp<<15;/*insert the regtype in opcode */ | |
839 | break; | |
840 | case 'S': /* stringinstruction optionslist */ | |
841 | optlist(argv[i],opt5,&tmp); | |
842 | opcode_bit_ptr-=4; | |
843 | iif.iifP[1].object|=tmp<<15; | |
844 | break; | |
845 | case 'u':case 'U': /* registerlist */ | |
846 | IIF(10,1,1,0,0,0,0,0,0,NULL,-1,0); | |
847 | switch (operandsP[(i<<1)+1]) { | |
848 | case 'u': /* restore, exit */ | |
849 | optlist(argv[i],opt1,&iif.iifP[10].object); | |
850 | break; | |
851 | case 'U': /* save,enter */ | |
852 | optlist(argv[i],opt2,&iif.iifP[10].object); | |
853 | break; | |
854 | } | |
855 | iif.instr_size+=1; | |
856 | break; | |
857 | case 'M': /* mmu register */ | |
858 | list_search(argv[i],mmureg,&tmp); | |
859 | opcode_bit_ptr-=4; | |
860 | iif.iifP[1].object|=tmp<<opcode_bit_ptr; | |
861 | break; | |
862 | case 'P': /* cpu register */ | |
863 | list_search(argv[i],cpureg,&tmp); | |
864 | opcode_bit_ptr-=4; | |
865 | iif.iifP[1].object|=tmp<<opcode_bit_ptr; | |
866 | break; | |
867 | case 'g': /* inss exts */ | |
868 | iif.instr_size+=1; /* 1 byte is allocated after the opcode */ | |
869 | IIF(10,2,1, | |
870 | (unsigned long)argv[i], /* i always 2 here */ | |
871 | 0,0,0,0,0, | |
872 | bit_fix_new(3,5,0,7,0,0,0), /* a bit_fix is targeted to the byte */ | |
873 | -1,0); | |
874 | case 'G': | |
875 | IIF(11,2,42, | |
876 | (unsigned long)argv[i], /* i always 3 here */ | |
877 | 0,0,0,0,0, | |
878 | bit_fix_new(5,0,1,32,-1,0,-1),-1,0); | |
879 | break; | |
880 | case 'i': | |
881 | iif.instr_size+=1; | |
882 | b=2+i; /* put the extension byte after opcode */ | |
883 | IIF(b,2,1,0,0,0,0,0,0,0,-1,0); | |
884 | default: | |
885 | as_fatal("Bad opcode-table-option, check in file ns32k-opcode.h"); | |
886 | } | |
887 | } | |
888 | } | |
889 | \f | |
890 | /* in: instruction line | |
891 | out: internal structure of instruction | |
892 | that has been prepared for direct conversion to fragment(s) and | |
893 | fixes in a systematical fashion | |
894 | Return-value = recursive_level | |
895 | */ | |
896 | /* build iif of one assembly text line */ | |
897 | int parse(line,recursive_level) | |
898 | char *line; | |
899 | int recursive_level; | |
900 | { | |
901 | register char *lineptr,c,suffix_separator; | |
902 | register int i; | |
903 | int argc,arg_type; | |
904 | char sqr,sep; | |
905 | char suffix[MAX_ARGS],*argv[MAX_ARGS];/* no more than 4 operands */ | |
906 | if (recursive_level<=0) { /* called from md_assemble */ | |
907 | for (lineptr=line;(*lineptr)!='\0' && (*lineptr)!=' ';lineptr++); | |
908 | c = *lineptr; | |
909 | *lineptr='\0'; | |
910 | if (!(desc=(struct ns32k_opcode*)hash_find(inst_hash_handle,line))) { | |
911 | as_fatal("No such opcode"); | |
912 | } | |
913 | *lineptr=c; | |
914 | } else { | |
915 | lineptr=line; | |
916 | } | |
917 | argc=0; | |
918 | if (*desc->operands) { | |
919 | if (*lineptr++!='\0') { | |
920 | sqr='['; | |
921 | sep=','; | |
922 | while (*lineptr!='\0') { | |
923 | if (desc->operands[argc<<1]) { | |
924 | suffix[argc]=0; | |
925 | arg_type=desc->operands[(argc<<1)+1]; | |
926 | switch (arg_type) { | |
927 | case 'd': case 'b': case 'p': case 'H': /* the operand is supposed to be a displacement */ | |
928 | /* Hackwarning: do not forget to update the 4 cases above when editing ns32k-opcode.h */ | |
929 | suffix_separator=':'; | |
930 | break; | |
931 | default: | |
932 | suffix_separator='\255'; /* if this char occurs we loose */ | |
933 | } | |
934 | suffix[argc]=0; /* 0 when no ':' is encountered */ | |
935 | argv[argc]=freeptr; | |
936 | *freeptr='\0'; | |
937 | while ((c = *lineptr)!='\0' && c!=sep) { | |
938 | if (c==sqr) { | |
939 | if (sqr=='[') { | |
940 | sqr=']';sep='\0'; | |
941 | } else { | |
942 | sqr='[';sep=','; | |
943 | } | |
944 | } | |
945 | if (c==suffix_separator) { /* ':' - label/suffix separator */ | |
946 | switch (lineptr[1]) { | |
947 | case 'b':suffix[argc]=1;break; | |
948 | case 'w':suffix[argc]=2;break; | |
949 | case 'd':suffix[argc]=4;break; | |
950 | default: as_warn("Bad suffix, defaulting to d"); | |
951 | suffix[argc]=4; | |
952 | if (lineptr[1]=='\0' || lineptr[1]==sep) { | |
953 | lineptr+=1; | |
954 | continue; | |
955 | } | |
956 | } | |
957 | lineptr+=2; | |
958 | continue; | |
959 | } | |
960 | *freeptr++=c; | |
961 | lineptr++; | |
962 | } | |
963 | *freeptr++='\0'; | |
964 | argc+=1; | |
965 | if (*lineptr=='\0') continue; | |
966 | lineptr+=1; | |
967 | } else { | |
968 | as_fatal("Too many operands passed to instruction"); | |
969 | } | |
970 | } | |
971 | } | |
972 | } | |
973 | if (argc!=strlen(desc->operands)/2) { | |
974 | if (strlen(desc->default_args)) { /* we can apply default, dont goof */ | |
975 | if (parse(desc->default_args,1)!=1) { /* check error in default */ | |
976 | as_fatal("Wrong numbers of operands in default, check ns32k-opcodes.h"); | |
977 | } | |
978 | } else { | |
979 | as_fatal("Wrong number of operands"); | |
980 | } | |
981 | ||
982 | } | |
983 | for (i=0;i<IIF_ENTRIES;i++) { | |
984 | iif.iifP[i].type=0; /* mark all entries as void*/ | |
985 | } | |
986 | ||
987 | /* build opcode iif-entry */ | |
988 | iif.instr_size=desc->opcode_size/8; | |
989 | IIF(1,1,iif.instr_size,desc->opcode_seed,0,0,0,0,0,0,-1,0); | |
990 | ||
991 | /* this call encodes operands to iif format */ | |
992 | if (argc) { | |
993 | encode_operand(argc, | |
994 | argv, | |
995 | &desc->operands[0], | |
996 | &suffix[0], | |
997 | desc->im_size, | |
998 | desc->opcode_size); | |
999 | } | |
1000 | return recursive_level; | |
1001 | } | |
1002 | ||
1003 | \f | |
1004 | /* Convert iif to fragments. | |
1005 | From this point we start to dribble with functions in other files than | |
1006 | this one.(Except hash.c) So, if it's possible to make an iif for an other | |
1007 | CPU, you don't need to know what frags, relax, obstacks, etc is in order | |
1008 | to port this assembler. You only need to know if it's possible to reduce | |
1009 | your cpu-instruction to iif-format (takes some work) and adopt the other | |
1010 | md_? parts according to given instructions | |
1011 | Note that iif was invented for the clean ns32k`s architecure. | |
1012 | */ | |
1013 | void convert_iif() { | |
1014 | register int i,j; | |
1015 | fragS *inst_frag; | |
1016 | char *inst_offset,*inst_opcode; | |
1017 | char *memP; | |
1018 | segT segment; | |
1019 | int l,k; | |
1020 | register int rem_size; /* count the remaining bytes of instruction */ | |
1021 | register char type; | |
1022 | register char size = 0; | |
1023 | int size_so_far=0; /* used to calculate pcrel_adjust */ | |
1024 | ||
1025 | rem_size=iif.instr_size; | |
1026 | memP=frag_more(iif.instr_size); /* make sure we have enough bytes for instruction */ | |
1027 | inst_opcode=memP; | |
1028 | inst_offset=(char*)(memP-frag_now->fr_literal); | |
1029 | inst_frag=frag_now; | |
1030 | for (i=0;i<IIF_ENTRIES;i++) { | |
1031 | if (type=iif.iifP[i].type) { /* the object exist, so handle it */ | |
1032 | switch (size=iif.iifP[i].size) { | |
1033 | case 42: size=0; /* it's a bitfix that operates on an existing object*/ | |
1034 | if (iif.iifP[i].bit_fixP->fx_bit_base) { /* expand fx_bit_base to point at opcode */ | |
1035 | iif.iifP[i].bit_fixP->fx_bit_base=(long)inst_opcode; | |
1036 | } | |
1037 | case 8: /* bignum or doublefloat */ | |
1038 | bzero (memP,8); | |
1039 | case 1:case 2:case 3:case 4:/* the final size in objectmemory is known */ | |
1040 | j=(unsigned long)iif.iifP[i].bit_fixP; | |
1041 | switch (type) { | |
1042 | case 1: /* the object is pure binary */ | |
1043 | if (j || iif.iifP[i].pcrel) { | |
1044 | fix_new_ns32k(frag_now, | |
1045 | (long)(memP-frag_now->fr_literal), | |
1046 | size, | |
1047 | 0, | |
1048 | 0, | |
1049 | iif.iifP[i].object, | |
1050 | iif.iifP[i].pcrel, | |
1051 | (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/ | |
1052 | iif.iifP[i].im_disp, | |
1053 | j, | |
1054 | iif.iifP[i].bsr); /* sequent hack */ | |
1055 | } else { /* good, just put them bytes out */ | |
1056 | switch (iif.iifP[i].im_disp) { | |
1057 | case 0: | |
1058 | md_number_to_chars(memP,iif.iifP[i].object,size);break; | |
1059 | case 1: | |
1060 | md_number_to_disp(memP,iif.iifP[i].object,size);break; | |
1061 | default: as_fatal("iif convert internal pcrel/binary"); | |
1062 | } | |
1063 | } | |
1064 | memP+=size; | |
1065 | rem_size-=size; | |
1066 | break; | |
1067 | case 2: /* the object is a pointer at an expression, so unpack | |
1068 | it, note that bignums may result from the expression | |
1069 | */ | |
1070 | if ((segment=evaluate_expr(&exprP,(char*)iif.iifP[i].object))==SEG_BIG || size==8) { | |
1071 | if ((k=exprP.X_add_number)>0) { /* we have a bignum ie a quad */ | |
1072 | /* this can only happens in a long suffixed instruction */ | |
1073 | bzero(memP,size); /* size normally is 8 */ | |
1074 | if (k*2>size) as_warn("Bignum too big for long"); | |
1075 | if (k==3) memP+=2; | |
1076 | for (l=0;k>0;k--,l+=2) { | |
1077 | md_number_to_chars(memP+l,generic_bignum[l>>1],sizeof(LITTLENUM_TYPE)); | |
1078 | } | |
1079 | } else { /* flonum */ | |
1080 | LITTLENUM_TYPE words[4]; | |
1081 | ||
1082 | switch(size) { | |
1083 | case 4: | |
1084 | gen_to_words(words,2,8); | |
1085 | md_number_to_imm(memP ,(long)words[0],sizeof(LITTLENUM_TYPE)); | |
1086 | md_number_to_imm(memP+sizeof(LITTLENUM_TYPE),(long)words[1],sizeof(LITTLENUM_TYPE)); | |
1087 | break; | |
1088 | case 8: | |
1089 | gen_to_words(words,4,11); | |
1090 | md_number_to_imm(memP ,(long)words[0],sizeof(LITTLENUM_TYPE)); | |
1091 | md_number_to_imm(memP+sizeof(LITTLENUM_TYPE) ,(long)words[1],sizeof(LITTLENUM_TYPE)); | |
1092 | md_number_to_imm(memP+2*sizeof(LITTLENUM_TYPE),(long)words[2],sizeof(LITTLENUM_TYPE)); | |
1093 | md_number_to_imm(memP+3*sizeof(LITTLENUM_TYPE),(long)words[3],sizeof(LITTLENUM_TYPE)); | |
1094 | break; | |
1095 | } | |
1096 | } | |
1097 | memP+=size; | |
1098 | rem_size-=size; | |
1099 | break; | |
1100 | } | |
1101 | if (j || | |
1102 | exprP.X_add_symbol || | |
1103 | exprP.X_subtract_symbol || | |
1104 | iif.iifP[i].pcrel) { /* fixit */ | |
1105 | /* the expression was undefined due to an undefined label */ | |
1106 | /* create a fix so we can fix the object later */ | |
1107 | exprP.X_add_number+=iif.iifP[i].object_adjust; | |
1108 | fix_new_ns32k(frag_now, | |
1109 | (long)(memP-frag_now->fr_literal), | |
1110 | size, | |
1111 | exprP.X_add_symbol, | |
1112 | exprP.X_subtract_symbol, | |
1113 | exprP.X_add_number, | |
1114 | iif.iifP[i].pcrel, | |
1115 | (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/ | |
1116 | iif.iifP[i].im_disp, | |
1117 | j, | |
1118 | iif.iifP[i].bsr); /* sequent hack */ | |
1119 | ||
1120 | } else { /* good, just put them bytes out */ | |
1121 | switch (iif.iifP[i].im_disp) { | |
1122 | case 0: | |
1123 | md_number_to_imm(memP,exprP.X_add_number,size);break; | |
1124 | case 1: | |
1125 | md_number_to_disp(memP,exprP.X_add_number,size);break; | |
1126 | default: as_fatal("iif convert internal pcrel/pointer"); | |
1127 | } | |
1128 | } | |
1129 | memP+=size; | |
1130 | rem_size-=size; | |
1131 | break; | |
1132 | default: as_fatal("Internal logic error in iif.iifP[n].type"); | |
1133 | } | |
1134 | break; | |
1135 | case 0: /* To bad, the object may be undefined as far as its final | |
1136 | nsize in object memory is concerned. The size of the object | |
1137 | in objectmemory is not explicitly given. | |
1138 | If the object is defined its length can be determined and | |
1139 | a fix can replace the frag. | |
1140 | */ | |
1141 | { | |
1142 | int temp; | |
1143 | segment=evaluate_expr(&exprP,(char*)iif.iifP[i].object); | |
1144 | if ((exprP.X_add_symbol || exprP.X_subtract_symbol) && | |
1145 | !iif.iifP[i].pcrel) { /* OVE: hack, clamp to 4 bytes */ | |
1146 | size=4; /* we dont wan't to frag this, use 4 so it reaches */ | |
1147 | fix_new_ns32k(frag_now, | |
1148 | (long)(memP-frag_now->fr_literal), | |
1149 | size, | |
1150 | exprP.X_add_symbol, | |
1151 | exprP.X_subtract_symbol, | |
1152 | exprP.X_add_number, | |
1153 | 0, /* never iif.iifP[i].pcrel, */ | |
1154 | (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/ | |
1155 | 1, /* always iif.iifP[i].im_disp, */ | |
1156 | 0,0); | |
1157 | memP+=size; | |
1158 | rem_size-=4; | |
1159 | break; /* exit this absolute hack */ | |
1160 | } | |
1161 | ||
1162 | if (exprP.X_add_symbol || exprP.X_subtract_symbol) { /* frag it */ | |
1163 | if (exprP.X_subtract_symbol) { /* We cant relax this case */ | |
1164 | as_fatal("Can't relax difference"); | |
1165 | } | |
1166 | else { | |
1167 | /* at this stage we must undo some of the effect caused | |
1168 | by frag_more, ie we must make sure that frag_var causes | |
1169 | frag_new to creat a valid fix-size in the frag it`s closing | |
1170 | */ | |
1171 | temp = -(rem_size-4); | |
1172 | obstack_blank_fast(&frags,temp); | |
1173 | /* we rewind none, some or all of the requested size we | |
1174 | requested by the first frag_more for this iif chunk. | |
1175 | Note: that we allocate 4 bytes to an object we NOT YET | |
1176 | know the size of, thus rem_size-4. | |
1177 | */ | |
1178 | (void)frag_variant(rs_machine_dependent, | |
1179 | 4, | |
1180 | 0, | |
1181 | IND(BRANCH,UNDEF), /* expecting the worst */ | |
1182 | exprP.X_add_symbol, | |
1183 | exprP.X_add_number, | |
1184 | (char*)inst_opcode, | |
1185 | (char)size_so_far, /*iif.iifP[i].pcrel_adjust);*/ | |
1186 | iif.iifP[i].bsr); /* sequent linker hack */ | |
1187 | rem_size-=4; | |
1188 | if (rem_size>0) { | |
1189 | memP=frag_more(rem_size); | |
1190 | } | |
1191 | } | |
1192 | } | |
1193 | else {/* Double work, this is done in md_number_to_disp */ | |
1194 | /* exprP.X_add_number; what was this supposed to be? | |
1195 | xoxorich. */ | |
1196 | if (-64<=exprP.X_add_number && exprP.X_add_number<=63) { | |
1197 | size=1; | |
1198 | } else { | |
1199 | if (-8192<=exprP.X_add_number && exprP.X_add_number<=8191) { | |
1200 | size=2; | |
1201 | } else { | |
1202 | if (-0x1f000000<=exprP.X_add_number && | |
1203 | exprP.X_add_number<=0x1fffffff) | |
1204 | /* if (-0x40000000<=exprP.X_add_number && | |
1205 | exprP.X_add_number<=0x3fffffff) */ | |
1206 | { | |
1207 | size=4; | |
1208 | } else { | |
1209 | as_warn("Displacement to large for :d"); | |
1210 | size=4; | |
1211 | } | |
1212 | } | |
1213 | } | |
1214 | /* rewind the bytes not used */ | |
1215 | temp = -(4-size); | |
1216 | md_number_to_disp(memP,exprP.X_add_number,size); | |
1217 | obstack_blank_fast(&frags,temp); | |
1218 | memP+=size; | |
1219 | rem_size-=4; /* we allocated this amount */ | |
1220 | } | |
1221 | } | |
1222 | break; | |
1223 | default: | |
1224 | as_fatal("Internal logic error in iif.iifP[].type"); | |
1225 | } | |
1226 | size_so_far+=size; | |
1227 | size=0; | |
1228 | } | |
1229 | } | |
1230 | } | |
1231 | \f | |
1232 | void md_assemble(line) | |
1233 | char *line; | |
1234 | { | |
1235 | freeptr=freeptr_static; | |
1236 | parse(line,0); /* explode line to more fix form in iif */ | |
1237 | convert_iif(); /* convert iif to frags, fix's etc */ | |
1238 | #ifdef SHOW_NUM | |
1239 | printf(" \t\t\t%s\n",line); | |
1240 | #endif | |
1241 | } | |
1242 | ||
1243 | ||
1244 | void md_begin() { | |
1245 | /* build a hashtable of the instructions */ | |
1246 | register const struct ns32k_opcode *ptr; | |
1247 | register char *stat; | |
1248 | inst_hash_handle=hash_new(); | |
1249 | for (ptr=ns32k_opcodes;ptr<endop;ptr++) { | |
1250 | if (*(stat=hash_insert(inst_hash_handle,ptr->name,(char*)ptr))) { | |
1251 | as_fatal("Can't hash %s: %s", ptr->name,stat); /*fatal*/ | |
1252 | exit(0); | |
1253 | } | |
1254 | } | |
1255 | freeptr_static=(char*)malloc(PRIVATE_SIZE); /* some private space please! */ | |
1256 | } | |
1257 | ||
1258 | ||
1259 | void | |
1260 | md_end() { | |
1261 | free(freeptr_static); | |
1262 | } | |
1263 | ||
1264 | /* Must be equal to MAX_PRECISON in atof-ieee.c */ | |
1265 | #define MAX_LITTLENUMS 6 | |
1266 | ||
1267 | /* Turn the string pointed to by litP into a floating point constant of type | |
1268 | type, and emit the appropriate bytes. The number of LITTLENUMS emitted | |
1269 | is stored in *sizeP . An error message is returned, or NULL on OK. | |
1270 | */ | |
1271 | char * | |
1272 | md_atof(type,litP,sizeP) | |
1273 | char type; | |
1274 | char *litP; | |
1275 | int *sizeP; | |
1276 | { | |
1277 | int prec; | |
1278 | LITTLENUM_TYPE words[MAX_LITTLENUMS]; | |
1279 | LITTLENUM_TYPE *wordP; | |
1280 | char *t; | |
1281 | ||
1282 | switch(type) { | |
1283 | case 'f': | |
1284 | prec = 2; | |
1285 | break; | |
1286 | ||
1287 | case 'd': | |
1288 | prec = 4; | |
1289 | break; | |
1290 | default: | |
1291 | *sizeP=0; | |
1292 | return "Bad call to MD_ATOF()"; | |
1293 | } | |
1294 | t=atof_ieee(input_line_pointer,type,words); | |
1295 | if(t) | |
1296 | input_line_pointer=t; | |
1297 | ||
1298 | *sizeP=prec * sizeof(LITTLENUM_TYPE); | |
1299 | for(wordP=words+prec;prec--;) { | |
1300 | md_number_to_chars(litP,(long)(*--wordP),sizeof(LITTLENUM_TYPE)); | |
1301 | litP+=sizeof(LITTLENUM_TYPE); | |
1302 | } | |
1303 | return ""; /* Someone should teach Dean about null pointers */ | |
1304 | } | |
1305 | \f | |
1306 | /* Convert number to chars in correct order */ | |
1307 | ||
1308 | void | |
1309 | md_number_to_chars (buf, value, nbytes) | |
1310 | char *buf; | |
1311 | long value; | |
1312 | int nbytes; | |
1313 | { | |
1314 | while (nbytes--) | |
1315 | { | |
1316 | #ifdef SHOW_NUM | |
1317 | printf("%x ",value & 0xff); | |
1318 | #endif | |
1319 | *buf++ = value; /* Lint wants & MASK_CHAR. */ | |
1320 | value >>= BITS_PER_CHAR; | |
1321 | } | |
1322 | } | |
1323 | /* Convert number to chars in correct order */ | |
1324 | ||
1325 | ||
1326 | ||
1327 | /* This is a variant of md_numbers_to_chars. The reason for its' existence | |
1328 | is the fact that ns32k uses Huffman coded displacements. This implies | |
1329 | that the bit order is reversed in displacements and that they are prefixed | |
1330 | with a size-tag. | |
1331 | ||
1332 | binary: msb -> lsb 0xxxxxxx byte | |
1333 | 10xxxxxx xxxxxxxx word | |
1334 | 11xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx double word | |
1335 | ||
1336 | This must be taken care of and we do it here! | |
1337 | */ | |
1338 | static void md_number_to_disp(buf,val,n) | |
1339 | char *buf; | |
1340 | long val; | |
1341 | char n; | |
1342 | { | |
1343 | switch(n) { | |
1344 | case 1: | |
1345 | if (val < -64 || val > 63) | |
1346 | as_warn("Byte displacement out of range. line number not valid"); | |
1347 | val&=0x7f; | |
1348 | #ifdef SHOW_NUM | |
1349 | printf("%x ",val & 0xff); | |
1350 | #endif | |
1351 | *buf++=val; | |
1352 | break; | |
1353 | case 2: | |
1354 | if (val < -8192 || val > 8191) | |
1355 | as_warn("Word displacement out of range. line number not valid"); | |
1356 | val&=0x3fff; | |
1357 | val|=0x8000; | |
1358 | #ifdef SHOW_NUM | |
1359 | printf("%x ",val>>8 & 0xff); | |
1360 | #endif | |
1361 | *buf++=(val>>8); | |
1362 | #ifdef SHOW_NUM | |
1363 | printf("%x ",val & 0xff); | |
1364 | #endif | |
1365 | *buf++=val; | |
1366 | break; | |
1367 | case 4: | |
1368 | if (val < -0x1f000000 || val >= 0x20000000) | |
1369 | /* if (val < -0x20000000 || val >= 0x20000000) */ | |
1370 | as_warn("Double word displacement out of range"); | |
1371 | val|=0xc0000000; | |
1372 | #ifdef SHOW_NUM | |
1373 | printf("%x ",val>>24 & 0xff); | |
1374 | #endif | |
1375 | *buf++=(val>>24); | |
1376 | #ifdef SHOW_NUM | |
1377 | printf("%x ",val>>16 & 0xff); | |
1378 | #endif | |
1379 | *buf++=(val>>16); | |
1380 | #ifdef SHOW_NUM | |
1381 | printf("%x ",val>>8 & 0xff); | |
1382 | #endif | |
1383 | *buf++=(val>>8); | |
1384 | #ifdef SHOW_NUM | |
1385 | printf("%x ",val & 0xff); | |
1386 | #endif | |
1387 | *buf++=val; | |
1388 | break; | |
1389 | default: | |
1390 | as_fatal("Internal logic error. line %s, file \"%s\"", __LINE__, __FILE__); | |
1391 | } | |
1392 | } | |
1393 | ||
1394 | static void md_number_to_imm(buf,val,n) | |
1395 | char *buf; | |
1396 | long val; | |
1397 | char n; | |
1398 | { | |
1399 | switch(n) { | |
1400 | case 1: | |
1401 | #ifdef SHOW_NUM | |
1402 | printf("%x ",val & 0xff); | |
1403 | #endif | |
1404 | *buf++=val; | |
1405 | break; | |
1406 | case 2: | |
1407 | #ifdef SHOW_NUM | |
1408 | printf("%x ",val>>8 & 0xff); | |
1409 | #endif | |
1410 | *buf++=(val>>8); | |
1411 | #ifdef SHOW_NUM | |
1412 | printf("%x ",val & 0xff); | |
1413 | #endif | |
1414 | *buf++=val; | |
1415 | break; | |
1416 | case 4: | |
1417 | #ifdef SHOW_NUM | |
1418 | printf("%x ",val>>24 & 0xff); | |
1419 | #endif | |
1420 | *buf++=(val>>24); | |
1421 | #ifdef SHOW_NUM | |
1422 | printf("%x ",val>>16 & 0xff); | |
1423 | #endif | |
1424 | *buf++=(val>>16); | |
1425 | #ifdef SHOW_NUM | |
1426 | printf("%x ",val>>8 & 0xff); | |
1427 | #endif | |
1428 | *buf++=(val>>8); | |
1429 | #ifdef SHOW_NUM | |
1430 | printf("%x ",val & 0xff); | |
1431 | #endif | |
1432 | *buf++=val; | |
1433 | break; | |
1434 | default: | |
1435 | as_fatal("Internal logic error. line %s, file \"%s\"", __LINE__, __FILE__); | |
1436 | } | |
1437 | } | |
1438 | ||
1439 | /* Translate internal representation of relocation info into target format. | |
1440 | ||
1441 | OVE: on a ns32k the twiddling continues at an even deeper level | |
1442 | here we have to distinguish between displacements and immediates. | |
1443 | ||
1444 | The sequent has a bit for this. It also has a bit for relocobjects that | |
1445 | points at the target for a bsr (BranchSubRoutine) !?!?!?! | |
1446 | ||
1447 | This md_ri.... is tailored for sequent. | |
1448 | */ | |
1449 | ||
1450 | void | |
1451 | md_ri_to_chars(the_bytes, ri) | |
1452 | char *the_bytes; | |
1453 | struct reloc_info_generic *ri; | |
1454 | { | |
1455 | if (ri->r_bsr) {ri->r_pcrel=0;} /* sequent seems to want this */ | |
1456 | md_number_to_chars(the_bytes, ri->r_address, sizeof(ri->r_address)); | |
1457 | md_number_to_chars(the_bytes+4, | |
1458 | (long)(ri->r_symbolnum ) | | |
1459 | (long)(ri->r_pcrel << 24 ) | | |
1460 | (long)(ri->r_length << 25 ) | | |
1461 | (long)(ri->r_extern << 27 ) | | |
1462 | (long)(ri->r_bsr << 28 ) | | |
1463 | (long)(ri->r_disp << 29 ), | |
1464 | 4); | |
1465 | /* the first and second md_number_to_chars never overlaps (32bit cpu case) */ | |
1466 | } | |
1467 | \f | |
1468 | /* fast bitfiddling support */ | |
1469 | /* mask used to zero bitfield before oring in the true field */ | |
1470 | ||
1471 | static unsigned long l_mask[]={ 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8, | |
1472 | 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, | |
1473 | 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800, | |
1474 | 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, | |
1475 | 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000, | |
1476 | 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000, | |
1477 | 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000, | |
1478 | 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000, | |
1479 | }; | |
1480 | static unsigned long r_mask[]={ 0x00000000, 0x00000001, 0x00000003, 0x00000007, | |
1481 | 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, | |
1482 | 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, | |
1483 | 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, | |
1484 | 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, | |
1485 | 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, | |
1486 | 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, | |
1487 | 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, | |
1488 | }; | |
1489 | #define MASK_BITS 31 | |
1490 | /* Insert bitfield described by field_ptr and val at buf | |
1491 | This routine is written for modification of the first 4 bytes pointed | |
1492 | to by buf, to yield speed. | |
1493 | The ifdef stuff is for selection between a ns32k-dependent routine | |
1494 | and a general version. (My advice: use the general version!) | |
1495 | */ | |
1496 | ||
1497 | static void | |
1498 | md_number_to_field(buf,val,field_ptr) | |
1499 | register char *buf; | |
1500 | register long val; | |
1501 | register bit_fixS *field_ptr; | |
1502 | { | |
1503 | register unsigned long object; | |
1504 | register unsigned long mask; | |
1505 | /* define ENDIAN on a ns32k machine */ | |
1506 | #ifdef ENDIAN | |
1507 | register unsigned long *mem_ptr; | |
1508 | #else | |
1509 | register char *mem_ptr; | |
1510 | #endif | |
1511 | if (field_ptr->fx_bit_min<=val && val<=field_ptr->fx_bit_max) { | |
1512 | #ifdef ENDIAN | |
1513 | if (field_ptr->fx_bit_base) { /* override buf */ | |
1514 | mem_ptr=(unsigned long*)field_ptr->fx_bit_base; | |
1515 | } else { | |
1516 | mem_ptr=(unsigned long*)buf; | |
1517 | } | |
1518 | #else | |
1519 | if (field_ptr->fx_bit_base) { /* override buf */ | |
1520 | mem_ptr=(char*)field_ptr->fx_bit_base; | |
1521 | } else { | |
1522 | mem_ptr=buf; | |
1523 | } | |
1524 | #endif | |
1525 | mem_ptr+=field_ptr->fx_bit_base_adj; | |
1526 | #ifdef ENDIAN /* we have a nice ns32k machine with lowbyte at low-physical mem */ | |
1527 | object = *mem_ptr; /* get some bytes */ | |
1528 | #else /* OVE Goof! the machine is a m68k or dito */ | |
1529 | /* That takes more byte fiddling */ | |
1530 | object=0; | |
1531 | object|=mem_ptr[3] & 0xff; | |
1532 | object<<=8; | |
1533 | object|=mem_ptr[2] & 0xff; | |
1534 | object<<=8; | |
1535 | object|=mem_ptr[1] & 0xff; | |
1536 | object<<=8; | |
1537 | object|=mem_ptr[0] & 0xff; | |
1538 | #endif | |
1539 | mask=0; | |
1540 | mask|=(r_mask[field_ptr->fx_bit_offset]); | |
1541 | mask|=(l_mask[field_ptr->fx_bit_offset+field_ptr->fx_bit_size]); | |
1542 | object&=mask; | |
1543 | val+=field_ptr->fx_bit_add; | |
1544 | object|=((val<<field_ptr->fx_bit_offset) & (mask ^ 0xffffffff)); | |
1545 | #ifdef ENDIAN | |
1546 | *mem_ptr=object; | |
1547 | #else | |
1548 | mem_ptr[0]=(char)object; | |
1549 | object>>=8; | |
1550 | mem_ptr[1]=(char)object; | |
1551 | object>>=8; | |
1552 | mem_ptr[2]=(char)object; | |
1553 | object>>=8; | |
1554 | mem_ptr[3]=(char)object; | |
1555 | #endif | |
1556 | } else { | |
1557 | as_warn("Bit field out of range"); | |
1558 | } | |
1559 | } | |
1560 | ||
1561 | /* Apply a fixS (fixup of an instruction or data that we didn't have | |
1562 | enough info to complete immediately) to the data in a frag. | |
1563 | ||
1564 | On the ns32k, everything is in a different format, so we have broken | |
1565 | out separate functions for each kind of thing we could be fixing. | |
1566 | They all get called from here. */ | |
1567 | ||
1568 | void | |
1569 | md_apply_fix(fixP, val) | |
1570 | fixS *fixP; | |
1571 | long val; | |
1572 | { | |
1573 | char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; | |
1574 | ||
1575 | if (fixP->fx_bit_fixP) { /* Bitfields to fix, sigh */ | |
1576 | md_number_to_field (buf, val, fixP->fx_bit_fixP); | |
1577 | } else switch (fixP->fx_im_disp) { | |
1578 | ||
1579 | case 0: /* Immediate field */ | |
1580 | md_number_to_imm (buf, val, fixP->fx_size); | |
1581 | break; | |
1582 | ||
1583 | case 1: /* Displacement field */ | |
1584 | md_number_to_disp (buf, | |
1585 | fixP->fx_pcrel? val + fixP->fx_pcrel_adjust: val, | |
1586 | fixP->fx_size); | |
1587 | break; | |
1588 | ||
1589 | case 2: /* Pointer in a data object */ | |
1590 | md_number_to_chars (buf, val, fixP->fx_size); | |
1591 | break; | |
1592 | } | |
1593 | } | |
1594 | \f | |
1595 | /* Convert a relaxed displacement to ditto in final output */ | |
1596 | ||
1597 | void | |
1598 | md_convert_frag(fragP) | |
1599 | register fragS *fragP; | |
1600 | { | |
1601 | long disp; | |
1602 | long ext; | |
1603 | ||
1604 | /* Address in gas core of the place to store the displacement. */ | |
1605 | register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal; | |
1606 | /* Address in object code of the displacement. */ | |
1607 | register int object_address = fragP -> fr_fix + fragP -> fr_address; | |
1608 | ||
1609 | know(fragP->fr_symbol); | |
1610 | ||
1611 | /* The displacement of the address, from current location. */ | |
1612 | disp = (S_GET_VALUE(fragP->fr_symbol) + fragP->fr_offset) - object_address; | |
1613 | disp+= fragP->fr_pcrel_adjust; | |
1614 | ||
1615 | switch(fragP->fr_subtype) { | |
1616 | case IND(BRANCH,BYTE): | |
1617 | ext=1; | |
1618 | break; | |
1619 | case IND(BRANCH,WORD): | |
1620 | ext=2; | |
1621 | break; | |
1622 | case IND(BRANCH,DOUBLE): | |
1623 | ext=4; | |
1624 | break; | |
1625 | } | |
1626 | if(ext) { | |
1627 | md_number_to_disp(buffer_address,(long)disp,(int)ext); | |
1628 | fragP->fr_fix+=ext; | |
1629 | } | |
1630 | } | |
1631 | ||
1632 | ||
1633 | ||
1634 | /* This function returns the estimated size a variable object will occupy, | |
1635 | one can say that we tries to guess the size of the objects before we | |
1636 | actually know it */ | |
1637 | ||
1638 | int md_estimate_size_before_relax(fragP, segment) | |
1639 | register fragS *fragP; | |
1640 | segT segment; | |
1641 | { | |
1642 | int old_fix; | |
1643 | old_fix=fragP->fr_fix; | |
1644 | switch(fragP->fr_subtype) { | |
1645 | case IND(BRANCH,UNDEF): | |
1646 | if(S_GET_SEGMENT(fragP->fr_symbol) == segment) { | |
1647 | /* the symbol has been assigned a value */ | |
1648 | fragP->fr_subtype=IND(BRANCH,BYTE); | |
1649 | } else { | |
1650 | /* we don't relax symbols defined in an other segment | |
1651 | the thing to do is to assume the object will occupy 4 bytes */ | |
1652 | fix_new_ns32k(fragP, | |
1653 | (int)(fragP->fr_fix), | |
1654 | 4, | |
1655 | fragP->fr_symbol, | |
1656 | (symbolS *)0, | |
1657 | fragP->fr_offset, | |
1658 | 1, | |
1659 | fragP->fr_pcrel_adjust, | |
1660 | 1, | |
1661 | 0, | |
1662 | fragP->fr_bsr); /*sequent hack */ | |
1663 | fragP->fr_fix+=4; | |
1664 | /* fragP->fr_opcode[1]=0xff; */ | |
1665 | frag_wane(fragP); | |
1666 | break; | |
1667 | } | |
1668 | case IND(BRANCH,BYTE): | |
1669 | fragP->fr_var+=1; | |
1670 | break; | |
1671 | default: | |
1672 | break; | |
1673 | } | |
1674 | return fragP->fr_var + fragP->fr_fix - old_fix; | |
1675 | } | |
1676 | ||
1677 | int md_short_jump_size = 3; | |
1678 | int md_long_jump_size = 5; | |
1679 | int md_reloc_size = 8; /* Size of relocation record */ | |
1680 | ||
1681 | void | |
1682 | md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol) | |
1683 | char *ptr; | |
1684 | long from_addr, | |
1685 | to_addr; | |
1686 | fragS *frag; | |
1687 | symbolS *to_symbol; | |
1688 | { | |
1689 | long offset; | |
1690 | ||
1691 | offset = to_addr - from_addr; | |
1692 | md_number_to_chars(ptr, (long)0xEA ,1); | |
1693 | md_number_to_disp(ptr+1,(long)offset,2); | |
1694 | } | |
1695 | ||
1696 | void | |
1697 | md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol) | |
1698 | char *ptr; | |
1699 | long from_addr, | |
1700 | to_addr; | |
1701 | fragS *frag; | |
1702 | symbolS *to_symbol; | |
1703 | { | |
1704 | long offset; | |
1705 | ||
1706 | offset= to_addr - from_addr; | |
1707 | md_number_to_chars(ptr, (long)0xEA, 2); | |
1708 | md_number_to_disp(ptr+2,(long)offset,4); | |
1709 | } | |
1710 | \f | |
1711 | /* JF this is a new function to parse machine-dep options */ | |
1712 | int | |
1713 | md_parse_option(argP,cntP,vecP) | |
1714 | char **argP; | |
1715 | int *cntP; | |
1716 | char ***vecP; | |
1717 | { | |
1718 | switch(**argP) { | |
1719 | case 'm': | |
1720 | (*argP)++; | |
1721 | ||
1722 | if(!strcmp(*argP,"32032")) { | |
1723 | cpureg = cpureg_032; | |
1724 | mmureg = mmureg_032; | |
1725 | } else if(!strcmp(*argP, "32532")) { | |
1726 | cpureg = cpureg_532; | |
1727 | mmureg = mmureg_532; | |
1728 | } else | |
1729 | as_warn("Unknown -m option ignored"); | |
1730 | ||
1731 | while(**argP) | |
1732 | (*argP)++; | |
1733 | break; | |
1734 | ||
1735 | default: | |
1736 | return 0; | |
1737 | } | |
1738 | return 1; | |
1739 | } | |
1740 | \f | |
1741 | /* | |
1742 | * bit_fix_new() | |
1743 | * | |
1744 | * Create a bit_fixS in obstack 'notes'. | |
1745 | * This struct is used to profile the normal fix. If the bit_fixP is a | |
1746 | * valid pointer (not NULL) the bit_fix data will be used to format the fix. | |
1747 | */ | |
1748 | bit_fixS *bit_fix_new (size,offset,min,max,add,base_type,base_adj) | |
1749 | char size; /* Length of bitfield */ | |
1750 | char offset; /* Bit offset to bitfield */ | |
1751 | long base_type; /* 0 or 1, if 1 it's exploded to opcode ptr */ | |
1752 | long base_adj; | |
1753 | long min; /* Signextended min for bitfield */ | |
1754 | long max; /* Signextended max for bitfield */ | |
1755 | long add; /* Add mask, used for huffman prefix */ | |
1756 | { | |
1757 | register bit_fixS * bit_fixP; | |
1758 | ||
1759 | bit_fixP = (bit_fixS *)obstack_alloc(¬es,sizeof(bit_fixS)); | |
1760 | ||
1761 | bit_fixP -> fx_bit_size = size; | |
1762 | bit_fixP -> fx_bit_offset = offset; | |
1763 | bit_fixP -> fx_bit_base = base_type; | |
1764 | bit_fixP -> fx_bit_base_adj = base_adj; | |
1765 | bit_fixP -> fx_bit_max = max; | |
1766 | bit_fixP -> fx_bit_min = min; | |
1767 | bit_fixP -> fx_bit_add = add; | |
1768 | ||
1769 | return bit_fixP; | |
1770 | } | |
1771 | ||
1772 | void | |
1773 | fix_new_ns32k (frag, where, size, add_symbol, sub_symbol, offset, pcrel, | |
1774 | pcrel_adjust, im_disp, bit_fixP, bsr) | |
1775 | fragS * frag; /* Which frag? */ | |
1776 | int where; /* Where in that frag? */ | |
1777 | short int size; /* 1, 2 or 4 usually. */ | |
1778 | symbolS * add_symbol; /* X_add_symbol. */ | |
1779 | symbolS * sub_symbol; /* X_subtract_symbol. */ | |
1780 | long offset; /* X_add_number. */ | |
1781 | int pcrel; /* TRUE if PC-relative relocation. */ | |
1782 | char pcrel_adjust; /* not zero if adjustment of pcrel offset is needed */ | |
1783 | char im_disp; /* true if the value to write is a displacement */ | |
1784 | bit_fixS *bit_fixP; /* pointer at struct of bit_fix's, ignored if NULL */ | |
1785 | char bsr; /* sequent-linker-hack: 1 when relocobject is a bsr */ | |
1786 | ||
1787 | { | |
1788 | register fixS * fixP; | |
1789 | ||
1790 | fixP = (fixS *)obstack_alloc(¬es,sizeof(fixS)); | |
1791 | fixP -> fx_frag = frag; | |
1792 | fixP -> fx_where = where; | |
1793 | fixP -> fx_size = size; | |
1794 | fixP -> fx_addsy = add_symbol; | |
1795 | fixP -> fx_subsy = sub_symbol; | |
1796 | fixP -> fx_offset = offset; | |
1797 | fixP -> fx_pcrel = pcrel; | |
1798 | fixP -> fx_pcrel_adjust = pcrel_adjust; | |
1799 | fixP -> fx_im_disp = im_disp; | |
1800 | fixP -> fx_bit_fixP = bit_fixP; | |
1801 | fixP -> fx_bsr = bsr; | |
1802 | fixP -> fx_next = * seg_fix_rootP; | |
1803 | ||
1804 | * seg_fix_rootP = fixP; | |
1805 | } | |
1806 | ||
1807 | /* We have no need to default values of symbols. */ | |
1808 | ||
1809 | symbolS * | |
1810 | md_undefined_symbol (name) | |
1811 | char *name; | |
1812 | { | |
1813 | return 0; | |
1814 | } | |
1815 | ||
1816 | /* Parse an operand that is machine-specific. | |
1817 | We just return without modifying the expression if we have nothing | |
1818 | to do. */ | |
1819 | ||
1820 | /* ARGSUSED */ | |
1821 | void | |
1822 | md_operand (expressionP) | |
1823 | expressionS *expressionP; | |
1824 | { | |
1825 | } | |
1826 | ||
1827 | /* Round up a section size to the appropriate boundary. */ | |
1828 | long | |
1829 | md_section_align (segment, size) | |
1830 | segT segment; | |
1831 | long size; | |
1832 | { | |
1833 | return size; /* Byte alignment is fine */ | |
1834 | } | |
1835 | ||
1836 | /* Exactly what point is a PC-relative offset relative TO? | |
1837 | On the National warts, they're relative to the address of the offset, | |
1838 | with some funny adjustments in some circumstances during blue moons. | |
1839 | (??? Is this right? FIXME-SOON) */ | |
1840 | long | |
1841 | md_pcrel_from (fixP) | |
1842 | fixS *fixP; | |
1843 | { | |
1844 | long res; | |
1845 | res = fixP->fx_where + fixP->fx_frag->fr_address; | |
1846 | #ifdef SEQUENT_COMPATABILITY | |
1847 | if (fixP->fx_frag->fr_bsr) | |
1848 | res += 0x12 /* FOO Kludge alert! */ | |
1849 | #endif | |
1850 | return res; | |
1851 | } | |
1852 | ||
1853 | /* | |
1854 | * $Log$ | |
1855 | * Revision 1.1 1991/04/04 18:17:05 rich | |
1856 | * Initial revision | |
1857 | * | |
1858 | * | |
1859 | */ | |
1860 | ||
1861 | /* | |
1862 | * Local Variables: | |
1863 | * comment-column: 0 | |
1864 | * End: | |
1865 | */ | |
1866 | ||
1867 | /* end of tc-ns32k.c */ |