use new form of suser()
[unix-history] / usr / src / sys / tahoe / align / Aoperand.c
CommitLineData
a4511bbc
SL
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
7struct oprnd *operand(infop, number)
8register process_info *infop;
9int 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
265trytoread (infop,pointer,number)
266process_info *infop;
267struct oprnd *pointer;
268int 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}