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
operand(infop,number)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
trytoread(infop,pointer,number)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