| @@ -1116,6 +1116,142 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) · 1115 unmodified lines |
| 1116 | } | 1116 | } |
| 1117 | } | 1117 | } |
| 1118 | | 1118 | |
| | 1119 | static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token) |
| | 1120 | { |
| | 1121 | Operand ops[3]; |
| | 1122 | int exclam = 0; |
| | 1123 | int closed_bracket = 0; |
| | 1124 | int op2_minus = 0; |
| | 1125 | uint32_t opcode = (1 << 7) | (1 << 4); |
| | 1126 | |
| | 1127 | /* Note: |
| | 1128 | The argument syntax is exactly the same as in arm_single_data_transfer_opcode, except that there's no STREX argument form. |
| | 1129 | The main difference between this function and asm_misc_single_data_transfer_opcode is that the immediate values here must be smaller. |
| | 1130 | Also, the combination (P=0, W=1) is unpredictable here. |
| | 1131 | The immediate flag has moved to bit index 22--and its meaning has flipped. |
| | 1132 | The immediate value itself has been split into two parts: one at bits 11...8, one at bits 3...0 |
| | 1133 | bit 26 (Load/Store instruction) is unset here. |
| | 1134 | bits 7 and 4 are set here. */ |
| | 1135 | |
| | 1136 | // Here: 0 0 0 P U I W L << 20 |
| | 1137 | // [compare single data transfer: 0 1 I P U B W L << 20] |
| | 1138 | |
| | 1139 | parse_operand(s1, &ops[0]); |
| | 1140 | if (ops[0].type == OP_REG32) |
| | 1141 | opcode |= ENCODE_RD(ops[0].reg); |
| | 1142 | else { |
| | 1143 | expect("(destination operand) register"); |
| | 1144 | return; |
| | 1145 | } |
| | 1146 | if (tok != ',') |
| | 1147 | expect("at least two arguments"); |
| | 1148 | else |
| | 1149 | next(); // skip ',' |
| | 1150 | |
| | 1151 | if (tok != '[') |
| | 1152 | expect("'['"); |
| | 1153 | else |
| | 1154 | next(); // skip '[' |
| | 1155 | |
| | 1156 | parse_operand(s1, &ops[1]); |
| | 1157 | if (ops[1].type == OP_REG32) |
| | 1158 | opcode |= ENCODE_RN(ops[1].reg); |
| | 1159 | else { |
| | 1160 | expect("(first source operand) register"); |
| | 1161 | return; |
| | 1162 | } |
| | 1163 | if (tok == ']') { |
| | 1164 | next(); |
| | 1165 | closed_bracket = 1; |
| | 1166 | // exclam = 1; // implicit in hardware; don't do it in software |
| | 1167 | } |
| | 1168 | if (tok == ',') { |
| | 1169 | next(); // skip ',' |
| | 1170 | if (tok == '-') { |
| | 1171 | op2_minus = 1; |
| | 1172 | next(); |
| | 1173 | } |
| | 1174 | parse_operand(s1, &ops[2]); |
| | 1175 | } else { |
| | 1176 | // end of input expression in brackets--assume 0 offset |
| | 1177 | ops[2].type = OP_IM8; |
| | 1178 | ops[2].e.v = 0; |
| | 1179 | opcode |= 1 << 24; // add offset before transfer |
| | 1180 | } |
| | 1181 | if (!closed_bracket) { |
| | 1182 | if (tok != ']') |
| | 1183 | expect("']'"); |
| | 1184 | else |
| | 1185 | next(); // skip ']' |
| | 1186 | opcode |= 1 << 24; // add offset before transfer |
| | 1187 | if (tok == '!') { |
| | 1188 | exclam = 1; |
| | 1189 | next(); // skip '!' |
| | 1190 | } |
| | 1191 | } |
| | 1192 | |
| | 1193 | if (exclam) { |
| | 1194 | if ((opcode & (1 << 24)) == 0) { |
| | 1195 | tcc_error("result of '%s' would be unpredictable here", get_tok_str(token, NULL)); |
| | 1196 | return; |
| | 1197 | } |
| | 1198 | opcode |= 1 << 21; // write offset back into register |
| | 1199 | } |
| | 1200 | |
| | 1201 | if (ops[2].type == OP_IM32 || ops[2].type == OP_IM8 || ops[2].type == OP_IM8N) { |
| | 1202 | int v = ops[2].e.v; |
| | 1203 | if (op2_minus) |
| | 1204 | tcc_error("minus before '#' not supported for immediate values"); |
| | 1205 | if (v >= 0) { |
| | 1206 | opcode |= 1 << 23; // up |
| | 1207 | if (v >= 0x100) |
| | 1208 | tcc_error("offset out of range for '%s'", get_tok_str(token, NULL)); |
| | 1209 | else { |
| | 1210 | // bits 11...8: immediate hi nibble |
| | 1211 | // bits 3...0: immediate lo nibble |
| | 1212 | opcode |= (v & 0xF0) << 4; |
| | 1213 | opcode |= v & 0xF; |
| | 1214 | } |
| | 1215 | } else { // down |
| | 1216 | if (v <= -0x100) |
| | 1217 | tcc_error("offset out of range for '%s'", get_tok_str(token, NULL)); |
| | 1218 | else { |
| | 1219 | v = -v; |
| | 1220 | // bits 11...8: immediate hi nibble |
| | 1221 | // bits 3...0: immediate lo nibble |
| | 1222 | opcode |= (v & 0xF0) << 4; |
| | 1223 | opcode |= v & 0xF; |
| | 1224 | } |
| | 1225 | } |
| | 1226 | opcode |= 1 << 22; // not ENCODE_IMMEDIATE_FLAG; |
| | 1227 | } else if (ops[2].type == OP_REG32) { |
| | 1228 | if (!op2_minus) |
| | 1229 | opcode |= 1 << 23; // up |
| | 1230 | opcode |= ops[2].reg; |
| | 1231 | } else |
| | 1232 | expect("register"); |
| | 1233 | |
| | 1234 | switch (ARM_INSTRUCTION_GROUP(token)) { |
| | 1235 | case TOK_ASM_ldrsheq: |
| | 1236 | opcode |= 1 << 5; // halfword, not byte |
| | 1237 | /* fallthrough */ |
| | 1238 | case TOK_ASM_ldrsbeq: |
| | 1239 | opcode |= 1 << 6; // sign extend |
| | 1240 | opcode |= 1 << 20; // L |
| | 1241 | asm_emit_opcode(token, opcode); |
| | 1242 | break; |
| | 1243 | case TOK_ASM_ldrheq: |
| | 1244 | opcode |= 1 << 5; // halfword, not byte |
| | 1245 | opcode |= 1 << 20; // L |
| | 1246 | asm_emit_opcode(token, opcode); |
| | 1247 | break; |
| | 1248 | case TOK_ASM_strheq: |
| | 1249 | opcode |= 1 << 5; // halfword, not byte |
| | 1250 | asm_emit_opcode(token, opcode); |
| | 1251 | break; |
| | 1252 | } |
| | 1253 | } |
| | 1254 | |
| 1119 | /* Note: almost dupe of encbranch in arm-gen.c */ | 1255 | /* Note: almost dupe of encbranch in arm-gen.c */ |
| 1120 | static uint32_t encbranchoffset(int pos, int addr, int fail) | 1256 | static uint32_t encbranchoffset(int pos, int addr, int fail) |
| 1121 | { | 1257 | { |
| @@ -1232,6 +1368,12 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 110 unmodified lines |
| 1232 | case TOK_ASM_strexbeq: | 1368 | case TOK_ASM_strexbeq: |
| 1233 | return asm_single_data_transfer_opcode(s1, token); | 1369 | return asm_single_data_transfer_opcode(s1, token); |
| 1234 | | 1370 | |
| | 1371 | case TOK_ASM_ldrheq: |
| | 1372 | case TOK_ASM_ldrsheq: |
| | 1373 | case TOK_ASM_ldrsbeq: |
| | 1374 | case TOK_ASM_strheq: |
| | 1375 | return asm_misc_single_data_transfer_opcode(s1, token); |
| | 1376 | |
| 1235 | case TOK_ASM_andeq: | 1377 | case TOK_ASM_andeq: |
| 1236 | case TOK_ASM_eoreq: | 1378 | case TOK_ASM_eoreq: |
| 1237 | case TOK_ASM_subeq: | 1379 | case TOK_ASM_subeq: |