]> Shamusworld >> Repos - rmac/blob - eagen0.c
Fix for subtle bug in the expression analyzer.
[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                                 if (tdb)
218                                         MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
219
220                                 // The value passed back from expr() is an internal C double;
221                                 // so we have to access it as such then convert it to an
222                                 // IEEE-754 float so we can store it as such in the instruction
223                                 // stream here.
224                                 PTR p;
225                                 p.u64 = &aNexval;
226                                 float f = (float)*p.dp;
227                                 uint32_t ieee754 = FloatToIEEE754(f);
228                                 D_long(ieee754);
229                         }
230                         else
231                         {
232                                 AddFixup(FU_FLOATSING, sloc, aNexpr);
233                                 D_long(0);      // IEEE-754 zero is all zeroes
234                         }
235
236                 break;
237                 case SIZD:
238                         // 68881/68882/68040 only
239                         if (w)
240                         {
241                                 if (tdb)
242                                         MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
243
244                                 PTR p;
245                                 p.u64 = &aNexval;
246                                 double d = *p.dp;
247                                 uint64_t ieee754 = DoubleToIEEE754(d);
248                                 D_quad(ieee754);
249                         }
250                         else
251                         {
252                                 AddFixup(FU_FLOATDOUB, sloc, aNexpr);
253                                 D_quad(0LL);    // IEEE-754 zero is all zeroes
254                         }
255
256                         break;
257                 case SIZX:
258                         // 68881/68882/68040 only
259                         if (w)
260                         {
261                                 if (tdb)
262                                         MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
263
264                                 PTR p;
265                                 p.u64 = &aNexval;
266                                 DoubleToExtended(*p.dp, extDbl);
267                                 D_extend(extDbl);
268                         }
269                         else
270                         {
271                                 AddFixup(FU_FLOATDOUB, sloc, aNexpr);
272                                 memset(extDbl, 0, 12);
273                                 D_extend(extDbl);
274                         }
275
276                         break;
277                 default:
278                         // IMMED size problem
279                         interror(1);
280                 }
281
282                 break;
283     case SIZP:
284                 // 68881/68882/68040 only
285                 return error("Sorry, .p constant format is not implemented yet!");
286                 break;
287         case ABSW:
288                 if (w) // Defined
289                 {
290                         if (tdb)
291                                 MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
292
293                         if (v + 0x8000 >= 0x10000)
294                                 return error(range_error);
295
296                         D_word(v);
297                 }
298                 else
299                 {
300                         AddFixup(FU_WORD | FU_SEXT, sloc, aNexpr);
301                         D_word(0);
302                 }
303
304                 break;
305         case ABSL:
306                 if (w) // Defined
307                 {
308                         if (tdb)
309                                 MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
310
311                         D_long(v);
312                 }
313                 else
314                 {
315                         AddFixup(FU_LONG, sloc, aNexpr);
316                         D_long(0);
317                 }
318
319                 break;
320         case DINDW:
321                 D_word((0x190 | (aNixreg << 12)));
322                 break;
323         case DINDL:
324                 D_word((0x990 | (aNixreg << 12)));
325                 break;
326         case ABASE:
327         case MEMPOST:
328         case MEMPRE:
329         case PCBASE:
330         case PCMPOST:
331         case PCMPRE:
332                 D_word(aNexten);
333                 // Deposit bd (if not suppressed)
334                 if ((aNexten & 0x0030) == EXT_BDSIZE0)
335                 {
336                         // Don't deposit anything (suppressed)
337                 }
338                 else if ((aNexten & 0x0030) == EXT_BDSIZEW)
339                 {
340                         // Deposit word bd
341                         if (wbd)
342                         {
343                                 // Just deposit it
344                                 if (tdb)
345                                         MarkRelocatable(cursect, sloc, tdbbd, MWORD, NULL);
346
347                                 if (vbd + 0x8000 >= 0x10000)
348                                         return error(range_error);
349
350                                 D_word(vbd);
351                         }
352                         else
353                         {
354                                 // Arrange for fixup later on
355                                 AddFixup(FU_WORD | FU_SEXT, sloc, aNbexpr);
356                                 D_word(0);
357                         }
358                 }
359                 else
360                 {
361                         // Deposit long bd
362                         if (wbd)
363                         {
364                                 // Just deposit it
365                                 if (tdbbd)
366                                         MarkRelocatable(cursect, sloc, tdbbd, MLONG, NULL);
367
368                                 D_long(vbd);
369                         }
370                         else
371                         {
372                                 // Arrange for fixup later on
373                                 AddFixup(FU_LONG, sloc, aNbexpr);
374                                 D_long(0);
375                         }
376                 }
377                 // Deposit od (if not suppressed)
378                 if ((aNexten & 7) == EXT_IISPRE0 || (aNexten & 7) == EXT_IISPREN
379                         || (aNexten & 7) == EXT_IISNOIN || (aNexten & 7) == EXT_IISPOSN)
380                 {
381                         // Don't deposit anything (suppressed)
382                 }
383                 else if ((aNexten & 7) == EXT_IISPREW
384                         || (aNexten & 7) == EXT_IISPOSW || (aNexten & 7) == EXT_IISNOIW)
385                 {
386                         // Deposit word od
387                         if (w)
388                         {
389                                 // Just deposit it
390                                 if (tdb)
391                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
392
393                                 if (v + 0x8000 >= 0x10000)
394                                         return error(range_error);
395
396                                 D_word(v);
397                         }
398                         else
399                         {
400                                 // Arrange for fixup later on
401                                 AddFixup(FU_WORD | FU_SEXT, sloc, aNexpr);
402                                 D_word(0);
403                         }
404                 }
405                 else
406                 {
407                         // Deposit long od
408                         if (w)
409                         {
410                                 // Just deposit it
411                                 if (tdb)
412                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
413
414                                 D_long(v);
415                         }
416                         else
417                         {
418                                 // Arrange for fixup later on
419                                 AddFixup(FU_LONG | FU_SEXT, sloc, aNexpr);
420                                 D_long(0);
421                         }
422                 }
423
424                 break;
425                 //return error("unsupported 68020 addressing mode");
426         default:
427                 // Bad addressing mode in ea gen
428                 interror(3);
429         }
430
431         return OK;
432 }
433
434 // Undefine dirty macros
435 #undef eaNgen
436 #undef amN
437 #undef aNexattr
438 #undef aNexval
439 #undef aNexpr
440 #undef aNixreg
441 #undef aNixsiz
442 #undef aNexten
443 #undef aNbexpr
444 #undef aNbdexval
445 #undef aNbdexattr
446 #undef AnESYM
447