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