xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/msp430-decode.opc (revision e992f068c547fd6e84b3f104dc2340adcc955732)
1/* -*- c -*- */
2/* Copyright (C) 2013-2022 Free Software Foundation, Inc.
3   Contributed by Red Hat.
4   Written by DJ Delorie.
5
6   This file is part of the GNU opcodes library.
7
8   This library is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3, or (at your option)
11   any later version.
12
13   It is distributed in the hope that it will be useful, but WITHOUT
14   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16   License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21   MA 02110-1301, USA.  */
22
23#include "sysdep.h"
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include "bfd.h"
28#include "opintl.h"
29#include "opcode/msp430-decode.h"
30
31static int trace = 0;
32
33typedef struct
34{
35  MSP430_Opcode_Decoded *msp430;
36  int (*getbyte)(void *);
37  void *ptr;
38  unsigned char *op;
39  int op_ptr;
40  int pc;
41} LocalData;
42
43#define AU ATTRIBUTE_UNUSED
44#define GETBYTE() getbyte_swapped (ld)
45#define B ((unsigned long) GETBYTE ())
46
47static int
48getbyte_swapped (LocalData *ld)
49{
50  int b;
51
52  if (ld->op_ptr == ld->msp430->n_bytes)
53    {
54      do
55	{
56	  b = ld->getbyte (ld->ptr);
57	  ld->op [(ld->msp430->n_bytes++)^1] = b;
58	}
59      while (ld->msp430->n_bytes & 1);
60    }
61  return ld->op[ld->op_ptr++];
62}
63
64#define ID(x)		msp430->id = x
65
66#define OP(n, t, r, a) (msp430->op[n].type = t,	     \
67		        msp430->op[n].reg = r,	     \
68		        msp430->op[n].addend = a)
69
70#define OPX(n, t, r1, r2, a)	 \
71  (msp430->op[n].type = t,	 \
72   msp430->op[n].reg = r1,	 \
73   msp430->op[n].reg2 = r2,	 \
74   msp430->op[n].addend = a)
75
76#define SYNTAX(x)	msp430->syntax = x
77#define UNSUPPORTED()	msp430->syntax = "*unknown*"
78
79#define DC(c)		OP (0, MSP430_Operand_Immediate, 0, c)
80#define DR(r)		OP (0, MSP430_Operand_Register, r, 0)
81#define DM(r, a)	OP (0, MSP430_Operand_Indirect, r, a)
82#define DA(a)		OP (0, MSP430_Operand_Indirect, MSR_None, a)
83#define AD(r, ad)	encode_ad (r, ad, ld, 0)
84#define ADX(r, ad, x)	encode_ad (r, ad, ld, x)
85
86#define SC(c)		OP (1, MSP430_Operand_Immediate, 0, c)
87#define SR(r)		OP (1, MSP430_Operand_Register, r, 0)
88#define SM(r, a)	OP (1, MSP430_Operand_Indirect, r, a)
89#define SA(a)		OP (1, MSP430_Operand_Indirect, MSR_None, a)
90#define SI(r)		OP (1, MSP430_Operand_Indirect_Postinc, r, 0)
91#define AS(r, as)	encode_as (r, as, ld, 0)
92#define ASX(r, as, x)	encode_as (r, as, ld, x)
93
94#define BW(x)		msp430->size = (x ? 8 : 16)
95/* The last 20 is for SWPBX.Z and SXTX.A.  */
96#define ABW(a,x)	msp430->size = (a ? ((x ? 8 : 16)) : (x ? 20 : 20))
97
98#define IMMU(bytes)	immediate (bytes, 0, ld)
99#define IMMS(bytes)	immediate (bytes, 1, ld)
100
101/* Helper macros for known status bits settings.  */
102#define	F_____		msp430->flags_1 = msp430->flags_0 = 0; msp430->flags_set = 0
103#define	F_VNZC		msp430->flags_1 = msp430->flags_0 = 0; msp430->flags_set = 0x87
104#define	F_0NZC		msp430->flags_1 = 0; msp430->flags_0 = 0x80; msp430->flags_set = 0x07
105
106
107/* The chip is little-endian, but GETBYTE byte-swaps words because the
108   decoder is based on 16-bit "words" so *this* logic is big-endian.  */
109
110static int
111immediate (int bytes, int sign_extend, LocalData *ld)
112{
113  unsigned long i = 0;
114
115  switch (bytes)
116    {
117    case 1:
118      i |= B;
119      if (sign_extend && (i & 0x80))
120	i -= 0x100;
121      break;
122    case 2:
123      i |= B << 8;
124      i |= B;
125      if (sign_extend && (i & 0x8000))
126	i -= 0x10000;
127      break;
128    case 3:
129      i |= B << 16;
130      i |= B << 8;
131      i |= B;
132      if (sign_extend && (i & 0x800000))
133	i -= 0x1000000;
134      break;
135    case 4:
136      i |= B << 24;
137      i |= B << 16;
138      i |= B << 8;
139      i |= B;
140      if (sign_extend && (i & 0x80000000ULL))
141	i -= 0x100000000ULL;
142      break;
143    default:
144      opcodes_error_handler
145	(_("internal error: immediate() called with invalid byte count %d"),
146	   bytes);
147      abort ();
148    }
149  return i;
150}
151
152/*
153		PC	SP	SR	CG
154  As
155  00	Rn	-	-	R2	#0
156  01	X(Rn)	Sym	-	X(abs)	#1
157  10	(Rn)	-	-	#4	#2
158  11	(Rn++)	#imm	-	#8	#-1
159
160  Ad
161  0	Rn	-	-	-	-
162  1	X(Rn)	Sym	-	X(abs)	-   */
163
164static void
165encode_ad (int reg, int ad, LocalData *ld, int ext)
166{
167  MSP430_Opcode_Decoded *msp430 = ld->msp430;
168
169  if (ad)
170    {
171      int x = IMMU(2) | (ext << 16);
172      switch (reg)
173	{
174	case 0: /* (PC) -> Symbolic.  */
175	  DA (x + ld->pc + ld->op_ptr - 2);
176	  break;
177	case 2: /* (SR) -> Absolute.  */
178	  DA (x);
179	  break;
180	default:
181	  DM (reg, x);
182	  break;
183	}
184    }
185  else
186    {
187      DR (reg);
188    }
189}
190
191static void
192encode_as (int reg, int as, LocalData *ld, int ext)
193{
194  MSP430_Opcode_Decoded *msp430 = ld->msp430;
195  int x;
196
197  switch (as)
198    {
199    case 0:
200      switch (reg)
201	{
202	case 3:
203	  SC (0);
204	  break;
205	default:
206	  SR (reg);
207	  break;
208	}
209      break;
210    case 1:
211      switch (reg)
212	{
213	case 0: /* PC -> Symbolic.  */
214	  x = IMMU(2) | (ext << 16);
215	  SA (x + ld->pc + ld->op_ptr - 2);
216	  break;
217	case 2: /* SR -> Absolute.  */
218	  x = IMMU(2) | (ext << 16);
219	  SA (x);
220	  break;
221	case 3:
222	  SC (1);
223	  break;
224	default:
225	  x = IMMU(2) | (ext << 16);
226	  SM (reg, x);
227	  break;
228	}
229      break;
230    case 2:
231      switch (reg)
232	{
233	case 2:
234	  SC (4);
235	  break;
236	case 3:
237	  SC (2);
238	  break;
239	case MSR_None:
240	  SA (0);
241	  break;
242	default:
243	  SM (reg, 0);
244	  break;
245	}
246      break;
247    case 3:
248      switch (reg)
249	{
250	case 0:
251	  {
252	    /* This fetch *is* the *PC++ that the opcode encodes :-)  */
253	    x = IMMU(2) | (ext << 16);
254	    SC (x);
255	  }
256	  break;
257	case 2:
258	  SC (8);
259	  break;
260	case 3:
261	  SC (-1);
262	  break;
263	default:
264	  SI (reg);
265	  break;
266	}
267      break;
268    }
269}
270
271static void
272encode_rep_zc (int srxt, int dsxt, LocalData *ld)
273{
274  MSP430_Opcode_Decoded *msp430 = ld->msp430;
275
276  msp430->repeat_reg = srxt & 1;
277  msp430->repeats = dsxt;
278  msp430->zc = (srxt & 2) ? 1 : 0;
279}
280
281#define REPZC(s,d) encode_rep_zc (s, d, ld)
282
283static int
284dopc_to_id (int dopc)
285{
286  switch (dopc)
287    {
288    case 4: return MSO_mov;
289    case 5: return MSO_add;
290    case 6: return MSO_addc;
291    case 7: return MSO_subc;
292    case 8: return MSO_sub;
293    case 9: return MSO_cmp;
294    case 10: return MSO_dadd;
295    case 11: return MSO_bit;
296    case 12: return MSO_bic;
297    case 13: return MSO_bis;
298    case 14: return MSO_xor;
299    case 15: return MSO_and;
300    default: return MSO_unknown;
301    }
302}
303
304static int
305sopc_to_id (int sop, int c)
306{
307  switch (sop * 2 + c)
308    {
309    case 0: return MSO_rrc;
310    case 1: return MSO_swpb;
311    case 2: return MSO_rra;
312    case 3: return MSO_sxt;
313    case 4: return MSO_push;
314    case 5: return MSO_call;
315    case 6: return MSO_reti;
316    default: return MSO_unknown;
317    }
318}
319
320int
321msp430_decode_opcode (unsigned long pc,
322		      MSP430_Opcode_Decoded *msp430,
323		      int (*getbyte)(void *),
324		      void *ptr)
325{
326  LocalData lds, *ld = &lds;
327  unsigned char op_buf[20] = {0};
328  unsigned char *op = op_buf;
329  int raddr;
330  int al_bit;
331  int srxt_bits, dsxt_bits;
332
333  lds.msp430 = msp430;
334  lds.getbyte = getbyte;
335  lds.ptr = ptr;
336  lds.op = op;
337  lds.op_ptr = 0;
338  lds.pc = pc;
339
340  memset (msp430, 0, sizeof (*msp430));
341
342  /* These are overridden by an extension word.  */
343  al_bit = 1;
344  srxt_bits = 0;
345  dsxt_bits = 0;
346
347 post_extension_word:
348  ;
349
350  /* 430X extention word.  */
351/** 0001 1srx t l 00 dsxt 	430x */
352
353  al_bit = l;
354  srxt_bits = srx * 2 + t;
355  dsxt_bits = dsxt;
356  op = op_buf + lds.op_ptr;
357  msp430->ofs_430x = 1;
358  goto post_extension_word;
359
360/* double-op insns:
361   opcode:4 sreg:4 Ad:1 BW:1 As:2 Dreg:4
362
363   single-op insn:
364   opcode:9 BW:1 Ad:2 DSreg:4
365
366   jumps:
367   opcode:3 Cond:3  pcrel:10. */
368
369/* Double-Operand "opcode" fields.  */
370/** VARY dopc 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 */
371
372/** dopc sreg a b as dreg	%D%b	%1,%0				*/
373
374  ID (dopc_to_id (dopc)); ASX (sreg, as, srxt_bits); ADX (dreg, a, dsxt_bits); ABW (al_bit, b);
375  if (a == 0 && as == 0)
376    REPZC (srxt_bits, dsxt_bits);
377
378  switch (msp430->id)
379    {
380    case MSO_mov:	F_____; break;
381    case MSO_add:	F_VNZC; break;
382    case MSO_addc:	F_VNZC; break;
383    case MSO_subc:	F_VNZC; break;
384    case MSO_sub:	F_VNZC; break;
385    case MSO_cmp:	F_VNZC; break;
386    case MSO_dadd:	F_VNZC; break;
387    case MSO_bit:	F_0NZC; break;
388    case MSO_bic:	F_____; break;
389    case MSO_bis:	F_____; break;
390    case MSO_xor:	F_VNZC; break;
391    case MSO_and:	F_0NZC; break;
392    default: break;
393    }
394
395/** 0001 00so c b ad dreg	%S%b	%1				*/
396
397  ID (sopc_to_id (so,c)); ASX (dreg, ad, srxt_bits); ABW (al_bit, b);
398
399  if (ad == 0)
400    REPZC (srxt_bits, dsxt_bits);
401
402  /* The helper functions encode for source, but it's
403     both source and dest, with a few documented exceptions.  */
404  msp430->op[0] = msp430->op[1];
405
406  /* RETI ignores the operand.  */
407  if (msp430->id == MSO_reti)
408    msp430->syntax = "%S";
409
410  switch (msp430->id)
411    {
412    case MSO_rrc:	F_VNZC; break;
413    case MSO_swpb:	F_____; break;
414    case MSO_rra:	F_0NZC; break;
415    case MSO_sxt:	F_0NZC; break;
416    case MSO_push:	F_____; break;
417    case MSO_call:	F_____; break;
418    case MSO_reti:	F_VNZC; break;
419    default: break;
420    }
421
422  /* 20xx 0010 0000 ---- ----
423     3cxx 0011 1100 ---- ----
424          001j mp-- ---- ----.  */
425/** 001jmp aa addrlsbs		%J	%1				*/
426
427  raddr = (aa << 9) | (addrlsbs << 1);
428  if (raddr & 0x400)
429    raddr = raddr - 0x800;
430  /* This is a pc-relative jump, but we don't use SM because that
431     would load the target address from the memory at X(PC), not use
432     PC+X *as* the address.  So we use SC to use the address, not the
433     data at that address.  */
434  ID (MSO_jmp); SC (pc + raddr + msp430->n_bytes);
435  msp430->cond = jmp;
436
437  /* Extended instructions.  */
438
439/** 0000 srcr 0000 dstr		MOVA @%1, %0 */
440  ID (MSO_mov); SM (srcr, 0); DR (dstr);
441  msp430->size = 20;
442  msp430->ofs_430x = 1;
443
444/** 0000 srcr 0001 dstr		MOVA @%1+, %0 */
445  ID (MSO_mov); SI (srcr); DR (dstr);
446  msp430->size = 20;
447  msp430->ofs_430x = 1;
448
449/** 0000 srcr 0010 dstr		MOVA &%1, %0 */
450  ID (MSO_mov); SA ((srcr << 16) + IMMU(2)); DR (dstr);
451  msp430->size = 20;
452  msp430->ofs_430x = 1;
453
454/** 0000 srcr 0011 dstr		MOVA %1, %0 */
455  ID (MSO_mov); SM (srcr, IMMS(2)); DR (dstr);
456  msp430->size = 20;
457  msp430->ofs_430x = 1;
458
459/** 0000 srcr 0110 dstr		MOVA %1, &%0 */
460  ID (MSO_mov); SR (srcr); DA ((dstr << 16) + IMMU(2));
461  msp430->size = 20;
462  msp430->ofs_430x = 1;
463
464/** 0000 srcr 0111 dstr		MOVA %1, &%0 */
465  ID (MSO_mov); SR (srcr); DM (dstr, IMMS(2));
466  msp430->size = 20;
467  msp430->ofs_430x = 1;
468
469/** 0000 srcr 1000 dstr		MOVA %1, %0 */
470  ID (MSO_mov); SC ((srcr << 16) + IMMU(2)); DR (dstr);
471  msp430->size = 20;
472  msp430->ofs_430x = 1;
473
474/** 0000 srcr 1001 dstr		CMPA %1, %0 */
475  ID (MSO_cmp); SC ((srcr << 16) + IMMU(2)); DR (dstr);
476  msp430->size = 20;
477  msp430->ofs_430x = 1;
478  F_VNZC;
479
480/** 0000 srcr 1010 dstr		ADDA %1, %0 */
481  ID (MSO_add); SC ((srcr << 16) + IMMU(2)); DR (dstr);
482  msp430->size = 20;
483  msp430->ofs_430x = 1;
484  F_VNZC;
485
486/** 0000 srcr 1011 dstr		SUBA %1, %0 */
487  ID (MSO_sub); SC ((srcr << 16) + IMMU(2)); DR (dstr);
488  msp430->size = 20;
489  msp430->ofs_430x = 1;
490  F_VNZC;
491
492/** 0000 srcr 1011 dstr		SUBA %1, %0 */
493  ID (MSO_sub); SC ((srcr << 16) + IMMU(2)); DR (dstr);
494  msp430->size = 20;
495  msp430->ofs_430x = 1;
496  F_VNZC;
497
498/** 0000 srcr 1100 dstr		MOVA %1, %0 */
499  ID (MSO_mov); SR (srcr); DR (dstr);
500  msp430->size = 20;
501  msp430->ofs_430x = 1;
502
503/** 0000 srcr 1101 dstr		CMPA %1, %0 */
504  ID (MSO_cmp); SR (srcr); DR (dstr);
505  msp430->size = 20;
506  msp430->ofs_430x = 1;
507  F_VNZC;
508
509/** 0000 srcr 1110 dstr		ADDA %1, %0 */
510  ID (MSO_add); SR (srcr); DR (dstr);
511  msp430->size = 20;
512  msp430->ofs_430x = 1;
513  F_VNZC;
514
515/** 0000 srcr 1111 dstr		SUBA %1, %0 */
516  ID (MSO_sub); SR (srcr); DR (dstr);
517  msp430->size = 20;
518  msp430->ofs_430x = 1;
519  F_VNZC;
520
521/** 0000 bt00 010w dstr		RRCM.A %c, %0 */
522  ID (MSO_rrc); DR (dstr); SR (dstr);
523  msp430->repeats = bt;
524  msp430->size = w ? 16 : 20;
525  msp430->ofs_430x = 1;
526  F_0NZC;
527
528/** 0000 bt01 010w dstr		RRAM.A %c, %0 */
529  ID (MSO_rra); DR (dstr); SR (dstr);
530  msp430->repeats = bt;
531  msp430->size = w ? 16 : 20;
532  msp430->ofs_430x = 1;
533  F_0NZC;
534
535/** 0000 bt10 010w dstr		RLAM.A %c, %0 */
536  ID (MSO_add); DR (dstr); SR (dstr);
537  msp430->repeats = bt;
538  msp430->size = w ? 16 : 20;
539  msp430->ofs_430x = 1;
540  F_0NZC;
541
542/** 0000 bt11 010w dstr		RRUM.A %c, %0 */
543  ID (MSO_rru); DR (dstr); SR (dstr);
544  msp430->repeats = bt;
545  msp430->size = w ? 16 : 20;
546  msp430->ofs_430x = 1;
547  F_0NZC;
548
549/** 0001 0011 0000 0000		RETI */
550  ID (MSO_reti);
551  msp430->size = 20;
552  msp430->ofs_430x = 1;
553
554/** 0001 0011 01as dstr		CALLA %0 */
555  ID (MSO_call); AS (dstr, as);
556  msp430->size = 20;
557  msp430->ofs_430x = 1;
558
559/** 0001 0011 1000 extb		CALLA %0 */
560  ID (MSO_call); SA (IMMU(2) | (extb << 16));
561  msp430->size = 20;
562  msp430->ofs_430x = 1;
563
564/** 0001 0011 1001 extb		CALLA %0 */
565  raddr = IMMU(2) | (extb << 16);
566  if (raddr & 0x80000)
567    raddr -= 0x100000;
568  ID (MSO_call); SA (pc + raddr + msp430->n_bytes);
569  msp430->size = 20;
570  msp430->ofs_430x = 1;
571
572/** 0001 0011 1011 extb		CALLA %0 */
573  ID (MSO_call); SC (IMMU(2) | (extb << 16));
574  msp430->size = 20;
575  msp430->ofs_430x = 1;
576
577/** 0001 010w bits srcr		PUSHM.A %0 */
578  ID (MSO_push); SR (srcr);
579  msp430->size = w ? 16 : 20;
580  msp430->repeats = bits;
581  msp430->ofs_430x = 1;
582
583/** 0001 011w bits dstr		POPM.A %0 */
584  ID (MSO_pop); DR (dstr);
585  msp430->size = w ? 16 : 20;
586  msp430->repeats = bits;
587  msp430->ofs_430x = 1;
588
589/** */
590
591  return msp430->n_bytes;
592}
593