Fix for bug #102. Thanks (blame!) go to ggn & dml for the idea. :-)
[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-2017 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         VALUE vbd, v = aNexval;
13         WORD wbd, w = (WORD)(aNexattr & DEFINED);
14         WORD tdbbd, tdb = (WORD)(aNexattr & TDB);
15         vbd = aNbdexval;
16         wbd = (WORD)(aNbdexattr & DEFINED);
17         tdbbd = (WORD)(aNbdexattr & TDB);
18
19         switch (amN)
20         {
21         // "Do nothing" - they're in the opword
22         case DREG:
23         case AREG:
24         case AIND:
25         case APOSTINC:
26         case APREDEC:
27         case AM_USP:
28         case AM_CCR:
29         case AM_SR:
30         case AM_NONE:
31                 // This is a performance hit, though
32                 break;
33         case ADISP:
34                 // expr(An)
35                 if (w)
36                 {
37                         // Just deposit it
38                         if (tdb)
39                                 MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
40
41                         if ((v == 0) && CHECK_OPTS(OPT_INDIRECT_DISP) && !movep)
42                         {
43                                 // If expr is 0, size optimise the opcode. Generally the lower
44                                 // 6 bits of the opcode for expr(ax) are 101rrr where rrr=the
45                                 // number of the register, then followed by a word containing
46                                 // 'expr'. We need to change that to 010rrr.
47                                 if ((siz & 0x8000) == 0)
48                                 {
49                                         chptr_opcode[0] &= ((0xFFC7 >> 8) & 255); // mask off bits
50                                         chptr_opcode[1] &= 0xFFC7 & 255;          // mask off bits
51                                         chptr_opcode[0] |= ((0x0010 >> 8) & 255); // slap in 010 bits
52                                         chptr_opcode[1] |= 0x0010 & 255;          // slap in 010 bits
53                                 }
54                                 else
55                                 {
56                                         // Special case for move ea,ea: there are two ea fields
57                                         // there and we get a signal if it's the second ea field
58                                         // from m_ea - siz's 16th bit is set
59                                         chptr_opcode[0] &= ((0xFE3F >> 8) & 255); // mask off bits
60                                         chptr_opcode[1] &= 0xFE3F & 255;          // mask off bits
61                                         chptr_opcode[0] |= ((0x0080 >> 8) & 255); // slap in 010 bits
62                                         chptr_opcode[1] |= 0x0080 & 255;          // slap in 010 bits
63                                 }
64
65                                 if (sbra_flag)
66                                         warn("0(An) converted to (An)");
67
68                                 return OK;
69                         }
70
71                         if ((v + 0x8000) >= 0x18000)
72                                 return error(range_error);
73
74                         D_word(v);
75                 }
76                 else
77                 {
78                         // Arrange for fixup later on
79                         AddFixup(FU_WORD | FU_SEXT, sloc, aNexpr);
80                         D_word(0);
81                 }
82
83                 break;
84         case PCDISP:
85                 if (w)
86                 {
87                         // Just deposit it
88                         if ((aNexattr & TDB) == cursect)
89                                 v -= (VALUE)sloc;
90                         else if ((aNexattr & TDB) != ABS)
91                                 error(rel_error);
92
93                         if (v + 0x8000 >= 0x10000)
94                                 return error(range_error);
95
96                         D_word(v);
97                 }
98                 else
99                 {
100                         // Arrange for fixup later on
101                         AddFixup(FU_WORD | FU_SEXT | FU_PCREL, sloc, aNexpr);
102                         D_word(0);
103                 }
104
105                 break;
106         case AINDEXED:
107                 // Compute ixreg and size+scale
108                 w = (WORD)((aNixreg << 12) | aNixsiz);
109
110                 if (aNexattr & DEFINED)
111                 {
112                         // Deposit a byte...
113                         if (tdb)
114                                 // Can't mark bytes
115                                 return error(abs_error);
116
117                         if (v + 0x80 >= 0x180)
118                                 return error(range_error);
119
120                         w |= v & 0xFF;
121                         D_word(w);
122                 }
123                 else
124                 {
125                         // Fixup the byte later
126                         AddFixup(FU_BYTE | FU_SEXT, sloc + 1, aNexpr);
127                         D_word(w);
128                 }
129
130                 break;
131         case PCINDEXED:
132                 // Compute ixreg and size+scale
133                 w = (WORD)((aNixreg << 12) | aNixsiz);
134
135                 if (aNexattr & DEFINED)
136                 {
137                         // Deposit a byte...
138                         if ((aNexattr & TDB) == cursect)
139                                 v -= (VALUE)sloc;
140                         else if ((aNexattr & TDB) != ABS)
141                                 error(rel_error);
142
143                         if (v + 0x80 >= 0x100)
144                                 return error(range_error);
145
146                         w |= v & 0xFF;
147                         D_word(w);
148                 }
149                 else
150                 {
151                         // Fixup the byte later
152                         AddFixup(FU_WBYTE | FU_SEXT | FU_PCREL, sloc, aNexpr);
153                         D_word(w);
154                 }
155
156                 break;
157         case IMMED:
158                 switch (siz)
159                 {
160                 case SIZB:
161                         if (w)
162                         {
163                                 if (tdb)
164                                         return error("illegal byte-sized relative reference");
165
166                                 if (v + 0x100 >= 0x200)
167                                         return error(range_error);
168
169                                 D_word(v);
170                         }
171                         else
172                         {
173                                 AddFixup(FU_BYTE | FU_SEXT, sloc + 1, aNexpr);
174                                 D_word(0);
175                         }
176
177                         break;
178                 case SIZW:
179                 case SIZN:
180                         if (w)
181                         {
182                                 if (v + 0x10000 >= 0x20000)
183                                         return error(range_error);
184
185                                 if (tdb)
186                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
187
188                                 D_word(v);
189                         }
190                         else
191                         {
192                                 AddFixup(FU_WORD | FU_SEXT, sloc, aNexpr);
193                                 D_word(0);
194                         }
195
196                         break;
197                 case SIZL:
198                         if (w)
199                         {
200                                 if (tdb)
201                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
202
203                                 D_long(v);
204                         }
205                         else
206                         {
207                                 AddFixup(FU_LONG, sloc, aNexpr);
208                                 D_long(0);
209                         }
210
211                         break;
212                 default:
213                         // IMMED size problem
214                         interror(1);
215                 }
216
217                 break;
218     case SIZP:
219                 // 68881/68882/68040 only
220                 return error("Sorry, .p constant format is not implemented yet!");
221                 break;
222         case ABSW:
223                 if (w) // Defined
224                 {
225                         if (tdb)
226                                 MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
227
228                         if (v + 0x8000 >= 0x10000)
229                                 return error(range_error);
230
231                         D_word(v);
232                 }
233                 else
234                 {
235                         AddFixup(FU_WORD | FU_SEXT, sloc, aNexpr);
236                         D_word(0);
237                 }
238
239                 break;
240         case ABSL:
241                 if (w) // Defined
242                 {
243                         if (tdb)
244                                 MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
245
246                         D_long(v);
247                 }
248                 else
249                 {
250                         AddFixup(FU_LONG, sloc, aNexpr);
251                         D_long(0);
252                 }
253
254                 break;
255         case DINDW:
256                 D_word(0x190|(aNixreg<<12));
257                 break;
258         case DINDL:
259                 D_word(0x990|(aNixreg<<12));
260                 break;
261         case ABASE:
262         case MEMPOST:
263         case MEMPRE:
264         case PCBASE:
265         case PCMPOST:
266         case PCMPRE:
267                 D_word(aNexten);
268                 // Deposit bd (if not suppressed)
269                 if ((aNexten&0x0030)==EXT_BDSIZE0)
270                 {
271                         // Don't deposit anything (suppressed)
272                 }
273                 else if ((aNexten&0x0030)==EXT_BDSIZEW)
274                 {
275                         // Deposit word bd
276                         if (wbd)
277                         {
278                                 // Just deposit it
279                                 if (tdb)
280                                         MarkRelocatable(cursect, sloc, tdbbd, MWORD, NULL);
281
282                                 if (vbd + 0x8000 >= 0x10000)
283                                         return error(range_error);
284
285                                 D_word(vbd);
286                         }
287                         else
288                         {
289                                 // Arrange for fixup later on
290                                 AddFixup(FU_WORD|FU_SEXT, sloc, aNbexpr);
291                                 D_word(0);
292                         }
293                 }
294                 else
295                 {
296                         // Deposit long bd
297                         if (wbd)
298                         {
299                                 // Just deposit it
300                                 if (tdbbd)
301                                         MarkRelocatable(cursect, sloc, tdbbd, MLONG, NULL);
302
303                                 D_long(vbd);
304                         }
305                         else
306                         {
307                                 // Arrange for fixup later on
308                                 AddFixup(FU_LONG, sloc, aNbexpr);
309                                 D_long(0);
310                         }
311                 }
312                 // Deposit od (if not suppressed)
313                 if ((aNexten&7)==EXT_IISPRE0 || (aNexten&7)==EXT_IISPREN
314                         || (aNexten&7)==EXT_IISNOIN || (aNexten&7)==EXT_IISPOSN)
315                 {
316                         // Don't deposit anything (suppressed)
317                 }
318                 else if ((aNexten&7)==EXT_IISPREW
319                         || (aNexten&7)==EXT_IISPOSW || (aNexten&7)==EXT_IISNOIW)
320                 {
321                         // Deposit word od
322                         if (w)
323                         {
324                                 // Just deposit it
325                                 if (tdb)
326                                         MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
327
328                                 if (v + 0x8000 >= 0x10000)
329                                         return error(range_error);
330
331                                 D_word(v);
332                         }
333                         else
334                         {
335                                 // Arrange for fixup later on
336                                 AddFixup(FU_WORD|FU_SEXT, sloc, aNexpr);
337                                 D_word(0);
338                         }
339                 }
340                 else
341                 {
342                         // Deposit long od
343                         if (w)
344                         {
345                                 // Just deposit it
346                                 if (tdb)
347                                         MarkRelocatable(cursect, sloc, tdb, MLONG, NULL);
348
349                                 D_long(v);
350                         }
351                         else
352                         {
353                                 // Arrange for fixup later on
354                                 AddFixup(FU_LONG|FU_SEXT, sloc, aNexpr);
355                                 D_long(0);
356                         }
357                 }
358
359                 break;
360                 //return error("unsupported 68020 addressing mode");
361         default:
362                 // Bad addressing mode in ea gen
363                 interror(3);
364         }
365
366         return OK;
367 }
368
369 // Undefine dirty macros
370 #undef eaNgen
371 #undef amN
372 #undef aNexattr
373 #undef aNexval
374 #undef aNexpr
375 #undef aNixreg
376 #undef aNixsiz
377 #undef aNexten
378 #undef aNbexpr
379 #undef aNbdexval
380 #undef aNbdexattr
381 #undef AnESYM
382