Home | History | Annotate | Download | only in lc3b
      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 
     90 typedef 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 
    109 typedef 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 
    122 static void lc3b_id_insn_destroy(void *contents);
    123 static void lc3b_id_insn_print(const void *contents, FILE *f, int indent_level);
    124 static void lc3b_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
    125 
    126 static 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 
    141 static const lc3b_insn_info empty_insn[] = {
    142     { 0, 0, 0, {0, 0, 0} }
    143 };
    144 
    145 static 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 
    152 static const lc3b_insn_info br_insn[] = {
    153     { MOD_OpHAdd, 0x0000, 1, {OPT_Imm|OPA_Imm|OPI_9PC, 0, 0} }
    154 };
    155 
    156 static const lc3b_insn_info jmp_insn[] = {
    157     { 0, 0xC000, 2, {OPT_Reg|OPA_DR, OPT_Imm|OPA_Imm|OPI_9, 0} }
    158 };
    159 
    160 static const lc3b_insn_info lea_insn[] = {
    161     { 0, 0xE000, 2, {OPT_Reg|OPA_DR, OPT_Imm|OPA_Imm|OPI_9PC, 0} }
    162 };
    163 
    164 static 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 
    169 static 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 
    174 static const lc3b_insn_info not_insn[] = {
    175     { 0, 0x903F, 2, {OPT_Reg|OPA_DR, OPT_Reg|OPA_SR, 0} }
    176 };
    177 
    178 static const lc3b_insn_info nooperand_insn[] = {
    179     { MOD_OpHAdd, 0x0000, 0, {0, 0, 0} }
    180 };
    181 
    182 static 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 
    187 static const lc3b_insn_info trap_insn[] = {
    188     { 0, 0xF000, 1, {OPT_Imm|OPA_Imm|OPI_8, 0, 0} }
    189 };
    190 
    191 static void
    192 lc3b_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 
    348 yasm_arch_regtmod
    349 yasm_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 
    379 yasm_arch_insnprefix
    380 yasm_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 
    443 done:
    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 
    453 static void
    454 lc3b_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 
    461 static void
    462 lc3b_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 *
    470 yasm_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