2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // RISCA.C - GPU/DSP Assembler
4 // Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
18 #define DEF_MR // Declar keyword values
19 #include "risckw.h" // Incl generated risc keywords
21 #define DEF_KW // Declare keyword values
22 #include "kwtab.h" // Incl generated keyword tables & defs
25 unsigned altbankok = 0; // Ok to use alternate register bank
26 unsigned orgactive = 0; // RISC org directive active
27 unsigned orgaddr = 0; // Org'd address
28 unsigned orgwarning = 0; // Has an ORG warning been issued
30 char reg_err[] = "missing register R0...R31";
32 // Jaguar Jump Condition Names
33 char condname[MAXINTERNCC][5] = {
34 "NZ", "Z", "NC", "NCNZ", "NCZ", "C", "CNZ", "CZ", "NN", "NNNZ", "NNZ",
35 "N", "N_NZ", "N_Z ", "T", "A", "NE", "EQ", "CC", "HS", "HI", "CS", "LO",
39 // Jaguar Jump Condition Numbers
41 1, 2, 4, 5, 6, 8, 9, 10, 20, 21, 22, 24, 25, 26,
42 0, 0, 1, 2, 4, 4, 5, 8, 8, 20, 24, 31
45 struct opcoderecord roptbl[] = {
46 { MR_ADD, RI_TWO, 0 },
47 { MR_ADDC, RI_TWO, 1 },
48 { MR_ADDQ, RI_NUM_32, 2 },
49 { MR_ADDQT, RI_NUM_32, 3 },
50 { MR_SUB, RI_TWO, 4 },
51 { MR_SUBC, RI_TWO, 5 },
52 { MR_SUBQ, RI_NUM_32, 6 },
53 { MR_SUBQT, RI_NUM_32, 7 },
54 { MR_NEG, RI_ONE, 8 },
55 { MR_AND, RI_TWO, 9 },
56 { MR_OR, RI_TWO, 10 },
57 { MR_XOR, RI_TWO, 11 },
58 { MR_NOT, RI_ONE, 12 },
59 { MR_BTST, RI_NUM_31, 13 },
60 { MR_BSET, RI_NUM_31, 14 },
61 { MR_BCLR, RI_NUM_31, 15 },
62 { MR_MULT, RI_TWO, 16 },
63 { MR_IMULT, RI_TWO, 17 },
64 { MR_IMULTN, RI_TWO, 18 },
65 { MR_RESMAC, RI_ONE, 19 },
66 { MR_IMACN, RI_TWO, 20 },
67 { MR_DIV, RI_TWO, 21 },
68 { MR_ABS, RI_ONE, 22 },
69 { MR_SH, RI_TWO, 23 },
70 { MR_SHLQ, RI_NUM_32, 24 + SUB32 },
71 { MR_SHRQ, RI_NUM_32, 25 },
72 { MR_SHA, RI_TWO, 26 },
73 { MR_SHARQ, RI_NUM_32, 27 },
74 { MR_ROR, RI_TWO, 28 },
75 { MR_RORQ, RI_NUM_32, 29 },
76 { MR_ROLQ, RI_NUM_32, 29 + SUB32 },
77 { MR_CMP, RI_TWO, 30 },
78 { MR_CMPQ, RI_NUM_15, 31 },
79 { MR_SAT8, RI_ONE, 32 + GPUONLY },
80 { MR_SUBQMOD, RI_NUM_32, 32 + DSPONLY },
81 { MR_SAT16, RI_ONE, 33 + GPUONLY },
82 { MR_SAT16S, RI_ONE, 33 + DSPONLY },
83 { MR_MOVEQ, RI_NUM_31, 35 },
84 { MR_MOVETA, RI_TWO, 36 },
85 { MR_MOVEFA, RI_TWO, 37 },
86 { MR_MOVEI, RI_MOVEI, 38 },
87 { MR_LOADB, RI_LOADN, 39 },
88 { MR_LOADW, RI_LOADN, 40 },
89 { MR_LOADP, RI_LOADN, 42 + GPUONLY },
90 { MR_SAT32S, RI_ONE, 42 + DSPONLY },
91 { MR_STOREB, RI_STOREN, 45 },
92 { MR_STOREW, RI_STOREN, 46 },
93 { MR_STOREP, RI_STOREN, 48 + GPUONLY },
94 { MR_MIRROR, RI_ONE, 48 + DSPONLY },
95 { MR_JUMP, RI_JUMP, 52 },
97 { MR_MMULT, RI_TWO, 54 },
98 { MR_MTOI, RI_TWO, 55 },
99 { MR_NORMI, RI_TWO, 56 },
100 { MR_NOP, RI_NONE, 57 },
101 { MR_SAT24, RI_ONE, 62 },
102 { MR_UNPACK, RI_ONE, 63 + GPUONLY },
103 { MR_PACK, RI_ONE, 63 + GPUONLY },
104 { MR_ADDQMOD, RI_NUM_32, 63 + DSPONLY },
105 { MR_MOVE, RI_MOVE, 0 },
106 { MR_LOAD, RI_LOAD, 0 },
107 { MR_STORE, RI_STORE, 0 }
112 // Convert a String to Uppercase
114 void strtoupper(char * s)
119 *s = (char)(toupper(*s));
130 // Function to return "malformed expression" error
131 // This is done mainly to remove a bunch of GOTO statements in the parser
133 static inline int MalformedOpcode(void)
135 error("Malformed opcode");
141 // Build RISC Instruction Word
143 void BuildRISCIntructionWord(unsigned short opcode, int reg1, int reg2)
145 // Check for absolute address setting
146 if (!orgwarning && !orgactive)
148 warn("GPU/DSP code outside of absolute section");
152 int value = ((opcode & 0x3F) << 10) + ((reg1 & 0x1F) << 5) + (reg2 & 0x1F);
158 // Get a RISC Register
160 int GetRegister(WORD rattr)
162 VALUE eval; // Expression value
163 WORD eattr; // Expression attributes
164 SYM * esym; // External symbol involved in expr.
165 TOKEN r_expr[EXPRSIZE]; // Expression token list
167 // Evaluate what's in the global "tok" buffer
168 if (expr(r_expr, &eval, &eattr, &esym) != OK)
169 return MalformedOpcode();
171 if ((challoc - ch_size) < 4)
174 // See if this symbol has been defined, then undefined:
176 //segfaults now (esym == NULL?)
177 /* if (esym->sattre & UNDEF_EQUR)
179 error("undefined register");
183 if (!(eattr & DEFINED))
185 fixup((WORD)(FU_WORD | rattr), sloc, r_expr);
189 // If we got a register in range (0-31), return it
190 if ((eval >= 0) && (eval <= 31))
193 // Otherwise, it's out of range & we flag an error
200 // Do RISC Code Generation
202 int GenerateRISCCode(int state)
204 int reg1; // Register 1
205 int reg2; // Register 2
206 int val = 0; // Constructed value
213 int indexed; // Indexed register flag
215 VALUE eval; // Expression value
216 WORD eattr; // Expression attributes
217 SYM * esym; // External symbol involved in expr.
218 TOKEN r_expr[EXPRSIZE]; // Expression token list
220 // Get opcode parameter and type
221 unsigned short parm = (WORD)(roptbl[state - 3000].parm);
222 unsigned type = roptbl[state - 3000].typ;
224 // Detect whether the opcode parmeter passed determines that the opcode is
225 // specific to only one of the RISC processors and ensure it is legal in
226 // the current code section. If not then show error and return.
227 if (((parm & GPUONLY) && rdsp) || ((parm & DSPONLY) && rgpu))
229 error("Opcode is not valid in this code section");
233 // Process RISC opcode
236 // No operand instructions
239 BuildRISCIntructionWord(parm, 0, 0);
242 // Single operand instructions (Rd)
243 // ABS, MIRROR, NEG, NOT, PACK, RESMAC, SAT8, SAT16, SAT16S, SAT24, SAT32S, UNPACK
245 reg2 = GetRegister(FU_REGTWO);
247 BuildRISCIntructionWord(parm, parm >> 6, reg2);
250 // Two operand instructions (Rs,Rd)
251 // ADD, ADDC, AND, CMP, DIV, IMACN, IMULT, IMULTN, MOVEFA, MOVETA, MULT, MMULT,
252 // MTOI, NORMI, OR, ROR, SH, SHA, SUB, SUBC, XOR
255 altbankok = 1; // MOVEFA
257 reg1 = GetRegister(FU_REGONE);
261 altbankok = 1; // MOVETA
263 reg2 = GetRegister(FU_REGTWO);
265 BuildRISCIntructionWord(parm, reg1, reg2);
268 // Numeric operand (n,Rd) where n = -16..+15
272 // Numeric operand (n,Rd) where n = 0..31
273 // BCLR, BSET, BTST, MOVEQ
276 // Numeric operand (n,Rd) where n = 1..32
277 // ADDQ, ADDQMOD, ADDQT, SHARQ, SHLQ, SHRQ, SUBQ, SUBQMOD, SUBQT, ROLQ, RORQ
282 reg1 = -16; reg2 = 15; attrflg = FU_NUM15;
286 reg1 = 0; reg2 = 31; attrflg = FU_NUM31;
289 reg1 = 1; reg2 = 32; attrflg = FU_NUM32;
297 return MalformedOpcode();
301 if (expr(r_expr, &eval, &eattr, &esym) != OK)
302 return MalformedOpcode();
304 if ((challoc - ch_size) < 4)
307 if (!(eattr & DEFINED))
309 fixup((WORD)(FU_WORD | attrflg), sloc, r_expr);
314 if ((int)eval < reg1 || (int)eval > reg2)
316 error("constant out of range");
322 else if (type == RI_NUM_32)
323 reg1 = (reg1 == 32 ? 0 : eval);
329 reg2 = GetRegister(FU_REGTWO);
331 BuildRISCIntructionWord(parm, reg1, reg2);
334 // Move Immediate--n,Rn--n in Second Word
337 return MalformedOpcode();
341 if (expr(r_expr, &eval, &eattr, &esym) != OK)
342 return MalformedOpcode();
344 if ((challoc - ch_size) < 4)
347 if (!(eattr & DEFINED))
349 fixup(FU_LONG | FU_MOVEI, sloc + 2, r_expr);
356 //printf("risca: Doing rmark for RI_MOVEI (tdb=$%X)...\n", eattr & TDB);
357 rmark(cursect, sloc + 2, (eattr & TDB), (MLONG | MMOVEI), NULL);
361 val = ((eval >> 16) & 0x0000FFFF) | ((eval << 16) & 0xFFFF0000);
363 reg2 = GetRegister(FU_REGTWO);
365 D_word((((parm & 0x3F) << 10) + reg2));
380 reg1 = GetRegister(FU_REGONE);
384 reg2 = GetRegister(FU_REGTWO);
386 BuildRISCIntructionWord(parm, reg1, reg2);
389 // (Rn),Rn = 41 / (R14/R15+n),Rn = 43/44 / (R14/R15+Rn),Rn = 58/59
395 return MalformedOpcode();
399 if ((*tok == KW_R14 || *tok == KW_R15) && (*(tok + 1) != ')'))
400 indexed = (*tok - KW_R0);
404 // sy = lookup((char *)tok[1], LABEL, 0);
405 sy = lookup(string[tok[1]], LABEL, 0);
413 if (sy->sattre & EQUATEDREG)
415 if (((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15)
416 && (*(tok + 2) != ')'))
418 indexed = (sy->svalue & 0x1F);
426 reg1 = GetRegister(FU_REGONE);
436 parm = (WORD)(reg1 - 14 + 58);
439 if (*tok >= KW_R0 && *tok <= KW_R31)
444 // sy = lookup((char *)tok[1], LABEL, 0);
445 sy = lookup(string[tok[1]], LABEL, 0);
453 if (sy->sattre & EQUATEDREG)
459 reg1 = GetRegister(FU_REGONE);
463 if (expr(r_expr, &eval, &eattr, &esym) != OK)
464 return MalformedOpcode();
466 if ((challoc - ch_size) < 4)
469 if (!(eattr & DEFINED))
471 error("constant expected");
479 reg1 = 14 + (parm - 58);
481 warn("NULL offset removed");
485 if (reg1 < 1 || reg1 > 32)
487 error("constant out of range");
494 parm = (WORD)(parm - 58 + 43);
500 reg1 = GetRegister(FU_REGONE);
505 return MalformedOpcode();
509 reg2 = GetRegister(FU_REGTWO);
511 BuildRISCIntructionWord(parm, reg1, reg2);
514 // Rn,(Rn) = 47 / Rn,(R14/R15+n) = 49/50 / Rn,(R14/R15+Rn) = 60/61
517 reg1 = GetRegister(FU_REGONE);
521 return MalformedOpcode();
526 if ((*tok == KW_R14 || *tok == KW_R15) && (*(tok + 1) != ')'))
527 indexed = (*tok - KW_R0);
531 // sy = lookup((char *)tok[1], LABEL, 0);
532 sy = lookup(string[tok[1]], LABEL, 0);
540 if (sy->sattre & EQUATEDREG)
542 if (((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15)
543 && (*(tok + 2) != ')'))
545 indexed = (sy->svalue & 0x1F);
553 reg2 = GetRegister(FU_REGTWO);
563 parm = (WORD)(reg2 - 14 + 60);
566 if (*tok >= KW_R0 && *tok <= KW_R31)
571 // sy = lookup((char *)tok[1], LABEL, 0);
572 sy = lookup(string[tok[1]], LABEL, 0);
580 if (sy->sattre & EQUATEDREG)
586 reg2 = GetRegister(FU_REGTWO);
590 if (expr(r_expr, &eval, &eattr, &esym) != OK)
591 return MalformedOpcode();
593 if ((challoc - ch_size) < 4)
596 if (!(eattr & DEFINED))
598 fixup(FU_WORD | FU_REGTWO, sloc, r_expr);
607 reg2 = 14 + (parm - 60);
609 warn("NULL offset removed");
613 if (reg2 < 1 || reg2 > 32)
615 error("constant out of range");
622 parm = (WORD)(parm - 60 + 49);
629 reg2 = GetRegister(FU_REGTWO);
634 return MalformedOpcode();
638 BuildRISCIntructionWord(parm, reg2, reg1);
641 // LOADB/LOADP/LOADW (Rn),Rn
644 return MalformedOpcode();
647 reg1 = GetRegister(FU_REGONE);
650 return MalformedOpcode();
654 reg2 = GetRegister(FU_REGTWO);
656 BuildRISCIntructionWord(parm, reg1, reg2);
659 // STOREB/STOREP/STOREW Rn,(Rn)
661 reg1 = GetRegister(FU_REGONE);
665 return MalformedOpcode();
668 reg2 = GetRegister(FU_REGTWO);
671 return MalformedOpcode();
675 BuildRISCIntructionWord(parm, reg2, reg1);
678 // Jump Relative - cc,n - n=-16..+15 words, reg2=cc
681 // Jump Absolute - cc,(Rs) - reg2=cc
683 // Check to see if there is a comma in the token string. If not then
684 // the JR or JUMP should default to 0, Jump Always
687 for(t=tok; *t!=EOL; t++)
700 // CC using a constant number
706 else if (*tok == SYMBOL)
709 // strcpy(scratch, (char *)tok[1]);
710 strcpy(scratch, string[tok[1]]);
713 for(i=0; i<MAXINTERNCC; i++)
715 // Look for the condition code & break if found
716 if (strcmp(condname[i], scratch) == 0)
723 // Standard CC was not found, look for an equated one
726 // ccsym = lookup((char *)tok[1], LABEL, 0);
727 ccsym = lookup(string[tok[1]], LABEL, 0);
729 if (ccsym && (ccsym->sattre & EQUATEDCC) && !(ccsym->sattre & UNDEF_CC))
735 error("unknown condition code");
743 else if (*tok == '(')
745 // Set CC to "Jump Always"
751 // Set CC to "Jump Always"
755 if (val < 0 || val > 31)
757 error("condition constant out of range");
761 // Store condition code
767 if (expr(r_expr, &eval, &eattr, &esym) != OK)
768 return MalformedOpcode();
770 if ((challoc - ch_size) < 4)
773 if (!(eattr & DEFINED))
775 fixup(FU_WORD | FU_JR, sloc, r_expr);
780 reg2 = ((int)(eval - ((orgactive ? orgaddr : sloc) + 2))) / 2;
782 if ((reg2 < -16) || (reg2 > 15))
783 error("PC relative overflow");
786 BuildRISCIntructionWord(parm, reg2, reg1);
792 return MalformedOpcode();
795 reg2 = GetRegister(FU_REGTWO);
798 return MalformedOpcode();
802 BuildRISCIntructionWord(parm, reg2, reg1);
807 // Should never get here :-D
809 error("Unknown risc opcode type");