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