2 // Jaguar Object Processor assembler
5 // (C) 2019 Underground Software
21 #include "opkw.h" // For MO_* macros
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);
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
42 // The main Object Processor assembler. Basically just calls the sub functions
43 // to generate the appropriate code.
45 int GenerateOPCode(int state)
48 return error("opcode only valid in OP mode");
53 return HandleBitmap();
55 return HandleScaledBitmap();
57 return HandleGPUObject();
59 return HandleBranch();
68 return error("unknown OP opcode");
72 static inline void GetSymbolUCFromTokenStream(char * s)
74 strcpy(s, string[tok[1]]);
80 static inline uint64_t CheckFlags(char * s)
82 GetSymbolUCFromTokenStream(s);
84 if (strcmp(scratchbuf, "REFLECT") == 0)
86 else if (strcmp(scratchbuf, "RMW") == 0)
88 else if (strcmp(scratchbuf, "TRANS") == 0)
90 else if (strcmp(scratchbuf, "RELEASE") == 0)
98 // Define a bitmap object
99 // Form: bitmap <data>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>, <bpp>,
100 // <pallete idx>, <flags>, <firstpix>, <pitch>
102 static int HandleBitmap(void)
106 uint64_t iheight = 0;
112 uint64_t firstpix = 0;
119 if ((orgaddr & 0x0F) != 0)
121 warn("bitmap not on double phrase boundary");
123 // Fixup org address (by emitting a NOP)...
126 // We don't need to do a fixup here, because we're guaranteed that the
127 // last object, if it was a scaled bitmap *or* regular bitmap, will
128 // already be on the correct boundary, so we won't have to fix it up.
131 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
134 if (!(eattr & DEFINED))
135 AddFixup(FU_QUAD | FU_OBJDATA, sloc, exprbuf);
136 else if (eattr & TDB)
137 MarkRelocatable(cursect, sloc, (eattr & TDB), MQUAD, NULL);
139 uint64_t dataAddr = eval & 0xFFFFF8;
140 uint64_t linkAddr = (orgaddr + 16) & 0x3FFFF8;
142 uint64_t * vars[10] = { &xpos, &ypos, &dwidth, &iwidth, &iheight, &bpp, &index, 0, &firstpix, &pitch };
144 for(int i=0; i<10; i++)
146 // If there are less than 10 arguments after the data address, use
147 // defaults for the rest of them
148 // N.B.: Should there be a default minimum # of args? Like the first 5?
156 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
159 if (!(eattr & DEFINED))
160 return error("bad expression");
166 // Handle FLAGs. Can have at most four.
167 for(int j=0; j<4; j++)
169 if (tok[0] != SYMBOL)
170 return error("missing REFLECT, RMW, TRANS, and/or RELEASE");
172 flags |= CheckFlags(scratchbuf);
174 // Break out if no more symbols...
175 if (tok[0] != SYMBOL)
183 uint64_t p1 = 0x00 | ((ypos * 2) << 3) | (iheight << 14) | (linkAddr << 21) | (dataAddr << 40);
184 uint64_t p2 = xpos | (bpp << 12) | (pitch << 15) | (dwidth << 18) | (iwidth << 28) | (index << 38) | (flags << 45) | (firstpix << 49);
196 // Define a scaled bitmap object
197 // Form: scbitmap <data>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>,
198 // <xscale>, <yscale>, <remainder>, <bpp>, <pallete idx>,
199 // <flags>, <firstpix>, <pitch>
201 static int HandleScaledBitmap(void)
205 uint64_t iheight = 0;
211 uint64_t firstpix = 0;
215 uint64_t remainder = 0;
221 if ((orgaddr & 0x1F) != 0)
223 warn("scaled bitmap not on quad phrase boundary");
225 // We only have to do a fixup here if the previous object was a bitmap,
226 // as it can live on a 16-byte boundary while scaled bitmaps can't. If
227 // the previous object was a scaled bitmap, it is guaranteed to have
228 // been aligned, therefore no fixup is necessary.
229 if (lastObjType == 0)
231 *fixupPtr.u64 = (orgaddr + 0x18) & 0xFFFFFFE0;
232 AddFixup(FU_QUAD | FU_OBJLINK, lastSloc, fixupExpr);
235 switch (orgaddr & 0x1F)
237 case 0x08: HandleNOP(); // Emit 3 NOPs
238 case 0x10: HandleNOP(); // Emit 2 NOPs
239 case 0x18: HandleNOP(); // Emit 1 NOP
243 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
246 if (!(eattr & DEFINED))
247 AddFixup(FU_QUAD | FU_OBJDATA, sloc, exprbuf);
248 else if (eattr & TDB)
249 MarkRelocatable(cursect, sloc, (eattr & TDB), MQUAD, NULL);
251 uint64_t dataAddr = eval & 0xFFFFF8;
252 uint64_t linkAddr = (orgaddr + 32) & 0x3FFFF8;
254 uint64_t * vars[13] = { &xpos, &ypos, &dwidth, &iwidth, &iheight, &xscale, &yscale, &remainder, &bpp, &index, 0, &firstpix, &pitch };
256 for(int i=0; i<13; i++)
258 // If there are less than 13 arguments after the data address, use
259 // defaults for the rest of them
260 // N.B.: Should there be a default minimum # of args? Like the first 5?
268 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
271 if (!(eattr & DEFINED))
272 return error("bad expression");
274 // Handle 3.5 fixed point nums (if any)...
275 if ((i >= 5) && (i <= 7))
277 if (eattr & FLOAT) // Handle floats
279 // PTR p = { .u64 = &eval }; // C99 \o/
280 PTR p = { (uint8_t *)&eval }; // Meh, it works
281 eval = DoubleToFixedPoint(*p.dp, 3, 5);
284 eval <<= 5; // Otherwise, it's just an int...
291 // Handle FLAGs. Can have at most four.
292 for(int j=0; j<4; j++)
294 if (tok[0] != SYMBOL)
295 return error("missing REFLECT, RMW, TRANS, and/or RELEASE");
297 flags |= CheckFlags(scratchbuf);
299 // Break out if no more symbols...
300 if (tok[0] != SYMBOL)
308 uint64_t p1 = 0x01 | ((ypos * 2) << 3) | (iheight << 14) | (linkAddr << 21) | (dataAddr << 40);
309 uint64_t p2 = xpos | (bpp << 12) | (pitch << 15) | (dwidth << 18) | (iwidth << 28) | (index << 38) | (flags << 45) | (firstpix << 49);
310 uint64_t p3 = (xscale & 0xFF) | (yscale & 0xFF) << 8 | (remainder & 0xFF) << 16;
325 // Form: gpuobj <line #>, <userdata> (bits 14-63 of this object)
327 static int HandleGPUObject(void)
333 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
336 if (!(eattr & DEFINED))
337 return error("bad expression in y position");
339 uint64_t ypos = eval;
343 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
346 if (!(eattr & DEFINED))
347 return error("bad expression in data");
351 uint64_t p1 = 0x02 | ((ypos * 2) << 3) | (eval << 14);
361 // Insert a branch object
362 // Form: branch VC <condition (<, =, >)> <line #>, <link addr>
363 // branch OPFLAG, <link addr>
364 // branch SECHALF, <link addr>
366 static int HandleBranch(void)
368 char missingKeyword[] = "missing VC, OPFLAG, or SECHALF in branch";
375 if (tok[0] != SYMBOL)
376 return error(missingKeyword);
378 GetSymbolUCFromTokenStream(scratchbuf);
380 if (strcmp(scratchbuf, "VC") == 0)
384 case '=': cc = 0; break;
385 case '<': cc = 1; break;
386 case '>': cc = 2; break;
388 return error("missing '<', '>', or '='");
391 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
394 if (!(eattr & DEFINED))
395 return error("bad expression");
397 ypos = (uint32_t)eval;
399 else if (strcmp(scratchbuf, "OPFLAG") == 0)
401 else if (strcmp(scratchbuf, "SECHALF") == 0)
404 return error(missingKeyword);
408 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
411 if (!(eattr & DEFINED))
412 AddFixup(FU_QUAD | FU_OBJLINK, sloc, exprbuf);
416 uint64_t p1 = 0x03 | (cc << 14) | ((ypos * 2) << 3) | ((eval & 0x3FFFF8) << 21);
426 // Insert a stop object
429 static int HandleStop(void)
439 // Insert a phrase sized "NOP" in the object list (psuedo-op)
442 static int HandleNOP(void)
444 uint64_t eval = (orgaddr + 8) & 0x3FFFF8;
445 // This is "branch if VC > 2047". Branch addr is next phrase, so either way
446 // it will pass by this phrase.
447 uint64_t p1 = 0x03 | (2 << 14) | (0x7FF << 3) | (eval << 21);
457 // Insert an unconditional jump in the object list (psuedo-op)
458 // Form: jump <link addr>
460 static int HandleJump(void)
466 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
469 if (!(eattr & DEFINED))
470 AddFixup(FU_QUAD | FU_OBJLINK, sloc, exprbuf);
474 // This is "branch if VC < 2047", which pretty much guarantees the branch.
475 uint64_t p1 = 0x03 | (1 << 14) | (0x7FF << 3) | ((eval & 0x3FFFF8) << 21);