1*45699Sbostic /* Aoperand.c 1.2 90/12/04 */ 229622Ssam 3*45699Sbostic #include "align.h" 429622Ssam #define illegal(x) ((look_at->add_modes & x)==0) 529622Ssam #define legal(x) !illegal(x) 629622Ssam 729622Ssam struct oprnd *operand(infop, number) 829622Ssam register process_info *infop; 929622Ssam int number; 1029622Ssam /* 1129622Ssam * Enter with pc pointing to an operand descriptor 1229622Ssam * in the 'text'. Decode the addressing mode, get 1329622Ssam * the effective address and some data from there. 1429622Ssam * Leave pc on the next oerand specifier or opcode. 1529622Ssam * Returns a pointer to a 'decoded operand' structure, 1629622Ssam * actually one of the 4 pre-allocated . 1729622Ssam * 1829622Ssam * This routine should be called in such a sequence 1929622Ssam * that pc will not have to be backed up to get some 2029622Ssam * operand. For example, operand(0) and then operand(1) 2129622Ssam * and then operand(2) is OK. Even operand(0), operand(1), 2229622Ssam * operand(1) is OK. The rule is that operand(N) should not 2329622Ssam * be called before operand(N-1) was. 2429622Ssam * 2529622Ssam ***********************************************************/ 2629622Ssam { 2729622Ssam register struct oprnd *next; 2829622Ssam register struct operand_des *look_at; 2929622Ssam register int header,reg_num,shift_count, displ; 3029622Ssam register int keep_last; 3129622Ssam 3229622Ssam next = &decoded[number]; 3329622Ssam if (number <= last_operand) return(next); 3429622Ssam if (number == last_operand+1) last_operand = number; 3529622Ssam else 3629622Ssam { 3729622Ssam printf ("Wrong sequence of OPERAND calls (alignment code)\n"); 3829622Ssam return (&decoded[number]); 3929622Ssam }; 4029622Ssam look_at = &Table[opCODE].operand[number]; 4129622Ssam next->data2 = 0; /* Prepare for quad fetch */ 4229622Ssam next->length = look_at->length; 4329622Ssam if (look_at->add_modes == Brd) 4429622Ssam { 4529622Ssam next->mode = Add; 4629622Ssam switch(look_at->length) 4729622Ssam { 4829622Ssam case 1: 4929622Ssam displ = get_byte(infop, pc); 5029622Ssam pc++; 5129622Ssam break; 5229622Ssam case 2: 5329622Ssam displ = get_word(infop, pc); 5429622Ssam pc +=2; 5529622Ssam break; 5629622Ssam default: 5729622Ssam printf ("Wrong branch displacement(alignment code)\n"); 5829622Ssam }; 5929622Ssam next->address = pc+displ; 6029622Ssam return(next); 6129622Ssam }; 6229622Ssam 6329622Ssam /* Not branch displacement, real operand */ 6429622Ssam header = get_byte(infop, pc) & 0xff; 6529622Ssam pc++; 6629622Ssam reg_num = header & 0xf; 6729622Ssam switch (header >> 4 & 0xf) { 6829622Ssam case 0: /* Short literals */ 6929622Ssam case 1: 7029622Ssam case 2: 7129622Ssam case 3: 7229622Ssam if (illegal(Lit)) exception(infop, ILL_ADDRMOD); 7329622Ssam next->mode = Imm; 7429622Ssam next->data = header; 7529622Ssam break; 7629622Ssam 7729622Ssam case 4: /* Indexed register */ 7829622Ssam if (illegal(Add) || reg_num==PCOUNTER || reg_num==SPOINTER) 7929622Ssam exception (infop, ILL_ADDRMOD); 8029622Ssam keep_last = last_operand; 8129622Ssam last_operand = number - 1; /* To get real results */ 8229622Ssam next = operand(infop, number); /* Get base address (recursive) */ 8329622Ssam last_operand = keep_last; 8429622Ssam if 8529622Ssam (! (next->mode & Indx)) exception (infop, ILL_ADDRMOD); 8629622Ssam switch (look_at->length) 8729622Ssam { 8829622Ssam case 1: 8929622Ssam shift_count = 0; 9029622Ssam break; 9129622Ssam case 2: 9229622Ssam shift_count = 1; 9329622Ssam break; 9429622Ssam case 4: 9529622Ssam shift_count = 2; 9629622Ssam break; 9729622Ssam case 8: 9829622Ssam shift_count = 3; 9929622Ssam break; 10029622Ssam default: 10129622Ssam printf("Wrong data length in table(alignment code)\n"); 10229622Ssam }; 10329622Ssam next->address += (Register(infop,reg_num) << shift_count); 10429622Ssam next->mode |= (look_at->add_modes & M); /* Set R/W bits */ 10529622Ssam trytoread (infop,next,number); 10629622Ssam break; 10729622Ssam 10829622Ssam case 5: /* Direct register */ 10929622Ssam if (illegal (Dir) || reg_num==PCOUNTER || 11029622Ssam reg_num==SPOINTER && legal(R)) exception (infop, ILL_ADDRMOD); 11129622Ssam next->mode = Dir; 11229622Ssam next->data = Register(infop,reg_num); 11329622Ssam next->mode |= (look_at->add_modes & M); /* Set R/W bits */ 11429622Ssam next->reg_number = reg_num; 11529622Ssam if (look_at->length == 8) 11629622Ssam { 11729622Ssam if (reg_num >= SPOINTER-1 || (reg_num & 1)==1 ) 11829622Ssam exception (infop, ILL_ADDRMOD); 11929622Ssam else next->data2 = Register(infop,reg_num+1); 12029622Ssam }; 12129622Ssam break; 12229622Ssam 12329622Ssam case 6: /* Indirect register */ 12429622Ssam if (illegal(Add) || reg_num==PCOUNTER ) 12529622Ssam exception (infop, ILL_ADDRMOD); 12629622Ssam next->mode = Add; 12729622Ssam next->mode |= (look_at->add_modes & M); /* Set R/W bits */ 12829622Ssam if (reg_num != SPOINTER) next->mode |= Indx; /* (sp) not indexable*/ 12929622Ssam next->reg_number = reg_num; 13029622Ssam next->address = Register(infop,reg_num); 13129622Ssam trytoread (infop,next,number); 13229622Ssam break; 13329622Ssam 13429622Ssam case 7: /* Autodecrement SP */ 13529622Ssam if (illegal(Add) || reg_num!=SPOINTER || look_at->length != 4 || 13629622Ssam legal(R)) exception (infop, ILL_ADDRMOD); 13729622Ssam next->mode = SPmode; /* Implies Add */ 13829622Ssam next->mode |= W; /* Set R/W bits */ 13929622Ssam next->reg_number = SPOINTER; 14029622Ssam next->length = 4; /* Regardless of big table */ 14129622Ssam sp -= 4; 14229622Ssam next->address = sp; 14329622Ssam break; 14429622Ssam 14529622Ssam case 8: /* Immediate or (sp)+ */ 14629622Ssam switch (reg_num) { 14729622Ssam case 8: /* Immediate byte */ 14829622Ssam if (illegal(Imm)) exception (infop, ILL_ADDRMOD); 14929622Ssam next->mode = Imm; 15029622Ssam next->data = get_byte(infop, pc); 15129622Ssam pc++; 15229622Ssam break; 15329622Ssam case 9: /* Immediate word */ 15429622Ssam if (illegal(Imm)) exception (infop, ILL_ADDRMOD); 15529622Ssam next->mode = Imm; 15629622Ssam next->data = get_word(infop, pc); 15729622Ssam pc +=2; 15829622Ssam break; 15929622Ssam case 0xf : /* Immediate longword */ 16029622Ssam if (illegal(Imm)) exception (infop, ILL_ADDRMOD); 16129622Ssam next->mode = Imm; 16229622Ssam next->data = get_longword(infop, pc); 16329622Ssam pc +=4; 16429622Ssam break; 16529622Ssam case 0xe: /* Autoincrement sp */ 16629622Ssam if (illegal(Add) || legal(W) || 16729622Ssam look_at->length != 4) exception (infop, ILL_ADDRMOD); 16829622Ssam next->mode = SPmode; /* Implies Add */ 16929622Ssam next->reg_number = SPOINTER; 17029622Ssam next->address = sp; 17129622Ssam next->data = get_longword(infop, sp); 17229622Ssam next->length = 4; /* Regardless of big table */ 17329622Ssam sp += 4; 17429622Ssam break; 17529622Ssam default: 17629622Ssam exception (infop, ILL_ADDRMOD); 17729622Ssam }; 17829622Ssam if (look_at -> length == 8) /* Quadword fetch,not (sp)+ */ 17929622Ssam { 18029622Ssam next->data2 = next->data; 18129622Ssam if (next->data2 >= 0) next->data = 0; 18229622Ssam else next->data = -1; 18329622Ssam } 18429622Ssam break; 18529622Ssam 18629622Ssam case 9: /* Autoincrement deferred SP or PC */ 18729622Ssam if (reg_num !=PCOUNTER && reg_num !=SPOINTER ) 18829622Ssam exception (infop, ILL_ADDRMOD); 18929622Ssam if (reg_num == PCOUNTER && illegal(Abs) || 19029622Ssam reg_num == SPOINTER && illegal(Add)) 19129622Ssam exception (infop, ILL_ADDRMOD); 19229622Ssam next->mode = Add | (look_at->add_modes & M) | Indx; 19329622Ssam next->address = get_longword (infop, (reg_num == PCOUNTER)?pc : sp ); 19429622Ssam Replace (infop,reg_num, Register(infop,reg_num)+4); 19529622Ssam trytoread (infop,next,number); 19629622Ssam break; 19729622Ssam 19829622Ssam case 0xa: /* Register or PC + byte displacement */ 19929622Ssam if (reg_num != PCOUNTER && illegal(Add) || 20029622Ssam reg_num == PCOUNTER && illegal(Pcrel) ) exception (infop, ILL_ADDRMOD); 20129622Ssam next->mode = Add | (look_at->add_modes & M); 20229622Ssam if (reg_num != SPOINTER && 20329622Ssam look_at->add_modes != PR) next->mode |= Indx; 20429622Ssam displ = get_byte(infop,pc); 20529622Ssam pc++; 20629622Ssam next->address = Register(infop,reg_num)+displ; 20729622Ssam trytoread (infop,next,number); 20829622Ssam break; 20929622Ssam 21029622Ssam case 0xb: /* Same, indirect */ 21129622Ssam if (illegal(Add)) exception (infop, ILL_ADDRMOD); 21229622Ssam next->mode = Add | (look_at->add_modes & M) | Indx; 21329622Ssam displ = get_byte(infop,pc); 21429622Ssam pc++; 21529622Ssam next->address = get_longword(infop, Register(infop,reg_num)+displ); 21629622Ssam trytoread (infop,next,number); 21729622Ssam break; 21829622Ssam 21929622Ssam case 0xc: /* Register or PC + word displacement */ 22029622Ssam if (reg_num != PCOUNTER && illegal(Add) || 22129622Ssam reg_num == PCOUNTER && illegal(Pcrel) ) exception (infop, ILL_ADDRMOD); 22229622Ssam next->mode = Add | (look_at->add_modes & M); 22329622Ssam if (reg_num != SPOINTER && 22429622Ssam look_at->add_modes != PR) next->mode |= Indx; 22529622Ssam displ = get_word(infop,pc); 22629622Ssam pc +=2; 22729622Ssam next->address = Register(infop,reg_num)+displ; 22829622Ssam trytoread (infop,next,number); 22929622Ssam break; 23029622Ssam 23129622Ssam case 0xd: /* Same, indirect */ 23229622Ssam if (illegal(Add)) exception (infop, ILL_ADDRMOD); 23329622Ssam next->mode =Add | (look_at->add_modes & M) | Indx ; 23429622Ssam displ = get_word(infop,pc); 23529622Ssam pc +=2; 23629622Ssam next->address = get_longword (infop,Register(infop,reg_num)+displ); 23729622Ssam trytoread (infop,next,number); 23829622Ssam break; 23929622Ssam 24029622Ssam 24129622Ssam case 0xe: /* Register or PC + longword displacement */ 24229622Ssam if (reg_num != PCOUNTER && illegal(Add) || 24329622Ssam reg_num == PCOUNTER && illegal(Pcrel) ) exception (infop, ILL_ADDRMOD); 24429622Ssam next->mode = Add | (look_at->add_modes & M); 24529622Ssam if (reg_num != SPOINTER && 24629622Ssam look_at->add_modes != PR) next->mode |= Indx; 24729622Ssam displ = get_longword(infop,pc); 24829622Ssam pc += 4; 24929622Ssam next->address = Register(infop,reg_num)+displ; 25029622Ssam trytoread (infop,next,number); 25129622Ssam break; 25229622Ssam 25329622Ssam case 0xf: /* Same, indirect */ 25429622Ssam if (illegal(Add)) exception (infop, ILL_ADDRMOD); 25529622Ssam next->mode = Add | (look_at->add_modes & M) | Indx; 25629622Ssam displ = get_longword(infop,pc); 25729622Ssam pc +=4; 25829622Ssam next->address = get_longword(infop, Register(infop,reg_num)+displ); 25929622Ssam trytoread (infop,next,number); 26029622Ssam }; 26129622Ssam return(next); 26229622Ssam } 26329622Ssam 26429622Ssam 26529622Ssam trytoread (infop,pointer,number) 26629622Ssam process_info *infop; 26729622Ssam struct oprnd *pointer; 26829622Ssam int number; 26929622Ssam /* 27029622Ssam /* Receives the opcode operand number and a pointer 27129622Ssam /* to the 'decoded' operand structure. 27229622Ssam /* If it's defined as readable data in the big table, 27329622Ssam /* it returns the data, sign extended. 27429622Ssam /* 27529622Ssam /**********************************************************/ 27629622Ssam 27729622Ssam { 27829622Ssam register struct operand_des *look_at; 27929622Ssam 28029622Ssam 28129622Ssam look_at = &Table[opCODE].operand[number]; 28229622Ssam if (legal(R)) 28329622Ssam switch (look_at->length) 28429622Ssam { 28529622Ssam case 1: 28629622Ssam pointer->data = get_byte (infop,pointer->address); 28729622Ssam break; 28829622Ssam case 2: 28929622Ssam pointer->data = get_word (infop,pointer->address); 29029622Ssam break; 29129622Ssam case 4: 29229622Ssam pointer->data = get_longword (infop,pointer->address); 29329622Ssam break; 29429622Ssam case 8: 29529622Ssam pointer->data = get_longword (infop,pointer->address); 29629622Ssam pointer->data2 = get_longword (infop,pointer->address+4); 29729622Ssam break; 29829622Ssam default: 29929622Ssam printf ("Wrong data length in table (alignment code)\n"); 30029622Ssam }; 30129622Ssam } 302