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)
97 // Define a bitmap object
98 // Form: bitmap <data>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>, <bpp>,
99 // <pallete idx>, <flags>, <firstpix>, <pitch>
101 static int HandleBitmap(void)
105 uint64_t iheight = 0;
111 uint64_t firstpix = 0;
118 if ((orgaddr & 0x0F) != 0)
120 warn("bitmap not on double phrase boundary");
122 // Fixup org address (by emitting a NOP)...
125 // We don't need to do a fixup here, because we're guaranteed that the
126 // last object, if it was a scaled bitmap *or* regular bitmap, will
127 // already be on the correct boundary, so we won't have to fix it up.
130 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
133 if (!(eattr & DEFINED))
134 AddFixup(FU_QUAD | FU_OBJDATA, sloc, exprbuf);
135 else if (eattr & TDB)
136 MarkRelocatable(cursect, sloc, (eattr & TDB), MQUAD, NULL);
138 uint64_t dataAddr = eval & 0xFFFFF8;
139 uint64_t linkAddr = (orgaddr + 16) & 0x3FFFF8;
141 uint64_t * vars[10] = { &xpos, &ypos, &dwidth, &iwidth, &iheight, &bpp, &index, 0, &firstpix, &pitch };
143 for(int i=0; i<10; i++)
145 // If there are less than 10 arguments after the data address, use
146 // defaults for the rest of them
147 // N.B.: Should there be a default minimum # of args? Like the first 5?
155 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
158 if (!(eattr & DEFINED))
159 return error("bad expression");
165 // Handle FLAGs. Can have at most four.
166 for(int j=0; j<4; j++)
168 if (tok[0] != SYMBOL)
169 return error("missing REFLECT, RMW, TRANS, and/or RELEASE");
171 flags |= CheckFlags(scratchbuf);
173 // Break out if no more symbols...
174 if (tok[0] != SYMBOL)
182 uint64_t p1 = 0x00 | ((ypos * 2) << 3) | (iheight << 14) | (linkAddr << 21) | (dataAddr << 40);
183 uint64_t p2 = xpos | (bpp << 12) | (pitch << 15) | (dwidth << 18) | (iwidth << 28) | (index << 38) | (flags << 45) | (firstpix << 49);
195 // Define a scaled bitmap object
196 // Form: scbitmap <data>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>,
197 // <xscale>, <yscale>, <remainder>, <bpp>, <pallete idx>,
198 // <flags>, <firstpix>, <pitch>
200 static int HandleScaledBitmap(void)
204 uint64_t iheight = 0;
210 uint64_t firstpix = 0;
214 uint64_t remainder = 0;
220 if ((orgaddr & 0x1F) != 0)
222 warn("scaled bitmap not on quad phrase boundary");
224 // We only have to do a fixup here if the previous object was a bitmap,
225 // as it can live on a 16-byte boundary while scaled bitmaps can't. If
226 // the previous object was a scaled bitmap, it is guaranteed to have
227 // been aligned, therefore no fixup is necessary.
228 if (lastObjType == 0)
230 *fixupPtr.u64 = (orgaddr + 0x18) & 0xFFFFFFE0;
231 AddFixup(FU_QUAD | FU_OBJLINK, lastSloc, fixupExpr);
234 switch (orgaddr & 0x1F)
236 case 0x08: HandleNOP(); // Emit 3 NOPs
237 case 0x10: HandleNOP(); // Emit 2 NOPs
238 case 0x18: HandleNOP(); // Emit 1 NOP
242 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
245 if (!(eattr & DEFINED))
246 AddFixup(FU_QUAD | FU_OBJDATA, sloc, exprbuf);
247 else if (eattr & TDB)
248 MarkRelocatable(cursect, sloc, (eattr & TDB), MQUAD, NULL);
250 uint64_t dataAddr = eval & 0xFFFFF8;
251 uint64_t linkAddr = (orgaddr + 32) & 0x3FFFF8;
253 uint64_t * vars[13] = { &xpos, &ypos, &dwidth, &iwidth, &iheight, &xscale, &yscale, &remainder, &bpp, &index, 0, &firstpix, &pitch };
255 for(int i=0; i<13; i++)
257 // If there are less than 13 arguments after the data address, use
258 // defaults for the rest of them
259 // N.B.: Should there be a default minimum # of args? Like the first 5?
267 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
270 if (!(eattr & DEFINED))
271 return error("bad expression");
273 // Handle 3.5 fixed point nums (if any)...
274 if ((i >= 5) && (i <= 7))
276 if (eattr & FLOAT) // Handle floats
278 // PTR p = { .u64 = &eval }; // C99 \o/
279 PTR p = { (uint8_t *)&eval }; // Meh, it works
280 eval = DoubleToFixedPoint(*p.dp, 3, 5);
283 eval <<= 5; // Otherwise, it's just an int...
290 // Handle FLAGs. Can have at most four.
291 for(int j=0; j<4; j++)
293 if (tok[0] != SYMBOL)
294 return error("missing REFLECT, RMW, TRANS, and/or RELEASE");
296 flags |= CheckFlags(scratchbuf);
298 // Break out if no more symbols...
299 if (tok[0] != SYMBOL)
307 uint64_t p1 = 0x01 | ((ypos * 2) << 3) | (iheight << 14) | (linkAddr << 21) | (dataAddr << 40);
308 uint64_t p2 = xpos | (bpp << 12) | (pitch << 15) | (dwidth << 18) | (iwidth << 28) | (index << 38) | (flags << 45) | (firstpix << 49);
309 uint64_t p3 = (xscale & 0xFF) | (yscale & 0xFF) << 8 | (remainder & 0xFF) << 16;
324 // Form: gpuobj <line #>, <userdata> (bits 14-63 of this object)
326 static int HandleGPUObject(void)
332 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
335 if (!(eattr & DEFINED))
336 return error("bad expression in y position");
338 uint64_t ypos = eval;
342 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
345 if (!(eattr & DEFINED))
346 return error("bad expression in data");
350 uint64_t p1 = 0x02 | ((ypos * 2) << 3) | (eval << 14);
360 // Insert a branch object
361 // Form: branch VC <condition (<, =, >)> <line #>, <link addr>
362 // branch OPFLAG, <link addr>
363 // branch SECHALF, <link addr>
365 static int HandleBranch(void)
367 char missingKeyword[] = "missing VC, OPFLAG, or SECHALF in branch";
374 if (tok[0] != SYMBOL)
375 return error(missingKeyword);
377 GetSymbolUCFromTokenStream(scratchbuf);
379 if (strcmp(scratchbuf, "VC") == 0)
383 case '=': cc = 0; break;
384 case '<': cc = 1; break;
385 case '>': cc = 2; break;
387 return error("missing '<', '>', or '='");
390 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
393 if (!(eattr & DEFINED))
394 return error("bad expression");
396 ypos = (uint32_t)eval;
398 else if (strcmp(scratchbuf, "OPFLAG") == 0)
400 else if (strcmp(scratchbuf, "SECHALF") == 0)
403 return error(missingKeyword);
407 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
410 if (!(eattr & DEFINED))
411 AddFixup(FU_QUAD | FU_OBJLINK, sloc, exprbuf);
415 uint64_t p1 = 0x03 | (cc << 14) | ((ypos * 2) << 3) | ((eval & 0x3FFFF8) << 21);
425 // Insert a stop object
428 static int HandleStop(void)
438 // Insert a phrase sized "NOP" in the object list (psuedo-op)
441 static int HandleNOP(void)
443 uint64_t eval = (orgaddr + 8) & 0x3FFFF8;
444 // This is "branch if VC > 2047". Branch addr is next phrase, so either way
445 // it will pass by this phrase.
446 uint64_t p1 = 0x03 | (2 << 14) | (0x7FF << 3) | (eval << 21);
456 // Insert an unconditional jump in the object list (psuedo-op)
457 // Form: jump <link addr>
459 static int HandleJump(void)
465 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
468 if (!(eattr & DEFINED))
469 AddFixup(FU_QUAD | FU_OBJLINK, sloc, exprbuf);
473 // This is "branch if VC < 2047", which pretty much guarantees the branch.
474 uint64_t p1 = 0x03 | (1 << 14) | (0x7FF << 3) | ((eval & 0x3FFFF8) << 21);