-int risccg(int state) {
- unsigned short parm; // Opcode parameters
- unsigned type; // Opcode type
- int reg1; // Register 1
- int reg2; // Register 2
- int val = 0; // Constructed value
- char scratch[80];
- SYM *ccsym;
- SYM *sy;
- int i; // Iterator
- int t, c;
- WORD tdb;
- unsigned locptr = 0; // Address location pointer
- unsigned page_jump = 0; // Memory page jump flag
- VALUE eval; // Expression value
- WORD eattr; // Expression attributes
- SYM *esym; // External symbol involved in expr.
- TOKEN r_expr[EXPRSIZE]; // Expression token list
- WORD defined; // Symbol defined flag
- WORD attrflg;
- int indexed; // Indexed register flag
-
- parm = (WORD)(roptbl[state-3000].parm); // Get opcode parameter and type
- type = roptbl[state-3000].typ;
-
- // Detect whether the opcode parmeter passed determines that the opcode is specific to only one
- // of the RISC processors and ensure it is legal in the current code section.
- // If not then error and return.
- if(((parm & GPUONLY) && rdsp) || ((parm & DSPONLY) && rgpu) ) {
- error("opcode is not valid in this code section");
- return(ERROR);
- }
-
- // Process RISC opcode
- switch(type) {
- // No operand instructions
- // NOP
- case RI_NONE:
- risc_instruction_word(parm, 0, 0);
- break;
- // Single operand instructions (Rd)
- // ABS, MIRROR, NEG, NOT, PACK, RESMAC, SAT8, SAT16, SAT16S, SAT24, SAT32S, UNPACK
- case RI_ONE:
- reg2 = getregister(FU_REGTWO);
- at_eol();
- risc_instruction_word(parm, parm >> 6, reg2);
- break;
- // Two operand instructions (Rs,Rd)
- // ADD, ADDC, AND, CMP, DIV, IMACN, IMULT, IMULTN, MOVEFA, MOVETA, MULT, MMULT,
- // MTOI, NORMI, OR, ROR, SH, SHA, SUB, SUBC, XOR
- case RI_TWO:
- if(parm == 37) altbankok = 1; // MOVEFA
- reg1 = getregister(FU_REGONE);
- CHECK_COMMA;
- if(parm == 36) altbankok = 1; // MOVETA
- reg2 = getregister(FU_REGTWO);
- at_eol();
- risc_instruction_word(parm, reg1, reg2);
- break;
- // Numeric operand (n,Rd) where n = -16..+15
- // CMPQ
- case RI_NUM_15:
- // Numeric operand (n,Rd) where n = 0..31
- // BCLR, BSET, BTST, MOVEQ
- case RI_NUM_31:
- // Numeric operand (n,Rd) where n = 1..32
- // ADDQ, ADDQMOD, ADDQT, SHARQ, SHLQ, SHRQ, SUBQ, SUBQMOD, SUBQT, ROLQ, RORQ
- case RI_NUM_32:
- switch(type) {
- case RI_NUM_15: reg1 = -16; reg2 = 15; attrflg = FU_NUM15; break;
- default:
- case RI_NUM_31: reg1 = 0; reg2 = 31; attrflg = FU_NUM31; break;
- case RI_NUM_32: reg1 = 1; reg2 = 32; attrflg = FU_NUM32; break;
- }
- if(parm & SUB32) attrflg |= FU_SUB32;
- if(*tok == '#') {
- ++tok;
- if(expr(r_expr, &eval, &eattr, &esym) != OK)
- goto malformed;
- else {
- defined = (WORD)(eattr & DEFINED);
- if((challoc - ch_size) < 4)
- chcheck(4L);
- if(!defined) {
- fixup((WORD)(FU_WORD|attrflg), sloc, r_expr);
- reg1 = 0;
- } else {
- if((int)eval < reg1 || (int)eval > reg2) {
- error("constant out of range");
- return(ERROR);
- }
- if(parm & SUB32)
- reg1 = 32 - eval;
- else if(type == RI_NUM_32)
- reg1 = (reg1 == 32) ? 0 : eval;
- else
- reg1 = eval;
- }
- }
- } else goto malformed;
- CHECK_COMMA;
- reg2 = getregister(FU_REGTWO);
- at_eol();
- risc_instruction_word(parm, reg1, reg2);
- break;
- // Move Immediate - n,Rn - n in Second Word
- case RI_MOVEI:
- if(*tok == '#') {
- ++tok;
- if(expr(r_expr, &eval, &eattr, &esym) != OK) {
- malformed:
- error("malformed opcode");
- return(ERROR);
- } else {
- // Opcode tracking for nop padding
- previousop = currentop;
- currentop = parm;
- // JUMP or JR
- if((previousop == 52) || (previousop == 53) && !jpad) {
- warn("NOP inserted before MOVEI instruction.");
- D_word(0xE400);
- }
- tdb = (WORD)(eattr & TDB);
- defined = (WORD)(eattr & DEFINED);
- if((challoc - ch_size) < 4)
- chcheck(4L);
- if(!defined) {
- fixup(FU_LONG|FU_MOVEI, sloc + 2, r_expr);
- eval = 0;
- } else {
- if(tdb) {
- rmark(cursect, sloc + 2, tdb, MLONG|MMOVEI, NULL);
- }
- }
- val = eval;
- // Store the defined flags and value of the movei when used in mjump
- if(mjump_align) {
- mjump_defined = defined;
- mjump_dest = val;
- }
- }
- } else goto malformed;
- ++tok;
- reg2 = getregister(FU_REGTWO);
- at_eol();
- D_word((((parm & 0x3F) << 10) + reg2));
- val = ((val >> 16) & 0x0000FFFF) | ((val << 16) & 0xFFFF0000);
- D_long(val);
- break;
- case RI_MOVE: // PC,Rd or Rs,Rd
- if(*tok == KW_PC) {
- parm = 51;
- reg1 = 0;
- ++tok;
- } else {
- parm = 34;
- reg1 = getregister(FU_REGONE);
- }
- CHECK_COMMA;
- reg2 = getregister(FU_REGTWO);
- at_eol();
- risc_instruction_word(parm, reg1, reg2);
- break;
- // (Rn),Rn = 41 / (R14/R15+n),Rn = 43/44 / (R14/R15+Rn),Rn = 58/59
- case RI_LOAD:
- indexed = 0;
- parm = 41;
- if(*tok != '(') goto malformed;
- ++tok;
- if((*tok == KW_R14 || *tok == KW_R15) && (*(tok+1) != ')'))
- indexed = (*tok - KW_R0);
- if(*tok == SYMBOL) {
- sy = lookup((char *)tok[1], LABEL, 0);
- if(!sy) {
- error(reg_err);
- return(ERROR);
- }
- if(sy->sattre & EQUATEDREG)
- if(((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15) && (*(tok+2) != ')')) {
- indexed = (sy->svalue & 0x1F);
- ++tok;
- }
- }
- if(!indexed) {
- reg1 = getregister(FU_REGONE);
- } else {
- reg1 = indexed;
- indexed = 0;
- ++tok;
- if(*tok == '+') {
- parm = (WORD)(reg1 - 14 + 58);
- tok++;
- if(*tok >= KW_R0 && *tok <= KW_R31) {
- indexed = 1;
- }
- if(*tok == SYMBOL) {
- sy = lookup((char *)tok[1], LABEL, 0);
- if(!sy) {
- error(reg_err);
- return(ERROR);
- }
- if(sy->sattre & EQUATEDREG) {
- indexed = 1;
- }
- }
- if(indexed) {
- reg1 = getregister(FU_REGONE);
- } else {
- if(expr(r_expr, &eval, &eattr, &esym) != OK) {
- goto malformed;
- } else {
- tdb = (WORD)(eattr & TDB);
- defined = (WORD)(eattr & DEFINED);
- if((challoc - ch_size) < 4)
- chcheck(4L);
- if(!defined) {
- error("constant expected");
- return(ERROR);
- //fixup(FU_WORD|FU_REGONE, sloc, r_expr);
- reg1 = 0;
- } else {
- reg1 = eval;
- if(reg1 == 0) {
- reg1 = 14+(parm-58);
- parm = 41;
- warn("NULL offset removed");
- } else {
- if(reg1 < 1 || reg1 > 32) {
- error("constant out of range");
- return(ERROR);
- }
- if(reg1 == 32) reg1 = 0;
- parm = (WORD)(parm - 58 + 43);
- }
- }
- }
- }
- } else {
- reg1 = getregister(FU_REGONE);
- }
- }
- if(*tok != ')') goto malformed;
- ++tok;
- CHECK_COMMA;
- reg2 = getregister(FU_REGTWO);
- at_eol();
- risc_instruction_word(parm, reg1, reg2);
- break;
- // Rn,(Rn) = 47 / Rn,(R14/R15+n) = 49/50 / Rn,(R14/R15+Rn) = 60/61
- case RI_STORE:
- parm = 47;
- reg1 = getregister(FU_REGONE);
- CHECK_COMMA;
- if(*tok != '(') goto malformed;
- ++tok;
- indexed = 0;
- if((*tok == KW_R14 || *tok == KW_R15) && (*(tok+1) != ')'))
- indexed = (*tok - KW_R0);
- if(*tok == SYMBOL) {
- sy = lookup((char *)tok[1], LABEL, 0);
- if(!sy) {
- error(reg_err);
- return(ERROR);
- }
- if(sy->sattre & EQUATEDREG)
- if(((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15) && (*(tok+2) != ')')) {
- indexed = (sy->svalue & 0x1F);
- ++tok;
- }
- }
- if(!indexed) {
- reg2 = getregister(FU_REGTWO);
- } else {
- reg2 = indexed;
- indexed = 0;
- ++tok;
- if(*tok == '+') {
- parm = (WORD)(reg2 - 14 + 60);
- tok++;
- if(*tok >= KW_R0 && *tok <= KW_R31) {
- indexed = 1;
- }
- if(*tok == SYMBOL) {
- sy = lookup((char *)tok[1], LABEL, 0);
- if(!sy) {
- error(reg_err);
- return(ERROR);
- }
- if(sy->sattre & EQUATEDREG) {
- indexed = 1;
- }
- }
- if(indexed) {
- reg2 = getregister(FU_REGTWO);
- } else {
- if(expr(r_expr, &eval, &eattr, &esym) != OK) {
- goto malformed;
- } else {
- tdb = (WORD)(eattr & TDB);
- defined = (WORD)(eattr & DEFINED);
- if((challoc - ch_size) < 4)
- chcheck(4L);
- if(!defined) {
- fixup(FU_WORD|FU_REGTWO, sloc, r_expr);
- reg2 = 0;
- } else {
- reg2 = eval;
- if(reg2 == 0 ) {
- reg2 = 14+(parm-60);
- parm = 47;
- warn("NULL offset removed");
- } else {
- if(reg2 < 1 || reg2 > 32) {
- error("constant out of range");
- return(ERROR);
- }
- if(reg2 == 32) reg2 = 0;
- parm = (WORD)(parm - 60 + 49);
- }
- }
- }
- }
- } else {
- reg2 = getregister(FU_REGTWO);
- }
- }
- if(*tok != ')') goto malformed;
- ++tok;
- at_eol();
- risc_instruction_word(parm, reg2, reg1);
- break;
- // LOADB/LOADP/LOADW (Rn),Rn
- case RI_LOADN:
- if(*tok != '(') goto malformed;
- ++tok;
- reg1 = getregister(FU_REGONE);
- if(*tok != ')') goto malformed;
- ++tok;
- CHECK_COMMA;
- reg2 = getregister(FU_REGTWO);
- at_eol();
- risc_instruction_word(parm, reg1, reg2);
- break;
- // STOREB/STOREP/STOREW Rn,(Rn)
- case RI_STOREN:
- reg1 = getregister(FU_REGONE);
- CHECK_COMMA;
- if(*tok != '(') goto malformed;
- ++tok;
- reg2 = getregister(FU_REGTWO);
- if(*tok != ')') goto malformed;
- ++tok;
- at_eol();
- risc_instruction_word(parm, reg2, reg1);
- break;
- case RI_JR: // Jump Relative - cc,n - n=-16..+15 words, reg2=cc
- case RI_JUMP: // Jump Absolute - cc,(Rs) - reg2=cc
- // Check to see if there is a comma in the token string. If not then the JR or JUMP should
- // default to 0, Jump Always
- t = i = c = 0;
- while(t != EOL) {
- t = *(tok + i);
- if(t == ',') c = 1;
- i++;
- }
- if(c) { // Comma present in token string
- if(*tok == CONST) { // CC using a constant number
- ++tok;
- val = *tok;
- ++tok;
- CHECK_COMMA;
- } else if(*tok == SYMBOL) {
- val = 99;
- for(i = 0; i < MAXINTERNCC; i++) {
- strcpy(scratch, (char *)tok[1]);
- strtoupper(scratch);
- if(!strcmp(condname[i], scratch))
- val = condnumber[i];
- }
- if(val == 99) {
- ccsym = lookup((char *)tok[1], LABEL, 0);
- if(ccsym && (ccsym->sattre & EQUATEDCC) && !(ccsym->sattre & UNDEF_CC)) {
- val = ccsym->svalue;
- } else {
- error("unknown condition code");
- return(ERROR);
- }
- }
- tok += 2;
- CHECK_COMMA;
- } else if(*tok == '(') {
- val = 0; // Jump always
- }
- } else {
- val = 0; // Jump always
- }
-
- if(val < 0 || val > 31) {
- error("condition constant out of range");
- return(ERROR);
- } else {
- reg1 = val; // Store condition code
- }
- if(type == RI_JR) { // JR cc,n
- if(expr(r_expr, &eval, &eattr, &esym) != OK)
- goto malformed;
- else {
- tdb = (WORD)(eattr & TDB);
- defined = (WORD)(eattr & DEFINED);
- if((challoc - ch_size) < 4)
- chcheck(4L);
- if(!defined) {
- if(in_main) {
- fixup(FU_WORD|FU_MJR, sloc, r_expr);
- } else {
- fixup(FU_WORD|FU_JR, sloc, r_expr);
- }
- reg2 = 0;
- } else {
- val = eval;
- if(orgactive) {
- reg2 = ((int)(val - (orgaddr + 2))) / 2;
- if((reg2 < -16) || (reg2 > 15))
- error("PC relative overflow");
- locptr = orgaddr;
- } else {
- reg2 = ((int)(val - (sloc + 2))) / 2;
- if((reg2 < -16) || (reg2 > 15))
- error("PC relative overflow");
- locptr = sloc;
- }
- }
- if(in_main) {
- if(defined) {
- if(((locptr >= 0xF03000) && (locptr < 0xF04000) && (val < 0xF03000)) ||
- ((val >= 0xF03000) && (val < 0xF04000) && (locptr < 0xF03000)) ) {
- warn("* cannot jump relative between main memory and local gpu ram");
- } else {
- page_jump = (locptr & 0xFFFFFF00) - (val & 0xFFFFFF00);
- if(page_jump) {
- if(val % 4) {
- warn("* destination address not aligned for long page jump relative, "
- "insert a \'nop\' before the destination label/address");
- }
- } else {
- if((val - 2) % 4) {
- warn("* destination address not aligned for short page jump relative, "
- "insert a \'nop\' before the destination label/address");
- }
- }
- }
- }
- }
- }
- risc_instruction_word(parm, reg2, reg1);
- } else { // JUMP cc, (Rn)
- if(*tok != '(') goto malformed;
- ++tok;
- reg2 = getregister(FU_REGTWO);
- if(*tok != ')') goto malformed;
- ++tok;
- at_eol();
- if(in_main) {
- if(!mjump_align) {
- warn("* \'jump\' is not recommended for .gpumain as destination addresses "
- "cannot be validated for alignment, use \'mjump\'");
- locptr = (orgactive) ? orgaddr : sloc;
- if(locptr % 4) {
- warn("* source address not aligned for long or short jump, "
- "insert a \'nop\' before the \'jump\'");
- }
- } else {
- if(mjump_defined) {
- locptr = (orgactive) ? orgaddr : sloc;
- page_jump = (locptr & 0xFFFFFF00) - (mjump_dest & 0xFFFFFF00);
- if(page_jump) {
- if(mjump_dest % 4) {
- warn("* destination address not aligned for long page jump, "
- "insert a \'nop\' before the destination label/address");
- }
- } else {
- if(!(mjump_dest & 0x0000000F) || ((mjump_dest - 2) % 4)) {
- warn("* destination address not aligned for short page jump, "
- "insert a \'nop\' before the destination label/address");
- }
- }
- } else {
- locptr = (orgactive) ? orgaddr : sloc;
- fwdjump[fwindex++] = locptr;
- }
- }
-
- }
- risc_instruction_word(parm, reg2, reg1);
- }
- break;
- // Should never get here :D
- default:
- error("unknown risc opcode type");
- return(ERROR);
- break;
-
- }
-
- return(0);