1 /* Aoperand.c 1.1 86/07/20 */ 2 3 #include "../tahoealign/align.h" 4 #define illegal(x) ((look_at->add_modes & x)==0) 5 #define legal(x) !illegal(x) 6 7 struct oprnd *operand(infop, number) 8 register process_info *infop; 9 int number; 10 /* 11 * Enter with pc pointing to an operand descriptor 12 * in the 'text'. Decode the addressing mode, get 13 * the effective address and some data from there. 14 * Leave pc on the next oerand specifier or opcode. 15 * Returns a pointer to a 'decoded operand' structure, 16 * actually one of the 4 pre-allocated . 17 * 18 * This routine should be called in such a sequence 19 * that pc will not have to be backed up to get some 20 * operand. For example, operand(0) and then operand(1) 21 * and then operand(2) is OK. Even operand(0), operand(1), 22 * operand(1) is OK. The rule is that operand(N) should not 23 * be called before operand(N-1) was. 24 * 25 ***********************************************************/ 26 { 27 register struct oprnd *next; 28 register struct operand_des *look_at; 29 register int header,reg_num,shift_count, displ; 30 register int keep_last; 31 32 next = &decoded[number]; 33 if (number <= last_operand) return(next); 34 if (number == last_operand+1) last_operand = number; 35 else 36 { 37 printf ("Wrong sequence of OPERAND calls (alignment code)\n"); 38 return (&decoded[number]); 39 }; 40 look_at = &Table[opCODE].operand[number]; 41 next->data2 = 0; /* Prepare for quad fetch */ 42 next->length = look_at->length; 43 if (look_at->add_modes == Brd) 44 { 45 next->mode = Add; 46 switch(look_at->length) 47 { 48 case 1: 49 displ = get_byte(infop, pc); 50 pc++; 51 break; 52 case 2: 53 displ = get_word(infop, pc); 54 pc +=2; 55 break; 56 default: 57 printf ("Wrong branch displacement(alignment code)\n"); 58 }; 59 next->address = pc+displ; 60 return(next); 61 }; 62 63 /* Not branch displacement, real operand */ 64 header = get_byte(infop, pc) & 0xff; 65 pc++; 66 reg_num = header & 0xf; 67 switch (header >> 4 & 0xf) { 68 case 0: /* Short literals */ 69 case 1: 70 case 2: 71 case 3: 72 if (illegal(Lit)) exception(infop, ILL_ADDRMOD); 73 next->mode = Imm; 74 next->data = header; 75 break; 76 77 case 4: /* Indexed register */ 78 if (illegal(Add) || reg_num==PCOUNTER || reg_num==SPOINTER) 79 exception (infop, ILL_ADDRMOD); 80 keep_last = last_operand; 81 last_operand = number - 1; /* To get real results */ 82 next = operand(infop, number); /* Get base address (recursive) */ 83 last_operand = keep_last; 84 if 85 (! (next->mode & Indx)) exception (infop, ILL_ADDRMOD); 86 switch (look_at->length) 87 { 88 case 1: 89 shift_count = 0; 90 break; 91 case 2: 92 shift_count = 1; 93 break; 94 case 4: 95 shift_count = 2; 96 break; 97 case 8: 98 shift_count = 3; 99 break; 100 default: 101 printf("Wrong data length in table(alignment code)\n"); 102 }; 103 next->address += (Register(infop,reg_num) << shift_count); 104 next->mode |= (look_at->add_modes & M); /* Set R/W bits */ 105 trytoread (infop,next,number); 106 break; 107 108 case 5: /* Direct register */ 109 if (illegal (Dir) || reg_num==PCOUNTER || 110 reg_num==SPOINTER && legal(R)) exception (infop, ILL_ADDRMOD); 111 next->mode = Dir; 112 next->data = Register(infop,reg_num); 113 next->mode |= (look_at->add_modes & M); /* Set R/W bits */ 114 next->reg_number = reg_num; 115 if (look_at->length == 8) 116 { 117 if (reg_num >= SPOINTER-1 || (reg_num & 1)==1 ) 118 exception (infop, ILL_ADDRMOD); 119 else next->data2 = Register(infop,reg_num+1); 120 }; 121 break; 122 123 case 6: /* Indirect register */ 124 if (illegal(Add) || reg_num==PCOUNTER ) 125 exception (infop, ILL_ADDRMOD); 126 next->mode = Add; 127 next->mode |= (look_at->add_modes & M); /* Set R/W bits */ 128 if (reg_num != SPOINTER) next->mode |= Indx; /* (sp) not indexable*/ 129 next->reg_number = reg_num; 130 next->address = Register(infop,reg_num); 131 trytoread (infop,next,number); 132 break; 133 134 case 7: /* Autodecrement SP */ 135 if (illegal(Add) || reg_num!=SPOINTER || look_at->length != 4 || 136 legal(R)) exception (infop, ILL_ADDRMOD); 137 next->mode = SPmode; /* Implies Add */ 138 next->mode |= W; /* Set R/W bits */ 139 next->reg_number = SPOINTER; 140 next->length = 4; /* Regardless of big table */ 141 sp -= 4; 142 next->address = sp; 143 break; 144 145 case 8: /* Immediate or (sp)+ */ 146 switch (reg_num) { 147 case 8: /* Immediate byte */ 148 if (illegal(Imm)) exception (infop, ILL_ADDRMOD); 149 next->mode = Imm; 150 next->data = get_byte(infop, pc); 151 pc++; 152 break; 153 case 9: /* Immediate word */ 154 if (illegal(Imm)) exception (infop, ILL_ADDRMOD); 155 next->mode = Imm; 156 next->data = get_word(infop, pc); 157 pc +=2; 158 break; 159 case 0xf : /* Immediate longword */ 160 if (illegal(Imm)) exception (infop, ILL_ADDRMOD); 161 next->mode = Imm; 162 next->data = get_longword(infop, pc); 163 pc +=4; 164 break; 165 case 0xe: /* Autoincrement sp */ 166 if (illegal(Add) || legal(W) || 167 look_at->length != 4) exception (infop, ILL_ADDRMOD); 168 next->mode = SPmode; /* Implies Add */ 169 next->reg_number = SPOINTER; 170 next->address = sp; 171 next->data = get_longword(infop, sp); 172 next->length = 4; /* Regardless of big table */ 173 sp += 4; 174 break; 175 default: 176 exception (infop, ILL_ADDRMOD); 177 }; 178 if (look_at -> length == 8) /* Quadword fetch,not (sp)+ */ 179 { 180 next->data2 = next->data; 181 if (next->data2 >= 0) next->data = 0; 182 else next->data = -1; 183 } 184 break; 185 186 case 9: /* Autoincrement deferred SP or PC */ 187 if (reg_num !=PCOUNTER && reg_num !=SPOINTER ) 188 exception (infop, ILL_ADDRMOD); 189 if (reg_num == PCOUNTER && illegal(Abs) || 190 reg_num == SPOINTER && illegal(Add)) 191 exception (infop, ILL_ADDRMOD); 192 next->mode = Add | (look_at->add_modes & M) | Indx; 193 next->address = get_longword (infop, (reg_num == PCOUNTER)?pc : sp ); 194 Replace (infop,reg_num, Register(infop,reg_num)+4); 195 trytoread (infop,next,number); 196 break; 197 198 case 0xa: /* Register or PC + byte displacement */ 199 if (reg_num != PCOUNTER && illegal(Add) || 200 reg_num == PCOUNTER && illegal(Pcrel) ) exception (infop, ILL_ADDRMOD); 201 next->mode = Add | (look_at->add_modes & M); 202 if (reg_num != SPOINTER && 203 look_at->add_modes != PR) next->mode |= Indx; 204 displ = get_byte(infop,pc); 205 pc++; 206 next->address = Register(infop,reg_num)+displ; 207 trytoread (infop,next,number); 208 break; 209 210 case 0xb: /* Same, indirect */ 211 if (illegal(Add)) exception (infop, ILL_ADDRMOD); 212 next->mode = Add | (look_at->add_modes & M) | Indx; 213 displ = get_byte(infop,pc); 214 pc++; 215 next->address = get_longword(infop, Register(infop,reg_num)+displ); 216 trytoread (infop,next,number); 217 break; 218 219 case 0xc: /* Register or PC + word displacement */ 220 if (reg_num != PCOUNTER && illegal(Add) || 221 reg_num == PCOUNTER && illegal(Pcrel) ) exception (infop, ILL_ADDRMOD); 222 next->mode = Add | (look_at->add_modes & M); 223 if (reg_num != SPOINTER && 224 look_at->add_modes != PR) next->mode |= Indx; 225 displ = get_word(infop,pc); 226 pc +=2; 227 next->address = Register(infop,reg_num)+displ; 228 trytoread (infop,next,number); 229 break; 230 231 case 0xd: /* Same, indirect */ 232 if (illegal(Add)) exception (infop, ILL_ADDRMOD); 233 next->mode =Add | (look_at->add_modes & M) | Indx ; 234 displ = get_word(infop,pc); 235 pc +=2; 236 next->address = get_longword (infop,Register(infop,reg_num)+displ); 237 trytoread (infop,next,number); 238 break; 239 240 241 case 0xe: /* Register or PC + longword displacement */ 242 if (reg_num != PCOUNTER && illegal(Add) || 243 reg_num == PCOUNTER && illegal(Pcrel) ) exception (infop, ILL_ADDRMOD); 244 next->mode = Add | (look_at->add_modes & M); 245 if (reg_num != SPOINTER && 246 look_at->add_modes != PR) next->mode |= Indx; 247 displ = get_longword(infop,pc); 248 pc += 4; 249 next->address = Register(infop,reg_num)+displ; 250 trytoread (infop,next,number); 251 break; 252 253 case 0xf: /* Same, indirect */ 254 if (illegal(Add)) exception (infop, ILL_ADDRMOD); 255 next->mode = Add | (look_at->add_modes & M) | Indx; 256 displ = get_longword(infop,pc); 257 pc +=4; 258 next->address = get_longword(infop, Register(infop,reg_num)+displ); 259 trytoread (infop,next,number); 260 }; 261 return(next); 262 } 263 264 265 trytoread (infop,pointer,number) 266 process_info *infop; 267 struct oprnd *pointer; 268 int number; 269 /* 270 /* Receives the opcode operand number and a pointer 271 /* to the 'decoded' operand structure. 272 /* If it's defined as readable data in the big table, 273 /* it returns the data, sign extended. 274 /* 275 /**********************************************************/ 276 277 { 278 register struct operand_des *look_at; 279 280 281 look_at = &Table[opCODE].operand[number]; 282 if (legal(R)) 283 switch (look_at->length) 284 { 285 case 1: 286 pointer->data = get_byte (infop,pointer->address); 287 break; 288 case 2: 289 pointer->data = get_word (infop,pointer->address); 290 break; 291 case 4: 292 pointer->data = get_longword (infop,pointer->address); 293 break; 294 case 8: 295 pointer->data = get_longword (infop,pointer->address); 296 pointer->data2 = get_longword (infop,pointer->address+4); 297 break; 298 default: 299 printf ("Wrong data length in table (alignment code)\n"); 300 }; 301 } 302