aboutsummaryrefslogtreecommitdiff
path: root/opcodes/m32r-asm.in
blob: 70f67ffbff8a9035fa8643f324c56a32efff98b9 (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
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
/* -- asm.c */

/* Handle shigh(), high().  */

static const char *
parse_h_hi16 (strp, opindex, min, max, valuep)
     const char **strp;
     int opindex;
     unsigned long min, max;
     unsigned long *valuep;
{
  const char *errmsg;
  enum cgen_parse_operand_result result_type;

  /* FIXME: Need # in assembler syntax (means '#' is optional).  */
  if (**strp == '#')
    ++*strp;

  if (strncmp (*strp, "high(", 5) == 0)
    {
      *strp += 5;
      errmsg = cgen_parse_address (strp, opindex, BFD_RELOC_M32R_HI16_ULO,
				   &result_type, valuep);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
  	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
	*valuep >>= 16;
      return errmsg;
    }
  else if (strncmp (*strp, "shigh(", 6) == 0)
    {
      *strp += 6;
      errmsg = cgen_parse_address (strp, opindex, BFD_RELOC_M32R_HI16_SLO,
 				   &result_type, valuep);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      if (errmsg == NULL
	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
	*valuep = (*valuep >> 16) + ((*valuep) & 0x8000 ? 1 : 0);
      return errmsg;
    }

  return cgen_parse_unsigned_integer (strp, opindex, min, max, valuep);
}

/* Handle low() in a signed context.  Also handle sda().
   The signedness of the value doesn't matter to low(), but this also
   handles the case where low() isn't present.  */

static const char *
parse_h_slo16 (strp, opindex, min, max, valuep)
     const char **strp;
     int opindex;
     long min, max;
     long *valuep;
{
  const char *errmsg;
  enum cgen_parse_operand_result result_type;

  /* FIXME: Need # in assembler syntax (means '#' is optional).  */
  if (**strp == '#')
    ++*strp;

  if (strncmp (*strp, "low(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (strp, opindex, BFD_RELOC_M32R_LO16,
				   &result_type, valuep);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      return errmsg;
    }

  if (strncmp (*strp, "sda(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (strp, opindex, BFD_RELOC_M32R_SDA16, NULL, valuep);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      return errmsg;
    }

  return cgen_parse_signed_integer (strp, opindex, min, max, valuep);
}

/* Handle low() in an unsigned context.
   The signedness of the value doesn't matter to low(), but this also
   handles the case where low() isn't present.  */

static const char *
parse_h_ulo16 (strp, opindex, min, max, valuep)
     const char **strp;
     int opindex;
     unsigned long min, max;
     unsigned long *valuep;
{
  const char *errmsg;
  enum cgen_parse_operand_result result_type;

  /* FIXME: Need # in assembler syntax (means '#' is optional).  */
  if (**strp == '#')
    ++*strp;

  if (strncmp (*strp, "low(", 4) == 0)
    {
      *strp += 4;
      errmsg = cgen_parse_address (strp, opindex, BFD_RELOC_M32R_LO16,
				   &result_type, valuep);
      if (**strp != ')')
	return "missing `)'";
      ++*strp;
      return errmsg;
    }

  return cgen_parse_unsigned_integer (strp, opindex, min, max, valuep);
}

/* -- */

/* Main entry point for operand parsing.

   This function is basically just a big switch statement.  Earlier versions
   used tables to look up the function to use, but
   - if the table contains both assembler and disassembler functions then
     the disassembler contains much of the assembler and vice-versa,
   - there's a lot of inlining possibilities as things grow,
   - using a switch statement avoids the function call overhead.

   This function could be moved into `parse_insn_normal', but keeping it
   separate makes clear the interface between `parse_insn_normal' and each of
   the handlers.
*/

CGEN_INLINE const char *
m32r_cgen_parse_operand (opindex, strp, fields)
     int opindex;
     const char **strp;
     CGEN_FIELDS *fields;
{
  const char *errmsg;

  switch (opindex)
    {
    case M32R_OPERAND_SR :
      errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_gr, &fields->f_r2);
      break;
    case M32R_OPERAND_DR :
      errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_gr, &fields->f_r1);
      break;
    case M32R_OPERAND_SRC1 :
      errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_gr, &fields->f_r1);
      break;
    case M32R_OPERAND_SRC2 :
      errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_gr, &fields->f_r2);
      break;
    case M32R_OPERAND_SCR :
      errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_cr, &fields->f_r2);
      break;
    case M32R_OPERAND_DCR :
      errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_cr, &fields->f_r1);
      break;
    case M32R_OPERAND_SIMM8 :
      errmsg = cgen_parse_signed_integer (strp, 7, -128, 127, &fields->f_simm8);
      break;
    case M32R_OPERAND_SIMM16 :
      errmsg = cgen_parse_signed_integer (strp, 8, -32768, 32767, &fields->f_simm16);
      break;
    case M32R_OPERAND_UIMM4 :
      errmsg = cgen_parse_unsigned_integer (strp, 9, 0, 15, &fields->f_uimm4);
      break;
    case M32R_OPERAND_UIMM5 :
      errmsg = cgen_parse_unsigned_integer (strp, 10, 0, 31, &fields->f_uimm5);
      break;
    case M32R_OPERAND_UIMM16 :
      errmsg = cgen_parse_unsigned_integer (strp, 11, 0, 65535, &fields->f_uimm16);
      break;
    case M32R_OPERAND_ACC_S :
      errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_accums, &fields->f_acc_s);
      break;
    case M32R_OPERAND_ACC :
      errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_accums, &fields->f_acc);
      break;
    case M32R_OPERAND_HI16 :
      errmsg = parse_h_hi16 (strp, 14, 0, 65535, &fields->f_hi16);
      break;
    case M32R_OPERAND_SLO16 :
      errmsg = parse_h_slo16 (strp, 15, -32768, 32767, &fields->f_simm16);
      break;
    case M32R_OPERAND_ULO16 :
      errmsg = parse_h_ulo16 (strp, 16, 0, 65535, &fields->f_uimm16);
      break;
    case M32R_OPERAND_UIMM24 :
      errmsg = cgen_parse_address (strp, 17, 0, NULL, &fields->f_uimm24);
      break;
    case M32R_OPERAND_DISP8 :
      errmsg = cgen_parse_address (strp, 18, 0, NULL, &fields->f_disp8);
      break;
    case M32R_OPERAND_DISP16 :
      errmsg = cgen_parse_address (strp, 19, 0, NULL, &fields->f_disp16);
      break;
    case M32R_OPERAND_DISP24 :
      errmsg = cgen_parse_address (strp, 20, 0, NULL, &fields->f_disp24);
      break;

    default :
      fprintf (stderr, "Unrecognized field %d while parsing.\n", opindex);
      abort ();
  }

  return errmsg;
}

/* Main entry point for operand insertion.

   This function is basically just a big switch statement.  Earlier versions
   used tables to look up the function to use, but
   - if the table contains both assembler and disassembler functions then
     the disassembler contains much of the assembler and vice-versa,
   - there's a lot of inlining possibilities as things grow,
   - using a switch statement avoids the function call overhead.

   This function could be moved into `parse_insn_normal', but keeping it
   separate makes clear the interface between `parse_insn_normal' and each of
   the handlers.  It's also needed by GAS to insert operands that couldn't be
   resolved during parsing.
*/

CGEN_INLINE void
m32r_cgen_insert_operand (opindex, fields, buffer)
     int opindex;
     CGEN_FIELDS *fields;
     cgen_insn_t *buffer;
{
  switch (opindex)
    {
    case M32R_OPERAND_SR :
      insert_normal (fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_DR :
      insert_normal (fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_SRC1 :
      insert_normal (fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_SRC2 :
      insert_normal (fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_SCR :
      insert_normal (fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_DCR :
      insert_normal (fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_SIMM8 :
      insert_normal (fields->f_simm8, 0, 8, 8, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_SIMM16 :
      insert_normal (fields->f_simm16, 0, 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_UIMM4 :
      insert_normal (fields->f_uimm4, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_UIMM5 :
      insert_normal (fields->f_uimm5, 0|(1<<CGEN_OPERAND_UNSIGNED), 11, 5, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_UIMM16 :
      insert_normal (fields->f_uimm16, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_ACC_S :
      insert_normal (fields->f_acc_s, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 2, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_ACC :
      insert_normal (fields->f_acc, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 1, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_HI16 :
      insert_normal (fields->f_hi16, 0|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_SLO16 :
      insert_normal (fields->f_simm16, 0, 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_ULO16 :
      insert_normal (fields->f_uimm16, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_UIMM24 :
      insert_normal (fields->f_uimm24, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR)|(1<<CGEN_OPERAND_UNSIGNED), 8, 24, 0, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_DISP8 :
      insert_normal (fields->f_disp8, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 8, 8, 2, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_DISP16 :
      insert_normal (fields->f_disp16, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 16, 16, 2, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;
    case M32R_OPERAND_DISP24 :
      insert_normal (fields->f_disp24, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 8, 24, 2, CGEN_FIELDS_BITSIZE (fields), buffer);
      break;

    default :
      fprintf (stderr, "Unrecognized field %d while building insn.\n",
	       opindex);
      abort ();
  }
}

/* Main entry point for operand validation.

   This function is called from GAS when it has fully resolved an operand
   that couldn't be resolved during parsing.

   The result is NULL for success or an error message (which may be
   computed into a static buffer).
*/

CGEN_INLINE const char *
m32r_cgen_validate_operand (opindex, fields)
     int opindex;
     const CGEN_FIELDS *fields;
{
  const char *errmsg = NULL;

  switch (opindex)
    {
    case M32R_OPERAND_SR :
      /* nothing to do */
      break;
    case M32R_OPERAND_DR :
      /* nothing to do */
      break;
    case M32R_OPERAND_SRC1 :
      /* nothing to do */
      break;
    case M32R_OPERAND_SRC2 :
      /* nothing to do */
      break;
    case M32R_OPERAND_SCR :
      /* nothing to do */
      break;
    case M32R_OPERAND_DCR :
      /* nothing to do */
      break;
    case M32R_OPERAND_SIMM8 :
      errmsg = cgen_validate_signed_integer (fields->f_simm8, -128, 127);
      break;
    case M32R_OPERAND_SIMM16 :
      errmsg = cgen_validate_signed_integer (fields->f_simm16, -32768, 32767);
      break;
    case M32R_OPERAND_UIMM4 :
      errmsg = cgen_validate_unsigned_integer (fields->f_uimm4, 0, 15);
      break;
    case M32R_OPERAND_UIMM5 :
      errmsg = cgen_validate_unsigned_integer (fields->f_uimm5, 0, 31);
      break;
    case M32R_OPERAND_UIMM16 :
      errmsg = cgen_validate_unsigned_integer (fields->f_uimm16, 0, 65535);
      break;
    case M32R_OPERAND_ACC_S :
      /* nothing to do */
      break;
    case M32R_OPERAND_ACC :
      /* nothing to do */
      break;
    case M32R_OPERAND_HI16 :
      errmsg = cgen_validate_unsigned_integer (fields->f_hi16, 0, 65535);
      break;
    case M32R_OPERAND_SLO16 :
      errmsg = cgen_validate_signed_integer (fields->f_simm16, -32768, 32767);
      break;
    case M32R_OPERAND_ULO16 :
      errmsg = cgen_validate_unsigned_integer (fields->f_uimm16, 0, 65535);
      break;
    case M32R_OPERAND_UIMM24 :
      /* nothing to do */
      break;
    case M32R_OPERAND_DISP8 :
      /* nothing to do */
      break;
    case M32R_OPERAND_DISP16 :
      /* nothing to do */
      break;
    case M32R_OPERAND_DISP24 :
      /* nothing to do */
      break;

    default :
      fprintf (stderr, "Unrecognized field %d while validating operand.\n",
	       opindex);
      abort ();
  }

  return errmsg;
}

cgen_parse_fn *m32r_cgen_parse_handlers[] = {
  0, /* default */
  parse_insn_normal,
};

cgen_insert_fn *m32r_cgen_insert_handlers[] = {
  0, /* default */
  insert_insn_normal,
};

void
m32r_cgen_init_asm (mach, endian)
     int mach;
     enum cgen_endian endian;
{
  m32r_cgen_init_tables (mach);
  cgen_set_cpu (& m32r_cgen_opcode_data, mach, endian);
  cgen_asm_init ();
}