diff --git a/arm-asm.c b/arm-asm.c index 9c390d24..8cbcd512 100644 --- a/arm-asm.c +++ b/arm-asm.c @@ -77,6 +77,20 @@ static int asm_parse_vfp_regvar(int t, int double_precision) return -1; } +static int asm_parse_vfp_status_regvar(int t) +{ + switch (t) { + case TOK_ASM_fpsid: + return 0; + case TOK_ASM_fpscr: + return 1; + case TOK_ASM_fpexc: + return 8; + default: + return -1; + } +} + /* Parse a text containing operand and store the result in OP */ static void parse_operand(TCCState *s1, Operand *op) { @@ -1915,10 +1929,6 @@ static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { VMOV Rd, Dn[0] VMOV Dn[1], Rd VMOV Rd, Dn[1] - - VMSR , Rd - VMRS Rd, - VMRS APSR_nzcv, FPSCR */ switch (ARM_INSTRUCTION_GROUP(token)) { @@ -2110,6 +2120,68 @@ static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) { asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode1, ops[0].reg, (ops[1].type == OP_IM8) ? ops[1].e.v : ops[1].reg, (ops[2].type == OP_IM8) ? ops[2].e.v : ops[2].reg, opcode2, 0); } + +static void asm_floating_point_status_register_opcode(TCCState* s1, int token) +{ + uint8_t coprocessor = CP_SINGLE_PRECISION_FLOAT; + uint8_t opcode; + int vfp_sys_reg = -1; + Operand arm_operand; + switch (ARM_INSTRUCTION_GROUP(token)) { + case TOK_ASM_vmrseq: + opcode = 0xf; + if (tok == TOK_ASM_apsr_nzcv) { + arm_operand.type = OP_REG32; + arm_operand.reg = 15; // not PC + next(); // skip apsr_nzcv + } else { + parse_operand(s1, &arm_operand); + if (arm_operand.type == OP_REG32 && arm_operand.reg == 15) { + tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL)); + return; + } + } + + if (tok != ',') + expect("','"); + else + next(); // skip ',' + vfp_sys_reg = asm_parse_vfp_status_regvar(tok); + next(); // skip vfp sys reg + if (arm_operand.type == OP_REG32 && arm_operand.reg == 15 && vfp_sys_reg != 1) { + tcc_error("'%s' only supports the variant 'vmrs apsr_nzcv, fpscr' here", get_tok_str(token, NULL)); + return; + } + break; + case TOK_ASM_vmsreq: + opcode = 0xe; + vfp_sys_reg = asm_parse_vfp_status_regvar(tok); + next(); // skip vfp sys reg + if (tok != ',') + expect("','"); + else + next(); // skip ',' + parse_operand(s1, &arm_operand); + if (arm_operand.type == OP_REG32 && arm_operand.reg == 15) { + tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL)); + return; + } + break; + default: + expect("floating point status register instruction"); + return; + } + if (vfp_sys_reg == -1) { + expect("VFP system register"); + return; + } + if (arm_operand.type != OP_REG32) { + expect("ARM register"); + return; + } + asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode, arm_operand.reg, vfp_sys_reg, 0x10, 0, 0); +} + #endif static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token) @@ -2518,6 +2590,11 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) case TOK_ASM_vstmdbeq: asm_floating_point_block_data_transfer_opcode(s1, token); return; + + case TOK_ASM_vmsreq: + case TOK_ASM_vmrseq: + asm_floating_point_status_register_opcode(s1, token); + return; #endif default: diff --git a/arm-tok.h b/arm-tok.h index 79514b04..2ee79ca7 100644 --- a/arm-tok.h +++ b/arm-tok.h @@ -120,6 +120,16 @@ DEF_ASM(d14) DEF_ASM(d15) + /* VFP status registers */ + + DEF_ASM(fpsid) + DEF_ASM(fpscr) + DEF_ASM(fpexc) + + /* VFP magical ARM register */ + + DEF_ASM(apsr_nzcv) + /* data processing directives */ DEF_ASM(asl) @@ -333,3 +343,5 @@ DEF_ASM_CONDED(vstm) DEF_ASM_CONDED(vstmia) DEF_ASM_CONDED(vstmdb) + DEF_ASM_CONDED(vmsr) + DEF_ASM_CONDED(vmrs) diff --git a/tests/arm-asm-testsuite.sh b/tests/arm-asm-testsuite.sh index 19acf907..bfa1e108 100755 --- a/tests/arm-asm-testsuite.sh +++ b/tests/arm-asm-testsuite.sh @@ -14,7 +14,7 @@ cat ../arm-tok.h | \ sed -e 's;^[ ]*DEF_ASM_CONDED_VFP_F32_F64[^(]*(\(.*\)).*$; DEF_ASM_CONDED(\1.f32)\ DEF_ASM_CONDED(\1.f64);g' | \ sed -e 's;^[ ]*DEF_ASM[^(]*(\(.*\)).*$;\1;g' | \ - egrep -v '^((r|c|p|s|d)[0-9]+|fp|ip|sp|lr|pc|asl)$' | while read s + egrep -v '^((r|c|p|s|d)[0-9]+|fp|ip|sp|lr|pc|asl|apsr_nzcv|fpsid|fpscr|fpexc)$' | while read s do as_opts="" if [ "${s#v}" != "${s}" ] @@ -155,6 +155,13 @@ do "d1, r2, r3" \ "s1, r2" \ "r2, s1" \ + "r2, fpexc" \ + "r2, fpscr" \ + "r2, fpsid" \ + "apsr_nzcv, fpscr" \ + "fpexc, r2" \ + "fpscr, r2" \ + "fpsid, r2" \ "" do #echo ".syntax unified" > a.s