| @@ -347,6 +347,137 @@ static void asm_block_data_transfer_opcode(TCCState *s1, int token) · 346 unmodified lines |
| 347 | 347 | } |
| 348 | 348 | } |
| 349 | 349 | |
| 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 | + |
| 350 | 481 | static void asm_multiplication_opcode(TCCState *s1, int token) |
| 351 | 482 | { |
| 352 | 483 | Operand ops[4]; |
| @@ -669,6 +800,40 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 316 unmodified lines |
| 669 | 800 | case TOK_ASM_strbeq: |
| 670 | 801 | return asm_single_data_transfer_opcode(s1, token); |
| 671 | 802 | |
| 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 | + |
| 672 | 837 | case TOK_ASM_muleq: |
| 673 | 838 | case TOK_ASM_mulseq: |
| 674 | 839 | case TOK_ASM_mlaeq: |