summaryrefslogtreecommitdiffstats
path: root/include/pyr-opcode.h
blob: 06632b8d91970cdf248fdc6eaa5bbafd9ad0b44d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/* pyramid.opcode.h -- gdb initial attempt. */

/* pyramid opcode table: wot to do with this
   particular opcode */

struct pyr_datum
{
  char              nargs;
  char *            args;	/* how to compile said opcode */
  unsigned long     mask;	/* Bit vector: which operand modes are valid
				   for this opcode */
  unsigned char     code;	/* op-code (always 6(?) bits */
};

typedef struct pyr_insn_format {
    unsigned int mode :4;
    unsigned int operator :8;
    unsigned int index_scale :2;
    unsigned int index_reg :6;
    unsigned int operand_1 :6;
    unsigned int operand_2:6;
} pyr_insn_format;
	

/* We store four bytes of opcode for all opcodes.
   Pyramid is sufficiently RISCy that:
      - insns are always an integral number of words;
      - the length of any insn can be told from the first word of
        the insn. (ie, if there are zero, one, or two words of
	immediate operand/offset).

   
   The args component is a string containing two characters for each
   operand of the instruction.  The first specifies the kind of operand;
   the second, the place it is stored. */

/* Kinds of operands:
   mask	 assembler syntax	description
   0x0001:  movw Rn,Rn		register to register
   0x0002:  movw K,Rn		quick immediate to register
   0x0004:  movw I,Rn		long immediate to register
   0x0008:  movw (Rn),Rn	register indirect to register
   	    movw (Rn)[x],Rn	register indirect to register
   0x0010:  movw I(Rn),Rn	offset register indirect to register
   	    movw I(Rn)[x],Rn	offset register indirect, indexed, to register

   0x0020:  movw Rn,(Rn)	register to register indirect                
   0x0040:  movw K,(Rn)		quick immediate to register indirect         
   0x0080:  movw I,(Rn)		long immediate to register indirect          
   0x0100:  movw (Rn),(Rn)	register indirect to-register indirect       
   0x0100:  movw (Rn),(Rn)	register indirect to-register indirect       
   0x0200:  movw I(Rn),(Rn)	register indirect+offset to register indirect
   0x0200:  movw I(Rn),(Rn)	register indirect+offset to register indirect

   0x0400:  movw Rn,I(Rn)	register to register indirect+offset
   0x0800:  movw K,I(Rn)	quick immediate to register indirect+offset
   0x1000:  movw I,I(Rn)	long immediate to register indirect+offset
   0x1000:  movw (Rn),I(Rn)	register indirect to-register indirect+offset
   0x1000:  movw I(Rn),I(Rn)	register indirect+offset to register indirect
   					+offset
   0x0000:  (irregular)		???
   

   Each insn has a four-bit field encoding the type(s) of its operands.
*/

/* Some common combinations
   */

/* the first 5,(0x1|0x2|0x4|0x8|0x10) ie (1|2|4|8|16), ie ( 32 -1)*/
#define GEN_TO_REG (31)

#define	UNKNOWN ((unsigned long)-1)
#define ANY (GEN_TO_REG | (GEN_TO_REG << 5) | (GEN_TO_REG << 15))

#define CONVERT (1|8|0x10|0x20|0x200)

#define K_TO_REG (2)
#define I_TO_REG (4)
#define NOTK_TO_REG (GEN_TO_REG & ~K_TO_REG)
#define NOTI_TO_REG (GEN_TO_REG & ~I_TO_REG)

/* The assembler requires that this array be sorted as follows:
   all instances of the same mnemonic must be consecutive.
   All instances of the same mnemonic with the same number of operands
   must be consecutive.
 */

struct pyr_opcode		/* pyr opcode text */
{
  char *            name;	/* opcode name: lowercase string  [key]  */
  struct pyr_datum  datum;	/* rest of opcode table          [datum] */
};

#define pyr_how args
#define pyr_nargs nargs
#define pyr_mask mask
#define pyr_name name

struct pyr_opcode pyr_opcodes[] =
{
  {"movb",	{ 2, "", UNKNOWN,		0x11}, },
  {"movh",	{ 2, "", UNKNOWN,		0x12} },
  {"movw",	{ 2, "", ANY,			0x10} },
  {"movl",	{ 2, "", ANY,			0x13} },
  {"mnegw",	{ 2, "", (0x1|0x8|0x10),	0x14} },
  {"mnegf",	{ 2, "", 0x1,			0x15} },
  {"mnegd",	{ 2, "", 0x1,			0x16} },
  {"mcomw",	{ 2, "", (0x1|0x8|0x10),	0x17} },
  {"mabsw",	{ 2, "", (0x1|0x8|0x10),	0x18} },
  {"mabsf",	{ 2, "", 0x1,			0x19} },
  {"mabsd",	{ 2, "", 0x1,			0x1a} },
  {"mtstw",	{ 2, "", (0x1|0x8|0x10),	0x1c} },
  {"mtstf",	{ 2, "", 0x1,			0x1d} },
  {"mtstd",	{ 2, "", 0x1,			0x1e} },
  {"mova",	{ 2, "", 0x8|0x10,		0x1f} },
  {"movzbw",	{ 2, "", (0x1|0x8|0x10),	0x20} },
  {"movzhw",	{ 2, "", (0x1|0x8|0x10),	0x21} },
				/* 2 insns out of order here */
  {"movbl",	{ 2, "", 1,			0x4f} },
  {"filbl",	{ 2, "", 1,			0x4e} },

  {"cvtbw",	{ 2, "", CONVERT,		0x22} },
  {"cvthw",	{ 2, "", CONVERT,		0x23} },
  {"cvtwb",	{ 2, "", CONVERT,		0x24} },
  {"cvtwh",	{ 2, "", CONVERT,		0x25} },
  {"cvtwf",	{ 2, "", CONVERT,		0x26} },
  {"cvtwd",	{ 2, "", CONVERT,		0x27} },
  {"cvtfw",	{ 2, "", CONVERT,		0x28} },
  {"cvtfd",	{ 2, "", CONVERT,		0x29} },
  {"cvtdw",	{ 2, "", CONVERT,		0x2a} },
  {"cvtdf",	{ 2, "", CONVERT,		0x2b} },

  {"addw",	{ 2, "", GEN_TO_REG,		0x40} },
  {"addwc",	{ 2, "", GEN_TO_REG,		0x41} },
  {"subw",	{ 2, "", GEN_TO_REG,		0x42} },
  {"subwb",	{ 2, "", GEN_TO_REG,		0x43} },
  {"rsubw",	{ 2, "", GEN_TO_REG,		0x44} },
  {"mulw",	{ 2, "", GEN_TO_REG,		0x45} },
  {"emul",	{ 2, "", GEN_TO_REG,		0x47} },
  {"umulw",	{ 2, "", GEN_TO_REG,		0x46} },
  {"divw",	{ 2, "", GEN_TO_REG,		0x48} },
  {"ediv",	{ 2, "", GEN_TO_REG,		0x4a} },
  {"rdivw",	{ 2, "", GEN_TO_REG,		0x4b} },
  {"udivw",	{ 2, "", GEN_TO_REG,		0x49} },
  {"modw",	{ 2, "", GEN_TO_REG,		0x4c} },
  {"umodw",	{ 2, "", GEN_TO_REG,		0x4d} },


  {"addf",	{ 2, "", 1,			0x50} },
  {"addd",	{ 2, "", 1,			0x51} },
  {"subf",	{ 2, "", 1,			0x52} },
  {"subd",	{ 2, "", 1,			0x53} },
  {"mulf",	{ 2, "", 1,			0x56} },
  {"muld",	{ 2, "", 1,			0x57} },
  {"divf",	{ 2, "", 1,			0x58} },
  {"divd",	{ 2, "", 1,			0x59} },


  {"cmpb",	{ 2, "", UNKNOWN,		0x61} },
  {"cmph",	{ 2, "", UNKNOWN,		0x62} },
  {"cmpw",	{ 2, "", UNKNOWN,		0x60} },
  {"ucmpb",	{ 2, "", UNKNOWN,		0x66} },
  /* WHY no "ucmph"??? */
  {"ucmpw",	{ 2, "", UNKNOWN,		0x65} },
  {"xchw",	{ 2, "", UNKNOWN,		0x0f} },


  {"andw",	{ 2, "", GEN_TO_REG,		0x30} },
  {"orw",	{ 2, "", GEN_TO_REG,		0x31} },
  {"xorw",	{ 2, "", GEN_TO_REG,		0x32} },
  {"bicw",	{ 2, "", GEN_TO_REG,		0x33} },
  {"lshlw",	{ 2, "", GEN_TO_REG,		0x38} },
  {"ashlw",	{ 2, "", GEN_TO_REG,		0x3a} },
  {"ashll",	{ 2, "", GEN_TO_REG,		0x3c} },
  {"ashrw",	{ 2, "", GEN_TO_REG,		0x3b} },
  {"ashrl",	{ 2, "", GEN_TO_REG,		0x3d} },
  {"rotlw",	{ 2, "", GEN_TO_REG,		0x3e} },
  {"rotrw",	{ 2, "", GEN_TO_REG,		0x3f} },

  /* push and pop insns are "going away next release". */
  {"pushw",	{ 2, "", GEN_TO_REG,		0x0c} },
  {"popw",	{ 2, "", (0x1|0x8|0x10),	0x0d} },
  {"pusha",	{ 2, "", (0x8|0x10),		0x0e} },

  {"bitsw",	{ 2, "", UNKNOWN,		0x35} },
  {"bitcw",	{ 2, "", UNKNOWN,		0x36} },
  /* some kind of ibra/dbra insns??*/
  {"icmpw",	{ 2, "", UNKNOWN,		0x67} },
  {"dcmpw",	{ 2, "", (1|4|0x20|0x80|0x400|0x1000),	0x69} },/*FIXME*/
  {"acmpw",	{ 2, "", 1,			0x6b} },

  /* Call is written as a 1-op insn, but is always (dis)assembled as a 2-op
     insn with a 2nd op of tr14.   The assembler will have to grok this.  */
  {"call",	{ 2, "", GEN_TO_REG,		0x04} },
  {"call",	{ 1, "", GEN_TO_REG,		0x04} },

  {"callk",	{ 1, "", UNKNOWN,		0x06} },/* system call?*/
  /* Ret is usually written as a 0-op insn, but gets disassembled as a
     1-op insn. The operand is always tr15. */
  {"ret",	{ 0, "", UNKNOWN,		0x09} },
  {"ret",	{ 1, "", UNKNOWN,		0x09} },
  {"adsf",	{ 2, "", (1|2|4),		0x08} },
  {"retd",	{ 2, "", UNKNOWN,		0x0a} },
  {"btc",	{ 2, "", UNKNOWN,		0x01} },
  {"bfc",	{ 2, "", UNKNOWN,		0x02} },
  /* Careful: halt is 0x00000000. Jump must have some other (mode?)bit set?? */
  {"jump",	{ 1, "", UNKNOWN,		0x00} },
  {"btp",	{ 2, "", UNKNOWN,		0xf00} },
  /* read control-stack pointer is another 1-or-2 operand insn. */
  {"rcsp",	{ 2, "", UNKNOWN,		0x01f} },
  {"rcsp",	{ 1, "", UNKNOWN,		0x01f} }
};

/* end: pyramid.opcode.h */
/* One day I will have to take the time to find out what operands
   are valid for these insns, and guess at what they mean.

   I can't imagine what the "I???" insns (iglob, etc) do.

   the arithmetic-sounding insns ending in "p" sound awfully like BCD
   arithmetic insns:
   	dshlp -> Decimal SHift Left Packed
	dshrp -> Decimal SHift Right Packed
   and cvtlp would be convert long to packed.
   I have no idea how the operands are interpreted; but having them be
   a long register with (address, length) of an in-memory packed BCD operand
   would not be surprising.
   They are unlikely to be a packed bcd string: 64 bits of long give
   is only 15 digits+sign, which isn't enough for COBOL.
 */ 
#if 0
  {"wcsp",	{ 2, "", UNKNOWN,		0x00} }, /*write csp?*/
  /* The OSx Operating System Porting Guide claims SSL does things
     with tr12 (a register reserved to it) to do with static block-structure
     references.  SSL=Set Static Link?  It's "Going away next release". */
  {"ssl",	{ 2, "", UNKNOWN,		0x00} },
  {"ccmps",	{ 2, "", UNKNOWN,		0x00} },
  {"lcd",	{ 2, "", UNKNOWN,		0x00} },
  {"uemul",	{ 2, "", UNKNOWN,		0x00} }, /*unsigned emul*/
  {"srf",	{ 2, "", UNKNOWN,		0x00} }, /*Gidget time???*/
  {"mnegp",	{ 2, "", UNKNOWN,		0x00} }, /move-neg phys?*/
  {"ldp",	{ 2, "", UNKNOWN,		0x00} }, /*load phys?*/
  {"ldti",	{ 2, "", UNKNOWN,		0x00} },
  {"ldb",	{ 2, "", UNKNOWN,		0x00} },
  {"stp",	{ 2, "", UNKNOWN,		0x00} },
  {"stti",	{ 2, "", UNKNOWN,		0x00} },
  {"stb",	{ 2, "", UNKNOWN,		0x00} },
  {"stu",	{ 2, "", UNKNOWN,		0x00} },
  {"addp",	{ 2, "", UNKNOWN,		0x00} },
  {"subp",	{ 2, "", UNKNOWN,		0x00} },
  {"mulp",	{ 2, "", UNKNOWN,		0x00} },
  {"divp",	{ 2, "", UNKNOWN,		0x00} },
  {"dshlp",	{ 2, "", UNKNOWN,		0x00} },  /* dec shl packed? */
  {"dshrp",	{ 2, "", UNKNOWN,		0x00} }, /* dec shr packed? */
  {"movs",	{ 2, "", UNKNOWN,		0x00} }, /*move (string?)?*/
  {"cmpp",	{ 2, "", UNKNOWN,		0x00} }, /* cmp phys?*/
  {"cmps",	{ 2, "", UNKNOWN,		0x00} }, /* cmp (string?)?*/
  {"cvtlp",	{ 2, "", UNKNOWN,		0x00} }, /* cvt long to p??*/
  {"cvtpl",	{ 2, "", UNKNOWN,		0x00} }, /* cvt p to l??*/
  {"dintr",	{ 2, "", UNKNOWN,		0x00} }, /* ?? intr ?*/
  {"rphysw",	{ 2, "", UNKNOWN,		0x00} }, /* read phys word?*/
  {"wphysw",	{ 2, "", UNKNOWN,		0x00} }, /* write phys word?*/
  {"cmovs",	{ 2, "", UNKNOWN,		0x00} },
  {"rsubw",	{ 2, "", UNKNOWN,		0x00} },
  {"bicpsw",	{ 2, "", UNKNOWN,		0x00} }, /* clr bit in psw? */
  {"bispsw",	{ 2, "", UNKNOWN,		0x00} }, /* set bit in psw? */
  {"eio",	{ 2, "", UNKNOWN,		0x00} }, /* ?? ?io ? */
  {"callp",	{ 2, "", UNKNOWN,		0x00} }, /* call phys?*/
  {"callr",	{ 2, "", UNKNOWN,		0x00} },
  {"lpcxt",	{ 2, "", UNKNOWN,		0x00} }, /*load proc context*/
  {"rei",	{ 2, "", UNKNOWN,		0x00} }, /*ret from intrpt*/
  {"rport",	{ 2, "", UNKNOWN,		0x00} }, /*read-port?*/
  {"rtod",	{ 2, "", UNKNOWN,		0x00} }, /*read-time-of-day?*/
  {"ssi",	{ 2, "", UNKNOWN,		0x00} },
  {"vtpa",	{ 2, "", UNKNOWN,		0x00} }, /*virt-to-phys-addr?*/
  {"wicl",	{ 2, "", UNKNOWN,		0x00} }, /* write icl ? */
  {"wport",	{ 2, "", UNKNOWN,		0x00} }, /*write-port?*/
  {"wtod",	{ 2, "", UNKNOWN,		0x00} }, /*write-time-of-day?*/
  {"flic",	{ 2, "", UNKNOWN,		0x00} },
  {"iglob",	{ 2, "", UNKNOWN,		0x00} }, /* I global? */
  {"iphys",	{ 2, "", UNKNOWN,		0x00} }, /* I physical? */
  {"ipid",	{ 2, "", UNKNOWN,		0x00} }, /* I pid? */
  {"ivect",	{ 2, "", UNKNOWN,		0x00} }, /* I vector? */
  {"lamst",	{ 2, "", UNKNOWN,		0x00} },
  {"tio",	{ 2, "", UNKNOWN,		0x00} },
#endif
OpenPOWER on IntegriCloud