Mercurial > hg > index.cgi
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 } |