From d1a6c4aefa1b3558a48250c6ba6db17443b22674 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 13 Jan 2021 03:16:56 +0100 Subject: [PATCH] arm-asm: Add mcr, mrc --- arm-asm.c | 50 ++++++++++++++++++++++++++++++++------ arm-tok.h | 2 ++ tests/arm-asm-testsuite.sh | 4 +++ 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/arm-asm.c b/arm-asm.c index b26000d0..dd802a94 100644 --- a/arm-asm.c +++ b/arm-asm.c @@ -336,6 +336,7 @@ static void asm_coprocessor_opcode(TCCState *s1, int token) { uint8_t registers[3]; unsigned int i; uint8_t high_nibble; + uint8_t mrc = 0; if (tok >= TOK_ASM_p0 && tok <= TOK_ASM_p15) { coprocessor = tok - TOK_ASM_p0; @@ -361,12 +362,22 @@ static void asm_coprocessor_opcode(TCCState *s1, int token) { next(); else expect("','"); - if (tok >= TOK_ASM_c0 && tok <= TOK_ASM_c15) { - registers[i] = tok - TOK_ASM_c0; - next(); + if (i == 0 && token != TOK_ASM_cdp2 && (ARM_INSTRUCTION_GROUP(token) == TOK_ASM_mrceq || ARM_INSTRUCTION_GROUP(token) == TOK_ASM_mcreq)) { + if (tok >= TOK_ASM_r0 && tok <= TOK_ASM_r15) { + registers[i] = tok - TOK_ASM_r0; + next(); + } else { + expect("'r'"); + return; + } } else { - expect("'c"); - return; + if (tok >= TOK_ASM_c0 && tok <= TOK_ASM_c15) { + registers[i] = tok - TOK_ASM_c0; + next(); + } else { + expect("'c'"); + return; + } } } if (tok == ',') { @@ -381,11 +392,32 @@ static void asm_coprocessor_opcode(TCCState *s1, int token) { return; } - if (token == TOK_ASM_cdp2) + if (token == TOK_ASM_cdp2) { high_nibble = 0xF; - else + asm_emit_coprocessor_opcode(high_nibble, coprocessor, opcode1.e.v, registers[0], registers[1], registers[2], opcode2.e.v, 0); + return; + } else high_nibble = condition_code_of_token(token); - asm_emit_coprocessor_opcode(high_nibble, coprocessor, opcode1.e.v, registers[0], registers[1], registers[2], opcode2.e.v, 0); + + switch (ARM_INSTRUCTION_GROUP(token)) { + case TOK_ASM_cdpeq: + asm_emit_coprocessor_opcode(high_nibble, coprocessor, opcode1.e.v, registers[0], registers[1], registers[2], opcode2.e.v, 0); + break; + case TOK_ASM_mrceq: + // opcode1 encoding changes! highest and lowest bit gone. + mrc = 1; + /* fallthrough */ + case TOK_ASM_mcreq: + // opcode1 encoding changes! highest and lowest bit gone. + if (opcode1.e.v > 7) { + tcc_error("opcode1 of instruction '%s' must be an immediate value between 0 and 7", get_tok_str(token, NULL)); + return; + } + asm_emit_coprocessor_opcode(high_nibble, coprocessor, (opcode1.e.v << 1) | mrc, registers[0], registers[1], registers[2], opcode2.e.v, 1); + break; + default: + expect("known instruction"); + } } /* data processing and single data transfer instructions only */ @@ -1554,6 +1586,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) return asm_long_multiplication_opcode(s1, token); case TOK_ASM_cdpeq: + case TOK_ASM_mcreq: + case TOK_ASM_mrceq: return asm_coprocessor_opcode(s1, token); default: expect("known instruction"); diff --git a/arm-tok.h b/arm-tok.h index 269c4a7d..7f15b736 100644 --- a/arm-tok.h +++ b/arm-tok.h @@ -214,3 +214,5 @@ DEF_ASM_CONDED(rrxs) DEF_ASM_CONDED(cdp) + DEF_ASM_CONDED(mcr) + DEF_ASM_CONDED(mrc) diff --git a/tests/arm-asm-testsuite.sh b/tests/arm-asm-testsuite.sh index 6628ec6f..902be620 100755 --- a/tests/arm-asm-testsuite.sh +++ b/tests/arm-asm-testsuite.sh @@ -82,6 +82,10 @@ do "r2, [r3, #-0x45]" \ "r2, r3, #4" \ "r2, r3, #-4" \ + "p10, #7, c2, c0, c1, #4" \ + "p10, #7, r2, c0, c1, #4" \ + "p10, #0, c2, c0, c1, #4" \ + "p10, #0, r2, c0, c1, #4" \ "r2, #4" \ "r2, #-4" \ "r2, #0xEFFF" \