2 // Jaguar Object Processor assembler
5 // (C) 2018 Underground Software
20 // Macros to help define things (though largely unnecessary for this assembler)
29 // Function prototypes
30 int HandleBitmap(void);
31 int HandleScaledBitmap(void);
32 int HandleGPUObject(void);
33 int HandleBranch(void);
39 static uint8_t lastObjType;
40 static uint32_t lastSloc;
41 static char scratchbuf[4096];
42 static TOKEN fixupExpr[4] = { CONST, 0, 0, ENDEXPR };
43 //static PTR fixupPtr = { .tk = (fixupExpr + 1) }; // C99 \o/
44 static PTR fixupPtr = { (uint8_t *)(fixupExpr + 1) }; // meh, it works
48 // The main Object Processor assembler. Basically just calls the sub functions
49 // to generate the appropriate code.
51 int GenerateOPCode(int state)
54 return error("opcode only valid in OP mode");
59 return HandleBitmap();
61 return HandleScaledBitmap();
63 return HandleGPUObject();
65 return HandleBranch();
74 return error("unknown OP opcode");
78 static inline void GetSymbolUCFromTokenStream(char * s)
80 strcpy(s, string[tok[1]]);
86 static inline uint64_t CheckFlags(char * s)
88 GetSymbolUCFromTokenStream(s);
90 if (strcmp(scratchbuf, "REFLECT") == 0)
92 else if (strcmp(scratchbuf, "RMW") == 0)
94 else if (strcmp(scratchbuf, "TRANS") == 0)
96 else if (strcmp(scratchbuf, "RELEASE") == 0)
103 // Define a bitmap object
104 // Form: bitmap <data>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>, <bpp>,
105 // <pallete idx>, <flags>, <firstpix>, <pitch>
107 int HandleBitmap(void)
111 uint64_t iheight = 0;
117 uint64_t firstpix = 0;
124 if ((orgaddr & 0x0F) != 0)
126 warn("bitmap not on double phrase boundary");
128 // Fixup org address (by emitting a NOP)...
131 // We don't need to do a fixup here, because we're guaranteed that the
132 // last object, if it was a scaled bitmap *or* regular bitmap, will
133 // already be on the correct boundary, so we won't have to fix it up.
136 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
139 if (!(eattr & DEFINED))
140 AddFixup(FU_QUAD | FU_OBJDATA, sloc, exprbuf);
141 else if (eattr & TDB)
142 MarkRelocatable(cursect, sloc, (eattr & TDB), MQUAD, NULL);
144 uint64_t dataAddr = eval & 0xFFFFF8;
145 uint64_t linkAddr = (orgaddr + 16) & 0x3FFFF8;
147 uint64_t * vars[10] = { &xpos, &ypos, &dwidth, &iwidth, &iheight, &bpp, &index, 0, &firstpix, &pitch };
149 for(int i=0; i<10; i++)
151 // If there are less than 10 arguments after the data address, use
152 // defaults for the rest of them
153 // N.B.: Should there be a default minimum # of args? Like the first 5?
161 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
164 if (!(eattr & DEFINED))
165 return error("bad expression");
171 // Handle FLAGs. Can have at most four.
172 for(int j=0; j<4; j++)
174 if (tok[0] != SYMBOL)
175 return error("missing REFLECT, RMW, TRANS, and/or RELEASE");
177 flags |= CheckFlags(scratchbuf);
179 // Break out if no more symbols...
180 if (tok[0] != SYMBOL)
188 uint64_t p1 = 0x00 | ((ypos * 2) << 3) | (iheight << 14) | (linkAddr << 21) | (dataAddr << 40);
189 uint64_t p2 = xpos | (bpp << 12) | (pitch << 15) | (dwidth << 18) | (iwidth << 28) | (index << 38) | (flags << 45) | (firstpix << 49);
201 // Define a scaled bitmap object
202 // Form: scbitmap <data>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>,
203 // <xscale>, <yscale>, <remainder>, <bpp>, <pallete idx>,
204 // <flags>, <firstpix>, <pitch>
206 int HandleScaledBitmap(void)
210 uint64_t iheight = 0;
216 uint64_t firstpix = 0;
220 uint64_t remainder = 0;
226 if ((orgaddr & 0x1F) != 0)
228 warn("scaled bitmap not on quad phrase boundary");
230 // We only have to do a fixup here if the previous object was a bitmap,
231 // as it can live on a 16-byte boundary while scaled bitmaps can't. If
232 // the previous object was a scaled bitmap, it is guaranteed to have
233 // been aligned, therefore no fixup is necessary.
234 if (lastObjType == 0)
236 *fixupPtr.u64 = (orgaddr + 0x18) & 0xFFFFFFE0;
237 AddFixup(FU_QUAD | FU_OBJLINK, lastSloc, fixupExpr);
240 switch (orgaddr & 0x1F)
242 case 0x08: HandleNOP(); // Emit 3 NOPs
243 case 0x10: HandleNOP(); // Emit 2 NOPs
244 case 0x18: HandleNOP(); // Emit 1 NOP
248 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
251 if (!(eattr & DEFINED))
252 AddFixup(FU_QUAD | FU_OBJDATA, sloc, exprbuf);
253 else if (eattr & TDB)
254 MarkRelocatable(cursect, sloc, (eattr & TDB), MQUAD, NULL);
256 uint64_t dataAddr = eval & 0xFFFFF8;
257 uint64_t linkAddr = (orgaddr + 32) & 0x3FFFF8;
259 uint64_t * vars[13] = { &xpos, &ypos, &dwidth, &iwidth, &iheight, &xscale, &yscale, &remainder, &bpp, &index, 0, &firstpix, &pitch };
261 for(int i=0; i<13; i++)
263 // If there are less than 13 arguments after the data address, use
264 // defaults for the rest of them
265 // N.B.: Should there be a default minimum # of args? Like the first 5?
273 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
276 if (!(eattr & DEFINED))
277 return error("bad expression");
279 // Handle 3.5 fixed point nums (if any)...
280 if ((i >= 5) && (i <= 7))
282 if (eattr & FLOAT) // Handle floats
284 // PTR p = { .u64 = &eval }; // C99 \o/
285 PTR p = { (uint8_t *)&eval }; // Meh, it works
286 eval = DoubleToFixedPoint(*p.dp, 3, 5);
289 eval <<= 5; // Otherwise, it's just an int...
296 // Handle FLAGs. Can have at most four.
297 for(int j=0; j<4; j++)
299 if (tok[0] != SYMBOL)
300 return error("missing REFLECT, RMW, TRANS, and/or RELEASE");
302 flags |= CheckFlags(scratchbuf);
304 // Break out if no more symbols...
305 if (tok[0] != SYMBOL)
313 uint64_t p1 = 0x01 | ((ypos * 2) << 3) | (iheight << 14) | (linkAddr << 21) | (dataAddr << 40);
314 uint64_t p2 = xpos | (bpp << 12) | (pitch << 15) | (dwidth << 18) | (iwidth << 28) | (index << 38) | (flags << 45) | (firstpix << 49);
315 uint64_t p3 = (xscale & 0xFF) | (yscale & 0xFF) << 8 | (remainder & 0xFF) << 16;
330 // Form: gpuobj <line #>, <userdata> (bits 14-63 of this object)
332 int HandleGPUObject(void)
338 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
341 if (!(eattr & DEFINED))
342 return error("bad expression in y position");
344 uint64_t ypos = eval;
348 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
351 if (!(eattr & DEFINED))
352 return error("bad expression in data");
356 uint64_t p1 = 0x02 | ((ypos * 2) << 3) | (eval << 14);
366 // Insert a branch object
367 // Form: branch VC <condition (<, =, >)> <line #>, <link addr>
368 // branch OPFLAG, <link addr>
369 // branch SECHALF, <link addr>
371 int HandleBranch(void)
373 char missingKeyword[] = "missing VC, OPFLAG, or SECHALF in branch";
380 if (tok[0] != SYMBOL)
381 return error(missingKeyword);
383 GetSymbolUCFromTokenStream(scratchbuf);
385 if (strcmp(scratchbuf, "VC") == 0)
389 case '=': cc = 0; break;
390 case '<': cc = 1; break;
391 case '>': cc = 2; break;
393 return error("missing '<', '>', or '='");
396 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
399 if (!(eattr & DEFINED))
400 return error("bad expression");
402 ypos = (uint32_t)eval;
404 else if (strcmp(scratchbuf, "OPFLAG") == 0)
406 else if (strcmp(scratchbuf, "SECHALF") == 0)
409 return error(missingKeyword);
413 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
416 if (!(eattr & DEFINED))
417 AddFixup(FU_QUAD | FU_OBJLINK, sloc, exprbuf);
421 uint64_t p1 = 0x03 | (cc << 14) | ((ypos * 2) << 3) | ((eval & 0x3FFFF8) << 21);
431 // Insert a stop object
444 // Insert a phrase sized "NOP" in the object list (psuedo-op)
449 uint64_t eval = (orgaddr + 8) & 0x3FFFF8;
450 // This is "branch if VC > 2047". Branch addr is next phrase, so either way
451 // it will pass by this phrase.
452 uint64_t p1 = 0x03 | (2 << 14) | (0x7FF << 3) | (eval << 21);
462 // Insert an unconditional jump in the object list (psuedo-op)
463 // Form: jump <link addr>
471 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
474 if (!(eattr & DEFINED))
475 AddFixup(FU_QUAD | FU_OBJLINK, sloc, exprbuf);
479 // This is "branch if VC < 2047", which pretty much guarantees the branch.
480 uint64_t p1 = 0x03 | (1 << 14) | (0x7FF << 3) | ((eval & 0x3FFFF8) << 21);