xref: /original-bsd/sys/tahoe/align/Aoperand.c (revision 4d1ce0b0)
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