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
yasm_lc3b__bc_transform_insn(yasm_bytecode * bc,lc3b_insn * insn)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
lc3b_bc_insn_destroy(void * contents)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
lc3b_bc_insn_print(const void * contents,FILE * f,int indent_level)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
lc3b_bc_insn_calc_len(yasm_bytecode * bc,yasm_bc_add_span_func add_span,void * add_span_data)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
lc3b_bc_insn_expand(yasm_bytecode * bc,int span,long old_val,long new_val,long * neg_thres,long * pos_thres)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
lc3b_bc_insn_tobytes(yasm_bytecode * bc,unsigned char ** bufp,unsigned char * bufstart,void * d,yasm_output_value_func output_value,yasm_output_reloc_func output_reloc)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
yasm_lc3b__intnum_tobytes(yasm_arch * arch,const yasm_intnum * intn,unsigned char * buf,size_t destsize,size_t valsize,int shift,const yasm_bytecode * bc,int warn)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