comparison lwasm/insn_rel.c @ 116:7b0716264251

Pragma autobranchlength implementation completed
author lost@l-w.ca
date Tue, 09 Aug 2011 18:08:55 -0600
parents 95181f1ad183
children 2be2649841f8
comparison
equal deleted inserted replaced
115:344cfc25afec 116:7b0716264251
20 20
21 /* 21 /*
22 for handling relative mode instructions 22 for handling relative mode instructions
23 */ 23 */
24 24
25 #include <ctype.h>
25 #include <stdlib.h> 26 #include <stdlib.h>
27 #include <stdio.h>
26 28
27 #include <lw_expr.h> 29 #include <lw_expr.h>
28 30
29 #include "lwasm.h" 31 #include "lwasm.h"
30 #include "instab.h" 32 #include "instab.h"
31 33
32 PARSEFUNC(insn_parse_rel8) 34 /*
35 For generic relative, the first "opcode" is the natural opcode for the
36 mneumonic. The second "opcode" is the natural size of the relative offset.
37 These will be used when pragma autobranchlength is NOT in effect.
38
39 The third "opcode" is the short (8 bit) version of the branch. The final one
40 is the long (16 bit) version of the branch. These will be used when pragma
41 autobranchlength is in effect.
42
43 When autobranchlength is in effect, the branch target can be prefixed with
44 either < or > to force a short or long branch. Note that in this mode,
45 a > or < on its own still specifies a branch point.
46
47 */
48 PARSEFUNC(insn_parse_relgen)
33 { 49 {
34 // int v;
35 lw_expr_t t, e1, e2; 50 lw_expr_t t, e1, e2;
36 // int r; 51
37 52 l -> lint = -1;
53 if (CURPRAGMA(l, PRAGMA_AUTOBRANCHLENGTH) == 0)
54 {
55 l -> lint = instab[l -> insn].ops[1];
56 }
57 else
58 {
59 if (**p == '>' && (((*p)[1]) && !isspace((*p)[1])))
60 {
61 (*p)++;
62 l -> lint = 16;
63 }
64 else if (**p == '<' && (((*p)[1]) && !isspace((*p)[1])))
65 {
66 (*p)++;
67 l -> lint = 8;
68 }
69 }
70
71 /* forced sizes handled */
72
38 // sometimes there is a "#", ignore if there 73 // sometimes there is a "#", ignore if there
39 if (**p == '#') 74 if (**p == '#')
40 (*p)++; 75 (*p)++;
41 76
42 t = lwasm_parse_expr(as, p); 77 t = lwasm_parse_expr(as, p);
78
43 if (!t) 79 if (!t)
44 { 80 {
45 lwasm_register_error(as, l, "Bad operand"); 81 lwasm_register_error(as, l, "Bad operand");
46 return; 82 return;
47 } 83 }
48 l -> len = OPLEN(instab[l -> insn].ops[0]) + 1; 84
49 85 // if we know the length of the instruction, set it now
50 e1 = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, l); 86 if (l -> lint == 8)
51 e2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, l -> addr); 87 {
52 lw_expr_destroy(e1); 88 l -> len = OPLEN(instab[l -> insn].ops[2]) + 1;
89 }
90 else if (l -> lint == 16)
91 {
92 l -> len = OPLEN(instab[l -> insn].ops[3]) + 1;
93 }
94
95 // the offset calculation here depends on the length of this line!
96 // how to calculate requirements?
97 // this is the same problem faced by ,pcr indexing
98 e2 = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, l);
53 e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, t, e2); 99 e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, t, e2);
54 lw_expr_destroy(e2); 100 lw_expr_destroy(e2);
101 e2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, e1, l -> addr);
102 lw_expr_destroy(e1);
103 lwasm_save_expr(l, 0, e2);
55 lw_expr_destroy(t); 104 lw_expr_destroy(t);
56 lwasm_save_expr(l, 0, e1); 105
106 if (l -> len == -1)
107 {
108 e1 = lw_expr_copy(e2);
109 l -> len = OPLEN(instab[l -> insn].ops[2]) + 1;
110 lwasm_reduce_expr(as, e1);
111 l -> len = -1;
112 if (lw_expr_istype(e1, lw_expr_type_int))
113 {
114 int v;
115 v = lw_expr_intval(e1);
116 if (v >= -128 && v <= 127)
117 {
118 l -> lint = 8;
119 l -> len = OPLEN(instab[l -> insn].ops[2]) + 1;
120 }
121 else
122 {
123 l -> lint = 16;
124 l -> len = OPLEN(instab[l -> insn].ops[3]) + 2;
125 }
126 }
127 lw_expr_destroy(e1);
128 }
57 } 129 }
58 130
59 EMITFUNC(insn_emit_rel8) 131 RESOLVEFUNC(insn_resolve_relgen)
132 {
133 lw_expr_t e, e2;
134 int offs;
135
136 if (l -> lint == -1)
137 {
138 e = lwasm_fetch_expr(l, 0);
139 if (!lw_expr_istype(e, lw_expr_type_int))
140 {
141 // temporarily set the instruction length to see if we get a
142 // constant for our expression; if so, we can select an instruction
143 // size
144 e2 = lw_expr_copy(e);
145 // size of 8-bit opcode + 8 bit offset
146 l -> len = OPLEN(instab[l -> insn].ops[2]) + 1;
147 lwasm_reduce_expr(as, e2);
148 l -> len = -1;
149 if (lw_expr_istype(e2, lw_expr_type_int))
150 {
151 // it reduced to an integer; is it in 8 bit range?
152 offs = lw_expr_intval(e2);
153 if (offs >= -128 && offs <= 127)
154 {
155 // fits in 8 bits
156 l -> len = OPLEN(instab[l -> insn].ops[2]) + 1;
157 l -> lint = 8;
158 }
159 else
160 {
161 // requires 16 bits
162 l -> len = OPLEN(instab[l -> insn].ops[3]) + 2;
163 l -> lint = 16;
164 }
165 }
166 lw_expr_destroy(e2);
167 }
168 if (lw_expr_istype(e, lw_expr_type_int))
169 {
170 // it reduced to an integer; is it in 8 bit range?
171 offs = lw_expr_intval(e);
172 if (offs >= -128 && offs <= 127)
173 {
174 // fits in 8 bits
175 l -> len = OPLEN(instab[l -> insn].ops[2]) + 1;
176 l -> lint = 8;
177 }
178 else
179 {
180 // requires 16 bits
181 l -> len = OPLEN(instab[l -> insn].ops[3]) + 2;
182 l -> lint = 16;
183 }
184 }
185 }
186 if (!force)
187 return;
188
189 if (l -> len == -1)
190 {
191 l -> len = OPLEN(instab[l -> insn].ops[3]) + 2;
192 l -> lint = 16;
193 }
194 }
195
196 EMITFUNC(insn_emit_relgen)
60 { 197 {
61 lw_expr_t e; 198 lw_expr_t e;
62 int offs; 199 int offs;
63 200
64 e = lwasm_fetch_expr(l, 0); 201 e = lwasm_fetch_expr(l, 0);
65 if (!lw_expr_istype(e, lw_expr_type_int)) 202 if (l -> lint == 8)
66 { 203 {
67 lwasm_register_error(as, l, "Illegal non-constant expression"); 204 if (!lw_expr_istype(e, lw_expr_type_int))
68 return; 205 {
69 } 206 lwasm_register_error(as, l, "Illegal non-constant expression");
70 207 return;
71 offs = lw_expr_intval(e); 208 }
72 if (offs < -128 || offs > 127) 209
73 { 210 offs = lw_expr_intval(e);
74 lwasm_register_error(as, l, "Byte overflow"); 211 if (l -> lint == 8 && (offs < -128 || offs > 127))
75 return; 212 {
76 } 213 lwasm_register_error(as, l, "Byte overflow");
77 214 return;
78 lwasm_emitop(l, instab[l -> insn].ops[0]); 215 }
79 lwasm_emit(l, offs); 216
217
218 lwasm_emitop(l, instab[l -> insn].ops[2]);
219 lwasm_emit(l, offs);
220 }
221 else
222 {
223 lwasm_emitop(l, instab[l -> insn].ops[3]);
224 lwasm_emitexpr(l, e, 2);
225 }
80 } 226 }
81
82 PARSEFUNC(insn_parse_rel16)
83 {
84 // int v;
85 lw_expr_t t, e1, e2;
86 // int r;
87
88 // sometimes there is a "#", ignore if there
89 if (**p == '#')
90 (*p)++;
91
92 t = lwasm_parse_expr(as, p);
93 if (!t)
94 {
95 lwasm_register_error(as, l, "Bad operand");
96 lw_expr_destroy(t);
97 return;
98 }
99 l -> len = OPLEN(instab[l -> insn].ops[0]) + 2;
100
101 e1 = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, l);
102 e2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, l -> addr);
103 lw_expr_destroy(e1);
104 e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, t, e2);
105 lw_expr_destroy(e2);
106 lw_expr_destroy(t);
107 lwasm_save_expr(l, 0, e1);
108 }
109
110 EMITFUNC(insn_emit_rel16)
111 {
112 lw_expr_t e;
113 // int offs;
114
115 e = lwasm_fetch_expr(l, 0);
116
117 lwasm_emitop(l, instab[l -> insn].ops[0]);
118 lwasm_emitexpr(l, e, 2);
119 }