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