xref: /csrg-svn/sys/tahoe/align/Aoperand.c (revision 45760)
1*45760Sbostic /*-
2*45760Sbostic  * Copyright (c) 1986 The Regents of the University of California.
3*45760Sbostic  * All rights reserved.
4*45760Sbostic  *
5*45760Sbostic  * This code is derived from software contributed to Berkeley by
6*45760Sbostic  * Computer Consoles Inc.
7*45760Sbostic  *
8*45760Sbostic  * %sccs.include.redist.c%
9*45760Sbostic  *
10*45760Sbostic  *	@(#)Aoperand.c	7.1 (Berkeley) 12/06/90
11*45760Sbostic  */
1229622Ssam 
1345699Sbostic #include	"align.h"
1429622Ssam #define	illegal(x) ((look_at->add_modes & x)==0)
1529622Ssam #define	legal(x) !illegal(x)
1629622Ssam 
operand(infop,number)1729622Ssam struct oprnd *operand(infop, number)
1829622Ssam register process_info *infop;
1929622Ssam int	number;
2029622Ssam /*
2129622Ssam  *	Enter with pc pointing to an operand descriptor
2229622Ssam  *	in the 'text'. Decode the addressing mode, get
2329622Ssam  *	the effective address and some data from there.
2429622Ssam  *	Leave pc on the next oerand specifier or opcode.
2529622Ssam  *	Returns a pointer to a 'decoded operand' structure,
2629622Ssam  *	actually one of the 4 pre-allocated .
2729622Ssam  *
2829622Ssam  *	This routine should be called in such a sequence
2929622Ssam  *	that pc will not have to be backed up to get some
3029622Ssam  *	operand. For example, operand(0) and then operand(1)
3129622Ssam  *	and then operand(2) is OK. Even operand(0), operand(1),
3229622Ssam  *	operand(1) is OK. The rule is that operand(N) should not
3329622Ssam  *	be called before operand(N-1) was.
3429622Ssam  *
3529622Ssam  ***********************************************************/
3629622Ssam {
3729622Ssam 	register struct oprnd *next;
3829622Ssam 	register struct operand_des *look_at;
3929622Ssam 	register int header,reg_num,shift_count, displ;
4029622Ssam 	register int keep_last;
4129622Ssam 
4229622Ssam 	next = &decoded[number];
4329622Ssam 	if (number <= last_operand) return(next);
4429622Ssam 	if (number == last_operand+1) last_operand = number;
4529622Ssam 	else
4629622Ssam 	{
4729622Ssam 		printf ("Wrong sequence of OPERAND calls (alignment code)\n");
4829622Ssam 		return (&decoded[number]);
4929622Ssam 	};
5029622Ssam 	look_at  = &Table[opCODE].operand[number];
5129622Ssam 	next->data2 = 0;		/* Prepare for quad fetch */
5229622Ssam 	next->length = look_at->length;
5329622Ssam 	if (look_at->add_modes == Brd)
5429622Ssam 	{
5529622Ssam 		next->mode = Add;
5629622Ssam 		switch(look_at->length)
5729622Ssam 		{
5829622Ssam 		case 1:
5929622Ssam 			displ = get_byte(infop, pc);
6029622Ssam 			pc++;
6129622Ssam 			break;
6229622Ssam 		case 2:
6329622Ssam 			displ = get_word(infop, pc);
6429622Ssam 			pc +=2;
6529622Ssam 			break;
6629622Ssam 		default:
6729622Ssam 			printf ("Wrong branch displacement(alignment code)\n");
6829622Ssam 		};
6929622Ssam 		next->address = pc+displ;
7029622Ssam 		return(next);
7129622Ssam 	};
7229622Ssam 
7329622Ssam 	/* Not branch displacement, real operand */
7429622Ssam 	header = get_byte(infop, pc) & 0xff;
7529622Ssam 	pc++;
7629622Ssam 	reg_num = header & 0xf;
7729622Ssam 	switch (header >> 4 & 0xf) {
7829622Ssam 	case 0: 			/* Short literals */
7929622Ssam 	case 1:
8029622Ssam 	case 2:
8129622Ssam 	case 3:
8229622Ssam 		if (illegal(Lit)) exception(infop, ILL_ADDRMOD);
8329622Ssam 		next->mode = Imm;
8429622Ssam 		next->data = header;
8529622Ssam 		break;
8629622Ssam 
8729622Ssam 	case 4: 			/* Indexed register */
8829622Ssam 		if (illegal(Add) || reg_num==PCOUNTER || reg_num==SPOINTER)
8929622Ssam 			exception (infop, ILL_ADDRMOD);
9029622Ssam 		keep_last = last_operand;
9129622Ssam 		last_operand = number - 1; /* To get real results */
9229622Ssam 		next = operand(infop, number);   /* Get base address (recursive) */
9329622Ssam 		last_operand = keep_last;
9429622Ssam 		if
9529622Ssam 		    (! (next->mode & Indx)) exception (infop, ILL_ADDRMOD);
9629622Ssam 		switch (look_at->length)
9729622Ssam 		{
9829622Ssam 		case 1:
9929622Ssam 			shift_count = 0;
10029622Ssam 			break;
10129622Ssam 		case 2:
10229622Ssam 			shift_count = 1;
10329622Ssam 			break;
10429622Ssam 		case 4:
10529622Ssam 			shift_count = 2;
10629622Ssam 			break;
10729622Ssam 		case 8:
10829622Ssam 			shift_count = 3;
10929622Ssam 			break;
11029622Ssam 		default:
11129622Ssam 			printf("Wrong data length in table(alignment code)\n");
11229622Ssam 		};
11329622Ssam 		next->address += (Register(infop,reg_num) << shift_count);
11429622Ssam 		next->mode |= (look_at->add_modes & M); /* Set R/W bits */
11529622Ssam 		trytoread (infop,next,number);
11629622Ssam 		break;
11729622Ssam 
11829622Ssam 	case 5: 			/* Direct register */
11929622Ssam 		if (illegal (Dir) || reg_num==PCOUNTER ||
12029622Ssam 		    reg_num==SPOINTER && legal(R)) exception (infop, ILL_ADDRMOD);
12129622Ssam 		next->mode = Dir;
12229622Ssam 		next->data = Register(infop,reg_num);
12329622Ssam 		next->mode |= (look_at->add_modes & M); /* Set R/W bits */
12429622Ssam 		next->reg_number = reg_num;
12529622Ssam 		if (look_at->length == 8)
12629622Ssam 		{
12729622Ssam 			if (reg_num >= SPOINTER-1 || (reg_num & 1)==1 )
12829622Ssam 				exception (infop, ILL_ADDRMOD);
12929622Ssam 			else next->data2 = Register(infop,reg_num+1);
13029622Ssam 		};
13129622Ssam 		break;
13229622Ssam 
13329622Ssam 	case 6: 			/* Indirect register */
13429622Ssam 		if (illegal(Add) || reg_num==PCOUNTER )
13529622Ssam 			exception (infop, ILL_ADDRMOD);
13629622Ssam 		next->mode = Add;
13729622Ssam 		next->mode |= (look_at->add_modes & M); /* Set R/W bits */
13829622Ssam 		if (reg_num != SPOINTER) next->mode |= Indx;  /* (sp) not indexable*/
13929622Ssam 		next->reg_number = reg_num;
14029622Ssam 		next->address = Register(infop,reg_num);
14129622Ssam 		trytoread (infop,next,number);
14229622Ssam 		break;
14329622Ssam 
14429622Ssam 	case 7: 			/* Autodecrement SP */
14529622Ssam 		if (illegal(Add) || reg_num!=SPOINTER || look_at->length != 4 ||
14629622Ssam 		    legal(R)) exception (infop, ILL_ADDRMOD);
14729622Ssam 		next->mode = SPmode;  	/* Implies Add */
14829622Ssam 		next->mode |= W; 	/* Set R/W bits */
14929622Ssam 		next->reg_number = SPOINTER;
15029622Ssam 		next->length = 4;	/* Regardless of big table */
15129622Ssam 		sp -= 4;
15229622Ssam 		next->address = sp;
15329622Ssam 		break;
15429622Ssam 
15529622Ssam 	case 8: 			/* Immediate or (sp)+ */
15629622Ssam 		switch (reg_num) {
15729622Ssam 		case 8: 		/* Immediate byte */
15829622Ssam 			if (illegal(Imm)) exception (infop, ILL_ADDRMOD);
15929622Ssam 			next->mode = Imm;
16029622Ssam 			next->data = get_byte(infop, pc);
16129622Ssam 			pc++;
16229622Ssam 			break;
16329622Ssam 		case 9: 		/* Immediate word */
16429622Ssam 			if (illegal(Imm)) exception (infop, ILL_ADDRMOD);
16529622Ssam 			next->mode = Imm;
16629622Ssam 			next->data = get_word(infop, pc);
16729622Ssam 			pc +=2;
16829622Ssam 			break;
16929622Ssam 		case 0xf : 		/* Immediate longword */
17029622Ssam 			if (illegal(Imm)) exception (infop, ILL_ADDRMOD);
17129622Ssam 			next->mode = Imm;
17229622Ssam 			next->data = get_longword(infop, pc);
17329622Ssam 			pc +=4;
17429622Ssam 			break;
17529622Ssam 		case 0xe: 		/* Autoincrement sp */
17629622Ssam 			if (illegal(Add) || legal(W) ||
17729622Ssam 				look_at->length != 4) exception (infop, ILL_ADDRMOD);
17829622Ssam 			next->mode = SPmode;	/* Implies Add */
17929622Ssam 			next->reg_number = SPOINTER;
18029622Ssam 			next->address = sp;
18129622Ssam 		        next->data = get_longword(infop, sp);
18229622Ssam 			next->length = 4;	/* Regardless of big table */
18329622Ssam 			sp += 4;
18429622Ssam 			break;
18529622Ssam 		default:
18629622Ssam 			exception (infop, ILL_ADDRMOD);
18729622Ssam 		};
18829622Ssam 		if (look_at -> length == 8)	/* Quadword fetch,not (sp)+ */
18929622Ssam 		{
19029622Ssam 			next->data2 = next->data;
19129622Ssam 			if (next->data2 >= 0) next->data = 0;
19229622Ssam 			else next->data = -1;
19329622Ssam 		}
19429622Ssam 		break;
19529622Ssam 
19629622Ssam 	case 9: 			/* Autoincrement deferred SP or PC */
19729622Ssam 		if (reg_num !=PCOUNTER && reg_num !=SPOINTER )
19829622Ssam 			exception (infop, ILL_ADDRMOD);
19929622Ssam 		if (reg_num == PCOUNTER && illegal(Abs) ||
20029622Ssam 		    reg_num == SPOINTER && illegal(Add))
20129622Ssam 			exception (infop, ILL_ADDRMOD);
20229622Ssam 		next->mode = Add | (look_at->add_modes & M) | Indx;
20329622Ssam 		next->address = get_longword (infop, (reg_num == PCOUNTER)?pc : sp );
20429622Ssam 		Replace (infop,reg_num, Register(infop,reg_num)+4);
20529622Ssam 		trytoread (infop,next,number);
20629622Ssam 		break;
20729622Ssam 
20829622Ssam 	case 0xa:			/* Register or PC + byte displacement */
20929622Ssam 		if (reg_num != PCOUNTER && illegal(Add) ||
21029622Ssam 		    reg_num == PCOUNTER && illegal(Pcrel) ) exception (infop, ILL_ADDRMOD);
21129622Ssam 		next->mode = Add | (look_at->add_modes & M);
21229622Ssam 		if (reg_num != SPOINTER &&
21329622Ssam 			look_at->add_modes != PR) next->mode |= Indx;
21429622Ssam 		displ = get_byte(infop,pc);
21529622Ssam 		pc++;
21629622Ssam 		next->address = Register(infop,reg_num)+displ;
21729622Ssam 		trytoread (infop,next,number);
21829622Ssam 		break;
21929622Ssam 
22029622Ssam 	case 0xb:			/* Same, indirect */
22129622Ssam 		if (illegal(Add)) exception (infop, ILL_ADDRMOD);
22229622Ssam 		next->mode = Add | (look_at->add_modes & M) | Indx;
22329622Ssam 		displ = get_byte(infop,pc);
22429622Ssam 		pc++;
22529622Ssam 		next->address = get_longword(infop, Register(infop,reg_num)+displ);
22629622Ssam 		trytoread (infop,next,number);
22729622Ssam 		break;
22829622Ssam 
22929622Ssam 	case 0xc:			/* Register or PC + word displacement */
23029622Ssam 		if (reg_num != PCOUNTER && illegal(Add) ||
23129622Ssam 		    reg_num == PCOUNTER && illegal(Pcrel) ) exception (infop, ILL_ADDRMOD);
23229622Ssam 		next->mode = Add | (look_at->add_modes & M);
23329622Ssam 		if (reg_num != SPOINTER &&
23429622Ssam 			look_at->add_modes != PR) next->mode |= Indx;
23529622Ssam 		displ = get_word(infop,pc);
23629622Ssam 		pc +=2;
23729622Ssam 		next->address = Register(infop,reg_num)+displ;
23829622Ssam 		trytoread (infop,next,number);
23929622Ssam 		break;
24029622Ssam 
24129622Ssam 	case 0xd:			/* Same, indirect */
24229622Ssam 		if (illegal(Add)) exception (infop, ILL_ADDRMOD);
24329622Ssam 		next->mode =Add | (look_at->add_modes & M) | Indx ;
24429622Ssam 		displ = get_word(infop,pc);
24529622Ssam 		pc +=2;
24629622Ssam 		next->address = get_longword (infop,Register(infop,reg_num)+displ);
24729622Ssam 		trytoread (infop,next,number);
24829622Ssam 		break;
24929622Ssam 
25029622Ssam 
25129622Ssam 	case 0xe:		/* Register or PC + longword displacement */
25229622Ssam 		if (reg_num != PCOUNTER && illegal(Add) ||
25329622Ssam 		    reg_num == PCOUNTER && illegal(Pcrel) ) exception (infop, ILL_ADDRMOD);
25429622Ssam 		next->mode = Add | (look_at->add_modes & M);
25529622Ssam 		if (reg_num != SPOINTER &&
25629622Ssam 			look_at->add_modes != PR) next->mode |= Indx;
25729622Ssam 		displ = get_longword(infop,pc);
25829622Ssam 		pc += 4;
25929622Ssam 		next->address = Register(infop,reg_num)+displ;
26029622Ssam 		trytoread (infop,next,number);
26129622Ssam 		break;
26229622Ssam 
26329622Ssam 	case 0xf:			/* Same, indirect */
26429622Ssam 		if (illegal(Add)) exception (infop, ILL_ADDRMOD);
26529622Ssam 		next->mode = Add | (look_at->add_modes & M) | Indx;
26629622Ssam 		displ = get_longword(infop,pc);
26729622Ssam 		pc +=4;
26829622Ssam 		next->address = get_longword(infop, Register(infop,reg_num)+displ);
26929622Ssam 		trytoread (infop,next,number);
27029622Ssam 	};
27129622Ssam 	return(next);
27229622Ssam }
27329622Ssam 
27429622Ssam 
trytoread(infop,pointer,number)27529622Ssam trytoread (infop,pointer,number)
27629622Ssam process_info	*infop;
27729622Ssam struct oprnd	*pointer;
27829622Ssam int		number;
27929622Ssam /*
28029622Ssam /*	Receives the opcode operand number and a pointer
28129622Ssam /*	to the 'decoded' operand structure.
28229622Ssam /*	If it's defined as readable data in the big table,
28329622Ssam /*	it returns the data, sign extended.
28429622Ssam /*
28529622Ssam /**********************************************************/
28629622Ssam 
28729622Ssam {
28829622Ssam 	register struct operand_des *look_at;
28929622Ssam 
29029622Ssam 
29129622Ssam 	look_at  = &Table[opCODE].operand[number];
29229622Ssam 	if (legal(R))
29329622Ssam 	switch (look_at->length)
29429622Ssam 	{
29529622Ssam 	case 1:
29629622Ssam 		pointer->data = get_byte (infop,pointer->address);
29729622Ssam 		break;
29829622Ssam 	case 2:
29929622Ssam 		pointer->data = get_word (infop,pointer->address);
30029622Ssam 		break;
30129622Ssam 	case 4:
30229622Ssam 		pointer->data = get_longword (infop,pointer->address);
30329622Ssam 		break;
30429622Ssam 	case 8:
30529622Ssam 		pointer->data = get_longword (infop,pointer->address);
30629622Ssam 		pointer->data2 = get_longword (infop,pointer->address+4);
30729622Ssam 		break;
30829622Ssam 	default:
30929622Ssam 		printf ("Wrong data length in table (alignment code)\n");
31029622Ssam 	};
31129622Ssam }
312