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