History

arm-asm: Add ldc, ldcl, stc, stcl

Danny Milosavljevic committed 5 years ago

Commit 7900a6b1 parent d1a6c4a3 files · +188 −1Browse files

Unified · Split

3 files
  1. arm-asm.c +177 −1
  2. arm-tok.h +5 −0
  3. tests/arm-asm-testsuite.sh +6 −0
arm-asm.c+177−1
@@ -165,6 +165,10 @@ static void asm_emit_opcode(int token, uint32_t opcode) { · 164 unmodified lines
165165 gen_le32((condition_code_of_token(token) << 28) | opcode);
166166 }
167167
168+static void asm_emit_unconditional_opcode(uint32_t opcode) {
169+ gen_le32(opcode);
170+}
171+
168172 static void asm_emit_coprocessor_opcode(uint32_t high_nibble, uint8_t cp_number, uint8_t cp_opcode, uint8_t cp_destination_register, uint8_t cp_n_operand_register, uint8_t cp_m_operand_register, uint8_t cp_opcode2, int inter_processor_transfer)
169173 {
170174 uint32_t opcode = 0xe000000;
@@ -182,7 +186,7 @@ static void asm_emit_coprocessor_opcode(uint32_t high_nibble, uint8_t cp_number, · 11 unmodified lines
182186 opcode |= cp_opcode2 << 5;
183187 //assert(cp_m_operand_register < 16);
184188 opcode |= cp_m_operand_register;
185− gen_le32((high_nibble << 28) | opcode);
189+ asm_emit_unconditional_opcode((high_nibble << 28) | opcode);
186190 }
187191
188192 static void asm_nullary_opcode(int token)
@@ -1260,6 +1264,171 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) · 1071 unmodified lines
12601264 }
12611265 }
12621266
1267+static void asm_emit_coprocessor_data_transfer(uint32_t high_nibble, uint8_t cp_number, uint8_t CRd, const Operand* Rn, const Operand* offset, int offset_minus, int preincrement, int writeback, int long_transfer, int load) {
1268+ uint32_t opcode = 0x0;
1269+ opcode |= 1 << 26; // Load/Store
1270+ opcode |= 1 << 27; // coprocessor
1271+
1272+ if (long_transfer)
1273+ opcode |= 1 << 22; // long transfer
1274+
1275+ if (load)
1276+ opcode |= 1 << 20; // L
1277+
1278+ opcode |= cp_number << 8;
1279+
1280+ opcode |= ENCODE_RD(CRd);
1281+
1282+ if (Rn->type != OP_REG32) {
1283+ expect("register");
1284+ return;
1285+ }
1286+ opcode |= ENCODE_RN(Rn->reg);
1287+ if (preincrement)
1288+ opcode |= 1 << 24; // add offset before transfer
1289+
1290+ if (writeback)
1291+ opcode |= 1 << 21; // write offset back into register
1292+
1293+ if (offset->type == OP_IM8 || offset->type == OP_IM8N || offset->type == OP_IM32) {
1294+ int v = offset->e.v;
1295+ if (offset_minus)
1296+ tcc_error("minus before '#' not supported for immediate values");
1297+ if (offset->type == OP_IM8N || v < 0)
1298+ v = -v;
1299+ else
1300+ opcode |= 1 << 23; // up
1301+ if (v & 3) {
1302+ tcc_error("immediate offset must be a multiple of 4");
1303+ return;
1304+ }
1305+ v >>= 2;
1306+ if (v > 255) {
1307+ tcc_error("immediate offset must be between -1020 and 1020");
1308+ return;
1309+ }
1310+ opcode |= v;
1311+ } else if (offset->type == OP_REG32) {
1312+ if (!offset_minus)
1313+ opcode |= 1 << 23; // up
1314+ opcode |= ENCODE_IMMEDIATE_FLAG; /* if set, it means it's NOT immediate */
1315+ opcode |= offset->reg;
1316+ tcc_error("Using register offset to register address is not possible here");
1317+ return;
1318+ } else
1319+ expect("immediate or register");
1320+
1321+ asm_emit_unconditional_opcode((high_nibble << 28) | opcode);
1322+}
1323+
1324+// Almost exactly the same as asm_single_data_transfer_opcode.
1325+// Difference: Offsets are smaller and multiples of 4; no shifts, no STREX, ENCODE_IMMEDIATE_FLAG is inverted again.
1326+static void asm_coprocessor_data_transfer_opcode(TCCState *s1, int token)
1327+{
1328+ Operand ops[3];
1329+ uint8_t coprocessor;
1330+ uint8_t coprocessor_destination_register;
1331+ int preincrement = 0;
1332+ int exclam = 0;
1333+ int closed_bracket = 0;
1334+ int op2_minus = 0;
1335+ int long_transfer = 0;
1336+ // Note: ldc p1, c0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged
1337+ // Note: ldc p2, c0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4
1338+ // Note: ldc p3, c0, [r4], #4 ; post-indexed: r0 = *(int*)(r4+0); r4 = r4+4
1339+
1340+ if (tok >= TOK_ASM_p0 && tok <= TOK_ASM_p15) {
1341+ coprocessor = tok - TOK_ASM_p0;
1342+ next();
1343+ } else {
1344+ expect("'c<number>'");
1345+ return;
1346+ }
1347+
1348+ if (tok == ',')
1349+ next();
1350+ else
1351+ expect("','");
1352+
1353+ if (tok >= TOK_ASM_c0 && tok <= TOK_ASM_c15) {
1354+ coprocessor_destination_register = tok - TOK_ASM_c0;
1355+ next();
1356+ } else {
1357+ expect("'c<number>'");
1358+ return;
1359+ }
1360+
1361+ if (tok == ',')
1362+ next();
1363+ else
1364+ expect("','");
1365+
1366+ if (tok != '[')
1367+ expect("'['");
1368+ else
1369+ next(); // skip '['
1370+
1371+ parse_operand(s1, &ops[1]);
1372+ if (ops[1].type != OP_REG32) {
1373+ expect("(first source operand) register");
1374+ return;
1375+ }
1376+ if (tok == ']') {
1377+ next();
1378+ closed_bracket = 1;
1379+ // exclam = 1; // implicit in hardware; don't do it in software
1380+ }
1381+ if (tok == ',') {
1382+ next(); // skip ','
1383+ if (tok == '-') {
1384+ op2_minus = 1;
1385+ next();
1386+ }
1387+ parse_operand(s1, &ops[2]);
1388+ if (ops[2].type == OP_REG32) {
1389+ if (ops[2].reg == 15) {
1390+ tcc_error("Using 'pc' for register offset in '%s' is not implemented by ARM", get_tok_str(token, NULL));
1391+ return;
1392+ }
1393+ }
1394+ } else {
1395+ // end of input expression in brackets--assume 0 offset
1396+ ops[2].type = OP_IM8;
1397+ ops[2].e.v = 0;
1398+ preincrement = 1; // add offset before transfer
1399+ }
1400+ if (!closed_bracket) {
1401+ if (tok != ']')
1402+ expect("']'");
1403+ else
1404+ next(); // skip ']'
1405+ preincrement = 1; // add offset before transfer
1406+ if (tok == '!') {
1407+ exclam = 1;
1408+ next(); // skip '!'
1409+ }
1410+ }
1411+
1412+ // TODO: Support options.
1413+
1414+ switch (ARM_INSTRUCTION_GROUP(token)) {
1415+ case TOK_ASM_stcleq:
1416+ long_transfer = 1;
1417+ /* fallthrough */
1418+ case TOK_ASM_stceq:
1419+ asm_emit_coprocessor_data_transfer(condition_code_of_token(token), coprocessor, coprocessor_destination_register, &ops[1], &ops[2], op2_minus, preincrement, exclam, long_transfer, 0);
1420+ break;
1421+ case TOK_ASM_ldcleq:
1422+ long_transfer = 1;
1423+ /* fallthrough */
1424+ case TOK_ASM_ldceq:
1425+ asm_emit_coprocessor_data_transfer(condition_code_of_token(token), coprocessor, coprocessor_destination_register, &ops[1], &ops[2], op2_minus, preincrement, exclam, long_transfer, 1);
1426+ break;
1427+ default:
1428+ expect("coprocessor data transfer instruction");
1429+ }
1430+}
1431+
12631432 static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token)
12641433 {
12651434 Operand ops[3];
@@ -1589,6 +1758,13 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 323 unmodified lines
15891758 case TOK_ASM_mcreq:
15901759 case TOK_ASM_mrceq:
15911760 return asm_coprocessor_opcode(s1, token);
1761+
1762+ case TOK_ASM_ldceq:
1763+ case TOK_ASM_ldcleq:
1764+ case TOK_ASM_stceq:
1765+ case TOK_ASM_stcleq:
1766+ return asm_coprocessor_data_transfer_opcode(s1, token);
1767+
15921768 default:
15931769 expect("known instruction");
15941770 }
arm-tok.h+5−0
@@ -155,6 +155,11 @@ · 154 unmodified lines
155155 DEF_ASM_CONDED(stmib)
156156 DEF_ASM_CONDED(ldmib)
157157
158+ DEF_ASM_CONDED(ldc)
159+ DEF_ASM_CONDED(ldcl)
160+ DEF_ASM_CONDED(stc)
161+ DEF_ASM_CONDED(stcl)
162+
158163 /* instruction macros */
159164
160165 DEF_ASM_CONDED(push)
tests/arm-asm-testsuite.sh+6−0
@@ -97,6 +97,12 @@ do · 96 unmodified lines
9797 "p10, #7, r2, c0, c1, #4" \
9898 "#4" \
9999 "#-4" \
100+ "p5, c2, [r3]" \
101+ "p5, c3, [r4]" \
102+ "p5, c2, [r3, #4]" \
103+ "p5, c2, [r3, #-4]" \
104+ "p5, c2, [r3, #0x45]" \
105+ "p5, c2, [r3, #-0x45]" \
100106 ""
101107 do
102108 #echo ".syntax unified" > a.s

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t