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