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 if (!(eattr & DEFINED))
176 fixup((WORD)(FU_WORD | rattr), sloc, r_expr);
180 // If we got a register in range (0-31), return it
181 if ((eval >= 0) && (eval <= 31))
184 // Otherwise, it's out of range & we flag an error
191 // Do RISC Code Generation
193 int GenerateRISCCode(int state)
195 int reg1; // Register 1
196 int reg2; // Register 2
197 int val = 0; // Constructed value
205 int indexed; // Indexed register flag
207 VALUE eval; // Expression value
208 WORD eattr; // Expression attributes
209 SYM * esym; // External symbol involved in expr.
210 TOKEN r_expr[EXPRSIZE]; // Expression token list
212 // Get opcode parameter and type
213 unsigned short parm = (WORD)(roptbl[state - 3000].parm);
214 unsigned type = roptbl[state - 3000].typ;
216 // Detect whether the opcode parmeter passed determines that the opcode is
217 // specific to only one of the RISC processors and ensure it is legal in
218 // the current code section. If not then show error and return.
219 if (((parm & GPUONLY) && rdsp) || ((parm & DSPONLY) && rgpu))
221 error("Opcode is not valid in this code section");
225 // Process RISC opcode
228 // No operand instructions
231 BuildRISCIntructionWord(parm, 0, 0);
234 // Single operand instructions (Rd)
235 // ABS, MIRROR, NEG, NOT, PACK, RESMAC, SAT8, SAT16, SAT16S, SAT24, SAT32S, UNPACK
237 reg2 = GetRegister(FU_REGTWO);
239 BuildRISCIntructionWord(parm, parm >> 6, reg2);
242 // Two operand instructions (Rs,Rd)
243 // ADD, ADDC, AND, CMP, DIV, IMACN, IMULT, IMULTN, MOVEFA, MOVETA, MULT, MMULT,
244 // MTOI, NORMI, OR, ROR, SH, SHA, SUB, SUBC, XOR
247 altbankok = 1; // MOVEFA
249 reg1 = GetRegister(FU_REGONE);
253 altbankok = 1; // MOVETA
255 reg2 = GetRegister(FU_REGTWO);
257 BuildRISCIntructionWord(parm, reg1, reg2);
260 // Numeric operand (n,Rd) where n = -16..+15
264 // Numeric operand (n,Rd) where n = 0..31
265 // BCLR, BSET, BTST, MOVEQ
268 // Numeric operand (n,Rd) where n = 1..32
269 // ADDQ, ADDQMOD, ADDQT, SHARQ, SHLQ, SHRQ, SUBQ, SUBQMOD, SUBQT, ROLQ, RORQ
274 reg1 = -16; reg2 = 15; attrflg = FU_NUM15;
278 reg1 = 0; reg2 = 31; attrflg = FU_NUM31;
281 reg1 = 1; reg2 = 32; attrflg = FU_NUM32;
289 return MalformedOpcode();
293 if (expr(r_expr, &eval, &eattr, &esym) != OK)
294 return MalformedOpcode();
296 if ((challoc - ch_size) < 4)
299 if (!(eattr & DEFINED))
301 fixup((WORD)(FU_WORD | attrflg), sloc, r_expr);
306 if ((int)eval < reg1 || (int)eval > reg2)
308 error("constant out of range");
314 else if (type == RI_NUM_32)
315 reg1 = (reg1 == 32 ? 0 : eval);
321 reg2 = GetRegister(FU_REGTWO);
323 BuildRISCIntructionWord(parm, reg1, reg2);
326 // Move Immediate--n,Rn--n in Second Word
329 return MalformedOpcode();
333 if (expr(r_expr, &eval, &eattr, &esym) != OK)
334 return MalformedOpcode();
336 if ((challoc - ch_size) < 4)
339 if (!(eattr & DEFINED))
341 fixup(FU_LONG | FU_MOVEI, sloc + 2, r_expr);
347 rmark(cursect, sloc + 2, tdb, MLONG | MMOVEI, NULL);
351 val = ((eval >> 16) & 0x0000FFFF) | ((eval << 16) & 0xFFFF0000);
352 // tok++; // assuming a comma here? tsk tsk
354 reg2 = GetRegister(FU_REGTWO);
356 D_word((((parm & 0x3F) << 10) + reg2));
371 reg1 = GetRegister(FU_REGONE);
375 reg2 = GetRegister(FU_REGTWO);
377 BuildRISCIntructionWord(parm, reg1, reg2);
380 // (Rn),Rn = 41 / (R14/R15+n),Rn = 43/44 / (R14/R15+Rn),Rn = 58/59
386 return MalformedOpcode();
390 if ((*tok == KW_R14 || *tok == KW_R15) && (*(tok + 1) != ')'))
391 indexed = (*tok - KW_R0);
395 // sy = lookup((char *)tok[1], LABEL, 0);
396 sy = lookup(string[tok[1]], LABEL, 0);
404 if (sy->sattre & EQUATEDREG)
406 if (((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15)
407 && (*(tok + 2) != ')'))
409 indexed = (sy->svalue & 0x1F);
417 reg1 = GetRegister(FU_REGONE);
427 parm = (WORD)(reg1 - 14 + 58);
430 if (*tok >= KW_R0 && *tok <= KW_R31)
435 // sy = lookup((char *)tok[1], LABEL, 0);
436 sy = lookup(string[tok[1]], LABEL, 0);
444 if (sy->sattre & EQUATEDREG)
450 reg1 = GetRegister(FU_REGONE);
454 if (expr(r_expr, &eval, &eattr, &esym) != OK)
455 return MalformedOpcode();
457 if ((challoc - ch_size) < 4)
460 if (!(eattr & DEFINED))
462 error("constant expected");
470 reg1 = 14 + (parm - 58);
472 warn("NULL offset removed");
476 if (reg1 < 1 || reg1 > 32)
478 error("constant out of range");
485 parm = (WORD)(parm - 58 + 43);
491 reg1 = GetRegister(FU_REGONE);
496 return MalformedOpcode();
500 reg2 = GetRegister(FU_REGTWO);
502 BuildRISCIntructionWord(parm, reg1, reg2);
505 // Rn,(Rn) = 47 / Rn,(R14/R15+n) = 49/50 / Rn,(R14/R15+Rn) = 60/61
508 reg1 = GetRegister(FU_REGONE);
512 return MalformedOpcode();
517 if ((*tok == KW_R14 || *tok == KW_R15) && (*(tok + 1) != ')'))
518 indexed = (*tok - KW_R0);
522 // sy = lookup((char *)tok[1], LABEL, 0);
523 sy = lookup(string[tok[1]], LABEL, 0);
531 if (sy->sattre & EQUATEDREG)
533 if (((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15)
534 && (*(tok + 2) != ')'))
536 indexed = (sy->svalue & 0x1F);
544 reg2 = GetRegister(FU_REGTWO);
554 parm = (WORD)(reg2 - 14 + 60);
557 if (*tok >= KW_R0 && *tok <= KW_R31)
562 // sy = lookup((char *)tok[1], LABEL, 0);
563 sy = lookup(string[tok[1]], LABEL, 0);
571 if (sy->sattre & EQUATEDREG)
577 reg2 = GetRegister(FU_REGTWO);
581 if (expr(r_expr, &eval, &eattr, &esym) != OK)
582 return MalformedOpcode();
584 if ((challoc - ch_size) < 4)
587 if (!(eattr & DEFINED))
589 fixup(FU_WORD | FU_REGTWO, sloc, r_expr);
598 reg2 = 14 + (parm - 60);
600 warn("NULL offset removed");
604 if (reg2 < 1 || reg2 > 32)
606 error("constant out of range");
613 parm = (WORD)(parm - 60 + 49);
620 reg2 = GetRegister(FU_REGTWO);
625 return MalformedOpcode();
629 BuildRISCIntructionWord(parm, reg2, reg1);
632 // LOADB/LOADP/LOADW (Rn),Rn
635 return MalformedOpcode();
638 reg1 = GetRegister(FU_REGONE);
641 return MalformedOpcode();
645 reg2 = GetRegister(FU_REGTWO);
647 BuildRISCIntructionWord(parm, reg1, reg2);
650 // STOREB/STOREP/STOREW Rn,(Rn)
652 reg1 = GetRegister(FU_REGONE);
656 return MalformedOpcode();
659 reg2 = GetRegister(FU_REGTWO);
662 return MalformedOpcode();
666 BuildRISCIntructionWord(parm, reg2, reg1);
669 // Jump Relative - cc,n - n=-16..+15 words, reg2=cc
672 // Jump Absolute - cc,(Rs) - reg2=cc
674 // Check to see if there is a comma in the token string. If not then
675 // the JR or JUMP should default to 0, Jump Always
678 for(t=tok; *t!=EOL; t++)
691 // CC using a constant number
697 else if (*tok == SYMBOL)
700 // strcpy(scratch, (char *)tok[1]);
701 strcpy(scratch, string[tok[1]]);
704 for(i=0; i<MAXINTERNCC; i++)
706 // Look for the condition code & break if found
707 if (strcmp(condname[i], scratch) == 0)
714 // Standard CC was not found, look for an equated one
717 // ccsym = lookup((char *)tok[1], LABEL, 0);
718 ccsym = lookup(string[tok[1]], LABEL, 0);
720 if (ccsym && (ccsym->sattre & EQUATEDCC) && !(ccsym->sattre & UNDEF_CC))
726 error("unknown condition code");
734 else if (*tok == '(')
736 // Set CC to "Jump Always"
742 // Set CC to "Jump Always"
746 if (val < 0 || val > 31)
748 error("condition constant out of range");
752 // Store condition code
758 if (expr(r_expr, &eval, &eattr, &esym) != OK)
759 return MalformedOpcode();
761 if ((challoc - ch_size) < 4)
764 if (!(eattr & DEFINED))
766 fixup(FU_WORD | FU_JR, sloc, r_expr);
775 reg2 = ((int)(val - (orgaddr + 2))) / 2;
777 reg2 = ((int)(val - (sloc + 2))) / 2;
779 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");