From patchwork Mon Nov 21 11:06:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aleksandar Rikalo X-Patchwork-Id: 60920 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8A7F5384F4BF for ; Mon, 21 Nov 2022 11:06:40 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from EUR05-DB8-obe.outbound.protection.outlook.com (mail-db8eur05on2101.outbound.protection.outlook.com [40.107.20.101]) by sourceware.org (Postfix) with ESMTPS id BAABC3857BB2 for ; Mon, 21 Nov 2022 11:06:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org BAABC3857BB2 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=syrmia.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=syrmia.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=RX7TeQ7T63crPTk63ZfftYosIbTEhD3xTgy9E7ddxQ988DUordsMHXczCmC+vKu3O9Y48WTOXL8JG16ZouMHw7sRFgvpu+vNMjpZ6Yz4ScUUfwu7cJI+KMWEYgs9GhyGMsdL3jRqsDfPhiZ4uDmKQr2DYIr1ylAHwwOz8bKyY0mS2erqts89AdgiS+R1QqsjLH+UabllYzH2X6ElE2gqRp2CIdnH2/MMbwtnFkFQ9qaJirGPvAPxbrlLGSuI4w3e7wSSBIS+Ol/K2/6cjq+3youd1KNRsyxBwDoNTxJDvVeb1tqbc4NaC/qy1cuogqe976ih7AH7Edg0186ltSpxvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=RtADv3mEquDCgrt7Yr1vRHcxXJidrYclfLsmBQq3vzE=; b=TF9qtIIZhc6MVRAjCLzEEbnpCPYGtbSglE6Ylkm5JX7ud42PuZG3WU46hcqY7+VquWogO2Fb3zQCpkKXBiCqjRZlyyu09ZEm1+cHX/oBJ63ctLcsI7S0Qm/wdBEgeC0dVvyul3nJQ31rVC8F9HPji+6cygxtZ3G0HkmguR+JDsk8RfWtfwYyQXkUojqDrnasMyixSRGL8Mz22LquJcnOB4fEJTIZllc4lBbf6kXs5EVnYk30V/FHkwxOWNFEOEUXa/bna1A9dBA7A43mlaGjBodTZAB9NNtr2WUanbQgYuV+UxXq8NIgsxcVwVaExVHnD9u0Y4TZQJivQ2tfF0E00w== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=syrmia.com; dmarc=pass action=none header.from=syrmia.com; dkim=pass header.d=syrmia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=syrmia.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=RtADv3mEquDCgrt7Yr1vRHcxXJidrYclfLsmBQq3vzE=; b=Uv2TAa9rFcw+QIXts0zXva83jFyn+ALaCHKYk+vmUV/46mY0ulFhJNRF6V7sG/BF+dccC4RlK2++SVklVq/4ABBeOgh1mEHO+hEaz5ks5QMBk1RwLsJArLKsOieTPlboidlhuUq9EpdIfH63DQi1HXgDdKgXXrMNCMA45P/RoeQ= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=syrmia.com; Received: from VI1PR0302MB3486.eurprd03.prod.outlook.com (2603:10a6:803:1e::32) by PAXPR03MB7806.eurprd03.prod.outlook.com (2603:10a6:102:201::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5834.15; Mon, 21 Nov 2022 11:06:10 +0000 Received: from VI1PR0302MB3486.eurprd03.prod.outlook.com ([fe80::19fa:5ce5:280a:b98e]) by VI1PR0302MB3486.eurprd03.prod.outlook.com ([fe80::19fa:5ce5:280a:b98e%3]) with mapi id 15.20.5834.015; Mon, 21 Nov 2022 11:06:09 +0000 From: Aleksandar Rikalo To: gdb-patches@sourceware.org Cc: aleksandar.rikalo@syrmia.com, arikalo@gmail.com Subject: [PATCH v3 1/2] sim: Add nanoMIPS port Date: Mon, 21 Nov 2022 12:06:02 +0100 Message-Id: <20221121110603.124056-1-aleksandar.rikalo@syrmia.com> X-Mailer: git-send-email 2.25.1 X-ClientProxiedBy: VE1PR03CA0031.eurprd03.prod.outlook.com (2603:10a6:803:118::20) To VI1PR0302MB3486.eurprd03.prod.outlook.com (2603:10a6:803:1e::32) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI1PR0302MB3486:EE_|PAXPR03MB7806:EE_ X-MS-Office365-Filtering-Correlation-Id: 51906fde-1f60-428d-1daf-08dacbb064fd X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: jBaq8myKwGlcmR8r4BaYsUPRMWF/iK5dSujzBajPZvd/n8MX6KHIkjG/2151/1guentMiJZQsqvE6HJnv595IhKPp9x4O6Ms3HBmZDNIA5NKh5ygiu6WwIUA+RhnP0HAX4f5iHMns5+OMjwpo7ry5pqCSWIqdfPKzl5WX161K5l/AZ0eG8Ttbc2WaCahSlTPIWVGCasD9Ud6PlXnz8zrnpeIJOOgQKUFACpHBpiIJiKsMKnHtZ3rA8rvPfby1Ni1JEVYPpmK7azAQtg13hhPu1Z0UIuj6MGd7nCH1Sk2gTugVNlNAk1hjRbm8lConev+iJ5IeSHVyhk52BkDpty5pMyWI5MU1V2LWBz8phh2/3giJpYlO6QsjfF1qBAyiCsszKty2q04/u0w/49esPYwSv3VZdbPVVYHVNDAtjp0cYHeyUkYpdecYH8F4Bj3u31kcFDsdJUG/dWwfkCXshYl3JjlIIA5TBgfCsQVjl8gG8uCXGSYZQ+nm0OCLEEi9Zqwc+Pwk6QKr23pggUB8oCf9mcbi7ODvUbGf1pjgrvByApJpbwlIwXkAx6T0HoiN+GyqYBMva5ts6oEjDp8GKR1KxPffKH4NPYE14wPgPF8Hzsz1p8y81P6lT8j4fsWcqvw+UxnwGER1yvPKfOaT1gZ+cG5Wkpv3rau5yay4JD7RDjA67WMNbyfd9fqZ2ixLyJmyN1Ivzt/1MZuZzQf1hq7hkjgeHOAl1Aa5j3hLy0i9d+hpTFHHvCUIoNVCRgW+LOi1jpNdWysgsynztpUjbdRCg== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:VI1PR0302MB3486.eurprd03.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230022)(136003)(376002)(346002)(396003)(366004)(39830400003)(451199015)(36756003)(86362001)(26005)(38350700002)(38100700002)(2616005)(1076003)(186003)(6512007)(44832011)(83380400001)(6916009)(30864003)(2906002)(5660300002)(8936002)(6666004)(52116002)(6506007)(478600001)(6486002)(19627235002)(41300700001)(66476007)(316002)(66556008)(4326008)(8676002)(66946007)(21314003)(2004002)(559001)(579004); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: KcAolZziuOf2P5i+hvOPEEaCg0B4UZ8Fh/yTU3pFycCsPIvrr9VoIQunTXEm5iwi6o/nA7nM4xN/AlDzEkxPXgWmJZvA/NY2XI2m90zPa62gHVytTa6FocFUeSrPREf5pNY5PGAYacrzIhP2w+448x4QexO/KK6k+0FUFqKDj6fp/1v/MZO3zTwRzdMGj2p2cOd8/a7ULiPXhYZ6XIef+D8ObKK25nPqf3dR9Up1+7MNIxEUAfHMadGcgb6Vx9i+KnjGAj1uuhkUOWKAe2RN9QSLyXZMx6H/sw0XT+fND9MDTgVg0Q+oQNTr2D4QGvX7RDUGNTSw6wQgRLJaBA9umOHmGVdslWefaKrLDga2Zel7SmQS2eAn/f6g6K2VZUJNNpFTAj2qOfTojYPmZOjDa5pza5jbh7j3Z9Bt8GKTHHQY1IzkbE6LdkugPC1W2kobGTSMlWnY7rkya9WVgasnv1tHzLNOr6aGaqr3FFWF/uuzwdKGtPohWygdaZ8d+oxvhvdOeABBgdpLW4hlX2KdBs0v5w/lJVMdIyfbAXezfxGPLkgXS5ZN9R5c/fj4QFBeAUS3X6mBFtWD8atpNnDD/r02CQAObV4OQK7HX5JwY/lbC82H65m9CJ4PfhJwPWlpo734g/B9X363JPl/w9crcEyj1TroC3bMNrOLxE1kecn7e8/fr5EgCIHKZvgGUi2FZ0mkW9YahkJPGgtV8yCAAbo5Dnf07vFG1AjjBMrm0ic/bCMjv9NpTkZcOUiNdErgQhe6Sm1wmdv5yQf/QKUliJQ3CmQlPWPY8aydl+a/DpBaFXvvTqhs+T1ygv/M8Hxygj5caArUrZufkjVM68f4rJ9YQYJi02O7/Ey0mFuoOi9e1IiE/hA4kR35Cjq/bGMzBoFsCr3Juo42VjKvqwTddDlq1urtG69byqpKSlVSFvU7m7K4PHb/pvKxM/q35B9rrcwB1Ld3+r0MQ7P3qsRRymP8AdXg/ZNW4uyXfNlvMYAWtXS7h0quNCh5/36FdWw5cmWXGdt68aQcOUX2AtvnIXLOhFV2l7PbqlLmVUZan808V6aaWKkZWNKaXBFO0icIOg0TIZnFAe7ihVVp1EIoZYHELXjtWGR9n37E6L36cfY75FQUByhP1BR9FcoqMjeJ5N4RPEkFAtQqC8PFE92i1z0eEJda87P9+upiu8s18GPHucaOtPjqjwUWRJx9EyXWTz21oyOCbaDse9ug3q9lSfbZmSW+cAcqhylXIuOQZC21tfyEBCdqD37kAzpDDR5F21WxLUEpfxYNMl0GWaymvvqsetpls3z9i8GtkzhNG7Kk1AwyA2T+sdeHGKsLQuoGVTx29kCDxHyWCCHx20tN8rlnePL+Hr+9CGYrsOJ3TeerrEMrKggVk5yy6Hhh6ufNYYdaWdQUYQVOe19IIE0VJHLUfLKCrc1LMmmvXj8IN82iZ8+WvowIosqlUjC3ddmPeINnTsXa8+moQ6GDRuvTAFDnnvMMWMLgYalcwfG1z7Dwu1G3H/pg/AY7EwSJHRnHtP5mIP0E5k+3AJc2F+9TzxHQfBMwNE/X3kv8RHJMdgqyjdv2VPuEl91kR9l+52+he3pTerROVjP35qwtrq67Sw== X-OriginatorOrg: syrmia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 51906fde-1f60-428d-1daf-08dacbb064fd X-MS-Exchange-CrossTenant-AuthSource: VI1PR0302MB3486.eurprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Nov 2022 11:06:09.8619 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 19214a73-c1ab-4e19-8f59-14bdcb09a66e X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 0ALsko/nmKlXqC5SIf7h+WE5fFEy2f5Q6E+UjgJ44tGAwnPXP4BSHV2+9BauGULzHSCQkkgvI6jSCQ3ISCs/I3c+qsOaDi9yuueHEbx1V+g= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR03MB7806 X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" Co-Authored-By: Jaydeep Patil Co-Authored-By: Matthew Fortune Co-Authored-By: Maciej W. Rozycki Co-Authored-By: Stefan Markovic Co-Authored-By: Sara Graovac Co-Authored-By: Dragan Mladjenovic --- sim/common/sim-bits.h | 4 + sim/configure | 2 +- sim/configure.ac | 2 +- sim/mips/Makefile.in | 28 + sim/mips/configure | 28 + sim/mips/configure.ac | 28 + sim/mips/interp.c | 21 +- sim/mips/micromips16.dc | 3 + sim/mips/mips.igen | 193 ++- sim/mips/nanomipsdsp.igen | 1115 +++++++++++++++ sim/mips/nanomipsr6.igen | 2744 +++++++++++++++++++++++++++++++++++++ sim/mips/nanomipsrun.c | 109 ++ sim/mips/nms.c | 44 + sim/mips/sim-main.h | 61 +- 14 files changed, 4358 insertions(+), 24 deletions(-) create mode 100644 sim/mips/nanomipsdsp.igen create mode 100644 sim/mips/nanomipsr6.igen create mode 100644 sim/mips/nanomipsrun.c create mode 100644 sim/mips/nms.c diff --git a/sim/common/sim-bits.h b/sim/common/sim-bits.h index fab1dab478c..8799916de26 100644 --- a/sim/common/sim-bits.h +++ b/sim/common/sim-bits.h @@ -499,15 +499,19 @@ INLINE_SIM_BITS(unsigned_word) MSINSERTED (unsigned_word val, int start, int sto #define EXTEND4(X) (LSSEXT ((X), 3)) #define EXTEND5(X) (LSSEXT ((X), 4)) #define EXTEND6(X) (LSSEXT ((X), 5)) +#define EXTEND7(X) (LSSEXT ((X), 6)) #define EXTEND8(X) ((signed_word)(int8_t)(X)) #define EXTEND9(X) (LSSEXT ((X), 8)) +#define EXTEND10(X) (LSSEXT ((X), 9)) #define EXTEND11(X) (LSSEXT ((X), 10)) #define EXTEND12(X) (LSSEXT ((X), 11)) +#define EXTEND14(X) (LSSEXT ((X), 13)) #define EXTEND15(X) (LSSEXT ((X), 14)) #define EXTEND16(X) ((signed_word)(int16_t)(X)) #define EXTEND18(X) (LSSEXT ((X), 17)) #define EXTEND19(X) (LSSEXT ((X), 18)) #define EXTEND21(X) (LSSEXT ((X), 20)) +#define EXTEND22(X) (LSSEXT ((X), 21)) #define EXTEND24(X) (LSSEXT ((X), 23)) #define EXTEND25(X) (LSSEXT ((X), 24)) #define EXTEND26(X) (LSSEXT ((X), 25)) diff --git a/sim/configure b/sim/configure index 57c4fcf6972..aa9e21a2923 100755 --- a/sim/configure +++ b/sim/configure @@ -15157,7 +15157,7 @@ fi sim_enable_arch_mips=false case "${targ}" in - all|mips*-*-*) + all|mips*-*-*|nanomips*-*-*) if test "${targ}" = "${target}"; then SIM_PRIMARY_TARGET=mips fi diff --git a/sim/configure.ac b/sim/configure.ac index 675fa1bb44d..3f606ac5b64 100644 --- a/sim/configure.ac +++ b/sim/configure.ac @@ -143,7 +143,7 @@ if test "${enable_sim}" != no; then SIM_TARGET([m68hc11-*-*|m6811-*-*], [m68hc11]) SIM_TARGET([mcore-*-*], [mcore]) SIM_TARGET([microblaze*-*-*], [microblaze]) - SIM_TARGET([mips*-*-*], [mips], [true], [sim_igen=yes]) + SIM_TARGET([mips*-*-*|nanomips*-*-*], [mips], [true], [sim_igen=yes]) SIM_TARGET([mn10300*-*-*], [mn10300], [], [sim_igen=yes]) SIM_TARGET([moxie-*-*], [moxie]) SIM_TARGET([msp430*-*-*], [msp430]) diff --git a/sim/mips/Makefile.in b/sim/mips/Makefile.in index 75438be5a18..8637b46b186 100644 --- a/sim/mips/Makefile.in +++ b/sim/mips/Makefile.in @@ -61,6 +61,7 @@ SIM_OBJS = \ cp1.o \ mdmx.o \ dsp.o \ + nms.o \ sim-main.o \ sim-resume.o \ @@ -99,6 +100,8 @@ IGEN_INCLUDE=\ $(srcdir)/dsp2.igen \ $(srcdir)/mips3264r2.igen \ $(srcdir)/mips3264r6.igen \ + $(srcdir)/nanomipsdsp.igen \ + $(srcdir)/nanomipsr6.igen # NB: Since these can be built by a number of generators, care # must be taken to ensure that they are only dependant on @@ -463,8 +466,11 @@ tmp-mach-multi: $(IGEN_INSN) $(IGEN_DC) $(IGEN) $(IGEN_INCLUDE) f=`echo $${t} | sed -e 's/.*://'` ; \ case $${p} in \ micromips16*) e="-B 16 -H 15 -o $(MICROMIPS16_DC) -F 16" ;; \ + nanomips16*) e="-B 16 -H 15 -o $(MICROMIPS16_DC) -F 16" ;; \ micromips32* | micromips64*) \ e="-B 32 -H 31 -o $(MICROMIPS32_DC) -F $${f}" ;; \ + nanomips32* | nanomips64*) \ + e="-B 32 -H 31 -o $(MICROMIPS32_DC) -F $${f}" ;; \ micromips_m32*) \ e="-B 32 -H 31 -o $(IGEN_DC) -F $${f}"; \ m="mips32r2,mips3d,mdmx,dsp,dsp2,smartmips" ;; \ @@ -579,6 +585,28 @@ tmp-run-multi: $(srcdir)/m16run.c $(srcdir)/micromipsrun.c $(SHELL) $(srcdir)/../../move-if-change tmp-run \ micromips$${m}_run.c ; \ ;;\ + nanomips32*) \ + m=`echo $${t} | sed -e 's/^nanomips32//' -e 's/:.*//'`; \ + sed < $(srcdir)/nanomipsrun.c > tmp-run \ + -e "s/^sim_/nanomips32$${m}_/" \ + -e "s/nanomips_instruction_decode/nanomips32$${m}_instruction_decode/g" \ + -e "s/nanomips16_/nanomips16$${m}_/" \ + -e "s/nanomips32_/nanomips32$${m}_/" \ + -e "s/m32_/m32$${m}_/" ; \ + $(SHELL) $(srcdir)/../../move-if-change tmp-run \ + nanomips$${m}_run.c ; \ + ;;\ + nanomips64*) \ + m=`echo $${t} | sed -e 's/^nanomips64//' -e 's/:.*//'`; \ + sed < $(srcdir)/nanomipsrun.c > tmp-run \ + -e "s/^sim_/nanomips64$${m}_/" \ + -e "s/nanomips_instruction_decode/nanomips64$${m}_instruction_decode/g" \ + -e "s/nanomips16_/nanomips16$${m}_/" \ + -e "s/nanomips32_/nanomips64$${m}_/" \ + -e "s/m32_/m64$${m}_/" ; \ + $(SHELL) $(srcdir)/../../move-if-change tmp-run \ + nanomips$${m}_run.c ; \ + ;;\ esac \ done $(SILENCE) touch $@ diff --git a/sim/mips/configure b/sim/mips/configure index b0ba7ba7470..493547fc97b 100755 --- a/sim/mips/configure +++ b/sim/mips/configure @@ -2028,6 +2028,12 @@ case "${target}" in mipsisa64r6:mips64r6:32,64,f:mipsisa32r6,mipsisa64r6" sim_multi_default=mipsisa64r2 ;; + nanomips*-elf*) + sim_gen=MULTI + sim_multi_configs="\ + nanor6sim:nanomips64r6,nanomipsdsp:32,64,f:nanomipsisa64r6,nanomipsisa32r6" + sim_multi_default=nanomipsisa32r6 + ;; mips64*-*-*) sim_igen_filter="32,64,f" sim_gen=IGEN ;; @@ -2226,6 +2232,17 @@ __EOF__ sim_multi_obj="${sim_multi_obj} micromips${name}_run.o" sim_multi_flags="${sim_multi_flags} -F 16,32" ;; + *:*nanomips32*) + # Run igen twice, once for nanomips32 and once for nanomips16. + ws="nanomips16 nanomips32" + + # The top-level function for the micromips simulator is + # in a file micromips${name}_run.c, generated by the + # tmp-run-multi Makefile rule. + sim_multi_src="${sim_multi_src} nanomips${name}_run.c" + sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o" + sim_multi_flags="${sim_multi_flags} -F 16,32" + ;; *:*micromips64*:*) # Run igen thrice, once for micromips64, once for micromips16, # and once for m64. @@ -2238,6 +2255,17 @@ __EOF__ sim_multi_obj="${sim_multi_obj} micromips${name}_run.o" sim_multi_flags="${sim_multi_flags} -F 16,32,64" ;; + *:*nanomips64*) + # Run igen twice, once for nanomips64 and once for nanomips16. + ws="nanomips16 nanomips64" + + # The top-level function for the micromips simulator is + # in a file micromips${name}_run.c, generated by the + # tmp-run-multi Makefile rule. + sim_multi_src="${sim_multi_src} nanomips${name}_run.c" + sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o" + sim_multi_flags="${sim_multi_flags} -F 16,32,64" + ;; *) ws=m32 ;; diff --git a/sim/mips/configure.ac b/sim/mips/configure.ac index f1d9f3d2410..e8153b0c5ac 100644 --- a/sim/mips/configure.ac +++ b/sim/mips/configure.ac @@ -106,6 +106,12 @@ case "${target}" in mipsisa64r6:mips64r6:32,64,f:mipsisa32r6,mipsisa64r6" sim_multi_default=mipsisa64r2 ;; + nanomips*-*-elf*) + sim_gen=MULTI + sim_multi_configs="\ + nanor6sim:nanomips64r6,nanomipsdsp:32,64,f:nanomipsisa64r6,nanomipsisa32r6" + sim_multi_default=nanomipsisa64r6 + ;; mips64*-*-*) sim_igen_filter="32,64,f" sim_gen=IGEN ;; @@ -304,6 +310,17 @@ __EOF__ sim_multi_obj="${sim_multi_obj} micromips${name}_run.o" sim_multi_flags="${sim_multi_flags} -F 16,32" ;; + *:*nanomips32*) + # Run igen twice, once for nanomips32 and once for nanomips16. + ws="nanomips16 nanomips32" + + # The top-level function for the micromips simulator is + # in a file micromips${name}_run.c, generated by the + # tmp-run-multi Makefile rule. + sim_multi_src="${sim_multi_src} nanomips${name}_run.c" + sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o" + sim_multi_flags="${sim_multi_flags} -F 16,32" + ;; *:*micromips64*:*) # Run igen thrice, once for micromips64, once for micromips16, # and once for m64. @@ -316,6 +333,17 @@ __EOF__ sim_multi_obj="${sim_multi_obj} micromips${name}_run.o" sim_multi_flags="${sim_multi_flags} -F 16,32,64" ;; + *:*nanomips64*) + # Run igen twice, once for nanomips64 and once for nanomips16. + ws="nanomips16 nanomips64" + + # The top-level function for the micromips simulator is + # in a file micromips${name}_run.c, generated by the + # tmp-run-multi Makefile rule. + sim_multi_src="${sim_multi_src} nanomips${name}_run.c" + sim_multi_obj="${sim_multi_obj} nanomips${name}_run.o" + sim_multi_flags="${sim_multi_flags} -F 16,32,64" + ;; *) ws=m32 ;; diff --git a/sim/mips/interp.c b/sim/mips/interp.c index ab20f079939..3612956bb2b 100644 --- a/sim/mips/interp.c +++ b/sim/mips/interp.c @@ -356,6 +356,8 @@ sim_open (SIM_OPEN_KIND kind, host_callback *cb, cpu = STATE_CPU (sd, 0); /* FIXME */ + IS_NANOMIPS = 0; + /* FIXME: watchpoints code shouldn't need this */ STATE_WATCHPOINTS (sd)->interrupt_handler = interrupt_event; @@ -672,10 +674,13 @@ sim_open (SIM_OPEN_KIND kind, host_callback *cb, cpu->register_widths[rn] = WITH_TARGET_FLOATING_POINT_BITSIZE; else if ((rn >= 33) && (rn <= 37)) cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE; + else if ((rn >= 70) && (rn <= 78)) + cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE; else if ((rn == SRIDX) || (rn == FCR0IDX) || (rn == FCR31IDX) - || ((rn >= 72) && (rn <= 89))) + || (rn == DSPCRIDX) + || ((rn >= 80) && (rn <= 89))) cpu->register_widths[rn] = 32; else cpu->register_widths[rn] = 0; @@ -1200,7 +1205,7 @@ sim_monitor (SIM_DESC sd, case 6: /* int open(char *path,int flags) */ { char *path = fetch_str (sd, A0); - V0 = sim_io_open (sd, path, (int)A1); + SET_RV0 (sim_io_open (sd, path, (int)A1)); free (path); break; } @@ -1210,7 +1215,7 @@ sim_monitor (SIM_DESC sd, int fd = A0; int nr = A2; char *buf = zalloc (nr); - V0 = sim_io_read (sd, fd, buf, nr); + SET_RV0 (sim_io_read (sd, fd, buf, nr)); sim_write (sd, A1, buf, nr); free (buf); } @@ -1222,7 +1227,7 @@ sim_monitor (SIM_DESC sd, int nr = A2; char *buf = zalloc (nr); sim_read (sd, A1, buf, nr); - V0 = sim_io_write (sd, fd, buf, nr); + SET_RV0 (sim_io_write (sd, fd, buf, nr)); if (fd == 1) sim_io_flush_stdout (sd); else if (fd == 2) @@ -1233,14 +1238,14 @@ sim_monitor (SIM_DESC sd, case 10: /* int close(int file) */ { - V0 = sim_io_close (sd, (int)A0); + SET_RV0 (sim_io_close (sd, (int)A0)); break; } case 2: /* Densan monitor: char inbyte(int waitflag) */ { if (A0 == 0) /* waitflag == NOWAIT */ - V0 = (unsigned_word)-1; + SET_RV0 ((unsigned_word)-1); } /* Drop through to case 11 */ @@ -1252,10 +1257,10 @@ sim_monitor (SIM_DESC sd, if (sim_io_read_stdin (sd, &tmp, sizeof(char)) != sizeof(char)) { sim_io_error(sd,"Invalid return from character read"); - V0 = (unsigned_word)-1; + SET_RV0 ((unsigned_word)-1); } else - V0 = (unsigned_word)tmp; + SET_RV0 ((unsigned_word)tmp); break; } diff --git a/sim/mips/micromips16.dc b/sim/mips/micromips16.dc index a1cd9a0ea89..ace9bb94fad 100644 --- a/sim/mips/micromips16.dc +++ b/sim/mips/micromips16.dc @@ -8,4 +8,7 @@ switch,combine : 9 : 6 : : : : : : switch,combine : 9 : 5 : : : : : : + switch,combine : 3 : 0 : : : : : : + switch,combine : 2 : 0 : : : : : : + switch,combine : 5 : 3 : : : : : : switch,combine : 0 : 0 : : : : : : diff --git a/sim/mips/mips.igen b/sim/mips/mips.igen index 0746a52d5ab..e9110c44f2f 100644 --- a/sim/mips/mips.igen +++ b/sim/mips/mips.igen @@ -79,6 +79,9 @@ :model:::micromips32:micromips64: // micromips.igen :model:::micromips64:micromips64: // micromips.igen :model:::micromipsdsp:micromipsdsp: // micromipsdsp.igen +:model:::nanomips32r6:nanomips32r6: // nanomipsr6.igen +:model:::nanomips64r6:nanomips64r6: // nanomipsr6.igen +:model:::nanomipsdsp:nanomipsdsp: // nanompsdsp.igen // Vendor Extensions // @@ -98,6 +101,33 @@ // For grep - RSVD_INSTRUCTION, RSVD_INSTRUCTION_MASK 000000,5.*,5.*,5.*,5.OP,111001:SPECIAL:32::RSVD "rsvd " +*mipsI: +*mipsII: +*mipsIII: +*mipsIV: +*mipsV: +*mips32: +*mips32r2: +*mips32r6: +*mips64: +*mips64r2: +*mips64r6: +*vr4100: +*vr4120: +*vr5000: +*vr5400: +*vr5500: +*r3900: +*mips16: +*mips16e: +*mips3d: +*mdmx: +*dsp: +*dsp2: +*smartmips: +*micromips32: +*micromips64: +*micromipsdsp: { SignalException (ReservedInstruction, instruction_0); } @@ -192,6 +222,7 @@ *vr5000: *r3900: *micromips32: +*nanomips32r6: { return base + offset; } @@ -201,6 +232,7 @@ *mips64r2: *micromips64: *mips64r6: +*nanomips64r6: { #if 0 /* XXX FIXME: enable this only after some additional testing. */ /* If in user mode and UX is not set, use 32-bit compatibility effective @@ -237,6 +269,8 @@ *micromips32: *micromips64: *mips64r6: +*nanomips32r6: +*nanomips64r6: { #if WITH_TARGET_WORD_BITSIZE == 64 return value != (((value & 0xffffffff) ^ 0x80000000) - 0x80000000); @@ -274,6 +308,8 @@ *micromips32: *micromips64: *mips64r6: +*nanomips32r6: +*nanomips64r6: { unpredictable_action (CPU, CIA); } @@ -369,6 +405,7 @@ *r3900: *micromips32: *micromips64: +*nanomipsdsp: { int64_t time = sim_events_time (SD); history->mt.timestamp = time; @@ -399,6 +436,7 @@ *r3900: *micromips32: *micromips64: +*nanomipsdsp: { int64_t time = sim_events_time (SD); int ok = 1; @@ -473,6 +511,7 @@ *r3900: *micromips32: *micromips64: +*nanomipsdsp: { /* FIXME: could record the fact that a stall occured if we want */ int64_t time = sim_events_time (SD); @@ -570,6 +609,8 @@ *micromips64: *micromips32: *mips64r6: +*nanomips32r6: +*nanomips64r6: { #if 0 /* XXX FIXME: enable this only after some additional testing. */ if (UserMode && (SR & (status_UX|status_PX)) == 0) @@ -781,12 +822,44 @@ } :function:::void:do_lb:int rt, int offset, int base +*mipsI: +*mipsII: +*mipsIII: +*mipsIV: +*mipsV: +*mips32: +*mips32r2: +*mips32r6: +*mips64: +*mips64r2: +*mips64r6: +*vr4100: +*vr5000: +*r3900: +*micromips32: +*micromips64: { GPR[rt] = EXTEND8 (do_load (SD_, AccessLength_BYTE, GPR[base], EXTEND16 (offset))); } :function:::void:do_lh:int rt, int offset, int base +*mipsI: +*mipsII: +*mipsIII: +*mipsIV: +*mipsV: +*mips32: +*mips32r2: +*mips32r6: +*mips64: +*mips64r2: +*mips64r6: +*vr4100: +*vr5000: +*r3900: +*micromips32: +*micromips64: { GPR[rt] = EXTEND16 (do_load (SD_, AccessLength_HALFWORD, GPR[base], EXTEND16 (offset))); @@ -811,6 +884,22 @@ } :function:::void:do_lw:int rt, int offset, int base +*mipsI: +*mipsII: +*mipsIII: +*mipsIV: +*mipsV: +*mips32: +*mips32r2: +*mips32r6: +*mips64: +*mips64r2: +*mips64r6: +*vr4100: +*vr5000: +*r3900: +*micromips32: +*micromips64: { GPR[rt] = EXTEND32 (do_load (SD_, AccessLength_WORD, GPR[base], EXTEND16 (offset))); @@ -823,6 +912,22 @@ } :function:::void:do_lhu:int rt, int offset, int base +*mipsI: +*mipsII: +*mipsIII: +*mipsIV: +*mipsV: +*mips32: +*mips32r2: +*mips32r6: +*mips64: +*mips64r2: +*mips64r6: +*vr4100: +*vr5000: +*r3900: +*micromips32: +*micromips64: { GPR[rt] = do_load (SD_, AccessLength_HALFWORD, GPR[base], EXTEND16 (offset)); } @@ -1861,7 +1966,23 @@ -:function:::void:do_addiu:int rs, int rt, uint16_t immediate +:function:::void:do_addiu:int rs, int rt, int immediate +*mipsI: +*mipsII: +*mipsIII: +*mipsIV: +*mipsV: +*mips32: +*mips32r2: +*mips32r6: +*mips64: +*mips64r2: +*mips64r6: +*vr4100: +*vr5000: +*r3900: +*micromips32: +*micromips64: { if (NotWordValue (GPR[rs])) Unpredictable (); @@ -2595,6 +2716,14 @@ :function:::void:do_ddiv:int rs, int rt +*mipsIII: +*mipsIV: +*mipsV: +*mips64: +*mips64r2: +*micromips64: +*vr4100: +*vr5000: { check_div_hilo (SD_, HIHISTORY, LOHISTORY); TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]); @@ -2641,6 +2770,14 @@ :function:::void:do_ddivu:int rs, int rt +*mipsIII: +*mipsIV: +*mipsV: +*mips64: +*mips64r2: +*micromips64: +*vr4100: +*vr5000: { check_div_hilo (SD_, HIHISTORY, LOHISTORY); TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]); @@ -2680,6 +2817,20 @@ } :function:::void:do_div:int rs, int rt +*mipsI: +*mipsII: +*mipsIII: +*mipsIV: +*mipsV: +*mips32: +*mips32r2: +*micromips32: +*mips64: +*mips64r2: +*micromips64: +*vr4100: +*vr5000: +*r3900: { check_div_hilo (SD_, HIHISTORY, LOHISTORY); TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]); @@ -2726,6 +2877,20 @@ :function:::void:do_divu:int rs, int rt +*mipsI: +*mipsII: +*mipsIII: +*mipsIV: +*mipsV: +*mips32: +*mips32r2: +*micromips32: +*mips64: +*mips64r2: +*micromips64: +*vr4100: +*vr5000: +*r3900: { check_div_hilo (SD_, HIHISTORY, LOHISTORY); TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]); @@ -3714,6 +3879,25 @@ :function:::void:do_mfhi:int rd +*mipsI: +*mipsII: +*mipsIII: +*mipsIV: +*mipsV: +*vr4100: +*vr5000: +*r3900: +*mips32: +*mips64: +*mips32r2: +*mips32r6: +*mips64r2: +*mips64r6: +*dsp: +*micromips32: +*micromips64: +*micromipsdsp: +*nanomipsdsp: { check_mf_hilo (SD_, HIHISTORY, LOHISTORY); TRACE_ALU_INPUT1 (HI); @@ -5225,6 +5409,8 @@ *vr4100: *vr5000: *r3900: +*nanomips32r6: +*nanomips64r6: { /* None of these ISAs support Paired Single, so just fall back to the single/double check. */ @@ -5273,6 +5459,8 @@ *r3900: *micromips32: *micromips64: +*nanomips32r6: +*nanomips64r6: { if (! COP_Usable (1)) SignalExceptionCoProcessorUnusable (1); @@ -6867,4 +7055,5 @@ :include:::smartmips.igen :include:::micromips.igen :include:::micromipsdsp.igen - +:include:::nanomipsr6.igen +:include:::nanomipsdsp.igen diff --git a/sim/mips/nanomipsdsp.igen b/sim/mips/nanomipsdsp.igen new file mode 100644 index 00000000000..07fd26b6ad0 --- /dev/null +++ b/sim/mips/nanomipsdsp.igen @@ -0,0 +1,1115 @@ +// Simulator definition for the micromips ASE. +// Copyright (C) 2018-2022 Free Software Foundation, Inc. +// Contributed by Imagination Technologies, Ltd. +// Written by Ali Lown +// +// This file is part of GDB, the GNU debugger. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +001000,5.RT,5.RS,0001000100111111:POOL32A:32::ABSQ_S.PH +"absq_s.ph r, r" +*nanomipsdsp: +{ + do_ph_s_absq (SD_, RT, RS); +} + +001000,5.RT,5.RS,0000000100111111:POOL32A:32::ABSQ_S.QB +"absq_s.qb r, r" +*nanomipsdsp: +{ + do_qb_s_absq (SD_, RT, RS); +} + +001000,5.RT,5.RS,0010000100111111:POOL32A:32::ABSQ_S.W +"absq_s.w r, r" +*nanomipsdsp: +{ + do_w_s_absq (SD_, RT, RS); +} + +001000,5.RT,5.RS,5.RD,00000001101:POOL32A:32::ADDQ.PH +"addq.ph r, r, r" +*nanomipsdsp: +{ + do_ph_op (SD_, RD, RS, RT, 0, 0); +} + +001000,5.RT,5.RS,5.RD,10000001101:POOL32A:32::ADDQ_S.PH +"addq_s.ph r, r, r" +*nanomipsdsp: +{ + do_ph_op (SD_, RD, RS, RT, 0, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,1100000101:POOL32A:32::ADDQ_S.W +"addq_s.w r, r, r" +*nanomipsdsp: +{ + do_w_op (SD_, RD, RS, RT, 0); +} + +001000,5.RT,5.RS,5.RD,00001001101:POOL32A:32::ADDQH.PH +"addqh.ph r, r, r" +*nanomipsdsp: +{ + do_qh_ph_op (SD_, RD, RS, RT, 0, 0); +} + +001000,5.RT,5.RS,5.RD,10001001101:POOL32A:32::ADDQH_R.PH +"addqh_r.ph r, r, r" +*nanomipsdsp: +{ + do_qh_ph_op (SD_, RD, RS, RT, 0, 1); +} + +001000,5.RT,5.RS,5.RD,00010001101:POOL32A:32::ADDQH.W +"addqh.w r, r, r" +*nanomipsdsp: +{ + do_qh_w_op (SD_, RD, RS, RT, 0, 0); +} + +001000,5.RT,5.RS,5.RD,10010001101:POOL32A:32::ADDQH_R.W +"addqh_r.w r, r, r" +*nanomipsdsp: +{ + do_qh_w_op (SD_, RD, RS, RT, 0, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,1110000101:POOL32A:32::ADDSC +"addsc r, r, r" +*nanomipsdsp: +{ + do_addsc (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,5.RD,00100001101:POOL32A:32::ADDU.PH +"addu.ph r, r, r" +*nanomipsdsp: +{ + do_u_ph_op (SD_, RD, RS, RT, 0, 0); +} + +001000,5.RT,5.RS,5.RD,10100001101:POOL32A:32::ADDU_S.PH +"addu_s.ph r, r, r" +*nanomipsdsp: +{ + do_u_ph_op (SD_, RD, RS, RT, 0, 1); +} + +001000,5.RT,5.RS,5.RD,00011001101:POOL32A:32::ADDU.QB +"addu.qb r, r, r" +*nanomipsdsp: +{ + do_qb_op (SD_, RD, RS, RT, 0, 0); +} + +001000,5.RT,5.RS,5.RD,10011001101:POOL32A:32::ADDU_S.QB +"addu_s.qb r, r, r" +*nanomipsdsp: +{ + do_qb_op (SD_, RD, RS, RT, 0, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,1111000101:POOL32A:32::ADDWC +"addwc r, r, r" +*nanomipsdsp: +{ + do_addwc (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,5.RD,00101001101:POOL32A:32::ADDUH.QB +"adduh.qb r, r, r" +*nanomipsdsp: +{ + do_uh_qb_op (SD_, RD, RS, RT, 0, 0); +} + +001000,5.RT,5.RS,5.RD,10101001101:POOL32A:32::ADDUH_R.QB +"adduh_r.qb r, r, r" +*nanomipsdsp: +{ + do_uh_qb_op (SD_, RD, RS, RT, 0, 1); +} + +001000,5.RT,5.RS,5.SA,1.X,1000010101:POOL32A:32::APPEND +"append r, r, " +*nanomipsdsp: +{ + do_append (SD_, RT, RS, SA); +} + +001000,5.RT,5.RS,2.BP,00100010111111:POOL32A:32::BALIGN +"balign r, r, " +*nanomipsdsp: +{ + do_balign (SD_, RT, RS, BP); +} + +001000,5.RT,5.RS,0011000100111111:POOL32A:32::BITREV +"bitrev r, r" +*nanomipsdsp: +{ + do_bitrev (SD_, RT, RS); +} + +100010,5.X,0010001,13.S1,1.S2:POOL32I:32::BPOSGE32C +"bposge32c " +*nanomipsdsp: +{ + uint32_t pos = (DSPCR >> DSPCR_POS_SHIFT) & DSPCR_POS_MASK; + if (pos >= 32) + NIA = ADDRESS15; +} + +001000,5.RT,5.RS,6.X,0000000101:POOL32A:32::CMP.EQ.PH +"cmp.eq.ph r, r" +*nanomipsdsp: +{ + do_ph_cmpu (SD_, RS, RT, 0); +} + +001000,5.RT,5.RS,0000000001,000101:POOL32A:32::CMP.LT.PH +"cmp.lt.ph r, r" +*nanomipsdsp: +{ + do_ph_cmpu (SD_, RS, RT, 1); +} + +001000,5.RT,5.RS,0000000010,000101:POOL32A:32::CMP.LE.PH +"cmp.le.ph r, r" +*nanomipsdsp: +{ + do_ph_cmpu (SD_, RS, RT, 2); +} + +001000,5.RT,5.RS,5.RD,1.X,0110000101:POOL32A:32::CMPGDU.EQ.QB +"cmpgdu.eq.qb r, r, r" +*nanomipsdsp: +{ + do_qb_cmpgdu (SD_, RD, RS, RT, 0); +} + +001000,5.RT,5.RS,5.RD,1.X,0111000101:POOL32A:32::CMPGDU.LT.QB +"cmpgdu.lt.qb r, r, r" +*nanomipsdsp: +{ + do_qb_cmpgdu (SD_, RD, RS, RT, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,1000000101:POOL32A:32::CMPGDU.LE.QB +"cmpgdu.le.qb r, r, r" +*nanomipsdsp: +{ + do_qb_cmpgdu (SD_, RD, RS, RT, 2); +} + +001000,5.RT,5.RS,5.RD,1.X,0011000101:POOL32A:32::CMPGU.EQ.QB +"cmpgu.eq.qb r, r, r" +*nanomipsdsp: +{ + do_qb_cmpgu (SD_, RD, RS, RT, 0); +} + +001000,5.RT,5.RS,5.RD,1.X,0100000101:POOL32A:32::CMPGU.LT.QB +"cmpgu.lt.qb r, r, r" +*nanomipsdsp: +{ + do_qb_cmpgu (SD_, RD, RS, RT, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,0101000101:POOL32A:32::CMPGU.LE.QB +"cmpgu.le.qb r, r, r" +*nanomipsdsp: +{ + do_qb_cmpgu (SD_, RD, RS, RT, 2); +} + +001000,5.RT,5.RS,5.X1,1.X2,1001000101:POOL32A:32::CMPU.EQ.QB +"cmpu.eq.qb r, r" +*nanomipsdsp: +{ + do_qb_cmpu (SD_, RS, RT, 0); +} + +001000,5.RT,5.RS,5.X1,1.X2,1010000101:POOL32A:32::CMPU.LT.QB +"cmpu.lt.qb r, r" +*nanomipsdsp: +{ + do_qb_cmpu (SD_, RS, RT, 1); +} + +001000,5.RT,5.RS,5.X1,1.X2,1011000101:POOL32A:32::CMPU.LE.QB +"cmpu.le.qb r, r" +*nanomipsdsp: +{ + do_qb_cmpu (SD_, RS, RT, 2); +} + +001000,5.RT,5.RS,2.AC,00000010111111:POOL32A:32::DPA.W.PH +"dpa.w.ph ac, r, r" +*nanomipsdsp: +{ + do_w_ph_dot_product (SD_, AC, RS, RT, 0); +} + +001000,5.RT,5.RS,2.AC,00001010111111:POOL32A:32::DPAQ_S.W.PH +"dpaq_s.w.ph ac, r, r" +*nanomipsdsp: +{ + do_ph_dot_product (SD_, AC, RS, RT, 0); +} + +001000,5.RT,5.RS,2.AC,01001010111111:POOL32A:32::DPAQ_SA.L.W +"dpaq_sa.l.w ac, r, r" +*nanomipsdsp: +{ + do_w_dot_product (SD_, AC, RS, RT, 0); +} + +001000,5.RT,5.RS,2.AC,10001010111111:POOL32A:32::DPAQX_S.W.PH +"dpaqx_s.w.ph ac, r, r" +*nanomipsdsp: +{ + do_qx_w_ph_dot_product (SD_, AC, RS, RT, 0, 0); +} + +001000,5.RT,5.RS,2.AC,11001010111111:POOL32A:32::DPAQX_SA.W.PH +"dpaqx_sa.w.ph ac, r, r" +*nanomipsdsp: +{ + do_qx_w_ph_dot_product (SD_, AC, RS, RT, 0, 1); +} + +001000,5.RT,5.RS,2.AC,10000010111111:POOL32A:32::DPAU.H.QBL +"dpau.h.qbl ac, r, r" +*nanomipsdsp: +{ + do_qb_dot_product (SD_, AC, RS, RT, 0, 0); +} + +001000,5.RT,5.RS,2.AC,11000010111111:POOL32A:32::DPAU.H.QBR +"dpau.h.qbr ac, r, r" +*nanomipsdsp: +{ + do_qb_dot_product (SD_, AC, RS, RT, 0, 1); +} + +001000,5.RT,5.RS,2.AC,01000010111111:POOL32A:32::DPAX.W.PH +"dpax.w.ph ac, r, r" +*nanomipsdsp: +{ + do_x_w_ph_dot_product (SD_, AC, RS, RT, 0); +} + +001000,5.RT,5.RS,2.AC,00010010111111:POOL32A:32::DPS.W.PH +"dps.w.ph ac, r, r" +*nanomipsdsp: +{ + do_w_ph_dot_product (SD_, AC, RS, RT, 1); +} + +001000,5.RT,5.RS,2.AC,00011010111111:POOL32A:32::DPSQ_S.W.PH +"dpsq_s.w.ph ac, r, r" +*nanomipsdsp: +{ + do_ph_dot_product (SD_, AC, RS, RT, 1); +} + +001000,5.RT,5.RS,2.AC,01011010111111:POOL32A:32::DPSQ_SA.L.W +"dpsq_sa.l.w ac, r, r" +*nanomipsdsp: +{ + do_w_dot_product (SD_, AC, RS, RT, 1); +} + +001000,5.RT,5.RS,2.AC,10011010111111:POOL32A:32::DPSQX_S.W.PH +"dpsqx_s.w.ph ac, r, r" +*nanomipsdsp: +{ + do_qx_w_ph_dot_product (SD_, AC, RS, RT, 1, 0); +} + +001000,5.RT,5.RS,2.AC,11011010111111:POOL32A:32::DPSQX_SA.W.PH +"dpsqx_sa.w.ph ac, r, r" +*nanomipsdsp: +{ + do_qx_w_ph_dot_product (SD_, AC, RS, RT, 1, 1); +} + +001000,5.RT,5.RS,2.AC,10010010111111:POOL32A:32::DPSU.H.QBL +"dpsu.h.qbl ac, r, r" +*nanomipsdsp: +{ + do_qb_dot_product (SD_, AC, RS, RT, 1, 0); +} + +001000,5.RT,5.RS,2.AC,11010010111111:POOL32A:32::DPSU.H.QBR +"dpsu.h.qbr ac, r, r" +*nanomipsdsp: +{ + do_qb_dot_product (SD_, AC, RS, RT, 1, 1); +} + +001000,5.RT,5.RS,2.AC,01010010111111:POOL32A:32::DPSX.W.PH +"dpsx.w.ph ac, r, r" +*nanomipsdsp: +{ + do_x_w_ph_dot_product (SD_, AC, RS, RT, 1); +} + +001000,5.RT,5.SIZE,2.AC,10011001111111:POOL32A:32::EXTP +"extp r, ac, " +*nanomipsdsp: +{ + do_extp (SD_, RT, AC, SIZE, 0); +} + +001000,5.RT,5.SIZE,2.AC,11011001111111:POOL32A:32::EXTPDP +"extpdp r, ac, " +*nanomipsdsp: +{ + do_extp (SD_, RT, AC, SIZE, 1); +} + +001000,5.RT,5.RS,2.AC,11100010111111:POOL32A:32::EXTPDPV +"extpdpv r, ac, r" +*nanomipsdsp: +{ + do_extpv (SD_, RT, AC, RS, 1); +} + +001000,5.RT,5.RS,2.AC,10100010111111:POOL32A:32::EXTPV +"extpv r, ac, r" +*nanomipsdsp: +{ + do_extpv (SD_, RT, AC, RS, 0); +} + +001000,5.RT,5.SHIFT,2.AC,00111001111111:POOL32A:32::EXTR.W +"extr.w r, ac, " +*nanomipsdsp: +{ + do_w_extr (SD_, RT, AC, SHIFT, 0); +} + +001000,5.RT,5.SHIFT,2.AC,01111001111111:POOL32A:32::EXTR_R.W +"extr_r.w r, ac, " +*nanomipsdsp: +{ + do_w_extr (SD_, RT, AC, SHIFT, 1); +} + +001000,5.RT,5.SHIFT,2.AC,10111001111111:POOL32A:32::EXTR_RS.W +"extr_rs.w r, ac, " +*nanomipsdsp: +{ + do_w_extr (SD_, RT, AC, SHIFT, 2); +} + +001000,5.RT,5.SHIFT,2.AC,11111001111111:POOL32A:32::EXTR_S.H +"extr_s.h r, ac, " +*nanomipsdsp: +{ + do_h_extr (SD_, RT, AC, SHIFT); +} + +001000,5.RT,5.RS,2.AC,00111010111111:POOL32A:32::EXTRV.W +"extrv.w r, ac, r" +*nanomipsdsp: +{ + do_extrv (SD_, RT, AC, RS, 0); +} + +001000,5.RT,5.RS,2.AC,01111010111111:POOL32A:32::EXTRV_R.W +"extrv_r.w r, ac, r" +*nanomipsdsp: +{ + do_extrv (SD_, RT, AC, RS, 1); +} + +001000,5.RT,5.RS,2.AC,10111010111111:POOL32A:32::EXTRV_RS.W +"extrv_rs.w r, ac, r" +*nanomipsdsp: +{ + do_extrv (SD_, RT, AC, RS, 2); +} + +001000,5.RT,5.RS,2.AC,11111010111111:POOL32A:32::EXTRV_S.H +"extrv_s.h r, ac, r" +*nanomipsdsp: +{ + do_extrv_s_h (SD_, RT, AC, RS); +} + +001000,5.RT,5.RS,0100000100111111:POOL32A:32::INSV +"insv r, r" +*nanomipsdsp: +{ + do_insv (SD_, RT, RS); +} + +001000,5.RT,5.RS,2.AC,00101010111111:POOL32A:32::MADD_DSP +"madd ac, r, r" +*nanomipsdsp: +{ + do_dsp_madd (SD_, AC, RS, RT); +} + +001000,5.RT,5.RS,2.AC,01101010111111:POOL32A:32::MADDU_DSP +"maddu ac, r, r" +*nanomipsdsp: +{ + do_dsp_maddu (SD_, AC, RS, RT); +} + +001000,5.RT,5.RS,2.AC,01101001111111:POOL32A:32::MAQ_S.W.PHL +"maq_s.w.phl ac, r, r" +*nanomipsdsp: +{ + do_ph_maq (SD_, AC, RS, RT, 0, 0); +} + +001000,5.RT,5.RS,2.AC,11101001111111:POOL32A:32::MAQ_SA.W.PHL +"maq_sa.w.phl ac, r, r" +*nanomipsdsp: +{ + do_ph_maq (SD_, AC, RS, RT, 1, 0); +} + +001000,5.RT,5.RS,2.AC,00101001111111:POOL32A:32::MAQ_S.W.PHR +"maq_s.w.phr ac, r, r" +*nanomipsdsp: +{ + do_ph_maq (SD_, AC, RS, RT, 0, 1); +} + +001000,5.RT,5.RS,2.AC,10101001111111:POOL32A:32::MAQ_SA.W.PHR +"maq_sa.w.phr ac, r, r" +*nanomipsdsp: +{ + do_ph_maq (SD_, AC, RS, RT, 1, 1); +} + +001000,5.RS,5.X,2.AC,00000001111111:POOL32A:32::MFHI_DSP +"mfhi r, ac" +*nanomipsdsp: +{ + do_dsp_mfhi (SD_, AC, RS); +} + +001000,5.RS,5.X,2.AC,01000001111111:POOL32A:32::MFLO_DSP +"mflo r, ac" +*nanomipsdsp: +{ + do_dsp_mflo (SD_, AC, RS); +} + +001000,5.RT,5.RS,5.RD,1.X,1010010101:POOL32A:32::MODSUB +"modsub r, r, r" +*nanomipsdsp: +{ + do_modsub (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,2.AC,10101010111111:POOL32A:32::MSUB_DSP +"msub ac, r, r" +*nanomipsdsp: +{ + do_dsp_msub (SD_, AC, RS, RT); +} + +001000,5.RT,5.RS,2.AC,11101010111111:POOL32A:32::MSUBU_DSP +"msubu ac, r, r" +*nanomipsdsp: +{ + do_dsp_msubu (SD_, AC, RS, RT); +} + +001000,00000,5.RS,2.AC,10000001111111:POOL32A:32::MTHI_DSP +"mthi r, ac" +*nanomipsdsp: +{ + do_dsp_mthi (SD_, AC, RS); +} + +001000,00000,5.RS,2.AC,00001001111111:POOL32A:32::MTHLIP +"mthlip r, ac" +*nanomipsdsp: +{ + do_mthlip (SD_, RS, AC); +} + +001000,00000,5.RS,2.AC,11000001111111:POOL32A:32::MTLO_DSP +"mtlo r, ac" +*nanomipsdsp: +{ + do_dsp_mtlo (SD_, AC, RS); +} + +001000,5.RT,5.RS,5.RD,00000101101:POOL32A:32::MUL.PH +"mul.ph r, r, r" +*nanomipsdsp: +{ + do_ph_op (SD_, RD, RS, RT, 2, 0); +} + +001000,5.RT,5.RS,5.RD,10000101101:POOL32A:32::MUL_S.PH +"mul_s.ph r, r, r" +*nanomipsdsp: +{ + do_ph_op (SD_, RD, RS, RT, 2, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,0000100101:POOL32A:32::MULEQ_S.W.PHL +"muleq_s.w.phl r, r, r" +*nanomipsdsp: +{ + do_ph_muleq (SD_, RD, RS, RT, 0); +} + +001000,5.RT,5.RS,5.RD,1.X,0001100101:POOL32A:32::MULEQ_S.W.PHR +"muleq_s.w.phr r, r, r" +*nanomipsdsp: +{ + do_ph_muleq (SD_, RD, RS, RT, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,0010010101:POOL32A:32::MULEU_S.PH.QBL +"muleu_s.ph.qbl r, r, r" +*nanomipsdsp: +{ + do_qb_muleu (SD_, RD, RS, RT, 0); +} + +001000,5.RT,5.RS,5.RD,1.X,0011010101:POOL32A:32::MULEU_S.PH.QBR +"muleu_s.ph.qbr r, r, r" +*nanomipsdsp: +{ + do_qb_muleu (SD_, RD, RS, RT, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,0100010101:POOL32A:32::MULQ_RS.PH +"mulq_rs.ph r, r, r" +*nanomipsdsp: +{ + do_ph_mulq (SD_, RD, RS, RT, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,0110010101:POOL32A:32::MULQ_RS.W +"mulq_rs.w r, r, r" +*nanomipsdsp: +{ + do_w_mulq (SD_, RD, RS, RT, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,0101010101:POOL32A:32::MULQ_S.PH +"mulq_s.ph r, r, r" +*nanomipsdsp: +{ + do_ph_mulq (SD_, RD, RS, RT, 0); +} + +001000,5.RT,5.RS,5.RD,1.X,0111010101:POOL32A:32::MULQ_S.W +"mulq_s.w r, r, r" +*nanomipsdsp: +{ + do_w_mulq (SD_, RD, RS, RT, 0); +} + +001000,5.RT,5.RS,2.AC,10110010111111:POOL32A:32::MULSA.W.PH +"mulsa.w.ph ac, r, r" +*nanomipsdsp: +{ + do_ph_w_mulsa (SD_, AC, RS, RT); +} + +001000,5.RT,5.RS,2.AC,11110010111111:POOL32A:32::MULSAQ_S.W.PH +"mulsaq_s.w.ph ac, r, r" +*nanomipsdsp: +{ + do_mulsaq_s_w_ph (SD_, AC, RS, RT); +} + +001000,5.RT,5.RS,2.AC,00110010111111:POOL32A:32::MULT_DSP +"mult ac, r, r" +*nanomipsdsp: +{ + do_dsp_mult (SD_, AC, RS, RT); +} + +001000,5.RT,5.RS,2.AC,01110010111111:POOL32A:32::MULTU_DSP +"multu ac, r, r" +*nanomipsdsp: +{ + do_dsp_multu (SD_, AC, RS, RT); +} + +001000,5.RT,5.RS,5.RD,1.X,0110101101:POOL32A:32::PACKRL.PH +"packrl.ph r, r, r" +*nanomipsdsp: +{ + do_ph_packrl (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,5.RD,1.X,1000101101:POOL32A:32::PICK.PH +"pick.ph r, r, r" +*nanomipsdsp: +{ + do_ph_pick (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,5.RD,1.X,0111101101:POOL32A:32::PICK.QB +"pick.qb r, r, r" +*nanomipsdsp: +{ + do_qb_pick (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,0101000100111111:POOL32A:32::PRECEQ.W.PHL +"preceq.w.phl r, r" +*nanomipsdsp: +{ + do_w_preceq (SD_, RT, RS, 0); +} + +001000,5.RT,5.RS,0110000100111111:POOL32A:32::PRECEQ.W.PHR +"preceq.w.phr r, r" +*nanomipsdsp: +{ + do_w_preceq (SD_, RT, RS, 1); +} + +001000,5.RT,5.RS,0111000100111111:POOL32A:32::PRECEQU.PH.QBL +"precequ.ph.qbl r, r" +*nanomipsdsp: +{ + do_qb_ph_precequ (SD_, RT, RS, 2); +} + +001000,5.RT,5.RS,0111001100111111:POOL32A:32::PRECEQU.PH.QBLA +"precequ.ph.qbla r, r" +*nanomipsdsp: +{ + do_qb_ph_precequ (SD_, RT, RS, 3); +} + +001000,5.RT,5.RS,1001000100111111:POOL32A:32::PRECEQU.PH.QBR +"precequ.ph.qbr r, r" +*nanomipsdsp: +{ + do_qb_ph_precequ (SD_, RT, RS, 0); +} + +001000,5.RT,5.RS,1001001100111111:POOL32A:32::PRECEQU.PH.QBRA +"precequ.ph.qbra r, r" +*nanomipsdsp: +{ + do_qb_ph_precequ (SD_, RT, RS, 1); +} + +001000,5.RT,5.RS,1011000100111111:POOL32A:32::PRECEU.PH.QBL +"preceu.ph.qbl r, r" +*nanomipsdsp: +{ + do_qb_ph_preceu (SD_, RT, RS, 2); +} + +001000,5.RT,5.RS,1011001100111111:POOL32A:32::PRECEU.PH.QBLA +"preceu.ph.qbla r, r" +*nanomipsdsp: +{ + do_qb_ph_preceu (SD_, RT, RS, 3); +} + +001000,5.RT,5.RS,1101000100111111:POOL32A:32::PRECEU.PH.QBR +"preceu.ph.qbr r, r" +*nanomipsdsp: +{ + do_qb_ph_preceu (SD_, RT, RS, 0); +} + +001000,5.RT,5.RS,1101001100111111:POOL32A:32::PRECEU.PH.QBRA +"preceu.ph.qbra r, r" +*nanomipsdsp: +{ + do_qb_ph_preceu (SD_, RT, RS, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,0001101101:POOL32A:32::PRECR.QB.PH +"precr.qb.ph r, r, r" +*nanomipsdsp: +{ + do_ph_qb_precr (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,5.SA,01111001101:POOL32A:32::PRECR_SRA.PH.W +"precr_sra.ph.w r, r, " +*nanomipsdsp: +{ + do_precr_sra (SD_, RT, RS, SA, 0); +} + +001000,5.RT,5.RS,5.SA,11111001101:POOL32A:32::PRECR_SRA_R.PH.W +"precr_sra_r.ph.w r, r, " +*nanomipsdsp: +{ + do_precr_sra (SD_, RT, RS, SA, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,0011101101:POOL32A:32::PRECRQ.PH.W +"precrq.ph.w r, r, r" +*nanomipsdsp: +{ + do_w_ph_precrq (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,5.RD,1.X,0010101101:POOL32A:32::PRECRQ.QB.PH +"precrq.qb.ph r, r, r" +*nanomipsdsp: +{ + do_ph_qb_precrq (SD_, RD, RS, RT, 0); +} + +001000,5.RT,5.RS,5.RD,1.X,0101101101:POOL32A:32::PRECRQU_S.QB.PH +"precrqu_s.qb.ph r, r, r" +*nanomipsdsp: +{ + do_ph_qb_precrq (SD_, RD, RS, RT, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,0100101101:POOL32A:32::PRECRQ_RS.PH.W +"precrq_rs.ph.w r, r, r" +*nanomipsdsp: +{ + do_w_ph_rs_precrq (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,5.SA,1.X,1001010101:POOL32A:32::PREPEND +"prepend r, r, " +*nanomipsdsp: +{ + do_prepend (SD_, RT, RS, SA); +} + +001000,5.RT,5.RS,1111000100111111:POOL32A:32::RADDU.W.QB +"raddu.w.qb r, r" +*nanomipsdsp: +{ + do_qb_w_raddu (SD_, RT, RS); +} + +001000,5.RT,7.CONTROL_MASK,00011001111111:POOL32A:32::RDDSP +"rddsp r":CONTROL_MASK == 1111111111 +"rddsp r, " +*nanomipsdsp: +{ + do_rddsp (SD_, RT, CONTROL_MASK); +} + +001000,5.RT,10.IMMEDIATE,1.X,0000111101:POOL32A:32::REPL.PH +"repl.ph r, " +*nanomipsdsp: +{ + do_repl (SD_, RT, IMMEDIATE, 2); +} + +001000,5.RT,8.IMMEDIATE,1.X,010111111111:POOL32A:32::REPL.QB +"repl.qb r, " +*nanomipsdsp: +{ + do_repl (SD_, RT, IMMEDIATE, 0); +} + +001000,5.RT,5.RS,0000001100111111:POOL32A:32::REPLV.PH +"replv.ph r, r" +*nanomipsdsp: +{ + do_repl (SD_, RT, RS, 3); +} + +001000,5.RT,5.RS,0001001100111111:POOL32A:32::REPLV.QB +"replv.qb r, r" +*nanomipsdsp: +{ + do_repl (SD_, RT, RS, 1); +} + +001000,0000,6.IMMEDIATE,2.AC,00000000011101:POOL32A:32::SHILO +"shilo ac, " +*nanomipsdsp: +{ + do_shilo (SD_, AC, IMMEDIATE); +} + +001000,00000,5.RS,2.AC,01001001111111:POOL32A:32::SHILOV +"shilov ac, r" +*nanomipsdsp: +{ + do_shilov (SD_, AC, RS); +} + +001000,5.RT,5.RS,4.SHIFT,001110110101:POOL32A:32::SHLL.PH +"shll.ph r, r, " +*nanomipsdsp: +{ + do_ph_shift (SD_, RT, RS, SHIFT, 0, 0); +} + +001000,5.RT,5.RS,4.SHIFT,101110110101:POOL32A:32::SHLL_S.PH +"shll_s.ph r, r, " +*nanomipsdsp: +{ + do_ph_shift (SD_, RT, RS, SHIFT, 0, 1); +} + +001000,5.RT,5.RS,3.SHIFT,0100001111111:POOL32A:32::SHLL.QB +"shll.qb r, r, " +*nanomipsdsp: +{ + do_qb_shift (SD_, RT, RS, SHIFT, 0); +} + +001000,5.RT,5.RS,5.RD,01110001101:POOL32A:32::SHLLV.PH +"shllv.ph r, r, r" +*nanomipsdsp: +{ + do_ph_shl (SD_, RD, RT, RS, 0, 0); +} + +001000,5.RT,5.RS,5.RD,11110001101:POOL32A:32::SHLLV_S.PH +"shllv_s.ph r, r, r" +*nanomipsdsp: +{ + do_ph_shl (SD_, RD, RT, RS, 0, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,1110010101:POOL32A:32::SHLLV.QB +"shllv.qb r, r, r" +*nanomipsdsp: +{ + do_qb_shl (SD_, RD, RT, RS, 0); +} + +001000,5.RT,5.RS,5.RD,1.X,1111010101:POOL32A:32::SHLLV_S.W +"shllv_s.w r, r, r" +*nanomipsdsp: +{ + do_w_s_shllv (SD_, RD, RT, RS); +} + +001000,5.RT,5.RS,5.SHIFT,1.X,1111110101:POOL32A:32::SHLL_S.W +"shll_s.w r, r, " +*nanomipsdsp: +{ + do_w_shll (SD_, RT, RS, SHIFT); +} + +001000,5.RT,5.RS,3.SHIFT,0000111111111:POOL32A:32::SHRA.QB +"shra.qb r, r, " +*nanomipsdsp: +{ + do_qb_shra (SD_, RT, RS, SHIFT, 0); +} + +001000,5.RT,5.RS,3.SHIFT,1000111111111:POOL32A:32::SHRA_R.QB +"shra_r.qb r, r, " +*nanomipsdsp: +{ + do_qb_shra (SD_, RT, RS, SHIFT, 1); +} + +001000,5.RT,5.RS,4.SHIFT,1.X,01100110101:POOL32A:32::SHRA.PH +"shra.ph r, r, " +*nanomipsdsp: +{ + do_ph_shift (SD_, RT, RS, SHIFT, 1, 0); +} + +001000,5.RT,5.RS,4.SHIFT,1.X,11100110101:POOL32A:32::SHRA_R.PH +"shra_r.ph r, r, " +*nanomipsdsp: +{ + do_ph_shift (SD_, RT, RS, SHIFT, 1, 1); +} + +001000,5.RT,5.RS,5.RD,00110001101:POOL32A:32::SHRAV.PH +"shrav.ph r, r, r" +*nanomipsdsp: +{ + do_ph_shl (SD_, RD, RT, RS, 1, 0); +} + +001000,5.RT,5.RS,5.RD,10110001101:POOL32A:32::SHRAV_R.PH +"shrav_r.ph r, r, r" +*nanomipsdsp: +{ + do_ph_shl (SD_, RD, RT, RS, 1, 1); +} + +001000,5.RT,5.RS,5.RD,00111001101:POOL32A:32::SHRAV.QB +"shrav.qb r, r, r" +*nanomipsdsp: +{ + do_qb_shrav (SD_, RD, RT, RS, 0); +} + +001000,5.RT,5.RS,5.RD,10111001101:POOL32A:32::SHRAV_R.QB +"shrav_r.qb r, r, r" +*nanomipsdsp: +{ + do_qb_shrav (SD_, RD, RT, RS, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,1011010101:POOL32A:32::SHRAV_R.W +"shrav_r.w r, r, r" +*nanomipsdsp: +{ + do_w_r_shrav (SD_, RD, RT, RS); +} + +001000,5.RT,5.RS,5.SHIFT,1.X,1011110101:POOL32A:32::SHRA_R.W +"shra_r.w r, r, " +*nanomipsdsp: +{ + do_w_shra (SD_, RT, RS, SHIFT); +} + +001000,5.RT,5.RS,4.SHIFT,001111111111:POOL32A:32::SHRL.PH +"shrl.ph r, r, " +*nanomipsdsp: +{ + do_ph_shrl (SD_, RT, RS, SHIFT); +} + +001000,5.RT,5.RS,3.SHIFT,1100001111111:POOL32A:32::SHRL.QB +"shrl.qb r, r, " +*nanomipsdsp: +{ + do_qb_shift (SD_, RT, RS, SHIFT, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,1100010101:POOL32A:32::SHRLV.PH +"shrlv.ph r, r, r" +*nanomipsdsp: +{ + do_ph_shrlv (SD_, RD, RT, RS); +} + +001000,5.RT,5.RS,5.RD,1.X,1101010101:POOL32A:32::SHRLV.QB +"shrlv.qb r, r, r" +*nanomipsdsp: +{ + do_qb_shl (SD_, RD, RT, RS, 1); +} + +001000,5.RT,5.RS,5.RD,01000001101:POOL32A:32::SUBQ.PH +"subq.ph r, r, r" +*nanomipsdsp: +{ + do_ph_op (SD_, RD, RS, RT, 1, 0); +} + +001000,5.RT,5.RS,5.RD,11000001101:POOL32A:32::SUBQ_S.PH +"subq_s.ph r, r, r" +*nanomipsdsp: +{ + do_ph_op (SD_, RD, RS, RT, 1, 1); +} + +001000,5.RT,5.RS,5.RD,1.X,1101000101:POOL32A:32::SUBQ_S.W +"subq_s.w r, r, r" +*nanomipsdsp: +{ + do_w_op (SD_, RD, RS, RT, 1); +} + +001000,5.RT,5.RS,5.RD,01001001101:POOL32A:32::SUBQH.PH +"subqh.ph r, r, r" +*nanomipsdsp: +{ + do_qh_ph_op (SD_, RD, RS, RT, 1, 0); +} + +001000,5.RT,5.RS,5.RD,11001001101:POOL32A:32::SUBQH_R.PH +"subqh_r.ph r, r, r" +*nanomipsdsp: +{ + do_qh_ph_op (SD_, RD, RS, RT, 1, 1); +} + +001000,5.RT,5.RS,5.RD,01010001101:POOL32A:32::SUBQH.W +"subqh.w r, r, r" +*nanomipsdsp: +{ + do_qh_w_op (SD_, RD, RS, RT, 1, 0); +} + +001000,5.RT,5.RS,5.RD,11010001101:POOL32A:32::SUBQH_R.W +"subqh_r.w r, r, r" +*nanomipsdsp: +{ + do_qh_w_op (SD_, RD, RS, RT, 1, 1); +} + +001000,5.RT,5.RS,5.RD,01100001101:POOL32A:32::SUBU.PH +"subu.ph r, r, r" +*nanomipsdsp: +{ + do_u_ph_op (SD_, RD, RS, RT, 1, 0); +} + +001000,5.RT,5.RS,5.RD,11100001101:POOL32A:32::SUBU_S.PH +"subu_s.ph r, r, r" +*nanomipsdsp: +{ + do_u_ph_op (SD_, RD, RS, RT, 1, 1); +} + +001000,5.RT,5.RS,5.RD,01011001101:POOL32A:32::SUBU.QB +"subu.qb r, r, r" +*nanomipsdsp: +{ + do_qb_op (SD_, RD, RS, RT, 1, 0); +} + +001000,5.RT,5.RS,5.RD,11011001101:POOL32A:32::SUBU_S.QB +"subu_s.qb r, r, r" +*nanomipsdsp: +{ + do_qb_op (SD_, RD, RS, RT, 1, 1); +} + +001000,5.RT,5.RS,5.RD,01101001101:POOL32A:32::SUBUH.QB +"subuh.qb r, r, r" +*nanomipsdsp: +{ + do_uh_qb_op (SD_, RD, RS, RT, 1, 0); +} + +001000,5.RT,5.RS,5.RD,11101001101:POOL32A:32::SUBUH_R.QB +"subuh_r.qb r, r, r" +*nanomipsdsp: +{ + do_uh_qb_op (SD_, RD, RS, RT, 1, 1); +} + +001000,5.RT,7.CONTROL_MASK,01011001111111:POOL32A:32::WRDSP +"wrdsp r":CONTROL_MASK == 1111111111 +"wrdsp r, " +*nanomipsdsp: +{ + do_wrdsp (SD_, RT, CONTROL_MASK); +} diff --git a/sim/mips/nanomipsr6.igen b/sim/mips/nanomipsr6.igen new file mode 100644 index 00000000000..bef5c04c3b3 --- /dev/null +++ b/sim/mips/nanomipsr6.igen @@ -0,0 +1,2744 @@ +// Simulator definition for the nanoMIPS. +// Copyright (C) 2018-2022 Free Software Foundation, Inc. +// Contributed by Imagination Technologies, Ltd. +// Written by Ali Lown +// +// This file is part of GDB, the GNU debugger. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +:compute:::int:U_SHIFT_1BIT:U:(U << 1) +:compute:::int:U_SHIFT_2BIT:U:(U << 2) +:compute:::int:U_SHIFT_3BIT:U:(U << 3) +:compute:::int:U_SHIFT_4BIT:U:(U << 4) +:compute:::int:EU_127:EU:((EU == 127) ? -1 \: EU) +:compute:::int:U_LW4X4:U2,U3:((U3 << 3) | (U2 << 2)) +:compute:::int:AXUIPC_S_LO:S1,S2,S3:((EXTEND32((S3 << 31) | (S2 << 21) | (S1 << 12))) & 0x0000ffff) +:compute:::int:AXUIPC_S_HI:S1,S2,S3:((EXTEND32((S3 << 31) | (S2 << 21) | (S1 << 12))) & 0xffff0000) +:compute:::int:AXUIPC_S:S1,S2,S3:(EXTEND32((S3 << 31) | (S2 << 21) | (S1 << 12))) +:compute:::int:TRD2:RD20,RD21:(compute_gpr2_dest1_reg (SD_, (RD21 << 1 | RD20))) +:compute:::int:TRE2:RD20,RD21:(compute_gpr2_dest2_reg (SD_, (RD21 << 1 | RD20))) +:compute:::int:TRS2:RS4,RS2_0:(compute_gpr4_zero (SD_, (RS4 << 3 | RS2_0))) +:compute:::int:TRT2:RT4,RT2_0:(compute_gpr4_zero (SD_, (RT4 << 3 | RT2_0))) +:compute:::int:TRD2_REV:RD4,RD2_0:(compute_gpr4 (SD_, (RD4 << 3) | RD2_0)) +:compute:::int:TRE2_REV:RE4,RE2_0:(compute_gpr4 (SD_, (RE4 << 3) | RE2_0)) +:compute:::int:TRS2_REV:RS20,RS21:(compute_gpr2_dest1_reg (SD_, (RS21 << 1 | RS20))) +:compute:::int:TRT2_REV:RS20,RS21:(compute_gpr2_dest2_reg (SD_, (RS21 << 1 | RS20))) +:compute:::address_word:ADDRESS8:S1,S2:(nia + EXTEND8((S2 << 7) | (S1 << 1))) +:compute:::address_word:ADDRESS11:S1,S2:(nia + EXTEND11((S2 << 10) | (S1 << 1))) +:compute:::address_word:ADDRESS15:S1,S2:(nia + EXTEND15((S2 << 14) | (S1 << 1))) +:compute:::address_word:ADDRESS21:S1,S2:(nia + EXTEND21((S2 << 20) | (S1 << 1))) +:compute:::address_word:ADDRESS22:S1,S2:(nia + EXTEND22((S2 << 21) | (S1 << 1))) +:compute:::address_word:ADDRESS26:S1,S2:(nia + EXTEND26((S2 << 25) | (S1 << 1))) +:compute:::int:INS_POS:LSB:(LSB) +:compute:::int:INS_SIZE:LSB,MSBD:(1 + MSBD - LSB) +:compute:::address_word:ADDRESS12:S1,S2:(nia + EXTEND12(S2 << 11 | S1 << 1)) +:compute:::int:S_14_BIT:S1,S2:(EXTEND14 ((S1 << 13) | S2)) +:compute:::int:S_4_BIT:S1,S2:(EXTEND4((S1 << 3) | S2)) +:compute:::int:S_9_BIT:S1,S2:(EXTEND9((S1 << 8) | S2)) +:compute:::int:S_9_BIT_LLSC:S1,S2:(EXTEND9((S1 << 8) | (S2 << 2))) +:compute:::int:RD1:RD:(compute_gpr1_dest_reg (SD_, RD)) +:compute:::int:RT_5_BIT_NM_Z:RT1,RT2:(compute_gpr4_zero (SD_, (RT1 << 3) | RT2)) +:compute:::int:RT_5_BIT_NM:RT1,RT2:(compute_gpr4 (SD_, (RT1 << 3) | RT2)) +:compute:::int:RS_5_BIT_NM:RS1,RS2:(compute_gpr4 (SD_, (RS1 << 3) | RS2)) +:compute:::int:TRTZ:RTZ:((RTZ >= 1 && RTZ <= 3) ? (16 + RTZ) \: RTZ) +:compute:::int:EU_12_13:EU:((EU == 12) ? 255 \: ((EU == 13) ? 65535 \: EU)) +:compute:::int:RS_MOVE:RS1,RS_CODE_1,RS_CODE_2:((RS1 << 3) | (RS_CODE_1 << 2) | RS_CODE_2) +:compute:::int:CODE_BREAK:RS_CODE_1,RS_CODE_2:((RS_CODE_1 << 2) | RS_CODE_2) +:compute:::int:TRD_NM:RD:((RD < 4) ? (16 + RD) \: RD) +:compute:::int:TRS_NM:RS:((RS < 4) ? (16 + RS) \: RS) +:compute:::int:TRT_NM:RT:((RT < 4) ? (16 + RT) \: RT) +:compute:::int:COUNT:COUNT3:(COUNT3 == 0 ? 8 \: COUNT3) +:compute:::int:SHIFTX_1BIT:SHIFTX:(SHIFTX << 1) + +:function:::void:do_msubf:int fd, int fs, int ft, int fmt, instruction_word instruction_0 +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + check_fmt_p (SD_, fmt, instruction_0); + TRACE_ALU_INPUT3 (FGR[fd], FGR[fs], FGR[ft]); + StoreFPR (fd, fmt, FusedMultiplySub (ValueFPR (fs, fmt), + ValueFPR (ft, fmt), + ValueFPR (fd, fmt), fmt)); + TRACE_ALU_RESULT (FGR[fd]); +} + +:function:::void:do_maddf:int fd, int fs, int ft, int fmt, instruction_word instruction_0 +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + check_fmt_p (SD_, fmt, instruction_0); + TRACE_ALU_INPUT3 (FGR[fd], FGR[fs], FGR[ft]); + StoreFPR (fd, fmt, FusedMultiplyAdd (ValueFPR (fs, fmt), + ValueFPR (ft, fmt), + ValueFPR (fd, fmt), fmt)); + TRACE_ALU_RESULT (FGR[fd]); +} + +:function:::void:do_rint:int fd, int fs, int fmt, instruction_word instruction_0 +{ + uint64_t result = 0; + check_fpu (SD_); + check_u64 (SD_, instruction_0); + check_fmt_p (SD_, fmt, instruction_0); + TRACE_ALU_INPUT1 (FGR[fs]); + RoundToIntegralExact (ValueFPR (fs, fmt), &result, fmt); + StoreFPR (fd, fmt, result); + TRACE_ALU_RESULT (FGR[fd]); +} + +:function:::void:do_class:int fd, int fs, int fmt, instruction_word instruction_0 +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + check_fmt_p (SD_, fmt, instruction_0); + StoreFPR (fd, fmt, Classify (ValueFPR (fs, fmt), fmt)); +} + +:function:::void:do_seleqzf:int fd, int fs, int ft, int fmt, instruction_word instruction_0 +{ + check_fpu (SD_); + check_fmt_p (SD_, fmt, instruction_0); + TRACE_ALU_INPUT2 (ValueFPR(fs, fmt), FGR[ft]); + if ((FGR[ft] & 0x01) == 0) + StoreFPR (fd, fmt, ValueFPR (fs, fmt)); + else + StoreFPR (fd, fmt, 0); + TRACE_ALU_RESULT (ValueFPR(fd, fmt)); +} + +:function:::void:do_selnezf:int fd, int fs, int ft, int fmt, instruction_word instruction_0 +{ + check_fpu (SD_); + check_fmt_p (SD_, fmt, instruction_0); + TRACE_ALU_INPUT2 (ValueFPR(fs, fmt), FGR[ft]); + if ((FGR[ft] & 0x01) == 0x1) + StoreFPR (fd, fmt, ValueFPR (fs, fmt)); + else + StoreFPR (fd, fmt, 0); + TRACE_ALU_RESULT (ValueFPR(fd, fmt)); +} + +:function:::void:do_self:int fd, int fs, int ft, int fmt, instruction_word instruction_0 +{ + check_fpu (SD_); + check_fmt_p (SD_, fmt, instruction_0); + TRACE_ALU_INPUT3 (FGR[fd], ValueFPR(fs, fmt), ValueFPR(ft, fmt)); + if ((FGR[fd] & 0x01) != 0) + StoreFPR (fd, fmt, ValueFPR (ft, fmt)); + else + StoreFPR (fd, fmt, ValueFPR (fs, fmt)); + TRACE_ALU_RESULT (ValueFPR(fd, fmt)); +} + +:function:::void:do_mina:int fd, int fs, int ft, int fmt, instruction_word instruction_0 +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + check_fmt_p (SD_, fmt, instruction_0); + TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]); + StoreFPR (fd, fmt, MinA (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt)); + TRACE_ALU_RESULT (FGR[fd]); +} + +:function:::void:do_maxa:int fd, int fs, int ft, int fmt, instruction_word instruction_0 +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + check_fmt_p (SD_, fmt, instruction_0); + TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]); + StoreFPR (fd, fmt, MaxA (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt)); + TRACE_ALU_RESULT (FGR[fd]); +} + +:function:::void:do_max:int fd, int fs, int ft, int fmt, instruction_word instruction_0 +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + check_fmt_p (SD_, fmt, instruction_0); + TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]); + StoreFPR (fd, fmt, Max (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt)); + TRACE_ALU_RESULT (FGR[fd]); +} + +:function:::void:do_min:int fd, int fs, int ft, int fmt, instruction_word instruction_0 +{ + check_fpu (SD_); + check_u64 (SD_, instruction_0); + check_fmt_p (SD_, fmt, instruction_0); + TRACE_ALU_INPUT2 (FGR[fs], FGR[ft]); + StoreFPR (fd, fmt, Min (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt)); + TRACE_ALU_RESULT (FGR[fd]); +} + +:function:::void:do_cmp:int fd, int fs, int ft, int fmt, int condition +{ + uint64_t result; + check_fpu (SD_); + TRACE_ALU_INPUT2 (ValueFPR (fs, fmt), ValueFPR (ft, fmt)); + result = R6Compare (ValueFPR (fs, fmt), ValueFPR (ft, fmt), fmt, condition); + StoreFPR (fd, fmt, result); + TRACE_ALU_RESULT (result); +} + +:function:::void:do_modu:int rd, int rs, int rt +{ + uint32_t n = GPR[rs]; + uint32_t d = GPR[rt]; + TRACE_ALU_INPUT2 (n,d); + if (d == 0) + GPR[rd] = EXTEND32 (0); + else + GPR[rd] = EXTEND32 (n % d); + + TRACE_ALU_RESULT (GPR[rd]); +} + +:function:::void:do_mod:int rd, int rs, int rt +{ + int32_t n = GPR[rs]; + int32_t d = GPR[rt]; + TRACE_ALU_INPUT2 (n,d); + if (d == 0 || (n == SIGNED32 (0x80000000) && d == -1)) + GPR[rd] = EXTEND32 (0); + else + GPR[rd] = EXTEND32 (n % d); + + TRACE_ALU_RESULT (GPR[rd]); +} + +:function:::void:do_muhu:int rd, int rs, int rt +{ + uint64_t prod; + if (NotWordValue (GPR[rs]) || NotWordValue (GPR[rt])) + Unpredictable (); + TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]); + prod = ((uint64_t)(uint32_t) GPR[rs]) + * ((uint64_t)(uint32_t) GPR[rt]); + GPR[rd] = EXTEND32 (VH4_8 (prod)); + TRACE_ALU_RESULT (GPR[rd]); +} + +:function:::void:do_mulu:int rd, int rs, int rt +{ + uint64_t prod; + if (NotWordValue (GPR[rs]) || NotWordValue (GPR[rt])) + Unpredictable (); + TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]); + prod = ((uint64_t)(uint32_t) GPR[rs]) + * ((uint64_t)(uint32_t) GPR[rt]); + GPR[rd] = EXTEND32 (VL4_8 (prod)); + TRACE_ALU_RESULT (GPR[rd]); +} + +:function:::void:do_muh:int rd, int rs, int rt +{ + int64_t prod; + if (NotWordValue (GPR[rs]) || NotWordValue (GPR[rt])) + Unpredictable (); + TRACE_ALU_INPUT2 (GPR[rs], GPR[rt]); + prod = ((int64_t)(int32_t) GPR[rs]) + * ((int64_t)(int32_t) GPR[rt]); + GPR[rd] = EXTEND32 (VH4_8 (prod)); + TRACE_ALU_RESULT (GPR[rd]); +} + +:function:::void:do_lsa:int rd, int rs, int rt, unsigned immediate +{ + uint32_t t = GPR[rs] << immediate; + GPR[rd] = EXTEND32(GPR[rt] + t); + TRACE_ALU_RESULT (GPR[rd]); +} + +:function:::void:do_divu:int rd, int rs, int rt +*nanomips32r6: +*nanomips64r6: +{ + uint32_t n = GPR[rs]; + uint32_t d = GPR[rt]; + TRACE_ALU_INPUT2 (n,d); + if (d == 0) + GPR[rd] = EXTEND32 (0x80000000); + else + GPR[rd] = EXTEND32 (n / d); + + TRACE_ALU_RESULT (GPR[rd]); +} + +:function:::void:do_div:int rd, int rs, int rt +*nanomips32r6: +*nanomips64r6: +{ + int32_t n = GPR[rs]; + int32_t d = GPR[rt]; + TRACE_ALU_INPUT2 (n,d); + if (d == 0) + GPR[rd] = EXTEND32 (0x80000000); + else if (n == SIGNED32 (0x80000000) && d == -1) + GPR[rd] = EXTEND32 (0x80000000); + else + GPR[rd] = EXTEND32 (n / d); + + TRACE_ALU_RESULT (GPR[rd]); +} + +:function:::void:do_llwp:int rt, int ru, int roffset, int rbase +{ + address_word base = GPR[rbase]; + address_word offset = EXTEND16 (roffset); + { + address_word vaddr = loadstore_ea (SD_, base, offset); + address_word paddr = vaddr; + int uncached; + if ((vaddr & 7) != 0) + { + SIM_CORE_SIGNAL (SD, CPU, cia, read_map, 8, vaddr, read_transfer, + sim_core_unaligned_signal); + } + else + { + uint64_t memval = 0; + uint64_t memval1 = 0; + uint64_t data = memval; + + LoadMemory (&memval, &memval1, AccessLength_DOUBLEWORD, paddr, + vaddr, isDATA, isREAL); + + GPR[rt] = EXTEND32 (data & 0xFFFFFFFF); + GPR[ru] = EXTEND32 (data >> 32); + + LLBIT = 1; + COP0_COUNT++; + } + } +} + +:function:::void:do_rotx:int rt, int rs, int shift, int shiftx, int stripe +{ + int i; + uint64_t tmp0 = ((uint64_t)GPR[rs] << 32) | (GPR[rs] & 0xFFFFFFFF); + uint64_t tmp1, tmp2, tmp3, tmp4, tmp5; + + tmp1 = tmp0; + for (i = 0; i <=46; i++) { + int s; + + if (i & 0x8) + s = shift; + else + s = shiftx; + + if (stripe != 0 && !(i & 0x4)) + s = ~s; + + if (s & 0x10) { + if (tmp0 & (1LL << (i + 16))) + tmp1 |= 1LL << i; + else + tmp1 &= ~(1LL << i); + } + } + + tmp2 = tmp1; + for (i = 0; i <=38; i++) { + int s; + + if (i & 0x4) + s = shift; + else + s = shiftx; + + if (s & 0x8) { + if (tmp1 & (1LL << (i + 8))) + tmp2 |= 1LL << i; + else + tmp2 &= ~(1LL << i); + } + } + + tmp3 = tmp2; + for (i = 0; i <=34; i++) { + int s; + + if (i & 0x2) + s = shift; + else + s = shiftx; + + if (s & 0x4) { + if (tmp2 & (1LL << (i + 4))) + tmp3 |= 1LL << i; + else + tmp3 &= ~(1LL << i); + } + } + + tmp4 = tmp3; + for (i = 0; i <=32; i++) { + int s; + + if (i & 0x1) + s = shift; + else + s = shiftx; + + if (s & 0x2) { + if (tmp3 & (1LL << (i + 2))) + tmp4 |= 1LL << i; + else + tmp4 &= ~(1LL << i); + } + } + + tmp5 = tmp4; + for (i = 0; i <=31; i++) { + int s; + + s = shift; + + if (s & 0x1) { + if (tmp4 & (1LL << (i + 1))) + tmp5 |= 1LL << i; + else + tmp5 &= ~(1LL << i); + } + } + + GPR[rt] = EXTEND32 (tmp5); +} + +:function:::void:do_lwc1xs:int ft, int rbase, int roffset +*nanomips32r6: +*nanomips64r6: +{ + check_fpu (SD_); + COP_LW (1, ft, do_load (SD_, AccessLength_WORD, GPR[rbase] << 2, + GPR[roffset])); +} + +:function:::void:do_lwpc_nanomips:int rt, uint32_t offset, address_word nia +*nanomips32r6: +*nanomips64r6: +{ + check_fpu (SD_); + GPR[rt] = EXTEND32 (do_load (SD_, AccessLength_WORD, nia, offset)); +} + +:function:::void:check_nms_flag: +*nanomips32r6: +*nanomips64r6: +{ + if(nms_flag == 0) + sim_engine_abort (SD, CPU, CIA, "Error: NMS instruction generated\ + (nanoMIPS Subset is disabled - use -march=32r6s option)\n"); +} + +:function:::uint32_t:compute_gpr2_dest1_reg:int reg +*nanomips32r6: +*nanomips64r6: +{ + switch(reg) + { + case 0: return 4; + case 1: return 5; + case 2: return 6; + case 3: return 7; + default: return 4; + } +} + +:function:::uint32_t:compute_gpr4_zero:int reg +*nanomips32r6: +*nanomips64r6: +{ + if (reg == 3) return 0; + else if (reg >=4 && reg <= 7) return reg; + else return reg + 8; +} + +:function:::uint32_t:compute_gpr4:int reg +*nanomips32r6: +*nanomips64r6: +{ + if (reg >=4 && reg <= 7) return reg; + else return reg + 8; +} + +:function:::uint32_t:compute_gpr2_dest2_reg:int reg +*nanomips32r6: +*nanomips64r6: +{ + switch(reg) + { + case 0: return 5; + case 1: return 6; + case 2: return 7; + case 3: return 8; + default: return 5; + } +} + +:function:::uint32_t:compute_gpr1_dest_reg:int reg +*nanomips32r6: +*nanomips64r6: +{ + switch(reg) + { + case 0: return 4; + case 1: return 5; + default: return 4; + } +} + +:function:::unsigned:zero_extend:signed_word value, uint32_t from_nbits +{ + uint32_t low_bits_mask = (1 << from_nbits) - 1; + return value & low_bits_mask; +} + +:function:::void:do_save_gprs_to_stack_and_adjust_sp: int first_gpr, int count, int gp, int u +*nanomips32r6: +*nanomips64r6: +{ + int counter = 0; + + while (counter != count) { + int gpr = (first_gpr & 0x10) | ((first_gpr + counter) & 0x1F); + int offset = - ( (counter + 1) << 2 ); + + if ( gp && (counter == count - 1)) + gpr = 28; + + do_store (SD_, AccessLength_WORD, GPR[SPIDX], offset, GPR[gpr]); + + counter++; + COP0_COUNT++; + } + + GPR[SPIDX] -= u; +} + +:function:::void:do_restore_gprs_from_stack_and_adjust_sp: int first_gpr, int count, int gp, int u +*nanomips32r6: +*nanomips64r6: +{ + int counter = 0; + + while (counter != count) { + int gpr = (first_gpr & 0x10) | ((first_gpr + counter) & 0x1F); + int offset; + + if (gpr == 29) + Unpredictable(); + + offset = u - ((counter + 1) << 2); + + if ( gp && (counter == count - 1)) + gpr = 28; + + GPR[gpr] = EXTEND32 (do_load(SD_, AccessLength_WORD, GPR[SPIDX], offset)); + + counter++; + COP0_COUNT++; + } + + GPR[SPIDX] += u; +} + +:function:::address_word:do_eret:int nc, address_word nia +*nanomips32r6: +*nanomips64r6: +{ + if (SR & status_ERL) + { + /* Oops, not yet available */ + sim_io_printf (SD, "Warning: ERET when SR[ERL] set not supported"); + nia = EPC; + SR &= ~status_ERL; + } + else + { + nia = EPC; + SR &= ~status_EXL; + //if ( SRSCtl.HSS > 0 && Status.BEV == 0) + // SRSCtl.CSS = SRSCtl.PSS + } + + if (!nc) + LLBIT = 0; + + //TODO: ClearHazards() + return nia; +} + +:%s::::GPR_LIST_SAVE:int count +*nanomips32r6: +*nanomips64r6: +{ + int i; + static char gpr_list[100]; + + gpr_list[0] = '\0'; + + i = 0; + + while (i 1) + strcat (gpr_list,"-"); + } + i++; + } + return (gpr_list); +} + +:function:::void:do_break_nanomips:address_word instruction_0 +{ + /* Check for some break instruction which are reserved for use by the + simulator. */ + unsigned int break_code = instruction_0 & HALT_INSTRUCTION_MASK_NANOMIPS; + if (break_code == (HALT_INSTRUCTION_NANOMIPS & HALT_INSTRUCTION_MASK_NANOMIPS)) + { + sim_engine_halt (SD, CPU, NULL, cia, + sim_exited, (unsigned int)(A0 & 0xFFFFFFFF)); + } + else if (break_code == (BREAKPOINT_INSTRUCTION_NANOMIPS & HALT_INSTRUCTION_MASK_NANOMIPS)) + { + PC = cia; + SignalException (BreakPoint, instruction_0); + } + + else + { + /* If we get this far, we're not an instruction reserved by the sim. Raise + the exception. */ + SignalException (BreakPoint, instruction_0); + } +} + +:%s::::GP_SAVE:int gp +*nanomips32r6: +*nanomips64r6: +{ + return (gp > 0) ? "gp" : ""; +} + +:%s::::FP_SAVE:int fp +*nanomips32r6: +*nanomips64r6: +{ + return (fp > 0) ? "fp" : ""; +} + +11111111111111111111111111111111:R6DUMMY:32,f::DUMMY0.fmt +"dummy 0" +*nanomips32r6: +*nanomips64r6: +{ + /* Just needed so GNUSIM builds */ +} + +011100,3.RT,1,6.U:R6P16A1:16::ADDIUR1SP +"addiu r, SP, " +*nanomips32r6: +*nanomips64r6: +{ + do_addiu (SD_, SPIDX, TRT_NM, U_SHIFT_2BIT); +} + +100100,3.RT,3.RS,0,3.U:R6P16A2:16::ADDIUR2 +"addiu r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_addiu (SD_, TRS_NM, TRT_NM, U_SHIFT_2BIT); +} + +100100,5.RT,1.S1,1,3.S2:R6P16ADDIURS5:16::ADDIURS5 +"nop":RT==0 +"addiu r, " +*nanomips32r6: +*nanomips64r6: +{ + if (RT != 0) + do_addiu (SD_, RT, RT, S_4_BIT); +} + +000001,5.RT,20.S1,1.S2:R6P32:32::ADDIUPC +"addiu r, " +*nanomips32r6: +*nanomips64r6: +{ + GPR[RT] = ADDRESS22; +} + +011000,5.RT,00011,16.IMM48:R6POOL48I:32::ADDIUPC48 +"addiu r, " +*nanomips32r6: +*nanomips64r6: +{ + uint16_t U2; + uint32_t total; + check_nms_flag (SD_); + U2 = do_load (SD_, AccessLength_HALFWORD, CIA + 4, 0); + total = U2 << 16 | IMM48; + TRACE_ALU_INPUT2(GPR[RT], total); + GPR[RT] = CIA + 6 + EXTEND32(total); + TRACE_ALU_RESULT(GPR[RT]); + NIA = CIA + 6; +} + +101100,3.RT,3.RS,3.RD,0:R6P16ADDU:16::ADDU16 +"addu r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_addu (SD_, TRS_NM, TRT_NM, TRD_NM); +} + +001111,1.RT1,0,3.RT2,1.RS1,0,3.RS2:R6P164X4:16::ADDU4X4 +"addu r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_addu (SD_, RS_5_BIT_NM, RT_5_BIT_NM, RT_5_BIT_NM); +} + +010100,3.RT,3.RS,10,0,0:R6POOL16C00:16::AND16 +"and r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_and (SD_, TRS_NM, TRT_NM, TRT_NM); +} + +111100,3.RT,3.RS,4.EU:R6P16:16::ANDI16 +"andi r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_andi (SD_, TRS_NM, TRT_NM, EU_12_13); +} + +001110,9.S1,1.S2:R6P16:16::BALC16 +"balc " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT1(RA); + RA = NIA; + NIA = ADDRESS11; + TRACE_ALU_RESULT(RA); + + // For cycle counting + COP0_COUNT++; +} + +000110,9.S1,1.S2:R6P16:16::BC16 +"bc " +*nanomips32r6: +*nanomips64r6: +{ + NIA = ADDRESS11; +} + +110110,3.RT,3.RS,4.U!0:R6P16BR1:16::BxxC16 +"beqc r, r, ":RS, r, " +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + TRACE_ALU_INPUT2(GPR[TRS_NM], GPR[TRT_NM]); + if (RS < RT && GPR[TRS_NM] == GPR[TRT_NM]) + NIA = NIA + U_SHIFT_1BIT; //BEQC + else if (RS >= RT && GPR[TRS_NM] != GPR[TRT_NM]) + NIA = NIA + U_SHIFT_1BIT; //BNEC +} + +100110,3.RT,6.S1,1.S2:R6P16:16::BEQZC16 +"beqzc r, " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT1(GPR[TRT_NM]); + if(GPR[TRT_NM] == 0) + NIA = ADDRESS8; +} + +101110,3.RT,6.S1,1.S2:R6P16:16::BNEZC16 +"bnezc r, " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT1(GPR[TRT_NM]); + if(GPR[TRT_NM] != 0) + NIA = ADDRESS8; +} + +110110,5.RT,1,0000:R6P16JRC:16::JALRC16 +"jalrc r" +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RT], RA); + RA = NIA; + NIA = GPR[RT]; + TRACE_ALU_RESULT(RA); + + // For cycle counting + COP0_COUNT++; +} + +110110,5.RT,0,0000:R6P16JRC:16::JRC16 +"jrc r" +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT1(GPR[RT]); + NIA = GPR[RT]; +} + +010111,3.RT,3.RS,00,2.U:R6P16LB:16::LB16 +"lb r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lb (SD_, TRT_NM, U, TRS_NM); +} + +010111,3.RT,3.RS,10,2.U:R6P16LB:16::LBU16 +"lbu r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2 (U, GPR[TRS_NM]); + do_lbu (SD_, TRT_NM, U, TRS_NM); + TRACE_ALU_RESULT (GPR[TRT_NM]); +} + +011111,3.RT,3.RS,0,2.U,0:R6P16LH:16::LH16 +"lh r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lh (SD_, TRT_NM, U_SHIFT_1BIT, TRS_NM); +} + +011111,3.RT,3.RS,1,2.U,0:R6P16LH:16::LHU16 +"lhu r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lhu (SD_, TRT_NM, U_SHIFT_1BIT, TRS_NM); +} + +110100,3.RT,7.EU:R6P16:16::LI16 +"li r, " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT1(GPR[TRT_NM]); + GPR[TRT_NM] = EU_127; + TRACE_ALU_RESULT(GPR[TRT_NM]); +} + +011101,1.RT1,1.U2,3.RT2,1.RS1,1.U3,3.RS2:R6P16:16::LW4X4 +"lw r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_lw (SD_, RT_5_BIT_NM, U_LW4X4, RS_5_BIT_NM); +} + +000101,3.RT,3.RS,4.U:R6P16:16::LW16 +"lw r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lw (SD_, TRT_NM, U_SHIFT_2BIT, TRS_NM); +} + +010101,3.RT,7.U:R6P16:16::LWGP16 +"lw r, (gp)" +*nanomips32r6: +*nanomips64r6: +{ + do_lw (SD_, TRT_NM, U_SHIFT_2BIT, GPIDX); +} + +001101,5.RT,5.U:R6P16:16::LWSP +"lw r, (sp)" +*nanomips32r6: +*nanomips64r6: +{ + do_lw (SD_, RT, U_SHIFT_2BIT, SPIDX); +} + +010100,3.RT,3.RS,3.RD,1:R6P16C:16::LWXS16 +"lwxs r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lw (SD_, TRD_NM, GPR[TRS_NM] << 2, TRT_NM); +} + +// These four instructions are grouped together because of a bug in GNUSIM +// pattern recognition +000100,5.RT,2.RS1,1.RS_CODE_1,2.RS_CODE_2:R6P16MOVE:16::P16MOVE_P16RI +"move r, r": RT != 0 +"syscall ": RS1 == 1 +"sdbbp ": RS1 == 3 +"break " +*nanomips32r6: +*nanomips64r6: +{ + if (RT == 0) { + if (RS1 == 1) + SignalException (SystemCall, instruction_0); + else if (RS1 == 3) + SignalException (DebugBreakPoint, instruction_0); + else + do_break_nanomips (SD_, instruction_0); + } + else { + TRACE_ALU_INPUT2 (GPR[RT], GPR[RS_MOVE]); + GPR[RT] = GPR[RS_MOVE]; + TRACE_ALU_RESULT2 (GPR[RT], GPR[RS_MOVE]); + } +} + +101111,1.RT4,1.RD20,3.RT2_0,1.RS4,1.RD21,3.RS2_0:R6P16:16::MOVEP +"movep r, r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + TRACE_ALU_INPUT4 (GPR[TRD2], GPR[TRE2], GPR[TRS2], GPR[TRT2]); + GPR[TRD2] = GPR[TRS2]; + GPR[TRE2] = GPR[TRT2]; + TRACE_ALU_RESULT2 (GPR[TRD2], GPR[TRE2]); + + // For cycle counting + COP0_COUNT++; +} + +111111,1.RE4,1.RS20,3.RE2_0,1.RD4,1.RS21,3.RD2_0:R6P16:16::MOVEPREV +"movep r, r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + TRACE_ALU_INPUT4 (GPR[TRD2_REV], GPR[TRE2_REV], GPR[TRS2_REV], GPR[TRT2_REV]); + GPR[TRD2_REV] = GPR[TRS2_REV]; + GPR[TRE2_REV] = GPR[TRT2_REV]; + TRACE_ALU_RESULT2 (GPR[TRD2_REV], GPR[TRE2_REV]); + + // For cycle counting + COP0_COUNT++; +} + +010100,3.RT,3.RS,00,0,0:R6POOL16C00:16::NOT16 +"not r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_nor (SD_, 0, TRS_NM, TRT_NM); +} + +010100,3.RT,3.RS,11,0,0:R6POOL16C00:16::OR16 +"or r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_or (SD_, TRS_NM, TRT_NM, TRT_NM); +} + +000111,1.RT1,1,4.U,4.GPR_LIST_SAVE:R6P16SR:16::RESTORE.JRC16 +"restore.jrc ":GPR_LIST_SAVE==15 +"restore.jrc , ra, %s" +*nanomips32r6: +*nanomips64r6: +{ + if (RT1 == 0) + do_restore_gprs_from_stack_and_adjust_sp(SD_, 30, GPR_LIST_SAVE, 0, + U_SHIFT_4BIT); + else + do_restore_gprs_from_stack_and_adjust_sp(SD_, 31, GPR_LIST_SAVE, 0, + U_SHIFT_4BIT); + NIA = RA; +} + +000111,1.RT1,0,4.U,4.GPR_LIST_SAVE:R6P16SR:16::SAVE16 +"save , ra": GPR_LIST_SAVE == 0 +"save , ra, %s" +*nanomips32r6: +*nanomips64r6: +{ + if (RT1 == 0) + do_save_gprs_to_stack_and_adjust_sp(SD_, 30, GPR_LIST_SAVE, 0, U_SHIFT_4BIT); + else + do_save_gprs_to_stack_and_adjust_sp(SD_, 31, GPR_LIST_SAVE, 0, U_SHIFT_4BIT); + +} + +010111,3.RTZ,3.RS,01,2.U:R6P16LB:16::SB16 +"sb r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_BYTE, GPR[TRS_NM], U, GPR[TRTZ]); +} + +011111,3.RTZ,3.RS,0,2.U,1:R6P16LH:16::SH16 +"sh r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_HALFWORD, GPR[TRS_NM], U_SHIFT_1BIT, GPR[TRTZ]); +} + +001100,3.RT,3.RS,0,3.SHIFT:R6P16SHIFT:16::SLL16 +"sll r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_sll (SD_, TRS_NM, TRT_NM, SHIFT_DEC); +} + +001100,3.RT,3.RS,1,3.SHIFT:R6P16SHIFT:16::SRL16 +"srl r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_srl (SD_, TRS_NM, TRT_NM, SHIFT_DEC); +} + +101100,3.RT,3.RS,3.RD,1:R6P16ADDU:16::SUBU16 +"subu r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_subu (SD_, TRS_NM, TRT_NM, TRD_NM); +} + +100101,3.RTZ,3.RS,4.U:R6P16:16::SW16 +"sw r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_WORD, GPR[TRS_NM], U_SHIFT_2BIT, GPR[TRTZ]); +} + +101101,5.RT,5.U:R6P16:16::SWSP +"sw r, (sp)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_WORD, SP, U_SHIFT_2BIT, GPR[RT]); +} + +010100,3.RT,3.RS,01,0,0:R6POOL16C00:16::XOR16 +"xor r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_xor (SD_, TRT_NM, TRS_NM, TRT_NM); +} + +// 32-bit instructions + +001000,5.RT,5.RS,5.RD,1.X,0100010,000:R6POOL32A0:32::ADD +"add r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_add (SD_, RS, RT, RD); +} + +000000,5.RT!0,5.RS,16.U:R6PPADDIU:32::ADDIU +"addiu r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_addiu (SD_, RS, RT, U); +} + +010001,5.RT,011,18.U:R6PGPBH:32::ADDIUGPB +"addiu r, GP, " +*nanomips32r6: +*nanomips64r6: +{ + do_addiu (SD_, GPIDX, RT, U); +} + +010000,5.RT,19.U,00:R6PGPW:32::ADDIUGPW +"addiu r, GP, " +*nanomips32r6: +*nanomips64r6: +{ + do_addiu (SD_, GPIDX, RT, U_SHIFT_2BIT); +} + +111000,5.RT,9.S1,10.S2,1,1.S3:R6PLUI:32::ALUIPC +"aluipc r, " +*nanomips32r6: +*nanomips64r6: +{ + address_word address = NIA + AXUIPC_S; + + TRACE_ALU_INPUT2(GPR[RT], address); + GPR[RT] = address & ~0xfff; + TRACE_ALU_RESULT(GPR[RT]); +} + +001000,5.RT,5.RS,5.RD,1.X,0101010,000:R6POOL32A0:32::ADDU +"addu r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_addu (SD_, RS, RT, RD); +} + +001000,5.RT,5.RS,5.RD,5.IMMEDIATE,011,111:R6POOL32A0:32::EXTW +"prepend r, r, ": RD == RS +"align r, r, r, ": IMMEDIATE != 0 +"extw r, r, r, " +*nanomips32r6: +*nanomips64r6: +{ + if (IMMEDIATE != 0) { + uint64_t tmp = ((uint64_t)GPR[RT] << 32) | (0xffffffff & GPR[RS]); + TRACE_ALU_INPUT4 (GPR[RD], GPR[RS], GPR[RT], tmp); + GPR[RD] = EXTEND32 (tmp >> IMMEDIATE); + TRACE_ALU_RESULT (GPR[RD]); + } else { + TRACE_ALU_INPUT2 (GPR[RD], GPR[RT]); + GPR[RD] = GPR[RT]; + TRACE_ALU_RESULT (GPR[RD]); + } +} + +001000,5.RT,5.RS,5.RD,1.X,1001010,000:R6POOL32A0:32::AND +"and r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_and (SD_, RS, RT, RD); +} + +100000,5.RT,5.RS,0010,12.U:R6PU12:32::ANDI +"andi r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_andi (SD_, RS, RT, U); +} + +001010,1,24.S1,1.S2:R6PBAL:32::BALC +"balc " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT1(RA); + RA = NIA; + NIA = ADDRESS26; + TRACE_ALU_RESULT(RA); + + // For cycle counting + COP0_COUNT++; +} + +001010,0,24.S1,1.S2:R6PBAL:32::BC +"bc " +*nanomips32r6: +*nanomips64r6: +{ + NIA = ADDRESS26; +} + +100010,5.RT,5.RS,00,13.S1,1.S2:R6PBR1:32::BEQC +"beqc r, r, " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RS], GPR[RT]); + if (GPR[RS] == GPR[RT]) + NIA = ADDRESS15; +} + +110010,5.RT,000,7.U,10.S1,1.S2:P7PBRI:32::BEQIC +"beqic r, , " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RT], U); + if (GPR[RT] == U) { + NIA = ADDRESS12; + } +} + +100010,5.RT,5.RS,10,13.S1,1.S2:P7PBR1:32::BGEC +"bgec r, r, " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RS], GPR[RT]); + if ((signed_word) GPR[RS] >= (signed_word) GPR[RT]) + NIA = ADDRESS15; +} + +110010,5.RT,010,7.U,10.S1,1.S2:P7PBRI:32::BGEIC +"bgeic r, , " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RT], U); + if ((signed_word) GPR[RT] >= U) { + NIA = ADDRESS12; + } +} + +100010,5.RT,5.RS,11,13.S1,1.S2:P7PBR2:32::BGEUC +"bgeuc r, r, " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RS], GPR[RT]); + if ((unsigned_word) (GPR[RS]) >= (unsigned_word)(GPR[RT])) { + NIA = ADDRESS15; + } +} + +110010,5.RT,011,7.U,10.S1,1.S2:P7PBRI:32::BGEUIC +"bgeuic r, , " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RT], U); + if ((unsigned_word) GPR[RT] >= U) { + NIA = ADDRESS12; + } +} + +101010,5.RT,5.RS,10,13.S1,1.S2:P7PBR2:32::BLTC +"bltc r, r, " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RS], GPR[RT]); + if ((signed_word) GPR[RS] < (signed_word) GPR[RT]) + NIA = ADDRESS15; +} + +110010,5.RT,110,7.U,10.S1,1.S2:P7PBRI:32::BLTIC +"bltic r, , " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RT], U); + if ((signed_word) GPR[RT] < U) { + NIA = ADDRESS12; + } +} + +101010,5.RT,5.RS,11,13.S1,1.S2:P7PBR2:32::BLTUC +"bltuc r, r, " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RS], GPR[RT]); + if ((unsigned_word) GPR[RS] < (unsigned_word) GPR[RT]) { + NIA = ADDRESS15; + } +} + +110010,5.RT,111,7.U,10.S1,1.S2:P7PBRI:32::BLTIUC +"bltiuc , , " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RT], U); + if ((unsigned_word) GPR[RT] < U) { + NIA = ADDRESS12; + } +} + +101010,5.RT,5.RS,00,13.S1,1.S2:R6PBR2:32::BNEC +"bnec r, r, " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RS], GPR[RT]); + if (GPR[RS] != GPR[RT]) + NIA = ADDRESS15; +} + +110010,5.RT,100,7.U,10.S1,1.S2:R6PBRI:32::BNEIC +"bneic r, , " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RT], U); + if (GPR[RT] != U) { + NIA = ADDRESS12; + } +} + +000000,00000,10,19.CODE:R6PRI:32::BREAK +"break %#lx" +*nanomips32r6: +*nanomips64r6: +{ + do_break_nanomips (SD_, instruction_0); +} + +101001,5.OP,5.RS,1.S1,0111,0,01,8.S2:R6PLSS1:32::CACHE +"cache , (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_cache (SD_, OP, RS, S_9_BIT, instruction_0); +} + +001000,5.RT,5.RS,0100101,100,111,111:R6POOL32AXF4:32::CLO +"clo r, r" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_clo (SD_, RT, RS); +} + +001000,5.RT,5.RS,0101101,100,111,111:R6POOL32AXF4:32::CLZ +"clz r, r" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_clz (SD_, RT, RS); +} + +001000,5.RT,5.X,01,00011,101,111,111:R6POOL32AXF5GROUP1:32::DI +"di":RT == 0 +"di r" +*nanomips32r6: +*nanomips64r6: +{ + do_di (SD_, RT); +} + +001000,5.RT,5.RS,5.RD,1.X,0100011,000:R6POOL32A0:32::DIV +"div r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_div (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,5.RD,1.X,0110011,000:R6POOL32A0:32::DIVU +"divu r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_divu (SD_, RD, RS, RT); +} + +001000,5.RT,5.X,01,01011,101,111,111:R6POOL32AXF5GROUP1:32::EI +"ei":RT == 0 +"ei r" +*nanomips32r6: +*nanomips64r6: +{ + do_ei (SD_, RT); +} + +001000,9.X,0,11,11001,101,111,111:R6ERETX:32::ERET +"eret" +*nanomips32r6: +*nanomips64r6: +{ + NIA = do_eret(SD_, 0, NIA); +} + +001000,9.X,1,11,11001,101,111,111:R6ERETX:32::ERETNC +"eretnc" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + SignalException (ReservedInstruction, instruction_0); + NIA = do_eret(SD_, 1, NIA); +} + +100000,5.RT,5.RS,1111,0,5.MSBD,0,5.LSB:R6PEXT:32::EXT +"ext r, r, , " +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + if (LSB + MSBD + 1 > 32) + Unpredictable (); + + do_ext (SD_, RT, RS, LSB, MSBD); +} + +100000,5.RT,5.RS,1110,0,5.MSBD,0,5.LSB:R6PINS:32::INS +"ins r, r, , " +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + if ((1 + MSBD - LSB) < 1) + Unpredictable (); + do_ins (SD_, RT, RS, LSB, MSBD); +} + +100000,5.RT,5.RS,1101,0,4.SHIFTX,1.STRIPE,0,5.SHIFT:R6PROTX:32::ROTX +"bitrev r, r": SHIFT == 31 && SHIFTX_1BIT == 0 +"bitswap r, r": SHIFT == 7 && SHIFTX_1BIT == 8 && STRIPE == 1 +"bitswap.h r, r": SHIFT == 15 && SHIFTX_1BIT == 16 +"byteswap r, r": SHIFT == 24 && SHIFTX_1BIT == 8 +"wsbh r, r": SHIFT == 8 && SHIFTX_1BIT == 24 +"rotx r, r, , ": STRIPE == 0 +"rotx r, r, , , " +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + + TRACE_ALU_INPUT4 (GPR[RT], GPR[RS], SHIFT, SHIFTX_1BIT); + do_rotx (SD_, RT, RS, SHIFT, SHIFTX_1BIT, STRIPE); + TRACE_ALU_RESULT (GPR[RT]); +} + +010010,5.RT,5.RS,0000,12.X:R6PJ:32::JALRC +"jalrc r, r" +*nanomips32r6: +*nanomips64r6: +{ + unsigned_word address; + TRACE_ALU_INPUT3(GPR[RT], GPR[RS], RA); + GPR[RT] = NIA; + address = GPR[RS]; + NIA = address; + + // For cycle counting + COP0_COUNT++; + TRACE_ALU_RESULT(NIA); + +} + +010010,5.RT,5.RS,0001,12.X:R6PJ:32::JALRC.HB +"jalrc.hb r, r" +*nanomips32r6: +*nanomips64r6: +{ + unsigned_word address; + GPR[RT] = NIA; + address = GPR[RS]; + NIA = address; + + // For cycle counting + COP0_COUNT++; +} + +100001,5.RT,5.RS,0000,12.U:R6PLSU12:32::LB +"lb r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lb (SD_, RT, U, RS); +} + +010001,5.RT,000,18.U:R6PLSGP:32::LBGP +"lb r, (GP)" +*nanomips32r6: +*nanomips64r6: +{ + do_lb (SD_, RT, U, GPIDX); +} + +101001,5.RT,5.RS,1.S1,0000,0,00,8.S2:R6PLSS0:32::LBS9 +"lb r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lb (SD_, RT, S_9_BIT, RS); +} + +100001,5.RT,5.RS,0010,12.U:R6PLSU12:32::LBU +"lbu r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lbu (SD_, RT, U, RS); +} + +010001,5.RT,010,18.U:R6GPBH:32::LBUGP +"lbu r, (GP)" +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2 (U, GP); + do_lbu (SD_, RT, U, GPIDX); + TRACE_ALU_RESULT (GPR[RT]); +} + +101001,5.RT,5.RS,1.S1,0010,0,00,8.S2:R6PLSS0:32::LBUS9 +"lbu r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lbu (SD_, RT, S_9_BIT, RS); +} + +001000,5.RT,5.RS,5.RD,0010,0,000,111:R6PPLSX:32::LBUX +"lbux r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lbu (SD_, RD, GPR[RS], RT); +} + +001000,5.RT,5.RS,5.RD,0000,0,000,111:R6PPLSX:32::LBX +"lbx r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lb (SD_, RD, GPR[RS], RT); +} + +100001,5.RT,5.RS,0100,12.U:R6PLSU12:32::LH +"lh r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lh (SD_, RT, U, RS); +} + +010001,5.RT,100,17.U,0:R6PGPLH:32::LHGP +"lh r, (GP)" +*nanomips32r6: +*nanomips64r6: +{ + do_lh (SD_, RT, U_SHIFT_1BIT, GPIDX); +} + +101001,5.RT,5.RS,1.S1,0100,0,00,8.S2:R6PLSS0:32::LHS9 +"lh r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lh (SD_, RT, S_9_BIT, RS); +} + +100001,5.RT,5.RS,0110,12.U:R6PLSU12:32::LHU +"lhu r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lhu (SD_, RT, U, RS); +} + +010001,5.RT,100,17.U,1:R6PLSGP:32::LHUGP +"lhu r, (gp)" +*nanomips32r6: +*nanomips64r6: +{ + do_lhu (SD_, RT, U_SHIFT_1BIT, GPIDX); +} + +101001,5.RT,5.RS,1.S1,0110,0,00,8.S2:R6PLSS0:32::LHUS9 +"lhu r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lhu (SD_, RT, S_9_BIT, RS); +} + +001000,5.RT,5.RS,5.RD,0110,0,000,111:R6PPLSX:32::LHUX +"lhux r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lhu (SD_, RD, GPR[RS], RT); +} + +001000,5.RT,5.RS,5.RD,0110,1,000,111:R6PPLSXS:32::LHUXS +"lhux r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lhu (SD_, RD, GPR[RS] << 1, RT); +} + +001000,5.RT,5.RS,5.RD,0100,0,000,111:R6PPLSX:32::LHX +"lhx r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lh (SD_, RD, GPR[RS], RT); +} + +001000,5.RT,5.RS,5.RD,0100,1,000,111:R6PPLSXS:32::LHXS +"lhxs r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lh (SD_, RD, GPR[RS] << 1, RT); +} + +101001,5.RT,5.RS,1.S1,1010,0,01,6.S2,00:R6PLL:32::LL +"ll r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT3(GPR[RT], S_9_BIT_LLSC, GPR[RS]); + do_ll (SD_, RT, S_9_BIT_LLSC, RS); + TRACE_ALU_RESULT(GPR[RT]); +} + +101001,5.RT,5.RS,1.X1,1010,0,01,5.RU,1.X2,01:R6PLL:32::LLWP +"llwp r, r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_llwp (SD_, RT, RU, 0, RS); +} + +001000,5.RT,5.RS,5.RD,2.U,3.X,001,111:R6POOL32A7:32::LSA +"lsa r, r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_lsa (SD_, RD, RS, RT, U); +} + +111000,5.RT,9.S1,10.S2,0,1.S3:R6PLUI:32::LUI +"lui r, , ":AXUIPC_S_LO != 0 +"lui r, " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2 (GPR[RT], AXUIPC_S); + GPR[RT] = AXUIPC_S; + TRACE_ALU_RESULT (GPR[RT]); +} + +100001,5.RT,5.RS,1000,12.U:R6PLSU12:32::LW +"lw r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT3 (GPR[RT], U, GPR[RS]); + do_lw (SD_, RT, U, RS); + TRACE_ALU_RESULT (GPR[RT]); +} + +101001,5.RT,5.RS,1.S1,1000000,8.S2:R6PLSS0:32::LWS9 +"lw r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lw (SD_, RT, S_9_BIT, RS); +} + +101001,5.RT,5.RS,1.S1,3.COUNT3,0,1,00,8.S2:R6PLSWM:32::LWM +"lwm r, (r), " +*nanomips32r6: +*nanomips64r6: +{ + int counter = 0; + int dest; + int this_offset; + + check_nms_flag (SD_); + + while (counter != COUNT) + { + dest = (RT & 0x10) | ((RT + counter) & 0x1F); + + if ((dest == RS) && (counter != (COUNT - 1))) + Unpredictable (); + + this_offset = S_9_BIT + (counter << 2); + + do_lw (SD_, dest, this_offset, RS); + + counter++; + if (counter != 0) + COP0_COUNT++; + } +} + +010000,5.RT,19.U,10:R6PGPW:32::LWGP +"lw r, (GP)" +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RT], GPR[RT]); + do_lw (SD_, RT, U_SHIFT_2BIT, GPIDX); + TRACE_ALU_RESULT(GPR[RT]); +} + +011000,5.RT,01011,16.IMM48:R6POOL48I:32::LWPC48 +"lwpc r, " +*nanomips32r6: +*nanomips64r6: +{ + uint16_t S2; + uint32_t total; + check_nms_flag (SD_); + S2 = do_load(SD_, AccessLength_HALFWORD, CIA + 4, 0); + total = S2 << 16 | IMM48; + + do_lwpc_nanomips (SD_, RT, total, CIA + 6); + NIA = CIA + 6; +} + +001000,5.RT,5.RS,5.RD,1000,0,000,111:R6PPLSX:32::LWX +"lwx r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lw (SD_, RD, GPR[RS], RT); +} + +001000,5.RT,5.RS,5.RD,1000,1,000,111:R6PPLSXS:32::LWXS +"lwxs r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + do_lw (SD_, RD, GPR[RS] << 2, RT); +} + +001000,5.RT,5.C0S,5.SEL,1.X,0000110,000:R6POOL32A0:32::MFC0 +"mfc0 r, r, " +*nanomips32r6: +*nanomips64r6: +{ + DecodeCoproc (instruction_0, 0, cp0_mfc0, RT, C0S, SEL); +} + +001000,5.RT,5.RS,5.RD,1.X,0101011,000:R6POOL32A0:32::MOD +"mod r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_mod (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,5.RD,1.X,0111011,000:R6POOL32A0:32::MODU +"modu r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_modu (SD_, RD, RS, RT); +} + +000010,1.RT1,1.RD,3.RT2,20.S1,1.S2:R6MOVEBALC:32::MOVE.BALC +"move.balc r, r, " +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + TRACE_ALU_INPUT2(GPR[RD1], GPR[RT_5_BIT_NM_Z]); + GPR[RD1] = GPR[RT_5_BIT_NM_Z]; + RA = NIA; + NIA = ADDRESS22; + TRACE_ALU_RESULT(GPR[RD1]); + + // For cycle counting + COP0_COUNT += 2; +} + +001000,5.RT,5.RS,5.RD,1,1000010,000:R6PCMOVE:32::MOVN +"movn r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT2(GPR[RS], GPR[RT]); + do_movn (SD_, RD, RS, RT); + TRACE_ALU_RESULT(GPR[RD]); +} + +001000,5.RT,5.RS,5.RD,0,1000010,000:R6PCMOVE:32::MOVZ +"movz r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_movz (SD_, RD, RS, RT); +} + +001000,5.RT,5.C0S,5.SEL,1.X,0001110,000:R6POOL32A0:32::MTC0 +"mtc0 r, r, " +*nanomips32r6: +*nanomips64r6: +{ + DecodeCoproc (instruction_0, 0, cp0_mtc0, RT, C0S, SEL); +} + +001000,5.RT,5.RS,5.RD,1.X,0001011,000:R6POOL32A0:32::MUH +"muh r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_muh (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,5.RD,1.X,0011011,000:R6POOL32A0:32::MUHU +"muhu r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_muhu (SD_, RD, RS, RT); +} + +001000,5.RT,5.RS,5.RD,1.X,0000011,000:R6POOL32A0:32::MUL32 +"mul r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_mul (SD_, RD, RS, RT); +} + +001111,1.RT1,0,3.RT2,1.RS1,1,3.RS2:R6P164X4:16::MUL4X4 +"mul r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_mul (SD_, RT_5_BIT_NM, RS_5_BIT_NM, RT_5_BIT_NM); +} + +001000,5.RT,5.RS,5.RD,1.X,0010011,000:R6POOL32A0:32::MULU +"mulu r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_mulu (SD_, RD, RS, RT); +} + +100000,00000,5.X1,1100,3.X2,0000,00000:R6PSLL:32::NOP32 +"nop" +*nanomips32r6: +*nanomips64r6: +{ +} + +001000,5.RT,5.RS,5.RD,1.X,1011010,000:R6POOL32A0:32::NOR +"nor r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_nor (SD_, RS, RT, RD); +} + +001000,5.RT,5.RS,5.RD,1.X,1010010,000:R6POOL32A0:32::OR32 +"or r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_or (SD_, RS, RT, RD); +} + +100000,5.RT,5.RS,0000,12.U:R6PU12:32::ORI +"ori r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_ori (SD_, RS, RT, U); +} + +100000,00000,5.X1,1100,3.X2,0000,00101:R6PSLL:32::PAUSE +"pause" +*nanomips32r6: +*nanomips64r6: +{ + sim_io_printf (SD, "Not implemented"); +} + +101001,5.HINT!31,5.RS,1.S1,0011,0,00,8.S2:R6PPREFS9:32::PREFS9 +"pref , (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_pref (SD_, HINT, S_9_BIT, RS); +} + +100001,5.HINT,5.RS,0011,12.U:R6PLSU12:32::PREFU12 +"pref , (r)": HINT != 31 +"synci (r)" +*nanomips32r6: +*nanomips64r6: +{ + if (HINT != 31) + do_pref (SD_, HINT, U, RS); + else + { + // synci - nothing to do currently + sim_io_printf (SD, "Not implemented"); + } +} + +100000,5.RT,0,4.GPR_LIST_SAVE,0011,9.U,1.GP_SAVE,10:R6PPSR:32::RESTORE +"restore , r": GPR_LIST_SAVE == 0 +"restore , r, %s": !GP_SAVE && GPR_LIST_SAVE != 0 +"restore , r": !GP_SAVE && GPR_LIST_SAVE < 2 +"restore , r, %s" : !GP_SAVE && GPR_LIST_SAVE >=2 +"restore , r, %s": GP_SAVE && GPR_LIST_SAVE < 2 +"restore , r, %s, %s" : GP_SAVE && GPR_LIST_SAVE >=2 +"restore , r, %s": GP_SAVE && GPR_LIST_SAVE < 3 +"restore , r, %s, %s" +*nanomips32r6: +*nanomips64r6: +{ + do_restore_gprs_from_stack_and_adjust_sp(SD_, RT, GPR_LIST_SAVE, + GP_SAVE, U_SHIFT_3BIT); +} + +100000,5.RT,0,4.GPR_LIST_SAVE,0011,9.U,1.GP_SAVE,11:R6PPSR:32::RESTORE.JRC +"restore.jrc , r": GPR_LIST_SAVE == 0 +"restore.jrc , r, %s": !GP_SAVE && GPR_LIST_SAVE != 0 +"restore.jrc , r": !GP_SAVE && GPR_LIST_SAVE < 2 +"restore.jrc , r, %s" : !GP_SAVE && GPR_LIST_SAVE >=2 +"restore.jrc , r, %s": GP_SAVE && GPR_LIST_SAVE < 2 +"restore.jrc , r, %s, %s" : GP_SAVE && GPR_LIST_SAVE >=2 +"restore.jrc , r, %s": GP_SAVE && GPR_LIST_SAVE < 3 +"restore.jrc , r, %s, %s" +*nanomips32r6: +*nanomips64r6: +{ + do_restore_gprs_from_stack_and_adjust_sp(SD_, RT, GPR_LIST_SAVE, + GP_SAVE, U_SHIFT_3BIT); + + NIA = GPR[RAIDX]; +} + +100000,5.RT,5.RS,1100,3.X,0110,5.SHIFT:R6PSHIFT:32::ROTR +"rotr r, r, " +*nanomips32r6: +*nanomips64r6: +{ + GPR[RT] = do_ror (SD_, GPR[RS], SHIFT); +} + +001000,5.RT,5.RS,5.RD,1.X,0011010,000:R6POOL32A0:32::ROTRV +"rotrv r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + uint32_t shift = GPR[RT] & 0x1f; + GPR[RD] = do_ror (SD_, GPR[RS], shift); +} + +001000,5.RT,5.RS,5.RD,0,1100010,000:R6POOL32A0:32::XOR +"xor r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_xor (SD_, RS, RT, RD); +} + +100000,5.RT,5.RS,0001,12.U:R6PU12:32::XORI +"xori r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_xori (SD_, RS, RT, U); +} + +100000,5.RT,0,4.GPR_LIST_SAVE,0011,9.U,1.GP_SAVE,00:R6PPSR:32::SAVE +"save , r": GPR_LIST_SAVE == 0 +"save , r, %s": !GP_SAVE && GPR_LIST_SAVE != 0 +"save , r": !GP_SAVE && GPR_LIST_SAVE < 2 +"save , r %s" : !GP_SAVE && GPR_LIST_SAVE >=2 +"save , r, %s": GP_SAVE && GPR_LIST_SAVE < 2 +"save , r, %s, %s" : GP_SAVE && GPR_LIST_SAVE >=2 +"save , r, %s": GP_SAVE && GPR_LIST_SAVE < 3 +"save , r, %s, %s" +*nanomips32r6: +*nanomips64r6: +{ + do_save_gprs_to_stack_and_adjust_sp(SD_, RT, GPR_LIST_SAVE, + GP_SAVE, U_SHIFT_3BIT); +} + +100001,5.RT,5.RS,0001,12.U:R6PLSU12:32::SBU12 +"sb r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_BYTE, GPR[RS], U, GPR[RT]); +} + +010001,5.RT,001,18.U:R6PGPBH:32::SBGP +"sb r, (gp)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_BYTE, GP, U, GPR[RT]); +} + +101001,5.RT,5.RS,1.S1,0001,0,00,8.S2:R6PLSS0:32::SBS9 +"sb r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_BYTE, GPR[RS], S_9_BIT, GPR[RT]); +} + +001000,5.RT,5.RS,5.RD,0001,0,000,111:R6PPLSX:32::SBX +"sbx r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_store (SD_, AccessLength_BYTE, GPR[RT], GPR[RS], GPR[RD]); +} + +101001,5.RT,5.RS,1.S1,1011,0,01,6.S2,00:R6PSC:32::SC +"sc r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_sc (SD_, RT, S_9_BIT_LLSC, RS, instruction_0, 1); +} + +101001,5.RT,5.RS,1.X1,1011,0,01,5.RU,1.X,01:R6PSC:32::SCWP +"scwp r, r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + int offset = BigEndianCPU ? 0 : 4; + + do_sc (SD_, RU, offset, RS, instruction_0, 0); + do_sc (SD_, RT, offset ^ 4, RS, instruction_0, 1); +} + +001000,5.RT,5.RS,6.X,0000001,000:R6POOL32A0:32::SEB +"seb r, r" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_seb (SD_, RT, RS); +} + +001000,5.RT,5.RS,6.X,0001001,000:R6POOL32A0:32::SEH +"seh r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_seh (SD_, RT, RS); +} + +100000,5.RT,5.RS,0110,12.IMMEDIATE:R6PU12:32::SEQI +"seqi r, r, " +*nanomips32r6: +*nanomips64r6: +{ + TRACE_ALU_INPUT3(GPR[RT], GPR[RS], IMMEDIATE); + GPR[RT] = (GPR[RS] == IMMEDIATE) ? 1 : 0; + TRACE_ALU_RESULT(GPR[RT]); +} + +100001,5.RT,5.RS,0101,12.U:R6PLSU12:32::SHU12 +"sh r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_HALFWORD, GPR[RS], U, GPR[RT]); +} + +010001,5.RT,101,17.U,0:R6PGPSH:32::SHGP +"sh r, (GP)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_HALFWORD, GP, U_SHIFT_1BIT, GPR[RT]); +} + +101001,5.RT,5.RS,1.S1,0101,0,00,8.S2:R6PLSS0:32::SHS9 +"sh r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_HALFWORD, GPR[RS], S_9_BIT, GPR[RT]); +} + +001000,5.RT,5.RS,5.RD,0101,0,000,111:R6PPLSX:32::SHX +"shx r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_store (SD_, AccessLength_HALFWORD, GPR[RT], GPR[RS], GPR[RD]); +} + +001000,5.RT,5.RS,5.RD,0101,1,000,111:R6PPLSXS:32::SHXS +"shxs r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_store (SD_, AccessLength_HALFWORD, GPR[RT], GPR[RS] << 1, GPR[RD]); +} + +000000,00000,00,19.CODE:R6PRI:32::SIGRIE +"sigrie %#lx" +*nanomips32r6: +*nanomips64r6: +{ + SignalException (ReservedInstruction, instruction_0); +} + +100000,5.RT!0,5.RS,1100,3.X,0000,5.SHIFT:R6PSLL:32::SLL32 +"sll r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_sll (SD_, RS, RT, SHIFT); +} + +001000,5.RT,5.RS,5.RD,1.X,0000010,000:R6POOL32A0:32::SLLV +"sllv r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_sllv (SD_, RT, RS, RD); +} + +001000,5.RT,5.RS,5.RD,1.X,1101010,000:R6POOL32A0:32::SLT +"slt r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_slt (SD_, RS, RT, RD); +} + +100000,5.RT,5.RS,0100,12.IMMEDIATE:R6PU12:32::SLTI +"slti r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_slti (SD_, RS, RT, EXTEND12(IMMEDIATE)); +} + +100000,5.RT,5.RS,0101,12.U:R6PU12:32::SLTIU +"sltiu r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_sltiu (SD_, RS, RT, EXTEND12(U)); +} + +001000,5.RT,5.RS,5.RD!0,1.X,1110010,000:R6PSLTU:32::SLTU +"sltu r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_sltu (SD_, RS, RT, RD); +} + +100000,5.RT,5.RS,1100,3.X,0100,5.SHIFT:R6PSHIFT:32::SRA +"sra r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_sra (SD_, RS, RT, SHIFT); +} + +001000,5.RT,5.RS,5.RD,1.X,0010010,000:R6POOL32A0:32::SRAV +"srav r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_srav (SD_, RT, RS, RD); +} + +100000,5.RT,5.RS,1100,3.X,0010,5.SHIFT:R6PSHIFT:32::SRL32 +"srl r, r, " +*nanomips32r6: +*nanomips64r6: +{ + do_srl (SD_, RS, RT, SHIFT); +} + +001000,5.RT,5.RS,5.RD,1.X,0001010,000:R6POOL32A0:32::SRLV +"srlv r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_srlv (SD_, RT, RS, RD); +} + +001000,5.RT,5.RS,5.RD,1.X,0110010,000:R6POOL32A0:32::SUB +"sub r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_sub (SD_, RS, RT, RD); +} + +001000,5.RT,5.RS,5.RD,1.X,0111010,000:R6POOL32A0:32::SUBU32 +"subu r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + do_subu (SD_, RS, RT, RD); +} + +100001,5.RT,5.RS,1001,12.U:R6PLSU12:32::SWU12 +"sw r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_WORD, GPR[RS], U, GPR[RT]); +} + +101001,5.RT,5.RS,1.S1,1001,0,00,8.S2:R6PLS0:32::SWS9 +"sw r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_WORD, GPR[RS], S_9_BIT, GPR[RT]); +} + +010000,5.RT,19.U,11:R6PGPW:32::SWGP +"sw r, (GP)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_WORD, GP, U_SHIFT_2BIT, GPR[RT]); +} + +011000,5.RT,01111,16.IMM48:R6POOL48I:32::SWPC48 +"swpc r, " +*nanomips32r6: +*nanomips64r6: +{ + uint16_t U2; + uint32_t total; + check_nms_flag (SD_); + U2 = do_load (SD_, AccessLength_HALFWORD, CIA + 4, 0); + total = U2 << 16 | IMM48; + TRACE_ALU_INPUT2(GPR[RT], total); + do_store(SD_, AccessLength_WORD, CIA + 6, total, GPR[RT]); + TRACE_ALU_RESULT(GPR[RT]); + NIA = CIA + 6; +} + + +110101,3.RTZ,7.U:R6P16:16::SWGP16 +"sw r, (GP)" +*nanomips32r6: +*nanomips64r6: +{ + do_store (SD_, AccessLength_WORD, GP, U_SHIFT_2BIT, GPR[TRTZ]); +} + +001000,5.RT,5.RS,5.RD,1001,0,000,111:R6PPLSX:32::SWX +"swx r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_store (SD_, AccessLength_WORD, GPR[RT], GPR[RS], GPR[RD]); +} + +001000,5.RT,5.RS,5.RD,1001,1,000,111:R6PPLSXS:32::SWXS +"swxs r, r(r)" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_store (SD_, AccessLength_WORD, GPR[RT], GPR[RS] << 2, GPR[RD]); +} + +111101,1.RT1,1.U2,3.RT2,1.RS1,1.U3,3.RS2:R6P16:16::SW4X4 +"sw r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_store (SD_, AccessLength_WORD, GPR[RS_5_BIT_NM], U_LW4X4, GPR[RT_5_BIT_NM_Z]); +} + +101001,5.RT,5.RS,1.S1,3.COUNT3,1,1,00,8.S2:R6PLSWM:32::SWM +"swm r, (r), " +*nanomips32r6: +*nanomips64r6: +{ + int counter = 0; + int source; + int offsetm; + + check_nms_flag (SD_); + + while (counter != COUNT) + { + if (RT == 0) + source = 0; + else + source = (RT & 0x10) | ((RT + counter) & 0x1F); + + offsetm = S_9_BIT + (counter << 2); + + do_sw (SD_, source, offsetm, RS); + + counter++; + + if (counter != 0) + COP0_COUNT++; + } +} + +100000,00000,5.STYPE,1100,3.X,0000,00110:R6PHB:32::SYNC +"sync":STYPE==0 +"sync " +*nanomips32r6: +*nanomips64r6: +{ + SyncOperation (STYPE); +} + +101001,11111,5.RS,1.S1,0011,0,00,8.S2:R6PPREFS:32::SYNCI +"synci (r)" +*nanomips32r6: +*nanomips64r6: +{ + // sync i-cache - nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + +000000,00000,11,19.CODE:R6PRI:32::SDBBP32 +"sdbbp %#lx" +*nanomips32r6: +*nanomips64r6: +{ + SignalException (DebugBreakPoint, instruction_0); +} + +001000,10.X,00,00001,101,111,111:R6POOL32AXF5GROUP0:32::TLBP +"tlbp" +*nanomips32r6: +*nanomips64r6: +{ + // nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + +001000,10.X,00,10001,101,111,111:R6POOL32AXF5GROUP0:32::TLBWI +"tlbwi" +*nanomips32r6: +*nanomips64r6: +{ + // nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + +001000,10.X,00,11001,101,111,111:R6POOL32AXF5GROUP0:32::TLBWR +"tlbwr" +*nanomips32r6: +*nanomips64r6: +{ + // nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + + +001000,0000000000,01,00001,101,111,111:R6POOL32AXF5GROUP1:32::TLBINV +"tlbinv" +*nanomips32r6: +*nanomips64r6: +{ + // invalidate a set of TLB entries based on ASID and Index match - nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + +001000,0000000000,01,01001,101,111,111:R6POOL32AXF5GROUP1:32::TLBINVF +"tlbinvf" +*nanomips32r6: +*nanomips64r6: +{ + // invalidate a set of TLB entries based on Index match - nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + +001000,10.CODE,10,00101,101,111,111:R6PSYSCALL:32::SYSCALL +"syscall %#lx" +*nanomips32r6: +*nanomips64r6: +{ + SignalException (SystemCall, instruction_0); +} + +100000,00000,5.X1,1100,3.X2,0000,00011:R6PHB:32::EHB +"ehb" +*nanomips32r6: +*nanomips64r6: +{ + // Do nothing, there are no hazards to clear +} + +001000,5.RT,5.RS,5.X,0,0000000,000:R6PTRAP:32::TEQ +"teq r, r" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + + if (GPR[RS] == GPR[RT]) + SignalException(Trap, instruction_0); +} + +001000,5.RT,5.RS,5.X,1,0000000,000:R6PTRAP:32::TNE +"tne r, r" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + + if (GPR[RS] != GPR[RT]) + SignalException(Trap, instruction_0); +} + +101001,5.RT,5.RS,1.S1,0100,0,01,8.S2:R6PLSS1:32::UALH +"ualh r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + + TRACE_ALU_INPUT3(GPR[RT], S_9_BIT, GPR[RS]); + do_lh (SD_, RT, S_9_BIT, RS); + TRACE_ALU_RESULT(GPR[RT]); +} + +101001,5.RT,5.RS,1.S1,3.COUNT3,0,1,01,8.S2:R6PLSUAWM:32::UALWM +"ualwm r, (r), ":COUNT != 1 +"ualw r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + int i; + int dest; + int this_offset; + + address_word base = GPR[RS]; + for(i = 0; i< COUNT; i++) + { + dest = (RT & 0x10) | ((RT + i) & 0x1F); + + if (dest == RS && i != COUNT - 1) + Unpredictable (); + + this_offset = S_9_BIT + (i << 2); + + if(BigEndianCPU) { + GPR[dest] = EXTEND32 (do_load_left (SD_, AccessLength_WORD, base, + EXTEND16 (this_offset), GPR[dest])); + GPR[dest] = EXTEND32 (do_load_right (SD_, AccessLength_WORD, base, + EXTEND16 (this_offset + AccessLength_WORD), GPR[dest])); + } else { + GPR[dest] = EXTEND32 (do_load_right (SD_, AccessLength_WORD, base, + EXTEND16 (this_offset), GPR[dest])); + GPR[dest] = EXTEND32 (do_load_left (SD_, AccessLength_WORD, base, + EXTEND16 (this_offset + AccessLength_WORD), GPR[dest])); + } + + if (i != 0) + COP0_COUNT++; + } +} + +101001,5.RT,5.RS,1.S1,0101,0,01,8.S2:R6PLSS1:32::UASH +"uash r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + + do_store (SD_, AccessLength_HALFWORD, GPR[RS], S_9_BIT, GPR[RT]); +} + +101001,5.RT,5.RS,1.S1,3.COUNT3,1,1,01,8.S2:R6PLSUAWM:32::UASWM +"uaswm r, (r), ":COUNT != 1 +"uasw r, (r)" +*nanomips32r6: +*nanomips64r6: +{ + + int i; + int source; + int offsetm; + + for(i = 0; i< COUNT; i++) + { + if (RT == 0) + source = 0; + else + source = (RT & 0x10) | ((RT + i) & 0x1F); + + offsetm = S_9_BIT + (i << 2); + + if(BigEndianCPU) { + do_store_left (SD_, AccessLength_WORD, GPR[RS], EXTEND16 (offsetm), GPR[source]); + do_store_right (SD_, AccessLength_WORD, GPR[RS], + EXTEND16 (offsetm + AccessLength_WORD), GPR[source]); + } else { + do_store_right (SD_, AccessLength_WORD, GPR[RS], EXTEND16 (offsetm), GPR[source]); + do_store_left (SD_, AccessLength_WORD, GPR[RS], + EXTEND16 (offsetm + AccessLength_WORD), GPR[source]); + } + + if (i != 0) + COP0_COUNT++; + } +} + +001000,5.RT,5.X,00000,0,1110010,000:R6PDVP:32::DVP +"dvp r" +*nanomips32r6: +*nanomips64r6: +{ + // nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + + +001000,5.RT,5.HS,2.X1,3.SEL,1.X2,0111000,000:R6POOL32A0:32::RDHWR +"rdhwr r, r, " +*nanomips32r6: +*nanomips64r6: +{ + check_nms_flag (SD_); + do_rdhwr (SD_, RT, HS); +} + +001000,5.RT,5.RS,11,10000,101,111,111:R6POOL32AXF5GROUP3:32::RDPGPR +"rdpgpr r, r" +*nanomips32r6: +*nanomips64r6: +{ + // nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + +001000,5.RT,5.RS,11,11000,101,111,111:R6POOL32AXF5GROUP3:32::WRPGPR +"wrpgpr r, r" +*nanomips32r6: +*nanomips64r6: +{ + // nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + +001000,5.RT,5.RS,5.RD,1.X,1111010,000:R6POOL32A0:32::SOV +"SOV r, r, r" +*nanomips32r6: +*nanomips64r6: +{ + if (NotWordValue (GPR[RS]) || NotWordValue (GPR[RT])) + Unpredictable (); + TRACE_ALU_INPUT2 (GPR[RS], GPR[RT]); + { + ALU32_BEGIN (GPR[RS]); + ALU32_ADD (GPR[RT]); + if (ALU32_HAD_OVERFLOW) + GPR[RD] = 1; + else + GPR[RD] = 0; + } + TRACE_ALU_RESULT (GPR[RD]); +} + +001000,10.X,11,10001,101,111,111:R6POOL32A0:32::DERET +"deret" +*nanomips32r6: +*nanomips64r6: +{ + // nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + +001000,5.RT,5.X,00000,1,1110010,000:R6PDVP:32::EVP +"evp r" : RT!=0 +"evp" +*nanomips32r6: +*nanomips64r6: +{ + // nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + +001000,10.CODE,110000110,1111111:R6POOL32AXF5GROUP2:32::WAIT +"wait" +*nanomips32r6: +*nanomips64r6: +{ + // nothing to do currently + sim_io_printf (SD, "Not implemented"); +} + +011000,5.RT,00000,16.IMM48:R6POOL48I:32::LI48 +"li r, " +*nanomips32r6: +*nanomips64r6: +{ + uint16_t U2; + uint32_t total; + check_nms_flag (SD_); + U2 = do_load (SD_, AccessLength_HALFWORD, CIA + 4, 0); + total = U2 << 16 | IMM48; + TRACE_ALU_INPUT2(GPR[RT], total); + GPR[RT] = EXTEND32(total); + TRACE_ALU_RESULT(GPR[RT]); + NIA = CIA + 6; +} + +011000,5.RT,00001,16.IMM48:R6POOL48I:32::ADDIU48 +"addiu r, " +*nanomips32r6: +*nanomips64r6: +{ + uint16_t S2; + uint32_t total; + check_nms_flag (SD_); + S2 = do_load(SD_, AccessLength_HALFWORD, CIA + 4, 0); + total = S2 << 16 | IMM48; + do_addiu(SD_, RT, RT, total); + NIA = CIA + 6; +} + +100000,5.RT,5.RS,1000,12.U:R6PU12:32::ADDIUNEG +"addiu r, r, -" +*nanomips32r6: +*nanomips64r6: +{ + do_addiu (SD_, RS, RT, -U); +} + +011000,5.RT,00010,16.IMM48:R6POOL48I:32::ADDIUGP48 +"addiu r, GP, " +*nanomips32r6: +*nanomips64r6: +{ + uint16_t S2; + uint32_t total; + check_nms_flag (SD_); + S2 = do_load(SD_, AccessLength_HALFWORD, CIA + 4, 0); + total = S2 << 16 | IMM48; + do_addiu (SD_, GPIDX, RT, total); + NIA = CIA + 6; +} + +010010,00000,5.RS,1000,12.X:R6BALRSC:32::BRSC +"brsc r" +*nanomips32r6: +*nanomips64r6: +{ + unsigned_word address = NIA + (GPR[RS] << 1); + NIA = address; +} + +010010,5.RT!0,5.RS,1000,12.X:R6PBALRSC:32::BALRSC +"balrsc r, r" +*nanomips32r6: +*nanomips64r6: +{ + unsigned_word address = NIA + (GPR[RS] << 1); + + GPR[RT] = NIA; + NIA = address; + + // For cycle counting + COP0_COUNT++; +} + +110010,5.RT,001,1.X,6.BIT,10.S1,1.S2:R6PBRI:32::BBEQZC +"bbeqzc r, , " +*nanomips32r6: +*nanomips64r6: +{ + int testbit = (GPR[RT] >> BIT) & 1; + + check_nms_flag (SD_); + + if (testbit == 0) + NIA = ADDRESS12; +} + +110010,5.RT,101,1.X,6.BIT,10.S1,1.S2:R6PBRI:32::BBNEZC +"bbnezc r, , " +*nanomips32r6: +*nanomips64r6: +{ + int testbit = (GPR[RT] >> BIT) & 1; + + check_nms_flag (SD_); + + if (testbit == 1) + NIA = ADDRESS12; +} + +:function:::void:do_lb:int rt, int offset, int base +*nanomips32r6: +*nanomips64r6: +{ + GPR[rt] = EXTEND8 (do_load (SD_, AccessLength_BYTE, GPR[base], offset)); +} + +:function:::void:do_lh:int rt, int offset, int base +*nanomips32r6: +*nanomips64r6: +{ + GPR[rt] = EXTEND16 (do_load (SD_, AccessLength_HALFWORD, GPR[base], offset)); +} + +:function:::void:do_lw:int rt, int offset, int base +*nanomips32r6: +*nanomips64r6: +{ + GPR[rt] = EXTEND32 (do_load (SD_, AccessLength_WORD, GPR[base], offset)); +} + +:function:::void:do_lhu:int rt, int offset, int base +*nanomips32r6: +*nanomips64r6: +{ + GPR[rt] = do_load (SD_, AccessLength_HALFWORD, GPR[base], offset); +} + +:function:::void:do_addiu:int rs, int rt, int immediate +*nanomips32r6: +*nanomips64r6: +{ + if (NotWordValue (GPR[rs])) + Unpredictable (); + TRACE_ALU_INPUT2 (GPR[rs], immediate); + GPR[rt] = EXTEND32 (GPR[rs] + immediate); + TRACE_ALU_RESULT (GPR[rt]); +} diff --git a/sim/mips/nanomipsrun.c b/sim/mips/nanomipsrun.c new file mode 100644 index 00000000000..8698726a9fa --- /dev/null +++ b/sim/mips/nanomipsrun.c @@ -0,0 +1,109 @@ +/* Run function for the nanomips simulator + + Copyright (C) 2018-2022 Free Software Foundation, Inc. + + Written by Andrew Bennett . + + This file is part of GDB, the GNU debugger. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "sim-main.h" +#include "nanomips16_idecode.h" +#include "nanomips32_idecode.h" +#include "bfd.h" + + +#define SD sd +#define CPU cpu +#define SIM_MONITOR_ADDRESS 0xBFC00000 + +void +sim_engine_run (SIM_DESC sd, int next_cpu_nr, int nr_cpus, int signal); + +address_word +nanomips_instruction_decode (SIM_DESC sd, sim_cpu * cpu, + address_word cia, + int instruction_size); + +address_word +nanomips_instruction_decode (SIM_DESC sd, sim_cpu * cpu, + address_word cia, + int instruction_size) +{ + + nanomips16_instruction_word instruction_0 = IMEM16_NANOMIPS (cia); + + if((cia & 0xFFF00000) == SIM_MONITOR_ADDRESS) { + nanomips32_instruction_word instruction_0 = IMEM32 (cia); + return nanomips32_idecode_issue (sd, instruction_0, cia); + } else if ((STATE_ARCHITECTURE (sd)->mach == bfd_mach_nanomipsisa32r6 + || STATE_ARCHITECTURE (sd)->mach == bfd_mach_nanomipsisa64r6) + && (NANOMIPS_MAJOR_OPCODE_3_5 (instruction_0) & 0x4) == 4) + return nanomips16_idecode_issue (sd, instruction_0, cia); + else + { + nanomips32_instruction_word instruction_0 = IMEM32_NANOMIPS (cia); + return nanomips32_idecode_issue (sd, instruction_0, cia); + } +} + +void +sim_engine_run (SIM_DESC sd, int next_cpu_nr, int nr_cpus, + int signal) +{ + nanomips32_instruction_word instruction_0; + sim_cpu *cpu = STATE_CPU (sd, next_cpu_nr); + nanomips32_instruction_address cia = CPU_PC_GET (cpu); + unsigned long bfdmach; + IS_NANOMIPS = 1; + + bfdmach = STATE_ARCHITECTURE(SD)->mach; + + if (is_nms_flag_set == 0 && (bfdmach == bfd_mach_nanomipsisa64r6 + || bfdmach == bfd_mach_nanomipsisa32r6)) + set_nms_flag (sd); + + while (1) + { + nanomips32_instruction_address nia; + + cia = cia & ~0x1; + +#if defined (ENGINE_ISSUE_PREFIX_HOOK) + ENGINE_ISSUE_PREFIX_HOOK (); +#endif + + nia = + nanomips_instruction_decode (sd, cpu, cia, + MICROMIPS_DELAYSLOT_SIZE_ANY); + +#if defined (ENGINE_ISSUE_POSTFIX_HOOK) + ENGINE_ISSUE_POSTFIX_HOOK (); +#endif + // Cycle counting + COP0_COUNT++; + + /* Update the instruction address */ + cia = nia; + + /* process any events */ + if (sim_events_tick (sd)) + { + CPU_PC_SET (CPU, cia); + sim_events_process (sd); + cia = CPU_PC_GET (CPU); + } + } +} diff --git a/sim/mips/nms.c b/sim/mips/nms.c new file mode 100644 index 00000000000..fd957d69e8b --- /dev/null +++ b/sim/mips/nms.c @@ -0,0 +1,44 @@ +/* Run function for the nanomips simulator + + Copyright (C) 2018-2022 Free Software Foundation, Inc. + + Written by Andrew Bennett . + + This file is part of GDB, the GNU debugger. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "sim-main.h" +#include "elf/mips-common.h" +#include "elf/nanomips.h" + +/* NMS Flag */ +int nms_flag = -1; + +int is_nms_flag_set = 0; + +void +set_nms_flag (SIM_DESC sd) +{ + Elf_Internal_ABIFlags_v0 *abiflags; + abiflags = bfd_nanomips_elf_get_abiflags (STATE_PROG_BFD(sd)); + + nms_flag = 0; + + if (abiflags != NULL + && ((abiflags->ases & NANOMIPS_ASE_xNMS) != 0)) + nms_flag = 1; + + is_nms_flag_set = 1; +} diff --git a/sim/mips/sim-main.h b/sim/mips/sim-main.h index 418c6599118..e6b2b47ede7 100644 --- a/sim/mips/sim-main.h +++ b/sim/mips/sim-main.h @@ -318,9 +318,9 @@ struct _sim_cpu { #define LAST_EMBED_REGNUM (96) #define NUM_REGS (LAST_EMBED_REGNUM + 1) -#define FP0_REGNUM 38 /* Floating point register 0 (single float) */ -#define FCRCS_REGNUM 70 /* FP control/status */ -#define FCRIR_REGNUM 71 /* FP implementation/revision */ +#define FP0_REGNUM ((CPU)->is_nanomips ? 36 : 38) /* Floating point register 0 (single float) */ +#define FCRCS_REGNUM ((CPU)->is_nanomips ? 68 : 70) /* FP control/status */ +#define FCRIR_REGNUM ((CPU)->is_nanomips ? 69 : 71) /* FP implementation/revision */ #endif @@ -336,16 +336,19 @@ struct _sim_cpu { #define GPR (®ISTERS[0]) #define GPR_SET(N,VAL) (REGISTERS[(N)] = (VAL)) -#define LO (REGISTERS[33]) -#define HI (REGISTERS[34]) -#define PCIDX 37 +#define HIIDX ((CPU)->is_nanomips ? 70 : 33) +#define LOIDX ((CPU)->is_nanomips ? 71 : 34) +#define HI (REGISTERS[HIIDX]) +#define LO (REGISTERS[LOIDX]) +#define PCIDX ((CPU)->is_nanomips ? 32 : 37) #define PC (REGISTERS[PCIDX]) -#define CAUSE (REGISTERS[36]) +#define COUSEIDX ((CPU)->is_nanomips ? 34 : 36) +#define CAUSE (REGISTERS[COUSEIDX]) #define SRIDX (32) #define SR (REGISTERS[SRIDX]) /* CPU status register */ -#define FCR0IDX (71) +#define FCR0IDX ((CPU)->is_nanomips ? 69 : 71) #define FCR0 (REGISTERS[FCR0IDX]) /* really a 32bit register */ -#define FCR31IDX (70) +#define FCR31IDX ((CPU)->is_nanomips ? 68 : 70) #define FCR31 (REGISTERS[FCR31IDX]) /* really a 32bit register */ #define FCSR (FCR31) #define Debug (REGISTERS[86]) @@ -362,10 +365,10 @@ struct _sim_cpu { #define AC3LOIDX (94) #define AC3HIIDX (95) -#define DSPLO(N) (REGISTERS[DSPLO_REGNUM[N]]) -#define DSPHI(N) (REGISTERS[DSPHI_REGNUM[N]]) +#define DSPLO(N) (REGISTERS[((CPU)->is_nanomips ? (LOIDX + 2 * N) : DSPLO_REGNUM[N])]) +#define DSPHI(N) (REGISTERS[((CPU)->is_nanomips ? (HIIDX + 2 * N) : DSPHI_REGNUM[N])]) -#define DSPCRIDX (96) /* DSP control register */ +#define DSPCRIDX ((CPU)->is_nanomips ? 79 : 96) /* DSP control register */ #define DSPCR (REGISTERS[DSPCRIDX]) #define DSPCR_POS_SHIFT (0) @@ -420,6 +423,8 @@ struct _sim_cpu { #define A3 (REGISTERS[7]) #define T8IDX 24 #define T8 (REGISTERS[T8IDX]) +#define GPIDX 28 +#define GP (REGISTERS[GPIDX]) #define SPIDX 29 #define SP (REGISTERS[SPIDX]) #define RAIDX 31 @@ -433,6 +438,7 @@ struct _sim_cpu { unsigned_word cop0_gpr[NR_COP0_GPR]; #define COP0_GPR ((CPU)->cop0_gpr) #define COP0_BADVADDR (COP0_GPR[8]) +#define COP0_COUNT (COP0_GPR[9]) /* While space is allocated for the floating point registers in the main registers array, they are stored separatly. This is because @@ -472,10 +478,21 @@ struct _sim_cpu { hilo_history lo_history; #define LOHISTORY (&(CPU)->lo_history) + int is_nanomips; +#define IS_NANOMIPS ((CPU)->is_nanomips) sim_cpu_base base; }; +#define SET_RV0(VAL) \ + do { \ + if ((CPU)->is_nanomips) \ + A0 = VAL; \ + else \ + V0 = VAL; \ + } while (0) + + extern void mips_sim_close (SIM_DESC sd, int quitting); #define SIM_CLOSE_HOOK(...) mips_sim_close (__VA_ARGS__) @@ -643,13 +660,16 @@ enum ExceptionCause { is used by gdb for break-points. NOTE: Care must be taken, since this value may be used in later revisions of the MIPS ISA. */ #define HALT_INSTRUCTION_MASK (0x03FFFFC0) +#define HALT_INSTRUCTION_MASK_NANOMIPS (0x0007FFFF) #define HALT_INSTRUCTION (0x03ff000d) #define HALT_INSTRUCTION2 (0x0000ffcd) +#define HALT_INSTRUCTION_NANOMIPS (0x001003FF) #define BREAKPOINT_INSTRUCTION (0x0005000d) #define BREAKPOINT_INSTRUCTION2 (0x0000014d) +#define BREAKPOINT_INSTRUCTION_NANOMIPS (0x00101400) @@ -1022,6 +1042,16 @@ INLINE_SIM_MAIN (uint16_t) ifetch16 (SIM_DESC sd, sim_cpu *cpu, address_word cia #define MICROMIPS_DELAYSLOT_SIZE_16 2 #define MICROMIPS_DELAYSLOT_SIZE_32 4 +#define IMEM32_NANOMIPS(CIA) \ + (ifetch16 (SD, CPU, (CIA), (CIA)) << 16 | ifetch16 (SD, CPU, (CIA + 2), \ + (CIA + 2))) +#define IMEM16_NANOMIPS(CIA) ifetch16 (SD, CPU, (CIA), ((CIA))) + + +#define NANOMIPS_MAJOR_OPCODE_3_5(INSN) ((INSN & 0x1c00) >> 10) + +#define NANOMIPS_DELAYSLOT_SIZE_ANY 0 + extern int isa_mode; #define ISA_MODE_MIPS32 0 @@ -1041,6 +1071,13 @@ extern FILE *tracefh; extern int DSPLO_REGNUM[4]; extern int DSPHI_REGNUM[4]; +/* NMS Flag */ +extern int nms_flag; +extern int is_nms_flag_set; + +void +set_nms_flag (SIM_DESC sd); + INLINE_SIM_MAIN (void) pending_tick (SIM_DESC sd, sim_cpu *cpu, address_word cia); extern SIM_CORE_SIGNAL_FN mips_core_signal; From patchwork Mon Nov 21 11:06:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aleksandar Rikalo X-Patchwork-Id: 60921 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7DD90384F6DB for ; Mon, 21 Nov 2022 11:06:55 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from EUR05-DB8-obe.outbound.protection.outlook.com (mail-db8eur05on2101.outbound.protection.outlook.com [40.107.20.101]) by sourceware.org (Postfix) with ESMTPS id 31B573854545 for ; Mon, 21 Nov 2022 11:06:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 31B573854545 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=syrmia.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=syrmia.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=VI3VyHR7/CDkVf+cRcvFLX2NtwvgIRrfpA7sh9wu3bJd/bMTqkiY3RSTnDVzjKYoyzUNlr/yKHS+lTdtCIB8jTIpCugTcVLmsVSlquin/q4XlGobyTJFod2Ci/zGPq1ScO2VioxhmokMn/agV0KnR+zkgTril9tCjrvd7sk7mTI2uH8dbnGPpZ3B/KPW3DQZwHL61Pv1ER2y304rU9cKq0QB43IQC6TEDfq5iwOFvtjCcOJ3Dv9PgefCiw2nPWRCrV1pvQGwTWISIL9SoUjX6Dftg5G8vv2u/bxDOt8Jc7oGn61ycQWOvizbvrBNa66pNEOLaj3fBa9HlsGO9FPQzg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=d0GtvjRHHD1LKG8Rw+u8PSFAjvjhoL2dTRrJlQHx6tU=; b=iE6Z7i/bCs/IdwuNo+krwA15pINkIiwbmNVv6C4fRCmJ8n8NiGUBmpB/8RIdjNnc8IzO8Bl4+gmDYZXqmahxGa9ZDBgRnWVdymtCf6gJz6cRPUVwlETrFkJgn2pkqFB3wYE+/7OUPdw+8zYZ5E3yTfP8bFGOEeRuYI5FgIgwnqw8oxVSRrOdfJ9pLMgG7+0xotqf0y1+FqnW+P416I6gscAqiqZga/xD5p69TYeyGor305kc7PcCThe+C/phFoS/1eOrU3d8CVrVd1H+W+LkAXi58Uo5s0jaXcQ8daBYeLk6KoQyLnxnR+/2VUBM9w17BTqoI3bQxPPzvDZzNaijQg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=syrmia.com; dmarc=pass action=none header.from=syrmia.com; dkim=pass header.d=syrmia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=syrmia.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=d0GtvjRHHD1LKG8Rw+u8PSFAjvjhoL2dTRrJlQHx6tU=; b=KCAyUs0F8KyLhj8YTfv6KxoaM8G2IypwSnh65L9IZL72B+QYDkYku2N+4FZ8Xaqzfd/7zFpK4qrzW2j0STUOnf5NdqXOt6VDDw8Q/6JeizeR3ZRIRRyaIPsnQk2wPORuQVd9In9gmSeV2vf28ldCAduxSRMiJrTLhxvV08pCqGE= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=syrmia.com; Received: from VI1PR0302MB3486.eurprd03.prod.outlook.com (2603:10a6:803:1e::32) by PAXPR03MB7806.eurprd03.prod.outlook.com (2603:10a6:102:201::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5834.15; Mon, 21 Nov 2022 11:06:10 +0000 Received: from VI1PR0302MB3486.eurprd03.prod.outlook.com ([fe80::19fa:5ce5:280a:b98e]) by VI1PR0302MB3486.eurprd03.prod.outlook.com ([fe80::19fa:5ce5:280a:b98e%3]) with mapi id 15.20.5834.015; Mon, 21 Nov 2022 11:06:10 +0000 From: Aleksandar Rikalo To: gdb-patches@sourceware.org Cc: aleksandar.rikalo@syrmia.com, arikalo@gmail.com Subject: [PATCH v3 2/2] gdb: Add nanoMIPS port Date: Mon, 21 Nov 2022 12:06:03 +0100 Message-Id: <20221121110603.124056-2-aleksandar.rikalo@syrmia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20221121110603.124056-1-aleksandar.rikalo@syrmia.com> References: <20221121110603.124056-1-aleksandar.rikalo@syrmia.com> X-ClientProxiedBy: VE1PR03CA0031.eurprd03.prod.outlook.com (2603:10a6:803:118::20) To VI1PR0302MB3486.eurprd03.prod.outlook.com (2603:10a6:803:1e::32) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI1PR0302MB3486:EE_|PAXPR03MB7806:EE_ X-MS-Office365-Filtering-Correlation-Id: 1320f0ab-cc32-4a89-2a40-08dacbb0656d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: VZBreCr89c+aVX7rWGU1mnVOHKxo90D5hYHIGG2Ey1dhrPc0/5xUokvTV+YdmP02rDHS5zV+4NuLPmZ8tsYb8KHoghArxaycPvqx/oIzE65z+5NabwDLLJcGSaTwar/xzDIUDonrbpYENp1BfSpPbelTwfMydVh5h4JBRVjTe/S3wueKL5KlHSKMUlqWCGnS7CXlCQBKyCt3FqgKfICwSisD9sqtPrMpgiadr1NykBA6TiVDCYX3P99p7mchFsQl8J8zjEBzmDbRCXrK8M6TxHK3ayEaFsovmPdzBGAExusmFGSqqsQIObcV3sTXg1wZpqozpHJgmTe74Lpn3z0gPn0wCVPkEfgtrck9PSpVex/NMQROF7DAjUpOhGJT80w4NlFU7gvsIJCwu1IHptG9kQwid8cgX5qIzjsvTWDO2gyPPqvkF+sYxNxifczwCquUlrC+X4j33PMBy7WpiOpPath76dywRwfFYHqXQ8DdvcLbHv3F84fw7FynPpkocuJQRdjvxNGpvyqTzdK4ren/6okQnEbHiUtxUq1Pr9PPXKnR6teEvRH1ed1xU/LWb/OJxW8xf9RFWTRrjp1ZXSsop9VMl3WiH4Wd3K5PbKRUk99+6ahCDdfAYJTpqsBwDLNtrNNarolPQU93wo4lAZyaYUkFNW8yTjvsWnKG3B3BzAIZti9J3/G7kZu+kUgnjUvquIg9OqQOcbTrlEZFYT+Wdi7ol6rb/57MGPyH1rf3qQ6NhTH1Ri5aJW9CjYPxU5Mq1Z6ByFYDmgm2cw+J/Hichw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:VI1PR0302MB3486.eurprd03.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230022)(136003)(376002)(346002)(396003)(366004)(39830400003)(451199015)(66899015)(36756003)(86362001)(26005)(38350700002)(38100700002)(2616005)(1076003)(186003)(21480400003)(6512007)(44832011)(83380400001)(6916009)(30864003)(2906002)(5660300002)(8936002)(6666004)(52116002)(6506007)(478600001)(6486002)(19627235002)(41300700001)(66476007)(316002)(66556008)(4326008)(8676002)(66946007)(2004002)(559001)(579004)(473944003); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: e4OS8KJCHtPmCnmq5Z4uIU7kTsQ1NNsubpTBDp06nak8ovEuPrSFX8j9nrd9GNTpdL4tREN0bpnyIend6TQwXNZ9PUU6rXMEaZzBtWczy6mD+HrPKG2k2fDGW/j88lNmMaedWqo5yNjkRYxTljRzQAP2C6R4c7I+yDYACPGX1zfuUfC6dB27+bLsyVKK2IyusxtXqZmG1ApDYsV9GdClNPlFFMTV9u4HzbJK6LN+rbI62rEkxsi/vmxPzuU2PyoMMB15pVx4oOV8oWysNehEF9N1FZZgxa+JQ0OGQOJw/siJ4Gn6IT3NIC72Yu+7UEPnWXpmgbrTS+YeWo0gDwJfhejSfHibBkDo0XNs/blHn8mRutljqfhqW46GVN+v7vunc33321z/mcGu352kc7b9zIqmEUslm1NNQP9hB9E7TQSVCqN7WzDNL9KdtH5ooGac+i2lBorTOVmQoBRmrKIMvaG9Yyre3X3Al6RfApe07FIhk0EkKg8cyUmemil87T6rAFZvJUkvvF/g4BfytUwcCMLVw/LwRvBfpQvgobQzOtUyVY0Ir79PMbXxq9ExI8/2g2sExCPUk724EJCC3D3RlW9+YWGMqqujedxl2M0qbkAykPBYcciCT4/JN+3g6Jze2Mq1ZvfMvCvp8MYYrOVTk6Rq9SgdxKWfi1nLJ4DQzqHUmlv/7OQzdgvWVdtJAqqIlhljUTka2wQIuZsK4VDOZZSgyBCueeIkST4VYEiwFPadqmiJzyop7wKQj3qwNL0k/GyaHF/YQTJjR1RUQAvWLNYm6IyQNgb/0dCC9UYKyFIzj85eDm505owj+bBb4XlJaQutpXkp2CPkuTIRetyUacTuAJsdpvRht1qpqckjOL6eD12PPRpOUncIRyAvy6+fXAETZPgHDEH7ZBn/pm8mG9GM6VXkJfPY1TlqSTVN8ok4iXXBlrVszx9NARzG1ghlEJ3bpfUqeRKf7CSXRlkSZ608zyJYfqeOBxNwI00DivSpvz8WKAVZv2rPgRsO7X340TPg2Dg8+uY9vrgY5IdLXoI+eHych0GbLVcZeO7VT3/cOTqdPxFBW112hCRPk/+nwOUHSE1jqEhpQlhY6X3xcm1lnOeVPChXRAkjSKZMJSz3GoDy+vi61t4TfGm4oq9PYuK6IlKaLgXG6TQRuagCIVzA67S5ab4V0janLMqIwZzU6IHmsj1sMllKJj40K4GAcqkitBAy9C5hsZdoNm2EVZrY3VpRvqalGlfFO0pdo4IlL+tzXnANtmD5234VyXo+EdQurz0iJ5hk6uCU9CpUidaZgn+vaGFiSJeiCf/MqW7ePv1kypv2+uOtUYMgtARAoA9CueBKPv1ie7YxuDy+goaKML14GykamuZc5mMrMaX6Bf3e11V2TEN4pywnZCmoEUJf1DeywjGyWzVsbK1Dlq61v0DDOE1yFEV2yroVNdKvLhanZnr0YIzEZ/R0rBdyLVzwYOR8Gti0IPiNTzqeewa/5f0aEGyt1Qu4zg129CJdZ2ZrxeJWhhytWhxBrvgKXHrQq8DVPO9bRFdeUM4PZy3HbIkzGY5sng11+QhmSWbWjAVKTi7m7CTYw6LFJslRsNZvgcys3hFHb3tVcEU9tw== X-OriginatorOrg: syrmia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 1320f0ab-cc32-4a89-2a40-08dacbb0656d X-MS-Exchange-CrossTenant-AuthSource: VI1PR0302MB3486.eurprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Nov 2022 11:06:10.5650 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 19214a73-c1ab-4e19-8f59-14bdcb09a66e X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 5dfFDQ0tSTf4nniFw/T5s1bTVWNRxCVctezhl19Rtdv8SZ+oNbzKVDRV7fjuPiGhCEpt9M0aEt+LD6n4+eKLFTsMPJfq65NL1EUhgwXEJjU= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PAXPR03MB7806 X-Spam-Status: No, score=-12.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_MANYCOMMENTS, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" Co-Authored-By: Jaydeep Patil Co-Authored-By: Matthew Fortune Co-Authored-By: Maciej W. Rozycki Co-Authored-By: Stefan Markovic Co-Authored-By: Sara Graovac Co-Authored-By: Dragan Mladjenovic --- config.sub | 1 + configure | 3 + configure.ac | 3 + gdb/Makefile.in | 2 + gdb/NEWS | 1 + gdb/configure.host | 1 + gdb/configure.tgt | 11 + gdb/features/Makefile | 4 + gdb/features/nanomips-cp0.xml | 13 + gdb/features/nanomips-cpu.xml | 44 + gdb/features/nanomips-dsp.xml | 20 + gdb/features/nanomips-fpu.xml | 45 + gdb/features/nanomips.c | 54 + gdb/features/nanomips.xml | 12 + gdb/features/nanomips64-cp0.xml | 13 + gdb/features/nanomips64-cpu.xml | 44 + gdb/features/nanomips64-dsp.xml | 20 + gdb/nanomips-tdep.c | 3407 +++++++++++++++++ gdb/nanomips-tdep.h | 144 + gdb/testsuite/gdb.asm/asm-source.exp | 9 +- gdb/testsuite/gdb.asm/nanomips.inc | 49 + .../gdb.base/catch-gdb-caused-signals.c | 3 + gdb/testsuite/gdb.base/float.exp | 2 +- gdb/testsuite/gdb.trace/trace-common.h | 2 +- gdb/testsuite/lib/gdb.exp | 1 + 25 files changed, 3905 insertions(+), 3 deletions(-) create mode 100644 gdb/features/nanomips-cp0.xml create mode 100644 gdb/features/nanomips-cpu.xml create mode 100644 gdb/features/nanomips-dsp.xml create mode 100644 gdb/features/nanomips-fpu.xml create mode 100644 gdb/features/nanomips.c create mode 100644 gdb/features/nanomips.xml create mode 100644 gdb/features/nanomips64-cp0.xml create mode 100644 gdb/features/nanomips64-cpu.xml create mode 100644 gdb/features/nanomips64-dsp.xml create mode 100644 gdb/nanomips-tdep.c create mode 100644 gdb/nanomips-tdep.h create mode 100644 gdb/testsuite/gdb.asm/nanomips.inc diff --git a/config.sub b/config.sub index dba16e84c77..b562e37aa09 100755 --- a/config.sub +++ b/config.sub @@ -1243,6 +1243,7 @@ case $cpu-$vendor in | moxie \ | mt \ | msp430 \ + | nanomips | nanomipseb \ | nds32 | nds32le | nds32be \ | nfp \ | nios | nios2 | nios2eb | nios2el \ diff --git a/configure b/configure index 80b2b02fe7e..626fe6de084 100755 --- a/configure +++ b/configure @@ -4064,6 +4064,9 @@ case "${target}" in mips*-*-*) noconfigdirs="$noconfigdirs gprof" ;; + nanomips*-*-elf*) + noconfigdirs="$noconfigdirs gas binutils ld gprof" + ;; nvptx*-*-*) noconfigdirs="$noconfigdirs target-libssp target-libstdc++-v3 target-libobjc" ;; diff --git a/configure.ac b/configure.ac index 36267d85785..352ff79fce7 100644 --- a/configure.ac +++ b/configure.ac @@ -1297,6 +1297,9 @@ case "${target}" in mips*-*-*) noconfigdirs="$noconfigdirs gprof" ;; + nanomips*-*-elf*) + noconfigdirs="$noconfigdirs gas binutils ld gprof" + ;; nvptx*-*-*) noconfigdirs="$noconfigdirs target-libssp target-libstdc++-v3 target-libobjc" ;; diff --git a/gdb/Makefile.in b/gdb/Makefile.in index fb4d42c7baa..3ef458477f9 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -824,6 +824,7 @@ ALL_TARGET_OBS = \ mn10300-tdep.o \ moxie-tdep.o \ msp430-tdep.o \ + nanomips-tdep.o \ netbsd-tdep.o \ nds32-tdep.o \ nios2-linux-tdep.o \ @@ -1394,6 +1395,7 @@ HFILES_NO_SRCDIR = \ mips-tdep.h \ mn10300-tdep.h \ moxie-tdep.h \ + nanomips-tdep.h \ netbsd-nat.h \ netbsd-tdep.h \ nds32-tdep.h \ diff --git a/gdb/NEWS b/gdb/NEWS index dddef6525de..57f74da652d 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -480,6 +480,7 @@ winheight * New targets +GNU/ELF/nanoMIPS nanomips*-*-* GNU/Linux/LoongArch loongarch*-*-linux* * Removed targets diff --git a/gdb/configure.host b/gdb/configure.host index da71675b201..3a9799ee56e 100644 --- a/gdb/configure.host +++ b/gdb/configure.host @@ -61,6 +61,7 @@ i[34567]86*) gdb_host_cpu=i386 ;; loongarch*) gdb_host_cpu=loongarch ;; m68*) gdb_host_cpu=m68k ;; mips*) gdb_host_cpu=mips ;; +nanomips*) gdb_host_cpu=nanomips ;; powerpc* | rs6000) gdb_host_cpu=powerpc ;; sparcv9 | sparc64) gdb_host_cpu=sparc ;; s390*) gdb_host_cpu=s390 ;; diff --git a/gdb/configure.tgt b/gdb/configure.tgt index e84e222ba0d..f4dba706a9c 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -448,6 +448,16 @@ msp430-*-elf*) gdb_target_obs="msp430-tdep.o" ;; +mt-*-*) + # Target: Morpho Technologies ms1 processor + gdb_target_obs="mt-tdep.o" + ;; + +nanomips*-*-*) + # Target: nanomips ELF + gdb_target_obs="nanomips-tdep.o" + ;; + nds32*-*-elf) # Target: AndesTech NDS32 core gdb_target_obs="nds32-tdep.o" @@ -766,6 +776,7 @@ m32r-*-*) gdb_sim=m32r ;; m68hc11-*-*|m6811-*-*) gdb_sim=m68hc11 ;; microblaze*-*-*) gdb_sim=microblaze ;; mips*-*-*) gdb_sim=mips ;; +nanomips*-*-*) gdb_sim=mips ;; mn10300*-*-*) gdb_sim=mn10300 ;; moxie-*-*) gdb_sim=moxie ;; msp430*-*-*) gdb_sim=msp430 ;; diff --git a/gdb/features/Makefile b/gdb/features/Makefile index c3e07809db3..f89823a3f31 100644 --- a/gdb/features/Makefile +++ b/gdb/features/Makefile @@ -46,6 +46,7 @@ # List of .dat files to create in ../regformats/ WHICH = mips-linux mips-dsp-linux \ mips64-linux mips64-dsp-linux \ + nanomips \ nios2-linux \ or1k-linux \ rs6000/powerpc-32 \ @@ -73,6 +74,8 @@ mips-expedite = r29,pc mips-dsp-expedite = r29,pc mips64-expedite = r29,pc mips64-dsp-expedite = r29,pc +microblaze-expedite = r1,rpc +nanomips-expedite = r29,pc nios2-linux-expedite = sp,pc or1k-expedite = r1,npc powerpc-expedite = r1,pc @@ -106,6 +109,7 @@ XMLTOC = \ mips-linux.xml \ mips64-dsp-linux.xml \ mips64-linux.xml \ + nanomips.xml \ nds32.xml \ nios2.xml \ or1k.xml \ diff --git a/gdb/features/nanomips-cp0.xml b/gdb/features/nanomips-cp0.xml new file mode 100644 index 00000000000..7a3995f0fd7 --- /dev/null +++ b/gdb/features/nanomips-cp0.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/gdb/features/nanomips-cpu.xml b/gdb/features/nanomips-cpu.xml new file mode 100644 index 00000000000..bb04a24d6f6 --- /dev/null +++ b/gdb/features/nanomips-cpu.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/features/nanomips-dsp.xml b/gdb/features/nanomips-dsp.xml new file mode 100644 index 00000000000..659fc3850c2 --- /dev/null +++ b/gdb/features/nanomips-dsp.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + diff --git a/gdb/features/nanomips-fpu.xml b/gdb/features/nanomips-fpu.xml new file mode 100644 index 00000000000..cac1d51f2ac --- /dev/null +++ b/gdb/features/nanomips-fpu.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/features/nanomips.c b/gdb/features/nanomips.c new file mode 100644 index 00000000000..43cdc8a95d5 --- /dev/null +++ b/gdb/features/nanomips.c @@ -0,0 +1,54 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: nanomips.xml */ + +#include "defs.h" +#include "osabi.h" +#include "target-descriptions.h" + +struct target_desc *tdesc_nanomips; +static void +initialize_tdesc_nanomips (void) +{ + struct target_desc *result; + result = allocate_target_description ().release(); + struct tdesc_feature *feature; + + set_tdesc_architecture (result, bfd_scan_arch ("nanomips")); + + feature = tdesc_create_feature (result, "org.gnu.gdb.nanomips.cpu"); + tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r13", 13, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r14", 14, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r15", 15, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r16", 16, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r17", 17, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r18", 18, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r19", 19, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r20", 20, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r21", 21, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r22", 22, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r23", 23, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r24", 24, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r25", 25, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r26", 26, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r27", 27, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r28", 28, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r29", 29, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r30", 30, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r31", 31, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "int"); + + tdesc_nanomips = result; +} diff --git a/gdb/features/nanomips.xml b/gdb/features/nanomips.xml new file mode 100644 index 00000000000..ae05a91e935 --- /dev/null +++ b/gdb/features/nanomips.xml @@ -0,0 +1,12 @@ + + + + + + nanomips + + diff --git a/gdb/features/nanomips64-cp0.xml b/gdb/features/nanomips64-cp0.xml new file mode 100644 index 00000000000..6af2e2c369d --- /dev/null +++ b/gdb/features/nanomips64-cp0.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/gdb/features/nanomips64-cpu.xml b/gdb/features/nanomips64-cpu.xml new file mode 100644 index 00000000000..30a237050a6 --- /dev/null +++ b/gdb/features/nanomips64-cpu.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/features/nanomips64-dsp.xml b/gdb/features/nanomips64-dsp.xml new file mode 100644 index 00000000000..84bf7b06cc6 --- /dev/null +++ b/gdb/features/nanomips64-dsp.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + diff --git a/gdb/nanomips-tdep.c b/gdb/nanomips-tdep.c new file mode 100644 index 00000000000..664d5d30a3a --- /dev/null +++ b/gdb/nanomips-tdep.c @@ -0,0 +1,3407 @@ +/* Target-dependent code for the nanoMIPS architecture, for GDB, + the GNU Debugger. + + Copyright (C) 2017-2022 Free Software Foundation, Inc. + Contributed by: + Jaydeep Patil + Matthew Fortune + Maciej W. Rozycki + Stefan Markovic + Sara Popadic + Dragan Mladjenovic + Aleksandar Rikalo + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" +#include "value.h" +#include "gdbcmd.h" +#include "language.h" +#include "gdbcore.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbtypes.h" +#include "target.h" +#include "arch-utils.h" +#include "regcache.h" +#include "osabi.h" +#include "nanomips-tdep.h" +#include "block.h" +#include "reggroups.h" +#include "opcode/nanomips.h" +#include "elf/mips-common.h" +#include "elf/nanomips.h" +#include "elf-bfd.h" +#include "symcat.h" +#include "sim-regno.h" +#include "dis-asm.h" +#include "disasm.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "trad-frame.h" +#include "infcall.h" +#include "floatformat.h" +#include "remote.h" +#include "target-descriptions.h" +#include "dwarf2/frame.h" +#include "user-regs.h" +#include "valprint.h" +#include "ax.h" +#include "target-float.h" +#include + +#include "features/nanomips.c" + +/* The sizes of registers. */ + +enum +{ + NANOMIPS32_REGSIZE = 4, + NANOMIPS64_REGSIZE = 8 +}; + +static const char *const nanomips_abi_strings[] = { + "auto", + "p32", + "p64", + NULL +}; + +/* Enum describing the different kinds of breakpoints. */ + +enum nanomips_breakpoint_kind +{ + /* 16-bit breakpoint. */ + NANOMIPS_BP_KIND_16 = 3, + + /* 32-bit breakpoint. */ + NANOMIPS_BP_KIND_32 = 5, +}; + +/* The standard register names, and all the valid aliases for them. */ +struct register_alias +{ + const char *name; + int regnum; +}; + + +static unsigned int nanomips_debug = 0; + +const struct nanomips_regnum * +nanomips_regnum (struct gdbarch *gdbarch) +{ + return gdbarch_tdep (gdbarch)->regnum; +} + +static int +nanomips_fp_arg_regnum (struct gdbarch *gdbarch) +{ + gdb_assert (nanomips_regnum (gdbarch)->fpr != -1); + + return nanomips_regnum (gdbarch)->fpr + NANOMIPS_FP0_REGNUM; +} + +/* Return 1 if REGNUM refers to a floating-point general register, raw + or cooked. Otherwise return 0. */ + +static int +nanomips_float_register_p (struct gdbarch *gdbarch, int regnum) +{ + int rawnum = regnum % gdbarch_num_regs (gdbarch); + int fprnum = nanomips_regnum (gdbarch)->fpr; + + return (fprnum != -1 + && rawnum >= fprnum + NANOMIPS_FP0_REGNUM + && rawnum < fprnum + NANOMIPS_FCSR_REGNUM); +} + +/* Return 1 if REGNUM refers to a floating-point control register, raw + or cooked. Otherwise return 0. */ + +static int +nanomips_float_control_register_p (struct gdbarch *gdbarch, int regnum) +{ + int rawnum = regnum % gdbarch_num_regs (gdbarch); + int fprnum = nanomips_regnum (gdbarch)->fpr; + + return (fprnum != -1 + && (rawnum == fprnum + NANOMIPS_FCSR_REGNUM + || rawnum == fprnum + NANOMIPS_FIR_REGNUM)); +} + +/* Return 1 if REGNUM refers to a DSP accumulator register, raw or cooked. + Otherwise return 0. */ + +static int +nanomips_dspacc_register_p (struct gdbarch *gdbarch, int regnum) +{ + int rawnum = regnum % gdbarch_num_regs (gdbarch); + int dspnum = nanomips_regnum (gdbarch)->dsp; + + return (dspnum != -1 + && rawnum >= dspnum + NANOMIPS_DSPHI0_REGNUM + && rawnum < dspnum + NANOMIPS_DSPCTL_REGNUM); +} + +#define FPU_TYPE(gdbarch) (gdbarch_tdep (gdbarch)->fpu_type) + +/* Return the nanoMIPS ABI associated with GDBARCH. */ +enum nanomips_abi +nanomips_abi (struct gdbarch *gdbarch) +{ + return (gdbarch_tdep (gdbarch))->nanomips_abi; +} + +int +nanomips_isa_regsize (struct gdbarch *gdbarch) +{ + return gdbarch_tdep (gdbarch)->register_size; +} + +/* Return the currently configured (or set) saved register size. */ + +unsigned int +nanomips_abi_regsize (struct gdbarch *gdbarch) +{ + switch (nanomips_abi (gdbarch)) + { + case NANOMIPS_ABI_P32: + return 4; + case NANOMIPS_ABI_P64: + return 8; + case NANOMIPS_ABI_UNKNOWN: + default: + internal_error_loc (__FILE__, __LINE__, _("bad switch")); + } +} + +static void +nanomips_xfer_register (struct gdbarch *gdbarch, struct regcache *regcache, + int reg_num, int length, + enum bfd_endian endian, gdb_byte *in, + const gdb_byte *out, int buf_offset) +{ + int reg_offset = 0; + + gdb_assert (reg_num >= gdbarch_num_regs (gdbarch)); + /* Need to transfer the left or right part of the register, based on + the targets byte order. */ + switch (endian) + { + case BFD_ENDIAN_BIG: + reg_offset = register_size (gdbarch, reg_num) - length; + break; + case BFD_ENDIAN_LITTLE: + reg_offset = 0; + break; + case BFD_ENDIAN_UNKNOWN: /* Indicates no alignment. */ + reg_offset = 0; + break; + default: + internal_error_loc (__FILE__, __LINE__, _("bad switch")); + } + if (nanomips_debug) + gdb_printf (gdb_stderr, + "xfer $%d, reg offset %d, buf offset %d, length %d, ", + reg_num, reg_offset, buf_offset, length); + if (nanomips_debug && out != NULL) + { + int i; + gdb_printf (gdb_stdlog, "out "); + for (i = 0; i < length; i++) + gdb_printf (gdb_stdlog, "%02x", out[buf_offset + i]); + } + if (in != NULL) + regcache->cooked_read_part (reg_num, reg_offset, length, in + buf_offset); + if (out != NULL) + regcache->cooked_write_part (reg_num, reg_offset, length, out + buf_offset); + if (nanomips_debug && in != NULL) + { + int i; + gdb_printf (gdb_stdlog, "in "); + for (i = 0; i < length; i++) + gdb_printf (gdb_stdlog, "%02x", in[buf_offset + i]); + } + if (nanomips_debug) + gdb_printf (gdb_stdlog, "\n"); +} + +#define VM_MIN_ADDRESS (CORE_ADDR)0x400000 + +static CORE_ADDR heuristic_proc_start (struct gdbarch *, CORE_ADDR); + +static void reinit_frame_cache_sfunc (const char *, int, struct cmd_list_element *); + +/* The list of available "set nanomips " and "show nanomips " commands. */ + +static struct cmd_list_element *setnanomipscmdlist = NULL; +static struct cmd_list_element *shownanomipscmdlist = NULL; + +/* Return the name of the register corresponding to REGNO. */ + +static const char * +nanomips_register_name (struct gdbarch *gdbarch, int regno) +{ + /* GPR names for p32 and p64 ABIs. */ + static const char *const gpr_names[] = { + "zero", "at", "t4", "t5", "a0", "a1", "a2", "a3", + "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "raw_fp", "ra" + }; + + const char *name; + /* Map [gdbarch_num_regs .. 2*gdbarch_num_regs) onto the raw registers, + but then don't make the raw register names visible. This (upper) + range of user visible register numbers are the pseudo-registers. + + This approach was adopted accommodate the following scenario: + It is possible to debug a 64-bit device using a 32-bit + programming model. In such instances, the raw registers are + configured to be 64-bits wide, while the pseudo registers are + configured to be 32-bits wide. The registers that the user + sees - the pseudo registers - match the users expectations + given the programming model being used. */ + int rawnum = regno % gdbarch_num_regs (gdbarch); + if (regno < gdbarch_num_regs (gdbarch)) + return ""; + + name = tdesc_register_name (gdbarch, rawnum); + + if (rawnum >= 0 && rawnum < 32) + { + gdb_assert (name != NULL && name[0] != 0); + gdb_assert ((sizeof (gpr_names) / sizeof (gpr_names[0])) == 32); + return gpr_names[rawnum]; + } + + return name; +} + +/* Return the groups that a nanoMIPS register can be categorised into. */ + +static int +nanomips_register_reggroup_p (struct gdbarch *gdbarch, int regnum, + const struct reggroup *reggroup) +{ + int vector_p; + int float_p; + int raw_p; + int rawnum = regnum % gdbarch_num_regs (gdbarch); + int pseudo = regnum / gdbarch_num_regs (gdbarch); + if (reggroup == all_reggroup) + return pseudo; + vector_p = (register_type (gdbarch, regnum))->is_vector (); + float_p = (nanomips_float_register_p (gdbarch, rawnum) + || nanomips_float_control_register_p (gdbarch, rawnum)); + /* FIXME: cagney/2003-04-13: Can't yet use gdbarch_num_regs + (gdbarch), as not all architectures are multi-arch. */ + raw_p = rawnum < gdbarch_num_regs (gdbarch); + if (gdbarch_register_name (gdbarch, regnum) == NULL + || gdbarch_register_name (gdbarch, regnum)[0] == '\0') + return 0; + if (reggroup == float_reggroup) + return float_p && pseudo; + if (reggroup == vector_reggroup) + return vector_p && pseudo; + if (reggroup == general_reggroup) + return (!vector_p && !float_p) && pseudo; + /* Save the pseudo registers. Need to make certain that any code + extracting register values from a saved register cache also uses + pseudo registers. */ + if (reggroup == save_reggroup) + return raw_p && pseudo; + /* Restore the same pseudo register. */ + if (reggroup == restore_reggroup) + return raw_p && pseudo; + return 0; +} + +/* Return the groups that a nanoMIPS register can be categorised into. + This version is only used if we have a target description which + describes real registers (and their groups). */ + +static int +nanomips_tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regnum, + const struct reggroup *reggroup) +{ + int rawnum = regnum % gdbarch_num_regs (gdbarch); + int pseudo = regnum / gdbarch_num_regs (gdbarch); + int ret; + + /* Only save, restore, and display the pseudo registers. Need to + make certain that any code extracting register values from a + saved register cache also uses pseudo registers. + + Note: saving and restoring the pseudo registers is slightly + strange; if we have 64 bits, we should save and restore all + 64 bits. But this is hard and has little benefit. */ + if (!pseudo) + return 0; + + ret = tdesc_register_in_reggroup_p (gdbarch, rawnum, reggroup); + if (ret != -1) + return ret; + + return nanomips_register_reggroup_p (gdbarch, regnum, reggroup); +} + +/* Map the symbol table registers which live in the range [1 * + gdbarch_num_regs .. 2 * gdbarch_num_regs) back onto the corresponding raw + registers. Take care of alignment and size problems. */ + +static enum register_status +nanomips_pseudo_register_read (struct gdbarch *gdbarch, + struct readable_regcache *regcache, + int cookednum, gdb_byte *buf) +{ + int rawnum = cookednum % gdbarch_num_regs (gdbarch); + gdb_assert (cookednum >= gdbarch_num_regs (gdbarch) + && cookednum < 2 * gdbarch_num_regs (gdbarch)); + if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum)) + return regcache->raw_read (rawnum, buf); + else if (register_size (gdbarch, rawnum) > + register_size (gdbarch, cookednum)) + { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + LONGEST regval; + enum register_status status; + + status = regcache->raw_read (rawnum, ®val); + if (status == REG_VALID) + store_signed_integer (buf, 4, byte_order, regval); + return status; + } + else + internal_error_loc (__FILE__, __LINE__, _("bad register size")); +} + +static void +nanomips_pseudo_register_write (struct gdbarch *gdbarch, + struct regcache *regcache, int cookednum, + const gdb_byte *buf) +{ + int rawnum = cookednum % gdbarch_num_regs (gdbarch); + gdb_assert (cookednum >= gdbarch_num_regs (gdbarch) + && cookednum < 2 * gdbarch_num_regs (gdbarch)); + if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum)) + regcache->raw_write (rawnum, buf); + else if (register_size (gdbarch, rawnum) > + register_size (gdbarch, cookednum)) + { + /* Sign extend the shortened version of the register prior + to placing it in the raw register. This is required for + some mips64 parts in order to avoid unpredictable behavior. */ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + LONGEST regval = extract_signed_integer (buf, 4, byte_order); + regcache_raw_write_signed (regcache, rawnum, regval); + } + else + internal_error_loc (__FILE__, __LINE__, _("bad register size")); +} + +static int +nanomips_ax_pseudo_register_collect (struct gdbarch *gdbarch, + struct agent_expr *ax, int reg) +{ + int rawnum = reg % gdbarch_num_regs (gdbarch); + gdb_assert (reg >= gdbarch_num_regs (gdbarch) + && reg < 2 * gdbarch_num_regs (gdbarch)); + + ax_reg_mask (ax, rawnum); + + return 0; +} + +static int +nanomips_ax_pseudo_register_push_stack (struct gdbarch *gdbarch, + struct agent_expr *ax, int reg) +{ + int rawnum = reg % gdbarch_num_regs (gdbarch); + gdb_assert (reg >= gdbarch_num_regs (gdbarch) + && reg < 2 * gdbarch_num_regs (gdbarch)); + if (register_size (gdbarch, rawnum) >= register_size (gdbarch, reg)) + { + ax_reg (ax, rawnum); + + if (register_size (gdbarch, rawnum) > register_size (gdbarch, reg)) + { + if (gdbarch_byte_order (gdbarch) != BFD_ENDIAN_BIG) + { + ax_const_l (ax, 32); + ax_simple (ax, aop_lsh); + } + ax_const_l (ax, 32); + ax_simple (ax, aop_rsh_signed); + } + } + else + internal_error_loc (__FILE__, __LINE__, _("bad register size")); + + return 0; +} + +/* Table to translate nanomips 3-bit register field to + actual register number. */ +static const signed char reg3_to_reg[8] = { 16, 17, 18, 19, 4, 5, 6, 7 }; + +/* Heuristic_proc_start may hunt through the text section for a long + time across a 2400 baud serial line. Allows the user to limit this + search. */ + +static int heuristic_fence_post = 0; + +/* Convert to/from a register and the corresponding memory value. */ + +/* This predicate tests for the case of a 4 byte floating point + value that is being transferred to or from a floating point + register which is 8 bytes wide. */ + +static int +nanomips_convert_register_float_case_p (struct gdbarch *gdbarch, int regnum, + struct type *type) +{ + return (register_size (gdbarch, regnum) == 8 + && nanomips_float_register_p (gdbarch, regnum) + && type->code () == TYPE_CODE_FLT && type->length () == 4); +} + +/* This predicate tests for the case of a value of less than 8 + bytes in width that is being transfered to or from an 8 byte + general purpose register. */ +static int +nanomips_convert_register_gpreg_case_p (struct gdbarch *gdbarch, int regnum, + struct type *type) +{ + int num_regs = gdbarch_num_regs (gdbarch); + + return (register_size (gdbarch, regnum) == 8 + && regnum % num_regs > 0 && regnum % num_regs < 32 + && type->length () < 8); +} + +static int +nanomips_convert_register_p (struct gdbarch *gdbarch, + int regnum, struct type *type) +{ + return (nanomips_convert_register_float_case_p (gdbarch, regnum, type) + || nanomips_convert_register_gpreg_case_p (gdbarch, regnum, type)); +} + +static int +nanomips_register_to_value (frame_info_ptr frame, int regnum, + struct type *type, gdb_byte *to, + int *optimizedp, int *unavailablep) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + + if (nanomips_convert_register_float_case_p (gdbarch, regnum, type)) + { + /* single comes from low half of 64-bit register */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + { + if (!get_frame_register_bytes (frame, regnum, 4, {to + 0, 4}, + optimizedp, unavailablep)) + return 0; + } + else + { + if (!get_frame_register_bytes (frame, regnum, 0, {to + 0, 4}, + optimizedp, unavailablep)) + return 0; + } + *optimizedp = *unavailablep = 0; + return 1; + } + else if (nanomips_convert_register_gpreg_case_p (gdbarch, regnum, type)) + { + int len = type->length (); + CORE_ADDR offset; + + offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 8 - len : 0; + if (!get_frame_register_bytes (frame, regnum, offset, {to, (size_t)len}, + optimizedp, unavailablep)) + return 0; + + *optimizedp = *unavailablep = 0; + return 1; + } + else + { + internal_error_loc (__FILE__, __LINE__, + _("nanomips_register_to_value: unrecognized case")); + } +} + +static void +nanomips_value_to_register (frame_info_ptr frame, int regnum, + struct type *type, const gdb_byte *from) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + + if (nanomips_convert_register_float_case_p (gdbarch, regnum, type)) + { + /* single goes in low half of 64-bit register */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + put_frame_register_bytes (frame, regnum, 4, {from, 4}); + else + put_frame_register_bytes (frame, regnum, 0, {from, 4}); + } + else if (nanomips_convert_register_gpreg_case_p (gdbarch, regnum, type)) + { + gdb_byte fill[8]; + int len = type->length (); + + /* Sign extend values, irrespective of type, that are stored to + a 64-bit general purpose register. (32-bit unsigned values + are stored as signed quantities within a 64-bit register. + When performing an operation, in compiled code, that combines + a 32-bit unsigned value with a signed 64-bit value, a type + conversion is first performed that zeroes out the high 32 bits.) */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + { + if (from[0] & 0x80) + store_signed_integer (fill, 8, BFD_ENDIAN_BIG, -1); + else + store_signed_integer (fill, 8, BFD_ENDIAN_BIG, 0); + put_frame_register_bytes (frame, regnum, 0, {fill, (size_t)(8 - len)}); + put_frame_register_bytes (frame, regnum, 8 - len, {from, (size_t)len}); + } + else + { + if (from[len-1] & 0x80) + store_signed_integer (fill, 8, BFD_ENDIAN_LITTLE, -1); + else + store_signed_integer (fill, 8, BFD_ENDIAN_LITTLE, 0); + put_frame_register_bytes (frame, regnum, 0, {from, (size_t)len}); + put_frame_register_bytes (frame, regnum, len, {fill, (size_t)(8 - len)}); + } + } + else + { + internal_error_loc (__FILE__, __LINE__, + _("nanomips_value_to_register: unrecognized case")); + } +} + +/* Return the GDB type for the pseudo register REGNUM, which is the + ABI-level view. This function is only called if there is a target + description which includes registers, so we know precisely the + types of hardware registers. */ + +static struct type * +nanomips_pseudo_register_type (struct gdbarch *gdbarch, int regnum) +{ + const int num_regs = gdbarch_num_regs (gdbarch); + int rawnum = regnum % num_regs; + struct type *rawtype; + + gdb_assert (regnum >= num_regs && regnum < 2 * num_regs); + + /* Absent registers are still absent. */ + rawtype = gdbarch_register_type (gdbarch, rawnum); + if (rawtype->length () == 0) + return rawtype; + + /* Present the floating point registers however the hardware did; + do not try to convert between FPU layouts. */ + if (nanomips_float_register_p (gdbarch, rawnum)) + return rawtype; + + /* Floating-point control registers are always 32-bit even though for + backwards compatibility reasons 64-bit targets will transfer them + as 64-bit quantities even if using XML descriptions. */ + if (nanomips_float_control_register_p (gdbarch, rawnum)) + return builtin_type (gdbarch)->builtin_int32; + + /* Use pointer types for registers if we can. For n32 we can not, + since we do not have a 64-bit pointer type. */ + if (nanomips_abi_regsize (gdbarch) + == (builtin_type (gdbarch)->builtin_data_ptr)->length()) + { + if (rawnum == NANOMIPS_SP_REGNUM + || rawnum == nanomips_regnum (gdbarch)->badvaddr) + return builtin_type (gdbarch)->builtin_data_ptr; + else if (rawnum == NANOMIPS_PC_REGNUM) + return builtin_type (gdbarch)->builtin_func_ptr; + } + + if (nanomips_abi_regsize (gdbarch) == 4 && rawtype->length () == 8 + && ((rawnum >= NANOMIPS_ZERO_REGNUM && rawnum <= NANOMIPS_PC_REGNUM) + || rawnum == nanomips_regnum (gdbarch)->badvaddr + || rawnum == nanomips_regnum (gdbarch)->status + || rawnum == nanomips_regnum (gdbarch)->cause + || nanomips_dspacc_register_p (gdbarch, rawnum))) + return builtin_type (gdbarch)->builtin_int32; + + /* For all other registers, pass through the hardware type. */ + return rawtype; +} + +/* Should the upper word of 64-bit addresses be zeroed? */ +static enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO; + +static int +nanomips_mask_address_p (const struct nanomips_gdbarch_tdep *tdep) +{ + switch (mask_address_var) + { + case AUTO_BOOLEAN_TRUE: + return 1; + case AUTO_BOOLEAN_FALSE: + return 0; + break; + case AUTO_BOOLEAN_AUTO: + return tdep->default_mask_address_p; + default: + internal_error_loc (__FILE__, __LINE__, + _("nanomips_mask_address_p: bad switch")); + return -1; + } +} + +static void +show_mask_address (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + struct nanomips_gdbarch_tdep *tdep = (struct nanomips_gdbarch_tdep*) (target_gdbarch ()); + + deprecated_show_value_hack (file, from_tty, c, value); + switch (mask_address_var) + { + case AUTO_BOOLEAN_TRUE: + gdb_printf ("The 32 bit nanomips address mask is enabled\n"); + break; + case AUTO_BOOLEAN_FALSE: + gdb_printf ("The 32 bit nanomips address mask is disabled\n"); + break; + case AUTO_BOOLEAN_AUTO: + gdb_printf + ("The 32 bit address mask is set automatically. Currently %s\n", + nanomips_mask_address_p (tdep) ? "enabled" : "disabled"); + break; + default: + internal_error_loc (__FILE__, __LINE__, _("show_mask_address: bad switch")); + break; + } +} + +/* nanoMIPS believes that the PC has a sign extended value. Perhaps + all registers should be sign extended for simplicity? */ + +static CORE_ADDR +nanomips_read_pc (struct readable_regcache *regcache) +{ + int regnum = gdbarch_pc_regnum (regcache->arch ()); + LONGEST pc; + + regcache->cooked_read (regnum, &pc); + return pc; +} + +static CORE_ADDR +nanomips_unwind_pc (struct gdbarch *gdbarch, frame_info_ptr next_frame) +{ + return frame_unwind_register_signed + (next_frame, gdbarch_pc_regnum (gdbarch)); +} + +static CORE_ADDR +nanomips_unwind_sp (struct gdbarch *gdbarch, frame_info_ptr next_frame) +{ + return frame_unwind_register_signed + (next_frame, gdbarch_num_regs (gdbarch) + NANOMIPS_SP_REGNUM); +} + +/* Assuming THIS_FRAME is a dummy, return the frame ID of that + dummy frame. The frame ID's base needs to match the TOS value + saved by save_dummy_frame_tos(), and the PC match the dummy frame's + breakpoint. */ + +static struct frame_id +nanomips_dummy_id (struct gdbarch *gdbarch, frame_info_ptr this_frame) +{ + return frame_id_build + (get_frame_register_signed (this_frame, + gdbarch_num_regs (gdbarch) + + NANOMIPS_SP_REGNUM), + get_frame_pc (this_frame)); +} + +/* Implement the "write_pc" gdbarch method. */ + +void +nanomips_write_pc (struct regcache *regcache, CORE_ADDR pc) +{ + int regnum = gdbarch_pc_regnum (regcache->arch ()); + regcache_cooked_write_unsigned (regcache, regnum, pc); +} + +/* Fetch and return 16-bit instruction from the specified location. */ + +static ULONGEST +nanomips_fetch_stack_slot (struct gdbarch *gdbarch, CORE_ADDR sp, int offset) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + return read_memory_unsigned_integer (sp + offset, 4, byte_order); +} + +static ULONGEST +nanomips_fetch_instruction (struct gdbarch *gdbarch, + CORE_ADDR addr, int *errp) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte buf[INSN16_SIZE]; + int err; + + err = target_read_memory (addr, buf, INSN16_SIZE); + if (errp != NULL) + *errp = err; + if (err != 0) + { + if (errp == NULL) + memory_error (TARGET_XFER_E_IO, addr); + return 0; + } + return extract_unsigned_integer (buf, INSN16_SIZE, byte_order); +} + +/* MicroMIPS instruction fields. */ +#define micromips_op(x) ((x) >> 10) + +/* 16-bit/32-bit-high-part instruction formats, B and S refer to the lowest + bit and the size respectively of the field extracted. */ +#define b0s4_imm(x) ((x) & 0xf) +#define b0s5_imm(x) ((x) & 0x1f) +#define b0s5_reg(x) ((x) & 0x1f) +#define b0s7_imm(x) ((x) & 0x7f) +#define b0s8_imm(x) ((x) & 0xff) +#define b0s10_imm(x) ((x) & 0x3ff) +#define b0u13_15s1_imm(x) (((x) & 0x1fff) | (((x) & 0x8000) >> 2)) +#define b1s4_imm(x) (((x) >> 1) & 0xf) +#define b1s9_imm(x) (((x) >> 1) & 0x1ff) +#define b2s1_op(x) (((x) >> 2) & 0x1) +#define b2s3_cc(x) (((x) >> 2) & 0x7) +#define b3s2_op(x) (((x) >> 3) & 0x3) +#define b3s9_imm(x) (((x) >> 3) & 0x1ff) +#define b4s2_regl(x) (((x) >> 4) & 0x3) +#define b4s3_reg(x) (((x) >> 4) & 0x7) +#define b4s4_imm(x) (((x) >> 4) & 0xf) +#define b5s5_op(x) (((x) >> 5) & 0x1f) +#define b5s5_reg(x) (((x) >> 5) & 0x1f) +#define b6s4_op(x) (((x) >> 6) & 0xf) +#define b7s3_reg(x) (((x) >> 7) & 0x7) +#define b8s2_regl(x) (((x) >> 8) & 0x3) +#define b8s7_op(x) (((x) >> 8) & 0x7f) + +/* 32-bit instruction formats, B and S refer to the lowest bit and the size + respectively of the field extracted. */ +#define b0s6_op(x) ((x) & 0x3f) +#define b0s10_op(x) ((x) & 0x3ff) +#define b0s11_op(x) ((x) & 0x7ff) +#define b0s12_imm(x) ((x) & 0xfff) +#define b0u16_imm(x) ((x) & 0xffff) +#define b0s21_imm(x) ((x) & 0x1fffff) +#define b0s26_imm(x) ((x) & 0x3ffffff) +#define b6s10_ext(x) (((x) >> 6) & 0x3ff) +#define b9s3_op(x) (((x) >> 9) & 0x7) +#define b11s5_reg(x) (((x) >> 11) & 0x1f) +#define b16s5_reg(x) (((x) >> 16) & 0x1f) +#define b21s5_reg(x) (((x) >> 21) & 0x1f) +#define b11s7_imm(x) (((x) >> 11) & 0x7f) +#define b12s4_op(x) (((x) >> 12) & 0xf) +#define b12s5_op(x) (((x) >> 12) & 0x1f) +#define b14s2_op(x) (((x) >> 14) & 0x3) +#define b16s4_imm(x) (((x) >> 16) & 0xf) + +/* Return the size in bytes of the instruction INSN encoded in the ISA + instruction set. */ + +static int +nanomips_insn_size (ULONGEST insn) +{ + if (micromips_op (insn) == 0x18) + return 3 * INSN16_SIZE; + else if ((micromips_op (insn) & 0x4) == 0x0) + return 2 * INSN16_SIZE; + else + return INSN16_SIZE; +} + +/* Calculate the address of the next nanoMIPS instruction to execute + after the instruction at the address PC. The nanomips_next_pc + function supports single_step when the remote target monitor or stub + is not developed enough to do a single_step. It works by decoding the + current instruction and predicting where a branch will go. This isn't + hard because all the data is available. */ + +static CORE_ADDR +nanomips_next_pc (struct regcache *regcache, CORE_ADDR pc) +{ + struct gdbarch *gdbarch = regcache->arch (); + ULONGEST insn; + CORE_ADDR offset, sp, ra; + int op, sreg, treg, uimm, count; + LONGEST val_rs, val_rt; + + insn = nanomips_fetch_instruction (gdbarch, pc, NULL); + pc += INSN16_SIZE; + switch (nanomips_insn_size (insn)) + { + /* 48-bit instructions. */ + case 3 * INSN16_SIZE: + /* No branch or jump instructions in this category. */ + pc += 2 * INSN16_SIZE; + break; + + /* 32-bit instructions. */ + case 2 * INSN16_SIZE: + insn <<= 16; + insn |= nanomips_fetch_instruction (gdbarch, pc, NULL); + pc += INSN16_SIZE; + switch (micromips_op (insn >> 16)) + { + case 0x0: /* P32 */ + op = b5s5_op (insn >> 16); + switch (op) + { + case 0x0: /* P.RI */ + switch (b3s2_op (insn >> 16)) + { + case 0x1: /* SYSCALL */ + if (b2s1_op (insn >> 16) == 0) + { + struct nanomips_gdbarch_tdep *tdep; + + tdep = gdbarch_tdep (gdbarch); + if (tdep->syscall_next_pc != NULL) + pc = tdep->syscall_next_pc (get_current_frame (), pc); + } + break; + } + break; + } + break; + + case 0x2: /* MOVE.BALC */ + offset = ((insn & 1) << 20 | ((insn >> 1) & 0xfffff)) << 1; + offset = (offset ^ 0x200000) - 0x200000; + pc += offset; + break; + + case 0xa: /* BALC, BC */ + offset = ((insn & 1) << 24 | ((insn >> 1) & 0xffffff)) << 1; + offset = (offset ^ 0x2000000) - 0x2000000; + pc += offset; + break; + + case 0x12: /* P.J P.BREG P.BALRC P.BALRSC */ + op = b12s4_op (insn); + sreg = b0s5_reg (insn >> 16); + treg = b5s5_reg (insn >> 16); + if (op == 0x8) /* BALRSC, BRSC */ + { + val_rs = regcache_raw_get_signed (regcache, sreg); + pc += (val_rs << 1); + } + else if (op == 0 || op == 1) /* JALRC JALRC.HB */ + pc = regcache_raw_get_signed (regcache, sreg); + break; + + case 0x20: /* PP.SR */ + if ((b12s4_op (insn) == 0x3) && ((insn & 3) == 3)) /* RESTORE.JRC */ + { + sp = regcache_raw_get_signed (regcache, NANOMIPS_SP_REGNUM); + ra = regcache_raw_get_signed (regcache, NANOMIPS_RA_REGNUM); + sp += (((insn >> 3) & 0x1ff) << 3); + count = ((insn >> 16) & 0xf); + treg = b5s5_reg(insn >> 16); + if (count != 0 && treg <= 31 && (treg + count) > 31) + ra = nanomips_fetch_stack_slot (gdbarch, sp, -(31 - treg + 1) * 4); + pc = ra; + } + break; + + case 0x22: /* P.BR1 */ + op = b14s2_op (insn); + sreg = b0s5_reg (insn >> 16); + treg = b5s5_reg (insn >> 16); + val_rs = regcache_raw_get_signed (regcache, sreg); + val_rt = regcache_raw_get_signed (regcache, treg); + offset = ((insn & 1) << 13 | ((insn >> 1) & 0x1fff)) << 1; + offset = (offset ^ 0x4000) - 0x4000; + if ((op == 0 && val_rs == val_rt) /* BEQC */ + || (op == 2 && val_rs >= val_rt) /* BGEC */ + || (op == 3 + && (ULONGEST) val_rs >= (ULONGEST) val_rt)) /* BGEUC */ + pc += offset; + break; + + case 0x2a: /* P.BR2 */ + op = b14s2_op (insn); + sreg = b0s5_reg (insn >> 16); + treg = b5s5_reg (insn >> 16); + val_rs = regcache_raw_get_signed (regcache, sreg); + val_rt = regcache_raw_get_signed (regcache, treg); + offset = ((insn & 1) << 13 | ((insn >> 1) & 0x1fff)) << 1; + offset = (offset ^ 0x4000) - 0x4000; + if ((op == 0 && val_rs != val_rt) /* BNEC */ + || (op == 2 && val_rs < val_rt) /* BLTC */ + || (op == 3 + && (ULONGEST) val_rs < (ULONGEST) val_rt)) /* BLTUC */ + pc += offset; + break; + + case 0x32: /* P.BRI */ + op = b2s3_cc (insn >> 16); + treg = b5s5_reg (insn >> 16); + val_rt = regcache_raw_get_signed (regcache, treg); + offset = ((insn & 1) << 10 | ((insn >> 1) & 0x3ff)) << 1; + offset = (offset ^ 0x800) - 0x800; + uimm = b11s7_imm (insn); + if ((op == 0 && val_rt == uimm) /* BEQIC */ + || (op == 1 && ((val_rt & (1 << uimm)) == 0)) /* BBEQZC */ + || (op == 2 && val_rt >= uimm) /* BGEIC */ + || (op == 3 && (ULONGEST) val_rt >= uimm) /* BGEIUC */ + || (op == 4 && val_rt != uimm) /* BNEIC */ + || (op == 5 && ((val_rt & (1 << uimm)) != 0)) /* BBNEZC */ + || (op == 6 && val_rt < uimm) /* BLTIC */ + || (op == 7 && (ULONGEST) val_rt < uimm)) /* BLTIUC */ + pc += offset; + break; + + case 0x3a: /* P.BZ */ + op = (insn & 0x80000); /* 20th bit */ + treg = b5s5_reg (insn >> 16); + val_rt = regcache_raw_get_signed (regcache, treg); + offset = ((insn & 1) << 19 | ((insn >> 1) & 0x7ffff)) << 1; + offset = (offset ^ 0x100000) - 0x100000; + if ((op == 0 && val_rt == 0) /* BEQZC */ + || (op != 0 && val_rt != 0)) /* BNEZC */ + pc += offset; + break; + + default: + break; + } + break; + + /* 16-bit instructions. */ + case INSN16_SIZE: + switch (micromips_op (insn)) + { + case 0x4: /* P16 */ + op = b5s5_op (insn); + switch (op) + { + case 0x0: /* P16.RI */ + switch (b3s2_op (insn)) + { + case 0x1: /* SYSCALL[16] */ + if (b2s1_op (insn) == 0) + { + struct nanomips_gdbarch_tdep *tdep; + + tdep = gdbarch_tdep (gdbarch); + if (tdep->syscall_next_pc != NULL) + pc = tdep->syscall_next_pc (get_current_frame (), pc); + } + break; + } + break; + } + break; + + case 0x6: /* BC[16] */ + case 0xe: /* BALC[16] */ + offset = ((insn & 1) << 9 | ((insn >> 1) & 0x1ff)) << 1; + offset = (offset ^ 0x400) - 0x400; + pc += offset; + break; + + case 0x7: /* RESTORE.JRC[16] */ + if ((insn & 1) == 0 && (insn & 0x20) == 0x20 && ((insn >> 8) & 1) == 1) + { + sp = regcache_raw_get_signed (regcache, NANOMIPS_SP_REGNUM); + ra = regcache_raw_get_signed (regcache, NANOMIPS_RA_REGNUM); + sp += (((insn >> 4) & 0xf) << 4); + count = insn & 0xf; + treg = ((insn >> 9) & 0x1) ? NANOMIPS_RA_REGNUM : NANOMIPS_FP_REGNUM; + if (count != 0 && treg + count > 31) { + ra = nanomips_fetch_stack_slot (gdbarch, sp, -(31 - treg + 1) * 4); + } + pc = ra; + } + break; + + case 0x26: /* BEQZC[16] */ + treg = reg3_to_reg[b7s3_reg (insn)]; + val_rt = regcache_raw_get_signed (regcache, treg); + offset = ((insn & 1) << 6 | ((insn >> 1) & 0x3f)) << 1; + offset = (offset ^ 0x80) - 0x80; + if (val_rt == 0) + pc += offset; + break; + + case 0x2e: /* BNEZC[16] */ + treg = reg3_to_reg[b7s3_reg (insn)]; + val_rt = regcache_raw_get_signed (regcache, treg); + offset = ((insn & 1) << 6 | ((insn >> 1) & 0x3f)) << 1; + offset = (offset ^ 0x80) - 0x80; + if (val_rt != 0) + pc += offset; + break; + + case 0x36: /* P16.BR P16.JRC */ + sreg = b4s3_reg (insn); + treg = b7s3_reg (insn); + val_rs = regcache_raw_get_signed (regcache, reg3_to_reg[sreg]); + val_rt = regcache_raw_get_signed (regcache, reg3_to_reg[treg]); + offset = insn & 0xf; + /* BEQC[16] BEQC[16] */ + if ((sreg < treg && offset != 0 && val_rs == val_rt) + || (sreg >= treg && offset != 0 && val_rs != val_rt)) + pc += (offset << 1); + else if (offset == 0) /* JALRC[16] JRC */ + pc = regcache_raw_get_signed (regcache, b5s5_reg(insn)); + break; + + default: + break; + } + break; + + default: + break; + } + return pc; +} + +struct nanomips_frame_cache +{ + CORE_ADDR base; + struct trad_frame_saved_reg *saved_regs; +}; + +/* Set a register's saved stack address in temp_saved_regs. If an + address has already been set for this register, do nothing; this + way we will only recognize the first save of a given register in a + function prologue. + + For simplicity, save the address in both [0 .. gdbarch_num_regs) and + [gdbarch_num_regs .. 2*gdbarch_num_regs). + Strictly speaking, only the second range is used as it is only second + range (the ABI instead of ISA registers) that comes into play when finding + saved registers in a frame. */ + +static void +set_reg_offset (struct gdbarch *gdbarch, struct nanomips_frame_cache *this_cache, + int regnum, CORE_ADDR offset) +{ + if (this_cache != NULL + && this_cache->saved_regs[regnum].addr() == -1) + { + this_cache->saved_regs[regnum + 0 * gdbarch_num_regs (gdbarch)].set_addr( + offset); + this_cache->saved_regs[regnum + 1 * gdbarch_num_regs (gdbarch)].set_addr( + offset); + } +} + +/* Analyze the function prologue from START_PC to LIMIT_PC. Return + the address of the first instruction past the prologue. */ + +static CORE_ADDR +nanomips_scan_prologue (struct gdbarch *gdbarch, + CORE_ADDR start_pc, CORE_ADDR limit_pc, + frame_info_ptr this_frame, + struct nanomips_frame_cache *this_cache) +{ + CORE_ADDR end_prologue_addr; + int prev_non_prologue_insn = 0; + int frame_reg = NANOMIPS_SP_REGNUM; + int this_non_prologue_insn; + int non_prologue_insns = 0; + long frame_offset = 0; /* Size of stack frame. */ + long frame_adjust = 0; /* Offset of FP from SP. */ + CORE_ADDR prev_pc; + CORE_ADDR cur_pc; + ULONGEST insn; /* current instruction */ + CORE_ADDR sp; + long offset; + long sp_adj; + long v1_off = 0; /* The assumption is LUI will replace it. */ + int breg; + int dreg; + int sreg; + int treg; + int loc; + int op; + + /* Can be called when there's no process, and hence when there's no + THIS_FRAME. */ + if (this_frame != NULL) + sp = get_frame_register_signed (this_frame, + gdbarch_num_regs (gdbarch) + + NANOMIPS_SP_REGNUM); + else + sp = 0; + + if (limit_pc > start_pc + 200) + limit_pc = start_pc + 200; + prev_pc = start_pc; + + /* Permit at most one non-prologue non-control-transfer instruction + in the middle which may have been reordered by the compiler for + optimisation. */ + for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += loc) + { + this_non_prologue_insn = 0; + sp_adj = 0; + loc = 0; + insn = nanomips_fetch_instruction (gdbarch, cur_pc, NULL); + loc += INSN16_SIZE; + switch (nanomips_insn_size (insn)) + { + /* 48-bit instructions. */ + case 3 * INSN16_SIZE: + if (micromips_op (insn) == 0x18) + { + op = b0s5_imm (insn); + treg = b5s5_reg (insn); + offset = nanomips_fetch_instruction (gdbarch, cur_pc + 2, NULL); + offset <<= 16; + offset |= nanomips_fetch_instruction (gdbarch, cur_pc + 4, NULL); + if (op == 0x0 && treg == 3) /* LI48 $v1, imm32 */ + v1_off = offset; + else if (op == 0x1 /* ADDIU48 $sp, imm32 */ + && treg == NANOMIPS_SP_REGNUM) + sp_adj = offset; + else + this_non_prologue_insn = 1; + } + else + this_non_prologue_insn = 1; + break; + + /* 32-bit instructions. */ + case 2 * INSN16_SIZE: + insn <<= 16; + insn |= nanomips_fetch_instruction (gdbarch, + cur_pc + loc, NULL); + loc += INSN16_SIZE; + + switch (micromips_op (insn >> 16)) + { + case 0x0: /* PP.ADDIU bits 000000 */ + sreg = b0s5_reg (insn >> 16); + treg = b5s5_reg (insn >> 16); + offset = b0u16_imm (insn); + if (sreg == treg + && treg == NANOMIPS_SP_REGNUM) /* ADDIU $sp, $sp, imm */ + sp_adj = offset; + else if (sreg == NANOMIPS_SP_REGNUM + && treg == NANOMIPS_FP_REGNUM) /* ADDIU $fp, $sp, imm */ + { + frame_adjust = offset; + frame_reg = NANOMIPS_FP_REGNUM; + } + else if (sreg != NANOMIPS_GP_REGNUM + || treg != NANOMIPS_GP_REGNUM) + this_non_prologue_insn = 1; + break; + + case 0x8: /* P32A: bits 001000 */ + op = b0s10_op (insn); + sreg = b0s5_reg (insn >> 16); + treg = b5s5_reg (insn >> 16); + dreg = b11s5_reg (insn); + if (op == 0x1d0 /* SUBU: bits 001000 0111010000 */ + && dreg == NANOMIPS_SP_REGNUM && sreg == NANOMIPS_SP_REGNUM + && treg == 3) /* SUBU $sp, $v1 */ + sp_adj = v1_off; + else + this_non_prologue_insn = 1; + break; + + case 0x20: /* P.U12 bits 100000 */ + /* SAVE: bits 100000 rt 0 count 0011 */ + if (b12s4_op (insn) == 0x3) + { + int rt, this_rt, gp, use_gp; + int counter = 0, count = b16s4_imm (insn); + long this_offset; + offset = b3s9_imm (insn) << 3; + rt = b21s5_reg (insn); + sp_adj = -offset; + gp = (insn >> 2) & 1; + while (counter != count) + { + use_gp = gp & (counter == count - 1); + if (use_gp) + this_rt = NANOMIPS_GP_REGNUM; + else + this_rt = (((rt >> 4) & 1) << 4) | (rt + counter); + this_offset = (counter + 1) << 2; + set_reg_offset (gdbarch, this_cache, this_rt, + sp + offset - this_offset); + counter++; + } + } + else if (b12s4_op (insn) == 8) /* ADDIU[NEG]: bits 100000 1000 */ + { + sreg = b0s5_reg (insn >> 16); + treg = b5s5_reg (insn >> 16); + if (sreg == treg && sreg == NANOMIPS_SP_REGNUM) + /* ADDIU[NEG] $sp, $sp, imm */ + { + offset = b0s11_op (insn); + sp_adj = -offset; + } + } + else if (b12s4_op (insn) == 0) /* ORI: bits 100000 0000 */ + { + sreg = b0s5_reg (insn >> 16); + treg = b5s5_reg (insn >> 16); + if (sreg == treg && treg == 3) /* ORI $v1, $v1, imm */ + v1_off |= b0s11_op (insn); + else + this_non_prologue_insn = 1; + } + else + this_non_prologue_insn = 1; + break; + + case 0x21: /* P.LS.U12 bits 100001 */ + if (b12s4_op (insn) == 0x9) /* SW 100001 1001 */ + { + breg = b0s5_reg (insn >> 16); + sreg = b5s5_reg (insn >> 16); + offset = b0s12_imm (insn); + if (breg == NANOMIPS_SP_REGNUM) /* SW reg,offset($sp) */ + set_reg_offset (gdbarch, this_cache, sreg, sp + offset); + else + this_non_prologue_insn = 1; + } + break; + + case 0x29: /* P.LS.S9 bits 101001 */ + if (b8s7_op (insn) == 0x48) /* SW[S9] 101001 1001 0 00 */ + { + breg = b0s5_reg (insn >> 16); + sreg = b5s5_reg (insn >> 16); + offset = (((insn >> 15) & 1) << 8) | b0s8_imm (insn); + offset = (offset ^ 0x100) - 0x100; + if (breg == NANOMIPS_SP_REGNUM) /* SW[S9] reg,offset($sp) */ + set_reg_offset (gdbarch, this_cache, sreg, sp + offset); + else + this_non_prologue_insn = 1; + } + break; + + case 0x38: /* P.LUI bits 111000 */ + treg = b5s5_reg (insn >> 16); + if ((insn & 2) == 0 /* LU20I bits 111000 0 */ + && treg == 3) /* LU20I $v1, imm */ + { + v1_off = ((insn & 1) << 19) + | (((insn >> 2) & 0x3ff) << 9) + | (((insn >> 12) & 0x1ff)); + v1_off = v1_off << 12; + } + else + this_non_prologue_insn = 1; + break; + + default: + this_non_prologue_insn = 1; + break; + } + + insn >>= 16; + break; + + /* 16-bit instructions. */ + case INSN16_SIZE: + switch (micromips_op (insn)) + { + case 0x4: /* MOVE: bits 000100 */ + sreg = b0s5_reg (insn); + dreg = b5s5_reg (insn); + if (sreg == NANOMIPS_SP_REGNUM && dreg == NANOMIPS_FP_REGNUM) + /* MOVE $fp, $sp */ + frame_reg = NANOMIPS_FP_REGNUM; + else + this_non_prologue_insn = 1; + break; + + case 0x7: /* SAVE: bits 000111 */ + { + int rt, rt1, this_rt; + int counter = 0, count = b0s4_imm (insn); + long this_offset; + offset = b4s4_imm (insn) << 4; + rt1 = (insn >> 9) & 1; + rt = 30 | rt1; + sp_adj = -offset; + while (counter != count) + { + this_rt = (((rt >> 4) & 1) << 4) | (rt + counter); + this_offset = (counter + 1) << 2; + set_reg_offset (gdbarch, this_cache, this_rt, + sp + offset - this_offset); + counter++; + } + break; + } + + case 0x35: /* SW[SP]: bits 110101 */ + treg = b5s5_reg (insn); + offset = b0s5_imm (insn); + set_reg_offset (gdbarch, this_cache, treg, sp + offset); + break; + + default: + this_non_prologue_insn = 1; + break; + } + break; + } + + if (sp_adj < 0) + frame_offset -= sp_adj; + + non_prologue_insns += this_non_prologue_insn; + + if (non_prologue_insns > 1 || sp_adj > 0) + break; + + prev_non_prologue_insn = this_non_prologue_insn; + prev_pc = cur_pc; + } + + if (this_cache != NULL) + { + this_cache->base = + (get_frame_register_signed (this_frame, + gdbarch_num_regs (gdbarch) + frame_reg) + + frame_offset - frame_adjust); + /* FIXME: brobecker/2004-10-10: Just as in the mips32 case, we should + be able to get rid of the assignment below, evetually. But it's + still needed for now. */ + this_cache->saved_regs[gdbarch_num_regs (gdbarch) + NANOMIPS_PC_REGNUM] + = this_cache->saved_regs[gdbarch_num_regs (gdbarch) + + NANOMIPS_RA_REGNUM]; + } + + /* Set end_prologue_addr to the address of the instruction immediately + after the last one we scanned. Unless the last one looked like a + non-prologue instruction (and we looked ahead), in which case use + its address instead. */ + end_prologue_addr + = prev_non_prologue_insn ? prev_pc : cur_pc; + + return end_prologue_addr; +} + +/* Heuristic unwinder for procedures using nanoMIPS instructions. + Procedures that use the 32-bit instruction set are handled by the + mips_insn32 unwinder. Likewise MIPS16 and the mips_insn16 unwinder. */ + +static struct nanomips_frame_cache * +nanomips_frame_cache (frame_info_ptr this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct nanomips_frame_cache *cache; + + if ((*this_cache) != NULL) + return (struct nanomips_frame_cache *) (*this_cache); + + cache = FRAME_OBSTACK_ZALLOC (struct nanomips_frame_cache); + (*this_cache) = cache; + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); + + /* Analyze the function prologue. */ + { + const CORE_ADDR pc = get_frame_address_in_block (this_frame); + CORE_ADDR start_addr; + + find_pc_partial_function (pc, NULL, &start_addr, NULL); + if (start_addr == 0) + start_addr = heuristic_proc_start (get_frame_arch (this_frame), pc); + /* We can't analyze the prologue if we couldn't find the begining + of the function. */ + if (start_addr == 0) + return cache; + + nanomips_scan_prologue (gdbarch, start_addr, pc, this_frame, + (struct nanomips_frame_cache *) *this_cache); + } + + /* gdbarch_sp_regnum contains the value and not the address. */ + cache->saved_regs[gdbarch_num_regs (gdbarch) + + NANOMIPS_SP_REGNUM].set_value (cache->base); + + return (struct nanomips_frame_cache *) (*this_cache); +} + +static void +nanomips_frame_this_id (frame_info_ptr this_frame, void **this_cache, + struct frame_id *this_id) +{ + struct nanomips_frame_cache *info = nanomips_frame_cache (this_frame, + this_cache); + /* This marks the outermost frame. */ + if (info->base == 0) + return; + (*this_id) = frame_id_build (info->base, get_frame_func (this_frame)); +} + +static struct value * +nanomips_frame_prev_register (frame_info_ptr this_frame, + void **this_cache, int regnum) +{ + struct nanomips_frame_cache *info = nanomips_frame_cache (this_frame, + this_cache); + return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum); +} + +static int +nanomips_frame_sniffer (const struct frame_unwind *self, + frame_info_ptr this_frame, void **this_cache) +{ + return 1; +} + +static const struct frame_unwind nanomips_frame_unwind = +{ + "nanoMIPS insn prologue", + NORMAL_FRAME, + default_frame_unwind_stop_reason, + nanomips_frame_this_id, + nanomips_frame_prev_register, + NULL, + nanomips_frame_sniffer +}; + +static CORE_ADDR +nanomips_frame_base_address (frame_info_ptr this_frame, + void **this_cache) +{ + struct nanomips_frame_cache *info = nanomips_frame_cache (this_frame, + this_cache); + return info->base; +} + +static const struct frame_base nanomips_frame_base = +{ + &nanomips_frame_unwind, + nanomips_frame_base_address, + nanomips_frame_base_address, + nanomips_frame_base_address +}; + +static const struct frame_base * +nanomips_frame_base_sniffer (frame_info_ptr this_frame) +{ + return &nanomips_frame_base; +} + +/* nanomips_addr_bits_remove - remove useless address bits */ + +static CORE_ADDR +nanomips_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr) +{ + struct nanomips_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (nanomips_mask_address_p (tdep) + && (((ULONGEST) addr) >> 32 == 0xffffffffUL)) + /* This hack is a work-around for existing boards using PMON, the + simulator, and any other 64-bit targets that doesn't have true + 64-bit addressing. On these targets, the upper 32 bits of + addresses are ignored by the hardware. Thus, the PC or SP are + likely to have been sign extended to all 1s by instruction + sequences that load 32-bit addresses. For example, a typical + piece of code that loads an address is this: + + lui $r2, + ori $r2, + + But the lui sign-extends the value such that the upper 32 bits + may be all 1s. The workaround is simply to mask off these + bits. In the future, gcc may be changed to support true 64-bit + addressing, and this masking will have to be disabled. */ + return addr &= 0xffffffffUL; + else + return addr; +} + + +/* Checks for an atomic sequence of instructions beginning with a LL/LLD + instruction and ending with a SC/SCD instruction. If such a sequence + is found, attempt to step through it. A breakpoint is placed at the end of + the sequence. */ + +static std::vector +nanomips_deal_with_atomic_sequence (struct gdbarch *gdbarch, + CORE_ADDR pc) +{ + const int atomic_sequence_length = 16; /* Instruction sequence length. */ + int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */ + CORE_ADDR breaks[2] = {CORE_ADDR_MAX, CORE_ADDR_MAX}; + CORE_ADDR branch_bp = 0; /* Breakpoint at branch instruction's + destination. */ + CORE_ADDR loc = pc; + int sc_found = 0; + ULONGEST insn; + int insn_count; + int index; + + /* Assume all atomic sequences start with a ll/lld instruction. */ + insn = nanomips_fetch_instruction (gdbarch, loc, NULL); + if (micromips_op (insn) != 0x29) /* P.LL: bits 101001 */ + return {}; + loc += INSN16_SIZE; + insn <<= 16; + insn |= nanomips_fetch_instruction (gdbarch, loc, NULL); + if (b8s7_op (insn) != 0x51) /* LL: bits 101001 1010 0 01 */ + return {}; + loc += INSN16_SIZE; + + /* Assume all atomic sequences end with an sc/scd instruction. Assume + that no atomic sequence is longer than "atomic_sequence_length" + instructions. */ + for (insn_count = 0; + !sc_found && insn_count < atomic_sequence_length; + ++insn_count) + { + int is_branch = 0, op; + CORE_ADDR offset; + + insn = nanomips_fetch_instruction (gdbarch, loc, NULL); + loc += INSN16_SIZE; + + /* Assume that there is at most one conditional branch in the + atomic sequence. If a branch is found, put a breakpoint in + its destination address. */ + switch (nanomips_insn_size (insn)) + { + /* 32-bit instructions. */ + case 2 * INSN16_SIZE: + insn <<= 16; + insn |= nanomips_fetch_instruction (gdbarch, loc, NULL); + loc += INSN16_SIZE; + + switch (micromips_op (insn >> 16)) + { + case 0xa: /* BALC, BC */ + offset = ((insn & 1) << 24 | ((insn >> 1) & 0xffffff)) << 1; + offset = (offset ^ 0x2000000) - 0x2000000; + branch_bp = loc + offset; + is_branch = 1; + break; + + case 0x12: + op = b12s4_op (insn); + if (op == 0x8) /* BALRC, BALRSC */ + return {}; /* Fall back to the standard single-step code. */ + else if (op == 0 || op == 1) /* JALRC JALRC.HB */ + return {}; /* Fall back to the standard single-step code. */ + break; + + case 0x20: /* PP.SR */ + if (b12s5_op (insn) == 0x13) /* RESTORE.JRC */ + return {}; /* Fall back to the standard single-step code. */ + break; + + case 0x22: /* P.BR1 */ + case 0x2a: /* P.BR2 */ + op = b14s2_op (insn); + offset = ((insn & 1) << 13 | ((insn >> 1) & 0x1fff)) << 1; + offset = (offset ^ 0x4000) - 0x4000; + if (op == 0 /* BEQC, BNEC */ + || op == 2 /* BGEC, BLTC */ + || op == 3) /* BGEUC, BLTUC */ + { + branch_bp = loc + offset; + is_branch = 1; + } + break; + + case 0x32: /* P.BRI */ + op = b2s3_cc (insn >> 16); + offset = ((insn & 1) << 10 | ((insn >> 1) & 0x3ff)) << 1; + offset = (offset ^ 0x800) - 0x800; + if (op == 0 /* BEQIC */ + || op == 2 /* BGEIC */ + || op == 3 /* BGEIUC */ + || op == 4 /* BNEIC */ + || op == 6 /* BLTIC */ + || op == 7 ) /* BLTIUC */ + { + branch_bp = loc + offset; + is_branch = 1; + } + break; + + case 0x3a: /* P.BZ */ + op = (insn & 0x80000); /* 20th bit */ + offset = ((insn & 1) << 19 | ((insn >> 1) & 0x7ffff)) << 1; + offset = (offset ^ 0x100000) - 0x100000; + if (op == 0 /* BEQZC */ + || op != 0 ) /* BNEZC */ + { + branch_bp = loc + offset; + is_branch = 1; + } + break; + + case 0x29: /* P.SC: bits 101001 */ + if (b8s7_op (insn) == 0x59) /* SC: bits 101001 1011 0 01 */ + sc_found = 1; + break; + } + break; + + /* 16-bit instructions. */ + case INSN16_SIZE: + switch (micromips_op (insn)) + { + case 0x6: /* BC[16] */ + case 0xe: /* BALC[16] */ + offset = ((insn & 1) << 9 | ((insn >> 1) & 0x1ff)) << 1; + offset = (offset ^ 0x400) - 0x400; + branch_bp = loc + offset; + is_branch = 1; + break; + + case 0x7: /* RESTORE.JRC[16] */ + if ((insn & 1) == 0 && (insn & 0x20) == 0x20) + return {}; /* Fall back to the standard single-step code. */ + break; + + case 0x26: /* BEQZC[16] */ + case 0x2e: /* BNEZC[16] */ + offset = ((insn & 1) << 6 | ((insn >> 1) & 0x3f)) << 1; + offset = (offset ^ 0x80) - 0x80; + branch_bp = loc + offset; + is_branch = 1; + break; + + case 0x36: /* P16.BR P16.JRC */ + offset = insn & 0xf; + /* BEQC[16] BEQC[16] */ + if (offset != 0) + { + branch_bp = loc + offset; + is_branch = 1; + } + else if (offset == 0) /* JALRC[16] JRC */ + return {}; /* Fall back to the standard single-step code. */ + break; + } + break; + } + + if (is_branch) + { + if (last_breakpoint >= 1) + return {}; /* More than one branch found, fallback to the + standard single-step code. */ + breaks[1] = branch_bp; + last_breakpoint++; + } + } + if (!sc_found) + return {}; + + /* Insert a breakpoint right after the end of the atomic sequence. */ + breaks[0] = loc; + + /* Check for duplicated breakpoints. Check also for a breakpoint + placed (branch instruction's destination) in the atomic sequence */ + if (last_breakpoint && pc <= breaks[1] && breaks[1] <= breaks[0]) + last_breakpoint = 0; + + std::vector next_pcs; + + /* Effectively inserts the breakpoints. */ + for (index = 0; index <= last_breakpoint; index++) + next_pcs.push_back (breaks[index]); + + return next_pcs; +} + +/* nanomips_software_single_step() is called just before we want to resume + the inferior, if we want to single-step it but there is no hardware + or kernel single-step support (nanoMIPS on GNU/Linux for example). We find + the target of the coming instruction and breakpoint it. */ + +std::vector +nanomips_software_single_step (struct regcache *regcache) +{ + struct gdbarch *gdbarch = regcache->arch (); + CORE_ADDR pc, next_pc; + + pc = regcache_read_pc (regcache); + std::vector next_pcs = + nanomips_deal_with_atomic_sequence (gdbarch, pc); + + if (!next_pcs.empty ()) + return next_pcs; + + next_pc = nanomips_next_pc (regcache, pc); + + return {next_pc}; +} + +/* This fencepost looks highly suspicious to me. Removing it also + seems suspicious as it could affect remote debugging across serial + lines. */ + +static CORE_ADDR +heuristic_proc_start (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + CORE_ADDR start_pc; + CORE_ADDR fence; + int instlen; + struct inferior *inf; + + pc = gdbarch_addr_bits_remove (gdbarch, pc); + start_pc = pc; + fence = start_pc - heuristic_fence_post; + if (start_pc == 0) + return 0; + + if (heuristic_fence_post == -1 || fence < VM_MIN_ADDRESS) + fence = VM_MIN_ADDRESS; + + instlen = INSN16_SIZE; + + inf = current_inferior (); + + /* Search back for previous return. */ + for (start_pc -= instlen;; start_pc -= instlen) + if (start_pc < fence) + { + /* It's not clear to me why we reach this point when + stop_soon, but with this test, at least we + don't print out warnings for every child forked (eg, on + decstation). 22apr93 rich@cygnus.com. */ + if (inf->control.stop_soon == NO_STOP_QUIETLY) + { + static int blurb_printed = 0; + + warning (_("GDB can't find the start of the function at %s."), + paddress (gdbarch, pc)); + + if (!blurb_printed) + { + /* This actually happens frequently in embedded + development, when you first connect to a board + and your stack pointer and pc are nowhere in + particular. This message needs to give people + in that situation enough information to + determine that it's no big deal. */ + gdb_printf ("\n\ + GDB is unable to find the start of the function at %s\n\ +and thus can't determine the size of that function's stack frame.\n\ +This means that GDB may be unable to access that stack frame, or\n\ +the frames below it.\n\ + This problem is most likely caused by an invalid program counter or\n\ +stack pointer.\n\ + However, if you think GDB should simply search farther back\n\ +from %s for code which looks like the beginning of a\n\ +function, you can increase the range of the search using the `set\n\ +heuristic-fence-post' command.\n", + paddress (gdbarch, pc), paddress (gdbarch, pc)); + blurb_printed = 1; + } + } + + return 0; + } + else + { + ULONGEST insn; + int size; + + /* On nanomips, SAVE is likely to be the start of a function. */ + insn = nanomips_fetch_instruction (gdbarch, pc, NULL); + size = nanomips_insn_size (insn); + if ((size == 2 && micromips_op (insn) == 0x7) || + (size == 4 && micromips_op (insn) == 0x20)) + break; + } + + return start_pc; +} + +/* On p32, argument passing in GPRs depends on the alignment of the type being + passed. Return 1 if this type must be aligned to a doubleword boundary. */ + +static int +type_needs_double_align (struct type *type) +{ + enum type_code typecode = type->code (); + + if ((typecode == TYPE_CODE_FLT || typecode == TYPE_CODE_INT) + && type->length () == 8) + return 1; + else if (typecode == TYPE_CODE_STRUCT) + { + if (type->num_fields () > 1) + return 0; + return type_needs_double_align (type->field (0).type ()); + } + else if (typecode == TYPE_CODE_UNION) + { + int i, n; + + n = type->num_fields (); + for (i = 0; i < n; i++) + if (type_needs_double_align (type->field (i).type ())) + return 1; + return 0; + } + return 0; +} + +/* Adjust the address downward (direction of stack growth) so that it + is correctly aligned for a new stack frame. */ +static CORE_ADDR +nanomips_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) +{ + return align_down (addr, 16); +} + +/* Implement the "push_dummy_code" gdbarch method. */ + +static CORE_ADDR +nanomips_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, + CORE_ADDR funaddr, struct value **args, + int nargs, struct type *value_type, + CORE_ADDR *real_pc, CORE_ADDR *bp_addr, + struct regcache *regcache) +{ + /* Reserve enough room on the stack for our breakpoint instruction. */ + sp = sp - 4; + *bp_addr = sp; + + /* Inferior resumes at the function entry point. */ + *real_pc = funaddr; + + return sp; +} + +/* p32, p64 ABI stuff. */ + +#define MAX_REG_ARGS 8 /* Maximum 8 arguments in registers */ + +static CORE_ADDR +nanomips_push_dummy_call (struct gdbarch *gdbarch, struct value *function, + struct regcache *regcache, CORE_ADDR bp_addr, + int nargs, struct value **args, CORE_ADDR sp, + function_call_return_method return_method, CORE_ADDR struct_addr) +{ + int arg_gpr = 0, arg_fpr = 0; + int argnum; + int stack_offset = 0, stack_size = 0; + int seen_on_stack = 0; + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + int regsize = nanomips_abi_regsize (gdbarch); + + /* Set the return address register to point to the entry point of + the program, where a breakpoint lies in wait. */ + regcache_cooked_write_signed (regcache, NANOMIPS_RA_REGNUM, bp_addr); + + /* First ensure that the stack and structure return address (if any) + are properly aligned. The stack has to be at least 64-bit + aligned even on 32-bit machines, because doubles must be 64-bit + aligned. */ + + sp = align_down (sp, 16); + struct_addr = align_down (struct_addr, 16); + + /* Calculate space required on the stack for the args. */ + for (argnum = 0; argnum < nargs; argnum++) + { + struct type *arg_type = check_typedef (value_type (args[argnum])); + + /* Align to double-word if necessary. */ + if (type_needs_double_align (arg_type)) + stack_size = align_up (stack_size, NANOMIPS32_REGSIZE * 2); + + /* Allocate space on the stack. */ + stack_size += align_up (arg_type->length(), NANOMIPS32_REGSIZE); + } + stack_size = align_up (stack_size, 16); + + if (nanomips_debug) + gdb_printf (gdb_stdlog, "nanomips_push_dummy_call (stack_size=%d)\n", stack_size); + + /* The struct_return pointer occupies the first parameter-passing reg. */ + if (return_method == return_method_struct) + { + if (nanomips_debug) + gdb_printf (gdb_stdlog, + " struct_return reg=%d %s\n", + arg_gpr + NANOMIPS_A0_REGNUM, + paddress (gdbarch, struct_addr)); + + regcache_cooked_write_unsigned (regcache, arg_gpr + NANOMIPS_A0_REGNUM, + struct_addr); + + /* occupy first argument reg */ + arg_gpr++; + } + + /* Now load as many as possible of the first arguments into + registers, and push the rest onto the stack. Loop thru args + from first to last. */ + for (argnum = 0; argnum < nargs; argnum++) + { + const gdb_byte *val; + gdb_byte valbuf[NANOMIPS64_REGSIZE]; + struct value *arg = args[argnum]; + struct type *arg_type = check_typedef (value_type (arg)); + int len = arg_type->length(); + enum type_code typecode = arg_type->code (); + + if (typecode == TYPE_CODE_STRUCT && arg_type->num_fields () == 1) + { + if ((arg_type->field (0).type ())->code () == TYPE_CODE_TYPEDEF) + { + struct type *type = check_typedef (arg_type->field (0).type ()); + typecode = type->code (); + len = arg_type->length(); + } + else if ((arg_type->field (0).type ())->code () == TYPE_CODE_FLT) + { + typecode = TYPE_CODE_FLT; + } + } + + /* The P32 ABI passes structures larger than 8 bytes by reference. */ + if ((typecode == TYPE_CODE_ARRAY || typecode == TYPE_CODE_STRUCT + || typecode == TYPE_CODE_UNION || typecode == TYPE_CODE_COMPLEX) + && len > regsize * 2) + { + store_unsigned_integer (valbuf, regsize, byte_order, + value_address (arg)); + typecode = TYPE_CODE_PTR; + len = 4; + val = valbuf; + + if (nanomips_debug) + gdb_printf (gdb_stdlog, " push"); + } + else + val = value_contents (arg).data (); + + + while (len > 0) + { + int partial_len = (len < NANOMIPS32_REGSIZE ? len : NANOMIPS32_REGSIZE); + LONGEST regval; + int use_stack = 0; + + /* Align the argument register for double and long long types. */ + if ((arg_gpr < MAX_REG_ARGS) && (arg_gpr & 1) && (len == 8) + && ((typecode == TYPE_CODE_FLT + && FPU_TYPE(gdbarch) == NANOMIPS_FPU_SOFT) + || typecode == TYPE_CODE_INT)) + { + arg_gpr++; + stack_offset += 4; + } + + if (typecode == TYPE_CODE_STRUCT && (len <= 8 && len > 4) && arg_gpr == 7) + arg_gpr ++; + + /* double type occupies only one register. */ + if (typecode == TYPE_CODE_FLT && len == 8) + partial_len = (FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD ? 8 : 4); + + regval = extract_unsigned_integer (val, partial_len, byte_order); + + /* Check if any argument register is available. */ + if (typecode == TYPE_CODE_FLT && FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD) + { + if(arg_fpr < MAX_REG_ARGS) + { + if (nanomips_debug) + { + int r_num = arg_fpr + nanomips_fp_arg_regnum (gdbarch) + + gdbarch_num_regs (gdbarch); + const char *r = nanomips_register_name (gdbarch, r_num); + gdb_printf (gdb_stdlog, + " argnum=%d,reg=%s,len=%d,val=%ld\n", + argnum + 1, r, partial_len, regval); + } + + /* Update the register with specified value. */ + regcache_cooked_write_unsigned (regcache, + arg_fpr + nanomips_fp_arg_regnum (gdbarch), + regval); + arg_fpr++; + } + else + use_stack = 1; + } + else + { + if (arg_gpr < MAX_REG_ARGS) + { + if (nanomips_debug) + { + int r_num = arg_gpr + NANOMIPS_A0_REGNUM + + gdbarch_num_regs (gdbarch); + const char *r = nanomips_register_name (gdbarch, r_num); + gdb_printf (gdb_stdlog, + " argnum=%d,reg=%s,len=%d,val=%ld\n", + argnum + 1, r, partial_len, regval); + } + + /* Update the register with specified value. */ + regcache_cooked_write_unsigned (regcache, + arg_gpr + NANOMIPS_A0_REGNUM, regval); + arg_gpr++; + + } + else + use_stack = 1; + + } + + if (use_stack) + { + CORE_ADDR addr; + + if (nanomips_debug) + { + LONGEST valreg = extract_unsigned_integer (val, len, + byte_order); + gdb_printf (gdb_stdlog, + " argnum=%d,off=%d,len=%d,val=%ld\n", + argnum + 1, stack_offset, partial_len, + valreg); + } + + addr = (sp - stack_size) + stack_offset; + write_memory (addr, val, partial_len); + + seen_on_stack = 1; + stack_offset += (partial_len <= NANOMIPS32_REGSIZE) + ? NANOMIPS32_REGSIZE : partial_len; + use_stack = 0; + } /* argument on stack */ + + val += partial_len; + len -= partial_len; + } + } + + if (seen_on_stack) + sp -= stack_size; + + regcache_cooked_write_signed (regcache, NANOMIPS_SP_REGNUM, sp); + + /* Return adjusted stack pointer. */ + return sp; +} + +static enum return_value_convention +nanomips_return_value (struct gdbarch *gdbarch, struct value *function, + struct type *type, struct regcache *regcache, + gdb_byte *readbuf, const gdb_byte *writebuf) +{ + if ((type->code () == TYPE_CODE_ARRAY + || type->code () == TYPE_CODE_STRUCT + || type->code () == TYPE_CODE_COMPLEX) + && type->length () > 2 * NANOMIPS32_REGSIZE) + return RETURN_VALUE_STRUCT_CONVENTION; + + else if (type->code () == TYPE_CODE_COMPLEX + && FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD) + { + gdb_assert (nanomips_regnum (gdbarch)->fpr != -1); + + nanomips_xfer_register (gdbarch, regcache, + (gdbarch_num_regs (gdbarch) + + nanomips_regnum (gdbarch)->fpr + + NANOMIPS_FP0_REGNUM), + 4, gdbarch_byte_order (gdbarch), + readbuf, writebuf, 0); + nanomips_xfer_register (gdbarch, regcache, + (gdbarch_num_regs (gdbarch) + + nanomips_regnum (gdbarch)->fpr + + NANOMIPS_FP0_REGNUM + 1), + 4, gdbarch_byte_order (gdbarch), + readbuf, writebuf, 4); + return RETURN_VALUE_REGISTER_CONVENTION; + } + else if (type->code () == TYPE_CODE_FLT + && FPU_TYPE(gdbarch) == NANOMIPS_FPU_HARD) + { + gdb_assert (nanomips_regnum (gdbarch)->fpr != -1); + + nanomips_xfer_register (gdbarch, regcache, + (gdbarch_num_regs (gdbarch) + + nanomips_regnum (gdbarch)->fpr + + NANOMIPS_FP0_REGNUM), + type->length (), gdbarch_byte_order (gdbarch), + readbuf, writebuf, 0); + return RETURN_VALUE_REGISTER_CONVENTION; + } + else + { + int offset; + int regnum; + for (offset = 0, regnum = NANOMIPS_A0_REGNUM; + offset < type->length (); + offset += NANOMIPS32_REGSIZE, regnum++) + { + int xfer = NANOMIPS32_REGSIZE; + if (offset + xfer > type->length ()) + xfer = type->length () - offset; + if (nanomips_debug) + gdb_printf (gdb_stderr, "Return scalar+%d:%d in $%d\n", + offset, xfer, regnum); + nanomips_xfer_register (gdbarch, regcache, + gdbarch_num_regs (gdbarch) + regnum, xfer, + gdbarch_byte_order (gdbarch), + readbuf, writebuf, offset); + } + return RETURN_VALUE_REGISTER_CONVENTION; + } +} + +/* Copy a 32-bit single-precision value from the current frame + into rare_buffer. */ + +static void +read_fp_register_single (frame_info_ptr frame, int regno, + gdb_byte *rare_buffer) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + int raw_size = register_size (gdbarch, regno); + int offset; + gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size); + + if (!deprecated_frame_register_read (frame, regno, raw_buffer)) + error (_("can't read register %d (%s)"), + regno, gdbarch_register_name (gdbarch, regno)); + + /* We have a 64-bit value for this register. Find the low-order 32 bits. */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + offset = 4; + else + offset = 0; + + memcpy (rare_buffer, raw_buffer + offset, 4); +} + +/* Copy a 64-bit double-precision value from the current frame into + rare_buffer. */ + +static void +read_fp_register_double (frame_info_ptr frame, int regno, + gdb_byte *rare_buffer) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + + /* We have a 64-bit value for this register, use all 64 bits. */ + if (!deprecated_frame_register_read (frame, regno, rare_buffer)) + error (_("can't read register %d (%s)"), + regno, gdbarch_register_name (gdbarch, regno)); +} + +static void +print_fp_register (struct ui_file *file, frame_info_ptr frame, + int regnum) +{ /* Do values for FP (float) regs. */ + struct gdbarch *gdbarch = get_frame_arch (frame); + gdb_byte *raw_buffer; + std::string flt_str, dbl_str; + struct value_print_options opts; + + const struct type *flt_type = builtin_type (gdbarch)->builtin_float; + const struct type *dbl_type = builtin_type (gdbarch)->builtin_double; + + gdb_assert (nanomips_regnum (gdbarch)->fpr != -1); + + raw_buffer + = ((gdb_byte *) + alloca (2 * register_size (gdbarch, + (nanomips_regnum (gdbarch)->fpr + + NANOMIPS_FP0_REGNUM)))); + + gdb_printf (file, "%s:", gdbarch_register_name (gdbarch, regnum)); + gdb_printf (file, "%*s", + 4 - (int) strlen (gdbarch_register_name (gdbarch, regnum)), + ""); + + /* Eight byte registers: print each one as hex, float and double. */ + read_fp_register_single (frame, regnum, raw_buffer); + flt_str = target_float_to_string (raw_buffer, flt_type, "%-17.9g"); + + read_fp_register_double (frame, regnum, raw_buffer); + dbl_str = target_float_to_string (raw_buffer, dbl_type, "%-24.17g"); + + get_formatted_print_options (&opts, 'x'); + print_scalar_formatted (raw_buffer, + builtin_type (gdbarch)->builtin_uint64, + &opts, 'g', file); + + gdb_printf (file, " flt: %s", flt_str.c_str ()); + + gdb_printf (file, " dbl: %s", dbl_str.c_str ()); +} + +static void +nanomips_print_register (struct ui_file *file, frame_info_ptr frame, + int regnum) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct value_print_options opts; + struct value *val; + + if (nanomips_float_register_p (gdbarch, regnum)) + { + print_fp_register (file, frame, regnum); + return; + } + + val = get_frame_register_value (frame, regnum); + + gdb_puts (gdbarch_register_name (gdbarch, regnum), file); + + /* The problem with printing numeric register names (r26, etc.) is that + the user can't use them on input. Probably the best solution is to + fix it so that either the numeric or the funky (a2, etc.) names + are accepted on input. */ + if (regnum < NUMREGS) + gdb_printf (file, "(r%d): ", regnum); + else + gdb_printf (file, ": "); + + get_formatted_print_options (&opts, 'x'); + value_print_scalar_formatted (val, &opts, 0, file); +} + +/* Print IEEE exception condition bits in FLAGS. */ + +static void +print_fpu_flags (struct ui_file *file, int flags) +{ + if (flags & (1 << 0)) + gdb_puts (" inexact", file); + if (flags & (1 << 1)) + gdb_puts (" uflow", file); + if (flags & (1 << 2)) + gdb_puts (" oflow", file); + if (flags & (1 << 3)) + gdb_puts (" div0", file); + if (flags & (1 << 4)) + gdb_puts (" inval", file); + if (flags & (1 << 5)) + gdb_puts (" unimp", file); + gdb_putc ('\n', file); +} + +/* Print interesting information about the floating point processor + (if present) or emulator. */ + +static void +nanomips_print_float_info (struct gdbarch *gdbarch, struct ui_file *file, + frame_info_ptr frame, const char *args) +{ + int fcsr = nanomips_regnum (gdbarch)->fpr + NANOMIPS_FCSR_REGNUM; + enum fpu_type type = FPU_TYPE (gdbarch); + ULONGEST fcs = 0; + int i; + + if (nanomips_regnum (gdbarch)->fpr == -1 + || !read_frame_register_unsigned (frame, fcsr, &fcs)) + type = NANOMIPS_FPU_NONE; + + gdb_printf (file, "fpu type: %s\n", + type == NANOMIPS_FPU_HARD ? "64bit hardware floating point" + : type == NANOMIPS_FPU_SOFT ? "Software floating point" + : "none / unused"); + + if (type == NANOMIPS_FPU_NONE) + return; + + gdb_printf (file, "reg size: %d bits\n", + register_size (gdbarch, + (nanomips_regnum (gdbarch)->fpr + + NANOMIPS_FP0_REGNUM)) * 8); + + gdb_puts ("cond :", file); + if (fcs & (1 << 23)) + gdb_puts (" 0", file); + for (i = 1; i <= 7; i++) + if (fcs & (1 << (24 + i))) + gdb_printf (file, " %d", i); + gdb_putc ('\n', file); + + gdb_puts ("cause :", file); + print_fpu_flags (file, (fcs >> 12) & 0x3f); + fputs ("mask :", stdout); + print_fpu_flags (file, (fcs >> 7) & 0x1f); + fputs ("flags :", stdout); + print_fpu_flags (file, (fcs >> 2) & 0x1f); + + gdb_puts ("rounding: ", file); + switch (fcs & 3) + { + case 0: gdb_puts ("nearest\n", file); break; + case 1: gdb_puts ("zero\n", file); break; + case 2: gdb_puts ("+inf\n", file); break; + case 3: gdb_puts ("-inf\n", file); break; + } + + gdb_puts ("flush :", file); + if (fcs & (1 << 21)) + gdb_puts (" nearest", file); + if (fcs & (1 << 22)) + gdb_puts (" override", file); + if (fcs & (1 << 24)) + gdb_puts (" zero", file); + if ((fcs & (0xb << 21)) == 0) + gdb_puts (" no", file); + gdb_putc ('\n', file); + + gdb_printf (file, "nan2008 : %s\n", fcs & (1 << 18) ? "yes" : "no"); + gdb_printf (file, "abs2008 : %s\n", fcs & (1 << 19) ? "yes" : "no"); + gdb_putc ('\n', file); + + default_print_float_info (gdbarch, file, frame, args); +} + +/* Replacement for generic do_registers_info. + Print regs in pretty columns. */ + +static int +print_fp_register_row (struct ui_file *file, frame_info_ptr frame, + int regnum) +{ + gdb_printf (file, " "); + print_fp_register (file, frame, regnum); + gdb_printf (file, "\n"); + return regnum + 1; +} + + +/* Print a row's worth of GP (int) registers, with name labels above. */ + +static int +print_gp_register_row (struct ui_file *file, frame_info_ptr frame, + int start_regnum) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + /* Do values for GP (int) regs. */ + gdb_byte raw_buffer[NANOMIPS64_REGSIZE]; + int ncols = (nanomips_abi_regsize (gdbarch) == 8 ? 4 : 8); /* display cols + per row. */ + int col, byte; + int regnum; + + /* For GP registers, we print a separate row of names above the vals. */ + for (col = 0, regnum = start_regnum; + col < ncols && regnum < gdbarch_num_regs (gdbarch) + + gdbarch_num_pseudo_regs (gdbarch); + regnum++) + { + if (*gdbarch_register_name (gdbarch, regnum) == '\0') + continue; /* unused register */ + if (nanomips_float_register_p (gdbarch, regnum)) + break; /* End the row: reached FP register. */ + /* Large registers are handled separately. */ + if (register_size (gdbarch, regnum) > nanomips_abi_regsize (gdbarch)) + { + if (col > 0) + break; /* End the row before this register. */ + + /* Print this register on a row by itself. */ + nanomips_print_register (file, frame, regnum); + gdb_printf (file, "\n"); + return regnum + 1; + } + if (col == 0) + gdb_printf (file, " "); + gdb_printf (file, + nanomips_abi_regsize (gdbarch) == 8 ? "%17s" : "%9s", + gdbarch_register_name (gdbarch, regnum)); + col++; + } + + if (col == 0) + return regnum; + + /* Print the R0 to R31 names. */ + if ((start_regnum % gdbarch_num_regs (gdbarch)) < NUMREGS) + gdb_printf (file, "\n R%-4d", + start_regnum % gdbarch_num_regs (gdbarch)); + else + gdb_printf (file, "\n "); + + /* Now print the values in hex, 4 or 8 to the row. */ + for (col = 0, regnum = start_regnum; + col < ncols && regnum < gdbarch_num_regs (gdbarch) + + gdbarch_num_pseudo_regs (gdbarch); + regnum++) + { + if (*gdbarch_register_name (gdbarch, regnum) == '\0') + continue; /* unused register */ + if (nanomips_float_register_p (gdbarch, regnum)) + break; /* End row: reached FP register. */ + if (register_size (gdbarch, regnum) > nanomips_abi_regsize (gdbarch)) + break; /* End row: large register. */ + + /* OK: get the data in raw format. */ + if (!deprecated_frame_register_read (frame, regnum, raw_buffer)) + error (_("can't read register %d (%s)"), + regnum, gdbarch_register_name (gdbarch, regnum)); + /* pad small registers */ + for (byte = 0; + byte < (nanomips_abi_regsize (gdbarch) + - register_size (gdbarch, regnum)); byte++) + gdb_printf (" "); + /* Now print the register value in hex, endian order. */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + for (byte = + register_size (gdbarch, regnum) - register_size (gdbarch, regnum); + byte < register_size (gdbarch, regnum); byte++) + gdb_printf (file, "%02x", raw_buffer[byte]); + else + for (byte = register_size (gdbarch, regnum) - 1; + byte >= 0; byte--) + gdb_printf (file, "%02x", raw_buffer[byte]); + gdb_printf (file, " "); + col++; + } + if (col > 0) /* ie. if we actually printed anything... */ + gdb_printf (file, "\n"); + + return regnum; +} + +/* MIPS_DO_REGISTERS_INFO(): called by "info register" command. */ + +static void +nanomips_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file, + frame_info_ptr frame, int regnum, int all) +{ + if (regnum != -1) /* Do one specified register. */ + { + gdb_assert (regnum >= gdbarch_num_regs (gdbarch)); + if (*(gdbarch_register_name (gdbarch, regnum)) == '\0') + error (_("Not a valid register for the current processor type")); + + nanomips_print_register (file, frame, regnum); + gdb_printf (file, "\n"); + } + else + /* Do all (or most) registers. */ + { + regnum = gdbarch_num_regs (gdbarch); + while (regnum < gdbarch_num_regs (gdbarch) + + gdbarch_num_pseudo_regs (gdbarch)) + { + if (nanomips_float_register_p (gdbarch, regnum)) + { + if (all) /* True for "INFO ALL-REGISTERS" command. */ + regnum = print_fp_register_row (file, frame, regnum); + else + regnum += NUMREGS; /* Skip floating point regs. */ + } + else + regnum = print_gp_register_row (file, frame, regnum); + } + } +} + +/* To skip prologues, I use this predicate. Returns either PC itself + if the code at PC does not look like a function prologue; otherwise + returns an address that (if we're lucky) follows the prologue. If + LENIENT, then we must skip everything which is involved in setting + up the frame (it's OK to skip more, just so long as we don't skip + anything which might clobber the registers which are being saved. + We must skip more in the case where part of the prologue is in the + delay slot of a non-prologue instruction). */ + +static CORE_ADDR +nanomips_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + CORE_ADDR limit_pc; + CORE_ADDR func_addr; + + /* See if we can determine the end of the prologue via the symbol table. + If so, then return either PC, or the PC after the prologue, whichever + is greater. */ + if (find_pc_partial_function (pc, NULL, &func_addr, NULL)) + { + CORE_ADDR post_prologue_pc + = skip_prologue_using_sal (gdbarch, func_addr); + if (post_prologue_pc != 0) + return std::max (pc, post_prologue_pc); + } + + /* Can't determine prologue from the symbol table, need to examine + instructions. */ + + /* Find an upper limit on the function prologue using the debug + information. If the debug information could not be used to provide + that bound, then use an arbitrary large number as the upper bound. */ + limit_pc = skip_prologue_using_sal (gdbarch, pc); + if (limit_pc == 0) + limit_pc = pc + 100; /* Magic. */ + + return nanomips_scan_prologue (gdbarch, pc, limit_pc, NULL, NULL); +} + +/* Implement the stack_frame_destroyed_p gdbarch method (nanoMIPS version). + This is a helper function for mips_stack_frame_destroyed_p. */ + +static int +nanomips_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + CORE_ADDR func_addr = 0; + CORE_ADDR func_end = 0; + CORE_ADDR addr; + ULONGEST insn; + int dreg; + int sreg; + int treg, op; + int loc; + + if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end)) + return 0; + + /* The nanoMIPS epilogue is max. 12 bytes long. */ + addr = func_end - 12; + + if (addr < func_addr + 2) + addr = func_addr + 2; + if (pc < addr) + return 0; + + for (; pc < func_end; pc += loc) + { + loc = 0; + insn = nanomips_fetch_instruction (gdbarch, pc, NULL); + loc += INSN16_SIZE; + switch (nanomips_insn_size (insn)) + { + /* 48-bit instructions. */ + case 3 * INSN16_SIZE: + if (micromips_op (insn) == 0x18) + { + op = b0s5_imm (insn); + treg = b5s5_reg (insn); + if (op == 0x0) /* LI48 xx, imm32 */ + break; /* continue scan */ + else if (op == 0x1 /* ADDIU48 $sp, imm32 */ + && treg == NANOMIPS_SP_REGNUM) + return 1; + } + return 0; + + /* 32-bit instructions. */ + case 2 * INSN16_SIZE: + insn <<= 16; + insn |= nanomips_fetch_instruction (gdbarch, pc + loc, NULL); + loc += INSN16_SIZE; + + switch (micromips_op (insn >> 16)) + { + case 0x0: /* PP.ADDIU bits 000000 */ + treg = b5s5_reg (insn >> 16); + sreg = b0s5_reg (insn >> 16); + if (sreg == treg + && treg == NANOMIPS_SP_REGNUM) /* ADDIU $sp, $sp, imm */ + return 1; + else if (sreg == NANOMIPS_SP_REGNUM && treg == 30) + break; /* continue scan */ + return 0; + + case 0x8: /* _POOL32A0 */ + if ((insn & 0x1ff) == 0x150) /* ADDU */ + { + dreg = b11s5_reg (insn); + sreg = b0s5_reg (insn >> 16); + if ((dreg == sreg && sreg == NANOMIPS_SP_REGNUM) + /* ADDU $sp, $sp, xx */ + || (dreg == NANOMIPS_SP_REGNUM && sreg == 30)) + /* ADDU $sp, $fp, xx */ + break; /* continue scan */ + } + else if (((insn & 0xffff) == 0xE37F) /* DERET */ + || ((insn & 0x1ffff) == 0xF37F) /* ERET */ + || ((insn & 0x1ffff) == 0x1F37F)) /* ERETNC */ + return 1; + return 0; + + case 0x20: /* P.U12 bits 100000 */ + if (b12s4_op (insn) == 0) /* ORI: bits 100000 0000 */ + { + sreg = b0s5_reg (insn >> 16); + treg = b5s5_reg (insn >> 16); + if (sreg == treg && treg == 3) /* ORI $v1, $v1, imm */ + break; /* continue scan */ + } + else if (b12s5_op (insn) == 0x13) /* RESTORE, RESTORE.JRC */ + return 1; + return 0; + + case 0x38: /* P.LUI bits 111000 */ + treg = b5s5_reg (insn >> 16); + if ((insn & 2) == 0 /* LU20I bits 111000 0 */ + && treg == 3) /* LU20I $v1, imm */ + break; /* continue scan */ + return 0; + + default: + return 0; + } + break; + + /* 16-bit instructions. */ + case INSN16_SIZE: + switch (micromips_op (insn)) + { + case 0x4: /* MOVE: bits 000100 */ + sreg = b0s5_reg (insn); + dreg = b5s5_reg (insn); + if (sreg == NANOMIPS_SP_REGNUM && dreg == 30) + /* MOVE $fp, $sp */ + return 1; + return 0; + + case 0x7: /* RESTORE[16], RESTORE.JRC[16] */ + if ((insn & 0x20) == 0x20) + return 1; + return 0; + + case 0x36: /* JRC[16] $31 */ + if ((insn & 0x1f) == 0 && b5s5_reg (insn) == 31) + return 1; + return 0; + + default: + return 0; + } + break; + } + } + + return 1; +} + +/* Root of all "set nanomips "/"show nanomips " commands. This will eventually be + used for all nanoMIPS-specific commands. */ + +static void +show_nanomips_command (const char *args, int from_tty) +{ + help_list (shownanomipscmdlist, "show nanomips ", all_commands, gdb_stdout); +} + +static void +set_nanomips_command (const char *args, int from_tty) +{ + printf_unfiltered + ("\"set nanomips\" must be followed by an appropriate subcommand.\n"); + help_list (setnanomipscmdlist, "set nanomips ", all_commands, gdb_stdout); +} + +/* Just like reinit_frame_cache, but with the right arguments to be + callable as an sfunc. */ + +static void +reinit_frame_cache_sfunc (const char *args, int from_tty, + struct cmd_list_element *c) +{ + reinit_frame_cache (); +} + +static int +gdb_print_insn_nanomips_p32 (bfd_vma memaddr, struct disassemble_info *info) +{ + info->mach = bfd_mach_nanomipsisa32r6; + info->flavour = bfd_target_elf_flavour; + info->disassembler_options = "gpr-names=p32"; + + return print_insn_nanomips (memaddr, info); +} + +static int +gdb_print_insn_nanomips_p64 (bfd_vma memaddr, struct disassemble_info *info) +{ + info->mach = bfd_mach_nanomipsisa64r6; + info->flavour = bfd_target_elf_flavour; + info->disassembler_options = "gpr-names=p64"; + + return print_insn_nanomips (memaddr, info); +} + +/* Implement the breakpoint_kind_from_pc gdbarch method. */ + +static int +nanomips_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) +{ + CORE_ADDR pc = *pcptr; + ULONGEST insn; + int status; + + insn = nanomips_fetch_instruction (gdbarch, pc, &status); + if (status || (nanomips_insn_size (insn) == 2)) + return NANOMIPS_BP_KIND_16; + else + return NANOMIPS_BP_KIND_32; +} + +/* Implement the sw_breakpoint_from_kind gdbarch method. */ + +static const gdb_byte * +nanomips_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size) +{ + enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); + + switch (kind) + { + case NANOMIPS_BP_KIND_16: + { + static gdb_byte be16_break[] = { 0x10, 0x10 }; + static gdb_byte le16_break[] = { 0x10, 0x10 }; + + *size = 2; + + if (byte_order_for_code == BFD_ENDIAN_BIG) + return be16_break; + else + return le16_break; + } + case NANOMIPS_BP_KIND_32: + { + static gdb_byte be32_break[] = { 0, 0x10, 0, 0 }; + static gdb_byte le32_break[] = { 0x10, 0, 0, 0 }; + + *size = 4; + if (byte_order_for_code == BFD_ENDIAN_BIG) + return be32_break; + else + return le32_break; + } + default: + gdb_assert_not_reached ("unexpected nanomips breakpoint kind"); + }; +} + +/* Convert a dbx stab register number (from `r' declaration) to a GDB + [1 * gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM. */ + +static int +nanomips_stab_reg_to_regnum (struct gdbarch *gdbarch, int num) +{ + int regnum; + if (num >= 0 && num < 32) + regnum = num; + else if (nanomips_regnum (gdbarch)->fpr != -1 && num >= 36 && num < 70) + regnum = num + nanomips_regnum (gdbarch)->fpr + NANOMIPS_FP0_REGNUM - 36; + else if (nanomips_regnum (gdbarch)->dsp != -1 && num >= 70 && num < 78) + regnum + = num + nanomips_regnum (gdbarch)->dsp + NANOMIPS_DSPHI0_REGNUM - 70; + else + return -1; + return gdbarch_num_regs (gdbarch) + regnum; +} + + +/* Convert a dwarf, dwarf2, or ecoff register number to a GDB [1 * + gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM. */ + +static int +nanomips_dwarf_dwarf2_ecoff_reg_to_regnum (struct gdbarch *gdbarch, int num) +{ + int regnum; + if (num >= 0 && num < 32) + regnum = num; + else if (nanomips_regnum (gdbarch)->fpr != -1 && num >= 32 && num < 64) + regnum = num + nanomips_regnum (gdbarch)->fpr + NANOMIPS_FP0_REGNUM - 32; + else if (nanomips_regnum (gdbarch)->dsp != -1 && num >= 64 && num < 72) + regnum + = num + nanomips_regnum (gdbarch)->dsp + NANOMIPS_DSPHI0_REGNUM - 64; + else + return -1; + return gdbarch_num_regs (gdbarch) + regnum; +} + +static int +nanomips_register_sim_regno (struct gdbarch *gdbarch, int regnum) +{ + /* Only makes sense to supply raw registers. */ + gdb_assert (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch)); + /* FIXME: cagney/2002-05-13: Need to look at the pseudo register to + decide if it is valid. Should instead define a standard sim/gdb + register numbering scheme. */ + if (gdbarch_register_name (gdbarch, + gdbarch_num_regs (gdbarch) + regnum) != NULL + && gdbarch_register_name (gdbarch, + gdbarch_num_regs (gdbarch) + + regnum)[0] != '\0') + return regnum; + else + return LEGACY_SIM_REGNO_IGNORE; +} + + +/* Convert an integer into an address. Extracting the value signed + guarantees a correctly sign extended address. */ + +static CORE_ADDR +nanomips_integer_to_address (struct gdbarch *gdbarch, + struct type *type, const gdb_byte *buf) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + return extract_signed_integer (buf, type->length (), byte_order); +} + +/* Dummy virtual frame pointer method. This is no more or less accurate + than most other architectures; we just need to be explicit about it, + because the pseudo-register gdbarch_sp_regnum will otherwise lead to + an assertion failure. */ + +static void +nanomips_virtual_frame_pointer (struct gdbarch *gdbarch, + CORE_ADDR pc, int *reg, LONGEST *offset) +{ + *reg = NANOMIPS_SP_REGNUM; + *offset = 0; +} + +static struct gdbarch * +nanomips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +{ + static const char *const mips_gprs[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" + }; + static const char *const mips_fprs[] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + }; + static const char *const mips_dsprs[] = { + "hi0", "lo0", "hi1", "lo1", "hi2", "lo2", "hi3", "lo3" + }; + const struct tdesc_feature *feature; + struct gdbarch *gdbarch; + struct nanomips_gdbarch_tdep *tdep; + int elf_flags; + enum nanomips_abi nanomips_abi, found_abi; + int i, num_regs; + enum fpu_type fpu_type; + tdesc_arch_data_up tdesc_data; + const struct target_desc *tdesc = info.target_desc; + int elf_fpu_type = Val_GNU_NANOMIPS_ABI_FP_ANY; + struct nanomips_regnum nanomips_regnum, *regnum; + int register_size; + int valid_p; + + num_regs = 0; + + nanomips_regnum.cause = -1; + nanomips_regnum.status = -1; + nanomips_regnum.badvaddr = -1; + nanomips_regnum.fpr = -1; + nanomips_regnum.dsp = -1; + nanomips_regnum.restart = -1; + + /* If there's no target description, then use the default. */ + if (!tdesc_has_registers (tdesc)) + tdesc = tdesc_nanomips; + + /* The CPU feature and the registers within are mandatory. */ + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.cpu"); + if (feature == NULL) + return NULL; + + tdesc_data = tdesc_data_alloc (); + + valid_p = 1; + for (i = 0; i < 32; i++, num_regs++) + valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs, + mips_gprs[i]); + valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++, "pc"); + if (!valid_p) + return NULL; + register_size = tdesc_register_bitsize (feature, "r0") / 8; + + /* All the remaining target description features are optional. */ + + /* Check for and assign a number to the syscall restart PC register. */ + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.linux"); + if (feature != NULL) + { + if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs, "restart")) + nanomips_regnum.restart = num_regs++; + + /* Check for and assign numbers to particular CP0 registers. + These are only special and need known numbers with Linux + targets, due to the use in signal frames, etc. Bare metal + stubs can simply include them along with other CP0 registers. */ + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.cp0"); + if (feature != NULL) + { + if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs, + "badvaddr")) + nanomips_regnum.badvaddr = num_regs++; + if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs, + "status")) + nanomips_regnum.status = num_regs++; + if (tdesc_numbered_register (feature, tdesc_data.get (), num_regs, + "cause")) + nanomips_regnum.cause = num_regs++; + } + } + + /* Check for and assign numbers to FPU registers. */ + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.fpu"); + if (feature != NULL) + { + nanomips_regnum.fpr = num_regs; + for (i = 0; i < 32; i++, num_regs++) + valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs, + mips_fprs[i]); + valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++, + "fcsr"); + valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++, + "fir"); + if (!valid_p) + return NULL; + } + + /* Check for and assign numbers to DSP registers. */ + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nanomips.dsp"); + if (feature != NULL) + { + nanomips_regnum.dsp = num_regs; + for (i = 0; i < 8; i++, num_regs++) + valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs, + mips_dsprs[i]); + valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), num_regs++, + "dspctl"); + if (!valid_p) + return NULL; + } + + /* First of all, extract the elf_flags, if available. */ + if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour) + elf_flags = elf_elfheader (info.abfd)->e_flags; + else if (arches != NULL) + elf_flags = (gdbarch_tdep (arches->gdbarch))->elf_flags; + else + elf_flags = 0; + + if (gdbarch_debug) + gdb_printf (gdb_stdlog, + "nanomips_gdbarch_init: elf_flags = 0x%08x\n", + elf_flags); + + /* Check ELF_FLAGS to see if it specifies the ABI being used. */ + switch ((elf_flags & EF_NANOMIPS_ABI)) + { + case E_NANOMIPS_ABI_P32: + found_abi = NANOMIPS_ABI_P32; + break; + case E_NANOMIPS_ABI_P64: + found_abi = NANOMIPS_ABI_P64; + break; + default: + found_abi = NANOMIPS_ABI_UNKNOWN; + break; + } + + /* If we have no useful BFD information, use the ABI from the last + nanoMIPS architecture (if there is one). */ + if (found_abi == NANOMIPS_ABI_UNKNOWN && info.abfd == NULL && arches != NULL) + found_abi = (gdbarch_tdep (arches->gdbarch))->found_abi; + + /* Try the architecture for any hint of the correct ABI. */ + if (found_abi == NANOMIPS_ABI_UNKNOWN + && info.bfd_arch_info != NULL + && info.bfd_arch_info->arch == bfd_arch_nanomips) + { + switch (info.bfd_arch_info->mach) + { + case bfd_mach_nanomipsisa32r6: + found_abi = NANOMIPS_ABI_P32; + break; + case bfd_mach_nanomipsisa64r6: + found_abi = NANOMIPS_ABI_P64; + break; + } + } + + /* Default 64-bit objects to P64 instead of P32. */ + if (found_abi == NANOMIPS_ABI_UNKNOWN + && info.abfd != NULL + && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour + && elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64) + found_abi = NANOMIPS_ABI_P64; + + if (gdbarch_debug) + gdb_printf (gdb_stdlog, "nanomips_gdbarch_init: found_abi = %d\n", + found_abi); + + /* Now that we have found what the ABI for this binary would be, + check whether the user is overriding it. */ + if (found_abi != NANOMIPS_ABI_UNKNOWN) + nanomips_abi = found_abi; + else + nanomips_abi = NANOMIPS_ABI_P32; + if (gdbarch_debug) + gdb_printf (gdb_stdlog, + "nanomips_gdbarch_init: nanomips_abi = %d\n", + nanomips_abi); + + /* Determine the nanoMIPS FPU type. */ + if (info.abfd + && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour) + { + Elf_Internal_ABIFlags_v0 *abiflags; + abiflags = bfd_nanomips_elf_get_abiflags (info.abfd); + if (abiflags != NULL) + elf_fpu_type = abiflags->fp_abi; + } + + if (elf_fpu_type != Val_GNU_NANOMIPS_ABI_FP_ANY) + { + switch (elf_fpu_type) + { + case Val_GNU_NANOMIPS_ABI_FP_SOFT: + fpu_type = NANOMIPS_FPU_SOFT; + break; + default: + fpu_type = NANOMIPS_FPU_HARD; + break; + } + } + else if (arches != NULL) + fpu_type = (gdbarch_tdep (arches->gdbarch))->fpu_type; + else + fpu_type = NANOMIPS_FPU_HARD; + + if (gdbarch_debug) + gdb_printf (gdb_stdlog, + "nanomips_gdbarch_init: fpu_type = %d\n", fpu_type); + + /* Check for blatant incompatibilities. */ + + /* If we have only 32-bit registers, then we can't debug a 64-bit ABI. */ + if (register_size == 4 && nanomips_abi != NANOMIPS_ABI_P32) + { + return NULL; + } + + /* Try to find a pre-existing architecture. */ + for (arches = gdbarch_list_lookup_by_info (arches, &info); + arches != NULL; + arches = gdbarch_list_lookup_by_info (arches->next, &info)) + { + /* nanoMIPS needs to be pedantic about which ABI and the compressed + ISA variation the object is using. */ + if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags) + continue; + if (gdbarch_tdep (arches->gdbarch)->nanomips_abi != nanomips_abi) + continue; + /* Be pedantic about which FPU is selected. */ + if (gdbarch_tdep (arches->gdbarch)->fpu_type != fpu_type) + continue; + + return arches->gdbarch; + } + + /* Need a new architecture. Fill in a target specific vector. */ + tdep = new (struct nanomips_gdbarch_tdep); + gdbarch = gdbarch_alloc (&info, tdep); + tdep->elf_flags = elf_flags; + tdep->found_abi = found_abi; + tdep->nanomips_abi = nanomips_abi; + tdep->fpu_type = fpu_type; + tdep->register_size = register_size; + + /* Initially set everything according to the default ABI/ISA. */ + set_gdbarch_short_bit (gdbarch, 16); + set_gdbarch_int_bit (gdbarch, 32); + set_gdbarch_float_bit (gdbarch, 32); + set_gdbarch_double_bit (gdbarch, 64); + set_gdbarch_long_double_bit (gdbarch, 64); + set_gdbarch_register_reggroup_p (gdbarch, nanomips_register_reggroup_p); + set_gdbarch_pseudo_register_read (gdbarch, nanomips_pseudo_register_read); + set_gdbarch_pseudo_register_write (gdbarch, nanomips_pseudo_register_write); + set_gdbarch_ax_pseudo_register_collect (gdbarch, + nanomips_ax_pseudo_register_collect); + set_gdbarch_ax_pseudo_register_push_stack + (gdbarch, nanomips_ax_pseudo_register_push_stack); + + tdep->default_mask_address_p = 0; + + set_gdbarch_push_dummy_call (gdbarch, nanomips_push_dummy_call); + set_gdbarch_return_value (gdbarch, nanomips_return_value); + + switch (nanomips_abi) + { + case NANOMIPS_ABI_P32: + set_gdbarch_long_bit (gdbarch, 32); + set_gdbarch_ptr_bit (gdbarch, 32); + set_gdbarch_long_long_bit (gdbarch, 64); + break; + case NANOMIPS_ABI_P64: + set_gdbarch_long_bit (gdbarch, 64); + set_gdbarch_ptr_bit (gdbarch, 64); + set_gdbarch_long_long_bit (gdbarch, 64); + set_gdbarch_long_double_bit (gdbarch, 128); + set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double); + break; + default: + internal_error_loc (__FILE__, __LINE__, _("unknown ABI in switch")); + } + + set_gdbarch_read_pc (gdbarch, nanomips_read_pc); + set_gdbarch_write_pc (gdbarch, nanomips_write_pc); + + /* Add/remove bits from an address. The nanoMIPS needs be careful to + ensure that all 32 bit addresses are sign extended to 64 bits. */ + set_gdbarch_addr_bits_remove (gdbarch, nanomips_addr_bits_remove); + + /* Unwind the frame. */ + set_gdbarch_unwind_pc (gdbarch, nanomips_unwind_pc); + set_gdbarch_unwind_sp (gdbarch, nanomips_unwind_sp); + set_gdbarch_dummy_id (gdbarch, nanomips_dummy_id); + + /* Map debug register numbers onto internal register numbers. */ + set_gdbarch_stab_reg_to_regnum (gdbarch, nanomips_stab_reg_to_regnum); + set_gdbarch_ecoff_reg_to_regnum (gdbarch, + nanomips_dwarf_dwarf2_ecoff_reg_to_regnum); + set_gdbarch_dwarf2_reg_to_regnum (gdbarch, + nanomips_dwarf_dwarf2_ecoff_reg_to_regnum); + set_gdbarch_register_sim_regno (gdbarch, nanomips_register_sim_regno); + + /* nanoMIPS version of CALL_DUMMY. */ + + set_gdbarch_call_dummy_location (gdbarch, ON_STACK); + set_gdbarch_push_dummy_code (gdbarch, nanomips_push_dummy_code); + set_gdbarch_frame_align (gdbarch, nanomips_frame_align); + + set_gdbarch_print_float_info (gdbarch, nanomips_print_float_info); + + set_gdbarch_convert_register_p (gdbarch, nanomips_convert_register_p); + set_gdbarch_register_to_value (gdbarch, nanomips_register_to_value); + set_gdbarch_value_to_register (gdbarch, nanomips_value_to_register); + + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + set_gdbarch_breakpoint_kind_from_pc (gdbarch, + nanomips_breakpoint_kind_from_pc); + set_gdbarch_sw_breakpoint_from_kind (gdbarch, + nanomips_sw_breakpoint_from_kind); + + set_gdbarch_skip_prologue (gdbarch, nanomips_skip_prologue); + + set_gdbarch_stack_frame_destroyed_p (gdbarch, + nanomips_stack_frame_destroyed_p); + + set_gdbarch_pointer_to_address (gdbarch, signed_pointer_to_address); + set_gdbarch_address_to_pointer (gdbarch, address_to_signed_pointer); + set_gdbarch_integer_to_address (gdbarch, nanomips_integer_to_address); + + set_gdbarch_print_registers_info (gdbarch, nanomips_print_registers_info); + + if (nanomips_abi == NANOMIPS_ABI_P64) + set_gdbarch_print_insn (gdbarch, gdb_print_insn_nanomips_p64); + else + set_gdbarch_print_insn (gdbarch, gdb_print_insn_nanomips_p32); + + /* FIXME: cagney/2003-08-29: The macros target_have_steppable_watchpoint, + HAVE_NONSTEPPABLE_WATCHPOINT, and target_have_continuable_watchpoint + need to all be folded into the target vector. Since they are + being used as guards for target_stopped_by_watchpoint, why not have + target_stopped_by_watchpoint return the type of watchpoint that the code + is sitting on? */ + set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1); + + /* Virtual tables. */ + set_gdbarch_vbit_in_delta (gdbarch, 0); + + /* Hook in OS ABI-specific overrides, if they have been registered. */ + info.target_desc = tdesc; + info.tdesc_data = tdesc_data.get (); + gdbarch_init_osabi (info, gdbarch); + + /* Unwind the frame. */ + dwarf2_append_unwinders (gdbarch); + frame_unwind_append_unwinder (gdbarch, &nanomips_frame_unwind); + frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer); + frame_base_append_sniffer (gdbarch, nanomips_frame_base_sniffer); + + regnum = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct nanomips_regnum); + *regnum = nanomips_regnum; + tdep->regnum = regnum; + + set_gdbarch_num_regs (gdbarch, num_regs); + set_tdesc_pseudo_register_type (gdbarch, nanomips_pseudo_register_type); + tdesc_use_registers (gdbarch, info.target_desc, std::move (tdesc_data)); + + /* Override the normal target description methods to handle our + dual real and pseudo registers. */ + set_gdbarch_register_name (gdbarch, nanomips_register_name); + set_gdbarch_register_reggroup_p (gdbarch, + nanomips_tdesc_register_reggroup_p); + + /* The target description may have adjusted num_regs, fetch the final + value and set pc_regnum and sp_regnum now that it has been fixed. */ + num_regs = gdbarch_num_regs (gdbarch); + set_gdbarch_num_pseudo_regs (gdbarch, num_regs); + set_gdbarch_pc_regnum (gdbarch, NANOMIPS_PC_REGNUM + num_regs); + set_gdbarch_sp_regnum (gdbarch, NANOMIPS_SP_REGNUM + num_regs); + if (regnum->fpr != -1) + set_gdbarch_fp0_regnum (gdbarch, regnum->fpr + NANOMIPS_FP0_REGNUM); + set_gdbarch_virtual_frame_pointer (gdbarch, nanomips_virtual_frame_pointer); + + return gdbarch; +} + +static void +nanomips_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file) +{ + struct nanomips_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + if (tdep != NULL) + { + int ef_mips_arch; + int ef_mips_32bitmode; + /* Determine the ISA. */ + switch (tdep->elf_flags & EF_NANOMIPS_ARCH) + { + case E_NANOMIPS_ARCH_32R6: + ef_mips_arch = 1; + break; + case E_NANOMIPS_ARCH_64R6: + ef_mips_arch = 2; + break; + default: + ef_mips_arch = 0; + break; + } + /* Determine the size of a pointer. */ + ef_mips_32bitmode = (tdep->elf_flags & EF_NANOMIPS_32BITMODE); + gdb_printf (file, + "nanomips_dump_tdep: tdep->elf_flags = 0x%x\n", + tdep->elf_flags); + gdb_printf (file, + "nanomips_dump_tdep: ef_mips_32bitmode = %d\n", + ef_mips_32bitmode); + gdb_printf (file, + "nanomips_dump_tdep: ef_mips_arch = %d\n", + ef_mips_arch); + gdb_printf (file, + "nanomips_dump_tdep: tdep->nanomips_abi = %d (%s)\n", + tdep->nanomips_abi, + nanomips_abi_strings[tdep->nanomips_abi]); + gdb_printf (file, + "nanomips_dump_tdep: " + "nanomips_mask_address_p() %d (default %d)\n", + nanomips_mask_address_p (tdep), + tdep->default_mask_address_p); + } + + gdb_printf (file, + "nanomips_dump_tdep: FPU_TYPE = %d (%s)\n", + FPU_TYPE (gdbarch), + (FPU_TYPE (gdbarch) == NANOMIPS_FPU_NONE ? "unknown" + : FPU_TYPE (gdbarch) == NANOMIPS_FPU_HARD ? + "64bit hardware floating point" + : FPU_TYPE (gdbarch) == NANOMIPS_FPU_SOFT ? + "Software floating point" + : "???")); +} + +void _initialize_nanomips_tdep(); /* -Wmissing-prototypes */ + +void +_initialize_nanomips_tdep () +{ + gdbarch_register (bfd_arch_nanomips, nanomips_gdbarch_init, + nanomips_dump_tdep); + + initialize_tdesc_nanomips (); + + /* Add root prefix command for all "set/show nanomips" commands. */ + add_prefix_cmd ("nanomips", no_class, set_nanomips_command, + _("Various nanoMIPS specific commands."), + &setnanomipscmdlist, 0, &setlist); + + add_prefix_cmd ("nanomips", no_class, show_nanomips_command, + _("Various nanoMIPS specific commands."), + &shownanomipscmdlist, 0, &showlist); + + /* We really would like to have both "0" and "unlimited" work, but + command.c doesn't deal with that. So make it a var_zinteger + because the user can always use "999999" or some such for unlimited. */ + add_setshow_zinteger_cmd ("heuristic-fence-post", class_support, + &heuristic_fence_post, _("\ +Set the distance searched for the start of a function."), _("\ +Show the distance searched for the start of a function."), _("\ +If you are debugging a stripped executable, GDB needs to search through the\n\ +program for the start of a function. This command sets the distance of the\n\ +search. The only need to set it is when debugging a stripped executable."), + reinit_frame_cache_sfunc, + NULL, /* FIXME: i18n: The distance searched for + the start of a function is %s. */ + &setlist, &showlist); + + /* Allow the user to control whether the upper bits of 64-bit + addresses should be zeroed. */ + add_setshow_auto_boolean_cmd ("mask-address", no_class, + &mask_address_var, _("\ +Set zeroing of upper 32 bits of 64-bit addresses."), _("\ +Show zeroing of upper 32 bits of 64-bit addresses."), _("\ +Use \"on\" to enable the masking, \"off\" to disable it and \"auto\" to\n\ +allow GDB to determine the correct value."), + NULL, show_mask_address, + &setnanomipscmdlist, &shownanomipscmdlist); + + /* Debug this files internals. */ + add_setshow_zuinteger_cmd ("nanomips", class_maintenance, + &nanomips_debug, _("\ +Set nanomips debugging."), _("\ +Show nanomips debugging."), _("\ +When non-zero, nanomips specific debugging is enabled."), + NULL, + NULL, /* FIXME: i18n: Mips debugging is + currently %s. */ + &setdebuglist, &showdebuglist); +} diff --git a/gdb/nanomips-tdep.h b/gdb/nanomips-tdep.h new file mode 100644 index 00000000000..97d85ec89d6 --- /dev/null +++ b/gdb/nanomips-tdep.h @@ -0,0 +1,144 @@ +/* Target-dependent header for the nanoMIPS architecture, for GDB, + the GNU Debugger. + + Copyright (C) 2002-2022 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef NANOMIPS_TDEP_H +#define NANOMIPS_TDEP_H + +#include "objfiles.h" + +struct gdbarch; + +/* All the possible nanoMIPS ABIs. */ +enum nanomips_abi + { + NANOMIPS_ABI_UNKNOWN = 0, + NANOMIPS_ABI_P32, + NANOMIPS_ABI_P64, + }; + +/* Return the nanoMIPS ABI associated with GDBARCH. */ +enum nanomips_abi nanomips_abi (struct gdbarch *gdbarch); + +/* Return the current index for various nanoMIPS registers. */ +struct nanomips_regnum +{ + int fpr; /* Floating-point unit registers. */ + int badvaddr; /* Bad vaddr for addressing exception. */ + int status; /* Status register. */ + int cause; /* Describes last exception. */ + int dsp; /* DSP registers. */ + int restart; /* Linux syscall restart flag. */ +}; + +extern const struct nanomips_regnum *nanomips_regnum (struct gdbarch *gdbarch); + +/* nanoMIPS floating-point operations. */ + +enum fpu_type +{ + NANOMIPS_FPU_NONE, /* Unknown floating point. */ + NANOMIPS_FPU_HARD, /* Double precision floating point. */ + NANOMIPS_FPU_SOFT /* Software floating point. */ +}; + +/* nanoMIPS specific per-architecture information. */ +struct nanomips_gdbarch_tdep : gdbarch_tdep_base +{ + /* from the elf header */ + int elf_flags; + + /* nanomips options */ + enum nanomips_abi nanomips_abi; + enum nanomips_abi found_abi; + enum fpu_type fpu_type; + int mips_last_arg_regnum; + int default_mask_address_p; + + /* Indexes for various registers determined dynamically at run time. + This contains the "public" fields. Don't add any that do not need + to be public. */ + struct nanomips_regnum *regnum; + + /* The size of register data available from the target. */ + int register_size; + + /* Return the expected next PC if FRAME is stopped at a syscall + instruction. */ + CORE_ADDR (*syscall_next_pc) (frame_info_ptr frame, CORE_ADDR pc); +}; + +/* Register numbers of various important registers from the fixed + GPR+PC register set that is always present. The rest is determined + dynamically at run time and held in `gdbarch_tdep->regnum'. */ + +enum +{ + NANOMIPS_ZERO_REGNUM = 0, + NANOMIPS_AT_REGNUM = 1, + NANOMIPS_T4_REGNUM = 2, + NANOMIPS_A0_REGNUM = 4, + NANOMIPS_GP_REGNUM = 28, + NANOMIPS_SP_REGNUM = 29, + NANOMIPS_FP_REGNUM = 30, + NANOMIPS_RA_REGNUM = 31, + NANOMIPS_PC_REGNUM = 32 +}; + +/* Floating-point register offsets relative to `gdbarch_tdep->regnum->fpr'. */ + +enum +{ + NANOMIPS_FP0_REGNUM = 0, + NANOMIPS_FCSR_REGNUM = 32, + NANOMIPS_FIR_REGNUM = 33 +}; + +/* DSP register offsets, relative to `gdbarch_tdep->regnum->dsp'. */ + +enum +{ + NANOMIPS_DSPHI0_REGNUM = 0, + NANOMIPS_DSPLO0_REGNUM = 1, + NANOMIPS_DSPCTL_REGNUM = 8 +}; + +/* Instruction sizes and other useful constants. */ +enum +{ + INSN16_SIZE = 2, + INSN32_SIZE = 4, + /* The number of floating-point or integer registers. */ + NUMREGS = 32 +}; + +/* Single step based on where the current instruction will take us. */ +extern std::vector +nanomips_software_single_step (struct regcache *regcache); + +/* Return the currently determined ISA register size. */ +extern int nanomips_isa_regsize (struct gdbarch *gdbarch); + +/* Return the currently configured (or set) saved register size. */ +extern unsigned int nanomips_abi_regsize (struct gdbarch *gdbarch); + +/* Make PC the address of the next instruction to execute. */ +extern void nanomips_write_pc (struct regcache *regcache, CORE_ADDR pc); + +#endif /* NANOMIPS_TDEP_H */ diff --git a/gdb/testsuite/gdb.asm/asm-source.exp b/gdb/testsuite/gdb.asm/asm-source.exp index d56a5076b44..c2ec299a81f 100644 --- a/gdb/testsuite/gdb.asm/asm-source.exp +++ b/gdb/testsuite/gdb.asm/asm-source.exp @@ -100,6 +100,13 @@ switch -glob -- [istarget] { "mips*-*" { set asm-arch mips } + "nanomips*-elf" { + set asm-arch nanomips + append link-flags " -Ttext 0x80020000 -Tdata 0x80030000" + set board [target_info name] + set old_ldscript [board_info $board ldscript] + set_board_info ldscript "" + } "powerpc64le-*" { set asm-arch powerpc64le set asm-flags "-a64 -I${srcdir}/${subdir} $obj_include" @@ -260,7 +267,7 @@ if {[target_link [list $asm1obj $asm2obj] "${binfile}" ${link-flags}] != "" } th } # Restore the target board linker script for HC11/HC12. -if { [istarget "m6811-*-*"] || [istarget "m6812-*-*"] } { +if { [istarget "m6811-*-*"] || [istarget "m6812-*-*"] || [istarget "nanomips*-elf"] } { set_board_info ldscript $old_ldscript } diff --git a/gdb/testsuite/gdb.asm/nanomips.inc b/gdb/testsuite/gdb.asm/nanomips.inc new file mode 100644 index 00000000000..6e2ead15d2c --- /dev/null +++ b/gdb/testsuite/gdb.asm/nanomips.inc @@ -0,0 +1,49 @@ + comment "subroutine declare" + .purgem gdbasm_declare + .macro gdbasm_declare name + .align 1 + .ent \name + .type \name,@function +\name: + .endm + + comment "subroutine prologue" + .macro gdbasm_enter + save 32, $fp, $ra + addiu $fp, $sp, -4080 + .endm + + comment "subroutine epilogue" + .macro gdbasm_leave + restore.jrc 32, $fp, $ra + .endm + + comment "subroutine end" + .purgem gdbasm_end + .macro gdbasm_end name + .end \name + .endm + + .macro gdbasm_call subr + li $t9, \subr + jalrc $ra, $t9 + .endm + + .macro gdbasm_several_nops + nop + nop + nop + nop + .endm + + comment "exit (0)" + .macro gdbasm_exit0 + comment "Don't know how to exit, but this will certainly halt..." + lw $a3, 0($zero) + .endm + + comment "crt0 startup" + .macro gdbasm_startup + li $sp, 0x8007fff0 + li $fp, 0 + .endm diff --git a/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c b/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c index e9923814b01..a2064b3bb2e 100644 --- a/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c +++ b/gdb/testsuite/gdb.base/catch-gdb-caused-signals.c @@ -27,6 +27,9 @@ main (void) { int i = 0; + /* Ensure printf function is available. */ + printf ("printf available %d\n", i); + gdb_unbuffer_output (); i++; /* set dprintf here */ diff --git a/gdb/testsuite/gdb.base/float.exp b/gdb/testsuite/gdb.base/float.exp index 7fff2b90727..76a274e936a 100644 --- a/gdb/testsuite/gdb.base/float.exp +++ b/gdb/testsuite/gdb.base/float.exp @@ -67,7 +67,7 @@ if { [is_aarch64_target] } then { pass "info float (without FPU)" } } -} elseif [istarget "mips*-*-*"] then { +} elseif { [istarget "mips*-*-*"] || [istarget "nanomips*-*-*"] } then { gdb_test_multiple "info float" "info float" { -re "fpu type: none / unused\r\n$gdb_prompt $" { pass "info float (without FPU)" diff --git a/gdb/testsuite/gdb.trace/trace-common.h b/gdb/testsuite/gdb.trace/trace-common.h index f8cd654ba2b..6dfab081f1e 100644 --- a/gdb/testsuite/gdb.trace/trace-common.h +++ b/gdb/testsuite/gdb.trace/trace-common.h @@ -43,7 +43,7 @@ x86_trace_dummy () " call " SYMBOL(x86_trace_dummy) "\n" \ ) -#elif (defined __aarch64__) || (defined __powerpc__) +#elif (defined __aarch64__) || (defined __powerpc__) || (__nanomips__) #define FAST_TRACEPOINT_LABEL(name) \ asm (" .global " SYMBOL(name) "\n" \ diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 7d05fbe557b..2df0d35ffa0 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -3284,6 +3284,7 @@ gdb_caching_proc supports_memtag { proc can_hardware_single_step {} { if { [istarget "arm*-*-*"] || [istarget "mips*-*-*"] + || [istarget "nanomips*-*-*"] || [istarget "tic6x-*-*"] || [istarget "sparc*-*-linux*"] || [istarget "nios2-*-*"] || [istarget "riscv*-*-linux*"] } { return 0