History

arm-asm: Add and, eor, sub, rsb, add, adc, sbc, rsc, tst, teq, cmp, cmn, orr, mov, bic, mvn

Danny Milosavljevic committed 5 years ago

Commit 3b1f06c1 parent c7682dd2 files · +200 −0Browse files

Unified · Split

2 files
  1. arm-asm.c +165 −0
  2. arm-tok.h +35 −0
arm-asm.c+165−0
@@ -347,6 +347,137 @@ static void asm_block_data_transfer_opcode(TCCState *s1, int token) · 346 unmodified lines
347347 }
348348 }
349349
350+static void asm_data_processing_opcode(TCCState *s1, int token)
351+{
352+ Operand ops[3];
353+ int nb_ops;
354+
355+ /* 16 entries per instruction for the different condition codes */
356+ uint32_t opcode_idx = (ARM_INSTRUCTION_GROUP(token) - TOK_ASM_andeq) >> 4;
357+
358+ for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
359+ parse_operand(s1, &ops[nb_ops]);
360+ if (tok != ',') {
361+ ++nb_ops;
362+ break;
363+ }
364+ next(); // skip ','
365+ }
366+ if (nb_ops < 2)
367+ expect("at least two operands");
368+ else if (nb_ops == 2) {
369+ memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
370+ memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
371+ nb_ops = 3;
372+ }
373+ if (nb_ops != 3) {
374+ expect("two or three operands");
375+ return;
376+ } else {
377+ uint32_t opcode = 0;
378+ uint32_t operands = 0;
379+
380+ // data processing (general case):
381+ // operands:
382+ // Rn: bits 19...16 (first operand)
383+ // Rd: bits 15...12 (destination)
384+ // Operand2: bits 11...0 (second operand); depending on I that's either a register or an immediate
385+ // operator:
386+ // bits 24...21: "OpCode"--see below
387+
388+ /* operations in the token list are ordered by opcode */
389+ opcode = (opcode_idx >> 1) << 21; // drop "s"
390+ if (ops[0].type != OP_REG32)
391+ expect("(destination operand) register");
392+ else if (opcode == 0xa << 21 || opcode == 0xb << 21 || opcode == 0x8 << 21 || opcode == 0x9 << 21 ) // cmp, cmn, tst, teq
393+ operands |= ENCODE_SET_CONDITION_CODES; // force S set, otherwise it's a completely different instruction.
394+ else
395+ operands |= ENCODE_RD(ops[0].reg);
396+ if (ops[1].type != OP_REG32)
397+ expect("(first source operand) register");
398+ else if (!(opcode == 0xd << 21 || opcode == 0xf << 21)) // not: mov, mvn (those have only one source operand)
399+ operands |= ENCODE_RN(ops[1].reg);
400+ switch (ops[2].type) {
401+ case OP_REG32:
402+ // TODO: Parse and encode shift.
403+ operands |= ops[2].reg;
404+ break;
405+ case OP_IM8:
406+ // TODO: Parse and encode rotation.
407+ operands |= ENCODE_IMMEDIATE_FLAG;
408+ operands |= ops[2].e.v;
409+ break;
410+ case OP_IM8N: // immediate negative value
411+ // TODO: Parse and encode rotation.
412+ operands |= ENCODE_IMMEDIATE_FLAG;
413+ /* Instruction swapping:
414+ 0001 = EOR - Rd:= Op1 EOR Op2 -> difficult
415+ 0011 = RSB - Rd:= Op2 - Op1 -> difficult
416+ 0111 = RSC - Rd:= Op2 - Op1 + C -> difficult
417+ 1000 = TST - CC on: Op1 AND Op2 -> difficult
418+ 1001 = TEQ - CC on: Op1 EOR Op2 -> difficult
419+ 1100 = ORR - Rd:= Op1 OR Op2 -> difficult
420+ */
421+ switch (opcode_idx >> 1) { // "OpCode" in ARM docs
422+#if 0
423+ case 0x0: // AND - Rd:= Op1 AND Op2
424+ opcode = 0xe << 21; // BIC
425+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
426+ break;
427+ case 0x2: // SUB - Rd:= Op1 - Op2
428+ opcode = 0x4 << 21; // ADD
429+ operands |= (-ops[2].e.v) & 0xFF;
430+ break;
431+ case 0x4: // ADD - Rd:= Op1 + Op2
432+ opcode = 0x2 << 21; // SUB
433+ operands |= (-ops[2].e.v) & 0xFF;
434+ break;
435+ case 0x5: // ADC - Rd:= Op1 + Op2 + C
436+ opcode = 0x6 << 21; // SBC
437+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
438+ break;
439+ case 0x6: // SBC - Rd:= Op1 - Op2 + C
440+ opcode = 0x5 << 21; // ADC
441+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
442+ break;
443+#endif
444+ case 0xa: // CMP - CC on: Op1 - Op2
445+ opcode = 0xb << 21; // CMN
446+ operands |= (-ops[2].e.v) & 0xFF;
447+ break;
448+ case 0xb: // CMN - CC on: Op1 + Op2
449+ opcode = 0xa << 21; // CMP
450+ operands |= (-ops[2].e.v) & 0xFF;
451+ break;
452+ // moveq r1, r3: 0x01a01003; mov Rd, Op2
453+ case 0xd: // MOV - Rd:= Op2
454+ opcode = 0xf << 21; // MVN
455+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
456+ break;
457+#if 0
458+ case 0xe: // BIC - Rd:= Op1 AND NOT Op2
459+ opcode = 0x0 << 21; // AND
460+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
461+ break;
462+#endif
463+ case 0xf: // MVN - Rd:= NOT Op2
464+ opcode = 0xd << 21; // MOV
465+ operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
466+ break;
467+ default:
468+ tcc_error("cannot use '%s' with a negative immediate value", get_tok_str(token, NULL));
469+ }
470+ break;
471+ default:
472+ expect("(second source operand) register or immediate value");
473+ }
474+
475+ /* S=0 and S=1 entries alternate one after another, in that order */
476+ opcode |= (opcode_idx & 1) ? ENCODE_SET_CONDITION_CODES : 0;
477+ asm_emit_opcode(token, opcode | operands);
478+ }
479+}
480+
350481 static void asm_multiplication_opcode(TCCState *s1, int token)
351482 {
352483 Operand ops[4];
@@ -669,6 +800,40 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 316 unmodified lines
669800 case TOK_ASM_strbeq:
670801 return asm_single_data_transfer_opcode(s1, token);
671802
803+ case TOK_ASM_andeq:
804+ case TOK_ASM_eoreq:
805+ case TOK_ASM_subeq:
806+ case TOK_ASM_rsbeq:
807+ case TOK_ASM_addeq:
808+ case TOK_ASM_adceq:
809+ case TOK_ASM_sbceq:
810+ case TOK_ASM_rsceq:
811+ case TOK_ASM_tsteq:
812+ case TOK_ASM_teqeq:
813+ case TOK_ASM_cmpeq:
814+ case TOK_ASM_cmneq:
815+ case TOK_ASM_orreq:
816+ case TOK_ASM_moveq:
817+ case TOK_ASM_biceq:
818+ case TOK_ASM_mvneq:
819+ case TOK_ASM_andseq:
820+ case TOK_ASM_eorseq:
821+ case TOK_ASM_subseq:
822+ case TOK_ASM_rsbseq:
823+ case TOK_ASM_addseq:
824+ case TOK_ASM_adcseq:
825+ case TOK_ASM_sbcseq:
826+ case TOK_ASM_rscseq:
827+// case TOK_ASM_tstseq:
828+// case TOK_ASM_teqseq:
829+// case TOK_ASM_cmpseq:
830+// case TOK_ASM_cmnseq:
831+ case TOK_ASM_orrseq:
832+ case TOK_ASM_movseq:
833+ case TOK_ASM_bicseq:
834+ case TOK_ASM_mvnseq:
835+ return asm_data_processing_opcode(s1, token);
836+
672837 case TOK_ASM_muleq:
673838 case TOK_ASM_mulseq:
674839 case TOK_ASM_mlaeq:
arm-tok.h+35−0
@@ -103,3 +103,38 @@ · 102 unmodified lines
103103
104104 DEF_ASM_CONDED(push)
105105 DEF_ASM_CONDED(pop)
106+
107+ /* data processing instructions; order is important */
108+
109+ DEF_ASM_CONDED(and)
110+ DEF_ASM_CONDED(ands)
111+ DEF_ASM_CONDED(eor)
112+ DEF_ASM_CONDED(eors)
113+ DEF_ASM_CONDED(sub)
114+ DEF_ASM_CONDED(subs)
115+ DEF_ASM_CONDED(rsb)
116+ DEF_ASM_CONDED(rsbs)
117+ DEF_ASM_CONDED(add)
118+ DEF_ASM_CONDED(adds)
119+ DEF_ASM_CONDED(adc)
120+ DEF_ASM_CONDED(adcs)
121+ DEF_ASM_CONDED(sbc)
122+ DEF_ASM_CONDED(sbcs)
123+ DEF_ASM_CONDED(rsc)
124+ DEF_ASM_CONDED(rscs)
125+ DEF_ASM_CONDED(tst)
126+ DEF_ASM_CONDED(tsts) // necessary here--but not useful to the user
127+ DEF_ASM_CONDED(teq)
128+ DEF_ASM_CONDED(teqs) // necessary here--but not useful to the user
129+ DEF_ASM_CONDED(cmp)
130+ DEF_ASM_CONDED(cmps) // necessary here--but not useful to the user
131+ DEF_ASM_CONDED(cmn)
132+ DEF_ASM_CONDED(cmns) // necessary here--but not useful to the user
133+ DEF_ASM_CONDED(orr)
134+ DEF_ASM_CONDED(orrs)
135+ DEF_ASM_CONDED(mov)
136+ DEF_ASM_CONDED(movs)
137+ DEF_ASM_CONDED(bic)
138+ DEF_ASM_CONDED(bics)
139+ DEF_ASM_CONDED(mvn)
140+ DEF_ASM_CONDED(mvns)

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