5f658dc53f8a42b59a70c6d2993266e3cbdf5680
[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", "N", "N_NZ", "N_Z ",
38    "T", "A", "NE", "EQ", "CC", "HS", "HI", "CS", "LO", "PL", "MI", "F"
39 };
40
41 // Jaguar Jump Condition Numbers
42 char condnumber[] = {1, 2, 4, 5, 6, 8, 9, 10, 20, 21, 22, 24, 25, 26,
43                      0, 0, 1, 2, 4, 4, 5,  8,  8, 20, 24, 31};
44
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 },
96    { MR_JR,      RI_JR,     53 },
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 }
108 };
109
110 //
111 // --- Convert a String to Uppercase ---------------------------------------------------------------
112 //
113
114 void strtoupper(char *s) {
115    while(*s) {
116       *s = (char)(toupper(*s));
117       s++;
118    }
119 }
120
121 //
122 // --- Build RISC Instruction Word -----------------------------------------------------------------
123 //
124
125 void risc_instruction_word(unsigned short parm, int reg1, int reg2) {
126    int value = 0xE400;
127
128    previousop = currentop;                                  // Opcode tracking for nop padding
129    currentop = parm;
130    
131    if(!orgwarning) {                                        // Check for absolute address setting
132       if(!orgactive && !in_main) {
133          warn("GPU/DSP code outside of absolute section");
134          orgwarning = 1;
135       }
136    }
137    
138    if(jpad) {                                               // JPAD directive
139       //                JUMP                   JR                    NOP
140       if(((previousop == 52) || (previousop == 53)) && (currentop != 57))
141          D_word(value);                                     // Insert NOP
142    } else {
143       //               JUMP                   JR
144       if((previousop == 52) || (previousop == 53)) {
145          switch(currentop) {
146             case 38: warn("NOP inserted before MOVEI instruction.");   D_word(value); break;
147             case 53: warn("NOP inserted before JR instruction.");      D_word(value); break;
148             case 52: warn("NOP inserted before JUMP instruction.");    D_word(value); break;
149             case 51: warn("NOP inserted before MOVE PC instruction."); D_word(value); break;
150             default:
151                break;
152          }
153       }
154    }
155
156    if(currentop == 20) {                                    // IMACN checks
157       if((previousop != 18) && (previousop != 20)) {
158          error("IMULTN/IMACN instruction must preceed IMACN instruction");
159       }
160    }
161
162    if(currentop == 19) {                                    // RESMAC checks
163       if(previousop != 20) {
164          error("IMACN instruction must preceed RESMAC instruction");
165       }
166    }
167
168    value =((parm & 0x3F) << 10) + ((reg1 & 0x1F) << 5) + (reg2 & 0x1F);
169    D_word(value);
170 }
171
172 //
173 // --- Get a RISC Register -------------------------------------------------------------------------
174 //
175
176 int getregister(WORD rattr) {
177    VALUE eval;                                              // Expression value
178    WORD eattr;                                              // Expression attributes
179    SYM *esym;                                               // External symbol involved in expr.
180    TOKEN r_expr[EXPRSIZE];                                  // Expression token list
181    WORD defined;                                            // Symbol defined flag
182
183    if(expr(r_expr, &eval, &eattr, &esym) != OK) {
184       error("malformed opcode");
185       return(ERROR);
186    } else {
187       defined = (WORD)(eattr & DEFINED);
188       if((challoc - ch_size) < 4)
189          chcheck(4L);
190       if(!defined) {
191          fixup((WORD)(FU_WORD|rattr), sloc, r_expr);      
192          return(0);
193       } else {
194          if((eval >= 0) && (eval <= 31)) {                  // Check for specified register, r0->r31
195             return(eval);
196          } else {
197             error(reg_err);
198             return(ERROR);
199          }
200       }
201    }
202    
203    return(ERROR);
204 }
205
206 //
207 // --- Do RISC Code Generation ---------------------------------------------------------------------
208 //
209
210 int risccg(int state) {
211    unsigned short parm;                                     // Opcode parameters
212    unsigned type;                                           // Opcode type
213    int reg1;                                                // Register 1
214    int reg2;                                                // Register 2
215    int val = 0;                                             // Constructed value
216    char scratch[80];
217    SYM *ccsym;
218    SYM *sy;
219    int i;                                                   // Iterator
220    int t, c;
221    WORD tdb;
222    unsigned locptr = 0;                                     // Address location pointer
223    unsigned page_jump = 0;                                  // Memory page jump flag
224    VALUE eval;                                              // Expression value
225    WORD eattr;                                              // Expression attributes
226    SYM *esym;                                               // External symbol involved in expr.
227    TOKEN r_expr[EXPRSIZE];                                  // Expression token list
228    WORD defined;                                            // Symbol defined flag
229    WORD attrflg;
230    int indexed;                                             // Indexed register flag
231
232    parm = (WORD)(roptbl[state-3000].parm);                  // Get opcode parameter and type
233    type = roptbl[state-3000].typ;
234
235    // Detect whether the opcode parmeter passed determines that the opcode is specific to only one 
236    // of the RISC processors and ensure it is legal in the current code section. 
237    // If not then error and return.
238    if(((parm & GPUONLY) && rdsp) || ((parm & DSPONLY) && rgpu) ) {
239       error("opcode is not valid in this code section");
240       return(ERROR);
241    }
242
243    // Process RISC opcode
244    switch(type) {
245       // No operand instructions
246       // NOP
247       case RI_NONE: 
248          risc_instruction_word(parm, 0, 0);
249          break;
250       // Single operand instructions (Rd)
251       // ABS, MIRROR, NEG, NOT, PACK, RESMAC, SAT8, SAT16, SAT16S, SAT24, SAT32S, UNPACK
252       case RI_ONE:
253          reg2 = getregister(FU_REGTWO);
254          at_eol();
255          risc_instruction_word(parm, parm >> 6, reg2);
256          break;   
257       // Two operand instructions (Rs,Rd)
258       // ADD, ADDC, AND, CMP, DIV, IMACN, IMULT, IMULTN, MOVEFA, MOVETA, MULT, MMULT, 
259       // MTOI, NORMI, OR, ROR, SH, SHA, SUB, SUBC, XOR
260       case RI_TWO:                      
261          if(parm == 37) altbankok = 1;                      // MOVEFA
262          reg1 = getregister(FU_REGONE);
263          CHECK_COMMA;         
264          if(parm == 36) altbankok = 1;                      // MOVETA
265          reg2 = getregister(FU_REGTWO);
266          at_eol();
267          risc_instruction_word(parm, reg1, reg2);
268          break;
269       // Numeric operand (n,Rd) where n = -16..+15
270       // CMPQ
271       case RI_NUM_15:                   
272       // Numeric operand (n,Rd) where n = 0..31
273       // BCLR, BSET, BTST, MOVEQ
274       case RI_NUM_31:      
275       // Numeric operand (n,Rd) where n = 1..32
276       // ADDQ, ADDQMOD, ADDQT, SHARQ, SHLQ, SHRQ, SUBQ, SUBQMOD, SUBQT, ROLQ, RORQ
277       case RI_NUM_32:                   
278          switch(type) {
279             case RI_NUM_15: reg1 = -16; reg2 = 15; attrflg = FU_NUM15; break;
280             default:
281             case RI_NUM_31: reg1 =   0; reg2 = 31; attrflg = FU_NUM31; break;
282             case RI_NUM_32: reg1 =   1; reg2 = 32; attrflg = FU_NUM32; break;
283          }
284          if(parm & SUB32) attrflg |= FU_SUB32;
285          if(*tok == '#') {
286             ++tok;
287             if(expr(r_expr, &eval, &eattr, &esym) != OK)
288                goto malformed;
289             else {
290                defined = (WORD)(eattr & DEFINED);
291                if((challoc - ch_size) < 4)
292                   chcheck(4L);
293                if(!defined) {
294                   fixup((WORD)(FU_WORD|attrflg), sloc, r_expr);
295                   reg1 = 0;
296                } else {
297                   if((int)eval < reg1 || (int)eval > reg2) {
298                      error("constant out of range");
299                      return(ERROR);
300                   }
301                   if(parm & SUB32) 
302                      reg1 = 32 - eval; 
303                   else if(type == RI_NUM_32)
304                      reg1 = (reg1 == 32) ? 0 : eval;
305                   else
306                      reg1 = eval;
307                }
308             }
309          } else goto malformed;
310          CHECK_COMMA;
311          reg2 = getregister(FU_REGTWO);
312          at_eol();
313          risc_instruction_word(parm, reg1, reg2);
314          break;
315       // Move Immediate - n,Rn - n in Second Word
316       case RI_MOVEI:       
317          if(*tok == '#') {
318             ++tok;
319             if(expr(r_expr, &eval, &eattr, &esym) != OK) {
320                malformed:
321                error("malformed opcode");
322                return(ERROR);
323             } else {
324                // Opcode tracking for nop padding
325                previousop = currentop;                          
326                currentop = parm;
327                // JUMP or JR
328                if((previousop == 52) || (previousop == 53) && !jpad) {
329                   warn("NOP inserted before MOVEI instruction.");   
330                   D_word(0xE400);
331                }
332                tdb = (WORD)(eattr & TDB);
333                defined = (WORD)(eattr & DEFINED);
334                if((challoc - ch_size) < 4)
335                   chcheck(4L);
336                if(!defined) {
337                   fixup(FU_LONG|FU_MOVEI, sloc + 2, r_expr);
338                   eval = 0;
339                } else {
340                   if(tdb) {
341                      rmark(cursect, sloc + 2, tdb, MLONG|MMOVEI, NULL);
342                   }
343                }        
344                val = eval;
345                // Store the defined flags and value of the movei when used in mjump
346                if(mjump_align) {
347                   mjump_defined = defined;
348                   mjump_dest = val;
349                }
350             }
351          } else goto malformed;
352          ++tok;
353          reg2 = getregister(FU_REGTWO);
354          at_eol();
355          D_word((((parm & 0x3F) << 10) + reg2));
356          val = ((val >> 16) & 0x0000FFFF) | ((val << 16) & 0xFFFF0000);
357          D_long(val);
358          break;
359       case RI_MOVE:                     // PC,Rd or Rs,Rd
360          if(*tok == KW_PC) {
361             parm = 51;
362             reg1 = 0;
363             ++tok;
364          } else {
365             parm = 34;
366             reg1 = getregister(FU_REGONE);
367          }
368          CHECK_COMMA;
369          reg2 = getregister(FU_REGTWO);
370          at_eol();
371          risc_instruction_word(parm, reg1, reg2);
372          break;
373       // (Rn),Rn = 41 / (R14/R15+n),Rn = 43/44 / (R14/R15+Rn),Rn = 58/59
374       case RI_LOAD:          
375          indexed = 0;
376          parm = 41;
377          if(*tok != '(') goto malformed;
378          ++tok;
379          if((*tok == KW_R14 || *tok == KW_R15) && (*(tok+1) != ')')) 
380             indexed = (*tok - KW_R0);
381          if(*tok == SYMBOL) {
382             sy = lookup((char *)tok[1], LABEL, 0);
383             if(!sy) {
384                error(reg_err);
385                return(ERROR);
386             }
387             if(sy->sattre & EQUATEDREG) 
388                if(((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15) && (*(tok+2) != ')')) {
389                   indexed = (sy->svalue & 0x1F);
390                   ++tok;
391                }
392          }
393          if(!indexed) {
394             reg1 = getregister(FU_REGONE);
395          } else {
396             reg1 = indexed;
397             indexed = 0;
398             ++tok;
399             if(*tok == '+') {
400                parm = (WORD)(reg1 - 14 + 58);
401                tok++;
402                if(*tok >= KW_R0 && *tok <= KW_R31) {
403                   indexed = 1;
404                }
405                if(*tok == SYMBOL) {
406                   sy = lookup((char *)tok[1], LABEL, 0);
407                   if(!sy) {
408                      error(reg_err);
409                      return(ERROR);
410                   }
411                   if(sy->sattre & EQUATEDREG) {
412                      indexed = 1;
413                   } 
414                }
415                if(indexed) {
416                   reg1 = getregister(FU_REGONE);
417                } else {
418                   if(expr(r_expr, &eval, &eattr, &esym) != OK) {
419                      goto malformed;
420                   } else {
421                      tdb = (WORD)(eattr & TDB);
422                      defined = (WORD)(eattr & DEFINED);
423                      if((challoc - ch_size) < 4)
424                         chcheck(4L);
425                      if(!defined) {
426                         error("constant expected");
427                         return(ERROR);
428                         //fixup(FU_WORD|FU_REGONE, sloc, r_expr);
429                         reg1 = 0;
430                      } else {
431                         reg1 = eval;
432                         if(reg1 == 0) {
433                            reg1 = 14+(parm-58);
434                            parm = 41;
435                            warn("NULL offset removed");
436                         } else {
437                            if(reg1 < 1 || reg1 > 32) {
438                               error("constant out of range");
439                               return(ERROR);
440                            }
441                            if(reg1 == 32) reg1 = 0;
442                            parm = (WORD)(parm - 58 + 43);
443                         }
444                      }  
445                   }
446                }
447             } else {
448                reg1 = getregister(FU_REGONE);
449             }
450          }
451          if(*tok != ')') goto malformed;
452          ++tok;
453          CHECK_COMMA;
454          reg2 = getregister(FU_REGTWO);
455          at_eol();
456          risc_instruction_word(parm, reg1, reg2);
457          break;
458       // Rn,(Rn) = 47 / Rn,(R14/R15+n) = 49/50 / Rn,(R14/R15+Rn) = 60/61
459       case RI_STORE:    
460          parm = 47;
461          reg1 = getregister(FU_REGONE);
462          CHECK_COMMA;
463          if(*tok != '(') goto malformed;
464          ++tok;
465          indexed = 0;
466          if((*tok == KW_R14 || *tok == KW_R15) && (*(tok+1) != ')')) 
467             indexed = (*tok - KW_R0);
468          if(*tok == SYMBOL) {
469             sy = lookup((char *)tok[1], LABEL, 0);
470             if(!sy) {
471                error(reg_err);
472                return(ERROR);
473             }
474             if(sy->sattre & EQUATEDREG) 
475                if(((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15) && (*(tok+2) != ')')) {
476                   indexed = (sy->svalue & 0x1F);
477                   ++tok;
478                }
479          }
480          if(!indexed) {
481             reg2 = getregister(FU_REGTWO);
482          } else {
483             reg2 = indexed;
484             indexed = 0;
485             ++tok;
486             if(*tok == '+') {
487                parm = (WORD)(reg2 - 14 + 60);
488                tok++;
489                if(*tok >= KW_R0 && *tok <= KW_R31) {
490                   indexed = 1;
491                }
492                if(*tok == SYMBOL) {
493                   sy = lookup((char *)tok[1], LABEL, 0);
494                   if(!sy) {
495                      error(reg_err);
496                      return(ERROR);
497                   }
498                   if(sy->sattre & EQUATEDREG) {
499                      indexed = 1;
500                   }
501                }
502                if(indexed) {
503                   reg2 = getregister(FU_REGTWO);
504                } else {
505                   if(expr(r_expr, &eval, &eattr, &esym) != OK) {
506                      goto malformed;
507                   } else {
508                      tdb = (WORD)(eattr & TDB);
509                      defined = (WORD)(eattr & DEFINED);
510                      if((challoc - ch_size) < 4)
511                         chcheck(4L);
512                      if(!defined) {
513                         fixup(FU_WORD|FU_REGTWO, sloc, r_expr);
514                         reg2 = 0;
515                      } else {
516                         reg2 = eval;
517                         if(reg2 == 0 ) {
518                            reg2 = 14+(parm-60);
519                            parm = 47;
520                            warn("NULL offset removed");
521                         } else {
522                            if(reg2 < 1 || reg2 > 32) {
523                               error("constant out of range");
524                               return(ERROR);
525                            }
526                            if(reg2 == 32) reg2 = 0;
527                            parm = (WORD)(parm - 60 + 49);
528                         }
529                      }  
530                   }
531                }
532             } else {
533                reg2 = getregister(FU_REGTWO);
534             }
535          }
536          if(*tok != ')') goto malformed;
537          ++tok;
538          at_eol();
539          risc_instruction_word(parm, reg2, reg1);
540          break;
541       // LOADB/LOADP/LOADW (Rn),Rn
542       case RI_LOADN:                    
543          if(*tok != '(') goto malformed;
544          ++tok;
545          reg1 = getregister(FU_REGONE);
546          if(*tok != ')') goto malformed;
547          ++tok;
548          CHECK_COMMA;
549          reg2 = getregister(FU_REGTWO);
550          at_eol();
551          risc_instruction_word(parm, reg1, reg2);
552          break;
553       // STOREB/STOREP/STOREW Rn,(Rn)
554       case RI_STOREN:                   
555          reg1 = getregister(FU_REGONE);
556          CHECK_COMMA;
557          if(*tok != '(') goto malformed;
558          ++tok;
559          reg2 = getregister(FU_REGTWO);
560          if(*tok != ')') goto malformed;
561          ++tok;
562          at_eol();
563          risc_instruction_word(parm, reg2, reg1);
564          break;
565       case RI_JR:                       // Jump Relative - cc,n - n=-16..+15 words, reg2=cc
566       case RI_JUMP:                     // Jump Absolute - cc,(Rs) - reg2=cc
567          // Check to see if there is a comma in the token string. If not then the JR or JUMP should
568          // default to 0, Jump Always
569          t = i = c = 0;
570          while(t != EOL) {
571             t = *(tok + i);
572             if(t == ',') c = 1;
573             i++;
574          }
575          if(c) {                                            // Comma present in token string
576             if(*tok == CONST) {                             // CC using a constant number
577                ++tok;
578                val = *tok;
579                ++tok;
580                CHECK_COMMA;
581             } else if(*tok == SYMBOL) {
582                val = 99;
583                for(i = 0; i < MAXINTERNCC; i++) {
584                   strcpy(scratch, (char *)tok[1]);
585                   strtoupper(scratch);
586                   if(!strcmp(condname[i], scratch)) 
587                      val = condnumber[i];
588                }
589                if(val == 99) {
590                   ccsym = lookup((char *)tok[1], LABEL, 0);
591                   if(ccsym && (ccsym->sattre & EQUATEDCC) && !(ccsym->sattre & UNDEF_CC)) {
592                      val = ccsym->svalue;
593                   } else {
594                      error("unknown condition code");
595                      return(ERROR);
596                   }
597                }
598                tok += 2;
599                CHECK_COMMA;
600             } else if(*tok == '(') {
601                val = 0;                                     // Jump always
602             }
603          } else {
604             val = 0;                                        // Jump always
605          }
606
607          if(val < 0 || val > 31) {
608             error("condition constant out of range");
609             return(ERROR);
610          } else {
611             reg1 = val;                                     // Store condition code
612          }
613          if(type == RI_JR) {                                // JR cc,n
614             if(expr(r_expr, &eval, &eattr, &esym) != OK)
615                goto malformed;
616             else {
617                tdb = (WORD)(eattr & TDB);
618                defined = (WORD)(eattr & DEFINED);
619                if((challoc - ch_size) < 4)
620                   chcheck(4L);
621                if(!defined) {
622                   if(in_main) {
623                      fixup(FU_WORD|FU_MJR, sloc, r_expr);
624                   } else {
625                      fixup(FU_WORD|FU_JR, sloc, r_expr);
626                   }
627                   reg2 = 0;
628                } else {
629                   val = eval;
630                   if(orgactive) {
631                      reg2 = ((int)(val - (orgaddr + 2))) / 2;
632                      if((reg2 < -16) || (reg2 > 15))
633                         error("PC relative overflow");
634                      locptr = orgaddr;
635                   } else {
636                      reg2 = ((int)(val - (sloc + 2))) / 2;
637                      if((reg2 < -16) || (reg2 > 15))
638                         error("PC relative overflow");
639                      locptr = sloc;
640                   }
641                }        
642                if(in_main) {
643                   if(defined) {
644                      if(((locptr >= 0xF03000) && (locptr < 0xF04000) && (val    < 0xF03000)) ||
645                         ((val    >= 0xF03000) && (val    < 0xF04000) && (locptr < 0xF03000)) ) {
646                         warn("* cannot jump relative between main memory and local gpu ram");
647                      } else {
648                         page_jump = (locptr & 0xFFFFFF00) - (val & 0xFFFFFF00);
649                         if(page_jump) {
650                            if(val % 4) {
651                               warn("* destination address not aligned for long page jump relative, "
652                                    "insert a \'nop\' before the destination label/address");
653                            }
654                         } else {
655                            if((val - 2) % 4) {
656                               warn("* destination address not aligned for short page jump relative, "
657                                    "insert a \'nop\' before the destination label/address");
658                            }
659                         }
660                      }
661                   }
662                }
663             }
664             risc_instruction_word(parm, reg2, reg1);
665          } else {                                           // JUMP cc, (Rn)
666             if(*tok != '(') goto malformed;
667             ++tok;
668             reg2 = getregister(FU_REGTWO);
669             if(*tok != ')') goto malformed;
670             ++tok;
671             at_eol();
672             if(in_main) {
673                if(!mjump_align) {
674                   warn("* \'jump\' is not recommended for .gpumain as destination addresses "
675                        "cannot be validated for alignment, use \'mjump\'");
676                   locptr = (orgactive) ? orgaddr : sloc;
677                   if(locptr % 4) {
678                      warn("* source address not aligned for long or short jump, "
679                           "insert a \'nop\' before the \'jump\'");
680                   }          
681                } else {
682                   if(mjump_defined) {
683                      locptr = (orgactive) ? orgaddr : sloc;
684                      page_jump = (locptr & 0xFFFFFF00) - (mjump_dest & 0xFFFFFF00);
685                      if(page_jump) {
686                         if(mjump_dest % 4) {
687                            warn("* destination address not aligned for long page jump, "
688                           "insert a \'nop\' before the destination label/address");
689                         }          
690                      } else {
691                         if(!(mjump_dest & 0x0000000F) || ((mjump_dest - 2) % 4)) {
692                            warn("* destination address not aligned for short page jump, "
693                           "insert a \'nop\' before the destination label/address");
694                         }          
695                      }
696                   } else {
697                      locptr = (orgactive) ? orgaddr : sloc;
698                      fwdjump[fwindex++] = locptr;
699                   }
700                }
701
702             }
703             risc_instruction_word(parm, reg2, reg1);
704          }
705          break;
706       // Should never get here :D
707       default:                                              
708          error("unknown risc opcode type");
709          return(ERROR);
710          break;
711
712    }
713
714    return(0);
715 }
716