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