From nobody Sat Apr 11 23:08:38 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1772954560; cv=none; d=zohomail.com; s=zohoarc; b=k34TIhvInbHzEZFC3lWk5bFyFGl5e/gvqZuWxb5qvXVgXWyXtO2oKteudTYLqzPpQ0e/jc7QQaKaHQ1aIDsJAz/Z/qw6tyE5pmNhRPyhsDKO2VZCrRRJIDyumvw82zM+s9DCONpbcCI8JYZKrNjM4gBMhhWvjvTHAo2ceZaQ/QI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1772954560; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=bcvnvVJoE5XYpkkYLdY/36Vds/J4Eu0RKogC8hkAKYU=; b=R1ylCk1Xwn3slAxR5h7Gr1ice6bzF1+VZsVVvL0eU4jdqqVVXs8dgIbwWGgMGmBbtnI5okJB16naZdLsVVQ4VcL8eGUJva2evHd4L1DImxprxYX+sTlUbdWX4TwhAUxxYE5FfWplxWaG50do8LMTqQ/nruTRRfAPKaiaEpDarw0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1772954560863677.4448466058609; Sat, 7 Mar 2026 23:22:40 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vz8T5-0005e4-OL; Sun, 08 Mar 2026 03:22:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vz8Rx-0002xA-TM for qemu-devel@nongnu.org; Sun, 08 Mar 2026 03:21:18 -0400 Received: from mail-dl1-x1243.google.com ([2607:f8b0:4864:20::1243]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vz8Rv-0003OG-NA for qemu-devel@nongnu.org; Sun, 08 Mar 2026 03:21:17 -0400 Received: by mail-dl1-x1243.google.com with SMTP id a92af1059eb24-126ea4e9694so4374397c88.1 for ; Sat, 07 Mar 2026 23:21:15 -0800 (PST) Received: from ZEVORN-PC.bbrouter ([38.95.120.198]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2be4f984ceasm6014081eec.32.2026.03.07.23.21.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Mar 2026 23:21:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1772954474; x=1773559274; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=bcvnvVJoE5XYpkkYLdY/36Vds/J4Eu0RKogC8hkAKYU=; b=MJKha3SgFA5Tj2E5mB0OtcpX8zF2A7DgBp3skZEcTSIGW0KjcVZbcDwjxo/6rbHYIO SFraSPqEEQwI8RFk0jUjFOY0XNpQg+sGIsYBv1IPgXf5myRTtVcnbtAj74aftMyCkATH /Md8RKfgXRWUOmhZ7Jn/h9V/9/+CucUZTDkBszfKUbDdkKxtE8qN6/mHf/mMGVnkGrZY d1Li8HL10O0iftxk1xTgumGktrtimIfmrIL13eZI6aHauxW2gM88qgYyl0kP3Ra66cfN Jc6aiproqN9F80PHWLnftI4Bpwa9+eJ+j7zSh55k+tSSGHEBPLVkeKU7U7qoJE2eBPAW YYcw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772954474; x=1773559274; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=bcvnvVJoE5XYpkkYLdY/36Vds/J4Eu0RKogC8hkAKYU=; b=GjKfi+aTzEi+nVdhU8BtZ4rjIlCfwG2YxyH71uU6Ji62XmnTjxrNzlPgzr+d64PdHn ePw6MgXZO/R0OsWhXAk5KIm+E6siQjnqzc0UD4d/WuhrJfdppBxroCPPKUa771dsuCQT Fii9p7kqnrUcGhwJZSkZ7Lt++2MxJjLr9PR2VWkMWhlwApJi/lztBxsnE03MYS3qtcSi MlNZtyDVyAlxBU1qzLPJ/sdI8H/aFWZVb5+xB5JxT8/sth0NaYvT0cx2GA/QxRwsHkPH SGqwmK65z0XYqI9Tgj9kY8U38s6PLwHxNfs3t4G5o5pBObg0FsENPNJZWYs9X3y2GB1M rbIA== X-Forwarded-Encrypted: i=1; AJvYcCV8ZtxUwhUGCZtp98RQi38LUcaNCOfh7jkJiSPPwRHzyawtUNAv+ApS4CplXEIHR2iXzBVBPRzaBx+J@nongnu.org X-Gm-Message-State: AOJu0YyhNFEqpp+Sa4oYE5bIRTkQLYJk/kcVPLTjgQittgxyvpYpbOEC t80ZZRCqum8yV0Ug15an73s5+2x/pRQB9/x7qkv2UQBcDMnvrlgraPzR X-Gm-Gg: ATEYQzxkv282bfVDCI/SnNqwp/sokDz3jS3l/G4yOTfynECP7+vWp/CbmaaHtu95WvI kDOJXL+ILxOIqoz2B08i5rWbno0Ls3sB6Kk1OzukaRemBn/l6Sgm/4cI26ipv1OFi5z8dTerupR K67bTQQJUjAUnCbPBQnUmDzWL3hCaY89zqJPzEU8DKO7QbjmQMh19iRitBrydH7GYiKrpH3BqA+ Z/USMuel6TtxfOXXUjaIX7DnPwICQ6B1BqNv+tOmlyXQhIy1ZD/0jHCiSKe+rtiKnORWsN/3N/U VSHTwVzYW8/XedD8/UfCV71iX50UxSkgXqducCWGJonP3RvEMExk0Gu11yPa4JiSv9W1+tniNs5 fS6LQURfOWomX50HIvQuKZkRpfOp4R60PN7rngLikbKZ+d9SH8a9oTYKzluCDpt6t+8db6DxcGr EWWnnuaRH2buQY0ej+2r/pH7OHJZ3o4v2a3X9u/dTFSdkIi5P/IUcn+V4MFFUQmkZUdyGR82YNf uZRL33GVt2oFJ5DvQG0VtTQQAE= X-Received: by 2002:a05:7022:b81:b0:128:d4be:7428 with SMTP id a92af1059eb24-128d4be781dmr204892c88.19.1772954474197; Sat, 07 Mar 2026 23:21:14 -0800 (PST) From: Chao Liu To: Paolo Bonzini , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , Fabiano Rosas , Laurent Vivier Cc: tangtao1634@phytium.com.cn, qemu-devel@nongnu.org, qemu-riscv@nongnu.org Subject: [PATCH v1 27/28] tests/qtest: add DM TCG halt and register access tests Date: Sun, 8 Mar 2026 15:17:30 +0800 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::1243; envelope-from=chao.liu.zevorn@gmail.com; helo=mail-dl1-x1243.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1772954563576154100 Add TCG-mode helper functions that boot a real CPU and interact with the Debug Module through clock stepping, then add the first batch of TCG tests: tcg/halt-dpc =E2=80=93 halt via HALTREQ, verify DPC/DCSR tcg/resethaltreq-priority =E2=80=93 resethaltreq takes effect on reset tcg/gpr-rw =E2=80=93 read/write GPRs via abstract cmds tcg/fpr-rw =E2=80=93 read/write FPRs via abstract cmds rv32-gpr64-notsup =E2=80=93 64-bit GPR access rejected on RV32 tcg/command-ignored-on-cmderr =E2=80=93 sticky cmderr blocks new cmds Signed-off-by: Chao Liu --- tests/qtest/riscv-dm-test.c | 355 ++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) diff --git a/tests/qtest/riscv-dm-test.c b/tests/qtest/riscv-dm-test.c index 1b1ab02284..2e7c29ed7c 100644 --- a/tests/qtest/riscv-dm-test.c +++ b/tests/qtest/riscv-dm-test.c @@ -213,6 +213,139 @@ static void sim_cpu_exception(QTestState *qts) rom_write32(qts, ROM_EXCP, 0); } =20 +/* TCG-mode helpers: real CPU execution with clock stepping. */ + +static QTestState *tcg_dm_init(void) +{ + const char *arch =3D qtest_get_arch(); + const char *cpu_type =3D strstr(arch, "64") ? "rv64" : "rv32"; + g_autofree char *args =3D g_strdup_printf( + "-machine virt -accel tcg -smp 1 -cpu %s,sdext=3Dtrue", cpu_type); + QTestState *qts =3D qtest_init(args); + + /* Check VM status */ + QDict *resp =3D qtest_qmp(qts, "{'execute': 'query-status'}"); + const QDict *ret =3D qdict_get_qdict(resp, "return"); + bool running =3D qdict_get_bool(ret, "running"); + const char *vm_status =3D qdict_get_str(ret, "status"); + g_test_message("VM status: %s running=3D%d", vm_status, running); + qobject_unref(resp); + + if (!running) { + resp =3D qtest_qmp(qts, "{'execute': 'cont'}"); + g_test_message("Sent cont"); + qobject_unref(resp); + } + + /* Let the CPU boot via MTTCG thread */ + g_usleep(TCG_BOOT_US); + + dm_set_active(qts); + return qts; +} + +static bool tcg_wait_for_halt(QTestState *qts) +{ + for (int t =3D 0; t < TCG_POLL_TIMEOUT_US; t +=3D TCG_POLL_STEP_US) { + g_usleep(TCG_POLL_STEP_US); + uint32_t st =3D dm_read(qts, A_DMSTATUS); + if (t < TCG_POLL_STEP_US * 5) { + g_test_message("halt poll: DMSTATUS=3D0x%08x", st); + } + if (st & DMSTATUS_ALLHALTED) { + return true; + } + } + return false; +} + +static bool tcg_wait_for_cmd_done(QTestState *qts) +{ + for (int t =3D 0; t < TCG_POLL_TIMEOUT_US; t +=3D TCG_POLL_STEP_US) { + g_usleep(TCG_POLL_STEP_US); + if (!(dm_read(qts, A_ABSTRACTCS) & ABSTRACTCS_BUSY)) { + return true; + } + } + return false; +} + +static bool tcg_halt_hart(QTestState *qts) +{ + dm_write(qts, A_DMCONTROL, DMCONTROL_DMACTIVE | DMCONTROL_HALTREQ); + return tcg_wait_for_halt(qts); +} + +static bool tcg_resume_hart(QTestState *qts) +{ + dm_write(qts, A_DMCONTROL, DMCONTROL_DMACTIVE | DMCONTROL_RESUMEREQ); + for (int t =3D 0; t < TCG_POLL_TIMEOUT_US; t +=3D TCG_POLL_STEP_US) { + g_usleep(TCG_POLL_STEP_US); + if (dm_read(qts, A_DMSTATUS) & DMSTATUS_ALLRESUMEACK) { + return true; + } + } + return false; +} + + +/* + * Read a register via Access Register abstract command. + * Returns true on success, false on error or timeout. + */ +static bool tcg_abstract_read_reg(QTestState *qts, uint32_t regno, + uint32_t *val) +{ + dm_write(qts, A_ABSTRACTCS, ABSTRACTCS_CMDERR_MASK); + + uint32_t cmd =3D (0u << 24) | /* cmdtype =3D Access Register */ + (1u << 17) | /* transfer =3D 1 */ + (2u << 20) | /* aarsize =3D 32-bit */ + (regno & 0xFFFF); + dm_write(qts, A_COMMAND, cmd); + + if (!tcg_wait_for_cmd_done(qts)) { + return false; + } + + uint32_t acs =3D dm_read(qts, A_ABSTRACTCS); + if (acs & ABSTRACTCS_CMDERR_MASK) { + return false; + } + + *val =3D dm_read(qts, A_DATA0); + return true; +} + +/* + * Write a register via Access Register abstract command. + * Returns true on success, false on error or timeout. + */ +static bool tcg_abstract_write_reg(QTestState *qts, uint32_t regno, + uint32_t val) +{ + dm_write(qts, A_ABSTRACTCS, ABSTRACTCS_CMDERR_MASK); + dm_write(qts, A_DATA0, val); + + uint32_t cmd =3D (0u << 24) | /* cmdtype =3D Access Register */ + (1u << 17) | /* transfer =3D 1 */ + (1u << 16) | /* write =3D 1 */ + (2u << 20) | /* aarsize =3D 32-bit */ + (regno & 0xFFFF); + dm_write(qts, A_COMMAND, cmd); + + if (!tcg_wait_for_cmd_done(qts)) { + return false; + } + + uint32_t acs =3D dm_read(qts, A_ABSTRACTCS); + return !(acs & ABSTRACTCS_CMDERR_MASK); +} + +/* + * Write a 64-bit register via Access Register abstract command (aarsize= =3D3). + * DATA1 holds high 32 bits, DATA0 holds low 32 bits. + */ =20 /* * Test: dmactive gate. @@ -930,6 +1063,218 @@ static void test_haltsum1_window(void) * 4. Read DPC via abstract command =E2=86=92 verify it's a valid address * 5. Resume CPU, then re-halt to verify the cycle works */ +static void test_tcg_halt_dpc(void) +{ + QTestState *qts =3D tcg_dm_init(); + + /* Halt the CPU */ + g_assert_true(tcg_halt_hart(qts)); + + uint32_t status =3D dm_read(qts, A_DMSTATUS); + g_assert_cmpuint(status & DMSTATUS_ALLHALTED, =3D=3D, DMSTATUS_ALLHALT= ED); + g_assert_cmpuint(status & DMSTATUS_ANYRUNNING, =3D=3D, 0); + + /* Read DCSR: verify cause =3D HALTREQ (3) */ + uint32_t dcsr; + g_assert_true(tcg_abstract_read_reg(qts, REGNO_DCSR, &dcsr)); + uint32_t cause =3D (dcsr & DCSR_CAUSE_MASK) >> DCSR_CAUSE_SHIFT; + g_assert_cmpuint(cause, =3D=3D, DCSR_CAUSE_HALTREQ); + + /* Read DPC: implementation dependent, but it must stay aligned. */ + uint32_t dpc; + g_assert_true(tcg_abstract_read_reg(qts, REGNO_DPC, &dpc)); + g_assert_cmpuint(dpc & 1u, =3D=3D, 0); + + /* Resume the CPU */ + g_assert_true(tcg_resume_hart(qts)); + status =3D dm_read(qts, A_DMSTATUS); + g_assert_cmpuint(status & DMSTATUS_ALLRESUMEACK, =3D=3D, + DMSTATUS_ALLRESUMEACK); + + /* Let it run a bit, then re-halt */ + g_usleep(TCG_BOOT_US); + + g_assert_true(tcg_halt_hart(qts)); + + /* DPC after re-halt is also execution dependent; only assert alignmen= t */ + uint32_t dpc2; + g_assert_true(tcg_abstract_read_reg(qts, REGNO_DPC, &dpc2)); + g_assert_cmpuint(dpc2 & 1u, =3D=3D, 0); + + /* DCSR cause should be HALTREQ again */ + g_assert_true(tcg_abstract_read_reg(qts, REGNO_DCSR, &dcsr)); + cause =3D (dcsr & DCSR_CAUSE_MASK) >> DCSR_CAUSE_SHIFT; + g_assert_cmpuint(cause, =3D=3D, DCSR_CAUSE_HALTREQ); + + qtest_quit(qts); +} + +/* + * Test: reset-haltreq and haltreq asserted together. + * + * Priority per Debug Spec v1.0 Table 4.2 requires reset-haltreq (cause=3D= 5) + * to win over haltreq (cause=3D3). + */ +static void test_tcg_resethaltreq_priority(void) +{ + QTestState *qts =3D tcg_dm_init(); + uint32_t status, dcsr, cause; + + dm_write(qts, A_DMCONTROL, DMCONTROL_DMACTIVE | DMCONTROL_SETRESETHALT= REQ); + + dm_write(qts, A_DMCONTROL, DMCONTROL_DMACTIVE | + DMCONTROL_HARTRESET | DMCONTROL_HALTREQ); + dm_write(qts, A_DMCONTROL, DMCONTROL_DMACTIVE | DMCONTROL_HALTREQ); + + g_assert_true(tcg_wait_for_halt(qts)); + status =3D dm_read(qts, A_DMSTATUS); + g_assert_cmpuint(status & DMSTATUS_ALLHALTED, =3D=3D, DMSTATUS_ALLHALT= ED); + + g_assert_true(tcg_abstract_read_reg(qts, REGNO_DCSR, &dcsr)); + cause =3D (dcsr & DCSR_CAUSE_MASK) >> DCSR_CAUSE_SHIFT; + g_assert_cmpuint(cause, =3D=3D, DCSR_CAUSE_RESET); + + dm_write(qts, A_DMCONTROL, DMCONTROL_DMACTIVE | + DMCONTROL_CLRRESETHALTREQ | DMCONTROL_HALTR= EQ); + dm_write(qts, A_DMCONTROL, DMCONTROL_DMACTIVE); + + qtest_quit(qts); +} + +/* + * Test: Read/Write all 32 GPR registers via abstract commands (TCG). + * + * For each GPR x0..x31: + * - x0: hardwired to 0, read should return 0 + * - x1..x31: write a test pattern, read back and verify + */ +static void test_tcg_gpr_rw(void) +{ + QTestState *qts =3D tcg_dm_init(); + + g_assert_true(tcg_halt_hart(qts)); + + /* x0 is hardwired to 0 */ + uint32_t val; + g_assert_true(tcg_abstract_read_reg(qts, REGNO_GPR(0), &val)); + g_assert_cmpuint(val, =3D=3D, 0); + + /* x1..x31: write test patterns and read back */ + for (int i =3D 1; i < 32; i++) { + uint32_t pattern =3D 0xA5000000u | (uint32_t)i; + + g_assert_true(tcg_abstract_write_reg(qts, REGNO_GPR(i), pattern)); + g_assert_true(tcg_abstract_read_reg(qts, REGNO_GPR(i), &val)); + g_assert_cmpuint(val, =3D=3D, pattern); + } + + /* Verify x0 is still 0 after all writes */ + g_assert_true(tcg_abstract_read_reg(qts, REGNO_GPR(0), &val)); + g_assert_cmpuint(val, =3D=3D, 0); + + qtest_quit(qts); +} + +/* + * Test: Read/Write all 32 FPR registers via abstract commands (TCG). + * + * For each FPR f0..f31: + * - Write a 32-bit test pattern (single-precision view) + * - Read back and verify + */ +static void test_tcg_fpr_rw(void) +{ + QTestState *qts =3D tcg_dm_init(); + + g_assert_true(tcg_halt_hart(qts)); + + uint32_t val; + + for (int i =3D 0; i < 32; i++) { + uint32_t pattern =3D 0x3F800000u + (uint32_t)i; /* 1.0f + i */ + + g_assert_true(tcg_abstract_write_reg(qts, REGNO_FPR(i), pattern)); + g_assert_true(tcg_abstract_read_reg(qts, REGNO_FPR(i), &val)); + g_assert_cmpuint(val, =3D=3D, pattern); + } + + qtest_quit(qts); +} + +/* + * Test: RV32 rejects 64-bit GPR abstract accesses at command decode time. + */ +static void test_rv32_gpr64_notsup(void) +{ + QTestState *qts; + uint32_t acs; + const char *arch =3D qtest_get_arch(); + + if (!strstr(arch, "32")) { + g_test_skip("RV32-only"); + return; + } + + qts =3D qtest_init("-machine virt"); + + dm_set_active(qts); + dm_write(qts, A_DMCONTROL, DMCONTROL_DMACTIVE | DMCONTROL_HALTREQ); + sim_cpu_halt_ack(qts, 0); + dm_write(qts, A_ABSTRACTCS, ABSTRACTCS_CMDERR_MASK); + + dm_write(qts, A_COMMAND, + (0u << 24) | (1u << 17) | (3u << 20) | REGNO_GPR(1)); + + acs =3D dm_read(qts, A_ABSTRACTCS); + g_assert_cmpuint(acs & ABSTRACTCS_BUSY, =3D=3D, 0); + g_assert_cmpuint((acs & ABSTRACTCS_CMDERR_MASK) >> + ABSTRACTCS_CMDERR_SHIFT, =3D=3D, 2); + + qtest_quit(qts); +} + +/* + * Test: COMMAND writes are ignored while CMDERR is non-zero. + */ +static void test_tcg_command_ignored_on_cmderr(void) +{ + QTestState *qts =3D tcg_dm_init(); + + g_assert_true(tcg_halt_hart(qts)); + + /* Baseline last command: read x0, result must be 0. */ + dm_write(qts, A_ABSTRACTCS, ABSTRACTCS_CMDERR_MASK); + dm_write(qts, A_COMMAND, + (0u << 24) | (1u << 17) | (2u << 20) | REGNO_GPR(0)); + g_assert_true(tcg_wait_for_cmd_done(qts)); + g_assert_cmpuint(dm_read(qts, A_DATA0), =3D=3D, 0); + + /* Latch cmderr with an unsupported command. */ + dm_write(qts, A_COMMAND, 0xFF000000); + uint32_t acs =3D dm_read(qts, A_ABSTRACTCS); + g_assert_cmpuint((acs & ABSTRACTCS_CMDERR_MASK) >> + ABSTRACTCS_CMDERR_SHIFT, =3D=3D, 2); + + /* + * This command must be ignored because cmderr !=3D 0. + * If it incorrectly overwrites last_cmd, later autoexec will read DCS= R. + */ + dm_write(qts, A_COMMAND, + (0u << 24) | (1u << 17) | (2u << 20) | REGNO_DCSR); + + dm_write(qts, A_ABSTRACTCS, ABSTRACTCS_CMDERR_MASK); + dm_write(qts, A_ABSTRACTAUTO, 0x1); /* autoexec on data0 */ + dm_write(qts, A_DATA0, 0xDEADBEEF); /* triggers autoexec of last_cm= d */ + + g_assert_true(tcg_wait_for_cmd_done(qts)); + acs =3D dm_read(qts, A_ABSTRACTCS); + g_assert_cmpuint((acs & ABSTRACTCS_CMDERR_MASK) >> + ABSTRACTCS_CMDERR_SHIFT, =3D=3D, 2); + g_assert_cmpuint(dm_read(qts, A_DATA0), =3D=3D, 0xDEADBEEF); + + qtest_quit(qts); +} + =20 /* * Test: Halt and resume cycle via ROM simulation. @@ -1008,5 +1353,15 @@ int main(int argc, char *argv[]) qtest_add_func("/riscv-dm/abstract-cmd-exception", test_abstract_cmd_exception); =20 + /* TCG-mode tests: real CPU execution */ + qtest_add_func("/riscv-dm/tcg/halt-dpc", test_tcg_halt_dpc); + qtest_add_func("/riscv-dm/tcg/resethaltreq-priority", + test_tcg_resethaltreq_priority); + qtest_add_func("/riscv-dm/tcg/gpr-rw", test_tcg_gpr_rw); + qtest_add_func("/riscv-dm/tcg/fpr-rw", test_tcg_fpr_rw); + qtest_add_func("/riscv-dm/rv32-gpr64-notsup", test_rv32_gpr64_notsup); + qtest_add_func("/riscv-dm/tcg/command-ignored-on-cmderr", + test_tcg_command_ignored_on_cmderr); + return g_test_run(); } --=20 2.53.0