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
29 int lastOpcode = -1; // Last RISC opcode assembled
31 char reg_err[] = "missing register R0...R31";
33 // Jaguar Jump Condition Names
34 char condname[MAXINTERNCC][5] = {
35 "NZ", "Z", "NC", "NCNZ", "NCZ", "C", "CNZ", "CZ", "NN", "NNNZ", "NNZ",
36 "N", "N_NZ", "N_Z", "T", "A", "NE", "EQ", "CC", "HS", "HI", "CS", "LO",
40 // Jaguar Jump Condition Numbers
42 1, 2, 4, 5, 6, 8, 9, 10, 20, 21, 22, 24, 25, 26,
43 0, 0, 1, 2, 4, 4, 5, 8, 8, 20, 24, 31
46 struct opcoderecord roptbl[] = {
47 { MR_ADD, RI_TWO, 0 },
48 { MR_ADDC, RI_TWO, 1 },
49 { MR_ADDQ, RI_NUM_32, 2 },
50 { MR_ADDQT, RI_NUM_32, 3 },
51 { MR_SUB, RI_TWO, 4 },
52 { MR_SUBC, RI_TWO, 5 },
53 { MR_SUBQ, RI_NUM_32, 6 },
54 { MR_SUBQT, RI_NUM_32, 7 },
55 { MR_NEG, RI_ONE, 8 },
56 { MR_AND, RI_TWO, 9 },
57 { MR_OR, RI_TWO, 10 },
58 { MR_XOR, RI_TWO, 11 },
59 { MR_NOT, RI_ONE, 12 },
60 { MR_BTST, RI_NUM_31, 13 },
61 { MR_BSET, RI_NUM_31, 14 },
62 { MR_BCLR, RI_NUM_31, 15 },
63 { MR_MULT, RI_TWO, 16 },
64 { MR_IMULT, RI_TWO, 17 },
65 { MR_IMULTN, RI_TWO, 18 },
66 { MR_RESMAC, RI_ONE, 19 },
67 { MR_IMACN, RI_TWO, 20 },
68 { MR_DIV, RI_TWO, 21 },
69 { MR_ABS, RI_ONE, 22 },
70 { MR_SH, RI_TWO, 23 },
71 { MR_SHLQ, RI_NUM_32, 24 + SUB32 },
72 { MR_SHRQ, RI_NUM_32, 25 },
73 { MR_SHA, RI_TWO, 26 },
74 { MR_SHARQ, RI_NUM_32, 27 },
75 { MR_ROR, RI_TWO, 28 },
76 { MR_RORQ, RI_NUM_32, 29 },
77 { MR_ROLQ, RI_NUM_32, 29 + SUB32 },
78 { MR_CMP, RI_TWO, 30 },
79 { MR_CMPQ, RI_NUM_15, 31 },
80 { MR_SAT8, RI_ONE, 32 + GPUONLY },
81 { MR_SUBQMOD, RI_NUM_32, 32 + DSPONLY },
82 { MR_SAT16, RI_ONE, 33 + GPUONLY },
83 { MR_SAT16S, RI_ONE, 33 + DSPONLY },
84 { MR_MOVEQ, RI_NUM_31, 35 },
85 { MR_MOVETA, RI_TWO, 36 },
86 { MR_MOVEFA, RI_TWO, 37 },
87 { MR_MOVEI, RI_MOVEI, 38 },
88 { MR_LOADB, RI_LOADN, 39 },
89 { MR_LOADW, RI_LOADN, 40 },
90 { MR_LOADP, RI_LOADN, 42 + GPUONLY },
91 { MR_SAT32S, RI_ONE, 42 + DSPONLY },
92 { MR_STOREB, RI_STOREN, 45 },
93 { MR_STOREW, RI_STOREN, 46 },
94 { MR_STOREP, RI_STOREN, 48 + GPUONLY },
95 { MR_MIRROR, RI_ONE, 48 + DSPONLY },
96 { MR_JUMP, RI_JUMP, 52 },
98 { MR_MMULT, RI_TWO, 54 },
99 { MR_MTOI, RI_TWO, 55 },
100 { MR_NORMI, RI_TWO, 56 },
101 { MR_NOP, RI_NONE, 57 },
102 { MR_SAT24, RI_ONE, 62 },
103 { MR_UNPACK, RI_ONE, 63 + GPUONLY },
104 { MR_PACK, RI_ONE, 63 + GPUONLY },
105 { MR_ADDQMOD, RI_NUM_32, 63 + DSPONLY },
106 { MR_MOVE, RI_MOVE, 0 },
107 { MR_LOAD, RI_LOAD, 0 },
108 { MR_STORE, RI_STORE, 0 }
113 // Convert a String to Uppercase
115 void strtoupper(char * s)
123 // Function to return "malformed expression" error
124 // This is done mainly to remove a bunch of GOTO statements in the parser
126 static inline int MalformedOpcode(int signal)
129 sprintf(buf, "%02X", signal);
130 errors("Malformed opcode [internal $%s]", buf);
136 // Build RISC Instruction Word
138 void BuildRISCIntructionWord(unsigned short opcode, int reg1, int reg2)
140 // Check for absolute address setting
141 if (!orgwarning && !orgactive)
143 warn("GPU/DSP code outside of absolute section");
147 int value = ((opcode & 0x3F) << 10) + ((reg1 & 0x1F) << 5) + (reg2 & 0x1F);
153 // Get a RISC Register
155 int GetRegister(WORD rattr)
157 VALUE eval; // Expression value
158 WORD eattr; // Expression attributes
159 SYM * esym; // External symbol involved in expr.
160 TOKEN r_expr[EXPRSIZE]; // Expression token list
162 // Evaluate what's in the global "tok" buffer
163 if (expr(r_expr, &eval, &eattr, &esym) != OK)
164 // Hmm, the evaluator should report the error to us...
165 // return MalformedOpcode(0x00);
168 if ((challoc - ch_size) < 4)
171 if (!(eattr & DEFINED))
173 fixup((WORD)(FU_WORD | rattr), sloc, r_expr);
177 // If we got a register in range (0-31), return it
178 if ((eval >= 0) && (eval <= 31))
181 // Otherwise, it's out of range & we flag an error
188 // Do RISC Code Generation
190 int GenerateRISCCode(int state)
192 int reg1; // Register 1
193 int reg2; // Register 2
194 int val = 0; // Constructed value
201 int indexed; // Indexed register flag
203 VALUE eval; // Expression value
204 WORD eattr; // Expression attributes
205 SYM * esym; // External symbol involved in expr.
206 TOKEN r_expr[EXPRSIZE]; // Expression token list
208 // Get opcode parameter and type
209 unsigned short parm = (WORD)(roptbl[state - 3000].parm);
210 unsigned type = roptbl[state - 3000].typ;
212 // Detect whether the opcode parmeter passed determines that the opcode is
213 // specific to only one of the RISC processors and ensure it is legal in
214 // the current code section. If not then show error and return.
215 if (((parm & GPUONLY) && rdsp) || ((parm & DSPONLY) && rgpu))
217 error("Opcode is not valid in this code section");
221 // Process RISC opcode
224 // No operand instructions
227 BuildRISCIntructionWord(parm, 0, 0);
230 // Single operand instructions (Rd)
231 // ABS, MIRROR, NEG, NOT, PACK, RESMAC, SAT8, SAT16, SAT16S, SAT24, SAT32S, UNPACK
233 reg2 = GetRegister(FU_REGTWO);
235 BuildRISCIntructionWord(parm, parm >> 6, reg2);
238 // Two operand instructions (Rs,Rd)
239 // ADD, ADDC, AND, CMP, DIV, IMACN, IMULT, IMULTN, MOVEFA, MOVETA, MULT, MMULT,
240 // MTOI, NORMI, OR, ROR, SH, SHA, SUB, SUBC, XOR
243 altbankok = 1; // MOVEFA
245 reg1 = GetRegister(FU_REGONE);
249 altbankok = 1; // MOVETA
251 reg2 = GetRegister(FU_REGTWO);
253 BuildRISCIntructionWord(parm, reg1, reg2);
256 // Numeric operand (n,Rd) where n = -16..+15
260 // Numeric operand (n,Rd) where n = 0..31
261 // BCLR, BSET, BTST, MOVEQ
264 // Numeric operand (n,Rd) where n = 1..32
265 // ADDQ, ADDQMOD, ADDQT, SHARQ, SHLQ, SHRQ, SUBQ, SUBQMOD, SUBQT, ROLQ, RORQ
270 reg1 = -16; reg2 = 15; attrflg = FU_NUM15;
274 reg1 = 0; reg2 = 31; attrflg = FU_NUM31;
277 reg1 = 1; reg2 = 32; attrflg = FU_NUM32;
285 return MalformedOpcode(0x01);
289 if (expr(r_expr, &eval, &eattr, &esym) != OK)
290 return MalformedOpcode(0x02);
292 if ((challoc - ch_size) < 4)
295 if (!(eattr & DEFINED))
297 fixup((WORD)(FU_WORD | attrflg), sloc, r_expr);
302 if ((int)eval < reg1 || (int)eval > reg2)
304 error("constant out of range");
310 else if (type == RI_NUM_32)
311 reg1 = (reg1 == 32 ? 0 : eval);
317 reg2 = GetRegister(FU_REGTWO);
319 BuildRISCIntructionWord(parm, reg1, reg2);
322 // Move Immediate--n,Rn--n in Second Word
325 return MalformedOpcode(0x03);
329 if (expr(r_expr, &eval, &eattr, &esym) != OK)
330 return MalformedOpcode(0x04);
332 if (lastOpcode == RI_JUMP || lastOpcode == RI_JR)
336 // User doesn't care, emit a NOP to fix
337 BuildRISCIntructionWord(57, 0, 0);
338 warn("MOVEI following JUMP, inserting NOP to fix your BROKEN CODE");
341 warn("MOVEI immediately follows JUMP");
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(0x05);
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(0x06);
466 if ((challoc - ch_size) < 4)
469 if (!(eattr & DEFINED))
471 error("constant expected after '+'");
479 reg1 = 14 + (parm - 58);
481 warn("NULL offset in LOAD ignored");
485 if (reg1 < 1 || reg1 > 32)
487 error("constant in LOAD out of range");
494 parm = (WORD)(parm - 58 + 43);
500 reg1 = GetRegister(FU_REGONE);
505 return MalformedOpcode(0x07);
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(0x08);
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(0x09);
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 in STORE ignored");
613 if (reg2 < 1 || reg2 > 32)
615 error("constant in STORE out of range");
622 parm = (WORD)(parm - 60 + 49);
629 reg2 = GetRegister(FU_REGTWO);
634 return MalformedOpcode(0x0A);
638 BuildRISCIntructionWord(parm, reg2, reg1);
641 // LOADB/LOADP/LOADW (Rn),Rn
644 return MalformedOpcode(0x0B);
647 reg1 = GetRegister(FU_REGONE);
650 return MalformedOpcode(0x0C);
654 reg2 = GetRegister(FU_REGTWO);
656 BuildRISCIntructionWord(parm, reg1, reg2);
659 // STOREB/STOREP/STOREW Rn,(Rn)
661 reg1 = GetRegister(FU_REGONE);
665 return MalformedOpcode(0x0D);
668 reg2 = GetRegister(FU_REGTWO);
671 return MalformedOpcode(0x0E);
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(0x0F);
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(0x10);
795 reg2 = GetRegister(FU_REGTWO);
798 return MalformedOpcode(0x11);
802 BuildRISCIntructionWord(parm, reg2, reg1);
807 // Should never get here :-D
809 error("Unknown risc opcode type");