1 /* 2 * LC-3b bytecode utility functions 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 "lc3barch.h" 32 33 34 /* Bytecode callback function prototypes */ 35 36 static void lc3b_bc_insn_destroy(void *contents); 37 static void lc3b_bc_insn_print(const void *contents, FILE *f, 38 int indent_level); 39 static int lc3b_bc_insn_calc_len(yasm_bytecode *bc, 40 yasm_bc_add_span_func add_span, 41 void *add_span_data); 42 static int lc3b_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, 43 long new_val, /*@out@*/ long *neg_thres, 44 /*@out@*/ long *pos_thres); 45 static int lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, 46 unsigned char *bufstart, 47 void *d, yasm_output_value_func output_value, 48 /*@null@*/ yasm_output_reloc_func output_reloc); 49 50 /* Bytecode callback structures */ 51 52 static const yasm_bytecode_callback lc3b_bc_callback_insn = { 53 lc3b_bc_insn_destroy, 54 lc3b_bc_insn_print, 55 yasm_bc_finalize_common, 56 NULL, 57 lc3b_bc_insn_calc_len, 58 lc3b_bc_insn_expand, 59 lc3b_bc_insn_tobytes, 60 0 61 }; 62 63 64 void 65 yasm_lc3b__bc_transform_insn(yasm_bytecode *bc, lc3b_insn *insn) 66 { 67 yasm_bc_transform(bc, &lc3b_bc_callback_insn, insn); 68 } 69 70 static void 71 lc3b_bc_insn_destroy(void *contents) 72 { 73 lc3b_insn *insn = (lc3b_insn *)contents; 74 yasm_value_delete(&insn->imm); 75 yasm_xfree(contents); 76 } 77 78 static void 79 lc3b_bc_insn_print(const void *contents, FILE *f, int indent_level) 80 { 81 const lc3b_insn *insn = (const lc3b_insn *)contents; 82 83 fprintf(f, "%*s_Instruction_\n", indent_level, ""); 84 fprintf(f, "%*sImmediate Value:", indent_level, ""); 85 if (!insn->imm.abs) 86 fprintf(f, " (nil)\n"); 87 else { 88 indent_level++; 89 fprintf(f, "\n"); 90 yasm_value_print(&insn->imm, f, indent_level); 91 fprintf(f, "%*sType=", indent_level, ""); 92 switch (insn->imm_type) { 93 case LC3B_IMM_NONE: 94 fprintf(f, "NONE-SHOULDN'T HAPPEN"); 95 break; 96 case LC3B_IMM_4: 97 fprintf(f, "4-bit"); 98 break; 99 case LC3B_IMM_5: 100 fprintf(f, "5-bit"); 101 break; 102 case LC3B_IMM_6_WORD: 103 fprintf(f, "6-bit, word-multiple"); 104 break; 105 case LC3B_IMM_6_BYTE: 106 fprintf(f, "6-bit, byte-multiple"); 107 break; 108 case LC3B_IMM_8: 109 fprintf(f, "8-bit, word-multiple"); 110 break; 111 case LC3B_IMM_9: 112 fprintf(f, "9-bit, signed, word-multiple"); 113 break; 114 case LC3B_IMM_9_PC: 115 fprintf(f, "9-bit, signed, word-multiple, PC-relative"); 116 break; 117 } 118 indent_level--; 119 } 120 /* FIXME 121 fprintf(f, "\n%*sOrigin=", indent_level, ""); 122 if (insn->origin) { 123 fprintf(f, "\n"); 124 yasm_symrec_print(insn->origin, f, indent_level+1); 125 } else 126 fprintf(f, "(nil)\n"); 127 */ 128 fprintf(f, "%*sOpcode: %04x\n", indent_level, "", 129 (unsigned int)insn->opcode); 130 } 131 132 static int 133 lc3b_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, 134 void *add_span_data) 135 { 136 lc3b_insn *insn = (lc3b_insn *)bc->contents; 137 yasm_bytecode *target_prevbc; 138 139 /* Fixed size instruction length */ 140 bc->len += 2; 141 142 /* Only need to worry about out-of-range to PC-relative */ 143 if (insn->imm_type != LC3B_IMM_9_PC) 144 return 0; 145 146 if (insn->imm.rel 147 && (!yasm_symrec_get_label(insn->imm.rel, &target_prevbc) 148 || target_prevbc->section != bc->section)) { 149 /* External or out of segment, so we can't check distance. */ 150 return 0; 151 } 152 153 /* 9-bit signed, word-multiple displacement */ 154 add_span(add_span_data, bc, 1, &insn->imm, -512+(long)bc->len, 155 511+(long)bc->len); 156 return 0; 157 } 158 159 static int 160 lc3b_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val, 161 /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) 162 { 163 yasm_error_set(YASM_ERROR_VALUE, N_("jump target out of range")); 164 return -1; 165 } 166 167 static int 168 lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, 169 unsigned char *bufstart, void *d, 170 yasm_output_value_func output_value, 171 /*@unused@*/ yasm_output_reloc_func output_reloc) 172 { 173 lc3b_insn *insn = (lc3b_insn *)bc->contents; 174 /*@only@*/ yasm_intnum *delta; 175 unsigned long buf_off = (unsigned long)(*bufp - bufstart); 176 177 /* Output opcode */ 178 YASM_SAVE_16_L(*bufp, insn->opcode); 179 180 /* Insert immediate into opcode. */ 181 switch (insn->imm_type) { 182 case LC3B_IMM_NONE: 183 break; 184 case LC3B_IMM_4: 185 insn->imm.size = 4; 186 if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) 187 return 1; 188 break; 189 case LC3B_IMM_5: 190 insn->imm.size = 5; 191 insn->imm.sign = 1; 192 if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) 193 return 1; 194 break; 195 case LC3B_IMM_6_WORD: 196 insn->imm.size = 6; 197 if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) 198 return 1; 199 break; 200 case LC3B_IMM_6_BYTE: 201 insn->imm.size = 6; 202 insn->imm.sign = 1; 203 if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) 204 return 1; 205 break; 206 case LC3B_IMM_8: 207 insn->imm.size = 8; 208 if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) 209 return 1; 210 break; 211 case LC3B_IMM_9_PC: 212 /* Adjust relative displacement to end of bytecode */ 213 delta = yasm_intnum_create_int(-1); 214 if (!insn->imm.abs) 215 insn->imm.abs = yasm_expr_create_ident(yasm_expr_int(delta), 216 bc->line); 217 else 218 insn->imm.abs = 219 yasm_expr_create(YASM_EXPR_ADD, 220 yasm_expr_expr(insn->imm.abs), 221 yasm_expr_int(delta), bc->line); 222 223 insn->imm.size = 9; 224 insn->imm.sign = 1; 225 if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) 226 return 1; 227 break; 228 case LC3B_IMM_9: 229 insn->imm.size = 9; 230 if (output_value(&insn->imm, *bufp, 2, buf_off, bc, 1, d)) 231 return 1; 232 break; 233 default: 234 yasm_internal_error(N_("Unrecognized immediate type")); 235 } 236 237 *bufp += 2; /* all instructions are 2 bytes in size */ 238 return 0; 239 } 240 241 int 242 yasm_lc3b__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn, 243 unsigned char *buf, size_t destsize, size_t valsize, 244 int shift, const yasm_bytecode *bc, int warn) 245 { 246 /* Write value out. */ 247 yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn); 248 return 0; 249 } 250