Commit | Line | Data |
---|---|---|
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 | ||
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 | } |