From patchwork Mon May 25 13:30:52 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Silva X-Patchwork-Id: 135610 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C96A14BAD14A for ; Mon, 25 May 2026 13:33:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C96A14BAD14A Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256 header.s=pfptdkimsnps header.b=OYrgYQ+B; dkim=pass (2048-bit key, unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256 header.s=mail header.b=M+PoZ8YQ X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mx0a-00230701.pphosted.com (mx0a-00230701.pphosted.com [148.163.156.19]) by sourceware.org (Postfix) with ESMTPS id 8445A4BA9006 for ; Mon, 25 May 2026 13:31:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8445A4BA9006 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=synopsys.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=synopsys.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 8445A4BA9006 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=148.163.156.19 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1779715879; cv=none; b=TsTe71+ss0uL4mOfSCGmHGEYhCjBDa6nye9Pd+V6K9KU4qSyUi/bJCoZZC4ZjZ86OqR0khdOBOgNhXLxQnnAviOWiHlyHKNIYWnDQE7lWLK+te6ORB8XutH9hz/sImJOM+S4NG23eOwQWUTwWw67vWj95geALBZ86zpfAsj7Pwk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1779715879; c=relaxed/simple; bh=fzAOlcbNXDT1xlmczlppeUPEePicfgGXQIPD7slXlrs=; h=DKIM-Signature:DKIM-Signature:From:To:Subject:Date:Message-Id: MIME-Version; b=LRiZXZKEr4W2TvZyLXYjrRC71qnzebfHyc6kDBpXLAz72fSbyBb04gIF2K9eFCcrAztGQDuSgJgpvP1RQcsitR+I0u/7QiA/hOv9fDuwlNbnQ/QruB0Sxg7dGnZ+6pdeHyp202cJbU6fk7HBKvTqLh25p3Ohp1XS/gjiI3aTUyo= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256 header.s=pfptdkimsnps header.b=OYrgYQ+B; dkim=pass (2048-bit key, unprotected) header.d=synopsys.com header.i=@synopsys.com header.a=rsa-sha256 header.s=mail header.b=M+PoZ8YQ DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8445A4BA9006 Received: from pps.filterd (m0297266.ppops.net [127.0.0.1]) by mx0a-00230701.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 64P9uPJx3690348; Mon, 25 May 2026 06:31:11 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=synopsys.com; h= cc:content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pfptdkimsnps; bh=CRAy6X4X 85kO+m2jBbDP6/EC79W0wt9wQfaU8DS7mnA=; b=OYrgYQ+BK8FY9OD0AxuJAHyb B16kgHaMzrchqXqDmUMyTxrmVW086m3Qwmx5OJyGkPFT7EnTgGV+95ZvhftMwAeh JpVYUAK2vaGcJgDwawhSKM8TEaC4cp7zBDFCozWIhT2ed+DSx3kB45ZyTEcOX1U1 lr/gdQ3LoeKBPDfKtw8tagJ3bZHHC9IQpW7SPD5O54JvXx7LXXIzzq+sWpp5T6Vv /fYwSRPcGbXw2otviEnJhIOBVFZpwF7hHNEG/i1K5s8bsCbEOOHdzQMEfSR9sYCl Ay/GBywZYZtA+D6YpsxWtgdCUn20878YpmHVvduct9eG5+WPjIQn/cCpAHtEmw== Received: from smtprelay-out1.synopsys.com (smtprelay-out1.synopsys.com [149.117.87.133]) by mx0a-00230701.pphosted.com (PPS) with ESMTPS id 4ebbg5aw71-1 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Mon, 25 May 2026 06:31:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=synopsys.com; s=mail; t=1779715870; bh=fzAOlcbNXDT1xlmczlppeUPEePicfgGXQIPD7slXlrs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=M+PoZ8YQi3qsybpw8UC6dvBrqXICw545c7R6BfwtL8JF75d5/8Yth2edQXuCeYf54 FYXysCK/BnMT36xoJRhO9OGcCfNKs56etFHPuP7PqyHK+2cTBTaiACB3eDa59Kh6uR eydP6ApARRcV2O2Lzy3gEysKajo6H22UchpNqgkA9aIKhnJEXMWtKf0/UX2kU/xAMc tcJNUiw00nfdwXeVmlbd4i1cCNH3zlwxtDnmWdbLQnyDkhuIyJqCg2uWzj/AMOjvj1 BhAZyfQ3ch422lsew3Aj3CzH6YApn4MUzo9mvNiXeScaJocUnQwFeVHvG8aZfct+2/ NMxiMd44iNK8A== Received: from mailhost.synopsys.com (badc-mailhost1.synopsys.com [10.192.0.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) client-signature RSA-PSS (2048 bits)) (Client CN "mailhost.synopsys.com", Issuer "SNPSica2" (verified OK)) by smtprelay-out1.synopsys.com (Postfix) with ESMTPS id 7DA7740544; Mon, 25 May 2026 13:31:10 +0000 (UTC) Received: from us01arcgnu3.internal.synopsys.com (unknown [10.194.34.166]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (Client did not present a certificate) by mailhost.synopsys.com (Postfix) with ESMTPSA id 28CA1A00CB; Mon, 25 May 2026 13:31:10 +0000 (UTC) X-SNPS-Relay: synopsys.com From: Luis Silva To: binutils@sourceware.org Cc: Palmer Dabbelt , Andrew Waterman , Jim Wilson , Nelson Chu , Kito Cheng , Jeff Law , Alex Turjan , Luis Silva , Luis Silva Subject: [PATCH 2/2] RISC-V: Add ARC-V APEX disassembler support Date: Mon, 25 May 2026 06:30:52 -0700 Message-Id: <20260525133052.1885254-3-luiss@synopsys.com> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20260525133052.1885254-1-luiss@synopsys.com> References: <20260525133052.1885254-1-luiss@synopsys.com> MIME-Version: 1.0 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTI1MDEzOCBTYWx0ZWRfX9Z8UTrFjjOs9 QmArgCeMp5Ul7E7GehIFDhi4VHcX0SKdhABMwgRlf+KG27u+5TPYl/ewlddlJFT26vMTvuXXZfp XF1T85O3zOarZplGzT0uN/iII0/k9PfUoS/eVY3Z6VPaHPY2HYgMINHjiWrJ8yuCvIlEARhy1Hh XBxvD+14pjnDwnHxgVGPHt4V7CauQY+tIpj3oI8/RDAHNz5wcP0pB8OmLTMlZL4Sc/vvvI5+8gO /ZDDHT3B+Zl6VDTJoX9+PNXaf9fwvL3k0/gHrSvpZaYftmOcWg27LDL3ByH+D/jHBTjCHNtujxA 3hhm9EMt91HSXdfD+xJlw2Gc3U5MiMT/OwJMUjL8F+OZJ8F+KKn8cAJK5EMZ5OA7YPxYSJC5Pdk y8Xk4jSlTHiEbqH7yIuu1XyGj3ZEGmxZWOSQd4FBf7R5iRBuqbjpPzb/TKSzTJBWRBYYfQxuGBs R8DWymk3WYmG+tYw6IQ== X-Proofpoint-GUID: -7EkU4J_1dESczbtD7k1Tq5vmWu9BlKx X-Authority-Analysis: v=2.4 cv=cKTQdFeN c=1 sm=1 tr=0 ts=6a144f1e cx=c_pps a=t4gDRyhI9k+KZ5gXRQysFQ==:117 a=t4gDRyhI9k+KZ5gXRQysFQ==:17 a=NGcC8JguVDcA:10 a=qPHU084jO2kA:10 a=VkNPw1HP01LnGYTKEx00:22 a=tU_645BZ7FZt8VqRJtHG:22 a=Wo6YDfOMAEstGd-0DxeT:22 a=jIQo8A4GAAAA:8 a=dKcoV_r8wEp98cCQz_EA:9 X-Proofpoint-ORIG-GUID: -7EkU4J_1dESczbtD7k1Tq5vmWu9BlKx X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-05-25_04,2026-05-18_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_active_cloned_notspam policy=outbound_active_cloned score=0 spamscore=0 lowpriorityscore=0 impostorscore=0 clxscore=1011 priorityscore=1501 malwarescore=0 phishscore=0 suspectscore=0 bulkscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605130000 definitions=main-2605250138 X-Spam-Status: No, score=-11.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_BLOCKED, SPF_HELO_NONE, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces~patchwork=sourceware.org@sourceware.org Add disassembler support for ARC-V APEX instructions by reading metadata from .riscvapex.* ELF sections (emitted by GAS) and reconstructing instruction definitions at startup. Each metadata record is deserialized into a dynamically allocated riscv_opcode entry and placed in the arcv_apex_insns[] lookup table, indexed by format offset plus sub-opcode. When the standard opcode table produces no match, the disassembler determines the instruction format from bits [14:12], extracts the sub-opcode, and looks up the corresponding entry. gas/ChangeLog: * testsuite/gas/riscv/x-arcv-apex-01.d: Add disassembly expected output. * testsuite/gas/riscv/x-arcv-apex-02.d: Likewise. * testsuite/gas/riscv/x-arcv-apex-04.d: Likewise. include/ChangeLog: * opcode/riscv.h (EXTRACT_ARCV_APEX_XS_IMM): New macro. (EXTRACT_ARCV_APEX_XI_XC_IMM): Likewise. ld/ChangeLog: * testsuite/ld-riscv-elf/x-arcv-apex-02.d: New test. opcodes/ChangeLog: * riscv-dis.c (arcv_apex_free_instructions): New function. (print_insn_args): Add 'Xa' vendor operand handling. (arcv_apex_xd_type_p): New function. (arcv_apex_xs_type_p): Likewise. (arcv_apex_xi_type_p): Likewise. (arcv_apex_xc_type_p): Likewise. (arcv_apex_decode_insn): New function. (riscv_disassemble_insn): Try APEX decode after static table. (arcv_apex_read_metadata): New function. (riscv_init_disasm_info): Read APEX metadata from ELF sections. Co-Authored-By: Alex Turjan Signed-off-by: Luis Silva --- gas/testsuite/gas/riscv/x-arcv-apex-01.d | 18 +- gas/testsuite/gas/riscv/x-arcv-apex-02.d | 8 +- gas/testsuite/gas/riscv/x-arcv-apex-04.d | 12 +- include/opcode/riscv.h | 6 + ld/testsuite/ld-riscv-elf/x-arcv-apex-02.d | 36 +-- opcodes/riscv-dis.c | 269 +++++++++++++++++++++ 6 files changed, 312 insertions(+), 37 deletions(-) diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-01.d b/gas/testsuite/gas/riscv/x-arcv-apex-01.d index e3faa8bd632..621241d8674 100644 --- a/gas/testsuite/gas/riscv/x-arcv-apex-01.d +++ b/gas/testsuite/gas/riscv/x-arcv-apex-01.d @@ -7,12 +7,12 @@ Disassembly of section .text: 0+[0-9a-f]+ <.text>: -[ ]+[0-9a-f]+:[ ]+00c5c50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+02c5800b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0205c00b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0400000b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0b15b50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0b15d00b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0163a50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0164200b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0214e50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+00c5c50b[ ]+foo0[ ]+a0,a1,a2 +[ ]+[0-9a-f]+:[ ]+02c5800b[ ]+foo1[ ]+a1,a2 +[ ]+[0-9a-f]+:[ ]+0205c00b[ ]+foo2[ ]+a1 +[ ]+[0-9a-f]+:[ ]+0400000b[ ]+foo3 +[ ]+[0-9a-f]+:[ ]+0b15b50b[ ]+foo4[ ]+a0,a1,(0xb|11) +[ ]+[0-9a-f]+:[ ]+0b15d00b[ ]+foo5[ ]+a1,(0xb|11) +[ ]+[0-9a-f]+:[ ]+0163a50b[ ]+foo6[ ]+a0,(0x16|22) +[ ]+[0-9a-f]+:[ ]+0164200b[ ]+foo7[ ]+(0x16|22) +[ ]+[0-9a-f]+:[ ]+0214e50b[ ]+foo8[ ]+a0,a0,(0x21|33) diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-02.d b/gas/testsuite/gas/riscv/x-arcv-apex-02.d index 6bb08202e2a..d5fa36ff77f 100644 --- a/gas/testsuite/gas/riscv/x-arcv-apex-02.d +++ b/gas/testsuite/gas/riscv/x-arcv-apex-02.d @@ -7,7 +7,7 @@ Disassembly of section .text: 0+[0-9a-f]+ <.text>: -[ ]+[0-9a-f]+:[ ]+0020e50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0205b50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+1000e50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0ff0e50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+0020e50b[ ]+foo[ ]+a0,a0,(0x2|2) +[ ]+[0-9a-f]+:[ ]+0205b50b[ ]+foo[ ]+a0,a1,(0x2|2) +[ ]+[0-9a-f]+:[ ]+1000e50b[ ]+foo[ ]+a0,a0,(0x100|256) +[ ]+[0-9a-f]+:[ ]+0ff0e50b[ ]+foo[ ]+a0,a0,(0xff|255) diff --git a/gas/testsuite/gas/riscv/x-arcv-apex-04.d b/gas/testsuite/gas/riscv/x-arcv-apex-04.d index f62d160a30b..a9461929b37 100644 --- a/gas/testsuite/gas/riscv/x-arcv-apex-04.d +++ b/gas/testsuite/gas/riscv/x-arcv-apex-04.d @@ -7,9 +7,9 @@ Disassembly of section .text: 0+[0-9a-f]+ <.text>: -[ ]+[0-9a-f]+:[ ]+8005b50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+7f05b50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+8000a50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+7ff0a50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+8000e50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+7ff0e50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+8005b50b[ ]+foo0[ ]+a0,a1,(-0x80|-128) +[ ]+[0-9a-f]+:[ ]+7f05b50b[ ]+foo0[ ]+a0,a1,(0x7f|127) +[ ]+[0-9a-f]+:[ ]+8000a50b[ ]+foo1[ ]+a0,(-0x800|-2048) +[ ]+[0-9a-f]+:[ ]+7ff0a50b[ ]+foo1[ ]+a0,(0x7ff|2047) +[ ]+[0-9a-f]+:[ ]+8000e50b[ ]+foo2[ ]+a0,a0,(-0x800|-2048) +[ ]+[0-9a-f]+:[ ]+7ff0e50b[ ]+foo2[ ]+a0,a0,(0x7ff|2047) diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h index fdb23c0958d..80cd0622683 100644 --- a/include/opcode/riscv.h +++ b/include/opcode/riscv.h @@ -794,6 +794,12 @@ struct apex_insn /* Metadata record type for APEX instructions. */ #define ARCV_APEX_METADATA_TYPE 1 +#define EXTRACT_ARCV_APEX_XS_IMM(x) \ + (RV_X(x, 24, 8) | (RV_IMM_SIGN(x) << 8)) + +#define EXTRACT_ARCV_APEX_XI_XC_IMM(x) \ + (RV_X(x, 20, 12) | (RV_IMM_SIGN(x) << 12)) + #define ENCODE_ARCV_APEX_8BIT_IMM(x) \ (RV_X(x, 0, 8) << 24) diff --git a/ld/testsuite/ld-riscv-elf/x-arcv-apex-02.d b/ld/testsuite/ld-riscv-elf/x-arcv-apex-02.d index abebb3566e6..317417795de 100644 --- a/ld/testsuite/ld-riscv-elf/x-arcv-apex-02.d +++ b/ld/testsuite/ld-riscv-elf/x-arcv-apex-02.d @@ -13,24 +13,24 @@ Disassembly of section .text: #... 0+[0-9a-f]+ : -[ ]+[0-9a-f]+:[ ]+00c5c50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+02c5800b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0205c00b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0400000b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0b15b50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0b15d00b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0163a50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0164200b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0214e50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+00c5c50b[ ]+foo0[ ]+a0,a1,a2 +[ ]+[0-9a-f]+:[ ]+02c5800b[ ]+foo1[ ]+a1,a2 +[ ]+[0-9a-f]+:[ ]+0205c00b[ ]+foo2[ ]+a1 +[ ]+[0-9a-f]+:[ ]+0400000b[ ]+foo3 +[ ]+[0-9a-f]+:[ ]+0b15b50b[ ]+foo4[ ]+a0,a1,(0xb|11) +[ ]+[0-9a-f]+:[ ]+0b15d00b[ ]+foo5[ ]+a1,(0xb|11) +[ ]+[0-9a-f]+:[ ]+0163a50b[ ]+foo6[ ]+a0,(0x16|22) +[ ]+[0-9a-f]+:[ ]+0164200b[ ]+foo7[ ]+(0x16|22) +[ ]+[0-9a-f]+:[ ]+0214e50b[ ]+foo8[ ]+a0,a0,(0x21|33) 0+[0-9a-f]+ : -[ ]+[0-9a-f]+:[ ]+00c5c50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+02c5800b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0205c00b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0400000b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0b15b50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0b15d00b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0163a50b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0164200b[ ]+.* -[ ]+[0-9a-f]+:[ ]+0214e50b[ ]+.* +[ ]+[0-9a-f]+:[ ]+00c5c50b[ ]+foo0[ ]+a0,a1,a2 +[ ]+[0-9a-f]+:[ ]+02c5800b[ ]+foo1[ ]+a1,a2 +[ ]+[0-9a-f]+:[ ]+0205c00b[ ]+foo2[ ]+a1 +[ ]+[0-9a-f]+:[ ]+0400000b[ ]+foo3 +[ ]+[0-9a-f]+:[ ]+0b15b50b[ ]+foo4[ ]+a0,a1,(0xb|11) +[ ]+[0-9a-f]+:[ ]+0b15d00b[ ]+foo5[ ]+a1,(0xb|11) +[ ]+[0-9a-f]+:[ ]+0163a50b[ ]+foo6[ ]+a0,(0x16|22) +[ ]+[0-9a-f]+:[ ]+0164200b[ ]+foo7[ ]+(0x16|22) +[ ]+[0-9a-f]+:[ ]+0214e50b[ ]+foo8[ ]+a0,a0,(0x21|33) #pass diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c index eda802ff420..46668046e8d 100644 --- a/opcodes/riscv-dis.c +++ b/opcodes/riscv-dis.c @@ -74,6 +74,28 @@ struct riscv_private_data bool all_ext; }; +/* Global instruction table for dynamically-defined APEX extensions. + Indexed by format offset (XD, XS, XI, XC) plus sub-opcode. */ +static struct riscv_opcode *arcv_apex_insns[ARCV_APEX_INSN_LIMIT]; + +/* Free all dynamically allocated APEX instructions. */ + +static void +arcv_apex_free_instructions (void) +{ + unsigned int i; + + for (i = 0; i < ARCV_APEX_INSN_LIMIT; i++) + { + if (arcv_apex_insns[i] != NULL) + { + free ((char *) arcv_apex_insns[i]->name); + free (arcv_apex_insns[i]); + arcv_apex_insns[i] = NULL; + } + } +} + /* Set default RISC-V disassembler options. */ static void @@ -917,6 +939,33 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info goto undefined_modifier; } break; + case 'a': /* Vendor-specific (ARC-V) operands. */ + switch (*++oparg) + { + case 'd': + print (info->stream, dis_style_register, "%s", + pd->riscv_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]); + break; + case 's': + print (info->stream, dis_style_register, "%s", + pd->riscv_gpr_names[(l >> OP_SH_RS1) & OP_MASK_RS1]); + break; + case 't': + print (info->stream, dis_style_register, "%s", + pd->riscv_gpr_names[(l >> OP_SH_RS2) & OP_MASK_RS2]); + break; + case 'k': + print (info->stream, dis_style_immediate, "%d", + (int)EXTRACT_ARCV_APEX_XS_IMM (l)); + break; + case 'j': + print (info->stream, dis_style_immediate, "%d", + (int)EXTRACT_ARCV_APEX_XI_XC_IMM (l)); + break; + default: + goto undefined_modifier; + } + break; default: goto undefined_modifier; } @@ -933,6 +982,77 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info } } +/* Check APEX format - bits [14:12] determine the format. */ + +static bool +arcv_apex_xd_type_p (insn_t word) +{ + return ((word >> 12) & 0x3) == 0x0; +} + +static bool +arcv_apex_xs_type_p (insn_t word) +{ + return ((word >> 12) & 0x1) == 0x1; +} + +static bool +arcv_apex_xi_type_p (insn_t word) +{ + return ((word >> 12) & 0x7) == 0x2; +} + +static bool +arcv_apex_xc_type_p (insn_t word) +{ + return ((word >> 12) & 0x7) == 0x6; +} + +/* Try to decode WORD as an APEX Custom-0 instruction. + Returns the matching opcode entry, or NULL on failure. */ + +static const struct riscv_opcode * +arcv_apex_decode_insn (insn_t word) +{ + if ((word & 0xF) != ARCV_APEX_CUSTOM0_OPCODE) + return NULL; + + unsigned int offset = 0, sub_opcode = 0; + + if (arcv_apex_xd_type_p (word)) + { + sub_opcode = (((word >> 25) & 0x7F) << 1) + | ((word >> 14) & 1); + offset = ARCV_APEX_OFFSET_XD; + } + else if (arcv_apex_xs_type_p (word)) + { + sub_opcode = (((word >> 20) & 0xF) << 2) + | ((word >> 13) & 0x3); + offset = ARCV_APEX_OFFSET_XS; + } + else if (arcv_apex_xi_type_p (word)) + { + sub_opcode = (word >> 15) & 0x1F; + offset = ARCV_APEX_OFFSET_XI; + } + else if (arcv_apex_xc_type_p (word)) + { + sub_opcode = (word >> 15) & 0x1F; + offset = ARCV_APEX_OFFSET_XC; + } + + if (sub_opcode + offset >= ARCV_APEX_INSN_LIMIT) + return NULL; + + const struct riscv_opcode *op + = arcv_apex_insns[sub_opcode + offset]; + if (op == NULL || !(op->match_func) (op, word)) + return NULL; + + return op; +} + /* Print the RISC-V instruction at address MEMADDR in debugged memory, on using INFO. Returns length of the instruction, in bytes. BIGENDIAN must be 1 if this is big-endian code, 0 if @@ -1068,6 +1188,17 @@ riscv_disassemble_insn (bfd_vma memaddr, } } + /* No match in the static table; try APEX metadata-driven Custom-0. */ + op = arcv_apex_decode_insn (word); + if (op != NULL) + { + (*info->fprintf_styled_func) (info->stream, + dis_style_mnemonic, + "%s", op->name); + print_insn_args (op->args, word, memaddr, info); + return insnlen; + } + /* We did not find a match, so just print the instruction bits in the shape of an assembler .insn directive. */ info->insn_type = dis_noninsn; @@ -1412,6 +1543,123 @@ riscv_disassemble_data (bfd_vma memaddr ATTRIBUTE_UNUSED, return info->bytes_per_chunk; } +/* Create a mapping between a serialized APEX instruction record + (emitted by GAS) and a dynamically allocated riscv_opcode entry. + + Record format (see struct apex_insn): + +------+------+--------+--------+-----------+---------+ + | Len | Type | Opcode | FuncT | Flags | Name... | + +------+------+--------+--------+-----------+---------+ + 1B 1B 1B 1B 2B NUL-term + + - 'block' points to the beginning of the serialized record. + - 'length' is the size of the block (must match record_len). + - The instruction name is stored at the end of the block and + is dynamically allocated here. */ + +static void +arcv_apex_read_metadata (unsigned char *block, + unsigned long length) +{ + /* Assert that the provided length matches the record length + declared at position 0 (as emitted by GAS). */ + unsigned int record_len = block[0]; + if (length != record_len) + { + opcodes_error_handler (_("APEX metadata: length mismatch " + "(section contents %lu bytes, " + "record header says %u)"), + (unsigned long) length, record_len); + return; + } + + /* Validate the metadata record type. */ + if (block[1] != ARCV_APEX_METADATA_TYPE) + { + opcodes_error_handler (_("APEX metadata: unknown " + "record type %u"), + (unsigned) block[1]); + return; + } + + /* Compute the length of the instruction name by + subtracting the base struct size. */ + size_t name_length = record_len + - offsetof (struct apex_insn, name); + + /* Allocate and null-terminate the instruction mnemonic. */ + char *name = xmalloc (name_length + 1); + memcpy (name, + block + offsetof (struct apex_insn, name), /* Mnemonic start. */ + name_length); + name[name_length] = '\0'; + + /* Extract sub-opcode and flags (flags is 16-bit, little-endian). */ + unsigned int sub_opcode = block[3]; + unsigned int flags = bfd_getl16 (block + 4); + + /* Allocate a new riscv_opcode entry. */ + struct riscv_opcode *insn = XNEW (struct riscv_opcode); + + arcv_apex_init_dynamic_insn (insn); + insn->name = name; + + unsigned int offset = 0; + /* Decode flags and adjust the opcode entry accordingly. */ + switch (flags & 0xF) + { + case APEX_FLAG_XD: + arcv_apex_setup_xd_insn (insn, flags, sub_opcode); + offset = ARCV_APEX_OFFSET_XD; + break; + + case APEX_FLAG_XS: + arcv_apex_setup_xs_insn (insn, flags, sub_opcode); + offset = ARCV_APEX_OFFSET_XS; + break; + + case APEX_FLAG_XI: + arcv_apex_setup_xi_insn (insn, flags, sub_opcode); + offset = ARCV_APEX_OFFSET_XI; + break; + + case APEX_FLAG_XC: + arcv_apex_setup_xc_insn (insn, sub_opcode); + offset = ARCV_APEX_OFFSET_XC; + break; + + /* If an instruction supports both XS and XC formats + (e.g., "extInstruction foo,123,XS,XC"), we create a separate + instruction for each format. This is safe because no other XS + or XC instruction can use the same sub-opcode (e.g., =123). */ + case (APEX_FLAG_XS | APEX_FLAG_XC): + { + arcv_apex_setup_xs_insn (insn, flags, sub_opcode); + arcv_apex_insns[sub_opcode + ARCV_APEX_OFFSET_XS] = insn; + + struct riscv_opcode *xc_copy = XNEW (struct riscv_opcode); + arcv_apex_init_dynamic_insn (xc_copy); + xc_copy->name = xstrdup (insn->name); + arcv_apex_setup_xc_insn (xc_copy, sub_opcode); + arcv_apex_insns[sub_opcode + ARCV_APEX_OFFSET_XC] = xc_copy; + return; + } + + default: + opcodes_error_handler (_("APEX metadata: unknown format flags 0x%x"), + flags & 0xF); + free (name); + free (insn); + return; + } + + /* Place the fully initialized APEX instruction in the + arcv_apex_insns array at an index determined by its sub-opcode + and the format-specific offset. This ensures each format + occupies a distinct array region. */ + arcv_apex_insns[sub_opcode + offset] = insn; +} + static bool riscv_init_disasm_info (struct disassemble_info *info) { @@ -1450,6 +1698,27 @@ riscv_init_disasm_info (struct disassemble_info *info) bfd *abfd = info->section->owner; if (abfd && bfd_get_flavour (abfd) == bfd_target_elf_flavour) { + arcv_apex_free_instructions (); + + asection *sect; + for (sect = abfd->sections; sect != NULL; sect = sect->next) + { + if (strstr (sect->name, ".riscvapex.")) + { + bfd_size_type count = bfd_section_size (sect); + unsigned char *buffer = xmalloc (count); + + if (bfd_get_section_contents (abfd, sect, buffer, 0, count)) + arcv_apex_read_metadata (buffer, count); + else + opcodes_error_handler + (_("warning: could not read APEX metadata " + "section `%s'"), + sect->name); + free (buffer); + } + } + const char *sec_name = get_elf_backend_data (abfd)->obj_attrs_section; if (bfd_get_section_by_name (abfd, sec_name) != NULL)