]> Shamusworld >> Repos - rmac/blob - risca.c
f1d2ed64cba8824c9ee1d495589a703e8d38767b
[rmac] / risca.c
1 //
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
7 //
8
9 #include "risca.h"
10 #include "error.h"
11 #include "sect.h"
12 #include "token.h"
13 #include "expr.h"
14 #include "direct.h"
15 #include "mark.h"
16 #include "amode.h"
17
18 #define DEF_MR                                              // Declar keyword values
19 #include "risckw.h"                                         // Incl generated risc keywords
20
21 #define DEF_KW                                              // Declare keyword values 
22 #include "kwtab.h"                                          // Incl generated keyword tables & defs
23
24 unsigned altbankok = 0;                                     // Ok to use alternate register bank
25 unsigned orgactive = 0;                                     // RISC org directive active
26 unsigned orgaddr = 0;                                       // Org'd address
27 unsigned orgwarning = 0;                                    // Has an ORG warning been issued
28 int jpad = 0;
29 unsigned previousop = 0;                                    // Used for NOP padding checks
30 unsigned currentop = 0;                                     // Used for NOP padding checks
31 unsigned mjump_defined, mjump_dest;                         // mjump macro flags, values etc
32
33 char reg_err[] = "missing register R0...R31";
34
35 // Jaguar Jump Condition Names
36 char condname[MAXINTERNCC][5] = { 
37         "NZ", "Z", "NC", "NCNZ", "NCZ", "C", "CNZ", "CZ", "NN", "NNNZ", "NNZ",
38         "N", "N_NZ", "N_Z ", "T", "A", "NE", "EQ", "CC", "HS", "HI", "CS", "LO",
39         "PL", "MI", "F"
40 };
41
42 // Jaguar Jump Condition Numbers
43 char condnumber[] = {1, 2, 4, 5, 6, 8, 9, 10, 20, 21, 22, 24, 25, 26,
44                      0, 0, 1, 2, 4, 4, 5,  8,  8, 20, 24, 31};
45
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 },
97         { MR_JR,      RI_JR,     53 },
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 }
109 };
110
111
112 //
113 // Convert a String to Uppercase
114 //
115 void strtoupper(char * s)
116 {
117         while (*s)
118         {
119                 *s = (char)(toupper(*s));
120                 s++;
121         }
122 }
123
124
125 //
126 // Build RISC Instruction Word
127 //
128 void risc_instruction_word(unsigned short parm, int reg1, int reg2)
129 {
130         int value = 0xE400;
131
132         previousop = currentop;                                  // Opcode tracking for nop padding
133         currentop = parm;
134
135         if (!orgwarning)
136         {                                        // Check for absolute address setting
137                 if (!orgactive && !in_main)
138                 {
139                         warn("GPU/DSP code outside of absolute section");
140                         orgwarning = 1;
141                 }
142         }
143
144         if (jpad)
145         {                                               // JPAD directive
146                 //                JUMP                   JR                    NOP
147                 if (((previousop == 52) || (previousop == 53)) && (currentop != 57))
148                         D_word(value);                                     // Insert NOP
149         }
150         else
151         {
152                 //               JUMP                   JR
153                 if ((previousop == 52) || (previousop == 53))
154                 {
155                         switch (currentop)
156                         {
157                         case 38:
158                                 warn("NOP inserted before MOVEI instruction.");
159                                 D_word(value);
160                                 break;
161                         case 53:
162                                 warn("NOP inserted before JR instruction.");
163                                 D_word(value);
164                                 break;
165                         case 52:
166                                 warn("NOP inserted before JUMP instruction.");
167                                 D_word(value);
168                                 break;
169                         case 51:
170                                 warn("NOP inserted before MOVE PC instruction.");
171                                 D_word(value);
172                                 break;
173                         default:
174                                 break;
175                         }
176                 }
177         }
178
179         if (currentop == 20)
180         {                                    // IMACN checks
181                 if ((previousop != 18) && (previousop != 20))
182                 {
183                         error("IMULTN/IMACN instruction must preceed IMACN instruction");
184                 }
185         }
186
187         if (currentop == 19)
188         {                                    // RESMAC checks
189                 if (previousop != 20)
190                 {
191                         error("IMACN instruction must preceed RESMAC instruction");
192                 }
193         }
194
195         value =((parm & 0x3F) << 10) + ((reg1 & 0x1F) << 5) + (reg2 & 0x1F);
196         D_word(value);
197 }
198
199
200 //
201 // Get a RISC Register
202 //
203 int getregister(WORD rattr)
204 {
205         VALUE eval;                                     // Expression value
206         WORD eattr;                                     // Expression attributes
207         SYM * esym;                                     // External symbol involved in expr.
208         TOKEN r_expr[EXPRSIZE];         // Expression token list
209         WORD defined;                           // Symbol defined flag
210
211         if (expr(r_expr, &eval, &eattr, &esym) != OK)
212         {
213                 error("malformed opcode");
214                 return ERROR;
215         }
216         else
217         {
218                 defined = (WORD)(eattr & DEFINED);
219
220                 if ((challoc - ch_size) < 4)
221                         chcheck(4L);
222
223                 if (!defined)
224                 {
225                         fixup((WORD)(FU_WORD|rattr), sloc, r_expr);      
226                         return 0;
227                 }
228                 else
229                 {
230                         // Check for specified register, r0->r31
231                         if ((eval >= 0) && (eval <= 31))
232                         {
233                                 return eval;
234                         }
235                         else
236                         {
237                                 error(reg_err);
238                                 return ERROR;
239                         }
240                 }
241         }
242
243         return ERROR;
244 }
245
246
247 //
248 // Do RISC Code Generation
249 //
250 int risccg(int state)
251 {
252         unsigned short parm;                                     // Opcode parameters
253         unsigned type;                                           // Opcode type
254         int reg1;                                                // Register 1
255         int reg2;                                                // Register 2
256         int val = 0;                                             // Constructed value
257         char scratch[80];
258         SYM * ccsym;
259         SYM * sy;
260         int i;                                                   // Iterator
261         int t, c;
262         WORD tdb;
263         unsigned locptr = 0;                                     // Address location pointer
264         unsigned page_jump = 0;                                  // Memory page jump flag
265         VALUE eval;                                              // Expression value
266         WORD eattr;                                              // Expression attributes
267         SYM * esym;                                              // External symbol involved in expr.
268         TOKEN r_expr[EXPRSIZE];                                  // Expression token list
269         WORD defined;                                            // Symbol defined flag
270         WORD attrflg;
271         int indexed;                                             // Indexed register flag
272
273         parm = (WORD)(roptbl[state-3000].parm);                  // Get opcode parameter and type
274         type = roptbl[state-3000].typ;
275
276         // Detect whether the opcode parmeter passed determines that the opcode is specific to only one 
277         // of the RISC processors and ensure it is legal in the current code section. 
278         // If not then error and return.
279         if (((parm & GPUONLY) && rdsp) || ((parm & DSPONLY) && rgpu))
280         {
281                 error("opcode is not valid in this code section");
282                 return ERROR;
283         }
284
285         // Process RISC opcode
286         switch (type)
287         {
288         // No operand instructions
289         // NOP
290         case RI_NONE: 
291                 risc_instruction_word(parm, 0, 0);
292                 break;
293         // Single operand instructions (Rd)
294         // ABS, MIRROR, NEG, NOT, PACK, RESMAC, SAT8, SAT16, SAT16S, SAT24, SAT32S, UNPACK
295         case RI_ONE:
296                 reg2 = getregister(FU_REGTWO);
297                 at_eol();
298                 risc_instruction_word(parm, parm >> 6, reg2);
299                 break;   
300         // Two operand instructions (Rs,Rd)
301         // ADD, ADDC, AND, CMP, DIV, IMACN, IMULT, IMULTN, MOVEFA, MOVETA, MULT, MMULT, 
302         // MTOI, NORMI, OR, ROR, SH, SHA, SUB, SUBC, XOR
303         case RI_TWO:                      
304                 if (parm == 37)
305                         altbankok = 1;                      // MOVEFA
306
307                 reg1 = getregister(FU_REGONE);
308                 CHECK_COMMA;         
309
310                 if (parm == 36)
311                         altbankok = 1;                      // MOVETA
312
313                 reg2 = getregister(FU_REGTWO);
314                 at_eol();
315                 risc_instruction_word(parm, reg1, reg2);
316                 break;
317         // Numeric operand (n,Rd) where n = -16..+15
318         // CMPQ
319         case RI_NUM_15:                   
320         // Numeric operand (n,Rd) where n = 0..31
321         // BCLR, BSET, BTST, MOVEQ
322         case RI_NUM_31:      
323         // Numeric operand (n,Rd) where n = 1..32
324         // ADDQ, ADDQMOD, ADDQT, SHARQ, SHLQ, SHRQ, SUBQ, SUBQMOD, SUBQT, ROLQ, RORQ
325         case RI_NUM_32:                   
326                 switch (type)
327                 {
328                 case RI_NUM_15:
329                         reg1 = -16; reg2 = 15; attrflg = FU_NUM15;
330                         break;
331                 default:
332                 case RI_NUM_31:
333                         reg1 =   0; reg2 = 31; attrflg = FU_NUM31;
334                         break;
335                 case RI_NUM_32:
336                         reg1 =   1; reg2 = 32; attrflg = FU_NUM32;
337                         break;
338                 }
339
340                 if (parm & SUB32) attrflg |= FU_SUB32;
341                 {
342                         if (*tok == '#')
343                         {
344                                 ++tok;
345
346                                 if (expr(r_expr, &eval, &eattr, &esym) != OK)
347                                         goto malformed;
348                                 else
349                                 {
350                                         defined = (WORD)(eattr & DEFINED);
351
352                                         if ((challoc - ch_size) < 4)
353                                                 chcheck(4L);
354
355                                         if (!defined)
356                                         {
357                                                 fixup((WORD)(FU_WORD|attrflg), sloc, r_expr);
358                                                 reg1 = 0;
359                                         }
360                                         else
361                                         {
362                                                 if ((int)eval < reg1 || (int)eval > reg2)
363                                                 {
364                                                         error("constant out of range");
365                                                         return ERROR;
366                                                 }
367
368                                                 if (parm & SUB32) 
369                                                         reg1 = 32 - eval; 
370                                                 else if (type == RI_NUM_32)
371                                                         reg1 = (reg1 == 32) ? 0 : eval;
372                                                 else
373                                                         reg1 = eval;
374                                         }
375                                 }
376                         }
377                         else
378                                 goto malformed;
379                 }
380
381                 CHECK_COMMA;
382                 reg2 = getregister(FU_REGTWO);
383                 at_eol();
384                 risc_instruction_word(parm, reg1, reg2);
385                 break;
386         // Move Immediate - n,Rn - n in Second Word
387         case RI_MOVEI:       
388                 if (*tok == '#')
389                 {
390                         ++tok;
391                         if (expr(r_expr, &eval, &eattr, &esym) != OK)
392                         {
393                                 malformed:
394                                 error("malformed opcode");
395                                 return ERROR;
396                         }
397                         else
398                         {
399                                 // Opcode tracking for nop padding
400                                 previousop = currentop;                          
401                                 currentop = parm;
402
403                                 // JUMP or JR
404                                 if ((previousop == 52) || (previousop == 53) && !jpad)
405                                 {
406                                         warn("NOP inserted before MOVEI instruction.");   
407                                         D_word(0xE400);
408                                 }
409
410                                 tdb = (WORD)(eattr & TDB);
411                                 defined = (WORD)(eattr & DEFINED);
412
413                                 if ((challoc - ch_size) < 4)
414                                         chcheck(4L);
415
416                                 if (!defined)
417                                 {
418                                         fixup(FU_LONG|FU_MOVEI, sloc + 2, r_expr);
419                                         eval = 0;
420                                 }
421                                 else
422                                 {
423                                         if (tdb)
424                                         {
425                                                 rmark(cursect, sloc + 2, tdb, MLONG|MMOVEI, NULL);
426                                         }
427                                 }       
428
429                                 val = eval;
430
431                                 // Store the defined flags and value of the movei when used in mjump
432                                 if (mjump_align)
433                                 {
434                                         mjump_defined = defined;
435                                         mjump_dest = val;
436                                 }
437                         }
438                 }
439                 else
440                         goto malformed;
441
442                 ++tok;
443                 reg2 = getregister(FU_REGTWO);
444                 at_eol();
445                 D_word((((parm & 0x3F) << 10) + reg2));
446                 val = ((val >> 16) & 0x0000FFFF) | ((val << 16) & 0xFFFF0000);
447                 D_long(val);
448                 break;
449         case RI_MOVE:                     // PC,Rd or Rs,Rd
450                 if (*tok == KW_PC)
451                 {
452                         parm = 51;
453                         reg1 = 0;
454                         ++tok;
455                 }
456                 else
457                 {
458                         parm = 34;
459                         reg1 = getregister(FU_REGONE);
460                 }
461
462                 CHECK_COMMA;
463                 reg2 = getregister(FU_REGTWO);
464                 at_eol();
465                 risc_instruction_word(parm, reg1, reg2);
466                 break;
467         // (Rn),Rn = 41 / (R14/R15+n),Rn = 43/44 / (R14/R15+Rn),Rn = 58/59
468         case RI_LOAD:          
469                 indexed = 0;
470                 parm = 41;
471
472                 if (*tok != '(')
473                         goto malformed;
474
475                 ++tok;
476                 if ((*tok == KW_R14 || *tok == KW_R15) && (*(tok+1) != ')')) 
477                         indexed = (*tok - KW_R0);
478
479                 if (*tok == SYMBOL)
480                 {
481                         sy = lookup((char *)tok[1], LABEL, 0);
482                         if (!sy)
483                         {
484                                 error(reg_err);
485                                 return ERROR;
486                         }
487
488                         if (sy->sattre & EQUATEDREG)
489                         {
490                                 if (((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15)
491                                         && (*(tok+2) != ')'))
492                                 {
493                                         indexed = (sy->svalue & 0x1F);
494                                         ++tok;
495                                 }
496                         }
497                 }
498
499                 if (!indexed)
500                 {
501                         reg1 = getregister(FU_REGONE);
502                 }
503                 else
504                 {
505                         reg1 = indexed;
506                         indexed = 0;
507                         ++tok;
508
509                         if (*tok == '+')
510                         {
511                                 parm = (WORD)(reg1 - 14 + 58);
512                                 tok++;
513
514                                 if (*tok >= KW_R0 && *tok <= KW_R31)
515                                 {
516                                         indexed = 1;
517                                 }
518
519                                 if (*tok == SYMBOL)
520                                 {
521                                         sy = lookup((char *)tok[1], LABEL, 0);
522
523                                         if (!sy)
524                                         {
525                                                 error(reg_err);
526                                                 return ERROR;
527                                         }
528
529                                         if (sy->sattre & EQUATEDREG)
530                                         {
531                                                 indexed = 1;
532                                         } 
533                                 }
534
535                                 if (indexed)
536                                 {
537                                         reg1 = getregister(FU_REGONE);
538                                 }
539                                 else
540                                 {
541                                         if (expr(r_expr, &eval, &eattr, &esym) != OK)
542                                         {
543                                                 goto malformed;
544                                         }
545                                         else
546                                         {
547                                                 tdb = (WORD)(eattr & TDB);
548                                                 defined = (WORD)(eattr & DEFINED);
549
550                                                 if ((challoc - ch_size) < 4)
551                                                         chcheck(4L);
552
553                                                 if (!defined)
554                                                 {
555                                                         error("constant expected");
556                                                         return ERROR;
557                                                         //fixup(FU_WORD|FU_REGONE, sloc, r_expr);
558                                                         reg1 = 0;
559                                                 }
560                                                 else
561                                                 {
562                                                         reg1 = eval;
563
564                                                         if (reg1 == 0)
565                                                         {
566                                                                 reg1 = 14 + (parm - 58);
567                                                                 parm = 41;
568                                                                 warn("NULL offset removed");
569                                                         }
570                                                         else
571                                                         {
572                                                                 if (reg1 < 1 || reg1 > 32)
573                                                                 {
574                                                                         error("constant out of range");
575                                                                         return ERROR;
576                                                                 }
577
578                                                                 if (reg1 == 32)
579                                                                         reg1 = 0;
580
581                                                                 parm = (WORD)(parm - 58 + 43);
582                                                         }
583                                                 }
584                                         }
585                                 }
586                         }
587                         else
588                         {
589                                 reg1 = getregister(FU_REGONE);
590                         }
591                 }
592
593                 if (*tok != ')')
594                         goto malformed;
595
596                 ++tok;
597                 CHECK_COMMA;
598                 reg2 = getregister(FU_REGTWO);
599                 at_eol();
600                 risc_instruction_word(parm, reg1, reg2);
601                 break;
602         // Rn,(Rn) = 47 / Rn,(R14/R15+n) = 49/50 / Rn,(R14/R15+Rn) = 60/61
603         case RI_STORE:    
604                 parm = 47;
605                 reg1 = getregister(FU_REGONE);
606                 CHECK_COMMA;
607
608                 if (*tok != '(') goto malformed;
609
610                 ++tok;
611                 indexed = 0;
612
613                 if ((*tok == KW_R14 || *tok == KW_R15) && (*(tok+1) != ')')) 
614                         indexed = (*tok - KW_R0);
615
616                 if (*tok == SYMBOL)
617                 {
618                         sy = lookup((char *)tok[1], LABEL, 0);
619
620                         if (!sy)
621                         {
622                                 error(reg_err);
623                                 return ERROR;
624                         }
625
626                         if (sy->sattre & EQUATEDREG) 
627                         {
628                                 if (((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15)
629                                         && (*(tok+2) != ')'))
630                                 {
631                                         indexed = (sy->svalue & 0x1F);
632                                         ++tok;
633                                 }
634                         }
635                 }
636
637                 if (!indexed)
638                 {
639                         reg2 = getregister(FU_REGTWO);
640                 }
641                 else
642                 {
643                         reg2 = indexed;
644                         indexed = 0;
645                         ++tok;
646
647                         if (*tok == '+')
648                         {
649                                 parm = (WORD)(reg2 - 14 + 60);
650                                 tok++;
651
652                                 if (*tok >= KW_R0 && *tok <= KW_R31)
653                                 {
654                                         indexed = 1;
655                                 }
656
657                                 if (*tok == SYMBOL)
658                                 {
659                                         sy = lookup((char *)tok[1], LABEL, 0);
660
661                                         if (!sy)
662                                         {
663                                                 error(reg_err);
664                                                 return ERROR;
665                                         }
666
667                                         if (sy->sattre & EQUATEDREG)
668                                         {
669                                                 indexed = 1;
670                                         }
671                                 }
672
673                                 if (indexed)
674                                 {
675                                         reg2 = getregister(FU_REGTWO);
676                                 }
677                                 else
678                                 {
679                                         if (expr(r_expr, &eval, &eattr, &esym) != OK)
680                                         {
681                                                 goto malformed;
682                                         }
683                                         else
684                                         {
685                                                 tdb = (WORD)(eattr & TDB);
686                                                 defined = (WORD)(eattr & DEFINED);
687
688                                                 if ((challoc - ch_size) < 4)
689                                                         chcheck(4L);
690
691                                                 if (!defined)
692                                                 {
693                                                         fixup(FU_WORD|FU_REGTWO, sloc, r_expr);
694                                                         reg2 = 0;
695                                                 }
696                                                 else
697                                                 {
698                                                         reg2 = eval;
699
700                                                         if (reg2 == 0 )
701                                                         {
702                                                                 reg2 = 14 + (parm - 60);
703                                                                 parm = 47;
704                                                                 warn("NULL offset removed");
705                                                         }
706                                                         else
707                                                         {
708                                                                 if (reg2 < 1 || reg2 > 32)
709                                                                 {
710                                                                         error("constant out of range");
711                                                                         return ERROR;
712                                                                 }
713
714                                                                 if (reg2 == 32)
715                                                                         reg2 = 0;
716
717                                                                 parm = (WORD)(parm - 60 + 49);
718                                                         }
719                                                 }       
720                                         }
721                                 }
722                         }
723                         else
724                         {
725                                 reg2 = getregister(FU_REGTWO);
726                         }
727                 }
728
729                 if (*tok != ')')
730                         goto malformed;
731
732                 ++tok;
733                 at_eol();
734                 risc_instruction_word(parm, reg2, reg1);
735                 break;
736         // LOADB/LOADP/LOADW (Rn),Rn
737         case RI_LOADN:                    
738                 if (*tok != '(')
739                         goto malformed;
740
741                 ++tok;
742                 reg1 = getregister(FU_REGONE);
743
744                 if (*tok != ')')
745                         goto malformed;
746
747                 ++tok;
748                 CHECK_COMMA;
749                 reg2 = getregister(FU_REGTWO);
750                 at_eol();
751                 risc_instruction_word(parm, reg1, reg2);
752                 break;
753         // STOREB/STOREP/STOREW Rn,(Rn)
754         case RI_STOREN:                   
755                 reg1 = getregister(FU_REGONE);
756                 CHECK_COMMA;
757
758                 if (*tok != '(')
759                         goto malformed;
760
761                 ++tok;
762                 reg2 = getregister(FU_REGTWO);
763
764                 if (*tok != ')')
765                         goto malformed;
766
767                 ++tok;
768                 at_eol();
769                 risc_instruction_word(parm, reg2, reg1);
770                 break;
771         case RI_JR:                       // Jump Relative - cc,n - n=-16..+15 words, reg2=cc
772         case RI_JUMP:                     // Jump Absolute - cc,(Rs) - reg2=cc
773                 // Check to see if there is a comma in the token string. If not then the JR or JUMP should
774                 // default to 0, Jump Always
775                 t = i = c = 0;
776                 while (t != EOL)
777                 {
778                         t = *(tok + i);
779                         if (t == ',') c = 1;
780                         i++;
781                 }
782
783                 if (c)
784                 {                                            // Comma present in token string
785                         if (*tok == CONST)
786                         {                             // CC using a constant number
787                                 ++tok;
788                                 val = *tok;
789                                 ++tok;
790                                 CHECK_COMMA;
791                         }
792                         else if (*tok == SYMBOL)
793                         {
794                                 val = 99;
795
796                                 for(i=0; i<MAXINTERNCC; i++)
797                                 {
798                                         strcpy(scratch, (char *)tok[1]);
799                                         strtoupper(scratch);
800
801                                         if (!strcmp(condname[i], scratch)) 
802                                                 val = condnumber[i];
803                                 }
804
805                                 if (val == 99)
806                                 {
807                                         ccsym = lookup((char *)tok[1], LABEL, 0);
808
809                                         if (ccsym && (ccsym->sattre & EQUATEDCC) && !(ccsym->sattre & UNDEF_CC))
810                                         {
811                                                 val = ccsym->svalue;
812                                         }
813                                         else
814                                         {
815                                                 error("unknown condition code");
816                                                 return ERROR;
817                                         }
818                                 }
819
820                                 tok += 2;
821                                 CHECK_COMMA;
822                         }
823                         else if (*tok == '(')
824                         {
825                                 val = 0;                                     // Jump always
826                         }
827                 }
828                 else
829                 {
830                         val = 0;                                        // Jump always
831                 }
832
833                 if (val < 0 || val > 31)
834                 {
835                         error("condition constant out of range");
836                         return ERROR;
837                 }
838                 else
839                 {
840                         reg1 = val;                                     // Store condition code
841                 }
842
843                 if (type == RI_JR)
844                 {                                // JR cc,n
845                         if (expr(r_expr, &eval, &eattr, &esym) != OK)
846                                 goto malformed;
847                         else
848                         {
849                                 tdb = (WORD)(eattr & TDB);
850                                 defined = (WORD)(eattr & DEFINED);
851
852                                 if ((challoc - ch_size) < 4)
853                                         chcheck(4L);
854
855                                 if (!defined)
856                                 {
857                                         if (in_main)
858                                         {
859                                                 fixup(FU_WORD|FU_MJR, sloc, r_expr);
860                                         }
861                                         else
862                                         {
863                                                 fixup(FU_WORD|FU_JR, sloc, r_expr);
864                                         }
865
866                                         reg2 = 0;
867                                 }
868                                 else
869                                 {
870                                         val = eval;
871
872                                         if (orgactive)
873                                         {
874                                                 reg2 = ((int)(val - (orgaddr + 2))) / 2;
875                                                 if ((reg2 < -16) || (reg2 > 15))
876                                                 error("PC relative overflow");
877                                                 locptr = orgaddr;
878                                         }
879                                         else
880                                         {
881                                                 reg2 = ((int)(val - (sloc + 2))) / 2;
882                                                 if ((reg2 < -16) || (reg2 > 15))
883                                                 error("PC relative overflow");
884                                                 locptr = sloc;
885                                         }
886                                 }       
887
888                                 if (in_main)
889                                 {
890                                         if (defined)
891                                         {
892                                                 if (((locptr >= 0xF03000) && (locptr < 0xF04000)
893                                                         && (val < 0xF03000)) || ((val >= 0xF03000)
894                                                         && (val < 0xF04000) && (locptr < 0xF03000)))
895                                                 {
896                                                         warn("* cannot jump relative between main memory and local gpu ram");
897                                                 }
898                                                 else
899                                                 {
900                                                         page_jump = (locptr & 0xFFFFFF00) - (val & 0xFFFFFF00);
901
902                                                         if (page_jump)
903                                                         {
904                                                                 if (val % 4)
905                                                                 {
906                                                                         warn("* destination address not aligned for long page jump relative, "
907                                                                         "insert a \'nop\' before the destination label/address");
908                                                                 }
909                                                         }
910                                                         else
911                                                         {
912                                                                 if ((val - 2) % 4)
913                                                                 {
914                                                                         warn("* destination address not aligned for short page jump relative, "
915                                                                                 "insert a \'nop\' before the destination label/address");
916                                                                 }
917                                                         }
918                                                 }
919                                         }
920                                 }
921                         }
922
923                         risc_instruction_word(parm, reg2, reg1);
924                 }
925                 else
926                 {                                           // JUMP cc, (Rn)
927                         if (*tok != '(')
928                                 goto malformed;
929
930                         ++tok;
931                         reg2 = getregister(FU_REGTWO);
932
933                         if (*tok != ')')
934                                 goto malformed;
935
936                         ++tok;
937                         at_eol();
938
939                         if (in_main)
940                         {
941                                 if (!mjump_align)
942                                 {
943                                         warn("* \'jump\' is not recommended for .gpumain as destination addresses "
944                                                 "cannot be validated for alignment, use \'mjump\'");
945                                         locptr = (orgactive) ? orgaddr : sloc;
946
947                                         if (locptr % 4)
948                                         {
949                                                 warn("* source address not aligned for long or short jump, "
950                                                         "insert a \'nop\' before the \'jump\'");
951                                         }          
952                                 }
953                                 else
954                                 {
955                                         if (mjump_defined)
956                                         {
957                                                 locptr = (orgactive) ? orgaddr : sloc;
958                                                 page_jump = (locptr & 0xFFFFFF00) - (mjump_dest & 0xFFFFFF00);
959
960                                                 if (page_jump)
961                                                 {
962                                                         if (mjump_dest % 4)
963                                                         {
964                                                                 warn("* destination address not aligned for long page jump, "
965                                                                 "insert a \'nop\' before the destination label/address");
966                                                         }          
967                                                 }
968                                                 else
969                                                 {
970                                                         if (!(mjump_dest & 0x0000000F) || ((mjump_dest - 2) % 4))
971                                                         {
972                                                                 warn("* destination address not aligned for short page jump, "
973                                                                 "insert a \'nop\' before the destination label/address");
974                                                         }          
975                                                 }
976                                         }
977                                         else
978                                         {
979                                                 locptr = (orgactive) ? orgaddr : sloc;
980                                                 fwdjump[fwindex++] = locptr;
981                                         }
982                                 }
983                         }
984
985                         risc_instruction_word(parm, reg2, reg1);
986                 }
987
988                 break;
989         // Should never get here :D
990         default:                                              
991                 error("unknown risc opcode type");
992                 return ERROR;
993                 break;
994         }
995
996         return 0;
997 }