1/*
2 * LC-3b identifier recognition and instruction handling
3 *
4 *  Copyright (C) 2003-2007  Peter Johnson
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27#include <util.h>
28
29#include <libyasm.h>
30
31#include "modules/arch/lc3b/lc3barch.h"
32
33
34/* Opcode modifiers.  The opcode bytes are in "reverse" order because the
35 * parameters are read from the arch-specific data in LSB->MSB order.
36 * (only for asthetic reasons in the lexer code below, no practical reason).
37 */
38#define MOD_OpHAdd  (1UL<<0)    /* Parameter adds to upper 8 bits of insn */
39#define MOD_OpLAdd  (1UL<<1)    /* Parameter adds to lower 8 bits of insn */
40
41/* Operand types.  These are more detailed than the "general" types for all
42 * architectures, as they include the size, for instance.
43 * Bit Breakdown (from LSB to MSB):
44 *  - 1 bit = general type (must be exact match, except for =3):
45 *            0 = immediate
46 *            1 = register
47 *
48 * MSBs than the above are actions: what to do with the operand if the
49 * instruction matches.  Essentially describes what part of the output bytecode
50 * gets the operand.  This may require conversion (e.g. a register going into
51 * an ea field).  Naturally, only one of each of these may be contained in the
52 * operands of a single insn_info structure.
53 *  - 2 bits = action:
54 *             0 = does nothing (operand data is discarded)
55 *             1 = DR field
56 *             2 = SR field
57 *             3 = immediate
58 *
59 * Immediate operands can have different sizes.
60 *  - 3 bits = size:
61 *             0 = no immediate
62 *             1 = 4-bit immediate
63 *             2 = 5-bit immediate
64 *             3 = 6-bit index, word (16 bit)-multiple
65 *             4 = 6-bit index, byte-multiple
66 *             5 = 8-bit immediate, word-multiple
67 *             6 = 9-bit signed immediate, word-multiple
68 *             7 = 9-bit signed offset from next PC ($+2), word-multiple
69 */
70#define OPT_Imm         0x0
71#define OPT_Reg         0x1
72#define OPT_MASK        0x1
73
74#define OPA_None        (0<<1)
75#define OPA_DR          (1<<1)
76#define OPA_SR          (2<<1)
77#define OPA_Imm         (3<<1)
78#define OPA_MASK        (3<<1)
79
80#define OPI_None        (LC3B_IMM_NONE<<3)
81#define OPI_4           (LC3B_IMM_4<<3)
82#define OPI_5           (LC3B_IMM_5<<3)
83#define OPI_6W          (LC3B_IMM_6_WORD<<3)
84#define OPI_6B          (LC3B_IMM_6_BYTE<<3)
85#define OPI_8           (LC3B_IMM_8<<3)
86#define OPI_9           (LC3B_IMM_9<<3)
87#define OPI_9PC         (LC3B_IMM_9_PC<<3)
88#define OPI_MASK        (7<<3)
89
90typedef struct lc3b_insn_info {
91    /* Opcode modifiers for variations of instruction.  As each modifier reads
92     * its parameter in LSB->MSB order from the arch-specific data[1] from the
93     * lexer data, and the LSB of the arch-specific data[1] is reserved for the
94     * count of insn_info structures in the instruction grouping, there can
95     * only be a maximum of 3 modifiers.
96     */
97    unsigned int modifiers;
98
99    /* The basic 2 byte opcode */
100    unsigned int opcode;
101
102    /* The number of operands this form of the instruction takes */
103    unsigned char num_operands;
104
105    /* The types of each operand, see above */
106    unsigned int operands[3];
107} lc3b_insn_info;
108
109typedef struct lc3b_id_insn {
110    yasm_insn insn;     /* base structure */
111
112    /* instruction parse group - NULL if empty instruction (just prefixes) */
113    /*@null@*/ const lc3b_insn_info *group;
114
115    /* Modifier data */
116    unsigned long mod_data;
117
118    /* Number of elements in the instruction parse group */
119    unsigned int num_info:8;
120} lc3b_id_insn;
121
122static void lc3b_id_insn_destroy(void *contents);
123static void lc3b_id_insn_print(const void *contents, FILE *f, int indent_level);
124static void lc3b_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
125
126static const yasm_bytecode_callback lc3b_id_insn_callback = {
127    lc3b_id_insn_destroy,
128    lc3b_id_insn_print,
129    lc3b_id_insn_finalize,
130    NULL,
131    yasm_bc_calc_len_common,
132    yasm_bc_expand_common,
133    yasm_bc_tobytes_common,
134    YASM_BC_SPECIAL_INSN
135};
136
137/*
138 * Instruction groupings
139 */
140
141static const lc3b_insn_info empty_insn[] = {
142    { 0, 0, 0, {0, 0, 0} }
143};
144
145static const lc3b_insn_info addand_insn[] = {
146    { MOD_OpHAdd, 0x1000, 3,
147      {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, OPT_Reg|OPA_Imm|OPI_5} },
148    { MOD_OpHAdd, 0x1020, 3,
149      {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, OPT_Imm|OPA_Imm|OPI_5} }
150};
151
152static const lc3b_insn_info br_insn[] = {
153    { MOD_OpHAdd, 0x0000, 1, {OPT_Imm|OPA_Imm|OPI_9PC, 0, 0} }
154};
155
156static const lc3b_insn_info jmp_insn[] = {
157    { 0, 0xC000, 2, {OPT_Reg|OPA_DR, OPT_Imm|OPA_Imm|OPI_9, 0} }
158};
159
160static const lc3b_insn_info lea_insn[] = {
161    { 0, 0xE000, 2, {OPT_Reg|OPA_DR, OPT_Imm|OPA_Imm|OPI_9PC, 0} }
162};
163
164static const lc3b_insn_info ldst_insn[] = {
165    { MOD_OpHAdd, 0x0000, 3,
166      {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, OPT_Imm|OPA_Imm|OPI_6W} }
167};
168
169static const lc3b_insn_info ldstb_insn[] = {
170    { MOD_OpHAdd, 0x0000, 3,
171      {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, OPT_Imm|OPA_Imm|OPI_6B} }
172};
173
174static const lc3b_insn_info not_insn[] = {
175    { 0, 0x903F, 2, {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, 0} }
176};
177
178static const lc3b_insn_info nooperand_insn[] = {
179    { MOD_OpHAdd, 0x0000, 0, {0, 0, 0} }
180};
181
182static const lc3b_insn_info shift_insn[] = {
183    { MOD_OpLAdd, 0xD000, 3,
184      {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, OPT_Imm|OPA_Imm|OPI_4} }
185};
186
187static const lc3b_insn_info trap_insn[] = {
188    { 0, 0xF000, 1, {OPT_Imm|OPA_Imm|OPI_8, 0, 0} }
189};
190
191static void
192lc3b_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
193{
194    lc3b_id_insn *id_insn = (lc3b_id_insn *)bc->contents;
195    lc3b_insn *insn;
196    int num_info = id_insn->num_info;
197    const lc3b_insn_info *info = id_insn->group;
198    unsigned long mod_data = id_insn->mod_data;
199    int found = 0;
200    yasm_insn_operand *op;
201    int i;
202
203    yasm_insn_finalize(&id_insn->insn);
204
205    /* Just do a simple linear search through the info array for a match.
206     * First match wins.
207     */
208    for (; num_info>0 && !found; num_info--, info++) {
209        int mismatch = 0;
210
211        /* Match # of operands */
212        if (id_insn->insn.num_operands != info->num_operands)
213            continue;
214
215        if (id_insn->insn.num_operands == 0) {
216            found = 1;      /* no operands -> must have a match here. */
217            break;
218        }
219
220        /* Match each operand type and size */
221        for(i = 0, op = yasm_insn_ops_first(&id_insn->insn);
222            op && i<info->num_operands && !mismatch;
223            op = yasm_insn_op_next(op), i++) {
224            /* Check operand type */
225            switch ((int)(info->operands[i] & OPT_MASK)) {
226                case OPT_Imm:
227                    if (op->type != YASM_INSN__OPERAND_IMM)
228                        mismatch = 1;
229                    break;
230                case OPT_Reg:
231                    if (op->type != YASM_INSN__OPERAND_REG)
232                        mismatch = 1;
233                    break;
234                default:
235                    yasm_internal_error(N_("invalid operand type"));
236            }
237
238            if (mismatch)
239                break;
240        }
241
242        if (!mismatch) {
243            found = 1;
244            break;
245        }
246    }
247
248    if (!found) {
249        /* Didn't find a matching one */
250        yasm_error_set(YASM_ERROR_TYPE,
251                       N_("invalid combination of opcode and operands"));
252        return;
253    }
254
255    /* Copy what we can from info */
256    insn = yasm_xmalloc(sizeof(lc3b_insn));
257    yasm_value_initialize(&insn->imm, NULL, 0);
258    insn->imm_type = LC3B_IMM_NONE;
259    insn->opcode = info->opcode;
260
261    /* Apply modifiers */
262    if (info->modifiers & MOD_OpHAdd) {
263        insn->opcode += ((unsigned int)(mod_data & 0xFF))<<8;
264        mod_data >>= 8;
265    }
266    if (info->modifiers & MOD_OpLAdd) {
267        insn->opcode += (unsigned int)(mod_data & 0xFF);
268        /*mod_data >>= 8;*/
269    }
270
271    /* Go through operands and assign */
272    if (id_insn->insn.num_operands > 0) {
273        for(i = 0, op = yasm_insn_ops_first(&id_insn->insn);
274            op && i<info->num_operands; op = yasm_insn_op_next(op), i++) {
275
276            switch ((int)(info->operands[i] & OPA_MASK)) {
277                case OPA_None:
278                    /* Throw away the operand contents */
279                    if (op->type == YASM_INSN__OPERAND_IMM)
280                        yasm_expr_destroy(op->data.val);
281                    break;
282                case OPA_DR:
283                    if (op->type != YASM_INSN__OPERAND_REG)
284                        yasm_internal_error(N_("invalid operand conversion"));
285                    insn->opcode |= ((unsigned int)(op->data.reg & 0x7)) << 9;
286                    break;
287                case OPA_SR:
288                    if (op->type != YASM_INSN__OPERAND_REG)
289                        yasm_internal_error(N_("invalid operand conversion"));
290                    insn->opcode |= ((unsigned int)(op->data.reg & 0x7)) << 6;
291                    break;
292                case OPA_Imm:
293                    insn->imm_type = (info->operands[i] & OPI_MASK)>>3;
294                    switch (op->type) {
295                        case YASM_INSN__OPERAND_IMM:
296                            if (insn->imm_type == LC3B_IMM_6_WORD
297                                || insn->imm_type == LC3B_IMM_8
298                                || insn->imm_type == LC3B_IMM_9
299                                || insn->imm_type == LC3B_IMM_9_PC)
300                                op->data.val = yasm_expr_create(YASM_EXPR_SHR,
301                                    yasm_expr_expr(op->data.val),
302                                    yasm_expr_int(yasm_intnum_create_uint(1)),
303                                    op->data.val->line);
304                            if (yasm_value_finalize_expr(&insn->imm,
305                                                         op->data.val,
306                                                         prev_bc, 0))
307                                yasm_error_set(YASM_ERROR_TOO_COMPLEX,
308                                    N_("immediate expression too complex"));
309                            break;
310                        case YASM_INSN__OPERAND_REG:
311                            if (yasm_value_finalize_expr(&insn->imm,
312                                    yasm_expr_create_ident(yasm_expr_int(
313                                    yasm_intnum_create_uint(op->data.reg & 0x7)),
314                                    bc->line), prev_bc, 0))
315                                yasm_internal_error(N_("reg expr too complex?"));
316                            break;
317                        default:
318                            yasm_internal_error(N_("invalid operand conversion"));
319                    }
320                    break;
321                default:
322                    yasm_internal_error(N_("unknown operand action"));
323            }
324
325            /* Clear so it doesn't get destroyed */
326            op->type = YASM_INSN__OPERAND_REG;
327        }
328
329        if (insn->imm_type == LC3B_IMM_9_PC) {
330            if (insn->imm.seg_of || insn->imm.rshift > 1
331                || insn->imm.curpos_rel)
332                yasm_error_set(YASM_ERROR_VALUE, N_("invalid jump target"));
333            insn->imm.curpos_rel = 1;
334        }
335    }
336
337    /* Transform the bytecode */
338    yasm_lc3b__bc_transform_insn(bc, insn);
339}
340
341
342#define YYCTYPE         unsigned char
343#define YYCURSOR        id
344#define YYLIMIT         id
345#define YYMARKER        marker
346#define YYFILL(n)       (void)(n)
347
348yasm_arch_regtmod
349yasm_lc3b__parse_check_regtmod(yasm_arch *arch, const char *oid, size_t id_len,
350                               uintptr_t *data)
351{
352    const YYCTYPE *id = (const YYCTYPE *)oid;
353    /*const char *marker;*/
354    /*!re2c
355        /* integer registers */
356        'r' [0-7]       {
357            *data = (oid[1]-'0');
358            return YASM_ARCH_REG;
359        }
360
361        /* catchalls */
362        [\001-\377]+    {
363            return YASM_ARCH_NOTREGTMOD;
364        }
365        [\000]  {
366            return YASM_ARCH_NOTREGTMOD;
367        }
368    */
369}
370
371#define RET_INSN(g, m) \
372    do { \
373        group = g##_insn; \
374        mod = m; \
375        nelems = NELEMS(g##_insn); \
376        goto done; \
377    } while(0)
378
379yasm_arch_insnprefix
380yasm_lc3b__parse_check_insnprefix(yasm_arch *arch, const char *oid,
381                                  size_t id_len, unsigned long line,
382                                  yasm_bytecode **bc, uintptr_t *prefix)
383{
384    const YYCTYPE *id = (const YYCTYPE *)oid;
385    const lc3b_insn_info *group = empty_insn;
386    unsigned long mod = 0;
387    unsigned int nelems = NELEMS(empty_insn);
388    lc3b_id_insn *id_insn;
389
390    *bc = (yasm_bytecode *)NULL;
391    *prefix = 0;
392
393    /*const char *marker;*/
394    /*!re2c
395        /* instructions */
396
397        'add' { RET_INSN(addand, 0x00); }
398        'and' { RET_INSN(addand, 0x40); }
399
400        'br' { RET_INSN(br, 0x00); }
401        'brn' { RET_INSN(br, 0x08); }
402        'brz' { RET_INSN(br, 0x04); }
403        'brp' { RET_INSN(br, 0x02); }
404        'brnz' { RET_INSN(br, 0x0C); }
405        'brnp' { RET_INSN(br, 0x0A); }
406        'brzp' { RET_INSN(br, 0x06); }
407        'brnzp' { RET_INSN(br, 0x0E); }
408        'jsr' { RET_INSN(br, 0x40); }
409
410        'jmp' { RET_INSN(jmp, 0); }
411
412        'lea' { RET_INSN(lea, 0); }
413
414        'ld' { RET_INSN(ldst, 0x20); }
415        'ldi' { RET_INSN(ldst, 0xA0); }
416        'st' { RET_INSN(ldst, 0x30); }
417        'sti' { RET_INSN(ldst, 0xB0); }
418
419        'ldb' { RET_INSN(ldstb, 0x60); }
420        'stb' { RET_INSN(ldstb, 0x70); }
421
422        'not' { RET_INSN(not, 0); }
423
424        'ret' { RET_INSN(nooperand, 0xCE); }
425        'rti' { RET_INSN(nooperand, 0x80); }
426        'nop' { RET_INSN(nooperand, 0); }
427
428        'lshf' { RET_INSN(shift, 0x00); }
429        'rshfl' { RET_INSN(shift, 0x10); }
430        'rshfa' { RET_INSN(shift, 0x30); }
431
432        'trap' { RET_INSN(trap, 0); }
433
434        /* catchalls */
435        [\001-\377]+    {
436            return YASM_ARCH_NOTINSNPREFIX;
437        }
438        [\000]  {
439            return YASM_ARCH_NOTINSNPREFIX;
440        }
441    */
442
443done:
444    id_insn = yasm_xmalloc(sizeof(lc3b_id_insn));
445    yasm_insn_initialize(&id_insn->insn);
446    id_insn->group = group;
447    id_insn->mod_data = mod;
448    id_insn->num_info = nelems;
449    *bc = yasm_bc_create_common(&lc3b_id_insn_callback, id_insn, line);
450    return YASM_ARCH_INSN;
451}
452
453static void
454lc3b_id_insn_destroy(void *contents)
455{
456    lc3b_id_insn *id_insn = (lc3b_id_insn *)contents;
457    yasm_insn_delete(&id_insn->insn, yasm_lc3b__ea_destroy);
458    yasm_xfree(contents);
459}
460
461static void
462lc3b_id_insn_print(const void *contents, FILE *f, int indent_level)
463{
464    const lc3b_id_insn *id_insn = (const lc3b_id_insn *)contents;
465    yasm_insn_print(&id_insn->insn, f, indent_level);
466    /*TODO*/
467}
468
469/*@only@*/ yasm_bytecode *
470yasm_lc3b__create_empty_insn(yasm_arch *arch, unsigned long line)
471{
472    lc3b_id_insn *id_insn = yasm_xmalloc(sizeof(lc3b_id_insn));
473
474    yasm_insn_initialize(&id_insn->insn);
475    id_insn->group = empty_insn;
476    id_insn->mod_data = 0;
477    id_insn->num_info = NELEMS(empty_insn);
478
479    return yasm_bc_create_common(&lc3b_id_insn_callback, id_insn, line);
480}
481