]> Shamusworld >> Repos - rmac/blob - op.c
Minor fix to kill unnecessary field YPOS in gpuobj in the OP assembler.
[rmac] / op.c
1 //
2 // Jaguar Object Processor assembler
3 //
4 // by James Hammons
5 // (C) 2019 Underground Software
6 //
7
8 #include "op.h"
9 #include "direct.h"
10 #include "error.h"
11 #include "expr.h"
12 #include "fltpoint.h"
13 #include "mark.h"
14 #include "procln.h"
15 #include "riscasm.h"
16 #include "rmac.h"
17 #include "sect.h"
18 #include "token.h"
19
20 #define DEF_MO
21 #include "opkw.h"               // For MO_* macros
22
23 // Function prototypes
24 static int HandleBitmap(void);
25 static int HandleScaledBitmap(void);
26 static int HandleGPUObject(void);
27 static int HandleBranch(void);
28 static int HandleStop(void);
29 static int HandleNOP(void);
30 static int HandleJump(void);
31
32 // OP assembler vars.
33 static uint8_t lastObjType;
34 static uint32_t lastSloc;
35 static char scratchbuf[4096];
36 static TOKEN fixupExpr[4] = { CONST, 0, 0, ENDEXPR };
37 //static PTR fixupPtr = { .tk = (fixupExpr + 1) };              // C99 \o/
38 static PTR fixupPtr = { (uint8_t *)(fixupExpr + 1) };   // meh, it works
39
40 //
41 // The main Object Processor assembler. Basically just calls the sub functions
42 // to generate the appropriate code.
43 //
44 int GenerateOPCode(int state)
45 {
46         if (!robjproc)
47                 return error("opcode only valid in OP mode");
48
49         switch (state)
50         {
51         case MO_BITMAP:
52                 return HandleBitmap();
53         case MO_SCBITMAP:
54                 return HandleScaledBitmap();
55         case MO_GPUOBJ:
56                 return HandleGPUObject();
57         case MO_BRANCH:
58                 return HandleBranch();
59         case MO_STOP:
60                 return HandleStop();
61         case MO_NOP:
62                 return HandleNOP();
63         case MO_JUMP:
64                 return HandleJump();
65         }
66
67         return error("unknown OP opcode");
68 }
69
70 static inline void GetSymbolUCFromTokenStream(char * s)
71 {
72         strcpy(s, string[tok[1]]);
73         strtoupper(s);
74         tok += 2;
75 }
76
77 static inline uint64_t CheckFlags(char * s)
78 {
79         GetSymbolUCFromTokenStream(s);
80
81         if (strcmp(scratchbuf, "REFLECT") == 0)
82                 return 0x01;
83         else if (strcmp(scratchbuf, "RMW") == 0)
84                 return 0x02;
85         else if (strcmp(scratchbuf, "TRANS") == 0)
86                 return 0x04;
87         else if (strcmp(scratchbuf, "RELEASE") == 0)
88                 return 0x08;
89
90         return 0;
91 }
92
93 //
94 // Define a bitmap object
95 // Form: bitmap <data>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>, <bpp>,
96 //              <pallete idx>, <flags>, <firstpix>, <pitch>
97 //
98 static int HandleBitmap(void)
99 {
100         uint64_t xpos = 0;
101         uint64_t ypos = 0;
102         uint64_t iheight = 0;
103         uint64_t dwidth = 0;
104         uint64_t iwidth = 0;
105         uint64_t bpp = 0;
106         uint64_t index = 0;
107         uint64_t flags = 0;
108         uint64_t firstpix = 0;
109         uint64_t pitch = 1;
110
111         uint64_t eval;
112         uint16_t eattr;
113         SYM * esym = 0;
114
115         if ((orgaddr & 0x0F) != 0)
116         {
117                 warn("bitmap not on double phrase boundary");
118
119                 // Fixup org address (by emitting a NOP)...
120                 HandleNOP();
121
122                 // We don't need to do a fixup here, because we're guaranteed that the
123                 // last object, if it was a scaled bitmap *or* regular bitmap, will
124                 // already be on the correct boundary, so we won't have to fix it up.
125         }
126
127         if (expr(exprbuf, &eval, &eattr, &esym) != OK)
128                 return ERROR;
129
130         if (!(eattr & DEFINED))
131                 AddFixup(FU_QUAD | FU_OBJDATA, sloc, exprbuf);
132         else if (eattr & TDB)
133                 MarkRelocatable(cursect, sloc, (eattr & TDB), MQUAD, NULL);
134
135         uint64_t dataAddr = eval & 0xFFFFF8;
136         uint64_t linkAddr = (orgaddr + 16) & 0x3FFFF8;
137
138         uint64_t * vars[10] = { &xpos, &ypos, &dwidth, &iwidth, &iheight, &bpp, &index, 0, &firstpix, &pitch };
139
140         for(int i=0; i<10; i++)
141         {
142                 // If there are less than 10 arguments after the data address, use
143                 // defaults for the rest of them
144                 // N.B.: Should there be a default minimum # of args? Like the first 5?
145                 if (tok[0] == EOL)
146                         break;
147
148                 CHECK_COMMA;
149
150                 if (i != 7)
151                 {
152                         if (expr(exprbuf, &eval, &eattr, &esym) != OK)
153                                 return ERROR;
154
155                         if (!(eattr & DEFINED))
156                                 return error("bad expression");
157
158                         *vars[i] = eval;
159                 }
160                 else
161                 {
162                         // Handle FLAGs. Can have at most four.
163                         for(int j=0; j<4; j++)
164                         {
165                                 if (tok[0] != SYMBOL)
166                                         return error("missing REFLECT, RMW, TRANS, and/or RELEASE");
167
168                                 flags |= CheckFlags(scratchbuf);
169
170                                 // Break out if no more symbols...
171                                 if (tok[0] != SYMBOL)
172                                         break;
173                         }
174                 }
175         }
176
177         ErrorIfNotAtEOL();
178
179         uint64_t p1 = 0x00 | ((ypos * 2) << 3) | (iheight << 14) | (linkAddr << 21) | (dataAddr << 40);
180         uint64_t p2 = xpos | (bpp << 12) | (pitch << 15) | (dwidth << 18) | (iwidth << 28) | (index << 38) | (flags << 45) | (firstpix << 49);
181
182         lastSloc = sloc;
183         lastObjType = 0;
184         D_quad(p1);
185         D_quad(p2);
186
187         return OK;
188 }
189
190 //
191 // Define a scaled bitmap object
192 // Form: scbitmap <data>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>,
193 //                <xscale>, <yscale>, <remainder>, <bpp>, <pallete idx>,
194 //                <flags>, <firstpix>, <pitch>
195 //
196 static int HandleScaledBitmap(void)
197 {
198         uint64_t xpos = 0;
199         uint64_t ypos = 0;
200         uint64_t iheight = 0;
201         uint64_t dwidth = 0;
202         uint64_t iwidth = 0;
203         uint64_t bpp = 0;
204         uint64_t index = 0;
205         uint64_t flags = 0;
206         uint64_t firstpix = 0;
207         uint64_t pitch = 1;
208         uint64_t xscale = 0;
209         uint64_t yscale = 0;
210         uint64_t remainder = 0;
211
212         uint64_t eval;
213         uint16_t eattr;
214         SYM * esym = 0;
215
216         if ((orgaddr & 0x1F) != 0)
217         {
218                 warn("scaled bitmap not on quad phrase boundary");
219
220                 // We only have to do a fixup here if the previous object was a bitmap,
221                 // as it can live on a 16-byte boundary while scaled bitmaps can't. If
222                 // the previous object was a scaled bitmap, it is guaranteed to have
223                 // been aligned, therefore no fixup is necessary.
224                 if (lastObjType == 0)
225                 {
226                         *fixupPtr.u64 = (orgaddr + 0x18) & 0xFFFFFFE0;
227                         AddFixup(FU_QUAD | FU_OBJLINK, lastSloc, fixupExpr);
228                 }
229
230                 switch (orgaddr & 0x1F)
231                 {
232                 case 0x08: HandleNOP(); // Emit 3 NOPs
233                 case 0x10: HandleNOP(); // Emit 2 NOPs
234                 case 0x18: HandleNOP(); // Emit 1 NOP
235                 }
236         }
237
238         if (expr(exprbuf, &eval, &eattr, &esym) != OK)
239                 return ERROR;
240
241         if (!(eattr & DEFINED))
242                 AddFixup(FU_QUAD | FU_OBJDATA, sloc, exprbuf);
243         else if (eattr & TDB)
244                 MarkRelocatable(cursect, sloc, (eattr & TDB), MQUAD, NULL);
245
246         uint64_t dataAddr = eval & 0xFFFFF8;
247         uint64_t linkAddr = (orgaddr + 32) & 0x3FFFF8;
248
249         uint64_t * vars[13] = { &xpos, &ypos, &dwidth, &iwidth, &iheight, &xscale, &yscale, &remainder, &bpp, &index, 0, &firstpix, &pitch };
250
251         for(int i=0; i<13; i++)
252         {
253                 // If there are less than 13 arguments after the data address, use
254                 // defaults for the rest of them
255                 // N.B.: Should there be a default minimum # of args? Like the first 5?
256                 if (tok[0] == EOL)
257                         break;
258
259                 CHECK_COMMA;
260
261                 if (i != 10)
262                 {
263                         if (expr(exprbuf, &eval, &eattr, &esym) != OK)
264                                 return ERROR;
265
266                         if (!(eattr & DEFINED))
267                                 return error("bad expression");
268
269                         // Handle 3.5 fixed point nums (if any)...
270                         if ((i >= 5) && (i <= 7))
271                         {
272                                 if (eattr & FLOAT)                      // Handle floats
273                                 {
274 //                                      PTR p = { .u64 = &eval };               // C99 \o/
275                                         PTR p = { (uint8_t *)&eval };   // Meh, it works
276                                         eval = DoubleToFixedPoint(*p.dp, 3, 5);
277                                 }
278                                 else
279                                         eval <<= 5;                             // Otherwise, it's just an int...
280                         }
281
282                         *vars[i] = eval;
283                 }
284                 else
285                 {
286                         // Handle FLAGs. Can have at most four.
287                         for(int j=0; j<4; j++)
288                         {
289                                 if (tok[0] != SYMBOL)
290                                         return error("missing REFLECT, RMW, TRANS, and/or RELEASE");
291
292                                 flags |= CheckFlags(scratchbuf);
293
294                                 // Break out if no more symbols...
295                                 if (tok[0] != SYMBOL)
296                                         break;
297                         }
298                 }
299         }
300
301         ErrorIfNotAtEOL();
302
303         uint64_t p1 = 0x01 | ((ypos * 2) << 3) | (iheight << 14) | (linkAddr << 21) | (dataAddr << 40);
304         uint64_t p2 = xpos | (bpp << 12) | (pitch << 15) | (dwidth << 18) | (iwidth << 28) | (index << 38) | (flags << 45) | (firstpix << 49);
305         uint64_t p3 = (xscale & 0xFF) | (yscale & 0xFF) << 8 | (remainder & 0xFF) << 16;
306
307         lastSloc = sloc;
308         lastObjType = 1;
309         D_quad(p1);
310         D_quad(p2);
311         D_quad(p3);
312         D_quad(0LL);
313
314         return OK;
315 }
316
317 //
318 // Insert GPU object
319 // Form: gpuobj <userdata> (bits 3-63 of this object)
320 //
321 static int HandleGPUObject(void)
322 {
323         uint64_t eval;
324         uint16_t eattr;
325         SYM * esym = 0;
326
327         if (expr(exprbuf, &eval, &eattr, &esym) != OK)
328                 return ERROR;
329
330         if (!(eattr & DEFINED))
331                 return error("bad expression in data");
332
333         ErrorIfNotAtEOL();
334
335         uint64_t p1 = 0x02 | (eval << 3);
336
337         lastObjType = 2;
338         D_quad(p1);
339
340         return OK;
341 }
342
343 //
344 // Insert a branch object
345 // Form: branch VC <condition (<, =, >)> <line #>, <link addr>
346 //       branch OPFLAG, <link addr>
347 //       branch SECHALF, <link addr>
348 //
349 static int HandleBranch(void)
350 {
351         char missingKeyword[] = "missing VC, OPFLAG, or SECHALF in branch";
352         uint32_t cc = 0;
353         uint32_t ypos = 0;
354         uint64_t eval;
355         uint16_t eattr;
356         SYM * esym = 0;
357
358         if (tok[0] != SYMBOL)
359                 return error(missingKeyword);
360
361         GetSymbolUCFromTokenStream(scratchbuf);
362
363         if (strcmp(scratchbuf, "VC") == 0)
364         {
365                 switch (*tok++)
366                 {
367                 case '=': cc = 0; break;
368                 case '<': cc = 1; break;
369                 case '>': cc = 2; break;
370                 default:
371                         return error("missing '<', '>', or '='");
372                 }
373
374                 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
375                         return ERROR;
376
377                 if (!(eattr & DEFINED))
378                         return error("bad expression");
379
380                 ypos = (uint32_t)eval;
381         }
382         else if (strcmp(scratchbuf, "OPFLAG") == 0)
383                 cc = 3;
384         else if (strcmp(scratchbuf, "SECHALF") == 0)
385                 cc = 4;
386         else
387                 return error(missingKeyword);
388
389         CHECK_COMMA;
390
391         if (expr(exprbuf, &eval, &eattr, &esym) != OK)
392                 return ERROR;
393
394         if (!(eattr & DEFINED))
395                 AddFixup(FU_QUAD | FU_OBJLINK, sloc, exprbuf);
396
397         ErrorIfNotAtEOL();
398
399         uint64_t p1 = 0x03 | (cc << 14) | ((ypos * 2) << 3) | ((eval & 0x3FFFF8) << 21);
400
401         lastObjType = 3;
402         D_quad(p1);
403
404         return OK;
405 }
406
407 //
408 // Insert a stop object
409 // Form: stop
410 //
411 static int HandleStop(void)
412 {
413         lastObjType = 4;
414         D_quad(4LL);
415
416         return OK;
417 }
418
419 //
420 // Insert a phrase sized "NOP" in the object list (psuedo-op)
421 // Form: nop
422 //
423 static int HandleNOP(void)
424 {
425         uint64_t eval = (orgaddr + 8) & 0x3FFFF8;
426         // This is "branch if VC > 2047". Branch addr is next phrase, so either way
427         // it will pass by this phrase.
428         uint64_t p1 = 0x03 | (2 << 14) | (0x7FF << 3) | (eval << 21);
429
430         lastObjType = 3;
431         D_quad(p1);
432
433         return OK;
434 }
435
436 //
437 // Insert an unconditional jump in the object list (psuedo-op)
438 // Form: jump <link addr>
439 //
440 static int HandleJump(void)
441 {
442         uint64_t eval;
443         uint16_t eattr;
444         SYM * esym = 0;
445
446         if (expr(exprbuf, &eval, &eattr, &esym) != OK)
447                 return ERROR;
448
449         if (!(eattr & DEFINED))
450                 AddFixup(FU_QUAD | FU_OBJLINK, sloc, exprbuf);
451
452         ErrorIfNotAtEOL();
453
454         // This is "branch if VC < 2047", which pretty much guarantees the branch.
455         uint64_t p1 = 0x03 | (1 << 14) | (0x7FF << 3) | ((eval & 0x3FFFF8) << 21);
456
457         lastObjType = 3;
458         D_quad(p1);
459
460         return OK;
461 }