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