Version bump for last commit + ws cleanups. Now at v2.0.18.
[rmac] / eagen0.c
1 //
2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // EAGEN0.C - Effective Address Code Generation
4 //            Generated Code for eaN (Included twice by "eagen.c")
5 // Copyright (C) 199x Landon Dyer, 2011-2020 Reboot and Friends
6 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
7 // Source utilised with the kind permission of Landon Dyer
8 //
9
10 int eaNgen(WORD siz)
11 {
12         uint32_t v = (uint32_t)aNexval;
13         WORD w = (WORD)(aNexattr & DEFINED);
14         WORD tdb = (WORD)(aNexattr & TDB);
15         uint32_t vbd = (uint32_t)aNbdexval;
16         WORD wbd = (WORD)(aNbdexattr & DEFINED);
17         WORD tdbbd = (WORD)(aNbdexattr & TDB);
18         uint8_t extDbl[12];
19
20         switch (amN)
21         {
22         // "Do nothing" - they're in the opword
23         case DREG:
24         case AREG:
25         case AIND:
26         case APOSTINC:
27         case APREDEC:
28         case AM_USP:
29         case AM_CCR:
30         case AM_SR:
31         case AM_NONE:
32                 // This is a performance hit, though
33                 break;
34
35         case ADISP:
36                 // expr(An)
37                 if (w)
38                 {
39                         // Just deposit it
40                         if (tdb)
41                                 MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
42
43                         if ((v == 0) && CHECK_OPTS(OPT_OUTER_DISP) && !movep)
44                         {
45                                 // If expr is 0, size optimise the opcode. Generally the lower
46                                 // 6 bits of the opcode for expr(ax) are 101rrr where rrr=the
47                                 // number of the register, then followed by a word containing
48                                 // 'expr'. We need to change that to 010rrr.
49                                 if ((siz & 0x8000) == 0)
50                                 {
51                                         chptr_opcode[0] &= ((0xFFC7 >> 8) & 255); // mask off bits
52                                         chptr_opcode[1] &= 0xFFC7 & 255;          // mask off bits
53                                         chptr_opcode[0] |= ((0x0010 >> 8) & 255); // slap in 010 bits
54                                         chptr_opcode[1] |= 0x0010 & 255;          // slap in 010 bits
55                                 }
56                                 else
57                                 {
58                                         // Special case for move ea,ea: there are two ea fields
59                                         // there and we get a signal if it's the second ea field
60                                         // from m_ea - siz's 16th bit is set
61                                         chptr_opcode[0] &= ((0xFE3F >> 8) & 255); // mask off bits
62                                         chptr_opcode[1] &= 0xFE3F & 255;          // mask off bits
63                                         chptr_opcode[0] |= ((0x0080 >> 8) & 255); // slap in 010 bits
64                                         chptr_opcode[1] |= 0x0080 & 255;          // slap in 010 bits
65                                 }
66
67                                 if (optim_warn_flag)
68                                         warn("0(An) converted to (An)");
69
70                                 return OK;
71                         }
72
73                         if ((v + 0x8000) >= 0x18000)
74                                 return error(range_error);
75
76                         D_word(v);
77                 }
78                 else
79                 {
80                         // Arrange for fixup later on
81                         AddFixup(FU_WORD | FU_SEXT, sloc, aNexpr);
82                         D_word(0);
83                 }
84
85                 break;
86
87         case PCDISP:
88                 if (w)
89                 {
90                         // Just deposit it
91                         if ((aNexattr & TDB) == cursect)
92                                 v -= (uint32_t)sloc;
93                         else if ((aNexattr & TDB) != ABS)
94                                 error(rel_error);
95
96                         if (v + 0x8000 >= 0x10000)
97                                 return error(range_error);
98
99                         D_word(v);
100                 }
101                 else
102                 {
103                         // Arrange for fixup later on
104                         AddFixup(FU_WORD | FU_SEXT | FU_PCREL, sloc, aNexpr);
105                         D_word(0);
106                 }
107
108                 break;
109
110         case AINDEXED:
111                 // Compute ixreg and size+scale
112                 w = (WORD)((aNixreg << 12) | aNixsiz);
113
114                 if (aNexattr & DEFINED)
115                 {
116                         // Deposit a byte...
117                         if (tdb)
118                                 // Can't mark bytes
119                                 return error(abs_error);
120
121                         if (v + 0x80 >= 0x180)
122                                 return error(range_error);
123
124                         w |= v & 0xFF;
125                         D_word(w);
126                 }
127                 else
128                 {
129                         // Fixup the byte later
130                         AddFixup(FU_BYTE | FU_SEXT, sloc + 1, aNexpr);
131                         D_word(w);
132                 }
133
134                 break;
135
136         case PCINDEXED:
137                 // Compute ixreg and size+scale
138                 w = (WORD)((aNixreg << 12) | aNixsiz);
139
140                 if (aNexattr & DEFINED)
141                 {
142                         // Deposit a byte...
143                         if ((aNexattr & TDB) == cursect)
144                                 v -= (uint32_t)sloc;
145                         else if ((aNexattr & TDB) != ABS)
146                                 error(rel_error);
147
148                         if (v + 0x80 >= 0x100)
149                                 return error(range_error);
150
151                         w |= v & 0xFF;
152                         D_word(w);
153                 }
154                 else
155                 {
156                         // Fixup the byte later
157                         AddFixup(FU_WBYTE | FU_SEXT | FU_PCREL, sloc, aNexpr);
158                         D_word(w);
159                 }
160
161                 break;
162
163         case IMMED:
164                 switch (siz)
165                 {
166                 case SIZB:
167                         if (w)
168                         {
169                                 if (tdb)
170                                         return error("illegal byte-sized relative reference");
171
172                                 if (v + 0x100 >= 0x200)
173                                         return error(range_error);
174
175                                 D_word(v & 0xFF);
176                         }
177                         else
178                         {
179                                 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, aNexpr);
180                                 D_word(0);
181                         }
182
183                         break;
184
185                 case SIZW:
186                 case SIZN:
187                         if (w)
188                         {
189                                 if (v + 0x10000 >= 0x20000)
190                                         return error(range_error);
191
192                                 if (tdb)
193                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
194
195                                 D_word(v);
196                         }
197                         else
198                         {
199                                 AddFixup(FU_WORD | FU_SEXT, sloc, aNexpr);
200                                 D_word(0);
201                         }
202
203                         break;
204
205                 case SIZL:
206                         if (w)
207                         {
208                                 if (tdb)
209                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
210
211                                 D_long(v);
212                         }
213                         else
214                         {
215                                 AddFixup(FU_LONG, sloc, aNexpr);
216                                 D_long(0);
217                         }
218
219                         break;
220
221                 case SIZS:
222                         // 68881/68882/68040 only
223                         if (w)
224                         {
225 //Would a floating point value *ever* need to be fixed up as if it were an address? :-P
226 //                              if (tdb)
227 //                                      MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
228
229                                 // The value passed back from expr() is an internal C double;
230                                 // so we have to access it as such then convert it to an
231                                 // IEEE-754 float so we can store it as such in the instruction
232                                 // stream here.
233                                 PTR p;
234                                 p.u64 = &aNexval;
235                                 float f = (float)*p.dp;
236                                 uint32_t ieee754 = FloatToIEEE754(f);
237                                 D_long(ieee754);
238                         }
239                         else
240                         {
241                                 AddFixup(FU_FLOATSING, sloc, aNexpr);
242                                 D_long(0);      // IEEE-754 zero is all zeroes
243                         }
244
245                 break;
246
247                 case SIZD:
248                         // 68881/68882/68040 only
249                         if (w)
250                         {
251 //Would a floating point value *ever* need to be fixed up as if it were an address? :-P
252 //                              if (tdb)
253 //                                      MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
254
255                                 PTR p;
256                                 p.u64 = &aNexval;
257                                 double d = *p.dp;
258                                 uint64_t ieee754 = DoubleToIEEE754(d);
259                                 D_quad(ieee754);
260                         }
261                         else
262                         {
263                                 AddFixup(FU_FLOATDOUB, sloc, aNexpr);
264                                 D_quad(0LL);    // IEEE-754 zero is all zeroes
265                         }
266
267                         break;
268
269                 case SIZX:
270                         // 68881/68882/68040 only
271                         if (w)
272                         {
273 //Would a floating point value *ever* need to be fixed up as if it were an address? :-P
274 //                              if (tdb)
275 //                                      MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
276
277                                 PTR p;
278                                 p.u64 = &aNexval;
279                                 DoubleToExtended(*p.dp, extDbl);
280                                 D_extend(extDbl);
281                         }
282                         else
283                         {
284                                 // Why would this be anything other than a floating point
285                                 // expression???  Even if there were an undefined symbol in
286                                 // the expression, how would that be relevant?  I can't see
287                                 // any use case where this would make sense.
288                                 AddFixup(FU_FLOATDOUB, sloc, aNexpr);
289                                 memset(extDbl, 0, 12);
290                                 D_extend(extDbl);
291                         }
292
293                         break;
294
295                 default:
296                         // IMMED size problem
297                         interror(1);
298                 }
299
300                 break;
301
302     case SIZP:
303                 // 68881/68882/68040 only
304                 return error("Sorry, .p constant format is not implemented yet!");
305                 break;
306
307         case ABSW:
308                 if (w) // Defined
309                 {
310                         if (tdb)
311                                 MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
312
313                         if (v + 0x8000 >= 0x10000)
314                                 return error(range_error);
315
316                         D_word(v);
317                 }
318                 else
319                 {
320                         AddFixup(FU_WORD | FU_SEXT, sloc, aNexpr);
321                         D_word(0);
322                 }
323
324                 break;
325
326         case ABSL:
327                 if (w) // Defined
328                 {
329                         if (CHECK_OPTS(OPT_PC_RELATIVE))
330                         {
331                                 if (aNexattr & (DEFINED | REFERENCED | EQUATED) == DEFINED | REFERENCED)
332                                         return error("relocation not allowed");
333                         }
334
335                         if (tdb)
336                                 MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
337
338                         D_long(v);
339                 }
340                 else
341                 {
342                         AddFixup(FU_LONG, sloc, aNexpr);
343                         D_long(0);
344                 }
345
346                 break;
347
348         case DINDW:
349                 D_word((0x190 | (aNixreg << 12)));
350                 break;
351
352         case DINDL:
353                 D_word((0x990 | (aNixreg << 12)));
354                 break;
355
356         case ABASE:
357         case MEMPOST:
358         case MEMPRE:
359         case PCBASE:
360         case PCMPOST:
361         case PCMPRE:
362                 D_word(aNexten);
363
364                 // Deposit bd (if not suppressed)
365                 if ((aNexten & 0x0030) == EXT_BDSIZE0)
366                 {
367                         // Don't deposit anything (suppressed)
368                 }
369                 else if ((aNexten & 0x0030) == EXT_BDSIZEW)
370                 {
371                         // Deposit word bd
372                         if (wbd)
373                         {
374                                 // Just deposit it
375                                 if (tdb)
376                                         MarkRelocatable(cursect, sloc, tdbbd, MWORD, NULL);
377
378                                 if (vbd + 0x8000 >= 0x10000)
379                                         return error(range_error);
380
381                                 D_word(vbd);
382                         }
383                         else
384                         {
385                                 // Arrange for fixup later on
386                                 AddFixup(FU_WORD | FU_SEXT | FU_PCRELX, sloc, aNbexpr);
387                                 D_word(0);
388                         }
389                 }
390                 else
391                 {
392                         // Deposit long bd
393                         if (wbd)
394                         {
395                                 // Just deposit it
396                                 if (tdbbd)
397                                         MarkRelocatable(cursect, sloc, tdbbd, MLONG, NULL);
398
399                                 D_long(vbd);
400                         }
401                         else
402                         {
403                                 // Arrange for fixup later on
404                                 AddFixup(FU_LONG, sloc, aNbexpr);
405                                 D_long(0);
406                         }
407                 }
408
409                 // Deposit od (if not suppressed)
410                 if ((aNexten & 7) == EXT_IISPRE0 || (aNexten & 7) == EXT_IISPREN
411                         || (aNexten & 7) == EXT_IISNOIN || (aNexten & 7) == EXT_IISPOSN)
412                 {
413                         // Don't deposit anything (suppressed)
414                 }
415                 else if ((aNexten & 7) == EXT_IISPREW
416                         || (aNexten & 7) == EXT_IISPOSW || (aNexten & 7) == EXT_IISNOIW)
417                 {
418                         // Deposit word od
419                         if (w)
420                         {
421                                 // Just deposit it
422                                 if (tdb)
423                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
424
425                                 if (v + 0x8000 >= 0x10000)
426                                         return error(range_error);
427
428                                 D_word(v);
429                         }
430                         else
431                         {
432                                 // Arrange for fixup later on
433                                 AddFixup(FU_WORD | FU_SEXT, sloc, aNexpr);
434                                 D_word(0);
435                         }
436                 }
437                 else
438                 {
439                         // Deposit long od
440                         if (w)
441                         {
442                                 // Just deposit it
443                                 if (tdb)
444                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
445
446                                 D_long(v);
447                         }
448                         else
449                         {
450                                 // Arrange for fixup later on
451                                 AddFixup(FU_LONG | FU_SEXT, sloc, aNexpr);
452                                 D_long(0);
453                         }
454                 }
455
456                 break;
457                 //return error("unsupported 68020 addressing mode");
458
459         default:
460                 // Bad addressing mode in ea gen
461                 interror(3);
462         }
463
464         return OK;
465 }
466
467 // Undefine dirty macros
468 #undef eaNgen
469 #undef amN
470 #undef aNexattr
471 #undef aNexval
472 #undef aNexpr
473 #undef aNixreg
474 #undef aNixsiz
475 #undef aNexten
476 #undef aNbexpr
477 #undef aNbdexval
478 #undef aNbdexattr
479 #undef AnESYM
480