Version bump for last commit; now at v2.0.23.
[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_INDIRECT_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 (sbra_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 (optim_pc)
330                                 if (aNexattr&(DEFINED | REFERENCED | EQUATED) == DEFINED | REFERENCED)
331                                         return error("relocation not allowed");
332
333                         if (tdb)
334                                 MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
335
336                         D_long(v);
337                 }
338                 else
339                 {
340                         AddFixup(FU_LONG, sloc, aNexpr);
341                         D_long(0);
342                 }
343
344                 break;
345
346         case DINDW:
347                 D_word((0x190 | (aNixreg << 12)));
348                 break;
349
350         case DINDL:
351                 D_word((0x990 | (aNixreg << 12)));
352                 break;
353
354         case ABASE:
355         case MEMPOST:
356         case MEMPRE:
357         case PCBASE:
358         case PCMPOST:
359         case PCMPRE:
360                 D_word(aNexten);
361
362                 // Deposit bd (if not suppressed)
363                 if ((aNexten & 0x0030) == EXT_BDSIZE0)
364                 {
365                         // Don't deposit anything (suppressed)
366                 }
367                 else if ((aNexten & 0x0030) == EXT_BDSIZEW)
368                 {
369                         // Deposit word bd
370                         if (wbd)
371                         {
372                                 // Just deposit it
373                                 if (tdb)
374                                         MarkRelocatable(cursect, sloc, tdbbd, MWORD, NULL);
375
376                                 if (vbd + 0x8000 >= 0x10000)
377                                         return error(range_error);
378
379                                 D_word(vbd);
380                         }
381                         else
382                         {
383                                 // Arrange for fixup later on
384                                 AddFixup(FU_WORD | FU_SEXT | FU_PCRELX, sloc, aNbexpr);
385                                 D_word(0);
386                         }
387                 }
388                 else
389                 {
390                         // Deposit long bd
391                         if (wbd)
392                         {
393                                 // Just deposit it
394                                 if (tdbbd)
395                                         MarkRelocatable(cursect, sloc, tdbbd, MLONG, NULL);
396
397                                 D_long(vbd);
398                         }
399                         else
400                         {
401                                 // Arrange for fixup later on
402                                 AddFixup(FU_LONG, sloc, aNbexpr);
403                                 D_long(0);
404                         }
405                 }
406
407                 // Deposit od (if not suppressed)
408                 if ((aNexten & 7) == EXT_IISPRE0 || (aNexten & 7) == EXT_IISPREN
409                         || (aNexten & 7) == EXT_IISNOIN || (aNexten & 7) == EXT_IISPOSN)
410                 {
411                         // Don't deposit anything (suppressed)
412                 }
413                 else if ((aNexten & 7) == EXT_IISPREW
414                         || (aNexten & 7) == EXT_IISPOSW || (aNexten & 7) == EXT_IISNOIW)
415                 {
416                         // Deposit word od
417                         if (w)
418                         {
419                                 // Just deposit it
420                                 if (tdb)
421                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
422
423                                 if (v + 0x8000 >= 0x10000)
424                                         return error(range_error);
425
426                                 D_word(v);
427                         }
428                         else
429                         {
430                                 // Arrange for fixup later on
431                                 AddFixup(FU_WORD | FU_SEXT, sloc, aNexpr);
432                                 D_word(0);
433                         }
434                 }
435                 else
436                 {
437                         // Deposit long od
438                         if (w)
439                         {
440                                 // Just deposit it
441                                 if (tdb)
442                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
443
444                                 D_long(v);
445                         }
446                         else
447                         {
448                                 // Arrange for fixup later on
449                                 AddFixup(FU_LONG | FU_SEXT, sloc, aNexpr);
450                                 D_long(0);
451                         }
452                 }
453
454                 break;
455                 //return error("unsupported 68020 addressing mode");
456
457         default:
458                 // Bad addressing mode in ea gen
459                 interror(3);
460         }
461
462         return OK;
463 }
464
465 // Undefine dirty macros
466 #undef eaNgen
467 #undef amN
468 #undef aNexattr
469 #undef aNexval
470 #undef aNexpr
471 #undef aNixreg
472 #undef aNixsiz
473 #undef aNexten
474 #undef aNbexpr
475 #undef aNbdexval
476 #undef aNbdexattr
477 #undef AnESYM
478