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
204 int indexed; // Indexed register flag
206 VALUE eval; // Expression value
207 WORD eattr; // Expression attributes
208 SYM * esym; // External symbol involved in expr.
209 TOKEN r_expr[EXPRSIZE]; // Expression token list
211 // Get opcode parameter and type
212 unsigned short parm = (WORD)(roptbl[state - 3000].parm);
213 unsigned type = roptbl[state - 3000].typ;
215 // Detect whether the opcode parmeter passed determines that the opcode is
216 // specific to only one of the RISC processors and ensure it is legal in
217 // the current code section. If not then show error and return.
218 if (((parm & GPUONLY) && rdsp) || ((parm & DSPONLY) && rgpu))
220 error("Opcode is not valid in this code section");
224 // Process RISC opcode
227 // No operand instructions
230 BuildRISCIntructionWord(parm, 0, 0);
233 // Single operand instructions (Rd)
234 // ABS, MIRROR, NEG, NOT, PACK, RESMAC, SAT8, SAT16, SAT16S, SAT24, SAT32S, UNPACK
236 reg2 = GetRegister(FU_REGTWO);
238 BuildRISCIntructionWord(parm, parm >> 6, reg2);
241 // Two operand instructions (Rs,Rd)
242 // ADD, ADDC, AND, CMP, DIV, IMACN, IMULT, IMULTN, MOVEFA, MOVETA, MULT, MMULT,
243 // MTOI, NORMI, OR, ROR, SH, SHA, SUB, SUBC, XOR
246 altbankok = 1; // MOVEFA
248 reg1 = GetRegister(FU_REGONE);
252 altbankok = 1; // MOVETA
254 reg2 = GetRegister(FU_REGTWO);
256 BuildRISCIntructionWord(parm, reg1, reg2);
259 // Numeric operand (n,Rd) where n = -16..+15
263 // Numeric operand (n,Rd) where n = 0..31
264 // BCLR, BSET, BTST, MOVEQ
267 // Numeric operand (n,Rd) where n = 1..32
268 // ADDQ, ADDQMOD, ADDQT, SHARQ, SHLQ, SHRQ, SUBQ, SUBQMOD, SUBQT, ROLQ, RORQ
273 reg1 = -16; reg2 = 15; attrflg = FU_NUM15;
277 reg1 = 0; reg2 = 31; attrflg = FU_NUM31;
280 reg1 = 1; reg2 = 32; attrflg = FU_NUM32;
288 return MalformedOpcode();
292 if (expr(r_expr, &eval, &eattr, &esym) != OK)
293 return MalformedOpcode();
295 if ((challoc - ch_size) < 4)
298 if (!(eattr & DEFINED))
300 fixup((WORD)(FU_WORD | attrflg), sloc, r_expr);
305 if ((int)eval < reg1 || (int)eval > reg2)
307 error("constant out of range");
313 else if (type == RI_NUM_32)
314 reg1 = (reg1 == 32 ? 0 : eval);
320 reg2 = GetRegister(FU_REGTWO);
322 BuildRISCIntructionWord(parm, reg1, reg2);
325 // Move Immediate--n,Rn--n in Second Word
328 return MalformedOpcode();
332 if (expr(r_expr, &eval, &eattr, &esym) != OK)
333 return MalformedOpcode();
335 if ((challoc - ch_size) < 4)
338 if (!(eattr & DEFINED))
340 fixup(FU_LONG | FU_MOVEI, sloc + 2, r_expr);
347 //printf("risca: Doing rmark for RI_MOVEI (tdb=$%X)...\n", eattr & TDB);
348 rmark(cursect, sloc + 2, (eattr & TDB), (MLONG | MMOVEI), NULL);
352 val = ((eval >> 16) & 0x0000FFFF) | ((eval << 16) & 0xFFFF0000);
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);
771 reg2 = ((int)(eval - ((orgactive ? orgaddr : sloc) + 2))) / 2;
773 if ((reg2 < -16) || (reg2 > 15))
774 error("PC relative overflow");
777 BuildRISCIntructionWord(parm, reg2, reg1);
783 return MalformedOpcode();
786 reg2 = GetRegister(FU_REGTWO);
789 return MalformedOpcode();
793 BuildRISCIntructionWord(parm, reg2, reg1);
798 // Should never get here :-D
800 error("Unknown risc opcode type");