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