]> Shamusworld >> Repos - rmac/blob - riscasm.c
.equr overhaul part 3: store and handle banks in .equr evaluation
[rmac] / riscasm.c
1 //
2 // RMAC - Renamed Macro Assembler for all Atari computers
3 // RISCA.C - GPU/DSP Assembler
4 // Copyright (C) 199x Landon Dyer, 2011-2021 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
7 //
8
9 #include "riscasm.h"
10 #include "amode.h"
11 #include "direct.h"
12 #include "error.h"
13 #include "expr.h"
14 #include "mark.h"
15 #include "procln.h"
16 #include "rmac.h"
17 #include "sect.h"
18 #include "token.h"
19
20 #define DEF_MR                          // Declare keyword values
21 #include "risckw.h"                     // Incl. generated risc keywords
22
23 #define DEF_KW                          // Declare keyword values
24 #include "kwtab.h"                      // Incl. generated keyword tables & defs
25
26 #define MAXINTERNCC 26          // Maximum internal condition codes
27
28 // Useful macros
29 #define EVAL_REG_RETURN_IF_ERROR(x, y) \
30 x = EvaluateRegisterFromTokenStream(y); \
31 \
32 if (x == ERROR) \
33         return ERROR;
34
35 #define EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(x, y) \
36 x = EvaluateRegisterFromTokenStream(y); \
37 \
38 if ((x == ERROR) || (ErrorIfNotAtEOL() == ERROR)) \
39         return ERROR;
40
41 #define CHECK_EOL \
42 if (ErrorIfNotAtEOL() == ERROR) \
43         return ERROR;
44
45 unsigned altbankok = 0;         // Ok to use alternate register bank
46 unsigned orgactive = 0;         // RISC/6502 org directive active
47 unsigned orgaddr = 0;           // Org'd address
48 unsigned orgwarning = 0;        // Has an ORG warning been issued
49 int lastOpcode = -1;            // Last RISC opcode assembled
50 uint8_t riscImmTokenSeen;       // The '#' (immediate) token was seen
51
52 static const char reg_err[] = "missing register R0...R31";
53
54 // Jaguar jump condition names
55 static const char condname[MAXINTERNCC][5] = {
56         "NZ", "Z", "NC", "NCNZ", "NCZ", "C", "CNZ", "CZ", "NN", "NNNZ", "NNZ",
57         "N", "N_NZ", "N_Z", "T", "A", "NE", "EQ", "CC", "HS", "HI", "CS", "LO",
58         "PL", "MI", "F"
59 };
60
61 // Jaguar jump condition numbers
62 static const char condnumber[] = {
63         1, 2, 4, 5, 6, 8, 9, 10, 20, 21, 22, 24, 25, 26,
64         0, 0, 1, 2, 4, 4, 5,  8,  8, 20, 24, 31
65 };
66
67 // Opcode Specific Data
68 struct opcoderecord {
69         uint16_t state;         // Opcode Name (unused)
70         uint16_t type;          // Opcode Type
71         uint16_t param;         // Opcode Parameter
72 };
73
74 static const struct opcoderecord roptbl[] = {
75         { MR_ADD,     RI_TWO,    0 },
76         { MR_ADDC,    RI_TWO,    1 },
77         { MR_ADDQ,    RI_NUM_32, 2 },
78         { MR_ADDQT,   RI_NUM_32, 3 },
79         { MR_SUB,     RI_TWO,    4 },
80         { MR_SUBC,    RI_TWO,    5 },
81         { MR_SUBQ,    RI_NUM_32, 6 },
82         { MR_SUBQT,   RI_NUM_32, 7 },
83         { MR_NEG,     RI_ONE,    8 },
84         { MR_AND,     RI_TWO,    9 },
85         { MR_OR,      RI_TWO,    10 },
86         { MR_XOR,     RI_TWO,    11 },
87         { MR_NOT,     RI_ONE,    12 },
88         { MR_BTST,    RI_NUM_31, 13 },
89         { MR_BSET,    RI_NUM_31, 14 },
90         { MR_BCLR,    RI_NUM_31, 15 },
91         { MR_MULT,    RI_TWO,    16 },
92         { MR_IMULT,   RI_TWO,    17 },
93         { MR_IMULTN,  RI_TWO,    18 },
94         { MR_RESMAC,  RI_ONE,    19 },
95         { MR_IMACN,   RI_TWO,    20 },
96         { MR_DIV,     RI_TWO,    21 },
97         { MR_ABS,     RI_ONE,    22 },
98         { MR_SH,      RI_TWO,    23 },
99         { MR_SHLQ,    RI_NUM_32, 24 + SUB32 },
100         { MR_SHRQ,    RI_NUM_32, 25 },
101         { MR_SHA,     RI_TWO,    26 },
102         { MR_SHARQ,   RI_NUM_32, 27 },
103         { MR_ROR,     RI_TWO,    28 },
104         { MR_RORQ,    RI_NUM_32, 29 },
105         { MR_ROLQ,    RI_NUM_32, 29 + SUB32 },
106         { MR_CMP,     RI_TWO,    30 },
107         { MR_CMPQ,    RI_NUM_15, 31 },
108         { MR_SAT8,    RI_ONE,    32 + GPUONLY },
109         { MR_SUBQMOD, RI_NUM_32, 32 + DSPONLY },
110         { MR_SAT16,   RI_ONE,    33 + GPUONLY },
111         { MR_SAT16S,  RI_ONE,    33 + DSPONLY },
112         { MR_MOVEQ,   RI_NUM_31, 35 },
113         { MR_MOVETA,  RI_TWO,    36 },
114         { MR_MOVEFA,  RI_TWO,    37 },
115         { MR_MOVEI,   RI_MOVEI,  38 },
116         { MR_LOADB,   RI_LOADN,  39 },
117         { MR_LOADW,   RI_LOADN,  40 },
118         { MR_LOADP,   RI_LOADN,  42 + GPUONLY },
119         { MR_SAT32S,  RI_ONE,    42 + DSPONLY },
120         { MR_STOREB,  RI_STOREN, 45 },
121         { MR_STOREW,  RI_STOREN, 46 },
122         { MR_STOREP,  RI_STOREN, 48 + GPUONLY },
123         { MR_MIRROR,  RI_ONE,    48 + DSPONLY },
124         { MR_JUMP,    RI_JUMP,   52 },
125         { MR_JR,      RI_JR,     53 },
126         { MR_MMULT,   RI_TWO,    54 },
127         { MR_MTOI,    RI_TWO,    55 },
128         { MR_NORMI,   RI_TWO,    56 },
129         { MR_NOP,     RI_NONE,   57 },
130         { MR_SAT24,   RI_ONE,    62 },
131         { MR_UNPACK,  RI_ONE,    63 + GPUONLY | (0 << 6) },
132         { MR_PACK,    RI_ONE,    63 + GPUONLY | (1 << 6) },
133         { MR_ADDQMOD, RI_NUM_32, 63 + DSPONLY },
134         { MR_MOVE,    RI_MOVE,   0 },
135         { MR_LOAD,    RI_LOAD,   0 },
136         { MR_STORE,   RI_STORE,  0 }
137 };
138
139 #define MALF_NUM                0
140 #define MALF_EXPR               1
141 #define MALF_LPAREN             2
142 #define MALF_RPAREN             3
143
144 static const char malform1[] = "missing '#'";
145 static const char malform2[] = "bad expression";
146 static const char malform3[] = "missing ')'";
147 static const char malform4[] = "missing '('";
148
149 static const char * malformErr[] = {
150         malform1, malform2, malform3, malform4
151 };
152
153 //
154 // Function to return "malformed expression" error
155 // This is done mainly to remove a bunch of GOTO statements in the parser
156 //
157 static inline int MalformedOpcode(int signal)
158 {
159         return error("Malformed opcode, %s", malformErr[signal]);
160 }
161
162 //
163 // Function to return "Illegal Indexed Register" error
164 // Anyone trying to index something other than R14 or R15
165 //
166 static inline int IllegalIndexedRegister(int reg)
167 {
168         return error("Attempted index reference with non-indexable register (r%d)", reg - KW_R0);
169 }
170
171 //
172 // Function to return "Illegal Indexed Register" error for EQUR scenarios
173 // Trying to use register value within EQUR that isn't 14 or 15
174 //
175 static inline int IllegalIndexedRegisterEqur(SYM * sy)
176 {
177         return error("Attempted index reference with non-indexable register within EQUR (%s = r%d)", sy->sname, sy->svalue);
178 }
179
180 //
181 // Build up & deposit RISC instruction word
182 //
183 static void DepositRISCInstructionWord(uint16_t opcode, int reg1, int reg2)
184 {
185         // Check for absolute address setting
186         if (!orgwarning && !orgactive)
187         {
188                 warn("RISC code generated with no origin defined");
189                 orgwarning = 1;
190         }
191
192         int value = ((opcode & 0x3F) << 10) + ((reg1 & 0x1F) << 5) + (reg2 & 0x1F);
193         D_word(value);
194 }
195
196 //
197 // Evaluate the RISC register from the token stream. Passed in value is the
198 // FIXUP attribute to use if the expression comes back as undefined.
199 //
200 static int EvaluateRegisterFromTokenStream(uint32_t fixup)
201 {
202         // Firstly, check to see if it's a register token and return that.  No
203         // need to invoke expr() for easy cases like this.
204         int reg = *tok & 255;
205         if (reg >= KW_R0 && reg <= KW_R31)
206         {
207                 // Check register bank usage in the case of .equr register
208                 // (encoded as bits 30 and 31 in *tok).
209                 // (I still think that this is superfluous and should be taken out, see my note in token.c)
210                 if (*tok & 0x80000000)
211                 {
212                         // Oops, with all the evaluation in token.c we now lost the equated symbol reference, so we
213                         // don't know its name or anything else. Oh well...
214                         if ((regbank == BANK_0) && (*tok & 0x40000000) && !altbankok)
215                                 return error("equated symbol cannot be used in register bank 0");
216
217                         if ((regbank == BANK_1) && !(*tok & 0x40000000) && !altbankok)
218                                 return error("equated symbol cannot be used in register bank 1");
219                 }
220                 reg -= KW_R0;
221                 tok++;
222                 return reg;
223         }
224
225         if (*tok != SYMBOL)
226         {
227                 // If at this point we don't have a symbol then it's garbage.  Punt.
228                 return error("Expected register number or EQUREG");
229         }
230
231         uint64_t eval;                          // Expression value
232         WORD eattr;                                     // Expression attributes
233         SYM * esym;                                     // External symbol involved in expr.
234         TOKEN r_expr[EXPRSIZE];         // Expression token list
235
236         // Evaluate what's in the global "tok" buffer
237         // N.B.: We should either get a fixup or a register name from EQUR
238         if (expr(r_expr, &eval, &eattr, &esym) != OK)
239                 return ERROR;
240
241         if (!(eattr & DEFINED))
242         {
243                 AddFixup(FU_WORD | fixup, sloc, r_expr);
244                 return 0;
245         }
246
247         // We shouldn't get here, that should not be legal
248         interror(9);
249
250         // If we got a register in range (0-31), return it
251         //if (eattr & RISCREG)
252         //      return (int)eval - KW_R0;
253
254         //// Otherwise, it's out of range & we flag an error
255         //return error(reg_err);
256 }
257
258 //
259 // Do RISC code generation
260 //
261 int GenerateRISCCode(int state)
262 {
263         int reg1;                                       // Register 1
264         int reg2;                                       // Register 2
265         int val = 0;                            // Constructed value
266         char scratch[80];
267         SYM * ccsym;
268         SYM * sy;
269         int i, commaFound;
270         TOKEN * t;
271         uint16_t attrflg;
272         int indexed;                            // Indexed register flag
273
274         uint64_t eval;                          // Expression value
275         uint16_t eattr;                         // Expression attributes
276         SYM * esym = NULL;                      // External symbol involved in expr.
277         TOKEN r_expr[EXPRSIZE];         // Expression token list
278
279         // Get opcode parameter and type
280         uint16_t parm = roptbl[state - 3000].param;
281         uint16_t type = roptbl[state - 3000].type;
282         riscImmTokenSeen = 0;           // Set to "token not seen yet"
283
284         // Detect whether the opcode parmeter passed determines that the opcode is
285         // specific to only one of the RISC processors and ensure it is legal in
286         // the current code section. If not then show error and return.
287         if (((parm & GPUONLY) && rdsp) || ((parm & DSPONLY) && rgpu))
288                 return error("Opcode is not valid in this code section");
289
290         // Process RISC opcode
291         switch (type)
292         {
293         // No operand instructions
294         // NOP (57)
295         case RI_NONE:
296                 DepositRISCInstructionWord(parm, 0, 0);
297                 break;
298
299         // Single operand instructions (Rd)
300         // ABS, MIRROR, NEG, NOT, PACK, RESMAC, SAT8, SAT16, SAT16S, SAT24, SAT32S,
301         // UNPACK
302         case RI_ONE:
303                 EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
304                 DepositRISCInstructionWord(parm, parm >> 6, reg2);
305                 break;
306
307         // Two operand instructions (Rs,Rd)
308         // ADD, ADDC, AND, CMP, DIV, IMACN, IMULT, IMULTN, MOVEFA, MOVETA, MULT,
309         // MMULT, MTOI, NORMI, OR, ROR, SH, SHA, SUB, SUBC, XOR
310         case RI_TWO:
311                 if (parm == 37)
312                         altbankok = 1;                      // MOVEFA
313
314                 EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
315                 CHECK_COMMA;
316
317                 if (parm == 36)
318                         altbankok = 1;                      // MOVETA
319
320                 EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
321                 DepositRISCInstructionWord(parm, reg1, reg2);
322                 break;
323
324         // Numeric operand (n,Rd) where n = -16..+15
325         // CMPQ
326         case RI_NUM_15:
327
328         // Numeric operand (n,Rd) where n = 0..31
329         // BCLR, BSET, BTST, MOVEQ
330         case RI_NUM_31:
331
332         // Numeric operand (n,Rd) where n = 1..32
333         // ADDQ, ADDQMOD, ADDQT, SHARQ, SHLQ, SHRQ, SUBQ, SUBQMOD, SUBQT, ROLQ,
334         // RORQ
335         case RI_NUM_32:
336                 switch (type)
337                 {
338                 case RI_NUM_15:
339                         reg1 = -16; reg2 = 15; attrflg = FU_NUM15;
340                         break;
341                 default:
342                 case RI_NUM_31:
343                         reg1 =   0; reg2 = 31; attrflg = FU_NUM31;
344                         break;
345                 case RI_NUM_32:
346                         reg1 =   1; reg2 = 32; attrflg = FU_NUM32;
347                         break;
348                 }
349
350                 if (parm & SUB32)
351                         attrflg |= FU_SUB32;
352
353                 if (*tok != '#')
354                         return MalformedOpcode(MALF_NUM);
355
356                 tok++;
357                 riscImmTokenSeen = 1;
358
359                 if (expr(r_expr, &eval, &eattr, &esym) != OK)
360                         return MalformedOpcode(MALF_EXPR);
361
362                 if (!(eattr & DEFINED))
363                 {
364                         AddFixup((WORD)(FU_WORD | attrflg), sloc, r_expr);
365                         reg1 = 0;
366                 }
367                 else
368                 {
369                         if (esym && (esym->sattre & EQUATEDREG))
370                                 return error("equated register seen for immediate value");
371
372                         if (eattr & RISCREG)
373                                 return error("register seen for immediate value");
374
375                         if (((int)eval < reg1) || ((int)eval > reg2))
376                                 return error("constant out of range (%d to %d)", reg1, reg2);
377
378                         if (parm & SUB32)
379                                 reg1 = 32 - (int)eval;
380                         else if (type == RI_NUM_32)
381                                 reg1 = (reg1 == 32 ? 0 : (int)eval);
382                         else
383                                 reg1 = (int)eval;
384                 }
385
386                 CHECK_COMMA;
387                 EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
388                 DepositRISCInstructionWord(parm, reg1, reg2);
389                 break;
390
391         // Move Immediate--n,Rn--n in Second Word
392         case RI_MOVEI:
393                 if (*tok != '#')
394                         return MalformedOpcode(MALF_NUM);
395
396                 tok++;
397                 riscImmTokenSeen = 1;
398
399                 // Check for equated register after # and return error if so
400                 if (*tok == SYMBOL)
401                 {
402                         sy = lookup(string[tok[1]], LABEL, 0);
403
404                         if (sy && (sy->sattre & EQUATEDREG))
405                                 return error("equated register in 1st operand of MOVEI instruction");
406                 }
407
408                 if (expr(r_expr, &eval, &eattr, &esym) != OK)
409                         return MalformedOpcode(MALF_EXPR);
410
411                 if ((lastOpcode == RI_JUMP) || (lastOpcode == RI_JR))
412                 {
413                         if (legacy_flag)
414                         {
415                                 // User doesn't care, emit a NOP to fix
416                                 DepositRISCInstructionWord(57, 0, 0);
417                                 warn("MOVEI following JUMP, inserting NOP to fix your BROKEN CODE");
418                         }
419                         else
420                                 warn("MOVEI immediately follows JUMP");
421                 }
422
423                 if (!(eattr & DEFINED))
424                 {
425                         AddFixup(FU_LONG | FU_MOVEI, sloc + 2, r_expr);
426                         eval = 0;
427                 }
428                 else
429                 {
430                         if (eattr & TDB)
431                                 MarkRelocatable(cursect, sloc + 2, (eattr & TDB), (MLONG | MMOVEI), NULL);
432                 }
433
434                 CHECK_COMMA;
435                 EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
436
437                 DepositRISCInstructionWord(parm, 0, reg2);
438                 val = WORDSWAP32(eval);
439                 D_long(val);
440                 break;
441
442         // PC,Rd or Rs,Rd
443         case RI_MOVE:
444                 if (*tok == KW_PC)
445                 {
446                         parm = 51;
447                         reg1 = 0;
448                         tok++;
449                 }
450                 else
451                 {
452                         parm = 34;
453                         EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
454                 }
455
456                 CHECK_COMMA;
457                 EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
458                 DepositRISCInstructionWord(parm, reg1, reg2);
459                 break;
460
461         // (Rn),Rn = 41 / (R14/R15+n),Rn = 43/44 / (R14/R15+Rn),Rn = 58/59
462         case RI_LOAD:
463                 indexed = 0;
464                 parm = 41;
465
466                 if (*tok != '(')
467                         return MalformedOpcode(MALF_LPAREN);
468
469                 tok++;
470
471         if ((tok[1] == '+') || (tok[1] == '-'))
472                 {
473                         // Trying to make indexed call
474                         // Note: no bank check for .equr symbol here, but the original code for .equr
475                         //       below also didn't check for banks. Even more reasons to throw away
476                         //       bank checks.
477                         if (((*tok & 0xff) == KW_R14) || ((*tok &0xff) == KW_R15))
478                                 indexed = ((*tok & 0xff) - KW_R0);
479                         else
480                                 return IllegalIndexedRegister(*tok);
481                 }
482
483                 //if (*tok == SYMBOL)
484                 //{
485                 //      sy = lookup(string[tok[1]], LABEL, 0);
486                 //
487                 //      if (!sy)
488                 //      {
489                 //              error(reg_err);
490                 //              return ERROR;
491                 //      }
492                 //
493                 //      if (sy->sattre & EQUATEDREG)
494                 //      {
495                 //              if ((tok[2] == '+') || (tok[2] == '-'))
496                 //              {
497                 //                      if ((sy->svalue - KW_R0) == 14 || (sy->svalue - KW_R0) == 15) {
498                 //                              indexed = (sy->svalue - KW_R0);
499                 //                              tok++;
500                 //                      }
501                 //                      else
502                 //                              return IllegalIndexedRegisterEqur(sy);
503                 //              }
504                 //      }
505                 //}
506
507                 if (!indexed)
508                 {
509                         EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
510                 }
511                 else
512                 {
513                         reg1 = indexed;
514                         indexed = 0;
515                         tok++;
516
517                         if (*tok == '+')
518                         {
519                                 parm = (WORD)(reg1 - 14 + 58);
520                                 tok++;
521
522                                 if (((*tok & 0xff) >= KW_R0) && ((*tok & 0xff) <= KW_R31))
523                                         indexed = 1;
524
525                                 if (*tok == SYMBOL)
526                                 {
527                                         sy = lookup(string[tok[1]], LABEL, 0);
528
529                                         if (!sy)
530                                         {
531                                                 error(reg_err);
532                                                 return ERROR;
533                                         }
534
535                                         if (sy->sattre & EQUATEDREG)
536                                                 indexed = 1;
537                                 }
538
539                                 if (indexed)
540                                 {
541                                         EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
542                                 }
543                                 else
544                                 {
545                                         if (expr(r_expr, &eval, &eattr, &esym) != OK)
546                                                 return MalformedOpcode(MALF_EXPR);
547
548                                         if (!(eattr & DEFINED))
549                                                 return error("constant expected after '+'");
550
551                                         reg1 = (int)eval;
552
553                                         if (reg1 == 0)
554                                         {
555                                                 reg1 = 14 + (parm - 58);
556                                                 parm = 41;
557                                                 warn("NULL offset in LOAD ignored");
558                                         }
559                                         else
560                                         {
561                                                 if ((reg1 < 1) || (reg1 > 32))
562                                                         return error("constant in LOAD out of range (1-32)");
563
564                                                 if (reg1 == 32)
565                                                         reg1 = 0;
566
567                                                 parm = (WORD)(parm - 58 + 43);
568                                         }
569                                 }
570                         }
571                         else
572                         {
573                                 EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
574                         }
575                 }
576
577                 if (*tok != ')')
578                         return MalformedOpcode(MALF_RPAREN);
579
580                 tok++;
581                 CHECK_COMMA;
582                 EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
583                 DepositRISCInstructionWord(parm, reg1, reg2);
584                 break;
585
586         // Rn,(Rn) = 47 / Rn,(R14/R15+n) = 49/50 / Rn,(R14/R15+Rn) = 60/61
587         case RI_STORE:
588                 parm = 47;
589                 EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
590                 CHECK_COMMA;
591
592                 if (*tok != '(')
593                         return MalformedOpcode(MALF_LPAREN);
594
595                 tok++;
596                 indexed = 0;
597
598                 // Again, no bank checks here or in the original code.
599                 // This check has more holes than a very hole-y thing.
600                 if ((((*tok & 0xff) == KW_R14) || ((*tok & 0xff) == KW_R15)) && (tok[1] != ')'))
601                         indexed = (*tok & 0xff) - KW_R0;
602
603                 //if (*tok == SYMBOL)
604                 //{
605                 //      sy = lookup(string[tok[1]], LABEL, 0);
606                 //
607                 //      if (!sy)
608                 //      {
609                 //              error(reg_err);
610                 //              return ERROR;
611                 //      }
612                 //
613                 //      if (sy->sattre & EQUATEDREG)
614                 //      {
615                 //              if (((sy->svalue - KW_R0) == 14 || (sy->svalue - KW_R0) == 15)
616                 //                      && (tok[2] != ')'))
617                 //              {
618                 //                      indexed = (sy->svalue - KW_R0);
619                 //                      tok++;
620                 //              }
621                 //      }
622                 //}
623
624                 if (!indexed)
625                 {
626                         EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
627                 }
628                 else
629                 {
630                         reg2 = indexed;
631                         indexed = 0;
632                         tok++;
633
634                         if (*tok == '+')
635                         {
636                                 parm = (WORD)(reg2 - 14 + 60);
637                                 tok++;
638
639                                 if (((*tok & 0xff) >= KW_R0) && ((*tok & 0xff) <= KW_R31))
640                                         indexed = 1;
641
642                                 if (*tok == SYMBOL)
643                                 {
644                                         sy = lookup(string[tok[1]], LABEL, 0);
645
646                                         if (!sy)
647                                         {
648                                                 error(reg_err);
649                                                 return ERROR;
650                                         }
651
652                                         if (sy->sattre & EQUATEDREG)
653                                                 indexed = 1;
654                                 }
655
656                                 if (indexed)
657                                 {
658                                         EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
659                                 }
660                                 else
661                                 {
662                                         if (expr(r_expr, &eval, &eattr, &esym) != OK)
663                                                 return MalformedOpcode(MALF_EXPR);
664
665                                         if (!(eattr & DEFINED))
666                                         {
667                                                 AddFixup(FU_WORD | FU_REGTWO, sloc, r_expr);
668                                                 reg2 = 0;
669                                         }
670                                         else
671                                         {
672                                                 reg2 = (int)eval;
673
674                                                 if (reg2 == 0)
675                                                 {
676                                                         reg2 = 14 + (parm - 60);
677                                                         parm = 47;
678                                                         warn("NULL offset in STORE ignored");
679                                                 }
680                                                 else
681                                                 {
682                                                         if ((reg2 < 1) || (reg2 > 32))
683                                                                 return error("constant in STORE out of range (1-32)");
684
685                                                         if (reg2 == 32)
686                                                                 reg2 = 0;
687
688                                                         parm = (WORD)(parm - 60 + 49);
689                                                 }
690                                         }
691                                 }
692                         }
693                         else
694                         {
695                                 EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
696                         }
697                 }
698
699                 if (*tok != ')')
700                         return MalformedOpcode(MALF_RPAREN);
701
702                 tok++;
703                 CHECK_EOL;
704                 DepositRISCInstructionWord(parm, reg2, reg1);
705                 break;
706
707         // LOADB/LOADP/LOADW (Rn),Rn
708         case RI_LOADN:
709                 if (*tok != '(')
710                         return MalformedOpcode(MALF_LPAREN);
711
712                 tok++;
713                 EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
714
715                 if (*tok != ')')
716                         return MalformedOpcode(MALF_RPAREN);
717
718                 tok++;
719                 CHECK_COMMA;
720                 EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
721                 DepositRISCInstructionWord(parm, reg1, reg2);
722                 break;
723
724         // STOREB/STOREP/STOREW Rn,(Rn)
725         case RI_STOREN:
726                 EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
727                 CHECK_COMMA;
728
729                 if (*tok != '(')
730                         return MalformedOpcode(MALF_LPAREN);
731
732                 tok++;
733                 EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
734
735                 if (*tok != ')')
736                         return MalformedOpcode(MALF_RPAREN);
737
738                 tok++;
739                 CHECK_EOL;
740                 DepositRISCInstructionWord(parm, reg2, reg1);
741                 break;
742
743         // Jump Relative - cc,n - n=-16..+15 words, reg2=cc
744         case RI_JR:
745
746         // Jump Absolute - cc,(Rs) - reg2=cc
747         case RI_JUMP:
748                 // Check to see if there is a comma in the token string. If not then
749                 // the JR or JUMP should default to 0, Jump Always
750                 commaFound = 0;
751
752                 for(t=tok; *t!=EOL; t++)
753                 {
754                         if (*t == ',')
755                         {
756                                 commaFound = 1;
757                                 break;
758                         }
759                 }
760
761                 if (commaFound)
762                 {
763                         if (*tok == CONST)
764                         {
765                                 // CC using a constant number (O_o)
766                                 PTR tp;
767                                 tp.tk = tok + 1;
768                                 val = *tp.i64++;
769                                 tok = tp.tk;
770                                 CHECK_COMMA;
771                         }
772                         else if (*tok == SYMBOL)
773                         {
774                                 val = 9999;
775                                 strcpy(scratch, string[tok[1]]);
776                                 strtoupper(scratch);
777
778                                 for(i=0; i<MAXINTERNCC; i++)
779                                 {
780                                         // Look for the condition code & break if found
781                                         if (strcmp(condname[i], scratch) == 0)
782                                         {
783                                                 val = condnumber[i];
784                                                 break;
785                                         }
786                                 }
787
788                                 // Standard CC was not found, look for an equated one
789                                 if (val == 9999)
790                                 {
791                                         ccsym = lookup(string[tok[1]], LABEL, 0);
792
793                                         if (ccsym && (ccsym->sattre & EQUATEDCC) && !(ccsym->sattre & UNDEF_CC))
794                                                 val = (int)ccsym->svalue;
795                                         else
796                                                 return error("unknown condition code");
797                                 }
798
799                                 tok += 2;
800                                 CHECK_COMMA;
801                         }
802                         else if (*tok == '(')
803                         {
804                                 // Set CC to "Jump Always"
805                                 val = 0;
806                         }
807                 }
808                 else
809                 {
810                         // Set CC to "Jump Always"
811                         val = 0;
812                 }
813
814                 if ((val < 0) || (val > 31))
815                         return error("condition constant out of range");
816
817                 // Store condition code
818                 reg1 = val;
819
820                 if (type == RI_JR)
821                 {
822                         // JR cc,n
823                         if (expr(r_expr, &eval, &eattr, &esym) != OK)
824                                 return MalformedOpcode(MALF_EXPR);
825
826                         if (!(eattr & DEFINED))
827                         {
828                                 AddFixup(FU_WORD | FU_JR, sloc, r_expr);
829                                 reg2 = 0;
830                         }
831                         else
832                         {
833                                 reg2 = ((int)(eval - ((orgactive ? orgaddr : sloc) + 2))) / 2;
834
835                                 if ((reg2 < -16) || (reg2 > 15))
836                                         error("PC relative overflow in JR (outside of -16 to 15)");
837                         }
838                 }
839                 else
840                 {
841                         // JUMP cc, (Rn)
842                         if (*tok != '(')
843                                 return MalformedOpcode(MALF_LPAREN);
844
845                         tok++;
846                         EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
847
848                         if (*tok != ')')
849                                 return MalformedOpcode(MALF_RPAREN);
850
851                         tok++;
852                         CHECK_EOL;
853                 }
854
855                 DepositRISCInstructionWord(parm, reg2, reg1);
856                 break;
857
858         // We should never get here. If we do, somebody done fucked up. :-D
859         default:
860                 return error("Unknown RISC opcode type");
861         }
862
863         lastOpcode = type;
864         return 0;
865 }